@cdevhub/ngx-chat 1.0.6
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/README.md +382 -0
- package/fesm2022/cdevhub-ngx-chat-testing.mjs +950 -0
- package/fesm2022/cdevhub-ngx-chat-testing.mjs.map +1 -0
- package/fesm2022/cdevhub-ngx-chat.mjs +11973 -0
- package/fesm2022/cdevhub-ngx-chat.mjs.map +1 -0
- package/package.json +55 -0
- package/types/cdevhub-ngx-chat-testing.d.ts +362 -0
- package/types/cdevhub-ngx-chat.d.ts +6973 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdevhub-ngx-chat.mjs","sources":["../../../projects/ngx-chat/src/lib/models/config.model.ts","../../../projects/ngx-chat/src/lib/models/i18n.model.ts","../../../projects/ngx-chat/src/lib/tokens/chat-config.token.ts","../../../projects/ngx-chat/src/lib/tokens/chat-i18n.token.ts","../../../projects/ngx-chat/src/lib/provide-chat.ts","../../../projects/ngx-chat/src/lib/services/chat-config.service.ts","../../../projects/ngx-chat/src/lib/services/chat-event.service.ts","../../../projects/ngx-chat/src/lib/directives/chat-header-content.directive.ts","../../../projects/ngx-chat/src/lib/components/chat-header/chat-header.component.ts","../../../projects/ngx-chat/src/lib/utils/validation.utils.ts","../../../projects/ngx-chat/src/lib/components/chat-sender/chat-sender.component.ts","../../../projects/ngx-chat/src/lib/components/chat-sender/chat-sender.component.html","../../../projects/ngx-chat/src/lib/components/chat/chat.component.ts","../../../projects/ngx-chat/src/lib/components/chat/chat.component.html","../../../projects/ngx-chat/src/lib/components/chat-typing-indicator/chat-typing-indicator.component.ts","../../../projects/ngx-chat/src/lib/utils/grouping.utils.ts","../../../projects/ngx-chat/src/lib/services/chat-a11y.service.ts","../../../projects/ngx-chat/src/lib/services/chat-virtual-scroll.service.ts","../../../projects/ngx-chat/src/lib/components/chat-message-bubble/chat-message-bubble.component.ts","../../../projects/ngx-chat/src/lib/components/chat-messages/chat-messages.component.ts","../../../projects/ngx-chat/src/lib/components/actions/confirm-action/confirm-action.component.ts","../../../projects/ngx-chat/src/lib/components/actions/select-action/select-action.component.ts","../../../projects/ngx-chat/src/lib/components/actions/multi-select-action/multi-select-action.component.ts","../../../projects/ngx-chat/src/lib/components/actions/buttons-action/buttons-action.component.ts","../../../projects/ngx-chat/src/lib/components/chat-message-actions/chat-message-actions.component.ts","../../../projects/ngx-chat/src/lib/directives/chat-drop-zone.directive.ts","../../../projects/ngx-chat/src/lib/components/chat-attachment-picker/attachment-picker.component.ts","../../../projects/ngx-chat/src/lib/components/chat-attachment-picker/attachment-preview.component.ts","../../../projects/ngx-chat/src/lib/components/chat-attachment/chat-attachment.component.ts","../../../projects/ngx-chat/src/lib/components/chat-attachment/image-preview.component.ts","../../../projects/ngx-chat/src/lib/components/chat-attachment/file-preview.component.ts","../../../projects/ngx-chat/src/lib/components/chat-attachment/video-preview.component.ts","../../../projects/ngx-chat/src/lib/components/chat-attachment/audio-preview.component.ts","../../../projects/ngx-chat/src/lib/services/chat-markdown.service.ts","../../../projects/ngx-chat/src/lib/components/chat-markdown/chat-markdown.component.ts","../../../projects/ngx-chat/src/lib/components/chat-error-boundary/chat-error-boundary.component.ts","../../../projects/ngx-chat/src/lib/components/index.ts","../../../projects/ngx-chat/src/lib/directives/index.ts","../../../projects/ngx-chat/src/lib/models/error.model.ts","../../../projects/ngx-chat/src/lib/models/index.ts","../../../projects/ngx-chat/src/lib/tokens/chat-features.token.ts","../../../projects/ngx-chat/src/lib/tokens/index.ts","../../../projects/ngx-chat/src/lib/utils/id.utils.ts","../../../projects/ngx-chat/src/lib/utils/message.utils.ts","../../../projects/ngx-chat/src/lib/utils/action.utils.ts","../../../projects/ngx-chat/src/lib/utils/index.ts","../../../projects/ngx-chat/src/lib/services/chat-error-recovery.service.ts","../../../projects/ngx-chat/src/lib/services/chat-attachment.service.ts","../../../projects/ngx-chat/src/lib/services/index.ts","../../../projects/ngx-chat/src/lib/animations/chat.animations.ts","../../../projects/ngx-chat/src/public-api.ts","../../../projects/ngx-chat/src/cdevhub-ngx-chat.ts"],"sourcesContent":["/**\n * @fileoverview Configuration interfaces and defaults for ngx-chat.\n * @module ngx-chat/models/config\n */\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\n/**\n * Recursively makes all properties of T optional.\n * Useful for configuration overrides where users only specify changes.\n *\n * @example\n * ```typescript\n * const partialConfig: DeepPartial<ChatConfig> = {\n * behavior: { sendOnEnter: false }\n * };\n * ```\n */\nexport type DeepPartial<T> = T extends object\n ? { [P in keyof T]?: DeepPartial<T[P]> }\n : T;\n\n// ============================================================================\n// Behavior Configuration\n// ============================================================================\n\n/**\n * Configuration for chat behavior and UX settings.\n */\nexport interface ChatBehaviorConfig {\n /**\n * Whether pressing Enter sends the message.\n * When false, Enter creates a new line.\n * @default true\n */\n readonly sendOnEnter: boolean;\n\n /**\n * Whether to display timestamps on messages.\n * @default true\n */\n readonly showTimestamps: boolean;\n\n /**\n * Format options for message timestamps.\n * Uses Intl.DateTimeFormat options.\n * @default { hour: 'numeric', minute: '2-digit' }\n */\n readonly timestampFormat: Intl.DateTimeFormatOptions;\n\n /**\n * Whether to automatically scroll to new messages.\n * @default true\n */\n readonly autoScroll: boolean;\n\n /**\n * Whether to group consecutive messages from the same sender.\n * @default true\n */\n readonly groupMessages: boolean;\n\n /**\n * Time threshold in milliseconds for grouping messages.\n * Messages within this threshold from the same sender are grouped.\n * @default 60000 (1 minute)\n */\n readonly groupTimeThreshold: number;\n\n /**\n * Cooldown in milliseconds between sends to prevent spam.\n * @default 500\n */\n readonly sendCooldown: number;\n\n /**\n * Debounce time in milliseconds for typing indicator.\n * @default 300\n */\n readonly typingDebounce: number;\n\n /**\n * Threshold in pixels from bottom to consider \"near bottom\" for auto-scroll.\n * @default 100\n */\n readonly scrollNearBottomThreshold: number;\n\n /**\n * Whether to show sender name on messages.\n * @default true\n */\n readonly showSenderName: boolean;\n\n /**\n * Whether to show avatar on messages.\n * @default true\n */\n readonly showAvatar: boolean;\n\n /**\n * Position of avatar relative to the message.\n * @default 'bottom'\n */\n readonly avatarPosition: 'top' | 'bottom';\n}\n\n// ============================================================================\n// Validation Configuration\n// ============================================================================\n\n/**\n * Configuration for message validation and sanitization.\n */\nexport interface ChatValidationConfig {\n /**\n * Minimum message length in characters.\n * @default 0\n */\n readonly minMessageLength: number;\n\n /**\n * Maximum message length in characters.\n * @default 5000\n */\n readonly maxMessageLength: number;\n\n /**\n * Regular expression patterns that are forbidden in messages.\n * Messages matching these patterns will be rejected.\n * @default []\n */\n readonly forbiddenPatterns: readonly RegExp[];\n\n /**\n * Whether to sanitize HTML in messages.\n * @default true\n */\n readonly sanitize: boolean;\n\n /**\n * Whether to trim leading/trailing whitespace from messages.\n * @default true\n */\n readonly trimWhitespace: boolean;\n\n /**\n * Whether to allow sending empty content (attachments only).\n * @default true\n */\n readonly allowEmptyContent: boolean;\n\n /**\n * Maximum length of a single word before it's broken with zero-width spaces.\n * Prevents long URLs or text from breaking layout.\n * @default 50\n */\n readonly maxWordLength: number;\n\n /**\n * Whether to normalize Unicode characters (NFC normalization).\n * @default true\n */\n readonly normalizeUnicode: boolean;\n\n /**\n * Whether to strip invisible characters (zero-width joiners, etc.).\n * @default true\n */\n readonly stripInvisibleChars: boolean;\n}\n\n// ============================================================================\n// Markdown Configuration\n// ============================================================================\n\n/**\n * Configuration for markdown rendering.\n */\nexport interface ChatMarkdownConfig {\n /**\n * Whether markdown rendering is enabled.\n * When disabled, content is displayed as plain text.\n * @default true\n */\n readonly enabled: boolean;\n\n /**\n * Whether syntax highlighting is enabled for code blocks.\n * Requires highlight.js to be installed.\n * @default true\n */\n readonly syntaxHighlighting: boolean;\n\n /**\n * Whether to add rel=\"noopener noreferrer\" to external links.\n * @default true\n */\n readonly sanitizeLinks: boolean;\n\n /**\n * Whether to open external links in a new tab.\n * @default true\n */\n readonly externalLinksNewTab: boolean;\n\n /**\n * Allowed HTML tags for sanitization.\n * Only these tags will be preserved in rendered markdown.\n * @default ['p', 'br', 'strong', 'em', 'code', 'pre', 'a', 'ul', 'ol', 'li', 'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']\n */\n readonly allowedTags: readonly string[];\n\n /**\n * Allowed HTML attributes for sanitization, keyed by tag name.\n * Use '*' for attributes allowed on all tags.\n * @default { 'a': ['href', 'title'], '*': ['class'] }\n */\n readonly allowedAttributes: Readonly<Record<string, readonly string[]>>;\n\n /**\n * Whether to render line breaks as <br> elements.\n * @default true\n */\n readonly breaks: boolean;\n\n /**\n * Whether to automatically linkify URLs.\n * @default true\n */\n readonly linkify: boolean;\n}\n\n// ============================================================================\n// Attachment Configuration\n// ============================================================================\n\n/**\n * Configuration for file attachments.\n */\nexport interface ChatAttachmentConfig {\n /**\n * Whether attachments are enabled.\n * @default true\n */\n readonly enabled: boolean;\n\n /**\n * Maximum file size in bytes.\n * @default 10485760 (10 MB)\n */\n readonly maxFileSize: number;\n\n /**\n * Maximum number of files per message.\n * @default 5\n */\n readonly maxFilesPerMessage: number;\n\n /**\n * Allowed MIME types. Empty array allows all types.\n * @default []\n */\n readonly allowedMimeTypes: readonly string[];\n\n /**\n * Blocked MIME types. Takes precedence over allowedMimeTypes.\n * @default ['application/x-executable', 'application/x-msdownload']\n */\n readonly blockedMimeTypes: readonly string[];\n\n /**\n * Whether to compress images before upload.\n * @default true\n */\n readonly imageCompression: boolean;\n\n /**\n * Quality for image compression (0-1).\n * @default 0.8\n */\n readonly imageCompressionQuality: number;\n\n /**\n * Maximum dimensions for uploaded images.\n * Images larger than this will be resized.\n * @default { width: 2048, height: 2048 }\n */\n readonly maxImageDimensions: Readonly<{ width: number; height: number }>;\n\n /**\n * Size for generated thumbnails.\n * @default { width: 200, height: 200 }\n */\n readonly thumbnailSize: Readonly<{ width: number; height: number }>;\n\n /**\n * Whether drag and drop is enabled for file uploads.\n * @default true\n */\n readonly dragAndDrop: boolean;\n\n /**\n * Whether to allow pasting files from clipboard.\n * @default true\n */\n readonly pasteFromClipboard: boolean;\n}\n\n// ============================================================================\n// Virtual Scroll Configuration\n// ============================================================================\n\n/**\n * Configuration for virtual scrolling.\n */\nexport interface ChatVirtualScrollConfig {\n /**\n * Whether virtual scrolling is enabled.\n * @default true\n */\n readonly enabled: boolean;\n\n /**\n * Minimum number of messages before virtual scrolling activates.\n * @default 100\n */\n readonly threshold: number;\n\n /**\n * Default item height in pixels for initial calculations.\n * @default 80\n */\n readonly defaultItemHeight: number;\n\n /**\n * Number of items to render outside the visible viewport.\n * @default 5\n */\n readonly bufferSize: number;\n\n /**\n * Whether to cache item heights for variable-height items.\n * @default true\n */\n readonly cacheItemHeights: boolean;\n}\n\n// ============================================================================\n// Error Recovery Configuration\n// ============================================================================\n\n/**\n * Configuration for error recovery and retry behavior.\n */\nexport interface ChatErrorRecoveryConfig {\n /**\n * Whether to automatically retry failed messages.\n * @default true\n */\n readonly autoRetry: boolean;\n\n /**\n * Maximum number of retry attempts.\n * @default 3\n */\n readonly maxRetries: number;\n\n /**\n * Base delay in milliseconds between retries.\n * @default 1000\n */\n readonly retryDelay: number;\n\n /**\n * Whether to use exponential backoff for retries.\n * @default true\n */\n readonly exponentialBackoff: boolean;\n\n /**\n * Maximum delay in milliseconds between retries.\n * @default 30000 (30 seconds)\n */\n readonly maxRetryDelay: number;\n\n /**\n * Whether to queue messages when offline.\n * @default true\n */\n readonly offlineQueue: boolean;\n\n /**\n * Maximum number of messages in the offline queue.\n * @default 50\n */\n readonly maxQueueSize: number;\n}\n\n// ============================================================================\n// Keyboard Configuration\n// ============================================================================\n\n/**\n * Configuration for keyboard shortcuts.\n */\nexport interface ChatKeyboardConfig {\n /**\n * Send message on Enter key.\n * @default true\n */\n readonly sendOnEnter: boolean;\n\n /**\n * Send message on Ctrl/Cmd + Enter.\n * @default false\n */\n readonly sendOnCtrlEnter: boolean;\n\n /**\n * Clear input on Escape key.\n * @default false\n */\n readonly escToClear: boolean;\n\n /**\n * Cancel action (close dropdown, etc.) on Escape key.\n * @default true\n */\n readonly escToCancelAction: boolean;\n\n /**\n * Navigate action options with arrow keys.\n * @default true\n */\n readonly arrowKeysForActions: boolean;\n\n /**\n * Edit last sent message on Arrow Up when input is empty.\n * @default false\n */\n readonly upToEditLast: boolean;\n\n /**\n * Whether to trap focus within the chat component.\n * @default false\n */\n readonly focusTrap: boolean;\n}\n\n// ============================================================================\n// Combined Configuration\n// ============================================================================\n\n/**\n * Theme setting for the chat component.\n * - 'light': Force light theme\n * - 'dark': Force dark theme\n * - 'auto': Follow system preference\n */\nexport type ChatTheme = 'light' | 'dark' | 'auto';\n\n/**\n * Text direction setting.\n * - 'ltr': Left-to-right\n * - 'rtl': Right-to-left\n * - 'auto': Detect from content/document\n */\nexport type ChatDirection = 'ltr' | 'rtl' | 'auto';\n\n/**\n * Complete configuration for the chat component.\n * All properties are readonly for immutability.\n */\nexport interface ChatConfig {\n /**\n * Behavior and UX settings.\n */\n readonly behavior: ChatBehaviorConfig;\n\n /**\n * Message validation and sanitization settings.\n */\n readonly validation: ChatValidationConfig;\n\n /**\n * Markdown rendering settings.\n */\n readonly markdown: ChatMarkdownConfig;\n\n /**\n * File attachment settings.\n */\n readonly attachments: ChatAttachmentConfig;\n\n /**\n * Virtual scrolling settings.\n */\n readonly virtualScroll: ChatVirtualScrollConfig;\n\n /**\n * Error recovery and retry settings.\n */\n readonly errorRecovery: ChatErrorRecoveryConfig;\n\n /**\n * Keyboard shortcut settings.\n */\n readonly keyboard: ChatKeyboardConfig;\n\n /**\n * Theme setting.\n * @default 'auto'\n */\n readonly theme: ChatTheme;\n\n /**\n * Text direction.\n * @default 'auto'\n */\n readonly direction: ChatDirection;\n}\n\n/**\n * Partial configuration for overriding defaults.\n * Use this type when accepting user configuration input.\n */\nexport type ChatConfigInput = DeepPartial<ChatConfig>;\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\n/**\n * Default behavior configuration.\n */\nexport const DEFAULT_BEHAVIOR_CONFIG: ChatBehaviorConfig = {\n sendOnEnter: true,\n showTimestamps: true,\n timestampFormat: { hour: 'numeric', minute: '2-digit' },\n autoScroll: true,\n groupMessages: true,\n groupTimeThreshold: 60000, // 1 minute\n sendCooldown: 500,\n typingDebounce: 300,\n scrollNearBottomThreshold: 100,\n showSenderName: true,\n showAvatar: true,\n avatarPosition: 'bottom',\n};\n\n/**\n * Default validation configuration.\n */\nexport const DEFAULT_VALIDATION_CONFIG: ChatValidationConfig = {\n minMessageLength: 0,\n maxMessageLength: 5000,\n forbiddenPatterns: [],\n sanitize: true,\n trimWhitespace: true,\n allowEmptyContent: true,\n maxWordLength: 50,\n normalizeUnicode: true,\n stripInvisibleChars: true,\n};\n\n/**\n * Default markdown configuration.\n */\nexport const DEFAULT_MARKDOWN_CONFIG: ChatMarkdownConfig = {\n enabled: true,\n syntaxHighlighting: true,\n sanitizeLinks: true,\n externalLinksNewTab: true,\n allowedTags: [\n 'p',\n 'br',\n 'strong',\n 'em',\n 'code',\n 'pre',\n 'a',\n 'ul',\n 'ol',\n 'li',\n 'blockquote',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n ],\n allowedAttributes: {\n a: ['href', 'title'],\n '*': ['class'],\n },\n breaks: true,\n linkify: true,\n};\n\n/**\n * Default attachment configuration.\n */\nexport const DEFAULT_ATTACHMENT_CONFIG: ChatAttachmentConfig = {\n enabled: true,\n maxFileSize: 10 * 1024 * 1024, // 10 MB\n maxFilesPerMessage: 5,\n allowedMimeTypes: [],\n blockedMimeTypes: ['application/x-executable', 'application/x-msdownload'],\n imageCompression: true,\n imageCompressionQuality: 0.8,\n maxImageDimensions: { width: 2048, height: 2048 },\n thumbnailSize: { width: 200, height: 200 },\n dragAndDrop: true,\n pasteFromClipboard: true,\n};\n\n/**\n * Default virtual scroll configuration.\n */\nexport const DEFAULT_VIRTUAL_SCROLL_CONFIG: ChatVirtualScrollConfig = {\n enabled: true,\n threshold: 100,\n defaultItemHeight: 80,\n bufferSize: 5,\n cacheItemHeights: true,\n};\n\n/**\n * Default error recovery configuration.\n */\nexport const DEFAULT_ERROR_RECOVERY_CONFIG: ChatErrorRecoveryConfig = {\n autoRetry: true,\n maxRetries: 3,\n retryDelay: 1000,\n exponentialBackoff: true,\n maxRetryDelay: 30000, // 30 seconds\n offlineQueue: true,\n maxQueueSize: 50,\n};\n\n/**\n * Default keyboard configuration.\n */\nexport const DEFAULT_KEYBOARD_CONFIG: ChatKeyboardConfig = {\n sendOnEnter: true,\n sendOnCtrlEnter: false,\n escToClear: false,\n escToCancelAction: true,\n arrowKeysForActions: true,\n upToEditLast: false,\n focusTrap: false,\n};\n\n/**\n * Complete default configuration for ngx-chat.\n * Use this as a base and merge with user overrides using DeepPartial.\n *\n * @example\n * ```typescript\n * // In app.config.ts\n * provideChat({\n * config: {\n * behavior: { sendOnEnter: false },\n * theme: 'dark'\n * }\n * });\n * ```\n */\nexport const DEFAULT_CHAT_CONFIG: ChatConfig = {\n behavior: DEFAULT_BEHAVIOR_CONFIG,\n validation: DEFAULT_VALIDATION_CONFIG,\n markdown: DEFAULT_MARKDOWN_CONFIG,\n attachments: DEFAULT_ATTACHMENT_CONFIG,\n virtualScroll: DEFAULT_VIRTUAL_SCROLL_CONFIG,\n errorRecovery: DEFAULT_ERROR_RECOVERY_CONFIG,\n keyboard: DEFAULT_KEYBOARD_CONFIG,\n theme: 'auto',\n direction: 'auto',\n};\n","/**\n * @fileoverview Internationalization interface and defaults for ngx-chat.\n * Provides all user-facing strings with support for parameter interpolation.\n * @module ngx-chat/models/i18n\n */\n\n// ============================================================================\n// I18n Interface\n// ============================================================================\n\n/**\n * Internationalization interface for all user-facing strings in ngx-chat.\n *\n * Parameter interpolation uses the `{paramName}` format. Components will\n * replace these placeholders with actual values at runtime.\n *\n * @example\n * ```typescript\n * // Custom i18n configuration\n * provideChat({\n * i18n: {\n * send: 'Enviar',\n * placeholder: 'Escribe un mensaje...',\n * typing: '{name} está escribiendo...',\n * }\n * });\n * ```\n */\nexport interface ChatI18n {\n // ==========================================================================\n // Action Buttons\n // ==========================================================================\n\n /**\n * Label for the send button.\n * @default \"Send\"\n */\n readonly send: string;\n\n /**\n * Label for cancel buttons.\n * @default \"Cancel\"\n */\n readonly cancel: string;\n\n /**\n * Label for confirm buttons.\n * @default \"Confirm\"\n */\n readonly confirm: string;\n\n /**\n * Label for submit buttons (multi-select, forms).\n * @default \"Submit\"\n */\n readonly submit: string;\n\n /**\n * Label for retry buttons on failed messages.\n * @default \"Retry\"\n */\n readonly retry: string;\n\n // ==========================================================================\n // Input\n // ==========================================================================\n\n /**\n * Placeholder text for the message input.\n * @default \"Type a message...\"\n */\n readonly placeholder: string;\n\n /**\n * Message shown when chat has no messages.\n * @default \"No messages yet\"\n */\n readonly emptyState: string;\n\n // ==========================================================================\n // Typing Indicator\n // ==========================================================================\n\n /**\n * Typing indicator with sender name.\n * Parameter: `{name}` - The name of the person typing.\n * @default \"{name} is typing...\"\n */\n readonly typing: string;\n\n /**\n * Typing indicator when sender is unknown.\n * @default \"Someone is typing...\"\n */\n readonly someoneTyping: string;\n\n // ==========================================================================\n // Message Status\n // ==========================================================================\n\n /**\n * Status label when message is being sent.\n * @default \"Sending...\"\n */\n readonly sending: string;\n\n /**\n * Status label when message has been sent.\n * @default \"Sent\"\n */\n readonly sent: string;\n\n /**\n * Status label when message has been delivered.\n * @default \"Delivered\"\n */\n readonly delivered: string;\n\n /**\n * Status label when message has been read.\n * @default \"Read\"\n */\n readonly read: string;\n\n /**\n * Status label for messages with errors.\n * @default \"Failed to send\"\n */\n readonly error: string;\n\n // ==========================================================================\n // Confirm Action\n // ==========================================================================\n\n /**\n * Label for the \"Yes\" button in confirm actions.\n * @default \"Yes\"\n */\n readonly confirmYes: string;\n\n /**\n * Label for the \"No\" button in confirm actions.\n * @default \"No\"\n */\n readonly confirmNo: string;\n\n /**\n * Status text after confirming an action.\n * @default \"Confirmed\"\n */\n readonly confirmed: string;\n\n /**\n * Status text after cancelling an action.\n * @default \"Cancelled\"\n */\n readonly cancelled: string;\n\n // ==========================================================================\n // Selection Actions\n // ==========================================================================\n\n /**\n * Status text when an option has been selected.\n * @default \"Selected\"\n */\n readonly selected: string;\n\n /**\n * Counter text for multi-select showing number selected.\n * Parameter: `{count}` - Number of items selected.\n * @default \"{count} selected\"\n */\n readonly selectedCount: string;\n\n /**\n * Label for displaying number of options available.\n * @default \"options\"\n */\n readonly options: string;\n\n /**\n * Placeholder for search input in select/multi-select.\n * @default \"Search...\"\n */\n readonly searchPlaceholder: string;\n\n /**\n * ARIA label for search input in select/multi-select.\n * @default \"Search options\"\n */\n readonly searchOptions: string;\n\n /**\n * ARIA label for clear search button.\n * @default \"Clear search\"\n */\n readonly clearSearch: string;\n\n /**\n * Message shown when no options match search filter.\n * @default \"No options found\"\n */\n readonly noOptionsFound: string;\n\n // ==========================================================================\n // Action ARIA Labels\n // ==========================================================================\n\n /**\n * ARIA label for the message actions container.\n * @default \"Message actions\"\n */\n readonly messageActions: string;\n\n /**\n * ARIA label for confirm action.\n * @default \"Confirmation action\"\n */\n readonly actionConfirm: string;\n\n /**\n * ARIA label for select action.\n * @default \"Selection action\"\n */\n readonly actionSelect: string;\n\n /**\n * ARIA label for multi-select action.\n * @default \"Multiple selection action\"\n */\n readonly actionMultiSelect: string;\n\n /**\n * ARIA label for buttons action.\n * @default \"Button choices\"\n */\n readonly actionButtons: string;\n\n // ==========================================================================\n // Attachments\n // ==========================================================================\n\n /**\n * Label for a single attachment.\n * @default \"Attachment\"\n */\n readonly attachment: string;\n\n /**\n * Label for multiple attachments.\n * Parameter: `{count}` - Number of attachments.\n * @default \"{count} attachments\"\n */\n readonly attachments: string;\n\n /**\n * Error message when file exceeds size limit.\n * Parameter: `{maxSize}` - Maximum allowed file size.\n * @default \"File is too large. Maximum size is {maxSize}.\"\n */\n readonly fileTooLarge: string;\n\n /**\n * Error message when file type is not allowed.\n * @default \"This file type is not allowed.\"\n */\n readonly fileTypeNotAllowed: string;\n\n /**\n * Label for attachment picker button.\n * @default \"Add attachment\"\n */\n readonly addAttachment: string;\n\n /**\n * Label for removing an attachment.\n * @default \"Remove attachment\"\n */\n readonly removeAttachment: string;\n\n // ==========================================================================\n // Loading States\n // ==========================================================================\n\n /**\n * Label for general loading state.\n * @default \"Loading...\"\n */\n readonly loading: string;\n\n /**\n * Label for load more button/link.\n * @default \"Load more messages\"\n */\n readonly loadMore: string;\n\n /**\n * Label when loading older messages.\n * @default \"Loading older messages...\"\n */\n readonly loadingMore: string;\n\n // ==========================================================================\n // ARIA Labels (Accessibility)\n // ==========================================================================\n\n /**\n * ARIA label for the message list container.\n * @default \"Chat messages\"\n */\n readonly ariaMessageList: string;\n\n /**\n * ARIA label for the message input.\n * @default \"Message input\"\n */\n readonly ariaMessageInput: string;\n\n /**\n * ARIA announcement for new messages.\n * Parameter: `{sender}` - Name of the message sender.\n * @default \"New message from {sender}\"\n */\n readonly ariaNewMessage: string;\n\n /**\n * ARIA label for the send button.\n * @default \"Send message\"\n */\n readonly ariaSendButton: string;\n\n /**\n * ARIA label for the typing indicator.\n * @default \"Typing indicator\"\n */\n readonly ariaTypingIndicator: string;\n\n /**\n * ARIA label for message status.\n * Parameter: `{status}` - Current message status.\n * @default \"Message status: {status}\"\n */\n readonly ariaMessageStatus: string;\n\n /**\n * ARIA label for attachment picker.\n * @default \"Choose file to attach\"\n */\n readonly ariaAttachmentPicker: string;\n\n /**\n * ARIA label for retry button.\n * @default \"Retry sending message\"\n */\n readonly ariaRetryButton: string;\n\n /**\n * ARIA label for remove attachment button.\n * Parameter: `{name}` - The file name being removed.\n * @default \"Remove {name}\"\n */\n readonly ariaRemoveAttachment: string;\n\n /**\n * ARIA label for retry upload button.\n * @default \"Retry upload\"\n */\n readonly ariaRetryUpload: string;\n\n // ==========================================================================\n // Sender Labels\n // ==========================================================================\n\n /**\n * Label for the current user's messages.\n * @default \"You\"\n */\n readonly you: string;\n\n /**\n * Label for other users when name is unknown.\n * @default \"Someone\"\n */\n readonly other: string;\n\n // ==========================================================================\n // Time & Date\n // ==========================================================================\n\n /**\n * Label indicating a message was edited.\n * @default \"Edited\"\n */\n readonly edited: string;\n\n /**\n * Label for messages sent today.\n * @default \"Today\"\n */\n readonly today: string;\n\n /**\n * Label for messages sent yesterday.\n * @default \"Yesterday\"\n */\n readonly yesterday: string;\n\n // ==========================================================================\n // Validation Messages\n // ==========================================================================\n\n /**\n * Error message when message is too short.\n * Parameter: `{minLength}` - Minimum required length.\n * @default \"Message must be at least {minLength} characters\"\n */\n readonly messageTooShort: string;\n\n /**\n * Error message when message is too long.\n * Parameter: `{maxLength}` - Maximum allowed length.\n * @default \"Message cannot exceed {maxLength} characters\"\n */\n readonly messageTooLong: string;\n\n /**\n * Character counter display.\n * Parameters: `{current}`, `{max}` - Current and maximum character count.\n * @default \"{current} / {max}\"\n */\n readonly characterCount: string;\n}\n\n// ============================================================================\n// Default I18n Values\n// ============================================================================\n\n/**\n * Default English internationalization strings for ngx-chat.\n * Use this as a base and merge with custom translations.\n *\n * @example\n * ```typescript\n * // In app.config.ts\n * provideChat({\n * i18n: {\n * ...DEFAULT_CHAT_I18N,\n * send: 'Enviar', // Override specific strings\n * }\n * });\n * ```\n */\nexport const DEFAULT_CHAT_I18N: ChatI18n = {\n // Action Buttons\n send: 'Send',\n cancel: 'Cancel',\n confirm: 'Confirm',\n submit: 'Submit',\n retry: 'Retry',\n\n // Input\n placeholder: 'Type a message...',\n emptyState: 'No messages yet',\n\n // Typing Indicator\n typing: '{name} is typing...',\n someoneTyping: 'Someone is typing...',\n\n // Message Status\n sending: 'Sending...',\n sent: 'Sent',\n delivered: 'Delivered',\n read: 'Read',\n error: 'Failed to send',\n\n // Confirm Action\n confirmYes: 'Yes',\n confirmNo: 'No',\n confirmed: 'Confirmed',\n cancelled: 'Cancelled',\n\n // Selection Actions\n selected: 'Selected',\n selectedCount: '{count} selected',\n options: 'options',\n searchPlaceholder: 'Search...',\n searchOptions: 'Search options',\n clearSearch: 'Clear search',\n noOptionsFound: 'No options found',\n\n // Action ARIA Labels\n messageActions: 'Message actions',\n actionConfirm: 'Confirmation action',\n actionSelect: 'Selection action',\n actionMultiSelect: 'Multiple selection action',\n actionButtons: 'Button choices',\n\n // Attachments\n attachment: 'Attachment',\n attachments: '{count} attachments',\n fileTooLarge: 'File is too large. Maximum size is {maxSize}.',\n fileTypeNotAllowed: 'This file type is not allowed.',\n addAttachment: 'Add attachment',\n removeAttachment: 'Remove attachment',\n\n // Loading States\n loading: 'Loading...',\n loadMore: 'Load more messages',\n loadingMore: 'Loading older messages...',\n\n // ARIA Labels\n ariaMessageList: 'Chat messages',\n ariaMessageInput: 'Message input',\n ariaNewMessage: 'New message from {sender}',\n ariaSendButton: 'Send message',\n ariaTypingIndicator: 'Typing indicator',\n ariaMessageStatus: 'Message status: {status}',\n ariaAttachmentPicker: 'Choose file to attach',\n ariaRetryButton: 'Retry sending message',\n ariaRemoveAttachment: 'Remove {name}',\n ariaRetryUpload: 'Retry upload',\n\n // Sender Labels\n you: 'You',\n other: 'Someone',\n\n // Time & Date\n edited: 'Edited',\n today: 'Today',\n yesterday: 'Yesterday',\n\n // Validation Messages\n messageTooShort: 'Message must be at least {minLength} characters',\n messageTooLong: 'Message cannot exceed {maxLength} characters',\n characterCount: '{current} / {max}',\n};\n","/**\n * @fileoverview Injection token for ChatConfig.\n * Provides configuration to the ngx-chat library via Angular DI.\n * @module ngx-chat/tokens/chat-config\n */\n\nimport { InjectionToken } from '@angular/core';\nimport {\n ChatConfig,\n ChatConfigInput,\n DEFAULT_CHAT_CONFIG,\n} from '../models/config.model';\n\n/**\n * Injection token for the complete chat configuration.\n *\n * This token provides the resolved ChatConfig to components and services.\n * Use `provideChat()` to configure at the application level.\n *\n * @example\n * ```typescript\n * // In a component or service\n * private readonly config = inject(CHAT_CONFIG);\n *\n * // Access configuration\n * const sendOnEnter = this.config.behavior.sendOnEnter;\n * ```\n */\nexport const CHAT_CONFIG = new InjectionToken<ChatConfig>('CHAT_CONFIG', {\n providedIn: 'root',\n factory: () => DEFAULT_CHAT_CONFIG,\n});\n\n/**\n * Injection token for partial configuration overrides.\n *\n * This token is used internally to collect user-provided overrides\n * before merging with defaults. Not typically used directly.\n *\n * @internal\n */\nexport const CHAT_CONFIG_OVERRIDES = new InjectionToken<ChatConfigInput>(\n 'CHAT_CONFIG_OVERRIDES'\n);\n","/**\n * @fileoverview Injection token for ChatI18n.\n * Provides internationalization strings to the ngx-chat library via Angular DI.\n * @module ngx-chat/tokens/chat-i18n\n */\n\nimport { InjectionToken } from '@angular/core';\nimport { ChatI18n, DEFAULT_CHAT_I18N } from '../models/i18n.model';\nimport { DeepPartial } from '../models/config.model';\n\n/**\n * Injection token for the complete i18n strings.\n *\n * This token provides the resolved ChatI18n strings to components and services.\n * Use `provideChat()` to configure at the application level.\n *\n * @example\n * ```typescript\n * // In a component or service\n * private readonly i18n = inject(CHAT_I18N);\n *\n * // Access strings\n * const sendLabel = this.i18n.send;\n * const placeholder = this.i18n.placeholder;\n * ```\n */\nexport const CHAT_I18N = new InjectionToken<ChatI18n>('CHAT_I18N', {\n providedIn: 'root',\n factory: () => DEFAULT_CHAT_I18N,\n});\n\n/**\n * Injection token for partial i18n overrides.\n *\n * This token is used internally to collect user-provided translations\n * before merging with defaults. Not typically used directly.\n *\n * @internal\n */\nexport const CHAT_I18N_OVERRIDES = new InjectionToken<DeepPartial<ChatI18n>>(\n 'CHAT_I18N_OVERRIDES'\n);\n","/**\n * @fileoverview Provider function for configuring ngx-chat.\n * Use `provideChat()` in your app.config.ts to configure the library.\n * @module ngx-chat/provide-chat\n */\n\nimport {\n EnvironmentProviders,\n makeEnvironmentProviders,\n} from '@angular/core';\nimport {\n ChatConfig,\n ChatConfigInput,\n DEFAULT_CHAT_CONFIG,\n} from './models/config.model';\nimport { ChatI18n, DEFAULT_CHAT_I18N } from './models/i18n.model';\nimport { DeepPartial } from './models/config.model';\nimport { CHAT_CONFIG } from './tokens/chat-config.token';\nimport { CHAT_I18N } from './tokens/chat-i18n.token';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Configuration options for `provideChat()`.\n *\n * All options are optional. Defaults are used for any unspecified values.\n *\n * @example\n * ```typescript\n * provideChat({\n * config: {\n * behavior: { sendOnEnter: false },\n * theme: 'dark'\n * },\n * i18n: {\n * send: 'Enviar',\n * placeholder: 'Escribe un mensaje...'\n * }\n * })\n * ```\n */\nexport interface ProvideChatOptions {\n /**\n * Partial configuration overrides.\n * Deeply merged with DEFAULT_CHAT_CONFIG.\n */\n readonly config?: ChatConfigInput;\n\n /**\n * Partial i18n string overrides.\n * Merged with DEFAULT_CHAT_I18N.\n */\n readonly i18n?: DeepPartial<ChatI18n>;\n}\n\n// ============================================================================\n// Deep Merge Utility\n// ============================================================================\n\n/**\n * Checks if a value is a plain object (not array, null, or other types).\n * @internal\n */\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.prototype.toString.call(value) === '[object Object]'\n );\n}\n\n/**\n * Recursively deep merges source object into target.\n *\n * Merge rules:\n * - Nested objects are recursively merged\n * - Arrays are replaced (not merged)\n * - Primitive values are replaced\n * - Undefined values in source are ignored\n *\n * @internal\n */\nfunction deepMerge<T extends Record<string, unknown>>(\n target: T,\n source: Partial<T> | undefined\n): T {\n if (!source || Object.keys(source).length === 0) {\n return target;\n }\n\n const result = { ...target } as Record<string, unknown>;\n\n for (const key of Object.keys(source)) {\n const sourceValue = (source as Record<string, unknown>)[key];\n const targetValue = (target as Record<string, unknown>)[key];\n\n // Skip undefined source values\n if (sourceValue === undefined) {\n continue;\n }\n\n // Handle nested objects (but not arrays)\n if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {\n result[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else {\n // Replace arrays and primitives\n result[key] = sourceValue;\n }\n }\n\n return result as T;\n}\n\n// ============================================================================\n// Provider Function\n// ============================================================================\n\n/**\n * Provides ngx-chat configuration for an Angular application.\n *\n * Use this function in your `app.config.ts` to configure the chat library.\n * All options are optional - defaults are used for any unspecified values.\n *\n * @param options - Optional configuration and i18n overrides\n * @returns Environment providers for Angular DI\n *\n * @example\n * ```typescript\n * // app.config.ts - Minimal setup (uses all defaults)\n * import { provideChat } from 'ngx-chat';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideZoneChangeDetection({ eventCoalescing: true }),\n * provideChat()\n * ]\n * };\n * ```\n *\n * @example\n * ```typescript\n * // app.config.ts - With configuration\n * import { provideChat } from 'ngx-chat';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideZoneChangeDetection({ eventCoalescing: true }),\n * provideChat({\n * config: {\n * behavior: {\n * sendOnEnter: true,\n * showTimestamps: true,\n * autoScroll: true,\n * groupMessages: true,\n * },\n * markdown: {\n * enabled: true,\n * syntaxHighlighting: true,\n * },\n * attachments: {\n * enabled: true,\n * maxFileSize: 10 * 1024 * 1024,\n * },\n * errorRecovery: {\n * autoRetry: true,\n * maxRetries: 3,\n * offlineQueue: true,\n * },\n * theme: 'auto',\n * },\n * i18n: {\n * send: 'Send',\n * placeholder: 'Type a message...',\n * }\n * })\n * ]\n * };\n * ```\n *\n * @example\n * ```typescript\n * // app.config.ts - Spanish localization\n * import { provideChat } from 'ngx-chat';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideChat({\n * config: {\n * theme: 'dark'\n * },\n * i18n: {\n * send: 'Enviar',\n * cancel: 'Cancelar',\n * confirm: 'Confirmar',\n * placeholder: 'Escribe un mensaje...',\n * typing: '{name} está escribiendo...',\n * someoneTyping: 'Alguien está escribiendo...',\n * sending: 'Enviando...',\n * sent: 'Enviado',\n * delivered: 'Entregado',\n * read: 'Leído',\n * error: 'Error al enviar',\n * }\n * })\n * ]\n * };\n * ```\n */\nexport function provideChat(\n options?: ProvideChatOptions\n): EnvironmentProviders {\n // Merge user config with defaults\n const mergedConfig = deepMerge(\n DEFAULT_CHAT_CONFIG as unknown as Record<string, unknown>,\n options?.config as unknown as Record<string, unknown> | undefined\n ) as unknown as ChatConfig;\n\n // Merge user i18n with defaults\n const mergedI18n = deepMerge(\n DEFAULT_CHAT_I18N as unknown as Record<string, unknown>,\n options?.i18n as unknown as Record<string, unknown> | undefined\n ) as unknown as ChatI18n;\n\n return makeEnvironmentProviders([\n {\n provide: CHAT_CONFIG,\n useValue: mergedConfig,\n },\n {\n provide: CHAT_I18N,\n useValue: mergedI18n,\n },\n ]);\n}\n","/**\n * @fileoverview Configuration service for ngx-chat.\n * Provides merged configuration with caching and i18n string formatting.\n * @module ngx-chat/services/chat-config\n */\n\nimport { Injectable, inject } from '@angular/core';\nimport {\n ChatConfig,\n ChatConfigInput,\n DeepPartial,\n} from '../models/config.model';\nimport { ChatI18n } from '../models/i18n.model';\nimport { CHAT_CONFIG } from '../tokens/chat-config.token';\nimport { CHAT_I18N } from '../tokens/chat-i18n.token';\n\n/**\n * Service for accessing and merging chat configuration.\n *\n * Provides:\n * - Deep merging of configuration overrides with defaults\n * - Caching of merged configurations for performance\n * - i18n string access with parameter interpolation\n *\n * @example\n * ```typescript\n * @Component({...})\n * export class MyComponent {\n * private readonly configService = inject(ChatConfigService);\n *\n * // Get full config with optional overrides\n * readonly config = this.configService.getConfig({\n * behavior: { sendOnEnter: false }\n * });\n *\n * // Format i18n string with parameters\n * readonly typingLabel = this.configService.formatI18n('typing', { name: 'John' });\n * // Result: \"John is typing...\"\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ChatConfigService {\n private readonly baseConfig = inject(CHAT_CONFIG);\n private readonly baseI18n = inject(CHAT_I18N);\n\n /**\n * Cache for merged configurations.\n * Keys are JSON-stringified overrides, values are merged configs.\n */\n private readonly configCache = new Map<string, ChatConfig>();\n\n /**\n * Returns the merged configuration with optional overrides.\n *\n * Configuration is deeply merged: nested objects are recursively merged,\n * while arrays and primitives are replaced. Results are cached by the\n * JSON representation of the overrides for performance.\n *\n * @param overrides - Partial configuration to merge with defaults\n * @returns Complete merged configuration\n *\n * @example\n * ```typescript\n * // Get default config\n * const config = configService.getConfig();\n *\n * // Get config with overrides\n * const customConfig = configService.getConfig({\n * behavior: { sendOnEnter: false },\n * theme: 'dark'\n * });\n * ```\n */\n getConfig(overrides?: ChatConfigInput): ChatConfig {\n // Return base config if no overrides\n if (!overrides || Object.keys(overrides).length === 0) {\n return this.baseConfig;\n }\n\n // Check cache\n const cacheKey = JSON.stringify(overrides);\n const cached = this.configCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n // Deep merge and cache\n const merged = this.deepMerge(\n this.baseConfig as unknown as Record<string, unknown>,\n overrides as Record<string, unknown>\n ) as unknown as ChatConfig;\n this.configCache.set(cacheKey, merged);\n\n return merged;\n }\n\n /**\n * Returns the i18n strings.\n *\n * @returns Complete i18n interface with all translatable strings\n *\n * @example\n * ```typescript\n * const i18n = configService.getI18n();\n * console.log(i18n.send); // \"Send\"\n * console.log(i18n.placeholder); // \"Type a message...\"\n * ```\n */\n getI18n(): ChatI18n {\n return this.baseI18n;\n }\n\n /**\n * Formats an i18n string by replacing parameter placeholders with values.\n *\n * Parameter placeholders use the `{paramName}` format and are replaced\n * with corresponding values from the params object.\n *\n * @param key - The i18n key to format\n * @param params - Object with parameter values to interpolate\n * @returns Formatted string with parameters replaced\n *\n * @example\n * ```typescript\n * // i18n.typing = \"{name} is typing...\"\n * configService.formatI18n('typing', { name: 'Alice' });\n * // Returns: \"Alice is typing...\"\n *\n * // i18n.selectedCount = \"{count} selected\"\n * configService.formatI18n('selectedCount', { count: 5 });\n * // Returns: \"5 selected\"\n *\n * // Multiple parameters\n * // i18n.characterCount = \"{current} / {max}\"\n * configService.formatI18n('characterCount', { current: 50, max: 500 });\n * // Returns: \"50 / 500\"\n * ```\n */\n formatI18n(\n key: keyof ChatI18n,\n params?: Record<string, string | number>\n ): string {\n const template = this.baseI18n[key];\n\n if (!params || Object.keys(params).length === 0) {\n return template;\n }\n\n return this.interpolateParams(template, params);\n }\n\n /**\n * Replaces `{paramName}` placeholders in a string with actual values.\n *\n * @param template - String containing `{paramName}` placeholders\n * @param params - Object with parameter values\n * @returns String with placeholders replaced\n */\n private interpolateParams(\n template: string,\n params: Record<string, string | number>\n ): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, paramName: string) => {\n const value = params[paramName];\n return value !== undefined ? String(value) : match;\n });\n }\n\n /**\n * Recursively deep merges source object into target.\n *\n * Merge rules:\n * - Nested objects are recursively merged\n * - Arrays are replaced (not merged)\n * - Primitive values are replaced\n * - Undefined values in source are ignored\n *\n * @param target - Base configuration object\n * @param source - Partial configuration with overrides\n * @returns New object with merged values\n */\n private deepMerge(\n target: Record<string, unknown>,\n source: Record<string, unknown>\n ): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target };\n\n for (const key of Object.keys(source)) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n // Skip undefined source values\n if (sourceValue === undefined) {\n continue;\n }\n\n // Handle nested objects (but not arrays)\n if (\n this.isPlainObject(sourceValue) &&\n this.isPlainObject(targetValue)\n ) {\n result[key] = this.deepMerge(targetValue, sourceValue);\n } else {\n // Replace arrays and primitives\n result[key] = sourceValue;\n }\n }\n\n return result;\n }\n\n /**\n * Checks if a value is a plain object (not array, null, or other types).\n *\n * @param value - Value to check\n * @returns True if value is a plain object\n */\n private isPlainObject(value: unknown): value is Record<string, unknown> {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.prototype.toString.call(value) === '[object Object]'\n );\n }\n\n /**\n * Clears the configuration cache.\n *\n * Useful for testing or when configuration needs to be re-evaluated.\n * In normal usage, the cache should not need to be cleared.\n */\n clearCache(): void {\n this.configCache.clear();\n }\n}\n","/**\n * @fileoverview Internal event bus service for ngx-chat component communication.\n * Enables child components to emit events that bubble up to the main ChatComponent.\n *\n * IMPORTANT: This service is NOT provided at root level. It must be provided\n * at the ChatComponent level to ensure each chat instance has isolated events.\n *\n * @module ngx-chat/services/chat-event\n */\n\nimport { Injectable } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\nimport { MessageActionEvent } from '../models/actions.model';\nimport { AttachmentClickEvent } from '../models/attachment.model';\nimport { ChatLoadMoreEvent, ChatRetryEvent } from '../models/message.model';\n\n/**\n * Internal event bus service for communication between child components\n * and the main ChatComponent.\n *\n * This service follows the pub/sub pattern:\n * - Child components call emit methods to publish events\n * - ChatComponent subscribes to observables and forwards to outputs\n *\n * **Important:** This service must NOT be `providedIn: 'root'`. It should be\n * provided at the ChatComponent level so each chat instance has its own\n * isolated event stream. Multiple chat instances on a page will each have\n * their own ChatEventService instance.\n *\n * @example\n * ```typescript\n * // In ChatComponent (provider)\n * @Component({\n * providers: [ChatEventService],\n * // ...\n * })\n * export class ChatComponent {\n * private readonly eventService = inject(ChatEventService);\n *\n * constructor() {\n * this.eventService.action$.subscribe(event => {\n * this.action.emit(event);\n * });\n * }\n * }\n *\n * // In child component (emitter)\n * @Component({...})\n * export class ActionComponent {\n * private readonly eventService = inject(ChatEventService);\n *\n * onConfirm(response: boolean) {\n * this.eventService.emitAction({\n * type: 'confirm',\n * messageId: this.messageId,\n * actionId: this.actionId,\n * response\n * });\n * }\n * }\n * ```\n */\n@Injectable()\nexport class ChatEventService {\n // ===========================================================================\n // Private Subjects\n // ===========================================================================\n\n /**\n * Subject for action response events.\n * Emitted when users interact with message actions (confirm, select, etc.)\n */\n private readonly actionSubject = new Subject<MessageActionEvent>();\n\n /**\n * Subject for retry request events.\n * Emitted when users click retry on a failed message.\n */\n private readonly retrySubject = new Subject<ChatRetryEvent>();\n\n /**\n * Subject for scroll-to-bottom commands.\n * Emitted when the chat should scroll to the latest message.\n */\n private readonly scrollToBottomSubject = new Subject<void>();\n\n /**\n * Subject for load-more events.\n * Emitted when the user scrolls to the top to load older messages.\n */\n private readonly loadMoreSubject = new Subject<ChatLoadMoreEvent>();\n\n /**\n * Subject for attachment click events.\n * Emitted when users click on message attachments.\n */\n private readonly attachmentClickSubject = new Subject<AttachmentClickEvent>();\n\n // ===========================================================================\n // Public Observables\n // ===========================================================================\n\n /**\n * Observable for action response events.\n * Subscribe to receive events when users respond to message actions.\n *\n * @example\n * ```typescript\n * this.eventService.action$.subscribe(event => {\n * switch (event.type) {\n * case 'confirm':\n * console.log('User confirmed:', event.response);\n * break;\n * case 'select':\n * console.log('User selected:', event.response);\n * break;\n * }\n * });\n * ```\n */\n readonly action$: Observable<MessageActionEvent> =\n this.actionSubject.asObservable();\n\n /**\n * Observable for retry request events.\n * Subscribe to receive events when users request to retry failed messages.\n *\n * @example\n * ```typescript\n * this.eventService.retry$.subscribe(event => {\n * this.retry.emit(event);\n * });\n * ```\n */\n readonly retry$: Observable<ChatRetryEvent> =\n this.retrySubject.asObservable();\n\n /**\n * Observable for scroll-to-bottom commands.\n * Subscribe to receive commands to scroll the chat to the bottom.\n *\n * @example\n * ```typescript\n * this.eventService.scrollToBottom$.subscribe(() => {\n * this.scrollbar.scrollTo({ bottom: 0 });\n * });\n * ```\n */\n readonly scrollToBottom$: Observable<void> =\n this.scrollToBottomSubject.asObservable();\n\n /**\n * Observable for load-more events.\n * Subscribe to receive events when users scroll to load older messages.\n *\n * @example\n * ```typescript\n * this.eventService.loadMore$.subscribe(event => {\n * this.loadMore.emit(event);\n * });\n * ```\n */\n readonly loadMore$: Observable<ChatLoadMoreEvent> =\n this.loadMoreSubject.asObservable();\n\n /**\n * Observable for attachment click events.\n * Subscribe to receive events when users click on attachments.\n *\n * @example\n * ```typescript\n * this.eventService.attachmentClick$.subscribe(event => {\n * if (event.action === 'preview') {\n * this.openLightbox(event.attachment);\n * }\n * });\n * ```\n */\n readonly attachmentClick$: Observable<AttachmentClickEvent> =\n this.attachmentClickSubject.asObservable();\n\n // ===========================================================================\n // Emit Methods\n // ===========================================================================\n\n /**\n * Emits an action response event.\n * Call this when a user responds to a message action.\n *\n * @param event - The action event containing the user's response\n *\n * @example\n * ```typescript\n * // Confirm action response\n * eventService.emitAction({\n * type: 'confirm',\n * messageId: 'msg-123',\n * actionId: 'action-456',\n * response: true\n * });\n *\n * // Select action response\n * eventService.emitAction({\n * type: 'select',\n * messageId: 'msg-123',\n * actionId: 'action-789',\n * response: 'option-1'\n * });\n * ```\n */\n emitAction(event: MessageActionEvent): void {\n this.actionSubject.next(event);\n }\n\n /**\n * Emits a retry request event.\n * Call this when a user clicks the retry button on a failed message.\n *\n * @param event - The retry event containing the message to retry\n *\n * @example\n * ```typescript\n * eventService.emitRetry({\n * messageId: 'msg-123',\n * message: failedMessage\n * });\n * ```\n */\n emitRetry(event: ChatRetryEvent): void {\n this.retrySubject.next(event);\n }\n\n /**\n * Emits a scroll-to-bottom command.\n * Call this to request the chat scroll to the latest message.\n *\n * @example\n * ```typescript\n * // After sending a message\n * eventService.emitScrollToBottom();\n * ```\n */\n emitScrollToBottom(): void {\n this.scrollToBottomSubject.next();\n }\n\n /**\n * Emits a load-more event.\n * Call this when the user scrolls to the top to load older messages.\n *\n * @param event - The load more event with pagination info\n *\n * @example\n * ```typescript\n * eventService.emitLoadMore({\n * beforeMessageId: oldestMessage.id,\n * count: 20\n * });\n * ```\n */\n emitLoadMore(event: ChatLoadMoreEvent): void {\n this.loadMoreSubject.next(event);\n }\n\n /**\n * Emits an attachment click event.\n * Call this when a user clicks on a message attachment.\n *\n * @param event - The attachment click event with attachment details\n *\n * @example\n * ```typescript\n * eventService.emitAttachmentClick({\n * messageId: 'msg-123',\n * attachment: imageAttachment,\n * action: 'preview'\n * });\n * ```\n */\n emitAttachmentClick(event: AttachmentClickEvent): void {\n this.attachmentClickSubject.next(event);\n }\n}\n","/**\n * @fileoverview Directive for marking header content templates in ngx-chat.\n * Used with contentChild() to query for projected header templates.\n * @module ngx-chat/directives/chat-header-content\n */\n\nimport { Directive, TemplateRef, inject } from '@angular/core';\n\n/**\n * Directive for projecting custom header content into the ChatComponent.\n *\n * Apply this directive to an `ng-template` element to provide custom header content.\n * The ChatComponent will query for this directive using `contentChild()` and render\n * the template in the header section.\n *\n * @example\n * ```html\n * <ngx-chat [messages]=\"messages()\">\n * <ng-template ngxChatHeaderContent>\n * <span>🤖 AI Assistant</span>\n * <button (click)=\"openSettings()\">⚙️</button>\n * </ng-template>\n * </ngx-chat>\n * ```\n *\n * @example\n * ```html\n * <!-- With context data -->\n * <ngx-chat [messages]=\"messages()\">\n * <ng-template ngxChatHeaderContent>\n * <div class=\"custom-header\">\n * <img [src]=\"agent.avatar\" alt=\"\">\n * <span>{{ agent.name }}</span>\n * <span class=\"status\">Online</span>\n * </div>\n * </ng-template>\n * </ngx-chat>\n * ```\n */\n@Directive({\n selector: '[ngxChatHeaderContent]',\n standalone: true,\n})\nexport class ChatHeaderContentDirective {\n /**\n * Reference to the template element this directive is attached to.\n * Used by ChatComponent to render the header content.\n */\n readonly templateRef = inject(TemplateRef<unknown>);\n}\n","/**\n * @fileoverview Chat header component for ngx-chat library.\n * Provides a styled container for header content with content projection.\n * @module ngx-chat/components/chat-header\n */\n\nimport { Component, ChangeDetectionStrategy, TemplateRef, input } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n/**\n * Chat header component.\n *\n * A simple presentational component that provides a styled container for header content.\n * Supports both direct content projection and template-based content.\n *\n * @example Direct content projection\n * ```html\n * <ngx-chat-header>\n * <span>🤖 AI Assistant</span>\n * </ngx-chat-header>\n * ```\n *\n * @example Template-based content (used internally by ChatComponent)\n * ```html\n * <ngx-chat-header [template]=\"headerTemplate\">\n * </ngx-chat-header>\n * ```\n *\n * @example With custom styling\n * ```html\n * <ngx-chat-header class=\"custom-header\">\n * <img src=\"avatar.png\" alt=\"Agent\">\n * <div>\n * <strong>Support Agent</strong>\n * <span>Online</span>\n * </div>\n * </ngx-chat-header>\n * ```\n */\n@Component({\n selector: 'ngx-chat-header',\n standalone: true,\n imports: [CommonModule],\n template: `\n @if (template()) {\n <ng-container *ngTemplateOutlet=\"template()!\" />\n } @else {\n <ng-content />\n }\n `,\n styleUrls: ['./chat-header.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-header',\n 'role': 'banner',\n },\n})\nexport class ChatHeaderComponent {\n /**\n * Optional template to render instead of projected content.\n * Used internally by ChatComponent when rendering directive-based headers.\n */\n readonly template = input<TemplateRef<unknown> | null>(null);\n}\n","/**\n * @fileoverview Validation and sanitization utilities for message content.\n * @module ngx-chat/utils/validation\n */\n\nimport { ChatValidationConfig } from '../models/config.model';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Result of message validation.\n *\n * @example\n * ```typescript\n * const result = validateMessage('Hello world', config);\n * if (!result.valid) {\n * console.error(result.error);\n * }\n * ```\n */\nexport interface ValidationResult {\n /**\n * Whether the content passed validation.\n */\n readonly valid: boolean;\n\n /**\n * Error message if validation failed, undefined otherwise.\n */\n readonly error?: string;\n\n /**\n * Error code for programmatic handling.\n * - 'empty': Content is empty when not allowed\n * - 'too_short': Content below minimum length\n * - 'too_long': Content exceeds maximum length\n * - 'forbidden_pattern': Content matches forbidden pattern\n */\n readonly errorCode?:\n | 'empty'\n | 'too_short'\n | 'too_long'\n | 'forbidden_pattern';\n\n /**\n * Sanitized/processed content if validation passed.\n * Includes trimming, unicode normalization, etc. based on config.\n */\n readonly sanitizedContent?: string;\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Zero-width space character (U+200B).\n * Used to insert word break opportunities in long words.\n */\nconst ZERO_WIDTH_SPACE = '\\u200B';\n\n/**\n * Regex pattern for invisible/control characters to strip.\n * Includes: zero-width joiner, zero-width non-joiner, object replacement,\n * soft hyphen, and various control characters.\n */\nconst INVISIBLE_CHARS_PATTERN =\n /[\\u200C\\u200D\\uFEFF\\u00AD\\u2060\\u2061\\u2062\\u2063\\u2064\\u2066\\u2067\\u2068\\u2069\\u206A\\u206B\\u206C\\u206D\\u206E\\u206F\\u034F\\u180B\\u180C\\u180D\\u180E\\uFFF9\\uFFFA\\uFFFB]/g;\n\n/**\n * Safe URL protocols for links.\n */\nconst SAFE_PROTOCOLS = ['http:', 'https:', 'mailto:'];\n\n/**\n * HTML entities map for sanitization.\n */\nconst HTML_ENTITIES: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n};\n\n// ============================================================================\n// Sanitization Functions\n// ============================================================================\n\n/**\n * Escapes HTML special characters to prevent XSS.\n *\n * Converts:\n * - `&` → `&`\n * - `<` → `<`\n * - `>` → `>`\n * - `\"` → `"`\n * - `'` → `'`\n *\n * @param content - The content to sanitize\n * @returns Content with HTML entities escaped\n *\n * @example\n * ```typescript\n * sanitizeContent('<script>alert(\"xss\")</script>');\n * // '<script>alert("xss")</script>'\n * ```\n */\nexport function sanitizeContent(content: string): string {\n if (!content) {\n return content;\n }\n\n return content.replace(/[&<>\"']/g, (char) => HTML_ENTITIES[char] || char);\n}\n\n/**\n * Removes invisible Unicode characters from content.\n *\n * Strips characters that are invisible but can affect text processing:\n * - Zero-width joiner (U+200D)\n * - Zero-width non-joiner (U+200C)\n * - Byte order mark (U+FEFF)\n * - Soft hyphen (U+00AD)\n * - Various formatting characters\n *\n * Note: Zero-width space (U+200B) is NOT stripped as it's used for word breaks.\n *\n * @param content - The content to process\n * @returns Content with invisible characters removed\n *\n * @example\n * ```typescript\n * stripInvisibleChars('Hello\\u200DWorld');\n * // 'HelloWorld'\n * ```\n */\nexport function stripInvisibleChars(content: string): string {\n if (!content) {\n return content;\n }\n\n return content.replace(INVISIBLE_CHARS_PATTERN, '');\n}\n\n/**\n * Inserts zero-width spaces into words exceeding the maximum length.\n *\n * This prevents long words (like URLs or technical strings) from breaking\n * layout by allowing the browser to wrap at the inserted break points.\n *\n * @param content - The content to process\n * @param maxLength - Maximum word length before breaking (default: 50)\n * @returns Content with zero-width spaces inserted in long words\n *\n * @example\n * ```typescript\n * breakLongWords('https://example.com/very/long/path/that/exceeds/limit', 20);\n * // Inserts \\u200B every 20 characters in the URL\n * ```\n */\nexport function breakLongWords(content: string, maxLength: number = 50): string {\n if (!content || maxLength <= 0) {\n return content;\n }\n\n // Match sequences of non-whitespace characters longer than maxLength\n const wordPattern = new RegExp(`(\\\\S{${maxLength}})`, 'g');\n\n return content.replace(wordPattern, (match) => {\n // Insert zero-width space after every maxLength characters\n const chunks: string[] = [];\n for (let i = 0; i < match.length; i += maxLength) {\n chunks.push(match.slice(i, i + maxLength));\n }\n return chunks.join(ZERO_WIDTH_SPACE);\n });\n}\n\n// ============================================================================\n// URL Validation\n// ============================================================================\n\n/**\n * Validates that a URL uses a safe protocol.\n *\n * Safe protocols are:\n * - http:\n * - https:\n * - mailto:\n *\n * This helps prevent JavaScript injection via `javascript:` URLs\n * and other potentially dangerous protocols.\n *\n * @param url - The URL to validate\n * @returns True if the URL uses a safe protocol, false otherwise\n *\n * @example\n * ```typescript\n * isSafeUrl('https://example.com'); // true\n * isSafeUrl('mailto:test@test.com'); // true\n * isSafeUrl('javascript:alert(1)'); // false\n * isSafeUrl('data:text/html,...'); // false\n * ```\n */\nexport function isSafeUrl(url: string): boolean {\n if (!url || typeof url !== 'string') {\n return false;\n }\n\n try {\n // Handle relative URLs by providing a base\n const urlObj = new URL(url, 'http://example.com');\n return SAFE_PROTOCOLS.includes(urlObj.protocol);\n } catch {\n // If URL parsing fails, check if it starts with a safe protocol\n const lowerUrl = url.toLowerCase().trim();\n return SAFE_PROTOCOLS.some(\n (protocol) =>\n lowerUrl.startsWith(protocol) ||\n lowerUrl.startsWith(protocol.replace(':', '://'))\n );\n }\n}\n\n// ============================================================================\n// Main Validation Function\n// ============================================================================\n\n/**\n * Validates message content against the provided configuration.\n *\n * Performs the following validations in order:\n * 1. Trimming (if enabled) - removes leading/trailing whitespace\n * 2. Empty check - validates content is not empty (unless allowed)\n * 3. Unicode normalization (if enabled) - normalizes to NFC form\n * 4. Invisible character stripping (if enabled)\n * 5. Minimum length check\n * 6. Maximum length check\n * 7. Forbidden pattern check\n * 8. Long word breaking (if configured)\n *\n * @param content - The message content to validate\n * @param config - Validation configuration options\n * @returns ValidationResult with valid status, error info, and sanitized content\n *\n * @example\n * ```typescript\n * const config: ChatValidationConfig = {\n * minMessageLength: 1,\n * maxMessageLength: 1000,\n * trimWhitespace: true,\n * normalizeUnicode: true,\n * stripInvisibleChars: true,\n * forbiddenPatterns: [/spam/i],\n * sanitize: true,\n * allowEmptyContent: false,\n * maxWordLength: 50,\n * };\n *\n * const result = validateMessage('Hello world!', config);\n * if (result.valid) {\n * console.log('Sanitized:', result.sanitizedContent);\n * } else {\n * console.error('Error:', result.error);\n * }\n * ```\n */\nexport function validateMessage(\n content: string,\n config: ChatValidationConfig\n): ValidationResult {\n let processedContent = content ?? '';\n\n // 1. Trim whitespace if configured\n if (config.trimWhitespace) {\n processedContent = processedContent.trim();\n }\n\n // 2. Check for empty content\n if (!processedContent && !config.allowEmptyContent) {\n return {\n valid: false,\n error: 'Message cannot be empty',\n errorCode: 'empty',\n };\n }\n\n // If content is empty but allowed, return valid with empty content\n if (!processedContent && config.allowEmptyContent) {\n return {\n valid: true,\n sanitizedContent: '',\n };\n }\n\n // 3. Normalize Unicode if configured\n if (config.normalizeUnicode) {\n processedContent = processedContent.normalize('NFC');\n }\n\n // 4. Strip invisible characters if configured\n if (config.stripInvisibleChars) {\n processedContent = stripInvisibleChars(processedContent);\n }\n\n // Re-trim after stripping invisible chars\n if (config.trimWhitespace) {\n processedContent = processedContent.trim();\n }\n\n // Re-check for empty after processing\n if (!processedContent && !config.allowEmptyContent) {\n return {\n valid: false,\n error: 'Message cannot be empty',\n errorCode: 'empty',\n };\n }\n\n // 5. Check minimum length\n if (\n config.minMessageLength > 0 &&\n processedContent.length < config.minMessageLength\n ) {\n return {\n valid: false,\n error: `Message must be at least ${config.minMessageLength} characters`,\n errorCode: 'too_short',\n };\n }\n\n // 6. Check maximum length\n if (\n config.maxMessageLength > 0 &&\n processedContent.length > config.maxMessageLength\n ) {\n return {\n valid: false,\n error: `Message cannot exceed ${config.maxMessageLength} characters`,\n errorCode: 'too_long',\n };\n }\n\n // 7. Check forbidden patterns\n for (const pattern of config.forbiddenPatterns) {\n if (pattern.test(processedContent)) {\n return {\n valid: false,\n error: 'Message contains forbidden content',\n errorCode: 'forbidden_pattern',\n };\n }\n }\n\n // 8. Break long words if configured\n if (config.maxWordLength > 0) {\n processedContent = breakLongWords(processedContent, config.maxWordLength);\n }\n\n // 9. Sanitize HTML if configured (for display purposes)\n // Note: This is basic HTML escaping. Full XSS protection should use DOMPurify\n // in the markdown service for rendered content.\n let sanitizedContent = processedContent;\n if (config.sanitize) {\n sanitizedContent = sanitizeContent(processedContent);\n }\n\n return {\n valid: true,\n sanitizedContent,\n };\n}\n","/**\n * @fileoverview Chat sender component for ngx-chat library.\n * Provides message input with validation, typing indicators, and keyboard shortcuts.\n * @module ngx-chat/components/chat-sender\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n computed,\n DestroyRef,\n ElementRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\n\nimport type { ChatConfig, ChatConfigInput } from '../../models/config.model';\nimport type { ChatSendEvent, ChatTypingEvent, PendingAttachmentRef } from '../../models/message.model';\nimport { ChatConfigService } from '../../services/chat-config.service';\nimport { validateMessage, ValidationResult } from '../../utils/validation.utils';\n\n/**\n * Chat sender component.\n *\n * Provides message input functionality with:\n * - Auto-resizing textarea\n * - Typing indicator emission with debounce\n * - Send on Enter (configurable)\n * - Validation with error display\n * - Character count (when near limit)\n * - Send cooldown to prevent spam\n * - Keyboard shortcuts from config\n * - Cleanup on destroy using DestroyRef\n *\n * This component is purely presentational. It emits send and typing events\n * for the parent component to handle.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-sender\n * (send)=\"onSend($event)\"\n * (typing)=\"onTyping($event)\"\n * />\n * ```\n *\n * @example With disabled state\n * ```html\n * <ngx-chat-sender\n * [disabled]=\"isLoading()\"\n * (send)=\"onSend($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ngx-chat-sender',\n standalone: true,\n templateUrl: './chat-sender.component.html',\n styleUrls: ['./chat-sender.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-sender',\n '[class.ngx-chat-sender--disabled]': 'disabled()',\n '[class.ngx-chat-sender--error]': 'hasValidationError()',\n '[class.ngx-chat-sender--cooldown]': 'isOnCooldown()',\n },\n})\nexport class ChatSenderComponent {\n // ===========================================================================\n // Injected Dependencies\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n private readonly destroyRef = inject(DestroyRef);\n\n // ===========================================================================\n // View Queries\n // ===========================================================================\n\n /**\n * Reference to the textarea element for auto-resize and focus management.\n */\n readonly textareaRef = viewChild<ElementRef<HTMLTextAreaElement>>('textareaElement');\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * Whether the sender is disabled.\n * When disabled, users cannot send messages.\n * @default false\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Optional configuration override.\n * If not provided, uses global configuration.\n */\n readonly config = input<ChatConfigInput | undefined>(undefined);\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emitted when the user sends a message.\n * Contains message content and optional attachments.\n */\n readonly send = output<ChatSendEvent>();\n\n /**\n * Emitted when the user's typing state changes.\n * Debounced to prevent excessive events.\n */\n readonly typing = output<ChatTypingEvent>();\n\n // ===========================================================================\n // Internal State (Signals)\n // ===========================================================================\n\n /**\n * Current value of the input textarea.\n */\n readonly inputValue = signal<string>('');\n\n /**\n * Current validation error, if any.\n */\n readonly validationError = signal<string | null>(null);\n\n /**\n * Pending attachments to be sent with the message.\n */\n readonly pendingAttachments = signal<PendingAttachmentRef[]>([]);\n\n /**\n * Whether the user is currently typing.\n */\n readonly isCurrentlyTyping = signal<boolean>(false);\n\n /**\n * Whether the sender is on cooldown after a send.\n */\n readonly isOnCooldown = signal<boolean>(false);\n\n // ===========================================================================\n // Private State\n // ===========================================================================\n\n /**\n * Timeout ID for typing debounce.\n */\n private typingDebounceTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Timeout ID for typing end detection.\n */\n private typingEndTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Timeout ID for send cooldown.\n */\n private cooldownTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Timeout ID for validation debounce.\n */\n private validationTimeout: ReturnType<typeof setTimeout> | null = null;\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * Merged configuration with defaults.\n */\n readonly effectiveConfig = computed(() => {\n const inputConfig = this.config();\n if (inputConfig) {\n return this.configService.getConfig(inputConfig);\n }\n return this.configService.getConfig();\n });\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n /**\n * Validation configuration from effective config.\n */\n readonly validationConfig = computed(() => this.effectiveConfig().validation);\n\n /**\n * Keyboard configuration from effective config.\n */\n readonly keyboardConfig = computed(() => this.effectiveConfig().keyboard);\n\n /**\n * Behavior configuration from effective config.\n */\n readonly behaviorConfig = computed(() => this.effectiveConfig().behavior);\n\n /**\n * Whether there's a validation error.\n */\n readonly hasValidationError = computed(() => this.validationError() !== null);\n\n /**\n * Current character count.\n */\n readonly characterCount = computed(() => this.inputValue().length);\n\n /**\n * Maximum character count from config.\n */\n readonly maxCharacterCount = computed(() => this.validationConfig().maxMessageLength);\n\n /**\n * Whether to show the character counter.\n * Shows when near the limit (within 20% of max).\n */\n readonly showCharacterCount = computed(() => {\n const max = this.maxCharacterCount();\n const current = this.characterCount();\n // Show when at 80% of limit or more\n return max > 0 && current >= max * 0.8;\n });\n\n /**\n * Formatted character count display.\n */\n readonly characterCountDisplay = computed(() => {\n const current = this.characterCount();\n const max = this.maxCharacterCount();\n return this.configService.formatI18n('characterCount', {\n current: current.toString(),\n max: max.toString(),\n });\n });\n\n /**\n * Whether character count is over limit.\n */\n readonly isOverLimit = computed(() => {\n const max = this.maxCharacterCount();\n return max > 0 && this.characterCount() > max;\n });\n\n /**\n * Whether the send button can be clicked.\n */\n readonly canSend = computed(() => {\n // Cannot send if disabled\n if (this.disabled()) {\n return false;\n }\n\n // Cannot send if on cooldown\n if (this.isOnCooldown()) {\n return false;\n }\n\n // Cannot send if there's a validation error\n if (this.hasValidationError()) {\n return false;\n }\n\n const content = this.inputValue().trim();\n const hasAttachments = this.pendingAttachments().length > 0;\n const validationConfig = this.validationConfig();\n\n // Can send if there are attachments (even without content)\n if (hasAttachments && validationConfig.allowEmptyContent) {\n return true;\n }\n\n // Must have content if no attachments\n if (!content && !hasAttachments) {\n return false;\n }\n\n // Check minimum length\n if (validationConfig.minMessageLength > 0 && content.length < validationConfig.minMessageLength) {\n return false;\n }\n\n return true;\n });\n\n /**\n * ARIA label for the send button.\n */\n readonly sendButtonAriaLabel = computed(() => this.i18n().ariaSendButton);\n\n // ===========================================================================\n // Constructor\n // ===========================================================================\n\n constructor() {\n // Setup cleanup on destroy\n this.destroyRef.onDestroy(() => {\n this.clearAllTimeouts();\n });\n }\n\n // ===========================================================================\n // Template Event Handlers\n // ===========================================================================\n\n /**\n * Handles input event on the textarea.\n * Updates input value, triggers validation, and manages typing indicator.\n */\n onInput(event: Event): void {\n const target = event.target as HTMLTextAreaElement;\n const value = target.value;\n\n this.inputValue.set(value);\n this.autoResizeTextarea();\n this.debounceValidation(value);\n this.handleTypingIndicator(value);\n }\n\n /**\n * Handles keydown events for keyboard shortcuts.\n */\n onKeydown(event: KeyboardEvent): void {\n const config = this.keyboardConfig();\n\n // Send on Enter (without modifier) if configured\n if (event.key === 'Enter' && !event.shiftKey && !event.ctrlKey && !event.metaKey) {\n if (config.sendOnEnter) {\n event.preventDefault();\n this.attemptSend();\n return;\n }\n }\n\n // Send on Ctrl+Enter or Cmd+Enter if configured\n if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {\n if (config.sendOnCtrlEnter) {\n event.preventDefault();\n this.attemptSend();\n return;\n }\n }\n\n // Clear input on Escape if configured\n if (event.key === 'Escape') {\n if (config.escToClear) {\n event.preventDefault();\n this.clearInput();\n return;\n }\n }\n }\n\n /**\n * Handles click on the send button.\n */\n onSendClick(): void {\n this.attemptSend();\n }\n\n /**\n * Handles focus on the textarea.\n */\n onFocus(): void {\n // Could emit focus event if needed\n }\n\n /**\n * Handles blur on the textarea.\n */\n onBlur(): void {\n // End typing indicator on blur\n if (this.isCurrentlyTyping()) {\n this.emitTypingEnd();\n }\n }\n\n // ===========================================================================\n // Public Methods\n // ===========================================================================\n\n /**\n * Focuses the textarea.\n */\n focus(): void {\n this.textareaRef()?.nativeElement.focus();\n }\n\n /**\n * Clears the input and resets state.\n */\n clearInput(): void {\n this.inputValue.set('');\n this.validationError.set(null);\n this.pendingAttachments.set([]);\n this.autoResizeTextarea();\n\n if (this.isCurrentlyTyping()) {\n this.emitTypingEnd();\n }\n }\n\n /**\n * Adds a pending attachment.\n */\n addAttachment(attachment: PendingAttachmentRef): void {\n this.pendingAttachments.update(attachments => [...attachments, attachment]);\n }\n\n /**\n * Removes a pending attachment by ID.\n */\n removeAttachment(attachmentId: string): void {\n this.pendingAttachments.update(attachments =>\n attachments.filter(a => a.id !== attachmentId)\n );\n }\n\n // ===========================================================================\n // Private Methods - Validation\n // ===========================================================================\n\n /**\n * Debounces validation to prevent excessive validation calls.\n */\n private debounceValidation(content: string): void {\n if (this.validationTimeout) {\n clearTimeout(this.validationTimeout);\n }\n\n // Immediate validation for empty content\n if (!content.trim()) {\n this.validationError.set(null);\n return;\n }\n\n this.validationTimeout = setTimeout(() => {\n this.runValidation(content);\n }, 150);\n }\n\n /**\n * Runs validation on the content.\n */\n private runValidation(content: string): void {\n const config = this.validationConfig();\n const result = validateMessage(content, config);\n\n if (!result.valid) {\n this.validationError.set(result.error ?? null);\n } else {\n this.validationError.set(null);\n }\n }\n\n // ===========================================================================\n // Private Methods - Typing Indicator\n // ===========================================================================\n\n /**\n * Manages the typing indicator with debounce.\n */\n private handleTypingIndicator(content: string): void {\n const debounceMs = this.behaviorConfig().typingDebounce;\n\n // Clear existing end timeout\n if (this.typingEndTimeout) {\n clearTimeout(this.typingEndTimeout);\n this.typingEndTimeout = null;\n }\n\n // If content is empty, end typing immediately\n if (!content.trim()) {\n if (this.isCurrentlyTyping()) {\n this.emitTypingEnd();\n }\n return;\n }\n\n // If not currently typing, emit typing start (debounced)\n if (!this.isCurrentlyTyping()) {\n if (this.typingDebounceTimeout) {\n clearTimeout(this.typingDebounceTimeout);\n }\n\n this.typingDebounceTimeout = setTimeout(() => {\n this.emitTypingStart(content);\n }, debounceMs);\n } else {\n // Already typing, schedule end detection\n this.typingEndTimeout = setTimeout(() => {\n this.emitTypingEnd();\n }, debounceMs * 3);\n }\n }\n\n /**\n * Emits typing start event.\n */\n private emitTypingStart(content: string): void {\n this.isCurrentlyTyping.set(true);\n this.typing.emit({\n isTyping: true,\n content,\n });\n\n // Schedule typing end\n this.typingEndTimeout = setTimeout(() => {\n this.emitTypingEnd();\n }, this.behaviorConfig().typingDebounce * 3);\n }\n\n /**\n * Emits typing end event.\n */\n private emitTypingEnd(): void {\n if (this.typingDebounceTimeout) {\n clearTimeout(this.typingDebounceTimeout);\n this.typingDebounceTimeout = null;\n }\n\n this.isCurrentlyTyping.set(false);\n this.typing.emit({\n isTyping: false,\n });\n }\n\n // ===========================================================================\n // Private Methods - Send\n // ===========================================================================\n\n /**\n * Attempts to send the message if validation passes.\n */\n private attemptSend(): void {\n if (!this.canSend()) {\n return;\n }\n\n const content = this.inputValue().trim();\n const attachments = this.pendingAttachments();\n const config = this.validationConfig();\n\n // Run final validation\n if (content) {\n const result = validateMessage(content, config);\n if (!result.valid) {\n this.validationError.set(result.error ?? null);\n return;\n }\n }\n\n // Emit send event\n const event: ChatSendEvent = {\n content: content,\n ...(attachments.length > 0 && { attachments }),\n };\n\n this.send.emit(event);\n\n // Clear input after send\n this.clearInput();\n\n // Start cooldown\n this.startCooldown();\n }\n\n /**\n * Starts the send cooldown period.\n */\n private startCooldown(): void {\n const cooldownMs = this.behaviorConfig().sendCooldown;\n\n if (cooldownMs <= 0) {\n return;\n }\n\n this.isOnCooldown.set(true);\n\n this.cooldownTimeout = setTimeout(() => {\n this.isOnCooldown.set(false);\n this.cooldownTimeout = null;\n }, cooldownMs);\n }\n\n // ===========================================================================\n // Private Methods - Textarea\n // ===========================================================================\n\n /**\n * Auto-resizes the textarea based on content.\n */\n private autoResizeTextarea(): void {\n const textarea = this.textareaRef()?.nativeElement;\n if (!textarea) {\n return;\n }\n\n // Reset height to auto to get the correct scrollHeight\n textarea.style.height = 'auto';\n\n // Set height to scrollHeight, capped at max height\n const maxHeight = 200; // 200px max height\n const newHeight = Math.min(textarea.scrollHeight, maxHeight);\n textarea.style.height = `${newHeight}px`;\n\n // Add overflow if content exceeds max height\n textarea.style.overflowY = textarea.scrollHeight > maxHeight ? 'auto' : 'hidden';\n }\n\n // ===========================================================================\n // Private Methods - Cleanup\n // ===========================================================================\n\n /**\n * Clears all active timeouts.\n */\n private clearAllTimeouts(): void {\n if (this.typingDebounceTimeout) {\n clearTimeout(this.typingDebounceTimeout);\n this.typingDebounceTimeout = null;\n }\n\n if (this.typingEndTimeout) {\n clearTimeout(this.typingEndTimeout);\n this.typingEndTimeout = null;\n }\n\n if (this.cooldownTimeout) {\n clearTimeout(this.cooldownTimeout);\n this.cooldownTimeout = null;\n }\n\n if (this.validationTimeout) {\n clearTimeout(this.validationTimeout);\n this.validationTimeout = null;\n }\n }\n}\n","<div class=\"ngx-chat-sender__container\">\n <!-- Pending attachments preview (placeholder for AttachmentPreviewComponent) -->\n @if (pendingAttachments().length > 0) {\n <div class=\"ngx-chat-sender__attachments\">\n @for (attachment of pendingAttachments(); track attachment.id) {\n <div class=\"ngx-chat-sender__attachment-item\">\n <span class=\"ngx-chat-sender__attachment-name\">{{ attachment.name }}</span>\n <button\n type=\"button\"\n class=\"ngx-chat-sender__attachment-remove\"\n [attr.aria-label]=\"i18n().removeAttachment\"\n (click)=\"removeAttachment(attachment.id)\"\n >\n ×\n </button>\n </div>\n }\n </div>\n }\n\n <!-- Input row -->\n <div class=\"ngx-chat-sender__input-row\">\n <!-- Textarea wrapper -->\n <div class=\"ngx-chat-sender__textarea-wrapper\">\n <textarea\n #textareaElement\n class=\"ngx-chat-sender__textarea\"\n [placeholder]=\"i18n().placeholder\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"i18n().ariaMessageInput\"\n [attr.aria-invalid]=\"hasValidationError()\"\n [attr.aria-describedby]=\"hasValidationError() ? 'sender-error' : null\"\n [attr.maxlength]=\"maxCharacterCount() > 0 ? maxCharacterCount() : null\"\n rows=\"1\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <!-- Send button -->\n <button\n type=\"button\"\n class=\"ngx-chat-sender__send-btn\"\n [disabled]=\"!canSend()\"\n [attr.aria-label]=\"sendButtonAriaLabel()\"\n (click)=\"onSendClick()\"\n >\n <span class=\"ngx-chat-sender__send-icon\" aria-hidden=\"true\">\n <!-- SVG arrow icon -->\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"20\"\n height=\"20\"\n >\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\"/>\n </svg>\n </span>\n <span class=\"ngx-chat-sender__send-text\">{{ i18n().send }}</span>\n </button>\n </div>\n\n <!-- Footer row (validation error and character count) -->\n @if (hasValidationError() || showCharacterCount()) {\n <div class=\"ngx-chat-sender__footer\">\n <!-- Validation error -->\n @if (hasValidationError()) {\n <span\n id=\"sender-error\"\n class=\"ngx-chat-sender__error\"\n role=\"alert\"\n aria-live=\"polite\"\n >\n {{ validationError() }}\n </span>\n }\n\n <!-- Character count -->\n @if (showCharacterCount()) {\n <span\n class=\"ngx-chat-sender__char-count\"\n [class.ngx-chat-sender__char-count--over]=\"isOverLimit()\"\n [attr.aria-label]=\"characterCountDisplay()\"\n >\n {{ characterCountDisplay() }}\n </span>\n }\n </div>\n }\n</div>\n","/**\n * @fileoverview Main chat container component for ngx-chat library.\n * This is the primary entry point that orchestrates all child components.\n * @module ngx-chat/components/chat\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n computed,\n contentChild,\n DestroyRef,\n inject,\n input,\n output,\n signal,\n TemplateRef,\n} from '@angular/core';\nimport { CommonModule, DOCUMENT } from '@angular/common';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { ChatMessage, ChatSendEvent, ChatTypingEvent, ChatRetryEvent, ChatLoadMoreEvent } from '../../models/message.model';\nimport { MessageActionEvent } from '../../models/actions.model';\nimport { AttachmentClickEvent } from '../../models/attachment.model';\nimport { ChatConfig, ChatConfigInput, ChatDirection, ChatTheme } from '../../models/config.model';\nimport { ChatConfigService } from '../../services/chat-config.service';\nimport { ChatEventService } from '../../services/chat-event.service';\nimport { ChatHeaderContentDirective } from '../../directives/chat-header-content.directive';\nimport { ChatHeaderComponent } from '../chat-header/chat-header.component';\nimport { ChatSenderComponent } from '../chat-sender/chat-sender.component';\n\n/**\n * Main chat container component.\n *\n * This is the primary entry point for the ngx-chat library. It:\n * - Orchestrates all child components (messages, sender, header, etc.)\n * - Provides ChatEventService at component level for isolated event streams\n * - Handles theme detection (light/dark/auto) with system preference\n * - Handles RTL detection from document or configuration\n * - Forwards internal events to outputs for parent handling\n *\n * @example\n * ```typescript\n * @Component({\n * template: `\n * <ngx-chat\n * [messages]=\"messages()\"\n * [isTyping]=\"isTyping()\"\n * (send)=\"onSend($event)\"\n * (action)=\"onAction($event)\"\n * >\n * <ng-template ngxChatHeaderContent>\n * <span>Chat with AI</span>\n * </ng-template>\n * </ngx-chat>\n * `\n * })\n * export class AppComponent {\n * messages = signal<ChatMessage[]>([]);\n * isTyping = signal(false);\n *\n * onSend(event: ChatSendEvent) {\n * this.messages.update(m => [...m, createSelfMessage(event.content)]);\n * }\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat',\n standalone: true,\n imports: [CommonModule, ChatHeaderComponent, ChatHeaderContentDirective, ChatSenderComponent],\n templateUrl: './chat.component.html',\n styleUrls: ['./chat.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [ChatEventService],\n host: {\n 'class': 'ngx-chat',\n '[class.ngx-chat--dark]': 'isDarkTheme()',\n '[class.ngx-chat--light]': 'isLightTheme()',\n '[class.ngx-chat--disabled]': 'disabled()',\n '[class.ngx-chat--loading]': 'loading()',\n '[attr.dir]': 'resolvedDirection()',\n 'role': 'region',\n '[attr.aria-label]': 'i18n.ariaMessageList',\n },\n})\nexport class ChatComponent {\n // ===========================================================================\n // Dependency Injection\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n private readonly eventService = inject(ChatEventService);\n private readonly destroyRef = inject(DestroyRef);\n private readonly document = inject(DOCUMENT);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * Array of messages to display in the chat.\n * Messages should be immutable - create new array when updating.\n */\n readonly messages = input<ChatMessage[]>([]);\n\n /**\n * Whether to show the typing indicator.\n * Set to true when the other party is typing.\n */\n readonly isTyping = input<boolean>(false);\n\n /**\n * Custom label for the typing indicator.\n * If not provided, uses i18n default (e.g., \"Someone is typing...\").\n */\n readonly typingLabel = input<string | undefined>(undefined);\n\n /**\n * Whether the chat is disabled.\n * When disabled, users cannot send messages or interact with actions.\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the chat is in a loading state.\n * Shows loading indicator and may disable interactions.\n */\n readonly loading = input<boolean>(false);\n\n /**\n * Configuration overrides merged with defaults.\n * Use to customize behavior, validation, markdown, etc.\n */\n readonly config = input<ChatConfigInput | undefined>(undefined);\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emitted when the user sends a message.\n * Parent should add the message to state and send to server.\n */\n readonly send = output<ChatSendEvent>();\n\n /**\n * Emitted when the user's typing state changes.\n * Use to send typing indicators to other participants.\n */\n readonly typing = output<ChatTypingEvent>();\n\n /**\n * Emitted when the user responds to a message action.\n * Parent should update the action response in message state.\n */\n readonly action = output<MessageActionEvent>();\n\n /**\n * Emitted when the user requests to retry a failed message.\n * Parent should attempt to resend the message.\n */\n readonly retry = output<ChatRetryEvent>();\n\n /**\n * Emitted when the user scrolls to load more message history.\n * Parent should fetch older messages and prepend to list.\n */\n readonly loadMore = output<ChatLoadMoreEvent>();\n\n /**\n * Emitted when the user clicks on an attachment.\n * Parent can open lightbox, download, or handle as needed.\n */\n readonly attachmentClick = output<AttachmentClickEvent>();\n\n // ===========================================================================\n // Content Projection\n // ===========================================================================\n\n /**\n * Optional custom header content directive.\n * Query for projected ng-template with ngxChatHeaderContent directive.\n */\n readonly headerContent = contentChild(ChatHeaderContentDirective);\n\n /**\n * Computed template ref from the header content directive.\n * Returns the template ref for rendering, or undefined if no header provided.\n */\n readonly headerTemplate = computed((): TemplateRef<unknown> | undefined => {\n return this.headerContent()?.templateRef;\n });\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /**\n * System preference for dark mode.\n * Updates reactively when system preference changes.\n */\n private readonly systemPrefersDark = signal<boolean>(false);\n\n /**\n * Media query listener reference for cleanup.\n */\n private mediaQueryList: MediaQueryList | null = null;\n\n // ===========================================================================\n // Computed Properties\n // ===========================================================================\n\n /**\n * Merged configuration with defaults.\n * Caches result based on input config.\n */\n readonly mergedConfig = computed((): ChatConfig => {\n return this.configService.getConfig(this.config());\n });\n\n /**\n * i18n strings for the component.\n */\n readonly i18n = this.configService.getI18n();\n\n /**\n * Resolved theme based on config and system preference.\n */\n readonly resolvedTheme = computed((): 'light' | 'dark' => {\n const theme = this.mergedConfig().theme;\n\n if (theme === 'light' || theme === 'dark') {\n return theme;\n }\n\n // Auto - use system preference\n return this.systemPrefersDark() ? 'dark' : 'light';\n });\n\n /**\n * Whether dark theme is active.\n */\n readonly isDarkTheme = computed((): boolean => {\n return this.resolvedTheme() === 'dark';\n });\n\n /**\n * Whether light theme is active.\n */\n readonly isLightTheme = computed((): boolean => {\n return this.resolvedTheme() === 'light';\n });\n\n /**\n * Resolved text direction based on config and document.\n */\n readonly resolvedDirection = computed((): 'ltr' | 'rtl' => {\n const direction = this.mergedConfig().direction;\n\n if (direction === 'ltr' || direction === 'rtl') {\n return direction;\n }\n\n // Auto - detect from document\n return this.getDocumentDirection();\n });\n\n /**\n * Whether RTL mode is active.\n */\n readonly isRtl = computed((): boolean => {\n return this.resolvedDirection() === 'rtl';\n });\n\n // ===========================================================================\n // Constructor\n // ===========================================================================\n\n constructor() {\n this.setupThemeDetection();\n this.setupEventForwarding();\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n /**\n * Sets up system theme preference detection.\n * Listens for changes in (prefers-color-scheme: dark).\n */\n private setupThemeDetection(): void {\n if (typeof window === 'undefined' || !window.matchMedia) {\n return;\n }\n\n this.mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)');\n this.systemPrefersDark.set(this.mediaQueryList.matches);\n\n const listener = (event: MediaQueryListEvent) => {\n this.systemPrefersDark.set(event.matches);\n };\n\n this.mediaQueryList.addEventListener('change', listener);\n\n this.destroyRef.onDestroy(() => {\n this.mediaQueryList?.removeEventListener('change', listener);\n });\n }\n\n /**\n * Sets up forwarding of internal events to component outputs.\n * ChatEventService events are forwarded to the appropriate outputs.\n */\n private setupEventForwarding(): void {\n // Forward action events\n this.eventService.action$\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => {\n this.action.emit(event);\n });\n\n // Forward retry events\n this.eventService.retry$\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => {\n this.retry.emit(event);\n });\n\n // Forward load more events\n this.eventService.loadMore$\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => {\n this.loadMore.emit(event);\n });\n\n // Forward attachment click events\n this.eventService.attachmentClick$\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => {\n this.attachmentClick.emit(event);\n });\n }\n\n /**\n * Gets the text direction from the document.\n * Checks document.dir or document.documentElement.dir.\n */\n private getDocumentDirection(): 'ltr' | 'rtl' {\n const dir = this.document.dir || this.document.documentElement?.dir || 'ltr';\n return dir === 'rtl' ? 'rtl' : 'ltr';\n }\n\n // ===========================================================================\n // Template Methods\n // ===========================================================================\n\n /**\n * Handles send event from child sender component.\n * Forwards to parent via output.\n */\n onSend(event: ChatSendEvent): void {\n if (this.disabled()) {\n return;\n }\n this.send.emit(event);\n }\n\n /**\n * Handles typing event from child sender component.\n * Forwards to parent via output.\n */\n onTyping(event: ChatTypingEvent): void {\n if (this.disabled()) {\n return;\n }\n this.typing.emit(event);\n }\n}\n","<!--\n Main Chat Container Template\n Structure: Header -> Messages -> Sender\n Child components will be added in subsequent tasks\n-->\n\n<div class=\"ngx-chat__container\">\n <!-- Header Section -->\n @if (headerTemplate()) {\n <ngx-chat-header [template]=\"headerTemplate()!\" />\n }\n\n <!-- Messages Section -->\n <main class=\"ngx-chat__messages\" role=\"log\" [attr.aria-live]=\"'polite'\">\n <!-- Loading state -->\n @if (loading()) {\n <div class=\"ngx-chat__loading\" [attr.aria-label]=\"i18n.loading\">\n <div class=\"ngx-chat__loading-spinner\" aria-hidden=\"true\"></div>\n <span class=\"ngx-chat__loading-text\">{{ i18n.loading }}</span>\n </div>\n }\n\n <!-- Empty state -->\n @if (!loading() && messages().length === 0) {\n <div class=\"ngx-chat__empty\" [attr.aria-label]=\"i18n.emptyState\">\n <span class=\"ngx-chat__empty-text\">{{ i18n.emptyState }}</span>\n </div>\n }\n\n <!-- Messages will be rendered by ChatMessagesComponent in Task 4.4 -->\n @if (!loading() && messages().length > 0) {\n <div class=\"ngx-chat__messages-list\" role=\"list\">\n <!-- Placeholder for ChatMessagesComponent -->\n @for (message of messages(); track message.id) {\n <div\n class=\"ngx-chat__message-placeholder\"\n [class.ngx-chat__message-placeholder--self]=\"message.sender === 'self'\"\n [class.ngx-chat__message-placeholder--other]=\"message.sender === 'other'\"\n [class.ngx-chat__message-placeholder--system]=\"message.sender === 'system'\"\n role=\"listitem\"\n >\n <!-- Temporary placeholder until ChatMessageBubbleComponent is created -->\n <div class=\"ngx-chat__message-content\">\n @if (message.senderName && message.sender === 'other') {\n <span class=\"ngx-chat__message-sender\">{{ message.senderName }}</span>\n }\n <div class=\"ngx-chat__message-text\">{{ message.content }}</div>\n @if (message.status === 'error') {\n <div class=\"ngx-chat__message-error\">\n <span>{{ message.error?.message || i18n.error }}</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Typing Indicator -->\n @if (isTyping()) {\n <div\n class=\"ngx-chat__typing\"\n role=\"status\"\n [attr.aria-live]=\"'polite'\"\n [attr.aria-label]=\"typingLabel() || i18n.someoneTyping\"\n >\n <div class=\"ngx-chat__typing-dots\" aria-hidden=\"true\">\n <span class=\"ngx-chat__typing-dot\"></span>\n <span class=\"ngx-chat__typing-dot\"></span>\n <span class=\"ngx-chat__typing-dot\"></span>\n </div>\n <span class=\"ngx-chat__typing-text\">{{ typingLabel() || i18n.someoneTyping }}</span>\n </div>\n }\n </main>\n\n <!-- Sender Section -->\n <footer class=\"ngx-chat__sender\">\n <ngx-chat-sender\n [disabled]=\"disabled()\"\n [config]=\"config()\"\n (send)=\"onSend($event)\"\n (typing)=\"onTyping($event)\"\n />\n </footer>\n</div>\n","/**\n * @fileoverview Chat typing indicator component for ngx-chat library.\n * Displays an animated typing indicator when another party is typing.\n * @module ngx-chat/components/chat-typing-indicator\n */\n\nimport { Component, ChangeDetectionStrategy, input } from '@angular/core';\n\n/**\n * Chat typing indicator component.\n *\n * Displays an animated typing indicator with three bouncing dots.\n * Supports custom label text and is fully accessible with aria-live.\n *\n * @example Basic usage (controlled by parent)\n * ```html\n * @if (isTyping()) {\n * <ngx-chat-typing-indicator />\n * }\n * ```\n *\n * @example With custom label\n * ```html\n * <ngx-chat-typing-indicator label=\"AI is thinking...\" />\n * ```\n *\n * @example With dynamic label\n * ```html\n * <ngx-chat-typing-indicator [label]=\"typingUserName() + ' is typing...'\" />\n * ```\n */\n@Component({\n selector: 'ngx-chat-typing-indicator',\n standalone: true,\n template: `\n <span class=\"ngx-chat-typing-indicator__dots\" aria-hidden=\"true\">\n <span class=\"ngx-chat-typing-indicator__dot\"></span>\n <span class=\"ngx-chat-typing-indicator__dot\"></span>\n <span class=\"ngx-chat-typing-indicator__dot\"></span>\n </span>\n @if (label()) {\n <span class=\"ngx-chat-typing-indicator__label\">{{ label() }}</span>\n }\n `,\n styleUrls: ['./chat-typing-indicator.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-typing-indicator',\n 'role': 'status',\n 'aria-live': 'polite',\n '[attr.aria-label]': 'label() || \"Someone is typing\"',\n },\n})\nexport class ChatTypingIndicatorComponent {\n /**\n * Optional label text to display alongside the dots.\n * If not provided, only the animated dots are shown.\n * The label is also used as the aria-label for screen readers.\n *\n * @example \"John is typing...\"\n * @example \"AI is thinking...\"\n */\n readonly label = input<string | undefined>(undefined);\n}\n","/**\n * Grouping Utilities\n *\n * Pure utility functions for grouping consecutive messages\n * from the same sender within a time threshold.\n */\n\nimport type { ChatMessage } from '../models/message.model';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Default time threshold for message grouping (1 minute in milliseconds).\n */\nexport const DEFAULT_GROUPING_THRESHOLD_MS = 60000;\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Represents a group of consecutive messages from the same sender.\n *\n * Messages are grouped when:\n * - They have the same sender\n * - They are within the time threshold of each other\n * - None of them are system messages\n * - None of them have actions\n * - None of them have attachments\n *\n * @example\n * ```typescript\n * const group: MessageGroup = {\n * senderId: 'self',\n * senderName: undefined,\n * avatar: '/avatar.png',\n * messages: [message1, message2, message3],\n * timestamp: message1.timestamp\n * };\n * ```\n */\nexport interface MessageGroup {\n /** The sender type of all messages in this group */\n readonly senderId: ChatMessage['sender'];\n\n /** Display name of the sender (from first message) */\n readonly senderName: string | undefined;\n\n /** Avatar URL of the sender (from first message) */\n readonly avatar: string | undefined;\n\n /** Messages in this group, in chronological order */\n readonly messages: readonly ChatMessage[];\n\n /** Timestamp of the first message in the group */\n readonly timestamp: Date;\n}\n\n// ============================================================================\n// Predicate Functions\n// ============================================================================\n\n/**\n * Checks if a message should break grouping.\n *\n * A message breaks grouping if it:\n * - Is a system message\n * - Has actions attached\n * - Has attachments\n *\n * @param message - The message to check\n * @returns True if the message should not be grouped\n *\n * @example\n * ```typescript\n * const systemMsg = createSystemMessage('User joined');\n * isUngroupable(systemMsg); // true\n *\n * const normalMsg = createOtherMessage('Hello');\n * isUngroupable(normalMsg); // false\n * ```\n */\nexport function isUngroupable(message: ChatMessage): boolean {\n // System messages are never grouped\n if (message.sender === 'system') {\n return true;\n }\n\n // Messages with actions are never grouped\n if (message.actions && message.actions.length > 0) {\n return true;\n }\n\n // Messages with attachments are never grouped\n if (message.attachments && message.attachments.length > 0) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Determines if two consecutive messages should be grouped together.\n *\n * Grouping rules:\n * 1. Same sender\n * 2. Within time threshold\n * 3. Neither message is ungroupable (system, has actions, has attachments)\n *\n * @param prevMessage - The previous message in sequence\n * @param currentMessage - The current message to check\n * @param thresholdMs - Maximum time difference in milliseconds (default: 60000)\n * @returns True if the messages should be in the same group\n *\n * @example\n * ```typescript\n * const msg1 = createOtherMessage('Hello', 'Alice');\n * const msg2 = createOtherMessage('How are you?', 'Alice');\n * // Assuming both have timestamps within 1 minute\n * shouldGroupMessages(msg1, msg2); // true\n *\n * const msg3 = createSelfMessage('I am fine');\n * shouldGroupMessages(msg2, msg3); // false (different sender)\n * ```\n */\nexport function shouldGroupMessages(\n prevMessage: ChatMessage,\n currentMessage: ChatMessage,\n thresholdMs: number = DEFAULT_GROUPING_THRESHOLD_MS\n): boolean {\n // Either message is ungroupable - cannot group\n if (isUngroupable(prevMessage) || isUngroupable(currentMessage)) {\n return false;\n }\n\n // Different senders - cannot group\n if (prevMessage.sender !== currentMessage.sender) {\n return false;\n }\n\n // Check time threshold\n const timeDiff = Math.abs(\n currentMessage.timestamp.getTime() - prevMessage.timestamp.getTime()\n );\n\n if (timeDiff > thresholdMs) {\n return false;\n }\n\n return true;\n}\n\n// ============================================================================\n// Grouping Functions\n// ============================================================================\n\n/**\n * Groups consecutive messages from the same sender within a time threshold.\n *\n * @param messages - Array of messages to group (should be in chronological order)\n * @param thresholdMs - Maximum time between messages to group (default: 60000ms)\n * @returns Array of message groups\n *\n * @example\n * ```typescript\n * const messages = [\n * createOtherMessage('Hello', 'Alice'),\n * createOtherMessage('How are you?', 'Alice'),\n * createSelfMessage('I am fine'),\n * createSelfMessage('Thanks for asking')\n * ];\n *\n * const groups = groupMessages(messages);\n * // Returns 2 groups:\n * // - Group 1: Alice's two messages\n * // - Group 2: Self's two messages\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * groupMessages([]); // Returns []\n * groupMessages([singleMessage]); // Returns [{ messages: [singleMessage], ... }]\n * ```\n */\nexport function groupMessages(\n messages: readonly ChatMessage[],\n thresholdMs: number = DEFAULT_GROUPING_THRESHOLD_MS\n): MessageGroup[] {\n // Handle empty array\n if (messages.length === 0) {\n return [];\n }\n\n const groups: MessageGroup[] = [];\n let currentGroupMessages: ChatMessage[] = [];\n\n for (let i = 0; i < messages.length; i++) {\n const message = messages[i];\n const prevMessage = i > 0 ? messages[i - 1] : null;\n\n // First message or should start a new group\n if (!prevMessage || !shouldGroupMessages(prevMessage, message, thresholdMs)) {\n // Save previous group if it exists\n if (currentGroupMessages.length > 0) {\n groups.push(createGroup(currentGroupMessages));\n }\n // Start new group\n currentGroupMessages = [message];\n } else {\n // Add to current group\n currentGroupMessages.push(message);\n }\n }\n\n // Don't forget the last group\n if (currentGroupMessages.length > 0) {\n groups.push(createGroup(currentGroupMessages));\n }\n\n return groups;\n}\n\n/**\n * Creates a MessageGroup from an array of messages.\n *\n * @param messages - Non-empty array of messages for this group\n * @returns A MessageGroup object\n */\nfunction createGroup(messages: ChatMessage[]): MessageGroup {\n const firstMessage = messages[0];\n\n return {\n senderId: firstMessage.sender,\n senderName: firstMessage.senderName,\n avatar: firstMessage.avatar,\n messages: messages,\n timestamp: firstMessage.timestamp,\n };\n}\n","/**\n * @fileoverview Accessibility service for ngx-chat screen reader announcements.\n * Provides methods to announce chat events to assistive technologies using\n * Angular CDK's LiveAnnouncer.\n *\n * @module ngx-chat/services/chat-a11y\n */\n\nimport { Injectable, inject } from '@angular/core';\nimport { LiveAnnouncer } from '@angular/cdk/a11y';\nimport { ChatMessage, ChatMessageError } from '../models/message.model';\nimport { MessageAction } from '../models/actions.model';\nimport { ChatConfigService } from './chat-config.service';\n\n/**\n * Default maximum length for content summarization.\n * Messages longer than this will be truncated with ellipsis.\n */\nconst DEFAULT_MAX_CONTENT_LENGTH = 100;\n\n/**\n * Service for making screen reader announcements in the chat.\n *\n * This service uses Angular CDK's LiveAnnouncer to communicate chat events\n * to assistive technologies. It implements best practices for accessibility:\n * - Polite announcements for non-urgent updates (new messages, typing, actions)\n * - Assertive announcements for errors requiring immediate attention\n * - Content summarization to avoid overwhelming screen reader users\n *\n * @example\n * ```typescript\n * @Component({...})\n * export class ChatMessagesComponent {\n * private readonly a11yService = inject(ChatA11yService);\n *\n * onNewMessage(message: ChatMessage) {\n * this.a11yService.announceNewMessage(message);\n * }\n *\n * onError(error: ChatMessageError) {\n * this.a11yService.announceError(error);\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ChatA11yService {\n private readonly liveAnnouncer = inject(LiveAnnouncer);\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // Public Methods\n // ===========================================================================\n\n /**\n * Announces a new message to screen reader users.\n *\n * The announcement includes:\n * - Sender name (or \"Someone\" if not provided)\n * - Summarized content (truncated if too long)\n * - Attachment count (if any)\n *\n * Uses polite politeness level to avoid interrupting the user.\n *\n * @param message - The new message to announce\n * @returns Promise that resolves when announcement is made\n *\n * @example\n * ```typescript\n * // Message with content\n * a11yService.announceNewMessage({\n * id: 'msg-1',\n * sender: 'other',\n * senderName: 'Alice',\n * content: 'Hello, how can I help you today?',\n * timestamp: new Date()\n * });\n * // Announces: \"New message from Alice: Hello, how can I help you today?\"\n *\n * // Message with attachments\n * a11yService.announceNewMessage({\n * id: 'msg-2',\n * sender: 'other',\n * senderName: 'Bob',\n * content: 'Check these files',\n * timestamp: new Date(),\n * attachments: [{...}, {...}]\n * });\n * // Announces: \"New message from Bob: Check these files. 2 attachments\"\n * ```\n */\n async announceNewMessage(message: ChatMessage): Promise<void> {\n const i18n = this.configService.getI18n();\n\n // Build sender name\n const senderName = message.senderName || i18n.other;\n\n // Build content summary\n const summarizedContent = this.summarizeContent(message.content);\n\n // Build attachment info\n const attachmentInfo = this.formatAttachmentCount(\n message.attachments?.length ?? 0\n );\n\n // Build full announcement\n const announcement = this.configService.formatI18n('ariaNewMessage', {\n sender: senderName,\n });\n\n // Combine parts\n let fullAnnouncement = `${announcement}: ${summarizedContent}`;\n if (attachmentInfo) {\n fullAnnouncement += `. ${attachmentInfo}`;\n }\n\n await this.liveAnnouncer.announce(fullAnnouncement, 'polite');\n }\n\n /**\n * Announces an error to screen reader users.\n *\n * Uses assertive politeness level to ensure errors are immediately\n * communicated, potentially interrupting other announcements.\n *\n * @param error - The error to announce (ChatMessageError or string)\n * @returns Promise that resolves when announcement is made\n *\n * @example\n * ```typescript\n * // Announce with ChatMessageError\n * a11yService.announceError({\n * code: 'NETWORK_ERROR',\n * message: 'Failed to send message. Please check your connection.',\n * retryable: true\n * });\n *\n * // Announce with string\n * a11yService.announceError('Unable to connect to server');\n * ```\n */\n async announceError(error: ChatMessageError | string): Promise<void> {\n const message = typeof error === 'string' ? error : error.message;\n await this.liveAnnouncer.announce(message, 'assertive');\n }\n\n /**\n * Announces the result of a user action.\n *\n * Formats the announcement based on the action type:\n * - confirm: \"Confirmed\" or \"Cancelled\"\n * - select: \"Selected: {option label}\"\n * - multi-select: \"{count} selected\"\n * - buttons: \"Selected: {button label}\"\n *\n * Uses polite politeness level.\n *\n * @param action - The action that was responded to\n * @param response - The user's response\n * @returns Promise that resolves when announcement is made\n *\n * @example\n * ```typescript\n * // Confirm action\n * a11yService.announceActionResult(\n * { type: 'confirm', id: 'action-1' },\n * true\n * );\n * // Announces: \"Confirmed\"\n *\n * // Select action\n * a11yService.announceActionResult(\n * {\n * type: 'select',\n * id: 'action-2',\n * options: [{ id: 'opt-1', label: 'Option One' }]\n * },\n * 'opt-1'\n * );\n * // Announces: \"Selected: Option One\"\n *\n * // Multi-select action\n * a11yService.announceActionResult(\n * { type: 'multi-select', id: 'action-3', options: [...] },\n * ['opt-1', 'opt-2']\n * );\n * // Announces: \"2 selected\"\n * ```\n */\n async announceActionResult(\n action: MessageAction,\n response: unknown\n ): Promise<void> {\n const announcement = this.getActionResultText(action, response);\n await this.liveAnnouncer.announce(announcement, 'polite');\n }\n\n /**\n * Announces that someone is typing.\n *\n * Uses polite politeness level. If no sender name is provided,\n * uses the generic \"Someone is typing...\" message.\n *\n * @param senderName - Optional name of the person typing\n * @returns Promise that resolves when announcement is made\n *\n * @example\n * ```typescript\n * // With sender name\n * a11yService.announceTyping('Alice');\n * // Announces: \"Alice is typing...\"\n *\n * // Without sender name\n * a11yService.announceTyping();\n * // Announces: \"Someone is typing...\"\n * ```\n */\n async announceTyping(senderName?: string): Promise<void> {\n const i18n = this.configService.getI18n();\n\n const announcement = senderName\n ? this.configService.formatI18n('typing', { name: senderName })\n : i18n.someoneTyping;\n\n await this.liveAnnouncer.announce(announcement, 'polite');\n }\n\n /**\n * Clears any pending announcements.\n *\n * Call this when navigating away from chat or when announcements\n * are no longer relevant.\n *\n * @returns Promise that resolves when cleared\n *\n * @example\n * ```typescript\n * ngOnDestroy() {\n * this.a11yService.clear();\n * }\n * ```\n */\n async clear(): Promise<void> {\n await this.liveAnnouncer.clear();\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n /**\n * Summarizes content by truncating if it exceeds the maximum length.\n *\n * @param content - The content to summarize\n * @param maxLength - Maximum length before truncation (default: 100)\n * @returns Original content if short enough, or truncated with ellipsis\n */\n private summarizeContent(\n content: string,\n maxLength: number = DEFAULT_MAX_CONTENT_LENGTH\n ): string {\n if (!content) {\n return '';\n }\n\n if (content.length <= maxLength) {\n return content;\n }\n\n return content.slice(0, maxLength - 3) + '...';\n }\n\n /**\n * Formats the attachment count for announcement.\n *\n * @param count - Number of attachments\n * @returns Formatted string like \"1 attachment\" or \"3 attachments\", or empty if 0\n */\n private formatAttachmentCount(count: number): string {\n if (count === 0) {\n return '';\n }\n\n const i18n = this.configService.getI18n();\n\n if (count === 1) {\n return i18n.attachment;\n }\n\n return this.configService.formatI18n('attachments', { count });\n }\n\n /**\n * Gets the appropriate announcement text for an action result.\n *\n * @param action - The action that was responded to\n * @param response - The user's response\n * @returns Formatted announcement text\n */\n private getActionResultText(action: MessageAction, response: unknown): string {\n const i18n = this.configService.getI18n();\n\n switch (action.type) {\n case 'confirm': {\n return response ? i18n.confirmed : i18n.cancelled;\n }\n\n case 'select': {\n const selectedOption = action.options.find(\n (opt) => opt.id === response\n );\n const label = selectedOption?.label ?? String(response);\n return `${i18n.selected}: ${label}`;\n }\n\n case 'multi-select': {\n const selectedIds = response as readonly string[];\n const count = selectedIds?.length ?? 0;\n return this.configService.formatI18n('selectedCount', { count });\n }\n\n case 'buttons': {\n const clickedButton = action.buttons.find(\n (btn) => btn.id === response\n );\n const label = clickedButton?.label ?? String(response);\n return `${i18n.selected}: ${label}`;\n }\n\n default:\n return i18n.selected;\n }\n }\n}\n","/**\n * @fileoverview Virtual scroll service for efficient rendering of large message lists.\n * Calculates visible ranges, offsets, and heights for virtualized rendering.\n * @module ngx-chat/services/chat-virtual-scroll\n */\n\nimport { Injectable, computed, inject, signal } from '@angular/core';\nimport { ChatConfigService } from './chat-config.service';\n\n/**\n * Represents the visible range of items in the virtual scroll viewport.\n */\nexport interface VisibleRange {\n /** Index of the first visible item (inclusive). */\n readonly startIndex: number;\n /** Index of the last visible item (inclusive). */\n readonly endIndex: number;\n}\n\n/**\n * Service for managing virtual scrolling state and calculations.\n *\n * This service enables efficient rendering of large message lists (10,000+)\n * by calculating which items are visible and their positions. It supports\n * both uniform and variable item heights.\n *\n * Key concepts:\n * - **Visible Range**: Items currently in viewport plus buffer\n * - **Total Height**: Combined height of all items (for scroll container)\n * - **Offset Y**: Transform offset for positioning visible items\n *\n * @example\n * ```typescript\n * @Component({...})\n * export class MessagesComponent {\n * private readonly virtualScroll = inject(ChatVirtualScrollService);\n *\n * // Set container dimensions\n * ngAfterViewInit() {\n * this.virtualScroll.setContainerHeight(500);\n * this.virtualScroll.setItemCount(this.messages().length);\n * }\n *\n * // On scroll\n * onScroll(event: Event) {\n * this.virtualScroll.setScrollTop(event.target.scrollTop);\n * }\n *\n * // Get visible items\n * readonly visibleMessages = computed(() => {\n * const range = this.virtualScroll.visibleRange();\n * return this.messages().slice(range.startIndex, range.endIndex + 1);\n * });\n *\n * // Apply offset transform\n * readonly containerStyle = computed(() => ({\n * transform: `translateY(${this.virtualScroll.offsetY()}px)`\n * }));\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ChatVirtualScrollService {\n private readonly configService = inject(ChatConfigService);\n private readonly config = this.configService.getConfig().virtualScroll;\n\n // =========================================================================\n // State Signals\n // =========================================================================\n\n /**\n * Default height for items without measured height.\n * Used for initial calculations and items not yet rendered.\n */\n private readonly _itemHeight = signal(this.config.defaultItemHeight);\n\n /**\n * Number of items to render outside the visible viewport.\n * Provides smooth scrolling by pre-rendering items.\n */\n private readonly _bufferSize = signal(this.config.bufferSize);\n\n /**\n * Current scroll position from the top.\n */\n private readonly _scrollTop = signal(0);\n\n /**\n * Height of the scroll container in pixels.\n */\n private readonly _containerHeight = signal(0);\n\n /**\n * Total number of items in the list.\n */\n private readonly _itemCount = signal(0);\n\n /**\n * Map of item index to measured height.\n * Used for variable-height items when cacheItemHeights is enabled.\n */\n private readonly _itemHeights = signal<Map<number, number>>(new Map());\n\n // =========================================================================\n // Public Read-Only State\n // =========================================================================\n\n /** Default item height. */\n readonly itemHeight = this._itemHeight.asReadonly();\n\n /** Buffer size (items outside viewport). */\n readonly bufferSize = this._bufferSize.asReadonly();\n\n /** Current scroll position. */\n readonly scrollTop = this._scrollTop.asReadonly();\n\n /** Container height. */\n readonly containerHeight = this._containerHeight.asReadonly();\n\n /** Total item count. */\n readonly itemCount = this._itemCount.asReadonly();\n\n /** Map of measured item heights. */\n readonly itemHeights = this._itemHeights.asReadonly();\n\n // =========================================================================\n // Computed Properties\n // =========================================================================\n\n /**\n * Total height of all items combined.\n * This is used to set the height of the scroll container's inner content.\n *\n * @returns Sum of all item heights in pixels\n */\n readonly totalHeight = computed(() => {\n const count = this._itemCount();\n if (count === 0) return 0;\n\n const heights = this._itemHeights();\n const defaultHeight = this._itemHeight();\n\n // If we have cached heights, use them\n if (heights.size > 0) {\n let total = 0;\n for (let i = 0; i < count; i++) {\n total += heights.get(i) ?? defaultHeight;\n }\n return total;\n }\n\n // Uniform height calculation\n return count * defaultHeight;\n });\n\n /**\n * Range of visible items including buffer.\n *\n * The range includes extra items (buffer) above and below the viewport\n * for smooth scrolling. Both startIndex and endIndex are inclusive.\n *\n * @returns Object with startIndex and endIndex\n */\n readonly visibleRange = computed((): VisibleRange => {\n const count = this._itemCount();\n if (count === 0) {\n return { startIndex: 0, endIndex: -1 };\n }\n\n const scrollTop = this._scrollTop();\n const containerHeight = this._containerHeight();\n const buffer = this._bufferSize();\n\n // Find start index\n const startIndex = Math.max(\n 0,\n this.findIndexAtOffset(scrollTop) - buffer\n );\n\n // Find end index\n const endOffset = scrollTop + containerHeight;\n const endIndex = Math.min(\n count - 1,\n this.findIndexAtOffset(endOffset) + buffer\n );\n\n return { startIndex, endIndex };\n });\n\n /**\n * Vertical offset to apply to the visible items container.\n *\n * This offset positions the rendered items correctly within the scroll\n * container by translating them to their expected position.\n *\n * @returns Offset in pixels from the top\n */\n readonly offsetY = computed(() => {\n const { startIndex } = this.visibleRange();\n if (startIndex === 0) return 0;\n return this.getItemOffset(startIndex);\n });\n\n // =========================================================================\n // State Update Methods\n // =========================================================================\n\n /**\n * Updates the scroll position.\n *\n * @param value - Scroll position from top in pixels\n */\n setScrollTop(value: number): void {\n this._scrollTop.set(Math.max(0, value));\n }\n\n /**\n * Updates the container height.\n *\n * @param value - Container height in pixels\n */\n setContainerHeight(value: number): void {\n this._containerHeight.set(Math.max(0, value));\n }\n\n /**\n * Updates the total item count.\n *\n * @param count - Number of items in the list\n */\n setItemCount(count: number): void {\n this._itemCount.set(Math.max(0, count));\n }\n\n /**\n * Updates the default item height.\n *\n * @param height - Default height in pixels\n */\n setItemHeight(height: number): void {\n this._itemHeight.set(Math.max(1, height));\n }\n\n /**\n * Sets the measured height for a specific item.\n *\n * Call this after measuring actual rendered item heights for\n * variable-height content. Heights are cached if cacheItemHeights is true.\n *\n * @param index - Item index\n * @param height - Measured height in pixels\n */\n setItemHeightAt(index: number, height: number): void {\n if (!this.config.cacheItemHeights) return;\n if (index < 0 || height < 1) return;\n\n this._itemHeights.update((map) => {\n const newMap = new Map(map);\n newMap.set(index, height);\n return newMap;\n });\n }\n\n /**\n * Updates the buffer size.\n *\n * @param size - Number of items to render outside viewport\n */\n setBufferSize(size: number): void {\n this._bufferSize.set(Math.max(0, size));\n }\n\n // =========================================================================\n // Query Methods\n // =========================================================================\n\n /**\n * Gets the vertical offset for an item at the given index.\n *\n * @param index - Item index\n * @returns Offset from top in pixels\n */\n getItemOffset(index: number): number {\n if (index <= 0) return 0;\n\n const heights = this._itemHeights();\n const defaultHeight = this._itemHeight();\n const count = this._itemCount();\n\n if (index >= count) {\n return this.totalHeight();\n }\n\n let offset = 0;\n for (let i = 0; i < index; i++) {\n offset += heights.get(i) ?? defaultHeight;\n }\n return offset;\n }\n\n /**\n * Gets the height of an item at the given index.\n *\n * @param index - Item index\n * @returns Item height in pixels\n */\n getItemHeight(index: number): number {\n return this._itemHeights().get(index) ?? this._itemHeight();\n }\n\n /**\n * Checks if an index is within the visible range.\n *\n * @param index - Item index to check\n * @returns True if the item is in the visible range\n */\n isIndexVisible(index: number): boolean {\n const { startIndex, endIndex } = this.visibleRange();\n return index >= startIndex && index <= endIndex;\n }\n\n // =========================================================================\n // Reset Method\n // =========================================================================\n\n /**\n * Resets all state to defaults.\n *\n * Call this when the message list changes completely (e.g., switching chats).\n */\n reset(): void {\n this._scrollTop.set(0);\n this._containerHeight.set(0);\n this._itemCount.set(0);\n this._itemHeights.set(new Map());\n this._itemHeight.set(this.config.defaultItemHeight);\n this._bufferSize.set(this.config.bufferSize);\n }\n\n // =========================================================================\n // Private Helpers\n // =========================================================================\n\n /**\n * Finds the item index at the given scroll offset.\n *\n * Uses binary search for efficiency when item heights are cached,\n * falls back to division for uniform heights.\n *\n * @param offset - Scroll offset from top in pixels\n * @returns Item index at that offset\n */\n private findIndexAtOffset(offset: number): number {\n if (offset <= 0) return 0;\n\n const count = this._itemCount();\n if (count === 0) return 0;\n\n const heights = this._itemHeights();\n const defaultHeight = this._itemHeight();\n\n // If no cached heights or caching disabled, use uniform calculation\n if (heights.size === 0) {\n return Math.min(Math.floor(offset / defaultHeight), count - 1);\n }\n\n // Binary search for variable heights\n let low = 0;\n let high = count - 1;\n let accumulatedHeight = 0;\n\n // Optimization: if offset is beyond total height, return last index\n const total = this.totalHeight();\n if (offset >= total) {\n return count - 1;\n }\n\n while (low < high) {\n const mid = Math.floor((low + high) / 2);\n const midOffset = this.getItemOffset(mid);\n const midHeight = heights.get(mid) ?? defaultHeight;\n\n if (offset < midOffset) {\n high = mid - 1;\n } else if (offset >= midOffset + midHeight) {\n low = mid + 1;\n } else {\n return mid;\n }\n }\n\n return low;\n }\n}\n","/**\n * @fileoverview Chat message bubble component for ngx-chat library.\n * Renders individual message bubbles with status, avatar, and retry support.\n * @module ngx-chat/components/chat-message-bubble\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n computed,\n inject,\n} from '@angular/core';\n\nimport type { ChatMessage, MessageStatus } from '../../models/message.model';\nimport type { ChatConfig } from '../../models/config.model';\nimport { ChatConfigService } from '../../services/chat-config.service';\nimport { ChatEventService } from '../../services/chat-event.service';\n\n/**\n * Status icon configuration for each message status.\n */\ninterface StatusIconConfig {\n /** Icon character or symbol */\n readonly icon: string;\n /** CSS class for styling */\n readonly cssClass: string;\n /** Accessible label */\n readonly label: string;\n}\n\n/**\n * Chat message bubble component.\n *\n * Renders an individual message bubble with support for:\n * - Different styling for self/other/system sender types\n * - Avatar display (optional)\n * - Sender name display (optional)\n * - Timestamp formatting using Intl.DateTimeFormat\n * - Status indicators (pending, sending, sent, delivered, read, error)\n * - Error state with retry button\n *\n * This component is purely presentational. It emits retry events through\n * the ChatEventService event bus, which bubbles up to the parent ChatComponent.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-message-bubble [message]=\"message\" />\n * ```\n *\n * @example With all options\n * ```html\n * <ngx-chat-message-bubble\n * [message]=\"message\"\n * [showAvatar]=\"true\"\n * [showSenderName]=\"true\"\n * [showTimestamp]=\"true\"\n * [isFirstInGroup]=\"true\"\n * [isLastInGroup]=\"true\"\n * />\n * ```\n */\n@Component({\n selector: 'ngx-chat-message-bubble',\n standalone: true,\n template: `\n <!-- Avatar (only for 'other' messages when enabled) -->\n @if (showAvatar() && message().sender === 'other' && isLastInGroup()) {\n <div class=\"ngx-chat-message-bubble__avatar\">\n @if (message().avatar) {\n <img\n [src]=\"message().avatar\"\n [alt]=\"displayName()\"\n class=\"ngx-chat-message-bubble__avatar-img\"\n />\n } @else {\n <span class=\"ngx-chat-message-bubble__avatar-placeholder\">\n {{ avatarInitial() }}\n </span>\n }\n </div>\n } @else if (showAvatar() && message().sender === 'other') {\n <!-- Spacer to maintain alignment when avatar not shown -->\n <div class=\"ngx-chat-message-bubble__avatar-spacer\"></div>\n }\n\n <div class=\"ngx-chat-message-bubble__content\">\n <!-- Sender name (only for first message in group from others) -->\n @if (showSenderName() && message().sender === 'other' && isFirstInGroup()) {\n <span class=\"ngx-chat-message-bubble__sender\">{{ displayName() }}</span>\n }\n\n <div class=\"ngx-chat-message-bubble__bubble\">\n <!-- Message content -->\n <div class=\"ngx-chat-message-bubble__text\">{{ message().content }}</div>\n\n <!-- Inline status for self messages -->\n @if (message().sender === 'self' && message().status) {\n <span\n class=\"ngx-chat-message-bubble__status\"\n [class]=\"statusConfig().cssClass\"\n [attr.aria-label]=\"statusConfig().label\"\n [title]=\"statusConfig().label\"\n >\n {{ statusConfig().icon }}\n </span>\n }\n </div>\n\n <!-- Error state with retry button -->\n @if (isError()) {\n <div class=\"ngx-chat-message-bubble__error\">\n <span class=\"ngx-chat-message-bubble__error-message\">\n {{ errorMessage() }}\n </span>\n @if (canRetry()) {\n <button\n type=\"button\"\n class=\"ngx-chat-message-bubble__retry-btn\"\n [attr.aria-label]=\"i18n().ariaRetryButton\"\n (click)=\"onRetry()\"\n >\n {{ i18n().retry }}\n </button>\n }\n </div>\n }\n\n <!-- Timestamp (only for last message in group) -->\n @if (showTimestamp() && isLastInGroup() && !isError()) {\n <time\n class=\"ngx-chat-message-bubble__timestamp\"\n [attr.datetime]=\"message().timestamp.toISOString()\"\n >\n {{ formattedTimestamp() }}\n @if (message().edited) {\n <span class=\"ngx-chat-message-bubble__edited\">\n ({{ i18n().edited }})\n </span>\n }\n </time>\n }\n </div>\n `,\n styleUrls: ['./chat-message-bubble.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-message-bubble',\n '[class.ngx-chat-message-bubble--self]': \"message().sender === 'self'\",\n '[class.ngx-chat-message-bubble--other]': \"message().sender === 'other'\",\n '[class.ngx-chat-message-bubble--system]': \"message().sender === 'system'\",\n '[class.ngx-chat-message-bubble--error]': 'isError()',\n '[class.ngx-chat-message-bubble--first]': 'isFirstInGroup()',\n '[class.ngx-chat-message-bubble--last]': 'isLastInGroup()',\n '[attr.data-message-id]': 'message().id',\n 'role': 'article',\n '[attr.aria-label]': 'ariaLabel()',\n },\n})\nexport class ChatMessageBubbleComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n private readonly eventService = inject(ChatEventService);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The message to display.\n */\n readonly message = input.required<ChatMessage>();\n\n /**\n * Whether to show the avatar for this message.\n * Only applies to 'other' sender type.\n * @default true\n */\n readonly showAvatar = input<boolean>(true);\n\n /**\n * Whether to show the sender name above the message.\n * Only applies to 'other' sender type.\n * @default true\n */\n readonly showSenderName = input<boolean>(true);\n\n /**\n * Whether to show the timestamp below the message.\n * @default true\n */\n readonly showTimestamp = input<boolean>(true);\n\n /**\n * Whether this is the first message in a group.\n * Affects border radius styling.\n * @default false\n */\n readonly isFirstInGroup = input<boolean>(false);\n\n /**\n * Whether this is the last message in a group.\n * Affects avatar display and timestamp visibility.\n * @default false\n */\n readonly isLastInGroup = input<boolean>(false);\n\n /**\n * Optional configuration override.\n * If not provided, uses global configuration.\n */\n readonly config = input<Partial<ChatConfig> | undefined>(undefined);\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * Merged configuration from input and global config.\n */\n readonly effectiveConfig = computed(() => {\n const inputConfig = this.config();\n if (inputConfig) {\n return this.configService.getConfig(inputConfig);\n }\n return this.configService.getConfig();\n });\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n /**\n * Display name for the sender.\n */\n readonly displayName = computed(() => {\n const msg = this.message();\n if (msg.sender === 'self') {\n return this.i18n().you;\n }\n return msg.senderName ?? this.i18n().other;\n });\n\n /**\n * Avatar initial for placeholder.\n */\n readonly avatarInitial = computed(() => {\n const name = this.displayName();\n return name.charAt(0).toUpperCase();\n });\n\n /**\n * Formatted timestamp using Intl.DateTimeFormat.\n */\n readonly formattedTimestamp = computed(() => {\n const config = this.effectiveConfig();\n const formatter = new Intl.DateTimeFormat(\n undefined,\n config.behavior.timestampFormat\n );\n return formatter.format(this.message().timestamp);\n });\n\n /**\n * Whether the message has an error status.\n */\n readonly isError = computed(() => {\n return this.message().status === 'error';\n });\n\n /**\n * Whether the message can be retried.\n */\n readonly canRetry = computed(() => {\n const error = this.message().error;\n return error?.retryable ?? true;\n });\n\n /**\n * Error message to display.\n */\n readonly errorMessage = computed(() => {\n const error = this.message().error;\n return error?.message ?? this.i18n().error;\n });\n\n /**\n * Status icon configuration based on message status.\n */\n readonly statusConfig = computed((): StatusIconConfig => {\n const status = this.message().status;\n const i18n = this.i18n();\n\n return this.getStatusIconConfig(status, i18n);\n });\n\n /**\n * ARIA label for the entire message bubble.\n */\n readonly ariaLabel = computed(() => {\n const msg = this.message();\n const sender = this.displayName();\n const status = msg.status ? `, ${this.statusConfig().label}` : '';\n return `${sender}: ${msg.content}${status}`;\n });\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles retry button click.\n * Emits retry event through ChatEventService.\n */\n onRetry(): void {\n const msg = this.message();\n this.eventService.emitRetry({\n messageId: msg.id,\n message: msg,\n });\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n /**\n * Gets status icon configuration for a message status.\n */\n private getStatusIconConfig(\n status: MessageStatus | undefined,\n i18n: ReturnType<typeof this.i18n>\n ): StatusIconConfig {\n switch (status) {\n case 'pending':\n return {\n icon: '○',\n cssClass: 'ngx-chat-message-bubble__status--pending',\n label: i18n.sending,\n };\n case 'sending':\n return {\n icon: '◔',\n cssClass: 'ngx-chat-message-bubble__status--sending',\n label: i18n.sending,\n };\n case 'sent':\n return {\n icon: '✓',\n cssClass: 'ngx-chat-message-bubble__status--sent',\n label: i18n.sent,\n };\n case 'delivered':\n return {\n icon: '✓✓',\n cssClass: 'ngx-chat-message-bubble__status--delivered',\n label: i18n.delivered,\n };\n case 'read':\n return {\n icon: '✓✓',\n cssClass: 'ngx-chat-message-bubble__status--read',\n label: i18n.read,\n };\n case 'error':\n return {\n icon: '!',\n cssClass: 'ngx-chat-message-bubble__status--error',\n label: i18n.error,\n };\n default:\n return {\n icon: '',\n cssClass: '',\n label: '',\n };\n }\n }\n}\n","/**\n * @fileoverview Chat messages container component for ngx-chat library.\n * Displays messages with auto-scroll, message grouping, and infinite scroll.\n * @module ngx-chat/components/chat-messages\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n viewChild,\n viewChildren,\n inject,\n afterRenderEffect,\n effect,\n ElementRef,\n OnDestroy,\n QueryList,\n} from '@angular/core';\nimport { NgScrollbar } from 'ngx-scrollbar';\n\nimport type { ChatMessage, ChatLoadMoreEvent } from '../../models/message.model';\nimport type { ChatConfig } from '../../models/config.model';\nimport { groupMessages, type MessageGroup } from '../../utils/grouping.utils';\nimport { ChatConfigService } from '../../services/chat-config.service';\nimport { ChatA11yService } from '../../services/chat-a11y.service';\nimport { ChatVirtualScrollService } from '../../services/chat-virtual-scroll.service';\nimport { ChatTypingIndicatorComponent } from '../chat-typing-indicator/chat-typing-indicator.component';\nimport { ChatMessageBubbleComponent } from '../chat-message-bubble/chat-message-bubble.component';\n\n/**\n * Chat messages container component.\n *\n * Displays a scrollable list of chat messages with automatic scrolling,\n * message grouping, and support for loading historical messages.\n *\n * Key features:\n * - Auto-scroll to new messages (when user is at bottom)\n * - Message grouping by sender and time\n * - Load more trigger when scrolled to top\n * - Typing indicator display\n * - Full accessibility support with ARIA attributes\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-messages\n * [messages]=\"messages()\"\n * [isTyping]=\"isTyping()\"\n * [hasMore]=\"hasMore()\"\n * (loadMore)=\"onLoadMore($event)\"\n * />\n * ```\n *\n * @example With loading states\n * ```html\n * <ngx-chat-messages\n * [messages]=\"messages()\"\n * [isTyping]=\"isTyping()\"\n * [typingLabel]=\"'AI is thinking...'\"\n * [loading]=\"loading()\"\n * [loadingMore]=\"loadingMore()\"\n * [hasMore]=\"hasMore()\"\n * (loadMore)=\"onLoadMore($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ngx-chat-messages',\n standalone: true,\n imports: [NgScrollbar, ChatTypingIndicatorComponent, ChatMessageBubbleComponent],\n template: `\n <ng-scrollbar\n #scrollbar\n class=\"ngx-chat-messages__scrollbar\"\n [visibility]=\"'hover'\"\n [appearance]=\"'compact'\"\n (scroll)=\"onScroll($event)\"\n >\n <!-- Initial loading state -->\n @if (loading()) {\n <div class=\"ngx-chat-messages__content\">\n <div class=\"ngx-chat-messages__loading\" role=\"status\" aria-live=\"polite\">\n <span class=\"ngx-chat-messages__loading-spinner\"></span>\n <span>{{ i18n().loading }}</span>\n </div>\n </div>\n } @else if (shouldUseVirtualScroll()) {\n <!-- Virtual scroll mode -->\n <div\n class=\"ngx-chat-messages__virtual-container\"\n [style.height.px]=\"virtualTotalHeight()\"\n >\n <!-- Load more trigger area (positioned at top) -->\n @if (hasMore()) {\n <div class=\"ngx-chat-messages__load-more ngx-chat-messages__load-more--virtual\" aria-hidden=\"true\">\n @if (loadingMore()) {\n <span class=\"ngx-chat-messages__loading-spinner\"></span>\n <span>{{ i18n().loadingMore }}</span>\n }\n </div>\n }\n\n <!-- Offset container for visible items -->\n <div\n class=\"ngx-chat-messages__virtual-offset\"\n [style.transform]=\"'translateY(' + virtualOffsetY() + 'px)'\"\n >\n @for (message of visibleMessages(); track message.id; let i = $index) {\n <div\n class=\"ngx-chat-messages__virtual-item\"\n [class.ngx-chat-messages__virtual-item--self]=\"message.sender === 'self'\"\n [class.ngx-chat-messages__virtual-item--other]=\"message.sender === 'other'\"\n [class.ngx-chat-messages__virtual-item--system]=\"message.sender === 'system'\"\n [attr.data-vs-index]=\"getMessageIndex(i)\"\n >\n <ngx-chat-message-bubble\n class=\"ngx-chat-messages__message\"\n [message]=\"message\"\n [showAvatar]=\"effectiveConfig().behavior.showAvatar\"\n [showSenderName]=\"effectiveConfig().behavior.showSenderName\"\n [showTimestamp]=\"effectiveConfig().behavior.showTimestamps\"\n [isFirstInGroup]=\"true\"\n [isLastInGroup]=\"true\"\n [config]=\"config()\"\n />\n </div>\n }\n </div>\n\n <!-- Typing indicator (positioned at bottom) -->\n @if (isTyping()) {\n <div class=\"ngx-chat-messages__typing ngx-chat-messages__typing--virtual\">\n <ngx-chat-typing-indicator [label]=\"typingLabel()\" />\n </div>\n }\n </div>\n } @else {\n <!-- Standard mode with message grouping -->\n <div class=\"ngx-chat-messages__content\">\n <!-- Load more trigger area -->\n @if (hasMore()) {\n <div class=\"ngx-chat-messages__load-more\" aria-hidden=\"true\">\n @if (loadingMore()) {\n <span class=\"ngx-chat-messages__loading-spinner\"></span>\n <span>{{ i18n().loadingMore }}</span>\n }\n </div>\n }\n\n <!-- Message groups -->\n @for (group of messageGroups(); track group.timestamp.getTime()) {\n <div\n class=\"ngx-chat-messages__group\"\n [class.ngx-chat-messages__group--self]=\"group.senderId === 'self'\"\n [class.ngx-chat-messages__group--other]=\"group.senderId === 'other'\"\n [class.ngx-chat-messages__group--system]=\"group.senderId === 'system'\"\n >\n @for (message of group.messages; track message.id; let isFirst = $first; let isLast = $last) {\n <ngx-chat-message-bubble\n class=\"ngx-chat-messages__message\"\n [message]=\"message\"\n [showAvatar]=\"effectiveConfig().behavior.showAvatar\"\n [showSenderName]=\"effectiveConfig().behavior.showSenderName\"\n [showTimestamp]=\"effectiveConfig().behavior.showTimestamps\"\n [isFirstInGroup]=\"isFirst\"\n [isLastInGroup]=\"isLast\"\n [config]=\"config()\"\n />\n }\n </div>\n }\n\n <!-- Typing indicator -->\n @if (isTyping()) {\n <div class=\"ngx-chat-messages__typing\">\n <ngx-chat-typing-indicator [label]=\"typingLabel()\" />\n </div>\n }\n </div>\n }\n </ng-scrollbar>\n `,\n styleUrls: ['./chat-messages.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-messages',\n 'role': 'log',\n 'aria-live': 'polite',\n '[attr.aria-busy]': 'loading() || loadingMore()',\n },\n})\nexport class ChatMessagesComponent implements OnDestroy {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n private readonly a11yService = inject(ChatA11yService);\n private readonly virtualScrollService = inject(ChatVirtualScrollService);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * Array of messages to display.\n * Messages should be in chronological order (oldest first).\n */\n readonly messages = input<readonly ChatMessage[]>([]);\n\n /**\n * Whether to display the typing indicator.\n */\n readonly isTyping = input<boolean>(false);\n\n /**\n * Optional label for the typing indicator.\n * @example \"Alice is typing...\"\n */\n readonly typingLabel = input<string | undefined>(undefined);\n\n /**\n * Whether messages are being initially loaded.\n * Displays a loading spinner.\n */\n readonly loading = input<boolean>(false);\n\n /**\n * Whether more historical messages are being loaded.\n * Displays a spinner at the top.\n */\n readonly loadingMore = input<boolean>(false);\n\n /**\n * Whether more historical messages are available.\n * When true, scrolling to top triggers loadMore.\n */\n readonly hasMore = input<boolean>(false);\n\n /**\n * Optional configuration override.\n * If not provided, uses global configuration.\n */\n readonly config = input<Partial<ChatConfig> | undefined>(undefined);\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emitted when the user scrolls near the top to load more messages.\n * The parent should fetch older messages and prepend to the list.\n */\n readonly loadMore = output<ChatLoadMoreEvent>();\n\n // ===========================================================================\n // View Queries\n // ===========================================================================\n\n private readonly scrollbar = viewChild<NgScrollbar>('scrollbar');\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /** Tracks whether auto-scroll is enabled (user is at bottom) */\n private readonly isNearBottom = signal<boolean>(true);\n\n /** Tracks the last message ID we processed for new message detection */\n private readonly lastProcessedMessageId = signal<string | null>(null);\n\n /** Debounce flag for load more to prevent rapid firing */\n private readonly loadMoreDebounced = signal<boolean>(false);\n\n /** Timestamp formatter cache */\n private timestampFormatter: Intl.DateTimeFormat | null = null;\n\n /** ResizeObserver for measuring message heights in virtual scroll mode */\n private resizeObserver: ResizeObserver | null = null;\n\n /** Map of message IDs to their indices for height measurement */\n private readonly messageIndexMap = new Map<string, number>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * Merged configuration from input and global config.\n */\n readonly effectiveConfig = computed(() => {\n const inputConfig = this.config();\n if (inputConfig) {\n return this.configService.getConfig(inputConfig);\n }\n return this.configService.getConfig();\n });\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n /**\n * Messages grouped by sender and time.\n */\n readonly messageGroups = computed<MessageGroup[]>(() => {\n const msgs = this.messages();\n const config = this.effectiveConfig();\n return groupMessages(msgs, config.behavior.groupTimeThreshold);\n });\n\n /**\n * The last message in the list.\n */\n private readonly lastMessage = computed(() => {\n const msgs = this.messages();\n return msgs.length > 0 ? msgs[msgs.length - 1] : null;\n });\n\n /**\n * The first message in the list (oldest).\n */\n private readonly firstMessage = computed(() => {\n const msgs = this.messages();\n return msgs.length > 0 ? msgs[0] : null;\n });\n\n // ===========================================================================\n // Virtual Scroll Computed Values\n // ===========================================================================\n\n /**\n * Whether virtual scrolling should be active.\n * Based on enabled flag and message count threshold.\n */\n readonly shouldUseVirtualScroll = computed(() => {\n const config = this.effectiveConfig();\n const count = this.messages().length;\n return config.virtualScroll.enabled && count >= config.virtualScroll.threshold;\n });\n\n /**\n * Messages to render when virtual scrolling is active.\n * Only includes messages within the visible range.\n */\n readonly visibleMessages = computed((): readonly ChatMessage[] => {\n if (!this.shouldUseVirtualScroll()) {\n return this.messages();\n }\n\n const range = this.virtualScrollService.visibleRange();\n const msgs = this.messages();\n\n // Slice messages based on visible range\n if (range.endIndex < 0 || range.startIndex > msgs.length - 1) {\n return [];\n }\n\n return msgs.slice(range.startIndex, range.endIndex + 1);\n });\n\n /**\n * Total height of all messages for virtual scroll container.\n */\n readonly virtualTotalHeight = computed(() => {\n return this.virtualScrollService.totalHeight();\n });\n\n /**\n * Offset Y transform for positioning visible messages.\n */\n readonly virtualOffsetY = computed(() => {\n return this.virtualScrollService.offsetY();\n });\n\n /**\n * Start index of visible messages (for track by and height measurement).\n */\n readonly visibleStartIndex = computed(() => {\n return this.virtualScrollService.visibleRange().startIndex;\n });\n\n // ===========================================================================\n // Constructor & Lifecycle\n // ===========================================================================\n\n constructor() {\n // Effect to sync message count with virtual scroll service\n effect(() => {\n const count = this.messages().length;\n this.virtualScrollService.setItemCount(count);\n\n // Build message ID to index map for height measurement\n this.messageIndexMap.clear();\n const msgs = this.messages();\n for (let i = 0; i < msgs.length; i++) {\n this.messageIndexMap.set(msgs[i].id, i);\n }\n });\n\n // Auto-scroll effect using afterRenderEffect with earlyRead/write phases\n // Phase order: earlyRead → write → mixedReadWrite → read\n afterRenderEffect({\n earlyRead: () => {\n const scrollbarInstance = this.scrollbar();\n if (!scrollbarInstance) {\n return { shouldScroll: false, newMessageId: null as string | null };\n }\n\n const viewport = scrollbarInstance.viewport;\n if (!viewport?.nativeElement) {\n return { shouldScroll: false, newMessageId: null as string | null };\n }\n\n // Check if we have a new message\n const currentLastMessage = this.lastMessage();\n const lastProcessedId = this.lastProcessedMessageId();\n const hasNewMessage =\n currentLastMessage &&\n currentLastMessage.id !== lastProcessedId;\n\n // Determine if we should scroll\n const shouldScroll =\n this.isNearBottom() &&\n hasNewMessage &&\n this.effectiveConfig().behavior.autoScroll;\n\n return {\n shouldScroll,\n newMessageId: currentLastMessage?.id ?? null,\n isFromOther: currentLastMessage?.sender === 'other',\n message: currentLastMessage,\n };\n },\n write: (earlyReadResultSignal) => {\n const readResult = earlyReadResultSignal();\n if (!readResult || !readResult.newMessageId) return;\n\n const { shouldScroll, newMessageId, isFromOther, message } = readResult;\n\n // Update last processed message ID\n if (newMessageId !== this.lastProcessedMessageId()) {\n this.lastProcessedMessageId.set(newMessageId);\n\n // Announce new message from others\n if (isFromOther && message) {\n this.a11yService.announceNewMessage(message);\n }\n }\n\n // Perform scroll if needed\n if (shouldScroll) {\n this.scrollToBottom();\n }\n },\n });\n\n // Height measurement effect for virtual scrolling\n // Uses read phase for DOM reading after Angular has rendered\n afterRenderEffect(() => {\n // Only measure heights when virtual scrolling is active\n if (!this.shouldUseVirtualScroll()) {\n // Disconnect observer when not in virtual mode\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n }\n return;\n }\n\n const scrollbarInstance = this.scrollbar();\n if (!scrollbarInstance?.viewport?.nativeElement) {\n return;\n }\n\n const viewport = scrollbarInstance.viewport.nativeElement;\n const virtualItems = viewport.querySelectorAll<HTMLElement>(\n '.ngx-chat-messages__virtual-item'\n );\n\n // Create ResizeObserver if it doesn't exist\n if (!this.resizeObserver) {\n this.resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const target = entry.target as HTMLElement;\n const indexAttr = target.getAttribute('data-vs-index');\n if (indexAttr !== null) {\n const index = parseInt(indexAttr, 10);\n const height = entry.contentRect.height;\n if (!isNaN(index) && height > 0) {\n this.virtualScrollService.setItemHeightAt(index, height);\n }\n }\n }\n });\n }\n\n // Observe all virtual items\n virtualItems.forEach((item) => {\n this.resizeObserver!.observe(item);\n });\n });\n }\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles scroll events from the scrollbar.\n * Updates near-bottom state, feeds data to virtual scroll service,\n * and triggers load more when at top.\n */\n onScroll(event: Event): void {\n const target = event.target as HTMLElement;\n if (!target) return;\n\n const { scrollTop, scrollHeight, clientHeight } = target;\n\n // Update virtual scroll service with scroll position and container height\n if (this.shouldUseVirtualScroll()) {\n this.virtualScrollService.setScrollTop(scrollTop);\n this.virtualScrollService.setContainerHeight(clientHeight);\n }\n\n // Check if user is near bottom\n const threshold = this.effectiveConfig().behavior.scrollNearBottomThreshold;\n const distanceFromBottom = scrollHeight - scrollTop - clientHeight;\n this.isNearBottom.set(distanceFromBottom <= threshold);\n\n // Check if user scrolled to top and we should load more\n const nearTop = scrollTop < 50;\n if (\n nearTop &&\n this.hasMore() &&\n !this.loadingMore() &&\n !this.loadMoreDebounced()\n ) {\n this.triggerLoadMore();\n }\n }\n\n // ===========================================================================\n // Public Methods\n // ===========================================================================\n\n /**\n * Programmatically scrolls to the bottom of the message list.\n */\n scrollToBottom(): void {\n const scrollbarInstance = this.scrollbar();\n if (!scrollbarInstance) return;\n\n scrollbarInstance.scrollTo({\n bottom: 0,\n duration: 200,\n });\n }\n\n /**\n * Programmatically scrolls to a specific message by ID.\n * @param messageId - The ID of the message to scroll to\n */\n scrollToMessage(messageId: string): void {\n const scrollbarInstance = this.scrollbar();\n if (!scrollbarInstance) return;\n\n const viewport = scrollbarInstance.viewport?.nativeElement;\n if (!viewport) return;\n\n const messageElement = viewport.querySelector(\n `[data-message-id=\"${messageId}\"]`\n );\n if (messageElement) {\n messageElement.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n }\n\n /**\n * Formats a timestamp using the configured format.\n * @param date - The date to format\n * @returns Formatted timestamp string\n */\n formatTimestamp(date: Date): string {\n if (!this.timestampFormatter) {\n this.timestampFormatter = new Intl.DateTimeFormat(\n undefined,\n this.effectiveConfig().behavior.timestampFormat\n );\n }\n return this.timestampFormatter.format(date);\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n /**\n * Triggers the loadMore event with debounce protection.\n */\n private triggerLoadMore(): void {\n const firstMsg = this.firstMessage();\n if (!firstMsg) return;\n\n // Set debounce flag\n this.loadMoreDebounced.set(true);\n\n // Emit load more event\n this.loadMore.emit({\n beforeMessageId: firstMsg.id,\n count: 20, // Default batch size\n });\n\n // Reset debounce after delay\n setTimeout(() => {\n this.loadMoreDebounced.set(false);\n }, 500);\n }\n\n /**\n * Handles message height changes from ResizeObserver.\n * Reports measured heights to virtual scroll service.\n */\n onMessageHeightChange(messageId: string, height: number): void {\n const index = this.messageIndexMap.get(messageId);\n if (index !== undefined && height > 0) {\n this.virtualScrollService.setItemHeightAt(index, height);\n }\n }\n\n /**\n * Gets the absolute index for a message in the full list.\n * Used for track by and height measurement.\n */\n getMessageIndex(localIndex: number): number {\n return this.visibleStartIndex() + localIndex;\n }\n\n // ===========================================================================\n // Lifecycle\n // ===========================================================================\n\n /**\n * Cleanup on component destroy.\n */\n ngOnDestroy(): void {\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n this.messageIndexMap.clear();\n }\n}\n","/**\n * @fileoverview Confirm action component for ngx-chat library.\n * Renders a confirm/cancel button pair for binary decision actions.\n * @module ngx-chat/components/actions/confirm-action\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n inject,\n computed,\n} from '@angular/core';\n\nimport type { ConfirmAction, ButtonVariant } from '../../../models/actions.model';\nimport { ChatConfigService } from '../../../services/chat-config.service';\n\n/**\n * Confirm action component that renders confirm/cancel buttons.\n *\n * This component renders a simple binary choice action with two buttons.\n * The confirm button triggers a `true` response, cancel triggers `false`.\n * After responding, both buttons become disabled with visual indication\n * of which choice was made.\n *\n * The component is purely presentational - the parent is responsible for\n * updating the action's `responded` and `response` properties based on\n * the emitted event.\n *\n * @example Basic usage\n * ```html\n * <ngx-confirm-action\n * [action]=\"confirmAction\"\n * (respond)=\"onConfirmResponse($event)\"\n * />\n * ```\n *\n * @example In message actions container\n * ```html\n * @case ('confirm') {\n * <ngx-confirm-action\n * [action]=\"getConfirmAction(action)\"\n * (respond)=\"onActionResponse(action.id, 'confirm', $event)\"\n * />\n * }\n * ```\n */\n@Component({\n selector: 'ngx-confirm-action',\n standalone: true,\n template: `\n <div\n class=\"ngx-confirm-action__buttons\"\n role=\"group\"\n [attr.aria-label]=\"i18n().actionConfirm\"\n >\n <!-- Confirm Button -->\n <button\n type=\"button\"\n class=\"ngx-confirm-action__button ngx-confirm-action__button--confirm\"\n [class]=\"confirmButtonClasses()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"action().responded && action().response === true\"\n (click)=\"onConfirm()\"\n >\n <span class=\"ngx-confirm-action__button-text\">\n {{ confirmText() }}\n </span>\n @if (action().responded && action().response === true) {\n <span class=\"ngx-confirm-action__check\" aria-hidden=\"true\">✓</span>\n }\n </button>\n\n <!-- Cancel Button -->\n <button\n type=\"button\"\n class=\"ngx-confirm-action__button ngx-confirm-action__button--cancel\"\n [class]=\"cancelButtonClasses()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-pressed]=\"action().responded && action().response === false\"\n (click)=\"onCancel()\"\n >\n <span class=\"ngx-confirm-action__button-text\">\n {{ cancelText() }}\n </span>\n @if (action().responded && action().response === false) {\n <span class=\"ngx-confirm-action__check\" aria-hidden=\"true\">✓</span>\n }\n </button>\n </div>\n\n <!-- Screen reader announcement -->\n @if (action().responded) {\n <span class=\"ngx-confirm-action__sr-announcement\" role=\"status\" aria-live=\"polite\">\n {{ action().response ? i18n().confirmed : i18n().cancelled }}\n </span>\n }\n `,\n styleUrls: ['./confirm-action.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-confirm-action',\n '[class.ngx-confirm-action--disabled]': 'isDisabled()',\n '[class.ngx-confirm-action--responded]': 'action().responded',\n '[class.ngx-confirm-action--confirmed]': 'action().responded && action().response === true',\n '[class.ngx-confirm-action--cancelled]': 'action().responded && action().response === false',\n },\n})\nexport class ConfirmActionComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The confirm action configuration.\n * Contains button text, variants, and responded state.\n */\n readonly action = input.required<ConfirmAction>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits when user clicks confirm (true) or cancel (false).\n */\n readonly respond = output<boolean>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n /**\n * Text for the confirm button.\n */\n readonly confirmText = computed(() =>\n this.action().confirmText ?? this.i18n().confirm\n );\n\n /**\n * Text for the cancel button.\n */\n readonly cancelText = computed(() =>\n this.action().cancelText ?? this.i18n().cancel\n );\n\n /**\n * Whether the action is disabled (either explicitly or after responding).\n */\n readonly isDisabled = computed(() =>\n this.action().disabled === true || this.action().responded === true\n );\n\n /**\n * CSS classes for the confirm button based on variant.\n */\n readonly confirmButtonClasses = computed(() => {\n const variant = this.action().confirmVariant ?? 'primary';\n const responded = this.action().responded;\n const isSelected = responded && this.action().response === true;\n\n return {\n [`ngx-confirm-action__button--${variant}`]: true,\n 'ngx-confirm-action__button--selected': isSelected,\n 'ngx-confirm-action__button--not-selected': responded && !isSelected,\n };\n });\n\n /**\n * CSS classes for the cancel button based on variant.\n */\n readonly cancelButtonClasses = computed(() => {\n const variant = this.action().cancelVariant ?? 'secondary';\n const responded = this.action().responded;\n const isSelected = responded && this.action().response === false;\n\n return {\n [`ngx-confirm-action__button--${variant}`]: true,\n 'ngx-confirm-action__button--selected': isSelected,\n 'ngx-confirm-action__button--not-selected': responded && !isSelected,\n };\n });\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles confirm button click.\n * Emits true if action is not disabled.\n */\n onConfirm(): void {\n if (!this.isDisabled()) {\n this.respond.emit(true);\n }\n }\n\n /**\n * Handles cancel button click.\n * Emits false if action is not disabled.\n */\n onCancel(): void {\n if (!this.isDisabled()) {\n this.respond.emit(false);\n }\n }\n}\n","/**\n * @fileoverview Select action component for ngx-chat library.\n * Renders a single-select list of options for user selection.\n * @module ngx-chat/components/actions/select-action\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n inject,\n computed,\n signal,\n ElementRef,\n viewChildren,\n} from '@angular/core';\n\nimport type { SelectAction, ActionOption } from '../../../models/actions.model';\nimport { ChatConfigService } from '../../../services/chat-config.service';\n\n/**\n * Select action component that renders a single-select list of options.\n *\n * This component renders a list of selectable options. When the user\n * clicks an option (or navigates with keyboard and presses Enter),\n * the component emits the selected option ID.\n *\n * After responding, the selected option is highlighted and the list\n * becomes disabled. The component is purely presentational - the parent\n * is responsible for updating the action's `responded` and `response`\n * properties based on the emitted event.\n *\n * @example Basic usage\n * ```html\n * <ngx-select-action\n * [action]=\"selectAction\"\n * (respond)=\"onSelectResponse($event)\"\n * />\n * ```\n *\n * @example With searchable options\n * ```html\n * <ngx-select-action\n * [action]=\"{\n * type: 'select',\n * id: 'priority',\n * label: 'Select priority:',\n * options: priorityOptions,\n * searchable: true,\n * placeholder: 'Choose a priority...'\n * }\"\n * (respond)=\"onPrioritySelected($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ngx-select-action',\n standalone: true,\n template: `\n <!-- Optional label -->\n @if (action().label) {\n <label\n [id]=\"labelId()\"\n class=\"ngx-select-action__label\"\n >\n {{ action().label }}\n </label>\n }\n\n <!-- Search input (when searchable) -->\n @if (action().searchable && !action().responded) {\n <div class=\"ngx-select-action__search\">\n <input\n type=\"text\"\n class=\"ngx-select-action__search-input\"\n [placeholder]=\"action().placeholder ?? i18n().searchPlaceholder\"\n [value]=\"searchQuery()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"i18n().searchOptions\"\n [attr.aria-controls]=\"listboxId()\"\n (input)=\"onSearchInput($event)\"\n (keydown)=\"onSearchKeydown($event)\"\n />\n @if (searchQuery()) {\n <button\n type=\"button\"\n class=\"ngx-select-action__search-clear\"\n [attr.aria-label]=\"i18n().clearSearch\"\n (click)=\"clearSearch()\"\n >\n <span aria-hidden=\"true\">×</span>\n </button>\n }\n </div>\n }\n\n <!-- Options list -->\n <ul\n [id]=\"listboxId()\"\n class=\"ngx-select-action__options\"\n role=\"listbox\"\n [attr.aria-labelledby]=\"action().label ? labelId() : null\"\n [attr.aria-label]=\"!action().label ? i18n().actionSelect : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n tabindex=\"0\"\n (keydown)=\"onListKeydown($event)\"\n (focus)=\"onListFocus()\"\n (blur)=\"onListBlur()\"\n >\n @for (option of filteredOptions(); track option.id; let i = $index) {\n <li\n #optionElement\n [id]=\"getOptionId(option.id)\"\n class=\"ngx-select-action__option\"\n [class.ngx-select-action__option--focused]=\"focusedIndex() === i\"\n [class.ngx-select-action__option--selected]=\"isSelected(option.id)\"\n [class.ngx-select-action__option--disabled]=\"option.disabled || isDisabled()\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(option.id)\"\n [attr.aria-disabled]=\"option.disabled || isDisabled()\"\n (click)=\"selectOption(option)\"\n (mouseenter)=\"onOptionMouseEnter(i)\"\n >\n <span class=\"ngx-select-action__option-content\">\n @if (option.icon) {\n <span class=\"ngx-select-action__option-icon\" aria-hidden=\"true\">\n {{ option.icon }}\n </span>\n }\n <span class=\"ngx-select-action__option-label\">\n {{ option.label }}\n </span>\n @if (option.description) {\n <span class=\"ngx-select-action__option-description\">\n {{ option.description }}\n </span>\n }\n </span>\n @if (isSelected(option.id)) {\n <span class=\"ngx-select-action__check\" aria-hidden=\"true\">✓</span>\n }\n </li>\n } @empty {\n <li class=\"ngx-select-action__empty\" role=\"option\" aria-disabled=\"true\">\n {{ i18n().noOptionsFound }}\n </li>\n }\n </ul>\n\n <!-- Screen reader announcement -->\n @if (action().responded) {\n <span class=\"ngx-select-action__sr-announcement\" role=\"status\" aria-live=\"polite\">\n {{ selectedLabel() }} {{ i18n().selected }}\n </span>\n }\n `,\n styleUrls: ['./select-action.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-select-action',\n '[class.ngx-select-action--disabled]': 'isDisabled()',\n '[class.ngx-select-action--responded]': 'action().responded',\n '[class.ngx-select-action--searchable]': 'action().searchable',\n '[class.ngx-select-action--focused]': 'listFocused()',\n },\n})\nexport class SelectActionComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // ViewChildren\n // ===========================================================================\n\n private readonly optionElements = viewChildren<ElementRef<HTMLLIElement>>('optionElement');\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The select action configuration.\n * Contains options, label, searchable flag, and responded state.\n */\n readonly action = input.required<SelectAction>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits the ID of the selected option.\n */\n readonly respond = output<string>();\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /**\n * Current search query for filtering options.\n */\n readonly searchQuery = signal('');\n\n /**\n * Index of the currently focused option (for keyboard navigation).\n */\n readonly focusedIndex = signal(-1);\n\n /**\n * Whether the listbox currently has focus.\n */\n readonly listFocused = signal(false);\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n /**\n * Unique ID for the label element.\n */\n readonly labelId = computed(() => `select-label-${this.action().id}`);\n\n /**\n * Unique ID for the listbox element.\n */\n readonly listboxId = computed(() => `select-listbox-${this.action().id}`);\n\n /**\n * Whether the action is disabled (either explicitly or after responding).\n */\n readonly isDisabled = computed(() =>\n this.action().disabled === true || this.action().responded === true\n );\n\n /**\n * Options filtered by search query.\n */\n readonly filteredOptions = computed(() => {\n const options = this.action().options;\n const query = this.searchQuery().toLowerCase().trim();\n\n if (!query) {\n return options;\n }\n\n return options.filter(option =>\n option.label.toLowerCase().includes(query) ||\n (option.description?.toLowerCase().includes(query) ?? false)\n );\n });\n\n /**\n * The ID of the currently active (focused) option for ARIA.\n */\n readonly activeDescendantId = computed(() => {\n const index = this.focusedIndex();\n const options = this.filteredOptions();\n\n if (index >= 0 && index < options.length) {\n return this.getOptionId(options[index].id);\n }\n\n return null;\n });\n\n /**\n * Label of the selected option.\n */\n readonly selectedLabel = computed(() => {\n const response = this.action().response;\n if (!response) return '';\n\n const option = this.action().options.find(o => o.id === response);\n return option?.label ?? response;\n });\n\n // ===========================================================================\n // ID Generation\n // ===========================================================================\n\n /**\n * Generates a unique ID for an option element.\n */\n getOptionId(optionId: string): string {\n return `select-option-${this.action().id}-${optionId}`;\n }\n\n // ===========================================================================\n // State Checks\n // ===========================================================================\n\n /**\n * Checks if an option is currently selected.\n */\n isSelected(optionId: string): boolean {\n return this.action().response === optionId;\n }\n\n // ===========================================================================\n // Search Handlers\n // ===========================================================================\n\n /**\n * Handles search input changes.\n */\n onSearchInput(event: Event): void {\n const input = event.target as HTMLInputElement;\n this.searchQuery.set(input.value);\n this.focusedIndex.set(-1);\n }\n\n /**\n * Handles keyboard navigation in search input.\n */\n onSearchKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n this.focusedIndex.set(0);\n this.focusListbox();\n } else if (event.key === 'Escape') {\n this.clearSearch();\n }\n }\n\n /**\n * Clears the search query.\n */\n clearSearch(): void {\n this.searchQuery.set('');\n this.focusedIndex.set(-1);\n }\n\n // ===========================================================================\n // List Focus Handlers\n // ===========================================================================\n\n /**\n * Handles listbox focus.\n */\n onListFocus(): void {\n this.listFocused.set(true);\n if (this.focusedIndex() < 0 && this.filteredOptions().length > 0) {\n // Focus first option or selected option\n const selectedIndex = this.findSelectedIndex();\n this.focusedIndex.set(selectedIndex >= 0 ? selectedIndex : 0);\n }\n }\n\n /**\n * Handles listbox blur.\n */\n onListBlur(): void {\n this.listFocused.set(false);\n }\n\n /**\n * Focuses the listbox element.\n */\n private focusListbox(): void {\n const listbox = document.getElementById(this.listboxId());\n listbox?.focus();\n }\n\n /**\n * Finds the index of the currently selected option in filtered options.\n */\n private findSelectedIndex(): number {\n const response = this.action().response;\n if (!response) return -1;\n\n return this.filteredOptions().findIndex(o => o.id === response);\n }\n\n // ===========================================================================\n // Keyboard Navigation\n // ===========================================================================\n\n /**\n * Handles keyboard navigation in the options list.\n */\n onListKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) return;\n\n const options = this.filteredOptions();\n const currentIndex = this.focusedIndex();\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.focusNextOption(options.length, currentIndex);\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.focusPreviousOption(options.length, currentIndex);\n break;\n\n case 'Home':\n event.preventDefault();\n this.focusFirstOption(options);\n break;\n\n case 'End':\n event.preventDefault();\n this.focusLastOption(options);\n break;\n\n case 'Enter':\n case ' ':\n event.preventDefault();\n this.selectFocusedOption(options, currentIndex);\n break;\n\n case 'Escape':\n event.preventDefault();\n this.focusedIndex.set(-1);\n break;\n\n default:\n // Type-ahead: find option starting with pressed key\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {\n this.typeAhead(event.key, options, currentIndex);\n }\n break;\n }\n }\n\n /**\n * Focuses the next option in the list.\n */\n private focusNextOption(optionsLength: number, currentIndex: number): void {\n if (optionsLength === 0) return;\n\n const nextIndex = currentIndex < optionsLength - 1 ? currentIndex + 1 : 0;\n this.focusedIndex.set(nextIndex);\n this.scrollOptionIntoView(nextIndex);\n }\n\n /**\n * Focuses the previous option in the list.\n */\n private focusPreviousOption(optionsLength: number, currentIndex: number): void {\n if (optionsLength === 0) return;\n\n const prevIndex = currentIndex > 0 ? currentIndex - 1 : optionsLength - 1;\n this.focusedIndex.set(prevIndex);\n this.scrollOptionIntoView(prevIndex);\n }\n\n /**\n * Focuses the first non-disabled option.\n */\n private focusFirstOption(options: readonly ActionOption[]): void {\n const firstIndex = options.findIndex(o => !o.disabled);\n if (firstIndex >= 0) {\n this.focusedIndex.set(firstIndex);\n this.scrollOptionIntoView(firstIndex);\n }\n }\n\n /**\n * Focuses the last non-disabled option.\n */\n private focusLastOption(options: readonly ActionOption[]): void {\n for (let i = options.length - 1; i >= 0; i--) {\n if (!options[i].disabled) {\n this.focusedIndex.set(i);\n this.scrollOptionIntoView(i);\n break;\n }\n }\n }\n\n /**\n * Selects the currently focused option.\n */\n private selectFocusedOption(options: readonly ActionOption[], currentIndex: number): void {\n if (currentIndex >= 0 && currentIndex < options.length) {\n const option = options[currentIndex];\n if (!option.disabled) {\n this.selectOption(option);\n }\n }\n }\n\n /**\n * Type-ahead search: finds and focuses option starting with the pressed key.\n */\n private typeAhead(key: string, options: readonly ActionOption[], currentIndex: number): void {\n const lowerKey = key.toLowerCase();\n\n // Search from current index + 1 to end, then wrap to beginning\n for (let i = 0; i < options.length; i++) {\n const searchIndex = (currentIndex + 1 + i) % options.length;\n const option = options[searchIndex];\n\n if (!option.disabled && option.label.toLowerCase().startsWith(lowerKey)) {\n this.focusedIndex.set(searchIndex);\n this.scrollOptionIntoView(searchIndex);\n break;\n }\n }\n }\n\n /**\n * Scrolls the focused option into view.\n */\n private scrollOptionIntoView(index: number): void {\n const elements = this.optionElements();\n if (index >= 0 && index < elements.length) {\n const element = elements[index].nativeElement;\n // Check if scrollIntoView is available (not in jsdom test environment)\n if (typeof element.scrollIntoView === 'function') {\n element.scrollIntoView({\n block: 'nearest',\n behavior: 'smooth',\n });\n }\n }\n }\n\n // ===========================================================================\n // Mouse Handlers\n // ===========================================================================\n\n /**\n * Handles mouse entering an option (updates focus for visual feedback).\n */\n onOptionMouseEnter(index: number): void {\n if (!this.isDisabled()) {\n this.focusedIndex.set(index);\n }\n }\n\n // ===========================================================================\n // Selection\n // ===========================================================================\n\n /**\n * Selects an option and emits the response.\n */\n selectOption(option: ActionOption): void {\n if (this.isDisabled() || option.disabled) {\n return;\n }\n\n this.respond.emit(option.id);\n }\n}\n","/**\n * @fileoverview Multi-select action component for ngx-chat library.\n * Renders a multi-select list of options with min/max selection limits.\n * Uses linkedSignal for selection state that resets when action changes.\n * @module ngx-chat/components/actions/multi-select-action\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n inject,\n computed,\n signal,\n linkedSignal,\n ElementRef,\n viewChildren,\n} from '@angular/core';\n\nimport type { MultiSelectAction, ActionOption } from '../../../models/actions.model';\nimport { ChatConfigService } from '../../../services/chat-config.service';\n\n/**\n * Multi-select action component that renders a checkbox-style list of options.\n *\n * This component renders a list of options with checkboxes. Users can select\n * multiple options within the min/max constraints defined by the action.\n * After selecting options, the user must click the submit button to confirm.\n *\n * The component uses `linkedSignal` to track selection state. This ensures\n * that when the action input changes (e.g., parent updates the action),\n * the selection state automatically resets to match the new action's response.\n *\n * After responding, the selected options are highlighted and the component\n * becomes disabled. The component is purely presentational - the parent\n * is responsible for updating the action's `responded` and `response`\n * properties based on the emitted event.\n *\n * @example Basic usage\n * ```html\n * <ngx-multi-select-action\n * [action]=\"multiSelectAction\"\n * (respond)=\"onMultiSelectResponse($event)\"\n * />\n * ```\n *\n * @example With min/max limits\n * ```html\n * <ngx-multi-select-action\n * [action]=\"{\n * type: 'multi-select',\n * id: 'features',\n * label: 'Select features:',\n * options: featureOptions,\n * minSelect: 1,\n * maxSelect: 3,\n * submitText: 'Apply'\n * }\"\n * (respond)=\"onFeaturesSelected($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ngx-multi-select-action',\n standalone: true,\n template: `\n <!-- Optional label -->\n @if (action().label) {\n <label\n [id]=\"labelId()\"\n class=\"ngx-multi-select-action__label\"\n >\n {{ action().label }}\n </label>\n }\n\n <!-- Selection count -->\n <div class=\"ngx-multi-select-action__count\" aria-live=\"polite\">\n {{ selectionCountText() }}\n @if (hasLimits()) {\n <span class=\"ngx-multi-select-action__limits\">\n ({{ minSelect() }}-{{ maxSelectDisplay() }})\n </span>\n }\n </div>\n\n <!-- Options list -->\n <ul\n [id]=\"listboxId()\"\n class=\"ngx-multi-select-action__options\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n [attr.aria-labelledby]=\"action().label ? labelId() : null\"\n [attr.aria-label]=\"!action().label ? i18n().actionMultiSelect : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n tabindex=\"0\"\n (keydown)=\"onListKeydown($event)\"\n (focus)=\"onListFocus()\"\n (blur)=\"onListBlur()\"\n >\n @for (option of action().options; track option.id; let i = $index) {\n <li\n #optionElement\n [id]=\"getOptionId(option.id)\"\n class=\"ngx-multi-select-action__option\"\n [class.ngx-multi-select-action__option--focused]=\"focusedIndex() === i\"\n [class.ngx-multi-select-action__option--selected]=\"isSelected(option.id)\"\n [class.ngx-multi-select-action__option--disabled]=\"isOptionDisabled(option)\"\n role=\"option\"\n [attr.aria-selected]=\"isSelected(option.id)\"\n [attr.aria-disabled]=\"isOptionDisabled(option)\"\n (click)=\"toggleOption(option)\"\n (mouseenter)=\"onOptionMouseEnter(i)\"\n >\n <!-- Checkbox indicator -->\n <span\n class=\"ngx-multi-select-action__checkbox\"\n [class.ngx-multi-select-action__checkbox--checked]=\"isSelected(option.id)\"\n aria-hidden=\"true\"\n >\n @if (isSelected(option.id)) {\n <span class=\"ngx-multi-select-action__checkbox-icon\">✓</span>\n }\n </span>\n\n <span class=\"ngx-multi-select-action__option-content\">\n @if (option.icon) {\n <span class=\"ngx-multi-select-action__option-icon\" aria-hidden=\"true\">\n {{ option.icon }}\n </span>\n }\n <span class=\"ngx-multi-select-action__option-label\">\n {{ option.label }}\n </span>\n @if (option.description) {\n <span class=\"ngx-multi-select-action__option-description\">\n {{ option.description }}\n </span>\n }\n </span>\n </li>\n }\n </ul>\n\n <!-- Submit button -->\n @if (!action().responded) {\n <button\n type=\"button\"\n class=\"ngx-multi-select-action__submit\"\n [class.ngx-multi-select-action__submit--disabled]=\"!canSubmit()\"\n [disabled]=\"!canSubmit()\"\n (click)=\"onSubmit()\"\n >\n {{ action().submitText ?? i18n().submit }}\n </button>\n }\n\n <!-- Screen reader announcement -->\n @if (action().responded) {\n <span class=\"ngx-multi-select-action__sr-announcement\" role=\"status\" aria-live=\"polite\">\n {{ selectedLabels() }} {{ i18n().selected }}\n </span>\n }\n `,\n styleUrls: ['./multi-select-action.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-multi-select-action',\n '[class.ngx-multi-select-action--disabled]': 'isDisabled()',\n '[class.ngx-multi-select-action--responded]': 'action().responded',\n '[class.ngx-multi-select-action--focused]': 'listFocused()',\n '[class.ngx-multi-select-action--invalid]': '!isValid()',\n },\n})\nexport class MultiSelectActionComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // ViewChildren\n // ===========================================================================\n\n private readonly optionElements = viewChildren<ElementRef<HTMLLIElement>>('optionElement');\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The multi-select action configuration.\n * Contains options, label, min/max limits, and responded state.\n */\n readonly action = input.required<MultiSelectAction>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits the IDs of the selected options when user submits.\n */\n readonly respond = output<readonly string[]>();\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /**\n * Current selection state using linkedSignal.\n * Automatically resets when action input changes.\n */\n readonly selection = linkedSignal<MultiSelectAction, string[]>({\n source: this.action,\n computation: (action) => action.response ? [...action.response] : [],\n });\n\n /**\n * Index of the currently focused option (for keyboard navigation).\n */\n readonly focusedIndex = signal(-1);\n\n /**\n * Whether the listbox currently has focus.\n */\n readonly listFocused = signal(false);\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n /**\n * Unique ID for the label element.\n */\n readonly labelId = computed(() => `multi-select-label-${this.action().id}`);\n\n /**\n * Unique ID for the listbox element.\n */\n readonly listboxId = computed(() => `multi-select-listbox-${this.action().id}`);\n\n /**\n * Whether the action is disabled (either explicitly or after responding).\n */\n readonly isDisabled = computed(() =>\n this.action().disabled === true || this.action().responded === true\n );\n\n /**\n * Minimum number of selections required.\n */\n readonly minSelect = computed(() => this.action().minSelect ?? 0);\n\n /**\n * Maximum number of selections allowed.\n */\n readonly maxSelect = computed(() => this.action().maxSelect ?? Infinity);\n\n /**\n * Display text for max selection (shows ∞ if unlimited).\n */\n readonly maxSelectDisplay = computed(() => {\n const max = this.action().maxSelect;\n return max !== undefined ? max.toString() : '∞';\n });\n\n /**\n * Whether there are min/max limits configured.\n */\n readonly hasLimits = computed(() =>\n this.action().minSelect !== undefined || this.action().maxSelect !== undefined\n );\n\n /**\n * Number of currently selected options.\n */\n readonly selectionCount = computed(() => this.selection().length);\n\n /**\n * Text showing selection count.\n */\n readonly selectionCountText = computed(() => {\n const count = this.selectionCount();\n return this.i18n().selectedCount.replace('{count}', count.toString());\n });\n\n /**\n * Whether the current selection is valid (within min/max limits).\n */\n readonly isValid = computed(() => {\n const count = this.selectionCount();\n return count >= this.minSelect() && count <= this.maxSelect();\n });\n\n /**\n * Whether the submit button should be enabled.\n */\n readonly canSubmit = computed(() =>\n !this.isDisabled() && this.isValid() && this.selectionCount() > 0\n );\n\n /**\n * Whether the maximum selection limit has been reached.\n */\n readonly isMaxReached = computed(() => this.selectionCount() >= this.maxSelect());\n\n /**\n * The ID of the currently active (focused) option for ARIA.\n */\n readonly activeDescendantId = computed(() => {\n const index = this.focusedIndex();\n const options = this.action().options;\n\n if (index >= 0 && index < options.length) {\n return this.getOptionId(options[index].id);\n }\n\n return null;\n });\n\n /**\n * Labels of all selected options (for screen reader announcement).\n */\n readonly selectedLabels = computed(() => {\n const response = this.action().response;\n if (!response || response.length === 0) return '';\n\n const options = this.action().options;\n const selectedLabels = response\n .map(id => options.find(o => o.id === id)?.label ?? id)\n .join(', ');\n\n return selectedLabels;\n });\n\n // ===========================================================================\n // ID Generation\n // ===========================================================================\n\n /**\n * Generates a unique ID for an option element.\n */\n getOptionId(optionId: string): string {\n return `multi-select-option-${this.action().id}-${optionId}`;\n }\n\n // ===========================================================================\n // State Checks\n // ===========================================================================\n\n /**\n * Checks if an option is currently selected.\n */\n isSelected(optionId: string): boolean {\n return this.selection().includes(optionId);\n }\n\n /**\n * Checks if an option should be disabled.\n * An option is disabled if:\n * - The action is disabled\n * - The option itself is disabled\n * - Max selection reached AND option is not already selected\n */\n isOptionDisabled(option: ActionOption): boolean {\n if (this.isDisabled() || option.disabled) {\n return true;\n }\n\n // If max is reached, only allow deselecting (not selecting new ones)\n if (this.isMaxReached() && !this.isSelected(option.id)) {\n return true;\n }\n\n return false;\n }\n\n // ===========================================================================\n // List Focus Handlers\n // ===========================================================================\n\n /**\n * Handles listbox focus.\n */\n onListFocus(): void {\n this.listFocused.set(true);\n if (this.focusedIndex() < 0 && this.action().options.length > 0) {\n // Focus first selected option or first option\n const firstSelectedIndex = this.findFirstSelectedIndex();\n this.focusedIndex.set(firstSelectedIndex >= 0 ? firstSelectedIndex : 0);\n }\n }\n\n /**\n * Handles listbox blur.\n */\n onListBlur(): void {\n this.listFocused.set(false);\n }\n\n /**\n * Finds the index of the first selected option.\n */\n private findFirstSelectedIndex(): number {\n const selection = this.selection();\n if (selection.length === 0) return -1;\n\n return this.action().options.findIndex(o => selection.includes(o.id));\n }\n\n // ===========================================================================\n // Keyboard Navigation\n // ===========================================================================\n\n /**\n * Handles keyboard navigation in the options list.\n */\n onListKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) return;\n\n const options = this.action().options;\n const currentIndex = this.focusedIndex();\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.focusNextOption(options.length, currentIndex);\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.focusPreviousOption(options.length, currentIndex);\n break;\n\n case 'Home':\n event.preventDefault();\n this.focusFirstOption(options);\n break;\n\n case 'End':\n event.preventDefault();\n this.focusLastOption(options);\n break;\n\n case ' ':\n event.preventDefault();\n this.toggleFocusedOption(options, currentIndex);\n break;\n\n case 'Enter':\n event.preventDefault();\n if (this.canSubmit()) {\n this.onSubmit();\n }\n break;\n\n case 'a':\n case 'A':\n if (event.ctrlKey || event.metaKey) {\n event.preventDefault();\n this.selectAll();\n }\n break;\n\n default:\n // Type-ahead: find option starting with pressed key\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {\n this.typeAhead(event.key, options, currentIndex);\n }\n break;\n }\n }\n\n /**\n * Focuses the next option in the list.\n */\n private focusNextOption(optionsLength: number, currentIndex: number): void {\n if (optionsLength === 0) return;\n\n const nextIndex = currentIndex < optionsLength - 1 ? currentIndex + 1 : 0;\n this.focusedIndex.set(nextIndex);\n this.scrollOptionIntoView(nextIndex);\n }\n\n /**\n * Focuses the previous option in the list.\n */\n private focusPreviousOption(optionsLength: number, currentIndex: number): void {\n if (optionsLength === 0) return;\n\n const prevIndex = currentIndex > 0 ? currentIndex - 1 : optionsLength - 1;\n this.focusedIndex.set(prevIndex);\n this.scrollOptionIntoView(prevIndex);\n }\n\n /**\n * Focuses the first non-disabled option.\n */\n private focusFirstOption(options: readonly ActionOption[]): void {\n const firstIndex = options.findIndex(o => !this.isOptionDisabled(o));\n if (firstIndex >= 0) {\n this.focusedIndex.set(firstIndex);\n this.scrollOptionIntoView(firstIndex);\n }\n }\n\n /**\n * Focuses the last non-disabled option.\n */\n private focusLastOption(options: readonly ActionOption[]): void {\n for (let i = options.length - 1; i >= 0; i--) {\n if (!this.isOptionDisabled(options[i])) {\n this.focusedIndex.set(i);\n this.scrollOptionIntoView(i);\n break;\n }\n }\n }\n\n /**\n * Toggles the currently focused option.\n */\n private toggleFocusedOption(options: readonly ActionOption[], currentIndex: number): void {\n if (currentIndex >= 0 && currentIndex < options.length) {\n const option = options[currentIndex];\n if (!this.isOptionDisabled(option)) {\n this.toggleOption(option);\n }\n }\n }\n\n /**\n * Type-ahead search: finds and focuses option starting with the pressed key.\n */\n private typeAhead(key: string, options: readonly ActionOption[], currentIndex: number): void {\n const lowerKey = key.toLowerCase();\n\n // Search from current index + 1 to end, then wrap to beginning\n for (let i = 0; i < options.length; i++) {\n const searchIndex = (currentIndex + 1 + i) % options.length;\n const option = options[searchIndex];\n\n if (!option.disabled && option.label.toLowerCase().startsWith(lowerKey)) {\n this.focusedIndex.set(searchIndex);\n this.scrollOptionIntoView(searchIndex);\n break;\n }\n }\n }\n\n /**\n * Scrolls the focused option into view.\n */\n private scrollOptionIntoView(index: number): void {\n const elements = this.optionElements();\n if (index >= 0 && index < elements.length) {\n const element = elements[index].nativeElement;\n if (typeof element.scrollIntoView === 'function') {\n element.scrollIntoView({\n block: 'nearest',\n behavior: 'smooth',\n });\n }\n }\n }\n\n // ===========================================================================\n // Mouse Handlers\n // ===========================================================================\n\n /**\n * Handles mouse entering an option (updates focus for visual feedback).\n */\n onOptionMouseEnter(index: number): void {\n if (!this.isDisabled()) {\n this.focusedIndex.set(index);\n }\n }\n\n // ===========================================================================\n // Selection\n // ===========================================================================\n\n /**\n * Toggles an option's selection state.\n */\n toggleOption(option: ActionOption): void {\n if (this.isOptionDisabled(option)) {\n return;\n }\n\n const current = this.selection();\n const isCurrentlySelected = current.includes(option.id);\n\n if (isCurrentlySelected) {\n // Remove from selection\n this.selection.set(current.filter(id => id !== option.id));\n } else {\n // Add to selection (if under max limit)\n if (current.length < this.maxSelect()) {\n this.selection.set([...current, option.id]);\n }\n }\n }\n\n /**\n * Selects all selectable options (up to max limit).\n */\n private selectAll(): void {\n if (this.isDisabled()) return;\n\n const options = this.action().options;\n const selectableOptions = options\n .filter(o => !o.disabled)\n .map(o => o.id)\n .slice(0, this.maxSelect());\n\n this.selection.set(selectableOptions);\n }\n\n // ===========================================================================\n // Submit\n // ===========================================================================\n\n /**\n * Submits the current selection.\n */\n onSubmit(): void {\n if (!this.canSubmit()) {\n return;\n }\n\n this.respond.emit(this.selection());\n }\n}\n","/**\n * @fileoverview Buttons action component for ngx-chat library.\n * Renders a group of buttons for quick-reply style actions.\n * @module ngx-chat/components/actions/buttons-action\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n inject,\n computed,\n} from '@angular/core';\n\nimport type { ButtonsAction, ActionButton, ButtonVariant } from '../../../models/actions.model';\nimport { ChatConfigService } from '../../../services/chat-config.service';\n\n/**\n * Buttons action component that renders a group of quick-reply buttons.\n *\n * This component displays multiple buttons in configurable layouts (horizontal,\n * vertical, or grid). When a user clicks any button, all buttons become disabled\n * and the clicked button is visually indicated with a checkmark.\n *\n * The component is purely presentational - the parent is responsible for\n * updating the action's `responded` and `response` properties based on\n * the emitted event.\n *\n * @example Basic usage\n * ```html\n * <ngx-buttons-action\n * [action]=\"buttonsAction\"\n * (respond)=\"onButtonResponse($event)\"\n * />\n * ```\n *\n * @example In message actions container\n * ```html\n * @case ('buttons') {\n * <ngx-buttons-action\n * [action]=\"getButtonsAction(action)\"\n * (respond)=\"onActionResponse(action.id, 'buttons', $event)\"\n * />\n * }\n * ```\n *\n * @example Different layouts\n * ```typescript\n * // Horizontal (default)\n * const horizontal: ButtonsAction = {\n * type: 'buttons',\n * id: 'action-1',\n * buttons: [{ id: 'a', label: 'Option A' }, { id: 'b', label: 'Option B' }],\n * layout: 'horizontal'\n * };\n *\n * // Vertical\n * const vertical: ButtonsAction = {\n * type: 'buttons',\n * id: 'action-2',\n * buttons: [{ id: 'a', label: 'Option A' }, { id: 'b', label: 'Option B' }],\n * layout: 'vertical'\n * };\n *\n * // Grid with 3 columns\n * const grid: ButtonsAction = {\n * type: 'buttons',\n * id: 'action-3',\n * buttons: [...],\n * layout: 'grid',\n * columns: 3\n * };\n * ```\n */\n@Component({\n selector: 'ngx-buttons-action',\n standalone: true,\n template: `\n <div\n class=\"ngx-buttons-action__buttons\"\n [class]=\"layoutClass()\"\n [style.--grid-columns]=\"gridColumns()\"\n role=\"group\"\n [attr.aria-label]=\"i18n().actionButtons\"\n >\n @for (button of action().buttons; track button.id) {\n <button\n type=\"button\"\n class=\"ngx-buttons-action__button\"\n [class]=\"getButtonClasses(button)\"\n [disabled]=\"isDisabled() || isButtonDisabled(button)\"\n [attr.aria-pressed]=\"isButtonSelected(button)\"\n (click)=\"onButtonClick(button.id)\"\n >\n <span class=\"ngx-buttons-action__button-text\">\n {{ button.label }}\n </span>\n @if (isButtonSelected(button)) {\n <span class=\"ngx-buttons-action__check\" aria-hidden=\"true\">✓</span>\n }\n </button>\n }\n </div>\n\n <!-- Screen reader announcement -->\n @if (action().responded && selectedButtonLabel()) {\n <span class=\"ngx-buttons-action__sr-announcement\" role=\"status\" aria-live=\"polite\">\n {{ selectedButtonLabel() }} {{ i18n().selected }}\n </span>\n }\n `,\n styleUrls: ['./buttons-action.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-buttons-action',\n '[class.ngx-buttons-action--disabled]': 'isDisabled()',\n '[class.ngx-buttons-action--responded]': 'action().responded',\n '[class.ngx-buttons-action--horizontal]': \"action().layout === 'horizontal' || !action().layout\",\n '[class.ngx-buttons-action--vertical]': \"action().layout === 'vertical'\",\n '[class.ngx-buttons-action--grid]': \"action().layout === 'grid'\",\n },\n})\nexport class ButtonsActionComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The buttons action configuration.\n * Contains button definitions, layout, and responded state.\n */\n readonly action = input.required<ButtonsAction>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits the ID of the clicked button.\n */\n readonly respond = output<string>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n /**\n * Whether the action is disabled (either explicitly or after responding).\n */\n readonly isDisabled = computed(() =>\n this.action().disabled === true || this.action().responded === true\n );\n\n /**\n * CSS class for the layout mode.\n */\n readonly layoutClass = computed(() => {\n const layout = this.action().layout ?? 'horizontal';\n return `ngx-buttons-action__buttons--${layout}`;\n });\n\n /**\n * Number of grid columns (only relevant for grid layout).\n */\n readonly gridColumns = computed(() => {\n if (this.action().layout === 'grid') {\n return this.action().columns ?? 2;\n }\n return undefined;\n });\n\n /**\n * Label of the selected button (for screen reader announcement).\n */\n readonly selectedButtonLabel = computed(() => {\n const action = this.action();\n if (!action.responded || !action.response) {\n return null;\n }\n const selectedButton = action.buttons.find(b => b.id === action.response);\n return selectedButton?.label ?? null;\n });\n\n // ===========================================================================\n // Methods\n // ===========================================================================\n\n /**\n * Gets CSS classes for a button based on its variant and state.\n *\n * @param button - The button to get classes for\n * @returns Object of CSS class names to boolean values\n */\n getButtonClasses(button: ActionButton): Record<string, boolean> {\n const variant = button.variant ?? 'secondary';\n const isSelected = this.isButtonSelected(button);\n const responded = this.action().responded;\n\n return {\n [`ngx-buttons-action__button--${variant}`]: true,\n 'ngx-buttons-action__button--selected': isSelected,\n 'ngx-buttons-action__button--not-selected': responded === true && !isSelected,\n 'ngx-buttons-action__button--individual-disabled': button.disabled === true,\n };\n }\n\n /**\n * Checks if a specific button is disabled.\n *\n * @param button - The button to check\n * @returns True if the button is individually disabled\n */\n isButtonDisabled(button: ActionButton): boolean {\n return button.disabled === true;\n }\n\n /**\n * Checks if a button is the selected one.\n *\n * @param button - The button to check\n * @returns True if this button was clicked\n */\n isButtonSelected(button: ActionButton): boolean {\n const action = this.action();\n return action.responded === true && action.response === button.id;\n }\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles button click.\n * Emits the button ID if the action and button are not disabled.\n *\n * @param buttonId - ID of the clicked button\n */\n onButtonClick(buttonId: string): void {\n const button = this.action().buttons.find(b => b.id === buttonId);\n if (!this.isDisabled() && button && !this.isButtonDisabled(button)) {\n this.respond.emit(buttonId);\n }\n }\n}\n","/**\n * @fileoverview Chat message actions container component for ngx-chat library.\n * Routes to appropriate action sub-components based on action type.\n * @module ngx-chat/components/chat-message-actions\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n inject,\n computed,\n} from '@angular/core';\n\nimport type {\n MessageAction,\n MessageActionType,\n ConfirmAction,\n SelectAction,\n MultiSelectAction,\n ButtonsAction,\n MessageActionEvent,\n} from '../../models/actions.model';\nimport { ChatEventService } from '../../services/chat-event.service';\nimport { ChatConfigService } from '../../services/chat-config.service';\nimport { ConfirmActionComponent } from '../actions/confirm-action/confirm-action.component';\nimport { SelectActionComponent } from '../actions/select-action/select-action.component';\nimport { MultiSelectActionComponent } from '../actions/multi-select-action/multi-select-action.component';\nimport { ButtonsActionComponent } from '../actions/buttons-action/buttons-action.component';\n\n/**\n * Container component for rendering interactive message actions.\n *\n * This component receives an array of actions attached to a message and\n * routes each action to the appropriate sub-component based on its type.\n * When users respond to actions, events are forwarded to the ChatEventService\n * which bubbles them up to the parent ChatComponent.\n *\n * Implemented action components:\n * - ConfirmAction: Binary confirm/cancel choice\n * - SelectAction: Single-select from list of options\n * - MultiSelectAction: Multi-select with min/max limits\n * - ButtonsAction: Quick-reply button group\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-message-actions\n * [actions]=\"message.actions\"\n * [messageId]=\"message.id\"\n * />\n * ```\n *\n * @example In message bubble template\n * ```html\n * @if (message().actions?.length) {\n * <ngx-chat-message-actions\n * [actions]=\"message().actions!\"\n * [messageId]=\"message().id\"\n * />\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat-message-actions',\n standalone: true,\n imports: [ConfirmActionComponent, SelectActionComponent, MultiSelectActionComponent, ButtonsActionComponent],\n template: `\n @for (action of actions(); track action.id) {\n <div\n class=\"ngx-chat-message-actions__action\"\n [class.ngx-chat-message-actions__action--disabled]=\"action.disabled\"\n [class.ngx-chat-message-actions__action--responded]=\"action.responded\"\n [attr.data-action-id]=\"action.id\"\n [attr.data-action-type]=\"action.type\"\n >\n @switch (action.type) {\n @case ('confirm') {\n <ngx-confirm-action\n [action]=\"getConfirmAction(action)\"\n (respond)=\"onActionResponse(action.id, 'confirm', $event)\"\n />\n }\n @case ('select') {\n <ngx-select-action\n [action]=\"getSelectAction(action)\"\n (respond)=\"onActionResponse(action.id, 'select', $event)\"\n />\n }\n @case ('multi-select') {\n <ngx-multi-select-action\n [action]=\"getMultiSelectAction(action)\"\n (respond)=\"onActionResponse(action.id, 'multi-select', $event)\"\n />\n }\n @case ('buttons') {\n <ngx-buttons-action\n [action]=\"getButtonsAction(action)\"\n (respond)=\"onActionResponse(action.id, 'buttons', $event)\"\n />\n }\n }\n </div>\n }\n `,\n styleUrls: ['./chat-message-actions.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-message-actions',\n '[class.ngx-chat-message-actions--empty]': 'actions().length === 0',\n 'role': 'region',\n '[attr.aria-label]': 'i18n().messageActions',\n },\n})\nexport class ChatMessageActionsComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly eventService = inject(ChatEventService);\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * Array of actions to render.\n * Each action will be routed to its appropriate component based on type.\n */\n readonly actions = input.required<readonly MessageAction[]>();\n\n /**\n * ID of the parent message.\n * Used to provide context in action events.\n */\n readonly messageId = input.required<string>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n // ===========================================================================\n // Type Guard Methods\n // ===========================================================================\n\n /**\n * Type guard to narrow MessageAction to ConfirmAction.\n * Used in template for type-safe property access.\n */\n getConfirmAction(action: MessageAction): ConfirmAction {\n return action as ConfirmAction;\n }\n\n /**\n * Type guard to narrow MessageAction to SelectAction.\n * Used in template for type-safe property access.\n */\n getSelectAction(action: MessageAction): SelectAction {\n return action as SelectAction;\n }\n\n /**\n * Type guard to narrow MessageAction to MultiSelectAction.\n * Used in template for type-safe property access.\n */\n getMultiSelectAction(action: MessageAction): MultiSelectAction {\n return action as MultiSelectAction;\n }\n\n /**\n * Type guard to narrow MessageAction to ButtonsAction.\n * Used in template for type-safe property access.\n */\n getButtonsAction(action: MessageAction): ButtonsAction {\n return action as ButtonsAction;\n }\n\n // ===========================================================================\n // Event Handling\n // ===========================================================================\n\n /**\n * Handles action response and emits to ChatEventService.\n * Called by child action components when user responds.\n *\n * @param actionId - ID of the action being responded to\n * @param type - Type of action\n * @param response - The user's response value\n */\n onActionResponse<T extends MessageActionType>(\n actionId: string,\n type: T,\n response: T extends 'confirm' ? boolean\n : T extends 'select' ? string\n : T extends 'multi-select' ? readonly string[]\n : T extends 'buttons' ? string\n : never\n ): void {\n const event = {\n type,\n messageId: this.messageId(),\n actionId,\n response,\n } as MessageActionEvent;\n\n this.eventService.emitAction(event);\n }\n}\n","/**\n * @fileoverview Drag-and-drop directive for file uploads in ngx-chat.\n * Enables users to drop files onto designated areas of the chat interface.\n * @module ngx-chat/directives/chat-drop-zone\n */\n\nimport { Directive, HostListener, output, signal } from '@angular/core';\n\n/**\n * Directive for creating drop zones that accept file uploads via drag-and-drop.\n *\n * Apply this directive to any element to make it a drop zone. When files are\n * dropped, the `filesDropped` output emits the FileList. The `isDragOver` signal\n * and host class binding provide visual feedback during drag operations.\n *\n * @example\n * ```html\n * <!-- Basic usage -->\n * <div ngxChatDropZone (filesDropped)=\"onFilesDropped($event)\">\n * Drop files here\n * </div>\n * ```\n *\n * @example\n * ```html\n * <!-- With custom styling based on drag state -->\n * <div ngxChatDropZone\n * (filesDropped)=\"onFilesDropped($event)\"\n * [class.custom-active]=\"dropZone.isDragOver()\">\n * <span *ngIf=\"!dropZone.isDragOver()\">Drop files here</span>\n * <span *ngIf=\"dropZone.isDragOver()\">Release to upload</span>\n * </div>\n * ```\n *\n * @example\n * ```typescript\n * // In component class\n * onFilesDropped(files: FileList): void {\n * Array.from(files).forEach(file => {\n * console.log('File dropped:', file.name, file.size);\n * });\n * }\n * ```\n *\n * The directive applies the CSS class `ngx-chat-drop-zone--active` to the host\n * element when files are being dragged over it. This class can be used for\n * visual feedback (e.g., border highlight, background color change).\n *\n * The directive uses a counter pattern to handle nested elements correctly.\n * This prevents flickering when dragging over child elements within the drop zone.\n */\n@Directive({\n selector: '[ngxChatDropZone]',\n standalone: true,\n exportAs: 'ngxChatDropZone',\n host: {\n '[class.ngx-chat-drop-zone--active]': 'isDragOver()',\n '[attr.aria-dropeffect]': '\"copy\"',\n },\n})\nexport class ChatDropZoneDirective {\n /**\n * Emits when files are dropped onto the drop zone.\n * The FileList contains all files that were dropped.\n * Only emits for file drops, not for text or other data types.\n */\n readonly filesDropped = output<FileList>();\n\n /**\n * Signal indicating whether files are currently being dragged over the drop zone.\n * Use this signal to provide visual feedback to users.\n */\n readonly isDragOver = signal(false);\n\n /**\n * Counter for tracking nested drag events.\n * Incremented on dragenter, decremented on dragleave.\n * This prevents flickering when dragging over child elements.\n * @internal\n */\n private dragCounter = 0;\n\n /**\n * Handles the dragenter event when files enter the drop zone.\n * Increments the counter and sets isDragOver to true.\n *\n * @param event - The drag event\n */\n @HostListener('dragenter', ['$event'])\n onDragEnter(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n\n this.dragCounter++;\n\n if (this.hasFiles(event)) {\n this.isDragOver.set(true);\n }\n }\n\n /**\n * Handles the dragleave event when files leave the drop zone.\n * Decrements the counter and sets isDragOver to false when counter reaches 0.\n *\n * @param event - The drag event\n */\n @HostListener('dragleave', ['$event'])\n onDragLeave(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n\n this.dragCounter--;\n\n if (this.dragCounter === 0) {\n this.isDragOver.set(false);\n }\n }\n\n /**\n * Handles the dragover event to allow dropping.\n * Prevents default browser behavior which would prevent the drop event.\n *\n * @param event - The drag event\n */\n @HostListener('dragover', ['$event'])\n onDragOver(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n\n if (event.dataTransfer && this.hasFiles(event)) {\n event.dataTransfer.dropEffect = 'copy';\n }\n }\n\n /**\n * Handles the drop event when files are released over the drop zone.\n * Resets the counter, sets isDragOver to false, and emits the dropped files.\n *\n * @param event - The drag event\n */\n @HostListener('drop', ['$event'])\n onDrop(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n\n // Reset state\n this.dragCounter = 0;\n this.isDragOver.set(false);\n\n // Extract and emit files\n const files = event.dataTransfer?.files;\n if (files && files.length > 0) {\n this.filesDropped.emit(files);\n }\n }\n\n /**\n * Checks if the drag event contains files.\n * Used to differentiate between file drops and text/other data drops.\n *\n * @param event - The drag event to check\n * @returns True if the event contains files, false otherwise\n * @internal\n */\n private hasFiles(event: DragEvent): boolean {\n if (!event.dataTransfer) {\n return false;\n }\n\n // Check dataTransfer types for files\n const types = event.dataTransfer.types;\n return types.includes('Files') || types.includes('application/x-moz-file');\n }\n}\n","/**\n * @fileoverview Attachment picker component for ngx-chat library.\n * Provides a button to select files and supports drag-and-drop.\n * @module ngx-chat/components/chat-attachment-picker\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n viewChild,\n ElementRef,\n inject,\n computed,\n} from '@angular/core';\n\nimport { ChatDropZoneDirective } from '../../directives/chat-drop-zone.directive';\nimport { ChatConfigService } from '../../services/chat-config.service';\n\n/**\n * Attachment picker component for selecting files to upload.\n *\n * This component provides a button that triggers a hidden file input,\n * and integrates with the drop zone directive for drag-and-drop support.\n * Both click-to-select and drag-drop emit the same `filesSelected` output.\n *\n * The component is purely presentational - the parent is responsible for\n * handling the selected files (uploading, previewing, etc.).\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-attachment-picker\n * (filesSelected)=\"onFilesSelected($event)\"\n * />\n * ```\n *\n * @example With file type filter\n * ```html\n * <ngx-chat-attachment-picker\n * accept=\"image/*,application/pdf\"\n * (filesSelected)=\"onFilesSelected($event)\"\n * />\n * ```\n *\n * @example Single file selection\n * ```html\n * <ngx-chat-attachment-picker\n * [multiple]=\"false\"\n * (filesSelected)=\"onFilesSelected($event)\"\n * />\n * ```\n *\n * @example Disabled state\n * ```html\n * <ngx-chat-attachment-picker\n * [disabled]=\"isUploading()\"\n * (filesSelected)=\"onFilesSelected($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ngx-chat-attachment-picker',\n standalone: true,\n imports: [ChatDropZoneDirective],\n template: `\n <!-- Hidden file input -->\n <input\n #fileInput\n type=\"file\"\n class=\"ngx-attachment-picker__input\"\n [accept]=\"accept()\"\n [multiple]=\"multiple()\"\n [disabled]=\"disabled()\"\n (change)=\"onFileInputChange($event)\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n />\n\n <!-- Picker button -->\n <button\n type=\"button\"\n class=\"ngx-attachment-picker__button\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"ariaLabel() || i18n().ariaAttachmentPicker\"\n (click)=\"openFilePicker()\"\n >\n <svg\n class=\"ngx-attachment-picker__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48\" />\n </svg>\n <span class=\"ngx-attachment-picker__label\">\n <ng-content>{{ i18n().addAttachment }}</ng-content>\n </span>\n </button>\n `,\n styleUrls: ['./attachment-picker.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n hostDirectives: [\n {\n directive: ChatDropZoneDirective,\n outputs: ['filesDropped'],\n },\n ],\n host: {\n 'class': 'ngx-attachment-picker',\n '[class.ngx-attachment-picker--disabled]': 'disabled()',\n '[class.ngx-attachment-picker--drag-over]': 'dropZone.isDragOver()',\n },\n})\nexport class AttachmentPickerComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n\n /**\n * Reference to the drop zone directive on the host element.\n * Used to detect drag-over state for visual feedback.\n */\n readonly dropZone = inject(ChatDropZoneDirective);\n\n // ===========================================================================\n // View Children\n // ===========================================================================\n\n /**\n * Reference to the hidden file input element.\n * Used to programmatically trigger the file picker.\n */\n private readonly fileInput = viewChild.required<ElementRef<HTMLInputElement>>('fileInput');\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * Whether the picker is disabled.\n * When disabled, the button cannot be clicked and files cannot be dropped.\n * @default false\n */\n readonly disabled = input(false);\n\n /**\n * Whether to allow multiple file selection.\n * When true, users can select multiple files at once.\n * @default true\n */\n readonly multiple = input(true);\n\n /**\n * Accepted file types (MIME types or file extensions).\n * Examples: \"image/*\", \".pdf,.doc\", \"image/png,image/jpeg\"\n * @default '' (all files accepted)\n */\n readonly accept = input('');\n\n /**\n * Custom ARIA label for the picker button.\n * Falls back to i18n.attachFiles if not provided.\n */\n readonly ariaLabel = input<string>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits when files are selected (via click or drag-and-drop).\n * The FileList contains all selected files.\n */\n readonly filesSelected = output<FileList>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n // ===========================================================================\n // Constructor\n // ===========================================================================\n\n constructor() {\n // Subscribe to drop zone file drops\n this.dropZone.filesDropped.subscribe((files: FileList) => {\n if (!this.disabled()) {\n this.filesSelected.emit(files);\n }\n });\n }\n\n // ===========================================================================\n // Public Methods\n // ===========================================================================\n\n /**\n * Opens the file picker dialog.\n * Called when the button is clicked.\n */\n openFilePicker(): void {\n if (!this.disabled()) {\n this.fileInput().nativeElement.click();\n }\n }\n\n /**\n * Handles file input change event.\n * Emits selected files and resets the input for re-selection.\n *\n * @param event - The change event from the file input\n */\n onFileInputChange(event: Event): void {\n const input = event.target as HTMLInputElement;\n const files = input.files;\n\n if (files && files.length > 0) {\n this.filesSelected.emit(files);\n }\n\n // Reset input to allow re-selecting the same file\n input.value = '';\n }\n}\n","/**\n * @fileoverview Attachment preview component for ngx-chat library.\n * Displays pending attachments with upload progress and actions.\n * @module ngx-chat/components/chat-attachment-picker\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n computed,\n inject,\n} from '@angular/core';\n\nimport { PendingAttachment, AttachmentType } from '../../models/attachment.model';\nimport { ChatConfigService } from '../../services/chat-config.service';\n\n/**\n * Attachment preview component for displaying pending uploads.\n *\n * This component displays a grid of pending attachments with:\n * - Image/video previews using blob URLs\n * - File type icons for non-image attachments\n * - Upload progress indicators\n * - Remove and retry buttons\n * - Error state display\n *\n * The component is purely presentational - the parent is responsible for\n * managing the attachment list and handling remove/retry actions.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-attachment-preview\n * [attachments]=\"pendingAttachments()\"\n * (remove)=\"onRemove($event)\"\n * (retry)=\"onRetry($event)\"\n * />\n * ```\n *\n * @example With custom styling\n * ```html\n * <ngx-chat-attachment-preview\n * [attachments]=\"pendingAttachments()\"\n * (remove)=\"onRemove($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'ngx-chat-attachment-preview',\n standalone: true,\n imports: [],\n template: `\n @if (attachments().length > 0) {\n <div class=\"ngx-attachment-preview__list\" role=\"list\">\n @for (attachment of attachments(); track attachment.id) {\n <div\n class=\"ngx-attachment-preview__item\"\n [class.ngx-attachment-preview__item--pending]=\"attachment.status === 'pending'\"\n [class.ngx-attachment-preview__item--uploading]=\"attachment.status === 'uploading'\"\n [class.ngx-attachment-preview__item--processing]=\"attachment.status === 'processing'\"\n [class.ngx-attachment-preview__item--complete]=\"attachment.status === 'complete'\"\n [class.ngx-attachment-preview__item--error]=\"attachment.status === 'error'\"\n role=\"listitem\"\n >\n <!-- Preview content -->\n <div class=\"ngx-attachment-preview__content\">\n @if (isVisualType(attachment.type) && attachment.previewUrl) {\n <!-- Image/Video preview -->\n <img\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.file.name\"\n class=\"ngx-attachment-preview__image\"\n loading=\"lazy\"\n />\n } @else {\n <!-- File type icon -->\n <div class=\"ngx-attachment-preview__icon-wrapper\">\n <svg\n class=\"ngx-attachment-preview__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (attachment.type) {\n @case ('audio') {\n <path d=\"M9 18V5l12-2v13\" />\n <circle cx=\"6\" cy=\"18\" r=\"3\" />\n <circle cx=\"18\" cy=\"16\" r=\"3\" />\n }\n @case ('video') {\n <rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" />\n <polygon points=\"10 8 16 12 10 16 10 8\" fill=\"currentColor\" />\n }\n @default {\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n }\n }\n </svg>\n </div>\n }\n\n <!-- Progress overlay for uploading/processing -->\n @if (attachment.status === 'uploading' || attachment.status === 'processing') {\n <div class=\"ngx-attachment-preview__progress-overlay\">\n <svg\n class=\"ngx-attachment-preview__progress-ring\"\n viewBox=\"0 0 36 36\"\n aria-hidden=\"true\"\n >\n <circle\n class=\"ngx-attachment-preview__progress-bg\"\n cx=\"18\"\n cy=\"18\"\n r=\"15.5\"\n fill=\"none\"\n stroke-width=\"3\"\n />\n <circle\n class=\"ngx-attachment-preview__progress-value\"\n cx=\"18\"\n cy=\"18\"\n r=\"15.5\"\n fill=\"none\"\n stroke-width=\"3\"\n [style.stroke-dasharray]=\"getProgressDashArray(attachment.progress)\"\n [style.stroke-dashoffset]=\"getProgressDashOffset(attachment.progress)\"\n />\n </svg>\n <span class=\"ngx-attachment-preview__progress-text\" aria-live=\"polite\">\n {{ attachment.progress }}%\n </span>\n </div>\n }\n\n <!-- Processing spinner -->\n @if (attachment.status === 'processing') {\n <div class=\"ngx-attachment-preview__spinner\" aria-label=\"Processing\">\n <svg\n class=\"ngx-attachment-preview__spinner-icon\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-dasharray=\"31.4 31.4\" />\n </svg>\n </div>\n }\n\n <!-- Error overlay -->\n @if (attachment.status === 'error') {\n <div class=\"ngx-attachment-preview__error-overlay\">\n <svg\n class=\"ngx-attachment-preview__error-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\" />\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\" />\n </svg>\n </div>\n }\n </div>\n\n <!-- File name -->\n <div class=\"ngx-attachment-preview__name\" [title]=\"attachment.file.name\">\n {{ truncateFileName(attachment.file.name) }}\n </div>\n\n <!-- Error message -->\n @if (attachment.status === 'error' && attachment.error) {\n <div class=\"ngx-attachment-preview__error-message\" role=\"alert\">\n {{ attachment.error }}\n </div>\n }\n\n <!-- Actions -->\n <div class=\"ngx-attachment-preview__actions\">\n <!-- Retry button for errors -->\n @if (attachment.status === 'error') {\n <button\n type=\"button\"\n class=\"ngx-attachment-preview__action ngx-attachment-preview__action--retry\"\n [attr.aria-label]=\"i18n().ariaRetryUpload || 'Retry upload'\"\n (click)=\"onRetryClick(attachment.id)\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"23 4 23 10 17 10\" />\n <path d=\"M20.49 15a9 9 0 1 1-2.12-9.36L23 10\" />\n </svg>\n </button>\n }\n\n <!-- Remove button -->\n <button\n type=\"button\"\n class=\"ngx-attachment-preview__action ngx-attachment-preview__action--remove\"\n [attr.aria-label]=\"getRemoveAriaLabel(attachment)\"\n (click)=\"onRemoveClick(attachment.id)\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n }\n </div>\n }\n `,\n styleUrls: ['./attachment-preview.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-attachment-preview',\n '[class.ngx-attachment-preview--empty]': 'attachments().length === 0',\n },\n})\nexport class AttachmentPreviewComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * Array of pending attachments to display.\n * Each attachment includes file info, status, and progress.\n * @default []\n */\n readonly attachments = input<PendingAttachment[]>([]);\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits the attachment ID when remove is clicked.\n * Parent should remove the attachment from the list.\n */\n readonly remove = output<string>();\n\n /**\n * Emits the attachment ID when retry is clicked.\n * Parent should retry the upload for the attachment.\n */\n readonly retry = output<string>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n // ===========================================================================\n // Constants\n // ===========================================================================\n\n /**\n * Circumference of the progress circle (2 * PI * radius).\n */\n private readonly CIRCLE_CIRCUMFERENCE = 2 * Math.PI * 15.5;\n\n /**\n * Maximum file name length before truncation.\n */\n private readonly MAX_FILE_NAME_LENGTH = 20;\n\n // ===========================================================================\n // Public Methods\n // ===========================================================================\n\n /**\n * Checks if the attachment type should show a visual preview.\n *\n * @param type - The attachment type\n * @returns True if images or videos should show preview\n */\n isVisualType(type: AttachmentType): boolean {\n return type === 'image' || type === 'video';\n }\n\n /**\n * Calculates the stroke-dasharray for the progress circle.\n *\n * @param progress - Progress percentage (0-100)\n * @returns The dasharray value as a string\n */\n getProgressDashArray(progress: number): string {\n return `${this.CIRCLE_CIRCUMFERENCE} ${this.CIRCLE_CIRCUMFERENCE}`;\n }\n\n /**\n * Calculates the stroke-dashoffset for the progress circle.\n * This creates the animated progress effect.\n *\n * @param progress - Progress percentage (0-100)\n * @returns The dashoffset value\n */\n getProgressDashOffset(progress: number): number {\n const clampedProgress = Math.max(0, Math.min(100, progress));\n return this.CIRCLE_CIRCUMFERENCE - (clampedProgress / 100) * this.CIRCLE_CIRCUMFERENCE;\n }\n\n /**\n * Truncates long file names with ellipsis in the middle.\n *\n * @param fileName - The original file name\n * @returns Truncated file name if too long\n */\n truncateFileName(fileName: string): string {\n if (fileName.length <= this.MAX_FILE_NAME_LENGTH) {\n return fileName;\n }\n\n const extension = fileName.lastIndexOf('.') > 0\n ? fileName.substring(fileName.lastIndexOf('.'))\n : '';\n const name = fileName.substring(0, fileName.length - extension.length);\n\n const availableLength = this.MAX_FILE_NAME_LENGTH - extension.length - 3; // 3 for '...'\n if (availableLength <= 0) {\n return fileName.substring(0, this.MAX_FILE_NAME_LENGTH - 3) + '...';\n }\n\n const start = Math.ceil(availableLength / 2);\n const end = Math.floor(availableLength / 2);\n\n return name.substring(0, start) + '...' + name.substring(name.length - end) + extension;\n }\n\n /**\n * Gets the ARIA label for the remove button.\n *\n * @param attachment - The attachment being removed\n * @returns Accessible label for the remove action\n */\n getRemoveAriaLabel(attachment: PendingAttachment): string {\n const i18n = this.i18n();\n const template = i18n.ariaRemoveAttachment || 'Remove {name}';\n return template.replace('{name}', attachment.file.name);\n }\n\n /**\n * Handles remove button click.\n * Emits the attachment ID via the remove output.\n *\n * @param attachmentId - The ID of the attachment to remove\n */\n onRemoveClick(attachmentId: string): void {\n this.remove.emit(attachmentId);\n }\n\n /**\n * Handles retry button click.\n * Emits the attachment ID via the retry output.\n *\n * @param attachmentId - The ID of the attachment to retry\n */\n onRetryClick(attachmentId: string): void {\n this.retry.emit(attachmentId);\n }\n}\n","/**\n * @fileoverview Chat attachment container component for ngx-chat library.\n * Displays completed attachments within messages with type-specific previews.\n * @module ngx-chat/components/chat-attachment\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n computed,\n inject,\n} from '@angular/core';\n\nimport { MessageAttachment, AttachmentClickEvent } from '../../models/attachment.model';\nimport { ChatConfigService } from '../../services/chat-config.service';\n\n/**\n * Chat attachment container component for displaying message attachments.\n *\n * This component displays a grid of completed attachments with:\n * - Type-specific previews (image, video, audio, file)\n * - Click handling for lightbox/preview interaction\n * - Accessible ARIA labels\n * - Responsive grid layout\n *\n * The component is purely presentational - the parent handles click events\n * for actions like opening lightbox or downloading files.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-attachment\n * [attachments]=\"message.attachments\"\n * [messageId]=\"message.id\"\n * (click)=\"onAttachmentClick($event)\"\n * />\n * ```\n *\n * @example In a message bubble\n * ```html\n * @if (message.attachments?.length) {\n * <ngx-chat-attachment\n * [attachments]=\"message.attachments\"\n * [messageId]=\"message.id\"\n * (click)=\"handleAttachmentClick($event)\"\n * />\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat-attachment',\n standalone: true,\n imports: [],\n template: `\n @if (attachments().length > 0) {\n <div\n class=\"ngx-attachment__grid\"\n [class.ngx-attachment__grid--single]=\"attachments().length === 1\"\n [class.ngx-attachment__grid--double]=\"attachments().length === 2\"\n [class.ngx-attachment__grid--multi]=\"attachments().length > 2\"\n role=\"list\"\n [attr.aria-label]=\"getGridAriaLabel()\"\n >\n @for (attachment of attachments(); track attachment.id) {\n <div\n class=\"ngx-attachment__item\"\n [class.ngx-attachment__item--image]=\"attachment.type === 'image'\"\n [class.ngx-attachment__item--video]=\"attachment.type === 'video'\"\n [class.ngx-attachment__item--audio]=\"attachment.type === 'audio'\"\n [class.ngx-attachment__item--file]=\"attachment.type === 'file'\"\n role=\"listitem\"\n >\n @switch (attachment.type) {\n @case ('image') {\n <button\n type=\"button\"\n class=\"ngx-attachment__image-button\"\n [attr.aria-label]=\"getImageAriaLabel(attachment)\"\n (click)=\"onAttachmentClick(attachment, 'preview')\"\n >\n <img\n [src]=\"attachment.thumbnail || attachment.url\"\n [alt]=\"attachment.name\"\n class=\"ngx-attachment__image\"\n loading=\"lazy\"\n (error)=\"onImageError($event)\"\n />\n @if (attachment.dimensions) {\n <span class=\"ngx-attachment__dimensions\">\n {{ attachment.dimensions.width }} × {{ attachment.dimensions.height }}\n </span>\n }\n </button>\n }\n @case ('video') {\n <button\n type=\"button\"\n class=\"ngx-attachment__video-button\"\n [attr.aria-label]=\"getVideoAriaLabel(attachment)\"\n (click)=\"onAttachmentClick(attachment, 'preview')\"\n >\n @if (attachment.thumbnail) {\n <img\n [src]=\"attachment.thumbnail\"\n [alt]=\"attachment.name\"\n class=\"ngx-attachment__video-thumbnail\"\n loading=\"lazy\"\n />\n } @else {\n <div class=\"ngx-attachment__video-placeholder\">\n <svg\n class=\"ngx-attachment__video-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" />\n <polygon points=\"10 8 16 12 10 16 10 8\" fill=\"currentColor\" />\n </svg>\n </div>\n }\n <div class=\"ngx-attachment__play-overlay\">\n <svg\n class=\"ngx-attachment__play-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </div>\n @if (attachment.duration) {\n <span class=\"ngx-attachment__duration\">\n {{ formatDuration(attachment.duration) }}\n </span>\n }\n </button>\n }\n @case ('audio') {\n <div class=\"ngx-attachment__audio\">\n <button\n type=\"button\"\n class=\"ngx-attachment__audio-play\"\n [attr.aria-label]=\"getAudioAriaLabel(attachment)\"\n (click)=\"onAttachmentClick(attachment, 'preview')\"\n >\n <svg\n class=\"ngx-attachment__audio-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <polygon points=\"5 3 19 12 5 21 5 3\" />\n </svg>\n </button>\n <div class=\"ngx-attachment__audio-info\">\n <span class=\"ngx-attachment__audio-name\" [title]=\"attachment.name\">\n {{ truncateFileName(attachment.name) }}\n </span>\n <span class=\"ngx-attachment__audio-meta\">\n @if (attachment.duration) {\n <span class=\"ngx-attachment__audio-duration\">\n {{ formatDuration(attachment.duration) }}\n </span>\n }\n <span class=\"ngx-attachment__audio-size\">\n {{ formatFileSize(attachment.size) }}\n </span>\n </span>\n </div>\n </div>\n }\n @default {\n <!-- Generic file -->\n <button\n type=\"button\"\n class=\"ngx-attachment__file\"\n [attr.aria-label]=\"getFileAriaLabel(attachment)\"\n (click)=\"onAttachmentClick(attachment, 'download')\"\n >\n <div class=\"ngx-attachment__file-icon-wrapper\">\n <svg\n class=\"ngx-attachment__file-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n <span class=\"ngx-attachment__file-ext\">\n {{ getFileExtension(attachment.name) }}\n </span>\n </div>\n <div class=\"ngx-attachment__file-info\">\n <span class=\"ngx-attachment__file-name\" [title]=\"attachment.name\">\n {{ truncateFileName(attachment.name) }}\n </span>\n <span class=\"ngx-attachment__file-size\">\n {{ formatFileSize(attachment.size) }}\n </span>\n </div>\n <svg\n class=\"ngx-attachment__download-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n }\n }\n </div>\n }\n </div>\n }\n `,\n styleUrls: ['./chat-attachment.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-attachment',\n '[class.ngx-attachment--empty]': 'attachments().length === 0',\n },\n})\nexport class ChatAttachmentComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly configService = inject(ChatConfigService);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * Array of completed message attachments to display.\n * @default []\n */\n readonly attachments = input<readonly MessageAttachment[]>([]);\n\n /**\n * ID of the message containing these attachments.\n * Required for building the click event.\n */\n readonly messageId = input.required<string>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits when an attachment is clicked.\n * Contains the message ID, attachment data, and interaction type.\n */\n readonly attachmentClick = output<AttachmentClickEvent>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * I18n strings from configuration.\n */\n readonly i18n = computed(() => this.configService.getI18n());\n\n // ===========================================================================\n // Constants\n // ===========================================================================\n\n /**\n * Maximum file name length before truncation.\n */\n private readonly MAX_FILE_NAME_LENGTH = 25;\n\n // ===========================================================================\n // Public Methods\n // ===========================================================================\n\n /**\n * Handles attachment click.\n * Emits an AttachmentClickEvent with the appropriate action type.\n *\n * @param attachment - The clicked attachment\n * @param action - The type of interaction\n */\n onAttachmentClick(\n attachment: MessageAttachment,\n action: 'click' | 'download' | 'preview'\n ): void {\n this.attachmentClick.emit({\n messageId: this.messageId(),\n attachment,\n action,\n });\n }\n\n /**\n * Handles image load error by setting a fallback.\n *\n * @param event - The error event from the image element\n */\n onImageError(event: Event): void {\n const img = event.target as HTMLImageElement;\n // Prevent infinite loop if fallback also fails\n if (!img.dataset['fallback']) {\n img.dataset['fallback'] = 'true';\n img.src = 'data:image/svg+xml,' + encodeURIComponent(`\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"/>\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/>\n <polyline points=\"21 15 16 10 5 21\"/>\n </svg>\n `);\n }\n }\n\n /**\n * Formats file size in human-readable format.\n *\n * @param bytes - File size in bytes\n * @returns Formatted size string (e.g., \"1.5 MB\")\n */\n formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n\n const units = ['B', 'KB', 'MB', 'GB'];\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n const size = bytes / Math.pow(k, i);\n\n return `${size.toFixed(i > 0 ? 1 : 0)} ${units[i]}`;\n }\n\n /**\n * Formats duration in MM:SS or HH:MM:SS format.\n *\n * @param seconds - Duration in seconds\n * @returns Formatted duration string\n */\n formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n\n if (h > 0) {\n return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n }\n return `${m}:${s.toString().padStart(2, '0')}`;\n }\n\n /**\n * Truncates long file names with ellipsis in the middle.\n *\n * @param fileName - The original file name\n * @returns Truncated file name if too long\n */\n truncateFileName(fileName: string): string {\n if (fileName.length <= this.MAX_FILE_NAME_LENGTH) {\n return fileName;\n }\n\n const extension = fileName.lastIndexOf('.') > 0\n ? fileName.substring(fileName.lastIndexOf('.'))\n : '';\n const name = fileName.substring(0, fileName.length - extension.length);\n\n const availableLength = this.MAX_FILE_NAME_LENGTH - extension.length - 3; // 3 for '...'\n if (availableLength <= 0) {\n return fileName.substring(0, this.MAX_FILE_NAME_LENGTH - 3) + '...';\n }\n\n const start = Math.ceil(availableLength / 2);\n const end = Math.floor(availableLength / 2);\n\n return name.substring(0, start) + '...' + name.substring(name.length - end) + extension;\n }\n\n /**\n * Extracts the file extension from a file name.\n *\n * @param fileName - The file name\n * @returns Upper-cased extension without the dot\n */\n getFileExtension(fileName: string): string {\n const lastDot = fileName.lastIndexOf('.');\n if (lastDot <= 0) return '';\n return fileName.substring(lastDot + 1).toUpperCase();\n }\n\n /**\n * Gets the ARIA label for the attachment grid.\n *\n * @returns Accessible label for the grid\n */\n getGridAriaLabel(): string {\n const i18n = this.i18n();\n const count = this.attachments().length;\n if (count === 1) {\n return i18n.attachment || 'Attachment';\n }\n return (i18n.attachments || '{count} attachments').replace('{count}', count.toString());\n }\n\n /**\n * Gets the ARIA label for an image attachment.\n *\n * @param attachment - The image attachment\n * @returns Accessible label\n */\n getImageAriaLabel(attachment: MessageAttachment): string {\n let label = `View image: ${attachment.name}`;\n if (attachment.dimensions) {\n label += ` (${attachment.dimensions.width} × ${attachment.dimensions.height})`;\n }\n return label;\n }\n\n /**\n * Gets the ARIA label for a video attachment.\n *\n * @param attachment - The video attachment\n * @returns Accessible label\n */\n getVideoAriaLabel(attachment: MessageAttachment): string {\n let label = `Play video: ${attachment.name}`;\n if (attachment.duration) {\n label += ` (${this.formatDuration(attachment.duration)})`;\n }\n return label;\n }\n\n /**\n * Gets the ARIA label for an audio attachment.\n *\n * @param attachment - The audio attachment\n * @returns Accessible label\n */\n getAudioAriaLabel(attachment: MessageAttachment): string {\n let label = `Play audio: ${attachment.name}`;\n if (attachment.duration) {\n label += ` (${this.formatDuration(attachment.duration)})`;\n }\n return label;\n }\n\n /**\n * Gets the ARIA label for a file attachment.\n *\n * @param attachment - The file attachment\n * @returns Accessible label\n */\n getFileAriaLabel(attachment: MessageAttachment): string {\n return `Download file: ${attachment.name} (${this.formatFileSize(attachment.size)})`;\n }\n}\n","/**\n * @fileoverview Image preview component for ngx-chat library.\n * Displays image attachments with loading skeleton, dimensions badge, and click handling.\n * @module ngx-chat/components/chat-attachment\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n} from '@angular/core';\n\nimport { MessageAttachment, AttachmentClickEvent } from '../../models/attachment.model';\n\n/**\n * Image preview component for displaying image attachments.\n *\n * This component displays an image attachment with:\n * - Loading skeleton while image loads\n * - Thumbnail preference over main URL\n * - Dimensions badge when available\n * - Click handling for lightbox/preview\n * - Error handling with fallback image\n * - Full accessibility support\n *\n * The component is purely presentational - the parent handles click events\n * for actions like opening a lightbox.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-image-preview\n * [attachment]=\"imageAttachment\"\n * [messageId]=\"message.id\"\n * (click)=\"onImageClick($event)\"\n * />\n * ```\n *\n * @example In ChatAttachmentComponent\n * ```html\n * @if (attachment.type === 'image') {\n * <ngx-chat-image-preview\n * [attachment]=\"attachment\"\n * [messageId]=\"messageId()\"\n * (click)=\"onAttachmentClick($event)\"\n * />\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat-image-preview',\n standalone: true,\n imports: [],\n template: `\n <button\n type=\"button\"\n class=\"ngx-image-preview__button\"\n [attr.aria-label]=\"ariaLabel()\"\n [disabled]=\"hasError()\"\n (click)=\"onClick()\"\n >\n <!-- Loading skeleton -->\n @if (isLoading()) {\n <div\n class=\"ngx-image-preview__skeleton\"\n role=\"progressbar\"\n aria-label=\"Loading image\"\n >\n <div class=\"ngx-image-preview__skeleton-shimmer\"></div>\n </div>\n }\n\n <!-- Image -->\n <img\n [src]=\"imageSrc()\"\n [alt]=\"attachment().name\"\n class=\"ngx-image-preview__image\"\n [class.ngx-image-preview__image--loading]=\"isLoading()\"\n [class.ngx-image-preview__image--error]=\"hasError()\"\n loading=\"lazy\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError($event)\"\n />\n\n <!-- Dimensions badge -->\n @if (showDimensions()) {\n <span class=\"ngx-image-preview__dimensions\">\n {{ attachment().dimensions!.width }} × {{ attachment().dimensions!.height }}\n </span>\n }\n\n <!-- Error overlay -->\n @if (hasError()) {\n <div class=\"ngx-image-preview__error\" aria-hidden=\"true\">\n <svg\n class=\"ngx-image-preview__error-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />\n <circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\" />\n <polyline points=\"21 15 16 10 5 21\" />\n <line x1=\"2\" y1=\"2\" x2=\"22\" y2=\"22\" />\n </svg>\n </div>\n }\n </button>\n `,\n styles: [`\n :host {\n display: block;\n container-type: inline-size;\n }\n\n .ngx-image-preview__button {\n display: block;\n position: relative;\n width: 100%;\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: var(--ngx-chat-attachment-radius, 8px);\n overflow: hidden;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n\n &:hover:not(:disabled) {\n transform: scale(1.02);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n\n &:focus-visible {\n outline: 2px solid var(--ngx-chat-focus-color, #2563eb);\n outline-offset: 2px;\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n }\n\n .ngx-image-preview__skeleton {\n position: absolute;\n inset: 0;\n background: var(--ngx-chat-skeleton-bg, #e5e7eb);\n z-index: 1;\n }\n\n .ngx-image-preview__skeleton-shimmer {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n var(--ngx-chat-skeleton-shimmer, rgba(255, 255, 255, 0.5)) 50%,\n transparent 100%\n );\n animation: shimmer 1.5s infinite;\n }\n\n @keyframes shimmer {\n 0% {\n transform: translateX(-100%);\n }\n 100% {\n transform: translateX(100%);\n }\n }\n\n .ngx-image-preview__image {\n display: block;\n width: 100%;\n height: auto;\n max-height: var(--ngx-chat-image-max-height, 300px);\n object-fit: cover;\n transition: opacity 0.2s ease;\n }\n\n .ngx-image-preview__image--loading {\n opacity: 0;\n }\n\n .ngx-image-preview__image--error {\n opacity: 0.3;\n filter: grayscale(100%);\n }\n\n .ngx-image-preview__dimensions {\n position: absolute;\n bottom: 8px;\n right: 8px;\n padding: 2px 6px;\n font-size: 11px;\n font-weight: 500;\n color: var(--ngx-chat-badge-text, #fff);\n background: var(--ngx-chat-badge-bg, rgba(0, 0, 0, 0.6));\n border-radius: 4px;\n backdrop-filter: blur(4px);\n }\n\n .ngx-image-preview__error {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ngx-chat-error-overlay-bg, rgba(0, 0, 0, 0.1));\n }\n\n .ngx-image-preview__error-icon {\n width: 48px;\n height: 48px;\n color: var(--ngx-chat-error-icon-color, #dc2626);\n opacity: 0.8;\n }\n\n /* Dark theme */\n :host-context([data-theme=\"dark\"]) {\n .ngx-image-preview__skeleton {\n background: var(--ngx-chat-skeleton-bg, #374151);\n }\n\n .ngx-image-preview__skeleton-shimmer {\n background: linear-gradient(\n 90deg,\n transparent 0%,\n rgba(255, 255, 255, 0.1) 50%,\n transparent 100%\n );\n }\n }\n\n /* Reduced motion */\n @media (prefers-reduced-motion: reduce) {\n .ngx-image-preview__button {\n transition: none;\n }\n\n .ngx-image-preview__skeleton-shimmer {\n animation: none;\n }\n\n .ngx-image-preview__image {\n transition: none;\n }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-image-preview',\n },\n})\nexport class ImagePreviewComponent {\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The image attachment to display.\n */\n readonly attachment = input.required<MessageAttachment>();\n\n /**\n * ID of the message containing this attachment.\n * Required for building the click event.\n */\n readonly messageId = input.required<string>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits when the image is clicked.\n * Contains the message ID, attachment data, and action type.\n */\n readonly imageClick = output<AttachmentClickEvent>();\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /**\n * Whether the image is currently loading.\n */\n readonly isLoading = signal(true);\n\n /**\n * Whether the image failed to load.\n */\n readonly hasError = signal(false);\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * The image source URL.\n * Prefers thumbnail if available, falls back to main URL.\n */\n readonly imageSrc = computed(() => {\n const att = this.attachment();\n return att.thumbnail || att.url;\n });\n\n /**\n * Whether to show the dimensions badge.\n * Only shown when dimensions are available and image is loaded.\n */\n readonly showDimensions = computed(() => {\n const att = this.attachment();\n return !this.isLoading() && !this.hasError() && !!att.dimensions;\n });\n\n /**\n * ARIA label for the image button.\n */\n readonly ariaLabel = computed(() => {\n const att = this.attachment();\n let label = `View image: ${att.name}`;\n\n if (att.dimensions) {\n label += ` (${att.dimensions.width} × ${att.dimensions.height} pixels)`;\n }\n\n if (this.hasError()) {\n label += ' - Failed to load';\n }\n\n return label;\n });\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles successful image load.\n */\n onImageLoad(): void {\n this.isLoading.set(false);\n }\n\n /**\n * Handles image load error.\n * Sets error state and attempts fallback.\n */\n onImageError(event: Event): void {\n const img = event.target as HTMLImageElement;\n const att = this.attachment();\n\n // If we were showing thumbnail and it failed, try main URL\n if (att.thumbnail && img.src === att.thumbnail) {\n img.src = att.url;\n return;\n }\n\n // If main URL also failed (or no thumbnail), show error state\n this.isLoading.set(false);\n this.hasError.set(true);\n\n // Set fallback SVG\n if (!img.dataset['fallback']) {\n img.dataset['fallback'] = 'true';\n img.src = 'data:image/svg+xml,' + encodeURIComponent(`\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill=\"#9ca3af\">\n <rect width=\"100\" height=\"100\" fill=\"#f3f4f6\"/>\n <path d=\"M35 35h30v30H35z\" fill=\"#e5e7eb\"/>\n </svg>\n `);\n }\n }\n\n /**\n * Handles button click.\n * Emits click event if not in error state.\n */\n onClick(): void {\n if (this.hasError()) {\n return;\n }\n\n this.imageClick.emit({\n messageId: this.messageId(),\n attachment: this.attachment(),\n action: 'preview',\n });\n }\n}\n","/**\n * @fileoverview File preview component for ngx-chat library.\n * Displays generic file attachments with type-based icons, size, and download functionality.\n * @module ngx-chat/components/chat-attachment\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n computed,\n} from '@angular/core';\n\nimport { MessageAttachment, AttachmentClickEvent } from '../../models/attachment.model';\n\n/**\n * File type category for icon mapping.\n */\ntype FileCategory =\n | 'pdf'\n | 'document'\n | 'spreadsheet'\n | 'presentation'\n | 'archive'\n | 'code'\n | 'text'\n | 'generic';\n\n/**\n * File preview component for displaying generic file attachments.\n *\n * This component displays a file attachment with:\n * - File type icon based on MIME type\n * - File name with ellipsis truncation\n * - Formatted file size (KB, MB, GB)\n * - File extension badge\n * - Download button with click handling\n * - Full accessibility support\n *\n * The component is purely presentational - the parent handles click events\n * for actions like downloading the file.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-file-preview\n * [attachment]=\"fileAttachment\"\n * [messageId]=\"message.id\"\n * (fileClick)=\"onFileClick($event)\"\n * />\n * ```\n *\n * @example In ChatAttachmentComponent\n * ```html\n * @if (attachment.type === 'file') {\n * <ngx-chat-file-preview\n * [attachment]=\"attachment\"\n * [messageId]=\"messageId()\"\n * (fileClick)=\"onAttachmentClick($event)\"\n * />\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat-file-preview',\n standalone: true,\n imports: [],\n template: `\n <button\n type=\"button\"\n class=\"ngx-file-preview__button\"\n [attr.aria-label]=\"ariaLabel()\"\n (click)=\"onClick()\"\n >\n <!-- File icon -->\n <div class=\"ngx-file-preview__icon-wrapper\">\n @switch (fileCategory()) {\n @case ('pdf') {\n <svg\n class=\"ngx-file-preview__icon ngx-file-preview__icon--pdf\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <path d=\"M10 12h4\" />\n <path d=\"M10 16h4\" />\n <path d=\"M10 20h4\" />\n </svg>\n }\n @case ('document') {\n <svg\n class=\"ngx-file-preview__icon ngx-file-preview__icon--doc\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n <polyline points=\"10 9 9 9 8 9\" />\n </svg>\n }\n @case ('spreadsheet') {\n <svg\n class=\"ngx-file-preview__icon ngx-file-preview__icon--xls\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <rect x=\"8\" y=\"12\" width=\"8\" height=\"8\" />\n <line x1=\"12\" y1=\"12\" x2=\"12\" y2=\"20\" />\n <line x1=\"8\" y1=\"16\" x2=\"16\" y2=\"16\" />\n </svg>\n }\n @case ('presentation') {\n <svg\n class=\"ngx-file-preview__icon ngx-file-preview__icon--ppt\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <rect x=\"8\" y=\"12\" width=\"8\" height=\"6\" rx=\"1\" />\n </svg>\n }\n @case ('archive') {\n <svg\n class=\"ngx-file-preview__icon ngx-file-preview__icon--zip\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <rect x=\"10\" y=\"12\" width=\"4\" height=\"2\" />\n <rect x=\"10\" y=\"16\" width=\"4\" height=\"2\" />\n <line x1=\"12\" y1=\"10\" x2=\"12\" y2=\"12\" />\n </svg>\n }\n @case ('code') {\n <svg\n class=\"ngx-file-preview__icon ngx-file-preview__icon--code\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <polyline points=\"10 13 8 15 10 17\" />\n <polyline points=\"14 13 16 15 14 17\" />\n </svg>\n }\n @case ('text') {\n <svg\n class=\"ngx-file-preview__icon ngx-file-preview__icon--txt\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n </svg>\n }\n @default {\n <svg\n class=\"ngx-file-preview__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n }\n }\n <!-- Extension badge -->\n @if (fileExtension()) {\n <span class=\"ngx-file-preview__extension\">\n {{ fileExtension() }}\n </span>\n }\n </div>\n\n <!-- File info -->\n <div class=\"ngx-file-preview__info\">\n <span class=\"ngx-file-preview__name\" [title]=\"attachment().name\">\n {{ truncatedName() }}\n </span>\n <span class=\"ngx-file-preview__size\">\n {{ formattedSize() }}\n </span>\n </div>\n\n <!-- Download icon -->\n <svg\n class=\"ngx-file-preview__download\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"7 10 12 15 17 10\" />\n <line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\" />\n </svg>\n </button>\n `,\n styles: [`\n :host {\n display: block;\n container-type: inline-size;\n }\n\n .ngx-file-preview__button {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n padding: 12px;\n border: 1px solid var(--ngx-chat-border-color, #e5e7eb);\n border-radius: var(--ngx-chat-attachment-radius, 8px);\n background: var(--ngx-chat-file-bg, #f9fafb);\n cursor: pointer;\n text-align: left;\n transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;\n\n &:hover {\n background: var(--ngx-chat-file-hover-bg, #f3f4f6);\n border-color: var(--ngx-chat-border-hover-color, #d1d5db);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);\n }\n\n &:focus-visible {\n outline: 2px solid var(--ngx-chat-focus-color, #2563eb);\n outline-offset: 2px;\n }\n }\n\n .ngx-file-preview__icon-wrapper {\n position: relative;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--ngx-chat-file-icon-bg, #e5e7eb);\n border-radius: 8px;\n }\n\n .ngx-file-preview__icon {\n width: 24px;\n height: 24px;\n color: var(--ngx-chat-file-icon-color, #6b7280);\n }\n\n .ngx-file-preview__icon--pdf {\n color: var(--ngx-chat-file-pdf-color, #dc2626);\n }\n\n .ngx-file-preview__icon--doc {\n color: var(--ngx-chat-file-doc-color, #2563eb);\n }\n\n .ngx-file-preview__icon--xls {\n color: var(--ngx-chat-file-xls-color, #16a34a);\n }\n\n .ngx-file-preview__icon--ppt {\n color: var(--ngx-chat-file-ppt-color, #ea580c);\n }\n\n .ngx-file-preview__icon--zip {\n color: var(--ngx-chat-file-zip-color, #7c3aed);\n }\n\n .ngx-file-preview__icon--code {\n color: var(--ngx-chat-file-code-color, #0891b2);\n }\n\n .ngx-file-preview__icon--txt {\n color: var(--ngx-chat-file-txt-color, #6b7280);\n }\n\n .ngx-file-preview__extension {\n position: absolute;\n bottom: -4px;\n right: -4px;\n padding: 1px 4px;\n font-size: 9px;\n font-weight: 600;\n text-transform: uppercase;\n color: var(--ngx-chat-file-ext-text, #fff);\n background: var(--ngx-chat-file-ext-bg, #374151);\n border-radius: 3px;\n line-height: 1.2;\n }\n\n .ngx-file-preview__info {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .ngx-file-preview__name {\n font-size: 14px;\n font-weight: 500;\n color: var(--ngx-chat-file-name-color, #111827);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .ngx-file-preview__size {\n font-size: 12px;\n color: var(--ngx-chat-file-size-color, #6b7280);\n }\n\n .ngx-file-preview__download {\n flex-shrink: 0;\n width: 20px;\n height: 20px;\n color: var(--ngx-chat-file-download-color, #6b7280);\n transition: color 0.15s ease;\n }\n\n .ngx-file-preview__button:hover .ngx-file-preview__download {\n color: var(--ngx-chat-file-download-hover-color, #2563eb);\n }\n\n /* Dark theme */\n :host-context([data-theme=\"dark\"]) {\n .ngx-file-preview__button {\n background: var(--ngx-chat-file-bg, #1f2937);\n border-color: var(--ngx-chat-border-color, #374151);\n\n &:hover {\n background: var(--ngx-chat-file-hover-bg, #374151);\n border-color: var(--ngx-chat-border-hover-color, #4b5563);\n }\n }\n\n .ngx-file-preview__icon-wrapper {\n background: var(--ngx-chat-file-icon-bg, #374151);\n }\n\n .ngx-file-preview__icon {\n color: var(--ngx-chat-file-icon-color, #9ca3af);\n }\n\n .ngx-file-preview__extension {\n background: var(--ngx-chat-file-ext-bg, #4b5563);\n }\n\n .ngx-file-preview__name {\n color: var(--ngx-chat-file-name-color, #f9fafb);\n }\n\n .ngx-file-preview__size {\n color: var(--ngx-chat-file-size-color, #9ca3af);\n }\n\n .ngx-file-preview__download {\n color: var(--ngx-chat-file-download-color, #9ca3af);\n }\n }\n\n /* Reduced motion */\n @media (prefers-reduced-motion: reduce) {\n .ngx-file-preview__button {\n transition: none;\n }\n\n .ngx-file-preview__download {\n transition: none;\n }\n }\n\n /* Container query for compact layout */\n @container (max-width: 200px) {\n .ngx-file-preview__button {\n padding: 8px;\n gap: 8px;\n }\n\n .ngx-file-preview__icon-wrapper {\n width: 32px;\n height: 32px;\n }\n\n .ngx-file-preview__icon {\n width: 18px;\n height: 18px;\n }\n\n .ngx-file-preview__extension {\n font-size: 8px;\n }\n\n .ngx-file-preview__name {\n font-size: 13px;\n }\n\n .ngx-file-preview__size {\n font-size: 11px;\n }\n\n .ngx-file-preview__download {\n width: 16px;\n height: 16px;\n }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-file-preview',\n },\n})\nexport class FilePreviewComponent {\n // ===========================================================================\n // Constants\n // ===========================================================================\n\n /**\n * Maximum file name length before truncation.\n */\n private readonly MAX_FILE_NAME_LENGTH = 30;\n\n /**\n * MIME type to file category mapping.\n */\n private readonly MIME_CATEGORY_MAP: Record<string, FileCategory> = {\n // PDF\n 'application/pdf': 'pdf',\n // Documents\n 'application/msword': 'document',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'document',\n 'application/rtf': 'document',\n 'application/vnd.oasis.opendocument.text': 'document',\n // Spreadsheets\n 'application/vnd.ms-excel': 'spreadsheet',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'spreadsheet',\n 'text/csv': 'spreadsheet',\n 'application/vnd.oasis.opendocument.spreadsheet': 'spreadsheet',\n // Presentations\n 'application/vnd.ms-powerpoint': 'presentation',\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'presentation',\n 'application/vnd.oasis.opendocument.presentation': 'presentation',\n // Archives\n 'application/zip': 'archive',\n 'application/x-zip-compressed': 'archive',\n 'application/x-rar-compressed': 'archive',\n 'application/vnd.rar': 'archive',\n 'application/x-7z-compressed': 'archive',\n 'application/gzip': 'archive',\n 'application/x-tar': 'archive',\n 'application/x-bzip2': 'archive',\n // Code\n 'application/javascript': 'code',\n 'application/json': 'code',\n 'application/xml': 'code',\n 'text/html': 'code',\n 'text/css': 'code',\n 'text/javascript': 'code',\n 'text/xml': 'code',\n 'application/x-sh': 'code',\n 'application/x-python-code': 'code',\n };\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The file attachment to display.\n */\n readonly attachment = input.required<MessageAttachment>();\n\n /**\n * ID of the message containing this attachment.\n * Required for building the click event.\n */\n readonly messageId = input.required<string>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits when the file is clicked (for download).\n * Contains the message ID, attachment data, and action type.\n */\n readonly fileClick = output<AttachmentClickEvent>();\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * Determines the file category based on MIME type.\n */\n readonly fileCategory = computed((): FileCategory => {\n const mimeType = this.attachment().mimeType;\n\n // Check exact match first\n if (this.MIME_CATEGORY_MAP[mimeType]) {\n return this.MIME_CATEGORY_MAP[mimeType];\n }\n\n // Check text/* types\n if (mimeType.startsWith('text/')) {\n return 'text';\n }\n\n return 'generic';\n });\n\n /**\n * Extracts and formats the file extension.\n */\n readonly fileExtension = computed((): string => {\n const name = this.attachment().name;\n const lastDot = name.lastIndexOf('.');\n if (lastDot <= 0 || lastDot === name.length - 1) {\n return '';\n }\n const ext = name.substring(lastDot + 1);\n // Limit to 4 characters\n return ext.length <= 4 ? ext.toUpperCase() : ext.substring(0, 4).toUpperCase();\n });\n\n /**\n * Truncates the file name if too long.\n * Uses middle ellipsis to preserve extension visibility.\n */\n readonly truncatedName = computed((): string => {\n const name = this.attachment().name;\n if (name.length <= this.MAX_FILE_NAME_LENGTH) {\n return name;\n }\n\n const extension = name.lastIndexOf('.') > 0\n ? name.substring(name.lastIndexOf('.'))\n : '';\n const baseName = name.substring(0, name.length - extension.length);\n\n const availableLength = this.MAX_FILE_NAME_LENGTH - extension.length - 3; // 3 for '...'\n if (availableLength <= 0) {\n return name.substring(0, this.MAX_FILE_NAME_LENGTH - 3) + '...';\n }\n\n const start = Math.ceil(availableLength / 2);\n const end = Math.floor(availableLength / 2);\n\n return baseName.substring(0, start) + '...' + baseName.substring(baseName.length - end) + extension;\n });\n\n /**\n * Formats the file size in human-readable format.\n */\n readonly formattedSize = computed((): string => {\n const bytes = this.attachment().size;\n if (bytes === 0) return '0 B';\n\n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n const size = bytes / Math.pow(k, i);\n\n return `${size.toFixed(i > 0 ? 1 : 0)} ${units[Math.min(i, units.length - 1)]}`;\n });\n\n /**\n * ARIA label for the file button.\n */\n readonly ariaLabel = computed((): string => {\n const att = this.attachment();\n return `Download file: ${att.name} (${this.formattedSize()})`;\n });\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles button click.\n * Emits click event with download action.\n */\n onClick(): void {\n this.fileClick.emit({\n messageId: this.messageId(),\n attachment: this.attachment(),\n action: 'download',\n });\n }\n}\n","/**\n * @fileoverview Video preview component for ngx-chat library.\n * Displays video attachments with thumbnail, play button overlay, and duration badge.\n * @module ngx-chat/components/chat-attachment\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n} from '@angular/core';\n\nimport { MessageAttachment, AttachmentClickEvent } from '../../models/attachment.model';\n\n/**\n * Video preview component for displaying video attachments.\n *\n * This component displays a video attachment with:\n * - Thumbnail preview (or video poster frame)\n * - Loading skeleton while thumbnail loads\n * - Play button overlay (centered)\n * - Duration badge (bottom-right corner)\n * - Error handling with fallback state\n * - Full accessibility support\n *\n * The component is purely presentational - the parent handles click events\n * for actions like opening a video lightbox or player.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-video-preview\n * [attachment]=\"videoAttachment\"\n * [messageId]=\"message.id\"\n * (videoClick)=\"onVideoClick($event)\"\n * />\n * ```\n *\n * @example In ChatAttachmentComponent\n * ```html\n * @if (attachment.type === 'video') {\n * <ngx-chat-video-preview\n * [attachment]=\"attachment\"\n * [messageId]=\"messageId()\"\n * (videoClick)=\"onAttachmentClick($event)\"\n * />\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat-video-preview',\n standalone: true,\n imports: [],\n template: `\n <button\n type=\"button\"\n class=\"ngx-video-preview__button\"\n [attr.aria-label]=\"ariaLabel()\"\n [disabled]=\"hasError()\"\n (click)=\"onClick()\"\n >\n <!-- Loading skeleton -->\n @if (isLoading()) {\n <div\n class=\"ngx-video-preview__skeleton\"\n role=\"progressbar\"\n aria-label=\"Loading video thumbnail\"\n >\n <div class=\"ngx-video-preview__skeleton-shimmer\"></div>\n </div>\n }\n\n <!-- Thumbnail image -->\n <img\n [src]=\"thumbnailSrc()\"\n [alt]=\"attachment().name\"\n class=\"ngx-video-preview__thumbnail\"\n [class.ngx-video-preview__thumbnail--loading]=\"isLoading()\"\n [class.ngx-video-preview__thumbnail--error]=\"hasError()\"\n loading=\"lazy\"\n (load)=\"onThumbnailLoad()\"\n (error)=\"onThumbnailError($event)\"\n />\n\n <!-- Play button overlay -->\n @if (!hasError()) {\n <div class=\"ngx-video-preview__play-overlay\" aria-hidden=\"true\">\n <div class=\"ngx-video-preview__play-button\">\n <svg\n class=\"ngx-video-preview__play-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </div>\n </div>\n }\n\n <!-- Duration badge -->\n @if (showDuration()) {\n <span class=\"ngx-video-preview__duration\">\n {{ formattedDuration() }}\n </span>\n }\n\n <!-- Error overlay -->\n @if (hasError()) {\n <div class=\"ngx-video-preview__error\" aria-hidden=\"true\">\n <svg\n class=\"ngx-video-preview__error-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" />\n <line x1=\"2\" y1=\"10\" x2=\"22\" y2=\"10\" />\n <line x1=\"2\" y1=\"2\" x2=\"22\" y2=\"22\" />\n </svg>\n </div>\n }\n </button>\n `,\n styles: [`\n :host {\n display: block;\n container-type: inline-size;\n }\n\n .ngx-video-preview__button {\n display: block;\n position: relative;\n width: 100%;\n padding: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: var(--ngx-chat-attachment-radius, 8px);\n overflow: hidden;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n\n &:hover:not(:disabled) {\n transform: scale(1.02);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n\n .ngx-video-preview__play-button {\n transform: translate(-50%, -50%) scale(1.1);\n background: var(--ngx-chat-video-play-hover-bg, rgba(0, 0, 0, 0.85));\n }\n }\n\n &:focus-visible {\n outline: 2px solid var(--ngx-chat-focus-color, #2563eb);\n outline-offset: 2px;\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.7;\n }\n }\n\n .ngx-video-preview__skeleton {\n position: absolute;\n inset: 0;\n background: var(--ngx-chat-skeleton-bg, #e5e7eb);\n z-index: 1;\n }\n\n .ngx-video-preview__skeleton-shimmer {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n var(--ngx-chat-skeleton-shimmer, rgba(255, 255, 255, 0.5)) 50%,\n transparent 100%\n );\n animation: shimmer 1.5s infinite;\n }\n\n @keyframes shimmer {\n 0% {\n transform: translateX(-100%);\n }\n 100% {\n transform: translateX(100%);\n }\n }\n\n .ngx-video-preview__thumbnail {\n display: block;\n width: 100%;\n height: auto;\n max-height: var(--ngx-chat-video-max-height, 300px);\n object-fit: cover;\n transition: opacity 0.2s ease;\n }\n\n .ngx-video-preview__thumbnail--loading {\n opacity: 0;\n }\n\n .ngx-video-preview__thumbnail--error {\n opacity: 0.3;\n filter: grayscale(100%);\n }\n\n .ngx-video-preview__play-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(\n to bottom,\n transparent 0%,\n rgba(0, 0, 0, 0.1) 100%\n );\n }\n\n .ngx-video-preview__play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 56px;\n height: 56px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ngx-chat-video-play-bg, rgba(0, 0, 0, 0.7));\n border-radius: 50%;\n transition: transform 0.15s ease, background-color 0.15s ease;\n }\n\n .ngx-video-preview__play-icon {\n width: 28px;\n height: 28px;\n color: var(--ngx-chat-video-play-icon, #fff);\n margin-left: 3px; /* Visual centering for play triangle */\n }\n\n .ngx-video-preview__duration {\n position: absolute;\n bottom: 8px;\n right: 8px;\n padding: 2px 6px;\n font-size: 12px;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n color: var(--ngx-chat-badge-text, #fff);\n background: var(--ngx-chat-badge-bg, rgba(0, 0, 0, 0.75));\n border-radius: 4px;\n backdrop-filter: blur(4px);\n }\n\n .ngx-video-preview__error {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ngx-chat-error-overlay-bg, rgba(0, 0, 0, 0.1));\n }\n\n .ngx-video-preview__error-icon {\n width: 48px;\n height: 48px;\n color: var(--ngx-chat-error-icon-color, #dc2626);\n opacity: 0.8;\n }\n\n /* Dark theme */\n :host-context([data-theme=\"dark\"]) {\n .ngx-video-preview__skeleton {\n background: var(--ngx-chat-skeleton-bg, #374151);\n }\n\n .ngx-video-preview__skeleton-shimmer {\n background: linear-gradient(\n 90deg,\n transparent 0%,\n rgba(255, 255, 255, 0.1) 50%,\n transparent 100%\n );\n }\n }\n\n /* Reduced motion */\n @media (prefers-reduced-motion: reduce) {\n .ngx-video-preview__button {\n transition: none;\n }\n\n .ngx-video-preview__skeleton-shimmer {\n animation: none;\n }\n\n .ngx-video-preview__thumbnail {\n transition: none;\n }\n\n .ngx-video-preview__play-button {\n transition: none;\n }\n }\n\n /* Container query for compact layout */\n @container (max-width: 200px) {\n .ngx-video-preview__play-button {\n width: 40px;\n height: 40px;\n }\n\n .ngx-video-preview__play-icon {\n width: 20px;\n height: 20px;\n margin-left: 2px;\n }\n\n .ngx-video-preview__duration {\n font-size: 10px;\n padding: 1px 4px;\n }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-video-preview',\n },\n})\nexport class VideoPreviewComponent {\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The video attachment to display.\n */\n readonly attachment = input.required<MessageAttachment>();\n\n /**\n * ID of the message containing this attachment.\n * Required for building the click event.\n */\n readonly messageId = input.required<string>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits when the video preview is clicked.\n * Contains the message ID, attachment data, and action type.\n */\n readonly videoClick = output<AttachmentClickEvent>();\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /**\n * Whether the thumbnail is currently loading.\n */\n readonly isLoading = signal(true);\n\n /**\n * Whether the thumbnail failed to load.\n */\n readonly hasError = signal(false);\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * The thumbnail source URL.\n * Prefers thumbnail if available, otherwise uses main URL with video placeholder.\n */\n readonly thumbnailSrc = computed(() => {\n const att = this.attachment();\n return att.thumbnail || att.url;\n });\n\n /**\n * Whether to show the duration badge.\n * Only shown when duration is available and thumbnail is loaded.\n */\n readonly showDuration = computed(() => {\n const att = this.attachment();\n return !this.isLoading() && !this.hasError() && att.duration !== undefined && att.duration > 0;\n });\n\n /**\n * Formats the duration as m:ss or h:mm:ss.\n */\n readonly formattedDuration = computed(() => {\n const duration = this.attachment().duration;\n if (duration === undefined || duration <= 0) {\n return '';\n }\n\n const hours = Math.floor(duration / 3600);\n const minutes = Math.floor((duration % 3600) / 60);\n const seconds = Math.floor(duration % 60);\n\n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;\n }\n\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n });\n\n /**\n * ARIA label for the video button.\n */\n readonly ariaLabel = computed(() => {\n const att = this.attachment();\n let label = `Play video: ${att.name}`;\n\n if (att.duration !== undefined && att.duration > 0) {\n label += ` (${this.formattedDuration()})`;\n }\n\n if (att.dimensions) {\n label += ` - ${att.dimensions.width} x ${att.dimensions.height}`;\n }\n\n if (this.hasError()) {\n label += ' - Failed to load preview';\n }\n\n return label;\n });\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles successful thumbnail load.\n */\n onThumbnailLoad(): void {\n this.isLoading.set(false);\n }\n\n /**\n * Handles thumbnail load error.\n * Sets error state and attempts fallback.\n */\n onThumbnailError(event: Event): void {\n const img = event.target as HTMLImageElement;\n const att = this.attachment();\n\n // If we were showing thumbnail and it failed, try main URL\n if (att.thumbnail && img.src === att.thumbnail) {\n img.src = att.url;\n return;\n }\n\n // If main URL also failed (or no thumbnail), show error state\n this.isLoading.set(false);\n this.hasError.set(true);\n\n // Set fallback video placeholder SVG\n if (!img.dataset['fallback']) {\n img.dataset['fallback'] = 'true';\n img.src = 'data:image/svg+xml,' + encodeURIComponent(`\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 160 90\" fill=\"#9ca3af\">\n <rect width=\"160\" height=\"90\" fill=\"#1f2937\"/>\n <rect x=\"65\" y=\"30\" width=\"30\" height=\"30\" rx=\"4\" fill=\"#374151\"/>\n <polygon points=\"75,38 75,52 87,45\" fill=\"#6b7280\"/>\n </svg>\n `);\n }\n }\n\n /**\n * Handles button click.\n * Emits click event if not in error state.\n */\n onClick(): void {\n if (this.hasError()) {\n return;\n }\n\n this.videoClick.emit({\n messageId: this.messageId(),\n attachment: this.attachment(),\n action: 'preview',\n });\n }\n}\n","/**\n * @fileoverview Audio preview component for ngx-chat library.\n * Displays audio attachments with play/pause controls, progress bar, and duration display.\n * @module ngx-chat/components/chat-attachment\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n viewChild,\n ElementRef,\n afterNextRender,\n Injector,\n inject,\n} from '@angular/core';\n\nimport { MessageAttachment, AttachmentClickEvent } from '../../models/attachment.model';\n\n/**\n * Audio preview component for displaying audio attachments.\n *\n * This component displays an audio attachment with:\n * - Play/pause button\n * - Progress bar with seek functionality\n * - Current time and duration display\n * - Waveform-style background (CSS decorative)\n * - Loading state handling\n * - Error state handling\n * - Full accessibility support\n *\n * The component handles playback internally but emits events\n * for parent tracking and analytics.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-audio-preview\n * [attachment]=\"audioAttachment\"\n * [messageId]=\"message.id\"\n * (audioClick)=\"onAudioClick($event)\"\n * (playStateChange)=\"onPlayStateChange($event)\"\n * />\n * ```\n *\n * @example In ChatAttachmentComponent\n * ```html\n * @if (attachment.type === 'audio') {\n * <ngx-chat-audio-preview\n * [attachment]=\"attachment\"\n * [messageId]=\"messageId()\"\n * (audioClick)=\"onAttachmentClick($event)\"\n * />\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat-audio-preview',\n standalone: true,\n imports: [],\n template: `\n <div\n class=\"ngx-audio-preview__container\"\n [class.ngx-audio-preview__container--playing]=\"isPlaying()\"\n [class.ngx-audio-preview__container--loading]=\"isLoading()\"\n [class.ngx-audio-preview__container--error]=\"hasError()\"\n >\n <!-- Hidden audio element -->\n <audio\n #audioElement\n [src]=\"attachment().url\"\n preload=\"metadata\"\n (loadedmetadata)=\"onLoadedMetadata()\"\n (timeupdate)=\"onTimeUpdate()\"\n (ended)=\"onEnded()\"\n (error)=\"onError()\"\n (canplay)=\"onCanPlay()\"\n (waiting)=\"onWaiting()\"\n ></audio>\n\n <!-- Play/Pause button -->\n <button\n type=\"button\"\n class=\"ngx-audio-preview__play-button\"\n [attr.aria-label]=\"playButtonAriaLabel()\"\n [disabled]=\"hasError()\"\n (click)=\"togglePlay()\"\n >\n @if (isLoading()) {\n <!-- Loading spinner -->\n <svg\n class=\"ngx-audio-preview__spinner\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" opacity=\"0.25\" />\n <path d=\"M12 2a10 10 0 0 1 10 10\" />\n </svg>\n } @else if (isPlaying()) {\n <!-- Pause icon -->\n <svg\n class=\"ngx-audio-preview__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\" />\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\" />\n </svg>\n } @else {\n <!-- Play icon -->\n <svg\n class=\"ngx-audio-preview__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n }\n </button>\n\n <!-- Waveform and progress container -->\n <div class=\"ngx-audio-preview__waveform-container\">\n <!-- Waveform background (decorative) -->\n <div class=\"ngx-audio-preview__waveform\" aria-hidden=\"true\">\n @for (bar of waveformBars; track $index) {\n <div\n class=\"ngx-audio-preview__waveform-bar\"\n [style.height.%]=\"bar\"\n ></div>\n }\n </div>\n\n <!-- Progress bar -->\n <input\n type=\"range\"\n class=\"ngx-audio-preview__progress\"\n [value]=\"progressPercent()\"\n [disabled]=\"hasError() || !canSeek()\"\n min=\"0\"\n max=\"100\"\n step=\"0.1\"\n [attr.aria-label]=\"'Audio progress: ' + formattedCurrentTime() + ' of ' + formattedDuration()\"\n (input)=\"onSeek($event)\"\n />\n\n <!-- Progress fill overlay -->\n <div\n class=\"ngx-audio-preview__progress-fill\"\n [style.width.%]=\"progressPercent()\"\n aria-hidden=\"true\"\n ></div>\n </div>\n\n <!-- Time display -->\n <div class=\"ngx-audio-preview__time\">\n <span class=\"ngx-audio-preview__current-time\">{{ formattedCurrentTime() }}</span>\n <span class=\"ngx-audio-preview__separator\">/</span>\n <span class=\"ngx-audio-preview__duration\">{{ formattedDuration() }}</span>\n </div>\n\n <!-- Error overlay -->\n @if (hasError()) {\n <div class=\"ngx-audio-preview__error-overlay\">\n <svg\n class=\"ngx-audio-preview__error-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n <span>Failed to load audio</span>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n container-type: inline-size;\n }\n\n .ngx-audio-preview__container {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: var(--ngx-chat-audio-bg, #f3f4f6);\n border: 1px solid var(--ngx-chat-border-color, #e5e7eb);\n border-radius: var(--ngx-chat-attachment-radius, 8px);\n position: relative;\n }\n\n .ngx-audio-preview__container--error {\n opacity: 0.7;\n }\n\n audio {\n display: none;\n }\n\n .ngx-audio-preview__play-button {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n padding: 0;\n border: none;\n border-radius: 50%;\n background: var(--ngx-chat-audio-play-bg, #2563eb);\n color: var(--ngx-chat-audio-play-color, #fff);\n cursor: pointer;\n transition: background-color 0.15s ease, transform 0.15s ease;\n\n &:hover:not(:disabled) {\n background: var(--ngx-chat-audio-play-hover-bg, #1d4ed8);\n transform: scale(1.05);\n }\n\n &:focus-visible {\n outline: 2px solid var(--ngx-chat-focus-color, #2563eb);\n outline-offset: 2px;\n }\n\n &:disabled {\n background: var(--ngx-chat-audio-play-disabled-bg, #9ca3af);\n cursor: not-allowed;\n }\n }\n\n .ngx-audio-preview__icon {\n width: 20px;\n height: 20px;\n }\n\n .ngx-audio-preview__spinner {\n width: 20px;\n height: 20px;\n animation: spin 1s linear infinite;\n }\n\n @keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n\n .ngx-audio-preview__waveform-container {\n flex: 1;\n position: relative;\n height: 32px;\n min-width: 0;\n }\n\n .ngx-audio-preview__waveform {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 0 2px;\n }\n\n .ngx-audio-preview__waveform-bar {\n flex: 1;\n min-width: 2px;\n max-width: 4px;\n background: var(--ngx-chat-audio-waveform-bg, #d1d5db);\n border-radius: 1px;\n transition: background-color 0.1s ease;\n }\n\n .ngx-audio-preview__container--playing .ngx-audio-preview__waveform-bar {\n background: var(--ngx-chat-audio-waveform-active-bg, #93c5fd);\n }\n\n .ngx-audio-preview__progress {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n background: transparent;\n cursor: pointer;\n opacity: 0;\n z-index: 2;\n\n &:disabled {\n cursor: not-allowed;\n }\n\n &:focus-visible {\n opacity: 1;\n outline: 2px solid var(--ngx-chat-focus-color, #2563eb);\n outline-offset: 2px;\n }\n }\n\n .ngx-audio-preview__progress-fill {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n background: var(--ngx-chat-audio-progress-bg, rgba(37, 99, 235, 0.15));\n border-radius: 4px 0 0 4px;\n pointer-events: none;\n z-index: 1;\n }\n\n .ngx-audio-preview__time {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n gap: 2px;\n font-size: 12px;\n font-weight: 500;\n font-variant-numeric: tabular-nums;\n color: var(--ngx-chat-audio-time-color, #6b7280);\n }\n\n .ngx-audio-preview__separator {\n opacity: 0.5;\n }\n\n .ngx-audio-preview__error-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n background: var(--ngx-chat-error-overlay-bg, rgba(255, 255, 255, 0.9));\n border-radius: var(--ngx-chat-attachment-radius, 8px);\n font-size: 12px;\n color: var(--ngx-chat-error-text, #dc2626);\n }\n\n .ngx-audio-preview__error-icon {\n width: 16px;\n height: 16px;\n }\n\n /* Dark theme */\n :host-context([data-theme=\"dark\"]) {\n .ngx-audio-preview__container {\n background: var(--ngx-chat-audio-bg, #1f2937);\n border-color: var(--ngx-chat-border-color, #374151);\n }\n\n .ngx-audio-preview__waveform-bar {\n background: var(--ngx-chat-audio-waveform-bg, #4b5563);\n }\n\n .ngx-audio-preview__container--playing .ngx-audio-preview__waveform-bar {\n background: var(--ngx-chat-audio-waveform-active-bg, #3b82f6);\n }\n\n .ngx-audio-preview__time {\n color: var(--ngx-chat-audio-time-color, #9ca3af);\n }\n\n .ngx-audio-preview__error-overlay {\n background: var(--ngx-chat-error-overlay-bg, rgba(31, 41, 55, 0.95));\n }\n }\n\n /* Reduced motion */\n @media (prefers-reduced-motion: reduce) {\n .ngx-audio-preview__play-button {\n transition: none;\n }\n\n .ngx-audio-preview__spinner {\n animation: none;\n }\n\n .ngx-audio-preview__waveform-bar {\n transition: none;\n }\n }\n\n /* Container query for compact layout */\n @container (max-width: 250px) {\n .ngx-audio-preview__container {\n padding: 8px;\n gap: 8px;\n }\n\n .ngx-audio-preview__play-button {\n width: 32px;\n height: 32px;\n }\n\n .ngx-audio-preview__icon {\n width: 16px;\n height: 16px;\n }\n\n .ngx-audio-preview__spinner {\n width: 16px;\n height: 16px;\n }\n\n .ngx-audio-preview__waveform-container {\n height: 24px;\n }\n\n .ngx-audio-preview__time {\n font-size: 10px;\n }\n }\n `],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-audio-preview',\n },\n})\nexport class AudioPreviewComponent {\n private readonly injector = inject(Injector);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The audio attachment to display.\n */\n readonly attachment = input.required<MessageAttachment>();\n\n /**\n * ID of the message containing this attachment.\n * Required for building the click event.\n */\n readonly messageId = input.required<string>();\n\n // ===========================================================================\n // Outputs\n // ===========================================================================\n\n /**\n * Emits when the audio is clicked/interacted with.\n * Contains the message ID, attachment data, and action type.\n */\n readonly audioClick = output<AttachmentClickEvent>();\n\n /**\n * Emits when the play state changes.\n * True = playing, false = paused.\n */\n readonly playStateChange = output<boolean>();\n\n // ===========================================================================\n // View Queries\n // ===========================================================================\n\n /**\n * Reference to the audio element.\n */\n readonly audioElement = viewChild<ElementRef<HTMLAudioElement>>('audioElement');\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /**\n * Whether the audio is currently playing.\n */\n readonly isPlaying = signal(false);\n\n /**\n * Whether the audio is loading/buffering.\n */\n readonly isLoading = signal(true);\n\n /**\n * Whether the audio failed to load.\n */\n readonly hasError = signal(false);\n\n /**\n * Whether seeking is available.\n */\n readonly canSeek = signal(false);\n\n /**\n * Current playback time in seconds.\n */\n readonly currentTime = signal(0);\n\n /**\n * Total duration in seconds.\n */\n readonly duration = signal(0);\n\n // ===========================================================================\n // Constants\n // ===========================================================================\n\n /**\n * Decorative waveform bar heights (percentages).\n * These create a visual waveform pattern.\n */\n readonly waveformBars = [\n 30, 50, 70, 45, 80, 55, 65, 40, 75, 50,\n 60, 35, 85, 45, 70, 55, 40, 65, 50, 75,\n 45, 60, 35, 80, 50, 55, 70, 40, 65, 45,\n ];\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * Progress as a percentage (0-100).\n */\n readonly progressPercent = computed(() => {\n const dur = this.duration();\n if (dur <= 0) return 0;\n return (this.currentTime() / dur) * 100;\n });\n\n /**\n * Formats the current time as m:ss.\n */\n readonly formattedCurrentTime = computed(() => {\n return this.formatTime(this.currentTime());\n });\n\n /**\n * Formats the total duration as m:ss.\n */\n readonly formattedDuration = computed(() => {\n const dur = this.duration();\n if (dur <= 0) {\n // Use attachment duration as fallback\n const attDur = this.attachment().duration;\n return attDur ? this.formatTime(attDur) : '0:00';\n }\n return this.formatTime(dur);\n });\n\n /**\n * ARIA label for the play button.\n */\n readonly playButtonAriaLabel = computed(() => {\n const att = this.attachment();\n\n if (this.hasError()) {\n return `Failed to load audio: ${att.name}`;\n }\n\n if (this.isLoading()) {\n return `Loading audio: ${att.name}`;\n }\n\n const action = this.isPlaying() ? 'Pause' : 'Play';\n return `${action} audio: ${att.name} (${this.formattedDuration()})`;\n });\n\n // ===========================================================================\n // Lifecycle\n // ===========================================================================\n\n constructor() {\n // Clean up on destroy\n afterNextRender(() => {\n // Any initialization after render\n }, { injector: this.injector });\n }\n\n // ===========================================================================\n // Event Handlers\n // ===========================================================================\n\n /**\n * Handles audio metadata loaded.\n */\n onLoadedMetadata(): void {\n const audio = this.audioElement()?.nativeElement;\n if (audio) {\n this.duration.set(audio.duration);\n this.canSeek.set(true);\n }\n }\n\n /**\n * Handles audio can play.\n */\n onCanPlay(): void {\n this.isLoading.set(false);\n }\n\n /**\n * Handles audio waiting (buffering).\n */\n onWaiting(): void {\n this.isLoading.set(true);\n }\n\n /**\n * Handles audio time update.\n */\n onTimeUpdate(): void {\n const audio = this.audioElement()?.nativeElement;\n if (audio) {\n this.currentTime.set(audio.currentTime);\n }\n }\n\n /**\n * Handles audio ended.\n */\n onEnded(): void {\n this.isPlaying.set(false);\n this.currentTime.set(0);\n this.playStateChange.emit(false);\n\n // Reset audio to beginning\n const audio = this.audioElement()?.nativeElement;\n if (audio) {\n audio.currentTime = 0;\n }\n }\n\n /**\n * Handles audio error.\n */\n onError(): void {\n this.isLoading.set(false);\n this.hasError.set(true);\n this.isPlaying.set(false);\n }\n\n /**\n * Toggles play/pause state.\n */\n togglePlay(): void {\n if (this.hasError()) {\n return;\n }\n\n const audio = this.audioElement()?.nativeElement;\n if (!audio) {\n return;\n }\n\n if (this.isPlaying()) {\n audio.pause();\n this.isPlaying.set(false);\n this.playStateChange.emit(false);\n } else {\n audio.play().then(() => {\n this.isPlaying.set(true);\n this.playStateChange.emit(true);\n }).catch(() => {\n // Play was prevented (e.g., autoplay policy)\n this.hasError.set(true);\n });\n }\n\n // Emit click event for analytics\n this.audioClick.emit({\n messageId: this.messageId(),\n attachment: this.attachment(),\n action: 'click',\n });\n }\n\n /**\n * Handles seek via progress bar.\n */\n onSeek(event: Event): void {\n const input = event.target as HTMLInputElement;\n const percent = parseFloat(input.value);\n const audio = this.audioElement()?.nativeElement;\n\n if (audio && this.duration() > 0) {\n audio.currentTime = (percent / 100) * this.duration();\n this.currentTime.set(audio.currentTime);\n }\n }\n\n // ===========================================================================\n // Utility Methods\n // ===========================================================================\n\n /**\n * Formats seconds to m:ss or h:mm:ss.\n */\n private formatTime(seconds: number): string {\n if (!isFinite(seconds) || seconds < 0) {\n return '0:00';\n }\n\n const hours = Math.floor(seconds / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const secs = Math.floor(seconds % 60);\n\n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n }\n\n return `${minutes}:${secs.toString().padStart(2, '0')}`;\n }\n}\n","/**\n * @fileoverview Markdown parsing service for ngx-chat.\n * Provides lazy loading of markdown dependencies with XSS protection.\n * @module ngx-chat/services/chat-markdown\n */\n\nimport { Injectable, inject, signal, computed } from '@angular/core';\nimport { ChatConfigService } from './chat-config.service';\nimport { ChatMarkdownConfig } from '../models/config.model';\n\n/**\n * Result of markdown parsing.\n */\nexport interface MarkdownParseResult {\n /** Parsed HTML content (sanitized) */\n readonly html: string;\n /** Whether parsing was successful */\n readonly success: boolean;\n /** Error message if parsing failed */\n readonly error?: string;\n}\n\n/**\n * Type definitions for dynamically imported modules.\n * Using 'any' for marked types to avoid version-specific type mismatches.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface MarkedModule {\n marked: MarkedInstance;\n Renderer: new () => any;\n}\n\ninterface MarkedInstance {\n parse(content: string, options?: MarkedOptions): string | Promise<string>;\n setOptions(options: MarkedOptions): void;\n use(extension: MarkedExtension): void;\n}\n\ninterface MarkedOptions {\n breaks?: boolean;\n gfm?: boolean;\n async?: boolean;\n}\n\ninterface MarkedExtension {\n renderer?: Record<string, any>;\n}\n\ninterface LinkToken {\n href: string;\n title?: string | null;\n tokens: any[];\n}\n\ninterface CodeToken {\n text: string;\n lang?: string;\n escaped?: boolean;\n}\n\ninterface DOMPurifyModule {\n default: {\n sanitize(content: string, config?: DOMPurifyConfig): string;\n };\n}\n\ninterface DOMPurifyConfig {\n ALLOWED_TAGS?: string[];\n ALLOWED_ATTR?: string[];\n ADD_ATTR?: string[];\n}\n\ninterface HighlightModule {\n default: {\n highlight(code: string, options: { language: string }): { value: string };\n highlightAuto(code: string): { value: string };\n getLanguage(name: string): unknown;\n };\n}\n\n/**\n * Service for parsing markdown content with XSS protection.\n *\n * This service lazily loads markdown dependencies (marked, DOMPurify, highlight.js)\n * only when needed, reducing initial bundle size. All parsed content is sanitized\n * to prevent XSS attacks.\n *\n * @example\n * ```typescript\n * @Component({...})\n * export class ChatMessage {\n * private readonly markdownService = inject(ChatMarkdownService);\n *\n * async ngOnInit() {\n * await this.markdownService.initialize();\n * }\n *\n * parseContent(content: string): string {\n * const result = this.markdownService.parse(content);\n * return result.success ? result.html : result.error ?? content;\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ChatMarkdownService {\n private readonly configService = inject(ChatConfigService);\n\n /**\n * Whether markdown dependencies have been loaded.\n */\n readonly isLoaded = signal(false);\n\n /**\n * Error message if loading failed.\n */\n readonly loadError = signal<string | null>(null);\n\n /**\n * Whether the service is ready to parse markdown.\n */\n readonly isReady = computed(() => this.isLoaded() && !this.loadError());\n\n /**\n * Private instances of dynamically loaded modules.\n */\n private markedInstance: MarkedInstance | null = null;\n private purifyInstance: DOMPurifyModule['default'] | null = null;\n private highlightInstance: HighlightModule['default'] | null = null;\n\n /**\n * Flag to prevent multiple initialization attempts.\n */\n private initPromise: Promise<void> | null = null;\n\n /**\n * Gets the current markdown configuration.\n */\n private get config(): ChatMarkdownConfig {\n return this.configService.getConfig().markdown;\n }\n\n /**\n * Initializes the markdown service by loading dependencies.\n *\n * This method lazily loads marked, DOMPurify, and optionally highlight.js.\n * It's safe to call multiple times - subsequent calls return the same promise.\n *\n * @returns Promise that resolves when dependencies are loaded\n *\n * @example\n * ```typescript\n * // Call once during component initialization\n * await markdownService.initialize();\n *\n * // Safe to call multiple times\n * await markdownService.initialize(); // Returns immediately\n * ```\n */\n async initialize(): Promise<void> {\n // If already loaded, return immediately\n if (this.isLoaded()) {\n return;\n }\n\n // If loading is in progress, return the existing promise\n if (this.initPromise) {\n return this.initPromise;\n }\n\n // Start loading\n this.initPromise = this.loadDependencies();\n return this.initPromise;\n }\n\n /**\n * Parses markdown content and returns sanitized HTML.\n *\n * If markdown is disabled in configuration, returns HTML-escaped content.\n * If dependencies are not loaded, attempts to load them first.\n *\n * @param content - Raw markdown content to parse\n * @returns Parse result with sanitized HTML or error\n *\n * @example\n * ```typescript\n * const result = markdownService.parse('**Hello** _world_');\n * if (result.success) {\n * element.innerHTML = result.html;\n * // <p><strong>Hello</strong> <em>world</em></p>\n * }\n * ```\n */\n parse(content: string): MarkdownParseResult {\n // Return empty for empty content\n if (!content || content.trim() === '') {\n return { html: '', success: true };\n }\n\n // If markdown is disabled, return escaped HTML\n if (!this.config.enabled) {\n return {\n html: this.escapeHtml(content),\n success: true,\n };\n }\n\n // If not loaded, return escaped content with error\n if (!this.isLoaded() || !this.markedInstance || !this.purifyInstance) {\n return {\n html: this.escapeHtml(content),\n success: false,\n error: 'Markdown dependencies not loaded. Call initialize() first.',\n };\n }\n\n try {\n // Parse markdown\n const rawHtml = this.markedInstance.parse(content, {\n async: false,\n }) as string;\n\n // Sanitize with DOMPurify\n const sanitized = this.sanitizeHtml(rawHtml);\n\n return { html: sanitized, success: true };\n } catch (error) {\n return {\n html: this.escapeHtml(content),\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n /**\n * Parses markdown content asynchronously.\n *\n * Automatically initializes the service if not already initialized.\n * Useful when you can't guarantee initialization has completed.\n *\n * @param content - Raw markdown content to parse\n * @returns Promise resolving to parse result\n *\n * @example\n * ```typescript\n * const result = await markdownService.parseAsync('# Hello');\n * element.innerHTML = result.html;\n * ```\n */\n async parseAsync(content: string): Promise<MarkdownParseResult> {\n // Initialize if needed\n if (!this.isLoaded()) {\n await this.initialize();\n }\n\n return this.parse(content);\n }\n\n /**\n * Loads all markdown dependencies.\n */\n private async loadDependencies(): Promise<void> {\n try {\n this.loadError.set(null);\n\n // Load marked and DOMPurify in parallel (required)\n const [markedModule, purifyModule] = await Promise.all([\n import('marked') as Promise<MarkedModule>,\n import('dompurify') as Promise<DOMPurifyModule>,\n ]);\n\n this.markedInstance = markedModule.marked;\n this.purifyInstance = purifyModule.default;\n\n // Configure marked\n this.configureMarked(markedModule);\n\n // Load highlight.js if syntax highlighting is enabled (optional)\n if (this.config.syntaxHighlighting) {\n try {\n const hljs = await import('highlight.js') as HighlightModule;\n this.highlightInstance = hljs.default;\n } catch {\n // Syntax highlighting is optional - fail silently\n console.warn(\n 'ngx-chat: highlight.js not found. Syntax highlighting disabled.'\n );\n }\n }\n\n this.isLoaded.set(true);\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : 'Failed to load markdown dependencies';\n this.loadError.set(message);\n this.initPromise = null; // Allow retry\n throw new Error(message);\n }\n }\n\n /**\n * Configures the marked renderer with custom options.\n */\n private configureMarked(_markedModule: MarkedModule): void {\n if (!this.markedInstance) return;\n\n const config = this.config;\n const hljs = this.highlightInstance;\n const self = this;\n\n // Configure base options\n this.markedInstance.setOptions({\n breaks: config.breaks,\n gfm: true,\n });\n\n // Custom renderer object for marked v17+ token-based API\n const rendererOverrides: Record<string, any> = {\n // Custom link renderer for security\n link(token: LinkToken): string {\n const { href, title, tokens } = token;\n // Get text content from tokens\n const text = tokens\n .map((t: any) => t.text || t.raw || '')\n .join('');\n\n // Determine if link is external\n const isExternal = self.isExternalLink(href);\n\n // Build attributes\n const attrs: string[] = [`href=\"${self.escapeAttribute(href)}\"`];\n\n if (title) {\n attrs.push(`title=\"${self.escapeAttribute(title)}\"`);\n }\n\n if (isExternal) {\n if (config.externalLinksNewTab) {\n attrs.push('target=\"_blank\"');\n }\n if (config.sanitizeLinks) {\n attrs.push('rel=\"noopener noreferrer\"');\n }\n }\n\n return `<a ${attrs.join(' ')}>${text}</a>`;\n },\n\n // Custom code renderer for syntax highlighting\n code(token: CodeToken): string {\n const { text, lang, escaped } = token;\n let highlighted = escaped ? text : self.escapeHtml(text);\n\n if (hljs && lang) {\n try {\n // Check if language is supported\n if (hljs.getLanguage(lang)) {\n highlighted = hljs.highlight(text, { language: lang }).value;\n } else {\n // Try auto-detection\n highlighted = hljs.highlightAuto(text).value;\n }\n } catch {\n // Fall back to escaped code\n }\n }\n\n const langClass = lang ? ` class=\"language-${lang}\"` : '';\n return `<pre><code${langClass}>${highlighted}</code></pre>`;\n },\n };\n\n // Apply custom renderer\n this.markedInstance.use({ renderer: rendererOverrides });\n }\n\n /**\n * Sanitizes HTML content using DOMPurify.\n */\n private sanitizeHtml(html: string): string {\n if (!this.purifyInstance) {\n return this.escapeHtml(html);\n }\n\n const config = this.config;\n const purifyConfig: DOMPurifyConfig = {\n ALLOWED_TAGS: [...config.allowedTags],\n ALLOWED_ATTR: this.flattenAllowedAttributes(config.allowedAttributes),\n };\n\n // Add target and rel to allowed attributes for links\n if (config.externalLinksNewTab || config.sanitizeLinks) {\n purifyConfig.ADD_ATTR = ['target', 'rel'];\n }\n\n return this.purifyInstance.sanitize(html, purifyConfig);\n }\n\n /**\n * Flattens the allowedAttributes configuration into a DOMPurify-compatible array.\n *\n * Converts the tag-specific attribute map into a flat array of attribute names.\n *\n * @param allowedAttributes - Configuration map { 'a': ['href'], '*': ['class'] }\n * @returns Flat array of allowed attribute names ['href', 'class']\n */\n private flattenAllowedAttributes(\n allowedAttributes: Readonly<Record<string, readonly string[]>>\n ): string[] {\n const attributeSet = new Set<string>();\n\n for (const attrs of Object.values(allowedAttributes)) {\n for (const attr of attrs) {\n attributeSet.add(attr);\n }\n }\n\n return [...attributeSet];\n }\n\n /**\n * Escapes HTML special characters.\n *\n * Used as fallback when markdown is disabled or dependencies aren't loaded.\n *\n * @param content - Raw content to escape\n * @returns HTML-escaped content\n */\n private escapeHtml(content: string): string {\n const escapeMap: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n };\n\n return content.replace(/[&<>\"']/g, (char) => escapeMap[char]);\n }\n\n /**\n * Escapes special characters in HTML attribute values.\n */\n private escapeAttribute(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n }\n\n /**\n * Checks if a URL is external.\n */\n private isExternalLink(href: string): boolean {\n // Handle protocol-relative URLs\n if (href.startsWith('//')) {\n return true;\n }\n\n // Handle absolute URLs\n if (href.startsWith('http://') || href.startsWith('https://')) {\n try {\n const url = new URL(href);\n return url.hostname !== window.location.hostname;\n } catch {\n return false;\n }\n }\n\n // Relative URLs are not external\n return false;\n }\n\n /**\n * Resets the service state for testing purposes.\n */\n resetForTesting(): void {\n this.isLoaded.set(false);\n this.loadError.set(null);\n this.markedInstance = null;\n this.purifyInstance = null;\n this.highlightInstance = null;\n this.initPromise = null;\n }\n}\n","/**\n * @fileoverview Markdown rendering component for ngx-chat library.\n * Provides lazy loading of markdown dependencies with XSS-safe rendering.\n * @module ngx-chat/components/chat-markdown\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n inject,\n signal,\n computed,\n effect,\n SecurityContext,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\n\nimport { ChatMarkdownService } from '../../services/chat-markdown.service';\nimport { ChatConfigService } from '../../services/chat-config.service';\n\n/**\n * Markdown rendering component.\n *\n * Renders markdown content with lazy loading of dependencies (marked, DOMPurify,\n * highlight.js). Displays a loading indicator while initializing and falls back\n * to escaped text when markdown is disabled or on error.\n *\n * The component automatically initializes the ChatMarkdownService on first use\n * and caches parsed content for performance.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-markdown [content]=\"message.content\" />\n * ```\n *\n * @example With dynamic content\n * ```html\n * <ngx-chat-markdown [content]=\"streamingContent()\" />\n * ```\n *\n * @remarks\n * All output is sanitized by DOMPurify to prevent XSS attacks.\n * The component uses OnPush change detection for optimal performance.\n */\n@Component({\n selector: 'ngx-chat-markdown',\n standalone: true,\n template: `\n @if (isLoading()) {\n <span class=\"ngx-chat-markdown__loading\" aria-hidden=\"true\">\n <span class=\"ngx-chat-markdown__loading-dot\"></span>\n <span class=\"ngx-chat-markdown__loading-dot\"></span>\n <span class=\"ngx-chat-markdown__loading-dot\"></span>\n </span>\n <span class=\"ngx-chat-markdown__sr-only\">{{ loadingText() }}</span>\n } @else if (hasError()) {\n <span class=\"ngx-chat-markdown__fallback\">{{ escapedContent() }}</span>\n } @else {\n <span\n class=\"ngx-chat-markdown__content\"\n [innerHTML]=\"safeHtml()\"\n ></span>\n }\n `,\n styleUrls: ['./chat-markdown.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-markdown',\n '[class.ngx-chat-markdown--loading]': 'isLoading()',\n '[class.ngx-chat-markdown--error]': 'hasError()',\n '[class.ngx-chat-markdown--disabled]': '!isMarkdownEnabled()',\n },\n})\nexport class ChatMarkdownComponent {\n // ===========================================================================\n // Injected Services\n // ===========================================================================\n\n private readonly markdownService = inject(ChatMarkdownService);\n private readonly configService = inject(ChatConfigService);\n private readonly sanitizer = inject(DomSanitizer);\n\n // ===========================================================================\n // Inputs\n // ===========================================================================\n\n /**\n * The markdown content to render.\n *\n * When content changes, the component will re-parse and render the new content.\n * Empty or whitespace-only content renders as empty.\n *\n * @example \"**Bold** and _italic_ text\"\n * @example \"```typescript\\nconst x = 1;\\n```\"\n */\n readonly content = input<string>('');\n\n // ===========================================================================\n // Internal State\n // ===========================================================================\n\n /**\n * Parsed HTML content from markdown.\n */\n private readonly parsedHtml = signal<string>('');\n\n /**\n * Whether parsing is in progress.\n */\n readonly isLoading = signal<boolean>(false);\n\n /**\n * Error message if parsing failed.\n */\n private readonly errorMessage = signal<string | null>(null);\n\n // ===========================================================================\n // Computed Values\n // ===========================================================================\n\n /**\n * Whether markdown rendering is enabled in configuration.\n */\n readonly isMarkdownEnabled = computed(() => {\n return this.configService.getConfig().markdown.enabled;\n });\n\n /**\n * Whether there was an error parsing the content.\n */\n readonly hasError = computed(() => {\n return this.errorMessage() !== null;\n });\n\n /**\n * Safe HTML for rendering via innerHTML binding.\n *\n * Uses Angular's DomSanitizer as an additional layer of protection,\n * even though content is already sanitized by DOMPurify.\n */\n readonly safeHtml = computed((): SafeHtml => {\n const html = this.parsedHtml();\n // Content is already sanitized by DOMPurify in ChatMarkdownService\n // We use bypassSecurityTrustHtml because we trust our sanitization\n return this.sanitizer.bypassSecurityTrustHtml(html);\n });\n\n /**\n * Escaped content for fallback display.\n */\n readonly escapedContent = computed(() => {\n return this.escapeHtml(this.content());\n });\n\n /**\n * Loading text for screen readers.\n */\n readonly loadingText = computed(() => {\n return this.configService.getI18n().loading;\n });\n\n // ===========================================================================\n // Constructor / Effects\n // ===========================================================================\n\n constructor() {\n // Effect to parse content when it changes\n effect(() => {\n const content = this.content();\n this.parseContent(content);\n });\n }\n\n // ===========================================================================\n // Private Methods\n // ===========================================================================\n\n /**\n * Parses markdown content asynchronously.\n *\n * Handles initialization of the markdown service automatically.\n * Falls back to escaped content on error.\n */\n private async parseContent(content: string): Promise<void> {\n // Handle empty content\n if (!content || content.trim() === '') {\n this.parsedHtml.set('');\n this.errorMessage.set(null);\n this.isLoading.set(false);\n return;\n }\n\n // If markdown is disabled, use escaped content\n if (!this.isMarkdownEnabled()) {\n this.parsedHtml.set(this.escapeHtml(content));\n this.errorMessage.set(null);\n this.isLoading.set(false);\n return;\n }\n\n // Show loading state\n this.isLoading.set(true);\n this.errorMessage.set(null);\n\n try {\n // Use parseAsync which auto-initializes the service\n const result = await this.markdownService.parseAsync(content);\n\n if (result.success) {\n this.parsedHtml.set(result.html);\n this.errorMessage.set(null);\n } else {\n // Parsing failed - use escaped content\n this.parsedHtml.set(this.escapeHtml(content));\n this.errorMessage.set(result.error ?? 'Parsing failed');\n }\n } catch (error) {\n // Service initialization or parsing error\n this.parsedHtml.set(this.escapeHtml(content));\n this.errorMessage.set(\n error instanceof Error ? error.message : 'Unknown error'\n );\n } finally {\n this.isLoading.set(false);\n }\n }\n\n /**\n * Escapes HTML special characters for safe display.\n *\n * Used as fallback when markdown is disabled or parsing fails.\n */\n private escapeHtml(content: string): string {\n const escapeMap: Record<string, string> = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n };\n\n return content.replace(/[&<>\"']/g, (char) => escapeMap[char]);\n }\n}\n","/**\n * @fileoverview Chat error boundary component for ngx-chat library.\n * Provides error handling with fallback UI and retry functionality.\n * @module ngx-chat/components/chat-error-boundary\n */\n\nimport {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n} from '@angular/core';\n\n/**\n * Chat error boundary component.\n *\n * Provides a boundary for catching and displaying errors gracefully.\n * When an error occurs, it displays a fallback message with a retry button.\n * When no error, it projects the child content normally.\n *\n * Note: This component does not catch errors automatically. The parent must\n * call `handleError()` when an error occurs and `reset()` to clear the error.\n *\n * @example Basic usage\n * ```html\n * <ngx-chat-error-boundary #errorBoundary (retry)=\"onRetry()\">\n * <app-risky-content />\n * </ngx-chat-error-boundary>\n * ```\n *\n * @example With custom fallback message\n * ```html\n * <ngx-chat-error-boundary\n * fallbackMessage=\"Failed to load messages\"\n * (retry)=\"loadMessages()\">\n * <app-messages-list />\n * </ngx-chat-error-boundary>\n * ```\n *\n * @example Programmatic error handling\n * ```typescript\n * @ViewChild('errorBoundary') errorBoundary!: ChatErrorBoundaryComponent;\n *\n * async loadData() {\n * try {\n * await this.dataService.load();\n * } catch (error) {\n * this.errorBoundary.handleError(error);\n * }\n * }\n *\n * onRetry() {\n * this.loadData();\n * }\n * ```\n */\n@Component({\n selector: 'ngx-chat-error-boundary',\n standalone: true,\n template: `\n @if (hasError()) {\n <div class=\"ngx-chat-error-boundary__error\">\n <span class=\"ngx-chat-error-boundary__icon\" aria-hidden=\"true\">!</span>\n <span class=\"ngx-chat-error-boundary__message\">\n {{ errorMessage() || fallbackMessage() }}\n </span>\n <button\n type=\"button\"\n class=\"ngx-chat-error-boundary__retry\"\n (click)=\"onRetry()\">\n Retry\n </button>\n </div>\n } @else {\n <ng-content />\n }\n `,\n styleUrls: ['./chat-error-boundary.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'class': 'ngx-chat-error-boundary',\n '[class.ngx-chat-error-boundary--has-error]': 'hasError()',\n 'role': 'region',\n '[attr.aria-live]': 'hasError() ? \"assertive\" : null',\n },\n})\nexport class ChatErrorBoundaryComponent {\n /**\n * Fallback message to display when an error occurs and no specific\n * error message is available.\n *\n * @default 'Something went wrong'\n */\n readonly fallbackMessage = input('Something went wrong');\n\n /**\n * Emits when the user clicks the retry button.\n * The parent component should handle this event to retry the failed operation.\n * The error state is automatically reset before emitting.\n */\n readonly retry = output<void>();\n\n /**\n * Whether the component is currently in an error state.\n * When true, the error UI is displayed instead of the projected content.\n */\n readonly hasError = signal(false);\n\n /**\n * The specific error message, if available.\n * If null/undefined, the fallbackMessage is used instead.\n */\n readonly errorMessage = signal<string | null>(null);\n\n /**\n * Sets the component into an error state with the given error.\n * The error can be an Error object (message is extracted) or a string.\n *\n * @param error - The error that occurred\n *\n * @example With Error object\n * ```typescript\n * try {\n * await riskyOperation();\n * } catch (error) {\n * this.errorBoundary.handleError(error);\n * }\n * ```\n *\n * @example With string message\n * ```typescript\n * this.errorBoundary.handleError('Connection lost');\n * ```\n */\n handleError(error: Error | string): void {\n const message = error instanceof Error ? error.message : error;\n this.errorMessage.set(message);\n this.hasError.set(true);\n }\n\n /**\n * Resets the error state, clearing any stored error.\n * After reset, the projected content will be displayed again.\n *\n * @example Manual reset\n * ```typescript\n * this.errorBoundary.reset();\n * ```\n */\n reset(): void {\n this.hasError.set(false);\n this.errorMessage.set(null);\n }\n\n /**\n * Handles the retry button click.\n * Resets the error state and emits the retry event.\n * @internal\n */\n protected onRetry(): void {\n this.reset();\n this.retry.emit();\n }\n}\n","/**\n * @fileoverview Components barrel export.\n * @module ngx-chat/components\n */\n\n// Main chat component\nexport { ChatComponent } from './chat/chat.component';\n\n// Chat header component\nexport { ChatHeaderComponent } from './chat-header/chat-header.component';\n\n// Chat typing indicator component\nexport { ChatTypingIndicatorComponent } from './chat-typing-indicator/chat-typing-indicator.component';\n\n// Chat messages container component\nexport { ChatMessagesComponent } from './chat-messages/chat-messages.component';\n\n// Chat message bubble component\nexport { ChatMessageBubbleComponent } from './chat-message-bubble/chat-message-bubble.component';\n\n// Chat sender component\nexport { ChatSenderComponent } from './chat-sender/chat-sender.component';\n\n// Chat message actions component\nexport { ChatMessageActionsComponent } from './chat-message-actions/chat-message-actions.component';\n\n// Action components\nexport { ConfirmActionComponent } from './actions/confirm-action/confirm-action.component';\nexport { SelectActionComponent } from './actions/select-action/select-action.component';\nexport { MultiSelectActionComponent } from './actions/multi-select-action/multi-select-action.component';\nexport { ButtonsActionComponent } from './actions/buttons-action/buttons-action.component';\n\n// Attachment components\nexport { AttachmentPickerComponent } from './chat-attachment-picker/attachment-picker.component';\nexport { AttachmentPreviewComponent } from './chat-attachment-picker/attachment-preview.component';\nexport { ChatAttachmentComponent } from './chat-attachment/chat-attachment.component';\nexport { ImagePreviewComponent } from './chat-attachment/image-preview.component';\nexport { FilePreviewComponent } from './chat-attachment/file-preview.component';\nexport { VideoPreviewComponent } from './chat-attachment/video-preview.component';\nexport { AudioPreviewComponent } from './chat-attachment/audio-preview.component';\n\n// Markdown component\nexport { ChatMarkdownComponent } from './chat-markdown/chat-markdown.component';\n\n// Error boundary component\nexport { ChatErrorBoundaryComponent } from './chat-error-boundary/chat-error-boundary.component';\n","/**\n * @fileoverview Directives barrel export.\n * @module ngx-chat/directives\n */\n\n// Header content projection directive\nexport { ChatHeaderContentDirective } from './chat-header-content.directive';\n\n// Drag and drop directive for file uploads\nexport { ChatDropZoneDirective } from './chat-drop-zone.directive';\n\n// Additional directives will be added as they are created:\n// export { ChatFocusTrapDirective } from './chat-focus-trap.directive';\n","/**\n * @fileoverview Error constants and factory functions for ngx-chat.\n * Provides centralized error definitions and utilities for error handling.\n * @module ngx-chat/models/error\n */\n\nimport type { ChatErrorCode, ChatMessageError } from './message.model';\nimport type { ChatErrorRecoveryConfig } from './config.model';\n\n// ============================================================================\n// Error Definition Type\n// ============================================================================\n\n/**\n * Definition of an error type with default message and retryability.\n * Used internally by ERROR_CODES constant.\n */\ninterface ErrorDefinition {\n /** The error code */\n readonly code: ChatErrorCode;\n /** Default human-readable message */\n readonly message: string;\n /** Whether this error type is retryable by default */\n readonly retryable: boolean;\n}\n\n// ============================================================================\n// Error Codes Constant\n// ============================================================================\n\n/**\n * Centralized definition of all error types.\n * Each error has a default message and retryability setting.\n *\n * @example\n * ```typescript\n * const errorDef = ERROR_CODES.NETWORK_ERROR;\n * console.log(errorDef.message); // \"Network connection failed\"\n * console.log(errorDef.retryable); // true\n * ```\n */\nexport const ERROR_CODES: Readonly<Record<ChatErrorCode, ErrorDefinition>> = {\n NETWORK_ERROR: {\n code: 'NETWORK_ERROR',\n message: 'Network connection failed',\n retryable: true,\n },\n TIMEOUT: {\n code: 'TIMEOUT',\n message: 'Request timed out',\n retryable: true,\n },\n SERVER_ERROR: {\n code: 'SERVER_ERROR',\n message: 'Server error occurred',\n retryable: true,\n },\n RATE_LIMITED: {\n code: 'RATE_LIMITED',\n message: 'Too many requests',\n retryable: true,\n },\n INVALID_CONTENT: {\n code: 'INVALID_CONTENT',\n message: 'Message content is invalid',\n retryable: false,\n },\n ATTACHMENT_TOO_LARGE: {\n code: 'ATTACHMENT_TOO_LARGE',\n message: 'File exceeds size limit',\n retryable: false,\n },\n ATTACHMENT_TYPE_NOT_ALLOWED: {\n code: 'ATTACHMENT_TYPE_NOT_ALLOWED',\n message: 'File type is not allowed',\n retryable: false,\n },\n UNAUTHORIZED: {\n code: 'UNAUTHORIZED',\n message: 'Authentication required',\n retryable: false,\n },\n FORBIDDEN: {\n code: 'FORBIDDEN',\n message: 'Access denied',\n retryable: false,\n },\n UNKNOWN: {\n code: 'UNKNOWN',\n message: 'An unexpected error occurred',\n retryable: true,\n },\n} as const;\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Creates a ChatMessageError instance with the given error code.\n * Uses default message from ERROR_CODES if no custom message provided.\n *\n * @param code - The error code to create\n * @param customMessage - Optional custom message to override the default\n * @param retryCount - Optional retry count (defaults to 0)\n * @returns A new ChatMessageError instance\n *\n * @example\n * ```typescript\n * // Basic usage\n * const error = createError('NETWORK_ERROR');\n *\n * // With custom message\n * const error = createError('TIMEOUT', 'Connection timed out after 30s');\n *\n * // With retry count\n * const error = createError('SERVER_ERROR', undefined, 2);\n * ```\n */\nexport function createError(\n code: ChatErrorCode,\n customMessage?: string,\n retryCount: number = 0\n): ChatMessageError {\n const errorDef = ERROR_CODES[code] ?? ERROR_CODES.UNKNOWN;\n\n return {\n code,\n message: customMessage ?? errorDef.message,\n retryable: errorDef.retryable,\n retryCount,\n lastRetryAt: retryCount > 0 ? new Date() : undefined,\n };\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Creates a new error with an incremented retry count.\n * Returns a new ChatMessageError instance (immutable pattern).\n *\n * @param error - The original error to increment\n * @returns A new ChatMessageError with retryCount + 1 and updated lastRetryAt\n *\n * @example\n * ```typescript\n * const original = createError('NETWORK_ERROR');\n * const afterRetry = incrementRetryCount(original);\n * console.log(afterRetry.retryCount); // 1\n * console.log(afterRetry.lastRetryAt); // Current date\n * ```\n */\nexport function incrementRetryCount(error: ChatMessageError): ChatMessageError {\n return {\n ...error,\n retryCount: (error.retryCount ?? 0) + 1,\n lastRetryAt: new Date(),\n };\n}\n\n/**\n * Determines if an error can be retried based on error properties and config.\n *\n * @param error - The error to check\n * @param config - The error recovery configuration\n * @returns true if the error can be retried, false otherwise\n *\n * @example\n * ```typescript\n * const error = createError('NETWORK_ERROR', undefined, 1);\n * const config: ChatErrorRecoveryConfig = { maxRetries: 3, ... };\n *\n * if (canRetry(error, config)) {\n * // Attempt retry\n * }\n * ```\n */\nexport function canRetry(\n error: ChatMessageError,\n config: ChatErrorRecoveryConfig\n): boolean {\n // Non-retryable errors can never be retried\n if (!error.retryable) {\n return false;\n }\n\n // Check if max retries exceeded\n const currentRetries = error.retryCount ?? 0;\n if (currentRetries >= config.maxRetries) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Calculates the delay before the next retry attempt using exponential backoff.\n *\n * @param error - The error with current retry count\n * @param config - The error recovery configuration\n * @returns Delay in milliseconds before next retry\n *\n * @example\n * ```typescript\n * const error = createError('NETWORK_ERROR', undefined, 2);\n * const config: ChatErrorRecoveryConfig = {\n * retryDelay: 1000,\n * exponentialBackoff: true,\n * maxRetryDelay: 30000,\n * ...\n * };\n *\n * const delay = getRetryDelay(error, config);\n * // With exponentialBackoff and 2 retries: 1000 * 2^2 = 4000ms\n * ```\n */\nexport function getRetryDelay(\n error: ChatMessageError,\n config: ChatErrorRecoveryConfig\n): number {\n const attempts = error.retryCount ?? 0;\n\n if (!config.exponentialBackoff) {\n return config.retryDelay;\n }\n\n const delay = config.retryDelay * Math.pow(2, attempts);\n return Math.min(delay, config.maxRetryDelay);\n}\n\n/**\n * Checks if an error code represents a client-side error (non-retryable by nature).\n *\n * @param code - The error code to check\n * @returns true if the error is a client-side error\n *\n * @example\n * ```typescript\n * isClientError('INVALID_CONTENT'); // true\n * isClientError('NETWORK_ERROR'); // false\n * ```\n */\nexport function isClientError(code: ChatErrorCode): boolean {\n const clientErrors: ChatErrorCode[] = [\n 'INVALID_CONTENT',\n 'ATTACHMENT_TOO_LARGE',\n 'ATTACHMENT_TYPE_NOT_ALLOWED',\n ];\n return clientErrors.includes(code);\n}\n\n/**\n * Checks if an error code represents an authentication/authorization error.\n *\n * @param code - The error code to check\n * @returns true if the error is an auth error\n *\n * @example\n * ```typescript\n * isAuthError('UNAUTHORIZED'); // true\n * isAuthError('FORBIDDEN'); // true\n * isAuthError('NETWORK_ERROR'); // false\n * ```\n */\nexport function isAuthError(code: ChatErrorCode): boolean {\n return code === 'UNAUTHORIZED' || code === 'FORBIDDEN';\n}\n\n/**\n * Checks if an error code represents a network-related error.\n *\n * @param code - The error code to check\n * @returns true if the error is network-related\n *\n * @example\n * ```typescript\n * isNetworkError('NETWORK_ERROR'); // true\n * isNetworkError('TIMEOUT'); // true\n * isNetworkError('INVALID_CONTENT'); // false\n * ```\n */\nexport function isNetworkError(code: ChatErrorCode): boolean {\n return code === 'NETWORK_ERROR' || code === 'TIMEOUT';\n}\n","/**\n * @fileoverview Barrel export for all ngx-chat models.\n * @module ngx-chat/models\n */\n\n// Message models\nexport type {\n MessageSender,\n MessageStatus,\n ChatErrorCode,\n ChatMessageError,\n ChatMessage,\n ChatSendEvent,\n PendingAttachmentRef,\n ChatTypingEvent,\n ChatRetryEvent,\n ChatLoadMoreEvent,\n ChatMessageStatusEvent,\n} from './message.model';\n\n// Action models\nexport type {\n MessageActionType,\n ButtonVariant,\n ButtonsLayout,\n ActionOption,\n ActionButton,\n ConfirmAction,\n SelectAction,\n MultiSelectAction,\n ButtonsAction,\n MessageAction,\n ConfirmActionEvent,\n SelectActionEvent,\n MultiSelectActionEvent,\n ButtonsActionEvent,\n MessageActionEvent,\n} from './actions.model';\n\n// Attachment models\nexport type {\n AttachmentType,\n AttachmentUploadStatus,\n MessageAttachment,\n PendingAttachment,\n AttachmentProgressEvent,\n AttachmentCompleteEvent,\n AttachmentErrorEvent,\n AttachmentClickEvent,\n AttachmentEvent,\n} from './attachment.model';\n\n// Configuration models\nexport type {\n DeepPartial,\n ChatBehaviorConfig,\n ChatValidationConfig,\n ChatMarkdownConfig,\n ChatAttachmentConfig,\n ChatVirtualScrollConfig,\n ChatErrorRecoveryConfig,\n ChatKeyboardConfig,\n ChatTheme,\n ChatDirection,\n ChatConfig,\n ChatConfigInput,\n} from './config.model';\n\nexport {\n DEFAULT_BEHAVIOR_CONFIG,\n DEFAULT_VALIDATION_CONFIG,\n DEFAULT_MARKDOWN_CONFIG,\n DEFAULT_ATTACHMENT_CONFIG,\n DEFAULT_VIRTUAL_SCROLL_CONFIG,\n DEFAULT_ERROR_RECOVERY_CONFIG,\n DEFAULT_KEYBOARD_CONFIG,\n DEFAULT_CHAT_CONFIG,\n} from './config.model';\n\n// I18n models\nexport type { ChatI18n } from './i18n.model';\n\nexport { DEFAULT_CHAT_I18N } from './i18n.model';\n\n// Error models\nexport {\n ERROR_CODES,\n createError,\n incrementRetryCount,\n canRetry,\n getRetryDelay,\n isClientError,\n isAuthError,\n isNetworkError,\n} from './error.model';\n","/**\n * @fileoverview Injection token for browser feature detection.\n * Provides runtime capability checks for optional features.\n * @module ngx-chat/tokens/chat-features\n */\n\nimport { InjectionToken, PLATFORM_ID, inject } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\n/**\n * Interface describing detected browser features.\n * All properties are readonly to prevent modification after detection.\n */\nexport interface ChatFeatures {\n /**\n * Whether IntersectionObserver is available.\n * Used for lazy loading and visibility detection.\n */\n readonly intersectionObserver: boolean;\n\n /**\n * Whether ResizeObserver is available.\n * Used for responsive textarea and container sizing.\n */\n readonly resizeObserver: boolean;\n\n /**\n * Whether CSS Container Queries are supported.\n * Used for component-level responsive design.\n */\n readonly containerQueries: boolean;\n\n /**\n * Whether Clipboard API is available.\n * Used for paste functionality.\n */\n readonly clipboardApi: boolean;\n\n /**\n * Whether Web Share API is available.\n * Used for native sharing on mobile devices.\n */\n readonly webShareApi: boolean;\n\n /**\n * Whether the page is running in a browser environment.\n * False during SSR.\n */\n readonly isBrowser: boolean;\n\n /**\n * Whether matchMedia is available for theme detection.\n * Used for auto theme switching.\n */\n readonly matchMedia: boolean;\n\n /**\n * Whether the device supports touch events.\n * Used for touch-specific interactions.\n */\n readonly touchEvents: boolean;\n\n /**\n * Whether the File API is available.\n * Used for file attachments.\n */\n readonly fileApi: boolean;\n\n /**\n * Whether the Blob API is available.\n * Used for file processing.\n */\n readonly blobApi: boolean;\n\n /**\n * Whether URL.createObjectURL is available.\n * Used for file previews.\n */\n readonly objectUrl: boolean;\n\n /**\n * Whether Canvas API is available.\n * Used for image compression and thumbnails.\n */\n readonly canvas: boolean;\n\n /**\n * Whether the user prefers reduced motion.\n * Used to disable animations for accessibility.\n */\n readonly prefersReducedMotion: boolean;\n}\n\n/**\n * Detects browser features at runtime.\n * Returns a ChatFeatures object with all capability flags.\n *\n * @param platformId - The platform identifier from Angular\n * @returns ChatFeatures object with detected capabilities\n */\nfunction detectFeatures(platformId: object): ChatFeatures {\n const isBrowser = isPlatformBrowser(platformId);\n\n if (!isBrowser) {\n // Return all false for SSR\n return {\n intersectionObserver: false,\n resizeObserver: false,\n containerQueries: false,\n clipboardApi: false,\n webShareApi: false,\n isBrowser: false,\n matchMedia: false,\n touchEvents: false,\n fileApi: false,\n blobApi: false,\n objectUrl: false,\n canvas: false,\n prefersReducedMotion: false,\n };\n }\n\n // Detect all features\n const hasMatchMedia = typeof window.matchMedia === 'function';\n\n return {\n intersectionObserver: typeof IntersectionObserver !== 'undefined',\n resizeObserver: typeof ResizeObserver !== 'undefined',\n containerQueries: CSS.supports?.('container-type', 'inline-size') ?? false,\n clipboardApi: typeof navigator.clipboard !== 'undefined',\n webShareApi: typeof navigator.share === 'function',\n isBrowser: true,\n matchMedia: hasMatchMedia,\n touchEvents: 'ontouchstart' in window || navigator.maxTouchPoints > 0,\n fileApi: typeof File !== 'undefined' && typeof FileReader !== 'undefined',\n blobApi: typeof Blob !== 'undefined',\n objectUrl:\n typeof URL !== 'undefined' &&\n typeof URL.createObjectURL === 'function',\n canvas:\n typeof document !== 'undefined' &&\n typeof document.createElement === 'function' &&\n !!document.createElement('canvas').getContext,\n prefersReducedMotion:\n hasMatchMedia &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches,\n };\n}\n\n/**\n * Injection token for browser feature detection.\n *\n * Provides runtime capability checks for optional features.\n * Uses PLATFORM_ID to safely handle SSR environments.\n *\n * @example\n * ```typescript\n * // In a component or service\n * private readonly features = inject(CHAT_FEATURES);\n *\n * // Check capabilities\n * if (this.features.intersectionObserver) {\n * // Use IntersectionObserver\n * }\n *\n * if (this.features.prefersReducedMotion) {\n * // Disable animations\n * }\n * ```\n */\nexport const CHAT_FEATURES = new InjectionToken<ChatFeatures>('CHAT_FEATURES', {\n providedIn: 'root',\n factory: () => detectFeatures(inject(PLATFORM_ID)),\n});\n","/**\n * @fileoverview Barrel export for injection tokens.\n * @module ngx-chat/tokens\n */\n\nexport { CHAT_CONFIG, CHAT_CONFIG_OVERRIDES } from './chat-config.token';\nexport { CHAT_I18N, CHAT_I18N_OVERRIDES } from './chat-i18n.token';\nexport { CHAT_FEATURES, type ChatFeatures } from './chat-features.token';\n","/**\n * ID Generation Utilities\n *\n * Provides unique ID generation for messages, actions, and other entities.\n * IDs are guaranteed unique through combination of timestamp, counter, and random components.\n */\n\n/** Internal counter for uniqueness within same millisecond */\nlet counter = 0;\n\n/** Last timestamp used for ID generation */\nlet lastTimestamp = 0;\n\n/**\n * Generates a unique ID string.\n *\n * Format: `{prefix}-{timestamp}-{counter}-{random}`\n *\n * Uniqueness is guaranteed through:\n * - Timestamp: millisecond precision\n * - Counter: sequential within same millisecond\n * - Random: 4-character alphanumeric for additional entropy\n *\n * @param prefix - Optional prefix for the ID (e.g., 'msg', 'action', 'attachment')\n * @returns A unique ID string\n *\n * @example\n * ```typescript\n * generateId('msg'); // 'msg-1703612345678-0-x7k2'\n * generateId('action'); // 'action-1703612345678-1-p9m4'\n * generateId(); // 'id-1703612345679-0-q3n8'\n * ```\n */\nexport function generateId(prefix: string = 'id'): string {\n const timestamp = Date.now();\n\n if (timestamp === lastTimestamp) {\n counter++;\n } else {\n counter = 0;\n lastTimestamp = timestamp;\n }\n\n const random = Math.random().toString(36).substring(2, 6);\n\n return `${prefix}-${timestamp}-${counter}-${random}`;\n}\n\n/**\n * Resets the internal ID counter.\n *\n * This function is intended for testing purposes only to ensure\n * predictable ID generation in test scenarios.\n *\n * @example\n * ```typescript\n * // In a test file\n * beforeEach(() => {\n * resetIdCounter();\n * });\n * ```\n */\nexport function resetIdCounter(): void {\n counter = 0;\n lastTimestamp = 0;\n}\n","/**\n * Message Utilities\n *\n * Pure utility functions for message creation, updates, and queries.\n * All update functions are immutable - they return new arrays/objects.\n */\n\nimport type {\n ChatMessage,\n ChatMessageError,\n MessageSender,\n MessageStatus,\n} from '../models/message.model';\nimport { generateId } from './id.utils';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for creating a message.\n */\nexport interface CreateMessageOptions {\n /** Custom ID (uses generateId if not provided) */\n readonly id?: string;\n\n /** Custom timestamp (uses current time if not provided) */\n readonly timestamp?: Date;\n\n /** Initial status */\n readonly status?: MessageStatus;\n\n /** Avatar URL */\n readonly avatar?: string;\n\n /** Custom metadata */\n readonly metadata?: Readonly<Record<string, unknown>>;\n\n /** ID of message being replied to */\n readonly replyTo?: string;\n}\n\n/**\n * Options specific to 'other' messages.\n */\nexport interface CreateOtherMessageOptions extends CreateMessageOptions {\n /** Sender display name */\n readonly senderName?: string;\n}\n\n// ============================================================================\n// Creation Functions\n// ============================================================================\n\n/**\n * Creates a message from the current user (self).\n *\n * @param content - The message text content\n * @param options - Optional configuration for the message\n * @returns A new ChatMessage with sender='self'\n *\n * @example\n * ```typescript\n * const message = createSelfMessage('Hello!');\n * // { id: 'msg-...', sender: 'self', content: 'Hello!', status: 'sending', ... }\n *\n * const withOptions = createSelfMessage('Hi', { status: 'sent', avatar: '/me.png' });\n * ```\n */\nexport function createSelfMessage(\n content: string,\n options?: CreateMessageOptions\n): ChatMessage {\n return {\n id: options?.id ?? generateId('msg'),\n sender: 'self',\n content,\n timestamp: options?.timestamp ?? new Date(),\n status: options?.status ?? 'sending',\n avatar: options?.avatar,\n metadata: options?.metadata,\n replyTo: options?.replyTo,\n };\n}\n\n/**\n * Creates a message from another user or AI.\n *\n * @param content - The message text content\n * @param senderName - Optional display name of the sender\n * @param options - Optional configuration for the message\n * @returns A new ChatMessage with sender='other'\n *\n * @example\n * ```typescript\n * const message = createOtherMessage('Hello!', 'Assistant');\n * // { id: 'msg-...', sender: 'other', content: 'Hello!', senderName: 'Assistant', ... }\n *\n * const withOptions = createOtherMessage('Hi', 'Bot', { avatar: '/bot.png' });\n * ```\n */\nexport function createOtherMessage(\n content: string,\n senderName?: string,\n options?: CreateOtherMessageOptions\n): ChatMessage {\n return {\n id: options?.id ?? generateId('msg'),\n sender: 'other',\n content,\n timestamp: options?.timestamp ?? new Date(),\n status: options?.status,\n senderName: senderName ?? options?.senderName,\n avatar: options?.avatar,\n metadata: options?.metadata,\n replyTo: options?.replyTo,\n };\n}\n\n/**\n * Creates a system message (notifications, status updates).\n *\n * @param content - The system message content\n * @param options - Optional configuration for the message\n * @returns A new ChatMessage with sender='system'\n *\n * @example\n * ```typescript\n * const message = createSystemMessage('User joined the chat');\n * // { id: 'msg-...', sender: 'system', content: 'User joined the chat', ... }\n * ```\n */\nexport function createSystemMessage(\n content: string,\n options?: CreateMessageOptions\n): ChatMessage {\n return {\n id: options?.id ?? generateId('msg'),\n sender: 'system',\n content,\n timestamp: options?.timestamp ?? new Date(),\n status: options?.status,\n avatar: options?.avatar,\n metadata: options?.metadata,\n replyTo: options?.replyTo,\n };\n}\n\n// ============================================================================\n// Update Functions (Immutable)\n// ============================================================================\n\n/**\n * Updates the status of a message in the array.\n *\n * @param messages - The array of messages\n * @param messageId - ID of the message to update\n * @param status - The new status\n * @param error - Optional error information (for 'error' status)\n * @returns A new array with the updated message\n *\n * @example\n * ```typescript\n * const updated = updateMessageStatus(messages, 'msg-123', 'sent');\n *\n * const withError = updateMessageStatus(messages, 'msg-123', 'error', {\n * code: 'NETWORK_ERROR',\n * message: 'Connection lost',\n * retryable: true\n * });\n * ```\n */\nexport function updateMessageStatus(\n messages: readonly ChatMessage[],\n messageId: string,\n status: MessageStatus,\n error?: ChatMessageError\n): ChatMessage[] {\n return messages.map((msg) =>\n msg.id === messageId\n ? { ...msg, status, error: status === 'error' ? error : undefined }\n : msg\n );\n}\n\n/**\n * Appends content to an existing message (for streaming responses).\n *\n * @param messages - The array of messages\n * @param messageId - ID of the message to update\n * @param chunk - The content chunk to append\n * @returns A new array with the updated message\n *\n * @example\n * ```typescript\n * // Streaming response\n * let msgs = [createOtherMessage('', 'AI')];\n * msgs = appendMessageContent(msgs, msgs[0].id, 'Hello');\n * msgs = appendMessageContent(msgs, msgs[0].id, ' world!');\n * // Message content is now 'Hello world!'\n * ```\n */\nexport function appendMessageContent(\n messages: readonly ChatMessage[],\n messageId: string,\n chunk: string\n): ChatMessage[] {\n return messages.map((msg) =>\n msg.id === messageId ? { ...msg, content: msg.content + chunk } : msg\n );\n}\n\n/**\n * Replaces the content of a message.\n *\n * @param messages - The array of messages\n * @param messageId - ID of the message to update\n * @param content - The new content\n * @returns A new array with the updated message\n *\n * @example\n * ```typescript\n * const updated = updateMessageContent(messages, 'msg-123', 'Edited message');\n * ```\n */\nexport function updateMessageContent(\n messages: readonly ChatMessage[],\n messageId: string,\n content: string\n): ChatMessage[] {\n return messages.map((msg) =>\n msg.id === messageId\n ? { ...msg, content, edited: true, editedAt: new Date() }\n : msg\n );\n}\n\n/**\n * Removes a message from the array.\n *\n * @param messages - The array of messages\n * @param messageId - ID of the message to remove\n * @returns A new array without the specified message\n *\n * @example\n * ```typescript\n * const updated = removeMessage(messages, 'msg-123');\n * ```\n */\nexport function removeMessage(\n messages: readonly ChatMessage[],\n messageId: string\n): ChatMessage[] {\n return messages.filter((msg) => msg.id !== messageId);\n}\n\n// ============================================================================\n// Query Functions\n// ============================================================================\n\n/**\n * Finds a message by its ID.\n *\n * @param messages - The array of messages to search\n * @param messageId - ID of the message to find\n * @returns The message if found, undefined otherwise\n *\n * @example\n * ```typescript\n * const message = findMessage(messages, 'msg-123');\n * if (message) {\n * console.log(message.content);\n * }\n * ```\n */\nexport function findMessage(\n messages: readonly ChatMessage[],\n messageId: string\n): ChatMessage | undefined {\n return messages.find((msg) => msg.id === messageId);\n}\n\n/**\n * Gets the last message in the array.\n *\n * @param messages - The array of messages\n * @returns The last message, or undefined if array is empty\n *\n * @example\n * ```typescript\n * const lastMsg = getLastMessage(messages);\n * if (lastMsg) {\n * console.log('Last message:', lastMsg.content);\n * }\n * ```\n */\nexport function getLastMessage(\n messages: readonly ChatMessage[]\n): ChatMessage | undefined {\n return messages.length > 0 ? messages[messages.length - 1] : undefined;\n}\n\n/**\n * Filters messages by status.\n *\n * @param messages - The array of messages to filter\n * @param status - The status to filter by\n * @returns Array of messages with the specified status\n *\n * @example\n * ```typescript\n * const pendingMessages = getMessagesByStatus(messages, 'pending');\n * const sentMessages = getMessagesByStatus(messages, 'sent');\n * ```\n */\nexport function getMessagesByStatus(\n messages: readonly ChatMessage[],\n status: MessageStatus\n): ChatMessage[] {\n return messages.filter((msg) => msg.status === status);\n}\n\n/**\n * Gets all messages with error status.\n *\n * @param messages - The array of messages to filter\n * @returns Array of messages with status='error'\n *\n * @example\n * ```typescript\n * const errors = getErrorMessages(messages);\n * errors.forEach(msg => console.log('Failed:', msg.error?.message));\n * ```\n */\nexport function getErrorMessages(\n messages: readonly ChatMessage[]\n): ChatMessage[] {\n return messages.filter((msg) => msg.status === 'error');\n}\n\n/**\n * Gets all messages that can be retried.\n *\n * A message is retryable if:\n * - Its status is 'error'\n * - Its error has retryable=true\n *\n * @param messages - The array of messages to filter\n * @returns Array of messages that can be retried\n *\n * @example\n * ```typescript\n * const retryable = getRetryableMessages(messages);\n * retryable.forEach(msg => retryMessage(msg.id));\n * ```\n */\nexport function getRetryableMessages(\n messages: readonly ChatMessage[]\n): ChatMessage[] {\n return messages.filter(\n (msg) => msg.status === 'error' && msg.error?.retryable === true\n );\n}\n","/**\n * Action Utilities\n *\n * Pure utility functions for action creation, updates, and queries.\n * All update functions are immutable - they return new arrays/objects.\n */\n\nimport type {\n ActionButton,\n ActionOption,\n ButtonsAction,\n ButtonsLayout,\n ButtonVariant,\n ConfirmAction,\n MessageAction,\n MessageActionEvent,\n MultiSelectAction,\n SelectAction,\n} from '../models/actions.model';\nimport type { ChatMessage } from '../models/message.model';\nimport { generateId } from './id.utils';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Options for creating a confirm action.\n */\nexport interface CreateConfirmActionOptions {\n /** Custom ID (uses generateId if not provided) */\n readonly id?: string;\n\n /** Text for the confirm button (default: 'Confirm') */\n readonly confirmText?: string;\n\n /** Text for the cancel button (default: 'Cancel') */\n readonly cancelText?: string;\n\n /** Styling variant for the confirm button */\n readonly confirmVariant?: ButtonVariant;\n\n /** Styling variant for the cancel button */\n readonly cancelVariant?: ButtonVariant;\n\n /** Whether this action is disabled */\n readonly disabled?: boolean;\n}\n\n/**\n * Options for creating a select action.\n */\nexport interface CreateSelectActionOptions {\n /** Custom ID (uses generateId if not provided) */\n readonly id?: string;\n\n /** Label text displayed above the selection */\n readonly label?: string;\n\n /** Placeholder text when no option is selected */\n readonly placeholder?: string;\n\n /** Whether to show a search/filter input */\n readonly searchable?: boolean;\n\n /** Whether this action is disabled */\n readonly disabled?: boolean;\n}\n\n/**\n * Options for creating a multi-select action.\n */\nexport interface CreateMultiSelectActionOptions {\n /** Custom ID (uses generateId if not provided) */\n readonly id?: string;\n\n /** Label text displayed above the selection */\n readonly label?: string;\n\n /** Minimum number of selections required */\n readonly minSelect?: number;\n\n /** Maximum number of selections allowed */\n readonly maxSelect?: number;\n\n /** Text for the submit button (default: 'Submit') */\n readonly submitText?: string;\n\n /** Whether this action is disabled */\n readonly disabled?: boolean;\n}\n\n/**\n * Options for creating a buttons action.\n */\nexport interface CreateButtonsActionOptions {\n /** Custom ID (uses generateId if not provided) */\n readonly id?: string;\n\n /** How to arrange the buttons */\n readonly layout?: ButtonsLayout;\n\n /** Number of columns when layout is 'grid' */\n readonly columns?: number;\n\n /** Whether this action is disabled */\n readonly disabled?: boolean;\n}\n\n// ============================================================================\n// Creation Functions\n// ============================================================================\n\n/**\n * Creates a confirm/cancel action.\n *\n * @param options - Optional configuration for the action\n * @returns A new ConfirmAction\n *\n * @example\n * ```typescript\n * // Default confirm/cancel\n * const action = createConfirmAction();\n *\n * // Custom text and styling\n * const deleteAction = createConfirmAction({\n * confirmText: 'Delete',\n * cancelText: 'Keep',\n * confirmVariant: 'danger'\n * });\n * ```\n */\nexport function createConfirmAction(\n options?: CreateConfirmActionOptions\n): ConfirmAction {\n return {\n type: 'confirm',\n id: options?.id ?? generateId('action'),\n confirmText: options?.confirmText,\n cancelText: options?.cancelText,\n confirmVariant: options?.confirmVariant,\n cancelVariant: options?.cancelVariant,\n disabled: options?.disabled,\n };\n}\n\n/**\n * Creates a single-select action from options.\n *\n * @param options - Array of selectable options\n * @param config - Optional configuration for the action\n * @returns A new SelectAction\n *\n * @example\n * ```typescript\n * const action = createSelectAction(\n * [\n * { id: 'low', label: 'Low' },\n * { id: 'medium', label: 'Medium' },\n * { id: 'high', label: 'High' }\n * ],\n * { label: 'Select priority:', searchable: true }\n * );\n * ```\n */\nexport function createSelectAction(\n options: readonly ActionOption[],\n config?: CreateSelectActionOptions\n): SelectAction {\n return {\n type: 'select',\n id: config?.id ?? generateId('action'),\n options,\n label: config?.label,\n placeholder: config?.placeholder,\n searchable: config?.searchable,\n disabled: config?.disabled,\n };\n}\n\n/**\n * Creates a multi-select action from options.\n *\n * @param options - Array of selectable options\n * @param config - Optional configuration for the action\n * @returns A new MultiSelectAction\n *\n * @example\n * ```typescript\n * const action = createMultiSelectAction(\n * [\n * { id: 'dark-mode', label: 'Dark Mode' },\n * { id: 'notifications', label: 'Notifications' },\n * { id: 'sync', label: 'Cloud Sync' }\n * ],\n * { label: 'Select features:', minSelect: 1, maxSelect: 2 }\n * );\n * ```\n */\nexport function createMultiSelectAction(\n options: readonly ActionOption[],\n config?: CreateMultiSelectActionOptions\n): MultiSelectAction {\n return {\n type: 'multi-select',\n id: config?.id ?? generateId('action'),\n options,\n label: config?.label,\n minSelect: config?.minSelect,\n maxSelect: config?.maxSelect,\n submitText: config?.submitText,\n disabled: config?.disabled,\n };\n}\n\n/**\n * Creates a buttons action.\n *\n * @param buttons - Array of button definitions\n * @param config - Optional configuration for the action\n * @returns A new ButtonsAction\n *\n * @example\n * ```typescript\n * const action = createButtonsAction(\n * [\n * { id: 'yes', label: 'Yes', variant: 'primary' },\n * { id: 'no', label: 'No', variant: 'secondary' },\n * { id: 'maybe', label: 'Maybe', variant: 'ghost' }\n * ],\n * { layout: 'horizontal' }\n * );\n * ```\n */\nexport function createButtonsAction(\n buttons: readonly ActionButton[],\n config?: CreateButtonsActionOptions\n): ButtonsAction {\n return {\n type: 'buttons',\n id: config?.id ?? generateId('action'),\n buttons,\n layout: config?.layout,\n columns: config?.columns,\n disabled: config?.disabled,\n };\n}\n\n// ============================================================================\n// Update Functions (Immutable)\n// ============================================================================\n\n/**\n * Updates an action with the user's response.\n *\n * This function finds the message containing the action and updates\n * the action with the response from the event. All updates are immutable.\n *\n * @param messages - The array of messages\n * @param event - The action event containing the response\n * @returns A new array with the updated message/action\n *\n * @example\n * ```typescript\n * const event: ConfirmActionEvent = {\n * type: 'confirm',\n * messageId: 'msg-123',\n * actionId: 'action-456',\n * response: true\n * };\n *\n * const updated = updateActionResponse(messages, event);\n * ```\n */\nexport function updateActionResponse(\n messages: readonly ChatMessage[],\n event: MessageActionEvent\n): ChatMessage[] {\n return messages.map((msg) => {\n if (msg.id !== event.messageId || !msg.actions) {\n return msg;\n }\n\n const updatedActions = msg.actions.map((action) => {\n if (action.id !== event.actionId) {\n return action;\n }\n\n // Update the action based on its type\n switch (event.type) {\n case 'confirm':\n return {\n ...action,\n responded: true,\n response: event.response,\n } as ConfirmAction;\n\n case 'select':\n return {\n ...action,\n responded: true,\n response: event.response,\n } as SelectAction;\n\n case 'multi-select':\n return {\n ...action,\n responded: true,\n response: event.response,\n } as MultiSelectAction;\n\n case 'buttons':\n return {\n ...action,\n responded: true,\n response: event.response,\n } as ButtonsAction;\n\n default:\n return action;\n }\n });\n\n return {\n ...msg,\n actions: updatedActions,\n };\n });\n}\n\n/**\n * Disables all actions on a specific message.\n *\n * Useful when you want to prevent further interaction with actions\n * after a certain event (e.g., message recalled, timeout, etc.)\n *\n * @param messages - The array of messages\n * @param messageId - ID of the message whose actions should be disabled\n * @returns A new array with the updated message\n *\n * @example\n * ```typescript\n * // Disable all actions after timeout\n * const updated = disableAllActions(messages, 'msg-123');\n * ```\n */\nexport function disableAllActions(\n messages: readonly ChatMessage[],\n messageId: string\n): ChatMessage[] {\n return messages.map((msg) => {\n if (msg.id !== messageId || !msg.actions) {\n return msg;\n }\n\n const updatedActions = msg.actions.map((action) => ({\n ...action,\n disabled: true,\n }));\n\n return {\n ...msg,\n actions: updatedActions as readonly MessageAction[],\n };\n });\n}\n\n// ============================================================================\n// Query Functions\n// ============================================================================\n\n/**\n * Checks if all actions on a message have been responded to.\n *\n * @param message - The message to check\n * @returns true if all actions have responses, false otherwise\n *\n * @example\n * ```typescript\n * if (allActionsResponded(message)) {\n * console.log('User has completed all actions');\n * }\n * ```\n */\nexport function allActionsResponded(message: ChatMessage): boolean {\n if (!message.actions || message.actions.length === 0) {\n return true;\n }\n\n return message.actions.every((action) => action.responded === true);\n}\n\n/**\n * Gets all actions that haven't been responded to yet.\n *\n * @param message - The message to check\n * @returns Array of actions without responses\n *\n * @example\n * ```typescript\n * const pending = getPendingActions(message);\n * console.log(`${pending.length} actions still waiting for response`);\n * ```\n */\nexport function getPendingActions(message: ChatMessage): MessageAction[] {\n if (!message.actions) {\n return [];\n }\n\n return message.actions.filter(\n (action) => action.responded !== true\n ) as MessageAction[];\n}\n\n/**\n * Finds a specific action by its ID within a message.\n *\n * @param message - The message to search\n * @param actionId - ID of the action to find\n * @returns The action if found, undefined otherwise\n *\n * @example\n * ```typescript\n * const action = getActionById(message, 'action-123');\n * if (action) {\n * console.log('Found action:', action.type);\n * }\n * ```\n */\nexport function getActionById(\n message: ChatMessage,\n actionId: string\n): MessageAction | undefined {\n if (!message.actions) {\n return undefined;\n }\n\n return message.actions.find((action) => action.id === actionId);\n}\n","/**\n * Utility Functions\n *\n * Pure utility functions for ID generation, message operations,\n * action handling, validation, and grouping.\n */\n\n// ID utilities\nexport { generateId, resetIdCounter } from './id.utils';\n\n// Message utilities - types\nexport type {\n CreateMessageOptions,\n CreateOtherMessageOptions,\n} from './message.utils';\n\n// Message utilities - functions\nexport {\n // Creation functions\n createSelfMessage,\n createOtherMessage,\n createSystemMessage,\n // Update functions\n updateMessageStatus,\n appendMessageContent,\n updateMessageContent,\n removeMessage,\n // Query functions\n findMessage,\n getLastMessage,\n getMessagesByStatus,\n getErrorMessages,\n getRetryableMessages,\n} from './message.utils';\n\n// Action utilities - types\nexport type {\n CreateConfirmActionOptions,\n CreateSelectActionOptions,\n CreateMultiSelectActionOptions,\n CreateButtonsActionOptions,\n} from './action.utils';\n\n// Action utilities - functions\nexport {\n // Creation functions\n createConfirmAction,\n createSelectAction,\n createMultiSelectAction,\n createButtonsAction,\n // Update functions\n updateActionResponse,\n disableAllActions,\n // Query functions\n allActionsResponded,\n getPendingActions,\n getActionById,\n} from './action.utils';\n\n// Validation utilities - types\nexport type { ValidationResult } from './validation.utils';\n\n// Validation utilities - functions\nexport {\n validateMessage,\n sanitizeContent,\n stripInvisibleChars,\n breakLongWords,\n isSafeUrl,\n} from './validation.utils';\n\n// Grouping utilities - constants\nexport { DEFAULT_GROUPING_THRESHOLD_MS } from './grouping.utils';\n\n// Grouping utilities - types\nexport type { MessageGroup } from './grouping.utils';\n\n// Grouping utilities - functions\nexport {\n isUngroupable,\n shouldGroupMessages,\n groupMessages,\n} from './grouping.utils';\n","/**\n * @fileoverview Error recovery service for ngx-chat.\n * Manages offline message queuing and retry delay calculations.\n * @module ngx-chat/services/chat-error-recovery\n */\n\nimport {\n Injectable,\n DestroyRef,\n inject,\n signal,\n computed,\n} from '@angular/core';\nimport type { ChatMessage, ChatMessageError } from '../models/message.model';\nimport { ChatConfigService } from './chat-config.service';\n\n// ============================================================================\n// Interfaces\n// ============================================================================\n\n/**\n * Represents a message that has been queued for later delivery.\n * Used when the user is offline or when retrying failed messages.\n */\nexport interface QueuedMessage {\n /** The original message to be sent */\n readonly message: ChatMessage;\n\n /** When the message was added to the queue */\n readonly queuedAt: Date;\n\n /** Number of retry attempts for this message */\n readonly retryCount: number;\n}\n\n// ============================================================================\n// Service\n// ============================================================================\n\n/**\n * Service for managing error recovery, including offline queuing and retry logic.\n *\n * Provides:\n * - Offline message queue with size limits\n * - Exponential backoff retry delay calculation\n * - Online/offline state detection\n * - Queue management (enqueue, dequeue, flush)\n *\n * @example\n * ```typescript\n * @Component({...})\n * export class ChatComponent {\n * private readonly errorRecovery = inject(ChatErrorRecoveryService);\n *\n * // Track online state\n * readonly isOnline = this.errorRecovery.isOnline;\n * readonly queuedCount = this.errorRecovery.queuedCount;\n *\n * async onSend(content: string) {\n * try {\n * await this.api.send(content);\n * } catch (error) {\n * const chatError = this.mapError(error);\n *\n * if (!this.isOnline()) {\n * this.errorRecovery.enqueue(message);\n * } else if (this.errorRecovery.shouldRetry(chatError)) {\n * const delay = this.errorRecovery.getRetryDelay(chatError.retryCount ?? 0);\n * setTimeout(() => this.retry(message), delay);\n * }\n * }\n * }\n *\n * // When coming back online\n * onOnline() {\n * const queued = this.errorRecovery.flushQueue();\n * queued.forEach(q => this.retry(q.message));\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ChatErrorRecoveryService {\n private readonly configService = inject(ChatConfigService);\n private readonly destroyRef = inject(DestroyRef);\n\n // ============================================================================\n // State\n // ============================================================================\n\n /**\n * Internal queue of messages waiting to be sent.\n * @internal\n */\n private readonly queue = signal<QueuedMessage[]>([]);\n\n /**\n * Number of messages currently in the queue.\n * Reactive signal that updates when queue changes.\n */\n readonly queuedCount = computed(() => this.queue().length);\n\n /**\n * Whether the browser is currently online.\n * Updates automatically when online/offline events fire.\n */\n readonly isOnline = signal(this.getNavigatorOnline());\n\n // ============================================================================\n // Event Listeners\n // ============================================================================\n\n /**\n * Bound event handler references for cleanup.\n * @internal\n */\n private readonly handleOnline = () => this.isOnline.set(true);\n private readonly handleOffline = () => this.isOnline.set(false);\n\n constructor() {\n this.setupEventListeners();\n }\n\n /**\n * Sets up online/offline event listeners and registers cleanup.\n * @internal\n */\n private setupEventListeners(): void {\n // Only set up listeners if window is available (browser environment)\n if (typeof window !== 'undefined') {\n window.addEventListener('online', this.handleOnline);\n window.addEventListener('offline', this.handleOffline);\n\n // Clean up listeners when service is destroyed\n this.destroyRef.onDestroy(() => {\n window.removeEventListener('online', this.handleOnline);\n window.removeEventListener('offline', this.handleOffline);\n });\n }\n }\n\n /**\n * Gets navigator.onLine value safely (handles SSR).\n * @internal\n */\n private getNavigatorOnline(): boolean {\n if (typeof navigator !== 'undefined') {\n return navigator.onLine;\n }\n // Assume online in SSR context\n return true;\n }\n\n // ============================================================================\n // Queue Management\n // ============================================================================\n\n /**\n * Adds a message to the offline queue.\n *\n * If the queue exceeds `maxQueueSize`, the oldest messages are removed\n * to make room for the new message.\n *\n * @param message - The message to queue\n * @param retryCount - Current retry count for this message (default 0)\n *\n * @example\n * ```typescript\n * // Queue a message when offline\n * if (!errorRecovery.isOnline()) {\n * errorRecovery.enqueue(failedMessage);\n * }\n *\n * // Queue with existing retry count\n * errorRecovery.enqueue(message, message.error?.retryCount ?? 0);\n * ```\n */\n enqueue(message: ChatMessage, retryCount: number = 0): void {\n const config = this.configService.getConfig().errorRecovery;\n\n if (!config.offlineQueue) {\n return; // Offline queue is disabled\n }\n\n const queuedMessage: QueuedMessage = {\n message,\n queuedAt: new Date(),\n retryCount,\n };\n\n this.queue.update((current) => {\n // Check if message already exists in queue (by ID)\n const existingIndex = current.findIndex(\n (q) => q.message.id === message.id\n );\n\n if (existingIndex >= 0) {\n // Update existing entry with new retry count\n return current.map((q, i) =>\n i === existingIndex ? queuedMessage : q\n );\n }\n\n // Add new message, enforcing size limit\n let newQueue = [...current, queuedMessage];\n\n // Remove oldest messages if over limit\n if (newQueue.length > config.maxQueueSize) {\n const removeCount = newQueue.length - config.maxQueueSize;\n newQueue = newQueue.slice(removeCount);\n }\n\n return newQueue;\n });\n }\n\n /**\n * Removes a specific message from the queue by ID.\n *\n * @param messageId - The ID of the message to remove\n * @returns true if the message was found and removed, false otherwise\n *\n * @example\n * ```typescript\n * // Remove a message after successful send\n * const wasRemoved = errorRecovery.dequeue(messageId);\n * if (wasRemoved) {\n * console.log('Message removed from queue');\n * }\n * ```\n */\n dequeue(messageId: string): boolean {\n let found = false;\n\n this.queue.update((current) => {\n const index = current.findIndex((q) => q.message.id === messageId);\n\n if (index >= 0) {\n found = true;\n return [...current.slice(0, index), ...current.slice(index + 1)];\n }\n\n return current;\n });\n\n return found;\n }\n\n /**\n * Returns all queued messages and clears the queue.\n *\n * Use this when coming back online to retrieve all pending messages\n * for retry. The queue is cleared immediately.\n *\n * @returns Array of queued messages, empty if none\n *\n * @example\n * ```typescript\n * // When online event fires\n * window.addEventListener('online', () => {\n * const queued = errorRecovery.flushQueue();\n * for (const item of queued) {\n * this.retrySend(item.message, item.retryCount);\n * }\n * });\n * ```\n */\n flushQueue(): QueuedMessage[] {\n const current = this.queue();\n this.queue.set([]);\n return current;\n }\n\n /**\n * Returns a read-only view of the current queue.\n *\n * Does not modify the queue. Use this to display pending messages\n * or check queue contents without removing them.\n *\n * @returns Read-only array of queued messages\n *\n * @example\n * ```typescript\n * const pending = errorRecovery.getQueue();\n * console.log(`${pending.length} messages waiting to be sent`);\n * ```\n */\n getQueue(): readonly QueuedMessage[] {\n return this.queue();\n }\n\n /**\n * Clears all messages from the queue without returning them.\n *\n * Use this to discard all pending messages, for example when\n * the user logs out or explicitly cancels pending sends.\n *\n * @example\n * ```typescript\n * // On logout, discard pending messages\n * errorRecovery.clearQueue();\n * ```\n */\n clearQueue(): void {\n this.queue.set([]);\n }\n\n // ============================================================================\n // Retry Logic\n // ============================================================================\n\n /**\n * Calculates the delay before the next retry attempt.\n *\n * When exponential backoff is enabled, the delay doubles with each attempt:\n * - Attempt 0: baseDelay\n * - Attempt 1: baseDelay * 2\n * - Attempt 2: baseDelay * 4\n * - etc.\n *\n * The delay is capped at `maxRetryDelay` from configuration.\n *\n * @param attempts - Number of previous retry attempts (0-based)\n * @returns Delay in milliseconds before next retry\n *\n * @example\n * ```typescript\n * // With default config (retryDelay=1000, exponentialBackoff=true)\n * errorRecovery.getRetryDelay(0); // 1000ms\n * errorRecovery.getRetryDelay(1); // 2000ms\n * errorRecovery.getRetryDelay(2); // 4000ms\n * errorRecovery.getRetryDelay(5); // 30000ms (capped at maxRetryDelay)\n * ```\n */\n getRetryDelay(attempts: number): number {\n const config = this.configService.getConfig().errorRecovery;\n\n if (!config.exponentialBackoff) {\n return config.retryDelay;\n }\n\n const delay = config.retryDelay * Math.pow(2, attempts);\n return Math.min(delay, config.maxRetryDelay);\n }\n\n /**\n * Determines if an error can be retried based on error properties and configuration.\n *\n * Returns false if:\n * - The error is not marked as retryable\n * - Auto-retry is disabled in configuration\n * - Maximum retry attempts have been reached\n *\n * @param error - The error to evaluate\n * @returns true if the error can be retried, false otherwise\n *\n * @example\n * ```typescript\n * const error = message.error;\n * if (error && errorRecovery.shouldRetry(error)) {\n * const delay = errorRecovery.getRetryDelay(error.retryCount ?? 0);\n * setTimeout(() => this.retry(message), delay);\n * } else {\n * // Show permanent error state\n * this.showError(message);\n * }\n * ```\n */\n shouldRetry(error: ChatMessageError): boolean {\n const config = this.configService.getConfig().errorRecovery;\n\n // Auto-retry must be enabled\n if (!config.autoRetry) {\n return false;\n }\n\n // Error must be marked as retryable\n if (!error.retryable) {\n return false;\n }\n\n // Check if max retries exceeded\n const currentRetries = error.retryCount ?? 0;\n if (currentRetries >= config.maxRetries) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Returns the maximum number of retry attempts from configuration.\n *\n * @returns Maximum retry attempts\n *\n * @example\n * ```typescript\n * const maxRetries = errorRecovery.getMaxRetries();\n * if (currentAttempt >= maxRetries) {\n * // Give up and show error\n * }\n * ```\n */\n getMaxRetries(): number {\n return this.configService.getConfig().errorRecovery.maxRetries;\n }\n\n /**\n * Checks if offline queuing is enabled in configuration.\n *\n * @returns true if offline queue is enabled\n *\n * @example\n * ```typescript\n * if (errorRecovery.isOfflineQueueEnabled()) {\n * // Show queue status in UI\n * }\n * ```\n */\n isOfflineQueueEnabled(): boolean {\n return this.configService.getConfig().errorRecovery.offlineQueue;\n }\n}\n","/**\n * @fileoverview Attachment handling service for ngx-chat.\n * Provides file validation, preview management, and image processing utilities.\n * @module ngx-chat/services/chat-attachment\n */\n\nimport { Injectable, inject } from '@angular/core';\nimport type { AttachmentType } from '../models/attachment.model';\nimport { ChatConfigService } from './chat-config.service';\n\n// ============================================================================\n// Interfaces\n// ============================================================================\n\n/**\n * Result of file validation.\n */\nexport interface FileValidationResult {\n /** Whether the file is valid for upload */\n readonly valid: boolean;\n\n /** Error message if validation failed */\n readonly error?: string;\n}\n\n/**\n * Dimensions for images and videos.\n */\nexport interface Dimensions {\n readonly width: number;\n readonly height: number;\n}\n\n// ============================================================================\n// Service\n// ============================================================================\n\n/**\n * Service for handling file attachments in the chat component.\n *\n * Provides:\n * - File validation against size and MIME type restrictions\n * - Preview URL creation and cleanup for images/videos\n * - Attachment type detection from MIME types\n * - Image compression using canvas API\n * - Thumbnail generation\n *\n * @example\n * ```typescript\n * @Component({...})\n * export class UploadComponent {\n * private readonly attachmentService = inject(ChatAttachmentService);\n *\n * async onFileSelected(file: File) {\n * // Validate the file\n * const validation = this.attachmentService.validateFile(file);\n * if (!validation.valid) {\n * this.showError(validation.error);\n * return;\n * }\n *\n * // Create preview for display\n * const previewUrl = this.attachmentService.createPreview(file);\n *\n * // Compress if it's an image\n * const type = this.attachmentService.getAttachmentType(file.type);\n * let uploadFile = file;\n * if (type === 'image') {\n * uploadFile = await this.attachmentService.compressImage(file);\n * }\n *\n * // Upload file...\n *\n * // Cleanup preview when done\n * if (previewUrl) {\n * this.attachmentService.revokePreview(previewUrl);\n * }\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ChatAttachmentService {\n private readonly configService = inject(ChatConfigService);\n\n // ============================================================================\n // Validation\n // ============================================================================\n\n /**\n * Validates a file against the configured restrictions.\n *\n * Checks:\n * - File size against `maxFileSize`\n * - MIME type against `blockedMimeTypes` (blocked first)\n * - MIME type against `allowedMimeTypes` (if not empty)\n *\n * @param file - The file to validate\n * @returns Validation result with error message if invalid\n *\n * @example\n * ```typescript\n * const result = attachmentService.validateFile(file);\n * if (!result.valid) {\n * console.error(result.error); // e.g., \"File size exceeds 10 MB limit\"\n * }\n * ```\n */\n validateFile(file: File): FileValidationResult {\n const config = this.configService.getConfig().attachments;\n\n // Check if attachments are enabled\n if (!config.enabled) {\n return { valid: false, error: 'Attachments are disabled' };\n }\n\n // Check file size\n if (file.size > config.maxFileSize) {\n const maxSizeFormatted = this.formatFileSize(config.maxFileSize);\n return {\n valid: false,\n error: `File size exceeds ${maxSizeFormatted} limit`,\n };\n }\n\n // Check blocked MIME types (takes precedence)\n if (config.blockedMimeTypes.includes(file.type)) {\n return { valid: false, error: 'File type is not allowed' };\n }\n\n // Check allowed MIME types (if specified)\n if (\n config.allowedMimeTypes.length > 0 &&\n !this.isMimeTypeAllowed(file.type, config.allowedMimeTypes)\n ) {\n return { valid: false, error: 'File type is not allowed' };\n }\n\n return { valid: true };\n }\n\n /**\n * Checks if a MIME type matches any of the allowed patterns.\n * Supports wildcards like 'image/*'.\n *\n * @param mimeType - The MIME type to check\n * @param allowedTypes - Array of allowed MIME types or patterns\n * @returns true if the MIME type is allowed\n */\n private isMimeTypeAllowed(\n mimeType: string,\n allowedTypes: readonly string[]\n ): boolean {\n return allowedTypes.some((allowed) => {\n if (allowed.endsWith('/*')) {\n // Wildcard pattern (e.g., 'image/*')\n const prefix = allowed.slice(0, -1); // Remove '*'\n return mimeType.startsWith(prefix);\n }\n return mimeType === allowed;\n });\n }\n\n // ============================================================================\n // Preview Management\n // ============================================================================\n\n /**\n * Creates a preview URL for a file using `URL.createObjectURL`.\n *\n * Only creates previews for images and videos. Other file types return null.\n * Remember to call `revokePreview()` when the preview is no longer needed\n * to free memory.\n *\n * @param file - The file to create a preview for\n * @returns Object URL for the file, or null if not previewable\n *\n * @example\n * ```typescript\n * const url = attachmentService.createPreview(file);\n * if (url) {\n * imageElement.src = url;\n * // Later: attachmentService.revokePreview(url);\n * }\n * ```\n */\n createPreview(file: File): string | null {\n const type = this.getAttachmentType(file.type);\n\n if (type === 'image' || type === 'video') {\n return URL.createObjectURL(file);\n }\n\n return null;\n }\n\n /**\n * Revokes a preview URL created by `createPreview()`.\n *\n * This releases the memory associated with the object URL.\n * Always call this when the preview is no longer needed.\n *\n * @param url - The object URL to revoke\n *\n * @example\n * ```typescript\n * // When component is destroyed or preview is replaced\n * attachmentService.revokePreview(previewUrl);\n * ```\n */\n revokePreview(url: string): void {\n URL.revokeObjectURL(url);\n }\n\n /**\n * Determines the attachment type from a MIME type.\n *\n * @param mimeType - The MIME type to categorize\n * @returns The attachment type: 'image', 'video', 'audio', or 'file'\n *\n * @example\n * ```typescript\n * attachmentService.getAttachmentType('image/png'); // 'image'\n * attachmentService.getAttachmentType('video/mp4'); // 'video'\n * attachmentService.getAttachmentType('audio/mpeg'); // 'audio'\n * attachmentService.getAttachmentType('application/pdf'); // 'file'\n * ```\n */\n getAttachmentType(mimeType: string): AttachmentType {\n if (mimeType.startsWith('image/')) {\n return 'image';\n }\n if (mimeType.startsWith('video/')) {\n return 'video';\n }\n if (mimeType.startsWith('audio/')) {\n return 'audio';\n }\n return 'file';\n }\n\n // ============================================================================\n // Image Processing\n // ============================================================================\n\n /**\n * Compresses an image file using the canvas API.\n *\n * The image is resized if it exceeds `maxImageDimensions` from configuration.\n * Compression quality is controlled by `imageCompressionQuality`.\n *\n * If compression is disabled in config or the file is not an image,\n * the original file is returned.\n *\n * @param file - The image file to compress\n * @returns Compressed file, or original if compression not applicable\n *\n * @example\n * ```typescript\n * const compressedFile = await attachmentService.compressImage(largeImage);\n * console.log(`Reduced from ${largeImage.size} to ${compressedFile.size}`);\n * ```\n */\n async compressImage(file: File): Promise<File> {\n const config = this.configService.getConfig().attachments;\n\n // Check if compression is enabled\n if (!config.imageCompression) {\n return file;\n }\n\n // Only compress images\n if (!file.type.startsWith('image/')) {\n return file;\n }\n\n // Skip GIFs (animation) and SVGs (vector)\n if (file.type === 'image/gif' || file.type === 'image/svg+xml') {\n return file;\n }\n\n try {\n // Load image\n const imageBitmap = await this.loadImage(file);\n\n // Calculate new dimensions\n const targetDimensions = this.calculateDimensions(\n imageBitmap.width,\n imageBitmap.height,\n config.maxImageDimensions.width,\n config.maxImageDimensions.height\n );\n\n // If no resize needed and file is already small, return original\n if (\n targetDimensions.width === imageBitmap.width &&\n targetDimensions.height === imageBitmap.height &&\n file.size < config.maxFileSize / 2\n ) {\n return file;\n }\n\n // Create canvas and draw resized image\n const canvas = document.createElement('canvas');\n canvas.width = targetDimensions.width;\n canvas.height = targetDimensions.height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return file;\n }\n\n ctx.drawImage(\n imageBitmap,\n 0,\n 0,\n targetDimensions.width,\n targetDimensions.height\n );\n\n // Convert to blob\n const blob = await this.canvasToBlob(\n canvas,\n 'image/jpeg',\n config.imageCompressionQuality\n );\n\n // Create new file with compressed data\n return new File([blob], file.name.replace(/\\.[^.]+$/, '.jpg'), {\n type: 'image/jpeg',\n lastModified: Date.now(),\n });\n } catch {\n // On error, return original file\n return file;\n }\n }\n\n /**\n * Generates a thumbnail data URL for an image or video file.\n *\n * The thumbnail respects `thumbnailSize` from configuration.\n * Returns null for non-visual file types or on error.\n *\n * @param file - The file to generate a thumbnail for\n * @returns Data URL of the thumbnail, or null if not possible\n *\n * @example\n * ```typescript\n * const thumbnail = await attachmentService.generateThumbnail(imageFile);\n * if (thumbnail) {\n * thumbnailElement.src = thumbnail;\n * }\n * ```\n */\n async generateThumbnail(file: File): Promise<string | null> {\n const config = this.configService.getConfig().attachments;\n const type = this.getAttachmentType(file.type);\n\n if (type === 'image') {\n return this.generateImageThumbnail(file, config.thumbnailSize);\n }\n\n if (type === 'video') {\n return this.generateVideoThumbnail(file, config.thumbnailSize);\n }\n\n return null;\n }\n\n /**\n * Generates a thumbnail for an image file.\n *\n * @param file - The image file\n * @param size - Target thumbnail dimensions\n * @returns Data URL of the thumbnail\n */\n private async generateImageThumbnail(\n file: File,\n size: Dimensions\n ): Promise<string | null> {\n try {\n const imageBitmap = await this.loadImage(file);\n\n const targetDimensions = this.calculateDimensions(\n imageBitmap.width,\n imageBitmap.height,\n size.width,\n size.height\n );\n\n const canvas = document.createElement('canvas');\n canvas.width = targetDimensions.width;\n canvas.height = targetDimensions.height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n\n ctx.drawImage(\n imageBitmap,\n 0,\n 0,\n targetDimensions.width,\n targetDimensions.height\n );\n\n return canvas.toDataURL('image/jpeg', 0.7);\n } catch {\n return null;\n }\n }\n\n /**\n * Generates a thumbnail for a video file.\n *\n * Captures the first frame of the video as the thumbnail.\n *\n * @param file - The video file\n * @param size - Target thumbnail dimensions\n * @returns Data URL of the thumbnail\n */\n private async generateVideoThumbnail(\n file: File,\n size: Dimensions\n ): Promise<string | null> {\n return new Promise((resolve) => {\n const video = document.createElement('video');\n const url = URL.createObjectURL(file);\n\n video.preload = 'metadata';\n video.muted = true;\n video.playsInline = true;\n\n const cleanup = () => {\n URL.revokeObjectURL(url);\n video.remove();\n };\n\n video.onloadeddata = () => {\n // Seek to first frame\n video.currentTime = 0;\n };\n\n video.onseeked = () => {\n try {\n const targetDimensions = this.calculateDimensions(\n video.videoWidth,\n video.videoHeight,\n size.width,\n size.height\n );\n\n const canvas = document.createElement('canvas');\n canvas.width = targetDimensions.width;\n canvas.height = targetDimensions.height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n cleanup();\n resolve(null);\n return;\n }\n\n ctx.drawImage(\n video,\n 0,\n 0,\n targetDimensions.width,\n targetDimensions.height\n );\n\n const dataUrl = canvas.toDataURL('image/jpeg', 0.7);\n cleanup();\n resolve(dataUrl);\n } catch {\n cleanup();\n resolve(null);\n }\n };\n\n video.onerror = () => {\n cleanup();\n resolve(null);\n };\n\n // Set timeout to prevent hanging\n setTimeout(() => {\n cleanup();\n resolve(null);\n }, 5000);\n\n video.src = url;\n });\n }\n\n // ============================================================================\n // Helper Methods\n // ============================================================================\n\n /**\n * Loads an image file and returns an ImageBitmap.\n *\n * @param file - The image file to load\n * @returns Promise resolving to ImageBitmap\n */\n private loadImage(file: File): Promise<ImageBitmap> {\n return createImageBitmap(file);\n }\n\n /**\n * Converts a canvas to a Blob.\n *\n * @param canvas - The canvas to convert\n * @param mimeType - Output MIME type\n * @param quality - Compression quality (0-1)\n * @returns Promise resolving to Blob\n */\n private canvasToBlob(\n canvas: HTMLCanvasElement,\n mimeType: string,\n quality: number\n ): Promise<Blob> {\n return new Promise((resolve, reject) => {\n canvas.toBlob(\n (blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error('Failed to create blob from canvas'));\n }\n },\n mimeType,\n quality\n );\n });\n }\n\n /**\n * Calculates dimensions for resizing while maintaining aspect ratio.\n *\n * The resulting dimensions will fit within the max bounds while\n * preserving the original aspect ratio.\n *\n * @param originalWidth - Original width\n * @param originalHeight - Original height\n * @param maxWidth - Maximum allowed width\n * @param maxHeight - Maximum allowed height\n * @returns Calculated dimensions that fit within bounds\n *\n * @example\n * ```typescript\n * // 4000x3000 image with 2048x2048 max\n * calculateDimensions(4000, 3000, 2048, 2048);\n * // Returns: { width: 2048, height: 1536 }\n * ```\n */\n private calculateDimensions(\n originalWidth: number,\n originalHeight: number,\n maxWidth: number,\n maxHeight: number\n ): Dimensions {\n // If already within bounds, return original dimensions\n if (originalWidth <= maxWidth && originalHeight <= maxHeight) {\n return { width: originalWidth, height: originalHeight };\n }\n\n // Calculate aspect ratio\n const aspectRatio = originalWidth / originalHeight;\n\n let width = maxWidth;\n let height = maxWidth / aspectRatio;\n\n // If height exceeds max, scale by height instead\n if (height > maxHeight) {\n height = maxHeight;\n width = maxHeight * aspectRatio;\n }\n\n return {\n width: Math.round(width),\n height: Math.round(height),\n };\n }\n\n /**\n * Formats a file size in bytes to a human-readable string.\n *\n * @param bytes - File size in bytes\n * @returns Formatted string (e.g., \"10.5 MB\")\n *\n * @example\n * ```typescript\n * formatFileSize(1024); // \"1 KB\"\n * formatFileSize(1048576); // \"1 MB\"\n * formatFileSize(10737418240); // \"10 GB\"\n * ```\n */\n formatFileSize(bytes: number): string {\n if (bytes === 0) {\n return '0 Bytes';\n }\n\n const units = ['Bytes', 'KB', 'MB', 'GB', 'TB'];\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n\n const size = bytes / Math.pow(k, i);\n const formatted = size % 1 === 0 ? size.toString() : size.toFixed(1);\n\n return `${formatted} ${units[i]}`;\n }\n\n /**\n * Gets the file extension from a filename or MIME type.\n *\n * @param filename - The filename to extract extension from\n * @returns File extension without dot, or empty string if none\n *\n * @example\n * ```typescript\n * getFileExtension('document.pdf'); // 'pdf'\n * getFileExtension('photo.JPG'); // 'jpg'\n * getFileExtension('noextension'); // ''\n * ```\n */\n getFileExtension(filename: string): string {\n const lastDot = filename.lastIndexOf('.');\n if (lastDot < 0) {\n return '';\n }\n return filename.slice(lastDot + 1).toLowerCase();\n }\n}\n","/**\n * @fileoverview Barrel export for ngx-chat services.\n *\n * Note: ChatEventService is intentionally NOT exported here. It is an internal\n * service provided at ChatComponent level for isolated event communication\n * between child components. Components that need it should import directly\n * from './chat-event.service'.\n *\n * @module ngx-chat/services\n */\n\nexport { ChatConfigService } from './chat-config.service';\nexport { ChatA11yService } from './chat-a11y.service';\nexport { ChatErrorRecoveryService } from './chat-error-recovery.service';\nexport type { QueuedMessage } from './chat-error-recovery.service';\nexport { ChatAttachmentService } from './chat-attachment.service';\nexport type { FileValidationResult, Dimensions } from './chat-attachment.service';\nexport { ChatMarkdownService } from './chat-markdown.service';\nexport type { MarkdownParseResult } from './chat-markdown.service';\nexport { ChatVirtualScrollService } from './chat-virtual-scroll.service';\nexport type { VisibleRange } from './chat-virtual-scroll.service';\n","import {\n animate,\n keyframes,\n state,\n style,\n transition,\n trigger,\n AnimationTriggerMetadata,\n} from '@angular/animations';\n\n/**\n * Animation timing values matching CSS custom properties:\n * --ngx-chat-animation-duration-fast: 150ms\n * --ngx-chat-animation-duration-normal: 200ms\n * --ngx-chat-animation-duration-slow: 300ms\n * --ngx-chat-animation-easing: cubic-bezier(0.4, 0, 0.2, 1)\n */\nconst TIMING = {\n fast: '150ms',\n normal: '200ms',\n slow: '300ms',\n easing: 'cubic-bezier(0.4, 0, 0.2, 1)',\n} as const;\n\n/**\n * Message entrance animation - fade in and slide up.\n * Used for new messages appearing in the chat.\n */\nexport const messageEnter: AnimationTriggerMetadata = trigger('messageEnter', [\n transition(':enter', [\n style({ opacity: 0, transform: 'translateY(10px)' }),\n animate(\n `${TIMING.normal} ${TIMING.easing}`,\n style({ opacity: 1, transform: 'translateY(0)' })\n ),\n ]),\n transition(':leave', [\n animate(\n `${TIMING.fast} ${TIMING.easing}`,\n style({ opacity: 0, transform: 'translateY(-10px)' })\n ),\n ]),\n]);\n\n/**\n * Typing indicator pulse animation.\n * Creates a pulsing effect for typing dots.\n */\nexport const typingPulse: AnimationTriggerMetadata = trigger('typingPulse', [\n state('pulse1', style({ opacity: 0.4 })),\n state('pulse2', style({ opacity: 0.7 })),\n state('pulse3', style({ opacity: 1 })),\n transition('* => *', [animate(`${TIMING.slow} ${TIMING.easing}`)]),\n]);\n\n/**\n * Error shake animation.\n * Provides visual feedback for errors or invalid actions.\n */\nexport const errorShake: AnimationTriggerMetadata = trigger('errorShake', [\n transition('* => shake', [\n animate(\n `${TIMING.slow} ${TIMING.easing}`,\n keyframes([\n style({ transform: 'translateX(0)', offset: 0 }),\n style({ transform: 'translateX(-6px)', offset: 0.1 }),\n style({ transform: 'translateX(6px)', offset: 0.2 }),\n style({ transform: 'translateX(-6px)', offset: 0.3 }),\n style({ transform: 'translateX(6px)', offset: 0.4 }),\n style({ transform: 'translateX(-4px)', offset: 0.5 }),\n style({ transform: 'translateX(4px)', offset: 0.6 }),\n style({ transform: 'translateX(-2px)', offset: 0.7 }),\n style({ transform: 'translateX(2px)', offset: 0.8 }),\n style({ transform: 'translateX(0)', offset: 1 }),\n ])\n ),\n ]),\n]);\n\n/**\n * Simple fade in/out animation.\n * Used for general visibility transitions.\n */\nexport const fadeInOut: AnimationTriggerMetadata = trigger('fadeInOut', [\n transition(':enter', [\n style({ opacity: 0 }),\n animate(`${TIMING.normal} ${TIMING.easing}`, style({ opacity: 1 })),\n ]),\n transition(':leave', [\n animate(`${TIMING.normal} ${TIMING.easing}`, style({ opacity: 0 })),\n ]),\n]);\n\n/**\n * Collection of all chat animations for easy import.\n *\n * @example\n * ```typescript\n * import { chatAnimations } from 'ngx-chat';\n *\n * @Component({\n * animations: [\n * chatAnimations.messageEnter,\n * chatAnimations.fadeInOut,\n * ],\n * })\n * export class MyComponent {}\n * ```\n */\nexport const chatAnimations = {\n messageEnter,\n typingPulse,\n errorShake,\n fadeInOut,\n} as const;\n","/*\n * Public API Surface of ngx-chat\n */\n\n// Provider function (primary entry point for configuration)\nexport { provideChat } from './lib/provide-chat';\nexport type { ProvideChatOptions } from './lib/provide-chat';\n\n// Components\nexport * from './lib/components';\n\n// Directives\nexport * from './lib/directives';\n\n// Models\nexport * from './lib/models';\n\n// Injection Tokens\nexport * from './lib/tokens';\n\n// Utilities\nexport * from './lib/utils';\n\n// Services\nexport * from './lib/services';\n\n// Animations\nexport * from './lib/animations/chat.animations';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.ChatDropZoneDirective"],"mappings":";;;;;;;;;;;AAAA;;;AAGG;AA+gBH;AACA;AACA;AAEA;;AAEG;AACI,MAAM,uBAAuB,GAAuB;AACzD,IAAA,WAAW,EAAE,IAAI;AACjB,IAAA,cAAc,EAAE,IAAI;IACpB,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;AACvD,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,aAAa,EAAE,IAAI;IACnB,kBAAkB,EAAE,KAAK;AACzB,IAAA,YAAY,EAAE,GAAG;AACjB,IAAA,cAAc,EAAE,GAAG;AACnB,IAAA,yBAAyB,EAAE,GAAG;AAC9B,IAAA,cAAc,EAAE,IAAI;AACpB,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,cAAc,EAAE,QAAQ;;AAG1B;;AAEG;AACI,MAAM,yBAAyB,GAAyB;AAC7D,IAAA,gBAAgB,EAAE,CAAC;AACnB,IAAA,gBAAgB,EAAE,IAAI;AACtB,IAAA,iBAAiB,EAAE,EAAE;AACrB,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,cAAc,EAAE,IAAI;AACpB,IAAA,iBAAiB,EAAE,IAAI;AACvB,IAAA,aAAa,EAAE,EAAE;AACjB,IAAA,gBAAgB,EAAE,IAAI;AACtB,IAAA,mBAAmB,EAAE,IAAI;;AAG3B;;AAEG;AACI,MAAM,uBAAuB,GAAuB;AACzD,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,kBAAkB,EAAE,IAAI;AACxB,IAAA,aAAa,EAAE,IAAI;AACnB,IAAA,mBAAmB,EAAE,IAAI;AACzB,IAAA,WAAW,EAAE;QACX,GAAG;QACH,IAAI;QACJ,QAAQ;QACR,IAAI;QACJ,MAAM;QACN,KAAK;QACL,GAAG;QACH,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,YAAY;QACZ,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,IAAI;AACL,KAAA;AACD,IAAA,iBAAiB,EAAE;AACjB,QAAA,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;QACpB,GAAG,EAAE,CAAC,OAAO,CAAC;AACf,KAAA;AACD,IAAA,MAAM,EAAE,IAAI;AACZ,IAAA,OAAO,EAAE,IAAI;;AAGf;;AAEG;AACI,MAAM,yBAAyB,GAAyB;AAC7D,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,WAAW,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;AAC7B,IAAA,kBAAkB,EAAE,CAAC;AACrB,IAAA,gBAAgB,EAAE,EAAE;AACpB,IAAA,gBAAgB,EAAE,CAAC,0BAA0B,EAAE,0BAA0B,CAAC;AAC1E,IAAA,gBAAgB,EAAE,IAAI;AACtB,IAAA,uBAAuB,EAAE,GAAG;IAC5B,kBAAkB,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IACjD,aAAa,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;AAC1C,IAAA,WAAW,EAAE,IAAI;AACjB,IAAA,kBAAkB,EAAE,IAAI;;AAG1B;;AAEG;AACI,MAAM,6BAA6B,GAA4B;AACpE,IAAA,OAAO,EAAE,IAAI;AACb,IAAA,SAAS,EAAE,GAAG;AACd,IAAA,iBAAiB,EAAE,EAAE;AACrB,IAAA,UAAU,EAAE,CAAC;AACb,IAAA,gBAAgB,EAAE,IAAI;;AAGxB;;AAEG;AACI,MAAM,6BAA6B,GAA4B;AACpE,IAAA,SAAS,EAAE,IAAI;AACf,IAAA,UAAU,EAAE,CAAC;AACb,IAAA,UAAU,EAAE,IAAI;AAChB,IAAA,kBAAkB,EAAE,IAAI;IACxB,aAAa,EAAE,KAAK;AACpB,IAAA,YAAY,EAAE,IAAI;AAClB,IAAA,YAAY,EAAE,EAAE;;AAGlB;;AAEG;AACI,MAAM,uBAAuB,GAAuB;AACzD,IAAA,WAAW,EAAE,IAAI;AACjB,IAAA,eAAe,EAAE,KAAK;AACtB,IAAA,UAAU,EAAE,KAAK;AACjB,IAAA,iBAAiB,EAAE,IAAI;AACvB,IAAA,mBAAmB,EAAE,IAAI;AACzB,IAAA,YAAY,EAAE,KAAK;AACnB,IAAA,SAAS,EAAE,KAAK;;AAGlB;;;;;;;;;;;;;;AAcG;AACI,MAAM,mBAAmB,GAAe;AAC7C,IAAA,QAAQ,EAAE,uBAAuB;AACjC,IAAA,UAAU,EAAE,yBAAyB;AACrC,IAAA,QAAQ,EAAE,uBAAuB;AACjC,IAAA,WAAW,EAAE,yBAAyB;AACtC,IAAA,aAAa,EAAE,6BAA6B;AAC5C,IAAA,aAAa,EAAE,6BAA6B;AAC5C,IAAA,QAAQ,EAAE,uBAAuB;AACjC,IAAA,KAAK,EAAE,MAAM;AACb,IAAA,SAAS,EAAE,MAAM;;;ACxqBnB;;;;AAIG;AA8aH;AACA;AACA;AAEA;;;;;;;;;;;;;;AAcG;AACI,MAAM,iBAAiB,GAAa;;AAEzC,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,KAAK,EAAE,OAAO;;AAGd,IAAA,WAAW,EAAE,mBAAmB;AAChC,IAAA,UAAU,EAAE,iBAAiB;;AAG7B,IAAA,MAAM,EAAE,qBAAqB;AAC7B,IAAA,aAAa,EAAE,sBAAsB;;AAGrC,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,KAAK,EAAE,gBAAgB;;AAGvB,IAAA,UAAU,EAAE,KAAK;AACjB,IAAA,SAAS,EAAE,IAAI;AACf,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,SAAS,EAAE,WAAW;;AAGtB,IAAA,QAAQ,EAAE,UAAU;AACpB,IAAA,aAAa,EAAE,kBAAkB;AACjC,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,iBAAiB,EAAE,WAAW;AAC9B,IAAA,aAAa,EAAE,gBAAgB;AAC/B,IAAA,WAAW,EAAE,cAAc;AAC3B,IAAA,cAAc,EAAE,kBAAkB;;AAGlC,IAAA,cAAc,EAAE,iBAAiB;AACjC,IAAA,aAAa,EAAE,qBAAqB;AACpC,IAAA,YAAY,EAAE,kBAAkB;AAChC,IAAA,iBAAiB,EAAE,2BAA2B;AAC9C,IAAA,aAAa,EAAE,gBAAgB;;AAG/B,IAAA,UAAU,EAAE,YAAY;AACxB,IAAA,WAAW,EAAE,qBAAqB;AAClC,IAAA,YAAY,EAAE,+CAA+C;AAC7D,IAAA,kBAAkB,EAAE,gCAAgC;AACpD,IAAA,aAAa,EAAE,gBAAgB;AAC/B,IAAA,gBAAgB,EAAE,mBAAmB;;AAGrC,IAAA,OAAO,EAAE,YAAY;AACrB,IAAA,QAAQ,EAAE,oBAAoB;AAC9B,IAAA,WAAW,EAAE,2BAA2B;;AAGxC,IAAA,eAAe,EAAE,eAAe;AAChC,IAAA,gBAAgB,EAAE,eAAe;AACjC,IAAA,cAAc,EAAE,2BAA2B;AAC3C,IAAA,cAAc,EAAE,cAAc;AAC9B,IAAA,mBAAmB,EAAE,kBAAkB;AACvC,IAAA,iBAAiB,EAAE,0BAA0B;AAC7C,IAAA,oBAAoB,EAAE,uBAAuB;AAC7C,IAAA,eAAe,EAAE,uBAAuB;AACxC,IAAA,oBAAoB,EAAE,eAAe;AACrC,IAAA,eAAe,EAAE,cAAc;;AAG/B,IAAA,GAAG,EAAE,KAAK;AACV,IAAA,KAAK,EAAE,SAAS;;AAGhB,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,KAAK,EAAE,OAAO;AACd,IAAA,SAAS,EAAE,WAAW;;AAGtB,IAAA,eAAe,EAAE,iDAAiD;AAClE,IAAA,cAAc,EAAE,8CAA8C;AAC9D,IAAA,cAAc,EAAE,mBAAmB;;;ACvhBrC;;;;AAIG;AASH;;;;;;;;;;;;;;AAcG;MACU,WAAW,GAAG,IAAI,cAAc,CAAa,aAAa,EAAE;AACvE,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,mBAAmB;AACnC,CAAA;AAED;;;;;;;AAOG;MACU,qBAAqB,GAAG,IAAI,cAAc,CACrD,uBAAuB;;AC1CzB;;;;AAIG;AAMH;;;;;;;;;;;;;;;AAeG;MACU,SAAS,GAAG,IAAI,cAAc,CAAW,WAAW,EAAE;AACjE,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,iBAAiB;AACjC,CAAA;AAED;;;;;;;AAOG;MACU,mBAAmB,GAAG,IAAI,cAAc,CACnD,qBAAqB;;ACxCvB;;;;AAIG;AAqDH;AACA;AACA;AAEA;;;AAGG;AACH,SAAS,aAAa,CAAC,KAAc,EAAA;IACnC,QACE,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;AACzB,QAAA,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;AACrB,QAAA,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,iBAAiB;AAE/D;AAEA;;;;;;;;;;AAUG;AACH,SAAS,SAAS,CAChB,MAAS,EACT,MAA8B,EAAA;AAE9B,IAAA,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;AAC/C,QAAA,OAAO,MAAM;IACf;AAEA,IAAA,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAA6B;IAEvD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AACrC,QAAA,MAAM,WAAW,GAAI,MAAkC,CAAC,GAAG,CAAC;AAC5D,QAAA,MAAM,WAAW,GAAI,MAAkC,CAAC,GAAG,CAAC;;AAG5D,QAAA,IAAI,WAAW,KAAK,SAAS,EAAE;YAC7B;QACF;;QAGA,IAAI,aAAa,CAAC,WAAW,CAAC,IAAI,aAAa,CAAC,WAAW,CAAC,EAAE;YAC5D,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CACrB,WAAsC,EACtC,WAAsC,CACvC;QACH;aAAO;;AAEL,YAAA,MAAM,CAAC,GAAG,CAAC,GAAG,WAAW;QAC3B;IACF;AAEA,IAAA,OAAO,MAAW;AACpB;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0FG;AACG,SAAU,WAAW,CACzB,OAA4B,EAAA;;IAG5B,MAAM,YAAY,GAAG,SAAS,CAC5B,mBAAyD,EACzD,OAAO,EAAE,MAAwD,CACzC;;IAG1B,MAAM,UAAU,GAAG,SAAS,CAC1B,iBAAuD,EACvD,OAAO,EAAE,IAAsD,CACzC;AAExB,IAAA,OAAO,wBAAwB,CAAC;AAC9B,QAAA;AACE,YAAA,OAAO,EAAE,WAAW;AACpB,YAAA,QAAQ,EAAE,YAAY;AACvB,SAAA;AACD,QAAA;AACE,YAAA,OAAO,EAAE,SAAS;AAClB,YAAA,QAAQ,EAAE,UAAU;AACrB,SAAA;AACF,KAAA,CAAC;AACJ;;AC/OA;;;;AAIG;AAYH;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;MAEU,iBAAiB,CAAA;AACX,IAAA,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;AAChC,IAAA,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC;AAE7C;;;AAGG;AACc,IAAA,WAAW,GAAG,IAAI,GAAG,EAAsB;AAE5D;;;;;;;;;;;;;;;;;;;;;AAqBG;AACH,IAAA,SAAS,CAAC,SAA2B,EAAA;;AAEnC,QAAA,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;YACrD,OAAO,IAAI,CAAC,UAAU;QACxB;;QAGA,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC7C,IAAI,MAAM,EAAE;AACV,YAAA,OAAO,MAAM;QACf;;AAGA,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAC3B,IAAI,CAAC,UAAgD,EACrD,SAAoC,CACZ;QAC1B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;AAEtC,QAAA,OAAO,MAAM;IACf;AAEA;;;;;;;;;;;AAWG;IACH,OAAO,GAAA;QACL,OAAO,IAAI,CAAC,QAAQ;IACtB;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;AAyBG;IACH,UAAU,CACR,GAAmB,EACnB,MAAwC,EAAA;QAExC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;AAEnC,QAAA,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE;AAC/C,YAAA,OAAO,QAAQ;QACjB;QAEA,OAAO,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC;IACjD;AAEA;;;;;;AAMG;IACK,iBAAiB,CACvB,QAAgB,EAChB,MAAuC,EAAA;QAEvC,OAAO,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,SAAiB,KAAI;AACjE,YAAA,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC;AAC/B,YAAA,OAAO,KAAK,KAAK,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK;AACpD,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;;;;;;;;AAYG;IACK,SAAS,CACf,MAA+B,EAC/B,MAA+B,EAAA;AAE/B,QAAA,MAAM,MAAM,GAA4B,EAAE,GAAG,MAAM,EAAE;QAErD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;AACrC,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC;AAC/B,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC;;AAG/B,YAAA,IAAI,WAAW,KAAK,SAAS,EAAE;gBAC7B;YACF;;AAGA,YAAA,IACE,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC;AAC/B,gBAAA,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAC/B;AACA,gBAAA,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;YACxD;iBAAO;;AAEL,gBAAA,MAAM,CAAC,GAAG,CAAC,GAAG,WAAW;YAC3B;QACF;AAEA,QAAA,OAAO,MAAM;IACf;AAEA;;;;;AAKG;AACK,IAAA,aAAa,CAAC,KAAc,EAAA;QAClC,QACE,KAAK,KAAK,IAAI;YACd,OAAO,KAAK,KAAK,QAAQ;AACzB,YAAA,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;AACrB,YAAA,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,iBAAiB;IAE/D;AAEA;;;;;AAKG;IACH,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;IAC1B;uGAjMW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAjB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cADJ,MAAM,EAAA,CAAA;;2FACnB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAD7B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACzClC;;;;;;;;AAQG;AAQH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CG;MAEU,gBAAgB,CAAA;;;;AAK3B;;;AAGG;AACc,IAAA,aAAa,GAAG,IAAI,OAAO,EAAsB;AAElE;;;AAGG;AACc,IAAA,YAAY,GAAG,IAAI,OAAO,EAAkB;AAE7D;;;AAGG;AACc,IAAA,qBAAqB,GAAG,IAAI,OAAO,EAAQ;AAE5D;;;AAGG;AACc,IAAA,eAAe,GAAG,IAAI,OAAO,EAAqB;AAEnE;;;AAGG;AACc,IAAA,sBAAsB,GAAG,IAAI,OAAO,EAAwB;;;;AAM7E;;;;;;;;;;;;;;;;;AAiBG;AACM,IAAA,OAAO,GACd,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE;AAEnC;;;;;;;;;;AAUG;AACM,IAAA,MAAM,GACb,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE;AAElC;;;;;;;;;;AAUG;AACM,IAAA,eAAe,GACtB,IAAI,CAAC,qBAAqB,CAAC,YAAY,EAAE;AAE3C;;;;;;;;;;AAUG;AACM,IAAA,SAAS,GAChB,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE;AAErC;;;;;;;;;;;;AAYG;AACM,IAAA,gBAAgB,GACvB,IAAI,CAAC,sBAAsB,CAAC,YAAY,EAAE;;;;AAM5C;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACH,IAAA,UAAU,CAAC,KAAyB,EAAA;AAClC,QAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;IAChC;AAEA;;;;;;;;;;;;;AAaG;AACH,IAAA,SAAS,CAAC,KAAqB,EAAA;AAC7B,QAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;IAC/B;AAEA;;;;;;;;;AASG;IACH,kBAAkB,GAAA;AAChB,QAAA,IAAI,CAAC,qBAAqB,CAAC,IAAI,EAAE;IACnC;AAEA;;;;;;;;;;;;;AAaG;AACH,IAAA,YAAY,CAAC,KAAwB,EAAA;AACnC,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;IAClC;AAEA;;;;;;;;;;;;;;AAcG;AACH,IAAA,mBAAmB,CAAC,KAA2B,EAAA;AAC7C,QAAA,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC;IACzC;uGA1NW,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAhB,gBAAgB,EAAA,CAAA;;2FAAhB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B;;;AC9DD;;;;AAIG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BG;MAKU,0BAA0B,CAAA;AACrC;;;AAGG;AACM,IAAA,WAAW,GAAG,MAAM,EAAC,WAAoB,EAAC;uGALxC,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAA1B,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAA1B,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAJtC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,wBAAwB;AAClC,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;AC1CD;;;;AAIG;AAKH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;MAmBU,mBAAmB,CAAA;AAC9B;;;AAGG;AACM,IAAA,QAAQ,GAAG,KAAK,CAA8B,IAAI,oDAAC;uGALjD,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAdpB;;;;;;AAMT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,26EAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAPS,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,yBAAA,EAAA,kBAAA,EAAA,0BAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAeX,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAlB/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,cACf,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,CAAC,EAAA,QAAA,EACb;;;;;;GAMT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,iBAAiB;AAC1B,wBAAA,MAAM,EAAE,QAAQ;AACjB,qBAAA,EAAA,MAAA,EAAA,CAAA,26EAAA,CAAA,EAAA;;;ACvDH;;;AAGG;AAkDH;AACA;AACA;AAEA;;;AAGG;AACH,MAAM,gBAAgB,GAAG,QAAQ;AAEjC;;;;AAIG;AACH,MAAM,uBAAuB,GAC3B,uKAAuK;AAEzK;;AAEG;AACH,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC;AAErD;;AAEG;AACH,MAAM,aAAa,GAA2B;AAC5C,IAAA,GAAG,EAAE,OAAO;AACZ,IAAA,GAAG,EAAE,MAAM;AACX,IAAA,GAAG,EAAE,MAAM;AACX,IAAA,GAAG,EAAE,QAAQ;AACb,IAAA,GAAG,EAAE,OAAO;CACb;AAED;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,eAAe,CAAC,OAAe,EAAA;IAC7C,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,OAAO;IAChB;AAEA,IAAA,OAAO,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AAC3E;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,mBAAmB,CAAC,OAAe,EAAA;IACjD,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,OAAO,OAAO;IAChB;IAEA,OAAO,OAAO,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC;AACrD;AAEA;;;;;;;;;;;;;;;AAeG;SACa,cAAc,CAAC,OAAe,EAAE,YAAoB,EAAE,EAAA;AACpE,IAAA,IAAI,CAAC,OAAO,IAAI,SAAS,IAAI,CAAC,EAAE;AAC9B,QAAA,OAAO,OAAO;IAChB;;IAGA,MAAM,WAAW,GAAG,IAAI,MAAM,CAAC,CAAA,KAAA,EAAQ,SAAS,CAAA,EAAA,CAAI,EAAE,GAAG,CAAC;IAE1D,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,KAAI;;QAE5C,MAAM,MAAM,GAAa,EAAE;AAC3B,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE;AAChD,YAAA,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;QAC5C;AACA,QAAA,OAAO,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACtC,IAAA,CAAC,CAAC;AACJ;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,SAAS,CAAC,GAAW,EAAA;IACnC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AACnC,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,IAAI;;QAEF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,oBAAoB,CAAC;QACjD,OAAO,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;IACjD;AAAE,IAAA,MAAM;;QAEN,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE;AACzC,QAAA,OAAO,cAAc,CAAC,IAAI,CACxB,CAAC,QAAQ,KACP,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC;AAC7B,YAAA,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CACpD;IACH;AACF;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCG;AACG,SAAU,eAAe,CAC7B,OAAe,EACf,MAA4B,EAAA;AAE5B,IAAA,IAAI,gBAAgB,GAAG,OAAO,IAAI,EAAE;;AAGpC,IAAA,IAAI,MAAM,CAAC,cAAc,EAAE;AACzB,QAAA,gBAAgB,GAAG,gBAAgB,CAAC,IAAI,EAAE;IAC5C;;IAGA,IAAI,CAAC,gBAAgB,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE;QAClD,OAAO;AACL,YAAA,KAAK,EAAE,KAAK;AACZ,YAAA,KAAK,EAAE,yBAAyB;AAChC,YAAA,SAAS,EAAE,OAAO;SACnB;IACH;;AAGA,IAAA,IAAI,CAAC,gBAAgB,IAAI,MAAM,CAAC,iBAAiB,EAAE;QACjD,OAAO;AACL,YAAA,KAAK,EAAE,IAAI;AACX,YAAA,gBAAgB,EAAE,EAAE;SACrB;IACH;;AAGA,IAAA,IAAI,MAAM,CAAC,gBAAgB,EAAE;AAC3B,QAAA,gBAAgB,GAAG,gBAAgB,CAAC,SAAS,CAAC,KAAK,CAAC;IACtD;;AAGA,IAAA,IAAI,MAAM,CAAC,mBAAmB,EAAE;AAC9B,QAAA,gBAAgB,GAAG,mBAAmB,CAAC,gBAAgB,CAAC;IAC1D;;AAGA,IAAA,IAAI,MAAM,CAAC,cAAc,EAAE;AACzB,QAAA,gBAAgB,GAAG,gBAAgB,CAAC,IAAI,EAAE;IAC5C;;IAGA,IAAI,CAAC,gBAAgB,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE;QAClD,OAAO;AACL,YAAA,KAAK,EAAE,KAAK;AACZ,YAAA,KAAK,EAAE,yBAAyB;AAChC,YAAA,SAAS,EAAE,OAAO;SACnB;IACH;;AAGA,IAAA,IACE,MAAM,CAAC,gBAAgB,GAAG,CAAC;AAC3B,QAAA,gBAAgB,CAAC,MAAM,GAAG,MAAM,CAAC,gBAAgB,EACjD;QACA,OAAO;AACL,YAAA,KAAK,EAAE,KAAK;AACZ,YAAA,KAAK,EAAE,CAAA,yBAAA,EAA4B,MAAM,CAAC,gBAAgB,CAAA,WAAA,CAAa;AACvE,YAAA,SAAS,EAAE,WAAW;SACvB;IACH;;AAGA,IAAA,IACE,MAAM,CAAC,gBAAgB,GAAG,CAAC;AAC3B,QAAA,gBAAgB,CAAC,MAAM,GAAG,MAAM,CAAC,gBAAgB,EACjD;QACA,OAAO;AACL,YAAA,KAAK,EAAE,KAAK;AACZ,YAAA,KAAK,EAAE,CAAA,sBAAA,EAAyB,MAAM,CAAC,gBAAgB,CAAA,WAAA,CAAa;AACpE,YAAA,SAAS,EAAE,UAAU;SACtB;IACH;;AAGA,IAAA,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,iBAAiB,EAAE;AAC9C,QAAA,IAAI,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE;YAClC,OAAO;AACL,gBAAA,KAAK,EAAE,KAAK;AACZ,gBAAA,KAAK,EAAE,oCAAoC;AAC3C,gBAAA,SAAS,EAAE,mBAAmB;aAC/B;QACH;IACF;;AAGA,IAAA,IAAI,MAAM,CAAC,aAAa,GAAG,CAAC,EAAE;QAC5B,gBAAgB,GAAG,cAAc,CAAC,gBAAgB,EAAE,MAAM,CAAC,aAAa,CAAC;IAC3E;;;;IAKA,IAAI,gBAAgB,GAAG,gBAAgB;AACvC,IAAA,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnB,QAAA,gBAAgB,GAAG,eAAe,CAAC,gBAAgB,CAAC;IACtD;IAEA,OAAO;AACL,QAAA,KAAK,EAAE,IAAI;QACX,gBAAgB;KACjB;AACH;;ACtXA;;;;AAIG;AAoBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAcU,mBAAmB,CAAA;;;;AAKb,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;;;;AAMhD;;AAEG;AACM,IAAA,WAAW,GAAG,SAAS,CAAkC,iBAAiB,uDAAC;;;;AAMpF;;;;AAIG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,oDAAC;AAEzC;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAA8B,SAAS,kDAAC;;;;AAM/D;;;AAGG;IACM,IAAI,GAAG,MAAM,EAAiB;AAEvC;;;AAGG;IACM,MAAM,GAAG,MAAM,EAAmB;;;;AAM3C;;AAEG;AACM,IAAA,UAAU,GAAG,MAAM,CAAS,EAAE,sDAAC;AAExC;;AAEG;AACM,IAAA,eAAe,GAAG,MAAM,CAAgB,IAAI,2DAAC;AAEtD;;AAEG;AACM,IAAA,kBAAkB,GAAG,MAAM,CAAyB,EAAE,8DAAC;AAEhE;;AAEG;AACM,IAAA,iBAAiB,GAAG,MAAM,CAAU,KAAK,6DAAC;AAEnD;;AAEG;AACM,IAAA,YAAY,GAAG,MAAM,CAAU,KAAK,wDAAC;;;;AAM9C;;AAEG;IACK,qBAAqB,GAAyC,IAAI;AAE1E;;AAEG;IACK,gBAAgB,GAAyC,IAAI;AAErE;;AAEG;IACK,eAAe,GAAyC,IAAI;AAEpE;;AAEG;IACK,iBAAiB,GAAyC,IAAI;;;;AAMtE;;AAEG;AACM,IAAA,eAAe,GAAG,QAAQ,CAAC,MAAK;AACvC,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE;QACjC,IAAI,WAAW,EAAE;YACf,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC;QAClD;AACA,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE;AACvC,IAAA,CAAC,2DAAC;AAEF;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;AAE5D;;AAEG;AACM,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC,UAAU,4DAAC;AAE7E;;AAEG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC,QAAQ,0DAAC;AAEzE;;AAEG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC,QAAQ,0DAAC;AAEzE;;AAEG;AACM,IAAA,kBAAkB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,KAAK,IAAI,8DAAC;AAE7E;;AAEG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC,MAAM,0DAAC;AAElE;;AAEG;AACM,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC,gBAAgB,6DAAC;AAErF;;;AAGG;AACM,IAAA,kBAAkB,GAAG,QAAQ,CAAC,MAAK;AAC1C,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,EAAE;AACpC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE;;QAErC,OAAO,GAAG,GAAG,CAAC,IAAI,OAAO,IAAI,GAAG,GAAG,GAAG;AACxC,IAAA,CAAC,8DAAC;AAEF;;AAEG;AACM,IAAA,qBAAqB,GAAG,QAAQ,CAAC,MAAK;AAC7C,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE;AACrC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,EAAE;AACpC,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,gBAAgB,EAAE;AACrD,YAAA,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE;AAC3B,YAAA,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE;AACpB,SAAA,CAAC;AACJ,IAAA,CAAC,iEAAC;AAEF;;AAEG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AACnC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,EAAE;QACpC,OAAO,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,GAAG,GAAG;AAC/C,IAAA,CAAC,uDAAC;AAEF;;AAEG;AACM,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;;AAE/B,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,EAAE;AACvB,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE;AAC7B,YAAA,OAAO,KAAK;QACd;QAEA,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE;QACxC,MAAM,cAAc,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC,MAAM,GAAG,CAAC;AAC3D,QAAA,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE;;AAGhD,QAAA,IAAI,cAAc,IAAI,gBAAgB,CAAC,iBAAiB,EAAE;AACxD,YAAA,OAAO,IAAI;QACb;;AAGA,QAAA,IAAI,CAAC,OAAO,IAAI,CAAC,cAAc,EAAE;AAC/B,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,IAAI,gBAAgB,CAAC,gBAAgB,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,gBAAgB,CAAC,gBAAgB,EAAE;AAC/F,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,mDAAC;AAEF;;AAEG;AACM,IAAA,mBAAmB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,cAAc,+DAAC;;;;AAMzE,IAAA,WAAA,GAAA;;AAEE,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;YAC7B,IAAI,CAAC,gBAAgB,EAAE;AACzB,QAAA,CAAC,CAAC;IACJ;;;;AAMA;;;AAGG;AACH,IAAA,OAAO,CAAC,KAAY,EAAA;AAClB,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAA6B;AAClD,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK;AAE1B,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,kBAAkB,EAAE;AACzB,QAAA,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC;AAC9B,QAAA,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC;IACnC;AAEA;;AAEG;AACH,IAAA,SAAS,CAAC,KAAoB,EAAA;AAC5B,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE;;QAGpC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;AAChF,YAAA,IAAI,MAAM,CAAC,WAAW,EAAE;gBACtB,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,WAAW,EAAE;gBAClB;YACF;QACF;;AAGA,QAAA,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,KAAK,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE;AAC7D,YAAA,IAAI,MAAM,CAAC,eAAe,EAAE;gBAC1B,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,WAAW,EAAE;gBAClB;YACF;QACF;;AAGA,QAAA,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE;AAC1B,YAAA,IAAI,MAAM,CAAC,UAAU,EAAE;gBACrB,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,UAAU,EAAE;gBACjB;YACF;QACF;IACF;AAEA;;AAEG;IACH,WAAW,GAAA;QACT,IAAI,CAAC,WAAW,EAAE;IACpB;AAEA;;AAEG;IACH,OAAO,GAAA;;IAEP;AAEA;;AAEG;IACH,MAAM,GAAA;;AAEJ,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE;YAC5B,IAAI,CAAC,aAAa,EAAE;QACtB;IACF;;;;AAMA;;AAEG;IACH,KAAK,GAAA;QACH,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,KAAK,EAAE;IAC3C;AAEA;;AAEG;IACH,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;AACvB,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;AAC9B,QAAA,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,IAAI,CAAC,kBAAkB,EAAE;AAEzB,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE;YAC5B,IAAI,CAAC,aAAa,EAAE;QACtB;IACF;AAEA;;AAEG;AACH,IAAA,aAAa,CAAC,UAAgC,EAAA;AAC5C,QAAA,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,CAAC;IAC7E;AAEA;;AAEG;AACH,IAAA,gBAAgB,CAAC,YAAoB,EAAA;QACnC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,WAAW,IACxC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,CAC/C;IACH;;;;AAMA;;AAEG;AACK,IAAA,kBAAkB,CAAC,OAAe,EAAA;AACxC,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE;AAC1B,YAAA,YAAY,CAAC,IAAI,CAAC,iBAAiB,CAAC;QACtC;;AAGA,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE;AACnB,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;YAC9B;QACF;AAEA,QAAA,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC,MAAK;AACvC,YAAA,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;QAC7B,CAAC,EAAE,GAAG,CAAC;IACT;AAEA;;AAEG;AACK,IAAA,aAAa,CAAC,OAAe,EAAA;AACnC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,EAAE;QACtC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC;AAE/C,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;YACjB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC;QAChD;aAAO;AACL,YAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;QAChC;IACF;;;;AAMA;;AAEG;AACK,IAAA,qBAAqB,CAAC,OAAe,EAAA;QAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,cAAc;;AAGvD,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE;AACzB,YAAA,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACnC,YAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;QAC9B;;AAGA,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE;AACnB,YAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE;gBAC5B,IAAI,CAAC,aAAa,EAAE;YACtB;YACA;QACF;;AAGA,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE;AAC7B,YAAA,IAAI,IAAI,CAAC,qBAAqB,EAAE;AAC9B,gBAAA,YAAY,CAAC,IAAI,CAAC,qBAAqB,CAAC;YAC1C;AAEA,YAAA,IAAI,CAAC,qBAAqB,GAAG,UAAU,CAAC,MAAK;AAC3C,gBAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;YAC/B,CAAC,EAAE,UAAU,CAAC;QAChB;aAAO;;AAEL,YAAA,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,MAAK;gBACtC,IAAI,CAAC,aAAa,EAAE;AACtB,YAAA,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC;QACpB;IACF;AAEA;;AAEG;AACK,IAAA,eAAe,CAAC,OAAe,EAAA;AACrC,QAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;AAChC,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AACf,YAAA,QAAQ,EAAE,IAAI;YACd,OAAO;AACR,SAAA,CAAC;;AAGF,QAAA,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,MAAK;YACtC,IAAI,CAAC,aAAa,EAAE;QACtB,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,cAAc,GAAG,CAAC,CAAC;IAC9C;AAEA;;AAEG;IACK,aAAa,GAAA;AACnB,QAAA,IAAI,IAAI,CAAC,qBAAqB,EAAE;AAC9B,YAAA,YAAY,CAAC,IAAI,CAAC,qBAAqB,CAAC;AACxC,YAAA,IAAI,CAAC,qBAAqB,GAAG,IAAI;QACnC;AAEA,QAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC;AACjC,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AACf,YAAA,QAAQ,EAAE,KAAK;AAChB,SAAA,CAAC;IACJ;;;;AAMA;;AAEG;IACK,WAAW,GAAA;AACjB,QAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE;YACnB;QACF;QAEA,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE;AACxC,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,EAAE;AAC7C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,EAAE;;QAGtC,IAAI,OAAO,EAAE;YACX,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC;AAC/C,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;gBACjB,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC;gBAC9C;YACF;QACF;;AAGA,QAAA,MAAM,KAAK,GAAkB;AAC3B,YAAA,OAAO,EAAE,OAAO;YAChB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;SAC/C;AAED,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;;QAGrB,IAAI,CAAC,UAAU,EAAE;;QAGjB,IAAI,CAAC,aAAa,EAAE;IACtB;AAEA;;AAEG;IACK,aAAa,GAAA;QACnB,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,YAAY;AAErD,QAAA,IAAI,UAAU,IAAI,CAAC,EAAE;YACnB;QACF;AAEA,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAE3B,QAAA,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,MAAK;AACrC,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,YAAA,IAAI,CAAC,eAAe,GAAG,IAAI;QAC7B,CAAC,EAAE,UAAU,CAAC;IAChB;;;;AAMA;;AAEG;IACK,kBAAkB,GAAA;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa;QAClD,IAAI,CAAC,QAAQ,EAAE;YACb;QACF;;AAGA,QAAA,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM;;AAG9B,QAAA,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC;QAC5D,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAA,EAAG,SAAS,IAAI;;AAGxC,QAAA,QAAQ,CAAC,KAAK,CAAC,SAAS,GAAG,QAAQ,CAAC,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ;IAClF;;;;AAMA;;AAEG;IACK,gBAAgB,GAAA;AACtB,QAAA,IAAI,IAAI,CAAC,qBAAqB,EAAE;AAC9B,YAAA,YAAY,CAAC,IAAI,CAAC,qBAAqB,CAAC;AACxC,YAAA,IAAI,CAAC,qBAAqB,GAAG,IAAI;QACnC;AAEA,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE;AACzB,YAAA,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC;AACnC,YAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI;QAC9B;AAEA,QAAA,IAAI,IAAI,CAAC,eAAe,EAAE;AACxB,YAAA,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC;AAClC,YAAA,IAAI,CAAC,eAAe,GAAG,IAAI;QAC7B;AAEA,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE;AAC1B,YAAA,YAAY,CAAC,IAAI,CAAC,iBAAiB,CAAC;AACpC,YAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI;QAC/B;IACF;uGAjkBW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,mBAAmB,2tBCrEhC,+gGA6FA,EAAA,MAAA,EAAA,CAAA,qvLAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDxBa,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAb/B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,cACf,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,iBAAiB;AAC1B,wBAAA,mCAAmC,EAAE,YAAY;AACjD,wBAAA,gCAAgC,EAAE,sBAAsB;AACxD,wBAAA,mCAAmC,EAAE,gBAAgB;AACtD,qBAAA,EAAA,QAAA,EAAA,+gGAAA,EAAA,MAAA,EAAA,CAAA,qvLAAA,CAAA,EAAA;mGAiBiE,iBAAiB,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,MAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,QAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AEpFrF;;;;AAIG;AA2BH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;MAoBU,aAAa,CAAA;;;;AAKP,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,IAAA,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACvC,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAC/B,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;;;;AAM5C;;;AAGG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAgB,EAAE,oDAAC;AAE5C;;;AAGG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,oDAAC;AAEzC;;;AAGG;AACM,IAAA,WAAW,GAAG,KAAK,CAAqB,SAAS,uDAAC;AAE3D;;;AAGG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,oDAAC;AAEzC;;;AAGG;AACM,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,mDAAC;AAExC;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAA8B,SAAS,kDAAC;;;;AAM/D;;;AAGG;IACM,IAAI,GAAG,MAAM,EAAiB;AAEvC;;;AAGG;IACM,MAAM,GAAG,MAAM,EAAmB;AAE3C;;;AAGG;IACM,MAAM,GAAG,MAAM,EAAsB;AAE9C;;;AAGG;IACM,KAAK,GAAG,MAAM,EAAkB;AAEzC;;;AAGG;IACM,QAAQ,GAAG,MAAM,EAAqB;AAE/C;;;AAGG;IACM,eAAe,GAAG,MAAM,EAAwB;;;;AAMzD;;;AAGG;AACM,IAAA,aAAa,GAAG,YAAY,CAAC,0BAA0B,yDAAC;AAEjE;;;AAGG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAuC;AACxE,QAAA,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,WAAW;AAC1C,IAAA,CAAC,0DAAC;;;;AAMF;;;AAGG;AACc,IAAA,iBAAiB,GAAG,MAAM,CAAU,KAAK,6DAAC;AAE3D;;AAEG;IACK,cAAc,GAA0B,IAAI;;;;AAMpD;;;AAGG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAiB;QAChD,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;AACpD,IAAA,CAAC,wDAAC;AAEF;;AAEG;AACM,IAAA,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAE5C;;AAEG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAuB;QACvD,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK;QAEvC,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM,EAAE;AACzC,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,OAAO,IAAI,CAAC,iBAAiB,EAAE,GAAG,MAAM,GAAG,OAAO;AACpD,IAAA,CAAC,yDAAC;AAEF;;AAEG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAc;AAC5C,QAAA,OAAO,IAAI,CAAC,aAAa,EAAE,KAAK,MAAM;AACxC,IAAA,CAAC,uDAAC;AAEF;;AAEG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAc;AAC7C,QAAA,OAAO,IAAI,CAAC,aAAa,EAAE,KAAK,OAAO;AACzC,IAAA,CAAC,wDAAC;AAEF;;AAEG;AACM,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAoB;QACxD,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,SAAS;QAE/C,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK,EAAE;AAC9C,YAAA,OAAO,SAAS;QAClB;;AAGA,QAAA,OAAO,IAAI,CAAC,oBAAoB,EAAE;AACpC,IAAA,CAAC,6DAAC;AAEF;;AAEG;AACM,IAAA,KAAK,GAAG,QAAQ,CAAC,MAAc;AACtC,QAAA,OAAO,IAAI,CAAC,iBAAiB,EAAE,KAAK,KAAK;AAC3C,IAAA,CAAC,iDAAC;;;;AAMF,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,mBAAmB,EAAE;QAC1B,IAAI,CAAC,oBAAoB,EAAE;IAC7B;;;;AAMA;;;AAGG;IACK,mBAAmB,GAAA;QACzB,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;YACvD;QACF;QAEA,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC;QACvE,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;AAEvD,QAAA,MAAM,QAAQ,GAAG,CAAC,KAA0B,KAAI;YAC9C,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC;AAC3C,QAAA,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC;AAExD,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;YAC7B,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC;AAC9D,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;IACK,oBAAoB,GAAA;;QAE1B,IAAI,CAAC,YAAY,CAAC;AACf,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC,CAAC,KAAK,KAAI;AACnB,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;AACzB,QAAA,CAAC,CAAC;;QAGJ,IAAI,CAAC,YAAY,CAAC;AACf,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC,CAAC,KAAK,KAAI;AACnB,YAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACxB,QAAA,CAAC,CAAC;;QAGJ,IAAI,CAAC,YAAY,CAAC;AACf,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC,CAAC,KAAK,KAAI;AACnB,YAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3B,QAAA,CAAC,CAAC;;QAGJ,IAAI,CAAC,YAAY,CAAC;AACf,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC,CAAC,KAAK,KAAI;AACnB,YAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;AAClC,QAAA,CAAC,CAAC;IACN;AAEA;;;AAGG;IACK,oBAAoB,GAAA;AAC1B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,IAAI,KAAK;QAC5E,OAAO,GAAG,KAAK,KAAK,GAAG,KAAK,GAAG,KAAK;IACtC;;;;AAMA;;;AAGG;AACH,IAAA,MAAM,CAAC,KAAoB,EAAA;AACzB,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;AACA,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACvB;AAEA;;;AAGG;AACH,IAAA,QAAQ,CAAC,KAAsB,EAAA;AAC7B,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;AACA,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB;uGApSW,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,sBAAA,EAAA,eAAA,EAAA,uBAAA,EAAA,gBAAA,EAAA,0BAAA,EAAA,YAAA,EAAA,yBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,EAAA,cAAA,EAAA,UAAA,EAAA,EAAA,SAAA,EAZb,CAAC,gBAAgB,CAAC,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,eAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EA8GS,0BAA0B,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECxLlE,mpGAsFA,EAAA,MAAA,EAAA,CAAA,m5QAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDhBY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,mBAAmB,kFAA8B,mBAAmB,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,MAAA,EAAA,QAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAgBjF,aAAa,EAAA,UAAA,EAAA,CAAA;kBAnBzB,SAAS;+BACE,UAAU,EAAA,UAAA,EACR,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,mBAAmB,CAAC,EAAA,eAAA,EAG5E,uBAAuB,CAAC,MAAM,aACpC,CAAC,gBAAgB,CAAC,EAAA,IAAA,EACvB;AACJ,wBAAA,OAAO,EAAE,UAAU;AACnB,wBAAA,wBAAwB,EAAE,eAAe;AACzC,wBAAA,yBAAyB,EAAE,gBAAgB;AAC3C,wBAAA,4BAA4B,EAAE,YAAY;AAC1C,wBAAA,2BAA2B,EAAE,WAAW;AACxC,wBAAA,YAAY,EAAE,qBAAqB;AACnC,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,mBAAmB,EAAE,sBAAsB;AAC5C,qBAAA,EAAA,QAAA,EAAA,mpGAAA,EAAA,MAAA,EAAA,CAAA,m5QAAA,CAAA,EAAA;k/BAoGqC,0BAA0B,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AExLlE;;;;AAIG;AAIH;;;;;;;;;;;;;;;;;;;;;;AAsBG;MAuBU,4BAA4B,CAAA;AACvC;;;;;;;AAOG;AACM,IAAA,KAAK,GAAG,KAAK,CAAqB,SAAS,iDAAC;uGAT1C,4BAA4B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA5B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,4BAA4B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,WAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,kCAAA,EAAA,EAAA,cAAA,EAAA,2BAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAnB7B;;;;;;;;;AAST,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,owEAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAUU,4BAA4B,EAAA,UAAA,EAAA,CAAA;kBAtBxC,SAAS;+BACE,2BAA2B,EAAA,UAAA,EACzB,IAAI,EAAA,QAAA,EACN;;;;;;;;;GAST,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,2BAA2B;AACpC,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,WAAW,EAAE,QAAQ;AACrB,wBAAA,mBAAmB,EAAE,gCAAgC;AACtD,qBAAA,EAAA,MAAA,EAAA,CAAA,owEAAA,CAAA,EAAA;;;ACnDH;;;;;AAKG;AAIH;AACA;AACA;AAEA;;AAEG;AACI,MAAM,6BAA6B,GAAG;AA4C7C;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;AAmBG;AACG,SAAU,aAAa,CAAC,OAAoB,EAAA;;AAEhD,IAAA,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,EAAE;AAC/B,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;AACjD,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;AACzD,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,OAAO,KAAK;AACd;AAEA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;AACG,SAAU,mBAAmB,CACjC,WAAwB,EACxB,cAA2B,EAC3B,cAAsB,6BAA6B,EAAA;;IAGnD,IAAI,aAAa,CAAC,WAAW,CAAC,IAAI,aAAa,CAAC,cAAc,CAAC,EAAE;AAC/D,QAAA,OAAO,KAAK;IACd;;IAGA,IAAI,WAAW,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM,EAAE;AAChD,QAAA,OAAO,KAAK;IACd;;IAGA,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CACvB,cAAc,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,OAAO,EAAE,CACrE;AAED,IAAA,IAAI,QAAQ,GAAG,WAAW,EAAE;AAC1B,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,OAAO,IAAI;AACb;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;SACa,aAAa,CAC3B,QAAgC,EAChC,cAAsB,6BAA6B,EAAA;;AAGnD,IAAA,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;AACzB,QAAA,OAAO,EAAE;IACX;IAEA,MAAM,MAAM,GAAmB,EAAE;IACjC,IAAI,oBAAoB,GAAkB,EAAE;AAE5C,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACxC,QAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC;AAC3B,QAAA,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI;;AAGlD,QAAA,IAAI,CAAC,WAAW,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE;;AAE3E,YAAA,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE;gBACnC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;YAChD;;AAEA,YAAA,oBAAoB,GAAG,CAAC,OAAO,CAAC;QAClC;aAAO;;AAEL,YAAA,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC;QACpC;IACF;;AAGA,IAAA,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE;QACnC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAChD;AAEA,IAAA,OAAO,MAAM;AACf;AAEA;;;;;AAKG;AACH,SAAS,WAAW,CAAC,QAAuB,EAAA;AAC1C,IAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,CAAC,CAAC;IAEhC,OAAO;QACL,QAAQ,EAAE,YAAY,CAAC,MAAM;QAC7B,UAAU,EAAE,YAAY,CAAC,UAAU;QACnC,MAAM,EAAE,YAAY,CAAC,MAAM;AAC3B,QAAA,QAAQ,EAAE,QAAQ;QAClB,SAAS,EAAE,YAAY,CAAC,SAAS;KAClC;AACH;;ACjPA;;;;;;AAMG;AAQH;;;AAGG;AACH,MAAM,0BAA0B,GAAG,GAAG;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;MAEU,eAAe,CAAA;AACT,IAAA,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;AACrC,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAM1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCG;IACH,MAAM,kBAAkB,CAAC,OAAoB,EAAA;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;;QAGzC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK;;QAGnD,MAAM,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;;AAGhE,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,qBAAqB,CAC/C,OAAO,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,CACjC;;QAGD,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,gBAAgB,EAAE;AACnE,YAAA,MAAM,EAAE,UAAU;AACnB,SAAA,CAAC;;AAGF,QAAA,IAAI,gBAAgB,GAAG,CAAA,EAAG,YAAY,CAAA,EAAA,EAAK,iBAAiB,EAAE;QAC9D,IAAI,cAAc,EAAE;AAClB,YAAA,gBAAgB,IAAI,CAAA,EAAA,EAAK,cAAc,CAAA,CAAE;QAC3C;QAEA,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,CAAC;IAC/D;AAEA;;;;;;;;;;;;;;;;;;;;;AAqBG;IACH,MAAM,aAAa,CAAC,KAAgC,EAAA;AAClD,QAAA,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC,OAAO;QACjE,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IACzD;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CG;AACH,IAAA,MAAM,oBAAoB,CACxB,MAAqB,EACrB,QAAiB,EAAA;QAEjB,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC;QAC/D,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC;IAC3D;AAEA;;;;;;;;;;;;;;;;;;;AAmBG;IACH,MAAM,cAAc,CAAC,UAAmB,EAAA;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;QAEzC,MAAM,YAAY,GAAG;AACnB,cAAE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE;AAC9D,cAAE,IAAI,CAAC,aAAa;QAEtB,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC;IAC3D;AAEA;;;;;;;;;;;;;;AAcG;AACH,IAAA,MAAM,KAAK,GAAA;AACT,QAAA,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;IAClC;;;;AAMA;;;;;;AAMG;AACK,IAAA,gBAAgB,CACtB,OAAe,EACf,SAAA,GAAoB,0BAA0B,EAAA;QAE9C,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,OAAO,EAAE;QACX;AAEA,QAAA,IAAI,OAAO,CAAC,MAAM,IAAI,SAAS,EAAE;AAC/B,YAAA,OAAO,OAAO;QAChB;AAEA,QAAA,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK;IAChD;AAEA;;;;;AAKG;AACK,IAAA,qBAAqB,CAAC,KAAa,EAAA;AACzC,QAAA,IAAI,KAAK,KAAK,CAAC,EAAE;AACf,YAAA,OAAO,EAAE;QACX;QAEA,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAEzC,QAAA,IAAI,KAAK,KAAK,CAAC,EAAE;YACf,OAAO,IAAI,CAAC,UAAU;QACxB;AAEA,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,CAAC;IAChE;AAEA;;;;;;AAMG;IACK,mBAAmB,CAAC,MAAqB,EAAE,QAAiB,EAAA;QAClE,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE;AAEzC,QAAA,QAAQ,MAAM,CAAC,IAAI;YACjB,KAAK,SAAS,EAAE;AACd,gBAAA,OAAO,QAAQ,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS;YACnD;YAEA,KAAK,QAAQ,EAAE;AACb,gBAAA,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CACxC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,KAAK,QAAQ,CAC7B;gBACD,MAAM,KAAK,GAAG,cAAc,EAAE,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC;AACvD,gBAAA,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAA,EAAA,EAAK,KAAK,EAAE;YACrC;YAEA,KAAK,cAAc,EAAE;gBACnB,MAAM,WAAW,GAAG,QAA6B;AACjD,gBAAA,MAAM,KAAK,GAAG,WAAW,EAAE,MAAM,IAAI,CAAC;AACtC,gBAAA,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,CAAC;YAClE;YAEA,KAAK,SAAS,EAAE;AACd,gBAAA,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CACvC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,KAAK,QAAQ,CAC7B;gBACD,MAAM,KAAK,GAAG,aAAa,EAAE,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC;AACtD,gBAAA,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAA,EAAA,EAAK,KAAK,EAAE;YACrC;AAEA,YAAA;gBACE,OAAO,IAAI,CAAC,QAAQ;;IAE1B;uGA9RW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAf,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,eAAe,cADF,MAAM,EAAA,CAAA;;2FACnB,eAAe,EAAA,UAAA,EAAA,CAAA;kBAD3B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;AC7ClC;;;;AAIG;AAeH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCG;MAEU,wBAAwB,CAAA;AAClB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;IACzC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,aAAa;;;;AAMtE;;;AAGG;IACc,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,aAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AAEpE;;;AAGG;IACc,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,aAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AAE7D;;AAEG;AACc,IAAA,UAAU,GAAG,MAAM,CAAC,CAAC,sDAAC;AAEvC;;AAEG;AACc,IAAA,gBAAgB,GAAG,MAAM,CAAC,CAAC,4DAAC;AAE7C;;AAEG;AACc,IAAA,UAAU,GAAG,MAAM,CAAC,CAAC,sDAAC;AAEvC;;;AAGG;AACc,IAAA,YAAY,GAAG,MAAM,CAAsB,IAAI,GAAG,EAAE,wDAAC;;;;;AAO7D,IAAA,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE;;AAG1C,IAAA,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE;;AAG1C,IAAA,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;;AAGxC,IAAA,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC,UAAU,EAAE;;AAGpD,IAAA,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE;;AAGxC,IAAA,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE;;;;AAMrD;;;;;AAKG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AACnC,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE;QAC/B,IAAI,KAAK,KAAK,CAAC;AAAE,YAAA,OAAO,CAAC;AAEzB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE;AACnC,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE;;AAGxC,QAAA,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE;YACpB,IAAI,KAAK,GAAG,CAAC;AACb,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;gBAC9B,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,aAAa;YAC1C;AACA,YAAA,OAAO,KAAK;QACd;;QAGA,OAAO,KAAK,GAAG,aAAa;AAC9B,IAAA,CAAC,uDAAC;AAEF;;;;;;;AAOG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAmB;AAClD,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE;AAC/B,QAAA,IAAI,KAAK,KAAK,CAAC,EAAE;YACf,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE;QACxC;AAEA,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE;AACnC,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC,gBAAgB,EAAE;AAC/C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE;;AAGjC,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CACzB,CAAC,EACD,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,GAAG,MAAM,CAC3C;;AAGD,QAAA,MAAM,SAAS,GAAG,SAAS,GAAG,eAAe;AAC7C,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CACvB,KAAK,GAAG,CAAC,EACT,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,GAAG,MAAM,CAC3C;AAED,QAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE;AACjC,IAAA,CAAC,wDAAC;AAEF;;;;;;;AAOG;AACM,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;QAC/B,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE;QAC1C,IAAI,UAAU,KAAK,CAAC;AAAE,YAAA,OAAO,CAAC;AAC9B,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;AACvC,IAAA,CAAC,mDAAC;;;;AAMF;;;;AAIG;AACH,IAAA,YAAY,CAAC,KAAa,EAAA;AACxB,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC;AAEA;;;;AAIG;AACH,IAAA,kBAAkB,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/C;AAEA;;;;AAIG;AACH,IAAA,YAAY,CAAC,KAAa,EAAA;AACxB,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC;AAEA;;;;AAIG;AACH,IAAA,aAAa,CAAC,MAAc,EAAA;AAC1B,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3C;AAEA;;;;;;;;AAQG;IACH,eAAe,CAAC,KAAa,EAAE,MAAc,EAAA;AAC3C,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB;YAAE;AACnC,QAAA,IAAI,KAAK,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC;YAAE;QAE7B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,KAAI;AAC/B,YAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC;AAC3B,YAAA,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC;AACzB,YAAA,OAAO,MAAM;AACf,QAAA,CAAC,CAAC;IACJ;AAEA;;;;AAIG;AACH,IAAA,aAAa,CAAC,IAAY,EAAA;AACxB,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACzC;;;;AAMA;;;;;AAKG;AACH,IAAA,aAAa,CAAC,KAAa,EAAA;QACzB,IAAI,KAAK,IAAI,CAAC;AAAE,YAAA,OAAO,CAAC;AAExB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE;AACnC,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE;AACxC,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE;AAE/B,QAAA,IAAI,KAAK,IAAI,KAAK,EAAE;AAClB,YAAA,OAAO,IAAI,CAAC,WAAW,EAAE;QAC3B;QAEA,IAAI,MAAM,GAAG,CAAC;AACd,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE;YAC9B,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,aAAa;QAC3C;AACA,QAAA,OAAO,MAAM;IACf;AAEA;;;;;AAKG;AACH,IAAA,aAAa,CAAC,KAAa,EAAA;AACzB,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;IAC7D;AAEA;;;;;AAKG;AACH,IAAA,cAAc,CAAC,KAAa,EAAA;QAC1B,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE;AACpD,QAAA,OAAO,KAAK,IAAI,UAAU,IAAI,KAAK,IAAI,QAAQ;IACjD;;;;AAMA;;;;AAIG;IACH,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACtB,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5B,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC;QACnD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;IAC9C;;;;AAMA;;;;;;;;AAQG;AACK,IAAA,iBAAiB,CAAC,MAAc,EAAA;QACtC,IAAI,MAAM,IAAI,CAAC;AAAE,YAAA,OAAO,CAAC;AAEzB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE;QAC/B,IAAI,KAAK,KAAK,CAAC;AAAE,YAAA,OAAO,CAAC;AAEzB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE;AACnC,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,EAAE;;AAGxC,QAAA,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE;AACtB,YAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC;QAChE;;QAGA,IAAI,GAAG,GAAG,CAAC;AACX,QAAA,IAAI,IAAI,GAAG,KAAK,GAAG,CAAC;QACpB,IAAI,iBAAiB,GAAG,CAAC;;AAGzB,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE;AAChC,QAAA,IAAI,MAAM,IAAI,KAAK,EAAE;YACnB,OAAO,KAAK,GAAG,CAAC;QAClB;AAEA,QAAA,OAAO,GAAG,GAAG,IAAI,EAAE;AACjB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,IAAI,CAAC,CAAC;YACxC,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;YACzC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,aAAa;AAEnD,YAAA,IAAI,MAAM,GAAG,SAAS,EAAE;AACtB,gBAAA,IAAI,GAAG,GAAG,GAAG,CAAC;YAChB;AAAO,iBAAA,IAAI,MAAM,IAAI,SAAS,GAAG,SAAS,EAAE;AAC1C,gBAAA,GAAG,GAAG,GAAG,GAAG,CAAC;YACf;iBAAO;AACL,gBAAA,OAAO,GAAG;YACZ;QACF;AAEA,QAAA,OAAO,GAAG;IACZ;uGA1UW,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAxB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,wBAAwB,cADX,MAAM,EAAA,CAAA;;2FACnB,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBADpC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;AC7DlC;;;;AAIG;AA2BH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BG;MAkGU,0BAA0B,CAAA;;;;AAKpB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,IAAA,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;;;;AAMxD;;AAEG;AACM,IAAA,OAAO,GAAG,KAAK,CAAC,QAAQ,kDAAe;AAEhD;;;;AAIG;AACM,IAAA,UAAU,GAAG,KAAK,CAAU,IAAI,sDAAC;AAE1C;;;;AAIG;AACM,IAAA,cAAc,GAAG,KAAK,CAAU,IAAI,0DAAC;AAE9C;;;AAGG;AACM,IAAA,aAAa,GAAG,KAAK,CAAU,IAAI,yDAAC;AAE7C;;;;AAIG;AACM,IAAA,cAAc,GAAG,KAAK,CAAU,KAAK,0DAAC;AAE/C;;;;AAIG;AACM,IAAA,aAAa,GAAG,KAAK,CAAU,KAAK,yDAAC;AAE9C;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAAkC,SAAS,kDAAC;;;;AAMnE;;AAEG;AACM,IAAA,eAAe,GAAG,QAAQ,CAAC,MAAK;AACvC,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE;QACjC,IAAI,WAAW,EAAE;YACf,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC;QAClD;AACA,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE;AACvC,IAAA,CAAC,2DAAC;AAEF;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;AAE5D;;AAEG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AACnC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,QAAA,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE;AACzB,YAAA,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG;QACxB;QACA,OAAO,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK;AAC5C,IAAA,CAAC,uDAAC;AAEF;;AAEG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AACrC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE;QAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;AACrC,IAAA,CAAC,yDAAC;AAEF;;AAEG;AACM,IAAA,kBAAkB,GAAG,QAAQ,CAAC,MAAK;AAC1C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE;AACrC,QAAA,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,cAAc,CACvC,SAAS,EACT,MAAM,CAAC,QAAQ,CAAC,eAAe,CAChC;QACD,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC;AACnD,IAAA,CAAC,8DAAC;AAEF;;AAEG;AACM,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;QAC/B,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,KAAK,OAAO;AAC1C,IAAA,CAAC,mDAAC;AAEF;;AAEG;AACM,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK;AAClC,QAAA,OAAO,KAAK,EAAE,SAAS,IAAI,IAAI;AACjC,IAAA,CAAC,oDAAC;AAEF;;AAEG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK;QAClC,OAAO,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK;AAC5C,IAAA,CAAC,wDAAC;AAEF;;AAEG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAuB;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM;AACpC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE;QAExB,OAAO,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC;AAC/C,IAAA,CAAC,wDAAC;AAEF;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AACjC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAA,EAAA,EAAK,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAA,CAAE,GAAG,EAAE;QACjE,OAAO,CAAA,EAAG,MAAM,CAAA,EAAA,EAAK,GAAG,CAAC,OAAO,CAAA,EAAG,MAAM,CAAA,CAAE;AAC7C,IAAA,CAAC,qDAAC;;;;AAMF;;;AAGG;IACH,OAAO,GAAA;AACL,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE;AAC1B,QAAA,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC;YAC1B,SAAS,EAAE,GAAG,CAAC,EAAE;AACjB,YAAA,OAAO,EAAE,GAAG;AACb,SAAA,CAAC;IACJ;;;;AAMA;;AAEG;IACK,mBAAmB,CACzB,MAAiC,EACjC,IAAkC,EAAA;QAElC,QAAQ,MAAM;AACZ,YAAA,KAAK,SAAS;gBACZ,OAAO;AACL,oBAAA,IAAI,EAAE,GAAG;AACT,oBAAA,QAAQ,EAAE,0CAA0C;oBACpD,KAAK,EAAE,IAAI,CAAC,OAAO;iBACpB;AACH,YAAA,KAAK,SAAS;gBACZ,OAAO;AACL,oBAAA,IAAI,EAAE,GAAG;AACT,oBAAA,QAAQ,EAAE,0CAA0C;oBACpD,KAAK,EAAE,IAAI,CAAC,OAAO;iBACpB;AACH,YAAA,KAAK,MAAM;gBACT,OAAO;AACL,oBAAA,IAAI,EAAE,GAAG;AACT,oBAAA,QAAQ,EAAE,uCAAuC;oBACjD,KAAK,EAAE,IAAI,CAAC,IAAI;iBACjB;AACH,YAAA,KAAK,WAAW;gBACd,OAAO;AACL,oBAAA,IAAI,EAAE,IAAI;AACV,oBAAA,QAAQ,EAAE,4CAA4C;oBACtD,KAAK,EAAE,IAAI,CAAC,SAAS;iBACtB;AACH,YAAA,KAAK,MAAM;gBACT,OAAO;AACL,oBAAA,IAAI,EAAE,IAAI;AACV,oBAAA,QAAQ,EAAE,uCAAuC;oBACjD,KAAK,EAAE,IAAI,CAAC,IAAI;iBACjB;AACH,YAAA,KAAK,OAAO;gBACV,OAAO;AACL,oBAAA,IAAI,EAAE,GAAG;AACT,oBAAA,QAAQ,EAAE,wCAAwC;oBAClD,KAAK,EAAE,IAAI,CAAC,KAAK;iBAClB;AACH,YAAA;gBACE,OAAO;AACL,oBAAA,IAAI,EAAE,EAAE;AACR,oBAAA,QAAQ,EAAE,EAAE;AACZ,oBAAA,KAAK,EAAE,EAAE;iBACV;;IAEP;uGA9NW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,SAAA,EAAA,EAAA,UAAA,EAAA,EAAA,qCAAA,EAAA,6BAAA,EAAA,sCAAA,EAAA,8BAAA,EAAA,uCAAA,EAAA,+BAAA,EAAA,sCAAA,EAAA,WAAA,EAAA,sCAAA,EAAA,kBAAA,EAAA,qCAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,EAAA,cAAA,EAAA,yBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA9F3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8ET,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,y+QAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAgBU,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAjGtC,SAAS;+BACE,yBAAyB,EAAA,UAAA,EACvB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8ET,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,yBAAyB;AAClC,wBAAA,uCAAuC,EAAE,6BAA6B;AACtE,wBAAA,wCAAwC,EAAE,8BAA8B;AACxE,wBAAA,yCAAyC,EAAE,+BAA+B;AAC1E,wBAAA,wCAAwC,EAAE,WAAW;AACrD,wBAAA,wCAAwC,EAAE,kBAAkB;AAC5D,wBAAA,uCAAuC,EAAE,iBAAiB;AAC1D,wBAAA,wBAAwB,EAAE,cAAc;AACxC,wBAAA,MAAM,EAAE,SAAS;AACjB,wBAAA,mBAAmB,EAAE,aAAa;AACnC,qBAAA,EAAA,MAAA,EAAA,CAAA,y+QAAA,CAAA,EAAA;;;AC7JH;;;;AAIG;AA6BH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;MA8HU,qBAAqB,CAAA;;;;AAKf,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,IAAA,WAAW,GAAG,MAAM,CAAC,eAAe,CAAC;AACrC,IAAA,oBAAoB,GAAG,MAAM,CAAC,wBAAwB,CAAC;;;;AAMxE;;;AAGG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAyB,EAAE,oDAAC;AAErD;;AAEG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAU,KAAK,oDAAC;AAEzC;;;AAGG;AACM,IAAA,WAAW,GAAG,KAAK,CAAqB,SAAS,uDAAC;AAE3D;;;AAGG;AACM,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,mDAAC;AAExC;;;AAGG;AACM,IAAA,WAAW,GAAG,KAAK,CAAU,KAAK,uDAAC;AAE5C;;;AAGG;AACM,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,mDAAC;AAExC;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAAkC,SAAS,kDAAC;;;;AAMnE;;;AAGG;IACM,QAAQ,GAAG,MAAM,EAAqB;;;;AAM9B,IAAA,SAAS,GAAG,SAAS,CAAc,WAAW,qDAAC;;;;;AAO/C,IAAA,YAAY,GAAG,MAAM,CAAU,IAAI,wDAAC;;AAGpC,IAAA,sBAAsB,GAAG,MAAM,CAAgB,IAAI,kEAAC;;AAGpD,IAAA,iBAAiB,GAAG,MAAM,CAAU,KAAK,6DAAC;;IAGnD,kBAAkB,GAA+B,IAAI;;IAGrD,cAAc,GAA0B,IAAI;;AAGnC,IAAA,eAAe,GAAG,IAAI,GAAG,EAAkB;;;;AAM5D;;AAEG;AACM,IAAA,eAAe,GAAG,QAAQ,CAAC,MAAK;AACvC,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE;QACjC,IAAI,WAAW,EAAE;YACf,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,CAAC;QAClD;AACA,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE;AACvC,IAAA,CAAC,2DAAC;AAEF;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;AAE5D;;AAEG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAiB,MAAK;AACrD,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC5B,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE;QACrC,OAAO,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC;AAChE,IAAA,CAAC,yDAAC;AAEF;;AAEG;AACc,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AAC3C,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;QAC5B,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI;AACvD,IAAA,CAAC,uDAAC;AAEF;;AAEG;AACc,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;AAC5C,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC5B,QAAA,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI;AACzC,IAAA,CAAC,wDAAC;;;;AAMF;;;AAGG;AACM,IAAA,sBAAsB,GAAG,QAAQ,CAAC,MAAK;AAC9C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM;AACpC,QAAA,OAAO,MAAM,CAAC,aAAa,CAAC,OAAO,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS;AAChF,IAAA,CAAC,kEAAC;AAEF;;;AAGG;AACM,IAAA,eAAe,GAAG,QAAQ,CAAC,MAA6B;AAC/D,QAAA,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE;AAClC,YAAA,OAAO,IAAI,CAAC,QAAQ,EAAE;QACxB;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE;AACtD,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;;AAG5B,QAAA,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAC5D,YAAA,OAAO,EAAE;QACX;AAEA,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;AACzD,IAAA,CAAC,2DAAC;AAEF;;AAEG;AACM,IAAA,kBAAkB,GAAG,QAAQ,CAAC,MAAK;AAC1C,QAAA,OAAO,IAAI,CAAC,oBAAoB,CAAC,WAAW,EAAE;AAChD,IAAA,CAAC,8DAAC;AAEF;;AAEG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAK;AACtC,QAAA,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE;AAC5C,IAAA,CAAC,0DAAC;AAEF;;AAEG;AACM,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;QACzC,OAAO,IAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE,CAAC,UAAU;AAC5D,IAAA,CAAC,6DAAC;;;;AAMF,IAAA,WAAA,GAAA;;QAEE,MAAM,CAAC,MAAK;YACV,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,MAAM;AACpC,YAAA,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,KAAK,CAAC;;AAG7C,YAAA,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;AAC5B,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC5B,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACpC,gBAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzC;AACF,QAAA,CAAC,CAAC;;;AAIF,QAAA,iBAAiB,CAAC;YAChB,SAAS,EAAE,MAAK;AACd,gBAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,EAAE;gBAC1C,IAAI,CAAC,iBAAiB,EAAE;oBACtB,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAqB,EAAE;gBACrE;AAEA,gBAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ;AAC3C,gBAAA,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE;oBAC5B,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAqB,EAAE;gBACrE;;AAGA,gBAAA,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE;AAC7C,gBAAA,MAAM,eAAe,GAAG,IAAI,CAAC,sBAAsB,EAAE;gBACrD,MAAM,aAAa,GACjB,kBAAkB;AAClB,oBAAA,kBAAkB,CAAC,EAAE,KAAK,eAAe;;AAG3C,gBAAA,MAAM,YAAY,GAChB,IAAI,CAAC,YAAY,EAAE;oBACnB,aAAa;AACb,oBAAA,IAAI,CAAC,eAAe,EAAE,CAAC,QAAQ,CAAC,UAAU;gBAE5C,OAAO;oBACL,YAAY;AACZ,oBAAA,YAAY,EAAE,kBAAkB,EAAE,EAAE,IAAI,IAAI;AAC5C,oBAAA,WAAW,EAAE,kBAAkB,EAAE,MAAM,KAAK,OAAO;AACnD,oBAAA,OAAO,EAAE,kBAAkB;iBAC5B;YACH,CAAC;AACD,YAAA,KAAK,EAAE,CAAC,qBAAqB,KAAI;AAC/B,gBAAA,MAAM,UAAU,GAAG,qBAAqB,EAAE;AAC1C,gBAAA,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,YAAY;oBAAE;gBAE7C,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,UAAU;;AAGvE,gBAAA,IAAI,YAAY,KAAK,IAAI,CAAC,sBAAsB,EAAE,EAAE;AAClD,oBAAA,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,YAAY,CAAC;;AAG7C,oBAAA,IAAI,WAAW,IAAI,OAAO,EAAE;AAC1B,wBAAA,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,OAAO,CAAC;oBAC9C;gBACF;;gBAGA,IAAI,YAAY,EAAE;oBAChB,IAAI,CAAC,cAAc,EAAE;gBACvB;YACF,CAAC;AACF,SAAA,CAAC;;;QAIF,iBAAiB,CAAC,MAAK;;AAErB,YAAA,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE;;AAElC,gBAAA,IAAI,IAAI,CAAC,cAAc,EAAE;AACvB,oBAAA,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;gBAClC;gBACA;YACF;AAEA,YAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,EAAE;AAC1C,YAAA,IAAI,CAAC,iBAAiB,EAAE,QAAQ,EAAE,aAAa,EAAE;gBAC/C;YACF;AAEA,YAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,aAAa;YACzD,MAAM,YAAY,GAAG,QAAQ,CAAC,gBAAgB,CAC5C,kCAAkC,CACnC;;AAGD,YAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;gBACxB,IAAI,CAAC,cAAc,GAAG,IAAI,cAAc,CAAC,CAAC,OAAO,KAAI;AACnD,oBAAA,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;AAC3B,wBAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB;wBAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC;AACtD,wBAAA,IAAI,SAAS,KAAK,IAAI,EAAE;4BACtB,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC;AACrC,4BAAA,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM;4BACvC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE;gCAC/B,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC;4BAC1D;wBACF;oBACF;AACF,gBAAA,CAAC,CAAC;YACJ;;AAGA,YAAA,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;AAC5B,gBAAA,IAAI,CAAC,cAAe,CAAC,OAAO,CAAC,IAAI,CAAC;AACpC,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;;;;AAMA;;;;AAIG;AACH,IAAA,QAAQ,CAAC,KAAY,EAAA;AACnB,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB;AAC1C,QAAA,IAAI,CAAC,MAAM;YAAE;QAEb,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,GAAG,MAAM;;AAGxD,QAAA,IAAI,IAAI,CAAC,sBAAsB,EAAE,EAAE;AACjC,YAAA,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,SAAS,CAAC;AACjD,YAAA,IAAI,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,YAAY,CAAC;QAC5D;;QAGA,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC,QAAQ,CAAC,yBAAyB;AAC3E,QAAA,MAAM,kBAAkB,GAAG,YAAY,GAAG,SAAS,GAAG,YAAY;QAClE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,kBAAkB,IAAI,SAAS,CAAC;;AAGtD,QAAA,MAAM,OAAO,GAAG,SAAS,GAAG,EAAE;AAC9B,QAAA,IACE,OAAO;YACP,IAAI,CAAC,OAAO,EAAE;YACd,CAAC,IAAI,CAAC,WAAW,EAAE;AACnB,YAAA,CAAC,IAAI,CAAC,iBAAiB,EAAE,EACzB;YACA,IAAI,CAAC,eAAe,EAAE;QACxB;IACF;;;;AAMA;;AAEG;IACH,cAAc,GAAA;AACZ,QAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,EAAE;AAC1C,QAAA,IAAI,CAAC,iBAAiB;YAAE;QAExB,iBAAiB,CAAC,QAAQ,CAAC;AACzB,YAAA,MAAM,EAAE,CAAC;AACT,YAAA,QAAQ,EAAE,GAAG;AACd,SAAA,CAAC;IACJ;AAEA;;;AAGG;AACH,IAAA,eAAe,CAAC,SAAiB,EAAA;AAC/B,QAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,EAAE;AAC1C,QAAA,IAAI,CAAC,iBAAiB;YAAE;AAExB,QAAA,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,EAAE,aAAa;AAC1D,QAAA,IAAI,CAAC,QAAQ;YAAE;QAEf,MAAM,cAAc,GAAG,QAAQ,CAAC,aAAa,CAC3C,CAAA,kBAAA,EAAqB,SAAS,CAAA,EAAA,CAAI,CACnC;QACD,IAAI,cAAc,EAAE;AAClB,YAAA,cAAc,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;QACxE;IACF;AAEA;;;;AAIG;AACH,IAAA,eAAe,CAAC,IAAU,EAAA;AACxB,QAAA,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE;AAC5B,YAAA,IAAI,CAAC,kBAAkB,GAAG,IAAI,IAAI,CAAC,cAAc,CAC/C,SAAS,EACT,IAAI,CAAC,eAAe,EAAE,CAAC,QAAQ,CAAC,eAAe,CAChD;QACH;QACA,OAAO,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC;IAC7C;;;;AAMA;;AAEG;IACK,eAAe,GAAA;AACrB,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE;AACpC,QAAA,IAAI,CAAC,QAAQ;YAAE;;AAGf,QAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC;;AAGhC,QAAA,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjB,eAAe,EAAE,QAAQ,CAAC,EAAE;YAC5B,KAAK,EAAE,EAAE;AACV,SAAA,CAAC;;QAGF,UAAU,CAAC,MAAK;AACd,YAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC;QACnC,CAAC,EAAE,GAAG,CAAC;IACT;AAEA;;;AAGG;IACH,qBAAqB,CAAC,SAAiB,EAAE,MAAc,EAAA;QACrD,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,GAAG,CAAC,EAAE;YACrC,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC;QAC1D;IACF;AAEA;;;AAGG;AACH,IAAA,eAAe,CAAC,UAAkB,EAAA;AAChC,QAAA,OAAO,IAAI,CAAC,iBAAiB,EAAE,GAAG,UAAU;IAC9C;;;;AAMA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,IAAI,IAAI,CAAC,cAAc,EAAE;AACvB,YAAA,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;AAChC,YAAA,IAAI,CAAC,cAAc,GAAG,IAAI;QAC5B;AACA,QAAA,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE;IAC9B;uGA5cW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,QAAA,EAAA,UAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,KAAA,EAAA,WAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,gBAAA,EAAA,4BAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,WAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,WAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAzHtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+GT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,+9NAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAhHS,WAAW,EAAA,QAAA,EAAA,sCAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,4BAA4B,EAAA,QAAA,EAAA,2BAAA,EAAA,MAAA,EAAA,CAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,0BAA0B,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,QAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FA0HpE,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA7HjC,SAAS;+BACE,mBAAmB,EAAA,UAAA,EACjB,IAAI,EAAA,OAAA,EACP,CAAC,WAAW,EAAE,4BAA4B,EAAE,0BAA0B,CAAC,EAAA,QAAA,EACtE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+GT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,mBAAmB;AAC5B,wBAAA,MAAM,EAAE,KAAK;AACb,wBAAA,WAAW,EAAE,QAAQ;AACrB,wBAAA,kBAAkB,EAAE,4BAA4B;AACjD,qBAAA,EAAA,MAAA,EAAA,CAAA,+9NAAA,CAAA,EAAA;0zBAsEmD,WAAW,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;ACtQjE;;;;AAIG;AAcH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;MA8DU,sBAAsB,CAAA;;;;AAKhB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAM1D;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,iDAAiB;;;;AAMjD;;AAEG;IACM,OAAO,GAAG,MAAM,EAAW;;;;AAMpC;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;AAE5D;;AAEG;IACM,WAAW,GAAG,QAAQ,CAAC,MAC9B,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,uDACjD;AAED;;AAEG;IACM,UAAU,GAAG,QAAQ,CAAC,MAC7B,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,sDAC/C;AAED;;AAEG;IACM,UAAU,GAAG,QAAQ,CAAC,MAC7B,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,KAAK,IAAI,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,YAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CACpE;AAED;;AAEG;AACM,IAAA,oBAAoB,GAAG,QAAQ,CAAC,MAAK;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,cAAc,IAAI,SAAS;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS;AACzC,QAAA,MAAM,UAAU,GAAG,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,KAAK,IAAI;QAE/D,OAAO;AACL,YAAA,CAAC,CAAA,4BAAA,EAA+B,OAAO,CAAA,CAAE,GAAG,IAAI;AAChD,YAAA,sCAAsC,EAAE,UAAU;AAClD,YAAA,0CAA0C,EAAE,SAAS,IAAI,CAAC,UAAU;SACrE;AACH,IAAA,CAAC,gEAAC;AAEF;;AAEG;AACM,IAAA,mBAAmB,GAAG,QAAQ,CAAC,MAAK;QAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,IAAI,WAAW;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS;AACzC,QAAA,MAAM,UAAU,GAAG,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,KAAK,KAAK;QAEhE,OAAO;AACL,YAAA,CAAC,CAAA,4BAAA,EAA+B,OAAO,CAAA,CAAE,GAAG,IAAI;AAChD,YAAA,sCAAsC,EAAE,UAAU;AAClD,YAAA,0CAA0C,EAAE,SAAS,IAAI,CAAC,UAAU;SACrE;AACH,IAAA,CAAC,+DAAC;;;;AAMF;;;AAGG;IACH,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE;AACtB,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QACzB;IACF;AAEA;;;AAGG;IACH,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE;AACtB,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAC1B;IACF;uGA5GW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,oCAAA,EAAA,cAAA,EAAA,qCAAA,EAAA,oBAAA,EAAA,qCAAA,EAAA,kDAAA,EAAA,qCAAA,EAAA,mDAAA,EAAA,EAAA,cAAA,EAAA,oBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA1DvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,y7LAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAWU,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBA7DlC,SAAS;+BACE,oBAAoB,EAAA,UAAA,EAClB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,oBAAoB;AAC7B,wBAAA,sCAAsC,EAAE,cAAc;AACtD,wBAAA,uCAAuC,EAAE,oBAAoB;AAC7D,wBAAA,uCAAuC,EAAE,kDAAkD;AAC3F,wBAAA,uCAAuC,EAAE,mDAAmD;AAC7F,qBAAA,EAAA,MAAA,EAAA,CAAA,y7LAAA,CAAA,EAAA;;;AC3GH;;;;AAIG;AAiBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MAgHU,qBAAqB,CAAA;;;;AAKf,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAMzC,IAAA,cAAc,GAAG,YAAY,CAA4B,eAAe,0DAAC;;;;AAM1F;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,iDAAgB;;;;AAMhD;;AAEG;IACM,OAAO,GAAG,MAAM,EAAU;;;;AAMnC;;AAEG;AACM,IAAA,WAAW,GAAG,MAAM,CAAC,EAAE,uDAAC;AAEjC;;AAEG;AACM,IAAA,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,wDAAC;AAElC;;AAEG;AACM,IAAA,WAAW,GAAG,MAAM,CAAC,KAAK,uDAAC;;;;AAMpC;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;AAE5D;;AAEG;AACM,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA,aAAA,EAAgB,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAA,CAAE,mDAAC;AAErE;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAA,eAAA,EAAkB,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAA,CAAE,qDAAC;AAEzE;;AAEG;IACM,UAAU,GAAG,QAAQ,CAAC,MAC7B,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,KAAK,IAAI,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,YAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CACpE;AAED;;AAEG;AACM,IAAA,eAAe,GAAG,QAAQ,CAAC,MAAK;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO;AACrC,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE;QAErD,IAAI,CAAC,KAAK,EAAE;AACV,YAAA,OAAO,OAAO;QAChB;AAEA,QAAA,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,IAC1B,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC1C,aAAC,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAC7D;AACH,IAAA,CAAC,2DAAC;AAEF;;AAEG;AACM,IAAA,kBAAkB,GAAG,QAAQ,CAAC,MAAK;AAC1C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE;AACjC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE;QAEtC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE;YACxC,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC5C;AAEA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,8DAAC;AAEF;;AAEG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ;AACvC,QAAA,IAAI,CAAC,QAAQ;AAAE,YAAA,OAAO,EAAE;QAExB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;AACjE,QAAA,OAAO,MAAM,EAAE,KAAK,IAAI,QAAQ;AAClC,IAAA,CAAC,yDAAC;;;;AAMF;;AAEG;AACH,IAAA,WAAW,CAAC,QAAgB,EAAA;QAC1B,OAAO,CAAA,cAAA,EAAiB,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAE;IACxD;;;;AAMA;;AAEG;AACH,IAAA,UAAU,CAAC,QAAgB,EAAA;QACzB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,KAAK,QAAQ;IAC5C;;;;AAMA;;AAEG;AACH,IAAA,aAAa,CAAC,KAAY,EAAA;AACxB,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B;QAC9C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;QACjC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3B;AAEA;;AAEG;AACH,IAAA,eAAe,CAAC,KAAoB,EAAA;AAClC,QAAA,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,EAAE;YAC7B,KAAK,CAAC,cAAc,EAAE;AACtB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;YACxB,IAAI,CAAC,YAAY,EAAE;QACrB;AAAO,aAAA,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE;YACjC,IAAI,CAAC,WAAW,EAAE;QACpB;IACF;AAEA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3B;;;;AAMA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE;;AAEhE,YAAA,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,EAAE;AAC9C,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,GAAG,aAAa,GAAG,CAAC,CAAC;QAC/D;IACF;AAEA;;AAEG;IACH,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;IAC7B;AAEA;;AAEG;IACK,YAAY,GAAA;QAClB,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACzD,OAAO,EAAE,KAAK,EAAE;IAClB;AAEA;;AAEG;IACK,iBAAiB,GAAA;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ;AACvC,QAAA,IAAI,CAAC,QAAQ;YAAE,OAAO,CAAC,CAAC;AAExB,QAAA,OAAO,IAAI,CAAC,eAAe,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;IACjE;;;;AAMA;;AAEG;AACH,IAAA,aAAa,CAAC,KAAoB,EAAA;QAChC,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE;AAEvB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE;AACtC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE;AAExC,QAAA,QAAQ,KAAK,CAAC,GAAG;AACf,YAAA,KAAK,WAAW;gBACd,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;gBAClD;AAEF,YAAA,KAAK,SAAS;gBACZ,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;gBACtD;AAEF,YAAA,KAAK,MAAM;gBACT,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;gBAC9B;AAEF,YAAA,KAAK,KAAK;gBACR,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;gBAC7B;AAEF,YAAA,KAAK,OAAO;AACZ,YAAA,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC;gBAC/C;AAEF,YAAA,KAAK,QAAQ;gBACX,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACzB;AAEF,YAAA;;AAEE,gBAAA,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;oBAC9D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,CAAC;gBAClD;gBACA;;IAEN;AAEA;;AAEG;IACK,eAAe,CAAC,aAAqB,EAAE,YAAoB,EAAA;QACjE,IAAI,aAAa,KAAK,CAAC;YAAE;AAEzB,QAAA,MAAM,SAAS,GAAG,YAAY,GAAG,aAAa,GAAG,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,CAAC;AACzE,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;AAChC,QAAA,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC;IACtC;AAEA;;AAEG;IACK,mBAAmB,CAAC,aAAqB,EAAE,YAAoB,EAAA;QACrE,IAAI,aAAa,KAAK,CAAC;YAAE;AAEzB,QAAA,MAAM,SAAS,GAAG,YAAY,GAAG,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,aAAa,GAAG,CAAC;AACzE,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;AAChC,QAAA,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC;IACtC;AAEA;;AAEG;AACK,IAAA,gBAAgB,CAAC,OAAgC,EAAA;AACvD,QAAA,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtD,QAAA,IAAI,UAAU,IAAI,CAAC,EAAE;AACnB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;AACjC,YAAA,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC;QACvC;IACF;AAEA;;AAEG;AACK,IAAA,eAAe,CAAC,OAAgC,EAAA;AACtD,QAAA,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;YAC5C,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;AACxB,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;AACxB,gBAAA,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;gBAC5B;YACF;QACF;IACF;AAEA;;AAEG;IACK,mBAAmB,CAAC,OAAgC,EAAE,YAAoB,EAAA;QAChF,IAAI,YAAY,IAAI,CAAC,IAAI,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE;AACtD,YAAA,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;AACpC,YAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;AACpB,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAC3B;QACF;IACF;AAEA;;AAEG;AACK,IAAA,SAAS,CAAC,GAAW,EAAE,OAAgC,EAAE,YAAoB,EAAA;AACnF,QAAA,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE;;AAGlC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACvC,YAAA,MAAM,WAAW,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM;AAC3D,YAAA,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;AAEnC,YAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AACvE,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC;AAClC,gBAAA,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC;gBACtC;YACF;QACF;IACF;AAEA;;AAEG;AACK,IAAA,oBAAoB,CAAC,KAAa,EAAA;AACxC,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE;QACtC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE;YACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,aAAa;;AAE7C,YAAA,IAAI,OAAO,OAAO,CAAC,cAAc,KAAK,UAAU,EAAE;gBAChD,OAAO,CAAC,cAAc,CAAC;AACrB,oBAAA,KAAK,EAAE,SAAS;AAChB,oBAAA,QAAQ,EAAE,QAAQ;AACnB,iBAAA,CAAC;YACJ;QACF;IACF;;;;AAMA;;AAEG;AACH,IAAA,kBAAkB,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE;AACtB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;QAC9B;IACF;;;;AAMA;;AAEG;AACH,IAAA,YAAY,CAAC,MAAoB,EAAA;QAC/B,IAAI,IAAI,CAAC,UAAU,EAAE,IAAI,MAAM,CAAC,QAAQ,EAAE;YACxC;QACF;QAEA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;IAC9B;uGAtYW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,mCAAA,EAAA,cAAA,EAAA,oCAAA,EAAA,oBAAA,EAAA,qCAAA,EAAA,qBAAA,EAAA,kCAAA,EAAA,eAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,SAAA,EAAA,CAAA,eAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA5GtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiGT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,43OAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAWU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA/GjC,SAAS;+BACE,mBAAmB,EAAA,UAAA,EACjB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiGT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,mBAAmB;AAC5B,wBAAA,qCAAqC,EAAE,cAAc;AACrD,wBAAA,sCAAsC,EAAE,oBAAoB;AAC5D,wBAAA,uCAAuC,EAAE,qBAAqB;AAC9D,wBAAA,oCAAoC,EAAE,eAAe;AACtD,qBAAA,EAAA,MAAA,EAAA,CAAA,43OAAA,CAAA,EAAA;+EAayE,eAAe,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,SAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AClL3F;;;;;AAKG;AAkBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCG;MAiHU,0BAA0B,CAAA;;;;AAKpB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAMzC,IAAA,cAAc,GAAG,YAAY,CAA4B,eAAe,0DAAC;;;;AAM1F;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,iDAAqB;;;;AAMrD;;AAEG;IACM,OAAO,GAAG,MAAM,EAAqB;;;;AAM9C;;;AAGG;AACM,IAAA,SAAS,GAAG,YAAY,CAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,WAAA,EAAA,GAAA,EAAA,CAAA,EAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,WAAW,EAAE,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAA,CACpE;AAEF;;AAEG;AACM,IAAA,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,wDAAC;AAElC;;AAEG;AACM,IAAA,WAAW,GAAG,MAAM,CAAC,KAAK,uDAAC;;;;AAMpC;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;AAE5D;;AAEG;AACM,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAA,mBAAA,EAAsB,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAA,CAAE,mDAAC;AAE3E;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAA,qBAAA,EAAwB,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAA,CAAE,qDAAC;AAE/E;;AAEG;IACM,UAAU,GAAG,QAAQ,CAAC,MAC7B,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,KAAK,IAAI,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,YAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CACpE;AAED;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,IAAI,CAAC,qDAAC;AAEjE;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,IAAI,QAAQ,qDAAC;AAExE;;AAEG;AACM,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAK;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS;AACnC,QAAA,OAAO,GAAG,KAAK,SAAS,GAAG,GAAG,CAAC,QAAQ,EAAE,GAAG,GAAG;AACjD,IAAA,CAAC,4DAAC;AAEF;;AAEG;IACM,SAAS,GAAG,QAAQ,CAAC,MAC5B,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,KAAK,SAAS,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,WAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAC/E;AAED;;AAEG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,0DAAC;AAEjE;;AAEG;AACM,IAAA,kBAAkB,GAAG,QAAQ,CAAC,MAAK;AAC1C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE;AACnC,QAAA,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;AACvE,IAAA,CAAC,8DAAC;AAEF;;AAEG;AACM,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AAC/B,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE;AACnC,QAAA,OAAO,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE;AAC/D,IAAA,CAAC,mDAAC;AAEF;;AAEG;IACM,SAAS,GAAG,QAAQ,CAAC,MAC5B,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,IAAI,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,WAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAClE;AAED;;AAEG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,cAAc,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE,wDAAC;AAEjF;;AAEG;AACM,IAAA,kBAAkB,GAAG,QAAQ,CAAC,MAAK;AAC1C,QAAA,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO;QAErC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE;YACxC,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC5C;AAEA,QAAA,OAAO,IAAI;AACb,IAAA,CAAC,8DAAC;AAEF;;AAEG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAK;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ;AACvC,QAAA,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,EAAE;QAEjD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO;QACrC,MAAM,cAAc,GAAG;aACpB,GAAG,CAAC,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,EAAE;aACrD,IAAI,CAAC,IAAI,CAAC;AAEb,QAAA,OAAO,cAAc;AACvB,IAAA,CAAC,0DAAC;;;;AAMF;;AAEG;AACH,IAAA,WAAW,CAAC,QAAgB,EAAA;QAC1B,OAAO,CAAA,oBAAA,EAAuB,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAE;IAC9D;;;;AAMA;;AAEG;AACH,IAAA,UAAU,CAAC,QAAgB,EAAA;QACzB,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC5C;AAEA;;;;;;AAMG;AACH,IAAA,gBAAgB,CAAC,MAAoB,EAAA;QACnC,IAAI,IAAI,CAAC,UAAU,EAAE,IAAI,MAAM,CAAC,QAAQ,EAAE;AACxC,YAAA,OAAO,IAAI;QACb;;AAGA,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;AACtD,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,OAAO,KAAK;IACd;;;;AAMA;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;AAC1B,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;;AAE/D,YAAA,MAAM,kBAAkB,GAAG,IAAI,CAAC,sBAAsB,EAAE;AACxD,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,GAAG,kBAAkB,GAAG,CAAC,CAAC;QACzE;IACF;AAEA;;AAEG;IACH,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;IAC7B;AAEA;;AAEG;IACK,sBAAsB,GAAA;AAC5B,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE;AAClC,QAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAErC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvE;;;;AAMA;;AAEG;AACH,IAAA,aAAa,CAAC,KAAoB,EAAA;QAChC,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE;QAEvB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO;AACrC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,EAAE;AAExC,QAAA,QAAQ,KAAK,CAAC,GAAG;AACf,YAAA,KAAK,WAAW;gBACd,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;gBAClD;AAEF,YAAA,KAAK,SAAS;gBACZ,KAAK,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC;gBACtD;AAEF,YAAA,KAAK,MAAM;gBACT,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC;gBAC9B;AAEF,YAAA,KAAK,KAAK;gBACR,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC;gBAC7B;AAEF,YAAA,KAAK,GAAG;gBACN,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC;gBAC/C;AAEF,YAAA,KAAK,OAAO;gBACV,KAAK,CAAC,cAAc,EAAE;AACtB,gBAAA,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;oBACpB,IAAI,CAAC,QAAQ,EAAE;gBACjB;gBACA;AAEF,YAAA,KAAK,GAAG;AACR,YAAA,KAAK,GAAG;gBACN,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;oBAClC,KAAK,CAAC,cAAc,EAAE;oBACtB,IAAI,CAAC,SAAS,EAAE;gBAClB;gBACA;AAEF,YAAA;;AAEE,gBAAA,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;oBAC9D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,CAAC;gBAClD;gBACA;;IAEN;AAEA;;AAEG;IACK,eAAe,CAAC,aAAqB,EAAE,YAAoB,EAAA;QACjE,IAAI,aAAa,KAAK,CAAC;YAAE;AAEzB,QAAA,MAAM,SAAS,GAAG,YAAY,GAAG,aAAa,GAAG,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,CAAC;AACzE,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;AAChC,QAAA,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC;IACtC;AAEA;;AAEG;IACK,mBAAmB,CAAC,aAAqB,EAAE,YAAoB,EAAA;QACrE,IAAI,aAAa,KAAK,CAAC;YAAE;AAEzB,QAAA,MAAM,SAAS,GAAG,YAAY,GAAG,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,aAAa,GAAG,CAAC;AACzE,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;AAChC,QAAA,IAAI,CAAC,oBAAoB,CAAC,SAAS,CAAC;IACtC;AAEA;;AAEG;AACK,IAAA,gBAAgB,CAAC,OAAgC,EAAA;AACvD,QAAA,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;AACpE,QAAA,IAAI,UAAU,IAAI,CAAC,EAAE;AACnB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;AACjC,YAAA,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC;QACvC;IACF;AAEA;;AAEG;AACK,IAAA,eAAe,CAAC,OAAgC,EAAA;AACtD,QAAA,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;YAC5C,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;AACtC,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;AACxB,gBAAA,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;gBAC5B;YACF;QACF;IACF;AAEA;;AAEG;IACK,mBAAmB,CAAC,OAAgC,EAAE,YAAoB,EAAA;QAChF,IAAI,YAAY,IAAI,CAAC,IAAI,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE;AACtD,YAAA,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YACpC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE;AAClC,gBAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAC3B;QACF;IACF;AAEA;;AAEG;AACK,IAAA,SAAS,CAAC,GAAW,EAAE,OAAgC,EAAE,YAAoB,EAAA;AACnF,QAAA,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,EAAE;;AAGlC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACvC,YAAA,MAAM,WAAW,GAAG,CAAC,YAAY,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM;AAC3D,YAAA,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;AAEnC,YAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AACvE,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC;AAClC,gBAAA,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC;gBACtC;YACF;QACF;IACF;AAEA;;AAEG;AACK,IAAA,oBAAoB,CAAC,KAAa,EAAA;AACxC,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE;QACtC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE;YACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,aAAa;AAC7C,YAAA,IAAI,OAAO,OAAO,CAAC,cAAc,KAAK,UAAU,EAAE;gBAChD,OAAO,CAAC,cAAc,CAAC;AACrB,oBAAA,KAAK,EAAE,SAAS;AAChB,oBAAA,QAAQ,EAAE,QAAQ;AACnB,iBAAA,CAAC;YACJ;QACF;IACF;;;;AAMA;;AAEG;AACH,IAAA,kBAAkB,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE;AACtB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;QAC9B;IACF;;;;AAMA;;AAEG;AACH,IAAA,YAAY,CAAC,MAAoB,EAAA;AAC/B,QAAA,IAAI,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE;YACjC;QACF;AAEA,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE;QAChC,MAAM,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAEvD,IAAI,mBAAmB,EAAE;;YAEvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5D;aAAO;;YAEL,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,EAAE;AACrC,gBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7C;QACF;IACF;AAEA;;AAEG;IACK,SAAS,GAAA;QACf,IAAI,IAAI,CAAC,UAAU,EAAE;YAAE;QAEvB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO;QACrC,MAAM,iBAAiB,GAAG;aACvB,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ;aACvB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE;aACb,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;AAE7B,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACvC;;;;AAMA;;AAEG;IACH,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE;YACrB;QACF;QAEA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;IACrC;uGAldW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,yCAAA,EAAA,cAAA,EAAA,0CAAA,EAAA,oBAAA,EAAA,wCAAA,EAAA,eAAA,EAAA,wCAAA,EAAA,YAAA,EAAA,EAAA,cAAA,EAAA,yBAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,SAAA,EAAA,CAAA,eAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA7G3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkGT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,6qPAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAWU,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAhHtC,SAAS;+BACE,yBAAyB,EAAA,UAAA,EACvB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkGT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,yBAAyB;AAClC,wBAAA,2CAA2C,EAAE,cAAc;AAC3D,wBAAA,4CAA4C,EAAE,oBAAoB;AAClE,wBAAA,0CAA0C,EAAE,eAAe;AAC3D,wBAAA,0CAA0C,EAAE,YAAY;AACzD,qBAAA,EAAA,MAAA,EAAA,CAAA,6qPAAA,CAAA,EAAA;+EAayE,eAAe,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,OAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,SAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AC1L3F;;;;AAIG;AAcH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDG;MAiDU,sBAAsB,CAAA;;;;AAKhB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAM1D;;;AAGG;AACM,IAAA,MAAM,GAAG,KAAK,CAAC,QAAQ,iDAAiB;;;;AAMjD;;AAEG;IACM,OAAO,GAAG,MAAM,EAAU;;;;AAMnC;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;AAE5D;;AAEG;IACM,UAAU,GAAG,QAAQ,CAAC,MAC7B,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,KAAK,IAAI,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,YAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CACpE;AAED;;AAEG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,IAAI,YAAY;QACnD,OAAO,CAAA,6BAAA,EAAgC,MAAM,CAAA,CAAE;AACjD,IAAA,CAAC,uDAAC;AAEF;;AAEG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QACnC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,KAAK,MAAM,EAAE;YACnC,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,IAAI,CAAC;QACnC;AACA,QAAA,OAAO,SAAS;AAClB,IAAA,CAAC,uDAAC;AAEF;;AAEG;AACM,IAAA,mBAAmB,GAAG,QAAQ,CAAC,MAAK;AAC3C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE;QAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;AACzC,YAAA,OAAO,IAAI;QACb;QACA,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC;AACzE,QAAA,OAAO,cAAc,EAAE,KAAK,IAAI,IAAI;AACtC,IAAA,CAAC,+DAAC;;;;AAMF;;;;;AAKG;AACH,IAAA,gBAAgB,CAAC,MAAoB,EAAA;AACnC,QAAA,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,WAAW;QAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC;QAChD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS;QAEzC,OAAO;AACL,YAAA,CAAC,CAAA,4BAAA,EAA+B,OAAO,CAAA,CAAE,GAAG,IAAI;AAChD,YAAA,sCAAsC,EAAE,UAAU;AAClD,YAAA,0CAA0C,EAAE,SAAS,KAAK,IAAI,IAAI,CAAC,UAAU;AAC7E,YAAA,iDAAiD,EAAE,MAAM,CAAC,QAAQ,KAAK,IAAI;SAC5E;IACH;AAEA;;;;;AAKG;AACH,IAAA,gBAAgB,CAAC,MAAoB,EAAA;AACnC,QAAA,OAAO,MAAM,CAAC,QAAQ,KAAK,IAAI;IACjC;AAEA;;;;;AAKG;AACH,IAAA,gBAAgB,CAAC,MAAoB,EAAA;AACnC,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE;AAC5B,QAAA,OAAO,MAAM,CAAC,SAAS,KAAK,IAAI,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE;IACnE;;;;AAMA;;;;;AAKG;AACH,IAAA,aAAa,CAAC,QAAgB,EAAA;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;AACjE,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE;AAClE,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC7B;IACF;uGAnIW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,sBAAsB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,OAAA,EAAA,SAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,oCAAA,EAAA,cAAA,EAAA,qCAAA,EAAA,oBAAA,EAAA,sCAAA,EAAA,sDAAA,EAAA,oCAAA,EAAA,gCAAA,EAAA,gCAAA,EAAA,4BAAA,EAAA,EAAA,cAAA,EAAA,oBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA7CvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,63MAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAYU,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAhDlC,SAAS;+BACE,oBAAoB,EAAA,UAAA,EAClB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,oBAAoB;AAC7B,wBAAA,sCAAsC,EAAE,cAAc;AACtD,wBAAA,uCAAuC,EAAE,oBAAoB;AAC7D,wBAAA,wCAAwC,EAAE,sDAAsD;AAChG,wBAAA,sCAAsC,EAAE,gCAAgC;AACxE,wBAAA,kCAAkC,EAAE,4BAA4B;AACjE,qBAAA,EAAA,MAAA,EAAA,CAAA,63MAAA,CAAA,EAAA;;;ACzHH;;;;AAIG;AA0BH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAoDU,2BAA2B,CAAA;;;;AAKrB,IAAA,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACvC,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAM1D;;;AAGG;AACM,IAAA,OAAO,GAAG,KAAK,CAAC,QAAQ,kDAA4B;AAE7D;;;AAGG;AACM,IAAA,SAAS,GAAG,KAAK,CAAC,QAAQ,oDAAU;;;;AAM7C;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;;;;AAM5D;;;AAGG;AACH,IAAA,gBAAgB,CAAC,MAAqB,EAAA;AACpC,QAAA,OAAO,MAAuB;IAChC;AAEA;;;AAGG;AACH,IAAA,eAAe,CAAC,MAAqB,EAAA;AACnC,QAAA,OAAO,MAAsB;IAC/B;AAEA;;;AAGG;AACH,IAAA,oBAAoB,CAAC,MAAqB,EAAA;AACxC,QAAA,OAAO,MAA2B;IACpC;AAEA;;;AAGG;AACH,IAAA,gBAAgB,CAAC,MAAqB,EAAA;AACpC,QAAA,OAAO,MAAuB;IAChC;;;;AAMA;;;;;;;AAOG;AACH,IAAA,gBAAgB,CACd,QAAgB,EAChB,IAAO,EACP,QAIS,EAAA;AAET,QAAA,MAAM,KAAK,GAAG;YACZ,IAAI;AACJ,YAAA,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;YAC3B,QAAQ;YACR,QAAQ;SACa;AAEvB,QAAA,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,CAAC;IACrC;uGAlGW,2BAA2B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA3B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,2BAA2B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,uCAAA,EAAA,wBAAA,EAAA,iBAAA,EAAA,uBAAA,EAAA,EAAA,cAAA,EAAA,0BAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA/C5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,yuHAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAtCS,sBAAsB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,qBAAqB,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,0BAA0B,8GAAE,sBAAsB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,SAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAgDhG,2BAA2B,EAAA,UAAA,EAAA,CAAA;kBAnDvC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,0BAA0B,EAAA,UAAA,EACxB,IAAI,EAAA,OAAA,EACP,CAAC,sBAAsB,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,sBAAsB,CAAC,EAAA,QAAA,EAClG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,0BAA0B;AACnC,wBAAA,yCAAyC,EAAE,wBAAwB;AACnE,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,mBAAmB,EAAE,uBAAuB;AAC7C,qBAAA,EAAA,MAAA,EAAA,CAAA,yuHAAA,CAAA,EAAA;;;AC/GH;;;;AAIG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CG;MAUU,qBAAqB,CAAA;AAChC;;;;AAIG;IACM,YAAY,GAAG,MAAM,EAAY;AAE1C;;;AAGG;AACM,IAAA,UAAU,GAAG,MAAM,CAAC,KAAK,sDAAC;AAEnC;;;;;AAKG;IACK,WAAW,GAAG,CAAC;AAEvB;;;;;AAKG;AAEH,IAAA,WAAW,CAAC,KAAgB,EAAA;QAC1B,KAAK,CAAC,cAAc,EAAE;QACtB,KAAK,CAAC,eAAe,EAAE;QAEvB,IAAI,CAAC,WAAW,EAAE;AAElB,QAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AACxB,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;QAC3B;IACF;AAEA;;;;;AAKG;AAEH,IAAA,WAAW,CAAC,KAAgB,EAAA;QAC1B,KAAK,CAAC,cAAc,EAAE;QACtB,KAAK,CAAC,eAAe,EAAE;QAEvB,IAAI,CAAC,WAAW,EAAE;AAElB,QAAA,IAAI,IAAI,CAAC,WAAW,KAAK,CAAC,EAAE;AAC1B,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;QAC5B;IACF;AAEA;;;;;AAKG;AAEH,IAAA,UAAU,CAAC,KAAgB,EAAA;QACzB,KAAK,CAAC,cAAc,EAAE;QACtB,KAAK,CAAC,eAAe,EAAE;QAEvB,IAAI,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AAC9C,YAAA,KAAK,CAAC,YAAY,CAAC,UAAU,GAAG,MAAM;QACxC;IACF;AAEA;;;;;AAKG;AAEH,IAAA,MAAM,CAAC,KAAgB,EAAA;QACrB,KAAK,CAAC,cAAc,EAAE;QACtB,KAAK,CAAC,eAAe,EAAE;;AAGvB,QAAA,IAAI,CAAC,WAAW,GAAG,CAAC;AACpB,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;;AAG1B,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,EAAE,KAAK;QACvC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7B,YAAA,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;QAC/B;IACF;AAEA;;;;;;;AAOG;AACK,IAAA,QAAQ,CAAC,KAAgB,EAAA;AAC/B,QAAA,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE;AACvB,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK;AACtC,QAAA,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,wBAAwB,CAAC;IAC5E;uGAhHW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAArB,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,OAAA,EAAA,EAAA,YAAA,EAAA,cAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,WAAA,EAAA,qBAAA,EAAA,WAAA,EAAA,qBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,gBAAA,EAAA,EAAA,UAAA,EAAA,EAAA,kCAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAArB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBATjC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,QAAQ,EAAE,iBAAiB;AAC3B,oBAAA,IAAI,EAAE;AACJ,wBAAA,oCAAoC,EAAE,cAAc;AACpD,wBAAA,wBAAwB,EAAE,QAAQ;AACnC,qBAAA;AACF,iBAAA;;sBA6BE,YAAY;uBAAC,WAAW,EAAE,CAAC,QAAQ,CAAC;;sBAkBpC,YAAY;uBAAC,WAAW,EAAE,CAAC,QAAQ,CAAC;;sBAkBpC,YAAY;uBAAC,UAAU,EAAE,CAAC,QAAQ,CAAC;;sBAgBnC,YAAY;uBAAC,MAAM,EAAE,CAAC,QAAQ,CAAC;;;AC5IlC;;;;AAIG;AAgBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCG;MA0DU,yBAAyB,CAAA;;;;AAKnB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAE1D;;;AAGG;AACM,IAAA,QAAQ,GAAG,MAAM,CAAC,qBAAqB,CAAC;;;;AAMjD;;;AAGG;AACc,IAAA,SAAS,GAAG,SAAS,CAAC,QAAQ,CAA+B,WAAW,CAAC;;;;AAM1F;;;;AAIG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAC,KAAK,oDAAC;AAEhC;;;;AAIG;AACM,IAAA,QAAQ,GAAG,KAAK,CAAC,IAAI,oDAAC;AAE/B;;;;AAIG;AACM,IAAA,MAAM,GAAG,KAAK,CAAC,EAAE,kDAAC;AAE3B;;;AAGG;IACM,SAAS,GAAG,KAAK,CAAA,IAAA,SAAA,GAAA,CAAA,SAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAU;;;;AAMpC;;;AAGG;IACM,aAAa,GAAG,MAAM,EAAY;;;;AAM3C;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;;;;AAM5D,IAAA,WAAA,GAAA;;QAEE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,KAAe,KAAI;AACvD,YAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;AACpB,gBAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;YAChC;AACF,QAAA,CAAC,CAAC;IACJ;;;;AAMA;;;AAGG;IACH,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;YACpB,IAAI,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE;QACxC;IACF;AAEA;;;;;AAKG;AACH,IAAA,iBAAiB,CAAC,KAAY,EAAA;AAC5B,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B;AAC9C,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK;QAEzB,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7B,YAAA,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QAChC;;AAGA,QAAA,KAAK,CAAC,KAAK,GAAG,EAAE;IAClB;uGApHW,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAzB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,4BAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,aAAA,EAAA,eAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,uCAAA,EAAA,YAAA,EAAA,wCAAA,EAAA,uBAAA,EAAA,EAAA,cAAA,EAAA,uBAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,WAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,WAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,cAAA,EAAA,CAAA,EAAA,SAAA,EAAAA,qBAAA,EAAA,OAAA,EAAA,CAAA,cAAA,EAAA,cAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EArD1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,ooDAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAeU,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAzDrC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,4BAA4B,cAC1B,IAAI,EAAA,OAAA,EACP,CAAC,qBAAqB,CAAC,EAAA,QAAA,EACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,cAAA,EAC/B;AACd,wBAAA;AACE,4BAAA,SAAS,EAAE,qBAAqB;4BAChC,OAAO,EAAE,CAAC,cAAc,CAAC;AAC1B,yBAAA;qBACF,EAAA,IAAA,EACK;AACJ,wBAAA,OAAO,EAAE,uBAAuB;AAChC,wBAAA,yCAAyC,EAAE,YAAY;AACvD,wBAAA,0CAA0C,EAAE,uBAAuB;AACpE,qBAAA,EAAA,MAAA,EAAA,CAAA,ooDAAA,CAAA,EAAA;iGAuB6E,WAAW,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,SAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,WAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,eAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AC3I3F;;;;AAIG;AAcH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BG;MAqMU,0BAA0B,CAAA;;;;AAKpB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAM1D;;;;AAIG;AACM,IAAA,WAAW,GAAG,KAAK,CAAsB,EAAE,uDAAC;;;;AAMrD;;;AAGG;IACM,MAAM,GAAG,MAAM,EAAU;AAElC;;;AAGG;IACM,KAAK,GAAG,MAAM,EAAU;;;;AAMjC;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;;;;AAM5D;;AAEG;IACc,oBAAoB,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI;AAE1D;;AAEG;IACc,oBAAoB,GAAG,EAAE;;;;AAM1C;;;;;AAKG;AACH,IAAA,YAAY,CAAC,IAAoB,EAAA;AAC/B,QAAA,OAAO,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO;IAC7C;AAEA;;;;;AAKG;AACH,IAAA,oBAAoB,CAAC,QAAgB,EAAA;QACnC,OAAO,CAAA,EAAG,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,oBAAoB,CAAA,CAAE;IACpE;AAEA;;;;;;AAMG;AACH,IAAA,qBAAqB,CAAC,QAAgB,EAAA;AACpC,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC5D,QAAA,OAAO,IAAI,CAAC,oBAAoB,GAAG,CAAC,eAAe,GAAG,GAAG,IAAI,IAAI,CAAC,oBAAoB;IACxF;AAEA;;;;;AAKG;AACH,IAAA,gBAAgB,CAAC,QAAgB,EAAA;QAC/B,IAAI,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,oBAAoB,EAAE;AAChD,YAAA,OAAO,QAAQ;QACjB;QAEA,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG;cAC1C,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC;cAC5C,EAAE;AACN,QAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC;AAEtE,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;AACzE,QAAA,IAAI,eAAe,IAAI,CAAC,EAAE;AACxB,YAAA,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC,GAAG,KAAK;QACrE;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,CAAC;QAE3C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,SAAS;IACzF;AAEA;;;;;AAKG;AACH,IAAA,kBAAkB,CAAC,UAA6B,EAAA;AAC9C,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE;AACxB,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,IAAI,eAAe;AAC7D,QAAA,OAAO,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;IACzD;AAEA;;;;;AAKG;AACH,IAAA,aAAa,CAAC,YAAoB,EAAA;AAChC,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;IAChC;AAEA;;;;;AAKG;AACH,IAAA,YAAY,CAAC,YAAoB,EAAA;AAC/B,QAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;IAC/B;uGAtJW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,OAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,qCAAA,EAAA,4BAAA,EAAA,EAAA,cAAA,EAAA,wBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAhM3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwLT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,m4KAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAQU,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBApMtC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,6BAA6B,EAAA,UAAA,EAC3B,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwLT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,wBAAwB;AACjC,wBAAA,uCAAuC,EAAE,4BAA4B;AACtE,qBAAA,EAAA,MAAA,EAAA,CAAA,m4KAAA,CAAA,EAAA;;;AClPH;;;;AAIG;AAcH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MA+LU,uBAAuB,CAAA;;;;AAKjB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAM1D;;;AAGG;AACM,IAAA,WAAW,GAAG,KAAK,CAA+B,EAAE,uDAAC;AAE9D;;;AAGG;AACM,IAAA,SAAS,GAAG,KAAK,CAAC,QAAQ,oDAAU;;;;AAM7C;;;AAGG;IACM,eAAe,GAAG,MAAM,EAAwB;;;;AAMzD;;AAEG;AACM,IAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,gDAAC;;;;AAM5D;;AAEG;IACc,oBAAoB,GAAG,EAAE;;;;AAM1C;;;;;;AAMG;IACH,iBAAiB,CACf,UAA6B,EAC7B,MAAwC,EAAA;AAExC,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC;AACxB,YAAA,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;YAC3B,UAAU;YACV,MAAM;AACP,SAAA,CAAC;IACJ;AAEA;;;;AAIG;AACH,IAAA,YAAY,CAAC,KAAY,EAAA;AACvB,QAAA,MAAM,GAAG,GAAG,KAAK,CAAC,MAA0B;;QAE5C,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AAC5B,YAAA,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM;AAChC,YAAA,GAAG,CAAC,GAAG,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;;;;;;AAMpD,MAAA,CAAA,CAAC;QACJ;IACF;AAEA;;;;;AAKG;AACH,IAAA,cAAc,CAAC,KAAa,EAAA;QAC1B,IAAI,KAAK,KAAK,CAAC;AAAE,YAAA,OAAO,KAAK;QAE7B,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI;QACd,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnD,QAAA,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QAEnC,OAAO,CAAA,EAAG,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAC,CAAA,CAAE;IACrD;AAEA;;;;;AAKG;AACH,IAAA,cAAc,CAAC,OAAe,EAAA;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;AACpC,QAAA,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;QAC3C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;AAElC,QAAA,IAAI,CAAC,GAAG,CAAC,EAAE;YACT,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAE;QACjF;AACA,QAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;IAChD;AAEA;;;;;AAKG;AACH,IAAA,gBAAgB,CAAC,QAAgB,EAAA;QAC/B,IAAI,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,oBAAoB,EAAE;AAChD,YAAA,OAAO,QAAQ;QACjB;QAEA,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG;cAC1C,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC;cAC5C,EAAE;AACN,QAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC;AAEtE,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;AACzE,QAAA,IAAI,eAAe,IAAI,CAAC,EAAE;AACxB,YAAA,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC,GAAG,KAAK;QACrE;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,CAAC;QAE3C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,SAAS;IACzF;AAEA;;;;;AAKG;AACH,IAAA,gBAAgB,CAAC,QAAgB,EAAA;QAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC;QACzC,IAAI,OAAO,IAAI,CAAC;AAAE,YAAA,OAAO,EAAE;QAC3B,OAAO,QAAQ,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE;IACtD;AAEA;;;;AAIG;IACH,gBAAgB,GAAA;AACd,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM;AACvC,QAAA,IAAI,KAAK,KAAK,CAAC,EAAE;AACf,YAAA,OAAO,IAAI,CAAC,UAAU,IAAI,YAAY;QACxC;AACA,QAAA,OAAO,CAAC,IAAI,CAAC,WAAW,IAAI,qBAAqB,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IACzF;AAEA;;;;;AAKG;AACH,IAAA,iBAAiB,CAAC,UAA6B,EAAA;AAC7C,QAAA,IAAI,KAAK,GAAG,CAAA,YAAA,EAAe,UAAU,CAAC,IAAI,EAAE;AAC5C,QAAA,IAAI,UAAU,CAAC,UAAU,EAAE;AACzB,YAAA,KAAK,IAAI,CAAA,EAAA,EAAK,UAAU,CAAC,UAAU,CAAC,KAAK,CAAA,GAAA,EAAM,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG;QAChF;AACA,QAAA,OAAO,KAAK;IACd;AAEA;;;;;AAKG;AACH,IAAA,iBAAiB,CAAC,UAA6B,EAAA;AAC7C,QAAA,IAAI,KAAK,GAAG,CAAA,YAAA,EAAe,UAAU,CAAC,IAAI,EAAE;AAC5C,QAAA,IAAI,UAAU,CAAC,QAAQ,EAAE;YACvB,KAAK,IAAI,CAAA,EAAA,EAAK,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA,CAAA,CAAG;QAC3D;AACA,QAAA,OAAO,KAAK;IACd;AAEA;;;;;AAKG;AACH,IAAA,iBAAiB,CAAC,UAA6B,EAAA;AAC7C,QAAA,IAAI,KAAK,GAAG,CAAA,YAAA,EAAe,UAAU,CAAC,IAAI,EAAE;AAC5C,QAAA,IAAI,UAAU,CAAC,QAAQ,EAAE;YACvB,KAAK,IAAI,CAAA,EAAA,EAAK,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA,CAAA,CAAG;QAC3D;AACA,QAAA,OAAO,KAAK;IACd;AAEA;;;;;AAKG;AACH,IAAA,gBAAgB,CAAC,UAA6B,EAAA;AAC5C,QAAA,OAAO,CAAA,eAAA,EAAkB,UAAU,CAAC,IAAI,KAAK,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG;IACtF;uGAtOW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAvB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,6BAAA,EAAA,4BAAA,EAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA1LxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkLT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,0/QAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAQU,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBA9LnC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,UAAA,EACnB,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkLT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,gBAAgB;AACzB,wBAAA,+BAA+B,EAAE,4BAA4B;AAC9D,qBAAA,EAAA,MAAA,EAAA,CAAA,0/QAAA,CAAA,EAAA;;;AC9OH;;;;AAIG;AAaH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;MAiNU,qBAAqB,CAAA;;;;AAKhC;;AAEG;AACM,IAAA,UAAU,GAAG,KAAK,CAAC,QAAQ,qDAAqB;AAEzD;;;AAGG;AACM,IAAA,SAAS,GAAG,KAAK,CAAC,QAAQ,oDAAU;;;;AAM7C;;;AAGG;IACM,UAAU,GAAG,MAAM,EAAwB;;;;AAMpD;;AAEG;AACM,IAAA,SAAS,GAAG,MAAM,CAAC,IAAI,qDAAC;AAEjC;;AAEG;AACM,IAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,oDAAC;;;;AAMjC;;;AAGG;AACM,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;AAChC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;AAC7B,QAAA,OAAO,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG;AACjC,IAAA,CAAC,oDAAC;AAEF;;;AAGG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAK;AACtC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;AAC7B,QAAA,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU;AAClE,IAAA,CAAC,0DAAC;AAEF;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AACjC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;AAC7B,QAAA,IAAI,KAAK,GAAG,CAAA,YAAA,EAAe,GAAG,CAAC,IAAI,EAAE;AAErC,QAAA,IAAI,GAAG,CAAC,UAAU,EAAE;AAClB,YAAA,KAAK,IAAI,CAAA,EAAA,EAAK,GAAG,CAAC,UAAU,CAAC,KAAK,CAAA,GAAA,EAAM,GAAG,CAAC,UAAU,CAAC,MAAM,UAAU;QACzE;AAEA,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB,KAAK,IAAI,mBAAmB;QAC9B;AAEA,QAAA,OAAO,KAAK;AACd,IAAA,CAAC,qDAAC;;;;AAMF;;AAEG;IACH,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;IAC3B;AAEA;;;AAGG;AACH,IAAA,YAAY,CAAC,KAAY,EAAA;AACvB,QAAA,MAAM,GAAG,GAAG,KAAK,CAAC,MAA0B;AAC5C,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;;AAG7B,QAAA,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,SAAS,EAAE;AAC9C,YAAA,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG;YACjB;QACF;;AAGA,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;;QAGvB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AAC5B,YAAA,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM;AAChC,YAAA,GAAG,CAAC,GAAG,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;;;;;AAKpD,MAAA,CAAA,CAAC;QACJ;IACF;AAEA;;;AAGG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;AAEA,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;AACnB,YAAA,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;AAC3B,YAAA,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;AAC7B,YAAA,MAAM,EAAE,SAAS;AAClB,SAAA,CAAC;IACJ;uGAvIW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UAAA,EAAA,YAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA5MtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,0vEAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkJU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAhNjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,UAAA,EACtB,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DT,EAAA,eAAA,EA6IgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,mBAAmB;AAC7B,qBAAA,EAAA,MAAA,EAAA,CAAA,0vEAAA,CAAA,EAAA;;;ACjQH;;;;AAIG;AAyBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;MAiZU,oBAAoB,CAAA;;;;AAK/B;;AAEG;IACc,oBAAoB,GAAG,EAAE;AAE1C;;AAEG;AACc,IAAA,iBAAiB,GAAiC;;AAEjE,QAAA,iBAAiB,EAAE,KAAK;;AAExB,QAAA,oBAAoB,EAAE,UAAU;AAChC,QAAA,yEAAyE,EAAE,UAAU;AACrF,QAAA,iBAAiB,EAAE,UAAU;AAC7B,QAAA,yCAAyC,EAAE,UAAU;;AAErD,QAAA,0BAA0B,EAAE,aAAa;AACzC,QAAA,mEAAmE,EAAE,aAAa;AAClF,QAAA,UAAU,EAAE,aAAa;AACzB,QAAA,gDAAgD,EAAE,aAAa;;AAE/D,QAAA,+BAA+B,EAAE,cAAc;AAC/C,QAAA,2EAA2E,EAAE,cAAc;AAC3F,QAAA,iDAAiD,EAAE,cAAc;;AAEjE,QAAA,iBAAiB,EAAE,SAAS;AAC5B,QAAA,8BAA8B,EAAE,SAAS;AACzC,QAAA,8BAA8B,EAAE,SAAS;AACzC,QAAA,qBAAqB,EAAE,SAAS;AAChC,QAAA,6BAA6B,EAAE,SAAS;AACxC,QAAA,kBAAkB,EAAE,SAAS;AAC7B,QAAA,mBAAmB,EAAE,SAAS;AAC9B,QAAA,qBAAqB,EAAE,SAAS;;AAEhC,QAAA,wBAAwB,EAAE,MAAM;AAChC,QAAA,kBAAkB,EAAE,MAAM;AAC1B,QAAA,iBAAiB,EAAE,MAAM;AACzB,QAAA,WAAW,EAAE,MAAM;AACnB,QAAA,UAAU,EAAE,MAAM;AAClB,QAAA,iBAAiB,EAAE,MAAM;AACzB,QAAA,UAAU,EAAE,MAAM;AAClB,QAAA,kBAAkB,EAAE,MAAM;AAC1B,QAAA,2BAA2B,EAAE,MAAM;KACpC;;;;AAMD;;AAEG;AACM,IAAA,UAAU,GAAG,KAAK,CAAC,QAAQ,qDAAqB;AAEzD;;;AAGG;AACM,IAAA,SAAS,GAAG,KAAK,CAAC,QAAQ,oDAAU;;;;AAM7C;;;AAGG;IACM,SAAS,GAAG,MAAM,EAAwB;;;;AAMnD;;AAEG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAmB;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ;;AAG3C,QAAA,IAAI,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,EAAE;AACpC,YAAA,OAAO,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC;QACzC;;AAGA,QAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;AAChC,YAAA,OAAO,MAAM;QACf;AAEA,QAAA,OAAO,SAAS;AAClB,IAAA,CAAC,wDAAC;AAEF;;AAEG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAa;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;AACrC,QAAA,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AAC/C,YAAA,OAAO,EAAE;QACX;QACA,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC;;QAEvC,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE;AAChF,IAAA,CAAC,yDAAC;AAEF;;;AAGG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAa;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI;QACnC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,oBAAoB,EAAE;AAC5C,YAAA,OAAO,IAAI;QACb;QAEA,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG;cACtC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;cACpC,EAAE;AACN,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC;AAElE,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;AACzE,QAAA,IAAI,eAAe,IAAI,CAAC,EAAE;AACxB,YAAA,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC,GAAG,KAAK;QACjE;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,CAAC;QAE3C,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,SAAS;AACrG,IAAA,CAAC,yDAAC;AAEF;;AAEG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAa;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI;QACpC,IAAI,KAAK,KAAK,CAAC;AAAE,YAAA,OAAO,KAAK;AAE7B,QAAA,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;QAC3C,MAAM,CAAC,GAAG,IAAI;QACd,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnD,QAAA,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;AAEnC,QAAA,OAAO,CAAA,EAAG,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE;AACjF,IAAA,CAAC,yDAAC;AAEF;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAa;AACzC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;QAC7B,OAAO,CAAA,eAAA,EAAkB,GAAG,CAAC,IAAI,CAAA,EAAA,EAAK,IAAI,CAAC,aAAa,EAAE,CAAA,CAAA,CAAG;AAC/D,IAAA,CAAC,qDAAC;;;;AAMF;;;AAGG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;AAClB,YAAA,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;AAC3B,YAAA,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;AAC7B,YAAA,MAAM,EAAE,UAAU;AACnB,SAAA,CAAC;IACJ;uGAhLW,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAApB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,kBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA5YrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsLT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,owHAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAsNU,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAhZhC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,uBAAuB,EAAA,UAAA,EACrB,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsLT,EAAA,eAAA,EAiNgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,kBAAkB;AAC5B,qBAAA,EAAA,MAAA,EAAA,CAAA,owHAAA,CAAA,EAAA;;;AC7cH;;;;AAIG;AAaH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;MA+RU,qBAAqB,CAAA;;;;AAKhC;;AAEG;AACM,IAAA,UAAU,GAAG,KAAK,CAAC,QAAQ,qDAAqB;AAEzD;;;AAGG;AACM,IAAA,SAAS,GAAG,KAAK,CAAC,QAAQ,oDAAU;;;;AAM7C;;;AAGG;IACM,UAAU,GAAG,MAAM,EAAwB;;;;AAMpD;;AAEG;AACM,IAAA,SAAS,GAAG,MAAM,CAAC,IAAI,qDAAC;AAEjC;;AAEG;AACM,IAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,oDAAC;;;;AAMjC;;;AAGG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;AACpC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;AAC7B,QAAA,OAAO,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG;AACjC,IAAA,CAAC,wDAAC;AAEF;;;AAGG;AACM,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;AACpC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;QAC7B,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,GAAG,CAAC;AAChG,IAAA,CAAC,wDAAC;AAEF;;AAEG;AACM,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ;QAC3C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,IAAI,CAAC,EAAE;AAC3C,YAAA,OAAO,EAAE;QACX;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;AACzC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC;AAEzC,QAAA,IAAI,KAAK,GAAG,CAAC,EAAE;YACb,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAE;QACjG;AAEA,QAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;AAC5D,IAAA,CAAC,6DAAC;AAEF;;AAEG;AACM,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAK;AACjC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;AAC7B,QAAA,IAAI,KAAK,GAAG,CAAA,YAAA,EAAe,GAAG,CAAC,IAAI,EAAE;AAErC,QAAA,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,GAAG,CAAC,EAAE;AAClD,YAAA,KAAK,IAAI,CAAA,EAAA,EAAK,IAAI,CAAC,iBAAiB,EAAE,GAAG;QAC3C;AAEA,QAAA,IAAI,GAAG,CAAC,UAAU,EAAE;AAClB,YAAA,KAAK,IAAI,CAAA,GAAA,EAAM,GAAG,CAAC,UAAU,CAAC,KAAK,CAAA,GAAA,EAAM,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE;QAClE;AAEA,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB,KAAK,IAAI,2BAA2B;QACtC;AAEA,QAAA,OAAO,KAAK;AACd,IAAA,CAAC,qDAAC;;;;AAMF;;AAEG;IACH,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;IAC3B;AAEA;;;AAGG;AACH,IAAA,gBAAgB,CAAC,KAAY,EAAA;AAC3B,QAAA,MAAM,GAAG,GAAG,KAAK,CAAC,MAA0B;AAC5C,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;;AAG7B,QAAA,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,SAAS,EAAE;AAC9C,YAAA,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG;YACjB;QACF;;AAGA,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;;QAGvB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;AAC5B,YAAA,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM;AAChC,YAAA,GAAG,CAAC,GAAG,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;;;;;;AAMpD,MAAA,CAAA,CAAC;QACJ;IACF;AAEA;;;AAGG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;AAEA,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;AACnB,YAAA,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;AAC3B,YAAA,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;AAC7B,YAAA,MAAM,EAAE,SAAS;AAClB,SAAA,CAAC;IACJ;uGAhKW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UAAA,EAAA,YAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA1RtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwET,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,m0GAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAkNU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA9RjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,UAAA,EACtB,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwET,EAAA,eAAA,EA6MgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,mBAAmB;AAC7B,qBAAA,EAAA,MAAA,EAAA,CAAA,m0GAAA,CAAA,EAAA;;;AC/UH;;;;AAIG;AAkBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCG;MAuXU,qBAAqB,CAAA;AACf,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;;;;AAM5C;;AAEG;AACM,IAAA,UAAU,GAAG,KAAK,CAAC,QAAQ,qDAAqB;AAEzD;;;AAGG;AACM,IAAA,SAAS,GAAG,KAAK,CAAC,QAAQ,oDAAU;;;;AAM7C;;;AAGG;IACM,UAAU,GAAG,MAAM,EAAwB;AAEpD;;;AAGG;IACM,eAAe,GAAG,MAAM,EAAW;;;;AAM5C;;AAEG;AACM,IAAA,YAAY,GAAG,SAAS,CAA+B,cAAc,wDAAC;;;;AAM/E;;AAEG;AACM,IAAA,SAAS,GAAG,MAAM,CAAC,KAAK,qDAAC;AAElC;;AAEG;AACM,IAAA,SAAS,GAAG,MAAM,CAAC,IAAI,qDAAC;AAEjC;;AAEG;AACM,IAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,oDAAC;AAEjC;;AAEG;AACM,IAAA,OAAO,GAAG,MAAM,CAAC,KAAK,mDAAC;AAEhC;;AAEG;AACM,IAAA,WAAW,GAAG,MAAM,CAAC,CAAC,uDAAC;AAEhC;;AAEG;AACM,IAAA,QAAQ,GAAG,MAAM,CAAC,CAAC,oDAAC;;;;AAM7B;;;AAGG;AACM,IAAA,YAAY,GAAG;AACtB,QAAA,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;AACtC,QAAA,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;AACtC,QAAA,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;KACvC;;;;AAMD;;AAEG;AACM,IAAA,eAAe,GAAG,QAAQ,CAAC,MAAK;AACvC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;QAC3B,IAAI,GAAG,IAAI,CAAC;AAAE,YAAA,OAAO,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,GAAG,IAAI,GAAG;AACzC,IAAA,CAAC,2DAAC;AAEF;;AAEG;AACM,IAAA,oBAAoB,GAAG,QAAQ,CAAC,MAAK;QAC5C,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;AAC5C,IAAA,CAAC,gEAAC;AAEF;;AAEG;AACM,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC3B,QAAA,IAAI,GAAG,IAAI,CAAC,EAAE;;YAEZ,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ;AACzC,YAAA,OAAO,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,MAAM;QAClD;AACA,QAAA,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;AAC7B,IAAA,CAAC,6DAAC;AAEF;;AAEG;AACM,IAAA,mBAAmB,GAAG,QAAQ,CAAC,MAAK;AAC3C,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE;AAE7B,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;AACnB,YAAA,OAAO,CAAA,sBAAA,EAAyB,GAAG,CAAC,IAAI,EAAE;QAC5C;AAEA,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;AACpB,YAAA,OAAO,CAAA,eAAA,EAAkB,GAAG,CAAC,IAAI,EAAE;QACrC;AAEA,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,OAAO,GAAG,MAAM;AAClD,QAAA,OAAO,CAAA,EAAG,MAAM,CAAA,QAAA,EAAW,GAAG,CAAC,IAAI,CAAA,EAAA,EAAK,IAAI,CAAC,iBAAiB,EAAE,CAAA,CAAA,CAAG;AACrE,IAAA,CAAC,+DAAC;;;;AAMF,IAAA,WAAA,GAAA;;QAEE,eAAe,CAAC,MAAK;;QAErB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjC;;;;AAMA;;AAEG;IACH,gBAAgB,GAAA;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa;QAChD,IAAI,KAAK,EAAE;YACT,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjC,YAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB;IACF;AAEA;;AAEG;IACH,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;IAC3B;AAEA;;AAEG;IACH,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1B;AAEA;;AAEG;IACH,YAAY,GAAA;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa;QAChD,IAAI,KAAK,EAAE;YACT,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC;QACzC;IACF;AAEA;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AACvB,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;;QAGhC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa;QAChD,IAAI,KAAK,EAAE;AACT,YAAA,KAAK,CAAC,WAAW,GAAG,CAAC;QACvB;IACF;AAEA;;AAEG;IACH,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AACvB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;IAC3B;AAEA;;AAEG;IACH,UAAU,GAAA;AACR,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa;QAChD,IAAI,CAAC,KAAK,EAAE;YACV;QACF;AAEA,QAAA,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;YACpB,KAAK,CAAC,KAAK,EAAE;AACb,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,YAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;QAClC;aAAO;AACL,YAAA,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,MAAK;AACrB,gBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,gBAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,YAAA,CAAC,CAAC,CAAC,KAAK,CAAC,MAAK;;AAEZ,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AACzB,YAAA,CAAC,CAAC;QACJ;;AAGA,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;AACnB,YAAA,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;AAC3B,YAAA,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE;AAC7B,YAAA,MAAM,EAAE,OAAO;AAChB,SAAA,CAAC;IACJ;AAEA;;AAEG;AACH,IAAA,MAAM,CAAC,KAAY,EAAA;AACjB,QAAA,MAAM,KAAK,GAAG,KAAK,CAAC,MAA0B;QAC9C,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa;QAEhD,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE;AAChC,YAAA,KAAK,CAAC,WAAW,GAAG,CAAC,OAAO,GAAG,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE;YACrD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC;QACzC;IACF;;;;AAMA;;AAEG;AACK,IAAA,UAAU,CAAC,OAAe,EAAA;QAChC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE;AACrC,YAAA,OAAO,MAAM;QACf;QAEA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;AACxC,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC;AAErC,QAAA,IAAI,KAAK,GAAG,CAAC,EAAE;YACb,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAA,EAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA,CAAE;QAC9F;AAEA,QAAA,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;IACzD;uGA9RW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,UAAA,EAAA,YAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,cAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,cAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAlXtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0HT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,igIAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAwPU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBAtXjC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,UAAA,EACtB,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0HT,EAAA,eAAA,EAmPgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,mBAAmB;AAC7B,qBAAA,EAAA,MAAA,EAAA,CAAA,igIAAA,CAAA,EAAA;oaA2C+D,cAAc,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;ACzdhF;;;;AAIG;AA8EH;;;;;;;;;;;;;;;;;;;;;;;AAuBG;MAEU,mBAAmB,CAAA;AACb,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAE1D;;AAEG;AACM,IAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,oDAAC;AAEjC;;AAEG;AACM,IAAA,SAAS,GAAG,MAAM,CAAgB,IAAI,qDAAC;AAEhD;;AAEG;AACM,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mDAAC;AAEvE;;AAEG;IACK,cAAc,GAA0B,IAAI;IAC5C,cAAc,GAAsC,IAAI;IACxD,iBAAiB,GAAsC,IAAI;AAEnE;;AAEG;IACK,WAAW,GAAyB,IAAI;AAEhD;;AAEG;AACH,IAAA,IAAY,MAAM,GAAA;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,QAAQ;IAChD;AAEA;;;;;;;;;;;;;;;;AAgBG;AACH,IAAA,MAAM,UAAU,GAAA;;AAEd,QAAA,IAAI,IAAI,CAAC,QAAQ,EAAE,EAAE;YACnB;QACF;;AAGA,QAAA,IAAI,IAAI,CAAC,WAAW,EAAE;YACpB,OAAO,IAAI,CAAC,WAAW;QACzB;;AAGA,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,gBAAgB,EAAE;QAC1C,OAAO,IAAI,CAAC,WAAW;IACzB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACH,IAAA,KAAK,CAAC,OAAe,EAAA;;QAEnB,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACrC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;QACpC;;AAGA,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YACxB,OAAO;AACL,gBAAA,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;AAC9B,gBAAA,OAAO,EAAE,IAAI;aACd;QACH;;AAGA,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YACpE,OAAO;AACL,gBAAA,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;AAC9B,gBAAA,OAAO,EAAE,KAAK;AACd,gBAAA,KAAK,EAAE,4DAA4D;aACpE;QACH;AAEA,QAAA,IAAI;;YAEF,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE;AACjD,gBAAA,KAAK,EAAE,KAAK;AACb,aAAA,CAAW;;YAGZ,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YAE5C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE;QAC3C;QAAE,OAAO,KAAK,EAAE;YACd,OAAO;AACL,gBAAA,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;AAC9B,gBAAA,OAAO,EAAE,KAAK;AACd,gBAAA,KAAK,EAAE,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,eAAe;aAChE;QACH;IACF;AAEA;;;;;;;;;;;;;;AAcG;IACH,MAAM,UAAU,CAAC,OAAe,EAAA;;AAE9B,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE;AACpB,YAAA,MAAM,IAAI,CAAC,UAAU,EAAE;QACzB;AAEA,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;IAC5B;AAEA;;AAEG;AACK,IAAA,MAAM,gBAAgB,GAAA;AAC5B,QAAA,IAAI;AACF,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;;YAGxB,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACrD,OAAO,QAAQ,CAA0B;gBACzC,OAAO,WAAW,CAA6B;AAChD,aAAA,CAAC;AAEF,YAAA,IAAI,CAAC,cAAc,GAAG,YAAY,CAAC,MAAM;AACzC,YAAA,IAAI,CAAC,cAAc,GAAG,YAAY,CAAC,OAAO;;AAG1C,YAAA,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC;;AAGlC,YAAA,IAAI,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE;AAClC,gBAAA,IAAI;AACF,oBAAA,MAAM,IAAI,GAAG,MAAM,OAAO,cAAc,CAAoB;AAC5D,oBAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,OAAO;gBACvC;AAAE,gBAAA,MAAM;;AAEN,oBAAA,OAAO,CAAC,IAAI,CACV,iEAAiE,CAClE;gBACH;YACF;AAEA,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACzB;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,MAAM,OAAO,GACX,KAAK,YAAY;kBACb,KAAK,CAAC;kBACN,sCAAsC;AAC5C,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;AAC3B,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;AACxB,YAAA,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC;QAC1B;IACF;AAEA;;AAEG;AACK,IAAA,eAAe,CAAC,aAA2B,EAAA;QACjD,IAAI,CAAC,IAAI,CAAC,cAAc;YAAE;AAE1B,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM;AAC1B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB;QACnC,MAAM,IAAI,GAAG,IAAI;;AAGjB,QAAA,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC;YAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;AACrB,YAAA,GAAG,EAAE,IAAI;AACV,SAAA,CAAC;;AAGF,QAAA,MAAM,iBAAiB,GAAwB;;AAE7C,YAAA,IAAI,CAAC,KAAgB,EAAA;gBACnB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,KAAK;;gBAErC,MAAM,IAAI,GAAG;AACV,qBAAA,GAAG,CAAC,CAAC,CAAM,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE;qBACrC,IAAI,CAAC,EAAE,CAAC;;gBAGX,MAAM,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;;AAG5C,gBAAA,MAAM,KAAK,GAAa,CAAC,CAAA,MAAA,EAAS,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC;gBAEhE,IAAI,KAAK,EAAE;AACT,oBAAA,KAAK,CAAC,IAAI,CAAC,CAAA,OAAA,EAAU,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA,CAAA,CAAG,CAAC;gBACtD;gBAEA,IAAI,UAAU,EAAE;AACd,oBAAA,IAAI,MAAM,CAAC,mBAAmB,EAAE;AAC9B,wBAAA,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC;oBAC/B;AACA,oBAAA,IAAI,MAAM,CAAC,aAAa,EAAE;AACxB,wBAAA,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC;oBACzC;gBACF;gBAEA,OAAO,CAAA,GAAA,EAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA,CAAA,EAAI,IAAI,CAAA,IAAA,CAAM;YAC5C,CAAC;;AAGD,YAAA,IAAI,CAAC,KAAgB,EAAA;gBACnB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK;AACrC,gBAAA,IAAI,WAAW,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;AAExD,gBAAA,IAAI,IAAI,IAAI,IAAI,EAAE;AAChB,oBAAA,IAAI;;AAEF,wBAAA,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;AAC1B,4BAAA,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK;wBAC9D;6BAAO;;4BAEL,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK;wBAC9C;oBACF;AAAE,oBAAA,MAAM;;oBAER;gBACF;AAEA,gBAAA,MAAM,SAAS,GAAG,IAAI,GAAG,CAAA,iBAAA,EAAoB,IAAI,CAAA,CAAA,CAAG,GAAG,EAAE;AACzD,gBAAA,OAAO,CAAA,UAAA,EAAa,SAAS,CAAA,CAAA,EAAI,WAAW,eAAe;YAC7D,CAAC;SACF;;QAGD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC1D;AAEA;;AAEG;AACK,IAAA,YAAY,CAAC,IAAY,EAAA;AAC/B,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;AACxB,YAAA,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAC9B;AAEA,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM;AAC1B,QAAA,MAAM,YAAY,GAAoB;AACpC,YAAA,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC;YACrC,YAAY,EAAE,IAAI,CAAC,wBAAwB,CAAC,MAAM,CAAC,iBAAiB,CAAC;SACtE;;QAGD,IAAI,MAAM,CAAC,mBAAmB,IAAI,MAAM,CAAC,aAAa,EAAE;YACtD,YAAY,CAAC,QAAQ,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC;QAC3C;QAEA,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IACzD;AAEA;;;;;;;AAOG;AACK,IAAA,wBAAwB,CAC9B,iBAA8D,EAAA;AAE9D,QAAA,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU;QAEtC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE;AACpD,YAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,gBAAA,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;YACxB;QACF;AAEA,QAAA,OAAO,CAAC,GAAG,YAAY,CAAC;IAC1B;AAEA;;;;;;;AAOG;AACK,IAAA,UAAU,CAAC,OAAe,EAAA;AAChC,QAAA,MAAM,SAAS,GAA2B;AACxC,YAAA,GAAG,EAAE,OAAO;AACZ,YAAA,GAAG,EAAE,MAAM;AACX,YAAA,GAAG,EAAE,MAAM;AACX,YAAA,GAAG,EAAE,QAAQ;AACb,YAAA,GAAG,EAAE,OAAO;SACb;AAED,QAAA,OAAO,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/D;AAEA;;AAEG;AACK,IAAA,eAAe,CAAC,KAAa,EAAA;AACnC,QAAA,OAAO;AACJ,aAAA,OAAO,CAAC,IAAI,EAAE,OAAO;AACrB,aAAA,OAAO,CAAC,IAAI,EAAE,QAAQ;AACtB,aAAA,OAAO,CAAC,IAAI,EAAE,OAAO;AACrB,aAAA,OAAO,CAAC,IAAI,EAAE,MAAM;AACpB,aAAA,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;IAC1B;AAEA;;AAEG;AACK,IAAA,cAAc,CAAC,IAAY,EAAA;;AAEjC,QAAA,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;AACzB,YAAA,OAAO,IAAI;QACb;;AAGA,QAAA,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;AAC7D,YAAA,IAAI;AACF,gBAAA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC;gBACzB,OAAO,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC,QAAQ;YAClD;AAAE,YAAA,MAAM;AACN,gBAAA,OAAO,KAAK;YACd;QACF;;AAGA,QAAA,OAAO,KAAK;IACd;AAEA;;AAEG;IACH,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI,CAAC,cAAc,GAAG,IAAI;AAC1B,QAAA,IAAI,CAAC,cAAc,GAAG,IAAI;AAC1B,QAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI;AAC7B,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI;IACzB;uGA/XW,mBAAmB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAnB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,cADN,MAAM,EAAA,CAAA;;2FACnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAD/B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;AC1GlC;;;;AAIG;AAiBH;;;;;;;;;;;;;;;;;;;;;;;AAuBG;MA8BU,qBAAqB,CAAA;;;;AAKf,IAAA,eAAe,GAAG,MAAM,CAAC,mBAAmB,CAAC;AAC7C,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,IAAA,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;;;;AAMjD;;;;;;;;AAQG;AACM,IAAA,OAAO,GAAG,KAAK,CAAS,EAAE,mDAAC;;;;AAMpC;;AAEG;AACc,IAAA,UAAU,GAAG,MAAM,CAAS,EAAE,sDAAC;AAEhD;;AAEG;AACM,IAAA,SAAS,GAAG,MAAM,CAAU,KAAK,qDAAC;AAE3C;;AAEG;AACc,IAAA,YAAY,GAAG,MAAM,CAAgB,IAAI,wDAAC;;;;AAM3D;;AAEG;AACM,IAAA,iBAAiB,GAAG,QAAQ,CAAC,MAAK;QACzC,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,OAAO;AACxD,IAAA,CAAC,6DAAC;AAEF;;AAEG;AACM,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAK;AAChC,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI;AACrC,IAAA,CAAC,oDAAC;AAEF;;;;;AAKG;AACM,IAAA,QAAQ,GAAG,QAAQ,CAAC,MAAe;AAC1C,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE;;;QAG9B,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC;AACrD,IAAA,CAAC,oDAAC;AAEF;;AAEG;AACM,IAAA,cAAc,GAAG,QAAQ,CAAC,MAAK;QACtC,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AACxC,IAAA,CAAC,0DAAC;AAEF;;AAEG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QACnC,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,OAAO;AAC7C,IAAA,CAAC,uDAAC;;;;AAMF,IAAA,WAAA,GAAA;;QAEE,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE;AAC9B,YAAA,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;AAC5B,QAAA,CAAC,CAAC;IACJ;;;;AAMA;;;;;AAKG;IACK,MAAM,YAAY,CAAC,OAAe,EAAA;;QAExC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;AACrC,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;AACvB,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB;QACF;;AAGA,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE;AAC7B,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC7C,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;YACzB;QACF;;AAGA,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAE3B,QAAA,IAAI;;YAEF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC;AAE7D,YAAA,IAAI,MAAM,CAAC,OAAO,EAAE;gBAClB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;AAChC,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;YAC7B;iBAAO;;AAEL,gBAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBAC7C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,gBAAgB,CAAC;YACzD;QACF;QAAE,OAAO,KAAK,EAAE;;AAEd,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC7C,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CACnB,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,eAAe,CACzD;QACH;gBAAU;AACR,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B;IACF;AAEA;;;;AAIG;AACK,IAAA,UAAU,CAAC,OAAe,EAAA;AAChC,QAAA,MAAM,SAAS,GAA2B;AACxC,YAAA,GAAG,EAAE,OAAO;AACZ,YAAA,GAAG,EAAE,MAAM;AACX,YAAA,GAAG,EAAE,MAAM;AACX,YAAA,GAAG,EAAE,QAAQ;AACb,YAAA,GAAG,EAAE,OAAO;SACb;AAED,QAAA,OAAO,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/D;uGAzKW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAArB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,kCAAA,EAAA,aAAA,EAAA,gCAAA,EAAA,YAAA,EAAA,mCAAA,EAAA,sBAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA1BtB;;;;;;;;;;;;;;;;AAgBT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,ishBAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAUU,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBA7BjC,SAAS;+BACE,mBAAmB,EAAA,UAAA,EACjB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;;GAgBT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,mBAAmB;AAC5B,wBAAA,oCAAoC,EAAE,aAAa;AACnD,wBAAA,kCAAkC,EAAE,YAAY;AAChD,wBAAA,qCAAqC,EAAE,sBAAsB;AAC9D,qBAAA,EAAA,MAAA,EAAA,CAAA,ishBAAA,CAAA,EAAA;;;ACxEH;;;;AAIG;AAUH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CG;MA+BU,0BAA0B,CAAA;AACrC;;;;;AAKG;AACM,IAAA,eAAe,GAAG,KAAK,CAAC,sBAAsB,2DAAC;AAExD;;;;AAIG;IACM,KAAK,GAAG,MAAM,EAAQ;AAE/B;;;AAGG;AACM,IAAA,QAAQ,GAAG,MAAM,CAAC,KAAK,oDAAC;AAEjC;;;AAGG;AACM,IAAA,YAAY,GAAG,MAAM,CAAgB,IAAI,wDAAC;AAEnD;;;;;;;;;;;;;;;;;;;AAmBG;AACH,IAAA,WAAW,CAAC,KAAqB,EAAA;AAC/B,QAAA,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,GAAG,KAAK,CAAC,OAAO,GAAG,KAAK;AAC9D,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;AAC9B,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;IACzB;AAEA;;;;;;;;AAQG;IACH,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AACxB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7B;AAEA;;;;AAIG;IACO,OAAO,GAAA;QACf,IAAI,CAAC,KAAK,EAAE;AACZ,QAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;IACnB;uGA5EW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA1B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,EAAA,eAAA,EAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,KAAA,EAAA,OAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,UAAA,EAAA,EAAA,0CAAA,EAAA,YAAA,EAAA,gBAAA,EAAA,mCAAA,EAAA,EAAA,cAAA,EAAA,yBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA3B3B;;;;;;;;;;;;;;;;;AAiBT,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,wxGAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAUU,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBA9BtC,SAAS;+BACE,yBAAyB,EAAA,UAAA,EACvB,IAAI,EAAA,QAAA,EACN;;;;;;;;;;;;;;;;;GAiBT,EAAA,eAAA,EAEgB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,OAAO,EAAE,yBAAyB;AAClC,wBAAA,4CAA4C,EAAE,YAAY;AAC1D,wBAAA,MAAM,EAAE,QAAQ;AAChB,wBAAA,kBAAkB,EAAE,iCAAiC;AACtD,qBAAA,EAAA,MAAA,EAAA,CAAA,wxGAAA,CAAA,EAAA;;;ACrFH;;;AAGG;AAEH;;ACLA;;;AAGG;AAEH;AAMA;AACA;;ACZA;;;;AAIG;AAsBH;AACA;AACA;AAEA;;;;;;;;;;AAUG;AACI,MAAM,WAAW,GAAqD;AAC3E,IAAA,aAAa,EAAE;AACb,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,OAAO,EAAE,2BAA2B;AACpC,QAAA,SAAS,EAAE,IAAI;AAChB,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,OAAO,EAAE,mBAAmB;AAC5B,QAAA,SAAS,EAAE,IAAI;AAChB,KAAA;AACD,IAAA,YAAY,EAAE;AACZ,QAAA,IAAI,EAAE,cAAc;AACpB,QAAA,OAAO,EAAE,uBAAuB;AAChC,QAAA,SAAS,EAAE,IAAI;AAChB,KAAA;AACD,IAAA,YAAY,EAAE;AACZ,QAAA,IAAI,EAAE,cAAc;AACpB,QAAA,OAAO,EAAE,mBAAmB;AAC5B,QAAA,SAAS,EAAE,IAAI;AAChB,KAAA;AACD,IAAA,eAAe,EAAE;AACf,QAAA,IAAI,EAAE,iBAAiB;AACvB,QAAA,OAAO,EAAE,4BAA4B;AACrC,QAAA,SAAS,EAAE,KAAK;AACjB,KAAA;AACD,IAAA,oBAAoB,EAAE;AACpB,QAAA,IAAI,EAAE,sBAAsB;AAC5B,QAAA,OAAO,EAAE,yBAAyB;AAClC,QAAA,SAAS,EAAE,KAAK;AACjB,KAAA;AACD,IAAA,2BAA2B,EAAE;AAC3B,QAAA,IAAI,EAAE,6BAA6B;AACnC,QAAA,OAAO,EAAE,0BAA0B;AACnC,QAAA,SAAS,EAAE,KAAK;AACjB,KAAA;AACD,IAAA,YAAY,EAAE;AACZ,QAAA,IAAI,EAAE,cAAc;AACpB,QAAA,OAAO,EAAE,yBAAyB;AAClC,QAAA,SAAS,EAAE,KAAK;AACjB,KAAA;AACD,IAAA,SAAS,EAAE;AACT,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,OAAO,EAAE,eAAe;AACxB,QAAA,SAAS,EAAE,KAAK;AACjB,KAAA;AACD,IAAA,OAAO,EAAE;AACP,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,OAAO,EAAE,8BAA8B;AACvC,QAAA,SAAS,EAAE,IAAI;AAChB,KAAA;;AAGH;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,WAAW,CACzB,IAAmB,EACnB,aAAsB,EACtB,aAAqB,CAAC,EAAA;IAEtB,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC,OAAO;IAEzD,OAAO;QACL,IAAI;AACJ,QAAA,OAAO,EAAE,aAAa,IAAI,QAAQ,CAAC,OAAO;QAC1C,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,UAAU;AACV,QAAA,WAAW,EAAE,UAAU,GAAG,CAAC,GAAG,IAAI,IAAI,EAAE,GAAG,SAAS;KACrD;AACH;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;AAcG;AACG,SAAU,mBAAmB,CAAC,KAAuB,EAAA;IACzD,OAAO;AACL,QAAA,GAAG,KAAK;QACR,UAAU,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC;QACvC,WAAW,EAAE,IAAI,IAAI,EAAE;KACxB;AACH;AAEA;;;;;;;;;;;;;;;;AAgBG;AACG,SAAU,QAAQ,CACtB,KAAuB,EACvB,MAA+B,EAAA;;AAG/B,IAAA,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;AACpB,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,IAAI,CAAC;AAC5C,IAAA,IAAI,cAAc,IAAI,MAAM,CAAC,UAAU,EAAE;AACvC,QAAA,OAAO,KAAK;IACd;AAEA,IAAA,OAAO,IAAI;AACb;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,aAAa,CAC3B,KAAuB,EACvB,MAA+B,EAAA;AAE/B,IAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,IAAI,CAAC;AAEtC,IAAA,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE;QAC9B,OAAO,MAAM,CAAC,UAAU;IAC1B;AAEA,IAAA,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;IACvD,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC;AAC9C;AAEA;;;;;;;;;;;AAWG;AACG,SAAU,aAAa,CAAC,IAAmB,EAAA;AAC/C,IAAA,MAAM,YAAY,GAAoB;QACpC,iBAAiB;QACjB,sBAAsB;QACtB,6BAA6B;KAC9B;AACD,IAAA,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC;AACpC;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,WAAW,CAAC,IAAmB,EAAA;AAC7C,IAAA,OAAO,IAAI,KAAK,cAAc,IAAI,IAAI,KAAK,WAAW;AACxD;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,cAAc,CAAC,IAAmB,EAAA;AAChD,IAAA,OAAO,IAAI,KAAK,eAAe,IAAI,IAAI,KAAK,SAAS;AACvD;;AC7RA;;;AAGG;;ACHH;;;;AAIG;AAyFH;;;;;;AAMG;AACH,SAAS,cAAc,CAAC,UAAkB,EAAA;AACxC,IAAA,MAAM,SAAS,GAAG,iBAAiB,CAAC,UAAU,CAAC;IAE/C,IAAI,CAAC,SAAS,EAAE;;QAEd,OAAO;AACL,YAAA,oBAAoB,EAAE,KAAK;AAC3B,YAAA,cAAc,EAAE,KAAK;AACrB,YAAA,gBAAgB,EAAE,KAAK;AACvB,YAAA,YAAY,EAAE,KAAK;AACnB,YAAA,WAAW,EAAE,KAAK;AAClB,YAAA,SAAS,EAAE,KAAK;AAChB,YAAA,UAAU,EAAE,KAAK;AACjB,YAAA,WAAW,EAAE,KAAK;AAClB,YAAA,OAAO,EAAE,KAAK;AACd,YAAA,OAAO,EAAE,KAAK;AACd,YAAA,SAAS,EAAE,KAAK;AAChB,YAAA,MAAM,EAAE,KAAK;AACb,YAAA,oBAAoB,EAAE,KAAK;SAC5B;IACH;;IAGA,MAAM,aAAa,GAAG,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;IAE7D,OAAO;AACL,QAAA,oBAAoB,EAAE,OAAO,oBAAoB,KAAK,WAAW;AACjE,QAAA,cAAc,EAAE,OAAO,cAAc,KAAK,WAAW;QACrD,gBAAgB,EAAE,GAAG,CAAC,QAAQ,GAAG,gBAAgB,EAAE,aAAa,CAAC,IAAI,KAAK;AAC1E,QAAA,YAAY,EAAE,OAAO,SAAS,CAAC,SAAS,KAAK,WAAW;AACxD,QAAA,WAAW,EAAE,OAAO,SAAS,CAAC,KAAK,KAAK,UAAU;AAClD,QAAA,SAAS,EAAE,IAAI;AACf,QAAA,UAAU,EAAE,aAAa;QACzB,WAAW,EAAE,cAAc,IAAI,MAAM,IAAI,SAAS,CAAC,cAAc,GAAG,CAAC;QACrE,OAAO,EAAE,OAAO,IAAI,KAAK,WAAW,IAAI,OAAO,UAAU,KAAK,WAAW;AACzE,QAAA,OAAO,EAAE,OAAO,IAAI,KAAK,WAAW;AACpC,QAAA,SAAS,EACP,OAAO,GAAG,KAAK,WAAW;AAC1B,YAAA,OAAO,GAAG,CAAC,eAAe,KAAK,UAAU;AAC3C,QAAA,MAAM,EACJ,OAAO,QAAQ,KAAK,WAAW;AAC/B,YAAA,OAAO,QAAQ,CAAC,aAAa,KAAK,UAAU;YAC5C,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,UAAU;AAC/C,QAAA,oBAAoB,EAClB,aAAa;AACb,YAAA,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO;KAChE;AACH;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;MACU,aAAa,GAAG,IAAI,cAAc,CAAe,eAAe,EAAE;AAC7E,IAAA,UAAU,EAAE,MAAM;IAClB,OAAO,EAAE,MAAM,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AACnD,CAAA;;AC7KD;;;AAGG;;ACHH;;;;;AAKG;AAEH;AACA,IAAI,OAAO,GAAG,CAAC;AAEf;AACA,IAAI,aAAa,GAAG,CAAC;AAErB;;;;;;;;;;;;;;;;;;;AAmBG;AACG,SAAU,UAAU,CAAC,MAAA,GAAiB,IAAI,EAAA;AAC9C,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AAE5B,IAAA,IAAI,SAAS,KAAK,aAAa,EAAE;AAC/B,QAAA,OAAO,EAAE;IACX;SAAO;QACL,OAAO,GAAG,CAAC;QACX,aAAa,GAAG,SAAS;IAC3B;AAEA,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;IAEzD,OAAO,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,SAAS,IAAI,OAAO,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE;AACtD;AAEA;;;;;;;;;;;;;AAaG;SACa,cAAc,GAAA;IAC5B,OAAO,GAAG,CAAC;IACX,aAAa,GAAG,CAAC;AACnB;;ACjEA;;;;;AAKG;AA6CH;AACA;AACA;AAEA;;;;;;;;;;;;;;AAcG;AACG,SAAU,iBAAiB,CAC/B,OAAe,EACf,OAA8B,EAAA;IAE9B,OAAO;QACL,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC;AACpC,QAAA,MAAM,EAAE,MAAM;QACd,OAAO;AACP,QAAA,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE;AAC3C,QAAA,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,SAAS;QACpC,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,QAAQ,EAAE,OAAO,EAAE,QAAQ;QAC3B,OAAO,EAAE,OAAO,EAAE,OAAO;KAC1B;AACH;AAEA;;;;;;;;;;;;;;;AAeG;SACa,kBAAkB,CAChC,OAAe,EACf,UAAmB,EACnB,OAAmC,EAAA;IAEnC,OAAO;QACL,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC;AACpC,QAAA,MAAM,EAAE,OAAO;QACf,OAAO;AACP,QAAA,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE;QAC3C,MAAM,EAAE,OAAO,EAAE,MAAM;AACvB,QAAA,UAAU,EAAE,UAAU,IAAI,OAAO,EAAE,UAAU;QAC7C,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,QAAQ,EAAE,OAAO,EAAE,QAAQ;QAC3B,OAAO,EAAE,OAAO,EAAE,OAAO;KAC1B;AACH;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,mBAAmB,CACjC,OAAe,EACf,OAA8B,EAAA;IAE9B,OAAO;QACL,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC;AACpC,QAAA,MAAM,EAAE,QAAQ;QAChB,OAAO;AACP,QAAA,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE;QAC3C,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,QAAQ,EAAE,OAAO,EAAE,QAAQ;QAC3B,OAAO,EAAE,OAAO,EAAE,OAAO;KAC1B;AACH;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;AAmBG;AACG,SAAU,mBAAmB,CACjC,QAAgC,EAChC,SAAiB,EACjB,MAAqB,EACrB,KAAwB,EAAA;AAExB,IAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,KACtB,GAAG,CAAC,EAAE,KAAK;UACP,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,KAAK,GAAG,SAAS;UAC/D,GAAG,CACR;AACH;AAEA;;;;;;;;;;;;;;;;AAgBG;SACa,oBAAoB,CAClC,QAAgC,EAChC,SAAiB,EACjB,KAAa,EAAA;AAEb,IAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,KACtB,GAAG,CAAC,EAAE,KAAK,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,GAAG,KAAK,EAAE,GAAG,GAAG,CACtE;AACH;AAEA;;;;;;;;;;;;AAYG;SACa,oBAAoB,CAClC,QAAgC,EAChC,SAAiB,EACjB,OAAe,EAAA;AAEf,IAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,KACtB,GAAG,CAAC,EAAE,KAAK;AACT,UAAE,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE;UACrD,GAAG,CACR;AACH;AAEA;;;;;;;;;;;AAWG;AACG,SAAU,aAAa,CAC3B,QAAgC,EAChC,SAAiB,EAAA;AAEjB,IAAA,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC;AACvD;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;AAcG;AACG,SAAU,WAAW,CACzB,QAAgC,EAChC,SAAiB,EAAA;AAEjB,IAAA,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC;AACrD;AAEA;;;;;;;;;;;;;AAaG;AACG,SAAU,cAAc,CAC5B,QAAgC,EAAA;IAEhC,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,SAAS;AACxE;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,mBAAmB,CACjC,QAAgC,EAChC,MAAqB,EAAA;AAErB,IAAA,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC;AACxD;AAEA;;;;;;;;;;;AAWG;AACG,SAAU,gBAAgB,CAC9B,QAAgC,EAAA;AAEhC,IAAA,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC;AACzD;AAEA;;;;;;;;;;;;;;;AAeG;AACG,SAAU,oBAAoB,CAClC,QAAgC,EAAA;IAEhC,OAAO,QAAQ,CAAC,MAAM,CACpB,CAAC,GAAG,KAAK,GAAG,CAAC,MAAM,KAAK,OAAO,IAAI,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CACjE;AACH;;AC1WA;;;;;AAKG;AAwGH;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,mBAAmB,CACjC,OAAoC,EAAA;IAEpC,OAAO;AACL,QAAA,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,UAAU,CAAC,QAAQ,CAAC;QACvC,WAAW,EAAE,OAAO,EAAE,WAAW;QACjC,UAAU,EAAE,OAAO,EAAE,UAAU;QAC/B,cAAc,EAAE,OAAO,EAAE,cAAc;QACvC,aAAa,EAAE,OAAO,EAAE,aAAa;QACrC,QAAQ,EAAE,OAAO,EAAE,QAAQ;KAC5B;AACH;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,kBAAkB,CAChC,OAAgC,EAChC,MAAkC,EAAA;IAElC,OAAO;AACL,QAAA,IAAI,EAAE,QAAQ;QACd,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,UAAU,CAAC,QAAQ,CAAC;QACtC,OAAO;QACP,KAAK,EAAE,MAAM,EAAE,KAAK;QACpB,WAAW,EAAE,MAAM,EAAE,WAAW;QAChC,UAAU,EAAE,MAAM,EAAE,UAAU;QAC9B,QAAQ,EAAE,MAAM,EAAE,QAAQ;KAC3B;AACH;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,uBAAuB,CACrC,OAAgC,EAChC,MAAuC,EAAA;IAEvC,OAAO;AACL,QAAA,IAAI,EAAE,cAAc;QACpB,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,UAAU,CAAC,QAAQ,CAAC;QACtC,OAAO;QACP,KAAK,EAAE,MAAM,EAAE,KAAK;QACpB,SAAS,EAAE,MAAM,EAAE,SAAS;QAC5B,SAAS,EAAE,MAAM,EAAE,SAAS;QAC5B,UAAU,EAAE,MAAM,EAAE,UAAU;QAC9B,QAAQ,EAAE,MAAM,EAAE,QAAQ;KAC3B;AACH;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,mBAAmB,CACjC,OAAgC,EAChC,MAAmC,EAAA;IAEnC,OAAO;AACL,QAAA,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,UAAU,CAAC,QAAQ,CAAC;QACtC,OAAO;QACP,MAAM,EAAE,MAAM,EAAE,MAAM;QACtB,OAAO,EAAE,MAAM,EAAE,OAAO;QACxB,QAAQ,EAAE,MAAM,EAAE,QAAQ;KAC3B;AACH;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG,SAAU,oBAAoB,CAClC,QAAgC,EAChC,KAAyB,EAAA;AAEzB,IAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,KAAI;AAC1B,QAAA,IAAI,GAAG,CAAC,EAAE,KAAK,KAAK,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE;AAC9C,YAAA,OAAO,GAAG;QACZ;QAEA,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,KAAI;YAChD,IAAI,MAAM,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,EAAE;AAChC,gBAAA,OAAO,MAAM;YACf;;AAGA,YAAA,QAAQ,KAAK,CAAC,IAAI;AAChB,gBAAA,KAAK,SAAS;oBACZ,OAAO;AACL,wBAAA,GAAG,MAAM;AACT,wBAAA,SAAS,EAAE,IAAI;wBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;qBACR;AAEpB,gBAAA,KAAK,QAAQ;oBACX,OAAO;AACL,wBAAA,GAAG,MAAM;AACT,wBAAA,SAAS,EAAE,IAAI;wBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;qBACT;AAEnB,gBAAA,KAAK,cAAc;oBACjB,OAAO;AACL,wBAAA,GAAG,MAAM;AACT,wBAAA,SAAS,EAAE,IAAI;wBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;qBACJ;AAExB,gBAAA,KAAK,SAAS;oBACZ,OAAO;AACL,wBAAA,GAAG,MAAM;AACT,wBAAA,SAAS,EAAE,IAAI;wBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;qBACR;AAEpB,gBAAA;AACE,oBAAA,OAAO,MAAM;;AAEnB,QAAA,CAAC,CAAC;QAEF,OAAO;AACL,YAAA,GAAG,GAAG;AACN,YAAA,OAAO,EAAE,cAAc;SACxB;AACH,IAAA,CAAC,CAAC;AACJ;AAEA;;;;;;;;;;;;;;;AAeG;AACG,SAAU,iBAAiB,CAC/B,QAAgC,EAChC,SAAiB,EAAA;AAEjB,IAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,KAAI;QAC1B,IAAI,GAAG,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE;AACxC,YAAA,OAAO,GAAG;QACZ;AAEA,QAAA,MAAM,cAAc,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,MAAM;AAClD,YAAA,GAAG,MAAM;AACT,YAAA,QAAQ,EAAE,IAAI;AACf,SAAA,CAAC,CAAC;QAEH,OAAO;AACL,YAAA,GAAG,GAAG;AACN,YAAA,OAAO,EAAE,cAA0C;SACpD;AACH,IAAA,CAAC,CAAC;AACJ;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;AAYG;AACG,SAAU,mBAAmB,CAAC,OAAoB,EAAA;AACtD,IAAA,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;AACpD,QAAA,OAAO,IAAI;IACb;AAEA,IAAA,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,SAAS,KAAK,IAAI,CAAC;AACrE;AAEA;;;;;;;;;;;AAWG;AACG,SAAU,iBAAiB,CAAC,OAAoB,EAAA;AACpD,IAAA,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AACpB,QAAA,OAAO,EAAE;IACX;AAEA,IAAA,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAC3B,CAAC,MAAM,KAAK,MAAM,CAAC,SAAS,KAAK,IAAI,CACnB;AACtB;AAEA;;;;;;;;;;;;;;AAcG;AACG,SAAU,aAAa,CAC3B,OAAoB,EACpB,QAAgB,EAAA;AAEhB,IAAA,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AACpB,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC;AACjE;;ACtbA;;;;;AAKG;AAEH;;ACPA;;;;AAIG;AA+BH;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCG;MAEU,wBAAwB,CAAA;AAClB,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;AACzC,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;;;;AAMhD;;;AAGG;AACc,IAAA,KAAK,GAAG,MAAM,CAAkB,EAAE,iDAAC;AAEpD;;;AAGG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,uDAAC;AAE1D;;;AAGG;IACM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,oDAAC;;;;AAMrD;;;AAGG;AACc,IAAA,YAAY,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5C,IAAA,aAAa,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAE/D,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,mBAAmB,EAAE;IAC5B;AAEA;;;AAGG;IACK,mBAAmB,GAAA;;AAEzB,QAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;YACjC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC;YACpD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC;;AAGtD,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;gBAC7B,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC;gBACvD,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC;AAC3D,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;;AAGG;IACK,kBAAkB,GAAA;AACxB,QAAA,IAAI,OAAO,SAAS,KAAK,WAAW,EAAE;YACpC,OAAO,SAAS,CAAC,MAAM;QACzB;;AAEA,QAAA,OAAO,IAAI;IACb;;;;AAMA;;;;;;;;;;;;;;;;;;;AAmBG;AACH,IAAA,OAAO,CAAC,OAAoB,EAAE,UAAA,GAAqB,CAAC,EAAA;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,aAAa;AAE3D,QAAA,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;AACxB,YAAA,OAAO;QACT;AAEA,QAAA,MAAM,aAAa,GAAkB;YACnC,OAAO;YACP,QAAQ,EAAE,IAAI,IAAI,EAAE;YACpB,UAAU;SACX;QAED,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,KAAI;;YAE5B,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,CACrC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CACnC;AAED,YAAA,IAAI,aAAa,IAAI,CAAC,EAAE;;gBAEtB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KACtB,CAAC,KAAK,aAAa,GAAG,aAAa,GAAG,CAAC,CACxC;YACH;;YAGA,IAAI,QAAQ,GAAG,CAAC,GAAG,OAAO,EAAE,aAAa,CAAC;;YAG1C,IAAI,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,YAAY,EAAE;gBACzC,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,YAAY;AACzD,gBAAA,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC;YACxC;AAEA,YAAA,OAAO,QAAQ;AACjB,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;;;;;;;;;;AAcG;AACH,IAAA,OAAO,CAAC,SAAiB,EAAA;QACvB,IAAI,KAAK,GAAG,KAAK;QAEjB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,KAAI;AAC5B,YAAA,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,SAAS,CAAC;AAElE,YAAA,IAAI,KAAK,IAAI,CAAC,EAAE;gBACd,KAAK,GAAG,IAAI;gBACZ,OAAO,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAClE;AAEA,YAAA,OAAO,OAAO;AAChB,QAAA,CAAC,CAAC;AAEF,QAAA,OAAO,KAAK;IACd;AAEA;;;;;;;;;;;;;;;;;;AAkBG;IACH,UAAU,GAAA;AACR,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE;AAC5B,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;AAClB,QAAA,OAAO,OAAO;IAChB;AAEA;;;;;;;;;;;;;AAaG;IACH,QAAQ,GAAA;AACN,QAAA,OAAO,IAAI,CAAC,KAAK,EAAE;IACrB;AAEA;;;;;;;;;;;AAWG;IACH,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACpB;;;;AAMA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH,IAAA,aAAa,CAAC,QAAgB,EAAA;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,aAAa;AAE3D,QAAA,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE;YAC9B,OAAO,MAAM,CAAC,UAAU;QAC1B;AAEA,QAAA,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;QACvD,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,aAAa,CAAC;IAC9C;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH,IAAA,WAAW,CAAC,KAAuB,EAAA;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,aAAa;;AAG3D,QAAA,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE;AACrB,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;AACpB,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,IAAI,CAAC;AAC5C,QAAA,IAAI,cAAc,IAAI,MAAM,CAAC,UAAU,EAAE;AACvC,YAAA,OAAO,KAAK;QACd;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;;;;AAYG;IACH,aAAa,GAAA;QACX,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,UAAU;IAChE;AAEA;;;;;;;;;;;AAWG;IACH,qBAAqB,GAAA;QACnB,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,aAAa,CAAC,YAAY;IAClE;uGAnVW,wBAAwB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAxB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,wBAAwB,cADX,MAAM,EAAA,CAAA;;2FACnB,wBAAwB,EAAA,UAAA,EAAA,CAAA;kBADpC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACjFlC;;;;AAIG;AA6BH;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CG;MAEU,qBAAqB,CAAA;AACf,IAAA,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC;;;;AAM1D;;;;;;;;;;;;;;;;;;AAkBG;AACH,IAAA,YAAY,CAAC,IAAU,EAAA;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,WAAW;;AAGzD,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YACnB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE;QAC5D;;QAGA,IAAI,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,WAAW,EAAE;YAClC,MAAM,gBAAgB,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC;YAChE,OAAO;AACL,gBAAA,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,CAAA,kBAAA,EAAqB,gBAAgB,CAAA,MAAA,CAAQ;aACrD;QACH;;QAGA,IAAI,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC/C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE;QAC5D;;AAGA,QAAA,IACE,MAAM,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC;AAClC,YAAA,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,gBAAgB,CAAC,EAC3D;YACA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE;QAC5D;AAEA,QAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;IACxB;AAEA;;;;;;;AAOG;IACK,iBAAiB,CACvB,QAAgB,EAChB,YAA+B,EAAA;AAE/B,QAAA,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,KAAI;AACnC,YAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;;AAE1B,gBAAA,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AACpC,gBAAA,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;YACpC;YACA,OAAO,QAAQ,KAAK,OAAO;AAC7B,QAAA,CAAC,CAAC;IACJ;;;;AAMA;;;;;;;;;;;;;;;;;;AAkBG;AACH,IAAA,aAAa,CAAC,IAAU,EAAA;QACtB,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QAE9C,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,EAAE;AACxC,YAAA,OAAO,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;QAClC;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;;;;;AAaG;AACH,IAAA,aAAa,CAAC,GAAW,EAAA;AACvB,QAAA,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC;IAC1B;AAEA;;;;;;;;;;;;;AAaG;AACH,IAAA,iBAAiB,CAAC,QAAgB,EAAA;AAChC,QAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AACjC,YAAA,OAAO,OAAO;QAChB;AACA,QAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AACjC,YAAA,OAAO,OAAO;QAChB;AACA,QAAA,IAAI,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AACjC,YAAA,OAAO,OAAO;QAChB;AACA,QAAA,OAAO,MAAM;IACf;;;;AAMA;;;;;;;;;;;;;;;;;AAiBG;IACH,MAAM,aAAa,CAAC,IAAU,EAAA;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,WAAW;;AAGzD,QAAA,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE;AAC5B,YAAA,OAAO,IAAI;QACb;;QAGA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;AACnC,YAAA,OAAO,IAAI;QACb;;AAGA,QAAA,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,EAAE;AAC9D,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,IAAI;;YAEF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;;YAG9C,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAC/C,WAAW,CAAC,KAAK,EACjB,WAAW,CAAC,MAAM,EAClB,MAAM,CAAC,kBAAkB,CAAC,KAAK,EAC/B,MAAM,CAAC,kBAAkB,CAAC,MAAM,CACjC;;AAGD,YAAA,IACE,gBAAgB,CAAC,KAAK,KAAK,WAAW,CAAC,KAAK;AAC5C,gBAAA,gBAAgB,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM;gBAC9C,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,WAAW,GAAG,CAAC,EAClC;AACA,gBAAA,OAAO,IAAI;YACb;;YAGA,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC/C,YAAA,MAAM,CAAC,KAAK,GAAG,gBAAgB,CAAC,KAAK;AACrC,YAAA,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM;YAEvC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YACnC,IAAI,CAAC,GAAG,EAAE;AACR,gBAAA,OAAO,IAAI;YACb;AAEA,YAAA,GAAG,CAAC,SAAS,CACX,WAAW,EACX,CAAC,EACD,CAAC,EACD,gBAAgB,CAAC,KAAK,EACtB,gBAAgB,CAAC,MAAM,CACxB;;AAGD,YAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,CAClC,MAAM,EACN,YAAY,EACZ,MAAM,CAAC,uBAAuB,CAC/B;;AAGD,YAAA,OAAO,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE;AAC7D,gBAAA,IAAI,EAAE,YAAY;AAClB,gBAAA,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE;AACzB,aAAA,CAAC;QACJ;AAAE,QAAA,MAAM;;AAEN,YAAA,OAAO,IAAI;QACb;IACF;AAEA;;;;;;;;;;;;;;;;AAgBG;IACH,MAAM,iBAAiB,CAAC,IAAU,EAAA;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,WAAW;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;AAE9C,QAAA,IAAI,IAAI,KAAK,OAAO,EAAE;YACpB,OAAO,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC;QAChE;AAEA,QAAA,IAAI,IAAI,KAAK,OAAO,EAAE;YACpB,OAAO,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC;QAChE;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;AAMG;AACK,IAAA,MAAM,sBAAsB,CAClC,IAAU,EACV,IAAgB,EAAA;AAEhB,QAAA,IAAI;YACF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAE9C,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAC/C,WAAW,CAAC,KAAK,EACjB,WAAW,CAAC,MAAM,EAClB,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,MAAM,CACZ;YAED,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC/C,YAAA,MAAM,CAAC,KAAK,GAAG,gBAAgB,CAAC,KAAK;AACrC,YAAA,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM;YAEvC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YACnC,IAAI,CAAC,GAAG,EAAE;AACR,gBAAA,OAAO,IAAI;YACb;AAEA,YAAA,GAAG,CAAC,SAAS,CACX,WAAW,EACX,CAAC,EACD,CAAC,EACD,gBAAgB,CAAC,KAAK,EACtB,gBAAgB,CAAC,MAAM,CACxB;YAED,OAAO,MAAM,CAAC,SAAS,CAAC,YAAY,EAAE,GAAG,CAAC;QAC5C;AAAE,QAAA,MAAM;AACN,YAAA,OAAO,IAAI;QACb;IACF;AAEA;;;;;;;;AAQG;AACK,IAAA,MAAM,sBAAsB,CAClC,IAAU,EACV,IAAgB,EAAA;AAEhB,QAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAI;YAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC;YAC7C,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC;AAErC,YAAA,KAAK,CAAC,OAAO,GAAG,UAAU;AAC1B,YAAA,KAAK,CAAC,KAAK,GAAG,IAAI;AAClB,YAAA,KAAK,CAAC,WAAW,GAAG,IAAI;YAExB,MAAM,OAAO,GAAG,MAAK;AACnB,gBAAA,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC;gBACxB,KAAK,CAAC,MAAM,EAAE;AAChB,YAAA,CAAC;AAED,YAAA,KAAK,CAAC,YAAY,GAAG,MAAK;;AAExB,gBAAA,KAAK,CAAC,WAAW,GAAG,CAAC;AACvB,YAAA,CAAC;AAED,YAAA,KAAK,CAAC,QAAQ,GAAG,MAAK;AACpB,gBAAA,IAAI;oBACF,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAC/C,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,WAAW,EACjB,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,MAAM,CACZ;oBAED,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC/C,oBAAA,MAAM,CAAC,KAAK,GAAG,gBAAgB,CAAC,KAAK;AACrC,oBAAA,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC,MAAM;oBAEvC,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;oBACnC,IAAI,CAAC,GAAG,EAAE;AACR,wBAAA,OAAO,EAAE;wBACT,OAAO,CAAC,IAAI,CAAC;wBACb;oBACF;AAEA,oBAAA,GAAG,CAAC,SAAS,CACX,KAAK,EACL,CAAC,EACD,CAAC,EACD,gBAAgB,CAAC,KAAK,EACtB,gBAAgB,CAAC,MAAM,CACxB;oBAED,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,EAAE,GAAG,CAAC;AACnD,oBAAA,OAAO,EAAE;oBACT,OAAO,CAAC,OAAO,CAAC;gBAClB;AAAE,gBAAA,MAAM;AACN,oBAAA,OAAO,EAAE;oBACT,OAAO,CAAC,IAAI,CAAC;gBACf;AACF,YAAA,CAAC;AAED,YAAA,KAAK,CAAC,OAAO,GAAG,MAAK;AACnB,gBAAA,OAAO,EAAE;gBACT,OAAO,CAAC,IAAI,CAAC;AACf,YAAA,CAAC;;YAGD,UAAU,CAAC,MAAK;AACd,gBAAA,OAAO,EAAE;gBACT,OAAO,CAAC,IAAI,CAAC;YACf,CAAC,EAAE,IAAI,CAAC;AAER,YAAA,KAAK,CAAC,GAAG,GAAG,GAAG;AACjB,QAAA,CAAC,CAAC;IACJ;;;;AAMA;;;;;AAKG;AACK,IAAA,SAAS,CAAC,IAAU,EAAA;AAC1B,QAAA,OAAO,iBAAiB,CAAC,IAAI,CAAC;IAChC;AAEA;;;;;;;AAOG;AACK,IAAA,YAAY,CAClB,MAAyB,EACzB,QAAgB,EAChB,OAAe,EAAA;QAEf,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,KAAI;AACrC,YAAA,MAAM,CAAC,MAAM,CACX,CAAC,IAAI,KAAI;gBACP,IAAI,IAAI,EAAE;oBACR,OAAO,CAAC,IAAI,CAAC;gBACf;qBAAO;AACL,oBAAA,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;gBACxD;AACF,YAAA,CAAC,EACD,QAAQ,EACR,OAAO,CACR;AACH,QAAA,CAAC,CAAC;IACJ;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACK,IAAA,mBAAmB,CACzB,aAAqB,EACrB,cAAsB,EACtB,QAAgB,EAChB,SAAiB,EAAA;;QAGjB,IAAI,aAAa,IAAI,QAAQ,IAAI,cAAc,IAAI,SAAS,EAAE;YAC5D,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE;QACzD;;AAGA,QAAA,MAAM,WAAW,GAAG,aAAa,GAAG,cAAc;QAElD,IAAI,KAAK,GAAG,QAAQ;AACpB,QAAA,IAAI,MAAM,GAAG,QAAQ,GAAG,WAAW;;AAGnC,QAAA,IAAI,MAAM,GAAG,SAAS,EAAE;YACtB,MAAM,GAAG,SAAS;AAClB,YAAA,KAAK,GAAG,SAAS,GAAG,WAAW;QACjC;QAEA,OAAO;AACL,YAAA,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;AACxB,YAAA,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;SAC3B;IACH;AAEA;;;;;;;;;;;;AAYG;AACH,IAAA,cAAc,CAAC,KAAa,EAAA;AAC1B,QAAA,IAAI,KAAK,KAAK,CAAC,EAAE;AACf,YAAA,OAAO,SAAS;QAClB;AAEA,QAAA,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;QAC/C,MAAM,CAAC,GAAG,IAAI;QACd,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAEnD,QAAA,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAEpE,OAAO,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAC,EAAE;IACnC;AAEA;;;;;;;;;;;;AAYG;AACH,IAAA,gBAAgB,CAAC,QAAgB,EAAA;QAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC;AACzC,QAAA,IAAI,OAAO,GAAG,CAAC,EAAE;AACf,YAAA,OAAO,EAAE;QACX;QACA,OAAO,QAAQ,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE;IAClD;uGAxiBW,qBAAqB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAArB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,qBAAqB,cADR,MAAM,EAAA,CAAA;;2FACnB,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBADjC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACjFlC;;;;;;;;;AASG;;ACCH;;;;;;AAMG;AACH,MAAM,MAAM,GAAG;AACb,IAAA,IAAI,EAAE,OAAO;AACb,IAAA,MAAM,EAAE,OAAO;AACf,IAAA,IAAI,EAAE,OAAO;AACb,IAAA,MAAM,EAAE,8BAA8B;CAC9B;AAEV;;;AAGG;AACI,MAAM,YAAY,GAA6B,OAAO,CAAC,cAAc,EAAE;IAC5E,UAAU,CAAC,QAAQ,EAAE;QACnB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;QACpD,OAAO,CACL,GAAG,MAAM,CAAC,MAAM,CAAA,CAAA,EAAI,MAAM,CAAC,MAAM,CAAA,CAAE,EACnC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAClD;KACF,CAAC;IACF,UAAU,CAAC,QAAQ,EAAE;QACnB,OAAO,CACL,GAAG,MAAM,CAAC,IAAI,CAAA,CAAA,EAAI,MAAM,CAAC,MAAM,CAAA,CAAE,EACjC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CACtD;KACF,CAAC;AACH,CAAA;AAED;;;AAGG;AACI,MAAM,WAAW,GAA6B,OAAO,CAAC,aAAa,EAAE;IAC1E,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IACxC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AACtC,IAAA,UAAU,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAA,EAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAA,CAAE,CAAC,CAAC,CAAC;AACnE,CAAA;AAED;;;AAGG;AACI,MAAM,UAAU,GAA6B,OAAO,CAAC,YAAY,EAAE;IACxE,UAAU,CAAC,YAAY,EAAE;AACvB,QAAA,OAAO,CACL,CAAA,EAAG,MAAM,CAAC,IAAI,CAAA,CAAA,EAAI,MAAM,CAAC,MAAM,CAAA,CAAE,EACjC,SAAS,CAAC;YACR,KAAK,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YAChD,KAAK,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACrD,KAAK,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACpD,KAAK,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACrD,KAAK,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACpD,KAAK,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACrD,KAAK,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACpD,KAAK,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACrD,KAAK,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACpD,KAAK,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AACjD,SAAA,CAAC,CACH;KACF,CAAC;AACH,CAAA;AAED;;;AAGG;AACI,MAAM,SAAS,GAA6B,OAAO,CAAC,WAAW,EAAE;IACtE,UAAU,CAAC,QAAQ,EAAE;AACnB,QAAA,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AACrB,QAAA,OAAO,CAAC,CAAA,EAAG,MAAM,CAAC,MAAM,CAAA,CAAA,EAAI,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;KACpE,CAAC;IACF,UAAU,CAAC,QAAQ,EAAE;AACnB,QAAA,OAAO,CAAC,CAAA,EAAG,MAAM,CAAC,MAAM,CAAA,CAAA,EAAI,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;KACpE,CAAC;AACH,CAAA;AAED;;;;;;;;;;;;;;;AAeG;AACI,MAAM,cAAc,GAAG;IAC5B,YAAY;IACZ,WAAW;IACX,UAAU;IACV,SAAS;;;ACjHX;;AAEG;AAEH;;ACJA;;AAEG;;;;"}
|