{"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/AIStateIndicator/hooks/useAIState.ts","../../src/context/AttachmentSelectorContext.tsx","../../src/context/MessageContext.tsx","../../src/components/MessageComposer/preEditSnapshot.ts","../../src/context/MessageBounceContext.tsx","../../src/context/MessageListContext.tsx","../../src/context/MessageTranslationViewContext.tsx","../../src/context/ModalContext.tsx","../../src/context/PollContext.tsx","../../src/context/WithComponents.tsx","../../src/components/AIStateIndicator/AIStateIndicator.tsx","../../src/components/VisuallyHidden/VisuallyHidden.tsx","../../src/components/Accessibility/useAriaLiveAnnouncer.ts","../../src/components/Accessibility/AriaLiveRegion.tsx","../../src/components/Notifications/NotificationConfigurationContext.tsx","../../src/components/Notifications/hooks/useNotifications.ts","../../src/a11y/hooks/useAriaIdentifiers.ts","../../src/components/Dialog/components/Alert.tsx","../../src/components/Dialog/service/DialogAnchor.tsx","../../src/components/Button/PlayButton.tsx","../../src/components/Dialog/components/Callout.tsx","../../src/components/Avatar/Avatar.tsx","../../src/components/Badge/Badge.tsx","../../src/components/Avatar/AvatarStack.tsx","../../src/components/Avatar/ChannelAvatar.tsx","../../src/components/Avatar/GroupAvatar.tsx","../../src/a11y/a11yUtils.ts","../../src/components/Dialog/components/ContextMenu.tsx","../../src/components/Dialog/components/Prompt.tsx","../../src/components/Dialog/components/Viewer.tsx","../../src/i18n/de.json","../../src/i18n/en.json","../../src/i18n/es.json","../../src/i18n/fr.json","../../src/i18n/hi.json","../../src/i18n/it.json","../../src/i18n/ja.json","../../src/i18n/ko.json","../../src/i18n/nl.json","../../src/i18n/pt.json","../../src/i18n/ru.json","../../src/i18n/tr.json","../../src/i18n/TranslationBuilder/TranslationBuilder.ts","../../src/i18n/TranslationBuilder/notifications/translators.ts","../../src/i18n/TranslationBuilder/notifications/translatorsByNotificationType.ts","../../src/i18n/TranslationBuilder/notifications/NotificationTranslationTopic.ts","../../src/i18n/Streami18n.ts","../../src/components/Loading/LoadingChannels.tsx","../../src/components/Loading/LoadingIndicator.tsx","../../src/components/Loading/progress-indicators.tsx","../../src/components/Loading/UploadProgressIndicator.tsx","../../src/components/MessageComposer/hooks/utils.ts","../../src/components/Attachment/components/FileSizeIndicator.tsx","../../src/components/Loading/UploadedSizeIndicator.tsx","../../src/utils/useStableCallback.ts","../../src/components/Message/hooks/useActionHandler.ts","../../src/components/Message/hooks/useDeleteHandler.ts","../../src/components/Message/hooks/useFlagHandler.ts","../../src/components/Message/hooks/useMentionsHandler.ts","../../src/components/Message/hooks/useMarkUnreadHandler.ts","../../src/components/Message/hooks/useMuteHandler.ts","../../src/components/Message/hooks/useOpenThreadHandler.ts","../../src/components/Message/hooks/usePinHandler.ts","../../src/components/Reactions/reactionOptions.tsx","../../src/components/Message/hooks/useReactionHandler.ts","../../src/components/Message/hooks/useRetryHandler.ts","../../src/components/Message/hooks/useUserHandler.ts","../../src/components/Message/hooks/useUserRole.ts","../../src/components/Message/hooks/useReactionsFetcher.ts","../../src/components/Message/hooks/useMessageTextStreaming.ts","../../src/components/Message/hooks/useMessageReminder.ts","../../src/a11y/hooks/useResolvedModalAriaProps.ts","../../src/components/Modal/GlobalModal.tsx","../../src/components/MessageBounce/MessageBounceModal.tsx","../../src/components/MessageBounce/MessageBouncePrompt.tsx","../../src/components/Message/MessageBubble.tsx","../../src/components/Message/MessageDeletedBubble.tsx","../../src/components/Message/MessageBlocked.tsx","../../src/components/MessageActions/hooks/useBaseMessageActionSetFilter.ts","../../src/components/Message/MessageAlsoSentInChannelIndicator.tsx","../../src/components/Message/MessageRepliesCountButton.tsx","../../src/components/Message/PinIndicator.tsx","../../src/components/Tooltip/Tooltip.tsx","../../src/components/Tooltip/hooks/useEnterLeaveHandlers.ts","../../src/components/Message/MessageStatus.tsx","../../src/components/Message/renderText/regex.ts","../../src/components/Message/renderText/rehypePlugins/emojiMarkdownPlugin.ts","../../src/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.ts","../../src/components/Message/renderText/remarkPlugins/htmlToTextPlugin.ts","../../src/components/Message/renderText/remarkPlugins/imageToLink.ts","../../src/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.ts","../../src/components/Message/renderText/remarkPlugins/plusPlusToEmphasis.ts","../../src/components/Message/renderText/remarkPlugins/remarkIgnoreMarkdown.ts","../../src/components/Message/renderText/componentRenderers/Anchor.tsx","../../src/components/Message/renderText/componentRenderers/Emoji.tsx","../../src/components/Message/renderText/componentRenderers/Mention.tsx","../../src/components/UtilityComponents/NullComponent.tsx","../../src/components/UtilityComponents/ErrorBoundary.tsx","../../src/components/Message/renderText/renderText.tsx","../../src/components/Message/MessageText.tsx","../../src/components/Message/Timestamp.tsx","../../src/components/Message/MessageTimestamp.tsx","../../src/components/Message/MessageEditedIndicator.tsx","../../src/components/Message/MessageTranslationIndicator.tsx","../../src/components/Attachment/components/DownloadButton.tsx","../../src/components/FileIcon/FileIconSet.tsx","../../src/components/FileIcon/mimeTypes.ts","../../src/components/FileIcon/iconMap.ts","../../src/components/FileIcon/FileIcon.tsx","../../src/components/AudioPlayback/components/formatTime.ts","../../src/components/AudioPlayback/components/DurationDisplay.tsx","../../src/components/AudioPlayback/components/PlaybackRateButton.tsx","../../src/components/AudioPlayback/components/keyboardSeek.ts","../../src/components/AudioPlayback/components/progressBarA11y.ts","../../src/components/AudioPlayback/components/useInteractiveProgressBar.ts","../../src/components/AudioPlayback/components/ProgressBar.tsx","../../src/components/Attachment/utils.tsx","../../src/components/Attachment/audioSampling.ts","../../src/components/AudioPlayback/components/WaveProgressBar.tsx","../../src/components/Attachment/Audio.tsx","../../src/components/Attachment/AttachmentActions.tsx","../../src/components/Attachment/VoiceRecording.tsx","../../src/components/BaseImage/ImagePlaceholder.tsx","../../src/components/BaseImage/BaseImage.tsx","../../src/components/BaseImage/toBaseImageDescriptors.ts","../../src/components/Gallery/GalleryContext.tsx","../../src/components/Gallery/GalleryHeader.tsx","../../src/components/VideoPlayer/VideoPlayer.tsx","../../src/components/VideoPlayer/VideoThumbnail.tsx","../../src/components/Gallery/GalleryUI.tsx","../../src/components/Gallery/Gallery.tsx","../../src/components/Attachment/ModalGallery.tsx","../../src/components/Attachment/Image.tsx","../../src/components/SafeAnchor/SafeAnchor.tsx","../../src/components/Attachment/LinkPreview/UnableToRenderCard.tsx","../../src/components/Attachment/LinkPreview/Card.tsx","../../src/components/Attachment/FileAttachment.tsx","../../src/components/Attachment/Giphy.tsx","../../src/components/Attachment/icons.tsx","../../src/components/Attachment/Geolocation.tsx","../../src/components/Attachment/UnsupportedAttachment.tsx","../../src/components/Attachment/VisibilityDisclaimer.tsx","../../src/components/Attachment/VideoAttachment.tsx","../../src/components/Attachment/AttachmentContainer.tsx","../../src/components/Attachment/Attachment.tsx","../../src/components/Location/hooks/useLiveLocationSharingManager.ts","../../src/components/MessageComposer/hooks/useAttachmentManagerState.ts","../../src/components/MessageComposer/hooks/useAttachmentsForPreview.ts","../../src/components/MessageComposer/hooks/useCanCreatePoll.ts","../../src/components/MessageComposer/hooks/useCooldownRemaining.tsx","../../src/components/MessageComposer/hooks/useTextareaRef.ts","../../src/components/MessageComposer/hooks/useSubmitHandler.ts","../../src/components/ReactFileUtilities/UploadButton.tsx","../../src/components/MessageComposer/hooks/usePasteHandler.ts","../../src/components/MediaRecorder/observable/Subscription.ts","../../src/components/MediaRecorder/observable/Observer.ts","../../src/components/MediaRecorder/observable/Observable.ts","../../src/components/MediaRecorder/observable/Subject.ts","../../src/components/MediaRecorder/observable/BehaviorSubject.ts","../../src/components/MediaRecorder/classes/BrowserPermission.ts","../../src/utils/mergeDeep.ts","../../src/components/MediaRecorder/classes/AmplitudeRecorder.ts","../../src/components/MediaRecorder/transcode/wav.ts","../../src/components/MediaRecorder/transcode/index.ts","../../src/components/MediaRecorder/classes/MediaRecorderController.ts","../../src/components/MediaRecorder/hooks/useMediaRecorder.ts","../../src/components/MessageComposer/hooks/useMessageComposerBindings.ts","../../src/components/MessageComposer/hooks/useMessageComposerCommands.ts","../../src/components/MessageComposer/hooks/useMessageComposerHasSendableData.ts","../../src/components/MessageComposer/hooks/useMessageContentIsEmpty.ts","../../src/components/MessageComposer/RemoveAttachmentPreviewButton.tsx","../../src/components/MessageComposer/QuotedMessageIndicator.tsx","../../src/components/MessageComposer/QuotedMessagePreview.tsx","../../src/components/Message/QuotedMessage.tsx","../../src/components/Message/ReminderNotification.tsx","../../src/components/Message/StreamedMessageText.tsx","../../src/components/Form/Dropdown.tsx","../../src/components/Form/SwitchField.tsx","../../src/components/Location/ShareLocationDialog.tsx","../../src/components/Poll/PollHeader.tsx","../../src/components/Form/FieldError.tsx","../../src/components/Form/NumericInput.tsx","../../src/components/Form/TextInput.tsx","../../src/components/DragAndDrop/DragAndDropContainer.tsx","../../src/components/Form/TextInputFieldSet.tsx","../../src/components/Form/hooks/useFormState.ts","../../src/components/Poll/PollActions/AddCommentPrompt.tsx","../../src/components/Poll/PollActions/EndPollAlert.tsx","../../src/components/Poll/PollActions/PollAction.tsx","../../src/components/Poll/PollActions/SuggestPollOptionPrompt.tsx","../../src/components/Poll/PollVote.tsx","../../src/components/Poll/hooks/useManagePollVotesRealtime.ts","../../src/components/InfiniteScrollPaginator/hooks/useCursorPaginator.ts","../../src/components/Poll/hooks/usePollAnswerPagination.ts","../../src/components/Poll/hooks/usePollOptionVotesPagination.ts","../../src/components/InfiniteScrollPaginator/InfiniteScrollPaginator.tsx","../../src/components/Poll/PollActions/PollAnswerList.tsx","../../src/components/Poll/PollActions/PollResults/PollOptionWithVotesHeader.tsx","../../src/components/Poll/PollActions/PollResults/PollOptionWithVotes.tsx","../../src/components/Poll/PollActions/PollQuestion.tsx","../../src/components/Poll/PollActions/PollResults/PollOptionWithVotesList.tsx","../../src/components/Poll/PollActions/PollResults/PollResults.tsx","../../src/components/Poll/PollActions/PollActions.tsx","../../src/components/Poll/PollOptionSelector.tsx","../../src/components/Poll/PollOptionList.tsx","../../src/components/Poll/PollActions/PollOptionsFullList.tsx","../../src/components/Poll/PollContent.tsx","../../src/components/Poll/Poll.tsx","../../src/components/Poll/PollCreationDialog/MultipleAnswersField.tsx","../../src/components/Poll/PollCreationDialog/NameField.tsx","../../src/components/Poll/PollCreationDialog/OptionFieldSet.tsx","../../src/components/Poll/PollCreationDialog/PollCreationDialogControls.tsx","../../src/components/Poll/PollCreationDialog/PollCreationDialog.tsx","../../src/components/MessageComposer/AttachmentSelector/CommandsMenu.tsx","../../src/components/MessageComposer/AttachmentSelector/AttachmentSelector.tsx","../../src/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.tsx","../../src/components/MessageComposer/AttachmentPreviewList/AttachmentUploadedSizeIndicator.tsx","../../src/components/MessageComposer/AttachmentPreviewList/utils/AttachmentPreviewRoot.tsx","../../src/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.tsx","../../src/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.tsx","../../src/components/Badge/MediaBadge.tsx","../../src/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.tsx","../../src/components/MessageComposer/AttachmentPreviewList/AttachmentPreviewList.tsx","../../src/components/MessageComposer/AttachmentPreviewList/VoiceRecordingPreviewSlot.tsx","../../src/components/MessageComposer/CommandChip.tsx","../../src/components/MessageComposer/CooldownTimer.tsx","../../src/components/MessageComposer/icons.tsx","../../src/components/MessageComposer/LinkPreviewList.tsx","../../src/components/MediaRecorder/RecordingPermissionDeniedNotification.tsx","../../src/components/MediaRecorder/AudioRecorder/AudioRecordingPlayback.tsx","../../src/components/MediaRecorder/AudioRecorder/hooks/useTimeElapsed.ts","../../src/components/MediaRecorder/AudioRecorder/RecordingTimer.tsx","../../src/components/MediaRecorder/AudioRecorder/AudioRecordingPreview.tsx","../../src/components/MediaRecorder/AudioRecorder/recordingStateIdentity.ts","../../src/components/MediaRecorder/AudioRecorder/AudioRecorderRecordingControls.tsx","../../src/components/MediaRecorder/AudioRecorder/AudioRecorder.tsx","../../src/components/MediaRecorder/AudioRecorder/AudioRecordingButtonWithNotification.tsx","../../src/components/MessageComposer/EditedMessagePreview.tsx","../../src/components/MessageComposer/SendToChannelCheckbox.tsx","../../src/components/TextareaComposer/SuggestionList/CommandItem.tsx","../../src/components/TextareaComposer/SuggestionList/EmoticonItem.tsx","../../src/components/TextareaComposer/SuggestionList/SuggestionListItem.tsx","../../src/components/TextareaComposer/SuggestionList/UserItem.tsx","../../src/utils/getTextareaCaretRect.ts","../../src/components/TextareaComposer/SuggestionList/SuggestionList.tsx","../../src/components/TextareaComposer/hooks/useTextareaPlaceholder.ts","../../src/components/TextareaComposer/TextareaComposer.tsx","../../src/components/MessageComposer/WithDragAndDropUpload.tsx","../../src/components/MessageComposer/StopAIGenerationButton.tsx","../../src/components/MessageComposer/SendButton.tsx","../../src/components/MessageComposer/MessageComposerActions.tsx","../../src/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.tsx","../../src/components/MessageComposer/MessageComposerUI.tsx","../../src/components/MessageComposer/hooks/useCreateMessageComposerContext.ts","../../src/components/MessageComposer/MessageComposer.tsx","../../src/components/ChannelListItem/utils.tsx","../../src/components/ChannelListItem/hooks/useChannelDisplayName.ts","../../src/components/ChannelListItem/hooks/useChannelPreviewInfo.ts","../../src/components/TypingIndicator/TypingIndicatorDots.tsx","../../src/components/TypingIndicator/hooks/useDebouncedTypingActive.ts","../../src/components/TypingIndicator/utils/getTypingStatusMessage.ts","../../src/components/TypingIndicator/TypingIndicatorHeader.tsx","../../src/components/Thread/ThreadHeader.tsx","../../src/components/Thread/ThreadStart.tsx","../../src/components/DateSeparator/DateSeparator.tsx","../../src/components/Thread/ThreadHead.tsx","../../src/components/Thread/Thread.tsx","../../src/components/Reactions/ReactionSelector.tsx","../../src/components/Reactions/hooks/useFetchReactions.ts","../../src/components/Reactions/MessageReactionsDetail.tsx","../../src/components/Reactions/hooks/useProcessReactions.tsx","../../src/components/Reactions/MessageReactions.tsx","../../src/components/Reactions/utils/utils.ts","../../src/components/Reactions/SpriteImage.tsx","../../src/components/Reactions/ReactionSelectorWithButton.tsx","../../src/components/MessageActions/RemindMeSubmenu.tsx","../../src/components/MessageActions/downloadUtils.ts","../../src/components/MessageActions/DownloadSubmenu.tsx","../../src/components/MessageActions/QuickMessageActionButton.tsx","../../src/components/MessageActions/DeleteMessageAlert.tsx","../../src/components/MessageActions/MessageActions.defaults.tsx","../../src/components/Chat/hooks/useSplitActionSet.ts","../../src/components/MessageActions/MessageActions.tsx","../../src/components/Message/MessageUI.tsx","../../src/components/Message/Message.tsx","../../src/components/MessageList/GiphyPreviewMessage.tsx","../../src/components/MessageList/hooks/MessageList/useEnrichedMessages.ts","../../src/components/MessageList/hooks/MessageList/useFloatingDateSeparatorMessageList.ts","../../src/components/MessageList/hooks/useLastReadData.ts","../../src/components/MessageList/hooks/useLastDeliveredData.ts","../../src/components/MessageList/hooks/MessageList/useMessageListElements.tsx","../../src/components/MessageList/hooks/MessageList/useMessageListScrollManager.ts","../../src/components/MessageList/hooks/MessageList/useScrollLocationLogic.tsx","../../src/components/MessageList/MessageListMainPanel.tsx","../../src/components/MessageList/UnreadMessagesSeparator.tsx","../../src/components/MessageList/hooks/MessageList/useUnreadMessagesNotification.ts","../../src/components/MessageList/hooks/useMarkRead.ts","../../src/components/MessageList/NewMessageNotification.tsx","../../src/components/MessageList/UnreadMessagesNotification.tsx","../../src/components/InfiniteScrollPaginator/InfiniteScroll.tsx","../../src/components/TypingIndicator/TypingIndicator.tsx","../../src/components/MessageList/hooks/VirtualizedMessageList/useFloatingDateSeparator.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useGiphyPreview.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useMessageSetKey.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useNewMessageNotification.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/usePrependMessagesCount.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useScrollToBottomOnNewMessage.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useShouldForceScrollToBottom.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useUnreadMessagesNotificationVirtualized.ts","../../src/components/MessageList/FloatingDateSeparator.tsx","../../src/components/EventComponent/EventComponent.tsx","../../src/components/MessageList/renderMessages.tsx","../../src/utils/findReverse.ts","../../src/components/MessageList/hooks/useLastOwnMessage.ts","../../src/components/MessageList/hooks/useReducedMotionPreference.ts","../../src/components/MessageList/ScrollToLatestMessageButton.tsx","../../src/components/MessageList/MessageList.tsx","../../src/components/MessageList/VirtualizedMessageListComponents.tsx","../../src/context/VirtualizedMessageListContext.tsx","../../src/components/MessageList/VirtualizedMessageList.tsx","../../src/utils/getWholeChar.ts","../../src/components/Search/hooks/useSearchQueriesInProgress.ts","../../src/components/ChannelList/hooks/useConnectionRecoveredListener.ts","../../src/components/ChannelList/hooks/usePaginatedChannels.ts","../../src/components/ChannelList/utils.ts","../../src/components/ChannelList/hooks/useChannelListShape.ts","../../src/components/ChannelList/ChannelListUI.tsx","../../src/components/Search/SearchContext.tsx","../../src/components/Search/SearchBar/SearchBar.tsx","../../src/components/Search/SearchResults/SearchResultItem.tsx","../../src/components/Search/SearchSourceResultsContext.tsx","../../src/components/Search/SearchResults/SearchSourceResultsLoadingIndicator.tsx","../../src/components/Search/SearchResults/SearchSourceResultListFooter.tsx","../../src/components/Search/SearchResults/SearchSourceResultList.tsx","../../src/components/Search/SearchResults/SearchSourceResultsEmpty.tsx","../../src/components/Search/SearchResults/SearchSourceResultsHeader.tsx","../../src/components/Search/SearchResults/SearchSourceResults.tsx","../../src/components/Search/SearchResults/SearchResultsHeader.tsx","../../src/components/Search/SearchResults/SearchResultsPresearch.tsx","../../src/components/Search/SearchResults/SearchResults.tsx","../../src/components/Search/Search.tsx","../../src/components/LoadMore/LoadMoreButton.tsx","../../src/components/LoadMore/LoadMorePaginator.tsx","../../src/components/ChannelList/ChannelListHeader.tsx","../../src/components/ChannelList/ChannelList.tsx","../../src/components/ChannelList/hooks/useSelectedChannelState.ts","../../src/components/ChannelList/hooks/useChannelMembershipState.ts","../../src/components/ChannelList/hooks/useChannelMembersState.ts","../../src/components/ChannelListItem/hooks/useIsChannelMuted.ts","../../src/components/ChannelListItem/ChannelListItemActionButtons.defaults.tsx","../../src/components/ChannelListItem/ChannelListItemActionButtons.tsx","../../src/components/ChannelListItem/ChannelListItemTimestamp.tsx","../../src/components/SummarizedMessagePreview/hooks/useLatestMessagePreview.ts","../../src/components/SummarizedMessagePreview/SummarizedMessagePreview.tsx","../../src/components/ChannelListItem/ChannelListItemUI.tsx","../../src/components/ChannelListItem/hooks/useMessageDeliveryStatus.ts","../../src/components/ChannelListItem/ChannelListItem.tsx","../../src/components/Threads/ThreadList/ThreadListItemUI.tsx","../../src/components/Threads/ThreadList/ThreadListItem.tsx","../../src/components/Threads/ThreadList/ThreadListEmptyPlaceholder.tsx","../../src/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.tsx","../../src/components/Threads/ThreadList/ThreadListLoadingIndicator.tsx","../../src/components/Threads/ThreadList/ThreadListHeader.tsx","../../src/components/Threads/ThreadList/ThreadList.tsx","../../src/components/Notifications/hooks/useSystemNotifications.ts","../../src/components/Notifications/Notification.tsx","../../src/components/Notifications/NotificationList.tsx","../../src/components/Accessibility/NotificationAnnouncer.tsx","../../src/components/Accessibility/hooks/useIncomingMessageAnnouncements.ts","../../src/components/ChannelHeader/hooks/useChannelHeaderOnlineStatus.ts","../../src/components/ChannelHeader/ChannelHeader.tsx","../../src/components/SkipNavigation/SkipNavigation.tsx","../../src/components/Chat/hooks/useChat.ts","../../src/components/Chat/hooks/useReportLostConnectionSystemNotification.ts","../../src/components/Chat/hooks/useCreateChatContext.ts","../../src/components/Chat/hooks/useChannelsQueryState.ts","../../src/components/Chat/Chat.tsx","../../src/components/Chat/hooks/useCreateChatClient.ts","../../src/components/Window/Window.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport type { AIState, Channel, Event } from 'stream-chat';\n\nexport const AIStates = {\n  Error: 'AI_STATE_ERROR',\n  ExternalSources: 'AI_STATE_EXTERNAL_SOURCES',\n  Generating: 'AI_STATE_GENERATING',\n  Idle: 'AI_STATE_IDLE',\n  Stop: 'AI_STATE_STOP',\n  Thinking: 'AI_STATE_THINKING',\n};\n\n/**\n * A hook that returns the current state of the AI.\n * @param {Channel} channel - The channel for which we want to know the AI state.\n * @returns {{ aiState: AIState }} The current AI state for the given channel.\n */\nexport const useAIState = (channel?: Channel): { aiState: AIState } => {\n  const [aiState, setAiState] = useState<AIState>(AIStates.Idle);\n\n  useEffect(() => {\n    if (!channel) {\n      return;\n    }\n\n    const indicatorChangedListener = channel.on('ai_indicator.update', (event: Event) => {\n      const { cid } = event;\n      const state = event.ai_state as AIState;\n      if (channel.cid === cid) {\n        setAiState(state);\n      }\n    });\n\n    const indicatorClearedListener = channel.on('ai_indicator.clear', (event) => {\n      const { cid } = event;\n      if (channel.cid === cid) {\n        setAiState(AIStates.Idle);\n      }\n    });\n\n    const indicatorStoppedListener = channel.on('ai_indicator.stop', (event) => {\n      const { cid } = event;\n      if (channel.cid === cid) {\n        setAiState(AIStates.Stop);\n      }\n    });\n\n    return () => {\n      indicatorChangedListener.unsubscribe();\n      indicatorClearedListener.unsubscribe();\n      indicatorStoppedListener.unsubscribe();\n    };\n  }, [channel]);\n\n  return { aiState };\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { createContext, useContext } from 'react';\n\nexport type AttachmentSelectorContextValue = {\n  fileInput: HTMLInputElement | null;\n};\n\nconst AttachmentSelectorContext = createContext<AttachmentSelectorContextValue>({\n  fileInput: null,\n});\n\nexport const AttachmentSelectorContextProvider = ({\n  children,\n  value,\n}: PropsWithChildren<{ value: AttachmentSelectorContextValue }>) => (\n  <AttachmentSelectorContext.Provider value={value}>\n    {children}\n  </AttachmentSelectorContext.Provider>\n);\n\nexport const useAttachmentSelectorContext = () => useContext(AttachmentSelectorContext);\n","import type { BaseSyntheticEvent, PropsWithChildren, ReactNode } from 'react';\nimport React, { useContext } from 'react';\n\nimport type {\n  DeleteMessageOptions,\n  LocalMessage,\n  Mute,\n  ReactionResponse,\n  ReactionSort,\n  UserResponse,\n} from 'stream-chat';\n\nimport type { ChannelActionContextValue } from './ChannelActionContext';\n\nimport type { ActionHandlerReturnType } from '../components/Message/hooks/useActionHandler';\nimport type { ReactEventHandler } from '../components/Message/types';\nimport type { MessageActionsArray } from '../components/Message/utils';\nimport type { GroupStyle } from '../components/MessageList/utils';\nimport type { ReactionsComparator, ReactionType } from '../components/Reactions/types';\n\nimport type { RenderTextOptions } from '../components/Message/renderText';\n\nexport type MessageContextValue = {\n  /** If actions such as edit, delete, flag, mute are enabled on Message */\n  actionsEnabled: boolean;\n  /**\n   * Returns all allowed actions on message by current user e.g., ['edit', 'delete', 'flag', 'mute', 'pin', 'quote', 'react', 'reply'].\n   * Please check [Message](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message.tsx) component for default implementation.\n   */\n  getMessageActions: () => MessageActionsArray<string>;\n  /** Function to send an action in a Channel */\n  handleAction: ActionHandlerReturnType;\n  /** Function to delete a message in a Channel */\n  handleDelete: (options?: DeleteMessageOptions) => Promise<void> | void;\n  /** Function to fetch the message reactions */\n  handleFetchReactions: (\n    reactionType?: ReactionType,\n    sort?: ReactionSort,\n  ) => Promise<Array<ReactionResponse>>;\n  /** Function to flag a message in a Channel */\n  handleFlag: ReactEventHandler;\n  /** Function to mark message and the messages that follow it as unread in a Channel */\n  handleMarkUnread: ReactEventHandler;\n  /** Function to mute a user in a Channel */\n  handleMute: ReactEventHandler;\n  /** Function to open a Thread on a Message */\n  handleOpenThread: ReactEventHandler;\n  /** Function to pin a Message in a Channel */\n  handlePin: ReactEventHandler;\n  /** Function to post a reaction on a Message */\n  handleReaction: (\n    reactionType: string,\n    event: React.BaseSyntheticEvent,\n  ) => Promise<void>;\n  /** Function to retry sending a Message */\n  handleRetry: ChannelActionContextValue['retrySendMessage'];\n  /** Function that returns whether the Message belongs to the current user */\n  isMyMessage: () => boolean;\n  /** The message object */\n  message: LocalMessage;\n  /** Indicates whether a message has not been read yet or has been marked unread */\n  messageIsUnread: boolean;\n  /** Handler function for a click event on an @mention in Message */\n  onMentionsClickMessage: ReactEventHandler;\n  /** Handler function for a hover event on an @mention in Message */\n  onMentionsHoverMessage: ReactEventHandler;\n  /** Handler function for a click event on the user that posted the Message */\n  onUserClick: ReactEventHandler;\n  /** Handler function for a hover event on the user that posted the Message */\n  onUserHover: ReactEventHandler;\n  /** Call this function to keep message list scrolled to the bottom when the scroll height increases, e.g. an element appears below the last message (only used in the `VirtualizedMessageList`) */\n  autoscrollToBottom?: () => void;\n  /** Message component configuration prop. If true, picking a reaction from the `ReactionSelector` component will close the selector */\n  closeReactionSelectorOnClick?: boolean;\n  /** An array of user IDs that have confirmed the message delivery to their device */\n  deliveredTo?: UserResponse[];\n  /** If true, the message is the last one in a group sent by a specific user (only used in the `VirtualizedMessageList`) */\n  endOfGroup?: boolean;\n  /** If true, the message is the first one in a group sent by a specific user (only used in the `VirtualizedMessageList`) */\n  firstOfGroup?: boolean;\n  /** Override the default formatting of the date. This is a function that has access to the original date object, returns a string  */\n  formatDate?: (date: Date) => string;\n  /** If true, group messages sent by each user (only used in the `VirtualizedMessageList`) */\n  groupedByUser?: boolean;\n  /** A list of styles to apply to this message, ie. top, bottom, single */\n  groupStyles?: GroupStyle[];\n  /** Whether to highlight and focus the message on load */\n  highlighted?: boolean;\n  /** Whether the threaded message is the first in the thread list */\n  initialMessage?: boolean;\n  /**\n   * A factory function that determines whether a message is AI generated or not.\n   */\n  isMessageAIGenerated?: (message: LocalMessage) => boolean;\n  /** Latest own message in currently displayed message set. */\n  lastOwnMessage?: LocalMessage;\n  /** Latest message id on current channel */\n  lastReceivedId?: string | null;\n  /** DOMRect object for parent MessageList component */\n  messageListRect?: DOMRect;\n  /** Array of muted users coming from [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/#mutes) */\n  mutes?: Mute[];\n  /** Sort options to provide to a reactions query */\n  reactionDetailsSort?: ReactionSort;\n  /** A list of users that have read this Message */\n  readBy?: UserResponse[];\n  /** When set, shows the sender avatar in a grid layout. Values: true | 'incoming' | 'outgoing'. */\n  showAvatar?: boolean | 'incoming' | 'outgoing';\n  /** Custom function to render message text content, defaults to the renderText function: [utils](https://github.com/GetStream/stream-chat-react/blob/master/src/utils.tsx) */\n  renderText?: (\n    text?: string,\n    mentioned_users?: UserResponse[],\n    options?: RenderTextOptions,\n  ) => ReactNode;\n  /** Keep track of read receipts for each message sent by the user. When disabled, only the last own message delivery / read status is rendered. */\n  returnAllReadData?: boolean;\n  /** Comparator function to sort reactions, defaults to chronological order */\n  sortReactions?: ReactionsComparator;\n  /** Whether or not the Message is in a Thread */\n  threadList?: boolean;\n  /** render HTML instead of markdown. Posting HTML is only allowed server-side */\n  unsafeHTML?: boolean;\n  /**\n   * User-specific view for translated messages: which text to show.\n   * - `'original'`: show `message.text` (source language).\n   * - `'translated'`: show the translation for the **current user language** (from\n   *   `useTranslationContext().userLanguage`), i.e. `message.i18n[userLanguage + '_text']`\n   *   or fallback to `message.text` when missing. Resolved via `getTranslatedMessageText`.\n   */\n  translationView?: 'original' | 'translated';\n  /** Set whether this message shows original or translated text (user-specific, does not change message data). */\n  setTranslationView?: (view: 'original' | 'translated') => void;\n};\n\nexport const MessageContext = React.createContext<MessageContextValue | undefined>(\n  undefined,\n);\n\nexport const MessageProvider = ({\n  children,\n  value,\n}: PropsWithChildren<{\n  value: MessageContextValue;\n}>) => (\n  <MessageContext.Provider value={value as unknown as MessageContextValue}>\n    {children}\n  </MessageContext.Provider>\n);\n\nexport const useMessageContext = (\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  _componentName?: string,\n) => {\n  const contextValue = useContext(MessageContext);\n\n  if (!contextValue) {\n    return {} as MessageContextValue;\n  }\n\n  return contextValue as unknown as MessageContextValue;\n};\n","import type { MessageComposer } from 'stream-chat';\n\ntype RestoreFunction = () => void;\n\nconst snapshots = new WeakMap<MessageComposer, RestoreFunction>();\n\n/**\n * Captures a full state snapshot of the composer before entering edit mode.\n * Does nothing if a snapshot already exists (e.g. switching between edits).\n */\nexport const savePreEditSnapshot = (messageComposer: MessageComposer) => {\n  if (snapshots.has(messageComposer)) return;\n\n  const composerState = messageComposer.state.getLatestValue();\n  const textState = messageComposer.textComposer.state.getLatestValue();\n  const attachmentState = messageComposer.attachmentManager.state.getLatestValue();\n  const linkPreviewState = messageComposer.linkPreviewsManager.state.getLatestValue();\n  const locationState = messageComposer.locationComposer.state.getLatestValue();\n  const pollState = messageComposer.pollComposer.state.getLatestValue();\n  const customDataState = messageComposer.customDataManager.state.getLatestValue();\n\n  snapshots.set(messageComposer, () => {\n    messageComposer.state.next(composerState);\n    messageComposer.textComposer.state.next(textState);\n    messageComposer.attachmentManager.state.next(attachmentState);\n    messageComposer.linkPreviewsManager.state.next(linkPreviewState);\n    messageComposer.locationComposer.state.next(locationState);\n    messageComposer.pollComposer.state.next(pollState);\n    messageComposer.customDataManager.state.next(customDataState);\n  });\n};\n\n/**\n * Restores the composer to the state captured before editing began.\n * Falls back to `clear()` if no snapshot exists.\n */\nexport const restorePreEditSnapshot = (messageComposer: MessageComposer) => {\n  const restore = snapshots.get(messageComposer);\n  snapshots.delete(messageComposer);\n  if (restore) {\n    restore();\n  } else {\n    messageComposer.clear();\n  }\n};\n\n/**\n * Discards the snapshot without restoring (e.g. after a successful edit save).\n */\nexport const discardPreEditSnapshot = (messageComposer: MessageComposer) => {\n  snapshots.delete(messageComposer);\n};\n","import type { ReactEventHandler } from 'react';\nimport React, { createContext, useCallback, useContext, useMemo } from 'react';\nimport { useMessageContext } from './MessageContext';\nimport { useChannelActionContext } from './ChannelActionContext';\nimport { isMessageBounced, useMessageComposerController } from '../components';\nimport { savePreEditSnapshot } from '../components/MessageComposer/preEditSnapshot';\nimport type { LocalMessage } from 'stream-chat';\nimport type { PropsWithChildrenOnly } from '../types/types';\n\nexport interface MessageBounceContextValue {\n  handleDelete: ReactEventHandler;\n  handleEdit: ReactEventHandler;\n  handleRetry: ReactEventHandler;\n  message: LocalMessage;\n}\n\nconst MessageBounceContext = createContext<MessageBounceContextValue | undefined>(\n  undefined,\n);\n\nexport function useMessageBounceContext(componentName?: string) {\n  const contextValue = useContext(MessageBounceContext);\n\n  if (!contextValue) {\n    console.warn(\n      `The useMessageBounceContext hook was called outside of the MessageBounceContext provider. The errored call is located in the ${componentName} component.`,\n    );\n\n    return {} as MessageBounceContextValue;\n  }\n\n  return contextValue;\n}\n\nexport function MessageBounceProvider({ children }: PropsWithChildrenOnly) {\n  const messageComposer = useMessageComposerController();\n  const { handleRetry: doHandleRetry, message } = useMessageContext(\n    'MessageBounceProvider',\n  );\n\n  if (!isMessageBounced(message)) {\n    console.warn(\n      `The MessageBounceProvider was rendered for a message that is not bounced. Have you missed the \"isMessageBounced\" check?`,\n    );\n  }\n\n  const { removeMessage } = useChannelActionContext('MessageBounceProvider');\n\n  const handleDelete: ReactEventHandler = useCallback(() => {\n    removeMessage(message);\n  }, [message, removeMessage]);\n\n  const handleEdit: ReactEventHandler = useCallback(\n    (e) => {\n      e.preventDefault();\n      savePreEditSnapshot(messageComposer);\n      messageComposer.initState({ composition: message });\n    },\n    [message, messageComposer],\n  );\n\n  const handleRetry = useCallback(() => {\n    doHandleRetry(message);\n  }, [doHandleRetry, message]);\n\n  const value = useMemo(\n    () => ({\n      handleDelete,\n      handleEdit,\n      handleRetry,\n      message,\n    }),\n    [handleDelete, handleEdit, handleRetry, message],\n  );\n\n  return (\n    <MessageBounceContext.Provider value={value}>\n      {children}\n    </MessageBounceContext.Provider>\n  );\n}\n","import React, { createContext, useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { RenderedMessage } from '../components';\n\nexport type MessageListContextValue = {\n  /** Enriched message list, including date separators and intro message (if enabled) */\n  processedMessages: RenderedMessage[];\n  /** The scroll container within which the messages and typing indicator are rendered */\n  listElement: HTMLDivElement | null;\n  /** Function that scrolls the `listElement` to the bottom. */\n  scrollToBottom: () => void;\n};\n\nexport const MessageListContext = createContext<MessageListContextValue | undefined>(\n  undefined,\n);\n\n/**\n * Context provider for components rendered within the `MessageList`\n */\nexport const MessageListContextProvider = ({\n  children,\n  value,\n}: PropsWithChildren<{\n  value: MessageListContextValue;\n}>) => (\n  <MessageListContext.Provider value={value as MessageListContextValue}>\n    {children}\n  </MessageListContext.Provider>\n);\n\nexport const useMessageListContext = (componentName?: string) => {\n  const contextValue = useContext(MessageListContext);\n\n  if (!contextValue) {\n    console.warn(\n      `The useMessageListContext hook was called outside of the MessageListContext provider. Make sure this hook is called within the MessageList component. The errored call is located in the ${componentName} component.`,\n    );\n\n    return {} as MessageListContextValue;\n  }\n\n  return contextValue as MessageListContextValue;\n};\n","/**\n * Message translation view context: user-specific state for whether each message\n * shows original text or a translation.\n *\n * ## Spec\n *\n * - **State**: Per message list (channel vs thread), we store a map\n *   `messageId → 'original' | 'translated'`. Default for messages with `message.i18n`\n *   is `'translated'`; otherwise `'original'`.\n *\n * - **Provider placement**: The provider is tied to the **message list**, not the channel.\n *   It is rendered inside `MessageList` and `VirtualizedMessageList`. That way the\n *   main channel list and the thread list each have their own translation view state\n *   (e.g. Thread.tsx gets correct behavior without sharing channel state).\n *\n * - **Multiple translations**: `message.i18n` can contain multiple languages, e.g.:\n *   `{ en_text: \"Good morning\", fr_text: \"Bonjour\", it_text: \"Buongiorno\", language: \"en\" }`.\n *   Which translation is shown is determined by the app’s **user language**\n *   (`useTranslationContext().userLanguage`). We use `message.i18n[userLanguage + '_text']`;\n *   if missing, we fall back to `message.text`. Only one translation is shown at a time.\n *\n * - **Source language**: When present, `message.i18n.language` is the original/source\n *   language of `message.text`. It can be used for the indicator label, e.g.\n *   \"Translated from English · View original\".\n *\n * - **Invariants**: The original message content, layout, grouping, and order stay\n *   unchanged. Removing or toggling translation only changes the annotation and which\n *   text is displayed. \"View original\" / \"View translation\" switch the displayed\n *   text and update the annotation (e.g. \"Original · View translation\" when showing\n *   original).\n *\n * - **Translation indicator visibility**: The translation indicator (e.g. \"Translated ·\n *   View original\") is **not** shown when the currently viewed text already corresponds\n *   to `userLanguage` — for example when viewing original and the original text is the\n *   user-language version (i.e. `getTranslatedMessageText({ language: userLanguage, message })`\n *   equals `message.text`). In that case there is no meaningful original/translated choice,\n *   so the indicator is hidden.\n */\n\nimport React, { createContext, useCallback, useContext, useState } from 'react';\nimport type { LocalMessage, TranslationLanguages } from 'stream-chat';\n\n/**\n * Returns the translated message text for a given language from `message.i18n`, or\n * undefined if not present. Used to resolve which of the multiple translations to show.\n */\nexport const getTranslatedMessageText = ({\n  language,\n  message,\n}: {\n  language: string;\n  message?: LocalMessage;\n}): string | undefined =>\n  message?.i18n?.[`${language}_text` as `${TranslationLanguages}_text`];\n\n/**\n * Which message text to show.\n * - `'original'`: `message.text` (source language).\n * - `'translated'`: translation for the **current user language** (TranslationContext’s\n *   `userLanguage`), i.e. `getTranslatedMessageText({ language: userLanguage, message })`\n *   or fallback to `message.text`.\n */\nexport type TranslationView = 'original' | 'translated';\n\nexport type MessageTranslationViewContextValue = {\n  getTranslationView: (messageId: string, hasI18n: boolean) => TranslationView;\n  setTranslationView: (messageId: string, view: TranslationView) => void;\n};\n\nconst defaultContextValue: MessageTranslationViewContextValue = {\n  getTranslationView: (_messageId, hasI18n) => (hasI18n ? 'translated' : 'original'),\n  // eslint-disable-next-line @typescript-eslint/no-empty-function\n  setTranslationView: () => {},\n};\n\nexport const MessageTranslationViewContext =\n  createContext<MessageTranslationViewContextValue>(defaultContextValue);\n\nexport const MessageTranslationViewProvider = ({\n  children,\n}: {\n  children: React.ReactNode;\n}) => {\n  const [viewByMessageId, setViewByMessageId] = useState<Record<string, TranslationView>>(\n    {},\n  );\n\n  const setTranslationView = useCallback((messageId: string, view: TranslationView) => {\n    setViewByMessageId((prev) => ({ ...prev, [messageId]: view }));\n  }, []);\n\n  const getTranslationView = useCallback(\n    (messageId: string, hasI18n: boolean): TranslationView =>\n      viewByMessageId[messageId] ?? (hasI18n ? 'translated' : 'original'),\n    [viewByMessageId],\n  );\n\n  const stableValue = React.useMemo(\n    () => ({ getTranslationView, setTranslationView }),\n    [getTranslationView, setTranslationView],\n  );\n\n  return (\n    <MessageTranslationViewContext.Provider value={stableValue}>\n      {children}\n    </MessageTranslationViewContext.Provider>\n  );\n};\n\nexport const useMessageTranslationViewContext =\n  (): MessageTranslationViewContextValue => {\n    const context = useContext(MessageTranslationViewContext);\n    return context ?? defaultContextValue;\n  };\n","import type { PropsWithChildren } from 'react';\nimport React, { useContext } from 'react';\n\nexport type ModalContextValue = {\n  close: () => void;\n  dialogId?: string;\n};\n\nexport const ModalContext = React.createContext<ModalContextValue | undefined>(undefined);\n\nexport const ModalContextProvider = ({\n  children,\n  value,\n}: PropsWithChildren<{\n  value: ModalContextValue;\n}>) => <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;\n\nexport const useModalContext = () => {\n  const contextValue = useContext(ModalContext);\n\n  if (!contextValue) {\n    console.warn(\n      `The useModalContext hook was called outside of the ModalContext provider. Make sure this hook is called within a child of the GlobalModal.`,\n    );\n\n    return { close: () => null };\n  }\n\n  return contextValue;\n};\n","import React, { useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { Poll } from 'stream-chat';\n\nexport type PollContextValue = {\n  poll: Poll;\n};\n\nexport const PollContext = React.createContext<PollContextValue | undefined>(undefined);\n\nexport const PollProvider = ({\n  children,\n  poll,\n}: PropsWithChildren<{\n  poll: Poll;\n}>) =>\n  poll ? (\n    <PollContext.Provider value={{ poll } as unknown as PollContextValue}>\n      {children}\n    </PollContext.Provider>\n  ) : null;\n\nexport const usePollContext = () => {\n  const contextValue = useContext(PollContext);\n  return contextValue as unknown as PollContextValue;\n};\n","import React, { useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\n\nimport { ComponentContext } from './ComponentContext';\nimport type { ComponentContextValue } from './ComponentContext';\n\nexport function WithComponents({\n  children,\n  overrides,\n}: PropsWithChildren<{ overrides: Partial<ComponentContextValue> }>) {\n  const parentOverrides = useContext(ComponentContext);\n  const actualOverrides: ComponentContextValue = { ...parentOverrides, ...overrides };\n  return (\n    <ComponentContext.Provider value={actualOverrides}>\n      {children}\n    </ComponentContext.Provider>\n  );\n}\n","import React from 'react';\nimport type { Channel } from 'stream-chat';\n\nimport { AIStates, useAIState } from './hooks/useAIState';\n\nimport { useChannelStateContext, useTranslationContext } from '../../context';\n\nexport type AIStateIndicatorProps = {\n  channel?: Channel;\n};\n\nexport const AIStateIndicator = ({\n  channel: channelFromProps,\n}: AIStateIndicatorProps) => {\n  const { t } = useTranslationContext();\n  const { channel: channelFromContext } = useChannelStateContext('AIStateIndicator');\n  const channel = channelFromProps || channelFromContext;\n  const { aiState } = useAIState(channel);\n  const allowedStates = {\n    [AIStates.Thinking]: t('Thinking...'),\n    [AIStates.Generating]: t('Generating...'),\n  };\n\n  return aiState in allowedStates ? (\n    <div className='str-chat__ai-state-indicator-container'>\n      <p className='str-chat__ai-state-indicator-text'>{allowedStates[aiState]}</p>\n    </div>\n  ) : null;\n};\n","import React, { type ComponentPropsWithoutRef, type CSSProperties } from 'react';\n\nexport type VisuallyHiddenProps = ComponentPropsWithoutRef<'span'>;\n\nconst visuallyHiddenStyle: CSSProperties = {\n  border: 0,\n  clip: 'rect(0, 0, 0, 0)',\n  height: '1px',\n  margin: '-1px',\n  overflow: 'hidden',\n  padding: 0,\n  position: 'absolute',\n  whiteSpace: 'nowrap',\n  width: '1px',\n};\n\n/**\n * Hides content visually while preserving it for assistive technologies.\n */\nexport const VisuallyHidden = ({ children, style, ...rest }: VisuallyHiddenProps) => (\n  <span {...rest} style={{ ...visuallyHiddenStyle, ...style }}>\n    {children}\n  </span>\n);\n","import { createContext, useContext } from 'react';\n\nexport type AriaLivePriority = 'assertive' | 'polite';\nexport type AriaLiveAnnounce = (message: string, priority?: AriaLivePriority) => void;\n\nexport type AriaLiveAnnouncerContextValue = {\n  announce: AriaLiveAnnounce;\n};\n\nconst noopAnnounce: AriaLiveAnnounce = () => undefined;\n\nexport const AriaLiveAnnouncerContext = createContext<\n  AriaLiveAnnouncerContextValue | undefined\n>(undefined);\n\nexport const useAriaLiveAnnouncer = () => {\n  const contextValue = useContext(AriaLiveAnnouncerContext);\n\n  if (!contextValue) {\n    console.warn(\n      'The useAriaLiveAnnouncer hook was called outside of the AriaLiveRegion provider.',\n    );\n\n    return noopAnnounce;\n  }\n\n  return contextValue.announce;\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Portal } from '../Portal/Portal';\nimport { VisuallyHidden } from '../VisuallyHidden';\nimport {\n  type AriaLiveAnnounce,\n  AriaLiveAnnouncerContext,\n  type AriaLivePriority,\n} from './useAriaLiveAnnouncer';\n\ntype SequenceByPriority = {\n  [key in AriaLivePriority]: number;\n};\n\ntype TimeoutByPriority = {\n  [key in AriaLivePriority]: ReturnType<typeof setTimeout> | undefined;\n};\n\nexport const AriaLiveRegion = ({ children }: PropsWithChildren) => {\n  const [assertiveMessage, setAssertiveMessage] = useState('');\n  const [politeMessage, setPoliteMessage] = useState('');\n  const sequenceByPriorityRef = useRef<SequenceByPriority>({\n    assertive: 0,\n    polite: 0,\n  });\n  const timeoutByPriorityRef = useRef<TimeoutByPriority>({\n    assertive: undefined,\n    polite: undefined,\n  });\n  const unmountedRef = useRef(false);\n\n  const clearPendingTimeout = useCallback((priority: AriaLivePriority) => {\n    if (!timeoutByPriorityRef.current[priority]) return;\n    clearTimeout(timeoutByPriorityRef.current[priority]);\n    timeoutByPriorityRef.current[priority] = undefined;\n  }, []);\n\n  const clearPendingTimeouts = useCallback(() => {\n    clearPendingTimeout('assertive');\n    clearPendingTimeout('polite');\n  }, [clearPendingTimeout]);\n\n  const announce = useCallback<AriaLiveAnnounce>(\n    (message, priority = 'polite') => {\n      const setAnnouncement =\n        priority === 'assertive' ? setAssertiveMessage : setPoliteMessage;\n      const sequence = sequenceByPriorityRef.current[priority] + 1;\n\n      sequenceByPriorityRef.current[priority] = sequence;\n      clearPendingTimeout(priority);\n      setAnnouncement('');\n      timeoutByPriorityRef.current[priority] = setTimeout(() => {\n        if (unmountedRef.current) return;\n        if (sequenceByPriorityRef.current[priority] !== sequence) return;\n        setAnnouncement(message);\n        timeoutByPriorityRef.current[priority] = undefined;\n      }, 50);\n    },\n    [clearPendingTimeout],\n  );\n\n  useEffect(() => {\n    unmountedRef.current = false;\n\n    return () => {\n      unmountedRef.current = true;\n      clearPendingTimeouts();\n    };\n  }, [clearPendingTimeouts]);\n\n  const contextValue = useMemo(() => ({ announce }), [announce]);\n\n  const getPortalDestination = useCallback(() => document.body, []);\n\n  return (\n    <AriaLiveAnnouncerContext.Provider value={contextValue}>\n      {children}\n      <Portal getPortalDestination={getPortalDestination} isOpen>\n        <VisuallyHidden>\n          <div\n            aria-atomic='true'\n            aria-live='polite'\n            aria-relevant='additions text'\n            data-testid='str-chat__aria-live-region--polite'\n            role='status'\n          >\n            {politeMessage}\n          </div>\n          <div\n            aria-atomic='true'\n            aria-live='assertive'\n            aria-relevant='additions text'\n            data-testid='str-chat__aria-live-region--assertive'\n            role='alert'\n          >\n            {assertiveMessage}\n          </div>\n        </VisuallyHidden>\n      </Portal>\n    </AriaLiveAnnouncerContext.Provider>\n  );\n};\n","import React, { useContext, useMemo } from 'react';\n\nimport type { Notification } from 'stream-chat';\nimport type { PropsWithChildrenOnly } from '../../types/types';\nimport type { NotificationTargetPanel } from './notificationTarget';\nimport type { NotificationListFilter } from './NotificationList';\n\nexport type NotificationDisplayFilterParams = {\n  /** Fallback panel used by the receiving NotificationList when a notification has no explicit target. */\n  fallbackPanel?: NotificationTargetPanel;\n  /** Local NotificationList filter. Runs only after the display filter accepts the notification. */\n  filter?: NotificationListFilter;\n  /** Notification being evaluated after panel/fallback routing matched it to this list. */\n  notification: Notification;\n  /** Panel of the NotificationList currently evaluating the notification. */\n  panel?: NotificationTargetPanel;\n};\n\nexport type NotificationDisplayFilter = (\n  params: NotificationDisplayFilterParams,\n) => boolean;\n\nexport type NotificationConfigurationContextValue = {\n  displayFilter: NotificationDisplayFilter;\n};\n\nconst defaultNotificationDisplayFilter: NotificationDisplayFilter = () => true;\n\nconst defaultNotificationConfigurationContextValue: NotificationConfigurationContextValue =\n  {\n    displayFilter: defaultNotificationDisplayFilter,\n  };\n\nconst NotificationConfigurationContext =\n  React.createContext<NotificationConfigurationContextValue>(\n    defaultNotificationConfigurationContextValue,\n  );\n\nexport type NotificationConfigurationProviderProps = PropsWithChildrenOnly & {\n  displayFilter?: NotificationDisplayFilter;\n};\n\nexport const NotificationConfigurationProvider = ({\n  children,\n  displayFilter,\n}: NotificationConfigurationProviderProps) => {\n  const parentConfiguration = useContext(NotificationConfigurationContext);\n  const value = useMemo<NotificationConfigurationContextValue>(\n    () => ({\n      displayFilter: displayFilter ?? parentConfiguration.displayFilter,\n    }),\n    [displayFilter, parentConfiguration.displayFilter],\n  );\n\n  return (\n    <NotificationConfigurationContext.Provider value={value}>\n      {children}\n    </NotificationConfigurationContext.Provider>\n  );\n};\n\nexport const useNotificationConfigurationContext = () =>\n  useContext(NotificationConfigurationContext);\n","import { useCallback } from 'react';\nimport { useChatContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport type { Notification, NotificationManagerState } from 'stream-chat';\nimport { useNotificationConfigurationContext } from '../NotificationConfigurationContext';\nimport { isNotificationForPanel } from '../notificationTarget';\n\nimport type { NotificationTargetPanel } from '../notificationTarget';\n\nexport type UseNotificationsFilter = (notification: Notification) => boolean;\n\nexport type UseNotificationsOptions = {\n  /**\n   * When true, the configured Chat-level notificationDisplayFilter is applied after\n   * panel routing and before the local filter.\n   */\n  applyDisplayFilter?: boolean;\n  /**\n   * When provided, only notifications that pass this filter are returned.\n   * Use to have a given NotificationList consume only a subset of client.notifications\n   * (e.g. by origin.emitter, origin.context, or metadata).\n   */\n  filter?: UseNotificationsFilter;\n  /**\n   * Panel target consumed by a specific notification list.\n   */\n  panel?: NotificationTargetPanel;\n  /**\n   * Fallback panel used when origin.context.panel is absent.\n   * Defaults to `channel`.\n   */\n  fallbackPanel?: NotificationTargetPanel;\n};\n\n/**\n * Subscribes to client.notifications.store and returns the list of notifications.\n * Optionally pass a filter so only notifications that match are returned (e.g. for a specific NotificationList).\n */\nexport const useNotifications = (options?: UseNotificationsOptions): Notification[] => {\n  const { client } = useChatContext();\n  const { displayFilter } = useNotificationConfigurationContext();\n  const { applyDisplayFilter, fallbackPanel, filter, panel } = options ?? {};\n  const selector = useCallback(\n    (state: NotificationManagerState) => {\n      const notifications = state.notifications;\n      return {\n        notifications: notifications.filter((notification) => {\n          if (\n            panel &&\n            !isNotificationForPanel(notification, panel, {\n              fallbackPanel,\n            })\n          ) {\n            return false;\n          }\n\n          if (\n            applyDisplayFilter &&\n            !displayFilter({\n              fallbackPanel,\n              filter,\n              notification,\n              panel,\n            })\n          ) {\n            return false;\n          }\n\n          return filter ? filter(notification) : true;\n        }),\n      };\n    },\n    [applyDisplayFilter, displayFilter, fallbackPanel, filter, panel],\n  );\n\n  const { notifications } = useStateStore(client.notifications.store, selector);\n\n  return notifications;\n};\n","import { useMemo } from 'react';\n\ntype AriaIdentifierDescriptor = 'description' | 'title';\n\nconst sanitizeAriaRootId = (rootId?: string) =>\n  rootId?.trim().replace(/[^A-Za-z0-9:_-]/g, '-') ?? '';\n\nconst buildAriaIdentifier = (\n  sanitizedRootId: string,\n  descriptor: AriaIdentifierDescriptor,\n) => (sanitizedRootId ? `${sanitizedRootId}-${descriptor}` : undefined);\n\n/**\n * Derives stable ARIA identifier IDs from a single root ID.\n *\n * Use this to keep dialog/component labeling conventions consistent without\n * manually building `*-title` and `*-description` IDs at each call site.\n *\n * Behavior:\n * - Root ID is trimmed and sanitized to `[A-Za-z0-9:_-]` before use.\n * - Returns `undefined` IDs when root ID is missing/empty after sanitization.\n */\nexport const useAriaIdentifiers = (rootId?: string) => {\n  const sanitizedRootId = sanitizeAriaRootId(rootId);\n\n  return useMemo(\n    () => ({\n      descriptionId: buildAriaIdentifier(sanitizedRootId, 'description'),\n      titleId: buildAriaIdentifier(sanitizedRootId, 'title'),\n    }),\n    [sanitizedRootId],\n  );\n};\n","import React, { type ComponentProps, type ComponentType, forwardRef } from 'react';\nimport clsx from 'clsx';\nimport { useModalContext } from '../../../context';\nimport { useAriaIdentifiers } from '../../../a11y/hooks/useAriaIdentifiers';\n\nexport const Root = forwardRef<HTMLDivElement, ComponentProps<'div'>>(function AlertRoot(\n  { children, className, ...props }: ComponentProps<'div'>,\n  ref,\n) {\n  return (\n    <div {...props} className={clsx('str-chat__alert-root', className)} ref={ref}>\n      {children}\n    </div>\n  );\n});\n\nexport type AlertHeaderProps = ComponentProps<'div'> & {\n  description?: string;\n  descriptionId?: string;\n  Icon?: ComponentType;\n  title?: string;\n  titleId?: string;\n};\n\nexport const Header = forwardRef<HTMLDivElement, AlertHeaderProps>(function AlertHeader(\n  { children, className, description, descriptionId, Icon, title, titleId, ...props },\n  ref,\n) {\n  const { dialogId } = useModalContext();\n  const { descriptionId: derivedDescriptionId, titleId: derivedTitleId } =\n    useAriaIdentifiers(dialogId);\n  const resolvedTitleId = titleId ?? derivedTitleId;\n  const resolvedDescriptionId = descriptionId ?? derivedDescriptionId;\n\n  return (\n    <div {...props} className={clsx('str-chat__alert-header', className)} ref={ref}>\n      {title ? (\n        <>\n          {Icon && <Icon />}\n          <div className='str-chat__alert-header__copy'>\n            <h2 className='str-chat__alert-header__title' id={resolvedTitleId}>\n              {title}\n            </h2>\n            {description && (\n              <p\n                className='str-chat__alert-header__description'\n                id={resolvedDescriptionId}\n              >\n                {description}\n              </p>\n            )}\n          </div>\n        </>\n      ) : (\n        children\n      )}\n    </div>\n  );\n});\n\nconst Actions = forwardRef<HTMLDivElement, ComponentProps<'div'>>(function AlertActions(\n  { children, className, ...props },\n  ref,\n) {\n  return (\n    <div {...props} className={clsx('str-chat__alert-actions', className)} ref={ref}>\n      {children}\n    </div>\n  );\n});\n\nexport const Alert = {\n  Actions,\n  Header,\n  Root,\n};\n","import clsx from 'clsx';\nimport type { ComponentProps, PropsWithChildren } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { FocusScope } from '@react-aria/focus';\nimport { DialogPortalEntry } from './DialogPortal';\nimport { useDialog, useDialogIsOpen } from '../hooks';\nimport { type OffsetOpt, usePopoverPosition } from '../hooks/usePopoverPosition';\nimport type { PopperLikePlacement } from '../hooks';\nimport type { Placement } from '@floating-ui/react';\n\nexport interface DialogAnchorOptions {\n  open: boolean;\n  placement: PopperLikePlacement;\n  referenceElement: HTMLElement | null;\n  allowFlip?: boolean;\n  updateKey?: unknown;\n  updatePositionOnContentResize?: boolean;\n  offset?: OffsetOpt;\n}\n\nexport function useDialogAnchor<T extends HTMLElement>({\n  allowFlip,\n  offset,\n  open,\n  placement,\n  referenceElement,\n  updateKey,\n  updatePositionOnContentResize = false,\n}: DialogAnchorOptions) {\n  const [popperElement, setPopperElement] = useState<T | null>(null);\n  // keeps track of the first \"chosen\" placement (after popperElement is set) to avoid popper \"jumping\" to a different placement when it updates and finds a better fit; resets when popperElement is unset (!open)\n  const [stabilisedChosenPlacement, setStabilisedChosenPlacement] =\n    useState<Placement | null>(null);\n\n  const {\n    placement: chosenPlacement,\n    refs,\n    strategy,\n    update,\n    x,\n    y,\n  } = usePopoverPosition({\n    allowFlip,\n    freeze: true,\n    offset,\n    placement: stabilisedChosenPlacement ?? placement,\n  });\n\n  if (!stabilisedChosenPlacement && popperElement && placement !== chosenPlacement) {\n    setStabilisedChosenPlacement(chosenPlacement);\n  } else if (stabilisedChosenPlacement && !popperElement) {\n    setStabilisedChosenPlacement(null);\n  }\n\n  // Freeze reference when dialog opens so submenus (e.g. ContextMenu level 2+) stay aligned to the original anchor\n  const frozenReferenceRef = useRef<HTMLElement | null>(null);\n  if (open && referenceElement && !frozenReferenceRef.current) {\n    frozenReferenceRef.current = referenceElement;\n  }\n  if (!open) {\n    frozenReferenceRef.current = null;\n  }\n  const effectiveReference = open ? frozenReferenceRef.current : referenceElement;\n\n  useEffect(() => {\n    refs.setReference(effectiveReference);\n  }, [effectiveReference, refs]);\n\n  useEffect(() => {\n    refs.setFloating(popperElement);\n  }, [popperElement, refs]);\n\n  useEffect(() => {\n    if (open && popperElement && effectiveReference) {\n      // Re-run when reference becomes available (e.g. after ref is set) or when updateKey changes (e.g. submenu open)\n      // Since the popper's reference element might not be (and usually is not) visible\n      // all the time, it's safer to force popper update before showing it.\n      // update is non-null only if popperElement is non-null\n      update?.();\n    }\n  }, [open, placement, popperElement, update, updateKey, effectiveReference]);\n\n  useEffect(() => {\n    if (!popperElement || !updatePositionOnContentResize) return;\n\n    const resizeObserver = new ResizeObserver(update);\n\n    resizeObserver.observe(popperElement);\n\n    return () => {\n      resizeObserver.disconnect();\n    };\n  }, [popperElement, update, updatePositionOnContentResize]);\n\n  if (popperElement && !open) {\n    setPopperElement(null);\n  }\n\n  return {\n    placement: stabilisedChosenPlacement ?? chosenPlacement,\n    setPopperElement,\n    styles: {\n      left: x ?? 0,\n      position: strategy,\n      top: y ?? 0,\n    } as React.CSSProperties,\n  };\n}\n\nexport type DialogAnchorProps = PropsWithChildren<Partial<DialogAnchorOptions>> & {\n  /**\n   * Optional per-dialog override for outside-click dismissal.\n   * If undefined, manager-level `DialogManager.closeOnClickOutside` is used.\n   */\n  closeOnClickOutside?: boolean;\n  id: string;\n  /**\n   * Delay (ms) before unmounting after dialog closes.\n   * Use this to keep the dialog in DOM long enough for CSS exit animations.\n   * `0` means immediate unmount (no exit-animation window).\n   */\n  closeTransitionMs?: number;\n  dialogManagerId?: string;\n  focus?: boolean;\n  trapFocus?: boolean;\n} & ComponentProps<'div'>;\n\nexport const DialogAnchor = ({\n  allowFlip = true,\n  children,\n  className,\n  closeOnClickOutside,\n  closeTransitionMs = 0,\n  dialogManagerId,\n  focus = true,\n  id,\n  offset,\n  placement = 'auto',\n  referenceElement = null,\n  tabIndex,\n  trapFocus,\n  updateKey,\n  updatePositionOnContentResize,\n  ...restDivProps\n}: DialogAnchorProps) => {\n  /**\n   * Rendering lifecycle notes:\n   * - `open=true` renders dialog contents immediately.\n   * - `open=false` can keep contents mounted for `closeTransitionMs` to allow CSS exit\n   *   animations before unmount.\n   *\n   * State exposed to CSS:\n   * - `data-str-chat-dialog-state=\"open\"` while actively open.\n   * - `data-str-chat-dialog-state=\"closing\"` during delayed unmount window.\n   *\n   * Consumers like `ContextMenu` combine:\n   * - `data-str-chat-dialog-state` from this component, and\n   * - `data-str-chat-placement` (e.g. `top-start`, `right-end`)\n   * to select the correct closing keyframe in CSS (horizontal vs vertical roll direction).\n   * In practice, JS only toggles state and timing (`closeTransitionMs`); CSS owns the\n   * visual motion details (transform/easing), so animation behavior stays declarative.\n   */\n  const dialog = useDialog({ closeOnClickOutside, dialogManagerId, id });\n  const open = useDialogIsOpen(id, dialogManagerId);\n  const [shouldRender, setShouldRender] = useState(open);\n  const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n  const isClosing = !open && shouldRender;\n\n  useEffect(() => {\n    if (open) {\n      setShouldRender(true);\n      if (closeTimeoutRef.current) {\n        clearTimeout(closeTimeoutRef.current);\n        closeTimeoutRef.current = null;\n      }\n      return;\n    }\n\n    if (!shouldRender) return;\n    if (!closeTransitionMs) {\n      setShouldRender(false);\n      return;\n    }\n\n    closeTimeoutRef.current = setTimeout(() => {\n      setShouldRender(false);\n      closeTimeoutRef.current = null;\n    }, closeTransitionMs);\n  }, [closeTransitionMs, open, shouldRender]);\n\n  useEffect(\n    () => () => {\n      if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current);\n    },\n    [],\n  );\n\n  const {\n    placement: chosenPlacement,\n    setPopperElement,\n    styles,\n  } = useDialogAnchor<HTMLDivElement>({\n    allowFlip,\n    offset,\n    open: shouldRender,\n    placement,\n    referenceElement,\n    updateKey,\n    updatePositionOnContentResize,\n  });\n\n  useEffect(() => {\n    if (!open) return;\n    const hideOnEscape = (event: KeyboardEvent) => {\n      if (event.key !== 'Escape' || event.defaultPrevented) return;\n      dialog?.close();\n    };\n\n    document.addEventListener('keyup', hideOnEscape);\n\n    return () => {\n      document.removeEventListener('keyup', hideOnEscape);\n    };\n  }, [dialog, open]);\n\n  // prevent rendering the dialog contents if the dialog should not be open / shown\n  if (!shouldRender) {\n    return null;\n  }\n\n  const {\n    ['aria-describedby']: ariaDescribedBy,\n    ['aria-label']: ariaLabel,\n    ['aria-labelledby']: ariaLabelledBy,\n    ['aria-modal']: ariaModal,\n    role,\n    ...anchorDivProps\n  } = restDivProps;\n  const resolvedRole = trapFocus ? (role ?? 'dialog') : role;\n  const resolvedAriaModal = trapFocus ? true : ariaModal;\n  const resolvedAriaLabel = ariaLabelledBy ? undefined : ariaLabel;\n\n  return (\n    <DialogPortalEntry dialogId={id} dialogManagerId={dialogManagerId}>\n      <FocusScope autoFocus={focus} contain={trapFocus} restoreFocus>\n        <div\n          {...anchorDivProps}\n          aria-describedby={ariaDescribedBy}\n          aria-label={resolvedAriaLabel}\n          aria-labelledby={ariaLabelledBy}\n          aria-modal={resolvedAriaModal}\n          className={clsx('str-chat__dialog-contents', className)}\n          data-str-chat-dialog-state={isClosing ? 'closing' : 'open'}\n          data-str-chat-placement={chosenPlacement}\n          data-testid='str-chat__dialog-contents'\n          ref={setPopperElement}\n          role={resolvedRole}\n          style={styles}\n          tabIndex={typeof tabIndex !== 'undefined' ? tabIndex : 0}\n        >\n          {children}\n        </div>\n      </FocusScope>\n    </DialogPortalEntry>\n  );\n};\n","import React from 'react';\nimport { Button } from './Button';\nimport type { ComponentProps } from 'react';\nimport clsx from 'clsx';\nimport { IconPauseFill, IconPlayFill } from '../Icons';\nimport { useTranslationContext } from '../../context';\n\nexport type PlayButtonProps = ComponentProps<'button'> & {\n  isPlaying: boolean;\n};\n\nexport const PlayButton = ({ className, isPlaying, ...props }: PlayButtonProps) => {\n  const { t } = useTranslationContext();\n  return (\n    <Button\n      appearance='outline'\n      aria-label={isPlaying ? t('aria/Pause') : t('aria/Play')}\n      circular\n      className={clsx('str-chat__button-play', className)}\n      data-testid={isPlaying ? 'pause-audio' : 'play-audio'}\n      size='sm'\n      variant='secondary'\n      {...props}\n    >\n      {isPlaying ? <IconPauseFill /> : <IconPlayFill />}\n    </Button>\n  );\n};\n","import React, { type PropsWithChildren } from 'react';\nimport { DialogAnchor, type DialogAnchorProps } from '../service';\nimport { useDialogIsOpen } from '../hooks';\nimport { Button } from '../../Button';\nimport clsx from 'clsx';\nimport { IconXmark } from '../../Icons';\nimport { useComponentContext, useTranslationContext } from '../../../context';\n\nexport type CalloutProps = PropsWithChildren<\n  DialogAnchorProps & {\n    onClose: () => void;\n    className?: string;\n  }\n>;\n\n/**\n * Callout is a general purpose component that displays content in dialog that has been previously opened by clicking on a reference element\n * and has to be dismissed to disappear.\n * Tooltip on the other side is a dialog that appears upon pointer device cursor hovering above a reference element.\n * @param children\n * @param className\n * @param dialogManagerId\n * @param dialogId\n * @param onClose\n * @param anchorProps\n * @constructor\n */\n\nexport const Callout = ({\n  children,\n  className,\n  dialogManagerId,\n  id: dialogId,\n  onClose,\n  ...anchorProps\n}: CalloutProps) => {\n  const { CalloutDialog = DefaultCalloutDialog } = useComponentContext();\n\n  const dialogIsOpen = useDialogIsOpen(dialogId, dialogManagerId);\n  return (\n    <DialogAnchor {...anchorProps} dialogManagerId={dialogManagerId} id={dialogId}>\n      {dialogIsOpen && (\n        <CalloutDialog className={className} onClose={onClose}>\n          {children}\n        </CalloutDialog>\n      )}\n    </DialogAnchor>\n  );\n};\n\nexport type CalloutDialogProps = Pick<CalloutProps, 'children' | 'className' | 'onClose'>;\n\nconst DefaultCalloutDialog = ({ children, className, onClose }: CalloutDialogProps) => {\n  const { t } = useTranslationContext();\n\n  return (\n    <div className='str-chat__callout'>\n      {children}\n      <Button\n        appearance='ghost'\n        aria-label={t('aria/Close callout dialog')}\n        circular\n        className={clsx(className, 'str-chat__callout__close-button')}\n        onClick={onClose}\n        size='sm'\n        variant='secondary'\n      >\n        <IconXmark />\n      </Button>\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport React, {\n  type ComponentPropsWithoutRef,\n  useEffect,\n  useMemo,\n  useState,\n} from 'react';\nimport { IconUser } from '../Icons';\n\nexport type AvatarProps = {\n  /** URL of the avatar image */\n  imageUrl?: string;\n  /** Name of the user, used for avatar image alt text and title fallback */\n  userName?: string;\n  /** Online status indicator, not rendered if not of type boolean */\n  isOnline?: boolean;\n  size: '2xl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs' | (string & {}) | null;\n} & ComponentPropsWithoutRef<'div'>;\n\nconst getInitials = (name?: string) => {\n  const regex = /(\\p{L}{1})\\p{L}+/gu;\n\n  if (!name || name.trim().length === 0) {\n    return '';\n  }\n\n  const initials = Array.from(name?.matchAll(regex) || []);\n\n  if (!initials.length) {\n    return '';\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n  const startInitial = initials.at(0)![1];\n  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n  const endInitial = initials.length > 1 ? initials.at(-1)![1] : '';\n\n  return `${startInitial}${endInitial}`;\n};\n\n/**\n * A round avatar image with fallback to username's first letter\n */\nexport const Avatar = ({\n  className,\n  imageUrl,\n  isOnline,\n  size,\n  userName,\n  ...rest\n}: AvatarProps) => {\n  const [error, setError] = useState(false);\n\n  useEffect(() => () => setError(false), [imageUrl]);\n\n  const nameString = userName?.toString() || '';\n  const avatarImageAlt = nameString.trim();\n\n  const sizeAwareInitials = useMemo(() => {\n    const initials = getInitials(nameString);\n\n    if (size === 'sm' || size === 'xs') {\n      return initials.charAt(0);\n    }\n\n    return initials;\n  }, [nameString, size]);\n\n  const showImage = typeof imageUrl === 'string' && imageUrl && !error;\n\n  return (\n    <div\n      className={clsx(`str-chat__avatar`, className, {\n        'str-chat__avatar--multiple-letters': sizeAwareInitials.length > 1,\n        'str-chat__avatar--no-letters': !sizeAwareInitials.length,\n        'str-chat__avatar--one-letter': sizeAwareInitials.length === 1,\n        [`str-chat__avatar--size-${size}`]: typeof size === 'string',\n      })}\n      data-testid='avatar'\n      role='button'\n      title={userName}\n      {...rest}\n    >\n      {typeof isOnline === 'boolean' && (\n        <div\n          className={clsx('str-chat__avatar-status-badge', {\n            'str-chat__avatar-status-badge--offline': !isOnline,\n            'str-chat__avatar-status-badge--online': isOnline,\n          })}\n        />\n      )}\n      {showImage ? (\n        <img\n          alt={avatarImageAlt}\n          className='str-chat__avatar-image'\n          data-testid='avatar-img'\n          onError={() => setError(true)}\n          src={imageUrl}\n        />\n      ) : (\n        <>\n          {!!sizeAwareInitials.length && (\n            <div className='str-chat__avatar-initials' data-testid='avatar-fallback'>\n              {sizeAwareInitials}\n            </div>\n          )}\n          {!sizeAwareInitials.length && <IconUser />}\n        </>\n      )}\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport React, { type ComponentProps } from 'react';\nimport { IconExclamationMarkFill } from '../Icons';\n\nexport type BadgeVariant =\n  | 'default'\n  | 'primary'\n  | 'error'\n  | 'neutral'\n  | 'counter'\n  | 'inverse';\n\nexport type BadgeSize = 'xs' | 'sm' | 'md' | 'lg' | null;\n\nexport type BadgeProps = ComponentProps<'div'> & {\n  /** Visual variant mapping to design tokens */\n  variant?: BadgeVariant;\n  /** Size preset (typography and padding) */\n  size?: BadgeSize;\n};\n\n/**\n * Compact pill/circle badge for counts and labels.\n * Uses design tokens: --badge-bg-*, --badge-text-*, --badge-border.\n */\nexport const Badge = ({\n  children,\n  className,\n  size = 'md',\n  variant = 'default',\n  ...spanProps\n}: BadgeProps) => (\n  <div\n    {...spanProps}\n    className={clsx(\n      'str-chat__badge',\n      `str-chat__badge--variant-${variant}`,\n      { [`str-chat__badge--size-${size}`]: size },\n      className,\n    )}\n  >\n    {children}\n  </div>\n);\n\nexport const ErrorBadge = ({\n  className,\n  size = 'sm',\n  ...rest\n}: Omit<BadgeProps, 'variant'>) => (\n  <Badge {...rest} className={className} size={size} variant='error'>\n    <IconExclamationMarkFill />\n  </Badge>\n);\n","import React, { type ComponentProps, type ElementType, useMemo } from 'react';\nimport { useComponentContext } from '../../context';\nimport { type AvatarProps, Avatar as DefaultAvatar } from './Avatar';\nimport clsx from 'clsx';\nimport { Badge, type BadgeSize } from '../Badge';\n\nexport function AvatarStack({\n  badgeSize,\n  capLimit = 3,\n  component: Component = 'div',\n  displayInfo = [],\n  size,\n}: {\n  component?: ElementType;\n  displayInfo?: (Pick<AvatarProps, 'imageUrl' | 'userName'> & { id?: string })[];\n  size: 'md' | 'sm' | 'xs' | null;\n  badgeSize?: BadgeSize;\n  capLimit?: number;\n}) {\n  const { Avatar = DefaultAvatar } = useComponentContext(AvatarStack.name);\n\n  const displayInfoToRender = useMemo(\n    () => (displayInfo.length > capLimit ? displayInfo.slice(0, capLimit) : displayInfo),\n    [displayInfo, capLimit],\n  );\n  const overflowCount = displayInfo.length - displayInfoToRender.length;\n\n  if (!displayInfo.length) {\n    return null;\n  }\n\n  return (\n    <Component\n      className={clsx('str-chat__avatar-stack', {\n        [`str-chat__avatar-stack--size-${size}`]: typeof size === 'string',\n      })}\n      data-testid='avatar-stack'\n    >\n      {displayInfoToRender.map((info, index) => (\n        <Avatar\n          imageUrl={info.imageUrl}\n          key={info.id ?? `${info.userName}-${info.imageUrl}-${index}`}\n          size={size}\n          userName={info.userName}\n        />\n      ))}\n      {typeof overflowCount === 'number' && overflowCount > 0 && (\n        <Badge\n          className='str-chat__avatar-stack__count-badge'\n          data-testid='avatar-stack-count-badge'\n          size={badgeSize ?? size}\n          variant='counter'\n        >\n          +{overflowCount}\n        </Badge>\n      )}\n    </Component>\n  );\n}\n\nexport type AvatarStackProps = ComponentProps<typeof AvatarStack>;\n","import React, { useMemo } from 'react';\n\nimport { GroupAvatar } from './';\nimport type { AvatarProps, GroupAvatarProps } from './';\n\nexport type ChannelAvatarProps = Partial<Omit<GroupAvatarProps & AvatarProps, 'size'>> & {\n  size: GroupAvatarProps['size'] | AvatarProps['size'];\n};\n\nexport const ChannelAvatar = ({\n  displayMembers,\n  imageUrl,\n  size,\n  userName,\n  ...sharedProps\n}: ChannelAvatarProps) => {\n  const displayInfo = useMemo(() => {\n    if (displayMembers && displayMembers.length > 0) {\n      return displayMembers;\n    }\n\n    return [\n      {\n        imageUrl,\n        userName,\n      },\n    ];\n  }, [displayMembers, imageUrl, userName]);\n\n  return <GroupAvatar displayMembers={displayInfo} size={size} {...sharedProps} />;\n};\n","import clsx from 'clsx';\nimport React, { type ComponentPropsWithoutRef, useMemo } from 'react';\nimport { Avatar, type AvatarProps } from './Avatar';\nimport { Badge, type BadgeSize } from '../Badge';\n\nexport type GroupAvatarMember = {\n  imageUrl?: string;\n  userName?: string;\n  id?: string;\n};\n\nexport type GroupAvatarProps = {\n  /** List of members to show as avatars; at most 2 when there's more than 4 members, otherwise 4. Defaults to [] when omitted. */\n  displayMembers?: GroupAvatarMember[];\n  size: '2xl' | 'xl' | 'lg' | (string & {}) | null;\n  badgeSize?: BadgeSize;\n  isOnline?: boolean;\n} & ComponentPropsWithoutRef<'div'>;\n\n/**\n * Avatar component to display multiple users' avatars in a group.\n * Renders a single Avatar if fewer than 2 members. Otherwise, renders up to 2 avatars (when overflowCount is set) or 4, plus an optional +N badge.\n */\nexport const GroupAvatar = ({\n  badgeSize,\n  className,\n  displayMembers = [],\n  isOnline,\n  size,\n  ...rest\n}: GroupAvatarProps) => {\n  const displayMembersToRender = useMemo(\n    () => (displayMembers.length > 4 ? displayMembers.slice(0, 2) : displayMembers),\n    [displayMembers],\n  );\n  const overflowCount = displayMembers.length - displayMembersToRender.length;\n\n  if (displayMembers.length < 2) {\n    const firstUser = displayMembers[0];\n\n    return (\n      <Avatar\n        imageUrl={firstUser?.imageUrl}\n        isOnline={isOnline}\n        size={size}\n        userName={firstUser?.userName}\n        {...rest}\n      />\n    );\n  }\n\n  let avatarSize: AvatarProps['size'] = null;\n  if (size === '2xl') {\n    avatarSize = 'lg';\n  } else if (size === 'xl') {\n    avatarSize = 'md';\n  } else if (size === 'lg') {\n    avatarSize = 'sm';\n  }\n\n  return (\n    <div\n      className={clsx(\n        'str-chat__avatar-group',\n        {\n          'str-chat__avatar-group--offline': typeof isOnline === 'boolean' && !isOnline,\n          'str-chat__avatar-group--online': typeof isOnline === 'boolean' && isOnline,\n          [`str-chat__avatar-group--size-${size}`]: typeof size === 'string',\n        },\n        className,\n      )}\n      data-testid='group-avatar'\n      role='button'\n      {...rest}\n    >\n      {displayMembersToRender.map(({ id, imageUrl, userName }, index) => (\n        <Avatar\n          imageUrl={imageUrl}\n          key={id || `${userName}-${imageUrl}-${index}`}\n          size={avatarSize}\n          userName={userName}\n        />\n      ))}\n      {typeof overflowCount === 'number' && overflowCount > 0 && (\n        <Badge\n          className='str-chat__avatar-group__count-badge'\n          data-testid='group-avatar-count-badge'\n          size={badgeSize}\n          variant='counter'\n        >\n          +{overflowCount}\n        </Badge>\n      )}\n    </div>\n  );\n};\n","const MENU_KEYBOARD_NAVIGATION_KEYS = ['ArrowDown', 'ArrowUp', 'End', 'Home'] as const;\n\ntype MenuKeyboardNavigationKey = (typeof MENU_KEYBOARD_NAVIGATION_KEYS)[number];\n\nconst isMenuKeyboardNavigationKey = (key: string): key is MenuKeyboardNavigationKey =>\n  (MENU_KEYBOARD_NAVIGATION_KEYS as readonly string[]).includes(key);\n\ntype GetNextRovingFocusIndexArgs = {\n  activeIndex: number;\n  itemCount: number;\n  key: string;\n};\n\nexport const getNextRovingFocusIndex = ({\n  activeIndex,\n  itemCount,\n  key,\n}: GetNextRovingFocusIndexArgs): number | null => {\n  if (itemCount <= 0 || !isMenuKeyboardNavigationKey(key)) return null;\n\n  const lastIndex = itemCount - 1;\n\n  if (key === 'Home') return 0;\n  if (key === 'End') return lastIndex;\n  if (activeIndex === -1) return key === 'ArrowUp' ? lastIndex : 0;\n  if (key === 'ArrowUp') return activeIndex <= 0 ? lastIndex : activeIndex - 1;\n\n  return activeIndex >= lastIndex ? 0 : activeIndex + 1;\n};\n\ntype RovingFocusKeyboardEvent = {\n  currentTarget: Element;\n  key: string;\n  preventDefault: () => void;\n};\n\ntype CreateRovingFocusKeyDownHandlerParams<T extends { focus: () => void }> = {\n  focusItem?: (item: T, event: RovingFocusKeyboardEvent) => void;\n  getActiveIndex?: (items: T[], event: RovingFocusKeyboardEvent) => number;\n  getItems: (event: RovingFocusKeyboardEvent) => T[];\n};\n\nconst getDefaultActiveIndex = <T extends { focus: () => void }>(items: T[]) => {\n  const activeElement = document.activeElement;\n  if (!(activeElement instanceof Element)) return -1;\n\n  return items.findIndex((item) => item instanceof Element && item === activeElement);\n};\n\nexport const createRovingFocusKeyDownHandler = <T extends { focus: () => void }>({\n  focusItem = (item) => item.focus(),\n  getActiveIndex = (items) => getDefaultActiveIndex(items),\n  getItems,\n}: CreateRovingFocusKeyDownHandlerParams<T>) => {\n  const handleKeyDown = (event: RovingFocusKeyboardEvent) => {\n    const items = getItems(event);\n    const activeIndex = getActiveIndex(items, event);\n    const nextIndex = getNextRovingFocusIndex({\n      activeIndex,\n      itemCount: items.length,\n      key: event.key,\n    });\n\n    if (nextIndex === null) return;\n\n    event.preventDefault();\n    const nextItem = items[nextIndex];\n    if (!nextItem) return;\n    focusItem(nextItem, event);\n  };\n\n  return handleKeyDown;\n};\n","import clsx from 'clsx';\nimport React, {\n  type ComponentProps,\n  type ComponentPropsWithoutRef,\n  type ComponentType,\n  type ReactNode,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport { Avatar, type AvatarProps } from '../../Avatar';\nimport { IconChevronLeft, IconChevronRight } from '../../Icons';\nimport type { PopperLikePlacement } from '../hooks';\nimport { useDialogIsOpen, useDialogOnNearestManager } from '../hooks';\nimport type { DialogAnchorProps } from '../service/DialogAnchor';\nimport { DialogAnchor, useDialogAnchor } from '../service/DialogAnchor';\nimport { useComponentContext } from '../../../context';\nimport { createRovingFocusKeyDownHandler } from '../../../a11y/a11yUtils';\n\n/**\n * ContextMenu module\n *\n * What this file provides\n * - Primitives for contextual action UIs:\n *   `ContextMenu`, `ContextMenuContent`, `ContextMenuButton`, `ContextMenuHeader`,\n *   `ContextMenuBody`, `ContextMenuBackButton`, and user/emoji button variants.\n * - A small runtime context (`useContextMenuContext`) used by menu items to:\n *   - close the current menu (`closeMenu`)\n *   - open a submenu (`openSubmenu`)\n *   - return to parent level (`returnToParentMenu`)\n *\n * Rendering modes\n * - Anchored mode (most common): pass `id` and `referenceElement`.\n *   The component renders inside `DialogAnchor` and uses dialog manager state.\n * - Inline mode: omit anchor props and render as a plain contextual list.\n * - Outside click dismissal can be overridden per menu via `closeOnClickOutside`;\n *   otherwise manager default is used.\n *\n * Submenu model\n * - Submenus are represented as a stack of menu levels.\n * - Each level can define `Header`, `Submenu`, `items`, `ItemsWrapper`,\n *   and `menuClassName`.\n * - Opening submenu pushes a level to the stack; going back pops one level.\n * - When anchored menu closes, stack resets to root to avoid stale submenu state\n *   on next open.\n *\n * Animation model\n * - Root menu open/close is handled by `DialogAnchor` transition timing.\n * - `ContextMenu` defaults `closeTransitionMs` to `130` so close animations can be visible.\n * - `DialogAnchor` marks rendered content with `data-str-chat-dialog-state`:\n *   - `open` while visible\n *   - `closing` during delayed unmount window (`closeTransitionMs`)\n * - Context-menu closing keyframes in `ContextMenu.scss` target\n *   `[data-str-chat-dialog-state='closing']` + placement selectors.\n * - Level-to-level transitions are directional:\n *   - forward: parent -> submenu\n *   - backward: submenu -> parent\n * - Direction is tracked in `ContextMenu` and passed to `ContextMenuContent`.\n * - `ContextMenuContent` bumps an internal key for `ContextMenuBody` so React\n *   remounts the body and CSS enter animation reliably restarts on each level change.\n * - Initial/root menu render does not apply submenu forward/backward classes;\n *   directional animation classes are used only for submenu transitions.\n * - `enableAnimations` can disable content animations through data attributes/CSS.\n * - `submenuTransitionDurationMs` controls how long directional transition state is kept.\n *\n * Submenu popover behavior (`ContextMenuButton` with `Submenu`)\n * - Submenu can be rendered by passing `Submenu` (and optional placement/container props).\n * - Default submenu roll axis is `x` (override with `submenuRollAxis`).\n * - Hover/focus management uses a \"keep open\" ref flag plus lazy close timeout to avoid\n *   accidental submenu dismissal when moving pointer/focus between parent and submenu.\n *\n * Customization via `ComponentContext`\n * - `ComponentContext.ContextMenu` replaces the whole menu component at SDK call sites.\n * - `ComponentContext.ContextMenuContent` replaces content-level behavior while preserving\n *   default anchoring/dialog integration from `ContextMenu`.\n * - Built-in call sites (message actions, channel list action buttons, attachment selector,\n *   suggestion list) resolve `ContextMenu` from `ComponentContext` with fallback to default.\n */\nexport type BaseContextMenuButtonProps = {\n  details?: ReactNode;\n  hasSubMenu?: boolean;\n  label?: ReactNode;\n  Icon?: ComponentType<ComponentProps<'svg'>>;\n  SubmenuIcon?: ComponentType<ComponentProps<'svg'>>;\n  variant?: 'destructive';\n} & ComponentProps<'button'>;\n\nexport const BaseContextMenuButton = ({\n  children,\n  className,\n  details,\n  hasSubMenu,\n  Icon,\n  label,\n  role = 'menuitem',\n  SubmenuIcon = IconChevronRight,\n  variant,\n  ...props\n}: BaseContextMenuButtonProps) => (\n  <button\n    {...props}\n    className={clsx(\n      'str-chat__context-menu__button',\n      {\n        'str-chat__context-menu__button--with-submenu': hasSubMenu,\n        [`str-chat__context-menu__button--${variant}`]: typeof variant === 'string',\n      },\n      className,\n    )}\n    role={role}\n    type='button'\n  >\n    {Icon && <Icon className='str-chat__context-menu__button__icon' />}\n    {label ? (\n      <>\n        <div className='str-chat__context-menu__button__label'>{label}</div>\n        <div className='str-chat__context-menu__button__details'>{details}</div>\n      </>\n    ) : (\n      <div className='str-chat__context-menu__button__label'>{children}</div>\n    )}\n    {!!hasSubMenu && (\n      <SubmenuIcon className='str-chat__context-menu__button__submenu-icon' />\n    )}\n  </button>\n);\n\nexport type UserContextMenuButtonProps = Pick<AvatarProps, 'imageUrl' | 'userName'> &\n  ComponentProps<'button'>;\n\nexport const UserContextMenuButton = ({\n  children,\n  className,\n  imageUrl,\n  role = 'menuitem',\n  userName,\n  ...props\n}: UserContextMenuButtonProps) => (\n  <button\n    {...props}\n    className={clsx(\n      'str-chat__context-menu__button str-chat__user-context-menu__button',\n      className,\n    )}\n    role={role}\n    type='button'\n  >\n    <Avatar imageUrl={imageUrl} size='sm' userName={userName} />\n    <div className='str-chat__context-menu__button__label'>{children ?? userName}</div>\n  </button>\n);\n\nexport type EmojiContextMenuButtonProps = { emoji: string } & Pick<\n  BaseContextMenuButtonProps,\n  'label'\n> &\n  ComponentProps<'button'>;\n\nexport const EmojiContextMenuButton = ({\n  children,\n  className,\n  emoji,\n  label,\n  role = 'menuitem',\n  ...props\n}: EmojiContextMenuButtonProps) => (\n  <button\n    {...props}\n    className={clsx(\n      'str-chat__context-menu__button str-chat__emoji-context-menu__button',\n      className,\n    )}\n    role={role}\n    type='button'\n  >\n    <span className='str-chat__context-menu__button__emoji str-chat__emoji-item--entity'>\n      {emoji}\n    </span>\n    <div className='str-chat__context-menu__button__label'>{children ?? label}</div>\n  </button>\n);\n\ntype ButtonWithSubmenuProps = {\n  Submenu: ComponentType;\n  submenuContainerProps?: ComponentProps<'div'>;\n  submenuPlacement?: PopperLikePlacement;\n  submenuRollAxis?: 'x' | 'y';\n};\n\nconst ContextMenuButtonWithSubmenu = ({\n  children,\n  className,\n  Submenu,\n  submenuContainerProps,\n  submenuPlacement = 'right-start',\n  submenuRollAxis = 'x',\n  ...buttonProps\n}: BaseContextMenuButtonProps & ButtonWithSubmenuProps) => {\n  const { className: submenuClassName, ...submenuContainerRestProps } =\n    submenuContainerProps ?? {};\n  const { registerDialogSubmenu, unregisterDialogSubmenu } = useContextMenuContext();\n  const buttonRef = useRef<HTMLButtonElement | null>(null);\n  const [dialogContainer, setDialogContainer] = useState<HTMLDivElement | null>(null);\n  const keepSubmenuOpenFlag = useRef(false);\n  const dialogCloseTimeout = useRef<NodeJS.Timeout | null>(null);\n  const dialogId = useMemo(() => `submenu-${Math.random().toString(36).slice(2)}`, []);\n  const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n  const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n  useEffect(() => {\n    if (!dialogIsOpen) return;\n    registerDialogSubmenu();\n    return () => unregisterDialogSubmenu();\n  }, [dialogIsOpen, registerDialogSubmenu, unregisterDialogSubmenu]);\n  const {\n    placement: chosenPlacement,\n    setPopperElement,\n    styles,\n  } = useDialogAnchor<HTMLDivElement>({\n    offset: 8,\n    open: dialogIsOpen,\n    placement: submenuPlacement,\n    referenceElement: buttonRef.current,\n  });\n\n  const closeDialogLazily = useCallback(() => {\n    if (dialogCloseTimeout.current) clearTimeout(dialogCloseTimeout.current);\n    dialogCloseTimeout.current = setTimeout(() => {\n      if (keepSubmenuOpenFlag.current) return;\n      dialog.close();\n    }, 100);\n  }, [dialog]);\n\n  const keepSubmenuOpen = useCallback(() => {\n    keepSubmenuOpenFlag.current = true;\n  }, []);\n\n  const allowToCloseSubmenu = useCallback(() => {\n    keepSubmenuOpenFlag.current = false;\n  }, []);\n\n  const closeSubmenu = useCallback(() => {\n    allowToCloseSubmenu();\n    closeDialogLazily();\n  }, [allowToCloseSubmenu, closeDialogLazily]);\n\n  const handleClose = useCallback(\n    (event: Event) => {\n      const parentButton = buttonRef.current;\n      if (!dialogIsOpen || !parentButton) return;\n      event.stopPropagation();\n      closeDialogLazily();\n      parentButton.focus();\n    },\n    [closeDialogLazily, dialogIsOpen, buttonRef],\n  );\n\n  const handleFocusParentButton = () => {\n    if (dialogIsOpen) return;\n    dialog.open();\n    keepSubmenuOpen();\n  };\n\n  useEffect(() => {\n    const parentButton = buttonRef.current;\n    if (!dialogIsOpen || !parentButton) return;\n    const hideOnEscape = (event: KeyboardEvent) => {\n      if (event.key !== 'Escape') return;\n      handleClose(event);\n      closeSubmenu();\n    };\n\n    document.addEventListener('keyup', hideOnEscape, { capture: true });\n\n    return () => {\n      document.removeEventListener('keyup', hideOnEscape, { capture: true });\n    };\n  }, [dialogIsOpen, handleClose, closeSubmenu]);\n\n  return (\n    <>\n      <BaseContextMenuButton\n        aria-expanded={dialogIsOpen}\n        aria-haspopup='menu'\n        className={clsx(className, 'str_chat__button-with-submenu', {\n          'str_chat__button-with-submenu--submenu-open': dialogIsOpen,\n        })}\n        hasSubMenu\n        onBlur={closeSubmenu}\n        onClick={(event) => {\n          event.stopPropagation();\n          dialog.toggle();\n        }}\n        onFocus={handleFocusParentButton}\n        onMouseEnter={handleFocusParentButton}\n        onMouseLeave={closeSubmenu}\n        {...buttonProps}\n        ref={buttonRef}\n      >\n        {children}\n      </BaseContextMenuButton>\n      {dialogIsOpen && (\n        <div\n          className={clsx('str-chat__context-menu__submenu-container', submenuClassName)}\n          data-str-chat-placement={chosenPlacement}\n          data-str-chat-roll-axis={submenuRollAxis}\n          onBlur={(event) => {\n            const isBlurredDescendant =\n              event.relatedTarget instanceof Node &&\n              dialogContainer?.contains(event.relatedTarget);\n            if (isBlurredDescendant) return;\n            closeSubmenu();\n          }}\n          onFocus={keepSubmenuOpen}\n          onMouseEnter={keepSubmenuOpen}\n          onMouseLeave={closeSubmenu}\n          ref={(element) => {\n            setPopperElement(element);\n            setDialogContainer(element);\n          }}\n          style={styles}\n          tabIndex={-1}\n          {...submenuContainerRestProps}\n        >\n          <Submenu />\n        </div>\n      )}\n    </>\n  );\n};\n\ntype ContextMenuButtonProps = BaseContextMenuButtonProps &\n  Partial<ButtonWithSubmenuProps>;\n\nexport const ContextMenuButton = (props: ContextMenuButtonProps) => {\n  const {\n    Submenu,\n    submenuContainerProps,\n    submenuPlacement,\n    submenuRollAxis,\n    ...buttonProps\n  } = props;\n  if (Submenu) {\n    return (\n      <ContextMenuButtonWithSubmenu\n        {...buttonProps}\n        Submenu={Submenu}\n        submenuContainerProps={submenuContainerProps}\n        submenuPlacement={submenuPlacement}\n        submenuRollAxis={submenuRollAxis}\n      />\n    );\n  }\n\n  return <BaseContextMenuButton {...buttonProps} />;\n};\n\nexport const ContextMenuBackButton = ({\n  children,\n  className,\n  role = 'menuitem',\n  ...props\n}: ComponentProps<'button'>) => (\n  <button\n    {...props}\n    className={clsx('str-chat__context-menu__back-button', className)}\n    role={role}\n    type='button'\n  >\n    {children}\n  </button>\n);\n\nexport const ContextMenuHeader = ({\n  children,\n  className,\n  ...props\n}: ComponentProps<'div'>) => (\n  <div {...props} className={clsx('str-chat__context-menu__header', className)}>\n    {children}\n  </div>\n);\n\nexport const ContextMenuBody = ({\n  children,\n  className,\n  ...props\n}: ComponentProps<'div'>) => (\n  <div {...props} className={clsx('str-chat__context-menu__body', className)}>\n    {children}\n  </div>\n);\n\nexport const ContextMenuRoot = React.forwardRef<HTMLDivElement, ComponentProps<'div'>>(\n  function ContextMenuRoot({ className, role = 'menu', ...props }, ref) {\n    return (\n      <div\n        {...props}\n        className={clsx('str-chat__context-menu', className)}\n        ref={ref}\n        role={role}\n      />\n    );\n  },\n);\n\nexport type ContextMenuHeaderComponent = ComponentType;\nexport type ContextMenuSubmenu = ComponentType;\n\nexport type ContextMenuOpenSubmenuParams = Omit<\n  ContextMenuLevel,\n  'focusRestoreRequest' | 'items'\n> & {\n  focusReturnTarget?: HTMLElement | null;\n};\n\nexport type ContextMenuItemProps = ComponentProps<'button'>;\n\nexport type ContextMenuItemComponent = ComponentType<ContextMenuItemProps>;\n\nexport const DEFAULT_CONTEXT_MENU_KEYBOARD_NAVIGATION_ITEM_SELECTOR = [\n  '[role=\"menuitem\"]:not(:disabled)',\n  '[role=\"menuitemradio\"]:not(:disabled)',\n  '[role=\"menuitemcheckbox\"]:not(:disabled)',\n].join(',');\n\nconst isVisibleContextMenuKeyboardNavigationItem = (item: HTMLElement) => {\n  // Fast path: offsetParent is null for display:none elements (and their descendants).\n  // offsetHeight covers position:fixed elements which have no offsetParent.\n  if (item.offsetParent !== null || item.offsetHeight > 0) return true;\n\n  // In environments without layout (e.g. jsdom), offsetParent/offsetHeight are always 0/null.\n  // Fall back to checking inline style and the `hidden` attribute.\n  if (item.hidden) return false;\n  const display = item.style.display;\n  if (display === 'none') return false;\n\n  // If no layout info and no explicit hiding signal, assume visible.\n  return true;\n};\n\ntype ContextMenuFocusRestoreRequest = {\n  /** Positional fallback used when the target element is no longer in the DOM. */\n  index: number;\n  target: HTMLElement | null;\n};\n\nconst getVisibleContextMenuKeyboardNavigationItems = (\n  contextMenuRoot: Element | null,\n  itemSelector: string = DEFAULT_CONTEXT_MENU_KEYBOARD_NAVIGATION_ITEM_SELECTOR,\n) =>\n  Array.from(contextMenuRoot?.querySelectorAll<HTMLElement>(itemSelector) ?? []).filter(\n    isVisibleContextMenuKeyboardNavigationItem,\n  );\n\nconst createContextMenuFocusRestoreRequest = ({\n  contextMenuRoot,\n  focusReturnTarget,\n}: {\n  contextMenuRoot: Element | null;\n  focusReturnTarget?: HTMLElement | null;\n}): ContextMenuFocusRestoreRequest => {\n  const target =\n    focusReturnTarget ??\n    (document.activeElement instanceof HTMLElement ? document.activeElement : null);\n\n  if (!target) return { index: -1, target: null };\n\n  const index = getVisibleContextMenuKeyboardNavigationItems(contextMenuRoot).findIndex(\n    (menuItem) => menuItem === target,\n  );\n\n  return { index, target };\n};\n\nconst resolveContextMenuFocusRestoreTarget = ({\n  contextMenuRoot,\n  request,\n}: {\n  contextMenuRoot: Element | null;\n  request: ContextMenuFocusRestoreRequest | null;\n}) => {\n  if (!request) return null;\n\n  // Prefer the original element if it's still in the DOM.\n  if (request.target?.isConnected) return request.target;\n\n  // Fall back to positional index when the element has been unmounted.\n  if (request.index >= 0) {\n    return (\n      getVisibleContextMenuKeyboardNavigationItems(contextMenuRoot)[request.index] ?? null\n    );\n  }\n\n  return null;\n};\n\nexport type ContextMenuKeyboardNavigation = {\n  /**\n   * CSS selector used to collect focusable menu items.\n   * Defaults to `[role=\"menuitem\"]:not(:disabled)`.\n   */\n  itemSelector?: string;\n};\n\ntype ContextMenuContextValue = {\n  anchorReferenceElement?: HTMLElement | null;\n  closeMenu: () => void;\n  openSubmenu: (params: ContextMenuOpenSubmenuParams) => void;\n  registerDialogSubmenu: () => void;\n  returnToParentMenu: () => void;\n  unregisterDialogSubmenu: () => void;\n};\n\nconst ContextMenuContext = React.createContext<ContextMenuContextValue | undefined>(\n  undefined,\n);\n\nexport const useContextMenuContext = () =>\n  useContext(ContextMenuContext) as ContextMenuContextValue;\n\ntype ContextMenuLevel = {\n  focusRestoreRequest?: ContextMenuFocusRestoreRequest;\n  items?: ContextMenuItemComponent[];\n  Submenu?: ContextMenuSubmenu;\n  Header?: ContextMenuHeaderComponent;\n  ItemsWrapper?: ComponentType;\n  menuClassName?: string;\n};\n\ntype ContextMenuBaseProps = ComponentPropsWithoutRef<'div'> & {\n  backLabel?: ReactNode;\n  enableAnimations?: boolean;\n  Header?: ContextMenuHeaderComponent;\n  /**\n   * Customizes roving-focus keyboard navigation for menu items.\n   * ArrowUp/ArrowDown/Home/End move focus across items matched by\n   * `keyboardNavigation.itemSelector` (defaults to `[role=\"menuitem\"]:not(:disabled)`).\n   * Navigation is always enabled; use this prop only to override the item selector.\n   */\n  keyboardNavigation?: ContextMenuKeyboardNavigation;\n  onClose?: () => void;\n  onMenuLevelChange?: (level: number) => void;\n  /** Duration (ms) to keep submenu transition direction active for forward/backward animations. */\n  submenuTransitionDurationMs?: number;\n} & ContextMenuLevel;\n\n/** When provided, ContextMenu renders inside DialogAnchor and wires menu level for submenu alignment. */\ntype ContextMenuAnchorProps = Partial<\n  Pick<\n    DialogAnchorProps,\n    | 'id'\n    | 'dialogManagerId'\n    | 'placement'\n    | 'referenceElement'\n    | 'tabIndex'\n    | 'trapFocus'\n    | 'allowFlip'\n    | 'closeOnClickOutside'\n    | 'focus'\n    | 'closeTransitionMs'\n    | 'offset'\n  >\n>;\n\nexport type ContextMenuProps = ContextMenuBaseProps & ContextMenuAnchorProps;\n\nexport type ContextMenuContentProps = ContextMenuBaseProps & {\n  anchorReferenceElement?: HTMLElement | null;\n  transitionDirection?: 'forward' | 'backward';\n};\n\n/**\n * Internal/default content renderer for {@link ContextMenu}.\n *\n * Override this through `ComponentContext.ContextMenuContent` when you need to\n * customize submenu/back navigation behavior while keeping the same anchor/focus\n * handling from `ContextMenu`.\n */\nexport function ContextMenuContent({\n  anchorReferenceElement,\n  backLabel = 'Back',\n  children,\n  className,\n  enableAnimations = true,\n  Header,\n  items,\n  ItemsWrapper,\n  keyboardNavigation,\n  menuClassName,\n  onClose,\n  onMenuLevelChange,\n  transitionDirection,\n  ...props\n}: ContextMenuContentProps) {\n  const rootLevel = useMemo<ContextMenuLevel>(\n    () => ({\n      Header,\n      items,\n      ItemsWrapper,\n      menuClassName,\n    }),\n    [Header, items, ItemsWrapper, menuClassName],\n  );\n  const [menuStack, setMenuStack] = useState<ContextMenuLevel[]>(() => [rootLevel]);\n  const [menuBodyAnimationKey, setMenuBodyAnimationKey] = useState(0);\n  const contextMenuRootRef = useRef<HTMLDivElement | null>(null);\n  const focusRestoreRequestRef = useRef<ContextMenuFocusRestoreRequest | null>(null);\n  const activeMenu = menuStack[menuStack.length - 1];\n\n  const ActiveMenuItemsWrapper = activeMenu.ItemsWrapper ?? React.Fragment;\n\n  const closeMenu = useCallback(() => {\n    onClose?.();\n  }, [onClose]);\n\n  const openSubmenu = useCallback(\n    ({\n      focusReturnTarget,\n      Header,\n      ItemsWrapper: SubmenuItemsWrapper,\n      menuClassName,\n      Submenu,\n    }: ContextMenuOpenSubmenuParams) => {\n      const nextLevel: ContextMenuLevel = {\n        focusRestoreRequest: createContextMenuFocusRestoreRequest({\n          contextMenuRoot: contextMenuRootRef.current,\n          focusReturnTarget,\n        }),\n        Header,\n        ItemsWrapper: SubmenuItemsWrapper ?? ItemsWrapper,\n        menuClassName,\n        Submenu,\n      };\n      setMenuStack((current) => [...current, nextLevel]);\n    },\n    [ItemsWrapper],\n  );\n\n  const returnToParentMenu = useCallback(() => {\n    setMenuStack((current) => {\n      if (current.length <= 1) return current;\n      focusRestoreRequestRef.current =\n        current[current.length - 1]?.focusRestoreRequest ?? null;\n      return current.slice(0, -1);\n    });\n  }, []);\n\n  useEffect(() => {\n    setMenuStack((current) => {\n      if (current.length === 1 && current[0] === rootLevel) return current;\n      return [rootLevel];\n    });\n  }, [rootLevel]);\n\n  useEffect(() => {\n    onMenuLevelChange?.(menuStack.length);\n  }, [menuStack.length, onMenuLevelChange]);\n\n  useEffect(() => {\n    const focusRestoreRequest = focusRestoreRequestRef.current;\n    if (!focusRestoreRequest) return;\n    focusRestoreRequestRef.current = null;\n\n    requestAnimationFrame(() => {\n      resolveContextMenuFocusRestoreTarget({\n        contextMenuRoot: contextMenuRootRef.current,\n        request: focusRestoreRequest,\n      })?.focus();\n    });\n  }, [menuStack.length]);\n\n  useEffect(() => {\n    if (!transitionDirection) return;\n    setMenuBodyAnimationKey((value) => value + 1);\n  }, [transitionDirection, menuStack.length]);\n\n  const dialogSubmenuOpenCountRef = useRef(0);\n\n  const registerDialogSubmenu = useCallback(() => {\n    dialogSubmenuOpenCountRef.current += 1;\n  }, []);\n\n  const unregisterDialogSubmenu = useCallback(() => {\n    dialogSubmenuOpenCountRef.current = Math.max(\n      0,\n      dialogSubmenuOpenCountRef.current - 1,\n    );\n  }, []);\n\n  const rovingFocusKeyDownHandler = useMemo(() => {\n    const itemSelector =\n      keyboardNavigation?.itemSelector ??\n      DEFAULT_CONTEXT_MENU_KEYBOARD_NAVIGATION_ITEM_SELECTOR;\n\n    return createRovingFocusKeyDownHandler<HTMLElement>({\n      getItems: (event) =>\n        getVisibleContextMenuKeyboardNavigationItems(event.currentTarget, itemSelector),\n    });\n  }, [keyboardNavigation]);\n\n  const escapeConsumedRef = useRef(false);\n\n  const keyboardNavigationHandler = useCallback(\n    (event: React.KeyboardEvent<HTMLElement>) => {\n      if (event.key === 'Escape') {\n        if (dialogSubmenuOpenCountRef.current > 0) return;\n\n        event.preventDefault();\n        event.stopPropagation();\n\n        if (menuStack.length > 1) {\n          escapeConsumedRef.current = true;\n          returnToParentMenu();\n        } else {\n          closeMenu();\n        }\n        return;\n      }\n\n      rovingFocusKeyDownHandler(event);\n    },\n    [closeMenu, menuStack.length, returnToParentMenu, rovingFocusKeyDownHandler],\n  );\n\n  const suppressEscapeKeyUp = useCallback((event: React.KeyboardEvent<HTMLElement>) => {\n    if (event.key === 'Escape' && escapeConsumedRef.current) {\n      escapeConsumedRef.current = false;\n      event.stopPropagation();\n    }\n  }, []);\n\n  return (\n    <ContextMenuContext.Provider\n      value={{\n        anchorReferenceElement,\n        closeMenu,\n        openSubmenu,\n        registerDialogSubmenu,\n        returnToParentMenu,\n        unregisterDialogSubmenu,\n      }}\n    >\n      <ContextMenuRoot\n        className={clsx(className, activeMenu.menuClassName)}\n        data-str-chat-enable-animations={enableAnimations}\n        onKeyDownCapture={keyboardNavigationHandler}\n        onKeyUpCapture={suppressEscapeKeyUp}\n        ref={contextMenuRootRef}\n        {...props}\n      >\n        {activeMenu.Header ? (\n          <activeMenu.Header />\n        ) : menuStack.length > 1 ? (\n          <ContextMenuHeader>\n            <ContextMenuBackButton onClick={returnToParentMenu}>\n              <IconChevronLeft />\n              <span>{backLabel}</span>\n            </ContextMenuBackButton>\n          </ContextMenuHeader>\n        ) : null}\n        <ContextMenuBody\n          className={clsx({\n            'str-chat__context-menu__body--submenu-backward':\n              transitionDirection === 'backward',\n            'str-chat__context-menu__body--submenu-forward':\n              transitionDirection === 'forward',\n          })}\n          key={`context-menu-body-${menuStack.length}-${menuBodyAnimationKey}`}\n        >\n          {activeMenu.Submenu ? (\n            <activeMenu.Submenu />\n          ) : (\n            <ActiveMenuItemsWrapper>\n              {typeof children !== 'undefined'\n                ? children\n                : activeMenu.items?.map((Item, index) => (\n                    <Item key={`context-menu-item-${index}`} />\n                  ))}\n            </ActiveMenuItemsWrapper>\n          )}\n        </ContextMenuBody>\n      </ContextMenuRoot>\n    </ContextMenuContext.Provider>\n  );\n}\n\n/**\n * Contextual actions menu that can be used in two modes:\n *\n * - Anchored dialog mode: pass `id` + `referenceElement` (submenu-aware positioning).\n * - Inline mode: omit `id` and render a plain contextual list.\n *\n * Customization via `ComponentContext`:\n *\n * - `ContextMenu`: replace the whole menu container/behavior.\n * - `ContextMenuContent`: keep default container behavior but customize menu content\n *   rendering (items, submenu transitions, back navigation UI).\n * - To customize outside-click dismissal via `ComponentContext`, provide a custom\n *   `ContextMenu` that sets `closeOnClickOutside`:\n *\n * ```tsx\n * const CustomContextMenu = (props: ContextMenuProps) => (\n *   <ContextMenu {...props} closeOnClickOutside={false} />\n * );\n *\n * <ComponentProvider value={{ ContextMenu: CustomContextMenu }}>\n *   <Chat client={client}>{children}</Chat>\n * </ComponentProvider>\n * ```\n *\n * Example:\n * ```tsx\n * <ComponentProvider\n *   value={{\n *     ContextMenu: MyContextMenu,\n *     ContextMenuContent: MyContextMenuContent,\n *   }}\n * >\n *   <Chat client={client}>{children}</Chat>\n * </ComponentProvider>\n * ```\n */\nexport const ContextMenu = (props: ContextMenuProps) => {\n  const { ContextMenuContent: ContextMenuContentComponent = ContextMenuContent } =\n    useComponentContext();\n  const {\n    allowFlip,\n    closeOnClickOutside,\n    closeTransitionMs = 130,\n    dialogManagerId,\n    focus,\n    id,\n    offset = 8,\n    onMenuLevelChange: onMenuLevelChangeProp,\n    placement,\n    referenceElement,\n    submenuTransitionDurationMs,\n    tabIndex,\n    trapFocus,\n    ...menuProps\n  } = props;\n  const resolvedSubmenuTransitionDurationMs = submenuTransitionDurationMs ?? 460;\n\n  const isAnchored = id != null;\n\n  const [menuLevel, setMenuLevel] = useState(1);\n  const [transitionDirection, setTransitionDirection] = useState<\n    'forward' | 'backward' | undefined\n  >(undefined);\n  const [contentResetToken, setContentResetToken] = useState(0);\n  const transitionTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n  const previousMenuLevelRef = useRef(1);\n  const open = useDialogIsOpen(id ?? '', dialogManagerId);\n  const previousOpenRef = useRef(open);\n\n  useEffect(() => {\n    if (!isAnchored) return;\n\n    if (previousOpenRef.current && !open) {\n      setMenuLevel(1);\n      setTransitionDirection(undefined);\n      setContentResetToken((value) => value + 1);\n      previousMenuLevelRef.current = 1;\n      if (transitionTimeoutRef.current) {\n        clearTimeout(transitionTimeoutRef.current);\n        transitionTimeoutRef.current = null;\n      }\n    }\n    previousOpenRef.current = open;\n  }, [isAnchored, open]);\n\n  useEffect(\n    () => () => {\n      if (transitionTimeoutRef.current) {\n        clearTimeout(transitionTimeoutRef.current);\n      }\n    },\n    [],\n  );\n\n  const handleMenuLevelChange = useCallback(\n    (level: number) => {\n      if (isAnchored) {\n        const previousLevel = previousMenuLevelRef.current;\n        if (level !== previousLevel) {\n          setTransitionDirection(level > previousLevel ? 'forward' : 'backward');\n          if (transitionTimeoutRef.current) clearTimeout(transitionTimeoutRef.current);\n          transitionTimeoutRef.current = setTimeout(() => {\n            setTransitionDirection(undefined);\n            transitionTimeoutRef.current = null;\n          }, resolvedSubmenuTransitionDurationMs);\n        }\n        previousMenuLevelRef.current = level;\n        setMenuLevel(level);\n        return;\n      }\n      onMenuLevelChangeProp?.(level);\n    },\n    [isAnchored, onMenuLevelChangeProp, resolvedSubmenuTransitionDurationMs],\n  );\n\n  const content = (\n    <ContextMenuContentComponent\n      anchorReferenceElement={isAnchored ? referenceElement : undefined}\n      {...menuProps}\n      key={`context-menu-content-${contentResetToken}`}\n      onMenuLevelChange={handleMenuLevelChange}\n      transitionDirection={transitionDirection}\n    />\n  );\n\n  if (isAnchored) {\n    const {\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      backLabel: _b,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      enableAnimations: _ea,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      Header: _h,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      items: _i,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      ItemsWrapper: _w,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      keyboardNavigation: _kn,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      menuClassName: _m,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      onClose: _c,\n      // eslint-disable-next-line @typescript-eslint/no-unused-vars\n      role: _r,\n      ...anchorDivProps\n    } = menuProps;\n    return (\n      <DialogAnchor\n        allowFlip={allowFlip}\n        closeOnClickOutside={closeOnClickOutside}\n        closeTransitionMs={closeTransitionMs}\n        dialogManagerId={dialogManagerId}\n        focus={focus}\n        id={id}\n        offset={offset}\n        placement={placement}\n        referenceElement={referenceElement}\n        tabIndex={tabIndex}\n        trapFocus={trapFocus}\n        updateKey={menuLevel}\n        {...anchorDivProps}\n      >\n        {content}\n      </DialogAnchor>\n    );\n  }\n\n  return content;\n};\n","import React, { type ComponentProps, type PropsWithChildren } from 'react';\nimport clsx from 'clsx';\nimport { Button, type ButtonProps } from '../../Button';\nimport { IconXmark } from '../../Icons';\nimport { useModalContext, useTranslationContext } from '../../../context';\nimport { useAriaIdentifiers } from '../../../a11y/hooks/useAriaIdentifiers';\n\nconst PromptRoot = ({ children, className, ...props }: ComponentProps<'div'>) => (\n  <div {...props} className={clsx('str-chat__prompt', className)}>\n    {children}\n  </div>\n);\n\nexport type PromptHeaderProps = {\n  title: string;\n  description?: string;\n  className?: string;\n  close?: () => void;\n  descriptionId?: string;\n  titleId?: string;\n};\n\nconst PromptHeader = ({\n  className,\n  close,\n  description,\n  descriptionId,\n  title,\n  titleId,\n}: PromptHeaderProps) => {\n  const { t } = useTranslationContext();\n  const { dialogId } = useModalContext();\n  const { descriptionId: derivedDescriptionId, titleId: derivedTitleId } =\n    useAriaIdentifiers(dialogId);\n  const resolvedTitleId = titleId ?? derivedTitleId;\n  const resolvedDescriptionId = descriptionId ?? derivedDescriptionId;\n\n  return (\n    <div className={clsx('str-chat__prompt__header', className)}>\n      <div className='str-chat__prompt__header__title-group'>\n        <h2 className='str-chat__prompt__header__title' id={resolvedTitleId}>\n          {title}\n        </h2>\n        {description != null && description !== '' && (\n          <p className='str-chat__prompt__header__description' id={resolvedDescriptionId}>\n            {description}\n          </p>\n        )}\n      </div>\n      {close && (\n        <Button\n          appearance='ghost'\n          aria-describedby={\n            description != null && description !== '' ? resolvedDescriptionId : undefined\n          }\n          aria-label={t('Close prompt: {{ title }}', { title })}\n          circular\n          className='str-chat__prompt__header__close-button'\n          onClick={close}\n          size='sm'\n          variant='secondary'\n        >\n          <IconXmark />\n        </Button>\n      )}\n    </div>\n  );\n};\n\nexport type PromptBodyProps = PropsWithChildren<{\n  className?: string;\n}>;\n\nconst PromptBody = ({ children, className }: PromptBodyProps) => (\n  <div className={clsx('str-chat__prompt__body', className)}>{children}</div>\n);\n\nexport type PromptFooterProps = PropsWithChildren<{\n  className?: string;\n}>;\n\nconst PromptFooter = ({ children, className }: PromptFooterProps) => (\n  <div className={clsx('str-chat__prompt__footer', className)}>{children}</div>\n);\n\ntype PromptFooterControlsProps = PropsWithChildren<{\n  className?: string;\n}>;\n\nconst PromptFooterControls = ({ children, className }: PromptFooterControlsProps) => (\n  <div className={clsx('str-chat__prompt__footer__controls', className)}>{children}</div>\n);\n\nconst PromptFooterControlsButtonSecondary = ({ className, ...props }: ButtonProps) => (\n  <Button\n    appearance='ghost'\n    className={clsx('str-chat__prompt__footer__controls-button', className)}\n    size='md'\n    variant='secondary'\n    {...props}\n  />\n);\n\nconst PromptFooterControlsButtonPrimary = ({ className, ...props }: ButtonProps) => (\n  <Button\n    appearance='solid'\n    className={clsx('str-chat__prompt__footer__controls-button', className)}\n    size='md'\n    variant='primary'\n    {...props}\n  />\n);\n\nexport const Prompt = {\n  Body: PromptBody,\n  Footer: PromptFooter,\n  FooterControls: PromptFooterControls,\n  FooterControlsButtonPrimary: PromptFooterControlsButtonPrimary,\n  FooterControlsButtonSecondary: PromptFooterControlsButtonSecondary,\n  Header: PromptHeader,\n  Root: PromptRoot,\n};\n","import React, { type ComponentProps, type PropsWithChildren } from 'react';\nimport clsx from 'clsx';\nimport { Button, type ButtonProps } from '../../Button';\nimport { IconArrowLeft, IconXmark } from '../../Icons';\nimport { useModalContext, useTranslationContext } from '../../../context';\nimport { useAriaIdentifiers } from '../../../a11y/hooks/useAriaIdentifiers';\n\nconst ViewerRoot = ({ children, className, ...props }: ComponentProps<'div'>) => (\n  <div {...props} className={clsx('str-chat__viewer', className)}>\n    {children}\n  </div>\n);\n\nexport type ViewerHeaderProps = {\n  title: string;\n  description?: string;\n  className?: string;\n  close?: () => void;\n  goBack?: () => void;\n  descriptionId?: string;\n  titleId?: string;\n};\n\nconst ViewerHeader = ({\n  className,\n  close,\n  description,\n  descriptionId,\n  goBack,\n  title,\n  titleId,\n}: ViewerHeaderProps) => {\n  const { t } = useTranslationContext();\n  const { dialogId } = useModalContext();\n  const { descriptionId: derivedDescriptionId, titleId: derivedTitleId } =\n    useAriaIdentifiers(dialogId);\n  const resolvedTitleId = titleId ?? derivedTitleId;\n  const resolvedDescriptionId = descriptionId ?? derivedDescriptionId;\n\n  return (\n    <div className={clsx('str-chat__viewer__header', className)}>\n      {goBack && (\n        <Button\n          appearance='ghost'\n          aria-describedby={\n            description != null && description !== '' ? resolvedDescriptionId : undefined\n          }\n          aria-label={t('Back')}\n          circular\n          className='str-chat__viewer__header__go-back-button'\n          onClick={goBack}\n          size='sm'\n          variant='secondary'\n        >\n          <IconArrowLeft />\n        </Button>\n      )}\n      <div className='str-chat__viewer__header__title-group'>\n        <h2 className='str-chat__viewer__header__title' id={resolvedTitleId}>\n          {title}\n        </h2>\n        {description != null && description !== '' && (\n          <p className='str-chat__viewer__header__description' id={resolvedDescriptionId}>\n            {description}\n          </p>\n        )}\n      </div>\n      {close && (\n        <Button\n          appearance='ghost'\n          aria-describedby={\n            description != null && description !== '' ? resolvedDescriptionId : undefined\n          }\n          aria-label={t('Close dialog')}\n          circular\n          className='str-chat__viewer__header__close-button'\n          onClick={close}\n          size='sm'\n          variant='secondary'\n        >\n          <IconXmark />\n        </Button>\n      )}\n    </div>\n  );\n};\n\nexport type ViewerBodyProps = PropsWithChildren<{\n  className?: string;\n}>;\n\nconst ViewerBody = ({ children, className }: ViewerBodyProps) => (\n  <div className={clsx('str-chat__viewer__body', className)}>{children}</div>\n);\n\nexport type ViewerFooterProps = PropsWithChildren<{\n  className?: string;\n}>;\n\nconst ViewerFooter = ({ children, className }: ViewerFooterProps) => (\n  <div className={clsx('str-chat__viewer__footer', className)}>{children}</div>\n);\n\ntype ViewerFooterControlsProps = PropsWithChildren<{\n  className?: string;\n}>;\n\nconst ViewerFooterControls = ({ children, className }: ViewerFooterControlsProps) => (\n  <div className={clsx('str-chat__viewer__footer__controls', className)}>{children}</div>\n);\n\nconst ViewerFooterControlsButtonSecondary = ({ className, ...props }: ButtonProps) => (\n  <Button\n    appearance='ghost'\n    className={clsx('str-chat__viewer__footer__controls-button', className)}\n    size='md'\n    variant='secondary'\n    {...props}\n  />\n);\n\nconst ViewerFooterControlsButtonPrimary = ({ className, ...props }: ButtonProps) => (\n  <Button\n    appearance='solid'\n    className={clsx('str-chat__viewer__footer__controls-button', className)}\n    size='md'\n    variant='primary'\n    {...props}\n  />\n);\n\nexport const Viewer = {\n  Body: ViewerBody,\n  Footer: ViewerFooter,\n  FooterControls: ViewerFooterControls,\n  FooterControlsButtonPrimary: ViewerFooterControlsButtonPrimary,\n  FooterControlsButtonSecondary: ViewerFooterControlsButtonSecondary,\n  Header: ViewerHeader,\n  Root: ViewerRoot,\n};\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} und {{moreCount}} mehr\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} und {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} Datei\",\n  \"{{ count }} files_other\": \"{{ count }} Dateien\",\n  \"{{ count }} people are typing_one\": \"{{ count }} Person tippt\",\n  \"{{ count }} people are typing_many\": \"{{ count }} Personen tippen\",\n  \"{{ count }} people are typing_other\": \"{{ count }} Personen tippen\",\n  \"{{ count }} photos_one\": \"{{ count }} Foto\",\n  \"{{ count }} photos_other\": \"{{ count }} Fotos\",\n  \"{{ count }} reactions_one\": \"{{ count }} Reaktion\",\n  \"{{ count }} reactions_other\": \"{{ count }} Reaktionen\",\n  \"{{ count }} videos_one\": \"{{ count }} Video\",\n  \"{{ count }} videos_other\": \"{{ count }} Videos\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} und {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} mehr\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} Mitglieder\",\n  \"{{ typing }} are typing\": \"{{ typing }} tippen\",\n  \"{{ typing }} is typing\": \"{{ typing }} tippt\",\n  \"{{ user }} has been muted\": \"{{ user }} wurde stummgeschaltet\",\n  \"{{ user }} has been unmuted\": \"Die Stummschaltung von {{ user }} wurde aufgehoben\",\n  \"{{ user }} is typing...\": \"{{ user }} tippt...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} und {{ user }} tippen...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} und mehr tippen...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n  \"{{count}} new messages_one\": \"{{count}} neue Nachricht\",\n  \"{{count}} new messages_other\": \"{{count}} neue Nachrichten\",\n  \"{{count}} unread_one\": \"{{count}} ungelesen\",\n  \"{{count}} unread_other\": \"{{count}} ungelesen\",\n  \"{{count}} votes_one\": \"{{count}} Stimme\",\n  \"{{count}} votes_other\": \"{{count}} Stimmen\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} weitere Option\",\n  \"+{{count}} more options_other\": \"+{{count}} weitere Optionen\",\n  \"🏙 Attachment...\": \"🏙 Anhang...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} hat erstellt: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} hat abgestimmt: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Geteilter Standort\",\n  \"Add a comment\": \"Einen Kommentar hinzufügen\",\n  \"Add a comment to your poll answer\": \"Füge einen Kommentar zu deiner Umfrageantwort hinzu\",\n  \"Add an option\": \"Eine Option hinzufügen\",\n  \"Add reaction\": \"Reaktion hinzufügen\",\n  \"All results loaded\": \"Alle Ergebnisse geladen\",\n  \"Allow access to camera\": \"Zugriff auf Kamera erlauben\",\n  \"Allow access to microphone\": \"Zugriff auf Mikrofon erlauben\",\n  \"Allow comments\": \"Kommentare erlauben\",\n  \"Allow option suggestion\": \"Optionsvorschläge erlauben\",\n  \"Allow others to add comments\": \"Anderen das Hinzufügen von Kommentaren erlauben\",\n  \"Also send as a direct message\": \"Auch als Direktnachricht senden\",\n  \"Also send in channel\": \"Auch im Kanal senden\",\n  \"Also sent in channel\": \"Auch im Kanal gesendet\",\n  \"An error has occurred during recording\": \"Ein Fehler ist während der Aufnahme aufgetreten\",\n  \"An error has occurred during the recording processing\": \"Ein Fehler ist während der Aufnahmeverarbeitung aufgetreten\",\n  \"Anonymous\": \"Anonym\",\n  \"Anonymous poll\": \"Anonyme Umfrage\",\n  \"Archive\": \"Archivieren\",\n  \"Are you sure you want to delete this message?\": \"Sind Sie sicher, dass Sie diese Nachricht löschen möchten?\",\n  \"aria/Attachment\": \"Anhang\",\n  \"aria/Attachment Actions\": \"Anhangaktionen\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Audioposition {{ elapsed }} von {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Audioposition {{ progress }} Prozent\",\n  \"aria/Block User\": \"Benutzer blockieren\",\n  \"aria/Bookmark Message\": \"Nachricht für später speichern\",\n  \"aria/Cancel recording\": \"Aufnahme abbrechen\",\n  \"aria/Cancel Reply\": \"Antwort abbrechen\",\n  \"aria/Cancel upload\": \"Upload abbrechen\",\n  \"aria/Channel Actions\": \"Kanalaktionen\",\n  \"aria/Channel list\": \"Kanalliste\",\n  \"aria/Channel search results\": \"Kanalsuchergebnisse\",\n  \"aria/Chat view tabs\": \"Chat-Ansicht Tabs\",\n  \"aria/Clear search\": \"Suche leeren\",\n  \"aria/Close callout dialog\": \"Hinweisdialog schließen\",\n  \"aria/Close thread\": \"Thread schließen\",\n  \"aria/Collapse sidebar\": \"Seitenleiste einklappen\",\n  \"aria/Command Suggestions\": \"Befehlsvorschläge\",\n  \"aria/Complete recording\": \"Aufnahme abschließen\",\n  \"aria/Copy Message Text\": \"Nachrichtentext kopieren\",\n  \"aria/Decrease value\": \"Wert verringern\",\n  \"aria/Delete Message\": \"Nachricht löschen\",\n  \"aria/Dismiss notification\": \"Benachrichtigung schließen\",\n  \"aria/Download attachment\": \"Anhang herunterladen\",\n  \"aria/Edit Message\": \"Nachricht bearbeiten\",\n  \"aria/Emoji picker\": \"Emoji-Auswahl\",\n  \"aria/Emoji Suggestions\": \"Emoji-Vorschläge\",\n  \"aria/Exit search\": \"Suche verlassen\",\n  \"aria/Expand sidebar\": \"Seitenleiste einblenden\",\n  \"aria/File input\": \"Dateieingabe\",\n  \"aria/File upload\": \"Datei hochladen\",\n  \"aria/Flag Message\": \"Nachricht melden\",\n  \"aria/Image failed to load\": \"Bild konnte nicht geladen werden\",\n  \"aria/Image input\": \"Bildeingabe\",\n  \"aria/Increase value\": \"Wert erhöhen\",\n  \"aria/Jump to latest message\": \"Zur neuesten Nachricht springen\",\n  \"aria/Jump to quoted message\": \"Zur zitierten Nachricht springen\",\n  \"aria/Load More Channels\": \"Mehr Kanäle laden\",\n  \"aria/Mark Message Unread\": \"Als ungelesen markieren\",\n  \"aria/Mark messages as read\": \"Nachrichten als gelesen markieren\",\n  \"aria/Menu\": \"Menü\",\n  \"aria/Message Actions\": \"Nachrichtenaktionen\",\n  \"aria/Message from {{ user }},\": \"Nachricht von {{ user }},\",\n  \"aria/Message Options\": \"Nachrichtenoptionen\",\n  \"aria/Message,\": \"Nachricht,\",\n  \"aria/Mute User\": \"Benutzer stummschalten\",\n  \"aria/Notifications\": \"Benachrichtigungen\",\n  \"aria/Open Attachment Selector\": \"Anhang-Auswahl öffnen\",\n  \"aria/Open Channel Actions Menu\": \"Kanalaktionsmenü öffnen\",\n  \"aria/Open Menu\": \"Menü öffnen\",\n  \"aria/Open Message Actions Menu\": \"Nachrichtenaktionsmenü öffnen\",\n  \"aria/Open Reaction Selector\": \"Reaktionsauswahl öffnen\",\n  \"aria/Open Thread\": \"Thread öffnen\",\n  \"aria/Pause\": \"Pausieren\",\n  \"aria/Pause recording\": \"Aufnahme pausieren\",\n  \"aria/Percent complete\": \"{{percent}} Prozent abgeschlossen\",\n  \"aria/Pin Message\": \"Nachricht anheften\",\n  \"aria/Play\": \"Abspielen\",\n  \"aria/Quote Message\": \"Nachricht zitieren\",\n  \"aria/Reaction list\": \"Reaktionsliste\",\n  \"aria/Remind Me Message\": \"Erinnern\",\n  \"aria/Remind Me Options\": \"Erinnerungsoptionen\",\n  \"aria/Remove attachment\": \"Anhang entfernen\",\n  \"aria/Remove location attachment\": \"Standortanhang entfernen\",\n  \"aria/Remove option\": \"Option entfernen\",\n  \"aria/Remove Reminder\": \"Erinnerung entfernen\",\n  \"aria/Remove Save For Later\": \"„Später ansehen“ entfernen\",\n  \"aria/Resend Message\": \"Nachricht erneut senden\",\n  \"aria/Resume recording\": \"Aufnahme fortsetzen\",\n  \"aria/Retry upload\": \"Upload erneut versuchen\",\n  \"aria/Review bounced message\": \"Zurückgewiesene Nachricht prüfen\",\n  \"aria/Search results\": \"Suchergebnisse\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Filterbutton in der Kopfzeile der Suchergebnisse für: {{ source }}\",\n  \"aria/Seek audio position\": \"Audioposition suchen\",\n  \"aria/Select Channel: {{ channelName }}\": \"Kanal auswählen: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Reaktion auswählen: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Benutzerkanal auswählen: {{ name }}\",\n  \"aria/Send\": \"Senden\",\n  \"aria/Show preview\": \"Vorschau anzeigen\",\n  \"aria/Start recording audio\": \"Audioaufnahme starten\",\n  \"aria/Stop AI Generation\": \"KI-Generierung stoppen\",\n  \"aria/Suggestions\": \"Vorschläge\",\n  \"aria/Thread list\": \"Thread-Liste\",\n  \"aria/Unblock User\": \"Benutzer entsperren\",\n  \"aria/Unmute User\": \"Stummschaltung aufheben\",\n  \"aria/Unpin Message\": \"Anheftung aufheben\",\n  \"aria/User Suggestions\": \"Benutzervorschläge\",\n  \"Ask a question\": \"Eine Frage stellen\",\n  \"Attach\": \"Anhängen\",\n  \"Attach files\": \"Dateien anhängen\",\n  \"Attachment\": \"Anhang\",\n  \"Attachment upload blocked due to {{reason}}\": \"Anhang-Upload blockiert wegen {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Anhang-Upload fehlgeschlagen wegen {{reason}}\",\n  \"Back\": \"Back\",\n  \"ban-command-args\": \"[@Benutzername] [Text]\",\n  \"ban-command-description\": \"Einen Benutzer verbannen\",\n  \"Block User\": \"Benutzer blockieren\",\n  \"Cancel\": \"Abbrechen\",\n  \"Cannot seek in the recording\": \"In der Aufnahme kann nicht gesucht werden\",\n  \"Channel archived\": \"Kanal archiviert\",\n  \"Channel Missing\": \"Kanal fehlt\",\n  \"Channel muted\": \"Kanal stummgeschaltet\",\n  \"Channel pinned\": \"Kanal angeheftet\",\n  \"Channel unarchived\": \"Kanal dearchiviert\",\n  \"Channel unmuted\": \"Stummschaltung des Kanals aufgehoben\",\n  \"Channel unpinned\": \"Kanal nicht mehr angeheftet\",\n  \"Channels\": \"Kanäle\",\n  \"Chats\": \"Chats\",\n  \"Choose between 2 to 10 options\": \"Wähle zwischen 2 und 10 Optionen\",\n  \"Close\": \"Schließen\",\n  \"Close dialog\": \"Dialog schließen\",\n  \"Close emoji picker\": \"Emoji-Auswahl schließen\",\n  \"Close prompt: {{ title }}\": \"Eingabeaufforderung schließen: {{ title }}\",\n  \"Command not available while editing\": \"Befehl beim Bearbeiten nicht verfügbar\",\n  \"Command not available while replying\": \"Befehl beim Antworten nicht verfügbar\",\n  \"Commands\": \"Befehle\",\n  \"Commands matching\": \"Übereinstimmende Befehle\",\n  \"Connection failure, reconnecting now...\": \"Verbindungsfehler, Wiederherstellung der Verbindung...\",\n  \"Copy Message\": \"Nachricht kopieren\",\n  \"Create\": \"Erstellen\",\n  \"Create a question, add options, and configure poll settings\": \"Erstelle eine Frage, füge Optionen hinzu und konfiguriere die Umfrageeinstellungen\",\n  \"Create poll\": \"Umfrage erstellen\",\n  \"Current location\": \"Aktueller Standort\",\n  \"Delete\": \"Löschen\",\n  \"Delete for me\": \"Für mich löschen\",\n  \"Delete message\": \"Nachricht löschen\",\n  \"Delivered\": \"Zugestellt\",\n  \"Direct message\": \"Direktnachricht\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Möchten Sie diese Umfrage jetzt beenden? Niemand wird mehr in dieser Umfrage abstimmen können.\",\n  \"Download All\": \"Alle herunterladen\",\n  \"Download Attachment\": \"Anhang herunterladen\",\n  \"Download attachment {{ name }}\": \"Anhang {{ name }} herunterladen\",\n  \"Drag your files here\": \"Ziehen Sie Ihre Dateien hierher\",\n  \"Drag your files here to add to your post\": \"Ziehen Sie Ihre Dateien hierher, um sie Ihrem Beitrag hinzuzufügen\",\n  \"Due {{ timeLeft }}\": \"Fällig {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Fällig seit {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Nachricht bearbeiten\",\n  \"Edit message request failed\": \"Anfrage zum Bearbeiten der Nachricht fehlgeschlagen\",\n  \"Edited\": \"Bearbeitet\",\n  \"Emoji matching\": \"Passende Emojis\",\n  \"Empty message...\": \"Leere Nachricht...\",\n  \"End\": \"Beenden\",\n  \"End poll\": \"Umfrage beenden\",\n  \"End this poll?\": \"Umfrage beenden?\",\n  \"End vote\": \"Abstimmung beenden\",\n  \"Enforce unique vote is enabled\": \"Eindeutige Abstimmung ist aktiviert\",\n  \"Error\": \"Fehler\",\n  \"Error adding flag\": \"Fehler beim Hinzufügen des Flags\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Verbindungsfehler zum Chat, aktualisieren Sie die Seite, um es erneut zu versuchen.\",\n  \"Error deleting message\": \"Fehler beim Löschen der Nachricht\",\n  \"Error fetching reactions\": \"Fehler beim Laden von Reaktionen\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Fehler beim Markieren der Nachricht als ungelesen. Kann keine älteren ungelesenen Nachrichten markieren als die neuesten 100 Kanalnachrichten.\",\n  \"Error muting a user ...\": \"Fehler beim Stummschalten eines Nutzers.\",\n  \"Error pinning message\": \"Fehler beim Pinnen der Nachricht\",\n  \"Error removing message pin\": \"Fehler beim Entfernen der gepinnten Nachricht\",\n  \"Error reproducing the recording\": \"Fehler bei der Wiedergabe der Aufnahme\",\n  \"Error starting recording\": \"Fehler beim Starten der Aufnahme\",\n  \"Error unmuting a user ...\": \"Fehler beim Aufheben der Stummschaltung eines Nutzers ...\",\n  \"Error uploading attachment\": \"Fehler beim Hochladen des Anhangs\",\n  \"Error uploading file\": \"Fehler beim Hochladen der Datei\",\n  \"Error uploading image\": \"Fehler beim Hochladen des Bildes\",\n  \"Error: {{ errorMessage }}\": \"Fehler: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Befehl beenden {{ command }}\",\n  \"Failed to block user\": \"Benutzer konnte nicht blockiert werden\",\n  \"Failed to create the poll\": \"Fehler beim Erstellen der Umfrage\",\n  \"Failed to create the poll due to {{reason}}\": \"Die Umfrage konnte aufgrund von {{reason}} nicht erstellt werden\",\n  \"Failed to delete the message\": \"Nachricht konnte nicht gelöscht werden\",\n  \"Failed to end the poll\": \"Umfrage konnte nicht beendet werden\",\n  \"Failed to end the poll due to {{reason}}\": \"Umfrage konnte aufgrund von {{reason}} nicht beendet werden\",\n  \"Failed to jump to the first unread message\": \"Fehler beim Springen zur ersten ungelesenen Nachricht\",\n  \"Failed to leave channel\": \"Kanal konnte nicht verlassen werden\",\n  \"Failed to load channels\": \"Kanäle konnten nicht geladen werden\",\n  \"Failed to load more channels\": \"Weitere Kanäle konnten nicht geladen werden\",\n  \"Failed to mark channel as read\": \"Fehler beim Markieren des Kanals als gelesen\",\n  \"Failed to play the recording\": \"Wiedergabe der Aufnahme fehlgeschlagen\",\n  \"Failed to retrieve location\": \"Standort konnte nicht abgerufen werden\",\n  \"Failed to share location\": \"Standort konnte nicht geteilt werden\",\n  \"Failed to update channel archive status\": \"Archivierungsstatus des Kanals konnte nicht aktualisiert werden\",\n  \"Failed to update channel mute status\": \"Stummschaltungsstatus des Kanals konnte nicht aktualisiert werden\",\n  \"Failed to update channel pinned status\": \"Anheftstatus des Kanals konnte nicht aktualisiert werden\",\n  \"File\": \"Datei\",\n  \"File is required for upload attachment\": \"Datei ist für den Anhang-Upload erforderlich\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Datei ist zu groß: {{ size }}, maximale Upload-Größe beträgt {{ limit }}\",\n  \"File too large\": \"Datei ist zu groß\",\n  \"fileCount_one\": \"1 datei\",\n  \"fileCount_other\": \"{{ count }} dateien\",\n  \"Flag\": \"Melden\",\n  \"Generating...\": \"Generieren...\",\n  \"giphy-command-args\": \"[Text]\",\n  \"giphy-command-description\": \"Poste ein zufälliges Gif in den Kanal\",\n  \"Hide who voted\": \"Verbergen, wer abgestimmt hat\",\n  \"Image\": \"Bild\",\n  \"imageCount_one\": \"Bild\",\n  \"imageCount_other\": \"{{ count }} bilder\",\n  \"Instant commands\": \"Instant commands\",\n  \"language/af\": \"Afrikaans\",\n  \"language/am\": \"Amharisch\",\n  \"language/ar\": \"Arabisch\",\n  \"language/az\": \"Aserbaidschanisch\",\n  \"language/bg\": \"Bulgarisch\",\n  \"language/bn\": \"Bengalisch\",\n  \"language/bs\": \"Bosnisch\",\n  \"language/cs\": \"Tschechisch\",\n  \"language/da\": \"Dänisch\",\n  \"language/de\": \"Deutsch\",\n  \"language/el\": \"Griechisch\",\n  \"language/en\": \"Englisch\",\n  \"language/es\": \"Spanisch\",\n  \"language/es-MX\": \"Spanisch (Mexiko)\",\n  \"language/et\": \"Estnisch\",\n  \"language/fa\": \"Persisch\",\n  \"language/fa-AF\": \"Dari\",\n  \"language/fi\": \"Finnisch\",\n  \"language/fr\": \"Französisch\",\n  \"language/fr-CA\": \"Französisch (Kanada)\",\n  \"language/ha\": \"Hausa\",\n  \"language/he\": \"Hebräisch\",\n  \"language/hi\": \"Hindi\",\n  \"language/hr\": \"Kroatisch\",\n  \"language/ht\": \"Haitianisches Kreolisch\",\n  \"language/hu\": \"Ungarisch\",\n  \"language/id\": \"Indonesisch\",\n  \"language/it\": \"Italienisch\",\n  \"language/ja\": \"Japanisch\",\n  \"language/ka\": \"Georgisch\",\n  \"language/ko\": \"Koreanisch\",\n  \"language/lt\": \"Litauisch\",\n  \"language/lv\": \"Lettisch\",\n  \"language/ms\": \"Malaiisch\",\n  \"language/nl\": \"Niederländisch\",\n  \"language/no\": \"Norwegisch\",\n  \"language/pl\": \"Polnisch\",\n  \"language/ps\": \"Paschtu\",\n  \"language/pt\": \"Portugiesisch\",\n  \"language/ro\": \"Rumänisch\",\n  \"language/ru\": \"Russisch\",\n  \"language/sk\": \"Slowakisch\",\n  \"language/sl\": \"Slowenisch\",\n  \"language/so\": \"Somali\",\n  \"language/sq\": \"Albanisch\",\n  \"language/sr\": \"Serbisch\",\n  \"language/sv\": \"Schwedisch\",\n  \"language/sw\": \"Swahili\",\n  \"language/ta\": \"Tamil\",\n  \"language/th\": \"Thailändisch\",\n  \"language/tl\": \"Tagalog\",\n  \"language/tr\": \"Türkisch\",\n  \"language/uk\": \"Ukrainisch\",\n  \"language/ur\": \"Urdu\",\n  \"language/vi\": \"Vietnamesisch\",\n  \"language/zh\": \"Chinesisch (Vereinfacht)\",\n  \"language/zh-TW\": \"Chinesisch (Traditionell)\",\n  \"Leave Channel\": \"Kanal verlassen\",\n  \"Left channel\": \"Kanal verlassen\",\n  \"Let others add options\": \"Andere Optionen hinzufügen lassen\",\n  \"Limit votes per person\": \"Stimmen pro Person begrenzen\",\n  \"Link\": \"Link\",\n  \"linkCount_one\": \"Link\",\n  \"linkCount_other\": \"{{ count }} links\",\n  \"live\": \"live\",\n  \"Live for {{duration}}\": \"Live für {{duration}}\",\n  \"Live location\": \"Live-Standort\",\n  \"Live until {{ timestamp }}\": \"Live bis {{ timestamp }}\",\n  \"Load more\": \"Mehr laden\",\n  \"Local upload attachment missing local id\": \"Lokaler Upload-Anhang hat keine lokale ID\",\n  \"Location\": \"Standort\",\n  \"Location sharing ended\": \"Standortfreigabe beendet\",\n  \"Location: {{ coordinates }}\": \"Standort: {{ coordinates }}\",\n  \"Mark as unread\": \"Als ungelesen markieren\",\n  \"Maximum number of votes (from 2 to 10)\": \"Maximale Anzahl der Stimmen (von 2 bis 10)\",\n  \"Maximum votes per person\": \"Maximale Stimmen pro Person\",\n  \"Menu\": \"Menü\",\n  \"Message deleted\": \"Nachricht gelöscht\",\n  \"Message failed to send\": \"Nachricht konnte nicht gesendet werden\",\n  \"Message has been successfully flagged\": \"Nachricht wurde erfolgreich gemeldet\",\n  \"Message marked as unread\": \"Nachricht als ungelesen markiert\",\n  \"Message pinned\": \"Nachricht angeheftet\",\n  \"Message unpinned\": \"Nachricht nicht mehr angeheftet\",\n  \"Message was blocked by moderation policies\": \"Nachricht wurde durch moderationsrichtlinien blockiert\",\n  \"Messages have been marked unread.\": \"Nachrichten wurden als ungelesen markiert.\",\n  \"Missing permissions to upload the attachment\": \"Fehlende Berechtigungen zum Hochladen des Anhangs\",\n  \"Multiple votes\": \"Mehrfachstimmen\",\n  \"Mute\": \"Stummschalten\",\n  \"mute-command-args\": \"[@Benutzername]\",\n  \"mute-command-description\": \"Stummschalten eines Benutzers\",\n  \"network error\": \"Netzwerkfehler\",\n  \"New\": \"Neu\",\n  \"New message from {{user}}\": \"Neue Nachricht von {{user}}\",\n  \"New Messages!\": \"Neue Nachrichten!\",\n  \"Next image\": \"Nächstes Bild\",\n  \"No chats here yet…\": \"Noch keine Chats hier...\",\n  \"No conversations yet\": \"Noch keine Unterhaltungen\",\n  \"No items exist\": \"Keine Elemente vorhanden\",\n  \"No results found\": \"Keine Ergebnisse gefunden\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Niemand kann mehr in dieser Umfrage abstimmen.\",\n  \"Nothing yet...\": \"Noch nichts...\",\n  \"Offline\": \"Offline\",\n  \"Ok\": \"OK\",\n  \"Online\": \"Online\",\n  \"Only numbers are allowed\": \"Nur Zahlen sind erlaubt\",\n  \"Only visible to you\": \"Nur für dich sichtbar\",\n  \"Open emoji picker\": \"Emoji-Auswahl öffnen\",\n  \"Open gallery at image {{ index }}\": \"Galerie bei Bild {{ index }} öffnen\",\n  \"Open image in gallery\": \"Bild in Galerie öffnen\",\n  \"Open location in a map\": \"Standort in einer Karte öffnen\",\n  \"Option already exists\": \"Option existiert bereits\",\n  \"Option is empty\": \"Option ist leer\",\n  \"Options\": \"Optionen\",\n  \"Original\": \"Original\",\n  \"People matching\": \"Passende Personen\",\n  \"Photo\": \"Foto\",\n  \"Pin\": \"Anheften\",\n  \"Pinned by {{ name }}\": \"Angeheftet von {{ name }}\",\n  \"Pinned by You\": \"Von Ihnen angeheftet\",\n  \"placeholder/PollComment\": \"Ihr Kommentar\",\n  \"placeholder/PollOptionSuggestion\": \"Neue Option eingeben\",\n  \"Play video\": \"Video abspielen\",\n  \"Playback speed {{ rate }}x\": \"Wiedergabegeschwindigkeit {{ rate }}x\",\n  \"Poll\": \"Umfrage\",\n  \"Poll comments\": \"Umfragekommentare\",\n  \"Poll ended\": \"Umfrage beendet\",\n  \"Poll options\": \"Umfrageoptionen\",\n  \"Poll results\": \"Umfrageergebnisse\",\n  \"Previous image\": \"Vorheriges Bild\",\n  \"Question\": \"Frage\",\n  \"Question {{ optionOrderNumber}}\": \"Frage {{ optionOrderNumber}}\",\n  \"Question is required\": \"Frage ist erforderlich\",\n  \"Quote Reply\": \"Zitat-Antwort\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Das Abstimmungslimit wurde erreicht. Entfernen Sie zuerst eine bestehende Stimme.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Aufnahmeformat wird nicht unterstützt und kann nicht wiedergegeben werden\",\n  \"Remind me\": \"Erinnern\",\n  \"Remind Me\": \"Erinnern\",\n  \"Reminder set\": \"Erinnerung gesetzt\",\n  \"Remove reminder\": \"Erinnerung entfernen\",\n  \"Remove save for later\": \"„Später ansehen“ entfernen\",\n  \"Replied to a thread\": \"In einem Thread geantwortet\",\n  \"Reply\": \"Antworten\",\n  \"Reply to {{ authorName }}\": \"Antwort an {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Antworte auf eine Nachricht, um einen Thread zu starten\",\n  \"Reply to Message\": \"Auf Nachricht antworten\",\n  \"replyCount_one\": \"1 Antwort\",\n  \"replyCount_other\": \"{{ count }} Antworten\",\n  \"Resend\": \"Erneut senden\",\n  \"Retry upload\": \"Upload erneut versuchen\",\n  \"Review all options available in this poll\": \"Überprüfe alle verfügbaren Optionen in dieser Umfrage\",\n  \"Review comments submitted with poll answers\": \"Überprüfe Kommentare, die mit Umfrageantworten eingereicht wurden\",\n  \"Review poll results and open an option to see detailed votes\": \"Überprüfe die Umfrageergebnisse und öffne eine Option, um detaillierte Stimmen zu sehen\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Überprüfe diese Nachricht und wähle, ob du sie löschen, bearbeiten oder trotzdem senden möchtest\",\n  \"Review who voted for this option\": \"Überprüfe, wer für diese Option gestimmt hat\",\n  \"Save for later\": \"Für später speichern\",\n  \"Saved for later\": \"Für später gespeichert\",\n  \"Search\": \"Suche\",\n  \"Search GIFs\": \"Search GIFs\",\n  \"search-results-header-filter-source-button-label--channels\": \"Kanäle\",\n  \"search-results-header-filter-source-button-label--messages\": \"Nachrichten\",\n  \"search-results-header-filter-source-button-label--users\": \"Benutzer\",\n  \"Searching for {{ searchSourceType }}...\": \"Suche nach {{ searchSourceType }}...\",\n  \"Searching...\": \"Suchen...\",\n  \"searchResultsCount_one\": \"1 Ergebnis\",\n  \"searchResultsCount_other\": \"{{ count }} Ergebnisse\",\n  \"Select a thread to continue the conversation\": \"Wähle einen Thread aus, um die Unterhaltung fortzusetzen\",\n  \"Select more than one option\": \"Mehr als eine Option auswählen\",\n  \"Select one\": \"Eine auswählen\",\n  \"Select one or more\": \"Eine oder mehrere auswählen\",\n  \"Select up to {{count}}_one\": \"Bis zu {{count}} auswählen\",\n  \"Select up to {{count}}_other\": \"Bis zu {{count}} auswählen\",\n  \"Select your current location and optionally enable live location sharing\": \"Wähle deinen aktuellen Standort und aktiviere optional das Teilen des Live-Standorts\",\n  \"Send\": \"Senden\",\n  \"Send a message\": \"Nachricht senden\",\n  \"Send a message to start the conversation\": \"Senden Sie eine Nachricht, um die Unterhaltung zu beginnen\",\n  \"Send Anyway\": \"Trotzdem senden\",\n  \"Send message request failed\": \"Senden der Nachrichtenanfrage fehlgeschlagen\",\n  \"Send poll\": \"Umfrage senden\",\n  \"Sending...\": \"Senden...\",\n  \"Sent\": \"Gesendet\",\n  \"Share\": \"Teilen\",\n  \"Share live location for\": \"Live-Standort teilen für\",\n  \"Share Location\": \"Standort teilen\",\n  \"Shared live location\": \"Geteilter Live-Standort\",\n  \"Shared location\": \"Geteilter Standort\",\n  \"Shuffle\": \"Mischen\",\n  \"size limit\": \"Größenbeschränkung\",\n  \"Slow Mode ON\": \"Langsamer Modus EIN\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Langsamer Modus, warte {{ seconds }}s...\",\n  \"Some of the files will not be accepted\": \"Einige der Dateien werden nicht akzeptiert\",\n  \"Start typing to search\": \"Tippen Sie, um zu suchen\",\n  \"Stop sharing\": \"Teilen beenden\",\n  \"Submit\": \"Absenden\",\n  \"Suggest a new option to add to this poll\": \"Schlage eine neue Option vor, die zu dieser Umfrage hinzugefügt werden soll\",\n  \"Suggest an option\": \"Eine Option vorschlagen\",\n  \"Tap to remove\": \"Tippen zum Entfernen\",\n  \"Tap to remove: {{ reactionName }}\": \"Tippen zum Entfernen: {{ reactionName }}\",\n  \"Thinking...\": \"Denken...\",\n  \"this content could not be displayed\": \"Dieser Inhalt konnte nicht angezeigt werden\",\n  \"This field cannot be empty or contain only spaces\": \"Dieses Feld darf nicht leer sein oder nur Leerzeichen enthalten\",\n  \"This message did not meet our content guidelines\": \"Diese Nachricht entsprach nicht unseren Inhaltsrichtlinien\",\n  \"Thread\": \"Thread\",\n  \"Thread has not been found\": \"Thread wurde nicht gefunden\",\n  \"Thread reply\": \"Thread-Antwort\",\n  \"Thread Reply\": \"Thread-Antwort\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Laden...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} ungelesener Thread\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} ungelesene Threads\",\n  \"Threads\": \"Diskussionen\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Gestern]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Heute]\\\", \\\"nextDay\\\": \\\"[Morgen]\\\", \\\"lastDay\\\": \\\"[Gestern]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Letzte] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Heute\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Gestern\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Um mit der Aufnahme zu beginnen, erlauben Sie den Zugriff auf die Kamera in Ihrem Browser\",\n  \"To start recording, allow the microphone access in your browser\": \"Um mit der Aufnahme zu beginnen, erlauben Sie den Zugriff auf das Mikrofon in Ihrem Browser\",\n  \"totalVoteCount_one\": \"1 Stimme insgesamt\",\n  \"totalVoteCount_other\": \"{{ count }} Stimmen insgesamt\",\n  \"Translated\": \"Übersetzt\",\n  \"Translated from {{ language }}\": \"Übersetzung aus {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Geben Sie eine Zahl von 2 bis 10 ein\",\n  \"Unarchive\": \"Archivierung aufheben\",\n  \"unban-command-args\": \"[@Benutzername]\",\n  \"unban-command-description\": \"Einen Benutzer entbannen\",\n  \"Unblock User\": \"Benutzer entsperren\",\n  \"unknown error\": \"Unbekannter Fehler\",\n  \"Unmute\": \"Stummschaltung aufheben\",\n  \"unmute-command-args\": \"[@Benutzername]\",\n  \"unmute-command-description\": \"Stummschaltung eines Benutzers aufheben\",\n  \"Unpin\": \"Anheftung aufheben\",\n  \"Unread messages\": \"Ungelesene Nachrichten\",\n  \"Unsupported attachment\": \"Nicht unterstützter Anhang\",\n  \"unsupported file type\": \"Nicht unterstützter Dateityp\",\n  \"Update\": \"Aktualisieren\",\n  \"Update the comment attached to your poll answer\": \"Aktualisiere den Kommentar, der an deine Umfrageantwort angehängt ist\",\n  \"Update your comment\": \"Ihren Kommentar aktualisieren\",\n  \"Upload blocked\": \"Upload blockiert\",\n  \"Upload error\": \"Upload-Fehler\",\n  \"Upload failed\": \"Upload fehlgeschlagen\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Upload-Typ: \\\"{{ type }}\\\" ist nicht erlaubt\",\n  \"User blocked\": \"Benutzer blockiert\",\n  \"User unblocked\": \"Blockierung des Benutzers aufgehoben\",\n  \"User uploaded content\": \"Vom Benutzer hochgeladener Inhalt\",\n  \"Video\": \"Video\",\n  \"videoCount_one\": \"Video\",\n  \"videoCount_other\": \"{{ count }} videos\",\n  \"View\": \"Ansehen\",\n  \"View {{count}} comments_one\": \"{{count}} Kommentar anzeigen\",\n  \"View {{count}} comments_other\": \"{{count}} Kommentare anzeigen\",\n  \"View all\": \"Alle anzeigen\",\n  \"View original\": \"Original anzeigen\",\n  \"View results\": \"Ergebnisse anzeigen\",\n  \"View translation\": \"Übersetzung anzeigen\",\n  \"Voice message\": \"Sprachnachricht\",\n  \"Voice message {{ duration }}\": \"Sprachnachricht {{ duration }}\",\n  \"Voice message deleted\": \"Sprachnachricht gelöscht\",\n  \"voiceMessageCount_one\": \"Sprachnachricht\",\n  \"voiceMessageCount_other\": \"{{ count }} sprachnachrichten\",\n  \"Vote ended\": \"Abstimmung beendet\",\n  \"Votes\": \"Stimmen\",\n  \"Wait until all attachments have uploaded\": \"Bitte warten, bis alle Anhänge hochgeladen wurden\",\n  \"Waiting for network…\": \"Warte auf Netzwerk…\",\n  \"You\": \"Du\",\n  \"You've reached the maximum number of files\": \"Die maximale Anzahl an Dateien ist erreicht\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} and {{ moreCount }} more\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }}, and {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} file\",\n  \"{{ count }} files_other\": \"{{ count }} files\",\n  \"{{ count }} people are typing_one\": \"{{ count }} person is typing\",\n  \"{{ count }} people are typing_many\": \"{{ count }} people are typing\",\n  \"{{ count }} people are typing_other\": \"{{ count }} people are typing\",\n  \"{{ count }} photos_one\": \"{{ count }} photo\",\n  \"{{ count }} photos_other\": \"{{ count }} photos\",\n  \"{{ count }} reactions_one\": \"{{ count }} reaction\",\n  \"{{ count }} reactions_other\": \"{{ count }} reactions\",\n  \"{{ count }} videos_one\": \"{{ count }} video\",\n  \"{{ count }} videos_other\": \"{{ count }} videos\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} and {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} more\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} members\",\n  \"{{ typing }} are typing\": \"{{ typing }} are typing\",\n  \"{{ typing }} is typing\": \"{{ typing }} is typing\",\n  \"{{ user }} has been muted\": \"{{ user }} has been muted\",\n  \"{{ user }} has been unmuted\": \"{{ user }} has been unmuted\",\n  \"{{ user }} is typing...\": \"{{ user }} is typing...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} and {{ user }} are typing...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} and more are typing...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n  \"{{count}} new messages_one\": \"{{count}} new message\",\n  \"{{count}} new messages_other\": \"{{count}} new messages\",\n  \"{{count}} unread_one\": \"{{count}} unread\",\n  \"{{count}} unread_other\": \"{{count}} unread\",\n  \"{{count}} votes_one\": \"{{count}} vote\",\n  \"{{count}} votes_other\": \"{{count}} votes\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} more option\",\n  \"+{{count}} more options_other\": \"+{{count}} more options\",\n  \"🏙 Attachment...\": \"🏙 Attachment...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} created: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} voted: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Shared location\",\n  \"Add a comment\": \"Add a Comment\",\n  \"Add a comment to your poll answer\": \"Add a comment to your poll answer\",\n  \"Add an option\": \"Add an Option\",\n  \"Add reaction\": \"Add reaction\",\n  \"All results loaded\": \"All results loaded\",\n  \"Allow access to camera\": \"Allow access to camera\",\n  \"Allow access to microphone\": \"Allow access to microphone\",\n  \"Allow comments\": \"Allow comments\",\n  \"Allow option suggestion\": \"Allow option suggestion\",\n  \"Allow others to add comments\": \"Allow Others to Add Comments\",\n  \"Also send as a direct message\": \"Also send as a direct message\",\n  \"Also send in channel\": \"Also send in channel\",\n  \"Also sent in channel\": \"Also sent in channel\",\n  \"An error has occurred during recording\": \"An error has occurred during recording\",\n  \"An error has occurred during the recording processing\": \"An error has occurred during the recording processing\",\n  \"Anonymous\": \"Anonymous\",\n  \"Anonymous poll\": \"Anonymous Poll\",\n  \"Archive\": \"Archive\",\n  \"Are you sure you want to delete this message?\": \"Are you sure you want to delete this message?\",\n  \"aria/Attachment\": \"Attachment\",\n  \"aria/Attachment Actions\": \"Attachment Actions\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Audio position {{ elapsed }} of {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Audio position {{ progress }} percent\",\n  \"aria/Block User\": \"Block User\",\n  \"aria/Bookmark Message\": \"Bookmark Message\",\n  \"aria/Cancel recording\": \"Cancel recording\",\n  \"aria/Cancel Reply\": \"Cancel Reply\",\n  \"aria/Cancel upload\": \"Cancel upload\",\n  \"aria/Channel Actions\": \"Channel Actions\",\n  \"aria/Channel list\": \"Channel list\",\n  \"aria/Channel search results\": \"Channel search results\",\n  \"aria/Chat view tabs\": \"Chat view tabs\",\n  \"aria/Clear search\": \"Clear search\",\n  \"aria/Close callout dialog\": \"Close callout dialog\",\n  \"aria/Close thread\": \"Close thread\",\n  \"aria/Collapse sidebar\": \"Collapse sidebar\",\n  \"aria/Command Suggestions\": \"Command Suggestions\",\n  \"aria/Complete recording\": \"Complete recording\",\n  \"aria/Copy Message Text\": \"Copy Message Text\",\n  \"aria/Decrease value\": \"Decrease value\",\n  \"aria/Delete Message\": \"Delete Message\",\n  \"aria/Dismiss notification\": \"Dismiss notification\",\n  \"aria/Download attachment\": \"Download attachment\",\n  \"aria/Edit Message\": \"Edit Message\",\n  \"aria/Emoji picker\": \"Emoji picker\",\n  \"aria/Emoji Suggestions\": \"Emoji Suggestions\",\n  \"aria/Exit search\": \"Exit search\",\n  \"aria/Expand sidebar\": \"Expand sidebar\",\n  \"aria/File input\": \"File input\",\n  \"aria/File upload\": \"File upload\",\n  \"aria/Flag Message\": \"Flag Message\",\n  \"aria/Image failed to load\": \"Image failed to load\",\n  \"aria/Image input\": \"Image input\",\n  \"aria/Increase value\": \"Increase value\",\n  \"aria/Jump to latest message\": \"Jump to latest message\",\n  \"aria/Jump to quoted message\": \"Jump to quoted message\",\n  \"aria/Load More Channels\": \"Load More Channels\",\n  \"aria/Mark Message Unread\": \"Mark Message Unread\",\n  \"aria/Mark messages as read\": \"Mark messages as read\",\n  \"aria/Menu\": \"Menu\",\n  \"aria/Message Actions\": \"Message Actions\",\n  \"aria/Message from {{ user }},\": \"Message from {{ user }},\",\n  \"aria/Message Options\": \"Message Options\",\n  \"aria/Message,\": \"Message,\",\n  \"aria/Mute User\": \"Mute User\",\n  \"aria/Notifications\": \"Notifications\",\n  \"aria/Open Attachment Selector\": \"Open Attachment Selector\",\n  \"aria/Open Channel Actions Menu\": \"Open Channel Actions Menu\",\n  \"aria/Open Menu\": \"Open Menu\",\n  \"aria/Open Message Actions Menu\": \"Open Message Actions Menu\",\n  \"aria/Open Reaction Selector\": \"Open Reaction Selector\",\n  \"aria/Open Thread\": \"Open Thread\",\n  \"aria/Pause\": \"Pause\",\n  \"aria/Pause recording\": \"Pause recording\",\n  \"aria/Percent complete\": \"{{percent}} percent complete\",\n  \"aria/Pin Message\": \"Pin Message\",\n  \"aria/Play\": \"Play\",\n  \"aria/Quote Message\": \"Quote Message\",\n  \"aria/Reaction list\": \"Reaction list\",\n  \"aria/Remind Me Message\": \"Remind Me Message\",\n  \"aria/Remind Me Options\": \"aria/Remind Me Options\",\n  \"aria/Remove attachment\": \"Remove attachment\",\n  \"aria/Remove location attachment\": \"Remove location attachment\",\n  \"aria/Remove option\": \"Remove option\",\n  \"aria/Remove Reminder\": \"Remove Reminder\",\n  \"aria/Remove Save For Later\": \"Remove Save For Later\",\n  \"aria/Resend Message\": \"Resend Message\",\n  \"aria/Resume recording\": \"Resume recording\",\n  \"aria/Retry upload\": \"Retry upload\",\n  \"aria/Review bounced message\": \"Review bounced message\",\n  \"aria/Search results\": \"Search results\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Search results header filter button for: {{ source }}\",\n  \"aria/Seek audio position\": \"Seek audio position\",\n  \"aria/Select Channel: {{ channelName }}\": \"Select Channel: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Select Reaction: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Select User Channel: {{ name }}\",\n  \"aria/Send\": \"Send\",\n  \"aria/Show preview\": \"Show preview\",\n  \"aria/Start recording audio\": \"Start recording audio\",\n  \"aria/Stop AI Generation\": \"Stop AI Generation\",\n  \"aria/Suggestions\": \"Suggestions\",\n  \"aria/Thread list\": \"Thread list\",\n  \"aria/Unblock User\": \"Unblock User\",\n  \"aria/Unmute User\": \"Unmute User\",\n  \"aria/Unpin Message\": \"Unpin Message\",\n  \"aria/User Suggestions\": \"User Suggestions\",\n  \"Ask a question\": \"Ask a Question\",\n  \"Attach\": \"Attach\",\n  \"Attach files\": \"Attach files\",\n  \"Attachment\": \"Attachment\",\n  \"Attachment upload blocked due to {{reason}}\": \"Attachment upload blocked due to {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Attachment upload failed due to {{reason}}\",\n  \"Back\": \"Back\",\n  \"ban-command-args\": \"[@username] [text]\",\n  \"ban-command-description\": \"Ban a user\",\n  \"Block User\": \"Block User\",\n  \"Cancel\": \"Cancel\",\n  \"Cannot seek in the recording\": \"Cannot seek in the recording\",\n  \"Channel archived\": \"Channel archived\",\n  \"Channel Missing\": \"Channel Missing\",\n  \"Channel muted\": \"Channel muted\",\n  \"Channel pinned\": \"Channel pinned\",\n  \"Channel unarchived\": \"Channel unarchived\",\n  \"Channel unmuted\": \"Channel unmuted\",\n  \"Channel unpinned\": \"Channel unpinned\",\n  \"Channels\": \"Channels\",\n  \"Chats\": \"Chats\",\n  \"Choose between 2 to 10 options\": \"Choose Between 2 to 10 Options\",\n  \"Close\": \"Close\",\n  \"Close dialog\": \"Close dialog\",\n  \"Close emoji picker\": \"Close emoji picker\",\n  \"Close prompt: {{ title }}\": \"Close prompt: {{ title }}\",\n  \"Command not available while editing\": \"Command not available while editing\",\n  \"Command not available while replying\": \"Command not available while replying\",\n  \"Commands\": \"Commands\",\n  \"Commands matching\": \"Commands matching\",\n  \"Connection failure, reconnecting now...\": \"Connection failure, reconnecting now...\",\n  \"Copy Message\": \"Copy Message\",\n  \"Create\": \"Create\",\n  \"Create a question, add options, and configure poll settings\": \"Create a question, add options, and configure poll settings\",\n  \"Create poll\": \"Create Poll\",\n  \"Current location\": \"Current location\",\n  \"Delete\": \"Delete\",\n  \"Delete for me\": \"Delete for me\",\n  \"Delete message\": \"Delete message\",\n  \"Delivered\": \"Delivered\",\n  \"Direct message\": \"Direct message\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\",\n  \"Download All\": \"Download All\",\n  \"Download Attachment\": \"Download Attachment\",\n  \"Download attachment {{ name }}\": \"Download attachment {{ name }}\",\n  \"Drag your files here\": \"Drag your files here\",\n  \"Drag your files here to add to your post\": \"Drag your files here to add to your post\",\n  \"Due {{ timeLeft }}\": \"Due {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Due since {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Edit Message\",\n  \"Edit message request failed\": \"Edit message request failed\",\n  \"Edited\": \"Edited\",\n  \"Emoji matching\": \"Emoji matching\",\n  \"Empty message...\": \"Empty message...\",\n  \"End\": \"End\",\n  \"End poll\": \"End Poll\",\n  \"End this poll?\": \"End this Poll?\",\n  \"End vote\": \"End Vote\",\n  \"Enforce unique vote is enabled\": \"Enforce unique vote is enabled\",\n  \"Error\": \"Error\",\n  \"Error adding flag\": \"Error adding flag\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Error connecting to chat, refresh the page to try again.\",\n  \"Error deleting message\": \"Error deleting message\",\n  \"Error fetching reactions\": \"Error loading reactions\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\",\n  \"Error muting a user ...\": \"Error muting a user ...\",\n  \"Error pinning message\": \"Error pinning message\",\n  \"Error removing message pin\": \"Error removing message pin\",\n  \"Error reproducing the recording\": \"Error reproducing the recording\",\n  \"Error starting recording\": \"Error starting recording\",\n  \"Error unmuting a user ...\": \"Error unmuting a user ...\",\n  \"Error uploading attachment\": \"Error uploading attachment\",\n  \"Error uploading file\": \"Error uploading file\",\n  \"Error uploading image\": \"Error uploading image\",\n  \"Error: {{ errorMessage }}\": \"Error: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Exit command {{ command }}\",\n  \"Failed to block user\": \"Failed to block user\",\n  \"Failed to create the poll\": \"Failed to create the poll\",\n  \"Failed to create the poll due to {{reason}}\": \"Failed to create the poll due to {{reason}}\",\n  \"Failed to delete the message\": \"Failed to delete the message\",\n  \"Failed to end the poll\": \"Failed to end the poll\",\n  \"Failed to end the poll due to {{reason}}\": \"Failed to end the poll due to {{reason}}\",\n  \"Failed to jump to the first unread message\": \"Failed to jump to the first unread message\",\n  \"Failed to leave channel\": \"Failed to leave channel\",\n  \"Failed to load channels\": \"Failed to load channels\",\n  \"Failed to load more channels\": \"Failed to load more channels\",\n  \"Failed to mark channel as read\": \"Failed to mark channel as read\",\n  \"Failed to play the recording\": \"Failed to play the recording\",\n  \"Failed to retrieve location\": \"Failed to retrieve location\",\n  \"Failed to share location\": \"Failed to share location\",\n  \"Failed to update channel archive status\": \"Failed to update channel archive status\",\n  \"Failed to update channel mute status\": \"Failed to update channel mute status\",\n  \"Failed to update channel pinned status\": \"Failed to update channel pinned status\",\n  \"File\": \"File\",\n  \"File is required for upload attachment\": \"File is required for upload attachment\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"File is too large: {{ size }}, maximum upload size is {{ limit }}\",\n  \"File too large\": \"File too large\",\n  \"fileCount_one\": \"File\",\n  \"fileCount_other\": \"{{ count }} files\",\n  \"Flag\": \"Flag\",\n  \"Generating...\": \"Generating...\",\n  \"giphy-command-args\": \"[text]\",\n  \"giphy-command-description\": \"Post a random gif to the channel\",\n  \"Hide who voted\": \"Hide Who Voted\",\n  \"Image\": \"Image\",\n  \"imageCount_one\": \"Image\",\n  \"imageCount_other\": \"{{ count }} images\",\n  \"Instant commands\": \"Instant commands\",\n  \"language/af\": \"Afrikaans\",\n  \"language/am\": \"Amharic\",\n  \"language/ar\": \"Arabic\",\n  \"language/az\": \"Azerbaijani\",\n  \"language/bg\": \"Bulgarian\",\n  \"language/bn\": \"Bengali\",\n  \"language/bs\": \"Bosnian\",\n  \"language/cs\": \"Czech\",\n  \"language/da\": \"Danish\",\n  \"language/de\": \"German\",\n  \"language/el\": \"Greek\",\n  \"language/en\": \"English\",\n  \"language/es\": \"Spanish\",\n  \"language/es-MX\": \"Spanish (Mexico)\",\n  \"language/et\": \"Estonian\",\n  \"language/fa\": \"Persian\",\n  \"language/fa-AF\": \"Dari\",\n  \"language/fi\": \"Finnish\",\n  \"language/fr\": \"French\",\n  \"language/fr-CA\": \"French (Canada)\",\n  \"language/ha\": \"Hausa\",\n  \"language/he\": \"Hebrew\",\n  \"language/hi\": \"Hindi\",\n  \"language/hr\": \"Croatian\",\n  \"language/ht\": \"Haitian Creole\",\n  \"language/hu\": \"Hungarian\",\n  \"language/id\": \"Indonesian\",\n  \"language/it\": \"Italian\",\n  \"language/ja\": \"Japanese\",\n  \"language/ka\": \"Georgian\",\n  \"language/ko\": \"Korean\",\n  \"language/lt\": \"Lithuanian\",\n  \"language/lv\": \"Latvian\",\n  \"language/ms\": \"Malay\",\n  \"language/nl\": \"Dutch\",\n  \"language/no\": \"Norwegian\",\n  \"language/pl\": \"Polish\",\n  \"language/ps\": \"Pashto\",\n  \"language/pt\": \"Portuguese\",\n  \"language/ro\": \"Romanian\",\n  \"language/ru\": \"Russian\",\n  \"language/sk\": \"Slovak\",\n  \"language/sl\": \"Slovenian\",\n  \"language/so\": \"Somali\",\n  \"language/sq\": \"Albanian\",\n  \"language/sr\": \"Serbian\",\n  \"language/sv\": \"Swedish\",\n  \"language/sw\": \"Swahili\",\n  \"language/ta\": \"Tamil\",\n  \"language/th\": \"Thai\",\n  \"language/tl\": \"Tagalog\",\n  \"language/tr\": \"Turkish\",\n  \"language/uk\": \"Ukrainian\",\n  \"language/ur\": \"Urdu\",\n  \"language/vi\": \"Vietnamese\",\n  \"language/zh\": \"Chinese (Simplified)\",\n  \"language/zh-TW\": \"Chinese (Traditional)\",\n  \"Leave Channel\": \"Leave Channel\",\n  \"Left channel\": \"Left channel\",\n  \"Let others add options\": \"Let Others Add Options\",\n  \"Limit votes per person\": \"Limit Votes per Person\",\n  \"Link\": \"Link\",\n  \"linkCount_one\": \"Link\",\n  \"linkCount_other\": \"{{ count }} links\",\n  \"live\": \"live\",\n  \"Live for {{duration}}\": \"Live for {{duration}}\",\n  \"Live location\": \"Live location\",\n  \"Live until {{ timestamp }}\": \"Live until {{ timestamp }}\",\n  \"Load more\": \"Load more\",\n  \"Local upload attachment missing local id\": \"Local upload attachment missing local id\",\n  \"Location\": \"Location\",\n  \"Location sharing ended\": \"Location sharing ended\",\n  \"Location: {{ coordinates }}\": \"Location: {{ coordinates }}\",\n  \"Mark as unread\": \"Mark as unread\",\n  \"Maximum number of votes (from 2 to 10)\": \"Maximum number of votes (from 2 to 10)\",\n  \"Maximum votes per person\": \"Maximum votes per person\",\n  \"Menu\": \"Menu\",\n  \"Message deleted\": \"Message deleted\",\n  \"Message failed to send\": \"Message failed to send\",\n  \"Message has been successfully flagged\": \"Message has been successfully flagged\",\n  \"Message marked as unread\": \"Message marked as unread\",\n  \"Message pinned\": \"Message pinned\",\n  \"Message unpinned\": \"Message unpinned\",\n  \"Message was blocked by moderation policies\": \"Message was blocked by moderation policies\",\n  \"Messages have been marked unread.\": \"Messages have been marked unread.\",\n  \"Missing permissions to upload the attachment\": \"Missing permissions to upload the attachment\",\n  \"Multiple votes\": \"Multiple Votes\",\n  \"Mute\": \"Mute\",\n  \"mute-command-args\": \"[@username]\",\n  \"mute-command-description\": \"Mute a user\",\n  \"network error\": \"network error\",\n  \"New\": \"New\",\n  \"New message from {{user}}\": \"New message from {{user}}\",\n  \"New Messages!\": \"New Messages!\",\n  \"Next image\": \"Next image\",\n  \"No chats here yet…\": \"No chats here yet…\",\n  \"No conversations yet\": \"No conversations yet\",\n  \"No items exist\": \"No items exist\",\n  \"No results found\": \"No results found\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Nobody will be able to vote in this poll anymore.\",\n  \"Nothing yet...\": \"Nothing yet...\",\n  \"Offline\": \"Offline\",\n  \"Ok\": \"Ok\",\n  \"Online\": \"Online\",\n  \"Only numbers are allowed\": \"Only numbers are allowed\",\n  \"Only visible to you\": \"Only visible to you\",\n  \"Open emoji picker\": \"Open emoji picker\",\n  \"Open gallery at image {{ index }}\": \"Open gallery at image {{ index }}\",\n  \"Open image in gallery\": \"Open image in gallery\",\n  \"Open location in a map\": \"Open location in a map\",\n  \"Option already exists\": \"Option already exists\",\n  \"Option is empty\": \"Option is empty\",\n  \"Options\": \"Options\",\n  \"Original\": \"Original\",\n  \"People matching\": \"People matching\",\n  \"Photo\": \"Photo\",\n  \"Pin\": \"Pin\",\n  \"Pinned by {{ name }}\": \"Pinned by {{ name }}\",\n  \"Pinned by You\": \"Pinned by You\",\n  \"placeholder/PollComment\": \"Your comment\",\n  \"placeholder/PollOptionSuggestion\": \"Enter a new option\",\n  \"Play video\": \"Play video\",\n  \"Playback speed {{ rate }}x\": \"Playback speed {{ rate }}x\",\n  \"Poll\": \"Poll\",\n  \"Poll comments\": \"Poll Comments\",\n  \"Poll ended\": \"Poll Ended\",\n  \"Poll options\": \"Poll Options\",\n  \"Poll results\": \"Poll Results\",\n  \"Previous image\": \"Previous image\",\n  \"Question\": \"Question\",\n  \"Question {{ optionOrderNumber}}\": \"Question {{ optionOrderNumber}}\",\n  \"Question is required\": \"Question is required\",\n  \"Quote Reply\": \"Quote Reply\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Reached the vote limit. Remove an existing vote first.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Recording format is not supported and cannot be reproduced\",\n  \"Remind me\": \"Remind me\",\n  \"Remind Me\": \"Remind Me\",\n  \"Reminder set\": \"Reminder set\",\n  \"Remove reminder\": \"Remove reminder\",\n  \"Remove save for later\": \"Remove save for later\",\n  \"Replied to a thread\": \"Replied to a thread\",\n  \"Reply\": \"Reply\",\n  \"Reply to {{ authorName }}\": \"Reply to {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Reply to a message to start a thread\",\n  \"Reply to Message\": \"Reply to Message\",\n  \"replyCount_one\": \"1 reply\",\n  \"replyCount_other\": \"{{ count }} replies\",\n  \"Resend\": \"Resend\",\n  \"Retry upload\": \"Retry upload\",\n  \"Review all options available in this poll\": \"Review all options available in this poll\",\n  \"Review comments submitted with poll answers\": \"Review comments submitted with poll answers\",\n  \"Review poll results and open an option to see detailed votes\": \"Review poll results and open an option to see detailed votes\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Review this message and choose whether to delete it, edit it, or send it anyway\",\n  \"Review who voted for this option\": \"Review who voted for this option\",\n  \"Save for later\": \"Save for later\",\n  \"Saved for later\": \"Saved for later\",\n  \"Search\": \"Search\",\n  \"Search GIFs\": \"Search GIFs\",\n  \"search-results-header-filter-source-button-label--channels\": \"channels\",\n  \"search-results-header-filter-source-button-label--messages\": \"messages\",\n  \"search-results-header-filter-source-button-label--users\": \"users\",\n  \"Searching for {{ searchSourceType }}...\": \"Searching for {{ searchSourceType }}...\",\n  \"Searching...\": \"Searching...\",\n  \"searchResultsCount_one\": \"1 result\",\n  \"searchResultsCount_other\": \"{{ count }} results\",\n  \"Select a thread to continue the conversation\": \"Select a thread to continue the conversation\",\n  \"Select more than one option\": \"Select More Than One Option\",\n  \"Select one\": \"Select one\",\n  \"Select one or more\": \"Select one or more\",\n  \"Select up to {{count}}_one\": \"Select up to {{count}}\",\n  \"Select up to {{count}}_other\": \"Select up to {{count}}\",\n  \"Select your current location and optionally enable live location sharing\": \"Select your current location and optionally enable live location sharing\",\n  \"Send\": \"Send\",\n  \"Send a message\": \"Send a message\",\n  \"Send a message to start the conversation\": \"Send a message to start the conversation\",\n  \"Send Anyway\": \"Send Anyway\",\n  \"Send message request failed\": \"Send message request failed\",\n  \"Send poll\": \"Send Poll\",\n  \"Sending...\": \"Sending...\",\n  \"Sent\": \"Sent\",\n  \"Share\": \"Share\",\n  \"Share live location for\": \"Share live location for\",\n  \"Share Location\": \"Share Location\",\n  \"Shared live location\": \"Shared live location\",\n  \"Shared location\": \"Shared location\",\n  \"Shuffle\": \"Shuffle\",\n  \"size limit\": \"size limit\",\n  \"Slow Mode ON\": \"Slow Mode ON\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Slow mode, wait {{ seconds }}s...\",\n  \"Some of the files will not be accepted\": \"Some of the files will not be accepted\",\n  \"Start typing to search\": \"Start typing to search\",\n  \"Stop sharing\": \"Stop sharing\",\n  \"Submit\": \"Submit\",\n  \"Suggest a new option to add to this poll\": \"Suggest a new option to add to this poll\",\n  \"Suggest an option\": \"Suggest an Option\",\n  \"Tap to remove\": \"Tap to remove\",\n  \"Tap to remove: {{ reactionName }}\": \"Tap to remove: {{ reactionName }}\",\n  \"Thinking...\": \"Thinking...\",\n  \"this content could not be displayed\": \"this content could not be displayed\",\n  \"This field cannot be empty or contain only spaces\": \"This field cannot be empty or contain only spaces\",\n  \"This message did not meet our content guidelines\": \"This message did not meet our content guidelines\",\n  \"Thread\": \"Thread\",\n  \"Thread has not been found\": \"Thread has not been found\",\n  \"Thread reply\": \"Thread reply\",\n  \"Thread Reply\": \"Thread Reply\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Loading...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} unread thread\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} unread threads\",\n  \"Threads\": \"Threads\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today]\\\", \\\"nextDay\\\": \\\"[Tomorrow]\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Last] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Today\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Yesterday\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"To start recording, allow the camera access in your browser\",\n  \"To start recording, allow the microphone access in your browser\": \"To start recording, allow the microphone access in your browser\",\n  \"totalVoteCount_one\": \"1 vote total\",\n  \"totalVoteCount_other\": \"{{ count }} votes total\",\n  \"Translated\": \"Translated\",\n  \"Translated from {{ language }}\": \"Translated from {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Type a number from 2 to 10\",\n  \"Unarchive\": \"Unarchive\",\n  \"unban-command-args\": \"[@username]\",\n  \"unban-command-description\": \"Unban a user\",\n  \"Unblock User\": \"Unblock User\",\n  \"unknown error\": \"unknown error\",\n  \"Unmute\": \"Unmute\",\n  \"unmute-command-args\": \"[@username]\",\n  \"unmute-command-description\": \"Unmute a user\",\n  \"Unpin\": \"Unpin\",\n  \"Unread messages\": \"Unread messages\",\n  \"Unsupported attachment\": \"Unsupported attachment\",\n  \"unsupported file type\": \"unsupported file type\",\n  \"Update\": \"Update\",\n  \"Update the comment attached to your poll answer\": \"Update the comment attached to your poll answer\",\n  \"Update your comment\": \"Update Your Comment\",\n  \"Upload blocked\": \"Upload blocked\",\n  \"Upload error\": \"Upload error\",\n  \"Upload failed\": \"Upload failed\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Upload type: \\\"{{ type }}\\\" is not allowed\",\n  \"User blocked\": \"User blocked\",\n  \"User unblocked\": \"User unblocked\",\n  \"User uploaded content\": \"User uploaded content\",\n  \"Video\": \"Video\",\n  \"videoCount_one\": \"Video\",\n  \"videoCount_other\": \"{{ count }} videos\",\n  \"View\": \"View\",\n  \"View {{count}} comments_one\": \"View {{count}} Comment\",\n  \"View {{count}} comments_other\": \"View {{count}} Comments\",\n  \"View all\": \"View all\",\n  \"View original\": \"View original\",\n  \"View results\": \"View Results\",\n  \"View translation\": \"View translation\",\n  \"Voice message\": \"Voice message\",\n  \"Voice message {{ duration }}\": \"Voice message {{ duration }}\",\n  \"Voice message deleted\": \"Voice message deleted\",\n  \"voiceMessageCount_one\": \"Voice message\",\n  \"voiceMessageCount_other\": \"{{ count }} voice messages\",\n  \"Vote ended\": \"Vote ended\",\n  \"Votes\": \"Votes\",\n  \"Wait until all attachments have uploaded\": \"Wait until all attachments have uploaded\",\n  \"Waiting for network…\": \"Waiting for network…\",\n  \"You\": \"You\",\n  \"You've reached the maximum number of files\": \"You've reached the maximum number of files\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} y {{ moreCount }} más\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} y {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} archivo\",\n  \"{{ count }} files_many\": \"{{ count }} archivos\",\n  \"{{ count }} files_other\": \"{{ count }} archivos\",\n  \"{{ count }} people are typing_one\": \"{{ count }} persona está escribiendo\",\n  \"{{ count }} people are typing_many\": \"{{ count }} personas están escribiendo\",\n  \"{{ count }} people are typing_other\": \"{{ count }} personas están escribiendo\",\n  \"{{ count }} photos_one\": \"{{ count }} foto\",\n  \"{{ count }} photos_many\": \"{{ count }} fotos\",\n  \"{{ count }} photos_other\": \"{{ count }} fotos\",\n  \"{{ count }} reactions_one\": \"{{ count }} reacción\",\n  \"{{ count }} reactions_many\": \"{{ count }} reacciones\",\n  \"{{ count }} reactions_other\": \"{{ count }} reacciones\",\n  \"{{ count }} videos_one\": \"{{ count }} vídeo\",\n  \"{{ count }} videos_many\": \"{{ count }} vídeos\",\n  \"{{ count }} videos_other\": \"{{ count }} vídeos\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} y {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} más\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} miembros\",\n  \"{{ typing }} are typing\": \"{{ typing }} están escribiendo\",\n  \"{{ typing }} is typing\": \"{{ typing }} está escribiendo\",\n  \"{{ user }} has been muted\": \"{{ user }} ha sido silenciado\",\n  \"{{ user }} has been unmuted\": \"Se ha desactivado el silencio de {{ user }}\",\n  \"{{ user }} is typing...\": \"{{ user }} está escribiendo...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} y {{ user }} están escribiendo...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} y más están escribiendo...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} en línea\",\n  \"{{count}} new messages_one\": \"{{count}} nuevo mensaje\",\n  \"{{count}} new messages_many\": \"{{count}} nuevos mensajes\",\n  \"{{count}} new messages_other\": \"{{count}} nuevos mensajes\",\n  \"{{count}} unread_one\": \"{{count}} no leído\",\n  \"{{count}} unread_many\": \"{{count}} no leídos\",\n  \"{{count}} unread_other\": \"{{count}} no leídos\",\n  \"{{count}} votes_one\": \"1 voto\",\n  \"{{count}} votes_many\": \"{{count}} votos\",\n  \"{{count}} votes_other\": \"{{count}} votos\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} opción más\",\n  \"+{{count}} more options_many\": \"+{{count}} opciones más\",\n  \"+{{count}} more options_other\": \"+{{count}} opciones más\",\n  \"🏙 Attachment...\": \"🏙 Adjunto...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} creó: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} votó: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Ubicación compartida\",\n  \"Add a comment\": \"Agregar un comentario\",\n  \"Add a comment to your poll answer\": \"Añade un comentario a tu respuesta de la encuesta\",\n  \"Add an option\": \"Agregar una opción\",\n  \"Add reaction\": \"Añadir reacción\",\n  \"All results loaded\": \"Todos los resultados cargados\",\n  \"Allow access to camera\": \"Permitir acceso a la cámara\",\n  \"Allow access to microphone\": \"Permitir acceso al micrófono\",\n  \"Allow comments\": \"Permitir comentarios\",\n  \"Allow option suggestion\": \"Permitir sugerencia de opciones\",\n  \"Allow others to add comments\": \"Permitir que otros añadan comentarios\",\n  \"Also send as a direct message\": \"También enviar como mensaje directo\",\n  \"Also send in channel\": \"También enviar en el canal\",\n  \"Also sent in channel\": \"También enviado en el canal\",\n  \"An error has occurred during recording\": \"Se ha producido un error durante la grabación\",\n  \"An error has occurred during the recording processing\": \"Se ha producido un error durante el procesamiento de la grabación\",\n  \"Anonymous\": \"Anónimo\",\n  \"Anonymous poll\": \"Encuesta anónima\",\n  \"Archive\": \"Archivo\",\n  \"Are you sure you want to delete this message?\": \"¿Estás seguro de que quieres eliminar este mensaje?\",\n  \"aria/Attachment\": \"Adjunto\",\n  \"aria/Attachment Actions\": \"Acciones del adjunto\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Posición de audio {{ elapsed }} de {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Posición de audio {{ progress }} por ciento\",\n  \"aria/Block User\": \"Bloquear usuario\",\n  \"aria/Bookmark Message\": \"Guardar mensaje\",\n  \"aria/Cancel recording\": \"Cancelar grabación\",\n  \"aria/Cancel Reply\": \"Cancelar respuesta\",\n  \"aria/Cancel upload\": \"Cancelar carga\",\n  \"aria/Channel Actions\": \"Acciones del canal\",\n  \"aria/Channel list\": \"Lista de canales\",\n  \"aria/Channel search results\": \"Resultados de búsqueda de canales\",\n  \"aria/Chat view tabs\": \"Pestañas de vista del chat\",\n  \"aria/Clear search\": \"Borrar búsqueda\",\n  \"aria/Close callout dialog\": \"Cerrar diálogo de aviso\",\n  \"aria/Close thread\": \"Cerrar hilo\",\n  \"aria/Collapse sidebar\": \"Contraer barra lateral\",\n  \"aria/Command Suggestions\": \"Sugerencias de comandos\",\n  \"aria/Complete recording\": \"Completar grabación\",\n  \"aria/Copy Message Text\": \"Copiar texto del mensaje\",\n  \"aria/Decrease value\": \"Disminuir valor\",\n  \"aria/Delete Message\": \"Eliminar mensaje\",\n  \"aria/Dismiss notification\": \"Descartar notificación\",\n  \"aria/Download attachment\": \"Descargar adjunto\",\n  \"aria/Edit Message\": \"Editar mensaje\",\n  \"aria/Emoji picker\": \"Selector de emojis\",\n  \"aria/Emoji Suggestions\": \"Sugerencias de emojis\",\n  \"aria/Exit search\": \"Salir de la búsqueda\",\n  \"aria/Expand sidebar\": \"Expandir barra lateral\",\n  \"aria/File input\": \"Entrada de archivo\",\n  \"aria/File upload\": \"Carga de archivo\",\n  \"aria/Flag Message\": \"Marcar mensaje\",\n  \"aria/Image failed to load\": \"Error al cargar la imagen\",\n  \"aria/Image input\": \"Entrada de imagen\",\n  \"aria/Increase value\": \"Aumentar valor\",\n  \"aria/Jump to latest message\": \"Ir al mensaje más reciente\",\n  \"aria/Jump to quoted message\": \"Ir al mensaje citado\",\n  \"aria/Load More Channels\": \"Cargar más canales\",\n  \"aria/Mark Message Unread\": \"Marcar como no leído\",\n  \"aria/Mark messages as read\": \"Marcar mensajes como leídos\",\n  \"aria/Menu\": \"Menú\",\n  \"aria/Message Actions\": \"Acciones del mensaje\",\n  \"aria/Message from {{ user }},\": \"Mensaje de {{ user }},\",\n  \"aria/Message Options\": \"Opciones de mensaje\",\n  \"aria/Message,\": \"Mensaje,\",\n  \"aria/Mute User\": \"Silenciar usuario\",\n  \"aria/Notifications\": \"Notificaciones\",\n  \"aria/Open Attachment Selector\": \"Abrir selector de adjuntos\",\n  \"aria/Open Channel Actions Menu\": \"Abrir menú de acciones del canal\",\n  \"aria/Open Menu\": \"Abrir menú\",\n  \"aria/Open Message Actions Menu\": \"Abrir menú de acciones de mensaje\",\n  \"aria/Open Reaction Selector\": \"Abrir selector de reacciones\",\n  \"aria/Open Thread\": \"Abrir hilo\",\n  \"aria/Pause\": \"Pausar\",\n  \"aria/Pause recording\": \"Pausar grabación\",\n  \"aria/Percent complete\": \"{{percent}} por ciento completado\",\n  \"aria/Pin Message\": \"Fijar mensaje\",\n  \"aria/Play\": \"Reproducir\",\n  \"aria/Quote Message\": \"Citar mensaje\",\n  \"aria/Reaction list\": \"Lista de reacciones\",\n  \"aria/Remind Me Message\": \"Recordarme\",\n  \"aria/Remind Me Options\": \"Opciones de recordatorio\",\n  \"aria/Remove attachment\": \"Eliminar adjunto\",\n  \"aria/Remove location attachment\": \"Eliminar adjunto de ubicación\",\n  \"aria/Remove option\": \"Eliminar opción\",\n  \"aria/Remove Reminder\": \"Quitar recordatorio\",\n  \"aria/Remove Save For Later\": \"Quitar guardar para después\",\n  \"aria/Resend Message\": \"Reenviar mensaje\",\n  \"aria/Resume recording\": \"Reanudar grabación\",\n  \"aria/Retry upload\": \"Reintentar carga\",\n  \"aria/Review bounced message\": \"Revisar mensaje rebotado\",\n  \"aria/Search results\": \"Resultados de búsqueda\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Botón de filtro del encabezado de resultados de búsqueda para: {{ source }}\",\n  \"aria/Seek audio position\": \"Buscar posición de audio\",\n  \"aria/Select Channel: {{ channelName }}\": \"Seleccionar canal: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Seleccionar reacción: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Seleccionar canal de usuario: {{ name }}\",\n  \"aria/Send\": \"Enviar\",\n  \"aria/Show preview\": \"Mostrar vista previa\",\n  \"aria/Start recording audio\": \"Iniciar grabación de audio\",\n  \"aria/Stop AI Generation\": \"Detener generación de IA\",\n  \"aria/Suggestions\": \"Sugerencias\",\n  \"aria/Thread list\": \"Lista de hilos\",\n  \"aria/Unblock User\": \"Desbloquear usuario\",\n  \"aria/Unmute User\": \"Activar sonido\",\n  \"aria/Unpin Message\": \"Desfijar mensaje\",\n  \"aria/User Suggestions\": \"Sugerencias de usuarios\",\n  \"Ask a question\": \"Hacer una pregunta\",\n  \"Attach\": \"Adjuntar\",\n  \"Attach files\": \"Adjuntar archivos\",\n  \"Attachment\": \"Archivo adjunto\",\n  \"Attachment upload blocked due to {{reason}}\": \"Carga de adjunto bloqueada debido a {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Carga de adjunto fallida debido a {{reason}}\",\n  \"Back\": \"Atrás\",\n  \"ban-command-args\": \"[@usuario] [texto]\",\n  \"ban-command-description\": \"Prohibir a un usuario\",\n  \"Block User\": \"Bloquear usuario\",\n  \"Cancel\": \"Cancelar\",\n  \"Cannot seek in the recording\": \"No se puede buscar en la grabación\",\n  \"Channel archived\": \"Canal archivado\",\n  \"Channel Missing\": \"Falta canal\",\n  \"Channel muted\": \"Canal silenciado\",\n  \"Channel pinned\": \"Canal fijado\",\n  \"Channel unarchived\": \"Canal desarchivado\",\n  \"Channel unmuted\": \"Silencio del canal desactivado\",\n  \"Channel unpinned\": \"Canal desanclado\",\n  \"Channels\": \"Canales\",\n  \"Chats\": \"Chats\",\n  \"Choose between 2 to 10 options\": \"Elige entre 2 y 10 opciones\",\n  \"Close\": \"Cerrar\",\n  \"Close dialog\": \"Cerrar diálogo\",\n  \"Close emoji picker\": \"Cerrar el selector de emojis\",\n  \"Close prompt: {{ title }}\": \"Cerrar diálogo: {{ title }}\",\n  \"Command not available while editing\": \"Comando no disponible durante la edición\",\n  \"Command not available while replying\": \"Comando no disponible mientras se responde\",\n  \"Commands\": \"Comandos\",\n  \"Commands matching\": \"Coincidencia de comandos\",\n  \"Connection failure, reconnecting now...\": \"Fallo de conexión, reconectando ahora...\",\n  \"Copy Message\": \"Copiar mensaje\",\n  \"Create\": \"Crear\",\n  \"Create a question, add options, and configure poll settings\": \"Crea una pregunta, añade opciones y configura los ajustes de la encuesta\",\n  \"Create poll\": \"Crear encuesta\",\n  \"Current location\": \"Ubicación actual\",\n  \"Delete\": \"Borrar\",\n  \"Delete for me\": \"Eliminar para mí\",\n  \"Delete message\": \"Eliminar mensaje\",\n  \"Delivered\": \"Entregado\",\n  \"Direct message\": \"Mensaje directo\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"¿Quieres terminar esta encuesta ahora? Nadie podrá votar más en esta encuesta.\",\n  \"Download All\": \"Descargar todo\",\n  \"Download Attachment\": \"Descargar archivo adjunto\",\n  \"Download attachment {{ name }}\": \"Descargar adjunto {{ name }}\",\n  \"Drag your files here\": \"Arrastra tus archivos aquí\",\n  \"Drag your files here to add to your post\": \"Arrastra tus archivos aquí para agregarlos a tu publicación\",\n  \"Due {{ timeLeft }}\": \"Vence en {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Vencido desde {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Editar mensaje\",\n  \"Edit message request failed\": \"Error al editar la solicitud de mensaje\",\n  \"Edited\": \"Editado\",\n  \"Emoji matching\": \"Coincidencia de emoji\",\n  \"Empty message...\": \"Mensaje vacío...\",\n  \"End\": \"Final\",\n  \"End poll\": \"Terminar encuesta\",\n  \"End this poll?\": \"¿Terminar esta encuesta?\",\n  \"End vote\": \"Finalizar votación\",\n  \"Enforce unique vote is enabled\": \"El voto único está habilitado\",\n  \"Error\": \"Error\",\n  \"Error adding flag\": \"Error al agregar la bandera\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Error al conectarse al chat, actualice la página para volver a intentarlo.\",\n  \"Error deleting message\": \"Error al eliminar el mensaje\",\n  \"Error fetching reactions\": \"Error al cargar las reacciones\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Error al marcar el mensaje como no leído. No se pueden marcar mensajes no leídos más antiguos que los últimos 100 mensajes del canal.\",\n  \"Error muting a user ...\": \"Error al silenciar el usuario...\",\n  \"Error pinning message\": \"Error al fijar el mensaje\",\n  \"Error removing message pin\": \"Error al quitar el pin del mensaje\",\n  \"Error reproducing the recording\": \"Error al reproducir la grabación\",\n  \"Error starting recording\": \"Error al iniciar la grabación\",\n  \"Error unmuting a user ...\": \"Error al desactivar el silencio del usuario...\",\n  \"Error uploading attachment\": \"Error al subir el archivo adjunto\",\n  \"Error uploading file\": \"Error al cargar el archivo\",\n  \"Error uploading image\": \"Error al subir la imagen\",\n  \"Error: {{ errorMessage }}\": \"Error: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Salir del comando {{ command }}\",\n  \"Failed to block user\": \"No se pudo bloquear al usuario\",\n  \"Failed to create the poll\": \"Error al crear la encuesta\",\n  \"Failed to create the poll due to {{reason}}\": \"No se pudo crear la encuesta debido a {{reason}}\",\n  \"Failed to delete the message\": \"No se pudo eliminar el mensaje\",\n  \"Failed to end the poll\": \"No se pudo terminar la encuesta\",\n  \"Failed to end the poll due to {{reason}}\": \"No se pudo terminar la encuesta debido a {{reason}}\",\n  \"Failed to jump to the first unread message\": \"Error al saltar al primer mensaje no leído\",\n  \"Failed to leave channel\": \"No se pudo salir del canal\",\n  \"Failed to load channels\": \"No se pudieron cargar los canales\",\n  \"Failed to load more channels\": \"No se pudieron cargar más canales\",\n  \"Failed to mark channel as read\": \"Error al marcar el canal como leído\",\n  \"Failed to play the recording\": \"No se pudo reproducir la grabación\",\n  \"Failed to retrieve location\": \"No se pudo obtener la ubicación\",\n  \"Failed to share location\": \"No se pudo compartir la ubicación\",\n  \"Failed to update channel archive status\": \"No se pudo actualizar el estado de archivo del canal\",\n  \"Failed to update channel mute status\": \"No se pudo actualizar el estado de silencio del canal\",\n  \"Failed to update channel pinned status\": \"No se pudo actualizar el estado de fijación del canal\",\n  \"File\": \"Archivo\",\n  \"File is required for upload attachment\": \"Se requiere un archivo para subir el adjunto\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"El archivo es demasiado grande: {{ size }}, el tamaño máximo de carga es de {{ limit }}\",\n  \"File too large\": \"Archivo demasiado grande\",\n  \"fileCount_one\": \"1 archivo\",\n  \"fileCount_many\": \"{{ count }} archivos\",\n  \"fileCount_other\": \"{{ count }} archivos\",\n  \"Flag\": \"Marcar\",\n  \"Generating...\": \"Generando...\",\n  \"giphy-command-args\": \"[texto]\",\n  \"giphy-command-description\": \"Publicar un gif aleatorio en el canal\",\n  \"Hide who voted\": \"Ocultar quién votó\",\n  \"Image\": \"Imagen\",\n  \"imageCount_one\": \"Imagen\",\n  \"imageCount_many\": \"{{ count }} imágenes\",\n  \"imageCount_other\": \"{{ count }} imágenes\",\n  \"Instant commands\": \"Comandos instantáneos\",\n  \"language/af\": \"Afrikáans\",\n  \"language/am\": \"Amárico\",\n  \"language/ar\": \"Árabe\",\n  \"language/az\": \"Azerbaiyano\",\n  \"language/bg\": \"Búlgaro\",\n  \"language/bn\": \"Bengalí\",\n  \"language/bs\": \"Bosnio\",\n  \"language/cs\": \"Checo\",\n  \"language/da\": \"Danés\",\n  \"language/de\": \"Alemán\",\n  \"language/el\": \"Griego\",\n  \"language/en\": \"Inglés\",\n  \"language/es\": \"Español\",\n  \"language/es-MX\": \"Español (México)\",\n  \"language/et\": \"Estonio\",\n  \"language/fa\": \"Persa\",\n  \"language/fa-AF\": \"Dari\",\n  \"language/fi\": \"Finlandés\",\n  \"language/fr\": \"Francés\",\n  \"language/fr-CA\": \"Francés (Canadá)\",\n  \"language/ha\": \"Hausa\",\n  \"language/he\": \"Hebreo\",\n  \"language/hi\": \"Hindi\",\n  \"language/hr\": \"Croata\",\n  \"language/ht\": \"Criollo haitiano\",\n  \"language/hu\": \"Húngaro\",\n  \"language/id\": \"Indonesio\",\n  \"language/it\": \"Italiano\",\n  \"language/ja\": \"Japonés\",\n  \"language/ka\": \"Georgiano\",\n  \"language/ko\": \"Coreano\",\n  \"language/lt\": \"Lituano\",\n  \"language/lv\": \"Letón\",\n  \"language/ms\": \"Malayo\",\n  \"language/nl\": \"Neerlandés\",\n  \"language/no\": \"Noruego\",\n  \"language/pl\": \"Polaco\",\n  \"language/ps\": \"Pastún\",\n  \"language/pt\": \"Portugués\",\n  \"language/ro\": \"Rumano\",\n  \"language/ru\": \"Ruso\",\n  \"language/sk\": \"Eslovaco\",\n  \"language/sl\": \"Esloveno\",\n  \"language/so\": \"Somalí\",\n  \"language/sq\": \"Albanés\",\n  \"language/sr\": \"Serbio\",\n  \"language/sv\": \"Sueco\",\n  \"language/sw\": \"Suajili\",\n  \"language/ta\": \"Tamil\",\n  \"language/th\": \"Tailandés\",\n  \"language/tl\": \"Tagalo\",\n  \"language/tr\": \"Turco\",\n  \"language/uk\": \"Ucraniano\",\n  \"language/ur\": \"Urdu\",\n  \"language/vi\": \"Vietnamita\",\n  \"language/zh\": \"Chino (simplificado)\",\n  \"language/zh-TW\": \"Chino (tradicional)\",\n  \"Leave Channel\": \"Abandonar canal\",\n  \"Left channel\": \"Canal abandonado\",\n  \"Let others add options\": \"Permitir que otros añadan opciones\",\n  \"Limit votes per person\": \"Limitar votos por persona\",\n  \"Link\": \"Enlace\",\n  \"linkCount_one\": \"Enlace\",\n  \"linkCount_many\": \"{{ count }} enlaces\",\n  \"linkCount_other\": \"{{ count }} enlaces\",\n  \"live\": \"En vivo\",\n  \"Live for {{duration}}\": \"En vivo durante {{duration}}\",\n  \"Live location\": \"Ubicación en vivo\",\n  \"Live until {{ timestamp }}\": \"En vivo hasta {{ timestamp }}\",\n  \"Load more\": \"Cargar más\",\n  \"Local upload attachment missing local id\": \"El adjunto de subida local no tiene id local\",\n  \"Location\": \"Ubicación\",\n  \"Location sharing ended\": \"Compartir ubicación terminado\",\n  \"Location: {{ coordinates }}\": \"Ubicación: {{ coordinates }}\",\n  \"Mark as unread\": \"Marcar como no leído\",\n  \"Maximum number of votes (from 2 to 10)\": \"Número máximo de votos (de 2 a 10)\",\n  \"Maximum votes per person\": \"Máximo de votos por persona\",\n  \"Menu\": \"Menú\",\n  \"Message deleted\": \"Mensaje eliminado\",\n  \"Message failed to send\": \"No se pudo enviar el mensaje\",\n  \"Message has been successfully flagged\": \"El mensaje se marcó correctamente\",\n  \"Message marked as unread\": \"Mensaje marcado como no leído\",\n  \"Message pinned\": \"Mensaje fijado\",\n  \"Message unpinned\": \"Mensaje desanclado\",\n  \"Message was blocked by moderation policies\": \"El mensaje fue bloqueado por las políticas de moderación\",\n  \"Messages have been marked unread.\": \"Los mensajes han sido marcados como no leídos.\",\n  \"Missing permissions to upload the attachment\": \"Faltan permisos para subir el archivo adjunto\",\n  \"Multiple votes\": \"Votos múltiples\",\n  \"Mute\": \"Silenciar\",\n  \"mute-command-args\": \"[@usuario]\",\n  \"mute-command-description\": \"Silenciar a un usuario\",\n  \"network error\": \"error de red\",\n  \"New\": \"Nuevo\",\n  \"New message from {{user}}\": \"Nuevo mensaje de {{user}}\",\n  \"New Messages!\": \"¡Nuevos mensajes!\",\n  \"Next image\": \"Siguiente imagen\",\n  \"No chats here yet…\": \"Aún no hay mensajes aquí...\",\n  \"No conversations yet\": \"Aún no hay conversaciones\",\n  \"No items exist\": \"No existen elementos\",\n  \"No results found\": \"No se han encontrado resultados\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Nadie podrá votar en esta encuesta.\",\n  \"Nothing yet...\": \"Nada aún...\",\n  \"Offline\": \"Desconectado\",\n  \"Ok\": \"Aceptar\",\n  \"Online\": \"En línea\",\n  \"Only numbers are allowed\": \"Solo se permiten números\",\n  \"Only visible to you\": \"Solo visible para ti\",\n  \"Open emoji picker\": \"Abrir el selector de emojis\",\n  \"Open gallery at image {{ index }}\": \"Abrir galería en la imagen {{ index }}\",\n  \"Open image in gallery\": \"Abrir imagen en la galería\",\n  \"Open location in a map\": \"Abrir ubicación en un mapa\",\n  \"Option already exists\": \"La opción ya existe\",\n  \"Option is empty\": \"La opción está vacía\",\n  \"Options\": \"Opciones\",\n  \"Original\": \"Original\",\n  \"People matching\": \"Personas que coinciden\",\n  \"Photo\": \"Foto\",\n  \"Pin\": \"Fijar\",\n  \"Pinned by {{ name }}\": \"Fijado por {{ name }}\",\n  \"Pinned by You\": \"Anclado por ti\",\n  \"placeholder/PollComment\": \"Tu comentario\",\n  \"placeholder/PollOptionSuggestion\": \"Introduce una nueva opción\",\n  \"Play video\": \"Reproducir video\",\n  \"Playback speed {{ rate }}x\": \"Velocidad de reproducción {{ rate }}x\",\n  \"Poll\": \"Encuesta\",\n  \"Poll comments\": \"Comentarios de la encuesta\",\n  \"Poll ended\": \"Encuesta finalizada\",\n  \"Poll options\": \"Opciones de la encuesta\",\n  \"Poll results\": \"Resultados de la encuesta\",\n  \"Previous image\": \"Imagen anterior\",\n  \"Question\": \"Pregunta\",\n  \"Question {{ optionOrderNumber}}\": \"Pregunta {{ optionOrderNumber}}\",\n  \"Question is required\": \"La pregunta es obligatoria\",\n  \"Quote Reply\": \"Responder con cita\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Se ha alcanzado el límite de votos. Elimina un voto existente primero.\",\n  \"Recording format is not supported and cannot be reproduced\": \"El formato de grabación no es compatible y no se puede reproducir\",\n  \"Remind me\": \"Recordarme\",\n  \"Remind Me\": \"Recordarme\",\n  \"Reminder set\": \"Recordatorio establecido\",\n  \"Remove reminder\": \"Eliminar recordatorio\",\n  \"Remove save for later\": \"Quitar guardar para después\",\n  \"Replied to a thread\": \"Respondió en un hilo\",\n  \"Reply\": \"Responder\",\n  \"Reply to {{ authorName }}\": \"Responder a {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Responde a un mensaje para iniciar un hilo\",\n  \"Reply to Message\": \"Responder al mensaje\",\n  \"replyCount_one\": \"1 respuesta\",\n  \"replyCount_many\": \"{{ count }} respuestas\",\n  \"replyCount_other\": \"{{ count }} respuestas\",\n  \"Resend\": \"Reenviar\",\n  \"Retry upload\": \"Reintentar la carga\",\n  \"Review all options available in this poll\": \"Revisa todas las opciones disponibles en esta encuesta\",\n  \"Review comments submitted with poll answers\": \"Revisa los comentarios enviados con las respuestas de la encuesta\",\n  \"Review poll results and open an option to see detailed votes\": \"Revisa los resultados de la encuesta y abre una opción para ver votos detallados\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Revisa este mensaje y elige si eliminarlo, editarlo o enviarlo de todos modos\",\n  \"Review who voted for this option\": \"Revisa quién votó por esta opción\",\n  \"Save for later\": \"Guardar para más tarde\",\n  \"Saved for later\": \"Guardado para más tarde\",\n  \"Search\": \"Buscar\",\n  \"Search GIFs\": \"Buscar GIFs\",\n  \"search-results-header-filter-source-button-label--channels\": \"canales\",\n  \"search-results-header-filter-source-button-label--messages\": \"mensajes\",\n  \"search-results-header-filter-source-button-label--users\": \"usuarios\",\n  \"Searching for {{ searchSourceType }}...\": \"Buscando {{ searchSourceType }}...\",\n  \"Searching...\": \"Buscando...\",\n  \"searchResultsCount_one\": \"1 resultado\",\n  \"searchResultsCount_many\": \"{{ count }} resultados\",\n  \"searchResultsCount_other\": \"{{ count }} resultados\",\n  \"Select a thread to continue the conversation\": \"Selecciona un hilo para continuar la conversación\",\n  \"Select more than one option\": \"Seleccionar más de una opción\",\n  \"Select one\": \"Seleccionar uno\",\n  \"Select one or more\": \"Seleccionar uno o más\",\n  \"Select up to {{count}}_one\": \"Selecciona hasta {{count}}\",\n  \"Select up to {{count}}_many\": \"Selecciona hasta {{count}}\",\n  \"Select up to {{count}}_other\": \"Selecciona hasta {{count}}\",\n  \"Select your current location and optionally enable live location sharing\": \"Selecciona tu ubicación actual y, opcionalmente, habilita el uso compartido de ubicación en vivo\",\n  \"Send\": \"Enviar\",\n  \"Send a message\": \"Envía un mensaje\",\n  \"Send a message to start the conversation\": \"Envía un mensaje para iniciar la conversación\",\n  \"Send Anyway\": \"Enviar de todos modos\",\n  \"Send message request failed\": \"Error al enviar la solicitud de mensaje\",\n  \"Send poll\": \"Enviar encuesta\",\n  \"Sending...\": \"Enviando...\",\n  \"Sent\": \"Enviado\",\n  \"Share\": \"Compartir\",\n  \"Share live location for\": \"Compartir ubicación en vivo durante\",\n  \"Share Location\": \"Compartir ubicación\",\n  \"Shared live location\": \"Ubicación en vivo compartida\",\n  \"Shared location\": \"Ubicación compartida\",\n  \"Shuffle\": \"Mezclar\",\n  \"size limit\": \"límite de tamaño\",\n  \"Slow Mode ON\": \"Modo lento activado\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Modo lento, espera {{ seconds }} s...\",\n  \"Some of the files will not be accepted\": \"Algunos archivos no serán aceptados\",\n  \"Start typing to search\": \"Empieza a escribir para buscar\",\n  \"Stop sharing\": \"Dejar de compartir\",\n  \"Submit\": \"Enviar\",\n  \"Suggest a new option to add to this poll\": \"Sugiere una nueva opción para añadir a esta encuesta\",\n  \"Suggest an option\": \"Sugerir una opción\",\n  \"Tap to remove\": \"Toca para quitar\",\n  \"Tap to remove: {{ reactionName }}\": \"Toca para quitar: {{ reactionName }}\",\n  \"Thinking...\": \"Pensando...\",\n  \"this content could not be displayed\": \"Este contenido no se pudo mostrar\",\n  \"This field cannot be empty or contain only spaces\": \"Este campo no puede estar vacío o contener solo espacios\",\n  \"This message did not meet our content guidelines\": \"Este mensaje no cumple con nuestras directrices de contenido\",\n  \"Thread\": \"Hilo\",\n  \"Thread has not been found\": \"No se ha encontrado el hilo\",\n  \"Thread reply\": \"Respuesta en hilo\",\n  \"Thread Reply\": \"Respuesta en hilo\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Cargando...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} hilo no leído\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} hilos no leídos\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} hilos no leídos\",\n  \"Threads\": \"Hilos\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Ayer]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Hoy]\\\", \\\"nextDay\\\": \\\"[Mañana]\\\", \\\"lastDay\\\": \\\"[Ayer]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Último] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Hoy\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Ayer\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Para comenzar a grabar, permita el acceso a la cámara en su navegador\",\n  \"To start recording, allow the microphone access in your browser\": \"Para comenzar a grabar, permita el acceso al micrófono en su navegador\",\n  \"totalVoteCount_one\": \"1 voto en total\",\n  \"totalVoteCount_many\": \"{{ count }} votos en total\",\n  \"totalVoteCount_other\": \"{{ count }} votos en total\",\n  \"Translated\": \"Traducido\",\n  \"Translated from {{ language }}\": \"Traducido de {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Escribe un número del 2 al 10\",\n  \"Unarchive\": \"Desarchivar\",\n  \"unban-command-args\": \"[@usuario]\",\n  \"unban-command-description\": \"Quitar la prohibición a un usuario\",\n  \"Unblock User\": \"Desbloquear usuario\",\n  \"unknown error\": \"error desconocido\",\n  \"Unmute\": \"Activar sonido\",\n  \"unmute-command-args\": \"[@usuario]\",\n  \"unmute-command-description\": \"Desactivar el silencio de un usuario\",\n  \"Unpin\": \"Desfijar\",\n  \"Unread messages\": \"Mensajes no leídos\",\n  \"Unsupported attachment\": \"Adjunto no compatible\",\n  \"unsupported file type\": \"tipo de archivo no compatible\",\n  \"Update\": \"Actualizar\",\n  \"Update the comment attached to your poll answer\": \"Actualiza el comentario adjunto a tu respuesta de la encuesta\",\n  \"Update your comment\": \"Actualizar tu comentario\",\n  \"Upload blocked\": \"Carga bloqueada\",\n  \"Upload error\": \"Error de carga\",\n  \"Upload failed\": \"Carga fallida\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Tipo de carga: \\\"{{ type }}\\\" no está permitido\",\n  \"User blocked\": \"Usuario bloqueado\",\n  \"User unblocked\": \"Usuario desbloqueado\",\n  \"User uploaded content\": \"Contenido subido por el usuario\",\n  \"Video\": \"Vídeo\",\n  \"videoCount_one\": \"Video\",\n  \"videoCount_many\": \"{{ count }} videos\",\n  \"videoCount_other\": \"{{ count }} videos\",\n  \"View\": \"Ver\",\n  \"View {{count}} comments_one\": \"Ver {{count}} comentario\",\n  \"View {{count}} comments_many\": \"Ver {{count}} comentarios\",\n  \"View {{count}} comments_other\": \"Ver {{count}} comentarios\",\n  \"View all\": \"Ver todo\",\n  \"View original\": \"Ver original\",\n  \"View results\": \"Ver resultados\",\n  \"View translation\": \"Ver traducción\",\n  \"Voice message\": \"Mensaje de voz\",\n  \"Voice message {{ duration }}\": \"Mensaje de voz {{ duration }}\",\n  \"Voice message deleted\": \"Mensaje de voz eliminado\",\n  \"voiceMessageCount_one\": \"Mensaje de voz\",\n  \"voiceMessageCount_many\": \"{{ count }} mensajes de voz\",\n  \"voiceMessageCount_other\": \"{{ count }} mensajes de voz\",\n  \"Vote ended\": \"Votación finalizada\",\n  \"Votes\": \"Votos\",\n  \"Wait until all attachments have uploaded\": \"Espere hasta que se hayan cargado todos los archivos adjuntos\",\n  \"Waiting for network…\": \"Esperando red…\",\n  \"You\": \"Tú\",\n  \"You've reached the maximum number of files\": \"Has alcanzado el número máximo de archivos\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} et {{ moreCount }} autres\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} et {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} fichier\",\n  \"{{ count }} files_many\": \"{{ count }} fichiers\",\n  \"{{ count }} files_other\": \"{{ count }} fichiers\",\n  \"{{ count }} people are typing_one\": \"{{ count }} personne écrit\",\n  \"{{ count }} people are typing_many\": \"{{ count }} personnes écrivent\",\n  \"{{ count }} people are typing_other\": \"{{ count }} personnes écrivent\",\n  \"{{ count }} photos_one\": \"{{ count }} photo\",\n  \"{{ count }} photos_many\": \"{{ count }} photos\",\n  \"{{ count }} photos_other\": \"{{ count }} photos\",\n  \"{{ count }} reactions_one\": \"{{ count }} réaction\",\n  \"{{ count }} reactions_many\": \"{{ count }} réactions\",\n  \"{{ count }} reactions_other\": \"{{ count }} réactions\",\n  \"{{ count }} videos_one\": \"{{ count }} vidéo\",\n  \"{{ count }} videos_many\": \"{{ count }} vidéos\",\n  \"{{ count }} videos_other\": \"{{ count }} vidéos\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} et {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} supplémentaires\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} membres\",\n  \"{{ typing }} are typing\": \"{{ typing }} écrivent\",\n  \"{{ typing }} is typing\": \"{{ typing }} écrit\",\n  \"{{ user }} has been muted\": \"{{ user }} a été mis en sourdine\",\n  \"{{ user }} has been unmuted\": \"{{ user }} n'est plus en sourdine\",\n  \"{{ user }} is typing...\": \"{{ user }} est en train d'écrire...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} et {{ user }} sont en train d'écrire...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} et plus sont en train d'écrire...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} en ligne\",\n  \"{{count}} new messages_one\": \"{{count}} nouveau message\",\n  \"{{count}} new messages_many\": \"{{count}} nouveaux messages\",\n  \"{{count}} new messages_other\": \"{{count}} nouveaux messages\",\n  \"{{count}} unread_one\": \"{{count}} non lu\",\n  \"{{count}} unread_many\": \"{{count}} non lus\",\n  \"{{count}} unread_other\": \"{{count}} non lus\",\n  \"{{count}} votes_one\": \"{{count}} vote\",\n  \"{{count}} votes_many\": \"{{count}} votes\",\n  \"{{count}} votes_other\": \"{{count}} votes\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} option de plus\",\n  \"+{{count}} more options_many\": \"+{{count}} options de plus\",\n  \"+{{count}} more options_other\": \"+{{count}} options de plus\",\n  \"🏙 Attachment...\": \"🏙 Pièce jointe...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} a créé : {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} a voté : {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Emplacement partagé\",\n  \"Add a comment\": \"Ajouter un commentaire\",\n  \"Add a comment to your poll answer\": \"Ajoutez un commentaire à votre réponse au sondage\",\n  \"Add an option\": \"Ajouter une option\",\n  \"Add reaction\": \"Ajouter une réaction\",\n  \"All results loaded\": \"Tous les résultats sont chargés\",\n  \"Allow access to camera\": \"Autoriser l'accès à la caméra\",\n  \"Allow access to microphone\": \"Autoriser l'accès au microphone\",\n  \"Allow comments\": \"Autoriser les commentaires\",\n  \"Allow option suggestion\": \"Autoriser la suggestion d'options\",\n  \"Allow others to add comments\": \"Permettre à d'autres d'ajouter des commentaires\",\n  \"Also send as a direct message\": \"Également envoyer en message direct\",\n  \"Also send in channel\": \"Également envoyer dans le canal\",\n  \"Also sent in channel\": \"Également envoyé dans le canal\",\n  \"An error has occurred during recording\": \"Une erreur s'est produite pendant l'enregistrement\",\n  \"An error has occurred during the recording processing\": \"Une erreur s'est produite pendant le traitement de l'enregistrement\",\n  \"Anonymous\": \"Anonyme\",\n  \"Anonymous poll\": \"Sondage anonyme\",\n  \"Archive\": \"Archiver\",\n  \"Are you sure you want to delete this message?\": \"Êtes-vous sûr de vouloir supprimer ce message ?\",\n  \"aria/Attachment\": \"Pièce jointe\",\n  \"aria/Attachment Actions\": \"Actions de la pièce jointe\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Position audio {{ elapsed }} sur {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Position audio {{ progress }} pour cent\",\n  \"aria/Block User\": \"Bloquer l'utilisateur\",\n  \"aria/Bookmark Message\": \"Enregistrer le message\",\n  \"aria/Cancel recording\": \"Annuler l'enregistrement\",\n  \"aria/Cancel Reply\": \"Annuler la réponse\",\n  \"aria/Cancel upload\": \"Annuler le téléchargement\",\n  \"aria/Channel Actions\": \"Actions du canal\",\n  \"aria/Channel list\": \"Liste des canaux\",\n  \"aria/Channel search results\": \"Résultats de recherche de canaux\",\n  \"aria/Chat view tabs\": \"Onglets de la vue de chat\",\n  \"aria/Clear search\": \"Effacer la recherche\",\n  \"aria/Close callout dialog\": \"Fermer la boîte de dialogue d'information\",\n  \"aria/Close thread\": \"Fermer le fil\",\n  \"aria/Collapse sidebar\": \"Réduire la barre latérale\",\n  \"aria/Command Suggestions\": \"Suggestions de commandes\",\n  \"aria/Complete recording\": \"Terminer l'enregistrement\",\n  \"aria/Copy Message Text\": \"Copier le texte du message\",\n  \"aria/Decrease value\": \"Diminuer la valeur\",\n  \"aria/Delete Message\": \"Supprimer le message\",\n  \"aria/Dismiss notification\": \"Ignorer la notification\",\n  \"aria/Download attachment\": \"Télécharger la pièce jointe\",\n  \"aria/Edit Message\": \"Éditer un message\",\n  \"aria/Emoji picker\": \"Sélecteur d'émojis\",\n  \"aria/Emoji Suggestions\": \"Suggestions d'émojis\",\n  \"aria/Exit search\": \"Quitter la recherche\",\n  \"aria/Expand sidebar\": \"Développer la barre latérale\",\n  \"aria/File input\": \"Entrée de fichier\",\n  \"aria/File upload\": \"Téléchargement de fichier\",\n  \"aria/Flag Message\": \"Signaler le message\",\n  \"aria/Image failed to load\": \"Échec du chargement de l'image\",\n  \"aria/Image input\": \"Entrée d'image\",\n  \"aria/Increase value\": \"Augmenter la valeur\",\n  \"aria/Jump to latest message\": \"Aller au dernier message\",\n  \"aria/Jump to quoted message\": \"Aller au message cité\",\n  \"aria/Load More Channels\": \"Charger plus de canaux\",\n  \"aria/Mark Message Unread\": \"Marquer comme non lu\",\n  \"aria/Mark messages as read\": \"Marquer les messages comme lus\",\n  \"aria/Menu\": \"Menu\",\n  \"aria/Message Actions\": \"Actions du message\",\n  \"aria/Message from {{ user }},\": \"Message de {{ user }},\",\n  \"aria/Message Options\": \"Options du message\",\n  \"aria/Message,\": \"Message,\",\n  \"aria/Mute User\": \"Mettre en sourdine\",\n  \"aria/Notifications\": \"Notifications\",\n  \"aria/Open Attachment Selector\": \"Ouvrir le sélecteur de pièces jointes\",\n  \"aria/Open Channel Actions Menu\": \"Ouvrir le menu des actions du canal\",\n  \"aria/Open Menu\": \"Ouvrir le menu\",\n  \"aria/Open Message Actions Menu\": \"Ouvrir le menu des actions du message\",\n  \"aria/Open Reaction Selector\": \"Ouvrir le sélecteur de réactions\",\n  \"aria/Open Thread\": \"Ouvrir le fil\",\n  \"aria/Pause\": \"Pause\",\n  \"aria/Pause recording\": \"Mettre en pause l'enregistrement\",\n  \"aria/Percent complete\": \"{{percent}} pour cent terminé\",\n  \"aria/Pin Message\": \"Épingler le message\",\n  \"aria/Play\": \"Lecture\",\n  \"aria/Quote Message\": \"Citer le message\",\n  \"aria/Reaction list\": \"Liste des réactions\",\n  \"aria/Remind Me Message\": \"Me rappeler\",\n  \"aria/Remind Me Options\": \"Options de rappel\",\n  \"aria/Remove attachment\": \"Supprimer la pièce jointe\",\n  \"aria/Remove location attachment\": \"Supprimer la pièce jointe d'emplacement\",\n  \"aria/Remove option\": \"Supprimer l'option\",\n  \"aria/Remove Reminder\": \"Supprimer le rappel\",\n  \"aria/Remove Save For Later\": \"Supprimer « Enregistrer pour plus tard »\",\n  \"aria/Resend Message\": \"Renvoyer le message\",\n  \"aria/Resume recording\": \"Reprendre l'enregistrement\",\n  \"aria/Retry upload\": \"Réessayer le téléchargement\",\n  \"aria/Review bounced message\": \"Examiner le message rejeté\",\n  \"aria/Search results\": \"Résultats de recherche\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Bouton de filtre d'en-tête des résultats de recherche pour : {{ source }}\",\n  \"aria/Seek audio position\": \"Rechercher la position audio\",\n  \"aria/Select Channel: {{ channelName }}\": \"Sélectionner le canal : {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Sélectionner la réaction : {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Sélectionner le canal utilisateur : {{ name }}\",\n  \"aria/Send\": \"Envoyer\",\n  \"aria/Show preview\": \"Afficher l'aperçu\",\n  \"aria/Start recording audio\": \"Commencer l'enregistrement audio\",\n  \"aria/Stop AI Generation\": \"Arrêter la génération d'IA\",\n  \"aria/Suggestions\": \"Suggestions\",\n  \"aria/Thread list\": \"Liste des fils\",\n  \"aria/Unblock User\": \"Débloquer l'utilisateur\",\n  \"aria/Unmute User\": \"Désactiver muet\",\n  \"aria/Unpin Message\": \"Détacher le message\",\n  \"aria/User Suggestions\": \"Suggestions d'utilisateurs\",\n  \"Ask a question\": \"Poser une question\",\n  \"Attach\": \"Joindre\",\n  \"Attach files\": \"Joindre des fichiers\",\n  \"Attachment\": \"Pièce jointe\",\n  \"Attachment upload blocked due to {{reason}}\": \"Téléchargement de pièce jointe bloqué en raison de {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Échec du téléchargement de la pièce jointe en raison de {{reason}}\",\n  \"Back\": \"Retour\",\n  \"ban-command-args\": \"[@nomdutilisateur] [texte]\",\n  \"ban-command-description\": \"Bannir un utilisateur\",\n  \"Block User\": \"Bloquer l'utilisateur\",\n  \"Cancel\": \"Annuler\",\n  \"Cannot seek in the recording\": \"Impossible de rechercher dans l'enregistrement\",\n  \"Channel archived\": \"Canal archivé\",\n  \"Channel Missing\": \"Canal Manquant\",\n  \"Channel muted\": \"Canal mis en sourdine\",\n  \"Channel pinned\": \"Canal épinglé\",\n  \"Channel unarchived\": \"Canal désarchivé\",\n  \"Channel unmuted\": \"Sourdine du canal désactivée\",\n  \"Channel unpinned\": \"Canal désépinglé\",\n  \"Channels\": \"Canaux\",\n  \"Chats\": \"Discussions\",\n  \"Choose between 2 to 10 options\": \"Choisir entre 2 et 10 options\",\n  \"Close\": \"Fermer\",\n  \"Close dialog\": \"Fermer la boîte de dialogue\",\n  \"Close emoji picker\": \"Fermer le sélecteur d'émojis\",\n  \"Close prompt: {{ title }}\": \"Fermer l'invite : {{ title }}\",\n  \"Command not available while editing\": \"Commande non disponible pendant la modification\",\n  \"Command not available while replying\": \"Commande non disponible pendant la réponse\",\n  \"Commands\": \"Commandes\",\n  \"Commands matching\": \"Correspondance des commandes\",\n  \"Connection failure, reconnecting now...\": \"Échec de la connexion, reconnexion en cours...\",\n  \"Copy Message\": \"Copier le message\",\n  \"Create\": \"Créer\",\n  \"Create a question, add options, and configure poll settings\": \"Créez une question, ajoutez des options et configurez les paramètres du sondage\",\n  \"Create poll\": \"Créer un sondage\",\n  \"Current location\": \"Emplacement actuel\",\n  \"Delete\": \"Supprimer\",\n  \"Delete for me\": \"Supprimer pour moi\",\n  \"Delete message\": \"Supprimer le message\",\n  \"Delivered\": \"Publié\",\n  \"Direct message\": \"Message direct\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Voulez-vous terminer ce sondage maintenant ? Personne ne pourra plus voter dans ce sondage.\",\n  \"Download All\": \"Tout télécharger\",\n  \"Download Attachment\": \"Télécharger la pièce jointe\",\n  \"Download attachment {{ name }}\": \"Télécharger la pièce jointe {{ name }}\",\n  \"Drag your files here\": \"Glissez vos fichiers ici\",\n  \"Drag your files here to add to your post\": \"Glissez vos fichiers ici pour les ajouter à votre publication\",\n  \"Due {{ timeLeft }}\": \"Échéance dans {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Échéance depuis {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Éditer un message\",\n  \"Edit message request failed\": \"Échec de la demande de modification du message\",\n  \"Edited\": \"Modifié\",\n  \"Emoji matching\": \"Correspondance d'émojis\",\n  \"Empty message...\": \"Message vide...\",\n  \"End\": \"Fin\",\n  \"End poll\": \"Terminer le sondage\",\n  \"End this poll?\": \"Terminer ce sondage ?\",\n  \"End vote\": \"Fin du vote\",\n  \"Enforce unique vote is enabled\": \"Le vote unique est activé\",\n  \"Error\": \"Erreur\",\n  \"Error adding flag\": \"Erreur lors de l'ajout du signalement\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Erreur de connexion au chat, rafraîchissez la page pour réessayer.\",\n  \"Error deleting message\": \"Erreur lors de la suppression du message\",\n  \"Error fetching reactions\": \"Erreur lors du chargement des réactions\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Erreur lors de la marque du message comme non lu. Impossible de marquer des messages non lus plus anciens que les 100 derniers messages du canal.\",\n  \"Error muting a user ...\": \"Erreur lors de la mise en sourdine d'un utilisateur...\",\n  \"Error pinning message\": \"Erreur lors de l'épinglage du message\",\n  \"Error removing message pin\": \"Erreur lors du retrait de l'épinglage du message\",\n  \"Error reproducing the recording\": \"Erreur lors de la reproduction de l'enregistrement\",\n  \"Error starting recording\": \"Erreur lors du démarrage de l'enregistrement\",\n  \"Error unmuting a user ...\": \"Erreur lors du démarrage de la sourdine d'un utilisateur ...\",\n  \"Error uploading attachment\": \"Erreur lors du téléchargement de la pièce jointe\",\n  \"Error uploading file\": \"Erreur lors du téléchargement du fichier\",\n  \"Error uploading image\": \"Erreur lors de l'envoi de l'image\",\n  \"Error: {{ errorMessage }}\": \"Erreur : {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Quitter la commande {{ command }}\",\n  \"Failed to block user\": \"Impossible de bloquer l'utilisateur\",\n  \"Failed to create the poll\": \"Échec de la création du sondage\",\n  \"Failed to create the poll due to {{reason}}\": \"Échec de la création du sondage en raison de {{reason}}\",\n  \"Failed to delete the message\": \"Échec de la suppression du message\",\n  \"Failed to end the poll\": \"Impossible de terminer le sondage\",\n  \"Failed to end the poll due to {{reason}}\": \"Impossible de terminer le sondage en raison de {{reason}}\",\n  \"Failed to jump to the first unread message\": \"Échec du saut vers le premier message non lu\",\n  \"Failed to leave channel\": \"Impossible de quitter le canal\",\n  \"Failed to load channels\": \"Impossible de charger les canaux\",\n  \"Failed to load more channels\": \"Impossible de charger davantage de canaux\",\n  \"Failed to mark channel as read\": \"Échec du marquage du canal comme lu\",\n  \"Failed to play the recording\": \"Impossible de lire l'enregistrement\",\n  \"Failed to retrieve location\": \"Impossible de récupérer l'emplacement\",\n  \"Failed to share location\": \"Impossible de partager l'emplacement\",\n  \"Failed to update channel archive status\": \"Impossible de mettre à jour l'état d'archivage du canal\",\n  \"Failed to update channel mute status\": \"Impossible de mettre à jour l'état de la mise en sourdine du canal\",\n  \"Failed to update channel pinned status\": \"Impossible de mettre à jour l'état d'épinglage du canal\",\n  \"File\": \"Fichier\",\n  \"File is required for upload attachment\": \"Un fichier est requis pour joindre une pièce\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Le fichier est trop volumineux : {{ size }}, la taille maximale de téléchargement est de {{ limit }}\",\n  \"File too large\": \"Fichier trop volumineux\",\n  \"fileCount_one\": \"1 fichier\",\n  \"fileCount_many\": \"{{ count }} fichiers\",\n  \"fileCount_other\": \"{{ count }} fichiers\",\n  \"Flag\": \"Signaler\",\n  \"Generating...\": \"Génération...\",\n  \"giphy-command-args\": \"[texte]\",\n  \"giphy-command-description\": \"Poster un GIF aléatoire dans le canal\",\n  \"Hide who voted\": \"Masquer qui a voté\",\n  \"Image\": \"Image\",\n  \"imageCount_one\": \"Photo\",\n  \"imageCount_many\": \"{{ count }} photos\",\n  \"imageCount_other\": \"{{ count }} photos\",\n  \"Instant commands\": \"Commandes instantanées\",\n  \"language/af\": \"Afrikaans\",\n  \"language/am\": \"Amharique\",\n  \"language/ar\": \"Arabe\",\n  \"language/az\": \"Azéri\",\n  \"language/bg\": \"Bulgare\",\n  \"language/bn\": \"Bengali\",\n  \"language/bs\": \"Bosnien\",\n  \"language/cs\": \"Tchèque\",\n  \"language/da\": \"Danois\",\n  \"language/de\": \"Allemand\",\n  \"language/el\": \"Grec\",\n  \"language/en\": \"Anglais\",\n  \"language/es\": \"Espagnol\",\n  \"language/es-MX\": \"Espagnol (Mexique)\",\n  \"language/et\": \"Estonien\",\n  \"language/fa\": \"Persan\",\n  \"language/fa-AF\": \"Dari\",\n  \"language/fi\": \"Finnois\",\n  \"language/fr\": \"Français\",\n  \"language/fr-CA\": \"Français (Canada)\",\n  \"language/ha\": \"Haoussa\",\n  \"language/he\": \"Hébreu\",\n  \"language/hi\": \"Hindi\",\n  \"language/hr\": \"Croate\",\n  \"language/ht\": \"Créole haïtien\",\n  \"language/hu\": \"Hongrois\",\n  \"language/id\": \"Indonésien\",\n  \"language/it\": \"Italien\",\n  \"language/ja\": \"Japonais\",\n  \"language/ka\": \"Géorgien\",\n  \"language/ko\": \"Coréen\",\n  \"language/lt\": \"Lituanien\",\n  \"language/lv\": \"Letton\",\n  \"language/ms\": \"Malais\",\n  \"language/nl\": \"Néerlandais\",\n  \"language/no\": \"Norvégien\",\n  \"language/pl\": \"Polonais\",\n  \"language/ps\": \"Pachto\",\n  \"language/pt\": \"Portugais\",\n  \"language/ro\": \"Roumain\",\n  \"language/ru\": \"Russe\",\n  \"language/sk\": \"Slovaque\",\n  \"language/sl\": \"Slovène\",\n  \"language/so\": \"Somali\",\n  \"language/sq\": \"Albanais\",\n  \"language/sr\": \"Serbe\",\n  \"language/sv\": \"Suédois\",\n  \"language/sw\": \"Swahili\",\n  \"language/ta\": \"Tamoul\",\n  \"language/th\": \"Thaï\",\n  \"language/tl\": \"Tagalog\",\n  \"language/tr\": \"Turc\",\n  \"language/uk\": \"Ukrainien\",\n  \"language/ur\": \"Ourdou\",\n  \"language/vi\": \"Vietnamien\",\n  \"language/zh\": \"Chinois (simplifié)\",\n  \"language/zh-TW\": \"Chinois (traditionnel)\",\n  \"Leave Channel\": \"Quitter le canal\",\n  \"Left channel\": \"Canal quitté\",\n  \"Let others add options\": \"Permettre à d'autres d'ajouter des options\",\n  \"Limit votes per person\": \"Limiter les votes par personne\",\n  \"Link\": \"Lien\",\n  \"linkCount_one\": \"Lien\",\n  \"linkCount_many\": \"{{ count }} liens\",\n  \"linkCount_other\": \"{{ count }} liens\",\n  \"live\": \"en direct\",\n  \"Live for {{duration}}\": \"En direct pendant {{duration}}\",\n  \"Live location\": \"Emplacement en direct\",\n  \"Live until {{ timestamp }}\": \"En direct jusqu'à {{ timestamp }}\",\n  \"Load more\": \"Charger plus\",\n  \"Local upload attachment missing local id\": \"Pièce jointe locale sans identifiant local\",\n  \"Location\": \"Emplacement\",\n  \"Location sharing ended\": \"Partage d'emplacement terminé\",\n  \"Location: {{ coordinates }}\": \"Emplacement : {{ coordinates }}\",\n  \"Mark as unread\": \"Marquer comme non lu\",\n  \"Maximum number of votes (from 2 to 10)\": \"Nombre maximum de votes (de 2 à 10)\",\n  \"Maximum votes per person\": \"Nombre maximal de votes par personne\",\n  \"Menu\": \"Menu\",\n  \"Message deleted\": \"Message supprimé\",\n  \"Message failed to send\": \"Échec de l'envoi du message\",\n  \"Message has been successfully flagged\": \"Le message a été signalé avec succès\",\n  \"Message marked as unread\": \"Message marqué comme non lu\",\n  \"Message pinned\": \"Message épinglé\",\n  \"Message unpinned\": \"Message désépinglé\",\n  \"Message was blocked by moderation policies\": \"Le message a été bloqué par les politiques de modération\",\n  \"Messages have been marked unread.\": \"Les messages ont été marqués comme non lus.\",\n  \"Missing permissions to upload the attachment\": \"Autorisations manquantes pour télécharger la pièce jointe\",\n  \"Multiple votes\": \"Votes multiples\",\n  \"Mute\": \"Muet\",\n  \"mute-command-args\": \"[@nomdutilisateur]\",\n  \"mute-command-description\": \"Muter un utilisateur\",\n  \"network error\": \"erreur réseau\",\n  \"New\": \"Nouveau\",\n  \"New message from {{user}}\": \"Nouveau message de {{user}}\",\n  \"New Messages!\": \"Nouveaux Messages!\",\n  \"Next image\": \"Image suivante\",\n  \"No chats here yet…\": \"Pas encore de messages ici...\",\n  \"No conversations yet\": \"Aucune conversation pour le moment\",\n  \"No items exist\": \"Aucun élément\",\n  \"No results found\": \"Aucun résultat trouvé\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Personne ne pourra plus voter dans ce sondage.\",\n  \"Nothing yet...\": \"Rien pour l'instant...\",\n  \"Offline\": \"Hors ligne\",\n  \"Ok\": \"D'accord\",\n  \"Online\": \"En ligne\",\n  \"Only numbers are allowed\": \"Seuls les chiffres sont autorisés\",\n  \"Only visible to you\": \"Visible uniquement pour vous\",\n  \"Open emoji picker\": \"Ouvrir le sélecteur d'émojis\",\n  \"Open gallery at image {{ index }}\": \"Ouvrir la galerie à l'image {{ index }}\",\n  \"Open image in gallery\": \"Ouvrir l'image dans la galerie\",\n  \"Open location in a map\": \"Ouvrir l'emplacement dans une carte\",\n  \"Option already exists\": \"L'option existe déjà\",\n  \"Option is empty\": \"L'option est vide\",\n  \"Options\": \"Options\",\n  \"Original\": \"Original\",\n  \"People matching\": \"Correspondance de personnes\",\n  \"Photo\": \"Photo\",\n  \"Pin\": \"Épingler\",\n  \"Pinned by {{ name }}\": \"Épinglé par {{ name }}\",\n  \"Pinned by You\": \"Épinglé par vous\",\n  \"placeholder/PollComment\": \"Votre commentaire\",\n  \"placeholder/PollOptionSuggestion\": \"Saisir une nouvelle option\",\n  \"Play video\": \"Lire la vidéo\",\n  \"Playback speed {{ rate }}x\": \"Vitesse de lecture {{ rate }}x\",\n  \"Poll\": \"Sondage\",\n  \"Poll comments\": \"Commentaires du sondage\",\n  \"Poll ended\": \"Sondage terminé\",\n  \"Poll options\": \"Options du sondage\",\n  \"Poll results\": \"Résultats du sondage\",\n  \"Previous image\": \"Image précédente\",\n  \"Question\": \"Question\",\n  \"Question {{ optionOrderNumber}}\": \"Question {{ optionOrderNumber}}\",\n  \"Question is required\": \"La question est obligatoire\",\n  \"Quote Reply\": \"Répondre par citation\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"La limite de votes a été atteinte. Supprimez d'abord un vote existant.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Le format d'enregistrement n'est pas pris en charge et ne peut pas être reproduit\",\n  \"Remind me\": \"Me rappeler\",\n  \"Remind Me\": \"Me rappeler\",\n  \"Reminder set\": \"Rappel défini\",\n  \"Remove reminder\": \"Supprimer le rappel\",\n  \"Remove save for later\": \"Supprimer « Enregistrer pour plus tard »\",\n  \"Replied to a thread\": \"A répondu à un fil\",\n  \"Reply\": \"Répondre\",\n  \"Reply to {{ authorName }}\": \"Répondre à {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Répondez à un message pour démarrer un fil\",\n  \"Reply to Message\": \"Répondre au message\",\n  \"replyCount_one\": \"1 réponse\",\n  \"replyCount_many\": \"{{ count }} réponses\",\n  \"replyCount_other\": \"{{ count }} réponses\",\n  \"Resend\": \"Renvoyer\",\n  \"Retry upload\": \"Réessayer le téléchargement\",\n  \"Review all options available in this poll\": \"Consultez toutes les options disponibles dans ce sondage\",\n  \"Review comments submitted with poll answers\": \"Consultez les commentaires envoyés avec les réponses au sondage\",\n  \"Review poll results and open an option to see detailed votes\": \"Consultez les résultats du sondage et ouvrez une option pour voir les votes détaillés\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Consultez ce message et choisissez de le supprimer, le modifier ou l'envoyer quand même\",\n  \"Review who voted for this option\": \"Consultez qui a voté pour cette option\",\n  \"Save for later\": \"Enregistrer pour plus tard\",\n  \"Saved for later\": \"Enregistré pour plus tard\",\n  \"Search\": \"Rechercher\",\n  \"Search GIFs\": \"Rechercher des GIFs\",\n  \"search-results-header-filter-source-button-label--channels\": \"canaux\",\n  \"search-results-header-filter-source-button-label--messages\": \"messages\",\n  \"search-results-header-filter-source-button-label--users\": \"utilisateurs\",\n  \"Searching for {{ searchSourceType }}...\": \"Recherche de {{ searchSourceType }}...\",\n  \"Searching...\": \"Recherche en cours...\",\n  \"searchResultsCount_one\": \"1 résultat\",\n  \"searchResultsCount_many\": \"{{ count }} résultats\",\n  \"searchResultsCount_other\": \"{{ count }} résultats\",\n  \"Select a thread to continue the conversation\": \"Sélectionnez un fil pour continuer la conversation\",\n  \"Select more than one option\": \"Sélectionner plus d'une option\",\n  \"Select one\": \"Sélectionner un\",\n  \"Select one or more\": \"Sélectionner un ou plusieurs\",\n  \"Select up to {{count}}_one\": \"Sélectionner jusqu'à {{count}}\",\n  \"Select up to {{count}}_many\": \"Sélectionner jusqu'à {{count}}\",\n  \"Select up to {{count}}_other\": \"Sélectionner jusqu'à {{count}}\",\n  \"Select your current location and optionally enable live location sharing\": \"Sélectionnez votre position actuelle et activez éventuellement le partage de position en direct\",\n  \"Send\": \"Envoyer\",\n  \"Send a message\": \"Envoyez un message\",\n  \"Send a message to start the conversation\": \"Envoyez un message pour commencer la conversation\",\n  \"Send Anyway\": \"Envoyer quand même\",\n  \"Send message request failed\": \"Échec de la demande d'envoi de message\",\n  \"Send poll\": \"Envoyer le sondage\",\n  \"Sending...\": \"Envoi en cours...\",\n  \"Sent\": \"Envoyé\",\n  \"Share\": \"Partager\",\n  \"Share live location for\": \"Partager l'emplacement en direct pendant\",\n  \"Share Location\": \"Partager l'emplacement\",\n  \"Shared live location\": \"Emplacement en direct partagé\",\n  \"Shared location\": \"Position partagée\",\n  \"Shuffle\": \"Mélanger\",\n  \"size limit\": \"limite de taille\",\n  \"Slow Mode ON\": \"Mode lent activé\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Mode lent, attendez {{ seconds }} s...\",\n  \"Some of the files will not be accepted\": \"Certains fichiers ne seront pas acceptés\",\n  \"Start typing to search\": \"Commencez à taper pour rechercher\",\n  \"Stop sharing\": \"Arrêter de partager\",\n  \"Submit\": \"Envoyer\",\n  \"Suggest a new option to add to this poll\": \"Suggérez une nouvelle option à ajouter à ce sondage\",\n  \"Suggest an option\": \"Suggérer une option\",\n  \"Tap to remove\": \"Appuyez pour retirer\",\n  \"Tap to remove: {{ reactionName }}\": \"Appuyez pour retirer: {{ reactionName }}\",\n  \"Thinking...\": \"Réflexion...\",\n  \"this content could not be displayed\": \"ce contenu n'a pas pu être affiché\",\n  \"This field cannot be empty or contain only spaces\": \"Ce champ ne peut pas être vide ou contenir uniquement des espaces\",\n  \"This message did not meet our content guidelines\": \"Ce message ne respecte pas nos directives de contenu\",\n  \"Thread\": \"Fil de discussion\",\n  \"Thread has not been found\": \"Le fil de discussion n'a pas été trouvé\",\n  \"Thread reply\": \"Réponse dans le fil\",\n  \"Thread Reply\": \"Réponse dans le fil\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Chargement...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} fil non lu\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} fils non lus\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} fils non lus\",\n  \"Threads\": \"Fils\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Hier]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Aujourd'hui]\\\", \\\"nextDay\\\": \\\"[Demain]\\\", \\\"lastDay\\\": \\\"[Hier]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Dernier] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Aujourd'hui\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Hier\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Pour commencer l'enregistrement, autorisez l'accès à la caméra dans votre navigateur\",\n  \"To start recording, allow the microphone access in your browser\": \"Pour commencer l'enregistrement, autorisez l'accès au microphone dans votre navigateur\",\n  \"totalVoteCount_one\": \"1 vote au total\",\n  \"totalVoteCount_many\": \"{{ count }} votes au total\",\n  \"totalVoteCount_other\": \"{{ count }} votes au total\",\n  \"Translated\": \"Traduit\",\n  \"Translated from {{ language }}\": \"Traduit du {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Tapez un nombre de 2 à 10\",\n  \"Unarchive\": \"Désarchiver\",\n  \"unban-command-args\": \"[@nomdutilisateur]\",\n  \"unban-command-description\": \"Débannir un utilisateur\",\n  \"Unblock User\": \"Débloquer l'utilisateur\",\n  \"unknown error\": \"erreur inconnue\",\n  \"Unmute\": \"Désactiver muet\",\n  \"unmute-command-args\": \"[@nomdutilisateur]\",\n  \"unmute-command-description\": \"Démuter un utilisateur\",\n  \"Unpin\": \"Détacher\",\n  \"Unread messages\": \"Messages non lus\",\n  \"Unsupported attachment\": \"Pièce jointe non prise en charge\",\n  \"unsupported file type\": \"type de fichier non pris en charge\",\n  \"Update\": \"Mettre à jour\",\n  \"Update the comment attached to your poll answer\": \"Mettez à jour le commentaire joint à votre réponse au sondage\",\n  \"Update your comment\": \"Mettre à jour votre commentaire\",\n  \"Upload blocked\": \"Téléversement bloqué\",\n  \"Upload error\": \"Erreur de téléversement\",\n  \"Upload failed\": \"Échec du téléversement\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Le type de fichier : \\\"{{ type }}\\\" n'est pas autorisé\",\n  \"User blocked\": \"Utilisateur bloqué\",\n  \"User unblocked\": \"Utilisateur débloqué\",\n  \"User uploaded content\": \"Contenu téléchargé par l'utilisateur\",\n  \"Video\": \"Vidéo\",\n  \"videoCount_one\": \"Vidéo\",\n  \"videoCount_many\": \"{{ count }} vidéos\",\n  \"videoCount_other\": \"{{ count }} vidéos\",\n  \"View\": \"Voir\",\n  \"View {{count}} comments_one\": \"Voir {{count}} commentaire\",\n  \"View {{count}} comments_many\": \"Voir {{count}} commentaires\",\n  \"View {{count}} comments_other\": \"Voir {{count}} commentaires\",\n  \"View all\": \"Tout voir\",\n  \"View original\": \"Voir l'original\",\n  \"View results\": \"Voir les résultats\",\n  \"View translation\": \"Voir la traduction\",\n  \"Voice message\": \"Message vocal\",\n  \"Voice message {{ duration }}\": \"Message vocal {{ duration }}\",\n  \"Voice message deleted\": \"Message vocal supprimé\",\n  \"voiceMessageCount_one\": \"Mémo vocal\",\n  \"voiceMessageCount_many\": \"{{ count }} mémos vocaux\",\n  \"voiceMessageCount_other\": \"{{ count }} mémos vocaux\",\n  \"Vote ended\": \"Vote terminé\",\n  \"Votes\": \"Votes\",\n  \"Wait until all attachments have uploaded\": \"Attendez que toutes les pièces jointes soient téléchargées\",\n  \"Waiting for network…\": \"En attente du réseau…\",\n  \"You\": \"Vous\",\n  \"You've reached the maximum number of files\": \"Vous avez atteint le nombre maximal de fichiers\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} और {{ moreCount }} और\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} और {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} फ़ाइल\",\n  \"{{ count }} files_other\": \"{{ count }} फ़ाइलें\",\n  \"{{ count }} people are typing_one\": \"{{ count }} व्यक्ति टाइप कर रहा है\",\n  \"{{ count }} people are typing_many\": \"{{ count }} लोग टाइप कर रहे हैं\",\n  \"{{ count }} people are typing_other\": \"{{ count }} लोग टाइप कर रहे हैं\",\n  \"{{ count }} photos_one\": \"{{ count }} फ़ोटो\",\n  \"{{ count }} photos_other\": \"{{ count }} फ़ोटो\",\n  \"{{ count }} reactions_one\": \"{{ count }} प्रतिक्रिया\",\n  \"{{ count }} reactions_other\": \"{{ count }} प्रतिक्रियाएं\",\n  \"{{ count }} videos_one\": \"{{ count }} वीडियो\",\n  \"{{ count }} videos_other\": \"{{ count }} वीडियो\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} और {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} और\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} मेंबर्स\",\n  \"{{ typing }} are typing\": \"{{ typing }} टाइप कर रहे हैं\",\n  \"{{ typing }} is typing\": \"{{ typing }} टाइप कर रहा है\",\n  \"{{ user }} has been muted\": \"{{ user }} को म्यूट कर दिया गया है\",\n  \"{{ user }} has been unmuted\": \"{{ user }} को अनम्यूट कर दिया गया है\",\n  \"{{ user }} is typing...\": \"{{ user }} टाइप कर रहा है...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} और {{ user }} टाइप कर रहे हैं...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} और अधिक टाइप कर रहे हैं...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} ऑनलाइन\",\n  \"{{count}} new messages_one\": \"{{count}} नया संदेश\",\n  \"{{count}} new messages_other\": \"{{count}} नए संदेश\",\n  \"{{count}} unread_one\": \"{{count}} अपठित\",\n  \"{{count}} unread_other\": \"{{count}} अपठित\",\n  \"{{count}} votes_one\": \"{{count}} वोट\",\n  \"{{count}} votes_other\": \"{{count}} वोट\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} और विकल्प\",\n  \"+{{count}} more options_other\": \"+{{count}} और विकल्प\",\n  \"🏙 Attachment...\": \"🏙 अटैचमेंट\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} ने बनाया: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} ने वोट दिया: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍साझा किया गया स्थान\",\n  \"Add a comment\": \"एक टिप्पणी जोड़ें\",\n  \"Add a comment to your poll answer\": \"अपने पोल उत्तर में एक टिप्पणी जोड़ें\",\n  \"Add an option\": \"एक विकल्प जोड़ें\",\n  \"Add reaction\": \"प्रतिक्रिया जोड़ें\",\n  \"All results loaded\": \"सभी परिणाम लोड हो गए\",\n  \"Allow access to camera\": \"कैमरा तक पहुँच दें\",\n  \"Allow access to microphone\": \"माइक्रोफ़ोन तक पहुँच दें\",\n  \"Allow comments\": \"टिप्पणियाँ की अनुमति दें\",\n  \"Allow option suggestion\": \"विकल्प सुझाव की अनुमति दें\",\n  \"Allow others to add comments\": \"दूसरों को टिप्पणी जोड़ने दें\",\n  \"Also send as a direct message\": \"सीधे संदेश के रूप में भी भेजें\",\n  \"Also send in channel\": \"चैनल में भी भेजें\",\n  \"Also sent in channel\": \"चैनल में भी भेजा गया\",\n  \"An error has occurred during recording\": \"रेकॉर्डिंग के दौरान एक त्रुटि आ गई है\",\n  \"An error has occurred during the recording processing\": \"रेकॉर्डिंग प्रोसेसिंग के दौरान एक त्रुटि आ गई है\",\n  \"Anonymous\": \"गुमनाम\",\n  \"Anonymous poll\": \"गुमनाम मतदान\",\n  \"Archive\": \"आर्काइव\",\n  \"Are you sure you want to delete this message?\": \"क्या आप वाकई इस संदेश को हटाना चाहते हैं?\",\n  \"aria/Attachment\": \"अनुलग्नक\",\n  \"aria/Attachment Actions\": \"अटैचमेंट क्रियाएँ\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"ऑडियो स्थिति {{ elapsed }} / {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"ऑडियो स्थिति {{ progress }} प्रतिशत\",\n  \"aria/Block User\": \"उपयोगकर्ता को ब्लॉक करें\",\n  \"aria/Bookmark Message\": \"संदेश बुकमार्क करें\",\n  \"aria/Cancel recording\": \"रिकॉर्डिंग रद्द करें\",\n  \"aria/Cancel Reply\": \"उत्तर रद्द करें\",\n  \"aria/Cancel upload\": \"अपलोड रद्द करें\",\n  \"aria/Channel Actions\": \"चैनल क्रियाएँ\",\n  \"aria/Channel list\": \"चैनल सूची\",\n  \"aria/Channel search results\": \"चैनल खोज परिणाम\",\n  \"aria/Chat view tabs\": \"चैट व्यू टैब\",\n  \"aria/Clear search\": \"खोज साफ़ करें\",\n  \"aria/Close callout dialog\": \"कॉलआउट संवाद बंद करें\",\n  \"aria/Close thread\": \"थ्रेड बंद करें\",\n  \"aria/Collapse sidebar\": \"साइडबार संक्षिप्त करें\",\n  \"aria/Command Suggestions\": \"कमांड सुझाव\",\n  \"aria/Complete recording\": \"रिकॉर्डिंग पूर्ण करें\",\n  \"aria/Copy Message Text\": \"संदेश की टेक्स्ट कॉपी करें\",\n  \"aria/Decrease value\": \"मान घटाएं\",\n  \"aria/Delete Message\": \"संदेश डिलीट करें\",\n  \"aria/Dismiss notification\": \"सूचना बंद करें\",\n  \"aria/Download attachment\": \"अनुलग्नक डाउनलोड करें\",\n  \"aria/Edit Message\": \"मैसेज में बदलाव करे\",\n  \"aria/Emoji picker\": \"इमोजी चुनने वाला\",\n  \"aria/Emoji Suggestions\": \"इमोजी सुझाव\",\n  \"aria/Exit search\": \"खोज से बाहर निकलें\",\n  \"aria/Expand sidebar\": \"साइडबार विस्तारित करें\",\n  \"aria/File input\": \"फ़ाइल इनपुट\",\n  \"aria/File upload\": \"फ़ाइल अपलोड\",\n  \"aria/Flag Message\": \"संदेश फ्लैग करें\",\n  \"aria/Image failed to load\": \"छवि लोड होने में विफल\",\n  \"aria/Image input\": \"छवि इनपुट\",\n  \"aria/Increase value\": \"मान बढ़ाएं\",\n  \"aria/Jump to latest message\": \"नवीनतम संदेश पर जाएं\",\n  \"aria/Jump to quoted message\": \"उद्धृत संदेश पर जाएं\",\n  \"aria/Load More Channels\": \"और चैनल लोड करें\",\n  \"aria/Mark Message Unread\": \"अपठित चिह्नित करें\",\n  \"aria/Mark messages as read\": \"संदेशों को पढ़ा हुआ चिह्नित करें\",\n  \"aria/Menu\": \"मेन्यू\",\n  \"aria/Message Actions\": \"संदेश कार्रवाइयाँ\",\n  \"aria/Message from {{ user }},\": \"{{ user }} का संदेश,\",\n  \"aria/Message Options\": \"संदेश विकल्प\",\n  \"aria/Message,\": \"संदेश,\",\n  \"aria/Mute User\": \"उपयोगकर्ता म्यूट करें\",\n  \"aria/Notifications\": \"सूचनाएं\",\n  \"aria/Open Attachment Selector\": \"अटैचमेंट चयनकर्ता खोलें\",\n  \"aria/Open Channel Actions Menu\": \"चैनल क्रियाएँ मेनू खोलें\",\n  \"aria/Open Menu\": \"मेन्यू खोलें\",\n  \"aria/Open Message Actions Menu\": \"संदेश क्रिया मेन्यू खोलें\",\n  \"aria/Open Reaction Selector\": \"प्रतिक्रिया चयनकर्ता खोलें\",\n  \"aria/Open Thread\": \"थ्रेड खोलें\",\n  \"aria/Pause\": \"रोकें\",\n  \"aria/Pause recording\": \"रिकॉर्डिंग रोकें\",\n  \"aria/Percent complete\": \"{{percent}} प्रतिशत पूर्ण\",\n  \"aria/Pin Message\": \"संदेश पिन करें\",\n  \"aria/Play\": \"चलाएँ\",\n  \"aria/Quote Message\": \"संदेश उद्धरण\",\n  \"aria/Reaction list\": \"प्रतिक्रिया सूची\",\n  \"aria/Remind Me Message\": \"मुझे याद दिलाएं\",\n  \"aria/Remind Me Options\": \"रिमाइंडर विकल्प\",\n  \"aria/Remove attachment\": \"संलग्नक हटाएं\",\n  \"aria/Remove location attachment\": \"स्थान संलग्नक हटाएं\",\n  \"aria/Remove option\": \"विकल्प हटाएं\",\n  \"aria/Remove Reminder\": \"अनुस्मारक हटाएं\",\n  \"aria/Remove Save For Later\": \"बाद में देखें हटाएं\",\n  \"aria/Resend Message\": \"संदेश फिर से भेजें\",\n  \"aria/Resume recording\": \"रिकॉर्डिंग फिर शुरू करें\",\n  \"aria/Retry upload\": \"अपलोड पुनः प्रयास करें\",\n  \"aria/Review bounced message\": \"वापस लौटा संदेश समीक्षा करें\",\n  \"aria/Search results\": \"खोज परिणाम\",\n  \"aria/Search results header filter button for: {{ source }}\": \"{{ source }} के लिए खोज परिणाम शीर्षक फ़िल्टर बटन\",\n  \"aria/Seek audio position\": \"ऑडियो स्थिति खोजें\",\n  \"aria/Select Channel: {{ channelName }}\": \"चैनल चुनें: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"प्रतिक्रिया चुनें: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"उपयोगकर्ता चैनल चुनें: {{ name }}\",\n  \"aria/Send\": \"भेजें\",\n  \"aria/Show preview\": \"पूर्वावलोकन दिखाएं\",\n  \"aria/Start recording audio\": \"ऑडियो रिकॉर्डिंग शुरू करें\",\n  \"aria/Stop AI Generation\": \"एआई जनरेशन रोकें\",\n  \"aria/Suggestions\": \"सुझाव\",\n  \"aria/Thread list\": \"थ्रेड सूची\",\n  \"aria/Unblock User\": \"उपयोगकर्ता अनब्लॉक करें\",\n  \"aria/Unmute User\": \"उपयोगकर्ता अनम्यूट करें\",\n  \"aria/Unpin Message\": \"संदेश अनपिन करें\",\n  \"aria/User Suggestions\": \"उपयोगकर्ता सुझाव\",\n  \"Ask a question\": \"एक प्रश्न पूछें\",\n  \"Attach\": \"संलग्न करें\",\n  \"Attach files\": \"फाइल्स अटैच करे\",\n  \"Attachment\": \"अनुलग्नक\",\n  \"Attachment upload blocked due to {{reason}}\": \"{{reason}} के कारण अटैचमेंट अपलोड ब्लॉक किया गया\",\n  \"Attachment upload failed due to {{reason}}\": \"{{reason}} के कारण अटैचमेंट अपलोड विफल रहा\",\n  \"Back\": \"वापस\",\n  \"ban-command-args\": \"[@उपयोगकर्तनाम] [पाठ]\",\n  \"ban-command-description\": \"एक उपयोगकर्ता को प्रतिषेधित करें\",\n  \"Block User\": \"उपयोगकर्ता को ब्लॉक करें\",\n  \"Cancel\": \"रद्द करें\",\n  \"Cannot seek in the recording\": \"रेकॉर्डिंग में खोज नहीं की जा सकती\",\n  \"Channel archived\": \"चैनल संग्रहीत किया गया\",\n  \"Channel Missing\": \"चैनल उपलब्ध नहीं है\",\n  \"Channel muted\": \"चैनल म्यूट किया गया\",\n  \"Channel pinned\": \"चैनल पिन किया गया\",\n  \"Channel unarchived\": \"चैनल असंग्रहीत किया गया\",\n  \"Channel unmuted\": \"चैनल अनम्यूट किया गया\",\n  \"Channel unpinned\": \"चैनल अनपिन किया गया\",\n  \"Channels\": \"चैनल\",\n  \"Chats\": \"चैट\",\n  \"Choose between 2 to 10 options\": \"2 से 10 विकल्प चुनें\",\n  \"Close\": \"बंद करे\",\n  \"Close dialog\": \"डायलॉग बंद करें\",\n  \"Close emoji picker\": \"इमोजी पिकर बंद करें\",\n  \"Close prompt: {{ title }}\": \"प्रॉम्प्ट बंद करें: {{ title }}\",\n  \"Command not available while editing\": \"संपादन के दौरान कमांड उपलब्ध नहीं है\",\n  \"Command not available while replying\": \"उत्तर देते समय कमांड उपलब्ध नहीं है\",\n  \"Commands\": \"कमांड\",\n  \"Commands matching\": \"मेल खाती है\",\n  \"Connection failure, reconnecting now...\": \"कनेक्शन विफल रहा, अब पुनः कनेक्ट हो रहा है ...\",\n  \"Copy Message\": \"संदेश कॉपी करें\",\n  \"Create\": \"बनाएँ\",\n  \"Create a question, add options, and configure poll settings\": \"एक प्रश्न बनाएं, विकल्प जोड़ें और पोल सेटिंग्स कॉन्फ़िगर करें\",\n  \"Create poll\": \"मतदान बनाएँ\",\n  \"Current location\": \"वर्तमान स्थान\",\n  \"Delete\": \"डिलीट\",\n  \"Delete for me\": \"मेरे लिए डिलीट करें\",\n  \"Delete message\": \"संदेश हटाएं\",\n  \"Delivered\": \"पहुंच गया\",\n  \"Direct message\": \"प्रत्यक्ष संदेश\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"क्या आप अभी इस पोल को समाप्त करना चाहते हैं? इस पोल में अब कोई भी वोट नहीं कर पाएगा।\",\n  \"Download All\": \"सब डाउनलोड करें\",\n  \"Download Attachment\": \"अटैचमेंट डाउनलोड करें\",\n  \"Download attachment {{ name }}\": \"अनुलग्नक {{ name }} डाउनलोड करें\",\n  \"Drag your files here\": \"अपनी फ़ाइलें यहाँ खींचें\",\n  \"Drag your files here to add to your post\": \"अपनी फ़ाइलें यहाँ खींचें और अपने पोस्ट में जोड़ने के लिए\",\n  \"Due {{ timeLeft }}\": \"{{ timeLeft }} में देय\",\n  \"Due since {{ dueSince }}\": \"{{ dueSince }} से देय\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"मैसेज में बदलाव करे\",\n  \"Edit message request failed\": \"संदेश संपादित करने का अनुरोध विफल रहा\",\n  \"Edited\": \"संपादित\",\n  \"Emoji matching\": \"इमोजी मिलान\",\n  \"Empty message...\": \"खाली संदेश ...\",\n  \"End\": \"समाप्त\",\n  \"End poll\": \"पोल समाप्त करें\",\n  \"End this poll?\": \"इस पोल को समाप्त करें?\",\n  \"End vote\": \"मत समाप्त करें\",\n  \"Enforce unique vote is enabled\": \"अनोखा वोट सक्षम है\",\n  \"Error\": \"त्रुटि\",\n  \"Error adding flag\": \"ध्वज जोड़ने में त्रुटि\",\n  \"Error connecting to chat, refresh the page to try again.\": \"चैट से कनेक्ट करने में त्रुटि, पेज को रिफ्रेश करें\",\n  \"Error deleting message\": \"संदेश हटाने में त्रुटि\",\n  \"Error fetching reactions\": \"प्रतिक्रियाएँ लोड करने में त्रुटि\",\n  \"Error marking message unread\": \"संदेश को अपठित चिह्नित करने में त्रुटि\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"संदेश को अपठित मार्क करने में त्रुटि। सबसे नए 100 चैनल संदेश से पहले के सभी अपठित संदेशों को अपठित मार्क नहीं किया जा सकता है।\",\n  \"Error muting a user ...\": \"यूजर को म्यूट करने का प्रयास फेल हुआ\",\n  \"Error pinning message\": \"संदेश को पिन करने में त्रुटि\",\n  \"Error removing message pin\": \"संदेश पिन निकालने में त्रुटि\",\n  \"Error reproducing the recording\": \"रिकॉर्डिंग पुन: उत्पन्न करने में त्रुटि\",\n  \"Error starting recording\": \"रेकॉर्डिंग शुरू करने में त्रुटि\",\n  \"Error unmuting a user ...\": \"यूजर को अनम्यूट करने का प्रयास फेल हुआ\",\n  \"Error uploading attachment\": \"अटैचमेंट अपलोड करते समय त्रुटि\",\n  \"Error uploading file\": \"फ़ाइल अपलोड करने में त्रुटि\",\n  \"Error uploading image\": \"छवि अपलोड करने में त्रुटि\",\n  \"Error: {{ errorMessage }}\": \"फेल: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"कमांड से बाहर निकलें {{ command }}\",\n  \"Failed to block user\": \"उपयोगकर्ता को ब्लॉक करने में विफल\",\n  \"Failed to create the poll\": \"मतदान बनाने में विफल\",\n  \"Failed to create the poll due to {{reason}}\": \"मतदान {{reason}} के कारण नहीं बन सका\",\n  \"Failed to delete the message\": \"संदेश हटाने में विफल\",\n  \"Failed to end the poll\": \"पोल समाप्त करने में विफल\",\n  \"Failed to end the poll due to {{reason}}\": \"{{reason}} के कारण पोल समाप्त करने में विफल\",\n  \"Failed to jump to the first unread message\": \"पहले अपठित संदेश पर जाने में विफल\",\n  \"Failed to leave channel\": \"चैनल छोड़ने में विफल\",\n  \"Failed to load channels\": \"चैनल लोड करने में विफल\",\n  \"Failed to load more channels\": \"और चैनल लोड करने में विफल\",\n  \"Failed to mark channel as read\": \"चैनल को पढ़ा हुआ चिह्नित करने में विफल।\",\n  \"Failed to play the recording\": \"रेकॉर्डिंग प्ले करने में विफल\",\n  \"Failed to retrieve location\": \"स्थान प्राप्त करने में विफल\",\n  \"Failed to share location\": \"स्थान साझा करने में विफल\",\n  \"Failed to update channel archive status\": \"चैनल के आर्काइव स्थिति को अपडेट करने में विफल\",\n  \"Failed to update channel mute status\": \"चैनल की म्यूट स्थिति को अपडेट करने में विफल\",\n  \"Failed to update channel pinned status\": \"चैनल की पिन स्थिति को अपडेट करने में विफल\",\n  \"File\": \"फ़ाइल\",\n  \"File is required for upload attachment\": \"अटैचमेंट अपलोड के लिए फ़ाइल आवश्यक है\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"फ़ाइल बहुत बड़ी है: {{ size }}, अधिकतम अपलोड साइज़ {{ limit }} है\",\n  \"File too large\": \"फ़ाइल बहुत बड़ी है\",\n  \"fileCount_one\": \"1 फ़ाइल\",\n  \"fileCount_other\": \"{{ count }} फ़ाइलें\",\n  \"Flag\": \"फ्लैग करे\",\n  \"Generating...\": \"बना रहा है...\",\n  \"giphy-command-args\": \"[पाठ]\",\n  \"giphy-command-description\": \"चैनल पर एक क्रॉफिल जीआइएफ पोस्ट करें\",\n  \"Hide who voted\": \"किसने वोट दिया छिपाएं\",\n  \"Image\": \"छवि\",\n  \"imageCount_one\": \"1 छवि\",\n  \"imageCount_other\": \"{{ count }} छवियाँ\",\n  \"Instant commands\": \"तत्काल कमांड\",\n  \"language/af\": \"अफ्रीकी\",\n  \"language/am\": \"अम्हारिक\",\n  \"language/ar\": \"अरबी\",\n  \"language/az\": \"अज़रबैजानी\",\n  \"language/bg\": \"बुल्गारियाई\",\n  \"language/bn\": \"बंगाली\",\n  \"language/bs\": \"बोस्नियाई\",\n  \"language/cs\": \"चेक\",\n  \"language/da\": \"डेनिश\",\n  \"language/de\": \"जर्मन\",\n  \"language/el\": \"यूनानी\",\n  \"language/en\": \"अंग्रेज़ी\",\n  \"language/es\": \"स्पेनिश\",\n  \"language/es-MX\": \"स्पेनिश (मेक्सिको)\",\n  \"language/et\": \"एस्तोनियाई\",\n  \"language/fa\": \"फ़ारसी\",\n  \"language/fa-AF\": \"दरी\",\n  \"language/fi\": \"फ़िनिश\",\n  \"language/fr\": \"फ़्रेंच\",\n  \"language/fr-CA\": \"फ़्रेंच (कनाडा)\",\n  \"language/ha\": \"हौसा\",\n  \"language/he\": \"हिब्रू\",\n  \"language/hi\": \"हिंदी\",\n  \"language/hr\": \"क्रोएशियाई\",\n  \"language/ht\": \"हैतियाई क्रियोल\",\n  \"language/hu\": \"हंगेरी\",\n  \"language/id\": \"इंडोनेशियाई\",\n  \"language/it\": \"इतालवी\",\n  \"language/ja\": \"जापानी\",\n  \"language/ka\": \"जॉर्जियाई\",\n  \"language/ko\": \"कोरियाई\",\n  \"language/lt\": \"लिथुआनियाई\",\n  \"language/lv\": \"लातवियाई\",\n  \"language/ms\": \"मलय\",\n  \"language/nl\": \"डच\",\n  \"language/no\": \"नॉर्वेजियाई\",\n  \"language/pl\": \"पोलिश\",\n  \"language/ps\": \"पश्तो\",\n  \"language/pt\": \"पुर्तगाली\",\n  \"language/ro\": \"रोमानियाई\",\n  \"language/ru\": \"रूसी\",\n  \"language/sk\": \"स्लोवाक\",\n  \"language/sl\": \"स्लोवेनियाई\",\n  \"language/so\": \"सोमाली\",\n  \"language/sq\": \"अल्बानियाई\",\n  \"language/sr\": \"सर्बियाई\",\n  \"language/sv\": \"स्वीडिश\",\n  \"language/sw\": \"स्वाहिली\",\n  \"language/ta\": \"तमिल\",\n  \"language/th\": \"थाई\",\n  \"language/tl\": \"तागालोग\",\n  \"language/tr\": \"तुर्की\",\n  \"language/uk\": \"यूक्रेनियाई\",\n  \"language/ur\": \"उर्दू\",\n  \"language/vi\": \"वियतनामी\",\n  \"language/zh\": \"चीनी (सरलीकृत)\",\n  \"language/zh-TW\": \"चीनी (पारंपरिक)\",\n  \"Leave Channel\": \"चैनल छोड़ें\",\n  \"Left channel\": \"चैनल छोड़ दिया गया\",\n  \"Let others add options\": \"दूसरों को विकल्प जोड़ने दें\",\n  \"Limit votes per person\": \"प्रति व्यक्ति वोट सीमित करें\",\n  \"Link\": \"लिंक\",\n  \"linkCount_one\": \"1 लिंक\",\n  \"linkCount_other\": \"{{ count }} लिंक\",\n  \"live\": \"लाइव\",\n  \"Live for {{duration}}\": \"{{duration}} के लिए लाइव\",\n  \"Live location\": \"लाइव स्थान\",\n  \"Live until {{ timestamp }}\": \"{{ timestamp }} तक लाइव\",\n  \"Load more\": \"और लोड करें\",\n  \"Local upload attachment missing local id\": \"लोकल अपलोड अटैचमेंट में लोकल आईडी नहीं है\",\n  \"Location\": \"स्थान\",\n  \"Location sharing ended\": \"स्थान साझा करना समाप्त\",\n  \"Location: {{ coordinates }}\": \"स्थान: {{ coordinates }}\",\n  \"Mark as unread\": \"अपठित चिह्नित करें\",\n  \"Maximum number of votes (from 2 to 10)\": \"अधिकतम वोटों की संख्या (2 से 10)\",\n  \"Maximum votes per person\": \"प्रति व्यक्ति अधिकतम वोट\",\n  \"Menu\": \"मेन्यू\",\n  \"Message deleted\": \"मैसेज हटा दिया गया\",\n  \"Message failed to send\": \"संदेश भेजने में विफल\",\n  \"Message has been successfully flagged\": \"मैसेज को फ्लैग कर दिया गया है\",\n  \"Message marked as unread\": \"संदेश को अपठित के रूप में चिह्नित किया गया\",\n  \"Message pinned\": \"संदेश पिन किया गया\",\n  \"Message unpinned\": \"संदेश अनपिन किया गया\",\n  \"Message was blocked by moderation policies\": \"संदेश को मॉडरेशन नीतियों द्वारा ब्लॉक कर दिया गया है\",\n  \"Messages have been marked unread.\": \"संदेशों को अपठित चिह्नित किया गया है।\",\n  \"Missing permissions to upload the attachment\": \"अटैचमेंट अपलोड करने के लिए अनुमतियां गायब\",\n  \"Multiple votes\": \"कई वोट\",\n  \"Mute\": \"म्यूट करे\",\n  \"mute-command-args\": \"[@उपयोगकर्तनाम]\",\n  \"mute-command-description\": \"एक उपयोगकर्ता को म्यूट करें\",\n  \"network error\": \"नेटवर्क त्रुटि\",\n  \"New\": \"नए\",\n  \"New message from {{user}}\": \"{{user}} से नया संदेश\",\n  \"New Messages!\": \"नए मैसेज!\",\n  \"Next image\": \"अगली छवि\",\n  \"No chats here yet…\": \"यहां अभी तक कोई चैट नहीं...\",\n  \"No conversations yet\": \"अभी तक कोई बातचीत नहीं है\",\n  \"No items exist\": \"कोई आइटम मौजूद नहीं है\",\n  \"No results found\": \"कोई परिणाम नहीं मिला\",\n  \"Nobody will be able to vote in this poll anymore.\": \"अब कोई भी इस मतदान में मतदान नहीं कर सकेगा।\",\n  \"Nothing yet...\": \"कोई मैसेज नहीं है\",\n  \"Offline\": \"ऑफलाइन\",\n  \"Ok\": \"ठीक है\",\n  \"Online\": \"ऑनलाइन\",\n  \"Only numbers are allowed\": \"केवल संख्याएँ अनुमत हैं\",\n  \"Only visible to you\": \"केवल आपको दिखाई देता है\",\n  \"Open emoji picker\": \"इमोजी पिकर खोलिये\",\n  \"Open gallery at image {{ index }}\": \"गैलरी को छवि {{ index }} पर खोलें\",\n  \"Open image in gallery\": \"छवि को गैलरी में खोलें\",\n  \"Open location in a map\": \"मानचित्र में स्थान खोलें\",\n  \"Option already exists\": \"विकल्प पहले से मौजूद है\",\n  \"Option is empty\": \"विकल्प खाली है\",\n  \"Options\": \"विकल्प\",\n  \"Original\": \"मूल\",\n  \"People matching\": \"मेल खाते लोग\",\n  \"Photo\": \"फ़ोटो\",\n  \"Pin\": \"पिन\",\n  \"Pinned by {{ name }}\": \"{{ name }} द्वारा पिन किया गया\",\n  \"Pinned by You\": \"आपके द्वारा पिन किया गया\",\n  \"placeholder/PollComment\": \"आपकी टिप्पणी\",\n  \"placeholder/PollOptionSuggestion\": \"नया विकल्प दर्ज करें\",\n  \"Play video\": \"वीडियो चलाएं\",\n  \"Playback speed {{ rate }}x\": \"प्लेबैक गति {{ rate }}x\",\n  \"Poll\": \"मतदान\",\n  \"Poll comments\": \"मतदान टिप्पणियाँ\",\n  \"Poll ended\": \"पोल समाप्त\",\n  \"Poll options\": \"मतदान विकल्प\",\n  \"Poll results\": \"मतदान परिणाम\",\n  \"Previous image\": \"पिछली छवि\",\n  \"Question\": \"प्रश्न\",\n  \"Question {{ optionOrderNumber}}\": \"प्रश्न {{ optionOrderNumber}}\",\n  \"Question is required\": \"प्रश्न आवश्यक है\",\n  \"Quote Reply\": \"उद्धरण जवाब\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"मतदान सीमा तक पहुंच गया। पहले एक मौजूदा वोट हटाएं।\",\n  \"Recording format is not supported and cannot be reproduced\": \"रेकॉर्डिंग फ़ॉर्मेट समर्थित नहीं है और पुनः उत्पन्न नहीं किया जा सकता\",\n  \"Remind me\": \"मुझे याद दिलाएं\",\n  \"Remind Me\": \"मुझे याद दिलाएं\",\n  \"Reminder set\": \"अनुस्मारक सेट किया गया\",\n  \"Remove reminder\": \"रिमाइंडर हटाएं\",\n  \"Remove save for later\": \"बाद में देखें हटाएं\",\n  \"Replied to a thread\": \"थ्रेड में जवाब दिया\",\n  \"Reply\": \"जवाब दे दो\",\n  \"Reply to {{ authorName }}\": \"{{ authorName }} को जवाब दें\",\n  \"Reply to a message to start a thread\": \"थ्रेड शुरू करने के लिए किसी संदेश का जवाब दें\",\n  \"Reply to Message\": \"संदेश का जवाब दें\",\n  \"replyCount_one\": \"1 रिप्लाई\",\n  \"replyCount_other\": \"{{ count }} रिप्लाई\",\n  \"Resend\": \"फिर से भेजें\",\n  \"Retry upload\": \"अपलोड फिर से करें\",\n  \"Review all options available in this poll\": \"इस पोल में उपलब्ध सभी विकल्पों की समीक्षा करें\",\n  \"Review comments submitted with poll answers\": \"पोल उत्तरों के साथ भेजी गई टिप्पणियों की समीक्षा करें\",\n  \"Review poll results and open an option to see detailed votes\": \"पोल परिणामों की समीक्षा करें और विस्तृत वोट देखने के लिए एक विकल्प खोलें\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"इस संदेश की समीक्षा करें और चुनें कि इसे हटाना है, संपादित करना है या फिर भी भेजना है\",\n  \"Review who voted for this option\": \"समीक्षा करें कि इस विकल्प के लिए किसने वोट किया\",\n  \"Save for later\": \"बाद के लिए सहेजें\",\n  \"Saved for later\": \"बाद के लिए सहेजा गया\",\n  \"Search\": \"खोज\",\n  \"Search GIFs\": \"GIF खोजें\",\n  \"search-results-header-filter-source-button-label--channels\": \"चैनल्स\",\n  \"search-results-header-filter-source-button-label--messages\": \"संदेश\",\n  \"search-results-header-filter-source-button-label--users\": \"उपयोगकर्ता\",\n  \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }} खोज रहे हैं...\",\n  \"Searching...\": \"खोज कर...\",\n  \"searchResultsCount_one\": \"1 परिणाम\",\n  \"searchResultsCount_other\": \"{{ count }} परिणाम\",\n  \"Select a thread to continue the conversation\": \"बातचीत जारी रखने के लिए एक थ्रेड चुनें\",\n  \"Select more than one option\": \"एक से अधिक विकल्प चुनें\",\n  \"Select one\": \"एक चुनें\",\n  \"Select one or more\": \"एक या अधिक चुनें\",\n  \"Select up to {{count}}_one\": \"अधिकतम {{count}} तक चुनें\",\n  \"Select up to {{count}}_other\": \"अधिकतम {{count}} तक चुनें\",\n  \"Select your current location and optionally enable live location sharing\": \"अपना वर्तमान स्थान चुनें और वैकल्पिक रूप से लाइव लोकेशन शेयरिंग सक्षम करें\",\n  \"Send\": \"भेजे\",\n  \"Send a message\": \"संदेश भेजें\",\n  \"Send a message to start the conversation\": \"बातचीत शुरू करने के लिए संदेश भेजें\",\n  \"Send Anyway\": \"वैसे भी भेजें\",\n  \"Send message request failed\": \"संदेश भेजने का अनुरोध विफल रहा\",\n  \"Send poll\": \"पोल भेजें\",\n  \"Sending...\": \"भेजा जा रहा है\",\n  \"Sent\": \"भेजा गया\",\n  \"Share\": \"साझा करें\",\n  \"Share live location for\": \"लाइव स्थान साझा करें\",\n  \"Share Location\": \"स्थान साझा करें\",\n  \"Shared live location\": \"साझा किया गया लाइव स्थान\",\n  \"Shared location\": \"साझा स्थान\",\n  \"Shuffle\": \"मिश्रित करें\",\n  \"size limit\": \"आकार सीमा\",\n  \"Slow Mode ON\": \"स्लो मोड ऑन\",\n  \"Slow mode, wait {{ seconds }}s...\": \"स्लो मोड, {{ seconds }} सेकंड प्रतीक्षा करें...\",\n  \"Some of the files will not be accepted\": \"कुछ फ़ाइलें स्वीकार नहीं की जाएंगी\",\n  \"Start typing to search\": \"खोजने के लिए टाइप करना शुरू करें\",\n  \"Stop sharing\": \"साझा करना बंद करें\",\n  \"Submit\": \"जमा करें\",\n  \"Suggest a new option to add to this poll\": \"इस पोल में जोड़ने के लिए एक नया विकल्प सुझाएं\",\n  \"Suggest an option\": \"एक विकल्प सुझाव दें\",\n  \"Tap to remove\": \"हटाने के लिए टैप करें\",\n  \"Tap to remove: {{ reactionName }}\": \"हटाने के लिए टैप करें: {{ reactionName }}\",\n  \"Thinking...\": \"सोच रहा है...\",\n  \"this content could not be displayed\": \"यह कॉन्टेंट लोड नहीं हो पाया\",\n  \"This field cannot be empty or contain only spaces\": \"यह फ़ील्ड खाली नहीं हो सकता या केवल रिक्त स्थान नहीं रख सकता\",\n  \"This message did not meet our content guidelines\": \"यह संदेश हमारे सामग्री दिशानिर्देशों के अनुरूप नहीं था\",\n  \"Thread\": \"रिप्लाई थ्रेड\",\n  \"Thread has not been found\": \"थ्रेड नहीं मिला\",\n  \"Thread reply\": \"थ्रेड में उत्तर\",\n  \"Thread Reply\": \"थ्रेड में उत्तर\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"लोड हो रहा है...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} अपठित थ्रेड\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} अपठित थ्रेड\",\n  \"Threads\": \"थ्रेड्स\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[बीता कल]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[आज]\\\", \\\"nextDay\\\": \\\"[कल]\\\", \\\"lastDay\\\": \\\"[बीता कल]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[पिछला] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"आज\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"बीता कल\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"रिकॉर्डिंग शुरू करने के लिए, अपने ब्राउज़र में कैमरा तक पहुँच दें\",\n  \"To start recording, allow the microphone access in your browser\": \"रिकॉर्डिंग शुरू करने के लिए, अपने ब्राउज़र में माइक्रोफ़ोन तक पहुँच दें\",\n  \"totalVoteCount_one\": \"कुल 1 वोट\",\n  \"totalVoteCount_other\": \"कुल {{ count }} वोट\",\n  \"Translated\": \"अनुवादित\",\n  \"Translated from {{ language }}\": \"{{ language }} से अनुवादित\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"2 से 10 तक का एक नंबर टाइप करें\",\n  \"Unarchive\": \"अनआर्काइव\",\n  \"unban-command-args\": \"[@उपयोगकर्तनाम]\",\n  \"unban-command-description\": \"एक उपयोगकर्ता को प्रतिषेध से मुक्त करें\",\n  \"Unblock User\": \"उपयोगकर्ता अनब्लॉक करें\",\n  \"unknown error\": \"अज्ञात त्रुटि\",\n  \"Unmute\": \"अनम्यूट\",\n  \"unmute-command-args\": \"[@उपयोगकर्तनाम]\",\n  \"unmute-command-description\": \"एक उपयोगकर्ता को अनम्यूट करें\",\n  \"Unpin\": \"अनपिन\",\n  \"Unread messages\": \"अपठित संदेश\",\n  \"Unsupported attachment\": \"असमर्थित अटैचमेंट\",\n  \"unsupported file type\": \"असमर्थित फ़ाइल प्रकार\",\n  \"Update\": \"अपडेट करें\",\n  \"Update the comment attached to your poll answer\": \"अपने पोल उत्तर से जुड़ी टिप्पणी अपडेट करें\",\n  \"Update your comment\": \"अपने टिप्पणी को अपडेट करें\",\n  \"Upload blocked\": \"अपलोड अवरुद्ध\",\n  \"Upload error\": \"अपलोड त्रुटि\",\n  \"Upload failed\": \"अपलोड विफल\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"अपलोड प्रकार: \\\"{{ type }}\\\" की अनुमति नहीं है\",\n  \"User blocked\": \"उपयोगकर्ता अवरुद्ध किया गया\",\n  \"User unblocked\": \"उपयोगकर्ता अनब्लॉक किया गया\",\n  \"User uploaded content\": \"उपयोगकर्ता अपलोड की गई सामग्री\",\n  \"Video\": \"वीडियो\",\n  \"videoCount_one\": \"1 वीडियो\",\n  \"videoCount_other\": \"{{ count }} वीडियो\",\n  \"View\": \"देखें\",\n  \"View {{count}} comments_one\": \"देखें {{count}} टिप्पणी\",\n  \"View {{count}} comments_other\": \"देखें {{count}} टिप्पणियाँ\",\n  \"View all\": \"सभी देखें\",\n  \"View original\": \"मूल देखें\",\n  \"View results\": \"परिणाम देखें\",\n  \"View translation\": \"अनुवाद देखें\",\n  \"Voice message\": \"आवाज संदेश\",\n  \"Voice message {{ duration }}\": \"वॉइस संदेश {{ duration }}\",\n  \"Voice message deleted\": \"वॉइस संदेश हटा दिया गया\",\n  \"voiceMessageCount_one\": \"1 ध्वनि संदेश\",\n  \"voiceMessageCount_other\": \"{{ count }} ध्वनि संदेश\",\n  \"Vote ended\": \"मतदान समाप्त\",\n  \"Votes\": \"वोट\",\n  \"Wait until all attachments have uploaded\": \"सभी अटैचमेंट अपलोड होने तक प्रतीक्षा करें\",\n  \"Waiting for network…\": \"नेटवर्क की प्रतीक्षा…\",\n  \"You\": \"आप\",\n  \"You've reached the maximum number of files\": \"आप अधिकतम फ़ाइलों तक पहुँच गए हैं\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} e altri {{ moreCount }}\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} e {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} file\",\n  \"{{ count }} files_many\": \"{{ count }} file\",\n  \"{{ count }} files_other\": \"{{ count }} file\",\n  \"{{ count }} people are typing_one\": \"{{ count }} persona sta scrivendo\",\n  \"{{ count }} people are typing_many\": \"{{ count }} persone stanno scrivendo\",\n  \"{{ count }} people are typing_other\": \"{{ count }} persone stanno scrivendo\",\n  \"{{ count }} photos_one\": \"{{ count }} foto\",\n  \"{{ count }} photos_many\": \"{{ count }} foto\",\n  \"{{ count }} photos_other\": \"{{ count }} foto\",\n  \"{{ count }} reactions_one\": \"{{ count }} reazione\",\n  \"{{ count }} reactions_many\": \"{{ count }} reazioni\",\n  \"{{ count }} reactions_other\": \"{{ count }} reazioni\",\n  \"{{ count }} videos_one\": \"{{ count }} video\",\n  \"{{ count }} videos_many\": \"{{ count }} video\",\n  \"{{ count }} videos_other\": \"{{ count }} video\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} e {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"+ {{ imageCount }}\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} membri\",\n  \"{{ typing }} are typing\": \"{{ typing }} stanno scrivendo\",\n  \"{{ typing }} is typing\": \"{{ typing }} sta scrivendo\",\n  \"{{ user }} has been muted\": \"{{ user }} è stato silenziato\",\n  \"{{ user }} has been unmuted\": \"Notifiche riattivate per {{ user }}\",\n  \"{{ user }} is typing...\": \"{{ user }} sta digitando...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} e {{ user }} stanno digitando...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} e altri stanno digitando...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n  \"{{count}} new messages_one\": \"{{count}} nuovo messaggio\",\n  \"{{count}} new messages_many\": \"{{count}} nuovi messaggi\",\n  \"{{count}} new messages_other\": \"{{count}} nuovi messaggi\",\n  \"{{count}} unread_one\": \"{{count}} non letto\",\n  \"{{count}} unread_many\": \"{{count}} non letti\",\n  \"{{count}} unread_other\": \"{{count}} non letti\",\n  \"{{count}} votes_one\": \"{{count}} voto\",\n  \"{{count}} votes_many\": \"{{count}} voti\",\n  \"{{count}} votes_other\": \"{{count}} voti\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} altra opzione\",\n  \"+{{count}} more options_many\": \"+{{count}} altre opzioni\",\n  \"+{{count}} more options_other\": \"+{{count}} altre opzioni\",\n  \"🏙 Attachment...\": \"🏙 Allegato...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} ha creato: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} ha votato: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Posizione condivisa\",\n  \"Add a comment\": \"Aggiungi un commento\",\n  \"Add a comment to your poll answer\": \"Aggiungi un commento alla tua risposta al sondaggio\",\n  \"Add an option\": \"Aggiungi un'opzione\",\n  \"Add reaction\": \"Aggiungi reazione\",\n  \"All results loaded\": \"Tutti i risultati caricati\",\n  \"Allow access to camera\": \"Consenti l'accesso alla fotocamera\",\n  \"Allow access to microphone\": \"Consenti l'accesso al microfono\",\n  \"Allow comments\": \"Consenti i commenti\",\n  \"Allow option suggestion\": \"Consenti il suggerimento di opzioni\",\n  \"Allow others to add comments\": \"Consenti ad altri di aggiungere commenti\",\n  \"Also send as a direct message\": \"Invia anche come messaggio diretto\",\n  \"Also send in channel\": \"Invia anche nel canale\",\n  \"Also sent in channel\": \"Inviato anche nel canale\",\n  \"An error has occurred during recording\": \"Si è verificato un errore durante la registrazione\",\n  \"An error has occurred during the recording processing\": \"Si è verificato un errore durante l'elaborazione della registrazione\",\n  \"Anonymous\": \"Anonimo\",\n  \"Anonymous poll\": \"Sondaggio anonimo\",\n  \"Archive\": \"Archivia\",\n  \"Are you sure you want to delete this message?\": \"Sei sicuro di voler eliminare questo messaggio?\",\n  \"aria/Attachment\": \"Allegato\",\n  \"aria/Attachment Actions\": \"Azioni allegato\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Posizione audio {{ elapsed }} di {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Posizione audio {{ progress }} percento\",\n  \"aria/Block User\": \"Blocca utente\",\n  \"aria/Bookmark Message\": \"Salva messaggio\",\n  \"aria/Cancel recording\": \"Annulla registrazione\",\n  \"aria/Cancel Reply\": \"Annulla risposta\",\n  \"aria/Cancel upload\": \"Annulla caricamento\",\n  \"aria/Channel Actions\": \"Azioni canale\",\n  \"aria/Channel list\": \"Elenco dei canali\",\n  \"aria/Channel search results\": \"Risultati della ricerca dei canali\",\n  \"aria/Chat view tabs\": \"Schede visualizzazione chat\",\n  \"aria/Clear search\": \"Cancella ricerca\",\n  \"aria/Close callout dialog\": \"Chiudi finestra informativa\",\n  \"aria/Close thread\": \"Chiudi discussione\",\n  \"aria/Collapse sidebar\": \"Comprimi barra laterale\",\n  \"aria/Command Suggestions\": \"Suggerimenti comandi\",\n  \"aria/Complete recording\": \"Completa registrazione\",\n  \"aria/Copy Message Text\": \"Copia testo messaggio\",\n  \"aria/Decrease value\": \"Diminuisci valore\",\n  \"aria/Delete Message\": \"Elimina messaggio\",\n  \"aria/Dismiss notification\": \"Chiudi notifica\",\n  \"aria/Download attachment\": \"Scarica l'allegato\",\n  \"aria/Edit Message\": \"Modifica messaggio\",\n  \"aria/Emoji picker\": \"Selettore di emoji\",\n  \"aria/Emoji Suggestions\": \"Suggerimenti emoji\",\n  \"aria/Exit search\": \"Esci dalla ricerca\",\n  \"aria/Expand sidebar\": \"Espandi barra laterale\",\n  \"aria/File input\": \"Input di file\",\n  \"aria/File upload\": \"Caricamento di file\",\n  \"aria/Flag Message\": \"Segnala messaggio\",\n  \"aria/Image failed to load\": \"Caricamento immagine non riuscito\",\n  \"aria/Image input\": \"Input di immagine\",\n  \"aria/Increase value\": \"Aumenta valore\",\n  \"aria/Jump to latest message\": \"Vai all'ultimo messaggio\",\n  \"aria/Jump to quoted message\": \"Vai al messaggio citato\",\n  \"aria/Load More Channels\": \"Carica altri canali\",\n  \"aria/Mark Message Unread\": \"Contrassegna come non letto\",\n  \"aria/Mark messages as read\": \"Segna i messaggi come letti\",\n  \"aria/Menu\": \"Menu\",\n  \"aria/Message Actions\": \"Azioni del messaggio\",\n  \"aria/Message from {{ user }},\": \"Messaggio di {{ user }},\",\n  \"aria/Message Options\": \"Opzioni di messaggio\",\n  \"aria/Message,\": \"Messaggio,\",\n  \"aria/Mute User\": \"Mute utente\",\n  \"aria/Notifications\": \"Notifiche\",\n  \"aria/Open Attachment Selector\": \"Apri selettore allegati\",\n  \"aria/Open Channel Actions Menu\": \"Apri menu azioni canale\",\n  \"aria/Open Menu\": \"Apri menu\",\n  \"aria/Open Message Actions Menu\": \"Apri il menu delle azioni di messaggio\",\n  \"aria/Open Reaction Selector\": \"Apri il selettore di reazione\",\n  \"aria/Open Thread\": \"Apri discussione\",\n  \"aria/Pause\": \"Pausa\",\n  \"aria/Pause recording\": \"Metti in pausa registrazione\",\n  \"aria/Percent complete\": \"{{percent}} percento completato\",\n  \"aria/Pin Message\": \"Appunta messaggio\",\n  \"aria/Play\": \"Riproduci\",\n  \"aria/Quote Message\": \"Citazione messaggio\",\n  \"aria/Reaction list\": \"Elenco delle reazioni\",\n  \"aria/Remind Me Message\": \"Ricordami\",\n  \"aria/Remind Me Options\": \"Opzioni promemoria\",\n  \"aria/Remove attachment\": \"Rimuovi allegato\",\n  \"aria/Remove location attachment\": \"Rimuovi allegato posizione\",\n  \"aria/Remove option\": \"Rimuovi opzione\",\n  \"aria/Remove Reminder\": \"Rimuovi promemoria\",\n  \"aria/Remove Save For Later\": \"Rimuovi Salva per dopo\",\n  \"aria/Resend Message\": \"Invia di nuovo messaggio\",\n  \"aria/Resume recording\": \"Riprendi registrazione\",\n  \"aria/Retry upload\": \"Riprova caricamento\",\n  \"aria/Review bounced message\": \"Rivedi il messaggio respinto\",\n  \"aria/Search results\": \"Risultati della ricerca\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Pulsante filtro intestazione risultati di ricerca per: {{ source }}\",\n  \"aria/Seek audio position\": \"Cerca posizione audio\",\n  \"aria/Select Channel: {{ channelName }}\": \"Seleziona canale: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Seleziona reazione: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Seleziona canale utente: {{ name }}\",\n  \"aria/Send\": \"Invia\",\n  \"aria/Show preview\": \"Mostra anteprima\",\n  \"aria/Start recording audio\": \"Avvia registrazione audio\",\n  \"aria/Stop AI Generation\": \"Interrompi generazione IA\",\n  \"aria/Suggestions\": \"Suggerimenti\",\n  \"aria/Thread list\": \"Elenco thread\",\n  \"aria/Unblock User\": \"Sblocca utente\",\n  \"aria/Unmute User\": \"Riattiva il notifiche\",\n  \"aria/Unpin Message\": \"Rimuovi messaggio appuntato\",\n  \"aria/User Suggestions\": \"Suggerimenti utenti\",\n  \"Ask a question\": \"Fai una domanda\",\n  \"Attach\": \"Allega\",\n  \"Attach files\": \"Allega file\",\n  \"Attachment\": \"Allegato\",\n  \"Attachment upload blocked due to {{reason}}\": \"Caricamento allegato bloccato a causa di {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Caricamento allegato fallito a causa di {{reason}}\",\n  \"Back\": \"Indietro\",\n  \"ban-command-args\": \"[@nomeutente] [testo]\",\n  \"ban-command-description\": \"Vietare un utente\",\n  \"Block User\": \"Blocca utente\",\n  \"Cancel\": \"Annulla\",\n  \"Cannot seek in the recording\": \"Impossibile cercare nella registrazione\",\n  \"Channel archived\": \"Canale archiviato\",\n  \"Channel Missing\": \"Il canale non esiste\",\n  \"Channel muted\": \"Canale silenziato\",\n  \"Channel pinned\": \"Canale fissato\",\n  \"Channel unarchived\": \"Archiviazione del canale annullata\",\n  \"Channel unmuted\": \"Canale non più silenziato\",\n  \"Channel unpinned\": \"Canale rimosso dai fissati\",\n  \"Channels\": \"Canali\",\n  \"Chats\": \"Chat\",\n  \"Choose between 2 to 10 options\": \"Scegli tra 2 e 10 opzioni\",\n  \"Close\": \"Chiudi\",\n  \"Close dialog\": \"Chiudi finestra di dialogo\",\n  \"Close emoji picker\": \"Chiudi il selettore di emoji\",\n  \"Close prompt: {{ title }}\": \"Chiudi prompt: {{ title }}\",\n  \"Command not available while editing\": \"Comando non disponibile durante la modifica\",\n  \"Command not available while replying\": \"Comando non disponibile durante la risposta\",\n  \"Commands\": \"Comandi\",\n  \"Commands matching\": \"Comandi corrispondenti\",\n  \"Connection failure, reconnecting now...\": \"Errore di connessione, riconnessione in corso...\",\n  \"Copy Message\": \"Copia messaggio\",\n  \"Create\": \"Crea\",\n  \"Create a question, add options, and configure poll settings\": \"Crea una domanda, aggiungi opzioni e configura le impostazioni del sondaggio\",\n  \"Create poll\": \"Crea sondaggio\",\n  \"Current location\": \"Posizione attuale\",\n  \"Delete\": \"Elimina\",\n  \"Delete for me\": \"Elimina per me\",\n  \"Delete message\": \"Elimina messaggio\",\n  \"Delivered\": \"Consegnato\",\n  \"Direct message\": \"Messaggio diretto\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Vuoi terminare questo sondaggio ora? Nessuno potrà più votare in questo sondaggio.\",\n  \"Download All\": \"Scarica tutto\",\n  \"Download Attachment\": \"Scarica allegato\",\n  \"Download attachment {{ name }}\": \"Scarica l'allegato {{ name }}\",\n  \"Drag your files here\": \"Trascina i tuoi file qui\",\n  \"Drag your files here to add to your post\": \"Trascina i tuoi file qui per aggiungerli al tuo post\",\n  \"Due {{ timeLeft }}\": \"Scadenza tra {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Scaduto dal {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Modifica messaggio\",\n  \"Edit message request failed\": \"Richiesta di modifica del messaggio non riuscita\",\n  \"Edited\": \"Modificato\",\n  \"Emoji matching\": \"Abbinamento emoji\",\n  \"Empty message...\": \"Messaggio vuoto...\",\n  \"End\": \"Fine\",\n  \"End poll\": \"Termina sondaggio\",\n  \"End this poll?\": \"Terminare questo sondaggio?\",\n  \"End vote\": \"Termina il voto\",\n  \"Enforce unique vote is enabled\": \"Il voto unico è abilitato\",\n  \"Error\": \"Errore\",\n  \"Error adding flag\": \"Errore durante l'aggiunta del flag\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Errore di connessione alla chat, aggiorna la pagina per riprovare.\",\n  \"Error deleting message\": \"Errore durante l'eliminazione del messaggio\",\n  \"Error fetching reactions\": \"Errore nel caricamento delle reazioni\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Errore durante la marcatura del messaggio come non letto. Impossibile marcare messaggi non letti più vecchi dei più recenti 100 messaggi del canale.\",\n  \"Error muting a user ...\": \"Errore nel silenziare un utente ...\",\n  \"Error pinning message\": \"Errore durante il blocco del messaggio\",\n  \"Error removing message pin\": \"Errore durante la rimozione del PIN del messaggio\",\n  \"Error reproducing the recording\": \"Errore durante la riproduzione della registrazione\",\n  \"Error starting recording\": \"Errore durante l'avvio della registrazione\",\n  \"Error unmuting a user ...\": \"Errore nel riattivare un utente ...\",\n  \"Error uploading attachment\": \"Errore durante il caricamento dell'allegato\",\n  \"Error uploading file\": \"Errore durante il caricamento del file\",\n  \"Error uploading image\": \"Errore durante il caricamento dell'immagine\",\n  \"Error: {{ errorMessage }}\": \"Errore: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Esci dal comando {{ command }}\",\n  \"Failed to block user\": \"Impossibile bloccare l'utente\",\n  \"Failed to create the poll\": \"Impossibile creare il sondaggio\",\n  \"Failed to create the poll due to {{reason}}\": \"Impossibile creare il sondaggio a causa di {{reason}}\",\n  \"Failed to delete the message\": \"Impossibile eliminare il messaggio\",\n  \"Failed to end the poll\": \"Impossibile terminare il sondaggio\",\n  \"Failed to end the poll due to {{reason}}\": \"Impossibile terminare il sondaggio a causa di {{reason}}\",\n  \"Failed to jump to the first unread message\": \"Impossibile passare al primo messaggio non letto\",\n  \"Failed to leave channel\": \"Impossibile lasciare il canale\",\n  \"Failed to load channels\": \"Impossibile caricare i canali\",\n  \"Failed to load more channels\": \"Impossibile caricare altri canali\",\n  \"Failed to mark channel as read\": \"Impossibile contrassegnare il canale come letto\",\n  \"Failed to play the recording\": \"Impossibile riprodurre la registrazione\",\n  \"Failed to retrieve location\": \"Impossibile recuperare la posizione\",\n  \"Failed to share location\": \"Impossibile condividere la posizione\",\n  \"Failed to update channel archive status\": \"Impossibile aggiornare lo stato di archiviazione del canale\",\n  \"Failed to update channel mute status\": \"Impossibile aggiornare lo stato di silenziamento del canale\",\n  \"Failed to update channel pinned status\": \"Impossibile aggiornare lo stato di blocco del canale\",\n  \"File\": \"File\",\n  \"File is required for upload attachment\": \"È richiesto un file per caricare l'allegato\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Il file è troppo grande: {{ size }}, la dimensione massima di caricamento è {{ limit }}\",\n  \"File too large\": \"File troppo grande\",\n  \"fileCount_one\": \"1 file\",\n  \"fileCount_many\": \"{{ count }} file\",\n  \"fileCount_other\": \"{{ count }} file\",\n  \"Flag\": \"Segnala\",\n  \"Generating...\": \"Generando...\",\n  \"giphy-command-args\": \"[testo]\",\n  \"giphy-command-description\": \"Pubblica un gif casuale sul canale\",\n  \"Hide who voted\": \"Nascondi chi ha votato\",\n  \"Image\": \"Immagine\",\n  \"imageCount_one\": \"Immagine\",\n  \"imageCount_many\": \"{{ count }} immagini\",\n  \"imageCount_other\": \"{{ count }} immagini\",\n  \"Instant commands\": \"Comandi istantanei\",\n  \"language/af\": \"Afrikaans\",\n  \"language/am\": \"Amarico\",\n  \"language/ar\": \"Arabo\",\n  \"language/az\": \"Azero\",\n  \"language/bg\": \"Bulgaro\",\n  \"language/bn\": \"Bengalese\",\n  \"language/bs\": \"Bosniaco\",\n  \"language/cs\": \"Ceco\",\n  \"language/da\": \"Danese\",\n  \"language/de\": \"Tedesco\",\n  \"language/el\": \"Greco\",\n  \"language/en\": \"Inglese\",\n  \"language/es\": \"Spagnolo\",\n  \"language/es-MX\": \"Spagnolo (Messico)\",\n  \"language/et\": \"Estone\",\n  \"language/fa\": \"Persiano\",\n  \"language/fa-AF\": \"Dari\",\n  \"language/fi\": \"Finlandese\",\n  \"language/fr\": \"Francese\",\n  \"language/fr-CA\": \"Francese (Canada)\",\n  \"language/ha\": \"Hausa\",\n  \"language/he\": \"Ebraico\",\n  \"language/hi\": \"Hindi\",\n  \"language/hr\": \"Croato\",\n  \"language/ht\": \"Creolo haitiano\",\n  \"language/hu\": \"Ungherese\",\n  \"language/id\": \"Indonesiano\",\n  \"language/it\": \"Italiano\",\n  \"language/ja\": \"Giapponese\",\n  \"language/ka\": \"Georgiano\",\n  \"language/ko\": \"Coreano\",\n  \"language/lt\": \"Lituano\",\n  \"language/lv\": \"Lettone\",\n  \"language/ms\": \"Malese\",\n  \"language/nl\": \"Olandese\",\n  \"language/no\": \"Norvegese\",\n  \"language/pl\": \"Polacco\",\n  \"language/ps\": \"Pashto\",\n  \"language/pt\": \"Portoghese\",\n  \"language/ro\": \"Rumeno\",\n  \"language/ru\": \"Russo\",\n  \"language/sk\": \"Slovacco\",\n  \"language/sl\": \"Sloveno\",\n  \"language/so\": \"Somalo\",\n  \"language/sq\": \"Albanese\",\n  \"language/sr\": \"Serbo\",\n  \"language/sv\": \"Svedese\",\n  \"language/sw\": \"Swahili\",\n  \"language/ta\": \"Tamil\",\n  \"language/th\": \"Thai\",\n  \"language/tl\": \"Tagalog\",\n  \"language/tr\": \"Turco\",\n  \"language/uk\": \"Ucraino\",\n  \"language/ur\": \"Urdu\",\n  \"language/vi\": \"Vietnamita\",\n  \"language/zh\": \"Cinese (semplificato)\",\n  \"language/zh-TW\": \"Cinese (tradizionale)\",\n  \"Leave Channel\": \"Lascia il canale\",\n  \"Left channel\": \"Canale lasciato\",\n  \"Let others add options\": \"Lascia che altri aggiungano opzioni\",\n  \"Limit votes per person\": \"Limita i voti per persona\",\n  \"Link\": \"Collegamento\",\n  \"linkCount_one\": \"Link\",\n  \"linkCount_many\": \"{{ count }} link\",\n  \"linkCount_other\": \"{{ count }} link\",\n  \"live\": \"live\",\n  \"Live for {{duration}}\": \"Live per {{duration}}\",\n  \"Live location\": \"Posizione live\",\n  \"Live until {{ timestamp }}\": \"Live fino a {{ timestamp }}\",\n  \"Load more\": \"Carica di più\",\n  \"Local upload attachment missing local id\": \"Allegato di caricamento locale senza id locale\",\n  \"Location\": \"Posizione\",\n  \"Location sharing ended\": \"Condivisione posizione terminata\",\n  \"Location: {{ coordinates }}\": \"Posizione: {{ coordinates }}\",\n  \"Mark as unread\": \"Contrassegna come non letto\",\n  \"Maximum number of votes (from 2 to 10)\": \"Numero massimo di voti (da 2 a 10)\",\n  \"Maximum votes per person\": \"Voti massimi per persona\",\n  \"Menu\": \"Menù\",\n  \"Message deleted\": \"Messaggio cancellato\",\n  \"Message failed to send\": \"Invio del messaggio non riuscito\",\n  \"Message has been successfully flagged\": \"Il messaggio è stato segnalato con successo\",\n  \"Message marked as unread\": \"Messaggio contrassegnato come non letto\",\n  \"Message pinned\": \"Messaggio bloccato\",\n  \"Message unpinned\": \"Messaggio rimosso dai fissati\",\n  \"Message was blocked by moderation policies\": \"Il messaggio è stato bloccato dalle politiche di moderazione\",\n  \"Messages have been marked unread.\": \"I messaggi sono stati contrassegnati come non letti.\",\n  \"Missing permissions to upload the attachment\": \"Autorizzazioni mancanti per caricare l'allegato\",\n  \"Multiple votes\": \"Voti multipli\",\n  \"Mute\": \"Silenzia\",\n  \"mute-command-args\": \"[@nomeutente]\",\n  \"mute-command-description\": \"Silenzia un utente\",\n  \"network error\": \"errore di rete\",\n  \"New\": \"Nuovo\",\n  \"New message from {{user}}\": \"Nuovo messaggio da {{user}}\",\n  \"New Messages!\": \"Nuovi messaggi!\",\n  \"Next image\": \"Immagine successiva\",\n  \"No chats here yet…\": \"Non ci sono ancora messaggi qui...\",\n  \"No conversations yet\": \"Ancora nessuna conversazione\",\n  \"No items exist\": \"Nessun elemento presente\",\n  \"No results found\": \"Nessun risultato trovato\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Nessuno potrà più votare in questo sondaggio.\",\n  \"Nothing yet...\": \"Ancora niente...\",\n  \"Offline\": \"Offline\",\n  \"Ok\": \"OK\",\n  \"Online\": \"Online\",\n  \"Only numbers are allowed\": \"Sono consentiti solo numeri\",\n  \"Only visible to you\": \"Visibile solo per te\",\n  \"Open emoji picker\": \"Apri il selettore di emoji\",\n  \"Open gallery at image {{ index }}\": \"Apri la galleria all'immagine {{ index }}\",\n  \"Open image in gallery\": \"Apri immagine nella galleria\",\n  \"Open location in a map\": \"Apri posizione in una mappa\",\n  \"Option already exists\": \"L'opzione esiste già\",\n  \"Option is empty\": \"L'opzione è vuota\",\n  \"Options\": \"Opzioni\",\n  \"Original\": \"Originale\",\n  \"People matching\": \"Persone che corrispondono\",\n  \"Photo\": \"Foto\",\n  \"Pin\": \"Appunta\",\n  \"Pinned by {{ name }}\": \"Appuntato da {{ name }}\",\n  \"Pinned by You\": \"Fissato da te\",\n  \"placeholder/PollComment\": \"Il tuo commento\",\n  \"placeholder/PollOptionSuggestion\": \"Inserisci una nuova opzione\",\n  \"Play video\": \"Riproduci video\",\n  \"Playback speed {{ rate }}x\": \"Velocità di riproduzione {{ rate }}x\",\n  \"Poll\": \"Sondaggio\",\n  \"Poll comments\": \"Commenti del sondaggio\",\n  \"Poll ended\": \"Sondaggio terminato\",\n  \"Poll options\": \"Opzioni del sondaggio\",\n  \"Poll results\": \"Risultati del sondaggio\",\n  \"Previous image\": \"Immagine precedente\",\n  \"Question\": \"Domanda\",\n  \"Question {{ optionOrderNumber}}\": \"Domanda {{ optionOrderNumber}}\",\n  \"Question is required\": \"La domanda è obbligatoria\",\n  \"Quote Reply\": \"Rispondi con citazione\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Raggiunto il limite di voti. Rimuovi prima un voto esistente.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Il formato di registrazione non è supportato e non può essere riprodotto\",\n  \"Remind me\": \"Promemoria\",\n  \"Remind Me\": \"Ricordami\",\n  \"Reminder set\": \"Promemoria impostato\",\n  \"Remove reminder\": \"Rimuovi promemoria\",\n  \"Remove save for later\": \"Rimuovi Salva per dopo\",\n  \"Replied to a thread\": \"Ha risposto in un thread\",\n  \"Reply\": \"Rispondi\",\n  \"Reply to {{ authorName }}\": \"Rispondi a {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Rispondi a un messaggio per avviare un thread\",\n  \"Reply to Message\": \"Rispondi al messaggio\",\n  \"replyCount_one\": \"Una risposta\",\n  \"replyCount_many\": \"{{ count }} risposte\",\n  \"replyCount_other\": \"{{ count }} risposte\",\n  \"Resend\": \"Invia di nuovo\",\n  \"Retry upload\": \"Riprova caricamento\",\n  \"Review all options available in this poll\": \"Rivedi tutte le opzioni disponibili in questo sondaggio\",\n  \"Review comments submitted with poll answers\": \"Rivedi i commenti inviati con le risposte al sondaggio\",\n  \"Review poll results and open an option to see detailed votes\": \"Rivedi i risultati del sondaggio e apri un'opzione per vedere i voti dettagliati\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Rivedi questo messaggio e scegli se eliminarlo, modificarlo o inviarlo comunque\",\n  \"Review who voted for this option\": \"Rivedi chi ha votato per questa opzione\",\n  \"Save for later\": \"Salva per dopo\",\n  \"Saved for later\": \"Salvato per dopo\",\n  \"Search\": \"Cerca\",\n  \"Search GIFs\": \"Cerca GIF\",\n  \"search-results-header-filter-source-button-label--channels\": \"canali\",\n  \"search-results-header-filter-source-button-label--messages\": \"messaggi\",\n  \"search-results-header-filter-source-button-label--users\": \"utenti\",\n  \"Searching for {{ searchSourceType }}...\": \"Ricerca di {{ searchSourceType }}...\",\n  \"Searching...\": \"Ricerca in corso...\",\n  \"searchResultsCount_one\": \"1 risultato\",\n  \"searchResultsCount_many\": \"{{ count }} risultati\",\n  \"searchResultsCount_other\": \"{{ count }} risultati\",\n  \"Select a thread to continue the conversation\": \"Seleziona un thread per continuare la conversazione\",\n  \"Select more than one option\": \"Seleziona più di un'opzione\",\n  \"Select one\": \"Seleziona uno\",\n  \"Select one or more\": \"Seleziona uno o più\",\n  \"Select up to {{count}}_one\": \"Seleziona fino a {{count}}\",\n  \"Select up to {{count}}_many\": \"Seleziona fino a {{count}}\",\n  \"Select up to {{count}}_other\": \"Seleziona fino a {{count}}\",\n  \"Select your current location and optionally enable live location sharing\": \"Seleziona la tua posizione attuale e abilita facoltativamente la condivisione della posizione in tempo reale\",\n  \"Send\": \"Invia\",\n  \"Send a message\": \"Invia un messaggio\",\n  \"Send a message to start the conversation\": \"Invia un messaggio per iniziare la conversazione\",\n  \"Send Anyway\": \"Invia comunque\",\n  \"Send message request failed\": \"Richiesta di invio messaggio non riuscita\",\n  \"Send poll\": \"Invia sondaggio\",\n  \"Sending...\": \"Invio in corso...\",\n  \"Sent\": \"Inviato\",\n  \"Share\": \"Condividi\",\n  \"Share live location for\": \"Condividi posizione live per\",\n  \"Share Location\": \"Condividi posizione\",\n  \"Shared live location\": \"Posizione live condivisa\",\n  \"Shared location\": \"Posizione condivisa\",\n  \"Shuffle\": \"Mescolare\",\n  \"size limit\": \"limite di dimensione\",\n  \"Slow Mode ON\": \"Modalità lenta attivata\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Modalità lenta, attendi {{ seconds }} s...\",\n  \"Some of the files will not be accepted\": \"Alcuni dei file non saranno accettati\",\n  \"Start typing to search\": \"Inizia a digitare per cercare\",\n  \"Stop sharing\": \"Ferma condivisione\",\n  \"Submit\": \"Invia\",\n  \"Suggest a new option to add to this poll\": \"Suggerisci una nuova opzione da aggiungere a questo sondaggio\",\n  \"Suggest an option\": \"Suggerisci un'opzione\",\n  \"Tap to remove\": \"Tocca per rimuovere\",\n  \"Tap to remove: {{ reactionName }}\": \"Tocca per rimuovere: {{ reactionName }}\",\n  \"Thinking...\": \"Pensando...\",\n  \"this content could not be displayed\": \"questo contenuto non può essere mostrato\",\n  \"This field cannot be empty or contain only spaces\": \"Questo campo non può essere vuoto o contenere solo spazi\",\n  \"This message did not meet our content guidelines\": \"Questo messaggio non soddisfa le nostre linee guida sui contenuti\",\n  \"Thread\": \"Discussione\",\n  \"Thread has not been found\": \"Discussione non trovata\",\n  \"Thread reply\": \"Risposta nella discussione\",\n  \"Thread Reply\": \"Risposta nella discussione\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Caricamento...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} thread non letto\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} thread non letti\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} thread non letti\",\n  \"Threads\": \"Thread\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Ieri]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Oggi]\\\", \\\"nextDay\\\": \\\"[Domani]\\\", \\\"lastDay\\\": \\\"[Ieri]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Scorsa] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Oggi\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Ieri\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Per iniziare a registrare, consenti l'accesso alla fotocamera nel tuo browser\",\n  \"To start recording, allow the microphone access in your browser\": \"Per iniziare a registrare, consenti l'accesso al microfono nel tuo browser\",\n  \"totalVoteCount_one\": \"1 voto in totale\",\n  \"totalVoteCount_many\": \"{{ count }} voti in totale\",\n  \"totalVoteCount_other\": \"{{ count }} voti in totale\",\n  \"Translated\": \"Tradotto\",\n  \"Translated from {{ language }}\": \"Tradotto da {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Digita un numero da 2 a 10\",\n  \"Unarchive\": \"Ripristina\",\n  \"unban-command-args\": \"[@nomeutente]\",\n  \"unban-command-description\": \"Togliere il divieto a un utente\",\n  \"Unblock User\": \"Sblocca utente\",\n  \"unknown error\": \"errore sconosciuto\",\n  \"Unmute\": \"Riattiva il notifiche\",\n  \"unmute-command-args\": \"[@nomeutente]\",\n  \"unmute-command-description\": \"Togliere il silenzio a un utente\",\n  \"Unpin\": \"Sblocca\",\n  \"Unread messages\": \"Messaggi non letti\",\n  \"Unsupported attachment\": \"Allegato non supportato\",\n  \"unsupported file type\": \"tipo di file non supportato\",\n  \"Update\": \"Aggiorna\",\n  \"Update the comment attached to your poll answer\": \"Aggiorna il commento allegato alla tua risposta al sondaggio\",\n  \"Update your comment\": \"Aggiorna il tuo commento\",\n  \"Upload blocked\": \"Caricamento bloccato\",\n  \"Upload error\": \"Errore di caricamento\",\n  \"Upload failed\": \"Caricamento non riuscito\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Tipo di caricamento: \\\"{{ type }}\\\" non è consentito\",\n  \"User blocked\": \"Utente bloccato\",\n  \"User unblocked\": \"Utente sbloccato\",\n  \"User uploaded content\": \"Contenuto caricato dall'utente\",\n  \"Video\": \"Video\",\n  \"videoCount_one\": \"Video\",\n  \"videoCount_many\": \"{{ count }} video\",\n  \"videoCount_other\": \"{{ count }} video\",\n  \"View\": \"Visualizza\",\n  \"View {{count}} comments_one\": \"Visualizza {{count}} commento\",\n  \"View {{count}} comments_many\": \"Visualizza {{count}} commenti\",\n  \"View {{count}} comments_other\": \"Visualizza {{count}} commenti\",\n  \"View all\": \"Visualizza tutto\",\n  \"View original\": \"Visualizza originale\",\n  \"View results\": \"Vedi risultati\",\n  \"View translation\": \"Visualizza traduzione\",\n  \"Voice message\": \"Messaggio vocale\",\n  \"Voice message {{ duration }}\": \"Messaggio vocale {{ duration }}\",\n  \"Voice message deleted\": \"Messaggio vocale eliminato\",\n  \"voiceMessageCount_one\": \"Messaggio vocale\",\n  \"voiceMessageCount_many\": \"{{ count }} messaggi vocali\",\n  \"voiceMessageCount_other\": \"{{ count }} messaggi vocali\",\n  \"Vote ended\": \"Voto terminato\",\n  \"Votes\": \"Voti\",\n  \"Wait until all attachments have uploaded\": \"Attendi il caricamento di tutti gli allegati\",\n  \"Waiting for network…\": \"In attesa della rete…\",\n  \"You\": \"Tu\",\n  \"You've reached the maximum number of files\": \"Hai raggiunto il numero massimo di file\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} と {{ moreCount }} 他人\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} と {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} ファイル\",\n  \"{{ count }} files_other\": \"{{ count }} ファイル\",\n  \"{{ count }} people are typing_one\": \"{{ count }}人が入力中です\",\n  \"{{ count }} people are typing_many\": \"{{ count }}人が入力中です\",\n  \"{{ count }} people are typing_other\": \"{{ count }}人が入力中です\",\n  \"{{ count }} photos_one\": \"{{ count }} 写真\",\n  \"{{ count }} photos_other\": \"{{ count }} 写真\",\n  \"{{ count }} reactions_other\": \"{{ count }}件のリアクション\",\n  \"{{ count }} videos_one\": \"{{ count }} 動画\",\n  \"{{ count }} videos_other\": \"{{ count }} 動画\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} と {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} イメージ\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} メンバー\",\n  \"{{ typing }} are typing\": \"{{ typing }}が入力中です\",\n  \"{{ typing }} is typing\": \"{{ typing }}が入力中です\",\n  \"{{ user }} has been muted\": \"{{ user }} 無音されています\",\n  \"{{ user }} has been unmuted\": \"{{ user }} 無音されていません\",\n  \"{{ user }} is typing...\": \"{{ user }} が入力中...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} と {{ user }} が入力中...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} とその他が入力中...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} オンライン\",\n  \"{{count}} new messages_one\": \"{{count}}件の新しいメッセージ\",\n  \"{{count}} new messages_other\": \"{{count}}件の新しいメッセージ\",\n  \"{{count}} unread_one\": \"{{count}} 未読\",\n  \"{{count}} unread_other\": \"{{count}} 未読\",\n  \"{{count}} votes_one\": \"{{count}} 票\",\n  \"{{count}} votes_other\": \"{{count}} 票\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"あと{{count}}件のオプション\",\n  \"+{{count}} more options_other\": \"あと{{count}}件のオプション\",\n  \"🏙 Attachment...\": \"🏙 アタッチメント...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} が作成: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} が投票: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍共有された位置情報\",\n  \"Add a comment\": \"コメントを追加\",\n  \"Add a comment to your poll answer\": \"投票回答にコメントを追加\",\n  \"Add an option\": \"オプションを追加\",\n  \"Add reaction\": \"リアクションを追加\",\n  \"All results loaded\": \"すべての結果が読み込まれました\",\n  \"Allow access to camera\": \"カメラへのアクセスを許可する\",\n  \"Allow access to microphone\": \"マイクロフォンへのアクセスを許可する\",\n  \"Allow comments\": \"コメントを許可\",\n  \"Allow option suggestion\": \"オプションの提案を許可\",\n  \"Allow others to add comments\": \"他の人にコメントを追加することを許可する\",\n  \"Also send as a direct message\": \"ダイレクトメッセージとしても送信\",\n  \"Also send in channel\": \"チャンネルにも送信\",\n  \"Also sent in channel\": \"チャンネルにも送信済み\",\n  \"An error has occurred during recording\": \"録音中にエラーが発生しました\",\n  \"An error has occurred during the recording processing\": \"録音処理中にエラーが発生しました\",\n  \"Anonymous\": \"匿名\",\n  \"Anonymous poll\": \"匿名投票\",\n  \"Archive\": \"アーカイブ\",\n  \"Are you sure you want to delete this message?\": \"このメッセージを削除してもよろしいですか？\",\n  \"aria/Attachment\": \"添付ファイル\",\n  \"aria/Attachment Actions\": \"添付ファイルの操作\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"音声位置 {{ elapsed }} / {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"音声位置 {{ progress }} パーセント\",\n  \"aria/Block User\": \"ユーザーをブロック\",\n  \"aria/Bookmark Message\": \"メッセージをブックマーク\",\n  \"aria/Cancel recording\": \"録音をキャンセル\",\n  \"aria/Cancel Reply\": \"返信をキャンセル\",\n  \"aria/Cancel upload\": \"アップロードをキャンセル\",\n  \"aria/Channel Actions\": \"チャンネル操作\",\n  \"aria/Channel list\": \"チャンネル一覧\",\n  \"aria/Channel search results\": \"チャンネル検索結果\",\n  \"aria/Chat view tabs\": \"チャットビューのタブ\",\n  \"aria/Clear search\": \"検索をクリア\",\n  \"aria/Close callout dialog\": \"吹き出しダイアログを閉じる\",\n  \"aria/Close thread\": \"スレッドを閉じる\",\n  \"aria/Collapse sidebar\": \"サイドバーを折りたたむ\",\n  \"aria/Command Suggestions\": \"コマンド候補\",\n  \"aria/Complete recording\": \"録音を完了\",\n  \"aria/Copy Message Text\": \"メッセージテキストをコピー\",\n  \"aria/Decrease value\": \"値を減らす\",\n  \"aria/Delete Message\": \"メッセージを削除\",\n  \"aria/Dismiss notification\": \"通知を閉じる\",\n  \"aria/Download attachment\": \"添付ファイルをダウンロード\",\n  \"aria/Edit Message\": \"メッセージを編集\",\n  \"aria/Emoji picker\": \"絵文字ピッカー\",\n  \"aria/Emoji Suggestions\": \"絵文字候補\",\n  \"aria/Exit search\": \"検索を終了\",\n  \"aria/Expand sidebar\": \"サイドバーを展開\",\n  \"aria/File input\": \"ファイル入力\",\n  \"aria/File upload\": \"ファイルアップロード\",\n  \"aria/Flag Message\": \"メッセージをフラグ\",\n  \"aria/Image failed to load\": \"画像の読み込みに失敗しました\",\n  \"aria/Image input\": \"画像入力\",\n  \"aria/Increase value\": \"値を増やす\",\n  \"aria/Jump to latest message\": \"最新のメッセージに移動\",\n  \"aria/Jump to quoted message\": \"引用されたメッセージに移動\",\n  \"aria/Load More Channels\": \"さらにチャンネルを読み込む\",\n  \"aria/Mark Message Unread\": \"未読としてマーク\",\n  \"aria/Mark messages as read\": \"メッセージを既読にする\",\n  \"aria/Menu\": \"メニュー\",\n  \"aria/Message Actions\": \"メッセージ操作\",\n  \"aria/Message from {{ user }},\": \"{{ user }}さんからのメッセージ,\",\n  \"aria/Message Options\": \"メッセージオプション\",\n  \"aria/Message,\": \"メッセージ,\",\n  \"aria/Mute User\": \"ユーザーをミュート\",\n  \"aria/Notifications\": \"通知\",\n  \"aria/Open Attachment Selector\": \"添付ファイル選択を開く\",\n  \"aria/Open Channel Actions Menu\": \"チャンネルアクションメニューを開く\",\n  \"aria/Open Menu\": \"メニューを開く\",\n  \"aria/Open Message Actions Menu\": \"メッセージアクションメニューを開く\",\n  \"aria/Open Reaction Selector\": \"リアクションセレクターを開く\",\n  \"aria/Open Thread\": \"スレッドを開く\",\n  \"aria/Pause\": \"一時停止\",\n  \"aria/Pause recording\": \"録音を一時停止\",\n  \"aria/Percent complete\": \"{{percent}}パーセント完了\",\n  \"aria/Pin Message\": \"メッセージをピン\",\n  \"aria/Play\": \"再生\",\n  \"aria/Quote Message\": \"メッセージを引用\",\n  \"aria/Reaction list\": \"リアクション一覧\",\n  \"aria/Remind Me Message\": \"リマインダー\",\n  \"aria/Remind Me Options\": \"リマインダーオプション\",\n  \"aria/Remove attachment\": \"添付ファイルを削除\",\n  \"aria/Remove location attachment\": \"位置情報の添付ファイルを削除\",\n  \"aria/Remove option\": \"オプションを削除\",\n  \"aria/Remove Reminder\": \"リマインダーを削除\",\n  \"aria/Remove Save For Later\": \"「後で見る」を削除\",\n  \"aria/Resend Message\": \"メッセージを再送信\",\n  \"aria/Resume recording\": \"録音を再開\",\n  \"aria/Retry upload\": \"アップロードを再試行\",\n  \"aria/Review bounced message\": \"バウンスされたメッセージを確認\",\n  \"aria/Search results\": \"検索結果\",\n  \"aria/Search results header filter button for: {{ source }}\": \"{{ source }} の検索結果ヘッダーのフィルターボタン\",\n  \"aria/Seek audio position\": \"音声位置をシーク\",\n  \"aria/Select Channel: {{ channelName }}\": \"チャンネルを選択: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"リアクションを選択: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"ユーザーチャンネルを選択: {{ name }}\",\n  \"aria/Send\": \"送信\",\n  \"aria/Show preview\": \"プレビューを表示\",\n  \"aria/Start recording audio\": \"音声録音を開始\",\n  \"aria/Stop AI Generation\": \"AI生成を停止\",\n  \"aria/Suggestions\": \"候補\",\n  \"aria/Thread list\": \"スレッド一覧\",\n  \"aria/Unblock User\": \"ユーザーのブロックを解除\",\n  \"aria/Unmute User\": \"無音を解除する\",\n  \"aria/Unpin Message\": \"ピンを解除\",\n  \"aria/User Suggestions\": \"ユーザー候補\",\n  \"Ask a question\": \"質問する\",\n  \"Attach\": \"添付\",\n  \"Attach files\": \"ファイルを添付する\",\n  \"Attachment\": \"添付ファイル\",\n  \"Attachment upload blocked due to {{reason}}\": \"{{reason}}のため添付ファイルのアップロードがブロックされました\",\n  \"Attachment upload failed due to {{reason}}\": \"{{reason}}のため添付ファイルのアップロードに失敗しました\",\n  \"Back\": \"戻る\",\n  \"ban-command-args\": \"[@ユーザ名] [テキスト]\",\n  \"ban-command-description\": \"ユーザーを禁止する\",\n  \"Block User\": \"ユーザーをブロック\",\n  \"Cancel\": \"キャンセル\",\n  \"Cannot seek in the recording\": \"録音中にシークできません\",\n  \"Channel archived\": \"チャンネルをアーカイブしました\",\n  \"Channel Missing\": \"チャネルがありません\",\n  \"Channel muted\": \"チャンネルをミュートしました\",\n  \"Channel pinned\": \"チャンネルをピン留めしました\",\n  \"Channel unarchived\": \"チャンネルのアーカイブを解除しました\",\n  \"Channel unmuted\": \"チャンネルのミュートを解除しました\",\n  \"Channel unpinned\": \"チャンネルのピン留めを解除しました\",\n  \"Channels\": \"チャンネル\",\n  \"Chats\": \"チャット\",\n  \"Choose between 2 to 10 options\": \"2〜10の選択肢から選ぶ\",\n  \"Close\": \"閉める\",\n  \"Close dialog\": \"ダイアログを閉じる\",\n  \"Close emoji picker\": \"絵文字ピッカーを閉める\",\n  \"Close prompt: {{ title }}\": \"プロンプトを閉じる: {{ title }}\",\n  \"Command not available while editing\": \"編集中はコマンドを使用できません\",\n  \"Command not available while replying\": \"返信中はコマンドを使用できません\",\n  \"Commands\": \"コマンド\",\n  \"Commands matching\": \"一致するコマンド\",\n  \"Connection failure, reconnecting now...\": \"接続が失敗しました。再接続中...\",\n  \"Copy Message\": \"メッセージをコピー\",\n  \"Create\": \"作成\",\n  \"Create a question, add options, and configure poll settings\": \"質問を作成し、選択肢を追加して投票設定を構成\",\n  \"Create poll\": \"投票を作成\",\n  \"Current location\": \"現在の位置\",\n  \"Delete\": \"消去\",\n  \"Delete for me\": \"自分用に削除\",\n  \"Delete message\": \"メッセージを削除\",\n  \"Delivered\": \"配信しました\",\n  \"Direct message\": \"ダイレクトメッセージ\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"このアンケートを今終了しますか？終了すると、誰も投票できなくなります。\",\n  \"Download All\": \"すべてダウンロード\",\n  \"Download Attachment\": \"添付ファイルをダウンロード\",\n  \"Download attachment {{ name }}\": \"添付ファイル {{ name }} をダウンロード\",\n  \"Drag your files here\": \"ここにファイルをドラッグ\",\n  \"Drag your files here to add to your post\": \"投稿に追加するためにここにファイルをドラッグ\",\n  \"Due {{ timeLeft }}\": \"{{ timeLeft }}に期限切れ\",\n  \"Due since {{ dueSince }}\": \"{{ dueSince }}から期限切れ\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"メッセージを編集\",\n  \"Edit message request failed\": \"メッセージの編集要求が失敗しました\",\n  \"Edited\": \"編集済み\",\n  \"Emoji matching\": \"絵文字マッチング\",\n  \"Empty message...\": \"空のメッセージ...\",\n  \"End\": \"終了\",\n  \"End poll\": \"アンケートを終了\",\n  \"End this poll?\": \"このアンケートを終了しますか？\",\n  \"End vote\": \"投票を終了\",\n  \"Enforce unique vote is enabled\": \"一意の投票が有効になっています\",\n  \"Error\": \"エラー\",\n  \"Error adding flag\": \"フラグを追加のエラーが発生しました\",\n  \"Error connecting to chat, refresh the page to try again.\": \"チャットへの接続ができませんでした。ページを更新してください。\",\n  \"Error deleting message\": \"メッセージを削除するエラーが発生しました\",\n  \"Error fetching reactions\": \"反応の読み込みエラー\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"メッセージを未読にする際にエラーが発生しました。最新の100件のチャンネルメッセージより古い未読メッセージはマークできません。\",\n  \"Error muting a user ...\": \"ユーザーを無音するエラーが発生しました...\",\n  \"Error pinning message\": \"メッセージをピンのエラーが発生しました\",\n  \"Error removing message pin\": \"メッセージのピンを削除のエラーが発生しました\",\n  \"Error reproducing the recording\": \"録音の再生中にエラーが発生しました\",\n  \"Error starting recording\": \"録音の開始時にエラーが発生しました\",\n  \"Error unmuting a user ...\": \"ユーザーの無音解除のエラーが発生しました...\",\n  \"Error uploading attachment\": \"添付ファイルのアップロード中にエラーが発生しました\",\n  \"Error uploading file\": \"ファイルをアップロードのエラーが発生しました\",\n  \"Error uploading image\": \"画像をアップロードのエラーが発生しました\",\n  \"Error: {{ errorMessage }}\": \"エラー: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"コマンドを終了 {{ command }}\",\n  \"Failed to block user\": \"ユーザーのブロックに失敗しました\",\n  \"Failed to create the poll\": \"投票の作成に失敗しました\",\n  \"Failed to create the poll due to {{reason}}\": \"{{reason}} のため投票の作成に失敗しました\",\n  \"Failed to delete the message\": \"メッセージの削除に失敗しました\",\n  \"Failed to end the poll\": \"アンケートの終了に失敗しました\",\n  \"Failed to end the poll due to {{reason}}\": \"{{reason}}のためアンケートの終了に失敗しました\",\n  \"Failed to jump to the first unread message\": \"最初の未読メッセージにジャンプできませんでした\",\n  \"Failed to leave channel\": \"チャンネルの退出に失敗しました\",\n  \"Failed to load channels\": \"チャンネルの読み込みに失敗しました\",\n  \"Failed to load more channels\": \"さらにチャンネルを読み込めませんでした\",\n  \"Failed to mark channel as read\": \"チャンネルを既読にすることができませんでした\",\n  \"Failed to play the recording\": \"録音の再生に失敗しました\",\n  \"Failed to retrieve location\": \"位置情報の取得に失敗しました\",\n  \"Failed to share location\": \"位置情報の共有に失敗しました\",\n  \"Failed to update channel archive status\": \"チャンネルのアーカイブ状態の更新に失敗しました\",\n  \"Failed to update channel mute status\": \"チャンネルのミュート状態の更新に失敗しました\",\n  \"Failed to update channel pinned status\": \"チャンネルのピン状態の更新に失敗しました\",\n  \"File\": \"ファイル\",\n  \"File is required for upload attachment\": \"添付ファイルのアップロードにはファイルが必要です\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"ファイルが大きすぎます：{{ size }}、最大アップロードサイズは{{ limit }}です\",\n  \"File too large\": \"ファイルが大きすぎます\",\n  \"fileCount_other\": \"{{ count }}件のファイル\",\n  \"Flag\": \"フラグ\",\n  \"Generating...\": \"生成中...\",\n  \"giphy-command-args\": \"[テキスト]\",\n  \"giphy-command-description\": \"チャンネルにランダムなGIFを投稿する\",\n  \"Hide who voted\": \"誰が投票したかを非表示にする\",\n  \"Image\": \"画像\",\n  \"imageCount_other\": \"{{ count }}件の画像\",\n  \"Instant commands\": \"インスタントコマンド\",\n  \"language/af\": \"アフリカース語\",\n  \"language/am\": \"アムハラ語\",\n  \"language/ar\": \"アラビア語\",\n  \"language/az\": \"アゼルバイジャン語\",\n  \"language/bg\": \"ブルガリア語\",\n  \"language/bn\": \"ベンガル語\",\n  \"language/bs\": \"ボスニア語\",\n  \"language/cs\": \"チェコ語\",\n  \"language/da\": \"デンマーク語\",\n  \"language/de\": \"ドイツ語\",\n  \"language/el\": \"ギリシャ語\",\n  \"language/en\": \"英語\",\n  \"language/es\": \"スペイン語\",\n  \"language/es-MX\": \"スペイン語（メキシコ）\",\n  \"language/et\": \"エストニア語\",\n  \"language/fa\": \"ペルシア語\",\n  \"language/fa-AF\": \"ダリー語\",\n  \"language/fi\": \"フィンランド語\",\n  \"language/fr\": \"フランス語\",\n  \"language/fr-CA\": \"フランス語（カナダ）\",\n  \"language/ha\": \"ハウサ語\",\n  \"language/he\": \"ヘブライ語\",\n  \"language/hi\": \"ヒンディー語\",\n  \"language/hr\": \"クロアチア語\",\n  \"language/ht\": \"ハイチ・クレオール語\",\n  \"language/hu\": \"ハンガリー語\",\n  \"language/id\": \"インドネシア語\",\n  \"language/it\": \"イタリア語\",\n  \"language/ja\": \"日本語\",\n  \"language/ka\": \"グルジア語\",\n  \"language/ko\": \"韓国語\",\n  \"language/lt\": \"リトアニア語\",\n  \"language/lv\": \"ラトビア語\",\n  \"language/ms\": \"マレー語\",\n  \"language/nl\": \"オランダ語\",\n  \"language/no\": \"ノルウェー語\",\n  \"language/pl\": \"ポーランド語\",\n  \"language/ps\": \"パシュトー語\",\n  \"language/pt\": \"ポルトガル語\",\n  \"language/ro\": \"ルーマニア語\",\n  \"language/ru\": \"ロシア語\",\n  \"language/sk\": \"スロバキア語\",\n  \"language/sl\": \"スロベニア語\",\n  \"language/so\": \"ソマリ語\",\n  \"language/sq\": \"アルバニア語\",\n  \"language/sr\": \"セルビア語\",\n  \"language/sv\": \"スウェーデン語\",\n  \"language/sw\": \"スワヒリ語\",\n  \"language/ta\": \"タミル語\",\n  \"language/th\": \"タイ語\",\n  \"language/tl\": \"タガログ語\",\n  \"language/tr\": \"トルコ語\",\n  \"language/uk\": \"ウクライナ語\",\n  \"language/ur\": \"ウルドゥー語\",\n  \"language/vi\": \"ベトナム語\",\n  \"language/zh\": \"中国語（簡体字）\",\n  \"language/zh-TW\": \"中国語（繁体字）\",\n  \"Leave Channel\": \"チャンネルを退出\",\n  \"Left channel\": \"チャンネルを退出しました\",\n  \"Let others add options\": \"他の人が選択肢を追加できるようにする\",\n  \"Limit votes per person\": \"1人あたりの投票数を制限する\",\n  \"Link\": \"リンク\",\n  \"linkCount_other\": \"{{ count }}件のリンク\",\n  \"live\": \"ライブ\",\n  \"Live for {{duration}}\": \"{{duration}}間ライブ\",\n  \"Live location\": \"ライブ位置情報\",\n  \"Live until {{ timestamp }}\": \"{{ timestamp }}までライブ\",\n  \"Load more\": \"もっと読み込む\",\n  \"Local upload attachment missing local id\": \"ローカルアップロード添付にローカルIDがありません\",\n  \"Location\": \"位置情報\",\n  \"Location sharing ended\": \"位置情報の共有が終了しました\",\n  \"Location: {{ coordinates }}\": \"位置: {{ coordinates }}\",\n  \"Mark as unread\": \"未読としてマーク\",\n  \"Maximum number of votes (from 2 to 10)\": \"最大投票数（2から10まで）\",\n  \"Maximum votes per person\": \"1人あたりの最大投票数\",\n  \"Menu\": \"メニュー\",\n  \"Message deleted\": \"メッセージが削除されました\",\n  \"Message failed to send\": \"メッセージの送信に失敗しました\",\n  \"Message has been successfully flagged\": \"メッセージに正常にフラグが付けられました\",\n  \"Message marked as unread\": \"メッセージを未読にしました\",\n  \"Message pinned\": \"メッセージにピンが付けられました\",\n  \"Message unpinned\": \"メッセージのピン留めを解除しました\",\n  \"Message was blocked by moderation policies\": \"メッセージはモデレーションポリシーによってブロックされました\",\n  \"Messages have been marked unread.\": \"メッセージは未読としてマークされました。\",\n  \"Missing permissions to upload the attachment\": \"添付ファイルをアップロードするための許可がありません\",\n  \"Multiple votes\": \"複数投票\",\n  \"Mute\": \"無音\",\n  \"mute-command-args\": \"[@ユーザ名]\",\n  \"mute-command-description\": \"ユーザーをミュートする\",\n  \"network error\": \"ネットワークエラー\",\n  \"New\": \"新しい\",\n  \"New message from {{user}}\": \"{{user}}からの新しいメッセージ\",\n  \"New Messages!\": \"新しいメッセージ!\",\n  \"Next image\": \"次の画像\",\n  \"No chats here yet…\": \"ここにはまだチャットはありません…\",\n  \"No conversations yet\": \"まだ会話はありません\",\n  \"No items exist\": \"項目がありません\",\n  \"No results found\": \"結果が見つかりません\",\n  \"Nobody will be able to vote in this poll anymore.\": \"この投票では、誰も投票できなくなります。\",\n  \"Nothing yet...\": \"まだ何もありません...\",\n  \"Offline\": \"オフライン\",\n  \"Ok\": \"OK\",\n  \"Online\": \"オンライン\",\n  \"Only numbers are allowed\": \"数字のみ許可されています\",\n  \"Only visible to you\": \"あなただけに表示\",\n  \"Open emoji picker\": \"絵文字ピッカーを開く\",\n  \"Open gallery at image {{ index }}\": \"画像 {{ index }} でギャラリーを開く\",\n  \"Open image in gallery\": \"画像をギャラリーで開く\",\n  \"Open location in a map\": \"地図で位置情報を開く\",\n  \"Option already exists\": \"オプションは既に存在します\",\n  \"Option is empty\": \"オプションが空です\",\n  \"Options\": \"オプション\",\n  \"Original\": \"原文\",\n  \"People matching\": \"一致する人\",\n  \"Photo\": \"写真\",\n  \"Pin\": \"ピン\",\n  \"Pinned by {{ name }}\": \"{{ name }}がピンしました\",\n  \"Pinned by You\": \"あなたがピン留めしました\",\n  \"placeholder/PollComment\": \"コメント\",\n  \"placeholder/PollOptionSuggestion\": \"新しい選択肢を入力\",\n  \"Play video\": \"動画を再生\",\n  \"Playback speed {{ rate }}x\": \"再生速度 {{ rate }}x\",\n  \"Poll\": \"投票\",\n  \"Poll comments\": \"投票コメント\",\n  \"Poll ended\": \"アンケート終了\",\n  \"Poll options\": \"投票オプション\",\n  \"Poll results\": \"投票結果\",\n  \"Previous image\": \"前の画像\",\n  \"Question\": \"質問\",\n  \"Question {{ optionOrderNumber}}\": \"質問 {{ optionOrderNumber}}\",\n  \"Question is required\": \"質問は必須です\",\n  \"Quote Reply\": \"引用返信\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"投票制限に達しました。既存の投票を先に削除してください。\",\n  \"Recording format is not supported and cannot be reproduced\": \"録音形式はサポートされておらず、再生できません\",\n  \"Remind me\": \"リマインド\",\n  \"Remind Me\": \"リマインダー\",\n  \"Reminder set\": \"リマインダーを設定しました\",\n  \"Remove reminder\": \"リマインダーを削除\",\n  \"Remove save for later\": \"「後で見る」を削除\",\n  \"Replied to a thread\": \"スレッドに返信しました\",\n  \"Reply\": \"返事\",\n  \"Reply to {{ authorName }}\": \"{{ authorName }} に返信\",\n  \"Reply to a message to start a thread\": \"メッセージに返信してスレッドを開始してください\",\n  \"Reply to Message\": \"メッセージに返信\",\n  \"replyCount_one\": \"1件の返信\",\n  \"replyCount_other\": \"{{ count }} 返信\",\n  \"Resend\": \"再送信\",\n  \"Retry upload\": \"アップロードを再試行\",\n  \"Review all options available in this poll\": \"この投票で利用可能なすべての選択肢を確認\",\n  \"Review comments submitted with poll answers\": \"投票回答とともに送信されたコメントを確認\",\n  \"Review poll results and open an option to see detailed votes\": \"投票結果を確認し、選択肢を開いて詳細な投票を表示\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"このメッセージを確認し、削除・編集・そのまま送信するかを選択\",\n  \"Review who voted for this option\": \"この選択肢に投票した人を確認\",\n  \"Save for later\": \"後で保存\",\n  \"Saved for later\": \"後で保存済み\",\n  \"Search\": \"探す\",\n  \"Search GIFs\": \"GIFを検索\",\n  \"search-results-header-filter-source-button-label--channels\": \"チャンネル\",\n  \"search-results-header-filter-source-button-label--messages\": \"メッセージ\",\n  \"search-results-header-filter-source-button-label--users\": \"ユーザー\",\n  \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }}を検索中...\",\n  \"Searching...\": \"検索中...\",\n  \"searchResultsCount_one\": \"1件の結果\",\n  \"searchResultsCount_other\": \"{{ count }}件の結果\",\n  \"Select a thread to continue the conversation\": \"会話を続けるにはスレッドを選択してください\",\n  \"Select more than one option\": \"複数の選択肢を選ぶ\",\n  \"Select one\": \"1つ選択\",\n  \"Select one or more\": \"1つ以上選択\",\n  \"Select up to {{count}}_one\": \"最大{{count}}まで選択\",\n  \"Select up to {{count}}_other\": \"最大{{count}}まで選択\",\n  \"Select your current location and optionally enable live location sharing\": \"現在地を選択し、必要に応じてライブ位置情報共有を有効化\",\n  \"Send\": \"送信\",\n  \"Send a message\": \"メッセージを送る\",\n  \"Send a message to start the conversation\": \"メッセージを送って会話を始めましょう\",\n  \"Send Anyway\": \"とにかく送信する\",\n  \"Send message request failed\": \"メッセージ送信リクエストが失敗しました\",\n  \"Send poll\": \"アンケートを送信\",\n  \"Sending...\": \"送信中...\",\n  \"Sent\": \"送信済み\",\n  \"Share\": \"共有\",\n  \"Share live location for\": \"ライブ位置情報を共有\",\n  \"Share Location\": \"位置情報を共有\",\n  \"Shared live location\": \"共有されたライブ位置情報\",\n  \"Shared location\": \"共有された位置情報\",\n  \"Shuffle\": \"シャッフル\",\n  \"size limit\": \"サイズ制限\",\n  \"Slow Mode ON\": \"スローモードオン\",\n  \"Slow mode, wait {{ seconds }}s...\": \"スローモード、{{ seconds }}秒お待ちください...\",\n  \"Some of the files will not be accepted\": \"一部のファイルは受け付けられません\",\n  \"Start typing to search\": \"検索するには入力を開始してください\",\n  \"Stop sharing\": \"共有を停止\",\n  \"Submit\": \"送信\",\n  \"Suggest a new option to add to this poll\": \"この投票に追加する新しい選択肢を提案\",\n  \"Suggest an option\": \"オプションを提案\",\n  \"Tap to remove\": \"タップして削除\",\n  \"Tap to remove: {{ reactionName }}\": \"タップして削除: {{ reactionName }}\",\n  \"Thinking...\": \"考え中...\",\n  \"this content could not be displayed\": \"このコンテンツは表示できませんでした\",\n  \"This field cannot be empty or contain only spaces\": \"このフィールドは空にすることはできません。また、空白文字のみを含むこともできません\",\n  \"This message did not meet our content guidelines\": \"このメッセージはコンテンツガイドラインに適合していません\",\n  \"Thread\": \"スレッド\",\n  \"Thread has not been found\": \"スレッドが見つかりませんでした\",\n  \"Thread reply\": \"スレッドの返信\",\n  \"Thread Reply\": \"スレッドの返信\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"読み込み中...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }}件の未読スレッド\",\n  \"Threads\": \"スレッド\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[昨日]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[今日]\\\", \\\"nextDay\\\": \\\"[明日]\\\", \\\"lastDay\\\": \\\"[昨日]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[先週の] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"今日\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"昨日\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"録音を開始するには、ブラウザーでカメラへのアクセスを許可してください\",\n  \"To start recording, allow the microphone access in your browser\": \"録音を開始するには、ブラウザーでマイクロフォンへのアクセスを許可してください\",\n  \"totalVoteCount_other\": \"合計{{ count }}票\",\n  \"Translated\": \"翻訳済み\",\n  \"Translated from {{ language }}\": \"{{ language }}から翻訳\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"2から10までの数字を入力してください\",\n  \"Unarchive\": \"アーカイブ解除\",\n  \"unban-command-args\": \"[@ユーザ名]\",\n  \"unban-command-description\": \"ユーザーの禁止を解除する\",\n  \"Unblock User\": \"ユーザーのブロックを解除\",\n  \"unknown error\": \"不明なエラー\",\n  \"Unmute\": \"無音を解除する\",\n  \"unmute-command-args\": \"[@ユーザ名]\",\n  \"unmute-command-description\": \"ユーザーのミュートを解除する\",\n  \"Unpin\": \"ピンを解除する\",\n  \"Unread messages\": \"未読メッセージ\",\n  \"Unsupported attachment\": \"サポートされていない添付ファイル\",\n  \"unsupported file type\": \"サポートされていないファイル形式\",\n  \"Update\": \"更新\",\n  \"Update the comment attached to your poll answer\": \"投票回答に添付されたコメントを更新\",\n  \"Update your comment\": \"コメントを更新\",\n  \"Upload blocked\": \"アップロードがブロックされました\",\n  \"Upload error\": \"アップロードエラー\",\n  \"Upload failed\": \"アップロードに失敗しました\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"アップロードタイプ：\\\"{{ type }}\\\"は許可されていません\",\n  \"User blocked\": \"ユーザーをブロックしました\",\n  \"User unblocked\": \"ユーザーのブロックを解除しました\",\n  \"User uploaded content\": \"ユーザーがアップロードしたコンテンツ\",\n  \"Video\": \"動画\",\n  \"videoCount_other\": \"{{ count }}件の動画\",\n  \"View\": \"表示\",\n  \"View {{count}} comments_one\": \"{{count}} コメントを表示\",\n  \"View {{count}} comments_other\": \"{{count}} コメントを表示\",\n  \"View all\": \"すべて表示\",\n  \"View original\": \"原文を表示\",\n  \"View results\": \"結果を表示\",\n  \"View translation\": \"翻訳を表示\",\n  \"Voice message\": \"ボイスメッセージ\",\n  \"Voice message {{ duration }}\": \"ボイスメッセージ {{ duration }}\",\n  \"Voice message deleted\": \"ボイスメッセージが削除されました\",\n  \"voiceMessageCount_other\": \"{{ count }}件のボイスメッセージ\",\n  \"Vote ended\": \"投票が終了しました\",\n  \"Votes\": \"投票\",\n  \"Wait until all attachments have uploaded\": \"すべての添付ファイルがアップロードされるまでお待ちください\",\n  \"Waiting for network…\": \"ネットワークを待機中…\",\n  \"You\": \"あなた\",\n  \"You've reached the maximum number of files\": \"ファイルの最大数に達しました\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} 그리고 {{ moreCount }}명 더\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} 그리고 {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }}개 파일\",\n  \"{{ count }} files_other\": \"{{ count }}개 파일\",\n  \"{{ count }} people are typing_one\": \"{{ count }}명이 입력 중입니다\",\n  \"{{ count }} people are typing_many\": \"{{ count }}명이 입력 중입니다\",\n  \"{{ count }} people are typing_other\": \"{{ count }}명이 입력 중입니다\",\n  \"{{ count }} photos_one\": \"{{ count }}개 사진\",\n  \"{{ count }} photos_other\": \"{{ count }}개 사진\",\n  \"{{ count }} reactions_other\": \"{{ count }}개 반응\",\n  \"{{ count }} videos_one\": \"{{ count }}개 동영상\",\n  \"{{ count }} videos_other\": \"{{ count }}개 동영상\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} 그리고 {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }}개 더\",\n  \"{{ memberCount }} members\": \"{{ memberCount }}명\",\n  \"{{ typing }} are typing\": \"{{ typing }} 입력 중입니다\",\n  \"{{ typing }} is typing\": \"{{ typing }} 입력 중입니다\",\n  \"{{ user }} has been muted\": \"{{ user }} 음소거되었습니다\",\n  \"{{ user }} has been unmuted\": \"{{ user }} 음소거가 해제되었습니다\",\n  \"{{ user }} is typing...\": \"{{ user }}이(가) 입력 중입니다...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }}와(과) {{ user }}이(가) 입력 중입니다...\",\n  \"{{ users }} and more are typing...\": \"{{ users }}와(과) 더 많은 사람들이 입력 중입니다...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} 온라인\",\n  \"{{count}} new messages_one\": \"{{count}}개의 새 메시지\",\n  \"{{count}} new messages_other\": \"{{count}}개의 새 메시지\",\n  \"{{count}} unread_one\": \"{{count}} 읽지 않음\",\n  \"{{count}} unread_other\": \"{{count}} 읽지 않음\",\n  \"{{count}} votes_one\": \"{{count}} 투표\",\n  \"{{count}} votes_other\": \"{{count}} 투표\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"옵션 {{count}}개 더\",\n  \"+{{count}} more options_other\": \"옵션 {{count}}개 더\",\n  \"🏙 Attachment...\": \"🏙 부착...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}}이(가) 생성함: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}}이(가) 투표함: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍공유된 위치\",\n  \"Add a comment\": \"댓글 추가\",\n  \"Add a comment to your poll answer\": \"투표 답변에 댓글 추가\",\n  \"Add an option\": \"옵션 추가\",\n  \"Add reaction\": \"반응 추가\",\n  \"All results loaded\": \"모든 결과가 로드되었습니다\",\n  \"Allow access to camera\": \"카메라에 대한 액세스 허용\",\n  \"Allow access to microphone\": \"마이크로폰에 대한 액세스 허용\",\n  \"Allow comments\": \"댓글 허용\",\n  \"Allow option suggestion\": \"옵션 제안 허용\",\n  \"Allow others to add comments\": \"다른 사람이 댓글을 추가할 수 있도록 허용\",\n  \"Also send as a direct message\": \"다이렉트 메시지로도 보내기\",\n  \"Also send in channel\": \"채널에도 보내기\",\n  \"Also sent in channel\": \"채널에도 전송됨\",\n  \"An error has occurred during recording\": \"녹음 중 오류가 발생했습니다\",\n  \"An error has occurred during the recording processing\": \"녹음 처리 중 오류가 발생했습니다\",\n  \"Anonymous\": \"익명\",\n  \"Anonymous poll\": \"익명 투표\",\n  \"Archive\": \"아카이브\",\n  \"Are you sure you want to delete this message?\": \"이 메시지를 삭제하시겠습니까?\",\n  \"aria/Attachment\": \"첨부 파일\",\n  \"aria/Attachment Actions\": \"첨부 파일 작업\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"오디오 위치 {{ elapsed }} / {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"오디오 위치 {{ progress }}퍼센트\",\n  \"aria/Block User\": \"사용자 차단\",\n  \"aria/Bookmark Message\": \"메시지 북마크\",\n  \"aria/Cancel recording\": \"녹음 취소\",\n  \"aria/Cancel Reply\": \"답장 취소\",\n  \"aria/Cancel upload\": \"업로드 취소\",\n  \"aria/Channel Actions\": \"채널 작업\",\n  \"aria/Channel list\": \"채널 목록\",\n  \"aria/Channel search results\": \"채널 검색 결과\",\n  \"aria/Chat view tabs\": \"채팅 보기 탭\",\n  \"aria/Clear search\": \"검색 지우기\",\n  \"aria/Close callout dialog\": \"콜아웃 대화 상자 닫기\",\n  \"aria/Close thread\": \"스레드 닫기\",\n  \"aria/Collapse sidebar\": \"사이드바 접기\",\n  \"aria/Command Suggestions\": \"명령어 제안\",\n  \"aria/Complete recording\": \"녹음 완료\",\n  \"aria/Copy Message Text\": \"메시지 텍스트 복사\",\n  \"aria/Decrease value\": \"값 감소\",\n  \"aria/Delete Message\": \"메시지 삭제\",\n  \"aria/Dismiss notification\": \"알림 닫기\",\n  \"aria/Download attachment\": \"첨부 파일 다운로드\",\n  \"aria/Edit Message\": \"메시지 수정\",\n  \"aria/Emoji picker\": \"이모지 선택기\",\n  \"aria/Emoji Suggestions\": \"이모지 제안\",\n  \"aria/Exit search\": \"검색 종료\",\n  \"aria/Expand sidebar\": \"사이드바 확장\",\n  \"aria/File input\": \"파일 입력\",\n  \"aria/File upload\": \"파일 업로드\",\n  \"aria/Flag Message\": \"메시지 신고\",\n  \"aria/Image failed to load\": \"이미지를 불러오지 못했습니다\",\n  \"aria/Image input\": \"이미지 입력\",\n  \"aria/Increase value\": \"값 증가\",\n  \"aria/Jump to latest message\": \"최신 메시지로 이동\",\n  \"aria/Jump to quoted message\": \"인용된 메시지로 이동\",\n  \"aria/Load More Channels\": \"더 많은 채널 불러오기\",\n  \"aria/Mark Message Unread\": \"읽지 않음으로 표시\",\n  \"aria/Mark messages as read\": \"메시지를 읽음으로 표시\",\n  \"aria/Menu\": \"메뉴\",\n  \"aria/Message Actions\": \"메시지 작업\",\n  \"aria/Message from {{ user }},\": \"{{ user }}의 메시지,\",\n  \"aria/Message Options\": \"메시지 옵션\",\n  \"aria/Message,\": \"메시지,\",\n  \"aria/Mute User\": \"사용자 음소거\",\n  \"aria/Notifications\": \"알림\",\n  \"aria/Open Attachment Selector\": \"첨부 파일 선택기 열기\",\n  \"aria/Open Channel Actions Menu\": \"채널 작업 메뉴 열기\",\n  \"aria/Open Menu\": \"메뉴 열기\",\n  \"aria/Open Message Actions Menu\": \"메시지 액션 메뉴 열기\",\n  \"aria/Open Reaction Selector\": \"반응 선택기 열기\",\n  \"aria/Open Thread\": \"스레드 열기\",\n  \"aria/Pause\": \"일시정지\",\n  \"aria/Pause recording\": \"녹음 일시정지\",\n  \"aria/Percent complete\": \"{{percent}}퍼센트 완료\",\n  \"aria/Pin Message\": \"메시지 고정\",\n  \"aria/Play\": \"재생\",\n  \"aria/Quote Message\": \"메시지 인용\",\n  \"aria/Reaction list\": \"반응 목록\",\n  \"aria/Remind Me Message\": \"알림 설정\",\n  \"aria/Remind Me Options\": \"알림 옵션\",\n  \"aria/Remove attachment\": \"첨부 파일 제거\",\n  \"aria/Remove location attachment\": \"위치 첨부 파일 제거\",\n  \"aria/Remove option\": \"옵션 제거\",\n  \"aria/Remove Reminder\": \"알림 제거\",\n  \"aria/Remove Save For Later\": \"나중에 보기 제거\",\n  \"aria/Resend Message\": \"메시지 다시 보내기\",\n  \"aria/Resume recording\": \"녹음 재개\",\n  \"aria/Retry upload\": \"업로드 다시 시도\",\n  \"aria/Review bounced message\": \"반송된 메시지 검토\",\n  \"aria/Search results\": \"검색 결과\",\n  \"aria/Search results header filter button for: {{ source }}\": \"{{ source }}에 대한 검색 결과 헤더 필터 버튼\",\n  \"aria/Seek audio position\": \"오디오 위치 탐색\",\n  \"aria/Select Channel: {{ channelName }}\": \"채널 선택: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"반응 선택: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"사용자 채널 선택: {{ name }}\",\n  \"aria/Send\": \"보내기\",\n  \"aria/Show preview\": \"미리보기 표시\",\n  \"aria/Start recording audio\": \"오디오 녹음 시작\",\n  \"aria/Stop AI Generation\": \"AI 생성 중지\",\n  \"aria/Suggestions\": \"제안\",\n  \"aria/Thread list\": \"스레드 목록\",\n  \"aria/Unblock User\": \"사용자 차단 해제\",\n  \"aria/Unmute User\": \"음소거 해제\",\n  \"aria/Unpin Message\": \"핀 해제\",\n  \"aria/User Suggestions\": \"사용자 제안\",\n  \"Ask a question\": \"질문하기\",\n  \"Attach\": \"첨부\",\n  \"Attach files\": \"파일 첨부\",\n  \"Attachment\": \"첨부 파일\",\n  \"Attachment upload blocked due to {{reason}}\": \"{{reason}}로 인해 첨부 파일 업로드가 차단되었습니다\",\n  \"Attachment upload failed due to {{reason}}\": \"{{reason}}로 인해 첨부 파일 업로드가 실패했습니다\",\n  \"Back\": \"뒤로\",\n  \"ban-command-args\": \"[@사용자이름] [텍스트]\",\n  \"ban-command-description\": \"사용자를 차단\",\n  \"Block User\": \"사용자 차단\",\n  \"Cancel\": \"취소\",\n  \"Cannot seek in the recording\": \"녹음에서 찾을 수 없습니다\",\n  \"Channel archived\": \"채널이 보관됨\",\n  \"Channel Missing\": \"채널 누락\",\n  \"Channel muted\": \"채널이 음소거됨\",\n  \"Channel pinned\": \"채널이 고정됨\",\n  \"Channel unarchived\": \"채널 보관이 해제됨\",\n  \"Channel unmuted\": \"채널 음소거가 해제됨\",\n  \"Channel unpinned\": \"채널 고정이 해제됨\",\n  \"Channels\": \"채널\",\n  \"Chats\": \"채팅\",\n  \"Choose between 2 to 10 options\": \"2~10개의 선택지 중에서 선택\",\n  \"Close\": \"닫기\",\n  \"Close dialog\": \"대화 상자 닫기\",\n  \"Close emoji picker\": \"이모티콘 선택기 닫기\",\n  \"Close prompt: {{ title }}\": \"프롬프트 닫기: {{ title }}\",\n  \"Command not available while editing\": \"편집 중에는 명령을 사용할 수 없습니다\",\n  \"Command not available while replying\": \"답장 중에는 명령을 사용할 수 없습니다\",\n  \"Commands\": \"명령어\",\n  \"Commands matching\": \"일치하는 명령\",\n  \"Connection failure, reconnecting now...\": \"연결 실패, 지금 다시 연결 중...\",\n  \"Copy Message\": \"메시지 복사\",\n  \"Create\": \"생성\",\n  \"Create a question, add options, and configure poll settings\": \"질문을 만들고 옵션을 추가한 뒤 투표 설정 구성\",\n  \"Create poll\": \"투표 생성\",\n  \"Current location\": \"현재 위치\",\n  \"Delete\": \"삭제\",\n  \"Delete for me\": \"나만 삭제\",\n  \"Delete message\": \"메시지 삭제\",\n  \"Delivered\": \"배달됨\",\n  \"Direct message\": \"다이렉트 메시지\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"지금 이 투표를 종료하시겠습니까? 종료 후에는 더 이상 투표할 수 없습니다.\",\n  \"Download All\": \"모두 다운로드\",\n  \"Download Attachment\": \"첨부 파일 다운로드\",\n  \"Download attachment {{ name }}\": \"첨부 파일 {{ name }} 다운로드\",\n  \"Drag your files here\": \"여기로 파일을 끌어다 놓으세요\",\n  \"Drag your files here to add to your post\": \"게시물에 추가하려면 파일을 여기로 끌어다 놓으세요\",\n  \"Due {{ timeLeft }}\": \"{{ timeLeft }}에 기한\",\n  \"Due since {{ dueSince }}\": \"{{ dueSince }}부터 기한\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"메시지 수정\",\n  \"Edit message request failed\": \"메시지 수정 요청 실패\",\n  \"Edited\": \"편집됨\",\n  \"Emoji matching\": \"이모티콘 매칭\",\n  \"Empty message...\": \"빈 메시지...\",\n  \"End\": \"종료\",\n  \"End poll\": \"투표 종료\",\n  \"End this poll?\": \"이 투표를 종료하시겠습니까?\",\n  \"End vote\": \"투표 종료\",\n  \"Enforce unique vote is enabled\": \"고유 투표가 활성화되었습니다\",\n  \"Error\": \"오류\",\n  \"Error adding flag\": \"플래그를 추가하는 동안 오류가 발생했습니다.\",\n  \"Error connecting to chat, refresh the page to try again.\": \"채팅에 연결하는 동안 오류가 발생했습니다. 페이지를 새로고침하여 다시 시도하세요.\",\n  \"Error deleting message\": \"메시지를 삭제하는 중에 오류가 발생했습니다.\",\n  \"Error fetching reactions\": \"반응 로딩 오류.\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"메시지를 읽지 않음으로 표시하는 중 오류가 발생했습니다. 가장 최근 100개의 채널 메시지보다 오래된 읽지 않은 메시지는 표시할 수 없습니다.\",\n  \"Error muting a user ...\": \"사용자를 음소거하는 중에 오류가 발생했습니다...\",\n  \"Error pinning message\": \"메시지를 핀하는 중에 오류가 발생했습니다.\",\n  \"Error removing message pin\": \"메시지 핀을 제거하는 중에 오류가 발생했습니다.\",\n  \"Error reproducing the recording\": \"녹음 재생 중 오류 발생\",\n  \"Error starting recording\": \"녹음 시작 중 오류가 발생했습니다\",\n  \"Error unmuting a user ...\": \"사용자 음소거 해제 중 오류 발생...\",\n  \"Error uploading attachment\": \"첨부 파일 업로드 중 오류가 발생했습니다\",\n  \"Error uploading file\": \"파일 업로드 오류\",\n  \"Error uploading image\": \"이미지를 업로드하는 동안 오류가 발생했습니다.\",\n  \"Error: {{ errorMessage }}\": \"오류: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"명령 종료 {{ command }}\",\n  \"Failed to block user\": \"사용자 차단에 실패했습니다\",\n  \"Failed to create the poll\": \"투표 생성 실패\",\n  \"Failed to create the poll due to {{reason}}\": \"{{reason}} 때문에 투표를 생성하지 못했습니다\",\n  \"Failed to delete the message\": \"메시지 삭제에 실패했습니다\",\n  \"Failed to end the poll\": \"투표 종료에 실패했습니다\",\n  \"Failed to end the poll due to {{reason}}\": \"{{reason}}(으)로 인해 투표 종료에 실패했습니다\",\n  \"Failed to jump to the first unread message\": \"첫 번째 읽지 않은 메시지로 이동하지 못했습니다\",\n  \"Failed to leave channel\": \"채널 나가기에 실패했습니다\",\n  \"Failed to load channels\": \"채널을 불러오지 못했습니다\",\n  \"Failed to load more channels\": \"채널을 더 불러오지 못했습니다\",\n  \"Failed to mark channel as read\": \"채널을 읽음으로 표시하는 데 실패했습니다\",\n  \"Failed to play the recording\": \"녹음을 재생하지 못했습니다\",\n  \"Failed to retrieve location\": \"위치를 가져오지 못했습니다\",\n  \"Failed to share location\": \"위치를 공유하지 못했습니다\",\n  \"Failed to update channel archive status\": \"채널 아카이브 상태 업데이트에 실패했습니다\",\n  \"Failed to update channel mute status\": \"채널 음소거 상태 업데이트에 실패했습니다\",\n  \"Failed to update channel pinned status\": \"채널 고정 상태 업데이트에 실패했습니다\",\n  \"File\": \"파일\",\n  \"File is required for upload attachment\": \"첨부 파일 업로드에 파일이 필요합니다\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"파일이 너무 큽니다: {{ size }}, 최대 업로드 크기는 {{ limit }}입니다\",\n  \"File too large\": \"파일이 너무 큽니다\",\n  \"fileCount_other\": \"파일 {{ count }}개\",\n  \"Flag\": \"플래그\",\n  \"Generating...\": \"생성 중...\",\n  \"giphy-command-args\": \"[텍스트]\",\n  \"giphy-command-description\": \"채널에 무작위 GIF 게시\",\n  \"Hide who voted\": \"누가 투표했는지 숨기기\",\n  \"Image\": \"이미지\",\n  \"imageCount_other\": \"이미지 {{ count }}개\",\n  \"Instant commands\": \"즉시 명령어\",\n  \"language/af\": \"아프리칸스어\",\n  \"language/am\": \"암하라어\",\n  \"language/ar\": \"아랍어\",\n  \"language/az\": \"아제르바이잔어\",\n  \"language/bg\": \"불가리아어\",\n  \"language/bn\": \"벵골어\",\n  \"language/bs\": \"보스니아어\",\n  \"language/cs\": \"체코어\",\n  \"language/da\": \"덴마크어\",\n  \"language/de\": \"독일어\",\n  \"language/el\": \"그리스어\",\n  \"language/en\": \"영어\",\n  \"language/es\": \"스페인어\",\n  \"language/es-MX\": \"스페인어(멕시코)\",\n  \"language/et\": \"에스토니아어\",\n  \"language/fa\": \"페르시아어\",\n  \"language/fa-AF\": \"다리어\",\n  \"language/fi\": \"핀란드어\",\n  \"language/fr\": \"프랑스어\",\n  \"language/fr-CA\": \"프랑스어(캐나다)\",\n  \"language/ha\": \"하우사어\",\n  \"language/he\": \"히브리어\",\n  \"language/hi\": \"힌디어\",\n  \"language/hr\": \"크로아티아어\",\n  \"language/ht\": \"아이티 크리올어\",\n  \"language/hu\": \"헝가리어\",\n  \"language/id\": \"인도네시아어\",\n  \"language/it\": \"이탈리아어\",\n  \"language/ja\": \"일본어\",\n  \"language/ka\": \"조지아어\",\n  \"language/ko\": \"한국어\",\n  \"language/lt\": \"리투아니아어\",\n  \"language/lv\": \"라트비아어\",\n  \"language/ms\": \"말레이어\",\n  \"language/nl\": \"네덜란드어\",\n  \"language/no\": \"노르웨이어\",\n  \"language/pl\": \"폴란드어\",\n  \"language/ps\": \"파슈토어\",\n  \"language/pt\": \"포르투갈어\",\n  \"language/ro\": \"루마니아어\",\n  \"language/ru\": \"러시아어\",\n  \"language/sk\": \"슬로바키아어\",\n  \"language/sl\": \"슬로베니아어\",\n  \"language/so\": \"소말리아어\",\n  \"language/sq\": \"알바니아어\",\n  \"language/sr\": \"세르비아어\",\n  \"language/sv\": \"스웨덴어\",\n  \"language/sw\": \"스와힐리어\",\n  \"language/ta\": \"타밀어\",\n  \"language/th\": \"태국어\",\n  \"language/tl\": \"타갈로그어\",\n  \"language/tr\": \"터키어\",\n  \"language/uk\": \"우크라이나어\",\n  \"language/ur\": \"우르두어\",\n  \"language/vi\": \"베트남어\",\n  \"language/zh\": \"중국어(간체)\",\n  \"language/zh-TW\": \"중국어(번체)\",\n  \"Leave Channel\": \"채널 나가기\",\n  \"Left channel\": \"채널을 나갔습니다\",\n  \"Let others add options\": \"다른 사람이 선택지를 추가할 수 있도록 허용\",\n  \"Limit votes per person\": \"1인당 투표 수 제한\",\n  \"Link\": \"링크\",\n  \"linkCount_other\": \"링크 {{ count }}개\",\n  \"live\": \"라이브\",\n  \"Live for {{duration}}\": \"{{duration}} 동안 라이브\",\n  \"Live location\": \"라이브 위치\",\n  \"Live until {{ timestamp }}\": \"{{ timestamp }}까지 라이브\",\n  \"Load more\": \"더 불러오기\",\n  \"Local upload attachment missing local id\": \"로컬 업로드 첨부에 로컬 ID가 없습니다\",\n  \"Location\": \"위치\",\n  \"Location sharing ended\": \"위치 공유가 종료되었습니다\",\n  \"Location: {{ coordinates }}\": \"위치: {{ coordinates }}\",\n  \"Mark as unread\": \"읽지 않음으로 표시\",\n  \"Maximum number of votes (from 2 to 10)\": \"최대 투표 수 (2에서 10까지)\",\n  \"Maximum votes per person\": \"1인당 최대 투표 수\",\n  \"Menu\": \"메뉴\",\n  \"Message deleted\": \"메시지가 삭제되었습니다.\",\n  \"Message failed to send\": \"메시지 전송 실패\",\n  \"Message has been successfully flagged\": \"메시지에 플래그가 지정되었습니다.\",\n  \"Message marked as unread\": \"메시지를 읽지 않음으로 표시했습니다\",\n  \"Message pinned\": \"메시지 핀했습니다\",\n  \"Message unpinned\": \"메시지 고정이 해제됨\",\n  \"Message was blocked by moderation policies\": \"메시지가 관리 정책에 의해 차단되었습니다.\",\n  \"Messages have been marked unread.\": \"메시지가 읽지 않음으로 표시되었습니다.\",\n  \"Missing permissions to upload the attachment\": \"첨부 파일을 업로드하려면 권한이 필요합니다\",\n  \"Multiple votes\": \"복수 투표\",\n  \"Mute\": \"무음\",\n  \"mute-command-args\": \"[@사용자이름]\",\n  \"mute-command-description\": \"사용자 음소거\",\n  \"network error\": \"네트워크 오류\",\n  \"New\": \"새로운\",\n  \"New message from {{user}}\": \"{{user}}의 새 메시지\",\n  \"New Messages!\": \"새 메시지!\",\n  \"Next image\": \"다음 이미지\",\n  \"No chats here yet…\": \"아직 채팅이 없습니다...\",\n  \"No conversations yet\": \"아직 대화가 없습니다.\",\n  \"No items exist\": \"항목이 없습니다.\",\n  \"No results found\": \"검색 결과가 없습니다\",\n  \"Nobody will be able to vote in this poll anymore.\": \"이 투표에 더 이상 아무도 투표할 수 없습니다.\",\n  \"Nothing yet...\": \"아직 아무것도...\",\n  \"Offline\": \"오프라인\",\n  \"Ok\": \"확인\",\n  \"Online\": \"온라인\",\n  \"Only numbers are allowed\": \"숫자만 입력 가능합니다\",\n  \"Only visible to you\": \"당신에게만 표시됨\",\n  \"Open emoji picker\": \"이모지 선택기 열기\",\n  \"Open gallery at image {{ index }}\": \"이미지 {{ index }}에서 갤러리 열기\",\n  \"Open image in gallery\": \"갤러리에서 이미지 열기\",\n  \"Open location in a map\": \"지도에서 위치 열기\",\n  \"Option already exists\": \"옵션이 이미 존재합니다\",\n  \"Option is empty\": \"옵션이 비어 있습니다\",\n  \"Options\": \"옵션\",\n  \"Original\": \"원문\",\n  \"People matching\": \"일치하는 사람\",\n  \"Photo\": \"사진\",\n  \"Pin\": \"핀\",\n  \"Pinned by {{ name }}\": \"{{ name }}님이 핀함\",\n  \"Pinned by You\": \"내가 고정함\",\n  \"placeholder/PollComment\": \"댓글\",\n  \"placeholder/PollOptionSuggestion\": \"새 옵션 입력\",\n  \"Play video\": \"동영상 재생\",\n  \"Playback speed {{ rate }}x\": \"재생 속도 {{ rate }}x\",\n  \"Poll\": \"투표\",\n  \"Poll comments\": \"투표 댓글\",\n  \"Poll ended\": \"투표 종료됨\",\n  \"Poll options\": \"투표 옵션\",\n  \"Poll results\": \"투표 결과\",\n  \"Previous image\": \"이전 이미지\",\n  \"Question\": \"질문\",\n  \"Question {{ optionOrderNumber}}\": \"질문 {{ optionOrderNumber}}\",\n  \"Question is required\": \"질문이 필요합니다\",\n  \"Quote Reply\": \"인용 답장\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"투표 한도에 도달했습니다. 기존 투표를 먼저 제거하세요.\",\n  \"Recording format is not supported and cannot be reproduced\": \"녹음 형식이 지원되지 않으므로 재생할 수 없습니다\",\n  \"Remind me\": \"알림\",\n  \"Remind Me\": \"알림 설정\",\n  \"Reminder set\": \"알림 설정됨\",\n  \"Remove reminder\": \"알림 제거\",\n  \"Remove save for later\": \"나중에 보기 제거\",\n  \"Replied to a thread\": \"스레드에 답글을 남겼습니다\",\n  \"Reply\": \"답장\",\n  \"Reply to {{ authorName }}\": \"{{ authorName }}님에게 답장\",\n  \"Reply to a message to start a thread\": \"스레드를 시작하려면 메시지에 답장하세요\",\n  \"Reply to Message\": \"메시지에 답장\",\n  \"replyCount_one\": \"답장 1개\",\n  \"replyCount_other\": \"{{ count }} 답장\",\n  \"Resend\": \"다시 보내기\",\n  \"Retry upload\": \"업로드 다시 시도\",\n  \"Review all options available in this poll\": \"이 투표에서 사용 가능한 모든 옵션 검토\",\n  \"Review comments submitted with poll answers\": \"투표 답변과 함께 제출된 댓글 검토\",\n  \"Review poll results and open an option to see detailed votes\": \"투표 결과를 검토하고 옵션을 열어 상세 득표 보기\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"이 메시지를 검토하고 삭제, 수정 또는 그대로 전송할지 선택\",\n  \"Review who voted for this option\": \"이 옵션에 투표한 사람 검토\",\n  \"Save for later\": \"나중에 저장\",\n  \"Saved for later\": \"나중에 저장됨\",\n  \"Search\": \"찾다\",\n  \"Search GIFs\": \"GIF 검색\",\n  \"search-results-header-filter-source-button-label--channels\": \"채널\",\n  \"search-results-header-filter-source-button-label--messages\": \"메시지\",\n  \"search-results-header-filter-source-button-label--users\": \"사용자\",\n  \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }} 검색 중...\",\n  \"Searching...\": \"수색...\",\n  \"searchResultsCount_one\": \"1개의 결과\",\n  \"searchResultsCount_other\": \"{{ count }}개 결과\",\n  \"Select a thread to continue the conversation\": \"대화를 계속하려면 스레드를 선택하세요\",\n  \"Select more than one option\": \"하나 이상의 선택지 선택\",\n  \"Select one\": \"하나 선택\",\n  \"Select one or more\": \"하나 이상 선택\",\n  \"Select up to {{count}}_one\": \"{{count}}개까지 선택\",\n  \"Select up to {{count}}_other\": \"{{count}}개까지 선택\",\n  \"Select your current location and optionally enable live location sharing\": \"현재 위치를 선택하고 필요 시 실시간 위치 공유를 활성화\",\n  \"Send\": \"보내다\",\n  \"Send a message\": \"메시지 보내기\",\n  \"Send a message to start the conversation\": \"대화를 시작하려면 메시지를 보내세요\",\n  \"Send Anyway\": \"어쨌든 보내기\",\n  \"Send message request failed\": \"메시지 보내기 요청 실패\",\n  \"Send poll\": \"투표 보내기\",\n  \"Sending...\": \"배상중...\",\n  \"Sent\": \"전송됨\",\n  \"Share\": \"공유\",\n  \"Share live location for\": \"라이브 위치 공유\",\n  \"Share Location\": \"위치 공유\",\n  \"Shared live location\": \"공유된 라이브 위치\",\n  \"Shared location\": \"공유된 위치\",\n  \"Shuffle\": \"셔플\",\n  \"size limit\": \"크기 제한\",\n  \"Slow Mode ON\": \"슬로우 모드 켜짐\",\n  \"Slow mode, wait {{ seconds }}s...\": \"슬로우 모드, {{ seconds }}초 기다려 주세요...\",\n  \"Some of the files will not be accepted\": \"일부 파일은 허용되지 않을 수 있습니다\",\n  \"Start typing to search\": \"검색하려면 입력을 시작하세요\",\n  \"Stop sharing\": \"공유 중지\",\n  \"Submit\": \"제출\",\n  \"Suggest a new option to add to this poll\": \"이 투표에 추가할 새 옵션 제안\",\n  \"Suggest an option\": \"옵션 제안\",\n  \"Tap to remove\": \"제거하려면 탭하세요\",\n  \"Tap to remove: {{ reactionName }}\": \"제거하려면 탭하세요: {{ reactionName }}\",\n  \"Thinking...\": \"생각 중...\",\n  \"this content could not be displayed\": \"이 콘텐츠를 표시할 수 없습니다\",\n  \"This field cannot be empty or contain only spaces\": \"이 필드는 비워둘 수 없으며 공백만 포함할 수도 없습니다\",\n  \"This message did not meet our content guidelines\": \"이 메시지는 콘텐츠 가이드라인을 충족하지 않습니다.\",\n  \"Thread\": \"스레드\",\n  \"Thread has not been found\": \"스레드를 찾을 수 없습니다\",\n  \"Thread reply\": \"스레드 답장\",\n  \"Thread Reply\": \"스레드 답장\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"로딩 중...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"읽지 않은 스레드 {{ count }}개\",\n  \"Threads\": \"스레드\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[어제]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[오늘]\\\", \\\"nextDay\\\": \\\"[내일]\\\", \\\"lastDay\\\": \\\"[어제]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[지난] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"오늘\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"어제\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"브라우저에서 카메라 액세스를 허용하여 녹음을 시작합니다\",\n  \"To start recording, allow the microphone access in your browser\": \"브라우저에서 마이크로폰 액세스를 허용하여 녹음을 시작합니다\",\n  \"totalVoteCount_other\": \"총 {{ count }}표\",\n  \"Translated\": \"번역됨\",\n  \"Translated from {{ language }}\": \"{{ language }}(으)로 번역됨\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"2에서 10 사이의 숫자를 입력하세요\",\n  \"Unarchive\": \"아카이브 해제\",\n  \"unban-command-args\": \"[@사용자이름]\",\n  \"unban-command-description\": \"사용자 차단 해제\",\n  \"Unblock User\": \"사용자 차단 해제\",\n  \"unknown error\": \"알 수 없는 오류\",\n  \"Unmute\": \"음소거 해제\",\n  \"unmute-command-args\": \"[@사용자이름]\",\n  \"unmute-command-description\": \"사용자 음소거 해제\",\n  \"Unpin\": \"핀 해제\",\n  \"Unread messages\": \"읽지 않은 메시지\",\n  \"Unsupported attachment\": \"지원되지 않는 첨부 파일\",\n  \"unsupported file type\": \"지원되지 않는 파일 형식\",\n  \"Update\": \"업데이트\",\n  \"Update the comment attached to your poll answer\": \"투표 답변에 첨부된 댓글 업데이트\",\n  \"Update your comment\": \"댓글 업데이트\",\n  \"Upload blocked\": \"업로드가 차단되었습니다\",\n  \"Upload error\": \"업로드 오류\",\n  \"Upload failed\": \"업로드에 실패했습니다\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"업로드 유형: \\\"{{ type }}\\\"은(는) 허용되지 않습니다.\",\n  \"User blocked\": \"사용자가 차단됨\",\n  \"User unblocked\": \"사용자 차단이 해제됨\",\n  \"User uploaded content\": \"사용자 업로드 콘텐츠\",\n  \"Video\": \"동영상\",\n  \"videoCount_other\": \"동영상 {{ count }}개\",\n  \"View\": \"보기\",\n  \"View {{count}} comments_one\": \"{{count}}개의 댓글 보기\",\n  \"View {{count}} comments_other\": \"{{count}}개의 댓글 보기\",\n  \"View all\": \"전체 보기\",\n  \"View original\": \"원문 보기\",\n  \"View results\": \"결과 보기\",\n  \"View translation\": \"번역 보기\",\n  \"Voice message\": \"음성 메시지\",\n  \"Voice message {{ duration }}\": \"음성 메시지 {{ duration }}\",\n  \"Voice message deleted\": \"음성 메시지가 삭제됨\",\n  \"voiceMessageCount_other\": \"음성 메시지 {{ count }}개\",\n  \"Vote ended\": \"투표 종료\",\n  \"Votes\": \"투표\",\n  \"Wait until all attachments have uploaded\": \"모든 첨부 파일이 업로드될 때까지 기다립니다.\",\n  \"Waiting for network…\": \"네트워크 대기 중…\",\n  \"You\": \"당신\",\n  \"You've reached the maximum number of files\": \"최대 파일 수에 도달했습니다.\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} en {{ moreCount }} meer\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} en {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} bestand\",\n  \"{{ count }} files_other\": \"{{ count }} bestanden\",\n  \"{{ count }} people are typing_one\": \"{{ count }} persoon typt\",\n  \"{{ count }} people are typing_many\": \"{{ count }} personen typen\",\n  \"{{ count }} people are typing_other\": \"{{ count }} personen typen\",\n  \"{{ count }} photos_one\": \"{{ count }} foto\",\n  \"{{ count }} photos_other\": \"{{ count }} foto's\",\n  \"{{ count }} reactions_one\": \"{{ count }} reactie\",\n  \"{{ count }} reactions_other\": \"{{ count }} reacties\",\n  \"{{ count }} videos_one\": \"{{ count }} video\",\n  \"{{ count }} videos_other\": \"{{ count }} video's\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} en {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"+{{ imageCount }}\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} deelnemers\",\n  \"{{ typing }} are typing\": \"{{ typing }} typen\",\n  \"{{ typing }} is typing\": \"{{ typing }} typt\",\n  \"{{ user }} has been muted\": \"{{ user }} is gedempt\",\n  \"{{ user }} has been unmuted\": \"{{ user }} is niet meer gedempt\",\n  \"{{ user }} is typing...\": \"{{ user }} is aan het typen...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} en {{ user }} zijn aan het typen...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} en meer zijn aan het typen...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n  \"{{count}} new messages_one\": \"{{count}} nieuw bericht\",\n  \"{{count}} new messages_other\": \"{{count}} nieuwe berichten\",\n  \"{{count}} unread_one\": \"{{count}} ongelezen\",\n  \"{{count}} unread_other\": \"{{count}} ongelezen\",\n  \"{{count}} votes_one\": \"{{count}} stem\",\n  \"{{count}} votes_other\": \"{{count}} stemmen\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} meer optie\",\n  \"+{{count}} more options_other\": \"+{{count}} meer opties\",\n  \"🏙 Attachment...\": \"🏙 Bijlage...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} heeft gemaakt: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} heeft gestemd: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Gedeelde locatie\",\n  \"Add a comment\": \"Voeg een opmerking toe\",\n  \"Add a comment to your poll answer\": \"Voeg een reactie toe aan je pollantwoord\",\n  \"Add an option\": \"Voeg een optie toe\",\n  \"Add reaction\": \"Reactie toevoegen\",\n  \"All results loaded\": \"Alle resultaten geladen\",\n  \"Allow access to camera\": \"Toegang tot camera toestaan\",\n  \"Allow access to microphone\": \"Toegang tot microfoon toestaan\",\n  \"Allow comments\": \"Sta opmerkingen toe\",\n  \"Allow option suggestion\": \"Sta optie-suggesties toe\",\n  \"Allow others to add comments\": \"Sta anderen toe om opmerkingen toe te voegen\",\n  \"Also send as a direct message\": \"Ook als direct bericht versturen\",\n  \"Also send in channel\": \"Ook in kanaal versturen\",\n  \"Also sent in channel\": \"Ook in kanaal verzonden\",\n  \"An error has occurred during recording\": \"Er is een fout opgetreden tijdens het opnemen\",\n  \"An error has occurred during the recording processing\": \"Er is een fout opgetreden tijdens de verwerking van de opname\",\n  \"Anonymous\": \"Anoniem\",\n  \"Anonymous poll\": \"Anonieme peiling\",\n  \"Archive\": \"Archief\",\n  \"Are you sure you want to delete this message?\": \"Weet je zeker dat je dit bericht wilt verwijderen?\",\n  \"aria/Attachment\": \"Bijlage\",\n  \"aria/Attachment Actions\": \"Bijlageacties\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Audiopositie {{ elapsed }} van {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Audiopositie {{ progress }} procent\",\n  \"aria/Block User\": \"Gebruiker blokkeren\",\n  \"aria/Bookmark Message\": \"Bericht bookmarken\",\n  \"aria/Cancel recording\": \"Opname annuleren\",\n  \"aria/Cancel Reply\": \"Antwoord annuleren\",\n  \"aria/Cancel upload\": \"Upload annuleren\",\n  \"aria/Channel Actions\": \"Kanaalacties\",\n  \"aria/Channel list\": \"Kanaallijst\",\n  \"aria/Channel search results\": \"Zoekresultaten voor kanalen\",\n  \"aria/Chat view tabs\": \"Tabbladen chatweergave\",\n  \"aria/Clear search\": \"Zoekopdracht wissen\",\n  \"aria/Close callout dialog\": \"Calloutdialoog sluiten\",\n  \"aria/Close thread\": \"Draad sluiten\",\n  \"aria/Collapse sidebar\": \"Zijbalk samenklappen\",\n  \"aria/Command Suggestions\": \"Opdrachtsuggesties\",\n  \"aria/Complete recording\": \"Opname voltooien\",\n  \"aria/Copy Message Text\": \"Berichttekst kopiëren\",\n  \"aria/Decrease value\": \"Waarde verlagen\",\n  \"aria/Delete Message\": \"Bericht verwijderen\",\n  \"aria/Dismiss notification\": \"Melding sluiten\",\n  \"aria/Download attachment\": \"Bijlage downloaden\",\n  \"aria/Edit Message\": \"Bericht bewerken\",\n  \"aria/Emoji picker\": \"Emoji kiezer\",\n  \"aria/Emoji Suggestions\": \"Emoji-suggesties\",\n  \"aria/Exit search\": \"Zoeken afsluiten\",\n  \"aria/Expand sidebar\": \"Zijbalken uitvouwen\",\n  \"aria/File input\": \"Bestandsinvoer\",\n  \"aria/File upload\": \"Bestand uploaden\",\n  \"aria/Flag Message\": \"Bericht markeren\",\n  \"aria/Image failed to load\": \"Afbeelding laden mislukt\",\n  \"aria/Image input\": \"Afbeelding invoeren\",\n  \"aria/Increase value\": \"Waarde verhogen\",\n  \"aria/Jump to latest message\": \"Ga naar laatste bericht\",\n  \"aria/Jump to quoted message\": \"Ga naar geciteerd bericht\",\n  \"aria/Load More Channels\": \"Meer kanalen laden\",\n  \"aria/Mark Message Unread\": \"Markeren als ongelezen\",\n  \"aria/Mark messages as read\": \"Markeer berichten als gelezen\",\n  \"aria/Menu\": \"Menu\",\n  \"aria/Message Actions\": \"Berichtacties\",\n  \"aria/Message from {{ user }},\": \"Bericht van {{ user }},\",\n  \"aria/Message Options\": \"Berichtopties\",\n  \"aria/Message,\": \"Bericht,\",\n  \"aria/Mute User\": \"Gebruiker dempen\",\n  \"aria/Notifications\": \"Meldingen\",\n  \"aria/Open Attachment Selector\": \"Open bijlage selector\",\n  \"aria/Open Channel Actions Menu\": \"Kanaalactiemenu openen\",\n  \"aria/Open Menu\": \"Menu openen\",\n  \"aria/Open Message Actions Menu\": \"Menu voor berichtacties openen\",\n  \"aria/Open Reaction Selector\": \"Reactiekiezer openen\",\n  \"aria/Open Thread\": \"Draad openen\",\n  \"aria/Pause\": \"Pauzeren\",\n  \"aria/Pause recording\": \"Opname pauzeren\",\n  \"aria/Percent complete\": \"{{percent}} procent voltooid\",\n  \"aria/Pin Message\": \"Bericht vastmaken\",\n  \"aria/Play\": \"Afspelen\",\n  \"aria/Quote Message\": \"Bericht citeren\",\n  \"aria/Reaction list\": \"Reactielijst\",\n  \"aria/Remind Me Message\": \"Herinner mij\",\n  \"aria/Remind Me Options\": \"Herinneringsopties\",\n  \"aria/Remove attachment\": \"Bijlage verwijderen\",\n  \"aria/Remove location attachment\": \"Locatie bijlage verwijderen\",\n  \"aria/Remove option\": \"Optie verwijderen\",\n  \"aria/Remove Reminder\": \"Herinnering verwijderen\",\n  \"aria/Remove Save For Later\": \"Verwijder 'Bewaren voor later'\",\n  \"aria/Resend Message\": \"Bericht opnieuw verzenden\",\n  \"aria/Resume recording\": \"Opname hervatten\",\n  \"aria/Retry upload\": \"Upload opnieuw proberen\",\n  \"aria/Review bounced message\": \"Controleer teruggestuurd bericht\",\n  \"aria/Search results\": \"Zoekresultaten\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Filterknop koptekst zoekresultaten voor: {{ source }}\",\n  \"aria/Seek audio position\": \"Audiopositie zoeken\",\n  \"aria/Select Channel: {{ channelName }}\": \"Kanaal selecteren: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Reactie selecteren: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Gebruikerskanaal selecteren: {{ name }}\",\n  \"aria/Send\": \"Verzenden\",\n  \"aria/Show preview\": \"Voorbeeld tonen\",\n  \"aria/Start recording audio\": \"Audio-opname starten\",\n  \"aria/Stop AI Generation\": \"AI-generatie stoppen\",\n  \"aria/Suggestions\": \"Suggesties\",\n  \"aria/Thread list\": \"Threadlijst\",\n  \"aria/Unblock User\": \"Gebruiker deblokkeren\",\n  \"aria/Unmute User\": \"Dempen opheffen\",\n  \"aria/Unpin Message\": \"Losmaken\",\n  \"aria/User Suggestions\": \"Gebruikerssuggesties\",\n  \"Ask a question\": \"Stel een vraag\",\n  \"Attach\": \"Bijvoegen\",\n  \"Attach files\": \"Bijlage toevoegen\",\n  \"Attachment\": \"Bijlage\",\n  \"Attachment upload blocked due to {{reason}}\": \"Bijlage upload geblokkeerd vanwege {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Bijlage upload mislukt vanwege {{reason}}\",\n  \"Back\": \"Terug\",\n  \"ban-command-args\": \"[@gebruikersnaam] [tekst]\",\n  \"ban-command-description\": \"Een gebruiker verbannen\",\n  \"Block User\": \"Gebruiker blokkeren\",\n  \"Cancel\": \"Annuleer\",\n  \"Cannot seek in the recording\": \"Kan niet zoeken in de opname\",\n  \"Channel archived\": \"Kanaal gearchiveerd\",\n  \"Channel Missing\": \"Kanaal niet gevonden\",\n  \"Channel muted\": \"Kanaal gedempt\",\n  \"Channel pinned\": \"Kanaal vastgezet\",\n  \"Channel unarchived\": \"Kanaal uit archief gehaald\",\n  \"Channel unmuted\": \"Dempen van kanaal opgeheven\",\n  \"Channel unpinned\": \"Kanaal losgemaakt\",\n  \"Channels\": \"Kanalen\",\n  \"Chats\": \"Chats\",\n  \"Choose between 2 to 10 options\": \"Kies tussen 2 en 10 opties\",\n  \"Close\": \"Sluit\",\n  \"Close dialog\": \"Dialoog sluiten\",\n  \"Close emoji picker\": \"Sluit de emoji-kiezer\",\n  \"Close prompt: {{ title }}\": \"Prompt sluiten: {{ title }}\",\n  \"Command not available while editing\": \"Opdracht niet beschikbaar tijdens bewerken\",\n  \"Command not available while replying\": \"Opdracht niet beschikbaar tijdens beantwoorden\",\n  \"Commands\": \"Commando's\",\n  \"Commands matching\": \"Bijpassende opdrachten\",\n  \"Connection failure, reconnecting now...\": \"Verbindingsfout, opnieuw verbinden...\",\n  \"Copy Message\": \"Bericht kopiëren\",\n  \"Create\": \"Maak\",\n  \"Create a question, add options, and configure poll settings\": \"Maak een vraag, voeg opties toe en stel de pollinstellingen in\",\n  \"Create poll\": \"Maak peiling\",\n  \"Current location\": \"Huidige locatie\",\n  \"Delete\": \"Verwijder\",\n  \"Delete for me\": \"Voor mij verwijderen\",\n  \"Delete message\": \"Bericht verwijderen\",\n  \"Delivered\": \"Afgeleverd\",\n  \"Direct message\": \"Direct bericht\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Wil je deze peiling nu beëindigen? Niemand kan daarna meer op deze peiling stemmen.\",\n  \"Download All\": \"Alles downloaden\",\n  \"Download Attachment\": \"Bijlage downloaden\",\n  \"Download attachment {{ name }}\": \"Bijlage {{ name }} downloaden\",\n  \"Drag your files here\": \"Sleep je bestanden hier naartoe\",\n  \"Drag your files here to add to your post\": \"Sleep je bestanden hier naartoe om aan je bericht toe te voegen\",\n  \"Due {{ timeLeft }}\": \"Vervallen in {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Vervallen sinds {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Bericht bewerken\",\n  \"Edit message request failed\": \"Verzoek om bericht bewerken mislukt\",\n  \"Edited\": \"Bewerkt\",\n  \"Emoji matching\": \"Emoji-overeenkomsten\",\n  \"Empty message...\": \"Leeg bericht...\",\n  \"End\": \"Einde\",\n  \"End poll\": \"Peiling beëindigen\",\n  \"End this poll?\": \"Peiling beëindigen?\",\n  \"End vote\": \"Einde stem\",\n  \"Enforce unique vote is enabled\": \"Unieke stem is ingeschakeld\",\n  \"Error\": \"Fout\",\n  \"Error adding flag\": \"Fout bij toevoegen van vlag\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Fout bij het verbinden, ververs de pagina om nogmaals te proberen\",\n  \"Error deleting message\": \"Fout bij verwijderen van bericht\",\n  \"Error fetching reactions\": \"Fout bij het laden van reacties\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Fout bij markeren van bericht als ongelezen. Kan geen oudere ongelezen berichten markeren dan de nieuwste 100 kanaalberichten.\",\n  \"Error muting a user ...\": \"Fout bij het muten van de gebruiker\",\n  \"Error pinning message\": \"Fout bij vastzetten van bericht\",\n  \"Error removing message pin\": \"Fout bij verwijderen van berichtpin\",\n  \"Error reproducing the recording\": \"Fout bij het afspelen van de opname\",\n  \"Error starting recording\": \"Fout bij het starten van de opname\",\n  \"Error unmuting a user ...\": \"Fout bij het unmuten van de gebruiker\",\n  \"Error uploading attachment\": \"Fout bij het uploaden van de bijlage\",\n  \"Error uploading file\": \"Fout bij uploaden bestand\",\n  \"Error uploading image\": \"Fout bij uploaden afbeelding\",\n  \"Error: {{ errorMessage }}\": \"Fout: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Opdracht verlaten {{ command }}\",\n  \"Failed to block user\": \"Gebruiker blokkeren mislukt\",\n  \"Failed to create the poll\": \"Fout bij het maken van de peiling\",\n  \"Failed to create the poll due to {{reason}}\": \"Peiling kon niet worden aangemaakt vanwege {{reason}}\",\n  \"Failed to delete the message\": \"Bericht verwijderen mislukt\",\n  \"Failed to end the poll\": \"Peiling kon niet worden beëindigd\",\n  \"Failed to end the poll due to {{reason}}\": \"Peiling kon niet worden beëindigd vanwege {{reason}}\",\n  \"Failed to jump to the first unread message\": \"Niet gelukt om naar het eerste ongelezen bericht te springen\",\n  \"Failed to leave channel\": \"Kanaal verlaten mislukt\",\n  \"Failed to load channels\": \"Kanalen konden niet worden geladen\",\n  \"Failed to load more channels\": \"Meer kanalen konden niet worden geladen\",\n  \"Failed to mark channel as read\": \"Kanaal kon niet als gelezen worden gemarkeerd\",\n  \"Failed to play the recording\": \"Kan de opname niet afspelen\",\n  \"Failed to retrieve location\": \"Locatie kon niet worden opgehaald\",\n  \"Failed to share location\": \"Locatie kon niet worden gedeeld\",\n  \"Failed to update channel archive status\": \"Archiefstatus van kanaal kon niet worden bijgewerkt\",\n  \"Failed to update channel mute status\": \"Muteerstatus van kanaal kon niet worden bijgewerkt\",\n  \"Failed to update channel pinned status\": \"Vastgezette status van kanaal kon niet worden bijgewerkt\",\n  \"File\": \"Bestand\",\n  \"File is required for upload attachment\": \"Bestand is vereist voor het uploaden van een bijlage\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Bestand is te groot: {{ size }}, maximale uploadgrootte is {{ limit }}\",\n  \"File too large\": \"Bestand is te groot\",\n  \"fileCount_one\": \"1 bestand\",\n  \"fileCount_other\": \"{{ count }} bestanden\",\n  \"Flag\": \"Markeer\",\n  \"Generating...\": \"Genereren...\",\n  \"giphy-command-args\": \"[tekst]\",\n  \"giphy-command-description\": \"Plaats een willekeurige gif in het kanaal\",\n  \"Hide who voted\": \"Verberg wie heeft gestemd\",\n  \"Image\": \"Afbeelding\",\n  \"imageCount_one\": \"Afbeelding\",\n  \"imageCount_other\": \"{{ count }} afbeeldingen\",\n  \"Instant commands\": \"Snelle opdrachten\",\n  \"language/af\": \"Afrikaans\",\n  \"language/am\": \"Amhaars\",\n  \"language/ar\": \"Arabisch\",\n  \"language/az\": \"Azerbeidzjaans\",\n  \"language/bg\": \"Bulgaars\",\n  \"language/bn\": \"Bengaals\",\n  \"language/bs\": \"Bosnisch\",\n  \"language/cs\": \"Tsjechisch\",\n  \"language/da\": \"Deens\",\n  \"language/de\": \"Duits\",\n  \"language/el\": \"Grieks\",\n  \"language/en\": \"Engels\",\n  \"language/es\": \"Spaans\",\n  \"language/es-MX\": \"Spaans (Mexico)\",\n  \"language/et\": \"Estlands\",\n  \"language/fa\": \"Perzisch\",\n  \"language/fa-AF\": \"Dari\",\n  \"language/fi\": \"Fins\",\n  \"language/fr\": \"Frans\",\n  \"language/fr-CA\": \"Frans (Canada)\",\n  \"language/ha\": \"Hausa\",\n  \"language/he\": \"Hebreeuws\",\n  \"language/hi\": \"Hindi\",\n  \"language/hr\": \"Kroatisch\",\n  \"language/ht\": \"Haïtiaans Creools\",\n  \"language/hu\": \"Hongaars\",\n  \"language/id\": \"Indonesisch\",\n  \"language/it\": \"Italiaans\",\n  \"language/ja\": \"Japans\",\n  \"language/ka\": \"Georgisch\",\n  \"language/ko\": \"Koreaans\",\n  \"language/lt\": \"Litouws\",\n  \"language/lv\": \"Letlands\",\n  \"language/ms\": \"Maleis\",\n  \"language/nl\": \"Nederlands\",\n  \"language/no\": \"Noors\",\n  \"language/pl\": \"Pools\",\n  \"language/ps\": \"Pasjtoe\",\n  \"language/pt\": \"Portugees\",\n  \"language/ro\": \"Roemeens\",\n  \"language/ru\": \"Russisch\",\n  \"language/sk\": \"Slowaaks\",\n  \"language/sl\": \"Sloveens\",\n  \"language/so\": \"Somali\",\n  \"language/sq\": \"Albanees\",\n  \"language/sr\": \"Servisch\",\n  \"language/sv\": \"Zweeds\",\n  \"language/sw\": \"Swahili\",\n  \"language/ta\": \"Tamil\",\n  \"language/th\": \"Thai\",\n  \"language/tl\": \"Tagalog\",\n  \"language/tr\": \"Turks\",\n  \"language/uk\": \"Oekraïens\",\n  \"language/ur\": \"Urdu\",\n  \"language/vi\": \"Vietnamees\",\n  \"language/zh\": \"Chinees (vereenvoudigd)\",\n  \"language/zh-TW\": \"Chinees (traditioneel)\",\n  \"Leave Channel\": \"Kanaal verlaten\",\n  \"Left channel\": \"Kanaal verlaten\",\n  \"Let others add options\": \"Laat anderen opties toevoegen\",\n  \"Limit votes per person\": \"Stemmen per persoon beperken\",\n  \"Link\": \"Link\",\n  \"linkCount_one\": \"Link\",\n  \"linkCount_other\": \"{{ count }} links\",\n  \"live\": \"live\",\n  \"Live for {{duration}}\": \"Live voor {{duration}}\",\n  \"Live location\": \"Live locatie\",\n  \"Live until {{ timestamp }}\": \"Live tot {{ timestamp }}\",\n  \"Load more\": \"Meer laden\",\n  \"Local upload attachment missing local id\": \"Lokale uploadbijlage mist lokale id\",\n  \"Location\": \"Locatie\",\n  \"Location sharing ended\": \"Locatie delen beëindigd\",\n  \"Location: {{ coordinates }}\": \"Locatie: {{ coordinates }}\",\n  \"Mark as unread\": \"Markeren als ongelezen\",\n  \"Maximum number of votes (from 2 to 10)\": \"Maximaal aantal stemmen (van 2 tot 10)\",\n  \"Maximum votes per person\": \"Maximum aantal stemmen per persoon\",\n  \"Menu\": \"Menu\",\n  \"Message deleted\": \"Bericht verwijderd\",\n  \"Message failed to send\": \"Bericht kon niet worden verzonden\",\n  \"Message has been successfully flagged\": \"Bericht is succesvol gemarkeerd\",\n  \"Message marked as unread\": \"Bericht gemarkeerd als ongelezen\",\n  \"Message pinned\": \"Bericht vastgezet\",\n  \"Message unpinned\": \"Bericht losgemaakt\",\n  \"Message was blocked by moderation policies\": \"Bericht is geblokkeerd door moderatiebeleid\",\n  \"Messages have been marked unread.\": \"Berichten zijn gemarkeerd als ongelezen.\",\n  \"Missing permissions to upload the attachment\": \"Missende toestemmingen om de bijlage te uploaden\",\n  \"Multiple votes\": \"Meerdere stemmen\",\n  \"Mute\": \"Dempen\",\n  \"mute-command-args\": \"[@gebruikersnaam]\",\n  \"mute-command-description\": \"Een gebruiker dempen\",\n  \"network error\": \"netwerkfout\",\n  \"New\": \"Nieuwe\",\n  \"New message from {{user}}\": \"Nieuw bericht van {{user}}\",\n  \"New Messages!\": \"Nieuwe Berichten!\",\n  \"Next image\": \"Volgende afbeelding\",\n  \"No chats here yet…\": \"Nog geen chats hier...\",\n  \"No conversations yet\": \"Nog geen gesprekken\",\n  \"No items exist\": \"Er zijn geen items\",\n  \"No results found\": \"Geen resultaten gevonden\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Niemand kan meer stemmen in deze peiling.\",\n  \"Nothing yet...\": \"Nog niets ...\",\n  \"Offline\": \"Offline\",\n  \"Ok\": \"Oké\",\n  \"Online\": \"Online\",\n  \"Only numbers are allowed\": \"Alleen nummers zijn toegestaan\",\n  \"Only visible to you\": \"Alleen zichtbaar voor jou\",\n  \"Open emoji picker\": \"Emoji-kiezer openen\",\n  \"Open gallery at image {{ index }}\": \"Galerij openen bij afbeelding {{ index }}\",\n  \"Open image in gallery\": \"Afbeelding openen in galerij\",\n  \"Open location in a map\": \"Locatie op een kaart openen\",\n  \"Option already exists\": \"Optie bestaat al\",\n  \"Option is empty\": \"Optie is leeg\",\n  \"Options\": \"Opties\",\n  \"Original\": \"Origineel\",\n  \"People matching\": \"Mensen die matchen\",\n  \"Photo\": \"Foto\",\n  \"Pin\": \"Vastmaken\",\n  \"Pinned by {{ name }}\": \"Vastgemaakt door {{ name }}\",\n  \"Pinned by You\": \"Door jou vastgezet\",\n  \"placeholder/PollComment\": \"Jouw reactie\",\n  \"placeholder/PollOptionSuggestion\": \"Voer een nieuwe optie in\",\n  \"Play video\": \"Video afspelen\",\n  \"Playback speed {{ rate }}x\": \"Afspeelsnelheid {{ rate }}x\",\n  \"Poll\": \"Peiling\",\n  \"Poll comments\": \"Peiling opmerkingen\",\n  \"Poll ended\": \"Peiling beëindigd\",\n  \"Poll options\": \"Peiling opties\",\n  \"Poll results\": \"Peiling resultaten\",\n  \"Previous image\": \"Vorige afbeelding\",\n  \"Question\": \"Vraag\",\n  \"Question {{ optionOrderNumber}}\": \"Vraag {{ optionOrderNumber}}\",\n  \"Question is required\": \"Vraag is verplicht\",\n  \"Quote Reply\": \"Citaatantwoord\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Stemlimiet bereikt. Verwijder eerst een bestaande stem.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Opnameformaat wordt niet ondersteund en kan niet worden gereproduceerd\",\n  \"Remind me\": \"Herinner me\",\n  \"Remind Me\": \"Herinner mij\",\n  \"Reminder set\": \"Herinnering ingesteld\",\n  \"Remove reminder\": \"Herinnering verwijderen\",\n  \"Remove save for later\": \"Verwijder 'Bewaren voor later'\",\n  \"Replied to a thread\": \"Heeft gereageerd in een thread\",\n  \"Reply\": \"Antwoord\",\n  \"Reply to {{ authorName }}\": \"Antwoord aan {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Beantwoord een bericht om een thread te starten\",\n  \"Reply to Message\": \"Antwoord op bericht\",\n  \"replyCount_one\": \"1 antwoord\",\n  \"replyCount_other\": \"{{ count }} antwoorden\",\n  \"Resend\": \"Opnieuw verzenden\",\n  \"Retry upload\": \"Upload opnieuw proberen\",\n  \"Review all options available in this poll\": \"Bekijk alle beschikbare opties in deze poll\",\n  \"Review comments submitted with poll answers\": \"Bekijk reacties die met pollantwoorden zijn ingediend\",\n  \"Review poll results and open an option to see detailed votes\": \"Bekijk pollresultaten en open een optie om gedetailleerde stemmen te zien\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Bekijk dit bericht en kies of je het verwijdert, bewerkt of toch verstuurt\",\n  \"Review who voted for this option\": \"Bekijk wie op deze optie heeft gestemd\",\n  \"Save for later\": \"Bewaren voor later\",\n  \"Saved for later\": \"Bewaard voor later\",\n  \"Search\": \"Zoeken\",\n  \"Search GIFs\": \"GIF's zoeken\",\n  \"search-results-header-filter-source-button-label--channels\": \"kanalen\",\n  \"search-results-header-filter-source-button-label--messages\": \"berichten\",\n  \"search-results-header-filter-source-button-label--users\": \"gebruikers\",\n  \"Searching for {{ searchSourceType }}...\": \"Zoeken naar {{ searchSourceType }}...\",\n  \"Searching...\": \"Zoeken...\",\n  \"searchResultsCount_one\": \"1 resultaat\",\n  \"searchResultsCount_other\": \"{{ count }} resultaten\",\n  \"Select a thread to continue the conversation\": \"Selecteer een thread om het gesprek voort te zetten\",\n  \"Select more than one option\": \"Selecteer meer dan één optie\",\n  \"Select one\": \"Selecteer er een\",\n  \"Select one or more\": \"Selecteer een of meer\",\n  \"Select up to {{count}}_one\": \"Selecteer tot {{count}}\",\n  \"Select up to {{count}}_other\": \"Selecteer tot {{count}}\",\n  \"Select your current location and optionally enable live location sharing\": \"Selecteer je huidige locatie en schakel eventueel live locatiedeling in\",\n  \"Send\": \"Verstuur\",\n  \"Send a message\": \"Stuur een bericht\",\n  \"Send a message to start the conversation\": \"Stuur een bericht om het gesprek te beginnen\",\n  \"Send Anyway\": \"Toch versturen\",\n  \"Send message request failed\": \"Verzoek om bericht te verzenden mislukt\",\n  \"Send poll\": \"Peiling versturen\",\n  \"Sending...\": \"Aan het verzenden...\",\n  \"Sent\": \"Verzonden\",\n  \"Share\": \"Delen\",\n  \"Share live location for\": \"Live locatie delen voor\",\n  \"Share Location\": \"Locatie delen\",\n  \"Shared live location\": \"Gedeelde live locatie\",\n  \"Shared location\": \"Gedeelde locatie\",\n  \"Shuffle\": \"Schudden\",\n  \"size limit\": \"grootte limiet\",\n  \"Slow Mode ON\": \"Langzame modus aan\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Langzame modus, wacht {{ seconds }}s...\",\n  \"Slow wait, wait {{ seconds }}s\": \"Langzame modus, wacht {{ seconds }}s\",\n  \"Slow wait, wait {{ seconds }}s...\": \"Langzame modus, wacht {{ seconds }}s...\",\n  \"Some of the files will not be accepted\": \"Sommige bestanden zullen niet worden geaccepteerd\",\n  \"Start typing to search\": \"Begin met typen om te zoeken\",\n  \"Stop sharing\": \"Delen stoppen\",\n  \"Submit\": \"Versturen\",\n  \"Suggest a new option to add to this poll\": \"Stel een nieuwe optie voor om aan deze poll toe te voegen\",\n  \"Suggest an option\": \"Stel een optie voor\",\n  \"Tap to remove\": \"Tik om te verwijderen\",\n  \"Tap to remove: {{ reactionName }}\": \"Tik om te verwijderen: {{ reactionName }}\",\n  \"Thinking...\": \"Denken...\",\n  \"this content could not be displayed\": \"Deze inhoud kan niet weergegeven worden\",\n  \"This field cannot be empty or contain only spaces\": \"Dit veld mag niet leeg zijn of alleen spaties bevatten\",\n  \"This message did not meet our content guidelines\": \"Dit bericht voldeed niet aan onze inhoudsrichtlijnen\",\n  \"Thread\": \"Draadje\",\n  \"Thread has not been found\": \"Draadje niet gevonden\",\n  \"Thread reply\": \"Draadje antwoord\",\n  \"Thread Reply\": \"Draadje antwoord\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Laden...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} ongelezen thread\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} ongelezen threads\",\n  \"Threads\": \"Discussies\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Gisteren]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Vandaag]\\\", \\\"nextDay\\\": \\\"[Morgen]\\\", \\\"lastDay\\\": \\\"[Gisteren]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Laatste] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Vandaag\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Gisteren\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Om te beginnen met opnemen, sta toegang tot de camera toe in uw browser\",\n  \"To start recording, allow the microphone access in your browser\": \"Om te beginnen met opnemen, sta toegang tot de microfoon toe in uw browser\",\n  \"totalVoteCount_one\": \"1 stem in totaal\",\n  \"totalVoteCount_other\": \"{{ count }} stemmen in totaal\",\n  \"Translated\": \"Vertaald\",\n  \"Translated from {{ language }}\": \"Vertaald uit {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Typ een getal van 2 tot 10\",\n  \"Unarchive\": \"Uit archief halen\",\n  \"unban-command-args\": \"[@gebruikersnaam]\",\n  \"unban-command-description\": \"Een gebruiker debannen\",\n  \"Unblock User\": \"Gebruiker deblokkeren\",\n  \"unknown error\": \"onbekende fout\",\n  \"Unmute\": \"Dempen opheffen\",\n  \"unmute-command-args\": \"[@gebruikersnaam]\",\n  \"unmute-command-description\": \"Een gebruiker niet meer dempen\",\n  \"Unpin\": \"Losmaken\",\n  \"Unread messages\": \"Ongelezen berichten\",\n  \"Unsupported attachment\": \"Niet-ondersteunde bijlage\",\n  \"unsupported file type\": \"niet-ondersteund bestandstype\",\n  \"Update\": \"Bijwerken\",\n  \"Update the comment attached to your poll answer\": \"Werk de reactie bij die aan je pollantwoord is toegevoegd\",\n  \"Update your comment\": \"Werk je opmerking bij\",\n  \"Upload blocked\": \"Upload geblokkeerd\",\n  \"Upload error\": \"Uploadfout\",\n  \"Upload failed\": \"Upload mislukt\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Uploadtype: \\\"{{ type }}\\\" is niet toegestaan\",\n  \"User blocked\": \"Gebruiker geblokkeerd\",\n  \"User unblocked\": \"Gebruiker gedeblokkeerd\",\n  \"User uploaded content\": \"Gebruikersgeüploade inhoud\",\n  \"Video\": \"Video\",\n  \"videoCount_one\": \"Video\",\n  \"videoCount_other\": \"{{ count }} video's\",\n  \"View\": \"Bekijken\",\n  \"View {{count}} comments_one\": \"Bekijk {{count}} opmerkingen\",\n  \"View {{count}} comments_other\": \"Bekijk {{count}} opmerkingen\",\n  \"View all\": \"Alles bekijken\",\n  \"View original\": \"Origineel bekijken\",\n  \"View results\": \"Bekijk resultaten\",\n  \"View translation\": \"Vertaling bekijken\",\n  \"Voice message\": \"Spraakbericht\",\n  \"Voice message {{ duration }}\": \"Spraakbericht {{ duration }}\",\n  \"Voice message deleted\": \"Spraakbericht verwijderd\",\n  \"voiceMessageCount_one\": \"Spraakbericht\",\n  \"voiceMessageCount_other\": \"{{ count }} spraakberichten\",\n  \"Vote ended\": \"Stemmen beëindigd\",\n  \"Votes\": \"Stemmen\",\n  \"Wait until all attachments have uploaded\": \"Wacht tot alle bijlagen zijn geüpload\",\n  \"Waiting for network…\": \"Wachten op netwerk…\",\n  \"You\": \"Jij\",\n  \"You've reached the maximum number of files\": \"Je hebt het maximale aantal bestanden bereikt\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} e mais {{ moreCount }}\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} e {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} arquivo\",\n  \"{{ count }} files_many\": \"{{ count }} arquivos\",\n  \"{{ count }} files_other\": \"{{ count }} arquivos\",\n  \"{{ count }} people are typing_one\": \"{{ count }} pessoa está digitando\",\n  \"{{ count }} people are typing_many\": \"{{ count }} pessoas estão digitando\",\n  \"{{ count }} people are typing_other\": \"{{ count }} pessoas estão digitando\",\n  \"{{ count }} photos_one\": \"{{ count }} foto\",\n  \"{{ count }} photos_many\": \"{{ count }} fotos\",\n  \"{{ count }} photos_other\": \"{{ count }} fotos\",\n  \"{{ count }} reactions_one\": \"{{ count }} reação\",\n  \"{{ count }} reactions_many\": \"{{ count }} reações\",\n  \"{{ count }} reactions_other\": \"{{ count }} reações\",\n  \"{{ count }} videos_one\": \"{{ count }} vídeo\",\n  \"{{ count }} videos_many\": \"{{ count }} vídeos\",\n  \"{{ count }} videos_other\": \"{{ count }} vídeos\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} e {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} mais\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} membros\",\n  \"{{ typing }} are typing\": \"{{ typing }} estão digitando\",\n  \"{{ typing }} is typing\": \"{{ typing }} está digitando\",\n  \"{{ user }} has been muted\": \"{{ user }} foi silenciado\",\n  \"{{ user }} has been unmuted\": \"{{ user }} foi reativado\",\n  \"{{ user }} is typing...\": \"{{ user }} está digitando...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} e {{ user }} estão digitando...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} e mais estão digitando...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n  \"{{count}} new messages_one\": \"{{count}} nova mensagem\",\n  \"{{count}} new messages_many\": \"{{count}} novas mensagens\",\n  \"{{count}} new messages_other\": \"{{count}} novas mensagens\",\n  \"{{count}} unread_one\": \"{{count}} não lido\",\n  \"{{count}} unread_many\": \"{{count}} não lidos\",\n  \"{{count}} unread_other\": \"{{count}} não lidos\",\n  \"{{count}} votes_one\": \"{{count}} voto\",\n  \"{{count}} votes_many\": \"{{count}} votos\",\n  \"{{count}} votes_other\": \"{{count}} votos\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} opção a mais\",\n  \"+{{count}} more options_many\": \"+{{count}} opções a mais\",\n  \"+{{count}} more options_other\": \"+{{count}} opções a mais\",\n  \"🏙 Attachment...\": \"🏙 Anexo...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} criou: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} votou: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Localização compartilhada\",\n  \"Add a comment\": \"Adicionar um comentário\",\n  \"Add a comment to your poll answer\": \"Adicione um comentário à sua resposta da enquete\",\n  \"Add an option\": \"Adicionar uma opção\",\n  \"Add reaction\": \"Adicionar reação\",\n  \"All results loaded\": \"Todos os resultados carregados\",\n  \"Allow access to camera\": \"Permitir acesso à câmera\",\n  \"Allow access to microphone\": \"Permitir acesso ao microfone\",\n  \"Allow comments\": \"Permitir comentários\",\n  \"Allow option suggestion\": \"Permitir sugestão de opção\",\n  \"Allow others to add comments\": \"Permitir que outros adicionem comentários\",\n  \"Also send as a direct message\": \"Também enviar como mensagem direta\",\n  \"Also send in channel\": \"Também enviar no canal\",\n  \"Also sent in channel\": \"Também enviado no canal\",\n  \"An error has occurred during recording\": \"Ocorreu um erro durante a gravação\",\n  \"An error has occurred during the recording processing\": \"Ocorreu um erro durante o processamento da gravação\",\n  \"Anonymous\": \"Anônimo\",\n  \"Anonymous poll\": \"Enquete anônima\",\n  \"Archive\": \"Arquivar\",\n  \"Are you sure you want to delete this message?\": \"Tem certeza de que deseja excluir esta mensagem?\",\n  \"aria/Attachment\": \"Anexo\",\n  \"aria/Attachment Actions\": \"Ações do anexo\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Posição do áudio {{ elapsed }} de {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Posição do áudio {{ progress }} por cento\",\n  \"aria/Block User\": \"Bloquear usuário\",\n  \"aria/Bookmark Message\": \"Marcar mensagem\",\n  \"aria/Cancel recording\": \"Cancelar gravação\",\n  \"aria/Cancel Reply\": \"Cancelar resposta\",\n  \"aria/Cancel upload\": \"Cancelar upload\",\n  \"aria/Channel Actions\": \"Ações do canal\",\n  \"aria/Channel list\": \"Lista de canais\",\n  \"aria/Channel search results\": \"Resultados de pesquisa de canais\",\n  \"aria/Chat view tabs\": \"Abas da visualização do chat\",\n  \"aria/Clear search\": \"Limpar pesquisa\",\n  \"aria/Close callout dialog\": \"Fechar diálogo de destaque\",\n  \"aria/Close thread\": \"Fechar tópico\",\n  \"aria/Collapse sidebar\": \"Recolher barra lateral\",\n  \"aria/Command Suggestions\": \"Sugestões de comandos\",\n  \"aria/Complete recording\": \"Concluir gravação\",\n  \"aria/Copy Message Text\": \"Copiar texto da mensagem\",\n  \"aria/Decrease value\": \"Diminuir valor\",\n  \"aria/Delete Message\": \"Excluir mensagem\",\n  \"aria/Dismiss notification\": \"Dispensar notificação\",\n  \"aria/Download attachment\": \"Baixar anexo\",\n  \"aria/Edit Message\": \"Editar Mensagem\",\n  \"aria/Emoji picker\": \"Seletor de emojis\",\n  \"aria/Emoji Suggestions\": \"Sugestões de emojis\",\n  \"aria/Exit search\": \"Sair da pesquisa\",\n  \"aria/Expand sidebar\": \"Expandir barra lateral\",\n  \"aria/File input\": \"Entrada de arquivo\",\n  \"aria/File upload\": \"Carregar arquivo\",\n  \"aria/Flag Message\": \"Reportar mensagem\",\n  \"aria/Image failed to load\": \"Falha ao carregar a imagem\",\n  \"aria/Image input\": \"Entrada de imagem\",\n  \"aria/Increase value\": \"Aumentar valor\",\n  \"aria/Jump to latest message\": \"Ir para a mensagem mais recente\",\n  \"aria/Jump to quoted message\": \"Ir para a mensagem citada\",\n  \"aria/Load More Channels\": \"Carregar mais canais\",\n  \"aria/Mark Message Unread\": \"Marcar como não lida\",\n  \"aria/Mark messages as read\": \"Marcar mensagens como lidas\",\n  \"aria/Menu\": \"Menu\",\n  \"aria/Message Actions\": \"Ações da mensagem\",\n  \"aria/Message from {{ user }},\": \"Mensagem de {{ user }},\",\n  \"aria/Message Options\": \"Opções de mensagem\",\n  \"aria/Message,\": \"Mensagem,\",\n  \"aria/Mute User\": \"Silenciar usuário\",\n  \"aria/Notifications\": \"Notificações\",\n  \"aria/Open Attachment Selector\": \"Abrir seletor de anexos\",\n  \"aria/Open Channel Actions Menu\": \"Abrir menu de ações do canal\",\n  \"aria/Open Menu\": \"Abrir menu\",\n  \"aria/Open Message Actions Menu\": \"Abrir menu de ações de mensagem\",\n  \"aria/Open Reaction Selector\": \"Abrir seletor de reações\",\n  \"aria/Open Thread\": \"Abrir tópico\",\n  \"aria/Pause\": \"Pausar\",\n  \"aria/Pause recording\": \"Pausar gravação\",\n  \"aria/Percent complete\": \"{{percent}} por cento concluído\",\n  \"aria/Pin Message\": \"Fixar mensagem\",\n  \"aria/Play\": \"Reproduzir\",\n  \"aria/Quote Message\": \"Citar mensagem\",\n  \"aria/Reaction list\": \"Lista de reações\",\n  \"aria/Remind Me Message\": \"Lembrar-me\",\n  \"aria/Remind Me Options\": \"Opções de lembrete\",\n  \"aria/Remove attachment\": \"Remover anexo\",\n  \"aria/Remove location attachment\": \"Remover anexo de localização\",\n  \"aria/Remove option\": \"Remover opção\",\n  \"aria/Remove Reminder\": \"Remover lembrete\",\n  \"aria/Remove Save For Later\": \"Remover Salvar para depois\",\n  \"aria/Resend Message\": \"Reenviar mensagem\",\n  \"aria/Resume recording\": \"Retomar gravação\",\n  \"aria/Retry upload\": \"Tentar upload novamente\",\n  \"aria/Review bounced message\": \"Revisar mensagem devolvida\",\n  \"aria/Search results\": \"Resultados da pesquisa\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Botão de filtro do cabeçalho dos resultados da pesquisa para: {{ source }}\",\n  \"aria/Seek audio position\": \"Buscar posição do áudio\",\n  \"aria/Select Channel: {{ channelName }}\": \"Selecionar canal: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Selecionar reação: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Selecionar canal do usuário: {{ name }}\",\n  \"aria/Send\": \"Enviar\",\n  \"aria/Show preview\": \"Mostrar prévia\",\n  \"aria/Start recording audio\": \"Iniciar gravação de áudio\",\n  \"aria/Stop AI Generation\": \"Parar geração de IA\",\n  \"aria/Suggestions\": \"Sugestões\",\n  \"aria/Thread list\": \"Lista de tópicos\",\n  \"aria/Unblock User\": \"Desbloquear usuário\",\n  \"aria/Unmute User\": \"Ativar som\",\n  \"aria/Unpin Message\": \"Desfixar mensagem\",\n  \"aria/User Suggestions\": \"Sugestões de usuários\",\n  \"Ask a question\": \"Faça uma pergunta\",\n  \"Attach\": \"Anexar\",\n  \"Attach files\": \"Anexar arquivos\",\n  \"Attachment\": \"Anexo\",\n  \"Attachment upload blocked due to {{reason}}\": \"Upload de anexo bloqueado devido a {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Upload de anexo falhou devido a {{reason}}\",\n  \"Back\": \"Voltar\",\n  \"ban-command-args\": \"[@nomedeusuário] [texto]\",\n  \"ban-command-description\": \"Banir um usuário\",\n  \"Block User\": \"Bloquear usuário\",\n  \"Cancel\": \"Cancelar\",\n  \"Cannot seek in the recording\": \"Não é possível buscar na gravação\",\n  \"Channel archived\": \"Canal arquivado\",\n  \"Channel Missing\": \"Canal ausente\",\n  \"Channel muted\": \"Canal silenciado\",\n  \"Channel pinned\": \"Canal fixado\",\n  \"Channel unarchived\": \"Canal desarquivado\",\n  \"Channel unmuted\": \"Silêncio do canal desativado\",\n  \"Channel unpinned\": \"Canal desafixado\",\n  \"Channels\": \"Canais\",\n  \"Chats\": \"Conversas\",\n  \"Choose between 2 to 10 options\": \"Escolha entre 2 a 10 opções\",\n  \"Close\": \"Fechar\",\n  \"Close dialog\": \"Fechar diálogo\",\n  \"Close emoji picker\": \"Fechar seletor de emoji\",\n  \"Close prompt: {{ title }}\": \"Fechar prompt: {{ title }}\",\n  \"Command not available while editing\": \"Comando não disponível durante a edição\",\n  \"Command not available while replying\": \"Comando não disponível durante a resposta\",\n  \"Commands\": \"Comandos\",\n  \"Commands matching\": \"Comandos correspondentes\",\n  \"Connection failure, reconnecting now...\": \"Falha de conexão, reconectando agora...\",\n  \"Copy Message\": \"Copiar mensagem\",\n  \"Create\": \"Criar\",\n  \"Create a question, add options, and configure poll settings\": \"Crie uma pergunta, adicione opções e configure as definições da enquete\",\n  \"Create poll\": \"Criar enquete\",\n  \"Current location\": \"Localização atual\",\n  \"Delete\": \"Excluir\",\n  \"Delete for me\": \"Excluir para mim\",\n  \"Delete message\": \"Excluir mensagem\",\n  \"Delivered\": \"Entregue\",\n  \"Direct message\": \"Mensagem direta\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Deseja encerrar esta enquete agora? Ninguém poderá mais votar nesta enquete.\",\n  \"Download All\": \"Baixar tudo\",\n  \"Download Attachment\": \"Baixar anexo\",\n  \"Download attachment {{ name }}\": \"Baixar anexo {{ name }}\",\n  \"Drag your files here\": \"Arraste seus arquivos aqui\",\n  \"Drag your files here to add to your post\": \"Arraste seus arquivos aqui para adicionar ao seu post\",\n  \"Due {{ timeLeft }}\": \"Vence em {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Vencido desde {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Editar Mensagem\",\n  \"Edit message request failed\": \"O pedido de edição da mensagem falhou\",\n  \"Edited\": \"Editada\",\n  \"Emoji matching\": \"Emoji correspondente\",\n  \"Empty message...\": \"Mensagem vazia...\",\n  \"End\": \"Fim\",\n  \"End poll\": \"Encerrar enquete\",\n  \"End this poll?\": \"Encerrar esta enquete?\",\n  \"End vote\": \"Encerrar votação\",\n  \"Enforce unique vote is enabled\": \"Voto único está habilitado\",\n  \"Error\": \"Erro\",\n  \"Error adding flag\": \"Erro ao reportar\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Erro ao conectar ao bate-papo, atualize a página para tentar novamente.\",\n  \"Error deleting message\": \"Erro ao deletar mensagem\",\n  \"Error fetching reactions\": \"Erro ao carregar reações\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Erro ao marcar a mensagem como não lida. Não é possível marcar mensagens não lidas mais antigas do que as 100 mensagens mais recentes do canal.\",\n  \"Error muting a user ...\": \"Erro ao silenciar um usuário...\",\n  \"Error pinning message\": \"Erro ao fixar mensagem\",\n  \"Error removing message pin\": \"Erro ao remover o PIN da mensagem\",\n  \"Error reproducing the recording\": \"Erro ao reproduzir a gravação\",\n  \"Error starting recording\": \"Erro ao iniciar a gravação\",\n  \"Error unmuting a user ...\": \"Erro ao ativar o som de um usuário...\",\n  \"Error uploading attachment\": \"Erro ao carregar o anexo\",\n  \"Error uploading file\": \"Erro ao enviar arquivo\",\n  \"Error uploading image\": \"Erro ao carregar a imagem\",\n  \"Error: {{ errorMessage }}\": \"Erro: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Sair do comando {{ command }}\",\n  \"Failed to block user\": \"Falha ao bloquear o usuário\",\n  \"Failed to create the poll\": \"Falha ao criar a pesquisa\",\n  \"Failed to create the poll due to {{reason}}\": \"Falha ao criar a enquete devido a {{reason}}\",\n  \"Failed to delete the message\": \"Falha ao excluir a mensagem\",\n  \"Failed to end the poll\": \"Falha ao encerrar a enquete\",\n  \"Failed to end the poll due to {{reason}}\": \"Falha ao encerrar a enquete devido a {{reason}}\",\n  \"Failed to jump to the first unread message\": \"Falha ao pular para a primeira mensagem não lida\",\n  \"Failed to leave channel\": \"Falha ao sair do canal\",\n  \"Failed to load channels\": \"Falha ao carregar os canais\",\n  \"Failed to load more channels\": \"Falha ao carregar mais canais\",\n  \"Failed to mark channel as read\": \"Falha ao marcar o canal como lido\",\n  \"Failed to play the recording\": \"Falha ao reproduzir a gravação\",\n  \"Failed to retrieve location\": \"Falha ao obter localização\",\n  \"Failed to share location\": \"Falha ao compartilhar localização\",\n  \"Failed to update channel archive status\": \"Falha ao atualizar o status de arquivamento do canal\",\n  \"Failed to update channel mute status\": \"Falha ao atualizar o status de mudo do canal\",\n  \"Failed to update channel pinned status\": \"Falha ao atualizar o status de fixação do canal\",\n  \"File\": \"Arquivo\",\n  \"File is required for upload attachment\": \"Arquivo é necessário para enviar o anexo\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"O arquivo é muito grande: {{ size }}, o tamanho máximo de upload é {{ limit }}\",\n  \"File too large\": \"Arquivo muito grande\",\n  \"fileCount_one\": \"1 arquivo\",\n  \"fileCount_many\": \"{{ count }} arquivos\",\n  \"fileCount_other\": \"{{ count }} arquivos\",\n  \"Flag\": \"Reportar\",\n  \"Generating...\": \"Gerando...\",\n  \"giphy-command-args\": \"[texto]\",\n  \"giphy-command-description\": \"Postar um gif aleatório no canal\",\n  \"Hide who voted\": \"Ocultar quem votou\",\n  \"Image\": \"Imagem\",\n  \"imageCount_one\": \"Imagem\",\n  \"imageCount_many\": \"{{ count }} imagens\",\n  \"imageCount_other\": \"{{ count }} imagens\",\n  \"Instant commands\": \"Comandos instantâneos\",\n  \"language/af\": \"Africâner\",\n  \"language/am\": \"Amárico\",\n  \"language/ar\": \"Árabe\",\n  \"language/az\": \"Azerbaijano\",\n  \"language/bg\": \"Búlgaro\",\n  \"language/bn\": \"Bengali\",\n  \"language/bs\": \"Bósnio\",\n  \"language/cs\": \"Tcheco\",\n  \"language/da\": \"Dinamarquês\",\n  \"language/de\": \"Alemão\",\n  \"language/el\": \"Grego\",\n  \"language/en\": \"Inglês\",\n  \"language/es\": \"Espanhol\",\n  \"language/es-MX\": \"Espanhol (México)\",\n  \"language/et\": \"Estoniano\",\n  \"language/fa\": \"Persa\",\n  \"language/fa-AF\": \"Dari\",\n  \"language/fi\": \"Finlandês\",\n  \"language/fr\": \"Francês\",\n  \"language/fr-CA\": \"Francês (Canadá)\",\n  \"language/ha\": \"Hauçá\",\n  \"language/he\": \"Hebraico\",\n  \"language/hi\": \"Hindi\",\n  \"language/hr\": \"Croata\",\n  \"language/ht\": \"Crioulo haitiano\",\n  \"language/hu\": \"Húngaro\",\n  \"language/id\": \"Indonésio\",\n  \"language/it\": \"Italiano\",\n  \"language/ja\": \"Japonês\",\n  \"language/ka\": \"Georgiano\",\n  \"language/ko\": \"Coreano\",\n  \"language/lt\": \"Lituano\",\n  \"language/lv\": \"Letão\",\n  \"language/ms\": \"Malaio\",\n  \"language/nl\": \"Holandês\",\n  \"language/no\": \"Norueguês\",\n  \"language/pl\": \"Polonês\",\n  \"language/ps\": \"Pashto\",\n  \"language/pt\": \"Português\",\n  \"language/ro\": \"Romeno\",\n  \"language/ru\": \"Russo\",\n  \"language/sk\": \"Eslovaco\",\n  \"language/sl\": \"Esloveno\",\n  \"language/so\": \"Somali\",\n  \"language/sq\": \"Albanês\",\n  \"language/sr\": \"Sérvio\",\n  \"language/sv\": \"Sueco\",\n  \"language/sw\": \"Suaíli\",\n  \"language/ta\": \"Tâmil\",\n  \"language/th\": \"Tailandês\",\n  \"language/tl\": \"Tagalo\",\n  \"language/tr\": \"Turco\",\n  \"language/uk\": \"Ucraniano\",\n  \"language/ur\": \"Urdu\",\n  \"language/vi\": \"Vietnamita\",\n  \"language/zh\": \"Chinês (simplificado)\",\n  \"language/zh-TW\": \"Chinês (tradicional)\",\n  \"Leave Channel\": \"Sair do canal\",\n  \"Left channel\": \"Canal abandonado\",\n  \"Let others add options\": \"Permitir que outros adicionem opções\",\n  \"Limit votes per person\": \"Limitar votos por pessoa\",\n  \"Link\": \"Link\",\n  \"linkCount_one\": \"Link\",\n  \"linkCount_many\": \"{{ count }} links\",\n  \"linkCount_other\": \"{{ count }} links\",\n  \"live\": \"ao vivo\",\n  \"Live for {{duration}}\": \"Ao vivo por {{duration}}\",\n  \"Live location\": \"Localização ao vivo\",\n  \"Live until {{ timestamp }}\": \"Ao vivo até {{ timestamp }}\",\n  \"Load more\": \"Carregar mais\",\n  \"Local upload attachment missing local id\": \"Anexo de envio local sem id local\",\n  \"Location\": \"Localização\",\n  \"Location sharing ended\": \"Compartilhamento de localização encerrado\",\n  \"Location: {{ coordinates }}\": \"Localização: {{ coordinates }}\",\n  \"Mark as unread\": \"Marcar como não lida\",\n  \"Maximum number of votes (from 2 to 10)\": \"Número máximo de votos (de 2 a 10)\",\n  \"Maximum votes per person\": \"Máximo de votos por pessoa\",\n  \"Menu\": \"Menu\",\n  \"Message deleted\": \"Mensagem apagada\",\n  \"Message failed to send\": \"Falha ao enviar a mensagem\",\n  \"Message has been successfully flagged\": \"A mensagem foi reportada com sucesso\",\n  \"Message marked as unread\": \"Mensagem marcada como não lida\",\n  \"Message pinned\": \"Mensagem fixada\",\n  \"Message unpinned\": \"Mensagem desafixada\",\n  \"Message was blocked by moderation policies\": \"A mensagem foi bloqueada pelas políticas de moderação\",\n  \"Messages have been marked unread.\": \"Mensagens foram marcadas como não lidas.\",\n  \"Missing permissions to upload the attachment\": \"Faltando permissões para enviar o anexo\",\n  \"Multiple votes\": \"Votos múltiplos\",\n  \"Mute\": \"Silenciar\",\n  \"mute-command-args\": \"[@nomedeusuário]\",\n  \"mute-command-description\": \"Silenciar um usuário\",\n  \"network error\": \"erro de rede\",\n  \"New\": \"Novo\",\n  \"New message from {{user}}\": \"Nova mensagem de {{user}}\",\n  \"New Messages!\": \"Novas Mensagens!\",\n  \"Next image\": \"Próxima imagem\",\n  \"No chats here yet…\": \"Ainda não há conversas aqui...\",\n  \"No conversations yet\": \"Ainda não há conversas\",\n  \"No items exist\": \"Não existem itens\",\n  \"No results found\": \"Nenhum resultado encontrado\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Ninguém mais poderá votar nesta pesquisa.\",\n  \"Nothing yet...\": \"Nada ainda...\",\n  \"Offline\": \"Offline\",\n  \"Ok\": \"OK\",\n  \"Online\": \"Online\",\n  \"Only numbers are allowed\": \"Apenas números são permitidos\",\n  \"Only visible to you\": \"Visível apenas para você\",\n  \"Open emoji picker\": \"Abrir seletor de emoji\",\n  \"Open gallery at image {{ index }}\": \"Abrir galeria na imagem {{ index }}\",\n  \"Open image in gallery\": \"Abrir imagem na galeria\",\n  \"Open location in a map\": \"Abrir localização em um mapa\",\n  \"Option already exists\": \"Opção já existe\",\n  \"Option is empty\": \"A opção está vazia\",\n  \"Options\": \"Opções\",\n  \"Original\": \"Original\",\n  \"People matching\": \"Pessoas correspondentes\",\n  \"Photo\": \"Foto\",\n  \"Pin\": \"Fixar\",\n  \"Pinned by {{ name }}\": \"Fixado por {{ name }}\",\n  \"Pinned by You\": \"Fixado por você\",\n  \"placeholder/PollComment\": \"O seu comentário\",\n  \"placeholder/PollOptionSuggestion\": \"Introduza uma nova opção\",\n  \"Play video\": \"Reproduzir vídeo\",\n  \"Playback speed {{ rate }}x\": \"Velocidade de reprodução {{ rate }}x\",\n  \"Poll\": \"Enquete\",\n  \"Poll comments\": \"Comentários da pesquisa\",\n  \"Poll ended\": \"Enquete encerrada\",\n  \"Poll options\": \"Opções da pesquisa\",\n  \"Poll results\": \"Resultados da pesquisa\",\n  \"Previous image\": \"Imagem anterior\",\n  \"Question\": \"Pergunta\",\n  \"Question {{ optionOrderNumber}}\": \"Pergunta {{ optionOrderNumber}}\",\n  \"Question is required\": \"A pergunta é obrigatória\",\n  \"Quote Reply\": \"Responder com citação\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Limite de votos atingido. Remova um voto existente primeiro.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Formato de gravação não é suportado e não pode ser reproduzido\",\n  \"Remind me\": \"Lembrar-me\",\n  \"Remind Me\": \"Lembrar-me\",\n  \"Reminder set\": \"Lembrete definido\",\n  \"Remove reminder\": \"Remover lembrete\",\n  \"Remove save for later\": \"Remover Salvar para depois\",\n  \"Replied to a thread\": \"Respondeu em um tópico\",\n  \"Reply\": \"Responder\",\n  \"Reply to {{ authorName }}\": \"Responder a {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Responda a uma mensagem para iniciar um thread\",\n  \"Reply to Message\": \"Responder à mensagem\",\n  \"replyCount_one\": \"1 resposta\",\n  \"replyCount_many\": \"{{ count }} respostas\",\n  \"replyCount_other\": \"{{ count }} respostas\",\n  \"Resend\": \"Reenviar\",\n  \"Retry upload\": \"Tentar enviar novamente\",\n  \"Review all options available in this poll\": \"Revise todas as opções disponíveis nesta enquete\",\n  \"Review comments submitted with poll answers\": \"Revise comentários enviados com respostas da enquete\",\n  \"Review poll results and open an option to see detailed votes\": \"Revise os resultados da enquete e abra uma opção para ver votos detalhados\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Revise esta mensagem e escolha se deseja excluí-la, editá-la ou enviá-la mesmo assim\",\n  \"Review who voted for this option\": \"Revise quem votou nesta opção\",\n  \"Save for later\": \"Salvar para depois\",\n  \"Saved for later\": \"Salvo para depois\",\n  \"Search\": \"Buscar\",\n  \"Search GIFs\": \"Pesquisar GIFs\",\n  \"search-results-header-filter-source-button-label--channels\": \"canais\",\n  \"search-results-header-filter-source-button-label--messages\": \"mensagens\",\n  \"search-results-header-filter-source-button-label--users\": \"usuários\",\n  \"Searching for {{ searchSourceType }}...\": \"Buscando {{ searchSourceType }}...\",\n  \"Searching...\": \"Buscando...\",\n  \"searchResultsCount_one\": \"1 resultado\",\n  \"searchResultsCount_many\": \"{{ count }} resultados\",\n  \"searchResultsCount_other\": \"{{ count }} resultados\",\n  \"Select a thread to continue the conversation\": \"Selecione uma thread para continuar a conversa\",\n  \"Select more than one option\": \"Selecionar mais de uma opção\",\n  \"Select one\": \"Selecionar um\",\n  \"Select one or more\": \"Selecionar um ou mais\",\n  \"Select up to {{count}}_one\": \"Selecionar até {{count}}\",\n  \"Select up to {{count}}_many\": \"Selecionar até {{count}}\",\n  \"Select up to {{count}}_other\": \"Selecionar até {{count}}\",\n  \"Select your current location and optionally enable live location sharing\": \"Selecione sua localização atual e, opcionalmente, ative o compartilhamento de localização ao vivo\",\n  \"Send\": \"Enviar\",\n  \"Send a message\": \"Envie uma mensagem\",\n  \"Send a message to start the conversation\": \"Envie uma mensagem para iniciar a conversa\",\n  \"Send Anyway\": \"Enviar de qualquer forma\",\n  \"Send message request failed\": \"O pedido de envio da mensagem falhou\",\n  \"Send poll\": \"Enviar enquete\",\n  \"Sending...\": \"Enviando...\",\n  \"Sent\": \"Enviado\",\n  \"Share\": \"Compartilhar\",\n  \"Share live location for\": \"Compartilhar localização ao vivo por\",\n  \"Share Location\": \"Compartilhar localização\",\n  \"Shared live location\": \"Localização ao vivo compartilhada\",\n  \"Shared location\": \"Localização compartilhada\",\n  \"Shuffle\": \"Embaralhar\",\n  \"size limit\": \"limite de tamanho\",\n  \"Slow Mode ON\": \"Modo lento LIGADO\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Modo lento, aguarde {{ seconds }} s...\",\n  \"Some of the files will not be accepted\": \"Alguns arquivos não serão aceitos\",\n  \"Start typing to search\": \"Comece a digitar para pesquisar\",\n  \"Stop sharing\": \"Parar de compartilhar\",\n  \"Submit\": \"Enviar\",\n  \"Suggest a new option to add to this poll\": \"Sugira uma nova opção para adicionar a esta enquete\",\n  \"Suggest an option\": \"Sugerir uma opção\",\n  \"Tap to remove\": \"Toque para remover\",\n  \"Tap to remove: {{ reactionName }}\": \"Toque para remover: {{ reactionName }}\",\n  \"Thinking...\": \"Pensando...\",\n  \"this content could not be displayed\": \"este conteúdo não pôde ser exibido\",\n  \"This field cannot be empty or contain only spaces\": \"Este campo não pode estar vazio ou conter apenas espaços\",\n  \"This message did not meet our content guidelines\": \"Esta mensagem não corresponde às nossas diretrizes de conteúdo\",\n  \"Thread\": \"Fio\",\n  \"Thread has not been found\": \"Fio não encontrado\",\n  \"Thread reply\": \"Resposta no fio\",\n  \"Thread Reply\": \"Resposta no fio\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Carregando...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} tópico não lido\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} tópicos não lidos\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} tópicos não lidos\",\n  \"Threads\": \"Tópicos\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Ontem]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Hoje]\\\", \\\"nextDay\\\": \\\"[Amanhã]\\\", \\\"lastDay\\\": \\\"[Ontem]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Último] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Hoje\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Ontem\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Para começar a gravar, permita o acesso à câmera no seu navegador\",\n  \"To start recording, allow the microphone access in your browser\": \"Para começar a gravar, permita o acesso ao microfone no seu navegador\",\n  \"totalVoteCount_one\": \"1 voto no total\",\n  \"totalVoteCount_many\": \"{{ count }} votos no total\",\n  \"totalVoteCount_other\": \"{{ count }} votos no total\",\n  \"Translated\": \"Traduzido\",\n  \"Translated from {{ language }}\": \"Traduzido de {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Digite um número de 2 a 10\",\n  \"Unarchive\": \"Desarquivar\",\n  \"unban-command-args\": \"[@nomedeusuário]\",\n  \"unban-command-description\": \"Desbanir um usuário\",\n  \"Unblock User\": \"Desbloquear usuário\",\n  \"unknown error\": \"erro desconhecido\",\n  \"Unmute\": \"Ativar som\",\n  \"unmute-command-args\": \"[@nomedeusuário]\",\n  \"unmute-command-description\": \"Retirar o silenciamento de um usuário\",\n  \"Unpin\": \"Desfixar\",\n  \"Unread messages\": \"Mensagens não lidas\",\n  \"Unsupported attachment\": \"Anexo não suportado\",\n  \"unsupported file type\": \"tipo de arquivo não suportado\",\n  \"Update\": \"Atualizar\",\n  \"Update the comment attached to your poll answer\": \"Atualize o comentário anexado à sua resposta da enquete\",\n  \"Update your comment\": \"Atualizar seu comentário\",\n  \"Upload blocked\": \"Envio bloqueado\",\n  \"Upload error\": \"Erro no envio\",\n  \"Upload failed\": \"Falha no envio\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Tipo de upload: \\\"{{ type }}\\\" não é permitido\",\n  \"User blocked\": \"Usuário bloqueado\",\n  \"User unblocked\": \"Usuário desbloqueado\",\n  \"User uploaded content\": \"Conteúdo enviado pelo usuário\",\n  \"Video\": \"Vídeo\",\n  \"videoCount_one\": \"Vídeo\",\n  \"videoCount_many\": \"{{ count }} vídeos\",\n  \"videoCount_other\": \"{{ count }} vídeos\",\n  \"View\": \"Ver\",\n  \"View {{count}} comments_one\": \"Ver {{count}} comentário\",\n  \"View {{count}} comments_many\": \"Ver {{count}} comentários\",\n  \"View {{count}} comments_other\": \"Ver {{count}} comentários\",\n  \"View all\": \"Ver tudo\",\n  \"View original\": \"Ver original\",\n  \"View results\": \"Ver resultados\",\n  \"View translation\": \"Ver tradução\",\n  \"Voice message\": \"Mensagem de voz\",\n  \"Voice message {{ duration }}\": \"Mensagem de voz {{ duration }}\",\n  \"Voice message deleted\": \"Mensagem de voz excluída\",\n  \"voiceMessageCount_one\": \"Mensagem de voz\",\n  \"voiceMessageCount_many\": \"{{ count }} mensagens de voz\",\n  \"voiceMessageCount_other\": \"{{ count }} mensagens de voz\",\n  \"Vote ended\": \"Votação encerrada\",\n  \"Votes\": \"Votos\",\n  \"Wait until all attachments have uploaded\": \"Espere até que todos os anexos tenham sido carregados\",\n  \"Waiting for network…\": \"Aguardando rede…\",\n  \"You\": \"Você\",\n  \"You've reached the maximum number of files\": \"Você atingiu o número máximo de arquivos\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} и {{ moreCount }} еще\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} и {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} файл\",\n  \"{{ count }} files_few\": \"{{ count }} файла\",\n  \"{{ count }} files_many\": \"{{ count }} файлов\",\n  \"{{ count }} files_other\": \"{{ count }} файла\",\n  \"{{ count }} people are typing_one\": \"{{ count }} человек печатает\",\n  \"{{ count }} people are typing_few\": \"{{ count }} человека печатают\",\n  \"{{ count }} people are typing_many\": \"{{ count }} человек печатают\",\n  \"{{ count }} people are typing_other\": \"{{ count }} человека печатают\",\n  \"{{ count }} photos_one\": \"{{ count }} фото\",\n  \"{{ count }} photos_few\": \"{{ count }} фото\",\n  \"{{ count }} photos_many\": \"{{ count }} фото\",\n  \"{{ count }} photos_other\": \"{{ count }} фото\",\n  \"{{ count }} reactions_one\": \"{{ count }} реакция\",\n  \"{{ count }} reactions_few\": \"{{ count }} реакции\",\n  \"{{ count }} reactions_many\": \"{{ count }} реакций\",\n  \"{{ count }} reactions_other\": \"{{ count }} реакций\",\n  \"{{ count }} videos_one\": \"{{ count }} видео\",\n  \"{{ count }} videos_few\": \"{{ count }} видео\",\n  \"{{ count }} videos_many\": \"{{ count }} видео\",\n  \"{{ count }} videos_other\": \"{{ count }} видео\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} и {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"Ещё {{ imageCount }}\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} участников\",\n  \"{{ typing }} are typing\": \"{{ typing }} печатают\",\n  \"{{ typing }} is typing\": \"{{ typing }} печатает\",\n  \"{{ user }} has been muted\": \"Вы отписались от уведомлений от {{ user }}\",\n  \"{{ user }} has been unmuted\": \"Уведомления от {{ user }} были включены\",\n  \"{{ user }} is typing...\": \"{{ user }} печатает...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} и {{ user }} печатают...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} и другие печатают...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} в сети\",\n  \"{{count}} new messages_one\": \"{{count}} новое сообщение\",\n  \"{{count}} new messages_few\": \"{{count}} новых сообщения\",\n  \"{{count}} new messages_many\": \"{{count}} новых сообщений\",\n  \"{{count}} new messages_other\": \"{{count}} новых сообщений\",\n  \"{{count}} unread_one\": \"{{count}} непрочитанное\",\n  \"{{count}} unread_few\": \"{{count}} непрочитанных\",\n  \"{{count}} unread_many\": \"{{count}} непрочитанных\",\n  \"{{count}} unread_other\": \"{{count}} непрочитанных\",\n  \"{{count}} votes_one\": \"{{count}} голос\",\n  \"{{count}} votes_few\": \"{{count}} голоса\",\n  \"{{count}} votes_many\": \"{{count}} голосов\",\n  \"{{count}} votes_other\": \"{{count}} голосов\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+ещё {{count}} вариант\",\n  \"+{{count}} more options_few\": \"+ещё {{count}} варианта\",\n  \"+{{count}} more options_many\": \"+ещё {{count}} вариантов\",\n  \"+{{count}} more options_other\": \"+ещё {{count}} вариантов\",\n  \"🏙 Attachment...\": \"🏙 Вложение...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} создал(а): {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} проголосовал(а): {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Общее местоположение\",\n  \"Add a comment\": \"Добавить комментарий\",\n  \"Add a comment to your poll answer\": \"Добавьте комментарий к вашему ответу в опросе\",\n  \"Add an option\": \"Добавить вариант\",\n  \"Add reaction\": \"Добавить реакцию\",\n  \"All results loaded\": \"Все результаты загружены\",\n  \"Allow access to camera\": \"Разрешить доступ к камере\",\n  \"Allow access to microphone\": \"Разрешить доступ к микрофону\",\n  \"Allow comments\": \"Разрешить комментарии\",\n  \"Allow option suggestion\": \"Разрешить предложение вариантов\",\n  \"Allow others to add comments\": \"Разрешить другим добавлять комментарии\",\n  \"Also send as a direct message\": \"Также отправить как личное сообщение\",\n  \"Also send in channel\": \"Также отправить в канал\",\n  \"Also sent in channel\": \"Также отправлено в канал\",\n  \"An error has occurred during recording\": \"Произошла ошибка во время записи\",\n  \"An error has occurred during the recording processing\": \"Произошла ошибка во время обработки записи\",\n  \"Anonymous\": \"Аноним\",\n  \"Anonymous poll\": \"Анонимный опрос\",\n  \"Archive\": \"Aрхивировать\",\n  \"Are you sure you want to delete this message?\": \"Вы уверены, что хотите удалить это сообщение?\",\n  \"aria/Attachment\": \"Вложение\",\n  \"aria/Attachment Actions\": \"Действия с вложением\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Позиция аудио {{ elapsed }} из {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Позиция аудио {{ progress }} процентов\",\n  \"aria/Block User\": \"Заблокировать пользователя\",\n  \"aria/Bookmark Message\": \"Сохранить сообщение\",\n  \"aria/Cancel recording\": \"Отменить запись\",\n  \"aria/Cancel Reply\": \"Отменить ответ\",\n  \"aria/Cancel upload\": \"Отменить загрузку\",\n  \"aria/Channel Actions\": \"Действия канала\",\n  \"aria/Channel list\": \"Список каналов\",\n  \"aria/Channel search results\": \"Результаты поиска по каналам\",\n  \"aria/Chat view tabs\": \"Вкладки вида чата\",\n  \"aria/Clear search\": \"Очистить поиск\",\n  \"aria/Close callout dialog\": \"Закрыть диалог выноски\",\n  \"aria/Close thread\": \"Закрыть тему\",\n  \"aria/Collapse sidebar\": \"Свернуть боковую панель\",\n  \"aria/Command Suggestions\": \"Подсказки команд\",\n  \"aria/Complete recording\": \"Завершить запись\",\n  \"aria/Copy Message Text\": \"Копировать текст сообщения\",\n  \"aria/Decrease value\": \"Уменьшить значение\",\n  \"aria/Delete Message\": \"Удалить сообщение\",\n  \"aria/Dismiss notification\": \"Закрыть уведомление\",\n  \"aria/Download attachment\": \"Скачать вложение\",\n  \"aria/Edit Message\": \"Редактировать сообщение\",\n  \"aria/Emoji picker\": \"Выбор эмодзи\",\n  \"aria/Emoji Suggestions\": \"Подсказки эмодзи\",\n  \"aria/Exit search\": \"Выйти из поиска\",\n  \"aria/Expand sidebar\": \"Развернуть боковую панель\",\n  \"aria/File input\": \"Ввод файла\",\n  \"aria/File upload\": \"Загрузка файла\",\n  \"aria/Flag Message\": \"Пожаловаться на сообщение\",\n  \"aria/Image failed to load\": \"Не удалось загрузить изображение\",\n  \"aria/Image input\": \"Ввод изображения\",\n  \"aria/Increase value\": \"Увеличить значение\",\n  \"aria/Jump to latest message\": \"Перейти к последнему сообщению\",\n  \"aria/Jump to quoted message\": \"Перейти к цитируемому сообщению\",\n  \"aria/Load More Channels\": \"Загрузить больше каналов\",\n  \"aria/Mark Message Unread\": \"Отметить как непрочитанное\",\n  \"aria/Mark messages as read\": \"Отметить сообщения как прочитанные\",\n  \"aria/Menu\": \"Меню\",\n  \"aria/Message Actions\": \"Действия с сообщением\",\n  \"aria/Message from {{ user }},\": \"Сообщение от {{ user }},\",\n  \"aria/Message Options\": \"Параметры сообщения\",\n  \"aria/Message,\": \"Сообщение,\",\n  \"aria/Mute User\": \"Отключить уведомления\",\n  \"aria/Notifications\": \"Уведомления\",\n  \"aria/Open Attachment Selector\": \"Открыть выбор вложений\",\n  \"aria/Open Channel Actions Menu\": \"Открыть меню действий канала\",\n  \"aria/Open Menu\": \"Открыть меню\",\n  \"aria/Open Message Actions Menu\": \"Открыть меню действий с сообщениями\",\n  \"aria/Open Reaction Selector\": \"Открыть селектор реакций\",\n  \"aria/Open Thread\": \"Открыть тему\",\n  \"aria/Pause\": \"Пауза\",\n  \"aria/Pause recording\": \"Приостановить запись\",\n  \"aria/Percent complete\": \"{{percent}} процентов завершено\",\n  \"aria/Pin Message\": \"Закрепить сообщение\",\n  \"aria/Play\": \"Воспроизвести\",\n  \"aria/Quote Message\": \"Цитировать сообщение\",\n  \"aria/Reaction list\": \"Список реакций\",\n  \"aria/Remind Me Message\": \"Напомнить мне\",\n  \"aria/Remind Me Options\": \"Параметры напоминания\",\n  \"aria/Remove attachment\": \"Удалить вложение\",\n  \"aria/Remove location attachment\": \"Удалить вложение местоположения\",\n  \"aria/Remove option\": \"Удалить вариант\",\n  \"aria/Remove Reminder\": \"Удалить напоминание\",\n  \"aria/Remove Save For Later\": \"Удалить «Сохранить на потом»\",\n  \"aria/Resend Message\": \"Отправить сообщение повторно\",\n  \"aria/Resume recording\": \"Возобновить запись\",\n  \"aria/Retry upload\": \"Повторить загрузку\",\n  \"aria/Review bounced message\": \"Проверить отклонённое сообщение\",\n  \"aria/Search results\": \"Результаты поиска\",\n  \"aria/Search results header filter button for: {{ source }}\": \"Кнопка фильтра заголовка результатов поиска для: {{ source }}\",\n  \"aria/Seek audio position\": \"Перемотать аудио\",\n  \"aria/Select Channel: {{ channelName }}\": \"Выбрать канал: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Выбрать реакцию: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Выбрать пользовательский канал: {{ name }}\",\n  \"aria/Send\": \"Отправить\",\n  \"aria/Show preview\": \"Показать предпросмотр\",\n  \"aria/Start recording audio\": \"Начать запись аудио\",\n  \"aria/Stop AI Generation\": \"Остановить генерацию ИИ\",\n  \"aria/Suggestions\": \"Подсказки\",\n  \"aria/Thread list\": \"Список тредов\",\n  \"aria/Unblock User\": \"Разблокировать пользователя\",\n  \"aria/Unmute User\": \"Включить уведомления\",\n  \"aria/Unpin Message\": \"Открепить сообщение\",\n  \"aria/User Suggestions\": \"Подсказки пользователей\",\n  \"Ask a question\": \"Задать вопрос\",\n  \"Attach\": \"Прикрепить\",\n  \"Attach files\": \"Прикрепить файлы\",\n  \"Attachment\": \"Вложение\",\n  \"Attachment upload blocked due to {{reason}}\": \"Загрузка вложения заблокирована из-за {{reason}}\",\n  \"Attachment upload failed due to {{reason}}\": \"Загрузка вложения не удалась из-за {{reason}}\",\n  \"Back\": \"Назад\",\n  \"ban-command-args\": \"[@имяпользователя] [текст]\",\n  \"ban-command-description\": \"Заблокировать пользователя\",\n  \"Block User\": \"Заблокировать пользователя\",\n  \"Cancel\": \"Отмена\",\n  \"Cannot seek in the recording\": \"Невозможно осуществить поиск в записи\",\n  \"Channel archived\": \"Канал в архиве\",\n  \"Channel Missing\": \"Канал не найден\",\n  \"Channel muted\": \"Канал заглушён\",\n  \"Channel pinned\": \"Канал закреплён\",\n  \"Channel unarchived\": \"Канал извлечён из архива\",\n  \"Channel unmuted\": \"Заглушение канала снято\",\n  \"Channel unpinned\": \"Канал откреплён\",\n  \"Channels\": \"Каналы\",\n  \"Chats\": \"Чаты\",\n  \"Choose between 2 to 10 options\": \"Выберите от 2 до 10 вариантов\",\n  \"Close\": \"Закрыть\",\n  \"Close dialog\": \"Закрыть диалог\",\n  \"Close emoji picker\": \"Закрыть окно выбора смайлов\",\n  \"Close prompt: {{ title }}\": \"Закрыть запрос: {{ title }}\",\n  \"Command not available while editing\": \"Команда недоступна при редактировании\",\n  \"Command not available while replying\": \"Команда недоступна при ответе\",\n  \"Commands\": \"Команды\",\n  \"Commands matching\": \"Соответствие команд\",\n  \"Connection failure, reconnecting now...\": \"Ошибка соединения, переподключение...\",\n  \"Copy Message\": \"Копировать сообщение\",\n  \"Create\": \"Создать\",\n  \"Create a question, add options, and configure poll settings\": \"Создайте вопрос, добавьте варианты и настройте параметры опроса\",\n  \"Create poll\": \"Создать опрос\",\n  \"Current location\": \"Текущее местоположение\",\n  \"Delete\": \"Удалить\",\n  \"Delete for me\": \"Удалить для меня\",\n  \"Delete message\": \"Удалить сообщение\",\n  \"Delivered\": \"Отправлено\",\n  \"Direct message\": \"Личное сообщение\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Вы хотите завершить этот опрос сейчас? После этого никто не сможет голосовать в этом опросе.\",\n  \"Download All\": \"Скачать всё\",\n  \"Download Attachment\": \"Скачать вложение\",\n  \"Download attachment {{ name }}\": \"Скачать вложение {{ name }}\",\n  \"Drag your files here\": \"Перетащите ваши файлы сюда\",\n  \"Drag your files here to add to your post\": \"Перетащите ваши файлы сюда, чтобы добавить их в ваш пост\",\n  \"Due {{ timeLeft }}\": \"Просрочено в {{ timeLeft }}\",\n  \"Due since {{ dueSince }}\": \"Просрочено с {{ dueSince }}\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Редактировать сообщение\",\n  \"Edit message request failed\": \"Не удалось изменить запрос сообщения\",\n  \"Edited\": \"Отредактировано\",\n  \"Emoji matching\": \"Соответствие эмодзи\",\n  \"Empty message...\": \"Пустое сообщение...\",\n  \"End\": \"Конец\",\n  \"End poll\": \"Завершить опрос\",\n  \"End this poll?\": \"Завершить этот опрос?\",\n  \"End vote\": \"Закончить голосование\",\n  \"Enforce unique vote is enabled\": \"Уникальное голосование включено\",\n  \"Error\": \"Ошибка\",\n  \"Error adding flag\": \"Ошибка добавления флага\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Ошибка подключения к чату, обновите страницу чтобы попробовать снова.\",\n  \"Error deleting message\": \"Ошибка при удалении сообщения\",\n  \"Error fetching reactions\": \"Ошибка при загрузке реакций\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Ошибка при отметке сообщения как непрочитанного. Невозможно отметить как непрочитанные сообщения старше последних 100 сообщений в канале.\",\n  \"Error muting a user ...\": \"Ошибка отключения уведомлений от пользователя...\",\n  \"Error pinning message\": \"Сообщение об ошибке при закреплении\",\n  \"Error removing message pin\": \"Ошибка при удалении булавки сообщения\",\n  \"Error reproducing the recording\": \"Ошибка воспроизведения записи\",\n  \"Error starting recording\": \"Ошибка при запуске записи\",\n  \"Error unmuting a user ...\": \"Ошибка включения уведомлений...\",\n  \"Error uploading attachment\": \"Ошибка при загрузке вложения\",\n  \"Error uploading file\": \"Ошибка при загрузке файла\",\n  \"Error uploading image\": \"Ошибка загрузки изображения\",\n  \"Error: {{ errorMessage }}\": \"Ошибка: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Выйти из команды {{ command }}\",\n  \"Failed to block user\": \"Не удалось заблокировать пользователя\",\n  \"Failed to create the poll\": \"Не удалось создать опрос\",\n  \"Failed to create the poll due to {{reason}}\": \"Не удалось создать опрос из-за {{reason}}\",\n  \"Failed to delete the message\": \"Не удалось удалить сообщение\",\n  \"Failed to end the poll\": \"Не удалось завершить опрос\",\n  \"Failed to end the poll due to {{reason}}\": \"Не удалось завершить опрос из-за {{reason}}\",\n  \"Failed to jump to the first unread message\": \"Не удалось перейти к первому непрочитанному сообщению\",\n  \"Failed to leave channel\": \"Не удалось покинуть канал\",\n  \"Failed to load channels\": \"Не удалось загрузить каналы\",\n  \"Failed to load more channels\": \"Не удалось загрузить больше каналов\",\n  \"Failed to mark channel as read\": \"Не удалось пометить канал как прочитанный\",\n  \"Failed to play the recording\": \"Не удалось воспроизвести запись\",\n  \"Failed to retrieve location\": \"Не удалось получить местоположение\",\n  \"Failed to share location\": \"Не удалось поделиться местоположением\",\n  \"Failed to update channel archive status\": \"Не удалось обновить статус архивации канала\",\n  \"Failed to update channel mute status\": \"Не удалось обновить статус отключения звука канала\",\n  \"Failed to update channel pinned status\": \"Не удалось обновить статус закрепления канала\",\n  \"File\": \"Файл\",\n  \"File is required for upload attachment\": \"Для загрузки вложения требуется файл\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Файл слишком большой: {{ size }}, максимальный размер загрузки составляет {{ limit }}\",\n  \"File too large\": \"Файл слишком большой\",\n  \"fileCount_four\": \"{{ count }} файла\",\n  \"fileCount_one\": \"{{ count }} файл\",\n  \"fileCount_few\": \"{{ count }} файла\",\n  \"fileCount_many\": \"{{ count }} файлов\",\n  \"fileCount_other\": \"{{ count }} файлов\",\n  \"fileCount_three\": \"{{ count }} файла\",\n  \"fileCount_two\": \"{{ count }} файла\",\n  \"Flag\": \"Пожаловаться\",\n  \"Generating...\": \"Генерирую...\",\n  \"giphy-command-args\": \"[текст]\",\n  \"giphy-command-description\": \"Опубликовать случайную GIF-анимацию в канале\",\n  \"Hide who voted\": \"Скрыть, кто голосовал\",\n  \"Image\": \"Изображение\",\n  \"imageCount_one\": \"{{ count }} изображение\",\n  \"imageCount_few\": \"{{ count }} изображения\",\n  \"imageCount_many\": \"{{ count }} изображений\",\n  \"imageCount_other\": \"{{ count }} изображений\",\n  \"Instant commands\": \"Мгновенные команды\",\n  \"language/af\": \"Африкаанс\",\n  \"language/am\": \"Амхарский\",\n  \"language/ar\": \"Арабский\",\n  \"language/az\": \"Азербайджанский\",\n  \"language/bg\": \"Болгарский\",\n  \"language/bn\": \"Бенгальский\",\n  \"language/bs\": \"Боснийский\",\n  \"language/cs\": \"Чешский\",\n  \"language/da\": \"Датский\",\n  \"language/de\": \"Немецкий\",\n  \"language/el\": \"Греческий\",\n  \"language/en\": \"Английский\",\n  \"language/es\": \"Испанский\",\n  \"language/es-MX\": \"Испанский (Мексика)\",\n  \"language/et\": \"Эстонский\",\n  \"language/fa\": \"Персидский\",\n  \"language/fa-AF\": \"Дари\",\n  \"language/fi\": \"Финский\",\n  \"language/fr\": \"Французский\",\n  \"language/fr-CA\": \"Французский (Канада)\",\n  \"language/ha\": \"Хауса\",\n  \"language/he\": \"Иврит\",\n  \"language/hi\": \"Хинди\",\n  \"language/hr\": \"Хорватский\",\n  \"language/ht\": \"Гаитянский креольский\",\n  \"language/hu\": \"Венгерский\",\n  \"language/id\": \"Индонезийский\",\n  \"language/it\": \"Итальянский\",\n  \"language/ja\": \"Японский\",\n  \"language/ka\": \"Грузинский\",\n  \"language/ko\": \"Корейский\",\n  \"language/lt\": \"Литовский\",\n  \"language/lv\": \"Латышский\",\n  \"language/ms\": \"Малайский\",\n  \"language/nl\": \"Нидерландский\",\n  \"language/no\": \"Норвежский\",\n  \"language/pl\": \"Польский\",\n  \"language/ps\": \"Пушту\",\n  \"language/pt\": \"Португальский\",\n  \"language/ro\": \"Румынский\",\n  \"language/ru\": \"Русский\",\n  \"language/sk\": \"Словацкий\",\n  \"language/sl\": \"Словенский\",\n  \"language/so\": \"Сомали\",\n  \"language/sq\": \"Албанский\",\n  \"language/sr\": \"Сербский\",\n  \"language/sv\": \"Шведский\",\n  \"language/sw\": \"Суахили\",\n  \"language/ta\": \"Тамильский\",\n  \"language/th\": \"Тайский\",\n  \"language/tl\": \"Тагальский\",\n  \"language/tr\": \"Турецкий\",\n  \"language/uk\": \"Украинский\",\n  \"language/ur\": \"Урду\",\n  \"language/vi\": \"Вьетнамский\",\n  \"language/zh\": \"Китайский (упрощённый)\",\n  \"language/zh-TW\": \"Китайский (традиционный)\",\n  \"Leave Channel\": \"Покинуть канал\",\n  \"Left channel\": \"Канал покинут\",\n  \"Let others add options\": \"Разрешить другим добавлять варианты\",\n  \"Limit votes per person\": \"Ограничить голоса на человека\",\n  \"Link\": \"Линк\",\n  \"linkCount_one\": \"{{ count }} линк\",\n  \"linkCount_few\": \"{{ count }} линка\",\n  \"linkCount_many\": \"{{ count }} линков\",\n  \"linkCount_other\": \"{{ count }} линков\",\n  \"live\": \"В прямом эфире\",\n  \"Live for {{duration}}\": \"В прямом эфире {{duration}}\",\n  \"Live location\": \"Местоположение в прямом эфире\",\n  \"Live until {{ timestamp }}\": \"В прямом эфире до {{ timestamp }}\",\n  \"Load more\": \"Загрузить больше\",\n  \"Local upload attachment missing local id\": \"У локального вложения нет локального id\",\n  \"Location\": \"Местоположение\",\n  \"Location sharing ended\": \"Обмен местоположением завершен\",\n  \"Location: {{ coordinates }}\": \"Местоположение: {{ coordinates }}\",\n  \"Mark as unread\": \"Отметить как непрочитанное\",\n  \"Maximum number of votes (from 2 to 10)\": \"Максимальное количество голосов (от 2 до 10)\",\n  \"Maximum votes per person\": \"Максимум голосов на человека\",\n  \"Menu\": \"Меню\",\n  \"Message deleted\": \"Сообщение удалено\",\n  \"Message failed to send\": \"Не удалось отправить сообщение\",\n  \"Message has been successfully flagged\": \"Жалоба на сообщение была принята\",\n  \"Message marked as unread\": \"Сообщение помечено как непрочитанное\",\n  \"Message pinned\": \"Сообщение закреплено\",\n  \"Message unpinned\": \"Сообщение откреплено\",\n  \"Message was blocked by moderation policies\": \"Сообщение было заблокировано модерацией\",\n  \"Messages have been marked unread.\": \"Сообщения были отмечены как непрочитанные.\",\n  \"Missing permissions to upload the attachment\": \"Отсутствуют разрешения для загрузки вложения\",\n  \"Multiple votes\": \"Несколько голосов\",\n  \"Mute\": \"Отключить уведомления\",\n  \"mute-command-args\": \"[@имяпользователя]\",\n  \"mute-command-description\": \"Выключить микрофон у пользователя\",\n  \"network error\": \"ошибка сети\",\n  \"New\": \"Новые\",\n  \"New message from {{user}}\": \"Новое сообщение от {{user}}\",\n  \"New Messages!\": \"Новые сообщения!\",\n  \"Next image\": \"Следующее изображение\",\n  \"No chats here yet…\": \"Здесь еще нет чатов...\",\n  \"No conversations yet\": \"Пока нет бесед\",\n  \"No items exist\": \"Элементов нет\",\n  \"No results found\": \"Результаты не найдены\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Никто больше не сможет голосовать в этом опросе.\",\n  \"Nothing yet...\": \"Пока ничего нет...\",\n  \"Offline\": \"Не в сети\",\n  \"Ok\": \"Ок\",\n  \"Online\": \"В сети\",\n  \"Only numbers are allowed\": \"Разрешены только цифры\",\n  \"Only visible to you\": \"Видно только вам\",\n  \"Open emoji picker\": \"Открыть выбор смайлов\",\n  \"Open gallery at image {{ index }}\": \"Открыть галерею на изображении {{ index }}\",\n  \"Open image in gallery\": \"Открыть изображение в галерее\",\n  \"Open location in a map\": \"Открыть местоположение на карте\",\n  \"Option already exists\": \"Вариант уже существует\",\n  \"Option is empty\": \"Вариант пуст\",\n  \"Options\": \"Варианты\",\n  \"Original\": \"Оригинал\",\n  \"People matching\": \"Совпадающие люди\",\n  \"Photo\": \"Фото\",\n  \"Pin\": \"Закрепить\",\n  \"Pinned by {{ name }}\": \"Закреплено: {{ name }}\",\n  \"Pinned by You\": \"Закреплено вами\",\n  \"placeholder/PollComment\": \"Ваш комментарий\",\n  \"placeholder/PollOptionSuggestion\": \"Введите новый вариант\",\n  \"Play video\": \"Воспроизвести видео\",\n  \"Playback speed {{ rate }}x\": \"Скорость воспроизведения {{ rate }}x\",\n  \"Poll\": \"Опрос\",\n  \"Poll comments\": \"Комментарии к опросу\",\n  \"Poll ended\": \"Опрос завершён\",\n  \"Poll options\": \"Опции опроса\",\n  \"Poll results\": \"Результаты опроса\",\n  \"Previous image\": \"Предыдущее изображение\",\n  \"Question\": \"Вопрос\",\n  \"Question {{ optionOrderNumber}}\": \"Вопрос {{ optionOrderNumber}}\",\n  \"Question is required\": \"Вопрос обязателен\",\n  \"Quote Reply\": \"Ответ со цитатой\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Достигнут лимит голосов. Сначала удалите существующий голос.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Формат записи не поддерживается и не может быть воспроизведен\",\n  \"Remind me\": \"Напомнить мне\",\n  \"Remind Me\": \"Напомнить мне\",\n  \"Reminder set\": \"Напоминание установлено\",\n  \"Remove reminder\": \"Удалить напоминание\",\n  \"Remove save for later\": \"Удалить «Сохранить на потом»\",\n  \"Replied to a thread\": \"Ответил в ветке\",\n  \"Reply\": \"Ответить\",\n  \"Reply to {{ authorName }}\": \"Ответить {{ authorName }}\",\n  \"Reply to a message to start a thread\": \"Ответьте на сообщение, чтобы начать тред\",\n  \"Reply to Message\": \"Ответить на сообщение\",\n  \"replyCount_one\": \"1 ответ\",\n  \"replyCount_few\": \"{{ count }} ответов\",\n  \"replyCount_many\": \"{{ count }} ответов\",\n  \"replyCount_other\": \"{{ count }} ответов\",\n  \"Resend\": \"Отправить повторно\",\n  \"Retry upload\": \"Повторить загрузку\",\n  \"Review all options available in this poll\": \"Просмотрите все варианты, доступные в этом опросе\",\n  \"Review comments submitted with poll answers\": \"Просмотрите комментарии, отправленные вместе с ответами в опросе\",\n  \"Review poll results and open an option to see detailed votes\": \"Просмотрите результаты опроса и откройте вариант, чтобы увидеть подробные голоса\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Просмотрите это сообщение и выберите, удалить его, отредактировать или отправить все равно\",\n  \"Review who voted for this option\": \"Просмотрите, кто проголосовал за этот вариант\",\n  \"Save for later\": \"Сохранить на потом\",\n  \"Saved for later\": \"Сохранено на потом\",\n  \"Search\": \"Поиск\",\n  \"Search GIFs\": \"Поиск GIF\",\n  \"search-results-header-filter-source-button-label--channels\": \"каналы\",\n  \"search-results-header-filter-source-button-label--messages\": \"сообщения\",\n  \"search-results-header-filter-source-button-label--users\": \"пользователи\",\n  \"Searching for {{ searchSourceType }}...\": \"Поиск {{ searchSourceType }}...\",\n  \"Searching...\": \"Ищем...\",\n  \"searchResultsCount_one\": \"1 результат\",\n  \"searchResultsCount_few\": \"{{ count }} результата\",\n  \"searchResultsCount_many\": \"{{ count }} результатов\",\n  \"searchResultsCount_other\": \"{{ count }} результатов\",\n  \"Select a thread to continue the conversation\": \"Выберите тред, чтобы продолжить беседу\",\n  \"Select more than one option\": \"Выберите более одного варианта\",\n  \"Select one\": \"Выберите один\",\n  \"Select one or more\": \"Выберите один или несколько\",\n  \"Select up to {{count}}_one\": \"Выберите до {{count}}\",\n  \"Select up to {{count}}_few\": \"Выберите до {{count}}\",\n  \"Select up to {{count}}_many\": \"Выберите до {{count}}\",\n  \"Select up to {{count}}_other\": \"Выберите до {{count}}\",\n  \"Select your current location and optionally enable live location sharing\": \"Выберите ваше текущее местоположение и при необходимости включите передачу геопозиции в реальном времени\",\n  \"Send\": \"Отправить\",\n  \"Send a message\": \"Отправьте сообщение\",\n  \"Send a message to start the conversation\": \"Отправьте сообщение, чтобы начать разговор\",\n  \"Send Anyway\": \"Мне всё равно, отправить\",\n  \"Send message request failed\": \"Не удалось отправить запрос на отправку сообщения\",\n  \"Send poll\": \"Отправить опрос\",\n  \"Sending...\": \"Отправка...\",\n  \"Sent\": \"Отправлено\",\n  \"Share\": \"Поделиться\",\n  \"Share live location for\": \"Поделиться местоположением в прямом эфире на\",\n  \"Share Location\": \"Поделиться местоположением\",\n  \"Shared live location\": \"Общее местоположение в прямом эфире\",\n  \"Shared location\": \"Общее местоположение\",\n  \"Shuffle\": \"Перемешать\",\n  \"size limit\": \"ограничение размера\",\n  \"Slow Mode ON\": \"Медленный режим включен\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Медленный режим: подождите {{ seconds }} с...\",\n  \"Some of the files will not be accepted\": \"Некоторые файлы не будут приняты\",\n  \"Start typing to search\": \"Начните вводить для поиска\",\n  \"Stop sharing\": \"Прекратить делиться\",\n  \"Submit\": \"Отправить\",\n  \"Suggest a new option to add to this poll\": \"Предложите новый вариант для добавления в этот опрос\",\n  \"Suggest an option\": \"Предложить вариант\",\n  \"Tap to remove\": \"Нажмите, чтобы удалить\",\n  \"Tap to remove: {{ reactionName }}\": \"Нажмите, чтобы удалить: {{ reactionName }}\",\n  \"Thinking...\": \"Думаю...\",\n  \"this content could not be displayed\": \"Этот контент не может быть отображен в данный момент\",\n  \"This field cannot be empty or contain only spaces\": \"Это поле не может быть пустым или содержать только пробелы\",\n  \"This message did not meet our content guidelines\": \"Сообщение не соответствует правилам\",\n  \"Thread\": \"Ветка\",\n  \"Thread has not been found\": \"Ветка не найдена\",\n  \"Thread reply\": \"Ответ в ветке\",\n  \"Thread Reply\": \"Ответ в ветке\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Загрузка...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} непрочитанная ветка\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_few\": \"{{ count }} непрочитанные ветки\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} непрочитанных веток\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} непрочитанных веток\",\n  \"Threads\": \"Треды\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Вчера]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Сегодня]\\\", \\\"nextDay\\\": \\\"[Завтра]\\\", \\\"lastDay\\\": \\\"[Вчера]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[В прошлый] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Сегодня\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Вчера\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Для начала записи разрешите доступ к камере в вашем браузере\",\n  \"To start recording, allow the microphone access in your browser\": \"Для начала записи разрешите доступ к микрофону в вашем браузере\",\n  \"totalVoteCount_one\": \"1 голос всего\",\n  \"totalVoteCount_few\": \"{{ count }} голоса всего\",\n  \"totalVoteCount_many\": \"{{ count }} голосов всего\",\n  \"totalVoteCount_other\": \"{{ count }} голосов всего\",\n  \"Translated\": \"Переведено\",\n  \"Translated from {{ language }}\": \"Переведено с {{ language }}\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"Введите число от 2 до 10\",\n  \"Unarchive\": \"Удалить из архива\",\n  \"unban-command-args\": \"[@имяпользователя]\",\n  \"unban-command-description\": \"Разблокировать пользователя\",\n  \"Unblock User\": \"Разблокировать пользователя\",\n  \"unknown error\": \"неизвестная ошибка\",\n  \"Unmute\": \"Включить уведомления\",\n  \"unmute-command-args\": \"[@имяпользователя]\",\n  \"unmute-command-description\": \"Включить микрофон у пользователя\",\n  \"Unpin\": \"Открепить\",\n  \"Unread messages\": \"Непрочитанные сообщения\",\n  \"Unsupported attachment\": \"Неподдерживаемое вложение\",\n  \"unsupported file type\": \"неподдерживаемый тип файла\",\n  \"Update\": \"Обновить\",\n  \"Update the comment attached to your poll answer\": \"Обновите комментарий, прикрепленный к вашему ответу в опросе\",\n  \"Update your comment\": \"Обновите ваш комментарий\",\n  \"Upload blocked\": \"Загрузка заблокирована\",\n  \"Upload error\": \"Ошибка загрузки\",\n  \"Upload failed\": \"Загрузка не удалась\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Тип загрузки: \\\"{{ type }}\\\" не разрешен\",\n  \"User blocked\": \"Пользователь заблокирован\",\n  \"User unblocked\": \"Пользователь разблокирован\",\n  \"User uploaded content\": \"Пользователь загрузил контент\",\n  \"Video\": \"Видео\",\n  \"videoCount_one\": \"{{ count }} видео\",\n  \"videoCount_few\": \"{{ count }} видео\",\n  \"videoCount_many\": \"{{ count }} видео\",\n  \"videoCount_other\": \"{{ count }} видео\",\n  \"View\": \"Просмотр\",\n  \"View {{count}} comments_one\": \"Просмотреть {{count}} комментарий\",\n  \"View {{count}} comments_few\": \"Просмотреть {{count}} комментариев\",\n  \"View {{count}} comments_many\": \"Просмотреть {{count}} комментариев\",\n  \"View {{count}} comments_other\": \"Просмотреть {{count}} комментариев\",\n  \"View all\": \"Показать все\",\n  \"View original\": \"Показать оригинал\",\n  \"View results\": \"Посмотреть результаты\",\n  \"View translation\": \"Показать перевод\",\n  \"Voice message\": \"Голосовое сообщение\",\n  \"Voice message {{ duration }}\": \"Голосовое сообщение {{ duration }}\",\n  \"Voice message deleted\": \"Голосовое сообщение удалено\",\n  \"voiceMessageCount_one\": \"{{ count }} голосовое сообщение\",\n  \"voiceMessageCount_few\": \"{{ count }} голосовых сообщения\",\n  \"voiceMessageCount_many\": \"{{ count }} голосовых сообщений\",\n  \"voiceMessageCount_other\": \"{{ count }} голосовых сообщений\",\n  \"Vote ended\": \"Голосование завершено\",\n  \"Votes\": \"Голоса\",\n  \"Wait until all attachments have uploaded\": \"Подождите, пока все вложения загрузятся\",\n  \"Waiting for network…\": \"Ожидание сети…\",\n  \"You\": \"Вы\",\n  \"You've reached the maximum number of files\": \"Вы достигли максимального количества файлов\"\n}\n","{\n  \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} ve {{ moreCount }} daha\",\n  \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} ve {{ lastUser }}\",\n  \"{{ count }} files_one\": \"{{ count }} dosya\",\n  \"{{ count }} files_other\": \"{{ count }} dosya\",\n  \"{{ count }} people are typing_one\": \"{{ count }} kişi yazıyor\",\n  \"{{ count }} people are typing_many\": \"{{ count }} kişi yazıyor\",\n  \"{{ count }} people are typing_other\": \"{{ count }} kişi yazıyor\",\n  \"{{ count }} photos_one\": \"{{ count }} fotoğraf\",\n  \"{{ count }} photos_other\": \"{{ count }} fotoğraf\",\n  \"{{ count }} reactions_one\": \"{{ count }} tepki\",\n  \"{{ count }} reactions_other\": \"{{ count }} tepki\",\n  \"{{ count }} videos_one\": \"{{ count }} video\",\n  \"{{ count }} videos_other\": \"{{ count }} video\",\n  \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} ve {{ secondUser }}\",\n  \"{{ imageCount }} more\": \"{{ imageCount }} adet daha\",\n  \"{{ memberCount }} members\": \"{{ memberCount }} üye\",\n  \"{{ typing }} are typing\": \"{{ typing }} yazıyor\",\n  \"{{ typing }} is typing\": \"{{ typing }} yazıyor\",\n  \"{{ user }} has been muted\": \"{{ user }} sessize alındı\",\n  \"{{ user }} has been unmuted\": \"{{ user }} sesi açıldı\",\n  \"{{ user }} is typing...\": \"{{ user }} yazıyor...\",\n  \"{{ users }} and {{ user }} are typing...\": \"{{ users }} ve {{ user }} yazıyor...\",\n  \"{{ users }} and more are typing...\": \"{{ users }} ve diğerleri yazıyor...\",\n  \"{{ watcherCount }} online\": \"{{ watcherCount }} çevrimiçi\",\n  \"{{count}} new messages_one\": \"{{count}} yeni mesaj\",\n  \"{{count}} new messages_other\": \"{{count}} yeni mesaj\",\n  \"{{count}} unread_one\": \"{{count}} okunmamış\",\n  \"{{count}} unread_other\": \"{{count}} okunmamış\",\n  \"{{count}} votes_one\": \"{{count}} oy\",\n  \"{{count}} votes_other\": \"{{count}} oy\",\n  \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n  \"+{{count}} more options_one\": \"+{{count}} seçenek daha\",\n  \"+{{count}} more options_other\": \"+{{count}} seçenek daha\",\n  \"🏙 Attachment...\": \"🏙 Ek...\",\n  \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} oluşturdu: {{ pollName}}\",\n  \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} oy verdi: {{pollOptionText}}\",\n  \"📍Shared location\": \"📍Paylaşılan konum\",\n  \"Add a comment\": \"Yorum ekle\",\n  \"Add a comment to your poll answer\": \"Anket yanıtınıza bir yorum ekleyin\",\n  \"Add an option\": \"Bir seçenek ekle\",\n  \"Add reaction\": \"Tepki ekle\",\n  \"All results loaded\": \"Tüm sonuçlar yüklendi\",\n  \"Allow access to camera\": \"Kameraya erişime izin ver\",\n  \"Allow access to microphone\": \"Mikrofona erişime izin ver\",\n  \"Allow comments\": \"Yorumlara izin ver\",\n  \"Allow option suggestion\": \"Seçenek önerisine izin ver\",\n  \"Allow others to add comments\": \"Diğerlerinin yorum eklemesine izin ver\",\n  \"Also send as a direct message\": \"Ayrıca doğrudan mesaj olarak gönder\",\n  \"Also send in channel\": \"Ayrıca kanala gönder\",\n  \"Also sent in channel\": \"Kanala da gönderildi\",\n  \"An error has occurred during recording\": \"Kayıt sırasında bir hata oluştu\",\n  \"An error has occurred during the recording processing\": \"Kayıt işlemi sırasında bir hata oluştu\",\n  \"Anonymous\": \"Anonim\",\n  \"Anonymous poll\": \"Anonim anket\",\n  \"Archive\": \"Arşivle\",\n  \"Are you sure you want to delete this message?\": \"Bu mesajı silmek istediğinizden emin misiniz?\",\n  \"aria/Attachment\": \"Ek\",\n  \"aria/Attachment Actions\": \"Ek işlemleri\",\n  \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Ses konumu {{ elapsed }} / {{ duration }}\",\n  \"aria/Audio position {{ progress }} percent\": \"Ses konumu yüzde {{ progress }}\",\n  \"aria/Block User\": \"Kullanıcıyı engelle\",\n  \"aria/Bookmark Message\": \"Mesajı yer imi ekle\",\n  \"aria/Cancel recording\": \"Kaydı iptal et\",\n  \"aria/Cancel Reply\": \"Cevabı İptal Et\",\n  \"aria/Cancel upload\": \"Yüklemeyi İptal Et\",\n  \"aria/Channel Actions\": \"Kanal işlemleri\",\n  \"aria/Channel list\": \"Kanal listesi\",\n  \"aria/Channel search results\": \"Kanal arama sonuçları\",\n  \"aria/Chat view tabs\": \"Sohbet görünümü sekmeleri\",\n  \"aria/Clear search\": \"Aramayı temizle\",\n  \"aria/Close callout dialog\": \"Bilgi balonu iletişim kutusunu kapat\",\n  \"aria/Close thread\": \"Konuyu kapat\",\n  \"aria/Collapse sidebar\": \"Kenar çubuğunu daralt\",\n  \"aria/Command Suggestions\": \"Komut önerileri\",\n  \"aria/Complete recording\": \"Kaydı tamamla\",\n  \"aria/Copy Message Text\": \"Mesaj metnini kopyala\",\n  \"aria/Decrease value\": \"Değeri azalt\",\n  \"aria/Delete Message\": \"Mesajı sil\",\n  \"aria/Dismiss notification\": \"Bildirimi kapat\",\n  \"aria/Download attachment\": \"Ek indir\",\n  \"aria/Edit Message\": \"Mesajı Düzenle\",\n  \"aria/Emoji picker\": \"Emoji seçici\",\n  \"aria/Emoji Suggestions\": \"Emoji önerileri\",\n  \"aria/Exit search\": \"Aramadan çık\",\n  \"aria/Expand sidebar\": \"Kenar çubuğunu genişlet\",\n  \"aria/File input\": \"Dosya girişi\",\n  \"aria/File upload\": \"Dosya yükleme\",\n  \"aria/Flag Message\": \"Mesajı bayrakla\",\n  \"aria/Image failed to load\": \"Görsel yüklenemedi\",\n  \"aria/Image input\": \"Resim girişi\",\n  \"aria/Increase value\": \"Değeri artır\",\n  \"aria/Jump to latest message\": \"En son mesaja git\",\n  \"aria/Jump to quoted message\": \"Alıntılanan mesaja git\",\n  \"aria/Load More Channels\": \"Daha Fazla Kanal Yükle\",\n  \"aria/Mark Message Unread\": \"Okunmamış olarak işaretle\",\n  \"aria/Mark messages as read\": \"Mesajları okundu olarak işaretle\",\n  \"aria/Menu\": \"Menü\",\n  \"aria/Message Actions\": \"Mesaj eylemleri\",\n  \"aria/Message from {{ user }},\": \"{{ user }} adlı kullanıcıdan mesaj,\",\n  \"aria/Message Options\": \"Mesaj Seçenekleri\",\n  \"aria/Message,\": \"Mesaj,\",\n  \"aria/Mute User\": \"Kullanıcıyı sustur\",\n  \"aria/Notifications\": \"Bildirimler\",\n  \"aria/Open Attachment Selector\": \"Ek Seçiciyi Aç\",\n  \"aria/Open Channel Actions Menu\": \"Kanal işlemleri menüsünü aç\",\n  \"aria/Open Menu\": \"Menüyü Aç\",\n  \"aria/Open Message Actions Menu\": \"Mesaj İşlemleri Menüsünü Aç\",\n  \"aria/Open Reaction Selector\": \"Tepki Seçiciyi Aç\",\n  \"aria/Open Thread\": \"Konuyu Aç\",\n  \"aria/Pause\": \"Duraklat\",\n  \"aria/Pause recording\": \"Kaydı duraklat\",\n  \"aria/Percent complete\": \"Yüzde {{percent}} tamamlandı\",\n  \"aria/Pin Message\": \"Mesajı sabitle\",\n  \"aria/Play\": \"Oynat\",\n  \"aria/Quote Message\": \"Mesajı alıntıla\",\n  \"aria/Reaction list\": \"Tepki listesi\",\n  \"aria/Remind Me Message\": \"Hatırlat\",\n  \"aria/Remind Me Options\": \"Hatırlatma seçenekleri\",\n  \"aria/Remove attachment\": \"Eki kaldır\",\n  \"aria/Remove location attachment\": \"Konum ekini kaldır\",\n  \"aria/Remove option\": \"Seçeneği kaldır\",\n  \"aria/Remove Reminder\": \"Hatırlatıcıyı kaldır\",\n  \"aria/Remove Save For Later\": \"Sonraya kaydet'i kaldır\",\n  \"aria/Resend Message\": \"Mesajı tekrar gönder\",\n  \"aria/Resume recording\": \"Kaydı devam ettir\",\n  \"aria/Retry upload\": \"Yüklemeyi Tekrar Dene\",\n  \"aria/Review bounced message\": \"Geri dönen mesajı incele\",\n  \"aria/Search results\": \"Arama sonuçları\",\n  \"aria/Search results header filter button for: {{ source }}\": \"{{ source }} için arama sonuçları başlık filtre düğmesi\",\n  \"aria/Seek audio position\": \"Ses konumunu ara\",\n  \"aria/Select Channel: {{ channelName }}\": \"Kanal seç: {{ channelName }}\",\n  \"aria/Select Reaction: {{ reactionName }}\": \"Tepki seç: {{ reactionName }}\",\n  \"aria/Select User Channel: {{ name }}\": \"Kullanıcı kanalını seç: {{ name }}\",\n  \"aria/Send\": \"Gönder\",\n  \"aria/Show preview\": \"Önizlemeyi göster\",\n  \"aria/Start recording audio\": \"Ses kaydını başlat\",\n  \"aria/Stop AI Generation\": \"Yapay Zeka Üretimini Durdur\",\n  \"aria/Suggestions\": \"Öneriler\",\n  \"aria/Thread list\": \"İleti dizisi listesi\",\n  \"aria/Unblock User\": \"Kullanıcının engelini kaldır\",\n  \"aria/Unmute User\": \"Sesini aç\",\n  \"aria/Unpin Message\": \"Sabitlemeyi kaldır\",\n  \"aria/User Suggestions\": \"Kullanıcı önerileri\",\n  \"Ask a question\": \"Bir soru sor\",\n  \"Attach\": \"Ekle\",\n  \"Attach files\": \"Dosya ekle\",\n  \"Attachment\": \"Ek\",\n  \"Attachment upload blocked due to {{reason}}\": \"{{reason}} nedeniyle ek yükleme engellendi\",\n  \"Attachment upload failed due to {{reason}}\": \"{{reason}} nedeniyle ek yükleme başarısız oldu\",\n  \"Back\": \"Geri\",\n  \"ban-command-args\": \"[@kullanıcıadı] [metin]\",\n  \"ban-command-description\": \"Bir kullanıcıyı yasakla\",\n  \"Block User\": \"Kullanıcıyı engelle\",\n  \"Cancel\": \"İptal\",\n  \"Cannot seek in the recording\": \"Kayıtta arama yapılamıyor\",\n  \"Channel archived\": \"Kanal arşivlendi\",\n  \"Channel Missing\": \"Kanal bulunamıyor\",\n  \"Channel muted\": \"Kanal sessize alındı\",\n  \"Channel pinned\": \"Kanal sabitlendi\",\n  \"Channel unarchived\": \"Kanal arşivden çıkarıldı\",\n  \"Channel unmuted\": \"Kanal sesi açıldı\",\n  \"Channel unpinned\": \"Kanal sabitlemesi kaldırıldı\",\n  \"Channels\": \"Kanallar\",\n  \"Chats\": \"Sohbetler\",\n  \"Choose between 2 to 10 options\": \"2 ile 10 seçenek arasından seçin\",\n  \"Close\": \"Kapat\",\n  \"Close dialog\": \"İletişim kutusunu kapat\",\n  \"Close emoji picker\": \"Emoji seçiciyi kapat\",\n  \"Close prompt: {{ title }}\": \"İstemi kapat: {{ title }}\",\n  \"Command not available while editing\": \"Düzenleme sırasında komut kullanılamaz\",\n  \"Command not available while replying\": \"Yanıtlama sırasında komut kullanılamaz\",\n  \"Commands\": \"Komutlar\",\n  \"Commands matching\": \"Eşleşen komutlar\",\n  \"Connection failure, reconnecting now...\": \"Bağlantı hatası, tekrar bağlanılıyor...\",\n  \"Copy Message\": \"Mesajı kopyala\",\n  \"Create\": \"Oluştur\",\n  \"Create a question, add options, and configure poll settings\": \"Bir soru oluşturun, seçenekler ekleyin ve anket ayarlarını yapılandırın\",\n  \"Create poll\": \"Anket oluştur\",\n  \"Current location\": \"Mevcut konum\",\n  \"Delete\": \"Sil\",\n  \"Delete for me\": \"Benim için sil\",\n  \"Delete message\": \"Mesajı sil\",\n  \"Delivered\": \"İletildi\",\n  \"Direct message\": \"Doğrudan mesaj\",\n  \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Bu anketi şimdi sonlandırmak istiyor musunuz? Sonlandırdıktan sonra bu ankette kimse oy kullanamayacak.\",\n  \"Download All\": \"Tümünü indir\",\n  \"Download Attachment\": \"Eki indir\",\n  \"Download attachment {{ name }}\": \"Ek {{ name }}'i indir\",\n  \"Drag your files here\": \"Dosyalarınızı buraya sürükleyin\",\n  \"Drag your files here to add to your post\": \"Gönderinize eklemek için dosyalarınızı buraya sürükleyin\",\n  \"Due {{ timeLeft }}\": \"{{ timeLeft }} içinde süresi dolacak\",\n  \"Due since {{ dueSince }}\": \"{{ dueSince }}'den beri süresi dolmuş\",\n  \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n  \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n  \"Edit Message\": \"Mesajı Düzenle\",\n  \"Edit message request failed\": \"Mesaj düzenleme isteği başarısız oldu\",\n  \"Edited\": \"Düzenlendi\",\n  \"Emoji matching\": \"Emoji eşleştirme\",\n  \"Empty message...\": \"Boş mesaj...\",\n  \"End\": \"Son\",\n  \"End poll\": \"Anketi sonlandır\",\n  \"End this poll?\": \"Bu anketi sonlandır?\",\n  \"End vote\": \"Oyu bitir\",\n  \"Enforce unique vote is enabled\": \"Benzersiz oy etkinleştirildi\",\n  \"Error\": \"Hata\",\n  \"Error adding flag\": \"Bayrak eklenirken hata oluştu\",\n  \"Error connecting to chat, refresh the page to try again.\": \"Bağlantı hatası, sayfayı yenileyip tekrar deneyin.\",\n  \"Error deleting message\": \"Mesaj silinirken hata oluştu\",\n  \"Error fetching reactions\": \"Reaksiyonlar alınırken hata oluştu\",\n  \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Mesajı okunmamış olarak işaretleme hatası. En yeni 100 kanal mesajından daha eski okunmamış mesajları işaretleme yapılamaz.\",\n  \"Error muting a user ...\": \"Kullanıcıyı sessize alırken hata oluştu ...\",\n  \"Error pinning message\": \"Mesaj sabitlenirken hata oluştu\",\n  \"Error removing message pin\": \"Mesaj PIN'i kaldırılırken hata oluştu\",\n  \"Error reproducing the recording\": \"Kaydı yeniden üretme hatası\",\n  \"Error starting recording\": \"Kayıt başlatılırken hata oluştu\",\n  \"Error unmuting a user ...\": \"Kullanıcının sesini açarken hata oluştu ...\",\n  \"Error uploading attachment\": \"Ek yüklenirken hata oluştu\",\n  \"Error uploading file\": \"Dosya yüklenirken hata oluştu\",\n  \"Error uploading image\": \"Resmi yüklerken hata\",\n  \"Error: {{ errorMessage }}\": \"Hata: {{ errorMessage }}\",\n  \"Exit command {{ command }}\": \"Komuttan çık {{ command }}\",\n  \"Failed to block user\": \"Kullanıcı engellenemedi\",\n  \"Failed to create the poll\": \"Anket oluşturulurken hata oluştu\",\n  \"Failed to create the poll due to {{reason}}\": \"{{reason}} nedeniyle anket oluşturulamadı\",\n  \"Failed to delete the message\": \"Mesaj silinemedi\",\n  \"Failed to end the poll\": \"Anket sonlandırılamadı\",\n  \"Failed to end the poll due to {{reason}}\": \"{{reason}} nedeniyle anket sonlandırılamadı\",\n  \"Failed to jump to the first unread message\": \"İlk okunmamış mesaja atlamada hata oluştu\",\n  \"Failed to leave channel\": \"Kanaldan çıkılamadı\",\n  \"Failed to load channels\": \"Kanallar yüklenemedi\",\n  \"Failed to load more channels\": \"Daha fazla kanal yüklenemedi\",\n  \"Failed to mark channel as read\": \"Kanalı okundu olarak işaretleme başarısız oldu\",\n  \"Failed to play the recording\": \"Kayıt oynatılamadı\",\n  \"Failed to retrieve location\": \"Konum alınamadı\",\n  \"Failed to share location\": \"Konum paylaşılamadı\",\n  \"Failed to update channel archive status\": \"Kanalın arşiv durumu güncellenemedi\",\n  \"Failed to update channel mute status\": \"Kanalın sessiz durumu güncellenemedi\",\n  \"Failed to update channel pinned status\": \"Kanalın sabitleme durumu güncellenemedi\",\n  \"File\": \"Dosya\",\n  \"File is required for upload attachment\": \"Ek yüklemek için dosya gerekli\",\n  \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Dosya çok büyük: {{ size }}, maksimum yükleme boyutu {{ limit }}\",\n  \"File too large\": \"Dosya çok büyük\",\n  \"fileCount_one\": \"1 dosya\",\n  \"fileCount_other\": \"{{ count }} dosya\",\n  \"Flag\": \"Bayrak\",\n  \"Generating...\": \"Oluşturuluyor...\",\n  \"giphy-command-args\": \"[metin]\",\n  \"giphy-command-description\": \"Rastgele bir gif'i kanala gönder\",\n  \"Hide who voted\": \"Kimin oy verdiğini gizle\",\n  \"Image\": \"Görsel\",\n  \"imageCount_one\": \"Görsel\",\n  \"imageCount_other\": \"{{ count }} görsel\",\n  \"Instant commands\": \"Anlık komutlar\",\n  \"language/af\": \"Afrikanca\",\n  \"language/am\": \"Amharca\",\n  \"language/ar\": \"Arapça\",\n  \"language/az\": \"Azerice\",\n  \"language/bg\": \"Bulgarca\",\n  \"language/bn\": \"Bengalce\",\n  \"language/bs\": \"Boşnakça\",\n  \"language/cs\": \"Çekçe\",\n  \"language/da\": \"Danca\",\n  \"language/de\": \"Almanca\",\n  \"language/el\": \"Yunanca\",\n  \"language/en\": \"İngilizce\",\n  \"language/es\": \"İspanyolca\",\n  \"language/es-MX\": \"İspanyolca (Meksika)\",\n  \"language/et\": \"Estonyaca\",\n  \"language/fa\": \"Farsça\",\n  \"language/fa-AF\": \"Darice\",\n  \"language/fi\": \"Fince\",\n  \"language/fr\": \"Fransızca\",\n  \"language/fr-CA\": \"Fransızca (Kanada)\",\n  \"language/ha\": \"Hausa\",\n  \"language/he\": \"İbranice\",\n  \"language/hi\": \"Hintçe\",\n  \"language/hr\": \"Hırvatça\",\n  \"language/ht\": \"Haiti Kreolcesi\",\n  \"language/hu\": \"Macarca\",\n  \"language/id\": \"Endonezce\",\n  \"language/it\": \"İtalyanca\",\n  \"language/ja\": \"Japonca\",\n  \"language/ka\": \"Gürcüce\",\n  \"language/ko\": \"Korece\",\n  \"language/lt\": \"Litvanca\",\n  \"language/lv\": \"Letonca\",\n  \"language/ms\": \"Malayca\",\n  \"language/nl\": \"Felemenkçe\",\n  \"language/no\": \"Norveççe\",\n  \"language/pl\": \"Lehçe\",\n  \"language/ps\": \"Peştuca\",\n  \"language/pt\": \"Portekizce\",\n  \"language/ro\": \"Romence\",\n  \"language/ru\": \"Rusça\",\n  \"language/sk\": \"Slovakça\",\n  \"language/sl\": \"Slovence\",\n  \"language/so\": \"Somalice\",\n  \"language/sq\": \"Arnavutça\",\n  \"language/sr\": \"Sırpça\",\n  \"language/sv\": \"İsveççe\",\n  \"language/sw\": \"Svahilice\",\n  \"language/ta\": \"Tamilce\",\n  \"language/th\": \"Tayca\",\n  \"language/tl\": \"Tagalogca\",\n  \"language/tr\": \"Türkçe\",\n  \"language/uk\": \"Ukraynaca\",\n  \"language/ur\": \"Urduca\",\n  \"language/vi\": \"Vietnamca\",\n  \"language/zh\": \"Çince (basitleştirilmiş)\",\n  \"language/zh-TW\": \"Çince (geleneksel)\",\n  \"Leave Channel\": \"Kanaldan ayrıl\",\n  \"Left channel\": \"Kanaldan ayrıldınız\",\n  \"Let others add options\": \"Başkalarının seçenek eklemesine izin ver\",\n  \"Limit votes per person\": \"Kişi başına oy sınırı\",\n  \"Link\": \"Bağlantı\",\n  \"linkCount_one\": \"Bağlantı\",\n  \"linkCount_other\": \"{{ count }} bağlantı\",\n  \"live\": \"canlı\",\n  \"Live for {{duration}}\": \"{{duration}} boyunca canlı\",\n  \"Live location\": \"Canlı konum\",\n  \"Live until {{ timestamp }}\": \"{{ timestamp }}'e kadar canlı\",\n  \"Load more\": \"Daha fazla yükle\",\n  \"Local upload attachment missing local id\": \"Yerel yükleme ekinde yerel kimlik eksik\",\n  \"Location\": \"Konum\",\n  \"Location sharing ended\": \"Konum paylaşımı sona erdi\",\n  \"Location: {{ coordinates }}\": \"Konum: {{ coordinates }}\",\n  \"Mark as unread\": \"Okunmamış olarak işaretle\",\n  \"Maximum number of votes (from 2 to 10)\": \"Maksimum oy sayısı (2 ile 10 arası)\",\n  \"Maximum votes per person\": \"Kişi başına maksimum oy\",\n  \"Menu\": \"Menü\",\n  \"Message deleted\": \"Mesaj silindi\",\n  \"Message failed to send\": \"Mesaj gönderilemedi\",\n  \"Message has been successfully flagged\": \"Mesaj başarıyla bayraklandı\",\n  \"Message marked as unread\": \"Mesaj okunmadı olarak işaretlendi\",\n  \"Message pinned\": \"Mesaj sabitlendi\",\n  \"Message unpinned\": \"Mesaj sabitlemesi kaldırıldı\",\n  \"Message was blocked by moderation policies\": \"Mesaj moderasyon politikaları tarafından engellendi\",\n  \"Messages have been marked unread.\": \"Mesajlar okunmamış olarak işaretlendi.\",\n  \"Missing permissions to upload the attachment\": \"Ek yüklemek için izinler eksik\",\n  \"Multiple votes\": \"Çoklu oy\",\n  \"Mute\": \"Sessiz\",\n  \"mute-command-args\": \"[@kullanıcıadı]\",\n  \"mute-command-description\": \"Bir kullanıcının sesini kapat\",\n  \"network error\": \"ağ hatası\",\n  \"New\": \"Yeni\",\n  \"New message from {{user}}\": \"{{user}} adlı kullanıcıdan yeni mesaj\",\n  \"New Messages!\": \"Yeni Mesajlar!\",\n  \"Next image\": \"Sonraki görsel\",\n  \"No chats here yet…\": \"Henüz burada sohbet yok...\",\n  \"No conversations yet\": \"Henüz konuşma yok\",\n  \"No items exist\": \"Hiç öğe yok\",\n  \"No results found\": \"Sonuç bulunamadı\",\n  \"Nobody will be able to vote in this poll anymore.\": \"Artık bu ankette kimse oy kullanamayacak.\",\n  \"Nothing yet...\": \"Şimdilik hiçbir şey...\",\n  \"Offline\": \"Çevrimdışı\",\n  \"Ok\": \"Tamam\",\n  \"Online\": \"Çevrimiçi\",\n  \"Only numbers are allowed\": \"Sadece sayılar kullanılabilir\",\n  \"Only visible to you\": \"Sadece sana görünür\",\n  \"Open emoji picker\": \"Emoji klavyesini aç\",\n  \"Open gallery at image {{ index }}\": \"Galeriyi {{ index }}. görselde aç\",\n  \"Open image in gallery\": \"Görseli galeride aç\",\n  \"Open location in a map\": \"Konumu haritada aç\",\n  \"Option already exists\": \"Seçenek zaten mevcut\",\n  \"Option is empty\": \"Seçenek boş\",\n  \"Options\": \"Seçenekler\",\n  \"Original\": \"Orijinal\",\n  \"People matching\": \"Eşleşen kişiler\",\n  \"Photo\": \"Fotoğraf\",\n  \"Pin\": \"Sabitle\",\n  \"Pinned by {{ name }}\": \"{{ name }} sabitledi\",\n  \"Pinned by You\": \"Sizin sabitlediğiniz\",\n  \"placeholder/PollComment\": \"Yorumunuz\",\n  \"placeholder/PollOptionSuggestion\": \"Yeni bir seçenek girin\",\n  \"Play video\": \"Videoyu oynat\",\n  \"Playback speed {{ rate }}x\": \"Oynatma hızı {{ rate }}x\",\n  \"Poll\": \"Anket\",\n  \"Poll comments\": \"Anket yorumları\",\n  \"Poll ended\": \"Anket sonlandı\",\n  \"Poll options\": \"Anket seçenekleri\",\n  \"Poll results\": \"Anket sonuçları\",\n  \"Previous image\": \"Önceki görsel\",\n  \"Question\": \"Soru\",\n  \"Question {{ optionOrderNumber}}\": \"Soru {{ optionOrderNumber}}\",\n  \"Question is required\": \"Soru gereklidir\",\n  \"Quote Reply\": \"Alıntıyla yanıtla\",\n  \"Reached the vote limit. Remove an existing vote first.\": \"Oylama sınırına ulaşıldı. Önce mevcut bir oyu kaldırın.\",\n  \"Recording format is not supported and cannot be reproduced\": \"Kayıt formatı desteklenmiyor ve çoğaltılamıyor\",\n  \"Remind me\": \"Bana hatırlat\",\n  \"Remind Me\": \"Hatırlat\",\n  \"Reminder set\": \"Hatırlatıcı ayarlandı\",\n  \"Remove reminder\": \"Hatırlatıcıyı kaldır\",\n  \"Remove save for later\": \"Sonraya kaydet'i kaldır\",\n  \"Replied to a thread\": \"Bir iş parçacığına yanıt verdi\",\n  \"Reply\": \"Cevapla\",\n  \"Reply to {{ authorName }}\": \"{{ authorName }} kişisine yanıt ver\",\n  \"Reply to a message to start a thread\": \"Bir thread başlatmak için bir mesaja yanıt verin\",\n  \"Reply to Message\": \"Mesaja Cevapla\",\n  \"replyCount_one\": \"1 cevap\",\n  \"replyCount_other\": \"{{ count }} cevap\",\n  \"Resend\": \"Tekrar gönder\",\n  \"Retry upload\": \"Yüklemeyi yeniden dene\",\n  \"Review all options available in this poll\": \"Bu anketteki tüm mevcut seçenekleri inceleyin\",\n  \"Review comments submitted with poll answers\": \"Anket yanıtlarıyla gönderilen yorumları inceleyin\",\n  \"Review poll results and open an option to see detailed votes\": \"Anket sonuçlarını inceleyin ve ayrıntılı oyları görmek için bir seçenek açın\",\n  \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Bu mesajı inceleyin ve silmeyi, düzenlemeyi veya yine de göndermeyi seçin\",\n  \"Review who voted for this option\": \"Bu seçenek için kimlerin oy verdiğini inceleyin\",\n  \"Save for later\": \"Daha sonra kaydet\",\n  \"Saved for later\": \"Daha sonra kaydedildi\",\n  \"Search\": \"Arama\",\n  \"Search GIFs\": \"GIF ara\",\n  \"search-results-header-filter-source-button-label--channels\": \"kanallar\",\n  \"search-results-header-filter-source-button-label--messages\": \"mesajlar\",\n  \"search-results-header-filter-source-button-label--users\": \"kullanıcılar\",\n  \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }} aranıyor...\",\n  \"Searching...\": \"Aranıyor...\",\n  \"searchResultsCount_one\": \"1 sonuç\",\n  \"searchResultsCount_other\": \"{{ count }} sonuç\",\n  \"Select a thread to continue the conversation\": \"Sohbeti sürdürmek için bir ileti dizisi seçin\",\n  \"Select more than one option\": \"Birden fazla seçenek seçin\",\n  \"Select one\": \"Birini seçin\",\n  \"Select one or more\": \"Bir veya daha fazlasını seçin\",\n  \"Select up to {{count}}_one\": \"En fazla {{count}}'yi seçin\",\n  \"Select up to {{count}}_other\": \"En fazla {{count}}'yi seçin\",\n  \"Select your current location and optionally enable live location sharing\": \"Mevcut konumunuzu seçin ve isteğe bağlı olarak canlı konum paylaşımını etkinleştirin\",\n  \"Send\": \"Gönder\",\n  \"Send a message\": \"Bir mesaj gönderin\",\n  \"Send a message to start the conversation\": \"Sohbete başlamak için bir mesaj gönderin\",\n  \"Send Anyway\": \"Yine de gönder\",\n  \"Send message request failed\": \"Mesaj gönderme isteği başarısız oldu\",\n  \"Send poll\": \"Anketi gönder\",\n  \"Sending...\": \"Gönderiliyor...\",\n  \"Sent\": \"Gönderildi\",\n  \"Share\": \"Paylaş\",\n  \"Share live location for\": \"Canlı konum paylaş\",\n  \"Share Location\": \"Konum Paylaş\",\n  \"Shared live location\": \"Paylaşılan canlı konum\",\n  \"Shared location\": \"Paylaşılan konum\",\n  \"Shuffle\": \"Karıştır\",\n  \"size limit\": \"boyut sınırı\",\n  \"Slow Mode ON\": \"Yavaş Mod Açık\",\n  \"Slow mode, wait {{ seconds }}s...\": \"Yavaş mod, {{ seconds }} sn bekleyin...\",\n  \"Some of the files will not be accepted\": \"Bazı dosyalar kabul edilmeyecek\",\n  \"Start typing to search\": \"Aramak için yazmaya başlayın\",\n  \"Stop sharing\": \"Paylaşımı durdur\",\n  \"Submit\": \"Gönder\",\n  \"Suggest a new option to add to this poll\": \"Bu ankete eklenecek yeni bir seçenek önerin\",\n  \"Suggest an option\": \"Bir seçenek önerin\",\n  \"Tap to remove\": \"Kaldırmak için dokunun\",\n  \"Tap to remove: {{ reactionName }}\": \"Kaldırmak için dokunun: {{ reactionName }}\",\n  \"Thinking...\": \"Düşünüyor...\",\n  \"this content could not be displayed\": \"bu içerik gösterilemiyor\",\n  \"This field cannot be empty or contain only spaces\": \"Bu alan boş olamaz veya sadece boşluk içeremez\",\n  \"This message did not meet our content guidelines\": \"Bu mesaj içerik yönergelerimize uygun değil\",\n  \"Thread\": \"Konu\",\n  \"Thread has not been found\": \"Konu bulunamadı\",\n  \"Thread reply\": \"Konu yanıtı\",\n  \"Thread Reply\": \"Konu yanıtı\",\n  \"ThreadListUnseenThreadsBanner/loading\": \"Yükleniyor...\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} okunmamış ileti dizisi\",\n  \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} okunmamış ileti dizisi\",\n  \"Threads\": \"İleti dizileri\",\n  \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Dün]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n  \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Bugün]\\\", \\\"nextDay\\\": \\\"[Yarın]\\\", \\\"lastDay\\\": \\\"[Dün]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Geçen] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n  \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n  \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n  \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n  \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n  \"timestamp/relativeToday\": \"Bugün\",\n  \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n  \"timestamp/relativeYesterday\": \"Dün\",\n  \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n  \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n  \"To start recording, allow the camera access in your browser\": \"Kayıt yapmaya başlamak için tarayıcınızda kameraya erişime izin verin\",\n  \"To start recording, allow the microphone access in your browser\": \"Kayıt yapmaya başlamak için tarayıcınızda mikrofona erişime izin verin\",\n  \"totalVoteCount_one\": \"toplam 1 oy\",\n  \"totalVoteCount_other\": \"toplam {{ count }} oy\",\n  \"Translated\": \"Çevrildi\",\n  \"Translated from {{ language }}\": \"{{ language }} dilinden çevrildi\",\n  \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n  \"Type a number from 2 to 10\": \"2 ile 10 arasında bir sayı yazın\",\n  \"Unarchive\": \"Arşivden çıkar\",\n  \"unban-command-args\": \"[@kullanıcıadı]\",\n  \"unban-command-description\": \"Bir kullanıcının yasağını kaldır\",\n  \"Unblock User\": \"Kullanıcının engelini kaldır\",\n  \"unknown error\": \"bilinmeyen hata\",\n  \"Unmute\": \"Sesini aç\",\n  \"unmute-command-args\": \"[@kullanıcıadı]\",\n  \"unmute-command-description\": \"Bir kullanıcının sesini aç\",\n  \"Unpin\": \"Sabitlemeyi kaldır\",\n  \"Unread messages\": \"Okunmamış mesajlar\",\n  \"Unsupported attachment\": \"Desteklenmeyen ek\",\n  \"unsupported file type\": \"desteklenmeyen dosya türü\",\n  \"Update\": \"Güncelle\",\n  \"Update the comment attached to your poll answer\": \"Anket yanıtınıza ekli yorumu güncelleyin\",\n  \"Update your comment\": \"Yorumunuzu güncelleyin\",\n  \"Upload blocked\": \"Yükleme engellendi\",\n  \"Upload error\": \"Yükleme hatası\",\n  \"Upload failed\": \"Yükleme başarısız oldu\",\n  \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Yükleme türü: \\\"{{ type }}\\\" izin verilmez\",\n  \"User blocked\": \"Kullanıcı engellendi\",\n  \"User unblocked\": \"Kullanıcının engeli kaldırıldı\",\n  \"User uploaded content\": \"Kullanıcı tarafından yüklenen içerik\",\n  \"Video\": \"Video\",\n  \"videoCount_one\": \"Video\",\n  \"videoCount_other\": \"{{ count }} video\",\n  \"View\": \"Görüntüle\",\n  \"View {{count}} comments_one\": \"{{count}} yorumu görüntüle\",\n  \"View {{count}} comments_other\": \"{{count}} yorumu görüntüle\",\n  \"View all\": \"Tümünü görüntüle\",\n  \"View original\": \"Orijinali görüntüle\",\n  \"View results\": \"Sonuçları görüntüle\",\n  \"View translation\": \"Çeviriyi görüntüle\",\n  \"Voice message\": \"Sesli mesaj\",\n  \"Voice message {{ duration }}\": \"Sesli mesaj {{ duration }}\",\n  \"Voice message deleted\": \"Sesli mesaj silindi\",\n  \"voiceMessageCount_one\": \"Sesli mesaj\",\n  \"voiceMessageCount_other\": \"{{ count }} sesli mesaj\",\n  \"Vote ended\": \"Oylama sona erdi\",\n  \"Votes\": \"Oylar\",\n  \"Wait until all attachments have uploaded\": \"Tüm ekler yüklenene kadar bekleyin\",\n  \"Waiting for network…\": \"Ağ bekleniyor…\",\n  \"You\": \"Sen\",\n  \"You've reached the maximum number of files\": \"Maksimum dosya sayısına ulaştınız\"\n}\n","import type { i18n, TFunction } from 'i18next';\n\ntype TopicName = string;\ntype TranslatorName = string;\n\nexport type Translator<O extends Record<string, unknown> = Record<string, unknown>> =\n  (params: { key: string; value: string; t: TFunction; options: O }) => string | null;\n\nexport type TranslationTopicOptions<\n  O extends Record<string, unknown> = Record<string, unknown>,\n> = {\n  i18next: i18n;\n  translators?: Record<string, Translator<O>>;\n};\n\nexport abstract class TranslationTopic<\n  O extends Record<string, unknown> = Record<string, unknown>,\n> {\n  protected translators: Map<string, Translator<O>> = new Map();\n  protected i18next: i18n;\n\n  constructor(protected options: TranslationTopicOptions<O>) {\n    this.i18next = options.i18next;\n    if (options.translators) {\n      Object.entries(options.translators).forEach(([name, translator]) => {\n        this.setTranslator(name, translator);\n      });\n    }\n  }\n\n  abstract translate(value: string, key: string, options: O): string;\n\n  setTranslator = (name: string, translator: Translator<O>) => {\n    this.translators.set(name, translator);\n  };\n\n  removeTranslator = (name: string) => {\n    this.translators.delete(name);\n  };\n}\n\nconst forwardTranslation: Translator = ({ value }) => value;\n\nexport type TranslationTopicConstructor = new (\n  options: TranslationTopicOptions,\n) => TranslationTopic;\n\nexport class TranslationBuilder {\n  private topics = new Map<string, TranslationTopic>();\n  // need to keep a registration buffer so that translators can be registered once a topic is registered\n  // what does not happen when Streami18n is instantiated but rather once Streami18n.init() is invoked\n  private translatorRegistrationsBuffer: Record<\n    TopicName,\n    Record<TranslatorName, Translator>\n  > = {};\n\n  constructor(private i18next: i18n) {}\n\n  registerTopic = (name: TopicName, Topic: TranslationTopicConstructor) => {\n    let topic = this.topics.get(name);\n\n    if (!topic) {\n      topic = new Topic({ i18next: this.i18next });\n      this.topics.set(name, topic);\n      this.i18next.use({\n        name,\n        process: (value: string, key: string, options: Record<string, unknown>) => {\n          const topic = this.topics.get(name);\n          if (!topic) return value;\n          return topic.translate(value, key, options);\n        },\n        type: 'postProcessor' as const,\n      });\n    }\n\n    const additionalTranslatorsToRegister = this.translatorRegistrationsBuffer[name];\n    if (additionalTranslatorsToRegister) {\n      Object.entries(additionalTranslatorsToRegister).forEach(\n        ([translatorName, translator]) => {\n          topic.setTranslator(translatorName, translator);\n        },\n      );\n      delete this.translatorRegistrationsBuffer[name];\n    }\n    return topic;\n  };\n\n  disableTopic = (topicName: TopicName) => {\n    const topic = this.topics.get(topicName);\n    if (!topic) return;\n    this.i18next.use({\n      name: topicName,\n      process: forwardTranslation,\n      type: 'postProcessor',\n    });\n    this.topics.delete(topicName);\n  };\n\n  getTopic = (topicName: TopicName) => this.topics.get(topicName);\n\n  registerTranslators(\n    topicName: TopicName,\n    translators: Record<TranslatorName, Translator>,\n  ) {\n    const topic = this.getTopic(topicName);\n    if (!topic) {\n      if (!this.translatorRegistrationsBuffer[topicName])\n        this.translatorRegistrationsBuffer[topicName] = {};\n\n      Object.entries(translators).forEach(([translatorName, translator]) => {\n        this.translatorRegistrationsBuffer[topicName][translatorName] = translator;\n      });\n      return;\n    }\n    Object.entries(translators).forEach(([name, translator]) => {\n      topic.setTranslator(name, translator);\n    });\n  }\n\n  removeTranslators(topicName: TopicName, translators: TranslatorName[]) {\n    const topic = this.getTopic(topicName);\n    if (this.translatorRegistrationsBuffer[topicName]) {\n      translators.forEach((translatorName) => {\n        delete this.translatorRegistrationsBuffer[topicName][translatorName];\n      });\n    }\n    if (!topic) return;\n    translators.forEach((name) => {\n      topic.removeTranslator(name);\n    });\n  }\n}\n","import type { Notification } from 'stream-chat';\n\nimport type { NotificationTranslatorOptions } from './types';\nimport type { TranslationTopicOptions, Translator } from '../../index';\n\nconst normalizeReason = (notification?: Notification) => {\n  const reason = notification?.metadata?.reason;\n  if (typeof reason !== 'string' || !reason.length) return undefined;\n  return reason.toLowerCase();\n};\n\nconst withReasonFallback = ({\n  fallbackTranslationKey,\n  notification,\n  reasonTranslationKey,\n  t,\n}: {\n  fallbackTranslationKey: string;\n  notification?: Notification;\n  reasonTranslationKey: string;\n  t: TranslationTopicOptions['i18next']['t'];\n}) => {\n  const reason = normalizeReason(notification);\n  if (!reason) return t(fallbackTranslationKey);\n  return t(reasonTranslationKey, { reason });\n};\n\nexport const translateAttachmentUploadBlocked: Translator<\n  NotificationTranslatorOptions\n> = ({ options: { notification }, t }) => {\n  const rawReason = notification?.metadata?.reason;\n  let reason = t('unsupported file type');\n  if (typeof rawReason !== 'string') reason = t('unknown error');\n  if (rawReason === 'size_limit') reason = t('size limit');\n  return t('Attachment upload blocked due to {{reason}}', { reason });\n};\n\nexport const translateAttachmentUploadFailed: Translator<\n  NotificationTranslatorOptions\n> = ({ options: { notification }, t }) =>\n  withReasonFallback({\n    fallbackTranslationKey: 'Error uploading attachment',\n    notification,\n    reasonTranslationKey: 'Attachment upload failed due to {{reason}}',\n    t,\n  });\n\nexport const translatePollCreateFailed: Translator<NotificationTranslatorOptions> = ({\n  options: { notification },\n  t,\n}) =>\n  withReasonFallback({\n    fallbackTranslationKey: 'Failed to create the poll',\n    notification,\n    reasonTranslationKey: 'Failed to create the poll due to {{reason}}',\n    t,\n  });\n\nexport const translatePollEndFailed: Translator<NotificationTranslatorOptions> = ({\n  options: { notification },\n  t,\n}) =>\n  withReasonFallback({\n    fallbackTranslationKey: 'Failed to end the poll',\n    notification,\n    reasonTranslationKey: 'Failed to end the poll due to {{reason}}',\n    t,\n  });\n\nexport const translateBrowserAudioPlaybackError: Translator<\n  NotificationTranslatorOptions\n> = ({ options: { notification }, t }) =>\n  notification?.message ? t(notification.message) : t('Error reproducing the recording');\n\nexport const translateCommandDisabled: Translator<NotificationTranslatorOptions> = ({\n  options: { notification },\n  t,\n}) => {\n  const reason = normalizeReason(notification);\n\n  if (reason === 'editing') {\n    return t('Command not available while editing');\n  }\n\n  if (reason === 'quoted_message') {\n    return t('Command not available while replying');\n  }\n\n  return t(notification?.message || 'Command not available');\n};\n","import type { NotificationTranslatorOptions } from './types';\nimport {\n  translateAttachmentUploadBlocked,\n  translateAttachmentUploadFailed,\n  translateBrowserAudioPlaybackError,\n  translateCommandDisabled,\n  translatePollCreateFailed,\n  translatePollEndFailed,\n} from './translators';\nimport type { Translator } from '../../index';\n\nexport const translatorsByNotificationType: Record<\n  string,\n  Translator<NotificationTranslatorOptions>\n> = {\n  'api:attachment:upload:failed': translateAttachmentUploadFailed,\n  'api:location:create:failed': ({ t }) => t('Failed to share location'),\n  'api:location:share:failed': ({ t }) => t('Failed to share location'),\n  'api:poll:create:failed': translatePollCreateFailed,\n  'api:poll:end:failed': translatePollEndFailed,\n  'api:poll:end:success': ({ t }) => t('Poll ended'),\n  'api:reply:search:failed': ({ t }) => t('Thread has not been found'),\n  'browser:audio:playback:error': translateBrowserAudioPlaybackError,\n  'browser:location:get:failed': ({ t }) => t('Failed to retrieve location'),\n  'channel:jumpToFirstUnread:failed': ({ t }) =>\n    t('Failed to jump to the first unread message'),\n  'validation:attachment:file:missing': ({ t }) =>\n    t('File is required for upload attachment'),\n  'validation:attachment:id:missing': ({ t }) =>\n    t('Local upload attachment missing local id'),\n  'validation:attachment:upload:blocked': translateAttachmentUploadBlocked,\n  'validation:attachment:upload:in-progress': ({ t }) =>\n    t('Wait until all attachments have uploaded'),\n  'validation:command:disabled': translateCommandDisabled,\n  'validation:poll:castVote:limit': ({ t }) =>\n    t('Reached the vote limit. Remove an existing vote first.'),\n};\n","import { TranslationTopic } from '../../TranslationBuilder';\nimport type { Notification } from 'stream-chat';\nimport type { NotificationTranslatorOptions } from './types';\nimport { translatorsByNotificationType } from './translatorsByNotificationType';\nimport type { TranslationTopicOptions, Translator } from '../../index';\n\nconst translateByNotificationType: Translator<NotificationTranslatorOptions> = ({\n  options: { notification },\n  ...params\n}) => {\n  if (!notification?.type) return null;\n  const translator = translatorsByNotificationType[notification.type];\n  if (!translator) return null;\n  return translator({ ...params, options: { notification } });\n};\n\nexport const defaultNotificationTranslators: Record<\n  string,\n  Translator<NotificationTranslatorOptions>\n> = {\n  '*': translateByNotificationType,\n};\n\nexport class NotificationTranslationTopic extends TranslationTopic<NotificationTranslatorOptions> {\n  constructor({ i18next, translators }: TranslationTopicOptions) {\n    super({ i18next, translators: defaultNotificationTranslators });\n    if (translators) {\n      Object.entries(translators).forEach(([name, translator]) => {\n        this.setTranslator(name, translator);\n      });\n    }\n  }\n\n  translate = (value: string, key: string, options: { notification?: Notification }) => {\n    const { notification } = options;\n    if (!notification) return value;\n    const byType = notification.type\n      ? this.translators.get(notification.type)\n      : undefined;\n    if (byType) return byType({ key, options, t: this.i18next.t, value }) || value;\n\n    const byFallback = this.translators.get('*');\n    const translated = byFallback?.({ key, options, t: this.i18next.t, value }) ?? null;\n    if (translated) return translated;\n    if (!notification.message) return value;\n\n    // Final fallback: attempt to translate message as natural key.\n    return this.i18next.t(notification.message, {\n      ...(notification.metadata ?? {}),\n      value: notification.message,\n    });\n  };\n}\n","import i18n from 'i18next';\nimport Dayjs from 'dayjs';\nimport calendar from 'dayjs/plugin/calendar';\nimport updateLocale from 'dayjs/plugin/updateLocale';\nimport LocalizedFormat from 'dayjs/plugin/localizedFormat';\nimport localeData from 'dayjs/plugin/localeData';\nimport relativeTime from 'dayjs/plugin/relativeTime';\nimport duration from 'dayjs/plugin/duration';\nimport utc from 'dayjs/plugin/utc';\nimport timezone from 'dayjs/plugin/timezone';\nimport { NotificationTranslationTopic, TranslationBuilder } from './TranslationBuilder';\nimport { defaultTranslatorFunction, predefinedFormatters } from './utils';\n\nimport type { i18n as I18n, TFunction } from 'i18next';\nimport type momentTimezone from 'moment-timezone';\nimport type { TranslationLanguages } from 'stream-chat';\n\nimport type { TranslationTopicConstructor } from './TranslationBuilder';\nimport type { UnknownType } from '../types/types';\nimport type { CustomFormatters, PredefinedFormatters, TDateTimeParser } from './types';\n\nimport {\n  deTranslations,\n  enTranslations,\n  esTranslations,\n  frTranslations,\n  hiTranslations,\n  itTranslations,\n  jaTranslations,\n  koTranslations,\n  nlTranslations,\n  ptTranslations,\n  ruTranslations,\n  trTranslations,\n} from './translations';\n\nimport 'dayjs/locale/de';\nimport 'dayjs/locale/es';\nimport 'dayjs/locale/fr';\nimport 'dayjs/locale/hi';\nimport 'dayjs/locale/it';\nimport 'dayjs/locale/ja';\nimport 'dayjs/locale/ko';\nimport 'dayjs/locale/nl';\nimport 'dayjs/locale/pt';\nimport 'dayjs/locale/ru';\nimport 'dayjs/locale/tr';\n// These locale imports also set these locale globally.\n// So As a last step I am going to import english locale\n// to make sure I don't mess up language at other places in app.\nimport 'dayjs/locale/en';\n\nconst defaultNS = 'translation';\nconst defaultLng = 'en';\n\ntype CalendarLocaleConfig = {\n  lastDay: string;\n  lastWeek: string;\n  nextDay: string;\n  nextWeek: string;\n  sameDay: string;\n  sameElse: string;\n};\n\nDayjs.extend(updateLocale);\nDayjs.extend(utc);\nDayjs.extend(timezone);\n\nDayjs.updateLocale('de', {\n  calendar: {\n    lastDay: '[gestern um] LT',\n    lastWeek: '[letzten] dddd [um] LT',\n    nextDay: '[morgen um] LT',\n    nextWeek: 'dddd [um] LT',\n    sameDay: '[heute um] LT',\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('es', {\n  calendar: {\n    lastDay: '[ayer a las] LT',\n    lastWeek: '[pasado] dddd [a] LT',\n    nextDay: '[mañana a] LT',\n    nextWeek: 'dddd [a] LT',\n    sameDay: '[hoy a las] LT',\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('fr', {\n  calendar: {\n    lastDay: '[Hier à] LT',\n    lastWeek: 'dddd [dernier à] LT',\n    nextDay: '[Demain à] LT',\n    nextWeek: 'dddd [à] LT',\n    sameDay: \"[Aujourd'hui à] LT\",\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('hi', {\n  calendar: {\n    lastDay: '[कल] LT',\n    lastWeek: '[पिछले] dddd, LT',\n    nextDay: '[कल] LT',\n    nextWeek: 'dddd, LT',\n    sameDay: '[आज] LT',\n    sameElse: 'L',\n  },\n  // Hindi notation for meridiems are quite fuzzy in practice. While there exists\n  // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.\n  meridiem(hour: number) {\n    if (hour < 4) {\n      return 'रात';\n    } else if (hour < 10) {\n      return 'सुबह';\n    } else if (hour < 17) {\n      return 'दोपहर';\n    } else if (hour < 20) {\n      return 'शाम';\n    } else {\n      return 'रात';\n    }\n  },\n  meridiemHour(hour: number, meridiem: string) {\n    if (hour === 12) {\n      hour = 0;\n    }\n    if (meridiem === 'रात') {\n      return hour < 4 ? hour : hour + 12;\n    } else if (meridiem === 'सुबह') {\n      return hour;\n    } else if (meridiem === 'दोपहर') {\n      return hour >= 10 ? hour : hour + 12;\n    } else if (meridiem === 'शाम') {\n      return hour + 12;\n    }\n    return hour;\n  },\n  meridiemParse: /रात|सुबह|दोपहर|शाम/,\n});\n\nDayjs.updateLocale('it', {\n  calendar: {\n    lastDay: '[Ieri alle] LT',\n    lastWeek: '[lo scorso] dddd [alle] LT',\n    nextDay: '[Domani alle] LT',\n    nextWeek: 'dddd [alle] LT',\n    sameDay: '[Oggi alle] LT',\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('ja', {\n  calendar: {\n    lastDay: '[昨日] LT',\n    lastWeek: 'dddd LT',\n    nextDay: '[明日] LT',\n    nextWeek: '[次の] dddd LT',\n    sameDay: '[今日] LT',\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('ko', {\n  calendar: {\n    lastDay: '[어제] LT',\n    lastWeek: '[지난] dddd LT',\n    nextDay: '[내일] LT',\n    nextWeek: 'dddd LT',\n    sameDay: '[오늘] LT',\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('nl', {\n  calendar: {\n    lastDay: '[gisteren om] LT',\n    lastWeek: '[afgelopen] dddd [om] LT',\n    nextDay: '[morgen om] LT',\n    nextWeek: 'dddd [om] LT',\n    sameDay: '[vandaag om] LT',\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('pt', {\n  calendar: {\n    lastDay: '[ontem às] LT',\n    lastWeek: 'dddd [passada às] LT',\n    nextDay: '[amanhã às] LT',\n    nextWeek: 'dddd [às] LT',\n    sameDay: '[hoje às] LT',\n    sameElse: 'L',\n  },\n});\n\nDayjs.updateLocale('ru', {\n  calendar: {\n    lastDay: '[Вчера, в] LT',\n    nextDay: '[Завтра, в] LT',\n    sameDay: '[Сегодня, в] LT',\n  },\n});\n\nDayjs.updateLocale('tr', {\n  calendar: {\n    lastDay: '[dün] LT',\n    lastWeek: '[geçen] dddd [saat] LT',\n    nextDay: '[yarın saat] LT',\n    nextWeek: '[gelecek] dddd [saat] LT',\n    sameDay: '[bugün saat] LT',\n    sameElse: 'L',\n  },\n});\n\nconst en_locale = {\n  formats: {},\n  months: [\n    'January',\n    'February',\n    'March',\n    'April',\n    'May',\n    'June',\n    'July',\n    'August',\n    'September',\n    'October',\n    'November',\n    'December',\n  ],\n  relativeTime: {},\n  weekdays: [\n    'Sunday',\n    'Monday',\n    'Tuesday',\n    'Wednesday',\n    'Thursday',\n    'Friday',\n    'Saturday',\n  ],\n};\n\ntype DateTimeParserModule = typeof Dayjs | typeof momentTimezone;\n// Type guards to check DayJs\nconst isDayJs = (dateTimeParser: DateTimeParserModule): dateTimeParser is typeof Dayjs =>\n  (dateTimeParser as typeof Dayjs).extend !== undefined;\n\ntype TimezoneParser = {\n  tz: momentTimezone.MomentTimezone | Dayjs.Dayjs;\n};\nconst supportsTz = (dateTimeParser: unknown): dateTimeParser is TimezoneParser =>\n  (dateTimeParser as TimezoneParser).tz !== undefined;\n\nexport type Streami18nOptions = {\n  DateTimeParser?: DateTimeParserModule;\n  dayjsLocaleConfigForLanguage?: Partial<ILocale> & { calendar?: CalendarLocaleConfig };\n  debug?: boolean;\n  disableDateTimeTranslations?: boolean;\n  formatters?: Partial<PredefinedFormatters> & CustomFormatters;\n  language?: TranslationLanguages;\n  logger?: (message?: string) => void;\n  translationBuilderTopics?: Record<string, TranslationTopicConstructor>;\n  parseMissingKeyHandler?: (key: string, defaultValue?: string) => string;\n  timezone?: string;\n  translationsForLanguage?: Partial<typeof enTranslations>;\n};\n\n/**\n * Wrapper around [i18next](https://www.i18next.com/) class for Stream related i18n.\n * Instance of this class should be provided to Chat component to handle i18n.\n * Stream provides following list of in-built i18n:\n * 1. English (en)\n * 2. Dutch (nl)\n * 3. Russian (ru)\n * 4. Turkish (tr)\n * 5. French (fr)\n * 6. Italian (it)\n * 7. Hindi (hi)\n * 8. Spanish (es)\n * 9. Portuguese (pt)\n * 10. German (de)\n * 11. Japanese (ja)\n * 12. Korean (ko)\n *\n * Simplest way to start using chat components in one of the in-built languages would be following:\n *\n * ```\n * const i18n = new Streami18n({ language 'nl' });\n * <Chat client={chatClient} i18nInstance={i18n}>\n *  ...\n * </Chat>\n * ```\n *\n * If you would like to override certain keys in in-built translation.\n * UI will be automatically updated in this case.\n *\n * ```\n * const i18n = new Streami18n({\n *  language: 'nl',\n *  translationsForLanguage: {\n *    'Nothing yet...': 'Nog Niet ...',\n *    '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} en {{ secondUser }} zijn aan het typen...',\n *  }\n * });\n *\n * If you would like to register additional languages, use registerTranslation. You can add as many languages as you want:\n *\n * i18n.registerTranslation('zh', {\n *  'Nothing yet...': 'Nog Niet ...',\n *  '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} en {{ secondUser }} zijn aan het typen...',\n * });\n *\n * <Chat client={chatClient} i18nInstance={i18n}>\n *  ...\n * </Chat>\n * ```\n *\n * You can use the same function to add whole new language as well.\n *\n * ```\n * const i18n = new Streami18n();\n *\n * i18n.registerTranslation('mr', {\n *  'Nothing yet...': 'काहीही नाही  ...',\n *  '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} आणि {{ secondUser }} टीपी करत आहेत ',\n * });\n *\n * // Make sure to call setLanguage to reflect new language in UI.\n * i18n.setLanguage('it');\n * <Chat client={chatClient} i18nInstance={i18n}>\n *  ...\n * </Chat>\n * ```\n *\n * ## Datetime i18n\n *\n * Stream react chat components uses [dayjs](https://day.js.org/en/) internally by default to format datetime stamp.\n * e.g., in ChannelPreview, MessageContent components.\n * Dayjs has locale support as well - https://day.js.org/docs/en/i18n/i18n\n * Dayjs is a lightweight alternative to Momentjs with the same modern API.\n *\n * Dayjs provides locale config for plenty of languages, you can check the whole list of locale configs at following url\n * https://github.com/iamkun/dayjs/tree/dev/src/locale\n *\n * You can either provide the dayjs locale config while registering\n * language with Streami18n (either via constructor or registerTranslation()) or you can provide your own Dayjs or Moment instance\n * to Streami18n constructor, which will be then used internally (using the language locale) in components.\n *\n * 1. Via language registration\n *\n * e.g.,\n * ```\n * const i18n = new Streami18n({\n *  language: 'nl',\n *  dayjsLocaleConfigForLanguage: {\n *    months: [...],\n *    monthsShort: [...],\n *    calendar: {\n *      sameDay: ...'\n *    }\n *  }\n * });\n * ```\n *\n * Similarly, you can add locale config for moment while registering translation via `registerTranslation` function.\n *\n * e.g.,\n * ```\n * const i18n = new Streami18n();\n *\n * i18n.registerTranslation(\n *  'mr',\n *  {\n *    'Nothing yet...': 'काहीही नाही  ...',\n *    '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} आणि {{ secondUser }} टीपी करत आहेत ',\n *  },\n *  {\n *    months: [...],\n *    monthsShort: [...],\n *    calendar: {\n *      sameDay: ...'\n *    }\n *  }\n * );\n *```\n * 2. Provide your own Moment object\n *\n * ```js\n * import 'moment/locale/nl';\n * import 'moment/locale/it';\n * // or if you want to include all locales\n * import 'moment/min/locales';\n *\n * import Moment from moment\n *\n * const i18n = new Streami18n({\n *  language: 'nl',\n *  DateTimeParser: Moment\n * })\n * ```\n *\n * 3. Provide your own Dayjs object\n *\n * ```js\n * import Dayjs from 'dayjs'\n *\n * import 'dayjs/locale/nl';\n * import 'dayjs/locale/it';\n * // or if you want to include all locales\n * import 'dayjs/min/locales';\n *\n * const i18n = new Streami18n({\n *  language: 'nl',\n *  DateTimeParser: Dayjs\n * })\n * ```\n * If you would like to stick with english language for datetimes in Stream components, you can set `disableDateTimeTranslations` to true.\n *\n */\nconst defaultStreami18nOptions = {\n  DateTimeParser: Dayjs,\n  dayjsLocaleConfigForLanguage: null,\n  debug: false,\n  disableDateTimeTranslations: false,\n  language: 'en' as TranslationLanguages,\n  logger: (message?: string) => console.warn(message),\n  /**\n   * Key in the translationBuilderTopics has to match postProcessorName in the translation value.\n   *\n   * {\n   *   \"key\": \"{{value, postProcessorName}}\"\n   * }\n   *\n   * At least the default topics will be supported.\n   */\n  translationBuilderTopics: {\n    notification: NotificationTranslationTopic,\n  },\n};\n\nexport class Streami18n {\n  i18nInstance: I18n = i18n.createInstance();\n  translationBuilder: TranslationBuilder;\n  private translationBuilderTopics: Record<string, TranslationTopicConstructor> = {};\n  Dayjs = null;\n  setLanguageCallback: (t: TFunction) => void = () => null;\n  initialized = false;\n\n  t: TFunction = defaultTranslatorFunction;\n  tDateTimeParser: TDateTimeParser;\n\n  translations: {\n    [key: string]: {\n      [key: string]: typeof enTranslations | UnknownType;\n    };\n  } = {\n    de: { [defaultNS]: deTranslations },\n    en: { [defaultNS]: enTranslations },\n    es: { [defaultNS]: esTranslations },\n    fr: { [defaultNS]: frTranslations },\n    hi: { [defaultNS]: hiTranslations },\n    it: { [defaultNS]: itTranslations },\n    ja: { [defaultNS]: jaTranslations },\n    ko: { [defaultNS]: koTranslations },\n    nl: { [defaultNS]: nlTranslations },\n    pt: { [defaultNS]: ptTranslations },\n    ru: { [defaultNS]: ruTranslations },\n    tr: { [defaultNS]: trTranslations },\n  };\n\n  /**\n   * dayjs.defineLanguage('nl') also changes the global locale. We don't want to do that\n   * when user calls registerTranslation() function. So instead we will store the locale configs\n   * given to registerTranslation() function in `dayjsLocales` object, and register the required locale\n   * with moment, when setLanguage is called.\n   * */\n  dayjsLocales: { [key: string]: Partial<ILocale> } = {};\n  // dayjsLocales = {};\n\n  /**\n   * Initialize properties used in constructor\n   */\n  logger: (msg?: string) => void;\n  currentLanguage: TranslationLanguages;\n  DateTimeParser: DateTimeParserModule;\n  formatters: PredefinedFormatters & CustomFormatters = predefinedFormatters;\n  isCustomDateTimeParser: boolean;\n  i18nextConfig: {\n    debug: boolean;\n    fallbackLng: false;\n    interpolation: { escapeValue: boolean; formatSeparator: string };\n    keySeparator: false;\n    lng: string;\n    nsSeparator: false;\n    parseMissingKeyHandler?: (key: string, defaultValue?: string) => string;\n    postProcess?: string[];\n  };\n  /**\n   * A valid TZ identifier string (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)\n   */\n  timezone?: string;\n  /**\n   * Constructor accepts following options:\n   *  - language (String) default: 'en'\n   *    Language code e.g., en, tr\n   *\n   *  - translationsForLanguage (object)\n   *    Translations object. Please check src/i18n/en.json for example.\n   *\n   *  - disableDateTimeTranslations (boolean) default: false\n   *    Disable translations for date-times\n   *\n   *  - debug (boolean) default: false\n   *    Enable debug mode in internal i18n class\n   *\n   *  - logger (function) default: () => {}\n   *    Logger function to log warnings/errors from this class\n   *\n   *  - dayjsLocaleConfigForLanguage (object) default: 'enConfig'\n   *    [Config object](https://momentjs.com/docs/#/i18n/changing-locale/) for internal moment object,\n   *    corresponding to language (param)\n   *\n   *  - DateTimeParser (function) Moment or Dayjs instance/function.\n   *    Make sure to load all the required locales in this Moment or Dayjs instance that you will be provide to Streami18n\n   *\n   * @param {*} options\n   */\n  constructor(options: Streami18nOptions = {}) {\n    const finalOptions = {\n      ...defaultStreami18nOptions,\n      ...options,\n    };\n    // Prepare the i18next configuration.\n    this.logger = finalOptions.logger;\n    this.currentLanguage = finalOptions.language;\n    this.DateTimeParser = finalOptions.DateTimeParser;\n    this.timezone = finalOptions.timezone;\n    this.formatters = { ...predefinedFormatters, ...options?.formatters };\n    this.translationBuilder = new TranslationBuilder(this.i18nInstance);\n    this.translationBuilderTopics = {\n      ...defaultStreami18nOptions.translationBuilderTopics,\n      ...options.translationBuilderTopics,\n    };\n\n    try {\n      if (this.DateTimeParser && isDayJs(this.DateTimeParser)) {\n        this.DateTimeParser.extend(LocalizedFormat);\n        this.DateTimeParser.extend(calendar);\n        this.DateTimeParser.extend(localeData);\n        this.DateTimeParser.extend(relativeTime);\n        this.DateTimeParser.extend(duration);\n      }\n    } catch (error) {\n      throw Error(\n        `Streami18n: Looks like you wanted to provide Dayjs instance, but something went wrong while adding plugins ${error}`,\n      );\n    }\n\n    this.isCustomDateTimeParser = !!options.DateTimeParser;\n    const translationsForLanguage = finalOptions.translationsForLanguage;\n\n    if (translationsForLanguage) {\n      this.translations[this.currentLanguage] = {\n        [defaultNS]:\n          this.translations[this.currentLanguage] &&\n          this.translations[this.currentLanguage][defaultNS]\n            ? {\n                ...this.translations[this.currentLanguage][defaultNS],\n                ...translationsForLanguage,\n              }\n            : translationsForLanguage,\n      };\n    }\n\n    // If translations don't exist for given language, then set it as empty object.\n    if (!this.translations[this.currentLanguage]) {\n      this.translations[this.currentLanguage] = {\n        [defaultNS]: {},\n      };\n    }\n\n    this.i18nextConfig = {\n      debug: finalOptions.debug,\n      fallbackLng: false,\n      interpolation: { escapeValue: false, formatSeparator: '|' },\n      keySeparator: false,\n      lng: this.currentLanguage,\n      nsSeparator: false,\n    };\n\n    const postProcess = Object.keys(this.translationBuilderTopics);\n\n    if (postProcess.length > 0) {\n      this.i18nextConfig.postProcess = postProcess;\n    }\n\n    if (finalOptions.parseMissingKeyHandler) {\n      this.i18nextConfig.parseMissingKeyHandler = finalOptions.parseMissingKeyHandler;\n    }\n\n    this.validateCurrentLanguage();\n\n    const dayjsLocaleConfigForLanguage = finalOptions.dayjsLocaleConfigForLanguage;\n\n    if (dayjsLocaleConfigForLanguage) {\n      this.addOrUpdateLocale(this.currentLanguage, {\n        ...dayjsLocaleConfigForLanguage,\n      });\n    } else if (!this.localeExists(this.currentLanguage)) {\n      this.logger(\n        `Streami18n: Streami18n(...) - Locale config for ${this.currentLanguage} does not exist in momentjs.` +\n          `Please import the locale file using \"import 'moment/locale/${this.currentLanguage}';\" in your app or ` +\n          `register the locale config with Streami18n using registerTranslation(language, translation, customDayjsLocale)`,\n      );\n    }\n\n    this.tDateTimeParser = (timestamp) => {\n      const language =\n        finalOptions.disableDateTimeTranslations ||\n        !this.localeExists(this.currentLanguage)\n          ? defaultLng\n          : this.currentLanguage;\n\n      if (isDayJs(this.DateTimeParser)) {\n        return supportsTz(this.DateTimeParser)\n          ? this.DateTimeParser(timestamp).tz(this.timezone).locale(language)\n          : this.DateTimeParser(timestamp).locale(language);\n      }\n\n      if (supportsTz(this.DateTimeParser) && this.timezone) {\n        return this.DateTimeParser(timestamp).tz(this.timezone).locale(language);\n      }\n      return this.DateTimeParser(timestamp).locale(language);\n    };\n  }\n\n  /**\n   * Initializes the i18next instance with configuration (which enables natural language as default keys)\n   */\n  async init() {\n    this.validateCurrentLanguage();\n\n    try {\n      this.t = await this.i18nInstance.init({\n        ...this.i18nextConfig,\n        lng: this.currentLanguage,\n        resources: this.translations,\n      });\n      this.initialized = true;\n      if (this.formatters) {\n        Object.entries(this.formatters).forEach(([name, formatterFactory]) => {\n          if (!formatterFactory) return;\n          this.i18nInstance.services.formatter?.add(name, formatterFactory(this));\n        });\n      }\n      // Register post-processors after initialization\n      Object.entries(this.translationBuilderTopics).forEach(\n        ([topic, TranslationTopic]) => {\n          this.translationBuilder.registerTopic(topic, TranslationTopic);\n        },\n      );\n    } catch (error) {\n      this.logger(`Something went wrong with init: ${JSON.stringify(error)}`);\n    }\n\n    return {\n      t: this.t,\n      tDateTimeParser: this.tDateTimeParser,\n    };\n  }\n\n  localeExists = (language: TranslationLanguages) => {\n    if (this.isCustomDateTimeParser) return true;\n\n    return Object.keys(Dayjs.Ls).indexOf(language) > -1;\n  };\n\n  validateCurrentLanguage = () => {\n    const availableLanguages = Object.keys(this.translations);\n    if (availableLanguages.indexOf(this.currentLanguage) === -1) {\n      this.logger(\n        `Streami18n: '${this.currentLanguage}' language is not registered.` +\n          ` Please make sure to call streami18n.registerTranslation('${this.currentLanguage}', {...}) or ` +\n          `use one the built-in supported languages - ${this.getAvailableLanguages()}`,\n      );\n\n      this.currentLanguage = defaultLng;\n    }\n  };\n\n  /** Returns an instance of i18next used within this class instance */\n  geti18Instance = (): I18n => this.i18nInstance;\n\n  /** Returns list of available languages. */\n  getAvailableLanguages = () => Object.keys(this.translations);\n\n  /** Returns all the translation dictionary for all inbuilt-languages */\n  getTranslations = () => this.translations;\n\n  /**\n   * Returns current version translator function.\n   */\n  async getTranslators() {\n    if (!this.initialized) {\n      if (this.dayjsLocales[this.currentLanguage]) {\n        this.addOrUpdateLocale(\n          this.currentLanguage,\n          this.dayjsLocales[this.currentLanguage],\n        );\n      }\n\n      return await this.init();\n    } else {\n      return {\n        t: this.t,\n        tDateTimeParser: this.tDateTimeParser,\n      };\n    }\n  }\n\n  registerTranslation(\n    language: TranslationLanguages,\n    translation: typeof enTranslations,\n    customDayjsLocale?: Partial<ILocale>,\n  ) {\n    if (!translation) {\n      this.logger(\n        `Streami18n: registerTranslation(language, translation, customDayjsLocale) called without translation`,\n      );\n      return;\n    }\n\n    if (!this.translations[language]) {\n      this.translations[language] = { [defaultNS]: translation };\n    } else {\n      this.translations[language][defaultNS] = translation;\n    }\n\n    if (customDayjsLocale) {\n      this.dayjsLocales[language] = { ...customDayjsLocale };\n    } else if (!this.localeExists(language)) {\n      this.logger(\n        `Streami18n: registerTranslation(language, translation, customDayjsLocale) - ` +\n          `Locale config for ${language} does not exist in Dayjs.` +\n          `Please import the locale file using \"import 'dayjs/locale/${language}';\" in your app or ` +\n          `register the locale config with Streami18n using registerTranslation(language, translation, customDayjsLocale)`,\n      );\n    }\n\n    if (this.initialized) {\n      this.i18nInstance.addResources(language, defaultNS, translation);\n    }\n  }\n\n  addOrUpdateLocale(key: TranslationLanguages, config: Partial<ILocale>) {\n    if (this.localeExists(key)) {\n      Dayjs.updateLocale(key, { ...config });\n    } else {\n      // Merging the custom locale config with en config, so missing keys can default to english.\n      Dayjs.locale({ name: key, ...en_locale, ...config }, undefined, true);\n    }\n  }\n\n  async setLanguage(language: TranslationLanguages) {\n    this.currentLanguage = language;\n\n    if (!this.initialized) return;\n\n    try {\n      const t = await this.i18nInstance.changeLanguage(language);\n      if (this.dayjsLocales[language]) {\n        this.addOrUpdateLocale(\n          this.currentLanguage,\n          this.dayjsLocales[this.currentLanguage],\n        );\n      }\n\n      this.setLanguageCallback(t);\n      return t;\n    } catch (error) {\n      this.logger(`Failed to set language: ${JSON.stringify(error)}`);\n      return this.t;\n    }\n  }\n\n  registerSetLanguageCallback(callback: (t: TFunction) => void) {\n    this.setLanguageCallback = callback;\n  }\n}\n","import React from 'react';\n\nconst LoadingItems = () => (\n  <div className='str-chat__channel-list-item-container'>\n    <div\n      aria-hidden='true'\n      className='str-chat__channel-list-item str-chat__channel-list-item--loading'\n    >\n      <div className='str-chat__loading-channels-avatar' />\n      <div className='str-chat__channel-list-item-data str-chat__channel-list-item-data--loading'>\n        <div className='str-chat__loading-channels-username' />\n        <div className='str-chat__loading-channels-status' />\n      </div>\n    </div>\n  </div>\n);\n\nexport const LoadingChannels = () => (\n  <div className='str-chat__loading-channels'>\n    <LoadingItems />\n    <LoadingItems />\n    <LoadingItems />\n    <LoadingItems />\n    <LoadingItems />\n  </div>\n);\n","import React, { type ComponentProps } from 'react';\nimport { IconLoading } from '../Icons';\n\nexport type LoadingIndicatorProps = ComponentProps<typeof IconLoading>;\n\nexport const LoadingIndicator = (props: LoadingIndicatorProps) => (\n  <IconLoading {...props} className='str-chat__loading-indicator' />\n);\n","import React from 'react';\n\nimport { useTranslationContext } from '../../context/TranslationContext';\n\nexport type ProgressIndicatorProps = {\n  /** Clamped 0–100 completion. */\n  percent: number;\n};\n\nconst RING_RADIUS = 12;\nconst RING_CIRCUMFERENCE = 2 * Math.PI * RING_RADIUS;\n\n/** Circular progress indicator with input from 0 to 100. */\nexport const CircularProgressIndicator = ({ percent }: ProgressIndicatorProps) => {\n  const { t } = useTranslationContext('CircularProgressIndicator');\n  const dashOffset = RING_CIRCUMFERENCE * (1 - percent / 100);\n\n  return (\n    <div className='str-chat__circular-progress-indicator str-chat__progress-indicator'>\n      <svg\n        aria-label={t('aria/Percent complete', { percent })}\n        aria-valuemax={100}\n        aria-valuemin={0}\n        aria-valuenow={percent}\n        data-testid='circular-progress-ring'\n        height='100%'\n        role='progressbar'\n        viewBox='0 0 32 32'\n        width='100%'\n        xmlns='http://www.w3.org/2000/svg'\n      >\n        <circle\n          cx='16'\n          cy='16'\n          fill='none'\n          r={RING_RADIUS}\n          stroke='currentColor'\n          strokeOpacity={0.35}\n          strokeWidth='2.5'\n        />\n        <circle\n          cx='16'\n          cy='16'\n          fill='none'\n          r={RING_RADIUS}\n          stroke='currentColor'\n          strokeDasharray={RING_CIRCUMFERENCE}\n          strokeDashoffset={dashOffset}\n          strokeLinecap='round'\n          strokeWidth='2.5'\n          transform='rotate(-90 16 16)'\n        />\n      </svg>\n    </div>\n  );\n};\n","import React from 'react';\n\nimport { useComponentContext } from '../../context';\nimport { CircularProgressIndicator as DefaultProgressIndicator } from './progress-indicators';\nimport { LoadingIndicator as DefaultLoadingIndicator } from './LoadingIndicator';\n\nexport type UploadProgressIndicatorProps = {\n  uploadProgress?: number;\n};\n\nexport const UploadProgressIndicator = ({\n  uploadProgress,\n}: UploadProgressIndicatorProps) => {\n  const {\n    LoadingIndicator = DefaultLoadingIndicator,\n    ProgressIndicator = DefaultProgressIndicator,\n  } = useComponentContext();\n\n  if (uploadProgress === undefined) {\n    return <LoadingIndicator data-testid='loading-indicator' />;\n  }\n\n  return <ProgressIndicator percent={uploadProgress} />;\n};\n","export function prettifyFileSize(bytes: number, precision = 3) {\n  const units = ['B', 'kB', 'MB', 'GB'];\n  const exponent =\n    bytes === 0\n      ? 0\n      : Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);\n  const mantissa = bytes / 1024 ** exponent;\n  const formattedMantissa =\n    precision === 0 ? Math.round(mantissa).toString() : mantissa.toPrecision(precision);\n  return `${formattedMantissa} ${units[exponent]}`;\n}\n","import React from 'react';\nimport { prettifyFileSize } from '../../MessageComposer/hooks/utils';\n\nexport type FileSizeIndicatorProps = {\n  /** file size in byte */\n  fileSize?: number | string;\n  /**\n   The maximum number of fraction digits to display. If not set, the default behavior is to round to 3 significant digits.\n   @default undefined\n   */\n  maximumFractionDigits?: number;\n};\n\nexport const FileSizeIndicator = ({\n  fileSize,\n  maximumFractionDigits,\n}: FileSizeIndicatorProps) => {\n  const actualFileSize = typeof fileSize === 'string' ? parseFloat(fileSize) : fileSize;\n\n  if (typeof actualFileSize === 'undefined' || !Number.isFinite(Number(actualFileSize))) {\n    return null;\n  }\n\n  return (\n    <span\n      className='str-chat__message-attachment-file--item-size'\n      data-testid='file-size-indicator'\n    >\n      {prettifyFileSize(actualFileSize, maximumFractionDigits)}\n    </span>\n  );\n};\n","import React from 'react';\n\nimport { useComponentContext } from '../../context';\nimport { FileSizeIndicator as DefaultFileSizeIndicator } from '../Attachment/components/FileSizeIndicator';\n\nexport type UploadedSizeIndicatorProps = {\n  fullBytes: number;\n  uploadedBytes: number;\n};\n\nexport const UploadedSizeIndicator = ({\n  fullBytes,\n  uploadedBytes,\n}: UploadedSizeIndicatorProps) => {\n  const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();\n  return (\n    <div\n      className='str-chat__attachment-preview-file__upload-size-fraction'\n      data-testid='upload-size-fraction'\n    >\n      <FileSizeIndicator fileSize={uploadedBytes} /> {` / `}\n      <FileSizeIndicator fileSize={fullBytes} />\n    </div>\n  );\n};\n","import { useCallback, useRef } from 'react';\n\nexport type StableCallback<A extends unknown[], R> = (...args: A) => R;\n\n/**\n * A utility hook implementing a stable callback. It takes in an unstable method that\n * is supposed to be invoked somewhere deeper in the DOM tree without making it\n * change its reference every time the parent component rerenders. It will also return\n * the value of the callback if it does return one.\n * A common use-case would be having a function whose invocation depends on state\n * somewhere high up in the DOM tree and wanting to use the same function deeper\n * down, for example in a leaf node and simply using useCallback results in\n * cascading dependency hell. If we wrap it in useStableCallback, we would be able\n * to:\n * - Use the same function as a dependency of another hook (since it is stable)\n * - Still invoke it and get the latest state\n *\n * **Caveats:**\n * - Never wrap a function that is supposed to return a React.ReactElement in\n *   useStableCallback, since React will not know that the DOM needs to be updated\n *   whenever the callback value changes (for example, renderItem from FlatList must\n *   never be wrapped in this hook)\n * - Always prefer using a standard useCallback/stable function wherever possible\n *   (the purpose of useStableCallback is to bridge the gap between top level contexts\n *   and cascading rereders in downstream components - **not** as an escape hatch)\n * @param callback - the callback we want to stabilize\n */\nexport const useStableCallback = <A extends unknown[], R>(\n  callback: StableCallback<A, R>,\n): StableCallback<A, R> => {\n  const ref = useRef(callback);\n  ref.current = callback;\n\n  return useCallback<StableCallback<A, R>>((...args) => ref.current(...args), []);\n};\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\n\nimport type React from 'react';\nimport type { LocalMessage } from 'stream-chat';\nimport { useStableCallback } from '../../../utils/useStableCallback';\n\nexport type FormData = Record<string, string>;\n\nexport type ActionHandlerReturnType = (\n  dataOrName?: string | FormData,\n  value?: string,\n  event?: React.BaseSyntheticEvent,\n) => Promise<void> | void;\n\nexport const handleActionWarning = `Action handler was called, but it is missing one of its required arguments. \nMake sure the ChannelAction and ChannelState contexts are properly set and the hook is initialized with a valid message.`;\n\nexport function useActionHandler(message?: LocalMessage): ActionHandlerReturnType {\n  const { removeMessage, updateMessage } = useChannelActionContext('useActionHandler');\n  const { channel } = useChannelStateContext('useActionHandler');\n\n  return useStableCallback(async (dataOrName, value, event) => {\n    if (event) event.preventDefault();\n\n    if (!message || !updateMessage || !removeMessage || !channel) {\n      console.warn(handleActionWarning);\n      return;\n    }\n\n    const messageId = message.id;\n    let formData: FormData = {};\n\n    // deprecated: value&name should be removed in favor of data obj\n    if (typeof dataOrName === 'string') {\n      formData[dataOrName] = value as string;\n    } else {\n      formData = { ...dataOrName };\n    }\n\n    if (messageId) {\n      const data = await channel.sendAction(messageId, formData);\n\n      if (data?.message) {\n        updateMessage(data.message);\n      } else {\n        removeMessage(message);\n      }\n    }\n  });\n}\n","import { isNetworkSendFailure } from '../utils';\n\nimport { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChatContext } from '../../../context/ChatContext';\n\nimport type { DeleteMessageOptions, LocalMessage } from 'stream-chat';\nimport type { MessageContextValue } from '../../../context';\n\nexport const useDeleteHandler = (\n  message?: LocalMessage,\n): MessageContextValue['handleDelete'] => {\n  const { deleteMessage, removeMessage, updateMessage } =\n    useChannelActionContext('useDeleteHandler');\n  const { client } = useChatContext('useDeleteHandler');\n\n  return async (options?: DeleteMessageOptions) => {\n    if (!message) {\n      return;\n    }\n\n    if (message.type === 'error' || isNetworkSendFailure(message)) {\n      removeMessage?.(message);\n      return;\n    }\n\n    if (!message.id || !client || !updateMessage) {\n      return;\n    }\n\n    const deletedMessage = await deleteMessage(message, options);\n    updateMessage(deletedMessage);\n  };\n};\n","import { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const missingUseFlagHandlerParameterWarning =\n  'useFlagHandler was called but it is missing one or more necessary parameters.';\n\nexport const useFlagHandler = (message?: LocalMessage): ReactEventHandler => {\n  const { client } = useChatContext('useFlagHandler');\n  const { t } = useTranslationContext('useFlagHandler');\n\n  return async (event) => {\n    event.preventDefault();\n\n    if (!client || !t || !message?.id) {\n      console.warn(missingUseFlagHandlerParameterWarning);\n      return;\n    }\n\n    await client.flagMessage(message.id);\n  };\n};\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\n\nimport type React from 'react';\nimport type { LocalMessage, UserResponse } from 'stream-chat';\n\nimport type { ReactEventHandler } from '../types';\n\nexport type CustomMentionHandler = (\n  event: React.BaseSyntheticEvent,\n  mentioned_users: UserResponse[],\n) => void;\n\nexport type MentionedUserEventHandler = (\n  event: React.BaseSyntheticEvent,\n  mentionedUsers: UserResponse[],\n) => void;\n\nfunction createEventHandler(\n  fn?: CustomMentionHandler,\n  message?: LocalMessage,\n): ReactEventHandler {\n  return (event) => {\n    if (typeof fn !== 'function' || !message?.mentioned_users?.length) {\n      return;\n    }\n    fn(event, message.mentioned_users);\n  };\n}\n\nexport const useMentionsHandler = (\n  message?: LocalMessage,\n  customMentionHandler?: {\n    onMentionsClick?: CustomMentionHandler;\n    onMentionsHover?: CustomMentionHandler;\n  },\n) => {\n  const {\n    onMentionsClick: contextOnMentionsClick,\n    onMentionsHover: contextOnMentionsHover,\n  } = useChannelActionContext('useMentionsHandler');\n\n  const onMentionsClick =\n    customMentionHandler?.onMentionsClick || contextOnMentionsClick || (() => null);\n\n  const onMentionsHover =\n    customMentionHandler?.onMentionsHover || contextOnMentionsHover || (() => null);\n\n  return {\n    onMentionsClick: createEventHandler(onMentionsClick, message),\n    onMentionsHover: createEventHandler(onMentionsHover, message),\n  };\n};\n","import { useChannelStateContext } from '../../../context';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const useMarkUnreadHandler = (message?: LocalMessage): ReactEventHandler => {\n  const { channel } = useChannelStateContext('useMarkUnreadHandler');\n\n  return async (event) => {\n    event.preventDefault();\n    if (!message?.id) {\n      console.warn('Mark unread handler does not have access to message id');\n      return;\n    }\n\n    await channel.markUnread({ message_id: message.id });\n  };\n};\n","import { isUserMuted } from '../utils';\n\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\nimport type { LocalMessage } from 'stream-chat';\n\nimport type { ReactEventHandler } from '../types';\n\nexport const missingUseMuteHandlerParamsWarning =\n  'useMuteHandler was called but it is missing one or more necessary parameter.';\n\nexport const useMuteHandler = (message?: LocalMessage): ReactEventHandler => {\n  const { mutes } = useChannelStateContext('useMuteHandler');\n  const { client } = useChatContext('useMuteHandler');\n  const { t } = useTranslationContext('useMuteHandler');\n\n  return async (event) => {\n    event.preventDefault();\n\n    if (!t || !message?.user || !client) {\n      console.warn(missingUseMuteHandlerParamsWarning);\n      return;\n    }\n\n    if (!isUserMuted(message, mutes)) {\n      await client.muteUser(message.user.id);\n    } else {\n      await client.unmuteUser(message.user.id);\n    }\n  };\n};\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const useOpenThreadHandler = (\n  message?: LocalMessage,\n  customOpenThread?: (message: LocalMessage, event: React.BaseSyntheticEvent) => void,\n): ReactEventHandler => {\n  const { openThread: channelOpenThread } =\n    useChannelActionContext('useOpenThreadHandler');\n\n  const openThread = customOpenThread || channelOpenThread;\n\n  return (event) => {\n    if (!openThread || !message) {\n      console.warn(\n        'Open thread handler was called but it is missing one of its parameters',\n      );\n      return;\n    }\n\n    openThread(message, event);\n  };\n};\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const usePinHandler = (message: LocalMessage) => {\n  const { updateMessage } = useChannelActionContext('usePinHandler');\n  const { channelCapabilities = {} } = useChannelStateContext('usePinHandler');\n  const { client } = useChatContext('usePinHandler');\n\n  const canPin = !!channelCapabilities['pin-message'];\n\n  const handlePin: ReactEventHandler = async (event) => {\n    event.preventDefault();\n\n    if (!message) return;\n\n    if (!message.pinned) {\n      try {\n        const optimisticMessage: LocalMessage = {\n          ...message,\n          pinned: true,\n          pinned_at: new Date(),\n          pinned_by: client.user,\n        };\n\n        updateMessage(optimisticMessage);\n\n        await client.pinMessage(message);\n      } catch (e) {\n        updateMessage(message);\n      }\n    } else {\n      try {\n        const optimisticMessage = {\n          ...message,\n          pin_expires: null,\n          pinned: false,\n          pinned_at: null,\n          pinned_by: null,\n        };\n\n        updateMessage(optimisticMessage);\n\n        await client.unpinMessage(message);\n      } catch (e) {\n        updateMessage(message);\n      }\n    }\n  };\n\n  return { canPin, handlePin };\n};\n","/* eslint-disable sort-keys */\n\nimport React from 'react';\n\ntype LegacyReactionOptions = Array<{\n  Component: React.ComponentType;\n  type: string;\n  name?: string;\n}>;\n\ntype ReactionOptionData = {\n  Component: React.ComponentType;\n  name?: string;\n  unicode?: string;\n};\n\nexport type ReactionOptions =\n  | LegacyReactionOptions\n  | {\n      quick: {\n        [key: string]: ReactionOptionData;\n      };\n      extended?: {\n        [key: string]: ReactionOptionData;\n      };\n    };\n\nexport const mapEmojiMartData = (\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  emojiMartData: any,\n): NonNullable<Exclude<ReactionOptions, LegacyReactionOptions>['extended']> => {\n  if (!emojiMartData || !emojiMartData.emojis) {\n    return {};\n  }\n\n  const newMap: ReturnType<typeof mapEmojiMartData> = {};\n\n  for (const emojiId in emojiMartData.emojis) {\n    const emojiData = emojiMartData.emojis[emojiId];\n    const [firstEmoji] = emojiData.skins;\n\n    if (!firstEmoji || !firstEmoji.native) continue;\n\n    const nativeEmoji = firstEmoji.native as string;\n\n    const unicode = emojiToUnicode(nativeEmoji);\n\n    newMap[unicode] = {\n      Component: () => <>{nativeEmoji}</>,\n      name: emojiData.name,\n      unicode,\n    };\n  }\n\n  return newMap;\n};\n\nexport type AdvancedReactionOptions = {\n  quick: ReactionOptions;\n  extended: ReactionOptions;\n};\n\nexport const emojiToUnicode = (emoji: string) => {\n  const unicodeStrings = [];\n  for (const c of emoji) {\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    const codePoint = c.codePointAt(0)!;\n    unicodeStrings.push(`U+${codePoint.toString(16).toUpperCase().padStart(4, '0')}`);\n  }\n\n  return unicodeStrings.join('-');\n};\n\nexport const unicodeToEmoji = (unicode: string) =>\n  unicode\n    .split('-')\n    .map((code) => String.fromCodePoint(parseInt(code.replace('U+', ''), 16)))\n    .join('');\n\nexport const defaultReactionOptions: ReactionOptions = {\n  quick: {\n    haha: {\n      Component: () => <>😂</>,\n      name: 'Joy',\n      unicode: emojiToUnicode('😂'),\n    },\n    like: {\n      Component: () => <>👍</>,\n      name: 'Thumbs up',\n      unicode: emojiToUnicode('👍'),\n    },\n    love: {\n      Component: () => <>❤️</>,\n      name: 'Heart',\n      unicode: emojiToUnicode('❤️'),\n    },\n    sad: { Component: () => <>😔</>, name: 'Sad', unicode: emojiToUnicode('😔') },\n    wow: {\n      Component: () => <>😮</>,\n      name: 'Astonished',\n      unicode: emojiToUnicode('😮'),\n    },\n    fire: {\n      Component: () => <>🔥</>,\n      name: 'Fire',\n      unicode: emojiToUnicode('🔥'),\n    },\n  },\n};\n\nexport const getHasExtendedReactions = (reactionOptions: ReactionOptions) =>\n  !Array.isArray(reactionOptions) &&\n  typeof reactionOptions.extended !== 'undefined' &&\n  Object.keys(reactionOptions.extended).length > 0;\n\n/**\n * Resolves the native emoji character (e.g. \"👍\") for a given reaction type from\n * the configured reaction options. The value is used as the `emoji_code` sent\n * with a reaction so that push notifications can render the emoji.\n *\n * Returns `undefined` when no `unicode` is available for the type (e.g. legacy\n * array reaction options or custom options that omit `unicode`).\n */\nexport const getEmojiCodeByReactionType = (\n  reactionOptions: ReactionOptions,\n  reactionType: string,\n): string | undefined => {\n  // Legacy array reaction options carry no unicode data.\n  if (Array.isArray(reactionOptions)) return undefined;\n\n  const unicode =\n    reactionOptions.quick[reactionType]?.unicode ??\n    reactionOptions.extended?.[reactionType]?.unicode;\n\n  return unicode ? unicodeToEmoji(unicode) : undefined;\n};\n","import type React from 'react';\nimport { useCallback } from 'react';\nimport throttle from 'lodash.throttle';\n\nimport { useThreadContext } from '../../Threads';\nimport { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useComponentContext } from '../../../context/ComponentContext';\nimport {\n  defaultReactionOptions,\n  getEmojiCodeByReactionType,\n} from '../../Reactions/reactionOptions';\n\nimport type { LocalMessage, Reaction, ReactionResponse } from 'stream-chat';\n\nexport const reactionHandlerWarning = `Reaction handler was called, but it is missing one of its required arguments.\nMake sure the ChannelAction and ChannelState contexts are properly set and the hook is initialized with a valid message.`;\n\nexport const useReactionHandler = (message?: LocalMessage) => {\n  const thread = useThreadContext();\n  const { updateMessage } = useChannelActionContext('useReactionHandler');\n  const { channel, channelCapabilities } = useChannelStateContext('useReactionHandler');\n  const { client } = useChatContext('useReactionHandler');\n  const { reactionOptions = defaultReactionOptions } =\n    useComponentContext('useReactionHandler');\n\n  const createMessagePreview = useCallback(\n    (add: boolean, reaction: ReactionResponse, message: LocalMessage): LocalMessage => {\n      const newReactionGroups = message?.reaction_groups || {};\n      const reactionType = reaction.type;\n      const hasReaction = !!newReactionGroups[reactionType];\n\n      if (add) {\n        const timestamp = new Date().toISOString();\n        newReactionGroups[reactionType] = hasReaction\n          ? {\n              ...newReactionGroups[reactionType],\n              count: newReactionGroups[reactionType].count + 1,\n            }\n          : {\n              count: 1,\n              first_reaction_at: timestamp,\n              last_reaction_at: timestamp,\n              sum_scores: 1,\n            };\n      } else {\n        if (hasReaction && newReactionGroups[reactionType].count > 1) {\n          newReactionGroups[reactionType] = {\n            ...newReactionGroups[reactionType],\n            count: newReactionGroups[reactionType].count - 1,\n          };\n        } else {\n          delete newReactionGroups[reactionType];\n        }\n      }\n\n      const newReactions: ReactionResponse[] | undefined = add\n        ? [reaction, ...(message?.latest_reactions || [])]\n        : message.latest_reactions?.filter(\n            (item) => !(item.type === reaction.type && item.user_id === reaction.user_id),\n          );\n\n      const newOwnReactions = add\n        ? [reaction, ...(message?.own_reactions || [])]\n        : message?.own_reactions?.filter((item) => item.type !== reaction.type);\n\n      return {\n        ...message,\n        latest_reactions: newReactions || message.latest_reactions,\n        own_reactions: newOwnReactions,\n        reaction_groups: newReactionGroups,\n      };\n    },\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [client.user, client.userID],\n  );\n\n  const createReactionPreview = (type: string, emojiCode?: string) => ({\n    message_id: message?.id,\n    score: 1,\n    type,\n    user: client.user,\n    user_id: client.user?.id,\n    ...(emojiCode && { emoji_code: emojiCode }),\n  });\n\n  const toggleReaction = throttle(async (id: string, type: string, add: boolean) => {\n    if (!message || !channelCapabilities['send-reaction']) return;\n\n    // Native emoji (e.g. \"👍\") for this reaction type, sent as `emoji_code` so\n    // push notifications in mobile SDKs can render the emoji.\n    const emojiCode = getEmojiCodeByReactionType(reactionOptions, type);\n    const newReaction = createReactionPreview(type, emojiCode) as ReactionResponse;\n    const tempMessage = createMessagePreview(add, newReaction, message);\n\n    try {\n      updateMessage(tempMessage);\n      thread?.upsertReplyLocally({ message: tempMessage });\n\n      const messageResponse = add\n        ? await channel.sendReaction(id, {\n            type,\n            ...(emojiCode && { emoji_code: emojiCode }),\n          } as Reaction)\n        : await channel.deleteReaction(id, type);\n\n      // seems useless as we're expecting WS event to come in and replace this anyway\n      updateMessage(messageResponse.message);\n    } catch (error) {\n      // revert to the original message if the API call fails\n      updateMessage(message);\n      thread?.upsertReplyLocally({ message });\n    }\n  }, 1000);\n\n  return async (reactionType: string, event?: React.BaseSyntheticEvent) => {\n    if (event?.preventDefault) {\n      event.preventDefault();\n    }\n\n    if (!message) {\n      return console.warn(reactionHandlerWarning);\n    }\n\n    let userExistingReaction = null as unknown as ReactionResponse;\n\n    if (message.own_reactions) {\n      message.own_reactions.forEach((reaction) => {\n        // own user should only ever contain the current user id\n        // just in case we check to prevent bugs with message updates from breaking reactions\n        if (\n          reaction.user &&\n          client.userID === reaction.user.id &&\n          reaction.type === reactionType\n        ) {\n          userExistingReaction = reaction;\n        } else if (reaction.user && client.userID !== reaction.user.id) {\n          console.warn(\n            `message.own_reactions contained reactions from a different user, this indicates a bug`,\n          );\n        }\n      });\n    }\n\n    try {\n      if (userExistingReaction) {\n        await toggleReaction(message.id, userExistingReaction.type, false);\n      } else {\n        await toggleReaction(message.id, reactionType, true);\n      }\n    } catch (error) {\n      console.log({ error });\n    }\n  };\n};\n","import type { RetrySendMessage } from '../../../context/ChannelActionContext';\nimport { useChannelActionContext } from '../../../context/ChannelActionContext';\n\nexport const useRetryHandler = (\n  customRetrySendMessage?: RetrySendMessage,\n): RetrySendMessage => {\n  const { retrySendMessage: contextRetrySendMessage } =\n    useChannelActionContext('useRetryHandler');\n\n  const retrySendMessage = customRetrySendMessage || contextRetrySendMessage;\n\n  return async (message) => {\n    if (message) {\n      await retrySendMessage(message);\n    }\n  };\n};\n","import type { User } from 'stream-chat';\n\nimport type { ReactEventHandler } from '../types';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UserEventHandler = (event: React.BaseSyntheticEvent, user: User) => void;\n\nexport const useUserHandler = (\n  message?: LocalMessage,\n  eventHandlers?: {\n    onUserClickHandler?: UserEventHandler;\n    onUserHoverHandler?: UserEventHandler;\n  },\n): {\n  onUserClick: ReactEventHandler;\n  onUserHover: ReactEventHandler;\n} => ({\n  onUserClick: (event) => {\n    if (typeof eventHandlers?.onUserClickHandler !== 'function' || !message?.user) {\n      return;\n    }\n    eventHandlers.onUserClickHandler(event, message.user);\n  },\n  onUserHover: (event) => {\n    if (typeof eventHandlers?.onUserHoverHandler !== 'function' || !message?.user) {\n      return;\n    }\n\n    eventHandlers.onUserHoverHandler(event, message.user);\n  },\n});\n","import { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\nimport type { LocalMessage } from 'stream-chat';\n\nexport const useUserRole = (message: LocalMessage, disableQuotedMessages?: boolean) => {\n  const { channel, channelCapabilities = {} } = useChannelStateContext('useUserRole');\n  const { client } = useChatContext('useUserRole');\n\n  /**\n   * @deprecated as it relies on `membership.role` check which is already deprecated and shouldn't be used anymore.\n   * `isAdmin` will be removed in future release. See `channelCapabilities`.\n   */\n  const isAdmin =\n    client.user?.role === 'admin' || channel.state.membership.role === 'admin';\n\n  /**\n   * @deprecated as it relies on `membership.role` check which is already deprecated and shouldn't be used anymore.\n   * `isOwner` will be removed in future release. See `channelCapabilities`.\n   */\n  const isOwner = channel.state.membership.role === 'owner';\n\n  /**\n   * @deprecated as it relies on `membership.role` check which is already deprecated and shouldn't be used anymore.\n   * `isModerator` will be removed in future release. See `channelCapabilities`.\n   */\n  const isModerator =\n    client.user?.role === 'channel_moderator' ||\n    channel.state.membership.role === 'channel_moderator' ||\n    channel.state.membership.role === 'moderator' ||\n    channel.state.membership.is_moderator === true ||\n    channel.state.membership.channel_role === 'channel_moderator';\n\n  const isMyMessage = client.userID === message.user?.id;\n\n  const canEdit =\n    !message.poll &&\n    message.command !== 'giphy' &&\n    (channelCapabilities['update-any-message'] ||\n      (isMyMessage && channelCapabilities['update-own-message']));\n\n  const canDelete =\n    channelCapabilities['delete-any-message'] ||\n    (isMyMessage && channelCapabilities['delete-own-message']);\n\n  const canFlag = !isMyMessage && channelCapabilities['flag-message'];\n  const canMute = !isMyMessage && channelCapabilities['mute-channel'];\n  const canBlockUser = !isMyMessage;\n  const canMarkUnread = !isMyMessage && channelCapabilities['read-events'];\n  const canQuote = !disableQuotedMessages && channelCapabilities['quote-message'];\n  const canReact = channelCapabilities['send-reaction'];\n  const canReply = channelCapabilities['send-reply'];\n  const canSendMessage = channelCapabilities['send-message'];\n\n  return {\n    canBlockUser,\n    canDelete,\n    canEdit,\n    canFlag,\n    canMarkUnread,\n    canMute,\n    canQuote,\n    canReact,\n    canReply,\n    canSendMessage,\n    isAdmin,\n    isModerator,\n    isMyMessage,\n    isOwner,\n  };\n};\n","import { useChatContext } from '../../../context';\nimport { useStableCallback } from '../../../utils/useStableCallback';\nimport type {\n  LocalMessage,\n  ReactionResponse,\n  ReactionSort,\n  StreamChat,\n} from 'stream-chat';\nimport type { ReactionType } from '../../Reactions/types';\n\nexport const MAX_MESSAGE_REACTIONS_TO_FETCH = 1000;\n\nexport function useReactionsFetcher(message: LocalMessage) {\n  const { client } = useChatContext('useRectionsFetcher');\n\n  return useStableCallback((reactionType?: ReactionType, sort?: ReactionSort) =>\n    fetchMessageReactions(client, message.id, reactionType, sort),\n  );\n}\n\nasync function fetchMessageReactions(\n  client: StreamChat,\n  messageId: string,\n  reactionType?: ReactionType,\n  sort?: ReactionSort,\n) {\n  const reactions: ReactionResponse[] = [];\n  const limit = 25;\n  let next: string | undefined;\n  let hasNext = true;\n\n  while (hasNext && reactions.length < MAX_MESSAGE_REACTIONS_TO_FETCH) {\n    const response = await client.queryReactions(\n      messageId,\n      reactionType ? { type: reactionType } : {},\n      sort,\n      { limit, next },\n    );\n\n    reactions.push(...response.reactions);\n    next = response.next;\n    hasNext = Boolean(next);\n  }\n\n  return reactions;\n}\n","import { useEffect, useRef, useState } from 'react';\n\nimport { useStableCallback } from '../../../utils/useStableCallback';\nimport type { StreamedMessageTextProps } from '../StreamedMessageText';\n\nexport type UseMessageTextStreamingProps = Pick<\n  StreamedMessageTextProps,\n  'streamingLetterIntervalMs' | 'renderingLetterCount'\n> & { text: string };\n\nconst DEFAULT_LETTER_INTERVAL = 30;\nconst DEFAULT_RENDERING_LETTER_COUNT = 2;\n\n/**\n * A hook that returns text in a streamed, typewriter fashion. The speed of streaming is\n * configurable.\n * @param {number} [streamingLetterIntervalMs=30] - The timeout between each typing animation in milliseconds.\n * @param {number} [renderingLetterCount=2] - The number of letters to be rendered each time we update.\n * @param {string} text - The text that we want to render in a typewriter fashion.\n * @returns {{ streamedMessageText: string }} - A substring of the text property, up until we've finished rendering the typewriter animation.\n */\nexport const useMessageTextStreaming = ({\n  renderingLetterCount = DEFAULT_RENDERING_LETTER_COUNT,\n  streamingLetterIntervalMs = DEFAULT_LETTER_INTERVAL,\n  text,\n}: UseMessageTextStreamingProps) => {\n  const [streamedMessageText, setStreamedMessageText] = useState<string>(text);\n  const textCursor = useRef<number>(text.length);\n\n  useEffect(() => {\n    const textLength = text.length;\n\n    const interval = setInterval(() => {\n      if (!text || textCursor.current >= textLength) {\n        clearInterval(interval);\n        return;\n      }\n      const newCursorValue = textCursor.current + renderingLetterCount;\n      const newText = text.substring(0, newCursorValue);\n      textCursor.current += newText.length - textCursor.current;\n      setStreamedMessageText(newText);\n    }, streamingLetterIntervalMs);\n\n    return () => {\n      clearInterval(interval);\n    };\n  }, [streamingLetterIntervalMs, renderingLetterCount, text]);\n\n  const skipAnimation = useStableCallback(() => {\n    textCursor.current = text.length;\n    setStreamedMessageText(text);\n  });\n\n  return { skipAnimation, streamedMessageText } as const;\n};\n","import { useCallback } from 'react';\nimport { useChatContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport type { ReminderManagerState } from 'stream-chat';\n\nexport const useMessageReminder = (messageId: string) => {\n  const { client } = useChatContext();\n  const reminderSelector = useCallback(\n    (state: ReminderManagerState) => ({\n      reminder: state.reminders.get(messageId),\n    }),\n    [messageId],\n  );\n  const { reminder } = useStateStore(client.reminders.state, reminderSelector);\n  return reminder;\n};\n","import { useMemo } from 'react';\nimport { useAriaIdentifiers } from './useAriaIdentifiers';\n\nexport type ResolvedModalAriaProps = {\n  'aria-describedby'?: string;\n  'aria-label'?: string;\n  'aria-labelledby'?: string;\n};\n\ntype UseResolvedModalAriaPropsParams = {\n  ariaDescribedby?: string;\n  ariaLabel?: string;\n  ariaLabelledby?: string;\n  dialogId?: string;\n};\n\n/**\n * Resolves modal labeling/description attributes from explicit props first,\n * then from the modal dialog id convention (`${dialogId}-title|description`).\n *\n * Rules:\n * - `aria-labelledby` wins over `aria-label`.\n * - `aria-describedby` defaults to inferred id when explicit value is absent.\n */\nexport const useResolvedModalAriaProps = ({\n  ariaDescribedby,\n  ariaLabel,\n  ariaLabelledby,\n  dialogId,\n}: UseResolvedModalAriaPropsParams): ResolvedModalAriaProps => {\n  const { descriptionId, titleId } = useAriaIdentifiers(dialogId);\n\n  return useMemo(() => {\n    const resolvedAriaLabelledby = ariaLabel\n      ? ariaLabelledby\n      : (ariaLabelledby ?? titleId);\n    const resolvedAriaDescribedby = ariaDescribedby ?? descriptionId;\n    const resolvedAriaLabel = resolvedAriaLabelledby ? undefined : ariaLabel;\n\n    return {\n      'aria-describedby': resolvedAriaDescribedby,\n      'aria-label': resolvedAriaLabel,\n      'aria-labelledby': resolvedAriaLabelledby,\n    };\n  }, [ariaDescribedby, ariaLabel, ariaLabelledby, descriptionId, titleId]);\n};\n","import clsx from 'clsx';\nimport React, {\n  type ComponentProps,\n  type ComponentType,\n  type PropsWithChildren,\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n} from 'react';\nimport { FocusScope } from '@react-aria/focus';\n\nimport { NotificationList as DefaultNotificationList } from '../Notifications';\nimport {\n  ModalContextProvider,\n  modalDialogManagerId,\n  useChatContext,\n  useComponentContext,\n} from '../../context';\nimport {\n  DialogPortalEntry,\n  modalDialogId,\n  useModalDialog,\n  useModalDialogIsOpen,\n  useModalDialogIsTopmost,\n} from '../Dialog';\nimport { useResolvedModalAriaProps } from '../../a11y/hooks/useResolvedModalAriaProps';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nexport type ModalCloseEvent =\n  | KeyboardEvent\n  | React.KeyboardEvent\n  | React.MouseEvent<HTMLButtonElement | HTMLDivElement>;\n\nexport type ModalCloseSource = 'overlay' | 'button' | 'escape';\n\nexport type ModalProps = {\n  /** If true, modal is opened or visible. */\n  open: boolean;\n  /** Custom class to be applied to the modal root div */\n  className?: string;\n  /** Optional stable id for this modal instance. Generated automatically when omitted. */\n  dialogId?: string;\n  /** Accessible label for the modal dialog. Ignored when aria-labelledby is provided. */\n  'aria-label'?: string;\n  /** ID of the element that labels the modal dialog. */\n  'aria-labelledby'?: string;\n  /** ID of the element that describes the modal dialog. */\n  'aria-describedby'?: string;\n  /** ARIA role for the modal dialog surface. */\n  role?: 'alertdialog' | 'dialog';\n  /** If provided, the close button is rendered on overlay */\n  CloseButtonOnOverlay?: ComponentType<ComponentProps<'button'>>;\n  /** Callback handler for closing of modal. */\n  onClose?: (event: ModalCloseEvent) => void;\n  /** Optional handler to intercept closing logic. Return false to prevent onClose. */\n  onCloseAttempt?: (source: ModalCloseSource, event: ModalCloseEvent) => boolean;\n};\n\nexport const GlobalModal = ({\n  'aria-describedby': ariaDescribedby,\n  'aria-label': ariaLabel,\n  'aria-labelledby': ariaLabelledby,\n  children,\n  className,\n  CloseButtonOnOverlay,\n  dialogId,\n  onClose,\n  onCloseAttempt,\n  open,\n  role = 'dialog',\n}: PropsWithChildren<ModalProps>) => {\n  const generatedDialogId = useStableId();\n  const resolvedDialogId = dialogId ?? `${modalDialogId}-${generatedDialogId}`;\n  const dialog = useModalDialog(resolvedDialogId);\n  const isOpen = useModalDialogIsOpen(resolvedDialogId);\n  const isTopmost = useModalDialogIsTopmost(resolvedDialogId);\n  const overlayRef = useRef<HTMLDivElement | null>(null);\n  const closeButtonRef = useRef<HTMLButtonElement | null>(null);\n  const closingRef = useRef(false);\n  const { theme } = useChatContext();\n  const { NotificationList = DefaultNotificationList } = useComponentContext();\n  const dialogLabelingBaseId = dialog.id;\n  const resolvedModalAriaProps = useResolvedModalAriaProps({\n    ariaDescribedby,\n    ariaLabel,\n    ariaLabelledby,\n    dialogId: dialogLabelingBaseId,\n  });\n\n  const maybeClose = useCallback(\n    (source: ModalCloseSource, event: ModalCloseEvent) => {\n      const allow = onCloseAttempt?.(source, event);\n      if (allow !== false) {\n        dialog.close();\n        closingRef.current = true;\n        onClose?.(event);\n      }\n    },\n    [dialog, onClose, onCloseAttempt],\n  );\n\n  const modalContextValue = useMemo<{ close: () => void; dialogId?: string }>(\n    () => ({\n      close: () => maybeClose('button', {} as ModalCloseEvent),\n      dialogId: dialogLabelingBaseId,\n    }),\n    [dialogLabelingBaseId, maybeClose],\n  );\n\n  const handleOverlayClick = (event: React.MouseEvent<HTMLDivElement>) => {\n    if (!isTopmost) return;\n    const target = event.target as HTMLDivElement;\n    if (overlayRef.current === target) {\n      maybeClose('overlay', event);\n    }\n  };\n\n  const handleCloseButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n    if (!isTopmost) return;\n    maybeClose('button', event);\n  };\n\n  const handleDialogKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n    if (event.defaultPrevented || event.key !== 'Escape' || !isTopmost) return;\n    maybeClose('escape', event);\n  };\n\n  // Sync open prop to dialog state.\n  // closingRef blocks re-open when we just closed and parent hasn't set open=false yet.\n  useEffect(() => {\n    if (!open) {\n      closingRef.current = false;\n      if (isOpen) {\n        dialog.close();\n      }\n      return;\n    }\n    if (open && !isOpen && !closingRef.current) {\n      dialog.open();\n    }\n  }, [dialog, isOpen, open]);\n\n  if (!open || !isOpen) return null;\n\n  return (\n    <DialogPortalEntry dialogId={resolvedDialogId} dialogManagerId={modalDialogManagerId}>\n      <ModalContextProvider value={modalContextValue}>\n        <div\n          className={clsx(\n            'str-chat',\n            theme,\n            'str-chat__modal str-chat-react__modal str-chat__modal--open',\n            className,\n          )}\n          onClick={handleOverlayClick}\n          ref={overlayRef}\n        >\n          <FocusScope autoFocus={isTopmost} contain={isTopmost} restoreFocus>\n            <div\n              aria-describedby={resolvedModalAriaProps['aria-describedby']}\n              aria-label={resolvedModalAriaProps['aria-label']}\n              aria-labelledby={resolvedModalAriaProps['aria-labelledby']}\n              aria-modal={isTopmost ? 'true' : undefined}\n              className='str-chat__modal__dialog'\n              inert={isTopmost ? undefined : true}\n              onKeyDown={handleDialogKeyDown}\n              role={role}\n              tabIndex={isTopmost ? 0 : -1}\n            >\n              {children}\n            </div>\n          </FocusScope>\n          <NotificationList\n            className='str-chat__modal__notification-list'\n            panel='modal'\n            verticalAlignment='top'\n          />\n          {CloseButtonOnOverlay && (\n            <CloseButtonOnOverlay onClick={handleCloseButtonClick} ref={closeButtonRef} />\n          )}\n        </div>\n      </ModalContextProvider>\n    </DialogPortalEntry>\n  );\n};\n","import type { ComponentType, PropsWithChildren } from 'react';\nimport React from 'react';\nimport { GlobalModal, type ModalProps } from '../Modal';\nimport { MessageBounceProvider, useComponentContext } from '../../context';\nimport type { MessageBouncePromptProps } from './MessageBouncePrompt';\n\nexport type MessageBounceModalProps = PropsWithChildren<\n  ModalProps & {\n    MessageBouncePrompt: ComponentType<MessageBouncePromptProps>;\n  }\n>;\n\nexport function MessageBounceModal({\n  MessageBouncePrompt,\n  ...modalProps\n}: MessageBounceModalProps) {\n  const { Modal = GlobalModal } = useComponentContext();\n  return (\n    <Modal className='str-chat__message-bounce-modal' {...modalProps}>\n      <MessageBounceProvider>\n        <MessageBouncePrompt />\n      </MessageBounceProvider>\n    </Modal>\n  );\n}\n","import type { MouseEventHandler } from 'react';\nimport React from 'react';\nimport {\n  useMessageBounceContext,\n  useModalContext,\n  useTranslationContext,\n} from '../../context';\nimport { Button } from '../Button';\nimport { IconExclamationMark } from '../Icons';\nimport { Alert } from '../Dialog';\nimport type { PropsWithChildrenOnly } from '../../types/types';\n\nexport type MessageBouncePromptProps = PropsWithChildrenOnly;\n\n// todo: shall we rename this to MessageBounceAlert?\nexport function MessageBouncePrompt({ children }: MessageBouncePromptProps) {\n  const { handleDelete, handleEdit, handleRetry } = useMessageBounceContext();\n  const { t } = useTranslationContext();\n  const { close } = useModalContext();\n\n  function createHandler(\n    handle: MouseEventHandler<HTMLButtonElement>,\n  ): MouseEventHandler<HTMLButtonElement> {\n    return (e) => {\n      handle(e);\n      close();\n    };\n  }\n\n  return (\n    <Alert.Root\n      className='str-chat__message-bounce-alert'\n      data-testid='message-bounce-prompt'\n    >\n      <Alert.Header\n        className='str-chat__message-bounce-alert-header'\n        description={\n          !children\n            ? t(\n                'Review this message and choose whether to delete it, edit it, or send it anyway',\n              )\n            : undefined\n        }\n        Icon={IconExclamationMark}\n        title={\n          !children ? t('This message did not meet our content guidelines') : undefined\n        }\n      >\n        {children}\n      </Alert.Header>\n      <Alert.Actions className={'str-chat__message-bounce-actions'}>\n        <Button\n          appearance='outline'\n          className='str-chat__message-bounce-delete'\n          data-testid='message-bounce-delete'\n          onClick={createHandler(handleDelete)}\n          size='md'\n          variant='danger'\n        >\n          {t('Delete')}\n        </Button>\n        <Button\n          appearance='outline'\n          className='str-chat__message-bounce-edit'\n          data-testid='message-bounce-edit'\n          onClick={createHandler(handleEdit)}\n          size='md'\n          variant='secondary'\n        >\n          {t('Edit Message')}\n        </Button>\n        <Button\n          appearance='outline'\n          className='str-chat__message-bounce-send'\n          data-testid='message-bounce-send'\n          onClick={createHandler(handleRetry)}\n          size='md'\n          variant='secondary'\n        >\n          {t('Send Anyway')}\n        </Button>\n      </Alert.Actions>\n    </Alert.Root>\n  );\n}\n","import React, { type ComponentProps } from 'react';\nimport clsx from 'clsx';\n\nexport const MessageBubble = ({ className, ...props }: ComponentProps<'div'>) => (\n  <div {...props} className={clsx('str-chat__message-bubble', className)} />\n);\n","import React from 'react';\n\nimport { IconNoSign } from '../Icons';\nimport { useTranslationContext } from '../../context/TranslationContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport { MessageBubble } from './MessageBubble';\n\nexport type MessageDeletedProps = {\n  message: LocalMessage;\n};\n\nexport const MessageDeletedBubble = () => {\n  const { t } = useTranslationContext();\n\n  return (\n    <MessageBubble data-testid={'message-deleted-bubble'}>\n      <div className='str-chat__message-text'>\n        <IconNoSign />\n        <span>{t('Message deleted')}</span>\n      </div>\n    </MessageBubble>\n  );\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nimport { useUserRole } from './hooks/useUserRole';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useMessageContext } from '../../context';\n\nexport const MessageBlocked = () => {\n  const { message } = useMessageContext();\n  const { t } = useTranslationContext('MessageBlocked');\n\n  const { isMyMessage } = useUserRole(message);\n\n  const messageClasses = clsx(\n    'str-chat__message str-chat__message--blocked',\n    message.type,\n    {\n      'str-chat__message--me': isMyMessage,\n      'str-chat__message--other': !isMyMessage,\n    },\n  );\n\n  return (\n    <div\n      className={messageClasses}\n      data-testid='message-blocked-component'\n      key={message.id}\n    >\n      <div className='str-chat__message--blocked-inner'>\n        {t('Message was blocked by moderation policies')}\n      </div>\n    </div>\n  );\n};\n","import { useMemo } from 'react';\n\nimport { useChannelStateContext, useMessageContext } from '../../../context';\nimport { useUserRole } from '../../Message/hooks';\nimport {\n  ACTIONS_NOT_WORKING_IN_THREAD,\n  isMessageBounced,\n  isMessageDeleted,\n  isMessageErrorRetryable,\n  isNetworkSendFailure,\n} from '../../Message/utils';\n\nimport type { MessageActionSetItem } from '../MessageActions';\nimport {\n  isAudioAttachment,\n  isFileAttachment,\n  isImageAttachment,\n  isVideoAttachment,\n  isVoiceRecordingAttachment,\n} from 'stream-chat';\n\n/**\n * Base filter hook which covers actions of type `delete`, `edit`,\n * `flag`, `markUnread`, `mute`, `quote`, `react` and `reply`, whether\n * the rendered message is a reply (replies are limited to certain actions) and\n * whether the message has appropriate type and status (including soft-deleted).\n */\nexport const useBaseMessageActionSetFilter = (\n  messageActionSet: MessageActionSetItem[],\n  disable = false,\n) => {\n  const { initialMessage: isInitialMessage, message } = useMessageContext();\n  const { channelConfig } = useChannelStateContext();\n  const messageIsDeleted = isMessageDeleted(message);\n  const {\n    canBlockUser,\n    canDelete,\n    canEdit,\n    canFlag,\n    canMarkUnread,\n    canMute,\n    canQuote,\n    canReact,\n    canReply,\n    canSendMessage,\n  } = useUserRole(message);\n  const isMessageThreadReply = typeof message.parent_id === 'string';\n  const isBounced = isMessageBounced(message);\n  const allowRetry = isMessageErrorRetryable(message);\n  const hasNetworkSendFailure = isNetworkSendFailure(message);\n\n  return useMemo(() => {\n    if (disable) return messageActionSet;\n\n    // filter out all actions if any of these are true\n    if (\n      isBounced ||\n      isInitialMessage || // not sure whether this thing even works anymore\n      !message.type ||\n      message.type === 'system' ||\n      message.type === 'ephemeral' ||\n      message.status === 'sending'\n    )\n      return [];\n\n    return messageActionSet.filter((action) => {\n      if (action.placement === 'quick-dropdown-toggle') return true;\n\n      const type = action.type;\n\n      // filter out actions with types that do not work in thread\n      if (ACTIONS_NOT_WORKING_IN_THREAD.includes(type) && isMessageThreadReply)\n        return false;\n\n      // failed message menu has special treatment\n      if (message.error) {\n        return (\n          (type === 'resendMessage' && canSendMessage && (allowRetry || isBounced)) ||\n          (type === 'edit' && ((isBounced && canEdit) || hasNetworkSendFailure)) ||\n          (type === 'delete' &&\n            !messageIsDeleted &&\n            ((isBounced && canDelete) || hasNetworkSendFailure))\n        );\n      }\n\n      if (\n        type === 'resendMessage' ||\n        (type === 'blockUser' && !canBlockUser) ||\n        (type === 'copyMessageText' && !message.text) ||\n        (type === 'download' &&\n          !message.attachments?.some(\n            (attachment) =>\n              isFileAttachment(attachment) ||\n              isImageAttachment(attachment) ||\n              isVideoAttachment(attachment) ||\n              isAudioAttachment(attachment) ||\n              isVoiceRecordingAttachment(attachment),\n          )) ||\n        (type === 'delete' && (!canDelete || messageIsDeleted)) ||\n        (type === 'edit' && !canEdit) ||\n        (type === 'flag' && !canFlag) ||\n        (type === 'markUnread' && !canMarkUnread) ||\n        (type === 'mute' && !canMute) ||\n        (type === 'quote' && !canQuote) ||\n        (type === 'react' && !canReact) ||\n        (type === 'reply' && !canReply) ||\n        (type === 'remindMe' && !channelConfig?.['user_message_reminders']) ||\n        (type === 'saveForLater' && !channelConfig?.['user_message_reminders'])\n      )\n        return false;\n\n      return true;\n    });\n  }, [\n    allowRetry,\n    canBlockUser,\n    canDelete,\n    canEdit,\n    canFlag,\n    canMarkUnread,\n    canMute,\n    canQuote,\n    canReact,\n    canReply,\n    canSendMessage,\n    channelConfig,\n    isBounced,\n    isInitialMessage,\n    messageIsDeleted,\n    isMessageThreadReply,\n    message.error,\n    message.attachments,\n    message.status,\n    message.text,\n    message.type,\n    disable,\n    hasNetworkSendFailure,\n    messageActionSet,\n  ]);\n};\n","import React, { useEffect, useRef } from 'react';\n\nimport { IconArrowUpRight } from '../Icons';\nimport { useNotificationApi } from '../Notifications';\nimport {\n  useChannelActionContext,\n  useChannelStateContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\nimport { formatMessage, type LocalMessage } from 'stream-chat';\n\n/**\n * Indicator shown when the message was also sent to the main channel (show_in_channel === true).\n */\nexport const MessageAlsoSentInChannelIndicator = () => {\n  const { addNotification } = useNotificationApi();\n  const { t } = useTranslationContext();\n  const { channel } = useChannelStateContext();\n  const { jumpToMessage, openThread } = useChannelActionContext();\n  const { message, threadList } = useMessageContext('MessageAlsoSentInChannelIndicator');\n  const targetMessageRef = useRef<LocalMessage | null | undefined>(undefined);\n\n  const queryParent = () =>\n    channel\n      .getClient()\n      .search({ cid: channel.cid }, { id: message.parent_id })\n      .then(({ results }) => {\n        if (!results.length) {\n          throw new Error('Thread has not been found');\n        }\n        targetMessageRef.current = formatMessage(results[0].message);\n      })\n      .catch((error: Error) => {\n        addNotification({\n          context: { threadReply: message },\n          emitter: 'MessageIsThreadReplyInChannelButtonIndicator',\n          error,\n          message: t('Thread has not been found'),\n          severity: 'error',\n          type: 'api:reply:search:failed',\n        });\n      });\n\n  // todo: it is not possible to jump to a message in thread\n  const jumpToReplyInChannelMessages = async (id: string) => {\n    await jumpToMessage(id);\n    // todo: we do not have API to control, whether thread of channel message list is show - on mobile devices important\n  };\n\n  useEffect(() => {\n    if (\n      targetMessageRef.current ||\n      targetMessageRef.current === null ||\n      !message.parent_id\n    )\n      return;\n    const localMessage = channel.state.findMessage(message.parent_id);\n    if (localMessage) {\n      targetMessageRef.current = localMessage;\n      return;\n    }\n  }, [channel, message]);\n\n  const handleClickViewReference = async () => {\n    if (!targetMessageRef.current) {\n      // search query is performed here in order to prevent multiple search queries in useEffect\n      // due to the message list 3x remounting its items\n      if (threadList) {\n        await jumpToReplyInChannelMessages(message.id); // we are in thread, and we want to jump to this reply in the main message list\n        return;\n      } else await queryParent(); // we are in the main list and need to query the thread\n    }\n    const target = targetMessageRef.current;\n    if (!target) {\n      // prevent further search queries if the message is not found in the DB\n      targetMessageRef.current = null;\n      return;\n    }\n\n    if (threadList) await jumpToReplyInChannelMessages(message.id);\n    else openThread(target);\n  };\n\n  if (!message?.show_in_channel) return null;\n\n  return (\n    <div className='str-chat__message-also-sent-in-channel' role='status'>\n      <IconArrowUpRight />\n      <span>{threadList ? t('Also sent in channel') : t('Replied to a thread')}</span>\n      <span> · </span>\n      <button\n        className='str-chat__message-also-sent-in-channel__link-button'\n        onClick={handleClickViewReference}\n        type='button'\n      >\n        {t('View')}\n      </button>\n    </div>\n  );\n};\n","import type { MouseEventHandler } from 'react';\nimport type { UserResponse } from 'stream-chat';\nimport React, { useMemo } from 'react';\n\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useChannelStateContext, useComponentContext } from '../../context';\nimport { AvatarStack as DefaultAvatarStack } from '../Avatar';\n\nexport type MessageRepliesCountButtonProps = {\n  /* If supplied, adds custom text to the end of a multiple replies message */\n  labelPlural?: string;\n  /* If supplied, adds custom text to the end of a single reply message */\n  labelSingle?: string;\n  /* Function to navigate into an existing thread on a message */\n  onClick?: MouseEventHandler;\n  /* The amount of replies (i.e., threaded messages) on a message */\n  reply_count?: number;\n  thread_participants?: UserResponse[];\n};\n\nfunction UnMemoizedMessageRepliesCountButton(props: MessageRepliesCountButtonProps) {\n  const { AvatarStack = DefaultAvatarStack } = useComponentContext(\n    MessageRepliesCountButton.name,\n  );\n  const {\n    labelPlural,\n    labelSingle,\n    onClick,\n    reply_count: replyCount = 0,\n    thread_participants: threadParticipants = [],\n  } = props;\n  const { channelCapabilities } = useChannelStateContext();\n\n  const { t } = useTranslationContext('MessageRepliesCountButton');\n\n  const avatarStackDisplayInfo = useMemo(\n    () =>\n      threadParticipants.slice(0, 3).map((participant) => ({\n        imageUrl: participant.image,\n        userName: participant.name || participant.id,\n      })),\n    [threadParticipants],\n  );\n\n  if (!replyCount) return null;\n\n  let replyCountText = t('replyCount', { count: replyCount });\n\n  if (labelPlural && replyCount > 1) {\n    replyCountText = `${replyCount} ${labelPlural}`;\n  } else if (labelSingle) {\n    replyCountText = `1 ${labelSingle}`;\n  }\n\n  return (\n    <div className='str-chat__message-replies-count-button-wrapper'>\n      <button\n        className='str-chat__message-replies-count-button'\n        data-testid='replies-count-button'\n        disabled={!channelCapabilities['send-reply']}\n        onClick={onClick}\n      >\n        {replyCountText}\n\n        <AvatarStack displayInfo={avatarStackDisplayInfo} size='xs' />\n      </button>\n    </div>\n  );\n}\n\nexport const MessageRepliesCountButton = React.memo(\n  UnMemoizedMessageRepliesCountButton,\n) as typeof UnMemoizedMessageRepliesCountButton;\n","import React from 'react';\n\nimport { IconPin } from '../Icons';\nimport { useChatContext, useTranslationContext } from '../../context';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type PinIndicatorProps = {\n  message?: LocalMessage;\n};\n\n/**\n * Default pinned message indicator. Renders \"Pinned by [name]\" with pin icon above the message bubble.\n * Name is taken from message.pinned_by (who pinned).\n */\nexport const PinIndicator = ({ message }: PinIndicatorProps) => {\n  const { t } = useTranslationContext();\n  const { client } = useChatContext();\n\n  if (!message) return null;\n\n  const isOwnPin = !!message.pinned_by?.id && message.pinned_by.id === client.user?.id;\n  const name = message.pinned_by?.name ?? message.pinned_by?.id ?? '';\n\n  const label = isOwnPin\n    ? t('Pinned by You')\n    : name\n      ? t('Pinned by {{ name }}', { name })\n      : t('Message pinned');\n\n  return (\n    <div className='str-chat__message-pin-indicator'>\n      <div className='str-chat__message-pin-indicator__content'>\n        <span aria-hidden className='str-chat__message-pin-indicator__icon'>\n          <IconPin />\n        </span>\n        <span>{label}</span>\n      </div>\n    </div>\n  );\n};\n","import type { ComponentProps } from 'react';\nimport React, { useEffect, useState } from 'react';\nimport type { PopperLikePlacement } from '../Dialog';\nimport { usePopoverPosition } from '../Dialog/hooks/usePopoverPosition';\nimport clsx from 'clsx';\n\nexport const Tooltip = ({ children, className, ...rest }: ComponentProps<'div'>) => (\n  <div className={clsx('str-chat__tooltip', className)} {...rest}>\n    {children}\n  </div>\n);\n\nexport type PopperTooltipProps<T extends HTMLElement> = React.PropsWithChildren<{\n  /** Reference element to which the tooltip should attach to */\n  referenceElement: T | null;\n  /** Custom class to be merged along the defaults */\n  className?: string;\n  /** Popper's modifier (offset) property - [xAxis offset, yAxis offset], default [0, 10] */\n  offset?: [number, number];\n  /** Popper's placement property defining default position of the tooltip, default 'top' */\n  placement?: PopperLikePlacement;\n  /** Tells component whether to render its contents */\n  visible?: boolean;\n}>;\n\nexport const PopperTooltip = <T extends HTMLElement>({\n  children,\n  className,\n  offset = [0, 10],\n  placement = 'top',\n  referenceElement,\n  visible = false,\n}: PopperTooltipProps<T>) => {\n  const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);\n  const {\n    placement: resolvedPlacement,\n    refs,\n    strategy,\n    x,\n    y,\n  } = usePopoverPosition({\n    offset,\n    placement,\n  });\n\n  useEffect(() => {\n    refs.setReference(referenceElement);\n  }, [referenceElement, refs]);\n\n  useEffect(() => {\n    refs.setFloating(popperElement);\n  }, [popperElement, refs]);\n\n  if (!visible) return null;\n\n  return (\n    <div\n      className={clsx('str-chat__tooltip', className)}\n      data-placement={resolvedPlacement}\n      ref={setPopperElement}\n      style={{ left: x ?? 0, position: strategy, top: y ?? 0 }}\n    >\n      {children}\n    </div>\n  );\n};\n","import type React from 'react';\nimport { useCallback, useState } from 'react';\n\nexport const useEnterLeaveHandlers = <T extends HTMLElement>({\n  onMouseEnter,\n  onMouseLeave,\n}: Partial<Record<'onMouseEnter' | 'onMouseLeave', React.MouseEventHandler<T>>> = {}) => {\n  const [tooltipVisible, setTooltipVisible] = useState(false);\n\n  const handleEnter: React.MouseEventHandler<T> = useCallback(\n    (e) => {\n      setTooltipVisible(true);\n      onMouseEnter?.(e);\n    },\n    [onMouseEnter],\n  );\n\n  const handleLeave: React.MouseEventHandler<T> = useCallback(\n    (e) => {\n      setTooltipVisible(false);\n      onMouseLeave?.(e);\n    },\n    [onMouseLeave],\n  );\n\n  return { handleEnter, handleLeave, tooltipVisible };\n};\n","import React, { useState } from 'react';\nimport clsx from 'clsx';\nimport type { TooltipUsernameMapper } from './utils';\nimport { getReadByTooltipText, mapToUserNameOrId } from './utils';\nimport { PopperTooltip } from '../Tooltip';\nimport { useEnterLeaveHandlers } from '../Tooltip/hooks';\n\nimport { useChatContext } from '../../context/ChatContext';\nimport { useMessageContext } from '../../context/MessageContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { IconCheckmark1Small, IconChecks, IconClock } from '../Icons';\n\nexport type MessageStatusProps = {\n  /* Custom component to render when message is considered delivered, not read. The default UI renders MessageDeliveredIcon and a tooltip with string 'Delivered'. */\n  MessageDeliveredStatus?: React.ComponentType;\n  /* Custom component to render when message is considered delivered and read. The default UI renders the last reader's Avatar and a tooltip with string readers' names. */\n  MessageReadStatus?: React.ComponentType;\n  /* Custom component to render when message is considered as being the in the process of delivery. The default UI renders a clock icon and a tooltip with string 'Sending...'. */\n  MessageSendingStatus?: React.ComponentType;\n  /* Custom component to render when message is considered created on the server, but not delivered. The default UI renders MessageSentIcon and a tooltip with string 'Sent'. */\n  MessageSentStatus?: React.ComponentType;\n  /* Message type string to be added to CSS class names. */\n  messageType?: string;\n  /* Allows to customize the username(s) that appear on the message status tooltip */\n  tooltipUserNameMapper?: TooltipUsernameMapper;\n};\n\nconst UnMemoizedMessageStatus = (props: MessageStatusProps) => {\n  const {\n    MessageDeliveredStatus,\n    MessageReadStatus,\n    MessageSendingStatus,\n    MessageSentStatus,\n    messageType = 'simple',\n    tooltipUserNameMapper = mapToUserNameOrId,\n  } = props;\n\n  const { handleEnter, handleLeave, tooltipVisible } =\n    useEnterLeaveHandlers<HTMLSpanElement>();\n\n  const { client } = useChatContext('MessageStatus');\n  const {\n    deliveredTo,\n    isMyMessage,\n    lastOwnMessage,\n    message,\n    readBy,\n    returnAllReadData,\n    threadList,\n  } = useMessageContext('MessageStatus');\n  const { t } = useTranslationContext('MessageStatus');\n  const [referenceElement, setReferenceElement] = useState<HTMLSpanElement | null>(null);\n\n  if (!isMyMessage() || message.type === 'error') return null;\n\n  const justReadByMe = readBy?.length === 1 && readBy[0].id === client.user?.id;\n  const deliveredOnlyToMe =\n    deliveredTo?.length === 1 && deliveredTo[0].id === client.user?.id;\n  const sending = message.status === 'sending';\n  const read = !!(readBy?.length && !justReadByMe && !threadList);\n  const delivered = !!(deliveredTo?.length && !deliveredOnlyToMe && !read && !threadList);\n  const sent =\n    (returnAllReadData || lastOwnMessage?.id === message.id) &&\n    message.status === 'received' &&\n    !delivered &&\n    !read &&\n    !threadList;\n\n  const readersWithoutOwnUser = read\n    ? readBy.filter((item) => item.id !== client.user?.id)\n    : [];\n\n  return (\n    <span\n      className={clsx(\n        `str-chat__message-${messageType}-status str-chat__message-status`,\n        {\n          'str-chat__message-status-delivered': delivered,\n          'str-chat__message-status-read-by': read,\n          'str-chat__message-status-sending': sending,\n          'str-chat__message-status-sent': sent,\n        },\n      )}\n      data-testid={clsx({\n        'message-status-delivered': delivered,\n        'message-status-read-by': read,\n        'message-status-sending': sending,\n        'message-status-sent': sent,\n      })}\n      onMouseEnter={handleEnter}\n      onMouseLeave={handleLeave}\n      ref={setReferenceElement}\n    >\n      {sending &&\n        (MessageSendingStatus ? (\n          <MessageSendingStatus />\n        ) : (\n          <>\n            <PopperTooltip\n              offset={[0, 5]}\n              referenceElement={referenceElement}\n              visible={tooltipVisible}\n            >\n              {t('Sending...')}\n            </PopperTooltip>\n            <IconClock className='str-chat__message-status-sending' />\n          </>\n        ))}\n\n      {sent &&\n        (MessageSentStatus ? (\n          <MessageSentStatus />\n        ) : (\n          <>\n            <PopperTooltip\n              offset={[0, 5]}\n              referenceElement={referenceElement}\n              visible={tooltipVisible}\n            >\n              {t('Sent')}\n            </PopperTooltip>\n            <IconCheckmark1Small className='str-chat__message-status-sent' />\n          </>\n        ))}\n\n      {delivered &&\n        (MessageDeliveredStatus ? (\n          <MessageDeliveredStatus />\n        ) : (\n          <>\n            <PopperTooltip\n              offset={[0, 5]}\n              referenceElement={referenceElement}\n              visible={tooltipVisible}\n            >\n              {t('Delivered')}\n            </PopperTooltip>\n            <IconChecks className='str-chat__message-status-delivered' />\n          </>\n        ))}\n\n      {read &&\n        (MessageReadStatus ? (\n          <MessageReadStatus />\n        ) : (\n          <>\n            <PopperTooltip\n              offset={[0, 5]}\n              referenceElement={referenceElement}\n              visible={tooltipVisible}\n            >\n              {getReadByTooltipText(readBy, t, client, tooltipUserNameMapper)}\n            </PopperTooltip>\n\n            <IconChecks className='str-chat__message-status-read' />\n\n            {readersWithoutOwnUser.length > 1 && (\n              <span\n                className={`str-chat__message-${messageType}-status-number`}\n                data-testid='message-status-read-by-many'\n              >\n                {readersWithoutOwnUser.length}\n              </span>\n            )}\n          </>\n        ))}\n    </span>\n  );\n};\n\nexport const MessageStatus = React.memo(\n  UnMemoizedMessageStatus,\n) as typeof UnMemoizedMessageStatus;\n","export function escapeRegExp(text: string) {\n  return text.replace(/[-[\\]{}()*+?.,/\\\\^$|#]/g, '\\\\$&');\n}\n\nexport const detectHttp = /(http(s?):\\/\\/)?(www\\.)?/;\n\n// Regexes are hoisted to module scope so they are compiled once rather than on\n// every call. `codeRegex`/`regexMdLinks` are only used with `String#match`\n// (which resets `lastIndex`) and `singleMatch` is non-global (`.exec` ignores\n// `lastIndex`), so sharing the instances is safe.\nconst codeRegex = /```[a-z]*\\n[\\s\\S]*?\\n```|`[a-z]*[\\s\\S]*?`/gm;\nconst regexMdLinks = /\\[([^[]+)\\](\\(.*\\))/gm;\nconst singleMatch = /\\[([^[]+)\\]\\((.*)\\)/;\n\nexport const messageCodeBlocks = (message: string) => {\n  const matches = message.match(codeRegex);\n  return matches || [];\n};\n\nexport const matchMarkdownLinks = (message: string) => {\n  const matches = message.match(regexMdLinks);\n\n  const links = matches\n    ? matches.map((match) => {\n        const i = singleMatch.exec(match);\n        return i && [i[1], i[2]];\n      })\n    : [];\n\n  return links.flat();\n};\n","import type { ReplaceFunction } from 'hast-util-find-and-replace';\nimport { findAndReplace } from 'hast-util-find-and-replace';\nimport { u } from 'unist-builder';\nimport type { Nodes } from 'hast';\n\nimport { EMOJI_REGEX } from '../../emojiRegex';\n\nexport const emojiMarkdownPlugin = () => {\n  const replace: ReplaceFunction = (match) =>\n    u('element', { properties: {}, tagName: 'emoji' }, [u('text', match)]);\n\n  const transform = (node: Nodes) => findAndReplace(node, [EMOJI_REGEX, replace]);\n\n  return transform;\n};\n","import { escapeRegExp } from '../regex';\nimport type { ReplaceFunction } from 'hast-util-find-and-replace';\nimport { findAndReplace } from 'hast-util-find-and-replace';\nimport { u } from 'unist-builder';\nimport { visit } from 'unist-util-visit';\n\nimport type { Element, Nodes } from 'hast';\nimport type { UserResponse } from 'stream-chat';\n\nexport const mentionsMarkdownPlugin = (mentioned_users: UserResponse[]) => () => {\n  const mentioned_usernames = mentioned_users\n    .map((user) => user.name || user.id)\n    .filter(Boolean)\n    .map(escapeRegExp);\n\n  const mentionedUsersRegex = new RegExp(\n    mentioned_usernames.map((username) => `@${username}`).join('|'),\n    'g',\n  );\n\n  const replace: ReplaceFunction = (match) => {\n    const usernameOrId = match.replace('@', '');\n    const user = mentioned_users.find(\n      ({ id, name }) => name === usernameOrId || id === usernameOrId,\n    );\n    return u('element', { mentionedUser: user, properties: {}, tagName: 'mention' }, [\n      u('text', match),\n    ]);\n  };\n\n  const transform = (tree: Nodes) => {\n    if (!mentioned_usernames.length) return;\n\n    // handles special cases of mentions where user.name is an e-mail\n    // Remark GFM translates all e-mail-like text nodes to links creating\n    // two separate child nodes \"@\" and \"your.name@as.email\" instead of\n    // keeping it as one text node with value \"@your.name@as.email\"\n    // this piece finds these two separated nodes and merges them together\n    // before \"replace\" function takes over\n    visit(tree, (node, index, parent) => {\n      if (typeof index === 'undefined') return;\n      if (!parent) return;\n\n      const nextChild = parent.children.at(index + 1) as Element;\n      const nextChildHref = nextChild?.properties?.href as string | undefined;\n\n      if (\n        node.type === 'text' &&\n        // text value has to have @ sign at the end of the string\n        // and no other characters except whitespace can precede it\n        // valid cases:   \"text @\", \"@\", \" @\"\n        // invalid cases: \"text@\", \"@text\",\n        /.?\\s?@$|^@$/.test(node.value) &&\n        nextChildHref?.startsWith('mailto:')\n      ) {\n        const newTextValue = node.value.replace(/@$/, '');\n        const username = nextChildHref.replace('mailto:', '');\n        parent.children[index] = u('text', newTextValue);\n        parent.children[index + 1] = u('text', `@${username}`);\n      }\n    });\n\n    findAndReplace(tree, [mentionedUsersRegex, replace]);\n  };\n\n  return transform;\n};\n","import type { Visitor } from 'unist-util-visit';\nimport { visit } from 'unist-util-visit';\n\n// `Nodes` is not part of hast-util-find-and-replace's public surface; derive\n// the visit-compatible tree type from `visit` itself.\ntype Nodes = Parameters<typeof visit>[0];\n\nconst visitor: Visitor = (node) => {\n  if (node.type !== 'html') return;\n\n  node.type = 'text';\n};\nconst transform = (tree: Nodes) => {\n  visit(tree, visitor);\n};\n\nexport const htmlToTextPlugin = () => transform;\n","import { SKIP, visit, type VisitorResult } from 'unist-util-visit';\nimport type { Image, Link, Parent, Text } from 'mdast';\nimport type { Node } from 'unist';\n\ntype ImgVisitor = (\n  node: Image,\n  index: number | null,\n  parent: Parent | null,\n) => VisitorResult;\n\nexport type ImageToLinkPluginOptions = {\n  getTextLabelFrom?: 'alt' | 'title' | 'url';\n};\n\nconst text = (value: string): Text => ({ type: 'text', value });\n\n/**\n * Converts image Markdown links (![Minion](https://octodex.github.com/images/minion.png))\n * to HTML <a href={url}>{url | title | alt}</a>\n *\n * By default, the anchor text content is the image url so that image preview can be generated / enriched on the server.\n * @param getTextLabelFrom\n */\nexport function imageToLink({ getTextLabelFrom = 'url' }: ImageToLinkPluginOptions = {}) {\n  return (tree: Node) => {\n    const visitor: ImgVisitor = (node, index, parent) => {\n      if (parent == null || index == null) return;\n\n      const label = node[getTextLabelFrom] ?? node.url; // node.alt || node.title || node.url;\n      const link: Link = {\n        children: [text(label)],\n        title: node.title ?? node.alt ?? node.url,\n        type: 'link',\n        url: node.url,\n      };\n\n      parent.children.splice(index, 1, link);\n      return [SKIP, index + 1] as const;\n    };\n\n    visit(tree, 'image', visitor);\n  };\n}\n","import type { Plugin } from 'unified';\nimport { visit } from 'unist-util-visit';\nimport type { Node, Parent as UnistParent } from 'unist';\nimport type { Root, RootContent, ThematicBreak } from 'mdast';\n\n/** Type guard: does the node have mdast children? */\nfunction isParentWithChildren(\n  node: Node,\n): node is UnistParent & { children: RootContent[] } {\n  const maybe = node as unknown as { children?: unknown };\n  return Array.isArray(maybe.children);\n}\n\n/** Build a single <br> by mapping a standard mdast node via data.hName */\nfunction brNode(): ThematicBreak {\n  return { data: { hName: 'br' }, type: 'thematicBreak' };\n}\n\n/**\n * Inserts runs of <br> between sibling block nodes to preserve the exact\n * number of *blank source lines* between them. No paragraph wrappers are added.\n *\n * Works because `mdast-util-to-hast` respects `data.hName`, turning our\n * `thematicBreak` into `<br>`. Multiple blank lines -> multiple `<br>` siblings.\n */\nexport const keepLineBreaksPlugin: Plugin<[], Root> = () => (tree) => {\n  visit(\n    tree as unknown as UnistParent, // visit needs a Unist parent-like root\n    isParentWithChildren, // limit to parents with children\n    (parent) => {\n      const children = parent.children as RootContent[];\n      if (children.length < 2) return;\n\n      const out: RootContent[] = [];\n\n      for (let i = 0; i < children.length; i++) {\n        const curr = children[i];\n        out.push(curr);\n\n        if (i === children.length - 1) break;\n\n        const next = children[i + 1];\n\n        const currEndLine =\n          curr.position && curr.position.end ? curr.position.end.line : undefined;\n        const nextStartLine =\n          next.position && next.position.start ? next.position.start.line : undefined;\n\n        if (typeof currEndLine !== 'number' || typeof nextStartLine !== 'number') {\n          continue;\n        }\n\n        // Markdown already separates blocks by at least one visual gap.\n        // We add back only the *extra* blank lines from the source.\n        const extraBlankLines = Math.max(0, nextStartLine - currEndLine - 1);\n        if (extraBlankLines > 0) {\n          for (let k = 0; k < extraBlankLines; k++) {\n            out.push(brNode());\n          }\n        }\n      }\n\n      parent.children = out;\n    },\n  );\n};\n","// remark-plusplus-ins.ts\nimport type { Plugin } from 'unified';\nimport { SKIP, visit } from 'unist-util-visit';\nimport type { Visitor } from 'unist-util-visit';\nimport type { Parent, PhrasingContent, Text } from 'mdast';\n\n/**\n * \\S → first char must be non-whitespace\n * (?:...)?→ optional middle+closing when length > 1\n * [\\s\\S]*?→ anything (including newlines), lazy\n * final \\S→ last char non-whitespace (only required when there’s more than 1)\n *\n * Matches:\n * ++a++\n * Does not match:\n * ++++\n * ++ ++\n */\nconst INS_REGEX = /\\+\\+(\\S(?:[\\s\\S]*?\\S)?)\\+\\+/g;\nconst IGNORE_NODE_TYPES = new Set([\n  'code',\n  'inlineCode',\n  'link',\n  'linkReference',\n  'definition',\n  'math',\n  'inlineMath',\n]);\n\n/**\n * Converts MD \"++Some text++\" to inserted text element rendered in HTML as <ins>Some text</ins>\n * https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/ins\n */\nexport const plusPlusToEmphasis: Plugin<[]> = () => {\n  const visitor: Visitor = (node, index, parent) => {\n    // 1) Don’t traverse inside ignored nodes\n    if (IGNORE_NODE_TYPES.has(node.type)) return SKIP;\n\n    // 2) Only transform text nodes with a valid parent + index\n    if (node.type !== 'text' || parent == null || typeof index !== 'number') return;\n\n    const value = (node as Text).value;\n\n    // Reset lastIndex to 0 per node so each node is scanned from the beginning\n    INS_REGEX.lastIndex = 0;\n\n    let match: RegExpExecArray | null;\n    let last = 0;\n    const out: PhrasingContent[] = [];\n\n    while ((match = INS_REGEX.exec(value))) {\n      const [full, inner] = match;\n      const start = match.index;\n\n      if (start > last) out.push({ type: 'text', value: value.slice(last, start) });\n\n      // Render as <ins>…</ins> (remark-rehype respects data.hName)\n      out.push({\n        children: [{ type: 'text', value: inner }],\n        data: { hName: 'ins' },\n        type: 'emphasis',\n      });\n\n      last = start + full.length;\n    }\n\n    if (out.length === 0) return; // nothing to change\n    if (last < value.length) out.push({ type: 'text', value: value.slice(last) });\n\n    (parent as Parent).children.splice(index, 1, ...out);\n\n    // Skip re-visiting the replaced range; continue after inserted nodes\n    return [SKIP, index + out.length];\n  };\n\n  return (tree) => visit(tree, visitor);\n};\n","import type { Plugin } from 'unified';\nimport type { Paragraph, Root, Text } from 'mdast';\n\n/**\n * Replace the parsed Markdown tree with a single paragraph containing the\n * original source as a plain text node. No Markdown formatting is interpreted.\n * React will escape it.\n */\nexport const remarkIgnoreMarkdown: Plugin<[], Root> = () => (tree, file) => {\n  const source = String(file.value ?? '');\n\n  const text: Text = { type: 'text', value: source };\n  const paragraph: Paragraph = { children: [text], type: 'paragraph' };\n\n  tree.children = [paragraph];\n};\n","import clsx from 'clsx';\nimport type { ComponentProps } from 'react';\nimport React from 'react';\n\nexport const Anchor = ({ children, href }: ComponentProps<'a'>) => {\n  const isEmail = href?.startsWith('mailto:');\n  const isUrl = href?.startsWith('http');\n\n  if (!href || (!isEmail && !isUrl)) return <>{children}</>;\n\n  return (\n    <a\n      className={clsx({ 'str-chat__message-url-link': isUrl })}\n      href={href}\n      rel='nofollow noreferrer noopener'\n      target='_blank'\n    >\n      {children}\n    </a>\n  );\n};\n","import React from 'react';\nimport type { PropsWithChildrenOnly } from '../../../../types/types';\n\nexport const Emoji = ({ children }: PropsWithChildrenOnly) => (\n  <span className='inline-text-emoji' data-testid='inline-text-emoji'>\n    {children}\n  </span>\n);\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\n\nimport type { UserResponse } from 'stream-chat';\n\nexport type MentionProps = PropsWithChildren<{\n  node: {\n    mentionedUser: UserResponse;\n  };\n}>;\n\nexport const Mention = ({ children, node: { mentionedUser } }: MentionProps) => (\n  <span className='str-chat__message-mention' data-user-id={mentionedUser.id}>\n    {children}\n  </span>\n);\n","export const NullComponent = () => null;\n","import { Component } from 'react';\nimport type { PropsWithChildren, ReactNode } from 'react';\n\ntype ErrorBoundaryProps = PropsWithChildren<{ fallback?: ReactNode }>;\n\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, { hasError: boolean }> {\n  constructor(props: ErrorBoundaryProps) {\n    super(props);\n    this.state = { hasError: false };\n  }\n\n  static getDerivedStateFromError() {\n    return { hasError: true };\n  }\n\n  componentDidCatch(error: unknown, information: unknown) {\n    console.error(error, information);\n  }\n\n  render() {\n    if (this.state.hasError) {\n      return this.props.fallback;\n    }\n\n    return this.props.children;\n  }\n}\n","import React from 'react';\nimport ReactMarkdown, { defaultUrlTransform } from 'react-markdown';\nimport { find } from 'linkifyjs';\nimport remarkGfm from 'remark-gfm';\nimport type { ComponentType, JSX } from 'react';\nimport type { Options } from 'react-markdown';\nimport type { UserResponse } from 'stream-chat';\nimport type { PluggableList } from 'unified'; // A sub-dependency of react-markdown. The type is not declared or re-exported from anywhere else\n\nimport { Anchor, Emoji, Mention } from './componentRenderers';\nimport { detectHttp, matchMarkdownLinks, messageCodeBlocks } from './regex';\nimport { emojiMarkdownPlugin, mentionsMarkdownPlugin } from './rehypePlugins';\nimport {\n  htmlToTextPlugin,\n  imageToLink,\n  keepLineBreaksPlugin,\n  plusPlusToEmphasis,\n} from './remarkPlugins';\nimport { ErrorBoundary } from '../../UtilityComponents';\nimport type { MentionProps } from './componentRenderers';\n\nexport type RenderTextPluginConfigurator = (\n  defaultPlugins: PluggableList,\n) => PluggableList;\n\ntype IntrinsicElementTagName = keyof JSX.IntrinsicElements & string;\n\nexport const defaultAllowedTagNames: Array<\n  IntrinsicElementTagName | 'emoji' | 'mention'\n> = [\n  'html',\n  'text',\n  'br',\n  'p',\n  'em',\n  'strong',\n  'a',\n  'ol',\n  'ul',\n  'li',\n  'code',\n  'pre',\n  'blockquote',\n  'del',\n  'table',\n  'thead',\n  'tbody',\n  'th',\n  'tr',\n  'td',\n  'tfoot',\n  // custom types (tagNames)\n  'emoji',\n  'mention',\n  'h1',\n  'h2',\n  'h3',\n  'h4',\n  'h5',\n  'h6',\n  'ins',\n];\n\nfunction formatUrlForDisplay(url: string) {\n  try {\n    return decodeURIComponent(url).replace(detectHttp, '');\n  } catch (e) {\n    return url;\n  }\n}\n\nfunction encodeDecode(url: string) {\n  try {\n    return encodeURI(decodeURIComponent(url));\n  } catch (error) {\n    return url;\n  }\n}\n\nconst urlTransform = (uri: string) =>\n  uri.startsWith('app://') ? uri : defaultUrlTransform(uri);\n\nconst getPluginsForward: RenderTextPluginConfigurator = (plugins: PluggableList) =>\n  plugins;\n\nexport const markDownRenderers: RenderTextOptions['customMarkDownRenderers'] = {\n  a: Anchor,\n  emoji: Emoji,\n  mention: Mention,\n};\n\nexport type RenderTextOptions = {\n  allowedTagNames?: Array<IntrinsicElementTagName | 'emoji' | 'mention' | (string & {})>;\n  customMarkDownRenderers?: Options['components'] &\n    Partial<{\n      emoji: ComponentType;\n      mention: ComponentType<MentionProps>;\n    }>;\n  getRehypePlugins?: RenderTextPluginConfigurator;\n  getRemarkPlugins?: RenderTextPluginConfigurator;\n};\n\nexport const renderText = (\n  text?: string,\n  mentionedUsers?: UserResponse[],\n  {\n    allowedTagNames = defaultAllowedTagNames,\n    customMarkDownRenderers,\n    getRehypePlugins = getPluginsForward,\n    getRemarkPlugins = getPluginsForward,\n  }: RenderTextOptions = {},\n) => {\n  // take the @ mentions and turn them into markdown?\n  // translate links\n  if (!text) return null;\n  if (text.trim().length === 1) return <>{text}</>;\n\n  let newText = text;\n  const markdownLinks = matchMarkdownLinks(newText);\n  const codeBlocks = messageCodeBlocks(newText);\n\n  // Extract all valid links/emails within text and replace it with proper markup\n  // Revert the link order to avoid getting out of sync of the original start and end positions of links\n  // - due to the addition of new characters when creating Markdown links\n  const links = [...find(newText, 'email'), ...find(newText, 'url')];\n  for (let i = links.length - 1; i >= 0; i--) {\n    const { end, href, start, type, value } = links[i];\n    const linkIsInBlock = codeBlocks.some((block) => block?.includes(value));\n\n    // check if message is already  markdown\n    const noParsingNeeded =\n      markdownLinks &&\n      markdownLinks.filter((text) => {\n        const strippedHref = href?.replace(detectHttp, '');\n        const strippedText = text?.replace(detectHttp, '');\n\n        if (!strippedHref || !strippedText) return false;\n\n        return strippedHref.includes(strippedText) || strippedText.includes(strippedHref);\n      });\n\n    if (noParsingNeeded.length > 0 || linkIsInBlock) continue;\n\n    try {\n      // special case for mentions:\n      // it could happen that a user's name matches with an e-mail format pattern.\n      // in that case, we check whether the found e-mail is actually a mention\n      // by naively checking for an existence of @ sign in front of it.\n      if (type === 'email' && mentionedUsers) {\n        const emailMatchesWithName = mentionedUsers.find((u) => u.name === value);\n        if (emailMatchesWithName) {\n          // FIXME: breaks if the mention symbol is not '@'\n          const isMention = newText.charAt(start - 1) === '@';\n          // in case of mention, we leave the match in its original form,\n          // and we let `mentionsMarkdownPlugin` to do its job\n          newText =\n            newText.slice(0, start) +\n            (isMention ? value : `[${value}](${encodeDecode(href)})`) +\n            newText.slice(end);\n        }\n      } else {\n        const displayLink = type === 'email' ? value : formatUrlForDisplay(href);\n\n        newText =\n          newText.slice(0, start) +\n          `[${displayLink}](${encodeDecode(href)})` +\n          newText.slice(end);\n      }\n    } catch (e) {\n      void e;\n    }\n  }\n\n  const remarkPlugins: PluggableList = [\n    htmlToTextPlugin,\n    keepLineBreaksPlugin,\n    [remarkGfm, { singleTilde: false }],\n    plusPlusToEmphasis,\n    imageToLink,\n  ];\n  const rehypePlugins: PluggableList = [emojiMarkdownPlugin];\n\n  if (mentionedUsers?.length) {\n    rehypePlugins.push(mentionsMarkdownPlugin(mentionedUsers));\n  }\n\n  return (\n    <ErrorBoundary fallback={<>{text}</>}>\n      <ReactMarkdown\n        allowedElements={allowedTagNames}\n        components={{\n          ...markDownRenderers,\n          ...customMarkDownRenderers,\n        }}\n        rehypePlugins={getRehypePlugins(rehypePlugins)}\n        remarkPlugins={getRemarkPlugins(remarkPlugins)}\n        skipHtml\n        unwrapDisallowed\n        urlTransform={urlTransform}\n      >\n        {newText}\n      </ReactMarkdown>\n    </ErrorBoundary>\n  );\n};\n","import clsx from 'clsx';\nimport React, { useMemo } from 'react';\nimport { messageHasAttachments, messageTextHasEmojisOnly } from './utils';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nimport type { MessageContextValue } from '../../context';\nimport { useMessageContext, useTranslationContext } from '../../context';\nimport { VisuallyHidden } from '../VisuallyHidden';\nimport { renderText as defaultRenderText } from './renderText';\n\nimport type { LocalMessage } from 'stream-chat';\nimport { getTranslatedMessageText } from '../../context/MessageTranslationViewContext';\n\nexport type MessageTextProps = {\n  /* Replaces the CSS class name placed on the component's inner `div` container */\n  customInnerClass?: string;\n  /* Adds a CSS class name to the component's outer `div` container */\n  customWrapperClass?: string;\n  /* The `StreamChat` message object, which provides necessary data to the underlying UI components (overrides the value stored in `MessageContext`) */\n  message?: LocalMessage;\n} & Pick<MessageContextValue, 'renderText'>;\n\nconst UnMemoizedMessageTextComponent = (props: MessageTextProps) => {\n  const {\n    customInnerClass,\n    customWrapperClass = '',\n    message: propMessage,\n    renderText: propsRenderText,\n  } = props;\n\n  const {\n    message: contextMessage,\n    onMentionsClickMessage,\n    onMentionsHoverMessage,\n    renderText: contextRenderText,\n    translationView = 'translated',\n    unsafeHTML,\n  } = useMessageContext('MessageText');\n\n  const renderText = propsRenderText ?? contextRenderText ?? defaultRenderText;\n\n  const { t, userLanguage } = useTranslationContext('MessageText');\n  const message = propMessage || contextMessage;\n  const hasAttachment = messageHasAttachments(message);\n  const messageContextId = useStableId();\n  const messageTextId = useStableId();\n\n  const messageTextToRender =\n    translationView === 'original'\n      ? message.text\n      : getTranslatedMessageText({ language: userLanguage, message }) || message.text;\n\n  const messageText = useMemo(\n    () => renderText(messageTextToRender, message.mentioned_users),\n    [message.mentioned_users, messageTextToRender, renderText],\n  );\n\n  const wrapperClass = customWrapperClass || 'str-chat__message-text';\n  const innerClass = customInnerClass;\n  const hasMentionedUsers = Boolean(message.mentioned_users?.length);\n  const isMentionsInteractionEnabled =\n    hasMentionedUsers && typeof onMentionsClickMessage === 'function';\n  const senderName = message.user?.name;\n  const messageContext = senderName\n    ? t('aria/Message from {{ user }},', { user: senderName })\n    : t('aria/Message,');\n  // `aria-labelledby` accepts a space-separated list of element ids. We point to the\n  // hidden message context and the rendered message text so screen readers announce both.\n  const messageLabelledBy = `${messageContextId} ${messageTextId}`;\n\n  const handleMentionsKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n    if (!isMentionsInteractionEnabled || (event.key !== 'Enter' && event.key !== ' ')) {\n      return;\n    }\n\n    event.preventDefault();\n    onMentionsClickMessage(event);\n  };\n\n  if (!messageTextToRender) return null;\n\n  /**\n   * The component has two mutually exclusive focus models. The reason is this bit of behavior:\n   *\n   * if mentions are not interactive:\n   *  - the whole message text block is just a readable focus stop\n   *  - outer wrapper gets tabIndex={0}\n   *  - inner wrapper is not focusable\n   * if mentions are interactive:\n   *  - keyboard interaction needs to land on the inner element, because that’s where onClick, onKeyDown, and mention hover/click behavior live\n   *  - inner wrapper gets tabIndex={0}\n   *  - outer wrapper must stop being focusable, otherwise you create an extra dead focus stop before the actual interactive target\n   */\n  return (\n    <div\n      aria-labelledby={isMentionsInteractionEnabled ? undefined : messageLabelledBy}\n      className={wrapperClass}\n      tabIndex={isMentionsInteractionEnabled ? undefined : 0}\n    >\n      <VisuallyHidden id={messageContextId}>{messageContext}</VisuallyHidden>\n      <div\n        aria-labelledby={isMentionsInteractionEnabled ? messageLabelledBy : undefined}\n        className={clsx(innerClass, {\n          [` str-chat__message-text-inner--is-emoji`]:\n            messageTextHasEmojisOnly(message) && !message.quoted_message,\n          [`str-chat__message-text-inner--has-attachment`]: hasAttachment,\n        })}\n        data-testid='message-text-inner-wrapper'\n        onClick={onMentionsClickMessage}\n        onKeyDown={isMentionsInteractionEnabled ? handleMentionsKeyDown : undefined}\n        onMouseOver={onMentionsHoverMessage}\n        tabIndex={isMentionsInteractionEnabled ? 0 : undefined}\n      >\n        {unsafeHTML && message.html ? (\n          <div dangerouslySetInnerHTML={{ __html: message.html }} id={messageTextId} />\n        ) : (\n          <div id={messageTextId}>{messageText}</div>\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport const MessageText = React.memo(\n  UnMemoizedMessageTextComponent,\n) as typeof UnMemoizedMessageTextComponent;\n","import React, { useMemo } from 'react';\n\nimport { useMessageContext } from '../../context/MessageContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { getDateString, isDate } from '../../i18n/utils';\nimport type { TimestampFormatterOptions } from '../../i18n/types';\n\nexport interface TimestampProps extends TimestampFormatterOptions {\n  /* Adds a CSS class name to the component's outer `time` container. */\n  customClass?: string;\n  /* Timestamp to display */\n  timestamp?: Date | string;\n}\n\nexport function Timestamp(props: TimestampProps) {\n  const { calendar, calendarFormats, customClass, format, timestamp } = props;\n\n  const { formatDate } = useMessageContext('MessageTimestamp');\n  const { t, tDateTimeParser } = useTranslationContext('MessageTimestamp');\n\n  const normalizedTimestamp =\n    timestamp && isDate(timestamp) ? timestamp.toISOString() : timestamp;\n\n  const when = useMemo(\n    () =>\n      getDateString({\n        calendar,\n        calendarFormats,\n        format,\n        formatDate,\n        messageCreatedAt: normalizedTimestamp,\n        t,\n        tDateTimeParser,\n        timestampTranslationKey: 'timestamp/MessageTimestamp',\n      }),\n    [\n      calendar,\n      calendarFormats,\n      format,\n      formatDate,\n      normalizedTimestamp,\n      t,\n      tDateTimeParser,\n    ],\n  );\n\n  if (!when) {\n    return null;\n  }\n\n  return (\n    <time\n      className={customClass}\n      dateTime={normalizedTimestamp}\n      title={normalizedTimestamp}\n    >\n      {when}\n    </time>\n  );\n}\n","import React from 'react';\nimport { useMessageContext } from '../../context/MessageContext';\nimport { Timestamp as DefaultTimestamp } from './Timestamp';\nimport { useComponentContext } from '../../context';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { TimestampFormatterOptions } from '../../i18n/types';\n\nexport type MessageTimestampProps = TimestampFormatterOptions & {\n  /* Adds a CSS class name to the component's outer `time` container. */\n  customClass?: string;\n  /* The `StreamChat` message object, which provides necessary data to the underlying UI components (overrides the value from `MessageContext`) */\n  message?: LocalMessage;\n};\n\nconst UnMemoizedMessageTimestamp = (props: MessageTimestampProps) => {\n  const { message: propMessage, ...timestampProps } = props;\n  const { message: contextMessage } = useMessageContext('MessageTimestamp');\n  const { Timestamp = DefaultTimestamp } = useComponentContext('MessageTimestamp');\n  const message = propMessage || contextMessage;\n  return <Timestamp timestamp={message.created_at} {...timestampProps} />;\n};\n\nexport const MessageTimestamp = React.memo(\n  UnMemoizedMessageTimestamp,\n) as typeof UnMemoizedMessageTimestamp;\n","import React, { useState } from 'react';\nimport type { LocalMessage } from 'stream-chat';\nimport type { TimestampFormatterOptions } from '../../i18n/types';\nimport { PopperTooltip } from '../Tooltip';\nimport { useEnterLeaveHandlers } from '../Tooltip/hooks';\nimport { Timestamp as DefaultTimestamp } from './Timestamp';\nimport {\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\n\nexport type MessageEditedIndicatorProps = TimestampFormatterOptions & {\n  /* Adds a CSS class name to the component's outer container. */\n  customClass?: string;\n  /* The `StreamChat` message object, which provides necessary data to the underlying UI components (overrides the value from `MessageContext`) */\n  message?: LocalMessage;\n};\n\nconst UnMemoizedMessageEditedIndicator = (props: MessageEditedIndicatorProps) => {\n  const { customClass, message: propMessage, ...timestampProps } = props;\n  const { message: contextMessage } = useMessageContext('MessageEditedIndicator');\n  const { t } = useTranslationContext('MessageEditedIndicator');\n  const { Timestamp = DefaultTimestamp } = useComponentContext('MessageEditedIndicator');\n  const message = propMessage ?? contextMessage;\n\n  const [referenceElement, setReferenceElement] = useState<HTMLSpanElement | null>(null);\n  const { handleEnter, handleLeave, tooltipVisible } =\n    useEnterLeaveHandlers<HTMLSpanElement>();\n\n  if (!message?.message_text_updated_at) {\n    return null;\n  }\n\n  return (\n    <span\n      className={customClass ?? 'str-chat__message-edited-indicator'}\n      data-testid='message-edited-indicator'\n      onMouseEnter={handleEnter}\n      onMouseLeave={handleLeave}\n      ref={setReferenceElement}\n    >\n      {t('Edited')}\n      <PopperTooltip\n        offset={[0, 5]}\n        placement='top'\n        referenceElement={referenceElement}\n        visible={tooltipVisible}\n      >\n        <Timestamp timestamp={message.message_text_updated_at} {...timestampProps} />\n      </PopperTooltip>\n    </span>\n  );\n};\n\nexport const MessageEditedIndicator = React.memo(\n  UnMemoizedMessageEditedIndicator,\n) as typeof UnMemoizedMessageEditedIndicator;\n","import type { LocalMessage } from 'stream-chat';\nimport React, { useCallback, useMemo } from 'react';\nimport { IconTranslate } from '../Icons';\nimport {\n  getTranslatedMessageText,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\nimport { Button } from '../Button';\n\nexport type TranslationIndicatorProps = {\n  message?: LocalMessage;\n};\n\nexport const MessageTranslationIndicator = ({\n  message: propMessage,\n}: TranslationIndicatorProps) => {\n  const { t, userLanguage } = useTranslationContext();\n  const {\n    message: contextMessage,\n    setTranslationView,\n    translationView,\n  } = useMessageContext('MessageTranslationIndicator');\n  const message = propMessage ?? contextMessage;\n\n  const translatedTextForUser = useMemo(\n    () => getTranslatedMessageText({ language: userLanguage, message }),\n    [userLanguage, message],\n  );\n\n  const hasTranslationForUserLanguage = useMemo(\n    () =>\n      translatedTextForUser != null &&\n      message?.text !== undefined &&\n      translatedTextForUser !== message.text,\n    [translatedTextForUser, message?.text],\n  );\n\n  const viewingOriginal = useMemo(\n    () =>\n      translationView === 'original' ||\n      (translationView === undefined && !hasTranslationForUserLanguage),\n    [translationView, hasTranslationForUserLanguage],\n  );\n\n  const handleToggle = useCallback(() => {\n    setTranslationView?.(viewingOriginal ? 'translated' : 'original');\n  }, [setTranslationView, viewingOriginal]);\n\n  const sourceLanguageName = useMemo(() => {\n    const sourceLanguageCode = message?.i18n?.language;\n    if (!sourceLanguageCode) return '';\n    const languageKey = 'language/' + sourceLanguageCode;\n    const translatedName = t(languageKey);\n    return translatedName && translatedName !== languageKey\n      ? translatedName\n      : sourceLanguageCode;\n  }, [message?.i18n?.language, t]);\n\n  if (!message?.i18n || !setTranslationView) return null;\n  if (!hasTranslationForUserLanguage) return null;\n\n  return (\n    <div className='str-chat__message-translation-indicator'>\n      <IconTranslate />\n      <span className='str-chat__message-translation-indicator__sign'>\n        {viewingOriginal\n          ? t('Original')\n          : sourceLanguageName\n            ? t('Translated from {{ language }}', { language: sourceLanguageName })\n            : t('Translated')}\n      </span>\n      <span> · </span>\n      <Button\n        className='str-chat__message-translation-indicator__translation-toggle'\n        onClick={handleToggle}\n        type='button'\n      >\n        {viewingOriginal ? t('View translation') : t('View original')}\n      </Button>\n    </div>\n  );\n};\n","import React from 'react';\nimport clsx from 'clsx';\nimport { sanitizeUrl } from '@braintree/sanitize-url';\n\nimport { useTranslationContext } from '../../../context';\nimport { IconDownload } from '../../Icons';\n\nexport type DownloadButtonProps = {\n  /** Attachment asset URL (e.g. `asset_url`). */\n  assetUrl?: string;\n  className?: string;\n  /** Suggested filename for the `download` attribute (not the HTML `title` tooltip). */\n  suggestedFileName?: string;\n  /** Native browser tooltip; defaults to translated “Download Attachment”. */\n  tooltipTitle?: string;\n};\n\n/**\n * Icon download control for {@link Audio} and {@link FileAttachment} rows.\n * (BaseImage defines its own small download link when `showDownloadButtonOnError` is used.)\n */\nexport const DownloadButton = ({\n  assetUrl,\n  className,\n  suggestedFileName,\n  tooltipTitle,\n}: DownloadButtonProps) => {\n  const { t } = useTranslationContext();\n  if (!assetUrl) return null;\n  const href = sanitizeUrl(assetUrl);\n  if (!href) return null;\n\n  return (\n    <a\n      aria-label={t('aria/Download attachment')}\n      className={clsx(\n        'str-chat__button',\n        'str-chat__button--secondary',\n        'str-chat__button--outline',\n        'str-chat__button--circular',\n        'str-chat__button--size-sm',\n        'str-chat__audio-attachment-download-button',\n        className,\n      )}\n      download={suggestedFileName ?? ''}\n      href={href}\n      rel='noopener noreferrer'\n      target='_blank'\n      title={tooltipTitle ?? t('Download Attachment')}\n    >\n      <div className='str-chat__button__content'>\n        <IconDownload className='str-chat__icon str-chat__audio-attachment-download-button__icon' />\n      </div>\n    </a>\n  );\n};\n","import type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport React from 'react';\nimport clsx from 'clsx';\n\nexport const BASE_FILE_ICON_CLASSNAME = 'str-chat__file-icon' as const;\nexport const FILE_ICON_GRAPHIC_CLASSNAME = 'str-chat__file-icon__graphic' as const;\n/** Add this class (e.g. via className) when hiding the label with CSS to center the icon graphic. */\nexport const FILE_ICON_NO_LABEL_CLASSNAME = 'str-chat__file-icon--no-label' as const;\n\nexport type FileIconSize = 'sm' | 'md' | 'lg' | 'xl';\n\nexport type FileIconSizeConfigEntry = {\n  width: number;\n  height: number;\n  labelX: number;\n  labelY: number;\n};\n\n/** Rendered dimensions (px) and label position in viewBox coords for consistent spacing. */\nexport const FILE_ICON_SIZE_CONFIG: Record<FileIconSize, FileIconSizeConfigEntry> = {\n  lg: { height: 40, labelX: 16, labelY: 36, width: 32 },\n  md: { height: 32, labelX: 16, labelY: 35, width: 26 },\n  sm: { height: 24, labelX: 16, labelY: 31.5, width: 19 },\n  xl: { height: 48, labelX: 16, labelY: 36, width: 40 },\n};\n\n/** Merge partial overrides with default config. Use for Chat-level fileIconSizeConfig. */\nexport const mergeFileIconSizeConfig = (\n  overrides?: Partial<Record<FileIconSize, Partial<FileIconSizeConfigEntry>>>,\n): Record<FileIconSize, FileIconSizeConfigEntry> => {\n  if (!overrides) return FILE_ICON_SIZE_CONFIG;\n  return (['sm', 'md', 'lg', 'xl'] as const).reduce(\n    (acc, size) => ({\n      ...acc,\n      [size]: { ...FILE_ICON_SIZE_CONFIG[size], ...overrides[size] },\n    }),\n    {} as Record<FileIconSize, FileIconSizeConfigEntry>,\n  );\n};\n\nconst FILE_ICON_VIEWBOX = { height: 40, width: 32 } as const;\nconst FILE_ICON_PAPER_PATH =\n  'M0 4C0 1.79086 1.79086 0 4 0H22.4L32 10V36C32 38.2091 30.2091 40 28 40H4C1.79086 40 0 38.2091 0 36V4Z';\nconst FILE_ICON_FOLD_PATH = 'M32 10H25.4C23.7431 10 22.4 8.65685 22.4 7V0L32 10Z';\nconst FILE_ICON_WITHOUT_CAPTION_SYMBOL_SCALE_X = 32 / 26;\nconst FILE_ICON_WITHOUT_CAPTION_SYMBOL_SCALE_Y = 40 / 32;\n\nexport type BaseFileIconProps = {\n  label?: string;\n  /** Resolved size config (defaults from FILE_ICON_SIZE_CONFIG when omitted). Pass sizeConfig on FileIcon or use AttachmentFileIcon to override. */\n  sizeConfig?: Record<FileIconSize, FileIconSizeConfigEntry>;\n  size?: FileIconSize;\n} & ComponentPropsWithoutRef<'svg'>;\n\ntype SvgProps = Omit<BaseFileIconProps, 'label'>;\n\nconst Svg = ({ className, size, sizeConfig, ...props }: SvgProps) => {\n  const config = sizeConfig ?? FILE_ICON_SIZE_CONFIG;\n  const dimensions = size ? config[size] : undefined;\n  const dimensionsStyle = dimensions\n    ? {\n        flexShrink: 0,\n        height: `${dimensions.height}px`,\n        width: `${dimensions.width}px`,\n      }\n    : undefined;\n\n  return (\n    <svg\n      height={dimensions?.height}\n      viewBox={`0 0 ${FILE_ICON_VIEWBOX.width} ${FILE_ICON_VIEWBOX.height}`}\n      width={dimensions?.width}\n      xmlns='http://www.w3.org/2000/svg'\n      {...props}\n      className={clsx(\n        BASE_FILE_ICON_CLASSNAME,\n        { [`${BASE_FILE_ICON_CLASSNAME}--size-${size}`]: size },\n        className,\n      )}\n      style={{ ...dimensionsStyle, ...props.style }}\n    />\n  );\n};\n\ntype FileIconLabelProps = {\n  label?: string;\n  size?: FileIconSize;\n  sizeConfig?: Record<FileIconSize, FileIconSizeConfigEntry>;\n};\n\nconst FileIconLabel = ({ label, size, sizeConfig }: FileIconLabelProps) => {\n  const configMap = sizeConfig ?? FILE_ICON_SIZE_CONFIG;\n  const config = size ? configMap[size] : { labelX: 16, labelY: 33 };\n  return (\n    <text className='str-chat__file-icon__label' x={config.labelX} y={config.labelY}>\n      {label}\n    </text>\n  );\n};\n\ntype FileIconSymbolMap = {\n  withCaption: ReactNode;\n  withoutCaption: ReactNode;\n};\n\nconst TEXT_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <>\n      <rect fill='white' height='1.6' rx='0.8' width='14.4' x='8' y='12.2' />\n      <rect fill='white' height='1.6' rx='0.8' width='14.4' x='8' y='20.2' />\n      <rect fill='white' height='1.6' rx='0.8' width='9.6' x='8' y='16.2' />\n    </>\n  ),\n  withoutCaption: (\n    <>\n      <rect fill='white' height='1.4' rx='0.7' width='12.6' x='6' y='14.8' />\n      <rect fill='white' height='1.4' rx='0.7' width='12.6' x='6' y='21.8' />\n      <rect fill='white' height='1.4' rx='0.7' width='8.4' x='6' y='18.3' />\n    </>\n  ),\n};\n\nconst OTHER_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <>\n      <rect fill='white' height='1.6' rx='0.8' width='14.4' x='8' y='13.2' />\n      <rect fill='white' height='1.6' rx='0.8' width='14.4' x='8' y='21.2' />\n      <rect fill='white' height='1.6' rx='0.8' width='9.6' x='8' y='17.2' />\n    </>\n  ),\n  withoutCaption: TEXT_SYMBOLS.withoutCaption,\n};\n\nconst CODE_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <path\n      d='M14.5 22.5L17.5 11.5M20.1666 14.1667L21.9732 16.0862C22.4564 16.5996 22.4564 17.4004 21.9732 17.9138L20.1666 19.8333M11.8333 19.8333L10.0267 17.9138C9.54351 17.4004 9.54351 16.5996 10.0267 16.0862L11.8333 14.1667'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.2'\n    />\n  ),\n  withoutCaption: (\n    <path\n      d='M11.6876 23.8125L14.3126 14.1875M16.646 16.5208L18.2267 18.2004C18.6495 18.6496 18.6495 19.3503 18.2267 19.7996L16.646 21.4792M9.3543 21.4792L7.77352 19.7996C7.35072 19.3503 7.35072 18.6496 7.77352 18.2004L9.3543 16.5208'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.33333'\n    />\n  ),\n};\n\nconst AUDIO_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <path\n      d='M20.5 15.5V18.5M22.5 14.5V19.5M13.5 19.5H10.5C10.3674 19.5 10.2402 19.4473 10.1464 19.3536C10.0527 19.2598 10 19.1326 10 19V15C10 14.8674 10.0527 14.7402 10.1464 14.6464C10.2402 14.5527 10.3674 14.5 10.5 14.5H13.5L18 11V23L13.5 19.5Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.2'\n    />\n  ),\n  withoutCaption: (\n    <path\n      d='M17.5 17.5V20.5M19.5 16.5V21.5M10.5 21.5H7.5C7.36739 21.5 7.24021 21.4473 7.14645 21.3536C7.05268 21.2598 7 21.1326 7 21V17C7 16.8674 7.05268 16.7402 7.14645 16.6464C7.24021 16.5527 7.36739 16.5 7.5 16.5H10.5L15 13V25L10.5 21.5Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.33333'\n    />\n  ),\n};\n\nconst PRESENTATION_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <path\n      d='M12.5 15.5H19.5M16 17.5V22.5M14 22.5H18M9.49999 17.5C9.41472 17.5001 9.33085 17.4783 9.25635 17.4368C9.18185 17.3953 9.1192 17.3355 9.07436 17.263C9.02952 17.1904 9.00397 17.1076 9.00014 17.0224C8.99631 16.9373 9.01433 16.8525 9.05249 16.7762L11.5525 11.7763C11.5941 11.6932 11.6579 11.6233 11.737 11.5745C11.816 11.5257 11.9071 11.4999 12 11.5H20C20.0929 11.4999 20.184 11.5257 20.263 11.5745C20.342 11.6233 20.4059 11.6932 20.4475 11.7763L22.9475 16.7762C22.9857 16.8525 23.0037 16.9373 22.9998 17.0224C22.996 17.1076 22.9705 17.1904 22.9256 17.263C22.8808 17.3355 22.8181 17.3953 22.7436 17.4368C22.6691 17.4783 22.5853 17.5001 22.5 17.5H9.49999Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.2'\n    />\n  ),\n  withoutCaption: (\n    <path\n      d='M9.49999 17.5H16.5M13 19.5V24.5M11 24.5H15M6.49999 19.5C6.41472 19.5001 6.33085 19.4783 6.25635 19.4368C6.18185 19.3953 6.11921 19.3355 6.07436 19.263C6.02952 19.1904 6.00397 19.1076 6.00014 19.0224C5.99631 18.9373 6.01433 18.8525 6.05249 18.7763L8.55249 13.7763C8.59406 13.6932 8.65795 13.6233 8.73699 13.5745C8.81603 13.5257 8.9071 13.4999 8.99999 13.5H17C17.0929 13.4999 17.184 13.5257 17.263 13.5745C17.342 13.6233 17.4059 13.6932 17.4475 13.7763L19.9475 18.7763C19.9857 18.8525 20.0037 18.9373 19.9998 19.0224C19.996 19.1076 19.9705 19.1904 19.9256 19.263C19.8808 19.3355 19.8181 19.3953 19.7436 19.4368C19.6691 19.4783 19.5853 19.5001 19.5 19.5H6.49999Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.33333'\n    />\n  ),\n};\n\nconst SPREADSHEET_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <path\n      d='M10 15.5H22M10 18.5H22M13.5 15.5V21.5M10 12.5H22V21C22 21.1326 21.9473 21.2598 21.8536 21.3536C21.7598 21.4473 21.6326 21.5 21.5 21.5H10.5C10.3674 21.5 10.2402 21.4473 10.1464 21.3536C10.0527 21.2598 10 21.1326 10 21V12.5Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.5'\n    />\n  ),\n  withoutCaption: (\n    <path\n      d='M7 17.5H19M7 20.5H19M10.5 17.5V23.5M7 14.5H19V23C19 23.1326 18.9473 23.2598 18.8536 23.3536C18.7598 23.4473 18.6326 23.5 18.5 23.5H7.5C7.36739 23.5 7.24021 23.4473 7.14645 23.3536C7.05268 23.2598 7 23.1326 7 23V14.5Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.2'\n    />\n  ),\n};\n\nconst COMPRESSION_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <path\n      clipRule='evenodd'\n      d='M9.41177 0H7.52942V2H9.41177V4H7.52942V6H9.41177V8H7.52942V10H9.41177V12H7.52942V14H9.41177V12H11.2941V10H9.41177V8H11.2941V6H9.41177V4H11.2941V2H9.41177V0ZM7.52942 17C7.52942 16.4477 7.9508 16 8.4706 16H10.3529C10.8727 16 11.2941 16.4477 11.2941 17V23C11.2941 23.5523 10.8727 24 10.3529 24H8.4706C7.9508 24 7.52942 23.5523 7.52942 23V17ZM8.4706 23V20H10.3529V23H8.4706Z'\n      fill='white'\n      fillRule='evenodd'\n    />\n  ),\n  withoutCaption: (\n    <path\n      clipRule='evenodd'\n      d='M8.17031 0H6.11768V2.14737H8.17031V4.29474H6.11768V6.4421H8.17031V8.58947H6.11768V10.7368H8.17031V12.8842H6.11768V15.0316H8.17031V12.8842H10.2229V10.7368H8.17031V8.58947H10.2229V6.4421H8.17031V4.29474H10.2229V2.14737H8.17031V0ZM6.11768 18.2526C6.11768 17.6597 6.57717 17.1789 7.14399 17.1789H9.19662C9.76344 17.1789 10.2229 17.6597 10.2229 18.2526V24.6947C10.2229 25.2877 9.76344 25.7684 9.19662 25.7684H7.14399C6.57717 25.7684 6.11768 25.2877 6.11768 24.6947V18.2526ZM7.14399 24.6947V21.4737H9.19662V24.6947H7.14399Z'\n      fill='white'\n      fillRule='evenodd'\n    />\n  ),\n};\n\nconst VIDEO_SYMBOLS: FileIconSymbolMap = {\n  withCaption: (\n    <path\n      d='M20.5 16L23.5 14V20L20.5 18M10 13H20C20.2761 13 20.5 13.2239 20.5 13.5V20.5C20.5 20.7761 20.2761 21 20 21H10C9.72386 21 9.5 20.7761 9.5 20.5V13.5C9.5 13.2239 9.72386 13 10 13Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.2'\n    />\n  ),\n  withoutCaption: (\n    <path\n      d='M17.5001 18L20.5001 16V22L17.5001 20M7.00012 15H17.0001C17.2763 15 17.5001 15.2239 17.5001 15.5V22.5C17.5001 22.7761 17.2763 23 17.0001 23H7.00012C6.72398 23 6.50012 22.7761 6.50012 22.5V15.5C6.50012 15.2239 6.72398 15 7.00012 15Z'\n      stroke='white'\n      strokeLinecap='round'\n      strokeLinejoin='round'\n      strokeWidth='1.33333'\n    />\n  ),\n};\n\ntype StandardFileTypeIconProps = BaseFileIconProps & {\n  color: string;\n  fileTypeClassName: string;\n  symbols: FileIconSymbolMap;\n};\n\nconst StandardFileTypeIcon = ({\n  className,\n  color,\n  fileTypeClassName,\n  label,\n  size,\n  sizeConfig,\n  symbols,\n  ...props\n}: StandardFileTypeIconProps) => {\n  const renderLabel = !!label;\n  const resolvedLabel = renderLabel ? label : undefined;\n  const symbolVariant = renderLabel ? 'withCaption' : 'withoutCaption';\n\n  return (\n    <Svg\n      {...props}\n      className={clsx(fileTypeClassName, className)}\n      size={size}\n      sizeConfig={sizeConfig}\n    >\n      <g className={FILE_ICON_GRAPHIC_CLASSNAME}>\n        <path d={FILE_ICON_PAPER_PATH} fill={color} />\n        {renderLabel ? (\n          symbols[symbolVariant]\n        ) : (\n          <g\n            transform={`scale(${FILE_ICON_WITHOUT_CAPTION_SYMBOL_SCALE_X} ${FILE_ICON_WITHOUT_CAPTION_SYMBOL_SCALE_Y})`}\n          >\n            {symbols[symbolVariant]}\n          </g>\n        )}\n        <path d={FILE_ICON_FOLD_PATH} fill='white' opacity='0.5' />\n      </g>\n      {resolvedLabel && (\n        <FileIconLabel label={resolvedLabel} size={size} sizeConfig={sizeConfig} />\n      )}\n    </Svg>\n  );\n};\n\nconst PDF_SMALL_SYMBOL = (\n  <path\n    d='M20.7533 19.5337C20.28 19.037 19.3093 18.7537 17.9373 18.7537C17.204 18.7537 16.3526 18.8244 15.43 18.9897C14.8647 18.4461 14.3499 17.8523 13.892 17.2157C13.5373 16.7424 13.2293 16.2224 12.9453 15.725C13.49 14.069 13.75 12.7204 13.75 11.7504C13.75 10.6624 13.348 9.52637 12.1886 9.52637C11.834 9.52637 11.4786 9.7397 11.2893 10.047C10.7693 10.9697 11.006 12.9804 11.9046 14.9677C11.5664 15.984 11.1876 16.9863 10.7693 17.9724C10.3906 18.8717 9.96465 19.7944 9.49131 20.6457C6.88931 21.687 5.20931 22.8937 5.01998 23.839C4.94931 24.1944 5.06731 24.5257 5.32798 24.7857C5.42265 24.857 5.75398 25.141 6.32131 25.141C8.04798 25.141 9.86998 22.349 10.7926 20.6697C11.5026 20.433 12.2126 20.1964 12.922 20.007C13.6704 19.8038 14.4284 19.638 15.1933 19.5104C17.0146 21.1424 18.6233 21.403 19.428 21.403C20.4213 21.403 20.7766 21.0004 20.8946 20.6697C21.108 20.243 20.966 19.7704 20.7533 19.5337ZM19.8066 20.2204C19.7353 20.575 19.38 20.8117 18.884 20.8117C18.742 20.8117 18.624 20.7877 18.4813 20.7644C17.5826 20.551 16.7306 20.1017 15.8793 19.3917C16.5357 19.2807 17.2003 19.2254 17.866 19.2264C18.3633 19.2264 18.7893 19.2497 19.0726 19.321C19.404 19.3917 19.9246 19.605 19.806 20.2197L19.8066 20.2204ZM14.7906 19.1084C14.1305 19.2321 13.4755 19.382 12.8273 19.5577C12.262 19.7047 11.7017 19.8703 11.1473 20.0544C11.4355 19.4962 11.7039 18.9281 11.952 18.351C12.236 17.6884 12.472 17.0024 12.7093 16.3637C12.9453 16.7657 13.206 17.1684 13.466 17.523C13.8911 18.065 14.3329 18.5937 14.7906 19.1084ZM11.692 10.307C11.7338 10.2232 11.7978 10.1525 11.877 10.1025C11.9563 10.0526 12.0477 10.0253 12.1413 10.0237C12.638 10.0237 12.7326 10.591 12.7326 11.041C12.7326 11.7977 12.496 12.957 12.094 14.2817C11.4073 12.4364 11.3606 10.899 11.692 10.307ZM9.08931 21.3317C7.88265 23.319 6.72331 24.549 6.01398 24.549C5.88599 24.5498 5.76132 24.5083 5.65931 24.431C5.51731 24.289 5.44598 24.1237 5.49331 23.9344C5.63531 23.2244 7.00731 22.231 9.08931 21.3317Z'\n    fill='white'\n  />\n);\n\nconst PDF_LEGACY_SYMBOL = (\n  <>\n    <path\n      d='M23.7533 19.2C23.28 18.7033 22.3093 18.42 20.9373 18.42C20.204 18.42 19.3526 18.4906 18.43 18.656C17.8647 18.1124 17.3499 17.5186 16.892 16.882C16.5373 16.4086 16.2293 15.8886 15.9453 15.3913C16.49 13.7353 16.75 12.3866 16.75 11.4166C16.75 10.3286 16.348 9.19263 15.1886 9.19263C14.834 9.19263 14.4786 9.40596 14.2893 9.71329C13.7693 10.636 14.006 12.6466 14.9046 14.634C14.5664 15.6502 14.1877 16.6526 13.7693 17.6386C13.3906 18.538 12.9646 19.4606 12.4913 20.312C9.88931 21.3533 8.20931 22.56 8.01998 23.5053C7.94931 23.8606 8.06731 24.192 8.32798 24.452C8.42265 24.5233 8.75398 24.8073 9.32131 24.8073C11.048 24.8073 12.87 22.0153 13.7926 20.336C14.5026 20.0993 15.2126 19.8626 15.922 19.6733C16.6704 19.4701 17.4284 19.3043 18.1933 19.1766C20.0146 20.8086 21.6233 21.0693 22.428 21.0693C23.4213 21.0693 23.7766 20.6666 23.8946 20.336C24.108 19.9093 23.966 19.4366 23.7533 19.2ZM22.8066 19.8866C22.7353 20.2413 22.38 20.478 21.884 20.478C21.742 20.478 21.624 20.454 21.4813 20.4306C20.5826 20.2173 19.7306 19.768 18.8793 19.058C19.5357 18.947 20.2003 18.8917 20.866 18.8926C21.3633 18.8926 21.7893 18.916 22.0726 18.9873C22.404 19.058 22.9246 19.2713 22.806 19.886L22.8066 19.8866ZM17.7906 18.7746C17.1305 18.8983 16.4755 19.0482 15.8273 19.224C15.262 19.3709 14.7017 19.5366 14.1473 19.7206C14.4355 19.1625 14.7039 18.5944 14.952 18.0173C15.236 17.3546 15.472 16.6686 15.7093 16.03C15.9453 16.432 16.206 16.8346 16.466 17.1893C16.8911 17.7313 17.3329 18.26 17.7906 18.7746ZM14.692 9.97329C14.7338 9.88949 14.7978 9.81875 14.877 9.7688C14.9563 9.71884 15.0477 9.69157 15.1413 9.68996C15.638 9.68996 15.7326 10.2573 15.7326 10.7073C15.7326 11.464 15.496 12.6233 15.094 13.948C14.4073 12.1026 14.3606 10.5653 14.692 9.97329ZM12.0893 20.998C10.8826 22.9853 9.72331 24.2153 9.01398 24.2153C8.88599 24.2161 8.76132 24.1746 8.65931 24.0973C8.51731 23.9553 8.44598 23.79 8.49331 23.6006C8.63531 22.8906 10.0073 21.8973 12.0893 20.998Z'\n      fill='white'\n    />\n    <path\n      d='M9.74219 34.4258V28.6992H10.8828V29.3633H10.9531C11.0286 29.2096 11.1276 29.0781 11.25 28.9688C11.375 28.8594 11.5208 28.776 11.6875 28.7188C11.8542 28.6589 12.0391 28.6289 12.2422 28.6289C12.6016 28.6289 12.9115 28.7188 13.1719 28.8984C13.4323 29.0781 13.6328 29.3333 13.7734 29.6641C13.9167 29.9922 13.9883 30.3854 13.9883 30.8438V30.8516C13.9883 31.3125 13.918 31.7083 13.7773 32.0391C13.6367 32.3698 13.4362 32.6237 13.1758 32.8008C12.9154 32.9779 12.6042 33.0664 12.2422 33.0664C12.0443 33.0664 11.8607 33.0365 11.6914 32.9766C11.5247 32.9141 11.3776 32.8268 11.25 32.7148C11.125 32.6029 11.026 32.4688 10.9531 32.3125H10.8828V34.4258H9.74219ZM11.8516 32.1211C12.0547 32.1211 12.2279 32.0703 12.3711 31.9688C12.5169 31.8672 12.6289 31.7214 12.707 31.5312C12.7878 31.3411 12.8281 31.1146 12.8281 30.8516V30.8438C12.8281 30.5807 12.7878 30.3542 12.707 30.1641C12.6289 29.974 12.5169 29.8281 12.3711 29.7266C12.2279 29.625 12.0547 29.5742 11.8516 29.5742C11.651 29.5742 11.4766 29.625 11.3281 29.7266C11.1823 29.8281 11.069 29.974 10.9883 30.1641C10.9102 30.3516 10.8711 30.5781 10.8711 30.8438V30.8516C10.8711 31.112 10.9115 31.3385 10.9922 31.5312C11.0729 31.7214 11.1862 31.8672 11.332 31.9688C11.4805 32.0703 11.6536 32.1211 11.8516 32.1211ZM16.457 33.0664C16.1003 33.0664 15.7904 32.9779 15.5273 32.8008C15.2669 32.6211 15.0651 32.3659 14.9219 32.0352C14.7812 31.7044 14.7109 31.3099 14.7109 30.8516V30.8438C14.7109 30.3828 14.7799 29.987 14.918 29.6562C15.0586 29.3255 15.2591 29.0716 15.5195 28.8945C15.7799 28.7174 16.0924 28.6289 16.457 28.6289C16.6523 28.6289 16.8333 28.6602 17 28.7227C17.1693 28.7826 17.3177 28.8685 17.4453 28.9805C17.5729 29.0924 17.6719 29.2279 17.7422 29.3867H17.8125V27.0547H18.9531V33H17.8125V32.332H17.7422C17.6693 32.4857 17.5703 32.6172 17.4453 32.7266C17.3229 32.8359 17.1784 32.9206 17.0117 32.9805C16.8451 33.0378 16.6602 33.0664 16.457 33.0664ZM16.8438 32.1211C17.0469 32.1211 17.2214 32.0703 17.3672 31.9688C17.513 31.8672 17.625 31.7214 17.7031 31.5312C17.7839 31.3411 17.8242 31.1159 17.8242 30.8555V30.8477C17.8242 30.582 17.7839 30.3555 17.7031 30.168C17.625 29.9779 17.5117 29.832 17.3633 29.7305C17.2174 29.6263 17.0443 29.5742 16.8438 29.5742C16.6458 29.5742 16.4727 29.6263 16.3242 29.7305C16.1784 29.832 16.0664 29.9779 15.9883 30.168C15.9102 30.3555 15.8711 30.5807 15.8711 30.8438V30.8516C15.8711 31.1146 15.9102 31.3411 15.9883 31.5312C16.0664 31.7214 16.1784 31.8672 16.3242 31.9688C16.4701 32.0703 16.6432 32.1211 16.8438 32.1211ZM20.4648 33V29.5586H19.7695V28.6992H20.4648V28.2969C20.4648 28.0104 20.5156 27.7721 20.6172 27.582C20.7188 27.3919 20.8776 27.25 21.0938 27.1562C21.3125 27.0599 21.5951 27.0117 21.9414 27.0117C22.0586 27.0117 22.1641 27.0156 22.2578 27.0234C22.3542 27.0312 22.444 27.0417 22.5273 27.0547V27.8164C22.4909 27.8086 22.4427 27.8034 22.3828 27.8008C22.3255 27.7956 22.2604 27.793 22.1875 27.793C21.9661 27.793 21.8099 27.8438 21.7188 27.9453C21.6276 28.0443 21.582 28.1875 21.582 28.375V28.6992H22.4922V29.5586H21.6055V33H20.4648Z'\n      fill='white'\n    />\n  </>\n);\n\nexport const FilePdfIcon = ({\n  className,\n  label,\n  size,\n  sizeConfig,\n  ...props\n}: BaseFileIconProps) => {\n  const useLegacyPdfMarkup = !!label;\n\n  return (\n    <Svg\n      {...props}\n      className={clsx(\n        'str-chat__file-icon--pdf',\n        useLegacyPdfMarkup && FILE_ICON_NO_LABEL_CLASSNAME,\n        className,\n      )}\n      size={size}\n      sizeConfig={sizeConfig}\n    >\n      <g className={FILE_ICON_GRAPHIC_CLASSNAME}>\n        <path d={FILE_ICON_PAPER_PATH} fill='#E71A01' />\n        {useLegacyPdfMarkup ? (\n          PDF_LEGACY_SYMBOL\n        ) : (\n          <g\n            transform={`scale(${FILE_ICON_WITHOUT_CAPTION_SYMBOL_SCALE_X} ${FILE_ICON_WITHOUT_CAPTION_SYMBOL_SCALE_Y})`}\n          >\n            {PDF_SMALL_SYMBOL}\n          </g>\n        )}\n        <path d={FILE_ICON_FOLD_PATH} fill='white' opacity='0.5' />\n      </g>\n    </Svg>\n  );\n};\n\nexport const FileWordIcon = ({ className, label, ...props }: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#3375E2'\n    fileTypeClassName='str-chat__file-icon--doc'\n    label={label}\n    symbols={TEXT_SYMBOLS}\n  />\n);\n\nexport const FilePowerPointIcon = ({ className, label, ...props }: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#D14423'\n    fileTypeClassName='str-chat__file-icon--ppt'\n    label={label}\n    symbols={PRESENTATION_SYMBOLS}\n  />\n);\n\nexport const FileExcelIcon = ({ className = '', label, ...props }: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#0C864B'\n    fileTypeClassName='str-chat__file-icon--xls'\n    label={label}\n    symbols={SPREADSHEET_SYMBOLS}\n  />\n);\n\nexport const FileArchiveIcon = ({\n  className = '',\n  label = '',\n  ...props\n}: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#E59E34'\n    fileTypeClassName='str-chat__file-icon--compressed'\n    label={label}\n    symbols={COMPRESSION_SYMBOLS}\n  />\n);\n\nexport const FileCodeIcon = ({ className = '', label, ...props }: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#00ACA1'\n    fileTypeClassName='str-chat__file-icon--code'\n    label={label}\n    symbols={CODE_SYMBOLS}\n  />\n);\n\nexport const FileAudioIcon = ({ className = '', label, ...props }: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#2727B0'\n    fileTypeClassName='str-chat__file-icon--audio'\n    label={label}\n    symbols={AUDIO_SYMBOLS}\n  />\n);\n\nexport const FileVideoIcon = ({ className = '', label, ...props }: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#A847B7'\n    fileTypeClassName='str-chat__file-icon--video'\n    label={label}\n    symbols={VIDEO_SYMBOLS}\n  />\n);\n\nexport const FileFallbackIcon = ({\n  className = '',\n  label = '',\n  ...props\n}: BaseFileIconProps) => (\n  <StandardFileTypeIcon\n    {...props}\n    className={className}\n    color='#888888'\n    fileTypeClassName='str-chat__file-icon--other'\n    label={label}\n    symbols={OTHER_SYMBOLS}\n  />\n);\n","export type GeneralType = 'audio/' | 'video/' | 'image/' | 'text/';\n\nexport type SupportedMimeType =\n  | (typeof wordMimeTypes)[number]\n  | (typeof excelMimeTypes)[number]\n  | (typeof powerpointMimeTypes)[number]\n  | (typeof archiveFileTypes)[number]\n  | (typeof codeFileTypes)[number];\n\nexport const wordMimeTypes = [\n  // Microsoft Word\n  // .doc .dot\n  'application/msword',\n  // .doc .dot\n  'application/msword-template',\n  // .docx\n  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n  // .dotx (no test)\n  'application/vnd.openxmlformats-officedocument.wordprocessingml.template',\n  // .docm\n  'application/vnd.ms-word.document.macroEnabled.12',\n  // .dotm (no test)\n  'application/vnd.ms-word.template.macroEnabled.12',\n\n  // LibreOffice/OpenOffice Writer\n  // .odt\n  'application/vnd.oasis.opendocument.text',\n  // .ott\n  'application/vnd.oasis.opendocument.text-template',\n  // .fodt\n  'application/vnd.oasis.opendocument.text-flat-xml',\n  // .uot\n  // NOTE: firefox doesn't know mimetype so maybe ignore\n];\n\nexport const excelMimeTypes = [\n  // .csv\n  'text/csv',\n  // TODO: maybe more data files\n\n  // Microsoft Excel\n  // .xls .xlt .xla (no test for .xla)\n  'application/vnd.ms-excel',\n  // .xlsx\n  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n  // .xltx (no test)\n  'application/vnd.openxmlformats-officedocument.spreadsheetml.template',\n  // .xlsm\n  'application/vnd.ms-excel.sheet.macroEnabled.12',\n  // .xltm (no test)\n  'application/vnd.ms-excel.template.macroEnabled.12',\n  // .xlam (no test)\n  'application/vnd.ms-excel.addin.macroEnabled.12',\n  // .xlsb (no test)\n  'application/vnd.ms-excel.addin.macroEnabled.12',\n\n  // LibreOffice/OpenOffice Calc\n  // .ods\n  'application/vnd.oasis.opendocument.spreadsheet',\n  // .ots\n  'application/vnd.oasis.opendocument.spreadsheet-template',\n  // .fods\n  'application/vnd.oasis.opendocument.spreadsheet-flat-xml',\n  // .uos\n  // NOTE: firefox doesn't know mimetype so maybe ignore\n];\n\nexport const powerpointMimeTypes = [\n  // Microsoft Word\n  // .ppt .pot .pps .ppa (no test for .ppa)\n  'application/vnd.ms-powerpoint',\n  // .pptx\n  'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n  // .potx (no test)\n  'application/vnd.openxmlformats-officedocument.presentationml.template',\n  // .ppsx\n  'application/vnd.openxmlformats-officedocument.presentationml.slideshow',\n  // .ppam\n  'application/vnd.ms-powerpoint.addin.macroEnabled.12',\n  // .pptm\n  'application/vnd.ms-powerpoint.presentation.macroEnabled.12',\n  // .potm\n  'application/vnd.ms-powerpoint.template.macroEnabled.12',\n  // .ppsm\n  'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',\n\n  // LibreOffice/OpenOffice Writer\n  // .odp\n  'application/vnd.oasis.opendocument.presentation',\n  // .otp\n  'application/vnd.oasis.opendocument.presentation-template',\n  // .fodp\n  'application/vnd.oasis.opendocument.presentation-flat-xml',\n  // .uop\n  // NOTE: firefox doesn't know mimetype so maybe ignore\n];\n\nexport const archiveFileTypes = [\n  // .zip\n  'application/zip',\n  // .z7\n  'application/x-7z-compressed',\n  // .ar\n  'application/x-archive',\n  // .tar\n  'application/x-tar',\n  // .tar.gz\n  'application/gzip',\n  // .tar.Z\n  'application/x-compress',\n  // .tar.bz2\n  'application/x-bzip',\n  // .tar.lz\n  'application/x-lzip',\n  // .tar.lz4\n  'application/x-lz4',\n  // .tar.lzma\n  'application/x-lzma',\n  // .tar.lzo (no test)\n  'application/x-lzop',\n  // .tar.xz\n  'application/x-xz',\n  // .war\n  'application/x-webarchive',\n  // .rar\n  'application/vnd.rar',\n];\n\nexport const codeFileTypes = [\n  // .html .htm\n  'text/html',\n  // .css\n  'text/css',\n  // .js\n  'application/x-javascript',\n  'text/javascript',\n  // .json\n  'application/json',\n  // .py\n  'text/x-python',\n  // .go\n  'text/x-go',\n  // .c\n  'text/x-csrc',\n  // .cpp\n  'text/x-c++src',\n  // .rb\n  'application/x-ruby',\n  // .rust\n  'text/rust',\n  // .java\n  'text/x-java',\n  // .php\n  'application/x-php',\n  // .cs\n  'text/x-csharp',\n  // .scala\n  'text/x-scala',\n  // .erl\n  'text/x-erlang',\n  // .sh\n  'application/x-shellscript',\n];\n\nexport const mimeTypeToExtensionMap: Record<string, string> = {\n  // Application types (sorted alphabetically)\n  'application/epub+zip': 'epub',\n  'application/gzip': 'gz',\n  'application/java-archive': 'jar',\n  'application/json': 'json',\n  'application/ld+json': 'jsonld',\n  'application/msword': 'doc',\n  'application/msword-template': 'dot',\n  'application/octet-stream': 'bin',\n  'application/ogg': 'ogx',\n  'application/pdf': 'pdf',\n  'application/postscript': 'ps',\n  'application/rtf': 'rtf',\n  'application/vnd.amazon.ebook': 'azw',\n  'application/vnd.apple.installer+xml': 'mpkg',\n  'application/vnd.mozilla.xul+xml': 'xul',\n  'application/vnd.ms-excel': 'xls',\n  'application/vnd.ms-excel.addin.macroEnabled.12': 'xlam',\n  'application/vnd.ms-excel.sheet.macroEnabled.12': 'xlsm',\n  'application/vnd.ms-excel.template.macroEnabled.12': 'xltm',\n  'application/vnd.ms-fontobject': 'eot',\n  'application/vnd.ms-powerpoint': 'ppt',\n  'application/vnd.ms-powerpoint.addin.macroEnabled.12': 'ppam',\n  'application/vnd.ms-powerpoint.presentation.macroEnabled.12': 'pptm',\n  'application/vnd.ms-powerpoint.slideshow.macroEnabled.12': 'ppsm',\n  'application/vnd.ms-powerpoint.template.macroEnabled.12': 'potm',\n  'application/vnd.ms-word.document.macroEnabled.12': 'docm',\n  'application/vnd.ms-word.template.macroEnabled.12': 'dotm',\n  'application/vnd.oasis.opendocument.presentation': 'odp',\n  'application/vnd.oasis.opendocument.presentation-flat-xml': 'fodp',\n  'application/vnd.oasis.opendocument.presentation-template': 'otp',\n  'application/vnd.oasis.opendocument.spreadsheet': 'ods',\n  'application/vnd.oasis.opendocument.spreadsheet-flat-xml': 'fods',\n  'application/vnd.oasis.opendocument.spreadsheet-template': 'ots',\n  'application/vnd.oasis.opendocument.text': 'odt',\n  'application/vnd.oasis.opendocument.text-flat-xml': 'fodt',\n  'application/vnd.oasis.opendocument.text-template': 'ott',\n  'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',\n  'application/vnd.openxmlformats-officedocument.presentationml.slideshow': 'ppsx',\n  'application/vnd.openxmlformats-officedocument.presentationml.template': 'potx',\n  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',\n  'application/vnd.openxmlformats-officedocument.spreadsheetml.template': 'xltx',\n  'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',\n  'application/vnd.openxmlformats-officedocument.wordprocessingml.template': 'dotx',\n  'application/vnd.rar': 'rar',\n  'application/vnd.visio': 'vsd',\n  'application/wasm': 'wasm',\n  'application/x-7z-compressed': '7z',\n  'application/x-abiword': 'abw',\n  'application/x-archive': 'ar',\n  'application/x-bzip': 'bz',\n  'application/x-bzip2': 'bz2',\n  'application/x-cdf': 'cda',\n  'application/x-compress': 'Z',\n  'application/x-csh': 'csh',\n  'application/x-dosexec': 'exe',\n  'application/x-freearc': 'arc',\n  'application/x-httpd-php': 'php',\n  'application/x-iso9660-image': 'iso',\n  'application/x-javascript': 'js',\n  'application/x-lz4': 'lz4',\n  'application/x-lzip': 'lz',\n  'application/x-lzma': 'lzma',\n  'application/x-lzop': 'lzo',\n  'application/x-mobipocket-ebook': 'mobi',\n  'application/x-msdownload': 'exe',\n  'application/x-perl': 'pl',\n  'application/x-php': 'php',\n  'application/x-rar-compressed': 'rar',\n  'application/x-ruby': 'rb',\n  'application/x-sh': 'sh',\n  'application/x-shellscript': 'sh',\n  'application/x-shockwave-flash': 'swf',\n  'application/x-sql': 'sql',\n  'application/x-stuffit': 'sit',\n  'application/x-tar': 'tar',\n  'application/x-webarchive': 'war',\n  'application/x-xz': 'xz',\n  'application/x-yaml': 'yaml',\n  'application/xhtml+xml': 'xhtml',\n  'application/xml': 'xml',\n  'application/zip': 'zip',\n\n  // Audio types\n  'audio/aac': 'aac',\n  'audio/flac': 'flac',\n  'audio/midi': 'midi',\n  'audio/mp4': 'm4a',\n  'audio/mpeg': 'mp3',\n  'audio/ogg': 'oga',\n  'audio/opus': 'opus',\n  'audio/wav': 'wav',\n  'audio/webm': 'weba',\n  'audio/x-aiff': 'aiff',\n  'audio/x-m4a': 'm4a',\n  'audio/x-midi': 'midi',\n  'audio/x-ms-wma': 'wma',\n  'audio/x-wav': 'wav',\n\n  // Font types\n  'font/otf': 'otf',\n  'font/ttf': 'ttf',\n  'font/woff': 'woff',\n  'font/woff2': 'woff2',\n\n  // Image types\n  'image/apng': 'apng',\n  'image/avif': 'avif',\n  'image/bmp': 'bmp',\n  'image/gif': 'gif',\n  'image/heic': 'heic',\n  'image/heif': 'heif',\n  'image/jpeg': 'jpg',\n  'image/png': 'png',\n  'image/svg+xml': 'svg',\n  'image/tiff': 'tiff',\n  'image/vnd.microsoft.icon': 'ico',\n  'image/webp': 'webp',\n  'image/x-icon': 'ico',\n\n  // Text types\n  'text/calendar': 'ics',\n  'text/css': 'css',\n  'text/csv': 'csv',\n  'text/html': 'html',\n  'text/javascript': 'js',\n  'text/markdown': 'md',\n  'text/plain': 'txt',\n  'text/rtf': 'rtf',\n  'text/rust': 'rs',\n  'text/tab-separated-values': 'tsv',\n  'text/vcard': 'vcf',\n  'text/x-c': 'c',\n  'text/x-c++src': 'cpp',\n  'text/x-csharp': 'cs',\n  'text/x-csrc': 'c',\n  'text/x-diff': 'diff',\n  'text/x-erlang': 'erl',\n  'text/x-go': 'go',\n  'text/x-java': 'java',\n  'text/x-java-source': 'java',\n  'text/x-kotlin': 'kt',\n  'text/x-lua': 'lua',\n  'text/x-markdown': 'md',\n  'text/x-objectivec': 'm',\n  'text/x-pascal': 'pas',\n  'text/x-perl': 'pl',\n  'text/x-python': 'py',\n  'text/x-ruby': 'rb',\n  'text/x-rust': 'rs',\n  'text/x-scala': 'scala',\n  'text/x-sh': 'sh',\n  'text/x-shellscript': 'sh',\n  'text/x-sql': 'sql',\n  'text/x-swift': 'swift',\n  'text/x-typescript': 'ts',\n  'text/x-yaml': 'yaml',\n  'text/xml': 'xml',\n  'text/yaml': 'yaml',\n\n  // Video types\n  'video/3gpp': '3gp',\n  'video/3gpp2': '3g2',\n  'video/mp2t': 'ts',\n  'video/mp4': 'mp4',\n  'video/mpeg': 'mpeg',\n  'video/ogg': 'ogv',\n  'video/quicktime': 'mov',\n  'video/webm': 'webm',\n  'video/x-flv': 'flv',\n  'video/x-m4v': 'm4v',\n  'video/x-matroska': 'mkv',\n  'video/x-ms-wmv': 'wmv',\n  'video/x-msvideo': 'avi',\n};\n","import * as fileIconSet from './FileIconSet';\nimport type { GeneralType, SupportedMimeType } from './mimeTypes';\nimport {\n  archiveFileTypes,\n  codeFileTypes,\n  excelMimeTypes,\n  powerpointMimeTypes,\n  wordMimeTypes,\n} from './mimeTypes';\nimport type { ComponentType } from 'react';\nimport type { BaseFileIconProps } from './FileIconSet';\n\ntype MimeTypeMappedComponent =\n  | 'FilePdfIcon'\n  | 'FileWordIcon'\n  | 'FileExcelIcon'\n  | 'FilePowerPointIcon'\n  | 'FileArchiveIcon'\n  | 'FileCodeIcon';\n\ntype GeneralContentTypeComponent = 'FileAudioIcon' | 'FileVideoIcon' | 'FileAltIcon';\n\ntype IconComponents<Props> = {\n  FileAltIcon: ComponentType<Props>;\n  FileArchiveIcon: ComponentType<Props>;\n  FileAudioIcon: ComponentType<Props>;\n  FileCodeIcon: ComponentType<Props>;\n  FileExcelIcon: ComponentType<Props>;\n  FileFallbackIcon: ComponentType<Props>;\n  FilePdfIcon: ComponentType<Props>;\n  FilePowerPointIcon: ComponentType<Props>;\n  FileVideoIcon: ComponentType<Props>;\n  FileWordIcon: ComponentType<Props>;\n};\n\ntype MimeTypeToIconMap<Props> = {\n  [key: string]: ComponentType<Props>;\n};\n\nfunction generateMimeTypeToIconMap<Props>({\n  FileArchiveIcon,\n  FileCodeIcon,\n  FileExcelIcon,\n  FilePdfIcon,\n  FilePowerPointIcon,\n  FileWordIcon,\n}: Pick<IconComponents<Props>, MimeTypeMappedComponent>) {\n  const mimeTypeToIconMap: MimeTypeToIconMap<Props> = {\n    'application/pdf': FilePdfIcon,\n  };\n\n  for (const type of wordMimeTypes) {\n    mimeTypeToIconMap[type] = FileWordIcon;\n  }\n\n  for (const type of excelMimeTypes) {\n    mimeTypeToIconMap[type] = FileExcelIcon;\n  }\n\n  for (const type of powerpointMimeTypes) {\n    mimeTypeToIconMap[type] = FilePowerPointIcon;\n  }\n\n  for (const type of archiveFileTypes) {\n    mimeTypeToIconMap[type] = FileArchiveIcon;\n  }\n\n  for (const type of codeFileTypes) {\n    mimeTypeToIconMap[type] = FileCodeIcon;\n  }\n  return mimeTypeToIconMap;\n}\n\nfunction generateGeneralTypeToIconMap<Props>({\n  FileAltIcon,\n  FileAudioIcon,\n  FileVideoIcon,\n}: Pick<IconComponents<Props>, GeneralContentTypeComponent>) {\n  return {\n    'audio/': FileAudioIcon,\n    'text/': FileAltIcon,\n    'video/': FileVideoIcon,\n  };\n}\n\ntype IconMap = {\n  standard: Record<\n    SupportedMimeType | GeneralType | 'fallback',\n    ComponentType<BaseFileIconProps>\n  >;\n};\n\nexport const iconMap: IconMap = {\n  standard: {\n    ...generateMimeTypeToIconMap<BaseFileIconProps>({\n      FileArchiveIcon: fileIconSet.FileArchiveIcon,\n      FileCodeIcon: fileIconSet.FileCodeIcon,\n      FileExcelIcon: fileIconSet.FileExcelIcon,\n      FilePdfIcon: fileIconSet.FilePdfIcon,\n      FilePowerPointIcon: fileIconSet.FilePowerPointIcon,\n      FileWordIcon: fileIconSet.FileWordIcon,\n    }),\n    ...generateGeneralTypeToIconMap<BaseFileIconProps>({\n      FileAltIcon: fileIconSet.FileFallbackIcon,\n      FileAudioIcon: fileIconSet.FileAudioIcon,\n      FileVideoIcon: fileIconSet.FileVideoIcon,\n    }),\n    fallback: fileIconSet.FileFallbackIcon,\n  },\n};\n","import React, { useMemo } from 'react';\nimport { iconMap } from './iconMap';\nimport { mergeFileIconSizeConfig } from './FileIconSet';\nimport { mimeTypeToExtensionMap } from './mimeTypes';\nimport type { FileIconSize } from './FileIconSet';\n\nexport type FileIconSizeConfigOverride = Partial<\n  Record<\n    FileIconSize,\n    Partial<{ width: number; height: number; labelX: number; labelY: number }>\n  >\n>;\n\nexport type FileIconProps = {\n  className?: string;\n  fileName?: string;\n  mimeType?: string;\n  /** Override dimensions/label position per size (sm, md, lg, xl). */\n  sizeConfig?: FileIconSizeConfigOverride;\n  size?: FileIconSize;\n};\n\nexport function mimeTypeToIcon(mimeType?: string) {\n  const theMap = iconMap['standard'];\n\n  if (!mimeType) return theMap.fallback;\n\n  const icon = theMap[mimeType];\n  if (icon) return icon;\n\n  if (mimeType.startsWith('audio/')) return theMap['audio/'];\n  if (mimeType.startsWith('video/')) return theMap['video/'];\n  if (mimeType.startsWith('image/')) return theMap['image/'];\n  if (mimeType.startsWith('text/')) return theMap['text/'];\n\n  return theMap.fallback;\n}\n\nconst labelFromMimeType = ({\n  fileName,\n  mimeType,\n}: Pick<FileIconProps, 'fileName' | 'mimeType'>) => {\n  let label;\n\n  if (mimeType) {\n    label = mimeTypeToExtensionMap[mimeType];\n  }\n\n  if (!label && fileName) {\n    label = fileName.split('.').slice(-1)[0];\n  }\n  return label;\n};\n\nexport const FileIcon = (props: FileIconProps) => {\n  const {\n    className,\n    fileName,\n    mimeType,\n    size = 'md',\n    sizeConfig: sizeConfigOverride,\n    ...rest\n  } = props;\n  const sizeConfig = useMemo(\n    () => mergeFileIconSizeConfig(sizeConfigOverride),\n    [sizeConfigOverride],\n  );\n  const Icon = mimeTypeToIcon(mimeType);\n  const label = fileName ? labelFromMimeType({ fileName, mimeType }) : undefined;\n  return (\n    <Icon\n      {...rest}\n      className={className}\n      label={label}\n      size={size}\n      sizeConfig={sizeConfig}\n    />\n  );\n};\n","export const formatTime = (\n  totalSeconds?: number,\n  rounding: 'ceil' | 'floor' = 'ceil',\n) => {\n  if (totalSeconds == null || Number.isNaN(totalSeconds) || totalSeconds < 0) {\n    return null;\n  }\n\n  const roundedSeconds =\n    rounding === 'floor' ? Math.floor(totalSeconds) : Math.ceil(totalSeconds);\n  const hours = Math.floor(roundedSeconds / 3600);\n  const minutes = Math.floor((roundedSeconds % 3600) / 60);\n  const seconds = roundedSeconds % 60;\n  const minSec = `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(\n    2,\n    '0',\n  )}`;\n\n  return hours ? `${String(hours).padStart(2, '0')}:${minSec}` : minSec;\n};\n","import React from 'react';\nimport clsx from 'clsx';\nimport { formatTime } from './formatTime';\n\ntype DurationDisplayProps = {\n  /** Whether audio is currently playing */\n  isPlaying: boolean;\n  /** Optional className for styling */\n  className?: string;\n  /** Total duration in seconds */\n  duration?: number;\n  /** Elapsed time in seconds */\n  secondsElapsed?: number;\n  /** Show remaining time instead of elapsed when possible */\n  showRemaining?: boolean;\n};\n\nexport function DurationDisplay({\n  className,\n  duration,\n  isPlaying,\n  secondsElapsed,\n  showRemaining = false,\n}: DurationDisplayProps) {\n  const remainingSeconds =\n    duration != null && secondsElapsed != null\n      ? Math.max(0, duration - secondsElapsed)\n      : undefined;\n  const formattedDuration = formatTime(duration);\n  const formattedSecondsElapsed = formatTime(secondsElapsed);\n  const formattedRemaining = formatTime(remainingSeconds);\n\n  const shouldShowElapsed =\n    !!secondsElapsed && secondsElapsed > 0 && secondsElapsed < (duration || 0);\n  const canShowRemaining = showRemaining && duration != null && secondsElapsed != null;\n  const primaryValue = showRemaining ? formattedRemaining : formattedSecondsElapsed;\n  const showPrimary = (canShowRemaining || shouldShowElapsed) && !!primaryValue;\n  const showDuration = !showPrimary && !!formattedDuration;\n\n  return (\n    <div\n      className={clsx(\n        'str-chat__duration-display',\n        {\n          'str-chat__duration-display--hasProgress': !!secondsElapsed,\n          'str-chat__duration-display--isPlaying': isPlaying,\n        },\n        className,\n      )}\n    >\n      {showPrimary && (\n        <span className='str-chat__duration-display__time-elapsed'>{primaryValue}</span>\n      )}\n      {showDuration && (\n        <span className='str-chat__duration-display__duration'>{formattedDuration}</span>\n      )}\n    </div>\n  );\n}\n","import React from 'react';\nimport { Button } from '../../Button';\nimport clsx from 'clsx';\n\nexport type PlaybackRateButtonProps = React.ComponentProps<'button'>;\n\nexport const PlaybackRateButton = ({\n  children,\n  className,\n  ...rest\n}: PlaybackRateButtonProps) => (\n  <Button\n    data-testid='playback-rate-button'\n    {...rest}\n    className={clsx('str-chat__playback-rate-button', className)}\n  >\n    {children}\n  </Button>\n);\n","import type { KeyboardEvent } from 'react';\nimport type { SeekFn as AudioPlayerSeekFn } from '../AudioPlayer';\n\ntype SeekParams = Parameters<AudioPlayerSeekFn>[0];\n\nconst DEFAULT_KEYBOARD_PROGRESS_STEP = 5;\nconst DEFAULT_KEYBOARD_PROGRESS_LARGE_STEP = 10;\n\nconst getNextProgressByKey = ({\n  key,\n  largeStep,\n  progress,\n  step,\n}: {\n  key: string;\n  largeStep: number;\n  progress: number;\n  step: number;\n}) => {\n  switch (key) {\n    case 'ArrowRight':\n    case 'ArrowUp':\n      return Math.min(100, progress + step);\n    case 'ArrowLeft':\n    case 'ArrowDown':\n      return Math.max(0, progress - step);\n    case 'PageUp':\n      return Math.min(100, progress + largeStep);\n    case 'PageDown':\n      return Math.max(0, progress - largeStep);\n    case 'Home':\n      return 0;\n    case 'End':\n      return 100;\n    default:\n      return null;\n  }\n};\n\nexport const handleProgressBarKeyboardSeek = ({\n  event,\n  largeStep = DEFAULT_KEYBOARD_PROGRESS_LARGE_STEP,\n  progress,\n  seek,\n  step = DEFAULT_KEYBOARD_PROGRESS_STEP,\n}: {\n  event: KeyboardEvent<HTMLDivElement>;\n  largeStep?: number;\n  progress: number;\n  seek: (params: SeekParams) => void;\n  step?: number;\n}) => {\n  const nextProgress = getNextProgressByKey({\n    key: event.key,\n    largeStep,\n    progress,\n    step,\n  });\n\n  if (nextProgress === null) return;\n\n  event.preventDefault();\n  const currentTarget = event.currentTarget;\n  const { width, x } = currentTarget.getBoundingClientRect();\n\n  seek({\n    clientX: x + (width * nextProgress) / 100,\n    currentTarget,\n  });\n};\n","import type { TFunction } from 'i18next';\nimport { formatTime } from './formatTime';\n\ntype GetAudioTrackSliderAriaValueTextParams = {\n  durationSeconds?: number;\n  progress: number;\n  secondsElapsed?: number;\n  t: TFunction;\n};\n\nexport const getAudioTrackSliderAriaValueText = ({\n  durationSeconds,\n  progress,\n  secondsElapsed,\n  t,\n}: GetAudioTrackSliderAriaValueTextParams) => {\n  const normalizedProgress = Math.max(0, Math.min(100, progress));\n\n  if (typeof durationSeconds === 'number' && Number.isFinite(durationSeconds)) {\n    const normalizedDuration = Math.max(0, durationSeconds);\n    const elapsed =\n      typeof secondsElapsed === 'number' && Number.isFinite(secondsElapsed)\n        ? Math.max(0, Math.min(secondsElapsed, normalizedDuration))\n        : (normalizedDuration * normalizedProgress) / 100;\n    const formattedElapsed = formatTime(elapsed, 'floor');\n    const formattedDuration = formatTime(normalizedDuration, 'floor');\n\n    if (formattedElapsed && formattedDuration) {\n      return t('aria/Audio position {{ elapsed }} of {{ duration }}', {\n        duration: formattedDuration,\n        elapsed: formattedElapsed,\n      });\n    }\n  }\n\n  return t('aria/Audio position {{ progress }} percent', {\n    progress: Math.round(normalizedProgress),\n  });\n};\n","import type { PointerEventHandler } from 'react';\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport type { SeekFn as AudioPlayerSeekFn } from '../AudioPlayer';\n\ntype SeekParams = Parameters<AudioPlayerSeekFn>[0];\n\ntype UseInteractiveProgressBarParams = {\n  progress?: number;\n  seek: (params: SeekParams) => void;\n};\n\nconst getAvailableTrackWidth = (trackRoot: HTMLDivElement | null) => {\n  if (!trackRoot) return 0;\n\n  const parent = trackRoot.parentElement;\n  if (!parent) return trackRoot.getBoundingClientRect().width;\n\n  const parentWidth = parent.getBoundingClientRect().width;\n  const computedStyle = window.getComputedStyle(parent);\n  const paddingLeft = parseFloat(computedStyle.paddingLeft) || 0;\n  const paddingRight = parseFloat(computedStyle.paddingRight) || 0;\n  const rawColumnGap = computedStyle.columnGap || computedStyle.gap;\n  const parsedColumnGap = parseFloat(rawColumnGap);\n  const columnGap = Number.isNaN(parsedColumnGap) ? 0 : parsedColumnGap;\n  const gapCount = Math.max(0, parent.children.length - 1);\n  const totalGapsWidth = columnGap * gapCount;\n  const siblingsWidth = Array.from(parent.children).reduce((total, child) => {\n    if (child === trackRoot) return total;\n    return total + child.getBoundingClientRect().width;\n  }, 0);\n\n  return Math.max(\n    0,\n    parentWidth - paddingLeft - paddingRight - totalGapsWidth - siblingsWidth,\n  );\n};\n\nexport const useInteractiveProgressBar = ({\n  progress = 0,\n  seek,\n}: UseInteractiveProgressBarParams) => {\n  const isDragging = useRef(false);\n  const [availableTrackWidth, setAvailableTrackWidth] = useState(0);\n  const [root, setRoot] = useState<HTMLDivElement | null>(null);\n  const [progressIndicator, setProgressIndicator] = useState<HTMLDivElement | null>(null);\n  const lastIndicatorWidth = useRef(0);\n\n  const handleDragStart: PointerEventHandler<HTMLDivElement> = (e) => {\n    e.preventDefault();\n    if (!progressIndicator) return;\n\n    isDragging.current = true;\n    progressIndicator.style.cursor = 'grabbing';\n    root?.classList.add('str-chat__wave-progress-bar__track--dragging');\n  };\n\n  const handleDrag: PointerEventHandler<HTMLDivElement> = (e) => {\n    if (!isDragging.current) return;\n    // Snapshot the event because seek is throttled.\n    seek({ ...e });\n  };\n\n  const handleDragStop = useCallback(() => {\n    if (!progressIndicator) return;\n\n    isDragging.current = false;\n    progressIndicator.style.removeProperty('cursor');\n    root?.classList.remove('str-chat__wave-progress-bar__track--dragging');\n  }, [progressIndicator, root]);\n\n  useEffect(() => {\n    document.addEventListener('pointerup', handleDragStop);\n\n    return () => {\n      document.removeEventListener('pointerup', handleDragStop);\n    };\n  }, [handleDragStop]);\n\n  useEffect(() => {\n    if (!root || typeof ResizeObserver === 'undefined') return;\n\n    const observer = new ResizeObserver(([entry]) => {\n      const nextAvailableWidth = getAvailableTrackWidth(entry.target as HTMLDivElement);\n      setAvailableTrackWidth(nextAvailableWidth || entry.contentRect.width);\n    });\n\n    observer.observe(root);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [root]);\n\n  useLayoutEffect(() => {\n    if (root) {\n      setAvailableTrackWidth(getAvailableTrackWidth(root));\n    }\n\n    if (progressIndicator) {\n      lastIndicatorWidth.current = progressIndicator.getBoundingClientRect().width;\n    }\n  }, [progressIndicator, root]);\n\n  const indicatorLeft =\n    progress === 0 || !progressIndicator\n      ? 0\n      : Math.max(0, availableTrackWidth - lastIndicatorWidth.current) * (progress / 100) +\n        1;\n\n  return {\n    availableTrackWidth,\n    handleDrag,\n    handleDragStart,\n    handleDragStop,\n    indicatorLeft,\n    root,\n    setProgressIndicator,\n    setRoot,\n  };\n};\n","import clsx from 'clsx';\nimport React from 'react';\nimport { handleProgressBarKeyboardSeek } from './keyboardSeek';\nimport { getAudioTrackSliderAriaValueText } from './progressBarA11y';\nimport { useInteractiveProgressBar } from './useInteractiveProgressBar';\nimport type { SeekFn as AudioPlayerSeekFn } from '../AudioPlayer';\nimport { useTranslationContext } from '../../../context';\n\ntype SeekParams = Parameters<AudioPlayerSeekFn>[0];\n\nexport type ProgressBarProps = {\n  /** Progress expressed in fractional number value btw 0 and 100. */\n  progress: number;\n  /** Total track duration in seconds. */\n  durationSeconds?: number;\n  /** Current elapsed position in seconds. */\n  secondsElapsed?: number;\n  seek: (params: SeekParams) => void;\n} & Pick<React.ComponentProps<'div'>, 'className'>;\n\nexport const ProgressBar = ({\n  className,\n  durationSeconds,\n  progress,\n  secondsElapsed,\n  seek,\n}: ProgressBarProps) => {\n  const { t } = useTranslationContext('ProgressBar');\n  const {\n    handleDrag,\n    handleDragStart,\n    handleDragStop,\n    indicatorLeft,\n    setProgressIndicator,\n    setRoot,\n  } = useInteractiveProgressBar({ progress, seek });\n  const normalizedProgress = Math.max(0, Math.min(100, progress));\n  const ariaValueText = getAudioTrackSliderAriaValueText({\n    durationSeconds,\n    progress: normalizedProgress,\n    secondsElapsed,\n    t,\n  });\n\n  return (\n    <div\n      aria-label={t('aria/Seek audio position')}\n      aria-orientation='horizontal'\n      aria-valuemax={100}\n      aria-valuemin={0}\n      aria-valuenow={Math.round(normalizedProgress)}\n      aria-valuetext={ariaValueText}\n      className={clsx(\n        'str-chat__message-attachment-audio-widget--progress-track',\n        className,\n      )}\n      data-progress={normalizedProgress}\n      data-testid='audio-progress'\n      onClick={seek}\n      onKeyDown={(event) =>\n        handleProgressBarKeyboardSeek({ event, progress: normalizedProgress, seek })\n      }\n      onPointerDown={handleDragStart}\n      onPointerMove={handleDrag}\n      onPointerUp={handleDragStop}\n      ref={setRoot}\n      role='slider'\n      style={\n        {\n          '--str-chat__message-attachment-audio-widget-progress':\n            normalizedProgress + '%',\n        } as React.CSSProperties\n      }\n      tabIndex={0}\n    >\n      <div\n        aria-hidden='true'\n        className='str-chat__message-attachment-audio-widget--progress-indicator'\n        ref={setProgressIndicator}\n        style={{ insetInlineStart: `${indicatorLeft}px` }}\n      />\n    </div>\n  );\n};\n","import type { ReactNode } from 'react';\nimport type { Attachment, SharedLocationResponse } from 'stream-chat';\nimport type { ATTACHMENT_GROUPS_ORDER, AttachmentProps } from './Attachment';\nimport * as linkify from 'linkifyjs';\n\nexport const SUPPORTED_VIDEO_FORMATS = [\n  'video/mp4',\n  'video/ogg',\n  'video/webm',\n  'video/quicktime',\n];\n\nexport type AttachmentComponentType =\n  | 'card'\n  | 'gallery'\n  | 'giphy'\n  | 'image'\n  | 'media'\n  | 'audio'\n  | 'voiceRecording'\n  | 'file'\n  | 'geolocation'\n  | 'unsupported';\n\nexport type AttachmentContainerType = (typeof ATTACHMENT_GROUPS_ORDER)[number];\n\nexport type GroupedRenderedAttachment = Record<AttachmentContainerType, ReactNode[]>;\n\nexport type GalleryAttachment = {\n  items: Attachment[];\n  type: 'gallery';\n};\n\nexport type RenderAttachmentProps = Omit<AttachmentProps, 'attachments'> & {\n  attachment: Attachment;\n};\n\nexport type RenderGalleryProps = Omit<AttachmentProps, 'attachments'> & {\n  attachment: GalleryAttachment;\n};\n\nexport type RenderMediaProps = Omit<AttachmentProps, 'attachments'> & {\n  attachments: Attachment[];\n};\n\nexport type GeolocationContainerProps = Omit<AttachmentProps, 'attachments'> & {\n  location: SharedLocationResponse;\n};\n\n// This identity function determines attachment type specific to React.\n// Once made sure other SDKs support the same logic, move to stream-chat-js\nexport const isGalleryAttachmentType = (\n  attachment: Attachment | GalleryAttachment,\n): attachment is GalleryAttachment =>\n  Array.isArray((attachment as GalleryAttachment).items);\n\nexport const isSvgAttachment = (attachment: Attachment) => {\n  const filename = attachment.fallback || '';\n  return filename.toLowerCase().endsWith('.svg');\n};\n\nexport const divMod = (num: number, divisor: number) => [\n  Math.floor(num / divisor),\n  num % divisor,\n];\n\nexport const displayDuration = (totalSeconds?: number) => {\n  if (!totalSeconds || totalSeconds < 0) return '00:00';\n\n  const [hours, hoursLeftover] = divMod(totalSeconds, 3600);\n  const [minutes, seconds] = divMod(hoursLeftover, 60);\n  const roundedSeconds = Math.ceil(seconds);\n  const prependHrsZero = String(hours).padStart(2, '0');\n  const prependMinZero = String(minutes).padStart(2, '0');\n  const prependSecZero = String(roundedSeconds).padStart(2, '0');\n  const minSec = `${prependMinZero}:${prependSecZero}`;\n\n  return hours ? `${prependHrsZero}:` + minSec : minSec;\n};\nexport function getCssDimensionsVariables(url: string) {\n  const cssVars = {\n    '--original-height': 1000000,\n    '--original-width': 1000000,\n  } as Record<string, number>;\n\n  if (linkify.test(url, 'url')) {\n    const urlParams = new URL(url).searchParams;\n    const oh = Number(urlParams.get('oh'));\n    const ow = Number(urlParams.get('ow'));\n    const originalHeight = oh > 1 ? oh : 1000000;\n    const originalWidth = ow > 1 ? ow : 1000000;\n    cssVars['--original-width'] = originalWidth;\n    cssVars['--original-height'] = originalHeight;\n  }\n\n  return cssVars;\n}\n","import { divMod } from './utils';\n\nexport const resampleWaveformData = (waveformData: number[], amplitudesCount: number) =>\n  waveformData.length === amplitudesCount\n    ? waveformData\n    : waveformData.length > amplitudesCount\n      ? downSample(waveformData, amplitudesCount)\n      : upSample(waveformData, amplitudesCount);\n\n/**\n * The downSample function uses the Largest-Triangle-Three-Buckets (LTTB) algorithm.\n * See the thesis Downsampling Time Series for Visual Representation by Sveinn Steinarsson for more (https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf)\n * @param data\n * @param targetOutputSize\n */\nexport function downSample(data: number[], targetOutputSize: number): number[] {\n  if (data.length <= targetOutputSize || targetOutputSize === 0) {\n    return data;\n  }\n\n  if (targetOutputSize === 1) return [mean(data)];\n\n  const result: number[] = [];\n  // bucket size adjusted due to the fact that the first and the last item in the original data array is kept in target output\n  const bucketSize = (data.length - 2) / (targetOutputSize - 2);\n  let lastSelectedPointIndex = 0;\n  result.push(data[lastSelectedPointIndex]); // Always add the first point\n  let maxAreaPoint, maxArea, triangleArea;\n\n  for (let bucketIndex = 1; bucketIndex < targetOutputSize - 1; bucketIndex++) {\n    const previousBucketRefPoint = data[lastSelectedPointIndex];\n    const nextBucketMean = getNextBucketMean(data, bucketIndex, bucketSize);\n\n    const currentBucketStartIndex = Math.floor((bucketIndex - 1) * bucketSize) + 1;\n    const nextBucketStartIndex = Math.floor(bucketIndex * bucketSize) + 1;\n    const countUnitsBetweenAtoC = 1 + nextBucketStartIndex - currentBucketStartIndex;\n\n    maxArea = triangleArea = -1;\n\n    for (\n      let currentPointIndex = currentBucketStartIndex;\n      currentPointIndex < nextBucketStartIndex;\n      currentPointIndex++\n    ) {\n      const countUnitsBetweenAtoB =\n        Math.abs(currentPointIndex - currentBucketStartIndex) + 1;\n      const countUnitsBetweenBtoC = countUnitsBetweenAtoC - countUnitsBetweenAtoB;\n      const currentPointValue = data[currentPointIndex];\n\n      triangleArea = triangleAreaHeron(\n        triangleBase(\n          Math.abs(previousBucketRefPoint - currentPointValue),\n          countUnitsBetweenAtoB,\n        ),\n        triangleBase(Math.abs(currentPointValue - nextBucketMean), countUnitsBetweenBtoC),\n        triangleBase(\n          Math.abs(previousBucketRefPoint - nextBucketMean),\n          countUnitsBetweenAtoC,\n        ),\n      );\n\n      if (triangleArea > maxArea) {\n        maxArea = triangleArea;\n        maxAreaPoint = data[currentPointIndex];\n        lastSelectedPointIndex = currentPointIndex;\n      }\n    }\n\n    if (typeof maxAreaPoint !== 'undefined') result.push(maxAreaPoint);\n  }\n\n  result.push(data[data.length - 1]); // Always add the last point\n\n  return result;\n}\n\nconst triangleAreaHeron = (a: number, b: number, c: number) => {\n  const s = (a + b + c) / 2;\n  return Math.sqrt(s * (s - a) * (s - b) * (s - c));\n};\nconst triangleBase = (a: number, b: number) => Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));\nconst mean = (values: number[]) =>\n  values.reduce((acc, value) => acc + value, 0) / values.length;\nconst getNextBucketMean = (\n  data: number[],\n  currentBucketIndex: number,\n  bucketSize: number,\n) => {\n  const nextBucketStartIndex = Math.floor(currentBucketIndex * bucketSize) + 1;\n  let nextNextBucketStartIndex = Math.floor((currentBucketIndex + 1) * bucketSize) + 1;\n  nextNextBucketStartIndex =\n    nextNextBucketStartIndex < data.length ? nextNextBucketStartIndex : data.length;\n\n  return mean(data.slice(nextBucketStartIndex, nextNextBucketStartIndex));\n};\nexport const upSample = (values: number[], targetSize: number) => {\n  if (!values.length) {\n    console.warn('Cannot extend empty array of amplitudes.');\n    return values;\n  }\n\n  if (values.length > targetSize) {\n    console.warn(\n      'Requested to extend the waveformData that is longer than the target list size',\n    );\n    return values;\n  }\n\n  if (targetSize === values.length) return values;\n\n  // eslint-disable-next-line prefer-const\n  let [bucketSize, remainder] = divMod(targetSize, values.length);\n  const result: number[] = [];\n\n  for (let i = 0; i < values.length; i++) {\n    const extra = remainder && remainder-- ? 1 : 0;\n    result.push(...Array(bucketSize + extra).fill(values[i]));\n  }\n  return result;\n};\n","import throttle from 'lodash.throttle';\nimport React, { useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport clsx from 'clsx';\nimport { resampleWaveformData } from '../../Attachment/audioSampling';\nimport type { SeekFn as AudioPlayerSeekFn } from '../AudioPlayer';\nimport { handleProgressBarKeyboardSeek } from './keyboardSeek';\nimport { getAudioTrackSliderAriaValueText } from './progressBarA11y';\nimport { useInteractiveProgressBar } from './useInteractiveProgressBar';\nimport { useTranslationContext } from '../../../context';\n\ntype SeekParams = Parameters<AudioPlayerSeekFn>[0];\n\ntype WaveProgressBarProps = {\n  /** Function that allows to change the track progress */\n  seek: (params: SeekParams) => void;\n  /** The array of fractional number values between 0 and 1 representing the height of amplitudes */\n  waveformData: number[];\n  /** Progress expressed in fractional number value btw 0 and 100. */\n  progress?: number;\n  /** Total track duration in seconds. */\n  durationSeconds?: number;\n  /** Current elapsed position in seconds. */\n  secondsElapsed?: number;\n  /** Absolute gap width between bars in px (overrides computed gap var). */\n  amplitudeBarGapWidthPx?: number;\n  relativeAmplitudeBarWidth?: number;\n  relativeAmplitudeGap?: number;\n};\n\nexport const WaveProgressBar = ({\n  amplitudeBarGapWidthPx,\n  durationSeconds,\n  progress = 0,\n  relativeAmplitudeBarWidth = 2,\n  relativeAmplitudeGap = 1,\n  secondsElapsed,\n  seek,\n  waveformData,\n}: WaveProgressBarProps) => {\n  const { t } = useTranslationContext('WaveProgressBar');\n  const [trackAxisX, setTrackAxisX] = useState<{\n    barCount: number;\n    barWidth: number;\n    gap: number;\n  }>();\n  const lastAvailableTrackWidth = useRef<number>(0);\n  const minAmplitudeBarWidthRef = useRef<number | null>(null);\n  const lastMinAmplitudeBarWidthUsed = useRef<number | null>(null);\n  const {\n    availableTrackWidth,\n    handleDrag,\n    handleDragStart,\n    handleDragStop,\n    indicatorLeft,\n    root,\n    setProgressIndicator,\n    setRoot,\n  } = useInteractiveProgressBar({ progress, seek });\n  const normalizedProgress = Math.max(0, Math.min(100, progress));\n\n  const getTrackAxisX = useMemo(\n    () =>\n      throttle((availableWidth: number) => {\n        const minAmplitudeBarWidth = minAmplitudeBarWidthRef.current;\n        const hasMinWidthChanged =\n          minAmplitudeBarWidth !== lastMinAmplitudeBarWidthUsed.current;\n        if (availableWidth === lastAvailableTrackWidth.current && !hasMinWidthChanged) {\n          return;\n        }\n        lastAvailableTrackWidth.current = availableWidth;\n        lastMinAmplitudeBarWidthUsed.current = minAmplitudeBarWidth;\n        const possibleAmpCount = Math.floor(\n          availableWidth / (relativeAmplitudeGap + relativeAmplitudeBarWidth),\n        );\n        const amplitudeBarWidthToGapRatio =\n          relativeAmplitudeBarWidth / (relativeAmplitudeBarWidth + relativeAmplitudeGap);\n        const maxCountByMinWidth =\n          typeof minAmplitudeBarWidth === 'number' && minAmplitudeBarWidth > 0\n            ? Math.floor(\n                (availableWidth * amplitudeBarWidthToGapRatio) / minAmplitudeBarWidth,\n              )\n            : possibleAmpCount;\n        const barCount = Math.max(0, Math.min(possibleAmpCount, maxCountByMinWidth));\n        const barWidth =\n          barCount && (availableWidth / barCount) * amplitudeBarWidthToGapRatio;\n\n        setTrackAxisX({\n          barCount,\n          barWidth,\n          gap: barWidth * (relativeAmplitudeGap / relativeAmplitudeBarWidth),\n        });\n      }, 1),\n    [relativeAmplitudeBarWidth, relativeAmplitudeGap],\n  );\n\n  const resampledWaveformData = useMemo(\n    () => (trackAxisX ? resampleWaveformData(waveformData, trackAxisX.barCount) : []),\n    [trackAxisX, waveformData],\n  );\n\n  useLayoutEffect(() => {\n    if (availableTrackWidth > 0) {\n      getTrackAxisX(availableTrackWidth);\n    }\n  }, [availableTrackWidth, getTrackAxisX]);\n\n  useLayoutEffect(() => {\n    if (!root || typeof window === 'undefined') return;\n    const amplitudeBar = root.querySelector<HTMLElement>(\n      '.str-chat__wave-progress-bar__amplitude-bar',\n    );\n    if (!amplitudeBar) return;\n    const computedStyle = window.getComputedStyle(amplitudeBar);\n    const parsedMinWidth = parseFloat(computedStyle.minWidth);\n    if (!Number.isNaN(parsedMinWidth) && parsedMinWidth > 0) {\n      minAmplitudeBarWidthRef.current = parsedMinWidth;\n    }\n    if (availableTrackWidth > 0) {\n      getTrackAxisX(availableTrackWidth);\n    }\n  }, [availableTrackWidth, getTrackAxisX, root, trackAxisX?.barCount]);\n\n  if (!waveformData.length || trackAxisX?.barCount === 0) return null;\n\n  const amplitudeGapWidth = amplitudeBarGapWidthPx ?? trackAxisX?.gap;\n  const ariaValueText = getAudioTrackSliderAriaValueText({\n    durationSeconds,\n    progress: normalizedProgress,\n    secondsElapsed,\n    t,\n  });\n\n  return (\n    <div\n      aria-label={t('aria/Seek audio position')}\n      aria-orientation='horizontal'\n      aria-valuemax={100}\n      aria-valuemin={0}\n      aria-valuenow={Math.round(normalizedProgress)}\n      aria-valuetext={ariaValueText}\n      className={clsx('str-chat__wave-progress-bar__track', {\n        'str-chat__wave-progress-bar__track--playback-initiated': normalizedProgress > 0,\n      })}\n      data-testid='wave-progress-bar-track'\n      onClick={seek}\n      onKeyDown={(event) =>\n        handleProgressBarKeyboardSeek({ event, progress: normalizedProgress, seek })\n      }\n      onPointerDown={handleDragStart}\n      onPointerMove={handleDrag}\n      onPointerUp={handleDragStop}\n      ref={setRoot}\n      role='slider'\n      style={\n        {\n          '--str-chat__voice-recording-amplitude-bar-gap-width':\n            typeof amplitudeGapWidth === 'number' ? `${amplitudeGapWidth}px` : undefined,\n        } as React.CSSProperties\n      }\n      tabIndex={0}\n    >\n      {resampledWaveformData.map((amplitude, i) => (\n        <div\n          aria-hidden='true'\n          className={clsx('str-chat__wave-progress-bar__amplitude-bar', {\n            ['str-chat__wave-progress-bar__amplitude-bar--active']:\n              normalizedProgress > (i / resampledWaveformData.length) * 100,\n          })}\n          data-testid='amplitude-bar'\n          key={`amplitude-${i}`}\n          style={\n            {\n              '--str-chat__voice-recording-amplitude-bar-width':\n                trackAxisX?.barWidth + 'px',\n              '--str-chat__wave-progress-bar__amplitude-bar-height': amplitude\n                ? amplitude * 100 + '%'\n                : '0%',\n            } as React.CSSProperties\n          }\n        />\n      ))}\n      <div\n        aria-hidden='true'\n        className='str-chat__wave-progress-bar__progress-indicator'\n        data-testid='wave-progress-bar-progress-indicator'\n        ref={setProgressIndicator}\n        style={{\n          insetInlineStart: `${indicatorLeft}px`,\n        }}\n      />\n    </div>\n  );\n};\n","import React from 'react';\nimport type { Attachment } from 'stream-chat';\n\nimport {\n  FileSizeIndicator as DefaultFileSizeIndicator,\n  DownloadButton,\n} from './components';\nimport type { AudioPlayerState } from '../AudioPlayback/AudioPlayer';\nimport { useAudioPlayer } from '../AudioPlayback/WithAudioPlayback';\nimport { useStateStore } from '../../store';\nimport { useComponentContext, useMessageContext } from '../../context';\nimport type { AudioPlayer } from '../AudioPlayback/AudioPlayer';\nimport { PlayButton } from '../Button/PlayButton';\nimport { FileIcon } from '../FileIcon';\nimport { DurationDisplay, ProgressBar } from '../AudioPlayback';\n\ntype AudioAttachmentUIProps = {\n  audioPlayer: AudioPlayer;\n};\n\n// todo: finish creating a BaseAudioPlayer derived from VoiceRecordingPlayerUI and AudioAttachmentUI\nconst AudioAttachmentUI = ({ audioPlayer }: AudioAttachmentUIProps) => {\n  const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();\n  const dataTestId = 'audio-widget';\n  const rootClassName = 'str-chat__message-attachment-audio-widget';\n\n  const { durationSeconds, isPlaying, progress, secondsElapsed } =\n    useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};\n\n  return (\n    <div className={rootClassName} data-testid={dataTestId}>\n      <div className='str-chat__message-attachment-audio-widget--play-controls'>\n        <PlayButton isPlaying={!!isPlaying} onClick={audioPlayer.togglePlay} />\n      </div>\n      <div className='str-chat__message-attachment-audio-widget--data'>\n        <div className='str-chat__message-attachment-audio-widget--text-first-row'>\n          <div className='str-chat__message-attachment-audio-widget--title'>\n            {audioPlayer.title}\n          </div>\n        </div>\n        <div className='str-chat__message-attachment-audio-widget--text-second-row'>\n          {durationSeconds ? (\n            <>\n              <DurationDisplay\n                duration={durationSeconds}\n                isPlaying={!!isPlaying}\n                secondsElapsed={secondsElapsed}\n              />\n              <ProgressBar\n                durationSeconds={durationSeconds}\n                progress={progress ?? 0}\n                secondsElapsed={secondsElapsed}\n                seek={audioPlayer.seek}\n              />\n            </>\n          ) : (\n            <>\n              <FileSizeIndicator fileSize={audioPlayer.fileSize} />\n              <ProgressBar\n                durationSeconds={durationSeconds}\n                progress={progress ?? 0}\n                secondsElapsed={secondsElapsed}\n                seek={audioPlayer.seek}\n              />\n            </>\n          )}\n        </div>\n      </div>\n      <FileIcon className='str-chat__file-icon' mimeType={audioPlayer.mimeType} />\n      <DownloadButton assetUrl={audioPlayer.src} suggestedFileName={audioPlayer.title} />\n    </div>\n  );\n};\n\nexport type AudioProps = {\n  attachment: Attachment;\n};\n\nconst audioPlayerStateSelector = (state: AudioPlayerState) => ({\n  durationSeconds: state.durationSeconds,\n  isPlaying: state.isPlaying,\n  progress: state.progressPercent,\n  secondsElapsed: state.secondsElapsed,\n});\n\n/**\n * Audio attachment with play/pause button and progress bar\n */\nexport const Audio = (props: AudioProps) => {\n  const {\n    attachment: { asset_url, duration, file_size, mime_type, title },\n  } = props;\n\n  /**\n   * Introducing message context. This could be breaking change, therefore the fallback to {} is provided.\n   * If this component is used outside the message context, then there will be no audio player namespacing\n   * => scrolling away from the message in virtualized ML would create a new AudioPlayer instance.\n   *\n   * Edge case: the requester (message) has multiple attachments with the same assetURL - does not happen\n   * with the default SDK components, but can be done with custom API calls.In this case all the Audio\n   * widgets will share the state.\n   */\n  const { message, threadList } = useMessageContext() ?? {};\n\n  const audioPlayer = useAudioPlayer({\n    durationSeconds: duration,\n    fileSize: file_size,\n    mimeType: mime_type,\n    requester:\n      message?.id &&\n      `${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,\n    src: asset_url,\n    title,\n    waveformData: props.attachment.waveform_data,\n  });\n\n  return audioPlayer ? <AudioAttachmentUI audioPlayer={audioPlayer} /> : null;\n};\n","import React, { useEffect, useMemo, useRef } from 'react';\nimport type { Action, Attachment } from 'stream-chat';\n\nimport { useTranslationContext } from '../../context';\n\nimport type { ActionHandlerReturnType } from '../Message/hooks/useActionHandler';\nimport { Button } from '../Button';\nimport clsx from 'clsx';\n\nexport type AttachmentActionsProps = Attachment & {\n  /** A list of actions */\n  actions: Action[];\n  /** Unique id for action button key. Key is generated by concatenating this id with action value - {`${id}-${action.value}`} */\n  id: string;\n  /** The text for the form input */\n  text: string;\n  /** Click event handler */\n  actionHandler?: ActionHandlerReturnType;\n  /** Which action should be focused on initial render (match by action.value) */\n  defaultFocusedActionValue?: string;\n};\n\nexport type AttachmentActionsDefaultFocusByType = Partial<\n  Record<NonNullable<Attachment['type']>, string>\n>;\n\nexport const defaultAttachmentActionsDefaultFocus: AttachmentActionsDefaultFocusByType = {\n  giphy: 'send',\n};\n\nconst UnMemoizedAttachmentActions = (props: AttachmentActionsProps) => {\n  const { actionHandler, actions, defaultFocusedActionValue, id, text } = props;\n  const { t } = useTranslationContext('UnMemoizedAttachmentActions');\n  const buttonRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n  const handleActionClick = (\n    event: React.MouseEvent<HTMLButtonElement, MouseEvent>,\n    name?: string,\n    value?: string,\n  ) => actionHandler?.(name, value, event);\n\n  const knownActionText = useMemo<Record<string, string>>(\n    () => ({\n      Cancel: t('Cancel'),\n      Send: t('Send'),\n      Shuffle: t('Shuffle'),\n    }),\n    [t],\n  );\n\n  const focusIndex = useMemo(() => {\n    if (!defaultFocusedActionValue) return null;\n    const index = actions.findIndex(\n      (action) => action.value === defaultFocusedActionValue,\n    );\n    return index >= 0 ? index : null;\n  }, [actions, defaultFocusedActionValue]);\n\n  useEffect(() => {\n    if (focusIndex === null) return;\n    const button = buttonRefs.current[focusIndex];\n    if (button && document.activeElement !== button) {\n      button.focus();\n    }\n  }, [focusIndex]);\n\n  return (\n    <div className='str-chat__message-attachment-actions'>\n      <div className='str-chat__message-attachment-actions-form'>\n        <span>{text}</span>\n        {actions.map((action, index) => (\n          <Button\n            appearance='ghost'\n            className={clsx(\n              `str-chat__message-attachment-actions-button str-chat__message-attachment-actions-button--${action.style}`,\n            )}\n            data-testid={`${action.name}`}\n            data-value={action.value}\n            key={`${id}-${action.value}`}\n            onClick={(event) => handleActionClick(event, action.name, action.value)}\n            ref={(element) => {\n              buttonRefs.current[index] = element;\n            }}\n            variant='secondary'\n          >\n            {action.text ? (knownActionText[action.text] ?? t(action.text)) : null}\n          </Button>\n        ))}\n      </div>\n    </div>\n  );\n};\n\n/**\n * A component for rendering the actions you can take on an attachment.\n */\nexport const AttachmentActions = React.memo(\n  UnMemoizedAttachmentActions,\n) as typeof UnMemoizedAttachmentActions;\n","import React from 'react';\nimport type { Attachment } from 'stream-chat';\n\nimport { FileSizeIndicator as DefaultFileSizeIndicator } from './components';\nimport { FileIcon } from '../FileIcon';\nimport {\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\nimport {\n  type AudioPlayer,\n  type AudioPlayerState,\n  DurationDisplay,\n  PlaybackRateButton,\n  WaveProgressBar,\n} from '../AudioPlayback';\nimport { useAudioPlayer } from '../AudioPlayback/WithAudioPlayback';\nimport { useStateStore } from '../../store';\nimport { PlayButton } from '../Button';\n\nconst rootClassName = 'str-chat__message-attachment__voice-recording-widget';\n\nconst audioPlayerStateSelector = (state: AudioPlayerState) => ({\n  canPlayRecord: state.canPlayRecord,\n  durationSeconds: state.durationSeconds,\n  isPlaying: state.isPlaying,\n  playbackRate: state.currentPlaybackRate,\n  progress: state.progressPercent,\n  secondsElapsed: state.secondsElapsed,\n});\n\ntype VoiceRecordingPlayerUIProps = {\n  audioPlayer: AudioPlayer;\n};\n\n// todo: finish creating a BaseAudioPlayer derived from VoiceRecordingPlayerUI and AudioAttachmentUI\nconst VoiceRecordingPlayerUI = ({ audioPlayer }: VoiceRecordingPlayerUIProps) => {\n  const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();\n  const { t } = useTranslationContext();\n  const {\n    canPlayRecord,\n    durationSeconds,\n    isPlaying,\n    playbackRate,\n    progress,\n    secondsElapsed,\n  } = useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};\n\n  return (\n    <div className={rootClassName} data-testid='voice-recording-widget'>\n      <div className='str-chat__message-attachment__voice-recording-widget__play-button-container'>\n        <PlayButton isPlaying={!!isPlaying} onClick={audioPlayer.togglePlay} />\n      </div>\n      <div className='str-chat__message-attachment__voice-recording-widget__metadata'>\n        <div className='str-chat__message-attachment__voice-recording-widget__audio-state'>\n          <div className='str-chat__message-attachment__voice-recording-widget__timer'>\n            {durationSeconds ? (\n              <DurationDisplay\n                duration={durationSeconds}\n                isPlaying={!!isPlaying}\n                secondsElapsed={secondsElapsed}\n                showRemaining\n              />\n            ) : (\n              <FileSizeIndicator\n                fileSize={audioPlayer.fileSize}\n                maximumFractionDigits={0}\n              />\n            )}\n          </div>\n          <WaveProgressBar\n            durationSeconds={durationSeconds}\n            progress={progress}\n            secondsElapsed={secondsElapsed}\n            seek={audioPlayer.seek}\n            waveformData={audioPlayer.waveformData || []}\n          />\n        </div>\n      </div>\n      <div className='str-chat__message-attachment__voice-recording-widget__right-section'>\n        <PlaybackRateButton\n          aria-label={t('Playback speed {{ rate }}x', {\n            rate: playbackRate?.toString() ?? '1',\n          })}\n          disabled={!canPlayRecord}\n          onClick={audioPlayer.increasePlaybackRate}\n        >\n          x{playbackRate?.toString()}\n        </PlaybackRateButton>\n      </div>\n    </div>\n  );\n};\n\nexport type VoiceRecordingPlayerProps = Pick<VoiceRecordingProps, 'attachment'> & {\n  /** An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0) */\n  playbackRates?: number[];\n};\n\nexport const VoiceRecordingPlayer = ({\n  attachment,\n  playbackRates,\n}: VoiceRecordingPlayerProps) => {\n  const { t } = useTranslationContext();\n  const {\n    asset_url,\n    duration = 0,\n    file_size,\n    mime_type,\n    title = t('Voice message'),\n    waveform_data,\n  } = attachment;\n\n  /**\n   * Introducing message context. This could be breaking change, therefore the fallback to {} is provided.\n   * If this component is used outside the message context, then there will be no audio player namespacing\n   * => scrolling away from the message in virtualized ML would create a new AudioPlayer instance.\n   *\n   * Edge case: the requester (message) has multiple attachments with the same assetURL - does not happen\n   * with the default SDK components, but can be done with custom API calls.In this case all the Audio\n   * widgets will share the state.\n   */\n  const { message, threadList } = useMessageContext() ?? {};\n\n  const audioPlayer = useAudioPlayer({\n    durationSeconds: duration ?? 0,\n    fileSize: file_size,\n    mimeType: mime_type,\n    playbackRates,\n    requester:\n      message?.id &&\n      `${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,\n    src: asset_url,\n    title,\n    waveformData: waveform_data,\n  });\n\n  return audioPlayer ? <VoiceRecordingPlayerUI audioPlayer={audioPlayer} /> : null;\n};\n\nexport type QuotedVoiceRecordingProps = Pick<VoiceRecordingProps, 'attachment'>;\n\nexport const QuotedVoiceRecording = ({ attachment }: QuotedVoiceRecordingProps) => {\n  const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();\n  return (\n    <div className={rootClassName} data-testid='quoted-voice-recording-widget'>\n      <div className='str-chat__message-attachment__voice-recording-widget__metadata'>\n        <div className='str-chat__message-attachment__voice-recording-widget__audio-state'>\n          <div className='str-chat__message-attachment__voice-recording-widget__timer'>\n            {attachment.duration ? (\n              <DurationDisplay\n                duration={attachment.duration}\n                isPlaying={false}\n                secondsElapsed={undefined}\n              />\n            ) : (\n              <FileSizeIndicator\n                fileSize={attachment.file_size}\n                maximumFractionDigits={0}\n              />\n            )}\n          </div>\n        </div>\n      </div>\n      <FileIcon mimeType={attachment.mime_type} />\n    </div>\n  );\n};\n\nexport type VoiceRecordingProps = {\n  /** The attachment object from the message's attachment list. */\n  attachment: Attachment;\n  /** A boolean flag to signal whether the attachment will be rendered inside the quoted reply. */\n  isQuoted?: boolean;\n};\n\nexport const VoiceRecording = ({ attachment, isQuoted }: VoiceRecordingProps) =>\n  isQuoted ? (\n    <QuotedVoiceRecording attachment={attachment} />\n  ) : (\n    <VoiceRecordingPlayer attachment={attachment} />\n  );\n","import React from 'react';\nimport clsx from 'clsx';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { IconImage } from '../Icons';\n\nexport type ImagePlaceholderProps = {\n  className?: string;\n};\n\nexport const ImagePlaceholder = ({ className }: ImagePlaceholderProps) => {\n  const { t } = useTranslationContext();\n  return (\n    <div\n      aria-label={t('aria/Image failed to load')}\n      className={clsx('str-chat__image-placeholder', className)}\n      data-testid='str-chat__base-image-placeholder'\n      role='img'\n    >\n      <IconImage />\n    </div>\n  );\n};\n","import React, { forwardRef, useEffect, useMemo, useState } from 'react';\nimport clsx from 'clsx';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { DownloadButton } from '../Attachment';\nimport { ImagePlaceholder as DefaultImagePlaceholder } from './ImagePlaceholder';\nimport { sanitizeUrl } from '@braintree/sanitize-url';\n\nexport type BaseImageProps = React.ComponentPropsWithRef<'img'> & {\n  showDownloadButtonOnError?: boolean;\n};\n\nexport const BaseImage = forwardRef<HTMLImageElement, BaseImageProps>(function BaseImage(\n  { src, ...props },\n  ref,\n) {\n  const {\n    alt: propsAlt,\n    className: propsClassName,\n    onError: propsOnError,\n    showDownloadButtonOnError = false,\n    ...imgProps\n  } = props;\n  // Store the failed URL rather than a boolean so that when src changes (e.g. retry\n  // with a cache-busting param), the error state clears synchronously via the derived\n  // `error` check below. A boolean would require a useEffect to reset, causing a\n  // 1-frame flash of the error placeholder before the loading state kicks in.\n  const [failedSrc, setFailedSrc] = useState<string | null>(null);\n  const { ImagePlaceholder: ImagePlaceholderComponent = DefaultImagePlaceholder } =\n    useComponentContext();\n\n  const sanitizedUrl = useMemo(() => sanitizeUrl(src), [src]);\n  const error = failedSrc === sanitizedUrl;\n\n  useEffect(\n    () => () => {\n      setFailedSrc(null);\n    },\n    [sanitizedUrl],\n  );\n\n  if (error) {\n    return (\n      <>\n        <ImagePlaceholderComponent\n          className={clsx(propsClassName, 'str-chat__base-image--load-failed')}\n        />\n        {showDownloadButtonOnError && <DownloadButton assetUrl={sanitizedUrl} />}\n      </>\n    );\n  }\n\n  return (\n    <img\n      data-testid='str-chat__base-image'\n      {...imgProps}\n      alt={propsAlt ?? ''}\n      className={clsx(propsClassName, 'str-chat__base-image')}\n      onError={(e) => {\n        setFailedSrc(sanitizedUrl);\n        propsOnError?.(e);\n      }}\n      ref={ref}\n      src={sanitizedUrl}\n    />\n  );\n});\n","import {\n  type Attachment,\n  isGiphyAttachment,\n  isImageAttachment,\n  isLocalImageAttachment,\n  isLocalVideoAttachment,\n  isScrapedContent,\n  isVideoAttachment,\n  type LinkPreview,\n  type LocalImageAttachment,\n  type LocalVideoAttachment,\n} from 'stream-chat';\nimport type { Dimensions } from '../../types/types';\n\ntype AttachmentPreviewableInGallery =\n  | LocalImageAttachment\n  | LocalVideoAttachment\n  | LinkPreview\n  | Attachment;\n\n/** Fields shared with gallery items for image/video preview from an attachment. */\nexport type BaseImageDescriptor = {\n  alt?: string;\n  dimensions?: Dimensions;\n  imageUrl?: string;\n  title?: string;\n  videoThumbnailUrl?: string;\n  videoUrl?: string;\n};\n\n/**\n * Maps an attachment (or link preview) to image/video URLs and metadata for {@link BaseImage} or the gallery.\n */\nexport const toBaseImageDescriptors = (\n  attachment: AttachmentPreviewableInGallery,\n  options: { giphyVersionName?: string } = {},\n): BaseImageDescriptor | undefined => {\n  if (isGiphyAttachment(attachment)) {\n    const giphyVersion =\n      options?.giphyVersionName && attachment.giphy\n        ? attachment.giphy[\n            options.giphyVersionName as keyof NonNullable<Attachment['giphy']>\n          ]\n        : undefined;\n\n    return {\n      alt: giphyVersion?.url || attachment.thumb_url,\n      dimensions: giphyVersion\n        ? {\n            height: giphyVersion.height,\n            width: giphyVersion.width,\n          }\n        : undefined,\n      imageUrl: attachment.thumb_url,\n      title: attachment.title || attachment.thumb_url,\n    };\n  }\n\n  if (isScrapedContent(attachment)) {\n    const imageUrl = attachment.image_url || attachment.thumb_url;\n    return {\n      alt: attachment.title || imageUrl,\n      imageUrl,\n      title: attachment.title,\n    };\n  }\n\n  if (isLocalVideoAttachment(attachment)) {\n    return {\n      title: attachment.title,\n      videoThumbnailUrl: attachment.thumb_url ?? attachment.localMetadata.previewUri,\n      videoUrl: attachment.asset_url ?? attachment.localMetadata.previewUri,\n    };\n  }\n\n  if (isVideoAttachment(attachment)) {\n    return {\n      title: attachment.title,\n      videoThumbnailUrl: attachment.thumb_url,\n      videoUrl: attachment.asset_url,\n    };\n  }\n\n  if (isLocalImageAttachment(attachment)) {\n    const imageUrl = attachment.image_url || attachment.localMetadata.previewUri;\n    return {\n      alt: attachment.title || imageUrl,\n      imageUrl,\n      title: attachment.title,\n    };\n  }\n\n  if (isImageAttachment(attachment)) {\n    const imageUrl = attachment.image_url;\n    return {\n      alt: attachment.title || imageUrl,\n      imageUrl,\n      title: attachment.title,\n    };\n  }\n\n  return undefined;\n};\n","import { createContext, useContext } from 'react';\n\nimport { toBaseImageDescriptors } from '../BaseImage';\nimport type { BaseImageProps } from '../BaseImage';\nimport type { Dimensions } from '../../types/types';\n\nexport type GalleryItem = Omit<BaseImageProps, 'src'> & {\n  dimensions?: Dimensions;\n  imageUrl?: string;\n  videoThumbnailUrl?: string;\n  videoUrl?: string;\n};\n\n/**\n * Maps an attachment (or link preview) to gallery item fields.\n * Delegates to {@link toBaseImageDescriptors}.\n */\nexport const toGalleryItemDescriptors = (\n  ...args: Parameters<typeof toBaseImageDescriptors>\n):\n  | Pick<\n      GalleryItem,\n      'alt' | 'dimensions' | 'imageUrl' | 'title' | 'videoThumbnailUrl' | 'videoUrl'\n    >\n  | undefined => toBaseImageDescriptors(...args);\n\nexport type GalleryContextValue = {\n  /** Whether clicking the empty gallery background should request close */\n  closeOnBackgroundClick: boolean;\n  /** Currently displayed item index */\n  currentIndex: number;\n  /** Currently displayed item */\n  currentItem: GalleryItem;\n  /** Navigate to a specific index */\n  goToIndex: (index: number) => void;\n  /** Navigate to the next item */\n  goToNext: () => void;\n  /** Navigate to the previous item */\n  goToPrevious: () => void;\n  /** Whether there is a next item */\n  hasNext: boolean;\n  /** Whether there is a previous item */\n  hasPrevious: boolean;\n  /** Total number of items */\n  itemCount: number;\n  /** All items in the gallery */\n  items: GalleryItem[];\n  /** Request closing the gallery viewer */\n  onRequestClose?: () => void;\n};\n\nexport const GalleryContext = createContext<GalleryContextValue | undefined>(undefined);\n\nexport const useGalleryContext = () => {\n  const contextValue = useContext(GalleryContext);\n\n  if (!contextValue) {\n    console.warn(\n      `The useGalleryContext hook was called outside of the GalleryContext provider. Make sure this hook is called within a child of the Gallery component.`,\n    );\n\n    return {} as GalleryContextValue;\n  }\n\n  return contextValue;\n};\n","import React, { useContext, useMemo } from 'react';\nimport { sanitizeUrl } from '@braintree/sanitize-url';\n\nimport { type GalleryItem } from './GalleryContext';\nimport { Button } from '../Button';\nimport { IconArrowDownCircle, IconXmark } from '../Icons';\nimport { MessageTimestamp as DefaultMessageTimestamp } from '../Message/MessageTimestamp';\nimport {\n  ModalContext,\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\n\ntype GalleryHeaderProps = {\n  currentItem: GalleryItem;\n};\n\nexport const GalleryHeader = ({ currentItem }: GalleryHeaderProps) => {\n  const { t } = useTranslationContext();\n  const { MessageTimestamp = DefaultMessageTimestamp } = useComponentContext('GalleryUI');\n  const { isMyMessage, message } = useMessageContext('GalleryUI');\n  const modalContext = useContext(ModalContext);\n\n  const headerTitle =\n    (isMyMessage?.() && t('You')) ||\n    message?.user?.name ||\n    message?.user?.id ||\n    currentItem.title ||\n    t('User uploaded content');\n  const downloadUrl = useMemo(() => {\n    const rawDownloadUrl = currentItem.videoUrl ?? currentItem.imageUrl;\n\n    if (!rawDownloadUrl) return undefined;\n\n    const sanitizedUrl = sanitizeUrl(rawDownloadUrl);\n\n    return sanitizedUrl === 'about:blank' ? undefined : sanitizedUrl;\n  }, [currentItem.imageUrl, currentItem.videoUrl]);\n  const downloadLabel = t('aria/Download attachment');\n\n  return (\n    <div className='str-chat__gallery__header'>\n      <div aria-hidden='true' className='str-chat__gallery__header-spacer' />\n      <div className='str-chat__gallery__header-meta'>\n        <div className='str-chat__gallery__title'>{headerTitle}</div>\n        {message?.created_at ? (\n          <MessageTimestamp customClass='str-chat__gallery__timestamp' />\n        ) : null}\n      </div>\n      <div className='str-chat__gallery__header-actions'>\n        {downloadUrl ? (\n          <a\n            aria-label={downloadLabel}\n            className='str-chat__gallery__action-button str-chat__gallery__action-button--download'\n            download\n            href={downloadUrl}\n            rel='noreferrer'\n            target='_blank'\n            title={downloadLabel}\n          >\n            <IconArrowDownCircle />\n          </a>\n        ) : null}\n        {modalContext?.close ? (\n          <Button\n            aria-label={t('Close')}\n            className='str-chat__gallery__action-button str-chat__gallery__action-button--close'\n            onClick={modalContext.close}\n            title={t('Close')}\n          >\n            <IconXmark />\n          </Button>\n        ) : null}\n      </div>\n    </div>\n  );\n};\n","import React from 'react';\n\nimport { useComponentContext } from '../../context';\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../Loading/LoadingIndicator';\n\n// `react-player` (~2 MB) is loaded lazily so it stays out of the SDK's eager\n// import graph; the consumer's bundler emits it as a separate chunk that is\n// fetched only when a default video player renders. Consumers who override\n// `VideoPlayer` via `ComponentContext` never load it at all.\nconst ReactPlayer = React.lazy(() => import('./ReactPlayerWrapper'));\n\nexport type VideoPlayerProps = {\n  isPlaying?: boolean;\n  videoUrl?: string;\n  thumbnailUrl?: string;\n};\n\nexport const VideoPlayer = ({ isPlaying, thumbnailUrl, videoUrl }: VideoPlayerProps) => {\n  const { LoadingIndicator = DefaultLoadingIndicator, VideoPlayer: VideoPlayerContext } =\n    useComponentContext();\n\n  return VideoPlayerContext ? (\n    <VideoPlayerContext thumbnailUrl={thumbnailUrl} videoUrl={videoUrl} />\n  ) : (\n    <React.Suspense\n      fallback={\n        <div className='str-chat__video-player-loading'>\n          <LoadingIndicator />\n        </div>\n      }\n    >\n      <ReactPlayer\n        isPlaying={isPlaying}\n        thumbnailUrl={thumbnailUrl}\n        videoUrl={videoUrl}\n      />\n    </React.Suspense>\n  );\n};\n","import { BaseImage, type BaseImageProps } from '../BaseImage';\nimport { Button } from '../Button';\nimport clsx from 'clsx';\nimport { IconPlayFill } from '../Icons';\nimport React from 'react';\nimport { useTranslationContext } from '../../context';\n\nexport type VideoThumbnailProps = BaseImageProps & {\n  onPlay?: () => void;\n};\n\nexport const VideoThumbnail = ({\n  className,\n  onPlay,\n  ...imageProps\n}: VideoThumbnailProps) => {\n  const { t } = useTranslationContext();\n\n  return (\n    <div className='str-chat__message-attachment__video-thumbnail'>\n      <BaseImage\n        className={clsx('str-chat__message-attachment__video-thumbnail-image', className)}\n        {...imageProps}\n      />\n      {onPlay ? (\n        <Button\n          appearance='solid'\n          aria-label={t('Play video')}\n          circular\n          className={clsx(\n            'str-chat__message-attachment__video-thumbnail__play-indicator',\n          )}\n          onClick={onPlay}\n          size='lg'\n          variant='secondary'\n        >\n          <IconPlayFill />\n        </Button>\n      ) : (\n        <div className='str-chat__message-attachment__video-thumbnail__play-indicator'>\n          <IconPlayFill />\n        </div>\n      )}\n    </div>\n  );\n};\n","import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';\n\nimport { BaseImage } from '../BaseImage';\nimport { GalleryHeader } from './GalleryHeader';\nimport { useGalleryContext } from './GalleryContext';\nimport { Button, type ButtonProps } from '../Button';\nimport { IconChevronLeft, IconChevronRight } from '../Icons';\nimport { ModalContext, useTranslationContext } from '../../context';\nimport { VideoPlayer } from '../VideoPlayer';\nimport { VideoThumbnail } from '../VideoPlayer/VideoThumbnail';\n\nimport clsx from 'clsx';\n\nconst SWIPE_THRESHOLD = 50;\nconst TRANSITION_DURATION = 300;\n\nexport const GalleryUI = () => {\n  const { t } = useTranslationContext();\n  const {\n    closeOnBackgroundClick,\n    currentIndex,\n    currentItem,\n    goToNext,\n    goToPrevious,\n    hasNext,\n    hasPrevious,\n    itemCount,\n    onRequestClose,\n  } = useGalleryContext();\n  const modalContext = useContext(ModalContext);\n\n  const [showVideo, setShowVideo] = useState(false);\n\n  // Slide transition state\n  const isTransitioningRef = useRef(false);\n  const [slideOffset, setSlideOffset] = useState(0);\n  const [isDragging, setIsDragging] = useState(false);\n  const [slideDirection, setSlideDirection] = useState<'forward' | 'backward' | null>(\n    null,\n  );\n\n  // Touch tracking refs\n  // Some touch interactions on the slide container are followed by a click; suppress\n  // that one-shot click so swipe navigation doesn't immediately trigger background close.\n  const ignoreNextClickRef = useRef(false);\n  const touchStartRef = useRef<{ x: number; y: number } | null>(null);\n  const isVerticalSwipeRef = useRef(false);\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  // Reset video play state when navigating to a new item\n  useEffect(() => {\n    setShowVideo(false);\n  }, [currentIndex]);\n\n  // Slide animation on index change\n  const prevIndexRef = useRef(currentIndex);\n  useEffect(() => {\n    if (prevIndexRef.current === currentIndex) return;\n    const direction = currentIndex > prevIndexRef.current ? 'forward' : 'backward';\n    setSlideDirection(direction);\n    setSlideOffset(0);\n    setIsDragging(false);\n    isTransitioningRef.current = true;\n\n    const timer = setTimeout(() => {\n      setSlideDirection(null);\n      isTransitioningRef.current = false;\n    }, TRANSITION_DURATION);\n\n    prevIndexRef.current = currentIndex;\n    return () => clearTimeout(timer);\n  }, [currentIndex]);\n\n  // Wrapped navigation functions that respect transition lock\n  const handleGoToNext = useCallback(() => {\n    if (isTransitioningRef.current) return;\n    goToNext();\n  }, [goToNext]);\n\n  const handleGoToPrevious = useCallback(() => {\n    if (isTransitioningRef.current) return;\n    goToPrevious();\n  }, [goToPrevious]);\n\n  // Keyboard navigation\n  const handleKeyDown = useCallback(\n    (event: KeyboardEvent) => {\n      if (event.key === 'ArrowLeft') {\n        event.preventDefault();\n        handleGoToPrevious();\n      } else if (event.key === 'ArrowRight') {\n        event.preventDefault();\n        handleGoToNext();\n      }\n    },\n    [handleGoToNext, handleGoToPrevious],\n  );\n\n  useEffect(() => {\n    document.addEventListener('keydown', handleKeyDown);\n    return () => document.removeEventListener('keydown', handleKeyDown);\n  }, [handleKeyDown]);\n\n  // Touch event handlers\n  const handleTouchStart = useCallback((event: React.TouchEvent) => {\n    if (isTransitioningRef.current) return;\n    const touch = event.touches[0];\n    ignoreNextClickRef.current = false;\n    touchStartRef.current = { x: touch.clientX, y: touch.clientY };\n    isVerticalSwipeRef.current = false;\n  }, []);\n\n  const handleTouchMove = useCallback(\n    (event: React.TouchEvent) => {\n      if (!touchStartRef.current || isTransitioningRef.current) return;\n\n      const touch = event.touches[0];\n      const deltaX = touch.clientX - touchStartRef.current.x;\n      const deltaY = touch.clientY - touchStartRef.current.y;\n\n      // Determine swipe direction on first significant movement\n      if (!isDragging && !isVerticalSwipeRef.current) {\n        if (Math.abs(deltaY) > Math.abs(deltaX) && Math.abs(deltaY) > 10) {\n          ignoreNextClickRef.current = true;\n          isVerticalSwipeRef.current = true;\n          return;\n        }\n        if (Math.abs(deltaX) > 10) {\n          ignoreNextClickRef.current = true;\n          setIsDragging(true);\n        }\n      }\n\n      if (isVerticalSwipeRef.current) return;\n\n      // Constrain drag when at boundaries\n      if ((!hasNext && deltaX < 0) || (!hasPrevious && deltaX > 0)) {\n        setSlideOffset(deltaX * 0.3); // Rubber-band effect\n      } else {\n        setSlideOffset(deltaX);\n      }\n    },\n    [isDragging, hasNext, hasPrevious],\n  );\n\n  const handleTouchEnd = useCallback(() => {\n    if (!touchStartRef.current || isVerticalSwipeRef.current) {\n      if (isVerticalSwipeRef.current) ignoreNextClickRef.current = true;\n      touchStartRef.current = null;\n      return;\n    }\n\n    const offset = slideOffset;\n    if (isDragging || Math.abs(offset) > 10) {\n      ignoreNextClickRef.current = true;\n    }\n    touchStartRef.current = null;\n\n    if (Math.abs(offset) >= SWIPE_THRESHOLD) {\n      if (offset < 0 && hasNext) {\n        goToNext();\n      } else if (offset > 0 && hasPrevious) {\n        goToPrevious();\n      } else {\n        // Snap back — at boundary\n        setSlideOffset(0);\n      }\n    } else {\n      // Snap back — below threshold\n      setSlideOffset(0);\n    }\n\n    setIsDragging(false);\n  }, [slideOffset, hasNext, hasPrevious, goToNext, goToPrevious, isDragging]);\n\n  const requestClose = modalContext?.close ?? onRequestClose;\n  const handleBackgroundClick = useCallback(\n    (event: React.MouseEvent<HTMLDivElement>) => {\n      if (event.target !== event.currentTarget) return;\n\n      if (ignoreNextClickRef.current) {\n        ignoreNextClickRef.current = false;\n        return;\n      }\n\n      if (!closeOnBackgroundClick) return;\n\n      requestClose?.();\n    },\n    [closeOnBackgroundClick, requestClose],\n  );\n\n  const mediaStyle: React.CSSProperties =\n    isDragging || (slideOffset !== 0 && slideDirection === null)\n      ? { transform: `translateX(${slideOffset}px)` }\n      : {};\n\n  return (\n    <div className='str-chat__gallery'>\n      <div className='str-chat__gallery__main'>\n        <GalleryHeader currentItem={currentItem} />\n        <NavButton\n          aria-label={t('Previous image')}\n          className={clsx(\n            'str-chat__gallery__nav-button--prev',\n            !hasPrevious && 'str-chat__gallery__nav-button--hidden',\n          )}\n          disabled={!hasPrevious}\n          onClick={handleGoToPrevious}\n        >\n          <IconChevronLeft />\n        </NavButton>\n        <div\n          className='str-chat__gallery__slide-container'\n          onClick={handleBackgroundClick}\n          onTouchEnd={handleTouchEnd}\n          onTouchMove={handleTouchMove}\n          onTouchStart={handleTouchStart}\n          ref={containerRef}\n        >\n          <div\n            className={clsx('str-chat__gallery__media-container', {\n              'str-chat__gallery__media--dragging': isDragging,\n              'str-chat__gallery__media--slide-backward':\n                !isDragging && slideDirection === 'backward',\n              'str-chat__gallery__media--slide-forward':\n                !isDragging && slideDirection === 'forward',\n            })}\n            style={mediaStyle}\n          >\n            {currentItem.videoUrl && currentItem.videoThumbnailUrl ? (\n              <div className='str-chat__gallery__media str-chat__gallery__media--video'>\n                {showVideo ? (\n                  <VideoPlayer isPlaying videoUrl={currentItem.videoUrl} />\n                ) : (\n                  <VideoThumbnail\n                    alt={currentItem.title ?? ''}\n                    onPlay={() => setShowVideo(true)}\n                    src={currentItem.videoThumbnailUrl}\n                  />\n                )}\n              </div>\n            ) : (\n              <div className='str-chat__gallery__media str-chat__gallery__media--image'>\n                <BaseImage alt={currentItem.alt} src={currentItem.imageUrl} />\n              </div>\n            )}\n          </div>\n        </div>\n        <NavButton\n          aria-label={t('Next image')}\n          className={clsx(\n            'str-chat__gallery__nav-button--next',\n            !hasNext && 'str-chat__gallery__nav-button--hidden',\n          )}\n          disabled={!hasNext}\n          onClick={handleGoToNext}\n        >\n          <IconChevronRight />\n        </NavButton>\n      </div>\n      {itemCount > 1 && (\n        <div className='str-chat__gallery__position-indicator'>\n          {currentIndex + 1} of {itemCount}\n        </div>\n      )}\n    </div>\n  );\n};\n\nconst NavButton = ({ className, ...props }: ButtonProps) => (\n  <Button {...props} className={clsx('str-chat__gallery__nav-button', className)} />\n);\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { GalleryContext } from './GalleryContext';\nimport { GalleryUI as DefaultGalleryUI } from './GalleryUI';\nimport { useComponentContext } from '../../context';\n\nimport type { GalleryContextValue, GalleryItem } from './GalleryContext';\n\nexport type GalleryProps = {\n  /** Whether clicking the empty gallery background should request close (default: true) */\n  closeOnBackgroundClick?: boolean;\n  /** Array of media attachments to display */\n  items: GalleryItem[];\n  /** Custom UI component to replace the default GalleryUI */\n  GalleryUI?: React.ComponentType;\n  /** Initial index of the item to display (default: 0) */\n  initialIndex?: number;\n  /** Callback when the active item changes */\n  onIndexChange?: (index: number) => void;\n  /** Callback invoked when the gallery requests to close */\n  onRequestClose?: () => void;\n};\n\nexport const Gallery = ({\n  closeOnBackgroundClick = true,\n  GalleryUI,\n  initialIndex = 0,\n  items,\n  onIndexChange,\n  onRequestClose,\n}: GalleryProps) => {\n  const { GalleryUI: ContextGalleryUI } = useComponentContext();\n  const ResolvedGalleryUI = GalleryUI ?? ContextGalleryUI ?? DefaultGalleryUI;\n  const [currentIndex, setCurrentIndex] = useState(initialIndex);\n\n  const itemCount = items.length;\n\n  const goToIndex = useCallback(\n    (index: number) => {\n      if (index >= 0 && index < itemCount) {\n        setCurrentIndex(index);\n      }\n    },\n    [itemCount],\n  );\n\n  const goToNext = useCallback(() => {\n    setCurrentIndex((prev) => (prev < itemCount - 1 ? prev + 1 : prev));\n  }, [itemCount]);\n\n  const goToPrevious = useCallback(() => {\n    setCurrentIndex((prev) => (prev > 0 ? prev - 1 : prev));\n  }, []);\n\n  useEffect(() => {\n    onIndexChange?.(currentIndex);\n  }, [currentIndex, onIndexChange]);\n\n  const hasNext = currentIndex < itemCount - 1;\n  const hasPrevious = currentIndex > 0;\n  const currentItem = items[currentIndex];\n\n  const contextValue = useMemo<GalleryContextValue>(\n    () => ({\n      closeOnBackgroundClick,\n      currentIndex,\n      currentItem,\n      goToIndex,\n      goToNext,\n      goToPrevious,\n      hasNext,\n      hasPrevious,\n      itemCount,\n      items,\n      onRequestClose,\n    }),\n    [\n      closeOnBackgroundClick,\n      currentIndex,\n      currentItem,\n      goToIndex,\n      goToNext,\n      goToPrevious,\n      hasNext,\n      hasPrevious,\n      itemCount,\n      items,\n      onRequestClose,\n    ],\n  );\n\n  return (\n    <GalleryContext.Provider value={contextValue}>\n      <ResolvedGalleryUI />\n    </GalleryContext.Provider>\n  );\n};\n","import React, { useCallback, useState } from 'react';\nimport clsx from 'clsx';\n\nimport type { BaseImageProps } from '../BaseImage';\nimport type { GalleryItem } from '../Gallery/GalleryContext';\nimport { BaseImage as DefaultBaseImage } from '../BaseImage';\nimport { Gallery as DefaultGallery, GalleryUI } from '../Gallery';\nimport { LoadingIndicator } from '../Loading';\nimport { GlobalModal, type ModalCloseSource } from '../Modal';\nimport { useComponentContext, useTranslationContext } from '../../context';\nimport { IconRetry } from '../Icons';\nimport { VideoThumbnail } from '../VideoPlayer/VideoThumbnail';\n\nconst MAX_VISIBLE_THUMBNAILS = 4;\nconst BASE_IMAGE_PROP_KEYS = [\n  'className',\n  'crossOrigin',\n  'decoding',\n  'draggable',\n  'fetchPriority',\n  'height',\n  'loading',\n  'onError',\n  'onLoad',\n  'ref',\n  'showDownloadButtonOnError',\n  'sizes',\n  'srcSet',\n  'style',\n  'title',\n  'useMap',\n  'width',\n] as const satisfies ReadonlyArray<keyof Omit<BaseImageProps, 'src'>>;\ntype BaseImagePropsWithoutSrc = Omit<BaseImageProps, 'src'>;\ntype PartialBaseImagePropMap = Partial<\n  Record<(typeof BASE_IMAGE_PROP_KEYS)[number], unknown>\n>;\n\nexport type ModalGalleryProps = {\n  /** Array of media attachments to display */\n  items: GalleryItem[];\n  className?: string;\n  /** Whether clicking the empty gallery background should close the modal (default: true) */\n  closeOnBackgroundClick?: boolean;\n  modalClassName?: string;\n};\n\nexport const ModalGallery = ({\n  className,\n  closeOnBackgroundClick = true,\n  items,\n  modalClassName,\n}: ModalGalleryProps) => {\n  const {\n    BaseImage = DefaultBaseImage,\n    Gallery = DefaultGallery,\n    Modal = GlobalModal,\n  } = useComponentContext();\n  const [modalOpen, setModalOpen] = useState(false);\n  const [selectedIndex, setSelectedIndex] = useState(0);\n  const usesDefaultBaseImage = BaseImage === DefaultBaseImage;\n\n  const closeModal = useCallback(() => {\n    setModalOpen(false);\n  }, []);\n  const preventOverlayClose = useCallback(\n    (source: ModalCloseSource) => source !== 'overlay',\n    [],\n  );\n\n  const handleThumbnailClick = useCallback((index: number) => {\n    setSelectedIndex(index);\n    setModalOpen(true);\n  }, []);\n\n  const itemCount = items.length;\n  const visibleItems = items.slice(0, MAX_VISIBLE_THUMBNAILS);\n  const overflowCount = itemCount - MAX_VISIBLE_THUMBNAILS;\n\n  return (\n    <>\n      <div\n        className={clsx('str-chat__modal-gallery', className, {\n          'str-chat__modal-gallery--three-images': itemCount === 3,\n          'str-chat__modal-gallery--two-images': itemCount === 2,\n        })}\n      >\n        {visibleItems.map((item, index) => {\n          const isLastVisible = index === MAX_VISIBLE_THUMBNAILS - 1;\n          const showOverlay = isLastVisible && overflowCount > 0;\n\n          return (\n            <ThumbnailButton\n              BaseImage={BaseImage}\n              baseImageUsesDefaultBehavior={usesDefaultBaseImage}\n              index={index}\n              item={item}\n              itemCount={itemCount}\n              key={index}\n              onClick={() => handleThumbnailClick(index)}\n              overflowCount={overflowCount}\n              showOverlay={showOverlay}\n            />\n          );\n        })}\n      </div>\n      <Modal\n        className={clsx('str-chat__gallery-modal', modalClassName)}\n        onClose={closeModal}\n        onCloseAttempt={preventOverlayClose}\n        open={modalOpen}\n      >\n        <Gallery\n          closeOnBackgroundClick={closeOnBackgroundClick}\n          GalleryUI={GalleryUI}\n          initialIndex={selectedIndex}\n          items={items}\n          onRequestClose={closeModal}\n        />\n      </Modal>\n    </>\n  );\n};\n\ntype ThumbnailButtonProps = {\n  BaseImage: React.ComponentType<BaseImageProps>;\n  baseImageUsesDefaultBehavior: boolean;\n  index: number;\n  item: GalleryItem;\n  itemCount: number;\n  onClick: () => void;\n  overflowCount: number;\n  showOverlay: boolean;\n};\n\nconst ThumbnailButton = ({\n  BaseImage,\n  baseImageUsesDefaultBehavior,\n  index,\n  item,\n  itemCount,\n  onClick,\n  overflowCount,\n  showOverlay,\n}: ThumbnailButtonProps) => {\n  const { t } = useTranslationContext();\n  const imageUrl = item.imageUrl;\n  const [isLoadFailed, setIsLoadFailed] = useState(false);\n  const [isImageLoading, setIsImageLoading] = useState(Boolean(imageUrl));\n  // Cache-busting suffix appended to image src on retry. Using a suffix instead of\n  // a React key remount keeps the component (and its placeholder) mounted, preventing\n  // layout shifts and height collapse during the reload attempt.\n  const [retrySuffix, setRetrySuffix] = useState('');\n\n  const {\n    onError: itemOnError,\n    onLoad: itemOnLoad,\n    ...baseImageProps\n  } = getBaseImageProps(item);\n  const showRetryIndicator = isLoadFailed && !showOverlay;\n  const showLoadingIndicator = isImageLoading && !showRetryIndicator && !showOverlay;\n\n  const handleButtonClick = () => {\n    if (showRetryIndicator) {\n      setIsLoadFailed(false);\n      setIsImageLoading(true);\n      setRetrySuffix(`&retry=${Date.now()}`);\n      return;\n    }\n\n    onClick();\n  };\n\n  const buttonLabel = showRetryIndicator\n    ? t('aria/Retry upload')\n    : itemCountAwareLabel({ imageIndex: index + 1, itemCount, t });\n\n  return (\n    <button\n      aria-label={buttonLabel}\n      className={clsx('str-chat__modal-gallery__image', {\n        'str-chat__modal-gallery__image--load-failed': showRetryIndicator,\n        'str-chat__modal-gallery__image--loading': showLoadingIndicator,\n      })}\n      onClick={handleButtonClick}\n      type='button'\n    >\n      {item.videoThumbnailUrl ? (\n        <VideoThumbnail alt={t('User uploaded content')} src={item.videoThumbnailUrl} />\n      ) : (\n        <BaseImage\n          {...baseImageProps}\n          alt={item.alt ?? t('User uploaded content')}\n          onError={(event) => {\n            setIsImageLoading(false);\n            setIsLoadFailed(true);\n            itemOnError?.(event);\n          }}\n          onLoad={(event) => {\n            setIsImageLoading(false);\n            setIsLoadFailed(false);\n            itemOnLoad?.(event);\n          }}\n          src={imageUrl ? `${imageUrl}${retrySuffix}` : imageUrl}\n          {...(baseImageUsesDefaultBehavior ? { showDownloadButtonOnError: false } : {})}\n        />\n      )}\n      {showLoadingIndicator && (\n        <div\n          aria-hidden='true'\n          className='str-chat__modal-gallery__image-loading-overlay'\n          data-testid='str-chat__modal-gallery__image-loading-overlay'\n        >\n          <LoadingIndicator />\n        </div>\n      )}\n      {showRetryIndicator && (\n        <div\n          aria-hidden='true'\n          className='str-chat__modal-gallery__image-load-failed-overlay'\n          data-testid='str-chat__modal-gallery__image-load-failed-overlay'\n        >\n          <div className='str-chat__modal-gallery__image-retry-indicator'>\n            <IconRetry />\n          </div>\n        </div>\n      )}\n      {showOverlay && (\n        <div className='str-chat__modal-gallery__placeholder'>+{overflowCount}</div>\n      )}\n    </button>\n  );\n};\n\nconst itemCountAwareLabel = ({\n  imageIndex,\n  itemCount,\n  t,\n}: {\n  imageIndex: number;\n  itemCount: number;\n  t: ReturnType<typeof useTranslationContext>['t'];\n}) =>\n  itemCount === 1\n    ? t('Open image in gallery')\n    : t('Open gallery at image {{ index }}', {\n        index: imageIndex,\n      });\n\nconst getBaseImageProps = (item: GalleryItem): BaseImagePropsWithoutSrc => {\n  const baseImageProps: PartialBaseImagePropMap = {};\n  for (const key of BASE_IMAGE_PROP_KEYS) {\n    const value = item[key];\n    if (value !== undefined) {\n      baseImageProps[key] = value;\n    }\n  }\n\n  return baseImageProps as BaseImagePropsWithoutSrc;\n};\n","import React from 'react';\nimport { ModalGallery as DefaultModalGallery } from './ModalGallery';\nimport { useComponentContext } from '../../context';\nimport type { GalleryItem } from '../Gallery/GalleryContext';\n\nexport type ImageProps = GalleryItem;\n\n/**\n * Display image with tap-to-expand modal gallery.\n */\nexport const ImageComponent = (galleryItem: ImageProps) => {\n  const { ModalGallery = DefaultModalGallery } = useComponentContext();\n\n  return <ModalGallery items={[galleryItem]} modalClassName='str-chat__image-modal' />;\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport { sanitizeUrl } from '@braintree/sanitize-url';\n\n/**\n * Similar to a regular anchor tag, but it sanitizes the href value and prevents XSS\n */\nexport type SafeAnchorProps = {\n  /** Set the className for the anchor tag element */\n  className?: string;\n  /** Specifies that the target (href attribute) will be downloaded instead of navigating to a file */\n  download?: boolean;\n  /** Set the href attribute for the anchor tag element */\n  href?: string;\n  /** Set the rel attribute for the anchor tag element */\n  rel?: string;\n  /** Set the target attribute for the anchor tag element */\n  target?: string;\n};\n\nconst UnMemoizedSafeAnchor = (props: PropsWithChildren<SafeAnchorProps>) => {\n  const { children, className, download, href, rel, target } = props;\n  if (!href) return null;\n  const sanitized = sanitizeUrl(href);\n  return (\n    <a\n      className={className}\n      download={download}\n      href={sanitized}\n      rel={rel}\n      target={target}\n    >\n      {children}\n    </a>\n  );\n};\n\nexport const SafeAnchor = React.memo(UnMemoizedSafeAnchor) as typeof UnMemoizedSafeAnchor;\n","import type { Attachment } from 'stream-chat';\nimport { useTranslationContext } from '../../../context';\nimport clsx from 'clsx';\nimport React from 'react';\n\nexport const UnableToRenderCard = ({ type }: { type?: Attachment['type'] }) => {\n  const { t } = useTranslationContext('Card');\n\n  return (\n    <div\n      className={clsx('str-chat__message-attachment-card', {\n        [`str-chat__message-attachment-card--${type}`]: type,\n      })}\n    >\n      <div className='str-chat__message-attachment-card--content'>\n        <div className='str-chat__message-attachment-card--text'>\n          {t('this content could not be displayed')}\n        </div>\n      </div>\n    </div>\n  );\n};\n","import React from 'react';\nimport { BaseImage } from '../../BaseImage';\nimport { SafeAnchor } from '../../SafeAnchor';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\n\nimport type { Attachment } from 'stream-chat';\nimport type { RenderAttachmentProps } from '../utils';\nimport type { Dimensions } from '../../../types/types';\nimport { IconLink } from '../../Icons';\nimport { UnableToRenderCard } from './UnableToRenderCard';\nimport clsx from 'clsx';\n\ntype CardRootProps = {\n  cardUrl: string | undefined;\n  children: React.ReactNode;\n  type?: CardProps['type'];\n};\n\nconst CardRoot = ({ cardUrl, children, type }: CardRootProps) => {\n  const className = clsx(\n    `str-chat__message-attachment-card str-chat__message-attachment-card--${type}`,\n  );\n\n  return cardUrl ? (\n    <SafeAnchor\n      className={className}\n      href={cardUrl}\n      rel='noopener noreferrer'\n      target='_blank'\n    >\n      {children}\n    </SafeAnchor>\n  ) : (\n    <div className={className}>{children}</div>\n  );\n};\n\ntype CardHeaderProps = Pick<CardProps, 'title' | 'type' | 'image_url' | 'thumb_url'> & {\n  dimensions: Dimensions;\n  image?: string;\n};\n\nconst CardHeader = (props: CardHeaderProps) => {\n  const { dimensions, image, image_url, thumb_url, title } = props;\n\n  return image ? (\n    <div\n      className='str-chat__message-attachment-card--header str-chat__message-attachment-card-react--header'\n      data-testid={'card-header'}\n    >\n      <BaseImage\n        alt={title || image}\n        data-testid='image-test'\n        src={image_url ?? thumb_url}\n        title={title || image}\n        {...dimensions}\n      />\n    </div>\n  ) : null;\n};\n\ntype CardContentProps = RenderAttachmentProps['attachment'];\n\nconst CardContent = (props: CardContentProps) => {\n  const { og_scrape_url, text, title, title_link } = props;\n  const url = title_link || og_scrape_url;\n\n  return (\n    <div className='str-chat__message-attachment-card--content'>\n      {title && <div className='str-chat__message-attachment-card--title'>{title}</div>}\n      {text && <div className='str-chat__message-attachment-card--text'>{text}</div>}\n      {url && (\n        <div\n          className='str-chat__message-attachment-card--source-link'\n          data-testid='card-source-link'\n        >\n          <IconLink />\n          <div className='str-chat__message-attachment-card--url'>{url}</div>\n        </div>\n      )}\n    </div>\n  );\n};\n\nexport type CardProps = RenderAttachmentProps['attachment'] & {\n  compact?: boolean;\n};\n\nconst UnMemoizedCard = (props: CardProps) => {\n  const { giphy, image_url, og_scrape_url, thumb_url, title, title_link, type } = props;\n  const { giphyVersion: giphyVersionName } = useChannelStateContext('');\n  const cardUrl = title_link || og_scrape_url;\n\n  let image = thumb_url || image_url;\n  const dimensions: { height?: string; width?: string } = {};\n\n  if (type === 'giphy' && typeof giphy !== 'undefined') {\n    const giphyVersion =\n      giphy[giphyVersionName as keyof NonNullable<Attachment['giphy']>];\n    image = giphyVersion.url;\n    dimensions.height = giphyVersion.height;\n    dimensions.width = giphyVersion.width;\n  }\n\n  if (!title && !cardUrl && !image) {\n    return <UnableToRenderCard />;\n  }\n\n  return (\n    <CardRoot cardUrl={cardUrl} type={type}>\n      <CardHeader {...props} dimensions={dimensions} image={image} />\n      <CardContent {...props} />\n    </CardRoot>\n  );\n};\n\n/**\n * Simple Card Layout for displaying links\n */\nexport const Card = React.memo(UnMemoizedCard) as typeof UnMemoizedCard;\n","import React from 'react';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { FileIcon } from '../FileIcon';\nimport type { Attachment } from 'stream-chat';\n\nimport {\n  FileSizeIndicator as DefaultFileSizeIndicator,\n  DownloadButton,\n} from './components';\n\nexport type FileAttachmentProps = {\n  attachment: Attachment;\n};\n\nexport const FileAttachment = ({ attachment }: FileAttachmentProps) => {\n  const { AttachmentFileIcon, FileSizeIndicator = DefaultFileSizeIndicator } =\n    useComponentContext();\n  const FileIconComponent = AttachmentFileIcon ?? FileIcon;\n  return (\n    <div\n      className='str-chat__message-attachment-file--item'\n      data-testid='attachment-file'\n    >\n      <FileIconComponent\n        className='str-chat__file-icon'\n        fileName={attachment.title}\n        mimeType={attachment.mime_type}\n      />\n      <div className='str-chat__message-attachment-file--item__info'>\n        <div className='str-chat__message-attachment-file--item__first-row'>\n          <div\n            className='str-chat__message-attachment-file--item__name'\n            data-testid='file-title'\n          >\n            {attachment.title}\n          </div>\n        </div>\n        <div className='str-chat__message-attachment-file--item__data'>\n          <FileSizeIndicator fileSize={attachment.file_size} />\n        </div>\n      </div>\n      <DownloadButton\n        assetUrl={attachment.asset_url}\n        suggestedFileName={attachment.title}\n      />\n    </div>\n  );\n};\n","import type { Attachment } from 'stream-chat';\nimport { BaseImage as DefaultBaseImage } from '../BaseImage';\nimport { toGalleryItemDescriptors } from '../Gallery';\nimport clsx from 'clsx';\nimport {\n  useChannelStateContext,\n  useComponentContext,\n  useTranslationContext,\n} from '../../context';\nimport { IconGiphy } from '../Icons';\nimport { type CSSProperties, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type { ImageAttachmentConfiguration } from '../../types/types';\n\nexport type GiphyAttachmentProps = {\n  attachment: Attachment;\n};\n\nexport const Giphy = ({ attachment }: GiphyAttachmentProps) => {\n  const { giphyVersion: giphyVersionName, imageAttachmentSizeHandler } =\n    useChannelStateContext();\n  const { BaseImage = DefaultBaseImage } = useComponentContext();\n  const { t } = useTranslationContext();\n  const usesDefaultBaseImage = BaseImage === DefaultBaseImage;\n  const imageElement = useRef<HTMLImageElement>(null);\n  const [attachmentConfiguration, setAttachmentConfiguration] = useState<\n    ImageAttachmentConfiguration | undefined\n  >(undefined);\n\n  const imageDescriptors = useMemo(\n    () => toGalleryItemDescriptors(attachment, { giphyVersionName }),\n    [attachment, giphyVersionName],\n  );\n  const alt = imageDescriptors && imageDescriptors.alt;\n  const dimensions = imageDescriptors && imageDescriptors.dimensions;\n  const imageUrl = imageDescriptors && imageDescriptors.imageUrl;\n  const title = imageDescriptors && imageDescriptors.title;\n  const resolvedImageUrl = attachmentConfiguration?.url || imageUrl;\n  const imageStyleVariables = useMemo(() => {\n    const originalHeight = Number(dimensions?.height);\n    const originalWidth = Number(dimensions?.width);\n\n    return {\n      '--original-height': String(originalHeight > 1 ? originalHeight : 1000000),\n      '--original-width': String(originalWidth > 1 ? originalWidth : 1000000),\n    } as CSSProperties;\n  }, [dimensions?.height, dimensions?.width]);\n\n  useLayoutEffect(() => {\n    if (!imageElement.current || !imageAttachmentSizeHandler) return;\n\n    const config = imageAttachmentSizeHandler(attachment, imageElement.current);\n    setAttachmentConfiguration(config);\n  }, [attachment, imageAttachmentSizeHandler]);\n\n  if (!imageUrl) return null;\n\n  return (\n    <div className={clsx(`str-chat__message-attachment-giphy`)}>\n      <BaseImage\n        alt={alt ?? title ?? t('User uploaded content')}\n        height={dimensions?.height}\n        ref={imageElement}\n        src={resolvedImageUrl}\n        style={imageStyleVariables}\n        width={dimensions?.width}\n        {...(usesDefaultBaseImage ? { showDownloadButtonOnError: false } : {})}\n      />\n      <GiphyBadge />\n    </div>\n  );\n};\n\nconst GiphyBadge = () => (\n  <div className='str-chat__giphy-badge'>\n    <IconGiphy />\n    Giphy\n  </div>\n);\n","import React from 'react';\nimport type { IconProps } from '../../types/types';\n\nexport const DownloadIcon = ({ className }: IconProps) => (\n  <svg\n    className={className}\n    data-testid='download'\n    fill='none'\n    height='24'\n    viewBox='0 0 24 24'\n    width='24'\n    xmlns='http://www.w3.org/2000/svg'\n  >\n    <path\n      d='M19.35 10.04C18.67 6.59 15.64 4 12 4C9.11 4 6.6 5.64 5.35 8.04C2.34 8.36 0 10.91 0 14C0 17.31 2.69 20 6 20H19C21.76 20 24 17.76 24 15C24 12.36 21.95 10.22 19.35 10.04ZM19 18H6C3.79 18 2 16.21 2 14C2 11.95 3.53 10.24 5.56 10.03L6.63 9.92L7.13 8.97C8.08 7.14 9.94 6 12 6C14.62 6 16.88 7.86 17.39 10.43L17.69 11.93L19.22 12.04C20.78 12.14 22 13.45 22 15C22 16.65 20.65 18 19 18ZM13.45 10H10.55V13H8L12 17L16 13H13.45V10Z'\n      fill='black'\n    />\n  </svg>\n);\n\nexport const ExternalLinkIcon = () => (\n  <svg fill='currentColor' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'>\n    <path d='M12.586 2H10a1 1 0 1 1 0-2h5a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0V3.414l-6.793 6.793a1 1 0 0 1-1.414-1.414L12.586 2zM6 1a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h8.967a1 1 0 0 0 1-.99L13 9.99a1 1 0 1 1 2 .02l-.033 3.023a3 3 0 0 1-3 2.967H3a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3h3z' />\n  </svg>\n);\n","import type { ComponentType } from 'react';\nimport { useEffect } from 'react';\nimport { useRef, useState } from 'react';\nimport React from 'react';\nimport type { Coords, SharedLocationResponse } from 'stream-chat';\nimport { useChatContext, useTranslationContext } from '../../context';\nimport { ExternalLinkIcon } from './icons';\nimport { IconLocation } from '../Icons';\nimport { Button } from '../Button';\n\nexport type GeolocationMapProps = Coords;\n\nexport type GeolocationProps = {\n  location: SharedLocationResponse;\n  GeolocationAttachmentMapPlaceholder?: ComponentType<GeolocationAttachmentMapPlaceholderProps>;\n  GeolocationMap?: ComponentType<GeolocationMapProps>;\n};\n\nexport const Geolocation = ({\n  GeolocationAttachmentMapPlaceholder = DefaultGeolocationAttachmentMapPlaceholder,\n  GeolocationMap,\n  location,\n}: GeolocationProps) => {\n  const { channel, client } = useChatContext();\n  const { t } = useTranslationContext();\n\n  const [stoppedSharing, setStoppedSharing] = useState(\n    !!location.end_at && new Date(location.end_at).getTime() < new Date().getTime(),\n  );\n  const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n  const isMyLocation = location.user_id === client.userID;\n  const isLiveLocation = !!location.end_at;\n\n  useEffect(() => {\n    if (!location.end_at) return;\n    clearTimeout(timeoutRef.current);\n    timeoutRef.current = setTimeout(\n      () => setStoppedSharing(true),\n      new Date(location.end_at).getTime() - Date.now(),\n    );\n  }, [location.end_at]);\n\n  return (\n    <div\n      className='str-chat__message-attachment-geolocation'\n      data-testid='attachment-geolocation'\n    >\n      <div className='str-chat__message-attachment-geolocation__location-preview'>\n        {GeolocationMap ? (\n          <GeolocationMap latitude={location.latitude} longitude={location.longitude} />\n        ) : (\n          <GeolocationAttachmentMapPlaceholder location={location} />\n        )}\n      </div>\n      <div className='str-chat__message-attachment-geolocation__status'>\n        {isLiveLocation ? (\n          stoppedSharing ? (\n            t('Location sharing ended')\n          ) : isMyLocation ? (\n            <div className='str-chat__message-attachment-geolocation__status--active'>\n              <Button\n                appearance='outline'\n                className='str-chat__message-attachment-geolocation__stop-sharing-button'\n                onClick={() => channel?.stopLiveLocationSharing(location)}\n                size='sm'\n                variant='secondary'\n              >\n                {t('Stop sharing')}\n              </Button>\n              <div className='str-chat__message-attachment-geolocation__status--active-until'>\n                {t('Live until {{ timestamp }}', {\n                  timestamp: t('timestamp/LiveLocation', { timestamp: location.end_at }),\n                })}\n              </div>\n            </div>\n          ) : (\n            <div className='str-chat__message-attachment-geolocation__status--active'>\n              <div className='str-chat__message-attachment-geolocation__status--active-status'>\n                {t('Live location')}\n              </div>\n              <div className='str-chat__message-attachment-geolocation__status--active-until'>\n                {t('Live until {{ timestamp }}', {\n                  timestamp: t('timestamp/LiveLocation', { timestamp: location.end_at }),\n                })}\n              </div>\n            </div>\n          )\n        ) : (\n          t('Current location')\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport type GeolocationAttachmentMapPlaceholderProps = {\n  location: SharedLocationResponse;\n};\n\nconst DefaultGeolocationAttachmentMapPlaceholder = ({\n  location,\n}: GeolocationAttachmentMapPlaceholderProps) => {\n  const { t } = useTranslationContext();\n\n  return (\n    <div\n      className='str-chat__message-attachment-geolocation__placeholder'\n      data-testid='geolocation-attachment-map-placeholder'\n    >\n      <IconLocation />\n      <a\n        aria-label={t('Open location in a map')}\n        className='str-chat__message-attachment-geolocation__placeholder-link'\n        href={`https://maps.google.com?q=${[location.latitude, location.longitude].join()}`}\n        rel='noreferrer'\n        target='_blank'\n      >\n        <ExternalLinkIcon />\n      </a>\n    </div>\n  );\n};\n","import React from 'react';\nimport type { Attachment } from 'stream-chat';\nimport { useTranslationContext } from '../../context';\nimport { IconUnsupportedAttachment } from '../Icons';\n\nexport type UnsupportedAttachmentProps = {\n  attachment: Attachment;\n};\n\nexport const UnsupportedAttachment = () => {\n  const { t } = useTranslationContext('UnsupportedAttachment');\n  return (\n    <div\n      className='str-chat__message-attachment-unsupported'\n      data-testid='attachment-unsupported'\n    >\n      <IconUnsupportedAttachment />\n      <div className='str-chat__message-attachment-unsupported__metadata'>\n        <div\n          className='str-chat__message-attachment-unsupported__title'\n          data-testid='unsupported-attachment-title'\n        >\n          {t('Unsupported attachment')}\n        </div>\n      </div>\n    </div>\n  );\n};\n","import React from 'react';\nimport { IconEyeFill } from '../Icons';\nimport { useTranslationContext } from '../../context';\n\nexport const VisibilityDisclaimer = () => {\n  const { t } = useTranslationContext();\n  return (\n    <div className='str-chat__visibility-disclaimer'>\n      <IconEyeFill />\n      {t('Only visible to you')}\n    </div>\n  );\n};\n","import type { VideoAttachment as VideoAttachmentType } from 'stream-chat';\nimport { useChannelStateContext } from '../../context';\nimport React, { type ComponentType, useLayoutEffect, useRef, useState } from 'react';\nimport type { VideoAttachmentConfiguration } from '../../types/types';\nimport { getCssDimensionsVariables } from './utils';\nimport type { VideoPlayerProps } from '../VideoPlayer';\nimport { VideoPlayer as DefaultVideoPlayer } from '../VideoPlayer';\nimport { VideoThumbnail } from '../VideoPlayer/VideoThumbnail';\n\nexport type VideoAttachmentProps = {\n  attachment: VideoAttachmentType;\n  VideoPlayer?: ComponentType<VideoPlayerProps>;\n};\n\nexport const VideoAttachment = ({\n  attachment,\n  VideoPlayer = DefaultVideoPlayer,\n}: VideoAttachmentProps) => {\n  const { shouldGenerateVideoThumbnail, videoAttachmentSizeHandler } =\n    useChannelStateContext();\n  const videoElement = useRef<HTMLDivElement>(null);\n  const [attachmentConfiguration, setAttachmentConfiguration] =\n    useState<VideoAttachmentConfiguration>();\n  const [showVideo, setShowVideo] = React.useState(!shouldGenerateVideoThumbnail);\n\n  useLayoutEffect(() => {\n    if (videoElement.current && videoAttachmentSizeHandler) {\n      const config = videoAttachmentSizeHandler(\n        attachment,\n        videoElement.current,\n        shouldGenerateVideoThumbnail,\n      );\n      setAttachmentConfiguration(config);\n    }\n  }, [\n    videoElement,\n    videoAttachmentSizeHandler,\n    attachment,\n    shouldGenerateVideoThumbnail,\n  ]);\n\n  const renderThumbnailFirst = Boolean(\n    attachment.thumb_url && shouldGenerateVideoThumbnail,\n  );\n\n  // todo: handle failed thumbnail loading\n  return (\n    <div\n      className='str-chat__player-wrapper'\n      data-testid='video-wrapper'\n      ref={videoElement}\n      style={getCssDimensionsVariables(attachment.thumb_url || '')}\n    >\n      {renderThumbnailFirst && !showVideo ? (\n        <VideoThumbnail\n          alt={attachment.title}\n          data-testid='image-test'\n          onPlay={() => setShowVideo(true)}\n          src={attachment.thumb_url}\n          title={attachment.title}\n        />\n      ) : (\n        <VideoPlayer\n          isPlaying={renderThumbnailFirst}\n          thumbnailUrl={attachmentConfiguration?.thumbUrl}\n          videoUrl={attachmentConfiguration?.url}\n        />\n      )}\n    </div>\n  );\n};\n","import React, {\n  type PropsWithChildren,\n  useLayoutEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport clsx from 'clsx';\nimport type {\n  Attachment,\n  LocalAttachment,\n  SharedLocationResponse,\n  VideoAttachment as VideoAttachmentType,\n} from 'stream-chat';\nimport {\n  isAudioAttachment,\n  isFileAttachment,\n  isSharedLocationResponse,\n  isVideoAttachment,\n  isVoiceRecordingAttachment,\n} from 'stream-chat';\n\nimport { Audio as DefaultAudioAttachment } from './Audio';\nimport { AttachmentActions as DefaultAttachmentActions } from './AttachmentActions';\nimport { VoiceRecording as DefaultVoiceRecording } from './VoiceRecording';\nimport { type GalleryItem, toGalleryItemDescriptors } from '../Gallery';\nimport { ImageComponent as DefaultImage } from './Image';\nimport { Card as DefaultCard } from './LinkPreview/Card';\nimport { FileAttachment as DefaultFile } from './FileAttachment';\nimport { Giphy as DefaultGiphy } from './Giphy';\nimport { Geolocation as DefaultGeolocation } from './Geolocation';\nimport { ModalGallery as DefaultModalGallery } from './ModalGallery';\nimport { UnsupportedAttachment as DefaultUnsupportedAttachment } from './UnsupportedAttachment';\nimport {\n  type AttachmentComponentType,\n  type GalleryAttachment,\n  type GeolocationContainerProps,\n  getCssDimensionsVariables,\n  isGalleryAttachmentType,\n  isSvgAttachment,\n  type RenderAttachmentProps,\n  type RenderGalleryProps,\n  type RenderMediaProps,\n  SUPPORTED_VIDEO_FORMATS,\n} from './utils';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport type { ImageAttachmentConfiguration } from '../../types/types';\nimport { VisibilityDisclaimer } from './VisibilityDisclaimer';\nimport { VideoAttachment } from './VideoAttachment';\nimport type { AttachmentProps } from './Attachment';\n\nexport type AttachmentContainerProps = {\n  attachment: Attachment | GalleryAttachment | SharedLocationResponse;\n  componentType: AttachmentComponentType;\n};\nexport const AttachmentWithinContainer = ({\n  attachment,\n  children,\n  componentType,\n}: PropsWithChildren<AttachmentContainerProps>) => {\n  const isGAT = isGalleryAttachmentType(attachment);\n  let extra = '';\n\n  if (!isGAT && !isSharedLocationResponse(attachment)) {\n    extra =\n      componentType === 'card' && !attachment?.image_url && !attachment?.thumb_url\n        ? 'no-image'\n        : attachment?.actions?.length\n          ? 'actions'\n          : '';\n  }\n\n  const classNames = clsx(\n    'str-chat__message-attachment str-chat__message-attachment-dynamic-size',\n    {\n      [`str-chat__message-attachment--${componentType}`]: componentType,\n      [`str-chat__message-attachment--${(attachment as Attachment)?.type}`]: (\n        attachment as Attachment\n      )?.type,\n      [`str-chat__message-attachment--${componentType}--${extra}`]:\n        componentType && extra,\n      'str-chat__message-attachment--svg-image': isSvgAttachment(attachment),\n      'str-chat__message-attachment-with-actions': extra === 'actions',\n    },\n  );\n\n  return <div className={classNames}>{children}</div>;\n};\n\nexport const AttachmentActionsContainer = ({\n  actionHandler,\n  attachment,\n  AttachmentActions = DefaultAttachmentActions,\n  attachmentActionsDefaultFocus,\n}: RenderAttachmentProps) => {\n  if (!attachment.actions?.length) return null;\n\n  const defaultFocusedActionValue =\n    attachment.type && attachmentActionsDefaultFocus?.[attachment.type];\n\n  return (\n    <AttachmentActions\n      {...attachment}\n      actionHandler={actionHandler}\n      actions={attachment.actions}\n      defaultFocusedActionValue={defaultFocusedActionValue}\n      id={(attachment as LocalAttachment).localMetadata?.id || ''}\n      text={attachment.text || ''}\n    />\n  );\n};\n\nexport const MediaContainer = (props: RenderMediaProps) => {\n  const { attachments: mediaAttachments } = props;\n  if (!mediaAttachments.length) return null;\n\n  if (mediaAttachments.length > 1) {\n    return (\n      <GalleryContainer\n        {...props}\n        attachment={{ items: mediaAttachments, type: 'gallery' }}\n      />\n    );\n  }\n\n  const mediaAttachment = mediaAttachments[0];\n  const { attachments: _attachments, ...rest } = props; // eslint-disable-line @typescript-eslint/no-unused-vars\n\n  if (isVideoAttachment(mediaAttachment, SUPPORTED_VIDEO_FORMATS)) {\n    return <VideoContainer attachment={mediaAttachment} {...rest} />;\n  }\n\n  return <ImageContainer attachment={mediaAttachment} {...rest} />;\n};\n\nexport const CardContainer = (props: RenderAttachmentProps) => {\n  const { attachment, Card = DefaultCard } = props;\n  const componentType = 'card';\n\n  if (attachment.actions && attachment.actions.length) {\n    return (\n      <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n        <div className='str-chat__attachment'>\n          <Card {...attachment} />\n          <AttachmentActionsContainer {...props} />\n        </div>\n      </AttachmentWithinContainer>\n    );\n  }\n\n  return (\n    <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n      <Card {...attachment} />\n    </AttachmentWithinContainer>\n  );\n};\n\nexport const GiphyContainer = (props: RenderAttachmentProps) => {\n  const { attachment, Giphy = DefaultGiphy } = props;\n  const componentType = 'giphy';\n\n  if (attachment.actions && attachment.actions.length) {\n    return (\n      <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n        <div className='str-chat__attachment'>\n          <VisibilityDisclaimer />\n          <Giphy attachment={attachment} />\n          <AttachmentActionsContainer {...props} />\n        </div>\n      </AttachmentWithinContainer>\n    );\n  }\n\n  return (\n    <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n      <Giphy attachment={attachment} />\n    </AttachmentWithinContainer>\n  );\n};\n\nexport const FileContainer = (props: RenderAttachmentProps) => {\n  const { attachment } = props;\n\n  if (isVoiceRecordingAttachment(attachment)) {\n    return <VoiceRecordingContainer {...props} />;\n  }\n\n  if (isAudioAttachment(attachment)) {\n    return <AudioContainer {...props} />;\n  }\n\n  if (!attachment.asset_url || !isFileAttachment(attachment, SUPPORTED_VIDEO_FORMATS)) {\n    return null;\n  }\n\n  return <OtherFilesContainer {...props} />;\n};\n\nexport const GalleryContainer = ({\n  attachment,\n  ModalGallery = DefaultModalGallery,\n}: RenderGalleryProps) => {\n  const items = useMemo<GalleryItem[]>(\n    () =>\n      attachment.items.reduce<GalleryItem[]>((acc, attachment) => {\n        const item = toGalleryItemDescriptors(attachment);\n        if (item) acc.push(item);\n        return acc;\n      }, []),\n    [attachment.items],\n  );\n  return (\n    <AttachmentWithinContainer attachment={attachment} componentType='gallery'>\n      <ModalGallery items={items} key='gallery' />\n    </AttachmentWithinContainer>\n  );\n};\n\nexport const ImageContainer = (props: RenderAttachmentProps) => {\n  const { attachment, Image = DefaultImage } = props;\n  const componentType = 'image';\n  const imageElement = useRef<HTMLImageElement>(null);\n  const { imageAttachmentSizeHandler } = useChannelStateContext();\n  const [attachmentConfiguration, setAttachmentConfiguration] = useState<\n    ImageAttachmentConfiguration | undefined\n  >(undefined);\n\n  useLayoutEffect(() => {\n    if (imageElement.current && imageAttachmentSizeHandler) {\n      const config = imageAttachmentSizeHandler(attachment, imageElement.current);\n      setAttachmentConfiguration(config);\n    }\n  }, [imageElement, imageAttachmentSizeHandler, attachment]);\n\n  const imgUrlFromAttachment = attachment.image_url || attachment.thumb_url || '';\n\n  const imageConfig: GalleryItem = {\n    ...toGalleryItemDescriptors({\n      ...attachment,\n      image_url: attachmentConfiguration?.url || imgUrlFromAttachment,\n    }),\n    ref: imageElement,\n    style: getCssDimensionsVariables(imgUrlFromAttachment),\n  };\n\n  if (attachment.actions && attachment.actions.length) {\n    return (\n      <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n        <div className='str-chat__attachment'>\n          <Image {...imageConfig} />\n          <AttachmentActionsContainer {...props} />\n        </div>\n      </AttachmentWithinContainer>\n    );\n  }\n\n  return (\n    <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n      <Image {...imageConfig} />\n    </AttachmentWithinContainer>\n  );\n};\n\nexport const OtherFilesContainer = ({\n  attachment,\n  File = DefaultFile,\n}: RenderAttachmentProps) => {\n  if (!attachment.asset_url) return null;\n\n  return (\n    <AttachmentWithinContainer attachment={attachment} componentType='file'>\n      <File attachment={attachment} />\n    </AttachmentWithinContainer>\n  );\n};\n\nexport const AudioContainer = ({\n  attachment,\n  Audio = DefaultAudioAttachment,\n}: RenderAttachmentProps) => (\n  <AttachmentWithinContainer attachment={attachment} componentType='audio'>\n    <div className='str-chat__attachment'>\n      <Audio attachment={attachment} />\n    </div>\n  </AttachmentWithinContainer>\n);\n\nexport const VoiceRecordingContainer = ({\n  attachment,\n  isQuoted,\n  VoiceRecording = DefaultVoiceRecording,\n}: RenderAttachmentProps) => (\n  <AttachmentWithinContainer attachment={attachment} componentType='voiceRecording'>\n    <div className='str-chat__attachment'>\n      <VoiceRecording attachment={attachment} isQuoted={isQuoted} />\n    </div>\n  </AttachmentWithinContainer>\n);\n\nexport const VideoContainer = (\n  props: Omit<AttachmentProps, 'attachments'> & { attachment: VideoAttachmentType },\n) => {\n  const { attachment, Media } = props;\n  const componentType = 'media';\n\n  return attachment.actions?.length ? (\n    <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n      <div className='str-chat__attachment'>\n        <VideoAttachment attachment={attachment} VideoPlayer={Media} />\n        <AttachmentActionsContainer {...props} />\n      </div>\n    </AttachmentWithinContainer>\n  ) : (\n    <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n      <VideoAttachment attachment={attachment} VideoPlayer={Media} />\n    </AttachmentWithinContainer>\n  );\n};\n\nexport const GeolocationContainer = ({\n  Geolocation = DefaultGeolocation,\n  location,\n}: GeolocationContainerProps) => (\n  <AttachmentWithinContainer attachment={location} componentType='geolocation'>\n    <Geolocation location={location} />\n  </AttachmentWithinContainer>\n);\n\nexport const UnsupportedAttachmentContainer = ({\n  attachment,\n  UnsupportedAttachment = DefaultUnsupportedAttachment,\n}: RenderAttachmentProps) => (\n  <AttachmentWithinContainer attachment={attachment} componentType='unsupported'>\n    <UnsupportedAttachment attachment={attachment} />\n  </AttachmentWithinContainer>\n);\n","import React, { useMemo } from 'react';\nimport type { SharedLocationResponse, Attachment as StreamAttachment } from 'stream-chat';\nimport {\n  isAudioAttachment,\n  isFileAttachment,\n  isImageAttachment,\n  isScrapedContent,\n  isSharedLocationResponse,\n  isVideoAttachment,\n  isVoiceRecordingAttachment,\n} from 'stream-chat';\n\nimport {\n  CardContainer,\n  FileContainer,\n  GeolocationContainer,\n  GiphyContainer,\n  MediaContainer,\n  UnsupportedAttachmentContainer,\n} from './AttachmentContainer';\nimport type { GroupedRenderedAttachment } from './utils';\nimport { SUPPORTED_VIDEO_FORMATS } from './utils';\nimport type {\n  AttachmentActionsDefaultFocusByType,\n  AttachmentActionsProps,\n} from './AttachmentActions';\nimport { defaultAttachmentActionsDefaultFocus } from './AttachmentActions';\nimport type { AudioProps } from './Audio';\nimport type { VoiceRecordingProps } from './VoiceRecording';\nimport type { CardProps } from './LinkPreview/Card';\nimport type { FileAttachmentProps } from './FileAttachment';\nimport type { GalleryItem } from '../Gallery';\nimport type { UnsupportedAttachmentProps } from './UnsupportedAttachment';\nimport type { ActionHandlerReturnType } from '../Message/hooks/useActionHandler';\nimport type { GeolocationProps } from './Geolocation';\nimport type { GiphyAttachmentProps } from './Giphy';\nimport type { VideoPlayerProps } from '../VideoPlayer';\nimport type { ModalGalleryProps } from './ModalGallery';\nimport type { ImageProps } from './Image';\n\nexport const ATTACHMENT_GROUPS_ORDER = [\n  'media',\n  'giphy',\n  'card',\n  'geolocation',\n  'file',\n  'unsupported',\n] as const;\n\nexport type AttachmentProps = {\n  /** The message attachments to render, see [attachment structure](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) **/\n  attachments: (StreamAttachment | SharedLocationResponse)[];\n  /**\tThe handler function to call when an action is performed on an attachment, examples include canceling a \\/giphy command or shuffling the results. */\n  actionHandler?: ActionHandlerReturnType;\n  /**\n   * Which attachment action button receives focus on initial render, keyed by attachment type.\n   * Values must match an action's `value` (e.g. `'send'`, `'cancel'`, `'shuffle'` for giphy attachment).\n   * Default: `{ giphy: 'send' }`.\n   * To disable auto-focus (e.g. when rendering the Giphy preview above the composer so focus\n   * stays in the message input), pass an empty object: `attachmentActionsDefaultFocus={{}}`.\n   */\n  attachmentActionsDefaultFocus?: AttachmentActionsDefaultFocusByType;\n  /** Custom UI component for displaying attachment actions, defaults to and accepts same props as: [AttachmentActions](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/AttachmentActions.tsx) */\n  AttachmentActions?: React.ComponentType<AttachmentActionsProps>;\n  /** Custom UI component for displaying an audio type attachment, defaults to and accepts same props as: [Audio](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Audio.tsx) */\n  Audio?: React.ComponentType<AudioProps>;\n  /** Custom UI component for displaying a card type attachment, defaults to and accepts same props as: [Card](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Card.tsx) */\n  Card?: React.ComponentType<CardProps>;\n  /** Custom UI component for displaying a file type attachment, defaults to and accepts same props as: [File](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/FileAttachment.tsx) */\n  File?: React.ComponentType<FileAttachmentProps>;\n  /** Custom UI component for displaying a gallery of image type attachments, defaults to and accepts same props as: [ModalGallery](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/ModalGallery.tsx) */\n  ModalGallery?: React.ComponentType<ModalGalleryProps>;\n  Geolocation?: React.ComponentType<GeolocationProps>;\n  /** Custom UI component for displaying a Giphy image, defaults to and accepts same props as: [Giphy](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Giphy.tsx) */\n  Giphy?: React.ComponentType<GiphyAttachmentProps>;\n  /** Custom UI component for displaying an image type attachment, defaults to and accepts same props as: [Image](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Image.tsx) */\n  Image?: React.ComponentType<ImageProps>;\n  /** Optional flag to signal that an attachment is a displayed as a part of a quoted message */\n  isQuoted?: boolean;\n  /** Custom UI component for displaying a media type attachment, defaults to `ReactPlayer` from 'react-player' */\n  Media?: React.ComponentType<VideoPlayerProps>;\n  /** Custom UI component for displaying unsupported attachment types, defaults to NullComponent */\n  UnsupportedAttachment?: React.ComponentType<UnsupportedAttachmentProps>;\n  /** Custom UI component for displaying an audio recording attachment, defaults to and accepts same props as: [VoiceRecording](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/VoiceRecording.tsx) */\n  VoiceRecording?: React.ComponentType<VoiceRecordingProps>;\n};\n\n/**\n * A component used for rendering message attachments.\n */\nexport const Attachment = (props: AttachmentProps) => {\n  const {\n    attachmentActionsDefaultFocus = defaultAttachmentActionsDefaultFocus,\n    attachments,\n    ...rest\n  } = props;\n\n  const groupedAttachments = useMemo(\n    () =>\n      renderGroupedAttachments({\n        attachmentActionsDefaultFocus,\n        attachments,\n        ...rest,\n      }),\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [attachments, attachmentActionsDefaultFocus],\n  );\n\n  return (\n    <div className='str-chat__attachment-list'>\n      {ATTACHMENT_GROUPS_ORDER.reduce(\n        (acc, groupName) => [...acc, ...groupedAttachments[groupName]],\n        [] as React.ReactNode[],\n      )}\n    </div>\n  );\n};\n\nconst renderGroupedAttachments = ({\n  attachments,\n  ...rest\n}: AttachmentProps): GroupedRenderedAttachment => {\n  const mediaAttachments: GalleryItem[] = [];\n  const containers = attachments.reduce<GroupedRenderedAttachment>(\n    (typeMap, attachment) => {\n      if (isSharedLocationResponse(attachment)) {\n        typeMap.geolocation.push(\n          <GeolocationContainer\n            {...rest}\n            key={`geolocation-${typeMap.geolocation.length}`}\n            location={attachment}\n          />,\n        );\n      } else if (attachment.type === 'giphy') {\n        typeMap.card.push(\n          <GiphyContainer\n            key={`giphy-${typeMap.giphy.length}`}\n            {...rest}\n            attachment={attachment}\n          />,\n        );\n      } else if (isScrapedContent(attachment)) {\n        typeMap.card.push(\n          <CardContainer\n            key={`card-${typeMap.card.length}`}\n            {...rest}\n            attachment={attachment}\n          />,\n        );\n      } else if (\n        isImageAttachment(attachment) ||\n        isVideoAttachment(attachment, SUPPORTED_VIDEO_FORMATS)\n      ) {\n        mediaAttachments.push(attachment as GalleryItem);\n      } else if (\n        isAudioAttachment(attachment) ||\n        isVoiceRecordingAttachment(attachment) ||\n        isFileAttachment(attachment, SUPPORTED_VIDEO_FORMATS)\n      ) {\n        typeMap.file.push(\n          <FileContainer\n            key={`file-${typeMap.file.length}`}\n            {...rest}\n            attachment={attachment}\n          />,\n        );\n      } else {\n        typeMap.unsupported.push(\n          <UnsupportedAttachmentContainer\n            key={`unsupported-${typeMap.unsupported.length}`}\n            {...rest}\n            attachment={attachment}\n          />,\n        );\n      }\n\n      return typeMap;\n    },\n    {\n      card: [],\n      file: [],\n      geolocation: [],\n      giphy: [],\n      media: [],\n      unsupported: [],\n    },\n  );\n\n  if (mediaAttachments.length) {\n    containers.media.push(\n      <MediaContainer key='media-container' {...rest} attachments={mediaAttachments} />,\n    );\n  }\n\n  return containers;\n};\n","import { LiveLocationManager } from 'stream-chat';\nimport { useEffect, useMemo } from 'react';\nimport type { LiveLocationManagerConstructorParameters, StreamChat } from 'stream-chat';\n\nconst isMobile = () => /Mobi/i.test(navigator.userAgent);\n/**\n * Checks whether the current browser is Safari.\n */\nexport const isSafari = () => {\n  if (typeof navigator === 'undefined') return false;\n  return /^((?!chrome|android).)*safari/i.test(navigator.userAgent || '');\n};\n\n/**\n * Checks whether the current browser is Firefox.\n */\nexport const isFirefox = () => {\n  if (typeof navigator === 'undefined') return false;\n  return navigator.userAgent?.includes('Firefox');\n};\n\n/**\n * Checks whether the current browser is Google Chrome.\n */\nexport const isChrome = () => {\n  if (typeof navigator === 'undefined') return false;\n  return navigator.userAgent?.includes('Chrome');\n};\n\nconst browser = () => {\n  if (isChrome()) return 'chrome';\n  if (isFirefox()) return 'firefox';\n  if (isSafari()) return 'safari';\n  return 'other';\n};\n\nexport const useLiveLocationSharingManager = ({\n  client,\n  getDeviceId,\n  watchLocation,\n}: Omit<LiveLocationManagerConstructorParameters, 'client' | 'getDeviceId'> & {\n  client?: StreamChat | null;\n  getDeviceId?: () => string;\n}) => {\n  const manager = useMemo(() => {\n    if (!client) return null;\n\n    return new LiveLocationManager({\n      client,\n      getDeviceId:\n        getDeviceId ??\n        (() => `web-${isMobile() ? 'mobile' : 'desktop'}-${browser()}-${client.userID}`),\n      watchLocation,\n    });\n  }, [client, getDeviceId, watchLocation]);\n\n  useEffect(() => {\n    if (!manager) return;\n\n    manager.init();\n\n    return () => {\n      manager.unregisterSubscriptions();\n    };\n  }, [manager]);\n\n  return manager;\n};\n","import { useMessageComposerController } from './useMessageComposerController';\nimport { useStateStore } from '../../../store';\nimport type { AttachmentManagerState } from 'stream-chat';\n\nconst stateSelector = (state: AttachmentManagerState) => ({\n  attachments: state.attachments,\n});\n\nexport const useAttachmentManagerState = () => {\n  const { attachmentManager } = useMessageComposerController();\n  const { attachments } = useStateStore(attachmentManager.state, stateSelector);\n  return {\n    attachments,\n    availableUploadSlots: attachmentManager.availableUploadSlots,\n    blockedUploadsCount: attachmentManager.blockedUploadsCount,\n    failedUploadsCount: attachmentManager.failedUploadsCount,\n    isUploadEnabled: attachmentManager.isUploadEnabled,\n    pendingUploadsCount: attachmentManager.pendingUploadsCount,\n    successfulUploadsCount: attachmentManager.successfulUploadsCount,\n    uploadsInProgressCount: attachmentManager.uploadsInProgressCount,\n  };\n};\n","import { useMessageComposerController } from './useMessageComposerController';\nimport { useStateStore } from '../../../store';\nimport type {\n  AttachmentManagerState,\n  LocationComposerState,\n  PollComposerState,\n} from 'stream-chat';\n\nconst attachmentManagerStateSelector = (state: AttachmentManagerState) => ({\n  attachments: state.attachments,\n});\nconst pollComposerStateSelector = (state: PollComposerState) => ({\n  poll: state.data,\n});\nconst locationComposerStateSelector = (state: LocationComposerState) => ({\n  location: state.location,\n});\n\nexport const useAttachmentsForPreview = () => {\n  const { attachmentManager, locationComposer, pollComposer } =\n    useMessageComposerController();\n  const { attachments } = useStateStore(\n    attachmentManager.state,\n    attachmentManagerStateSelector,\n  );\n  const { poll } = useStateStore(pollComposer.state, pollComposerStateSelector);\n  const { location } = useStateStore(\n    locationComposer.state,\n    locationComposerStateSelector,\n  );\n\n  return {\n    attachments,\n    location,\n    poll,\n  };\n};\n","import { useMessageComposerController } from './useMessageComposerController';\nimport { useEffect, useState } from 'react';\n\nexport const useCanCreatePoll = () => {\n  const { pollComposer } = useMessageComposerController();\n  const [canCreatePoll, setCanCreatePoll] = useState(pollComposer.canCreatePoll);\n  useEffect(\n    () =>\n      pollComposer.state.subscribe(() => {\n        setCanCreatePoll(pollComposer.canCreatePoll);\n      }),\n    [pollComposer],\n  );\n  return canCreatePoll;\n};\n","import { type CooldownTimerState } from 'stream-chat';\n\nimport { useChannelStateContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst cooldownTimerStateSelector = (state: CooldownTimerState) => ({\n  cooldownRemaining: state.cooldownRemaining,\n});\n\n/**\n * Provides and initial value of cooldown, from which the countdown should start, e.g.:\n *\n * The value of channel.data.cooldown is 100s but 30s has already elapsed, user reloads the page,\n * the initial value is now 70s from which the countdown will continue using useTimer() hook.\n */\nexport const useCooldownRemaining = (): number => {\n  const { channel } = useChannelStateContext();\n  return (\n    useStateStore(channel.cooldownTimer.state, cooldownTimerStateSelector)\n      .cooldownRemaining ?? 0\n  );\n};\n","import { useEffect, useRef } from 'react';\nimport type { MessageComposerProps } from '../MessageComposer';\n\nexport const useTextareaRef = (props: MessageComposerProps) => {\n  const { focus } = props;\n  const textareaRef = useRef<HTMLTextAreaElement>(undefined);\n  // Focus\n  useEffect(() => {\n    if (focus && textareaRef.current) {\n      textareaRef.current.focus();\n    }\n  }, [focus]);\n\n  return {\n    textareaRef,\n  };\n};\n","import { useCallback } from 'react';\nimport { MessageComposer } from 'stream-chat';\nimport { useMessageComposerController } from './useMessageComposerController';\nimport { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\nimport { useNotificationApi } from '../../Notifications';\nimport { discardPreEditSnapshot } from '../preEditSnapshot';\n\nimport type { MessageComposerProps } from '../MessageComposer';\n\nconst takeStateSnapshot = (messageComposer: MessageComposer) => {\n  const textComposerState = messageComposer.textComposer.state.getLatestValue();\n  const attachmentManagerState = messageComposer.attachmentManager.state.getLatestValue();\n  const linkPreviewsManagerState =\n    messageComposer.linkPreviewsManager.state.getLatestValue();\n  const pollComposerState = messageComposer.pollComposer.state.getLatestValue();\n  const customDataManagerState = messageComposer.customDataManager.state.getLatestValue();\n  const state = messageComposer.state.getLatestValue();\n\n  return () => {\n    messageComposer.state.next(state);\n    messageComposer.textComposer.state.next(textComposerState);\n    messageComposer.attachmentManager.state.next(attachmentManagerState);\n    messageComposer.linkPreviewsManager.state.next(linkPreviewsManagerState);\n    messageComposer.pollComposer.state.next(pollComposerState);\n    messageComposer.customDataManager.state.next(customDataManagerState);\n  };\n};\n\nexport const useSubmitHandler = (props: MessageComposerProps) => {\n  const { overrideSubmitHandler } = props;\n\n  const { addNotification } = useNotificationApi();\n  const { editMessage, sendMessage } = useChannelActionContext('useSubmitHandler');\n  const { t } = useTranslationContext('useSubmitHandler');\n  const messageComposer = useMessageComposerController();\n\n  const handleSubmit = useCallback(\n    async (event?: React.BaseSyntheticEvent) => {\n      event?.preventDefault();\n      const composition = await messageComposer.compose();\n      if (!composition || !composition.message) return;\n\n      const { localMessage, message, sendOptions } = composition;\n\n      if (messageComposer.editedMessage && localMessage.type !== 'error') {\n        try {\n          await editMessage(localMessage, sendOptions);\n          discardPreEditSnapshot(messageComposer);\n          messageComposer.clear();\n        } catch (err) {\n          addNotification({\n            emitter: 'MessageComposer',\n            incident: {\n              domain: 'api',\n              entity: 'message',\n              operation: 'edit',\n            },\n            message: t('Edit message request failed'),\n            severity: 'error',\n          });\n        }\n      } else {\n        const restoreComposerStateSnapshot = takeStateSnapshot(messageComposer);\n        try {\n          // FIXME: once MessageComposer has sendMessage method, then the following condition should be encapsulated by it\n          // keep attachments, text, quoted message (treat them as draft) ... if sending a poll\n          const sentPollMessage = !!message.poll_id;\n          if (sentPollMessage) {\n            messageComposer.state.partialNext({\n              id: MessageComposer.generateId(),\n              pollId: null,\n            });\n          } else {\n            messageComposer.clear();\n          }\n          // todo: get rid of overrideSubmitHandler once MessageComposer supports submission flow\n          if (overrideSubmitHandler) {\n            await overrideSubmitHandler({\n              cid: messageComposer.channel.cid,\n              localMessage,\n              message,\n              sendOptions,\n            });\n          } else {\n            await sendMessage({ localMessage, message, options: sendOptions });\n          }\n          if (messageComposer.config.text.publishTypingEvents)\n            await messageComposer.channel.stopTyping();\n        } catch (err) {\n          restoreComposerStateSnapshot();\n          addNotification({\n            emitter: 'MessageComposer',\n            incident: {\n              domain: 'api',\n              entity: 'message',\n              operation: 'send',\n            },\n            message: t('Send message request failed'),\n            severity: 'error',\n          });\n        }\n      }\n    },\n    [\n      addNotification,\n      editMessage,\n      messageComposer,\n      overrideSubmitHandler,\n      sendMessage,\n      t,\n    ],\n  );\n\n  return { handleSubmit };\n};\n","import clsx from 'clsx';\nimport { nanoid } from 'nanoid';\nimport type { ComponentProps } from 'react';\nimport React, { forwardRef, useCallback, useMemo } from 'react';\n\nimport { useHandleFileChangeWrapper } from './utils';\nimport { useMessageComposerContext, useTranslationContext } from '../../context';\nimport { useMessageComposerController } from '../MessageComposer/hooks/useMessageComposerController';\nimport { useAttachmentManagerState } from '../MessageComposer/hooks/useAttachmentManagerState';\nimport { useIsCooldownActive } from '../MessageComposer/hooks/useIsCooldownActive';\nimport { useStateStore } from '../../store';\nimport type { MessageComposerConfig } from 'stream-chat';\nimport type { PartialSelected } from '../../types/types';\n\nconst attachmentManagerConfigStateSelector = (state: MessageComposerConfig) => ({\n  acceptedFiles: state.attachments.acceptedFiles,\n  maxNumberOfFilesPerMessage: state.attachments.maxNumberOfFilesPerMessage,\n});\n\nexport type FileInputProps = {\n  onFileChange: (files: Array<File>) => void;\n  resetOnChange?: boolean;\n} & Omit<ComponentProps<'input'>, 'type' | 'onChange'>;\n\nexport const FileInput = forwardRef(function FileInput(\n  { onFileChange, resetOnChange = true, ...rest }: FileInputProps,\n  ref: React.ForwardedRef<HTMLInputElement>,\n) {\n  const handleInputChange = useHandleFileChangeWrapper(resetOnChange, onFileChange);\n\n  return <input onChange={handleInputChange} ref={ref} type='file' {...rest} />;\n});\n\nexport const UploadFileInput = forwardRef(function UploadFileInput(\n  {\n    className,\n    onFileChange: onFileChangeCustom,\n    ...props\n  }: PartialSelected<FileInputProps, 'onFileChange'>,\n  ref: React.ForwardedRef<HTMLInputElement>,\n) {\n  const { t } = useTranslationContext('UploadFileInput');\n  const { textareaRef } = useMessageComposerContext();\n  const messageComposer = useMessageComposerController();\n  const { attachmentManager } = messageComposer;\n  const { isUploadEnabled } = useAttachmentManagerState();\n  const { acceptedFiles, maxNumberOfFilesPerMessage } = useStateStore(\n    messageComposer.configState,\n    attachmentManagerConfigStateSelector,\n  );\n  const isCooldownActive = useIsCooldownActive();\n  const id = useMemo(() => nanoid(), []);\n\n  const onFileChange = useCallback(\n    (files: Array<File>) => {\n      attachmentManager.uploadFiles(files);\n      textareaRef.current?.focus();\n      onFileChangeCustom?.(files);\n    },\n    [onFileChangeCustom, attachmentManager, textareaRef],\n  );\n\n  return (\n    <FileInput\n      accept={acceptedFiles?.join(',')}\n      aria-label={t('aria/File upload')}\n      data-testid='file-input'\n      disabled={!isUploadEnabled || isCooldownActive}\n      id={id}\n      multiple={maxNumberOfFilesPerMessage > 1}\n      {...props}\n      className={clsx('str-chat__file-input', className)}\n      onFileChange={onFileChange}\n      ref={ref}\n    />\n  );\n});\n","import { useCallback } from 'react';\nimport { useMessageComposerController } from './useMessageComposerController';\nimport { dataTransferItemsToFiles } from '../../ReactFileUtilities';\n\nexport const usePasteHandler = () => {\n  const { attachmentManager, textComposer } = useMessageComposerController();\n  const onPaste = useCallback(\n    (clipboardEvent: React.ClipboardEvent<HTMLTextAreaElement>) => {\n      (async (event) => {\n        const { items } = event.clipboardData;\n        event.preventDefault();\n        // Get a promise for the plain text in case no files are\n        // found. This needs to be done here because chrome cleans\n        // up the DataTransferItems after resolving of a promise.\n        let plainTextPromise: Promise<string> | undefined = undefined;\n        for (let i = 0; i < items.length; i++) {\n          const item = items[i];\n          if (item.kind === 'string' && item.type === 'text/plain') {\n            plainTextPromise = new Promise((resolve) => {\n              item.getAsString((string) => {\n                resolve(string);\n              });\n            });\n            break;\n          }\n        }\n\n        const fileLikes = await dataTransferItemsToFiles(Array.from(items));\n\n        if (plainTextPromise) {\n          const pastedText = await plainTextPromise;\n          textComposer.insertText({ text: pastedText });\n        } else {\n          attachmentManager.uploadFiles(fileLikes);\n        }\n      })(clipboardEvent);\n    },\n    [attachmentManager, textComposer],\n  );\n\n  return { onPaste };\n};\n","export interface SubscriptionLike {\n  closed: boolean;\n\n  unsubscribe(): void;\n}\n\nexport class Subscription implements SubscriptionLike {\n  closed = false;\n  private _unsubscribe: (() => void) | undefined;\n\n  constructor(unsubscribe?: () => void) {\n    this._unsubscribe = unsubscribe;\n  }\n\n  unsubscribe() {\n    this.closed = true;\n    this._unsubscribe?.();\n  }\n}\n","type Next<T> = (value: T) => void;\nexport type Observer<T> = {\n  next(value: T): void;\n  complete?(): void;\n  error?(error: Error): void;\n};\nexport type ObserverOrNext<T> = Next<T> | Observer<T>;\n\nexport function createObserver<T>(observerOrNext: ObserverOrNext<T>): Observer<T> {\n  return typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n}\n","import type { ObserverOrNext } from './Observer';\nimport { createObserver } from './Observer';\nimport { Subscription } from './Subscription';\n\nexport interface Unsubscribable {\n  unsubscribe(): void;\n}\n\ntype Producer<T> = (observer: ObserverOrNext<T>) => Subscription;\n\nexport interface Subscribable<T> {\n  subscribe(observerOrNext: ObserverOrNext<T>): Unsubscribable;\n}\n\nexport class Observable<T> implements Subscribable<T> {\n  protected _closed = false;\n  private _producer: Producer<T> | undefined;\n\n  constructor(producer?: Producer<T>) {\n    if (producer) this._producer = producer;\n  }\n\n  get closed() {\n    return this._closed;\n  }\n\n  subscribe(observerOrNext: ObserverOrNext<T>): Subscription {\n    const observer = createObserver<T>(observerOrNext);\n    if (!this.closed) {\n      this._producer?.(observer);\n    }\n    return new Subscription(() => {\n      this._closed = true;\n    });\n  }\n}\n","import { Observable } from './Observable';\nimport type { SubscriptionLike } from './Subscription';\nimport { Subscription } from './Subscription';\nimport type { Observer, ObserverOrNext } from './Observer';\nimport { createObserver } from './Observer';\n\nexport class Subject<T> extends Observable<T> implements SubscriptionLike {\n  private _observers: Map<number, Observer<T>> = new Map();\n  private _observerCounter = 0;\n  thrownError: Error | undefined;\n\n  constructor() {\n    super();\n  }\n\n  get observers() {\n    return Array.from(this._observers.values());\n  }\n\n  next(value: T) {\n    if (this.closed) return;\n    const observers = this.observers;\n    for (let i = 0; i < observers.length; i++) {\n      observers[i].next(value);\n    }\n  }\n\n  error(err: Error) {\n    if (this.closed) return;\n    this.thrownError = err;\n    const { observers } = this;\n    for (let i = 0; i < observers.length; i++) {\n      observers[i].error?.(err);\n    }\n    this._observers.clear();\n  }\n\n  complete() {\n    if (this.closed) return;\n    this._closed = true;\n    const { observers } = this;\n    for (let i = 0; i < observers.length; i++) {\n      observers[i].complete?.();\n    }\n    this._observers.clear();\n  }\n\n  subscribe(observerOrNext: ObserverOrNext<T>): Subscription {\n    const observer = createObserver<T>(observerOrNext);\n    if (this.thrownError || this.closed) {\n      const subscription = new Subscription();\n      subscription.closed = true;\n      return subscription;\n    }\n\n    const observerId = this._observerCounter++;\n    this._observers.set(observerId, observer);\n    return new Subscription(() => {\n      this._observers.delete(observerId);\n    });\n  }\n\n  unsubscribe(): void {\n    this._closed = true;\n    this._observers.clear();\n  }\n}\n","import { Subject } from './Subject';\nimport type { ObserverOrNext } from './Observer';\nimport { createObserver } from './Observer';\nimport type { Subscription } from './Subscription';\n\nexport class BehaviorSubject<T> extends Subject<T> {\n  constructor(private _value: T) {\n    super();\n  }\n\n  get value(): T {\n    const { _value, thrownError } = this;\n    if (thrownError) {\n      throw thrownError;\n    }\n    return _value;\n  }\n\n  subscribe(observerOrNext: ObserverOrNext<T>): Subscription {\n    const observer = createObserver<T>(observerOrNext);\n    const subscription = super.subscribe(observerOrNext);\n    if (!subscription.closed) observer.next(this._value);\n    return subscription;\n  }\n\n  next(value: T): void {\n    super.next((this._value = value));\n  }\n}\n","import type { RecordedMediaType } from '../../ReactFileUtilities';\nimport type { ChangeEvent } from 'react';\nimport { Subscription } from '../observable/Subscription';\nimport { Subject } from '../observable/Subject';\nimport { BehaviorSubject } from '../observable/BehaviorSubject';\n\nexport enum RecordingPermission {\n  CAM = 'camera',\n  MIC = 'microphone',\n}\n\nconst MEDIA_TO_PERMISSION: Record<RecordedMediaType, RecordingPermission> = {\n  audio: RecordingPermission.MIC,\n  video: RecordingPermission.CAM,\n};\n\nexport type BrowserPermissionOptions = {\n  mediaType: RecordedMediaType;\n};\n\nexport class BrowserPermission {\n  name: string;\n  state = new BehaviorSubject<PermissionState | undefined>(undefined);\n  status = new BehaviorSubject<PermissionStatus | undefined>(undefined);\n  error = new Subject<Error | undefined>();\n\n  private changeSubscriptions: Subscription[] = [];\n\n  constructor({ mediaType }: BrowserPermissionOptions) {\n    this.name = MEDIA_TO_PERMISSION[mediaType];\n  }\n\n  get isWatching() {\n    return this.changeSubscriptions.some((subscription) => !subscription.closed);\n  }\n\n  async watch() {\n    if (!this.status.value) {\n      await this.check();\n      if (!this.status.value) return;\n    }\n\n    const status = this.status.value;\n    const handlePermissionChange = (e: Event) => {\n      const { state } = (e as unknown as ChangeEvent<PermissionStatus>).target;\n      this.state.next(state);\n    };\n    status.addEventListener('change', handlePermissionChange);\n\n    this.changeSubscriptions.push(\n      new Subscription(() => {\n        status.removeEventListener('change', handlePermissionChange);\n      }),\n    );\n  }\n\n  unwatch() {\n    this.changeSubscriptions.forEach((subscription) => subscription.unsubscribe());\n  }\n\n  async check() {\n    if (!this.name) {\n      this.error.next(new Error('Unknown media recording permission'));\n      return;\n    }\n\n    let permissionState: PermissionState;\n    try {\n      const permissionStatus = await navigator.permissions.query({\n        name: this.name as unknown as PermissionName,\n      });\n      permissionState = permissionStatus.state;\n      this.status.next(permissionStatus);\n    } catch (e) {\n      // permission does not exist - cannot be queried\n      // an example would be Firefox - camera, neither microphone perms can be queried\n      permissionState = 'granted' as PermissionState;\n    }\n    this.state.next(permissionState);\n  }\n}\n","import mergeWith from 'lodash.mergewith';\n\nconst overrideEverything = (_: unknown, source: unknown) => source;\n\nexport const mergeDeep = <TObject, TSource>(target: TObject, source: TSource) =>\n  mergeWith<TObject, TSource>(target, source, overrideEverything);\n\nconst overrideUndefinedOnly = (object: unknown, source: unknown) => object ?? source;\n\nexport const mergeDeepUndefined = <TObject, TSource>(target: TObject, source: TSource) =>\n  mergeWith<TObject, TSource>(target, source, overrideUndefinedOnly);\n","import { BehaviorSubject } from '../observable/BehaviorSubject';\nimport { Subject } from '../observable/Subject';\nimport { mergeDeepUndefined } from '../../../utils/mergeDeep';\n\nconst MAX_FREQUENCY_AMPLITUDE = 255 as const;\n\nconst logError = (e?: Error) => e && console.error('[AMPLITUDE RECORDER ERROR]', e);\n\nconst rootMeanSquare = (values: Uint8Array) =>\n  Math.sqrt(values.reduce((acc, val) => acc + Math.pow(val, 2), 0) / values.length);\n\n/**\n * fftSize\n * An unsigned integer, representing the window size of the FFT, given in number of samples.\n * A higher value will result in more details in the frequency domain but fewer details\n * in the amplitude domain.\n *\n * Must be a power of 2 between 2^5 and 2^15, so one of: 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, and 32768.\n * Defaults to 32.\n *\n * maxDecibels\n * A double, representing the maximum decibel value for scaling the FFT analysis data,\n * where 0 dB is the loudest possible sound, -10 dB is a 10th of that, etc.\n * The default value is -30 dB.\n *\n * minDecibels\n * A double, representing the minimum decibel value for scaling the FFT analysis data,\n * where 0 dB is the loudest possible sound, -10 dB is a 10th of that, etc.\n * The default value is -100 dB.\n */\nexport type AmplitudeAnalyserConfig = Pick<\n  AnalyserNode,\n  'fftSize' | 'maxDecibels' | 'minDecibels'\n>;\nexport type AmplitudeRecorderConfig = {\n  analyserConfig: AmplitudeAnalyserConfig;\n  sampleCount: number;\n  samplingFrequencyMs: number;\n};\n\nexport const DEFAULT_AMPLITUDE_RECORDER_CONFIG: AmplitudeRecorderConfig = {\n  analyserConfig: {\n    fftSize: 32,\n    maxDecibels: 0,\n    minDecibels: -100,\n  } as AmplitudeAnalyserConfig,\n  sampleCount: 100,\n  samplingFrequencyMs: 60,\n};\n\ntype AmplitudeAnalyserOptions = {\n  stream: MediaStream;\n  config?: AmplitudeRecorderConfig;\n};\n\nexport enum AmplitudeRecorderState {\n  CLOSED = 'closed',\n  RECORDING = 'recording',\n  STOPPED = 'stopped',\n}\n\nexport class AmplitudeRecorder {\n  audioContext: AudioContext | undefined;\n  analyserNode: AnalyserNode | undefined;\n  microphone: MediaStreamAudioSourceNode | undefined;\n  stream: MediaStream;\n\n  config: AmplitudeRecorderConfig;\n\n  amplitudeSamplingInterval: ReturnType<typeof setInterval> | undefined;\n\n  amplitudes = new BehaviorSubject<number[]>([]);\n  state = new BehaviorSubject<AmplitudeRecorderState | undefined>(undefined);\n  error = new Subject<Error | undefined>();\n\n  constructor({ config, stream }: AmplitudeAnalyserOptions) {\n    this.config = mergeDeepUndefined({ ...config }, DEFAULT_AMPLITUDE_RECORDER_CONFIG);\n    this.stream = stream;\n  }\n\n  init() {\n    this.audioContext = new AudioContext();\n    this.analyserNode = this.audioContext.createAnalyser();\n    const { analyserConfig } = this.config;\n    this.analyserNode.fftSize = analyserConfig.fftSize;\n    this.analyserNode.maxDecibels = analyserConfig.maxDecibels;\n    this.analyserNode.minDecibels = analyserConfig.minDecibels;\n\n    this.microphone = this.audioContext.createMediaStreamSource(this.stream);\n    this.microphone.connect(this.analyserNode);\n  }\n\n  stop() {\n    clearInterval(this.amplitudeSamplingInterval);\n    this.amplitudeSamplingInterval = undefined;\n    this.state.next(AmplitudeRecorderState.STOPPED);\n  }\n\n  start = () => {\n    if (this.state.value === AmplitudeRecorderState.CLOSED) return;\n    if (!this.stream) {\n      throw new Error(\n        'Missing MediaStream instance. Cannot to start amplitude recording',\n      );\n    }\n\n    if (this.state.value === AmplitudeRecorderState.RECORDING) this.stop();\n\n    if (!this.analyserNode) {\n      if (!this.stream) return;\n      this.init();\n    }\n\n    this.state.next(AmplitudeRecorderState.RECORDING);\n\n    this.amplitudeSamplingInterval = setInterval(() => {\n      if (!(this.analyserNode && this.state.value === AmplitudeRecorderState.RECORDING))\n        return;\n      const frequencyBins = new Uint8Array(this.analyserNode.frequencyBinCount);\n      try {\n        this.analyserNode.getByteFrequencyData(frequencyBins);\n      } catch (e) {\n        logError(e as Error);\n        this.error.next(e as Error);\n        return;\n      }\n      const normalizedSignalStrength =\n        rootMeanSquare(frequencyBins) / MAX_FREQUENCY_AMPLITUDE;\n      this.amplitudes.next([...this.amplitudes.value, normalizedSignalStrength]);\n    }, this.config.samplingFrequencyMs);\n  };\n\n  close() {\n    if (this.state.value !== AmplitudeRecorderState.STOPPED) this.stop();\n    this.state.next(AmplitudeRecorderState.CLOSED);\n    this.amplitudes.next([]);\n    this.microphone?.disconnect();\n    this.analyserNode?.disconnect();\n    if (this.audioContext?.state !== 'closed') this.audioContext?.close();\n  }\n}\n","import { renderAudio, toAudioBuffer } from './audioProcessing';\n\nconst WAV_HEADER_LENGTH_BYTES = 44 as const;\nconst BYTES_PER_SAMPLE = 2 as const;\nconst RIFF_FILE_MAX_BYTES = 4294967295 as const;\n\nconst HEADER = {\n  AUDIO_FORMAT: { offset: 20, value: 1 }, // PCM = 1\n  BITS_PER_SAMPLE: { offset: 34, value: BYTES_PER_SAMPLE * 8 }, // 16 bits encoding\n  BLOCK_ALIGN: { offset: 32 },\n  BYTE_RATE: { offset: 28 },\n  CHANNEL_COUNT: { offset: 22 }, // 1 - mono, 2 - stereo\n  CHUNK_ID: { offset: 0, value: 0x52494646 }, // hex representation of string \"RIFF\" (Resource Interchange File Format) - identifies the file structure that defines a class of more specific file formats, e.g. WAVE\n  CHUNK_SIZE: { offset: 4 },\n  FILE_FORMAT: { offset: 8, value: 0x57415645 }, // hex representation of string \"WAVE\"\n  SAMPLE_RATE: { offset: 24 },\n  SUBCHUNK1_ID: { offset: 12, value: 0x666d7420 }, // hex representation of string \"fmt \" - identifies the start of \"format\" section of the header\n  SUBCHUNK1_SIZE: { offset: 16, value: 16 }, // Subchunk1 Size without SUBCHUNK1_ID and SUBCHUNK1_SIZE fields\n  SUBCHUNK2_ID: { offset: 36, value: 0x64617461 }, // hex representation of string \"data\" - identifies the start of actual audio data section\n  SUBCHUNK2_SIZE: { offset: 40 }, // actual audio data size\n} as const;\n\nconst fourCharsToInt = (chars: string) =>\n  (chars.charCodeAt(0) << 24) |\n  (chars.charCodeAt(1) << 16) |\n  (chars.charCodeAt(2) << 8) |\n  chars.charCodeAt(3);\n\nconst WAV_HEADER_FLAGS = {\n  data: fourCharsToInt('data'),\n  fmt: fourCharsToInt('fmt '),\n  RIFF: fourCharsToInt('RIFF'),\n  WAVE: fourCharsToInt('WAVE'),\n};\n\ntype WriteWaveHeaderParams = {\n  arrayBuffer: ArrayBuffer;\n  // 1 - mono, 2 - stereo\n  channelCount: number;\n  // Number of samples per second, e.g. 44100Hz\n  sampleRate: number;\n};\nconst writeWavHeader = ({\n  arrayBuffer,\n  channelCount,\n  sampleRate,\n}: WriteWaveHeaderParams) => {\n  const byteRate = sampleRate * channelCount * BYTES_PER_SAMPLE; // bytes/sec\n  const blockAlign = channelCount * BYTES_PER_SAMPLE;\n\n  const dataView = new DataView(arrayBuffer);\n  /*\n   * The maximum size of a RIFF file is 4294967295 bytes and since the header takes up 44 bytes there are 4294967251 bytes left for the\n   * data chunk.\n   */\n  const dataChunkSize = Math.min(\n    dataView.byteLength - WAV_HEADER_LENGTH_BYTES,\n    RIFF_FILE_MAX_BYTES - WAV_HEADER_LENGTH_BYTES,\n  );\n\n  dataView.setUint32(HEADER.CHUNK_ID.offset, HEADER.CHUNK_ID.value); // \"RIFF\"\n  dataView.setUint32(HEADER.CHUNK_SIZE.offset, arrayBuffer.byteLength - 8, true); // adjustment for the first two headers - chunk id + file size\n  dataView.setUint32(HEADER.FILE_FORMAT.offset, HEADER.FILE_FORMAT.value); // \"WAVE\"\n\n  dataView.setUint32(HEADER.SUBCHUNK1_ID.offset, HEADER.SUBCHUNK1_ID.value); // \"fmt \"\n  dataView.setUint32(HEADER.SUBCHUNK1_SIZE.offset, HEADER.SUBCHUNK1_SIZE.value, true);\n  dataView.setUint16(HEADER.AUDIO_FORMAT.offset, HEADER.AUDIO_FORMAT.value, true);\n  dataView.setUint16(HEADER.CHANNEL_COUNT.offset, channelCount, true);\n  dataView.setUint32(HEADER.SAMPLE_RATE.offset, sampleRate, true);\n  dataView.setUint32(HEADER.BYTE_RATE.offset, byteRate, true);\n  dataView.setUint16(HEADER.BLOCK_ALIGN.offset, blockAlign, true);\n  dataView.setUint16(HEADER.BITS_PER_SAMPLE.offset, HEADER.BITS_PER_SAMPLE.value, true);\n\n  dataView.setUint32(HEADER.SUBCHUNK2_ID.offset, HEADER.SUBCHUNK2_ID.value); // \"data\"\n  dataView.setUint32(HEADER.SUBCHUNK2_SIZE.offset, dataChunkSize, true);\n};\n\nexport const readWavHeader = (dataView: DataView) => {\n  const header = dataView.getUint32(0, false);\n  if (WAV_HEADER_FLAGS.RIFF !== header) {\n    console.error('Missing RIFF header in WAVE file');\n    return;\n  }\n  if (WAV_HEADER_FLAGS.WAVE !== dataView.getUint32(HEADER.FILE_FORMAT.offset, false)) {\n    console.error('Missing WAVE header in WAVE file');\n    return;\n  }\n  if (WAV_HEADER_FLAGS.fmt !== dataView.getUint32(HEADER.SUBCHUNK1_ID.offset, false)) {\n    console.error('Missing fmt header in WAVE file');\n    return;\n  }\n\n  return {\n    audioDataSizeBytes: dataView.getUint32(HEADER.SUBCHUNK2_SIZE.offset, true),\n    audioDataStartOffset: WAV_HEADER_LENGTH_BYTES,\n    channelCount: dataView.getUint16(HEADER.CHANNEL_COUNT.offset, true),\n    sampleRate: dataView.getUint32(HEADER.SAMPLE_RATE.offset, true),\n  };\n};\n\nconst splitDataByChannel = (audioBuffer: AudioBuffer) =>\n  Array.from({ length: audioBuffer.numberOfChannels }, (_, i) =>\n    audioBuffer.getChannelData(i),\n  );\n\ntype WriteAudioDataParams = {\n  arrayBuffer: ArrayBuffer;\n  dataByChannel: Float32Array[];\n};\n\n/**\n * In a WAV file, samples for each channel are usually interleaved, meaning samples from each channel are grouped together sequentially.\n * For example, in a stereo audio file (2 channels), samples alternate between the left and right channels.\n * @param arrayBuffer\n * @param dataByChannel\n */\nconst writeWavAudioData = ({ arrayBuffer, dataByChannel }: WriteAudioDataParams) => {\n  const dataView = new DataView(arrayBuffer);\n  const channelCount = dataByChannel.length;\n\n  dataByChannel.forEach((channelData, channelIndex) => {\n    let writeOffset = WAV_HEADER_LENGTH_BYTES + channelCount * channelIndex;\n\n    channelData.forEach((float32Value) => {\n      dataView.setInt16(\n        writeOffset,\n        float32Value < 0\n          ? Math.max(-1, float32Value) * 32768\n          : Math.min(1, float32Value) * 32767,\n        true,\n      );\n      writeOffset += channelCount * BYTES_PER_SAMPLE;\n    });\n  });\n};\n\nexport const encodeToWaw = async (file: File, sampleRate: number) => {\n  const audioBuffer = await renderAudio(await toAudioBuffer(file), sampleRate);\n  const numberOfSamples = audioBuffer.duration * sampleRate;\n  const fileSizeBytes =\n    numberOfSamples * audioBuffer.numberOfChannels * BYTES_PER_SAMPLE +\n    WAV_HEADER_LENGTH_BYTES;\n\n  const arrayBuffer = new ArrayBuffer(fileSizeBytes);\n  writeWavHeader({ arrayBuffer, channelCount: audioBuffer.numberOfChannels, sampleRate });\n  writeWavAudioData({ arrayBuffer, dataByChannel: splitDataByChannel(audioBuffer) });\n  return new Blob([arrayBuffer], { type: 'audio/wav' });\n};\n","import { encodeToWaw } from './wav';\nimport { createFileFromBlobs, getExtensionFromMimeType } from '../../ReactFileUtilities';\n\nexport type TranscoderConfig = {\n  // defaults to 16000Hz\n  sampleRate: number;\n  // Custom encoder function that converts the recorded audio file into a blob with the desired MIME type\n  encoder?: (file: File, sampleRate: number) => Promise<Blob>;\n};\n\nexport type TranscodeParams = TranscoderConfig & {\n  blob: Blob;\n};\n\nexport const transcode = ({\n  blob,\n  encoder = encodeToWaw,\n  sampleRate,\n}: TranscodeParams): Promise<Blob> =>\n  encoder(\n    createFileFromBlobs({\n      blobsArray: [blob],\n      fileName: `audio_recording_${new Date().toISOString()}.${getExtensionFromMimeType(\n        blob.type,\n      )}`,\n      mimeType: blob.type,\n    }),\n    sampleRate,\n  );\n","import fixWebmDuration from 'fix-webm-duration';\nimport { nanoid } from 'nanoid';\nimport {\n  AmplitudeRecorder,\n  DEFAULT_AMPLITUDE_RECORDER_CONFIG,\n} from './AmplitudeRecorder';\nimport { BrowserPermission } from './BrowserPermission';\nimport { BehaviorSubject, Subject } from '../observable';\nimport type { TranscoderConfig } from '../transcode';\nimport { transcode } from '../transcode';\nimport { resampleWaveformData } from '../../Attachment';\nimport type { RecordedMediaType } from '../../ReactFileUtilities';\nimport {\n  createFileFromBlobs,\n  getExtensionFromMimeType,\n  getRecordedMediaTypeFromMimeType,\n} from '../../ReactFileUtilities';\nimport { defaultTranslatorFunction } from '../../../i18n';\nimport { mergeDeepUndefined } from '../../../utils/mergeDeep';\nimport type { LocalVoiceRecordingAttachment } from 'stream-chat';\nimport type { AmplitudeRecorderConfig } from './AmplitudeRecorder';\nimport type { TranslationContextValue } from '../../../context';\n\nexport const RECORDED_MIME_TYPE_BY_BROWSER = {\n  audio: {\n    others: 'audio/webm',\n    safari: 'audio/mp4;codecs=mp4a.40.2',\n  },\n} as const;\n\nexport const DEFAULT_AUDIO_TRANSCODER_CONFIG: TranscoderConfig = {\n  sampleRate: 16000,\n} as const;\n\nconst disposeOfMediaStream = (stream?: MediaStream) => {\n  if (!stream?.active) return;\n  stream.getTracks().forEach((track) => {\n    track.stop();\n    stream.removeTrack(track);\n  });\n};\n\nconst logError = (e?: Error) => e && console.error('[MEDIA RECORDER ERROR]', e);\n\ntype MediaRecorderConfig = Omit<MediaRecorderOptions, 'mimeType'> &\n  Required<Pick<MediaRecorderOptions, 'mimeType'>>;\n\nexport type AudioRecorderConfig = {\n  amplitudeRecorderConfig: AmplitudeRecorderConfig;\n  mediaRecorderConfig: MediaRecorderOptions;\n  transcoderConfig: TranscoderConfig;\n};\n\ntype PartialValues<T> = { [P in keyof T]?: Partial<T[P]> };\n\nexport type CustomAudioRecordingConfig = PartialValues<AudioRecorderConfig>;\n\nexport type AudioRecorderOptions = {\n  config?: CustomAudioRecordingConfig;\n  generateRecordingTitle?: (mimeType: string) => string;\n  t?: TranslationContextValue['t'];\n};\n\nexport enum MediaRecordingState {\n  PAUSED = 'paused',\n  RECORDING = 'recording',\n  STOPPED = 'stopped',\n}\n\nexport enum RecordingAttachmentType {\n  VOICE_RECORDING = 'voiceRecording',\n}\n\nexport class MediaRecorderController {\n  permission: BrowserPermission;\n  mediaRecorder: MediaRecorder | undefined;\n  amplitudeRecorder: AmplitudeRecorder | undefined;\n\n  amplitudeRecorderConfig: AmplitudeRecorderConfig;\n  mediaRecorderConfig: MediaRecorderConfig;\n  transcoderConfig: TranscoderConfig;\n\n  startTime: number | undefined;\n  recordedChunkDurations: number[] = [];\n  recordedData: Blob[] = [];\n  recordingUri: string | undefined;\n  mediaType: RecordedMediaType;\n\n  signalRecordingReady: ((r: LocalVoiceRecordingAttachment) => void) | undefined;\n\n  recordingState = new BehaviorSubject<MediaRecordingState | undefined>(undefined);\n  recording = new BehaviorSubject<LocalVoiceRecordingAttachment | undefined>(undefined);\n  error = new Subject<Error | undefined>();\n  notification = new Subject<{ text: string; type: 'success' | 'error' } | undefined>();\n\n  customGenerateRecordingTitle: ((mimeType: string) => string) | undefined;\n  t: TranslationContextValue['t'];\n\n  constructor({ config, generateRecordingTitle, t }: AudioRecorderOptions = {}) {\n    this.t = t || defaultTranslatorFunction;\n\n    this.amplitudeRecorderConfig = mergeDeepUndefined(\n      { ...config?.amplitudeRecorderConfig },\n      DEFAULT_AMPLITUDE_RECORDER_CONFIG,\n    );\n\n    this.mediaRecorderConfig = mergeDeepUndefined(\n      { ...config?.mediaRecorderConfig },\n      {\n        mimeType: MediaRecorder.isTypeSupported('audio/webm')\n          ? RECORDED_MIME_TYPE_BY_BROWSER.audio.others\n          : RECORDED_MIME_TYPE_BY_BROWSER.audio.safari,\n      },\n    );\n\n    this.transcoderConfig = mergeDeepUndefined(\n      { ...config?.transcoderConfig },\n      DEFAULT_AUDIO_TRANSCODER_CONFIG,\n    );\n\n    const mediaType = getRecordedMediaTypeFromMimeType(this.mediaRecorderConfig.mimeType);\n    if (!mediaType) {\n      throw new Error(\n        `Unsupported media type (supported audio or video only). Provided mimeType: ${this.mediaRecorderConfig.mimeType}`,\n      );\n    }\n    this.mediaType = mediaType;\n\n    this.permission = new BrowserPermission({ mediaType });\n\n    this.customGenerateRecordingTitle = generateRecordingTitle;\n  }\n\n  get durationMs() {\n    return this.recordedChunkDurations.reduce((acc, val) => acc + val, 0);\n  }\n\n  generateRecordingTitle = (mimeType: string) => {\n    if (this.customGenerateRecordingTitle) {\n      return this.customGenerateRecordingTitle(mimeType);\n    }\n    return `${this.mediaType}_recording_${new Date().toISOString()}.${getExtensionFromMimeType(\n      mimeType,\n    )}`; // extension needed so that desktop Safari can play the asset\n  };\n\n  makeVoiceRecording = async () => {\n    if (this.recordingUri) URL.revokeObjectURL(this.recordingUri);\n\n    if (!this.recordedData.length) return;\n    const { mimeType } = this.mediaRecorderConfig;\n    let blob = new Blob(this.recordedData, { type: mimeType });\n    if (mimeType.match('audio/webm')) {\n      // The browser does not include duration metadata with the recorded blob\n      blob = await fixWebmDuration(blob, this.durationMs, {\n        logger: () => null, // prevents polluting the browser console\n      });\n    }\n    if (!mimeType.match('audio/mp4')) {\n      blob = await transcode({\n        blob,\n        ...this.transcoderConfig,\n      });\n    }\n\n    if (!blob) return;\n\n    this.recordingUri = URL.createObjectURL(blob);\n    const file = createFileFromBlobs({\n      blobsArray: [blob],\n      fileName: this.generateRecordingTitle(blob.type),\n      mimeType: blob.type,\n    });\n\n    return {\n      asset_url: this.recordingUri,\n      duration: this.durationMs / 1000,\n      file_size: blob.size,\n      localMetadata: {\n        file,\n        id: nanoid(),\n      },\n      mime_type: blob.type,\n      title: file.name,\n      type: RecordingAttachmentType.VOICE_RECORDING,\n      waveform_data: resampleWaveformData(\n        this.amplitudeRecorder?.amplitudes.value ?? [],\n        this.amplitudeRecorderConfig.sampleCount,\n      ),\n    } as LocalVoiceRecordingAttachment;\n  };\n\n  handleErrorEvent = (e: Event) => {\n    const { error } = e as ErrorEvent;\n    logError(error);\n    this.error.next(error);\n    this.notification.next({\n      text: this.t('An error has occurred during recording'),\n      type: 'error',\n    });\n  };\n\n  handleDataavailableEvent = async (e: BlobEvent) => {\n    if (!e.data.size) return;\n    if (this.mediaType !== 'audio') return;\n    try {\n      this.recordedData.push(e.data);\n      const recording = await this.makeVoiceRecording();\n      if (!recording) return;\n      this.signalRecordingReady?.(recording);\n      this.recording.next(recording);\n    } catch (e) {\n      logError(e as Error);\n      this.error.next(e as Error);\n      this.notification.next({\n        text: this.t('An error has occurred during the recording processing'),\n        type: 'error',\n      });\n    }\n  };\n\n  resetRecordingState = () => {\n    this.recordedData = [];\n    this.recording.next(undefined);\n    this.recordingState.next(undefined);\n    this.recordedChunkDurations = [];\n    this.startTime = undefined;\n  };\n\n  cleanUp = () => {\n    this.resetRecordingState();\n    if (this.recordingUri) URL.revokeObjectURL(this.recordingUri);\n    this.amplitudeRecorder?.close();\n    if (this.mediaRecorder) {\n      disposeOfMediaStream(this.mediaRecorder.stream);\n      this.mediaRecorder.removeEventListener(\n        'dataavailable',\n        this.handleDataavailableEvent,\n      );\n      this.mediaRecorder.removeEventListener('error', this.handleErrorEvent);\n    }\n  };\n\n  start = async () => {\n    if (\n      [MediaRecordingState.RECORDING, MediaRecordingState.PAUSED].includes(\n        this.recordingState.value as MediaRecordingState,\n      )\n    ) {\n      const error = new Error('Cannot start recording. Recording already in progress');\n      logError(error);\n      this.error.next(error);\n      return;\n    }\n\n    // account for requirement on iOS as per this bug report: https://bugs.webkit.org/show_bug.cgi?id=252303\n    if (!navigator.mediaDevices) {\n      const error = new Error('Media recording is not supported');\n      logError(error);\n      this.error.next(error);\n      this.notification.next({ text: this.t('Error starting recording'), type: 'error' });\n      return;\n    }\n\n    if (this.mediaType === 'video') {\n      const error = new Error(\n        `Video recording is not supported. Provided MIME type: ${this.mediaRecorderConfig.mimeType}`,\n      );\n      logError(error);\n      this.error.next(error);\n      this.notification.next({ text: this.t('Error starting recording'), type: 'error' });\n      return;\n    }\n\n    if (!this.permission.state.value) {\n      await this.permission.check();\n    }\n\n    if (this.permission.state.value === 'denied') {\n      logError(new Error('Permission denied'));\n      return;\n    }\n\n    try {\n      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n      this.mediaRecorder = new MediaRecorder(stream, this.mediaRecorderConfig);\n\n      this.mediaRecorder.addEventListener('dataavailable', this.handleDataavailableEvent);\n      this.mediaRecorder.addEventListener('error', this.handleErrorEvent);\n\n      this.startTime = new Date().getTime();\n      this.mediaRecorder.start();\n\n      if (this.mediaType === 'audio' && stream) {\n        this.amplitudeRecorder = new AmplitudeRecorder({\n          config: this.amplitudeRecorderConfig,\n          stream,\n        });\n        this.amplitudeRecorder.start();\n      }\n\n      this.recordingState.next(MediaRecordingState.RECORDING);\n    } catch (error) {\n      logError(error as Error);\n      this.cancel();\n      this.error.next(error as Error);\n      this.notification.next({ text: this.t('Error starting recording'), type: 'error' });\n    }\n  };\n\n  pause = () => {\n    if (this.recordingState.value !== MediaRecordingState.RECORDING) return;\n    if (this.startTime) {\n      this.recordedChunkDurations.push(new Date().getTime() - this.startTime);\n      this.startTime = undefined;\n    }\n    this.mediaRecorder?.pause();\n    // Flush current chunk so preview is available while paused.\n    this.mediaRecorder?.requestData();\n    this.amplitudeRecorder?.stop();\n    this.recordingState.next(MediaRecordingState.PAUSED);\n  };\n\n  resume = () => {\n    if (this.recordingState.value !== MediaRecordingState.PAUSED) return;\n    this.startTime = new Date().getTime();\n    this.mediaRecorder?.resume();\n    this.amplitudeRecorder?.start();\n    this.recordingState.next(MediaRecordingState.RECORDING);\n  };\n\n  stop = () => {\n    const recording = this.recording.value;\n    if (recording && this.mediaRecorder?.state === 'inactive')\n      return Promise.resolve(recording);\n\n    if (\n      ![MediaRecordingState.PAUSED, MediaRecordingState.RECORDING].includes(\n        (this.mediaRecorder?.state || '') as MediaRecordingState,\n      )\n    )\n      return Promise.resolve(undefined);\n\n    if (this.startTime) {\n      this.recordedChunkDurations.push(new Date().getTime() - this.startTime);\n      this.startTime = undefined;\n    }\n    const result = new Promise<LocalVoiceRecordingAttachment>((res) => {\n      this.signalRecordingReady = res;\n    });\n    this.mediaRecorder?.stop();\n    this.amplitudeRecorder?.stop();\n    this.recordingState.next(MediaRecordingState.STOPPED);\n    return result;\n  };\n\n  cancel = () => {\n    this.stop();\n    this.cleanUp();\n  };\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport { MediaRecorderController } from '../classes';\nimport { useTranslationContext } from '../../../context';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\n\nimport type { LocalVoiceRecordingAttachment } from 'stream-chat';\nimport type { CustomAudioRecordingConfig, MediaRecordingState } from '../classes';\nimport type { MessageComposerContextValue } from '../../../context';\n\nexport type RecordingController = {\n  completeRecording: () => void;\n  permissionState?: PermissionState;\n  recorder?: MediaRecorderController;\n  recording?: LocalVoiceRecordingAttachment;\n  recordingState?: MediaRecordingState;\n};\n\ntype UseMediaRecorderParams = Pick<\n  MessageComposerContextValue,\n  'asyncMessagesMultiSendEnabled' | 'handleSubmit'\n> & {\n  enabled: boolean;\n  generateRecordingTitle?: (mimeType: string) => string;\n  recordingConfig?: CustomAudioRecordingConfig;\n};\n\nexport const useMediaRecorder = ({\n  asyncMessagesMultiSendEnabled,\n  enabled,\n  generateRecordingTitle,\n  handleSubmit,\n  recordingConfig,\n}: UseMediaRecorderParams): RecordingController => {\n  const { t } = useTranslationContext('useMediaRecorder');\n  const messageComposer = useMessageComposerController();\n  const [recording, setRecording] = useState<LocalVoiceRecordingAttachment>();\n  const [recordingState, setRecordingState] = useState<MediaRecordingState>();\n  const [permissionState, setPermissionState] = useState<PermissionState>();\n  const [isScheduledForSubmit, scheduleForSubmit] = useState(false);\n\n  const recorder = useMemo(\n    () =>\n      enabled\n        ? new MediaRecorderController({\n            config: recordingConfig ?? {},\n            generateRecordingTitle,\n            t,\n          })\n        : undefined,\n    [recordingConfig, enabled, generateRecordingTitle, t],\n  );\n\n  const completeRecording = useCallback(async () => {\n    if (!recorder) return;\n    const recording = await recorder.stop();\n    if (!recording) return;\n    await messageComposer.attachmentManager.uploadAttachment(recording);\n    if (!asyncMessagesMultiSendEnabled) {\n      // FIXME: cannot call handleSubmit() directly as the function has stale reference to attachments\n      scheduleForSubmit(true);\n    }\n    recorder.cleanUp();\n  }, [asyncMessagesMultiSendEnabled, messageComposer, recorder]);\n\n  useEffect(() => {\n    if (!isScheduledForSubmit) return;\n    handleSubmit();\n    scheduleForSubmit(false);\n  }, [handleSubmit, isScheduledForSubmit]);\n\n  useEffect(() => {\n    if (!recorder) return;\n    recorder.permission.watch();\n    const recordingSubscription = recorder.recording.subscribe(setRecording);\n    const recordingStateSubscription =\n      recorder.recordingState.subscribe(setRecordingState);\n    const permissionStateSubscription =\n      recorder.permission.state.subscribe(setPermissionState);\n\n    return () => {\n      recorder.cancel();\n      recorder.permission.unwatch();\n      recordingSubscription.unsubscribe();\n      recordingStateSubscription.unsubscribe();\n      permissionStateSubscription.unsubscribe();\n    };\n  }, [recorder]);\n\n  return {\n    completeRecording,\n    permissionState,\n    recorder,\n    recording,\n    recordingState,\n  };\n};\n","import type React from 'react';\nimport { useTextareaRef } from './useTextareaRef';\nimport { useSubmitHandler } from './useSubmitHandler';\nimport { usePasteHandler } from './usePasteHandler';\nimport type { RecordingController } from '../../MediaRecorder/hooks/useMediaRecorder';\nimport { useMediaRecorder } from '../../MediaRecorder/hooks/useMediaRecorder';\nimport type { MessageComposerProps } from '../MessageComposer';\n\nexport type UseMessageComposerBindingsParams = {\n  handleSubmit: (event?: React.BaseSyntheticEvent) => void;\n  onPaste: (event: React.ClipboardEvent<HTMLTextAreaElement>) => void;\n  recordingController: RecordingController;\n  textareaRef: React.RefObject<HTMLTextAreaElement | null | undefined>;\n};\n\nexport const useMessageComposerBindings = (\n  props: MessageComposerProps,\n): UseMessageComposerBindingsParams => {\n  const { asyncMessagesMultiSendEnabled, audioRecordingConfig, audioRecordingEnabled } =\n    props;\n\n  const { textareaRef } = useTextareaRef(props);\n\n  const { handleSubmit } = useSubmitHandler(props);\n\n  const recordingController = useMediaRecorder({\n    asyncMessagesMultiSendEnabled,\n    enabled: !!audioRecordingEnabled,\n    handleSubmit,\n    recordingConfig: audioRecordingConfig,\n  });\n\n  const { onPaste } = usePasteHandler();\n\n  return {\n    handleSubmit,\n    onPaste,\n    recordingController,\n    textareaRef,\n  };\n};\n","import { useMemo } from 'react';\nimport type { CommandResponse, MessageComposerState } from 'stream-chat';\n\nimport { useStateStore } from '../../../store';\nimport { useMessageComposerController } from './useMessageComposerController';\n\nconst messageComposerStateSelector = ({\n  editedMessage,\n  quotedMessage,\n}: MessageComposerState) => ({\n  editedMessage,\n  quotedMessage,\n});\n\nexport type MessageComposerCommand = {\n  command: CommandResponse & { name: string };\n  enabled: boolean;\n};\n\nexport const useMessageComposerCommands = () => {\n  const messageComposer = useMessageComposerController();\n  const channelConfig = messageComposer.channel.getConfig();\n  const { editedMessage, quotedMessage } = useStateStore(\n    messageComposer.state,\n    messageComposerStateSelector,\n  );\n\n  return useMemo<MessageComposerCommand[]>(\n    () =>\n      (channelConfig?.commands ?? [])\n        .filter(\n          (command): command is CommandResponse & { name: string } => !!command.name,\n        )\n        .map((command) => ({\n          command,\n          enabled: !messageComposer.isCommandDisabled(command),\n        })),\n    // editedMessage and quotedMessage are necessary in deps for reactivity\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [channelConfig, editedMessage, messageComposer, quotedMessage],\n  );\n};\n","import { useMessageComposerController } from './useMessageComposerController';\nimport { useStateStore } from '../../../store';\nimport type { EditingAuditState } from 'stream-chat';\n\nconst editingAuditStateStateSelector = (state: EditingAuditState) => state;\n\nexport const useMessageComposerHasSendableData = () => {\n  const messageComposer = useMessageComposerController();\n  useStateStore(messageComposer.editingAuditState, editingAuditStateStateSelector);\n  return messageComposer.hasSendableData;\n};\n","import type { EditingAuditState } from 'stream-chat';\nimport { useMessageComposerController } from './useMessageComposerController';\nimport { useStateStore } from '../../../store';\n\nconst editingAuditStateStateSelector = (state: EditingAuditState) => state;\n\nexport const useMessageContentIsEmpty = () => {\n  const messageComposer = useMessageComposerController();\n  useStateStore(messageComposer.editingAuditState, editingAuditStateStateSelector);\n  return messageComposer.contentIsEmpty;\n};\n","import clsx from 'clsx';\nimport { IconXmarkSmall } from '../Icons';\nimport { Button } from '../Button';\nimport React, { type ComponentProps } from 'react';\nimport { useTranslationContext } from '../../context';\nimport type { AttachmentLoadingState } from 'stream-chat';\n\nexport const RemoveAttachmentPreviewButton = ({\n  className,\n  uploadState,\n  ...props\n}: ComponentProps<'button'> & {\n  uploadState?: AttachmentLoadingState;\n}) => {\n  const { t } = useTranslationContext();\n  return (\n    <Button\n      aria-label={t('aria/Remove attachment')}\n      circular\n      className={clsx('str-chat__attachment-preview__remove-button', className)}\n      data-testid='preview-item-delete-button'\n      disabled={uploadState === 'uploading'}\n      {...props}\n    >\n      <IconXmarkSmall />\n    </Button>\n  );\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nexport const QuotedMessageIndicator = ({ isOwnMessage }: { isOwnMessage?: boolean }) => (\n  <div\n    className={clsx('str-chat__quoted-message-indicator', {\n      'str-chat__quoted-message-indicator--own-message': isOwnMessage,\n    })}\n  />\n);\n","import React, {\n  type ComponentType,\n  type KeyboardEvent,\n  type MouseEventHandler,\n  type ReactElement,\n  type ReactNode,\n  useMemo,\n} from 'react';\n\nimport { displayDuration, SUPPORTED_VIDEO_FORMATS } from '../Attachment';\n\nimport { useChatContext } from '../../context/ChatContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\n\nimport { useStateStore } from '../../store';\nimport { useMessageComposerController } from './hooks';\nimport {\n  type Attachment,\n  type GiphyVersions,\n  isAudioAttachment,\n  isFileAttachment,\n  isGiphyAttachment,\n  isImageAttachment,\n  isScrapedContent,\n  isVideoAttachment,\n  isVoiceRecordingAttachment,\n  type LocalMessage,\n  type LocalMessageBase,\n  type MessageComposerState,\n  type PollResponse,\n  type SharedLocationResponse,\n  type TranslationLanguages,\n} from 'stream-chat';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport type { MessageContextValue } from '../../context';\nimport { RemoveAttachmentPreviewButton } from './RemoveAttachmentPreviewButton';\nimport {\n  IconCamera,\n  IconFile,\n  IconLink,\n  IconLocation,\n  IconPlayFill,\n  IconPoll,\n  IconVideo,\n  IconVoice,\n} from '../Icons';\nimport clsx from 'clsx';\nimport { BaseImage } from '../BaseImage';\nimport { FileIcon } from '../FileIcon';\nimport { QuotedMessageIndicator } from './QuotedMessageIndicator';\n\nconst messageComposerStateStoreSelector = (state: MessageComposerState) => ({\n  quotedMessage: state.quotedMessage,\n});\n\nexport type QuotedMessagePreviewProps = {\n  getQuotedMessageAuthor?: (message: LocalMessage) => string;\n  renderText?: MessageContextValue['renderText'];\n};\n\nconst NullAttachmentIcon = () => null;\n\nconst QUOTED_GIPHY_PREVIEW_LABEL = 'Giphy';\n\ntype AttachmentType = 'documents' | 'images' | 'links' | 'videos' | 'voiceRecordings';\n\n/** Giphy GIFs: only native type (e.g. /giphy command) is recognized as Giphy. */\nconst isQuotedGiphyAttachment = (attachment: Attachment) => isGiphyAttachment(attachment);\n\nconst getAttachmentType = (attachment: Attachment) => {\n  if (isQuotedGiphyAttachment(attachment)) {\n    return 'giphy';\n  }\n  if (isScrapedContent(attachment)) {\n    return 'link';\n  } else if (isVideoAttachment(attachment, SUPPORTED_VIDEO_FORMATS)) {\n    return 'video';\n  } else if (isImageAttachment(attachment)) {\n    return 'image';\n  } else if (isAudioAttachment(attachment)) {\n    return 'audio';\n  } else if (isVoiceRecordingAttachment(attachment)) {\n    return 'voiceRecording';\n  } else if (isFileAttachment(attachment, SUPPORTED_VIDEO_FORMATS)) {\n    return 'file';\n  }\n\n  return 'unsupported';\n};\n\ntype GroupedAttachments = Record<AttachmentType, Attachment[]> & {\n  giphies: Attachment[];\n  locations: SharedLocationResponse[];\n  polls: PollResponse[];\n  total: number;\n};\n\nconst getGroupedAttachments = (quotedMessage: LocalMessage | null) => {\n  const groupedAttachments = {\n    documents: [],\n    giphies: [],\n    images: [],\n    links: [],\n    locations: [],\n    polls: [],\n    total: 0,\n    videos: [],\n    voiceRecordings: [],\n  };\n\n  if (!quotedMessage || !quotedMessage.attachments) return groupedAttachments;\n\n  const result = quotedMessage.attachments.reduce<GroupedAttachments>(\n    (count, attachment) => {\n      switch (getAttachmentType(attachment)) {\n        case 'giphy':\n          count.giphies.push(attachment);\n          count.total += 1;\n          break;\n        case 'link':\n          count.links.push(attachment);\n          count.total += 1;\n          break;\n        case 'video':\n          count.videos.push(attachment);\n          count.total += 1;\n          break;\n        case 'voiceRecording':\n          count.voiceRecordings.push(attachment);\n          count.total += 1;\n          break;\n        case 'audio':\n        case 'file':\n          count.documents.push(attachment);\n          count.total += 1;\n          break;\n        default:\n          if (isImageAttachment(attachment)) {\n            count.images.push(attachment);\n            count.total += 1;\n          }\n      }\n\n      return count;\n    },\n    groupedAttachments,\n  );\n  if (quotedMessage.shared_location) {\n    result.locations.push(quotedMessage.shared_location);\n    result.total += 1;\n  } else if (quotedMessage.poll) {\n    result.polls.push(quotedMessage.poll);\n    result.total += 1;\n  }\n\n  return result;\n};\n\ntype PreviewType =\n  | 'voice'\n  | 'file'\n  | 'image'\n  | 'giphy'\n  | 'link'\n  | 'location'\n  | 'poll'\n  | 'video'\n  | 'mixed';\n\nconst getAttachmentIconWithType = (\n  quotedMessage: LocalMessage | null,\n  giphyVersionName: GiphyVersions,\n): {\n  groupedAttachments: GroupedAttachments;\n  Icon: ComponentType;\n  PreviewImage: ReactElement | null;\n  previewType: PreviewType | null;\n} => {\n  const groupedAttachments = getGroupedAttachments(quotedMessage);\n  const result = {\n    groupedAttachments,\n    Icon: NullAttachmentIcon,\n    PreviewImage: null,\n    previewType: null,\n  };\n  if (!groupedAttachments.total) return result;\n  if (groupedAttachments.polls.length > 0)\n    return { ...result, Icon: IconPoll, previewType: 'poll' };\n  if (groupedAttachments.locations.length > 0)\n    // todo: we do not generate the location preview image\n    return { ...result, Icon: IconLocation, previewType: 'location' };\n  if (\n    groupedAttachments.giphies.length > 0 &&\n    groupedAttachments.giphies.length === groupedAttachments.total\n  ) {\n    const giphyAttachment = groupedAttachments.giphies[0] as Attachment & {\n      giphy?: Record<string, { url?: string } | undefined>;\n    };\n    const giphyVersion =\n      giphyAttachment.giphy?.[giphyVersionName as keyof NonNullable<Attachment['giphy']>];\n    const src =\n      giphyVersion?.url || giphyAttachment.thumb_url || giphyAttachment.image_url || '';\n    return {\n      ...result,\n      Icon: IconFile,\n      PreviewImage: (\n        <BaseImage\n          alt={QUOTED_GIPHY_PREVIEW_LABEL}\n          className='str-chat__attachment-preview__thumbnail'\n          src={src}\n          title={QUOTED_GIPHY_PREVIEW_LABEL}\n        />\n      ),\n      previewType: 'giphy',\n    };\n  }\n  if (\n    groupedAttachments.documents.length === groupedAttachments.total &&\n    groupedAttachments.documents.length === 1\n  ) {\n    const fileAttachment = groupedAttachments.documents[0] as Attachment;\n    return {\n      ...result,\n      Icon: IconFile,\n      PreviewImage: (\n        <FileIcon fileName={fileAttachment.title} mimeType={fileAttachment.mime_type} />\n      ),\n      previewType: 'file',\n    };\n  }\n  if (groupedAttachments.links.length === groupedAttachments.total) {\n    const linkAttachment = groupedAttachments.links[0];\n    return {\n      ...result,\n      Icon: IconLink,\n      PreviewImage: (\n        <BaseImage\n          alt={linkAttachment.title}\n          className='str-chat__attachment-preview__thumbnail'\n          src={linkAttachment.thumb_url || linkAttachment.image_url}\n          title={linkAttachment.title}\n        />\n      ),\n      previewType: 'link',\n    };\n  }\n  if (groupedAttachments.videos.length === groupedAttachments.total) {\n    const videoAttachment = groupedAttachments.videos[0];\n    return {\n      ...result,\n      Icon: IconVideo,\n      PreviewImage: (\n        <>\n          <BaseImage\n            alt={videoAttachment.asset_url}\n            className='str-chat__attachment-preview__thumbnail'\n            src={videoAttachment.thumb_url}\n            title={videoAttachment.title}\n          />\n          <div className='str-chat__attachment-preview__thumbnail__play-indicator'>\n            <IconPlayFill />\n          </div>\n        </>\n      ),\n      previewType: 'video',\n    };\n  }\n  if (groupedAttachments.images.length === groupedAttachments.total) {\n    const imageAttachment = groupedAttachments.images[0];\n    return {\n      ...result,\n      Icon: IconCamera,\n      PreviewImage: (\n        <BaseImage\n          alt={imageAttachment.fallback}\n          className='str-chat__attachment-preview__thumbnail'\n          src={imageAttachment.image_url}\n          title={imageAttachment.title}\n        />\n      ),\n      previewType: 'image',\n    };\n  }\n  if (groupedAttachments.voiceRecordings.length === groupedAttachments.total)\n    return { ...result, Icon: IconVoice, previewType: 'voice' };\n\n  return { ...result, Icon: IconFile, previewType: 'mixed' };\n};\n\nexport const QuotedMessagePreview = ({\n  getQuotedMessageAuthor,\n  renderText,\n}: QuotedMessagePreviewProps) => {\n  const messageComposer = useMessageComposerController();\n  const { quotedMessage } = useStateStore(\n    messageComposer.state,\n    messageComposerStateStoreSelector,\n  );\n\n  return quotedMessage ? (\n    <div className='str-chat__message-composer__quoted-message-preview-slot'>\n      <QuotedMessagePreviewUI\n        getQuotedMessageAuthor={getQuotedMessageAuthor}\n        onRemove={() => messageComposer.setQuotedMessage(null)}\n        quotedMessage={quotedMessage}\n        renderText={renderText}\n      />\n    </div>\n  ) : null;\n};\n\ntype QuotedMessagePreviewUIProps = QuotedMessagePreviewProps & {\n  quotedMessage: LocalMessageBase;\n  authorLabel?: ReactNode;\n  className?: string;\n  onClick?: MouseEventHandler<HTMLDivElement>;\n  onRemove?: () => void;\n};\n\nexport const QuotedMessagePreviewUI = ({\n  authorLabel,\n  className,\n  getQuotedMessageAuthor,\n  onClick,\n  onRemove,\n  quotedMessage,\n  renderText,\n}: QuotedMessagePreviewUIProps) => {\n  const { client } = useChatContext();\n  const { t, userLanguage } = useTranslationContext();\n  const { giphyVersion: giphyVersionName = 'fixed_height' } =\n    useChannelStateContext('QuotedMessagePreview');\n\n  const quotedMessageText = useMemo(\n    () =>\n      quotedMessage?.i18n?.[`${userLanguage}_text` as `${TranslationLanguages}_text`] ||\n      quotedMessage?.text,\n    [quotedMessage?.i18n, quotedMessage?.text, userLanguage],\n  );\n\n  const { AttachmentIcon, PreviewImage, renderedText } = useMemo(() => {\n    if (!quotedMessage) return { AttachmentIcon: NullAttachmentIcon, renderedText: null };\n\n    const {\n      groupedAttachments,\n      Icon: AttachmentIcon,\n      PreviewImage,\n      previewType,\n    } = getAttachmentIconWithType(quotedMessage, giphyVersionName);\n\n    let renderedText: ReactNode | undefined;\n\n    if (!quotedMessageText) {\n      if (previewType === 'poll') {\n        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n        renderedText = quotedMessage.poll!.name;\n      } else if (previewType === 'location') {\n        renderedText = t('Live location');\n      } else if (previewType === 'voice') {\n        {\n          const voiceRecording = groupedAttachments.voiceRecordings[0];\n          renderedText = t('Voice message {{ duration }}', {\n            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n            duration: displayDuration(voiceRecording!.duration),\n          });\n        }\n      } else if (previewType === 'giphy') {\n        renderedText = QUOTED_GIPHY_PREVIEW_LABEL;\n      } else if (previewType === 'link') {\n        renderedText = groupedAttachments.links[0].title;\n      } else if (previewType === 'mixed') {\n        renderedText = t('{{ count }} files', { count: groupedAttachments.total });\n      } else if (previewType === 'video') {\n        renderedText =\n          groupedAttachments.videos.length === 1\n            ? t('Video')\n            : t('{{ count }} videos', {\n                count: groupedAttachments.videos.length,\n              });\n      } else if (previewType === 'file') {\n        renderedText = groupedAttachments.documents[0].title;\n      } else if (previewType === 'image') {\n        renderedText =\n          groupedAttachments.images.length === 1\n            ? t('Photo')\n            : t('{{ count }} photos', {\n                count: groupedAttachments.images.length,\n              });\n      }\n    } else if (renderText) {\n      renderedText = renderText(quotedMessageText, quotedMessage?.mentioned_users);\n    } else {\n      renderedText = quotedMessageText;\n    }\n\n    return {\n      AttachmentIcon,\n      PreviewImage,\n      renderedText,\n    };\n  }, [giphyVersionName, quotedMessage, quotedMessageText, renderText, t]);\n\n  const isOwnMessage = client.user?.id === quotedMessage?.user?.id;\n  const isInteractive = !!onClick;\n\n  const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n    if (!onClick || (event.key !== 'Enter' && event.key !== ' ')) return;\n\n    event.preventDefault();\n    onClick(event as unknown as Parameters<NonNullable<typeof onClick>>[0]);\n  };\n\n  if (!renderedText && !AttachmentIcon && !PreviewImage) return null;\n\n  const authorName = getQuotedMessageAuthor?.(quotedMessage) ?? quotedMessage.user?.name;\n  return (\n    <div\n      aria-label={isInteractive ? t('aria/Jump to quoted message') : undefined}\n      className={clsx('str-chat__quoted-message-preview', className, {\n        'str-chat__quoted-message-preview--own': isOwnMessage,\n      })}\n      data-testid='quoted-message-preview'\n      onClick={onClick}\n      onKeyDown={isInteractive ? handleKeyDown : undefined}\n      role={isInteractive ? 'button' : undefined}\n      tabIndex={isInteractive ? 0 : undefined}\n    >\n      <QuotedMessageIndicator isOwnMessage={isOwnMessage} />\n      <div className='str-chat__quoted-message-preview__content'>\n        <div className='str-chat__quoted-message-preview__author'>\n          {authorLabel ??\n            (isOwnMessage\n              ? t('You')\n              : authorName\n                ? t('Reply to {{ authorName }}', { authorName })\n                : t('Reply'))}\n        </div>\n\n        <div\n          className='str-chat__quoted-message-preview__message'\n          data-testid='quoted-message-text'\n        >\n          <AttachmentIcon />\n          <div className='str-chat__quoted-message-preview__message-text'>\n            {renderedText}\n          </div>\n        </div>\n      </div>\n      {PreviewImage && (\n        <div className='str-chat__quoted-message-preview__image'>{PreviewImage}</div>\n      )}\n\n      {onRemove && (\n        <RemoveAttachmentPreviewButton\n          aria-label={t('aria/Cancel Reply')}\n          data-testid='quoted-message-preview-dismiss-btn'\n          onClick={onRemove}\n        />\n      )}\n    </div>\n  );\n};\n","import React from 'react';\nimport type { MessageContextValue } from '../../context/MessageContext';\nimport { useMessageContext } from '../../context/MessageContext';\nimport { useChannelActionContext } from '../../context/ChannelActionContext';\nimport { QuotedMessagePreviewUI } from '../MessageComposer/QuotedMessagePreview';\n\nexport type QuotedMessageProps = Pick<MessageContextValue, 'renderText'>;\n\nexport const QuotedMessage = ({ renderText: propsRenderText }: QuotedMessageProps) => {\n  const { message, renderText: contextRenderText } = useMessageContext('QuotedMessage');\n  const { jumpToMessage } = useChannelActionContext('QuotedMessage');\n\n  const renderText = propsRenderText ?? contextRenderText;\n\n  const { quoted_message } = message;\n\n  return quoted_message ? (\n    <QuotedMessagePreviewUI\n      onClick={(e) => {\n        if (!quoted_message) return;\n        e.stopPropagation();\n        e.preventDefault();\n        jumpToMessage(quoted_message.id);\n      }}\n      quotedMessage={quoted_message}\n      renderText={renderText}\n    />\n  ) : null;\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../context';\nimport { useStateStore } from '../../store';\nimport type { Reminder, ReminderState } from 'stream-chat';\nimport { IconBell, IconBookmark } from '../Icons';\n\nexport type ReminderNotificationProps = {\n  reminder?: Reminder;\n};\n\nconst reminderStateSelector = (state: ReminderState) => ({\n  timeLeftMs: state.timeLeftMs,\n});\n\nfunction SavedForLaterContent() {\n  const { t } = useTranslationContext();\n  return (\n    <div className='str-chat__message-saved-for-later'>\n      <IconBookmark />\n      <span>{t('Saved for later')}</span>\n    </div>\n  );\n}\n\nconst THRESHOLD_RELATIVE_MINUTES = 59;\n\nfunction RemindMeContent({ reminder }: { reminder: Reminder }) {\n  const { t } = useTranslationContext();\n  const { timeLeftMs } = useStateStore(reminder?.state, reminderStateSelector) ?? {};\n\n  const stopRefreshBoundaryMs = reminder?.timer.stopRefreshBoundaryMs;\n  const stopRefreshTimeStamp =\n    reminder?.remindAt && stopRefreshBoundaryMs\n      ? reminder.remindAt.getTime() + stopRefreshBoundaryMs\n      : undefined;\n\n  const isBehindRefreshBoundary =\n    !!stopRefreshTimeStamp && new Date().getTime() > stopRefreshTimeStamp;\n\n  if (timeLeftMs === null || !reminder.remindAt) return null;\n\n  const nowMs = Date.now();\n  const remindAtMs = reminder.remindAt.getTime();\n  const diffMs = remindAtMs - nowMs;\n  const diffMinutes = Math.abs(diffMs) / (60 * 1000);\n  const useAbsoluteFormat = diffMinutes > THRESHOLD_RELATIVE_MINUTES;\n\n  const renderTime = () => {\n    if (isBehindRefreshBoundary) {\n      // Past: reminder time has passed\n      if (useAbsoluteFormat) {\n        // > 59 min ago: calendar + time (same as DateSeparator + HH:mm)\n        // e.g. \"Due since Today at 15:00\", \"Due since Yesterday at 09:30\"\n        return t('Due since {{ dueSince }}', {\n          dueSince: t('timestamp/ReminderNotification', {\n            timestamp: reminder.remindAt,\n          }),\n        });\n      }\n      // Within 59 min ago: relative\n      // e.g. \"Due since 5 minutes ago\", \"Due since a minute ago\"\n      return t('Due since {{ dueSince }}', {\n        dueSince: t('duration/Message reminder', {\n          milliseconds: diffMs,\n        }),\n      });\n    }\n    // Future: reminder not yet due\n    if (useAbsoluteFormat) {\n      // > 59 min from now: calendar + time (no \"Due\" prefix)\n      // e.g. \"Today at 15:00\", \"Tomorrow at 09:30\"\n      return t('timestamp/ReminderNotification', {\n        timestamp: reminder.remindAt,\n      });\n    }\n    // Within 59 min from now: relative\n    // e.g. \"Due in 30 minutes\", \"Due in a minute\"\n    return t('Due {{ timeLeft }}', {\n      timeLeft: t('duration/Message reminder', {\n        milliseconds: timeLeftMs,\n      }),\n    });\n  };\n\n  return (\n    <p className='str-chat__message-reminder'>\n      <IconBell />\n      <span>{t('Reminder set')}</span>\n      <span> · </span>\n      <span className='str-chat__message-reminder__time-left'>{renderTime()}</span>\n    </p>\n  );\n}\n\nexport const ReminderNotification = ({ reminder }: ReminderNotificationProps) => {\n  if (!reminder) return null;\n\n  if (!reminder.remindAt) {\n    return <SavedForLaterContent />;\n  }\n\n  return <RemindMeContent reminder={reminder} />;\n};\n","import React, { useEffect } from 'react';\n\nimport type { MessageTextProps } from './MessageText';\nimport { MessageText } from './MessageText';\n\nimport { useChannelStateContext, useMessageContext } from '../../context';\nimport { useMessageTextStreaming } from './hooks';\n\nexport type StreamedMessageTextProps = Pick<\n  MessageTextProps,\n  'message' | 'renderText'\n> & {\n  renderingLetterCount?: number;\n  streamingLetterIntervalMs?: number;\n};\n\nexport const StreamedMessageText = (props: StreamedMessageTextProps) => {\n  const {\n    message: messageFromProps,\n    renderingLetterCount,\n    renderText,\n    streamingLetterIntervalMs,\n  } = props;\n  const { message: messageFromContext } = useMessageContext('StreamedMessageText');\n  const { channel } = useChannelStateContext();\n  const message = messageFromProps || messageFromContext;\n  const { text = '' } = message;\n  const { skipAnimation, streamedMessageText } = useMessageTextStreaming({\n    renderingLetterCount,\n    streamingLetterIntervalMs,\n    text,\n  });\n\n  useEffect(() => {\n    channel?.on('ai_indicator.stop', () => {\n      skipAnimation();\n    });\n  }, [channel, skipAnimation]);\n\n  return (\n    <MessageText\n      message={{ ...message, text: streamedMessageText }}\n      renderText={renderText}\n    />\n  );\n};\n","import { FocusScope } from '@react-aria/focus';\nimport clsx from 'clsx';\nimport type {\n  ComponentProps,\n  ComponentType,\n  PropsWithChildren,\n  ReactNode,\n  Ref,\n} from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { createRovingFocusKeyDownHandler } from '../../a11y/a11yUtils';\nimport {\n  type PopperLikePlacement,\n  usePopoverPosition,\n} from '../Dialog/hooks/usePopoverPosition';\n\nconst DEFAULT_DROPDOWN_ITEM_SELECTOR =\n  '[role=\"option\"]:not(:disabled), [role=\"menuitem\"]:not(:disabled), button:not(:disabled), a:not(:disabled)';\n\nconst isEditableTarget = (target: EventTarget | null) =>\n  target instanceof HTMLInputElement ||\n  target instanceof HTMLTextAreaElement ||\n  (target instanceof HTMLElement && target.isContentEditable);\n\ntype DropdownContextValue = {\n  close(): void;\n};\n\nconst DropdownContext = React.createContext<DropdownContextValue>({\n  close: () => null,\n});\n\ntype DropdownContextProviderProps = DropdownContextValue;\n\nconst DropdownContextProvider = ({\n  children,\n  ...props\n}: PropsWithChildren<DropdownContextProviderProps>) => (\n  <DropdownContext.Provider value={props}>{children}</DropdownContext.Provider>\n);\n\nexport const useDropdownContext = () => React.useContext(DropdownContext);\n\nexport type DropdownTriggerProps = Pick<\n  ComponentProps<'button'>,\n  'aria-expanded' | 'onClick'\n> & {\n  children?: ReactNode;\n  referenceRef?: Ref<HTMLElement>;\n};\n\nexport type DropdownProps = PropsWithChildren<{\n  className?: string;\n  matchReferenceWidth?: boolean;\n  onClose?: () => void;\n  onOpen?: () => void;\n  placement?: PopperLikePlacement;\n  TriggerComponent?: ComponentType<DropdownTriggerProps>;\n  triggerProps?: Omit<DropdownTriggerProps, 'aria-expanded' | 'onClick' | 'referenceRef'>;\n  referenceElement?: HTMLElement | null;\n}>;\n\nexport const Dropdown = ({\n  children,\n  className,\n  matchReferenceWidth = false,\n  onClose,\n  onOpen,\n  placement = 'bottom',\n  referenceElement,\n  TriggerComponent,\n  triggerProps,\n}: DropdownProps) => {\n  const [mountedReferenceElement, setMountedReferenceElement] =\n    useState<HTMLElement | null>(null);\n  const resolvedReferenceElement = TriggerComponent\n    ? mountedReferenceElement\n    : (referenceElement ?? null);\n  const [isOpen, setIsOpen] = useState(!TriggerComponent);\n  const [floatingElement, setFloatingElement] = useState<HTMLDivElement | null>(null);\n  const { refs, strategy, update, x, y } = usePopoverPosition({\n    placement,\n  });\n\n  useEffect(() => {\n    if (!TriggerComponent) return;\n    setIsOpen(false);\n  }, [TriggerComponent]);\n\n  const close = useCallback(() => {\n    setIsOpen(false);\n    onClose?.();\n  }, [onClose]);\n\n  const open = useCallback(() => {\n    setIsOpen(true);\n    onOpen?.();\n  }, [onOpen]);\n\n  const toggle = useCallback(() => {\n    if (isOpen) {\n      close();\n      return;\n    }\n    open();\n  }, [close, isOpen, open]);\n\n  useEffect(() => {\n    refs.setReference(resolvedReferenceElement);\n  }, [refs, resolvedReferenceElement]);\n\n  useEffect(() => {\n    refs.setFloating(floatingElement);\n  }, [floatingElement, refs]);\n\n  useEffect(() => {\n    if (!isOpen || !floatingElement || !resolvedReferenceElement) return;\n    update?.();\n  }, [floatingElement, isOpen, resolvedReferenceElement, update]);\n\n  useEffect(() => {\n    if (!isOpen) return;\n\n    const handleClickOutside = (event: MouseEvent) => {\n      if (!(event.target instanceof Node)) return;\n      if (floatingElement?.contains(event.target)) return;\n      if (resolvedReferenceElement?.contains(event.target)) return;\n      close();\n    };\n\n    document.addEventListener('mousedown', handleClickOutside);\n\n    return () => {\n      document.removeEventListener('mousedown', handleClickOutside);\n    };\n  }, [close, floatingElement, isOpen, resolvedReferenceElement]);\n\n  const rovingFocusKeyDownHandler = useMemo(\n    () =>\n      createRovingFocusKeyDownHandler<HTMLElement>({\n        getItems: (event) =>\n          Array.from(\n            event.currentTarget.querySelectorAll<HTMLElement>(\n              DEFAULT_DROPDOWN_ITEM_SELECTOR,\n            ),\n          ),\n      }),\n    [],\n  );\n\n  const escapeConsumedRef = useRef(false);\n\n  const handleKeyDown = useCallback(\n    (event: React.KeyboardEvent<HTMLElement>) => {\n      if (event.key === 'Escape') {\n        event.preventDefault();\n        event.stopPropagation();\n        escapeConsumedRef.current = true;\n        close();\n        return;\n      }\n      if (isEditableTarget(event.target)) {\n        return;\n      }\n      rovingFocusKeyDownHandler(event);\n    },\n    [close, rovingFocusKeyDownHandler],\n  );\n\n  const suppressEscapeKeyUp = useCallback((event: React.KeyboardEvent<HTMLElement>) => {\n    if (event.key === 'Escape' && escapeConsumedRef.current) {\n      escapeConsumedRef.current = false;\n      event.stopPropagation();\n    }\n  }, []);\n\n  const DropdownTriggerComponent = TriggerComponent;\n\n  const trigger = DropdownTriggerComponent ? (\n    <DropdownTriggerComponent\n      aria-expanded={isOpen}\n      onClick={toggle}\n      referenceRef={setMountedReferenceElement}\n      {...triggerProps}\n    />\n  ) : null;\n\n  const content =\n    isOpen && resolvedReferenceElement ? (\n      <FocusScope autoFocus restoreFocus>\n        <DropdownContextProvider close={close}>\n          <div\n            className={clsx('str-chat__dropdown__items', className)}\n            onClick={close}\n            onKeyDown={handleKeyDown}\n            onKeyUpCapture={suppressEscapeKeyUp}\n            ref={setFloatingElement}\n            role='menu'\n            style={{\n              left: x ?? 0,\n              minWidth: matchReferenceWidth\n                ? resolvedReferenceElement.getBoundingClientRect().width\n                : undefined,\n              position: strategy,\n              top: y ?? 0,\n            }}\n          >\n            {children}\n          </div>\n        </DropdownContextProvider>\n      </FocusScope>\n    ) : null;\n\n  return (\n    <div className='str-chat__dropdown'>\n      {trigger}\n      {content}\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport type {\n  ChangeEventHandler,\n  ComponentProps,\n  KeyboardEventHandler,\n  MouseEventHandler,\n  PropsWithChildren,\n  ReactNode,\n} from 'react';\nimport React, { isValidElement, useRef, useState } from 'react';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nexport type SwitchFieldProps = Omit<\n  PropsWithChildren<ComponentProps<'input'>>,\n  'children'\n> & {\n  /** Main label content when title/description are not used */\n  children?: ReactNode;\n  /** Optional description line below title */\n  description?: string;\n  /** Class applied to the root div element of the SwitchField component */\n  fieldClassName?: string;\n  /** Optional title line */\n  title?: string;\n};\n\nexport const SwitchField = ({\n  children,\n  description,\n  fieldClassName,\n  title,\n  ...props\n}: SwitchFieldProps) => {\n  const {\n    'aria-label': ariaLabel,\n    'aria-labelledby': ariaLabelledBy,\n    checked,\n    defaultChecked,\n    disabled,\n    id,\n    onChange,\n    onKeyDown,\n    ...rest\n  } = props;\n  const generatedSwitchId = useStableId();\n  const switchId = id ?? `str-chat__switch-field-${generatedSwitchId}`;\n  const switchLabelId = `${switchId}-label`;\n  const inputRef = useRef<HTMLInputElement | null>(null);\n\n  const [uncontrolledChecked, setUncontrolledChecked] = useState(Boolean(defaultChecked));\n  const isControlled = checked !== undefined;\n  const isOn = isControlled ? checked : uncontrolledChecked;\n  const isReadOnly = isControlled && onChange === undefined;\n\n  const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {\n    if (!isControlled) {\n      setUncontrolledChecked(event.target.checked);\n    }\n\n    onChange?.(event);\n  };\n\n  const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = (event) => {\n    onKeyDown?.(event);\n    if (event.defaultPrevented || event.key !== ' ') return;\n\n    event.preventDefault();\n    event.currentTarget.click();\n  };\n\n  const handleSwitchClick: MouseEventHandler<HTMLDivElement> = (event) => {\n    if (disabled || event.target === inputRef.current) return;\n    inputRef.current?.click();\n  };\n\n  // When no title/aria-label is provided, SwitchField can still be named by a caller-supplied\n  // child element id via aria-labelledby.\n  const childElement = isValidElement<{ id?: string }>(children) ? children : undefined;\n  const childLabelId = childElement?.props.id;\n  // Accessible-name precedence:\n  // 1) explicit aria-labelledby prop\n  // 2) explicit aria-label prop\n  // 3) generated title label id (title path)\n  // 4) caller-supplied child id (children path)\n  const resolvedAriaLabelledBy =\n    ariaLabelledBy ?? (!ariaLabel ? (title ? switchLabelId : childLabelId) : undefined);\n\n  return (\n    <div\n      className={clsx(\n        'str-chat__form__switch-field',\n        fieldClassName,\n        disabled && 'str-chat__form__switch-field--disabled',\n      )}\n    >\n      {title ? (\n        <SwitchFieldLabel\n          description={description}\n          htmlFor={switchId}\n          id={switchLabelId}\n          title={title}\n        />\n      ) : (\n        children\n      )}\n      <Switch\n        {...rest}\n        aria-label={ariaLabel}\n        aria-labelledby={resolvedAriaLabelledBy}\n        checked={isOn}\n        disabled={disabled}\n        id={switchId}\n        on={isOn}\n        onChange={handleChange}\n        onKeyDown={handleKeyDown}\n        onSwitchClick={handleSwitchClick}\n        readOnly={isReadOnly}\n        switchRef={inputRef}\n      />\n    </div>\n  );\n};\n\nexport type SwitchProps = Omit<ComponentProps<'input'>, 'type'> & {\n  on?: boolean;\n  onSwitchClick?: MouseEventHandler<HTMLDivElement>;\n  switchRef?: React.RefObject<HTMLInputElement | null>;\n};\n\nconst Switch = ({ className, on, onSwitchClick, switchRef, ...props }: SwitchProps) => (\n  <div\n    className={clsx('str-chat__form__switch-field__switch', {\n      'str-chat__form__switch-field__switch--on': on,\n    })}\n    onClick={onSwitchClick}\n  >\n    <input\n      {...props}\n      className={clsx('str-chat__form__switch-field__input', className)}\n      ref={switchRef}\n      role='switch'\n      type='checkbox'\n    />\n    <span className='str-chat__form__switch-field__switch-handle' />\n  </div>\n);\n\nexport type SwitchFieldLabelProps = ComponentProps<'label'> & {\n  /** Adds className str-chat__form__switch-field__label--as-error to the root */\n  asError?: boolean;\n  title?: string;\n  description?: string;\n};\n\nexport const SwitchFieldLabel = ({\n  asError,\n  children,\n  className,\n  description,\n  title,\n  ...props\n}: SwitchFieldLabelProps) => (\n  <label\n    className={clsx(\n      'str-chat__form__switch-field__label',\n      { 'str-chat__form__switch-field__label--as-error': asError },\n      className,\n    )}\n    {...props}\n  >\n    <div className='str-chat__form__switch-field__label__content'>\n      {title ? (\n        <>\n          <SwitchFieldTitle>{title}</SwitchFieldTitle>\n          {description != null && description !== '' && (\n            <SwitchFieldDescription>{description}</SwitchFieldDescription>\n          )}\n        </>\n      ) : (\n        children\n      )}\n    </div>\n  </label>\n);\n\nexport type SwitchFieldTitleProps = ComponentProps<'div'> & {\n  title?: string;\n};\n\nexport const SwitchFieldTitle = ({\n  children,\n  className,\n  title,\n  ...props\n}: SwitchFieldTitleProps) => (\n  <div\n    className={clsx('str-chat__form__switch-field__label__text', className)}\n    {...props}\n  >\n    {children ?? title}\n  </div>\n);\n\nexport type SwitchFieldDescriptionProps = ComponentProps<'div'> & {\n  description?: string;\n};\n\nexport const SwitchFieldDescription = ({\n  children,\n  className,\n  description,\n  ...props\n}: SwitchFieldDescriptionProps) => (\n  <div\n    className={clsx('str-chat__form__switch-field__label__description', className)}\n    {...props}\n  >\n    {children ?? description}\n  </div>\n);\n","import React, {\n  type ComponentType,\n  useCallback,\n  useEffect,\n  useMemo,\n  useState,\n} from 'react';\nimport { useTranslationContext } from '../../context';\nimport { ContextMenuBody, ContextMenuButton, ContextMenuRoot, Prompt } from '../Dialog';\nimport {\n  Dropdown,\n  type DropdownTriggerProps,\n  useDropdownContext,\n} from '../Form/Dropdown';\nimport { IconChevronDown } from '../Icons';\nimport { useMessageComposerController } from '../MessageComposer/hooks/useMessageComposerController';\nimport { SwitchField } from '../Form/SwitchField';\nimport { useNotificationApi } from '../Notifications';\nimport type { Coords } from 'stream-chat';\nimport { Button } from '../Button';\nimport clsx from 'clsx';\n\nconst MIN_LIVE_LOCATION_SHARE_DURATION = 60 * 1000; // 1 minute;\n\nconst DEFAULT_SHARE_LOCATION_DURATIONS = [\n  15 * 60 * 1000, // 15 minutes\n  60 * 60 * 1000, // 1 hour\n  8 * 60 * 60 * 1000, // 8 hours\n];\n\nexport type ShareGeolocationMapProps = Partial<Coords> & {\n  loadingLocation: boolean;\n  restartLocationWatching: () => void;\n  geolocationPositionError?: GeolocationPositionError;\n};\n\nexport type ShareLocationDialogProps = {\n  close: () => void;\n  shareDurations?: number[];\n  GeolocationMap?: ComponentType<ShareGeolocationMapProps>;\n  DurationDropdownItems?: ComponentType<DurationDropdownItemsProps>;\n};\n\nconst DefaultGeolocationMap = () => null;\n\nconst LiveLocationDurationTrigger = ({\n  children,\n  onClick,\n  referenceRef,\n  ...props\n}: DropdownTriggerProps) => (\n  <Button\n    {...props}\n    className='str-chat__live-location-sharing-duration-selector__button'\n    onClick={onClick}\n    ref={referenceRef as React.Ref<HTMLButtonElement>}\n    type='button'\n  >\n    {children}\n  </Button>\n);\n\nexport const ShareLocationDialog = ({\n  close,\n  GeolocationMap = DefaultGeolocationMap,\n  shareDurations = DEFAULT_SHARE_LOCATION_DURATIONS,\n}: ShareLocationDialogProps) => {\n  const { addNotification } = useNotificationApi();\n  const { t } = useTranslationContext();\n  const messageComposer = useMessageComposerController();\n  const [durations, setDurations] = useState<number[]>([]);\n  const [selectedDuration, setSelectedDuration] = useState<number | undefined>(undefined);\n  const [geolocationPosition, setGeolocationPosition] =\n    useState<GeolocationPosition | null>(null);\n  const [loadingLocation, setLoadingLocation] = useState<boolean>(false);\n  const [geolocationPositionError, setGeolocationPositionError] = useState<\n    GeolocationPositionError | undefined\n  >(undefined);\n\n  const validShareDurations = useMemo(\n    () => shareDurations.filter((d) => d >= MIN_LIVE_LOCATION_SHARE_DURATION),\n    [shareDurations],\n  );\n\n  const selectedDurationLabel = useMemo(\n    () =>\n      durations.length > 0\n        ? t('duration/Share Location', {\n            milliseconds: selectedDuration ?? durations[0],\n          })\n        : undefined,\n    [durations, selectedDuration, t],\n  );\n\n  const durationTriggerProps = useMemo(\n    () => ({\n      children: selectedDurationLabel ? (\n        <>\n          <span>{selectedDurationLabel}</span>\n          <IconChevronDown />\n        </>\n      ) : null,\n    }),\n    [selectedDurationLabel],\n  );\n\n  const getPosition = useCallback(\n    (): Promise<GeolocationPosition> =>\n      new Promise((resolve, reject) => {\n        navigator.geolocation.getCurrentPosition(\n          (position) => {\n            resolve(position);\n          },\n          (positionError) => {\n            console.warn(positionError);\n            reject(positionError);\n          },\n          { timeout: 1000 },\n        );\n      }),\n    [],\n  );\n\n  const setupPositionWatching = useCallback(() => {\n    setLoadingLocation(true);\n    const watch = navigator.geolocation.watchPosition(\n      (position) => {\n        setGeolocationPosition(position);\n        setLoadingLocation(false);\n        setGeolocationPositionError(undefined);\n      },\n      (error) => {\n        setGeolocationPosition(null);\n        setLoadingLocation(false);\n        setGeolocationPositionError(error);\n      },\n      { timeout: 1000 },\n    );\n\n    return () => {\n      navigator.geolocation.clearWatch(watch);\n    };\n  }, []);\n\n  useEffect(() => setupPositionWatching(), [setupPositionWatching]);\n\n  const liveLocationSwitchEnabled = durations.length > 0;\n  return (\n    <Prompt.Root\n      className='str-chat__share-location-dialog'\n      data-testid='share-location-dialog'\n    >\n      <Prompt.Header\n        close={close}\n        description={t(\n          'Select your current location and optionally enable live location sharing',\n        )}\n        title={t('Share Location')}\n      />\n      <Prompt.Body>\n        <GeolocationMap\n          geolocationPositionError={geolocationPositionError}\n          latitude={geolocationPosition?.coords.latitude}\n          loadingLocation={loadingLocation}\n          longitude={geolocationPosition?.coords.longitude}\n          restartLocationWatching={setupPositionWatching}\n        />\n        {validShareDurations.length > 0 && (\n          <div\n            className={clsx('str-chat__live-location-activation', {\n              'str-chat__live-location-activation--expanded': liveLocationSwitchEnabled,\n            })}\n          >\n            <SwitchField\n              checked={liveLocationSwitchEnabled}\n              data-testid='share-location-dialog-live-location-switch'\n              disabled={!geolocationPosition}\n              onChange={(e) => {\n                e.stopPropagation();\n                if (liveLocationSwitchEnabled) {\n                  setDurations([]);\n                  setSelectedDuration(undefined);\n                } else {\n                  setDurations(validShareDurations);\n                  setSelectedDuration(validShareDurations[0]);\n                }\n              }}\n              title={t('Share live location for')}\n            />\n            {liveLocationSwitchEnabled && selectedDurationLabel && (\n              <div className='str-chat__live-location-sharing-duration-selector'>\n                <Dropdown\n                  placement='bottom-start'\n                  TriggerComponent={LiveLocationDurationTrigger}\n                  triggerProps={durationTriggerProps}\n                >\n                  <DurationDropdownItems\n                    durations={durations}\n                    selectDuration={setSelectedDuration}\n                    selectedDuration={selectedDuration}\n                  />\n                </Dropdown>\n              </div>\n            )}\n          </div>\n        )}\n      </Prompt.Body>\n      <Prompt.Footer>\n        <Prompt.FooterControls>\n          <Prompt.FooterControlsButtonSecondary\n            className='str-chat__prompt__footer__controls-button--cancel'\n            onClick={() => {\n              messageComposer.locationComposer.initState();\n              close();\n            }}\n          >\n            {t('Cancel')}\n          </Prompt.FooterControlsButtonSecondary>\n          <Prompt.FooterControlsButtonSecondary\n            className='str-chat__prompt__footer__controls-button--submit'\n            disabled={!geolocationPosition}\n            onClick={async () => {\n              let coords = geolocationPosition && {\n                latitude: geolocationPosition.coords.latitude,\n                longitude: geolocationPosition.coords.longitude,\n              };\n              if (!coords) {\n                coords = (await getPosition()).coords;\n              }\n              messageComposer.locationComposer.setData({\n                ...coords,\n                durationMs: selectedDuration,\n              });\n              close();\n            }}\n            type='submit'\n          >\n            {t('Attach')}\n          </Prompt.FooterControlsButtonSecondary>\n          <Prompt.FooterControlsButtonPrimary\n            className='str-chat__prompt__footer__controls-button--submit'\n            disabled={!geolocationPosition}\n            onClick={async () => {\n              let coords = geolocationPosition && {\n                latitude: geolocationPosition.coords.latitude,\n                longitude: geolocationPosition.coords.longitude,\n              };\n              if (!coords) {\n                try {\n                  coords = (await getPosition()).coords;\n                } catch (e) {\n                  addNotification({\n                    emitter: 'ShareLocationDialog',\n                    error: e instanceof Error ? e : undefined,\n                    message: t('Failed to retrieve location'),\n                    severity: 'error',\n                    type: 'browser:location:get:failed',\n                  });\n                  return;\n                }\n              }\n\n              messageComposer.locationComposer.setData({\n                ...coords,\n                durationMs: selectedDuration,\n              });\n              try {\n                await messageComposer.sendLocation();\n              } catch (err) {\n                addNotification({\n                  emitter: 'ShareLocationDialog',\n                  error: err instanceof Error ? err : undefined,\n                  message: t('Failed to share location'),\n                  severity: 'error',\n                  type: 'api:location:share:failed',\n                });\n                return;\n              }\n              close();\n            }}\n            type='submit'\n          >\n            {t('Share')}\n          </Prompt.FooterControlsButtonPrimary>\n        </Prompt.FooterControls>\n      </Prompt.Footer>\n    </Prompt.Root>\n  );\n};\n\nexport type DurationDropdownItemsProps = {\n  durations: number[];\n  selectedDuration?: number;\n  selectDuration: (duration: number) => void;\n};\nconst DurationDropdownItems = ({\n  durations,\n  selectDuration,\n  selectedDuration,\n}: DurationDropdownItemsProps) => {\n  const { t } = useTranslationContext();\n  const { close } = useDropdownContext();\n  return (\n    <ContextMenuRoot>\n      <ContextMenuBody>\n        {durations.map((duration) => (\n          <ContextMenuButton\n            aria-checked={selectedDuration === duration}\n            className='str-chat__live-location-sharing-duration-option'\n            key={`duration-${duration}`}\n            onClick={() => {\n              selectDuration(duration);\n              close();\n            }}\n            role='menuitemradio'\n          >\n            {t('duration/Share Location', { milliseconds: duration })}\n          </ContextMenuButton>\n        ))}\n      </ContextMenuBody>\n    </ContextMenuRoot>\n  );\n};\n","import React, { useMemo } from 'react';\nimport { usePollContext, useTranslationContext } from '../../context';\nimport { useStateStore } from '../../store';\nimport type { PollOption, PollState } from 'stream-chat';\n\ntype PollStateSelectorReturnValue = {\n  enforce_unique_vote: boolean;\n  is_closed: boolean | undefined;\n  max_votes_allowed: number;\n  name: string;\n  options: PollOption[];\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  enforce_unique_vote: nextValue.enforce_unique_vote,\n  is_closed: nextValue.is_closed,\n  max_votes_allowed: nextValue.max_votes_allowed,\n  name: nextValue.name,\n  options: nextValue.options,\n});\n\nexport const PollHeader = () => {\n  const { t } = useTranslationContext('PollHeader');\n\n  const { poll } = usePollContext();\n  const { enforce_unique_vote, is_closed, max_votes_allowed, name, options } =\n    useStateStore(poll.state, pollStateSelector);\n\n  const selectionInstructions = useMemo(() => {\n    if (is_closed) return t('Vote ended');\n    if (enforce_unique_vote || options.length === 1) return t('Select one');\n    if (max_votes_allowed)\n      return t('Select up to {{count}}', {\n        count: max_votes_allowed > options.length ? options.length : max_votes_allowed,\n      });\n    if (options.length > 1) return t('Select one or more');\n    return '';\n  }, [is_closed, enforce_unique_vote, max_votes_allowed, options.length, t]);\n\n  if (!name) return null;\n\n  return (\n    <div className='str-chat__poll-header'>\n      <div className='str-chat__poll-title'>{name}</div>\n      <div className='str-chat__poll-subtitle'>{selectionInstructions}</div>\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport type { ComponentProps, ReactNode } from 'react';\nimport React from 'react';\n\nexport type FieldErrorProps = ComponentProps<'div'> & {\n  /** Error message (string or custom content e.g. icon + text) */\n  text?: ReactNode;\n};\n\nexport const FieldError = ({ className, text, ...props }: FieldErrorProps) => (\n  <div {...props} className={clsx('str-chat__form-field-error', className)}>\n    {text}\n  </div>\n);\n","import clsx from 'clsx';\nimport React, { forwardRef, useCallback } from 'react';\nimport type { ChangeEvent, ComponentProps, KeyboardEvent } from 'react';\nimport { useTranslationContext } from '../../context';\nimport { useStableId } from '../UtilityComponents/useStableId';\nimport { IconMinus, IconPlusSmall } from '../Icons';\nimport { Button } from '../Button';\n\nexport type NumericInputProps = Omit<\n  ComponentProps<'input'>,\n  'className' | 'type' | 'value' | 'onChange'\n> & {\n  value: string;\n  onChange: (e: ChangeEvent<HTMLInputElement>) => void;\n  /** Optional label above the input */\n  label?: string;\n  /** Minimum value (stepper) */\n  min?: number;\n  /** Maximum value (stepper) */\n  max?: number;\n  /** Step for increment/decrement (default 1) */\n  step?: number;\n  className?: string;\n};\n\nconst parseNumeric = (s: string): number | null => {\n  const trimmed = s.trim();\n  if (trimmed === '') return null;\n  const n = Number(trimmed);\n  return Number.isFinite(n) ? n : null;\n};\n\nconst clamp = (n: number, min: number, max: number): number =>\n  Math.min(Math.max(n, min), max);\n\nexport const NumericInput = forwardRef<HTMLInputElement, NumericInputProps>(\n  function NumericInput(\n    {\n      className,\n      disabled = false,\n      id: idProp,\n      label,\n      max,\n      min,\n      onChange,\n      step = 1,\n      value,\n      ...inputProps\n    },\n    ref,\n  ) {\n    const generatedId = useStableId();\n    const id = idProp ?? generatedId;\n    const { t } = useTranslationContext();\n\n    const num = parseNumeric(value);\n    const minDef = min ?? -Infinity;\n    const maxDef = max ?? Infinity;\n    const atMin = num !== null && num <= minDef;\n    const atMax = num !== null && num >= maxDef;\n\n    const handleInputChange = useCallback(\n      (e: ChangeEvent<HTMLInputElement>) => {\n        const next = e.target.value;\n        if (next === '' || /^\\d+$/.test(next)) {\n          onChange(e);\n        }\n      },\n      [onChange],\n    );\n\n    const createChangeEvent = useCallback(\n      (newValue: string): ChangeEvent<HTMLInputElement> =>\n        ({\n          currentTarget: { value: newValue },\n          target: { value: newValue },\n        }) as ChangeEvent<HTMLInputElement>,\n      [],\n    );\n\n    const handleDecrement = useCallback(() => {\n      if (disabled || atMin) return;\n      const next = num !== null ? clamp(num - step, minDef, maxDef) : minDef;\n      onChange(createChangeEvent(String(next)));\n    }, [disabled, atMin, num, step, minDef, maxDef, onChange, createChangeEvent]);\n\n    const handleIncrement = useCallback(() => {\n      if (disabled || atMax) return;\n      const next = num !== null ? clamp(num + step, minDef, maxDef) : minDef;\n      onChange(createChangeEvent(String(next)));\n    }, [disabled, atMax, num, step, minDef, maxDef, onChange, createChangeEvent]);\n\n    const handleKeyDown = useCallback(\n      (e: KeyboardEvent<HTMLInputElement>) => {\n        if (e.key === 'ArrowDown') {\n          e.preventDefault();\n          handleDecrement();\n        } else if (e.key === 'ArrowUp') {\n          e.preventDefault();\n          handleIncrement();\n        }\n      },\n      [handleDecrement, handleIncrement],\n    );\n\n    return (\n      <div\n        className={clsx(\n          'str-chat__form-numeric-input',\n          disabled && 'str-chat__form-numeric-input--disabled',\n          className,\n        )}\n      >\n        {!!label && (\n          <label className='str-chat__form-numeric-input__label' htmlFor={id}>\n            {label}\n          </label>\n        )}\n        <div className={clsx('str-chat__form-numeric-input__wrapper')}>\n          <Button\n            appearance='outline'\n            aria-label={t('aria/Decrease value')}\n            circular\n            className={clsx(\n              'str-chat__form-numeric-input__stepper str-chat__form-numeric-input__stepper--decrement',\n            )}\n            disabled={disabled || atMin}\n            onClick={handleDecrement}\n            size='xs'\n            variant='secondary'\n          >\n            <IconMinus className='str-chat__form-numeric-input__stepper-icon' />\n          </Button>\n          <input\n            aria-valuemax={Number.isFinite(maxDef) ? maxDef : undefined}\n            aria-valuemin={Number.isFinite(minDef) ? minDef : undefined}\n            aria-valuenow={num ?? undefined}\n            className='str-chat__form-numeric-input__input'\n            disabled={disabled}\n            id={id}\n            inputMode='numeric'\n            onChange={handleInputChange}\n            onKeyDown={handleKeyDown}\n            ref={ref}\n            role='spinbutton'\n            type='text'\n            value={value}\n            {...inputProps}\n          />\n          <Button\n            appearance='outline'\n            aria-label={t('aria/Increase value')}\n            circular\n            className={clsx(\n              'str-chat__form-numeric-input__stepper str-chat__form-numeric-input__stepper--increment',\n            )}\n            disabled={disabled || atMax}\n            onClick={handleIncrement}\n            size='xs'\n            variant='secondary'\n          >\n            <IconPlusSmall className='str-chat__form-numeric-input__stepper-icon' />\n          </Button>\n        </div>\n      </div>\n    );\n  },\n);\n","import clsx from 'clsx';\nimport React, { forwardRef } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { useStableId } from '../UtilityComponents/useStableId';\nimport { IconCheckmark, IconExclamationMark } from '../Icons';\n\nexport type TextInputVariant = 'outline' | 'ghost';\n\n/** Where the active field message (error, success, or neutral) sits relative to the bordered control */\nexport type TextInputFieldMessagePlacement = 'outside' | 'inside';\n\nexport type TextInputProps = Omit<ComponentProps<'input'>, 'className'> & {\n  /** Root class name */\n  className?: string;\n  /**\n   * `outside` (default): message below the bordered wrapper.\n   * `inside`: message under the value row, inside the border (error, success, or neutral).\n   */\n  fieldMessagePlacement?: TextInputFieldMessagePlacement;\n  /** Optional label above the input */\n  label?: string;\n  /** Optional leading content (e.g. icon) inside the input area */\n  leading?: ReactNode;\n  /** Optional trailing content (e.g. clear button) inside the input area */\n  trailing?: ReactNode;\n  /** Optional suffix text shown after the input value, inside the field */\n  trailingText?: string;\n  /** Neutral/helper message below the input (no icon) */\n  message?: ReactNode;\n  /** Error message; shown when `error` is true, with `errorMessageIcon` */\n  errorMessage?: ReactNode;\n  /** Icon before error text (default: exclamation) */\n  errorMessageIcon?: ReactNode;\n  /** Success message below the input */\n  successMessage?: ReactNode;\n  /** Icon before success text (default: checkmark) */\n  successMessageIcon?: ReactNode;\n  /** When true, error border and error styling */\n  error?: boolean;\n  /** `outline` = border always; `ghost` = border on focus */\n  variant?: TextInputVariant;\n};\n\ntype TextInputIconMessageLineProps = {\n  icon: ReactNode;\n  text: ReactNode;\n};\n\nconst TextInputIconMessageLine = ({ icon, text }: TextInputIconMessageLineProps) => (\n  <>\n    <span aria-hidden className='str-chat__form-text-input__message-icon'>\n      {icon}\n    </span>\n    <span className='str-chat__form-text-input__message-text'>{text}</span>\n  </>\n);\n\n/** At most one of error / success / neutral is shown under the field */\ntype TextInputFieldMessageProps =\n  | {\n      kind: 'error';\n      id?: string;\n      insidePlacement: boolean;\n      errorMessageIcon?: ReactNode;\n      text: ReactNode;\n    }\n  | {\n      kind: 'success';\n      id?: string;\n      insidePlacement: boolean;\n      successMessageIcon?: ReactNode;\n      text: ReactNode;\n    }\n  | {\n      kind: 'neutral';\n      id?: string;\n      insidePlacement: boolean;\n      text: ReactNode;\n    };\n\nconst TextInputFieldMessage = (props: TextInputFieldMessageProps) => {\n  if (props.kind === 'neutral') {\n    return (\n      <div\n        className={clsx(\n          'str-chat__form-text-input__message',\n          props.insidePlacement &&\n            'str-chat__form-text-input__message--field-message-inside',\n        )}\n        id={props.id}\n      >\n        {props.text}\n      </div>\n    );\n  } else if (props.kind === 'success') {\n    return (\n      <div\n        className={clsx(\n          'str-chat__form-text-input__message',\n          'str-chat__form-text-input__message--success',\n          props.insidePlacement &&\n            'str-chat__form-text-input__message--field-message-inside',\n        )}\n        id={props.id}\n      >\n        <TextInputIconMessageLine\n          icon={props.successMessageIcon ?? <IconCheckmark />}\n          text={props.text}\n        />\n      </div>\n    );\n  } else if (props.kind === 'error') {\n    return (\n      <div\n        className={clsx(\n          'str-chat__form-text-input__message',\n          'str-chat__form-field-error',\n          props.insidePlacement &&\n            'str-chat__form-text-input__message--field-message-inside',\n        )}\n        id={props.id}\n        role='alert'\n      >\n        <TextInputIconMessageLine\n          icon={props.errorMessageIcon ?? <IconExclamationMark />}\n          text={props.text}\n        />\n      </div>\n    );\n  }\n\n  return null;\n};\n\nexport const TextInput = forwardRef<HTMLInputElement, TextInputProps>(function TextInput(\n  {\n    className,\n    disabled,\n    error = false,\n    errorMessage,\n    errorMessageIcon,\n    fieldMessagePlacement = 'outside',\n    id: idProp,\n    label,\n    leading,\n    message,\n    successMessage,\n    successMessageIcon,\n    trailing,\n    trailingText,\n    variant = 'outline',\n    ...inputProps\n  },\n  ref,\n) {\n  const autoId = useStableId();\n  const id = idProp ?? autoId;\n\n  const hasError = error && (errorMessage != null || message != null);\n  const showSuccess = !hasError && successMessage != null;\n  const showNeutral = !hasError && !showSuccess && message != null;\n  const hasFeedback = hasError || showSuccess || showNeutral;\n  const messageInside = fieldMessagePlacement === 'inside' && hasFeedback;\n\n  const messageId = hasError\n    ? `${id}-field-error`\n    : showSuccess || showNeutral\n      ? `${id}-message`\n      : undefined;\n  const describedBy = [inputProps['aria-describedby'], messageId]\n    .filter((value): value is string => !!value)\n    .join(' ');\n\n  const fieldMessage = hasError ? (\n    <TextInputFieldMessage\n      errorMessageIcon={errorMessageIcon}\n      id={messageId}\n      insidePlacement={messageInside}\n      kind='error'\n      text={errorMessage ?? message}\n    />\n  ) : showSuccess ? (\n    <TextInputFieldMessage\n      id={messageId}\n      insidePlacement={messageInside}\n      kind='success'\n      successMessageIcon={successMessageIcon}\n      text={successMessage}\n    />\n  ) : showNeutral ? (\n    <TextInputFieldMessage\n      id={messageId}\n      insidePlacement={messageInside}\n      kind='neutral'\n      text={message}\n    />\n  ) : null;\n\n  return (\n    <div\n      className={clsx(\n        'str-chat__form-text-input',\n        error && 'str-chat__form-text-input--error',\n        showSuccess && 'str-chat__form-text-input--success',\n        disabled && 'str-chat__form-text-input--disabled',\n        messageInside && 'str-chat__form-text-input--field-message-inside',\n        className,\n      )}\n    >\n      {label ? (\n        <label className='str-chat__form-text-input__label' htmlFor={id}>\n          {label}\n        </label>\n      ) : null}\n      <div\n        className={clsx(\n          'str-chat__form-text-input__wrapper',\n          `str-chat__form-text-input__wrapper--${variant}`,\n          messageInside && 'str-chat__form-text-input__wrapper--field-message-inside',\n        )}\n      >\n        <div className='str-chat__form-text-input__control-row'>\n          {leading ? (\n            <span aria-hidden className='str-chat__form-text-input__leading'>\n              {leading}\n            </span>\n          ) : null}\n          <input\n            aria-describedby={describedBy}\n            aria-invalid={error}\n            className='str-chat__form-text-input__input'\n            disabled={disabled}\n            id={id}\n            ref={ref}\n            {...inputProps}\n          />\n          {trailingText != null ? (\n            <span aria-hidden className='str-chat__form-text-input__suffix'>\n              {trailingText}\n            </span>\n          ) : null}\n          {trailing ? (\n            <span aria-hidden className='str-chat__form-text-input__trailing'>\n              {trailing}\n            </span>\n          ) : null}\n        </div>\n        {messageInside ? fieldMessage : null}\n      </div>\n      {messageInside ? null : fieldMessage}\n    </div>\n  );\n});\n","import type { PropsWithChildren } from 'react';\nimport React, { useEffect, useState } from 'react';\nimport clsx from 'clsx';\n\nexport type DragAndDropContainerProps = PropsWithChildren<{\n  className?: string;\n  draggable?: boolean;\n  onSetNewOrder?: (newOrder: number[]) => void;\n}>;\n\nexport const DragAndDropContainer = ({\n  children,\n  className,\n  draggable,\n  onSetNewOrder,\n}: DragAndDropContainerProps) => {\n  const [order, setOrder] = useState<number[]>([]);\n  const [dragStartIndex, setDragStartIndex] = useState<number | null>(null);\n  const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);\n  const [container, setContainer] = useState<HTMLDivElement | null>(null);\n\n  const moveDirection =\n    dragStartIndex === null || dragOverIndex === null\n      ? undefined\n      : dragStartIndex <= dragOverIndex\n        ? 'down'\n        : 'up';\n\n  const childrenArray = React.Children.toArray(children);\n\n  useEffect(() => {\n    setOrder(React.Children.map(children, (_, index) => index) || []);\n  }, [children]);\n\n  useEffect(() => {\n    if (!container) return;\n\n    const handleDragStart = (e: DragEvent) => {\n      const target = e.target as HTMLElement;\n      const draggableItem = target.closest('.str-chat__drag-and-drop-container__item');\n      if (e.dataTransfer) {\n        e.dataTransfer.effectAllowed = 'move';\n      }\n\n      if (draggableItem instanceof HTMLElement) {\n        const index = Array.from(draggableItem.parentElement?.children || []).indexOf(\n          draggableItem,\n        );\n        setDragStartIndex(index);\n        e.dataTransfer?.setData('text/plain', index.toString());\n        draggableItem.style.opacity = '0.3';\n      }\n    };\n\n    const handleDragOver = (e: DragEvent) => {\n      e.preventDefault();\n      const target = e.target as HTMLElement;\n      const draggableItem = target.closest('.str-chat__drag-and-drop-container__item');\n      if (draggableItem instanceof HTMLElement) {\n        const index = Array.from(draggableItem.parentElement?.children || []).indexOf(\n          draggableItem,\n        );\n        setDragOverIndex(index);\n      }\n    };\n\n    const handleDragLeave = () => {\n      setDragOverIndex(null);\n    };\n\n    const handleDrop = (e: DragEvent) => {\n      e.preventDefault();\n      const draggedIndex = parseInt(e.dataTransfer?.getData('text/plain') || '-1', 10);\n      const target = e.target as HTMLElement;\n      const draggableItem = target.closest('.str-chat__drag-and-drop-container__item');\n      if (draggableItem instanceof HTMLElement) {\n        const dropIndex = Array.from(draggableItem.parentElement?.children || []).indexOf(\n          draggableItem,\n        );\n        if (draggedIndex !== -1 && draggedIndex !== dropIndex) {\n          setOrder((prevOrder) => {\n            const newOrder = [...prevOrder];\n            const [removed] = newOrder.splice(draggedIndex, 1);\n            newOrder.splice(dropIndex, 0, removed);\n            onSetNewOrder?.(newOrder);\n            return newOrder;\n          });\n        }\n      }\n      setDragStartIndex(null);\n      setDragOverIndex(null);\n    };\n\n    const handleDragEnd = (e: DragEvent) => {\n      const target = e.target as HTMLElement;\n      if (target instanceof HTMLElement) {\n        target.style.opacity = '';\n      }\n      setDragStartIndex(null);\n      setDragOverIndex(null);\n    };\n\n    container.addEventListener('dragstart', handleDragStart);\n    container.addEventListener('dragover', handleDragOver);\n    container.addEventListener('dragleave', handleDragLeave);\n    container.addEventListener('drop', handleDrop);\n    container.addEventListener('dragend', handleDragEnd);\n\n    return () => {\n      container.removeEventListener('dragstart', handleDragStart);\n      container.removeEventListener('dragover', handleDragOver);\n      container.removeEventListener('dragleave', handleDragLeave);\n      container.removeEventListener('drop', handleDrop);\n      container.removeEventListener('dragend', handleDragEnd);\n    };\n  }, [container, onSetNewOrder]);\n\n  return (\n    <div\n      className={clsx('str-chat__drag-and-drop-container', className)}\n      ref={setContainer}\n    >\n      {order.map((originalIndex, currentIndex) => {\n        const child = childrenArray[originalIndex];\n        return (\n          <div\n            className={clsx('str-chat__drag-and-drop-container__item', {\n              'str-chat__drag-and-drop-container__item--dragged-over-from-bottom':\n                moveDirection === 'up' && dragOverIndex === currentIndex,\n              'str-chat__drag-and-drop-container__item--dragged-over-from-top':\n                moveDirection === 'down' && dragOverIndex === currentIndex,\n            })}\n            draggable={draggable}\n            key={\n              React.isValidElement(child) ? child.key : `draggable-item-${originalIndex}`\n            }\n          >\n            {child}\n          </div>\n        );\n      })}\n    </div>\n  );\n};\n","import React from 'react';\nimport clsx from 'clsx';\nimport {\n  DragAndDropContainer,\n  type DragAndDropContainerProps,\n} from '../DragAndDrop/DragAndDropContainer';\n\nexport type TextInputFieldSetProps = DragAndDropContainerProps & {\n  label?: string;\n};\n\nexport const TextInputFieldSet = ({\n  children,\n  className,\n  draggable,\n  label,\n  onSetNewOrder,\n}: TextInputFieldSetProps) => (\n  <fieldset className={clsx('str-chat__form__input-fieldset', className)}>\n    <legend className='str-chat__form__input-fieldset__label'>{label}</legend>\n    <DragAndDropContainer\n      className='str-chat__form__input-fieldset__values'\n      draggable={draggable}\n      onSetNewOrder={onSetNewOrder}\n    >\n      {children}\n    </DragAndDropContainer>\n  </fieldset>\n);\n","import type { Dispatch, SetStateAction } from 'react';\nimport { useCallback, useState } from 'react';\n\nexport type Validators<V extends Record<string, unknown>> = {\n  [K in keyof V]?: (value: V[K]) => Error | undefined;\n};\n\nexport type UseFormStateOptions<V extends Record<string, unknown>> = {\n  initialValue: V;\n  validators?: Validators<V>;\n  onSubmit: (value: V) => Promise<void>;\n};\n\nexport type UseFormStateReturn<V extends Record<string, unknown>> = {\n  value: V;\n  setValue: Dispatch<SetStateAction<V>>;\n  setFieldValue: (field: keyof V, value: V[keyof V]) => void;\n  fieldErrors: Record<string, Error>;\n  handleSubmit: (e?: React.FormEvent) => void;\n};\n\nexport function useFormState<V extends Record<string, unknown>>(\n  options: UseFormStateOptions<V>,\n): UseFormStateReturn<V> {\n  const { initialValue, onSubmit, validators = {} as Validators<V> } = options;\n  const [value, setValue] = useState<V>(initialValue);\n  const [fieldErrors, setFieldErrors] = useState<Record<string, Error>>({});\n\n  const setFieldValue = useCallback(\n    (field: keyof V, fieldValue: V[keyof V]) => {\n      setValue((prev) => ({ ...prev, [field]: fieldValue }) as V);\n      const validator = validators[field];\n      if (validator) {\n        const err = validator(fieldValue);\n        setFieldErrors((prev) => {\n          const next = { ...prev };\n          if (err) next[field as string] = err;\n          else delete next[field as string];\n          return next;\n        });\n      }\n    },\n    [validators],\n  );\n\n  const handleSubmit = useCallback(\n    (e?: React.FormEvent) => {\n      e?.preventDefault();\n      const errors: Record<string, Error> = {};\n      for (const key of Object.keys(value) as (keyof V)[]) {\n        const validator = validators[key];\n        if (validator) {\n          const err = validator(value[key]);\n          if (err) errors[key as string] = err;\n        }\n      }\n      if (Object.keys(errors).length > 0) {\n        setFieldErrors(errors);\n        return;\n      }\n      setFieldErrors({});\n      void onSubmit(value);\n    },\n    [value, validators, onSubmit],\n  );\n\n  return {\n    fieldErrors,\n    handleSubmit,\n    setFieldValue,\n    setValue,\n    value,\n  };\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useStateStore } from '../../../store';\nimport { useModalContext, usePollContext, useTranslationContext } from '../../../context';\nimport type { PollAnswer, PollState } from 'stream-chat';\nimport { Prompt } from '../../Dialog';\nimport { TextInput } from '../../Form';\nimport { useFormState } from '../../Form/hooks';\n\ntype PollStateSelectorReturnValue = { ownAnswer: PollAnswer | undefined };\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  ownAnswer: nextValue.ownAnswer,\n});\n\nexport type AddCommentPromptProps = {\n  messageId: string;\n};\n\nexport const AddCommentPrompt = ({ messageId }: AddCommentPromptProps) => {\n  const { t } = useTranslationContext();\n  const { close } = useModalContext();\n  const { poll } = usePollContext();\n  const { ownAnswer } = useStateStore(poll.state, pollStateSelector);\n  const [input, setInput] = useState<HTMLInputElement | null>(null);\n\n  const initialComment = ownAnswer?.answer_text ?? '';\n  const initialValue = useMemo(() => ({ comment: initialComment }), [initialComment]);\n  const validators = useMemo(\n    () => ({\n      comment: (v: string) => {\n        const trimmed = typeof v === 'string' ? v.trim() : '';\n        if (!trimmed) {\n          return new Error(t('This field cannot be empty or contain only spaces'));\n        }\n        return undefined;\n      },\n    }),\n    [t],\n  );\n  const onSubmit = useCallback(\n    async (formValue: { comment: string }) => {\n      await poll.addAnswer(formValue.comment, messageId);\n      close();\n    },\n    [poll, messageId, close],\n  );\n  const { fieldErrors, handleSubmit, setFieldValue, value } = useFormState<{\n    comment: string;\n  }>({\n    initialValue,\n    onSubmit,\n    validators,\n  });\n\n  useEffect(() => {\n    input?.focus();\n  }, [input]);\n\n  const title = ownAnswer ? t('Update your comment') : t('Add a comment');\n  const description = ownAnswer\n    ? t('Update the comment attached to your poll answer')\n    : t('Add a comment to your poll answer');\n  const submitDisabled =\n    !value.comment?.trim() || value.comment === ownAnswer?.answer_text;\n\n  return (\n    <Prompt.Root className='str-chat__modal__poll-add-comment'>\n      {title && <Prompt.Header close={close} description={description} title={title} />}\n      <form autoComplete='off' onSubmit={handleSubmit}>\n        <Prompt.Body>\n          <TextInput\n            aria-label={title}\n            error={!!fieldErrors.comment}\n            errorMessage={fieldErrors.comment?.message}\n            id='comment'\n            name='comment'\n            onChange={(e) => setFieldValue('comment', e.target.value)}\n            placeholder={t('placeholder/PollComment')}\n            ref={setInput}\n            required\n            type='text'\n            value={value.comment}\n          />\n        </Prompt.Body>\n        <Prompt.Footer>\n          <Prompt.FooterControls>\n            <Prompt.FooterControlsButtonSecondary\n              className='str-chat__prompt__footer__controls-button--cancel'\n              onClick={close}\n              type='button'\n            >\n              {t('Cancel')}\n            </Prompt.FooterControlsButtonSecondary>\n            <Prompt.FooterControlsButtonPrimary\n              className='str-chat__prompt__footer__controls-button--submit'\n              disabled={Object.keys(fieldErrors).length > 0 || submitDisabled}\n              type='submit'\n            >\n              {initialComment ? t('Update') : t('Send')}\n            </Prompt.FooterControlsButtonPrimary>\n          </Prompt.FooterControls>\n        </Prompt.Footer>\n      </form>\n    </Prompt.Root>\n  );\n};\n","import React from 'react';\nimport { Alert } from '../../Dialog';\nimport { useModalContext, usePollContext, useTranslationContext } from '../../../context';\nimport { Button } from '../../Button';\nimport { useNotificationApi } from '../../Notifications';\n\nexport const EndPollAlert = () => {\n  const { addNotification } = useNotificationApi();\n  const { t } = useTranslationContext();\n  const { poll } = usePollContext();\n  const { close } = useModalContext();\n\n  return (\n    <Alert.Root className={'str-chat__end-poll-alert'}>\n      <Alert.Header\n        description={t(\n          'Do you want to end this poll now? Nobody will be able to vote in this poll anymore.',\n        )}\n        title={t('End this poll?')}\n      ></Alert.Header>\n      <Alert.Actions>\n        <Button\n          appearance='outline'\n          className='str-chat__end-poll-alert__end-vote-button'\n          data-testid='end-poll-alert-end-vote-button'\n          onClick={async () => {\n            try {\n              await poll.close();\n              close();\n              addNotification({\n                emitter: 'EndPollAlert',\n                message: t('Poll ended'),\n                severity: 'success',\n                type: 'api:poll:end:success',\n              });\n            } catch (e) {\n              addNotification({\n                emitter: 'EndPollAlert',\n                error: e instanceof Error ? e : undefined,\n                message: t('Failed to end the poll'),\n                severity: 'error',\n                type: 'api:poll:end:failed',\n              });\n            }\n          }}\n          size='md'\n          variant='danger'\n        >\n          {t('End poll')}\n        </Button>\n        <Button\n          appearance='outline'\n          className='str-chat__end-poll-alert__cancel-button'\n          data-testid='end-poll-alert-cancel-button'\n          onClick={close}\n          size='md'\n          variant='secondary'\n        >\n          {t('Cancel')}\n        </Button>\n      </Alert.Actions>\n    </Alert.Root>\n  );\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport { GlobalModal } from '../../Modal';\nimport { useComponentContext } from '../../../context';\nimport { Button } from '../../Button';\nimport clsx from 'clsx';\n\nexport type PollActionProps = {\n  buttonText: string;\n  closeModal: () => void;\n  modalIsOpen: boolean;\n  openModal: () => void;\n  /**\n   * Additional actions are shown based on the poll settings defined by the creator.\n   * Examples are \"Suggest an option\", \"Add a comment\", \"View N comment(s)\".\n   */\n  isAdditionalAction?: boolean;\n  modalClassName?: string;\n};\n\nexport const PollAction = ({\n  buttonText,\n  children,\n  closeModal,\n  isAdditionalAction,\n  modalClassName,\n  modalIsOpen,\n  openModal,\n}: PropsWithChildren<PollActionProps>) => {\n  const { Modal = GlobalModal } = useComponentContext();\n  return (\n    <>\n      <Button\n        appearance='outline'\n        className={clsx('str-chat__poll-action', {\n          'str-chat__poll-action--additional': isAdditionalAction,\n        })}\n        onClick={openModal}\n        size='md'\n        variant='secondary'\n      >\n        {buttonText}\n      </Button>\n      <Modal className={modalClassName} onClose={closeModal} open={modalIsOpen}>\n        {children}\n      </Modal>\n    </>\n  );\n};\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n  useChatContext,\n  useModalContext,\n  usePollContext,\n  useTranslationContext,\n} from '../../../context';\nimport { useStateStore } from '../../../store';\nimport type { PollOption, PollState } from 'stream-chat';\nimport { Prompt } from '../../Dialog';\nimport { TextInput } from '../../Form';\nimport { useFormState } from '../../Form/hooks';\n\ntype PollStateSelectorReturnValue = { options: PollOption[] };\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  options: nextValue.options,\n});\n\nexport type SuggestPollOptionFormProps = Record<string, never>;\n\nexport const SuggestPollOptionPrompt = () => {\n  const { client } = useChatContext();\n  const { t } = useTranslationContext();\n  const { poll } = usePollContext();\n  const { close } = useModalContext();\n  const { options } = useStateStore(poll.state, pollStateSelector);\n  const [input, setInput] = useState<HTMLInputElement | null>(null);\n\n  const initialValue = useMemo(() => ({ optionText: '' }), []);\n  const validators = useMemo(\n    () => ({\n      optionText: (v: string) => {\n        const trimmed = typeof v === 'string' ? v.trim() : '';\n        if (!trimmed) {\n          return new Error(t('This field cannot be empty or contain only spaces'));\n        }\n        const existingOption = options.find((option) => option.text === trimmed);\n        if (existingOption) {\n          return new Error(t('Option already exists'));\n        }\n        return undefined;\n      },\n    }),\n    [t, options],\n  );\n\n  const onSubmit = useCallback(\n    async (formValue: { optionText: string }) => {\n      await client.createPollOption(poll.id, {\n        text: formValue.optionText,\n      });\n      close();\n    },\n    [client, poll, close],\n  );\n\n  const { fieldErrors, handleSubmit, setFieldValue, value } = useFormState<{\n    optionText: string;\n  }>({\n    initialValue,\n    onSubmit,\n    validators,\n  });\n\n  useEffect(() => {\n    input?.focus();\n  }, [input]);\n\n  const submitDisabled = !value.optionText?.trim();\n\n  return (\n    <Prompt.Root className='str-chat__modal__suggest-poll-option-prompt'>\n      <Prompt.Header\n        close={close}\n        description={t('Suggest a new option to add to this poll')}\n        title={t('Suggest an option')}\n      />\n      <form autoComplete='off' onSubmit={handleSubmit}>\n        <Prompt.Body>\n          <TextInput\n            aria-label={t('Suggest an option')}\n            error={!!fieldErrors.optionText}\n            errorMessage={fieldErrors.optionText?.message}\n            id='optionText'\n            name='optionText'\n            onChange={(e) => setFieldValue('optionText', e.target.value)}\n            placeholder={t('placeholder/PollOptionSuggestion')}\n            ref={setInput}\n            required\n            type='text'\n            value={value.optionText}\n          />\n        </Prompt.Body>\n        <Prompt.Footer>\n          <Prompt.FooterControls>\n            <Prompt.FooterControlsButtonSecondary\n              className='str-chat__prompt__footer__controls-button--cancel'\n              onClick={close}\n            >\n              {t('Cancel')}\n            </Prompt.FooterControlsButtonSecondary>\n            <Prompt.FooterControlsButtonPrimary\n              className='str-chat__prompt__footer__controls-button--submit'\n              disabled={Object.keys(fieldErrors).length > 0 || submitDisabled}\n              type='submit'\n            >\n              {t('Send')}\n            </Prompt.FooterControlsButtonPrimary>\n          </Prompt.FooterControls>\n        </Prompt.Footer>\n      </form>\n    </Prompt.Root>\n  );\n};\n","import React, { useState } from 'react';\nimport { Avatar } from '../Avatar';\nimport { PopperTooltip } from '../Tooltip';\nimport { useEnterLeaveHandlers } from '../Tooltip/hooks';\nimport { useChatContext, useTranslationContext } from '../../context';\n\nimport type { PollVote as PollVoteType } from 'stream-chat';\n\nconst PollVoteTimestamp = ({ timestamp }: { timestamp: string }) => {\n  const { t } = useTranslationContext();\n  const { handleEnter, handleLeave, tooltipVisible } =\n    useEnterLeaveHandlers<HTMLSpanElement>();\n  const [referenceElement, setReferenceElement] = useState<HTMLSpanElement | null>(null);\n  const timestampDate = new Date(timestamp);\n  return (\n    <div\n      className='str-chat__poll-vote__timestamp'\n      onMouseEnter={handleEnter}\n      onMouseLeave={handleLeave}\n      ref={setReferenceElement}\n    >\n      {t('timestamp/PollVote', { timestamp: timestampDate })}\n      <PopperTooltip\n        offset={[0, 5]}\n        placement='bottom'\n        referenceElement={referenceElement}\n        visible={tooltipVisible}\n      >\n        {t('timestamp/PollVoteTooltip', { timestamp: timestampDate })}\n      </PopperTooltip>\n    </div>\n  );\n};\n\ntype PollVoteProps = {\n  vote: PollVoteType;\n};\n\ntype PollVoteAuthor = PollVoteProps;\n\nconst PollVoteAuthor = ({ vote }: PollVoteAuthor) => {\n  const { t } = useTranslationContext();\n  const { client } = useChatContext();\n  const displayName =\n    client.user?.id && client.user.id === vote.user?.id\n      ? t('You')\n      : vote.user?.name || vote.user?.id || t('Anonymous');\n\n  return (\n    <div className='str-chat__poll-vote__author'>\n      {vote.user && (\n        <Avatar\n          className='str-chat__avatar--poll-vote-author'\n          imageUrl={vote.user.image}\n          key={`poll-vote-${vote.id}-avatar-${vote.user.id}`}\n          size='md'\n          userName={vote.user.name}\n        />\n      )}\n      <div className='str-chat__poll-vote__author__name'>{displayName}</div>\n    </div>\n  );\n};\n\nexport const PollVote = ({ vote }: PollVoteProps) => (\n  <div className='str-chat__poll-vote'>\n    <PollVoteAuthor vote={vote} />\n    <PollVoteTimestamp timestamp={vote.created_at} />\n  </div>\n);\n\nexport type PollVoteListingProps = {\n  votes: PollVoteType[];\n};\n\nexport const PollVoteListing = ({ votes }: PollVoteListingProps) => (\n  <div className='str-chat__poll-vote-listing'>\n    {votes.map((vote) => (\n      <PollVote key={`poll-vote-${vote.id}`} vote={vote} />\n    ))}\n  </div>\n);\n","import { useEffect, useState } from 'react';\nimport { isVoteAnswer } from 'stream-chat';\nimport { useChatContext } from '../../../context';\nimport type { Event, PollAnswer, PollVote } from 'stream-chat';\n\nimport type { CursorPaginatorStateStore } from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\n\nexport function useManagePollVotesRealtime<T extends PollVote | PollAnswer = PollVote>(\n  managedVoteType: 'answer' | 'vote',\n  cursorPaginatorState?: CursorPaginatorStateStore<T>,\n  optionId?: string,\n) {\n  const { client } = useChatContext();\n  const [votesInRealtime, setVotesInRealtime] = useState<T[]>(\n    cursorPaginatorState?.getLatestValue().items ?? [],\n  );\n\n  useEffect(\n    () =>\n      cursorPaginatorState?.subscribeWithSelector(\n        (state) => [state.latestPageItems],\n        ([latestPageItems]) =>\n          setVotesInRealtime((prev) => [...prev, ...latestPageItems]),\n      ),\n    [cursorPaginatorState],\n  );\n\n  useEffect(() => {\n    const handleVoteEvent = (event: Event) => {\n      if (!event.poll_vote) return;\n      const isAnswer = isVoteAnswer(event.poll_vote);\n      if (\n        (managedVoteType === 'answer' && !isAnswer) ||\n        (managedVoteType === 'vote' &&\n          (isAnswer || event.poll_vote.option_id !== optionId))\n      )\n        return;\n\n      if (event.type === 'poll.vote_removed') {\n        setVotesInRealtime((prev) =>\n          event.poll_vote\n            ? prev.filter((vote) => vote.id !== (event.poll_vote as T).id)\n            : prev,\n        );\n      }\n      if (event.type === 'poll.vote_changed') {\n        setVotesInRealtime((prev) =>\n          event.poll_vote\n            ? prev.filter((vote) => vote.id !== (event.poll_vote as T).id)\n            : prev,\n        );\n      }\n      if (['poll.vote_casted', 'poll.vote_changed'].includes(event.type)) {\n        setVotesInRealtime((prev) =>\n          event.poll_vote ? [event.poll_vote as T, ...prev] : prev,\n        );\n      }\n    };\n\n    const voteCastedSubscription = client.on('poll.vote_casted', handleVoteEvent);\n    const voteRemovedSubscription = client.on('poll.vote_removed', handleVoteEvent);\n    const voteChangedSubscription = client.on('poll.vote_changed', handleVoteEvent);\n\n    return () => {\n      voteCastedSubscription.unsubscribe();\n      voteRemovedSubscription.unsubscribe();\n      voteChangedSubscription.unsubscribe();\n    };\n  }, [client, optionId, managedVoteType]);\n\n  return votesInRealtime;\n}\n","import uniqBy from 'lodash.uniqby';\nimport { useCallback, useEffect, useMemo } from 'react';\nimport { StateStore } from 'stream-chat';\n\nexport type CursorPaginatorState<T> = {\n  hasNextPage: boolean;\n  items: T[];\n  latestPageItems: T[];\n  loading: boolean;\n  error?: Error;\n  next?: string | null;\n};\n\nexport type CursorPaginatorStateStore<T> = StateStore<CursorPaginatorState<T>>;\n\nexport type PaginationFn<T> = (next?: string) => Promise<{ items: T[]; next?: string }>;\n\nexport const useCursorPaginator = <T>(\n  paginationFn: PaginationFn<T>,\n  loadFirstPage?: boolean,\n) => {\n  const cursorPaginatorState = useMemo(\n    () =>\n      new StateStore<CursorPaginatorState<T>>({\n        hasNextPage: true,\n        items: [],\n        latestPageItems: [],\n        loading: false,\n      }),\n    [],\n  );\n\n  const loadMore = useCallback(async () => {\n    const { loading, next: currentNext } = cursorPaginatorState.getLatestValue();\n    if (currentNext === null || loading) return;\n\n    cursorPaginatorState.partialNext({ loading: true });\n\n    try {\n      const { items, next } = await paginationFn(currentNext);\n      cursorPaginatorState.next((prev) => ({\n        ...prev,\n        hasNextPage: !!next,\n        items: uniqBy(prev.items.concat(items), 'id'),\n        latestPageItems: items,\n        next: next || null,\n      }));\n    } catch (error) {\n      cursorPaginatorState.partialNext({ error: error as Error });\n    }\n    cursorPaginatorState.partialNext({ loading: false });\n  }, [cursorPaginatorState, paginationFn]);\n\n  useEffect(() => {\n    const { items } = cursorPaginatorState.getLatestValue();\n    if (!loadFirstPage || items.length) return;\n    loadMore();\n  }, [cursorPaginatorState, loadFirstPage, loadMore]);\n\n  return {\n    cursorPaginatorState,\n    loadMore,\n  };\n};\n","import { useCallback } from 'react';\nimport { useManagePollVotesRealtime } from './useManagePollVotesRealtime';\nimport type {\n  CursorPaginatorState,\n  PaginationFn,\n} from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { useCursorPaginator } from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { usePollContext } from '../../../context';\n\nimport { useStateStore } from '../../../store';\nimport type { PollAnswer, PollAnswersQueryParams, PollVote } from 'stream-chat';\n\nconst paginationStateSelector = (\n  state: CursorPaginatorState<PollVote>,\n): [Error | undefined, boolean, boolean] => [\n  state.error,\n  state.hasNextPage,\n  state.loading,\n];\n\ntype UsePollAnswerPaginationParams = {\n  paginationParams?: PollAnswersQueryParams;\n};\n\nexport const usePollAnswerPagination = ({\n  paginationParams,\n}: UsePollAnswerPaginationParams = {}) => {\n  const { poll } = usePollContext();\n\n  const paginationFn = useCallback<PaginationFn<PollAnswer>>(\n    async (next) => {\n      const { next: newNext, votes } = await poll.queryAnswers({\n        filter: paginationParams?.filter,\n        options: !next\n          ? paginationParams?.options\n          : { ...paginationParams?.options, next },\n        sort: { created_at: -1, ...paginationParams?.sort },\n      });\n      return { items: votes, next: newNext };\n    },\n    [paginationParams, poll],\n  );\n\n  const { cursorPaginatorState, loadMore } = useCursorPaginator(paginationFn, true);\n  const answers = useManagePollVotesRealtime<PollAnswer>('answer', cursorPaginatorState);\n  const [error, hasNextPage, loading] = useStateStore(\n    cursorPaginatorState,\n    paginationStateSelector,\n  );\n\n  return {\n    answers,\n    error,\n    hasNextPage,\n    loading,\n    loadMore,\n  };\n};\n","import { useCallback } from 'react';\nimport { useManagePollVotesRealtime } from './useManagePollVotesRealtime';\nimport type {\n  CursorPaginatorState,\n  PaginationFn,\n} from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { useCursorPaginator } from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { useStateStore } from '../../../store';\nimport { usePollContext } from '../../../context';\n\nimport type { PollOptionVotesQueryParams, PollVote } from 'stream-chat';\n\nconst paginationStateSelector = (\n  state: CursorPaginatorState<PollVote>,\n): [Error | undefined, boolean, boolean] => [\n  state.error,\n  state.hasNextPage,\n  state.loading,\n];\n\ntype UsePollOptionVotesPaginationParams = {\n  paginationParams: PollOptionVotesQueryParams;\n};\n\nexport const usePollOptionVotesPagination = ({\n  paginationParams,\n}: UsePollOptionVotesPaginationParams) => {\n  const { poll } = usePollContext();\n\n  const paginationFn = useCallback<PaginationFn<PollVote>>(\n    async (next) => {\n      const { next: newNext, votes } = await poll.queryOptionVotes({\n        filter: paginationParams.filter,\n        options: !next\n          ? paginationParams?.options\n          : { ...paginationParams?.options, next },\n        sort: { created_at: -1, ...paginationParams?.sort },\n      });\n      return { items: votes, next: newNext };\n    },\n    [paginationParams, poll],\n  );\n\n  const { cursorPaginatorState, loadMore } = useCursorPaginator(paginationFn, true);\n  const votes = useManagePollVotesRealtime<PollVote>(\n    'vote',\n    cursorPaginatorState,\n    paginationParams.filter.option_id,\n  );\n  const [error, hasNextPage, loading] = useStateStore(\n    cursorPaginatorState,\n    paginationStateSelector,\n  );\n\n  return {\n    error,\n    hasNextPage,\n    loading,\n    loadMore,\n    votes,\n  };\n};\n","import clsx from 'clsx';\nimport debounce from 'lodash.debounce';\nimport type { PropsWithChildren } from 'react';\nimport React, { useEffect, useMemo, useRef } from 'react';\nimport { DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD } from '../../constants/limits';\n\n/**\n * Prevents Chrome hangups\n * See: https://stackoverflow.com/questions/47524205/random-high-content-download-time-in-chrome/47684257#47684257\n */\nconst mousewheelListener = (event: Event) => {\n  if (event instanceof WheelEvent && event.deltaY === 1) {\n    event.preventDefault();\n  }\n};\n\nexport type InfiniteScrollPaginatorProps = React.ComponentProps<'div'> & {\n  listenToScroll?: (\n    distanceFromBottom: number,\n    distanceFromTop: number,\n    threshold: number,\n  ) => void;\n  loadNextDebounceMs?: number;\n  loadNextOnScrollToBottom?: () => void;\n  loadNextOnScrollToTop?: () => void;\n  /** Offset from when to start the loadNextPage call */\n  threshold?: number;\n  useCapture?: boolean;\n};\n\nexport const InfiniteScrollPaginator = (\n  props: PropsWithChildren<InfiniteScrollPaginatorProps>,\n) => {\n  const {\n    children,\n    className,\n    listenToScroll,\n    loadNextDebounceMs = 500,\n    loadNextOnScrollToBottom,\n    loadNextOnScrollToTop,\n    threshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD,\n    useCapture = false,\n    ...componentProps\n  } = props;\n\n  const rootRef = useRef<HTMLDivElement | null>(null);\n  const childRef = useRef<HTMLDivElement | null>(null);\n\n  const scrollListener = useMemo(\n    () =>\n      debounce(() => {\n        const root = rootRef.current;\n        const child = childRef.current;\n        if (!root || root.offsetParent === null || !child) {\n          return;\n        }\n\n        const distanceFromBottom =\n          child.scrollHeight - root.scrollTop - root.clientHeight;\n        const distanceFromTop = root.scrollTop;\n\n        if (listenToScroll) {\n          listenToScroll(distanceFromBottom, distanceFromTop, threshold);\n        }\n\n        if (distanceFromTop < Number(threshold)) {\n          loadNextOnScrollToTop?.();\n        }\n\n        if (distanceFromBottom < Number(threshold)) {\n          loadNextOnScrollToBottom?.();\n        }\n      }, loadNextDebounceMs),\n    [\n      listenToScroll,\n      loadNextDebounceMs,\n      loadNextOnScrollToBottom,\n      loadNextOnScrollToTop,\n      threshold,\n    ],\n  );\n\n  useEffect(() => {\n    const scrollElement = rootRef.current;\n    if (!scrollElement) return;\n\n    scrollElement.addEventListener('scroll', scrollListener, useCapture);\n\n    return () => {\n      scrollElement.removeEventListener('scroll', scrollListener, useCapture);\n    };\n  }, [scrollListener, useCapture]);\n\n  useEffect(() => {\n    const root = rootRef.current;\n    if (!root || typeof ResizeObserver === 'undefined' || !scrollListener) return;\n    const observer = new ResizeObserver(scrollListener);\n    observer.observe(root as Element);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [scrollListener]);\n\n  useEffect(() => {\n    const root = rootRef.current;\n    if (root) {\n      root.addEventListener('wheel', mousewheelListener, { passive: false });\n    }\n    return () => {\n      if (root) {\n        root.removeEventListener('wheel', mousewheelListener, useCapture);\n      }\n    };\n  }, [useCapture]);\n\n  return (\n    <div\n      {...componentProps}\n      className={clsx('str-chat__infinite-scroll-paginator', className)}\n      ref={rootRef}\n    >\n      <div className='str-chat__infinite-scroll-paginator__content' ref={childRef}>\n        {children}\n      </div>\n    </div>\n  );\n};\n","import React from 'react';\nimport { Button } from '../../Button';\nimport { Viewer } from '../../Dialog';\nimport { PollVote } from '../PollVote';\nimport { usePollAnswerPagination } from '../hooks';\nimport { InfiniteScrollPaginator } from '../../InfiniteScrollPaginator/InfiniteScrollPaginator';\nimport { LoadingIndicator } from '../../Loading';\nimport { useStateStore } from '../../../store';\nimport {\n  useChatContext,\n  useModalContext,\n  usePollContext,\n  useTranslationContext,\n} from '../../../context';\n\nimport type { PollAnswer, PollState } from 'stream-chat';\n\ntype PollStateSelectorReturnValue = {\n  is_closed: boolean | undefined;\n  ownAnswer: PollAnswer | undefined;\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  is_closed: nextValue.is_closed,\n  ownAnswer: nextValue.ownAnswer,\n});\n\nexport type PollAnswerListProps = {\n  onUpdateOwnAnswerClick: () => void;\n};\n\nexport const PollAnswerList = ({ onUpdateOwnAnswerClick }: PollAnswerListProps) => {\n  const { client } = useChatContext();\n  const { t } = useTranslationContext();\n  const { poll } = usePollContext();\n  const { close } = useModalContext();\n  const { is_closed } = useStateStore(poll.state, pollStateSelector);\n\n  const { answers, error, hasNextPage, loading, loadMore } = usePollAnswerPagination();\n\n  return (\n    <Viewer.Root className='str-chat__modal__poll-answer-list'>\n      <Viewer.Header\n        close={close}\n        description={t('Review comments submitted with poll answers')}\n        title={t('Poll comments')}\n      />\n      <Viewer.Body className='str-chat__modal__poll-answer-list__body'>\n        <div className='str-chat__poll-answer-list'>\n          <InfiniteScrollPaginator loadNextOnScrollToBottom={loadMore} threshold={40}>\n            {answers.map((answer) => (\n              <div className='str-chat__poll-answer' key={`comment-${answer.id}`}>\n                <div className='str-chat__poll-answer__data'>\n                  {answer.answer_text && (\n                    <p className='str-chat__poll-answer__text'>{answer.answer_text}</p>\n                  )}\n                  <PollVote key={`poll-vote-${answer.id}`} vote={answer} />\n                </div>\n                {!is_closed && answer.user?.id === client.user?.id && (\n                  <div className='str-chat__poll-vote__update-vote-button-container'>\n                    <Button\n                      appearance='ghost'\n                      className='str-chat__poll-vote__update-vote-button'\n                      onClick={onUpdateOwnAnswerClick}\n                      size='md'\n                      variant='secondary'\n                    >\n                      {t('Update your comment')}\n                    </Button>\n                  </div>\n                )}\n              </div>\n            ))}\n\n            {hasNextPage && (\n              <div className='str-chat__loading-indicator-placeholder'>\n                {loading && <LoadingIndicator />}\n              </div>\n            )}\n          </InfiniteScrollPaginator>\n        </div>\n        {error?.message && <div>{error?.message}</div>}\n      </Viewer.Body>\n      {/*<Viewer.Footer>*/}\n      {/*  {answers.length > 0 && !is_closed && (*/}\n      {/*    <Viewer.FooterControls>*/}\n      {/*      <Viewer.FooterControlsButtonSecondary*/}\n      {/*        className='str-chat__poll-action'*/}\n      {/*        onClick={onUpdateOwnAnswerClick}*/}\n      {/*      >*/}\n      {/*        {ownAnswer ? t('Update your comment') : t('Add a comment')}*/}\n      {/*      </Viewer.FooterControlsButtonSecondary>*/}\n      {/*    </Viewer.FooterControls>*/}\n      {/*  )}*/}\n      {/*</Viewer.Footer>*/}\n    </Viewer.Root>\n  );\n};\n","import React from 'react';\nimport { useStateStore } from '../../../../store';\nimport { usePollContext, useTranslationContext } from '../../../../context';\nimport type { PollOption, PollState } from 'stream-chat';\nimport { IconTrophy } from '../../../Icons';\n\ntype PollStateSelectorReturnValue = {\n  maxVotedOptionIds: string[];\n  vote_counts_by_option: Record<string, number>;\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  maxVotedOptionIds: nextValue.maxVotedOptionIds,\n  vote_counts_by_option: nextValue.vote_counts_by_option,\n});\n\nexport type PollResultOptionVoteCounterProps = {\n  optionId: string;\n};\n\nexport const PollResultOptionVoteCounter = ({\n  optionId,\n}: PollResultOptionVoteCounterProps) => {\n  const { t } = useTranslationContext();\n  const { poll } = usePollContext();\n  const { maxVotedOptionIds, vote_counts_by_option } = useStateStore(\n    poll.state,\n    pollStateSelector,\n  );\n\n  return (\n    <div className='str-chat__poll-result-option-vote-counter'>\n      {maxVotedOptionIds.length === 1 && maxVotedOptionIds[0] === optionId && (\n        <IconTrophy />\n      )}\n      <span className='str-chat__poll-result-option-vote-count'>\n        {t('{{count}} votes', { count: vote_counts_by_option[optionId] ?? 0 })}\n      </span>\n    </div>\n  );\n};\n\nexport type PollOptionWithVotesHeaderProps = {\n  option: PollOption;\n  optionOrderNumber: number;\n};\n\nexport const PollOptionWithVotesHeader = ({\n  option,\n  optionOrderNumber,\n}: PollOptionWithVotesHeaderProps) => {\n  const { t } = useTranslationContext();\n\n  return (\n    <div className='str-chat__poll-option__header'>\n      <div className='str-chat__poll-option__header__label'>\n        {t('Question {{ optionOrderNumber}}', { optionOrderNumber })}\n      </div>\n      <div className='str-chat__poll-option__header__title'>\n        <div className='str-chat__poll-option__option-text'>{option.text}</div>\n        <PollResultOptionVoteCounter optionId={option.id} />\n      </div>\n    </div>\n  );\n};\n","import React from 'react';\nimport { PollOptionWithVotesHeader } from './PollOptionWithVotesHeader';\nimport { PollVoteListing } from '../../PollVote';\nimport { useStateStore } from '../../../../store';\nimport {\n  useChannelStateContext,\n  usePollContext,\n  useTranslationContext,\n} from '../../../../context';\nimport type { PollOption, PollState, PollVote } from 'stream-chat';\nimport { Button } from '../../../Button';\nimport clsx from 'clsx';\n\ntype PollStateSelectorReturnValue = {\n  latest_votes_by_option: Record<string, PollVote[]>;\n};\n\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  latest_votes_by_option: nextValue.latest_votes_by_option,\n});\n\nexport type PollOptionWithVotesProps = {\n  option: PollOption;\n  orderNumber: number;\n  countVotesPreview?: number;\n  showAllVotes?: () => void;\n};\n\nexport const PollOptionWithVotes = ({\n  countVotesPreview,\n  option,\n  orderNumber,\n  showAllVotes,\n}: PollOptionWithVotesProps) => {\n  const { t } = useTranslationContext();\n  const { channelCapabilities = {} } = useChannelStateContext('PollOptionWithVotes');\n  const { poll } = usePollContext();\n  const { latest_votes_by_option } = useStateStore(poll.state, pollStateSelector);\n\n  const votes = latest_votes_by_option && latest_votes_by_option[option.id];\n  const voteCount = votes?.length ?? 0;\n  const isVotesPreview = typeof countVotesPreview === 'number';\n\n  return (\n    <div\n      className={clsx('str-chat__poll-option', {\n        'str-chat__poll-option--has-more-votes':\n          isVotesPreview && voteCount > countVotesPreview,\n        'str-chat__poll-option--has-votes': voteCount,\n      })}\n    >\n      <PollOptionWithVotesHeader option={option} optionOrderNumber={orderNumber} />\n      {!!votes && <PollVoteListing votes={votes.slice(0, countVotesPreview)} />}\n      {channelCapabilities['query-poll-votes'] &&\n        showAllVotes &&\n        isVotesPreview &&\n        votes?.length > countVotesPreview && (\n          <div className='str-chat__poll-option__show-all-votes-button-container'>\n            <Button\n              appearance='ghost'\n              className='str-chat__poll-option__show-all-votes-button'\n              onClick={showAllVotes}\n              size='md'\n              variant='secondary'\n            >\n              {t('View all')}\n            </Button>\n          </div>\n        )}\n    </div>\n  );\n};\n","import { useTranslationContext } from '../../../context';\n\nexport type PollQuestionProps = {\n  question: string;\n};\n\nexport const PollQuestion = ({ question }: PollQuestionProps) => {\n  const { t } = useTranslationContext();\n  return (\n    <div className='str-chat__modal__poll-question'>\n      <div className='str-chat__modal__poll-question__label'>{t('Question')}</div>\n      <div className='str-chat__modal__poll-question__text'>{question}</div>\n    </div>\n  );\n};\n","import React, { useMemo } from 'react';\nimport { PollVoteListing } from '../../PollVote';\nimport { usePollOptionVotesPagination } from '../../hooks';\nimport { LoadingIndicator } from '../../../Loading';\nimport { InfiniteScrollPaginator } from '../../../InfiniteScrollPaginator/InfiniteScrollPaginator';\nimport type { PollOption, PollOptionVotesQueryParams } from 'stream-chat';\nimport { PollOptionWithVotesHeader } from './PollOptionWithVotesHeader';\n\nexport type PollOptionWithVotesListProps = {\n  option: PollOption;\n  optionOrderNumber: number;\n};\n\nexport const PollOptionWithVotesList = ({\n  option,\n  optionOrderNumber,\n}: PollOptionWithVotesListProps) => {\n  const paginationParams = useMemo<PollOptionVotesQueryParams>(\n    () => ({ filter: { option_id: option.id } }),\n    [option.id],\n  );\n  const { hasNextPage, loading, loadMore, votes } = usePollOptionVotesPagination({\n    paginationParams,\n  });\n\n  return (\n    <InfiniteScrollPaginator loadNextOnScrollToBottom={loadMore} threshold={40}>\n      <div className='str-chat_poll-option-with-votes-list'>\n        <div className='str-chat__poll-option'>\n          <div className='str-chat__poll-option__votes-paginated-list'>\n            <PollOptionWithVotesHeader\n              option={option}\n              optionOrderNumber={optionOrderNumber}\n            />\n            <PollVoteListing votes={votes} />\n            {hasNextPage && (\n              <div className='str-chat__loading-indicator-placeholder'>\n                {loading && <LoadingIndicator />}\n              </div>\n            )}\n          </div>\n        </div>\n      </div>\n    </InfiniteScrollPaginator>\n  );\n};\n","import clsx from 'clsx';\nimport React, { useCallback, useState } from 'react';\nimport { PollOptionWithVotes } from './PollOptionWithVotes';\nimport { Viewer } from '../../../Dialog';\nimport { useStateStore } from '../../../../store';\nimport {\n  useModalContext,\n  usePollContext,\n  useTranslationContext,\n} from '../../../../context';\nimport type { PollOption, PollState } from 'stream-chat';\nimport { COUNT_OPTION_VOTES_PREVIEW } from '../../constants';\nimport { PollQuestion } from '../PollQuestion';\nimport { PollOptionWithVotesList } from './PollOptionWithVotesList';\n\nconst pollStateSelector = ({\n  name,\n  options,\n  vote_count,\n  vote_counts_by_option,\n}: PollState) => ({\n  name,\n  options: [...options],\n  vote_count,\n  vote_counts_by_option,\n});\n\nexport const PollResults = () => {\n  const { t } = useTranslationContext();\n  const { poll } = usePollContext();\n  const { close } = useModalContext();\n  const { name, options, vote_count, vote_counts_by_option } = useStateStore(\n    poll.state,\n    pollStateSelector,\n  );\n  const [optionToView, setOptionToView] = useState<{\n    option: PollOption;\n    optionOrderNumber: number;\n  } | null>(null);\n\n  const goBack = useCallback(() => setOptionToView(null), []);\n\n  return (\n    <Viewer.Root\n      className={clsx('str-chat__modal__poll-results', {\n        'str-chat__modal__poll-results--option-detail': optionToView,\n      })}\n    >\n      {optionToView?.option ? (\n        <>\n          <Viewer.Header\n            close={close}\n            description={t('Review who voted for this option')}\n            goBack={goBack}\n            title={t('Votes')}\n          />\n          <Viewer.Body className='str-chat__modal__poll-results__body'>\n            <PollOptionWithVotesList\n              option={optionToView?.option}\n              optionOrderNumber={optionToView?.optionOrderNumber}\n            />\n          </Viewer.Body>\n        </>\n      ) : (\n        <>\n          <Viewer.Header\n            close={close}\n            description={t(\n              'Review poll results and open an option to see detailed votes',\n            )}\n            title={t('Poll results')}\n          />\n          <Viewer.Body className='str-chat__modal__poll-results__body'>\n            <PollQuestion question={name} />\n            <div className='str-chat__modal__poll-results__options'>\n              <div className='str-chat__modal__poll-results__option-list'>\n                {options\n                  .sort((next, current) =>\n                    (vote_counts_by_option[current.id] ?? 0) >=\n                    (vote_counts_by_option[next.id] ?? 0)\n                      ? 1\n                      : -1,\n                  )\n                  .map((option, i) => {\n                    const optionOrderNumber = i + 1;\n                    return (\n                      <PollOptionWithVotes\n                        countVotesPreview={COUNT_OPTION_VOTES_PREVIEW}\n                        key={`poll-option-${option.id}`}\n                        option={option}\n                        orderNumber={optionOrderNumber}\n                        showAllVotes={() =>\n                          setOptionToView({ option, optionOrderNumber })\n                        }\n                      />\n                    );\n                  })}\n              </div>\n              <div className='str-chat__modal__poll-results__options__footer'>\n                <div className='str-chat__modal__poll-results__options-total-count'>\n                  {t('totalVoteCount', { count: vote_count })}\n                </div>\n              </div>\n            </div>\n          </Viewer.Body>\n        </>\n      )}\n    </Viewer.Root>\n  );\n};\n","import clsx from 'clsx';\nimport React, { useCallback, useState } from 'react';\nimport { PollAction } from './PollAction';\nimport type { AddCommentPromptProps } from './AddCommentPrompt';\nimport { AddCommentPrompt as DefaultAddCommentPrompt } from './AddCommentPrompt';\nimport type { SuggestPollOptionFormProps } from './SuggestPollOptionPrompt';\nimport { SuggestPollOptionPrompt as DefaultSuggestPollOptionForm } from './SuggestPollOptionPrompt';\nimport { EndPollAlert as DefaultEndPollAlert } from './EndPollAlert';\nimport type { PollAnswerListProps } from './PollAnswerList';\nimport { PollAnswerList as DefaultPollAnswerList } from './PollAnswerList';\nimport { PollResults as DefaultPollResults } from './PollResults';\nimport { MAX_POLL_OPTIONS } from '../constants';\nimport {\n  useChannelStateContext,\n  useChatContext,\n  useMessageContext,\n  usePollContext,\n  useTranslationContext,\n} from '../../../context';\nimport { useStateStore } from '../../../store';\n\nimport type { PollState } from 'stream-chat';\n\nconst COMMON_MODAL_CLASS = 'str-chat__poll-action-modal' as const;\n\ntype ModalName =\n  | 'suggest-option'\n  | 'add-comment'\n  | 'view-comments'\n  | 'view-results'\n  | 'end-vote';\n\nconst pollStateSelector = (nextValue: PollState) => ({\n  allow_answers: nextValue.allow_answers,\n  allow_user_suggested_options: nextValue.allow_user_suggested_options,\n  answers_count: nextValue.answers_count,\n  created_by_id: nextValue.created_by_id,\n  is_closed: nextValue.is_closed,\n  options: nextValue.options,\n  ownAnswer: nextValue.ownAnswer,\n  voteCount: nextValue.vote_count,\n});\n\nexport type PollActionsProps = {\n  AddCommentPrompt?: React.ComponentType<AddCommentPromptProps>;\n  EndPollAlert?: React.ComponentType;\n  PollAnswerList?: React.ComponentType<PollAnswerListProps>;\n  PollResults?: React.ComponentType;\n  SuggestPollOptionForm?: React.ComponentType<SuggestPollOptionFormProps>;\n};\n\nexport const PollActions = ({\n  AddCommentPrompt = DefaultAddCommentPrompt,\n  EndPollAlert = DefaultEndPollAlert,\n  PollAnswerList = DefaultPollAnswerList,\n  PollResults = DefaultPollResults,\n  SuggestPollOptionForm = DefaultSuggestPollOptionForm,\n}: PollActionsProps) => {\n  const { client } = useChatContext();\n  const { t } = useTranslationContext('PollActions');\n  const { channelCapabilities = {} } = useChannelStateContext('PollActions');\n  const { message } = useMessageContext('PollActions');\n  const { poll } = usePollContext();\n  const {\n    allow_answers,\n    allow_user_suggested_options,\n    answers_count,\n    created_by_id,\n    is_closed,\n    options,\n    ownAnswer,\n    voteCount,\n  } = useStateStore(poll.state, pollStateSelector);\n  const [modalOpen, setModalOpen] = useState<ModalName | undefined>();\n\n  const canCastVote = channelCapabilities['cast-poll-vote'] && !is_closed;\n  const closeModal = useCallback(() => setModalOpen(undefined), []);\n  const onUpdateAnswerClick = useCallback(() => setModalOpen('add-comment'), []);\n\n  const hasContents =\n    (!is_closed && created_by_id === client.user?.id) ||\n    !!voteCount ||\n    (canCastVote && allow_user_suggested_options && options.length < MAX_POLL_OPTIONS) ||\n    (!is_closed && allow_answers) ||\n    (answers_count > 0 && channelCapabilities['query-poll-votes']);\n\n  if (!hasContents) return null;\n\n  return (\n    <div className='str-chat__poll-actions'>\n      {!is_closed && created_by_id === client.user?.id && (\n        <PollAction\n          buttonText={t('End poll')}\n          closeModal={closeModal}\n          modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__end-poll-modal')}\n          modalIsOpen={modalOpen === 'end-vote'}\n          openModal={() => setModalOpen('end-vote')}\n        >\n          <EndPollAlert />\n        </PollAction>\n      )}\n\n      {!!voteCount && (\n        <PollAction\n          buttonText={t('View results')}\n          closeModal={closeModal}\n          modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__poll-results-modal')}\n          modalIsOpen={modalOpen === 'view-results'}\n          openModal={() => setModalOpen('view-results')}\n        >\n          <PollResults />\n        </PollAction>\n      )}\n\n      {canCastVote &&\n        allow_user_suggested_options &&\n        options.length < MAX_POLL_OPTIONS && (\n          <PollAction\n            buttonText={t('Suggest an option')}\n            closeModal={closeModal}\n            isAdditionalAction\n            modalClassName={clsx(\n              COMMON_MODAL_CLASS,\n              'str-chat__suggest-poll-option-modal',\n            )}\n            modalIsOpen={modalOpen === 'suggest-option'}\n            openModal={() => setModalOpen('suggest-option')}\n          >\n            <SuggestPollOptionForm />\n          </PollAction>\n        )}\n\n      {!is_closed && allow_answers && (\n        <PollAction\n          buttonText={ownAnswer ? t('Update your comment') : t('Add a comment')}\n          closeModal={closeModal}\n          isAdditionalAction\n          modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__add-poll-answer-modal')}\n          modalIsOpen={modalOpen === 'add-comment'}\n          openModal={() => setModalOpen('add-comment')}\n        >\n          <AddCommentPrompt messageId={message.id} />\n        </PollAction>\n      )}\n\n      {answers_count > 0 && channelCapabilities['query-poll-votes'] && (\n        <PollAction\n          buttonText={t('View {{count}} comments', { count: answers_count })}\n          closeModal={closeModal}\n          isAdditionalAction\n          modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__poll-answer-list-modal')}\n          modalIsOpen={modalOpen === 'view-comments'}\n          openModal={() => setModalOpen('view-comments')}\n        >\n          <PollAnswerList onUpdateOwnAnswerClick={onUpdateAnswerClick} />\n        </PollAction>\n      )}\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport debounce from 'lodash.debounce';\nimport React, { useMemo } from 'react';\nimport type { PollOption, PollState, PollVote, VotingVisibility } from 'stream-chat';\nimport { isVoteAnswer } from 'stream-chat';\nimport { AvatarStack as DefaultAvatarStack } from '../Avatar';\nimport {\n  useChannelStateContext,\n  useComponentContext,\n  useMessageContext,\n  usePollContext,\n  useTranslationContext,\n} from '../../context';\nimport { useStateStore } from '../../store';\n\ntype AmountBarProps = {\n  amount: number;\n  className?: string;\n};\n\nexport const AmountBar = ({ amount, className }: AmountBarProps) => (\n  <div\n    aria-hidden='true'\n    className={clsx('str-chat__amount-bar', className)}\n    data-testid='amount-bar'\n    style={\n      {\n        '--str-chat__amount-bar-fulfillment': amount + '%',\n      } as React.CSSProperties\n    }\n  />\n);\n\nexport type CheckmarkProps = { checked?: boolean };\n\nexport const Checkmark = ({ checked }: CheckmarkProps) => (\n  <div\n    className={clsx('str-chat__checkmark', { 'str-chat__checkmark--checked': checked })}\n  />\n);\n\ntype PollStateSelectorReturnValue = {\n  is_closed: boolean | undefined;\n  latest_votes_by_option: Record<string, PollVote[]>;\n  maxVotedOptionIds: string[];\n  ownVotesByOptionId: Record<string, PollVote>;\n  vote_counts_by_option: Record<string, number>;\n  voting_visibility: VotingVisibility | undefined;\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  is_closed: nextValue.is_closed,\n  latest_votes_by_option: nextValue.latest_votes_by_option,\n  maxVotedOptionIds: nextValue.maxVotedOptionIds,\n  ownVotesByOptionId: nextValue.ownVotesByOptionId,\n  vote_counts_by_option: nextValue.vote_counts_by_option,\n  voting_visibility: nextValue.voting_visibility,\n});\n\nexport type PollOptionSelectorProps = {\n  option: PollOption;\n  displayAvatarCount?: number;\n  voteCountVerbose?: boolean;\n};\n\nexport const PollOptionSelector = ({\n  displayAvatarCount,\n  option,\n  voteCountVerbose,\n}: PollOptionSelectorProps) => {\n  const { t } = useTranslationContext();\n  const { channelCapabilities = {} } = useChannelStateContext('PollOptionsShortlist');\n  const { message } = useMessageContext();\n  const { AvatarStack = DefaultAvatarStack } = useComponentContext();\n  const { poll } = usePollContext();\n  const {\n    is_closed,\n    latest_votes_by_option,\n    maxVotedOptionIds,\n    ownVotesByOptionId,\n    vote_counts_by_option,\n    voting_visibility,\n  } = useStateStore(poll.state, pollStateSelector);\n\n  const canCastVote = channelCapabilities['cast-poll-vote'] && !is_closed;\n  const isInteractive = !!canCastVote;\n  const isSelected = !!ownVotesByOptionId[option.id];\n  const winningOptionCount = maxVotedOptionIds[0]\n    ? vote_counts_by_option[maxVotedOptionIds[0]]\n    : 0;\n\n  const toggleVote = useMemo(\n    () =>\n      debounce(() => {\n        if (!canCastVote) return;\n        const haveVotedForTheOption = !!ownVotesByOptionId[option.id];\n        return haveVotedForTheOption\n          ? poll.removeVote(ownVotesByOptionId[option.id].id, message.id)\n          : poll.castVote(option.id, message.id);\n      }, 100),\n    [canCastVote, message.id, option.id, ownVotesByOptionId, poll],\n  );\n\n  const avatarDisplayInfo = useMemo(\n    () =>\n      latest_votes_by_option?.[option.id] &&\n      (latest_votes_by_option[option.id] as PollVote[])\n        .filter((vote) => !!vote.user && !isVoteAnswer(vote))\n        .slice(0, displayAvatarCount)\n        .map(({ user }) => ({\n          id: user!.id, // eslint-disable-line @typescript-eslint/no-non-null-assertion\n          imageUrl: user!.image, // eslint-disable-line @typescript-eslint/no-non-null-assertion\n          userName: user!.name, // eslint-disable-line @typescript-eslint/no-non-null-assertion\n        })),\n    [displayAvatarCount, latest_votes_by_option, option.id],\n  );\n\n  return (\n    <div\n      aria-pressed={isInteractive ? isSelected : undefined}\n      className={clsx('str-chat__poll-option', {\n        'str-chat__poll-option--votable': canCastVote,\n      })}\n      key={`base-poll-option-${option.id}`}\n      onClick={isInteractive ? toggleVote : undefined}\n      onKeyDown={\n        isInteractive\n          ? (event) => {\n              if (event.key !== 'Enter' && event.key !== ' ') return;\n              event.preventDefault();\n              toggleVote();\n            }\n          : undefined\n      }\n      role={isInteractive ? 'button' : undefined}\n      tabIndex={isInteractive ? 0 : undefined}\n    >\n      {canCastVote && <Checkmark checked={isSelected} />}\n      <div className='str-chat__poll-option-data'>\n        <p className='str-chat__poll-option-text'>{option.text}</p>\n        <div className='str-chat__poll-option-votes'>\n          {displayAvatarCount && voting_visibility === 'public' && (\n            <div className='str-chat__poll-option-voters'>\n              <AvatarStack displayInfo={avatarDisplayInfo} size='xs' />\n            </div>\n          )}\n          <div className='str-chat__poll-option-vote-count'>\n            {voteCountVerbose\n              ? t('{{count}} votes', {\n                  count: vote_counts_by_option[option.id] ?? 0,\n                })\n              : (vote_counts_by_option[option.id] ?? 0)}\n          </div>\n        </div>\n      </div>\n      <AmountBar\n        amount={\n          (winningOptionCount &&\n            (vote_counts_by_option[option.id] ?? 0) / winningOptionCount) * 100\n        }\n        className={clsx('str-chat__poll-option__votes-bar', {\n          'str-chat__poll-option__votes-bar--winner':\n            is_closed &&\n            maxVotedOptionIds.length === 1 &&\n            maxVotedOptionIds[0] === option.id,\n        })}\n      />\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport React, { useCallback, useState } from 'react';\nimport { PollAction } from './PollActions/PollAction';\nimport { PollOptionSelector as DefaultPollOptionSelector } from './PollOptionSelector';\nimport { useStateStore } from '../../store';\nimport {\n  useComponentContext,\n  usePollContext,\n  useTranslationContext,\n} from '../../context';\nimport type { PollOption, PollState } from 'stream-chat';\nimport { PollOptionsFullList as DefaultPollOptionsFullList } from './PollActions/PollOptionsFullList';\n\ntype PollStateSelectorReturnValue = { options: PollOption[] };\n\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  options: nextValue.options,\n});\n\nexport type PollOptionListProps = {\n  optionsDisplayCount?: number;\n  PollOptionsFullList?: React.ComponentType;\n};\n\nexport const PollOptionList = ({\n  optionsDisplayCount,\n  PollOptionsFullList = DefaultPollOptionsFullList,\n}: PollOptionListProps) => {\n  const { PollOptionSelector = DefaultPollOptionSelector } = useComponentContext();\n  const { t } = useTranslationContext('PollOptionList');\n  const { poll } = usePollContext();\n  const { options } = useStateStore(poll.state, pollStateSelector);\n  const [viewAllOptionsOpen, setViewAllOptionsOpen] = useState(false);\n  const closeViewAllOptions = useCallback(() => setViewAllOptionsOpen(false), []);\n  const openViewAllOptions = useCallback(() => setViewAllOptionsOpen(true), []);\n\n  const showMoreOptionsButton =\n    typeof optionsDisplayCount === 'number' && options.length > optionsDisplayCount;\n\n  return (\n    <>\n      <div\n        className={clsx('str-chat__poll-option-list', {\n          'str-chat__poll-option-list--full': typeof optionsDisplayCount === 'undefined',\n        })}\n      >\n        {options.slice(0, optionsDisplayCount ?? options.length).map((option) => (\n          <PollOptionSelector\n            displayAvatarCount={3}\n            key={`poll-option-${option.id}`}\n            option={option}\n          />\n        ))}\n      </div>\n      {showMoreOptionsButton && (\n        <PollAction\n          buttonText={t('+{{count}} more options', {\n            count: options.length,\n          })}\n          closeModal={closeViewAllOptions}\n          isAdditionalAction\n          modalClassName='str-chat__poll-action-modal'\n          modalIsOpen={viewAllOptionsOpen}\n          openModal={openViewAllOptions}\n        >\n          <PollOptionsFullList />\n        </PollAction>\n      )}\n    </>\n  );\n};\n","import React from 'react';\nimport { Viewer } from '../../Dialog';\nimport { PollOptionList } from '../PollOptionList';\nimport { useStateStore } from '../../../store';\nimport { useModalContext, usePollContext, useTranslationContext } from '../../../context';\n\nimport type { PollState } from 'stream-chat';\nimport { PollQuestion } from './PollQuestion';\n\ntype PollStateSelectorReturnValue = { name: string };\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n  name: nextValue.name,\n});\n\nexport const PollOptionsFullList = () => {\n  const { t } = useTranslationContext();\n  const { poll } = usePollContext();\n  const { close } = useModalContext();\n  const { name } = useStateStore(poll.state, pollStateSelector);\n\n  return (\n    <Viewer.Root className={'str-chat__modal__poll-option-list'}>\n      <Viewer.Header\n        close={close}\n        description={t('Review all options available in this poll')}\n        title={t('Poll options')}\n      />\n      <Viewer.Body className='str-chat__modal__poll-option-list__body'>\n        <PollQuestion question={name} />\n        <PollOptionList />\n      </Viewer.Body>\n    </Viewer.Root>\n  );\n};\n","import clsx from 'clsx';\nimport React from 'react';\nimport { PollHeader as DefaultPollHeader } from './PollHeader';\nimport { PollActions as DefaultPollActions } from './PollActions';\nimport { PollOptionList } from './PollOptionList';\nimport { MAX_OPTIONS_DISPLAYED } from './constants';\nimport { useComponentContext, usePollContext } from '../../context';\nimport { useStateStore } from '../../store';\nimport type { PollState } from 'stream-chat';\n\ntype PollStateSelectorPollContentReturnValue = { is_closed: boolean | undefined };\nconst pollStateSelectorPollContent = (\n  nextValue: PollState,\n): PollStateSelectorPollContentReturnValue => ({ is_closed: nextValue.is_closed });\nexport const PollContent = () => {\n  const { PollActions = DefaultPollActions, PollHeader = DefaultPollHeader } =\n    useComponentContext();\n  const { poll } = usePollContext();\n  const { is_closed } = useStateStore(poll.state, pollStateSelectorPollContent);\n\n  return (\n    <div className={clsx('str-chat__poll', { 'str-chat__poll--closed': is_closed })}>\n      <PollHeader />\n      <PollOptionList optionsDisplayCount={MAX_OPTIONS_DISPLAYED} />\n      <PollActions />\n    </div>\n  );\n};\n","import React from 'react';\nimport { PollContent as DefaultPollContent } from './PollContent';\nimport { PollProvider, useComponentContext } from '../../context';\nimport type { Poll as PollClass } from 'stream-chat';\n\nexport const Poll = ({ poll }: { poll: PollClass }) => {\n  const { PollContent = DefaultPollContent } = useComponentContext();\n  if (!poll) return null;\n  return (\n    <PollProvider poll={poll}>\n      <PollContent />\n    </PollProvider>\n  );\n};\n","import clsx from 'clsx';\nimport React, { useMemo, useRef, useState } from 'react';\nimport { NumericInput } from '../../Form/NumericInput';\nimport { SwitchField, SwitchFieldLabel } from '../../Form/SwitchField';\nimport { useTranslationContext } from '../../../context';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\nimport { useStateStore } from '../../../store';\nimport type { PollComposerState } from 'stream-chat';\n\nconst pollComposerStateSelector = (state: PollComposerState) => ({\n  enforce_unique_vote: state.data.enforce_unique_vote,\n  error: state.errors.max_votes_allowed,\n  max_votes_allowed: state.data.max_votes_allowed,\n});\n\nexport const MultipleAnswersField = () => {\n  const { t } = useTranslationContext();\n  const { pollComposer } = useMessageComposerController();\n  const { enforce_unique_vote, error, max_votes_allowed } = useStateStore(\n    pollComposer.state,\n    pollComposerStateSelector,\n  );\n  const [voteLimitEnabled, setVoteLimitEnabled] = useState(false);\n  const maxVotesInputRef = useRef<HTMLInputElement | null>(null);\n\n  const knownValidationErrors = useMemo<Record<string, string>>(\n    () => ({\n      'Enforce unique vote is enabled': t('Enforce unique vote is enabled'),\n      'Type a number from 2 to 10': t('Type a number from 2 to 10'),\n    }),\n    [t],\n  );\n\n  const multipleVotesEnabled = !enforce_unique_vote;\n  const errorText = error && knownValidationErrors[error];\n  const voteLimitSwitchId = 'max_votes_allowed_enabled';\n  const voteLimitSwitchLabelId = `${voteLimitSwitchId}-label`;\n\n  return (\n    <div className={clsx('str-chat__form__switch-fieldset', {})}>\n      <SwitchField\n        checked={multipleVotesEnabled}\n        description={t('Select more than one option')}\n        id='enforce_unique_vote'\n        onChange={(e) => {\n          setVoteLimitEnabled(false);\n          pollComposer.updateFields({ enforce_unique_vote: !e.target.checked });\n        }}\n        title={t('Multiple votes')}\n      />\n      {multipleVotesEnabled && (\n        <SwitchField\n          aria-labelledby={voteLimitSwitchLabelId}\n          checked={voteLimitEnabled}\n          fieldClassName='str-chat__multiple-answers-field__votes-limit-field'\n          id={voteLimitSwitchId}\n          onChange={(event) => {\n            const nextVoteLimitEnabled = event.target.checked;\n            setVoteLimitEnabled(nextVoteLimitEnabled);\n            pollComposer.updateFields({ max_votes_allowed: '2' });\n            if (!nextVoteLimitEnabled) return;\n            requestAnimationFrame(() => {\n              maxVotesInputRef.current?.focus();\n            });\n          }}\n        >\n          <div className='str-chat__multiple-answers-field__votes-limit-field__numeric-field'>\n            <SwitchFieldLabel\n              asError={!!errorText}\n              description={t('Choose between 2 to 10 options')}\n              htmlFor={voteLimitSwitchId}\n              id={voteLimitSwitchLabelId}\n              title={t('Limit votes per person')}\n            />\n            {voteLimitEnabled && (\n              <NumericInput\n                aria-label={t('Maximum votes per person')}\n                id='max_votes_allowed'\n                max={10}\n                min={2}\n                onBlur={() => {\n                  pollComposer.handleFieldBlur('max_votes_allowed');\n                }}\n                onChange={(e) => {\n                  const raw = e.target.value;\n                  const nativeFieldValidation =\n                    raw !== '' && !/^\\d+$/.test(raw)\n                      ? { max_votes_allowed: t('Only numbers are allowed') }\n                      : undefined;\n                  pollComposer.updateFields(\n                    {\n                      max_votes_allowed: nativeFieldValidation\n                        ? pollComposer.max_votes_allowed\n                        : raw,\n                    },\n                    nativeFieldValidation,\n                  );\n                }}\n                ref={maxVotesInputRef}\n                value={max_votes_allowed ?? ''}\n              />\n            )}\n          </div>\n        </SwitchField>\n      )}\n    </div>\n  );\n};\n","import React, { useMemo } from 'react';\nimport { TextInput } from '../../Form';\nimport { useModalContext, useTranslationContext } from '../../../context';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\nimport { useStateStore } from '../../../store';\nimport type { PollComposerState } from 'stream-chat';\nimport { useAriaIdentifiers } from '../../../a11y/hooks/useAriaIdentifiers';\n\nconst pollComposerStateSelector = (state: PollComposerState) => ({\n  error: state.errors.name,\n  name: state.data.name,\n});\n\nexport const NameField = () => {\n  const { t } = useTranslationContext();\n  const { pollComposer } = useMessageComposerController();\n  const { dialogId } = useModalContext();\n  const { descriptionId } = useAriaIdentifiers(dialogId);\n  const { error, name } = useStateStore(pollComposer.state, pollComposerStateSelector);\n  const knownValidationErrors = useMemo<Record<string, string>>(\n    () => ({\n      'Question is required': t('Question is required'),\n    }),\n    [t],\n  );\n\n  return (\n    <TextInput\n      aria-describedby={descriptionId}\n      className='str-chat__form__input-field__value'\n      error={!!error}\n      errorMessage={\n        error ? (\n          <span data-testid='poll-name-input-field-error'>\n            {knownValidationErrors[error] ?? t('Error')}\n          </span>\n        ) : undefined\n      }\n      id='name'\n      label={t('Question')}\n      onBlur={() => {\n        pollComposer.handleFieldBlur('name');\n      }}\n      onChange={(e) => {\n        pollComposer.updateFields({ name: e.target.value });\n      }}\n      placeholder={t('Ask a question')}\n      type='text'\n      value={name}\n    />\n  );\n};\n","import clsx from 'clsx';\nimport React, { useCallback, useMemo } from 'react';\nimport { TextInput } from '../../Form/TextInput';\nimport { useTranslationContext } from '../../../context';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\nimport { useStateStore } from '../../../store';\nimport type { PollComposerState } from 'stream-chat';\nimport { IconMinusCircle, IconReorder } from '../../Icons';\nimport { Button, type ButtonProps } from '../../Button';\nimport { TextInputFieldSet } from '../../Form/TextInputFieldSet';\n\nconst pollComposerStateSelector = (state: PollComposerState) => ({\n  errors: state.errors.options,\n  options: state.data.options,\n});\n\nexport const OptionFieldSet = () => {\n  const { pollComposer } = useMessageComposerController();\n  const { errors, options } = useStateStore(\n    pollComposer.state,\n    pollComposerStateSelector,\n  );\n  const { t } = useTranslationContext('OptionFieldSet');\n\n  const knownValidationErrors = useMemo<Record<string, string>>(\n    () => ({\n      'Option already exists': t('Option already exists'),\n      'Option is empty': t('Option is empty'),\n    }),\n    [t],\n  );\n\n  const onSetNewOrder = useCallback(\n    (newOrder: number[]) => {\n      const prevOptions = pollComposer.options;\n      pollComposer.updateFields({ options: newOrder.map((index) => prevOptions[index]) });\n    },\n    [pollComposer],\n  );\n\n  const clearOption = useCallback(\n    (removedOptionId: string) => {\n      pollComposer.updateFields({\n        options: pollComposer.options.filter((option) => option.id !== removedOptionId),\n      });\n    },\n    [pollComposer],\n  );\n\n  const draggable = options.length > 1;\n\n  return (\n    <TextInputFieldSet\n      draggable={draggable}\n      label={t('Options')}\n      onSetNewOrder={onSetNewOrder}\n    >\n      {options.map((option, i) => {\n        const error = errors?.[option.id];\n        return (\n          <div\n            className={clsx('str-chat__form__input-field', {\n              'str-chat__form__input-field--draggable': draggable,\n              'str-chat__form__input-field--has-error': error,\n            })}\n            key={`new-poll-option-${i}`}\n          >\n            <TextInput\n              className='str-chat__form__input-field__value'\n              error={!!error}\n              fieldMessagePlacement='inside'\n              id={option.id}\n              leading={\n                draggable ? <IconReorder className='str-chat__drag-handle' /> : undefined\n              }\n              message={\n                error ? (\n                  <span data-testid='poll-option-input-field-error'>\n                    {knownValidationErrors[error] ?? t('Error')}\n                  </span>\n                ) : undefined\n              }\n              onBlur={() => {\n                pollComposer.handleFieldBlur('options');\n              }}\n              onChange={(e) => {\n                pollComposer.updateFields({\n                  options: { index: i, text: e.target.value },\n                });\n              }}\n              onKeyUp={(event) => {\n                const isFocusedLastOptionField = i === options.length - 1;\n                if (event.key === 'Enter' && !isFocusedLastOptionField) {\n                  const nextInputId = options[i + 1].id;\n                  document.getElementById(nextInputId)?.focus();\n                }\n              }}\n              placeholder={t('Add an option')}\n              trailing={\n                option.text ? (\n                  <RemoveOptionButton\n                    aria-label={t('aria/Remove option')}\n                    onClick={() => clearOption(option.id)}\n                  />\n                ) : undefined\n              }\n              type='text'\n              value={option.text}\n            />\n          </div>\n        );\n      })}\n    </TextInputFieldSet>\n  );\n};\n\nconst RemoveOptionButton = ({ className, ...props }: ButtonProps) => (\n  <Button\n    appearance='ghost'\n    circular\n    className={clsx('str-chat__form__remove-option-button', className)}\n    size='xs'\n    variant='secondary'\n    {...props}\n  >\n    <IconMinusCircle />\n  </Button>\n);\n","import React from 'react';\nimport { useCanCreatePoll } from '../../MessageComposer/hooks/useCanCreatePoll';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\nimport { useMessageComposerContext, useTranslationContext } from '../../../context';\nimport clsx from 'clsx';\nimport { IconSend } from '../../Icons';\nimport { Prompt } from '../../Dialog';\n\nexport type PollCreationDialogControlsProps = {\n  close: () => void;\n};\n\nexport const PollCreationDialogControls = ({\n  close,\n}: PollCreationDialogControlsProps) => {\n  const { t } = useTranslationContext('PollCreationDialogControls');\n  const { handleSubmit: handleSubmitMessage } = useMessageComposerContext();\n  const messageComposer = useMessageComposerController();\n  const canCreatePoll = useCanCreatePoll();\n\n  return (\n    <Prompt.Footer>\n      <Prompt.FooterControls>\n        <Prompt.FooterControlsButtonSecondary\n          className={clsx('str-chat__prompt__footer__controls-button--cancel')}\n          onClick={() => {\n            messageComposer.pollComposer.initState();\n            close();\n          }}\n          type='button'\n        >\n          {t('Cancel')}\n        </Prompt.FooterControlsButtonSecondary>\n        <Prompt.FooterControlsButtonPrimary\n          className={clsx('str-chat__prompt__footer__controls-button--submit')}\n          disabled={!canCreatePoll}\n          onClick={() => {\n            messageComposer\n              .createPoll()\n              .then(() => handleSubmitMessage())\n              .then(() => {\n                messageComposer.pollComposer.initState();\n                close();\n              })\n              .catch(console.error);\n          }}\n          type='submit'\n        >\n          <IconSend />\n          {t('Send poll')}\n        </Prompt.FooterControlsButtonPrimary>\n      </Prompt.FooterControls>\n    </Prompt.Footer>\n  );\n};\n","import React, { useCallback } from 'react';\nimport type { PollComposerState } from 'stream-chat';\nimport { VotingVisibility } from 'stream-chat';\nimport { MultipleAnswersField } from './MultipleAnswersField';\nimport { NameField } from './NameField';\nimport { OptionFieldSet } from './OptionFieldSet';\nimport { PollCreationDialogControls } from './PollCreationDialogControls';\nimport { Prompt } from '../../Dialog';\nimport { SwitchField } from '../../Form/SwitchField';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\nimport { useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nexport type PollCreationDialogProps = {\n  close: () => void;\n};\n\nconst pollComposerStateSelector = (state: PollComposerState) => ({\n  allow_answers: state.data.allow_answers,\n  allow_user_suggested_options: state.data.allow_user_suggested_options,\n  voting_visibility: state.data.voting_visibility,\n});\n\nexport const PollCreationDialog = ({ close }: PollCreationDialogProps) => {\n  const { t } = useTranslationContext();\n  const { pollComposer } = useMessageComposerController();\n  const { allow_answers, allow_user_suggested_options, voting_visibility } =\n    useStateStore(pollComposer.state, pollComposerStateSelector);\n\n  const onClose = useCallback(() => {\n    pollComposer.initState();\n    close();\n  }, [pollComposer, close]);\n\n  return (\n    <Prompt.Root\n      className='str-chat__poll-creation-dialog'\n      data-testid='poll-creation-dialog'\n    >\n      <Prompt.Header\n        close={onClose}\n        description={t('Create a question, add options, and configure poll settings')}\n        title={t('Create poll')}\n      />\n      <Prompt.Body>\n        <form autoComplete='off'>\n          <NameField />\n          <OptionFieldSet />\n          <div className='str-chat__poll-creation-dialog__features-selectors'>\n            <MultipleAnswersField />\n            <SwitchField\n              checked={voting_visibility === 'anonymous'}\n              description={t('Hide who voted')}\n              id='voting_visibility'\n              onChange={(e) =>\n                pollComposer.updateFields({\n                  voting_visibility: e.target.checked\n                    ? VotingVisibility.anonymous\n                    : VotingVisibility.public,\n                })\n              }\n              title={t('Anonymous poll')}\n            />\n            <SwitchField\n              checked={allow_user_suggested_options}\n              description={t('Let others add options')}\n              id='allow_user_suggested_options'\n              onChange={(e) =>\n                pollComposer.updateFields({\n                  allow_user_suggested_options: e.target.checked,\n                })\n              }\n              title={t('Suggest an option')}\n            />\n            <SwitchField\n              checked={allow_answers}\n              description={t('Allow others to add comments')}\n              id='allow_answers'\n              onChange={(e) =>\n                pollComposer.updateFields({ allow_answers: e.target.checked })\n              }\n              title={t('Add a comment')}\n            />\n          </div>\n        </form>\n      </Prompt.Body>\n      <PollCreationDialogControls close={close} />\n    </Prompt.Root>\n  );\n};\n","import React, { type ComponentProps, type ComponentType, useMemo } from 'react';\nimport type { CommandResponse } from 'stream-chat';\nimport { useMessageComposerContext, useTranslationContext } from '../../../context';\nimport { useMessageComposerCommands, useMessageComposerController } from '../hooks';\nimport {\n  ContextMenuBackButton,\n  ContextMenuButton,\n  ContextMenuHeader,\n  useContextMenuContext,\n} from '../../Dialog';\nimport {\n  IconAudio,\n  IconChevronLeft,\n  IconFlag,\n  IconGiphy,\n  IconMute,\n  IconUserAdd,\n  IconUserRemove,\n} from '../../Icons';\nimport clsx from 'clsx';\n\nconst icons: Record<string, ComponentType> = {\n  ban: IconUserRemove,\n  flag: IconFlag,\n  giphy: IconGiphy,\n  mute: IconMute,\n  unban: IconUserAdd,\n  unmute: IconAudio,\n};\n\nexport const CommandsMenuClassName = 'str-chat__context-menu--commands';\n\nexport const CommandsSubmenuHeader = () => {\n  const { t } = useTranslationContext();\n  const { returnToParentMenu } = useContextMenuContext();\n  return (\n    <ContextMenuHeader className='str-chat__context-menu__header--commands str-chat__context-menu__header--submenu-commands'>\n      <ContextMenuBackButton onClick={returnToParentMenu}>\n        <IconChevronLeft />\n        <span>{t('Instant commands')}</span>\n      </ContextMenuBackButton>\n    </ContextMenuHeader>\n  );\n};\n\nexport const CommandsMenuHeader = () => {\n  const { t } = useTranslationContext();\n  return (\n    <ContextMenuHeader className='str-chat__context-menu__header--commands'>\n      <span>{t('Instant commands')}</span>\n    </ContextMenuHeader>\n  );\n};\n\nexport const CommandsMenu = () => {\n  const { closeMenu } = useContextMenuContext();\n  const messageComposer = useMessageComposerController();\n  const { textareaRef } = useMessageComposerContext();\n  const commands = useMessageComposerCommands();\n  const sortedCommands = useMemo(\n    () =>\n      [...commands].sort((a, b) =>\n        (a.command.name ?? '').localeCompare(b.command.name ?? ''),\n      ),\n    [commands],\n  );\n\n  return (\n    <>\n      {sortedCommands.map(({ command, enabled }) => (\n        <CommandContextMenuItem\n          command={command}\n          enabled={enabled}\n          key={command.name}\n          onClick={() => {\n            if (!command.name || !enabled) return;\n            messageComposer.textComposer.setCommand(command);\n            closeMenu();\n            // Defer the focus to the next frame so it wins over FocusScope's restore-to-attachment-selector-button behavior.\n            requestAnimationFrame(() => textareaRef.current?.focus());\n          }}\n        />\n      ))}\n    </>\n  );\n};\n\nexport const useCommandTranslation = (command: CommandResponse) => {\n  const { t } = useTranslationContext();\n\n  const knownArgsTranslations = useMemo<Record<string, string>>(\n    () => ({\n      ban: t('ban-command-args'),\n      giphy: t('giphy-command-args'),\n      mute: t('mute-command-args'),\n      unban: t('unban-command-args'),\n      unmute: t('unmute-command-args'),\n    }),\n    [t],\n  );\n  const knownDescriptionTranslations = useMemo<Record<string, string>>(\n    () => ({\n      ban: t('ban-command-description'),\n      giphy: t('giphy-command-description'),\n      mute: t('mute-command-description'),\n      unban: t('unban-command-description'),\n      unmute: t('unmute-command-description'),\n    }),\n    [t],\n  );\n\n  const args =\n    command.args && (knownArgsTranslations[command.name ?? ''] ?? t(command.args));\n  const description =\n    command.description &&\n    (knownDescriptionTranslations[command.name ?? ''] ?? t(command.description));\n\n  return { args, description };\n};\n\nexport const CommandContextMenuItem = ({\n  className,\n  command,\n  enabled = true,\n  ...props\n}: ComponentProps<'button'> & {\n  command: CommandResponse & { name: string };\n  enabled?: boolean;\n}) => {\n  const { args, description } = useCommandTranslation(command);\n\n  // todo: retrieve the command trigger char from textComposer - needed adjustment in LLC\n  const details = useMemo(\n    () => (args ? `/${command.name} ${args}` : `/${command.name}`),\n    [args, command.name],\n  );\n\n  return (\n    <ContextMenuButton\n      {...props}\n      className={clsx('str-chat__context-menu__button--command', className)}\n      details={details}\n      disabled={!enabled}\n      Icon={icons[command.name]}\n      key={command.name}\n      label={command.name}\n      title={`${description} ${command.args}`}\n    />\n  );\n};\n","import React, {\n  type ComponentType,\n  forwardRef,\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport {\n  useAttachmentManagerState,\n  useMessageComposerCommands,\n  useMessageComposerController,\n} from '../hooks';\nimport { CHANNEL_CONTAINER_ID } from '../../Channel/constants';\nimport {\n  ContextMenu,\n  ContextMenuButton,\n  type ContextMenuHeaderComponent,\n  type ContextMenuSubmenu,\n  useContextMenuContext,\n  useDialogIsOpen,\n  useDialogOnNearestManager,\n} from '../../Dialog';\nimport { GlobalModal } from '../../Modal';\nimport { ShareLocationDialog as DefaultLocationDialog } from '../../Location';\nimport { PollCreationDialog as DefaultPollCreationDialog } from '../../Poll';\nimport { Portal } from '../../Portal/Portal';\nimport { UploadFileInput } from '../../ReactFileUtilities';\nimport {\n  useChannelStateContext,\n  useComponentContext,\n  useTranslationContext,\n} from '../../../context';\nimport {\n  AttachmentSelectorContextProvider,\n  useAttachmentSelectorContext,\n} from '../../../context/AttachmentSelectorContext';\nimport { useStableId } from '../../UtilityComponents/useStableId';\nimport clsx from 'clsx';\nimport { Button, type ButtonProps } from '../../Button';\nimport {\n  IconAttachment,\n  IconCommand,\n  IconLocation,\n  IconPlus,\n  IconPoll,\n} from '../../Icons';\nimport { useIsCooldownActive } from '../hooks/useIsCooldownActive';\nimport {\n  CommandsMenu,\n  CommandsMenuClassName,\n  CommandsSubmenuHeader,\n} from './CommandsMenu';\n\nconst AttachmentSelectorMenuInitButtonIcon = ({ className }: { className?: string }) => {\n  const { AttachmentSelectorInitiationButtonContents } = useComponentContext();\n\n  if (AttachmentSelectorInitiationButtonContents) {\n    return (\n      <span className={className}>\n        <AttachmentSelectorInitiationButtonContents />\n      </span>\n    );\n  }\n\n  return (\n    <IconPlus\n      className={clsx('str-chat__attachment-selector__menu-button__icon', className)}\n    />\n  );\n};\n\nexport const AttachmentSelectorButton = forwardRef<\n  HTMLButtonElement,\n  ButtonProps & { iconClassName?: string }\n>(function AttachmentSelectorButton({ className, iconClassName, ...props }, ref) {\n  return (\n    <Button\n      appearance='outline'\n      circular\n      className={clsx('str-chat__attachment-selector__menu-button', className)}\n      data-testid='invoke-attachment-selector-button'\n      size='lg'\n      variant='secondary'\n      {...props}\n      ref={ref}\n    >\n      <AttachmentSelectorMenuInitButtonIcon className={iconClassName} />\n    </Button>\n  );\n});\n\nexport const SimpleAttachmentSelector = () => {\n  const { channelCapabilities } = useChannelStateContext();\n  const { t } = useTranslationContext();\n  const inputRef = useRef<HTMLInputElement | null>(null);\n  const [buttonElement, setButtonElement] = useState<HTMLButtonElement | null>(null);\n  const id = useStableId();\n  const isCooldownActive = useIsCooldownActive();\n\n  useEffect(() => {\n    if (!buttonElement) return;\n    const handleKeyUp = (event: KeyboardEvent) => {\n      if (![' ', 'Enter'].includes(event.key) || !inputRef.current) return;\n      event.preventDefault();\n      inputRef.current.click();\n    };\n    buttonElement.addEventListener('keyup', handleKeyUp);\n    return () => {\n      buttonElement.removeEventListener('keyup', handleKeyUp);\n    };\n  }, [buttonElement]);\n\n  if (!channelCapabilities['upload-file']) return null;\n\n  return (\n    <div className='str-chat__attachment-selector'>\n      <AttachmentSelectorButton\n        aria-label={t('aria/Open Attachment Selector')}\n        disabled={isCooldownActive}\n        onClick={() => inputRef.current?.click()}\n        ref={setButtonElement}\n      />\n      <UploadFileInput id={id} ref={inputRef} />\n    </div>\n  );\n};\n\nexport type AttachmentSelectorModalContentProps = {\n  close: () => void;\n};\n\nexport type AttachmentSelectorAction = {\n  ActionButton: ComponentType<AttachmentSelectorActionProps>;\n  id?: string;\n  ModalContent?: React.ComponentType<AttachmentSelectorModalContentProps>;\n  Submenu?: ContextMenuSubmenu;\n  Header?: ContextMenuHeaderComponent;\n  type: 'uploadFile' | 'createPoll' | 'addLocation' | 'selectCommand' | (string & {});\n};\n\nexport type AttachmentSelectorActionProps = {\n  openModalForAction: (actionType: AttachmentSelectorAction['type']) => void;\n  submenuItems?: ContextMenuSubmenu;\n  submenuHeader?: ContextMenuHeaderComponent;\n};\n\nexport const DefaultAttachmentSelectorComponents = {\n  Command({ submenuHeader, submenuItems }: AttachmentSelectorActionProps) {\n    const { t } = useTranslationContext();\n    const { openSubmenu } = useContextMenuContext();\n    const commands = useMessageComposerCommands();\n    const hasEnabledCommands = commands.some(({ enabled }) => enabled);\n    const hasSubmenu = !!submenuItems;\n\n    return (\n      <ContextMenuButton\n        className='str-chat__attachment-selector-actions-menu__button str-chat__attachment-selector-actions-menu__commands-button'\n        disabled={!hasEnabledCommands}\n        hasSubMenu={hasSubmenu}\n        Icon={IconCommand}\n        onClick={(event) => {\n          if (!hasSubmenu) return;\n          openSubmenu({\n            focusReturnTarget: event.currentTarget,\n            Header: submenuHeader,\n            menuClassName: CommandsMenuClassName,\n            Submenu: submenuItems,\n          });\n        }}\n      >\n        {t('Commands')}\n      </ContextMenuButton>\n    );\n  },\n  File() {\n    const { t } = useTranslationContext();\n    const { fileInput } = useAttachmentSelectorContext();\n    const { closeMenu } = useContextMenuContext();\n\n    return (\n      <ContextMenuButton\n        className='str-chat__attachment-selector-actions-menu__button str-chat__attachment-selector-actions-menu__upload-file-button'\n        Icon={IconAttachment}\n        onClick={() => {\n          fileInput?.click();\n          closeMenu();\n        }}\n      >\n        {t('File')}\n      </ContextMenuButton>\n    );\n  },\n  Location({ openModalForAction }: AttachmentSelectorActionProps) {\n    const { t } = useTranslationContext();\n    const { closeMenu } = useContextMenuContext();\n    return (\n      <ContextMenuButton\n        className='str-chat__attachment-selector-actions-menu__button str-chat__attachment-selector-actions-menu__add-location-button'\n        Icon={IconLocation}\n        onClick={() => {\n          openModalForAction('addLocation');\n          closeMenu();\n        }}\n      >\n        {t('Location')}\n      </ContextMenuButton>\n    );\n  },\n  Poll({ openModalForAction }: AttachmentSelectorActionProps) {\n    const { t } = useTranslationContext();\n    const { closeMenu } = useContextMenuContext();\n    return (\n      <ContextMenuButton\n        className='str-chat__attachment-selector-actions-menu__button str-chat__attachment-selector-actions-menu__create-poll-button'\n        Icon={IconPoll}\n        onClick={() => {\n          openModalForAction('createPoll');\n          closeMenu();\n        }}\n      >\n        {t('Poll')}\n      </ContextMenuButton>\n    );\n  },\n};\n\n/**\n * Order of AttachmentSelectorAction objects defines the order in the context menu width index 0 being at the top.\n */\nexport const defaultAttachmentSelectorActionSet: AttachmentSelectorAction[] = [\n  {\n    ActionButton: DefaultAttachmentSelectorComponents.File,\n    type: 'uploadFile',\n  },\n  {\n    ActionButton: DefaultAttachmentSelectorComponents.Poll,\n    type: 'createPoll',\n  },\n  {\n    ActionButton: DefaultAttachmentSelectorComponents.Location,\n    type: 'addLocation',\n  },\n  {\n    ActionButton: DefaultAttachmentSelectorComponents.Command,\n    Header: CommandsSubmenuHeader,\n    Submenu: CommandsMenu,\n    type: 'selectCommand',\n  },\n];\n\nexport type AttachmentSelectorProps = {\n  attachmentSelectorActionSet?: AttachmentSelectorAction[];\n  getModalPortalDestination?: () => HTMLElement | null;\n};\n\nconst useAttachmentSelectorActionsFiltered = (original: AttachmentSelectorAction[]) => {\n  const {\n    PollCreationDialog = DefaultPollCreationDialog,\n    ShareLocationDialog = DefaultLocationDialog,\n  } = useComponentContext();\n  const { channelCapabilities } = useChannelStateContext();\n  const { isUploadEnabled } = useAttachmentManagerState();\n  const messageComposer = useMessageComposerController();\n  const channelConfig = messageComposer.channel.getConfig();\n\n  return useMemo(\n    () =>\n      original\n        .filter((action) => {\n          if (action.type === 'uploadFile')\n            return (\n              channelCapabilities['upload-file'] &&\n              channelConfig?.uploads &&\n              isUploadEnabled\n            );\n\n          if (action.type === 'createPoll')\n            return (\n              channelCapabilities['send-poll'] &&\n              !messageComposer.threadId &&\n              channelConfig?.polls\n            );\n\n          if (action.type === 'addLocation') {\n            return channelConfig?.shared_locations && !messageComposer.threadId;\n          }\n\n          if (action.type === 'selectCommand') {\n            return !!channelConfig?.commands?.some((command) => !!command.name);\n          }\n\n          return true;\n        })\n        .map((action) => {\n          if (action.type === 'createPoll' && !action.ModalContent) {\n            return { ...action, ModalContent: PollCreationDialog };\n          }\n          if (action.type === 'addLocation' && !action.ModalContent) {\n            return { ...action, ModalContent: ShareLocationDialog };\n          }\n          return action;\n        }),\n    [\n      PollCreationDialog,\n      ShareLocationDialog,\n      channelCapabilities,\n      channelConfig,\n      isUploadEnabled,\n      messageComposer.threadId,\n      original,\n    ],\n  );\n};\n\nexport const AttachmentSelector = ({\n  attachmentSelectorActionSet = defaultAttachmentSelectorActionSet,\n  getModalPortalDestination,\n}: AttachmentSelectorProps) => {\n  const { t } = useTranslationContext();\n  const { ContextMenu: ContextMenuComponent = ContextMenu, Modal = GlobalModal } =\n    useComponentContext();\n  const { channelCapabilities } = useChannelStateContext();\n  const messageComposer = useMessageComposerController();\n  const isCooldownActive = useIsCooldownActive();\n  const actions = useAttachmentSelectorActionsFiltered(attachmentSelectorActionSet);\n\n  const menuDialogId = `attachment-actions-menu${messageComposer.threadId ? '-thread' : ''}`;\n  const { dialog: menuDialog, dialogManager } = useDialogOnNearestManager({\n    id: menuDialogId,\n  });\n  const menuDialogIsOpen = useDialogIsOpen(menuDialogId, dialogManager?.id);\n\n  const [modalContentAction, setModalContentActionAction] =\n    useState<AttachmentSelectorAction>();\n  const shouldRestoreFocusToTriggerRef = useRef(false);\n  const openModalForAction = useCallback(\n    (actionType: AttachmentSelectorAction['type']) => {\n      const action = actions.find((a) => a.type === actionType);\n      if (!action?.ModalContent) return;\n      setModalContentActionAction(action);\n    },\n    [actions],\n  );\n\n  const closeModal = useCallback(() => {\n    shouldRestoreFocusToTriggerRef.current = true;\n    setModalContentActionAction(undefined);\n  }, []);\n\n  const [fileInput, setFileInput] = useState<HTMLInputElement | null>(null);\n  const menuButtonRef = useRef<HTMLButtonElement>(null);\n\n  useEffect(() => {\n    if (modalContentAction || !shouldRestoreFocusToTriggerRef.current) return;\n\n    const frame = requestAnimationFrame(() => {\n      menuButtonRef.current?.focus();\n      shouldRestoreFocusToTriggerRef.current = false;\n    });\n\n    return () => cancelAnimationFrame(frame);\n  }, [modalContentAction]);\n\n  const contextMenuItems = useMemo(\n    () =>\n      actions.map((action) => (\n        <action.ActionButton\n          key={action.type}\n          openModalForAction={openModalForAction}\n          submenuHeader={action.Header}\n          submenuItems={action.Submenu}\n        />\n      )),\n    [actions, openModalForAction],\n  );\n\n  const getDefaultPortalDestination = useCallback(\n    () => document.getElementById(CHANNEL_CONTAINER_ID),\n    [],\n  );\n\n  if (actions.length === 0) return null;\n\n  if (actions.length === 1 && actions[0].type === 'uploadFile')\n    return <SimpleAttachmentSelector />;\n\n  const ModalContent = modalContentAction?.ModalContent;\n  const modalIsOpen = !!ModalContent;\n  return (\n    <AttachmentSelectorContextProvider value={{ fileInput }}>\n      <div className='str-chat__attachment-selector'>\n        {channelCapabilities['upload-file'] && <UploadFileInput ref={setFileInput} />}\n        <AttachmentSelectorButton\n          aria-expanded={menuDialogIsOpen}\n          aria-haspopup='true'\n          aria-label={t('aria/Open Attachment Selector')}\n          disabled={isCooldownActive}\n          iconClassName={clsx('str-chat__prepare-rotate45', {\n            'str-chat__rotate45': menuDialogIsOpen,\n          })}\n          onClick={() => menuDialog?.toggle()}\n          ref={menuButtonRef}\n        />\n        <ContextMenuComponent\n          allowFlip\n          aria-label={t('aria/Attachment Actions')}\n          backLabel={t('Back')}\n          className='str-chat__attachment-selector-actions-menu'\n          data-testid='attachment-selector-actions-menu'\n          dialogManagerId={dialogManager?.id}\n          id={menuDialogId}\n          onClose={menuDialog.close}\n          placement='top-start'\n          referenceElement={menuButtonRef.current}\n          tabIndex={-1}\n          trapFocus\n        >\n          {contextMenuItems}\n        </ContextMenuComponent>\n        <Portal\n          getPortalDestination={getModalPortalDestination ?? getDefaultPortalDestination}\n          isOpen={modalIsOpen}\n        >\n          <Modal\n            className={clsx({\n              'str-chat__create-poll-modal': modalContentAction?.type === 'createPoll',\n              'str-chat__share-location-modal':\n                modalContentAction?.type === 'addLocation',\n            })}\n            onClose={closeModal}\n            open={modalIsOpen}\n          >\n            {ModalContent && <ModalContent close={closeModal} />}\n          </Modal>\n        </Portal>\n      </div>\n    </AttachmentSelectorContextProvider>\n  );\n};\n","import React from 'react';\nimport type { AnyLocalAttachment, LocalUploadAttachment } from 'stream-chat';\nimport { IconUnsupportedAttachment } from '../../Icons';\nimport { useTranslationContext } from '../../../context';\nimport { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';\n\nexport type UnsupportedAttachmentPreviewProps<\n  CustomLocalMetadata = Record<string, unknown>,\n> = {\n  attachment: AnyLocalAttachment<CustomLocalMetadata>;\n  handleRetry: (\n    attachment: LocalUploadAttachment,\n  ) => void | Promise<LocalUploadAttachment | undefined>;\n  removeAttachments: (ids: string[]) => void;\n};\n\nexport const UnsupportedAttachmentPreview = ({\n  attachment,\n  removeAttachments,\n}: UnsupportedAttachmentPreviewProps) => {\n  const { t } = useTranslationContext();\n  const { id } = attachment.localMetadata ?? {};\n\n  return (\n    <div\n      className='str-chat__attachment-preview-unsupported'\n      data-testid='attachment-preview-unsupported'\n    >\n      <IconUnsupportedAttachment />\n      <div className='str-chat__attachment-preview-unsupported__metadata'>\n        <div\n          className='str-chat__attachment-preview-unsupported__title'\n          data-testid='unsupported-attachment-preview-title'\n        >\n          {t('Unsupported attachment')}\n        </div>\n      </div>\n      <RemoveAttachmentPreviewButton\n        data-testid='file-preview-item-delete-button'\n        onClick={() => {\n          if (id) removeAttachments([id]);\n        }}\n      />\n    </div>\n  );\n};\n","import React from 'react';\n\nimport { useComponentContext } from '../../../context';\nimport { FileSizeIndicator as DefaultFileSizeIndicator } from '../../Attachment/components/FileSizeIndicator';\nimport { UploadedSizeIndicator as DefaultUploadedSizeIndicator } from '../../Loading/UploadedSizeIndicator';\n\nfunction resolveAttachmentFullByteSize(attachment: {\n  file_size?: number | string;\n  localMetadata?: { file?: { size?: unknown } } | null;\n}): number | undefined {\n  const fromFile = attachment.localMetadata?.file?.size;\n  if (typeof fromFile === 'number' && Number.isFinite(fromFile) && fromFile >= 0) {\n    return fromFile;\n  }\n  const raw = attachment.file_size;\n  if (typeof raw === 'number' && Number.isFinite(raw) && raw >= 0) return raw;\n  if (typeof raw === 'string') {\n    const n = parseFloat(raw);\n    if (Number.isFinite(n) && n >= 0) return n;\n  }\n  return undefined;\n}\n\nexport type AttachmentUploadedSizeIndicatorProps = {\n  attachment: {\n    file_size?: number | string;\n    localMetadata?: {\n      file?: { size?: unknown };\n      uploadProgress?: number;\n      uploadState?: string;\n    } | null;\n  };\n};\n\nexport const AttachmentUploadedSizeIndicator = ({\n  attachment,\n}: AttachmentUploadedSizeIndicatorProps) => {\n  const {\n    FileSizeIndicator = DefaultFileSizeIndicator,\n    UploadedSizeIndicator = DefaultUploadedSizeIndicator,\n  } = useComponentContext();\n  const { uploadProgress, uploadState } = attachment.localMetadata ?? {};\n  const fullBytes = resolveAttachmentFullByteSize(attachment);\n  const uploaded =\n    uploadProgress !== undefined && fullBytes !== undefined\n      ? Math.round((uploadProgress / 100) * fullBytes)\n      : undefined;\n\n  if (uploadState === 'uploading' && uploaded !== undefined && fullBytes !== undefined) {\n    return <UploadedSizeIndicator fullBytes={fullBytes} uploadedBytes={uploaded} />;\n  }\n\n  if (uploadState === 'finished') {\n    return <FileSizeIndicator fileSize={attachment.file_size} />;\n  }\n\n  return null;\n};\n","import React, {\n  type ComponentProps,\n  type KeyboardEvent,\n  type MouseEvent,\n  useState,\n} from 'react';\nimport { useTranslationContext } from '../../../../context';\nimport {\n  isImageAttachment,\n  isVideoAttachment,\n  type LocalUploadAttachment,\n} from 'stream-chat';\n\ntype AttachmentPreviewRootProps = Omit<ComponentProps<'div'>, 'onClick' | 'onKeyDown'> & {\n  attachment: LocalUploadAttachment;\n  /**\n   * Called when the attachment preview is pressed and can be previewed.\n   * The parent is responsible for opening the gallery at the correct index.\n   */\n  openPreview?: () => void;\n  /**\n   * Returns boolean value to signal whether the event handling should be terminated immediately (return false)\n   *  or default logic can be executed next (return true)\n   */\n  onPressed?: (e: MouseEvent<Element> | KeyboardEvent<Element>) => boolean;\n};\n\nconst INTERACTIVE_SELECTOR =\n  'button, a, input, textarea, select, [role=\"button\"], [role=\"link\"], [data-interactive=\"true\"]';\n\nfunction hasInteractiveAncestorBeforeRoot(\n  target: EventTarget | null,\n  root: HTMLElement | null,\n): boolean {\n  if (!(target instanceof Element) || !root) return false;\n\n  let el: Element | null = target;\n  while (el && el !== root) {\n    if (el.matches(INTERACTIVE_SELECTOR)) return true;\n    el = el.parentElement;\n  }\n  return false;\n}\n\n// todo: use this component for all the attachment previews\nexport const AttachmentPreviewRoot = ({\n  attachment,\n  onPressed,\n  openPreview,\n  tabIndex = 0,\n  ...props\n}: AttachmentPreviewRootProps) => {\n  const { t } = useTranslationContext();\n  const [root, setRoot] = useState<HTMLDivElement | null>(null);\n  const url =\n    attachment.asset_url || attachment.image_url || attachment.localMetadata.previewUri;\n\n  const canDownloadAttachment = false; //!!url;\n\n  const canPreviewAttachment =\n    !!openPreview &&\n    ((!!url && isImageAttachment(attachment)) || isVideoAttachment(attachment));\n\n  const handlePressed = (e: MouseEvent<Element> | KeyboardEvent<Element>) => {\n    if (e.defaultPrevented) return;\n\n    if (hasInteractiveAncestorBeforeRoot(e.target as Element, root)) return;\n\n    if (onPressed) {\n      const shouldContinue = onPressed(e);\n      if (!shouldContinue) return;\n    }\n\n    if (canPreviewAttachment) {\n      openPreview();\n      return;\n    }\n\n    if (canDownloadAttachment) {\n      window.open(url, '_blank', 'noopener,noreferrer');\n    }\n  };\n\n  const isInteractive = canPreviewAttachment || canDownloadAttachment;\n\n  return (\n    <div\n      aria-label={\n        isInteractive\n          ? t(canPreviewAttachment ? 'aria/Show preview' : 'aria/Download attachment')\n          : undefined\n      }\n      {...props}\n      onClick={handlePressed}\n      onKeyDown={\n        isInteractive\n          ? (e) => {\n              if (e.key !== 'Enter' && e.key !== ' ') return;\n              handlePressed(e);\n              e.preventDefault();\n            }\n          : undefined\n      }\n      ref={setRoot}\n      role={isInteractive ? 'button' : undefined}\n      tabIndex={isInteractive ? tabIndex : -1}\n    >\n      {props.children}\n    </div>\n  );\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../../context';\nimport { FileIcon } from '../../FileIcon';\nimport { UploadProgressIndicator } from '../../Loading/UploadProgressIndicator';\nimport { AttachmentUploadedSizeIndicator } from './AttachmentUploadedSizeIndicator';\nimport type { LocalAudioAttachment, LocalFileAttachment } from 'stream-chat';\nimport type { UploadAttachmentPreviewProps } from './types';\nimport { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';\nimport { AttachmentPreviewRoot } from './utils/AttachmentPreviewRoot';\nimport { IconExclamationMark, IconExclamationTriangleFill } from '../../Icons';\n\nexport type FileAttachmentPreviewProps<CustomLocalMetadata = unknown> =\n  UploadAttachmentPreviewProps<\n    LocalFileAttachment<CustomLocalMetadata> | LocalAudioAttachment<CustomLocalMetadata>\n  >;\n\nexport const FileAttachmentPreview = ({\n  attachment,\n  handleRetry,\n  removeAttachments,\n}: FileAttachmentPreviewProps) => {\n  const { t } = useTranslationContext('FilePreview');\n  const { id, uploadPermissionCheck, uploadProgress, uploadState } =\n    attachment.localMetadata ?? {};\n\n  const hasSizeLimitError = uploadPermissionCheck?.reason === 'size_limit';\n  const hasFatalError = uploadState === 'blocked' || hasSizeLimitError;\n  const hasRetriableError = uploadState === 'failed' && !!handleRetry;\n\n  return (\n    <AttachmentPreviewRoot\n      attachment={attachment}\n      className='str-chat__attachment-preview-file'\n      data-testid='attachment-preview-file'\n    >\n      <div className='str-chat__attachment-preview-file__icon'>\n        <FileIcon fileName={attachment.title} mimeType={attachment.mime_type} />\n      </div>\n\n      <div className='str-chat__attachment-preview-file__info'>\n        <div className='str-chat__attachment-preview-file-name' title={attachment.title}>\n          {attachment.title}\n        </div>\n        <div className='str-chat__attachment-preview-file__data'>\n          {uploadState === 'uploading' && (\n            <UploadProgressIndicator uploadProgress={uploadProgress} />\n          )}\n          <AttachmentUploadedSizeIndicator attachment={attachment} />\n          {hasFatalError && (\n            <div className='str-chat__attachment-preview-file__fatal-error'>\n              <IconExclamationMark />\n              <span>\n                {hasSizeLimitError\n                  ? t('File too large')\n                  : uploadState === 'blocked'\n                    ? t('Upload blocked')\n                    : t('Upload failed')}\n              </span>\n            </div>\n          )}\n          {hasRetriableError && (\n            <div className='str-chat__attachment-preview-file__retriable-error'>\n              <IconExclamationTriangleFill />\n              <span>{t('Upload error')}</span>\n              <button\n                aria-label={t('aria/Retry upload')}\n                className='str-chat__attachment-preview-file__retry-upload-button'\n                data-testid='file-preview-item-retry-button'\n                onClick={() => {\n                  handleRetry(attachment);\n                }}\n                type='button'\n              >\n                {t('Retry upload')}\n              </button>\n            </div>\n          )}\n        </div>\n      </div>\n\n      <RemoveAttachmentPreviewButton\n        data-testid='file-preview-item-delete-button'\n        onClick={() => {\n          if (id) removeAttachments([id]);\n        }}\n        uploadState={uploadState}\n      />\n    </AttachmentPreviewRoot>\n  );\n};\n","import type { UploadAttachmentPreviewProps } from './types';\nimport {\n  isVoiceRecordingAttachment,\n  type LocalAudioAttachment,\n  type LocalVoiceRecordingAttachment,\n} from 'stream-chat';\nimport { useTranslationContext } from '../../../context';\nimport React, { useEffect } from 'react';\nimport clsx from 'clsx';\nimport { UploadProgressIndicator } from '../../Loading/UploadProgressIndicator';\nimport { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';\nimport { AttachmentPreviewRoot } from './utils/AttachmentPreviewRoot';\nimport { IconExclamationMark, IconExclamationTriangleFill } from '../../Icons';\nimport { PlayButton } from '../../Button';\nimport {\n  type AudioPlayerState,\n  DurationDisplay,\n  PlaybackRateButton,\n  WaveProgressBar,\n} from '../../AudioPlayback';\nimport { useAudioPlayer } from '../../AudioPlayback/WithAudioPlayback';\nimport { useStateStore } from '../../../store';\nimport { AttachmentUploadedSizeIndicator } from './AttachmentUploadedSizeIndicator';\n\nexport type AudioAttachmentPreviewProps<CustomLocalMetadata = Record<string, unknown>> =\n  UploadAttachmentPreviewProps<\n    | LocalAudioAttachment<CustomLocalMetadata>\n    | LocalVoiceRecordingAttachment<CustomLocalMetadata>\n  >;\n\nconst audioPlayerStateSelector = (state: AudioPlayerState) => ({\n  canPlayRecord: state.canPlayRecord,\n  isPlaying: state.isPlaying,\n  playbackRate: state.currentPlaybackRate,\n  progressPercent: state.progressPercent,\n  secondsElapsed: state.secondsElapsed,\n});\n\nexport const AudioAttachmentPreview = ({\n  attachment,\n  handleRetry,\n  removeAttachments,\n}: AudioAttachmentPreviewProps) => {\n  const { t } = useTranslationContext();\n  const { id, previewUri, uploadPermissionCheck, uploadProgress, uploadState } =\n    attachment.localMetadata ?? {};\n  const url = attachment.asset_url || previewUri;\n\n  const audioPlayer = useAudioPlayer({\n    fileSize: attachment.localMetadata.file?.size ?? attachment.file_size,\n    mimeType: attachment.localMetadata.file?.type ?? attachment.mime_type,\n    requester: attachment.localMetadata.id,\n    src: url,\n    title: attachment.title,\n    waveformData: attachment.waveform_data,\n  });\n\n  useEffect(() => {\n    audioPlayer?.cancelScheduledRemoval();\n    return () => {\n      audioPlayer?.scheduleRemoval();\n    };\n  }, [audioPlayer]);\n\n  const { canPlayRecord, isPlaying, playbackRate, progressPercent, secondsElapsed } =\n    useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};\n\n  const resolvedDuration = audioPlayer?.durationSeconds ?? attachment.duration;\n\n  const hasWaveform = !!audioPlayer?.waveformData?.length;\n  const hasSizeLimitError = uploadPermissionCheck?.reason === 'size_limit';\n  const hasFatalError = uploadState === 'blocked' || hasSizeLimitError;\n  const hasRetriableError = uploadState === 'failed' && !!handleRetry;\n  const hasError = hasRetriableError || hasFatalError;\n\n  const showProgressControls = !hasError || (hasError && isPlaying);\n\n  return (\n    <AttachmentPreviewRoot\n      attachment={attachment}\n      className={clsx('str-chat__attachment-preview-audio')}\n      data-testid='attachment-preview-audio'\n    >\n      <PlayButton\n        isPlaying={Boolean(isPlaying)}\n        onClick={() => {\n          audioPlayer?.togglePlay();\n        }}\n      />\n\n      <div className='str-chat__attachment-preview-file__info'>\n        <div className='str-chat__attachment-preview-file-name' title={attachment.title}>\n          {isVoiceRecordingAttachment(attachment) ? t('Voice message') : attachment.title}\n        </div>\n        <div className='str-chat__attachment-preview-file__data'>\n          {uploadState === 'uploading' && (\n            <UploadProgressIndicator uploadProgress={uploadProgress} />\n          )}\n          {showProgressControls ? (\n            <>\n              {!resolvedDuration && !progressPercent && !isPlaying && (\n                <AttachmentUploadedSizeIndicator attachment={attachment} />\n              )}\n              {hasWaveform ? (\n                <>\n                  <DurationDisplay\n                    duration={resolvedDuration}\n                    isPlaying={Boolean(isPlaying)}\n                    secondsElapsed={secondsElapsed}\n                    showRemaining\n                  />\n                  <WaveProgressBar\n                    durationSeconds={resolvedDuration}\n                    progress={progressPercent}\n                    relativeAmplitudeBarWidth={1}\n                    relativeAmplitudeGap={1}\n                    secondsElapsed={secondsElapsed}\n                    seek={audioPlayer.seek}\n                    waveformData={audioPlayer.waveformData}\n                  />\n                </>\n              ) : (\n                <DurationDisplay\n                  duration={resolvedDuration}\n                  isPlaying={Boolean(isPlaying)}\n                  secondsElapsed={secondsElapsed}\n                />\n              )}\n            </>\n          ) : hasFatalError ? (\n            <div className='str-chat__attachment-preview-file__fatal-error'>\n              <IconExclamationMark />\n              <span>\n                {hasSizeLimitError\n                  ? t('File too large')\n                  : uploadState === 'blocked'\n                    ? t('Upload blocked')\n                    : t('Upload failed')}\n              </span>\n            </div>\n          ) : (\n            <div className='str-chat__attachment-preview-file__retriable-error'>\n              <IconExclamationTriangleFill />\n              <span>{t('Upload error')}</span>\n              <button\n                aria-label={t('aria/Retry upload')}\n                className='str-chat__attachment-preview-file__retry-upload-button'\n                data-testid='file-preview-item-retry-button'\n                onClick={() => {\n                  handleRetry(attachment);\n                }}\n                type='button'\n              >\n                {t('Retry upload')}\n              </button>\n            </div>\n          )}\n        </div>\n      </div>\n      {audioPlayer && canPlayRecord && (\n        <PlaybackRateButton\n          aria-label={t('Playback speed {{ rate }}x', {\n            rate: playbackRate?.toString() ?? '1',\n          })}\n          onClick={audioPlayer.increasePlaybackRate}\n        >\n          x{playbackRate?.toString()}\n        </PlaybackRateButton>\n      )}\n      <RemoveAttachmentPreviewButton\n        data-testid='audio-preview-item-delete-button'\n        onClick={() => {\n          if (id) removeAttachments([id]);\n        }}\n        uploadState={uploadState}\n      />\n    </AttachmentPreviewRoot>\n  );\n};\n","import { IconMicrophoneSolid, IconVideoFill } from '../Icons';\nimport React, { type ComponentType } from 'react';\nimport type { LocalAttachment } from 'stream-chat';\nimport clsx from 'clsx';\n\nexport type MediaBadgeVariant = 'video' | 'voice-recording' | string;\n\nexport type MediaBadgeProps = {\n  attachment: LocalAttachment;\n  variant: 'video' | 'voice-recording' | string;\n};\n\nconst MediaBadgeVariantToIcon: Record<MediaBadgeVariant, ComponentType> = {\n  video: IconVideoFill,\n  voiceRecording: IconMicrophoneSolid,\n};\n\nexport const MediaBadge = ({ attachment, variant }: MediaBadgeProps) => {\n  const Icon = MediaBadgeVariantToIcon[variant];\n  return (\n    <div\n      className={clsx('str-chat__media-badge', {\n        [`str-chat__media-badge--${variant}`]: variant,\n      })}\n    >\n      {Icon && <Icon />}\n      {attachment.duration ? <div>{attachment.duration}</div> : null}\n    </div>\n  );\n};\n","import type { UploadAttachmentPreviewProps } from './types';\nimport {\n  isVideoAttachment,\n  type LocalImageAttachment,\n  type LocalVideoAttachment,\n} from 'stream-chat';\nimport { useComponentContext, useTranslationContext } from '../../../context';\nimport { BaseImage as DefaultBaseImage } from '../../BaseImage';\nimport React, {\n  type KeyboardEvent,\n  type MouseEvent,\n  useCallback,\n  useMemo,\n  useState,\n} from 'react';\nimport clsx from 'clsx';\nimport { IconExclamationMark, IconRetry } from '../../Icons';\nimport { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';\nimport { Button } from '../../Button';\nimport { UploadProgressIndicator } from '../../Loading/UploadProgressIndicator';\nimport { AttachmentPreviewRoot } from './utils/AttachmentPreviewRoot';\nimport { MediaBadge } from '../../Badge/MediaBadge';\n\nexport type MediaAttachmentPreviewProps<CustomLocalMetadata = Record<string, unknown>> =\n  UploadAttachmentPreviewProps<\n    LocalVideoAttachment<CustomLocalMetadata> | LocalImageAttachment<CustomLocalMetadata>\n  > & {\n    openPreview?: () => void;\n  };\n\nexport const MediaAttachmentPreview = ({\n  attachment,\n  handleRetry,\n  openPreview,\n  removeAttachments,\n}: MediaAttachmentPreviewProps) => {\n  const { t } = useTranslationContext();\n  const { BaseImage = DefaultBaseImage } = useComponentContext();\n  const [thumbnailPreviewError, setThumbnailPreviewError] = useState(false);\n\n  const { id, uploadPermissionCheck, uploadProgress, uploadState } =\n    attachment.localMetadata ?? {};\n\n  const isUploading = uploadState === 'uploading';\n  const handleThumbnailLoadError = useCallback(() => setThumbnailPreviewError(true), []);\n  const hasSizeLimitError = uploadPermissionCheck?.reason === 'size_limit';\n  const hasFatalError = uploadState === 'blocked' || hasSizeLimitError;\n  const hasRetriableError = uploadState === 'failed' && !!handleRetry;\n  const hasUploadError = hasRetriableError || hasFatalError;\n\n  const retry = (e: MouseEvent<Element> | KeyboardEvent<Element>) => {\n    e.stopPropagation();\n    handleRetry(attachment);\n    return false;\n  };\n\n  const thumbnail = useMemo(\n    () =>\n      isVideoAttachment(attachment)\n        ? {\n            alt: attachment.title,\n            title: attachment.title,\n            url: attachment.thumb_url,\n          }\n        : {\n            alt: attachment.fallback,\n            title: attachment.fallback,\n            url: attachment.image_url || attachment.localMetadata.previewUri,\n          },\n    [attachment],\n  );\n\n  return (\n    <AttachmentPreviewRoot\n      attachment={attachment}\n      className={clsx('str-chat__attachment-preview-media', {\n        'str-chat__attachment-preview-media--thumbnail-preview-error':\n          thumbnailPreviewError,\n        'str-chat__attachment-preview-media--upload-error': hasUploadError,\n        'str-chat__attachment-preview-media--uploading': isUploading,\n      })}\n      data-testid='attachment-preview-media'\n      onPressed={hasRetriableError ? retry : undefined}\n      openPreview={!isUploading && !hasUploadError ? openPreview : undefined}\n    >\n      <div className='str-chat__attachment-preview-media__thumbnail-wrapper'>\n        {thumbnail.url && (\n          <BaseImage\n            alt={thumbnail.alt}\n            className='str-chat__attachment-preview-media__thumbnail'\n            onError={handleThumbnailLoadError}\n            src={thumbnail.url}\n            title={thumbnail.title}\n          />\n        )}\n\n        <div className={clsx('str-chat__attachment-preview-media__overlay')}>\n          {isUploading && <UploadProgressIndicator uploadProgress={uploadProgress} />}\n\n          {isVideoAttachment(attachment) &&\n            !hasUploadError &&\n            uploadState !== 'uploading' && (\n              <MediaBadge attachment={attachment} variant='video' />\n            )}\n\n          {hasFatalError && <IconExclamationMark />}\n\n          {hasRetriableError && (\n            <Button\n              appearance='solid'\n              aria-label={t('aria/Retry upload')}\n              circular\n              className='str-chat__attachment-preview-media__retry-upload-button'\n              data-testid='video-preview-item-retry-button'\n              onClick={retry}\n              size='sm'\n              variant='danger'\n            >\n              <IconRetry />\n            </Button>\n          )}\n        </div>\n      </div>\n\n      <RemoveAttachmentPreviewButton\n        data-testid='video-preview-item-delete-button'\n        onClick={() => {\n          if (id) removeAttachments([id]);\n        }}\n        uploadState={uploadState}\n      />\n    </AttachmentPreviewRoot>\n  );\n};\n","import React, { type ComponentType, useCallback, useMemo, useRef, useState } from 'react';\nimport {\n  isLocalAttachment,\n  isLocalAudioAttachment,\n  isLocalFileAttachment,\n  isLocalImageAttachment,\n  isLocalVideoAttachment,\n  isLocalVoiceRecordingAttachment,\n  isScrapedContent,\n  isVoiceRecordingAttachment,\n} from 'stream-chat';\nimport {\n  UnsupportedAttachmentPreview as DefaultUnknownAttachmentPreview,\n  type UnsupportedAttachmentPreviewProps,\n} from './UnsupportedAttachmentPreview';\nimport {\n  FileAttachmentPreview as DefaultFileAttachmentPreview,\n  type FileAttachmentPreviewProps,\n} from './FileAttachmentPreview';\nimport { type AudioAttachmentPreviewProps } from './AudioAttachmentPreview';\nimport { type ImageAttachmentPreviewProps } from './ImageAttachmentPreview';\nimport { useAttachmentsForPreview, useMessageComposerController } from '../hooks';\nimport {\n  MediaAttachmentPreview,\n  type MediaAttachmentPreviewProps,\n} from './MediaAttachmentPreview';\nimport { toBaseImageDescriptors } from '../../BaseImage';\nimport { Gallery } from '../../Gallery';\nimport { GlobalModal, type ModalCloseSource } from '../../Modal';\nimport { useComponentContext } from '../../../context';\n\nexport type AttachmentPreviewListProps = {\n  AudioAttachmentPreview?:\n    | ComponentType<AudioAttachmentPreviewProps>\n    | ComponentType<FileAttachmentPreviewProps>;\n  FileAttachmentPreview?: ComponentType<FileAttachmentPreviewProps>;\n  ImageAttachmentPreview?: ComponentType<ImageAttachmentPreviewProps>;\n  UnsupportedAttachmentPreview?: ComponentType<UnsupportedAttachmentPreviewProps>;\n  VideoAttachmentPreview?: ComponentType<MediaAttachmentPreviewProps>;\n};\n\nexport const AttachmentPreviewList = ({\n  AudioAttachmentPreview = DefaultFileAttachmentPreview,\n  FileAttachmentPreview = DefaultFileAttachmentPreview,\n  ImageAttachmentPreview = MediaAttachmentPreview,\n  UnsupportedAttachmentPreview = DefaultUnknownAttachmentPreview,\n  VideoAttachmentPreview = MediaAttachmentPreview,\n}: AttachmentPreviewListProps) => {\n  const messageComposer = useMessageComposerController();\n  const { Modal = GlobalModal } = useComponentContext();\n  const [showPreview, setShowPreview] = useState(false);\n  const initialIndexRef = useRef(0);\n  const preventOverlayClose = useCallback(\n    (source: ModalCloseSource) => source !== 'overlay',\n    [],\n  );\n\n  const { attachments } = useAttachmentsForPreview();\n  const filteredAttachments = useMemo(\n    () => attachments.filter((a) => !isVoiceRecordingAttachment(a)),\n    [attachments],\n  );\n\n  const { galleryItems, previewIndexById } = useMemo(() => {\n    const items: NonNullable<ReturnType<typeof toBaseImageDescriptors>>[] = [];\n    const indexById: Record<string, number> = {};\n    for (const a of attachments) {\n      if (isLocalImageAttachment(a) || isLocalVideoAttachment(a)) {\n        const descriptor = toBaseImageDescriptors(a);\n        if (descriptor) {\n          indexById[a.localMetadata.id] = items.length;\n          items.push(descriptor);\n        }\n      }\n    }\n    return { galleryItems: items, previewIndexById: indexById };\n  }, [attachments]);\n\n  const openPreviewAtIndex = useCallback((index: number) => {\n    initialIndexRef.current = index;\n    setShowPreview(true);\n  }, []);\n\n  if (!filteredAttachments.length) return null;\n\n  return (\n    <div\n      className='str-chat__attachment-preview-list'\n      data-testid='attachment-preview-list'\n    >\n      {attachments.map((attachment) => {\n        if (isScrapedContent(attachment)) return null;\n        // Voice recordings are rendered in the dedicated slot above (VoiceRecordingPreviewSlot)\n        if (isLocalVoiceRecordingAttachment(attachment)) return null;\n        if (isLocalAudioAttachment(attachment)) {\n          return (\n            <AudioAttachmentPreview\n              attachment={attachment}\n              handleRetry={messageComposer.attachmentManager.uploadAttachment}\n              key={attachment.localMetadata.id || attachment.asset_url}\n              removeAttachments={messageComposer.attachmentManager.removeAttachments}\n            />\n          );\n        } else if (isLocalVideoAttachment(attachment)) {\n          return (\n            <VideoAttachmentPreview\n              attachment={attachment}\n              handleRetry={messageComposer.attachmentManager.uploadAttachment}\n              key={attachment.localMetadata.id || attachment.asset_url}\n              openPreview={() =>\n                openPreviewAtIndex(previewIndexById[attachment.localMetadata.id] ?? 0)\n              }\n              removeAttachments={messageComposer.attachmentManager.removeAttachments}\n            />\n          );\n        } else if (isLocalImageAttachment(attachment)) {\n          return (\n            <ImageAttachmentPreview\n              attachment={attachment}\n              handleRetry={messageComposer.attachmentManager.uploadAttachment}\n              key={attachment.localMetadata.id || attachment.image_url}\n              openPreview={() =>\n                openPreviewAtIndex(previewIndexById[attachment.localMetadata.id] ?? 0)\n              }\n              removeAttachments={messageComposer.attachmentManager.removeAttachments}\n            />\n          );\n        } else if (isLocalFileAttachment(attachment)) {\n          return (\n            <FileAttachmentPreview\n              attachment={attachment}\n              handleRetry={messageComposer.attachmentManager.uploadAttachment}\n              key={attachment.localMetadata.id || attachment.asset_url}\n              removeAttachments={messageComposer.attachmentManager.removeAttachments}\n            />\n          );\n        } else if (isLocalAttachment(attachment)) {\n          return (\n            <UnsupportedAttachmentPreview\n              attachment={attachment}\n              handleRetry={messageComposer.attachmentManager.uploadAttachment}\n              key={attachment.localMetadata.id}\n              removeAttachments={messageComposer.attachmentManager.removeAttachments}\n            />\n          );\n        }\n        return null;\n      })}\n      {galleryItems.length > 0 && (\n        <Modal\n          className='str-chat__gallery-modal'\n          onClose={() => setShowPreview(false)}\n          onCloseAttempt={preventOverlayClose}\n          open={showPreview}\n        >\n          <Gallery initialIndex={initialIndexRef.current} items={galleryItems} />\n        </Modal>\n      )}\n    </div>\n  );\n};\n","import type { ComponentType } from 'react';\nimport React from 'react';\nimport {\n  isLocalVoiceRecordingAttachment,\n  type LocalVoiceRecordingAttachment,\n} from 'stream-chat';\nimport { useAttachmentsForPreview, useMessageComposerController } from '../hooks';\nimport { AudioAttachmentPreview } from './AudioAttachmentPreview';\nimport type { UploadAttachmentPreviewProps } from './types';\n\nexport type VoiceRecordingPreviewProps<CustomLocalMetadata = Record<string, unknown>> =\n  UploadAttachmentPreviewProps<LocalVoiceRecordingAttachment<CustomLocalMetadata>>;\n\nexport type VoiceRecordingPreviewSlotProps = {\n  /** Custom UI component for each voice recording preview in the slot; defaults to AudioAttachmentPreview */\n  VoiceRecordingPreview?: ComponentType<VoiceRecordingPreviewProps>;\n};\n\n/**\n * Dedicated slot for voice recording preview(s), rendered apart from the main attachment preview list\n */\nexport const VoiceRecordingPreviewSlot = ({\n  VoiceRecordingPreview = AudioAttachmentPreview,\n}: VoiceRecordingPreviewSlotProps) => {\n  const messageComposer = useMessageComposerController();\n  const { attachments } = useAttachmentsForPreview();\n\n  const voiceAttachments = attachments.filter(isLocalVoiceRecordingAttachment);\n  const firstVoice = voiceAttachments[0];\n  if (!firstVoice) return null;\n\n  return (\n    <div\n      className='str-chat__message-composer-voice-preview-slot'\n      data-testid='voice-preview-slot'\n    >\n      <VoiceRecordingPreview\n        attachment={firstVoice}\n        handleRetry={messageComposer.attachmentManager.uploadAttachment}\n        removeAttachments={messageComposer.attachmentManager.removeAttachments}\n      />\n    </div>\n  );\n};\n","import { useMessageComposerController } from './hooks';\nimport type { TextComposerState } from 'stream-chat';\nimport { IconBolt, IconXmark } from '../Icons';\nimport { useMessageComposerContext, useTranslationContext } from '../../context';\n\nexport type CommandChipProps = {\n  command?: TextComposerState['command'];\n};\n\nexport const CommandChip = ({ command }: CommandChipProps) => {\n  const { textComposer } = useMessageComposerController();\n  const { textareaRef } = useMessageComposerContext();\n  const { t } = useTranslationContext();\n  if (!command) return null;\n\n  return (\n    <div className='str-chat__command-chip'>\n      <IconBolt />\n      <span>{command.name}</span>\n      <button\n        aria-label={t('Exit command {{ command }}', { command: command.name })}\n        className={'str-chat__command-chip__close-button'}\n        onClick={() => {\n          textComposer.setCommand(null);\n          textareaRef.current?.focus();\n        }}\n      >\n        <IconXmark />\n      </button>\n    </div>\n  );\n};\n","import React from 'react';\nimport { useCooldownRemaining } from './hooks';\n\nexport const CooldownTimer = () => {\n  const secondsLeft = useCooldownRemaining();\n\n  return (\n    <div className='str-chat__message-composer-cooldown' data-testid='cooldown-timer'>\n      {secondsLeft}\n    </div>\n  );\n};\n","import { useTranslationContext } from '../../context/TranslationContext';\n\nexport const UploadIcon = () => {\n  const { t } = useTranslationContext('UploadIcon');\n  return (\n    <svg\n      data-testid='attach-icon'\n      fill='none'\n      height='24'\n      viewBox='0 0 24 24'\n      width='24'\n      xmlns='http://www.w3.org/2000/svg'\n    >\n      <title>{t('Attach files')}</title>\n      <g clipPath='url(#clip0_10878_5)'>\n        <path\n          d='M12.9997 6.99993L10.9997 6.99993L10.9997 10.9999L6.99972 10.9999L6.99972 12.9999L10.9997 12.9999L10.9997 16.9999L12.9997 16.9999L12.9997 12.9999L16.9997 12.9999L16.9997 10.9999L12.9997 10.9999L12.9997 6.99993ZM11.9997 1.99992C6.47972 1.99992 1.99972 6.47993 1.99972 11.9999C1.99972 17.5199 6.47972 21.9999 11.9997 21.9999C17.5197 21.9999 21.9997 17.5199 21.9997 11.9999C21.9997 6.47993 17.5197 1.99992 11.9997 1.99992ZM11.9997 19.9999C7.58972 19.9999 3.99972 16.4099 3.99972 11.9999C3.99972 7.58993 7.58972 3.99993 11.9997 3.99993C16.4097 3.99993 19.9997 7.58993 19.9997 11.9999C19.9997 16.4099 16.4097 19.9999 11.9997 19.9999Z'\n          fill='black'\n        />\n      </g>\n      <defs>\n        <clipPath id='clip0_10878_5'>\n          <rect fill='white' height='24' width='24' />\n        </clipPath>\n      </defs>\n    </svg>\n  );\n};\n\nexport const BinIcon = () => (\n  <svg fill='currentColor' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'>\n    <path d='M8.00033 25.3333C8.00033 26.8 9.20033 28 10.667 28H21.3337C22.8003 28 24.0003 26.8 24.0003 25.3333V12C24.0003 10.5333 22.8003 9.33333 21.3337 9.33333H10.667C9.20033 9.33333 8.00033 10.5333 8.00033 12V25.3333ZM24.0003 5.33333H20.667L19.7203 4.38667C19.4803 4.14667 19.1337 4 18.787 4H13.2137C12.867 4 12.5203 4.14667 12.2803 4.38667L11.3337 5.33333H8.00033C7.26699 5.33333 6.66699 5.93333 6.66699 6.66667C6.66699 7.4 7.26699 8 8.00033 8H24.0003C24.7337 8 25.3337 7.4 25.3337 6.66667C25.3337 5.93333 24.7337 5.33333 24.0003 5.33333Z' />\n  </svg>\n);\n\nexport const PauseIcon = () => (\n  <svg\n    data-testid='str-chat__pause-icon'\n    fill='currentColor'\n    viewBox='0 0 16 20'\n    xmlns='http://www.w3.org/2000/svg'\n  >\n    <path d='M0 19.3333H5.33333V0.666626H0V19.3333ZM10.6667 0.666626V19.3333H16V0.666626H10.6667Z' />\n  </svg>\n);\n\nexport const PlayIcon = () => (\n  <svg\n    data-testid='str-chat__play-icon'\n    fill='currentColor'\n    viewBox='0 0 14 18'\n    xmlns='http://www.w3.org/2000/svg'\n  >\n    <path d='M0.236328 2.09338V15.9067C0.236328 16.9601 1.39633 17.6001 2.28966 17.0267L13.143 10.1201C13.9697 9.60005 13.9697 8.40005 13.143 7.86672L2.28966 0.973385C1.39633 0.400051 0.236328 1.04005 0.236328 2.09338Z' />\n  </svg>\n);\n\nexport const CheckSignIcon = () => (\n  <svg fill='currentColor' viewBox='0 0 18 14' xmlns='http://www.w3.org/2000/svg'>\n    <path d='M5.79457 10.875L2.32457 7.40502C1.93457 7.01502 1.30457 7.01502 0.91457 7.40502C0.52457 7.79502 0.52457 8.42502 0.91457 8.81502L5.09457 12.995C5.48457 13.385 6.11457 13.385 6.50457 12.995L17.0846 2.41502C17.4746 2.02502 17.4746 1.39502 17.0846 1.00502C16.6946 0.615024 16.0646 0.615024 15.6746 1.00502L5.79457 10.875Z' />\n  </svg>\n);\n","import clsx from 'clsx';\nimport React, { useState } from 'react';\nimport type { LinkPreview, LinkPreviewsManagerState } from 'stream-chat';\nimport { LinkPreviewsManager } from 'stream-chat';\nimport { useStateStore } from '../../store';\nimport { PopperTooltip } from '../Tooltip';\nimport { useEnterLeaveHandlers } from '../Tooltip/hooks';\nimport { useMessageComposerController } from './hooks';\nimport { BaseImage } from '../BaseImage';\nimport { RemoveAttachmentPreviewButton } from './RemoveAttachmentPreviewButton';\nimport { IconLink } from '../Icons';\n\nexport type LinkPreviewListProps = {\n  displayLinkCount?: number;\n};\n\nconst linkPreviewsManagerStateSelector = (state: LinkPreviewsManagerState) => ({\n  linkPreviews: Array.from(state.previews.values()).filter(\n    (preview) =>\n      LinkPreviewsManager.previewIsLoaded(preview) ||\n      LinkPreviewsManager.previewIsLoading(preview),\n  ),\n});\n\nexport const LinkPreviewList = ({ displayLinkCount = 1 }: LinkPreviewListProps) => {\n  const messageComposer = useMessageComposerController();\n  const { linkPreviewsManager } = messageComposer;\n  const { linkPreviews } = useStateStore(\n    linkPreviewsManager.state,\n    linkPreviewsManagerStateSelector,\n  );\n\n  if (linkPreviews.length === 0) return null;\n\n  return (\n    <div className='str-chat__link-preview-list'>\n      {linkPreviews.slice(0, displayLinkCount).map((linkPreview) => (\n        <LinkPreviewCard key={linkPreview.og_scrape_url} linkPreview={linkPreview} />\n      ))}\n    </div>\n  );\n};\n\ntype LinkPreviewProps = {\n  linkPreview: LinkPreview;\n};\n\nexport const LinkPreviewCard = ({ linkPreview }: LinkPreviewProps) => {\n  const { linkPreviewsManager } = useMessageComposerController();\n  const { handleEnter, handleLeave, tooltipVisible } =\n    useEnterLeaveHandlers<HTMLDivElement>();\n  const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null);\n  const { image_url, thumb_url, title, title_link } = linkPreview;\n\n  if (\n    !LinkPreviewsManager.previewIsLoaded(linkPreview) &&\n    !LinkPreviewsManager.previewIsLoading(linkPreview)\n  )\n    return null;\n\n  const previewImageSrc = title_link || image_url || thumb_url;\n  return (\n    <div\n      className={clsx('str-chat__link-preview-card', {\n        'str-chat__link-preview-card--loading':\n          LinkPreviewsManager.previewIsLoading(linkPreview),\n      })}\n      data-testid='link-preview-card'\n      onMouseEnter={handleEnter}\n      onMouseLeave={handleLeave}\n      ref={setReferenceElement}\n    >\n      <PopperTooltip\n        offset={[0, 5]}\n        referenceElement={referenceElement}\n        visible={tooltipVisible}\n      >\n        {linkPreview.og_scrape_url}\n      </PopperTooltip>\n\n      {previewImageSrc && (\n        <BaseImage\n          alt={title}\n          className='str-chat__attachment-preview__thumbnail'\n          src={previewImageSrc}\n          title={title}\n        />\n      )}\n      <div className='str-chat__link-preview-card__content'>\n        <div className='str-chat__link-preview-card__content-title'>\n          {linkPreview.title}\n        </div>\n        <div className='str-chat__link-preview-card__content-description'>\n          {linkPreview.text}\n        </div>\n        <div className='str-chat__link-preview-card__content__url'>\n          <IconLink />\n          <span>{linkPreview.og_scrape_url}</span>\n        </div>\n      </div>\n\n      <RemoveAttachmentPreviewButton\n        className='str-chat__link-preview-card__dismiss-button'\n        data-testid='link-preview-card-dismiss-btn'\n        onClick={() => linkPreviewsManager.dismissPreview(linkPreview.og_scrape_url)}\n      />\n    </div>\n  );\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../context';\nimport type { RecordingPermission } from './classes/BrowserPermission';\n\nexport type RecordingPermissionDeniedNotificationProps = {\n  permissionName: RecordingPermission;\n};\n\nexport const RecordingPermissionDeniedNotification = ({\n  permissionName,\n}: RecordingPermissionDeniedNotificationProps) => {\n  const { t } = useTranslationContext();\n  const permissionTranslations = {\n    body: {\n      camera: t('To start recording, allow the camera access in your browser'),\n      microphone: t('To start recording, allow the microphone access in your browser'),\n    },\n    heading: {\n      camera: t('Allow access to camera'),\n      microphone: t('Allow access to microphone'),\n    },\n  };\n\n  return (\n    <div className='str-chat__recording-permission-denied-notification'>\n      <div className='str-chat__recording-permission-denied-notification__heading'>\n        {permissionTranslations.heading[permissionName]}\n      </div>\n      <p className='str-chat__recording-permission-denied-notification__message'>\n        {permissionTranslations.body[permissionName]}\n      </p>\n    </div>\n  );\n};\n","import React, { useEffect } from 'react';\nimport { DurationDisplay, WaveProgressBar } from '../../AudioPlayback';\nimport type { AudioPlayerState } from '../../AudioPlayback/AudioPlayer';\nimport { useAudioPlayer } from '../../AudioPlayback/WithAudioPlayback';\nimport { useStateStore } from '../../../store';\nimport { IconPauseFill, IconPlayFill } from '../../Icons';\nimport { Button } from '../../Button';\nimport { useTranslationContext } from '../../../context';\nimport clsx from 'clsx';\n\nconst audioPlayerStateSelector = (state: AudioPlayerState) => ({\n  isPlaying: state.isPlaying,\n  progress: state.progressPercent,\n  secondsElapsed: state.secondsElapsed,\n});\n\nexport type AudioRecordingPlayerProps = {\n  durationSeconds: number;\n  mimeType?: string;\n  src?: string;\n  waveformData?: number[];\n};\n\nexport const AudioRecordingPlayback = ({\n  durationSeconds,\n  mimeType,\n  src,\n  waveformData,\n}: AudioRecordingPlayerProps) => {\n  const { t } = useTranslationContext();\n  const audioPlayer = useAudioPlayer({\n    durationSeconds,\n    mimeType,\n    src,\n    waveformData,\n  });\n\n  const { isPlaying, progress, secondsElapsed } =\n    useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};\n\n  const displayedDuration = secondsElapsed || durationSeconds;\n\n  useEffect(() => {\n    audioPlayer?.cancelScheduledRemoval();\n    return () => {\n      audioPlayer?.scheduleRemoval();\n    };\n  }, [audioPlayer]);\n\n  if (!audioPlayer) return null;\n\n  return (\n    <div\n      className={clsx('str-chat__audio-recorder__recording-playback', {\n        'str-chat__audio-recorder__recording-playback--isPlaying': isPlaying,\n      })}\n    >\n      <Button\n        appearance='ghost'\n        aria-label={isPlaying ? t('aria/Pause') : t('aria/Play')}\n        circular\n        className='str-chat__audio_recorder__toggle-playback-button'\n        data-testid='audio-recording-preview-toggle-play-btn'\n        onClick={audioPlayer.togglePlay}\n        size='sm'\n        variant='secondary'\n      >\n        {isPlaying ? <IconPauseFill /> : <IconPlayFill />}\n      </Button>\n      <DurationDisplay\n        className={clsx('str-chat__recording-timer', {\n          'str-chat__recording-timer--hours': displayedDuration >= 3600,\n        })}\n        duration={durationSeconds}\n        isPlaying={!!isPlaying}\n        secondsElapsed={secondsElapsed}\n      />\n      <div className='str-chat__wave-progress-bar__track-container'>\n        <WaveProgressBar\n          durationSeconds={durationSeconds}\n          progress={progress}\n          secondsElapsed={secondsElapsed}\n          seek={audioPlayer.seek}\n          waveformData={waveformData || []}\n        />\n      </div>\n    </div>\n  );\n};\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\ntype UseTimeElapsedParams = {\n  initialSeconds?: number;\n  startOnMount?: boolean;\n};\n\n// todo: provide start timestamp\nexport const useTimeElapsed = ({\n  initialSeconds = 0,\n  startOnMount,\n}: UseTimeElapsedParams = {}) => {\n  const [secondsElapsed, setSecondsElapsed] = useState<number>(initialSeconds);\n  const updateInterval = useRef<ReturnType<typeof setInterval>>(undefined);\n\n  const startCounter = useCallback(() => {\n    if (updateInterval.current) return;\n    updateInterval.current = setInterval(() => {\n      setSecondsElapsed((prev) => prev + 1);\n    }, 1000);\n  }, []);\n\n  const stopCounter = useCallback(() => {\n    clearInterval(updateInterval.current);\n    updateInterval.current = undefined;\n  }, []);\n\n  useEffect(() => {\n    if (updateInterval.current) return;\n    setSecondsElapsed(initialSeconds);\n  }, [initialSeconds]);\n\n  useEffect(() => {\n    if (!startOnMount) return;\n    startCounter();\n    return () => {\n      stopCounter();\n    };\n  }, [startCounter, startOnMount, stopCounter]);\n\n  return {\n    secondsElapsed,\n    startCounter,\n    stopCounter,\n  };\n};\n","import clsx from 'clsx';\nimport { displayDuration } from '../../Attachment';\nimport React from 'react';\n\nexport type RecordingTimerProps = {\n  durationSeconds: number;\n};\n\nexport const RecordingTimer = ({ durationSeconds }: RecordingTimerProps) => (\n  <div\n    className={clsx('str-chat__recording-timer', {\n      'str-chat__recording-timer--hours': durationSeconds >= 3600,\n    })}\n  >\n    {displayDuration(durationSeconds)}\n  </div>\n);\n","import React, { useEffect, useState } from 'react';\nimport { useTimeElapsed } from './hooks/useTimeElapsed';\nimport { useMessageComposerContext } from '../../../context';\nimport { RecordingTimer } from './RecordingTimer';\nimport { IconVoice } from '../../Icons';\n\ntype WaveformProps = {\n  maxDataPointsDrawn?: number;\n};\n\nconst AudioRecordingWaveform = ({ maxDataPointsDrawn = 200 }: WaveformProps) => {\n  const {\n    recordingController: { recorder },\n  } = useMessageComposerContext();\n\n  const [amplitudes, setAmplitudes] = useState<number[]>([]);\n\n  useEffect(() => {\n    if (!recorder?.amplitudeRecorder) return;\n    const amplitudesSubscription =\n      recorder.amplitudeRecorder.amplitudes.subscribe(setAmplitudes);\n    return () => {\n      amplitudesSubscription.unsubscribe();\n    };\n  }, [recorder]);\n\n  if (!recorder) return null;\n\n  return (\n    <div className='str-chat__waveform-box-container'>\n      <div className='str-chat__wave-progress-bar__track'>\n        {amplitudes.slice(-maxDataPointsDrawn).map((amplitude, i) => (\n          <div\n            className='str-chat__wave-progress-bar__amplitude-bar'\n            key={`amplitude-${i}-voice-recording`}\n            style={\n              {\n                '--str-chat__wave-progress-bar__amplitude-bar-height': amplitude\n                  ? amplitude * 100 + '%'\n                  : '0%',\n              } as React.CSSProperties\n            }\n          />\n        ))}\n      </div>\n    </div>\n  );\n};\nexport const AudioRecordingPreview = () => {\n  const {\n    recordingController: { recorder },\n  } = useMessageComposerContext();\n\n  const initialSeconds = recorder?.durationMs ? recorder.durationMs / 1000 : 0;\n  const { secondsElapsed, startCounter, stopCounter } = useTimeElapsed({\n    initialSeconds,\n  });\n\n  useEffect(() => {\n    if (!recorder?.mediaRecorder) return;\n    const { mediaRecorder } = recorder;\n\n    if (mediaRecorder.state === 'recording') {\n      startCounter();\n    }\n\n    mediaRecorder.addEventListener('start', startCounter);\n    mediaRecorder.addEventListener('resume', startCounter);\n    mediaRecorder.addEventListener('stop', stopCounter);\n    mediaRecorder.addEventListener('pause', stopCounter);\n\n    return () => {\n      mediaRecorder.removeEventListener('start', startCounter);\n      mediaRecorder.removeEventListener('resume', startCounter);\n      mediaRecorder.removeEventListener('stop', stopCounter);\n      mediaRecorder.removeEventListener('pause', stopCounter);\n    };\n  }, [recorder, startCounter, stopCounter]);\n\n  return (\n    <div className='str-chat__audio-recorder__recording-preview'>\n      <IconVoice />\n      <RecordingTimer durationSeconds={secondsElapsed} />\n      <AudioRecordingWaveform />\n    </div>\n  );\n};\n","import { MediaRecordingState } from '../classes';\n\nexport const isPaused = (recordingState?: MediaRecordingState) =>\n  recordingState === MediaRecordingState.PAUSED;\nexport const isStopped = (recordingState?: MediaRecordingState) =>\n  recordingState === MediaRecordingState.STOPPED;\nexport const isRecording = (recordingState?: MediaRecordingState) =>\n  recordingState === MediaRecordingState.RECORDING;\n","import { CheckSignIcon } from '../../MessageComposer/icons';\nimport { IconDelete, IconPauseFill, IconVoice } from '../../Icons';\nimport React from 'react';\nimport { useMessageComposerContext, useTranslationContext } from '../../../context';\nimport { isRecording } from './recordingStateIdentity';\nimport { Button } from '../../Button';\nimport { useNotificationApi } from '../../Notifications';\nimport { UploadProgressIndicator } from '../../Loading/UploadProgressIndicator';\n\nconst ToggleRecordingButton = () => {\n  const { t } = useTranslationContext();\n  const {\n    recordingController: { recorder, recordingState },\n  } = useMessageComposerContext();\n\n  const recording = isRecording(recordingState);\n\n  return (\n    <Button\n      appearance='outline'\n      aria-label={recording ? t('aria/Pause recording') : t('aria/Resume recording')}\n      circular\n      className='str-chat__audio_recorder__toggle-recording-button'\n      onClick={() => (recording ? recorder?.pause() : recorder?.resume())}\n      size='sm'\n      variant='secondary'\n    >\n      {recording ? <IconPauseFill /> : <IconVoice />}\n    </Button>\n  );\n};\n\nexport const AudioRecorderRecordingControls = () => {\n  const { addNotification } = useNotificationApi();\n  const { t } = useTranslationContext();\n  const {\n    recordingController: { completeRecording, recorder, recording, recordingState },\n  } = useMessageComposerContext();\n  const isUploadingFile = recording?.localMetadata?.uploadState === 'uploading';\n  const uploadProgress = recording?.localMetadata?.uploadProgress;\n\n  if (!recorder) return null;\n\n  return (\n    <div className='str-chat__audio_recorder__recording-controls'>\n      {!isRecording(recordingState) && (\n        <Button\n          appearance='ghost'\n          aria-label={t('aria/Cancel recording')}\n          circular\n          className='str-chat__audio_recorder__cancel-button'\n          data-testid={'cancel-recording-audio-button'}\n          disabled={isUploadingFile}\n          onClick={() => {\n            recorder.cancel();\n            addNotification({\n              emitter: 'AudioRecorder',\n              message: t('Voice message deleted'),\n              severity: 'info',\n              type: 'audioRecording:cancel:success',\n            });\n          }}\n          size='sm'\n          variant='secondary'\n        >\n          <IconDelete />\n        </Button>\n      )}\n      <ToggleRecordingButton />\n      <Button\n        appearance='solid'\n        aria-label={t('aria/Complete recording')}\n        circular\n        className='str-chat__audio_recorder__stop-button'\n        data-testid='audio-recorder-stop-button'\n        onClick={completeRecording}\n        size='sm'\n        variant='primary'\n      >\n        {isUploadingFile ? (\n          <UploadProgressIndicator uploadProgress={uploadProgress} />\n        ) : (\n          <CheckSignIcon />\n        )}\n      </Button>\n    </div>\n  );\n};\n","import React, { useMemo } from 'react';\nimport { AudioRecordingPlayback } from './AudioRecordingPlayback';\nimport { AudioRecordingPreview } from './AudioRecordingPreview';\nimport { MediaRecordingState } from '../classes';\nimport { useMessageComposerContext } from '../../../context/MessageComposerContext';\nimport { AudioRecorderRecordingControls } from './AudioRecorderRecordingControls';\nimport { isStopped } from './recordingStateIdentity';\n\nexport const AudioRecorder = () => {\n  const {\n    recordingController: { recorder, recording, recordingState },\n  } = useMessageComposerContext();\n\n  const state = useMemo(\n    () => ({\n      paused: recordingState === MediaRecordingState.PAUSED,\n      recording: recordingState === MediaRecordingState.RECORDING,\n      stopped: recordingState === MediaRecordingState.STOPPED,\n    }),\n    [recordingState],\n  );\n\n  if (!recorder) return null;\n\n  return (\n    <div className='str-chat__audio_recorder' data-testid={'audio-recorder'}>\n      {(isStopped(recordingState) || state.paused) && recording?.asset_url ? (\n        <AudioRecordingPlayback\n          durationSeconds={recording.duration ?? 0}\n          mimeType={recording.mime_type}\n          src={recording.asset_url}\n          waveformData={recording.waveform_data}\n        />\n      ) : state.recording ? (\n        <AudioRecordingPreview />\n      ) : null}\n\n      <AudioRecorderRecordingControls />\n    </div>\n  );\n};\n","import { RecordingAttachmentType, RecordingPermission } from '../classes';\nimport { RecordingPermissionDeniedNotification as DefaultRecordingPermissionDeniedNotification } from '../RecordingPermissionDeniedNotification';\nimport React, { forwardRef, useRef } from 'react';\nimport { useAttachmentManagerState } from '../../MessageComposer/hooks/useAttachmentManagerState';\nimport {\n  useComponentContext,\n  useMessageComposerContext,\n  useTranslationContext,\n} from '../../../context';\nimport { Callout, useDialogOnNearestManager } from '../../Dialog';\nimport { Button } from '../../Button';\nimport { IconVoice } from '../../Icons';\n\nconst dialogId = 'recording-permission-denied-notification';\n\nexport const AudioRecordingButtonWithNotification = () => {\n  const {\n    RecordingPermissionDeniedNotification = DefaultRecordingPermissionDeniedNotification,\n    StartRecordingAudioButton = DefaultStartRecordingAudioButton,\n  } = useComponentContext();\n  const { asyncMessagesMultiSendEnabled, recordingController } =\n    useMessageComposerContext();\n  const { attachments } = useAttachmentManagerState();\n\n  const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n\n  const audioRecordingBtnRef = useRef<HTMLButtonElement | null>(null);\n  const isRecording = !!recordingController.recordingState;\n\n  return (\n    <>\n      <StartRecordingAudioButton\n        disabled={\n          isRecording ||\n          (!asyncMessagesMultiSendEnabled &&\n            attachments.some((a) => a.type === RecordingAttachmentType.VOICE_RECORDING))\n        }\n        onClick={() => {\n          recordingController.recorder?.start();\n\n          const recordingEnabled = !!(\n            recordingController.recorder && navigator.mediaDevices\n          );\n\n          const shouldShowNotification =\n            recordingEnabled && recordingController.permissionState === 'denied';\n          if (shouldShowNotification) dialog.open();\n        }}\n        ref={audioRecordingBtnRef}\n      />\n      <Callout\n        className='str-chat__recording-permission-denied-notification'\n        dialogManagerId={dialogManager?.id}\n        id={dialogId}\n        onClose={dialog.close}\n        placement={'top-start'}\n        referenceElement={audioRecordingBtnRef.current}\n      >\n        <RecordingPermissionDeniedNotification permissionName={RecordingPermission.MIC} />\n      </Callout>\n    </>\n  );\n};\n\nexport type StartRecordingAudioButtonProps = React.ComponentProps<'button'>;\n\nexport const DefaultStartRecordingAudioButton = forwardRef<\n  HTMLButtonElement,\n  StartRecordingAudioButtonProps\n>(function StartRecordingAudioButton(props, ref) {\n  const { t } = useTranslationContext();\n\n  return (\n    <Button\n      appearance='ghost'\n      aria-label={t('aria/Start recording audio')}\n      circular\n      className='str-chat__start-recording-audio-button'\n      data-testid='start-recording-audio-button'\n      size='sm'\n      variant='secondary'\n      {...props}\n      ref={ref}\n    >\n      <IconVoice />\n    </Button>\n  );\n});\n","import React from 'react';\nimport { QuotedMessagePreviewUI } from './QuotedMessagePreview';\nimport type { LocalMessage } from 'stream-chat';\nimport { useTranslationContext } from '../../context';\n\nexport type EditedMessagePreviewProps = {\n  message: LocalMessage;\n  onCancel: () => void;\n};\n\nexport const EditedMessagePreview = ({\n  message,\n  onCancel,\n}: EditedMessagePreviewProps) => {\n  const { t } = useTranslationContext();\n\n  return (\n    <QuotedMessagePreviewUI\n      authorLabel={t('Edit Message')}\n      onRemove={onCancel}\n      quotedMessage={message}\n    />\n  );\n};\n","import clsx from 'clsx';\nimport React from 'react';\nimport { useMessageComposerController } from './hooks';\nimport { IconCheckmark } from '../Icons';\nimport type { MessageComposerState } from 'stream-chat';\nimport { useStateStore } from '../../store';\nimport { useTranslationContext } from '../../context';\n\nconst stateSelector = (state: MessageComposerState) => ({\n  showReplyInChannel: state.showReplyInChannel,\n});\n\nexport const SendToChannelCheckbox = () => {\n  const { t } = useTranslationContext();\n  const messageComposer = useMessageComposerController();\n  const { showReplyInChannel } = useStateStore(messageComposer.state, stateSelector);\n\n  if (messageComposer.editedMessage || !messageComposer.threadId) return null;\n\n  const labelText =\n    Object.keys(messageComposer.channel.state.members).length === 2\n      ? t('Also send as a direct message')\n      : t('Also send in channel');\n\n  return (\n    <div\n      className={clsx('str-chat__send-to-channel-checkbox__container', {\n        'str-chat__send-to-channel-checkbox__container--checked': showReplyInChannel,\n      })}\n      data-testid='send-to-channel-checkbox'\n    >\n      <label\n        className='str-chat__send-to-channel-checkbox__field'\n        htmlFor='send-to-channel-checkbox'\n      >\n        <input\n          aria-checked={showReplyInChannel}\n          checked={showReplyInChannel}\n          className='str-chat__send-to-channel-checkbox__input'\n          id='send-to-channel-checkbox'\n          onChange={() => messageComposer.toggleShowReplyInChannel()}\n          type='checkbox'\n        />\n        <span aria-hidden className='str-chat__send-to-channel-checkbox__visual'>\n          <span className='str-chat__send-to-channel-checkbox__checkmark'>\n            <IconCheckmark />\n          </span>\n        </span>\n        <span className='str-chat__send-to-channel-checkbox__label'>{labelText}</span>\n      </label>\n    </div>\n  );\n};\n","import type { ComponentProps, PropsWithChildren } from 'react';\nimport React from 'react';\nimport type { CommandResponse, MessageComposerState } from 'stream-chat';\nimport { CommandContextMenuItem } from '../../MessageComposer/AttachmentSelector/CommandsMenu';\nimport { useStateStore } from '../../../store';\nimport { useMessageComposerController } from '../../MessageComposer/hooks';\n\nexport type CommandItemProps = {\n  entity: CommandResponse;\n  enabled?: boolean;\n  focused?: boolean;\n} & ComponentProps<'button'>;\n\nconst messageComposerStateSelector = ({\n  editedMessage,\n  quotedMessage,\n}: MessageComposerState) => ({\n  editedMessage,\n  quotedMessage,\n});\n\nexport const CommandItem = (props: PropsWithChildren<CommandItemProps>) => {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  const { enabled, entity, focused: _, ...buttonProps } = props;\n  const messageComposer = useMessageComposerController();\n  useStateStore(messageComposer.state, messageComposerStateSelector);\n\n  if (!entity.name) return null;\n\n  const resolvedEnabled =\n    enabled ??\n    !messageComposer.isCommandDisabled(entity as CommandResponse & { name: string });\n\n  return (\n    <CommandContextMenuItem\n      {...buttonProps}\n      command={entity as CommandResponse & { name: string }}\n      enabled={resolvedEnabled}\n    />\n  );\n};\n","import clsx from 'clsx';\nimport type { ComponentProps } from 'react';\nimport React from 'react';\nimport { EmojiContextMenuButton } from '../../Dialog';\n\nexport type EmoticonItemProps = {\n  entity: {\n    /** Name for emoticon */\n    name: string;\n    /** Native value or actual emoticon */\n    native: string;\n    /** The parts of the Name property of the entity (or id if no name) that can be matched to the user input value.\n     * Default is bold for matches, but can be overwritten in css.\n     * */\n    tokenizedDisplayName: { token: string; parts: string[] };\n  };\n  focused?: boolean;\n} & ComponentProps<'button'>;\n\nexport const EmoticonItem = (props: EmoticonItemProps) => {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  const { className, entity, focused: _, ...buttonProps } = props;\n  const hasEntity = Object.keys(entity).length;\n  if (!hasEntity) return null;\n\n  const { parts, token } = entity.tokenizedDisplayName ?? ({} as EmoticonItemProps);\n\n  return (\n    <EmojiContextMenuButton\n      {...buttonProps}\n      className={clsx('str-chat__emoji-item', className)}\n      emoji={entity.native}\n    >\n      {parts?.map((part, i) =>\n        part.toLowerCase() === token ? (\n          <span className='str-chat__emoji-item--highlight' key={`part-${i}`}>\n            {part}\n          </span>\n        ) : (\n          <span className='str-chat__emoji-item--part' key={`part-${i}`}>\n            {part}\n          </span>\n        ),\n      ) ?? null}\n    </EmojiContextMenuButton>\n  );\n};\n","import clsx from 'clsx';\nimport { type ComponentProps, useRef } from 'react';\nimport React, { useCallback, useLayoutEffect } from 'react';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\nimport type { TextComposerSuggestion } from 'stream-chat';\nimport type { UserItemProps } from './UserItem';\nimport type { CommandItemProps } from './CommandItem';\nimport type { EmoticonItemProps } from './EmoticonItem';\nimport { useMessageComposerContext } from '../../../context';\n\nexport type DefaultSuggestionListItemEntity =\n  | UserItemProps['entity']\n  | CommandItemProps['entity']\n  | EmoticonItemProps['entity'];\n\nexport type SuggestionListItemComponentProps = {\n  entity: DefaultSuggestionListItemEntity | unknown;\n  focused: boolean;\n} & ComponentProps<'button'>;\n\nexport type SuggestionItemProps = ComponentProps<'button'> & {\n  component: React.ComponentType<SuggestionListItemComponentProps>;\n  item: TextComposerSuggestion;\n  focused: boolean;\n};\n\nexport const SuggestionListItem = ({\n  className,\n  component: Component,\n  focused,\n  item,\n  onClick,\n  onKeyDown,\n  onMouseEnter,\n  ...restProps\n}: SuggestionItemProps) => {\n  const { textComposer } = useMessageComposerController();\n  const { textareaRef } = useMessageComposerContext();\n  const componentRef = useRef<HTMLButtonElement | null>(null);\n\n  const handleSelect = useCallback(() => {\n    textComposer.handleSelect(item);\n    textareaRef.current?.focus();\n  }, [item, textareaRef, textComposer]);\n\n  useLayoutEffect(() => {\n    if (!focused) return;\n    componentRef.current?.scrollIntoView({ behavior: 'instant', block: 'nearest' });\n  }, [focused]);\n\n  return (\n    <Component\n      {...restProps}\n      className={clsx('str-chat__suggestion-list-item', className, {\n        'str-chat__suggestion-list-item--selected': focused,\n      })}\n      entity={item}\n      focused={focused}\n      onClick={(e) => {\n        handleSelect();\n        onClick?.(e);\n      }}\n      onKeyDown={(event) => {\n        if (event.key === 'Enter') handleSelect();\n        onKeyDown?.(event);\n      }}\n      onMouseEnter={onMouseEnter}\n      ref={componentRef}\n    />\n  );\n};\n","import type { ComponentProps } from 'react';\nimport React from 'react';\nimport clsx from 'clsx';\nimport { UserContextMenuButton } from '../../Dialog';\n\nexport type UserItemProps = {\n  /** The user */\n  entity: {\n    /** The parts of the Name property of the entity (or id if no name) that can be matched to the user input value.\n     * Default is bold for matches, but can be overwritten in css.\n     * */\n    tokenizedDisplayName: { token: string; parts: string[] };\n    /** Id of the user */\n    id?: string;\n    /** Image of the user */\n    image?: string;\n    /** Name of the user */\n    name?: string;\n  };\n  focused?: boolean;\n} & ComponentProps<'button'>;\n\n/**\n * UI component for mentions rendered in suggestion list\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport const UserItem = ({ entity, focused: _, ...buttonProps }: UserItemProps) => {\n  const hasEntity = !!Object.keys(entity).length;\n  if (!hasEntity) return null;\n\n  const { parts, token } = entity.tokenizedDisplayName;\n  const renderName = () =>\n    parts.map((part, i) => {\n      const matches = part.toLowerCase() === token;\n      const partWithHTMLSpacesAround = part.replace(/^\\s+|\\s+$/g, '\\u00A0');\n      return (\n        <span\n          className={clsx({\n            'str-chat__emoji-item-part': !matches,\n            'str-chat__suggestion-item-part--match': matches,\n          })}\n          key={`part-${i}`}\n        >\n          {partWithHTMLSpacesAround}\n        </span>\n      );\n    });\n\n  return (\n    <UserContextMenuButton\n      {...buttonProps}\n      imageUrl={entity.image}\n      title={entity.name || entity.id}\n      userName={entity.name || entity.id}\n    >\n      {renderName()}\n    </UserContextMenuButton>\n  );\n};\n","const CARET_MIRROR_CLASS = 'str-chat__textarea-caret-mirror';\nconst CARET_MARKER_CLASS = 'str-chat__textarea-caret-marker';\n\nexport type TextareaCaretRect = DOMRect | null;\n\n/**\n * Returns the caret rectangle for a textarea using a mirror-measure hack.\n * It clones computed styles and content into a hidden element to infer the\n * caret position because textarea doesn't expose caret geometry.\n */\n\nexport const getTextareaCaretRect = (\n  textarea: HTMLTextAreaElement | null,\n  selectionEnd?: number,\n): TextareaCaretRect => {\n  if (!textarea || typeof window === 'undefined') return null;\n\n  const caretIndex = Math.max(0, selectionEnd ?? textarea.selectionEnd ?? 0);\n  const value = textarea.value ?? '';\n  const valueBeforeCaret = value.slice(0, caretIndex);\n  const valueAfterCaret = value.slice(caretIndex);\n\n  const computedStyle = window.getComputedStyle(textarea);\n  const mirror = document.createElement('div');\n  mirror.className = CARET_MIRROR_CLASS;\n  mirror.style.position = 'absolute';\n  mirror.style.visibility = 'hidden';\n  mirror.style.top = '0';\n  mirror.style.left = '-9999px';\n  mirror.style.whiteSpace = 'pre-wrap';\n  mirror.style.wordWrap = 'break-word';\n\n  for (const property of computedStyle) {\n    mirror.style.setProperty(property, computedStyle.getPropertyValue(property));\n  }\n\n  mirror.textContent = valueBeforeCaret;\n\n  const caretMarker = document.createElement('span');\n  caretMarker.className = CARET_MARKER_CLASS;\n  caretMarker.textContent = valueAfterCaret.length ? valueAfterCaret : '.';\n  mirror.appendChild(caretMarker);\n\n  document.body.appendChild(mirror);\n  mirror.scrollTop = textarea.scrollTop;\n  mirror.scrollLeft = textarea.scrollLeft;\n\n  const textareaRect = textarea.getBoundingClientRect();\n  const mirrorRect = mirror.getBoundingClientRect();\n  const caretRect = caretMarker.getBoundingClientRect();\n\n  document.body.removeChild(mirror);\n\n  const left = textareaRect.left + (caretRect.left - mirrorRect.left);\n  const top = textareaRect.top + (caretRect.top - mirrorRect.top);\n  const height = caretRect.height || parseFloat(computedStyle.lineHeight) || 0;\n\n  return new DOMRect(left, top, 0, height);\n};\n","import clsx from 'clsx';\nimport React, {\n  useCallback,\n  useEffect,\n  useLayoutEffect,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport type { VirtualElement } from '@floating-ui/react';\nimport type { CommandItemProps } from './CommandItem';\nimport { CommandItem } from './CommandItem';\nimport type { EmoticonItemProps } from './EmoticonItem';\nimport { EmoticonItem } from './EmoticonItem';\nimport type { SuggestionListItemComponentProps } from './SuggestionListItem';\nimport { SuggestionListItem as DefaultSuggestionListItem } from './SuggestionListItem';\nimport type { UserItemProps } from './UserItem';\nimport { UserItem } from './UserItem';\nimport { useComponentContext } from '../../../context/ComponentContext';\nimport { useMessageComposerContext } from '../../../context/MessageComposerContext';\nimport { useStateStore } from '../../../store';\nimport { getTextareaCaretRect } from '../../../utils/getTextareaCaretRect';\nimport type { ContextMenuItemComponent, ContextMenuItemProps } from '../../Dialog';\nimport { ContextMenu } from '../../Dialog';\nimport { usePopoverPosition } from '../../Dialog/hooks/usePopoverPosition';\nimport { InfiniteScrollPaginator } from '../../InfiniteScrollPaginator/InfiniteScrollPaginator';\nimport {\n  useMessageComposerCommands,\n  useMessageComposerController,\n} from '../../MessageComposer/hooks';\nimport { useTranslationContext } from '../../../context';\nimport type {\n  SearchSourceState,\n  TextComposerState,\n  TextComposerSuggestion,\n} from 'stream-chat';\nimport {\n  CommandsMenuClassName,\n  CommandsMenuHeader,\n} from '../../MessageComposer/AttachmentSelector/CommandsMenu';\n\ntype SuggestionTrigger = '/' | ':' | '@' | string;\n\nexport type SuggestionListProps = Partial<{\n  suggestionItemComponents: Record<\n    SuggestionTrigger,\n    React.ComponentType<SuggestionListItemComponentProps>\n  >;\n  className?: string;\n  closeOnClickOutside?: boolean;\n  containerClassName?: string;\n  focusedItemIndex: number;\n  setFocusedItemIndex: (index: number) => void;\n}>;\n\nconst textComposerStateSelector = ({ selection, suggestions }: TextComposerState) => ({\n  selection,\n  suggestions,\n});\n\nconst searchSourceStateSelector = (\n  nextValue: SearchSourceState<TextComposerSuggestion>,\n): { items: TextComposerSuggestion[] } => ({\n  items: nextValue.items ?? [],\n});\n\nexport const defaultComponents: Record<\n  SuggestionTrigger,\n  React.ComponentType<SuggestionListItemComponentProps>\n> = {\n  '/': (props: SuggestionListItemComponentProps) => (\n    <CommandItem {...props} entity={props.entity as CommandItemProps['entity']} />\n  ),\n  ':': (props: SuggestionListItemComponentProps) => (\n    <EmoticonItem {...props} entity={props.entity as EmoticonItemProps['entity']} />\n  ),\n  '@': (props: SuggestionListItemComponentProps) => (\n    <UserItem {...props} entity={props.entity as UserItemProps['entity']} />\n  ),\n} as const;\n\nexport const SuggestionList = ({\n  className,\n  closeOnClickOutside = true,\n  containerClassName,\n  focusedItemIndex,\n  setFocusedItemIndex,\n  suggestionItemComponents = defaultComponents,\n}: SuggestionListProps) => {\n  const { t } = useTranslationContext();\n  const {\n    AutocompleteSuggestionItem = DefaultSuggestionListItem,\n    ContextMenu: ContextMenuComponent = ContextMenu,\n  } = useComponentContext();\n  const { textareaRef } = useMessageComposerContext();\n  const messageComposer = useMessageComposerController();\n  const commands = useMessageComposerCommands();\n  const { textComposer } = messageComposer;\n  const { selection, suggestions } = useStateStore(\n    textComposer.state,\n    textComposerStateSelector,\n  );\n  const { items } =\n    useStateStore(suggestions?.searchSource.state, searchSourceStateSelector) ?? {};\n  const hasEnabledCommandSuggestions = useMemo(\n    () =>\n      suggestions?.searchSource.type !== 'commands' ||\n      commands.some(({ enabled }) => enabled),\n    [commands, suggestions?.searchSource.type],\n  );\n\n  const [container, setContainer] = useState<HTMLDivElement | null>(null);\n  const caretRectRef = useRef<DOMRect | null>(null);\n  const virtualCaretReference = useMemo<VirtualElement>(\n    () => ({\n      getBoundingClientRect: () => caretRectRef.current ?? new DOMRect(),\n    }),\n    [],\n  );\n\n  const { refs, strategy, update, x, y } = usePopoverPosition({\n    allowFlip: false,\n    offset: 8,\n    placement: 'top-start',\n    // For top placements, the cross-axis is X; we need this to allow flipping the list to the right when it overflows the right edge.\n    shiftOptions: { crossAxis: true },\n  });\n\n  const component = suggestions?.trigger\n    ? suggestionItemComponents[suggestions?.trigger]\n    : undefined;\n\n  const contextMenuItems = useMemo<ContextMenuItemComponent[]>(() => {\n    if (!component) return [];\n    const sortedItems =\n      suggestions?.searchSource.type === 'commands'\n        ? [...(items ?? [])].sort((a, b) =>\n            String((a as { name?: string }).name ?? '').localeCompare(\n              String((b as { name?: string }).name ?? ''),\n            ),\n          )\n        : (items ?? []);\n    return sortedItems.map((item, i) => {\n      const Item: ContextMenuItemComponent = ({ ...props }: ContextMenuItemProps) => (\n        <AutocompleteSuggestionItem\n          {...props}\n          component={component}\n          focused={focusedItemIndex === i}\n          item={item}\n          key={item.id.toString()}\n          onMouseEnter={() => setFocusedItemIndex?.(i)}\n        />\n      );\n      return Item;\n    });\n  }, [\n    items,\n    component,\n    focusedItemIndex,\n    setFocusedItemIndex,\n    AutocompleteSuggestionItem,\n    suggestions?.searchSource.type,\n  ]);\n\n  const ItemsWrapper = useCallback(\n    ({ children }: React.ComponentProps<'div'>) => (\n      <InfiniteScrollPaginator\n        loadNextOnScrollToBottom={suggestions?.searchSource.search}\n        threshold={100}\n      >\n        {children}\n      </InfiniteScrollPaginator>\n    ),\n    [suggestions?.searchSource.search],\n  );\n\n  useEffect(() => {\n    if (!closeOnClickOutside || !suggestions || !container) return;\n    const handleClick = (event: MouseEvent) => {\n      if (container.contains(event.target as Node)) return;\n      textComposer.closeSuggestions();\n    };\n    document.addEventListener('click', handleClick);\n    return () => {\n      document.removeEventListener('click', handleClick);\n    };\n  }, [closeOnClickOutside, suggestions, container, textComposer]);\n\n  useEffect(() => {\n    refs.setFloating(container);\n  }, [container, refs]);\n\n  useLayoutEffect(() => {\n    if (!suggestions || !update) return;\n    const updatePosition = () => {\n      const rect = getTextareaCaretRect(textareaRef.current ?? null, selection?.end);\n      if (!rect) {\n        caretRectRef.current = null;\n        refs.setReference(null);\n        return;\n      }\n      caretRectRef.current = rect;\n      virtualCaretReference.contextElement = textareaRef.current ?? undefined;\n      refs.setReference(virtualCaretReference);\n      update();\n    };\n\n    updatePosition();\n  }, [\n    container,\n    items?.length,\n    refs,\n    selection?.end,\n    suggestions,\n    textareaRef,\n    update,\n    virtualCaretReference,\n  ]);\n\n  if (!suggestions || !items?.length || !component || !hasEnabledCommandSuggestions)\n    return null;\n\n  const suggestionMenuLabel =\n    suggestions.searchSource.type === 'commands'\n      ? t('aria/Command Suggestions')\n      : suggestions.searchSource.type === 'emojis'\n        ? t('aria/Emoji Suggestions')\n        : suggestions.searchSource.type === 'mentions'\n          ? t('aria/User Suggestions')\n          : t('aria/Suggestions');\n\n  return (\n    <div\n      className={clsx('str-chat__suggestion-list-container', containerClassName)}\n      ref={setContainer}\n      style={{\n        left: x ?? 0,\n        position: strategy,\n        top: y ?? 0,\n        visibility: x == null || y == null ? 'hidden' : undefined,\n        zIndex: 1000,\n      }}\n    >\n      <ContextMenuComponent\n        aria-label={suggestionMenuLabel}\n        className={clsx('str-chat__suggestion-list', className)}\n        Header={\n          suggestions.searchSource.type === 'commands' ? CommandsMenuHeader : undefined\n        }\n        items={contextMenuItems}\n        ItemsWrapper={ItemsWrapper}\n        menuClassName={\n          suggestions.searchSource.type === 'commands' ? CommandsMenuClassName : undefined\n        }\n      />\n    </div>\n  );\n};\n","import { useMemo } from 'react';\nimport type { TextComposerState } from 'stream-chat';\nimport { useMessageComposerContext, useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { useCooldownRemaining } from '../../MessageComposer/hooks/useCooldownRemaining';\nimport { useMessageComposerController } from '../../MessageComposer/hooks/useMessageComposerController';\n\ntype UseTextareaPlaceholderProps = {\n  placeholder?: string;\n};\n\nconst textComposerStateSelector = ({ command }: TextComposerState) => ({ command });\n\nexport const useTextareaPlaceholder = ({\n  placeholder,\n}: UseTextareaPlaceholderProps = {}) => {\n  const { t } = useTranslationContext();\n  const { additionalTextareaProps } = useMessageComposerContext();\n  const cooldownRemaining = useCooldownRemaining();\n  const messageComposer = useMessageComposerController();\n  const { command } = useStateStore(\n    messageComposer.textComposer.state,\n    textComposerStateSelector,\n  );\n\n  const knownArgsTranslations = useMemo<Record<string, string>>(\n    () => ({\n      ban: t('ban-command-args'),\n      giphy: t('giphy-command-args'),\n      mute: t('mute-command-args'),\n      unban: t('unban-command-args'),\n      unmute: t('unmute-command-args'),\n    }),\n    [t],\n  );\n\n  const commandArgs =\n    command?.args && (knownArgsTranslations[command.name ?? ''] ?? t(command.args));\n  const commandPlaceholder =\n    command?.name === 'giphy' ? t('Search GIFs') : (commandArgs ?? undefined);\n\n  const defaultPlaceholder =\n    placeholder ?? additionalTextareaProps?.placeholder ?? t('Send a message');\n\n  if (cooldownRemaining) {\n    return t('Slow mode, wait {{ seconds }}s...', { seconds: cooldownRemaining });\n  }\n\n  return commandPlaceholder ?? defaultPlaceholder;\n};\n","import clsx from 'clsx';\nimport React, {\n  type ChangeEventHandler,\n  type SyntheticEvent,\n  type TextareaHTMLAttributes,\n  type UIEventHandler,\n  useCallback,\n  useEffect,\n  useLayoutEffect,\n  useRef,\n  useState,\n} from 'react';\nimport Textarea from 'react-textarea-autosize';\nimport { useCooldownRemaining } from '../MessageComposer/hooks/useCooldownRemaining';\nimport { useMessageComposerController } from '../MessageComposer/hooks/useMessageComposerController';\nimport type {\n  AttachmentManagerState,\n  MessageComposerConfig,\n  MessageComposerState,\n  SearchSourceState,\n  TextComposerState,\n} from 'stream-chat';\nimport { useComponentContext, useMessageComposerContext } from '../../context';\nimport { useStateStore } from '../../store';\nimport { SuggestionList as DefaultSuggestionList } from './SuggestionList';\nimport { useTextareaPlaceholder } from './hooks/useTextareaPlaceholder';\n\nconst textComposerStateSelector = (state: TextComposerState) => ({\n  selection: state.selection,\n  suggestions: state.suggestions,\n  text: state.text,\n});\n\nconst searchSourceStateSelector = (state: SearchSourceState) => ({\n  isLoadingItems: state.isLoading,\n  items: state.items,\n});\n\nconst configStateSelector = (state: MessageComposerConfig) => ({\n  enabled: state.text.enabled,\n});\n\nconst messageComposerStateSelector = (state: MessageComposerState) => ({\n  quotedMessage: state.quotedMessage,\n});\n\nconst attachmentManagerStateSelector = (state: AttachmentManagerState) => ({\n  attachments: state.attachments,\n});\n\n/**\n * isComposing prevents double submissions in Korean and other languages.\n * starting point for a read:\n * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/isComposing\n * In the long term, the fix should happen by handling keypress, but changing this has unknown implications.\n */\nconst defaultShouldSubmit = (event: React.KeyboardEvent<HTMLTextAreaElement>) =>\n  event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing;\n\nexport const shouldBackspaceExitCommandMode = (text: string) => text.length === 0;\n\nexport type TextareaComposerProps = Omit<\n  TextareaHTMLAttributes<HTMLTextAreaElement>,\n  'style' | 'defaultValue' | 'disabled' | 'value'\n> & {\n  closeSuggestionsOnClickOutside?: boolean;\n  containerClassName?: string;\n  listClassName?: string;\n  maxRows?: number;\n  minRows?: number;\n  shouldSubmit?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => boolean;\n};\n\nexport const TextareaComposer = ({\n  className,\n  closeSuggestionsOnClickOutside,\n  containerClassName,\n  listClassName,\n  maxRows: maxRowsProp,\n  minRows: minRowsProp,\n  onBlur,\n  onChange,\n  onKeyDown,\n  onScroll,\n  onSelect,\n  placeholder: placeholderProp,\n  shouldSubmit: shouldSubmitProp,\n  ...restTextareaProps\n}: TextareaComposerProps) => {\n  const { AutocompleteSuggestionList = DefaultSuggestionList } = useComponentContext();\n  const {\n    additionalTextareaProps,\n    focus,\n    handleSubmit,\n    maxRows: maxRowsContext,\n    minRows: minRowsContext,\n    onPaste,\n    shouldSubmit: shouldSubmitContext,\n    textareaRef,\n  } = useMessageComposerContext();\n  const cooldownRemaining = useCooldownRemaining();\n\n  const placeholder = useTextareaPlaceholder({ placeholder: placeholderProp });\n\n  const maxRows = maxRowsProp ?? maxRowsContext ?? 10;\n  const minRows = minRowsProp ?? minRowsContext;\n\n  const shouldSubmit = shouldSubmitProp ?? shouldSubmitContext ?? defaultShouldSubmit;\n\n  const messageComposer = useMessageComposerController();\n  const { textComposer } = messageComposer;\n  const { selection, suggestions, text } = useStateStore(\n    textComposer.state,\n    textComposerStateSelector,\n  );\n  // react-textarea-autosize can measure placeholder content as multi-line in narrow layouts,\n  // producing an inflated initial height (e.g. 2 rows) before the user types.\n  // Clamp to a single row only while empty unless the integrator explicitly set minRows.\n  const autosizeRows = !text && minRows == null ? 1 : undefined;\n  const textareaStyle = text\n    ? undefined\n    : ({\n        overflow: 'hidden',\n        textOverflow: 'ellipsis',\n        whiteSpace: 'nowrap',\n      } satisfies React.CSSProperties);\n\n  const { enabled } = useStateStore(messageComposer.configState, configStateSelector);\n  const { quotedMessage } = useStateStore(\n    messageComposer.state,\n    messageComposerStateSelector,\n  );\n  const { attachments } = useStateStore(\n    messageComposer.attachmentManager.state,\n    attachmentManagerStateSelector,\n  );\n\n  const { isLoadingItems } =\n    useStateStore(suggestions?.searchSource.state, searchSourceStateSelector) ?? {};\n\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [focusedItemIndex, setFocusedItemIndex] = useState(0);\n\n  const [isComposing, setIsComposing] = useState(false);\n\n  const changeHandler: ChangeEventHandler<HTMLTextAreaElement> = useCallback(\n    (e) => {\n      if (onChange) {\n        onChange(e);\n        return;\n      }\n      if (!textareaRef.current) return;\n      textComposer.handleChange({\n        selection: {\n          end: textareaRef.current.selectionEnd,\n          start: textareaRef.current.selectionStart,\n        },\n        text: e.target.value,\n      });\n    },\n    [onChange, textComposer, textareaRef],\n  );\n\n  const onCompositionEnd = useCallback(() => {\n    setIsComposing(false);\n  }, []);\n\n  const onCompositionStart = useCallback(() => {\n    setIsComposing(true);\n  }, []);\n\n  const keyDownHandler = useCallback(\n    (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n      if (onKeyDown) {\n        onKeyDown(event);\n        return;\n      }\n\n      // use the textarea value directly as the composer state is a step behind\n      const textareaValue = textareaRef.current?.value ?? event.currentTarget.value;\n\n      if (\n        textComposer.suggestions &&\n        textComposer.suggestions.searchSource.items?.length\n      ) {\n        if (event.key === 'Escape') return textComposer.closeSuggestions();\n        const loadedItems = textComposer.suggestions.searchSource.items;\n        if (event.key === 'Enter') {\n          event.preventDefault();\n          textComposer.handleSelect(loadedItems[focusedItemIndex]);\n        }\n        if (event.key === 'ArrowUp') {\n          event.preventDefault();\n          setFocusedItemIndex((prev) => {\n            let nextIndex = prev - 1;\n            if (suggestions?.searchSource.hasNext) {\n              nextIndex = prev;\n            } else if (nextIndex < 0) {\n              nextIndex = loadedItems.length - 1;\n            }\n            return nextIndex;\n          });\n        }\n        if (event.key === 'ArrowDown') {\n          event.preventDefault();\n          setFocusedItemIndex((prev) => {\n            let nextIndex = prev + 1;\n            if (suggestions?.searchSource.hasNext) {\n              nextIndex = prev;\n            } else if (nextIndex >= loadedItems.length) {\n              nextIndex = 0;\n            }\n\n            return nextIndex;\n          });\n        }\n      } else if (\n        textComposer.command &&\n        (event.key === 'Escape' ||\n          (event.key === 'Backspace' && shouldBackspaceExitCommandMode(textareaValue)))\n      ) {\n        event.preventDefault();\n        textComposer.clearCommand();\n      } else if (\n        shouldSubmit(event) &&\n        textareaRef.current &&\n        messageComposer.hasSendableData\n      ) {\n        if (event.key === 'Enter') {\n          // prevent adding newline when submitting a message with\n          event.preventDefault();\n        }\n        handleSubmit();\n      }\n    },\n    [\n      focusedItemIndex,\n      handleSubmit,\n      messageComposer,\n      onKeyDown,\n      shouldSubmit,\n      suggestions,\n      textComposer,\n      textareaRef,\n    ],\n  );\n\n  const scrollHandler: UIEventHandler<HTMLTextAreaElement> = useCallback(\n    (event) => {\n      if (onScroll) {\n        onScroll(event);\n      } else {\n        textComposer.closeSuggestions();\n      }\n    },\n    [onScroll, textComposer],\n  );\n\n  const setSelection = useCallback(\n    (e: SyntheticEvent<HTMLTextAreaElement>) => {\n      onSelect?.(e);\n      textComposer.setSelection({\n        end: (e.target as HTMLTextAreaElement).selectionEnd,\n        start: (e.target as HTMLTextAreaElement).selectionStart,\n      });\n    },\n    [onSelect, textComposer],\n  );\n\n  useEffect(() => {\n    if (textComposer.suggestions) {\n      setFocusedItemIndex(0);\n    }\n  }, [textComposer.suggestions]);\n\n  useEffect(() => {\n    const textareaIsFocused = textareaRef.current?.matches(':focus');\n    if (!textareaRef.current || textareaIsFocused || !focus) return;\n    textareaRef.current.focus();\n  }, [attachments, focus, quotedMessage, textareaRef]);\n\n  useLayoutEffect(() => {\n    /**\n     * It is important to perform set text and after that the range\n     * to prevent cursor reset to the end of the textarea if doing it in separate effects.\n     */\n    const textarea = textareaRef.current;\n    if (!textarea || isComposing) return;\n\n    /**\n     * The textarea value has to be overridden outside the render cycle so that the events like compositionend can be triggered.\n     * If we have overridden the value during the component rendering, the compositionend event would not be triggered, and\n     * it would not be possible to type composed characters (ô).\n     * On the other hand, just removing the value override via prop (value={text}) would not allow us to change the text based on\n     * middleware results (e.g. replace characters with emojis)\n     */\n    if (textarea.value !== text) {\n      textarea.value = text;\n    }\n\n    const length = textarea.value.length;\n    const start = Math.max(0, Math.min(selection.start, length));\n    const end = Math.max(start, Math.min(selection.end, length));\n\n    if (textarea.selectionStart === start && textarea.selectionEnd === end) return;\n\n    textarea.setSelectionRange(start, end, 'forward');\n  }, [text, selection.start, selection.end, isComposing, textareaRef]);\n\n  return (\n    <div\n      className={clsx('rta', 'str-chat__textarea', containerClassName, {\n        ['rta--loading']: isLoadingItems,\n      })}\n      ref={containerRef}\n    >\n      <Textarea\n        {...{ ...additionalTextareaProps, ...restTextareaProps }}\n        aria-label={placeholder}\n        className={clsx(\n          'rta__textarea',\n          'str-chat__textarea__textarea str-chat__message-textarea',\n          className,\n        )}\n        data-testid='message-input'\n        disabled={!enabled || !!cooldownRemaining}\n        maxRows={autosizeRows ?? maxRows}\n        minRows={autosizeRows ?? minRows}\n        onBlur={onBlur}\n        onChange={changeHandler}\n        onCompositionEnd={onCompositionEnd}\n        onCompositionStart={onCompositionStart}\n        onKeyDown={keyDownHandler}\n        onPaste={onPaste}\n        onScroll={scrollHandler}\n        onSelect={setSelection}\n        placeholder={placeholder}\n        ref={(ref) => {\n          textareaRef.current = ref;\n        }}\n        style={textareaStyle}\n      />\n      {/* todo: X document the layout change for the accessibility purpose (tabIndex) */}\n      {!isComposing && (\n        <AutocompleteSuggestionList\n          className={listClassName}\n          closeOnClickOutside={closeSuggestionsOnClickOutside}\n          focusedItemIndex={focusedItemIndex}\n          setFocusedItemIndex={setFocusedItemIndex}\n        />\n      )}\n    </div>\n  );\n};\n","import type { CSSProperties, ElementType, PropsWithChildren } from 'react';\nimport React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react';\nimport { useDropzone } from 'react-dropzone';\nimport clsx from 'clsx';\nimport type { MessageComposerConfig } from 'stream-chat';\n\nimport { useMessageComposerContext, useTranslationContext } from '../../context';\nimport { useAttachmentManagerState, useMessageComposerController } from './hooks';\nimport { useStateStore } from '../../store';\nimport { useIsCooldownActive } from './hooks/useIsCooldownActive';\nimport { IconUpload } from '../Icons';\n\nconst DragAndDropUploadContext = React.createContext<{\n  subscribeToDrop: ((fn: (files: File[]) => void) => () => void) | null;\n}>({\n  subscribeToDrop: null,\n});\n\nexport const useDragAndDropUploadContext = () => useContext(DragAndDropUploadContext);\n\n/**\n * @private This hook should be used only once directly in the `MessageComposerProvider` to\n * register `uploadNewFiles` functions of the rendered message composers. Each `MessageComposer`\n * will then be notified when the drop event occurs from within the `WithDragAndDropUpload`\n * component.\n */\nexport const useRegisterDropHandlers = () => {\n  const { subscribeToDrop } = useDragAndDropUploadContext();\n\n  const messageComposer = useMessageComposerController();\n\n  useEffect(() => {\n    const unsubscribe = subscribeToDrop?.(messageComposer.attachmentManager.uploadFiles);\n\n    return unsubscribe;\n  }, [subscribeToDrop, messageComposer]);\n};\n\nconst attachmentManagerConfigStateSelector = (state: MessageComposerConfig) => ({\n  acceptedFiles: state.attachments.acceptedFiles,\n  multipleUploads: state.attachments.maxNumberOfFilesPerMessage > 1,\n});\n\n/**\n * Wrapper to replace now deprecated `Channel.dragAndDropWindow` option.\n *\n * @example\n * ```tsx\n * <Channel>\n *  <WithDragAndDropUpload component=\"section\" className=\"message-list-dnd-wrapper\">\n *    <Window>\n *      <MessageList />\n *      <MessageComposer />\n *    </Window>\n *  </WithDragAndDropUpload>\n *  <Thread />\n * <Channel>\n * ```\n */\nexport const WithDragAndDropUpload = ({\n  children,\n  className,\n  component: Component = 'div',\n  style,\n}: PropsWithChildren<{\n  acceptedFiles?: string[];\n  /**\n   * @description An element to render as a wrapper onto which drag & drop functionality will be applied.\n   * @default 'div'\n   */\n  component?: ElementType;\n  className?: string;\n  style?: CSSProperties;\n}>) => {\n  const dropHandlersRef = useRef<Set<(f: File[]) => void>>(new Set());\n  const messageComposerContext = useMessageComposerContext();\n  const dragAndDropUploadContext = useDragAndDropUploadContext();\n  const messageComposer = useMessageComposerController();\n  const { isUploadEnabled } = useAttachmentManagerState();\n  const { acceptedFiles, multipleUploads } = useStateStore(\n    messageComposer.configState,\n    attachmentManagerConfigStateSelector,\n  );\n\n  const isCooldownActive = useIsCooldownActive();\n  // if message composer context is available, there's no need to use the queue\n  const isWithinMessageComposerContext = Object.keys(messageComposerContext).length > 0;\n\n  const accept = useMemo(\n    () =>\n      acceptedFiles.reduce<Record<string, Array<string>>>((mediaTypeMap, mediaType) => {\n        mediaTypeMap[mediaType] ??= [];\n        return mediaTypeMap;\n      }, {}),\n    [acceptedFiles],\n  );\n\n  const subscribeToDrop = useCallback((fn: (files: File[]) => void) => {\n    dropHandlersRef.current.add(fn);\n\n    return () => {\n      dropHandlersRef.current.delete(fn);\n    };\n  }, []);\n\n  const handleDrop = useCallback((files: File[]) => {\n    dropHandlersRef.current.forEach((fn) => fn(files));\n  }, []);\n\n  const {\n    getRootProps,\n    isDragActive,\n    isDragReject: isDragRejected,\n  } = useDropzone({\n    accept,\n    // apply `disabled` rules if available, otherwise allow anything and\n    // let the `uploadNewFiles` handle the limitations internally\n    disabled: isWithinMessageComposerContext\n      ? !isUploadEnabled || isCooldownActive\n      : false,\n    multiple: multipleUploads,\n    noClick: true,\n    noKeyboard: true,\n    onDrop: isWithinMessageComposerContext\n      ? messageComposer.attachmentManager.uploadFiles\n      : handleDrop,\n  });\n\n  // nested WithDragAndDropUpload components render wrappers without functionality\n  // (MessageComposerUI has a default WithDragAndDropUpload)\n  if (dragAndDropUploadContext.subscribeToDrop !== null) {\n    return <Component className={className}>{children}</Component>;\n  }\n\n  const rootClassName = clsx('str-chat__dropzone-root', className);\n\n  return (\n    <DragAndDropUploadContext.Provider value={{ subscribeToDrop }}>\n      <Component {...getRootProps({ className: rootClassName, style })}>\n        {isDragActive && (\n          <div\n            className={clsx('str-chat__dropzone-container', {\n              'str-chat__dropzone-container--not-accepted': isDragRejected,\n            })}\n            role='presentation'\n          >\n            <FileDragAndDropContent isDragRejected={isDragRejected} />\n          </div>\n        )}\n        {children}\n      </Component>\n    </DragAndDropUploadContext.Provider>\n  );\n};\n\nexport type FileDragAndDropContentProps = {\n  isDragRejected: boolean;\n};\n\nexport const FileDragAndDropContent = ({\n  isDragRejected,\n}: FileDragAndDropContentProps) => {\n  const { t } = useTranslationContext();\n  return (\n    <div className='str-chat__dropzone-container__content'>\n      {isDragRejected ? (\n        <p>{t('Some of the files will not be accepted')}</p>\n      ) : (\n        <>\n          <IconUpload />\n          <p>{t('Drag your files here')}</p>\n        </>\n      )}\n    </div>\n  );\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../context';\n\nexport type StopAIGenerationButtonProps = React.ComponentProps<'button'>;\n\nexport const StopAIGenerationButton = ({\n  onClick,\n  ...restProps\n}: StopAIGenerationButtonProps) => {\n  const { t } = useTranslationContext();\n  return (\n    <button\n      aria-label={t('aria/Stop AI Generation')}\n      className='str-chat__stop-ai-generation-button'\n      data-testid='stop-ai-generation-button'\n      onClick={onClick}\n      {...restProps}\n    />\n  );\n};\n","import React from 'react';\nimport { useMessageComposerHasSendableData } from './hooks';\nimport { useTranslationContext } from '../../context';\nimport { IconSend } from '../Icons';\nimport { Button } from '../Button';\n\nexport type SendButtonProps = {\n  sendMessage: (event: React.BaseSyntheticEvent) => void;\n} & React.ComponentProps<'button'>;\n\nexport const SendButton = ({ children, sendMessage, ...rest }: SendButtonProps) => {\n  const { t } = useTranslationContext();\n  const hasSendableData = useMessageComposerHasSendableData();\n  return (\n    <Button\n      appearance='solid'\n      aria-label={t('aria/Send')}\n      circular\n      className='str-chat__send-button'\n      data-testid='send-button'\n      disabled={!hasSendableData}\n      onClick={sendMessage}\n      size='sm'\n      variant='primary'\n      {...rest}\n    >\n      {children ?? <IconSend />}\n    </Button>\n  );\n};\n","import React, { useCallback } from 'react';\nimport { StopAIGenerationButton as DefaultStopAIGenerationButton } from './StopAIGenerationButton';\nimport { CooldownTimer as DefaultCooldownTimer } from './CooldownTimer';\nimport { SendButton as DefaultSendButton } from './SendButton';\nimport {\n  useChannelStateContext,\n  useComponentContext,\n  useMessageComposerContext,\n} from '../../context';\nimport { AIStates, useAIState } from '../AIStateIndicator';\nimport { useMessageComposerController, useMessageContentIsEmpty } from './hooks';\nimport { AudioRecordingButtonWithNotification } from '../MediaRecorder/AudioRecorder/AudioRecordingButtonWithNotification';\nimport { useIsCooldownActive } from './hooks/useIsCooldownActive';\nimport type { MessageComposerState, TextComposerState } from 'stream-chat';\nimport { useStateStore } from '../../store';\nimport { IconCheckmark, IconSend } from '../Icons';\n\nconst messageComposerStateSelector = ({ editedMessage }: MessageComposerState) => ({\n  editedMessage,\n});\n\nconst textComposerStateSelector = ({ command, text }: TextComposerState) => ({\n  command,\n  text,\n});\n\nexport const MessageComposerActions = () => {\n  const { channel } = useChannelStateContext();\n  const { hideSendButton } = useMessageComposerContext();\n  const messageComposer = useMessageComposerController();\n  const {\n    CooldownTimer = DefaultCooldownTimer,\n    SendButton,\n    StopAIGenerationButton: StopAIGenerationButtonOverride,\n  } = useComponentContext();\n\n  const { editedMessage } = useStateStore(\n    messageComposer.state,\n    messageComposerStateSelector,\n  );\n\n  const { command } = useStateStore(\n    messageComposer.textComposer.state,\n    textComposerStateSelector,\n  );\n\n  const contentIsEmpty = useMessageContentIsEmpty();\n  /**\n   * This bit here is needed to make sure that we can get rid of the default behaviour\n   * if need be. Essentially, this allows us to pass StopAIGenerationButton={null} and\n   * completely circumvent the default logic if it's not what we want. We need it as a\n   * prop because there is no other trivial way to override the SendMessage button otherwise.\n   */\n  const StopAIGenerationButton =\n    StopAIGenerationButtonOverride === undefined\n      ? DefaultStopAIGenerationButton\n      : StopAIGenerationButtonOverride;\n\n  const { handleSubmit, recordingController } = useMessageComposerContext();\n  const isCooldownActive = useIsCooldownActive();\n\n  const { aiState } = useAIState(channel);\n  const stopGenerating = useCallback(() => channel?.stopAIResponse(), [channel]);\n  const shouldDisplayStopAIGeneration =\n    [AIStates.Thinking, AIStates.Generating].includes(aiState) &&\n    !!StopAIGenerationButton;\n\n  const recordingEnabled = !!(recordingController.recorder && navigator.mediaDevices); // account for requirement on iOS as per this bug report: https://bugs.webkit.org/show_bug.cgi?id=252303\n\n  let content = SendButton ? (\n    <SendButton sendMessage={handleSubmit} />\n  ) : (\n    <DefaultSendButton sendMessage={handleSubmit}>\n      {editedMessage || command ? <IconCheckmark /> : <IconSend />}\n    </DefaultSendButton>\n  );\n\n  if (shouldDisplayStopAIGeneration) {\n    content = <StopAIGenerationButton onClick={stopGenerating} />;\n  } else if (hideSendButton) return null;\n\n  if (isCooldownActive) {\n    content = <CooldownTimer />;\n  } else if (contentIsEmpty && !editedMessage && !command && recordingEnabled) {\n    content = <AudioRecordingButtonWithNotification />;\n  }\n\n  return <div className='str-chat__message-composer__actions'>{content}</div>;\n};\n\nexport const AdditionalMessageComposerActions = () => {\n  const { EmojiPicker } = useComponentContext();\n  const isCooldownActive = useIsCooldownActive();\n\n  return (\n    <div className='str-chat__message-composer__additional-actions'>\n      {!isCooldownActive && EmojiPicker ? <EmojiPicker /> : null}\n    </div>\n  );\n};\n","import type { LiveLocationPreview, StaticLocationPreview } from 'stream-chat';\nimport type { ComponentType } from 'react';\nimport React from 'react';\nimport { useTranslationContext } from '../../../context';\nimport { IconLocation } from '../../Icons';\nimport { RemoveAttachmentPreviewButton } from '../RemoveAttachmentPreviewButton';\n\ntype GeolocationPreviewImageProps = {\n  location: StaticLocationPreview | LiveLocationPreview;\n};\n\nconst GeolocationPreviewImage = () => (\n  <div className='str-chat__location-preview-image'>\n    <IconLocation />\n  </div>\n);\n\nexport type GeolocationPreviewProps = {\n  location: StaticLocationPreview | LiveLocationPreview;\n  PreviewImage?: ComponentType<GeolocationPreviewImageProps>;\n  remove?: () => void;\n};\n\nexport const GeolocationPreview = ({\n  location,\n  PreviewImage = GeolocationPreviewImage,\n  remove,\n}: GeolocationPreviewProps) => {\n  const { t } = useTranslationContext();\n  const shareDuration = (location as LiveLocationPreview).durationMs;\n  const title = shareDuration ? t('Live location') : t('Current location');\n\n  return (\n    <div className='str-chat__location-preview' data-testid='location-preview'>\n      <PreviewImage location={location} />\n      <div className='str-chat__location-preview__data'>\n        <div\n          className='str-chat__location-preview__data__title'\n          title={t('Shared location')}\n        >\n          {title}\n        </div>\n        <div className='str-chat__location-preview__data__subtitle'>\n          {t('Location: {{ coordinates }}', {\n            coordinates: `${location.latitude}, ${location.longitude}`,\n          })}\n        </div>\n        {shareDuration && (\n          <div className='str-chat__location-preview__data__sharing-duration'>\n            {t('Live for {{duration}}', {\n              duration: t('duration/Share Location', {\n                milliseconds: shareDuration,\n              }),\n            })}\n          </div>\n        )}\n      </div>\n      {remove && (\n        <RemoveAttachmentPreviewButton\n          aria-label={t('aria/Remove location attachment')}\n          className='str-chat__attachment-preview__remove-button'\n          data-testid='location-preview-item-delete-button'\n          onClick={remove}\n        />\n      )}\n    </div>\n  );\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nimport {\n  AttachmentSelector as DefaultAttachmentSelector,\n  SimpleAttachmentSelector,\n} from './AttachmentSelector/AttachmentSelector';\nimport {\n  AttachmentPreviewList as DefaultAttachmentPreviewList,\n  VoiceRecordingPreviewSlot as DefaultVoiceRecordingPreviewSlot,\n} from './AttachmentPreviewList';\nimport { AudioRecorder as DefaultAudioRecorder } from '../MediaRecorder';\nimport { EditedMessagePreview as DefaultEditedMessagePreview } from './EditedMessagePreview';\nimport { QuotedMessagePreview as DefaultQuotedMessagePreview } from './QuotedMessagePreview';\nimport { LinkPreviewList as DefaultLinkPreviewList } from './LinkPreviewList';\nimport { SendToChannelCheckbox as DefaultSendToChannelCheckbox } from './SendToChannelCheckbox';\nimport { TextareaComposer as DefaultTextareaComposer } from '../TextareaComposer';\nimport { useMessageComposerContext as useMessageComposerContext } from '../../context/MessageComposerContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useMessageContext } from '../../context';\nimport { restorePreEditSnapshot } from './preEditSnapshot';\nimport { WithDragAndDropUpload } from './WithDragAndDropUpload';\nimport {\n  AdditionalMessageComposerActions as DefaultAdditionalMessageComposerActions,\n  MessageComposerActions,\n} from './MessageComposerActions';\nimport { useMessageComposerController } from './hooks';\nimport { useStateStore } from '../../store';\nimport {\n  type AttachmentManagerState,\n  LinkPreviewsManager,\n  type LinkPreviewsManagerState,\n  type LocationComposerState,\n  type MessageComposerState,\n  type TextComposerState,\n} from 'stream-chat';\nimport { CommandChip as DefaultCommandChip } from './CommandChip';\nimport { GeolocationPreview } from './AttachmentPreviewList/GeolocationPreview';\n\nconst messageComposerStateSelector = ({\n  editedMessage,\n  quotedMessage,\n}: MessageComposerState) => ({\n  editedMessage,\n  quotedMessage,\n});\n\nconst attachmentManagerStateSelector = (state: AttachmentManagerState) => ({\n  attachments: state.attachments,\n});\n\nconst linkPreviewsManagerStateSelector = (state: LinkPreviewsManagerState) => ({\n  linkPreviews: Array.from(state.previews.values()).filter(\n    (preview) =>\n      LinkPreviewsManager.previewIsLoaded(preview) ||\n      LinkPreviewsManager.previewIsLoading(preview),\n  ),\n});\n\nconst locationComposerStateSelector = (state: LocationComposerState) => ({\n  location: state.location,\n});\n\nconst textComposerCommandSelector = ({ command }: TextComposerState) => ({ command });\n\nconst MessageComposerPreviews = () => {\n  const {\n    AttachmentPreviewList = DefaultAttachmentPreviewList,\n    EditedMessagePreview = DefaultEditedMessagePreview,\n    LinkPreviewList = DefaultLinkPreviewList,\n    QuotedMessagePreview = DefaultQuotedMessagePreview,\n    VoiceRecordingPreviewSlot = DefaultVoiceRecordingPreviewSlot,\n  } = useComponentContext();\n\n  const messageComposer = useMessageComposerController();\n  const { editedMessage, quotedMessage } = useStateStore(\n    messageComposer.state,\n    messageComposerStateSelector,\n  );\n\n  const { attachments } = useStateStore(\n    messageComposer.attachmentManager.state,\n    attachmentManagerStateSelector,\n  );\n\n  const { location } = useStateStore(\n    messageComposer.locationComposer.state,\n    locationComposerStateSelector,\n  );\n\n  const { linkPreviewsManager } = messageComposer;\n  const { linkPreviews } = useStateStore(\n    linkPreviewsManager.state,\n    linkPreviewsManagerStateSelector,\n  );\n\n  if (\n    !quotedMessage &&\n    attachments.length === 0 &&\n    linkPreviews.length === 0 &&\n    !location &&\n    !editedMessage\n  )\n    return null;\n\n  // todo: pass the entity arrays from here so that the preview lists do not have to subscribe to the composer state changes too?\n  return (\n    <div className='str-chat__message-composer-previews'>\n      {editedMessage ? (\n        <div className='str-chat__message-composer-previews'>\n          <EditedMessagePreview\n            message={editedMessage}\n            onCancel={() => {\n              restorePreEditSnapshot(messageComposer);\n            }}\n          />\n        </div>\n      ) : (\n        <QuotedMessagePreview />\n      )}\n      <VoiceRecordingPreviewSlot />\n      <AttachmentPreviewList />\n      <LinkPreviewList />\n      {location && (\n        <GeolocationPreview\n          location={location}\n          // It is not possible to nullify shared_location field so we do not show a preview when editing\n          // to prevent a user from wanting to remove the location\n          remove={\n            messageComposer.editedMessage\n              ? undefined\n              : messageComposer.locationComposer.initState\n          }\n        />\n      )}\n    </div>\n  );\n};\n\nexport const MessageComposerUI = () => {\n  const { message } = useMessageContext();\n  const { recordingController } = useMessageComposerContext();\n  const messageComposerController = useMessageComposerController();\n  const { command } = useStateStore(\n    messageComposerController.textComposer.state,\n    textComposerCommandSelector,\n  );\n\n  const {\n    AdditionalMessageComposerActions = DefaultAdditionalMessageComposerActions,\n    AttachmentSelector = message ? SimpleAttachmentSelector : DefaultAttachmentSelector,\n    AudioRecorder = DefaultAudioRecorder,\n    CommandChip = DefaultCommandChip,\n    SendToChannelCheckbox = DefaultSendToChannelCheckbox,\n    TextareaComposer = DefaultTextareaComposer,\n  } = useComponentContext();\n\n  return (\n    <WithDragAndDropUpload\n      className='str-chat__message-composer-container'\n      component='div'\n    >\n      <div\n        className={clsx('str-chat__message-composer', {\n          'str-chat__message-composer--command-active': !!command,\n        })}\n      >\n        {recordingController.recordingState ? (\n          <AudioRecorder />\n        ) : (\n          <>\n            <AttachmentSelector />\n            <div className='str-chat__message-composer-compose-area'>\n              <MessageComposerPreviews />\n              <div className='str-chat__message-composer-controls'>\n                <div className='str-chat__message-composer-controls__text-composition-controls'>\n                  <div className='str-chat__message-composer-controls__text-composition-controls__text'>\n                    {command && (\n                      <div className='str-chat__message-composer-controls__text-composition-controls__command-chip-container'>\n                        <CommandChip command={command} />\n                      </div>\n                    )}\n                    <TextareaComposer />\n                  </div>\n                  <SendToChannelCheckbox />\n                </div>\n                <AdditionalMessageComposerActions />\n                <MessageComposerActions />\n              </div>\n            </div>\n          </>\n        )}\n      </div>\n    </WithDragAndDropUpload>\n  );\n};\n","import { useMemo } from 'react';\n\nimport type { MessageComposerContextValue } from '../../../context/MessageComposerContext';\n\nexport const useCreateMessageComposerContext = (value: MessageComposerContextValue) => {\n  const {\n    additionalTextareaProps,\n    asyncMessagesMultiSendEnabled,\n    audioRecordingEnabled,\n    emojiSearchIndex,\n    focus,\n    handleSubmit,\n    hideSendButton,\n    maxRows,\n    minRows,\n    onPaste,\n    parent,\n    recordingController,\n    shouldSubmit,\n    textareaRef,\n  } = value;\n\n  const parentId = parent?.id;\n\n  const messageComposerContext: MessageComposerContextValue = useMemo(\n    () => ({\n      additionalTextareaProps,\n      asyncMessagesMultiSendEnabled,\n      audioRecordingEnabled,\n      emojiSearchIndex,\n      focus,\n      handleSubmit,\n      hideSendButton,\n      maxRows,\n      minRows,\n      onPaste,\n      parent,\n      recordingController,\n      shouldSubmit,\n      textareaRef,\n    }),\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [\n      asyncMessagesMultiSendEnabled,\n      audioRecordingEnabled,\n      emojiSearchIndex,\n      handleSubmit,\n      hideSendButton,\n      minRows,\n      parentId,\n      recordingController,\n    ],\n  );\n\n  return messageComposerContext;\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { useEffect } from 'react';\n\nimport { MessageComposerUI as DefaultMessageComposerUI } from './MessageComposerUI';\nimport { useMessageComposerController } from './hooks';\nimport { useCreateMessageComposerContext } from './hooks/useCreateMessageComposerContext';\nimport { useMessageComposerBindings } from './hooks/useMessageComposerBindings';\nimport type { ComponentContextValue } from '../../context/ComponentContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { MessageComposerContextProvider } from '../../context/MessageComposerContext';\nimport { DialogManagerProvider } from '../../context';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nimport type { LocalMessage, Message, SendMessageOptions } from 'stream-chat';\n\nimport type { CustomAudioRecordingConfig } from '../MediaRecorder';\nimport { useRegisterDropHandlers } from './WithDragAndDropUpload';\n\nexport type EmojiSearchIndexResult = {\n  id: string;\n  name: string;\n  skins: Array<{ native: string }>;\n  emoticons?: Array<string>;\n  native?: string;\n};\n\nexport interface EmojiSearchIndex {\n  search: (\n    query: string,\n  ) => PromiseLike<Array<EmojiSearchIndexResult>> | Array<EmojiSearchIndexResult> | null;\n}\n\nexport type MessageComposerProps = {\n  /**\n   * Additional props to be passed to the underlying `AutoCompleteTextarea` component.\n   * Default value is handled via MessageComposer.\n   * [Available props](https://www.npmjs.com/package/react-textarea-autosize)\n   */\n  additionalTextareaProps?: Omit<\n    React.TextareaHTMLAttributes<HTMLTextAreaElement>,\n    'defaultValue' | 'style' | 'disabled' | 'value'\n  >;\n  /**\n   * When enabled, recorded messages won’t be sent immediately.\n   * Instead, they will “stack up” with other attachments in the message composer allowing the user to send multiple attachments as part of the same message.\n   */\n  asyncMessagesMultiSendEnabled?: boolean;\n  /** Allows to configure the audio recording parameters for voice messages. */\n  audioRecordingConfig?: CustomAudioRecordingConfig;\n  /** Controls whether the users will be provided with the UI to record voice messages. */\n  audioRecordingEnabled?: boolean;\n  /** Mechanism to be used with autocomplete and text replace features of the `MessageComposer` component, see [emoji-mart `SearchIndex`](https://github.com/missive/emoji-mart#%EF%B8%8F%EF%B8%8F-headless-search) */\n  emojiSearchIndex?: ComponentContextValue['emojiSearchIndex'];\n  /** If true, focuses the text input on component mount */\n  focus?: boolean;\n  // todo: what sense does hideSendButton prop make, when we have message composer actions (recording, send msg). Can we remove it?\n  // /** Allows to hide MessageComposer's send button. */\n  hideSendButton?: boolean;\n  /** Max number of rows the underlying `textarea` component is allowed to grow */\n  maxRows?: number;\n  /** Min number of rows the underlying `textarea` will start with. The `grow` on MessageComposer prop has to be enabled for `minRows` to take effect. */\n  minRows?: number;\n  /** Function to override the default message sending process. Not message updating process. */\n  overrideSubmitHandler?: (params: {\n    cid: string;\n    localMessage: LocalMessage;\n    message: Message;\n    sendOptions: SendMessageOptions;\n  }) => Promise<void> | void;\n  /** When replying in a thread, the parent message object */\n  parent?: LocalMessage;\n  /**\n   * Currently, `Enter` is the default submission key and  `Shift`+`Enter` is the default combination for the new line.\n   * If specified, this function overrides the default behavior specified previously.\n   *\n   * Example of default behavior:\n   * ```tsx\n   * const defaultShouldSubmit = (event) => event.key === \"Enter\" && !event.shiftKey;\n   * ```\n   */\n  shouldSubmit?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => boolean;\n};\n\nconst MessageComposerProvider = (props: PropsWithChildren<MessageComposerProps>) => {\n  const messageComposerBindings = useMessageComposerBindings(props);\n  const { emojiSearchIndex } = useComponentContext('MessageComposer');\n\n  const messageComposerContextValue = useCreateMessageComposerContext({\n    ...messageComposerBindings,\n    ...props,\n    emojiSearchIndex: props.emojiSearchIndex ?? emojiSearchIndex,\n  });\n\n  const messageComposer = useMessageComposerController();\n\n  useEffect(\n    () => () => {\n      messageComposer.createDraft().finally(() => messageComposer.clear());\n    },\n    [messageComposer],\n  );\n\n  useEffect(() => {\n    const threadId = messageComposer.threadId;\n    if (\n      !threadId ||\n      !messageComposer.channel ||\n      !messageComposer.contentIsEmpty ||\n      !messageComposer.config.drafts.enabled\n    )\n      return;\n    // get draft data for legacy thead composer\n    messageComposer.channel\n      .getDraft({ parent_id: threadId })\n      .then(({ draft }) => {\n        if (draft) {\n          messageComposer.initState({ composition: draft });\n        }\n      })\n      .catch(console.error);\n  }, [messageComposer]);\n\n  useRegisterDropHandlers();\n\n  return (\n    <MessageComposerContextProvider value={messageComposerContextValue}>\n      {props.children}\n    </MessageComposerContextProvider>\n  );\n};\n\nconst UnMemoizedMessageComposer = (props: MessageComposerProps) => {\n  const { MessageComposerUI = DefaultMessageComposerUI } =\n    useComponentContext('MessageComposer');\n  const messageComposer = useMessageComposerController();\n  const id = useStableId();\n\n  const dialogManagerId = messageComposer.threadId\n    ? `message-input-dialog-manager-thread-${id}`\n    : `message-input-dialog-manager-${id}`;\n\n  return (\n    <DialogManagerProvider id={dialogManagerId}>\n      <MessageComposerProvider {...props}>\n        <MessageComposerUI />\n      </MessageComposerProvider>\n    </DialogManagerProvider>\n  );\n};\n\n/**\n * A high level component that has provides all functionality to the Input it renders.\n */\nexport const MessageComposer = React.memo(\n  UnMemoizedMessageComposer,\n) as typeof UnMemoizedMessageComposer;\n","import type { ReactNode } from 'react';\nimport React from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport type { Channel, PollVote } from 'stream-chat';\n\nimport type { ChatContextValue } from '../../context';\nimport { getTranslatedMessageText } from '../../context/MessageTranslationViewContext';\nimport type { TranslationContextValue } from '../../context/TranslationContext';\nimport type { PluggableList } from 'unified';\nimport { htmlToTextPlugin, imageToLink, plusPlusToEmphasis } from '../Message';\nimport { isMessageDeleted } from '../Message/utils';\nimport remarkGfm from 'remark-gfm';\n\nconst remarkPlugins: PluggableList = [\n  htmlToTextPlugin,\n  [remarkGfm, { singleTilde: false }],\n  plusPlusToEmphasis,\n  imageToLink,\n];\n\nexport const renderPreviewText = (text: string) => (\n  <ReactMarkdown remarkPlugins={remarkPlugins} skipHtml>\n    {text}\n  </ReactMarkdown>\n);\n\nconst getLatestPollVote = (latestVotesByOption: Record<string, PollVote[]>) => {\n  let latestVote: PollVote | undefined;\n  for (const optionVotes of Object.values(latestVotesByOption)) {\n    optionVotes.forEach((vote) => {\n      if (latestVote && new Date(latestVote.updated_at) >= new Date(vote.created_at))\n        return;\n      latestVote = vote;\n    });\n  }\n\n  return latestVote;\n};\n\nexport const getLatestMessagePreview = (\n  channel: Channel,\n  t: TranslationContextValue['t'],\n  userLanguage: TranslationContextValue['userLanguage'] = 'en',\n  isMessageAIGenerated?: ChatContextValue['isMessageAIGenerated'],\n): ReactNode => {\n  const latestMessage =\n    channel.state.latestMessages[channel.state.latestMessages.length - 1];\n\n  const previewTextToRender =\n    getTranslatedMessageText({ language: userLanguage, message: latestMessage }) ||\n    latestMessage?.text;\n  const poll = latestMessage?.poll;\n\n  if (!latestMessage) {\n    return t('Nothing yet...');\n  }\n\n  if (isMessageDeleted(latestMessage)) {\n    return t('Message deleted');\n  }\n\n  if (poll) {\n    if (!poll.vote_count) {\n      const createdBy =\n        poll.created_by?.id === channel.getClient().userID\n          ? t('You')\n          : (poll.created_by?.name ?? t('Poll'));\n      return t('📊 {{createdBy}} created: {{ pollName}}', {\n        createdBy,\n        pollName: poll.name,\n      });\n    } else {\n      const latestVote = getLatestPollVote(\n        poll.latest_votes_by_option as Record<string, PollVote[]>,\n      );\n      const option =\n        latestVote && poll.options.find((opt) => opt.id === latestVote.option_id);\n\n      if (option && latestVote) {\n        return t('📊 {{votedBy}} voted: {{pollOptionText}}', {\n          pollOptionText: option.text,\n          votedBy:\n            latestVote?.user?.id === channel.getClient().userID\n              ? t('You')\n              : (latestVote.user?.name ?? t('Poll')),\n        });\n      }\n    }\n  }\n\n  if (previewTextToRender) {\n    return isMessageAIGenerated?.(latestMessage)\n      ? previewTextToRender\n      : renderPreviewText(previewTextToRender);\n  }\n\n  if (latestMessage.command) {\n    return `/${latestMessage.command}`;\n  }\n\n  if (latestMessage.attachments?.length) {\n    return t('🏙 Attachment...');\n  }\n\n  if (latestMessage.shared_location) {\n    return t('📍Shared location');\n  }\n\n  return t('Empty message...');\n};\n\nexport type GroupChannelDisplayInfoMember = {\n  imageUrl?: string;\n  userName?: string;\n};\n\nexport type GroupChannelDisplayInfo = {\n  members: GroupChannelDisplayInfoMember[];\n  /** When members.length > 4, count for the \"+N\" badge (members.length - 2). */\n  overflowCount?: number;\n};\n\n/**\n * Channel display image: channel.data.image, or for DM (2 members) the other member's user.image.\n */\nexport const getChannelDisplayImage = (\n  channel: Channel,\n  currentUserId?: string,\n): string | undefined => {\n  const data = channel.data as { image?: string } | undefined;\n  if (data?.image && typeof data.image === 'string') return data.image;\n\n  const memberList = Object.values(channel.state.members);\n  if (memberList.length === 2) {\n    const other = memberList.find((m) => m.user?.id !== currentUserId);\n    const image = other?.user?.image;\n    if (image && typeof image === 'string') return image;\n  }\n  return undefined;\n};\n\nexport const getGroupChannelDisplayInfo = (\n  channel: Channel,\n): GroupChannelDisplayInfo | undefined => {\n  const members = Object.values(channel.state.members);\n  if (members.length <= 2) return;\n\n  const memberList: GroupChannelDisplayInfoMember[] = [];\n  for (const member of members) {\n    const { user } = member;\n    if (!user?.name && !user?.image) continue;\n    memberList.push({ imageUrl: user.image, userName: user.name });\n  }\n  return {\n    members: memberList,\n  };\n};\n","import { useEffect, useState } from 'react';\nimport type { Channel } from 'stream-chat';\n\nimport { useChatContext } from '../../../context';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\n/**\n * 1. channel.data.name\n * 2. DM (exactly 2 members): other member's name, then directMessageLabel\n * 3. Group (3+ members): comma-separated list of 2 other members' names (no ellipsis)\n * 4. undefined otherwise\n */\nfunction computeChannelDisplayName(\n  channel: Channel,\n  directMessageLabel: string,\n  currentUserId: string | undefined,\n): string | undefined {\n  const data = channel.data as { name?: string } | undefined;\n  if (data?.name && typeof data.name === 'string') return data.name;\n\n  const memberList = Object.values(channel.state.members);\n  const otherMembers = memberList.filter((m) => m.user?.id !== currentUserId);\n\n  if (memberList.length === 2 && otherMembers.length === 1) {\n    const name = otherMembers[0].user?.name;\n    return name || directMessageLabel;\n  }\n  if (otherMembers.length >= 2) {\n    const names = otherMembers\n      .map((m) => m.user?.name)\n      .filter(Boolean)\n      .slice(0, 2) as string[];\n    if (names.length > 0) return names.join(', ');\n  }\n  return undefined;\n}\n\n/**\n * Channel display name with translation context.\n * 1. channel.data.name\n * 2. DM (exactly 2 members): other member's name, then translated \"Direct message\"\n * 3. Group (3+ members): comma-separated list of 2 other members' names (no ellipsis)\n * 4. undefined otherwise\n */\nexport const useChannelDisplayName = (\n  channel: Channel | undefined,\n): string | undefined => {\n  const { client } = useChatContext('useChannelDisplayName');\n  const { t } = useTranslationContext('useChannelDisplayName');\n  const directMessageLabel = t('Direct message');\n\n  const [displayName, setDisplayName] = useState<string | undefined>(() =>\n    channel\n      ? computeChannelDisplayName(channel, directMessageLabel, client.userID ?? undefined)\n      : undefined,\n  );\n\n  useEffect(() => {\n    if (!channel) {\n      setDisplayName(undefined);\n      return;\n    }\n    const updateDisplayName = () =>\n      setDisplayName(\n        computeChannelDisplayName(\n          channel,\n          directMessageLabel,\n          client.userID ?? undefined,\n        ),\n      );\n    updateDisplayName();\n    client.on('user.updated', updateDisplayName);\n    return () => {\n      client.off('user.updated', updateDisplayName);\n    };\n  }, [channel, channel?.data, client, directMessageLabel]);\n\n  return displayName;\n};\n","import { useEffect, useMemo, useState } from 'react';\nimport type { Channel } from 'stream-chat';\n\nimport { useChatContext } from '../../../context';\nimport {\n  getChannelDisplayImage,\n  getGroupChannelDisplayInfo,\n  type GroupChannelDisplayInfo,\n} from '../utils';\nimport { useChannelDisplayName } from './useChannelDisplayName';\n\nconst emptyGroupInfo: GroupChannelDisplayInfo = {\n  members: [],\n  overflowCount: undefined,\n};\n\nexport type ChannelPreviewInfoParams = {\n  /** Channel to read display info from; when undefined, returns undefined display title/image */\n  channel?: Channel;\n  /** Manually set the image to render, defaults to the Channel image */\n  overrideImage?: string;\n  /** Set title manually */\n  overrideTitle?: string;\n};\n\nexport const useChannelPreviewInfo = (props: ChannelPreviewInfoParams) => {\n  const { channel, overrideImage, overrideTitle } = props;\n  const { client } = useChatContext();\n\n  const channelDisplayName = useChannelDisplayName(channel);\n  const displayTitle = overrideTitle ?? channelDisplayName;\n\n  const [displayImage, setDisplayImage] = useState<string | undefined>(() =>\n    channel\n      ? (overrideImage ?? getChannelDisplayImage(channel, client.userID ?? undefined))\n      : undefined,\n  );\n  const [groupChannelDisplayInfo, setGroupChannelDisplayInfo] =\n    useState<GroupChannelDisplayInfo>(() =>\n      channel ? (getGroupChannelDisplayInfo(channel) ?? emptyGroupInfo) : emptyGroupInfo,\n    );\n\n  useEffect(() => {\n    if (!channel) return;\n    if (overrideImage) return;\n\n    const updateInfo = () => {\n      setDisplayImage(getChannelDisplayImage(channel, client.userID ?? undefined));\n      setGroupChannelDisplayInfo(getGroupChannelDisplayInfo(channel) ?? emptyGroupInfo);\n    };\n\n    updateInfo();\n    client.on('user.updated', updateInfo);\n    return () => {\n      client.off('user.updated', updateInfo);\n    };\n  }, [channel, channel?.data, client, overrideImage]);\n\n  return useMemo(\n    () => ({\n      displayImage: overrideImage ?? displayImage,\n      displayTitle,\n      groupChannelDisplayInfo,\n    }),\n    [displayImage, displayTitle, groupChannelDisplayInfo, overrideImage],\n  );\n};\n","import React from 'react';\n\n/** Three dots for typing indicator; fill and opacity animation come from TypingIndicator.scss (--chat-text-typing-indicator). */\nexport const TypingIndicatorDots = () => (\n  <svg\n    aria-hidden\n    fill='none'\n    height='5'\n    viewBox='0 0 23 5'\n    width='23'\n    xmlns='http://www.w3.org/2000/svg'\n  >\n    <circle cx='2.5' cy='2.5' r='2.5' />\n    <circle cx='11.5' cy='2.5' r='2.5' />\n    <circle cx='20.5' cy='2.5' r='2.5' />\n  </svg>\n);\n","import { useEffect, useMemo, useRef, useState } from 'react';\n\nconst DEFAULT_HIDE_DELAY_MS = 2000;\n\nexport type TypingEntry = {\n  user?: { id?: string; name?: string; image?: string };\n  parent_id?: string;\n};\n\n/**\n * Derive a stable key from typing users so that the effect only runs when the\n * actual set of users (by id) changes, not on every render due to new array\n * references.\n *\n * Important: callers must pass entries where `user` is an object with an `id`\n * field (not a plain string). If `user?.id` is undefined for every entry the\n * key degenerates to an empty string, the memo returns a new array each time\n * it is \"invalidated\" by React, and `setDisplayUsers` in the effect below will\n * loop infinitely because it always receives a fresh reference.\n */\nconst useStableTypingUsers = (typingUsers: readonly TypingEntry[]) => {\n  const key = typingUsers\n    .map((entry) => entry.user?.id ?? '')\n    .sort()\n    .join(',');\n\n  // eslint-disable-next-line react-hooks/exhaustive-deps\n  return useMemo(() => [...typingUsers], [key]);\n};\n\n/**\n * Debounces hiding the typing indicator: when typing users go to zero, keep showing for delayMs\n * to avoid flicker when typing stops and starts again quickly. Returns the list to display\n * (current typers or last non-empty list during the debounce period). Show the indicator\n * when displayUsers.length > 0.\n */\nexport function useDebouncedTypingActive(\n  typingUsers: readonly TypingEntry[],\n  delayMs: number = DEFAULT_HIDE_DELAY_MS,\n): { displayUsers: TypingEntry[] } {\n  const stableTypingUsers = useStableTypingUsers(typingUsers);\n  const [displayUsers, setDisplayUsers] = useState<TypingEntry[]>([]);\n  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const hadTypersRef = useRef(false);\n\n  useEffect(() => {\n    if (stableTypingUsers.length > 0) {\n      if (timerRef.current) {\n        clearTimeout(timerRef.current);\n        timerRef.current = null;\n      }\n      hadTypersRef.current = true;\n      setDisplayUsers(stableTypingUsers);\n      return;\n    }\n\n    if (stableTypingUsers.length === 0 && hadTypersRef.current && !timerRef.current) {\n      timerRef.current = setTimeout(() => {\n        timerRef.current = null;\n        hadTypersRef.current = false;\n        setDisplayUsers([]);\n      }, delayMs);\n    }\n  }, [stableTypingUsers, delayMs]);\n\n  useEffect(\n    () => () => {\n      if (timerRef.current) clearTimeout(timerRef.current);\n    },\n    [],\n  );\n\n  return { displayUsers };\n}\n","import type { TypingEntry } from '../hooks/useDebouncedTypingActive';\n\ntype TranslationFunction = (\n  key: string,\n  options?: Record<string, number | string>,\n) => string;\n\n/**\n * Build a localized typing-status message for screen-reader and inline indicator text.\n */\nexport const getTypingStatusMessage = (\n  displayUsers: readonly TypingEntry[],\n  t: TranslationFunction,\n) => {\n  const namedUsers = displayUsers\n    .map(({ user }) => user?.name?.trim() || user?.id || '')\n    .filter(Boolean);\n  const count = displayUsers.length;\n\n  if (count === 1 && namedUsers.length === 1) {\n    return t('{{ typing }} is typing', { typing: namedUsers[0] });\n  }\n\n  if (count === 2 && namedUsers.length === 2) {\n    return t('{{ typing }} are typing', {\n      typing: `${namedUsers[0]} and ${namedUsers[1]}`,\n    });\n  }\n\n  return t('{{ count }} people are typing', { count });\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nimport { TypingIndicatorDots } from './TypingIndicatorDots';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useTypingContext } from '../../context/TypingContext';\nimport { useThreadContext } from '../Threads';\n\nimport { useDebouncedTypingActive } from './hooks/useDebouncedTypingActive';\nimport { getTypingStatusMessage } from './utils/getTypingStatusMessage';\n\nexport type TypingIndicatorHeaderProps = {\n  /** When true, show typing in the current thread only; when false, show typing in the channel. */\n  threadList?: boolean;\n};\n\n/**\n * Inline typing indicator for ChannelHeader or ThreadHeader: text (1/2/3+ people) followed by animated dots.\n * Only shows other participants; respects channelConfig.typing_events.\n */\nexport const TypingIndicatorHeader = (props: TypingIndicatorHeaderProps) => {\n  const { threadList = false } = props;\n\n  const { t } = useTranslationContext();\n  const { channelConfig, thread } = useChannelStateContext('TypingIndicatorHeader');\n  const threadInstance = useThreadContext();\n  const parentId = threadInstance?.id ?? thread?.id;\n  const { client } = useChatContext('TypingIndicatorHeader');\n  const { typing = {} } = useTypingContext('TypingIndicatorHeader');\n\n  const typingInChannel = !threadList\n    ? Object.values(typing).filter(\n        ({ parent_id, user }) => user?.id !== client.user?.id && !parent_id,\n      )\n    : [];\n\n  const typingInThread = threadList\n    ? Object.values(typing).filter(\n        ({ parent_id, user }) => user?.id !== client.user?.id && parent_id === parentId,\n      )\n    : [];\n\n  const typingUsers = threadList ? typingInThread : typingInChannel;\n  const { displayUsers } = useDebouncedTypingActive(typingUsers);\n  const label = getTypingStatusMessage(displayUsers, t);\n\n  if (channelConfig?.typing_events === false || displayUsers.length === 0) {\n    return null;\n  }\n\n  return (\n    <span\n      className={clsx('str-chat__typing-indicator-header', {\n        'str-chat__typing-indicator-header--thread': threadList,\n      })}\n      data-testid='typing-indicator-header'\n    >\n      <span className='str-chat__typing-indicator-header__text'>{label}</span>\n      <span className='str-chat__typing-indicator__dots str-chat__typing-indicator-header__dots'>\n        <TypingIndicatorDots />\n      </span>\n    </span>\n  );\n};\n","import React from 'react';\n\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useStateStore } from '../../store';\nimport { useChannelPreviewInfo } from '../ChannelListItem/hooks/useChannelPreviewInfo';\nimport { TypingIndicatorHeader } from '../TypingIndicator/TypingIndicatorHeader';\nimport { useThreadContext } from '../Threads';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useTypingContext } from '../../context/TypingContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ThreadState } from 'stream-chat';\nimport { Button } from '../Button';\nimport { IconXmark } from '../Icons';\nimport { useChatViewContext } from '../ChatView';\n\nconst threadStateSelector = ({ replyCount }: ThreadState) => ({ replyCount });\n\n/** Fallback when channel has no display title: parent message author (name only). */\nconst displayNameFromParentMessage = (message: LocalMessage): string | undefined =>\n  message.user?.name ?? undefined;\n\n/** Subtitle: replyCount, threadDisplayName, defaultSubtitle (name · reply count), and when typing also TypingIndicatorHeader. */\nconst ThreadHeaderSubtitle = ({\n  replyCount,\n  threadDisplayName,\n  threadList,\n}: {\n  replyCount: number | undefined;\n  threadDisplayName: string | undefined;\n  threadList: boolean;\n}) => {\n  const { t } = useTranslationContext();\n  const { channelConfig, thread } = useChannelStateContext('ThreadHeaderSubtitle');\n  const threadInstance = useThreadContext();\n  const parentId = threadInstance?.id ?? thread?.id;\n  const { client } = useChatContext('ThreadHeaderSubtitle');\n  const { typing = {} } = useTypingContext('ThreadHeaderSubtitle');\n  const typingInThread = Object.values(typing).filter(\n    ({ parent_id, user }) => user?.id !== client.user?.id && parent_id === parentId,\n  );\n  const hasTyping = channelConfig?.typing_events !== false && typingInThread.length > 0;\n  const replyCountText = t('replyCount', { count: replyCount ?? 0 });\n  const defaultSubtitle = threadDisplayName\n    ? `${threadDisplayName} · ${replyCountText}`\n    : replyCountText;\n  return (\n    <div className='str-chat__thread-header-subtitle'>\n      <span\n        className='str-chat__subtitle-content-transition'\n        key={hasTyping ? 'typing' : 'default'}\n      >\n        {hasTyping ? (\n          <TypingIndicatorHeader threadList={threadList} />\n        ) : (\n          <>{defaultSubtitle}</>\n        )}\n      </span>\n    </div>\n  );\n};\n\nexport type ThreadHeaderProps = {\n  /** Callback for closing the thread */\n  closeThread: (event?: React.BaseSyntheticEvent) => void;\n  /** The thread parent message */\n  thread: LocalMessage;\n  /** Override the thread display title */\n  overrideTitle?: string;\n};\n\nexport const ThreadHeader = (props: ThreadHeaderProps) => {\n  const { closeThread, overrideTitle, thread } = props;\n\n  const { t } = useTranslationContext();\n  const { channel } = useChannelStateContext();\n  const { HeaderStartContent } = useComponentContext();\n  const { activeChatView } = useChatViewContext();\n  const { displayTitle: channelDisplayTitle } = useChannelPreviewInfo({ channel });\n\n  const threadInstance = useThreadContext();\n  const { replyCount: replyCountThreadInstance } =\n    useStateStore(threadInstance?.state, threadStateSelector) ?? {};\n\n  const replyCount = threadInstance\n    ? replyCountThreadInstance\n    : thread\n      ? (thread.reply_count ?? 0)\n      : 0;\n\n  // Subtitle: channel display title (from parent or hook), with override and fallback to parent message author\n  const threadDisplayName =\n    overrideTitle ??\n    channelDisplayTitle ??\n    displayNameFromParentMessage(thread) ??\n    undefined;\n\n  return (\n    <div className='str-chat__thread-header'>\n      <div className='str-chat__thread-header__start'>\n        {activeChatView === 'threads' && HeaderStartContent && <HeaderStartContent />}\n      </div>\n      <div className='str-chat__thread-header-details'>\n        <div className='str-chat__thread-header-title'>{t('Thread')}</div>\n        <ThreadHeaderSubtitle\n          replyCount={replyCount}\n          threadDisplayName={threadDisplayName}\n          threadList\n        />\n      </div>\n      {!threadInstance && (\n        <div className='str-chat__thread-header__end'>\n          <Button\n            appearance='ghost'\n            aria-label={t('aria/Close thread')}\n            circular\n            className='str-chat__close-thread-button'\n            data-testid='close-thread-button'\n            onClick={closeThread}\n            size='md'\n            variant='secondary'\n          >\n            <IconXmark />\n          </Button>\n        </div>\n      )}\n    </div>\n  );\n};\n","import React from 'react';\n\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useThreadContext } from '../Threads';\nimport { useStateStore } from '../../store';\nimport type { ThreadState } from 'stream-chat';\n\nconst threadStateSelector = ({ replyCount }: ThreadState) => ({\n  replyCount,\n});\n\nexport const ThreadStart = () => {\n  const { thread } = useChannelStateContext('ThreadStart');\n  const { t } = useTranslationContext('ThreadStart');\n  const threadInstance = useThreadContext();\n  const { replyCount: replyCountThreadInstance } =\n    useStateStore(threadInstance?.state, threadStateSelector) ?? {};\n\n  const replyCount = threadInstance\n    ? replyCountThreadInstance\n    : thread\n      ? (thread.reply_count ?? 0)\n      : 0;\n\n  if (!replyCount) return null;\n\n  return (\n    <div className='str-chat__thread-start'>{t('replyCount', { count: replyCount })}</div>\n  );\n};\n","import clsx from 'clsx';\nimport React from 'react';\n\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { getDateString } from '../../i18n/utils';\n\nimport type { TimestampFormatterOptions } from '../../i18n/types';\n\nexport type DateSeparatorProps = TimestampFormatterOptions & {\n  /** Optional className for the root element */\n  className?: string;\n  /** The date to format */\n  date: Date;\n  /** When true, applies floating positioning (fixed at top when scrolling) */\n  floating?: boolean;\n  /** Override the default formatting of the date. This is a function that has access to the original date object. */\n  formatDate?: (date: Date) => string;\n  // todo: position and unread are not necessary anymore\n  /** Set the position of the date in the separator, options are 'left', 'center', 'right', @default right */\n  position?: 'left' | 'center' | 'right';\n  /** If following messages are not new */\n  unread?: boolean;\n};\n\nconst UnMemoizedDateSeparator = (props: DateSeparatorProps) => {\n  const {\n    calendar,\n    className,\n    date: messageCreatedAt,\n    floating,\n    formatDate,\n    ...restTimestampFormatterOptions\n  } = props;\n\n  const { t, tDateTimeParser } = useTranslationContext('DateSeparator');\n\n  const formattedDate = getDateString({\n    calendar,\n    ...restTimestampFormatterOptions,\n    formatDate,\n    messageCreatedAt,\n    t,\n    tDateTimeParser,\n    timestampTranslationKey: 'timestamp/DateSeparator',\n  });\n\n  return (\n    <div\n      className={clsx(\n        'str-chat__date-separator',\n        { 'str-chat__date-separator--floating': floating },\n        className,\n      )}\n      data-date={messageCreatedAt.toISOString()}\n      data-testid={floating ? 'floating-date-separator' : 'date-separator'}\n    >\n      <div className='str-chat__date-separator-date'>{formattedDate}</div>\n    </div>\n  );\n};\n\n/**\n * A simple date separator between messages.\n */\nexport const DateSeparator = React.memo(\n  UnMemoizedDateSeparator,\n) as typeof UnMemoizedDateSeparator;\n","import React from 'react';\n\nimport type { MessageProps } from '../Message';\nimport { Message } from '../Message';\nimport { ThreadStart as DefaultThreadStart } from './ThreadStart';\n\nimport { useComponentContext } from '../../context';\nimport { DateSeparator } from '../DateSeparator';\n\nexport const ThreadHead = (props: MessageProps) => {\n  const { ThreadStart = DefaultThreadStart } = useComponentContext('ThreadHead');\n  return (\n    <div className='str-chat__parent-message-li'>\n      <DateSeparator date={props.message.created_at} />\n      <Message initialMessage threadList {...props} />\n      <ThreadStart />\n    </div>\n  );\n};\n","import React, { useEffect } from 'react';\nimport clsx from 'clsx';\n\nimport { LegacyThreadContext } from './LegacyThreadContext';\nimport { MESSAGE_ACTIONS } from '../Message';\nimport type { MessageComposerProps } from '../MessageComposer';\nimport { MessageComposer } from '../MessageComposer';\nimport type { MessageListProps, VirtualizedMessageListProps } from '../MessageList';\nimport { MessageList, VirtualizedMessageList } from '../MessageList';\nimport { ThreadHeader as DefaultThreadHeader } from './ThreadHeader';\nimport { ThreadHead as DefaultThreadHead } from '../Thread/ThreadHead';\n\nimport {\n  useChannelActionContext,\n  useChannelStateContext,\n  useChatContext,\n  useComponentContext,\n} from '../../context';\nimport { useThreadContext } from '../Threads';\nimport { useStateStore } from '../../store';\n\nimport type { MessageProps, MessageUIComponentProps } from '../Message/types';\nimport type { MessageActionsArray } from '../Message/utils';\nimport type { ThreadState } from 'stream-chat';\n\nexport type ThreadProps = {\n  /** Additional props for `MessageComposer` component: [available props](https://getstream.io/chat/docs/sdk/react/message-composer-components/message_composer/#props) */\n  additionalMessageComposerProps?: MessageComposerProps;\n  /** Additional props for `MessageList` component: [available props](https://getstream.io/chat/docs/sdk/react/core-components/message_list/#props) */\n  additionalMessageListProps?: MessageListProps;\n  /** Additional props for `Message` component of the parent message: [available props](https://getstream.io/chat/docs/sdk/react/message-components/message/#props) */\n  additionalParentMessageProps?: Partial<MessageProps>;\n  /** Additional props for `VirtualizedMessageList` component: [available props](https://getstream.io/chat/docs/sdk/react/core-components/virtualized_list/#props) */\n  additionalVirtualizedMessageListProps?: VirtualizedMessageListProps;\n  /** If true, focuses the `MessageComposer` component on opening a thread */\n  autoFocus?: boolean;\n  /** Injects date separator components into `Thread`, defaults to `false`. To be passed to the underlying `MessageList` or `VirtualizedMessageList` components */\n  enableDateSeparator?: boolean;\n  /** Custom thread message UI component used to override the default `Message` value stored in `ComponentContext` */\n  Message?: React.ComponentType<MessageUIComponentProps>;\n  /** Array of allowed message actions (ex: ['edit', 'delete', 'flag', 'mute', 'pin', 'quote', 'react', 'reply']). To disable all actions, provide an empty array. */\n  messageActions?: MessageActionsArray;\n  /** If true, render the `VirtualizedMessageList` instead of the standard `MessageList` component */\n  virtualized?: boolean;\n};\n\n/**\n * The Thread component renders a parent Message with a list of replies\n */\nexport const Thread = (props: ThreadProps) => {\n  const { channel, channelConfig, thread } = useChannelStateContext('Thread');\n  const threadInstance = useThreadContext();\n\n  if (!thread && !threadInstance) return null;\n  if (channelConfig?.replies === false) return null;\n\n  // the wrapper ensures a key variable is set and the component recreates on thread switch\n  return (\n    // FIXME: TS is having trouble here as at least one of the two would always be defined\n    <ThreadInner\n      {...props}\n      key={`thread-${(thread ?? threadInstance)?.id}-${channel?.cid}`}\n    />\n  );\n};\n\nconst selector = (nextValue: ThreadState) => ({\n  isLoadingNext: nextValue.pagination.isLoadingNext,\n  isLoadingPrev: nextValue.pagination.isLoadingPrev,\n  parentMessage: nextValue.parentMessage,\n  replies: nextValue.replies,\n});\n\nconst ThreadInner = (props: ThreadProps & { key: string }) => {\n  const {\n    additionalMessageComposerProps,\n    additionalMessageListProps,\n    additionalParentMessageProps,\n    additionalVirtualizedMessageListProps,\n    autoFocus = true,\n    enableDateSeparator = false,\n    Message: PropMessage,\n    messageActions = Object.keys(MESSAGE_ACTIONS),\n    virtualized,\n  } = props;\n  const threadInstance = useThreadContext();\n\n  const {\n    thread,\n    threadHasMore,\n    threadLoadingMore,\n    threadMessages = [],\n    threadSuppressAutoscroll,\n  } = useChannelStateContext('Thread');\n  const { closeThread, loadMoreThread } = useChannelActionContext('Thread');\n  const { customClasses } = useChatContext('Thread');\n  const {\n    Message: ContextMessage,\n    ThreadHead = DefaultThreadHead,\n    ThreadHeader = DefaultThreadHeader,\n    VirtualMessage,\n  } = useComponentContext('Thread');\n\n  const { isLoadingNext, isLoadingPrev, parentMessage, replies } =\n    useStateStore(threadInstance?.state, selector) ?? {};\n\n  const ThreadMessage = PropMessage || additionalMessageListProps?.Message;\n  const FallbackMessage = virtualized && VirtualMessage ? VirtualMessage : ContextMessage;\n  const MessageUIComponent = ThreadMessage || FallbackMessage;\n\n  const ThreadMessageList = virtualized ? VirtualizedMessageList : MessageList;\n\n  useEffect(() => {\n    if (threadInstance) return;\n\n    if ((thread?.reply_count ?? 0) > 0) {\n      // FIXME: integrators can customize channel query options but cannot customize channel.getReplies() options\n      loadMoreThread();\n    }\n  }, [thread, loadMoreThread, threadInstance]);\n\n  const threadProps: Pick<\n    VirtualizedMessageListProps,\n    | 'hasMoreNewer'\n    | 'loadMoreNewer'\n    | 'loadingMoreNewer'\n    | 'hasMore'\n    | 'loadMore'\n    | 'loadingMore'\n    | 'messages'\n  > = threadInstance\n    ? {\n        loadingMore: isLoadingPrev,\n        loadingMoreNewer: isLoadingNext,\n        loadMore: threadInstance.loadPrevPage,\n        loadMoreNewer: threadInstance.loadNextPage,\n        messages: replies,\n      }\n    : {\n        hasMore: threadHasMore,\n        loadingMore: threadLoadingMore,\n        loadMore: loadMoreThread,\n        messages: threadMessages,\n      };\n\n  const messageAsThread = thread ?? parentMessage;\n\n  if (!messageAsThread) return null;\n\n  const threadClass =\n    customClasses?.thread ||\n    clsx('str-chat__thread-container str-chat__thread', {\n      'str-chat__thread--virtualized': virtualized,\n    });\n\n  const head = (\n    <ThreadHead\n      key={messageAsThread.id}\n      message={messageAsThread}\n      Message={MessageUIComponent}\n      {...additionalParentMessageProps}\n    />\n  );\n\n  return (\n    // Thread component needs a context which we can use for message composer\n    <LegacyThreadContext.Provider\n      value={{\n        legacyThread: thread ?? undefined,\n      }}\n    >\n      <div className={threadClass}>\n        <ThreadHeader closeThread={closeThread} thread={messageAsThread} />\n        <ThreadMessageList\n          disableDateSeparator={!enableDateSeparator}\n          head={head}\n          Message={MessageUIComponent}\n          messageActions={messageActions}\n          suppressAutoscroll={threadSuppressAutoscroll}\n          threadList\n          {...threadProps}\n          {...(virtualized\n            ? additionalVirtualizedMessageListProps\n            : additionalMessageListProps)}\n        />\n        <MessageComposer\n          focus={autoFocus}\n          parent={thread ?? parentMessage}\n          {...additionalMessageComposerProps}\n        />\n      </div>\n    </LegacyThreadContext.Provider>\n  );\n};\n","import React, { type ReactNode, useMemo, useState } from 'react';\nimport clsx from 'clsx';\n\nimport { useDialogOnNearestManager } from '../Dialog';\nimport { defaultReactionOptions, getHasExtendedReactions } from './reactionOptions';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useMessageContext } from '../../context/MessageContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { Button } from '../Button';\nimport { IconPlus } from '../Icons';\n\nimport type { ReactionResponse } from 'stream-chat';\n\nexport type ReactionSelectorProps = {\n  /** Override dialog id used by the selector popover. */\n  dialogId?: string;\n  /** Function that adds/removes a reaction on a message (overrides the function stored in `MessageContext`) */\n  handleReaction?: (\n    reactionType: string,\n    event: React.BaseSyntheticEvent,\n  ) => Promise<void>;\n  /** An array of the own reaction objects to distinguish own reactions visually */\n  own_reactions?: ReactionResponse[];\n};\n\ninterface ReactionSelectorInterface {\n  (props: ReactionSelectorProps): ReactNode;\n  getDialogId: (_: { messageId: string; threadList?: boolean }) => string;\n  displayName: string;\n  ExtendedList: React.ComponentType<ReactionSelectorProps & { dialogId?: string }>;\n}\n\nconst stableOwnReactions: ReactionResponse[] = [];\n\nexport const ReactionSelector: ReactionSelectorInterface = (props) => {\n  const {\n    dialogId: propDialogId,\n    handleReaction: propHandleReaction,\n    own_reactions: propOwnReactions,\n  } = props;\n  const [extendedListOpen, setExtendedListOpen] = useState(false);\n\n  const {\n    reactionOptions = defaultReactionOptions,\n    ReactionSelectorExtendedList = ReactionSelector.ExtendedList,\n  } = useComponentContext('ReactionSelector');\n\n  const {\n    closeReactionSelectorOnClick,\n    handleReaction: contextHandleReaction,\n    message,\n    threadList,\n  } = useMessageContext('ReactionSelector');\n  const { t } = useTranslationContext('ReactionSelector');\n  const dialogId =\n    propDialogId ??\n    ReactionSelector.getDialogId({\n      messageId: message.id,\n      threadList,\n    });\n  const { dialog } = useDialogOnNearestManager({ id: dialogId });\n\n  const handleReaction = propHandleReaction ?? contextHandleReaction;\n  const ownReactions = propOwnReactions ?? message?.own_reactions ?? stableOwnReactions;\n\n  const ownReactionByType = useMemo(() => {\n    const map: { [key: string]: ReactionResponse } = {};\n\n    for (const reaction of ownReactions) {\n      map[reaction.type] ??= reaction;\n    }\n\n    return map;\n  }, [ownReactions]);\n\n  const adjustedQuickReactionOptions = useMemo(() => {\n    if (Array.isArray(reactionOptions)) return reactionOptions;\n\n    return Object.entries(reactionOptions.quick).map(\n      ([type, { Component, name, unicode }]) => ({\n        Component,\n        name,\n        type,\n        unicode,\n      }),\n    );\n  }, [reactionOptions]);\n\n  const hasExtendedReactions = getHasExtendedReactions(reactionOptions);\n\n  return (\n    <div\n      aria-label={t('aria/Reaction list')}\n      className='str-chat__reaction-selector'\n      data-testid='reaction-selector'\n      role='group'\n    >\n      {!extendedListOpen ? (\n        <>\n          <ul\n            className='str-chat__reaction-selector-list'\n            data-testid='reaction-selector-list'\n          >\n            {adjustedQuickReactionOptions.map(\n              ({ Component, name: reactionName, type: reactionType }) => (\n                <li className='str-chat__reaction-list-selector__item' key={reactionType}>\n                  <button\n                    aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n                      reactionName: reactionName || reactionType,\n                    })}\n                    aria-pressed={typeof ownReactionByType[reactionType] !== 'undefined'}\n                    className={clsx('str-chat__reaction-selector-list__item-button')}\n                    data-testid='select-reaction-button'\n                    data-text={reactionType}\n                    onClick={(event) => {\n                      handleReaction(reactionType, event);\n                      if (closeReactionSelectorOnClick) {\n                        dialog.close();\n                      }\n                    }}\n                    type='button'\n                  >\n                    <span className='str-chat__reaction-icon'>\n                      <Component />\n                    </span>\n                  </button>\n                </li>\n              ),\n            )}\n          </ul>\n          {hasExtendedReactions && (\n            <Button\n              appearance='outline'\n              aria-label={t('aria/Open Reaction Selector')}\n              circular\n              className='str-chat__reaction-selector__add-button'\n              data-testid='reaction-selector-add-button'\n              onClick={() => {\n                setExtendedListOpen(true);\n              }}\n              size='sm'\n              variant='secondary'\n            >\n              <IconPlus />\n            </Button>\n          )}\n        </>\n      ) : (\n        <ReactionSelectorExtendedList\n          {...props}\n          dialogId={dialogId}\n          handleReaction={async (reactionType, event) => {\n            await handleReaction(reactionType, event);\n            if (closeReactionSelectorOnClick) {\n              dialog.close();\n            }\n          }}\n        />\n      )}\n    </div>\n  );\n};\n\nReactionSelector.getDialogId = ({ messageId, threadList }) => {\n  const dialogIdNamespace = threadList ? '-thread' : '';\n  return `reaction-selector${dialogIdNamespace}-${messageId}`;\n};\n\nReactionSelector.displayName = 'ReactionSelector';\n\nReactionSelector.ExtendedList = function ReactionSelectorExtendedList({\n  dialogId,\n  handleReaction: propHandleReaction,\n  own_reactions: propOwnReactions,\n}) {\n  const { reactionOptions = defaultReactionOptions } = useComponentContext(\n    'ReactionSelector.ExtendedList',\n  );\n  const {\n    closeReactionSelectorOnClick,\n    handleReaction: contextHandleReaction,\n    message,\n  } = useMessageContext('ReactionSelector');\n  const { t } = useTranslationContext('ReactionSelector');\n\n  const handleReaction = propHandleReaction ?? contextHandleReaction;\n  const ownReactions = propOwnReactions ?? message?.own_reactions ?? stableOwnReactions;\n\n  const { dialog } = useDialogOnNearestManager({ id: dialogId || '' });\n\n  const ownReactionByType = useMemo(() => {\n    const map: { [key: string]: ReactionResponse } = {};\n\n    for (const reaction of ownReactions) {\n      map[reaction.type] ??= reaction;\n    }\n\n    return map;\n  }, [ownReactions]);\n\n  if (Array.isArray(reactionOptions) || !reactionOptions.extended) {\n    return null;\n  }\n\n  return (\n    <div\n      aria-label={t('aria/Reaction list')}\n      className='str-chat__reaction-selector-extended-list'\n      data-testid='reaction-selector-extended-list'\n      role='group'\n    >\n      {Object.entries(reactionOptions.extended).map(\n        ([reactionType, { Component, name: reactionName }]) => (\n          <button\n            aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n              reactionName: reactionName || reactionType,\n            })}\n            aria-pressed={typeof ownReactionByType[reactionType] !== 'undefined'}\n            className='str-chat__reaction-selector-extended-list__button str-chat__button str-chat__button--ghost str-chat__button--size-sm str-chat__button--circular'\n            data-testid='select-reaction-button'\n            data-text={reactionType}\n            key={reactionType}\n            onClick={(event) => {\n              handleReaction(reactionType, event);\n              if (closeReactionSelectorOnClick) {\n                dialog.close();\n              }\n            }}\n            type='button'\n          >\n            <span className='str-chat__reaction-icon'>\n              <Component />\n            </span>\n          </button>\n        ),\n      )}\n    </div>\n  );\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport type { ReactionResponse, ReactionSort } from 'stream-chat';\nimport type { MessageContextValue } from '../../../context';\nimport { useMessageContext, useTranslationContext } from '../../../context';\nimport { useNotificationApi } from '../../Notifications';\n\nimport type { ReactionType } from '../types';\n\nexport interface FetchReactionsOptions {\n  reactionType: ReactionType | null;\n  shouldFetch: boolean;\n  handleFetchReactions?: MessageContextValue['handleFetchReactions'];\n  sort?: ReactionSort;\n}\n\nexport function useFetchReactions(options: FetchReactionsOptions) {\n  const { addNotification } = useNotificationApi();\n  const { handleFetchReactions: contextHandleFetchReactions } =\n    useMessageContext('useFetchReactions');\n  const { t } = useTranslationContext('useFetchReactions');\n  const [reactions, setReactions] = useState<ReactionResponse[]>([]);\n  const {\n    handleFetchReactions: propHandleFetchReactions,\n    reactionType,\n    shouldFetch,\n    sort,\n  } = options;\n  const [isLoading, setIsLoading] = useState(shouldFetch);\n  const handleFetchReactions = propHandleFetchReactions ?? contextHandleFetchReactions;\n  const [refetchNonce, setRefetchNonce] = useState<number | null>(null);\n\n  useEffect(() => {\n    if (!shouldFetch) {\n      return;\n    }\n\n    let cancel = false;\n\n    (async () => {\n      try {\n        setIsLoading(true);\n        const reactions = await handleFetchReactions(reactionType ?? undefined, sort);\n\n        if (!cancel) {\n          setReactions(reactions);\n        }\n      } catch (e) {\n        if (!cancel) {\n          setReactions([]);\n          addNotification({\n            emitter: 'Reactions',\n            error: e instanceof Error ? e : undefined,\n            message: t('Error fetching reactions'),\n            severity: 'error',\n            type: 'api:message:reactions:fetch:failed',\n          });\n        }\n      } finally {\n        if (!cancel) {\n          setIsLoading(false);\n        }\n      }\n    })();\n\n    return () => {\n      cancel = true;\n    };\n  }, [\n    addNotification,\n    handleFetchReactions,\n    reactionType,\n    refetchNonce,\n    shouldFetch,\n    sort,\n    t,\n  ]);\n\n  const refetch = useCallback(() => {\n    setRefetchNonce(Math.random());\n  }, []);\n\n  return { isLoading, reactions, refetch };\n}\n","import React, { useMemo, useState } from 'react';\n\nimport type { ReactionSummary, ReactionType } from './types';\n\nimport { useFetchReactions } from './hooks/useFetchReactions';\nimport { Avatar as DefaultAvatar } from '../Avatar';\nimport type { MessageContextValue } from '../../context';\nimport {\n  useChatContext,\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\nimport type { ReactionSort } from 'stream-chat';\nimport { defaultReactionOptions, getHasExtendedReactions } from './reactionOptions';\nimport type { useProcessReactions } from './hooks/useProcessReactions';\nimport { IconEmojiAdd } from '../Icons';\nimport { ReactionSelector, type ReactionSelectorProps } from './ReactionSelector';\n\nexport type MessageReactionsDetailProps = Partial<\n  Pick<MessageContextValue, 'handleFetchReactions' | 'reactionDetailsSort'>\n> & {\n  reactions: ReactionSummary[];\n  selectedReactionType: ReactionType | null;\n  onSelectedReactionTypeChange?: (reactionType: ReactionType | null) => void;\n  sort?: ReactionSort;\n  totalReactionCount?: number;\n  reactionGroups?: ReturnType<typeof useProcessReactions>['reactionGroups'];\n} & ReactionSelectorProps;\n\nconst defaultReactionDetailsSort = { created_at: -1 } as const;\n\nexport const MessageReactionsDetailLoadingIndicator = () => {\n  const elements = useMemo(\n    () =>\n      Array.from({ length: 3 }, (_, index) => (\n        <div className='str-chat__message-reactions-detail__skeleton-item' key={index}>\n          <div className='str-chat__message-reactions-detail__skeleton-avatar' />\n          <div className='str-chat__message-reactions-detail__skeleton-line' />\n        </div>\n      )),\n    [],\n  );\n\n  return <>{elements}</>;\n};\n\ninterface MessageReactionsDetailInterface {\n  (props: MessageReactionsDetailProps): React.ReactNode;\n  displayName: string;\n  getDialogId: (_: { messageId: string }) => string;\n}\n\nexport const MessageReactionsDetail: MessageReactionsDetailInterface = ({\n  handleFetchReactions,\n  handleReaction,\n  onSelectedReactionTypeChange,\n  own_reactions,\n  reactionDetailsSort: propReactionDetailsSort,\n  reactionGroups,\n  reactions,\n  selectedReactionType,\n  totalReactionCount,\n}) => {\n  const [extendedReactionListOpen, setExtendedReactionListOpen] = useState(false);\n  const { client } = useChatContext();\n  const {\n    Avatar = DefaultAvatar,\n    LoadingIndicator = MessageReactionsDetailLoadingIndicator,\n    reactionOptions = defaultReactionOptions,\n    ReactionSelectorExtendedList = ReactionSelector.ExtendedList,\n  } = useComponentContext(MessageReactionsDetail.name);\n  const { t } = useTranslationContext();\n\n  const {\n    handleReaction: contextHandleReaction,\n    message,\n    reactionDetailsSort: contextReactionDetailsSort,\n  } = useMessageContext(MessageReactionsDetail.name);\n\n  const reactionDetailsSort =\n    propReactionDetailsSort ?? contextReactionDetailsSort ?? defaultReactionDetailsSort;\n\n  const hasExtendedReactions = getHasExtendedReactions(reactionOptions);\n\n  const {\n    isLoading: areReactionsLoading,\n    reactions: reactionDetails,\n    refetch,\n  } = useFetchReactions({\n    handleFetchReactions,\n    reactionType: selectedReactionType,\n    shouldFetch: true,\n    sort: reactionDetailsSort,\n  });\n\n  const getReactionName = (reactionType: string) => {\n    if (Array.isArray(reactionOptions)) {\n      return (\n        reactionOptions.find((reactionOption) => reactionOption.type === reactionType)\n          ?.name ?? reactionType\n      );\n    }\n\n    return (\n      reactionOptions.quick[reactionType]?.name ??\n      reactionOptions.extended?.[reactionType]?.name ??\n      reactionType\n    );\n  };\n\n  if (extendedReactionListOpen) {\n    return (\n      <div\n        className='str-chat__message-reactions-detail'\n        data-testid='message-reactions-detail'\n      >\n        <ReactionSelectorExtendedList\n          dialogId={MessageReactionsDetail.getDialogId({ messageId: message.id })}\n          handleReaction={handleReaction}\n          own_reactions={own_reactions}\n        />\n      </div>\n    );\n  }\n\n  return (\n    <div\n      className='str-chat__message-reactions-detail'\n      data-testid='message-reactions-detail'\n    >\n      {typeof totalReactionCount === 'number' && (\n        <div className='str-chat__message-reactions-detail__total-count'>\n          {t('{{ count }} reactions', { count: totalReactionCount })}\n        </div>\n      )}\n      <div className='str-chat__message-reactions-detail__reaction-type-list-container'>\n        <ul\n          className='str-chat__message-reactions-detail__reaction-type-list'\n          data-testid='reaction-type-list'\n        >\n          {hasExtendedReactions && (\n            <li className='str-chat__message-reactions-detail__reaction-type-list-item'>\n              <button\n                aria-label={t('Add reaction')}\n                className='str-chat__message-reactions-detail__reaction-type-list-item-button'\n                data-testid='add-reaction-button'\n                onClick={() => setExtendedReactionListOpen(true)}\n                type='button'\n              >\n                <span className='str-chat__message-reactions-detail__reaction-type-list-item-icon'>\n                  <IconEmojiAdd />\n                </span>\n              </button>\n            </li>\n          )}\n\n          {reactions.map(\n            ({ EmojiComponent, reactionCount, reactionType }) =>\n              EmojiComponent && (\n                <li\n                  className='str-chat__message-reactions-detail__reaction-type-list-item'\n                  key={reactionType}\n                >\n                  <button\n                    aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n                      reactionName: reactionType,\n                    })}\n                    aria-pressed={reactionType === selectedReactionType}\n                    className='str-chat__message-reactions-detail__reaction-type-list-item-button'\n                    onClick={() =>\n                      onSelectedReactionTypeChange?.(\n                        selectedReactionType === reactionType ? null : reactionType,\n                      )\n                    }\n                    type='button'\n                  >\n                    <span className='str-chat__message-reactions-detail__reaction-type-list-item-icon'>\n                      <EmojiComponent />\n                    </span>\n                    <span\n                      className='str-chat__message-reactions-detail__reaction-type-list-item-count'\n                      data-testid='reaction-type-count'\n                    >\n                      {reactionCount}\n                    </span>\n                  </button>\n                </li>\n              ),\n          )}\n        </ul>\n      </div>\n      <div className='str-chat__message-reactions-detail__user-list-container'>\n        <div\n          className='str-chat__message-reactions-detail__user-list'\n          data-testid='all-reacting-users'\n        >\n          {areReactionsLoading && <LoadingIndicator />}\n          {!areReactionsLoading && (\n            <>\n              {reactionDetails.map(({ type, user }) => {\n                const belongsToCurrentUser = client.user?.id === user?.id;\n                const reactionName = getReactionName(type);\n                const EmojiComponent = Array.isArray(reactionOptions)\n                  ? undefined\n                  : (reactionOptions.quick[type]?.Component ??\n                    reactionOptions.extended?.[type]?.Component);\n\n                return (\n                  <div\n                    className='str-chat__message-reactions-detail__user-list-item'\n                    key={`${user?.id}-${type}`}\n                  >\n                    <Avatar\n                      className='str-chat__avatar--with-border'\n                      data-testid='avatar'\n                      imageUrl={user?.image as string | undefined}\n                      size='md'\n                      userName={user?.name || user?.id}\n                    />\n                    <div className='str-chat__message-reactions-detail__user-list-item-info'>\n                      <span\n                        className='str-chat__message-reactions-detail__user-list-item-username'\n                        data-testid='reaction-user-username'\n                      >\n                        {belongsToCurrentUser ? t('You') : user?.name || user?.id}\n                      </span>\n                      {belongsToCurrentUser && (\n                        <button\n                          aria-label={t('Tap to remove: {{ reactionName }}', {\n                            reactionName,\n                          })}\n                          className='str-chat__message-reactions-detail__user-list-item-button'\n                          data-testid='remove-reaction-button'\n                          onClick={async (e) => {\n                            const reactionCountBeforeRemoval =\n                              reactionGroups?.[type]?.count ?? 0;\n\n                            await contextHandleReaction(type, e);\n\n                            // was 1, should be 0 after removal, display all reactions\n                            if (\n                              selectedReactionType !== null &&\n                              reactionCountBeforeRemoval <= 1\n                            ) {\n                              onSelectedReactionTypeChange?.(null);\n                            } else {\n                              refetch();\n                            }\n                          }}\n                          type='button'\n                        >\n                          {t('Tap to remove')}\n                        </button>\n                      )}\n                    </div>\n                    <span className='str-chat__message-reactions-detail__user-list-item-icon'>\n                      {!selectedReactionType && EmojiComponent && <EmojiComponent />}\n                    </span>\n                  </div>\n                );\n              })}\n            </>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n};\n\nMessageReactionsDetail.displayName = 'MessageReactionsDetail';\n\nMessageReactionsDetail.getDialogId = ({ messageId }) =>\n  `message-reactions-detail-${messageId}`;\n","import { useCallback, useMemo } from 'react';\n\nimport { useComponentContext, useMessageContext } from '../../../context';\nimport { defaultReactionOptions } from '../reactionOptions';\n\nimport type { MessageReactionsProps } from '../MessageReactions';\nimport type { ReactionsComparator, ReactionSummary } from '../types';\n\nexport type UseProcessReactionsParams = Pick<\n  MessageReactionsProps,\n  'own_reactions' | 'reaction_groups' | 'reactions'\n> & {\n  sortReactions?: ReactionsComparator;\n};\n\nexport const defaultReactionsSort: ReactionsComparator = (a, b) => {\n  if (a.firstReactionAt && b.firstReactionAt) {\n    return +a.firstReactionAt - +b.firstReactionAt;\n  }\n\n  return a.reactionType.localeCompare(b.reactionType, 'en');\n};\n\nexport const useProcessReactions = (params: UseProcessReactionsParams) => {\n  const {\n    own_reactions: propOwnReactions,\n    reaction_groups: propReactionGroups,\n    reactions: propReactions,\n    sortReactions: propSortReactions,\n  } = params;\n  const { message, sortReactions: contextSortReactions } =\n    useMessageContext('useProcessReactions');\n  const { reactionOptions = defaultReactionOptions } =\n    useComponentContext('useProcessReactions');\n\n  const sortReactions = propSortReactions ?? contextSortReactions ?? defaultReactionsSort;\n  const latestReactions = propReactions ?? message.latest_reactions;\n  const ownReactions = propOwnReactions ?? message?.own_reactions;\n  const reactionGroups = propReactionGroups ?? message?.reaction_groups ?? undefined;\n\n  const isOwnReaction = useCallback(\n    (reactionType: string) =>\n      ownReactions?.some((reaction) => reaction.type === reactionType) ?? false,\n    [ownReactions],\n  );\n\n  const getEmojiByReactionType = useCallback(\n    (reactionType: string) => {\n      if (Array.isArray(reactionOptions)) {\n        return (\n          reactionOptions.find(({ type }) => type === reactionType)?.Component ?? null\n        );\n      }\n\n      return (\n        reactionOptions.quick[reactionType]?.Component ??\n        reactionOptions.extended?.[reactionType]?.Component ??\n        null\n      );\n    },\n    [reactionOptions],\n  );\n\n  const isSupportedReaction = useCallback(\n    (reactionType: string) => {\n      if (Array.isArray(reactionOptions)) {\n        return reactionOptions.some(\n          (reactionOption) => reactionOption.type === reactionType,\n        );\n      }\n\n      return (\n        typeof reactionOptions.quick[reactionType] !== 'undefined' ||\n        typeof reactionOptions.extended?.[reactionType] !== 'undefined'\n      );\n    },\n    [reactionOptions],\n  );\n\n  /**\n   * Amount of unique reaction types (\"haha\", \"like\", etc.) on a message.\n   */\n  const uniqueReactionTypeCount = useMemo(() => {\n    if (!reactionGroups) {\n      return 0;\n    }\n\n    return Object.keys(reactionGroups).filter((reactionType) =>\n      isSupportedReaction(reactionType),\n    ).length;\n  }, [isSupportedReaction, reactionGroups]);\n\n  // Group the reacting user names by reaction type in a single pass, so each\n  // reaction group can look its names up in O(1) instead of re-scanning the\n  // whole `latestReactions` array per type (previously O(types × reactions)).\n  const latestReactedUserNamesByType = useMemo(() => {\n    const namesByType = new Map<string, string[]>();\n    if (!latestReactions) return namesByType;\n\n    for (const reaction of latestReactions) {\n      if (!reaction.type) continue;\n      const username = reaction.user?.name || reaction.user?.id;\n      if (!username) continue;\n\n      const existing = namesByType.get(reaction.type);\n      if (existing) {\n        existing.push(username);\n      } else {\n        namesByType.set(reaction.type, [username]);\n      }\n    }\n\n    return namesByType;\n  }, [latestReactions]);\n\n  const existingReactions: ReactionSummary[] = useMemo(() => {\n    if (!reactionGroups) {\n      return [];\n    }\n\n    const unsortedReactions = Object.entries(reactionGroups).flatMap(\n      ([reactionType, { count, first_reaction_at, last_reaction_at }]) => {\n        if (count === 0 || !isSupportedReaction(reactionType)) {\n          return [];\n        }\n\n        const latestReactedUserNames =\n          latestReactedUserNamesByType.get(reactionType) ?? [];\n\n        return [\n          {\n            EmojiComponent: getEmojiByReactionType(reactionType),\n            firstReactionAt: first_reaction_at ? new Date(first_reaction_at) : null,\n            isOwnReaction: isOwnReaction(reactionType),\n            lastReactionAt: last_reaction_at ? new Date(last_reaction_at) : null,\n            latestReactedUserNames,\n            reactionCount: count,\n            reactionType,\n            unlistedReactedUserCount: count - latestReactedUserNames.length,\n          },\n        ];\n      },\n    );\n\n    return unsortedReactions.sort(sortReactions);\n  }, [\n    getEmojiByReactionType,\n    latestReactedUserNamesByType,\n    isOwnReaction,\n    isSupportedReaction,\n    reactionGroups,\n    sortReactions,\n  ]);\n\n  const hasReactions = existingReactions.length > 0;\n\n  const totalReactionCount = useMemo(\n    () =>\n      Object.values(reactionGroups ?? {}).reduce((total, { count }) => total + count, 0),\n\n    [reactionGroups],\n  );\n\n  return {\n    existingReactions,\n    hasReactions,\n    reactionGroups,\n    totalReactionCount,\n    uniqueReactionTypeCount,\n  } as const;\n};\n","import React, {\n  type ComponentPropsWithoutRef,\n  type ComponentRef,\n  useMemo,\n  useRef,\n  useState,\n} from 'react';\nimport clsx from 'clsx';\n\nimport { MessageReactionsDetail as DefaultMessageReactionsDetail } from './MessageReactionsDetail';\nimport { useProcessReactions } from './hooks/useProcessReactions';\nimport type { MessageContextValue } from '../../context';\nimport {\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\n\nimport { MAX_MESSAGE_REACTIONS_TO_FETCH } from '../Message/hooks';\n\nimport type { ReactionGroupResponse, ReactionResponse } from 'stream-chat';\nimport type { ReactionsComparator, ReactionType } from './types';\nimport { DialogAnchor, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';\n\nexport type MessageReactionsProps = Partial<\n  Pick<MessageContextValue, 'handleFetchReactions' | 'reactionDetailsSort'>\n> & {\n  /** An array of the own reaction objects to distinguish own reactions visually */\n  own_reactions?: ReactionResponse[];\n  /** An object containing summary for each reaction type on a message */\n  reaction_groups?: Record<string, ReactionGroupResponse>;\n  /** An array of the reaction objects to display in the list */\n  reactions?: ReactionResponse[];\n  /** Display the reactions in the list in reverse order, defaults to false */\n  reverse?: boolean;\n  /** Comparator function to sort reactions, defaults to chronological order */\n  sortReactions?: ReactionsComparator;\n  /**\n   * Positioning of the reactions list relative to the message. Position is flipped by default for the messages of other users.\n   */\n  flipHorizontalPosition?: boolean;\n  verticalPosition?: 'top' | 'bottom' | null;\n  visualStyle?: 'clustered' | 'segmented' | null;\n  capLimit?: {\n    [key in Extract<MessageReactionsProps['visualStyle'], string>]?: number;\n  };\n};\n\n/**\n * Renders a button if `buttonIf` is true, otherwise renders a fragment. No props but children are passed to fragment, but all props are passed to button if it's rendered.\n */\nconst FragmentOrButton = ({\n  buttonIf: renderButton = false,\n  children,\n  type = 'button',\n  ...props\n}: ComponentPropsWithoutRef<'button'> & { buttonIf?: boolean }) => {\n  if (renderButton) {\n    return (\n      <button {...props} type={type}>\n        {children}\n      </button>\n    );\n  }\n\n  return <>{children}</>;\n};\n\nconst UnMemoizedMessageReactions = (props: MessageReactionsProps) => {\n  const {\n    capLimit: { clustered: capLimitClustered = 5, segmented: capLimitSegmented = 4 } = {},\n    flipHorizontalPosition = false,\n    handleFetchReactions,\n    reactionDetailsSort,\n    verticalPosition = 'top',\n    visualStyle = 'clustered',\n    ...rest\n  } = props;\n\n  const {\n    existingReactions,\n    hasReactions,\n    reactionGroups,\n    totalReactionCount,\n    uniqueReactionTypeCount,\n  } = useProcessReactions(rest);\n  const [selectedReactionType, setSelectedReactionType] = useState<ReactionType | null>(\n    null,\n  );\n  const { t } = useTranslationContext('MessageReactions');\n  const { MessageReactionsDetail = DefaultMessageReactionsDetail } =\n    useComponentContext();\n  const { isMyMessage, message } = useMessageContext('MessageReactions');\n\n  const divRef = useRef<ComponentRef<'div'>>(null);\n  const dialogId = DefaultMessageReactionsDetail.getDialogId({\n    messageId: message.id,\n  });\n  const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n  const isDialogOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n  const handleReactionButtonClick = (reactionType: ReactionType | null) => {\n    if (totalReactionCount > MAX_MESSAGE_REACTIONS_TO_FETCH) {\n      return;\n    }\n\n    setSelectedReactionType(reactionType);\n\n    dialog.open();\n  };\n\n  /**\n   * In segmented style with top position we show max 4 reactions and a\n   * count of the rest, so we need to cap the existing reactions to display\n   * at 4 and calculate the count of the rest. For clustered(top/bottom) we cap\n   * the existing reactions to 5 but we don't calculate the count of the rest\n   * because we show the total count instead. For segmented style with bottom\n   * position we don't cap the existing reactions and we show all of them.\n   */\n  const cappedExistingReactions = useMemo(() => {\n    if (visualStyle === 'segmented' && verticalPosition !== 'top') return null;\n\n    const capLimit = visualStyle === 'segmented' ? capLimitSegmented : capLimitClustered;\n\n    const sliced = existingReactions.slice(0, capLimit);\n\n    return {\n      /**\n       * Accumulated reaction count of capped reaction types, first four in case of\n       * segmented(top) and first five in case of clustered(top/bottom) variations.\n       */\n      reactionCountToDisplay: sliced.reduce(\n        (accumulatedCount, { reactionCount }) => accumulatedCount + reactionCount,\n        0,\n      ),\n      reactionsToDisplay: sliced,\n    } as const;\n  }, [\n    capLimitClustered,\n    capLimitSegmented,\n    existingReactions,\n    verticalPosition,\n    visualStyle,\n  ]);\n\n  if (!hasReactions) return null;\n\n  return (\n    <>\n      <div\n        aria-label={t('aria/Reaction list')}\n        className={clsx('str-chat__message-reactions', {\n          [`str-chat__message-reactions--flipped-horizontally`]: flipHorizontalPosition,\n          [`str-chat__message-reactions--${verticalPosition}`]:\n            typeof verticalPosition === 'string',\n          [`str-chat__message-reactions--${visualStyle}`]:\n            typeof visualStyle === 'string',\n        })}\n        ref={divRef}\n        role='figure'\n      >\n        <FragmentOrButton\n          aria-expanded={isDialogOpen}\n          aria-label={t('aria/Reaction list')}\n          aria-pressed={isDialogOpen}\n          buttonIf={visualStyle === 'clustered'}\n          className='str-chat__message-reactions__list-button'\n          data-testid='message-reactions-list-button'\n          onClick={() => handleReactionButtonClick(null)}\n        >\n          <ul className='str-chat__message-reactions__list'>\n            {(cappedExistingReactions?.reactionsToDisplay ?? existingReactions).map(\n              ({ EmojiComponent, reactionCount, reactionType }) =>\n                EmojiComponent && (\n                  <li\n                    className='str-chat__message-reactions__list-item'\n                    data-testid='message-reactions-list-item'\n                    key={reactionType}\n                  >\n                    <FragmentOrButton\n                      aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n                        reactionName: reactionType,\n                      })}\n                      buttonIf={visualStyle === 'segmented'}\n                      className='str-chat__message-reactions__list-item-button'\n                      onClick={() => handleReactionButtonClick(reactionType)}\n                    >\n                      <span\n                        className='str-chat__message-reactions__list-item-icon'\n                        data-testid='message-reactions-list-item-icon'\n                      >\n                        <EmojiComponent />\n                      </span>\n                      {visualStyle === 'segmented' && reactionCount > 1 && (\n                        <span\n                          className='str-chat__message-reactions__list-item-count'\n                          data-testclass='message-reactions-item-count'\n                        >\n                          {reactionCount}\n                        </span>\n                      )}\n                    </FragmentOrButton>\n                  </li>\n                ),\n            )}\n            {uniqueReactionTypeCount > 4 &&\n              cappedExistingReactions &&\n              visualStyle === 'segmented' && (\n                <li className='str-chat__message-reactions__list-item str-chat__message-reactions__list-item--more'>\n                  <button\n                    aria-label={t('aria/Reaction list')}\n                    className='str-chat__message-reactions__list-item-button'\n                    onClick={() => handleReactionButtonClick(null)}\n                    type='button'\n                  >\n                    <span className='str-chat__message-reactions__overflow-count'>\n                      +\n                      {totalReactionCount -\n                        cappedExistingReactions.reactionCountToDisplay}\n                    </span>\n                  </button>\n                </li>\n              )}\n          </ul>\n          {visualStyle === 'clustered' && (\n            <span\n              className='str-chat__message-reactions__total-count'\n              data-testid='message-reactions-total-count'\n            >\n              {totalReactionCount}\n            </span>\n          )}\n        </FragmentOrButton>\n      </div>\n\n      <DialogAnchor\n        dialogManagerId={dialogManager?.id}\n        id={dialogId}\n        offset={8}\n        placement={isMyMessage() ? 'bottom-end' : 'bottom-start'}\n        referenceElement={divRef.current}\n        trapFocus\n        updatePositionOnContentResize\n      >\n        <MessageReactionsDetail\n          handleFetchReactions={handleFetchReactions}\n          onSelectedReactionTypeChange={setSelectedReactionType}\n          reactionDetailsSort={reactionDetailsSort}\n          reactionGroups={reactionGroups}\n          reactions={existingReactions}\n          selectedReactionType={selectedReactionType}\n          totalReactionCount={totalReactionCount}\n        />\n      </DialogAnchor>\n    </>\n  );\n};\n\n/**\n * Component that displays a list of reactions on a message.\n */\nexport const MessageReactions = React.memo(\n  UnMemoizedMessageReactions,\n) as typeof UnMemoizedMessageReactions;\n","import type { ForwardedRef, MutableRefObject } from 'react';\n\nexport const isMutableRef = <T>(\n  ref: ForwardedRef<T> | null,\n): ref is MutableRefObject<T> => {\n  if (ref) {\n    return (ref as MutableRefObject<T>).current !== undefined;\n  }\n  return false;\n};\n\nexport const getImageDimensions = (source: string) =>\n  new Promise<[number, number]>((resolve, reject) => {\n    const image = new Image();\n\n    image.addEventListener(\n      'load',\n      () => {\n        resolve([image.width, image.height]);\n      },\n      { once: true },\n    );\n\n    image.addEventListener('error', () => reject(`Couldn't load image from ${source}`), {\n      once: true,\n    });\n\n    image.src = source;\n  });\n","import React, { useEffect, useState } from 'react';\n\nimport { getImageDimensions } from './utils/utils';\n\nexport type SpriteImageProps = {\n  columns: number;\n  position: [number, number];\n  rows: number;\n  spriteUrl: string;\n  fallback?: React.ReactNode;\n  height?: number;\n  style?: React.CSSProperties;\n  width?: number;\n};\n\nexport const SpriteImage = ({\n  columns,\n  fallback,\n  height,\n  position,\n  rows,\n  spriteUrl,\n  style,\n  width,\n}: SpriteImageProps) => {\n  const [[spriteWidth, spriteHeight], setSpriteDimensions] = useState([0, 0]);\n\n  useEffect(() => {\n    getImageDimensions(spriteUrl).then(setSpriteDimensions).catch(console.error);\n  }, [spriteUrl]);\n\n  const [x, y] = position;\n\n  if (!spriteHeight || !spriteWidth) return <>{fallback}</>;\n\n  return (\n    <div\n      data-testid='sprite-image'\n      style={\n        {\n          ...style,\n          '--str-chat__sprite-image-resize-ratio':\n            'var(--str-chat__sprite-image-resize-ratio-x, var(--str-chat__sprite-image-resize-ratio-y, 1))',\n          '--str-chat__sprite-image-resize-ratio-x':\n            'calc(var(--str-chat__sprite-image-width) / var(--str-chat__sprite-item-width))',\n          '--str-chat__sprite-image-resize-ratio-y':\n            'calc(var(--str-chat__sprite-image-height) / var(--str-chat__sprite-item-height))',\n          '--str-chat__sprite-item-height': `${spriteHeight / rows}`,\n          '--str-chat__sprite-item-width': `${spriteWidth / columns}`,\n          ...(Number.isFinite(height)\n            ? { '--str-chat__sprite-image-height': `${height}px` }\n            : {}),\n          ...(Number.isFinite(width)\n            ? { '--str-chat__sprite-image-width': `${width}px` }\n            : {}),\n          backgroundImage: `url('${spriteUrl}')`,\n          backgroundPosition: `${x * (100 / (columns - 1))}% ${y * (100 / (rows - 1))}%`,\n          backgroundSize: `${columns * 100}% ${rows * 100}%`,\n          height:\n            'var(--str-chat__sprite-image-height, calc(var(--str-chat__sprite-item-height) * var(--str-chat__sprite-image-resize-ratio)))',\n          width:\n            'var(--str-chat__sprite-image-width, calc(var(--str-chat__sprite-item-width) * var(--str-chat__sprite-image-resize-ratio)))',\n        } as React.CSSProperties\n      }\n    />\n  );\n};\n","import type { ComponentRef } from 'react';\nimport React, { useRef } from 'react';\nimport { ReactionSelector as DefaultReactionSelector } from './ReactionSelector';\nimport { DialogAnchor, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';\nimport {\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\n\nimport type { IconProps } from '../../types/types';\nimport { QuickMessageActionsButton } from '../MessageActions';\n\ntype ReactionSelectorWithButtonProps = {\n  /* Custom component rendering the icon used in a button invoking reactions selector for a given message. */\n  ReactionIcon: React.ComponentType<IconProps>;\n};\n\n/**\n * Internal convenience component - not to be exported. It just groups the button and the dialog anchor and thus prevents\n * cluttering the parent component.\n */\nexport const ReactionSelectorWithButton = ({\n  ReactionIcon,\n}: ReactionSelectorWithButtonProps) => {\n  const { t } = useTranslationContext('ReactionSelectorWithButton');\n  const { isMyMessage, message, threadList } = useMessageContext('MessageOptions');\n  const { ReactionSelector = DefaultReactionSelector } =\n    useComponentContext('MessageOptions');\n  const buttonRef = useRef<ComponentRef<'button'>>(null);\n  const dialogId = DefaultReactionSelector.getDialogId({\n    messageId: message.id,\n    threadList,\n  });\n  const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n  const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n  return (\n    <>\n      <DialogAnchor\n        dialogManagerId={dialogManager?.id}\n        id={dialogId}\n        offset={8}\n        placement={isMyMessage() ? 'top-end' : 'top-start'}\n        referenceElement={buttonRef.current}\n        trapFocus\n        updatePositionOnContentResize\n      >\n        <ReactionSelector />\n      </DialogAnchor>\n      <QuickMessageActionsButton\n        aria-expanded={dialogIsOpen}\n        aria-label={t('aria/Open Reaction Selector')}\n        className='str-chat__message-reactions-button'\n        data-testid='message-reaction-action'\n        onClick={() => dialog?.toggle()}\n        ref={buttonRef}\n      >\n        <ReactionIcon className='str-chat__message-action-icon' />\n      </QuickMessageActionsButton>\n    </>\n  );\n};\n","import React from 'react';\nimport { useChatContext, useMessageContext, useTranslationContext } from '../../context';\nimport { useNotificationApi } from '../Notifications';\nimport {\n  ContextMenuBackButton,\n  ContextMenuButton,\n  ContextMenuHeader,\n  useContextMenuContext,\n} from '../Dialog';\nimport { IconChevronLeft } from '../Icons';\n\nconst getErrorMessage = (error: unknown, fallback: string) =>\n  error instanceof Error && error.message ? error.message : fallback;\n\nconst getNotificationError = (error: unknown): Error | undefined => {\n  if (error instanceof Error) return error;\n  if (typeof error === 'string') return new Error(error);\n  if (error && typeof error === 'object' && 'message' in error) {\n    const message = error.message;\n    if (typeof message === 'string') return new Error(message);\n  }\n  return undefined;\n};\n\nexport const RemindMeSubmenuHeader = () => {\n  const { t } = useTranslationContext();\n  const { returnToParentMenu } = useContextMenuContext();\n  return (\n    <ContextMenuHeader>\n      <ContextMenuBackButton onClick={returnToParentMenu}>\n        <IconChevronLeft />\n        <span>{t('Remind Me')}</span>\n      </ContextMenuBackButton>\n    </ContextMenuHeader>\n  );\n};\n\nexport const RemindMeSubmenu = () => {\n  const { t } = useTranslationContext();\n  const { client } = useChatContext();\n  const { message } = useMessageContext();\n  const { closeMenu } = useContextMenuContext();\n  const { addNotification } = useNotificationApi();\n  return (\n    <div\n      aria-label={t('aria/Remind Me Options')}\n      className='str-chat__message-actions-box__submenu'\n      role='menu'\n    >\n      {client.reminders.scheduledOffsetsMs.map((offsetMs) => (\n        <ContextMenuButton\n          className='str-chat__message-actions-list-item-button'\n          key={`reminder-offset-option--${offsetMs}`}\n          onClick={async () => {\n            try {\n              await client.reminders.upsertReminder({\n                messageId: message.id,\n                remind_at: new Date(new Date().getTime() + offsetMs).toISOString(),\n              });\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                message: t('Reminder set'),\n                severity: 'success',\n                type: 'api:message:reminder:set:success',\n              });\n            } catch (error) {\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                error: getNotificationError(error),\n                message: getErrorMessage(error, 'Error setting reminder'),\n                severity: 'error',\n                type: 'api:message:reminder:set:failed',\n              });\n            } finally {\n              closeMenu();\n            }\n          }}\n        >\n          {t('duration/Remind Me', { milliseconds: offsetMs })}\n        </ContextMenuButton>\n      ))}\n      {/* todo: potential improvement to add a custom option that would trigger rendering modal with custom date picker - we need date picker */}\n    </div>\n  );\n};\n","import {\n  type Attachment,\n  isAudioAttachment,\n  isFileAttachment,\n  isImageAttachment,\n  isVideoAttachment,\n  isVoiceRecordingAttachment,\n  type LocalAttachment,\n  type LocalUploadAttachment,\n} from 'stream-chat';\n\n/**\n * Download behavior notes:\n *\n * - Remote attachments prefer `fetch -> blob -> objectURL` instead of direct link clicks.\n * - In Chromium, direct sequential clicks on cross-origin URLs can yield only one actual\n *   downloaded file even when multiple anchor clicks are fired.\n * - Blob URLs are same-document downloads and preserve caller-provided `a.download` names\n *   more reliably than direct remote URLs.\n * - If remote fetch fails (e.g. CORS/policy/network), the code falls back to direct URL\n *   download so the action remains functional.\n */\nexport type DownloadableAttachment = {\n  asset_url?: string;\n  image_url?: string;\n  localMetadata?: LocalUploadAttachment['localMetadata'];\n  title?: string;\n};\n\nexport const isDownloadableAttachment = (\n  attachment: unknown,\n): attachment is DownloadableAttachment => {\n  if (!attachment || typeof attachment !== 'object') return false;\n  const typedAttachment = attachment as Attachment | LocalAttachment;\n\n  return (\n    isFileAttachment(typedAttachment) ||\n    isImageAttachment(typedAttachment) ||\n    isVideoAttachment(typedAttachment) ||\n    isAudioAttachment(typedAttachment) ||\n    isVoiceRecordingAttachment(typedAttachment)\n  );\n};\n\nconst triggerUrlDownload = ({\n  filename,\n  openInNewTab,\n  revokeObjectUrl,\n  url,\n}: {\n  openInNewTab?: boolean;\n  revokeObjectUrl?: boolean;\n  url: string;\n  filename: string;\n}) => {\n  const anchor = document.createElement('a');\n  anchor.download = filename;\n  anchor.href = url;\n  anchor.rel = 'noopener noreferrer';\n  // Keep chat in place for direct remote URLs by opening in a new tab when requested.\n  if (openInNewTab && !url.startsWith('blob:')) {\n    anchor.target = '_blank';\n  }\n  document.body.append(anchor);\n  anchor.click();\n  anchor.remove();\n\n  // Revoke object URLs by default; direct network URLs are never revoked.\n  const shouldRevokeObjectUrl = revokeObjectUrl ?? url.startsWith('blob:');\n  if (shouldRevokeObjectUrl && url.startsWith('blob:')) {\n    setTimeout(() => URL.revokeObjectURL(url), 0);\n  }\n};\n\nconst fetchRemoteAttachmentAsObjectUrl = async (url: string) => {\n  if (typeof fetch !== 'function') return null;\n\n  const response = await fetch(url);\n  if (!response.ok) {\n    throw new Error(`Failed to fetch attachment, status ${response.status}`);\n  }\n  const blob = await response.blob();\n  return URL.createObjectURL(blob);\n};\n\nexport const downloadAttachment = async (\n  attachment: DownloadableAttachment,\n  options: { openRemoteInNewTab?: boolean; preferRemoteFetch?: boolean } = {},\n) => {\n  const { openRemoteInNewTab = true, preferRemoteFetch = true } = options;\n  const titleFallback = attachment.title ?? 'downloaded-attachment';\n  const rawFile = attachment.localMetadata?.file;\n\n  if (rawFile instanceof Blob) {\n    const filename =\n      rawFile instanceof File && rawFile.name ? rawFile.name : titleFallback;\n    triggerUrlDownload({\n      filename,\n      url: URL.createObjectURL(rawFile),\n    });\n    return;\n  }\n\n  const filename =\n    rawFile &&\n    typeof rawFile === 'object' &&\n    'name' in rawFile &&\n    typeof (rawFile as { name: unknown }).name === 'string'\n      ? (rawFile as { name: string }).name\n      : titleFallback;\n\n  const url = attachment.asset_url ?? attachment.image_url;\n  if (!url) return;\n\n  // Prefer blob-based download for remote files when requested.\n  if (preferRemoteFetch) {\n    try {\n      const objectUrl = await fetchRemoteAttachmentAsObjectUrl(url);\n      if (objectUrl) {\n        triggerUrlDownload({\n          filename,\n          url: objectUrl,\n        });\n        return;\n      }\n    } catch {\n      // Fall back to direct URL download when fetch is blocked (e.g. CORS/policy).\n    }\n  }\n\n  triggerUrlDownload({ filename, openInNewTab: openRemoteInNewTab, url });\n};\n\nexport const downloadAllAttachments = async (attachments: DownloadableAttachment[]) => {\n  // Sequential execution keeps user intent clear and avoids bursting simultaneous requests.\n  for (const attachment of attachments) {\n    await downloadAttachment(attachment, {\n      openRemoteInNewTab: true,\n      preferRemoteFetch: true,\n    });\n  }\n};\n","import React from 'react';\nimport { useMessageContext, useTranslationContext } from '../../context';\nimport {\n  ContextMenuBackButton,\n  ContextMenuButton,\n  ContextMenuHeader,\n  useContextMenuContext,\n} from '../Dialog';\nimport { IconChevronLeft, IconDownload } from '../Icons';\nimport {\n  downloadAllAttachments,\n  downloadAttachment,\n  isDownloadableAttachment,\n} from './downloadUtils';\n\nconst msgActionsBoxButtonClassName =\n  'str-chat__message-actions-list-item-button' as const;\n\nexport const DownloadSubmenuHeader = () => {\n  const { returnToParentMenu: goBack } = useContextMenuContext();\n  const { t } = useTranslationContext();\n  return (\n    <ContextMenuHeader>\n      <ContextMenuBackButton onClick={goBack}>\n        <IconChevronLeft />\n        <span>{t('Download Attachment')}</span>\n      </ContextMenuBackButton>\n    </ContextMenuHeader>\n  );\n};\n\nexport const DownloadSubmenu = () => {\n  const { closeMenu } = useContextMenuContext();\n  const { message } = useMessageContext();\n  const { t } = useTranslationContext();\n\n  const downloadableAttachments = (message.attachments ?? []).filter(\n    isDownloadableAttachment,\n  );\n\n  return (\n    <div\n      aria-label={t('aria/Download attachment')}\n      className='str-chat__message-actions-box__submenu str-chat__message-actions-box__submenu--download-attachments'\n      role='menu'\n    >\n      {downloadableAttachments.map((attachment, index) => {\n        const fileName =\n          attachment.localMetadata?.file?.name ??\n          attachment.title ??\n          t('Download Attachment');\n\n        return (\n          <ContextMenuButton\n            className={msgActionsBoxButtonClassName}\n            Icon={IconDownload}\n            key={\n              attachment.localMetadata?.id ??\n              attachment.asset_url ??\n              attachment.image_url ??\n              `${fileName}-${index}`\n            }\n            onClick={() => {\n              void downloadAttachment(attachment);\n              closeMenu();\n            }}\n          >\n            {`Download ${fileName}`}\n          </ContextMenuButton>\n        );\n      })}\n      <ContextMenuButton\n        className={msgActionsBoxButtonClassName}\n        Icon={IconDownload}\n        onClick={() => {\n          void downloadAllAttachments(downloadableAttachments);\n          closeMenu();\n        }}\n      >\n        {t('Download All')}\n      </ContextMenuButton>\n    </div>\n  );\n};\n","import { Button, type ButtonProps } from '../Button';\nimport clsx from 'clsx';\nimport React, { forwardRef } from 'react';\n\nexport const QuickMessageActionsButton = forwardRef<HTMLButtonElement, ButtonProps>(\n  function QuickMessageActionsButton({ className, ...props }, ref) {\n    return (\n      <Button\n        appearance='ghost'\n        circular\n        className={clsx('str-chat__message-actions-box-button', className)}\n        ref={ref}\n        size='sm'\n        variant='secondary'\n        {...props}\n      />\n    );\n  },\n);\n","import { Alert } from '../Dialog';\nimport { Button } from '../Button';\nimport React from 'react';\nimport { useModalContext, useTranslationContext } from '../../context';\n\nexport type DeleteMessageAlertProps = {\n  onCancel: () => void;\n  onDelete: () => void;\n};\n\nexport const DeleteMessageAlert = ({ onCancel, onDelete }: DeleteMessageAlertProps) => {\n  const { t } = useTranslationContext();\n  const { close } = useModalContext();\n\n  return (\n    <Alert.Root\n      className='str-chat__delete-message-alert'\n      data-testid='message-delete-alert'\n    >\n      <Alert.Header\n        description={t('Are you sure you want to delete this message?')}\n        title={t('Delete message')}\n      />\n      <Alert.Actions>\n        <Button\n          appearance='outline'\n          className='str-chat__delete-message-alert__delete-button'\n          data-testid='delete-message-alert-delete-button'\n          onClick={onDelete}\n          size='md'\n          variant='danger'\n        >\n          {t('Delete message')}\n        </Button>\n        <Button\n          appearance='outline'\n          autoFocus\n          className='str-chat__delete-message-alert__cancel-button'\n          data-testid='delete-message-alert-cancel-button'\n          onClick={() => {\n            onCancel();\n            close();\n          }}\n          size='md'\n          variant='secondary'\n        >\n          {t('Cancel')}\n        </Button>\n      </Alert.Actions>\n    </Alert.Root>\n  );\n};\n","/* eslint-disable sort-keys */\nimport React, { forwardRef, useState } from 'react';\n\nimport { GlobalModal } from '../Modal';\nimport {\n  IconAudio,\n  IconBell,\n  IconBellOff,\n  IconBookmark,\n  IconBookmarkRemove,\n  IconCopy,\n  IconDelete,\n  IconDownload,\n  IconEdit,\n  IconEmoji,\n  IconFlag,\n  IconMore,\n  IconMute,\n  IconNoSign,\n  IconNotification,\n  IconPin,\n  IconQuote,\n  IconReply,\n  IconRetry,\n  IconThread,\n  IconUnpin,\n  IconUserCheck,\n} from '../Icons';\nimport { isMessageDeleted, isUserMuted } from '../Message/utils';\nimport { useMessageComposerController } from '../MessageComposer/hooks/useMessageComposerController';\nimport { savePreEditSnapshot } from '../MessageComposer/preEditSnapshot';\nimport { useNotificationApi } from '../Notifications';\nimport { useMessageReminder } from '../Message/hooks/useMessageReminder';\nimport { ReactionSelector as DefaultReactionSelector } from '../Reactions';\nimport { ReactionSelectorWithButton } from '../Reactions/ReactionSelectorWithButton';\nimport {\n  useChatContext,\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\nimport { RemindMeSubmenu, RemindMeSubmenuHeader } from './RemindMeSubmenu';\nimport { DownloadSubmenu, DownloadSubmenuHeader } from './DownloadSubmenu';\nimport {\n  ContextMenuButton,\n  DialogAnchor,\n  useContextMenuContext,\n  useDialogIsOpen,\n  useDialogOnNearestManager,\n} from '../Dialog';\nimport { MessageActions, type MessageActionSetItem } from './MessageActions';\nimport { QuickMessageActionsButton } from './QuickMessageActionButton';\nimport clsx from 'clsx';\nimport { DeleteMessageAlert } from './DeleteMessageAlert';\nimport { downloadAttachment, isDownloadableAttachment } from './downloadUtils';\n\nconst msgActionsBoxButtonClassName =\n  'str-chat__message-actions-list-item-button' as const;\n\nconst MessageActionsMenuItemButton = (\n  props: React.ComponentProps<typeof ContextMenuButton>,\n) => <ContextMenuButton {...props} />;\n\nconst getErrorMessage = (error: unknown, fallback: string) =>\n  error instanceof Error && error.message ? error.message : fallback;\n\nconst getNotificationError = (error: unknown): Error | undefined => {\n  if (error instanceof Error) return error;\n  if (typeof error === 'string') return new Error(error);\n  if (error && typeof error === 'object' && 'message' in error) {\n    const message = error.message;\n    if (typeof message === 'string') return new Error(message);\n  }\n  return undefined;\n};\n\nconst DefaultMessageActionComponents = {\n  dropdown: {\n    React() {\n      const { ReactionSelector = DefaultReactionSelector } = useComponentContext();\n      const { anchorReferenceElement } = useContextMenuContext();\n      const { isMyMessage, message, threadList } = useMessageContext();\n      const { t } = useTranslationContext();\n      const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(null);\n      const dialogId = `${DefaultReactionSelector.getDialogId({\n        messageId: message.id,\n        threadList,\n      })}-dropdown`;\n      const { dialog, dialogManager } = useDialogOnNearestManager({\n        id: dialogId,\n      });\n      const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n      return (\n        <>\n          <DialogAnchor\n            dialogManagerId={dialogManager?.id}\n            id={dialogId}\n            offset={8}\n            placement={isMyMessage() ? 'top-end' : 'top-start'}\n            referenceElement={referenceElement}\n            trapFocus\n            updatePositionOnContentResize\n          >\n            <ReactionSelector dialogId={dialogId} />\n          </DialogAnchor>\n          <MessageActionsMenuItemButton\n            aria-expanded={dialogIsOpen}\n            aria-label={t('aria/Open Reaction Selector')}\n            className={clsx(\n              msgActionsBoxButtonClassName,\n              'str-chat__message-actions-list-item-button--react',\n            )}\n            data-testid='dropdown-react-action'\n            Icon={IconEmoji}\n            onClick={(event) => {\n              if (dialogIsOpen) {\n                dialog.close();\n                return;\n              }\n              setReferenceElement(\n                anchorReferenceElement instanceof HTMLElement\n                  ? anchorReferenceElement\n                  : event.currentTarget,\n              );\n              dialog.open();\n            }}\n          >\n            {t('Add reaction')}\n          </MessageActionsMenuItemButton>\n        </>\n      );\n    },\n    ThreadReply() {\n      const { closeMenu } = useContextMenuContext();\n      const { handleOpenThread } = useMessageContext();\n      const { t } = useTranslationContext();\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Open Thread')}\n          className={msgActionsBoxButtonClassName}\n          data-testid='thread-action'\n          Icon={IconThread}\n          onClick={(e) => {\n            handleOpenThread(e);\n            closeMenu();\n          }}\n        >\n          {t('Thread Reply')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Quote() {\n      const { closeMenu } = useContextMenuContext();\n      const { message } = useMessageContext();\n      const { t } = useTranslationContext();\n      const messageComposer = useMessageComposerController();\n\n      const handleQuote = () => {\n        messageComposer.setQuotedMessage(message);\n\n        const elements = message.parent_id\n          ? document.querySelectorAll('.str-chat__thread .str-chat__textarea__textarea')\n          : document.getElementsByClassName('str-chat__textarea__textarea');\n        const textarea = elements.item(0);\n\n        if (textarea instanceof HTMLTextAreaElement) {\n          textarea.focus();\n        }\n      };\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Quote Message')}\n          className={msgActionsBoxButtonClassName}\n          Icon={IconQuote}\n          onClick={() => {\n            handleQuote();\n            closeMenu();\n          }}\n        >\n          {t('Quote Reply')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Download() {\n      const { closeMenu, openSubmenu } = useContextMenuContext();\n      const { message } = useMessageContext();\n      const { t } = useTranslationContext();\n\n      const downloadableAttachments = (message.attachments ?? []).filter(\n        isDownloadableAttachment,\n      );\n\n      if (!downloadableAttachments.length) return null;\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Download attachment')}\n          className={msgActionsBoxButtonClassName}\n          hasSubMenu={downloadableAttachments.length > 1}\n          Icon={IconDownload}\n          onClick={(event) => {\n            if (downloadableAttachments.length > 1) {\n              openSubmenu({\n                focusReturnTarget: event.currentTarget,\n                Header: DownloadSubmenuHeader,\n                Submenu: DownloadSubmenu,\n              });\n              return;\n            }\n\n            void downloadAttachment(downloadableAttachments[0]);\n            closeMenu();\n          }}\n        >\n          {t('Download Attachment')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Pin() {\n      const { closeMenu } = useContextMenuContext();\n      const { handlePin, message } = useMessageContext();\n      const { addNotification } = useNotificationApi();\n      const { t } = useTranslationContext();\n      const isPinned = !!message.pinned;\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={isPinned ? t('aria/Unpin Message') : t('aria/Pin Message')}\n          className={msgActionsBoxButtonClassName}\n          Icon={isPinned ? IconUnpin : IconPin}\n          onClick={async (event) => {\n            try {\n              await handlePin(event);\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                message: isPinned ? t('Message unpinned') : t('Message pinned'),\n                severity: 'success',\n                type: isPinned ? 'api:message:unpin:success' : 'api:message:pin:success',\n              });\n            } catch (error) {\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                error: getNotificationError(error),\n                message: getErrorMessage(\n                  error,\n                  isPinned ? t('Error removing message pin') : t('Error pinning message'),\n                ),\n                severity: 'error',\n                type: isPinned ? 'api:message:unpin:failed' : 'api:message:pin:failed',\n              });\n            }\n            closeMenu();\n          }}\n        >\n          {isPinned ? t('Unpin') : t('Pin')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    CopyMessageText() {\n      const { closeMenu } = useContextMenuContext();\n      const { message } = useMessageContext();\n      const { t } = useTranslationContext();\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Copy Message Text')}\n          className={msgActionsBoxButtonClassName}\n          Icon={IconCopy}\n          onClick={() => {\n            if (message.text) navigator.clipboard.writeText(message.text);\n            closeMenu();\n          }}\n        >\n          {t('Copy Message')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Resend() {\n      const { closeMenu } = useContextMenuContext();\n      const { handleRetry, message } = useMessageContext();\n      const { t } = useTranslationContext();\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Resend Message')}\n          className={msgActionsBoxButtonClassName}\n          Icon={IconRetry}\n          onClick={() => {\n            handleRetry(message);\n            closeMenu();\n          }}\n        >\n          {t('Resend')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Edit() {\n      const messageComposer = useMessageComposerController();\n      const { message } = useMessageContext();\n      const { t } = useTranslationContext();\n      const { closeMenu } = useContextMenuContext();\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Edit Message')}\n          className={msgActionsBoxButtonClassName}\n          Icon={IconEdit}\n          onClick={() => {\n            savePreEditSnapshot(messageComposer);\n            messageComposer.initState({ composition: message });\n            closeMenu();\n          }}\n        >\n          {t('Edit Message')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    MarkUnread() {\n      const { closeMenu } = useContextMenuContext();\n      const { handleMarkUnread, message } = useMessageContext();\n      const { addNotification } = useNotificationApi();\n      const { t } = useTranslationContext();\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Mark Message Unread')}\n          className={msgActionsBoxButtonClassName}\n          Icon={IconNotification}\n          onClick={async (event) => {\n            try {\n              await handleMarkUnread(event);\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                message: t('Message marked as unread'),\n                severity: 'success',\n                type: 'api:message:markUnread:success',\n              });\n            } catch (error) {\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                error: getNotificationError(error),\n                message: getErrorMessage(\n                  error,\n                  t(\n                    'Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.',\n                  ),\n                ),\n                severity: 'error',\n                type: 'api:message:markUnread:failed',\n              });\n            }\n            closeMenu();\n          }}\n        >\n          {t('Mark as unread')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    RemindMe() {\n      const { closeMenu, openSubmenu } = useContextMenuContext();\n      const { client } = useChatContext();\n      const { addNotification } = useNotificationApi();\n      const { t } = useTranslationContext();\n      const { message } = useMessageContext();\n      const reminder = useMessageReminder(message.id);\n      const messageAlreadyBookmarked = reminder && !reminder?.remindAt;\n\n      if (messageAlreadyBookmarked) return null;\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={reminder ? t('aria/Remind Me Message') : t('aria/Remove Reminder')}\n          className={msgActionsBoxButtonClassName}\n          hasSubMenu={!reminder}\n          Icon={reminder ? IconBellOff : IconBell}\n          onClick={async (event) => {\n            if (reminder) {\n              try {\n                await client.reminders.deleteReminder(reminder.id);\n                addNotification({\n                  context: {\n                    message,\n                  },\n                  emitter: 'MessageActions',\n                  message: t('Remove reminder'),\n                  severity: 'success',\n                  type: 'api:message:reminder:delete:success',\n                });\n              } catch (error) {\n                addNotification({\n                  context: {\n                    message,\n                  },\n                  emitter: 'MessageActions',\n                  error: getNotificationError(error),\n                  message: getErrorMessage(error, 'Error removing reminder'),\n                  severity: 'error',\n                  type: 'api:message:reminder:delete:failed',\n                });\n              } finally {\n                closeMenu();\n              }\n            } else {\n              openSubmenu({\n                focusReturnTarget: event.currentTarget,\n                Header: RemindMeSubmenuHeader,\n                Submenu: RemindMeSubmenu,\n              });\n            }\n          }}\n        >\n          {reminder ? t('Remove reminder') : t('Remind me')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    SaveForLater() {\n      const { closeMenu } = useContextMenuContext();\n      const { client } = useChatContext();\n      const { addNotification } = useNotificationApi();\n      const { message } = useMessageContext();\n      const { t } = useTranslationContext();\n      const reminder = useMessageReminder(message.id);\n      const messageAlreadyHasReminderScheduled = Boolean(reminder && reminder?.remindAt);\n\n      if (messageAlreadyHasReminderScheduled) return null;\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={\n            reminder ? t('aria/Remove Save For Later') : t('aria/Bookmark Message')\n          }\n          className={msgActionsBoxButtonClassName}\n          Icon={reminder ? IconBookmarkRemove : IconBookmark}\n          onClick={async () => {\n            try {\n              if (reminder) {\n                await client.reminders.deleteReminder(reminder.id);\n                addNotification({\n                  context: {\n                    message,\n                  },\n                  emitter: 'MessageActions',\n                  message: t('Remove save for later'),\n                  severity: 'success',\n                  type: 'api:message:saveForLater:delete:success',\n                });\n              } else {\n                await client.reminders.createReminder({ messageId: message.id });\n                addNotification({\n                  context: {\n                    message,\n                  },\n                  emitter: 'MessageActions',\n                  message: t('Saved for later'),\n                  severity: 'success',\n                  type: 'api:message:saveForLater:create:success',\n                });\n              }\n            } catch (error) {\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                error: getNotificationError(error),\n                message: getErrorMessage(\n                  error,\n                  reminder\n                    ? 'Error removing message from saved for later'\n                    : 'Error saving message for later',\n                ),\n                severity: 'error',\n                type: reminder\n                  ? 'api:message:saveForLater:delete:failed'\n                  : 'api:message:saveForLater:create:failed',\n              });\n            } finally {\n              closeMenu();\n            }\n          }}\n        >\n          {reminder ? t('Remove save for later') : t('Save for later')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Flag() {\n      const { closeMenu } = useContextMenuContext();\n      const { handleFlag, message } = useMessageContext();\n      const { addNotification } = useNotificationApi();\n      const { t } = useTranslationContext();\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={t('aria/Flag Message')}\n          className={msgActionsBoxButtonClassName}\n          Icon={IconFlag}\n          onClick={async (event) => {\n            try {\n              await handleFlag(event);\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                message: t('Message has been successfully flagged'),\n                severity: 'success',\n                type: 'api:message:flag:success',\n              });\n            } catch (error) {\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                error: getNotificationError(error),\n                message: getErrorMessage(error, t('Error adding flag')),\n                severity: 'error',\n                type: 'api:message:flag:failed',\n              });\n            }\n            closeMenu();\n          }}\n        >\n          {t('Flag')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Mute() {\n      const { closeMenu } = useContextMenuContext();\n      const { handleMute, message } = useMessageContext();\n      const { addNotification } = useNotificationApi();\n      const { mutes } = useChatContext();\n      const { t } = useTranslationContext();\n\n      const isMuted = isUserMuted(message, mutes);\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={isMuted ? t('aria/Unmute User') : t('aria/Mute User')}\n          className={msgActionsBoxButtonClassName}\n          Icon={isMuted ? IconAudio : IconMute}\n          onClick={async (event) => {\n            try {\n              await handleMute(event);\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                message: isMuted\n                  ? t('{{ user }} has been unmuted', {\n                      user: message.user?.name || message.user?.id,\n                    })\n                  : t('{{ user }} has been muted', {\n                      user: message.user?.name || message.user?.id,\n                    }),\n                severity: 'success',\n                type: isMuted ? 'api:user:unmute:success' : 'api:user:mute:success',\n              });\n            } catch (error) {\n              addNotification({\n                context: {\n                  message,\n                },\n                emitter: 'MessageActions',\n                error: getNotificationError(error),\n                message: getErrorMessage(\n                  error,\n                  isMuted ? t('Error unmuting a user ...') : t('Error muting a user ...'),\n                ),\n                severity: 'error',\n                type: isMuted ? 'api:user:unmute:failed' : 'api:user:mute:failed',\n              });\n            }\n            closeMenu();\n          }}\n        >\n          {isMuted ? t('Unmute') : t('Mute')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n    Delete() {\n      const { closeMenu } = useContextMenuContext();\n      const { addNotification } = useNotificationApi();\n      const { Modal = GlobalModal } = useComponentContext();\n      const { handleDelete, message } = useMessageContext();\n      const { t } = useTranslationContext();\n      const [openModal, setOpenModal] = useState(false);\n\n      if (isMessageDeleted(message)) return null;\n\n      return (\n        <>\n          <MessageActionsMenuItemButton\n            aria-label={t('aria/Delete Message')}\n            className={msgActionsBoxButtonClassName}\n            Icon={IconDelete}\n            onClick={() => {\n              setOpenModal(true);\n            }}\n            variant='destructive'\n          >\n            {t('Delete message')}\n          </MessageActionsMenuItemButton>\n          <Modal open={openModal} role='alertdialog'>\n            <DeleteMessageAlert\n              onCancel={() => {\n                setOpenModal(false);\n                closeMenu();\n              }}\n              onDelete={async () => {\n                try {\n                  await handleDelete();\n                  addNotification({\n                    context: {\n                      message,\n                    },\n                    emitter: 'MessageActions',\n                    message: t('Message deleted'),\n                    severity: 'success',\n                    type: 'api:message:delete:success',\n                  });\n                } catch (error) {\n                  addNotification({\n                    context: {\n                      message,\n                    },\n                    emitter: 'MessageActions',\n                    error: getNotificationError(error),\n                    message: getErrorMessage(error, t('Error deleting message')),\n                    severity: 'error',\n                    type: 'api:message:delete:failed',\n                  });\n                } finally {\n                  setOpenModal(false);\n                  closeMenu();\n                }\n              }}\n            />\n          </Modal>\n        </>\n      );\n    },\n    BlockUser() {\n      const { closeMenu } = useContextMenuContext();\n      const { client } = useChatContext();\n      const { message } = useMessageContext();\n      const { t } = useTranslationContext();\n      const isBlocked =\n        !message.user?.id ||\n        new Set(client.blockedUsers.getLatestValue().userIds).has(message.user?.id);\n\n      return (\n        <MessageActionsMenuItemButton\n          aria-label={isBlocked ? t('aria/Unblock User') : t('aria/Block User')}\n          className={clsx(msgActionsBoxButtonClassName)}\n          Icon={isBlocked ? IconUserCheck : IconNoSign}\n          onClick={() => {\n            const targetId = message.user?.id;\n            if (targetId) {\n              if (isBlocked) client.unBlockUser(targetId);\n              else client.blockUser(targetId);\n            }\n            closeMenu();\n          }}\n        >\n          {isBlocked ? t('Unblock User') : t('Block User')}\n        </MessageActionsMenuItemButton>\n      );\n    },\n  },\n  quick: {\n    // eslint-disable-next-line react/display-name\n    DropdownToggle: forwardRef<HTMLButtonElement>((_, ref) => {\n      const { t } = useTranslationContext();\n      const { message, threadList } = useMessageContext();\n      const dropdownDialogIsOpen = useDialogIsOpen(\n        MessageActions.getDialogId({ messageId: message.id }),\n      );\n      const { dialog } = useDialogOnNearestManager({\n        id: MessageActions.getDialogId({ messageId: message.id }),\n      });\n      const reactionSelectorDialogId = DefaultReactionSelector.getDialogId({\n        messageId: message.id,\n        threadList,\n      });\n      const { dialog: dropdownReactionSelectorDialog } = useDialogOnNearestManager({\n        id: `${reactionSelectorDialogId}-dropdown`,\n      });\n\n      return (\n        <QuickMessageActionsButton\n          aria-expanded={dropdownDialogIsOpen}\n          aria-haspopup='true'\n          aria-label={t('aria/Open Message Actions Menu')}\n          className='str-chat__message-actions-box-button'\n          data-testid='message-actions-toggle-button'\n          onClick={() => {\n            // Close dropdown-anchored reaction selectors before toggling actions menu\n            // to avoid stale selector re-anchoring.\n            dropdownReactionSelectorDialog?.close();\n            dialog?.toggle();\n          }}\n          ref={ref}\n        >\n          <IconMore className='str-chat__message-action-icon' />\n        </QuickMessageActionsButton>\n      );\n    }),\n    React() {\n      return <ReactionSelectorWithButton ReactionIcon={IconEmoji} />;\n    },\n    Reply() {\n      const { handleOpenThread } = useMessageContext();\n      const { t } = useTranslationContext();\n\n      return (\n        <QuickMessageActionsButton\n          aria-label={t('aria/Open Thread')}\n          className='str-chat__message-reply-in-thread-button'\n          data-testid='thread-action'\n          onClick={handleOpenThread}\n        >\n          <IconReply className='str-chat__message-action-icon' />\n        </QuickMessageActionsButton>\n      );\n    },\n  },\n};\n\nexport const defaultMessageActionSet: MessageActionSetItem[] = [\n  {\n    Component: DefaultMessageActionComponents.quick.DropdownToggle,\n    placement: 'quick-dropdown-toggle',\n  },\n  {\n    Component: DefaultMessageActionComponents.quick.Reply,\n    placement: 'quick',\n    type: 'reply',\n  },\n  {\n    Component: DefaultMessageActionComponents.quick.React,\n    placement: 'quick',\n    type: 'react',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.React,\n    placement: 'dropdown',\n    type: 'react',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.ThreadReply,\n    placement: 'dropdown',\n    type: 'reply',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Quote,\n    placement: 'dropdown',\n    type: 'quote',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Download,\n    placement: 'dropdown',\n    type: 'download',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Pin,\n    placement: 'dropdown',\n    type: 'pin',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.CopyMessageText,\n    placement: 'dropdown',\n    type: 'copyMessageText',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Resend,\n    placement: 'dropdown',\n    type: 'resendMessage',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Edit,\n    placement: 'dropdown',\n    type: 'edit',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.MarkUnread,\n    placement: 'dropdown',\n    type: 'markUnread',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.RemindMe,\n    placement: 'dropdown',\n    type: 'remindMe',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.SaveForLater,\n    placement: 'dropdown',\n    type: 'saveForLater',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Flag,\n    placement: 'dropdown',\n    type: 'flag',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Mute,\n    placement: 'dropdown',\n    type: 'mute',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.Delete,\n    placement: 'dropdown',\n    type: 'delete',\n  },\n  {\n    Component: DefaultMessageActionComponents.dropdown.BlockUser,\n    placement: 'dropdown',\n    type: 'blockUser',\n  },\n] as const;\n","import { useMemo } from 'react';\n\nexport const useSplitActionSet = <\n  T extends\n    | { placement: 'quick' }\n    | { placement: 'dropdown' }\n    | { placement: 'quick-dropdown-toggle' },\n>(\n  actionSet: T[],\n) =>\n  useMemo(() => {\n    const quickActionSet: Extract<T, { placement: 'quick' }>[] = [];\n    const dropdownActionSet: Extract<T, { placement: 'dropdown' }>[] = [];\n    let quickDropdownToggleAction:\n      | Extract<T, { placement: 'quick-dropdown-toggle' }>\n      | undefined;\n\n    for (const action of actionSet) {\n      if (action.placement === 'quick')\n        quickActionSet.push(action as (typeof quickActionSet)[number]);\n      if (action.placement === 'dropdown')\n        dropdownActionSet.push(action as (typeof dropdownActionSet)[number]);\n      if (action.placement === 'quick-dropdown-toggle') {\n        quickDropdownToggleAction ??= action as Extract<\n          T,\n          { placement: 'quick-dropdown-toggle' }\n        >;\n      }\n    }\n\n    return { dropdownActionSet, quickActionSet, quickDropdownToggleAction } as const;\n  }, [actionSet]);\n","import clsx from 'clsx';\nimport React, { type ComponentPropsWithRef, useState } from 'react';\n\nimport {\n  useComponentContext,\n  useMessageContext,\n  useTranslationContext,\n} from '../../context';\nimport {\n  ContextMenu,\n  type ContextMenuItemProps,\n  useDialogIsOpen,\n  useDialogOnNearestManager,\n} from '../Dialog';\nimport { useBaseMessageActionSetFilter } from './hooks';\nimport { defaultMessageActionSet } from './MessageActions.defaults';\nimport { type MESSAGE_ACTIONS } from '../Message';\nimport { ReactionSelector } from '../Reactions';\nimport { useSplitActionSet } from '../Chat/hooks/useSplitActionSet';\n\ntype BaseMessageActionSetItem = {\n  type: keyof typeof MESSAGE_ACTIONS | (string & {});\n};\n\nexport type QuickMessageActionSetItem = BaseMessageActionSetItem & {\n  Component: React.ComponentType;\n  placement: 'quick';\n};\n\nexport type DropdownMessageActionSetItem = BaseMessageActionSetItem & {\n  Component: React.ComponentType<ContextMenuItemProps>;\n  placement: 'dropdown';\n};\n\nexport type QuickDropdownToggleActionSetItem = {\n  Component: React.ComponentType<ComponentPropsWithRef<'button'>>;\n  placement: 'quick-dropdown-toggle';\n};\n\nexport type MessageActionSetItem =\n  | QuickMessageActionSetItem\n  | DropdownMessageActionSetItem\n  | QuickDropdownToggleActionSetItem;\n\nexport type MessageActionsProps = {\n  disableBaseMessageActionSetFilter?: boolean;\n  messageActionSet?: MessageActionSetItem[];\n};\n\ninterface MessageActionsInterface {\n  (props: MessageActionsProps): React.ReactNode;\n  getDialogId: (_: { messageId: string }) => string;\n  displayName: string;\n}\n\n/**\n * A new actions component to replace current `MessageOptions` component.\n * Exports from `stream-chat-react/experimental` __MIGHT__ change - use with caution\n * and follow release notes in case you notice unexpected behavior.\n */\nexport const MessageActions: MessageActionsInterface = ({\n  disableBaseMessageActionSetFilter = false,\n  messageActionSet = defaultMessageActionSet,\n}) => {\n  const { isMyMessage, message, threadList } = useMessageContext();\n  const { ContextMenu: ContextMenuComponent = ContextMenu } = useComponentContext();\n  const { t } = useTranslationContext();\n  const [actionsBoxButtonElement, setActionsBoxButtonElement] =\n    useState<HTMLButtonElement | null>(null);\n\n  const filteredMessageActionSet = useBaseMessageActionSetFilter(\n    messageActionSet,\n    disableBaseMessageActionSetFilter,\n  );\n\n  const { dropdownActionSet, quickActionSet, quickDropdownToggleAction } =\n    useSplitActionSet(filteredMessageActionSet);\n\n  const messageActionsDialogId = MessageActions.getDialogId({ messageId: message.id });\n  const reactionSelectorDialogId = ReactionSelector.getDialogId({\n    messageId: message.id,\n    threadList,\n  });\n  const dropdownReactionSelectorDialogId = `${reactionSelectorDialogId}-dropdown`;\n  const { dialog, dialogManager } = useDialogOnNearestManager({\n    id: messageActionsDialogId,\n  });\n  const messageActionsDialogIsOpen = useDialogIsOpen(\n    messageActionsDialogId,\n    dialogManager?.id,\n  );\n  const reactionSelectorDialogIsOpen = useDialogIsOpen(\n    reactionSelectorDialogId,\n    dialogManager?.id,\n  );\n  const dropdownReactionSelectorDialogIsOpen = useDialogIsOpen(\n    dropdownReactionSelectorDialogId,\n    dialogManager?.id,\n  );\n\n  // do not render anything if total action count is zero\n  if (dropdownActionSet.length + quickActionSet.length === 0) {\n    return null;\n  }\n\n  return (\n    <div\n      className={clsx('str-chat__message-options', {\n        'str-chat__message-options--active':\n          messageActionsDialogIsOpen ||\n          reactionSelectorDialogIsOpen ||\n          dropdownReactionSelectorDialogIsOpen,\n      })}\n    >\n      {quickDropdownToggleAction && dropdownActionSet.length > 0 && (\n        <>\n          <quickDropdownToggleAction.Component ref={setActionsBoxButtonElement} />\n\n          <ContextMenuComponent\n            aria-label={t('aria/Message Actions')}\n            backLabel={t('Back')}\n            className={clsx('str-chat__message-actions-box', {\n              'str-chat__message-actions-box--hidden':\n                dropdownReactionSelectorDialogIsOpen,\n              'str-chat__message-actions-box--open': messageActionsDialogIsOpen,\n            })}\n            dialogManagerId={dialogManager?.id}\n            id={messageActionsDialogId}\n            onClose={dialog?.close}\n            placement={isMyMessage() ? 'top-end' : 'top-start'}\n            referenceElement={actionsBoxButtonElement}\n            tabIndex={-1}\n            trapFocus\n          >\n            {dropdownActionSet.map(({ Component, type }) => (\n              <Component key={type} />\n            ))}\n          </ContextMenuComponent>\n        </>\n      )}\n      {quickActionSet.map(({ Component: QuickActionComponent, type }) => (\n        <QuickActionComponent key={type} />\n      ))}\n    </div>\n  );\n};\n\nMessageActions.getDialogId = ({ messageId }) => `message-actions-${messageId}`;\n\nMessageActions.displayName = 'MessageActions';\n","import React, { useMemo, useState } from 'react';\nimport clsx from 'clsx';\nimport { MessageBouncePrompt as DefaultMessageBouncePrompt } from '../MessageBounce';\nimport { MessageDeletedBubble as DefaultMessageDeletedBubble } from './MessageDeletedBubble';\nimport { MessageBlocked as DefaultMessageBlocked } from './MessageBlocked';\nimport { MessageActions as DefaultMessageActions } from '../MessageActions';\nimport { MessageRepliesCountButton as DefaultMessageRepliesCountButton } from './MessageRepliesCountButton';\nimport { MessageStatus as DefaultMessageStatus } from './MessageStatus';\nimport { MessageText } from './MessageText';\nimport { MessageEditedIndicator as DefaultMessageEditedIndicator } from './MessageEditedIndicator';\nimport { MessageTimestamp as DefaultMessageTimestamp } from './MessageTimestamp';\nimport { StreamedMessageText as DefaultStreamedMessageText } from './StreamedMessageText';\nimport { isDateSeparatorMessage } from '../MessageList';\nimport { MessageAlsoSentInChannelIndicator as DefaultMessageAlsoSentInChannelIndicator } from './MessageAlsoSentInChannelIndicator';\nimport { ReminderNotification as DefaultReminderNotification } from './ReminderNotification';\nimport { MessageTranslationIndicator as DefaultMessageTranslationIndicator } from './MessageTranslationIndicator';\nimport { useMessageReminder } from './hooks';\nimport {\n  areMessageUIPropsEqual,\n  countEmojis,\n  isMessageBlocked,\n  isMessageBounced,\n  isMessageDeleted,\n  isMessageEdited,\n  isMessageErrorRetryable,\n  messageHasAttachments,\n  messageHasGiphyAttachment,\n  messageHasQuotedMessage,\n  messageHasReactions,\n  messageHasSingleAttachment,\n  messageTextHasEmojisOnly,\n} from './utils';\n\nimport { Avatar as DefaultAvatar } from '../Avatar';\nimport { Attachment as DefaultAttachment } from '../Attachment';\nimport { Poll } from '../Poll';\nimport { MessageReactions as DefaultMessageReactions } from '../Reactions';\nimport { MessageBounceModal } from '../MessageBounce/MessageBounceModal';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport type { MessageContextValue } from '../../context/MessageContext';\nimport { useMessageContext } from '../../context/MessageContext';\n\nimport {\n  useChannelStateContext,\n  useChatContext,\n  useTranslationContext,\n} from '../../context';\n\nimport type { MessageUIComponentProps } from './types';\nimport { PinIndicator as DefaultPinIndicator } from './PinIndicator';\nimport { QuotedMessage as DefaultQuotedMessage } from './QuotedMessage';\nimport { MessageBubble } from './MessageBubble';\nimport { ErrorBadge } from '../Badge';\n\ntype MessageUIWithContextProps = MessageContextValue;\n\nconst MessageUIWithContext = ({\n  endOfGroup,\n  firstOfGroup,\n  groupedByUser,\n  handleAction,\n  handleOpenThread,\n  highlighted,\n  isMessageAIGenerated,\n  isMyMessage,\n  message,\n  onUserClick,\n  onUserHover,\n  renderText,\n  showAvatar = 'incoming',\n  threadList,\n}: MessageUIWithContextProps) => {\n  const { channel } = useChannelStateContext();\n  const { client } = useChatContext();\n  const { t } = useTranslationContext('MessageUI');\n  const [isBounceDialogOpen, setIsBounceDialogOpen] = useState(false);\n  const reminder = useMessageReminder(message.id);\n\n  const {\n    Attachment = DefaultAttachment,\n    Avatar = DefaultAvatar,\n    MessageActions = DefaultMessageActions,\n    MessageAlsoSentInChannelIndicator = DefaultMessageAlsoSentInChannelIndicator,\n    MessageBlocked = DefaultMessageBlocked,\n    MessageBouncePrompt = DefaultMessageBouncePrompt,\n    MessageDeleted,\n    MessageDeletedBubble = DefaultMessageDeletedBubble,\n    MessageEditedIndicator = DefaultMessageEditedIndicator,\n    MessageReactions = DefaultMessageReactions,\n    MessageRepliesCountButton = DefaultMessageRepliesCountButton,\n    MessageStatus = DefaultMessageStatus,\n    MessageTimestamp = DefaultMessageTimestamp,\n    MessageTranslationIndicator = DefaultMessageTranslationIndicator,\n    PinIndicator = DefaultPinIndicator,\n    QuotedMessage = DefaultQuotedMessage,\n    ReminderNotification = DefaultReminderNotification,\n    StreamedMessageText = DefaultStreamedMessageText,\n  } = useComponentContext('MessageUI');\n\n  const isAIGenerated = useMemo(\n    () => isMessageAIGenerated?.(message),\n    [isMessageAIGenerated, message],\n  );\n  const isDeleted = isMessageDeleted(message);\n\n  const finalAttachments = useMemo(\n    () =>\n      !message.shared_location && !message.attachments\n        ? []\n        : !message.shared_location\n          ? message.attachments\n          : [message.shared_location, ...(message.attachments ?? [])],\n    [message],\n  );\n\n  if (isDateSeparatorMessage(message)) {\n    return null;\n  }\n\n  if (MessageDeleted && isDeleted) {\n    return <MessageDeleted message={message} />;\n  }\n\n  if (isMessageBlocked(message)) {\n    return <MessageBlocked />;\n  }\n\n  const poll = message.poll_id && client.polls.fromState(message.poll_id);\n\n  const memberCount = Object.keys(channel?.state?.members ?? {}).length;\n  const hasAttachment = !isDeleted && messageHasAttachments(message);\n  const hasSingleAttachment = !isDeleted && messageHasSingleAttachment(message);\n  const hasGiphyAttachment = !isDeleted && messageHasGiphyAttachment(message);\n  const hasReactions = !isDeleted && messageHasReactions(message);\n  const hasQuotedMessage = !isDeleted && messageHasQuotedMessage(message);\n  const textHasEmojisOnly = !isDeleted && messageTextHasEmojisOnly(message);\n\n  const allowRetry = isMessageErrorRetryable(message);\n  const isBounced = isMessageBounced(message);\n  const isEdited = isMessageEdited(message) && !isAIGenerated;\n\n  const showMetadata = !groupedByUser || endOfGroup;\n  const showReplyCountButton = !threadList && !!message.reply_count;\n\n  const rootClassName = clsx(\n    'str-chat__message',\n    `str-chat__message--${message.type}`,\n    `str-chat__message--${message.status}`,\n    {\n      'str-chat__message--has-attachment': hasAttachment,\n      'str-chat__message--has-giphy-attachment': hasGiphyAttachment,\n      'str-chat__message--has-no-text': !message.text,\n      'str-chat__message--has-quoted-message': hasQuotedMessage,\n      'str-chat__message--has-single-attachment': hasSingleAttachment,\n      'str-chat__message--has-text': !!message.text,\n      'str-chat__message--highlighted': highlighted,\n      'str-chat__message--is-emoji-only': textHasEmojisOnly,\n      [`str-chat__message--is-emoji-only-count-${countEmojis(message.text)}`]:\n        textHasEmojisOnly,\n      'str-chat__message--me': isMyMessage(),\n      'str-chat__message--other': !isMyMessage(),\n      'str-chat__message--pinned': message.pinned,\n      'str-chat__message--with-avatar': (() => {\n        if (!message.user) return false;\n        if (showAvatar === 'incoming') return !isMyMessage();\n        if (showAvatar === 'outgoing') return isMyMessage();\n        return showAvatar;\n      })(),\n      'str-chat__message--with-reactions': hasReactions,\n      'str-chat__message-send-can-be-retried':\n        message?.status === 'failed' && message?.error?.status !== 403,\n      'str-chat__message-with-thread-link': showReplyCountButton,\n      'str-chat__virtual-message__wrapper--end': endOfGroup,\n      'str-chat__virtual-message__wrapper--first': firstOfGroup,\n      'str-chat__virtual-message__wrapper--group': groupedByUser,\n    },\n  );\n\n  let handleClick: (() => void) | undefined;\n\n  if (isBounced) {\n    handleClick = () => setIsBounceDialogOpen(true);\n  }\n\n  const isMessageInnerInteractive = !!handleClick;\n  const messageInnerAriaLabel = isMessageInnerInteractive\n    ? t('aria/Review bounced message')\n    : undefined;\n\n  const handleMessageInnerKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n    if (!handleClick || (event.key !== 'Enter' && event.key !== ' ')) return;\n\n    event.preventDefault();\n    handleClick();\n  };\n\n  return (\n    <>\n      {isBounceDialogOpen && (\n        <MessageBounceModal\n          MessageBouncePrompt={MessageBouncePrompt}\n          onClose={() => setIsBounceDialogOpen(false)}\n          open={isBounceDialogOpen}\n        />\n      )}\n      <div className={rootClassName} key={message.id}>\n        {message.pinned && <PinIndicator message={message} />}\n        {message.show_in_channel && <MessageAlsoSentInChannelIndicator />}\n        {!!reminder && <ReminderNotification reminder={reminder} />}\n        <MessageTranslationIndicator message={message} />\n        {message.user && (\n          <Avatar\n            className='str-chat__avatar--with-border'\n            imageUrl={message.user.image}\n            onClick={onUserClick}\n            onMouseOver={onUserHover}\n            size='md'\n            userName={message.user.name || message.user.id}\n          />\n        )}\n        <div\n          aria-label={messageInnerAriaLabel}\n          className={clsx('str-chat__message-inner', {\n            'str-chat__message-inner--error': allowRetry || isBounced,\n          })}\n          data-testid='message-inner'\n          onClick={handleClick}\n          onKeyDown={isMessageInnerInteractive ? handleMessageInnerKeyDown : undefined}\n          role={isMessageInnerInteractive ? 'button' : undefined}\n          tabIndex={isMessageInnerInteractive ? 0 : undefined}\n        >\n          {!isDeleted && <MessageActions />}\n          {showReplyCountButton && (\n            <MessageRepliesCountButton\n              onClick={handleOpenThread}\n              reply_count={message.reply_count}\n              thread_participants={message.thread_participants}\n            />\n          )}\n          {isDeleted ? (\n            <MessageDeletedBubble />\n          ) : (\n            <>\n              <MessageBubble>\n                {poll && <Poll poll={poll} />}\n                {message.quoted_message && <QuotedMessage />}\n                {finalAttachments?.length ? (\n                  <Attachment\n                    actionHandler={handleAction}\n                    attachments={finalAttachments}\n                  />\n                ) : null}\n                {isAIGenerated ? (\n                  <StreamedMessageText message={message} renderText={renderText} />\n                ) : (\n                  <MessageText message={message} renderText={renderText} />\n                )}\n              </MessageBubble>\n              <div className='str-chat__message-reactions-host'>\n                {hasReactions && <MessageReactions reverse />}\n              </div>\n              <div className='str-chat__message-error-indicator'>\n                <ErrorBadge />\n              </div>\n            </>\n          )}\n        </div>\n        {showMetadata && (\n          <div className='str-chat__message-metadata'>\n            <MessageStatus />\n            {!isMyMessage() && !!message.user && memberCount > 2 && (\n              <span className='str-chat__message-metadata__name'>\n                {message.user.name || message.user.id}\n              </span>\n            )}\n            <MessageTimestamp customClass='str-chat__message-metadata__timestamp' />\n            {!isDeleted && isEdited && <MessageEditedIndicator />}\n          </div>\n        )}\n      </div>\n    </>\n  );\n};\n\nconst MemoizedMessageUI = React.memo(\n  MessageUIWithContext,\n  areMessageUIPropsEqual,\n) as typeof MessageUIWithContext;\n\n/**\n * The default UI component that renders a message and receives functionality and logic from the MessageContext.\n */\nexport const MessageUI = (props: MessageUIComponentProps) => {\n  const messageContext = useMessageContext('MessageUI');\n\n  return <MemoizedMessageUI {...messageContext} {...props} />;\n};\n","import React, { useCallback, useMemo } from 'react';\n\nimport {\n  useActionHandler,\n  useDeleteHandler,\n  useFlagHandler,\n  useMarkUnreadHandler,\n  useMentionsHandler,\n  useMuteHandler,\n  useOpenThreadHandler,\n  usePinHandler,\n  useReactionHandler,\n  useReactionsFetcher,\n  useRetryHandler,\n  useUserHandler,\n  useUserRole,\n} from './hooks';\nimport { areMessagePropsEqual, getMessageActions, MESSAGE_ACTIONS } from './utils';\n\nimport type { MessageContextValue } from '../../context';\nimport {\n  MessageProvider,\n  useChannelStateContext,\n  useChatContext,\n  useComponentContext,\n  useMessageTranslationViewContext,\n} from '../../context';\n\nimport { MessageUI as DefaultMessageUI } from './MessageUI';\n\nimport type { MessageProps } from './types';\n\ntype MessagePropsToOmit =\n  | 'onMentionsClick'\n  | 'onMentionsHover'\n  | 'openThread'\n  | 'retrySendMessage';\n\ntype MessageContextPropsToPick =\n  | 'handleAction'\n  | 'handleDelete'\n  | 'handleFetchReactions'\n  | 'handleFlag'\n  | 'handleMarkUnread'\n  | 'handleMute'\n  | 'handleOpenThread'\n  | 'handlePin'\n  | 'handleReaction'\n  | 'handleRetry'\n  | 'mutes'\n  | 'onMentionsClickMessage'\n  | 'onMentionsHoverMessage'\n  | 'reactionDetailsSort'\n  | 'sortReactions';\n\ntype MessageWithContextProps = Omit<MessageProps, MessagePropsToOmit> &\n  Pick<MessageContextValue, MessageContextPropsToPick> & {\n    canPin: boolean;\n    userRoles: ReturnType<typeof useUserRole>;\n  };\n\nconst MessageWithContext = (props: MessageWithContextProps) => {\n  const {\n    canPin,\n    Message: propMessage,\n    message,\n    messageActions = Object.keys(MESSAGE_ACTIONS),\n    onUserClick: propOnUserClick,\n    onUserHover: propOnUserHover,\n    userRoles,\n  } = props;\n\n  const { client, isMessageAIGenerated } = useChatContext('Message');\n  const { channelConfig, read } = useChannelStateContext('Message');\n  const {\n    Message: contextMessage = DefaultMessageUI,\n    // TODO: remove this passthrough once we drop Message from the ComponentContext\n    MessageUI: contextMessageUI = contextMessage,\n  } = useComponentContext('Message');\n  const { getTranslationView, setTranslationView: setTranslationViewInContext } =\n    useMessageTranslationViewContext();\n\n  const translationView = getTranslationView(message.id, !!message.i18n);\n  const setTranslationView = useCallback(\n    (view: 'original' | 'translated') => setTranslationViewInContext(message.id, view),\n    [message.id, setTranslationViewInContext],\n  );\n\n  const actionsEnabled = message.type === 'regular' && message.status === 'received';\n  const MessageUIComponent = propMessage ?? contextMessageUI;\n\n  const { onUserClick, onUserHover } = useUserHandler(message, {\n    onUserClickHandler: propOnUserClick,\n    onUserHoverHandler: propOnUserHover,\n  });\n\n  const {\n    canDelete,\n    canEdit,\n    canFlag,\n    canMarkUnread,\n    canMute,\n    canQuote,\n    canReact,\n    canReply,\n    isMyMessage,\n  } = userRoles;\n\n  const messageIsUnread = useMemo(\n    () =>\n      !!(\n        !isMyMessage &&\n        client.user?.id &&\n        read &&\n        (!read[client.user.id] ||\n          (message?.created_at &&\n            new Date(message.created_at).getTime() >\n              read[client.user.id].last_read.getTime()))\n      ),\n    [client, isMyMessage, message.created_at, read],\n  );\n\n  const messageActionsHandler = useCallback(\n    () =>\n      getMessageActions(\n        messageActions,\n        {\n          canDelete,\n          canEdit,\n          canFlag,\n          canMarkUnread,\n          canMute,\n          canPin,\n          canQuote,\n          canReact,\n          canReply,\n        },\n        channelConfig,\n      ),\n\n    [\n      messageActions,\n      canDelete,\n      canEdit,\n      canFlag,\n      canMarkUnread,\n      canMute,\n      canPin,\n      canQuote,\n      canReact,\n      canReply,\n      channelConfig,\n    ],\n  );\n\n  const {\n    canPin: canPinPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    messageActions: messageActionsPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    onUserClick: onUserClickPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    onUserHover: onUserHoverPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    userRoles: userRolesPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    ...rest\n  } = props;\n\n  const messageContextValue: MessageContextValue = {\n    ...rest,\n    actionsEnabled,\n    getMessageActions: messageActionsHandler,\n    isMessageAIGenerated,\n    isMyMessage: () => isMyMessage,\n    messageIsUnread,\n    onUserClick,\n    onUserHover,\n    setTranslationView,\n    translationView,\n  };\n\n  return (\n    <MessageProvider value={messageContextValue}>\n      <MessageUIComponent />\n    </MessageProvider>\n  );\n};\n\nconst MemoizedMessage = React.memo(\n  MessageWithContext,\n  areMessagePropsEqual,\n) as typeof MessageWithContext;\n\n/**\n * The Message component is a context provider which implements all the logic required for rendering\n * an individual message. The actual UI of the message is delegated via the Message prop on Channel.\n */\nexport const Message = (props: MessageProps) => {\n  const {\n    closeReactionSelectorOnClick,\n    disableQuotedMessages,\n    message,\n    onMentionsClick: propOnMentionsClick,\n    onMentionsHover: propOnMentionsHover,\n    openThread: propOpenThread,\n    reactionDetailsSort,\n    retrySendMessage: propRetrySendMessage,\n    sortReactions,\n  } = props;\n\n  const { highlightedMessageId, mutes } = useChannelStateContext('Message');\n\n  const handleAction = useActionHandler(message);\n  const handleOpenThread = useOpenThreadHandler(message, propOpenThread);\n  const handleReaction = useReactionHandler(message);\n  const handleRetry = useRetryHandler(propRetrySendMessage);\n  const userRoles = useUserRole(message, disableQuotedMessages);\n\n  const handleFetchReactions = useReactionsFetcher(message);\n\n  const handleDelete = useDeleteHandler(message);\n\n  const handleFlag = useFlagHandler(message);\n\n  const handleMarkUnread = useMarkUnreadHandler(message);\n\n  const handleMute = useMuteHandler(message);\n\n  const { onMentionsClick, onMentionsHover } = useMentionsHandler(message, {\n    onMentionsClick: propOnMentionsClick,\n    onMentionsHover: propOnMentionsHover,\n  });\n\n  const { canPin, handlePin } = usePinHandler(message);\n\n  const highlighted = highlightedMessageId === message.id;\n\n  return (\n    <MemoizedMessage\n      additionalMessageComposerProps={props.additionalMessageComposerProps}\n      autoscrollToBottom={props.autoscrollToBottom}\n      canPin={canPin}\n      closeReactionSelectorOnClick={closeReactionSelectorOnClick}\n      deliveredTo={props.deliveredTo}\n      disableQuotedMessages={props.disableQuotedMessages}\n      formatDate={props.formatDate}\n      groupStyles={props.groupStyles}\n      handleAction={handleAction}\n      handleDelete={handleDelete}\n      handleFetchReactions={handleFetchReactions}\n      handleFlag={handleFlag}\n      handleMarkUnread={handleMarkUnread}\n      handleMute={handleMute}\n      handleOpenThread={handleOpenThread}\n      handlePin={handlePin}\n      handleReaction={handleReaction}\n      handleRetry={handleRetry}\n      highlighted={highlighted}\n      initialMessage={props.initialMessage}\n      lastOwnMessage={props.lastOwnMessage}\n      lastReceivedId={props.lastReceivedId}\n      message={message}\n      Message={props.Message}\n      messageActions={props.messageActions}\n      messageListRect={props.messageListRect}\n      mutes={mutes}\n      onMentionsClickMessage={onMentionsClick}\n      onMentionsHoverMessage={onMentionsHover}\n      onUserClick={props.onUserClick}\n      onUserHover={props.onUserHover}\n      reactionDetailsSort={reactionDetailsSort}\n      readBy={props.readBy}\n      renderText={props.renderText}\n      returnAllReadData={props.returnAllReadData}\n      sortReactions={sortReactions}\n      threadList={props.threadList}\n      unsafeHTML={props.unsafeHTML}\n      userRoles={userRoles}\n    />\n  );\n};\n","import React from 'react';\n\nimport { Message } from '../Message/Message';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type GiphyPreviewMessageProps = {\n  message: LocalMessage;\n};\n\nexport const GiphyPreviewMessage = (props: GiphyPreviewMessageProps) => {\n  const { message } = props;\n\n  return (\n    <div className='giphy-preview-message'>\n      <Message message={message} />\n    </div>\n  );\n};\n","import { useMemo } from 'react';\n\nimport type { GroupStyle, ProcessMessagesParams, RenderedMessage } from '../../utils';\nimport { getGroupStyles, insertIntro, processMessages } from '../../utils';\n\nimport { useChatContext } from '../../../../context/ChatContext';\nimport { useComponentContext } from '../../../../context/ComponentContext';\n\nimport type { Channel, LocalMessage } from 'stream-chat';\n\nexport const useEnrichedMessages = (args: {\n  channel: Channel;\n  disableDateSeparator: boolean;\n  hideDeletedMessages: boolean;\n  hideNewMessageSeparator: boolean;\n  messages: LocalMessage[];\n  noGroupByUser: boolean;\n  groupStyles?: (\n    message: RenderedMessage,\n    previousMessage: RenderedMessage,\n    nextMessage: RenderedMessage,\n    noGroupByUser: boolean,\n    maxTimeBetweenGroupedMessages?: number,\n  ) => GroupStyle;\n  headerPosition?: number;\n  maxTimeBetweenGroupedMessages?: number;\n  reviewProcessedMessage?: ProcessMessagesParams['reviewProcessedMessage'];\n}) => {\n  const {\n    channel,\n    disableDateSeparator,\n    groupStyles,\n    headerPosition,\n    hideDeletedMessages,\n    hideNewMessageSeparator,\n    maxTimeBetweenGroupedMessages,\n    messages,\n    noGroupByUser,\n    reviewProcessedMessage,\n  } = args;\n\n  const { client } = useChatContext('useEnrichedMessages');\n  const { HeaderComponent } = useComponentContext('useEnrichedMessages');\n\n  const lastRead = useMemo(() => channel.lastRead?.(), [channel]);\n\n  const enableDateSeparator = !disableDateSeparator;\n\n  let messagesWithDates =\n    !enableDateSeparator && !hideDeletedMessages && hideNewMessageSeparator\n      ? messages\n      : processMessages({\n          enableDateSeparator,\n          hideDeletedMessages,\n          hideNewMessageSeparator,\n          lastRead,\n          messages,\n          reviewProcessedMessage,\n          userId: client.userID || '',\n        });\n\n  if (HeaderComponent) {\n    messagesWithDates = insertIntro(messagesWithDates, headerPosition);\n  }\n\n  const groupStylesFn = groupStyles || getGroupStyles;\n  const messageGroupStyles = useMemo(\n    () =>\n      messagesWithDates.reduce<Record<string, GroupStyle>>((acc, message, i) => {\n        const style = groupStylesFn(\n          message,\n          messagesWithDates[i - 1],\n          messagesWithDates[i + 1],\n          noGroupByUser,\n          maxTimeBetweenGroupedMessages,\n        );\n        if (style) acc[message.id] = style;\n        return acc;\n      }, {}),\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [maxTimeBetweenGroupedMessages, messagesWithDates, noGroupByUser],\n  );\n\n  return { messageGroupStyles, messages: messagesWithDates };\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport throttle from 'lodash.throttle';\n\nimport type { RenderedMessage } from '../../utils';\n\nconst DATE_SEPARATOR_SELECTOR =\n  '.str-chat__date-separator:not(.str-chat__date-separator--floating)';\nconst THROTTLE_MS = 100;\n\nexport type UseFloatingDateSeparatorMessageListParams = {\n  disableDateSeparator: boolean;\n  listElement: HTMLDivElement | null;\n  processedMessages: RenderedMessage[];\n};\n\nexport type UseFloatingDateSeparatorMessageListResult = {\n  floatingDate: Date | null;\n  showFloatingDate: boolean;\n};\n\n/**\n * For non-virtualized MessageList: keeps the floating date synced with the\n * separator currently pinned to the top boundary of the list viewport.\n */\nexport const useFloatingDateSeparatorMessageList = ({\n  disableDateSeparator,\n  listElement,\n  processedMessages,\n}: UseFloatingDateSeparatorMessageListParams): UseFloatingDateSeparatorMessageListResult => {\n  const [state, setState] = useState<{ date: Date | null; visible: boolean }>({\n    date: null,\n    visible: false,\n  });\n\n  const update = useCallback(() => {\n    if (disableDateSeparator || !listElement || processedMessages.length === 0) {\n      setState({ date: null, visible: false });\n      return;\n    }\n\n    const separators = listElement.querySelectorAll<HTMLElement>(DATE_SEPARATOR_SELECTOR);\n    if (separators.length === 0) {\n      setState({ date: null, visible: false });\n      return;\n    }\n\n    const containerRect = listElement.getBoundingClientRect();\n    let bestDate: Date | null = null;\n    let bestTop = -Infinity;\n\n    for (const el of separators) {\n      const rect = el.getBoundingClientRect();\n      const dataDate = el.getAttribute('data-date');\n      if (!dataDate) continue;\n\n      const isAtOrAboveTopBoundary = rect.top <= containerRect.top;\n\n      if (isAtOrAboveTopBoundary && rect.top > bestTop) {\n        bestTop = rect.top;\n        const d = new Date(dataDate);\n        if (!isNaN(d.getTime())) bestDate = d;\n      }\n    }\n\n    setState({\n      date: bestDate,\n      visible: bestDate !== null,\n    });\n  }, [disableDateSeparator, listElement, processedMessages]);\n\n  useEffect(() => {\n    if (!listElement) return;\n\n    const throttled = throttle(update, THROTTLE_MS);\n\n    throttled();\n    listElement.addEventListener('scroll', throttled);\n\n    if (typeof ResizeObserver === 'undefined') {\n      return () => {\n        listElement.removeEventListener('scroll', throttled);\n        throttled.cancel();\n      };\n    }\n\n    const resizeObserver = new ResizeObserver(throttled);\n    resizeObserver.observe(listElement);\n\n    return () => {\n      listElement.removeEventListener('scroll', throttled);\n      resizeObserver.disconnect();\n      throttled.cancel();\n    };\n  }, [listElement, update]);\n\n  return {\n    floatingDate: state.date,\n    showFloatingDate: state.visible,\n  };\n};\n","import { useMemo } from 'react';\nimport type { Channel, LocalMessage, UserResponse } from 'stream-chat';\n\ntype UseLastReadDataParams = {\n  channel: Channel;\n  messages: LocalMessage[];\n  returnAllReadData: boolean;\n  lastOwnMessage?: LocalMessage;\n};\n\nexport const useLastReadData = (props: UseLastReadDataParams) => {\n  const { channel, lastOwnMessage, messages, returnAllReadData } = props;\n\n  return useMemo(() => {\n    if (returnAllReadData) {\n      return messages.reduce(\n        (acc, msg) => {\n          acc[msg.id] = channel.messageReceiptsTracker.readersForMessage({\n            msgId: msg.id,\n            timestampMs: msg.created_at.getTime(),\n          });\n          return acc;\n        },\n        {} as Record<string, UserResponse[]>,\n      );\n    }\n\n    if (!lastOwnMessage) return {};\n    return {\n      [lastOwnMessage.id]: channel.messageReceiptsTracker.readersForMessage({\n        msgId: lastOwnMessage.id,\n        timestampMs: lastOwnMessage.created_at.getTime(),\n      }),\n    };\n  }, [channel, lastOwnMessage, messages, returnAllReadData]);\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport type { Channel, LocalMessage, UserResponse } from 'stream-chat';\n\ntype UseLastDeliveredDataParams = {\n  channel: Channel;\n  messages: LocalMessage[];\n  returnAllReadData: boolean;\n  lastOwnMessage?: LocalMessage;\n};\n\nexport const useLastDeliveredData = (\n  props: UseLastDeliveredDataParams,\n): Record<string, UserResponse[]> => {\n  const { channel, lastOwnMessage, messages, returnAllReadData } = props;\n\n  const calculateForAll = useCallback(\n    () =>\n      messages.reduce(\n        (acc, msg) => {\n          acc[msg.id] = channel.messageReceiptsTracker.deliveredForMessage({\n            msgId: msg.id,\n            timestampMs: msg.created_at.getTime(),\n          });\n          return acc;\n        },\n        {} as Record<string, UserResponse[]>,\n      ),\n    [channel, messages],\n  );\n\n  const calculateForLastOwn = useCallback(() => {\n    if (!lastOwnMessage) return {};\n    return {\n      [lastOwnMessage.id]: channel.messageReceiptsTracker.deliveredForMessage({\n        msgId: lastOwnMessage.id,\n        timestampMs: lastOwnMessage.created_at.getTime(),\n      }),\n    };\n  }, [channel, lastOwnMessage]);\n\n  const [deliveredTo, setDeliveredTo] = useState<Record<string, UserResponse[]>>(\n    returnAllReadData ? calculateForAll : calculateForLastOwn,\n  );\n\n  useEffect(() => {\n    if (!returnAllReadData) return;\n    setDeliveredTo(calculateForAll);\n    return channel.on('message.delivered', () => setDeliveredTo(calculateForAll))\n      .unsubscribe;\n  }, [channel, calculateForAll, returnAllReadData]);\n\n  useEffect(() => {\n    if (returnAllReadData) return;\n    else setDeliveredTo(calculateForLastOwn);\n    return channel.on('message.delivered', () => setDeliveredTo(calculateForLastOwn))\n      .unsubscribe;\n  }, [channel, calculateForLastOwn, returnAllReadData]);\n\n  return deliveredTo;\n};\n","import type React from 'react';\nimport { useMemo } from 'react';\n\nimport { useLastReadData } from '../useLastReadData';\nimport type { GroupStyle, RenderedMessage } from '../../utils';\nimport { getLastReceived } from '../../utils';\n\nimport { useChatContext } from '../../../../context/ChatContext';\nimport { useComponentContext } from '../../../../context/ComponentContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ChannelUnreadUiState } from '../../../../types/types';\nimport type { MessageRenderer, SharedMessageProps } from '../../renderMessages';\nimport { useChannelStateContext } from '../../../../context';\nimport { useLastDeliveredData } from '../useLastDeliveredData';\n\ntype UseMessageListElementsProps = {\n  messages: LocalMessage[];\n  enrichedMessages: RenderedMessage[];\n  internalMessageProps: SharedMessageProps;\n  messageGroupStyles: Record<string, GroupStyle>;\n  renderMessages: MessageRenderer;\n  returnAllReadData: boolean;\n  threadList: boolean;\n  channelUnreadUiState?: ChannelUnreadUiState;\n  lastOwnMessage?: LocalMessage;\n};\n\nexport const useMessageListElements = (props: UseMessageListElementsProps) => {\n  const {\n    channelUnreadUiState,\n    enrichedMessages,\n    internalMessageProps,\n    lastOwnMessage,\n    messageGroupStyles,\n    messages,\n    renderMessages,\n    returnAllReadData,\n    threadList,\n  } = props;\n\n  const { customClasses } = useChatContext('useMessageListElements');\n  const { channel } = useChannelStateContext();\n  const components = useComponentContext('useMessageListElements');\n\n  // get the readData, but only for messages submitted by the user themselves\n  const readData = useLastReadData({\n    channel,\n    lastOwnMessage,\n    messages,\n    returnAllReadData,\n  });\n\n  const ownMessagesDeliveredToOthers = useLastDeliveredData({\n    channel,\n    lastOwnMessage,\n    messages,\n    returnAllReadData,\n  });\n\n  const lastReceivedMessageId = useMemo(\n    () => getLastReceived(enrichedMessages),\n    [enrichedMessages],\n  );\n\n  const elements: React.ReactNode[] = useMemo(\n    () =>\n      renderMessages({\n        channelUnreadUiState,\n        components,\n        customClasses,\n        lastOwnMessage,\n        lastReceivedMessageId,\n        messageGroupStyles,\n        messages: enrichedMessages,\n        ownMessagesDeliveredToOthers,\n        readData,\n        sharedMessageProps: { ...internalMessageProps, returnAllReadData, threadList },\n      }),\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [\n      enrichedMessages,\n      internalMessageProps,\n      lastOwnMessage,\n      lastReceivedMessageId,\n      messageGroupStyles,\n      channelUnreadUiState,\n      readData,\n      renderMessages,\n      returnAllReadData,\n      threadList,\n    ],\n  );\n\n  return elements;\n};\n","import { useLayoutEffect, useRef } from 'react';\n\nimport { useChatContext } from '../../../../context/ChatContext';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type ContainerMeasures = {\n  offsetHeight: number;\n  scrollHeight: number;\n  scrollTop: number;\n};\n\nexport type UseMessageListScrollManagerParams = {\n  captureAnchor: () => { id: string; offsetTop: number } | null;\n  disableScrollManagement?: boolean;\n  justReachedLatestMessageSet?: boolean;\n  loadMoreScrollThreshold: number;\n  loadingMore?: boolean;\n  messages: LocalMessage[];\n  onScrollBy: (scrollBy: number) => void;\n  onScrollToTop: () => void;\n  restoreAnchor: (anchor: { id: string; offsetTop: number }) => void;\n  scrollContainerMeasures: () => ContainerMeasures;\n  scrolledUpThreshold: number;\n  scrollToBottom: () => void;\n  showNewMessages: () => void;\n};\n\n// Tracks how the current older-page pagination cycle should restore the viewport\n// once messages are prepended. The mode is chosen when loading starts and cleared\n// after the prepend has been handled.\n//\n// Modes:\n// - `idle`: there is no active older-page restoration strategy\n// - `stick-to-top`: pagination started from the absolute top, so keep the newly\n//   loaded page pinned to the top of the container\n// - `preserve-anchor`: pagination started near the top but not at the absolute\n//   top, so restore the captured anchor message to its previous viewport offset\ntype OlderPaginationState =\n  | { anchor: null; mode: 'idle' }\n  | { anchor: null; mode: 'stick-to-top' }\n  | { anchor: { id: string; offsetTop: number }; mode: 'preserve-anchor' };\n\n// An \"anchor\" is the currently visible message row we want to keep visually pinned\n// to the same spot in the viewport while older messages are inserted above it.\n// It stores:\n// - `id`: which rendered message row should stay stable\n// - `offsetTop`: how far that row sits from the top edge of the scroll container\n//\n// After a prepend, the DOM shifts downward. Restoring the anchor means finding the\n// same message row again and correcting scrollTop until it returns to that offset.\n\n// When all previous messages appear at the start of the new array, the growth\n// happened at the bottom of the list.\nconst messageIdsMatchAsPrefix = (\n  prevMessages: LocalMessage[],\n  newMessages: LocalMessage[],\n) => prevMessages.every((message, index) => message.id === newMessages[index]?.id);\n\n// When all previous messages appear at the end of the new array, the growth\n// happened at the top of the list.\nconst messageIdsMatchAsSuffix = (\n  prevMessages: LocalMessage[],\n  newMessages: LocalMessage[],\n) =>\n  prevMessages.every(\n    (message, index) =>\n      message.id === newMessages[newMessages.length - prevMessages.length + index]?.id,\n  );\n\n/**\n * Coordinates scroll-position preservation when the rendered message array changes.\n *\n * The hook distinguishes three broad cases:\n * 1. Older-page pagination prepends messages at the top of the list.\n *    This path either sticks to the top of the new page or restores a captured\n *    message anchor, depending on where the user was when pagination started.\n * 2. Newer messages append to the bottom of the list.\n *    This path preserves normal chat behavior by auto-scrolling only when the\n *    user was already near the bottom or the appended message is the user's own.\n * 3. Disjunct/overlapping page switches.\n *    These intentionally bypass prepend heuristics because the old and new arrays\n *    are not comparable as a single contiguous list.\n */\nexport function useMessageListScrollManager(params: UseMessageListScrollManagerParams) {\n  const {\n    captureAnchor,\n    disableScrollManagement = false,\n    justReachedLatestMessageSet = false,\n    loadingMore = false,\n    loadMoreScrollThreshold,\n    onScrollBy,\n    onScrollToTop,\n    restoreAnchor,\n    scrollContainerMeasures,\n    scrolledUpThreshold,\n    scrollToBottom,\n    showNewMessages,\n  } = params;\n\n  const { client } = useChatContext('useMessageListScrollManager');\n\n  const measures = useRef<ContainerMeasures>({\n    offsetHeight: 0,\n    scrollHeight: 0,\n    scrollTop: 0,\n  });\n  const messages = useRef<LocalMessage[]>(undefined);\n  const olderPaginationState = useRef<OlderPaginationState>({\n    anchor: null,\n    mode: 'idle',\n  });\n  const previousLoadingMoreRef = useRef(loadingMore);\n  const scrollTop = useRef(0);\n\n  useLayoutEffect(() => {\n    if (disableScrollManagement) {\n      // Even while management is disabled we still refresh the cached list shape,\n      // so the next enabled render compares against the most recent DOM state.\n      messages.current = params.messages;\n      measures.current = scrollContainerMeasures();\n      previousLoadingMoreRef.current = loadingMore;\n      return;\n    }\n\n    const prevMeasures = measures.current;\n    const prevMessages = messages.current;\n    const newMessages = params.messages;\n    const lastNewMessage = newMessages[newMessages.length - 1] || {};\n    const lastPrevMessage = prevMessages?.[prevMessages.length - 1];\n    const newMeasures = scrollContainerMeasures();\n    const startedLoadingOlder = loadingMore && !previousLoadingMoreRef.current;\n    const finishedLoadingOlder = !loadingMore && previousLoadingMoreRef.current;\n\n    if (startedLoadingOlder) {\n      // Read the live DOM scroll position instead of the cached ref so we get\n      // the correct value even when scrollToBottom() has been called but the\n      // async scroll event hasn't updated the ref yet (common on initial mount).\n      const liveMeasures = scrollContainerMeasures();\n      const hasOverflow = liveMeasures.scrollHeight > liveMeasures.offsetHeight;\n      const liveScrollTop = liveMeasures.scrollTop;\n\n      // Older-page pagination uses one of three modes:\n      // - `stick-to-top`: user hit the absolute top and wants to keep reading upward\n      // - `preserve-anchor`: user was only near the top, so keep the same message in view\n      // - `idle`: no restoration needed for this load cycle\n      //\n      // When the container doesn't overflow yet (e.g. content hasn't reached its\n      // final height due to font loading) the scroll position is meaningless, so\n      // default to idle to avoid a false stick-to-top that would jump the list.\n      if (!hasOverflow) {\n        olderPaginationState.current = {\n          anchor: null,\n          mode: 'idle',\n        };\n      } else if (liveScrollTop <= 1) {\n        olderPaginationState.current = {\n          anchor: null,\n          mode: 'stick-to-top',\n        };\n      } else if (liveScrollTop < loadMoreScrollThreshold) {\n        const capturedAnchor = captureAnchor();\n        if (capturedAnchor) {\n          olderPaginationState.current = {\n            anchor: capturedAnchor,\n            mode: 'preserve-anchor',\n          };\n        } else {\n          olderPaginationState.current = {\n            anchor: null,\n            mode: 'idle',\n          };\n        }\n      } else {\n        olderPaginationState.current = {\n          anchor: null,\n          mode: 'idle',\n        };\n      }\n    }\n\n    // Evaluate bottom proximity from the previous render, before any new content\n    // changes the list height and invalidates the prior bottom distance.\n    const wasAtBottom =\n      prevMeasures.scrollHeight - prevMeasures.offsetHeight - scrollTop.current <\n      scrolledUpThreshold;\n\n    if (typeof prevMessages !== 'undefined') {\n      if (prevMessages.length < newMessages.length) {\n        const messagesAddedToTop = messageIdsMatchAsSuffix(prevMessages, newMessages);\n        const messagesAddedToBottom = messageIdsMatchAsPrefix(prevMessages, newMessages);\n\n        // A clean prepend means older messages were inserted ahead of the current\n        // viewport. Restore the viewport according to the mode chosen when loading\n        // started, then clear the mode for the next pagination cycle.\n        if (messagesAddedToTop) {\n          const preservedAnchor =\n            olderPaginationState.current.mode === 'preserve-anchor' &&\n            olderPaginationState.current.anchor &&\n            (finishedLoadingOlder || loadingMore)\n              ? olderPaginationState.current.anchor\n              : null;\n\n          // When pagination was triggered from absolute top, keep the newly\n          // loaded page pinned to top instead of restoring the old viewport.\n          if (olderPaginationState.current.mode === 'stick-to-top') {\n            onScrollToTop();\n          } else if (preservedAnchor) {\n            restoreAnchor(preservedAnchor);\n          } else if (scrollTop.current < loadMoreScrollThreshold) {\n            // Fallback for prepends when there is no stable DOM anchor to restore.\n            // This is less accurate than anchor restoration, but still avoids a full\n            // jump by compensating for the inserted page height.\n            const listHeightDelta = newMeasures.scrollHeight - prevMeasures.scrollHeight;\n            onScrollBy(listHeightDelta);\n          }\n\n          olderPaginationState.current = {\n            anchor: null,\n            mode: 'idle',\n          };\n        }\n        // A clean append means the list grew downward. Preserve the usual chat\n        // semantics: auto-scroll only for self-sent messages or when the user was\n        // already close enough to bottom.\n        else if (messagesAddedToBottom) {\n          if (justReachedLatestMessageSet) {\n            // Merging into the latest page is handled by dedicated logic higher up.\n            // Returning here avoids undoing that behavior with a normal append scroll.\n            messages.current = newMessages;\n            measures.current = newMeasures;\n            previousLoadingMoreRef.current = loadingMore;\n            return;\n          }\n\n          const lastMessageIsFromCurrentUser = lastNewMessage.user?.id === client.userID;\n\n          if (lastMessageIsFromCurrentUser || wasAtBottom) {\n            scrollToBottom();\n          } else {\n            showNewMessages();\n          }\n        } else {\n          // If the new page is neither a pure prepend nor a pure append, treat it as\n          // a disjunct/overlapping page switch and avoid applying prepend heuristics.\n          olderPaginationState.current = {\n            anchor: null,\n            mode: 'idle',\n          };\n        }\n      }\n      // message list length didn't change, but check if last message had reaction/reply update\n      else {\n        const hasNewReactions =\n          lastPrevMessage?.latest_reactions?.length !==\n          lastNewMessage.latest_reactions?.length;\n        const hasNewReplies = lastPrevMessage?.reply_count !== lastNewMessage.reply_count;\n\n        if ((hasNewReactions || hasNewReplies) && wasAtBottom) {\n          scrollToBottom();\n        }\n\n        if (finishedLoadingOlder) {\n          // Clear any older-page mode when the request ends without increasing the\n          // rendered list size, so the next pagination cycle starts from a clean slate.\n          olderPaginationState.current = {\n            anchor: null,\n            mode: 'idle',\n          };\n        }\n      }\n    }\n\n    messages.current = newMessages;\n    measures.current = newMeasures;\n    previousLoadingMoreRef.current = loadingMore;\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [\n    captureAnchor,\n    disableScrollManagement,\n    justReachedLatestMessageSet,\n    loadingMore,\n    measures,\n    messages,\n    params.messages,\n    restoreAnchor,\n    scrollContainerMeasures,\n  ]);\n\n  return (\n    scrollTopValue: number,\n    getLatestAnchor: (() => { id: string; offsetTop: number } | null) | null = null,\n  ) => {\n    scrollTop.current = scrollTopValue;\n\n    if (\n      loadingMore &&\n      getLatestAnchor &&\n      olderPaginationState.current.mode === 'preserve-anchor'\n    ) {\n      // Keep the anchor fresh while the request is in flight so restoration matches\n      // the latest viewport position if the user keeps scrolling before data arrives.\n      // The getter keeps normal scroll events cheap by avoiding DOM anchor capture\n      // unless anchor preservation is actually active.\n      const latestAnchor = getLatestAnchor();\n      if (!latestAnchor) return;\n\n      olderPaginationState.current = {\n        anchor: latestAnchor,\n        mode: 'preserve-anchor',\n      };\n    }\n  };\n}\n","import type React from 'react';\nimport { useCallback, useLayoutEffect, useRef, useState } from 'react';\n\nimport { useMessageListScrollManager } from './useMessageListScrollManager';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UseScrollLocationLogicParams = {\n  /** Disables automatic scroll-to-bottom updates after message changes. */\n  disableAutoScrollToBottom?: boolean;\n  /** Disables scroll-management adjustments (anchor restore, append/prepend handling). */\n  disableScrollManagement?: boolean;\n  /** True when there are newer messages to load beyond the currently rendered page. */\n  hasMoreNewer: boolean;\n  /** Scrollable message-list container element. */\n  listElement: HTMLDivElement | null;\n  /** Threshold used to detect older-page pagination proximity near the top. */\n  loadMoreScrollThreshold: number;\n  /** Indicates whether older-page pagination is currently in progress. */\n  loadingMore?: boolean;\n  /** Hard-disable all autoscroll behavior. */\n  suppressAutoscroll: boolean;\n  /** Current rendered message set used for scroll reconciliation. */\n  messages?: LocalMessage[];\n  /** Distance from bottom (px) considered as \"near bottom\". */\n  scrolledUpThreshold?: number;\n};\n\n/**\n * Centralized scroll-position logic for MessageList.\n *\n * Responsibilities:\n * - Keep viewport stable during prepend/append pagination updates.\n * - Track whether the list is near bottom and expose that state to UI.\n * - Auto-scroll to bottom when appropriate while respecting suppression flags.\n * - Perform a short hydration settle pass so freshly loaded lists land at bottom.\n */\nexport const useScrollLocationLogic = (params: UseScrollLocationLogicParams) => {\n  const {\n    disableAutoScrollToBottom = false,\n    disableScrollManagement = false,\n    hasMoreNewer,\n    listElement,\n    loadingMore = false,\n    loadMoreScrollThreshold,\n    messages = [],\n    scrolledUpThreshold = 200,\n    suppressAutoscroll,\n  } = params;\n\n  const [hasNewMessages, setHasNewMessages] = useState(false);\n  const [wrapperRect, setWrapperRect] = useState<DOMRect>();\n  const previousHasMoreNewerRef = useRef(hasMoreNewer);\n  const justReachedLatestMessageSet = previousHasMoreNewerRef.current && !hasMoreNewer;\n  const skipNextAutoScrollRef = useRef(false);\n  const isRestoringOlderAnchorRef = useRef(false);\n\n  const [isMessageListScrolledToBottom, setIsMessageListScrolledToBottom] =\n    useState(true);\n  const closeToBottom = useRef(false);\n  const closeToTop = useRef(false);\n  const previousScrollTopRef = useRef(0);\n  const previousMessagesLengthRef = useRef(messages.length);\n  const previousDisableAutoScrollToBottomRef = useRef(disableAutoScrollToBottom);\n  const previousDisableAutoScrollSettleRef = useRef(disableAutoScrollToBottom);\n  const anchorRestoreCleanupRef = useRef<(() => void) | null>(null);\n\n  const captureAnchor = useCallback(() => {\n    if (!listElement) return null;\n\n    const listRect = listElement.getBoundingClientRect();\n    const listTop = listRect.top;\n    const listBottom = listRect.bottom;\n    const listCenter = listTop + listRect.height / 2;\n    // Older-page pagination should track the top edge, while the generic\n    // “keep this viewport stable” case works better from the center.\n    const preferTopEdgeAnchor =\n      loadingMore || listElement.scrollTop < loadMoreScrollThreshold;\n    const messageElements = Array.from(\n      listElement.querySelectorAll<HTMLElement>('[data-message-id]'),\n    );\n    const messageAnchors = messageElements.map((element) => {\n      const rect = element.getBoundingClientRect();\n      return {\n        center: rect.top + rect.height / 2,\n        element,\n        offsetTop: rect.top - listTop,\n        rect,\n      };\n    });\n\n    const visibleMessageAnchors = messageAnchors.filter(\n      ({ rect }) => rect.bottom > listTop && rect.top < listBottom,\n    );\n\n    const topEdgeAnchor = visibleMessageAnchors.reduce<\n      (typeof visibleMessageAnchors)[number] | null\n    >((closest, candidate) => {\n      if (!closest || candidate.rect.top < closest.rect.top) {\n        return candidate;\n      }\n\n      return closest;\n    }, null);\n\n    const centerAnchor =\n      visibleMessageAnchors.find(\n        ({ rect }) => rect.top <= listCenter && rect.bottom >= listCenter,\n      ) ??\n      visibleMessageAnchors.reduce<(typeof visibleMessageAnchors)[number] | null>(\n        (closest, candidate) => {\n          if (!closest) return candidate;\n\n          const distance = Math.abs(candidate.center - listCenter);\n          const closestDistance = Math.abs(closest.center - listCenter);\n\n          return distance < closestDistance ? candidate : closest;\n        },\n        null,\n      );\n\n    const anchor =\n      (preferTopEdgeAnchor ? topEdgeAnchor : centerAnchor) ?? messageAnchors[0];\n\n    if (!anchor?.element.dataset.messageId) return null;\n\n    return {\n      id: anchor.element.dataset.messageId,\n      offsetTop: anchor.offsetTop,\n    };\n  }, [listElement, loadMoreScrollThreshold, loadingMore]);\n\n  const restoreAnchor = useCallback(\n    (anchor: { id: string; offsetTop: number }) => {\n      if (!listElement) return;\n\n      anchorRestoreCleanupRef.current?.();\n\n      let cancelled = false;\n      let stableFrameCount = 0;\n      let frameQueued = false;\n      let resizeObserver: ResizeObserver | undefined;\n      // eslint-disable-next-line prefer-const\n      let settleTimeoutId: ReturnType<typeof setTimeout> | undefined;\n      let animationFrameId: number | undefined;\n\n      isRestoringOlderAnchorRef.current = true;\n\n      const applyAnchor = () => {\n        if (cancelled) return true;\n\n        const anchorElement = listElement.querySelector<HTMLElement>(\n          `[data-message-id='${anchor.id}']`,\n        );\n        if (!anchorElement) return true;\n\n        const listTop = listElement.getBoundingClientRect().top;\n        const nextOffsetTop = anchorElement.getBoundingClientRect().top - listTop;\n        const offsetDelta = nextOffsetTop - anchor.offsetTop;\n\n        if (Math.abs(offsetDelta) > 1) {\n          listElement.scrollBy({ top: offsetDelta });\n          return false;\n        }\n\n        return true;\n      };\n\n      const cleanup = () => {\n        cancelled = true;\n        frameQueued = false;\n        isRestoringOlderAnchorRef.current = false;\n        if (typeof animationFrameId !== 'undefined') {\n          window.cancelAnimationFrame(animationFrameId);\n        }\n        if (settleTimeoutId) {\n          clearTimeout(settleTimeoutId);\n        }\n        resizeObserver?.disconnect();\n      };\n\n      // Keep correcting against the same anchor until the DOM stops shifting.\n      const queueNextFrame = () => {\n        if (cancelled || frameQueued) return;\n        frameQueued = true;\n        animationFrameId = window.requestAnimationFrame(() => {\n          frameQueued = false;\n          const isStable = applyAnchor();\n          stableFrameCount = isStable ? stableFrameCount + 1 : 0;\n\n          if (stableFrameCount >= 2) {\n            cleanup();\n            return;\n          }\n\n          queueNextFrame();\n        });\n      };\n\n      stableFrameCount = applyAnchor() ? 1 : 0;\n      queueNextFrame();\n\n      // Late media/layout updates can still move the anchor after the first\n      // correction, so restart the settle check when the list resizes.\n      if (typeof ResizeObserver !== 'undefined') {\n        resizeObserver = new ResizeObserver(() => {\n          stableFrameCount = 0;\n          queueNextFrame();\n        });\n        resizeObserver.observe(listElement);\n      }\n\n      settleTimeoutId = setTimeout(() => {\n        cleanup();\n      }, 1200);\n\n      anchorRestoreCleanupRef.current = cleanup;\n    },\n    [listElement],\n  );\n\n  useLayoutEffect(\n    () => () => {\n      anchorRestoreCleanupRef.current?.();\n    },\n    [],\n  );\n\n  const scrollToBottom = useCallback(\n    (options?: ScrollToOptions) => {\n      if (\n        !listElement?.scrollTo ||\n        hasMoreNewer ||\n        isRestoringOlderAnchorRef.current ||\n        justReachedLatestMessageSet ||\n        suppressAutoscroll\n      ) {\n        return;\n      }\n\n      listElement.scrollTo({\n        behavior: options?.behavior,\n        top: listElement.scrollHeight,\n      });\n      setHasNewMessages(false);\n    },\n    [hasMoreNewer, justReachedLatestMessageSet, listElement, suppressAutoscroll],\n  );\n\n  /**\n   * Keeps wrapper geometry up to date and handles the \"reached latest merged set\"\n   * path where existing viewport position must be preserved.\n   */\n  useLayoutEffect(() => {\n    const disableAutoScrollJustReleased =\n      previousDisableAutoScrollToBottomRef.current && !disableAutoScrollToBottom;\n    previousDisableAutoScrollToBottomRef.current = disableAutoScrollToBottom;\n\n    // Re-enabling auto-scroll should not immediately force a jump to bottom.\n    // This avoids snap-back after temporary suppression (e.g. jump-to-message).\n    if (disableAutoScrollJustReleased) {\n      return;\n    }\n\n    if (listElement) {\n      setWrapperRect(listElement.getBoundingClientRect());\n    }\n\n    if (listElement && justReachedLatestMessageSet) {\n      listElement.scrollTop = previousScrollTopRef.current;\n      skipNextAutoScrollRef.current = true;\n      return;\n    }\n\n    if (skipNextAutoScrollRef.current) {\n      skipNextAutoScrollRef.current = false;\n      return;\n    }\n\n    if (listElement && !disableAutoScrollToBottom && !isRestoringOlderAnchorRef.current) {\n      scrollToBottom();\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [disableAutoScrollToBottom, justReachedLatestMessageSet, listElement, hasMoreNewer]);\n\n  /**\n   * Short post-render bottom settle. This is intentionally small (immediate + 2 retries)\n   * to catch late layout updates without keeping the list in a prolonged lock loop.\n   */\n  useLayoutEffect(() => {\n    const disableAutoScrollJustReleased =\n      previousDisableAutoScrollSettleRef.current && !disableAutoScrollToBottom;\n    previousDisableAutoScrollSettleRef.current = disableAutoScrollToBottom;\n\n    // Skip one settle cycle when auto-scroll suppression is released.\n    // Without this guard, a jump-to-message flow can scroll to the target and then\n    // get pulled back down by the delayed \"keep pinned to bottom\" retries\n    // (80/260/420/900/1700ms), which looks like a snap-back to the latest message.\n    // Letting this transition frame pass preserves the jump destination.\n    if (disableAutoScrollJustReleased) {\n      return;\n    }\n\n    if (\n      !listElement ||\n      disableAutoScrollToBottom ||\n      hasMoreNewer ||\n      suppressAutoscroll ||\n      justReachedLatestMessageSet ||\n      isRestoringOlderAnchorRef.current\n    ) {\n      return;\n    }\n\n    const initialDistanceToBottom =\n      listElement.scrollHeight - (listElement.scrollTop + listElement.clientHeight);\n    const messagesHydrated =\n      previousMessagesLengthRef.current === 0 && messages.length > 0;\n\n    if (initialDistanceToBottom > scrolledUpThreshold && !messagesHydrated) {\n      return;\n    }\n\n    let keepPinnedToBottom = true;\n\n    const maybeScrollToBottom = () => {\n      if (keepPinnedToBottom) {\n        scrollToBottom();\n      }\n    };\n\n    maybeScrollToBottom();\n    const settleDelays = [80, messagesHydrated ? 260 : 420, 900, 1700];\n    const settleTimeoutIds = settleDelays.map((delay) =>\n      setTimeout(maybeScrollToBottom, delay),\n    );\n\n    const stopKeepingPinnedToBottom = () => {\n      keepPinnedToBottom = false;\n    };\n\n    // Any direct user interaction with the scroller disables the temporary\n    // initial-load pin, so manual scrolling is never force-overridden.\n    listElement.addEventListener('pointerdown', stopKeepingPinnedToBottom, {\n      passive: true,\n    });\n    listElement.addEventListener('touchstart', stopKeepingPinnedToBottom, {\n      passive: true,\n    });\n    listElement.addEventListener('wheel', stopKeepingPinnedToBottom, {\n      passive: true,\n    });\n    listElement.addEventListener('keydown', stopKeepingPinnedToBottom);\n\n    const pinWindowTimeoutId = setTimeout(() => {\n      stopKeepingPinnedToBottom();\n    }, 2200);\n\n    return () => {\n      settleTimeoutIds.forEach(clearTimeout);\n      clearTimeout(pinWindowTimeoutId);\n      listElement.removeEventListener('pointerdown', stopKeepingPinnedToBottom);\n      listElement.removeEventListener('touchstart', stopKeepingPinnedToBottom);\n      listElement.removeEventListener('wheel', stopKeepingPinnedToBottom);\n      listElement.removeEventListener('keydown', stopKeepingPinnedToBottom);\n    };\n  }, [\n    disableAutoScrollToBottom,\n    hasMoreNewer,\n    justReachedLatestMessageSet,\n    listElement,\n    messages.length,\n    scrollToBottom,\n    scrolledUpThreshold,\n    suppressAutoscroll,\n  ]);\n\n  const updateScrollTop = useMessageListScrollManager({\n    captureAnchor,\n    disableScrollManagement: disableScrollManagement || isRestoringOlderAnchorRef.current,\n    justReachedLatestMessageSet,\n    loadingMore,\n    loadMoreScrollThreshold,\n    messages,\n    onScrollBy: (scrollBy) => {\n      listElement?.scrollBy({ top: scrollBy });\n    },\n    onScrollToTop: () => {\n      if (!listElement) return;\n      listElement.scrollTop = 0;\n    },\n    restoreAnchor,\n\n    scrollContainerMeasures: () => ({\n      offsetHeight: listElement?.offsetHeight || 0,\n      scrollHeight: listElement?.scrollHeight || 0,\n      scrollTop: listElement?.scrollTop || 0,\n    }),\n    scrolledUpThreshold,\n    scrollToBottom,\n    showNewMessages: () => setHasNewMessages(true),\n  });\n\n  useLayoutEffect(() => {\n    previousHasMoreNewerRef.current = hasMoreNewer;\n  }, [hasMoreNewer]);\n\n  useLayoutEffect(() => {\n    previousMessagesLengthRef.current = messages.length;\n  }, [messages.length]);\n\n  /**\n   * Updates cached scroll metrics and bottom/top proximity state used by\n   * notifications, autoscroll decisions, and paginator behavior.\n   */\n  const onScroll = useCallback(\n    (event: React.UIEvent<HTMLDivElement>) => {\n      const element = event.target as HTMLDivElement;\n      const scrollTop = element.scrollTop;\n      previousScrollTopRef.current = scrollTop;\n\n      updateScrollTop(scrollTop, captureAnchor);\n\n      const offsetHeight = element.offsetHeight;\n      const scrollHeight = element.scrollHeight;\n      const distanceToBottom = scrollHeight - (scrollTop + offsetHeight);\n      const bottomEnterThreshold = Math.max(Math.floor(scrolledUpThreshold * 0.6), 24);\n\n      const prevCloseToBottom = closeToBottom.current;\n      closeToBottom.current = prevCloseToBottom\n        ? distanceToBottom < scrolledUpThreshold\n        : distanceToBottom < bottomEnterThreshold;\n      closeToTop.current = scrollTop < scrolledUpThreshold;\n\n      if (closeToBottom.current) {\n        setHasNewMessages(false);\n      }\n      if (prevCloseToBottom && !closeToBottom.current) {\n        setIsMessageListScrolledToBottom(false);\n      } else if (!prevCloseToBottom && closeToBottom.current) {\n        setIsMessageListScrolledToBottom(true);\n      }\n    },\n    [captureAnchor, updateScrollTop, closeToTop, closeToBottom, scrolledUpThreshold],\n  );\n\n  return {\n    hasNewMessages,\n    isMessageListScrolledToBottom,\n    onScroll,\n    scrollToBottom,\n    wrapperRect,\n  };\n};\n","import React from 'react';\nimport type { PropsWithChildrenOnly } from '../../types/types';\n\nexport const MESSAGE_LIST_MAIN_PANEL_CLASS =\n  'str-chat__main-panel-inner str-chat__message-list-main-panel' as const;\n\nexport const MessageListMainPanel = ({ children }: PropsWithChildrenOnly) => (\n  <div className={MESSAGE_LIST_MAIN_PANEL_CLASS}>{children}</div>\n);\n","import React from 'react';\nimport { useChannelActionContext, useTranslationContext } from '../../context';\nimport { Button } from '../Button';\nimport { IconXmark } from '../Icons';\n\nexport const UNREAD_MESSAGE_SEPARATOR_CLASS = 'str-chat__unread-messages-separator';\n\nexport type UnreadMessagesSeparatorProps = {\n  /**\n   * Configuration parameter to determine, whether the unread count is to be shown on the component. Enabled by default.\n   */\n  showCount?: boolean;\n  /**\n   * The count of unread messages to be displayed if enabled.\n   */\n  unreadCount?: number;\n};\n\nexport const UnreadMessagesSeparator = ({\n  showCount = true,\n  unreadCount,\n}: UnreadMessagesSeparatorProps) => {\n  const { t } = useTranslationContext('UnreadMessagesSeparator');\n  const { markRead } = useChannelActionContext();\n  return (\n    <div\n      className={UNREAD_MESSAGE_SEPARATOR_CLASS}\n      data-testid='unread-messages-separator'\n    >\n      <div className={'str-chat__unread-messages-separator__text'}>\n        {unreadCount && showCount\n          ? t('{{count}} unread', { count: unreadCount })\n          : t('Unread messages')}\n      </div>\n      <Button\n        appearance='ghost'\n        aria-label={t('aria/Mark messages as read')}\n        circular\n        onClick={() => markRead()}\n        size='sm'\n        variant='secondary'\n      >\n        <IconXmark />\n      </Button>\n    </div>\n  );\n};\n","import { useChannelStateContext } from '../../../../context';\nimport { useEffect, useRef, useState } from 'react';\nimport { MESSAGE_LIST_MAIN_PANEL_CLASS } from '../../MessageListMainPanel';\nimport { UNREAD_MESSAGE_SEPARATOR_CLASS } from '../../UnreadMessagesSeparator';\n\nconst targetScrolledAboveVisibleContainerArea = (\n  element: Element,\n  container?: Element,\n) => {\n  const { bottom: targetBottom } = element.getBoundingClientRect();\n  const containerTop = container?.getBoundingClientRect().top ?? 0;\n  return targetBottom < containerTop;\n};\n\nconst targetScrolledBelowVisibleContainerArea = (\n  element: Element,\n  container: Element,\n) => {\n  const { top: targetTop } = element.getBoundingClientRect();\n  const { bottom: containerBottom } = container.getBoundingClientRect();\n  return targetTop > containerBottom;\n};\n\nexport type UseUnreadMessagesNotificationParams = {\n  /** Scroll container (the element with overflow that actually scrolls). When provided, used as IntersectionObserver root and for initial visibility. */\n  listElement: HTMLDivElement | null;\n  isMessageListScrolledToBottom: boolean;\n  showAlways: boolean;\n  unreadCount?: number;\n};\n\nexport const useUnreadMessagesNotification = ({\n  isMessageListScrolledToBottom,\n  listElement,\n  showAlways,\n  unreadCount,\n}: UseUnreadMessagesNotificationParams) => {\n  const { messages } = useChannelStateContext('UnreadMessagesNotification');\n  const [show, setShow] = useState(false);\n  const isScrolledAboveTargetTop = useRef(false);\n  const intersectionObserverIsSupported = typeof IntersectionObserver !== 'undefined';\n\n  useEffect(() => {\n    if (!(unreadCount && intersectionObserverIsSupported)) {\n      setShow(false);\n      return;\n    }\n\n    const scrollRoot = listElement ?? null;\n    if (!scrollRoot) {\n      const [msgListPanel] = document.getElementsByClassName(\n        MESSAGE_LIST_MAIN_PANEL_CLASS,\n      );\n      if (!msgListPanel) return;\n      const [observedTarget] = document.getElementsByClassName(\n        UNREAD_MESSAGE_SEPARATOR_CLASS,\n      );\n      if (!observedTarget) {\n        setShow(true);\n      }\n      return;\n    }\n\n    const [observedTarget] = document.getElementsByClassName(\n      UNREAD_MESSAGE_SEPARATOR_CLASS,\n    );\n    if (!observedTarget) {\n      setShow(true);\n      return;\n    }\n\n    const scrolledBelowSeparator = targetScrolledAboveVisibleContainerArea(\n      observedTarget,\n      scrollRoot,\n    );\n    const scrolledAboveSeparator = targetScrolledBelowVisibleContainerArea(\n      observedTarget,\n      scrollRoot,\n    );\n\n    setShow(\n      showAlways\n        ? scrolledBelowSeparator || scrolledAboveSeparator\n        : scrolledBelowSeparator,\n    );\n\n    const observer = new IntersectionObserver(\n      (elements) => {\n        if (!elements.length) return;\n        const entry = elements[0];\n        const { boundingClientRect, isIntersecting, rootBounds } = entry;\n        if (isIntersecting) {\n          setShow(false);\n          return;\n        }\n        const rootTop = rootBounds?.top ?? 0;\n        const separatorIsAboveContainerTop = boundingClientRect.bottom < rootTop;\n        setShow(showAlways || separatorIsAboveContainerTop);\n        isScrolledAboveTargetTop.current = separatorIsAboveContainerTop;\n      },\n      { root: scrollRoot },\n    );\n    observer.observe(observedTarget);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [\n    intersectionObserverIsSupported,\n    listElement,\n    isMessageListScrolledToBottom,\n    messages,\n    showAlways,\n    unreadCount,\n  ]);\n\n  useEffect(() => {\n    /**\n     * Handle situation when scrollToBottom is called from another component when the msg list is scrolled above the observed target (unread separator).\n     * The intersection observer is not triggered when Element.scrollTo() is called. So we end up in a situation when we are scrolled to the bottom\n     * and at the same time scrolled above the observed target.\n     */\n\n    if (\n      unreadCount &&\n      isMessageListScrolledToBottom &&\n      isScrolledAboveTargetTop.current\n    ) {\n      setShow(true);\n      isScrolledAboveTargetTop.current = false;\n    }\n  }, [isMessageListScrolledToBottom, unreadCount]);\n\n  return { show: show && intersectionObserverIsSupported };\n};\n","import { useEffect } from 'react';\nimport {\n  useChannelActionContext,\n  useChannelStateContext,\n  useChatContext,\n} from '../../../context';\nimport type { Channel, Event, LocalMessage, MessageResponse } from 'stream-chat';\n\nconst hasReadLastMessage = (channel: Channel, userId: string) => {\n  const latestMessageIdInChannel = channel.state.latestMessages.slice(-1)[0]?.id;\n  const lastReadMessageIdServer = channel.state.read[userId]?.last_read_message_id;\n  return latestMessageIdInChannel === lastReadMessageIdServer;\n};\n\ntype UseMarkReadParams = {\n  isMessageListScrolledToBottom: boolean;\n  messageListIsThread: boolean;\n  wasMarkedUnread?: boolean;\n};\n\n/**\n * Takes care of marking a channel read. The channel is read only if all the following applies:\n * 1. the message list is not rendered in a thread\n * 2. the message list is scrolled to the bottom\n * 3. the channel was not marked unread by the user\n * @param isMessageListScrolledToBottom\n * @param messageListIsThread\n * @param wasChannelMarkedUnread\n */\nexport const useMarkRead = ({\n  isMessageListScrolledToBottom,\n  messageListIsThread,\n  wasMarkedUnread,\n}: UseMarkReadParams) => {\n  const { client } = useChatContext('useMarkRead');\n  const { markRead, setChannelUnreadUiState } = useChannelActionContext('useMarkRead');\n  const { channel } = useChannelStateContext('useMarkRead');\n\n  useEffect(() => {\n    if (!channel.getConfig()?.read_events) return;\n    const shouldMarkRead = () =>\n      !document.hidden &&\n      !wasMarkedUnread &&\n      !messageListIsThread &&\n      isMessageListScrolledToBottom &&\n      client.user?.id &&\n      !hasReadLastMessage(channel, client.user.id);\n\n    const onVisibilityChange = () => {\n      if (shouldMarkRead()) markRead();\n    };\n\n    const handleMessageNew = (event: Event) => {\n      const mainChannelUpdated =\n        !event.message?.parent_id || event.message?.show_in_channel;\n\n      if (!isMessageListScrolledToBottom || wasMarkedUnread || document.hidden) {\n        setChannelUnreadUiState((prev) => {\n          const previousUnreadCount = prev?.unread_messages ?? 0;\n          const previousLastMessage = getPreviousLastMessage(\n            channel.state.messages,\n            event.message,\n          );\n          return {\n            ...(prev || {}),\n            last_read:\n              prev?.last_read ??\n              (previousUnreadCount === 0 && previousLastMessage?.created_at\n                ? new Date(previousLastMessage.created_at)\n                : new Date(0)), // not having information about the last read message means the whole channel is unread,\n            unread_messages: previousUnreadCount + 1,\n          };\n        });\n      } else if (mainChannelUpdated && shouldMarkRead()) {\n        markRead();\n      }\n    };\n\n    channel.on('message.new', handleMessageNew);\n    document.addEventListener('visibilitychange', onVisibilityChange);\n\n    if (shouldMarkRead()) {\n      markRead();\n    }\n\n    return () => {\n      channel.off('message.new', handleMessageNew);\n      document.removeEventListener('visibilitychange', onVisibilityChange);\n    };\n  }, [\n    channel,\n    client,\n    isMessageListScrolledToBottom,\n    markRead,\n    messageListIsThread,\n    setChannelUnreadUiState,\n    wasMarkedUnread,\n  ]);\n};\n\nfunction getPreviousLastMessage(messages: LocalMessage[], newMessage?: MessageResponse) {\n  if (!newMessage) return;\n  let previousLastMessage;\n  for (let i = messages.length - 1; i >= 0; i--) {\n    const msg = messages[i];\n    if (!msg?.id) break;\n    if (msg.id !== newMessage.id) {\n      previousLastMessage = msg;\n      break;\n    }\n  }\n  return previousLastMessage;\n}\n","import React from 'react';\n\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\n\nexport type NewMessageNotificationProps = {\n  /** Pre-computed label text (passed to custom override) */\n  label?: string;\n  /** Controls the notification display */\n  showNotification?: boolean;\n  /** Number of new messages since user scrolled up (optional; when provided shows \"{{count}} new messages\") */\n  newMessageCount?: number;\n};\n\nconst UnMemoizedNewMessageNotification = (props: NewMessageNotificationProps) => {\n  const { newMessageCount = 0, showNotification } = props;\n\n  const { t } = useTranslationContext();\n\n  const { NewMessageNotification: CustomNewMessageNotification } = useComponentContext();\n\n  if (!showNotification) return null;\n\n  const label =\n    newMessageCount > 0\n      ? t('{{count}} new messages', { count: newMessageCount })\n      : t('New Messages!');\n\n  if (CustomNewMessageNotification) {\n    return <CustomNewMessageNotification {...props} label={label} />;\n  }\n\n  return (\n    <div className='str-chat__new-message-notification'>\n      <div\n        aria-atomic='true'\n        aria-live='polite'\n        className='str-chat__message-notification__label'\n        data-testid='message-notification'\n        role='status'\n      >\n        {label}\n      </div>\n    </div>\n  );\n};\n\nexport const NewMessageNotification = React.memo(\n  UnMemoizedNewMessageNotification,\n) as typeof UnMemoizedNewMessageNotification;\n","import React from 'react';\nimport { useChannelActionContext, useTranslationContext } from '../../context';\nimport { Button } from '../Button';\nimport { IconArrowUp, IconXmark } from '../Icons';\nimport clsx from 'clsx';\n\nexport type UnreadMessagesNotificationProps = {\n  /**\n   * Configuration parameter to determine the message page size, when jumping to the first unread message.\n   */\n  queryMessageLimit?: number;\n  /**\n   * Configuration parameter to determine, whether the unread count is to be shown on the component. Enabled by default.\n   */\n  showCount?: boolean;\n  /**\n   * The count of unread messages to be displayed if enabled.\n   */\n  unreadCount?: number;\n};\n\nexport const UnreadMessagesNotification = ({\n  queryMessageLimit,\n  showCount = true,\n  unreadCount,\n}: UnreadMessagesNotificationProps) => {\n  const { jumpToFirstUnreadMessage, markRead } = useChannelActionContext();\n  const { t } = useTranslationContext('UnreadMessagesNotification');\n\n  return (\n    <div\n      className={clsx('str-chat__unread-messages-notification', {\n        'str-chat__unread-messages-notification--with-count': unreadCount && showCount,\n      })}\n      data-testid='unread-messages-notification'\n    >\n      <Button\n        appearance='outline'\n        onClick={() => jumpToFirstUnreadMessage(queryMessageLimit)}\n        variant='secondary'\n      >\n        <IconArrowUp />\n        {unreadCount && showCount\n          ? t('{{count}} unread', { count: unreadCount })\n          : t('Unread messages')}\n      </Button>\n      <Button\n        appearance='outline'\n        aria-label={t('aria/Mark messages as read')}\n        onClick={() => markRead()}\n        variant='secondary'\n      >\n        <IconXmark />\n      </Button>\n    </div>\n  );\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\nimport type { PaginatorProps } from '../../types/types';\nimport { DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD } from '../../constants/limits';\n\n/**\n * Prevents Chrome hangups\n * See: https://stackoverflow.com/questions/47524205/random-high-content-download-time-in-chrome/47684257#47684257\n */\nconst mousewheelListener = (event: Event) => {\n  if (event instanceof WheelEvent && event.deltaY === 1) {\n    event.preventDefault();\n  }\n};\n\nexport type InfiniteScrollProps = PaginatorProps & {\n  className?: string;\n  element?: React.ElementType;\n  /** Element to be rendered at the top of the thread message list. By default, Message and ThreadStart components */\n  head?: React.ReactNode;\n  initialLoad?: boolean;\n  isLoading?: boolean;\n  listenToScroll?: (offset: number, reverseOffset: number, threshold: number) => void;\n  loader?: React.ReactNode;\n  useCapture?: boolean;\n};\n\n/**\n * This component serves a single purpose - load more items on scroll inside the MessageList component\n * It is not a general purpose infinite scroll controller, because:\n * 1. It is re-rendered whenever queryInProgress, hasNext, hasPrev changes. This can lead to scrollListener to have stale data.\n * 2. It pretends to invoke scrollListener on resize event even though this event is emitted only on window resize. It should\n * rather use ResizeObserver. But then again, it ResizeObserver would invoke a stale version of scrollListener.\n *\n * In general, the infinite scroll controller should not aim for checking the loading state and whether there is more data to load.\n * That should be controlled by the loading function.\n */\nexport const InfiniteScroll = (props: PropsWithChildren<InfiniteScrollProps>) => {\n  const {\n    children,\n    element: Component = 'div',\n    hasNextPage,\n    hasPreviousPage,\n    head,\n    initialLoad = true,\n    isLoading,\n    listenToScroll,\n    loader,\n    loadNextPage,\n    loadPreviousPage,\n    threshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD,\n    useCapture = false,\n    ...elementProps\n  } = props;\n\n  const [scrollComponent, setScrollComponent] = useState<HTMLElement | null>(null);\n  const previousOffset = useRef<number | undefined>(undefined);\n  const previousReverseOffset = useRef<number | undefined>(undefined);\n\n  const scrollListenerRef = useRef<() => void>(undefined);\n  scrollListenerRef.current = () => {\n    const element = scrollComponent;\n\n    if (!element || element.offsetParent === null) {\n      return;\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    const parentElement = element.parentElement!;\n\n    const offset =\n      element.scrollHeight - parentElement.scrollTop - parentElement.clientHeight;\n    const reverseOffset = parentElement.scrollTop;\n\n    if (listenToScroll) {\n      listenToScroll(offset, reverseOffset, threshold);\n    }\n\n    if (isLoading) return;\n\n    if (\n      previousOffset.current === offset &&\n      previousReverseOffset.current === reverseOffset\n    )\n      return;\n    previousOffset.current = offset;\n    previousReverseOffset.current = reverseOffset;\n\n    // FIXME: this triggers loadMore call when a user types messages in thread and the scroll container expands\n    if (\n      reverseOffset < Number(threshold) &&\n      typeof loadPreviousPage === 'function' &&\n      hasPreviousPage\n    ) {\n      loadPreviousPage();\n    }\n\n    if (offset < Number(threshold) && typeof loadNextPage === 'function' && hasNextPage) {\n      loadNextPage();\n    }\n  };\n\n  useEffect(() => {\n    const scrollElement = scrollComponent?.parentNode;\n\n    if (!scrollElement) return;\n\n    const scrollListener = () => scrollListenerRef.current?.();\n\n    scrollElement.addEventListener('scroll', scrollListener, useCapture);\n    scrollElement.addEventListener('resize', scrollListener, useCapture);\n\n    // Defer the initial proximity check so that any pending scroll-to-bottom\n    // from useLayoutEffect (e.g. the MessageList settle pass) has been applied\n    // to the DOM before we evaluate whether more pages should be loaded.\n    // Without this, scrollTop is still 0 on mount which falsely triggers\n    // loadPreviousPage and breaks the initial scroll position.\n    const rafId = requestAnimationFrame(() => {\n      scrollListener();\n    });\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      scrollElement.removeEventListener('scroll', scrollListener, useCapture);\n      scrollElement.removeEventListener('resize', scrollListener, useCapture);\n    };\n  }, [initialLoad, scrollComponent, useCapture]);\n\n  useEffect(() => {\n    const scrollElement = scrollComponent?.parentNode;\n\n    if (!scrollElement) return;\n\n    scrollElement.addEventListener('wheel', mousewheelListener, { passive: false });\n\n    return () => {\n      scrollElement.removeEventListener('wheel', mousewheelListener, useCapture);\n    };\n  }, [scrollComponent, useCapture]);\n\n  return (\n    <Component {...elementProps} ref={setScrollComponent}>\n      {head}\n      {loader}\n      {children}\n    </Component>\n  );\n};\n","import React, { useEffect, useMemo } from 'react';\nimport clsx from 'clsx';\n\nimport { AvatarStack } from '../Avatar';\nimport { TypingIndicatorDots } from './TypingIndicatorDots';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useTypingContext } from '../../context/TypingContext';\nimport { useThreadContext } from '../Threads';\nimport { VisuallyHidden } from '../VisuallyHidden';\n\nimport { useDebouncedTypingActive } from './hooks/useDebouncedTypingActive';\nimport { getTypingStatusMessage } from './utils/getTypingStatusMessage';\n\nexport type TypingIndicatorProps = {\n  /** When false, the indicator is not rendered (e.g. when list is not scrolled to bottom). Omit or true to show when typing. */\n  isMessageListScrolledToBottom?: boolean;\n  scrollToBottom: () => void;\n  /** Whether the typing indicator is in a thread */\n  threadList?: boolean;\n};\n\n/**\n * TypingIndicator shows avatars of users currently typing and a bubble with animated dots.\n * Renders only for other participants (never the current user), only when scrolled to latest message if isMessageListScrolledToBottom is provided.\n * It must be a child of Channel component.\n */\nconst UnMemoizedTypingIndicator = (props: TypingIndicatorProps) => {\n  const { isMessageListScrolledToBottom = true, scrollToBottom, threadList } = props;\n\n  const { channelConfig, thread } = useChannelStateContext('TypingIndicator');\n  const threadInstance = useThreadContext();\n  const parentId = threadInstance?.id ?? thread?.id;\n  const { client } = useChatContext('TypingIndicator');\n  const { t } = useTranslationContext();\n  const { typing = {} } = useTypingContext('TypingIndicator');\n\n  const typingInChannel = !threadList\n    ? Object.values(typing).filter(\n        ({ parent_id, user }) => user?.id !== client.user?.id && !parent_id,\n      )\n    : [];\n\n  const typingInThread = threadList\n    ? Object.values(typing).filter(\n        ({ parent_id, user }) => user?.id !== client.user?.id && parent_id === parentId,\n      )\n    : [];\n\n  const typingUsers = threadList ? typingInThread : typingInChannel;\n  const { displayUsers } = useDebouncedTypingActive(typingUsers);\n  const showIndicator = displayUsers.length > 0;\n  const typingAnnouncement = useMemo(\n    () => getTypingStatusMessage(displayUsers, t),\n    [displayUsers, t],\n  );\n\n  const displayInfo = useMemo(\n    () =>\n      displayUsers.map(\n        ({ user }) =>\n          ({\n            id: user?.id,\n            imageUrl: user?.image,\n            userName: user?.name,\n          }) as const,\n      ),\n    [displayUsers],\n  );\n\n  useEffect(() => {\n    if (showIndicator && isMessageListScrolledToBottom) scrollToBottom();\n  }, [scrollToBottom, isMessageListScrolledToBottom, showIndicator]);\n\n  if (channelConfig?.typing_events === false) {\n    return null;\n  }\n\n  if (!showIndicator || !isMessageListScrolledToBottom) {\n    return null;\n  }\n\n  return (\n    <div\n      className={clsx(\n        'str-chat__typing-indicator',\n        'str-chat__typing-indicator--with-transition',\n        {\n          'str-chat__typing-indicator--typing': showIndicator,\n        },\n      )}\n      data-testid='typing-indicator'\n    >\n      {displayInfo.length > 0 && (\n        <div aria-hidden='true'>\n          <AvatarStack badgeSize='md' displayInfo={displayInfo} size='md' />\n        </div>\n      )}\n      <div aria-hidden='true' className='str-chat__typing-indicator__bubble'>\n        <div className='str-chat__typing-indicator__dots'>\n          <TypingIndicatorDots />\n        </div>\n      </div>\n      <VisuallyHidden>\n        <span\n          aria-atomic='true'\n          aria-live='polite'\n          data-testid='typing-indicator-status'\n          role='status'\n        >\n          {typingAnnouncement}\n        </span>\n      </VisuallyHidden>\n    </div>\n  );\n};\n\nexport const TypingIndicator = React.memo(\n  UnMemoizedTypingIndicator,\n) as typeof UnMemoizedTypingIndicator;\n","import { useCallback, useState } from 'react';\n\nimport type { RenderedMessage } from '../../utils';\nimport { isDateSeparatorMessage, isIntroMessage } from '../../utils';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UseFloatingDateSeparatorParams = {\n  disableDateSeparator: boolean;\n  processedMessages: RenderedMessage[];\n};\n\nexport type UseFloatingDateSeparatorResult = {\n  floatingDate: Date | null;\n  onItemsRendered: (rendered: RenderedMessage[]) => void;\n  showFloatingDate: boolean;\n};\n\n/**\n * Returns the date to show in the floating date separator based on currently visible messages.\n * When the first visible item is a message (not a date separator), we've scrolled past its\n * date separator — find that separator's date.\n */\nfunction getFloatingDateForFirstMessage(\n  firstMessage: RenderedMessage,\n  processedMessages: RenderedMessage[],\n  firstMessageIndex: number,\n): Date | null {\n  if (isIntroMessage(firstMessage)) return null;\n\n  // Walk backwards to find the last date separator before this message\n  for (let i = firstMessageIndex - 1; i >= 0; i -= 1) {\n    const item = processedMessages[i];\n    if (isDateSeparatorMessage(item)) {\n      return item.date;\n    }\n  }\n\n  // No preceding date separator; use message's created_at\n  const msg = firstMessage as LocalMessage;\n  const created = msg.created_at;\n  if (created) {\n    const d = new Date(created);\n    return isNaN(d.getTime()) ? null : d;\n  }\n  return null;\n}\n\nfunction getFloatingDateForFirstItem(\n  firstItem: RenderedMessage,\n  processedMessages: RenderedMessage[],\n  firstItemIndex: number,\n): Date | null {\n  if (isDateSeparatorMessage(firstItem)) return firstItem.date;\n\n  return getFloatingDateForFirstMessage(firstItem, processedMessages, firstItemIndex);\n}\n\n/**\n * Controls the floating date separator as a sticky \"current section\" label.\n * It follows the date separator represented by the first visible item.\n */\nconst HIDDEN_STATE = { date: null, visible: false } as const;\n\nexport const useFloatingDateSeparator = ({\n  disableDateSeparator,\n  processedMessages,\n}: UseFloatingDateSeparatorParams): UseFloatingDateSeparatorResult => {\n  const [state, setState] = useState<{\n    date: Date | null;\n    visible: boolean;\n  }>(HIDDEN_STATE);\n\n  const onItemsRendered = useCallback(\n    (rendered: RenderedMessage[]) => {\n      if (disableDateSeparator || processedMessages.length === 0) {\n        setState(HIDDEN_STATE);\n        return;\n      }\n\n      const valid = rendered.filter((m): m is RenderedMessage => m != null);\n      if (valid.length === 0) {\n        setState(HIDDEN_STATE);\n        return;\n      }\n\n      const first = valid[0];\n      const firstIndex = processedMessages.findIndex((m) => m.id === first.id);\n      const date =\n        firstIndex >= 0\n          ? getFloatingDateForFirstItem(first, processedMessages, firstIndex)\n          : null;\n\n      const visible = date !== null;\n      setState((prev) => {\n        const prevTime = prev.date?.getTime() ?? null;\n        const nextTime = date?.getTime() ?? null;\n        if (prev.visible === visible && prevTime === nextTime) return prev;\n        return { date, visible };\n      });\n    },\n    [disableDateSeparator, processedMessages],\n  );\n\n  return {\n    floatingDate: state.date,\n    onItemsRendered,\n    showFloatingDate: !!state.date && state.visible,\n  };\n};\n","import { useEffect, useState } from 'react';\n\nimport { useChatContext } from '../../../../context/ChatContext';\n\nimport type { EventHandler, LocalMessage } from 'stream-chat';\n\nexport const useGiphyPreview = (separateGiphyPreview: boolean) => {\n  const [giphyPreviewMessage, setGiphyPreviewMessage] = useState<LocalMessage>();\n\n  const { client } = useChatContext('useGiphyPreview');\n\n  useEffect(() => {\n    if (!separateGiphyPreview) return;\n    const handleEvent: EventHandler = (event) => {\n      const { message, user } = event;\n\n      if (message?.command === 'giphy' && user?.id === client.userID) {\n        setGiphyPreviewMessage(undefined);\n      }\n    };\n\n    client.on('message.new', handleEvent);\n    return () => client.off('message.new', handleEvent);\n  }, [client, separateGiphyPreview]);\n\n  return {\n    giphyPreviewMessage,\n    setGiphyPreviewMessage: separateGiphyPreview ? setGiphyPreviewMessage : undefined,\n  };\n};\n","import { useEffect, useRef, useState } from 'react';\nimport type { LocalMessage } from 'stream-chat';\n\ntype UseMessageSetKeyParams = {\n  messages?: LocalMessage[];\n};\n\nexport const useMessageSetKey = ({ messages }: UseMessageSetKeyParams) => {\n  /**\n   * Logic to update the key of the virtuoso component when the list jumps to a new location.\n   */\n  const [messageSetKey, setMessageSetKey] = useState(+new Date());\n  const firstMessageId = useRef<string | undefined>(undefined);\n\n  useEffect(() => {\n    const continuousSet = messages?.find(\n      (message) => message.id === firstMessageId.current,\n    );\n    if (!continuousSet) {\n      setMessageSetKey(+new Date());\n    }\n    firstMessageId.current = messages?.[0]?.id;\n  }, [messages]);\n\n  return {\n    messageSetKey,\n  };\n};\n","import { useEffect, useRef, useState } from 'react';\nimport type { LocalMessage } from 'stream-chat';\nimport type { RenderedMessage } from '../../utils';\n\nexport function useNewMessageNotification(\n  messages: RenderedMessage[],\n  currentUserId: string | undefined,\n  hasMoreNewer?: boolean,\n) {\n  const [newMessagesNotification, setNewMessagesNotification] = useState(false);\n  const [isMessageListScrolledToBottom, setIsMessageListScrolledToBottom] =\n    useState(true);\n  /**\n   * use the flag to avoid the initial \"new messages\" quick blink\n   */\n  const didMount = useRef(false);\n\n  const lastMessageId = useRef('');\n  const atBottom = useRef(false);\n\n  useEffect(() => {\n    if (hasMoreNewer) {\n      setNewMessagesNotification(true);\n      return;\n    }\n    /* handle scrolling behavior for new messages */\n    if (!messages?.length) return;\n\n    const lastMessage = messages[messages.length - 1];\n    const prevMessageId = lastMessageId.current;\n    lastMessageId.current = lastMessage.id || ''; // update last message id\n\n    /* do nothing if new messages are loaded from top(loadMore)  */\n    if (lastMessage.id === prevMessageId) return;\n\n    /* if list is already at the bottom return, followOutput will do the job */\n    if (atBottom.current) return;\n\n    /* if the new message belongs to current user scroll to bottom */\n    if ((lastMessage as LocalMessage).user?.id !== currentUserId && didMount.current) {\n      /* otherwise just show newMessage notification  */\n      setNewMessagesNotification(true);\n    }\n    didMount.current = true;\n  }, [currentUserId, messages, hasMoreNewer]);\n\n  return {\n    atBottom,\n    isMessageListScrolledToBottom,\n    newMessagesNotification,\n    setIsMessageListScrolledToBottom,\n    setNewMessagesNotification,\n  };\n}\n","import { useMemo, useRef } from 'react';\nimport type { RenderedMessage } from '../../utils';\nimport { isLocalMessage } from '../../utils';\n\nconst STATUSES_EXCLUDED_FROM_PREPEND = {\n  failed: true,\n  sending: true,\n} as const as Record<string, boolean>;\n\nexport function usePrependedMessagesCount(\n  messages: RenderedMessage[],\n  hasDateSeparator: boolean,\n) {\n  const firstRealMessageIndex = hasDateSeparator ? 1 : 0;\n  const firstMessageOnFirstLoadedPage = useRef<RenderedMessage>(undefined);\n  const previousFirstMessageOnFirstLoadedPage = useRef<RenderedMessage>(undefined);\n  const previousNumItemsPrepended = useRef(0);\n\n  const numItemsPrepended = useMemo(() => {\n    if (!messages || !messages.length) {\n      previousNumItemsPrepended.current = 0;\n      return 0;\n    }\n\n    const currentFirstMessage = messages?.[firstRealMessageIndex];\n\n    const noNewMessages =\n      currentFirstMessage?.id === previousFirstMessageOnFirstLoadedPage.current?.id;\n\n    // This is possible only, when sending messages very quickly (basically single char messages submitted like a crazy) in empty channel (first page)\n    // Optimistic UI update, when sending messages, can lead to a situation, when\n    // the order of the messages changes for a moment. This can happen, when a user\n    // sends multiple messages withing few milliseconds. E.g. we send a message A\n    // then message B. At first we have message array with both messages of status \"sending\"\n    // then response for message A is received with a new - later - created_at timestamp\n    // this leads to rearrangement of 1.B (\"sending\"), 2.A (\"received\"). Still firstMessageOnFirstLoadedPage.current\n    // points to message A, but now this message has index 1 => previousNumItemsPrepended.current === 1\n    // That in turn leads to incorrect index calculation in VirtualizedMessageList trying to access a message\n    // at non-existent index. Therefore, we ignore messages of status \"sending\" / \"failed\" in order they are\n    // not considered as prepended messages.\n    const currentFirstMessageStatus = isLocalMessage(currentFirstMessage)\n      ? currentFirstMessage.status\n      : undefined;\n    const firstMsgMovedAfterMessagesInExcludedStatus = !!(\n      currentFirstMessageStatus &&\n      STATUSES_EXCLUDED_FROM_PREPEND[currentFirstMessageStatus]\n    );\n\n    if (noNewMessages || firstMsgMovedAfterMessagesInExcludedStatus) {\n      return previousNumItemsPrepended.current;\n    }\n\n    if (!firstMessageOnFirstLoadedPage.current) {\n      firstMessageOnFirstLoadedPage.current = currentFirstMessage;\n    }\n    previousFirstMessageOnFirstLoadedPage.current = currentFirstMessage;\n    // if new messages were prepended, find out how many\n    // start with this number because there cannot be fewer prepended items than before\n    for (\n      let prependedMessageCount = previousNumItemsPrepended.current;\n      prependedMessageCount < messages.length;\n      prependedMessageCount += 1\n    ) {\n      const messageIsFirstOnFirstLoadedPage =\n        messages[prependedMessageCount].id === firstMessageOnFirstLoadedPage.current?.id;\n\n      if (messageIsFirstOnFirstLoadedPage) {\n        previousNumItemsPrepended.current = prependedMessageCount - firstRealMessageIndex;\n        return previousNumItemsPrepended.current;\n      }\n    }\n\n    // if no match has found, we have jumped - reset the prepended item count.\n    firstMessageOnFirstLoadedPage.current = currentFirstMessage;\n    previousNumItemsPrepended.current = 0;\n    return 0;\n    // TODO: there's a bug here, the messages prop is the same array instance (something mutates it)\n    // that's why the second dependency is necessary\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [firstRealMessageIndex, messages, messages?.length]);\n\n  return numItemsPrepended;\n}\n","import { useEffect, useRef, useState } from 'react';\nimport type { RenderedMessage } from '../../utils';\n\ntype UseScrollToBottomOnNewMessageParams = {\n  scrollToBottom: () => void;\n  messages?: RenderedMessage[];\n  /** When `true`, the list will scroll to the latest message when the window regains focus */\n  scrollToLatestMessageOnFocus?: boolean;\n};\n\nexport const useScrollToBottomOnNewMessage = ({\n  messages,\n  scrollToBottom,\n  scrollToLatestMessageOnFocus,\n}: UseScrollToBottomOnNewMessageParams) => {\n  const [newMessagesReceivedInBackground, setNewMessagesReceivedInBackground] =\n    useState(false);\n\n  const scrollToBottomIfConfigured = useRef<(e: Event) => void>(undefined);\n\n  scrollToBottomIfConfigured.current = (event: Event) => {\n    if (\n      !scrollToLatestMessageOnFocus ||\n      !newMessagesReceivedInBackground ||\n      event.target !== window\n    ) {\n      return;\n    }\n\n    setTimeout(scrollToBottom, 100);\n  };\n\n  useEffect(() => {\n    setNewMessagesReceivedInBackground(true);\n  }, [messages]);\n\n  useEffect(() => {\n    const handleFocus = (event: Event) => {\n      scrollToBottomIfConfigured.current?.(event);\n    };\n\n    const handleBlur = () => {\n      setNewMessagesReceivedInBackground(false);\n    };\n\n    if (typeof window !== 'undefined') {\n      window.addEventListener('focus', handleFocus);\n      window.addEventListener('blur', handleBlur);\n    }\n\n    return () => {\n      window.removeEventListener('focus', handleFocus);\n      window.removeEventListener('blur', handleBlur);\n    };\n  }, []);\n};\n","import { useEffect, useRef } from 'react';\nimport type { RenderedMessage } from '../../utils';\nimport type { LocalMessage } from 'stream-chat';\n\nexport function useShouldForceScrollToBottom(\n  messages: RenderedMessage[],\n  currentUserId?: string,\n) {\n  const lastFocusedOwnMessage = useRef('');\n  const initialFocusRegistered = useRef(false);\n\n  function recheckForNewOwnMessage() {\n    if (messages && messages.length > 0) {\n      const lastMessage = messages[messages.length - 1];\n\n      if (\n        (lastMessage as LocalMessage).user?.id === currentUserId &&\n        lastFocusedOwnMessage.current !== lastMessage.id\n      ) {\n        lastFocusedOwnMessage.current = lastMessage.id;\n        return true;\n      }\n    }\n    return false;\n  }\n\n  useEffect(() => {\n    if (messages && messages.length && !initialFocusRegistered.current) {\n      initialFocusRegistered.current = true;\n      recheckForNewOwnMessage();\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [messages, messages?.length]);\n\n  return recheckForNewOwnMessage;\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { RenderedMessage } from '../../utils';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UseUnreadMessagesNotificationParams = {\n  showAlways: boolean;\n  unreadCount: number;\n  lastRead?: Date | null;\n};\n\n/**\n * Controls the logic when an `UnreadMessagesNotification` component should be shown.\n * In virtualized message list there is no notion of being scrolled below or above `UnreadMessagesSeparator`.\n * Therefore, the `UnreadMessagesNotification` component is rendered based on timestamps.\n * If the there are unread messages in the channel and the `VirtualizedMessageList` renders\n * messages created later than the last read message in the channel, then the\n * `UnreadMessagesNotification` component is rendered. This is an approximate equivalent to being\n * scrolled below the `UnreadMessagesNotification` component.\n * @param lastRead\n * @param showAlways\n * @param unreadCount\n */\nexport const useUnreadMessagesNotificationVirtualized = ({\n  lastRead,\n  showAlways,\n  unreadCount,\n}: UseUnreadMessagesNotificationParams) => {\n  const [show, setShow] = useState(false);\n\n  const toggleShowUnreadMessagesNotification = useCallback(\n    (renderedMessages: RenderedMessage[]) => {\n      if (!unreadCount) return;\n      const firstRenderedMessage = renderedMessages[0];\n      const lastRenderedMessage = renderedMessages.slice(-1)[0];\n      if (!(firstRenderedMessage && lastRenderedMessage)) return;\n\n      const firstRenderedMessageTime = new Date(\n        (firstRenderedMessage as LocalMessage).created_at ?? 0,\n      ).getTime();\n      const lastRenderedMessageTime = new Date(\n        (lastRenderedMessage as LocalMessage).created_at ?? 0,\n      ).getTime();\n      const lastReadTime = new Date(lastRead ?? 0).getTime();\n\n      const scrolledBelowSeparator =\n        !!lastReadTime && firstRenderedMessageTime > lastReadTime;\n      const scrolledAboveSeparator =\n        !!lastReadTime && lastRenderedMessageTime < lastReadTime;\n\n      setShow(\n        showAlways\n          ? scrolledBelowSeparator || scrolledAboveSeparator\n          : scrolledBelowSeparator,\n      );\n    },\n    [lastRead, showAlways, unreadCount],\n  );\n\n  useEffect(() => {\n    if (!unreadCount) setShow(false);\n  }, [unreadCount]);\n\n  return { show, toggleShowUnreadMessagesNotification };\n};\n","import React, { useLayoutEffect } from 'react';\nimport type { RefObject } from 'react';\n\nimport { DateSeparator as DefaultDateSeparator } from '../DateSeparator';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useFloatingDateSeparatorMessageList } from './hooks/MessageList';\nimport { useFloatingDateSeparator } from './hooks/VirtualizedMessageList';\nimport type { RenderedMessage } from './utils';\n\ntype BaseProps = {\n  disableDateSeparator: boolean;\n  processedMessages: RenderedMessage[];\n};\n\nexport type FloatingDateSeparatorProps = BaseProps &\n  (\n    | {\n        /** For VirtualizedMessageList: ref the parent calls with visible items */\n        itemsRenderedRef: RefObject<((rendered: RenderedMessage[]) => void) | null>;\n      }\n    | {\n        /** For MessageList: scroll container to query DOM for date separators */\n        listElement: HTMLDivElement | null;\n      }\n  );\n\n/**\n * Renders a floating date separator when the user has scrolled past the in-flow date.\n * State is internal so MessageList/VirtualizedMessageList do not re-render when it changes.\n * Use itemsRenderedRef for Virtuoso, listElement for non-virtualized MessageList.\n */\nexport const FloatingDateSeparator = (props: FloatingDateSeparatorProps) => {\n  const { DateSeparator = DefaultDateSeparator } = useComponentContext(\n    'FloatingDateSeparator',\n  );\n  const { disableDateSeparator, processedMessages } = props;\n\n  const listElement = 'listElement' in props ? props.listElement : null;\n  const useDomMode = listElement != null;\n\n  const virtuosoResult = useFloatingDateSeparator({\n    disableDateSeparator,\n    processedMessages,\n  });\n  const domResult = useFloatingDateSeparatorMessageList({\n    disableDateSeparator,\n    listElement,\n    processedMessages,\n  });\n\n  const floatingDate = useDomMode ? domResult.floatingDate : virtuosoResult.floatingDate;\n  const showFloatingDate = useDomMode\n    ? domResult.showFloatingDate\n    : virtuosoResult.showFloatingDate;\n\n  const itemsRenderedRef = 'itemsRenderedRef' in props ? props.itemsRenderedRef : null;\n  useLayoutEffect(() => {\n    if (!itemsRenderedRef) return;\n    itemsRenderedRef.current = virtuosoResult.onItemsRendered;\n    return () => {\n      itemsRenderedRef.current = null;\n    };\n  }, [itemsRenderedRef, virtuosoResult.onItemsRendered]);\n\n  if (!showFloatingDate || !floatingDate || !DateSeparator) return null;\n\n  return <DateSeparator date={floatingDate} floating />;\n};\n","import React from 'react';\n\nimport type { Event, LocalMessage } from 'stream-chat';\nimport type { TimestampFormatterOptions } from '../../i18n/types';\n\nexport type EventComponentProps = TimestampFormatterOptions & {\n  message: LocalMessage & {\n    event?: Event;\n  };\n  unsafeHTML?: boolean;\n};\n\n/**\n * Component to display system and channel event messages\n */\nconst UnMemoizedEventComponent = (props: EventComponentProps) => {\n  const { message, unsafeHTML = false } = props;\n  const { type } = message;\n\n  if (type !== 'system') return null;\n\n  return (\n    <div className='str-chat__message--system' data-testid='message-system'>\n      <div className='str-chat__message--system__text'>\n        {unsafeHTML ? (\n          <div\n            dangerouslySetInnerHTML={{ __html: message.html || '' }}\n            data-unsafe-inner-html\n          />\n        ) : (\n          <span>{message.text}</span>\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport const EventComponent = React.memo(\n  UnMemoizedEventComponent,\n) as typeof UnMemoizedEventComponent;\n","import type { ReactNode } from 'react';\nimport React, { Fragment } from 'react';\nimport type { GroupStyle, RenderedMessage } from './utils';\nimport { getIsFirstUnreadMessage, isDateSeparatorMessage, isIntroMessage } from './utils';\nimport type { MessageProps } from '../Message';\nimport { Message } from '../Message';\nimport { DateSeparator as DefaultDateSeparator } from '../DateSeparator';\nimport { EventComponent as DefaultMessageSystem } from '../EventComponent';\nimport { UnreadMessagesSeparator as DefaultUnreadMessagesSeparator } from './UnreadMessagesSeparator';\nimport type { LocalMessage, UserResponse } from 'stream-chat';\nimport type { ComponentContextValue, CustomClasses } from '../../context';\nimport type { ChannelUnreadUiState } from '../../types';\n\nexport interface RenderMessagesOptions {\n  components: ComponentContextValue;\n  lastReceivedMessageId: string | null;\n  messageGroupStyles: Record<string, GroupStyle>;\n  messages: Array<RenderedMessage>;\n  ownMessagesDeliveredToOthers: Record<string, UserResponse[]>;\n  /**\n   * Object mapping message IDs of own messages to the users who read those messages.\n   */\n  readData: Record<string, Array<UserResponse>>;\n  /**\n   * Props forwarded to the Message component.\n   */\n  sharedMessageProps: SharedMessageProps;\n  /** Latest own message in currently displayed message set. */\n  lastOwnMessage?: LocalMessage;\n  /**\n   * Current user's channel read state used to render components reflecting unread state.\n   * It does not reflect the back-end state if a channel is marked read on mount.\n   * This is in order to keep the unread UI when an unread channel is open.\n   */\n  channelUnreadUiState?: ChannelUnreadUiState;\n  customClasses?: CustomClasses;\n}\n\nexport type SharedMessageProps = Omit<MessageProps, MessagePropsToOmit>;\n\nexport type MessageRenderer = (options: RenderMessagesOptions) => Array<ReactNode>;\n\ntype MessagePropsToOmit =\n  | 'channel'\n  | 'deliveredTo'\n  | 'groupStyles'\n  | 'initialMessage'\n  | 'lastReceivedId'\n  | 'message'\n  | 'readBy';\n\nexport function defaultRenderMessages({\n  channelUnreadUiState,\n  components,\n  customClasses,\n  lastOwnMessage,\n  lastReceivedMessageId: lastReceivedId,\n  messageGroupStyles,\n  messages,\n  ownMessagesDeliveredToOthers,\n  readData,\n  sharedMessageProps: messageProps,\n}: RenderMessagesOptions) {\n  const {\n    DateSeparator = DefaultDateSeparator,\n    HeaderComponent,\n    MessageListItem = 'li',\n    MessageSystem = DefaultMessageSystem,\n    UnreadMessagesSeparator = DefaultUnreadMessagesSeparator,\n  } = components;\n\n  const renderedMessages = [];\n  let firstMessage;\n  let previousMessage = undefined;\n  for (let index = 0; index < messages.length; index++) {\n    const message = messages[index];\n    if (isDateSeparatorMessage(message)) {\n      renderedMessages.push(\n        <MessageListItem data-index={index} key={`${message.date.toISOString()}-i`}>\n          <DateSeparator\n            date={message.date}\n            formatDate={messageProps.formatDate}\n            unread={message.unread}\n          />\n        </MessageListItem>,\n      );\n    } else if (isIntroMessage(message)) {\n      if (HeaderComponent) {\n        renderedMessages.push(\n          <MessageListItem data-index={index} key='intro'>\n            <HeaderComponent />\n          </MessageListItem>,\n        );\n      }\n    } else if (message.type === 'system') {\n      renderedMessages.push(\n        <MessageListItem\n          data-index={index}\n          data-message-id={message.id}\n          key={message.id || message.created_at.toISOString()}\n        >\n          <MessageSystem message={message} unsafeHTML={messageProps.unsafeHTML} />\n        </MessageListItem>,\n      );\n    } else {\n      if (!firstMessage) {\n        firstMessage = message;\n      }\n      const groupStyles: GroupStyle = messageGroupStyles[message.id] || '';\n      const messageClass =\n        customClasses?.message || `str-chat__li str-chat__li--${groupStyles}`;\n\n      const isFirstUnreadMessage = getIsFirstUnreadMessage({\n        firstUnreadMessageId: channelUnreadUiState?.first_unread_message_id,\n        isFirstMessage: !!firstMessage?.id && firstMessage.id === message.id,\n        lastReadDate: channelUnreadUiState?.last_read,\n        lastReadMessageId: channelUnreadUiState?.last_read_message_id,\n        message,\n        previousMessage,\n        unreadMessageCount: channelUnreadUiState?.unread_messages,\n      });\n\n      renderedMessages.push(\n        <Fragment key={message.id || message.created_at.toISOString()}>\n          {isFirstUnreadMessage && UnreadMessagesSeparator && (\n            <MessageListItem className='str-chat__li str-chat__unread-messages-separator-wrapper'>\n              <UnreadMessagesSeparator\n                unreadCount={channelUnreadUiState?.unread_messages}\n              />\n            </MessageListItem>\n          )}\n          <MessageListItem\n            className={messageClass}\n            data-index={index}\n            data-message-id={message.id}\n            data-testid={messageClass}\n          >\n            <Message\n              deliveredTo={ownMessagesDeliveredToOthers[message.id] || []}\n              groupStyles={[groupStyles]} /* TODO: convert to simple string */\n              lastOwnMessage={lastOwnMessage}\n              lastReceivedId={lastReceivedId}\n              message={message}\n              readBy={readData[message.id] || []}\n              {...messageProps}\n            />\n          </MessageListItem>\n        </Fragment>,\n      );\n      previousMessage = message;\n    }\n  }\n  return renderedMessages;\n}\n","// last own message should be tracked in the low-level client\nexport const findReverse = <T>(\n  items: T[],\n  matches: (items: T) => boolean,\n): T | undefined => {\n  for (let i = items.length - 1; i >= 0; i -= 1) {\n    if (matches(items[i])) {\n      return items[i];\n    }\n  }\n\n  return undefined;\n};\n","import { useMemo } from 'react';\nimport { findReverse } from '../../../utils/findReverse';\nimport type { LocalMessage } from 'stream-chat';\n\n// fixme: we should be able to retrieve last own message quickly from the LLC. Should be done when refactoring the LLC Channel state to reactive.\nexport const useLastOwnMessage = ({\n  messages,\n  ownUserId,\n}: {\n  messages?: LocalMessage[];\n  ownUserId?: string;\n}) =>\n  useMemo(\n    () =>\n      messages && findReverse(messages, (msg) => (msg.user && msg.user.id) === ownUserId),\n    [messages, ownUserId],\n  );\n","import { useSyncExternalStore } from 'use-sync-external-store/shim';\n\nconst REDUCED_MOTION_MEDIA_QUERY = '(prefers-reduced-motion: reduce)';\n\nconst getReducedMotionSnapshot = () => {\n  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n    return false;\n  }\n\n  return window.matchMedia(REDUCED_MOTION_MEDIA_QUERY).matches;\n};\n\nconst subscribeToReducedMotion = (onStoreChange: () => void) => {\n  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n    return () => undefined;\n  }\n\n  const mediaQueryList = window.matchMedia(REDUCED_MOTION_MEDIA_QUERY);\n  const handleChange = () => onStoreChange();\n\n  if (typeof mediaQueryList.addEventListener === 'function') {\n    mediaQueryList.addEventListener('change', handleChange);\n    return () => mediaQueryList.removeEventListener('change', handleChange);\n  }\n\n  mediaQueryList.addListener(handleChange);\n  return () => mediaQueryList.removeListener(handleChange);\n};\n\nexport const useReducedMotionPreference = () =>\n  useSyncExternalStore(subscribeToReducedMotion, getReducedMotionSnapshot, () => false);\n","import React, { useEffect, useState } from 'react';\n\nimport {\n  useChannelStateContext,\n  useChatContext,\n  useTranslationContext,\n} from '../../context';\n\nimport type { Event } from 'stream-chat';\nimport { Badge } from '../Badge';\nimport { Button } from '../Button';\nimport { IconArrowDown } from '../Icons';\n\nexport type ScrollToLatestMessageButtonProps = {\n  /** When true, user has jumped to an older message set and newer messages can be loaded */\n  isNotAtLatestMessageSet?: boolean;\n  isMessageListScrolledToBottom?: boolean;\n  onClick: React.MouseEventHandler;\n  threadList?: boolean;\n};\n\nconst UnMemoizedScrollToLatestMessageButton = (\n  props: ScrollToLatestMessageButtonProps,\n) => {\n  const {\n    isMessageListScrolledToBottom,\n    isNotAtLatestMessageSet = false,\n    onClick,\n    threadList,\n  } = props;\n\n  const { channel: activeChannel, client } = useChatContext();\n  const { thread } = useChannelStateContext();\n  const { t } = useTranslationContext();\n  const [countUnread, setCountUnread] = useState(activeChannel?.countUnread() || 0);\n  const [replyCount, setReplyCount] = useState(thread?.reply_count || 0);\n  const observedEvent = threadList ? 'message.updated' : 'message.new';\n\n  useEffect(() => {\n    const handleEvent = (event: Event) => {\n      const newMessageInAnotherChannel = event.cid !== activeChannel?.cid;\n      const newMessageIsMine = event.user?.id === client.user?.id;\n\n      const isThreadOpen = !!thread;\n      const newMessageIsReply = !!event.message?.parent_id;\n      const dontIncreaseMainListCounterOnNewReply =\n        isThreadOpen && !threadList && newMessageIsReply;\n\n      if (\n        isMessageListScrolledToBottom ||\n        newMessageInAnotherChannel ||\n        newMessageIsMine ||\n        dontIncreaseMainListCounterOnNewReply\n      ) {\n        return;\n      }\n\n      if (event.type === 'message.new') {\n        // cannot rely on channel.countUnread because active channel is automatically marked read\n        setCountUnread((prev) => prev + 1);\n      } else if (event.message?.id === thread?.id) {\n        const newReplyCount = event.message?.reply_count || 0;\n        setCountUnread(() => newReplyCount - replyCount);\n      }\n    };\n    client.on(observedEvent, handleEvent);\n\n    return () => {\n      client.off(observedEvent, handleEvent);\n    };\n  }, [\n    activeChannel,\n    client,\n    isMessageListScrolledToBottom,\n    observedEvent,\n    replyCount,\n    thread,\n    threadList,\n  ]);\n\n  useEffect(() => {\n    if (isMessageListScrolledToBottom) {\n      setCountUnread(0);\n      setReplyCount(thread?.reply_count || 0);\n    }\n  }, [isMessageListScrolledToBottom, thread]);\n\n  if (isMessageListScrolledToBottom && !isNotAtLatestMessageSet) return null;\n\n  return (\n    <div className='str-chat__jump-to-latest-message'>\n      <Button\n        appearance='ghost'\n        aria-label={t('aria/Jump to latest message')}\n        aria-live='polite'\n        circular\n        className='str-chat__jump-to-latest-message__button'\n        data-testid='scroll-to-latest-message-button'\n        onClick={onClick}\n        size='md'\n        variant='secondary'\n      >\n        <IconArrowDown />\n      </Button>\n      {countUnread > 0 && (\n        <Badge\n          className='str-chat__jump-to-latest__unread-count'\n          data-testid='unread-message-notification-counter'\n          size='md'\n          variant='primary'\n        >\n          {countUnread}\n        </Badge>\n      )}\n    </div>\n  );\n};\n\nexport const ScrollToLatestMessageButton = React.memo(\n  UnMemoizedScrollToLatestMessageButton,\n) as typeof UnMemoizedScrollToLatestMessageButton;\n","import clsx from 'clsx';\nimport React from 'react';\n\nimport {\n  useEnrichedMessages,\n  useMessageListElements,\n  useScrollLocationLogic,\n  useUnreadMessagesNotification,\n} from './hooks/MessageList';\nimport { useMarkRead } from './hooks/useMarkRead';\nimport { NewMessageNotification as DefaultNewMessageNotification } from './NewMessageNotification';\nimport { UnreadMessagesNotification as DefaultUnreadMessagesNotification } from './UnreadMessagesNotification';\n\nimport type { ChannelActionContextValue } from '../../context/ChannelActionContext';\nimport { useChannelActionContext } from '../../context/ChannelActionContext';\nimport type { ChannelStateContextValue } from '../../context/ChannelStateContext';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { DialogManagerProvider } from '../../context';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { MessageListContextProvider } from '../../context/MessageListContext';\nimport { MessageTranslationViewProvider } from '../../context/MessageTranslationViewContext';\nimport { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';\nimport type { InfiniteScrollProps } from '../InfiniteScrollPaginator/InfiniteScroll';\nimport { InfiniteScroll } from '../InfiniteScrollPaginator/InfiniteScroll';\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../Loading';\nimport { MESSAGE_ACTIONS } from '../Message/utils';\nimport { TypingIndicator as DefaultTypingIndicator } from '../TypingIndicator';\nimport { MessageListMainPanel as DefaultMessageListMainPanel } from './MessageListMainPanel';\n\nimport { FloatingDateSeparator } from './FloatingDateSeparator';\nimport type { MessageRenderer } from './renderMessages';\nimport { defaultRenderMessages } from './renderMessages';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { GroupStyle, ProcessMessagesParams, RenderedMessage } from './utils';\nimport type { MessageProps } from '../Message/types';\n\nimport {\n  DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD,\n  DEFAULT_NEXT_CHANNEL_PAGE_SIZE,\n} from '../../constants/limits';\nimport { useLastOwnMessage } from './hooks/useLastOwnMessage';\nimport { useReducedMotionPreference } from './hooks/useReducedMotionPreference';\nimport { ScrollToLatestMessageButton as DefaultScrollToLatestMessageButton } from './ScrollToLatestMessageButton';\nimport {\n  NotificationList as DefaultNotificationList,\n  useNotificationTarget,\n} from '../Notifications';\nimport { AriaLiveRegion, useIncomingMessageAnnouncements } from '../Accessibility';\n\ntype MessageListWithContextProps = Omit<\n  ChannelStateContextValue,\n  'members' | 'mutes' | 'watchers'\n> &\n  MessageListProps;\n\ntype JumpToLatestPhase = 'idle' | 'waiting-for-render' | 'animating';\ntype HighlightedJumpPhase = 'idle' | 'waiting-for-render' | 'animating';\n\nconst getMessageSetSignature = (messages: LocalMessage[]) =>\n  `${messages.length}:${messages[0]?.id || ''}:${messages[messages.length - 1]?.id || ''}`;\n\nconst getMessageTimestamp = (message?: LocalMessage) =>\n  message?.created_at?.getTime?.() ?? null;\n\nconst MessageListWithContext = (props: MessageListWithContextProps) => {\n  const {\n    channel,\n    channelUnreadUiState,\n    disableDateSeparator = false,\n    groupStyles,\n    hasMoreNewer = false,\n    headerPosition,\n    hideDeletedMessages = false,\n    hideNewMessageSeparator = false,\n    highlightedMessageId,\n    internalInfiniteScrollProps: {\n      threshold: loadMoreScrollThreshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD,\n      ...restInternalInfiniteScrollProps\n    } = {},\n    jumpToLatestMessage = () => Promise.resolve(),\n    loadMore: loadMoreCallback,\n    loadMoreNewer: loadMoreNewerCallback,\n    maxTimeBetweenGroupedMessages,\n    messageActions = Object.keys(MESSAGE_ACTIONS),\n    messageLimit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE,\n    messages = [],\n    noGroupByUser = false,\n    reactionDetailsSort,\n    renderMessages = defaultRenderMessages,\n    returnAllReadData = false,\n    reviewProcessedMessage,\n    showUnreadNotificationAlways,\n    sortReactions,\n    suppressAutoscroll,\n    thread,\n    threadList = false,\n    unsafeHTML = false,\n  } = props;\n\n  const [listElement, setListElement] = React.useState<HTMLDivElement | null>(null);\n  const [jumpToLatestPhase, setJumpToLatestPhase] =\n    React.useState<JumpToLatestPhase>('idle');\n  const [highlightedJumpPhase, setHighlightedJumpPhase] =\n    React.useState<HighlightedJumpPhase>('idle');\n  const [jumpSourceMessageSetSignature, setJumpSourceMessageSetSignature] =\n    React.useState<string | null>(null);\n  const previousHasMoreNewerRef = React.useRef(hasMoreNewer);\n  const previousMessageSetSignatureRef = React.useRef('');\n  const previousMessageSetBoundsRef = React.useRef<{\n    firstTimestamp: number | null;\n    lastTimestamp: number | null;\n  }>({\n    firstTimestamp: null,\n    lastTimestamp: null,\n  });\n\n  const { customClasses } = useChatContext('MessageList');\n  const prefersReducedMotion = useReducedMotionPreference();\n  const scrollBehavior = prefersReducedMotion ? 'auto' : 'smooth';\n\n  const {\n    EmptyStateIndicator = DefaultEmptyStateIndicator,\n    LoadingIndicator = DefaultLoadingIndicator,\n    MessageListMainPanel = DefaultMessageListMainPanel,\n    MessageListWrapper = 'ul',\n    NewMessageNotification = DefaultNewMessageNotification,\n    NotificationList = DefaultNotificationList,\n    ScrollToLatestMessageButton = DefaultScrollToLatestMessageButton,\n    TypingIndicator = DefaultTypingIndicator,\n    UnreadMessagesNotification = DefaultUnreadMessagesNotification,\n  } = useComponentContext();\n\n  const notificationTarget = useNotificationTarget();\n  const messageSetSignature = React.useMemo(\n    () => getMessageSetSignature(messages),\n    [messages],\n  );\n  const messageSetBounds = React.useMemo(\n    () => ({\n      firstTimestamp: getMessageTimestamp(messages[0]),\n      lastTimestamp: getMessageTimestamp(messages[messages.length - 1]),\n    }),\n    [messages],\n  );\n  const isJumpingToLatest = jumpToLatestPhase !== 'idle';\n  const isHighlightedJumpRequested = !!highlightedMessageId;\n  // Highlighted jumps temporarily disable prepend pagination so a target\n  // message rendered near the top does not immediately load the previous page.\n  const isJumpingToHighlightedMessage = highlightedJumpPhase !== 'idle';\n  const justReachedLatestMergedSet = previousHasMoreNewerRef.current && !hasMoreNewer;\n\n  const {\n    hasNewMessages,\n    isMessageListScrolledToBottom,\n    onScroll,\n    scrollToBottom,\n    wrapperRect,\n  } = useScrollLocationLogic({\n    disableAutoScrollToBottom:\n      isJumpingToLatest || isHighlightedJumpRequested || justReachedLatestMergedSet,\n    disableScrollManagement: isJumpingToLatest || isJumpingToHighlightedMessage,\n    hasMoreNewer,\n    listElement,\n    loadingMore: props.loadingMore,\n    loadMoreScrollThreshold,\n    messages, // todo: is it correct to base the scroll logic on an array that does not contain date separators or intro?\n    scrolledUpThreshold: props.scrolledUpThreshold,\n    suppressAutoscroll,\n  });\n  const isTypingIndicatorScrolledToBottom =\n    isMessageListScrolledToBottom &&\n    !isJumpingToLatest &&\n    !isJumpingToHighlightedMessage &&\n    !justReachedLatestMergedSet;\n\n  const { show: showUnreadMessagesNotification } = useUnreadMessagesNotification({\n    isMessageListScrolledToBottom,\n    listElement,\n    showAlways: !!showUnreadNotificationAlways,\n    unreadCount: channelUnreadUiState?.unread_messages,\n  });\n\n  useMarkRead({\n    isMessageListScrolledToBottom: isTypingIndicatorScrolledToBottom,\n    messageListIsThread: threadList,\n    wasMarkedUnread: !!channelUnreadUiState?.first_unread_message_id,\n  });\n\n  const { messageGroupStyles, messages: enrichedMessages } = useEnrichedMessages({\n    channel,\n    disableDateSeparator,\n    groupStyles,\n    headerPosition,\n    hideDeletedMessages,\n    hideNewMessageSeparator,\n    maxTimeBetweenGroupedMessages,\n    messages,\n    noGroupByUser,\n    reviewProcessedMessage,\n  });\n\n  const lastOwnMessage = useLastOwnMessage({\n    messages,\n    ownUserId: channel.getClient().user?.id,\n  });\n\n  const elements = useMessageListElements({\n    channelUnreadUiState,\n    enrichedMessages,\n    internalMessageProps: {\n      additionalMessageComposerProps: props.additionalMessageComposerProps,\n      closeReactionSelectorOnClick: props.closeReactionSelectorOnClick,\n      disableQuotedMessages: props.disableQuotedMessages,\n      formatDate: props.formatDate,\n      Message: props.Message,\n      messageActions,\n      messageListRect: wrapperRect,\n      onMentionsClick: props.onMentionsClick,\n      onMentionsHover: props.onMentionsHover,\n      onUserClick: props.onUserClick,\n      onUserHover: props.onUserHover,\n      openThread: props.openThread,\n      reactionDetailsSort,\n      renderText: props.renderText,\n      retrySendMessage: props.retrySendMessage,\n      showAvatar: props.showAvatar,\n      sortReactions,\n      unsafeHTML,\n    },\n    lastOwnMessage,\n    messageGroupStyles,\n    messages,\n    renderMessages,\n    returnAllReadData,\n    threadList,\n  });\n\n  useIncomingMessageAnnouncements({\n    activeThreadId: thread?.id,\n    channel,\n    ownUserId: channel.getClient().user?.id,\n    threadList,\n  });\n\n  const messageListClass = customClasses?.messageList || 'str-chat__message-list';\n\n  const loadMore = React.useCallback(() => {\n    if (loadMoreCallback) {\n      loadMoreCallback(messageLimit);\n    }\n  }, [loadMoreCallback, messageLimit]);\n\n  const loadMoreNewer = React.useCallback(() => {\n    if (loadMoreNewerCallback) {\n      loadMoreNewerCallback(messageLimit);\n    }\n  }, [loadMoreNewerCallback, messageLimit]);\n\n  const scrollToBottomFromNotification = React.useCallback(async () => {\n    if (hasMoreNewer) {\n      setJumpSourceMessageSetSignature(messageSetSignature);\n      setJumpToLatestPhase('waiting-for-render');\n      try {\n        await jumpToLatestMessage();\n      } catch (error) {\n        setJumpSourceMessageSetSignature(null);\n        setJumpToLatestPhase('idle');\n        throw error;\n      }\n      return;\n    }\n\n    scrollToBottom({ behavior: scrollBehavior });\n  }, [\n    scrollBehavior,\n    hasMoreNewer,\n    jumpToLatestMessage,\n    messageSetSignature,\n    scrollToBottom,\n  ]);\n\n  React.useLayoutEffect(() => {\n    if (\n      jumpToLatestPhase !== 'waiting-for-render' ||\n      hasMoreNewer ||\n      !listElement?.scrollTo ||\n      messageSetSignature === jumpSourceMessageSetSignature\n    ) {\n      return;\n    }\n\n    listElement.scrollTo({ top: 0 });\n\n    const animationFrameId = requestAnimationFrame(() => {\n      setJumpToLatestPhase('animating');\n      listElement.scrollTo({\n        behavior: scrollBehavior,\n        top: listElement.scrollHeight,\n      });\n    });\n\n    return () => cancelAnimationFrame(animationFrameId);\n  }, [\n    scrollBehavior,\n    hasMoreNewer,\n    jumpSourceMessageSetSignature,\n    jumpToLatestPhase,\n    listElement,\n    messageSetSignature,\n  ]);\n\n  React.useLayoutEffect(() => {\n    if (jumpToLatestPhase !== 'animating' || !listElement?.scrollTo) {\n      return;\n    }\n\n    const finalize = () => {\n      listElement.scrollTo({ top: listElement.scrollHeight });\n      setJumpSourceMessageSetSignature(null);\n      setJumpToLatestPhase('idle');\n    };\n\n    const settleTimeoutId = setTimeout(finalize, 500);\n\n    return () => {\n      clearTimeout(settleTimeoutId);\n    };\n  }, [jumpToLatestPhase, listElement]);\n\n  React.useLayoutEffect(() => {\n    if (!highlightedMessageId) {\n      setHighlightedJumpPhase('idle');\n      return;\n    }\n\n    const element = listElement?.querySelector(\n      `[data-message-id='${highlightedMessageId}']`,\n    );\n    if (!element) {\n      setHighlightedJumpPhase('waiting-for-render');\n      return;\n    }\n\n    const messageSetChanged =\n      previousMessageSetSignatureRef.current !== messageSetSignature;\n    setHighlightedJumpPhase(messageSetChanged ? 'animating' : 'idle');\n    let settleTimeoutId: ReturnType<typeof setTimeout> | undefined;\n\n    const animationFrameId = requestAnimationFrame(() => {\n      element.scrollIntoView({\n        behavior: scrollBehavior,\n        block: 'center',\n      });\n\n      if (!messageSetChanged || !listElement?.scrollTo) {\n        setHighlightedJumpPhase('idle');\n        return;\n      }\n\n      settleTimeoutId = setTimeout(() => {\n        const elementRect = element.getBoundingClientRect();\n        const listRect = listElement.getBoundingClientRect();\n        const targetTop =\n          listElement.scrollTop +\n          (elementRect.top - listRect.top) -\n          (listElement.clientHeight - elementRect.height) / 2;\n\n        listElement.scrollTo({ top: Math.max(targetTop, 0) });\n        setHighlightedJumpPhase('idle');\n      }, 500);\n    });\n\n    return () => {\n      cancelAnimationFrame(animationFrameId);\n      if (settleTimeoutId) {\n        clearTimeout(settleTimeoutId);\n      }\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [scrollBehavior, highlightedMessageId, messageSetSignature]);\n\n  React.useEffect(() => {\n    previousHasMoreNewerRef.current = hasMoreNewer;\n  }, [hasMoreNewer]);\n\n  React.useEffect(() => {\n    previousMessageSetSignatureRef.current = messageSetSignature;\n    previousMessageSetBoundsRef.current = messageSetBounds;\n  }, [messageSetBounds, messageSetSignature]);\n\n  const id = useStableId();\n\n  const showEmptyStateIndicator = elements.length === 0 && !threadList;\n  const dialogManagerId = threadList\n    ? `message-list-dialog-manager-thread-${id}`\n    : `message-list-dialog-manager-${id}`;\n\n  return (\n    <MessageListContextProvider\n      value={{\n        listElement,\n        processedMessages: enrichedMessages,\n        scrollToBottom,\n      }}\n    >\n      <MessageTranslationViewProvider>\n        <MessageListMainPanel>\n          <DialogManagerProvider id={dialogManagerId}>\n            {!threadList && showUnreadMessagesNotification && (\n              <UnreadMessagesNotification\n                unreadCount={channelUnreadUiState?.unread_messages}\n              />\n            )}\n            <FloatingDateSeparator\n              disableDateSeparator={disableDateSeparator}\n              listElement={listElement}\n              processedMessages={enrichedMessages}\n            />\n            <div\n              className={clsx(messageListClass, customClasses?.threadList)}\n              onScroll={onScroll}\n              ref={setListElement}\n              tabIndex={0}\n            >\n              {showEmptyStateIndicator ? (\n                <EmptyStateIndicator listType={threadList ? 'thread' : 'message'} />\n              ) : (\n                <InfiniteScroll\n                  className='str-chat__message-list-scroll'\n                  data-testid='reverse-infinite-scroll'\n                  hasNextPage={props.hasMoreNewer}\n                  hasPreviousPage={isJumpingToHighlightedMessage ? false : props.hasMore}\n                  head={props.head}\n                  isLoading={Boolean(\n                    props.loadingMore || props.loadingMoreForJumpToChannelMessage,\n                  )}\n                  loader={\n                    <div className='str-chat__list__loading' key='loading-indicator'>\n                      {(props.loadingMore ||\n                        props.loadingMoreForJumpToChannelMessage) && <LoadingIndicator />}\n                    </div>\n                  }\n                  loadNextPage={loadMoreNewer}\n                  loadPreviousPage={\n                    isJumpingToHighlightedMessage ? () => undefined : loadMore\n                  }\n                  threshold={loadMoreScrollThreshold}\n                  {...restInternalInfiniteScrollProps}\n                >\n                  <MessageListWrapper className='str-chat__ul'>\n                    {elements}\n                  </MessageListWrapper>\n                  <TypingIndicator\n                    isMessageListScrolledToBottom={isTypingIndicatorScrolledToBottom}\n                    scrollToBottom={scrollToBottom}\n                    threadList={threadList}\n                  />\n\n                  <div key='bottom' />\n                </InfiniteScroll>\n              )}\n            </div>\n            <NewMessageNotification\n              newMessageCount={channelUnreadUiState?.unread_messages}\n              showNotification={hasNewMessages || hasMoreNewer}\n            />\n            <ScrollToLatestMessageButton\n              isMessageListScrolledToBottom={isMessageListScrolledToBottom}\n              isNotAtLatestMessageSet={hasMoreNewer}\n              onClick={scrollToBottomFromNotification}\n              threadList={threadList}\n            />\n          </DialogManagerProvider>\n          <NotificationList panel={notificationTarget} />\n        </MessageListMainPanel>\n      </MessageTranslationViewProvider>\n    </MessageListContextProvider>\n  );\n};\n\ntype PropsDrilledToMessage =\n  | 'additionalMessageComposerProps'\n  | 'closeReactionSelectorOnClick'\n  | 'disableQuotedMessages'\n  | 'formatDate'\n  | 'Message'\n  | 'messageActions'\n  | 'onMentionsClick'\n  | 'onMentionsHover'\n  | 'onUserClick'\n  | 'onUserHover'\n  | 'openThread'\n  | 'reactionDetailsSort'\n  | 'renderText'\n  | 'retrySendMessage'\n  | 'showAvatar'\n  | 'sortReactions'\n  | 'unsafeHTML';\n\nexport type MessageListProps = Partial<Pick<MessageProps, PropsDrilledToMessage>> & {\n  /** Disables the injection of date separator components in MessageList, defaults to `false` */\n  disableDateSeparator?: boolean;\n  /** Callback function to set group styles for each message */\n  groupStyles?: (\n    message: RenderedMessage,\n    previousMessage: RenderedMessage,\n    nextMessage: RenderedMessage,\n    noGroupByUser: boolean,\n    maxTimeBetweenGroupedMessages?: number,\n  ) => GroupStyle;\n  /** Whether the list has more items to load */\n  hasMore?: boolean;\n  /** Element to be rendered at the top of the thread message list. By default, these are the Message and ThreadStart components */\n  head?: React.ReactElement;\n  /** Position to render HeaderComponent */\n  headerPosition?: number;\n  /** Hides the MessageDeleted components from the list, defaults to `false` */\n  hideDeletedMessages?: boolean;\n  /** Hides the DateSeparator component when new messages are received in a channel that's watched but not active, defaults to false */\n  hideNewMessageSeparator?: boolean;\n  /** Overrides the default props passed to [InfiniteScroll](https://github.com/GetStream/stream-chat-react/blob/master/src/components/InfiniteScrollPaginator/InfiniteScroll.tsx) */\n  internalInfiniteScrollProps?: Partial<InfiniteScrollProps>;\n  /** Function called when latest messages should be loaded, after the list has jumped at an earlier message set */\n  jumpToLatestMessage?: () => Promise<void>;\n  /** Whether or not the list is currently loading more items */\n  loadingMore?: boolean;\n  /** Whether or not the list is currently jumping to a highlighted message */\n  loadingMoreForJumpToChannelMessage?: boolean;\n  /** Whether or not the list is currently loading newer items */\n  loadingMoreNewer?: boolean;\n  /** Function called when more messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n  loadMore?: ChannelActionContextValue['loadMore'] | (() => Promise<void>);\n  /** Function called when newer messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n  loadMoreNewer?: ChannelActionContextValue['loadMoreNewer'] | (() => Promise<void>);\n  /** Maximum time in milliseconds that should occur between messages to still consider them grouped together */\n  maxTimeBetweenGroupedMessages?: number;\n  /** The limit to use when paginating messages */\n  messageLimit?: number;\n  /** The messages to render in the list, defaults to messages stored in [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/) */\n  messages?: LocalMessage[];\n  /** If true, turns off message UI grouping by user */\n  noGroupByUser?: boolean;\n  /** Overrides the way MessageList renders messages */\n  renderMessages?: MessageRenderer;\n  /** If true, `readBy` data supplied to the `Message` components will include all user read states per sent message */\n  returnAllReadData?: boolean;\n  /**\n   * Allows to review changes introduced to messages array on per message basis (e.g. date separator injection before a message).\n   * The array returned from the function is appended to the array of messages that are later rendered into React elements in the `MessageList`.\n   */\n  reviewProcessedMessage?: ProcessMessagesParams['reviewProcessedMessage'];\n  /**\n   * The pixel threshold under which the message list is considered to be so near to the bottom,\n   * so that if a new message is delivered, the list will be scrolled to the absolute bottom.\n   * Defaults to 200px\n   */\n  scrolledUpThreshold?: number;\n  /**\n   * The floating notification informing about unread messages will be shown when the\n   * UnreadMessagesSeparator is not visible. The default is false, that means the notification\n   * is shown only when viewing unread messages.\n   */\n  showUnreadNotificationAlways?: boolean;\n  /** If true, indicates the message list is a thread  */\n  threadList?: boolean; // todo: refactor needed - message list should have a state in which among others it would be optionally flagged as thread\n};\n\n/**\n * The MessageList component renders a list of Messages.\n * It is a consumer of the following contexts:\n * - [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/)\n * - [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/)\n * - [ComponentContext](https://getstream.io/chat/docs/sdk/react/contexts/component_context/)\n * - [TypingContext](https://getstream.io/chat/docs/sdk/react/contexts/typing_context/)\n */\nexport const MessageList = (props: MessageListProps) => {\n  const { jumpToLatestMessage, loadMore, loadMoreNewer } =\n    useChannelActionContext('MessageList');\n\n  const {\n    members: membersPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    mutes: mutesPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    watchers: watchersPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n    ...restChannelStateContext\n  } = useChannelStateContext('MessageList');\n\n  return (\n    <AriaLiveRegion>\n      <MessageListWithContext\n        jumpToLatestMessage={jumpToLatestMessage}\n        loadMore={loadMore}\n        loadMoreNewer={loadMoreNewer}\n        {...restChannelStateContext}\n        {...props}\n      />\n    </AriaLiveRegion>\n  );\n};\n","import clsx from 'clsx';\nimport throttle from 'lodash.throttle';\nimport React from 'react';\nimport type { ItemProps, ListItem } from 'react-virtuoso';\n\nimport { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../Loading';\nimport { Message } from '../Message';\n\nimport { useComponentContext } from '../../context';\nimport type { GroupStyle, RenderedMessage } from './utils';\nimport { getIsFirstUnreadMessage, isDateSeparatorMessage, isIntroMessage } from './utils';\nimport type { VirtuosoContext } from './VirtualizedMessageList';\nimport type { UnknownType } from '../../types/types';\n\nconst PREPEND_OFFSET = 10 ** 7;\n\nexport function calculateItemIndex(virtuosoIndex: number, numItemsPrepended: number) {\n  return virtuosoIndex + numItemsPrepended - PREPEND_OFFSET;\n}\n\nexport function calculateFirstItemIndex(numItemsPrepended: number) {\n  return PREPEND_OFFSET - numItemsPrepended;\n}\n\nexport const makeItemsRenderedHandler = (\n  renderedItemsActions: Array<(msg: RenderedMessage[]) => void>,\n  processedMessages: RenderedMessage[],\n) =>\n  throttle((items: ListItem<UnknownType>[]) => {\n    const renderedMessages = items\n      .map((item) => {\n        if (!item.originalIndex) return undefined;\n        return processedMessages[calculateItemIndex(item.originalIndex, PREPEND_OFFSET)];\n      })\n      .filter((msg) => !!msg);\n    renderedItemsActions.forEach((action) =>\n      action(renderedMessages as RenderedMessage[]),\n    );\n  }, 200);\n\ntype CommonVirtuosoComponentProps = {\n  context?: VirtuosoContext;\n};\n// using 'display: inline-block'\n// traps CSS margins of the item elements, preventing incorrect item measurements\nexport const Item = ({ context, ...props }: ItemProps & CommonVirtuosoComponentProps) => {\n  if (!context) return <></>;\n\n  const message =\n    context.processedMessages[\n      calculateItemIndex(props['data-item-index'], context.numItemsPrepended)\n    ];\n  const groupStyles: GroupStyle = context.messageGroupStyles[message.id];\n\n  return (\n    <div\n      {...props}\n      className={\n        context?.customClasses?.virtualMessage ||\n        clsx('str-chat__virtual-list-message-wrapper str-chat__li', {\n          [`str-chat__li--${groupStyles}`]: groupStyles,\n        })\n      }\n    />\n  );\n};\nexport const Header = ({ context }: CommonVirtuosoComponentProps) => {\n  const { LoadingIndicator = DefaultLoadingIndicator } = useComponentContext(\n    'VirtualizedMessageListHeader',\n  );\n\n  return (\n    <>\n      {context?.head}\n      {context?.loadingMore && LoadingIndicator && (\n        <div className='str-chat__virtual-list__loading'>\n          <LoadingIndicator />\n        </div>\n      )}\n    </>\n  );\n};\nexport const EmptyPlaceholder = ({ context }: CommonVirtuosoComponentProps) => {\n  const { EmptyStateIndicator = DefaultEmptyStateIndicator } = useComponentContext(\n    'VirtualizedMessageList',\n  );\n  // prevent showing that there are no messages if there actually are messages (for some reason virtuoso decides to render empty placeholder first, even though it has the totalCount prop > 0)\n  if (\n    typeof context?.processedMessages !== 'undefined' &&\n    context.processedMessages.length > 0\n  )\n    return null;\n\n  return (\n    <>\n      {EmptyStateIndicator && (\n        <EmptyStateIndicator listType={context?.threadList ? 'thread' : 'message'} />\n      )}\n    </>\n  );\n};\n\nexport const messageRenderer = (\n  virtuosoIndex: number,\n  _data: UnknownType,\n  virtuosoContext: VirtuosoContext,\n) => {\n  const {\n    additionalMessageComposerProps,\n    closeReactionSelectorOnClick,\n    customMessageRenderer,\n    DateSeparator,\n    firstUnreadMessageId,\n    formatDate,\n    lastOwnMessage,\n    lastReadDate,\n    lastReadMessageId,\n    lastReceivedMessageId,\n    Message: MessageUIComponent,\n    messageActions,\n    messageGroupStyles,\n    MessageSystem,\n    numItemsPrepended,\n    openThread,\n    ownMessagesDeliveredToOthers,\n    ownMessagesReadByOthers,\n    processedMessages: messageList,\n    reactionDetailsSort,\n    renderText,\n    returnAllReadData,\n    showAvatar,\n    sortReactions,\n    threadList,\n    unreadMessageCount = 0,\n    UnreadMessagesSeparator,\n    virtuosoRef,\n  } = virtuosoContext;\n\n  const streamMessageIndex = calculateItemIndex(virtuosoIndex, numItemsPrepended);\n\n  if (customMessageRenderer) {\n    return customMessageRenderer(messageList, streamMessageIndex);\n  }\n\n  const message = messageList[streamMessageIndex];\n\n  if (!message || isIntroMessage(message)) return <div style={{ height: '1px' }}></div>; // returning null or zero height breaks the virtuoso\n\n  if (isDateSeparatorMessage(message)) {\n    return DateSeparator ? (\n      <DateSeparator date={message.date} unread={message.unread} />\n    ) : null;\n  }\n\n  if (message.type === 'system') {\n    return MessageSystem ? <MessageSystem message={message} /> : null;\n  }\n\n  const isFirstUnreadMessage = getIsFirstUnreadMessage({\n    firstUnreadMessageId,\n    isFirstMessage: streamMessageIndex === 0,\n    lastReadDate,\n    lastReadMessageId,\n    message,\n    previousMessage: streamMessageIndex ? messageList[streamMessageIndex - 1] : undefined,\n    unreadMessageCount,\n  });\n\n  return (\n    <>\n      {isFirstUnreadMessage && (\n        <div className='str-chat__unread-messages-separator-wrapper'>\n          <UnreadMessagesSeparator unreadCount={unreadMessageCount} />\n        </div>\n      )}\n      <Message\n        additionalMessageComposerProps={additionalMessageComposerProps}\n        autoscrollToBottom={virtuosoRef.current?.autoscrollToBottom}\n        closeReactionSelectorOnClick={closeReactionSelectorOnClick}\n        deliveredTo={ownMessagesDeliveredToOthers[message.id] || []}\n        formatDate={formatDate}\n        groupStyles={[messageGroupStyles[message.id] ?? '']}\n        lastOwnMessage={lastOwnMessage}\n        lastReceivedId={lastReceivedMessageId}\n        message={message}\n        Message={MessageUIComponent}\n        messageActions={messageActions}\n        openThread={openThread}\n        reactionDetailsSort={reactionDetailsSort}\n        readBy={ownMessagesReadByOthers[message.id] || []}\n        renderText={renderText}\n        returnAllReadData={returnAllReadData}\n        showAvatar={showAvatar}\n        sortReactions={sortReactions}\n        threadList={threadList}\n      />\n    </>\n  );\n};\n","import React, { createContext, useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\n\nexport type VirtualizedMessageListContextValue = {\n  /** Function that scrolls the list to the bottom. */\n  scrollToBottom: () => void;\n};\n\nexport const VirtualizedMessageListContext = createContext<\n  VirtualizedMessageListContextValue | undefined\n>(undefined);\n\n/**\n * Context provider for components rendered within the `VirtualizedMessageList`\n */\nexport const VirtualizedMessageListContextProvider = ({\n  children,\n  value,\n}: PropsWithChildren<{\n  value: VirtualizedMessageListContextValue;\n}>) => (\n  <VirtualizedMessageListContext.Provider\n    value={value as VirtualizedMessageListContextValue}\n  >\n    {children}\n  </VirtualizedMessageListContext.Provider>\n);\n\nexport const useVirtualizedMessageListContext = () =>\n  useContext(VirtualizedMessageListContext) as VirtualizedMessageListContextValue;\n","import type { RefObject } from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { FloatingDateSeparator } from './FloatingDateSeparator';\nimport type {\n  ComputeItemKey,\n  ScrollSeekConfiguration,\n  ScrollSeekPlaceholderProps,\n  VirtuosoHandle,\n  VirtuosoProps,\n} from 'react-virtuoso';\nimport { Virtuoso } from 'react-virtuoso';\n\nimport { GiphyPreviewMessage as DefaultGiphyPreviewMessage } from './GiphyPreviewMessage';\nimport { useLastReadData } from './hooks';\nimport {\n  useGiphyPreview,\n  useMessageSetKey,\n  useNewMessageNotification,\n  usePrependedMessagesCount,\n  useScrollToBottomOnNewMessage,\n  useShouldForceScrollToBottom,\n  useUnreadMessagesNotificationVirtualized,\n} from './hooks/VirtualizedMessageList';\nimport { useMarkRead } from './hooks/useMarkRead';\nimport { NewMessageNotification as DefaultNewMessageNotification } from './NewMessageNotification';\nimport { MessageListMainPanel as DefaultMessageListMainPanel } from './MessageListMainPanel';\nimport type { GroupStyle, ProcessMessagesParams, RenderedMessage } from './utils';\nimport { getGroupStyles, getLastReceived, processMessages } from './utils';\nimport type { MessageProps, MessageUIComponentProps } from '../Message';\nimport { MessageUI } from '../Message';\nimport { UnreadMessagesNotification as DefaultUnreadMessagesNotification } from './UnreadMessagesNotification';\nimport {\n  calculateFirstItemIndex,\n  calculateItemIndex,\n  EmptyPlaceholder,\n  Header,\n  Item,\n  makeItemsRenderedHandler,\n  messageRenderer,\n} from './VirtualizedMessageListComponents';\n\nimport {\n  ScrollToLatestMessageButton as DefaultScrollToLatestMessageButton,\n  UnreadMessagesSeparator as DefaultUnreadMessagesSeparator,\n} from '../MessageList';\nimport { DateSeparator as DefaultDateSeparator } from '../DateSeparator';\nimport { EventComponent as DefaultMessageSystem } from '../EventComponent';\nimport {\n  NotificationList as DefaultNotificationList,\n  useNotificationTarget,\n} from '../Notifications';\n\nimport { DialogManagerProvider } from '../../context';\nimport type { ChannelActionContextValue } from '../../context/ChannelActionContext';\nimport { useChannelActionContext } from '../../context/ChannelActionContext';\nimport type {\n  ChannelNotifications,\n  ChannelStateContextValue,\n} from '../../context/ChannelStateContext';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport type { ChatContextValue } from '../../context/ChatContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport type { ComponentContextValue } from '../../context/ComponentContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { MessageTranslationViewProvider } from '../../context/MessageTranslationViewContext';\nimport { VirtualizedMessageListContextProvider } from '../../context/VirtualizedMessageListContext';\n\nimport type {\n  Channel,\n  LocalMessage,\n  ChannelState as StreamChannelState,\n  UserResponse,\n} from 'stream-chat';\nimport type { UnknownType } from '../../types/types';\nimport { DEFAULT_NEXT_CHANNEL_PAGE_SIZE } from '../../constants/limits';\nimport { useStableId } from '../UtilityComponents/useStableId';\nimport { useLastDeliveredData } from './hooks/useLastDeliveredData';\nimport { useLastOwnMessage } from './hooks/useLastOwnMessage';\nimport { useReducedMotionPreference } from './hooks/useReducedMotionPreference';\nimport { AriaLiveRegion, useIncomingMessageAnnouncements } from '../Accessibility';\n\ntype PropsDrilledToMessage =\n  | 'additionalMessageComposerProps'\n  | 'formatDate'\n  | 'messageActions'\n  | 'openThread'\n  | 'reactionDetailsSort'\n  | 'renderText'\n  | 'showAvatar'\n  | 'sortReactions';\n\ntype VirtualizedMessageListPropsForContext =\n  | PropsDrilledToMessage\n  | 'closeReactionSelectorOnClick'\n  | 'customMessageRenderer'\n  | 'head'\n  | 'loadingMore'\n  | 'Message'\n  | 'returnAllReadData'\n  | 'shouldGroupByUser'\n  | 'threadList';\n\n/**\n * Context object provided to some Virtuoso props that are functions (components rendered by Virtuoso and other functions)\n */\nexport type VirtuosoContext = Required<\n  Pick<\n    ComponentContextValue,\n    'DateSeparator' | 'MessageSystem' | 'UnreadMessagesSeparator'\n  >\n> &\n  Pick<VirtualizedMessageListProps, VirtualizedMessageListPropsForContext> &\n  Pick<ChatContextValue, 'customClasses'> & {\n    /** Latest received message id in the current channel */\n    lastReceivedMessageId: string | null | undefined;\n    /** Object mapping between the message ID and a string representing the position in the group of a sequence of messages posted by the same user. */\n    messageGroupStyles: Record<string, GroupStyle>;\n    /** Number of messages prepended before the first page of messages. This is needed to calculate the virtual position in the virtual list. */\n    numItemsPrepended: number;\n    /** Mapping of message ID of own messages to the array of users, who were delivered the given message */\n    ownMessagesDeliveredToOthers: Record<string, UserResponse[]>;\n    /** Mapping of message ID of own messages to the array of users, who read the given message */\n    ownMessagesReadByOthers: Record<string, UserResponse[]>;\n    /** The original message list enriched with date separators, omitted deleted messages or giphy previews. */\n    processedMessages: RenderedMessage[];\n    /** Instance of VirtuosoHandle object providing the API to navigate in the virtualized list by various scroll actions. */\n    virtuosoRef: RefObject<VirtuosoHandle | null>;\n    /** Latest own message in currently displayed message set. */\n    lastOwnMessage?: LocalMessage;\n    /** Message id which was marked as unread. ALl the messages following this message are considered unrea.  */\n    firstUnreadMessageId?: string;\n    lastReadDate?: Date;\n    /**\n     * The ID of the last message considered read by the current user in the current channel.\n     * All the messages following this message are considered unread.\n     */\n    lastReadMessageId?: string;\n    /** The number of unread messages in the current channel. */\n    unreadMessageCount?: number;\n  };\n\ntype VirtualizedMessageListWithContextProps = VirtualizedMessageListProps & {\n  channel: Channel;\n  hasMore: boolean;\n  hasMoreNewer: boolean;\n  jumpToLatestMessage: () => Promise<void>;\n  loadingMore: boolean;\n  loadingMoreNewer: boolean;\n  notifications: ChannelNotifications;\n  read?: StreamChannelState['read'];\n  thread?: ChannelStateContextValue['thread'];\n};\n\nfunction captureResizeObserverExceededError(e: ErrorEvent) {\n  if (\n    e.message === 'ResizeObserver loop completed with undelivered notifications.' ||\n    e.message === 'ResizeObserver loop limit exceeded'\n  ) {\n    e.stopImmediatePropagation();\n  }\n}\n\nfunction useCaptureResizeObserverExceededError() {\n  useEffect(() => {\n    window.addEventListener('error', captureResizeObserverExceededError);\n    return () => {\n      window.removeEventListener('error', captureResizeObserverExceededError);\n    };\n  }, []);\n}\n\nfunction fractionalItemSize(element: HTMLElement) {\n  return element.getBoundingClientRect().height;\n}\n\nfunction findMessageIndex(messages: RenderedMessage[], id: string) {\n  return messages.findIndex((message) => message.id === id);\n}\n\nfunction calculateInitialTopMostItemIndex(\n  messages: RenderedMessage[],\n  highlightedMessageId: string | undefined,\n) {\n  if (highlightedMessageId) {\n    const index = findMessageIndex(messages, highlightedMessageId);\n    if (index !== -1) {\n      return { align: 'center', index } as const;\n    }\n  }\n  return messages.length - 1;\n}\n\nconst VirtualizedMessageListWithContext = (\n  props: VirtualizedMessageListWithContextProps,\n) => {\n  const {\n    additionalMessageComposerProps,\n    additionalVirtuosoProps = {},\n    channel,\n    channelUnreadUiState,\n    closeReactionSelectorOnClick,\n    customMessageRenderer,\n    defaultItemHeight,\n    disableDateSeparator = true,\n    formatDate,\n    groupStyles,\n    hasMoreNewer,\n    head,\n    hideDeletedMessages = false,\n    hideNewMessageSeparator = false,\n    highlightedMessageId,\n    jumpToLatestMessage,\n    loadingMore,\n    loadMore,\n    loadMoreNewer,\n    maxTimeBetweenGroupedMessages,\n    Message: MessageUIComponentFromProps,\n    messageActions,\n    messageLimit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE,\n    messages,\n    openThread,\n    // TODO: refactor to scrollSeekPlaceHolderConfiguration and components.ScrollSeekPlaceholder, like the Virtuoso Component\n    overscan = 0,\n    reactionDetailsSort,\n    renderText,\n    returnAllReadData = false,\n    reviewProcessedMessage,\n    scrollSeekPlaceHolder,\n    scrollToLatestMessageOnFocus = false,\n    separateGiphyPreview = false,\n    shouldGroupByUser = false,\n    showAvatar,\n    showUnreadNotificationAlways,\n    sortReactions,\n    stickToBottomScrollBehavior = 'smooth',\n    suppressAutoscroll,\n    thread,\n    threadList,\n  } = props;\n\n  const { components: virtuosoComponentsFromProps, ...overridingVirtuosoProps } =\n    additionalVirtuosoProps;\n\n  // Stops errors generated from react-virtuoso to bubble up\n  // to Sentry or other tracking tools.\n  useCaptureResizeObserverExceededError();\n\n  const {\n    DateSeparator = DefaultDateSeparator,\n    GiphyPreviewMessage = DefaultGiphyPreviewMessage,\n    MessageListMainPanel = DefaultMessageListMainPanel,\n    MessageSystem = DefaultMessageSystem,\n    NewMessageNotification = DefaultNewMessageNotification,\n    NotificationList = DefaultNotificationList,\n    ScrollToLatestMessageButton = DefaultScrollToLatestMessageButton,\n    TypingIndicator,\n    UnreadMessagesNotification = DefaultUnreadMessagesNotification,\n    UnreadMessagesSeparator = DefaultUnreadMessagesSeparator,\n    VirtualMessage: MessageUIComponentFromContext = MessageUI,\n  } = useComponentContext('VirtualizedMessageList');\n  const MessageUIComponent = MessageUIComponentFromProps || MessageUIComponentFromContext;\n\n  const { client, customClasses } = useChatContext('VirtualizedMessageList');\n  const prefersReducedMotion = useReducedMotionPreference();\n  const effectiveStickToBottomScrollBehavior = prefersReducedMotion\n    ? 'auto'\n    : stickToBottomScrollBehavior;\n  const notificationTarget = useNotificationTarget();\n\n  const virtuoso = useRef<VirtuosoHandle>(null);\n\n  const lastRead = useMemo(() => channel.lastRead?.(), [channel]);\n\n  const { show: showUnreadMessagesNotification, toggleShowUnreadMessagesNotification } =\n    useUnreadMessagesNotificationVirtualized({\n      lastRead: channelUnreadUiState?.last_read,\n      showAlways: !!showUnreadNotificationAlways,\n      unreadCount: channelUnreadUiState?.unread_messages ?? 0,\n    });\n\n  const { giphyPreviewMessage, setGiphyPreviewMessage } =\n    useGiphyPreview(separateGiphyPreview);\n\n  const processedMessages = useMemo(() => {\n    if (typeof messages === 'undefined') {\n      return [];\n    }\n\n    if (\n      disableDateSeparator &&\n      !hideDeletedMessages &&\n      hideNewMessageSeparator &&\n      !separateGiphyPreview\n    ) {\n      return messages;\n    }\n\n    return processMessages({\n      enableDateSeparator: !disableDateSeparator,\n      hideDeletedMessages,\n      hideNewMessageSeparator,\n      lastRead,\n      messages,\n      reviewProcessedMessage,\n      setGiphyPreviewMessage,\n      userId: client.userID || '',\n    });\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [\n    disableDateSeparator,\n    hideDeletedMessages,\n    hideNewMessageSeparator,\n    lastRead,\n    messages,\n    messages?.length,\n    client.userID,\n  ]);\n\n  /**\n   * This indirection via a ref is needed because Virtuoso’s itemsRendered is set at render time,\n   * while FloatingDateSeparator lives in a child component that may run its hooks in a different order.\n   * Using a ref lets the parent provide the callback to Virtuoso while the child keeps ownership\n   * of the actual handler implementation.\n   */\n  const floatingDateItemsRenderedRef = useRef<\n    ((rendered: RenderedMessage[]) => void) | null\n  >(null);\n\n  const lastOwnMessage = useLastOwnMessage({ messages, ownUserId: client.user?.id });\n\n  // get the mapping of own messages to array of users who read them\n  const ownMessagesReadByOthers = useLastReadData({\n    channel,\n    lastOwnMessage,\n    messages: messages || [],\n    returnAllReadData,\n  });\n\n  const ownMessagesDeliveredToOthers = useLastDeliveredData({\n    channel,\n    lastOwnMessage,\n    messages: messages || [],\n    returnAllReadData,\n  });\n\n  const lastReceivedMessageId = useMemo(\n    () => getLastReceived(processedMessages),\n    [processedMessages],\n  );\n\n  const groupStylesFn = groupStyles || getGroupStyles;\n  const messageGroupStyles = useMemo(\n    () =>\n      processedMessages.reduce<Record<string, GroupStyle>>((acc, message, i) => {\n        const style = groupStylesFn(\n          message,\n          processedMessages[i - 1],\n          processedMessages[i + 1],\n          !shouldGroupByUser,\n          maxTimeBetweenGroupedMessages,\n        );\n        if (style && message.id) acc[message.id] = style;\n        return acc;\n      }, {}),\n    // processedMessages were incorrectly rebuilt with a new object identity at some point, hence the .length usage\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [\n      maxTimeBetweenGroupedMessages,\n      processedMessages.length,\n      shouldGroupByUser,\n      groupStylesFn,\n    ],\n  );\n\n  const {\n    atBottom,\n    isMessageListScrolledToBottom,\n    newMessagesNotification,\n    setIsMessageListScrolledToBottom,\n    setNewMessagesNotification,\n  } = useNewMessageNotification(processedMessages, client.userID, hasMoreNewer);\n\n  useMarkRead({\n    isMessageListScrolledToBottom,\n    messageListIsThread: !!threadList,\n    wasMarkedUnread: !!channelUnreadUiState?.first_unread_message_id,\n  });\n\n  const scrollToBottom = useCallback(async () => {\n    if (hasMoreNewer) {\n      await jumpToLatestMessage();\n      return;\n    }\n\n    if (virtuoso.current) {\n      virtuoso.current.scrollToIndex(processedMessages.length - 1);\n    }\n\n    setNewMessagesNotification(false);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [\n    virtuoso,\n    processedMessages,\n    setNewMessagesNotification,\n    // processedMessages were incorrectly rebuilt with a new object identity at some point, hence the .length usage\n    processedMessages.length,\n    hasMoreNewer,\n    jumpToLatestMessage,\n  ]);\n\n  useScrollToBottomOnNewMessage({\n    messages,\n    scrollToBottom,\n    scrollToLatestMessageOnFocus,\n  });\n\n  const numItemsPrepended = usePrependedMessagesCount(\n    processedMessages,\n    !disableDateSeparator,\n  );\n\n  const { messageSetKey } = useMessageSetKey({ messages });\n\n  const shouldForceScrollToBottom = useShouldForceScrollToBottom(\n    processedMessages,\n    client.userID,\n  );\n\n  useIncomingMessageAnnouncements({\n    activeThreadId: thread?.id,\n    channel,\n    ownUserId: client.userID,\n    threadList,\n  });\n\n  const handleItemsRendered = useMemo(\n    () =>\n      makeItemsRenderedHandler(\n        [\n          toggleShowUnreadMessagesNotification,\n          (rendered) => floatingDateItemsRenderedRef.current?.(rendered),\n        ],\n        processedMessages,\n      ),\n    [processedMessages, toggleShowUnreadMessagesNotification],\n  );\n  const followOutput = (isAtBottom: boolean) => {\n    if (hasMoreNewer || suppressAutoscroll) {\n      return false;\n    }\n\n    if (shouldForceScrollToBottom()) {\n      return isAtBottom ? effectiveStickToBottomScrollBehavior : 'auto';\n    }\n    // a message from another user has been received - don't scroll to bottom unless already there\n    return isAtBottom ? effectiveStickToBottomScrollBehavior : false;\n  };\n\n  const computeItemKey = useCallback<ComputeItemKey<UnknownType, VirtuosoContext>>(\n    (index, _, { numItemsPrepended, processedMessages }) =>\n      processedMessages[calculateItemIndex(index, numItemsPrepended)].id,\n    [],\n  );\n\n  const atBottomStateChange = (isAtBottom: boolean) => {\n    atBottom.current = isAtBottom;\n    setIsMessageListScrolledToBottom(isAtBottom);\n\n    if (isAtBottom) {\n      loadMoreNewer?.(messageLimit);\n      setNewMessagesNotification?.(false);\n    }\n  };\n  const atTopStateChange = (isAtTop: boolean) => {\n    if (isAtTop) {\n      loadMore?.(messageLimit);\n    }\n  };\n\n  useEffect(() => {\n    let scrollTimeout: ReturnType<typeof setTimeout>;\n    if (highlightedMessageId) {\n      const index = findMessageIndex(processedMessages, highlightedMessageId);\n      if (index !== -1) {\n        scrollTimeout = setTimeout(() => {\n          virtuoso.current?.scrollToIndex({ align: 'center', index });\n        }, 0);\n      }\n    }\n    return () => {\n      clearTimeout(scrollTimeout);\n    };\n  }, [highlightedMessageId, processedMessages]);\n\n  const id = useStableId();\n\n  if (!processedMessages) return null;\n\n  const dialogManagerId = threadList\n    ? `virtualized-message-list-dialog-manager-thread-${id}`\n    : `virtualized-message-list-dialog-manager-${id}`;\n\n  return (\n    <VirtualizedMessageListContextProvider value={{ scrollToBottom }}>\n      <MessageTranslationViewProvider>\n        <MessageListMainPanel>\n          <DialogManagerProvider id={dialogManagerId}>\n            {!threadList && showUnreadMessagesNotification && (\n              <UnreadMessagesNotification\n                unreadCount={channelUnreadUiState?.unread_messages}\n              />\n            )}\n            <div\n              className={\n                customClasses?.virtualizedMessageList || 'str-chat__virtual-list'\n              }\n            >\n              <FloatingDateSeparator\n                disableDateSeparator={disableDateSeparator}\n                itemsRenderedRef={floatingDateItemsRenderedRef}\n                processedMessages={processedMessages}\n              />\n              <Virtuoso<UnknownType, VirtuosoContext>\n                atBottomStateChange={atBottomStateChange}\n                atBottomThreshold={100}\n                atTopStateChange={atTopStateChange}\n                atTopThreshold={100}\n                className='str-chat__message-list-scroll'\n                components={{\n                  EmptyPlaceholder,\n                  Header,\n                  Item,\n                  ...(TypingIndicator && {\n                    Footer: () =>\n                      isMessageListScrolledToBottom ? (\n                        <TypingIndicator\n                          isMessageListScrolledToBottom={isMessageListScrolledToBottom}\n                          scrollToBottom={scrollToBottom}\n                          threadList={threadList}\n                        />\n                      ) : null,\n                  }),\n                  ...virtuosoComponentsFromProps,\n                }}\n                computeItemKey={computeItemKey}\n                context={{\n                  additionalMessageComposerProps,\n                  closeReactionSelectorOnClick,\n                  customClasses,\n                  customMessageRenderer,\n                  DateSeparator,\n                  firstUnreadMessageId: channelUnreadUiState?.first_unread_message_id,\n                  formatDate,\n                  head,\n                  lastOwnMessage,\n                  lastReadDate: channelUnreadUiState?.last_read,\n                  lastReadMessageId: channelUnreadUiState?.last_read_message_id,\n                  lastReceivedMessageId,\n                  loadingMore,\n                  Message: MessageUIComponent,\n                  messageActions,\n                  messageGroupStyles,\n                  MessageSystem,\n                  numItemsPrepended,\n                  openThread,\n                  ownMessagesDeliveredToOthers,\n                  ownMessagesReadByOthers,\n                  processedMessages,\n                  reactionDetailsSort,\n                  renderText,\n                  returnAllReadData,\n                  shouldGroupByUser,\n                  showAvatar,\n                  sortReactions,\n                  threadList,\n                  unreadMessageCount: channelUnreadUiState?.unread_messages,\n                  UnreadMessagesSeparator,\n                  virtuosoRef: virtuoso,\n                }}\n                firstItemIndex={calculateFirstItemIndex(numItemsPrepended)}\n                followOutput={followOutput}\n                increaseViewportBy={{ bottom: 200, top: 0 }}\n                initialTopMostItemIndex={calculateInitialTopMostItemIndex(\n                  processedMessages,\n                  highlightedMessageId,\n                )}\n                itemContent={messageRenderer}\n                itemSize={fractionalItemSize}\n                itemsRendered={handleItemsRendered}\n                key={messageSetKey}\n                overscan={overscan}\n                ref={virtuoso}\n                style={{ overflowX: 'hidden' }}\n                totalCount={processedMessages.length}\n                {...overridingVirtuosoProps}\n                {...(scrollSeekPlaceHolder ? { scrollSeek: scrollSeekPlaceHolder } : {})}\n                {...(defaultItemHeight ? { defaultItemHeight } : {})}\n              />\n              <NewMessageNotification\n                newMessageCount={channelUnreadUiState?.unread_messages}\n                showNotification={newMessagesNotification || hasMoreNewer}\n              />\n              <ScrollToLatestMessageButton\n                isMessageListScrolledToBottom={isMessageListScrolledToBottom}\n                isNotAtLatestMessageSet={hasMoreNewer}\n                onClick={scrollToBottom}\n                threadList={threadList}\n              />\n            </div>\n          </DialogManagerProvider>\n          <NotificationList panel={notificationTarget} />\n        </MessageListMainPanel>\n        {giphyPreviewMessage && <GiphyPreviewMessage message={giphyPreviewMessage} />}\n      </MessageTranslationViewProvider>\n    </VirtualizedMessageListContextProvider>\n  );\n};\n\nexport type VirtualizedMessageListProps = Partial<\n  Pick<MessageProps, PropsDrilledToMessage>\n> & {\n  /** Additional props to be passed the underlying [`react-virtuoso` virtualized list dependency](https://virtuoso.dev/virtuoso-api-reference/) */\n  additionalVirtuosoProps?: VirtuosoProps<UnknownType, VirtuosoContext>;\n  channelUnreadUiState?: ChannelStateContextValue['channelUnreadUiState'];\n  /** If true, picking a reaction from the `ReactionSelector` component will close the selector */\n  closeReactionSelectorOnClick?: boolean;\n  /** Custom render function, if passed, certain UI props are ignored */\n  customMessageRenderer?: (\n    messageList: RenderedMessage[],\n    index: number,\n  ) => React.ReactElement;\n  /** @deprecated Use additionalVirtuosoProps.defaultItemHeight instead. Will be removed with next major release - `v11.0.0`.\n   * If set, the default item height is used for the calculation of the total list height. Use if you expect messages with a lot of height variance\n   * */\n  defaultItemHeight?: number;\n  /** Disables the injection of date separator components in MessageList, defaults to `true` */\n  disableDateSeparator?: boolean;\n  /** Callback function to set group styles for each message */\n  groupStyles?: (\n    message: RenderedMessage,\n    previousMessage: RenderedMessage,\n    nextMessage: RenderedMessage,\n    noGroupByUser: boolean,\n    maxTimeBetweenGroupedMessages?: number,\n  ) => GroupStyle;\n  /** Whether or not the list has more items to load */\n  hasMore?: boolean;\n  /** Whether or not the list has newer items to load */\n  hasMoreNewer?: boolean;\n  /**\n   * @deprecated Use additionalVirtuosoProps.components.Header to override default component rendered above the list ove messages.\n   * Element to be rendered at the top of the thread message list. By default, these are the Message and ThreadStart components\n   */\n  head?: React.ReactElement;\n  /** Hides the `MessageDeleted` components from the list, defaults to `false` */\n  hideDeletedMessages?: boolean;\n  /** Hides the `DateSeparator` component when new messages are received in a channel that's watched but not active, defaults to false */\n  hideNewMessageSeparator?: boolean;\n  /** The id of the message to highlight and center */\n  highlightedMessageId?: string;\n  /** Whether or not the list is currently loading more items */\n  loadingMore?: boolean;\n  /** Whether or not the list is currently loading newer items */\n  loadingMoreNewer?: boolean;\n  /** Function called when more messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n  loadMore?: ChannelActionContextValue['loadMore'] | (() => Promise<void>);\n  /** Function called when new messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n  loadMoreNewer?: ChannelActionContextValue['loadMore'] | (() => Promise<void>);\n  /** Maximum time in milliseconds that should occur between messages to still consider them grouped together */\n  maxTimeBetweenGroupedMessages?: number;\n  /** Custom UI component to display a message, defaults to and accepts same props as [MessageUI](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/MessageUI.tsx) */\n  Message?: React.ComponentType<MessageUIComponentProps>;\n  /** The limit to use when paginating messages */\n  messageLimit?: number;\n  /** Optional prop to override the messages available from [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/) */\n  messages?: LocalMessage[];\n  /**\n   * @deprecated Use additionalVirtuosoProps.overscan instead. Will be removed with next major release - `v11.0.0`.\n   * The amount of extra content the list should render in addition to what's necessary to fill in the viewport\n   */\n  overscan?: number;\n  /** Keep track of read receipts for each message sent by the user. When disabled, only the last own message delivery / read status is rendered. */\n  returnAllReadData?: boolean;\n  /**\n   * Allows to review changes introduced to messages array on per message basis (e.g. date separator injected before a message).\n   * The array returned from the function is appended to the array of messages that are later rendered into React elements in the `VirtualizedMessageList`.\n   */\n  reviewProcessedMessage?: ProcessMessagesParams['reviewProcessedMessage'];\n  /**\n   * @deprecated Pass additionalVirtuosoProps.scrollSeekConfiguration and specify the placeholder in additionalVirtuosoProps.components.ScrollSeekPlaceholder instead.  Will be removed with next major release - `v11.0.0`.\n   * Performance improvement by showing placeholders if user scrolls fast through list.\n   * it can be used like this:\n   * ```\n   *  {\n   *    enter: (velocity) => Math.abs(velocity) > 120,\n   *    exit: (velocity) => Math.abs(velocity) < 40,\n   *    change: () => null,\n   *    placeholder: ({index, height})=> <div style={{height: height + \"px\"}}>{index}</div>,\n   *  }\n   *  ```\n   */\n  scrollSeekPlaceHolder?: ScrollSeekConfiguration & {\n    placeholder: React.ComponentType<ScrollSeekPlaceholderProps>;\n  };\n  /** When `true`, the list will scroll to the latest message when the window regains focus */\n  scrollToLatestMessageOnFocus?: boolean;\n  /** If true, the Giphy preview will render as a separate component above the `MessageComposer`, rather than inline with the other messages in the list */\n  separateGiphyPreview?: boolean;\n  /** If true, group messages belonging to the same user, otherwise show each message individually */\n  shouldGroupByUser?: boolean;\n  /**\n   * The floating notification informing about unread messages will be shown when the\n   * UnreadMessagesSeparator is not visible. The default is false, that means the notification\n   * is shown only when viewing unread messages.\n   */\n  showUnreadNotificationAlways?: boolean;\n  /** The scrollTo behavior when new messages appear. Use `\"smooth\"` for regular chat channels, and `\"auto\"` (which results in instant scroll to bottom) if you expect high throughput. Reduced-motion users are always treated as `\"auto\"`. */\n  stickToBottomScrollBehavior?: 'smooth' | 'auto';\n  /** stops the list from autoscrolling when new messages are loaded */\n  suppressAutoscroll?: boolean;\n  /** If true, indicates the message list is a thread  */\n  threadList?: boolean;\n};\n\n/**\n * The VirtualizedMessageList component renders a list of messages in a virtualized list.\n * It is a consumer of the React contexts set in [Channel](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Channel/Channel.tsx).\n */\nexport function VirtualizedMessageList(props: VirtualizedMessageListProps) {\n  const { jumpToLatestMessage, loadMore, loadMoreNewer } = useChannelActionContext(\n    'VirtualizedMessageList',\n  );\n  const {\n    channel,\n    channelUnreadUiState,\n    hasMore,\n    hasMoreNewer,\n    highlightedMessageId,\n    loadingMore,\n    loadingMoreNewer,\n    messages: contextMessages,\n    notifications,\n    read,\n    suppressAutoscroll,\n    thread,\n  } = useChannelStateContext('VirtualizedMessageList');\n\n  const messages = props.messages || contextMessages;\n\n  return (\n    <AriaLiveRegion>\n      <VirtualizedMessageListWithContext\n        channel={channel}\n        channelUnreadUiState={props.channelUnreadUiState ?? channelUnreadUiState}\n        hasMore={!!hasMore}\n        hasMoreNewer={!!hasMoreNewer}\n        highlightedMessageId={highlightedMessageId}\n        jumpToLatestMessage={jumpToLatestMessage}\n        loadingMore={!!loadingMore}\n        loadingMoreNewer={!!loadingMoreNewer}\n        loadMore={loadMore}\n        loadMoreNewer={loadMoreNewer}\n        messages={messages}\n        notifications={notifications}\n        read={read}\n        suppressAutoscroll={suppressAutoscroll}\n        thread={thread}\n        {...props}\n      />\n    </AriaLiveRegion>\n  );\n}\n","// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt#getting_whole_characters\nexport const getWholeChar = (str: string, i: number) => {\n  const code = str.charCodeAt(i);\n\n  if (Number.isNaN(code)) return '';\n\n  if (code < 0xd800 || code > 0xdfff) return str.charAt(i);\n\n  if (0xd800 <= code && code <= 0xdbff) {\n    if (str.length <= i + 1) {\n      throw 'High surrogate without following low surrogate';\n    }\n\n    const next = str.charCodeAt(i + 1);\n\n    if (0xdc00 > next || next > 0xdfff) {\n      throw 'High surrogate without following low surrogate';\n    }\n\n    return str.charAt(i) + str.charAt(i + 1);\n  }\n\n  if (i === 0) {\n    throw 'Low surrogate without preceding high surrogate';\n  }\n\n  const prev = str.charCodeAt(i - 1);\n\n  if (0xd800 > prev || prev > 0xdbff) {\n    throw 'Low surrogate without preceding high surrogate';\n  }\n\n  return '';\n};\n","import { useEffect, useState } from 'react';\nimport type { SearchController, SearchControllerState, SearchSource } from 'stream-chat';\n\nimport { useStateStore } from '../../../store';\n\nconst searchControllerStateSelector = (value: SearchControllerState) => ({\n  sources: value.sources,\n});\n\nexport type UseSearchQueriesInProgressParams = {\n  searchController: SearchController;\n};\n\nexport const useSearchQueriesInProgress = (searchController: SearchController) => {\n  const [queriesInProgress, setQueriesInProgress] = useState<string[]>([]);\n  const { sources } = useStateStore(\n    searchController.state,\n    searchControllerStateSelector,\n  );\n\n  useEffect(() => {\n    const subscriptions = sources.map((source: SearchSource) =>\n      source.state.subscribeWithSelector(\n        (value) => ({ isLoading: value.isLoading }),\n        ({ isLoading }) => {\n          setQueriesInProgress((prev) => {\n            if (isLoading) return prev.concat(source.type);\n            return prev.filter((type) => type !== source.type);\n          });\n        },\n      ),\n    );\n\n    return () => {\n      subscriptions.forEach((unsubscribe) => unsubscribe());\n    };\n  }, [sources]);\n  return queriesInProgress;\n};\n","import { useEffect } from 'react';\n\nimport { useChatContext } from '../../../context/ChatContext';\n\nexport const useConnectionRecoveredListener = (forceUpdate?: () => void) => {\n  const { client } = useChatContext('useConnectionRecoveredListener');\n\n  useEffect(() => {\n    const handleEvent = () => {\n      if (forceUpdate) {\n        forceUpdate();\n      }\n    };\n\n    client.on('connection.recovered', handleEvent);\n\n    return () => {\n      client.off('connection.recovered', handleEvent);\n    };\n  }, [client, forceUpdate]);\n};\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport uniqBy from 'lodash.uniqby';\n\nimport type {\n  APIErrorResponse,\n  Channel,\n  ChannelFilters,\n  ChannelOptions,\n  ChannelSort,\n  ErrorFromResponse,\n  ParsedPredefinedFilterResponse,\n  StreamChat,\n} from 'stream-chat';\n\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\nimport { useNotificationApi } from '../../Notifications';\n\nimport type { ChannelsQueryState } from '../../Chat/hooks/useChannelsQueryState';\n\nconst RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS = 5000;\nconst MIN_RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS = 2000;\n\ntype AllowedQueryType = Extract<\n  ChannelsQueryState['queryInProgress'],\n  'reload' | 'load-more'\n>;\n\nexport type CustomQueryChannelParams = {\n  currentChannels: Array<Channel>;\n  queryType: AllowedQueryType;\n  setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>;\n  setHasNextPage: React.Dispatch<React.SetStateAction<boolean>>;\n};\n\nexport type CustomQueryChannelsFn = (params: CustomQueryChannelParams) => Promise<void>;\n\n/**\n * Filters and sort effectively used by the channel list. When `options.predefined_filter`\n * is set, these reflect the backend-resolved values from `predefined_filter` response\n * metadata; otherwise they fall back to the caller-supplied `filters`/`sort`.\n */\nexport type EffectiveQueryParams = {\n  filters: ChannelFilters;\n  sort: ChannelSort;\n};\n\n/**\n * The `predefined_filter` response carries sort as\n * `[{ field, direction }]`. `ChannelSort` expects `[{ field: direction }]`.\n */\nconst mapPredefinedFilterSortToChannelSort = (\n  sort: NonNullable<ParsedPredefinedFilterResponse['sort']>,\n): ChannelSort =>\n  sort.map(({ direction = 1, field }) => ({\n    [field]: direction,\n  })) as ChannelSort;\n\nexport const usePaginatedChannels = (\n  client: StreamChat,\n  filters: ChannelFilters,\n  sort: ChannelSort,\n  options: ChannelOptions,\n  activeChannelHandler: (\n    channels: Array<Channel>,\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    effectiveQueryParams: EffectiveQueryParams,\n  ) => void,\n  recoveryThrottleIntervalMs: number = RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS,\n  customQueryChannels?: CustomQueryChannelsFn,\n) => {\n  const { addNotification } = useNotificationApi();\n  const {\n    channelsQueryState: { error, setError, setQueryInProgress },\n  } = useChatContext('usePaginatedChannels');\n  const { t } = useTranslationContext();\n  const [channels, setChannels] = useState<Array<Channel>>([]);\n  const [hasNextPage, setHasNextPage] = useState(true);\n  // Backend-resolved filter/sort from `predefined_filter` response metadata.\n  // Used to override the caller `filters`/`sort` for local WS-driven list\n  // mutation decisions (archiving, pinning) when a predefined filter is in\n  // use. Stays `undefined` for non-predefined queries.\n  const [responseFilters, setResponseFilters] = useState<ChannelFilters | undefined>(\n    undefined,\n  );\n  const [responseSort, setResponseSort] = useState<ChannelSort | undefined>(undefined);\n  const lastRecoveryTimestamp = useRef<number | undefined>(undefined);\n\n  const recoveryThrottleInterval =\n    recoveryThrottleIntervalMs < MIN_RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS\n      ? MIN_RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS\n      : (recoveryThrottleIntervalMs ?? RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS);\n  // memoize props\n  const filterString = useMemo(() => JSON.stringify(filters), [filters]);\n  const sortString = useMemo(() => JSON.stringify(sort), [sort]);\n\n  // eslint-disable-next-line react-hooks/exhaustive-deps\n  const queryChannels = async (queryType = 'load-more') => {\n    setError(null);\n    const offset = queryType === 'reload' ? 0 : channels.length;\n    const isFirstPage = offset === 0;\n\n    if (queryType === 'reload') {\n      setChannels([]);\n    }\n    setQueryInProgress(queryType as AllowedQueryType);\n\n    try {\n      if (customQueryChannels) {\n        await customQueryChannels({\n          currentChannels: channels,\n          queryType: queryType as AllowedQueryType,\n          setChannels,\n          setHasNextPage,\n        });\n        // `customQueryChannels` bypasses the SDK response so any previously\n        // resolved predefined-filter metadata is no longer trustworthy.\n        setResponseFilters(undefined);\n        setResponseSort(undefined);\n      } else {\n        const newOptions = {\n          offset,\n          ...options,\n        };\n\n        const channelQueryResponse = await client.queryChannels(\n          filters,\n          sort || {},\n          newOptions,\n          { withResponse: true },\n        );\n\n        const newChannels =\n          queryType === 'reload'\n            ? channelQueryResponse.channels\n            : uniqBy([...channels, ...channelQueryResponse.channels], 'cid');\n\n        setChannels(newChannels);\n        setHasNextPage(channelQueryResponse.channels.length >= (newOptions.limit ?? 1));\n\n        // Pull backend-resolved filter/sort from `predefined_filter` metadata so\n        // WS-driven list mutations use the effective semantics. Always reset\n        // first; non-predefined queries do not return this metadata and keeping\n        // stale values would silently change list behavior.\n        const predefinedFilter = channelQueryResponse.predefined_filter;\n        const nextResponseFilters = predefinedFilter\n          ? (predefinedFilter.filter as ChannelFilters)\n          : undefined;\n        const nextResponseSort = predefinedFilter?.sort\n          ? mapPredefinedFilterSortToChannelSort(predefinedFilter.sort)\n          : undefined;\n\n        setResponseFilters(nextResponseFilters);\n        setResponseSort(nextResponseSort);\n\n        // Set active channel only on load of first page\n        if (!offset && activeChannelHandler) {\n          activeChannelHandler(newChannels, setChannels, {\n            filters: nextResponseFilters ?? filters,\n            sort: nextResponseSort ?? sort,\n          });\n        }\n      }\n    } catch (error) {\n      console.warn(error);\n      addNotification({\n        emitter: 'ChannelList',\n        error: error instanceof Error ? error : undefined,\n        message: isFirstPage\n          ? t('Failed to load channels')\n          : t('Failed to load more channels'),\n        severity: 'error',\n        targetPanels: ['channel-list'],\n        type: isFirstPage\n          ? 'api:channel-list:load:failed'\n          : 'api:channel-list:load-more:failed',\n      });\n\n      if (isFirstPage) {\n        setError(error as ErrorFromResponse<APIErrorResponse>);\n      }\n    }\n\n    setQueryInProgress(null);\n  };\n\n  const throttleRecover = useCallback(() => {\n    const now = Date.now();\n    const isFirstRecovery = !lastRecoveryTimestamp.current;\n    const timeElapsedSinceLastRecoveryMs = lastRecoveryTimestamp.current\n      ? now - lastRecoveryTimestamp.current\n      : 0;\n\n    if (\n      !isFirstRecovery &&\n      timeElapsedSinceLastRecoveryMs < recoveryThrottleInterval &&\n      !error\n    ) {\n      return;\n    }\n\n    lastRecoveryTimestamp.current = now;\n    queryChannels('reload');\n  }, [error, queryChannels, recoveryThrottleInterval]);\n\n  const loadNextPage = () => queryChannels();\n\n  useEffect(() => {\n    if (client.recoverStateOnReconnect) return;\n    const { unsubscribe } = client.on('connection.recovered', throttleRecover);\n\n    return () => {\n      unsubscribe();\n    };\n  }, [client, throttleRecover]);\n\n  useEffect(() => {\n    queryChannels('reload');\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [filterString, sortString]);\n\n  // Effective filters/sort: response-derived values take precedence over\n  // caller-supplied props when a predefined filter is in use. Falls back to\n  // the caller props for non-predefined queries and during the initial load\n  // before the first response.\n  const effectiveFilters = responseFilters ?? filters;\n  const effectiveSort = responseSort ?? sort;\n\n  return {\n    channels,\n    effectiveFilters,\n    effectiveSort,\n    hasNextPage,\n    loadNextPage,\n    setChannels,\n  };\n};\n","import type { Channel, ChannelSort, ChannelSortBase } from 'stream-chat';\n\nimport type { ChannelListProps } from './ChannelList';\n\n/**\n * Expects channel array sorted by `{ pinned_at: -1 }`.\n *\n * TODO: add support for the `{ pinned_at: 1 }`\n */\nexport function findLastPinnedChannelIndex({ channels }: { channels: Channel[] }) {\n  let lastPinnedChannelIndex: number | null = null;\n\n  for (const channel of channels) {\n    if (!isChannelPinned(channel)) break;\n\n    if (typeof lastPinnedChannelIndex === 'number') {\n      lastPinnedChannelIndex++;\n    } else {\n      lastPinnedChannelIndex = 0;\n    }\n  }\n\n  return lastPinnedChannelIndex;\n}\n\ntype MoveChannelUpwardsParams = {\n  channels: Array<Channel>;\n  channelToMove: Channel;\n  sort: ChannelSort;\n  /**\n   * If the index of the channel within `channels` list which is being moved upwards\n   * (`channelToMove`) is known, you can supply it to skip extra calculation.\n   */\n  channelToMoveIndexWithinChannels?: number;\n};\n\nexport const moveChannelUpwards = ({\n  channels,\n  channelToMove,\n  channelToMoveIndexWithinChannels,\n  sort,\n}: MoveChannelUpwardsParams) => {\n  // get index of channel to move up\n  const targetChannelIndex =\n    channelToMoveIndexWithinChannels ??\n    channels.findIndex((channel) => channel.cid === channelToMove.cid);\n\n  const targetChannelExistsWithinList = targetChannelIndex >= 0;\n  const targetChannelAlreadyAtTheTop = targetChannelIndex === 0;\n\n  // pinned channels should not move within the list based on recent activity, channels which\n  // receive messages and are not pinned should move upwards but only under the last pinned channel\n  // in the list\n  const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n  const isTargetChannelPinned = isChannelPinned(channelToMove);\n\n  if (targetChannelAlreadyAtTheTop || (considerPinnedChannels && isTargetChannelPinned)) {\n    return channels;\n  }\n\n  const newChannels = [...channels];\n\n  // target channel index is known, remove it from the list\n  if (targetChannelExistsWithinList) {\n    newChannels.splice(targetChannelIndex, 1);\n  }\n\n  // as position of pinned channels has to stay unchanged, we need to\n  // find last pinned channel in the list to move the target channel after\n  let lastPinnedChannelIndex: number | null = null;\n  if (considerPinnedChannels) {\n    lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });\n  }\n\n  // re-insert it at the new place (to specific index if pinned channels are considered)\n  newChannels.splice(\n    typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0,\n    0,\n    channelToMove,\n  );\n\n  return newChannels;\n};\n\n/**\n * Returns `true` only if object with `pinned_at` property is first within the `sort` array\n * or if `pinned_at` key of the `sort` object gets picked first when using `for...in` looping mechanism\n * and value of the `pinned_at` is either `1` or `-1`.\n */\nexport const shouldConsiderPinnedChannels = (sort: ChannelListProps['sort']) => {\n  const value = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' });\n\n  if (typeof value !== 'number') return false;\n\n  return Math.abs(value) === 1;\n};\n\nexport const extractSortValue = ({\n  atIndex,\n  sort,\n  targetKey,\n}: {\n  atIndex: number;\n  targetKey: keyof ChannelSortBase;\n  sort?: ChannelListProps['sort'];\n}) => {\n  if (!sort) return null;\n  let option: null | ChannelSortBase = null;\n\n  if (Array.isArray(sort)) {\n    option = sort[atIndex] ?? null;\n  } else {\n    let index = 0;\n    for (const key in sort) {\n      if (index !== atIndex) {\n        index++;\n        continue;\n      }\n\n      if (key !== targetKey) {\n        return null;\n      }\n\n      option = sort;\n\n      break;\n    }\n  }\n\n  return option?.[targetKey] ?? null;\n};\n\n/**\n * Returns `true` only if `archived` property is of type `boolean` within `filters` object.\n */\nexport const shouldConsiderArchivedChannels = (filters: ChannelListProps['filters']) => {\n  if (!filters) return false;\n\n  return typeof filters.archived === 'boolean';\n};\n\n/**\n * Returns `true` only if `pinned_at` property is of type `string` within `membership` object.\n */\nexport const isChannelPinned = (channel: Channel) => {\n  if (!channel) return false;\n\n  const membership = channel.state.membership;\n\n  return typeof membership.pinned_at === 'string';\n};\n\n/**\n * Returns `true` only if `archived_at` property is of type `string` within `membership` object.\n */\nexport const isChannelArchived = (channel: Channel) => {\n  if (!channel) return false;\n\n  const membership = channel.state.membership;\n\n  return typeof membership.archived_at === 'string';\n};\n","import { useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { Channel, Event } from 'stream-chat';\nimport type { Dispatch, SetStateAction } from 'react';\n\nimport {\n  extractSortValue,\n  findLastPinnedChannelIndex,\n  isChannelArchived,\n  isChannelPinned,\n  moveChannelUpwards,\n  shouldConsiderArchivedChannels,\n  shouldConsiderPinnedChannels,\n} from '../utils';\nimport { useChatContext } from '../../../context';\nimport { getChannel } from '../../../utils';\nimport type { ChannelListProps } from '../ChannelList';\n\ntype SetChannels = Dispatch<SetStateAction<Channel[]>>;\n\ntype BaseParameters = {\n  event: Event;\n  setChannels: SetChannels;\n};\n\ntype RepeatedParameters = {\n  customHandler?: (\n    setChannels: BaseParameters['setChannels'],\n    event: BaseParameters['event'],\n  ) => void;\n};\n\ntype HandleMessageNewParameters = BaseParameters &\n  RepeatedParameters & {\n    allowNewMessagesFromUnfilteredChannels: boolean;\n    lockChannelOrder: boolean;\n  } & Required<Pick<ChannelListProps, 'filters' | 'sort'>>;\n\ntype HandleNotificationMessageNewParameters = BaseParameters &\n  RepeatedParameters & {\n    allowNewMessagesFromUnfilteredChannels: boolean;\n    lockChannelOrder: boolean;\n  } & Required<Pick<ChannelListProps, 'filters' | 'sort'>>;\n\ntype HandleNotificationRemovedFromChannelParameters = BaseParameters & RepeatedParameters;\n\ntype HandleNotificationAddedToChannelParameters = BaseParameters &\n  RepeatedParameters & {\n    allowNewMessagesFromUnfilteredChannels: boolean;\n    lockChannelOrder: boolean;\n  } & Required<Pick<ChannelListProps, 'sort'>>;\n\ntype HandleChannelVisibleParameters = BaseParameters &\n  RepeatedParameters &\n  Required<Pick<ChannelListProps, 'sort' | 'filters'>>;\n\ntype HandleMemberUpdatedParameters = BaseParameters & {\n  lockChannelOrder: boolean;\n} & Required<Pick<ChannelListProps, 'sort' | 'filters'>>;\n\ntype HandleChannelDeletedParameters = BaseParameters & RepeatedParameters;\n\ntype HandleChannelHiddenParameters = BaseParameters & RepeatedParameters;\n\ntype HandleChannelTruncatedParameters = BaseParameters & RepeatedParameters;\n\ntype HandleChannelUpdatedParameters = BaseParameters & RepeatedParameters;\n\ntype HandleUserPresenceChangedParameters = BaseParameters;\n\nconst shared = ({\n  customHandler,\n  event,\n  setChannels,\n}: BaseParameters & RepeatedParameters) => {\n  if (typeof customHandler === 'function') {\n    return customHandler(setChannels, event);\n  }\n\n  setChannels((channels) => {\n    const channelIndex = channels.findIndex((channel) => channel.cid === event.cid);\n\n    if (channelIndex < 0) return channels;\n\n    channels.splice(channelIndex, 1);\n\n    return [...channels];\n  });\n};\n\nexport const useChannelListShapeDefaults = () => {\n  const { client } = useChatContext();\n\n  const handleMessageNew = useCallback(\n    ({\n      allowNewMessagesFromUnfilteredChannels,\n      customHandler,\n      event,\n      filters,\n      lockChannelOrder,\n      setChannels,\n      sort,\n    }: HandleMessageNewParameters) => {\n      if (typeof customHandler === 'function') {\n        return customHandler(setChannels, event);\n      }\n\n      const channelType = event.channel_type;\n      const channelId = event.channel_id;\n\n      if (!channelType || !channelId) return;\n\n      setChannels((currentChannels) => {\n        const targetChannel = client.channel(channelType, channelId);\n        const targetChannelIndex = currentChannels.indexOf(targetChannel);\n        const targetChannelExistsWithinList = targetChannelIndex >= 0;\n\n        const isTargetChannelPinned = isChannelPinned(targetChannel);\n        const isTargetChannelArchived = isChannelArchived(targetChannel);\n\n        const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n        const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n\n        if (\n          // filter is defined, target channel is archived and filter option is set to false\n          (considerArchivedChannels && isTargetChannelArchived && !filters.archived) ||\n          // filter is defined, target channel isn't archived and filter option is set to true\n          (considerArchivedChannels && !isTargetChannelArchived && filters.archived) ||\n          // sort option is defined, target channel is pinned\n          (considerPinnedChannels && isTargetChannelPinned) ||\n          // list order is locked\n          lockChannelOrder ||\n          // target channel is not within the loaded list and loading from cache is disallowed\n          (!targetChannelExistsWithinList && !allowNewMessagesFromUnfilteredChannels)\n        ) {\n          return currentChannels;\n        }\n\n        return moveChannelUpwards({\n          channels: currentChannels,\n          channelToMove: targetChannel,\n          channelToMoveIndexWithinChannels: targetChannelIndex,\n          sort,\n        });\n      });\n    },\n    [client],\n  );\n\n  const handleNotificationMessageNew = useCallback(\n    async ({\n      allowNewMessagesFromUnfilteredChannels,\n      customHandler,\n      event,\n      filters,\n      setChannels,\n      sort,\n    }: HandleNotificationMessageNewParameters) => {\n      if (typeof customHandler === 'function') {\n        return customHandler(setChannels, event);\n      }\n\n      if (!event.channel) {\n        return;\n      }\n\n      const channel = await getChannel({\n        client,\n        id: event.channel.id,\n        type: event.channel.type,\n      });\n\n      const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n      if (isChannelArchived(channel) && considerArchivedChannels && !filters.archived) {\n        return;\n      }\n\n      if (!allowNewMessagesFromUnfilteredChannels) {\n        return;\n      }\n\n      setChannels((channels) =>\n        moveChannelUpwards({\n          channels,\n          channelToMove: channel,\n          sort,\n        }),\n      );\n    },\n    [client],\n  );\n\n  const handleNotificationAddedToChannel = useCallback(\n    async ({\n      allowNewMessagesFromUnfilteredChannels,\n      customHandler,\n      event,\n      setChannels,\n      sort,\n    }: HandleNotificationAddedToChannelParameters) => {\n      if (typeof customHandler === 'function') {\n        return customHandler(setChannels, event);\n      }\n\n      if (!event.channel || !allowNewMessagesFromUnfilteredChannels) {\n        return;\n      }\n\n      const channel = await getChannel({\n        client,\n        id: event.channel.id,\n        members: event.channel.members?.reduce<string[]>(\n          (newMembers, { user, user_id }) => {\n            const userId = user_id || user?.id;\n\n            if (userId) newMembers.push(userId);\n\n            return newMembers;\n          },\n          [],\n        ),\n        type: event.channel.type,\n      });\n\n      // membership has been reset (target channel shouldn't be pinned nor archived)\n      setChannels((channels) =>\n        moveChannelUpwards({\n          channels,\n          channelToMove: channel,\n          sort,\n        }),\n      );\n    },\n    [client],\n  );\n\n  const handleNotificationRemovedFromChannel = useCallback(\n    ({\n      customHandler,\n      event,\n      setChannels,\n    }: HandleNotificationRemovedFromChannelParameters) => {\n      if (typeof customHandler === 'function') {\n        return customHandler(setChannels, event);\n      }\n\n      setChannels((channels) =>\n        channels.filter((channel) => channel.cid !== event.channel?.cid),\n      );\n    },\n    [],\n  );\n\n  const handleMemberUpdated = useCallback(\n    ({\n      event,\n      filters,\n      lockChannelOrder,\n      setChannels,\n      sort,\n    }: HandleMemberUpdatedParameters) => {\n      if (\n        !event.member?.user ||\n        event.member.user.id !== client.userID ||\n        !event.channel_type\n      ) {\n        return;\n      }\n\n      const channelType = event.channel_type;\n      const channelId = event.channel_id;\n\n      const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n      const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n\n      // `pinned_at` nor `archived` properties are set or channel list order is locked, return early\n      if ((!considerPinnedChannels && !considerArchivedChannels) || lockChannelOrder) {\n        return;\n      }\n\n      const pinnedAtSort = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' });\n\n      setChannels((currentChannels) => {\n        const targetChannel = client.channel(channelType, channelId);\n        // assumes that channel instances are not changing\n        const targetChannelIndex = currentChannels.indexOf(targetChannel);\n        const targetChannelExistsWithinList = targetChannelIndex >= 0;\n\n        const isTargetChannelArchived = isChannelArchived(targetChannel);\n        const isTargetChannelPinned = isChannelPinned(targetChannel);\n\n        const newChannels = [...currentChannels];\n\n        if (targetChannelExistsWithinList) {\n          newChannels.splice(targetChannelIndex, 1);\n        }\n\n        // handle archiving (remove channel)\n        if (\n          (considerArchivedChannels && isTargetChannelArchived && !filters.archived) ||\n          (considerArchivedChannels && !isTargetChannelArchived && filters.archived)\n        ) {\n          return newChannels;\n        }\n\n        let lastPinnedChannelIndex: number | null = null;\n\n        // calculate last pinned channel index only if `pinned_at` sort is set to\n        // ascending order or if it's in descending order while the pin is being removed, otherwise\n        // we move to the top (index 0)\n        if (pinnedAtSort === 1 || (pinnedAtSort === -1 && !isTargetChannelPinned)) {\n          lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });\n        }\n\n        const newTargetChannelIndex =\n          typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0;\n\n        newChannels.splice(newTargetChannelIndex, 0, targetChannel);\n\n        return newChannels;\n      });\n    },\n    [client],\n  );\n\n  const handleChannelDeleted = useCallback(\n    (p: HandleChannelDeletedParameters) => shared(p),\n    [],\n  );\n\n  const handleChannelHidden = useCallback(\n    (p: HandleChannelHiddenParameters) => shared(p),\n    [],\n  );\n\n  const handleChannelVisible = useCallback(\n    async ({\n      customHandler,\n      event,\n      filters,\n      setChannels,\n      sort,\n    }: HandleChannelVisibleParameters) => {\n      if (typeof customHandler === 'function') {\n        return customHandler(setChannels, event);\n      }\n\n      if (!event.channel_id && !event.channel_type) {\n        return;\n      }\n\n      const channel = await getChannel({\n        client,\n        id: event.channel_id,\n        type: event.channel_type,\n      });\n\n      const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n      if (isChannelArchived(channel) && considerArchivedChannels && !filters.archived) {\n        return;\n      }\n\n      setChannels((channels) =>\n        moveChannelUpwards({\n          channels,\n          channelToMove: channel,\n          sort,\n        }),\n      );\n    },\n    [client],\n  );\n\n  const handleChannelTruncated = useCallback(\n    ({ customHandler, event, setChannels }: HandleChannelTruncatedParameters) => {\n      if (typeof customHandler === 'function') {\n        return customHandler(setChannels, event);\n      }\n\n      // TODO: not sure whether this is needed\n      setChannels((channels) => [...channels]);\n      // if (forceUpdate) {\n      //   forceUpdate();\n      // }\n    },\n    [],\n  );\n\n  const handleChannelUpdated = useCallback(\n    ({ customHandler, event, setChannels }: HandleChannelUpdatedParameters) => {\n      if (typeof customHandler === 'function') {\n        return customHandler(setChannels, event);\n      }\n\n      setChannels((channels) => {\n        const channelIndex = channels.findIndex(\n          (channel) => channel.cid === event.channel?.cid,\n        );\n\n        if (channelIndex > -1 && event.channel) {\n          const newChannels = channels;\n          newChannels[channelIndex].data = {\n            ...event.channel,\n            hidden: event.channel?.hidden ?? newChannels[channelIndex].data?.hidden,\n            own_capabilities:\n              event.channel?.own_capabilities ??\n              newChannels[channelIndex].data?.own_capabilities,\n          };\n\n          return [...newChannels];\n        }\n\n        return channels;\n      });\n\n      // if (forceUpdate) {\n      //   forceUpdate();\n      // }\n    },\n    [],\n  );\n\n  const handleUserPresenceChanged = useCallback(\n    ({ event, setChannels }: HandleUserPresenceChangedParameters) => {\n      setChannels((channels) => {\n        const newChannels = channels.map((channel) => {\n          if (!event.user?.id || !channel.state.members[event.user.id]) {\n            return channel;\n          }\n\n          // FIXME: oh no...\n          const newChannel = channel;\n          newChannel.state.members[event.user.id].user = event.user;\n\n          return newChannel;\n        });\n\n        return newChannels;\n      });\n    },\n    [],\n  );\n\n  return useMemo(\n    () => ({\n      handleChannelDeleted,\n      handleChannelHidden,\n      handleChannelTruncated,\n      handleChannelUpdated,\n      handleChannelVisible,\n      handleMemberUpdated,\n      handleMessageNew,\n      handleNotificationAddedToChannel,\n      handleNotificationMessageNew,\n      handleNotificationRemovedFromChannel,\n      handleUserPresenceChanged,\n    }),\n    [\n      handleChannelDeleted,\n      handleChannelHidden,\n      handleChannelTruncated,\n      handleChannelUpdated,\n      handleChannelVisible,\n      handleMemberUpdated,\n      handleMessageNew,\n      handleNotificationAddedToChannel,\n      handleNotificationMessageNew,\n      handleNotificationRemovedFromChannel,\n      handleUserPresenceChanged,\n    ],\n  );\n};\n\ntype UseDefaultHandleChannelListShapeParameters = Required<\n  Pick<\n    ChannelListProps,\n    'allowNewMessagesFromUnfilteredChannels' | 'lockChannelOrder' | 'filters' | 'sort'\n  >\n> &\n  Pick<\n    ChannelListProps,\n    | 'onAddedToChannel'\n    | 'onChannelDeleted'\n    | 'onChannelHidden'\n    | 'onChannelTruncated'\n    | 'onChannelUpdated'\n    | 'onChannelVisible'\n    | 'onMessageNew'\n    | 'onMessageNewHandler'\n    | 'onRemovedFromChannel'\n  > & {\n    setChannels: SetChannels;\n    customHandleChannelListShape?: (data: {\n      defaults: ReturnType<typeof useChannelListShapeDefaults>;\n      event: Event;\n      setChannels: SetChannels;\n    }) => void;\n  };\n\nexport const usePrepareShapeHandlers = ({\n  allowNewMessagesFromUnfilteredChannels,\n  customHandleChannelListShape,\n  filters,\n  lockChannelOrder,\n  onAddedToChannel,\n  onChannelDeleted,\n  onChannelHidden,\n  onChannelTruncated,\n  onChannelUpdated,\n  onChannelVisible,\n  onMessageNew,\n  onMessageNewHandler,\n  onRemovedFromChannel,\n  setChannels,\n  sort,\n}: UseDefaultHandleChannelListShapeParameters) => {\n  const defaults = useChannelListShapeDefaults();\n\n  const defaultHandleChannelListShapeRef = useRef<(e: Event) => void>(undefined);\n\n  const customHandleChannelListShapeRef = useRef<(e: Event) => void>(undefined);\n\n  customHandleChannelListShapeRef.current = (event: Event) => {\n    customHandleChannelListShape?.({ defaults, event, setChannels });\n  };\n\n  defaultHandleChannelListShapeRef.current = (event: Event) => {\n    switch (event.type) {\n      case 'message.new':\n        defaults.handleMessageNew({\n          allowNewMessagesFromUnfilteredChannels,\n          customHandler: onMessageNewHandler,\n          event,\n          filters,\n          lockChannelOrder,\n          setChannels,\n          sort,\n        });\n        break;\n      case 'notification.message_new':\n        defaults.handleNotificationMessageNew({\n          allowNewMessagesFromUnfilteredChannels,\n          customHandler: onMessageNew,\n          event,\n          filters,\n          lockChannelOrder,\n          setChannels,\n          sort,\n        });\n        break;\n      case 'notification.added_to_channel':\n        defaults.handleNotificationAddedToChannel({\n          allowNewMessagesFromUnfilteredChannels,\n          customHandler: onAddedToChannel,\n          event,\n          lockChannelOrder,\n          setChannels,\n          sort,\n        });\n        break;\n      case 'notification.removed_from_channel':\n        defaults.handleNotificationRemovedFromChannel({\n          customHandler: onRemovedFromChannel,\n          event,\n          setChannels,\n        });\n        break;\n      case 'channel.deleted':\n        defaults.handleChannelDeleted({\n          customHandler: onChannelDeleted,\n          event,\n          setChannels,\n        });\n        break;\n      case 'channel.hidden':\n        defaults.handleChannelHidden({\n          customHandler: onChannelHidden,\n          event,\n          setChannels,\n        });\n        break;\n      case 'channel.visible':\n        defaults.handleChannelVisible({\n          customHandler: onChannelVisible,\n          event,\n          filters,\n          setChannels,\n          sort,\n        });\n        break;\n      case 'channel.truncated':\n        defaults.handleChannelTruncated({\n          customHandler: onChannelTruncated,\n          event,\n          setChannels,\n        });\n        break;\n      case 'channel.updated':\n        defaults.handleChannelUpdated({\n          customHandler: onChannelUpdated,\n          event,\n          setChannels,\n        });\n        break;\n      case 'user.presence.changed':\n        defaults.handleUserPresenceChanged({ event, setChannels });\n        break;\n      case 'member.updated':\n        defaults.handleMemberUpdated({\n          event,\n          filters,\n          lockChannelOrder,\n          setChannels,\n          sort,\n        });\n        break;\n      default:\n        break;\n    }\n  };\n\n  const defaultFn = useCallback((e: Event) => {\n    defaultHandleChannelListShapeRef.current?.(e);\n  }, []);\n\n  const customFn = useMemo(() => {\n    if (!customHandleChannelListShape) return null;\n    return (e: Event) => {\n      customHandleChannelListShapeRef.current?.(e);\n    };\n  }, [customHandleChannelListShape]);\n\n  return {\n    customHandler: customFn,\n    defaultHandler: defaultFn,\n  };\n};\n\nexport const useChannelListShape = (handler: (e: Event) => void) => {\n  const { client } = useChatContext();\n\n  useEffect(() => {\n    const subscription = client.on('all', handler);\n\n    return subscription.unsubscribe;\n  }, [client, handler]);\n};\n","import React from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { APIErrorResponse, Channel, ErrorFromResponse } from 'stream-chat';\n\nimport { LoadingChannels } from '../Loading/LoadingChannels';\nimport { NullComponent } from '../UtilityComponents';\nimport { useComponentContext, useTranslationContext } from '../../context';\n\nexport type ChannelListUIProps = {\n  /** Whether the channel query request returned an errored response */\n  error: ErrorFromResponse<APIErrorResponse> | null;\n  /** The channels currently loaded in the list, only defined if `sendChannelsToList` on `ChannelList` is true */\n  loadedChannels?: Channel[];\n  /** Whether the channels are currently loading */\n  loading?: boolean;\n  /** Local state hook that resets the currently loaded channels */\n  setChannels?: React.Dispatch<React.SetStateAction<Channel[]>>;\n};\n\n/**\n * A preview list of channels, allowing you to select the channel you want to open\n */\nexport const ChannelListUI = (props: PropsWithChildren<ChannelListUIProps>) => {\n  const { children, error = null, loading = false } = props;\n  const { LoadingErrorIndicator = NullComponent, LoadingIndicator = LoadingChannels } =\n    useComponentContext('ChannelListUI');\n  const { t } = useTranslationContext('ChannelListUI');\n\n  if (error) {\n    return <LoadingErrorIndicator error={error} />;\n  }\n\n  return (\n    <div className='str-chat__channel-list-inner'>\n      <div\n        aria-label={t('aria/Channel list')}\n        className='str-chat__channel-list-inner__main'\n        role='listbox'\n      >\n        {loading ? <LoadingIndicator /> : children}\n      </div>\n    </div>\n  );\n};\n","import React, { createContext, useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { SearchController } from 'stream-chat';\nimport type { SearchProps } from './Search';\n\nexport type SearchContextValue = {\n  /** Instance of the search controller that handles the data management */\n  searchController: SearchController;\n  /** Reference to the container element of the search component */\n  containerRef: React.RefObject<HTMLDivElement | null>;\n  /** Reference to the container element of the filter buttons */\n  filterButtonsContainerRef: React.RefObject<HTMLDivElement | null>;\n} & Pick<SearchProps, 'disabled' | 'placeholder'> &\n  Required<Pick<SearchProps, 'exitSearchOnInputBlur' | 'directMessagingChannelType'>>;\n\nexport const SearchContext = createContext<SearchContextValue | undefined>(undefined);\n\n/**\n * Context provider for components rendered within the `Search` component\n */\nexport const SearchContextProvider = ({\n  children,\n  value,\n}: PropsWithChildren<{\n  value: SearchContextValue;\n}>) => (\n  <SearchContext.Provider value={value as unknown as SearchContextValue}>\n    {children}\n  </SearchContext.Provider>\n);\n\nexport const useSearchContext = () => {\n  const contextValue = useContext(SearchContext);\n  return contextValue as unknown as SearchContextValue;\n};\n","import clsx from 'clsx';\nimport React, { useEffect, useState } from 'react';\n\nimport { useStableId } from '../../UtilityComponents/useStableId';\nimport { useSearchContext } from '../SearchContext';\nimport { useSearchQueriesInProgress } from '../hooks';\nimport { useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { Button, IconSearch, IconXCircle, VisuallyHidden } from '../../../components';\n\nimport type { SearchControllerState } from 'stream-chat';\n\nconst searchControllerStateSelector = (nextValue: SearchControllerState) => ({\n  isActive: nextValue.isActive,\n  searchQuery: nextValue.searchQuery,\n});\n\nexport const SearchBar = () => {\n  const { t } = useTranslationContext();\n  const {\n    disabled,\n    exitSearchOnInputBlur,\n    filterButtonsContainerRef,\n    placeholder,\n    searchController,\n  } = useSearchContext();\n  const queriesInProgress = useSearchQueriesInProgress(searchController);\n  const clearButtonRef = React.useRef<HTMLButtonElement | null>(null);\n  const searchInputId = useStableId();\n\n  const [input, setInput] = useState<HTMLInputElement | null>(null);\n  const { isActive, searchQuery } = useStateStore(\n    searchController.state,\n    searchControllerStateSelector,\n  );\n\n  useEffect(() => {\n    if (!input) return;\n    const handleKeyDown = (event: KeyboardEvent) => {\n      if (event.key === 'Escape') {\n        input.blur();\n        searchController.exit();\n      }\n    };\n\n    document.addEventListener('keydown', handleKeyDown);\n    return () => {\n      document.removeEventListener('keydown', handleKeyDown);\n    };\n  }, [searchController, input]);\n\n  return (\n    <div className='str-chat__search-bar' data-testid='search-bar' role='search'>\n      <div\n        className={clsx('str-chat__search-bar__input-wrapper', {\n          'str-chat__search-bar__input-wrapper--active': isActive,\n        })}\n      >\n        <label htmlFor={searchInputId}>\n          <VisuallyHidden>{t('Search')}</VisuallyHidden>\n        </label>\n        <IconSearch />\n        <input\n          className='str-chat__search-bar__input'\n          data-testid='search-input'\n          disabled={disabled}\n          id={searchInputId}\n          onBlur={({ currentTarget, relatedTarget }) => {\n            if (\n              exitSearchOnInputBlur &&\n              // input is empty\n              !currentTarget.value &&\n              // clicking on filter buttons or clear button shouldn't trigger exit search on blur\n              !filterButtonsContainerRef.current?.contains(relatedTarget) &&\n              // clicking clear button shouldn't trigger exit search on blur\n              (!clearButtonRef.current || relatedTarget !== clearButtonRef.current)\n            ) {\n              searchController.exit();\n            }\n          }}\n          onChange={(event: React.ChangeEvent<HTMLInputElement>) => {\n            if (event.target.value) {\n              searchController.search(event.target.value);\n            } else if (!event.target.value) {\n              searchController.clear();\n            }\n          }}\n          onFocus={searchController.activate}\n          placeholder={placeholder ?? t('Search')}\n          ref={setInput}\n          type='text'\n          value={searchQuery}\n        />\n        {searchQuery && (\n          <Button\n            appearance='ghost'\n            aria-label={t('aria/Clear search')}\n            circular\n            className='str-chat__search-bar__clear-button'\n            data-testid='clear-input-button'\n            disabled={queriesInProgress.length > 0} // prevent user from clearing the input while query is in progress and avoid out-of-sync UX\n            onClick={() => {\n              searchController.clear();\n              input?.focus();\n            }}\n            ref={clearButtonRef}\n            size='xs'\n            variant='secondary'\n          >\n            <IconXCircle />\n          </Button>\n        )}\n      </div>\n      {isActive && (\n        <Button\n          appearance='ghost'\n          aria-label={t('aria/Exit search')}\n          className='str-chat__search-bar__exit-search-button'\n          data-testid='search-bar-button'\n          onClick={() => {\n            input?.blur();\n            searchController.exit();\n          }}\n          size='sm'\n          variant='secondary'\n        >\n          {t('Cancel')}\n        </Button>\n      )}\n    </div>\n  );\n};\n","import React, { useCallback, useMemo } from 'react';\nimport uniqBy from 'lodash.uniqby';\nimport type { ComponentType } from 'react';\nimport type { Channel, MessageResponse, User } from 'stream-chat';\n\nimport { useSearchContext } from '../SearchContext';\nimport { Avatar } from '../../../components/Avatar';\nimport { ChannelListItem } from '../../../components/ChannelListItem';\nimport {\n  useChannelListContext,\n  useChatContext,\n  useTranslationContext,\n} from '../../../context';\nimport { DEFAULT_JUMP_TO_PAGE_SIZE } from '../../../constants/limits';\nimport { Timestamp } from '../../../components/Message/Timestamp';\n\nexport type ChannelSearchResultItemProps = {\n  item: Channel;\n};\n\nexport const ChannelSearchResultItem = ({ item }: ChannelSearchResultItemProps) => {\n  const { setActiveChannel } = useChatContext();\n  const { setChannels } = useChannelListContext();\n\n  const onSelect = useCallback(() => {\n    setActiveChannel(item);\n    setChannels?.((channels) => uniqBy([item, ...channels], 'cid'));\n  }, [item, setActiveChannel, setChannels]);\n\n  return (\n    <ChannelListItem\n      channel={item}\n      className='str-chat__search-result'\n      onSelect={onSelect}\n    />\n  );\n};\n\nexport type ChannelByMessageSearchResultItemProps = {\n  item: MessageResponse;\n};\n\nexport const MessageSearchResultItem = ({\n  item,\n}: ChannelByMessageSearchResultItemProps) => {\n  const {\n    channel: activeChannel,\n    client,\n    searchController,\n    setActiveChannel,\n  } = useChatContext();\n  const { setChannels } = useChannelListContext();\n\n  const channel = useMemo(() => {\n    const { channel: channelData } = item;\n    const type = channelData?.type ?? 'unknown';\n    const id = channelData?.id ?? 'unknown';\n    return client.channel(type, id);\n  }, [client, item]);\n\n  const onSelect = useCallback(async () => {\n    if (!channel) return;\n    await channel.state.loadMessageIntoState(\n      item.id,\n      undefined,\n      DEFAULT_JUMP_TO_PAGE_SIZE,\n    );\n    // FIXME: message focus should be handled by yet non-existent msg list controller in client packaged\n    searchController._internalState.partialNext({ focusedMessage: item });\n    setActiveChannel(channel);\n    setChannels?.((channels) => uniqBy([channel, ...channels], 'cid'));\n  }, [channel, item, searchController, setActiveChannel, setChannels]);\n\n  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n  const getLatestMessagePreview = useCallback(() => item.text!, [item]);\n\n  if (!channel) return null;\n\n  return (\n    <ChannelListItem\n      active={\n        channel.cid === activeChannel?.cid &&\n        item.id === searchController._internalState.getLatestValue().focusedMessage?.id\n      }\n      channel={channel}\n      className='str-chat__search-result'\n      getLatestMessagePreview={getLatestMessagePreview}\n      onSelect={onSelect}\n    />\n  );\n};\n\nexport type UserSearchResultItemProps = {\n  item: User;\n};\n\nexport const UserSearchResultItem = ({ item }: UserSearchResultItemProps) => {\n  const { client, setActiveChannel } = useChatContext();\n  const { setChannels } = useChannelListContext();\n  const { directMessagingChannelType } = useSearchContext();\n  const { t } = useTranslationContext();\n\n  const onClick = useCallback(() => {\n    const newChannel = client.channel(directMessagingChannelType, {\n      members: [client.userID as string, item.id],\n    });\n    newChannel.watch();\n    setActiveChannel(newChannel);\n    setChannels?.((channels) => uniqBy([newChannel, ...channels], 'cid'));\n  }, [client, item, setActiveChannel, setChannels, directMessagingChannelType]);\n\n  return (\n    <div className='str-chat__search-result-container'>\n      <button\n        aria-label={t('aria/Select User Channel: {{ name }}', {\n          name: item.name || '',\n        })}\n        className='str-chat__search-result str-chat__search-result--user'\n        data-testid='search-result-user'\n        onClick={onClick}\n        role='option'\n      >\n        <Avatar\n          imageUrl={item.image}\n          isOnline={item.online}\n          size='xl'\n          userName={item.name || item.id}\n        />\n        <div className='str-chat__search-result-data'>\n          <div className='str-chat__search-result__display-name'>\n            {item.name || item.username || item.id}\n          </div>\n          <Timestamp\n            customClass='str-chat__search-result__last-active-timestamp'\n            timestamp={item.last_active}\n          />\n        </div>\n      </button>\n    </div>\n  );\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SearchResultItemComponents = Record<string, ComponentType<{ item: any }>>;\n\nexport const DefaultSearchResultItems: SearchResultItemComponents = {\n  channels: ChannelSearchResultItem,\n  messages: MessageSearchResultItem,\n  users: UserSearchResultItem,\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { createContext, useContext } from 'react';\nimport type { SearchSource } from 'stream-chat';\n\nexport type SearchSourceResultsContextValue = {\n  searchSource: SearchSource;\n};\n\nexport const SearchSourceResultsContext = createContext<\n  SearchSourceResultsContextValue | undefined\n>(undefined);\n\n/**\n * Context provider for components rendered within the `SearchSourceResults`\n */\nexport const SearchSourceResultsContextProvider = ({\n  children,\n  value,\n}: PropsWithChildren<{\n  value: SearchSourceResultsContextValue;\n}>) => (\n  <SearchSourceResultsContext.Provider\n    value={value as unknown as SearchSourceResultsContextValue}\n  >\n    {children}\n  </SearchSourceResultsContext.Provider>\n);\n\nexport const useSearchSourceResultsContext = () => {\n  const contextValue = useContext(SearchSourceResultsContext);\n  return contextValue as unknown as SearchSourceResultsContextValue;\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../../context';\nimport { useSearchSourceResultsContext } from '../SearchSourceResultsContext';\n\nexport const SearchSourceResultsLoadingIndicator = () => {\n  const { t } = useTranslationContext();\n  const { searchSource } = useSearchSourceResultsContext();\n  return (\n    <div\n      className='str-chat__search-source-results__loading-indicator'\n      data-testid='search-loading-indicator'\n    >\n      {t('Searching for {{ searchSourceType }}...', {\n        searchSourceType: searchSource.type,\n      })}\n    </div>\n  );\n};\n","import React from 'react';\nimport type { SearchSourceState } from 'stream-chat';\n\nimport { SearchSourceResultsLoadingIndicator as DefaultSearchSourceResultsLoadingIndicator } from './SearchSourceResultsLoadingIndicator';\nimport { useSearchSourceResultsContext } from '../SearchSourceResultsContext';\nimport { useComponentContext, useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst searchSourceStateSelector = (value: SearchSourceState) => ({\n  hasNext: value.hasNext,\n  isLoading: value.isLoading,\n});\n\nexport const SearchSourceResultListFooter = () => {\n  const { t } = useTranslationContext();\n  const {\n    SearchSourceResultsLoadingIndicator = DefaultSearchSourceResultsLoadingIndicator,\n  } = useComponentContext();\n  const { searchSource } = useSearchSourceResultsContext();\n  const { hasNext, isLoading } = useStateStore(\n    searchSource.state,\n    searchSourceStateSelector,\n  );\n\n  return (\n    <div\n      className='str-chat__search-source-result-list__footer'\n      data-testid='search-footer'\n    >\n      {isLoading ? (\n        <SearchSourceResultsLoadingIndicator />\n      ) : !hasNext ? (\n        <div className='str-chat__search-source-results---empty'>\n          {t('All results loaded')}\n        </div>\n      ) : null}\n    </div>\n  );\n};\n","import React from 'react';\nimport type { ComponentType } from 'react';\nimport type { SearchSourceState, SearchSourceType } from 'stream-chat';\n\nimport { DefaultSearchResultItems } from './SearchResultItem';\nimport { SearchSourceResultListFooter as DefaultSearchSourceResultListFooter } from './SearchSourceResultListFooter';\nimport { useSearchSourceResultsContext } from '../SearchSourceResultsContext';\nimport { InfiniteScrollPaginator } from '../../../components/InfiniteScrollPaginator/InfiniteScrollPaginator';\nimport { useComponentContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport type { SearchResultItemComponents } from './SearchResultItem';\n\nconst searchSourceStateSelector = (nextValue: SearchSourceState) => ({\n  items: nextValue.items,\n});\n\nexport type SearchSourceResultListProps = {\n  loadMoreDebounceMs?: number;\n  loadMoreThresholdPx?: number;\n  SearchResultItems?: SearchResultItemComponents;\n};\n\nexport const SearchSourceResultList = ({\n  loadMoreDebounceMs = 100,\n  loadMoreThresholdPx = 80,\n  SearchResultItems = DefaultSearchResultItems,\n}: SearchSourceResultListProps) => {\n  const { SearchSourceResultListFooter = DefaultSearchSourceResultListFooter } =\n    useComponentContext();\n\n  const { searchSource } = useSearchSourceResultsContext();\n  const { items } = useStateStore(searchSource.state, searchSourceStateSelector);\n\n  const SearchResultItem = SearchResultItems[\n    searchSource.type as SearchSourceType\n  ] as ComponentType<{ item: unknown }>;\n\n  if (!SearchResultItem) return null;\n\n  return (\n    <div\n      className='str-chat__search-source-result-list'\n      data-testid='search-source-result-list'\n    >\n      <InfiniteScrollPaginator\n        loadNextDebounceMs={loadMoreDebounceMs}\n        loadNextOnScrollToBottom={searchSource.search}\n        threshold={loadMoreThresholdPx}\n      >\n        {items?.map((item, i) => (\n          <SearchResultItem\n            item={item}\n            key={`source-search-result-${searchSource.type}-${i}`}\n          />\n        ))}\n        <SearchSourceResultListFooter />\n      </InfiniteScrollPaginator>\n    </div>\n  );\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../../context';\n\nexport const SearchSourceResultsEmpty = () => {\n  const { t } = useTranslationContext();\n  return (\n    <div className='str-chat__search-source-results-empty'>{t('No results found')}</div>\n  );\n};\n","export const SearchSourceResultsHeader = () => null;\n","import React from 'react';\nimport type { SearchSource, SearchSourceState } from 'stream-chat';\n\nimport { SearchSourceResultList as DefaultSearchSourceResultList } from './SearchSourceResultList';\nimport { SearchSourceResultsEmpty as DefaultSearchSourceResultsEmpty } from './SearchSourceResultsEmpty';\nimport { SearchSourceResultsHeader as DefaultSearchSourceResultsHeader } from './SearchSourceResultsHeader';\nimport { SearchSourceResultsContextProvider } from '../SearchSourceResultsContext';\nimport { useComponentContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst searchSourceStateSelector = (nextValue: SearchSourceState) => ({\n  isLoading: nextValue.isLoading,\n  items: nextValue.items,\n});\n\nexport type SearchSourceResultsProps = { searchSource: SearchSource };\n\nexport const SearchSourceResults = ({ searchSource }: SearchSourceResultsProps) => {\n  const {\n    SearchSourceResultList = DefaultSearchSourceResultList,\n    SearchSourceResultsEmpty = DefaultSearchSourceResultsEmpty,\n    SearchSourceResultsHeader = DefaultSearchSourceResultsHeader,\n  } = useComponentContext();\n  const { isLoading, items } = useStateStore(\n    searchSource.state,\n    searchSourceStateSelector,\n  );\n\n  if (!items && !isLoading) return null;\n\n  return (\n    <SearchSourceResultsContextProvider value={{ searchSource }}>\n      <div\n        className='str-chat__search-source-results'\n        data-testid='search-source-results'\n      >\n        <SearchSourceResultsHeader />\n        {items?.length || isLoading ? (\n          <SearchSourceResultList />\n        ) : (\n          <SearchSourceResultsEmpty />\n        )}\n      </div>\n    </SearchSourceResultsContextProvider>\n  );\n};\n","import clsx from 'clsx';\nimport React, { useMemo } from 'react';\nimport type { SearchSource, SearchSourceState } from 'stream-chat';\n\nimport { useSearchContext } from '../SearchContext';\nimport { useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { Button } from '../../../components';\n\nconst searchSourceStateSelector = (nextValue: SearchSourceState) => ({\n  isActive: nextValue.isActive,\n});\n\ntype SearchSourceFilterButtonProps = {\n  source: SearchSource;\n};\n\nconst SearchSourceFilterButton = ({ source }: SearchSourceFilterButtonProps) => {\n  const { t } = useTranslationContext();\n  const { searchController } = useSearchContext();\n  const { isActive } = useStateStore(source.state, searchSourceStateSelector);\n  const label = `search-results-header-filter-source-button-label--${source.type}`;\n\n  const knownLabels = useMemo<Record<string, string>>(\n    () => ({\n      'search-results-header-filter-source-button-label--channels': t(\n        'search-results-header-filter-source-button-label--channels',\n      ),\n      'search-results-header-filter-source-button-label--messages': t(\n        'search-results-header-filter-source-button-label--messages',\n      ),\n      'search-results-header-filter-source-button-label--users': t(\n        'search-results-header-filter-source-button-label--users',\n      ),\n    }),\n    [t],\n  );\n\n  const buttonContent = knownLabels[label] ?? t(label);\n  return (\n    <Button\n      appearance='outline'\n      aria-label={t('aria/Search results header filter button for: {{ source }}', {\n        source: buttonContent,\n      })}\n      aria-pressed={isActive}\n      className={clsx('str-chat__search-results-header__filter-source-button', {\n        'str-chat__search-results-header__filter-source-button--active': isActive,\n      })}\n      key={label}\n      onClick={() => {\n        if (source.isActive) {\n          searchController.deactivateSource(source.type);\n        } else {\n          searchController.activateSource(source.type);\n          if (searchController.searchQuery && !source.items?.length)\n            source.search(searchController.searchQuery);\n        }\n      }}\n      size='xs'\n      variant='secondary'\n    >\n      {buttonContent}\n    </Button>\n  );\n};\n\nexport const SearchResultsHeader = () => {\n  const { filterButtonsContainerRef, searchController } = useSearchContext();\n\n  // render nothing if there's only one source (can't change filters)\n  if (searchController.sources.length < 2) return null;\n\n  return (\n    <div className='str-chat__search-results-header' data-testid='search-results-header'>\n      <div\n        className='str-chat__search-results-header__filter-source-buttons'\n        data-testid='filter-source-buttons'\n        ref={filterButtonsContainerRef}\n      >\n        {searchController.sources.map((source) => (\n          <SearchSourceFilterButton key={source.type} source={source} />\n        ))}\n      </div>\n    </div>\n  );\n};\n","import React from 'react';\n\nimport { useTranslationContext } from '../../../context';\n\nimport type { SearchSource } from 'stream-chat';\n\nexport type SearchResultsPresearchProps = {\n  activeSources: SearchSource[];\n};\n\nexport const SearchResultsPresearch = () => {\n  const { t } = useTranslationContext();\n  return (\n    <div className='str-chat__search-results-presearch'>\n      {t('Start typing to search')}\n    </div>\n  );\n};\n","import React from 'react';\nimport type { SearchControllerState } from 'stream-chat';\n\nimport { SearchSourceResults as DefaultSourceSearchResults } from './SearchSourceResults';\nimport { SearchResultsHeader as DefaultSearchResultsHeader } from './SearchResultsHeader';\nimport { SearchResultsPresearch as DefaultSearchResultsPresearch } from './SearchResultsPresearch';\nimport { useSearchContext } from '../SearchContext';\nimport { useComponentContext, useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst searchControllerStateSelector = (nextValue: SearchControllerState) => ({\n  activeSources: nextValue.sources.filter((s) => s.isActive),\n  isActive: nextValue.isActive,\n  searchQuery: nextValue.searchQuery,\n});\n\nexport const SearchResults = () => {\n  const { t } = useTranslationContext('ResultsContainer');\n  const {\n    SearchResultsHeader = DefaultSearchResultsHeader,\n    SearchResultsPresearch = DefaultSearchResultsPresearch,\n    SearchSourceResults = DefaultSourceSearchResults,\n  } = useComponentContext();\n  const { searchController } = useSearchContext();\n  const { activeSources, isActive, searchQuery } = useStateStore(\n    searchController.state,\n    searchControllerStateSelector,\n  );\n\n  return !isActive ? null : (\n    <div aria-label={t('aria/Search results')} className='str-chat__search-results'>\n      <SearchResultsHeader />\n      {!searchQuery ? (\n        <SearchResultsPresearch activeSources={activeSources} />\n      ) : (\n        activeSources.map((source) => (\n          <SearchSourceResults key={source.type} searchSource={source} />\n        ))\n      )}\n    </div>\n  );\n};\n","import clsx from 'clsx';\nimport React, { useRef } from 'react';\nimport type { SearchControllerState } from 'stream-chat';\n\nimport { SearchBar as DefaultSearchBar } from './SearchBar/SearchBar';\nimport { SearchResults as DefaultSearchResults } from './SearchResults/SearchResults';\nimport { SearchContextProvider } from './SearchContext';\nimport { useChatContext, useComponentContext } from '../../context';\nimport { useStateStore } from '../../store';\n\ntype SearchControllerStateSelectorReturnValue = {\n  isActive: boolean;\n};\n\nconst searchControllerStateSelector = (\n  nextValue: SearchControllerState,\n): SearchControllerStateSelectorReturnValue => ({ isActive: nextValue.isActive });\n\nexport type SearchProps = {\n  /** The type of channel to create on user result select, defaults to `messaging` */\n  directMessagingChannelType?: string;\n  /** Sets the input element into disabled state */\n  disabled?: boolean;\n  /** Clear the search state/results on every click outside the search input, defaults to `false` */\n  exitSearchOnInputBlur?: boolean;\n  /** Custom placeholder text to be displayed in the search input */\n  placeholder?: string;\n};\n\nexport const Search = ({\n  directMessagingChannelType = 'messaging',\n  disabled,\n  exitSearchOnInputBlur = false,\n  placeholder,\n}: SearchProps) => {\n  const { SearchBar = DefaultSearchBar, SearchResults = DefaultSearchResults } =\n    useComponentContext();\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  const filterButtonsContainerRef = useRef<HTMLDivElement | null>(null);\n\n  const { searchController } = useChatContext();\n\n  const { isActive } = useStateStore<\n    SearchControllerState,\n    SearchControllerStateSelectorReturnValue\n  >(searchController.state, searchControllerStateSelector);\n\n  return (\n    <SearchContextProvider\n      value={{\n        containerRef,\n        directMessagingChannelType,\n        disabled,\n        exitSearchOnInputBlur,\n        filterButtonsContainerRef,\n        placeholder,\n        searchController,\n      }}\n    >\n      <div\n        className={clsx('str-chat__search', {\n          'str-chat__search--active': isActive,\n        })}\n        data-testid='search'\n        ref={containerRef}\n      >\n        <SearchBar />\n        <SearchResults />\n      </div>\n    </SearchContextProvider>\n  );\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport { LoadingIndicator } from '../Loading';\nimport { useTranslationContext } from '../../context';\nimport { Button } from '../Button';\n\nexport type LoadMoreButtonProps = {\n  /** onClick handler load more button. Pagination logic should be executed in this handler. */\n  onClick: React.MouseEventHandler<HTMLButtonElement>;\n  /** indicates whether a loading request is in progress */\n  isLoading?: boolean;\n};\n\nconst UnMemoizedLoadMoreButton = ({\n  children,\n  isLoading,\n  onClick,\n}: PropsWithChildren<LoadMoreButtonProps>) => {\n  const { t } = useTranslationContext('UnMemoizedLoadMoreButton');\n\n  const childrenOrDefaultString = children ?? t('Load more');\n\n  return (\n    <div className='str-chat__load-more-button'>\n      <Button\n        appearance='ghost'\n        aria-label={t('Load more')}\n        data-testid='load-more-button'\n        disabled={isLoading}\n        onClick={onClick}\n        size='sm'\n        variant='secondary'\n      >\n        {isLoading ? <LoadingIndicator /> : childrenOrDefaultString}\n      </Button>\n    </div>\n  );\n};\n\nexport const LoadMoreButton = React.memo(\n  UnMemoizedLoadMoreButton,\n) as typeof UnMemoizedLoadMoreButton;\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\n\nimport type { LoadMoreButtonProps } from './LoadMoreButton';\nimport { LoadMoreButton as DefaultLoadMoreButton } from './LoadMoreButton';\nimport type { PaginatorProps } from '../../types/types';\n\nexport type LoadMorePaginatorProps = PaginatorProps & {\n  /** A UI button component that handles pagination logic */\n  LoadMoreButton?: React.ComponentType<LoadMoreButtonProps>;\n  /** indicates if the `LoadMoreButton` should be displayed at the top of the list of channels instead of the bottom of the list (the default) */\n  reverse?: boolean;\n};\n\nexport const UnMemoizedLoadMorePaginator = (\n  props: PropsWithChildren<LoadMorePaginatorProps>,\n) => {\n  const {\n    children,\n    hasNextPage,\n    isLoading,\n    LoadMoreButton = DefaultLoadMoreButton,\n    loadNextPage,\n    reverse,\n  } = props;\n\n  return (\n    <>\n      {!reverse && children}\n      {hasNextPage && <LoadMoreButton isLoading={isLoading} onClick={loadNextPage} />}\n      {reverse && children}\n    </>\n  );\n};\n\nexport const LoadMorePaginator = React.memo(\n  UnMemoizedLoadMorePaginator,\n) as typeof UnMemoizedLoadMorePaginator;\n","import React from 'react';\nimport {\n  useChatContext,\n  useComponentContext,\n  useTranslationContext,\n} from '../../context';\n\nexport const ChannelListHeader = () => {\n  const { t } = useTranslationContext();\n  const { channel } = useChatContext();\n  const { HeaderEndContent } = useComponentContext();\n  return (\n    <div className='str-chat__channel-list__header'>\n      <div className='str-chat__channel-list__header__title'>{t('Chats')}</div>\n      {channel && HeaderEndContent && <HeaderEndContent />}\n    </div>\n  );\n};\n","import type { ReactNode } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\nimport type {\n  Channel,\n  ChannelFilters,\n  ChannelOptions,\n  ChannelSort,\n  Event,\n  SearchControllerState,\n} from 'stream-chat';\n\nimport { useConnectionRecoveredListener } from './hooks/useConnectionRecoveredListener';\nimport type {\n  CustomQueryChannelsFn,\n  EffectiveQueryParams,\n} from './hooks/usePaginatedChannels';\nimport { usePaginatedChannels } from './hooks/usePaginatedChannels';\nimport {\n  useChannelListShape,\n  usePrepareShapeHandlers,\n} from './hooks/useChannelListShape';\nimport { useStateStore } from '../../store';\nimport { ChannelListUI as DefaultChannelListUI } from './ChannelListUI';\nimport { ChannelListItem } from '../ChannelListItem/ChannelListItem';\nimport { Search as DefaultSearch } from '../Search';\nimport type { EmptyStateIndicatorProps } from '../EmptyStateIndicator';\nimport { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';\nimport type { LoadMorePaginatorProps } from '../LoadMore/LoadMorePaginator';\nimport { LoadMorePaginator } from '../LoadMore/LoadMorePaginator';\nimport { NotificationList as DefaultNotificationList } from '../Notifications';\nimport type { ChatContextValue } from '../../context';\nimport {\n  ChannelListContextProvider,\n  DialogManagerProvider,\n  useChatContext,\n  useComponentContext,\n} from '../../context';\nimport { moveChannelUpwards } from './utils';\nimport type { TranslationContextValue } from '../../context/TranslationContext';\nimport type { PaginatorProps } from '../../types/types';\nimport { ChannelListHeader } from './ChannelListHeader';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nconst DEFAULT_FILTERS = {};\nconst DEFAULT_OPTIONS = {};\nconst DEFAULT_SORT = {};\n\nconst searchControllerStateSelector = (nextValue: SearchControllerState) => ({\n  searchIsActive: nextValue.isActive,\n});\n\nexport type ChannelListProps = {\n  /**\n   * When the client receives `message.new`, `notification.message_new`, and `notification.added_to_channel` events, we automatically\n   * push that channel to the top of the list. If the channel doesn't currently exist in the list, we grab the channel from\n   * `client.activeChannels` and push it to the top of the list. You can disable this behavior by setting this prop\n   * to false, which will prevent channels not in the list from incrementing the list. The default is true.\n   */\n  allowNewMessagesFromUnfilteredChannels?: boolean;\n  /** Optional function to filter channels prior to loading in the DOM. Do not use any complex or async logic that would delay the loading of the ChannelList. We recommend using a pure function with array methods like filter/sort/reduce. */\n  channelRenderFilterFn?: (channels: Array<Channel>) => Array<Channel>;\n  // FIXME: how is this even legal (WHY IS IT STRING?!)\n  /** Set a channel (with this ID) to active and manually move it to the top of the list */\n  customActiveChannel?: string;\n  /** Custom function that handles the channel pagination. Has to build query filters, sort and options and query and append channels to the current channels state and update the hasNext pagination flag after each query. */\n  customQueryChannels?: CustomQueryChannelsFn;\n  /** Custom UI component for rendering an empty list, defaults to and accepts same props as: [EmptyStateIndicator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx) */\n  EmptyStateIndicator?: React.ComponentType<EmptyStateIndicatorProps>;\n  /** An object containing channel query filters */\n  filters?: ChannelFilters;\n  /** Custom function that generates the message preview in ChannelPreview component */\n  getLatestMessagePreview?: (\n    channel: Channel,\n    t: TranslationContextValue['t'],\n    userLanguage: TranslationContextValue['userLanguage'],\n    isMessageAIGenerated?: ChatContextValue['isMessageAIGenerated'],\n  ) => ReactNode;\n  /** When true, channels won't dynamically sort by most recent message */\n  lockChannelOrder?: boolean;\n  /** Function to override the default behavior when a user is added to a channel, corresponds to [notification.added\\_to\\_channel](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onAddedToChannel?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default behavior when a channel is deleted, corresponds to [channel.deleted](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onChannelDeleted?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default behavior when a channel is hidden, corresponds to [channel.hidden](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onChannelHidden?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default behavior when a channel is truncated, corresponds to [channel.truncated](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onChannelTruncated?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default behavior when a channel is updated, corresponds to [channel.updated](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onChannelUpdated?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default channel visible behavior, corresponds to [channel.visible](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onChannelVisible?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default behavior when a message is received on a channel not being watched, corresponds to [notification.message\\_new](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onMessageNew?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default behavior when a message is received on a channel being watched, handles [message.new](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onMessageNewHandler?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** Function to override the default behavior when a user gets removed from a channel, corresponds to [notification.removed\\_from\\_channel](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n  onRemovedFromChannel?: (\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    event: Event,\n  ) => void;\n  /** An object containing channel query options */\n  options?: ChannelOptions;\n  /** Custom UI component to handle channel pagination logic, defaults to and accepts same props as: [LoadMorePaginator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/LoadMore/LoadMorePaginator.tsx) */\n  Paginator?: React.ComponentType<PaginatorProps | LoadMorePaginatorProps>;\n  /**\n   * Custom interval during which the recovery channel list queries will be prevented.\n   * This is to avoid firing unnecessary queries during internet connection fluctuation.\n   * Recovery channel query is triggered upon `connection.recovered` and leads to complete channel list reload with pagination offset 0.\n   * The minimum throttle interval is 2000ms. The default throttle interval is 5000ms.\n   */\n  recoveryThrottleIntervalMs?: number;\n  /** Function to override the default behavior when rendering channels, so this function is called instead of rendering the Preview directly */\n  renderChannels?: (\n    channels: Channel[],\n    channelPreview: (item: Channel) => React.ReactNode,\n  ) => React.ReactNode;\n  /** If true, sends the list's currently loaded channels to the `List` component as the `loadedChannels` prop */\n  sendChannelsToList?: boolean;\n  /** Last channel will be set as active channel if true, defaults to true */\n  setActiveChannelOnMount?: boolean;\n  /** Whether or not to load the list with a search component, defaults to false */\n  showChannelSearch?: boolean;\n  /** An object containing channel query sort parameters */\n  sort?: ChannelSort;\n  /** An object containing query parameters for fetching channel watchers */\n  watchers?: { limit?: number; offset?: number };\n};\n\nconst UnMemoizedChannelList = (props: ChannelListProps) => {\n  const {\n    allowNewMessagesFromUnfilteredChannels = true,\n    channelRenderFilterFn,\n    customActiveChannel,\n    customQueryChannels,\n    EmptyStateIndicator = DefaultEmptyStateIndicator,\n    filters = {},\n    getLatestMessagePreview,\n    lockChannelOrder = false,\n    onAddedToChannel,\n    onChannelDeleted,\n    onChannelHidden,\n    onChannelTruncated,\n    onChannelUpdated,\n    onChannelVisible,\n    onMessageNew,\n    onMessageNewHandler,\n    onRemovedFromChannel,\n    options,\n    Paginator = LoadMorePaginator,\n    recoveryThrottleIntervalMs,\n    renderChannels,\n    sendChannelsToList = false,\n    setActiveChannelOnMount = true,\n    showChannelSearch = false,\n    sort = DEFAULT_SORT,\n    watchers = {},\n  } = props;\n\n  const stableId = useStableId();\n\n  const {\n    channel,\n    channelsQueryState,\n    client,\n    customClasses,\n    searchController,\n    setActiveChannel,\n    theme,\n    useImageFlagEmojisOnWindows,\n  } = useChatContext('ChannelList');\n  const {\n    ChannelListUI = DefaultChannelListUI,\n    NotificationList = DefaultNotificationList,\n    Search = DefaultSearch,\n  } = useComponentContext();\n\n  const channelListRef = useRef<HTMLDivElement | null>(null);\n  const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n  // Indicator relevant when Search component that relies on SearchController is used\n  const { searchIsActive } = useStateStore(\n    searchController.state,\n    searchControllerStateSelector,\n  );\n  /**\n   * Set a channel with id {customActiveChannel} as active and move it to the top of the list.\n   * If customActiveChannel prop is absent, then set the first channel in list as active channel.\n   */\n  const activeChannelHandler = async (\n    channels: Array<Channel>,\n    setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n    effectiveQueryParams: EffectiveQueryParams,\n  ) => {\n    if (!channels.length) {\n      return;\n    }\n\n    if (customActiveChannel) {\n      // FIXME: this is wrong...\n      let customActiveChannelObject = channels.find(\n        (chan) => chan.id === customActiveChannel,\n      );\n\n      if (!customActiveChannelObject) {\n        [customActiveChannelObject] = await client.queryChannels({\n          id: customActiveChannel,\n        });\n      }\n\n      if (customActiveChannelObject) {\n        setActiveChannel(customActiveChannelObject, watchers);\n\n        const newChannels = moveChannelUpwards({\n          channels,\n          channelToMove: customActiveChannelObject,\n          sort: effectiveQueryParams.sort,\n        });\n\n        setChannels(newChannels);\n        return;\n      }\n    }\n\n    if (setActiveChannelOnMount) {\n      setActiveChannel(channels[0], watchers);\n    }\n  };\n\n  /**\n   * For some events, inner properties on the channel will update but the shallow comparison will not\n   * force a re-render. Incrementing this dummy variable ensures the channel previews update.\n   */\n  const forceUpdate = useCallback(() => setChannelUpdateCount((count) => count + 1), []);\n\n  const {\n    channels,\n    effectiveFilters,\n    effectiveSort,\n    hasNextPage,\n    loadNextPage,\n    setChannels,\n  } = usePaginatedChannels(\n    client,\n    filters || DEFAULT_FILTERS,\n    sort || DEFAULT_SORT,\n    options || DEFAULT_OPTIONS,\n    activeChannelHandler,\n    recoveryThrottleIntervalMs,\n    customQueryChannels,\n  );\n\n  const loadedChannels = channelRenderFilterFn\n    ? channelRenderFilterFn(channels)\n    : channels;\n\n  const { customHandler, defaultHandler } = usePrepareShapeHandlers({\n    allowNewMessagesFromUnfilteredChannels,\n    // `effectiveFilters`/`effectiveSort` reflect the backend-resolved\n    // `predefined_filter` metadata when `options.predefined_filter` is in use.\n    // For non-predefined queries they fall back to the caller-supplied\n    // `filters`/`sort` props so behavior is unchanged.\n    filters: effectiveFilters,\n    lockChannelOrder,\n    onAddedToChannel,\n    onChannelDeleted,\n    onChannelHidden,\n    onChannelTruncated,\n    onChannelUpdated,\n    onChannelVisible,\n    onMessageNew,\n    onMessageNewHandler,\n    onRemovedFromChannel,\n    setChannels,\n    sort: effectiveSort,\n    // TODO: implement\n    // customHandleChannelListShape\n  });\n\n  useChannelListShape(customHandler ?? defaultHandler);\n\n  // TODO: maybe move this too\n  useConnectionRecoveredListener(forceUpdate);\n\n  useEffect(() => {\n    const handleEvent = (event: Event) => {\n      if (event.cid === channel?.cid) {\n        setActiveChannel();\n      }\n    };\n\n    client.on('channel.deleted', handleEvent);\n    client.on('channel.hidden', handleEvent);\n\n    return () => {\n      client.off('channel.deleted', handleEvent);\n      client.off('channel.hidden', handleEvent);\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [channel?.cid]);\n\n  const renderChannel = (item: Channel) => {\n    const previewProps = {\n      activeChannel: channel,\n      channel: item,\n      // forces the update of preview component on channel update\n      channelUpdateCount,\n      getLatestMessagePreview,\n      setActiveChannel,\n      watchers,\n    };\n\n    return <ChannelListItem key={item.cid} {...previewProps} />;\n  };\n\n  const baseClass = 'str-chat__channel-list';\n  const className = clsx(\n    customClasses?.chat ?? 'str-chat',\n    theme,\n    customClasses?.channelList ?? `${baseClass}`,\n    {\n      'str-chat--windows-flags':\n        useImageFlagEmojisOnWindows && navigator.userAgent.match(/Win/),\n    },\n  );\n\n  const showChannelList = !searchIsActive;\n  return (\n    <ChannelListContextProvider\n      value={{ channels, hasNextPage, loadNextPage, setChannels }}\n    >\n      <div className={className} ref={channelListRef}>\n        <DialogManagerProvider id={`channel-list-dialog-manager-${stableId}`}>\n          <ChannelListHeader />\n          {showChannelSearch && <Search />}\n          {showChannelList && (\n            <ChannelListUI\n              error={channelsQueryState.error}\n              loadedChannels={sendChannelsToList ? loadedChannels : undefined}\n              loading={\n                !!channelsQueryState.queryInProgress &&\n                ['reload', 'uninitialized'].includes(channelsQueryState.queryInProgress)\n              }\n              setChannels={setChannels}\n            >\n              {!loadedChannels?.length ? (\n                <EmptyStateIndicator listType='channel' />\n              ) : (\n                <Paginator\n                  hasNextPage={hasNextPage}\n                  isLoading={channelsQueryState.queryInProgress === 'load-more'}\n                  loadNextPage={loadNextPage}\n                >\n                  {renderChannels\n                    ? renderChannels(loadedChannels, renderChannel)\n                    : loadedChannels.map((channel) => renderChannel(channel))}\n                </Paginator>\n              )}\n            </ChannelListUI>\n          )}\n          <NotificationList panel='channel-list' />\n        </DialogManagerProvider>\n      </div>\n    </ChannelListContextProvider>\n  );\n};\n\n/**\n * Renders a preview list of Channels, allowing you to select the Channel you want to open\n */\nexport const ChannelList = React.memo(\n  UnMemoizedChannelList,\n) as typeof UnMemoizedChannelList;\n","import { useCallback } from 'react';\nimport { useSyncExternalStore } from 'use-sync-external-store/shim';\nimport type { Channel, EventTypes } from 'stream-chat';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst noop = () => {};\n\nexport function useSelectedChannelState<O>(_: {\n  channel: Channel;\n  selector: (channel: Channel) => O;\n  stateChangeEventKeys?: EventTypes[];\n}): O;\nexport function useSelectedChannelState<O>(_: {\n  selector: (channel: Channel) => O;\n  channel?: Channel | undefined;\n  stateChangeEventKeys?: EventTypes[];\n}): O | undefined;\nexport function useSelectedChannelState<O>({\n  channel,\n  selector,\n  stateChangeEventKeys = ['all'],\n}: {\n  selector: (channel: Channel) => O;\n  channel?: Channel;\n  stateChangeEventKeys?: EventTypes[];\n}): O | undefined {\n  const subscribe = useCallback(\n    (onStoreChange: (value: O) => void) => {\n      if (!channel) return noop;\n\n      const subscriptions = stateChangeEventKeys.map((et) =>\n        channel.on(et, () => {\n          onStoreChange(selector(channel));\n        }),\n      );\n\n      return () => subscriptions.forEach((subscription) => subscription.unsubscribe());\n    },\n    [channel, selector, stateChangeEventKeys],\n  );\n\n  const getSnapshot = useCallback(() => {\n    if (!channel) return undefined;\n\n    return selector(channel);\n  }, [channel, selector]);\n\n  return useSyncExternalStore(subscribe, getSnapshot);\n}\n","import type { Channel, ChannelMemberResponse, EventTypes } from 'stream-chat';\nimport { useSelectedChannelState } from './useSelectedChannelState';\n\nconst selector = (c: Channel) => c.state.membership;\nconst keys: EventTypes[] = ['member.updated'];\n\nexport function useChannelMembershipState(channel: Channel): ChannelMemberResponse;\nexport function useChannelMembershipState(\n  channel?: Channel | undefined,\n): ChannelMemberResponse | undefined;\nexport function useChannelMembershipState(channel?: Channel) {\n  return useSelectedChannelState({ channel, selector, stateChangeEventKeys: keys });\n}\n","import type { Channel, ChannelMemberResponse, EventTypes } from 'stream-chat';\nimport { useSelectedChannelState } from './useSelectedChannelState';\n\nconst selector = (c: Channel) => c.state.members;\nconst keys: EventTypes[] = [\n  'member.updated',\n  'member.added',\n  'member.removed',\n  'user.banned',\n  'user.unbanned',\n  'user.deleted',\n  'user.presence.changed',\n];\n\nexport function useChannelMembersState(\n  channel: Channel,\n): Record<string, ChannelMemberResponse>;\nexport function useChannelMembersState(\n  channel?: Channel | undefined,\n): Record<string, ChannelMemberResponse> | undefined;\nexport function useChannelMembersState(channel?: Channel) {\n  return useSelectedChannelState({ channel, selector, stateChangeEventKeys: keys });\n}\n","import { useEffect, useState } from 'react';\n\nimport { useChatContext } from '../../../context/ChatContext';\n\nimport type { Channel } from 'stream-chat';\n\nexport const useIsChannelMuted = (channel: Channel) => {\n  const { client } = useChatContext('useIsChannelMuted');\n\n  const [muted, setMuted] = useState(channel.muteStatus());\n\n  useEffect(() => {\n    const handleEvent = () => setMuted(channel.muteStatus());\n\n    client.on('notification.channel_mutes_updated', handleEvent);\n    return () => client.off('notification.channel_mutes_updated', handleEvent);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [muted]);\n\n  return muted;\n};\n","import {\n  type ComponentPropsWithoutRef,\n  type ComponentPropsWithRef,\n  forwardRef,\n  useMemo,\n  useState,\n} from 'react';\n\nimport { useChatContext, useTranslationContext } from '../../context';\nimport { useChannelMembershipState, useChannelMembersState } from '../ChannelList';\nimport { useChannelListItemContext } from './ChannelListItem';\nimport { Button } from '../Button';\nimport {\n  IconArchive,\n  IconLeave,\n  IconMore,\n  IconMute,\n  IconNoSign,\n  IconPin,\n} from '../Icons';\nimport { useIsChannelMuted } from './hooks/useIsChannelMuted';\nimport { ContextMenuButton, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';\nimport { useNotificationApi } from '../Notifications';\nimport { ChannelListItemActionButtons } from './ChannelListItemActionButtons';\n\nconst useMuteActionButtonBehavior = () => {\n  const { addNotification } = useNotificationApi();\n  const { channel } = useChannelListItemContext();\n  const { t } = useTranslationContext();\n  const { muted: isMuted } = useIsChannelMuted(channel);\n  const [inProgress, setInProgress] = useState(false);\n\n  return {\n    'aria-pressed': isMuted,\n    disabled: inProgress,\n    onClick: async (e: React.MouseEvent<HTMLButtonElement>) => {\n      e.stopPropagation();\n      try {\n        setInProgress(true);\n        if (isMuted) {\n          await channel.unmute();\n          addNotification({\n            context: {\n              channel,\n            },\n            emitter: ChannelListItemActionButtons.name,\n            message: t('Channel unmuted'),\n            severity: 'success',\n            type: 'api:channel:unmute:success',\n          });\n        } else {\n          await channel.mute();\n          addNotification({\n            context: {\n              channel,\n            },\n            emitter: ChannelListItemActionButtons.name,\n            message: t('Channel muted'),\n            severity: 'success',\n            type: 'api:channel:mute:success',\n          });\n        }\n      } catch (error) {\n        addNotification({\n          context: {\n            channel,\n          },\n          emitter: ChannelListItemActionButtons.name,\n          error: error instanceof Error ? error : new Error('An unknown error occurred'),\n          message: t('Failed to update channel mute status'),\n          severity: 'error',\n          type: 'api:channel:mute:failed',\n        });\n      } finally {\n        setInProgress(false);\n      }\n    },\n    title: isMuted ? t('Unmute') : t('Mute'),\n  } satisfies ComponentPropsWithoutRef<'button'>;\n};\n\nconst useArchiveActionButtonBehavior = () => {\n  const { channel } = useChannelListItemContext();\n  const { addNotification } = useNotificationApi();\n  const membership = useChannelMembershipState(channel);\n  const { t } = useTranslationContext();\n  const [inProgress, setInProgress] = useState(false);\n\n  return {\n    'aria-pressed': typeof membership.archived_at === 'string',\n    disabled: inProgress,\n    onClick: async (e: React.MouseEvent<HTMLButtonElement>) => {\n      e.stopPropagation();\n      try {\n        setInProgress(true);\n        if (membership.archived_at) {\n          await channel.unarchive();\n          addNotification({\n            context: {\n              channel,\n            },\n            emitter: ChannelListItemActionButtons.name,\n            message: t('Channel unarchived'),\n            severity: 'success',\n            type: 'api:channel:unarchive:success',\n          });\n        } else {\n          await channel.archive();\n          addNotification({\n            context: {\n              channel,\n            },\n            emitter: ChannelListItemActionButtons.name,\n            message: t('Channel archived'),\n            severity: 'success',\n            type: 'api:channel:archive:success',\n          });\n        }\n      } catch (error) {\n        addNotification({\n          context: {\n            channel,\n          },\n          emitter: ChannelListItemActionButtons.name,\n          error: error instanceof Error ? error : new Error('An unknown error occurred'),\n          message: t('Failed to update channel archive status'),\n          severity: 'error',\n          type: 'api:channel:archive:failed',\n        });\n      } finally {\n        setInProgress(false);\n      }\n    },\n    title: membership.archived_at ? t('Unarchive') : t('Archive'),\n  } satisfies ComponentPropsWithoutRef<'button'>;\n};\n\ntype ChannelActionItem =\n  | (({ placement: 'quick' } | { placement: 'dropdown' }) & {\n      type: string;\n      Component: React.ComponentType;\n    })\n  | {\n      placement: 'quick-dropdown-toggle';\n      Component: React.ComponentType<ComponentPropsWithRef<'button'>>;\n    };\n\nconst defaultComponents = {\n  dropdown: {\n    Archive() {\n      const behaviorProps = useArchiveActionButtonBehavior();\n\n      return (\n        <ContextMenuButton\n          aria-label={behaviorProps.title}\n          data-testid='dropdown-action-archive'\n          Icon={IconArchive}\n          {...behaviorProps}\n        >\n          {behaviorProps.title}\n        </ContextMenuButton>\n      );\n    },\n    Ban() {\n      const { client } = useChatContext();\n      const { addNotification } = useNotificationApi();\n      const { t } = useTranslationContext();\n      const { channel } = useChannelListItemContext();\n      const [inProgress, setInProgress] = useState(false);\n      const members = useChannelMembersState(channel);\n      const isUserBanned = Object.values(members || {}).some(\n        (member) => member.user?.id !== client.userID && member.banned,\n      );\n\n      const title = isUserBanned ? t('Unblock User') : t('Block User');\n\n      return (\n        <ContextMenuButton\n          aria-label={title}\n          data-testid='dropdown-action-ban'\n          disabled={inProgress}\n          Icon={IconNoSign}\n          onClick={async () => {\n            try {\n              setInProgress(true);\n              const otherUserId = Object.keys(channel.state.members).find(\n                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n                (userId) => userId !== client.userID!,\n              );\n\n              if (!otherUserId) return;\n\n              if (isUserBanned) {\n                await channel.unbanUser(otherUserId);\n                addNotification({\n                  context: {\n                    channel,\n                  },\n                  emitter: ChannelListItemActionButtons.name,\n                  message: t('User unblocked'),\n                  severity: 'success',\n                  type: 'api:user:unban:success',\n                });\n              } else {\n                await channel.banUser(otherUserId, {});\n                addNotification({\n                  context: {\n                    channel,\n                  },\n                  emitter: ChannelListItemActionButtons.name,\n                  message: t('User blocked'),\n                  severity: 'success',\n                  type: 'api:user:ban:success',\n                });\n              }\n            } catch (error) {\n              addNotification({\n                context: {\n                  channel,\n                },\n                emitter: ChannelListItemActionButtons.name,\n                error:\n                  error instanceof Error ? error : new Error('An unknown error occurred'),\n                message: t('Failed to block user'),\n                severity: 'error',\n                type: 'api:user:ban:failed',\n              });\n            } finally {\n              setInProgress(false);\n            }\n          }}\n        >\n          {title}\n        </ContextMenuButton>\n      );\n    },\n    Leave() {\n      const { t } = useTranslationContext();\n      const { channel } = useChannelListItemContext();\n      const { client } = useChatContext();\n      const { addNotification } = useNotificationApi();\n      const [inProgress, setInProgress] = useState(false);\n\n      const title = t('Leave Channel');\n\n      return (\n        <ContextMenuButton\n          aria-label={title}\n          data-testid='dropdown-action-leave'\n          disabled={inProgress}\n          Icon={IconLeave}\n          onClick={async (e) => {\n            e.stopPropagation();\n            try {\n              setInProgress(true);\n              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n              await channel.removeMembers([client.userID!]);\n              addNotification({\n                context: {\n                  channel,\n                },\n                emitter: ChannelListItemActionButtons.name,\n                message: t('Left channel'),\n                severity: 'success',\n                type: 'api:channel:leave:success',\n              });\n            } catch (error) {\n              addNotification({\n                context: {\n                  channel,\n                },\n                emitter: ChannelListItemActionButtons.name,\n                error:\n                  error instanceof Error ? error : new Error('An unknown error occurred'),\n                message: t('Failed to leave channel'),\n                severity: 'error',\n                type: 'api:channel:leave:failed',\n              });\n            } finally {\n              setInProgress(false);\n            }\n          }}\n          title={title}\n          variant='destructive'\n        >\n          {title}\n        </ContextMenuButton>\n      );\n    },\n    Mute() {\n      const behaviorProps = useMuteActionButtonBehavior();\n\n      return (\n        <ContextMenuButton\n          aria-label={behaviorProps.title}\n          data-testid='dropdown-action-mute'\n          Icon={IconMute}\n          {...behaviorProps}\n        >\n          {behaviorProps.title}\n        </ContextMenuButton>\n      );\n    },\n    Pin() {\n      const { t } = useTranslationContext();\n      const { addNotification } = useNotificationApi();\n      const { channel } = useChannelListItemContext();\n      const membership = useChannelMembershipState(channel);\n      const dialogId = ChannelListItemActionButtons.getDialogId(\n        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n        { channelId: channel.id! },\n      );\n      const { dialog } = useDialogOnNearestManager({ id: dialogId });\n      const [inProgress, setInProgress] = useState(false);\n\n      const title = membership.pinned_at ? t('Unpin') : t('Pin');\n\n      return (\n        <ContextMenuButton\n          aria-label={title}\n          data-testid='dropdown-action-pin'\n          disabled={inProgress}\n          Icon={IconPin}\n          onClick={async (e) => {\n            e.stopPropagation();\n            let error: Error | null = null;\n            try {\n              setInProgress(true);\n              if (membership.pinned_at) {\n                await channel.unpin();\n                addNotification({\n                  context: {\n                    channel,\n                  },\n                  emitter: ChannelListItemActionButtons.name,\n                  message: t('Channel unpinned'),\n                  severity: 'success',\n                  type: 'api:channel:unpin:success',\n                });\n              } else {\n                await channel.pin();\n                addNotification({\n                  context: {\n                    channel,\n                  },\n                  emitter: ChannelListItemActionButtons.name,\n                  message: t('Channel pinned'),\n                  severity: 'success',\n                  type: 'api:channel:pin:success',\n                });\n              }\n            } catch (e) {\n              error = e instanceof Error ? e : new Error('An unknown error occurred');\n              addNotification({\n                context: {\n                  channel,\n                },\n                emitter: ChannelListItemActionButtons.name,\n                error,\n                message: t('Failed to update channel pinned status'),\n                severity: 'error',\n                type: 'api:channel:pin:failed',\n              });\n            } finally {\n              if (!error) dialog?.close();\n              setInProgress(false);\n            }\n          }}\n          title={title}\n        >\n          {title}\n        </ContextMenuButton>\n      );\n    },\n  },\n  quick: {\n    Archive() {\n      const behaviorProps = useArchiveActionButtonBehavior();\n\n      return (\n        <Button\n          appearance='ghost'\n          aria-label={behaviorProps.title}\n          circular\n          data-testid='quick-action-archive'\n          size='sm'\n          variant='secondary'\n          {...behaviorProps}\n        >\n          <IconArchive />\n        </Button>\n      );\n    },\n    Mute() {\n      const behaviorProps = useMuteActionButtonBehavior();\n\n      return (\n        <Button\n          appearance='ghost'\n          aria-label={behaviorProps.title}\n          circular\n          data-testid='quick-action-mute'\n          size='sm'\n          variant='secondary'\n          {...behaviorProps}\n        >\n          <IconMute />\n        </Button>\n      );\n    },\n  },\n  QuickDropdownToggle: forwardRef<HTMLButtonElement>((_, ref) => {\n    const { channel } = useChannelListItemContext();\n    const { t } = useTranslationContext();\n\n    const dialogId = ChannelListItemActionButtons.getDialogId({\n      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n      channelId: channel.id!,\n    });\n    const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n    const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n    return (\n      <Button\n        appearance='ghost'\n        aria-expanded={dialogIsOpen}\n        aria-label={t('aria/Open Channel Actions Menu')}\n        aria-pressed={dialogIsOpen}\n        circular\n        data-testid='channel-list-item-dropdown-toggle'\n        onClick={(e) => {\n          e.stopPropagation();\n\n          dialog.toggle();\n        }}\n        ref={ref}\n        size='sm'\n        variant='secondary'\n      >\n        <IconMore />\n      </Button>\n    );\n  }),\n};\n\ndefaultComponents.QuickDropdownToggle.displayName = 'QuickDropdownToggle';\n\nexport const defaultChannelActionSet: ChannelActionItem[] = [\n  {\n    Component: defaultComponents.QuickDropdownToggle,\n    placement: 'quick-dropdown-toggle',\n  },\n  {\n    Component: defaultComponents.quick.Mute,\n    placement: 'quick',\n    type: 'mute',\n  },\n  {\n    Component: defaultComponents.dropdown.Archive,\n    placement: 'dropdown',\n    type: 'archive',\n  },\n  {\n    Component: defaultComponents.dropdown.Ban,\n    placement: 'dropdown',\n    type: 'ban',\n  },\n  {\n    Component: defaultComponents.dropdown.Pin,\n    placement: 'dropdown',\n    type: 'pin',\n  },\n  {\n    Component: defaultComponents.dropdown.Leave,\n    placement: 'dropdown',\n    type: 'leave',\n  },\n];\n\nexport const useBaseChannelActionSetFilter = (channelActionSet: ChannelActionItem[]) => {\n  const { channel } = useChannelListItemContext();\n  const membership = useChannelMembershipState(channel);\n  const memberCount = channel.data?.member_count ?? 0;\n  const connectedUserIsMember = typeof membership.user !== 'undefined';\n  const isDirectMessageChannel = connectedUserIsMember && memberCount === 2;\n\n  const ownCapabilities = channel.data?.own_capabilities;\n\n  return useMemo(() => {\n    const filtered = channelActionSet.filter((action) => {\n      if (action.placement === 'quick-dropdown-toggle') return true;\n\n      switch (action.type) {\n        case 'archive':\n          return connectedUserIsMember;\n        case 'mute':\n          return ownCapabilities?.includes('mute-channel');\n        case 'ban':\n          return (\n            isDirectMessageChannel && ownCapabilities?.includes('ban-channel-members')\n          );\n        case 'leave':\n          return ownCapabilities?.includes('leave-channel');\n        case 'pin':\n          return connectedUserIsMember;\n        default:\n          return true;\n      }\n    });\n\n    return filtered;\n  }, [channelActionSet, connectedUserIsMember, ownCapabilities, isDirectMessageChannel]);\n};\n","import React, { type ComponentProps, type ComponentType, type ReactNode } from 'react';\n\nimport clsx from 'clsx';\nimport { ContextMenu, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';\nimport { useComponentContext, useTranslationContext } from '../../context';\nimport {\n  defaultChannelActionSet,\n  useBaseChannelActionSetFilter,\n} from './ChannelListItemActionButtons.defaults';\nimport { useSplitActionSet } from '../Chat/hooks/useSplitActionSet';\nimport { useChannelListItemContext } from './ChannelListItem';\n\nexport type ChannelListItemActionButtonsProps = ComponentProps<ComponentType>; // hack to allow empty props\n\ninterface ChannelListItemActionButtonsInterface {\n  (props: ChannelListItemActionButtonsProps): ReactNode;\n  getDialogId: (_: { channelId: string }) => string;\n  displayName: string;\n}\n\nexport const ChannelListItemActionButtons: ChannelListItemActionButtonsInterface = () => {\n  const { ContextMenu: ContextMenuComponent = ContextMenu } = useComponentContext();\n  const { t } = useTranslationContext();\n  const { channel } = useChannelListItemContext();\n  const [referenceElement, setReferenceElement] =\n    React.useState<HTMLButtonElement | null>(null);\n  const [isRestoringFocus, setIsRestoringFocus] = React.useState(false);\n  const dialogId = ChannelListItemActionButtons.getDialogId({\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    channelId: channel.id!,\n  });\n  const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n  const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n  const closeContextMenu = React.useCallback(() => {\n    setIsRestoringFocus(true);\n    dialog?.close();\n\n    requestAnimationFrame(() => {\n      if (!referenceElement?.isConnected) {\n        setIsRestoringFocus(false);\n        return;\n      }\n\n      referenceElement.focus();\n\n      requestAnimationFrame(() => {\n        if (document.activeElement !== referenceElement) {\n          setIsRestoringFocus(false);\n        }\n      });\n    });\n  }, [dialog, referenceElement]);\n\n  const filteredActionSet = useBaseChannelActionSetFilter(defaultChannelActionSet);\n  const { dropdownActionSet, quickActionSet, quickDropdownToggleAction } =\n    useSplitActionSet(filteredActionSet);\n\n  if (quickActionSet.length + dropdownActionSet.length === 0) {\n    // no buttons to render, omit rendering wrapper\n    return null;\n  }\n\n  return (\n    <div\n      className={clsx('str-chat__channel-list-item__action-buttons', {\n        'str-chat__channel-list-item__action-buttons--active':\n          dialogIsOpen || isRestoringFocus,\n      })}\n      data-testid='channel-list-item-action-buttons'\n      onFocusCapture={() => {\n        setIsRestoringFocus(false);\n      }}\n    >\n      {quickDropdownToggleAction && dropdownActionSet.length > 0 && (\n        <quickDropdownToggleAction.Component ref={setReferenceElement} />\n      )}\n      {quickActionSet.map(({ Component, type }) => (\n        <Component key={type} />\n      ))}\n      <ContextMenuComponent\n        aria-label={t('aria/Channel Actions')}\n        className='str-chat__channel-list-item__action-buttons-context-menu'\n        data-testid='channel-list-item-context-menu'\n        dialogManagerId={dialogManager?.id}\n        id={dialog.id}\n        onClose={closeContextMenu}\n        placement='bottom-start'\n        referenceElement={referenceElement}\n        tabIndex={-1}\n        trapFocus\n      >\n        {dropdownActionSet.map(({ Component, type }) => (\n          <Component key={type} />\n        ))}\n      </ContextMenuComponent>\n    </div>\n  );\n};\n\nChannelListItemActionButtons.getDialogId = ({ channelId }) =>\n  `channel-action-buttons-${channelId}`;\n\nChannelListItemActionButtons.displayName = 'ChannelListItemActionButtons';\n","import React, { useMemo } from 'react';\nimport type { LocalMessage } from 'stream-chat';\n\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { getDateString, isDate } from '../../i18n/utils';\n\nexport type ChannelListItemTimestampProps = {\n  /** The last message in the channel, used to extract the timestamp */\n  lastMessage?: LocalMessage;\n};\n\nexport function ChannelListItemTimestamp({ lastMessage }: ChannelListItemTimestampProps) {\n  const { t, tDateTimeParser } = useTranslationContext('ChannelListItemTimestamp');\n\n  const timestamp = lastMessage?.created_at;\n  const normalizedTimestamp =\n    timestamp && isDate(timestamp) ? timestamp.toISOString() : undefined;\n\n  const when = useMemo(\n    () =>\n      getDateString({\n        messageCreatedAt: normalizedTimestamp,\n        t,\n        tDateTimeParser,\n        timestampTranslationKey: 'timestamp/ChannelPreviewTimestamp',\n      }),\n    [normalizedTimestamp, t, tDateTimeParser],\n  );\n\n  if (!when) return null;\n\n  return (\n    <time\n      className='str-chat__channel-list-item-timestamp'\n      dateTime={normalizedTimestamp}\n    >\n      {when}\n    </time>\n  );\n}\n","import { useMemo } from 'react';\nimport type { Attachment, LocalMessage } from 'stream-chat';\nimport {\n  isAudioAttachment,\n  isFileAttachment,\n  isImageAttachment,\n  isScrapedContent,\n  isVideoAttachment,\n  isVoiceRecordingAttachment,\n} from 'stream-chat';\n\nimport {\n  getTranslatedMessageText,\n  type TranslationContextValue,\n  useChatContext,\n  useTranslationContext,\n} from '../../../context';\nimport { isMessageDeleted } from '../../Message/utils';\n\nimport type { MessageDeliveryStatus } from '../../ChannelListItem';\n\nexport type ChannelPreviewMessageType =\n  | 'text'\n  | 'deleted'\n  | 'error'\n  | 'empty'\n  | 'image'\n  | 'giphy'\n  | 'video'\n  | 'voice'\n  | 'file'\n  | 'unsupported'\n  | 'link'\n  | 'location'\n  | 'poll';\n\nconst SUPPORTED_VIDEO_FORMATS: string[] = [\n  'video/mp4',\n  'video/ogg',\n  'video/webm',\n  'video/quicktime',\n];\n\n/**\n * Delivery status of the last own message.\n * Determines which delivery status icon to render in the preview.\n *\n * - `sending` — Clock icon\n * - `sent` — Single checkmark icon\n * - `delivered` — Double checkmark icon\n * - `read` — Double checkmark icon (with distinct color)\n */\nexport type ChannelPreviewDeliveryStatus = 'sending' | 'sent' | 'delivered' | 'read';\n\nexport type LatestMessagePreviewData = {\n  /**\n   * The type of content being previewed.\n   * Use this to render the appropriate content-type icon.\n   */\n  type: ChannelPreviewMessageType;\n  /**\n   * The preview text to display.\n   */\n  text: string;\n  /**\n   * Delivery status of own message.\n   * Only present for own messages that are not in error state.\n   * Use this to render the delivery status icon (clock, checkmark, double checkmark).\n   */\n  deliveryStatus?: ChannelPreviewDeliveryStatus;\n  /**\n   * Sender name prefix.\n   * - `\"You\"` (translated) for own messages\n   * - Sender's display name for incoming messages in group channels (>2 members)\n   * - `undefined` for incoming messages in direct conversations\n   */\n  senderName?: string;\n};\n\nfunction getAttachmentContentType(attachment: Attachment): ChannelPreviewMessageType {\n  if (!attachment) return 'text';\n\n  if (attachment.type === 'giphy') return 'giphy';\n  if (isScrapedContent(attachment)) return 'link';\n  if (isImageAttachment(attachment)) return 'image';\n  if (isVideoAttachment(attachment, SUPPORTED_VIDEO_FORMATS)) return 'video';\n  if (isVoiceRecordingAttachment(attachment)) return 'voice';\n  if (\n    isAudioAttachment(attachment) ||\n    isFileAttachment(attachment, SUPPORTED_VIDEO_FORMATS)\n  ) {\n    return 'file';\n  }\n\n  return 'unsupported';\n}\n\nfunction getAttachmentFallbackText(\n  type: ChannelPreviewMessageType,\n  count: number,\n  t: TranslationContextValue['t'],\n): string {\n  switch (type) {\n    case 'image':\n      return t('imageCount', { count });\n    case 'video':\n      return t('videoCount', { count });\n    case 'voice':\n      return t('voiceMessageCount', { count });\n    case 'link':\n      return t('linkCount', { count });\n    case 'file':\n      return t('fileCount', { count });\n    case 'unsupported':\n      return t('Unsupported attachment');\n    default:\n      return t('fileCount', { count });\n  }\n}\n\nexport type UseLatestMessagePreviewParams = {\n  /** The channel to generate preview for */\n  participantCount?: number;\n  /** The latest message in the channel */\n  latestMessage?: LocalMessage;\n  /**\n   * Delivery status from the `useMessageDeliveryStatus` hook.\n   * When provided, used to determine the delivery status icon.\n   * When omitted, delivery status icons are not shown.\n   */\n  messageDeliveryStatus?: MessageDeliveryStatus;\n};\n\nexport const useLatestMessagePreview = ({\n  latestMessage,\n  messageDeliveryStatus,\n  participantCount,\n}: UseLatestMessagePreviewParams): LatestMessagePreviewData => {\n  const { client } = useChatContext('useLatestMessagePreview');\n  const { t, userLanguage } = useTranslationContext('useLatestMessagePreview');\n\n  return useMemo(() => {\n    if (!latestMessage) {\n      return { text: t('Nothing yet...'), type: 'empty' as const };\n    }\n\n    if (latestMessage.status === 'failed' || latestMessage.type === 'error') {\n      return { text: t('Message failed to send'), type: 'error' as const };\n    }\n\n    const isOwnMessage = latestMessage.user?.id === client.user?.id;\n\n    let deliveryStatus: ChannelPreviewDeliveryStatus | undefined;\n    if (isOwnMessage) {\n      deliveryStatus = messageDeliveryStatus ?? (latestMessage.status as 'sending');\n    }\n\n    let senderName: string | undefined;\n    if (isOwnMessage) {\n      senderName = t('You');\n    } else if (!isOwnMessage && participantCount !== undefined && participantCount > 2) {\n      senderName = latestMessage.user?.name || latestMessage.user?.id;\n    }\n\n    if (isMessageDeleted(latestMessage)) {\n      return {\n        deliveryStatus,\n        senderName,\n        text: t('Message deleted'),\n        type: 'deleted' as const,\n      };\n    }\n\n    if (latestMessage.poll) {\n      return {\n        deliveryStatus,\n        senderName,\n        text: t('Poll'),\n        type: 'poll' as const,\n      };\n    }\n\n    const textContent =\n      getTranslatedMessageText({ language: userLanguage, message: latestMessage }) ||\n      latestMessage.text;\n\n    if (latestMessage.shared_location) {\n      return {\n        deliveryStatus,\n        senderName,\n        text: textContent || t('Location'),\n        type: 'location' as const,\n      };\n    }\n\n    if (latestMessage.attachments && latestMessage.attachments.length) {\n      const attachments = latestMessage.attachments;\n\n      let contentType: ChannelPreviewMessageType;\n\n      const [firstAttachment] = attachments;\n      const firstAttachmentType = getAttachmentContentType(firstAttachment);\n\n      if (\n        attachments.every(\n          (attachment) => getAttachmentContentType(attachment) === firstAttachmentType,\n        )\n      ) {\n        contentType = firstAttachmentType;\n      } else {\n        contentType = 'file';\n      }\n\n      let text =\n        contentType === 'giphy'\n          ? `GIPHY ${firstAttachment.title ?? ''}`.trim()\n          : // prioritize message text content if available\n            textContent ||\n            // then fallback text of the single attachment if only one attachment is present and it's not a voice recording (fallback text is generic for voice recordings, so not useful in the preview)\n            (attachments.length === 1 &&\n            contentType !== 'voice' &&\n            contentType !== 'unsupported'\n              ? firstAttachment.fallback || firstAttachment.title\n              : '') ||\n            // then generic fallback text based on attachment type and count\n            getAttachmentFallbackText(contentType, attachments.length, t);\n\n      // attach duration for audio/video attachments if available\n      if (attachments.length === 1 && typeof firstAttachment.duration === 'number') {\n        const minutes = Math.floor(firstAttachment.duration / 60);\n        const seconds = Math.ceil(firstAttachment.duration) % 60;\n        const durationString = `${minutes}:${seconds.toString().padStart(2, '0')}`;\n        text += ` (${durationString})`;\n      }\n\n      return {\n        deliveryStatus,\n        senderName,\n        text,\n        type: contentType,\n      };\n    }\n\n    if (textContent) {\n      return {\n        deliveryStatus,\n        senderName,\n        text: textContent,\n        type: 'text' as const,\n      };\n    }\n\n    return { text: t('Empty message...'), type: 'empty' as const };\n  }, [\n    client.user?.id,\n    latestMessage,\n    messageDeliveryStatus,\n    participantCount,\n    t,\n    userLanguage,\n  ]);\n};\n","import React from 'react';\nimport clsx from 'clsx';\nimport {\n  type ChannelPreviewDeliveryStatus,\n  type ChannelPreviewMessageType,\n  useLatestMessagePreview,\n  type UseLatestMessagePreviewParams,\n} from './hooks/useLatestMessagePreview';\nimport {\n  IconCamera,\n  IconCheckmark1Small,\n  IconChecks,\n  IconClock,\n  IconExclamationCircleFill,\n  IconFile,\n  IconGiphy,\n  IconLink,\n  IconLocation,\n  IconNoSign,\n  IconUnsupportedAttachment,\n  IconVideo,\n  IconVoice,\n} from '../Icons';\n\nconst deliveryStatusIconMap: Record<ChannelPreviewDeliveryStatus, React.ComponentType> = {\n  delivered: IconChecks,\n  read: IconChecks,\n  sending: IconClock,\n  sent: IconCheckmark1Small,\n};\n\nconst contentTypeIconMap: Partial<\n  Record<ChannelPreviewMessageType, React.ComponentType>\n> = {\n  deleted: IconNoSign,\n  error: IconExclamationCircleFill,\n  file: IconFile,\n  giphy: IconGiphy,\n  image: IconCamera,\n  link: IconLink,\n  location: IconLocation,\n  unsupported: IconUnsupportedAttachment,\n  video: IconVideo,\n  voice: IconVoice,\n};\n\nexport const SummarizedMessagePreview = ({\n  latestMessage,\n  messageDeliveryStatus,\n  participantCount,\n}: UseLatestMessagePreviewParams) => {\n  const { deliveryStatus, senderName, text, type } = useLatestMessagePreview({\n    latestMessage,\n    messageDeliveryStatus,\n    participantCount,\n  });\n\n  const DeliveryStatusIcon = deliveryStatus\n    ? deliveryStatusIconMap[deliveryStatus]\n    : undefined;\n  const ContentTypeIcon = contentTypeIconMap[type];\n\n  return (\n    <div\n      className={clsx('str-chat__summarized-message-preview', {\n        [`str-chat__summarized-message-preview--${type}`]: type,\n      })}\n    >\n      {type !== 'error' && (\n        <>\n          {DeliveryStatusIcon && (\n            <span\n              className={clsx('str-chat__summarized-message-preview__delivery-status', {\n                [`str-chat__summarized-message-preview__delivery-status--${deliveryStatus}`]:\n                  deliveryStatus,\n              })}\n            >\n              <DeliveryStatusIcon />\n            </span>\n          )}\n          {senderName && (\n            <span className='str-chat__summarized-message-preview__sender'>\n              {senderName}:\n            </span>\n          )}\n        </>\n      )}\n      {ContentTypeIcon && <ContentTypeIcon />}\n      <span className='str-chat__summarized-message-preview__text'>{text}</span>\n    </div>\n  );\n};\n","import React, { useRef } from 'react';\nimport clsx from 'clsx';\n\nimport { ChannelListItemActionButtons as DefaultChannelListItemActionButtons } from './ChannelListItemActionButtons';\nimport { ChannelListItemTimestamp } from './ChannelListItemTimestamp';\n\nimport { ChannelAvatar as DefaultChannelAvatar } from '../Avatar';\nimport { Badge } from '../Badge';\nimport { IconMute, IconPin } from '../Icons';\nimport { useComponentContext, useTranslationContext } from '../../context';\nimport type { ChannelListItemUIProps } from './ChannelListItem';\nimport { SummarizedMessagePreview } from '../SummarizedMessagePreview';\n\nconst UnMemoizedChannelListItemUI = (props: ChannelListItemUIProps) => {\n  const {\n    active,\n    channel,\n    className: customClassName = '',\n    displayImage,\n    displayTitle,\n    groupChannelDisplayInfo,\n    lastMessage,\n    messageDeliveryStatus,\n    muted,\n    onSelect: customOnSelectChannel,\n    pinned,\n    setActiveChannel,\n    unread,\n    watchers,\n  } = props;\n\n  const {\n    Avatar = DefaultChannelAvatar,\n    ChannelListItemActionButtons = DefaultChannelListItemActionButtons,\n  } = useComponentContext();\n  const { t } = useTranslationContext();\n\n  const channelPreviewButton = useRef<HTMLButtonElement | null>(null);\n\n  const avatarName =\n    displayTitle || channel.state.messages[channel.state.messages.length - 1]?.user?.id;\n\n  const onSelectChannel = (e: React.MouseEvent<HTMLButtonElement>) => {\n    if (customOnSelectChannel) {\n      customOnSelectChannel(e);\n    } else if (setActiveChannel) {\n      setActiveChannel(channel, watchers);\n    }\n    if (channelPreviewButton?.current) {\n      channelPreviewButton.current.blur();\n    }\n  };\n\n  return (\n    <div className='str-chat__channel-list-item-container'>\n      <button\n        aria-label={t('aria/Select Channel: {{ channelName }}', {\n          channelName: displayTitle || '',\n        })}\n        aria-selected={active}\n        className={clsx(\n          'str-chat__channel-list-item',\n          {\n            'str-chat__channel-list-item--muted': muted,\n            'str-chat__channel-list-item--pinned': pinned,\n            'str-chat__channel-list-item--unread':\n              typeof unread === 'number' && unread > 0,\n          },\n          customClassName,\n        )}\n        data-testid='channel-list-item-button'\n        onClick={onSelectChannel}\n        ref={channelPreviewButton}\n        role='option'\n      >\n        <Avatar\n          displayMembers={groupChannelDisplayInfo?.members}\n          imageUrl={displayImage}\n          size='xl'\n          userName={avatarName}\n        />\n        <div className='str-chat__channel-list-item-data'>\n          <div className='str-chat__channel-list-item-data__first-row'>\n            <div className='str-chat__channel-list-item-data__title'>\n              <span>{displayTitle || 'N/A'}</span>\n              {pinned && <IconPin />}\n              {muted && <IconMute />}\n            </div>\n            <div className='str-chat__channel-list-item-data__timestamp-and-badge'>\n              <ChannelListItemTimestamp lastMessage={lastMessage} />\n              {typeof unread === 'number' && unread > 0 && (\n                <Badge data-testid='unread-badge' size='md' variant='primary'>\n                  {unread}\n                </Badge>\n              )}\n            </div>\n          </div>\n          <SummarizedMessagePreview\n            latestMessage={lastMessage}\n            messageDeliveryStatus={messageDeliveryStatus}\n            participantCount={channel.data?.member_count}\n          />\n        </div>\n      </button>\n      <ChannelListItemActionButtons />\n    </div>\n  );\n};\n\n/**\n * Used as preview component for channel item in [ChannelList](#channellist) component.\n * Its best suited for messenger type chat.\n */\nexport const ChannelListItemUI = React.memo(\n  UnMemoizedChannelListItemUI,\n) as typeof UnMemoizedChannelListItemUI;\n","import { useCallback, useEffect, useState } from 'react';\nimport type { Channel, Event, LocalMessage, UserResponse } from 'stream-chat';\n\nimport { useChatContext } from '../../../context';\n\nexport enum MessageDeliveryStatus {\n  SENT = 'sent',\n  DELIVERED = 'delivered',\n  READ = 'read',\n}\n\ntype UseMessageStatusParamsChannelPreviewProps = {\n  channel: Channel;\n  /** The last message received in a channel */\n  lastMessage?: LocalMessage;\n};\n\nexport const useMessageDeliveryStatus = ({\n  channel,\n  lastMessage,\n}: UseMessageStatusParamsChannelPreviewProps) => {\n  const { client } = useChatContext();\n  const [messageDeliveryStatus, setMessageDeliveryStatus] = useState<\n    MessageDeliveryStatus | undefined\n  >();\n\n  const isOwnMessage = useCallback(\n    (message?: { user?: UserResponse | null }) =>\n      client.user && message && message.user?.id === client.user.id,\n    [client],\n  );\n\n  useEffect(() => {\n    // empty channel\n    if (!lastMessage) {\n      setMessageDeliveryStatus(undefined);\n    }\n\n    const lastMessageIsOwn = isOwnMessage(lastMessage);\n    if (!lastMessage?.created_at || !lastMessageIsOwn) return;\n\n    const msgRef = {\n      msgId: lastMessage.id,\n      timestampMs: lastMessage.created_at.getTime(),\n    };\n    const readersForMessage = channel.messageReceiptsTracker.readersForMessage(msgRef);\n    const deliveredForMessage =\n      channel.messageReceiptsTracker.deliveredForMessage(msgRef);\n    setMessageDeliveryStatus(\n      readersForMessage.length > 1 ||\n        (readersForMessage.length === 1 && readersForMessage[0].id !== client.user?.id)\n        ? MessageDeliveryStatus.READ\n        : deliveredForMessage.length > 1 ||\n            (deliveredForMessage.length === 1 &&\n              deliveredForMessage[0].id !== client.user?.id)\n          ? MessageDeliveryStatus.DELIVERED\n          : MessageDeliveryStatus.SENT,\n    );\n  }, [channel, client, isOwnMessage, lastMessage]);\n\n  useEffect(() => {\n    const handleMessageNew = (event: Event) => {\n      // the last message is not mine, so do not show the delivery status\n      if (!isOwnMessage(event.message)) {\n        return setMessageDeliveryStatus(undefined);\n      }\n      return setMessageDeliveryStatus(MessageDeliveryStatus.SENT);\n    };\n\n    channel.on('message.new', handleMessageNew);\n\n    return () => {\n      channel.off('message.new', handleMessageNew);\n    };\n  }, [channel, isOwnMessage]);\n\n  useEffect(() => {\n    if (!isOwnMessage(lastMessage)) return;\n    const handleMessageDelivered = (event: Event) => {\n      if (\n        event.user?.id !== client.user?.id &&\n        lastMessage &&\n        lastMessage.id === event.last_delivered_message_id\n      )\n        setMessageDeliveryStatus(MessageDeliveryStatus.DELIVERED);\n    };\n\n    const handleMarkRead = (event: Event) => {\n      if (event.user?.id !== client.user?.id)\n        setMessageDeliveryStatus(MessageDeliveryStatus.READ);\n    };\n\n    channel.on('message.delivered', handleMessageDelivered);\n    channel.on('message.read', handleMarkRead);\n\n    return () => {\n      channel.off('message.delivered', handleMessageDelivered);\n      channel.off('message.read', handleMarkRead);\n    };\n  }, [channel, client, isOwnMessage, lastMessage]);\n\n  return {\n    messageDeliveryStatus,\n  };\n};\n","import throttle from 'lodash.throttle';\nimport React, { useContext, useEffect, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport type { Channel, Event, LocalMessage } from 'stream-chat';\n\nimport { ChannelListItemUI as DefaultChannelListItemUI } from './ChannelListItemUI';\nimport { useIsChannelMuted } from './hooks/useIsChannelMuted';\nimport { useChannelPreviewInfo } from './hooks/useChannelPreviewInfo';\nimport { getLatestMessagePreview as defaultGetLatestMessagePreview } from './utils';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useMessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';\nimport type { MessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';\nimport type { GroupChannelDisplayInfo } from './utils';\nimport {\n  type ChatContextValue,\n  type TranslationContextValue,\n  useChatContext,\n  useComponentContext,\n} from '../../context';\nimport { useChannelMembershipState } from '../ChannelList';\n\nexport type ChannelListItemUIProps = ChannelListItemProps & {\n  /** Image of Channel to display */\n  displayImage?: string;\n  /** Title of Channel to display */\n  displayTitle?: string;\n  /** Title of Channel to display */\n  groupChannelDisplayInfo?: GroupChannelDisplayInfo;\n  /** The last message received in a channel */\n  lastMessage?: LocalMessage;\n  /** Latest message preview to display, will be a string or JSX element supporting markdown. */\n  latestMessagePreview?: ReactNode;\n  /** Status describing whether own message has been delivered or read by another. If the last message is not an own message, then the status is undefined. */\n  messageDeliveryStatus?: MessageDeliveryStatus;\n  /** Whether the channel is muted by the current user */\n  muted?: boolean;\n  /** Whether the channel is pinned by the current user */\n  pinned?: boolean;\n  /** Number of unread Messages */\n  unread?: number;\n};\n\nexport type ChannelListItemProps = {\n  /** Comes from either the `channelRenderFilterFn` or `usePaginatedChannels` call from [ChannelList](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelList/ChannelList.tsx) */\n  channel: Channel;\n  /** If the component's channel is the active (selected) Channel */\n  active?: boolean;\n  /** Current selected channel object */\n  activeChannel?: Channel;\n  /** Forces the update of preview component on channel update */\n  channelUpdateCount?: number;\n  /** Custom class for the channel preview root */\n  className?: string;\n  /** Custom function that generates the message preview in ChannelListItem component */\n  getLatestMessagePreview?: (\n    channel: Channel,\n    t: TranslationContextValue['t'],\n    userLanguage: TranslationContextValue['userLanguage'],\n    isMessageAIGenerated: ChatContextValue['isMessageAIGenerated'],\n  ) => ReactNode;\n  key?: string;\n  /** Custom ChannelListItem click handler function */\n  onSelect?: (event: React.MouseEvent) => void;\n  /** Setter for selected Channel */\n  setActiveChannel?: ChatContextValue['setActiveChannel'];\n  /** Object containing watcher parameters */\n  watchers?: { limit?: number; offset?: number };\n};\n\nconst ChannelListItemContext = React.createContext<{ channel: Channel }>({\n  channel: null as unknown as Channel,\n});\n\nexport const useChannelListItemContext = () => useContext(ChannelListItemContext);\n\nexport const ChannelListItem = (props: ChannelListItemProps) => {\n  const {\n    active,\n    channel,\n    channelUpdateCount,\n    getLatestMessagePreview = defaultGetLatestMessagePreview,\n  } = props;\n  const { ChannelListItemUI = DefaultChannelListItemUI } = useComponentContext();\n  const {\n    channel: activeChannel,\n    client,\n    isMessageAIGenerated,\n    setActiveChannel,\n  } = useChatContext('ChannelPreview');\n  const { t, userLanguage } = useTranslationContext('ChannelPreview');\n  const { displayImage, displayTitle, groupChannelDisplayInfo } = useChannelPreviewInfo({\n    channel,\n  });\n  const membership = useChannelMembershipState(channel);\n\n  const [lastMessage, setLastMessage] = useState<LocalMessage>(\n    channel.state.messages[channel.state.messages.length - 1],\n  );\n  const [latestMessagePreview, setLatestMessagePreview] = useState<ReactNode>(() =>\n    getLatestMessagePreview(channel, t, userLanguage, isMessageAIGenerated),\n  );\n\n  const [unread, setUnread] = useState(0);\n  const { messageDeliveryStatus } = useMessageDeliveryStatus({\n    channel,\n    lastMessage,\n  });\n\n  const isActive =\n    typeof active === 'undefined' ? activeChannel?.cid === channel.cid : active;\n  const { muted } = useIsChannelMuted(channel);\n\n  useEffect(() => {\n    const handleEvent = (event: Event) => {\n      if (!event.cid) return setUnread(0);\n      if (channel.cid === event.cid) setUnread(0);\n    };\n\n    client.on('notification.mark_read', handleEvent);\n    return () => client.off('notification.mark_read', handleEvent);\n  }, [channel, client]);\n\n  useEffect(() => {\n    const handleEvent = (event: Event) => {\n      if (channel.cid !== event.cid) return;\n      if (event.user?.id !== client.user?.id) return;\n      setUnread(channel.countUnread());\n    };\n    channel.on('notification.mark_unread', handleEvent);\n    return () => {\n      channel.off('notification.mark_unread', handleEvent);\n    };\n  }, [channel, client]);\n\n  const refreshUnreadCount = useMemo(\n    () =>\n      throttle(() => {\n        if (muted) {\n          setUnread(0);\n        } else {\n          setUnread(channel.countUnread());\n        }\n      }, 400),\n    [channel, muted],\n  );\n\n  useEffect(() => {\n    refreshUnreadCount();\n    setLatestMessagePreview(\n      getLatestMessagePreview(channel, t, userLanguage, isMessageAIGenerated),\n    );\n\n    const handleEvent = (event: Event) => {\n      const deletedMessagesInAnotherChannel =\n        event.type === 'user.messages.deleted' && event.cid && event.cid !== channel.cid;\n\n      if (deletedMessagesInAnotherChannel) return;\n\n      setLastMessage(\n        channel.state.latestMessages[channel.state.latestMessages.length - 1],\n      );\n      setLatestMessagePreview(\n        getLatestMessagePreview(channel, t, userLanguage, isMessageAIGenerated),\n      );\n      refreshUnreadCount();\n    };\n\n    channel.on('message.new', handleEvent);\n    channel.on('message.updated', handleEvent);\n    channel.on('message.deleted', handleEvent);\n    client.on('user.messages.deleted', handleEvent);\n    channel.on('message.undeleted', handleEvent);\n    channel.on('channel.truncated', handleEvent);\n\n    return () => {\n      channel.off('message.new', handleEvent);\n      channel.off('message.updated', handleEvent);\n      channel.off('message.deleted', handleEvent);\n      client.off('user.messages.deleted', handleEvent);\n      channel.off('message.undeleted', handleEvent);\n      channel.off('channel.truncated', handleEvent);\n    };\n  }, [\n    channel,\n    client,\n    refreshUnreadCount,\n    channelUpdateCount,\n    getLatestMessagePreview,\n    t,\n    userLanguage,\n    isMessageAIGenerated,\n  ]);\n\n  const channelPreviewContextValue = useMemo(() => ({ channel }), [channel]);\n\n  if (!ChannelListItemUI) return null;\n\n  return (\n    <ChannelListItemContext.Provider value={channelPreviewContextValue}>\n      <ChannelListItemUI\n        {...props}\n        active={isActive}\n        displayImage={displayImage}\n        displayTitle={displayTitle}\n        groupChannelDisplayInfo={groupChannelDisplayInfo}\n        lastMessage={lastMessage}\n        latestMessagePreview={latestMessagePreview}\n        messageDeliveryStatus={messageDeliveryStatus}\n        muted={muted}\n        pinned={!!membership.pinned_at}\n        setActiveChannel={setActiveChannel}\n        unread={unread}\n      />\n    </ChannelListItemContext.Provider>\n  );\n};\n","import React, { useCallback, useEffect, useMemo } from 'react';\nimport clsx from 'clsx';\n\nimport type { ThreadState } from 'stream-chat';\nimport type { ComponentPropsWithoutRef } from 'react';\n\nimport { Timestamp } from '../../Message/Timestamp';\nimport { Avatar, type AvatarProps, AvatarStack } from '../../Avatar';\nimport { useChannelPreviewInfo } from '../../ChannelListItem';\nimport { useChatContext, useTranslationContext } from '../../../context';\nimport { useThreadsViewContext } from '../../ChatView';\nimport { useThreadListItemContext } from './ThreadListItem';\nimport { useStateStore } from '../../../store';\nimport { Badge } from '../../Badge';\nimport { SummarizedMessagePreview } from '../../SummarizedMessagePreview';\n\nexport type ThreadListItemUIProps = ComponentPropsWithoutRef<'button'> & {\n  resetHighlighting?: () => void;\n};\n\nexport const ThreadListItemUI = ({\n  resetHighlighting,\n  ...props\n}: ThreadListItemUIProps) => {\n  const { client } = useChatContext();\n  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n  const thread = useThreadListItemContext()!;\n\n  const selector = useCallback(\n    (nextValue: ThreadState) => ({\n      channel: nextValue.channel,\n      deletedAt: nextValue.deletedAt,\n      latestReply: nextValue.replies.at(-1),\n      ownUnreadMessageCount:\n        (client.userID && nextValue.read[client.userID]?.unreadMessageCount) || 0,\n      parentMessage: nextValue.parentMessage,\n      participants: nextValue.participants,\n      replyCount: nextValue.replyCount,\n    }),\n    [client],\n  );\n\n  const {\n    channel,\n    deletedAt,\n    latestReply,\n    ownUnreadMessageCount,\n    parentMessage,\n    participants,\n    replyCount,\n  } = useStateStore(thread.state, selector);\n\n  const { displayTitle: channelDisplayTitle } = useChannelPreviewInfo({ channel });\n  const { t } = useTranslationContext('ThreadListItemUI');\n\n  const { activeThread, setActiveThread } = useThreadsViewContext();\n\n  const avatarProps: Partial<AvatarProps> | undefined = deletedAt\n    ? undefined\n    : ({\n        imageUrl: latestReply?.user?.image,\n        userName: latestReply?.user?.name || latestReply?.user?.id,\n      } as const);\n\n  const displayInfo = useMemo(() => {\n    if (!participants) return [];\n\n    return participants.slice(0, 3).map((participant) => ({\n      id: participant.user?.id ?? undefined,\n      imageUrl: participant.user?.image,\n      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n      userName: participant.user?.name || participant.user!.id,\n    }));\n  }, [participants]);\n\n  useEffect(() => {\n    if (!resetHighlighting) return;\n\n    const reset = resetHighlighting;\n\n    const timeout = setTimeout(() => {\n      reset();\n    }, 2000);\n\n    return () => clearTimeout(timeout);\n  }, [resetHighlighting]);\n\n  return (\n    <div className='str-chat__thread-list-item-container'>\n      <button\n        aria-selected={activeThread === thread}\n        className={clsx('str-chat__thread-list-item', {\n          'str-chat__thread-list-item--highlighted':\n            typeof resetHighlighting !== 'undefined',\n        })}\n        data-thread-id={thread.id}\n        onClick={() => setActiveThread(thread)}\n        role='option'\n        {...props}\n      >\n        <Avatar size='xl' {...avatarProps} />\n        <div className='str-chat__thread-list-item__content'>\n          <div className='str-chat__thread-list-item__content-leading'>\n            <span className='str-chat__thread-list-item__title'>\n              {channelDisplayTitle}\n            </span>\n            <SummarizedMessagePreview\n              latestMessage={parentMessage}\n              participantCount={participants?.length}\n            />\n          </div>\n          <div className='str-chat__thread-list-item__content-trailing'>\n            <div className='str-chat__thread-list-item__reply-information'>\n              <AvatarStack displayInfo={displayInfo} size='sm' />\n              <span className='str-chat__thread-list-item__reply-count'>\n                {t('replyCount', { count: replyCount })}\n              </span>\n            </div>\n            <Timestamp\n              customClass='str-chat__thread-list-item__timestamp'\n              timestamp={latestReply?.created_at}\n            />\n          </div>\n        </div>\n        {ownUnreadMessageCount > 0 && (\n          <Badge size='md' variant='primary'>\n            {ownUnreadMessageCount}\n          </Badge>\n        )}\n      </button>\n    </div>\n  );\n};\n","import React, { createContext, useContext } from 'react';\n\nimport type { Thread } from 'stream-chat';\n\nimport { useComponentContext } from '../../../context';\nimport { ThreadListItemUI as DefaultThreadListItemUI } from './ThreadListItemUI';\n\nimport type { ThreadListItemUIProps } from './ThreadListItemUI';\n\nexport type ThreadListItemProps = {\n  thread: Thread;\n  threadListItemUIProps?: ThreadListItemUIProps;\n};\n\nconst ThreadListItemContext = createContext<Thread | undefined>(undefined);\n\nexport const useThreadListItemContext = () => useContext(ThreadListItemContext);\n\nexport const ThreadListItem = ({\n  thread,\n  threadListItemUIProps,\n}: ThreadListItemProps) => {\n  const { ThreadListItemUI = DefaultThreadListItemUI } = useComponentContext();\n\n  return (\n    <ThreadListItemContext.Provider value={thread}>\n      <ThreadListItemUI {...threadListItemUIProps} />\n    </ThreadListItemContext.Provider>\n  );\n};\n","import React from 'react';\n\nimport { useTranslationContext } from '../../../context';\nimport { IconMessageBubbles } from '../../Icons';\n\nexport const ThreadListEmptyPlaceholder = () => {\n  const { t } = useTranslationContext('ThreadListEmptyPlaceholder');\n\n  return (\n    <div className='str-chat__thread-list-empty-placeholder'>\n      <IconMessageBubbles />\n      <p>{t('Reply to a message to start a thread')}</p>\n    </div>\n  );\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nimport type { ThreadManagerState } from 'stream-chat';\n\nimport { IconRefresh } from '../../Icons';\nimport { useChatContext, useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { LoadingIndicator } from '../../Loading';\n\nconst selector = (nextValue: ThreadManagerState) => ({\n  isLoading: nextValue.pagination.isLoading,\n  unseenThreadIds: nextValue.unseenThreadIds,\n});\n\nexport const ThreadListUnseenThreadsBanner = () => {\n  const { client } = useChatContext();\n  const { t } = useTranslationContext();\n  const { isLoading, unseenThreadIds } = useStateStore(client.threads.state, selector);\n\n  if (!unseenThreadIds.length) return null;\n\n  return (\n    <button\n      className={clsx('str-chat__unseen-threads-banner', {\n        'str-chat__unseen-threads-banner--loading': isLoading,\n      })}\n      disabled={isLoading}\n      onClick={() => client.threads.reload()}\n    >\n      {!isLoading && (\n        <>\n          <IconRefresh />\n          <span>\n            {t('ThreadListUnseenThreadsBanner/unreadThreads', {\n              count: unseenThreadIds.length,\n            })}\n          </span>\n        </>\n      )}\n      {isLoading && (\n        <>\n          <LoadingIndicator />\n          <span>{t('ThreadListUnseenThreadsBanner/loading')}</span>\n        </>\n      )}\n    </button>\n  );\n};\n","import React from 'react';\n\nimport type { ThreadManagerState } from 'stream-chat';\n\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../../Loading';\nimport { useChatContext, useComponentContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst selector = (nextValue: ThreadManagerState) => ({\n  isLoadingNext: nextValue.pagination.isLoadingNext,\n});\n\nexport const ThreadListLoadingIndicator = () => {\n  const { LoadingIndicator = DefaultLoadingIndicator } = useComponentContext();\n  const { client } = useChatContext();\n  const { isLoadingNext } = useStateStore(client.threads.state, selector);\n\n  if (!isLoadingNext) return null;\n\n  return (\n    <div className='str-chat__thread-list-loading-indicator'>\n      <LoadingIndicator />\n    </div>\n  );\n};\n","import React from 'react';\nimport { useComponentContext, useTranslationContext } from '../../../context';\nimport { useThreadsViewContext } from '../../ChatView';\n\nexport const ThreadListHeader = () => {\n  const { t } = useTranslationContext();\n  const { HeaderEndContent } = useComponentContext();\n  const { activeThread } = useThreadsViewContext();\n  return (\n    <div className='str-chat__thread-list__header'>\n      <div className='str-chat__thread-list__header__title'>{t('Threads')}</div>\n      {activeThread && HeaderEndContent && <HeaderEndContent />}\n    </div>\n  );\n};\n","import React, { useEffect, useState } from 'react';\nimport type { ComputeItemKey, VirtuosoProps } from 'react-virtuoso';\nimport { Virtuoso } from 'react-virtuoso';\nimport type { Thread, ThreadManager, ThreadManagerState } from 'stream-chat';\n\nimport { ThreadListItem as DefaultThreadListItem } from './ThreadListItem';\nimport { ThreadListEmptyPlaceholder as DefaultThreadListEmptyPlaceholder } from './ThreadListEmptyPlaceholder';\nimport { ThreadListUnseenThreadsBanner as DefaultThreadListUnseenThreadsBanner } from './ThreadListUnseenThreadsBanner';\nimport { ThreadListLoadingIndicator as DefaultThreadListLoadingIndicator } from './ThreadListLoadingIndicator';\nimport { LoadingChannels } from '../../Loading';\nimport { NotificationList } from '../../Notifications';\nimport {\n  useChatContext,\n  useComponentContext,\n  useTranslationContext,\n} from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { ThreadListHeader } from './ThreadListHeader';\n\nconst selector = (nextValue: ThreadManagerState) => ({\n  isLoading: nextValue.pagination.isLoading,\n  threads: nextValue.threads,\n});\n\nconst computeItemKey: ComputeItemKey<Thread, unknown> = (_, item) => item.id;\n\ntype ThreadListProps = {\n  virtuosoProps?: VirtuosoProps<Thread, unknown>;\n};\n\nexport const useThreadList = () => {\n  const { client } = useChatContext();\n\n  useEffect(() => {\n    const handleVisibilityChange = () => {\n      if (document.visibilityState === 'visible') {\n        client.threads.activate();\n      }\n      if (document.visibilityState === 'hidden') {\n        client.threads.deactivate();\n      }\n    };\n\n    handleVisibilityChange();\n\n    document.addEventListener('visibilitychange', handleVisibilityChange);\n    return () => {\n      client.threads.deactivate();\n      document.removeEventListener('visibilitychange', handleVisibilityChange);\n    };\n  }, [client]);\n};\n\nconst useThreadHighlighting = (threadManager: ThreadManager) => {\n  const [threadsToHighlight, setThreadsToHighlight] = useState<\n    Record<string, () => void>\n  >({});\n\n  useEffect(() => {\n    const unsubscribe = threadManager.state.subscribeWithSelector(\n      (state) => state.threads,\n      (nextThreads, previousThreads) => {\n        if (!previousThreads) return;\n\n        const resetByThreadId: Record<string, () => void> = {};\n\n        for (const thread of nextThreads) {\n          if (previousThreads.includes(thread)) continue;\n\n          resetByThreadId[thread.id] = () => {\n            setThreadsToHighlight((pv) => {\n              const copy = { ...pv };\n              delete copy[thread.id];\n              return copy;\n            });\n          };\n        }\n\n        setThreadsToHighlight(resetByThreadId);\n      },\n    );\n\n    return unsubscribe;\n  });\n\n  return threadsToHighlight;\n};\n\nexport const ThreadList = ({ virtuosoProps }: ThreadListProps) => {\n  const { client } = useChatContext();\n  const { t } = useTranslationContext('ThreadList');\n  const {\n    NotificationList: NotificationListFromContext = NotificationList,\n    ThreadListEmptyPlaceholder = DefaultThreadListEmptyPlaceholder,\n    ThreadListItem = DefaultThreadListItem,\n    ThreadListLoadingIndicator = DefaultThreadListLoadingIndicator,\n    ThreadListUnseenThreadsBanner = DefaultThreadListUnseenThreadsBanner,\n  } = useComponentContext();\n  const { isLoading, threads } = useStateStore(client.threads.state, selector);\n\n  const resetByThreadId = useThreadHighlighting(client.threads);\n\n  useThreadList();\n\n  if (isLoading && !threads.length) {\n    return (\n      <div className='str-chat__thread-list-container'>\n        <ThreadListHeader />\n        <div className='str-chat__thread-list str-chat__thread-list--loading'>\n          <LoadingChannels />\n        </div>\n      </div>\n    );\n  }\n\n  return (\n    <div className='str-chat__thread-list-container'>\n      <ThreadListHeader />\n      {/* TODO: allow re-load on stale ThreadManager state */}\n      <ThreadListUnseenThreadsBanner />\n      <Virtuoso\n        aria-label={t('aria/Thread list')}\n        atBottomStateChange={(atBottom) => atBottom && client.threads.loadNextPage()}\n        className='str-chat__thread-list'\n        components={{\n          EmptyPlaceholder: ThreadListEmptyPlaceholder,\n          Footer: ThreadListLoadingIndicator,\n        }}\n        computeItemKey={computeItemKey}\n        data={threads}\n        itemContent={(_, thread) => (\n          <ThreadListItem\n            thread={thread}\n            threadListItemUIProps={{\n              resetHighlighting: resetByThreadId[thread.id],\n            }}\n          />\n        )}\n        role='listbox'\n        // TODO: handle visibility (for a button that scrolls to the unread thread)\n        // itemsRendered={(items) => console.log({ items })}\n        {...virtuosoProps}\n      />\n      <NotificationListFromContext panel='thread-list' />\n    </div>\n  );\n};\n","import { useCallback } from 'react';\n\nimport type { Notification, NotificationManagerState } from 'stream-chat';\n\nimport { useChatContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nimport { hasSystemNotificationTag } from './useNotificationApi';\n\nexport type UseSystemNotificationsFilter = (notification: Notification) => boolean;\n\nexport type UseSystemNotificationsOptions = {\n  /**\n   * Applied after the built-in filter that keeps only notifications tagged for the system banner.\n   */\n  filter?: UseSystemNotificationsFilter;\n};\n\n/**\n * Subscribes to `client.notifications` and returns only **system** banner notifications\n * (same subset `NotificationList` excludes from toasts). Optional `filter` narrows further.\n */\nexport const useSystemNotifications = (\n  options?: UseSystemNotificationsOptions,\n): Notification[] => {\n  const { client } = useChatContext();\n  const selector = useCallback(\n    (state: NotificationManagerState) => {\n      const withSystemTag = state.notifications.filter(hasSystemNotificationTag);\n      const notifications = options?.filter\n        ? withSystemTag.filter(options.filter)\n        : withSystemTag;\n\n      return { notifications };\n    },\n    [options?.filter],\n  );\n\n  const { notifications } = useStateStore(client.notifications.store, selector);\n\n  return notifications;\n};\n","import React, { type ComponentType, forwardRef } from 'react';\nimport clsx from 'clsx';\nimport type { NotificationSeverity } from 'stream-chat';\nimport { type Notification as NotificationType } from 'stream-chat';\n\nimport {\n  IconCheckmark,\n  IconExclamationMark,\n  IconExclamationTriangleFill,\n  IconRefresh,\n  IconXmark,\n} from '../../components/Icons';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { Button } from '../Button';\nimport { useNotificationApi } from './hooks/useNotificationApi';\n\ntype NotificationEntryDirection = 'bottom' | 'left' | 'right' | 'top';\ntype NotificationTransitionState = 'enter' | 'exit';\n\nexport type NotificationIconProps = {\n  notification: NotificationType;\n};\n\nconst IconsBySeverity: Record<NotificationSeverity, ComponentType | null> = {\n  error: IconExclamationMark,\n  info: null,\n  loading: IconRefresh,\n  success: IconCheckmark,\n  warning: IconExclamationTriangleFill,\n};\n\nconst DefaultNotificationIcon = ({ notification }: NotificationIconProps) => {\n  if (!notification.severity) return null;\n\n  const Icon = IconsBySeverity[notification.severity] ?? null;\n  return (\n    Icon && (\n      <div className='str-chat__notification-icon'>\n        <Icon />\n      </div>\n    )\n  );\n};\n\nexport type NotificationProps = {\n  /** Notification from client.notifications state */\n  notification: NotificationType;\n  /** Optional class name */\n  className?: string;\n  /** Direction from which the notification enters. */\n  entryDirection?: NotificationEntryDirection;\n  /** Optional custom icon component. */\n  Icon?: React.ComponentType<NotificationIconProps>;\n  /** Optional dismiss handler */\n  onDismiss?: () => void;\n  /** Show close button (for persistent notifications) */\n  showClose?: boolean;\n  /** Optional transition state applied by NotificationList. */\n  transitionState?: NotificationTransitionState;\n};\n\nexport const Notification = forwardRef<HTMLDivElement, NotificationProps>(\n  (\n    {\n      className,\n      entryDirection,\n      Icon = DefaultNotificationIcon,\n      notification,\n      onDismiss,\n      showClose = false,\n      transitionState,\n    }: NotificationProps,\n    ref,\n  ) => {\n    const { removeNotification } = useNotificationApi();\n    const { t } = useTranslationContext();\n\n    const displayMessage = t('translationBuilderTopic/notification', {\n      notification,\n      value: notification.message,\n    });\n\n    const handleDismiss = () => {\n      if (onDismiss) {\n        onDismiss();\n        return;\n      }\n\n      removeNotification(notification.id);\n    };\n\n    const isPersistent = !notification.duration;\n\n    const severity = notification.severity;\n    const livePriority = severity === 'error' ? 'assertive' : 'polite';\n\n    return (\n      <div\n        className={clsx(\n          'str-chat__notification',\n          entryDirection && `str-chat__notification--enter-from-${entryDirection}`,\n          transitionState === 'enter' && 'str-chat__notification--is-entering',\n          transitionState === 'exit' && 'str-chat__notification--is-exiting',\n          severity && `str-chat__notification--${severity}`,\n          severity === 'loading' && 'str-chat__notification--loading',\n          className,\n        )}\n        data-testid='notification'\n        ref={ref}\n      >\n        <div className='str-chat__notification-content'>\n          {Icon && <Icon notification={notification} />}\n          <div\n            aria-atomic='true'\n            aria-live={livePriority}\n            className='str-chat__notification-message'\n            role={livePriority === 'assertive' ? 'alert' : 'status'}\n          >\n            {displayMessage}\n          </div>\n        </div>\n        {notification.actions && notification.actions.length > 0 && (\n          <div className='str-chat__notification-actions'>\n            {notification.actions.map((action, index) => (\n              <Button\n                appearance='outline'\n                className='str-chat__notification-action'\n                inverseTheme\n                key={index}\n                onClick={() => {\n                  action.handler();\n                }}\n                size='sm'\n                variant='secondary'\n              >\n                {action.label}\n              </Button>\n            ))}\n          </div>\n        )}\n        {(showClose || isPersistent) && (\n          <Button\n            appearance='ghost'\n            aria-label={t('aria/Dismiss notification')}\n            circular\n            className='str-chat__notification-close-button'\n            inverseTheme\n            onClick={handleDismiss}\n            size='sm'\n            variant='secondary'\n          >\n            <IconXmark />\n          </Button>\n        )}\n      </div>\n    );\n  },\n);\n\nNotification.displayName = 'Notification';\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\nimport type { Notification } from 'stream-chat';\n\nimport { hasSystemNotificationTag, useNotificationApi } from './hooks/useNotificationApi';\nimport { useNotifications } from './hooks/useNotifications';\nimport { Notification as DefaultNotification } from './Notification';\nimport { useComponentContext, useTranslationContext } from '../../context';\n\nimport type { NotificationTargetPanel } from './notificationTarget';\n\nexport type NotificationListFilter = (notification: Notification) => boolean;\nexport type NotificationListEnterFrom = 'bottom' | 'left' | 'right' | 'top';\nexport type NotificationListVerticalAlignment = 'bottom' | 'top';\n/**\n * Selects the candidate notification to display. Receives the current store contents and\n * the currently displayed notification (or `null` when nothing is mounted). Returning\n * `displayed` (or any notification with the same id) means \"no swap\"; returning a\n * different notification triggers a swap (immediate or after `minDisplayMs`, see the\n * scheduling effect); returning `null` triggers the empty-slot exit.\n *\n * Default: `createDefaultPickNext(pickOldest)` — applies persistent-wins,\n * same-type-refresh and FIFO queue rules from the design spec. Pass\n * `pickNext={createDefaultPickNext(pickNewest)}` to swap FIFO for LIFO without\n * reimplementing those rules, or your own `pickNext` to opt out entirely.\n */\nexport type PickNextNotification = (\n  notifications: Notification[],\n  displayed: Notification | null,\n) => Notification | null;\n\n/**\n * Picks the next queued notification when no higher-priority rule applies (persistent\n * wins, same-type refresh). Used by `createDefaultPickNext`.\n */\nexport type PickFromQueue = (\n  notifications: Notification[],\n  displayed: Notification | null,\n) => Notification | null;\n\nexport type NotificationListProps = {\n  /** Optional class name for the list container */\n  className?: string;\n  /**\n   * Direction from which the replacement notification enters the single visible slot.\n   * Travel distance is configured in `ENTER_TRANSLATION` below.\n   */\n  enterFrom?: NotificationListEnterFrom;\n  /**\n   * When provided, this list only shows notifications that pass the filter.\n   * Use to declare which notifications this list consumes (e.g. by origin.emitter, origin.context.channelId, or metadata).\n   */\n  filter?: NotificationListFilter;\n  /**\n   * Minimum time in milliseconds the active notification stays visible before a queued one\n   * can replace it. Replacements scheduled while the dwell window is open wait until it has\n   * elapsed; arrivals after that window replace the active notification immediately.\n   * Same-type repeated triggers and external dismissals bypass this dwell.\n   * Defaults to 1000ms.\n   */\n  minDisplayMs?: number;\n  /**\n   * Override the candidate-selection policy. The function decides which notification\n   * should be displayed given the store and the currently displayed one. Defaults to\n   * `createDefaultPickNext(pickOldest)`. Pass `createDefaultPickNext(pickNewest)` for LIFO.\n   */\n  pickNext?: PickNextNotification;\n  /** Panel target consumed by this list. */\n  panel?: NotificationTargetPanel;\n  /** Fallback panel when emitted notifications do not include origin.context.panel. */\n  fallbackPanel?: NotificationTargetPanel;\n  /** Vertical alignment of the single notification slot within its parent. Defaults to `bottom`. */\n  verticalAlignment?: NotificationListVerticalAlignment;\n};\n\n// Entry motion is controlled through CSS variables so the keyframe can stay shared in SCSS.\n// Use full-size percentages on the active axis to make a replacement notification slide in\n// from outside its slot. If future tuning needs more travel, prefer `calc(100% + gap)` here.\nconst ENTER_TRANSLATION: Record<NotificationListEnterFrom, { x: string; y: string }> = {\n  bottom: { x: '0%', y: '100%' },\n  left: { x: '-100%', y: '0%' },\n  right: { x: '100%', y: '0%' },\n  top: { x: '0%', y: '-100%' },\n};\n\nconst EXIT_ANIMATION_MS = 340;\nconst DEFAULT_MIN_DISPLAY_MS = 1000;\n\nconst isEnterFrom = (value: unknown): value is NotificationListEnterFrom =>\n  value === 'bottom' || value === 'left' || value === 'right' || value === 'top';\n\nconst getNotificationEnterFrom = (\n  notification: Notification | null,\n  fallbackEnterFrom: NotificationListEnterFrom,\n) => {\n  if (!notification) return fallbackEnterFrom;\n\n  const metadataEnterFrom = notification.metadata?.entryDirection;\n  if (isEnterFrom(metadataEnterFrom)) return metadataEnterFrom;\n\n  const originEnterFrom = notification.origin.context?.entryDirection;\n  if (isEnterFrom(originEnterFrom)) return originEnterFrom;\n\n  return fallbackEnterFrom;\n};\n\nconst isPersistent = (notification: Notification) => !notification.duration;\n\nconst haveSameType = (a: Notification | null, b: Notification | null) =>\n  !!a?.type && !!b?.type && a.type === b.type;\n\n/** FIFO queue selector — oldest `createdAt` other than `displayed` wins. */\nexport const pickOldest: PickFromQueue = (notifications, displayed) => {\n  const excludeId = displayed?.id ?? null;\n  let oldest: Notification | null = null;\n  for (const notification of notifications) {\n    if (notification.id === excludeId) continue;\n    if (!oldest || notification.createdAt < oldest.createdAt) {\n      oldest = notification;\n    }\n  }\n  return oldest;\n};\n\n/** LIFO queue selector — newest `createdAt` other than `displayed` wins. */\nexport const pickNewest: PickFromQueue = (notifications, displayed) => {\n  const excludeId = displayed?.id ?? null;\n  let newest: Notification | null = null;\n  for (const notification of notifications) {\n    if (notification.id === excludeId) continue;\n    if (!newest || notification.createdAt > newest.createdAt) {\n      newest = notification;\n    }\n  }\n  return newest;\n};\n\nconst pickNewestPersistent = (\n  notifications: Notification[],\n  excludeId: string | null,\n): Notification | null => {\n  let newest: Notification | null = null;\n  for (const notification of notifications) {\n    if (notification.id === excludeId) continue;\n    if (!isPersistent(notification)) continue;\n    if (!newest || notification.createdAt > newest.createdAt) {\n      newest = notification;\n    }\n  }\n  return newest;\n};\n\nconst pickNewestOfType = (\n  notifications: Notification[],\n  type: string | undefined | null,\n  excludeId: string | null,\n): Notification | null => {\n  if (!type) return null;\n  let newest: Notification | null = null;\n  for (const notification of notifications) {\n    if (notification.id === excludeId) continue;\n    if (notification.type !== type) continue;\n    if (!newest || notification.createdAt > newest.createdAt) {\n      newest = notification;\n    }\n  }\n  return newest;\n};\n\n/**\n * Builds the default `PickNextNotification` selector with a configurable queue fallback.\n * Encodes the snackbar concurrency rules from the design spec — the scheduling effect\n * only decides *when* to swap, the returned function decides *what* to swap to.\n *\n * Rules, in order of precedence:\n *   1. **Persistent wins.** Persistent variants (no `duration`) jump ahead of any\n *      queued transient because they carry an action the user must acknowledge.\n *   2. **Persistent ↛ replaced by transient.** While a persistent is displayed it stays\n *      put until dismissed externally or a *newer* persistent arrives.\n *   3. **Same-type refresh.** While a transient is displayed, a repeated trigger of the\n *      same `type` collapses to its latest occurrence. (The scheduling effect detects\n *      this via `haveSameType` and bypasses the dwell window so the refresh feels\n *      instant; this function just makes sure the latest same-type is returned.)\n *   4. **Queue fallback.** Otherwise, `pickFromQueue` selects the next notification\n *      (default: `pickOldest` / FIFO).\n *\n * Exported so callers that want to layer behavior on top of the design rules can wrap\n * the result instead of rewriting it.\n */\nexport const createDefaultPickNext =\n  (pickFromQueue: PickFromQueue = pickOldest): PickNextNotification =>\n  (notifications, displayed) => {\n    if (notifications.length === 0) return null;\n\n    const newestPersistent = pickNewestPersistent(notifications, null);\n\n    if (!displayed) {\n      return newestPersistent ?? pickFromQueue(notifications, null);\n    }\n\n    const displayedInStore = notifications.some(({ id }) => id === displayed.id);\n    if (!displayedInStore) {\n      return newestPersistent ?? pickFromQueue(notifications, null);\n    }\n\n    if (isPersistent(displayed)) {\n      // Currently showing a persistent: only a newer persistent can replace it. Reuse the\n      // earlier lookup when it already points at a different persistent.\n      const newerPersistent =\n        newestPersistent && newestPersistent.id !== displayed.id\n          ? newestPersistent\n          : pickNewestPersistent(notifications, displayed.id);\n      if (newerPersistent && newerPersistent.createdAt > displayed.createdAt) {\n        return newerPersistent;\n      }\n      return displayed;\n    }\n\n    // Currently showing a transient.\n    // 1. Same-type \"refresh of current\" wins immediately — a repeated trigger of the\n    //    displayed snackbar collapses to the latest occurrence of that type.\n    const sameTypeNewest = pickNewestOfType(notifications, displayed.type, displayed.id);\n    if (sameTypeNewest) return sameTypeNewest;\n\n    // 2. Any queued persistent jumps ahead of the queue.\n    if (newestPersistent) return newestPersistent;\n\n    // 3. Queue fallback.\n    return pickFromQueue(notifications, displayed) ?? displayed;\n  };\n\n/** Default selector — design-spec rules with FIFO queue fallback (`pickOldest`). */\nconst defaultPickNext = createDefaultPickNext(pickOldest);\n\nexport const NotificationList = ({\n  className,\n  enterFrom = 'bottom',\n  fallbackPanel,\n  filter,\n  minDisplayMs = DEFAULT_MIN_DISPLAY_MS,\n  panel,\n  pickNext = defaultPickNext,\n  verticalAlignment = 'bottom',\n}: NotificationListProps) => {\n  const { Notification: NotificationComponent = DefaultNotification } =\n    useComponentContext();\n  const { t } = useTranslationContext();\n  const { removeNotification, startNotificationTimeout } = useNotificationApi();\n  // Holds the timer that runs the exit animation. Set when we flip `transitionState` to\n  // `'exit'`; when it fires, the previously displayed notification is removed and either the\n  // next candidate is mounted (entering) or the list collapses to empty. Only one exit\n  // animation can be in flight at a time.\n  const exitTimeoutRef = useRef<number | null>(null);\n  // Holds the dwell timer that defers a swap until `minDisplayMs` has elapsed since the\n  // active notification became visible. It only exists while we're waiting out the dwell\n  // window; same-type triggers, external dismissals and arrivals after the dwell window\n  // bypass it and trigger the exit animation directly.\n  const replacementTimeoutRef = useRef<number | null>(null);\n  const candidateRef = useRef<Notification | null>(null);\n  const displayedAtRef = useRef<number | null>(null);\n  const listRef = useRef<HTMLDivElement | null>(null);\n  const observedElementRef = useRef<HTMLDivElement | null>(null);\n  const startedTimeoutIdsRef = useRef<Set<string> | null>(null);\n\n  if (!startedTimeoutIdsRef.current) {\n    startedTimeoutIdsRef.current = new Set<string>();\n  }\n\n  const [displayedNotification, setDisplayedNotification] = useState<Notification | null>(\n    null,\n  );\n  const [transitionState, setTransitionState] = useState<'enter' | 'exit'>('enter');\n  const combinedFilter = useCallback(\n    (notification: Notification) => {\n      if (hasSystemNotificationTag(notification)) return false;\n      return filter ? filter(notification) : true;\n    },\n    [filter],\n  );\n  const notifications = useNotifications({\n    applyDisplayFilter: true,\n    fallbackPanel,\n    filter: combinedFilter,\n    panel,\n  });\n\n  const dismiss = useCallback(\n    (id: string) => {\n      startedTimeoutIdsRef.current?.delete(id);\n      removeNotification(id);\n    },\n    [removeNotification],\n  );\n\n  // Drop any stale entries from the started-timeouts set whenever the store changes.\n  useEffect(() => {\n    const notificationIds = new Set(notifications.map(({ id }) => id));\n\n    startedTimeoutIdsRef.current?.forEach((id) => {\n      if (!notificationIds.has(id)) {\n        startedTimeoutIdsRef.current?.delete(id);\n      }\n    });\n  }, [notifications]);\n\n  const clearReplacementTimeout = useCallback(() => {\n    if (replacementTimeoutRef.current !== null) {\n      window.clearTimeout(replacementTimeoutRef.current);\n      replacementTimeoutRef.current = null;\n    }\n  }, []);\n\n  // Cleanup pending timers on unmount.\n  useEffect(\n    () => () => {\n      clearReplacementTimeout();\n      if (exitTimeoutRef.current !== null) {\n        window.clearTimeout(exitTimeoutRef.current);\n        exitTimeoutRef.current = null;\n      }\n    },\n    [clearReplacementTimeout],\n  );\n\n  // Keep the freshest candidate around so swap completion can read the latest value, even\n  // when a new notification arrives mid-exit-animation.\n  useEffect(() => {\n    candidateRef.current = pickNext(notifications, displayedNotification);\n  }, [displayedNotification, notifications, pickNext]);\n\n  // Main scheduling effect — owns *when* swaps happen. The *what* is delegated entirely\n  // to `pickNext` (default: `createDefaultPickNext(pickOldest)`).\n  //\n  // Runs on every change to `displayedNotification`, `notifications`, `pickNext`, or\n  // `transitionState`, and decides one of four outcomes:\n  //   1. Do nothing (the right notification is already on screen, or an exit animation\n  //      is mid-flight and will re-trigger this effect when it finishes).\n  //   2. Mount the first notification (no `displayedNotification` yet).\n  //   3. Unmount the current one (`pickNext` returned `null`, the store became empty).\n  //   4. Swap the displayed one for the new candidate — either immediately or after the\n  //      `minDisplayMs` dwell window has elapsed.\n  //\n  // Timing rules applied here (independent of selection policy):\n  //   - **Dwell window.** When `pickNext` returns a different candidate, hold the active\n  //     notification on screen until at least `minDisplayMs` has passed since it became\n  //     visible. Replacements that arrive after that window swap immediately.\n  //   - **Same-type bypass.** If the candidate has the same `type` as the displayed\n  //     notification, swap immediately (no dwell) — this is the \"repeated trigger\n  //     refreshes the snackbar and resets the auto-dismiss timer\" behavior. The timer\n  //     reset is achieved by removing the previously displayed notification on swap\n  //     (which clears its `NotificationManager` timer) so the new one starts its own\n  //     when it next intersects the slot.\n  //   - **External-dismiss bypass.** If the displayed notification is no longer in the\n  //     store (user clicked the close button, `NotificationManager` auto-removed it,\n  //     etc.), swap immediately — we should not stall an empty slot for the dwell.\n  useEffect(() => {\n    // An exit animation is already in flight. Once its timer fires it sets new state\n    // (either the next notification or `null`), which will re-run this effect from a\n    // clean baseline.\n    if (transitionState === 'exit') return;\n\n    // No notification is mounted yet — pick whatever the candidate logic prefers and\n    // mount it directly with an enter animation. No swap required.\n    if (!displayedNotification) {\n      const candidate = pickNext(notifications, null);\n      if (candidate) {\n        displayedAtRef.current = Date.now();\n        setDisplayedNotification(candidate);\n        setTransitionState('enter');\n      }\n      return;\n    }\n\n    const candidate = pickNext(notifications, displayedNotification);\n\n    // The store has been drained while a notification was visible. Play the exit\n    // animation, then unmount.\n    if (!candidate) {\n      clearReplacementTimeout();\n      setTransitionState('exit');\n      exitTimeoutRef.current = window.setTimeout(() => {\n        exitTimeoutRef.current = null;\n        displayedAtRef.current = null;\n        setDisplayedNotification(null);\n        setTransitionState('enter');\n      }, EXIT_ANIMATION_MS);\n      return;\n    }\n\n    // The candidate is the displayed notification itself — nothing to do. Cancel any\n    // dwell timer that may have been queued by an earlier run that has since become\n    // moot (e.g. the incoming notification was removed before its dwell expired).\n    if (candidate.id === displayedNotification.id) {\n      clearReplacementTimeout();\n      return;\n    }\n\n    const displayedInStore = notifications.some(\n      ({ id }) => id === displayedNotification.id,\n    );\n\n    // Swap routine shared by the immediate and dwell-deferred branches below. Captures\n    // `previousId` / `wasInStore` from the effect's closure so the exit timer can run\n    // the right cleanup even if state has moved on by the time it fires.\n    const startSwap = () => {\n      replacementTimeoutRef.current = null;\n      setTransitionState('exit');\n      const previousId = displayedNotification.id;\n      const wasInStore = displayedInStore;\n      exitTimeoutRef.current = window.setTimeout(() => {\n        exitTimeoutRef.current = null;\n        if (wasInStore) {\n          // Remove the previously displayed notification from the store so it does not\n          // re-appear, and so its NotificationManager auto-dismiss timer is cleared.\n          startedTimeoutIdsRef.current?.delete(previousId);\n          removeNotification(previousId);\n        }\n        // Read the latest candidate at the moment the exit animation actually completes —\n        // it may differ from the one decided when `startSwap` was queued because new\n        // notifications could have arrived during the 340ms exit window.\n        const next = candidateRef.current;\n        if (next && next.id !== previousId) {\n          displayedAtRef.current = Date.now();\n          setDisplayedNotification(next);\n          setTransitionState('enter');\n        } else {\n          displayedAtRef.current = null;\n          setDisplayedNotification(null);\n          setTransitionState('enter');\n        }\n      }, EXIT_ANIMATION_MS);\n    };\n\n    // External dismissal or auto-dismiss removed the displayed notification: swap right\n    // away (no dwell wait — the slot would otherwise stall empty for `minDisplayMs`).\n    if (!displayedInStore) {\n      clearReplacementTimeout();\n      startSwap();\n      return;\n    }\n\n    // Repeated triggers of the same snackbar replace the active one and reset the\n    // auto-dismiss timer immediately — feedback for the same condition should feel like\n    // a single, persistent thing being refreshed.\n    if (haveSameType(displayedNotification, candidate)) {\n      clearReplacementTimeout();\n      startSwap();\n      return;\n    }\n\n    // Default branch: enforce the dwell window. `displayedAtRef` is stamped synchronously\n    // every time we set `displayedNotification` (initial mount and swap completion), so it\n    // is in sync with what is on screen by the time this effect runs.\n    const elapsed = displayedAtRef.current ? Date.now() - displayedAtRef.current : 0;\n    const remaining = Math.max(0, minDisplayMs - elapsed);\n\n    if (remaining === 0) {\n      // Dwell already elapsed; swap right now.\n      clearReplacementTimeout();\n      startSwap();\n    } else if (replacementTimeoutRef.current === null) {\n      // A swap is pending but the dwell hasn't elapsed yet. Schedule the swap once —\n      // subsequent re-runs of this effect (e.g. as even newer notifications arrive)\n      // intentionally do NOT reschedule. `candidateRef` keeps tracking the freshest\n      // candidate, so when the timer fires `startSwap` → exit completes → the latest\n      // candidate is picked up automatically.\n      replacementTimeoutRef.current = window.setTimeout(startSwap, remaining);\n    }\n  }, [\n    clearReplacementTimeout,\n    displayedNotification,\n    minDisplayMs,\n    notifications,\n    pickNext,\n    removeNotification,\n    transitionState,\n  ]);\n\n  const notification = displayedNotification;\n  const notificationEnterFrom = getNotificationEnterFrom(notification, enterFrom);\n\n  useEffect(() => {\n    const element = observedElementRef.current;\n    if (!element || !notification || transitionState === 'exit') return;\n\n    const startTimeout = () => {\n      if (\n        !startedTimeoutIdsRef.current ||\n        startedTimeoutIdsRef.current.has(notification.id)\n      )\n        return;\n\n      startedTimeoutIdsRef.current.add(notification.id);\n      startNotificationTimeout(notification.id);\n    };\n\n    if (typeof IntersectionObserver === 'undefined') {\n      startTimeout();\n      return;\n    }\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        const [entry] = entries;\n        if (!entry?.isIntersecting) return;\n\n        startTimeout();\n        observer.disconnect();\n      },\n      {\n        root: listRef.current,\n        threshold: 0.5,\n      },\n    );\n\n    observer.observe(element);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [notification, startNotificationTimeout, transitionState]);\n\n  if (!notification) return null;\n\n  return (\n    <div\n      aria-label={t('aria/Notifications')}\n      className={clsx(\n        'str-chat__notification-list',\n        `str-chat__notification-list--enter-from-${notificationEnterFrom}`,\n        `str-chat__notification-list--position-${verticalAlignment}`,\n        panel && `str-chat__notification-list--${panel}`,\n        className,\n      )}\n      data-testid='notification-list'\n      ref={listRef}\n      role='region'\n      style={\n        {\n          '--str-chat__notification-list-enter-x':\n            ENTER_TRANSLATION[notificationEnterFrom].x,\n          '--str-chat__notification-list-enter-y':\n            ENTER_TRANSLATION[notificationEnterFrom].y,\n        } as React.CSSProperties\n      }\n    >\n      <div\n        aria-hidden\n        className='str-chat__notification-list__edge str-chat__notification-list__edge--top'\n      />\n      <NotificationComponent\n        entryDirection={notificationEnterFrom}\n        key={notification.id}\n        notification={notification}\n        onDismiss={() => dismiss(notification.id)}\n        ref={(element) => {\n          observedElementRef.current = element;\n        }}\n        showClose={!notification.duration}\n        transitionState={transitionState}\n      />\n      <div\n        aria-hidden\n        className='str-chat__notification-list__edge str-chat__notification-list__edge--bottom'\n      />\n    </div>\n  );\n};\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport type { Notification } from 'stream-chat';\n\nimport { useNotifications } from '../Notifications';\nimport { VisuallyHidden } from '../VisuallyHidden';\nimport { useTranslationContext } from '../../context';\n\ntype LivePriority = 'assertive' | 'polite';\n\ntype QueuedAnnouncement = {\n  id: string;\n  message: string;\n  priority: LivePriority;\n};\n\nexport type NotificationAnnouncementBuilderParams = {\n  defaultMessage: string;\n  notification: Notification;\n  translatedMessage: string;\n};\n\nexport type NotificationAnnouncementBuilder = (\n  params: NotificationAnnouncementBuilderParams,\n) => string;\nexport type NotificationAnnouncementFilter = (notification: Notification) => boolean;\n\nconst ANNOUNCEMENT_CLEAR_DELAY_MS = 50;\nconst ANNOUNCEMENT_QUEUE_GAP_MS = 120;\n\nconst getAnnouncementPriority = (notification: Notification): LivePriority =>\n  notification.severity === 'error' ? 'assertive' : 'polite';\n\nconst getSeverityLabel = (notification: Notification) => {\n  if (!notification.severity) return null;\n  return `${notification.severity[0].toUpperCase()}${notification.severity.slice(1)}`;\n};\n\nconst getDefaultAnnouncementMessage = (notification: Notification, message: string) => {\n  const severityLabel = getSeverityLabel(notification);\n\n  if (severityLabel) {\n    return `${severityLabel} notification: ${message}`;\n  }\n\n  return `Notification: ${message}`;\n};\n\nexport type NotificationAnnouncerProps = {\n  buildNotificationAnnouncement?: NotificationAnnouncementBuilder;\n  notificationFilter?: NotificationAnnouncementFilter;\n};\n\nconst defaultBuildNotificationAnnouncement: NotificationAnnouncementBuilder = ({\n  defaultMessage,\n}) => defaultMessage;\nconst defaultNotificationFilter: NotificationAnnouncementFilter = () => true;\n\nexport const NotificationAnnouncer = ({\n  buildNotificationAnnouncement = defaultBuildNotificationAnnouncement,\n  notificationFilter = defaultNotificationFilter,\n}: NotificationAnnouncerProps) => {\n  const { t } = useTranslationContext();\n  const notifications = useNotifications();\n  const [announcementQueue, setAnnouncementQueue] = useState<QueuedAnnouncement[]>([]);\n  const [isAnnouncing, setIsAnnouncing] = useState(false);\n  const [politeAnnouncement, setPoliteAnnouncement] = useState('');\n  const [assertiveAnnouncement, setAssertiveAnnouncement] = useState('');\n  const initializedRef = useRef(false);\n  const seenNotificationIdsRef = useRef(new Set<string>());\n  const announceTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const dequeueTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  const clearTimeouts = useCallback(() => {\n    if (announceTimeoutRef.current) {\n      clearTimeout(announceTimeoutRef.current);\n      announceTimeoutRef.current = null;\n    }\n\n    if (dequeueTimeoutRef.current) {\n      clearTimeout(dequeueTimeoutRef.current);\n      dequeueTimeoutRef.current = null;\n    }\n  }, []);\n\n  useEffect(\n    () => () => {\n      clearTimeouts();\n    },\n    [clearTimeouts],\n  );\n\n  useEffect(() => {\n    const visibleNotificationIds = new Set(notifications.map(({ id }) => id));\n\n    seenNotificationIdsRef.current.forEach((id) => {\n      if (!visibleNotificationIds.has(id)) {\n        seenNotificationIdsRef.current.delete(id);\n      }\n    });\n\n    if (!initializedRef.current) {\n      notifications.forEach(({ id }) => {\n        seenNotificationIdsRef.current.add(id);\n      });\n      initializedRef.current = true;\n      return;\n    }\n\n    const nextAnnouncements: QueuedAnnouncement[] = [];\n\n    notifications.forEach((notification) => {\n      if (seenNotificationIdsRef.current.has(notification.id)) return;\n\n      seenNotificationIdsRef.current.add(notification.id);\n      if (!notificationFilter(notification)) return;\n\n      const message = t('translationBuilderTopic/notification', {\n        notification,\n        value: notification.message,\n      });\n\n      if (!message) return;\n\n      const defaultMessage = getDefaultAnnouncementMessage(notification, message);\n      const announcementMessage = buildNotificationAnnouncement({\n        defaultMessage,\n        notification,\n        translatedMessage: message,\n      });\n\n      if (!announcementMessage) return;\n\n      nextAnnouncements.push({\n        id: notification.id,\n        message: announcementMessage,\n        priority: getAnnouncementPriority(notification),\n      });\n    });\n\n    if (!nextAnnouncements.length) return;\n\n    setAnnouncementQueue((currentQueue) => [...currentQueue, ...nextAnnouncements]);\n  }, [buildNotificationAnnouncement, notificationFilter, notifications, t]);\n\n  useEffect(() => {\n    if (isAnnouncing) return;\n\n    const nextAnnouncement = announcementQueue[0];\n    if (!nextAnnouncement) return;\n\n    setIsAnnouncing(true);\n    clearTimeouts();\n    setPoliteAnnouncement('');\n    setAssertiveAnnouncement('');\n\n    announceTimeoutRef.current = setTimeout(() => {\n      if (nextAnnouncement.priority === 'assertive') {\n        setAssertiveAnnouncement(nextAnnouncement.message);\n      } else {\n        setPoliteAnnouncement(nextAnnouncement.message);\n      }\n\n      dequeueTimeoutRef.current = setTimeout(() => {\n        setAnnouncementQueue((currentQueue) =>\n          currentQueue.filter(({ id }) => id !== nextAnnouncement.id),\n        );\n        setIsAnnouncing(false);\n        dequeueTimeoutRef.current = null;\n      }, ANNOUNCEMENT_QUEUE_GAP_MS);\n\n      announceTimeoutRef.current = null;\n    }, ANNOUNCEMENT_CLEAR_DELAY_MS);\n  }, [announcementQueue, clearTimeouts, isAnnouncing]);\n\n  return (\n    <VisuallyHidden data-testid='notification-announcer'>\n      <div aria-atomic='true' aria-live='polite' role='status'>\n        {politeAnnouncement}\n      </div>\n      <div aria-atomic='true' aria-live='assertive' role='alert'>\n        {assertiveAnnouncement}\n      </div>\n    </VisuallyHidden>\n  );\n};\n","import { useCallback, useEffect, useRef } from 'react';\nimport type { Channel, Event, MessageResponse } from 'stream-chat';\n\nimport { useAriaLiveAnnouncer } from '../useAriaLiveAnnouncer';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\nconst MESSAGE_ANNOUNCEMENT_THROTTLE_MS = 1000;\n\nconst isAnnounceableIncomingMessage = (\n  message: MessageResponse,\n  ownUserId?: string,\n): boolean => {\n  const messageUserId = message.user?.id;\n\n  if (!message.id || !messageUserId || messageUserId === ownUserId) {\n    return false;\n  }\n\n  return (\n    message.type !== 'deleted' &&\n    message.type !== 'ephemeral' &&\n    message.type !== 'error' &&\n    message.type !== 'system' &&\n    message.status !== 'failed' &&\n    message.status !== 'sending'\n  );\n};\n\nconst getSenderName = (\n  message: MessageResponse,\n  t: ReturnType<typeof useTranslationContext>['t'],\n) => message.user?.name?.trim() || message.user?.id || t('Anonymous');\n\nexport type UseIncomingMessageAnnouncementsParams = {\n  activeThreadId?: string;\n  channel?: Channel;\n  ownUserId?: string;\n  threadList?: boolean;\n};\n\nexport const useIncomingMessageAnnouncements = ({\n  activeThreadId,\n  channel,\n  ownUserId,\n  threadList = false,\n}: UseIncomingMessageAnnouncementsParams) => {\n  const announce = useAriaLiveAnnouncer();\n  const { t } = useTranslationContext('useIncomingMessageAnnouncements');\n  const lastAnnouncementTimestampRef = useRef(0);\n  const flushTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n  const announcedMessageIdsRef = useRef(new Set<string>());\n  const pendingAnnouncementBatchRef = useRef<{\n    count: number;\n    firstSender: string | null;\n  }>({\n    count: 0,\n    firstSender: null,\n  });\n\n  const flushPendingAnnouncements = useCallback(() => {\n    const pendingAnnouncementBatch = pendingAnnouncementBatchRef.current;\n\n    if (pendingAnnouncementBatch.count <= 0) return;\n\n    if (pendingAnnouncementBatch.count === 1) {\n      announce(\n        t('New message from {{user}}', {\n          user: pendingAnnouncementBatch.firstSender || t('Anonymous'),\n        }),\n      );\n    } else {\n      announce(t('{{count}} new messages', { count: pendingAnnouncementBatch.count }));\n    }\n\n    pendingAnnouncementBatch.count = 0;\n    pendingAnnouncementBatch.firstSender = null;\n    lastAnnouncementTimestampRef.current = Date.now();\n  }, [announce, t]);\n\n  const scheduleFlush = useCallback(() => {\n    if (flushTimeoutRef.current) return;\n\n    const now = Date.now();\n    const elapsedSinceLastAnnouncement = now - lastAnnouncementTimestampRef.current;\n\n    if (elapsedSinceLastAnnouncement >= MESSAGE_ANNOUNCEMENT_THROTTLE_MS) {\n      flushPendingAnnouncements();\n      return;\n    }\n\n    flushTimeoutRef.current = setTimeout(() => {\n      flushTimeoutRef.current = undefined;\n      flushPendingAnnouncements();\n    }, MESSAGE_ANNOUNCEMENT_THROTTLE_MS - elapsedSinceLastAnnouncement);\n  }, [flushPendingAnnouncements]);\n\n  useEffect(\n    () => () => {\n      if (flushTimeoutRef.current) {\n        clearTimeout(flushTimeoutRef.current);\n      }\n    },\n    [],\n  );\n\n  useEffect(() => {\n    if (!channel) {\n      return;\n    }\n\n    const handleMessageNew = (event: Event) => {\n      const message = event.message;\n      if (!message) return;\n\n      if (\n        (event.cid && event.cid !== channel.cid) ||\n        !isAnnounceableIncomingMessage(message, ownUserId)\n      ) {\n        return;\n      }\n\n      const isReply = !!message.parent_id;\n      const belongsToActiveThread =\n        !!activeThreadId && message.parent_id === activeThreadId;\n      const shouldAnnounceInThreadList = threadList && belongsToActiveThread;\n      const shouldAnnounceInMainList = !threadList && !isReply;\n\n      if (!shouldAnnounceInThreadList && !shouldAnnounceInMainList) {\n        return;\n      }\n\n      if (announcedMessageIdsRef.current.has(message.id || '')) {\n        return;\n      }\n\n      if (message.id) {\n        if (announcedMessageIdsRef.current.size > 500) {\n          announcedMessageIdsRef.current.clear();\n        }\n        announcedMessageIdsRef.current.add(message.id);\n      }\n\n      pendingAnnouncementBatchRef.current.count += 1;\n      if (!pendingAnnouncementBatchRef.current.firstSender) {\n        pendingAnnouncementBatchRef.current.firstSender = getSenderName(message, t);\n      }\n\n      scheduleFlush();\n    };\n\n    const subscription = channel.on('message.new', handleMessageNew);\n\n    return () => {\n      subscription.unsubscribe();\n      if (flushTimeoutRef.current) {\n        clearTimeout(flushTimeoutRef.current);\n        flushTimeoutRef.current = undefined;\n      }\n    };\n  }, [activeThreadId, channel, ownUserId, scheduleFlush, t, threadList]);\n};\n","import { useEffect, useState } from 'react';\nimport type { ChannelState } from 'stream-chat';\n\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\n/**\n * Returns the channel header online status text (e.g. \"Online\", \"Offline\", or \"X members, Y online\").\n * Returns null when the channel has no members (nothing to show).\n */\nexport function useChannelHeaderOnlineStatus(): string | null {\n  const { t } = useTranslationContext();\n  const { client } = useChatContext();\n  const { channel, watcherCount = 0 } = useChannelStateContext();\n  const { member_count: memberCount = 0 } = channel?.data || {};\n\n  // todo: we need reactive state for watchers in LLC\n  const [watchers, setWatchers] = useState<ChannelState['watchers']>(() =>\n    Object.assign({}, channel?.state?.watchers ?? {}),\n  );\n\n  useEffect(() => {\n    if (!channel) return;\n    const subscription = channel.on('user.watching.start', (event) => {\n      setWatchers((prev) => {\n        if (!event.user?.id) return prev;\n        if (prev[event.user.id]) return prev;\n        return Object.assign({ [event.user.id]: event.user }, prev);\n      });\n    });\n    return () => subscription.unsubscribe();\n  }, [channel]);\n\n  if (!memberCount) return null;\n\n  const isDmChannel =\n    memberCount === 1 ||\n    (memberCount === 2 &&\n      Object.values(channel?.state?.members ?? {}).some(\n        ({ user }) => user?.id === client.user?.id,\n      ));\n\n  if (isDmChannel) {\n    const hasWatchers = Object.keys(watchers).length > 0;\n    return hasWatchers ? t('Online') : t('Offline');\n  }\n\n  return `${t('{{ memberCount }} members', { memberCount })}, ${t('{{ watcherCount }} online', { watcherCount })}`;\n}\n","import React from 'react';\n\nimport { type ChannelAvatarProps, ChannelAvatar as DefaultAvatar } from '../Avatar';\nimport { TypingIndicatorHeader } from '../TypingIndicator/TypingIndicatorHeader';\nimport { useChannelHeaderOnlineStatus } from './hooks/useChannelHeaderOnlineStatus';\nimport { useChannelPreviewInfo } from '../ChannelListItem/hooks/useChannelPreviewInfo';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useTypingContext } from '../../context/TypingContext';\n\nconst ChannelHeaderSubtitle = () => {\n  const { channelConfig } = useChannelStateContext('ChannelHeaderSubtitle');\n  const { client } = useChatContext('ChannelHeaderSubtitle');\n  const { typing = {} } = useTypingContext('ChannelHeaderSubtitle');\n  const onlineStatusText = useChannelHeaderOnlineStatus();\n  const typingInChannel = Object.values(typing).filter(\n    ({ parent_id, user }) => user?.id !== client.user?.id && !parent_id,\n  );\n  const hasTyping = channelConfig?.typing_events !== false && typingInChannel.length > 0;\n\n  if (!hasTyping && !onlineStatusText) return null;\n\n  return (\n    <div className='str-chat__channel-header__data__subtitle'>\n      <span\n        className='str-chat__subtitle-content-transition'\n        key={hasTyping ? 'typing' : 'default'}\n      >\n        {hasTyping ? <TypingIndicatorHeader /> : onlineStatusText}\n      </span>\n    </div>\n  );\n};\n\nexport type ChannelHeaderProps = {\n  /** UI component to display an avatar, defaults to [Avatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/Avatar.tsx) component and accepts the same props as: [ChannelAvatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/ChannelAvatar.tsx) */\n  Avatar?: React.ComponentType<ChannelAvatarProps>;\n  /** Manually set the image to render, defaults to the Channel image */\n  image?: string;\n  /** Set title manually */\n  title?: string;\n};\n\n/**\n * The ChannelHeader component renders some basic information about a Channel.\n */\nexport const ChannelHeader = (props: ChannelHeaderProps) => {\n  const { Avatar = DefaultAvatar, image: overrideImage, title: overrideTitle } = props;\n\n  const { channel } = useChannelStateContext();\n  const { HeaderStartContent } = useComponentContext();\n  const { displayImage, displayTitle, groupChannelDisplayInfo } = useChannelPreviewInfo({\n    channel,\n    overrideImage,\n    overrideTitle,\n  });\n\n  return (\n    <div className='str-chat__channel-header'>\n      <div className='str-chat__channel-header__start'>\n        {HeaderStartContent && <HeaderStartContent />}\n      </div>\n      <div className='str-chat__channel-header__data'>\n        <div className='str-chat__channel-header__data__title'>{displayTitle}</div>\n        <ChannelHeaderSubtitle />\n      </div>\n      <div className='str-chat__channel-header__end'>\n        <Avatar\n          className='str-chat__avatar--channel-header'\n          displayMembers={groupChannelDisplayInfo?.members}\n          imageUrl={displayImage}\n          size='lg'\n          userName={displayTitle}\n        />\n      </div>\n    </div>\n  );\n};\n","import type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport React, { useEffect, useRef } from 'react';\n\n/**\n * `SkipNavigation` is an opt-in skip links helper for integrators and is not rendered by `Chat`.\n *\n * Intended integration:\n * - Render as the first keyboard-focusable element in your chat layout.\n * - Pass `targetIds` ordered by keyboard priority (for example message composer first).\n * - Each value must be a DOM id (without `#`) so links keep native hash navigation semantics.\n *\n * Activation behavior:\n * - Renders one link per target id.\n * - Keeps native hash-link behavior via `href=\"#{targetId}\"`.\n * - Programmatically moves focus to each target element for reliable keyboard navigation.\n * - If the target is not naturally focusable, temporarily applies `tabindex=\"-1\"` and\n *   removes it on blur.\n *\n * The caller can intercept activation by passing `onClick` and calling `event.preventDefault()`.\n *\n * @example\n * ```tsx\n * <SkipNavigation\n *   getLinkLabel={(targetId) =>\n *     targetId === 'my-message-composer-textarea'\n *       ? 'Skip to message composer'\n *       : 'Skip to channel messages'\n *   }\n *   targetIds={['my-message-composer-textarea', 'my-channel-root']}\n * />\n * ```\n */\nexport type SkipNavigationProps = Omit<ComponentPropsWithoutRef<'a'>, 'href'> & {\n  /** Optional per-link label generator. Defaults to `Skip to {targetId}`. */\n  getLinkLabel?: (targetId: string, index: number) => ReactNode;\n  /** Ordered DOM ids of elements that should receive focus when links are activated. */\n  targetIds: string[];\n};\n\nconst normalizeTargetId = (targetId: string) =>\n  targetId.startsWith('#') ? targetId.slice(1) : targetId;\nconst isActivationKey = (event: React.KeyboardEvent<HTMLAnchorElement>) =>\n  event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar';\n\ntype FocusCleanupState = {\n  cleanup: () => void;\n  hasTemporaryTabIndex: boolean;\n};\n\nconst focusTargetElement = (\n  targetId: string,\n  focusCleanupRegistry: React.MutableRefObject<Map<HTMLElement, FocusCleanupState>>,\n) => {\n  const targetElement = document.getElementById(targetId);\n  if (!targetElement) return;\n\n  const hasTabIndexAttribute = targetElement.hasAttribute('tabindex');\n  if (!hasTabIndexAttribute) {\n    targetElement.setAttribute('tabindex', '-1');\n  }\n\n  targetElement.focus();\n\n  if (!hasTabIndexAttribute) {\n    const existingFocusCleanup = focusCleanupRegistry.current.get(targetElement);\n    if (existingFocusCleanup) {\n      existingFocusCleanup.cleanup();\n    }\n\n    const handleBlur = () => {\n      targetElement.removeAttribute('tabindex');\n      focusCleanupRegistry.current.delete(targetElement);\n    };\n\n    targetElement.addEventListener('blur', handleBlur, { once: true });\n\n    focusCleanupRegistry.current.set(targetElement, {\n      cleanup: () => targetElement.removeEventListener('blur', handleBlur),\n      hasTemporaryTabIndex: true,\n    });\n  }\n};\n\nexport const SkipNavigation = ({\n  className,\n  getLinkLabel,\n  onClick,\n  onKeyDown,\n  targetIds,\n  ...anchorProps\n}: SkipNavigationProps) => {\n  const focusCleanupRegistry = useRef<Map<HTMLElement, FocusCleanupState>>(new Map());\n\n  useEffect(\n    () => () => {\n      focusCleanupRegistry.current.forEach(\n        ({ cleanup, hasTemporaryTabIndex }, targetElement) => {\n          cleanup();\n          if (hasTemporaryTabIndex && targetElement.getAttribute('tabindex') === '-1') {\n            targetElement.removeAttribute('tabindex');\n          }\n        },\n      );\n\n      focusCleanupRegistry.current.clear();\n    },\n    [],\n  );\n\n  if (!targetIds.length) return null;\n\n  const handleClick = (event: React.MouseEvent<HTMLAnchorElement>, targetId: string) => {\n    onClick?.(event);\n    if (event.defaultPrevented) return;\n\n    // Move keyboard focus to the target element and keep hash-link fallback behavior.\n    focusTargetElement(targetId, focusCleanupRegistry);\n  };\n  const handleKeyDown = (\n    event: React.KeyboardEvent<HTMLAnchorElement>,\n    targetId: string,\n  ) => {\n    onKeyDown?.(event);\n    if (event.defaultPrevented || !isActivationKey(event)) return;\n\n    event.preventDefault();\n    focusTargetElement(targetId, focusCleanupRegistry);\n  };\n\n  return (\n    <>\n      {targetIds.map((targetId, index) => {\n        const normalizedTargetId = normalizeTargetId(targetId);\n        const linkLabel =\n          getLinkLabel?.(normalizedTargetId, index) ?? `Skip to ${normalizedTargetId}`;\n\n        return (\n          <a\n            {...anchorProps}\n            className={['str-chat__skip-navigation-link', className]\n              .filter(Boolean)\n              .join(' ')}\n            href={`#${normalizedTargetId}`}\n            key={`${normalizedTargetId}-${index}`}\n            onClick={(event) => handleClick(event, normalizedTargetId)}\n            onKeyDown={(event) => handleKeyDown(event, normalizedTargetId)}\n          >\n            {linkLabel}\n          </a>\n        );\n      })}\n    </>\n  );\n};\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport type { TranslationContextValue } from '../../../context/TranslationContext';\nimport type { SupportedTranslations } from '../../../i18n';\nimport {\n  defaultDateTimeParser,\n  defaultTranslatorFunction,\n  isLanguageSupported,\n  Streami18n,\n} from '../../../i18n';\n\nimport type {\n  AppSettingsAPIResponse,\n  Channel,\n  Event,\n  Mute,\n  OwnUserResponse,\n  StreamChat,\n} from 'stream-chat';\n\nexport type UseChatParams = {\n  client: StreamChat;\n  defaultLanguage?: SupportedTranslations;\n  i18nInstance?: Streami18n;\n};\n\nexport const useChat = ({\n  client,\n  defaultLanguage = 'en',\n  i18nInstance,\n}: UseChatParams) => {\n  const [translators, setTranslators] = useState<TranslationContextValue>({\n    t: defaultTranslatorFunction,\n    tDateTimeParser: defaultDateTimeParser,\n    userLanguage: 'en',\n  });\n\n  const [channel, setChannel] = useState<Channel>();\n  const [mutes, setMutes] = useState<Array<Mute>>([]);\n  const [latestMessageDatesByChannels, setLatestMessageDatesByChannels] = useState({});\n\n  const clientMutes = (client.user as OwnUserResponse)?.mutes ?? [];\n\n  const appSettings = useRef<Promise<AppSettingsAPIResponse> | null>(null);\n\n  const getAppSettings = () => {\n    if (appSettings.current) {\n      return appSettings.current;\n    }\n    appSettings.current = client.getAppSettings();\n    return appSettings.current;\n  };\n\n  useEffect(() => {\n    if (!client) return;\n\n    const version = process.env.STREAM_CHAT_REACT_VERSION;\n\n    const userAgent = client.getUserAgent();\n    if (!userAgent.includes('stream-chat-react')) {\n      // result looks like: 'stream-chat-react-2.3.2-stream-chat-javascript-client-browser-2.2.2'\n      // the upper-case text between double underscores is replaced with the actual semantic version of the library\n      client.setUserAgent(`stream-chat-react-${version}-${userAgent}`);\n    }\n\n    client.threads.registerSubscriptions();\n    client.polls.registerSubscriptions();\n    client.reminders.registerSubscriptions();\n    client.reminders.initTimers();\n\n    return () => {\n      client.threads.unregisterSubscriptions();\n      client.polls.unregisterSubscriptions();\n      client.reminders.unregisterSubscriptions();\n      client.reminders.clearTimers();\n    };\n  }, [client]);\n\n  useEffect(() => {\n    setMutes(clientMutes);\n\n    const handleEvent = (event: Event) => {\n      setMutes(event.me?.mutes || []);\n    };\n\n    client.on('notification.mutes_updated', handleEvent);\n    return () => client.off('notification.mutes_updated', handleEvent);\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [clientMutes?.length]);\n\n  useEffect(() => {\n    let userLanguage = client.user?.language;\n\n    if (!userLanguage) {\n      const browserLanguage = window.navigator.language.slice(0, 2); // just get language code, not country-specific version\n      userLanguage = isLanguageSupported(browserLanguage)\n        ? browserLanguage\n        : defaultLanguage;\n    }\n\n    const streami18n = i18nInstance || new Streami18n({ language: userLanguage });\n\n    streami18n.registerSetLanguageCallback((t) =>\n      setTranslators((prevTranslator) => ({ ...prevTranslator, t })),\n    );\n\n    streami18n.getTranslators().then((translator) => {\n      setTranslators({\n        ...translator,\n        userLanguage: userLanguage || defaultLanguage,\n      });\n    });\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [i18nInstance]);\n\n  const setActiveChannel = useCallback(\n    async (\n      activeChannel?: Channel,\n      watchers: { limit?: number; offset?: number } = {},\n      event?: React.BaseSyntheticEvent,\n    ) => {\n      if (event && event.preventDefault) event.preventDefault();\n\n      if (activeChannel && Object.keys(watchers).length) {\n        await activeChannel.query({ watch: true, watchers });\n      }\n\n      setChannel(activeChannel);\n    },\n    [],\n  );\n\n  useEffect(() => {\n    setLatestMessageDatesByChannels({});\n  }, [client.user?.id]);\n\n  return {\n    channel,\n    getAppSettings,\n    latestMessageDatesByChannels,\n    mutes,\n    setActiveChannel,\n    translators,\n  };\n};\n","import { useEffect, useRef } from 'react';\n\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\nimport { useNotificationApi } from '../../Notifications/hooks/useNotificationApi';\n\n/**\n * Publishes a persistent system notification while the client is offline and removes it when\n * back online. Must run under `ChatProvider` and `TranslationProvider` (e.g. from a child of `<Chat>`).\n */\nexport const useReportLostConnectionSystemNotification = () => {\n  const { t } = useTranslationContext();\n  const { client } = useChatContext();\n  const { addSystemNotification, removeNotification } = useNotificationApi();\n  const connectionLostNotificationIdRef = useRef<string | null>(null);\n\n  useEffect(() => {\n    if (!t || !client) return;\n\n    const dismissConnectionLostNotification = () => {\n      if (!connectionLostNotificationIdRef.current) return;\n      removeNotification(connectionLostNotificationIdRef.current);\n      connectionLostNotificationIdRef.current = null;\n    };\n\n    const handleConnectionChanged = ({ online }: { online?: boolean }) => {\n      if (!online) {\n        if (connectionLostNotificationIdRef.current) return;\n\n        connectionLostNotificationIdRef.current = addSystemNotification({\n          duration: 0,\n          emitter: 'Chat',\n          message: t('Waiting for network…'),\n          severity: 'loading',\n          type: 'system:network:connection:lost',\n        });\n        return;\n      }\n\n      dismissConnectionLostNotification();\n    };\n\n    client.on('connection.changed', handleConnectionChanged);\n\n    return () => {\n      client.off('connection.changed', handleConnectionChanged);\n      dismissConnectionLostNotification();\n    };\n  }, [addSystemNotification, client, removeNotification, t]);\n};\n","import { useMemo } from 'react';\n\nimport type { ChatContextValue } from '../../../context/ChatContext';\n\nexport const useCreateChatContext = (value: ChatContextValue) => {\n  const {\n    channel,\n    channelsQueryState,\n    client,\n    customClasses,\n    getAppSettings,\n    isMessageAIGenerated,\n    latestMessageDatesByChannels,\n    mutes,\n    searchController,\n    setActiveChannel,\n    theme,\n    useImageFlagEmojisOnWindows,\n  } = value;\n\n  const channelCid = channel?.cid;\n  const channelsQueryError = channelsQueryState.error;\n  const channelsQueryInProgress = channelsQueryState.queryInProgress;\n  const clientValues = `${client.clientID}${Object.keys(client.activeChannels).length}${\n    Object.keys(client.listeners).length\n  }${client.mutedChannels.length}\n  ${client.user?.id}`;\n  const mutedUsersLength = mutes.length;\n\n  const chatContext: ChatContextValue = useMemo(\n    () => ({\n      channel,\n      channelsQueryState,\n      client,\n      customClasses,\n      getAppSettings,\n      isMessageAIGenerated,\n      latestMessageDatesByChannels,\n      mutes,\n      searchController,\n      setActiveChannel,\n      theme,\n      useImageFlagEmojisOnWindows,\n    }),\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [\n      channelCid,\n      channelsQueryError,\n      channelsQueryInProgress,\n      clientValues,\n      getAppSettings,\n      searchController,\n      mutedUsersLength,\n      isMessageAIGenerated,\n    ],\n  );\n\n  return chatContext;\n};\n","import type { Dispatch, SetStateAction } from 'react';\nimport { useState } from 'react';\nimport type { APIErrorResponse, ErrorFromResponse } from 'stream-chat';\n\ntype ChannelQueryState =\n  | 'uninitialized' // the initial state before the first channels query is triggered\n  | 'reload' // the initial channels query (loading the first page) is in progress\n  | 'load-more' // loading the next page of channels\n  | null; // at least one channels page has been loaded and there is no query in progress at the moment\n\nexport interface ChannelsQueryState {\n  error: ErrorFromResponse<APIErrorResponse> | null;\n  queryInProgress: ChannelQueryState;\n  setError: Dispatch<SetStateAction<ErrorFromResponse<APIErrorResponse> | null>>;\n  setQueryInProgress: Dispatch<SetStateAction<ChannelQueryState>>;\n}\n\nexport const useChannelsQueryState = (): ChannelsQueryState => {\n  const [error, setError] = useState<ErrorFromResponse<APIErrorResponse> | null>(null);\n  const [queryInProgress, setQueryInProgress] =\n    useState<ChannelQueryState>('uninitialized');\n\n  return {\n    error,\n    queryInProgress,\n    setError,\n    setQueryInProgress,\n  };\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { useMemo } from 'react';\nimport type { StreamChat } from 'stream-chat';\nimport {\n  ChannelSearchSource,\n  MessageSearchSource,\n  SearchController,\n  UserSearchSource,\n} from 'stream-chat';\n\nimport { NotificationAnnouncer as DefaultNotificationAnnouncer } from '../Accessibility';\nimport { useModalDialogIsOpen } from '../Dialog';\nimport {\n  getNotificationTargetPanels,\n  NotificationConfigurationProvider,\n  type NotificationDisplayFilter,\n} from '../Notifications';\nimport { useChat } from './hooks/useChat';\nimport { useReportLostConnectionSystemNotification } from './hooks/useReportLostConnectionSystemNotification';\nimport { useCreateChatContext } from './hooks/useCreateChatContext';\nimport { useChannelsQueryState } from './hooks/useChannelsQueryState';\nimport type { CustomClasses } from '../../context/ChatContext';\nimport { ChatProvider } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { TranslationProvider } from '../../context/TranslationContext';\nimport { type MessageContextValue, ModalDialogManagerProvider } from '../../context';\nimport type { SupportedTranslations } from '../../i18n/types';\nimport type { Streami18n } from '../../i18n/Streami18n';\n\nconst NetworkConnectionNotificationReporter = () => {\n  useReportLostConnectionSystemNotification();\n  return null;\n};\n\nconst createDefaultNotificationDisplayFilter =\n  (modalIsOpen: boolean): NotificationDisplayFilter =>\n  ({ notification, panel }) => {\n    const targetPanels = getNotificationTargetPanels(notification);\n\n    if (targetPanels.includes('modal')) {\n      return panel === 'modal';\n    }\n\n    if (!modalIsOpen) return true;\n\n    return panel === 'modal';\n  };\n\nconst ModalNotificationConfiguration = ({\n  children,\n  notificationDisplayFilter,\n}: PropsWithChildren<{\n  notificationDisplayFilter?: NotificationDisplayFilter;\n}>) => {\n  const modalIsOpen = useModalDialogIsOpen();\n  const displayFilter = useMemo<NotificationDisplayFilter>(\n    () =>\n      notificationDisplayFilter ?? createDefaultNotificationDisplayFilter(modalIsOpen),\n    [modalIsOpen, notificationDisplayFilter],\n  );\n\n  return (\n    <NotificationConfigurationProvider displayFilter={displayFilter}>\n      {children}\n    </NotificationConfigurationProvider>\n  );\n};\n\nexport type ChatProps = {\n  /** The StreamChat client object */\n  client: StreamChat;\n  /** Object containing custom CSS classnames to override the library's default container CSS */\n  customClasses?: CustomClasses;\n  /** Sets the default fallback language for UI component translation, defaults to 'en' for English */\n  defaultLanguage?: SupportedTranslations;\n  /** Instance of Stream i18n */\n  i18nInstance?: Streami18n;\n  /** Instance of SearchController class that allows to control all the search operations. */\n  searchController?: SearchController;\n  /** Controls whether a notification can be displayed by a NotificationList. */\n  notificationDisplayFilter?: NotificationDisplayFilter;\n  /** Used for injecting className/s to the Channel and ChannelList components */\n  theme?: string;\n  /**\n   * Windows 10 does not support country flag emojis out of the box. It chooses to render these emojis as characters instead. Stream\n   * Chat can override this behavior by loading a custom web font that will render images instead (PNGs or SVGs depending on the platform).\n   * Set this prop to true if you want to use these custom emojis for Windows users.\n   *\n   * Note: requires importing `stream-chat-react/css/v2/emoji-replacement.css` style sheet\n   */\n  useImageFlagEmojisOnWindows?: boolean;\n} & Partial<Pick<MessageContextValue, 'isMessageAIGenerated'>>;\n\n/**\n * Wrapper component for a StreamChat application. Chat needs to be placed around any other chat components\n * as it provides the ChatContext.\n */\nexport const Chat = (props: PropsWithChildren<ChatProps>) => {\n  const {\n    children,\n    client,\n    customClasses,\n    defaultLanguage,\n    i18nInstance,\n    isMessageAIGenerated,\n    notificationDisplayFilter,\n    searchController: customChannelSearchController,\n    theme = 'messaging light',\n    useImageFlagEmojisOnWindows = false,\n  } = props;\n\n  const {\n    channel,\n    getAppSettings,\n    latestMessageDatesByChannels,\n    mutes,\n    setActiveChannel,\n    translators,\n  } = useChat({\n    client,\n    defaultLanguage,\n    i18nInstance,\n  });\n\n  const channelsQueryState = useChannelsQueryState();\n\n  const searchController = useMemo(\n    () =>\n      customChannelSearchController ??\n      new SearchController({\n        sources: [\n          new ChannelSearchSource(client),\n          new UserSearchSource(client),\n          new MessageSearchSource(client),\n        ],\n      }),\n    [client, customChannelSearchController],\n  );\n\n  const chatContextValue = useCreateChatContext({\n    channel,\n    channelsQueryState,\n    client,\n    customClasses,\n    getAppSettings,\n    isMessageAIGenerated,\n    latestMessageDatesByChannels,\n    mutes,\n    searchController,\n    setActiveChannel,\n    theme,\n    useImageFlagEmojisOnWindows,\n  });\n  const { NotificationAnnouncer = DefaultNotificationAnnouncer } = useComponentContext();\n\n  if (!translators.t) return null;\n\n  return (\n    <ChatProvider value={chatContextValue}>\n      <TranslationProvider value={translators}>\n        <ModalDialogManagerProvider>\n          <ModalNotificationConfiguration\n            notificationDisplayFilter={notificationDisplayFilter}\n          >\n            <NetworkConnectionNotificationReporter />\n            <NotificationAnnouncer />\n            {children}\n          </ModalNotificationConfiguration>\n        </ModalDialogManagerProvider>\n      </TranslationProvider>\n    </ChatProvider>\n  );\n};\n","import { useEffect, useState } from 'react';\n\nimport { StreamChat } from 'stream-chat';\n\nimport type {\n  OwnUserResponse,\n  StreamChatOptions,\n  TokenOrProvider,\n  UserResponse,\n} from 'stream-chat';\n\n/**\n * React hook to create, connect and return `StreamChat` client.\n */\nexport const useCreateChatClient = ({\n  apiKey,\n  options,\n  tokenOrProvider,\n  userData,\n}: {\n  apiKey: string;\n  tokenOrProvider: TokenOrProvider;\n  userData: OwnUserResponse | UserResponse;\n  options?: StreamChatOptions;\n}) => {\n  const [chatClient, setChatClient] = useState<StreamChat | null>(null);\n  const [cachedUserData, setCachedUserData] = useState(userData);\n\n  if (userData.id !== cachedUserData.id) {\n    setCachedUserData(userData);\n  }\n\n  const [cachedOptions] = useState(options);\n\n  useEffect(() => {\n    const client = new StreamChat(apiKey, undefined, cachedOptions);\n    let didUserConnectInterrupt = false;\n\n    const connectionPromise = client\n      .connectUser(cachedUserData, tokenOrProvider)\n      .then(() => {\n        if (!didUserConnectInterrupt) setChatClient(client);\n      });\n\n    return () => {\n      didUserConnectInterrupt = true;\n      setChatClient(null);\n      connectionPromise\n        .then(() => client.disconnectUser())\n        .then(() => {\n          console.log(`Connection for user \"${cachedUserData.id}\" has been closed`);\n        });\n    };\n  }, [apiKey, cachedUserData, cachedOptions, tokenOrProvider]);\n\n  return chatClient;\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport clsx from 'clsx';\n\nimport type { LocalMessage } from 'stream-chat';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\n\nexport type WindowProps = {\n  /** optional prop to force addition of class str-chat__main-panel---with-thread-opn to the Window root element */\n  thread?: LocalMessage;\n};\n\nconst UnMemoizedWindow = (props: PropsWithChildren<WindowProps>) => {\n  const { children, thread: propThread } = props;\n\n  const { thread: contextThread } = useChannelStateContext('Window');\n\n  return (\n    <div\n      className={clsx('str-chat__main-panel', {\n        'str-chat__main-panel--thread-open': contextThread || propThread,\n      })}\n    >\n      {children}\n    </div>\n  );\n};\n\n/**\n * A UI component for conditionally displaying a Thread or Channel\n */\nexport const Window = React.memo(UnMemoizedWindow) as typeof UnMemoizedWindow;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,IAAa,WAAW;CACtB,OAAO;CACP,iBAAiB;CACjB,YAAY;CACZ,MAAM;CACN,MAAM;CACN,UAAU;AACZ;;;;;;AAOA,IAAa,cAAc,YAA4C;CACrE,MAAM,CAAC,SAAS,cAAc,SAAkB,SAAS,IAAI;CAE7D,gBAAgB;EACd,IAAI,CAAC,SACH;EAGF,MAAM,2BAA2B,QAAQ,GAAG,wBAAwB,UAAiB;GACnF,MAAM,EAAE,QAAQ;GAChB,MAAM,QAAQ,MAAM;GACpB,IAAI,QAAQ,QAAQ,KAClB,WAAW,KAAK;EAEpB,CAAC;EAED,MAAM,2BAA2B,QAAQ,GAAG,uBAAuB,UAAU;GAC3E,MAAM,EAAE,QAAQ;GAChB,IAAI,QAAQ,QAAQ,KAClB,WAAW,SAAS,IAAI;EAE5B,CAAC;EAED,MAAM,2BAA2B,QAAQ,GAAG,sBAAsB,UAAU;GAC1E,MAAM,EAAE,QAAQ;GAChB,IAAI,QAAQ,QAAQ,KAClB,WAAW,SAAS,IAAI;EAE5B,CAAC;EAED,aAAa;GACX,yBAAyB,YAAY;GACrC,yBAAyB,YAAY;GACrC,yBAAyB,YAAY;EACvC;CACF,GAAG,CAAC,OAAO,CAAC;CAEZ,OAAO,EAAE,QAAQ;AACnB;;;AChDA,IAAM,4BAA4B,cAA8C,EAC9E,WAAW,KACb,CAAC;AAED,IAAa,qCAAqC,EAChD,UACA,YAEA,oBAAC,0BAA0B,UAA3B;CAA2C;CACxC;AACiC,CAAA;AAGtC,IAAa,qCAAqC,WAAW,yBAAyB;;;ACkHtF,IAAa,iBAAiB,MAAM,cAClC,KAAA,CACF;AAEA,IAAa,mBAAmB,EAC9B,UACA,YAIA,oBAAC,eAAe,UAAhB;CAAgC;CAC7B;AACsB,CAAA;AAG3B,IAAa,qBAEX,mBACG;CACH,MAAM,eAAe,WAAW,cAAc;CAE9C,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,OAAO;AACT;;;AC5JA,IAAM,4BAAY,IAAI,QAA0C;;;;;AAMhE,IAAa,uBAAuB,oBAAqC;CACvE,IAAI,UAAU,IAAI,eAAe,GAAG;CAEpC,MAAM,gBAAgB,gBAAgB,MAAM,eAAe;CAC3D,MAAM,YAAY,gBAAgB,aAAa,MAAM,eAAe;CACpE,MAAM,kBAAkB,gBAAgB,kBAAkB,MAAM,eAAe;CAC/E,MAAM,mBAAmB,gBAAgB,oBAAoB,MAAM,eAAe;CAClF,MAAM,gBAAgB,gBAAgB,iBAAiB,MAAM,eAAe;CAC5E,MAAM,YAAY,gBAAgB,aAAa,MAAM,eAAe;CACpE,MAAM,kBAAkB,gBAAgB,kBAAkB,MAAM,eAAe;CAE/E,UAAU,IAAI,uBAAuB;EACnC,gBAAgB,MAAM,KAAK,aAAa;EACxC,gBAAgB,aAAa,MAAM,KAAK,SAAS;EACjD,gBAAgB,kBAAkB,MAAM,KAAK,eAAe;EAC5D,gBAAgB,oBAAoB,MAAM,KAAK,gBAAgB;EAC/D,gBAAgB,iBAAiB,MAAM,KAAK,aAAa;EACzD,gBAAgB,aAAa,MAAM,KAAK,SAAS;EACjD,gBAAgB,kBAAkB,MAAM,KAAK,eAAe;CAC9D,CAAC;AACH;;;;;AAMA,IAAa,0BAA0B,oBAAqC;CAC1E,MAAM,UAAU,UAAU,IAAI,eAAe;CAC7C,UAAU,OAAO,eAAe;CAChC,IAAI,SACF,QAAQ;MAER,gBAAgB,MAAM;AAE1B;;;;AAKA,IAAa,0BAA0B,oBAAqC;CAC1E,UAAU,OAAO,eAAe;AAClC;;;ACnCA,IAAM,uBAAuB,cAC3B,KAAA,CACF;AAEA,SAAgB,wBAAwB,eAAwB;CAC9D,MAAM,eAAe,WAAW,oBAAoB;CAEpD,IAAI,CAAC,cAAc;EACjB,QAAQ,KACN,gIAAgI,cAAc,YAChJ;EAEA,OAAO,CAAC;CACV;CAEA,OAAO;AACT;AAEA,SAAgB,sBAAsB,EAAE,YAAmC;CACzE,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,aAAa,eAAe,YAAY,kBAC9C,uBACF;CAEA,IAAI,CAAC,iBAAiB,OAAO,GAC3B,QAAQ,KACN,yHACF;CAGF,MAAM,EAAE,kBAAkB,wBAAwB,uBAAuB;CAEzE,MAAM,eAAkC,kBAAkB;EACxD,cAAc,OAAO;CACvB,GAAG,CAAC,SAAS,aAAa,CAAC;CAE3B,MAAM,aAAgC,aACnC,MAAM;EACL,EAAE,eAAe;EACjB,oBAAoB,eAAe;EACnC,gBAAgB,UAAU,EAAE,aAAa,QAAQ,CAAC;CACpD,GACA,CAAC,SAAS,eAAe,CAC3B;CAEA,MAAM,cAAc,kBAAkB;EACpC,cAAc,OAAO;CACvB,GAAG,CAAC,eAAe,OAAO,CAAC;CAE3B,MAAM,QAAQ,eACL;EACL;EACA;EACA;EACA;CACF,IACA;EAAC;EAAc;EAAY;EAAa;CAAO,CACjD;CAEA,OACE,oBAAC,qBAAqB,UAAtB;EAAsC;EACnC;CAC4B,CAAA;AAEnC;;;ACnEA,IAAa,qBAAqB,cAChC,KAAA,CACF;;;;AAKA,IAAa,8BAA8B,EACzC,UACA,YAIA,oBAAC,mBAAmB,UAApB;CAAoC;CACjC;AAC0B,CAAA;AAG/B,IAAa,yBAAyB,kBAA2B;CAC/D,MAAM,eAAe,WAAW,kBAAkB;CAElD,IAAI,CAAC,cAAc;EACjB,QAAQ,KACN,4LAA4L,cAAc,YAC5M;EAEA,OAAO,CAAC;CACV;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACGA,IAAa,4BAA4B,EACvC,UACA,cAKA,SAAS,OAAO,GAAG,SAAS;AAgB9B,IAAM,sBAA0D;CAC9D,qBAAqB,YAAY,YAAa,UAAU,eAAe;CAEvE,0BAA0B,CAAC;AAC7B;AAEA,IAAa,gCACX,cAAkD,mBAAmB;AAEvE,IAAa,kCAAkC,EAC7C,eAGI;CACJ,MAAM,CAAC,iBAAiB,sBAAsB,SAC5C,CAAC,CACH;CAEA,MAAM,qBAAqB,aAAa,WAAmB,SAA0B;EACnF,oBAAoB,UAAU;GAAE,GAAG;IAAO,YAAY;EAAK,EAAE;CAC/D,GAAG,CAAC,CAAC;CAEL,MAAM,qBAAqB,aACxB,WAAmB,YAClB,gBAAgB,eAAe,UAAU,eAAe,aAC1D,CAAC,eAAe,CAClB;CAEA,MAAM,cAAc,MAAM,eACjB;EAAE;EAAoB;CAAmB,IAChD,CAAC,oBAAoB,kBAAkB,CACzC;CAEA,OACE,oBAAC,8BAA8B,UAA/B;EAAwC,OAAO;EAC5C;CACqC,CAAA;AAE5C;AAEA,IAAa,yCAC+B;CAExC,OADgB,WAAW,6BACpB,KAAW;AACpB;;;ACzGF,IAAa,eAAe,MAAM,cAA6C,KAAA,CAAS;AAExF,IAAa,wBAAwB,EACnC,UACA,YAGK,oBAAC,aAAa,UAAd;CAA8B;CAAQ;AAAgC,CAAA;AAE7E,IAAa,wBAAwB;CACnC,MAAM,eAAe,WAAW,YAAY;CAE5C,IAAI,CAAC,cAAc;EACjB,QAAQ,KACN,4IACF;EAEA,OAAO,EAAE,aAAa,KAAK;CAC7B;CAEA,OAAO;AACT;;;ACrBA,IAAa,cAAc,MAAM,cAA4C,KAAA,CAAS;AAEtF,IAAa,gBAAgB,EAC3B,UACA,WAIA,OACE,oBAAC,YAAY,UAAb;CAAsB,OAAO,EAAE,KAAK;CACjC;AACmB,CAAA,IACpB;AAEN,IAAa,uBAAuB;CAElC,OADqB,WAAW,WACzB;AACT;;;ACnBA,SAAgB,eAAe,EAC7B,UACA,aACmE;CAEnE,MAAM,kBAAyC;EAAE,GADzB,WAAW,gBACiB;EAAiB,GAAG;CAAU;CAClF,OACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO;EAC/B;CACwB,CAAA;AAE/B;;;ACNA,IAAa,oBAAoB,EAC/B,SAAS,uBACkB;CAC3B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,uBAAuB,uBAAuB,kBAAkB;CAEjF,MAAM,EAAE,YAAY,WADJ,oBAAoB,kBACE;CACtC,MAAM,gBAAgB;GACnB,SAAS,WAAW,EAAE,aAAa;GACnC,SAAS,aAAa,EAAE,eAAe;CAC1C;CAEA,OAAO,WAAW,gBAChB,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,KAAD;GAAG,WAAU;aAAqC,cAAc;EAAY,CAAA;CACzE,CAAA,IACH;AACN;;;ACxBA,IAAM,sBAAqC;CACzC,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,SAAS;CACT,UAAU;CACV,YAAY;CACZ,OAAO;AACT;;;;AAKA,IAAa,kBAAkB,EAAE,UAAU,OAAO,GAAG,WACnD,oBAAC,QAAD;CAAM,GAAI;CAAM,OAAO;EAAE,GAAG;EAAqB,GAAG;CAAM;CACvD;AACG,CAAA;;;ACbR,IAAM,qBAAuC,KAAA;AAE7C,IAAa,2BAA2B,cAEtC,KAAA,CAAS;AAEX,IAAa,6BAA6B;CACxC,MAAM,eAAe,WAAW,wBAAwB;CAExD,IAAI,CAAC,cAAc;EACjB,QAAQ,KACN,kFACF;EAEA,OAAO;CACT;CAEA,OAAO,aAAa;AACtB;;;ACRA,IAAa,kBAAkB,EAAE,eAAkC;CACjE,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,EAAE;CAC3D,MAAM,CAAC,eAAe,oBAAoB,SAAS,EAAE;CACrD,MAAM,wBAAwB,OAA2B;EACvD,WAAW;EACX,QAAQ;CACV,CAAC;CACD,MAAM,uBAAuB,OAA0B;EACrD,WAAW,KAAA;EACX,QAAQ,KAAA;CACV,CAAC;CACD,MAAM,eAAe,OAAO,KAAK;CAEjC,MAAM,sBAAsB,aAAa,aAA+B;EACtE,IAAI,CAAC,qBAAqB,QAAQ,WAAW;EAC7C,aAAa,qBAAqB,QAAQ,SAAS;EACnD,qBAAqB,QAAQ,YAAY,KAAA;CAC3C,GAAG,CAAC,CAAC;CAEL,MAAM,uBAAuB,kBAAkB;EAC7C,oBAAoB,WAAW;EAC/B,oBAAoB,QAAQ;CAC9B,GAAG,CAAC,mBAAmB,CAAC;CAExB,MAAM,WAAW,aACd,SAAS,WAAW,aAAa;EAChC,MAAM,kBACJ,aAAa,cAAc,sBAAsB;EACnD,MAAM,WAAW,sBAAsB,QAAQ,YAAY;EAE3D,sBAAsB,QAAQ,YAAY;EAC1C,oBAAoB,QAAQ;EAC5B,gBAAgB,EAAE;EAClB,qBAAqB,QAAQ,YAAY,iBAAiB;GACxD,IAAI,aAAa,SAAS;GAC1B,IAAI,sBAAsB,QAAQ,cAAc,UAAU;GAC1D,gBAAgB,OAAO;GACvB,qBAAqB,QAAQ,YAAY,KAAA;EAC3C,GAAG,EAAE;CACP,GACA,CAAC,mBAAmB,CACtB;CAEA,gBAAgB;EACd,aAAa,UAAU;EAEvB,aAAa;GACX,aAAa,UAAU;GACvB,qBAAqB;EACvB;CACF,GAAG,CAAC,oBAAoB,CAAC;CAEzB,MAAM,eAAe,eAAe,EAAE,SAAS,IAAI,CAAC,QAAQ,CAAC;CAE7D,MAAM,uBAAuB,kBAAkB,SAAS,MAAM,CAAC,CAAC;CAEhE,OACE,qBAAC,yBAAyB,UAA1B;EAAmC,OAAO;YAA1C,CACG,UACD,oBAAC,QAAD;GAA8B;GAAsB,QAAA;aAClD,qBAAC,gBAAD,EAAA,UAAA,CACE,oBAAC,OAAD;IACE,eAAY;IACZ,aAAU;IACV,iBAAc;IACd,eAAY;IACZ,MAAK;cAEJ;GACE,CAAA,GACL,oBAAC,OAAD;IACE,eAAY;IACZ,aAAU;IACV,iBAAc;IACd,eAAY;IACZ,MAAK;cAEJ;GACE,CAAA,CACS,EAAA,CAAA;EACV,CAAA,CACyB;;AAEvC;;;AC5EA,IAAM,yCAAoE;AAE1E,IAAM,+CACJ,EACE,eAAe,iCACjB;AAEF,IAAM,mCACJ,MAAM,cACJ,4CACF;AAMF,IAAa,qCAAqC,EAChD,UACA,oBAC4C;CAC5C,MAAM,sBAAsB,WAAW,gCAAgC;CACvE,MAAM,QAAQ,eACL,EACL,eAAe,iBAAiB,oBAAoB,cACtD,IACA,CAAC,eAAe,oBAAoB,aAAa,CACnD;CAEA,OACE,oBAAC,iCAAiC,UAAlC;EAAkD;EAC/C;CACwC,CAAA;AAE/C;AAEA,IAAa,4CACX,WAAW,gCAAgC;;;;;;;ACxB7C,IAAa,oBAAoB,YAAsD;CACrF,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,kBAAkB,oCAAoC;CAC9D,MAAM,EAAE,oBAAoB,eAAe,QAAQ,UAAU,WAAW,CAAC;CACzE,MAAM,WAAW,aACd,UAAoC;EAEnC,OAAO,EACL,eAFoB,MAAM,cAEG,QAAQ,iBAAiB;GACpD,IACE,SACA,CAAC,uBAAuB,cAAc,OAAO,EAC3C,cACF,CAAC,GAED,OAAO;GAGT,IACE,sBACA,CAAC,cAAc;IACb;IACA;IACA;IACA;GACF,CAAC,GAED,OAAO;GAGT,OAAO,SAAS,OAAO,YAAY,IAAI;EACzC,CAAC,EACH;CACF,GACA;EAAC;EAAoB;EAAe;EAAe;EAAQ;CAAK,CAClE;CAEA,MAAM,EAAE,kBAAkB,cAAc,OAAO,cAAc,OAAO,QAAQ;CAE5E,OAAO;AACT;;;AC1EA,IAAM,sBAAsB,WAC1B,QAAQ,KAAK,EAAE,QAAQ,oBAAoB,GAAG,KAAK;AAErD,IAAM,uBACJ,iBACA,eACI,kBAAkB,GAAG,gBAAgB,GAAG,eAAe,KAAA;;;;;;;;;;;AAY7D,IAAa,sBAAsB,WAAoB;CACrD,MAAM,kBAAkB,mBAAmB,MAAM;CAEjD,OAAO,eACE;EACL,eAAe,oBAAoB,iBAAiB,aAAa;EACjE,SAAS,oBAAoB,iBAAiB,OAAO;CACvD,IACA,CAAC,eAAe,CAClB;AACF;;;AC3BA,IAAa,OAAO,WAAkD,SAAS,UAC7E,EAAE,UAAU,WAAW,GAAG,SAC1B,KACA;CACA,OACE,oBAAC,OAAD;EAAK,GAAI;EAAO,WAAW,KAAK,wBAAwB,SAAS;EAAQ;EACtE;CACE,CAAA;AAET,CAAC;AAUD,IAAa,SAAS,WAA6C,SAAS,YAC1E,EAAE,UAAU,WAAW,aAAa,eAAe,MAAM,OAAO,SAAS,GAAG,SAC5E,KACA;CACA,MAAM,EAAE,aAAa,gBAAgB;CACrC,MAAM,EAAE,eAAe,sBAAsB,SAAS,mBACpD,mBAAmB,QAAQ;CAC7B,MAAM,kBAAkB,WAAW;CACnC,MAAM,wBAAwB,iBAAiB;CAE/C,OACE,oBAAC,OAAD;EAAK,GAAI;EAAO,WAAW,KAAK,0BAA0B,SAAS;EAAQ;YACxE,QACC,qBAAA,YAAA,EAAA,UAAA,CACG,QAAQ,oBAAC,MAAD,CAAO,CAAA,GAChB,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,MAAD;IAAI,WAAU;IAAgC,IAAI;cAC/C;GACC,CAAA,GACH,eACC,oBAAC,KAAD;IACE,WAAU;IACV,IAAI;cAEH;GACA,CAAA,CAEF;IACL,EAAA,CAAA,IAEF;CAEC,CAAA;AAET,CAAC;AAaD,IAAa,QAAQ;CACnB,SAZc,WAAkD,SAAS,aACzE,EAAE,UAAU,WAAW,GAAG,SAC1B,KACA;EACA,OACE,oBAAC,OAAD;GAAK,GAAI;GAAO,WAAW,KAAK,2BAA2B,SAAS;GAAQ;GACzE;EACE,CAAA;CAET,CAGE;CACA;CACA;AACF;;;ACvDA,SAAgB,gBAAuC,EACrD,WACA,QACA,MACA,WACA,kBACA,WACA,gCAAgC,SACV;CACtB,MAAM,CAAC,eAAe,oBAAoB,SAAmB,IAAI;CAEjE,MAAM,CAAC,2BAA2B,gCAChC,SAA2B,IAAI;CAEjC,MAAM,EACJ,WAAW,iBACX,MACA,UACA,QACA,GACA,MACE,mBAAmB;EACrB;EACA,QAAQ;EACR;EACA,WAAW,6BAA6B;CAC1C,CAAC;CAED,IAAI,CAAC,6BAA6B,iBAAiB,cAAc,iBAC/D,6BAA6B,eAAe;MACvC,IAAI,6BAA6B,CAAC,eACvC,6BAA6B,IAAI;CAInC,MAAM,qBAAqB,OAA2B,IAAI;CAC1D,IAAI,QAAQ,oBAAoB,CAAC,mBAAmB,SAClD,mBAAmB,UAAU;CAE/B,IAAI,CAAC,MACH,mBAAmB,UAAU;CAE/B,MAAM,qBAAqB,OAAO,mBAAmB,UAAU;CAE/D,gBAAgB;EACd,KAAK,aAAa,kBAAkB;CACtC,GAAG,CAAC,oBAAoB,IAAI,CAAC;CAE7B,gBAAgB;EACd,KAAK,YAAY,aAAa;CAChC,GAAG,CAAC,eAAe,IAAI,CAAC;CAExB,gBAAgB;EACd,IAAI,QAAQ,iBAAiB,oBAK3B,SAAS;CAEb,GAAG;EAAC;EAAM;EAAW;EAAe;EAAQ;EAAW;CAAkB,CAAC;CAE1E,gBAAgB;EACd,IAAI,CAAC,iBAAiB,CAAC,+BAA+B;EAEtD,MAAM,iBAAiB,IAAI,eAAe,MAAM;EAEhD,eAAe,QAAQ,aAAa;EAEpC,aAAa;GACX,eAAe,WAAW;EAC5B;CACF,GAAG;EAAC;EAAe;EAAQ;CAA6B,CAAC;CAEzD,IAAI,iBAAiB,CAAC,MACpB,iBAAiB,IAAI;CAGvB,OAAO;EACL,WAAW,6BAA6B;EACxC;EACA,QAAQ;GACN,MAAM,KAAK;GACX,UAAU;GACV,KAAK,KAAK;EACZ;CACF;AACF;AAoBA,IAAa,gBAAgB,EAC3B,YAAY,MACZ,UACA,WACA,qBACA,oBAAoB,GACpB,iBACA,QAAQ,MACR,IACA,QACA,YAAY,QACZ,mBAAmB,MACnB,UACA,WACA,WACA,+BACA,GAAG,mBACoB;;;;;;;;;;;;;;;;;;CAkBvB,MAAM,SAAS,UAAU;EAAE;EAAqB;EAAiB;CAAG,CAAC;CACrE,MAAM,OAAO,gBAAgB,IAAI,eAAe;CAChD,MAAM,CAAC,cAAc,mBAAmB,SAAS,IAAI;CACrD,MAAM,kBAAkB,OAA8B,IAAI;CAC1D,MAAM,YAAY,CAAC,QAAQ;CAE3B,gBAAgB;EACd,IAAI,MAAM;GACR,gBAAgB,IAAI;GACpB,IAAI,gBAAgB,SAAS;IAC3B,aAAa,gBAAgB,OAAO;IACpC,gBAAgB,UAAU;GAC5B;GACA;EACF;EAEA,IAAI,CAAC,cAAc;EACnB,IAAI,CAAC,mBAAmB;GACtB,gBAAgB,KAAK;GACrB;EACF;EAEA,gBAAgB,UAAU,iBAAiB;GACzC,gBAAgB,KAAK;GACrB,gBAAgB,UAAU;EAC5B,GAAG,iBAAiB;CACtB,GAAG;EAAC;EAAmB;EAAM;CAAY,CAAC;CAE1C,sBACc;EACV,IAAI,gBAAgB,SAAS,aAAa,gBAAgB,OAAO;CACnE,GACA,CAAC,CACH;CAEA,MAAM,EACJ,WAAW,iBACX,kBACA,WACE,gBAAgC;EAClC;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;CACF,CAAC;CAED,gBAAgB;EACd,IAAI,CAAC,MAAM;EACX,MAAM,gBAAgB,UAAyB;GAC7C,IAAI,MAAM,QAAQ,YAAY,MAAM,kBAAkB;GACtD,QAAQ,MAAM;EAChB;EAEA,SAAS,iBAAiB,SAAS,YAAY;EAE/C,aAAa;GACX,SAAS,oBAAoB,SAAS,YAAY;EACpD;CACF,GAAG,CAAC,QAAQ,IAAI,CAAC;CAGjB,IAAI,CAAC,cACH,OAAO;CAGT,MAAM,GACH,qBAAqB,kBACrB,eAAe,YACf,oBAAoB,iBACpB,eAAe,WAChB,MACA,GAAG,mBACD;CACJ,MAAM,eAAe,YAAa,QAAQ,WAAY;CACtD,MAAM,oBAAoB,YAAY,OAAO;CAC7C,MAAM,oBAAoB,iBAAiB,KAAA,IAAY;CAEvD,OACE,oBAAC,mBAAD;EAAmB,UAAU;EAAqB;YAChD,oBAAC,YAAD;GAAY,WAAW;GAAO,SAAS;GAAW,cAAA;aAChD,oBAAC,OAAD;IACE,GAAI;IACJ,oBAAkB;IAClB,cAAY;IACZ,mBAAiB;IACjB,cAAY;IACZ,WAAW,KAAK,6BAA6B,SAAS;IACtD,8BAA4B,YAAY,YAAY;IACpD,2BAAyB;IACzB,eAAY;IACZ,KAAK;IACL,MAAM;IACN,OAAO;IACP,UAAU,OAAO,aAAa,cAAc,WAAW;IAEtD;GACE,CAAA;EACK,CAAA;CACK,CAAA;AAEvB;;;AC9PA,IAAa,cAAc,EAAE,WAAW,WAAW,GAAG,YAA6B;CACjF,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,QAAD;EACE,YAAW;EACX,cAAY,YAAY,EAAE,YAAY,IAAI,EAAE,WAAW;EACvD,UAAA;EACA,WAAW,KAAK,yBAAyB,SAAS;EAClD,eAAa,YAAY,gBAAgB;EACzC,MAAK;EACL,SAAQ;EACR,GAAI;YAEH,YAAY,oBAAC,eAAD,CAAgB,CAAA,IAAI,oBAAC,cAAD,CAAe,CAAA;CAC1C,CAAA;AAEZ;;;;;;;;;;;;;;;ACCA,IAAa,WAAW,EACtB,UACA,WACA,iBACA,IAAI,UACJ,SACA,GAAG,kBACe;CAClB,MAAM,EAAE,gBAAgB,yBAAyB,oBAAoB;CAErE,MAAM,eAAe,gBAAgB,UAAU,eAAe;CAC9D,OACE,oBAAC,cAAD;EAAc,GAAI;EAA8B;EAAiB,IAAI;YAClE,gBACC,oBAAC,eAAD;GAA0B;GAAoB;GAC3C;EACY,CAAA;CAEL,CAAA;AAElB;AAIA,IAAM,wBAAwB,EAAE,UAAU,WAAW,cAAkC;CACrF,MAAM,EAAE,MAAM,sBAAsB;CAEpC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,UACD,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,2BAA2B;GACzC,UAAA;GACA,WAAW,KAAK,WAAW,iCAAiC;GAC5D,SAAS;GACT,MAAK;GACL,SAAQ;aAER,oBAAC,WAAD,CAAY,CAAA;EACN,CAAA,CACL;;AAET;;;ACpDA,IAAM,eAAe,SAAkB;CACrC,MAAM,QAAQ;CAEd,IAAI,CAAC,QAAQ,KAAK,KAAK,EAAE,WAAW,GAClC,OAAO;CAGT,MAAM,WAAW,MAAM,KAAK,MAAM,SAAS,KAAK,KAAK,CAAC,CAAC;CAEvD,IAAI,CAAC,SAAS,QACZ,OAAO;CAQT,OAAO,GAJc,SAAS,GAAG,CAAC,EAAG,KAElB,SAAS,SAAS,IAAI,SAAS,GAAG,EAAE,EAAG,KAAK;AAGjE;;;;AAKA,IAAa,UAAU,EACrB,WACA,UACA,UACA,MACA,UACA,GAAG,WACc;CACjB,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CAExC,sBAAsB,SAAS,KAAK,GAAG,CAAC,QAAQ,CAAC;CAEjD,MAAM,aAAa,UAAU,SAAS,KAAK;CAC3C,MAAM,iBAAiB,WAAW,KAAK;CAEvC,MAAM,oBAAoB,cAAc;EACtC,MAAM,WAAW,YAAY,UAAU;EAEvC,IAAI,SAAS,QAAQ,SAAS,MAC5B,OAAO,SAAS,OAAO,CAAC;EAG1B,OAAO;CACT,GAAG,CAAC,YAAY,IAAI,CAAC;CAErB,MAAM,YAAY,OAAO,aAAa,YAAY,YAAY,CAAC;CAE/D,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,oBAAoB,WAAW;GAC7C,sCAAsC,kBAAkB,SAAS;GACjE,gCAAgC,CAAC,kBAAkB;GACnD,gCAAgC,kBAAkB,WAAW;IAC5D,0BAA0B,SAAS,OAAO,SAAS;EACtD,CAAC;EACD,eAAY;EACZ,MAAK;EACL,OAAO;EACP,GAAI;YAVN,CAYG,OAAO,aAAa,aACnB,oBAAC,OAAD,EACE,WAAW,KAAK,iCAAiC;GAC/C,0CAA0C,CAAC;GAC3C,yCAAyC;EAC3C,CAAC,EACF,CAAA,GAEF,YACC,oBAAC,OAAD;GACE,KAAK;GACL,WAAU;GACV,eAAY;GACZ,eAAe,SAAS,IAAI;GAC5B,KAAK;EACN,CAAA,IAED,qBAAA,YAAA,EAAA,UAAA,CACG,CAAC,CAAC,kBAAkB,UACnB,oBAAC,OAAD;GAAK,WAAU;GAA4B,eAAY;aACpD;EACE,CAAA,GAEN,CAAC,kBAAkB,UAAU,oBAAC,UAAD,CAAW,CAAA,CACzC,EAAA,CAAA,CAED;;AAET;;;;;;;ACtFA,IAAa,SAAS,EACpB,UACA,WACA,OAAO,MACP,UAAU,WACV,GAAG,gBAEH,oBAAC,OAAD;CACE,GAAI;CACJ,WAAW,KACT,mBACA,4BAA4B,WAC5B,GAAG,yBAAyB,SAAS,KAAK,GAC1C,SACF;CAEC;AACE,CAAA;AAGP,IAAa,cAAc,EACzB,WACA,OAAO,MACP,GAAG,WAEH,oBAAC,OAAD;CAAO,GAAI;CAAiB;CAAiB;CAAM,SAAQ;WACzD,oBAAC,yBAAD,CAA0B,CAAA;AACrB,CAAA;;;AC9CT,SAAgB,YAAY,EAC1B,WACA,WAAW,GACX,WAAW,YAAY,OACvB,cAAc,CAAC,GACf,QAOC;CACD,MAAM,EAAE,QAAA,WAAS,WAAkB,oBAAoB,YAAY,IAAI;CAEvE,MAAM,sBAAsB,cACnB,YAAY,SAAS,WAAW,YAAY,MAAM,GAAG,QAAQ,IAAI,aACxE,CAAC,aAAa,QAAQ,CACxB;CACA,MAAM,gBAAgB,YAAY,SAAS,oBAAoB;CAE/D,IAAI,CAAC,YAAY,QACf,OAAO;CAGT,OACE,qBAAC,WAAD;EACE,WAAW,KAAK,0BAA0B,GACvC,gCAAgC,SAAS,OAAO,SAAS,SAC5D,CAAC;EACD,eAAY;YAJd,CAMG,oBAAoB,KAAK,MAAM,UAC9B,oBAAC,UAAD;GACE,UAAU,KAAK;GAET;GACN,UAAU,KAAK;EAChB,GAHM,KAAK,MAAM,GAAG,KAAK,SAAS,GAAG,KAAK,SAAS,GAAG,OAGtD,CACF,GACA,OAAO,kBAAkB,YAAY,gBAAgB,KACpD,qBAAC,OAAD;GACE,WAAU;GACV,eAAY;GACZ,MAAM,aAAa;GACnB,SAAQ;aAJV,CAKC,KACG,aACG;IAEA;;AAEf;;;ACjDA,IAAa,iBAAiB,EAC5B,gBACA,UACA,MACA,UACA,GAAG,kBACqB;CAcxB,OAAO,oBAAC,aAAD;EAAa,gBAbA,cAAc;GAChC,IAAI,kBAAkB,eAAe,SAAS,GAC5C,OAAO;GAGT,OAAO,CACL;IACE;IACA;GACF,CACF;EACF,GAAG;GAAC;GAAgB;GAAU;EAAQ,CAEF;EAAmB;EAAM,GAAI;CAAc,CAAA;AACjF;;;;;;;ACPA,IAAa,eAAe,EAC1B,WACA,WACA,iBAAiB,CAAC,GAClB,UACA,MACA,GAAG,WACmB;CACtB,MAAM,yBAAyB,cACtB,eAAe,SAAS,IAAI,eAAe,MAAM,GAAG,CAAC,IAAI,gBAChE,CAAC,cAAc,CACjB;CACA,MAAM,gBAAgB,eAAe,SAAS,uBAAuB;CAErE,IAAI,eAAe,SAAS,GAAG;EAC7B,MAAM,YAAY,eAAe;EAEjC,OACE,oBAAC,QAAD;GACE,UAAU,WAAW;GACX;GACJ;GACN,UAAU,WAAW;GACrB,GAAI;EACL,CAAA;CAEL;CAEA,IAAI,aAAkC;CACtC,IAAI,SAAS,OACX,aAAa;MACR,IAAI,SAAS,MAClB,aAAa;MACR,IAAI,SAAS,MAClB,aAAa;CAGf,OACE,qBAAC,OAAD;EACE,WAAW,KACT,0BACA;GACE,mCAAmC,OAAO,aAAa,aAAa,CAAC;GACrE,kCAAkC,OAAO,aAAa,aAAa;IAClE,gCAAgC,SAAS,OAAO,SAAS;EAC5D,GACA,SACF;EACA,eAAY;EACZ,MAAK;EACL,GAAI;YAZN,CAcG,uBAAuB,KAAK,EAAE,IAAI,UAAU,YAAY,UACvD,oBAAC,QAAD;GACY;GAEV,MAAM;GACI;EACX,GAHM,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAGvC,CACF,GACA,OAAO,kBAAkB,YAAY,gBAAgB,KACpD,qBAAC,OAAD;GACE,WAAU;GACV,eAAY;GACZ,MAAM;GACN,SAAQ;aAJV,CAKC,KACG,aACG;IAEN;;AAET;;;AC/FA,IAAM,gCAAgC;CAAC;CAAa;CAAW;CAAO;AAAM;AAI5E,IAAM,+BAA+B,QAClC,8BAAoD,SAAS,GAAG;AAQnE,IAAa,2BAA2B,EACtC,aACA,WACA,UACgD;CAChD,IAAI,aAAa,KAAK,CAAC,4BAA4B,GAAG,GAAG,OAAO;CAEhE,MAAM,YAAY,YAAY;CAE9B,IAAI,QAAQ,QAAQ,OAAO;CAC3B,IAAI,QAAQ,OAAO,OAAO;CAC1B,IAAI,gBAAgB,IAAI,OAAO,QAAQ,YAAY,YAAY;CAC/D,IAAI,QAAQ,WAAW,OAAO,eAAe,IAAI,YAAY,cAAc;CAE3E,OAAO,eAAe,YAAY,IAAI,cAAc;AACtD;AAcA,IAAM,yBAA0D,UAAe;CAC7E,MAAM,gBAAgB,SAAS;CAC/B,IAAI,EAAE,yBAAyB,UAAU,OAAO;CAEhD,OAAO,MAAM,WAAW,SAAS,gBAAgB,WAAW,SAAS,aAAa;AACpF;AAEA,IAAa,mCAAoE,EAC/E,aAAa,SAAS,KAAK,MAAM,GACjC,kBAAkB,UAAU,sBAAsB,KAAK,GACvD,eAC8C;CAC9C,MAAM,iBAAiB,UAAoC;EACzD,MAAM,QAAQ,SAAS,KAAK;EAE5B,MAAM,YAAY,wBAAwB;GACxC,aAFkB,eAAe,OAAO,KAExC;GACA,WAAW,MAAM;GACjB,KAAK,MAAM;EACb,CAAC;EAED,IAAI,cAAc,MAAM;EAExB,MAAM,eAAe;EACrB,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,UAAU;EACf,UAAU,UAAU,KAAK;CAC3B;CAEA,OAAO;AACT;;;ACkBA,IAAa,yBAAyB,EACpC,UACA,WACA,SACA,YACA,MACA,OACA,OAAO,YACP,cAAc,kBACd,SACA,GAAG,YAEH,qBAAC,UAAD;CACE,GAAI;CACJ,WAAW,KACT,kCACA;EACE,gDAAgD;GAC/C,mCAAmC,YAAY,OAAO,YAAY;CACrE,GACA,SACF;CACM;CACN,MAAK;WAXP;EAaG,QAAQ,oBAAC,MAAD,EAAM,WAAU,uCAAwC,CAAA;EAChE,QACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;GAAK,WAAU;aAAyC;EAAW,CAAA,GACnE,oBAAC,OAAD;GAAK,WAAU;aAA2C;EAAa,CAAA,CACvE,EAAA,CAAA,IAEF,oBAAC,OAAD;GAAK,WAAU;GAAyC;EAAc,CAAA;EAEvE,CAAC,CAAC,cACD,oBAAC,aAAD,EAAa,WAAU,+CAAgD,CAAA;CAEnE;;AAMV,IAAa,yBAAyB,EACpC,UACA,WACA,UACA,OAAO,YACP,UACA,GAAG,YAEH,qBAAC,UAAD;CACE,GAAI;CACJ,WAAW,KACT,sEACA,SACF;CACM;CACN,MAAK;WAPP,CASE,oBAAC,QAAD;EAAkB;EAAU,MAAK;EAAe;CAAW,CAAA,GAC3D,oBAAC,OAAD;EAAK,WAAU;YAAyC,YAAY;CAAc,CAAA,CAC5E;;AASV,IAAa,0BAA0B,EACrC,UACA,WACA,OACA,OACA,OAAO,YACP,GAAG,YAEH,qBAAC,UAAD;CACE,GAAI;CACJ,WAAW,KACT,uEACA,SACF;CACM;CACN,MAAK;WAPP,CASE,oBAAC,QAAD;EAAM,WAAU;YACb;CACG,CAAA,GACN,oBAAC,OAAD;EAAK,WAAU;YAAyC,YAAY;CAAW,CAAA,CACzE;;AAUV,IAAM,gCAAgC,EACpC,UACA,WACA,SACA,uBACA,mBAAmB,eACnB,kBAAkB,KAClB,GAAG,kBACsD;CACzD,MAAM,EAAE,WAAW,kBAAkB,GAAG,8BACtC,yBAAyB,CAAC;CAC5B,MAAM,EAAE,uBAAuB,4BAA4B,sBAAsB;CACjF,MAAM,YAAY,OAAiC,IAAI;CACvD,MAAM,CAAC,iBAAiB,sBAAsB,SAAgC,IAAI;CAClF,MAAM,sBAAsB,OAAO,KAAK;CACxC,MAAM,qBAAqB,OAA8B,IAAI;CAC7D,MAAM,WAAW,cAAc,WAAW,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;CACnF,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAAE,IAAI,SAAS,CAAC;CAC5E,MAAM,eAAe,gBAAgB,UAAU,eAAe,EAAE;CAEhE,gBAAgB;EACd,IAAI,CAAC,cAAc;EACnB,sBAAsB;EACtB,aAAa,wBAAwB;CACvC,GAAG;EAAC;EAAc;EAAuB;CAAuB,CAAC;CACjE,MAAM,EACJ,WAAW,iBACX,kBACA,WACE,gBAAgC;EAClC,QAAQ;EACR,MAAM;EACN,WAAW;EACX,kBAAkB,UAAU;CAC9B,CAAC;CAED,MAAM,oBAAoB,kBAAkB;EAC1C,IAAI,mBAAmB,SAAS,aAAa,mBAAmB,OAAO;EACvE,mBAAmB,UAAU,iBAAiB;GAC5C,IAAI,oBAAoB,SAAS;GACjC,OAAO,MAAM;EACf,GAAG,GAAG;CACR,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,kBAAkB,kBAAkB;EACxC,oBAAoB,UAAU;CAChC,GAAG,CAAC,CAAC;CAEL,MAAM,sBAAsB,kBAAkB;EAC5C,oBAAoB,UAAU;CAChC,GAAG,CAAC,CAAC;CAEL,MAAM,eAAe,kBAAkB;EACrC,oBAAoB;EACpB,kBAAkB;CACpB,GAAG,CAAC,qBAAqB,iBAAiB,CAAC;CAE3C,MAAM,cAAc,aACjB,UAAiB;EAChB,MAAM,eAAe,UAAU;EAC/B,IAAI,CAAC,gBAAgB,CAAC,cAAc;EACpC,MAAM,gBAAgB;EACtB,kBAAkB;EAClB,aAAa,MAAM;CACrB,GACA;EAAC;EAAmB;EAAc;CAAS,CAC7C;CAEA,MAAM,gCAAgC;EACpC,IAAI,cAAc;EAClB,OAAO,KAAK;EACZ,gBAAgB;CAClB;CAEA,gBAAgB;EACd,MAAM,eAAe,UAAU;EAC/B,IAAI,CAAC,gBAAgB,CAAC,cAAc;EACpC,MAAM,gBAAgB,UAAyB;GAC7C,IAAI,MAAM,QAAQ,UAAU;GAC5B,YAAY,KAAK;GACjB,aAAa;EACf;EAEA,SAAS,iBAAiB,SAAS,cAAc,EAAE,SAAS,KAAK,CAAC;EAElE,aAAa;GACX,SAAS,oBAAoB,SAAS,cAAc,EAAE,SAAS,KAAK,CAAC;EACvE;CACF,GAAG;EAAC;EAAc;EAAa;CAAY,CAAC;CAE5C,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,uBAAD;EACE,iBAAe;EACf,iBAAc;EACd,WAAW,KAAK,WAAW,iCAAiC,EAC1D,+CAA+C,aACjD,CAAC;EACD,YAAA;EACA,QAAQ;EACR,UAAU,UAAU;GAClB,MAAM,gBAAgB;GACtB,OAAO,OAAO;EAChB;EACA,SAAS;EACT,cAAc;EACd,cAAc;EACd,GAAI;EACJ,KAAK;EAEJ;CACoB,CAAA,GACtB,gBACC,oBAAC,OAAD;EACE,WAAW,KAAK,6CAA6C,gBAAgB;EAC7E,2BAAyB;EACzB,2BAAyB;EACzB,SAAS,UAAU;GAIjB,IAFE,MAAM,yBAAyB,QAC/B,iBAAiB,SAAS,MAAM,aAAa,GACtB;GACzB,aAAa;EACf;EACA,SAAS;EACT,cAAc;EACd,cAAc;EACd,MAAM,YAAY;GAChB,iBAAiB,OAAO;GACxB,mBAAmB,OAAO;EAC5B;EACA,OAAO;EACP,UAAU;EACV,GAAI;YAEJ,oBAAC,SAAD,CAAU,CAAA;CACP,CAAA,CAEP,EAAA,CAAA;AAEN;AAKA,IAAa,qBAAqB,UAAkC;CAClE,MAAM,EACJ,SACA,uBACA,kBACA,iBACA,GAAG,gBACD;CACJ,IAAI,SACF,OACE,oBAAC,8BAAD;EACE,GAAI;EACK;EACc;EACL;EACD;CAClB,CAAA;CAIL,OAAO,oBAAC,uBAAD,EAAuB,GAAI,YAAc,CAAA;AAClD;AAEA,IAAa,yBAAyB,EACpC,UACA,WACA,OAAO,YACP,GAAG,YAEH,oBAAC,UAAD;CACE,GAAI;CACJ,WAAW,KAAK,uCAAuC,SAAS;CAC1D;CACN,MAAK;CAEJ;AACK,CAAA;AAGV,IAAa,qBAAqB,EAChC,UACA,WACA,GAAG,YAEH,oBAAC,OAAD;CAAK,GAAI;CAAO,WAAW,KAAK,kCAAkC,SAAS;CACxE;AACE,CAAA;AAGP,IAAa,mBAAmB,EAC9B,UACA,WACA,GAAG,YAEH,oBAAC,OAAD;CAAK,GAAI;CAAO,WAAW,KAAK,gCAAgC,SAAS;CACtE;AACE,CAAA;AAGP,IAAa,kBAAkB,MAAM,WACnC,SAAS,gBAAgB,EAAE,WAAW,OAAO,QAAQ,GAAG,SAAS,KAAK;CACpE,OACE,oBAAC,OAAD;EACE,GAAI;EACJ,WAAW,KAAK,0BAA0B,SAAS;EAC9C;EACC;CACP,CAAA;AAEL,CACF;AAgBA,IAAa,yDAAyD;CACpE;CACA;CACA;AACF,EAAE,KAAK,GAAG;AAEV,IAAM,8CAA8C,SAAsB;CAGxE,IAAI,KAAK,iBAAiB,QAAQ,KAAK,eAAe,GAAG,OAAO;CAIhE,IAAI,KAAK,QAAQ,OAAO;CAExB,IADgB,KAAK,MAAM,YACX,QAAQ,OAAO;CAG/B,OAAO;AACT;AAQA,IAAM,gDACJ,iBACA,eAAuB,2DAEvB,MAAM,KAAK,iBAAiB,iBAA8B,YAAY,KAAK,CAAC,CAAC,EAAE,OAC7E,0CACF;AAEF,IAAM,wCAAwC,EAC5C,iBACA,wBAIoC;CACpC,MAAM,SACJ,sBACC,SAAS,yBAAyB,cAAc,SAAS,gBAAgB;CAE5E,IAAI,CAAC,QAAQ,OAAO;EAAE,OAAO;EAAI,QAAQ;CAAK;CAM9C,OAAO;EAAE,OAJK,6CAA6C,eAAe,EAAE,WACzE,aAAa,aAAa,MAGpB;EAAO;CAAO;AACzB;AAEA,IAAM,wCAAwC,EAC5C,iBACA,cAII;CACJ,IAAI,CAAC,SAAS,OAAO;CAGrB,IAAI,QAAQ,QAAQ,aAAa,OAAO,QAAQ;CAGhD,IAAI,QAAQ,SAAS,GACnB,OACE,6CAA6C,eAAe,EAAE,QAAQ,UAAU;CAIpF,OAAO;AACT;AAmBA,IAAM,qBAAqB,MAAM,cAC/B,KAAA,CACF;AAEA,IAAa,8BACX,WAAW,kBAAkB;;;;;;;;AA4D/B,SAAgB,mBAAmB,EACjC,wBACA,YAAY,QACZ,UACA,WACA,mBAAmB,MACnB,QACA,OACA,cACA,oBACA,eACA,SACA,mBACA,qBACA,GAAG,SACuB;CAC1B,MAAM,YAAY,eACT;EACL;EACA;EACA;EACA;CACF,IACA;EAAC;EAAQ;EAAO;EAAc;CAAa,CAC7C;CACA,MAAM,CAAC,WAAW,gBAAgB,eAAmC,CAAC,SAAS,CAAC;CAChF,MAAM,CAAC,sBAAsB,2BAA2B,SAAS,CAAC;CAClE,MAAM,qBAAqB,OAA8B,IAAI;CAC7D,MAAM,yBAAyB,OAA8C,IAAI;CACjF,MAAM,aAAa,UAAU,UAAU,SAAS;CAEhD,MAAM,yBAAyB,WAAW,gBAAgB,MAAM;CAEhE,MAAM,YAAY,kBAAkB;EAClC,UAAU;CACZ,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,cAAc,aACjB,EACC,mBACA,QACA,cAAc,qBACd,eACA,cACkC;EAClC,MAAM,YAA8B;GAClC,qBAAqB,qCAAqC;IACxD,iBAAiB,mBAAmB;IACpC;GACF,CAAC;GACD;GACA,cAAc,uBAAuB;GACrC;GACA;EACF;EACA,cAAc,YAAY,CAAC,GAAG,SAAS,SAAS,CAAC;CACnD,GACA,CAAC,YAAY,CACf;CAEA,MAAM,qBAAqB,kBAAkB;EAC3C,cAAc,YAAY;GACxB,IAAI,QAAQ,UAAU,GAAG,OAAO;GAChC,uBAAuB,UACrB,QAAQ,QAAQ,SAAS,IAAI,uBAAuB;GACtD,OAAO,QAAQ,MAAM,GAAG,EAAE;EAC5B,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,cAAc,YAAY;GACxB,IAAI,QAAQ,WAAW,KAAK,QAAQ,OAAO,WAAW,OAAO;GAC7D,OAAO,CAAC,SAAS;EACnB,CAAC;CACH,GAAG,CAAC,SAAS,CAAC;CAEd,gBAAgB;EACd,oBAAoB,UAAU,MAAM;CACtC,GAAG,CAAC,UAAU,QAAQ,iBAAiB,CAAC;CAExC,gBAAgB;EACd,MAAM,sBAAsB,uBAAuB;EACnD,IAAI,CAAC,qBAAqB;EAC1B,uBAAuB,UAAU;EAEjC,4BAA4B;GAC1B,qCAAqC;IACnC,iBAAiB,mBAAmB;IACpC,SAAS;GACX,CAAC,GAAG,MAAM;EACZ,CAAC;CACH,GAAG,CAAC,UAAU,MAAM,CAAC;CAErB,gBAAgB;EACd,IAAI,CAAC,qBAAqB;EAC1B,yBAAyB,UAAU,QAAQ,CAAC;CAC9C,GAAG,CAAC,qBAAqB,UAAU,MAAM,CAAC;CAE1C,MAAM,4BAA4B,OAAO,CAAC;CAE1C,MAAM,wBAAwB,kBAAkB;EAC9C,0BAA0B,WAAW;CACvC,GAAG,CAAC,CAAC;CAEL,MAAM,0BAA0B,kBAAkB;EAChD,0BAA0B,UAAU,KAAK,IACvC,GACA,0BAA0B,UAAU,CACtC;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,4BAA4B,cAAc;EAC9C,MAAM,eACJ,oBAAoB,gBACpB;EAEF,OAAO,gCAA6C,EAClD,WAAW,UACT,6CAA6C,MAAM,eAAe,YAAY,EAClF,CAAC;CACH,GAAG,CAAC,kBAAkB,CAAC;CAEvB,MAAM,oBAAoB,OAAO,KAAK;CAEtC,MAAM,4BAA4B,aAC/B,UAA4C;EAC3C,IAAI,MAAM,QAAQ,UAAU;GAC1B,IAAI,0BAA0B,UAAU,GAAG;GAE3C,MAAM,eAAe;GACrB,MAAM,gBAAgB;GAEtB,IAAI,UAAU,SAAS,GAAG;IACxB,kBAAkB,UAAU;IAC5B,mBAAmB;GACrB,OACE,UAAU;GAEZ;EACF;EAEA,0BAA0B,KAAK;CACjC,GACA;EAAC;EAAW,UAAU;EAAQ;EAAoB;CAAyB,CAC7E;CAEA,MAAM,sBAAsB,aAAa,UAA4C;EACnF,IAAI,MAAM,QAAQ,YAAY,kBAAkB,SAAS;GACvD,kBAAkB,UAAU;GAC5B,MAAM,gBAAgB;EACxB;CACF,GAAG,CAAC,CAAC;CAEL,OACE,oBAAC,mBAAmB,UAApB;EACE,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;EACF;YAEA,qBAAC,iBAAD;GACE,WAAW,KAAK,WAAW,WAAW,aAAa;GACnD,mCAAiC;GACjC,kBAAkB;GAClB,gBAAgB;GAChB,KAAK;GACL,GAAI;aANN,CAQG,WAAW,SACV,oBAAC,WAAW,QAAZ,CAAoB,CAAA,IAClB,UAAU,SAAS,IACrB,oBAAC,mBAAD,EAAA,UACE,qBAAC,uBAAD;IAAuB,SAAS;cAAhC,CACE,oBAAC,iBAAD,CAAkB,CAAA,GAClB,oBAAC,QAAD,EAAA,UAAO,UAAgB,CAAA,CACF;MACN,CAAA,IACjB,MACJ,oBAAC,iBAAD;IACE,WAAW,KAAK;KACd,kDACE,wBAAwB;KAC1B,iDACE,wBAAwB;IAC5B,CAAC;cAGA,WAAW,UACV,oBAAC,WAAW,SAAZ,CAAqB,CAAA,IAErB,oBAAC,wBAAD,EAAA,UACG,OAAO,aAAa,cACjB,WACA,WAAW,OAAO,KAAK,MAAM,UAC3B,oBAAC,MAAD,CAA0C,GAA/B,qBAAqB,OAAU,CAC3C,EACiB,CAAA;GAEX,GAbV,qBAAqB,UAAU,OAAO,GAAG,sBAa/B,CACF;;CACU,CAAA;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,IAAa,eAAe,UAA4B;CACtD,MAAM,EAAE,oBAAoB,8BAA8B,uBACxD,oBAAoB;CACtB,MAAM,EACJ,WACA,qBACA,oBAAoB,KACpB,iBACA,OACA,IACA,SAAS,GACT,mBAAmB,uBACnB,WACA,kBACA,6BACA,UACA,WACA,GAAG,cACD;CACJ,MAAM,sCAAsC,+BAA+B;CAE3E,MAAM,aAAa,MAAM;CAEzB,MAAM,CAAC,WAAW,gBAAgB,SAAS,CAAC;CAC5C,MAAM,CAAC,qBAAqB,0BAA0B,SAEpD,KAAA,CAAS;CACX,MAAM,CAAC,mBAAmB,wBAAwB,SAAS,CAAC;CAC5D,MAAM,uBAAuB,OAA8B,IAAI;CAC/D,MAAM,uBAAuB,OAAO,CAAC;CACrC,MAAM,OAAO,gBAAgB,MAAM,IAAI,eAAe;CACtD,MAAM,kBAAkB,OAAO,IAAI;CAEnC,gBAAgB;EACd,IAAI,CAAC,YAAY;EAEjB,IAAI,gBAAgB,WAAW,CAAC,MAAM;GACpC,aAAa,CAAC;GACd,uBAAuB,KAAA,CAAS;GAChC,sBAAsB,UAAU,QAAQ,CAAC;GACzC,qBAAqB,UAAU;GAC/B,IAAI,qBAAqB,SAAS;IAChC,aAAa,qBAAqB,OAAO;IACzC,qBAAqB,UAAU;GACjC;EACF;EACA,gBAAgB,UAAU;CAC5B,GAAG,CAAC,YAAY,IAAI,CAAC;CAErB,sBACc;EACV,IAAI,qBAAqB,SACvB,aAAa,qBAAqB,OAAO;CAE7C,GACA,CAAC,CACH;CAEA,MAAM,wBAAwB,aAC3B,UAAkB;EACjB,IAAI,YAAY;GACd,MAAM,gBAAgB,qBAAqB;GAC3C,IAAI,UAAU,eAAe;IAC3B,uBAAuB,QAAQ,gBAAgB,YAAY,UAAU;IACrE,IAAI,qBAAqB,SAAS,aAAa,qBAAqB,OAAO;IAC3E,qBAAqB,UAAU,iBAAiB;KAC9C,uBAAuB,KAAA,CAAS;KAChC,qBAAqB,UAAU;IACjC,GAAG,mCAAmC;GACxC;GACA,qBAAqB,UAAU;GAC/B,aAAa,KAAK;GAClB;EACF;EACA,wBAAwB,KAAK;CAC/B,GACA;EAAC;EAAY;EAAuB;CAAmC,CACzE;CAEA,MAAM,UACJ,8BAAC,6BAAD;EACE,wBAAwB,aAAa,mBAAmB,KAAA;EACxD,GAAI;EACJ,KAAK,wBAAwB;EAC7B,mBAAmB;EACE;CACtB,CAAA;CAGH,IAAI,YAAY;EACd,MAAM,EAEJ,WAAW,IAEX,kBAAkB,KAElB,QAAQ,IAER,OAAO,IAEP,cAAc,IAEd,oBAAoB,KAEpB,eAAe,IAEf,SAAS,IAET,MAAM,IACN,GAAG,mBACD;EACJ,OACE,oBAAC,cAAD;GACa;GACU;GACF;GACF;GACV;GACH;GACI;GACG;GACO;GACR;GACC;GACX,WAAW;GACX,GAAI;aAEH;EACW,CAAA;CAElB;CAEA,OAAO;AACT;;;ACx7BA,IAAM,cAAc,EAAE,UAAU,WAAW,GAAG,YAC5C,oBAAC,OAAD;CAAK,GAAI;CAAO,WAAW,KAAK,oBAAoB,SAAS;CAC1D;AACE,CAAA;AAYP,IAAM,gBAAgB,EACpB,WACA,OACA,aACA,eACA,OACA,cACuB;CACvB,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,aAAa,gBAAgB;CACrC,MAAM,EAAE,eAAe,sBAAsB,SAAS,mBACpD,mBAAmB,QAAQ;CAC7B,MAAM,kBAAkB,WAAW;CACnC,MAAM,wBAAwB,iBAAiB;CAE/C,OACE,qBAAC,OAAD;EAAK,WAAW,KAAK,4BAA4B,SAAS;YAA1D,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,MAAD;IAAI,WAAU;IAAkC,IAAI;cACjD;GACC,CAAA,GACH,eAAe,QAAQ,gBAAgB,MACtC,oBAAC,KAAD;IAAG,WAAU;IAAwC,IAAI;cACtD;GACA,CAAA,CAEF;MACJ,SACC,oBAAC,QAAD;GACE,YAAW;GACX,oBACE,eAAe,QAAQ,gBAAgB,KAAK,wBAAwB,KAAA;GAEtE,cAAY,EAAE,6BAA6B,EAAE,MAAM,CAAC;GACpD,UAAA;GACA,WAAU;GACV,SAAS;GACT,MAAK;GACL,SAAQ;aAER,oBAAC,WAAD,CAAY,CAAA;EACN,CAAA,CAEP;;AAET;AAMA,IAAM,cAAc,EAAE,UAAU,gBAC9B,oBAAC,OAAD;CAAK,WAAW,KAAK,0BAA0B,SAAS;CAAI;AAAc,CAAA;AAO5E,IAAM,gBAAgB,EAAE,UAAU,gBAChC,oBAAC,OAAD;CAAK,WAAW,KAAK,4BAA4B,SAAS;CAAI;AAAc,CAAA;AAO9E,IAAM,wBAAwB,EAAE,UAAU,gBACxC,oBAAC,OAAD;CAAK,WAAW,KAAK,sCAAsC,SAAS;CAAI;AAAc,CAAA;AAGxF,IAAM,uCAAuC,EAAE,WAAW,GAAG,YAC3D,oBAAC,QAAD;CACE,YAAW;CACX,WAAW,KAAK,6CAA6C,SAAS;CACtE,MAAK;CACL,SAAQ;CACR,GAAI;AACL,CAAA;AAGH,IAAM,qCAAqC,EAAE,WAAW,GAAG,YACzD,oBAAC,QAAD;CACE,YAAW;CACX,WAAW,KAAK,6CAA6C,SAAS;CACtE,MAAK;CACL,SAAQ;CACR,GAAI;AACL,CAAA;AAGH,IAAa,SAAS;CACpB,MAAM;CACN,QAAQ;CACR,gBAAgB;CAChB,6BAA6B;CAC7B,+BAA+B;CAC/B,QAAQ;CACR,MAAM;AACR;;;AClHA,IAAM,cAAc,EAAE,UAAU,WAAW,GAAG,YAC5C,oBAAC,OAAD;CAAK,GAAI;CAAO,WAAW,KAAK,oBAAoB,SAAS;CAC1D;AACE,CAAA;AAaP,IAAM,gBAAgB,EACpB,WACA,OACA,aACA,eACA,QACA,OACA,cACuB;CACvB,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,aAAa,gBAAgB;CACrC,MAAM,EAAE,eAAe,sBAAsB,SAAS,mBACpD,mBAAmB,QAAQ;CAC7B,MAAM,kBAAkB,WAAW;CACnC,MAAM,wBAAwB,iBAAiB;CAE/C,OACE,qBAAC,OAAD;EAAK,WAAW,KAAK,4BAA4B,SAAS;YAA1D;GACG,UACC,oBAAC,QAAD;IACE,YAAW;IACX,oBACE,eAAe,QAAQ,gBAAgB,KAAK,wBAAwB,KAAA;IAEtE,cAAY,EAAE,MAAM;IACpB,UAAA;IACA,WAAU;IACV,SAAS;IACT,MAAK;IACL,SAAQ;cAER,oBAAC,eAAD,CAAgB,CAAA;GACV,CAAA;GAEV,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,MAAD;KAAI,WAAU;KAAkC,IAAI;eACjD;IACC,CAAA,GACH,eAAe,QAAQ,gBAAgB,MACtC,oBAAC,KAAD;KAAG,WAAU;KAAwC,IAAI;eACtD;IACA,CAAA,CAEF;;GACJ,SACC,oBAAC,QAAD;IACE,YAAW;IACX,oBACE,eAAe,QAAQ,gBAAgB,KAAK,wBAAwB,KAAA;IAEtE,cAAY,EAAE,cAAc;IAC5B,UAAA;IACA,WAAU;IACV,SAAS;IACT,MAAK;IACL,SAAQ;cAER,oBAAC,WAAD,CAAY,CAAA;GACN,CAAA;EAEP;;AAET;AAMA,IAAM,cAAc,EAAE,UAAU,gBAC9B,oBAAC,OAAD;CAAK,WAAW,KAAK,0BAA0B,SAAS;CAAI;AAAc,CAAA;AAO5E,IAAM,gBAAgB,EAAE,UAAU,gBAChC,oBAAC,OAAD;CAAK,WAAW,KAAK,4BAA4B,SAAS;CAAI;AAAc,CAAA;AAO9E,IAAM,wBAAwB,EAAE,UAAU,gBACxC,oBAAC,OAAD;CAAK,WAAW,KAAK,sCAAsC,SAAS;CAAI;AAAc,CAAA;AAGxF,IAAM,uCAAuC,EAAE,WAAW,GAAG,YAC3D,oBAAC,QAAD;CACE,YAAW;CACX,WAAW,KAAK,6CAA6C,SAAS;CACtE,MAAK;CACL,SAAQ;CACR,GAAI;AACL,CAAA;AAGH,IAAM,qCAAqC,EAAE,WAAW,GAAG,YACzD,oBAAC,QAAD;CACE,YAAW;CACX,WAAW,KAAK,6CAA6C,SAAS;CACtE,MAAK;CACL,SAAQ;CACR,GAAI;AACL,CAAA;AAGH,IAAa,SAAS;CACpB,MAAM;CACN,QAAQ;CACR,gBAAgB;CAChB,6BAA6B;CAC7B,+BAA+B;CAC/B,QAAQ;CACR,MAAM;AACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Aa5HA,IAAsB,mBAAtB,MAEE;CAIA,YAAY,SAA+C;EAArC,KAAA,UAAA;qCAH8B,IAAI,IAAI;wBAc3C,MAAc,eAA8B;GAC3D,KAAK,YAAY,IAAI,MAAM,UAAU;EACvC;2BAEoB,SAAiB;GACnC,KAAK,YAAY,OAAO,IAAI;EAC9B;EAhBE,KAAK,UAAU,QAAQ;EACvB,IAAI,QAAQ,aACV,OAAO,QAAQ,QAAQ,WAAW,EAAE,SAAS,CAAC,MAAM,gBAAgB;GAClE,KAAK,cAAc,MAAM,UAAU;EACrC,CAAC;CAEL;AAWF;AAEA,IAAM,sBAAkC,EAAE,YAAY;AAMtD,IAAa,qBAAb,MAAgC;CAS9B,YAAY,SAAuB;EAAf,KAAA,UAAA;gCARH,IAAI,IAA8B;uCAM/C,CAAC;wBAIY,MAAiB,UAAuC;GACvE,IAAI,QAAQ,KAAK,OAAO,IAAI,IAAI;GAEhC,IAAI,CAAC,OAAO;IACV,QAAQ,IAAI,MAAM,EAAE,SAAS,KAAK,QAAQ,CAAC;IAC3C,KAAK,OAAO,IAAI,MAAM,KAAK;IAC3B,KAAK,QAAQ,IAAI;KACf;KACA,UAAU,OAAe,KAAa,YAAqC;MACzE,MAAM,QAAQ,KAAK,OAAO,IAAI,IAAI;MAClC,IAAI,CAAC,OAAO,OAAO;MACnB,OAAO,MAAM,UAAU,OAAO,KAAK,OAAO;KAC5C;KACA,MAAM;IACR,CAAC;GACH;GAEA,MAAM,kCAAkC,KAAK,8BAA8B;GAC3E,IAAI,iCAAiC;IACnC,OAAO,QAAQ,+BAA+B,EAAE,SAC7C,CAAC,gBAAgB,gBAAgB;KAChC,MAAM,cAAc,gBAAgB,UAAU;IAChD,CACF;IACA,OAAO,KAAK,8BAA8B;GAC5C;GACA,OAAO;EACT;uBAEgB,cAAyB;GAEvC,IAAI,CADU,KAAK,OAAO,IAAI,SACzB,GAAO;GACZ,KAAK,QAAQ,IAAI;IACf,MAAM;IACN,SAAS;IACT,MAAM;GACR,CAAC;GACD,KAAK,OAAO,OAAO,SAAS;EAC9B;mBAEY,cAAyB,KAAK,OAAO,IAAI,SAAS;CA1C1B;CA4CpC,oBACE,WACA,aACA;EACA,MAAM,QAAQ,KAAK,SAAS,SAAS;EACrC,IAAI,CAAC,OAAO;GACV,IAAI,CAAC,KAAK,8BAA8B,YACtC,KAAK,8BAA8B,aAAa,CAAC;GAEnD,OAAO,QAAQ,WAAW,EAAE,SAAS,CAAC,gBAAgB,gBAAgB;IACpE,KAAK,8BAA8B,WAAW,kBAAkB;GAClE,CAAC;GACD;EACF;EACA,OAAO,QAAQ,WAAW,EAAE,SAAS,CAAC,MAAM,gBAAgB;GAC1D,MAAM,cAAc,MAAM,UAAU;EACtC,CAAC;CACH;CAEA,kBAAkB,WAAsB,aAA+B;EACrE,MAAM,QAAQ,KAAK,SAAS,SAAS;EACrC,IAAI,KAAK,8BAA8B,YACrC,YAAY,SAAS,mBAAmB;GACtC,OAAO,KAAK,8BAA8B,WAAW;EACvD,CAAC;EAEH,IAAI,CAAC,OAAO;EACZ,YAAY,SAAS,SAAS;GAC5B,MAAM,iBAAiB,IAAI;EAC7B,CAAC;CACH;AACF;;;AC9HA,IAAM,mBAAmB,iBAAgC;CACvD,MAAM,SAAS,cAAc,UAAU;CACvC,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,QAAQ,OAAO,KAAA;CACzD,OAAO,OAAO,YAAY;AAC5B;AAEA,IAAM,sBAAsB,EAC1B,wBACA,cACA,sBACA,QAMI;CACJ,MAAM,SAAS,gBAAgB,YAAY;CAC3C,IAAI,CAAC,QAAQ,OAAO,EAAE,sBAAsB;CAC5C,OAAO,EAAE,sBAAsB,EAAE,OAAO,CAAC;AAC3C;AAEA,IAAa,oCAER,EAAE,SAAS,EAAE,gBAAgB,QAAQ;CACxC,MAAM,YAAY,cAAc,UAAU;CAC1C,IAAI,SAAS,EAAE,uBAAuB;CACtC,IAAI,OAAO,cAAc,UAAU,SAAS,EAAE,eAAe;CAC7D,IAAI,cAAc,cAAc,SAAS,EAAE,YAAY;CACvD,OAAO,EAAE,+CAA+C,EAAE,OAAO,CAAC;AACpE;AAEA,IAAa,mCAER,EAAE,SAAS,EAAE,gBAAgB,QAChC,mBAAmB;CACjB,wBAAwB;CACxB;CACA,sBAAsB;CACtB;AACF,CAAC;AAEH,IAAa,6BAAwE,EACnF,SAAS,EAAE,gBACX,QAEA,mBAAmB;CACjB,wBAAwB;CACxB;CACA,sBAAsB;CACtB;AACF,CAAC;AAEH,IAAa,0BAAqE,EAChF,SAAS,EAAE,gBACX,QAEA,mBAAmB;CACjB,wBAAwB;CACxB;CACA,sBAAsB;CACtB;AACF,CAAC;AAEH,IAAa,sCAER,EAAE,SAAS,EAAE,gBAAgB,QAChC,cAAc,UAAU,EAAE,aAAa,OAAO,IAAI,EAAE,iCAAiC;AAEvF,IAAa,4BAAuE,EAClF,SAAS,EAAE,gBACX,QACI;CACJ,MAAM,SAAS,gBAAgB,YAAY;CAE3C,IAAI,WAAW,WACb,OAAO,EAAE,qCAAqC;CAGhD,IAAI,WAAW,kBACb,OAAO,EAAE,sCAAsC;CAGjD,OAAO,EAAE,cAAc,WAAW,uBAAuB;AAC3D;;;AC9EA,IAAa,gCAGT;CACF,gCAAgC;CAChC,+BAA+B,EAAE,QAAQ,EAAE,0BAA0B;CACrE,8BAA8B,EAAE,QAAQ,EAAE,0BAA0B;CACpE,0BAA0B;CAC1B,uBAAuB;CACvB,yBAAyB,EAAE,QAAQ,EAAE,YAAY;CACjD,4BAA4B,EAAE,QAAQ,EAAE,2BAA2B;CACnE,gCAAgC;CAChC,gCAAgC,EAAE,QAAQ,EAAE,6BAA6B;CACzE,qCAAqC,EAAE,QACrC,EAAE,4CAA4C;CAChD,uCAAuC,EAAE,QACvC,EAAE,wCAAwC;CAC5C,qCAAqC,EAAE,QACrC,EAAE,0CAA0C;CAC9C,wCAAwC;CACxC,6CAA6C,EAAE,QAC7C,EAAE,0CAA0C;CAC9C,+BAA+B;CAC/B,mCAAmC,EAAE,QACnC,EAAE,wDAAwD;AAC9D;;;AC9BA,IAAM,+BAA0E,EAC9E,SAAS,EAAE,gBACX,GAAG,aACC;CACJ,IAAI,CAAC,cAAc,MAAM,OAAO;CAChC,MAAM,aAAa,8BAA8B,aAAa;CAC9D,IAAI,CAAC,YAAY,OAAO;CACxB,OAAO,WAAW;EAAE,GAAG;EAAQ,SAAS,EAAE,aAAa;CAAE,CAAC;AAC5D;AAEA,IAAa,iCAGT,EACF,KAAK,4BACP;AAEA,IAAa,+BAAb,cAAkD,iBAAgD;CAChG,YAAY,EAAE,SAAS,eAAwC;EAC7D,MAAM;GAAE;GAAS,aAAa;EAA+B,CAAC;oBAQnD,OAAe,KAAa,YAA6C;GACpF,MAAM,EAAE,iBAAiB;GACzB,IAAI,CAAC,cAAc,OAAO;GAC1B,MAAM,SAAS,aAAa,OACxB,KAAK,YAAY,IAAI,aAAa,IAAI,IACtC,KAAA;GACJ,IAAI,QAAQ,OAAO,OAAO;IAAE;IAAK;IAAS,GAAG,KAAK,QAAQ;IAAG;GAAM,CAAC,KAAK;GAGzE,MAAM,aADa,KAAK,YAAY,IAAI,GACrB,IAAa;IAAE;IAAK;IAAS,GAAG,KAAK,QAAQ;IAAG;GAAM,CAAC,KAAK;GAC/E,IAAI,YAAY,OAAO;GACvB,IAAI,CAAC,aAAa,SAAS,OAAO;GAGlC,OAAO,KAAK,QAAQ,EAAE,aAAa,SAAS;IAC1C,GAAI,aAAa,YAAY,CAAC;IAC9B,OAAO,aAAa;GACtB,CAAC;EACH;EAzBE,IAAI,aACF,OAAO,QAAQ,WAAW,EAAE,SAAS,CAAC,MAAM,gBAAgB;GAC1D,KAAK,cAAc,MAAM,UAAU;EACrC,CAAC;CAEL;AAqBF;;;ACAA,IAAM,YAAY;AAClB,IAAM,aAAa;AAWnB,MAAM,OAAO,YAAY;AACzB,MAAM,OAAO,GAAG;AAChB,MAAM,OAAO,QAAQ;AAErB,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM;CACvB,UAAU;EACR,SAAS;EACT,UAAU;EACV,SAAS;EACT,UAAU;EACV,SAAS;EACT,UAAU;CACZ;CAGA,SAAS,MAAc;EACrB,IAAI,OAAO,GACT,OAAO;OACF,IAAI,OAAO,IAChB,OAAO;OACF,IAAI,OAAO,IAChB,OAAO;OACF,IAAI,OAAO,IAChB,OAAO;OAEP,OAAO;CAEX;CACA,aAAa,MAAc,UAAkB;EAC3C,IAAI,SAAS,IACX,OAAO;EAET,IAAI,aAAa,OACf,OAAO,OAAO,IAAI,OAAO,OAAO;OAC3B,IAAI,aAAa,QACtB,OAAO;OACF,IAAI,aAAa,SACtB,OAAO,QAAQ,KAAK,OAAO,OAAO;OAC7B,IAAI,aAAa,OACtB,OAAO,OAAO;EAEhB,OAAO;CACT;CACA,eAAe;AACjB,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,SAAS;CACT,SAAS;AACX,EACF,CAAC;AAED,MAAM,aAAa,MAAM,EACvB,UAAU;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;AACZ,EACF,CAAC;AAED,IAAM,YAAY;CAChB,SAAS,CAAC;CACV,QAAQ;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;CACA,cAAc,CAAC;CACf,UAAU;EACR;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;AAIA,IAAM,WAAW,mBACd,eAAgC,WAAW,KAAA;AAK9C,IAAM,cAAc,mBACjB,eAAkC,OAAO,KAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwK5C,IAAM,2BAA2B;CAC/B,gBAAgB;CAChB,8BAA8B;CAC9B,OAAO;CACP,6BAA6B;CAC7B,UAAU;CACV,SAAS,YAAqB,QAAQ,KAAK,OAAO;;;;;;;;;;CAUlD,0BAA0B,EACxB,cAAc,6BAChB;AACF;AAEA,IAAa,aAAb,MAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuFtB,YAAY,UAA6B,CAAC,GAAG;sBAtFxB,KAAK,eAAe;kCAEuC,CAAC;eACzE;mCAC4C;qBACtC;WAEC;sBAOX;GACF,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;GAClC,IAAI,GAAG,YAAY,WAAe;EACpC;sBAQoD,CAAC;oBASC;uBA0LtC,aAAmC;GACjD,IAAI,KAAK,wBAAwB,OAAO;GAExC,OAAO,OAAO,KAAK,MAAM,EAAE,EAAE,QAAQ,QAAQ,IAAI;EACnD;uCAEgC;GAE9B,IAD2B,OAAO,KAAK,KAAK,YACxC,EAAmB,QAAQ,KAAK,eAAe,MAAM,IAAI;IAC3D,KAAK,OACH,gBAAgB,KAAK,gBAAgB,yFAC0B,KAAK,gBAAgB,0DACpC,KAAK,sBAAsB,GAC7E;IAEA,KAAK,kBAAkB;GACzB;EACF;8BAG6B,KAAK;qCAGJ,OAAO,KAAK,KAAK,YAAY;+BAGnC,KAAK;EAzK3B,MAAM,eAAe;GACnB,GAAG;GACH,GAAG;EACL;EAEA,KAAK,SAAS,aAAa;EAC3B,KAAK,kBAAkB,aAAa;EACpC,KAAK,iBAAiB,aAAa;EACnC,KAAK,WAAW,aAAa;EAC7B,KAAK,aAAa;GAAE,GAAG;GAAsB,GAAG,SAAS;EAAW;EACpE,KAAK,qBAAqB,IAAI,mBAAmB,KAAK,YAAY;EAClE,KAAK,2BAA2B;GAC9B,GAAG,yBAAyB;GAC5B,GAAG,QAAQ;EACb;EAEA,IAAI;GACF,IAAI,KAAK,kBAAkB,QAAQ,KAAK,cAAc,GAAG;IACvD,KAAK,eAAe,OAAO,eAAe;IAC1C,KAAK,eAAe,OAAO,QAAQ;IACnC,KAAK,eAAe,OAAO,UAAU;IACrC,KAAK,eAAe,OAAO,YAAY;IACvC,KAAK,eAAe,OAAO,QAAQ;GACrC;EACF,SAAS,OAAO;GACd,MAAM,MACJ,8GAA8G,OAChH;EACF;EAEA,KAAK,yBAAyB,CAAC,CAAC,QAAQ;EACxC,MAAM,0BAA0B,aAAa;EAE7C,IAAI,yBACF,KAAK,aAAa,KAAK,mBAAmB,GACvC,YACC,KAAK,aAAa,KAAK,oBACvB,KAAK,aAAa,KAAK,iBAAiB,aACpC;GACE,GAAG,KAAK,aAAa,KAAK,iBAAiB;GAC3C,GAAG;EACL,IACA,wBACR;EAIF,IAAI,CAAC,KAAK,aAAa,KAAK,kBAC1B,KAAK,aAAa,KAAK,mBAAmB,GACvC,YAAY,CAAC,EAChB;EAGF,KAAK,gBAAgB;GACnB,OAAO,aAAa;GACpB,aAAa;GACb,eAAe;IAAE,aAAa;IAAO,iBAAiB;GAAI;GAC1D,cAAc;GACd,KAAK,KAAK;GACV,aAAa;EACf;EAEA,MAAM,cAAc,OAAO,KAAK,KAAK,wBAAwB;EAE7D,IAAI,YAAY,SAAS,GACvB,KAAK,cAAc,cAAc;EAGnC,IAAI,aAAa,wBACf,KAAK,cAAc,yBAAyB,aAAa;EAG3D,KAAK,wBAAwB;EAE7B,MAAM,+BAA+B,aAAa;EAElD,IAAI,8BACF,KAAK,kBAAkB,KAAK,iBAAiB,EAC3C,GAAG,6BACL,CAAC;OACI,IAAI,CAAC,KAAK,aAAa,KAAK,eAAe,GAChD,KAAK,OACH,mDAAmD,KAAK,gBAAgB,yFACR,KAAK,gBAAgB,kIAEvF;EAGF,KAAK,mBAAmB,cAAc;GACpC,MAAM,WACJ,aAAa,+BACb,CAAC,KAAK,aAAa,KAAK,eAAe,IACnC,aACA,KAAK;GAEX,IAAI,QAAQ,KAAK,cAAc,GAC7B,OAAO,WAAW,KAAK,cAAc,IACjC,KAAK,eAAe,SAAS,EAAE,GAAG,KAAK,QAAQ,EAAE,OAAO,QAAQ,IAChE,KAAK,eAAe,SAAS,EAAE,OAAO,QAAQ;GAGpD,IAAI,WAAW,KAAK,cAAc,KAAK,KAAK,UAC1C,OAAO,KAAK,eAAe,SAAS,EAAE,GAAG,KAAK,QAAQ,EAAE,OAAO,QAAQ;GAEzE,OAAO,KAAK,eAAe,SAAS,EAAE,OAAO,QAAQ;EACvD;CACF;;;;CAKA,MAAM,OAAO;EACX,KAAK,wBAAwB;EAE7B,IAAI;GACF,KAAK,IAAI,MAAM,KAAK,aAAa,KAAK;IACpC,GAAG,KAAK;IACR,KAAK,KAAK;IACV,WAAW,KAAK;GAClB,CAAC;GACD,KAAK,cAAc;GACnB,IAAI,KAAK,YACP,OAAO,QAAQ,KAAK,UAAU,EAAE,SAAS,CAAC,MAAM,sBAAsB;IACpE,IAAI,CAAC,kBAAkB;IACvB,KAAK,aAAa,SAAS,WAAW,IAAI,MAAM,iBAAiB,IAAI,CAAC;GACxE,CAAC;GAGH,OAAO,QAAQ,KAAK,wBAAwB,EAAE,SAC3C,CAAC,OAAO,sBAAsB;IAC7B,KAAK,mBAAmB,cAAc,OAAO,gBAAgB;GAC/D,CACF;EACF,SAAS,OAAO;GACd,KAAK,OAAO,mCAAmC,KAAK,UAAU,KAAK,GAAG;EACxE;EAEA,OAAO;GACL,GAAG,KAAK;GACR,iBAAiB,KAAK;EACxB;CACF;;;;CAiCA,MAAM,iBAAiB;EACrB,IAAI,CAAC,KAAK,aAAa;GACrB,IAAI,KAAK,aAAa,KAAK,kBACzB,KAAK,kBACH,KAAK,iBACL,KAAK,aAAa,KAAK,gBACzB;GAGF,OAAO,MAAM,KAAK,KAAK;EACzB,OACE,OAAO;GACL,GAAG,KAAK;GACR,iBAAiB,KAAK;EACxB;CAEJ;CAEA,oBACE,UACA,aACA,mBACA;EACA,IAAI,CAAC,aAAa;GAChB,KAAK,OACH,sGACF;GACA;EACF;EAEA,IAAI,CAAC,KAAK,aAAa,WACrB,KAAK,aAAa,YAAY,GAAG,YAAY,YAAY;OAEzD,KAAK,aAAa,UAAU,aAAa;EAG3C,IAAI,mBACF,KAAK,aAAa,YAAY,EAAE,GAAG,kBAAkB;OAChD,IAAI,CAAC,KAAK,aAAa,QAAQ,GACpC,KAAK,OACH,iGACuB,SAAS,qFAC+B,SAAS,kIAE1E;EAGF,IAAI,KAAK,aACP,KAAK,aAAa,aAAa,UAAU,WAAW,WAAW;CAEnE;CAEA,kBAAkB,KAA2B,QAA0B;EACrE,IAAI,KAAK,aAAa,GAAG,GACvB,MAAM,aAAa,KAAK,EAAE,GAAG,OAAO,CAAC;OAGrC,MAAM,OAAO;GAAE,MAAM;GAAK,GAAG;GAAW,GAAG;EAAO,GAAG,KAAA,GAAW,IAAI;CAExE;CAEA,MAAM,YAAY,UAAgC;EAChD,KAAK,kBAAkB;EAEvB,IAAI,CAAC,KAAK,aAAa;EAEvB,IAAI;GACF,MAAM,IAAI,MAAM,KAAK,aAAa,eAAe,QAAQ;GACzD,IAAI,KAAK,aAAa,WACpB,KAAK,kBACH,KAAK,iBACL,KAAK,aAAa,KAAK,gBACzB;GAGF,KAAK,oBAAoB,CAAC;GAC1B,OAAO;EACT,SAAS,OAAO;GACd,KAAK,OAAO,2BAA2B,KAAK,UAAU,KAAK,GAAG;GAC9D,OAAO,KAAK;EACd;CACF;CAEA,4BAA4B,UAAkC;EAC5D,KAAK,sBAAsB;CAC7B;AACF;;;ACrxBA,IAAM,qBACJ,oBAAC,OAAD;CAAK,WAAU;WACb,qBAAC,OAAD;EACE,eAAY;EACZ,WAAU;YAFZ,CAIE,oBAAC,OAAD,EAAK,WAAU,oCAAqC,CAAA,GACpD,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD,EAAK,WAAU,sCAAuC,CAAA,GACtD,oBAAC,OAAD,EAAK,WAAU,oCAAqC,CAAA,CACjD;IACF;;AACF,CAAA;AAGP,IAAa,wBACX,qBAAC,OAAD;CAAK,WAAU;WAAf;EACE,oBAAC,cAAD,CAAe,CAAA;EACf,oBAAC,cAAD,CAAe,CAAA;EACf,oBAAC,cAAD,CAAe,CAAA;EACf,oBAAC,cAAD,CAAe,CAAA;EACf,oBAAC,cAAD,CAAe,CAAA;CACZ;;;;ACnBP,IAAa,oBAAoB,UAC/B,oBAAC,aAAD;CAAa,GAAI;CAAO,WAAU;AAA+B,CAAA;;;ACGnE,IAAM,cAAc;AACpB,IAAM,qBAAqB,IAAI,KAAK,KAAK;;AAGzC,IAAa,6BAA6B,EAAE,cAAsC;CAChF,MAAM,EAAE,MAAM,sBAAsB,2BAA2B;CAC/D,MAAM,aAAa,sBAAsB,IAAI,UAAU;CAEvD,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,OAAD;GACE,cAAY,EAAE,yBAAyB,EAAE,QAAQ,CAAC;GAClD,iBAAe;GACf,iBAAe;GACf,iBAAe;GACf,eAAY;GACZ,QAAO;GACP,MAAK;GACL,SAAQ;GACR,OAAM;GACN,OAAM;aAVR,CAYE,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,MAAK;IACL,GAAG;IACH,QAAO;IACP,eAAe;IACf,aAAY;GACb,CAAA,GACD,oBAAC,UAAD;IACE,IAAG;IACH,IAAG;IACH,MAAK;IACL,GAAG;IACH,QAAO;IACP,iBAAiB;IACjB,kBAAkB;IAClB,eAAc;IACd,aAAY;IACZ,WAAU;GACX,CAAA,CACE;;CACF,CAAA;AAET;;;AC7CA,IAAa,2BAA2B,EACtC,qBACkC;CAClC,MAAM,EACJ,kBAAA,qBAAmB,kBACnB,oBAAoB,8BAClB,oBAAoB;CAExB,IAAI,mBAAmB,KAAA,GACrB,OAAO,oBAAC,oBAAD,EAAkB,eAAY,oBAAqB,CAAA;CAG5D,OAAO,oBAAC,mBAAD,EAAmB,SAAS,eAAiB,CAAA;AACtD;;;ACvBA,SAAgB,iBAAiB,OAAe,YAAY,GAAG;CAC7D,MAAM,QAAQ;EAAC;EAAK;EAAM;EAAM;CAAI;CACpC,MAAM,WACJ,UAAU,IACN,IACA,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,MAAM,SAAS,CAAC;CAC7E,MAAM,WAAW,QAAQ,QAAQ;CAGjC,OAAO,GADL,cAAc,IAAI,KAAK,MAAM,QAAQ,EAAE,SAAS,IAAI,SAAS,YAAY,SAAS,EACxD,GAAG,MAAM;AACvC;;;ACGA,IAAa,qBAAqB,EAChC,UACA,4BAC4B;CAC5B,MAAM,iBAAiB,OAAO,aAAa,WAAW,WAAW,QAAQ,IAAI;CAE7E,IAAI,OAAO,mBAAmB,eAAe,CAAC,OAAO,SAAS,OAAO,cAAc,CAAC,GAClF,OAAO;CAGT,OACE,oBAAC,QAAD;EACE,WAAU;EACV,eAAY;YAEX,iBAAiB,gBAAgB,qBAAqB;CACnD,CAAA;AAEV;;;ACrBA,IAAa,yBAAyB,EACpC,WACA,oBACgC;CAChC,MAAM,EAAE,mBAAA,sBAAoB,sBAA6B,oBAAoB;CAC7E,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd;GAIE,oBAAC,qBAAD,EAAmB,UAAU,cAAgB,CAAA;GAAC;GAAE;GAChD,oBAAC,qBAAD,EAAmB,UAAU,UAAY,CAAA;EACtC;;AAET;;;;;;;;;;;;;;;;;;;;;;;;;;ACGA,IAAa,qBACX,aACyB;CACzB,MAAM,MAAM,OAAO,QAAQ;CAC3B,IAAI,UAAU;CAEd,OAAO,aAAmC,GAAG,SAAS,IAAI,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC;AAChF;;;ACnBA,IAAa,sBAAsB;;AAGnC,SAAgB,iBAAiB,SAAiD;CAChF,MAAM,EAAE,eAAe,kBAAkB,wBAAwB,kBAAkB;CACnF,MAAM,EAAE,YAAY,uBAAuB,kBAAkB;CAE7D,OAAO,kBAAkB,OAAO,YAAY,OAAO,UAAU;EAC3D,IAAI,OAAO,MAAM,eAAe;EAEhC,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,SAAS;GAC5D,QAAQ,KAAK,mBAAmB;GAChC;EACF;EAEA,MAAM,YAAY,QAAQ;EAC1B,IAAI,WAAqB,CAAC;EAG1B,IAAI,OAAO,eAAe,UACxB,SAAS,cAAc;OAEvB,WAAW,EAAE,GAAG,WAAW;EAG7B,IAAI,WAAW;GACb,MAAM,OAAO,MAAM,QAAQ,WAAW,WAAW,QAAQ;GAEzD,IAAI,MAAM,SACR,cAAc,KAAK,OAAO;QAE1B,cAAc,OAAO;EAEzB;CACF,CAAC;AACH;;;AC1CA,IAAa,oBACX,YACwC;CACxC,MAAM,EAAE,eAAe,eAAe,kBACpC,wBAAwB,kBAAkB;CAC5C,MAAM,EAAE,WAAW,eAAe,kBAAkB;CAEpD,OAAO,OAAO,YAAmC;EAC/C,IAAI,CAAC,SACH;EAGF,IAAI,QAAQ,SAAS,WAAW,qBAAqB,OAAO,GAAG;GAC7D,gBAAgB,OAAO;GACvB;EACF;EAEA,IAAI,CAAC,QAAQ,MAAM,CAAC,UAAU,CAAC,eAC7B;EAIF,cAAc,MADe,cAAc,SAAS,OAAO,CAC/B;CAC9B;AACF;;;AC1BA,IAAa,wCACX;AAEF,IAAa,kBAAkB,YAA8C;CAC3E,MAAM,EAAE,WAAW,eAAe,gBAAgB;CAClD,MAAM,EAAE,MAAM,sBAAsB,gBAAgB;CAEpD,OAAO,OAAO,UAAU;EACtB,MAAM,eAAe;EAErB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,IAAI;GACjC,QAAQ,KAAK,qCAAqC;GAClD;EACF;EAEA,MAAM,OAAO,YAAY,QAAQ,EAAE;CACrC;AACF;;;ACNA,SAAS,mBACP,IACA,SACmB;CACnB,QAAQ,UAAU;EAChB,IAAI,OAAO,OAAO,cAAc,CAAC,SAAS,iBAAiB,QACzD;EAEF,GAAG,OAAO,QAAQ,eAAe;CACnC;AACF;AAEA,IAAa,sBACX,SACA,yBAIG;CACH,MAAM,EACJ,iBAAiB,wBACjB,iBAAiB,2BACf,wBAAwB,oBAAoB;CAEhD,MAAM,kBACJ,sBAAsB,mBAAmB,iCAAiC;CAE5E,MAAM,kBACJ,sBAAsB,mBAAmB,iCAAiC;CAE5E,OAAO;EACL,iBAAiB,mBAAmB,iBAAiB,OAAO;EAC5D,iBAAiB,mBAAmB,iBAAiB,OAAO;CAC9D;AACF;;;AC9CA,IAAa,wBAAwB,YAA8C;CACjF,MAAM,EAAE,YAAY,uBAAuB,sBAAsB;CAEjE,OAAO,OAAO,UAAU;EACtB,MAAM,eAAe;EACrB,IAAI,CAAC,SAAS,IAAI;GAChB,QAAQ,KAAK,wDAAwD;GACrE;EACF;EAEA,MAAM,QAAQ,WAAW,EAAE,YAAY,QAAQ,GAAG,CAAC;CACrD;AACF;;;ACPA,IAAa,qCACX;AAEF,IAAa,kBAAkB,YAA8C;CAC3E,MAAM,EAAE,UAAU,uBAAuB,gBAAgB;CACzD,MAAM,EAAE,WAAW,eAAe,gBAAgB;CAClD,MAAM,EAAE,MAAM,sBAAsB,gBAAgB;CAEpD,OAAO,OAAO,UAAU;EACtB,MAAM,eAAe;EAErB,IAAI,CAAC,KAAK,CAAC,SAAS,QAAQ,CAAC,QAAQ;GACnC,QAAQ,KAAK,kCAAkC;GAC/C;EACF;EAEA,IAAI,CAAC,YAAY,SAAS,KAAK,GAC7B,MAAM,OAAO,SAAS,QAAQ,KAAK,EAAE;OAErC,MAAM,OAAO,WAAW,QAAQ,KAAK,EAAE;CAE3C;AACF;;;AC3BA,IAAa,wBACX,SACA,qBACsB;CACtB,MAAM,EAAE,YAAY,sBAClB,wBAAwB,sBAAsB;CAEhD,MAAM,aAAa,oBAAoB;CAEvC,QAAQ,UAAU;EAChB,IAAI,CAAC,cAAc,CAAC,SAAS;GAC3B,QAAQ,KACN,wEACF;GACA;EACF;EAEA,WAAW,SAAS,KAAK;CAC3B;AACF;;;ACjBA,IAAa,iBAAiB,YAA0B;CACtD,MAAM,EAAE,kBAAkB,wBAAwB,eAAe;CACjE,MAAM,EAAE,sBAAsB,CAAC,MAAM,uBAAuB,eAAe;CAC3E,MAAM,EAAE,WAAW,eAAe,eAAe;CAEjD,MAAM,SAAS,CAAC,CAAC,oBAAoB;CAErC,MAAM,YAA+B,OAAO,UAAU;EACpD,MAAM,eAAe;EAErB,IAAI,CAAC,SAAS;EAEd,IAAI,CAAC,QAAQ,QACX,IAAI;GAQF,cAAc;IANZ,GAAG;IACH,QAAQ;IACR,2BAAW,IAAI,KAAK;IACpB,WAAW,OAAO;GAGN,CAAiB;GAE/B,MAAM,OAAO,WAAW,OAAO;EACjC,SAAS,GAAG;GACV,cAAc,OAAO;EACvB;OAEA,IAAI;GASF,cAAc;IAPZ,GAAG;IACH,aAAa;IACb,QAAQ;IACR,WAAW;IACX,WAAW;GAGC,CAAiB;GAE/B,MAAM,OAAO,aAAa,OAAO;EACnC,SAAS,GAAG;GACV,cAAc,OAAO;EACvB;CAEJ;CAEA,OAAO;EAAE;EAAQ;CAAU;AAC7B;;;AC3BA,IAAa,oBAEX,kBAC6E;CAC7E,IAAI,CAAC,iBAAiB,CAAC,cAAc,QACnC,OAAO,CAAC;CAGV,MAAM,SAA8C,CAAC;CAErD,KAAK,MAAM,WAAW,cAAc,QAAQ;EAC1C,MAAM,YAAY,cAAc,OAAO;EACvC,MAAM,CAAC,cAAc,UAAU;EAE/B,IAAI,CAAC,cAAc,CAAC,WAAW,QAAQ;EAEvC,MAAM,cAAc,WAAW;EAE/B,MAAM,UAAU,eAAe,WAAW;EAE1C,OAAO,WAAW;GAChB,iBAAiB,oBAAA,YAAA,EAAA,UAAG,YAAc,CAAA;GAClC,MAAM,UAAU;GAChB;EACF;CACF;CAEA,OAAO;AACT;AAOA,IAAa,kBAAkB,UAAkB;CAC/C,MAAM,iBAAiB,CAAC;CACxB,KAAK,MAAM,KAAK,OAAO;EAErB,MAAM,YAAY,EAAE,YAAY,CAAC;EACjC,eAAe,KAAK,KAAK,UAAU,SAAS,EAAE,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG,GAAG;CAClF;CAEA,OAAO,eAAe,KAAK,GAAG;AAChC;AAEA,IAAa,kBAAkB,YAC7B,QACG,MAAM,GAAG,EACT,KAAK,SAAS,OAAO,cAAc,SAAS,KAAK,QAAQ,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EACxE,KAAK,EAAE;AAEZ,IAAa,yBAA0C,EACrD,OAAO;CACL,MAAM;EACJ,iBAAiB,oBAAA,YAAA,EAAA,UAAE,KAAI,CAAA;EACvB,MAAM;EACN,SAAS,eAAe,IAAI;CAC9B;CACA,MAAM;EACJ,iBAAiB,oBAAA,YAAA,EAAA,UAAE,KAAI,CAAA;EACvB,MAAM;EACN,SAAS,eAAe,IAAI;CAC9B;CACA,MAAM;EACJ,iBAAiB,oBAAA,YAAA,EAAA,UAAE,KAAI,CAAA;EACvB,MAAM;EACN,SAAS,eAAe,IAAI;CAC9B;CACA,KAAK;EAAE,iBAAiB,oBAAA,YAAA,EAAA,UAAE,KAAI,CAAA;EAAG,MAAM;EAAO,SAAS,eAAe,IAAI;CAAE;CAC5E,KAAK;EACH,iBAAiB,oBAAA,YAAA,EAAA,UAAE,KAAI,CAAA;EACvB,MAAM;EACN,SAAS,eAAe,IAAI;CAC9B;CACA,MAAM;EACJ,iBAAiB,oBAAA,YAAA,EAAA,UAAE,KAAI,CAAA;EACvB,MAAM;EACN,SAAS,eAAe,IAAI;CAC9B;AACF,EACF;AAEA,IAAa,2BAA2B,oBACtC,CAAC,MAAM,QAAQ,eAAe,KAC9B,OAAO,gBAAgB,aAAa,eACpC,OAAO,KAAK,gBAAgB,QAAQ,EAAE,SAAS;;;;;;;;;AAUjD,IAAa,8BACX,iBACA,iBACuB;CAEvB,IAAI,MAAM,QAAQ,eAAe,GAAG,OAAO,KAAA;CAE3C,MAAM,UACJ,gBAAgB,MAAM,eAAe,WACrC,gBAAgB,WAAW,eAAe;CAE5C,OAAO,UAAU,eAAe,OAAO,IAAI,KAAA;AAC7C;;;ACvHA,IAAa,yBAAyB;;AAGtC,IAAa,sBAAsB,YAA2B;CAC5D,MAAM,SAAS,iBAAiB;CAChC,MAAM,EAAE,kBAAkB,wBAAwB,oBAAoB;CACtE,MAAM,EAAE,SAAS,wBAAwB,uBAAuB,oBAAoB;CACpF,MAAM,EAAE,WAAW,eAAe,oBAAoB;CACtD,MAAM,EAAE,kBAAkB,2BACxB,oBAAoB,oBAAoB;CAE1C,MAAM,uBAAuB,aAC1B,KAAc,UAA4B,YAAwC;EACjF,MAAM,oBAAoB,SAAS,mBAAmB,CAAC;EACvD,MAAM,eAAe,SAAS;EAC9B,MAAM,cAAc,CAAC,CAAC,kBAAkB;EAExC,IAAI,KAAK;GACP,MAAM,6BAAY,IAAI,KAAK,GAAE,YAAY;GACzC,kBAAkB,gBAAgB,cAC9B;IACE,GAAG,kBAAkB;IACrB,OAAO,kBAAkB,cAAc,QAAQ;GACjD,IACA;IACE,OAAO;IACP,mBAAmB;IACnB,kBAAkB;IAClB,YAAY;GACd;EACN,OACE,IAAI,eAAe,kBAAkB,cAAc,QAAQ,GACzD,kBAAkB,gBAAgB;GAChC,GAAG,kBAAkB;GACrB,OAAO,kBAAkB,cAAc,QAAQ;EACjD;OAEA,OAAO,kBAAkB;EAI7B,MAAM,eAA+C,MACjD,CAAC,UAAU,GAAI,SAAS,oBAAoB,CAAC,CAAE,IAC/C,QAAQ,kBAAkB,QACvB,SAAS,EAAE,KAAK,SAAS,SAAS,QAAQ,KAAK,YAAY,SAAS,QACvE;EAEJ,MAAM,kBAAkB,MACpB,CAAC,UAAU,GAAI,SAAS,iBAAiB,CAAC,CAAE,IAC5C,SAAS,eAAe,QAAQ,SAAS,KAAK,SAAS,SAAS,IAAI;EAExE,OAAO;GACL,GAAG;GACH,kBAAkB,gBAAgB,QAAQ;GAC1C,eAAe;GACf,iBAAiB;EACnB;CACF,GAEA,CAAC,OAAO,MAAM,OAAO,MAAM,CAC7B;CAEA,MAAM,yBAAyB,MAAc,eAAwB;EACnE,YAAY,SAAS;EACrB,OAAO;EACP;EACA,MAAM,OAAO;EACb,SAAS,OAAO,MAAM;EACtB,GAAI,aAAa,EAAE,YAAY,UAAU;CAC3C;CAEA,MAAM,iBAAiB,SAAS,OAAO,IAAY,MAAc,QAAiB;EAChF,IAAI,CAAC,WAAW,CAAC,oBAAoB,kBAAkB;EAIvD,MAAM,YAAY,2BAA2B,iBAAiB,IAAI;EAElE,MAAM,cAAc,qBAAqB,KADrB,sBAAsB,MAAM,SACF,GAAa,OAAO;EAElE,IAAI;GACF,cAAc,WAAW;GACzB,QAAQ,mBAAmB,EAAE,SAAS,YAAY,CAAC;GAUnD,eARwB,MACpB,MAAM,QAAQ,aAAa,IAAI;IAC7B;IACA,GAAI,aAAa,EAAE,YAAY,UAAU;GAC3C,CAAa,IACb,MAAM,QAAQ,eAAe,IAAI,IAAI,GAGX,OAAO;EACvC,SAAS,OAAO;GAEd,cAAc,OAAO;GACrB,QAAQ,mBAAmB,EAAE,QAAQ,CAAC;EACxC;CACF,GAAG,GAAI;CAEP,OAAO,OAAO,cAAsB,UAAqC;EACvE,IAAI,OAAO,gBACT,MAAM,eAAe;EAGvB,IAAI,CAAC,SACH,OAAO,QAAQ,KAAK,sBAAsB;EAG5C,IAAI,uBAAuB;EAE3B,IAAI,QAAQ,eACV,QAAQ,cAAc,SAAS,aAAa;GAG1C,IACE,SAAS,QACT,OAAO,WAAW,SAAS,KAAK,MAChC,SAAS,SAAS,cAElB,uBAAuB;QAClB,IAAI,SAAS,QAAQ,OAAO,WAAW,SAAS,KAAK,IAC1D,QAAQ,KACN,uFACF;EAEJ,CAAC;EAGH,IAAI;GACF,IAAI,sBACF,MAAM,eAAe,QAAQ,IAAI,qBAAqB,MAAM,KAAK;QAEjE,MAAM,eAAe,QAAQ,IAAI,cAAc,IAAI;EAEvD,SAAS,OAAO;GACd,QAAQ,IAAI,EAAE,MAAM,CAAC;EACvB;CACF;AACF;;;ACxJA,IAAa,mBACX,2BACqB;CACrB,MAAM,EAAE,kBAAkB,4BACxB,wBAAwB,iBAAiB;CAE3C,MAAM,mBAAmB,0BAA0B;CAEnD,OAAO,OAAO,YAAY;EACxB,IAAI,SACF,MAAM,iBAAiB,OAAO;CAElC;AACF;;;ACTA,IAAa,kBACX,SACA,mBAOI;CACJ,cAAc,UAAU;EACtB,IAAI,OAAO,eAAe,uBAAuB,cAAc,CAAC,SAAS,MACvE;EAEF,cAAc,mBAAmB,OAAO,QAAQ,IAAI;CACtD;CACA,cAAc,UAAU;EACtB,IAAI,OAAO,eAAe,uBAAuB,cAAc,CAAC,SAAS,MACvE;EAGF,cAAc,mBAAmB,OAAO,QAAQ,IAAI;CACtD;AACF;;;AC1BA,IAAa,eAAe,SAAuB,0BAAoC;CACrF,MAAM,EAAE,SAAS,sBAAsB,CAAC,MAAM,uBAAuB,aAAa;CAClF,MAAM,EAAE,WAAW,eAAe,aAAa;;;;;CAM/C,MAAM,UACJ,OAAO,MAAM,SAAS,WAAW,QAAQ,MAAM,WAAW,SAAS;;;;;CAMrE,MAAM,UAAU,QAAQ,MAAM,WAAW,SAAS;;;;;CAMlD,MAAM,cACJ,OAAO,MAAM,SAAS,uBACtB,QAAQ,MAAM,WAAW,SAAS,uBAClC,QAAQ,MAAM,WAAW,SAAS,eAClC,QAAQ,MAAM,WAAW,iBAAiB,QAC1C,QAAQ,MAAM,WAAW,iBAAiB;CAE5C,MAAM,cAAc,OAAO,WAAW,QAAQ,MAAM;CAEpD,MAAM,UACJ,CAAC,QAAQ,QACT,QAAQ,YAAY,YACnB,oBAAoB,yBAClB,eAAe,oBAAoB;CAExC,MAAM,YACJ,oBAAoB,yBACnB,eAAe,oBAAoB;CAEtC,MAAM,UAAU,CAAC,eAAe,oBAAoB;CACpD,MAAM,UAAU,CAAC,eAAe,oBAAoB;CAQpD,OAAO;EACL,cAAA,CARoB;EASpB;EACA;EACA;EACA,eAXoB,CAAC,eAAe,oBAAoB;EAYxD;EACA,UAZe,CAAC,yBAAyB,oBAAoB;EAa7D,UAZe,oBAAoB;EAanC,UAZe,oBAAoB;EAanC,gBAZqB,oBAAoB;EAazC;EACA;EACA;EACA;CACF;AACF;;;AC3DA,IAAa,iCAAiC;AAE9C,SAAgB,oBAAoB,SAAuB;CACzD,MAAM,EAAE,WAAW,eAAe,oBAAoB;CAEtD,OAAO,mBAAmB,cAA6B,SACrD,sBAAsB,QAAQ,QAAQ,IAAI,cAAc,IAAI,CAC9D;AACF;AAEA,eAAe,sBACb,QACA,WACA,cACA,MACA;CACA,MAAM,YAAgC,CAAC;CACvC,MAAM,QAAQ;CACd,IAAI;CACJ,IAAI,UAAU;CAEd,OAAO,WAAW,UAAU,SAAA,KAAyC;EACnE,MAAM,WAAW,MAAM,OAAO,eAC5B,WACA,eAAe,EAAE,MAAM,aAAa,IAAI,CAAC,GACzC,MACA;GAAE;GAAO;EAAK,CAChB;EAEA,UAAU,KAAK,GAAG,SAAS,SAAS;EACpC,OAAO,SAAS;EAChB,UAAU,QAAQ,IAAI;CACxB;CAEA,OAAO;AACT;;;ACnCA,IAAM,0BAA0B;AAChC,IAAM,iCAAiC;;;;;;;;;AAUvC,IAAa,2BAA2B,EACtC,uBAAuB,gCACvB,4BAA4B,yBAC5B,WACkC;CAClC,MAAM,CAAC,qBAAqB,0BAA0B,SAAiB,IAAI;CAC3E,MAAM,aAAa,OAAe,KAAK,MAAM;CAE7C,gBAAgB;EACd,MAAM,aAAa,KAAK;EAExB,MAAM,WAAW,kBAAkB;GACjC,IAAI,CAAC,QAAQ,WAAW,WAAW,YAAY;IAC7C,cAAc,QAAQ;IACtB;GACF;GACA,MAAM,iBAAiB,WAAW,UAAU;GAC5C,MAAM,UAAU,KAAK,UAAU,GAAG,cAAc;GAChD,WAAW,WAAW,QAAQ,SAAS,WAAW;GAClD,uBAAuB,OAAO;EAChC,GAAG,yBAAyB;EAE5B,aAAa;GACX,cAAc,QAAQ;EACxB;CACF,GAAG;EAAC;EAA2B;EAAsB;CAAI,CAAC;CAO1D,OAAO;EAAE,eALa,wBAAwB;GAC5C,WAAW,UAAU,KAAK;GAC1B,uBAAuB,IAAI;EAC7B,CAES;EAAe;CAAoB;AAC9C;;;ACjDA,IAAa,sBAAsB,cAAsB;CACvD,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,mBAAmB,aACtB,WAAiC,EAChC,UAAU,MAAM,UAAU,IAAI,SAAS,EACzC,IACA,CAAC,SAAS,CACZ;CACA,MAAM,EAAE,aAAa,cAAc,OAAO,UAAU,OAAO,gBAAgB;CAC3E,OAAO;AACT;;;;;;;;;;;ACSA,IAAa,6BAA6B,EACxC,iBACA,WACA,gBACA,eAC6D;CAC7D,MAAM,EAAE,eAAe,YAAY,mBAAmB,QAAQ;CAE9D,OAAO,cAAc;EACnB,MAAM,yBAAyB,YAC3B,iBACC,kBAAkB;EAIvB,OAAO;GACL,oBAJ8B,mBAAmB;GAKjD,cAJwB,yBAAyB,KAAA,IAAY;GAK7D,mBAAmB;EACrB;CACF,GAAG;EAAC;EAAiB;EAAW;EAAgB;EAAe;CAAO,CAAC;AACzE;;;ACcA,IAAa,eAAe,EAC1B,oBAAoB,iBACpB,cAAc,WACd,mBAAmB,gBACnB,UACA,WACA,sBACA,UACA,SACA,gBACA,MACA,OAAO,eAC4B;CACnC,MAAM,oBAAoB,YAAY;CACtC,MAAM,mBAAmB,YAAY,gBAAoB;CACzD,MAAM,SAAS,eAAe,gBAAgB;CAC9C,MAAM,SAAS,qBAAqB,gBAAgB;CACpD,MAAM,YAAY,wBAAwB,gBAAgB;CAC1D,MAAM,aAAa,OAA8B,IAAI;CACrD,MAAM,iBAAiB,OAAiC,IAAI;CAC5D,MAAM,aAAa,OAAO,KAAK;CAC/B,MAAM,EAAE,UAAU,eAAe;CACjC,MAAM,EAAE,kBAAA,qBAAmB,qBAA4B,oBAAoB;CAC3E,MAAM,uBAAuB,OAAO;CACpC,MAAM,yBAAyB,0BAA0B;EACvD;EACA;EACA;EACA,UAAU;CACZ,CAAC;CAED,MAAM,aAAa,aAChB,QAA0B,UAA2B;EAEpD,IADc,iBAAiB,QAAQ,KAAK,MAC9B,OAAO;GACnB,OAAO,MAAM;GACb,WAAW,UAAU;GACrB,UAAU,KAAK;EACjB;CACF,GACA;EAAC;EAAQ;EAAS;CAAc,CAClC;CAEA,MAAM,oBAAoB,eACjB;EACL,aAAa,WAAW,UAAU,CAAC,CAAoB;EACvD,UAAU;CACZ,IACA,CAAC,sBAAsB,UAAU,CACnC;CAEA,MAAM,sBAAsB,UAA4C;EACtE,IAAI,CAAC,WAAW;EAChB,MAAM,SAAS,MAAM;EACrB,IAAI,WAAW,YAAY,QACzB,WAAW,WAAW,KAAK;CAE/B;CAEA,MAAM,0BAA0B,UAA+C;EAC7E,IAAI,CAAC,WAAW;EAChB,WAAW,UAAU,KAAK;CAC5B;CAEA,MAAM,uBAAuB,UAA+C;EAC1E,IAAI,MAAM,oBAAoB,MAAM,QAAQ,YAAY,CAAC,WAAW;EACpE,WAAW,UAAU,KAAK;CAC5B;CAIA,gBAAgB;EACd,IAAI,CAAC,MAAM;GACT,WAAW,UAAU;GACrB,IAAI,QACF,OAAO,MAAM;GAEf;EACF;EACA,IAAI,QAAQ,CAAC,UAAU,CAAC,WAAW,SACjC,OAAO,KAAK;CAEhB,GAAG;EAAC;EAAQ;EAAQ;CAAI,CAAC;CAEzB,IAAI,CAAC,QAAQ,CAAC,QAAQ,OAAO;CAE7B,OACE,oBAAC,mBAAD;EAAmB,UAAU;EAAkB,iBAAiB;YAC9D,oBAAC,sBAAD;GAAsB,OAAO;aAC3B,qBAAC,OAAD;IACE,WAAW,KACT,YACA,OACA,+DACA,SACF;IACA,SAAS;IACT,KAAK;cARP;KAUE,oBAAC,YAAD;MAAY,WAAW;MAAW,SAAS;MAAW,cAAA;gBACpD,oBAAC,OAAD;OACE,oBAAkB,uBAAuB;OACzC,cAAY,uBAAuB;OACnC,mBAAiB,uBAAuB;OACxC,cAAY,YAAY,SAAS,KAAA;OACjC,WAAU;OACV,OAAO,YAAY,KAAA,IAAY;OAC/B,WAAW;OACL;OACN,UAAU,YAAY,IAAI;OAEzB;MACE,CAAA;KACK,CAAA;KACZ,oBAAC,oBAAD;MACE,WAAU;MACV,OAAM;MACN,mBAAkB;KACnB,CAAA;KACA,wBACC,oBAAC,sBAAD;MAAsB,SAAS;MAAwB,KAAK;KAAiB,CAAA;IAE5E;;EACe,CAAA;CACL,CAAA;AAEvB;;;AC7KA,SAAgB,mBAAmB,EACjC,qBACA,GAAG,cACuB;CAC1B,MAAM,EAAE,QAAQ,gBAAgB,oBAAoB;CACpD,OACE,oBAAC,OAAD;EAAO,WAAU;EAAiC,GAAI;YACpD,oBAAC,uBAAD,EAAA,UACE,oBAAC,qBAAD,CAAsB,CAAA,EACD,CAAA;CAClB,CAAA;AAEX;;;ACTA,SAAgB,oBAAoB,EAAE,YAAsC;CAC1E,MAAM,EAAE,cAAc,YAAY,gBAAgB,wBAAwB;CAC1E,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,UAAU,gBAAgB;CAElC,SAAS,cACP,QACsC;EACtC,QAAQ,MAAM;GACZ,OAAO,CAAC;GACR,MAAM;EACR;CACF;CAEA,OACE,qBAAC,MAAM,MAAP;EACE,WAAU;EACV,eAAY;YAFd,CAIE,oBAAC,MAAM,QAAP;GACE,WAAU;GACV,aACE,CAAC,WACG,EACE,iFACF,IACA,KAAA;GAEN,MAAM;GACN,OACE,CAAC,WAAW,EAAE,kDAAkD,IAAI,KAAA;GAGrE;EACW,CAAA,GACd,qBAAC,MAAM,SAAP;GAAe,WAAW;aAA1B;IACE,oBAAC,QAAD;KACE,YAAW;KACX,WAAU;KACV,eAAY;KACZ,SAAS,cAAc,YAAY;KACnC,MAAK;KACL,SAAQ;eAEP,EAAE,QAAQ;IACL,CAAA;IACR,oBAAC,QAAD;KACE,YAAW;KACX,WAAU;KACV,eAAY;KACZ,SAAS,cAAc,UAAU;KACjC,MAAK;KACL,SAAQ;eAEP,EAAE,cAAc;IACX,CAAA;IACR,oBAAC,QAAD;KACE,YAAW;KACX,WAAU;KACV,eAAY;KACZ,SAAS,cAAc,WAAW;KAClC,MAAK;KACL,SAAQ;eAEP,EAAE,aAAa;IACV,CAAA;GACK;IACL;;AAEhB;;;ACjFA,IAAa,iBAAiB,EAAE,WAAW,GAAG,YAC5C,oBAAC,OAAD;CAAK,GAAI;CAAO,WAAW,KAAK,4BAA4B,SAAS;AAAI,CAAA;;;ACQ3E,IAAa,6BAA6B;CACxC,MAAM,EAAE,MAAM,sBAAsB;CAEpC,OACE,oBAAC,eAAD;EAAe,eAAa;YAC1B,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,YAAD,CAAa,CAAA,GACb,oBAAC,QAAD,EAAA,UAAO,EAAE,iBAAiB,EAAQ,CAAA,CAC/B;;CACQ,CAAA;AAEnB;;;AChBA,IAAa,uBAAuB;CAClC,MAAM,EAAE,YAAY,kBAAkB;CACtC,MAAM,EAAE,MAAM,sBAAsB,gBAAgB;CAEpD,MAAM,EAAE,gBAAgB,YAAY,OAAO;CAW3C,OACE,oBAAC,OAAD;EACE,WAXmB,KACrB,gDACA,QAAQ,MACR;GACE,yBAAyB;GACzB,4BAA4B,CAAC;EAC/B,CAKa;EACX,eAAY;YAGZ,oBAAC,OAAD;GAAK,WAAU;aACZ,EAAE,4CAA4C;EAC5C,CAAA;CACF,GALE,QAAQ,EAKV;AAET;;;;;;;;;ACNA,IAAa,iCACX,kBACA,UAAU,UACP;CACH,MAAM,EAAE,gBAAgB,kBAAkB,YAAY,kBAAkB;CACxE,MAAM,EAAE,kBAAkB,uBAAuB;CACjD,MAAM,mBAAmB,iBAAiB,OAAO;CACjD,MAAM,EACJ,cACA,WACA,SACA,SACA,eACA,SACA,UACA,UACA,UACA,mBACE,YAAY,OAAO;CACvB,MAAM,uBAAuB,OAAO,QAAQ,cAAc;CAC1D,MAAM,YAAY,iBAAiB,OAAO;CAC1C,MAAM,aAAa,wBAAwB,OAAO;CAClD,MAAM,wBAAwB,qBAAqB,OAAO;CAE1D,OAAO,cAAc;EACnB,IAAI,SAAS,OAAO;EAGpB,IACE,aACA,oBACA,CAAC,QAAQ,QACT,QAAQ,SAAS,YACjB,QAAQ,SAAS,eACjB,QAAQ,WAAW,WAEnB,OAAO,CAAC;EAEV,OAAO,iBAAiB,QAAQ,WAAW;GACzC,IAAI,OAAO,cAAc,yBAAyB,OAAO;GAEzD,MAAM,OAAO,OAAO;GAGpB,IAAI,8BAA8B,SAAS,IAAI,KAAK,sBAClD,OAAO;GAGT,IAAI,QAAQ,OACV,OACG,SAAS,mBAAmB,mBAAmB,cAAc,cAC7D,SAAS,WAAY,aAAa,WAAY,0BAC9C,SAAS,YACR,CAAC,qBACC,aAAa,aAAc;GAInC,IACE,SAAS,mBACR,SAAS,eAAe,CAAC,gBACzB,SAAS,qBAAqB,CAAC,QAAQ,QACvC,SAAS,cACR,CAAC,QAAQ,aAAa,MACnB,eACC,iBAAiB,UAAU,KAC3B,kBAAkB,UAAU,KAC5B,kBAAkB,UAAU,KAC5B,kBAAkB,UAAU,KAC5B,2BAA2B,UAAU,CACzC,KACD,SAAS,aAAa,CAAC,aAAa,qBACpC,SAAS,UAAU,CAAC,WACpB,SAAS,UAAU,CAAC,WACpB,SAAS,gBAAgB,CAAC,iBAC1B,SAAS,UAAU,CAAC,WACpB,SAAS,WAAW,CAAC,YACrB,SAAS,WAAW,CAAC,YACrB,SAAS,WAAW,CAAC,YACrB,SAAS,cAAc,CAAC,gBAAgB,6BACxC,SAAS,kBAAkB,CAAC,gBAAgB,2BAE7C,OAAO;GAET,OAAO;EACT,CAAC;CACH,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR;EACA;EACA;CACF,CAAC;AACH;;;;;;AC5HA,IAAa,0CAA0C;CACrD,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,YAAY,uBAAuB;CAC3C,MAAM,EAAE,eAAe,eAAe,wBAAwB;CAC9D,MAAM,EAAE,SAAS,eAAe,kBAAkB,mCAAmC;CACrF,MAAM,mBAAmB,OAAwC,KAAA,CAAS;CAE1E,MAAM,oBACJ,QACG,UAAU,EACV,OAAO,EAAE,KAAK,QAAQ,IAAI,GAAG,EAAE,IAAI,QAAQ,UAAU,CAAC,EACtD,MAAM,EAAE,cAAc;EACrB,IAAI,CAAC,QAAQ,QACX,MAAM,IAAI,MAAM,2BAA2B;EAE7C,iBAAiB,UAAU,cAAc,QAAQ,GAAG,OAAO;CAC7D,CAAC,EACA,OAAO,UAAiB;EACvB,gBAAgB;GACd,SAAS,EAAE,aAAa,QAAQ;GAChC,SAAS;GACT;GACA,SAAS,EAAE,2BAA2B;GACtC,UAAU;GACV,MAAM;EACR,CAAC;CACH,CAAC;CAGL,MAAM,+BAA+B,OAAO,OAAe;EACzD,MAAM,cAAc,EAAE;CAExB;CAEA,gBAAgB;EACd,IACE,iBAAiB,WACjB,iBAAiB,YAAY,QAC7B,CAAC,QAAQ,WAET;EACF,MAAM,eAAe,QAAQ,MAAM,YAAY,QAAQ,SAAS;EAChE,IAAI,cAAc;GAChB,iBAAiB,UAAU;GAC3B;EACF;CACF,GAAG,CAAC,SAAS,OAAO,CAAC;CAErB,MAAM,2BAA2B,YAAY;EAC3C,IAAI,CAAC,iBAAiB,SAGpB,IAAI,YAAY;GACd,MAAM,6BAA6B,QAAQ,EAAE;GAC7C;EACF,OAAO,MAAM,YAAY;EAE3B,MAAM,SAAS,iBAAiB;EAChC,IAAI,CAAC,QAAQ;GAEX,iBAAiB,UAAU;GAC3B;EACF;EAEA,IAAI,YAAY,MAAM,6BAA6B,QAAQ,EAAE;OACxD,WAAW,MAAM;CACxB;CAEA,IAAI,CAAC,SAAS,iBAAiB,OAAO;CAEtC,OACE,qBAAC,OAAD;EAAK,WAAU;EAAyC,MAAK;YAA7D;GACE,oBAAC,kBAAD,CAAmB,CAAA;GACnB,oBAAC,QAAD,EAAA,UAAO,aAAa,EAAE,sBAAsB,IAAI,EAAE,qBAAqB,EAAQ,CAAA;GAC/E,oBAAC,QAAD,EAAA,UAAM,MAAS,CAAA;GACf,oBAAC,UAAD;IACE,WAAU;IACV,SAAS;IACT,MAAK;cAEJ,EAAE,MAAM;GACH,CAAA;EACL;;AAET;;;AChFA,SAAS,oCAAoC,OAAuC;CAClF,MAAM,EAAE,aAAA,gBAAc,gBAAuB,oBAC3C,0BAA0B,IAC5B;CACA,MAAM,EACJ,aACA,aACA,SACA,aAAa,aAAa,GAC1B,qBAAqB,qBAAqB,CAAC,MACzC;CACJ,MAAM,EAAE,wBAAwB,uBAAuB;CAEvD,MAAM,EAAE,MAAM,sBAAsB,2BAA2B;CAE/D,MAAM,yBAAyB,cAE3B,mBAAmB,MAAM,GAAG,CAAC,EAAE,KAAK,iBAAiB;EACnD,UAAU,YAAY;EACtB,UAAU,YAAY,QAAQ,YAAY;CAC5C,EAAE,GACJ,CAAC,kBAAkB,CACrB;CAEA,IAAI,CAAC,YAAY,OAAO;CAExB,IAAI,iBAAiB,EAAE,cAAc,EAAE,OAAO,WAAW,CAAC;CAE1D,IAAI,eAAe,aAAa,GAC9B,iBAAiB,GAAG,WAAW,GAAG;MAC7B,IAAI,aACT,iBAAiB,KAAK;CAGxB,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,UAAD;GACE,WAAU;GACV,eAAY;GACZ,UAAU,CAAC,oBAAoB;GACtB;aAJX,CAMG,gBAED,oBAAC,eAAD;IAAa,aAAa;IAAwB,MAAK;GAAM,CAAA,CACvD;;CACL,CAAA;AAET;AAEA,IAAa,4BAA4B,MAAM,KAC7C,mCACF;;;;;;;AC1DA,IAAa,gBAAgB,EAAE,cAAiC;CAC9D,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,WAAW,eAAe;CAElC,IAAI,CAAC,SAAS,OAAO;CAErB,MAAM,WAAW,CAAC,CAAC,QAAQ,WAAW,MAAM,QAAQ,UAAU,OAAO,OAAO,MAAM;CAClF,MAAM,OAAO,QAAQ,WAAW,QAAQ,QAAQ,WAAW,MAAM;CAEjE,MAAM,QAAQ,WACV,EAAE,eAAe,IACjB,OACE,EAAE,wBAAwB,EAAE,KAAK,CAAC,IAClC,EAAE,gBAAgB;CAExB,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD;IAAM,eAAA;IAAY,WAAU;cAC1B,oBAAC,SAAD,CAAU,CAAA;GACN,CAAA,GACN,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA,CAChB;;CACF,CAAA;AAET;;;ACjCA,IAAa,WAAW,EAAE,UAAU,WAAW,GAAG,WAChD,oBAAC,OAAD;CAAK,WAAW,KAAK,qBAAqB,SAAS;CAAG,GAAI;CACvD;AACE,CAAA;AAgBP,IAAa,iBAAwC,EACnD,UACA,WACA,SAAS,CAAC,GAAG,EAAE,GACf,YAAY,OACZ,kBACA,UAAU,YACiB;CAC3B,MAAM,CAAC,eAAe,oBAAoB,SAAgC,IAAI;CAC9E,MAAM,EACJ,WAAW,mBACX,MACA,UACA,GACA,MACE,mBAAmB;EACrB;EACA;CACF,CAAC;CAED,gBAAgB;EACd,KAAK,aAAa,gBAAgB;CACpC,GAAG,CAAC,kBAAkB,IAAI,CAAC;CAE3B,gBAAgB;EACd,KAAK,YAAY,aAAa;CAChC,GAAG,CAAC,eAAe,IAAI,CAAC;CAExB,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,oBAAC,OAAD;EACE,WAAW,KAAK,qBAAqB,SAAS;EAC9C,kBAAgB;EAChB,KAAK;EACL,OAAO;GAAE,MAAM,KAAK;GAAG,UAAU;GAAU,KAAK,KAAK;EAAE;EAEtD;CACE,CAAA;AAET;;;AC9DA,IAAa,yBAAgD,EAC3D,cACA,iBACgF,CAAC,MAAM;CACvF,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,KAAK;CAkB1D,OAAO;EAAE,aAhBuC,aAC7C,MAAM;GACL,kBAAkB,IAAI;GACtB,eAAe,CAAC;EAClB,GACA,CAAC,YAAY,CAWN;EAAa,aAR0B,aAC7C,MAAM;GACL,kBAAkB,KAAK;GACvB,eAAe,CAAC;EAClB,GACA,CAAC,YAAY,CAGO;EAAa;CAAe;AACpD;;;ACCA,IAAM,2BAA2B,UAA8B;CAC7D,MAAM,EACJ,wBACA,mBACA,sBACA,mBACA,cAAc,UACd,wBAAwB,sBACtB;CAEJ,MAAM,EAAE,aAAa,aAAa,mBAChC,sBAAuC;CAEzC,MAAM,EAAE,WAAW,eAAe,eAAe;CACjD,MAAM,EACJ,aACA,aACA,gBACA,SACA,QACA,mBACA,eACE,kBAAkB,eAAe;CACrC,MAAM,EAAE,MAAM,sBAAsB,eAAe;CACnD,MAAM,CAAC,kBAAkB,uBAAuB,SAAiC,IAAI;CAErF,IAAI,CAAC,YAAY,KAAK,QAAQ,SAAS,SAAS,OAAO;CAEvD,MAAM,eAAe,QAAQ,WAAW,KAAK,OAAO,GAAG,OAAO,OAAO,MAAM;CAC3E,MAAM,oBACJ,aAAa,WAAW,KAAK,YAAY,GAAG,OAAO,OAAO,MAAM;CAClE,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,OAAO,CAAC,EAAE,QAAQ,UAAU,CAAC,gBAAgB,CAAC;CACpD,MAAM,YAAY,CAAC,EAAE,aAAa,UAAU,CAAC,qBAAqB,CAAC,QAAQ,CAAC;CAC5E,MAAM,QACH,qBAAqB,gBAAgB,OAAO,QAAQ,OACrD,QAAQ,WAAW,cACnB,CAAC,aACD,CAAC,QACD,CAAC;CAEH,MAAM,wBAAwB,OAC1B,OAAO,QAAQ,SAAS,KAAK,OAAO,OAAO,MAAM,EAAE,IACnD,CAAC;CAEL,OACE,qBAAC,QAAD;EACE,WAAW,KACT,qBAAqB,YAAY,mCACjC;GACE,sCAAsC;GACtC,oCAAoC;GACpC,oCAAoC;GACpC,iCAAiC;EACnC,CACF;EACA,eAAa,KAAK;GAChB,4BAA4B;GAC5B,0BAA0B;GAC1B,0BAA0B;GAC1B,uBAAuB;EACzB,CAAC;EACD,cAAc;EACd,cAAc;EACd,KAAK;YAlBP;GAoBG,YACE,uBACC,oBAAC,sBAAD,CAAuB,CAAA,IAEvB,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,eAAD;IACE,QAAQ,CAAC,GAAG,CAAC;IACK;IAClB,SAAS;cAER,EAAE,YAAY;GACF,CAAA,GACf,oBAAC,WAAD,EAAW,WAAU,mCAAoC,CAAA,CACzD,EAAA,CAAA;GAGL,SACE,oBACC,oBAAC,mBAAD,CAAoB,CAAA,IAEpB,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,eAAD;IACE,QAAQ,CAAC,GAAG,CAAC;IACK;IAClB,SAAS;cAER,EAAE,MAAM;GACI,CAAA,GACf,oBAAC,qBAAD,EAAqB,WAAU,gCAAiC,CAAA,CAChE,EAAA,CAAA;GAGL,cACE,yBACC,oBAAC,wBAAD,CAAyB,CAAA,IAEzB,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,eAAD;IACE,QAAQ,CAAC,GAAG,CAAC;IACK;IAClB,SAAS;cAER,EAAE,WAAW;GACD,CAAA,GACf,oBAAC,YAAD,EAAY,WAAU,qCAAsC,CAAA,CAC5D,EAAA,CAAA;GAGL,SACE,oBACC,oBAAC,mBAAD,CAAoB,CAAA,IAEpB,qBAAA,YAAA,EAAA,UAAA;IACE,oBAAC,eAAD;KACE,QAAQ,CAAC,GAAG,CAAC;KACK;KAClB,SAAS;eAER,qBAAqB,QAAQ,GAAG,QAAQ,qBAAqB;IACjD,CAAA;IAEf,oBAAC,YAAD,EAAY,WAAU,gCAAiC,CAAA;IAEtD,sBAAsB,SAAS,KAC9B,oBAAC,QAAD;KACE,WAAW,qBAAqB,YAAY;KAC5C,eAAY;eAEX,sBAAsB;IACnB,CAAA;GAER,EAAA,CAAA;EAEF;;AAEV;AAEA,IAAa,gBAAgB,MAAM,KACjC,uBACF;;;AC5KA,SAAgB,aAAa,MAAc;CACzC,OAAO,KAAK,QAAQ,2BAA2B,MAAM;AACvD;AAEA,IAAa,aAAa;AAM1B,IAAM,YAAY;AAClB,IAAM,eAAe;AACrB,IAAM,cAAc;AAEpB,IAAa,qBAAqB,YAAoB;CAEpD,OADgB,QAAQ,MAAM,SACvB,KAAW,CAAC;AACrB;AAEA,IAAa,sBAAsB,YAAoB;CACrD,MAAM,UAAU,QAAQ,MAAM,YAAY;CAS1C,QAPc,UACV,QAAQ,KAAK,UAAU;EACrB,MAAM,IAAI,YAAY,KAAK,KAAK;EAChC,OAAO,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE;CACzB,CAAC,IACD,CAAC,GAEQ,KAAK;AACpB;;;ACvBA,IAAa,4BAA4B;CACvC,MAAM,WAA4B,UAChC,EAAE,WAAW;EAAE,YAAY,CAAC;EAAG,SAAS;CAAQ,GAAG,CAAC,EAAE,QAAQ,KAAK,CAAC,CAAC;CAEvE,MAAM,aAAa,SAAgB,eAAe,MAAM,CAAC,aAAa,OAAO,CAAC;CAE9E,OAAO;AACT;;;ACLA,IAAa,0BAA0B,0BAA0C;CAC/E,MAAM,sBAAsB,gBACzB,KAAK,SAAS,KAAK,QAAQ,KAAK,EAAE,EAClC,OAAO,OAAO,EACd,IAAI,YAAY;CAEnB,MAAM,sBAAsB,IAAI,OAC9B,oBAAoB,KAAK,aAAa,IAAI,UAAU,EAAE,KAAK,GAAG,GAC9D,GACF;CAEA,MAAM,WAA4B,UAAU;EAC1C,MAAM,eAAe,MAAM,QAAQ,KAAK,EAAE;EAI1C,OAAO,EAAE,WAAW;GAAE,eAHT,gBAAgB,MAC1B,EAAE,IAAI,WAAW,SAAS,gBAAgB,OAAO,YAEf;GAAM,YAAY,CAAC;GAAG,SAAS;EAAU,GAAG,CAC/E,EAAE,QAAQ,KAAK,CACjB,CAAC;CACH;CAEA,MAAM,aAAa,SAAgB;EACjC,IAAI,CAAC,oBAAoB,QAAQ;EAQjC,MAAM,OAAO,MAAM,OAAO,WAAW;GACnC,IAAI,OAAO,UAAU,aAAa;GAClC,IAAI,CAAC,QAAQ;GAGb,MAAM,gBADY,OAAO,SAAS,GAAG,QAAQ,CACvB,GAAW,YAAY;GAE7C,IACE,KAAK,SAAS,UAKd,cAAc,KAAK,KAAK,KAAK,KAC7B,eAAe,WAAW,SAAS,GACnC;IACA,MAAM,eAAe,KAAK,MAAM,QAAQ,MAAM,EAAE;IAChD,MAAM,WAAW,cAAc,QAAQ,WAAW,EAAE;IACpD,OAAO,SAAS,SAAS,EAAE,QAAQ,YAAY;IAC/C,OAAO,SAAS,QAAQ,KAAK,EAAE,QAAQ,IAAI,UAAU;GACvD;EACF,CAAC;EAED,eAAe,MAAM,CAAC,qBAAqB,OAAO,CAAC;CACrD;CAEA,OAAO;AACT;;;AC3DA,IAAM,WAAoB,SAAS;CACjC,IAAI,KAAK,SAAS,QAAQ;CAE1B,KAAK,OAAO;AACd;AACA,IAAM,aAAa,SAAgB;CACjC,MAAM,MAAM,OAAO;AACrB;AAEA,IAAa,yBAAyB;;;ACFtC,IAAM,QAAQ,WAAyB;CAAE,MAAM;CAAQ;AAAM;;;;;;;;AAS7D,SAAgB,YAAY,EAAE,mBAAmB,UAAoC,CAAC,GAAG;CACvF,QAAQ,SAAe;EACrB,MAAM,WAAuB,MAAM,OAAO,WAAW;GACnD,IAAI,UAAU,QAAQ,SAAS,MAAM;GAGrC,MAAM,OAAa;IACjB,UAAU,CAAC,KAFC,KAAK,qBAAqB,KAAK,GAEtB,CAAC;IACtB,OAAO,KAAK,SAAS,KAAK,OAAO,KAAK;IACtC,MAAM;IACN,KAAK,KAAK;GACZ;GAEA,OAAO,SAAS,OAAO,OAAO,GAAG,IAAI;GACrC,OAAO,CAAC,MAAM,QAAQ,CAAC;EACzB;EAEA,MAAM,MAAM,SAAS,OAAO;CAC9B;AACF;;;;ACpCA,SAAS,qBACP,MACmD;CACnD,MAAM,QAAQ;CACd,OAAO,MAAM,QAAQ,MAAM,QAAQ;AACrC;;AAGA,SAAS,SAAwB;CAC/B,OAAO;EAAE,MAAM,EAAE,OAAO,KAAK;EAAG,MAAM;CAAgB;AACxD;;;;;;;;AASA,IAAa,8BAAgD,SAAS;CACpE,MACE,MACA,uBACC,WAAW;EACV,MAAM,WAAW,OAAO;EACxB,IAAI,SAAS,SAAS,GAAG;EAEzB,MAAM,MAAqB,CAAC;EAE5B,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;GACxC,MAAM,OAAO,SAAS;GACtB,IAAI,KAAK,IAAI;GAEb,IAAI,MAAM,SAAS,SAAS,GAAG;GAE/B,MAAM,OAAO,SAAS,IAAI;GAE1B,MAAM,cACJ,KAAK,YAAY,KAAK,SAAS,MAAM,KAAK,SAAS,IAAI,OAAO,KAAA;GAChE,MAAM,gBACJ,KAAK,YAAY,KAAK,SAAS,QAAQ,KAAK,SAAS,MAAM,OAAO,KAAA;GAEpE,IAAI,OAAO,gBAAgB,YAAY,OAAO,kBAAkB,UAC9D;GAKF,MAAM,kBAAkB,KAAK,IAAI,GAAG,gBAAgB,cAAc,CAAC;GACnE,IAAI,kBAAkB,GACpB,KAAK,IAAI,IAAI,GAAG,IAAI,iBAAiB,KACnC,IAAI,KAAK,OAAO,CAAC;EAGvB;EAEA,OAAO,WAAW;CACpB,CACF;AACF;;;;;;;;;;;;;;;AC/CA,IAAM,YAAY;AAClB,IAAM,oBAAoB,IAAI,IAAI;CAChC;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;AAMD,IAAa,2BAAuC;CAClD,MAAM,WAAoB,MAAM,OAAO,WAAW;EAEhD,IAAI,kBAAkB,IAAI,KAAK,IAAI,GAAG,OAAO;EAG7C,IAAI,KAAK,SAAS,UAAU,UAAU,QAAQ,OAAO,UAAU,UAAU;EAEzE,MAAM,QAAS,KAAc;EAG7B,UAAU,YAAY;EAEtB,IAAI;EACJ,IAAI,OAAO;EACX,MAAM,MAAyB,CAAC;EAEhC,OAAQ,QAAQ,UAAU,KAAK,KAAK,GAAI;GACtC,MAAM,CAAC,MAAM,SAAS;GACtB,MAAM,QAAQ,MAAM;GAEpB,IAAI,QAAQ,MAAM,IAAI,KAAK;IAAE,MAAM;IAAQ,OAAO,MAAM,MAAM,MAAM,KAAK;GAAE,CAAC;GAG5E,IAAI,KAAK;IACP,UAAU,CAAC;KAAE,MAAM;KAAQ,OAAO;IAAM,CAAC;IACzC,MAAM,EAAE,OAAO,MAAM;IACrB,MAAM;GACR,CAAC;GAED,OAAO,QAAQ,KAAK;EACtB;EAEA,IAAI,IAAI,WAAW,GAAG;EACtB,IAAI,OAAO,MAAM,QAAQ,IAAI,KAAK;GAAE,MAAM;GAAQ,OAAO,MAAM,MAAM,IAAI;EAAE,CAAC;EAE5E,OAAmB,SAAS,OAAO,OAAO,GAAG,GAAG,GAAG;EAGnD,OAAO,CAAC,MAAM,QAAQ,IAAI,MAAM;CAClC;CAEA,QAAQ,SAAS,MAAM,MAAM,OAAO;AACtC;;;;;;;;ACpEA,IAAa,8BAAgD,MAAM,SAAS;CAM1E,KAAK,WAAW,CAAC;EAFc,UAAU,CAAC;GADrB,MAAM;GAAQ,OAFpB,OAAO,KAAK,SAAS,EAEM;EACA,CAAI;EAAG,MAAM;CAEtC,CAAS;AAC5B;;;ACXA,IAAa,UAAU,EAAE,UAAU,WAAgC;CACjE,MAAM,UAAU,MAAM,WAAW,SAAS;CAC1C,MAAM,QAAQ,MAAM,WAAW,MAAM;CAErC,IAAI,CAAC,QAAS,CAAC,WAAW,CAAC,OAAQ,OAAO,oBAAA,YAAA,EAAG,SAAW,CAAA;CAExD,OACE,oBAAC,KAAD;EACE,WAAW,KAAK,EAAE,8BAA8B,MAAM,CAAC;EACjD;EACN,KAAI;EACJ,QAAO;EAEN;CACA,CAAA;AAEP;;;ACjBA,IAAa,SAAS,EAAE,eACtB,oBAAC,QAAD;CAAM,WAAU;CAAoB,eAAY;CAC7C;AACG,CAAA;;;ACKR,IAAa,WAAW,EAAE,UAAU,MAAM,EAAE,sBAC1C,oBAAC,QAAD;CAAM,WAAU;CAA4B,gBAAc,cAAc;CACrE;AACG,CAAA;;;ACdR,IAAa,sBAAsB;;;ACKnC,IAAa,gBAAb,cAAmC,UAAqD;CACtF,YAAY,OAA2B;EACrC,MAAM,KAAK;EACX,KAAK,QAAQ,EAAE,UAAU,MAAM;CACjC;CAEA,OAAO,2BAA2B;EAChC,OAAO,EAAE,UAAU,KAAK;CAC1B;CAEA,kBAAkB,OAAgB,aAAsB;EACtD,QAAQ,MAAM,OAAO,WAAW;CAClC;CAEA,SAAS;EACP,IAAI,KAAK,MAAM,UACb,OAAO,KAAK,MAAM;EAGpB,OAAO,KAAK,MAAM;CACpB;AACF;;;ACCA,IAAa,yBAET;CACF;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,SAAS,oBAAoB,KAAa;CACxC,IAAI;EACF,OAAO,mBAAmB,GAAG,EAAE,QAAQ,YAAY,EAAE;CACvD,SAAS,GAAG;EACV,OAAO;CACT;AACF;AAEA,SAAS,aAAa,KAAa;CACjC,IAAI;EACF,OAAO,UAAU,mBAAmB,GAAG,CAAC;CAC1C,SAAS,OAAO;EACd,OAAO;CACT;AACF;AAEA,IAAM,gBAAgB,QACpB,IAAI,WAAW,QAAQ,IAAI,MAAM,oBAAoB,GAAG;AAE1D,IAAM,qBAAmD,YACvD;AAEF,IAAa,oBAAkE;CAC7E,GAAG;CACH,OAAO;CACP,SAAS;AACX;AAaA,IAAa,cACX,MACA,gBACA,EACE,kBAAkB,wBAClB,yBACA,mBAAmB,mBACnB,mBAAmB,sBACE,CAAC,MACrB;CAGH,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,KAAK,KAAK,EAAE,WAAW,GAAG,OAAO,oBAAA,YAAA,EAAA,UAAG,KAAO,CAAA;CAE/C,IAAI,UAAU;CACd,MAAM,gBAAgB,mBAAmB,OAAO;CAChD,MAAM,aAAa,kBAAkB,OAAO;CAK5C,MAAM,QAAQ,CAAC,GAAG,KAAK,SAAS,OAAO,GAAG,GAAG,KAAK,SAAS,KAAK,CAAC;CACjE,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;EAC1C,MAAM,EAAE,KAAK,MAAM,OAAO,MAAM,UAAU,MAAM;EAChD,MAAM,gBAAgB,WAAW,MAAM,UAAU,OAAO,SAAS,KAAK,CAAC;EAcvE,KAVE,iBACA,cAAc,QAAQ,SAAS;GAC7B,MAAM,eAAe,MAAM,QAAQ,YAAY,EAAE;GACjD,MAAM,eAAe,MAAM,QAAQ,YAAY,EAAE;GAEjD,IAAI,CAAC,gBAAgB,CAAC,cAAc,OAAO;GAE3C,OAAO,aAAa,SAAS,YAAY,KAAK,aAAa,SAAS,YAAY;EAClF,CAAC,GAEiB,SAAS,KAAK,eAAe;EAEjD,IAAI;GAKF,IAAI,SAAS,WAAW;QACO,eAAe,MAAM,MAAM,EAAE,SAAS,KAC/D,GAAsB;KAExB,MAAM,YAAY,QAAQ,OAAO,QAAQ,CAAC,MAAM;KAGhD,UACE,QAAQ,MAAM,GAAG,KAAK,KACrB,YAAY,QAAQ,IAAI,MAAM,IAAI,aAAa,IAAI,EAAE,MACtD,QAAQ,MAAM,GAAG;IACrB;UACK;IACL,MAAM,cAAc,SAAS,UAAU,QAAQ,oBAAoB,IAAI;IAEvE,UACE,QAAQ,MAAM,GAAG,KAAK,IACtB,IAAI,YAAY,IAAI,aAAa,IAAI,EAAE,KACvC,QAAQ,MAAM,GAAG;GACrB;EACF,SAAS,GAAG,CAEZ;CACF;CAEA,MAAM,gBAA+B;EACnC;EACA;EACA,CAAC,WAAW,EAAE,aAAa,MAAM,CAAC;EAClC;EACA;CACF;CACA,MAAM,gBAA+B,CAAC,mBAAmB;CAEzD,IAAI,gBAAgB,QAClB,cAAc,KAAK,uBAAuB,cAAc,CAAC;CAG3D,OACE,oBAAC,eAAD;EAAe,UAAU,oBAAA,YAAA,EAAA,UAAG,KAAO,CAAA;YACjC,oBAAC,eAAD;GACE,iBAAiB;GACjB,YAAY;IACV,GAAG;IACH,GAAG;GACL;GACA,eAAe,iBAAiB,aAAa;GAC7C,eAAe,iBAAiB,aAAa;GAC7C,UAAA;GACA,kBAAA;GACc;aAEb;EACY,CAAA;CACF,CAAA;AAEnB;;;ACtLA,IAAM,kCAAkC,UAA4B;CAClE,MAAM,EACJ,kBACA,qBAAqB,IACrB,SAAS,aACT,YAAY,oBACV;CAEJ,MAAM,EACJ,SAAS,gBACT,wBACA,wBACA,YAAY,mBACZ,kBAAkB,cAClB,eACE,kBAAkB,aAAa;CAEnC,MAAM,eAAa,mBAAmB,qBAAqB;CAE3D,MAAM,EAAE,GAAG,iBAAiB,sBAAsB,aAAa;CAC/D,MAAM,UAAU,eAAe;CAC/B,MAAM,gBAAgB,sBAAsB,OAAO;CACnD,MAAM,mBAAmB,YAAY;CACrC,MAAM,gBAAgB,YAAY;CAElC,MAAM,sBACJ,oBAAoB,aAChB,QAAQ,OACR,yBAAyB;EAAE,UAAU;EAAc;CAAQ,CAAC,KAAK,QAAQ;CAE/E,MAAM,cAAc,cACZ,aAAW,qBAAqB,QAAQ,eAAe,GAC7D;EAAC,QAAQ;EAAiB;EAAqB;CAAU,CAC3D;CAEA,MAAM,eAAe,sBAAsB;CAC3C,MAAM,aAAa;CAEnB,MAAM,+BADoB,QAAQ,QAAQ,iBAAiB,MAEzD,KAAqB,OAAO,2BAA2B;CACzD,MAAM,aAAa,QAAQ,MAAM;CACjC,MAAM,iBAAiB,aACnB,EAAE,iCAAiC,EAAE,MAAM,WAAW,CAAC,IACvD,EAAE,eAAe;CAGrB,MAAM,oBAAoB,GAAG,iBAAiB,GAAG;CAEjD,MAAM,yBAAyB,UAA+C;EAC5E,IAAI,CAAC,gCAAiC,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAC3E;EAGF,MAAM,eAAe;EACrB,uBAAuB,KAAK;CAC9B;CAEA,IAAI,CAAC,qBAAqB,OAAO;;;;;;;;;;;;;CAcjC,OACE,qBAAC,OAAD;EACE,mBAAiB,+BAA+B,KAAA,IAAY;EAC5D,WAAW;EACX,UAAU,+BAA+B,KAAA,IAAY;YAHvD,CAKE,oBAAC,gBAAD;GAAgB,IAAI;aAAmB;EAA+B,CAAA,GACtE,oBAAC,OAAD;GACE,mBAAiB,+BAA+B,oBAAoB,KAAA;GACpE,WAAW,KAAK,YAAY;KACzB,4CACC,yBAAyB,OAAO,KAAK,CAAC,QAAQ;KAC/C,iDAAiD;GACpD,CAAC;GACD,eAAY;GACZ,SAAS;GACT,WAAW,+BAA+B,wBAAwB,KAAA;GAClE,aAAa;GACb,UAAU,+BAA+B,IAAI,KAAA;aAE5C,cAAc,QAAQ,OACrB,oBAAC,OAAD;IAAK,yBAAyB,EAAE,QAAQ,QAAQ,KAAK;IAAG,IAAI;GAAgB,CAAA,IAE5E,oBAAC,OAAD;IAAK,IAAI;cAAgB;GAAiB,CAAA;EAEzC,CAAA,CACF;;AAET;AAEA,IAAa,cAAc,MAAM,KAC/B,8BACF;;;AC/GA,SAAgB,UAAU,OAAuB;CAC/C,MAAM,EAAE,UAAU,iBAAiB,aAAa,QAAQ,cAAc;CAEtE,MAAM,EAAE,eAAe,kBAAkB,kBAAkB;CAC3D,MAAM,EAAE,GAAG,oBAAoB,sBAAsB,kBAAkB;CAEvE,MAAM,sBACJ,aAAa,OAAO,SAAS,IAAI,UAAU,YAAY,IAAI;CAE7D,MAAM,OAAO,cAET,cAAc;EACZ;EACA;EACA;EACA;EACA,kBAAkB;EAClB;EACA;EACA,yBAAyB;CAC3B,CAAC,GACH;EACE;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,IAAI,CAAC,MACH,OAAO;CAGT,OACE,oBAAC,QAAD;EACE,WAAW;EACX,UAAU;EACV,OAAO;YAEN;CACG,CAAA;AAEV;;;AC5CA,IAAM,8BAA8B,UAAiC;CACnE,MAAM,EAAE,SAAS,aAAa,GAAG,mBAAmB;CACpD,MAAM,EAAE,SAAS,mBAAmB,kBAAkB,kBAAkB;CACxE,MAAM,EAAE,WAAA,cAAY,cAAqB,oBAAoB,kBAAkB;CAE/E,OAAO,oBAAC,aAAD;EAAW,YADF,eAAe,gBACM;EAAY,GAAI;CAAiB,CAAA;AACxE;AAEA,IAAa,mBAAmB,MAAM,KACpC,0BACF;;;ACNA,IAAM,oCAAoC,UAAuC;CAC/E,MAAM,EAAE,aAAa,SAAS,aAAa,GAAG,mBAAmB;CACjE,MAAM,EAAE,SAAS,mBAAmB,kBAAkB,wBAAwB;CAC9E,MAAM,EAAE,MAAM,sBAAsB,wBAAwB;CAC5D,MAAM,EAAE,WAAA,cAAY,cAAqB,oBAAoB,wBAAwB;CACrF,MAAM,UAAU,eAAe;CAE/B,MAAM,CAAC,kBAAkB,uBAAuB,SAAiC,IAAI;CACrF,MAAM,EAAE,aAAa,aAAa,mBAChC,sBAAuC;CAEzC,IAAI,CAAC,SAAS,yBACZ,OAAO;CAGT,OACE,qBAAC,QAAD;EACE,WAAW,eAAe;EAC1B,eAAY;EACZ,cAAc;EACd,cAAc;EACd,KAAK;YALP,CAOG,EAAE,QAAQ,GACX,oBAAC,eAAD;GACE,QAAQ,CAAC,GAAG,CAAC;GACb,WAAU;GACQ;GAClB,SAAS;aAET,oBAAC,aAAD;IAAW,WAAW,QAAQ;IAAyB,GAAI;GAAiB,CAAA;EAC/D,CAAA,CACX;;AAEV;AAEA,IAAa,yBAAyB,MAAM,KAC1C,gCACF;;;AC3CA,IAAa,+BAA+B,EAC1C,SAAS,kBACsB;CAC/B,MAAM,EAAE,GAAG,iBAAiB,sBAAsB;CAClD,MAAM,EACJ,SAAS,gBACT,oBACA,oBACE,kBAAkB,6BAA6B;CACnD,MAAM,UAAU,eAAe;CAE/B,MAAM,wBAAwB,cACtB,yBAAyB;EAAE,UAAU;EAAc;CAAQ,CAAC,GAClE,CAAC,cAAc,OAAO,CACxB;CAEA,MAAM,gCAAgC,cAElC,yBAAyB,QACzB,SAAS,SAAS,KAAA,KAClB,0BAA0B,QAAQ,MACpC,CAAC,uBAAuB,SAAS,IAAI,CACvC;CAEA,MAAM,kBAAkB,cAEpB,oBAAoB,cACnB,oBAAoB,KAAA,KAAa,CAAC,+BACrC,CAAC,iBAAiB,6BAA6B,CACjD;CAEA,MAAM,eAAe,kBAAkB;EACrC,qBAAqB,kBAAkB,eAAe,UAAU;CAClE,GAAG,CAAC,oBAAoB,eAAe,CAAC;CAExC,MAAM,qBAAqB,cAAc;EACvC,MAAM,qBAAqB,SAAS,MAAM;EAC1C,IAAI,CAAC,oBAAoB,OAAO;EAChC,MAAM,cAAc,cAAc;EAClC,MAAM,iBAAiB,EAAE,WAAW;EACpC,OAAO,kBAAkB,mBAAmB,cACxC,iBACA;CACN,GAAG,CAAC,SAAS,MAAM,UAAU,CAAC,CAAC;CAE/B,IAAI,CAAC,SAAS,QAAQ,CAAC,oBAAoB,OAAO;CAClD,IAAI,CAAC,+BAA+B,OAAO;CAE3C,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,eAAD,CAAgB,CAAA;GAChB,oBAAC,QAAD;IAAM,WAAU;cACb,kBACG,EAAE,UAAU,IACZ,qBACE,EAAE,kCAAkC,EAAE,UAAU,mBAAmB,CAAC,IACpE,EAAE,YAAY;GAChB,CAAA;GACN,oBAAC,QAAD,EAAA,UAAM,MAAS,CAAA;GACf,oBAAC,QAAD;IACE,WAAU;IACV,SAAS;IACT,MAAK;cAEJ,kBAAkB,EAAE,kBAAkB,IAAI,EAAE,eAAe;GACtD,CAAA;EACL;;AAET;;;;;;;AC7DA,IAAa,kBAAkB,EAC7B,UACA,WACA,mBACA,mBACyB;CACzB,MAAM,EAAE,MAAM,sBAAsB;CACpC,IAAI,CAAC,UAAU,OAAO;CACtB,MAAM,OAAO,YAAY,QAAQ;CACjC,IAAI,CAAC,MAAM,OAAO;CAElB,OACE,oBAAC,KAAD;EACE,cAAY,EAAE,0BAA0B;EACxC,WAAW,KACT,oBACA,+BACA,6BACA,8BACA,6BACA,8CACA,SACF;EACA,UAAU,qBAAqB;EACzB;EACN,KAAI;EACJ,QAAO;EACP,OAAO,gBAAgB,EAAE,qBAAqB;YAE9C,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,cAAD,EAAc,WAAU,kEAAmE,CAAA;EACxF,CAAA;CACJ,CAAA;AAEP;;;ACnDA,IAAa,2BAA2B;AACxC,IAAa,8BAA8B;;AAE3C,IAAa,+BAA+B;;AAY5C,IAAa,wBAAuE;CAClF,IAAI;EAAE,QAAQ;EAAI,QAAQ;EAAI,QAAQ;EAAI,OAAO;CAAG;CACpD,IAAI;EAAE,QAAQ;EAAI,QAAQ;EAAI,QAAQ;EAAI,OAAO;CAAG;CACpD,IAAI;EAAE,QAAQ;EAAI,QAAQ;EAAI,QAAQ;EAAM,OAAO;CAAG;CACtD,IAAI;EAAE,QAAQ;EAAI,QAAQ;EAAI,QAAQ;EAAI,OAAO;CAAG;AACtD;;AAGA,IAAa,2BACX,cACkD;CAClD,IAAI,CAAC,WAAW,OAAO;CACvB,OAAQ;EAAC;EAAM;EAAM;EAAM;CAAI,EAAY,QACxC,KAAK,UAAU;EACd,GAAG;GACF,OAAO;GAAE,GAAG,sBAAsB;GAAO,GAAG,UAAU;EAAM;CAC/D,IACA,CAAC,CACH;AACF;AAEA,IAAM,oBAAoB;CAAE,QAAQ;CAAI,OAAO;AAAG;AAClD,IAAM,uBACJ;AACF,IAAM,sBAAsB;AAC5B,IAAM,2CAA2C,KAAK;AACtD,IAAM,2CAA2C,KAAK;AAWtD,IAAM,OAAO,EAAE,WAAW,MAAM,YAAY,GAAG,YAAsB;CAEnE,MAAM,aAAa,QADJ,cAAc,uBACI,QAAQ,KAAA;CACzC,MAAM,kBAAkB,aACpB;EACE,YAAY;EACZ,QAAQ,GAAG,WAAW,OAAO;EAC7B,OAAO,GAAG,WAAW,MAAM;CAC7B,IACA,KAAA;CAEJ,OACE,oBAAC,OAAD;EACE,QAAQ,YAAY;EACpB,SAAS,OAAO,kBAAkB,MAAM,GAAG,kBAAkB;EAC7D,OAAO,YAAY;EACnB,OAAM;EACN,GAAI;EACJ,WAAW,KACT,0BACA,GAAG,GAAG,yBAAyB,SAAS,SAAS,KAAK,GACtD,SACF;EACA,OAAO;GAAE,GAAG;GAAiB,GAAG,MAAM;EAAM;CAC7C,CAAA;AAEL;AAQA,IAAM,iBAAiB,EAAE,OAAO,MAAM,iBAAqC;CAEzE,MAAM,SAAS,QADG,cAAc,uBACA,QAAQ;EAAE,QAAQ;EAAI,QAAQ;CAAG;CACjE,OACE,oBAAC,QAAD;EAAM,WAAU;EAA6B,GAAG,OAAO;EAAQ,GAAG,OAAO;YACtE;CACG,CAAA;AAEV;AAOA,IAAM,eAAkC;CACtC,aACE,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAO,GAAE;GAAI,GAAE;EAAQ,CAAA;EACtE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAO,GAAE;GAAI,GAAE;EAAQ,CAAA;EACtE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAM,GAAE;GAAI,GAAE;EAAQ,CAAA;CACrE,EAAA,CAAA;CAEJ,gBACE,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAO,GAAE;GAAI,GAAE;EAAQ,CAAA;EACtE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAO,GAAE;GAAI,GAAE;EAAQ,CAAA;EACtE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAM,GAAE;GAAI,GAAE;EAAQ,CAAA;CACrE,EAAA,CAAA;AAEN;AAEA,IAAM,gBAAmC;CACvC,aACE,qBAAA,YAAA,EAAA,UAAA;EACE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAO,GAAE;GAAI,GAAE;EAAQ,CAAA;EACtE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAO,GAAE;GAAI,GAAE;EAAQ,CAAA;EACtE,oBAAC,QAAD;GAAM,MAAK;GAAQ,QAAO;GAAM,IAAG;GAAM,OAAM;GAAM,GAAE;GAAI,GAAE;EAAQ,CAAA;CACrE,EAAA,CAAA;CAEJ,gBAAgB,aAAa;AAC/B;AAEA,IAAM,eAAkC;CACtC,aACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;CAEH,gBACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;AAEL;AAEA,IAAM,gBAAmC;CACvC,aACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;CAEH,gBACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;AAEL;AAEA,IAAM,uBAA0C;CAC9C,aACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;CAEH,gBACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;AAEL;AAEA,IAAM,sBAAyC;CAC7C,aACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;CAEH,gBACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;AAEL;AAEA,IAAM,sBAAyC;CAC7C,aACE,oBAAC,QAAD;EACE,UAAS;EACT,GAAE;EACF,MAAK;EACL,UAAS;CACV,CAAA;CAEH,gBACE,oBAAC,QAAD;EACE,UAAS;EACT,GAAE;EACF,MAAK;EACL,UAAS;CACV,CAAA;AAEL;AAEA,IAAM,gBAAmC;CACvC,aACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;CAEH,gBACE,oBAAC,QAAD;EACE,GAAE;EACF,QAAO;EACP,eAAc;EACd,gBAAe;EACf,aAAY;CACb,CAAA;AAEL;AAQA,IAAM,wBAAwB,EAC5B,WACA,OACA,mBACA,OACA,MACA,YACA,SACA,GAAG,YAC4B;CAC/B,MAAM,cAAc,CAAC,CAAC;CACtB,MAAM,gBAAgB,cAAc,QAAQ,KAAA;CAC5C,MAAM,gBAAgB,cAAc,gBAAgB;CAEpD,OACE,qBAAC,KAAD;EACE,GAAI;EACJ,WAAW,KAAK,mBAAmB,SAAS;EACtC;EACM;YAJd,CAME,qBAAC,KAAD;GAAG,WAAW;aAAd;IACE,oBAAC,QAAD;KAAM,GAAG;KAAsB,MAAM;IAAQ,CAAA;IAC5C,cACC,QAAQ,iBAER,oBAAC,KAAD;KACE,WAAW,SAAS,yCAAyC,GAAG,yCAAyC;eAExG,QAAQ;IACR,CAAA;IAEL,oBAAC,QAAD;KAAM,GAAG;KAAqB,MAAK;KAAQ,SAAQ;IAAO,CAAA;GACzD;MACF,iBACC,oBAAC,eAAD;GAAe,OAAO;GAAqB;GAAkB;EAAa,CAAA,CAEzE;;AAET;AAEA,IAAM,mBACJ,oBAAC,QAAD;CACE,GAAE;CACF,MAAK;AACN,CAAA;AAGH,IAAM,oBACJ,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,QAAD;CACE,GAAE;CACF,MAAK;AACN,CAAA,GACD,oBAAC,QAAD;CACE,GAAE;CACF,MAAK;AACN,CAAA,CACD,EAAA,CAAA;AAGJ,IAAa,eAAe,EAC1B,WACA,OACA,MACA,YACA,GAAG,YACoB;CACvB,MAAM,qBAAqB,CAAC,CAAC;CAE7B,OACE,oBAAC,KAAD;EACE,GAAI;EACJ,WAAW,KACT,4BACA,sBAAA,iCACA,SACF;EACM;EACM;YAEZ,qBAAC,KAAD;GAAG,WAAW;aAAd;IACE,oBAAC,QAAD;KAAM,GAAG;KAAsB,MAAK;IAAW,CAAA;IAC9C,qBACC,oBAEA,oBAAC,KAAD;KACE,WAAW,SAAS,yCAAyC,GAAG,yCAAyC;eAExG;IACA,CAAA;IAEL,oBAAC,QAAD;KAAM,GAAG;KAAqB,MAAK;KAAQ,SAAQ;IAAO,CAAA;GACzD;;CACA,CAAA;AAET;AAEA,IAAa,gBAAgB,EAAE,WAAW,OAAO,GAAG,YAClD,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;AAGH,IAAa,sBAAsB,EAAE,WAAW,OAAO,GAAG,YACxD,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;AAGH,IAAa,iBAAiB,EAAE,YAAY,IAAI,OAAO,GAAG,YACxD,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;AAGH,IAAa,mBAAmB,EAC9B,YAAY,IACZ,QAAQ,IACR,GAAG,YAEH,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;AAGH,IAAa,gBAAgB,EAAE,YAAY,IAAI,OAAO,GAAG,YACvD,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;AAGH,IAAa,iBAAiB,EAAE,YAAY,IAAI,OAAO,GAAG,YACxD,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;AAGH,IAAa,iBAAiB,EAAE,YAAY,IAAI,OAAO,GAAG,YACxD,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;AAGH,IAAa,oBAAoB,EAC/B,YAAY,IACZ,QAAQ,IACR,GAAG,YAEH,oBAAC,sBAAD;CACE,GAAI;CACO;CACX,OAAM;CACN,mBAAkB;CACX;CACP,SAAS;AACV,CAAA;;;AC7bH,IAAa,gBAAgB;CAG3B;CAEA;CAEA;CAEA;CAEA;CAEA;CAIA;CAEA;CAEA;AAGF;AAEA,IAAa,iBAAiB;CAE5B;CAKA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAIA;CAEA;CAEA;AAGF;AAEA,IAAa,sBAAsB;CAGjC;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAIA;CAEA;CAEA;AAGF;AAEA,IAAa,mBAAmB;CAE9B;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;AACF;AAEA,IAAa,gBAAgB;CAE3B;CAEA;CAEA;CACA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;AACF;AAEA,IAAa,yBAAiD;CAE5D,wBAAwB;CACxB,oBAAoB;CACpB,4BAA4B;CAC5B,oBAAoB;CACpB,uBAAuB;CACvB,sBAAsB;CACtB,+BAA+B;CAC/B,4BAA4B;CAC5B,mBAAmB;CACnB,mBAAmB;CACnB,0BAA0B;CAC1B,mBAAmB;CACnB,gCAAgC;CAChC,uCAAuC;CACvC,mCAAmC;CACnC,4BAA4B;CAC5B,kDAAkD;CAClD,kDAAkD;CAClD,qDAAqD;CACrD,iCAAiC;CACjC,iCAAiC;CACjC,uDAAuD;CACvD,8DAA8D;CAC9D,2DAA2D;CAC3D,0DAA0D;CAC1D,oDAAoD;CACpD,oDAAoD;CACpD,mDAAmD;CACnD,4DAA4D;CAC5D,4DAA4D;CAC5D,kDAAkD;CAClD,2DAA2D;CAC3D,2DAA2D;CAC3D,2CAA2C;CAC3C,oDAAoD;CACpD,oDAAoD;CACpD,6EAA6E;CAC7E,0EAA0E;CAC1E,yEAAyE;CACzE,qEAAqE;CACrE,wEAAwE;CACxE,2EAA2E;CAC3E,2EAA2E;CAC3E,uBAAuB;CACvB,yBAAyB;CACzB,oBAAoB;CACpB,+BAA+B;CAC/B,yBAAyB;CACzB,yBAAyB;CACzB,sBAAsB;CACtB,uBAAuB;CACvB,qBAAqB;CACrB,0BAA0B;CAC1B,qBAAqB;CACrB,yBAAyB;CACzB,yBAAyB;CACzB,2BAA2B;CAC3B,+BAA+B;CAC/B,4BAA4B;CAC5B,qBAAqB;CACrB,sBAAsB;CACtB,sBAAsB;CACtB,sBAAsB;CACtB,kCAAkC;CAClC,4BAA4B;CAC5B,sBAAsB;CACtB,qBAAqB;CACrB,gCAAgC;CAChC,sBAAsB;CACtB,oBAAoB;CACpB,6BAA6B;CAC7B,iCAAiC;CACjC,qBAAqB;CACrB,yBAAyB;CACzB,qBAAqB;CACrB,4BAA4B;CAC5B,oBAAoB;CACpB,sBAAsB;CACtB,yBAAyB;CACzB,mBAAmB;CACnB,mBAAmB;CAGnB,aAAa;CACb,cAAc;CACd,cAAc;CACd,aAAa;CACb,cAAc;CACd,aAAa;CACb,cAAc;CACd,aAAa;CACb,cAAc;CACd,gBAAgB;CAChB,eAAe;CACf,gBAAgB;CAChB,kBAAkB;CAClB,eAAe;CAGf,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,cAAc;CAGd,cAAc;CACd,cAAc;CACd,aAAa;CACb,aAAa;CACb,cAAc;CACd,cAAc;CACd,cAAc;CACd,aAAa;CACb,iBAAiB;CACjB,cAAc;CACd,4BAA4B;CAC5B,cAAc;CACd,gBAAgB;CAGhB,iBAAiB;CACjB,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,mBAAmB;CACnB,iBAAiB;CACjB,cAAc;CACd,YAAY;CACZ,aAAa;CACb,6BAA6B;CAC7B,cAAc;CACd,YAAY;CACZ,iBAAiB;CACjB,iBAAiB;CACjB,eAAe;CACf,eAAe;CACf,iBAAiB;CACjB,aAAa;CACb,eAAe;CACf,sBAAsB;CACtB,iBAAiB;CACjB,cAAc;CACd,mBAAmB;CACnB,qBAAqB;CACrB,iBAAiB;CACjB,eAAe;CACf,iBAAiB;CACjB,eAAe;CACf,eAAe;CACf,gBAAgB;CAChB,aAAa;CACb,sBAAsB;CACtB,cAAc;CACd,gBAAgB;CAChB,qBAAqB;CACrB,eAAe;CACf,YAAY;CACZ,aAAa;CAGb,cAAc;CACd,eAAe;CACf,cAAc;CACd,aAAa;CACb,cAAc;CACd,aAAa;CACb,mBAAmB;CACnB,cAAc;CACd,eAAe;CACf,eAAe;CACf,oBAAoB;CACpB,kBAAkB;CAClB,mBAAmB;AACrB;;;AC5SA,SAAS,0BAAiC,EACxC,iBACA,cACA,eACA,aACA,oBACA,gBACuD;CACvD,MAAM,oBAA8C,EAClD,mBAAmB,YACrB;CAEA,KAAK,MAAM,QAAQ,eACjB,kBAAkB,QAAQ;CAG5B,KAAK,MAAM,QAAQ,gBACjB,kBAAkB,QAAQ;CAG5B,KAAK,MAAM,QAAQ,qBACjB,kBAAkB,QAAQ;CAG5B,KAAK,MAAM,QAAQ,kBACjB,kBAAkB,QAAQ;CAG5B,KAAK,MAAM,QAAQ,eACjB,kBAAkB,QAAQ;CAE5B,OAAO;AACT;AAEA,SAAS,6BAAoC,EAC3C,aACA,eACA,iBAC2D;CAC3D,OAAO;EACL,UAAU;EACV,SAAS;EACT,UAAU;CACZ;AACF;AASA,IAAa,UAAmB,EAC9B,UAAU;CACR,GAAG,0BAA6C;EAC7B;EACH;EACC;EACF;EACO;EACN;CAChB,CAAC;CACD,GAAG,6BAAgD;EACjD,aAAa;EACE;EACA;CACjB,CAAC;CACD,UAAU;AACZ,EACF;;;ACvFA,SAAgB,eAAe,UAAmB;CAChD,MAAM,SAAS,QAAQ;CAEvB,IAAI,CAAC,UAAU,OAAO,OAAO;CAE7B,MAAM,OAAO,OAAO;CACpB,IAAI,MAAM,OAAO;CAEjB,IAAI,SAAS,WAAW,QAAQ,GAAG,OAAO,OAAO;CACjD,IAAI,SAAS,WAAW,QAAQ,GAAG,OAAO,OAAO;CACjD,IAAI,SAAS,WAAW,QAAQ,GAAG,OAAO,OAAO;CACjD,IAAI,SAAS,WAAW,OAAO,GAAG,OAAO,OAAO;CAEhD,OAAO,OAAO;AAChB;AAEA,IAAM,qBAAqB,EACzB,UACA,eACkD;CAClD,IAAI;CAEJ,IAAI,UACF,QAAQ,uBAAuB;CAGjC,IAAI,CAAC,SAAS,UACZ,QAAQ,SAAS,MAAM,GAAG,EAAE,MAAM,EAAE,EAAE;CAExC,OAAO;AACT;AAEA,IAAa,YAAY,UAAyB;CAChD,MAAM,EACJ,WACA,UACA,UACA,OAAO,MACP,YAAY,oBACZ,GAAG,SACD;CACJ,MAAM,aAAa,cACX,wBAAwB,kBAAkB,GAChD,CAAC,kBAAkB,CACrB;CACA,MAAM,OAAO,eAAe,QAAQ;CACpC,MAAM,QAAQ,WAAW,kBAAkB;EAAE;EAAU;CAAS,CAAC,IAAI,KAAA;CACrE,OACE,oBAAC,MAAD;EACE,GAAI;EACO;EACJ;EACD;EACM;CACb,CAAA;AAEL;;;AC9EA,IAAa,cACX,cACA,WAA6B,WAC1B;CACH,IAAI,gBAAgB,QAAQ,OAAO,MAAM,YAAY,KAAK,eAAe,GACvE,OAAO;CAGT,MAAM,iBACJ,aAAa,UAAU,KAAK,MAAM,YAAY,IAAI,KAAK,KAAK,YAAY;CAC1E,MAAM,QAAQ,KAAK,MAAM,iBAAiB,IAAI;CAC9C,MAAM,UAAU,KAAK,MAAO,iBAAiB,OAAQ,EAAE;CACvD,MAAM,UAAU,iBAAiB;CACjC,MAAM,SAAS,GAAG,OAAO,OAAO,EAAE,SAAS,GAAG,GAAG,EAAE,GAAG,OAAO,OAAO,EAAE,SACpE,GACA,GACF;CAEA,OAAO,QAAQ,GAAG,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG,EAAE,GAAG,WAAW;AACjE;;;ACFA,SAAgB,gBAAgB,EAC9B,WACA,UACA,WACA,gBACA,gBAAgB,SACO;CACvB,MAAM,mBACJ,YAAY,QAAQ,kBAAkB,OAClC,KAAK,IAAI,GAAG,WAAW,cAAc,IACrC,KAAA;CACN,MAAM,oBAAoB,WAAW,QAAQ;CAC7C,MAAM,0BAA0B,WAAW,cAAc;CACzD,MAAM,qBAAqB,WAAW,gBAAgB;CAEtD,MAAM,oBACJ,CAAC,CAAC,kBAAkB,iBAAiB,KAAK,kBAAkB,YAAY;CAC1E,MAAM,mBAAmB,iBAAiB,YAAY,QAAQ,kBAAkB;CAChF,MAAM,eAAe,gBAAgB,qBAAqB;CAC1D,MAAM,eAAe,oBAAoB,sBAAsB,CAAC,CAAC;CACjE,MAAM,eAAe,CAAC,eAAe,CAAC,CAAC;CAEvC,OACE,qBAAC,OAAD;EACE,WAAW,KACT,8BACA;GACE,2CAA2C,CAAC,CAAC;GAC7C,yCAAyC;EAC3C,GACA,SACF;YARF,CAUG,eACC,oBAAC,QAAD;GAAM,WAAU;aAA4C;EAAmB,CAAA,GAEhF,gBACC,oBAAC,QAAD;GAAM,WAAU;aAAwC;EAAwB,CAAA,CAE/E;;AAET;;;ACpDA,IAAa,sBAAsB,EACjC,UACA,WACA,GAAG,WAEH,oBAAC,QAAD;CACE,eAAY;CACZ,GAAI;CACJ,WAAW,KAAK,kCAAkC,SAAS;CAE1D;AACK,CAAA;;;ACZV,IAAM,iCAAiC;AACvC,IAAM,uCAAuC;AAE7C,IAAM,wBAAwB,EAC5B,KACA,WACA,UACA,WAMI;CACJ,QAAQ,KAAR;EACE,KAAK;EACL,KAAK,WACH,OAAO,KAAK,IAAI,KAAK,WAAW,IAAI;EACtC,KAAK;EACL,KAAK,aACH,OAAO,KAAK,IAAI,GAAG,WAAW,IAAI;EACpC,KAAK,UACH,OAAO,KAAK,IAAI,KAAK,WAAW,SAAS;EAC3C,KAAK,YACH,OAAO,KAAK,IAAI,GAAG,WAAW,SAAS;EACzC,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,IAAa,iCAAiC,EAC5C,OACA,YAAY,sCACZ,UACA,MACA,OAAO,qCAOH;CACJ,MAAM,eAAe,qBAAqB;EACxC,KAAK,MAAM;EACX;EACA;EACA;CACF,CAAC;CAED,IAAI,iBAAiB,MAAM;CAE3B,MAAM,eAAe;CACrB,MAAM,gBAAgB,MAAM;CAC5B,MAAM,EAAE,OAAO,MAAM,cAAc,sBAAsB;CAEzD,KAAK;EACH,SAAS,IAAK,QAAQ,eAAgB;EACtC;CACF,CAAC;AACH;;;AC3DA,IAAa,oCAAoC,EAC/C,iBACA,UACA,gBACA,QAC4C;CAC5C,MAAM,qBAAqB,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,QAAQ,CAAC;CAE9D,IAAI,OAAO,oBAAoB,YAAY,OAAO,SAAS,eAAe,GAAG;EAC3E,MAAM,qBAAqB,KAAK,IAAI,GAAG,eAAe;EAKtD,MAAM,mBAAmB,WAHvB,OAAO,mBAAmB,YAAY,OAAO,SAAS,cAAc,IAChE,KAAK,IAAI,GAAG,KAAK,IAAI,gBAAgB,kBAAkB,CAAC,IACvD,qBAAqB,qBAAsB,KACL,OAAO;EACpD,MAAM,oBAAoB,WAAW,oBAAoB,OAAO;EAEhE,IAAI,oBAAoB,mBACtB,OAAO,EAAE,uDAAuD;GAC9D,UAAU;GACV,SAAS;EACX,CAAC;CAEL;CAEA,OAAO,EAAE,8CAA8C,EACrD,UAAU,KAAK,MAAM,kBAAkB,EACzC,CAAC;AACH;;;AC3BA,IAAM,0BAA0B,cAAqC;CACnE,IAAI,CAAC,WAAW,OAAO;CAEvB,MAAM,SAAS,UAAU;CACzB,IAAI,CAAC,QAAQ,OAAO,UAAU,sBAAsB,EAAE;CAEtD,MAAM,cAAc,OAAO,sBAAsB,EAAE;CACnD,MAAM,gBAAgB,OAAO,iBAAiB,MAAM;CACpD,MAAM,cAAc,WAAW,cAAc,WAAW,KAAK;CAC7D,MAAM,eAAe,WAAW,cAAc,YAAY,KAAK;CAC/D,MAAM,eAAe,cAAc,aAAa,cAAc;CAC9D,MAAM,kBAAkB,WAAW,YAAY;CAG/C,MAAM,kBAFY,OAAO,MAAM,eAAe,IAAI,IAAI,mBACrC,KAAK,IAAI,GAAG,OAAO,SAAS,SAAS,CACnB;CACnC,MAAM,gBAAgB,MAAM,KAAK,OAAO,QAAQ,EAAE,QAAQ,OAAO,UAAU;EACzE,IAAI,UAAU,WAAW,OAAO;EAChC,OAAO,QAAQ,MAAM,sBAAsB,EAAE;CAC/C,GAAG,CAAC;CAEJ,OAAO,KAAK,IACV,GACA,cAAc,cAAc,eAAe,iBAAiB,aAC9D;AACF;AAEA,IAAa,6BAA6B,EACxC,WAAW,GACX,WACqC;CACrC,MAAM,aAAa,OAAO,KAAK;CAC/B,MAAM,CAAC,qBAAqB,0BAA0B,SAAS,CAAC;CAChE,MAAM,CAAC,MAAM,WAAW,SAAgC,IAAI;CAC5D,MAAM,CAAC,mBAAmB,wBAAwB,SAAgC,IAAI;CACtF,MAAM,qBAAqB,OAAO,CAAC;CAEnC,MAAM,mBAAwD,MAAM;EAClE,EAAE,eAAe;EACjB,IAAI,CAAC,mBAAmB;EAExB,WAAW,UAAU;EACrB,kBAAkB,MAAM,SAAS;EACjC,MAAM,UAAU,IAAI,8CAA8C;CACpE;CAEA,MAAM,cAAmD,MAAM;EAC7D,IAAI,CAAC,WAAW,SAAS;EAEzB,KAAK,EAAE,GAAG,EAAE,CAAC;CACf;CAEA,MAAM,iBAAiB,kBAAkB;EACvC,IAAI,CAAC,mBAAmB;EAExB,WAAW,UAAU;EACrB,kBAAkB,MAAM,eAAe,QAAQ;EAC/C,MAAM,UAAU,OAAO,8CAA8C;CACvE,GAAG,CAAC,mBAAmB,IAAI,CAAC;CAE5B,gBAAgB;EACd,SAAS,iBAAiB,aAAa,cAAc;EAErD,aAAa;GACX,SAAS,oBAAoB,aAAa,cAAc;EAC1D;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,gBAAgB;EACd,IAAI,CAAC,QAAQ,OAAO,mBAAmB,aAAa;EAEpD,MAAM,WAAW,IAAI,gBAAgB,CAAC,WAAW;GAE/C,uBAD2B,uBAAuB,MAAM,MACjC,KAAsB,MAAM,YAAY,KAAK;EACtE,CAAC;EAED,SAAS,QAAQ,IAAI;EAErB,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,IAAI,CAAC;CAET,sBAAsB;EACpB,IAAI,MACF,uBAAuB,uBAAuB,IAAI,CAAC;EAGrD,IAAI,mBACF,mBAAmB,UAAU,kBAAkB,sBAAsB,EAAE;CAE3E,GAAG,CAAC,mBAAmB,IAAI,CAAC;CAQ5B,OAAO;EACL;EACA;EACA;EACA;EACA,eAVA,aAAa,KAAK,CAAC,oBACf,IACA,KAAK,IAAI,GAAG,sBAAsB,mBAAmB,OAAO,KAAK,WAAW,OAC5E;EAQJ;EACA;EACA;CACF;AACF;;;ACnGA,IAAa,eAAe,EAC1B,WACA,iBACA,UACA,gBACA,WACsB;CACtB,MAAM,EAAE,MAAM,sBAAsB,aAAa;CACjD,MAAM,EACJ,YACA,iBACA,gBACA,eACA,sBACA,YACE,0BAA0B;EAAE;EAAU;CAAK,CAAC;CAChD,MAAM,qBAAqB,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,QAAQ,CAAC;CAC9D,MAAM,gBAAgB,iCAAiC;EACrD;EACA,UAAU;EACV;EACA;CACF,CAAC;CAED,OACE,oBAAC,OAAD;EACE,cAAY,EAAE,0BAA0B;EACxC,oBAAiB;EACjB,iBAAe;EACf,iBAAe;EACf,iBAAe,KAAK,MAAM,kBAAkB;EAC5C,kBAAgB;EAChB,WAAW,KACT,6DACA,SACF;EACA,iBAAe;EACf,eAAY;EACZ,SAAS;EACT,YAAY,UACV,8BAA8B;GAAE;GAAO,UAAU;GAAoB;EAAK,CAAC;EAE7E,eAAe;EACf,eAAe;EACf,aAAa;EACb,KAAK;EACL,MAAK;EACL,OACE,EACE,wDACE,qBAAqB,IACzB;EAEF,UAAU;YAEV,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,KAAK;GACL,OAAO,EAAE,kBAAkB,GAAG,cAAc,IAAI;EACjD,CAAA;CACE,CAAA;AAET;;;AC9EA,IAAa,0BAA0B;CACrC;CACA;CACA;CACA;AACF;AAyCA,IAAa,2BACX,eAEA,MAAM,QAAS,WAAiC,KAAK;AAEvD,IAAa,mBAAmB,eAA2B;CAEzD,QADiB,WAAW,YAAY,IACxB,YAAY,EAAE,SAAS,MAAM;AAC/C;AAEA,IAAa,UAAU,KAAa,YAAoB,CACtD,KAAK,MAAM,MAAM,OAAO,GACxB,MAAM,OACR;AAEA,IAAa,mBAAmB,iBAA0B;CACxD,IAAI,CAAC,gBAAgB,eAAe,GAAG,OAAO;CAE9C,MAAM,CAAC,OAAO,iBAAiB,OAAO,cAAc,IAAI;CACxD,MAAM,CAAC,SAAS,WAAW,OAAO,eAAe,EAAE;CACnD,MAAM,iBAAiB,KAAK,KAAK,OAAO;CACxC,MAAM,iBAAiB,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;CAGpD,MAAM,SAAS,GAFQ,OAAO,OAAO,EAAE,SAAS,GAAG,GAEjC,EAAe,GADV,OAAO,cAAc,EAAE,SAAS,GAAG,GACtB;CAEpC,OAAO,QAAQ,GAAG,eAAe,KAAK,SAAS;AACjD;AACA,SAAgB,0BAA0B,KAAa;CACrD,MAAM,UAAU;EACd,qBAAqB;EACrB,oBAAoB;CACtB;CAEA,IAAI,QAAQ,KAAK,KAAK,KAAK,GAAG;EAC5B,MAAM,YAAY,IAAI,IAAI,GAAG,EAAE;EAC/B,MAAM,KAAK,OAAO,UAAU,IAAI,IAAI,CAAC;EACrC,MAAM,KAAK,OAAO,UAAU,IAAI,IAAI,CAAC;EACrC,MAAM,iBAAiB,KAAK,IAAI,KAAK;EAErC,QAAQ,sBADc,KAAK,IAAI,KAAK;EAEpC,QAAQ,uBAAuB;CACjC;CAEA,OAAO;AACT;;;AC9FA,IAAa,wBAAwB,cAAwB,oBAC3D,aAAa,WAAW,kBACpB,eACA,aAAa,SAAS,kBACpB,WAAW,cAAc,eAAe,IACxC,SAAS,cAAc,eAAe;;;;;;;AAQ9C,SAAgB,WAAW,MAAgB,kBAAoC;CAC7E,IAAI,KAAK,UAAU,oBAAoB,qBAAqB,GAC1D,OAAO;CAGT,IAAI,qBAAqB,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC;CAE9C,MAAM,SAAmB,CAAC;CAE1B,MAAM,cAAc,KAAK,SAAS,MAAM,mBAAmB;CAC3D,IAAI,yBAAyB;CAC7B,OAAO,KAAK,KAAK,uBAAuB;CACxC,IAAI,cAAc,SAAS;CAE3B,KAAK,IAAI,cAAc,GAAG,cAAc,mBAAmB,GAAG,eAAe;EAC3E,MAAM,yBAAyB,KAAK;EACpC,MAAM,iBAAiB,kBAAkB,MAAM,aAAa,UAAU;EAEtE,MAAM,0BAA0B,KAAK,OAAO,cAAc,KAAK,UAAU,IAAI;EAC7E,MAAM,uBAAuB,KAAK,MAAM,cAAc,UAAU,IAAI;EACpE,MAAM,wBAAwB,IAAI,uBAAuB;EAEzD,UAAU,eAAe;EAEzB,KACE,IAAI,oBAAoB,yBACxB,oBAAoB,sBACpB,qBACA;GACA,MAAM,wBACJ,KAAK,IAAI,oBAAoB,uBAAuB,IAAI;GAC1D,MAAM,wBAAwB,wBAAwB;GACtD,MAAM,oBAAoB,KAAK;GAE/B,eAAe,kBACb,aACE,KAAK,IAAI,yBAAyB,iBAAiB,GACnD,qBACF,GACA,aAAa,KAAK,IAAI,oBAAoB,cAAc,GAAG,qBAAqB,GAChF,aACE,KAAK,IAAI,yBAAyB,cAAc,GAChD,qBACF,CACF;GAEA,IAAI,eAAe,SAAS;IAC1B,UAAU;IACV,eAAe,KAAK;IACpB,yBAAyB;GAC3B;EACF;EAEA,IAAI,OAAO,iBAAiB,aAAa,OAAO,KAAK,YAAY;CACnE;CAEA,OAAO,KAAK,KAAK,KAAK,SAAS,EAAE;CAEjC,OAAO;AACT;AAEA,IAAM,qBAAqB,GAAW,GAAW,MAAc;CAC7D,MAAM,KAAK,IAAI,IAAI,KAAK;CACxB,OAAO,KAAK,KAAK,KAAK,IAAI,MAAM,IAAI,MAAM,IAAI,EAAE;AAClD;AACA,IAAM,gBAAgB,GAAW,MAAc,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC;AACxF,IAAM,QAAQ,WACZ,OAAO,QAAQ,KAAK,UAAU,MAAM,OAAO,CAAC,IAAI,OAAO;AACzD,IAAM,qBACJ,MACA,oBACA,eACG;CACH,MAAM,uBAAuB,KAAK,MAAM,qBAAqB,UAAU,IAAI;CAC3E,IAAI,2BAA2B,KAAK,OAAO,qBAAqB,KAAK,UAAU,IAAI;CACnF,2BACE,2BAA2B,KAAK,SAAS,2BAA2B,KAAK;CAE3E,OAAO,KAAK,KAAK,MAAM,sBAAsB,wBAAwB,CAAC;AACxE;AACA,IAAa,YAAY,QAAkB,eAAuB;CAChE,IAAI,CAAC,OAAO,QAAQ;EAClB,QAAQ,KAAK,0CAA0C;EACvD,OAAO;CACT;CAEA,IAAI,OAAO,SAAS,YAAY;EAC9B,QAAQ,KACN,+EACF;EACA,OAAO;CACT;CAEA,IAAI,eAAe,OAAO,QAAQ,OAAO;CAGzC,IAAI,CAAC,YAAY,aAAa,OAAO,YAAY,OAAO,MAAM;CAC9D,MAAM,SAAmB,CAAC;CAE1B,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,aAAa,cAAc,IAAI;EAC7C,OAAO,KAAK,GAAG,MAAM,aAAa,KAAK,EAAE,KAAK,OAAO,EAAE,CAAC;CAC1D;CACA,OAAO;AACT;;;AC1FA,IAAa,mBAAmB,EAC9B,wBACA,iBACA,WAAW,GACX,4BAA4B,GAC5B,uBAAuB,GACvB,gBACA,MACA,mBAC0B;CAC1B,MAAM,EAAE,MAAM,sBAAsB,iBAAiB;CACrD,MAAM,CAAC,YAAY,iBAAiB,SAIjC;CACH,MAAM,0BAA0B,OAAe,CAAC;CAChD,MAAM,0BAA0B,OAAsB,IAAI;CAC1D,MAAM,+BAA+B,OAAsB,IAAI;CAC/D,MAAM,EACJ,qBACA,YACA,iBACA,gBACA,eACA,MACA,sBACA,YACE,0BAA0B;EAAE;EAAU;CAAK,CAAC;CAChD,MAAM,qBAAqB,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,QAAQ,CAAC;CAE9D,MAAM,gBAAgB,cAElB,UAAU,mBAA2B;EACnC,MAAM,uBAAuB,wBAAwB;EACrD,MAAM,qBACJ,yBAAyB,6BAA6B;EACxD,IAAI,mBAAmB,wBAAwB,WAAW,CAAC,oBACzD;EAEF,wBAAwB,UAAU;EAClC,6BAA6B,UAAU;EACvC,MAAM,mBAAmB,KAAK,MAC5B,kBAAkB,uBAAuB,0BAC3C;EACA,MAAM,8BACJ,6BAA6B,4BAA4B;EAC3D,MAAM,qBACJ,OAAO,yBAAyB,YAAY,uBAAuB,IAC/D,KAAK,MACF,iBAAiB,8BAA+B,oBACnD,IACA;EACN,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,kBAAkB,kBAAkB,CAAC;EAC3E,MAAM,WACJ,YAAa,iBAAiB,WAAY;EAE5C,cAAc;GACZ;GACA;GACA,KAAK,YAAY,uBAAuB;EAC1C,CAAC;CACH,GAAG,CAAC,GACN,CAAC,2BAA2B,oBAAoB,CAClD;CAEA,MAAM,wBAAwB,cACrB,aAAa,qBAAqB,cAAc,WAAW,QAAQ,IAAI,CAAC,GAC/E,CAAC,YAAY,YAAY,CAC3B;CAEA,sBAAsB;EACpB,IAAI,sBAAsB,GACxB,cAAc,mBAAmB;CAErC,GAAG,CAAC,qBAAqB,aAAa,CAAC;CAEvC,sBAAsB;EACpB,IAAI,CAAC,QAAQ,OAAO,WAAW,aAAa;EAC5C,MAAM,eAAe,KAAK,cACxB,6CACF;EACA,IAAI,CAAC,cAAc;EACnB,MAAM,gBAAgB,OAAO,iBAAiB,YAAY;EAC1D,MAAM,iBAAiB,WAAW,cAAc,QAAQ;EACxD,IAAI,CAAC,OAAO,MAAM,cAAc,KAAK,iBAAiB,GACpD,wBAAwB,UAAU;EAEpC,IAAI,sBAAsB,GACxB,cAAc,mBAAmB;CAErC,GAAG;EAAC;EAAqB;EAAe;EAAM,YAAY;CAAQ,CAAC;CAEnE,IAAI,CAAC,aAAa,UAAU,YAAY,aAAa,GAAG,OAAO;CAE/D,MAAM,oBAAoB,0BAA0B,YAAY;CAChE,MAAM,gBAAgB,iCAAiC;EACrD;EACA,UAAU;EACV;EACA;CACF,CAAC;CAED,OACE,qBAAC,OAAD;EACE,cAAY,EAAE,0BAA0B;EACxC,oBAAiB;EACjB,iBAAe;EACf,iBAAe;EACf,iBAAe,KAAK,MAAM,kBAAkB;EAC5C,kBAAgB;EAChB,WAAW,KAAK,sCAAsC,EACpD,0DAA0D,qBAAqB,EACjF,CAAC;EACD,eAAY;EACZ,SAAS;EACT,YAAY,UACV,8BAA8B;GAAE;GAAO,UAAU;GAAoB;EAAK,CAAC;EAE7E,eAAe;EACf,eAAe;EACf,aAAa;EACb,KAAK;EACL,MAAK;EACL,OACE,EACE,uDACE,OAAO,sBAAsB,WAAW,GAAG,kBAAkB,MAAM,KAAA,EACvE;EAEF,UAAU;YA1BZ,CA4BG,sBAAsB,KAAK,WAAW,MACrC,oBAAC,OAAD;GACE,eAAY;GACZ,WAAW,KAAK,8CAA8C,GAC3D,uDACC,qBAAsB,IAAI,sBAAsB,SAAU,IAC9D,CAAC;GACD,eAAY;GAEZ,OACE;IACE,mDACE,YAAY,WAAW;IACzB,uDAAuD,YACnD,YAAY,MAAM,MAClB;GACN;EAEH,GAVM,aAAa,GAUnB,CACF,GACD,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,eAAY;GACZ,KAAK;GACL,OAAO,EACL,kBAAkB,GAAG,cAAc,IACrC;EACD,CAAA,CACE;;AAET;;;AC3KA,IAAM,qBAAqB,EAAE,kBAA0C;CACrE,MAAM,EAAE,mBAAA,sBAAoB,sBAA6B,oBAAoB;CAC7E,MAAM,aAAa;CACnB,MAAM,gBAAgB;CAEtB,MAAM,EAAE,iBAAiB,WAAW,UAAU,mBAC5C,cAAc,aAAa,OAAO,0BAAwB,KAAK,CAAC;CAElE,OACE,qBAAC,OAAD;EAAK,WAAW;EAAe,eAAa;YAA5C;GACE,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,YAAD;KAAY,WAAW,CAAC,CAAC;KAAW,SAAS,YAAY;IAAa,CAAA;GACnE,CAAA;GACL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,OAAD;MAAK,WAAU;gBACZ,YAAY;KACV,CAAA;IACF,CAAA,GACL,oBAAC,OAAD;KAAK,WAAU;eACZ,kBACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,iBAAD;MACE,UAAU;MACV,WAAW,CAAC,CAAC;MACG;KACjB,CAAA,GACD,oBAAC,aAAD;MACmB;MACjB,UAAU,YAAY;MACN;MAChB,MAAM,YAAY;KACnB,CAAA,CACD,EAAA,CAAA,IAEF,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,qBAAD,EAAmB,UAAU,YAAY,SAAW,CAAA,GACpD,oBAAC,aAAD;MACmB;MACjB,UAAU,YAAY;MACN;MAChB,MAAM,YAAY;KACnB,CAAA,CACD,EAAA,CAAA;IAED,CAAA,CACF;;GACL,oBAAC,UAAD;IAAU,WAAU;IAAsB,UAAU,YAAY;GAAW,CAAA;GAC3E,oBAAC,gBAAD;IAAgB,UAAU,YAAY;IAAK,mBAAmB,YAAY;GAAQ,CAAA;EAC/E;;AAET;AAMA,IAAM,8BAA4B,WAA6B;CAC7D,iBAAiB,MAAM;CACvB,WAAW,MAAM;CACjB,UAAU,MAAM;CAChB,gBAAgB,MAAM;AACxB;;;;AAKA,IAAa,SAAS,UAAsB;CAC1C,MAAM,EACJ,YAAY,EAAE,WAAW,UAAU,WAAW,WAAW,YACvD;;;;;;;;;;CAWJ,MAAM,EAAE,SAAS,eAAe,kBAAkB,KAAK,CAAC;CAExD,MAAM,cAAc,eAAe;EACjC,iBAAiB;EACjB,UAAU;EACV,UAAU;EACV,WACE,SAAS,MACT,GAAG,aAAc,QAAQ,aAAa,QAAQ,KAAM,KAAK,QAAQ;EACnE,KAAK;EACL;EACA,cAAc,MAAM,WAAW;CACjC,CAAC;CAED,OAAO,cAAc,oBAAC,mBAAD,EAAgC,YAAc,CAAA,IAAI;AACzE;;;AC3FA,IAAa,uCAA4E,EACvF,OAAO,OACT;AAEA,IAAM,+BAA+B,UAAkC;CACrE,MAAM,EAAE,eAAe,SAAS,2BAA2B,IAAI,SAAS;CACxE,MAAM,EAAE,MAAM,sBAAsB,6BAA6B;CACjE,MAAM,aAAa,OAAwC,CAAC,CAAC;CAE7D,MAAM,qBACJ,OACA,MACA,UACG,gBAAgB,MAAM,OAAO,KAAK;CAEvC,MAAM,kBAAkB,eACf;EACL,QAAQ,EAAE,QAAQ;EAClB,MAAM,EAAE,MAAM;EACd,SAAS,EAAE,SAAS;CACtB,IACA,CAAC,CAAC,CACJ;CAEA,MAAM,aAAa,cAAc;EAC/B,IAAI,CAAC,2BAA2B,OAAO;EACvC,MAAM,QAAQ,QAAQ,WACnB,WAAW,OAAO,UAAU,yBAC/B;EACA,OAAO,SAAS,IAAI,QAAQ;CAC9B,GAAG,CAAC,SAAS,yBAAyB,CAAC;CAEvC,gBAAgB;EACd,IAAI,eAAe,MAAM;EACzB,MAAM,SAAS,WAAW,QAAQ;EAClC,IAAI,UAAU,SAAS,kBAAkB,QACvC,OAAO,MAAM;CAEjB,GAAG,CAAC,UAAU,CAAC;CAEf,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD,EAAA,UAAO,KAAW,CAAA,GACjB,QAAQ,KAAK,QAAQ,UACpB,oBAAC,QAAD;IACE,YAAW;IACX,WAAW,KACT,4FAA4F,OAAO,OACrG;IACA,eAAa,GAAG,OAAO;IACvB,cAAY,OAAO;IAEnB,UAAU,UAAU,kBAAkB,OAAO,OAAO,MAAM,OAAO,KAAK;IACtE,MAAM,YAAY;KAChB,WAAW,QAAQ,SAAS;IAC9B;IACA,SAAQ;cAEP,OAAO,OAAQ,gBAAgB,OAAO,SAAS,EAAE,OAAO,IAAI,IAAK;GAC5D,GARD,GAAG,GAAG,GAAG,OAAO,OAQf,CACT,CACE;;CACF,CAAA;AAET;;;;AAKA,IAAa,oBAAoB,MAAM,KACrC,2BACF;;;AC7EA,IAAM,gBAAgB;AAEtB,IAAM,8BAA4B,WAA6B;CAC7D,eAAe,MAAM;CACrB,iBAAiB,MAAM;CACvB,WAAW,MAAM;CACjB,cAAc,MAAM;CACpB,UAAU,MAAM;CAChB,gBAAgB,MAAM;AACxB;AAOA,IAAM,0BAA0B,EAAE,kBAA+C;CAC/E,MAAM,EAAE,mBAAA,sBAAoB,sBAA6B,oBAAoB;CAC7E,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,eACA,iBACA,WACA,cACA,UACA,mBACE,cAAc,aAAa,OAAO,0BAAwB,KAAK,CAAC;CAEpE,OACE,qBAAC,OAAD;EAAK,WAAW;EAAe,eAAY;YAA3C;GACE,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,YAAD;KAAY,WAAW,CAAC,CAAC;KAAW,SAAS,YAAY;IAAa,CAAA;GACnE,CAAA;GACL,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,OAAD;MAAK,WAAU;gBACZ,kBACC,oBAAC,iBAAD;OACE,UAAU;OACV,WAAW,CAAC,CAAC;OACG;OAChB,eAAA;MACD,CAAA,IAED,oBAAC,qBAAD;OACE,UAAU,YAAY;OACtB,uBAAuB;MACxB,CAAA;KAEA,CAAA,GACL,oBAAC,iBAAD;MACmB;MACP;MACM;MAChB,MAAM,YAAY;MAClB,cAAc,YAAY,gBAAgB,CAAC;KAC5C,CAAA,CACE;;GACF,CAAA;GACL,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,oBAAD;KACE,cAAY,EAAE,8BAA8B,EAC1C,MAAM,cAAc,SAAS,KAAK,IACpC,CAAC;KACD,UAAU,CAAC;KACX,SAAS,YAAY;eALvB,CAMC,KACG,cAAc,SAAS,CACP;;GACjB,CAAA;EACF;;AAET;AAOA,IAAa,wBAAwB,EACnC,YACA,oBAC+B;CAC/B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,WACA,WAAW,GACX,WACA,WACA,QAAQ,EAAE,eAAe,GACzB,kBACE;;;;;;;;;;CAWJ,MAAM,EAAE,SAAS,eAAe,kBAAkB,KAAK,CAAC;CAExD,MAAM,cAAc,eAAe;EACjC,iBAAiB,YAAY;EAC7B,UAAU;EACV,UAAU;EACV;EACA,WACE,SAAS,MACT,GAAG,aAAc,QAAQ,aAAa,QAAQ,KAAM,KAAK,QAAQ;EACnE,KAAK;EACL;EACA,cAAc;CAChB,CAAC;CAED,OAAO,cAAc,oBAAC,wBAAD,EAAqC,YAAc,CAAA,IAAI;AAC9E;AAIA,IAAa,wBAAwB,EAAE,iBAA4C;CACjF,MAAM,EAAE,mBAAA,sBAAoB,sBAA6B,oBAAoB;CAC7E,OACE,qBAAC,OAAD;EAAK,WAAW;EAAe,eAAY;YAA3C,CACE,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,OAAD;KAAK,WAAU;eACZ,WAAW,WACV,oBAAC,iBAAD;MACE,UAAU,WAAW;MACrB,WAAW;MACX,gBAAgB,KAAA;KACjB,CAAA,IAED,oBAAC,qBAAD;MACE,UAAU,WAAW;MACrB,uBAAuB;KACxB,CAAA;IAEA,CAAA;GACF,CAAA;EACF,CAAA,GACL,oBAAC,UAAD,EAAU,UAAU,WAAW,UAAY,CAAA,CACxC;;AAET;AASA,IAAa,kBAAkB,EAAE,YAAY,eAC3C,WACE,oBAAC,sBAAD,EAAkC,WAAa,CAAA,IAE/C,oBAAC,sBAAD,EAAkC,WAAa,CAAA;;;AC5KnD,IAAa,oBAAoB,EAAE,gBAAuC;CACxE,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,OAAD;EACE,cAAY,EAAE,2BAA2B;EACzC,WAAW,KAAK,+BAA+B,SAAS;EACxD,eAAY;EACZ,MAAK;YAEL,oBAAC,WAAD,CAAY,CAAA;CACT,CAAA;AAET;;;ACVA,IAAa,YAAY,WAA6C,SAAS,UAC7E,EAAE,KAAK,GAAG,SACV,KACA;CACA,MAAM,EACJ,KAAK,UACL,WAAW,gBACX,SAAS,cACT,4BAA4B,OAC5B,GAAG,aACD;CAKJ,MAAM,CAAC,WAAW,gBAAgB,SAAwB,IAAI;CAC9D,MAAM,EAAE,kBAAkB,4BAA4B,qBACpD,oBAAoB;CAEtB,MAAM,eAAe,cAAc,YAAY,GAAG,GAAG,CAAC,GAAG,CAAC;CAC1D,MAAM,QAAQ,cAAc;CAE5B,sBACc;EACV,aAAa,IAAI;CACnB,GACA,CAAC,YAAY,CACf;CAEA,IAAI,OACF,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,2BAAD,EACE,WAAW,KAAK,gBAAgB,mCAAmC,EACpE,CAAA,GACA,6BAA6B,oBAAC,gBAAD,EAAgB,UAAU,aAAe,CAAA,CACvE,EAAA,CAAA;CAIN,OACE,oBAAC,OAAD;EACE,eAAY;EACZ,GAAI;EACJ,KAAK,YAAY;EACjB,WAAW,KAAK,gBAAgB,sBAAsB;EACtD,UAAU,MAAM;GACd,aAAa,YAAY;GACzB,eAAe,CAAC;EAClB;EACK;EACL,KAAK;CACN,CAAA;AAEL,CAAC;;;;;;AChCD,IAAa,0BACX,YACA,UAAyC,CAAC,MACN;CACpC,IAAI,kBAAkB,UAAU,GAAG;EACjC,MAAM,eACJ,SAAS,oBAAoB,WAAW,QACpC,WAAW,MACT,QAAQ,oBAEV,KAAA;EAEN,OAAO;GACL,KAAK,cAAc,OAAO,WAAW;GACrC,YAAY,eACR;IACE,QAAQ,aAAa;IACrB,OAAO,aAAa;GACtB,IACA,KAAA;GACJ,UAAU,WAAW;GACrB,OAAO,WAAW,SAAS,WAAW;EACxC;CACF;CAEA,IAAI,iBAAiB,UAAU,GAAG;EAChC,MAAM,WAAW,WAAW,aAAa,WAAW;EACpD,OAAO;GACL,KAAK,WAAW,SAAS;GACzB;GACA,OAAO,WAAW;EACpB;CACF;CAEA,IAAI,uBAAuB,UAAU,GACnC,OAAO;EACL,OAAO,WAAW;EAClB,mBAAmB,WAAW,aAAa,WAAW,cAAc;EACpE,UAAU,WAAW,aAAa,WAAW,cAAc;CAC7D;CAGF,IAAI,kBAAkB,UAAU,GAC9B,OAAO;EACL,OAAO,WAAW;EAClB,mBAAmB,WAAW;EAC9B,UAAU,WAAW;CACvB;CAGF,IAAI,uBAAuB,UAAU,GAAG;EACtC,MAAM,WAAW,WAAW,aAAa,WAAW,cAAc;EAClE,OAAO;GACL,KAAK,WAAW,SAAS;GACzB;GACA,OAAO,WAAW;EACpB;CACF;CAEA,IAAI,kBAAkB,UAAU,GAAG;EACjC,MAAM,WAAW,WAAW;EAC5B,OAAO;GACL,KAAK,WAAW,SAAS;GACzB;GACA,OAAO,WAAW;EACpB;CACF;AAGF;;;;;;;ACrFA,IAAa,4BACX,GAAG,SAMY,uBAAuB,GAAG,IAAI;AA2B/C,IAAa,iBAAiB,cAA+C,KAAA,CAAS;AAEtF,IAAa,0BAA0B;CACrC,MAAM,eAAe,WAAW,cAAc;CAE9C,IAAI,CAAC,cAAc;EACjB,QAAQ,KACN,sJACF;EAEA,OAAO,CAAC;CACV;CAEA,OAAO;AACT;;;AC/CA,IAAa,iBAAiB,EAAE,kBAAsC;CACpE,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,kBAAA,qBAAmB,qBAA4B,oBAAoB,WAAW;CACtF,MAAM,EAAE,aAAa,YAAY,kBAAkB,WAAW;CAC9D,MAAM,eAAe,WAAW,YAAY;CAE5C,MAAM,cACH,cAAc,KAAK,EAAE,KAAK,KAC3B,SAAS,MAAM,QACf,SAAS,MAAM,MACf,YAAY,SACZ,EAAE,uBAAuB;CAC3B,MAAM,cAAc,cAAc;EAChC,MAAM,iBAAiB,YAAY,YAAY,YAAY;EAE3D,IAAI,CAAC,gBAAgB,OAAO,KAAA;EAE5B,MAAM,eAAe,YAAY,cAAc;EAE/C,OAAO,iBAAiB,gBAAgB,KAAA,IAAY;CACtD,GAAG,CAAC,YAAY,UAAU,YAAY,QAAQ,CAAC;CAC/C,MAAM,gBAAgB,EAAE,0BAA0B;CAElD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,OAAD;IAAK,eAAY;IAAO,WAAU;GAAoC,CAAA;GACtE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eAA4B;IAAiB,CAAA,GAC3D,SAAS,aACR,oBAAC,oBAAD,EAAkB,aAAY,+BAAgC,CAAA,IAC5D,IACD;;GACL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,cACC,oBAAC,KAAD;KACE,cAAY;KACZ,WAAU;KACV,UAAA;KACA,MAAM;KACN,KAAI;KACJ,QAAO;KACP,OAAO;eAEP,oBAAC,qBAAD,CAAsB,CAAA;IACrB,CAAA,IACD,MACH,cAAc,QACb,oBAAC,QAAD;KACE,cAAY,EAAE,OAAO;KACrB,WAAU;KACV,SAAS,aAAa;KACtB,OAAO,EAAE,OAAO;eAEhB,oBAAC,WAAD,CAAY,CAAA;IACN,CAAA,IACN,IACD;;EACF;;AAET;;;ACpEA,IAAM,cAAc,MAAM,WAAW,OAAO,oCAAuB;AAQnE,IAAa,eAAe,EAAE,WAAW,cAAc,eAAiC;CACtF,MAAM,EAAE,kBAAA,qBAAmB,kBAAyB,aAAa,uBAC/D,oBAAoB;CAEtB,OAAO,qBACL,oBAAC,oBAAD;EAAkC;EAAwB;CAAW,CAAA,IAErE,oBAAC,MAAM,UAAP;EACE,UACE,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,oBAAD,CAAmB,CAAA;EAChB,CAAA;YAGP,oBAAC,aAAD;GACa;GACG;GACJ;EACX,CAAA;CACa,CAAA;AAEpB;;;AC3BA,IAAa,kBAAkB,EAC7B,WACA,QACA,GAAG,iBACsB;CACzB,MAAM,EAAE,MAAM,sBAAsB;CAEpC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,WAAD;GACE,WAAW,KAAK,uDAAuD,SAAS;GAChF,GAAI;EACL,CAAA,GACA,SACC,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,YAAY;GAC1B,UAAA;GACA,WAAW,KACT,+DACF;GACA,SAAS;GACT,MAAK;GACL,SAAQ;aAER,oBAAC,cAAD,CAAe,CAAA;EACT,CAAA,IAER,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,cAAD,CAAe,CAAA;EACZ,CAAA,CAEJ;;AAET;;;AChCA,IAAM,kBAAkB;AACxB,IAAM,sBAAsB;AAE5B,IAAa,kBAAkB;CAC7B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,wBACA,cACA,aACA,UACA,cACA,SACA,aACA,WACA,mBACE,kBAAkB;CACtB,MAAM,eAAe,WAAW,YAAY;CAE5C,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAGhD,MAAM,qBAAqB,OAAO,KAAK;CACvC,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAChD,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,CAAC,gBAAgB,qBAAqB,SAC1C,IACF;CAKA,MAAM,qBAAqB,OAAO,KAAK;CACvC,MAAM,gBAAgB,OAAwC,IAAI;CAClE,MAAM,qBAAqB,OAAO,KAAK;CACvC,MAAM,eAAe,OAAuB,IAAI;CAGhD,gBAAgB;EACd,aAAa,KAAK;CACpB,GAAG,CAAC,YAAY,CAAC;CAGjB,MAAM,eAAe,OAAO,YAAY;CACxC,gBAAgB;EACd,IAAI,aAAa,YAAY,cAAc;EAE3C,kBADkB,eAAe,aAAa,UAAU,YAAY,UACzC;EAC3B,eAAe,CAAC;EAChB,cAAc,KAAK;EACnB,mBAAmB,UAAU;EAE7B,MAAM,QAAQ,iBAAiB;GAC7B,kBAAkB,IAAI;GACtB,mBAAmB,UAAU;EAC/B,GAAG,mBAAmB;EAEtB,aAAa,UAAU;EACvB,aAAa,aAAa,KAAK;CACjC,GAAG,CAAC,YAAY,CAAC;CAGjB,MAAM,iBAAiB,kBAAkB;EACvC,IAAI,mBAAmB,SAAS;EAChC,SAAS;CACX,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,qBAAqB,kBAAkB;EAC3C,IAAI,mBAAmB,SAAS;EAChC,aAAa;CACf,GAAG,CAAC,YAAY,CAAC;CAGjB,MAAM,gBAAgB,aACnB,UAAyB;EACxB,IAAI,MAAM,QAAQ,aAAa;GAC7B,MAAM,eAAe;GACrB,mBAAmB;EACrB,OAAO,IAAI,MAAM,QAAQ,cAAc;GACrC,MAAM,eAAe;GACrB,eAAe;EACjB;CACF,GACA,CAAC,gBAAgB,kBAAkB,CACrC;CAEA,gBAAgB;EACd,SAAS,iBAAiB,WAAW,aAAa;EAClD,aAAa,SAAS,oBAAoB,WAAW,aAAa;CACpE,GAAG,CAAC,aAAa,CAAC;CAGlB,MAAM,mBAAmB,aAAa,UAA4B;EAChE,IAAI,mBAAmB,SAAS;EAChC,MAAM,QAAQ,MAAM,QAAQ;EAC5B,mBAAmB,UAAU;EAC7B,cAAc,UAAU;GAAE,GAAG,MAAM;GAAS,GAAG,MAAM;EAAQ;EAC7D,mBAAmB,UAAU;CAC/B,GAAG,CAAC,CAAC;CAEL,MAAM,kBAAkB,aACrB,UAA4B;EAC3B,IAAI,CAAC,cAAc,WAAW,mBAAmB,SAAS;EAE1D,MAAM,QAAQ,MAAM,QAAQ;EAC5B,MAAM,SAAS,MAAM,UAAU,cAAc,QAAQ;EACrD,MAAM,SAAS,MAAM,UAAU,cAAc,QAAQ;EAGrD,IAAI,CAAC,cAAc,CAAC,mBAAmB,SAAS;GAC9C,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,IAAI,IAAI;IAChE,mBAAmB,UAAU;IAC7B,mBAAmB,UAAU;IAC7B;GACF;GACA,IAAI,KAAK,IAAI,MAAM,IAAI,IAAI;IACzB,mBAAmB,UAAU;IAC7B,cAAc,IAAI;GACpB;EACF;EAEA,IAAI,mBAAmB,SAAS;EAGhC,IAAK,CAAC,WAAW,SAAS,KAAO,CAAC,eAAe,SAAS,GACxD,eAAe,SAAS,EAAG;OAE3B,eAAe,MAAM;CAEzB,GACA;EAAC;EAAY;EAAS;CAAW,CACnC;CAEA,MAAM,iBAAiB,kBAAkB;EACvC,IAAI,CAAC,cAAc,WAAW,mBAAmB,SAAS;GACxD,IAAI,mBAAmB,SAAS,mBAAmB,UAAU;GAC7D,cAAc,UAAU;GACxB;EACF;EAEA,MAAM,SAAS;EACf,IAAI,cAAc,KAAK,IAAI,MAAM,IAAI,IACnC,mBAAmB,UAAU;EAE/B,cAAc,UAAU;EAExB,IAAI,KAAK,IAAI,MAAM,KAAK,iBACtB,IAAI,SAAS,KAAK,SAChB,SAAS;OACJ,IAAI,SAAS,KAAK,aACvB,aAAa;OAGb,eAAe,CAAC;OAIlB,eAAe,CAAC;EAGlB,cAAc,KAAK;CACrB,GAAG;EAAC;EAAa;EAAS;EAAa;EAAU;EAAc;CAAU,CAAC;CAE1E,MAAM,eAAe,cAAc,SAAS;CAC5C,MAAM,wBAAwB,aAC3B,UAA4C;EAC3C,IAAI,MAAM,WAAW,MAAM,eAAe;EAE1C,IAAI,mBAAmB,SAAS;GAC9B,mBAAmB,UAAU;GAC7B;EACF;EAEA,IAAI,CAAC,wBAAwB;EAE7B,eAAe;CACjB,GACA,CAAC,wBAAwB,YAAY,CACvC;CAEA,MAAM,aACJ,cAAe,gBAAgB,KAAK,mBAAmB,OACnD,EAAE,WAAW,cAAc,YAAY,KAAK,IAC5C,CAAC;CAEP,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,eAAD,EAA4B,YAAc,CAAA;IAC1C,oBAAC,WAAD;KACE,cAAY,EAAE,gBAAgB;KAC9B,WAAW,KACT,uCACA,CAAC,eAAe,uCAClB;KACA,UAAU,CAAC;KACX,SAAS;eAET,oBAAC,iBAAD,CAAkB,CAAA;IACT,CAAA;IACX,oBAAC,OAAD;KACE,WAAU;KACV,SAAS;KACT,YAAY;KACZ,aAAa;KACb,cAAc;KACd,KAAK;eAEL,oBAAC,OAAD;MACE,WAAW,KAAK,sCAAsC;OACpD,sCAAsC;OACtC,4CACE,CAAC,cAAc,mBAAmB;OACpC,2CACE,CAAC,cAAc,mBAAmB;MACtC,CAAC;MACD,OAAO;gBAEN,YAAY,YAAY,YAAY,oBACnC,oBAAC,OAAD;OAAK,WAAU;iBACZ,YACC,oBAAC,aAAD;QAAa,WAAA;QAAU,UAAU,YAAY;OAAW,CAAA,IAExD,oBAAC,gBAAD;QACE,KAAK,YAAY,SAAS;QAC1B,cAAc,aAAa,IAAI;QAC/B,KAAK,YAAY;OAClB,CAAA;MAEA,CAAA,IAEL,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,WAAD;QAAW,KAAK,YAAY;QAAK,KAAK,YAAY;OAAW,CAAA;MAC1D,CAAA;KAEJ,CAAA;IACF,CAAA;IACL,oBAAC,WAAD;KACE,cAAY,EAAE,YAAY;KAC1B,WAAW,KACT,uCACA,CAAC,WAAW,uCACd;KACA,UAAU,CAAC;KACX,SAAS;eAET,oBAAC,kBAAD,CAAmB,CAAA;IACV,CAAA;GACR;MACJ,YAAY,KACX,qBAAC,OAAD;GAAK,WAAU;aAAf;IACG,eAAe;IAAE;IAAK;GACpB;IAEJ;;AAET;AAEA,IAAM,aAAa,EAAE,WAAW,GAAG,YACjC,oBAAC,QAAD;CAAQ,GAAI;CAAO,WAAW,KAAK,iCAAiC,SAAS;AAAI,CAAA;;;ACxPnF,IAAa,WAAW,EACtB,yBAAyB,MACzB,WAAA,aACA,eAAe,GACf,OACA,eACA,qBACkB;CAClB,MAAM,EAAE,WAAW,qBAAqB,oBAAoB;CAC5D,MAAM,oBAAoB,eAAa,oBAAoB;CAC3D,MAAM,CAAC,cAAc,mBAAmB,SAAS,YAAY;CAE7D,MAAM,YAAY,MAAM;CAExB,MAAM,YAAY,aACf,UAAkB;EACjB,IAAI,SAAS,KAAK,QAAQ,WACxB,gBAAgB,KAAK;CAEzB,GACA,CAAC,SAAS,CACZ;CAEA,MAAM,WAAW,kBAAkB;EACjC,iBAAiB,SAAU,OAAO,YAAY,IAAI,OAAO,IAAI,IAAK;CACpE,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,eAAe,kBAAkB;EACrC,iBAAiB,SAAU,OAAO,IAAI,OAAO,IAAI,IAAK;CACxD,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,gBAAgB,YAAY;CAC9B,GAAG,CAAC,cAAc,aAAa,CAAC;CAEhC,MAAM,UAAU,eAAe,YAAY;CAC3C,MAAM,cAAc,eAAe;CACnC,MAAM,cAAc,MAAM;CAE1B,MAAM,eAAe,eACZ;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,OACE,oBAAC,eAAe,UAAhB;EAAyB,OAAO;YAC9B,oBAAC,mBAAD,CAAoB,CAAA;CACG,CAAA;AAE7B;;;ACnFA,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAeA,IAAa,gBAAgB,EAC3B,WACA,yBAAyB,MACzB,OACA,qBACuB;CACvB,MAAM,EACJ,WAAA,cAAY,WACZ,SAAA,YAAU,SACV,QAAQ,gBACN,oBAAoB;CACxB,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,eAAe,oBAAoB,SAAS,CAAC;CACpD,MAAM,uBAAuB,gBAAc;CAE3C,MAAM,aAAa,kBAAkB;EACnC,aAAa,KAAK;CACpB,GAAG,CAAC,CAAC;CACL,MAAM,sBAAsB,aACzB,WAA6B,WAAW,WACzC,CAAC,CACH;CAEA,MAAM,uBAAuB,aAAa,UAAkB;EAC1D,iBAAiB,KAAK;EACtB,aAAa,IAAI;CACnB,GAAG,CAAC,CAAC;CAEL,MAAM,YAAY,MAAM;CACxB,MAAM,eAAe,MAAM,MAAM,GAAG,sBAAsB;CAC1D,MAAM,gBAAgB,YAAY;CAElC,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EACE,WAAW,KAAK,2BAA2B,WAAW;GACpD,yCAAyC,cAAc;GACvD,uCAAuC,cAAc;EACvD,CAAC;YAEA,aAAa,KAAK,MAAM,UAAU;GAIjC,OACE,oBAAC,iBAAD;IACa,WAAA;IACX,8BAA8B;IACvB;IACD;IACK;IAEX,eAAe,qBAAqB,KAAK;IAC1B;IACF,aAbK,UAAU,yBAAyB,KACpB,gBAAgB;GAalD,GAJM,KAIN;EAEL,CAAC;CACE,CAAA,GACL,oBAAC,OAAD;EACE,WAAW,KAAK,2BAA2B,cAAc;EACzD,SAAS;EACT,gBAAgB;EAChB,MAAM;YAEN,oBAAC,WAAD;GAC0B;GACb;GACX,cAAc;GACP;GACP,gBAAgB;EACjB,CAAA;CACI,CAAA,CACP,EAAA,CAAA;AAEN;AAaA,IAAM,mBAAmB,EACvB,WACA,8BACA,OACA,MACA,WACA,SACA,eACA,kBAC0B;CAC1B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,WAAW,KAAK;CACtB,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CACtD,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,QAAQ,QAAQ,CAAC;CAItE,MAAM,CAAC,aAAa,kBAAkB,SAAS,EAAE;CAEjD,MAAM,EACJ,SAAS,aACT,QAAQ,YACR,GAAG,mBACD,kBAAkB,IAAI;CAC1B,MAAM,qBAAqB,gBAAgB,CAAC;CAC5C,MAAM,uBAAuB,kBAAkB,CAAC,sBAAsB,CAAC;CAEvE,MAAM,0BAA0B;EAC9B,IAAI,oBAAoB;GACtB,gBAAgB,KAAK;GACrB,kBAAkB,IAAI;GACtB,eAAe,UAAU,KAAK,IAAI,GAAG;GACrC;EACF;EAEA,QAAQ;CACV;CAMA,OACE,qBAAC,UAAD;EACE,cANgB,qBAChB,EAAE,mBAAmB,IACrB,oBAAoB;GAAE,YAAY,QAAQ;GAAG;GAAW;EAAE,CAAC;EAK3D,WAAW,KAAK,kCAAkC;GAChD,+CAA+C;GAC/C,2CAA2C;EAC7C,CAAC;EACD,SAAS;EACT,MAAK;YAPP;GASG,KAAK,oBACJ,oBAAC,gBAAD;IAAgB,KAAK,EAAE,uBAAuB;IAAG,KAAK,KAAK;GAAoB,CAAA,IAE/E,oBAAC,WAAD;IACE,GAAI;IACJ,KAAK,KAAK,OAAO,EAAE,uBAAuB;IAC1C,UAAU,UAAU;KAClB,kBAAkB,KAAK;KACvB,gBAAgB,IAAI;KACpB,cAAc,KAAK;IACrB;IACA,SAAS,UAAU;KACjB,kBAAkB,KAAK;KACvB,gBAAgB,KAAK;KACrB,aAAa,KAAK;IACpB;IACA,KAAK,WAAW,GAAG,WAAW,gBAAgB;IAC9C,GAAK,+BAA+B,EAAE,2BAA2B,MAAM,IAAI,CAAC;GAC7E,CAAA;GAEF,wBACC,oBAAC,OAAD;IACE,eAAY;IACZ,WAAU;IACV,eAAY;cAEZ,oBAAC,kBAAD,CAAmB,CAAA;GAChB,CAAA;GAEN,sBACC,oBAAC,OAAD;IACE,eAAY;IACZ,WAAU;IACV,eAAY;cAEZ,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,WAAD,CAAY,CAAA;IACT,CAAA;GACF,CAAA;GAEN,eACC,qBAAC,OAAD;IAAK,WAAU;cAAf,CAAsD,KAAE,aAAmB;;EAEvE;;AAEZ;AAEA,IAAM,uBAAuB,EAC3B,YACA,WACA,QAMA,cAAc,IACV,EAAE,uBAAuB,IACzB,EAAE,qCAAqC,EACrC,OAAO,WACT,CAAC;AAEP,IAAM,qBAAqB,SAAgD;CACzE,MAAM,iBAA0C,CAAC;CACjD,KAAK,MAAM,OAAO,sBAAsB;EACtC,MAAM,QAAQ,KAAK;EACnB,IAAI,UAAU,KAAA,GACZ,eAAe,OAAO;CAE1B;CAEA,OAAO;AACT;;;;;;ACzPA,IAAa,kBAAkB,gBAA4B;CACzD,MAAM,EAAE,cAAA,iBAAe,iBAAwB,oBAAoB;CAEnE,OAAO,oBAAC,gBAAD;EAAc,OAAO,CAAC,WAAW;EAAG,gBAAe;CAAyB,CAAA;AACrF;;;ACMA,IAAM,wBAAwB,UAA8C;CAC1E,MAAM,EAAE,UAAU,WAAW,UAAU,MAAM,KAAK,WAAW;CAC7D,IAAI,CAAC,MAAM,OAAO;CAElB,OACE,oBAAC,KAAD;EACa;EACD;EACV,MALc,YAAY,IAKpB;EACD;EACG;EAEP;CACA,CAAA;AAEP;AAEA,IAAa,aAAa,MAAM,KAAK,oBAAoB;;;AChCzD,IAAa,sBAAsB,EAAE,WAA0C;CAC7E,MAAM,EAAE,MAAM,sBAAsB,MAAM;CAE1C,OACE,oBAAC,OAAD;EACE,WAAW,KAAK,qCAAqC,GAClD,sCAAsC,SAAS,KAClD,CAAC;YAED,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IAAK,WAAU;cACZ,EAAE,qCAAqC;GACrC,CAAA;EACF,CAAA;CACF,CAAA;AAET;;;ACHA,IAAM,YAAY,EAAE,SAAS,UAAU,WAA0B;CAC/D,MAAM,YAAY,KAChB,wEAAwE,MAC1E;CAEA,OAAO,UACL,oBAAC,YAAD;EACa;EACX,MAAM;EACN,KAAI;EACJ,QAAO;EAEN;CACS,CAAA,IAEZ,oBAAC,OAAD;EAAgB;EAAY;CAAc,CAAA;AAE9C;AAOA,IAAM,cAAc,UAA2B;CAC7C,MAAM,EAAE,YAAY,OAAO,WAAW,WAAW,UAAU;CAE3D,OAAO,QACL,oBAAC,OAAD;EACE,WAAU;EACV,eAAa;YAEb,oBAAC,WAAD;GACE,KAAK,SAAS;GACd,eAAY;GACZ,KAAK,aAAa;GAClB,OAAO,SAAS;GAChB,GAAI;EACL,CAAA;CACE,CAAA,IACH;AACN;AAIA,IAAM,eAAe,UAA4B;CAC/C,MAAM,EAAE,eAAe,MAAM,OAAO,eAAe;CACnD,MAAM,MAAM,cAAc;CAE1B,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,SAAS,oBAAC,OAAD;IAAK,WAAU;cAA4C;GAAW,CAAA;GAC/E,QAAQ,oBAAC,OAAD;IAAK,WAAU;cAA2C;GAAU,CAAA;GAC5E,OACC,qBAAC,OAAD;IACE,WAAU;IACV,eAAY;cAFd,CAIE,oBAAC,UAAD,CAAW,CAAA,GACX,oBAAC,OAAD;KAAK,WAAU;eAA0C;IAAS,CAAA,CAC/D;;EAEJ;;AAET;AAMA,IAAM,kBAAkB,UAAqB;CAC3C,MAAM,EAAE,OAAO,WAAW,eAAe,WAAW,OAAO,YAAY,SAAS;CAChF,MAAM,EAAE,cAAc,qBAAqB,uBAAuB,EAAE;CACpE,MAAM,UAAU,cAAc;CAE9B,IAAI,QAAQ,aAAa;CACzB,MAAM,aAAkD,CAAC;CAEzD,IAAI,SAAS,WAAW,OAAO,UAAU,aAAa;EACpD,MAAM,eACJ,MAAM;EACR,QAAQ,aAAa;EACrB,WAAW,SAAS,aAAa;EACjC,WAAW,QAAQ,aAAa;CAClC;CAEA,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,OACzB,OAAO,oBAAC,oBAAD,CAAqB,CAAA;CAG9B,OACE,qBAAC,UAAD;EAAmB;EAAe;YAAlC,CACE,oBAAC,YAAD;GAAY,GAAI;GAAmB;GAAmB;EAAQ,CAAA,GAC9D,oBAAC,aAAD,EAAa,GAAI,MAAQ,CAAA,CACjB;;AAEd;;;;AAKA,IAAa,OAAO,MAAM,KAAK,cAAc;;;ACzG7C,IAAa,kBAAkB,EAAE,iBAAsC;CACrE,MAAM,EAAE,oBAAoB,mBAAA,sBAAoB,sBAC9C,oBAAoB;CAEtB,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd;GAIE,oBANsB,sBAAsB,UAM5C;IACE,WAAU;IACV,UAAU,WAAW;IACrB,UAAU,WAAW;GACtB,CAAA;GACD,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,OAAD;MACE,WAAU;MACV,eAAY;gBAEX,WAAW;KACT,CAAA;IACF,CAAA,GACL,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,qBAAD,EAAmB,UAAU,WAAW,UAAY,CAAA;IACjD,CAAA,CACF;;GACL,oBAAC,gBAAD;IACE,UAAU,WAAW;IACrB,mBAAmB,WAAW;GAC/B,CAAA;EACE;;AAET;;;AC9BA,IAAa,SAAS,EAAE,iBAAuC;CAC7D,MAAM,EAAE,cAAc,kBAAkB,+BACtC,uBAAuB;CACzB,MAAM,EAAE,WAAA,cAAY,cAAqB,oBAAoB;CAC7D,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,uBAAuB,gBAAc;CAC3C,MAAM,eAAe,OAAyB,IAAI;CAClD,MAAM,CAAC,yBAAyB,8BAA8B,SAE5D,KAAA,CAAS;CAEX,MAAM,mBAAmB,cACjB,yBAAyB,YAAY,EAAE,iBAAiB,CAAC,GAC/D,CAAC,YAAY,gBAAgB,CAC/B;CACA,MAAM,MAAM,oBAAoB,iBAAiB;CACjD,MAAM,aAAa,oBAAoB,iBAAiB;CACxD,MAAM,WAAW,oBAAoB,iBAAiB;CACtD,MAAM,QAAQ,oBAAoB,iBAAiB;CACnD,MAAM,mBAAmB,yBAAyB,OAAO;CACzD,MAAM,sBAAsB,cAAc;EACxC,MAAM,iBAAiB,OAAO,YAAY,MAAM;EAChD,MAAM,gBAAgB,OAAO,YAAY,KAAK;EAE9C,OAAO;GACL,qBAAqB,OAAO,iBAAiB,IAAI,iBAAiB,GAAO;GACzE,oBAAoB,OAAO,gBAAgB,IAAI,gBAAgB,GAAO;EACxE;CACF,GAAG,CAAC,YAAY,QAAQ,YAAY,KAAK,CAAC;CAE1C,sBAAsB;EACpB,IAAI,CAAC,aAAa,WAAW,CAAC,4BAA4B;EAG1D,2BADe,2BAA2B,YAAY,aAAa,OACxC,CAAM;CACnC,GAAG,CAAC,YAAY,0BAA0B,CAAC;CAE3C,IAAI,CAAC,UAAU,OAAO;CAEtB,OACE,qBAAC,OAAD;EAAK,WAAW,KAAK,oCAAoC;YAAzD,CACE,oBAAC,aAAD;GACE,KAAK,OAAO,SAAS,EAAE,uBAAuB;GAC9C,QAAQ,YAAY;GACpB,KAAK;GACL,KAAK;GACL,OAAO;GACP,OAAO,YAAY;GACnB,GAAK,uBAAuB,EAAE,2BAA2B,MAAM,IAAI,CAAC;EACrE,CAAA,GACD,oBAAC,YAAD,CAAa,CAAA,CACV;;AAET;AAEA,IAAM,mBACJ,qBAAC,OAAD;CAAK,WAAU;WAAf,CACE,oBAAC,WAAD,CAAY,CAAA,GAAC,OAEV;;;;ACxDP,IAAa,yBACX,oBAAC,OAAD;CAAK,MAAK;CAAe,SAAQ;CAAY,OAAM;WACjD,oBAAC,QAAD,EAAM,GAAE,iRAAkR,CAAA;AACvR,CAAA;;;ACLP,IAAa,eAAe,EAC1B,sCAAsC,4CACtC,gBACA,eACsB;CACtB,MAAM,EAAE,SAAS,WAAW,eAAe;CAC3C,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,CAAC,gBAAgB,qBAAqB,SAC1C,CAAC,CAAC,SAAS,UAAU,IAAI,KAAK,SAAS,MAAM,EAAE,QAAQ,qBAAI,IAAI,KAAK,GAAE,QAAQ,CAChF;CACA,MAAM,aAAa,OAAkD,KAAA,CAAS;CAE9E,MAAM,eAAe,SAAS,YAAY,OAAO;CACjD,MAAM,iBAAiB,CAAC,CAAC,SAAS;CAElC,gBAAgB;EACd,IAAI,CAAC,SAAS,QAAQ;EACtB,aAAa,WAAW,OAAO;EAC/B,WAAW,UAAU,iBACb,kBAAkB,IAAI,GAC5B,IAAI,KAAK,SAAS,MAAM,EAAE,QAAQ,IAAI,KAAK,IAAI,CACjD;CACF,GAAG,CAAC,SAAS,MAAM,CAAC;CAEpB,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd,CAIE,oBAAC,OAAD;GAAK,WAAU;aACZ,iBACC,oBAAC,gBAAD;IAAgB,UAAU,SAAS;IAAU,WAAW,SAAS;GAAY,CAAA,IAE7E,oBAAC,qCAAD,EAA+C,SAAW,CAAA;EAEzD,CAAA,GACL,oBAAC,OAAD;GAAK,WAAU;aACZ,iBACC,iBACE,EAAE,wBAAwB,IACxB,eACF,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD;KACE,YAAW;KACX,WAAU;KACV,eAAe,SAAS,wBAAwB,QAAQ;KACxD,MAAK;KACL,SAAQ;eAEP,EAAE,cAAc;IACX,CAAA,GACR,oBAAC,OAAD;KAAK,WAAU;eACZ,EAAE,8BAA8B,EAC/B,WAAW,EAAE,0BAA0B,EAAE,WAAW,SAAS,OAAO,CAAC,EACvE,CAAC;IACE,CAAA,CACF;QAEL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eACZ,EAAE,eAAe;IACf,CAAA,GACL,oBAAC,OAAD;KAAK,WAAU;eACZ,EAAE,8BAA8B,EAC/B,WAAW,EAAE,0BAA0B,EAAE,WAAW,SAAS,OAAO,CAAC,EACvE,CAAC;IACE,CAAA,CACF;QAGP,EAAE,kBAAkB;EAEnB,CAAA,CACF;;AAET;AAMA,IAAM,8CAA8C,EAClD,eAC8C;CAC9C,MAAM,EAAE,MAAM,sBAAsB;CAEpC,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd,CAIE,oBAAC,cAAD,CAAe,CAAA,GACf,oBAAC,KAAD;GACE,cAAY,EAAE,wBAAwB;GACtC,WAAU;GACV,MAAM,6BAA6B,CAAC,SAAS,UAAU,SAAS,SAAS,EAAE,KAAK;GAChF,KAAI;GACJ,QAAO;aAEP,oBAAC,kBAAD,CAAmB,CAAA;EAClB,CAAA,CACA;;AAET;;;ACjHA,IAAa,8BAA8B;CACzC,MAAM,EAAE,MAAM,sBAAsB,uBAAuB;CAC3D,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd,CAIE,oBAAC,2BAAD,CAA4B,CAAA,GAC5B,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IACE,WAAU;IACV,eAAY;cAEX,EAAE,wBAAwB;GACxB,CAAA;EACF,CAAA,CACF;;AAET;;;ACvBA,IAAa,6BAA6B;CACxC,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,aAAD,CAAc,CAAA,GACb,EAAE,qBAAqB,CACrB;;AAET;;;ACEA,IAAa,mBAAmB,EAC9B,YACA,aAAA,gBAAc,kBACY;CAC1B,MAAM,EAAE,8BAA8B,+BACpC,uBAAuB;CACzB,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,CAAC,yBAAyB,8BAC9B,SAAuC;CACzC,MAAM,CAAC,WAAW,gBAAgB,MAAM,SAAS,CAAC,4BAA4B;CAE9E,sBAAsB;EACpB,IAAI,aAAa,WAAW,4BAM1B,2BALe,2BACb,YACA,aAAa,SACb,4BAEyB,CAAM;CAErC,GAAG;EACD;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,uBAAuB,QAC3B,WAAW,aAAa,4BAC1B;CAGA,OACE,oBAAC,OAAD;EACE,WAAU;EACV,eAAY;EACZ,KAAK;EACL,OAAO,0BAA0B,WAAW,aAAa,EAAE;YAE1D,wBAAwB,CAAC,YACxB,oBAAC,gBAAD;GACE,KAAK,WAAW;GAChB,eAAY;GACZ,cAAc,aAAa,IAAI;GAC/B,KAAK,WAAW;GAChB,OAAO,WAAW;EACnB,CAAA,IAED,oBAAC,eAAD;GACE,WAAW;GACX,cAAc,yBAAyB;GACvC,UAAU,yBAAyB;EACpC,CAAA;CAEA,CAAA;AAET;;;ACfA,IAAa,6BAA6B,EACxC,YACA,UACA,oBACiD;CACjD,MAAM,QAAQ,wBAAwB,UAAU;CAChD,IAAI,QAAQ;CAEZ,IAAI,CAAC,SAAS,CAAC,yBAAyB,UAAU,GAChD,QACE,kBAAkB,UAAU,CAAC,YAAY,aAAa,CAAC,YAAY,YAC/D,aACA,YAAY,SAAS,SACnB,YACA;CAiBV,OAAO,oBAAC,OAAD;EAAK,WAdO,KACjB,0EACA;IACG,iCAAiC,kBAAkB;IACnD,iCAAkC,YAA2B,SAC5D,YACC;IACF,iCAAiC,cAAc,IAAI,UAClD,iBAAiB;GACnB,2CAA2C,gBAAgB,UAAU;GACrE,6CAA6C,UAAU;EACzD,CAGqB;EAAa;CAAc,CAAA;AACpD;AAEA,IAAa,8BAA8B,EACzC,eACA,YACA,mBAAA,sBAAoB,mBACpB,oCAC2B;CAC3B,IAAI,CAAC,WAAW,SAAS,QAAQ,OAAO;CAExC,MAAM,4BACJ,WAAW,QAAQ,gCAAgC,WAAW;CAEhE,OACE,oBAAC,qBAAD;EACE,GAAI;EACW;EACf,SAAS,WAAW;EACO;EAC3B,IAAK,WAA+B,eAAe,MAAM;EACzD,MAAM,WAAW,QAAQ;CAC1B,CAAA;AAEL;AAEA,IAAa,kBAAkB,UAA4B;CACzD,MAAM,EAAE,aAAa,qBAAqB;CAC1C,IAAI,CAAC,iBAAiB,QAAQ,OAAO;CAErC,IAAI,iBAAiB,SAAS,GAC5B,OACE,oBAAC,kBAAD;EACE,GAAI;EACJ,YAAY;GAAE,OAAO;GAAkB,MAAM;EAAU;CACxD,CAAA;CAIL,MAAM,kBAAkB,iBAAiB;CACzC,MAAM,EAAE,aAAa,cAAc,GAAG,SAAS;CAE/C,IAAI,kBAAkB,iBAAiB,uBAAuB,GAC5D,OAAO,oBAAC,gBAAD;EAAgB,YAAY;EAAiB,GAAI;CAAO,CAAA;CAGjE,OAAO,oBAAC,gBAAD;EAAgB,YAAY;EAAiB,GAAI;CAAO,CAAA;AACjE;AAEA,IAAa,iBAAiB,UAAiC;CAC7D,MAAM,EAAE,YAAY,MAAA,SAAO,SAAgB;CAC3C,MAAM,gBAAgB;CAEtB,IAAI,WAAW,WAAW,WAAW,QAAQ,QAC3C,OACE,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,QAAD,EAAM,GAAI,WAAa,CAAA,GACvB,oBAAC,4BAAD,EAA4B,GAAI,MAAQ,CAAA,CACrC;;CACoB,CAAA;CAI/B,OACE,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,oBAAC,QAAD,EAAM,GAAI,WAAa,CAAA;CACE,CAAA;AAE/B;AAEA,IAAa,kBAAkB,UAAiC;CAC9D,MAAM,EAAE,YAAY,OAAA,UAAQ,UAAiB;CAC7C,MAAM,gBAAgB;CAEtB,IAAI,WAAW,WAAW,WAAW,QAAQ,QAC3C,OACE,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,sBAAD,CAAuB,CAAA;IACvB,oBAAC,SAAD,EAAmB,WAAa,CAAA;IAChC,oBAAC,4BAAD,EAA4B,GAAI,MAAQ,CAAA;GACrC;;CACoB,CAAA;CAI/B,OACE,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,oBAAC,SAAD,EAAmB,WAAa,CAAA;CACP,CAAA;AAE/B;AAEA,IAAa,iBAAiB,UAAiC;CAC7D,MAAM,EAAE,eAAe;CAEvB,IAAI,2BAA2B,UAAU,GACvC,OAAO,oBAAC,yBAAD,EAAyB,GAAI,MAAQ,CAAA;CAG9C,IAAI,kBAAkB,UAAU,GAC9B,OAAO,oBAAC,gBAAD,EAAgB,GAAI,MAAQ,CAAA;CAGrC,IAAI,CAAC,WAAW,aAAa,CAAC,iBAAiB,YAAY,uBAAuB,GAChF,OAAO;CAGT,OAAO,oBAAC,qBAAD,EAAqB,GAAI,MAAQ,CAAA;AAC1C;AAEA,IAAa,oBAAoB,EAC/B,YACA,cAAA,iBAAe,mBACS;CAUxB,OACE,oBAAC,2BAAD;EAAuC;EAAY,eAAc;YAC/D,oBAAC,gBAAD,EAAqB,OAXX,cAEV,WAAW,MAAM,QAAuB,KAAK,eAAe;GAC1D,MAAM,OAAO,yBAAyB,UAAU;GAChD,IAAI,MAAM,IAAI,KAAK,IAAI;GACvB,OAAO;EACT,GAAG,CAAC,CAAC,GACP,CAAC,WAAW,KAAK,CAIM,EAAsB,GAAX,SAAW;CAClB,CAAA;AAE/B;AAEA,IAAa,kBAAkB,UAAiC;CAC9D,MAAM,EAAE,YAAY,QAAQ,mBAAiB;CAC7C,MAAM,gBAAgB;CACtB,MAAM,eAAe,OAAyB,IAAI;CAClD,MAAM,EAAE,+BAA+B,uBAAuB;CAC9D,MAAM,CAAC,yBAAyB,8BAA8B,SAE5D,KAAA,CAAS;CAEX,sBAAsB;EACpB,IAAI,aAAa,WAAW,4BAE1B,2BADe,2BAA2B,YAAY,aAAa,OACxC,CAAM;CAErC,GAAG;EAAC;EAAc;EAA4B;CAAU,CAAC;CAEzD,MAAM,uBAAuB,WAAW,aAAa,WAAW,aAAa;CAE7E,MAAM,cAA2B;EAC/B,GAAG,yBAAyB;GAC1B,GAAG;GACH,WAAW,yBAAyB,OAAO;EAC7C,CAAC;EACD,KAAK;EACL,OAAO,0BAA0B,oBAAoB;CACvD;CAEA,IAAI,WAAW,WAAW,WAAW,QAAQ,QAC3C,OACE,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD,EAAO,GAAI,YAAc,CAAA,GACzB,oBAAC,4BAAD,EAA4B,GAAI,MAAQ,CAAA,CACrC;;CACoB,CAAA;CAI/B,OACE,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,oBAAC,OAAD,EAAO,GAAI,YAAc,CAAA;CACA,CAAA;AAE/B;AAEA,IAAa,uBAAuB,EAClC,YACA,OAAO,qBACoB;CAC3B,IAAI,CAAC,WAAW,WAAW,OAAO;CAElC,OACE,oBAAC,2BAAD;EAAuC;EAAY,eAAc;YAC/D,oBAAC,MAAD,EAAkB,WAAa,CAAA;CACN,CAAA;AAE/B;AAEA,IAAa,kBAAkB,EAC7B,YACA,OAAA,UAAQ,YAER,oBAAC,2BAAD;CAAuC;CAAY,eAAc;WAC/D,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,SAAD,EAAmB,WAAa,CAAA;CAC7B,CAAA;AACoB,CAAA;AAG7B,IAAa,2BAA2B,EACtC,YACA,UACA,gBAAA,mBAAiB,qBAEjB,oBAAC,2BAAD;CAAuC;CAAY,eAAc;WAC/D,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,kBAAD;GAA4B;GAAsB;EAAW,CAAA;CAC1D,CAAA;AACoB,CAAA;AAG7B,IAAa,kBACX,UACG;CACH,MAAM,EAAE,YAAY,UAAU;CAC9B,MAAM,gBAAgB;CAEtB,OAAO,WAAW,SAAS,SACzB,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,iBAAD;IAA6B;IAAY,aAAa;GAAQ,CAAA,GAC9D,oBAAC,4BAAD,EAA4B,GAAI,MAAQ,CAAA,CACrC;;CACoB,CAAA,IAE3B,oBAAC,2BAAD;EAAuC;EAA2B;YAChE,oBAAC,iBAAD;GAA6B;GAAY,aAAa;EAAQ,CAAA;CACrC,CAAA;AAE/B;AAEA,IAAa,wBAAwB,EACnC,aAAA,gBAAc,aACd,eAEA,oBAAC,2BAAD;CAA2B,YAAY;CAAU,eAAc;WAC7D,oBAAC,eAAD,EAAuB,SAAW,CAAA;AACT,CAAA;AAG7B,IAAa,kCAAkC,EAC7C,YACA,uBAAA,0BAAwB,4BAExB,oBAAC,2BAAD;CAAuC;CAAY,eAAc;WAC/D,oBAAC,yBAAD,EAAmC,WAAa,CAAA;AACvB,CAAA;;;ACtS7B,IAAa,0BAA0B;CACrC;CACA;CACA;CACA;CACA;CACA;AACF;;;;AA2CA,IAAa,cAAc,UAA2B;CACpD,MAAM,EACJ,gCAAgC,sCAChC,aACA,GAAG,SACD;CAEJ,MAAM,qBAAqB,cAEvB,yBAAyB;EACvB;EACA;EACA,GAAG;CACL,CAAC,GAEH,CAAC,aAAa,6BAA6B,CAC7C;CAEA,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,wBAAwB,QACtB,KAAK,cAAc,CAAC,GAAG,KAAK,GAAG,mBAAmB,UAAU,GAC7D,CAAC,CACH;CACG,CAAA;AAET;AAEA,IAAM,4BAA4B,EAChC,aACA,GAAG,WAC6C;CAChD,MAAM,mBAAkC,CAAC;CACzC,MAAM,aAAa,YAAY,QAC5B,SAAS,eAAe;EACvB,IAAI,yBAAyB,UAAU,GACrC,QAAQ,YAAY,KAClB,8BAAC,sBAAD;GACE,GAAI;GACJ,KAAK,eAAe,QAAQ,YAAY;GACxC,UAAU;EACX,CAAA,CACH;OACK,IAAI,WAAW,SAAS,SAC7B,QAAQ,KAAK,KACX,oBAAC,gBAAD;GAEE,GAAI;GACQ;EACb,GAHM,SAAS,QAAQ,MAAM,QAG7B,CACH;OACK,IAAI,iBAAiB,UAAU,GACpC,QAAQ,KAAK,KACX,oBAAC,eAAD;GAEE,GAAI;GACQ;EACb,GAHM,QAAQ,QAAQ,KAAK,QAG3B,CACH;OACK,IACL,kBAAkB,UAAU,KAC5B,kBAAkB,YAAY,uBAAuB,GAErD,iBAAiB,KAAK,UAAyB;OAC1C,IACL,kBAAkB,UAAU,KAC5B,2BAA2B,UAAU,KACrC,iBAAiB,YAAY,uBAAuB,GAEpD,QAAQ,KAAK,KACX,oBAAC,eAAD;GAEE,GAAI;GACQ;EACb,GAHM,QAAQ,QAAQ,KAAK,QAG3B,CACH;OAEA,QAAQ,YAAY,KAClB,oBAAC,gCAAD;GAEE,GAAI;GACQ;EACb,GAHM,eAAe,QAAQ,YAAY,QAGzC,CACH;EAGF,OAAO;CACT,GACA;EACE,MAAM,CAAC;EACP,MAAM,CAAC;EACP,aAAa,CAAC;EACd,OAAO,CAAC;EACR,OAAO,CAAC;EACR,aAAa,CAAC;CAChB,CACF;CAEA,IAAI,iBAAiB,QACnB,WAAW,MAAM,KACf,oBAAC,gBAAD;EAAsC,GAAI;EAAM,aAAa;CAAmB,GAA5D,iBAA4D,CAClF;CAGF,OAAO;AACT;;;AC/LA,IAAM,iBAAiB,QAAQ,KAAK,UAAU,SAAS;;;;AAIvD,IAAa,iBAAiB;CAC5B,IAAI,OAAO,cAAc,aAAa,OAAO;CAC7C,OAAO,iCAAiC,KAAK,UAAU,aAAa,EAAE;AACxE;;;;AAKA,IAAa,kBAAkB;CAC7B,IAAI,OAAO,cAAc,aAAa,OAAO;CAC7C,OAAO,UAAU,WAAW,SAAS,SAAS;AAChD;;;;AAKA,IAAa,iBAAiB;CAC5B,IAAI,OAAO,cAAc,aAAa,OAAO;CAC7C,OAAO,UAAU,WAAW,SAAS,QAAQ;AAC/C;AAEA,IAAM,gBAAgB;CACpB,IAAI,SAAS,GAAG,OAAO;CACvB,IAAI,UAAU,GAAG,OAAO;CACxB,IAAI,SAAS,GAAG,OAAO;CACvB,OAAO;AACT;AAEA,IAAa,iCAAiC,EAC5C,QACA,aACA,oBAII;CACJ,MAAM,UAAU,cAAc;EAC5B,IAAI,CAAC,QAAQ,OAAO;EAEpB,OAAO,IAAI,oBAAoB;GAC7B;GACA,aACE,sBACO,OAAO,SAAS,IAAI,WAAW,UAAU,GAAG,QAAQ,EAAE,GAAG,OAAO;GACzE;EACF,CAAC;CACH,GAAG;EAAC;EAAQ;EAAa;CAAa,CAAC;CAEvC,gBAAgB;EACd,IAAI,CAAC,SAAS;EAEd,QAAQ,KAAK;EAEb,aAAa;GACX,QAAQ,wBAAwB;EAClC;CACF,GAAG,CAAC,OAAO,CAAC;CAEZ,OAAO;AACT;;;AC/DA,IAAM,mBAAiB,WAAmC,EACxD,aAAa,MAAM,YACrB;AAEA,IAAa,kCAAkC;CAC7C,MAAM,EAAE,sBAAsB,6BAA6B;CAC3D,MAAM,EAAE,gBAAgB,cAAc,kBAAkB,OAAO,eAAa;CAC5E,OAAO;EACL;EACA,sBAAsB,kBAAkB;EACxC,qBAAqB,kBAAkB;EACvC,oBAAoB,kBAAkB;EACtC,iBAAiB,kBAAkB;EACnC,qBAAqB,kBAAkB;EACvC,wBAAwB,kBAAkB;EAC1C,wBAAwB,kBAAkB;CAC5C;AACF;;;ACbA,IAAM,oCAAkC,WAAmC,EACzE,aAAa,MAAM,YACrB;AACA,IAAM,+BAA6B,WAA8B,EAC/D,MAAM,MAAM,KACd;AACA,IAAM,mCAAiC,WAAkC,EACvE,UAAU,MAAM,SAClB;AAEA,IAAa,iCAAiC;CAC5C,MAAM,EAAE,mBAAmB,kBAAkB,iBAC3C,6BAA6B;CAC/B,MAAM,EAAE,gBAAgB,cACtB,kBAAkB,OAClB,gCACF;CACA,MAAM,EAAE,SAAS,cAAc,aAAa,OAAO,2BAAyB;CAC5E,MAAM,EAAE,aAAa,cACnB,iBAAiB,OACjB,+BACF;CAEA,OAAO;EACL;EACA;EACA;CACF;AACF;;;ACjCA,IAAa,yBAAyB;CACpC,MAAM,EAAE,iBAAiB,6BAA6B;CACtD,MAAM,CAAC,eAAe,oBAAoB,SAAS,aAAa,aAAa;CAC7E,gBAEI,aAAa,MAAM,gBAAgB;EACjC,iBAAiB,aAAa,aAAa;CAC7C,CAAC,GACH,CAAC,YAAY,CACf;CACA,OAAO;AACT;;;ACTA,IAAM,8BAA8B,WAA+B,EACjE,mBAAmB,MAAM,kBAC3B;;;;;;;AAQA,IAAa,6BAAqC;CAChD,MAAM,EAAE,YAAY,uBAAuB;CAC3C,OACE,cAAc,QAAQ,cAAc,OAAO,0BAA0B,EAClE,qBAAqB;AAE5B;;;AClBA,IAAa,kBAAkB,UAAgC;CAC7D,MAAM,EAAE,UAAU;CAClB,MAAM,cAAc,OAA4B,KAAA,CAAS;CAEzD,gBAAgB;EACd,IAAI,SAAS,YAAY,SACvB,YAAY,QAAQ,MAAM;CAE9B,GAAG,CAAC,KAAK,CAAC;CAEV,OAAO,EACL,YACF;AACF;;;ACNA,IAAM,qBAAqB,oBAAqC;CAC9D,MAAM,oBAAoB,gBAAgB,aAAa,MAAM,eAAe;CAC5E,MAAM,yBAAyB,gBAAgB,kBAAkB,MAAM,eAAe;CACtF,MAAM,2BACJ,gBAAgB,oBAAoB,MAAM,eAAe;CAC3D,MAAM,oBAAoB,gBAAgB,aAAa,MAAM,eAAe;CAC5E,MAAM,yBAAyB,gBAAgB,kBAAkB,MAAM,eAAe;CACtF,MAAM,QAAQ,gBAAgB,MAAM,eAAe;CAEnD,aAAa;EACX,gBAAgB,MAAM,KAAK,KAAK;EAChC,gBAAgB,aAAa,MAAM,KAAK,iBAAiB;EACzD,gBAAgB,kBAAkB,MAAM,KAAK,sBAAsB;EACnE,gBAAgB,oBAAoB,MAAM,KAAK,wBAAwB;EACvE,gBAAgB,aAAa,MAAM,KAAK,iBAAiB;EACzD,gBAAgB,kBAAkB,MAAM,KAAK,sBAAsB;CACrE;AACF;AAEA,IAAa,oBAAoB,UAAgC;CAC/D,MAAM,EAAE,0BAA0B;CAElC,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EAAE,aAAa,gBAAgB,wBAAwB,kBAAkB;CAC/E,MAAM,EAAE,MAAM,sBAAsB,kBAAkB;CACtD,MAAM,kBAAkB,6BAA6B;CA+ErD,OAAO,EAAE,cA7EY,YACnB,OAAO,UAAqC;EAC1C,OAAO,eAAe;EACtB,MAAM,cAAc,MAAM,gBAAgB,QAAQ;EAClD,IAAI,CAAC,eAAe,CAAC,YAAY,SAAS;EAE1C,MAAM,EAAE,cAAc,SAAS,gBAAgB;EAE/C,IAAI,gBAAgB,iBAAiB,aAAa,SAAS,SACzD,IAAI;GACF,MAAM,YAAY,cAAc,WAAW;GAC3C,uBAAuB,eAAe;GACtC,gBAAgB,MAAM;EACxB,SAAS,KAAK;GACZ,gBAAgB;IACd,SAAS;IACT,UAAU;KACR,QAAQ;KACR,QAAQ;KACR,WAAW;IACb;IACA,SAAS,EAAE,6BAA6B;IACxC,UAAU;GACZ,CAAC;EACH;OACK;GACL,MAAM,+BAA+B,kBAAkB,eAAe;GACtE,IAAI;IAIF,IAAI,CADqB,CAAC,QAAQ,SAEhC,gBAAgB,MAAM,YAAY;KAChC,IAAI,kBAAgB,WAAW;KAC/B,QAAQ;IACV,CAAC;SAED,gBAAgB,MAAM;IAGxB,IAAI,uBACF,MAAM,sBAAsB;KAC1B,KAAK,gBAAgB,QAAQ;KAC7B;KACA;KACA;IACF,CAAC;SAED,MAAM,YAAY;KAAE;KAAc;KAAS,SAAS;IAAY,CAAC;IAEnE,IAAI,gBAAgB,OAAO,KAAK,qBAC9B,MAAM,gBAAgB,QAAQ,WAAW;GAC7C,SAAS,KAAK;IACZ,6BAA6B;IAC7B,gBAAgB;KACd,SAAS;KACT,UAAU;MACR,QAAQ;MACR,QAAQ;MACR,WAAW;KACb;KACA,SAAS,EAAE,6BAA6B;KACxC,UAAU;IACZ,CAAC;GACH;EACF;CACF,GACA;EACE;EACA;EACA;EACA;EACA;EACA;CACF,CAGO,EAAa;AACxB;;;ACrGA,IAAM,0CAAwC,WAAkC;CAC9E,eAAe,MAAM,YAAY;CACjC,4BAA4B,MAAM,YAAY;AAChD;AAOA,IAAa,YAAY,WAAW,SAAS,UAC3C,EAAE,cAAc,gBAAgB,MAAM,GAAG,QACzC,KACA;CAGA,OAAO,oBAAC,SAAD;EAAO,UAFY,2BAA2B,eAAe,YAE5C;EAAwB;EAAK,MAAK;EAAO,GAAI;CAAO,CAAA;AAC9E,CAAC;AAED,IAAa,kBAAkB,WAAW,SAAS,gBACjD,EACE,WACA,cAAc,oBACd,GAAG,SAEL,KACA;CACA,MAAM,EAAE,MAAM,sBAAsB,iBAAiB;CACrD,MAAM,EAAE,gBAAgB,0BAA0B;CAClD,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,sBAAsB;CAC9B,MAAM,EAAE,oBAAoB,0BAA0B;CACtD,MAAM,EAAE,eAAe,+BAA+B,cACpD,gBAAgB,aAChB,sCACF;CACA,MAAM,mBAAmB,oBAAoB;CAC7C,MAAM,KAAK,cAAc,OAAO,GAAG,CAAC,CAAC;CAErC,MAAM,eAAe,aAClB,UAAuB;EACtB,kBAAkB,YAAY,KAAK;EACnC,YAAY,SAAS,MAAM;EAC3B,qBAAqB,KAAK;CAC5B,GACA;EAAC;EAAoB;EAAmB;CAAW,CACrD;CAEA,OACE,oBAAC,WAAD;EACE,QAAQ,eAAe,KAAK,GAAG;EAC/B,cAAY,EAAE,kBAAkB;EAChC,eAAY;EACZ,UAAU,CAAC,mBAAmB;EAC1B;EACJ,UAAU,6BAA6B;EACvC,GAAI;EACJ,WAAW,KAAK,wBAAwB,SAAS;EACnC;EACT;CACN,CAAA;AAEL,CAAC;;;ACxED,IAAa,wBAAwB;CACnC,MAAM,EAAE,mBAAmB,iBAAiB,6BAA6B;CAmCzE,OAAO,EAAE,SAlCO,aACb,mBAA8D;EAC7D,CAAC,OAAO,UAAU;GAChB,MAAM,EAAE,UAAU,MAAM;GACxB,MAAM,eAAe;GAIrB,IAAI,mBAAgD,KAAA;GACpD,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;IACrC,MAAM,OAAO,MAAM;IACnB,IAAI,KAAK,SAAS,YAAY,KAAK,SAAS,cAAc;KACxD,mBAAmB,IAAI,SAAS,YAAY;MAC1C,KAAK,aAAa,WAAW;OAC3B,QAAQ,MAAM;MAChB,CAAC;KACH,CAAC;KACD;IACF;GACF;GAEA,MAAM,YAAY,MAAM,yBAAyB,MAAM,KAAK,KAAK,CAAC;GAElE,IAAI,kBAAkB;IACpB,MAAM,aAAa,MAAM;IACzB,aAAa,WAAW,EAAE,MAAM,WAAW,CAAC;GAC9C,OACE,kBAAkB,YAAY,SAAS;EAE3C,GAAG,cAAc;CACnB,GACA,CAAC,mBAAmB,YAAY,CAGzB,EAAQ;AACnB;;;ACnCA,IAAa,eAAb,MAAsD;CAIpD,YAAY,aAA0B;gBAH7B;EAIP,KAAK,eAAe;CACtB;CAEA,cAAc;EACZ,KAAK,SAAS;EACd,KAAK,eAAe;CACtB;AACF;;;ACVA,SAAgB,eAAkB,gBAAgD;CAChF,OAAO,OAAO,mBAAmB,aAAa,EAAE,MAAM,eAAe,IAAI;AAC3E;;;ACIA,IAAa,aAAb,MAAsD;CAIpD,YAAY,UAAwB;iBAHhB;EAIlB,IAAI,UAAU,KAAK,YAAY;CACjC;CAEA,IAAI,SAAS;EACX,OAAO,KAAK;CACd;CAEA,UAAU,gBAAiD;EACzD,MAAM,WAAW,eAAkB,cAAc;EACjD,IAAI,CAAC,KAAK,QACR,KAAK,YAAY,QAAQ;EAE3B,OAAO,IAAI,mBAAmB;GAC5B,KAAK,UAAU;EACjB,CAAC;CACH;AACF;;;AC7BA,IAAa,UAAb,cAAgC,WAA0C;CAKxE,cAAc;EACZ,MAAM;oCALuC,IAAI,IAAI;0BAC5B;CAK3B;CAEA,IAAI,YAAY;EACd,OAAO,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC;CAC5C;CAEA,KAAK,OAAU;EACb,IAAI,KAAK,QAAQ;EACjB,MAAM,YAAY,KAAK;EACvB,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,UAAU,GAAG,KAAK,KAAK;CAE3B;CAEA,MAAM,KAAY;EAChB,IAAI,KAAK,QAAQ;EACjB,KAAK,cAAc;EACnB,MAAM,EAAE,cAAc;EACtB,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,UAAU,GAAG,QAAQ,GAAG;EAE1B,KAAK,WAAW,MAAM;CACxB;CAEA,WAAW;EACT,IAAI,KAAK,QAAQ;EACjB,KAAK,UAAU;EACf,MAAM,EAAE,cAAc;EACtB,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,UAAU,GAAG,WAAW;EAE1B,KAAK,WAAW,MAAM;CACxB;CAEA,UAAU,gBAAiD;EACzD,MAAM,WAAW,eAAkB,cAAc;EACjD,IAAI,KAAK,eAAe,KAAK,QAAQ;GACnC,MAAM,eAAe,IAAI,aAAa;GACtC,aAAa,SAAS;GACtB,OAAO;EACT;EAEA,MAAM,aAAa,KAAK;EACxB,KAAK,WAAW,IAAI,YAAY,QAAQ;EACxC,OAAO,IAAI,mBAAmB;GAC5B,KAAK,WAAW,OAAO,UAAU;EACnC,CAAC;CACH;CAEA,cAAoB;EAClB,KAAK,UAAU;EACf,KAAK,WAAW,MAAM;CACxB;AACF;;;AC7DA,IAAa,kBAAb,cAAwC,QAAW;CACjD,YAAY,QAAmB;EAC7B,MAAM;EADY,KAAA,SAAA;CAEpB;CAEA,IAAI,QAAW;EACb,MAAM,EAAE,QAAQ,gBAAgB;EAChC,IAAI,aACF,MAAM;EAER,OAAO;CACT;CAEA,UAAU,gBAAiD;EACzD,MAAM,WAAW,eAAkB,cAAc;EACjD,MAAM,eAAe,MAAM,UAAU,cAAc;EACnD,IAAI,CAAC,aAAa,QAAQ,SAAS,KAAK,KAAK,MAAM;EACnD,OAAO;CACT;CAEA,KAAK,OAAgB;EACnB,MAAM,KAAM,KAAK,SAAS,KAAM;CAClC;AACF;;;ACtBA,IAAY,sBAAL,yBAAA,qBAAA;CACL,oBAAA,SAAA;CACA,oBAAA,SAAA;;AACF,EAAA,CAAA,CAAA;AAEA,IAAM,sBAAsE;CAC1E,OAAA;CACA,OAAA;AACF;AAMA,IAAa,oBAAb,MAA+B;CAQ7B,YAAY,EAAE,aAAuC;eAN7C,IAAI,gBAA6C,KAAA,CAAS;gBACzD,IAAI,gBAA8C,KAAA,CAAS;eAC5D,IAAI,QAA2B;6BAEO,CAAC;EAG7C,KAAK,OAAO,oBAAoB;CAClC;CAEA,IAAI,aAAa;EACf,OAAO,KAAK,oBAAoB,MAAM,iBAAiB,CAAC,aAAa,MAAM;CAC7E;CAEA,MAAM,QAAQ;EACZ,IAAI,CAAC,KAAK,OAAO,OAAO;GACtB,MAAM,KAAK,MAAM;GACjB,IAAI,CAAC,KAAK,OAAO,OAAO;EAC1B;EAEA,MAAM,SAAS,KAAK,OAAO;EAC3B,MAAM,0BAA0B,MAAa;GAC3C,MAAM,EAAE,UAAW,EAA+C;GAClE,KAAK,MAAM,KAAK,KAAK;EACvB;EACA,OAAO,iBAAiB,UAAU,sBAAsB;EAExD,KAAK,oBAAoB,KACvB,IAAI,mBAAmB;GACrB,OAAO,oBAAoB,UAAU,sBAAsB;EAC7D,CAAC,CACH;CACF;CAEA,UAAU;EACR,KAAK,oBAAoB,SAAS,iBAAiB,aAAa,YAAY,CAAC;CAC/E;CAEA,MAAM,QAAQ;EACZ,IAAI,CAAC,KAAK,MAAM;GACd,KAAK,MAAM,qBAAK,IAAI,MAAM,oCAAoC,CAAC;GAC/D;EACF;EAEA,IAAI;EACJ,IAAI;GACF,MAAM,mBAAmB,MAAM,UAAU,YAAY,MAAM,EACzD,MAAM,KAAK,KACb,CAAC;GACD,kBAAkB,iBAAiB;GACnC,KAAK,OAAO,KAAK,gBAAgB;EACnC,SAAS,GAAG;GAGV,kBAAkB;EACpB;EACA,KAAK,MAAM,KAAK,eAAe;CACjC;AACF;;;ACzEA,IAAM,yBAAyB,QAAiB,WAAoB,UAAU;AAE9E,IAAa,sBAAwC,QAAiB,WACpE,UAA4B,QAAQ,QAAQ,qBAAqB;;;ACNnE,IAAM,0BAA0B;AAEhC,IAAM,cAAY,MAAc,KAAK,QAAQ,MAAM,8BAA8B,CAAC;AAElF,IAAM,kBAAkB,WACtB,KAAK,KAAK,OAAO,QAAQ,KAAK,QAAQ,MAAM,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM;AA+BlF,IAAa,oCAA6D;CACxE,gBAAgB;EACd,SAAS;EACT,aAAa;EACb,aAAa;CACf;CACA,aAAa;CACb,qBAAqB;AACvB;AAaA,IAAa,oBAAb,MAA+B;CAc7B,YAAY,EAAE,QAAQ,UAAoC;oBAJ7C,IAAI,gBAA0B,CAAC,CAAC;eACrC,IAAI,gBAAoD,KAAA,CAAS;eACjE,IAAI,QAA2B;qBAyBzB;GACZ,IAAI,KAAK,MAAM,UAAA,UAAyC;GACxD,IAAI,CAAC,KAAK,QACR,MAAM,IAAI,MACR,mEACF;GAGF,IAAI,KAAK,MAAM,UAAA,aAA4C,KAAK,KAAK;GAErE,IAAI,CAAC,KAAK,cAAc;IACtB,IAAI,CAAC,KAAK,QAAQ;IAClB,KAAK,KAAK;GACZ;GAEA,KAAK,MAAM,KAAA,WAAqC;GAEhD,KAAK,4BAA4B,kBAAkB;IACjD,IAAI,EAAE,KAAK,gBAAgB,KAAK,MAAM,UAAA,cACpC;IACF,MAAM,gBAAgB,IAAI,WAAW,KAAK,aAAa,iBAAiB;IACxE,IAAI;KACF,KAAK,aAAa,qBAAqB,aAAa;IACtD,SAAS,GAAG;KACV,WAAS,CAAU;KACnB,KAAK,MAAM,KAAK,CAAU;KAC1B;IACF;IACA,MAAM,2BACJ,eAAe,aAAa,IAAI;IAClC,KAAK,WAAW,KAAK,CAAC,GAAG,KAAK,WAAW,OAAO,wBAAwB,CAAC;GAC3E,GAAG,KAAK,OAAO,mBAAmB;EACpC;EAtDE,KAAK,SAAS,mBAAmB,EAAE,GAAG,OAAO,GAAG,iCAAiC;EACjF,KAAK,SAAS;CAChB;CAEA,OAAO;EACL,KAAK,eAAe,IAAI,aAAa;EACrC,KAAK,eAAe,KAAK,aAAa,eAAe;EACrD,MAAM,EAAE,mBAAmB,KAAK;EAChC,KAAK,aAAa,UAAU,eAAe;EAC3C,KAAK,aAAa,cAAc,eAAe;EAC/C,KAAK,aAAa,cAAc,eAAe;EAE/C,KAAK,aAAa,KAAK,aAAa,wBAAwB,KAAK,MAAM;EACvE,KAAK,WAAW,QAAQ,KAAK,YAAY;CAC3C;CAEA,OAAO;EACL,cAAc,KAAK,yBAAyB;EAC5C,KAAK,4BAA4B,KAAA;EACjC,KAAK,MAAM,KAAA,SAAmC;CAChD;CAoCA,QAAQ;EACN,IAAI,KAAK,MAAM,UAAA,WAA0C,KAAK,KAAK;EACnE,KAAK,MAAM,KAAA,QAAkC;EAC7C,KAAK,WAAW,KAAK,CAAC,CAAC;EACvB,KAAK,YAAY,WAAW;EAC5B,KAAK,cAAc,WAAW;EAC9B,IAAI,KAAK,cAAc,UAAU,UAAU,KAAK,cAAc,MAAM;CACtE;AACF;;;AC1IA,IAAM,0BAA0B;AAChC,IAAM,mBAAmB;AACzB,IAAM,sBAAsB;AAE5B,IAAM,SAAS;CACb,cAAc;EAAE,QAAQ;EAAI,OAAO;CAAE;CACrC,iBAAiB;EAAE,QAAQ;EAAI,OAAO,mBAAmB;CAAE;CAC3D,aAAa,EAAE,QAAQ,GAAG;CAC1B,WAAW,EAAE,QAAQ,GAAG;CACxB,eAAe,EAAE,QAAQ,GAAG;CAC5B,UAAU;EAAE,QAAQ;EAAG,OAAO;CAAW;CACzC,YAAY,EAAE,QAAQ,EAAE;CACxB,aAAa;EAAE,QAAQ;EAAG,OAAO;CAAW;CAC5C,aAAa,EAAE,QAAQ,GAAG;CAC1B,cAAc;EAAE,QAAQ;EAAI,OAAO;CAAW;CAC9C,gBAAgB;EAAE,QAAQ;EAAI,OAAO;CAAG;CACxC,cAAc;EAAE,QAAQ;EAAI,OAAO;CAAW;CAC9C,gBAAgB,EAAE,QAAQ,GAAG;AAC/B;AAEA,IAAM,kBAAkB,UACrB,MAAM,WAAW,CAAC,KAAK,KACvB,MAAM,WAAW,CAAC,KAAK,KACvB,MAAM,WAAW,CAAC,KAAK,IACxB,MAAM,WAAW,CAAC;AAGZ,eAAe,MAAM,GACtB,eAAe,MAAM,GACpB,eAAe,MAAM,GACrB,eAAe,MAAM;AAU7B,IAAM,kBAAkB,EACtB,aACA,cACA,iBAC2B;CAC3B,MAAM,WAAW,aAAa,eAAe;CAC7C,MAAM,aAAa,eAAe;CAElC,MAAM,WAAW,IAAI,SAAS,WAAW;CAKzC,MAAM,gBAAgB,KAAK,IACzB,SAAS,aAAa,yBACtB,sBAAsB,uBACxB;CAEA,SAAS,UAAU,OAAO,SAAS,QAAQ,OAAO,SAAS,KAAK;CAChE,SAAS,UAAU,OAAO,WAAW,QAAQ,YAAY,aAAa,GAAG,IAAI;CAC7E,SAAS,UAAU,OAAO,YAAY,QAAQ,OAAO,YAAY,KAAK;CAEtE,SAAS,UAAU,OAAO,aAAa,QAAQ,OAAO,aAAa,KAAK;CACxE,SAAS,UAAU,OAAO,eAAe,QAAQ,OAAO,eAAe,OAAO,IAAI;CAClF,SAAS,UAAU,OAAO,aAAa,QAAQ,OAAO,aAAa,OAAO,IAAI;CAC9E,SAAS,UAAU,OAAO,cAAc,QAAQ,cAAc,IAAI;CAClE,SAAS,UAAU,OAAO,YAAY,QAAQ,YAAY,IAAI;CAC9D,SAAS,UAAU,OAAO,UAAU,QAAQ,UAAU,IAAI;CAC1D,SAAS,UAAU,OAAO,YAAY,QAAQ,YAAY,IAAI;CAC9D,SAAS,UAAU,OAAO,gBAAgB,QAAQ,OAAO,gBAAgB,OAAO,IAAI;CAEpF,SAAS,UAAU,OAAO,aAAa,QAAQ,OAAO,aAAa,KAAK;CACxE,SAAS,UAAU,OAAO,eAAe,QAAQ,eAAe,IAAI;AACtE;AAyBA,IAAM,sBAAsB,gBAC1B,MAAM,KAAK,EAAE,QAAQ,YAAY,iBAAiB,IAAI,GAAG,MACvD,YAAY,eAAe,CAAC,CAC9B;;;;;;;AAaF,IAAM,qBAAqB,EAAE,aAAa,oBAA0C;CAClF,MAAM,WAAW,IAAI,SAAS,WAAW;CACzC,MAAM,eAAe,cAAc;CAEnC,cAAc,SAAS,aAAa,iBAAiB;EACnD,IAAI,cAAc,0BAA0B,eAAe;EAE3D,YAAY,SAAS,iBAAiB;GACpC,SAAS,SACP,aACA,eAAe,IACX,KAAK,IAAI,IAAI,YAAY,IAAI,QAC7B,KAAK,IAAI,GAAG,YAAY,IAAI,OAChC,IACF;GACA,eAAe,eAAe;EAChC,CAAC;CACH,CAAC;AACH;AAEA,IAAa,cAAc,OAAO,MAAY,eAAuB;CACnE,MAAM,cAAc,MAAM,YAAY,MAAM,cAAc,IAAI,GAAG,UAAU;CAE3E,MAAM,gBADkB,YAAY,WAAW,aAE3B,YAAY,mBAAmB,mBACjD;CAEF,MAAM,cAAc,IAAI,YAAY,aAAa;CACjD,eAAe;EAAE;EAAa,cAAc,YAAY;EAAkB;CAAW,CAAC;CACtF,kBAAkB;EAAE;EAAa,eAAe,mBAAmB,WAAW;CAAE,CAAC;CACjF,OAAO,IAAI,KAAK,CAAC,WAAW,GAAG,EAAE,MAAM,YAAY,CAAC;AACtD;;;ACrIA,IAAa,aAAa,EACxB,MACA,UAAU,aACV,iBAEA,QACE,oBAAoB;CAClB,YAAY,CAAC,IAAI;CACjB,UAAU,oCAAmB,IAAI,KAAK,GAAE,YAAY,EAAE,GAAG,yBACvD,KAAK,IACP;CACA,UAAU,KAAK;AACjB,CAAC,GACD,UACF;;;ACLF,IAAa,gCAAgC,EAC3C,OAAO;CACL,QAAQ;CACR,QAAQ;AACV,EACF;AAEA,IAAa,kCAAoD,EAC/D,YAAY,KACd;AAEA,IAAM,wBAAwB,WAAyB;CACrD,IAAI,CAAC,QAAQ,QAAQ;CACrB,OAAO,UAAU,EAAE,SAAS,UAAU;EACpC,MAAM,KAAK;EACX,OAAO,YAAY,KAAK;CAC1B,CAAC;AACH;AAEA,IAAM,YAAY,MAAc,KAAK,QAAQ,MAAM,0BAA0B,CAAC;AAqB9E,IAAY,sBAAL,yBAAA,qBAAA;CACL,oBAAA,YAAA;CACA,oBAAA,eAAA;CACA,oBAAA,aAAA;;AACF,EAAA,CAAA,CAAA;AAEA,IAAY,0BAAL,yBAAA,yBAAA;CACL,wBAAA,qBAAA;;AACF,EAAA,CAAA,CAAA;AAEA,IAAa,0BAAb,MAAqC;CAyBnC,YAAY,EAAE,QAAQ,wBAAwB,MAA4B,CAAC,GAAG;gCAf3C,CAAC;sBACb,CAAC;wBAMP,IAAI,gBAAiD,KAAA,CAAS;mBACnE,IAAI,gBAA2D,KAAA,CAAS;eAC5E,IAAI,QAA2B;sBACxB,IAAI,QAAiE;iCA4C1D,aAAqB;GAC7C,IAAI,KAAK,8BACP,OAAO,KAAK,6BAA6B,QAAQ;GAEnD,OAAO,GAAG,KAAK,UAAU,8BAAa,IAAI,KAAK,GAAE,YAAY,EAAE,GAAG,yBAChE,QACF;EACF;4BAEqB,YAAY;GAC/B,IAAI,KAAK,cAAc,IAAI,gBAAgB,KAAK,YAAY;GAE5D,IAAI,CAAC,KAAK,aAAa,QAAQ;GAC/B,MAAM,EAAE,aAAa,KAAK;GAC1B,IAAI,OAAO,IAAI,KAAK,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;GACzD,IAAI,SAAS,MAAM,YAAY,GAE7B,OAAO,MAAM,gBAAgB,MAAM,KAAK,YAAY,EAClD,cAAc,KAChB,CAAC;GAEH,IAAI,CAAC,SAAS,MAAM,WAAW,GAC7B,OAAO,MAAM,UAAU;IACrB;IACA,GAAG,KAAK;GACV,CAAC;GAGH,IAAI,CAAC,MAAM;GAEX,KAAK,eAAe,IAAI,gBAAgB,IAAI;GAC5C,MAAM,OAAO,oBAAoB;IAC/B,YAAY,CAAC,IAAI;IACjB,UAAU,KAAK,uBAAuB,KAAK,IAAI;IAC/C,UAAU,KAAK;GACjB,CAAC;GAED,OAAO;IACL,WAAW,KAAK;IAChB,UAAU,KAAK,aAAa;IAC5B,WAAW,KAAK;IAChB,eAAe;KACb;KACA,IAAI,OAAO;IACb;IACA,WAAW,KAAK;IAChB,OAAO,KAAK;IACZ,MAAA;IACA,eAAe,qBACb,KAAK,mBAAmB,WAAW,SAAS,CAAC,GAC7C,KAAK,wBAAwB,WAC/B;GACF;EACF;2BAEoB,MAAa;GAC/B,MAAM,EAAE,UAAU;GAClB,SAAS,KAAK;GACd,KAAK,MAAM,KAAK,KAAK;GACrB,KAAK,aAAa,KAAK;IACrB,MAAM,KAAK,EAAE,wCAAwC;IACrD,MAAM;GACR,CAAC;EACH;kCAE2B,OAAO,MAAiB;GACjD,IAAI,CAAC,EAAE,KAAK,MAAM;GAClB,IAAI,KAAK,cAAc,SAAS;GAChC,IAAI;IACF,KAAK,aAAa,KAAK,EAAE,IAAI;IAC7B,MAAM,YAAY,MAAM,KAAK,mBAAmB;IAChD,IAAI,CAAC,WAAW;IAChB,KAAK,uBAAuB,SAAS;IACrC,KAAK,UAAU,KAAK,SAAS;GAC/B,SAAS,GAAG;IACV,SAAS,CAAU;IACnB,KAAK,MAAM,KAAK,CAAU;IAC1B,KAAK,aAAa,KAAK;KACrB,MAAM,KAAK,EAAE,uDAAuD;KACpE,MAAM;IACR,CAAC;GACH;EACF;mCAE4B;GAC1B,KAAK,eAAe,CAAC;GACrB,KAAK,UAAU,KAAK,KAAA,CAAS;GAC7B,KAAK,eAAe,KAAK,KAAA,CAAS;GAClC,KAAK,yBAAyB,CAAC;GAC/B,KAAK,YAAY,KAAA;EACnB;uBAEgB;GACd,KAAK,oBAAoB;GACzB,IAAI,KAAK,cAAc,IAAI,gBAAgB,KAAK,YAAY;GAC5D,KAAK,mBAAmB,MAAM;GAC9B,IAAI,KAAK,eAAe;IACtB,qBAAqB,KAAK,cAAc,MAAM;IAC9C,KAAK,cAAc,oBACjB,iBACA,KAAK,wBACP;IACA,KAAK,cAAc,oBAAoB,SAAS,KAAK,gBAAgB;GACvE;EACF;eAEQ,YAAY;GAClB,IACE,CAAA,aAAA,QAA0D,EAAE,SAC1D,KAAK,eAAe,KACtB,GACA;IACA,MAAM,wBAAQ,IAAI,MAAM,uDAAuD;IAC/E,SAAS,KAAK;IACd,KAAK,MAAM,KAAK,KAAK;IACrB;GACF;GAGA,IAAI,CAAC,UAAU,cAAc;IAC3B,MAAM,wBAAQ,IAAI,MAAM,kCAAkC;IAC1D,SAAS,KAAK;IACd,KAAK,MAAM,KAAK,KAAK;IACrB,KAAK,aAAa,KAAK;KAAE,MAAM,KAAK,EAAE,0BAA0B;KAAG,MAAM;IAAQ,CAAC;IAClF;GACF;GAEA,IAAI,KAAK,cAAc,SAAS;IAC9B,MAAM,wBAAQ,IAAI,MAChB,yDAAyD,KAAK,oBAAoB,UACpF;IACA,SAAS,KAAK;IACd,KAAK,MAAM,KAAK,KAAK;IACrB,KAAK,aAAa,KAAK;KAAE,MAAM,KAAK,EAAE,0BAA0B;KAAG,MAAM;IAAQ,CAAC;IAClF;GACF;GAEA,IAAI,CAAC,KAAK,WAAW,MAAM,OACzB,MAAM,KAAK,WAAW,MAAM;GAG9B,IAAI,KAAK,WAAW,MAAM,UAAU,UAAU;IAC5C,yBAAS,IAAI,MAAM,mBAAmB,CAAC;IACvC;GACF;GAEA,IAAI;IACF,MAAM,SAAS,MAAM,UAAU,aAAa,aAAa,EAAE,OAAO,KAAK,CAAC;IACxE,KAAK,gBAAgB,IAAI,cAAc,QAAQ,KAAK,mBAAmB;IAEvE,KAAK,cAAc,iBAAiB,iBAAiB,KAAK,wBAAwB;IAClF,KAAK,cAAc,iBAAiB,SAAS,KAAK,gBAAgB;IAElE,KAAK,6BAAY,IAAI,KAAK,GAAE,QAAQ;IACpC,KAAK,cAAc,MAAM;IAEzB,IAAI,KAAK,cAAc,WAAW,QAAQ;KACxC,KAAK,oBAAoB,IAAI,kBAAkB;MAC7C,QAAQ,KAAK;MACb;KACF,CAAC;KACD,KAAK,kBAAkB,MAAM;IAC/B;IAEA,KAAK,eAAe,KAAA,WAAkC;GACxD,SAAS,OAAO;IACd,SAAS,KAAc;IACvB,KAAK,OAAO;IACZ,KAAK,MAAM,KAAK,KAAc;IAC9B,KAAK,aAAa,KAAK;KAAE,MAAM,KAAK,EAAE,0BAA0B;KAAG,MAAM;IAAQ,CAAC;GACpF;EACF;qBAEc;GACZ,IAAI,KAAK,eAAe,UAAA,aAAyC;GACjE,IAAI,KAAK,WAAW;IAClB,KAAK,uBAAuB,sBAAK,IAAI,KAAK,GAAE,QAAQ,IAAI,KAAK,SAAS;IACtE,KAAK,YAAY,KAAA;GACnB;GACA,KAAK,eAAe,MAAM;GAE1B,KAAK,eAAe,YAAY;GAChC,KAAK,mBAAmB,KAAK;GAC7B,KAAK,eAAe,KAAA,QAA+B;EACrD;sBAEe;GACb,IAAI,KAAK,eAAe,UAAA,UAAsC;GAC9D,KAAK,6BAAY,IAAI,KAAK,GAAE,QAAQ;GACpC,KAAK,eAAe,OAAO;GAC3B,KAAK,mBAAmB,MAAM;GAC9B,KAAK,eAAe,KAAA,WAAkC;EACxD;oBAEa;GACX,MAAM,YAAY,KAAK,UAAU;GACjC,IAAI,aAAa,KAAK,eAAe,UAAU,YAC7C,OAAO,QAAQ,QAAQ,SAAS;GAElC,IACE,CAAC,CAAA,UAAA,WAA0D,EAAE,SAC1D,KAAK,eAAe,SAAS,EAChC,GAEA,OAAO,QAAQ,QAAQ,KAAA,CAAS;GAElC,IAAI,KAAK,WAAW;IAClB,KAAK,uBAAuB,sBAAK,IAAI,KAAK,GAAE,QAAQ,IAAI,KAAK,SAAS;IACtE,KAAK,YAAY,KAAA;GACnB;GACA,MAAM,SAAS,IAAI,SAAwC,QAAQ;IACjE,KAAK,uBAAuB;GAC9B,CAAC;GACD,KAAK,eAAe,KAAK;GACzB,KAAK,mBAAmB,KAAK;GAC7B,KAAK,eAAe,KAAA,SAAgC;GACpD,OAAO;EACT;sBAEe;GACb,KAAK,KAAK;GACV,KAAK,QAAQ;EACf;EApQE,KAAK,IAAI,KAAK;EAEd,KAAK,0BAA0B,mBAC7B,EAAE,GAAG,QAAQ,wBAAwB,GACrC,iCACF;EAEA,KAAK,sBAAsB,mBACzB,EAAE,GAAG,QAAQ,oBAAoB,GACjC,EACE,UAAU,cAAc,gBAAgB,YAAY,IAChD,8BAA8B,MAAM,SACpC,8BAA8B,MAAM,OAC1C,CACF;EAEA,KAAK,mBAAmB,mBACtB,EAAE,GAAG,QAAQ,iBAAiB,GAC9B,+BACF;EAEA,MAAM,YAAY,iCAAiC,KAAK,oBAAoB,QAAQ;EACpF,IAAI,CAAC,WACH,MAAM,IAAI,MACR,8EAA8E,KAAK,oBAAoB,UACzG;EAEF,KAAK,YAAY;EAEjB,KAAK,aAAa,IAAI,kBAAkB,EAAE,UAAU,CAAC;EAErD,KAAK,+BAA+B;CACtC;CAEA,IAAI,aAAa;EACf,OAAO,KAAK,uBAAuB,QAAQ,KAAK,QAAQ,MAAM,KAAK,CAAC;CACtE;AAiOF;;;AC9UA,IAAa,oBAAoB,EAC/B,+BACA,SACA,wBACA,cACA,sBACiD;CACjD,MAAM,EAAE,MAAM,sBAAsB,kBAAkB;CACtD,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,CAAC,WAAW,gBAAgB,SAAwC;CAC1E,MAAM,CAAC,gBAAgB,qBAAqB,SAA8B;CAC1E,MAAM,CAAC,iBAAiB,sBAAsB,SAA0B;CACxE,MAAM,CAAC,sBAAsB,qBAAqB,SAAS,KAAK;CAEhE,MAAM,WAAW,cAEb,UACI,IAAI,wBAAwB;EAC1B,QAAQ,mBAAmB,CAAC;EAC5B;EACA;CACF,CAAC,IACD,KAAA,GACN;EAAC;EAAiB;EAAS;EAAwB;CAAC,CACtD;CAEA,MAAM,oBAAoB,YAAY,YAAY;EAChD,IAAI,CAAC,UAAU;EACf,MAAM,YAAY,MAAM,SAAS,KAAK;EACtC,IAAI,CAAC,WAAW;EAChB,MAAM,gBAAgB,kBAAkB,iBAAiB,SAAS;EAClE,IAAI,CAAC,+BAEH,kBAAkB,IAAI;EAExB,SAAS,QAAQ;CACnB,GAAG;EAAC;EAA+B;EAAiB;CAAQ,CAAC;CAE7D,gBAAgB;EACd,IAAI,CAAC,sBAAsB;EAC3B,aAAa;EACb,kBAAkB,KAAK;CACzB,GAAG,CAAC,cAAc,oBAAoB,CAAC;CAEvC,gBAAgB;EACd,IAAI,CAAC,UAAU;EACf,SAAS,WAAW,MAAM;EAC1B,MAAM,wBAAwB,SAAS,UAAU,UAAU,YAAY;EACvE,MAAM,6BACJ,SAAS,eAAe,UAAU,iBAAiB;EACrD,MAAM,8BACJ,SAAS,WAAW,MAAM,UAAU,kBAAkB;EAExD,aAAa;GACX,SAAS,OAAO;GAChB,SAAS,WAAW,QAAQ;GAC5B,sBAAsB,YAAY;GAClC,2BAA2B,YAAY;GACvC,4BAA4B,YAAY;EAC1C;CACF,GAAG,CAAC,QAAQ,CAAC;CAEb,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;AChFA,IAAa,8BACX,UACqC;CACrC,MAAM,EAAE,+BAA+B,sBAAsB,0BAC3D;CAEF,MAAM,EAAE,gBAAgB,eAAe,KAAK;CAE5C,MAAM,EAAE,iBAAiB,iBAAiB,KAAK;CAE/C,MAAM,sBAAsB,iBAAiB;EAC3C;EACA,SAAS,CAAC,CAAC;EACX;EACA,iBAAiB;CACnB,CAAC;CAED,MAAM,EAAE,YAAY,gBAAgB;CAEpC,OAAO;EACL;EACA;EACA;EACA;CACF;AACF;;;AClCA,IAAM,kCAAgC,EACpC,eACA,qBAC2B;CAC3B;CACA;AACF;AAOA,IAAa,mCAAmC;CAC9C,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,gBAAgB,gBAAgB,QAAQ,UAAU;CACxD,MAAM,EAAE,eAAe,kBAAkB,cACvC,gBAAgB,OAChB,8BACF;CAEA,OAAO,eAEF,eAAe,YAAY,CAAC,GAC1B,QACE,YAA2D,CAAC,CAAC,QAAQ,IACxE,EACC,KAAK,aAAa;EACjB;EACA,SAAS,CAAC,gBAAgB,kBAAkB,OAAO;CACrD,EAAE,GAGN;EAAC;EAAe;EAAe;EAAiB;CAAa,CAC/D;AACF;;;ACrCA,IAAM,oCAAkC,UAA6B;AAErE,IAAa,0CAA0C;CACrD,MAAM,kBAAkB,6BAA6B;CACrD,cAAc,gBAAgB,mBAAmB,gCAA8B;CAC/E,OAAO,gBAAgB;AACzB;;;ACNA,IAAM,kCAAkC,UAA6B;AAErE,IAAa,iCAAiC;CAC5C,MAAM,kBAAkB,6BAA6B;CACrD,cAAc,gBAAgB,mBAAmB,8BAA8B;CAC/E,OAAO,gBAAgB;AACzB;;;ACHA,IAAa,iCAAiC,EAC5C,WACA,aACA,GAAG,YAGC;CACJ,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,QAAD;EACE,cAAY,EAAE,wBAAwB;EACtC,UAAA;EACA,WAAW,KAAK,+CAA+C,SAAS;EACxE,eAAY;EACZ,UAAU,gBAAgB;EAC1B,GAAI;YAEJ,oBAAC,gBAAD,CAAiB,CAAA;CACX,CAAA;AAEZ;;;ACxBA,IAAa,0BAA0B,EAAE,mBACvC,oBAAC,OAAD,EACE,WAAW,KAAK,sCAAsC,EACpD,mDAAmD,aACrD,CAAC,EACF,CAAA;;;AC2CH,IAAM,qCAAqC,WAAiC,EAC1E,eAAe,MAAM,cACvB;AAOA,IAAM,2BAA2B;AAEjC,IAAM,6BAA6B;;AAKnC,IAAM,2BAA2B,eAA2B,kBAAkB,UAAU;AAExF,IAAM,qBAAqB,eAA2B;CACpD,IAAI,wBAAwB,UAAU,GACpC,OAAO;CAET,IAAI,iBAAiB,UAAU,GAC7B,OAAO;MACF,IAAI,kBAAkB,YAAY,uBAAuB,GAC9D,OAAO;MACF,IAAI,kBAAkB,UAAU,GACrC,OAAO;MACF,IAAI,kBAAkB,UAAU,GACrC,OAAO;MACF,IAAI,2BAA2B,UAAU,GAC9C,OAAO;MACF,IAAI,iBAAiB,YAAY,uBAAuB,GAC7D,OAAO;CAGT,OAAO;AACT;AASA,IAAM,yBAAyB,kBAAuC;CACpE,MAAM,qBAAqB;EACzB,WAAW,CAAC;EACZ,SAAS,CAAC;EACV,QAAQ,CAAC;EACT,OAAO,CAAC;EACR,WAAW,CAAC;EACZ,OAAO,CAAC;EACR,OAAO;EACP,QAAQ,CAAC;EACT,iBAAiB,CAAC;CACpB;CAEA,IAAI,CAAC,iBAAiB,CAAC,cAAc,aAAa,OAAO;CAEzD,MAAM,SAAS,cAAc,YAAY,QACtC,OAAO,eAAe;EACrB,QAAQ,kBAAkB,UAAU,GAApC;GACE,KAAK;IACH,MAAM,QAAQ,KAAK,UAAU;IAC7B,MAAM,SAAS;IACf;GACF,KAAK;IACH,MAAM,MAAM,KAAK,UAAU;IAC3B,MAAM,SAAS;IACf;GACF,KAAK;IACH,MAAM,OAAO,KAAK,UAAU;IAC5B,MAAM,SAAS;IACf;GACF,KAAK;IACH,MAAM,gBAAgB,KAAK,UAAU;IACrC,MAAM,SAAS;IACf;GACF,KAAK;GACL,KAAK;IACH,MAAM,UAAU,KAAK,UAAU;IAC/B,MAAM,SAAS;IACf;GACF,SACE,IAAI,kBAAkB,UAAU,GAAG;IACjC,MAAM,OAAO,KAAK,UAAU;IAC5B,MAAM,SAAS;GACjB;EACJ;EAEA,OAAO;CACT,GACA,kBACF;CACA,IAAI,cAAc,iBAAiB;EACjC,OAAO,UAAU,KAAK,cAAc,eAAe;EACnD,OAAO,SAAS;CAClB,OAAO,IAAI,cAAc,MAAM;EAC7B,OAAO,MAAM,KAAK,cAAc,IAAI;EACpC,OAAO,SAAS;CAClB;CAEA,OAAO;AACT;AAaA,IAAM,6BACJ,eACA,qBAMG;CACH,MAAM,qBAAqB,sBAAsB,aAAa;CAC9D,MAAM,SAAS;EACb;EACA,MAAM;EACN,cAAc;EACd,aAAa;CACf;CACA,IAAI,CAAC,mBAAmB,OAAO,OAAO;CACtC,IAAI,mBAAmB,MAAM,SAAS,GACpC,OAAO;EAAE,GAAG;EAAQ,MAAM;EAAU,aAAa;CAAO;CAC1D,IAAI,mBAAmB,UAAU,SAAS,GAExC,OAAO;EAAE,GAAG;EAAQ,MAAM;EAAc,aAAa;CAAW;CAClE,IACE,mBAAmB,QAAQ,SAAS,KACpC,mBAAmB,QAAQ,WAAW,mBAAmB,OACzD;EACA,MAAM,kBAAkB,mBAAmB,QAAQ;EAKnD,MAAM,OADJ,gBAAgB,QAAQ,oBAEV,OAAO,gBAAgB,aAAa,gBAAgB,aAAa;EACjF,OAAO;GACL,GAAG;GACH,MAAM;GACN,cACE,oBAAC,WAAD;IACE,KAAK;IACL,WAAU;IACL;IACL,OAAO;GACR,CAAA;GAEH,aAAa;EACf;CACF;CACA,IACE,mBAAmB,UAAU,WAAW,mBAAmB,SAC3D,mBAAmB,UAAU,WAAW,GACxC;EACA,MAAM,iBAAiB,mBAAmB,UAAU;EACpD,OAAO;GACL,GAAG;GACH,MAAM;GACN,cACE,oBAAC,UAAD;IAAU,UAAU,eAAe;IAAO,UAAU,eAAe;GAAY,CAAA;GAEjF,aAAa;EACf;CACF;CACA,IAAI,mBAAmB,MAAM,WAAW,mBAAmB,OAAO;EAChE,MAAM,iBAAiB,mBAAmB,MAAM;EAChD,OAAO;GACL,GAAG;GACH,MAAM;GACN,cACE,oBAAC,WAAD;IACE,KAAK,eAAe;IACpB,WAAU;IACV,KAAK,eAAe,aAAa,eAAe;IAChD,OAAO,eAAe;GACvB,CAAA;GAEH,aAAa;EACf;CACF;CACA,IAAI,mBAAmB,OAAO,WAAW,mBAAmB,OAAO;EACjE,MAAM,kBAAkB,mBAAmB,OAAO;EAClD,OAAO;GACL,GAAG;GACH,MAAM;GACN,cACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,WAAD;IACE,KAAK,gBAAgB;IACrB,WAAU;IACV,KAAK,gBAAgB;IACrB,OAAO,gBAAgB;GACxB,CAAA,GACD,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,cAAD,CAAe,CAAA;GACZ,CAAA,CACL,EAAA,CAAA;GAEJ,aAAa;EACf;CACF;CACA,IAAI,mBAAmB,OAAO,WAAW,mBAAmB,OAAO;EACjE,MAAM,kBAAkB,mBAAmB,OAAO;EAClD,OAAO;GACL,GAAG;GACH,MAAM;GACN,cACE,oBAAC,WAAD;IACE,KAAK,gBAAgB;IACrB,WAAU;IACV,KAAK,gBAAgB;IACrB,OAAO,gBAAgB;GACxB,CAAA;GAEH,aAAa;EACf;CACF;CACA,IAAI,mBAAmB,gBAAgB,WAAW,mBAAmB,OACnE,OAAO;EAAE,GAAG;EAAQ,MAAM;EAAW,aAAa;CAAQ;CAE5D,OAAO;EAAE,GAAG;EAAQ,MAAM;EAAU,aAAa;CAAQ;AAC3D;AAEA,IAAa,wBAAwB,EACnC,wBACA,iBAC+B;CAC/B,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,kBAAkB,cACxB,gBAAgB,OAChB,iCACF;CAEA,OAAO,gBACL,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,wBAAD;GAC0B;GACxB,gBAAgB,gBAAgB,iBAAiB,IAAI;GACtC;GACH;EACb,CAAA;CACE,CAAA,IACH;AACN;AAUA,IAAa,0BAA0B,EACrC,aACA,WACA,wBACA,SACA,UACA,eACA,iBACiC;CACjC,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,GAAG,iBAAiB,sBAAsB;CAClD,MAAM,EAAE,cAAc,mBAAmB,mBACvC,uBAAuB,sBAAsB;CAE/C,MAAM,oBAAoB,cAEtB,eAAe,OAAO,GAAG,aAAa,WACtC,eAAe,MACjB;EAAC,eAAe;EAAM,eAAe;EAAM;CAAY,CACzD;CAEA,MAAM,EAAE,gBAAgB,cAAc,iBAAiB,cAAc;EACnE,IAAI,CAAC,eAAe,OAAO;GAAE,gBAAgB;GAAoB,cAAc;EAAK;EAEpF,MAAM,EACJ,oBACA,MAAM,gBACN,cACA,gBACE,0BAA0B,eAAe,gBAAgB;EAE7D,IAAI;EAEJ,IAAI,CAAC;OACC,gBAAgB,QAElB,eAAe,cAAc,KAAM;QAC9B,IAAI,gBAAgB,YACzB,eAAe,EAAE,eAAe;QAC3B,IAAI,gBAAgB,SACzB;IACE,MAAM,iBAAiB,mBAAmB,gBAAgB;IAC1D,eAAe,EAAE,gCAAgC,EAE/C,UAAU,gBAAgB,eAAgB,QAAQ,EACpD,CAAC;GACH,OACK,IAAI,gBAAgB,SACzB,eAAe;QACV,IAAI,gBAAgB,QACzB,eAAe,mBAAmB,MAAM,GAAG;QACtC,IAAI,gBAAgB,SACzB,eAAe,EAAE,qBAAqB,EAAE,OAAO,mBAAmB,MAAM,CAAC;QACpE,IAAI,gBAAgB,SACzB,eACE,mBAAmB,OAAO,WAAW,IACjC,EAAE,OAAO,IACT,EAAE,sBAAsB,EACtB,OAAO,mBAAmB,OAAO,OACnC,CAAC;QACF,IAAI,gBAAgB,QACzB,eAAe,mBAAmB,UAAU,GAAG;QAC1C,IAAI,gBAAgB,SACzB,eACE,mBAAmB,OAAO,WAAW,IACjC,EAAE,OAAO,IACT,EAAE,sBAAsB,EACtB,OAAO,mBAAmB,OAAO,OACnC,CAAC;EAAA,OAEJ,IAAI,YACT,eAAe,WAAW,mBAAmB,eAAe,eAAe;OAE3E,eAAe;EAGjB,OAAO;GACL;GACA;GACA;EACF;CACF,GAAG;EAAC;EAAkB;EAAe;EAAmB;EAAY;CAAC,CAAC;CAEtE,MAAM,eAAe,OAAO,MAAM,OAAO,eAAe,MAAM;CAC9D,MAAM,gBAAgB,CAAC,CAAC;CAExB,MAAM,iBAAiB,UAAyC;EAC9D,IAAI,CAAC,WAAY,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAM;EAE9D,MAAM,eAAe;EACrB,QAAQ,KAA8D;CACxE;CAEA,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,cAAc,OAAO;CAE9D,MAAM,aAAa,yBAAyB,aAAa,KAAK,cAAc,MAAM;CAClF,OACE,qBAAC,OAAD;EACE,cAAY,gBAAgB,EAAE,6BAA6B,IAAI,KAAA;EAC/D,WAAW,KAAK,oCAAoC,WAAW,EAC7D,yCAAyC,aAC3C,CAAC;EACD,eAAY;EACH;EACT,WAAW,gBAAgB,gBAAgB,KAAA;EAC3C,MAAM,gBAAgB,WAAW,KAAA;EACjC,UAAU,gBAAgB,IAAI,KAAA;YAThC;GAWE,oBAAC,wBAAD,EAAsC,aAAe,CAAA;GACrD,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eACZ,gBACE,eACG,EAAE,KAAK,IACP,aACE,EAAE,6BAA6B,EAAE,WAAW,CAAC,IAC7C,EAAE,OAAO;IACd,CAAA,GAEL,qBAAC,OAAD;KACE,WAAU;KACV,eAAY;eAFd,CAIE,oBAAC,gBAAD,CAAiB,CAAA,GACjB,oBAAC,OAAD;MAAK,WAAU;gBACZ;KACE,CAAA,CACF;MACF;;GACJ,gBACC,oBAAC,OAAD;IAAK,WAAU;cAA2C;GAAkB,CAAA;GAG7E,YACC,oBAAC,+BAAD;IACE,cAAY,EAAE,mBAAmB;IACjC,eAAY;IACZ,SAAS;GACV,CAAA;EAEA;;AAET;;;ACrcA,IAAa,iBAAiB,EAAE,YAAY,sBAA0C;CACpF,MAAM,EAAE,SAAS,YAAY,sBAAsB,kBAAkB,eAAe;CACpF,MAAM,EAAE,kBAAkB,wBAAwB,eAAe;CAEjE,MAAM,aAAa,mBAAmB;CAEtC,MAAM,EAAE,mBAAmB;CAE3B,OAAO,iBACL,oBAAC,wBAAD;EACE,UAAU,MAAM;GACd,IAAI,CAAC,gBAAgB;GACrB,EAAE,gBAAgB;GAClB,EAAE,eAAe;GACjB,cAAc,eAAe,EAAE;EACjC;EACA,eAAe;EACH;CACb,CAAA,IACC;AACN;;;AClBA,IAAM,yBAAyB,WAA0B,EACvD,YAAY,MAAM,WACpB;AAEA,SAAS,uBAAuB;CAC9B,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,cAAD,CAAe,CAAA,GACf,oBAAC,QAAD,EAAA,UAAO,EAAE,iBAAiB,EAAQ,CAAA,CAC/B;;AAET;AAEA,IAAM,6BAA6B;AAEnC,SAAS,gBAAgB,EAAE,YAAoC;CAC7D,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,eAAe,cAAc,UAAU,OAAO,qBAAqB,KAAK,CAAC;CAEjF,MAAM,wBAAwB,UAAU,MAAM;CAC9C,MAAM,uBACJ,UAAU,YAAY,wBAClB,SAAS,SAAS,QAAQ,IAAI,wBAC9B,KAAA;CAEN,MAAM,0BACJ,CAAC,CAAC,yCAAwB,IAAI,KAAK,GAAE,QAAQ,IAAI;CAEnD,IAAI,eAAe,QAAQ,CAAC,SAAS,UAAU,OAAO;CAEtD,MAAM,QAAQ,KAAK,IAAI;CAEvB,MAAM,SADa,SAAS,SAAS,QACtB,IAAa;CAE5B,MAAM,oBADc,KAAK,IAAI,MAAM,KAAK,KAAK,OACL;CAExC,MAAM,mBAAmB;EACvB,IAAI,yBAAyB;GAE3B,IAAI,mBAGF,OAAO,EAAE,4BAA4B,EACnC,UAAU,EAAE,kCAAkC,EAC5C,WAAW,SAAS,SACtB,CAAC,EACH,CAAC;GAIH,OAAO,EAAE,4BAA4B,EACnC,UAAU,EAAE,6BAA6B,EACvC,cAAc,OAChB,CAAC,EACH,CAAC;EACH;EAEA,IAAI,mBAGF,OAAO,EAAE,kCAAkC,EACzC,WAAW,SAAS,SACtB,CAAC;EAIH,OAAO,EAAE,sBAAsB,EAC7B,UAAU,EAAE,6BAA6B,EACvC,cAAc,WAChB,CAAC,EACH,CAAC;CACH;CAEA,OACE,qBAAC,KAAD;EAAG,WAAU;YAAb;GACE,oBAAC,UAAD,CAAW,CAAA;GACX,oBAAC,QAAD,EAAA,UAAO,EAAE,cAAc,EAAQ,CAAA;GAC/B,oBAAC,QAAD,EAAA,UAAM,MAAS,CAAA;GACf,oBAAC,QAAD;IAAM,WAAU;cAAyC,WAAW;GAAQ,CAAA;EAC3E;;AAEP;AAEA,IAAa,wBAAwB,EAAE,eAA0C;CAC/E,IAAI,CAAC,UAAU,OAAO;CAEtB,IAAI,CAAC,SAAS,UACZ,OAAO,oBAAC,sBAAD,CAAuB,CAAA;CAGhC,OAAO,oBAAC,iBAAD,EAA2B,SAAW,CAAA;AAC/C;;;ACtFA,IAAa,uBAAuB,UAAoC;CACtE,MAAM,EACJ,SAAS,kBACT,sBACA,YACA,8BACE;CACJ,MAAM,EAAE,SAAS,uBAAuB,kBAAkB,qBAAqB;CAC/E,MAAM,EAAE,YAAY,uBAAuB;CAC3C,MAAM,UAAU,oBAAoB;CACpC,MAAM,EAAE,OAAO,OAAO;CACtB,MAAM,EAAE,eAAe,wBAAwB,wBAAwB;EACrE;EACA;EACA;CACF,CAAC;CAED,gBAAgB;EACd,SAAS,GAAG,2BAA2B;GACrC,cAAc;EAChB,CAAC;CACH,GAAG,CAAC,SAAS,aAAa,CAAC;CAE3B,OACE,oBAAC,aAAD;EACE,SAAS;GAAE,GAAG;GAAS,MAAM;EAAoB;EACrC;CACb,CAAA;AAEL;;;AC5BA,IAAM,iCACJ;AAEF,IAAM,oBAAoB,WACxB,kBAAkB,oBAClB,kBAAkB,uBACjB,kBAAkB,eAAe,OAAO;AAM3C,IAAM,kBAAkB,MAAM,cAAoC,EAChE,aAAa,KACf,CAAC;AAID,IAAM,2BAA2B,EAC/B,UACA,GAAG,YAEH,oBAAC,gBAAgB,UAAjB;CAA0B,OAAO;CAAQ;AAAmC,CAAA;AAG9E,IAAa,2BAA2B,MAAM,WAAW,eAAe;AAqBxE,IAAa,YAAY,EACvB,UACA,WACA,sBAAsB,OACtB,SACA,QACA,YAAY,UACZ,kBACA,kBACA,mBACmB;CACnB,MAAM,CAAC,yBAAyB,8BAC9B,SAA6B,IAAI;CACnC,MAAM,2BAA2B,mBAC7B,0BACC,oBAAoB;CACzB,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC,gBAAgB;CACtD,MAAM,CAAC,iBAAiB,sBAAsB,SAAgC,IAAI;CAClF,MAAM,EAAE,MAAM,UAAU,QAAQ,GAAG,MAAM,mBAAmB,EAC1D,UACF,CAAC;CAED,gBAAgB;EACd,IAAI,CAAC,kBAAkB;EACvB,UAAU,KAAK;CACjB,GAAG,CAAC,gBAAgB,CAAC;CAErB,MAAM,QAAQ,kBAAkB;EAC9B,UAAU,KAAK;EACf,UAAU;CACZ,GAAG,CAAC,OAAO,CAAC;CAEZ,MAAM,OAAO,kBAAkB;EAC7B,UAAU,IAAI;EACd,SAAS;CACX,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,SAAS,kBAAkB;EAC/B,IAAI,QAAQ;GACV,MAAM;GACN;EACF;EACA,KAAK;CACP,GAAG;EAAC;EAAO;EAAQ;CAAI,CAAC;CAExB,gBAAgB;EACd,KAAK,aAAa,wBAAwB;CAC5C,GAAG,CAAC,MAAM,wBAAwB,CAAC;CAEnC,gBAAgB;EACd,KAAK,YAAY,eAAe;CAClC,GAAG,CAAC,iBAAiB,IAAI,CAAC;CAE1B,gBAAgB;EACd,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,0BAA0B;EAC9D,SAAS;CACX,GAAG;EAAC;EAAiB;EAAQ;EAA0B;CAAM,CAAC;CAE9D,gBAAgB;EACd,IAAI,CAAC,QAAQ;EAEb,MAAM,sBAAsB,UAAsB;GAChD,IAAI,EAAE,MAAM,kBAAkB,OAAO;GACrC,IAAI,iBAAiB,SAAS,MAAM,MAAM,GAAG;GAC7C,IAAI,0BAA0B,SAAS,MAAM,MAAM,GAAG;GACtD,MAAM;EACR;EAEA,SAAS,iBAAiB,aAAa,kBAAkB;EAEzD,aAAa;GACX,SAAS,oBAAoB,aAAa,kBAAkB;EAC9D;CACF,GAAG;EAAC;EAAO;EAAiB;EAAQ;CAAwB,CAAC;CAE7D,MAAM,4BAA4B,cAE9B,gCAA6C,EAC3C,WAAW,UACT,MAAM,KACJ,MAAM,cAAc,iBAClB,8BACF,CACF,EACJ,CAAC,GACH,CAAC,CACH;CAEA,MAAM,oBAAoB,OAAO,KAAK;CAEtC,MAAM,gBAAgB,aACnB,UAA4C;EAC3C,IAAI,MAAM,QAAQ,UAAU;GAC1B,MAAM,eAAe;GACrB,MAAM,gBAAgB;GACtB,kBAAkB,UAAU;GAC5B,MAAM;GACN;EACF;EACA,IAAI,iBAAiB,MAAM,MAAM,GAC/B;EAEF,0BAA0B,KAAK;CACjC,GACA,CAAC,OAAO,yBAAyB,CACnC;CAEA,MAAM,sBAAsB,aAAa,UAA4C;EACnF,IAAI,MAAM,QAAQ,YAAY,kBAAkB,SAAS;GACvD,kBAAkB,UAAU;GAC5B,MAAM,gBAAgB;EACxB;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,2BAA2B;CAqCjC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CApCc,2BACd,oBAAC,0BAAD;GACE,iBAAe;GACf,SAAS;GACT,cAAc;GACd,GAAI;EACL,CAAA,IACC,MAGF,UAAU,2BACR,oBAAC,YAAD;GAAY,WAAA;GAAU,cAAA;aACpB,oBAAC,yBAAD;IAAgC;cAC9B,oBAAC,OAAD;KACE,WAAW,KAAK,6BAA6B,SAAS;KACtD,SAAS;KACT,WAAW;KACX,gBAAgB;KAChB,KAAK;KACL,MAAK;KACL,OAAO;MACL,MAAM,KAAK;MACX,UAAU,sBACN,yBAAyB,sBAAsB,EAAE,QACjD,KAAA;MACJ,UAAU;MACV,KAAK,KAAK;KACZ;KAEC;IACE,CAAA;GACkB,CAAA;EACf,CAAA,IACV,IAMC;;AAET;;;AClMA,IAAa,eAAe,EAC1B,UACA,aACA,gBACA,OACA,GAAG,YACmB;CACtB,MAAM,EACJ,cAAc,WACd,mBAAmB,gBACnB,SACA,gBACA,UACA,IACA,UACA,WACA,GAAG,SACD;CACJ,MAAM,oBAAoB,YAAY;CACtC,MAAM,WAAW,MAAM,0BAA0B;CACjD,MAAM,gBAAgB,GAAG,SAAS;CAClC,MAAM,WAAW,OAAgC,IAAI;CAErD,MAAM,CAAC,qBAAqB,0BAA0B,SAAS,QAAQ,cAAc,CAAC;CACtF,MAAM,eAAe,YAAY,KAAA;CACjC,MAAM,OAAO,eAAe,UAAU;CACtC,MAAM,aAAa,gBAAgB,aAAa,KAAA;CAEhD,MAAM,gBAAsD,UAAU;EACpE,IAAI,CAAC,cACH,uBAAuB,MAAM,OAAO,OAAO;EAG7C,WAAW,KAAK;CAClB;CAEA,MAAM,iBAAyD,UAAU;EACvE,YAAY,KAAK;EACjB,IAAI,MAAM,oBAAoB,MAAM,QAAQ,KAAK;EAEjD,MAAM,eAAe;EACrB,MAAM,cAAc,MAAM;CAC5B;CAEA,MAAM,qBAAwD,UAAU;EACtE,IAAI,YAAY,MAAM,WAAW,SAAS,SAAS;EACnD,SAAS,SAAS,MAAM;CAC1B;CAKA,MAAM,gBADe,eAAgC,QAAQ,IAAI,WAAW,KAAA,IACzC,MAAM;CAMzC,MAAM,yBACJ,mBAAmB,CAAC,YAAa,QAAQ,gBAAgB,eAAgB,KAAA;CAE3E,OACE,qBAAC,OAAD;EACE,WAAW,KACT,gCACA,gBACA,YAAY,wCACd;YALF,CAOG,QACC,oBAAC,kBAAD;GACe;GACb,SAAS;GACT,IAAI;GACG;EACR,CAAA,IAED,UAEF,oBAAC,QAAD;GACE,GAAI;GACJ,cAAY;GACZ,mBAAiB;GACjB,SAAS;GACC;GACV,IAAI;GACJ,IAAI;GACJ,UAAU;GACV,WAAW;GACX,eAAe;GACf,UAAU;GACV,WAAW;EACZ,CAAA,CACE;;AAET;AAQA,IAAM,UAAU,EAAE,WAAW,IAAI,eAAe,WAAW,GAAG,YAC5D,qBAAC,OAAD;CACE,WAAW,KAAK,wCAAwC,EACtD,4CAA4C,GAC9C,CAAC;CACD,SAAS;WAJX,CAME,oBAAC,SAAD;EACE,GAAI;EACJ,WAAW,KAAK,uCAAuC,SAAS;EAChE,KAAK;EACL,MAAK;EACL,MAAK;CACN,CAAA,GACD,oBAAC,QAAD,EAAM,WAAU,8CAA+C,CAAA,CAC5D;;AAUP,IAAa,oBAAoB,EAC/B,SACA,UACA,WACA,aACA,OACA,GAAG,YAEH,oBAAC,SAAD;CACE,WAAW,KACT,uCACA,EAAE,iDAAiD,QAAQ,GAC3D,SACF;CACA,GAAI;WAEJ,oBAAC,OAAD;EAAK,WAAU;YACZ,QACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,kBAAD,EAAA,UAAmB,MAAwB,CAAA,GAC1C,eAAe,QAAQ,gBAAgB,MACtC,oBAAC,wBAAD,EAAA,UAAyB,YAAoC,CAAA,CAE/D,EAAA,CAAA,IAEF;CAEC,CAAA;AACA,CAAA;AAOT,IAAa,oBAAoB,EAC/B,UACA,WACA,OACA,GAAG,YAEH,oBAAC,OAAD;CACE,WAAW,KAAK,6CAA6C,SAAS;CACtE,GAAI;WAEH,YAAY;AACV,CAAA;AAOP,IAAa,0BAA0B,EACrC,UACA,WACA,aACA,GAAG,YAEH,oBAAC,OAAD;CACE,WAAW,KAAK,oDAAoD,SAAS;CAC7E,GAAI;WAEH,YAAY;AACV,CAAA;;;ACpMP,IAAM,mCAAmC,KAAK;AAE9C,IAAM,mCAAmC;CACvC,MAAU;CACV,OAAU;CACV,MAAS,KAAK;AAChB;AAeA,IAAM,8BAA8B;AAEpC,IAAM,+BAA+B,EACnC,UACA,SACA,cACA,GAAG,YAEH,oBAAC,QAAD;CACE,GAAI;CACJ,WAAU;CACD;CACT,KAAK;CACL,MAAK;CAEJ;AACK,CAAA;AAGV,IAAa,uBAAuB,EAClC,OACA,iBAAiB,uBACjB,iBAAiB,uCACa;CAC9B,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,CAAC,WAAW,gBAAgB,SAAmB,CAAC,CAAC;CACvD,MAAM,CAAC,kBAAkB,uBAAuB,SAA6B,KAAA,CAAS;CACtF,MAAM,CAAC,qBAAqB,0BAC1B,SAAqC,IAAI;CAC3C,MAAM,CAAC,iBAAiB,sBAAsB,SAAkB,KAAK;CACrE,MAAM,CAAC,0BAA0B,+BAA+B,SAE9D,KAAA,CAAS;CAEX,MAAM,sBAAsB,cACpB,eAAe,QAAQ,MAAM,KAAK,gCAAgC,GACxE,CAAC,cAAc,CACjB;CAEA,MAAM,wBAAwB,cAE1B,UAAU,SAAS,IACf,EAAE,2BAA2B,EAC3B,cAAc,oBAAoB,UAAU,GAC9C,CAAC,IACD,KAAA,GACN;EAAC;EAAW;EAAkB;CAAC,CACjC;CAEA,MAAM,uBAAuB,eACpB,EACL,UAAU,wBACR,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,QAAD,EAAA,UAAO,sBAA4B,CAAA,GACnC,oBAAC,iBAAD,CAAkB,CAAA,CAClB,EAAA,CAAA,IACA,KACN,IACA,CAAC,qBAAqB,CACxB;CAEA,MAAM,cAAc,kBAEhB,IAAI,SAAS,SAAS,WAAW;EAC/B,UAAU,YAAY,oBACnB,aAAa;GACZ,QAAQ,QAAQ;EAClB,IACC,kBAAkB;GACjB,QAAQ,KAAK,aAAa;GAC1B,OAAO,aAAa;EACtB,GACA,EAAE,SAAS,IAAK,CAClB;CACF,CAAC,GACH,CAAC,CACH;CAEA,MAAM,wBAAwB,kBAAkB;EAC9C,mBAAmB,IAAI;EACvB,MAAM,QAAQ,UAAU,YAAY,eACjC,aAAa;GACZ,uBAAuB,QAAQ;GAC/B,mBAAmB,KAAK;GACxB,4BAA4B,KAAA,CAAS;EACvC,IACC,UAAU;GACT,uBAAuB,IAAI;GAC3B,mBAAmB,KAAK;GACxB,4BAA4B,KAAK;EACnC,GACA,EAAE,SAAS,IAAK,CAClB;EAEA,aAAa;GACX,UAAU,YAAY,WAAW,KAAK;EACxC;CACF,GAAG,CAAC,CAAC;CAEL,gBAAgB,sBAAsB,GAAG,CAAC,qBAAqB,CAAC;CAEhE,MAAM,4BAA4B,UAAU,SAAS;CACrD,OACE,qBAAC,OAAO,MAAR;EACE,WAAU;EACV,eAAY;YAFd;GAIE,oBAAC,OAAO,QAAR;IACS;IACP,aAAa,EACX,0EACF;IACA,OAAO,EAAE,gBAAgB;GAC1B,CAAA;GACD,qBAAC,OAAO,MAAR,EAAA,UAAA,CACE,oBAAC,gBAAD;IAC4B;IAC1B,UAAU,qBAAqB,OAAO;IACrB;IACjB,WAAW,qBAAqB,OAAO;IACvC,yBAAyB;GAC1B,CAAA,GACA,oBAAoB,SAAS,KAC5B,qBAAC,OAAD;IACE,WAAW,KAAK,sCAAsC,EACpD,gDAAgD,0BAClD,CAAC;cAHH,CAKE,oBAAC,aAAD;KACE,SAAS;KACT,eAAY;KACZ,UAAU,CAAC;KACX,WAAW,MAAM;MACf,EAAE,gBAAgB;MAClB,IAAI,2BAA2B;OAC7B,aAAa,CAAC,CAAC;OACf,oBAAoB,KAAA,CAAS;MAC/B,OAAO;OACL,aAAa,mBAAmB;OAChC,oBAAoB,oBAAoB,EAAE;MAC5C;KACF;KACA,OAAO,EAAE,yBAAyB;IACnC,CAAA,GACA,6BAA6B,yBAC5B,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,UAAD;MACE,WAAU;MACV,kBAAkB;MAClB,cAAc;gBAEd,oBAAC,uBAAD;OACa;OACX,gBAAgB;OACE;MACnB,CAAA;KACO,CAAA;IACP,CAAA,CAEJ;KAEI,EAAA,CAAA;GACb,oBAAC,OAAO,QAAR,EAAA,UACE,qBAAC,OAAO,gBAAR,EAAA,UAAA;IACE,oBAAC,OAAO,+BAAR;KACE,WAAU;KACV,eAAe;MACb,gBAAgB,iBAAiB,UAAU;MAC3C,MAAM;KACR;eAEC,EAAE,QAAQ;IACyB,CAAA;IACtC,oBAAC,OAAO,+BAAR;KACE,WAAU;KACV,UAAU,CAAC;KACX,SAAS,YAAY;MACnB,IAAI,SAAS,uBAAuB;OAClC,UAAU,oBAAoB,OAAO;OACrC,WAAW,oBAAoB,OAAO;MACxC;MACA,IAAI,CAAC,QACH,UAAU,MAAM,YAAY,GAAG;MAEjC,gBAAgB,iBAAiB,QAAQ;OACvC,GAAG;OACH,YAAY;MACd,CAAC;MACD,MAAM;KACR;KACA,MAAK;eAEJ,EAAE,QAAQ;IACyB,CAAA;IACtC,oBAAC,OAAO,6BAAR;KACE,WAAU;KACV,UAAU,CAAC;KACX,SAAS,YAAY;MACnB,IAAI,SAAS,uBAAuB;OAClC,UAAU,oBAAoB,OAAO;OACrC,WAAW,oBAAoB,OAAO;MACxC;MACA,IAAI,CAAC,QACH,IAAI;OACF,UAAU,MAAM,YAAY,GAAG;MACjC,SAAS,GAAG;OACV,gBAAgB;QACd,SAAS;QACT,OAAO,aAAa,QAAQ,IAAI,KAAA;QAChC,SAAS,EAAE,6BAA6B;QACxC,UAAU;QACV,MAAM;OACR,CAAC;OACD;MACF;MAGF,gBAAgB,iBAAiB,QAAQ;OACvC,GAAG;OACH,YAAY;MACd,CAAC;MACD,IAAI;OACF,MAAM,gBAAgB,aAAa;MACrC,SAAS,KAAK;OACZ,gBAAgB;QACd,SAAS;QACT,OAAO,eAAe,QAAQ,MAAM,KAAA;QACpC,SAAS,EAAE,0BAA0B;QACrC,UAAU;QACV,MAAM;OACR,CAAC;OACD;MACF;MACA,MAAM;KACR;KACA,MAAK;eAEJ,EAAE,OAAO;IACwB,CAAA;GACf,EAAA,CAAA,EACV,CAAA;EACJ;;AAEjB;AAOA,IAAM,yBAAyB,EAC7B,WACA,gBACA,uBACgC;CAChC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,UAAU,mBAAmB;CACrC,OACE,oBAAC,iBAAD,EAAA,UACE,oBAAC,iBAAD,EAAA,UACG,UAAU,KAAK,aACd,oBAAC,mBAAD;EACE,gBAAc,qBAAqB;EACnC,WAAU;EAEV,eAAe;GACb,eAAe,QAAQ;GACvB,MAAM;EACR;EACA,MAAK;YAEJ,EAAE,2BAA2B,EAAE,cAAc,SAAS,CAAC;CACvC,GARZ,YAAY,UAQA,CACpB,EACc,CAAA,EACF,CAAA;AAErB;;;ACtTA,IAAM,wBAAqB,eAAwD;CACjF,qBAAqB,UAAU;CAC/B,WAAW,UAAU;CACrB,mBAAmB,UAAU;CAC7B,MAAM,UAAU;CAChB,SAAS,UAAU;AACrB;AAEA,IAAa,mBAAmB;CAC9B,MAAM,EAAE,MAAM,sBAAsB,YAAY;CAEhD,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,qBAAqB,WAAW,mBAAmB,MAAM,YAC/D,cAAc,KAAK,OAAO,oBAAiB;CAE7C,MAAM,wBAAwB,cAAc;EAC1C,IAAI,WAAW,OAAO,EAAE,YAAY;EACpC,IAAI,uBAAuB,QAAQ,WAAW,GAAG,OAAO,EAAE,YAAY;EACtE,IAAI,mBACF,OAAO,EAAE,0BAA0B,EACjC,OAAO,oBAAoB,QAAQ,SAAS,QAAQ,SAAS,kBAC/D,CAAC;EACH,IAAI,QAAQ,SAAS,GAAG,OAAO,EAAE,oBAAoB;EACrD,OAAO;CACT,GAAG;EAAC;EAAW;EAAqB;EAAmB,QAAQ;EAAQ;CAAC,CAAC;CAEzE,IAAI,CAAC,MAAM,OAAO;CAElB,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD;GAAK,WAAU;aAAwB;EAAU,CAAA,GACjD,oBAAC,OAAD;GAAK,WAAU;aAA2B;EAA2B,CAAA,CAClE;;AAET;;;ACrCA,IAAa,cAAc,EAAE,WAAW,MAAM,GAAG,YAC/C,oBAAC,OAAD;CAAK,GAAI;CAAO,WAAW,KAAK,8BAA8B,SAAS;WACpE;AACE,CAAA;;;ACaP,IAAM,gBAAgB,MAA6B;CACjD,MAAM,UAAU,EAAE,KAAK;CACvB,IAAI,YAAY,IAAI,OAAO;CAC3B,MAAM,IAAI,OAAO,OAAO;CACxB,OAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAEA,IAAM,SAAS,GAAW,KAAa,QACrC,KAAK,IAAI,KAAK,IAAI,GAAG,GAAG,GAAG,GAAG;AAEhC,IAAa,eAAe,WAC1B,SAAS,aACP,EACE,WACA,WAAW,OACX,IAAI,QACJ,OACA,KACA,KACA,UACA,OAAO,GACP,OACA,GAAG,cAEL,KACA;CACA,MAAM,cAAc,YAAY;CAChC,MAAM,KAAK,UAAU;CACrB,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,MAAM,aAAa,KAAK;CAC9B,MAAM,SAAS,OAAO;CACtB,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,QAAQ,QAAQ,OAAO;CACrC,MAAM,QAAQ,QAAQ,QAAQ,OAAO;CAErC,MAAM,oBAAoB,aACvB,MAAqC;EACpC,MAAM,OAAO,EAAE,OAAO;EACtB,IAAI,SAAS,MAAM,QAAQ,KAAK,IAAI,GAClC,SAAS,CAAC;CAEd,GACA,CAAC,QAAQ,CACX;CAEA,MAAM,oBAAoB,aACvB,cACE;EACC,eAAe,EAAE,OAAO,SAAS;EACjC,QAAQ,EAAE,OAAO,SAAS;CAC5B,IACF,CAAC,CACH;CAEA,MAAM,kBAAkB,kBAAkB;EACxC,IAAI,YAAY,OAAO;EACvB,MAAM,OAAO,QAAQ,OAAO,MAAM,MAAM,MAAM,QAAQ,MAAM,IAAI;EAChE,SAAS,kBAAkB,OAAO,IAAI,CAAC,CAAC;CAC1C,GAAG;EAAC;EAAU;EAAO;EAAK;EAAM;EAAQ;EAAQ;EAAU;CAAiB,CAAC;CAE5E,MAAM,kBAAkB,kBAAkB;EACxC,IAAI,YAAY,OAAO;EACvB,MAAM,OAAO,QAAQ,OAAO,MAAM,MAAM,MAAM,QAAQ,MAAM,IAAI;EAChE,SAAS,kBAAkB,OAAO,IAAI,CAAC,CAAC;CAC1C,GAAG;EAAC;EAAU;EAAO;EAAK;EAAM;EAAQ;EAAQ;EAAU;CAAiB,CAAC;CAE5E,MAAM,gBAAgB,aACnB,MAAuC;EACtC,IAAI,EAAE,QAAQ,aAAa;GACzB,EAAE,eAAe;GACjB,gBAAgB;EAClB,OAAO,IAAI,EAAE,QAAQ,WAAW;GAC9B,EAAE,eAAe;GACjB,gBAAgB;EAClB;CACF,GACA,CAAC,iBAAiB,eAAe,CACnC;CAEA,OACE,qBAAC,OAAD;EACE,WAAW,KACT,gCACA,YAAY,0CACZ,SACF;YALF,CAOG,CAAC,CAAC,SACD,oBAAC,SAAD;GAAO,WAAU;GAAsC,SAAS;aAC7D;EACI,CAAA,GAET,qBAAC,OAAD;GAAK,WAAW,KAAK,uCAAuC;aAA5D;IACE,oBAAC,QAAD;KACE,YAAW;KACX,cAAY,EAAE,qBAAqB;KACnC,UAAA;KACA,WAAW,KACT,wFACF;KACA,UAAU,YAAY;KACtB,SAAS;KACT,MAAK;KACL,SAAQ;eAER,oBAAC,WAAD,EAAW,WAAU,6CAA8C,CAAA;IAC7D,CAAA;IACR,oBAAC,SAAD;KACE,iBAAe,OAAO,SAAS,MAAM,IAAI,SAAS,KAAA;KAClD,iBAAe,OAAO,SAAS,MAAM,IAAI,SAAS,KAAA;KAClD,iBAAe,OAAO,KAAA;KACtB,WAAU;KACA;KACN;KACJ,WAAU;KACV,UAAU;KACV,WAAW;KACN;KACL,MAAK;KACL,MAAK;KACE;KACP,GAAI;IACL,CAAA;IACD,oBAAC,QAAD;KACE,YAAW;KACX,cAAY,EAAE,qBAAqB;KACnC,UAAA;KACA,WAAW,KACT,wFACF;KACA,UAAU,YAAY;KACtB,SAAS;KACT,MAAK;KACL,SAAQ;eAER,oBAAC,eAAD,EAAe,WAAU,6CAA8C,CAAA;IACjE,CAAA;GACL;IACF;;AAET,CACF;;;ACvHA,IAAM,4BAA4B,EAAE,MAAM,WACxC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,QAAD;CAAM,eAAA;CAAY,WAAU;WACzB;AACG,CAAA,GACN,oBAAC,QAAD;CAAM,WAAU;WAA2C;AAAW,CAAA,CACtE,EAAA,CAAA;AA0BJ,IAAM,yBAAyB,UAAsC;CACnE,IAAI,MAAM,SAAS,WACjB,OACE,oBAAC,OAAD;EACE,WAAW,KACT,sCACA,MAAM,mBACJ,0DACJ;EACA,IAAI,MAAM;YAET,MAAM;CACJ,CAAA;MAEF,IAAI,MAAM,SAAS,WACxB,OACE,oBAAC,OAAD;EACE,WAAW,KACT,sCACA,+CACA,MAAM,mBACJ,0DACJ;EACA,IAAI,MAAM;YAEV,oBAAC,0BAAD;GACE,MAAM,MAAM,sBAAsB,oBAAC,eAAD,CAAgB,CAAA;GAClD,MAAM,MAAM;EACb,CAAA;CACE,CAAA;MAEF,IAAI,MAAM,SAAS,SACxB,OACE,oBAAC,OAAD;EACE,WAAW,KACT,sCACA,8BACA,MAAM,mBACJ,0DACJ;EACA,IAAI,MAAM;EACV,MAAK;YAEL,oBAAC,0BAAD;GACE,MAAM,MAAM,oBAAoB,oBAAC,qBAAD,CAAsB,CAAA;GACtD,MAAM,MAAM;EACb,CAAA;CACE,CAAA;CAIT,OAAO;AACT;AAEA,IAAa,YAAY,WAA6C,SAAS,UAC7E,EACE,WACA,UACA,QAAQ,OACR,cACA,kBACA,wBAAwB,WACxB,IAAI,QACJ,OACA,SACA,SACA,gBACA,oBACA,UACA,cACA,UAAU,WACV,GAAG,cAEL,KACA;CACA,MAAM,SAAS,YAAY;CAC3B,MAAM,KAAK,UAAU;CAErB,MAAM,WAAW,UAAU,gBAAgB,QAAQ,WAAW;CAC9D,MAAM,cAAc,CAAC,YAAY,kBAAkB;CACnD,MAAM,cAAc,CAAC,YAAY,CAAC,eAAe,WAAW;CAE5D,MAAM,gBAAgB,0BAA0B,aAD5B,YAAY,eAAe;CAG/C,MAAM,YAAY,WACd,GAAG,GAAG,gBACN,eAAe,cACb,GAAG,GAAG,YACN,KAAA;CACN,MAAM,cAAc,CAAC,WAAW,qBAAqB,SAAS,EAC3D,QAAQ,UAA2B,CAAC,CAAC,KAAK,EAC1C,KAAK,GAAG;CAEX,MAAM,eAAe,WACnB,oBAAC,uBAAD;EACoB;EAClB,IAAI;EACJ,iBAAiB;EACjB,MAAK;EACL,MAAM,gBAAgB;CACvB,CAAA,IACC,cACF,oBAAC,uBAAD;EACE,IAAI;EACJ,iBAAiB;EACjB,MAAK;EACe;EACpB,MAAM;CACP,CAAA,IACC,cACF,oBAAC,uBAAD;EACE,IAAI;EACJ,iBAAiB;EACjB,MAAK;EACL,MAAM;CACP,CAAA,IACC;CAEJ,OACE,qBAAC,OAAD;EACE,WAAW,KACT,6BACA,SAAS,oCACT,eAAe,sCACf,YAAY,uCACZ,iBAAiB,mDACjB,SACF;YARF;GAUG,QACC,oBAAC,SAAD;IAAO,WAAU;IAAmC,SAAS;cAC1D;GACI,CAAA,IACL;GACJ,qBAAC,OAAD;IACE,WAAW,KACT,sCACA,uCAAuC,WACvC,iBAAiB,0DACnB;cALF,CAOE,qBAAC,OAAD;KAAK,WAAU;eAAf;MACG,UACC,oBAAC,QAAD;OAAM,eAAA;OAAY,WAAU;iBACzB;MACG,CAAA,IACJ;MACJ,oBAAC,SAAD;OACE,oBAAkB;OAClB,gBAAc;OACd,WAAU;OACA;OACN;OACC;OACL,GAAI;MACL,CAAA;MACA,gBAAgB,OACf,oBAAC,QAAD;OAAM,eAAA;OAAY,WAAU;iBACzB;MACG,CAAA,IACJ;MACH,WACC,oBAAC,QAAD;OAAM,eAAA;OAAY,WAAU;iBACzB;MACG,CAAA,IACJ;KACD;QACJ,gBAAgB,eAAe,IAC7B;;GACJ,gBAAgB,OAAO;EACrB;;AAET,CAAC;;;AClPD,IAAa,wBAAwB,EACnC,UACA,WACA,WACA,oBAC+B;CAC/B,MAAM,CAAC,OAAO,YAAY,SAAmB,CAAC,CAAC;CAC/C,MAAM,CAAC,gBAAgB,qBAAqB,SAAwB,IAAI;CACxE,MAAM,CAAC,eAAe,oBAAoB,SAAwB,IAAI;CACtE,MAAM,CAAC,WAAW,gBAAgB,SAAgC,IAAI;CAEtE,MAAM,gBACJ,mBAAmB,QAAQ,kBAAkB,OACzC,KAAA,IACA,kBAAkB,gBAChB,SACA;CAER,MAAM,gBAAgB,MAAM,SAAS,QAAQ,QAAQ;CAErD,gBAAgB;EACd,SAAS,MAAM,SAAS,IAAI,WAAW,GAAG,UAAU,KAAK,KAAK,CAAC,CAAC;CAClE,GAAG,CAAC,QAAQ,CAAC;CAEb,gBAAgB;EACd,IAAI,CAAC,WAAW;EAEhB,MAAM,mBAAmB,MAAiB;GAExC,MAAM,gBADS,EAAE,OACY,QAAQ,0CAA0C;GAC/E,IAAI,EAAE,cACJ,EAAE,aAAa,gBAAgB;GAGjC,IAAI,yBAAyB,aAAa;IACxC,MAAM,QAAQ,MAAM,KAAK,cAAc,eAAe,YAAY,CAAC,CAAC,EAAE,QACpE,aACF;IACA,kBAAkB,KAAK;IACvB,EAAE,cAAc,QAAQ,cAAc,MAAM,SAAS,CAAC;IACtD,cAAc,MAAM,UAAU;GAChC;EACF;EAEA,MAAM,kBAAkB,MAAiB;GACvC,EAAE,eAAe;GAEjB,MAAM,gBADS,EAAE,OACY,QAAQ,0CAA0C;GAC/E,IAAI,yBAAyB,aAI3B,iBAHc,MAAM,KAAK,cAAc,eAAe,YAAY,CAAC,CAAC,EAAE,QACpE,aAEe,CAAK;EAE1B;EAEA,MAAM,wBAAwB;GAC5B,iBAAiB,IAAI;EACvB;EAEA,MAAM,cAAc,MAAiB;GACnC,EAAE,eAAe;GACjB,MAAM,eAAe,SAAS,EAAE,cAAc,QAAQ,YAAY,KAAK,MAAM,EAAE;GAE/E,MAAM,gBADS,EAAE,OACY,QAAQ,0CAA0C;GAC/E,IAAI,yBAAyB,aAAa;IACxC,MAAM,YAAY,MAAM,KAAK,cAAc,eAAe,YAAY,CAAC,CAAC,EAAE,QACxE,aACF;IACA,IAAI,iBAAiB,MAAM,iBAAiB,WAC1C,UAAU,cAAc;KACtB,MAAM,WAAW,CAAC,GAAG,SAAS;KAC9B,MAAM,CAAC,WAAW,SAAS,OAAO,cAAc,CAAC;KACjD,SAAS,OAAO,WAAW,GAAG,OAAO;KACrC,gBAAgB,QAAQ;KACxB,OAAO;IACT,CAAC;GAEL;GACA,kBAAkB,IAAI;GACtB,iBAAiB,IAAI;EACvB;EAEA,MAAM,iBAAiB,MAAiB;GACtC,MAAM,SAAS,EAAE;GACjB,IAAI,kBAAkB,aACpB,OAAO,MAAM,UAAU;GAEzB,kBAAkB,IAAI;GACtB,iBAAiB,IAAI;EACvB;EAEA,UAAU,iBAAiB,aAAa,eAAe;EACvD,UAAU,iBAAiB,YAAY,cAAc;EACrD,UAAU,iBAAiB,aAAa,eAAe;EACvD,UAAU,iBAAiB,QAAQ,UAAU;EAC7C,UAAU,iBAAiB,WAAW,aAAa;EAEnD,aAAa;GACX,UAAU,oBAAoB,aAAa,eAAe;GAC1D,UAAU,oBAAoB,YAAY,cAAc;GACxD,UAAU,oBAAoB,aAAa,eAAe;GAC1D,UAAU,oBAAoB,QAAQ,UAAU;GAChD,UAAU,oBAAoB,WAAW,aAAa;EACxD;CACF,GAAG,CAAC,WAAW,aAAa,CAAC;CAE7B,OACE,oBAAC,OAAD;EACE,WAAW,KAAK,qCAAqC,SAAS;EAC9D,KAAK;YAEJ,MAAM,KAAK,eAAe,iBAAiB;GAC1C,MAAM,QAAQ,cAAc;GAC5B,OACE,oBAAC,OAAD;IACE,WAAW,KAAK,2CAA2C;KACzD,qEACE,kBAAkB,QAAQ,kBAAkB;KAC9C,kEACE,kBAAkB,UAAU,kBAAkB;IAClD,CAAC;IACU;cAKV;GACE,GAJD,MAAM,eAAe,KAAK,IAAI,MAAM,MAAM,kBAAkB,eAI3D;EAET,CAAC;CACE,CAAA;AAET;;;ACpIA,IAAa,qBAAqB,EAChC,UACA,WACA,WACA,OACA,oBAEA,qBAAC,YAAD;CAAU,WAAW,KAAK,kCAAkC,SAAS;WAArE,CACE,oBAAC,UAAD;EAAQ,WAAU;YAAyC;CAAc,CAAA,GACzE,oBAAC,sBAAD;EACE,WAAU;EACC;EACI;EAEd;CACmB,CAAA,CACd;;;;ACNZ,SAAgB,aACd,SACuB;CACvB,MAAM,EAAE,cAAc,UAAU,aAAa,CAAC,MAAuB;CACrE,MAAM,CAAC,OAAO,YAAY,SAAY,YAAY;CAClD,MAAM,CAAC,aAAa,kBAAkB,SAAgC,CAAC,CAAC;CAExE,MAAM,gBAAgB,aACnB,OAAgB,eAA2B;EAC1C,UAAU,UAAU;GAAE,GAAG;IAAO,QAAQ;EAAW,EAAO;EAC1D,MAAM,YAAY,WAAW;EAC7B,IAAI,WAAW;GACb,MAAM,MAAM,UAAU,UAAU;GAChC,gBAAgB,SAAS;IACvB,MAAM,OAAO,EAAE,GAAG,KAAK;IACvB,IAAI,KAAK,KAAK,SAAmB;SAC5B,OAAO,KAAK;IACjB,OAAO;GACT,CAAC;EACH;CACF,GACA,CAAC,UAAU,CACb;CAuBA,OAAO;EACL;EACA,cAvBmB,aAClB,MAAwB;GACvB,GAAG,eAAe;GAClB,MAAM,SAAgC,CAAC;GACvC,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAAkB;IACnD,MAAM,YAAY,WAAW;IAC7B,IAAI,WAAW;KACb,MAAM,MAAM,UAAU,MAAM,IAAI;KAChC,IAAI,KAAK,OAAO,OAAiB;IACnC;GACF;GACA,IAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;IAClC,eAAe,MAAM;IACrB;GACF;GACA,eAAe,CAAC,CAAC;GACjB,SAAc,KAAK;EACrB,GACA;GAAC;GAAO;GAAY;EAAQ,CAK5B;EACA;EACA;EACA;CACF;AACF;;;AChEA,IAAM,uBAAqB,eAAwD,EACjF,WAAW,UAAU,UACvB;AAMA,IAAa,oBAAoB,EAAE,gBAAuC;CACxE,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,UAAU,gBAAgB;CAClC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,cAAc,cAAc,KAAK,OAAO,mBAAiB;CACjE,MAAM,CAAC,OAAO,YAAY,SAAkC,IAAI;CAEhE,MAAM,iBAAiB,WAAW,eAAe;CACjD,MAAM,eAAe,eAAe,EAAE,SAAS,eAAe,IAAI,CAAC,cAAc,CAAC;CAClF,MAAM,aAAa,eACV,EACL,UAAU,MAAc;EAEtB,IAAI,EADY,OAAO,MAAM,WAAW,EAAE,KAAK,IAAI,KAEjD,OAAO,IAAI,MAAM,EAAE,mDAAmD,CAAC;CAG3E,EACF,IACA,CAAC,CAAC,CACJ;CAQA,MAAM,EAAE,aAAa,cAAc,eAAe,UAAU,aAEzD;EACD;EACA,UAXe,YACf,OAAO,cAAmC;GACxC,MAAM,KAAK,UAAU,UAAU,SAAS,SAAS;GACjD,MAAM;EACR,GACA;GAAC;GAAM;GAAW;EAAK,CAMvB;EACA;CACF,CAAC;CAED,gBAAgB;EACd,OAAO,MAAM;CACf,GAAG,CAAC,KAAK,CAAC;CAEV,MAAM,QAAQ,YAAY,EAAE,qBAAqB,IAAI,EAAE,eAAe;CACtE,MAAM,cAAc,YAChB,EAAE,iDAAiD,IACnD,EAAE,mCAAmC;CACzC,MAAM,iBACJ,CAAC,MAAM,SAAS,KAAK,KAAK,MAAM,YAAY,WAAW;CAEzD,OACE,qBAAC,OAAO,MAAR;EAAa,WAAU;YAAvB,CACG,SAAS,oBAAC,OAAO,QAAR;GAAsB;GAAoB;GAAoB;EAAQ,CAAA,GAChF,qBAAC,QAAD;GAAM,cAAa;GAAM,UAAU;aAAnC,CACE,oBAAC,OAAO,MAAR,EAAA,UACE,oBAAC,WAAD;IACE,cAAY;IACZ,OAAO,CAAC,CAAC,YAAY;IACrB,cAAc,YAAY,SAAS;IACnC,IAAG;IACH,MAAK;IACL,WAAW,MAAM,cAAc,WAAW,EAAE,OAAO,KAAK;IACxD,aAAa,EAAE,yBAAyB;IACxC,KAAK;IACL,UAAA;IACA,MAAK;IACL,OAAO,MAAM;GACd,CAAA,EACU,CAAA,GACb,oBAAC,OAAO,QAAR,EAAA,UACE,qBAAC,OAAO,gBAAR,EAAA,UAAA,CACE,oBAAC,OAAO,+BAAR;IACE,WAAU;IACV,SAAS;IACT,MAAK;cAEJ,EAAE,QAAQ;GACyB,CAAA,GACtC,oBAAC,OAAO,6BAAR;IACE,WAAU;IACV,UAAU,OAAO,KAAK,WAAW,EAAE,SAAS,KAAK;IACjD,MAAK;cAEJ,iBAAiB,EAAE,QAAQ,IAAI,EAAE,MAAM;GACN,CAAA,CACf,EAAA,CAAA,EACV,CAAA,CACX;IACK;;AAEjB;;;AClGA,IAAa,qBAAqB;CAChC,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,UAAU,gBAAgB;CAElC,OACE,qBAAC,MAAM,MAAP;EAAY,WAAW;YAAvB,CACE,oBAAC,MAAM,QAAP;GACE,aAAa,EACX,qFACF;GACA,OAAO,EAAE,gBAAgB;EACZ,CAAA,GACf,qBAAC,MAAM,SAAP,EAAA,UAAA,CACE,oBAAC,QAAD;GACE,YAAW;GACX,WAAU;GACV,eAAY;GACZ,SAAS,YAAY;IACnB,IAAI;KACF,MAAM,KAAK,MAAM;KACjB,MAAM;KACN,gBAAgB;MACd,SAAS;MACT,SAAS,EAAE,YAAY;MACvB,UAAU;MACV,MAAM;KACR,CAAC;IACH,SAAS,GAAG;KACV,gBAAgB;MACd,SAAS;MACT,OAAO,aAAa,QAAQ,IAAI,KAAA;MAChC,SAAS,EAAE,wBAAwB;MACnC,UAAU;MACV,MAAM;KACR,CAAC;IACH;GACF;GACA,MAAK;GACL,SAAQ;aAEP,EAAE,UAAU;EACP,CAAA,GACR,oBAAC,QAAD;GACE,YAAW;GACX,WAAU;GACV,eAAY;GACZ,SAAS;GACT,MAAK;GACL,SAAQ;aAEP,EAAE,QAAQ;EACL,CAAA,CACK,EAAA,CAAA,CACL;;AAEhB;;;AC3CA,IAAa,cAAc,EACzB,YACA,UACA,YACA,oBACA,gBACA,aACA,gBACwC;CACxC,MAAM,EAAE,QAAQ,gBAAgB,oBAAoB;CACpD,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EACE,YAAW;EACX,WAAW,KAAK,yBAAyB,EACvC,qCAAqC,mBACvC,CAAC;EACD,SAAS;EACT,MAAK;EACL,SAAQ;YAEP;CACK,CAAA,GACR,oBAAC,OAAD;EAAO,WAAW;EAAgB,SAAS;EAAY,MAAM;EAC1D;CACI,CAAA,CACP,EAAA,CAAA;AAEN;;;AClCA,IAAM,uBAAqB,eAAwD,EACjF,SAAS,UAAU,QACrB;AAIA,IAAa,gCAAgC;CAC3C,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,UAAU,gBAAgB;CAClC,MAAM,EAAE,YAAY,cAAc,KAAK,OAAO,mBAAiB;CAC/D,MAAM,CAAC,OAAO,YAAY,SAAkC,IAAI;CAEhE,MAAM,eAAe,eAAe,EAAE,YAAY,GAAG,IAAI,CAAC,CAAC;CAC3D,MAAM,aAAa,eACV,EACL,aAAa,MAAc;EACzB,MAAM,UAAU,OAAO,MAAM,WAAW,EAAE,KAAK,IAAI;EACnD,IAAI,CAAC,SACH,OAAO,IAAI,MAAM,EAAE,mDAAmD,CAAC;EAGzE,IADuB,QAAQ,MAAM,WAAW,OAAO,SAAS,OAC5D,GACF,OAAO,IAAI,MAAM,EAAE,uBAAuB,CAAC;CAG/C,EACF,IACA,CAAC,GAAG,OAAO,CACb;CAYA,MAAM,EAAE,aAAa,cAAc,eAAe,UAAU,aAEzD;EACD;EACA,UAde,YACf,OAAO,cAAsC;GAC3C,MAAM,OAAO,iBAAiB,KAAK,IAAI,EACrC,MAAM,UAAU,WAClB,CAAC;GACD,MAAM;EACR,GACA;GAAC;GAAQ;GAAM;EAAK,CAOpB;EACA;CACF,CAAC;CAED,gBAAgB;EACd,OAAO,MAAM;CACf,GAAG,CAAC,KAAK,CAAC;CAEV,MAAM,iBAAiB,CAAC,MAAM,YAAY,KAAK;CAE/C,OACE,qBAAC,OAAO,MAAR;EAAa,WAAU;YAAvB,CACE,oBAAC,OAAO,QAAR;GACS;GACP,aAAa,EAAE,0CAA0C;GACzD,OAAO,EAAE,mBAAmB;EAC7B,CAAA,GACD,qBAAC,QAAD;GAAM,cAAa;GAAM,UAAU;aAAnC,CACE,oBAAC,OAAO,MAAR,EAAA,UACE,oBAAC,WAAD;IACE,cAAY,EAAE,mBAAmB;IACjC,OAAO,CAAC,CAAC,YAAY;IACrB,cAAc,YAAY,YAAY;IACtC,IAAG;IACH,MAAK;IACL,WAAW,MAAM,cAAc,cAAc,EAAE,OAAO,KAAK;IAC3D,aAAa,EAAE,kCAAkC;IACjD,KAAK;IACL,UAAA;IACA,MAAK;IACL,OAAO,MAAM;GACd,CAAA,EACU,CAAA,GACb,oBAAC,OAAO,QAAR,EAAA,UACE,qBAAC,OAAO,gBAAR,EAAA,UAAA,CACE,oBAAC,OAAO,+BAAR;IACE,WAAU;IACV,SAAS;cAER,EAAE,QAAQ;GACyB,CAAA,GACtC,oBAAC,OAAO,6BAAR;IACE,WAAU;IACV,UAAU,OAAO,KAAK,WAAW,EAAE,SAAS,KAAK;IACjD,MAAK;cAEJ,EAAE,MAAM;GACyB,CAAA,CACf,EAAA,CAAA,EACV,CAAA,CACX;IACK;;AAEjB;;;ACzGA,IAAM,qBAAqB,EAAE,gBAAuC;CAClE,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,aAAa,aAAa,mBAChC,sBAAuC;CACzC,MAAM,CAAC,kBAAkB,uBAAuB,SAAiC,IAAI;CACrF,MAAM,gBAAgB,IAAI,KAAK,SAAS;CACxC,OACE,qBAAC,OAAD;EACE,WAAU;EACV,cAAc;EACd,cAAc;EACd,KAAK;YAJP,CAMG,EAAE,sBAAsB,EAAE,WAAW,cAAc,CAAC,GACrD,oBAAC,eAAD;GACE,QAAQ,CAAC,GAAG,CAAC;GACb,WAAU;GACQ;GAClB,SAAS;aAER,EAAE,6BAA6B,EAAE,WAAW,cAAc,CAAC;EAC/C,CAAA,CACZ;;AAET;AAQA,IAAM,kBAAkB,EAAE,WAA2B;CACnD,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,cACJ,OAAO,MAAM,MAAM,OAAO,KAAK,OAAO,KAAK,MAAM,KAC7C,EAAE,KAAK,IACP,KAAK,MAAM,QAAQ,KAAK,MAAM,MAAM,EAAE,WAAW;CAEvD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,KAAK,QACJ,oBAAC,QAAD;GACE,WAAU;GACV,UAAU,KAAK,KAAK;GAEpB,MAAK;GACL,UAAU,KAAK,KAAK;EACrB,GAHM,aAAa,KAAK,GAAG,UAAU,KAAK,KAAK,IAG/C,GAEH,oBAAC,OAAD;GAAK,WAAU;aAAqC;EAAiB,CAAA,CAClE;;AAET;AAEA,IAAa,YAAY,EAAE,WACzB,qBAAC,OAAD;CAAK,WAAU;WAAf,CACE,oBAAC,gBAAD,EAAsB,KAAO,CAAA,GAC7B,oBAAC,mBAAD,EAAmB,WAAW,KAAK,WAAa,CAAA,CAC7C;;AAOP,IAAa,mBAAmB,EAAE,YAChC,oBAAC,OAAD;CAAK,WAAU;WACZ,MAAM,KAAK,SACV,oBAAC,UAAD,EAA6C,KAAO,GAArC,aAAa,KAAK,IAAmB,CACrD;AACE,CAAA;;;ACzEP,SAAgB,2BACd,iBACA,sBACA,UACA;CACA,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,CAAC,iBAAiB,sBAAsB,SAC5C,sBAAsB,eAAe,EAAE,SAAS,CAAC,CACnD;CAEA,gBAEI,sBAAsB,uBACnB,UAAU,CAAC,MAAM,eAAe,IAChC,CAAC,qBACA,oBAAoB,SAAS,CAAC,GAAG,MAAM,GAAG,eAAe,CAAC,CAC9D,GACF,CAAC,oBAAoB,CACvB;CAEA,gBAAgB;EACd,MAAM,mBAAmB,UAAiB;GACxC,IAAI,CAAC,MAAM,WAAW;GACtB,MAAM,WAAW,aAAa,MAAM,SAAS;GAC7C,IACG,oBAAoB,YAAY,CAAC,YACjC,oBAAoB,WAClB,YAAY,MAAM,UAAU,cAAc,WAE7C;GAEF,IAAI,MAAM,SAAS,qBACjB,oBAAoB,SAClB,MAAM,YACF,KAAK,QAAQ,SAAS,KAAK,OAAQ,MAAM,UAAgB,EAAE,IAC3D,IACN;GAEF,IAAI,MAAM,SAAS,qBACjB,oBAAoB,SAClB,MAAM,YACF,KAAK,QAAQ,SAAS,KAAK,OAAQ,MAAM,UAAgB,EAAE,IAC3D,IACN;GAEF,IAAI,CAAC,oBAAoB,mBAAmB,EAAE,SAAS,MAAM,IAAI,GAC/D,oBAAoB,SAClB,MAAM,YAAY,CAAC,MAAM,WAAgB,GAAG,IAAI,IAAI,IACtD;EAEJ;EAEA,MAAM,yBAAyB,OAAO,GAAG,oBAAoB,eAAe;EAC5E,MAAM,0BAA0B,OAAO,GAAG,qBAAqB,eAAe;EAC9E,MAAM,0BAA0B,OAAO,GAAG,qBAAqB,eAAe;EAE9E,aAAa;GACX,uBAAuB,YAAY;GACnC,wBAAwB,YAAY;GACpC,wBAAwB,YAAY;EACtC;CACF,GAAG;EAAC;EAAQ;EAAU;CAAe,CAAC;CAEtC,OAAO;AACT;;;ACtDA,IAAa,sBACX,cACA,kBACG;CACH,MAAM,uBAAuB,cAEzB,IAAI,WAAoC;EACtC,aAAa;EACb,OAAO,CAAC;EACR,iBAAiB,CAAC;EAClB,SAAS;CACX,CAAC,GACH,CAAC,CACH;CAEA,MAAM,WAAW,YAAY,YAAY;EACvC,MAAM,EAAE,SAAS,MAAM,gBAAgB,qBAAqB,eAAe;EAC3E,IAAI,gBAAgB,QAAQ,SAAS;EAErC,qBAAqB,YAAY,EAAE,SAAS,KAAK,CAAC;EAElD,IAAI;GACF,MAAM,EAAE,OAAO,SAAS,MAAM,aAAa,WAAW;GACtD,qBAAqB,MAAM,UAAU;IACnC,GAAG;IACH,aAAa,CAAC,CAAC;IACf,OAAO,OAAO,KAAK,MAAM,OAAO,KAAK,GAAG,IAAI;IAC5C,iBAAiB;IACjB,MAAM,QAAQ;GAChB,EAAE;EACJ,SAAS,OAAO;GACd,qBAAqB,YAAY,EAAS,MAAe,CAAC;EAC5D;EACA,qBAAqB,YAAY,EAAE,SAAS,MAAM,CAAC;CACrD,GAAG,CAAC,sBAAsB,YAAY,CAAC;CAEvC,gBAAgB;EACd,MAAM,EAAE,UAAU,qBAAqB,eAAe;EACtD,IAAI,CAAC,iBAAiB,MAAM,QAAQ;EACpC,SAAS;CACX,GAAG;EAAC;EAAsB;EAAe;CAAQ,CAAC;CAElD,OAAO;EACL;EACA;CACF;AACF;;;ACnDA,IAAM,6BACJ,UAC0C;CAC1C,MAAM;CACN,MAAM;CACN,MAAM;AACR;AAMA,IAAa,2BAA2B,EACtC,qBACiC,CAAC,MAAM;CACxC,MAAM,EAAE,SAAS,eAAe;CAgBhC,MAAM,EAAE,sBAAsB,aAAa,mBAdtB,YACnB,OAAO,SAAS;EACd,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,KAAK,aAAa;GACvD,QAAQ,kBAAkB;GAC1B,SAAS,CAAC,OACN,kBAAkB,UAClB;IAAE,GAAG,kBAAkB;IAAS;GAAK;GACzC,MAAM;IAAE,YAAY;IAAI,GAAG,kBAAkB;GAAK;EACpD,CAAC;EACD,OAAO;GAAE,OAAO;GAAO,MAAM;EAAQ;CACvC,GACA,CAAC,kBAAkB,IAAI,CAGqC,GAAc,IAAI;CAChF,MAAM,UAAU,2BAAuC,UAAU,oBAAoB;CACrF,MAAM,CAAC,OAAO,aAAa,WAAW,cACpC,sBACA,yBACF;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;AC7CA,IAAM,2BACJ,UAC0C;CAC1C,MAAM;CACN,MAAM;CACN,MAAM;AACR;AAMA,IAAa,gCAAgC,EAC3C,uBACwC;CACxC,MAAM,EAAE,SAAS,eAAe;CAgBhC,MAAM,EAAE,sBAAsB,aAAa,mBAdtB,YACnB,OAAO,SAAS;EACd,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,KAAK,iBAAiB;GAC3D,QAAQ,iBAAiB;GACzB,SAAS,CAAC,OACN,kBAAkB,UAClB;IAAE,GAAG,kBAAkB;IAAS;GAAK;GACzC,MAAM;IAAE,YAAY;IAAI,GAAG,kBAAkB;GAAK;EACpD,CAAC;EACD,OAAO;GAAE,OAAO;GAAO,MAAM;EAAQ;CACvC,GACA,CAAC,kBAAkB,IAAI,CAGqC,GAAc,IAAI;CAChF,MAAM,QAAQ,2BACZ,QACA,sBACA,iBAAiB,OAAO,SAC1B;CACA,MAAM,CAAC,OAAO,aAAa,WAAW,cACpC,sBACA,uBACF;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;ACnDA,IAAM,wBAAsB,UAAiB;CAC3C,IAAI,iBAAiB,cAAc,MAAM,WAAW,GAClD,MAAM,eAAe;AAEzB;AAgBA,IAAa,2BACX,UACG;CACH,MAAM,EACJ,UACA,WACA,gBACA,qBAAqB,KACrB,0BACA,uBACA,YAAA,KACA,aAAa,OACb,GAAG,mBACD;CAEJ,MAAM,UAAU,OAA8B,IAAI;CAClD,MAAM,WAAW,OAA8B,IAAI;CAEnD,MAAM,iBAAiB,cAEnB,eAAe;EACb,MAAM,OAAO,QAAQ;EACrB,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,QAAQ,KAAK,iBAAiB,QAAQ,CAAC,OAC1C;EAGF,MAAM,qBACJ,MAAM,eAAe,KAAK,YAAY,KAAK;EAC7C,MAAM,kBAAkB,KAAK;EAE7B,IAAI,gBACF,eAAe,oBAAoB,iBAAiB,SAAS;EAG/D,IAAI,kBAAkB,OAAO,SAAS,GACpC,wBAAwB;EAG1B,IAAI,qBAAqB,OAAO,SAAS,GACvC,2BAA2B;CAE/B,GAAG,kBAAkB,GACvB;EACE;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,gBAAgB;EACd,MAAM,gBAAgB,QAAQ;EAC9B,IAAI,CAAC,eAAe;EAEpB,cAAc,iBAAiB,UAAU,gBAAgB,UAAU;EAEnE,aAAa;GACX,cAAc,oBAAoB,UAAU,gBAAgB,UAAU;EACxE;CACF,GAAG,CAAC,gBAAgB,UAAU,CAAC;CAE/B,gBAAgB;EACd,MAAM,OAAO,QAAQ;EACrB,IAAI,CAAC,QAAQ,OAAO,mBAAmB,eAAe,CAAC,gBAAgB;EACvE,MAAM,WAAW,IAAI,eAAe,cAAc;EAClD,SAAS,QAAQ,IAAe;EAEhC,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG,CAAC,cAAc,CAAC;CAEnB,gBAAgB;EACd,MAAM,OAAO,QAAQ;EACrB,IAAI,MACF,KAAK,iBAAiB,SAAS,sBAAoB,EAAE,SAAS,MAAM,CAAC;EAEvE,aAAa;GACX,IAAI,MACF,KAAK,oBAAoB,SAAS,sBAAoB,UAAU;EAEpE;CACF,GAAG,CAAC,UAAU,CAAC;CAEf,OACE,oBAAC,OAAD;EACE,GAAI;EACJ,WAAW,KAAK,uCAAuC,SAAS;EAChE,KAAK;YAEL,oBAAC,OAAD;GAAK,WAAU;GAA+C,KAAK;GAChE;EACE,CAAA;CACF,CAAA;AAET;;;AC1GA,IAAM,uBAAqB,eAAwD;CACjF,WAAW,UAAU;CACrB,WAAW,UAAU;AACvB;AAMA,IAAa,kBAAkB,EAAE,6BAAkD;CACjF,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,UAAU,gBAAgB;CAClC,MAAM,EAAE,cAAc,cAAc,KAAK,OAAO,mBAAiB;CAEjE,MAAM,EAAE,SAAS,OAAO,aAAa,SAAS,aAAa,wBAAwB;CAEnF,OACE,qBAAC,OAAO,MAAR;EAAa,WAAU;YAAvB,CACE,oBAAC,OAAO,QAAR;GACS;GACP,aAAa,EAAE,6CAA6C;GAC5D,OAAO,EAAE,eAAe;EACzB,CAAA,GACD,qBAAC,OAAO,MAAR;GAAa,WAAU;aAAvB,CACE,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,yBAAD;KAAyB,0BAA0B;KAAU,WAAW;eAAxE,CACG,QAAQ,KAAK,WACZ,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,qBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,OAAO,eACN,oBAAC,KAAD;QAAG,WAAU;kBAA+B,OAAO;OAAe,CAAA,GAEpE,oBAAC,UAAD,EAAyC,MAAM,OAAS,GAAzC,aAAa,OAAO,IAAqB,CACrD;UACJ,CAAC,aAAa,OAAO,MAAM,OAAO,OAAO,MAAM,MAC9C,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,QAAD;QACE,YAAW;QACX,WAAU;QACV,SAAS;QACT,MAAK;QACL,SAAQ;kBAEP,EAAE,qBAAqB;OAClB,CAAA;MACL,CAAA,CAEJ;QApBuC,WAAW,OAAO,IAoBzD,CACN,GAEA,eACC,oBAAC,OAAD;MAAK,WAAU;gBACZ,WAAW,oBAAC,kBAAD,CAAmB,CAAA;KAC5B,CAAA,CAEgB;;GACtB,CAAA,GACJ,OAAO,WAAW,oBAAC,OAAD,EAAA,UAAM,OAAO,QAAa,CAAA,CAClC;IAaF;;AAEjB;;;ACtFA,IAAM,uBAAqB,eAAwD;CACjF,mBAAmB,UAAU;CAC7B,uBAAuB,UAAU;AACnC;AAMA,IAAa,+BAA+B,EAC1C,eACsC;CACtC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,mBAAmB,0BAA0B,cACnD,KAAK,OACL,mBACF;CAEA,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACG,kBAAkB,WAAW,KAAK,kBAAkB,OAAO,YAC1D,oBAAC,YAAD,CAAa,CAAA,GAEf,oBAAC,QAAD;GAAM,WAAU;aACb,EAAE,mBAAmB,EAAE,OAAO,sBAAsB,aAAa,EAAE,CAAC;EACjE,CAAA,CACH;;AAET;AAOA,IAAa,6BAA6B,EACxC,QACA,wBACoC;CACpC,MAAM,EAAE,MAAM,sBAAsB;CAEpC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD;GAAK,WAAU;aACZ,EAAE,mCAAmC,EAAE,kBAAkB,CAAC;EACxD,CAAA,GACL,qBAAC,OAAD;GAAK,WAAU;aAAf,CACE,oBAAC,OAAD;IAAK,WAAU;cAAsC,OAAO;GAAU,CAAA,GACtE,oBAAC,6BAAD,EAA6B,UAAU,OAAO,GAAK,CAAA,CAChD;IACF;;AAET;;;AC9CA,IAAM,uBAAqB,eAAwD,EACjF,wBAAwB,UAAU,uBACpC;AASA,IAAa,uBAAuB,EAClC,mBACA,QACA,aACA,mBAC8B;CAC9B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,sBAAsB,CAAC,MAAM,uBAAuB,qBAAqB;CACjF,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,2BAA2B,cAAc,KAAK,OAAO,mBAAiB;CAE9E,MAAM,QAAQ,0BAA0B,uBAAuB,OAAO;CACtE,MAAM,YAAY,OAAO,UAAU;CACnC,MAAM,iBAAiB,OAAO,sBAAsB;CAEpD,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,yBAAyB;GACvC,yCACE,kBAAkB,YAAY;GAChC,oCAAoC;EACtC,CAAC;YALH;GAOE,oBAAC,2BAAD;IAAmC;IAAQ,mBAAmB;GAAc,CAAA;GAC3E,CAAC,CAAC,SAAS,oBAAC,iBAAD,EAAiB,OAAO,MAAM,MAAM,GAAG,iBAAiB,EAAI,CAAA;GACvE,oBAAoB,uBACnB,gBACA,kBACA,OAAO,SAAS,qBACd,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,QAAD;KACE,YAAW;KACX,WAAU;KACV,SAAS;KACT,MAAK;KACL,SAAQ;eAEP,EAAE,UAAU;IACP,CAAA;GACL,CAAA;EAEN;;AAET;;;ACjEA,IAAa,gBAAgB,EAAE,eAAkC;CAC/D,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD;GAAK,WAAU;aAAyC,EAAE,UAAU;EAAO,CAAA,GAC3E,oBAAC,OAAD;GAAK,WAAU;aAAwC;EAAc,CAAA,CAClE;;AAET;;;ACDA,IAAa,2BAA2B,EACtC,QACA,wBACkC;CAKlC,MAAM,EAAE,aAAa,SAAS,UAAU,UAAU,6BAA6B,EAC7E,kBALuB,eAChB,EAAE,QAAQ,EAAE,WAAW,OAAO,GAAG,EAAE,IAC1C,CAAC,OAAO,EAAE,CAGV,EACF,CAAC;CAED,OACE,oBAAC,yBAAD;EAAyB,0BAA0B;EAAU,WAAW;YACtE,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,OAAD;KAAK,WAAU;eAAf;MACE,oBAAC,2BAAD;OACU;OACW;MACpB,CAAA;MACD,oBAAC,iBAAD,EAAwB,MAAQ,CAAA;MAC/B,eACC,oBAAC,OAAD;OAAK,WAAU;iBACZ,WAAW,oBAAC,kBAAD,CAAmB,CAAA;MAC5B,CAAA;KAEJ;;GACF,CAAA;EACF,CAAA;CACkB,CAAA;AAE7B;;;AC9BA,IAAM,uBAAqB,EACzB,MACA,SACA,YACA,6BACgB;CAChB;CACA,SAAS,CAAC,GAAG,OAAO;CACpB;CACA;AACF;AAEA,IAAa,oBAAoB;CAC/B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,UAAU,gBAAgB;CAClC,MAAM,EAAE,MAAM,SAAS,YAAY,0BAA0B,cAC3D,KAAK,OACL,mBACF;CACA,MAAM,CAAC,cAAc,mBAAmB,SAG9B,IAAI;CAEd,MAAM,SAAS,kBAAkB,gBAAgB,IAAI,GAAG,CAAC,CAAC;CAE1D,OACE,oBAAC,OAAO,MAAR;EACE,WAAW,KAAK,iCAAiC,EAC/C,gDAAgD,aAClD,CAAC;YAEA,cAAc,SACb,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAO,QAAR;GACS;GACP,aAAa,EAAE,kCAAkC;GACzC;GACR,OAAO,EAAE,OAAO;EACjB,CAAA,GACD,oBAAC,OAAO,MAAR;GAAa,WAAU;aACrB,oBAAC,yBAAD;IACE,QAAQ,cAAc;IACtB,mBAAmB,cAAc;GAClC,CAAA;EACU,CAAA,CACb,EAAA,CAAA,IAEF,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAO,QAAR;GACS;GACP,aAAa,EACX,8DACF;GACA,OAAO,EAAE,cAAc;EACxB,CAAA,GACD,qBAAC,OAAO,MAAR;GAAa,WAAU;aAAvB,CACE,oBAAC,cAAD,EAAc,UAAU,KAAO,CAAA,GAC/B,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eACZ,QACE,MAAM,MAAM,aACV,sBAAsB,QAAQ,OAAO,OACrC,sBAAsB,KAAK,OAAO,KAC/B,IACA,EACN,EACC,KAAK,QAAQ,MAAM;MAClB,MAAM,oBAAoB,IAAI;MAC9B,OACE,oBAAC,qBAAD;OACE,mBAAA;OAEQ;OACR,aAAa;OACb,oBACE,gBAAgB;QAAE;QAAQ;OAAkB,CAAC;MAEhD,GANM,eAAe,OAAO,IAM5B;KAEL,CAAC;IACA,CAAA,GACL,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,OAAD;MAAK,WAAU;gBACZ,EAAE,kBAAkB,EAAE,OAAO,WAAW,CAAC;KACvC,CAAA;IACF,CAAA,CACF;KACM;IACb,EAAA,CAAA;CAEO,CAAA;AAEjB;;;ACtFA,IAAM,qBAAqB;AAS3B,IAAM,uBAAqB,eAA0B;CACnD,eAAe,UAAU;CACzB,8BAA8B,UAAU;CACxC,eAAe,UAAU;CACzB,eAAe,UAAU;CACzB,WAAW,UAAU;CACrB,SAAS,UAAU;CACnB,WAAW,UAAU;CACrB,WAAW,UAAU;AACvB;AAUA,IAAa,eAAe,EAC1B,kBAAA,qBAAmB,kBACnB,cAAA,iBAAe,cACf,gBAAA,mBAAiB,gBACjB,aAAA,gBAAc,aACd,wBAAwB,8BACF;CACtB,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,MAAM,sBAAsB,aAAa;CACjD,MAAM,EAAE,sBAAsB,CAAC,MAAM,uBAAuB,aAAa;CACzE,MAAM,EAAE,YAAY,kBAAkB,aAAa;CACnD,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EACJ,eACA,8BACA,eACA,eACA,WACA,SACA,WACA,cACE,cAAc,KAAK,OAAO,mBAAiB;CAC/C,MAAM,CAAC,WAAW,gBAAgB,SAAgC;CAElE,MAAM,cAAc,oBAAoB,qBAAqB,CAAC;CAC9D,MAAM,aAAa,kBAAkB,aAAa,KAAA,CAAS,GAAG,CAAC,CAAC;CAChE,MAAM,sBAAsB,kBAAkB,aAAa,aAAa,GAAG,CAAC,CAAC;CAS7E,IAAI,EAND,CAAC,aAAa,kBAAkB,OAAO,MAAM,MAC9C,CAAC,CAAC,aACD,eAAe,gCAAgC,QAAQ,SAAA,OACvD,CAAC,aAAa,iBACd,gBAAgB,KAAK,oBAAoB,sBAE1B,OAAO;CAEzB,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,CAAC,aAAa,kBAAkB,OAAO,MAAM,MAC5C,oBAAC,YAAD;IACE,YAAY,EAAE,UAAU;IACZ;IACZ,gBAAgB,KAAK,oBAAoB,0BAA0B;IACnE,aAAa,cAAc;IAC3B,iBAAiB,aAAa,UAAU;cAExC,oBAAC,gBAAD,CAAe,CAAA;GACL,CAAA;GAGb,CAAC,CAAC,aACD,oBAAC,YAAD;IACE,YAAY,EAAE,cAAc;IAChB;IACZ,gBAAgB,KAAK,oBAAoB,8BAA8B;IACvE,aAAa,cAAc;IAC3B,iBAAiB,aAAa,cAAc;cAE5C,oBAAC,eAAD,CAAc,CAAA;GACJ,CAAA;GAGb,eACC,gCACA,QAAQ,SAAA,OACN,oBAAC,YAAD;IACE,YAAY,EAAE,mBAAmB;IACrB;IACZ,oBAAA;IACA,gBAAgB,KACd,oBACA,qCACF;IACA,aAAa,cAAc;IAC3B,iBAAiB,aAAa,gBAAgB;cAE9C,oBAAC,uBAAD,CAAwB,CAAA;GACd,CAAA;GAGf,CAAC,aAAa,iBACb,oBAAC,YAAD;IACE,YAAY,YAAY,EAAE,qBAAqB,IAAI,EAAE,eAAe;IACxD;IACZ,oBAAA;IACA,gBAAgB,KAAK,oBAAoB,iCAAiC;IAC1E,aAAa,cAAc;IAC3B,iBAAiB,aAAa,aAAa;cAE3C,oBAAC,oBAAD,EAAkB,WAAW,QAAQ,GAAK,CAAA;GAChC,CAAA;GAGb,gBAAgB,KAAK,oBAAoB,uBACxC,oBAAC,YAAD;IACE,YAAY,EAAE,2BAA2B,EAAE,OAAO,cAAc,CAAC;IACrD;IACZ,oBAAA;IACA,gBAAgB,KAAK,oBAAoB,kCAAkC;IAC3E,aAAa,cAAc;IAC3B,iBAAiB,aAAa,eAAe;cAE7C,oBAAC,kBAAD,EAAgB,wBAAwB,oBAAsB,CAAA;GACpD,CAAA;EAEX;;AAET;;;AC3IA,IAAa,aAAa,EAAE,QAAQ,gBAClC,oBAAC,OAAD;CACE,eAAY;CACZ,WAAW,KAAK,wBAAwB,SAAS;CACjD,eAAY;CACZ,OACE,EACE,sCAAsC,SAAS,IACjD;AAEH,CAAA;AAKH,IAAa,aAAa,EAAE,cAC1B,oBAAC,OAAD,EACE,WAAW,KAAK,uBAAuB,EAAE,gCAAgC,QAAQ,CAAC,EACnF,CAAA;AAWH,IAAM,uBAAqB,eAAwD;CACjF,WAAW,UAAU;CACrB,wBAAwB,UAAU;CAClC,mBAAmB,UAAU;CAC7B,oBAAoB,UAAU;CAC9B,uBAAuB,UAAU;CACjC,mBAAmB,UAAU;AAC/B;AAQA,IAAa,sBAAsB,EACjC,oBACA,QACA,uBAC6B;CAC7B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,sBAAsB,CAAC,MAAM,uBAAuB,sBAAsB;CAClF,MAAM,EAAE,YAAY,kBAAkB;CACtC,MAAM,EAAE,aAAA,gBAAc,gBAAuB,oBAAoB;CACjE,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EACJ,WACA,wBACA,mBACA,oBACA,uBACA,sBACE,cAAc,KAAK,OAAO,mBAAiB;CAE/C,MAAM,cAAc,oBAAoB,qBAAqB,CAAC;CAC9D,MAAM,gBAAgB,CAAC,CAAC;CACxB,MAAM,aAAa,CAAC,CAAC,mBAAmB,OAAO;CAC/C,MAAM,qBAAqB,kBAAkB,KACzC,sBAAsB,kBAAkB,MACxC;CAEJ,MAAM,aAAa,cAEf,eAAe;EACb,IAAI,CAAC,aAAa;EAElB,OAAO,CADwB,CAAC,mBAAmB,OAAO,MAEtD,KAAK,WAAW,mBAAmB,OAAO,IAAI,IAAI,QAAQ,EAAE,IAC5D,KAAK,SAAS,OAAO,IAAI,QAAQ,EAAE;CACzC,GAAG,GAAG,GACR;EAAC;EAAa,QAAQ;EAAI,OAAO;EAAI;EAAoB;CAAI,CAC/D;CAEA,MAAM,oBAAoB,cAEtB,yBAAyB,OAAO,OAC/B,uBAAuB,OAAO,IAC5B,QAAQ,SAAS,CAAC,CAAC,KAAK,QAAQ,CAAC,aAAa,IAAI,CAAC,EACnD,MAAM,GAAG,kBAAkB,EAC3B,KAAK,EAAE,YAAY;EAClB,IAAI,KAAM;EACV,UAAU,KAAM;EAChB,UAAU,KAAM;CAClB,EAAE,GACN;EAAC;EAAoB;EAAwB,OAAO;CAAE,CACxD;CAEA,OACE,qBAAC,OAAD;EACE,gBAAc,gBAAgB,aAAa,KAAA;EAC3C,WAAW,KAAK,yBAAyB,EACvC,kCAAkC,YACpC,CAAC;EAED,SAAS,gBAAgB,aAAa,KAAA;EACtC,WACE,iBACK,UAAU;GACT,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;GAChD,MAAM,eAAe;GACrB,WAAW;EACb,IACA,KAAA;EAEN,MAAM,gBAAgB,WAAW,KAAA;EACjC,UAAU,gBAAgB,IAAI,KAAA;YAjBhC;GAmBG,eAAe,oBAAC,WAAD,EAAW,SAAS,WAAa,CAAA;GACjD,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,KAAD;KAAG,WAAU;eAA8B,OAAO;IAAQ,CAAA,GAC1D,qBAAC,OAAD;KAAK,WAAU;eAAf,CACG,sBAAsB,sBAAsB,YAC3C,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,eAAD;OAAa,aAAa;OAAmB,MAAK;MAAM,CAAA;KACrD,CAAA,GAEP,oBAAC,OAAD;MAAK,WAAU;gBACZ,mBACG,EAAE,mBAAmB,EACnB,OAAO,sBAAsB,OAAO,OAAO,EAC7C,CAAC,IACA,sBAAsB,OAAO,OAAO;KACtC,CAAA,CACF;MACF;;GACL,oBAAC,WAAD;IACE,SACG,uBACE,sBAAsB,OAAO,OAAO,KAAK,sBAAsB;IAEpE,WAAW,KAAK,oCAAoC,EAClD,4CACE,aACA,kBAAkB,WAAW,KAC7B,kBAAkB,OAAO,OAAO,GACpC,CAAC;GACF,CAAA;EACE;IA5CE,oBAAoB,OAAO,IA4C7B;AAET;;;ACzJA,IAAM,uBAAqB,eAAwD,EACjF,SAAS,UAAU,QACrB;AAOA,IAAa,kBAAkB,EAC7B,qBACA,qBAAA,wBAAsB,0BACG;CACzB,MAAM,EAAE,oBAAA,uBAAqB,uBAA8B,oBAAoB;CAC/E,MAAM,EAAE,MAAM,sBAAsB,gBAAgB;CACpD,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,YAAY,cAAc,KAAK,OAAO,mBAAiB;CAC/D,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,KAAK;CAClE,MAAM,sBAAsB,kBAAkB,sBAAsB,KAAK,GAAG,CAAC,CAAC;CAC9E,MAAM,qBAAqB,kBAAkB,sBAAsB,IAAI,GAAG,CAAC,CAAC;CAE5E,MAAM,wBACJ,OAAO,wBAAwB,YAAY,QAAQ,SAAS;CAE9D,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EACE,WAAW,KAAK,8BAA8B,EAC5C,oCAAoC,OAAO,wBAAwB,YACrE,CAAC;YAEA,QAAQ,MAAM,GAAG,uBAAuB,QAAQ,MAAM,EAAE,KAAK,WAC5D,oBAAC,sBAAD;GACE,oBAAoB;GAEZ;EACT,GAFM,eAAe,OAAO,IAE5B,CACF;CACE,CAAA,GACJ,yBACC,oBAAC,YAAD;EACE,YAAY,EAAE,2BAA2B,EACvC,OAAO,QAAQ,OACjB,CAAC;EACD,YAAY;EACZ,oBAAA;EACA,gBAAe;EACf,aAAa;EACb,WAAW;YAEX,oBAAC,uBAAD,CAAsB,CAAA;CACZ,CAAA,CAEd,EAAA,CAAA;AAEN;;;AC5DA,IAAM,qBAAqB,eAAwD,EACjF,MAAM,UAAU,KAClB;AAEA,IAAa,4BAA4B;CACvC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,UAAU,gBAAgB;CAClC,MAAM,EAAE,SAAS,cAAc,KAAK,OAAO,iBAAiB;CAE5D,OACE,qBAAC,OAAO,MAAR;EAAa,WAAW;YAAxB,CACE,oBAAC,OAAO,QAAR;GACS;GACP,aAAa,EAAE,2CAA2C;GAC1D,OAAO,EAAE,cAAc;EACxB,CAAA,GACD,qBAAC,OAAO,MAAR;GAAa,WAAU;aAAvB,CACE,oBAAC,cAAD,EAAc,UAAU,KAAO,CAAA,GAC/B,oBAAC,gBAAD,CAAiB,CAAA,CACN;IACF;;AAEjB;;;ACtBA,IAAM,gCACJ,eAC6C,EAAE,WAAW,UAAU,UAAU;AAChF,IAAa,oBAAoB;CAC/B,MAAM,EAAE,aAAA,gBAAc,aAAoB,YAAA,eAAa,eACrD,oBAAoB;CACtB,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,EAAE,cAAc,cAAc,KAAK,OAAO,4BAA4B;CAE5E,OACE,qBAAC,OAAD;EAAK,WAAW,KAAK,kBAAkB,EAAE,0BAA0B,UAAU,CAAC;YAA9E;GACE,oBAAC,cAAD,CAAa,CAAA;GACb,oBAAC,gBAAD,EAAgB,qBAAA,EAA6C,CAAA;GAC7D,oBAAC,eAAD,CAAc,CAAA;EACX;;AAET;;;ACtBA,IAAa,QAAQ,EAAE,WAAgC;CACrD,MAAM,EAAE,aAAA,gBAAc,gBAAuB,oBAAoB;CACjE,IAAI,CAAC,MAAM,OAAO;CAClB,OACE,oBAAC,cAAD;EAAoB;YAClB,oBAAC,eAAD,CAAc,CAAA;CACF,CAAA;AAElB;;;ACJA,IAAM,+BAA6B,WAA8B;CAC/D,qBAAqB,MAAM,KAAK;CAChC,OAAO,MAAM,OAAO;CACpB,mBAAmB,MAAM,KAAK;AAChC;AAEA,IAAa,6BAA6B;CACxC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,iBAAiB,6BAA6B;CACtD,MAAM,EAAE,qBAAqB,OAAO,sBAAsB,cACxD,aAAa,OACb,2BACF;CACA,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAC9D,MAAM,mBAAmB,OAAgC,IAAI;CAE7D,MAAM,wBAAwB,eACrB;EACL,kCAAkC,EAAE,gCAAgC;EACpE,8BAA8B,EAAE,4BAA4B;CAC9D,IACA,CAAC,CAAC,CACJ;CAEA,MAAM,uBAAuB,CAAC;CAC9B,MAAM,YAAY,SAAS,sBAAsB;CACjD,MAAM,oBAAoB;CAC1B,MAAM,yBAAyB,GAAG,kBAAkB;CAEpD,OACE,qBAAC,OAAD;EAAK,WAAW,KAAK,mCAAmC,CAAC,CAAC;YAA1D,CACE,oBAAC,aAAD;GACE,SAAS;GACT,aAAa,EAAE,6BAA6B;GAC5C,IAAG;GACH,WAAW,MAAM;IACf,oBAAoB,KAAK;IACzB,aAAa,aAAa,EAAE,qBAAqB,CAAC,EAAE,OAAO,QAAQ,CAAC;GACtE;GACA,OAAO,EAAE,gBAAgB;EAC1B,CAAA,GACA,wBACC,oBAAC,aAAD;GACE,mBAAiB;GACjB,SAAS;GACT,gBAAe;GACf,IAAI;GACJ,WAAW,UAAU;IACnB,MAAM,uBAAuB,MAAM,OAAO;IAC1C,oBAAoB,oBAAoB;IACxC,aAAa,aAAa,EAAE,mBAAmB,IAAI,CAAC;IACpD,IAAI,CAAC,sBAAsB;IAC3B,4BAA4B;KAC1B,iBAAiB,SAAS,MAAM;IAClC,CAAC;GACH;aAEA,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,kBAAD;KACE,SAAS,CAAC,CAAC;KACX,aAAa,EAAE,gCAAgC;KAC/C,SAAS;KACT,IAAI;KACJ,OAAO,EAAE,wBAAwB;IAClC,CAAA,GACA,oBACC,oBAAC,cAAD;KACE,cAAY,EAAE,0BAA0B;KACxC,IAAG;KACH,KAAK;KACL,KAAK;KACL,cAAc;MACZ,aAAa,gBAAgB,mBAAmB;KAClD;KACA,WAAW,MAAM;MACf,MAAM,MAAM,EAAE,OAAO;MACrB,MAAM,wBACJ,QAAQ,MAAM,CAAC,QAAQ,KAAK,GAAG,IAC3B,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,IACnD,KAAA;MACN,aAAa,aACX,EACE,mBAAmB,wBACf,aAAa,oBACb,IACN,GACA,qBACF;KACF;KACA,KAAK;KACL,OAAO,qBAAqB;IAC7B,CAAA,CAEA;;EACM,CAAA,CAEZ;;AAET;;;ACnGA,IAAM,+BAA6B,WAA8B;CAC/D,OAAO,MAAM,OAAO;CACpB,MAAM,MAAM,KAAK;AACnB;AAEA,IAAa,kBAAkB;CAC7B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,iBAAiB,6BAA6B;CACtD,MAAM,EAAE,aAAa,gBAAgB;CACrC,MAAM,EAAE,kBAAkB,mBAAmB,QAAQ;CACrD,MAAM,EAAE,OAAO,SAAS,cAAc,aAAa,OAAO,2BAAyB;CACnF,MAAM,wBAAwB,eACrB,EACL,wBAAwB,EAAE,sBAAsB,EAClD,IACA,CAAC,CAAC,CACJ;CAEA,OACE,oBAAC,WAAD;EACE,oBAAkB;EAClB,WAAU;EACV,OAAO,CAAC,CAAC;EACT,cACE,QACE,oBAAC,QAAD;GAAM,eAAY;aACf,sBAAsB,UAAU,EAAE,OAAO;EACtC,CAAA,IACJ,KAAA;EAEN,IAAG;EACH,OAAO,EAAE,UAAU;EACnB,cAAc;GACZ,aAAa,gBAAgB,MAAM;EACrC;EACA,WAAW,MAAM;GACf,aAAa,aAAa,EAAE,MAAM,EAAE,OAAO,MAAM,CAAC;EACpD;EACA,aAAa,EAAE,gBAAgB;EAC/B,MAAK;EACL,OAAO;CACR,CAAA;AAEL;;;ACxCA,IAAM,+BAA6B,WAA8B;CAC/D,QAAQ,MAAM,OAAO;CACrB,SAAS,MAAM,KAAK;AACtB;AAEA,IAAa,uBAAuB;CAClC,MAAM,EAAE,iBAAiB,6BAA6B;CACtD,MAAM,EAAE,QAAQ,YAAY,cAC1B,aAAa,OACb,2BACF;CACA,MAAM,EAAE,MAAM,sBAAsB,gBAAgB;CAEpD,MAAM,wBAAwB,eACrB;EACL,yBAAyB,EAAE,uBAAuB;EAClD,mBAAmB,EAAE,iBAAiB;CACxC,IACA,CAAC,CAAC,CACJ;CAEA,MAAM,gBAAgB,aACnB,aAAuB;EACtB,MAAM,cAAc,aAAa;EACjC,aAAa,aAAa,EAAE,SAAS,SAAS,KAAK,UAAU,YAAY,MAAM,EAAE,CAAC;CACpF,GACA,CAAC,YAAY,CACf;CAEA,MAAM,cAAc,aACjB,oBAA4B;EAC3B,aAAa,aAAa,EACxB,SAAS,aAAa,QAAQ,QAAQ,WAAW,OAAO,OAAO,eAAe,EAChF,CAAC;CACH,GACA,CAAC,YAAY,CACf;CAEA,MAAM,YAAY,QAAQ,SAAS;CAEnC,OACE,oBAAC,mBAAD;EACa;EACX,OAAO,EAAE,SAAS;EACH;YAEd,QAAQ,KAAK,QAAQ,MAAM;GAC1B,MAAM,QAAQ,SAAS,OAAO;GAC9B,OACE,oBAAC,OAAD;IACE,WAAW,KAAK,+BAA+B;KAC7C,0CAA0C;KAC1C,0CAA0C;IAC5C,CAAC;cAGD,oBAAC,WAAD;KACE,WAAU;KACV,OAAO,CAAC,CAAC;KACT,uBAAsB;KACtB,IAAI,OAAO;KACX,SACE,YAAY,oBAAC,aAAD,EAAa,WAAU,wBAAyB,CAAA,IAAI,KAAA;KAElE,SACE,QACE,oBAAC,QAAD;MAAM,eAAY;gBACf,sBAAsB,UAAU,EAAE,OAAO;KACtC,CAAA,IACJ,KAAA;KAEN,cAAc;MACZ,aAAa,gBAAgB,SAAS;KACxC;KACA,WAAW,MAAM;MACf,aAAa,aAAa,EACxB,SAAS;OAAE,OAAO;OAAG,MAAM,EAAE,OAAO;MAAM,EAC5C,CAAC;KACH;KACA,UAAU,UAAU;MAClB,MAAM,2BAA2B,MAAM,QAAQ,SAAS;MACxD,IAAI,MAAM,QAAQ,WAAW,CAAC,0BAA0B;OACtD,MAAM,cAAc,QAAQ,IAAI,GAAG;OACnC,SAAS,eAAe,WAAW,GAAG,MAAM;MAC9C;KACF;KACA,aAAa,EAAE,eAAe;KAC9B,UACE,OAAO,OACL,oBAAC,oBAAD;MACE,cAAY,EAAE,oBAAoB;MAClC,eAAe,YAAY,OAAO,EAAE;KACrC,CAAA,IACC,KAAA;KAEN,MAAK;KACL,OAAO,OAAO;IACf,CAAA;GACE,GA5CE,mBAAmB,GA4CrB;EAET,CAAC;CACgB,CAAA;AAEvB;AAEA,IAAM,sBAAsB,EAAE,WAAW,GAAG,YAC1C,oBAAC,QAAD;CACE,YAAW;CACX,UAAA;CACA,WAAW,KAAK,wCAAwC,SAAS;CACjE,MAAK;CACL,SAAQ;CACR,GAAI;WAEJ,oBAAC,iBAAD,CAAkB,CAAA;AACZ,CAAA;;;AClHV,IAAa,8BAA8B,EACzC,YACqC;CACrC,MAAM,EAAE,MAAM,sBAAsB,4BAA4B;CAChE,MAAM,EAAE,cAAc,wBAAwB,0BAA0B;CACxE,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,gBAAgB,iBAAiB;CAEvC,OACE,oBAAC,OAAO,QAAR,EAAA,UACE,qBAAC,OAAO,gBAAR,EAAA,UAAA,CACE,oBAAC,OAAO,+BAAR;EACE,WAAW,KAAK,mDAAmD;EACnE,eAAe;GACb,gBAAgB,aAAa,UAAU;GACvC,MAAM;EACR;EACA,MAAK;YAEJ,EAAE,QAAQ;CACyB,CAAA,GACtC,qBAAC,OAAO,6BAAR;EACE,WAAW,KAAK,mDAAmD;EACnE,UAAU,CAAC;EACX,eAAe;GACb,gBACG,WAAW,EACX,WAAW,oBAAoB,CAAC,EAChC,WAAW;IACV,gBAAgB,aAAa,UAAU;IACvC,MAAM;GACR,CAAC,EACA,MAAM,QAAQ,KAAK;EACxB;EACA,MAAK;YAbP,CAeE,oBAAC,UAAD,CAAW,CAAA,GACV,EAAE,WAAW,CACoB;GACf,EAAA,CAAA,EACV,CAAA;AAEnB;;;ACrCA,IAAM,6BAA6B,WAA8B;CAC/D,eAAe,MAAM,KAAK;CAC1B,8BAA8B,MAAM,KAAK;CACzC,mBAAmB,MAAM,KAAK;AAChC;AAEA,IAAa,sBAAsB,EAAE,YAAqC;CACxE,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,iBAAiB,6BAA6B;CACtD,MAAM,EAAE,eAAe,8BAA8B,sBACnD,cAAc,aAAa,OAAO,yBAAyB;CAE7D,MAAM,UAAU,kBAAkB;EAChC,aAAa,UAAU;EACvB,MAAM;CACR,GAAG,CAAC,cAAc,KAAK,CAAC;CAExB,OACE,qBAAC,OAAO,MAAR;EACE,WAAU;EACV,eAAY;YAFd;GAIE,oBAAC,OAAO,QAAR;IACE,OAAO;IACP,aAAa,EAAE,6DAA6D;IAC5E,OAAO,EAAE,aAAa;GACvB,CAAA;GACD,oBAAC,OAAO,MAAR,EAAA,UACE,qBAAC,QAAD;IAAM,cAAa;cAAnB;KACE,oBAAC,WAAD,CAAY,CAAA;KACZ,oBAAC,gBAAD,CAAiB,CAAA;KACjB,qBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,oBAAC,sBAAD,CAAuB,CAAA;OACvB,oBAAC,aAAD;QACE,SAAS,sBAAsB;QAC/B,aAAa,EAAE,gBAAgB;QAC/B,IAAG;QACH,WAAW,MACT,aAAa,aAAa,EACxB,mBAAmB,EAAE,OAAO,UACxB,iBAAiB,YACjB,iBAAiB,OACvB,CAAC;QAEH,OAAO,EAAE,gBAAgB;OAC1B,CAAA;OACD,oBAAC,aAAD;QACE,SAAS;QACT,aAAa,EAAE,wBAAwB;QACvC,IAAG;QACH,WAAW,MACT,aAAa,aAAa,EACxB,8BAA8B,EAAE,OAAO,QACzC,CAAC;QAEH,OAAO,EAAE,mBAAmB;OAC7B,CAAA;OACD,oBAAC,aAAD;QACE,SAAS;QACT,aAAa,EAAE,8BAA8B;QAC7C,IAAG;QACH,WAAW,MACT,aAAa,aAAa,EAAE,eAAe,EAAE,OAAO,QAAQ,CAAC;QAE/D,OAAO,EAAE,eAAe;OACzB,CAAA;MACE;;IACD;MACK,CAAA;GACb,oBAAC,4BAAD,EAAmC,MAAQ,CAAA;EAChC;;AAEjB;;;ACpEA,IAAM,QAAuC;CAC3C,KAAK;CACL,MAAM;CACN,OAAO;CACP,MAAM;CACN,OAAO;CACP,QAAQ;AACV;AAEA,IAAa,wBAAwB;AAErC,IAAa,8BAA8B;CACzC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,uBAAuB,sBAAsB;CACrD,OACE,oBAAC,mBAAD;EAAmB,WAAU;YAC3B,qBAAC,uBAAD;GAAuB,SAAS;aAAhC,CACE,oBAAC,iBAAD,CAAkB,CAAA,GAClB,oBAAC,QAAD,EAAA,UAAO,EAAE,kBAAkB,EAAQ,CAAA,CACd;;CACN,CAAA;AAEvB;AAEA,IAAa,2BAA2B;CACtC,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,mBAAD;EAAmB,WAAU;YAC3B,oBAAC,QAAD,EAAA,UAAO,EAAE,kBAAkB,EAAQ,CAAA;CAClB,CAAA;AAEvB;AAEA,IAAa,qBAAqB;CAChC,MAAM,EAAE,cAAc,sBAAsB;CAC5C,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,gBAAgB,0BAA0B;CAClD,MAAM,WAAW,2BAA2B;CAS5C,OACE,oBAAA,YAAA,EAAA,UATqB,cAEnB,CAAC,GAAG,QAAQ,EAAE,MAAM,GAAG,OACpB,EAAE,QAAQ,QAAQ,IAAI,cAAc,EAAE,QAAQ,QAAQ,EAAE,CAC3D,GACF,CAAC,QAAQ,CAKN,EAAe,KAAK,EAAE,SAAS,cAC9B,oBAAC,wBAAD;EACW;EACA;EAET,eAAe;GACb,IAAI,CAAC,QAAQ,QAAQ,CAAC,SAAS;GAC/B,gBAAgB,aAAa,WAAW,OAAO;GAC/C,UAAU;GAEV,4BAA4B,YAAY,SAAS,MAAM,CAAC;EAC1D;CACD,GARM,QAAQ,IAQd,CACF,EACD,CAAA;AAEN;AAEA,IAAa,yBAAyB,YAA6B;CACjE,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,wBAAwB,eACrB;EACL,KAAK,EAAE,kBAAkB;EACzB,OAAO,EAAE,oBAAoB;EAC7B,MAAM,EAAE,mBAAmB;EAC3B,OAAO,EAAE,oBAAoB;EAC7B,QAAQ,EAAE,qBAAqB;CACjC,IACA,CAAC,CAAC,CACJ;CACA,MAAM,+BAA+B,eAC5B;EACL,KAAK,EAAE,yBAAyB;EAChC,OAAO,EAAE,2BAA2B;EACpC,MAAM,EAAE,0BAA0B;EAClC,OAAO,EAAE,2BAA2B;EACpC,QAAQ,EAAE,4BAA4B;CACxC,IACA,CAAC,CAAC,CACJ;CAQA,OAAO;EAAE,MALP,QAAQ,SAAS,sBAAsB,QAAQ,QAAQ,OAAO,EAAE,QAAQ,IAAI;EAK/D,aAHb,QAAQ,gBACP,6BAA6B,QAAQ,QAAQ,OAAO,EAAE,QAAQ,WAAW;CAEjD;AAC7B;AAEA,IAAa,0BAA0B,EACrC,WACA,SACA,UAAU,MACV,GAAG,YAIC;CACJ,MAAM,EAAE,MAAM,gBAAgB,sBAAsB,OAAO;CAG3D,MAAM,UAAU,cACP,OAAO,IAAI,QAAQ,KAAK,GAAG,SAAS,IAAI,QAAQ,QACvD,CAAC,MAAM,QAAQ,IAAI,CACrB;CAEA,OACE,8BAAC,mBAAD;EACE,GAAI;EACJ,WAAW,KAAK,2CAA2C,SAAS;EAC3D;EACT,UAAU,CAAC;EACX,MAAM,MAAM,QAAQ;EACpB,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,OAAO,GAAG,YAAY,GAAG,QAAQ;CAClC,CAAA;AAEL;;;AC9FA,IAAM,wCAAwC,EAAE,gBAAwC;CACtF,MAAM,EAAE,+CAA+C,oBAAoB;CAE3E,IAAI,4CACF,OACE,oBAAC,QAAD;EAAiB;YACf,oBAAC,4CAAD,CAA6C,CAAA;CACzC,CAAA;CAIV,OACE,oBAAC,UAAD,EACE,WAAW,KAAK,oDAAoD,SAAS,EAC9E,CAAA;AAEL;AAEA,IAAa,2BAA2B,WAGtC,SAAS,yBAAyB,EAAE,WAAW,eAAe,GAAG,SAAS,KAAK;CAC/E,OACE,oBAAC,QAAD;EACE,YAAW;EACX,UAAA;EACA,WAAW,KAAK,8CAA8C,SAAS;EACvE,eAAY;EACZ,MAAK;EACL,SAAQ;EACR,GAAI;EACC;YAEL,oBAAC,sCAAD,EAAsC,WAAW,cAAgB,CAAA;CAC3D,CAAA;AAEZ,CAAC;AAED,IAAa,iCAAiC;CAC5C,MAAM,EAAE,wBAAwB,uBAAuB;CACvD,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,WAAW,OAAgC,IAAI;CACrD,MAAM,CAAC,eAAe,oBAAoB,SAAmC,IAAI;CACjF,MAAM,KAAK,YAAY;CACvB,MAAM,mBAAmB,oBAAoB;CAE7C,gBAAgB;EACd,IAAI,CAAC,eAAe;EACpB,MAAM,eAAe,UAAyB;GAC5C,IAAI,CAAC,CAAC,KAAK,OAAO,EAAE,SAAS,MAAM,GAAG,KAAK,CAAC,SAAS,SAAS;GAC9D,MAAM,eAAe;GACrB,SAAS,QAAQ,MAAM;EACzB;EACA,cAAc,iBAAiB,SAAS,WAAW;EACnD,aAAa;GACX,cAAc,oBAAoB,SAAS,WAAW;EACxD;CACF,GAAG,CAAC,aAAa,CAAC;CAElB,IAAI,CAAC,oBAAoB,gBAAgB,OAAO;CAEhD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,0BAAD;GACE,cAAY,EAAE,+BAA+B;GAC7C,UAAU;GACV,eAAe,SAAS,SAAS,MAAM;GACvC,KAAK;EACN,CAAA,GACD,oBAAC,iBAAD;GAAqB;GAAI,KAAK;EAAW,CAAA,CACtC;;AAET;AAqBA,IAAa,sCAAsC;CACjD,QAAQ,EAAE,eAAe,gBAA+C;EACtE,MAAM,EAAE,MAAM,sBAAsB;EACpC,MAAM,EAAE,gBAAgB,sBAAsB;EAE9C,MAAM,qBADW,2BACU,EAAS,MAAM,EAAE,cAAc,OAAO;EACjE,MAAM,aAAa,CAAC,CAAC;EAErB,OACE,oBAAC,mBAAD;GACE,WAAU;GACV,UAAU,CAAC;GACX,YAAY;GACZ,MAAM;GACN,UAAU,UAAU;IAClB,IAAI,CAAC,YAAY;IACjB,YAAY;KACV,mBAAmB,MAAM;KACzB,QAAQ;KACR,eAAe;KACf,SAAS;IACX,CAAC;GACH;aAEC,EAAE,UAAU;EACI,CAAA;CAEvB;CACA,OAAO;EACL,MAAM,EAAE,MAAM,sBAAsB;EACpC,MAAM,EAAE,cAAc,6BAA6B;EACnD,MAAM,EAAE,cAAc,sBAAsB;EAE5C,OACE,oBAAC,mBAAD;GACE,WAAU;GACV,MAAM;GACN,eAAe;IACb,WAAW,MAAM;IACjB,UAAU;GACZ;aAEC,EAAE,MAAM;EACQ,CAAA;CAEvB;CACA,SAAS,EAAE,sBAAqD;EAC9D,MAAM,EAAE,MAAM,sBAAsB;EACpC,MAAM,EAAE,cAAc,sBAAsB;EAC5C,OACE,oBAAC,mBAAD;GACE,WAAU;GACV,MAAM;GACN,eAAe;IACb,mBAAmB,aAAa;IAChC,UAAU;GACZ;aAEC,EAAE,UAAU;EACI,CAAA;CAEvB;CACA,KAAK,EAAE,sBAAqD;EAC1D,MAAM,EAAE,MAAM,sBAAsB;EACpC,MAAM,EAAE,cAAc,sBAAsB;EAC5C,OACE,oBAAC,mBAAD;GACE,WAAU;GACV,MAAM;GACN,eAAe;IACb,mBAAmB,YAAY;IAC/B,UAAU;GACZ;aAEC,EAAE,MAAM;EACQ,CAAA;CAEvB;AACF;;;;AAKA,IAAa,qCAAiE;CAC5E;EACE,cAAc,oCAAoC;EAClD,MAAM;CACR;CACA;EACE,cAAc,oCAAoC;EAClD,MAAM;CACR;CACA;EACE,cAAc,oCAAoC;EAClD,MAAM;CACR;CACA;EACE,cAAc,oCAAoC;EAClD,QAAQ;EACR,SAAS;EACT,MAAM;CACR;AACF;AAOA,IAAM,wCAAwC,aAAyC;CACrF,MAAM,EACJ,oBAAA,uBAAqB,oBACrB,qBAAA,wBAAsB,wBACpB,oBAAoB;CACxB,MAAM,EAAE,wBAAwB,uBAAuB;CACvD,MAAM,EAAE,oBAAoB,0BAA0B;CACtD,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,gBAAgB,gBAAgB,QAAQ,UAAU;CAExD,OAAO,cAEH,SACG,QAAQ,WAAW;EAClB,IAAI,OAAO,SAAS,cAClB,OACE,oBAAoB,kBACpB,eAAe,WACf;EAGJ,IAAI,OAAO,SAAS,cAClB,OACE,oBAAoB,gBACpB,CAAC,gBAAgB,YACjB,eAAe;EAGnB,IAAI,OAAO,SAAS,eAClB,OAAO,eAAe,oBAAoB,CAAC,gBAAgB;EAG7D,IAAI,OAAO,SAAS,iBAClB,OAAO,CAAC,CAAC,eAAe,UAAU,MAAM,YAAY,CAAC,CAAC,QAAQ,IAAI;EAGpE,OAAO;CACT,CAAC,EACA,KAAK,WAAW;EACf,IAAI,OAAO,SAAS,gBAAgB,CAAC,OAAO,cAC1C,OAAO;GAAE,GAAG;GAAQ,cAAc;EAAmB;EAEvD,IAAI,OAAO,SAAS,iBAAiB,CAAC,OAAO,cAC3C,OAAO;GAAE,GAAG;GAAQ,cAAc;EAAoB;EAExD,OAAO;CACT,CAAC,GACL;EACE;EACA;EACA;EACA;EACA;EACA,gBAAgB;EAChB;CACF,CACF;AACF;AAEA,IAAa,sBAAsB,EACjC,8BAA8B,oCAC9B,gCAC6B;CAC7B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,aAAa,uBAAuB,aAAa,QAAQ,gBAC/D,oBAAoB;CACtB,MAAM,EAAE,wBAAwB,uBAAuB;CACvD,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,mBAAmB,oBAAoB;CAC7C,MAAM,UAAU,qCAAqC,2BAA2B;CAEhF,MAAM,eAAe,0BAA0B,gBAAgB,WAAW,YAAY;CACtF,MAAM,EAAE,QAAQ,YAAY,kBAAkB,0BAA0B,EACtE,IAAI,aACN,CAAC;CACD,MAAM,mBAAmB,gBAAgB,cAAc,eAAe,EAAE;CAExE,MAAM,CAAC,oBAAoB,+BACzB,SAAmC;CACrC,MAAM,iCAAiC,OAAO,KAAK;CACnD,MAAM,qBAAqB,aACxB,eAAiD;EAChD,MAAM,SAAS,QAAQ,MAAM,MAAM,EAAE,SAAS,UAAU;EACxD,IAAI,CAAC,QAAQ,cAAc;EAC3B,4BAA4B,MAAM;CACpC,GACA,CAAC,OAAO,CACV;CAEA,MAAM,aAAa,kBAAkB;EACnC,+BAA+B,UAAU;EACzC,4BAA4B,KAAA,CAAS;CACvC,GAAG,CAAC,CAAC;CAEL,MAAM,CAAC,WAAW,gBAAgB,SAAkC,IAAI;CACxE,MAAM,gBAAgB,OAA0B,IAAI;CAEpD,gBAAgB;EACd,IAAI,sBAAsB,CAAC,+BAA+B,SAAS;EAEnE,MAAM,QAAQ,4BAA4B;GACxC,cAAc,SAAS,MAAM;GAC7B,+BAA+B,UAAU;EAC3C,CAAC;EAED,aAAa,qBAAqB,KAAK;CACzC,GAAG,CAAC,kBAAkB,CAAC;CAEvB,MAAM,mBAAmB,cAErB,QAAQ,KAAK,WACX,oBAAC,OAAO,cAAR;EAEsB;EACpB,eAAe,OAAO;EACtB,cAAc,OAAO;CACtB,GAJM,OAAO,IAIb,CACF,GACH,CAAC,SAAS,kBAAkB,CAC9B;CAEA,MAAM,8BAA8B,kBAC5B,SAAS,eAAe,oBAAoB,GAClD,CAAC,CACH;CAEA,IAAI,QAAQ,WAAW,GAAG,OAAO;CAEjC,IAAI,QAAQ,WAAW,KAAK,QAAQ,GAAG,SAAS,cAC9C,OAAO,oBAAC,0BAAD,CAA2B,CAAA;CAEpC,MAAM,eAAe,oBAAoB;CACzC,MAAM,cAAc,CAAC,CAAC;CACtB,OACE,oBAAC,mCAAD;EAAmC,OAAO,EAAE,UAAU;YACpD,qBAAC,OAAD;GAAK,WAAU;aAAf;IACG,oBAAoB,kBAAkB,oBAAC,iBAAD,EAAiB,KAAK,aAAe,CAAA;IAC5E,oBAAC,0BAAD;KACE,iBAAe;KACf,iBAAc;KACd,cAAY,EAAE,+BAA+B;KAC7C,UAAU;KACV,eAAe,KAAK,8BAA8B,EAChD,sBAAsB,iBACxB,CAAC;KACD,eAAe,YAAY,OAAO;KAClC,KAAK;IACN,CAAA;IACD,oBAAC,sBAAD;KACE,WAAA;KACA,cAAY,EAAE,yBAAyB;KACvC,WAAW,EAAE,MAAM;KACnB,WAAU;KACV,eAAY;KACZ,iBAAiB,eAAe;KAChC,IAAI;KACJ,SAAS,WAAW;KACpB,WAAU;KACV,kBAAkB,cAAc;KAChC,UAAU;KACV,WAAA;eAEC;IACmB,CAAA;IACtB,oBAAC,QAAD;KACE,sBAAsB,6BAA6B;KACnD,QAAQ;eAER,oBAAC,OAAD;MACE,WAAW,KAAK;OACd,+BAA+B,oBAAoB,SAAS;OAC5D,kCACE,oBAAoB,SAAS;MACjC,CAAC;MACD,SAAS;MACT,MAAM;gBAEL,gBAAgB,oBAAC,cAAD,EAAc,OAAO,WAAa,CAAA;KAC9C,CAAA;IACD,CAAA;GACL;;CAC4B,CAAA;AAEvC;;;ACxaA,IAAa,gCAAgC,EAC3C,YACA,wBACuC;CACvC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,OAAO,WAAW,iBAAiB,CAAC;CAE5C,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd;GAIE,oBAAC,2BAAD,CAA4B,CAAA;GAC5B,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,OAAD;KACE,WAAU;KACV,eAAY;eAEX,EAAE,wBAAwB;IACxB,CAAA;GACF,CAAA;GACL,oBAAC,+BAAD;IACE,eAAY;IACZ,eAAe;KACb,IAAI,IAAI,kBAAkB,CAAC,EAAE,CAAC;IAChC;GACD,CAAA;EACE;;AAET;;;ACvCA,SAAS,8BAA8B,YAGhB;CACrB,MAAM,WAAW,WAAW,eAAe,MAAM;CACjD,IAAI,OAAO,aAAa,YAAY,OAAO,SAAS,QAAQ,KAAK,YAAY,GAC3E,OAAO;CAET,MAAM,MAAM,WAAW;CACvB,IAAI,OAAO,QAAQ,YAAY,OAAO,SAAS,GAAG,KAAK,OAAO,GAAG,OAAO;CACxE,IAAI,OAAO,QAAQ,UAAU;EAC3B,MAAM,IAAI,WAAW,GAAG;EACxB,IAAI,OAAO,SAAS,CAAC,KAAK,KAAK,GAAG,OAAO;CAC3C;AAEF;AAaA,IAAa,mCAAmC,EAC9C,iBAC0C;CAC1C,MAAM,EACJ,mBAAA,sBAAoB,mBACpB,uBAAA,0BAAwB,0BACtB,oBAAoB;CACxB,MAAM,EAAE,gBAAgB,gBAAgB,WAAW,iBAAiB,CAAC;CACrE,MAAM,YAAY,8BAA8B,UAAU;CAC1D,MAAM,WACJ,mBAAmB,KAAA,KAAa,cAAc,KAAA,IAC1C,KAAK,MAAO,iBAAiB,MAAO,SAAS,IAC7C,KAAA;CAEN,IAAI,gBAAgB,eAAe,aAAa,KAAA,KAAa,cAAc,KAAA,GACzE,OAAO,oBAAC,yBAAD;EAAkC;EAAW,eAAe;CAAW,CAAA;CAGhF,IAAI,gBAAgB,YAClB,OAAO,oBAAC,qBAAD,EAAmB,UAAU,WAAW,UAAY,CAAA;CAG7D,OAAO;AACT;;;AC9BA,IAAM,uBACJ;AAEF,SAAS,iCACP,QACA,MACS;CACT,IAAI,EAAE,kBAAkB,YAAY,CAAC,MAAM,OAAO;CAElD,IAAI,KAAqB;CACzB,OAAO,MAAM,OAAO,MAAM;EACxB,IAAI,GAAG,QAAQ,oBAAoB,GAAG,OAAO;EAC7C,KAAK,GAAG;CACV;CACA,OAAO;AACT;AAGA,IAAa,yBAAyB,EACpC,YACA,WACA,aACA,WAAW,GACX,GAAG,YAC6B;CAChC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,CAAC,MAAM,WAAW,SAAgC,IAAI;CAC5D,MAAM,MACJ,WAAW,aAAa,WAAW,aAAa,WAAW,cAAc;CAE3E,MAAM,wBAAwB;;CAE9B,MAAM,uBACJ,CAAC,CAAC,gBACA,CAAC,CAAC,OAAO,kBAAkB,UAAU,KAAM,kBAAkB,UAAU;CAE3E,MAAM,iBAAiB,MAAoD;EACzE,IAAI,EAAE,kBAAkB;EAExB,IAAI,iCAAiC,EAAE,QAAmB,IAAI,GAAG;EAEjE,IAAI;OAEE,CADmB,UAAU,CAC5B,GAAgB;EAAA;EAGvB,IAAI,sBAAsB;GACxB,YAAY;GACZ;EACF;CAKF;CAEA,MAAM,gBAAgB,wBAAwB;CAE9C,OACE,oBAAC,OAAD;EACE,cACE,gBACI,EAAE,uBAAuB,sBAAsB,0BAA0B,IACzE,KAAA;EAEN,GAAI;EACJ,SAAS;EACT,WACE,iBACK,MAAM;GACL,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;GACxC,cAAc,CAAC;GACf,EAAE,eAAe;EACnB,IACA,KAAA;EAEN,KAAK;EACL,MAAM,gBAAgB,WAAW,KAAA;EACjC,UAAU,gBAAgB,WAAW;YAEpC,MAAM;CACJ,CAAA;AAET;;;AC9FA,IAAa,yBAAyB,EACpC,YACA,aACA,wBACgC;CAChC,MAAM,EAAE,MAAM,sBAAsB,aAAa;CACjD,MAAM,EAAE,IAAI,uBAAuB,gBAAgB,gBACjD,WAAW,iBAAiB,CAAC;CAE/B,MAAM,oBAAoB,uBAAuB,WAAW;CAC5D,MAAM,gBAAgB,gBAAgB,aAAa;CACnD,MAAM,oBAAoB,gBAAgB,YAAY,CAAC,CAAC;CAExD,OACE,qBAAC,uBAAD;EACc;EACZ,WAAU;EACV,eAAY;YAHd;GAKE,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,UAAD;KAAU,UAAU,WAAW;KAAO,UAAU,WAAW;IAAY,CAAA;GACpE,CAAA;GAEL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;KAAyC,OAAO,WAAW;eACvE,WAAW;IACT,CAAA,GACL,qBAAC,OAAD;KAAK,WAAU;eAAf;MACG,gBAAgB,eACf,oBAAC,yBAAD,EAAyC,eAAiB,CAAA;MAE5D,oBAAC,iCAAD,EAA6C,WAAa,CAAA;MACzD,iBACC,qBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,oBAAC,qBAAD,CAAsB,CAAA,GACtB,oBAAC,QAAD,EAAA,UACG,oBACG,EAAE,gBAAgB,IAClB,gBAAgB,YACd,EAAE,gBAAgB,IAClB,EAAE,eAAe,EACnB,CAAA,CACH;;MAEN,qBACC,qBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,oBAAC,6BAAD,CAA8B,CAAA;QAC9B,oBAAC,QAAD,EAAA,UAAO,EAAE,cAAc,EAAQ,CAAA;QAC/B,oBAAC,UAAD;SACE,cAAY,EAAE,mBAAmB;SACjC,WAAU;SACV,eAAY;SACZ,eAAe;UACb,YAAY,UAAU;SACxB;SACA,MAAK;mBAEJ,EAAE,cAAc;QACX,CAAA;OACL;;KAEJ;MACF;;GAEL,oBAAC,+BAAD;IACE,eAAY;IACZ,eAAe;KACb,IAAI,IAAI,kBAAkB,CAAC,EAAE,CAAC;IAChC;IACa;GACd,CAAA;EACoB;;AAE3B;;;AC3DA,IAAM,8BAA4B,WAA6B;CAC7D,eAAe,MAAM;CACrB,WAAW,MAAM;CACjB,cAAc,MAAM;CACpB,iBAAiB,MAAM;CACvB,gBAAgB,MAAM;AACxB;AAEA,IAAa,0BAA0B,EACrC,YACA,aACA,wBACiC;CACjC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,IAAI,YAAY,uBAAuB,gBAAgB,gBAC7D,WAAW,iBAAiB,CAAC;CAC/B,MAAM,MAAM,WAAW,aAAa;CAEpC,MAAM,cAAc,eAAe;EACjC,UAAU,WAAW,cAAc,MAAM,QAAQ,WAAW;EAC5D,UAAU,WAAW,cAAc,MAAM,QAAQ,WAAW;EAC5D,WAAW,WAAW,cAAc;EACpC,KAAK;EACL,OAAO,WAAW;EAClB,cAAc,WAAW;CAC3B,CAAC;CAED,gBAAgB;EACd,aAAa,uBAAuB;EACpC,aAAa;GACX,aAAa,gBAAgB;EAC/B;CACF,GAAG,CAAC,WAAW,CAAC;CAEhB,MAAM,EAAE,eAAe,WAAW,cAAc,iBAAiB,mBAC/D,cAAc,aAAa,OAAO,0BAAwB,KAAK,CAAC;CAElE,MAAM,mBAAmB,aAAa,mBAAmB,WAAW;CAEpE,MAAM,cAAc,CAAC,CAAC,aAAa,cAAc;CACjD,MAAM,oBAAoB,uBAAuB,WAAW;CAC5D,MAAM,gBAAgB,gBAAgB,aAAa;CAEnD,MAAM,WADoB,gBAAgB,YAAY,CAAC,CAAC,eAClB;CAEtC,MAAM,uBAAuB,CAAC,YAAa,YAAY;CAEvD,OACE,qBAAC,uBAAD;EACc;EACZ,WAAW,KAAK,oCAAoC;EACpD,eAAY;YAHd;GAKE,oBAAC,YAAD;IACE,WAAW,QAAQ,SAAS;IAC5B,eAAe;KACb,aAAa,WAAW;IAC1B;GACD,CAAA;GAED,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;KAAyC,OAAO,WAAW;eACvE,2BAA2B,UAAU,IAAI,EAAE,eAAe,IAAI,WAAW;IACvE,CAAA,GACL,qBAAC,OAAD;KAAK,WAAU;eAAf,CACG,gBAAgB,eACf,oBAAC,yBAAD,EAAyC,eAAiB,CAAA,GAE3D,uBACC,qBAAA,YAAA,EAAA,UAAA,CACG,CAAC,oBAAoB,CAAC,mBAAmB,CAAC,aACzC,oBAAC,iCAAD,EAA6C,WAAa,CAAA,GAE3D,cACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,iBAAD;MACE,UAAU;MACV,WAAW,QAAQ,SAAS;MACZ;MAChB,eAAA;KACD,CAAA,GACD,oBAAC,iBAAD;MACE,iBAAiB;MACjB,UAAU;MACV,2BAA2B;MAC3B,sBAAsB;MACN;MAChB,MAAM,YAAY;MAClB,cAAc,YAAY;KAC3B,CAAA,CACD,EAAA,CAAA,IAEF,oBAAC,iBAAD;MACE,UAAU;MACV,WAAW,QAAQ,SAAS;MACZ;KACjB,CAAA,CAEH,EAAA,CAAA,IACA,gBACF,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,oBAAC,qBAAD,CAAsB,CAAA,GACtB,oBAAC,QAAD,EAAA,UACG,oBACG,EAAE,gBAAgB,IAClB,gBAAgB,YACd,EAAE,gBAAgB,IAClB,EAAE,eAAe,EACnB,CAAA,CACH;UAEL,qBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,oBAAC,6BAAD,CAA8B,CAAA;OAC9B,oBAAC,QAAD,EAAA,UAAO,EAAE,cAAc,EAAQ,CAAA;OAC/B,oBAAC,UAAD;QACE,cAAY,EAAE,mBAAmB;QACjC,WAAU;QACV,eAAY;QACZ,eAAe;SACb,YAAY,UAAU;QACxB;QACA,MAAK;kBAEJ,EAAE,cAAc;OACX,CAAA;MACL;OAEJ;MACF;;GACJ,eAAe,iBACd,qBAAC,oBAAD;IACE,cAAY,EAAE,8BAA8B,EAC1C,MAAM,cAAc,SAAS,KAAK,IACpC,CAAC;IACD,SAAS,YAAY;cAJvB,CAKC,KACG,cAAc,SAAS,CACP;;GAEtB,oBAAC,+BAAD;IACE,eAAY;IACZ,eAAe;KACb,IAAI,IAAI,kBAAkB,CAAC,EAAE,CAAC;IAChC;IACa;GACd,CAAA;EACoB;;AAE3B;;;ACtKA,IAAM,0BAAoE;CACxE,OAAO;CACP,gBAAgB;AAClB;AAEA,IAAa,cAAc,EAAE,YAAY,cAA+B;CACtE,MAAM,OAAO,wBAAwB;CACrC,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,yBAAyB,GACtC,0BAA0B,YAAY,QACzC,CAAC;YAHH,CAKG,QAAQ,oBAAC,MAAD,CAAO,CAAA,GACf,WAAW,WAAW,oBAAC,OAAD,EAAA,UAAM,WAAW,SAAc,CAAA,IAAI,IACvD;;AAET;;;ACCA,IAAa,0BAA0B,EACrC,YACA,aACA,aACA,wBACiC;CACjC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,WAAA,cAAY,cAAqB,oBAAoB;CAC7D,MAAM,CAAC,uBAAuB,4BAA4B,SAAS,KAAK;CAExE,MAAM,EAAE,IAAI,uBAAuB,gBAAgB,gBACjD,WAAW,iBAAiB,CAAC;CAE/B,MAAM,cAAc,gBAAgB;CACpC,MAAM,2BAA2B,kBAAkB,yBAAyB,IAAI,GAAG,CAAC,CAAC;CACrF,MAAM,oBAAoB,uBAAuB,WAAW;CAC5D,MAAM,gBAAgB,gBAAgB,aAAa;CACnD,MAAM,oBAAoB,gBAAgB,YAAY,CAAC,CAAC;CACxD,MAAM,iBAAiB,qBAAqB;CAE5C,MAAM,SAAS,MAAoD;EACjE,EAAE,gBAAgB;EAClB,YAAY,UAAU;EACtB,OAAO;CACT;CAEA,MAAM,YAAY,cAEd,kBAAkB,UAAU,IACxB;EACE,KAAK,WAAW;EAChB,OAAO,WAAW;EAClB,KAAK,WAAW;CAClB,IACA;EACE,KAAK,WAAW;EAChB,OAAO,WAAW;EAClB,KAAK,WAAW,aAAa,WAAW,cAAc;CACxD,GACN,CAAC,UAAU,CACb;CAEA,OACE,qBAAC,uBAAD;EACc;EACZ,WAAW,KAAK,sCAAsC;GACpD,+DACE;GACF,oDAAoD;GACpD,iDAAiD;EACnD,CAAC;EACD,eAAY;EACZ,WAAW,oBAAoB,QAAQ,KAAA;EACvC,aAAa,CAAC,eAAe,CAAC,iBAAiB,cAAc,KAAA;YAV/D,CAYE,qBAAC,OAAD;GAAK,WAAU;aAAf,CACG,UAAU,OACT,oBAAC,aAAD;IACE,KAAK,UAAU;IACf,WAAU;IACV,SAAS;IACT,KAAK,UAAU;IACf,OAAO,UAAU;GAClB,CAAA,GAGH,qBAAC,OAAD;IAAK,WAAW,KAAK,6CAA6C;cAAlE;KACG,eAAe,oBAAC,yBAAD,EAAyC,eAAiB,CAAA;KAEzE,kBAAkB,UAAU,KAC3B,CAAC,kBACD,gBAAgB,eACd,oBAAC,YAAD;MAAwB;MAAY,SAAQ;KAAS,CAAA;KAGxD,iBAAiB,oBAAC,qBAAD,CAAsB,CAAA;KAEvC,qBACC,oBAAC,QAAD;MACE,YAAW;MACX,cAAY,EAAE,mBAAmB;MACjC,UAAA;MACA,WAAU;MACV,eAAY;MACZ,SAAS;MACT,MAAK;MACL,SAAQ;gBAER,oBAAC,WAAD,CAAY,CAAA;KACN,CAAA;IAEP;KACF;MAEL,oBAAC,+BAAD;GACE,eAAY;GACZ,eAAe;IACb,IAAI,IAAI,kBAAkB,CAAC,EAAE,CAAC;GAChC;GACa;EACd,CAAA,CACoB;;AAE3B;;;AC5FA,IAAa,yBAAyB,EACpC,yBAAyB,uBACzB,uBAAA,0BAAwB,uBACxB,yBAAyB,wBACzB,8BAAA,iCAA+B,8BAC/B,yBAAyB,6BACO;CAChC,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,QAAQ,gBAAgB,oBAAoB;CACpD,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,kBAAkB,OAAO,CAAC;CAChC,MAAM,sBAAsB,aACzB,WAA6B,WAAW,WACzC,CAAC,CACH;CAEA,MAAM,EAAE,gBAAgB,yBAAyB;CACjD,MAAM,sBAAsB,cACpB,YAAY,QAAQ,MAAM,CAAC,2BAA2B,CAAC,CAAC,GAC9D,CAAC,WAAW,CACd;CAEA,MAAM,EAAE,cAAc,qBAAqB,cAAc;EACvD,MAAM,QAAkE,CAAC;EACzE,MAAM,YAAoC,CAAC;EAC3C,KAAK,MAAM,KAAK,aACd,IAAI,uBAAuB,CAAC,KAAK,uBAAuB,CAAC,GAAG;GAC1D,MAAM,aAAa,uBAAuB,CAAC;GAC3C,IAAI,YAAY;IACd,UAAU,EAAE,cAAc,MAAM,MAAM;IACtC,MAAM,KAAK,UAAU;GACvB;EACF;EAEF,OAAO;GAAE,cAAc;GAAO,kBAAkB;EAAU;CAC5D,GAAG,CAAC,WAAW,CAAC;CAEhB,MAAM,qBAAqB,aAAa,UAAkB;EACxD,gBAAgB,UAAU;EAC1B,eAAe,IAAI;CACrB,GAAG,CAAC,CAAC;CAEL,IAAI,CAAC,oBAAoB,QAAQ,OAAO;CAExC,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd,CAIG,YAAY,KAAK,eAAe;GAC/B,IAAI,iBAAiB,UAAU,GAAG,OAAO;GAEzC,IAAI,gCAAgC,UAAU,GAAG,OAAO;GACxD,IAAI,uBAAuB,UAAU,GACnC,OACE,oBAAC,wBAAD;IACc;IACZ,aAAa,gBAAgB,kBAAkB;IAE/C,mBAAmB,gBAAgB,kBAAkB;GACtD,GAFM,WAAW,cAAc,MAAM,WAAW,SAEhD;QAEE,IAAI,uBAAuB,UAAU,GAC1C,OACE,oBAAC,wBAAD;IACc;IACZ,aAAa,gBAAgB,kBAAkB;IAE/C,mBACE,mBAAmB,iBAAiB,WAAW,cAAc,OAAO,CAAC;IAEvE,mBAAmB,gBAAgB,kBAAkB;GACtD,GALM,WAAW,cAAc,MAAM,WAAW,SAKhD;QAEE,IAAI,uBAAuB,UAAU,GAC1C,OACE,oBAAC,wBAAD;IACc;IACZ,aAAa,gBAAgB,kBAAkB;IAE/C,mBACE,mBAAmB,iBAAiB,WAAW,cAAc,OAAO,CAAC;IAEvE,mBAAmB,gBAAgB,kBAAkB;GACtD,GALM,WAAW,cAAc,MAAM,WAAW,SAKhD;QAEE,IAAI,sBAAsB,UAAU,GACzC,OACE,oBAAC,yBAAD;IACc;IACZ,aAAa,gBAAgB,kBAAkB;IAE/C,mBAAmB,gBAAgB,kBAAkB;GACtD,GAFM,WAAW,cAAc,MAAM,WAAW,SAEhD;QAEE,IAAI,kBAAkB,UAAU,GACrC,OACE,oBAAC,gCAAD;IACc;IACZ,aAAa,gBAAgB,kBAAkB;IAE/C,mBAAmB,gBAAgB,kBAAkB;GACtD,GAFM,WAAW,cAAc,EAE/B;GAGL,OAAO;EACT,CAAC,GACA,aAAa,SAAS,KACrB,oBAAC,OAAD;GACE,WAAU;GACV,eAAe,eAAe,KAAK;GACnC,gBAAgB;GAChB,MAAM;aAEN,oBAAC,SAAD;IAAS,cAAc,gBAAgB;IAAS,OAAO;GAAe,CAAA;EACjE,CAAA,CAEN;;AAET;;;;;;AC3IA,IAAa,6BAA6B,EACxC,wBAAwB,6BACY;CACpC,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,gBAAgB,yBAAyB;CAGjD,MAAM,aADmB,YAAY,OAAO,+BACzB,EAAiB;CACpC,IAAI,CAAC,YAAY,OAAO;CAExB,OACE,oBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAEZ,oBAAC,uBAAD;GACE,YAAY;GACZ,aAAa,gBAAgB,kBAAkB;GAC/C,mBAAmB,gBAAgB,kBAAkB;EACtD,CAAA;CACE,CAAA;AAET;;;AClCA,IAAa,eAAe,EAAE,cAAgC;CAC5D,MAAM,EAAE,iBAAiB,6BAA6B;CACtD,MAAM,EAAE,gBAAgB,0BAA0B;CAClD,MAAM,EAAE,MAAM,sBAAsB;CACpC,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,UAAD,CAAW,CAAA;GACX,oBAAC,QAAD,EAAA,UAAO,QAAQ,KAAW,CAAA;GAC1B,oBAAC,UAAD;IACE,cAAY,EAAE,8BAA8B,EAAE,SAAS,QAAQ,KAAK,CAAC;IACrE,WAAW;IACX,eAAe;KACb,aAAa,WAAW,IAAI;KAC5B,YAAY,SAAS,MAAM;IAC7B;cAEA,oBAAC,WAAD,CAAY,CAAA;GACN,CAAA;EACL;;AAET;;;AC5BA,IAAa,sBAAsB;CAGjC,OACE,oBAAC,OAAD;EAAK,WAAU;EAAsC,eAAY;YAH/C,qBAIf;CACE,CAAA;AAET;;;ACTA,IAAa,mBAAmB;CAC9B,MAAM,EAAE,MAAM,sBAAsB,YAAY;CAChD,OACE,qBAAC,OAAD;EACE,eAAY;EACZ,MAAK;EACL,QAAO;EACP,SAAQ;EACR,OAAM;EACN,OAAM;YANR;GAQE,oBAAC,SAAD,EAAA,UAAQ,EAAE,cAAc,EAAS,CAAA;GACjC,oBAAC,KAAD;IAAG,UAAS;cACV,oBAAC,QAAD;KACE,GAAE;KACF,MAAK;IACN,CAAA;GACA,CAAA;GACH,oBAAC,QAAD,EAAA,UACE,oBAAC,YAAD;IAAU,IAAG;cACX,oBAAC,QAAD;KAAM,MAAK;KAAQ,QAAO;KAAK,OAAM;IAAM,CAAA;GACnC,CAAA,EACN,CAAA;EACH;;AAET;AAEA,IAAa,gBACX,oBAAC,OAAD;CAAK,MAAK;CAAe,SAAQ;CAAY,OAAM;WACjD,oBAAC,QAAD,EAAM,GAAE,qhBAAshB,CAAA;AAC3hB,CAAA;AAGP,IAAa,kBACX,oBAAC,OAAD;CACE,eAAY;CACZ,MAAK;CACL,SAAQ;CACR,OAAM;WAEN,oBAAC,QAAD,EAAM,GAAE,uFAAwF,CAAA;AAC7F,CAAA;AAGP,IAAa,iBACX,oBAAC,OAAD;CACE,eAAY;CACZ,MAAK;CACL,SAAQ;CACR,OAAM;WAEN,oBAAC,QAAD,EAAM,GAAE,gNAAiN,CAAA;AACtN,CAAA;AAGP,IAAa,sBACX,oBAAC,OAAD;CAAK,MAAK;CAAe,SAAQ;CAAY,OAAM;WACjD,oBAAC,QAAD,EAAM,GAAE,gUAAiU,CAAA;AACtU,CAAA;;;AC5CP,IAAM,sCAAoC,WAAqC,EAC7E,cAAc,MAAM,KAAK,MAAM,SAAS,OAAO,CAAC,EAAE,QAC/C,YACC,oBAAoB,gBAAgB,OAAO,KAC3C,oBAAoB,iBAAiB,OAAO,CAChD,EACF;AAEA,IAAa,mBAAmB,EAAE,mBAAmB,QAA8B;CAEjF,MAAM,EAAE,wBADgB,6BACQ;CAChC,MAAM,EAAE,iBAAiB,cACvB,oBAAoB,OACpB,kCACF;CAEA,IAAI,aAAa,WAAW,GAAG,OAAO;CAEtC,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,aAAa,MAAM,GAAG,gBAAgB,EAAE,KAAK,gBAC5C,oBAAC,iBAAD,EAA8D,YAAc,GAAtD,YAAY,aAA0C,CAC7E;CACE,CAAA;AAET;AAMA,IAAa,mBAAmB,EAAE,kBAAoC;CACpE,MAAM,EAAE,wBAAwB,6BAA6B;CAC7D,MAAM,EAAE,aAAa,aAAa,mBAChC,sBAAsC;CACxC,MAAM,CAAC,kBAAkB,uBAAuB,SAAgC,IAAI;CACpF,MAAM,EAAE,WAAW,WAAW,OAAO,eAAe;CAEpD,IACE,CAAC,oBAAoB,gBAAgB,WAAW,KAChD,CAAC,oBAAoB,iBAAiB,WAAW,GAEjD,OAAO;CAET,MAAM,kBAAkB,cAAc,aAAa;CACnD,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,+BAA+B,EAC7C,wCACE,oBAAoB,iBAAiB,WAAW,EACpD,CAAC;EACD,eAAY;EACZ,cAAc;EACd,cAAc;EACd,KAAK;YARP;GAUE,oBAAC,eAAD;IACE,QAAQ,CAAC,GAAG,CAAC;IACK;IAClB,SAAS;cAER,YAAY;GACA,CAAA;GAEd,mBACC,oBAAC,WAAD;IACE,KAAK;IACL,WAAU;IACV,KAAK;IACE;GACR,CAAA;GAEH,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD;MAAK,WAAU;gBACZ,YAAY;KACV,CAAA;KACL,oBAAC,OAAD;MAAK,WAAU;gBACZ,YAAY;KACV,CAAA;KACL,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,oBAAC,UAAD,CAAW,CAAA,GACX,oBAAC,QAAD,EAAA,UAAO,YAAY,cAAoB,CAAA,CACpC;;IACF;;GAEL,oBAAC,+BAAD;IACE,WAAU;IACV,eAAY;IACZ,eAAe,oBAAoB,eAAe,YAAY,aAAa;GAC5E,CAAA;EACE;;AAET;;;ACpGA,IAAa,yCAAyC,EACpD,qBACgD;CAChD,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,yBAAyB;EAC7B,MAAM;GACJ,QAAQ,EAAE,6DAA6D;GACvE,YAAY,EAAE,iEAAiE;EACjF;EACA,SAAS;GACP,QAAQ,EAAE,wBAAwB;GAClC,YAAY,EAAE,4BAA4B;EAC5C;CACF;CAEA,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD;GAAK,WAAU;aACZ,uBAAuB,QAAQ;EAC7B,CAAA,GACL,oBAAC,KAAD;GAAG,WAAU;aACV,uBAAuB,KAAK;EAC5B,CAAA,CACA;;AAET;;;ACvBA,IAAM,4BAA4B,WAA6B;CAC7D,WAAW,MAAM;CACjB,UAAU,MAAM;CAChB,gBAAgB,MAAM;AACxB;AASA,IAAa,0BAA0B,EACrC,iBACA,UACA,KACA,mBAC+B;CAC/B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,cAAc,eAAe;EACjC;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,EAAE,WAAW,UAAU,mBAC3B,cAAc,aAAa,OAAO,wBAAwB,KAAK,CAAC;CAElE,MAAM,oBAAoB,kBAAkB;CAE5C,gBAAgB;EACd,aAAa,uBAAuB;EACpC,aAAa;GACX,aAAa,gBAAgB;EAC/B;CACF,GAAG,CAAC,WAAW,CAAC;CAEhB,IAAI,CAAC,aAAa,OAAO;CAEzB,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,gDAAgD,EAC9D,2DAA2D,UAC7D,CAAC;YAHH;GAKE,oBAAC,QAAD;IACE,YAAW;IACX,cAAY,YAAY,EAAE,YAAY,IAAI,EAAE,WAAW;IACvD,UAAA;IACA,WAAU;IACV,eAAY;IACZ,SAAS,YAAY;IACrB,MAAK;IACL,SAAQ;cAEP,YAAY,oBAAC,eAAD,CAAgB,CAAA,IAAI,oBAAC,cAAD,CAAe,CAAA;GAC1C,CAAA;GACR,oBAAC,iBAAD;IACE,WAAW,KAAK,6BAA6B,EAC3C,oCAAoC,qBAAqB,KAC3D,CAAC;IACD,UAAU;IACV,WAAW,CAAC,CAAC;IACG;GACjB,CAAA;GACD,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,iBAAD;KACmB;KACP;KACM;KAChB,MAAM,YAAY;KAClB,cAAc,gBAAgB,CAAC;IAChC,CAAA;GACE,CAAA;EACF;;AAET;;;AChFA,IAAa,kBAAkB,EAC7B,iBAAiB,GACjB,iBACwB,CAAC,MAAM;CAC/B,MAAM,CAAC,gBAAgB,qBAAqB,SAAiB,cAAc;CAC3E,MAAM,iBAAiB,OAAuC,KAAA,CAAS;CAEvE,MAAM,eAAe,kBAAkB;EACrC,IAAI,eAAe,SAAS;EAC5B,eAAe,UAAU,kBAAkB;GACzC,mBAAmB,SAAS,OAAO,CAAC;EACtC,GAAG,GAAI;CACT,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,kBAAkB;EACpC,cAAc,eAAe,OAAO;EACpC,eAAe,UAAU,KAAA;CAC3B,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,IAAI,eAAe,SAAS;EAC5B,kBAAkB,cAAc;CAClC,GAAG,CAAC,cAAc,CAAC;CAEnB,gBAAgB;EACd,IAAI,CAAC,cAAc;EACnB,aAAa;EACb,aAAa;GACX,YAAY;EACd;CACF,GAAG;EAAC;EAAc;EAAc;CAAW,CAAC;CAE5C,OAAO;EACL;EACA;EACA;CACF;AACF;;;ACrCA,IAAa,kBAAkB,EAAE,sBAC/B,oBAAC,OAAD;CACE,WAAW,KAAK,6BAA6B,EAC3C,oCAAoC,mBAAmB,KACzD,CAAC;WAEA,gBAAgB,eAAe;AAC7B,CAAA;;;ACLP,IAAM,0BAA0B,EAAE,qBAAqB,UAAyB;CAC9E,MAAM,EACJ,qBAAqB,EAAE,eACrB,0BAA0B;CAE9B,MAAM,CAAC,YAAY,iBAAiB,SAAmB,CAAC,CAAC;CAEzD,gBAAgB;EACd,IAAI,CAAC,UAAU,mBAAmB;EAClC,MAAM,yBACJ,SAAS,kBAAkB,WAAW,UAAU,aAAa;EAC/D,aAAa;GACX,uBAAuB,YAAY;EACrC;CACF,GAAG,CAAC,QAAQ,CAAC;CAEb,IAAI,CAAC,UAAU,OAAO;CAEtB,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,OAAD;GAAK,WAAU;aACZ,WAAW,MAAM,CAAC,kBAAkB,EAAE,KAAK,WAAW,MACrD,oBAAC,OAAD;IACE,WAAU;IAEV,OACE,EACE,uDAAuD,YACnD,YAAY,MAAM,MAClB,KACN;GAEH,GARM,aAAa,EAAE,iBAQrB,CACF;EACE,CAAA;CACF,CAAA;AAET;AACA,IAAa,8BAA8B;CACzC,MAAM,EACJ,qBAAqB,EAAE,eACrB,0BAA0B;CAG9B,MAAM,EAAE,gBAAgB,cAAc,gBAAgB,eAAe,EACnE,gBAFqB,UAAU,aAAa,SAAS,aAAa,MAAO,EAG3E,CAAC;CAED,gBAAgB;EACd,IAAI,CAAC,UAAU,eAAe;EAC9B,MAAM,EAAE,kBAAkB;EAE1B,IAAI,cAAc,UAAU,aAC1B,aAAa;EAGf,cAAc,iBAAiB,SAAS,YAAY;EACpD,cAAc,iBAAiB,UAAU,YAAY;EACrD,cAAc,iBAAiB,QAAQ,WAAW;EAClD,cAAc,iBAAiB,SAAS,WAAW;EAEnD,aAAa;GACX,cAAc,oBAAoB,SAAS,YAAY;GACvD,cAAc,oBAAoB,UAAU,YAAY;GACxD,cAAc,oBAAoB,QAAQ,WAAW;GACrD,cAAc,oBAAoB,SAAS,WAAW;EACxD;CACF,GAAG;EAAC;EAAU;EAAc;CAAW,CAAC;CAExC,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,WAAD,CAAY,CAAA;GACZ,oBAAC,gBAAD,EAAgB,iBAAiB,eAAiB,CAAA;GAClD,oBAAC,wBAAD,CAAyB,CAAA;EACtB;;AAET;;;AClFA,IAAa,aAAa,mBACxB,mBAAmB,oBAAoB;AACzC,IAAa,eAAe,mBAC1B,mBAAmB,oBAAoB;;;ACEzC,IAAM,8BAA8B;CAClC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,qBAAqB,EAAE,UAAU,qBAC/B,0BAA0B;CAE9B,MAAM,YAAY,YAAY,cAAc;CAE5C,OACE,oBAAC,QAAD;EACE,YAAW;EACX,cAAY,YAAY,EAAE,sBAAsB,IAAI,EAAE,uBAAuB;EAC7E,UAAA;EACA,WAAU;EACV,eAAgB,YAAY,UAAU,MAAM,IAAI,UAAU,OAAO;EACjE,MAAK;EACL,SAAQ;YAEP,YAAY,oBAAC,eAAD,CAAgB,CAAA,IAAI,oBAAC,WAAD,CAAY,CAAA;CACvC,CAAA;AAEZ;AAEA,IAAa,uCAAuC;CAClD,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,qBAAqB,EAAE,mBAAmB,UAAU,WAAW,qBAC7D,0BAA0B;CAC9B,MAAM,kBAAkB,WAAW,eAAe,gBAAgB;CAClE,MAAM,iBAAiB,WAAW,eAAe;CAEjD,IAAI,CAAC,UAAU,OAAO;CAEtB,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,CAAC,YAAY,cAAc,KAC1B,oBAAC,QAAD;IACE,YAAW;IACX,cAAY,EAAE,uBAAuB;IACrC,UAAA;IACA,WAAU;IACV,eAAa;IACb,UAAU;IACV,eAAe;KACb,SAAS,OAAO;KAChB,gBAAgB;MACd,SAAS;MACT,SAAS,EAAE,uBAAuB;MAClC,UAAU;MACV,MAAM;KACR,CAAC;IACH;IACA,MAAK;IACL,SAAQ;cAER,oBAAC,YAAD,CAAa,CAAA;GACP,CAAA;GAEV,oBAAC,uBAAD,CAAwB,CAAA;GACxB,oBAAC,QAAD;IACE,YAAW;IACX,cAAY,EAAE,yBAAyB;IACvC,UAAA;IACA,WAAU;IACV,eAAY;IACZ,SAAS;IACT,MAAK;IACL,SAAQ;cAEP,kBACC,oBAAC,yBAAD,EAAyC,eAAiB,CAAA,IAE1D,oBAAC,eAAD,CAAgB,CAAA;GAEZ,CAAA;EACL;;AAET;;;AC/EA,IAAa,sBAAsB;CACjC,MAAM,EACJ,qBAAqB,EAAE,UAAU,WAAW,qBAC1C,0BAA0B;CAE9B,MAAM,QAAQ,eACL;EACL,QAAQ,mBAAmB,oBAAoB;EAC/C,WAAW,mBAAmB,oBAAoB;EAClD,SAAS,mBAAmB,oBAAoB;CAClD,IACA,CAAC,cAAc,CACjB;CAEA,IAAI,CAAC,UAAU,OAAO;CAEtB,OACE,qBAAC,OAAD;EAAK,WAAU;EAA2B,eAAa;YAAvD,EACI,UAAU,cAAc,KAAK,MAAM,WAAW,WAAW,YACzD,oBAAC,wBAAD;GACE,iBAAiB,UAAU,YAAY;GACvC,UAAU,UAAU;GACpB,KAAK,UAAU;GACf,cAAc,UAAU;EACzB,CAAA,IACC,MAAM,YACR,oBAAC,uBAAD,CAAwB,CAAA,IACtB,MAEJ,oBAAC,gCAAD,CAAiC,CAAA,CAC9B;;AAET;;;AC3BA,IAAM,WAAW;AAEjB,IAAa,6CAA6C;CACxD,MAAM,EACJ,uCAAA,0CAAwC,uCACxC,4BAA4B,qCAC1B,oBAAoB;CACxB,MAAM,EAAE,+BAA+B,wBACrC,0BAA0B;CAC5B,MAAM,EAAE,gBAAgB,0BAA0B;CAElD,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAAE,IAAI,SAAS,CAAC;CAE5E,MAAM,uBAAuB,OAAiC,IAAI;CAGlE,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,2BAAD;EACE,UACE,CANa,CAAC,oBAAoB,kBAOjC,CAAC,iCACA,YAAY,MAAM,MAAM,EAAE,SAAS,wBAAwB,eAAe;EAE9E,eAAe;GACb,oBAAoB,UAAU,MAAM;GAQpC,IADE,CALwB,EACxB,oBAAoB,YAAY,UAAU,iBAItB,oBAAoB,oBAAoB,UAClC,OAAO,KAAK;EAC1C;EACA,KAAK;CACN,CAAA,GACD,oBAAC,SAAD;EACE,WAAU;EACV,iBAAiB,eAAe;EAChC,IAAI;EACJ,SAAS,OAAO;EAChB,WAAW;EACX,kBAAkB,qBAAqB;YAEvC,oBAAC,yCAAD,EAAuC,gBAAgB,oBAAoB,IAAM,CAAA;CAC1E,CAAA,CACT,EAAA,CAAA;AAEN;AAIA,IAAa,mCAAmC,WAG9C,SAAS,0BAA0B,OAAO,KAAK;CAC/C,MAAM,EAAE,MAAM,sBAAsB;CAEpC,OACE,oBAAC,QAAD;EACE,YAAW;EACX,cAAY,EAAE,4BAA4B;EAC1C,UAAA;EACA,WAAU;EACV,eAAY;EACZ,MAAK;EACL,SAAQ;EACR,GAAI;EACC;YAEL,oBAAC,WAAD,CAAY,CAAA;CACN,CAAA;AAEZ,CAAC;;;AC7ED,IAAa,wBAAwB,EACnC,SACA,eAC+B;CAC/B,MAAM,EAAE,MAAM,sBAAsB;CAEpC,OACE,oBAAC,wBAAD;EACE,aAAa,EAAE,cAAc;EAC7B,UAAU;EACV,eAAe;CAChB,CAAA;AAEL;;;ACfA,IAAM,iBAAiB,WAAiC,EACtD,oBAAoB,MAAM,mBAC5B;AAEA,IAAa,8BAA8B;CACzC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,uBAAuB,cAAc,gBAAgB,OAAO,aAAa;CAEjF,IAAI,gBAAgB,iBAAiB,CAAC,gBAAgB,UAAU,OAAO;CAEvE,MAAM,YACJ,OAAO,KAAK,gBAAgB,QAAQ,MAAM,OAAO,EAAE,WAAW,IAC1D,EAAE,+BAA+B,IACjC,EAAE,sBAAsB;CAE9B,OACE,oBAAC,OAAD;EACE,WAAW,KAAK,iDAAiD,EAC/D,0DAA0D,mBAC5D,CAAC;EACD,eAAY;YAEZ,qBAAC,SAAD;GACE,WAAU;GACV,SAAQ;aAFV;IAIE,oBAAC,SAAD;KACE,gBAAc;KACd,SAAS;KACT,WAAU;KACV,IAAG;KACH,gBAAgB,gBAAgB,yBAAyB;KACzD,MAAK;IACN,CAAA;IACD,oBAAC,QAAD;KAAM,eAAA;KAAY,WAAU;eAC1B,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,eAAD,CAAgB,CAAA;KACZ,CAAA;IACF,CAAA;IACN,oBAAC,QAAD;KAAM,WAAU;eAA6C;IAAgB,CAAA;GACxE;;CACJ,CAAA;AAET;;;ACvCA,IAAM,kCAAgC,EACpC,eACA,qBAC2B;CAC3B;CACA;AACF;AAEA,IAAa,eAAe,UAA+C;CAEzE,MAAM,EAAE,SAAS,QAAQ,SAAS,GAAG,GAAG,gBAAgB;CACxD,MAAM,kBAAkB,6BAA6B;CACrD,cAAc,gBAAgB,OAAO,8BAA4B;CAEjE,IAAI,CAAC,OAAO,MAAM,OAAO;CAEzB,MAAM,kBACJ,WACA,CAAC,gBAAgB,kBAAkB,MAA4C;CAEjF,OACE,oBAAC,wBAAD;EACE,GAAI;EACJ,SAAS;EACT,SAAS;CACV,CAAA;AAEL;;;ACrBA,IAAa,gBAAgB,UAA6B;CAExD,MAAM,EAAE,WAAW,QAAQ,SAAS,GAAG,GAAG,gBAAgB;CAE1D,IAAI,CADc,OAAO,KAAK,MAAM,EAAE,QACtB,OAAO;CAEvB,MAAM,EAAE,OAAO,UAAU,OAAO,wBAAyB,CAAC;CAE1D,OACE,oBAAC,wBAAD;EACE,GAAI;EACJ,WAAW,KAAK,wBAAwB,SAAS;EACjD,OAAO,OAAO;YAEb,OAAO,KAAK,MAAM,MACjB,KAAK,YAAY,MAAM,QACrB,oBAAC,QAAD;GAAM,WAAU;aACb;EACG,GAFiD,QAAQ,GAEzD,IAEN,oBAAC,QAAD;GAAM,WAAU;aACb;EACG,GAF4C,QAAQ,GAEpD,CAEV,KAAK;CACiB,CAAA;AAE5B;;;ACpBA,IAAa,sBAAsB,EACjC,WACA,WAAW,WACX,SACA,MACA,SACA,WACA,cACA,GAAG,gBACsB;CACzB,MAAM,EAAE,iBAAiB,6BAA6B;CACtD,MAAM,EAAE,gBAAgB,0BAA0B;CAClD,MAAM,eAAe,OAAiC,IAAI;CAE1D,MAAM,eAAe,kBAAkB;EACrC,aAAa,aAAa,IAAI;EAC9B,YAAY,SAAS,MAAM;CAC7B,GAAG;EAAC;EAAM;EAAa;CAAY,CAAC;CAEpC,sBAAsB;EACpB,IAAI,CAAC,SAAS;EACd,aAAa,SAAS,eAAe;GAAE,UAAU;GAAW,OAAO;EAAU,CAAC;CAChF,GAAG,CAAC,OAAO,CAAC;CAEZ,OACE,oBAAC,WAAD;EACE,GAAI;EACJ,WAAW,KAAK,kCAAkC,WAAW,EAC3D,4CAA4C,QAC9C,CAAC;EACD,QAAQ;EACC;EACT,UAAU,MAAM;GACd,aAAa;GACb,UAAU,CAAC;EACb;EACA,YAAY,UAAU;GACpB,IAAI,MAAM,QAAQ,SAAS,aAAa;GACxC,YAAY,KAAK;EACnB;EACc;EACd,KAAK;CACN,CAAA;AAEL;;;;;;AC5CA,IAAa,YAAY,EAAE,QAAQ,SAAS,GAAG,GAAG,kBAAiC;CAEjF,IAAI,CAAC,CADc,CAAC,OAAO,KAAK,MAAM,EAAE,QACxB,OAAO;CAEvB,MAAM,EAAE,OAAO,UAAU,OAAO;CAChC,MAAM,mBACJ,MAAM,KAAK,MAAM,MAAM;EACrB,MAAM,UAAU,KAAK,YAAY,MAAM;EACvC,MAAM,2BAA2B,KAAK,QAAQ,cAAc,MAAQ;EACpE,OACE,oBAAC,QAAD;GACE,WAAW,KAAK;IACd,6BAA6B,CAAC;IAC9B,yCAAyC;GAC3C,CAAC;aAGA;EACG,GAHC,QAAQ,GAGT;CAEV,CAAC;CAEH,OACE,oBAAC,uBAAD;EACE,GAAI;EACJ,UAAU,OAAO;EACjB,OAAO,OAAO,QAAQ,OAAO;EAC7B,UAAU,OAAO,QAAQ,OAAO;YAE/B,WAAW;CACS,CAAA;AAE3B;;;AC1DA,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;;;;;;AAU3B,IAAa,wBACX,UACA,iBACsB;CACtB,IAAI,CAAC,YAAY,OAAO,WAAW,aAAa,OAAO;CAEvD,MAAM,aAAa,KAAK,IAAI,GAAG,gBAAgB,SAAS,gBAAgB,CAAC;CACzE,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,mBAAmB,MAAM,MAAM,GAAG,UAAU;CAClD,MAAM,kBAAkB,MAAM,MAAM,UAAU;CAE9C,MAAM,gBAAgB,OAAO,iBAAiB,QAAQ;CACtD,MAAM,SAAS,SAAS,cAAc,KAAK;CAC3C,OAAO,YAAY;CACnB,OAAO,MAAM,WAAW;CACxB,OAAO,MAAM,aAAa;CAC1B,OAAO,MAAM,MAAM;CACnB,OAAO,MAAM,OAAO;CACpB,OAAO,MAAM,aAAa;CAC1B,OAAO,MAAM,WAAW;CAExB,KAAK,MAAM,YAAY,eACrB,OAAO,MAAM,YAAY,UAAU,cAAc,iBAAiB,QAAQ,CAAC;CAG7E,OAAO,cAAc;CAErB,MAAM,cAAc,SAAS,cAAc,MAAM;CACjD,YAAY,YAAY;CACxB,YAAY,cAAc,gBAAgB,SAAS,kBAAkB;CACrE,OAAO,YAAY,WAAW;CAE9B,SAAS,KAAK,YAAY,MAAM;CAChC,OAAO,YAAY,SAAS;CAC5B,OAAO,aAAa,SAAS;CAE7B,MAAM,eAAe,SAAS,sBAAsB;CACpD,MAAM,aAAa,OAAO,sBAAsB;CAChD,MAAM,YAAY,YAAY,sBAAsB;CAEpD,SAAS,KAAK,YAAY,MAAM;CAEhC,MAAM,OAAO,aAAa,QAAQ,UAAU,OAAO,WAAW;CAC9D,MAAM,MAAM,aAAa,OAAO,UAAU,MAAM,WAAW;CAC3D,MAAM,SAAS,UAAU,UAAU,WAAW,cAAc,UAAU,KAAK;CAE3E,OAAO,IAAI,QAAQ,MAAM,KAAK,GAAG,MAAM;AACzC;;;ACHA,IAAM,+BAA6B,EAAE,WAAW,mBAAsC;CACpF;CACA;AACF;AAEA,IAAM,+BACJ,eACyC,EACzC,OAAO,UAAU,SAAS,CAAC,EAC7B;AAEA,IAAa,oBAGT;CACF,MAAM,UACJ,oBAAC,aAAD;EAAa,GAAI;EAAO,QAAQ,MAAM;CAAuC,CAAA;CAE/E,MAAM,UACJ,oBAAC,cAAD;EAAc,GAAI;EAAO,QAAQ,MAAM;CAAwC,CAAA;CAEjF,MAAM,UACJ,oBAAC,UAAD;EAAU,GAAI;EAAO,QAAQ,MAAM;CAAoC,CAAA;AAE3E;AAEA,IAAa,kBAAkB,EAC7B,WACA,sBAAsB,MACtB,oBACA,kBACA,qBACA,2BAA2B,wBACF;CACzB,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,6BAA6B,oBAC7B,aAAa,uBAAuB,gBAClC,oBAAoB;CACxB,MAAM,EAAE,gBAAgB,0BAA0B;CAClD,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,WAAW,2BAA2B;CAC5C,MAAM,EAAE,iBAAiB;CACzB,MAAM,EAAE,WAAW,gBAAgB,cACjC,aAAa,OACb,2BACF;CACA,MAAM,EAAE,UACN,cAAc,aAAa,aAAa,OAAO,2BAAyB,KAAK,CAAC;CAChF,MAAM,+BAA+B,cAEjC,aAAa,aAAa,SAAS,cACnC,SAAS,MAAM,EAAE,cAAc,OAAO,GACxC,CAAC,UAAU,aAAa,aAAa,IAAI,CAC3C;CAEA,MAAM,CAAC,WAAW,gBAAgB,SAAgC,IAAI;CACtE,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,wBAAwB,eACrB,EACL,6BAA6B,aAAa,WAAW,IAAI,QAAQ,EACnE,IACA,CAAC,CACH;CAEA,MAAM,EAAE,MAAM,UAAU,QAAQ,GAAG,MAAM,mBAAmB;EAC1D,WAAW;EACX,QAAQ;EACR,WAAW;EAEX,cAAc,EAAE,WAAW,KAAK;CAClC,CAAC;CAED,MAAM,YAAY,aAAa,UAC3B,yBAAyB,aAAa,WACtC,KAAA;CAEJ,MAAM,mBAAmB,cAA0C;EACjE,IAAI,CAAC,WAAW,OAAO,CAAC;EASxB,QAPE,aAAa,aAAa,SAAS,aAC/B,CAAC,GAAI,SAAS,CAAC,CAAE,EAAE,MAAM,GAAG,MAC1B,OAAQ,EAAwB,QAAQ,EAAE,EAAE,cAC1C,OAAQ,EAAwB,QAAQ,EAAE,CAC5C,CACF,IACC,SAAS,CAAC,GACE,KAAK,MAAM,MAAM;GAClC,MAAM,QAAkC,EAAE,GAAG,YAC3C,8BAAC,4BAAD;IACE,GAAI;IACO;IACX,SAAS,qBAAqB;IACxB;IACN,KAAK,KAAK,GAAG,SAAS;IACtB,oBAAoB,sBAAsB,CAAC;GAC5C,CAAA;GAEH,OAAO;EACT,CAAC;CACH,GAAG;EACD;EACA;EACA;EACA;EACA;EACA,aAAa,aAAa;CAC5B,CAAC;CAED,MAAM,eAAe,aAClB,EAAE,eACD,oBAAC,yBAAD;EACE,0BAA0B,aAAa,aAAa;EACpD,WAAW;EAEV;CACsB,CAAA,GAE3B,CAAC,aAAa,aAAa,MAAM,CACnC;CAEA,gBAAgB;EACd,IAAI,CAAC,uBAAuB,CAAC,eAAe,CAAC,WAAW;EACxD,MAAM,eAAe,UAAsB;GACzC,IAAI,UAAU,SAAS,MAAM,MAAc,GAAG;GAC9C,aAAa,iBAAiB;EAChC;EACA,SAAS,iBAAiB,SAAS,WAAW;EAC9C,aAAa;GACX,SAAS,oBAAoB,SAAS,WAAW;EACnD;CACF,GAAG;EAAC;EAAqB;EAAa;EAAW;CAAY,CAAC;CAE9D,gBAAgB;EACd,KAAK,YAAY,SAAS;CAC5B,GAAG,CAAC,WAAW,IAAI,CAAC;CAEpB,sBAAsB;EACpB,IAAI,CAAC,eAAe,CAAC,QAAQ;EAC7B,MAAM,uBAAuB;GAC3B,MAAM,OAAO,qBAAqB,YAAY,WAAW,MAAM,WAAW,GAAG;GAC7E,IAAI,CAAC,MAAM;IACT,aAAa,UAAU;IACvB,KAAK,aAAa,IAAI;IACtB;GACF;GACA,aAAa,UAAU;GACvB,sBAAsB,iBAAiB,YAAY,WAAW,KAAA;GAC9D,KAAK,aAAa,qBAAqB;GACvC,OAAO;EACT;EAEA,eAAe;CACjB,GAAG;EACD;EACA,OAAO;EACP;EACA,WAAW;EACX;EACA;EACA;EACA;CACF,CAAC;CAED,IAAI,CAAC,eAAe,CAAC,OAAO,UAAU,CAAC,aAAa,CAAC,8BACnD,OAAO;CAET,MAAM,sBACJ,YAAY,aAAa,SAAS,aAC9B,EAAE,0BAA0B,IAC5B,YAAY,aAAa,SAAS,WAChC,EAAE,wBAAwB,IAC1B,YAAY,aAAa,SAAS,aAChC,EAAE,uBAAuB,IACzB,EAAE,kBAAkB;CAE9B,OACE,oBAAC,OAAD;EACE,WAAW,KAAK,uCAAuC,kBAAkB;EACzE,KAAK;EACL,OAAO;GACL,MAAM,KAAK;GACX,UAAU;GACV,KAAK,KAAK;GACV,YAAY,KAAK,QAAQ,KAAK,OAAO,WAAW,KAAA;GAChD,QAAQ;EACV;YAEA,oBAAC,sBAAD;GACE,cAAY;GACZ,WAAW,KAAK,6BAA6B,SAAS;GACtD,QACE,YAAY,aAAa,SAAS,aAAa,qBAAqB,KAAA;GAEtE,OAAO;GACO;GACd,eACE,YAAY,aAAa,SAAS,aAAa,wBAAwB,KAAA;EAE1E,CAAA;CACE,CAAA;AAET;;;ACtPA,IAAM,+BAA6B,EAAE,eAAkC,EAAE,QAAQ;AAEjF,IAAa,0BAA0B,EACrC,gBAC+B,CAAC,MAAM;CACtC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,4BAA4B,0BAA0B;CAC9D,MAAM,oBAAoB,qBAAqB;CAE/C,MAAM,EAAE,YAAY,cADI,6BAEtB,EAAgB,aAAa,OAC7B,2BACF;CAEA,MAAM,wBAAwB,eACrB;EACL,KAAK,EAAE,kBAAkB;EACzB,OAAO,EAAE,oBAAoB;EAC7B,MAAM,EAAE,mBAAmB;EAC3B,OAAO,EAAE,oBAAoB;EAC7B,QAAQ,EAAE,qBAAqB;CACjC,IACA,CAAC,CAAC,CACJ;CAEA,MAAM,cACJ,SAAS,SAAS,sBAAsB,QAAQ,QAAQ,OAAO,EAAE,QAAQ,IAAI;CAC/E,MAAM,qBACJ,SAAS,SAAS,UAAU,EAAE,aAAa,IAAK,eAAe,KAAA;CAEjE,MAAM,qBACJ,eAAe,yBAAyB,eAAe,EAAE,gBAAgB;CAE3E,IAAI,mBACF,OAAO,EAAE,qCAAqC,EAAE,SAAS,kBAAkB,CAAC;CAG9E,OAAO,sBAAsB;AAC/B;;;ACtBA,IAAM,+BAA6B,WAA8B;CAC/D,WAAW,MAAM;CACjB,aAAa,MAAM;CACnB,MAAM,MAAM;AACd;AAEA,IAAM,+BAA6B,WAA8B;CAC/D,gBAAgB,MAAM;CACtB,OAAO,MAAM;AACf;AAEA,IAAM,uBAAuB,WAAkC,EAC7D,SAAS,MAAM,KAAK,QACtB;AAEA,IAAM,kCAAgC,WAAiC,EACrE,eAAe,MAAM,cACvB;AAEA,IAAM,oCAAkC,WAAmC,EACzE,aAAa,MAAM,YACrB;;;;;;;AAQA,IAAM,uBAAuB,UAC3B,MAAM,QAAQ,WAAW,CAAC,MAAM,YAAY,CAAC,MAAM,YAAY;AAEjE,IAAa,kCAAkC,SAAiB,KAAK,WAAW;AAchF,IAAa,oBAAoB,EAC/B,WACA,gCACA,oBACA,eACA,SAAS,aACT,SAAS,aACT,QACA,UACA,WACA,UACA,UACA,aAAa,iBACb,cAAc,kBACd,GAAG,wBACwB;CAC3B,MAAM,EAAE,6BAA6B,mBAA0B,oBAAoB;CACnF,MAAM,EACJ,yBACA,OACA,cACA,SAAS,gBACT,SAAS,gBACT,SACA,cAAc,qBACd,gBACE,0BAA0B;CAC9B,MAAM,oBAAoB,qBAAqB;CAE/C,MAAM,cAAc,uBAAuB,EAAE,aAAa,gBAAgB,CAAC;CAE3E,MAAM,UAAU,eAAe,kBAAkB;CACjD,MAAM,UAAU,eAAe;CAE/B,MAAM,eAAe,oBAAoB,uBAAuB;CAEhE,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,iBAAiB;CACzB,MAAM,EAAE,WAAW,aAAa,SAAS,cACvC,aAAa,OACb,2BACF;CAIA,MAAM,eAAe,CAAC,QAAQ,WAAW,OAAO,IAAI,KAAA;CACpD,MAAM,gBAAgB,OAClB,KAAA,IACC;EACC,UAAU;EACV,cAAc;EACd,YAAY;CACd;CAEJ,MAAM,EAAE,YAAY,cAAc,gBAAgB,aAAa,mBAAmB;CAClF,MAAM,EAAE,kBAAkB,cACxB,gBAAgB,OAChB,8BACF;CACA,MAAM,EAAE,gBAAgB,cACtB,gBAAgB,kBAAkB,OAClC,gCACF;CAEA,MAAM,EAAE,mBACN,cAAc,aAAa,aAAa,OAAO,2BAAyB,KAAK,CAAC;CAEhF,MAAM,eAAe,OAAuB,IAAI;CAChD,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,CAAC;CAE1D,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CAEpD,MAAM,gBAAyD,aAC5D,MAAM;EACL,IAAI,UAAU;GACZ,SAAS,CAAC;GACV;EACF;EACA,IAAI,CAAC,YAAY,SAAS;EAC1B,aAAa,aAAa;GACxB,WAAW;IACT,KAAK,YAAY,QAAQ;IACzB,OAAO,YAAY,QAAQ;GAC7B;GACA,MAAM,EAAE,OAAO;EACjB,CAAC;CACH,GACA;EAAC;EAAU;EAAc;CAAW,CACtC;CAEA,MAAM,mBAAmB,kBAAkB;EACzC,eAAe,KAAK;CACtB,GAAG,CAAC,CAAC;CAEL,MAAM,qBAAqB,kBAAkB;EAC3C,eAAe,IAAI;CACrB,GAAG,CAAC,CAAC;CAEL,MAAM,iBAAiB,aACpB,UAAoD;EACnD,IAAI,WAAW;GACb,UAAU,KAAK;GACf;EACF;EAGA,MAAM,gBAAgB,YAAY,SAAS,SAAS,MAAM,cAAc;EAExE,IACE,aAAa,eACb,aAAa,YAAY,aAAa,OAAO,QAC7C;GACA,IAAI,MAAM,QAAQ,UAAU,OAAO,aAAa,iBAAiB;GACjE,MAAM,cAAc,aAAa,YAAY,aAAa;GAC1D,IAAI,MAAM,QAAQ,SAAS;IACzB,MAAM,eAAe;IACrB,aAAa,aAAa,YAAY,iBAAiB;GACzD;GACA,IAAI,MAAM,QAAQ,WAAW;IAC3B,MAAM,eAAe;IACrB,qBAAqB,SAAS;KAC5B,IAAI,YAAY,OAAO;KACvB,IAAI,aAAa,aAAa,SAC5B,YAAY;UACP,IAAI,YAAY,GACrB,YAAY,YAAY,SAAS;KAEnC,OAAO;IACT,CAAC;GACH;GACA,IAAI,MAAM,QAAQ,aAAa;IAC7B,MAAM,eAAe;IACrB,qBAAqB,SAAS;KAC5B,IAAI,YAAY,OAAO;KACvB,IAAI,aAAa,aAAa,SAC5B,YAAY;UACP,IAAI,aAAa,YAAY,QAClC,YAAY;KAGd,OAAO;IACT,CAAC;GACH;EACF,OAAO,IACL,aAAa,YACZ,MAAM,QAAQ,YACZ,MAAM,QAAQ,eAAe,+BAA+B,aAAa,IAC5E;GACA,MAAM,eAAe;GACrB,aAAa,aAAa;EAC5B,OAAO,IACL,aAAa,KAAK,KAClB,YAAY,WACZ,gBAAgB,iBAChB;GACA,IAAI,MAAM,QAAQ,SAEhB,MAAM,eAAe;GAEvB,aAAa;EACf;CACF,GACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,MAAM,gBAAqD,aACxD,UAAU;EACT,IAAI,UACF,SAAS,KAAK;OAEd,aAAa,iBAAiB;CAElC,GACA,CAAC,UAAU,YAAY,CACzB;CAEA,MAAM,eAAe,aAClB,MAA2C;EAC1C,WAAW,CAAC;EACZ,aAAa,aAAa;GACxB,KAAM,EAAE,OAA+B;GACvC,OAAQ,EAAE,OAA+B;EAC3C,CAAC;CACH,GACA,CAAC,UAAU,YAAY,CACzB;CAEA,gBAAgB;EACd,IAAI,aAAa,aACf,oBAAoB,CAAC;CAEzB,GAAG,CAAC,aAAa,WAAW,CAAC;CAE7B,gBAAgB;EACd,MAAM,oBAAoB,YAAY,SAAS,QAAQ,QAAQ;EAC/D,IAAI,CAAC,YAAY,WAAW,qBAAqB,CAAC,OAAO;EACzD,YAAY,QAAQ,MAAM;CAC5B,GAAG;EAAC;EAAa;EAAO;EAAe;CAAW,CAAC;CAEnD,sBAAsB;;;;;EAKpB,MAAM,WAAW,YAAY;EAC7B,IAAI,CAAC,YAAY,aAAa;;;;;;;;EAS9B,IAAI,SAAS,UAAU,MACrB,SAAS,QAAQ;EAGnB,MAAM,SAAS,SAAS,MAAM;EAC9B,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,OAAO,MAAM,CAAC;EAC3D,MAAM,MAAM,KAAK,IAAI,OAAO,KAAK,IAAI,UAAU,KAAK,MAAM,CAAC;EAE3D,IAAI,SAAS,mBAAmB,SAAS,SAAS,iBAAiB,KAAK;EAExE,SAAS,kBAAkB,OAAO,KAAK,SAAS;CAClD,GAAG;EAAC;EAAM,UAAU;EAAO,UAAU;EAAK;EAAa;CAAW,CAAC;CAEnE,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,OAAO,sBAAsB,oBAAoB,GAC9D,iBAAiB,eACpB,CAAC;EACD,KAAK;YAJP,CAME,oBAAC,UAAD;GACQ,GAAG;GAAyB,GAAG;GACrC,cAAY;GACZ,WAAW,KACT,iBACA,2DACA,SACF;GACA,eAAY;GACZ,UAAU,CAAC,WAAW,CAAC,CAAC;GACxB,SAAS,gBAAgB;GACzB,SAAS,gBAAgB;GACjB;GACR,UAAU;GACQ;GACE;GACpB,WAAW;GACF;GACT,UAAU;GACV,UAAU;GACG;GACb,MAAM,QAAQ;IACZ,YAAY,UAAU;GACxB;GACA,OAAO;EACR,CAAA,GAEA,CAAC,eACA,oBAAC,4BAAD;GACE,WAAW;GACX,qBAAqB;GACH;GACG;EACtB,CAAA,CAEA;;AAET;;;ACrVA,IAAM,2BAA2B,MAAM,cAEpC,EACD,iBAAiB,KACnB,CAAC;AAED,IAAa,oCAAoC,WAAW,wBAAwB;;;;;;;AAQpF,IAAa,gCAAgC;CAC3C,MAAM,EAAE,oBAAoB,4BAA4B;CAExD,MAAM,kBAAkB,6BAA6B;CAErD,gBAAgB;EAGd,OAFoB,kBAAkB,gBAAgB,kBAAkB,WAAW;CAGrF,GAAG,CAAC,iBAAiB,eAAe,CAAC;AACvC;AAEA,IAAM,wCAAwC,WAAkC;CAC9E,eAAe,MAAM,YAAY;CACjC,iBAAiB,MAAM,YAAY,6BAA6B;AAClE;;;;;;;;;;;;;;;;;AAkBA,IAAa,yBAAyB,EACpC,UACA,WACA,WAAW,YAAY,OACvB,YAUK;CACL,MAAM,kBAAkB,uBAAiC,IAAI,IAAI,CAAC;CAClE,MAAM,yBAAyB,0BAA0B;CACzD,MAAM,2BAA2B,4BAA4B;CAC7D,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,oBAAoB,0BAA0B;CACtD,MAAM,EAAE,eAAe,oBAAoB,cACzC,gBAAgB,aAChB,oCACF;CAEA,MAAM,mBAAmB,oBAAoB;CAE7C,MAAM,iCAAiC,OAAO,KAAK,sBAAsB,EAAE,SAAS;CAEpF,MAAM,SAAS,cAEX,cAAc,QAAuC,cAAc,cAAc;EAC/E,aAAa,eAAb,aAAa,aAAe,CAAC;EAC7B,OAAO;CACT,GAAG,CAAC,CAAC,GACP,CAAC,aAAa,CAChB;CAEA,MAAM,kBAAkB,aAAa,OAAgC;EACnE,gBAAgB,QAAQ,IAAI,EAAE;EAE9B,aAAa;GACX,gBAAgB,QAAQ,OAAO,EAAE;EACnC;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,aAAa,UAAkB;EAChD,gBAAgB,QAAQ,SAAS,OAAO,GAAG,KAAK,CAAC;CACnD,GAAG,CAAC,CAAC;CAEL,MAAM,EACJ,cACA,cACA,cAAc,mBACZ,YAAY;EACd;EAGA,UAAU,iCACN,CAAC,mBAAmB,mBACpB;EACJ,UAAU;EACV,SAAS;EACT,YAAY;EACZ,QAAQ,iCACJ,gBAAgB,kBAAkB,cAClC;CACN,CAAC;CAID,IAAI,yBAAyB,oBAAoB,MAC/C,OAAO,oBAAC,WAAD;EAAsB;EAAY;CAAoB,CAAA;CAG/D,MAAM,gBAAgB,KAAK,2BAA2B,SAAS;CAE/D,OACE,oBAAC,yBAAyB,UAA1B;EAAmC,OAAO,EAAE,gBAAgB;YAC1D,qBAAC,WAAD;GAAW,GAAI,aAAa;IAAE,WAAW;IAAe;GAAM,CAAC;aAA/D,CACG,gBACC,oBAAC,OAAD;IACE,WAAW,KAAK,gCAAgC,EAC9C,8CAA8C,eAChD,CAAC;IACD,MAAK;cAEL,oBAAC,wBAAD,EAAwC,eAAiB,CAAA;GACtD,CAAA,GAEN,QACQ;;CACsB,CAAA;AAEvC;AAMA,IAAa,0BAA0B,EACrC,qBACiC;CACjC,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,iBACC,oBAAC,KAAD,EAAA,UAAI,EAAE,wCAAwC,EAAK,CAAA,IAEnD,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,YAAD,CAAa,CAAA,GACb,oBAAC,KAAD,EAAA,UAAI,EAAE,sBAAsB,EAAK,CAAA,CACjC,EAAA,CAAA;CAED,CAAA;AAET;;;AC1KA,IAAa,0BAA0B,EACrC,SACA,GAAG,gBAC8B;CACjC,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,UAAD;EACE,cAAY,EAAE,yBAAyB;EACvC,WAAU;EACV,eAAY;EACH;EACT,GAAI;CACL,CAAA;AAEL;;;ACTA,IAAa,cAAc,EAAE,UAAU,aAAa,GAAG,WAA4B;CACjF,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,kBAAkB,kCAAkC;CAC1D,OACE,oBAAC,QAAD;EACE,YAAW;EACX,cAAY,EAAE,WAAW;EACzB,UAAA;EACA,WAAU;EACV,eAAY;EACZ,UAAU,CAAC;EACX,SAAS;EACT,MAAK;EACL,SAAQ;EACR,GAAI;YAEH,YAAY,oBAAC,UAAD,CAAW,CAAA;CAClB,CAAA;AAEZ;;;ACZA,IAAM,kCAAgC,EAAE,qBAA2C,EACjF,cACF;AAEA,IAAM,6BAA6B,EAAE,SAAS,YAA+B;CAC3E;CACA;AACF;AAEA,IAAa,+BAA+B;CAC1C,MAAM,EAAE,YAAY,uBAAuB;CAC3C,MAAM,EAAE,mBAAmB,0BAA0B;CACrD,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EACJ,eAAA,kBAAgB,eAChB,YAAA,cACA,wBAAwB,mCACtB,oBAAoB;CAExB,MAAM,EAAE,kBAAkB,cACxB,gBAAgB,OAChB,8BACF;CAEA,MAAM,EAAE,YAAY,cAClB,gBAAgB,aAAa,OAC7B,yBACF;CAEA,MAAM,iBAAiB,yBAAyB;;;;;;;CAOhD,MAAM,2BACJ,mCAAmC,KAAA,IAC/B,yBACA;CAEN,MAAM,EAAE,cAAc,wBAAwB,0BAA0B;CACxE,MAAM,mBAAmB,oBAAoB;CAE7C,MAAM,EAAE,YAAY,WAAW,OAAO;CACtC,MAAM,iBAAiB,kBAAkB,SAAS,eAAe,GAAG,CAAC,OAAO,CAAC;CAC7E,MAAM,gCACJ,CAAC,SAAS,UAAU,SAAS,UAAU,EAAE,SAAS,OAAO,KACzD,CAAC,CAAC;CAEJ,MAAM,mBAAmB,CAAC,EAAE,oBAAoB,YAAY,UAAU;CAEtE,IAAI,UAAU,eACZ,oBAAC,cAAD,EAAY,aAAa,aAAe,CAAA,IAExC,oBAAC,YAAD;EAAmB,aAAa;YAC7B,iBAAiB,UAAU,oBAAC,eAAD,CAAgB,CAAA,IAAI,oBAAC,UAAD,CAAW,CAAA;CAC1C,CAAA;CAGrB,IAAI,+BACF,UAAU,oBAAC,0BAAD,EAAwB,SAAS,eAAiB,CAAA;MACvD,IAAI,gBAAgB,OAAO;CAElC,IAAI,kBACF,UAAU,oBAAC,iBAAD,CAAgB,CAAA;MACrB,IAAI,kBAAkB,CAAC,iBAAiB,CAAC,WAAW,kBACzD,UAAU,oBAAC,sCAAD,CAAuC,CAAA;CAGnD,OAAO,oBAAC,OAAD;EAAK,WAAU;YAAuC;CAAa,CAAA;AAC5E;AAEA,IAAa,yCAAyC;CACpD,MAAM,EAAE,gBAAgB,oBAAoB;CAG5C,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,CAJoB,oBAInB,KAAoB,cAAc,oBAAC,aAAD,CAAc,CAAA,IAAI;CACnD,CAAA;AAET;;;ACxFA,IAAM,gCACJ,oBAAC,OAAD;CAAK,WAAU;WACb,oBAAC,cAAD,CAAe,CAAA;AACZ,CAAA;AASP,IAAa,sBAAsB,EACjC,UACA,eAAe,yBACf,aAC6B;CAC7B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,gBAAiB,SAAiC;CACxD,MAAM,QAAQ,gBAAgB,EAAE,eAAe,IAAI,EAAE,kBAAkB;CAEvE,OACE,qBAAC,OAAD;EAAK,WAAU;EAA6B,eAAY;YAAxD;GACE,oBAAC,cAAD,EAAwB,SAAW,CAAA;GACnC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD;MACE,WAAU;MACV,OAAO,EAAE,iBAAiB;gBAEzB;KACE,CAAA;KACL,oBAAC,OAAD;MAAK,WAAU;gBACZ,EAAE,+BAA+B,EAChC,aAAa,GAAG,SAAS,SAAS,IAAI,SAAS,YACjD,CAAC;KACE,CAAA;KACJ,iBACC,oBAAC,OAAD;MAAK,WAAU;gBACZ,EAAE,yBAAyB,EAC1B,UAAU,EAAE,2BAA2B,EACrC,cAAc,cAChB,CAAC,EACH,CAAC;KACE,CAAA;IAEJ;;GACJ,UACC,oBAAC,+BAAD;IACE,cAAY,EAAE,iCAAiC;IAC/C,WAAU;IACV,eAAY;IACZ,SAAS;GACV,CAAA;EAEA;;AAET;;;AC5BA,IAAM,gCAAgC,EACpC,eACA,qBAC2B;CAC3B;CACA;AACF;AAEA,IAAM,kCAAkC,WAAmC,EACzE,aAAa,MAAM,YACrB;AAEA,IAAM,oCAAoC,WAAqC,EAC7E,cAAc,MAAM,KAAK,MAAM,SAAS,OAAO,CAAC,EAAE,QAC/C,YACC,oBAAoB,gBAAgB,OAAO,KAC3C,oBAAoB,iBAAiB,OAAO,CAChD,EACF;AAEA,IAAM,iCAAiC,WAAkC,EACvE,UAAU,MAAM,SAClB;AAEA,IAAM,+BAA+B,EAAE,eAAkC,EAAE,QAAQ;AAEnF,IAAM,gCAAgC;CACpC,MAAM,EACJ,uBAAA,0BAAwB,uBACxB,sBAAA,yBAAuB,sBACvB,iBAAA,oBAAkB,iBAClB,sBAAA,yBAAuB,sBACvB,2BAAA,8BAA4B,8BAC1B,oBAAoB;CAExB,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,EAAE,eAAe,kBAAkB,cACvC,gBAAgB,OAChB,4BACF;CAEA,MAAM,EAAE,gBAAgB,cACtB,gBAAgB,kBAAkB,OAClC,8BACF;CAEA,MAAM,EAAE,aAAa,cACnB,gBAAgB,iBAAiB,OACjC,6BACF;CAEA,MAAM,EAAE,wBAAwB;CAChC,MAAM,EAAE,iBAAiB,cACvB,oBAAoB,OACpB,gCACF;CAEA,IACE,CAAC,iBACD,YAAY,WAAW,KACvB,aAAa,WAAW,KACxB,CAAC,YACD,CAAC,eAED,OAAO;CAGT,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACG,gBACC,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,wBAAD;KACE,SAAS;KACT,gBAAgB;MACd,uBAAuB,eAAe;KACxC;IACD,CAAA;GACE,CAAA,IAEL,oBAAC,wBAAD,CAAuB,CAAA;GAEzB,oBAAC,6BAAD,CAA4B,CAAA;GAC5B,oBAAC,yBAAD,CAAwB,CAAA;GACxB,oBAAC,mBAAD,CAAkB,CAAA;GACjB,YACC,oBAAC,oBAAD;IACY;IAGV,QACE,gBAAgB,gBACZ,KAAA,IACA,gBAAgB,iBAAiB;GAExC,CAAA;EAEA;;AAET;AAEA,IAAa,0BAA0B;CACrC,MAAM,EAAE,YAAY,kBAAkB;CACtC,MAAM,EAAE,wBAAwB,0BAA0B;CAE1D,MAAM,EAAE,YAAY,cADc,6BAEhC,EAA0B,aAAa,OACvC,2BACF;CAEA,MAAM,EACJ,kCAAA,qCAAmC,kCACnC,oBAAA,uBAAqB,UAAU,2BAA2B,oBAC1D,eAAA,kBAAgB,eAChB,aAAA,gBAAc,aACd,uBAAA,0BAAwB,uBACxB,kBAAA,qBAAmB,qBACjB,oBAAoB;CAExB,OACE,oBAAC,uBAAD;EACE,WAAU;EACV,WAAU;YAEV,oBAAC,OAAD;GACE,WAAW,KAAK,8BAA8B,EAC5C,8CAA8C,CAAC,CAAC,QAClD,CAAC;aAEA,oBAAoB,iBACnB,oBAAC,iBAAD,CAAgB,CAAA,IAEhB,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,sBAAD,CAAqB,CAAA,GACrB,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,yBAAD,CAA0B,CAAA,GAC1B,qBAAC,OAAD;KAAK,WAAU;eAAf;MACE,qBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,qBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,WACC,oBAAC,OAAD;SAAK,WAAU;mBACb,oBAAC,eAAD,EAAsB,QAAU,CAAA;QAC7B,CAAA,GAEP,oBAAC,oBAAD,CAAmB,CAAA,CAChB;WACL,oBAAC,yBAAD,CAAwB,CAAA,CACrB;;MACL,oBAAC,oCAAD,CAAmC,CAAA;MACnC,oBAAC,wBAAD,CAAyB,CAAA;KACtB;MACF;KACL,EAAA,CAAA;EAED,CAAA;CACgB,CAAA;AAE3B;;;AC/LA,IAAa,mCAAmC,UAAuC;CACrF,MAAM,EACJ,yBACA,+BACA,uBACA,kBACA,OACA,cACA,gBACA,SACA,SACA,SACA,QACA,qBACA,cACA,gBACE;CAEJ,MAAM,WAAW,QAAQ;CAgCzB,OA9B4D,eACnD;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAGK;AACT;;;AC4BA,IAAM,2BAA2B,UAAmD;CAClF,MAAM,0BAA0B,2BAA2B,KAAK;CAChE,MAAM,EAAE,qBAAqB,oBAAoB,iBAAiB;CAElE,MAAM,8BAA8B,gCAAgC;EAClE,GAAG;EACH,GAAG;EACH,kBAAkB,MAAM,oBAAoB;CAC9C,CAAC;CAED,MAAM,kBAAkB,6BAA6B;CAErD,sBACc;EACV,gBAAgB,YAAY,EAAE,cAAc,gBAAgB,MAAM,CAAC;CACrE,GACA,CAAC,eAAe,CAClB;CAEA,gBAAgB;EACd,MAAM,WAAW,gBAAgB;EACjC,IACE,CAAC,YACD,CAAC,gBAAgB,WACjB,CAAC,gBAAgB,kBACjB,CAAC,gBAAgB,OAAO,OAAO,SAE/B;EAEF,gBAAgB,QACb,SAAS,EAAE,WAAW,SAAS,CAAC,EAChC,MAAM,EAAE,YAAY;GACnB,IAAI,OACF,gBAAgB,UAAU,EAAE,aAAa,MAAM,CAAC;EAEpD,CAAC,EACA,MAAM,QAAQ,KAAK;CACxB,GAAG,CAAC,eAAe,CAAC;CAEpB,wBAAwB;CAExB,OACE,oBAAC,gCAAD;EAAgC,OAAO;YACpC,MAAM;CACuB,CAAA;AAEpC;AAEA,IAAM,6BAA6B,UAAgC;CACjE,MAAM,EAAE,mBAAA,sBAAoB,sBAC1B,oBAAoB,iBAAiB;CACvC,MAAM,kBAAkB,6BAA6B;CACrD,MAAM,KAAK,YAAY;CAMvB,OACE,oBAAC,uBAAD;EAAuB,IALD,gBAAgB,WACpC,uCAAuC,OACvC,gCAAgC;YAIhC,oBAAC,yBAAD;GAAyB,GAAI;aAC3B,oBAAC,qBAAD,CAAoB,CAAA;EACG,CAAA;CACJ,CAAA;AAE3B;;;;AAKA,IAAa,kBAAkB,MAAM,KACnC,yBACF;;;AC9IA,IAAM,gBAA+B;CACnC;CACA,CAAC,WAAW,EAAE,aAAa,MAAM,CAAC;CAClC;CACA;AACF;AAEA,IAAa,qBAAqB,SAChC,oBAAC,eAAD;CAA8B;CAAe,UAAA;WAC1C;AACY,CAAA;AAGjB,IAAM,qBAAqB,wBAAoD;CAC7E,IAAI;CACJ,KAAK,MAAM,eAAe,OAAO,OAAO,mBAAmB,GACzD,YAAY,SAAS,SAAS;EAC5B,IAAI,cAAc,IAAI,KAAK,WAAW,UAAU,KAAK,IAAI,KAAK,KAAK,UAAU,GAC3E;EACF,aAAa;CACf,CAAC;CAGH,OAAO;AACT;AAEA,IAAa,2BACX,SACA,GACA,eAAwD,MACxD,yBACc;CACd,MAAM,gBACJ,QAAQ,MAAM,eAAe,QAAQ,MAAM,eAAe,SAAS;CAErE,MAAM,sBACJ,yBAAyB;EAAE,UAAU;EAAc,SAAS;CAAc,CAAC,KAC3E,eAAe;CACjB,MAAM,OAAO,eAAe;CAE5B,IAAI,CAAC,eACH,OAAO,EAAE,gBAAgB;CAG3B,IAAI,iBAAiB,aAAa,GAChC,OAAO,EAAE,iBAAiB;CAG5B,IAAI,MACF,IAAI,CAAC,KAAK,YAKR,OAAO,EAAE,2CAA2C;EAClD,WAJA,KAAK,YAAY,OAAO,QAAQ,UAAU,EAAE,SACxC,EAAE,KAAK,IACN,KAAK,YAAY,QAAQ,EAAE,MAAM;EAGtC,UAAU,KAAK;CACjB,CAAC;MACI;EACL,MAAM,aAAa,kBACjB,KAAK,sBACP;EACA,MAAM,SACJ,cAAc,KAAK,QAAQ,MAAM,QAAQ,IAAI,OAAO,WAAW,SAAS;EAE1E,IAAI,UAAU,YACZ,OAAO,EAAE,4CAA4C;GACnD,gBAAgB,OAAO;GACvB,SACE,YAAY,MAAM,OAAO,QAAQ,UAAU,EAAE,SACzC,EAAE,KAAK,IACN,WAAW,MAAM,QAAQ,EAAE,MAAM;EAC1C,CAAC;CAEL;CAGF,IAAI,qBACF,OAAO,uBAAuB,aAAa,IACvC,sBACA,kBAAkB,mBAAmB;CAG3C,IAAI,cAAc,SAChB,OAAO,IAAI,cAAc;CAG3B,IAAI,cAAc,aAAa,QAC7B,OAAO,EAAE,kBAAkB;CAG7B,IAAI,cAAc,iBAChB,OAAO,EAAE,mBAAmB;CAG9B,OAAO,EAAE,kBAAkB;AAC7B;;;;AAgBA,IAAa,0BACX,SACA,kBACuB;CACvB,MAAM,OAAO,QAAQ;CACrB,IAAI,MAAM,SAAS,OAAO,KAAK,UAAU,UAAU,OAAO,KAAK;CAE/D,MAAM,aAAa,OAAO,OAAO,QAAQ,MAAM,OAAO;CACtD,IAAI,WAAW,WAAW,GAAG;EAE3B,MAAM,QADQ,WAAW,MAAM,MAAM,EAAE,MAAM,OAAO,aACtC,GAAO,MAAM;EAC3B,IAAI,SAAS,OAAO,UAAU,UAAU,OAAO;CACjD;AAEF;AAEA,IAAa,8BACX,YACwC;CACxC,MAAM,UAAU,OAAO,OAAO,QAAQ,MAAM,OAAO;CACnD,IAAI,QAAQ,UAAU,GAAG;CAEzB,MAAM,aAA8C,CAAC;CACrD,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,EAAE,SAAS;EACjB,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EACjC,WAAW,KAAK;GAAE,UAAU,KAAK;GAAO,UAAU,KAAK;EAAK,CAAC;CAC/D;CACA,OAAO,EACL,SAAS,WACX;AACF;;;;;;;;;AChJA,SAAS,0BACP,SACA,oBACA,eACoB;CACpB,MAAM,OAAO,QAAQ;CACrB,IAAI,MAAM,QAAQ,OAAO,KAAK,SAAS,UAAU,OAAO,KAAK;CAE7D,MAAM,aAAa,OAAO,OAAO,QAAQ,MAAM,OAAO;CACtD,MAAM,eAAe,WAAW,QAAQ,MAAM,EAAE,MAAM,OAAO,aAAa;CAE1E,IAAI,WAAW,WAAW,KAAK,aAAa,WAAW,GAErD,OADa,aAAa,GAAG,MAAM,QACpB;CAEjB,IAAI,aAAa,UAAU,GAAG;EAC5B,MAAM,QAAQ,aACX,KAAK,MAAM,EAAE,MAAM,IAAI,EACvB,OAAO,OAAO,EACd,MAAM,GAAG,CAAC;EACb,IAAI,MAAM,SAAS,GAAG,OAAO,MAAM,KAAK,IAAI;CAC9C;AAEF;;;;;;;;AASA,IAAa,yBACX,YACuB;CACvB,MAAM,EAAE,WAAW,eAAe,uBAAuB;CACzD,MAAM,EAAE,MAAM,sBAAsB,uBAAuB;CAC3D,MAAM,qBAAqB,EAAE,gBAAgB;CAE7C,MAAM,CAAC,aAAa,kBAAkB,eACpC,UACI,0BAA0B,SAAS,oBAAoB,OAAO,UAAU,KAAA,CAAS,IACjF,KAAA,CACN;CAEA,gBAAgB;EACd,IAAI,CAAC,SAAS;GACZ,eAAe,KAAA,CAAS;GACxB;EACF;EACA,MAAM,0BACJ,eACE,0BACE,SACA,oBACA,OAAO,UAAU,KAAA,CACnB,CACF;EACF,kBAAkB;EAClB,OAAO,GAAG,gBAAgB,iBAAiB;EAC3C,aAAa;GACX,OAAO,IAAI,gBAAgB,iBAAiB;EAC9C;CACF,GAAG;EAAC;EAAS,SAAS;EAAM;EAAQ;CAAkB,CAAC;CAEvD,OAAO;AACT;;;ACnEA,IAAM,iBAA0C;CAC9C,SAAS,CAAC;CACV,eAAe,KAAA;AACjB;AAWA,IAAa,yBAAyB,UAAoC;CACxE,MAAM,EAAE,SAAS,eAAe,kBAAkB;CAClD,MAAM,EAAE,WAAW,eAAe;CAElC,MAAM,qBAAqB,sBAAsB,OAAO;CACxD,MAAM,eAAe,iBAAiB;CAEtC,MAAM,CAAC,cAAc,mBAAmB,eACtC,UACK,iBAAiB,uBAAuB,SAAS,OAAO,UAAU,KAAA,CAAS,IAC5E,KAAA,CACN;CACA,MAAM,CAAC,yBAAyB,8BAC9B,eACE,UAAW,2BAA2B,OAAO,KAAK,iBAAkB,cACtE;CAEF,gBAAgB;EACd,IAAI,CAAC,SAAS;EACd,IAAI,eAAe;EAEnB,MAAM,mBAAmB;GACvB,gBAAgB,uBAAuB,SAAS,OAAO,UAAU,KAAA,CAAS,CAAC;GAC3E,2BAA2B,2BAA2B,OAAO,KAAK,cAAc;EAClF;EAEA,WAAW;EACX,OAAO,GAAG,gBAAgB,UAAU;EACpC,aAAa;GACX,OAAO,IAAI,gBAAgB,UAAU;EACvC;CACF,GAAG;EAAC;EAAS,SAAS;EAAM;EAAQ;CAAa,CAAC;CAElD,OAAO,eACE;EACL,cAAc,iBAAiB;EAC/B;EACA;CACF,IACA;EAAC;EAAc;EAAc;EAAyB;CAAa,CACrE;AACF;;;;AC/DA,IAAa,4BACX,qBAAC,OAAD;CACE,eAAA;CACA,MAAK;CACL,QAAO;CACP,SAAQ;CACR,OAAM;CACN,OAAM;WANR;EAQE,oBAAC,UAAD;GAAQ,IAAG;GAAM,IAAG;GAAM,GAAE;EAAO,CAAA;EACnC,oBAAC,UAAD;GAAQ,IAAG;GAAO,IAAG;GAAM,GAAE;EAAO,CAAA;EACpC,oBAAC,UAAD;GAAQ,IAAG;GAAO,IAAG;GAAM,GAAE;EAAO,CAAA;CACjC;;;;ACbP,IAAM,wBAAwB;;;;;;;;;;;;AAkB9B,IAAM,wBAAwB,gBAAwC;CAOpE,OAAO,cAAc,CAAC,GAAG,WAAW,GAAG,CAN3B,YACT,KAAK,UAAU,MAAM,MAAM,MAAM,EAAE,EACnC,KAAK,EACL,KAAK,GAGgC,CAAG,CAAC;AAC9C;;;;;;;AAQA,SAAgB,yBACd,aACA,UAAkB,uBACe;CACjC,MAAM,oBAAoB,qBAAqB,WAAW;CAC1D,MAAM,CAAC,cAAc,mBAAmB,SAAwB,CAAC,CAAC;CAClE,MAAM,WAAW,OAA6C,IAAI;CAClE,MAAM,eAAe,OAAO,KAAK;CAEjC,gBAAgB;EACd,IAAI,kBAAkB,SAAS,GAAG;GAChC,IAAI,SAAS,SAAS;IACpB,aAAa,SAAS,OAAO;IAC7B,SAAS,UAAU;GACrB;GACA,aAAa,UAAU;GACvB,gBAAgB,iBAAiB;GACjC;EACF;EAEA,IAAI,kBAAkB,WAAW,KAAK,aAAa,WAAW,CAAC,SAAS,SACtE,SAAS,UAAU,iBAAiB;GAClC,SAAS,UAAU;GACnB,aAAa,UAAU;GACvB,gBAAgB,CAAC,CAAC;EACpB,GAAG,OAAO;CAEd,GAAG,CAAC,mBAAmB,OAAO,CAAC;CAE/B,sBACc;EACV,IAAI,SAAS,SAAS,aAAa,SAAS,OAAO;CACrD,GACA,CAAC,CACH;CAEA,OAAO,EAAE,aAAa;AACxB;;;;;;AC/DA,IAAa,0BACX,cACA,MACG;CACH,MAAM,aAAa,aAChB,KAAK,EAAE,WAAW,MAAM,MAAM,KAAK,KAAK,MAAM,MAAM,EAAE,EACtD,OAAO,OAAO;CACjB,MAAM,QAAQ,aAAa;CAE3B,IAAI,UAAU,KAAK,WAAW,WAAW,GACvC,OAAO,EAAE,0BAA0B,EAAE,QAAQ,WAAW,GAAG,CAAC;CAG9D,IAAI,UAAU,KAAK,WAAW,WAAW,GACvC,OAAO,EAAE,2BAA2B,EAClC,QAAQ,GAAG,WAAW,GAAG,OAAO,WAAW,KAC7C,CAAC;CAGH,OAAO,EAAE,iCAAiC,EAAE,MAAM,CAAC;AACrD;;;;;;;ACRA,IAAa,yBAAyB,UAAsC;CAC1E,MAAM,EAAE,aAAa,UAAU;CAE/B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,eAAe,WAAW,uBAAuB,uBAAuB;CAEhF,MAAM,WADiB,iBACN,GAAgB,MAAM,QAAQ;CAC/C,MAAM,EAAE,WAAW,eAAe,uBAAuB;CACzD,MAAM,EAAE,SAAS,CAAC,MAAM,iBAAiB,uBAAuB;CAEhE,MAAM,kBAAkB,CAAC,aACrB,OAAO,OAAO,MAAM,EAAE,QACnB,EAAE,WAAW,WAAW,MAAM,OAAO,OAAO,MAAM,MAAM,CAAC,SAC5D,IACA,CAAC;CAEL,MAAM,iBAAiB,aACnB,OAAO,OAAO,MAAM,EAAE,QACnB,EAAE,WAAW,WAAW,MAAM,OAAO,OAAO,MAAM,MAAM,cAAc,QACzE,IACA,CAAC;CAGL,MAAM,EAAE,iBAAiB,yBADL,aAAa,iBAAiB,eACW;CAC7D,MAAM,QAAQ,uBAAuB,cAAc,CAAC;CAEpD,IAAI,eAAe,kBAAkB,SAAS,aAAa,WAAW,GACpE,OAAO;CAGT,OACE,qBAAC,QAAD;EACE,WAAW,KAAK,qCAAqC,EACnD,6CAA6C,WAC/C,CAAC;EACD,eAAY;YAJd,CAME,oBAAC,QAAD;GAAM,WAAU;aAA2C;EAAY,CAAA,GACvE,oBAAC,QAAD;GAAM,WAAU;aACd,oBAAC,qBAAD,CAAsB,CAAA;EAClB,CAAA,CACF;;AAEV;;;AC/CA,IAAM,yBAAuB,EAAE,kBAA+B,EAAE,WAAW;;AAG3E,IAAM,gCAAgC,YACpC,QAAQ,MAAM,QAAQ,KAAA;;AAGxB,IAAM,wBAAwB,EAC5B,YACA,mBACA,iBAKI;CACJ,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,eAAe,WAAW,uBAAuB,sBAAsB;CAE/E,MAAM,WADiB,iBACN,GAAgB,MAAM,QAAQ;CAC/C,MAAM,EAAE,WAAW,eAAe,sBAAsB;CACxD,MAAM,EAAE,SAAS,CAAC,MAAM,iBAAiB,sBAAsB;CAC/D,MAAM,iBAAiB,OAAO,OAAO,MAAM,EAAE,QAC1C,EAAE,WAAW,WAAW,MAAM,OAAO,OAAO,MAAM,MAAM,cAAc,QACzE;CACA,MAAM,YAAY,eAAe,kBAAkB,SAAS,eAAe,SAAS;CACpF,MAAM,iBAAiB,EAAE,cAAc,EAAE,OAAO,cAAc,EAAE,CAAC;CACjE,MAAM,kBAAkB,oBACpB,GAAG,kBAAkB,KAAK,mBAC1B;CACJ,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,QAAD;GACE,WAAU;aAGT,YACC,oBAAC,uBAAD,EAAmC,WAAa,CAAA,IAEhD,oBAAA,YAAA,EAAA,UAAG,gBAAkB,CAAA;EAEnB,GAPC,YAAY,WAAW,SAOxB;CACH,CAAA;AAET;AAWA,IAAa,gBAAgB,UAA6B;CACxD,MAAM,EAAE,aAAa,eAAe,WAAW;CAE/C,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,YAAY,uBAAuB;CAC3C,MAAM,EAAE,uBAAuB,oBAAoB;CACnD,MAAM,EAAE,mBAAmB,mBAAmB;CAC9C,MAAM,EAAE,cAAc,wBAAwB,sBAAsB,EAAE,QAAQ,CAAC;CAE/E,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,EAAE,YAAY,6BAClB,cAAc,gBAAgB,OAAO,qBAAmB,KAAK,CAAC;CAEhE,MAAM,aAAa,iBACf,2BACA,SACG,OAAO,eAAe,IACvB;CAGN,MAAM,oBACJ,iBACA,uBACA,6BAA6B,MAAM,KACnC,KAAA;CAEF,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,OAAD;IAAK,WAAU;cACZ,mBAAmB,aAAa,sBAAsB,oBAAC,oBAAD,CAAqB,CAAA;GACzE,CAAA;GACL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eAAiC,EAAE,QAAQ;IAAO,CAAA,GACjE,oBAAC,sBAAD;KACc;KACO;KACnB,YAAA;IACD,CAAA,CACE;;GACJ,CAAC,kBACA,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,QAAD;KACE,YAAW;KACX,cAAY,EAAE,mBAAmB;KACjC,UAAA;KACA,WAAU;KACV,eAAY;KACZ,SAAS;KACT,MAAK;KACL,SAAQ;eAER,oBAAC,WAAD,CAAY,CAAA;IACN,CAAA;GACL,CAAA;EAEJ;;AAET;;;AC1HA,IAAM,uBAAuB,EAAE,kBAA+B,EAC5D,WACF;AAEA,IAAa,oBAAoB;CAC/B,MAAM,EAAE,WAAW,uBAAuB,aAAa;CACvD,MAAM,EAAE,MAAM,sBAAsB,aAAa;CACjD,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,EAAE,YAAY,6BAClB,cAAc,gBAAgB,OAAO,mBAAmB,KAAK,CAAC;CAEhE,MAAM,aAAa,iBACf,2BACA,SACG,OAAO,eAAe,IACvB;CAEN,IAAI,CAAC,YAAY,OAAO;CAExB,OACE,oBAAC,OAAD;EAAK,WAAU;YAA0B,EAAE,cAAc,EAAE,OAAO,WAAW,CAAC;CAAO,CAAA;AAEzF;;;ACNA,IAAM,2BAA2B,UAA8B;CAC7D,MAAM,EACJ,UACA,WACA,MAAM,kBACN,UACA,YACA,GAAG,kCACD;CAEJ,MAAM,EAAE,GAAG,oBAAoB,sBAAsB,eAAe;CAEpE,MAAM,gBAAgB,cAAc;EAClC;EACA,GAAG;EACH;EACA;EACA;EACA;EACA,yBAAyB;CAC3B,CAAC;CAED,OACE,oBAAC,OAAD;EACE,WAAW,KACT,4BACA,EAAE,sCAAsC,SAAS,GACjD,SACF;EACA,aAAW,iBAAiB,YAAY;EACxC,eAAa,WAAW,4BAA4B;YAEpD,oBAAC,OAAD;GAAK,WAAU;aAAiC;EAAmB,CAAA;CAChE,CAAA;AAET;;;;AAKA,IAAa,gBAAgB,MAAM,KACjC,uBACF;;;ACzDA,IAAa,cAAc,UAAwB;CACjD,MAAM,EAAE,aAAA,gBAAc,gBAAuB,oBAAoB,YAAY;CAC7E,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,eAAD,EAAe,MAAM,MAAM,QAAQ,WAAa,CAAA;GAChD,oBAAC,SAAD;IAAS,gBAAA;IAAe,YAAA;IAAW,GAAI;GAAQ,CAAA;GAC/C,oBAAC,eAAD,CAAc,CAAA;EACX;;AAET;;;;;;AC+BA,IAAa,UAAU,UAAuB;CAC5C,MAAM,EAAE,SAAS,eAAe,WAAW,uBAAuB,QAAQ;CAC1E,MAAM,iBAAiB,iBAAiB;CAExC,IAAI,CAAC,UAAU,CAAC,gBAAgB,OAAO;CACvC,IAAI,eAAe,YAAY,OAAO,OAAO;CAG7C,OAEE,8BAAC,aAAD;EACE,GAAI;EACJ,KAAK,WAAW,UAAU,iBAAiB,GAAG,GAAG,SAAS;CAC3D,CAAA;AAEL;AAEA,IAAM,cAAY,eAA4B;CAC5C,eAAe,UAAU,WAAW;CACpC,eAAe,UAAU,WAAW;CACpC,eAAe,UAAU;CACzB,SAAS,UAAU;AACrB;AAEA,IAAM,eAAe,UAAyC;CAC5D,MAAM,EACJ,gCACA,4BACA,8BACA,uCACA,YAAY,MACZ,sBAAsB,OACtB,SAAS,aACT,iBAAiB,OAAO,KAAK,eAAe,GAC5C,gBACE;CACJ,MAAM,iBAAiB,iBAAiB;CAExC,MAAM,EACJ,QACA,eACA,mBACA,iBAAiB,CAAC,GAClB,6BACE,uBAAuB,QAAQ;CACnC,MAAM,EAAE,aAAa,mBAAmB,wBAAwB,QAAQ;CACxE,MAAM,EAAE,kBAAkB,eAAe,QAAQ;CACjD,MAAM,EACJ,SAAS,gBACT,YAAA,eAAa,YACb,cAAA,iBAAe,cACf,mBACE,oBAAoB,QAAQ;CAEhC,MAAM,EAAE,eAAe,eAAe,eAAe,YACnD,cAAc,gBAAgB,OAAO,UAAQ,KAAK,CAAC;CAIrD,MAAM,qBAFgB,eAAe,4BAA4B,YACzC,eAAe,iBAAiB,iBAAiB;CAGzE,MAAM,oBAAoB,cAAc,yBAAyB;CAEjE,gBAAgB;EACd,IAAI,gBAAgB;EAEpB,KAAK,QAAQ,eAAe,KAAK,GAE/B,eAAe;CAEnB,GAAG;EAAC;EAAQ;EAAgB;CAAc,CAAC;CAE3C,MAAM,cASF,iBACA;EACE,aAAa;EACb,kBAAkB;EAClB,UAAU,eAAe;EACzB,eAAe,eAAe;EAC9B,UAAU;CACZ,IACA;EACE,SAAS;EACT,aAAa;EACb,UAAU;EACV,UAAU;CACZ;CAEJ,MAAM,kBAAkB,UAAU;CAElC,IAAI,CAAC,iBAAiB,OAAO;CAE7B,MAAM,cACJ,eAAe,UACf,KAAK,+CAA+C,EAClD,iCAAiC,YACnC,CAAC;CAEH,MAAM,OACJ,oBAAC,cAAD;EAEE,SAAS;EACT,SAAS;EACT,GAAI;CACL,GAJM,gBAAgB,EAItB;CAGH,OAEE,oBAAC,oBAAoB,UAArB;EACE,OAAO,EACL,cAAc,UAAU,KAAA,EAC1B;YAEA,qBAAC,OAAD;GAAK,WAAW;aAAhB;IACE,oBAAC,gBAAD;KAA2B;KAAa,QAAQ;IAAkB,CAAA;IAClE,oBAAC,mBAAD;KACE,sBAAsB,CAAC;KACjB;KACN,SAAS;KACO;KAChB,oBAAoB;KACpB,YAAA;KACA,GAAI;KACJ,GAAK,cACD,wCACA;IACL,CAAA;IACD,oBAAC,iBAAD;KACE,OAAO;KACP,QAAQ,UAAU;KAClB,GAAI;IACL,CAAA;GACE;;CACuB,CAAA;AAElC;;;ACjKA,IAAM,qBAAyC,CAAC;AAEhD,IAAa,oBAA+C,UAAU;CACpE,MAAM,EACJ,UAAU,cACV,gBAAgB,oBAChB,eAAe,qBACb;CACJ,MAAM,CAAC,kBAAkB,uBAAuB,SAAS,KAAK;CAE9D,MAAM,EACJ,kBAAkB,wBAClB,+BAA+B,iBAAiB,iBAC9C,oBAAoB,kBAAkB;CAE1C,MAAM,EACJ,8BACA,gBAAgB,uBAChB,SACA,eACE,kBAAkB,kBAAkB;CACxC,MAAM,EAAE,MAAM,sBAAsB,kBAAkB;CACtD,MAAM,WACJ,gBACA,iBAAiB,YAAY;EAC3B,WAAW,QAAQ;EACnB;CACF,CAAC;CACH,MAAM,EAAE,WAAW,0BAA0B,EAAE,IAAI,SAAS,CAAC;CAE7D,MAAM,iBAAiB,sBAAsB;CAC7C,MAAM,eAAe,oBAAoB,SAAS,iBAAiB;CAEnE,MAAM,oBAAoB,cAAc;EACtC,MAAM,MAA2C,CAAC;EAElD,KAAK,MAAM,YAAY,cAAc;;GACnC,IAAA,iBAAI,SAAS,UAAb,IAAA,kBAAuB;EACzB;EAEA,OAAO;CACT,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,+BAA+B,cAAc;EACjD,IAAI,MAAM,QAAQ,eAAe,GAAG,OAAO;EAE3C,OAAO,OAAO,QAAQ,gBAAgB,KAAK,EAAE,KAC1C,CAAC,MAAM,EAAE,WAAW,MAAM,gBAAgB;GACzC;GACA;GACA;GACA;EACF,EACF;CACF,GAAG,CAAC,eAAe,CAAC;CAEpB,MAAM,uBAAuB,wBAAwB,eAAe;CAEpE,OACE,oBAAC,OAAD;EACE,cAAY,EAAE,oBAAoB;EAClC,WAAU;EACV,eAAY;EACZ,MAAK;YAEJ,CAAC,mBACA,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,MAAD;GACE,WAAU;GACV,eAAY;aAEX,6BAA6B,KAC3B,EAAE,WAAW,MAAM,cAAc,MAAM,mBACtC,oBAAC,MAAD;IAAI,WAAU;cACZ,oBAAC,UAAD;KACE,cAAY,EAAE,4CAA4C,EACxD,cAAc,gBAAgB,aAChC,CAAC;KACD,gBAAc,OAAO,kBAAkB,kBAAkB;KACzD,WAAW,KAAK,+CAA+C;KAC/D,eAAY;KACZ,aAAW;KACX,UAAU,UAAU;MAClB,eAAe,cAAc,KAAK;MAClC,IAAI,8BACF,OAAO,MAAM;KAEjB;KACA,MAAK;eAEL,oBAAC,QAAD;MAAM,WAAU;gBACd,oBAAC,WAAD,CAAY,CAAA;KACR,CAAA;IACA,CAAA;GACN,GArBwD,YAqBxD,CAER;EACE,CAAA,GACH,wBACC,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,6BAA6B;GAC3C,UAAA;GACA,WAAU;GACV,eAAY;GACZ,eAAe;IACb,oBAAoB,IAAI;GAC1B;GACA,MAAK;GACL,SAAQ;aAER,oBAAC,UAAD,CAAW,CAAA;EACL,CAAA,CAEV,EAAA,CAAA,IAEF,oBAAC,8BAAD;GACE,GAAI;GACM;GACV,gBAAgB,OAAO,cAAc,UAAU;IAC7C,MAAM,eAAe,cAAc,KAAK;IACxC,IAAI,8BACF,OAAO,MAAM;GAEjB;EACD,CAAA;CAEA,CAAA;AAET;AAEA,iBAAiB,eAAe,EAAE,WAAW,iBAAiB;CAE5D,OAAO,oBADmB,aAAa,YAAY,GACN,GAAG;AAClD;AAEA,iBAAiB,cAAc;AAE/B,iBAAiB,eAAe,SAAS,6BAA6B,EACpE,UACA,gBAAgB,oBAChB,eAAe,oBACd;CACD,MAAM,EAAE,kBAAkB,2BAA2B,oBACnD,+BACF;CACA,MAAM,EACJ,8BACA,gBAAgB,uBAChB,YACE,kBAAkB,kBAAkB;CACxC,MAAM,EAAE,MAAM,sBAAsB,kBAAkB;CAEtD,MAAM,iBAAiB,sBAAsB;CAC7C,MAAM,eAAe,oBAAoB,SAAS,iBAAiB;CAEnE,MAAM,EAAE,WAAW,0BAA0B,EAAE,IAAI,YAAY,GAAG,CAAC;CAEnE,MAAM,oBAAoB,cAAc;EACtC,MAAM,MAA2C,CAAC;EAElD,KAAK,MAAM,YAAY,cAAc;;GACnC,IAAA,kBAAI,SAAS,UAAb,IAAA,mBAAuB;EACzB;EAEA,OAAO;CACT,GAAG,CAAC,YAAY,CAAC;CAEjB,IAAI,MAAM,QAAQ,eAAe,KAAK,CAAC,gBAAgB,UACrD,OAAO;CAGT,OACE,oBAAC,OAAD;EACE,cAAY,EAAE,oBAAoB;EAClC,WAAU;EACV,eAAY;EACZ,MAAK;YAEJ,OAAO,QAAQ,gBAAgB,QAAQ,EAAE,KACvC,CAAC,cAAc,EAAE,WAAW,MAAM,oBACjC,oBAAC,UAAD;GACE,cAAY,EAAE,4CAA4C,EACxD,cAAc,gBAAgB,aAChC,CAAC;GACD,gBAAc,OAAO,kBAAkB,kBAAkB;GACzD,WAAU;GACV,eAAY;GACZ,aAAW;GAEX,UAAU,UAAU;IAClB,eAAe,cAAc,KAAK;IAClC,IAAI,8BACF,OAAO,MAAM;GAEjB;GACA,MAAK;aAEL,oBAAC,QAAD;IAAM,WAAU;cACd,oBAAC,WAAD,CAAY,CAAA;GACR,CAAA;EACA,GAZD,YAYC,CAEZ;CACG,CAAA;AAET;;;AC/NA,SAAgB,kBAAkB,SAAgC;CAChE,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EAAE,sBAAsB,gCAC5B,kBAAkB,mBAAmB;CACvC,MAAM,EAAE,MAAM,sBAAsB,mBAAmB;CACvD,MAAM,CAAC,WAAW,gBAAgB,SAA6B,CAAC,CAAC;CACjE,MAAM,EACJ,sBAAsB,0BACtB,cACA,aACA,SACE;CACJ,MAAM,CAAC,WAAW,gBAAgB,SAAS,WAAW;CACtD,MAAM,uBAAuB,4BAA4B;CACzD,MAAM,CAAC,cAAc,mBAAmB,SAAwB,IAAI;CAEpE,gBAAgB;EACd,IAAI,CAAC,aACH;EAGF,IAAI,SAAS;EAEb,CAAC,YAAY;GACX,IAAI;IACF,aAAa,IAAI;IACjB,MAAM,YAAY,MAAM,qBAAqB,gBAAgB,KAAA,GAAW,IAAI;IAE5E,IAAI,CAAC,QACH,aAAa,SAAS;GAE1B,SAAS,GAAG;IACV,IAAI,CAAC,QAAQ;KACX,aAAa,CAAC,CAAC;KACf,gBAAgB;MACd,SAAS;MACT,OAAO,aAAa,QAAQ,IAAI,KAAA;MAChC,SAAS,EAAE,0BAA0B;MACrC,UAAU;MACV,MAAM;KACR,CAAC;IACH;GACF,UAAU;IACR,IAAI,CAAC,QACH,aAAa,KAAK;GAEtB;EACF,GAAG;EAEH,aAAa;GACX,SAAS;EACX;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAMD,OAAO;EAAE;EAAW;EAAW,SAJf,kBAAkB;GAChC,gBAAgB,KAAK,OAAO,CAAC;EAC/B,GAAG,CAAC,CAE2B;CAAQ;AACzC;;;ACpDA,IAAM,6BAA6B,EAAE,YAAY,GAAG;AAEpD,IAAa,+CAA+C;CAY1D,OAAO,oBAAA,YAAA,EAAA,UAXU,cAEb,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,UAC5B,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD,EAAK,WAAU,sDAAuD,CAAA,GACtE,oBAAC,OAAD,EAAK,WAAU,oDAAqD,CAAA,CACjE;IAHmE,KAGnE,CACN,GACH,CAAC,CAGO,EAAW,CAAA;AACvB;AAQA,IAAa,0BAA2D,EACtE,sBACA,gBACA,8BACA,eACA,qBAAqB,yBACrB,gBACA,WACA,sBACA,yBACI;CACJ,MAAM,CAAC,0BAA0B,+BAA+B,SAAS,KAAK;CAC9E,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EACJ,QAAA,WAAS,QACT,mBAAmB,wCACnB,kBAAkB,wBAClB,+BAA+B,iBAAiB,iBAC9C,oBAAoB,uBAAuB,IAAI;CACnD,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,EACJ,gBAAgB,uBAChB,SACA,qBAAqB,+BACnB,kBAAkB,uBAAuB,IAAI;CAEjD,MAAM,sBACJ,2BAA2B,8BAA8B;CAE3D,MAAM,uBAAuB,wBAAwB,eAAe;CAEpE,MAAM,EACJ,WAAW,qBACX,WAAW,iBACX,YACE,kBAAkB;EACpB;EACA,cAAc;EACd,aAAa;EACb,MAAM;CACR,CAAC;CAED,MAAM,mBAAmB,iBAAyB;EAChD,IAAI,MAAM,QAAQ,eAAe,GAC/B,OACE,gBAAgB,MAAM,mBAAmB,eAAe,SAAS,YAAY,GACzE,QAAQ;EAIhB,OACE,gBAAgB,MAAM,eAAe,QACrC,gBAAgB,WAAW,eAAe,QAC1C;CAEJ;CAEA,IAAI,0BACF,OACE,oBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAEZ,oBAAC,8BAAD;GACE,UAAU,uBAAuB,YAAY,EAAE,WAAW,QAAQ,GAAG,CAAC;GACtD;GACD;EAChB,CAAA;CACE,CAAA;CAIT,OACE,qBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAFd;GAIG,OAAO,uBAAuB,YAC7B,oBAAC,OAAD;IAAK,WAAU;cACZ,EAAE,yBAAyB,EAAE,OAAO,mBAAmB,CAAC;GACtD,CAAA;GAEP,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,MAAD;KACE,WAAU;KACV,eAAY;eAFd,CAIG,wBACC,oBAAC,MAAD;MAAI,WAAU;gBACZ,oBAAC,UAAD;OACE,cAAY,EAAE,cAAc;OAC5B,WAAU;OACV,eAAY;OACZ,eAAe,4BAA4B,IAAI;OAC/C,MAAK;iBAEL,oBAAC,QAAD;QAAM,WAAU;kBACd,oBAAC,cAAD,CAAe,CAAA;OACX,CAAA;MACA,CAAA;KACN,CAAA,GAGL,UAAU,KACR,EAAE,gBAAgB,eAAe,mBAChC,kBACE,oBAAC,MAAD;MACE,WAAU;gBAGV,qBAAC,UAAD;OACE,cAAY,EAAE,4CAA4C,EACxD,cAAc,aAChB,CAAC;OACD,gBAAc,iBAAiB;OAC/B,WAAU;OACV,eACE,+BACE,yBAAyB,eAAe,OAAO,YACjD;OAEF,MAAK;iBAXP,CAaE,oBAAC,QAAD;QAAM,WAAU;kBACd,oBAAC,gBAAD,CAAiB,CAAA;OACb,CAAA,GACN,oBAAC,QAAD;QACE,WAAU;QACV,eAAY;kBAEX;OACG,CAAA,CACA;;KACN,GAzBG,YAyBH,CAEV,CACE;;GACD,CAAA;GACL,oBAAC,OAAD;IAAK,WAAU;cACb,qBAAC,OAAD;KACE,WAAU;KACV,eAAY;eAFd,CAIG,uBAAuB,oBAAC,kBAAD,CAAmB,CAAA,GAC1C,CAAC,uBACA,oBAAA,YAAA,EAAA,UACG,gBAAgB,KAAK,EAAE,MAAM,WAAW;MACvC,MAAM,uBAAuB,OAAO,MAAM,OAAO,MAAM;MACvD,MAAM,eAAe,gBAAgB,IAAI;MACzC,MAAM,iBAAiB,MAAM,QAAQ,eAAe,IAChD,KAAA,IACC,gBAAgB,MAAM,OAAO,aAC9B,gBAAgB,WAAW,OAAO;MAEtC,OACE,qBAAC,OAAD;OACE,WAAU;iBADZ;QAIE,oBAAC,UAAD;SACE,WAAU;SACV,eAAY;SACZ,UAAU,MAAM;SAChB,MAAK;SACL,UAAU,MAAM,QAAQ,MAAM;QAC/B,CAAA;QACD,qBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,oBAAC,QAAD;UACE,WAAU;UACV,eAAY;oBAEX,uBAAuB,EAAE,KAAK,IAAI,MAAM,QAAQ,MAAM;SACnD,CAAA,GACL,wBACC,oBAAC,UAAD;UACE,cAAY,EAAE,qCAAqC,EACjD,aACF,CAAC;UACD,WAAU;UACV,eAAY;UACZ,SAAS,OAAO,MAAM;WACpB,MAAM,6BACJ,iBAAiB,OAAO,SAAS;WAEnC,MAAM,sBAAsB,MAAM,CAAC;WAGnC,IACE,yBAAyB,QACzB,8BAA8B,GAE9B,+BAA+B,IAAI;gBAEnC,QAAQ;UAEZ;UACA,MAAK;oBAEJ,EAAE,eAAe;SACZ,CAAA,CAEP;;QACL,oBAAC,QAAD;SAAM,WAAU;mBACb,CAAC,wBAAwB,kBAAkB,oBAAC,gBAAD,CAAiB,CAAA;QACzD,CAAA;OACH;SAhDE,GAAG,MAAM,GAAG,GAAG,MAgDjB;KAET,CAAC,EACD,CAAA,CAED;;GACF,CAAA;EACF;;AAET;AAEA,uBAAuB,cAAc;AAErC,uBAAuB,eAAe,EAAE,gBACtC,4BAA4B;;;AClQ9B,IAAa,wBAA6C,GAAG,MAAM;CACjE,IAAI,EAAE,mBAAmB,EAAE,iBACzB,OAAO,CAAC,EAAE,kBAAkB,CAAC,EAAE;CAGjC,OAAO,EAAE,aAAa,cAAc,EAAE,cAAc,IAAI;AAC1D;AAEA,IAAa,uBAAuB,WAAsC;CACxE,MAAM,EACJ,eAAe,kBACf,iBAAiB,oBACjB,WAAW,eACX,eAAe,sBACb;CACJ,MAAM,EAAE,SAAS,eAAe,yBAC9B,kBAAkB,qBAAqB;CACzC,MAAM,EAAE,kBAAkB,2BACxB,oBAAoB,qBAAqB;CAE3C,MAAM,gBAAgB,qBAAqB,wBAAwB;CACnE,MAAM,kBAAkB,iBAAiB,QAAQ;CACjD,MAAM,eAAe,oBAAoB,SAAS;CAClD,MAAM,iBAAiB,sBAAsB,SAAS,mBAAmB,KAAA;CAEzE,MAAM,gBAAgB,aACnB,iBACC,cAAc,MAAM,aAAa,SAAS,SAAS,YAAY,KAAK,OACtE,CAAC,YAAY,CACf;CAEA,MAAM,yBAAyB,aAC5B,iBAAyB;EACxB,IAAI,MAAM,QAAQ,eAAe,GAC/B,OACE,gBAAgB,MAAM,EAAE,WAAW,SAAS,YAAY,GAAG,aAAa;EAI5E,OACE,gBAAgB,MAAM,eAAe,aACrC,gBAAgB,WAAW,eAAe,aAC1C;CAEJ,GACA,CAAC,eAAe,CAClB;CAEA,MAAM,sBAAsB,aACzB,iBAAyB;EACxB,IAAI,MAAM,QAAQ,eAAe,GAC/B,OAAO,gBAAgB,MACpB,mBAAmB,eAAe,SAAS,YAC9C;EAGF,OACE,OAAO,gBAAgB,MAAM,kBAAkB,eAC/C,OAAO,gBAAgB,WAAW,kBAAkB;CAExD,GACA,CAAC,eAAe,CAClB;;;;CAKA,MAAM,0BAA0B,cAAc;EAC5C,IAAI,CAAC,gBACH,OAAO;EAGT,OAAO,OAAO,KAAK,cAAc,EAAE,QAAQ,iBACzC,oBAAoB,YAAY,CAClC,EAAE;CACJ,GAAG,CAAC,qBAAqB,cAAc,CAAC;CAKxC,MAAM,+BAA+B,cAAc;EACjD,MAAM,8BAAc,IAAI,IAAsB;EAC9C,IAAI,CAAC,iBAAiB,OAAO;EAE7B,KAAK,MAAM,YAAY,iBAAiB;GACtC,IAAI,CAAC,SAAS,MAAM;GACpB,MAAM,WAAW,SAAS,MAAM,QAAQ,SAAS,MAAM;GACvD,IAAI,CAAC,UAAU;GAEf,MAAM,WAAW,YAAY,IAAI,SAAS,IAAI;GAC9C,IAAI,UACF,SAAS,KAAK,QAAQ;QAEtB,YAAY,IAAI,SAAS,MAAM,CAAC,QAAQ,CAAC;EAE7C;EAEA,OAAO;CACT,GAAG,CAAC,eAAe,CAAC;CAEpB,MAAM,oBAAuC,cAAc;EACzD,IAAI,CAAC,gBACH,OAAO,CAAC;EA2BV,OAxB0B,OAAO,QAAQ,cAAc,EAAE,SACtD,CAAC,cAAc,EAAE,OAAO,mBAAmB,wBAAwB;GAClE,IAAI,UAAU,KAAK,CAAC,oBAAoB,YAAY,GAClD,OAAO,CAAC;GAGV,MAAM,yBACJ,6BAA6B,IAAI,YAAY,KAAK,CAAC;GAErD,OAAO,CACL;IACE,gBAAgB,uBAAuB,YAAY;IACnD,iBAAiB,oBAAoB,IAAI,KAAK,iBAAiB,IAAI;IACnE,eAAe,cAAc,YAAY;IACzC,gBAAgB,mBAAmB,IAAI,KAAK,gBAAgB,IAAI;IAChE;IACA,eAAe;IACf;IACA,0BAA0B,QAAQ,uBAAuB;GAC3D,CACF;EACF,CAGK,EAAkB,KAAK,aAAa;CAC7C,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAWD,OAAO;EACL;EACA,cAXmB,kBAAkB,SAAS;EAY9C;EACA,oBAXyB,cAEvB,OAAO,OAAO,kBAAkB,CAAC,CAAC,EAAE,QAAQ,OAAO,EAAE,YAAY,QAAQ,OAAO,CAAC,GAEnF,CAAC,cAAc,CAOf;EACA;CACF;AACF;;;;;;ACvHA,IAAM,oBAAoB,EACxB,UAAU,eAAe,OACzB,UACA,OAAO,UACP,GAAG,YAC8D;CACjE,IAAI,cACF,OACE,oBAAC,UAAD;EAAQ,GAAI;EAAa;EACtB;CACK,CAAA;CAIZ,OAAO,oBAAA,YAAA,EAAG,SAAW,CAAA;AACvB;AAEA,IAAM,8BAA8B,UAAiC;CACnE,MAAM,EACJ,UAAU,EAAE,WAAW,oBAAoB,GAAG,WAAW,oBAAoB,MAAM,CAAC,GACpF,yBAAyB,OACzB,sBACA,qBACA,mBAAmB,OACnB,cAAc,aACd,GAAG,SACD;CAEJ,MAAM,EACJ,mBACA,cACA,gBACA,oBACA,4BACE,oBAAoB,IAAI;CAC5B,MAAM,CAAC,sBAAsB,2BAA2B,SACtD,IACF;CACA,MAAM,EAAE,MAAM,sBAAsB,kBAAkB;CACtD,MAAM,EAAE,wBAAA,2BAAyB,2BAC/B,oBAAoB;CACtB,MAAM,EAAE,aAAa,YAAY,kBAAkB,kBAAkB;CAErE,MAAM,SAAS,OAA4B,IAAI;CAC/C,MAAM,WAAW,uBAA8B,YAAY,EACzD,WAAW,QAAQ,GACrB,CAAC;CACD,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAAE,IAAI,SAAS,CAAC;CAC5E,MAAM,eAAe,gBAAgB,UAAU,eAAe,EAAE;CAEhE,MAAM,6BAA6B,iBAAsC;EACvE,IAAI,qBAAA,KACF;EAGF,wBAAwB,YAAY;EAEpC,OAAO,KAAK;CACd;;;;;;;;;CAUA,MAAM,0BAA0B,cAAc;EAC5C,IAAI,gBAAgB,eAAe,qBAAqB,OAAO,OAAO;EAEtE,MAAM,WAAW,gBAAgB,cAAc,oBAAoB;EAEnE,MAAM,SAAS,kBAAkB,MAAM,GAAG,QAAQ;EAElD,OAAO;;;;;GAKL,wBAAwB,OAAO,QAC5B,kBAAkB,EAAE,oBAAoB,mBAAmB,eAC5D,CACF;GACA,oBAAoB;EACtB;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,IAAI,CAAC,cAAc,OAAO;CAE1B,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EACE,cAAY,EAAE,oBAAoB;EAClC,WAAW,KAAK,+BAA+B;IAC5C,sDAAsD;IACtD,gCAAgC,qBAC/B,OAAO,qBAAqB;IAC7B,gCAAgC,gBAC/B,OAAO,gBAAgB;EAC3B,CAAC;EACD,KAAK;EACL,MAAK;YAEL,qBAAC,kBAAD;GACE,iBAAe;GACf,cAAY,EAAE,oBAAoB;GAClC,gBAAc;GACd,UAAU,gBAAgB;GAC1B,WAAU;GACV,eAAY;GACZ,eAAe,0BAA0B,IAAI;aAP/C,CASE,qBAAC,MAAD;IAAI,WAAU;cAAd,EACI,yBAAyB,sBAAsB,mBAAmB,KACjE,EAAE,gBAAgB,eAAe,mBAChC,kBACE,oBAAC,MAAD;KACE,WAAU;KACV,eAAY;eAGZ,qBAAC,kBAAD;MACE,cAAY,EAAE,4CAA4C,EACxD,cAAc,aAChB,CAAC;MACD,UAAU,gBAAgB;MAC1B,WAAU;MACV,eAAe,0BAA0B,YAAY;gBANvD,CAQE,oBAAC,QAAD;OACE,WAAU;OACV,eAAY;iBAEZ,oBAAC,gBAAD,CAAiB,CAAA;MACb,CAAA,GACL,gBAAgB,eAAe,gBAAgB,KAC9C,oBAAC,QAAD;OACE,WAAU;OACV,kBAAe;iBAEd;MACG,CAAA,CAEQ;;IAChB,GAzBG,YAyBH,CAEV,GACC,0BAA0B,KACzB,2BACA,gBAAgB,eACd,oBAAC,MAAD;KAAI,WAAU;eACZ,oBAAC,UAAD;MACE,cAAY,EAAE,oBAAoB;MAClC,WAAU;MACV,eAAe,0BAA0B,IAAI;MAC7C,MAAK;gBAEL,qBAAC,QAAD;OAAM,WAAU;iBAAhB,CAA8D,KAE3D,qBACC,wBAAwB,sBACtB;;KACA,CAAA;IACN,CAAA,CAEN;OACH,gBAAgB,eACf,oBAAC,QAAD;IACE,WAAU;IACV,eAAY;cAEX;GACG,CAAA,CAEQ;;CACf,CAAA,GAEL,oBAAC,cAAD;EACE,iBAAiB,eAAe;EAChC,IAAI;EACJ,QAAQ;EACR,WAAW,YAAY,IAAI,eAAe;EAC1C,kBAAkB,OAAO;EACzB,WAAA;EACA,+BAAA;YAEA,oBAAC,0BAAD;GACwB;GACtB,8BAA8B;GACT;GACL;GAChB,WAAW;GACW;GACF;EACrB,CAAA;CACW,CAAA,CACd,EAAA,CAAA;AAEN;;;;AAKA,IAAa,mBAAmB,MAAM,KACpC,0BACF;;;AC5PA,IAAa,sBAAsB,WACjC,IAAI,SAA2B,SAAS,WAAW;CACjD,MAAM,QAAQ,IAAI,MAAM;CAExB,MAAM,iBACJ,cACM;EACJ,QAAQ,CAAC,MAAM,OAAO,MAAM,MAAM,CAAC;CACrC,GACA,EAAE,MAAM,KAAK,CACf;CAEA,MAAM,iBAAiB,eAAe,OAAO,4BAA4B,QAAQ,GAAG,EAClF,MAAM,KACR,CAAC;CAED,MAAM,MAAM;AACd,CAAC;;;ACbH,IAAa,eAAe,EAC1B,SACA,UACA,QACA,UACA,MACA,WACA,OACA,YACsB;CACtB,MAAM,CAAC,CAAC,aAAa,eAAe,uBAAuB,SAAS,CAAC,GAAG,CAAC,CAAC;CAE1E,gBAAgB;EACd,mBAAmB,SAAS,EAAE,KAAK,mBAAmB,EAAE,MAAM,QAAQ,KAAK;CAC7E,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,CAAC,GAAG,KAAK;CAEf,IAAI,CAAC,gBAAgB,CAAC,aAAa,OAAO,oBAAA,YAAA,EAAA,UAAG,SAAW,CAAA;CAExD,OACE,oBAAC,OAAD;EACE,eAAY;EACZ,OACE;GACE,GAAG;GACH,yCACE;GACF,2CACE;GACF,2CACE;GACF,kCAAkC,GAAG,eAAe;GACpD,iCAAiC,GAAG,cAAc;GAClD,GAAI,OAAO,SAAS,MAAM,IACtB,EAAE,mCAAmC,GAAG,OAAO,IAAI,IACnD,CAAC;GACL,GAAI,OAAO,SAAS,KAAK,IACrB,EAAE,kCAAkC,GAAG,MAAM,IAAI,IACjD,CAAC;GACL,iBAAiB,QAAQ,UAAU;GACnC,oBAAoB,GAAG,KAAK,OAAO,UAAU,IAAI,IAAI,KAAK,OAAO,OAAO,IAAI;GAC5E,gBAAgB,GAAG,UAAU,IAAI,IAAI,OAAO,IAAI;GAChD,QACE;GACF,OACE;EACJ;CAEH,CAAA;AAEL;;;;;;;AC5CA,IAAa,8BAA8B,EACzC,mBACqC;CACrC,MAAM,EAAE,MAAM,sBAAsB,4BAA4B;CAChE,MAAM,EAAE,aAAa,SAAS,eAAe,kBAAkB,gBAAgB;CAC/E,MAAM,EAAE,kBAAA,qBAAmB,qBACzB,oBAAoB,gBAAgB;CACtC,MAAM,YAAY,OAA+B,IAAI;CACrD,MAAM,WAAW,iBAAwB,YAAY;EACnD,WAAW,QAAQ;EACnB;CACF,CAAC;CACD,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAAE,IAAI,SAAS,CAAC;CAC5E,MAAM,eAAe,gBAAgB,UAAU,eAAe,EAAE;CAEhE,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;EACE,iBAAiB,eAAe;EAChC,IAAI;EACJ,QAAQ;EACR,WAAW,YAAY,IAAI,YAAY;EACvC,kBAAkB,UAAU;EAC5B,WAAA;EACA,+BAAA;YAEA,oBAAC,oBAAD,CAAmB,CAAA;CACP,CAAA,GACd,oBAAC,2BAAD;EACE,iBAAe;EACf,cAAY,EAAE,6BAA6B;EAC3C,WAAU;EACV,eAAY;EACZ,eAAe,QAAQ,OAAO;EAC9B,KAAK;YAEL,oBAAC,cAAD,EAAc,WAAU,gCAAiC,CAAA;CAChC,CAAA,CAC3B,EAAA,CAAA;AAEN;;;ACnDA,IAAM,qBAAmB,OAAgB,aACvC,iBAAiB,SAAS,MAAM,UAAU,MAAM,UAAU;AAE5D,IAAM,0BAAwB,UAAsC;CAClE,IAAI,iBAAiB,OAAO,OAAO;CACnC,IAAI,OAAO,UAAU,UAAU,OAAO,IAAI,MAAM,KAAK;CACrD,IAAI,SAAS,OAAO,UAAU,YAAY,aAAa,OAAO;EAC5D,MAAM,UAAU,MAAM;EACtB,IAAI,OAAO,YAAY,UAAU,OAAO,IAAI,MAAM,OAAO;CAC3D;AAEF;AAEA,IAAa,8BAA8B;CACzC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,uBAAuB,sBAAsB;CACrD,OACE,oBAAC,mBAAD,EAAA,UACE,qBAAC,uBAAD;EAAuB,SAAS;YAAhC,CACE,oBAAC,iBAAD,CAAkB,CAAA,GAClB,oBAAC,QAAD,EAAA,UAAO,EAAE,WAAW,EAAQ,CAAA,CACP;IACN,CAAA;AAEvB;AAEA,IAAa,wBAAwB;CACnC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,YAAY,kBAAkB;CACtC,MAAM,EAAE,cAAc,sBAAsB;CAC5C,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,OACE,oBAAC,OAAD;EACE,cAAY,EAAE,wBAAwB;EACtC,WAAU;EACV,MAAK;YAEJ,OAAO,UAAU,mBAAmB,KAAK,aACxC,oBAAC,mBAAD;GACE,WAAU;GAEV,SAAS,YAAY;IACnB,IAAI;KACF,MAAM,OAAO,UAAU,eAAe;MACpC,WAAW,QAAQ;MACnB,WAAW,IAAI,sBAAK,IAAI,KAAK,GAAE,QAAQ,IAAI,QAAQ,EAAE,YAAY;KACnE,CAAC;KACD,gBAAgB;MACd,SAAS,EACP,QACF;MACA,SAAS;MACT,SAAS,EAAE,cAAc;MACzB,UAAU;MACV,MAAM;KACR,CAAC;IACH,SAAS,OAAO;KACd,gBAAgB;MACd,SAAS,EACP,QACF;MACA,SAAS;MACT,OAAO,uBAAqB,KAAK;MACjC,SAAS,kBAAgB,OAAO,wBAAwB;MACxD,UAAU;MACV,MAAM;KACR,CAAC;IACH,UAAU;KACR,UAAU;IACZ;GACF;aAEC,EAAE,sBAAsB,EAAE,cAAc,SAAS,CAAC;EAClC,GAjCZ,2BAA2B,UAiCf,CACpB;CAEE,CAAA;AAET;;;AC7DA,IAAa,4BACX,eACyC;CACzC,IAAI,CAAC,cAAc,OAAO,eAAe,UAAU,OAAO;CAC1D,MAAM,kBAAkB;CAExB,OACE,iBAAiB,eAAe,KAChC,kBAAkB,eAAe,KACjC,kBAAkB,eAAe,KACjC,kBAAkB,eAAe,KACjC,2BAA2B,eAAe;AAE9C;AAEA,IAAM,sBAAsB,EAC1B,UACA,cACA,iBACA,UAMI;CACJ,MAAM,SAAS,SAAS,cAAc,GAAG;CACzC,OAAO,WAAW;CAClB,OAAO,OAAO;CACd,OAAO,MAAM;CAEb,IAAI,gBAAgB,CAAC,IAAI,WAAW,OAAO,GACzC,OAAO,SAAS;CAElB,SAAS,KAAK,OAAO,MAAM;CAC3B,OAAO,MAAM;CACb,OAAO,OAAO;CAId,KAD8B,mBAAmB,IAAI,WAAW,OAAO,MAC1C,IAAI,WAAW,OAAO,GACjD,iBAAiB,IAAI,gBAAgB,GAAG,GAAG,CAAC;AAEhD;AAEA,IAAM,mCAAmC,OAAO,QAAgB;CAC9D,IAAI,OAAO,UAAU,YAAY,OAAO;CAExC,MAAM,WAAW,MAAM,MAAM,GAAG;CAChC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,sCAAsC,SAAS,QAAQ;CAEzE,MAAM,OAAO,MAAM,SAAS,KAAK;CACjC,OAAO,IAAI,gBAAgB,IAAI;AACjC;AAEA,IAAa,qBAAqB,OAChC,YACA,UAAyE,CAAC,MACvE;CACH,MAAM,EAAE,qBAAqB,MAAM,oBAAoB,SAAS;CAChE,MAAM,gBAAgB,WAAW,SAAS;CAC1C,MAAM,UAAU,WAAW,eAAe;CAE1C,IAAI,mBAAmB,MAAM;EAG3B,mBAAmB;GACjB,UAFA,mBAAmB,QAAQ,QAAQ,OAAO,QAAQ,OAAO;GAGzD,KAAK,IAAI,gBAAgB,OAAO;EAClC,CAAC;EACD;CACF;CAEA,MAAM,WACJ,WACA,OAAO,YAAY,YACnB,UAAU,WACV,OAAQ,QAA8B,SAAS,WAC1C,QAA6B,OAC9B;CAEN,MAAM,MAAM,WAAW,aAAa,WAAW;CAC/C,IAAI,CAAC,KAAK;CAGV,IAAI,mBACF,IAAI;EACF,MAAM,YAAY,MAAM,iCAAiC,GAAG;EAC5D,IAAI,WAAW;GACb,mBAAmB;IACjB;IACA,KAAK;GACP,CAAC;GACD;EACF;CACF,QAAQ,CAER;CAGF,mBAAmB;EAAE;EAAU,cAAc;EAAoB;CAAI,CAAC;AACxE;AAEA,IAAa,yBAAyB,OAAO,gBAA0C;CAErF,KAAK,MAAM,cAAc,aACvB,MAAM,mBAAmB,YAAY;EACnC,oBAAoB;EACpB,mBAAmB;CACrB,CAAC;AAEL;;;AC9HA,IAAM,iCACJ;AAEF,IAAa,8BAA8B;CACzC,MAAM,EAAE,oBAAoB,WAAW,sBAAsB;CAC7D,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,mBAAD,EAAA,UACE,qBAAC,uBAAD;EAAuB,SAAS;YAAhC,CACE,oBAAC,iBAAD,CAAkB,CAAA,GAClB,oBAAC,QAAD,EAAA,UAAO,EAAE,qBAAqB,EAAQ,CAAA,CACjB;IACN,CAAA;AAEvB;AAEA,IAAa,wBAAwB;CACnC,MAAM,EAAE,cAAc,sBAAsB;CAC5C,MAAM,EAAE,YAAY,kBAAkB;CACtC,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,2BAA2B,QAAQ,eAAe,CAAC,GAAG,OAC1D,wBACF;CAEA,OACE,qBAAC,OAAD;EACE,cAAY,EAAE,0BAA0B;EACxC,WAAU;EACV,MAAK;YAHP,CAKG,wBAAwB,KAAK,YAAY,UAAU;GAClD,MAAM,WACJ,WAAW,eAAe,MAAM,QAChC,WAAW,SACX,EAAE,qBAAqB;GAEzB,OACE,oBAAC,mBAAD;IACE,WAAW;IACX,MAAM;IAON,eAAe;KACb,mBAAwB,UAAU;KAClC,UAAU;IACZ;cAEC,YAAY;GACI,GAXf,WAAW,eAAe,MAC1B,WAAW,aACX,WAAW,aACX,GAAG,SAAS,GAAG,OAQA;EAEvB,CAAC,GACD,oBAAC,mBAAD;GACE,WAAW;GACX,MAAM;GACN,eAAe;IACb,uBAA4B,uBAAuB;IACnD,UAAU;GACZ;aAEC,EAAE,cAAc;EACA,CAAA,CAChB;;AAET;;;AC/EA,IAAa,4BAA4B,WACvC,SAAS,0BAA0B,EAAE,WAAW,GAAG,SAAS,KAAK;CAC/D,OACE,oBAAC,QAAD;EACE,YAAW;EACX,UAAA;EACA,WAAW,KAAK,wCAAwC,SAAS;EAC5D;EACL,MAAK;EACL,SAAQ;EACR,GAAI;CACL,CAAA;AAEL,CACF;;;ACRA,IAAa,sBAAsB,EAAE,UAAU,eAAwC;CACrF,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,UAAU,gBAAgB;CAElC,OACE,qBAAC,MAAM,MAAP;EACE,WAAU;EACV,eAAY;YAFd,CAIE,oBAAC,MAAM,QAAP;GACE,aAAa,EAAE,+CAA+C;GAC9D,OAAO,EAAE,gBAAgB;EAC1B,CAAA,GACD,qBAAC,MAAM,SAAP,EAAA,UAAA,CACE,oBAAC,QAAD;GACE,YAAW;GACX,WAAU;GACV,eAAY;GACZ,SAAS;GACT,MAAK;GACL,SAAQ;aAEP,EAAE,gBAAgB;EACb,CAAA,GACR,oBAAC,QAAD;GACE,YAAW;GACX,WAAA;GACA,WAAU;GACV,eAAY;GACZ,eAAe;IACb,SAAS;IACT,MAAM;GACR;GACA,MAAK;GACL,SAAQ;aAEP,EAAE,QAAQ;EACL,CAAA,CACK,EAAA,CAAA,CACL;;AAEhB;;;ACKA,IAAM,+BACJ;AAEF,IAAM,gCACJ,UACG,oBAAC,mBAAD,EAAmB,GAAI,MAAQ,CAAA;AAEpC,IAAM,mBAAmB,OAAgB,aACvC,iBAAiB,SAAS,MAAM,UAAU,MAAM,UAAU;AAE5D,IAAM,wBAAwB,UAAsC;CAClE,IAAI,iBAAiB,OAAO,OAAO;CACnC,IAAI,OAAO,UAAU,UAAU,OAAO,IAAI,MAAM,KAAK;CACrD,IAAI,SAAS,OAAO,UAAU,YAAY,aAAa,OAAO;EAC5D,MAAM,UAAU,MAAM;EACtB,IAAI,OAAO,YAAY,UAAU,OAAO,IAAI,MAAM,OAAO;CAC3D;AAEF;AAEA,IAAM,iCAAiC;CACrC,UAAU;EACR,QAAQ;GACN,MAAM,EAAE,kBAAA,qBAAmB,qBAA4B,oBAAoB;GAC3E,MAAM,EAAE,2BAA2B,sBAAsB;GACzD,MAAM,EAAE,aAAa,SAAS,eAAe,kBAAkB;GAC/D,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,CAAC,kBAAkB,uBAAuB,SAA6B,IAAI;GACjF,MAAM,WAAW,GAAG,iBAAwB,YAAY;IACtD,WAAW,QAAQ;IACnB;GACF,CAAC,EAAE;GACH,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAC1D,IAAI,SACN,CAAC;GACD,MAAM,eAAe,gBAAgB,UAAU,eAAe,EAAE;GAEhE,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;IACE,iBAAiB,eAAe;IAChC,IAAI;IACJ,QAAQ;IACR,WAAW,YAAY,IAAI,YAAY;IACrB;IAClB,WAAA;IACA,+BAAA;cAEA,oBAAC,oBAAD,EAA4B,SAAW,CAAA;GAC3B,CAAA,GACd,oBAAC,8BAAD;IACE,iBAAe;IACf,cAAY,EAAE,6BAA6B;IAC3C,WAAW,KACT,8BACA,mDACF;IACA,eAAY;IACZ,MAAM;IACN,UAAU,UAAU;KAClB,IAAI,cAAc;MAChB,OAAO,MAAM;MACb;KACF;KACA,oBACE,kCAAkC,cAC9B,yBACA,MAAM,aACZ;KACA,OAAO,KAAK;IACd;cAEC,EAAE,cAAc;GACW,CAAA,CAC9B,EAAA,CAAA;EAEN;EACA,cAAc;GACZ,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,qBAAqB,kBAAkB;GAC/C,MAAM,EAAE,MAAM,sBAAsB;GAEpC,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,kBAAkB;IAChC,WAAW;IACX,eAAY;IACZ,MAAM;IACN,UAAU,MAAM;KACd,iBAAiB,CAAC;KAClB,UAAU;IACZ;cAEC,EAAE,cAAc;GACW,CAAA;EAElC;EACA,QAAQ;GACN,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,YAAY,kBAAkB;GACtC,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,kBAAkB,6BAA6B;GAErD,MAAM,oBAAoB;IACxB,gBAAgB,iBAAiB,OAAO;IAKxC,MAAM,YAHW,QAAQ,YACrB,SAAS,iBAAiB,iDAAiD,IAC3E,SAAS,uBAAuB,8BAA8B,GACxC,KAAK,CAAC;IAEhC,IAAI,oBAAoB,qBACtB,SAAS,MAAM;GAEnB;GAEA,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,oBAAoB;IAClC,WAAW;IACX,MAAM;IACN,eAAe;KACb,YAAY;KACZ,UAAU;IACZ;cAEC,EAAE,aAAa;GACY,CAAA;EAElC;EACA,WAAW;GACT,MAAM,EAAE,WAAW,gBAAgB,sBAAsB;GACzD,MAAM,EAAE,YAAY,kBAAkB;GACtC,MAAM,EAAE,MAAM,sBAAsB;GAEpC,MAAM,2BAA2B,QAAQ,eAAe,CAAC,GAAG,OAC1D,wBACF;GAEA,IAAI,CAAC,wBAAwB,QAAQ,OAAO;GAE5C,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,0BAA0B;IACxC,WAAW;IACX,YAAY,wBAAwB,SAAS;IAC7C,MAAM;IACN,UAAU,UAAU;KAClB,IAAI,wBAAwB,SAAS,GAAG;MACtC,YAAY;OACV,mBAAmB,MAAM;OACzB,QAAQ;OACR,SAAS;MACX,CAAC;MACD;KACF;KAEA,mBAAwB,wBAAwB,EAAE;KAClD,UAAU;IACZ;cAEC,EAAE,qBAAqB;GACI,CAAA;EAElC;EACA,MAAM;GACJ,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,WAAW,YAAY,kBAAkB;GACjD,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,WAAW,CAAC,CAAC,QAAQ;GAC3B,OACE,oBAAC,8BAAD;IACE,cAAY,WAAW,EAAE,oBAAoB,IAAI,EAAE,kBAAkB;IACrE,WAAW;IACX,MAAM,WAAW,YAAY;IAC7B,SAAS,OAAO,UAAU;KACxB,IAAI;MACF,MAAM,UAAU,KAAK;MACrB,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,SAAS,WAAW,EAAE,kBAAkB,IAAI,EAAE,gBAAgB;OAC9D,UAAU;OACV,MAAM,WAAW,8BAA8B;MACjD,CAAC;KACH,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,OAAO,qBAAqB,KAAK;OACjC,SAAS,gBACP,OACA,WAAW,EAAE,4BAA4B,IAAI,EAAE,uBAAuB,CACxE;OACA,UAAU;OACV,MAAM,WAAW,6BAA6B;MAChD,CAAC;KACH;KACA,UAAU;IACZ;cAEC,WAAW,EAAE,OAAO,IAAI,EAAE,KAAK;GACJ,CAAA;EAElC;EACA,kBAAkB;GAChB,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,YAAY,kBAAkB;GACtC,MAAM,EAAE,MAAM,sBAAsB;GAEpC,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,wBAAwB;IACtC,WAAW;IACX,MAAM;IACN,eAAe;KACb,IAAI,QAAQ,MAAM,UAAU,UAAU,UAAU,QAAQ,IAAI;KAC5D,UAAU;IACZ;cAEC,EAAE,cAAc;GACW,CAAA;EAElC;EACA,SAAS;GACP,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,aAAa,YAAY,kBAAkB;GACnD,MAAM,EAAE,MAAM,sBAAsB;GAEpC,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,qBAAqB;IACnC,WAAW;IACX,MAAM;IACN,eAAe;KACb,YAAY,OAAO;KACnB,UAAU;IACZ;cAEC,EAAE,QAAQ;GACiB,CAAA;EAElC;EACA,OAAO;GACL,MAAM,kBAAkB,6BAA6B;GACrD,MAAM,EAAE,YAAY,kBAAkB;GACtC,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,EAAE,cAAc,sBAAsB;GAE5C,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,mBAAmB;IACjC,WAAW;IACX,MAAM;IACN,eAAe;KACb,oBAAoB,eAAe;KACnC,gBAAgB,UAAU,EAAE,aAAa,QAAQ,CAAC;KAClD,UAAU;IACZ;cAEC,EAAE,cAAc;GACW,CAAA;EAElC;EACA,aAAa;GACX,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,kBAAkB,YAAY,kBAAkB;GACxD,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,MAAM,sBAAsB;GAEpC,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,0BAA0B;IACxC,WAAW;IACX,MAAM;IACN,SAAS,OAAO,UAAU;KACxB,IAAI;MACF,MAAM,iBAAiB,KAAK;MAC5B,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,SAAS,EAAE,0BAA0B;OACrC,UAAU;OACV,MAAM;MACR,CAAC;KACH,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,OAAO,qBAAqB,KAAK;OACjC,SAAS,gBACP,OACA,EACE,uGACF,CACF;OACA,UAAU;OACV,MAAM;MACR,CAAC;KACH;KACA,UAAU;IACZ;cAEC,EAAE,gBAAgB;GACS,CAAA;EAElC;EACA,WAAW;GACT,MAAM,EAAE,WAAW,gBAAgB,sBAAsB;GACzD,MAAM,EAAE,WAAW,eAAe;GAClC,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,EAAE,YAAY,kBAAkB;GACtC,MAAM,WAAW,mBAAmB,QAAQ,EAAE;GAG9C,IAFiC,YAAY,CAAC,UAAU,UAE1B,OAAO;GAErC,OACE,oBAAC,8BAAD;IACE,cAAY,WAAW,EAAE,wBAAwB,IAAI,EAAE,sBAAsB;IAC7E,WAAW;IACX,YAAY,CAAC;IACb,MAAM,WAAW,cAAc;IAC/B,SAAS,OAAO,UAAU;KACxB,IAAI,UACF,IAAI;MACF,MAAM,OAAO,UAAU,eAAe,SAAS,EAAE;MACjD,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,SAAS,EAAE,iBAAiB;OAC5B,UAAU;OACV,MAAM;MACR,CAAC;KACH,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,OAAO,qBAAqB,KAAK;OACjC,SAAS,gBAAgB,OAAO,yBAAyB;OACzD,UAAU;OACV,MAAM;MACR,CAAC;KACH,UAAU;MACR,UAAU;KACZ;UAEA,YAAY;MACV,mBAAmB,MAAM;MACzB,QAAQ;MACR,SAAS;KACX,CAAC;IAEL;cAEC,WAAW,EAAE,iBAAiB,IAAI,EAAE,WAAW;GACpB,CAAA;EAElC;EACA,eAAe;GACb,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,WAAW,eAAe;GAClC,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,YAAY,kBAAkB;GACtC,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,WAAW,mBAAmB,QAAQ,EAAE;GAG9C,IAF2C,QAAQ,YAAY,UAAU,QAErE,GAAoC,OAAO;GAE/C,OACE,oBAAC,8BAAD;IACE,cACE,WAAW,EAAE,4BAA4B,IAAI,EAAE,uBAAuB;IAExE,WAAW;IACX,MAAM,WAAW,qBAAqB;IACtC,SAAS,YAAY;KACnB,IAAI;MACF,IAAI,UAAU;OACZ,MAAM,OAAO,UAAU,eAAe,SAAS,EAAE;OACjD,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS;QACT,SAAS,EAAE,uBAAuB;QAClC,UAAU;QACV,MAAM;OACR,CAAC;MACH,OAAO;OACL,MAAM,OAAO,UAAU,eAAe,EAAE,WAAW,QAAQ,GAAG,CAAC;OAC/D,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS;QACT,SAAS,EAAE,iBAAiB;QAC5B,UAAU;QACV,MAAM;OACR,CAAC;MACH;KACF,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,OAAO,qBAAqB,KAAK;OACjC,SAAS,gBACP,OACA,WACI,gDACA,gCACN;OACA,UAAU;OACV,MAAM,WACF,2CACA;MACN,CAAC;KACH,UAAU;MACR,UAAU;KACZ;IACF;cAEC,WAAW,EAAE,uBAAuB,IAAI,EAAE,gBAAgB;GAC/B,CAAA;EAElC;EACA,OAAO;GACL,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,YAAY,YAAY,kBAAkB;GAClD,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,MAAM,sBAAsB;GAEpC,OACE,oBAAC,8BAAD;IACE,cAAY,EAAE,mBAAmB;IACjC,WAAW;IACX,MAAM;IACN,SAAS,OAAO,UAAU;KACxB,IAAI;MACF,MAAM,WAAW,KAAK;MACtB,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,SAAS,EAAE,uCAAuC;OAClD,UAAU;OACV,MAAM;MACR,CAAC;KACH,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,OAAO,qBAAqB,KAAK;OACjC,SAAS,gBAAgB,OAAO,EAAE,mBAAmB,CAAC;OACtD,UAAU;OACV,MAAM;MACR,CAAC;KACH;KACA,UAAU;IACZ;cAEC,EAAE,MAAM;GACmB,CAAA;EAElC;EACA,OAAO;GACL,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,YAAY,YAAY,kBAAkB;GAClD,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,UAAU,eAAe;GACjC,MAAM,EAAE,MAAM,sBAAsB;GAEpC,MAAM,UAAU,YAAY,SAAS,KAAK;GAC1C,OACE,oBAAC,8BAAD;IACE,cAAY,UAAU,EAAE,kBAAkB,IAAI,EAAE,gBAAgB;IAChE,WAAW;IACX,MAAM,UAAU,YAAY;IAC5B,SAAS,OAAO,UAAU;KACxB,IAAI;MACF,MAAM,WAAW,KAAK;MACtB,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,SAAS,UACL,EAAE,+BAA+B,EAC/B,MAAM,QAAQ,MAAM,QAAQ,QAAQ,MAAM,GAC5C,CAAC,IACD,EAAE,6BAA6B,EAC7B,MAAM,QAAQ,MAAM,QAAQ,QAAQ,MAAM,GAC5C,CAAC;OACL,UAAU;OACV,MAAM,UAAU,4BAA4B;MAC9C,CAAC;KACH,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS;OACT,OAAO,qBAAqB,KAAK;OACjC,SAAS,gBACP,OACA,UAAU,EAAE,2BAA2B,IAAI,EAAE,yBAAyB,CACxE;OACA,UAAU;OACV,MAAM,UAAU,2BAA2B;MAC7C,CAAC;KACH;KACA,UAAU;IACZ;cAEC,UAAU,EAAE,QAAQ,IAAI,EAAE,MAAM;GACL,CAAA;EAElC;EACA,SAAS;GACP,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,QAAQ,gBAAgB,oBAAoB;GACpD,MAAM,EAAE,cAAc,YAAY,kBAAkB;GACpD,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;GAEhD,IAAI,iBAAiB,OAAO,GAAG,OAAO;GAEtC,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,8BAAD;IACE,cAAY,EAAE,qBAAqB;IACnC,WAAW;IACX,MAAM;IACN,eAAe;KACb,aAAa,IAAI;IACnB;IACA,SAAQ;cAEP,EAAE,gBAAgB;GACS,CAAA,GAC9B,oBAAC,OAAD;IAAO,MAAM;IAAW,MAAK;cAC3B,oBAAC,oBAAD;KACE,gBAAgB;MACd,aAAa,KAAK;MAClB,UAAU;KACZ;KACA,UAAU,YAAY;MACpB,IAAI;OACF,MAAM,aAAa;OACnB,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS;QACT,SAAS,EAAE,iBAAiB;QAC5B,UAAU;QACV,MAAM;OACR,CAAC;MACH,SAAS,OAAO;OACd,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS;QACT,OAAO,qBAAqB,KAAK;QACjC,SAAS,gBAAgB,OAAO,EAAE,wBAAwB,CAAC;QAC3D,UAAU;QACV,MAAM;OACR,CAAC;MACH,UAAU;OACR,aAAa,KAAK;OAClB,UAAU;MACZ;KACF;IACD,CAAA;GACI,CAAA,CACP,EAAA,CAAA;EAEN;EACA,YAAY;GACV,MAAM,EAAE,cAAc,sBAAsB;GAC5C,MAAM,EAAE,WAAW,eAAe;GAClC,MAAM,EAAE,YAAY,kBAAkB;GACtC,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,YACJ,CAAC,QAAQ,MAAM,MACf,IAAI,IAAI,OAAO,aAAa,eAAe,EAAE,OAAO,EAAE,IAAI,QAAQ,MAAM,EAAE;GAE5E,OACE,oBAAC,8BAAD;IACE,cAAY,YAAY,EAAE,mBAAmB,IAAI,EAAE,iBAAiB;IACpE,WAAW,KAAK,4BAA4B;IAC5C,MAAM,YAAY,gBAAgB;IAClC,eAAe;KACb,MAAM,WAAW,QAAQ,MAAM;KAC/B,IAAI,UACF,IAAI,WAAW,OAAO,YAAY,QAAQ;UACrC,OAAO,UAAU,QAAQ;KAEhC,UAAU;IACZ;cAEC,YAAY,EAAE,cAAc,IAAI,EAAE,YAAY;GACnB,CAAA;EAElC;CACF;CACA,OAAO;EAEL,gBAAgB,YAA+B,GAAG,QAAQ;GACxD,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,EAAE,SAAS,eAAe,kBAAkB;GAClD,MAAM,uBAAuB,gBAC3B,eAAe,YAAY,EAAE,WAAW,QAAQ,GAAG,CAAC,CACtD;GACA,MAAM,EAAE,WAAW,0BAA0B,EAC3C,IAAI,eAAe,YAAY,EAAE,WAAW,QAAQ,GAAG,CAAC,EAC1D,CAAC;GAKD,MAAM,EAAE,QAAQ,mCAAmC,0BAA0B,EAC3E,IAAI,GAL2B,iBAAwB,YAAY;IACnE,WAAW,QAAQ;IACnB;GACF,CAES,EAAyB,WAClC,CAAC;GAED,OACE,oBAAC,2BAAD;IACE,iBAAe;IACf,iBAAc;IACd,cAAY,EAAE,gCAAgC;IAC9C,WAAU;IACV,eAAY;IACZ,eAAe;KAGb,gCAAgC,MAAM;KACtC,QAAQ,OAAO;IACjB;IACK;cAEL,oBAAC,UAAD,EAAU,WAAU,gCAAiC,CAAA;GAC5B,CAAA;EAE/B,CAAC;EACD,QAAQ;GACN,OAAO,oBAAC,4BAAD,EAA4B,cAAc,UAAY,CAAA;EAC/D;EACA,QAAQ;GACN,MAAM,EAAE,qBAAqB,kBAAkB;GAC/C,MAAM,EAAE,MAAM,sBAAsB;GAEpC,OACE,oBAAC,2BAAD;IACE,cAAY,EAAE,kBAAkB;IAChC,WAAU;IACV,eAAY;IACZ,SAAS;cAET,oBAAC,WAAD,EAAW,WAAU,gCAAiC,CAAA;GAC7B,CAAA;EAE/B;CACF;AACF;AAEA,IAAa,0BAAkD;CAC7D;EACE,WAAW,+BAA+B,MAAM;EAChD,WAAW;CACb;CACA;EACE,WAAW,+BAA+B,MAAM;EAChD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,MAAM;EAChD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,+BAA+B,SAAS;EACnD,WAAW;EACX,MAAM;CACR;AACF;;;AC/zBA,IAAa,qBAMX,cAEA,cAAc;CACZ,MAAM,iBAAuD,CAAC;CAC9D,MAAM,oBAA6D,CAAC;CACpE,IAAI;CAIJ,KAAK,MAAM,UAAU,WAAW;EAC9B,IAAI,OAAO,cAAc,SACvB,eAAe,KAAK,MAAyC;EAC/D,IAAI,OAAO,cAAc,YACvB,kBAAkB,KAAK,MAA4C;EACrE,IAAI,OAAO,cAAc,yBACvB,8BAAA,4BAA8B;CAKlC;CAEA,OAAO;EAAE;EAAmB;EAAgB;CAA0B;AACxE,GAAG,CAAC,SAAS,CAAC;;;;;;;;AC6BhB,IAAa,kBAA2C,EACtD,oCAAoC,OACpC,mBAAmB,8BACf;CACJ,MAAM,EAAE,aAAa,SAAS,eAAe,kBAAkB;CAC/D,MAAM,EAAE,aAAa,uBAAuB,gBAAgB,oBAAoB;CAChF,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,CAAC,yBAAyB,8BAC9B,SAAmC,IAAI;CAOzC,MAAM,EAAE,mBAAmB,gBAAgB,8BACzC,kBAN+B,8BAC/B,kBACA,iCAIkB,CAAwB;CAE5C,MAAM,yBAAyB,eAAe,YAAY,EAAE,WAAW,QAAQ,GAAG,CAAC;CACnF,MAAM,2BAA2B,iBAAiB,YAAY;EAC5D,WAAW,QAAQ;EACnB;CACF,CAAC;CACD,MAAM,mCAAmC,GAAG,yBAAyB;CACrE,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAC1D,IAAI,uBACN,CAAC;CACD,MAAM,6BAA6B,gBACjC,wBACA,eAAe,EACjB;CACA,MAAM,+BAA+B,gBACnC,0BACA,eAAe,EACjB;CACA,MAAM,uCAAuC,gBAC3C,kCACA,eAAe,EACjB;CAGA,IAAI,kBAAkB,SAAS,eAAe,WAAW,GACvD,OAAO;CAGT,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,6BAA6B,EAC3C,qCACE,8BACA,gCACA,qCACJ,CAAC;YANH,CAQG,6BAA6B,kBAAkB,SAAS,KACvD,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,0BAA0B,WAA3B,EAAqC,KAAK,2BAA6B,CAAA,GAEvE,oBAAC,sBAAD;GACE,cAAY,EAAE,sBAAsB;GACpC,WAAW,EAAE,MAAM;GACnB,WAAW,KAAK,iCAAiC;IAC/C,yCACE;IACF,uCAAuC;GACzC,CAAC;GACD,iBAAiB,eAAe;GAChC,IAAI;GACJ,SAAS,QAAQ;GACjB,WAAW,YAAY,IAAI,YAAY;GACvC,kBAAkB;GAClB,UAAU;GACV,WAAA;aAEC,kBAAkB,KAAK,EAAE,WAAW,WACnC,oBAAC,WAAD,CAAuB,GAAP,IAAO,CACxB;EACmB,CAAA,CACtB,EAAA,CAAA,GAEH,eAAe,KAAK,EAAE,WAAW,sBAAsB,WACtD,oBAAC,sBAAD,CAAkC,GAAP,IAAO,CACnC,CACE;;AAET;AAEA,eAAe,eAAe,EAAE,gBAAgB,mBAAmB;AAEnE,eAAe,cAAc;;;AC7F7B,IAAM,wBAAwB,EAC5B,YACA,cACA,eACA,cACA,kBACA,aACA,sBACA,aACA,SACA,aACA,aACA,YACA,aAAa,YACb,iBAC+B;CAC/B,MAAM,EAAE,YAAY,uBAAuB;CAC3C,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,MAAM,sBAAsB,WAAW;CAC/C,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,KAAK;CAClE,MAAM,WAAW,mBAAmB,QAAQ,EAAE;CAE9C,MAAM,EACJ,YAAA,gBAAa,YACb,QAAA,WAAS,QACT,gBAAA,mBAAiB,gBACjB,mCAAA,sCAAoC,mCACpC,gBAAA,mBAAiB,gBACjB,qBAAA,wBAAsB,qBACtB,gBACA,sBAAA,yBAAuB,sBACvB,wBAAA,2BAAyB,wBACzB,kBAAA,qBAAmB,kBACnB,2BAAA,8BAA4B,2BAC5B,eAAA,kBAAgB,eAChB,kBAAA,qBAAmB,kBACnB,6BAAA,gCAA8B,6BAC9B,cAAA,iBAAe,cACf,eAAA,kBAAgB,eAChB,sBAAA,yBAAuB,sBACvB,qBAAA,wBAAsB,wBACpB,oBAAoB,WAAW;CAEnC,MAAM,gBAAgB,cACd,uBAAuB,OAAO,GACpC,CAAC,sBAAsB,OAAO,CAChC;CACA,MAAM,YAAY,iBAAiB,OAAO;CAE1C,MAAM,mBAAmB,cAErB,CAAC,QAAQ,mBAAmB,CAAC,QAAQ,cACjC,CAAC,IACD,CAAC,QAAQ,kBACP,QAAQ,cACR,CAAC,QAAQ,iBAAiB,GAAI,QAAQ,eAAe,CAAC,CAAE,GAChE,CAAC,OAAO,CACV;CAEA,IAAI,uBAAuB,OAAO,GAChC,OAAO;CAGT,IAAI,kBAAkB,WACpB,OAAO,oBAAC,gBAAD,EAAyB,QAAU,CAAA;CAG5C,IAAI,iBAAiB,OAAO,GAC1B,OAAO,oBAAC,kBAAD,CAAiB,CAAA;CAG1B,MAAM,OAAO,QAAQ,WAAW,OAAO,MAAM,UAAU,QAAQ,OAAO;CAEtE,MAAM,cAAc,OAAO,KAAK,SAAS,OAAO,WAAW,CAAC,CAAC,EAAE;CAC/D,MAAM,gBAAgB,CAAC,aAAa,sBAAsB,OAAO;CACjE,MAAM,sBAAsB,CAAC,aAAa,2BAA2B,OAAO;CAC5E,MAAM,qBAAqB,CAAC,aAAa,0BAA0B,OAAO;CAC1E,MAAM,eAAe,CAAC,aAAa,oBAAoB,OAAO;CAC9D,MAAM,mBAAmB,CAAC,aAAa,wBAAwB,OAAO;CACtE,MAAM,oBAAoB,CAAC,aAAa,yBAAyB,OAAO;CAExE,MAAM,aAAa,wBAAwB,OAAO;CAClD,MAAM,YAAY,iBAAiB,OAAO;CAC1C,MAAM,WAAW,gBAAgB,OAAO,KAAK,CAAC;CAE9C,MAAM,eAAe,CAAC,iBAAiB;CACvC,MAAM,uBAAuB,CAAC,cAAc,CAAC,CAAC,QAAQ;CAEtD,MAAM,gBAAgB,KACpB,qBACA,sBAAsB,QAAQ,QAC9B,sBAAsB,QAAQ,UAC9B;EACE,qCAAqC;EACrC,2CAA2C;EAC3C,kCAAkC,CAAC,QAAQ;EAC3C,yCAAyC;EACzC,4CAA4C;EAC5C,+BAA+B,CAAC,CAAC,QAAQ;EACzC,kCAAkC;EAClC,oCAAoC;GACnC,0CAA0C,YAAY,QAAQ,IAAI,MACjE;EACF,yBAAyB,YAAY;EACrC,4BAA4B,CAAC,YAAY;EACzC,6BAA6B,QAAQ;EACrC,yCAAyC;GACvC,IAAI,CAAC,QAAQ,MAAM,OAAO;GAC1B,IAAI,eAAe,YAAY,OAAO,CAAC,YAAY;GACnD,IAAI,eAAe,YAAY,OAAO,YAAY;GAClD,OAAO;EACT,GAAG;EACH,qCAAqC;EACrC,yCACE,SAAS,WAAW,YAAY,SAAS,OAAO,WAAW;EAC7D,sCAAsC;EACtC,2CAA2C;EAC3C,6CAA6C;EAC7C,6CAA6C;CAC/C,CACF;CAEA,IAAI;CAEJ,IAAI,WACF,oBAAoB,sBAAsB,IAAI;CAGhD,MAAM,4BAA4B,CAAC,CAAC;CACpC,MAAM,wBAAwB,4BAC1B,EAAE,6BAA6B,IAC/B,KAAA;CAEJ,MAAM,6BAA6B,UAA+C;EAChF,IAAI,CAAC,eAAgB,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAM;EAElE,MAAM,eAAe;EACrB,YAAY;CACd;CAEA,OACE,qBAAA,YAAA,EAAA,UAAA,CACG,sBACC,oBAAC,oBAAD;EACuB,qBAAA;EACrB,eAAe,sBAAsB,KAAK;EAC1C,MAAM;CACP,CAAA,GAEH,qBAAC,OAAD;EAAK,WAAW;YAAhB;GACG,QAAQ,UAAU,oBAAC,gBAAD,EAAuB,QAAU,CAAA;GACnD,QAAQ,mBAAmB,oBAAC,qCAAD,CAAoC,CAAA;GAC/D,CAAC,CAAC,YAAY,oBAAC,wBAAD,EAAgC,SAAW,CAAA;GAC1D,oBAAC,+BAAD,EAAsC,QAAU,CAAA;GAC/C,QAAQ,QACP,oBAAC,UAAD;IACE,WAAU;IACV,UAAU,QAAQ,KAAK;IACvB,SAAS;IACT,aAAa;IACb,MAAK;IACL,UAAU,QAAQ,KAAK,QAAQ,QAAQ,KAAK;GAC7C,CAAA;GAEH,qBAAC,OAAD;IACE,cAAY;IACZ,WAAW,KAAK,2BAA2B,EACzC,kCAAkC,cAAc,UAClD,CAAC;IACD,eAAY;IACZ,SAAS;IACT,WAAW,4BAA4B,4BAA4B,KAAA;IACnE,MAAM,4BAA4B,WAAW,KAAA;IAC7C,UAAU,4BAA4B,IAAI,KAAA;cAT5C;KAWG,CAAC,aAAa,oBAAC,kBAAD,CAAiB,CAAA;KAC/B,wBACC,oBAAC,6BAAD;MACE,SAAS;MACT,aAAa,QAAQ;MACrB,qBAAqB,QAAQ;KAC9B,CAAA;KAEF,YACC,oBAAC,wBAAD,CAAuB,CAAA,IAEvB,qBAAA,YAAA,EAAA,UAAA;MACE,qBAAC,eAAD,EAAA,UAAA;OACG,QAAQ,oBAAC,MAAD,EAAY,KAAO,CAAA;OAC3B,QAAQ,kBAAkB,oBAAC,iBAAD,CAAgB,CAAA;OAC1C,kBAAkB,SACjB,oBAAC,eAAD;QACE,eAAe;QACf,aAAa;OACd,CAAA,IACC;OACH,gBACC,oBAAC,uBAAD;QAA8B;QAAqB;OAAa,CAAA,IAEhE,oBAAC,aAAD;QAAsB;QAAqB;OAAa,CAAA;MAE7C,EAAA,CAAA;MACf,oBAAC,OAAD;OAAK,WAAU;iBACZ,gBAAgB,oBAAC,oBAAD,EAAkB,SAAA,KAAS,CAAA;MACzC,CAAA;MACL,oBAAC,OAAD;OAAK,WAAU;iBACb,oBAAC,YAAD,CAAa,CAAA;MACV,CAAA;KACL,EAAA,CAAA;IAED;;GACJ,gBACC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,iBAAD,CAAgB,CAAA;KACf,CAAC,YAAY,KAAK,CAAC,CAAC,QAAQ,QAAQ,cAAc,KACjD,oBAAC,QAAD;MAAM,WAAU;gBACb,QAAQ,KAAK,QAAQ,QAAQ,KAAK;KAC/B,CAAA;KAER,oBAAC,oBAAD,EAAkB,aAAY,wCAAyC,CAAA;KACtE,CAAC,aAAa,YAAY,oBAAC,0BAAD,CAAyB,CAAA;IACjD;;EAEJ;IA1E+B,QAAQ,EA0EvC,CACL,EAAA,CAAA;AAEN;AAEA,IAAM,oBAAoB,MAAM,KAC9B,sBACA,sBACF;;;;AAKA,IAAa,aAAa,UAAmC;CAG3D,OAAO,oBAAC,mBAAD;EAAmB,GAFH,kBAAkB,WAEX;EAAgB,GAAI;CAAQ,CAAA;AAC5D;;;AC3OA,IAAM,sBAAsB,UAAmC;CAC7D,MAAM,EACJ,QACA,SAAS,aACT,SACA,iBAAiB,OAAO,KAAK,eAAe,GAC5C,aAAa,iBACb,aAAa,iBACb,cACE;CAEJ,MAAM,EAAE,QAAQ,yBAAyB,eAAe,SAAS;CACjE,MAAM,EAAE,eAAe,SAAS,uBAAuB,SAAS;CAChE,MAAM,EACJ,SAAS,iBAAiB,WAE1B,WAAW,mBAAmB,mBAC5B,oBAAoB,SAAS;CACjC,MAAM,EAAE,oBAAoB,oBAAoB,gCAC9C,iCAAiC;CAEnC,MAAM,kBAAkB,mBAAmB,QAAQ,IAAI,CAAC,CAAC,QAAQ,IAAI;CACrE,MAAM,qBAAqB,aACxB,SAAoC,4BAA4B,QAAQ,IAAI,IAAI,GACjF,CAAC,QAAQ,IAAI,2BAA2B,CAC1C;CAEA,MAAM,iBAAiB,QAAQ,SAAS,aAAa,QAAQ,WAAW;CACxE,MAAM,qBAAqB,eAAe;CAE1C,MAAM,EAAE,aAAa,gBAAgB,eAAe,SAAS;EAC3D,oBAAoB;EACpB,oBAAoB;CACtB,CAAC;CAED,MAAM,EACJ,WACA,SACA,SACA,eACA,SACA,UACA,UACA,UACA,gBACE;CAEJ,MAAM,kBAAkB,cAEpB,CAAC,EACC,CAAC,eACD,OAAO,MAAM,MACb,SACC,CAAC,KAAK,OAAO,KAAK,OAChB,SAAS,cACR,IAAI,KAAK,QAAQ,UAAU,EAAE,QAAQ,IACnC,KAAK,OAAO,KAAK,IAAI,UAAU,QAAQ,KAEjD;EAAC;EAAQ;EAAa,QAAQ;EAAY;CAAI,CAChD;CAEA,MAAM,wBAAwB,kBAE1B,kBACE,gBACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,GACA,aACF,GAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CAEA,MAAM,EACJ,QAAQ,qBACR,gBAAgB,6BAChB,aAAa,0BACb,aAAa,0BACb,WAAW,wBACX,GAAG,SACD;CAeJ,OACE,oBAAC,iBAAD;EAAiB,OAAO;GAbxB,GAAG;GACH;GACA,mBAAmB;GACnB;GACA,mBAAmB;GACnB;GACA;GACA;GACA;GACA;EAIwB;YACtB,oBAAC,oBAAD,CAAqB,CAAA;CACN,CAAA;AAErB;AAEA,IAAM,kBAAkB,MAAM,KAC5B,oBACA,oBACF;;;;;AAMA,IAAa,WAAW,UAAwB;CAC9C,MAAM,EACJ,8BACA,uBACA,SACA,iBAAiB,qBACjB,iBAAiB,qBACjB,YAAY,gBACZ,qBACA,kBAAkB,sBAClB,kBACE;CAEJ,MAAM,EAAE,sBAAsB,UAAU,uBAAuB,SAAS;CAExE,MAAM,eAAe,iBAAiB,OAAO;CAC7C,MAAM,mBAAmB,qBAAqB,SAAS,cAAc;CACrE,MAAM,iBAAiB,mBAAmB,OAAO;CACjD,MAAM,cAAc,gBAAgB,oBAAoB;CACxD,MAAM,YAAY,YAAY,SAAS,qBAAqB;CAE5D,MAAM,uBAAuB,oBAAoB,OAAO;CAExD,MAAM,eAAe,iBAAiB,OAAO;CAE7C,MAAM,aAAa,eAAe,OAAO;CAEzC,MAAM,mBAAmB,qBAAqB,OAAO;CAErD,MAAM,aAAa,eAAe,OAAO;CAEzC,MAAM,EAAE,iBAAiB,oBAAoB,mBAAmB,SAAS;EACvE,iBAAiB;EACjB,iBAAiB;CACnB,CAAC;CAED,MAAM,EAAE,QAAQ,cAAc,cAAc,OAAO;CAEnD,MAAM,cAAc,yBAAyB,QAAQ;CAErD,OACE,oBAAC,iBAAD;EACE,gCAAgC,MAAM;EACtC,oBAAoB,MAAM;EAClB;EACsB;EAC9B,aAAa,MAAM;EACnB,uBAAuB,MAAM;EAC7B,YAAY,MAAM;EAClB,aAAa,MAAM;EACL;EACA;EACQ;EACV;EACM;EACN;EACM;EACP;EACK;EACH;EACA;EACb,gBAAgB,MAAM;EACtB,gBAAgB,MAAM;EACtB,gBAAgB,MAAM;EACb;EACT,SAAS,MAAM;EACf,gBAAgB,MAAM;EACtB,iBAAiB,MAAM;EAChB;EACP,wBAAwB;EACxB,wBAAwB;EACxB,aAAa,MAAM;EACnB,aAAa,MAAM;EACE;EACrB,QAAQ,MAAM;EACd,YAAY,MAAM;EAClB,mBAAmB,MAAM;EACV;EACf,YAAY,MAAM;EAClB,YAAY,MAAM;EACP;CACZ,CAAA;AAEL;;;AC3QA,IAAa,uBAAuB,UAAoC;CACtE,MAAM,EAAE,YAAY;CAEpB,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,SAAD,EAAkB,QAAU,CAAA;CACzB,CAAA;AAET;;;ACPA,IAAa,uBAAuB,SAiB9B;CACJ,MAAM,EACJ,SACA,sBACA,aACA,gBACA,qBACA,yBACA,+BACA,UACA,eACA,2BACE;CAEJ,MAAM,EAAE,WAAW,eAAe,qBAAqB;CACvD,MAAM,EAAE,oBAAoB,oBAAoB,qBAAqB;CAErE,MAAM,WAAW,cAAc,QAAQ,WAAW,GAAG,CAAC,OAAO,CAAC;CAE9D,MAAM,sBAAsB,CAAC;CAE7B,IAAI,oBACF,CAAC,uBAAuB,CAAC,uBAAuB,0BAC5C,WACA,gBAAgB;EACd;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ,OAAO,UAAU;CAC3B,CAAC;CAEP,IAAI,iBACF,oBAAoB,YAAY,mBAAmB,cAAc;CAGnE,MAAM,gBAAgB,eAAe;CAkBrC,OAAO;EAAE,oBAjBkB,cAEvB,kBAAkB,QAAoC,KAAK,SAAS,MAAM;GACxE,MAAM,QAAQ,cACZ,SACA,kBAAkB,IAAI,IACtB,kBAAkB,IAAI,IACtB,eACA,6BACF;GACA,IAAI,OAAO,IAAI,QAAQ,MAAM;GAC7B,OAAO;EACT,GAAG,CAAC,CAAC,GAEP;GAAC;GAA+B;GAAmB;EAAa,CAGzD;EAAoB,UAAU;CAAkB;AAC3D;;;AC/EA,IAAM,0BACJ;AACF,IAAM,cAAc;;;;;AAiBpB,IAAa,uCAAuC,EAClD,sBACA,aACA,wBAC0F;CAC1F,MAAM,CAAC,OAAO,YAAY,SAAkD;EAC1E,MAAM;EACN,SAAS;CACX,CAAC;CAED,MAAM,SAAS,kBAAkB;EAC/B,IAAI,wBAAwB,CAAC,eAAe,kBAAkB,WAAW,GAAG;GAC1E,SAAS;IAAE,MAAM;IAAM,SAAS;GAAM,CAAC;GACvC;EACF;EAEA,MAAM,aAAa,YAAY,iBAA8B,uBAAuB;EACpF,IAAI,WAAW,WAAW,GAAG;GAC3B,SAAS;IAAE,MAAM;IAAM,SAAS;GAAM,CAAC;GACvC;EACF;EAEA,MAAM,gBAAgB,YAAY,sBAAsB;EACxD,IAAI,WAAwB;EAC5B,IAAI,UAAU;EAEd,KAAK,MAAM,MAAM,YAAY;GAC3B,MAAM,OAAO,GAAG,sBAAsB;GACtC,MAAM,WAAW,GAAG,aAAa,WAAW;GAC5C,IAAI,CAAC,UAAU;GAIf,IAF+B,KAAK,OAAO,cAAc,OAE3B,KAAK,MAAM,SAAS;IAChD,UAAU,KAAK;IACf,MAAM,IAAI,IAAI,KAAK,QAAQ;IAC3B,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,WAAW;GACtC;EACF;EAEA,SAAS;GACP,MAAM;GACN,SAAS,aAAa;EACxB,CAAC;CACH,GAAG;EAAC;EAAsB;EAAa;CAAiB,CAAC;CAEzD,gBAAgB;EACd,IAAI,CAAC,aAAa;EAElB,MAAM,YAAY,SAAS,QAAQ,WAAW;EAE9C,UAAU;EACV,YAAY,iBAAiB,UAAU,SAAS;EAEhD,IAAI,OAAO,mBAAmB,aAC5B,aAAa;GACX,YAAY,oBAAoB,UAAU,SAAS;GACnD,UAAU,OAAO;EACnB;EAGF,MAAM,iBAAiB,IAAI,eAAe,SAAS;EACnD,eAAe,QAAQ,WAAW;EAElC,aAAa;GACX,YAAY,oBAAoB,UAAU,SAAS;GACnD,eAAe,WAAW;GAC1B,UAAU,OAAO;EACnB;CACF,GAAG,CAAC,aAAa,MAAM,CAAC;CAExB,OAAO;EACL,cAAc,MAAM;EACpB,kBAAkB,MAAM;CAC1B;AACF;;;ACzFA,IAAa,mBAAmB,UAAiC;CAC/D,MAAM,EAAE,SAAS,gBAAgB,UAAU,sBAAsB;CAEjE,OAAO,cAAc;EACnB,IAAI,mBACF,OAAO,SAAS,QACb,KAAK,QAAQ;GACZ,IAAI,IAAI,MAAM,QAAQ,uBAAuB,kBAAkB;IAC7D,OAAO,IAAI;IACX,aAAa,IAAI,WAAW,QAAQ;GACtC,CAAC;GACD,OAAO;EACT,GACA,CAAC,CACH;EAGF,IAAI,CAAC,gBAAgB,OAAO,CAAC;EAC7B,OAAO,GACJ,eAAe,KAAK,QAAQ,uBAAuB,kBAAkB;GACpE,OAAO,eAAe;GACtB,aAAa,eAAe,WAAW,QAAQ;EACjD,CAAC,EACH;CACF,GAAG;EAAC;EAAS;EAAgB;EAAU;CAAiB,CAAC;AAC3D;;;ACzBA,IAAa,wBACX,UACmC;CACnC,MAAM,EAAE,SAAS,gBAAgB,UAAU,sBAAsB;CAEjE,MAAM,kBAAkB,kBAEpB,SAAS,QACN,KAAK,QAAQ;EACZ,IAAI,IAAI,MAAM,QAAQ,uBAAuB,oBAAoB;GAC/D,OAAO,IAAI;GACX,aAAa,IAAI,WAAW,QAAQ;EACtC,CAAC;EACD,OAAO;CACT,GACA,CAAC,CACH,GACF,CAAC,SAAS,QAAQ,CACpB;CAEA,MAAM,sBAAsB,kBAAkB;EAC5C,IAAI,CAAC,gBAAgB,OAAO,CAAC;EAC7B,OAAO,GACJ,eAAe,KAAK,QAAQ,uBAAuB,oBAAoB;GACtE,OAAO,eAAe;GACtB,aAAa,eAAe,WAAW,QAAQ;EACjD,CAAC,EACH;CACF,GAAG,CAAC,SAAS,cAAc,CAAC;CAE5B,MAAM,CAAC,aAAa,kBAAkB,SACpC,oBAAoB,kBAAkB,mBACxC;CAEA,gBAAgB;EACd,IAAI,CAAC,mBAAmB;EACxB,eAAe,eAAe;EAC9B,OAAO,QAAQ,GAAG,2BAA2B,eAAe,eAAe,CAAC,EACzE;CACL,GAAG;EAAC;EAAS;EAAiB;CAAiB,CAAC;CAEhD,gBAAgB;EACd,IAAI,mBAAmB;OAClB,eAAe,mBAAmB;EACvC,OAAO,QAAQ,GAAG,2BAA2B,eAAe,mBAAmB,CAAC,EAC7E;CACL,GAAG;EAAC;EAAS;EAAqB;CAAiB,CAAC;CAEpD,OAAO;AACT;;;AC/BA,IAAa,0BAA0B,UAAuC;CAC5E,MAAM,EACJ,sBACA,kBACA,sBACA,gBACA,oBACA,UACA,gBACA,mBACA,eACE;CAEJ,MAAM,EAAE,kBAAkB,eAAe,wBAAwB;CACjE,MAAM,EAAE,YAAY,uBAAuB;CAC3C,MAAM,aAAa,oBAAoB,wBAAwB;CAG/D,MAAM,WAAW,gBAAgB;EAC/B;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,+BAA+B,qBAAqB;EACxD;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,wBAAwB,cACtB,gBAAgB,gBAAgB,GACtC,CAAC,gBAAgB,CACnB;CA+BA,OA7BoC,cAEhC,eAAe;EACb;EACA;EACA;EACA;EACA;EACA;EACA,UAAU;EACV;EACA;EACA,oBAAoB;GAAE,GAAG;GAAsB;GAAmB;EAAW;CAC/E,CAAC,GAEH;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAGK;AACT;;;AC1CA,IAAM,2BACJ,cACA,gBACG,aAAa,OAAO,SAAS,UAAU,QAAQ,OAAO,YAAY,QAAQ,EAAE;AAIjF,IAAM,2BACJ,cACA,gBAEA,aAAa,OACV,SAAS,UACR,QAAQ,OAAO,YAAY,YAAY,SAAS,aAAa,SAAS,QAAQ,EAClF;;;;;;;;;;;;;;;AAgBF,SAAgB,4BAA4B,QAA2C;CACrF,MAAM,EACJ,eACA,0BAA0B,OAC1B,8BAA8B,OAC9B,cAAc,OACd,yBACA,YACA,eACA,eACA,yBACA,qBACA,gBACA,oBACE;CAEJ,MAAM,EAAE,WAAW,eAAe,6BAA6B;CAE/D,MAAM,WAAW,OAA0B;EACzC,cAAc;EACd,cAAc;EACd,WAAW;CACb,CAAC;CACD,MAAM,WAAW,OAAuB,KAAA,CAAS;CACjD,MAAM,uBAAuB,OAA6B;EACxD,QAAQ;EACR,MAAM;CACR,CAAC;CACD,MAAM,yBAAyB,OAAO,WAAW;CACjD,MAAM,YAAY,OAAO,CAAC;CAE1B,sBAAsB;EACpB,IAAI,yBAAyB;GAG3B,SAAS,UAAU,OAAO;GAC1B,SAAS,UAAU,wBAAwB;GAC3C,uBAAuB,UAAU;GACjC;EACF;EAEA,MAAM,eAAe,SAAS;EAC9B,MAAM,eAAe,SAAS;EAC9B,MAAM,cAAc,OAAO;EAC3B,MAAM,iBAAiB,YAAY,YAAY,SAAS,MAAM,CAAC;EAC/D,MAAM,kBAAkB,eAAe,aAAa,SAAS;EAC7D,MAAM,cAAc,wBAAwB;EAC5C,MAAM,sBAAsB,eAAe,CAAC,uBAAuB;EACnE,MAAM,uBAAuB,CAAC,eAAe,uBAAuB;EAEpE,IAAI,qBAAqB;GAIvB,MAAM,eAAe,wBAAwB;GAC7C,MAAM,cAAc,aAAa,eAAe,aAAa;GAC7D,MAAM,gBAAgB,aAAa;GAUnC,IAAI,CAAC,aACH,qBAAqB,UAAU;IAC7B,QAAQ;IACR,MAAM;GACR;QACK,IAAI,iBAAiB,GAC1B,qBAAqB,UAAU;IAC7B,QAAQ;IACR,MAAM;GACR;QACK,IAAI,gBAAgB,yBAAyB;IAClD,MAAM,iBAAiB,cAAc;IACrC,IAAI,gBACF,qBAAqB,UAAU;KAC7B,QAAQ;KACR,MAAM;IACR;SAEA,qBAAqB,UAAU;KAC7B,QAAQ;KACR,MAAM;IACR;GAEJ,OACE,qBAAqB,UAAU;IAC7B,QAAQ;IACR,MAAM;GACR;EAEJ;EAIA,MAAM,cACJ,aAAa,eAAe,aAAa,eAAe,UAAU,UAClE;EAEF,IAAI,OAAO,iBAAiB,aAC1B,IAAI,aAAa,SAAS,YAAY,QAAQ;GAC5C,MAAM,qBAAqB,wBAAwB,cAAc,WAAW;GAC5E,MAAM,wBAAwB,wBAAwB,cAAc,WAAW;GAK/E,IAAI,oBAAoB;IACtB,MAAM,kBACJ,qBAAqB,QAAQ,SAAS,qBACtC,qBAAqB,QAAQ,WAC5B,wBAAwB,eACrB,qBAAqB,QAAQ,SAC7B;IAIN,IAAI,qBAAqB,QAAQ,SAAS,gBACxC,cAAc;SACT,IAAI,iBACT,cAAc,eAAe;SACxB,IAAI,UAAU,UAAU,yBAK7B,WADwB,YAAY,eAAe,aAAa,YACtC;IAG5B,qBAAqB,UAAU;KAC7B,QAAQ;KACR,MAAM;IACR;GACF,OAIK,IAAI,uBAAuB;IAC9B,IAAI,6BAA6B;KAG/B,SAAS,UAAU;KACnB,SAAS,UAAU;KACnB,uBAAuB,UAAU;KACjC;IACF;IAIA,IAFqC,eAAe,MAAM,OAAO,OAAO,UAEpC,aAClC,eAAe;SAEf,gBAAgB;GAEpB,OAGE,qBAAqB,UAAU;IAC7B,QAAQ;IACR,MAAM;GACR;EAEJ,OAEK;GACH,MAAM,kBACJ,iBAAiB,kBAAkB,WACnC,eAAe,kBAAkB;GACnC,MAAM,gBAAgB,iBAAiB,gBAAgB,eAAe;GAEtE,KAAK,mBAAmB,kBAAkB,aACxC,eAAe;GAGjB,IAAI,sBAGF,qBAAqB,UAAU;IAC7B,QAAQ;IACR,MAAM;GACR;EAEJ;EAGF,SAAS,UAAU;EACnB,SAAS,UAAU;EACnB,uBAAuB,UAAU;CAEnC,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA,OAAO;EACP;EACA;CACF,CAAC;CAED,QACE,gBACA,kBAA2E,SACxE;EACH,UAAU,UAAU;EAEpB,IACE,eACA,mBACA,qBAAqB,QAAQ,SAAS,mBACtC;GAKA,MAAM,eAAe,gBAAgB;GACrC,IAAI,CAAC,cAAc;GAEnB,qBAAqB,UAAU;IAC7B,QAAQ;IACR,MAAM;GACR;EACF;CACF;AACF;;;;;;;;;;;;ACpRA,IAAa,0BAA0B,WAAyC;CAC9E,MAAM,EACJ,4BAA4B,OAC5B,0BAA0B,OAC1B,cACA,aACA,cAAc,OACd,yBACA,WAAW,CAAC,GACZ,sBAAsB,KACtB,uBACE;CAEJ,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,KAAK;CAC1D,MAAM,CAAC,aAAa,kBAAkB,SAAkB;CACxD,MAAM,0BAA0B,OAAO,YAAY;CACnD,MAAM,8BAA8B,wBAAwB,WAAW,CAAC;CACxE,MAAM,wBAAwB,OAAO,KAAK;CAC1C,MAAM,4BAA4B,OAAO,KAAK;CAE9C,MAAM,CAAC,+BAA+B,oCACpC,SAAS,IAAI;CACf,MAAM,gBAAgB,OAAO,KAAK;CAClC,MAAM,aAAa,OAAO,KAAK;CAC/B,MAAM,uBAAuB,OAAO,CAAC;CACrC,MAAM,4BAA4B,OAAO,SAAS,MAAM;CACxD,MAAM,uCAAuC,OAAO,yBAAyB;CAC7E,MAAM,qCAAqC,OAAO,yBAAyB;CAC3E,MAAM,0BAA0B,OAA4B,IAAI;CAEhE,MAAM,gBAAgB,kBAAkB;EACtC,IAAI,CAAC,aAAa,OAAO;EAEzB,MAAM,WAAW,YAAY,sBAAsB;EACnD,MAAM,UAAU,SAAS;EACzB,MAAM,aAAa,SAAS;EAC5B,MAAM,aAAa,UAAU,SAAS,SAAS;EAG/C,MAAM,sBACJ,eAAe,YAAY,YAAY;EAIzC,MAAM,iBAHkB,MAAM,KAC5B,YAAY,iBAA8B,mBAAmB,CAExC,EAAgB,KAAK,YAAY;GACtD,MAAM,OAAO,QAAQ,sBAAsB;GAC3C,OAAO;IACL,QAAQ,KAAK,MAAM,KAAK,SAAS;IACjC;IACA,WAAW,KAAK,MAAM;IACtB;GACF;EACF,CAAC;EAED,MAAM,wBAAwB,eAAe,QAC1C,EAAE,WAAW,KAAK,SAAS,WAAW,KAAK,MAAM,UACpD;EAEA,MAAM,gBAAgB,sBAAsB,QAEzC,SAAS,cAAc;GACxB,IAAI,CAAC,WAAW,UAAU,KAAK,MAAM,QAAQ,KAAK,KAChD,OAAO;GAGT,OAAO;EACT,GAAG,IAAI;EAEP,MAAM,eACJ,sBAAsB,MACnB,EAAE,WAAW,KAAK,OAAO,cAAc,KAAK,UAAU,UACzD,KACA,sBAAsB,QACnB,SAAS,cAAc;GACtB,IAAI,CAAC,SAAS,OAAO;GAKrB,OAHiB,KAAK,IAAI,UAAU,SAAS,UAGtC,IAFiB,KAAK,IAAI,QAAQ,SAAS,UAEhC,IAAkB,YAAY;EAClD,GACA,IACF;EAEF,MAAM,UACH,sBAAsB,gBAAgB,iBAAiB,eAAe;EAEzE,IAAI,CAAC,QAAQ,QAAQ,QAAQ,WAAW,OAAO;EAE/C,OAAO;GACL,IAAI,OAAO,QAAQ,QAAQ;GAC3B,WAAW,OAAO;EACpB;CACF,GAAG;EAAC;EAAa;EAAyB;CAAW,CAAC;CAEtD,MAAM,gBAAgB,aACnB,WAA8C;EAC7C,IAAI,CAAC,aAAa;EAElB,wBAAwB,UAAU;EAElC,IAAI,YAAY;EAChB,IAAI,mBAAmB;EACvB,IAAI,cAAc;EAClB,IAAI;EAEJ,IAAI;EACJ,IAAI;EAEJ,0BAA0B,UAAU;EAEpC,MAAM,oBAAoB;GACxB,IAAI,WAAW,OAAO;GAEtB,MAAM,gBAAgB,YAAY,cAChC,qBAAqB,OAAO,GAAG,GACjC;GACA,IAAI,CAAC,eAAe,OAAO;GAE3B,MAAM,UAAU,YAAY,sBAAsB,EAAE;GAEpD,MAAM,cADgB,cAAc,sBAAsB,EAAE,MAAM,UAC9B,OAAO;GAE3C,IAAI,KAAK,IAAI,WAAW,IAAI,GAAG;IAC7B,YAAY,SAAS,EAAE,KAAK,YAAY,CAAC;IACzC,OAAO;GACT;GAEA,OAAO;EACT;EAEA,MAAM,gBAAgB;GACpB,YAAY;GACZ,cAAc;GACd,0BAA0B,UAAU;GACpC,IAAI,OAAO,qBAAqB,aAC9B,OAAO,qBAAqB,gBAAgB;GAE9C,IAAI,iBACF,aAAa,eAAe;GAE9B,gBAAgB,WAAW;EAC7B;EAGA,MAAM,uBAAuB;GAC3B,IAAI,aAAa,aAAa;GAC9B,cAAc;GACd,mBAAmB,OAAO,4BAA4B;IACpD,cAAc;IAEd,mBADiB,YACE,IAAW,mBAAmB,IAAI;IAErD,IAAI,oBAAoB,GAAG;KACzB,QAAQ;KACR;IACF;IAEA,eAAe;GACjB,CAAC;EACH;EAEA,mBAAmB,YAAY,IAAI,IAAI;EACvC,eAAe;EAIf,IAAI,OAAO,mBAAmB,aAAa;GACzC,iBAAiB,IAAI,qBAAqB;IACxC,mBAAmB;IACnB,eAAe;GACjB,CAAC;GACD,eAAe,QAAQ,WAAW;EACpC;EAEA,kBAAkB,iBAAiB;GACjC,QAAQ;EACV,GAAG,IAAI;EAEP,wBAAwB,UAAU;CACpC,GACA,CAAC,WAAW,CACd;CAEA,4BACc;EACV,wBAAwB,UAAU;CACpC,GACA,CAAC,CACH;CAEA,MAAM,iBAAiB,aACpB,YAA8B;EAC7B,IACE,CAAC,aAAa,YACd,gBACA,0BAA0B,WAC1B,+BACA,oBAEA;EAGF,YAAY,SAAS;GACnB,UAAU,SAAS;GACnB,KAAK,YAAY;EACnB,CAAC;EACD,kBAAkB,KAAK;CACzB,GACA;EAAC;EAAc;EAA6B;EAAa;CAAkB,CAC7E;;;;;CAMA,sBAAsB;EACpB,MAAM,gCACJ,qCAAqC,WAAW,CAAC;EACnD,qCAAqC,UAAU;EAI/C,IAAI,+BACF;EAGF,IAAI,aACF,eAAe,YAAY,sBAAsB,CAAC;EAGpD,IAAI,eAAe,6BAA6B;GAC9C,YAAY,YAAY,qBAAqB;GAC7C,sBAAsB,UAAU;GAChC;EACF;EAEA,IAAI,sBAAsB,SAAS;GACjC,sBAAsB,UAAU;GAChC;EACF;EAEA,IAAI,eAAe,CAAC,6BAA6B,CAAC,0BAA0B,SAC1E,eAAe;CAGnB,GAAG;EAAC;EAA2B;EAA6B;EAAa;CAAY,CAAC;;;;;CAMtF,sBAAsB;EACpB,MAAM,gCACJ,mCAAmC,WAAW,CAAC;EACjD,mCAAmC,UAAU;EAO7C,IAAI,+BACF;EAGF,IACE,CAAC,eACD,6BACA,gBACA,sBACA,+BACA,0BAA0B,SAE1B;EAGF,MAAM,0BACJ,YAAY,gBAAgB,YAAY,YAAY,YAAY;EAClE,MAAM,mBACJ,0BAA0B,YAAY,KAAK,SAAS,SAAS;EAE/D,IAAI,0BAA0B,uBAAuB,CAAC,kBACpD;EAGF,IAAI,qBAAqB;EAEzB,MAAM,4BAA4B;GAChC,IAAI,oBACF,eAAe;EAEnB;EAEA,oBAAoB;EAEpB,MAAM,mBAAmB;GADH;GAAI,mBAAmB,MAAM;GAAK;GAAK;EACpC,EAAa,KAAK,UACzC,WAAW,qBAAqB,KAAK,CACvC;EAEA,MAAM,kCAAkC;GACtC,qBAAqB;EACvB;EAIA,YAAY,iBAAiB,eAAe,2BAA2B,EACrE,SAAS,KACX,CAAC;EACD,YAAY,iBAAiB,cAAc,2BAA2B,EACpE,SAAS,KACX,CAAC;EACD,YAAY,iBAAiB,SAAS,2BAA2B,EAC/D,SAAS,KACX,CAAC;EACD,YAAY,iBAAiB,WAAW,yBAAyB;EAEjE,MAAM,qBAAqB,iBAAiB;GAC1C,0BAA0B;EAC5B,GAAG,IAAI;EAEP,aAAa;GACX,iBAAiB,QAAQ,YAAY;GACrC,aAAa,kBAAkB;GAC/B,YAAY,oBAAoB,eAAe,yBAAyB;GACxE,YAAY,oBAAoB,cAAc,yBAAyB;GACvE,YAAY,oBAAoB,SAAS,yBAAyB;GAClE,YAAY,oBAAoB,WAAW,yBAAyB;EACtE;CACF,GAAG;EACD;EACA;EACA;EACA;EACA,SAAS;EACT;EACA;EACA;CACF,CAAC;CAED,MAAM,kBAAkB,4BAA4B;EAClD;EACA,yBAAyB,2BAA2B,0BAA0B;EAC9E;EACA;EACA;EACA;EACA,aAAa,aAAa;GACxB,aAAa,SAAS,EAAE,KAAK,SAAS,CAAC;EACzC;EACA,qBAAqB;GACnB,IAAI,CAAC,aAAa;GAClB,YAAY,YAAY;EAC1B;EACA;EAEA,gCAAgC;GAC9B,cAAc,aAAa,gBAAgB;GAC3C,cAAc,aAAa,gBAAgB;GAC3C,WAAW,aAAa,aAAa;EACvC;EACA;EACA;EACA,uBAAuB,kBAAkB,IAAI;CAC/C,CAAC;CAED,sBAAsB;EACpB,wBAAwB,UAAU;CACpC,GAAG,CAAC,YAAY,CAAC;CAEjB,sBAAsB;EACpB,0BAA0B,UAAU,SAAS;CAC/C,GAAG,CAAC,SAAS,MAAM,CAAC;CAqCpB,OAAO;EACL;EACA;EACA,UAlCe,aACd,UAAyC;GACxC,MAAM,UAAU,MAAM;GACtB,MAAM,YAAY,QAAQ;GAC1B,qBAAqB,UAAU;GAE/B,gBAAgB,WAAW,aAAa;GAExC,MAAM,eAAe,QAAQ;GAE7B,MAAM,mBADe,QAAQ,gBACY,YAAY;GACrD,MAAM,uBAAuB,KAAK,IAAI,KAAK,MAAM,sBAAsB,EAAG,GAAG,EAAE;GAE/E,MAAM,oBAAoB,cAAc;GACxC,cAAc,UAAU,oBACpB,mBAAmB,sBACnB,mBAAmB;GACvB,WAAW,UAAU,YAAY;GAEjC,IAAI,cAAc,SAChB,kBAAkB,KAAK;GAEzB,IAAI,qBAAqB,CAAC,cAAc,SACtC,iCAAiC,KAAK;QACjC,IAAI,CAAC,qBAAqB,cAAc,SAC7C,iCAAiC,IAAI;EAEzC,GACA;GAAC;GAAe;GAAiB;GAAY;GAAe;EAAmB,CAM/E;EACA;EACA;CACF;AACF;;;ACjcA,IAAa,gCACX;AAEF,IAAa,wBAAwB,EAAE,eACrC,oBAAC,OAAD;CAAK,WAAW;CAAgC;AAAc,CAAA;;;ACFhE,IAAa,iCAAiC;AAa9C,IAAa,2BAA2B,EACtC,YAAY,MACZ,kBACkC;CAClC,MAAM,EAAE,MAAM,sBAAsB,yBAAyB;CAC7D,MAAM,EAAE,aAAa,wBAAwB;CAC7C,OACE,qBAAC,OAAD;EACE,WAAW;EACX,eAAY;YAFd,CAIE,oBAAC,OAAD;GAAK,WAAW;aACb,eAAe,YACZ,EAAE,oBAAoB,EAAE,OAAO,YAAY,CAAC,IAC5C,EAAE,iBAAiB;EACpB,CAAA,GACL,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,4BAA4B;GAC1C,UAAA;GACA,eAAe,SAAS;GACxB,MAAK;GACL,SAAQ;aAER,oBAAC,WAAD,CAAY,CAAA;EACN,CAAA,CACL;;AAET;;;ACzCA,IAAM,2CACJ,SACA,cACG;CACH,MAAM,EAAE,QAAQ,iBAAiB,QAAQ,sBAAsB;CAE/D,OAAO,gBADc,WAAW,sBAAsB,EAAE,OAAO;AAEjE;AAEA,IAAM,2CACJ,SACA,cACG;CACH,MAAM,EAAE,KAAK,cAAc,QAAQ,sBAAsB;CACzD,MAAM,EAAE,QAAQ,oBAAoB,UAAU,sBAAsB;CACpE,OAAO,YAAY;AACrB;AAUA,IAAa,iCAAiC,EAC5C,+BACA,aACA,YACA,kBACyC;CACzC,MAAM,EAAE,aAAa,uBAAuB,4BAA4B;CACxE,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CACtC,MAAM,2BAA2B,OAAO,KAAK;CAC7C,MAAM,kCAAkC,OAAO,yBAAyB;CAExE,gBAAgB;EACd,IAAI,EAAE,eAAe,kCAAkC;GACrD,QAAQ,KAAK;GACb;EACF;EAEA,MAAM,aAAa,eAAe;EAClC,IAAI,CAAC,YAAY;GACf,MAAM,CAAC,gBAAgB,SAAS,uBAC9B,6BACF;GACA,IAAI,CAAC,cAAc;GACnB,MAAM,CAAC,kBAAkB,SAAS,uBAChC,8BACF;GACA,IAAI,CAAC,gBACH,QAAQ,IAAI;GAEd;EACF;EAEA,MAAM,CAAC,kBAAkB,SAAS,uBAChC,8BACF;EACA,IAAI,CAAC,gBAAgB;GACnB,QAAQ,IAAI;GACZ;EACF;EAEA,MAAM,yBAAyB,wCAC7B,gBACA,UACF;EACA,MAAM,yBAAyB,wCAC7B,gBACA,UACF;EAEA,QACE,aACI,0BAA0B,yBAC1B,sBACN;EAEA,MAAM,WAAW,IAAI,sBAClB,aAAa;GACZ,IAAI,CAAC,SAAS,QAAQ;GAEtB,MAAM,EAAE,oBAAoB,gBAAgB,eAD9B,SAAS;GAEvB,IAAI,gBAAgB;IAClB,QAAQ,KAAK;IACb;GACF;GACA,MAAM,UAAU,YAAY,OAAO;GACnC,MAAM,+BAA+B,mBAAmB,SAAS;GACjE,QAAQ,cAAc,4BAA4B;GAClD,yBAAyB,UAAU;EACrC,GACA,EAAE,MAAM,WAAW,CACrB;EACA,SAAS,QAAQ,cAAc;EAE/B,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,gBAAgB;;;;;;EAOd,IACE,eACA,iCACA,yBAAyB,SACzB;GACA,QAAQ,IAAI;GACZ,yBAAyB,UAAU;EACrC;CACF,GAAG,CAAC,+BAA+B,WAAW,CAAC;CAE/C,OAAO,EAAE,MAAM,QAAQ,gCAAgC;AACzD;;;AC9HA,IAAM,sBAAsB,SAAkB,WAAmB;CAG/D,OAFiC,QAAQ,MAAM,eAAe,MAAM,EAAE,EAAE,IAAI,OAC5C,QAAQ,MAAM,KAAK,SAAS;AAE9D;;;;;;;;;;AAiBA,IAAa,eAAe,EAC1B,+BACA,qBACA,sBACuB;CACvB,MAAM,EAAE,WAAW,eAAe,aAAa;CAC/C,MAAM,EAAE,UAAU,4BAA4B,wBAAwB,aAAa;CACnF,MAAM,EAAE,YAAY,uBAAuB,aAAa;CAExD,gBAAgB;EACd,IAAI,CAAC,QAAQ,UAAU,GAAG,aAAa;EACvC,MAAM,uBACJ,CAAC,SAAS,UACV,CAAC,mBACD,CAAC,uBACD,iCACA,OAAO,MAAM,MACb,CAAC,mBAAmB,SAAS,OAAO,KAAK,EAAE;EAE7C,MAAM,2BAA2B;GAC/B,IAAI,eAAe,GAAG,SAAS;EACjC;EAEA,MAAM,oBAAoB,UAAiB;GACzC,MAAM,qBACJ,CAAC,MAAM,SAAS,aAAa,MAAM,SAAS;GAE9C,IAAI,CAAC,iCAAiC,mBAAmB,SAAS,QAChE,yBAAyB,SAAS;IAChC,MAAM,sBAAsB,MAAM,mBAAmB;IACrD,MAAM,sBAAsB,uBAC1B,QAAQ,MAAM,UACd,MAAM,OACR;IACA,OAAO;KACL,GAAI,QAAQ,CAAC;KACb,WACE,MAAM,cACL,wBAAwB,KAAK,qBAAqB,aAC/C,IAAI,KAAK,oBAAoB,UAAU,oBACvC,IAAI,KAAK,CAAC;KAChB,iBAAiB,sBAAsB;IACzC;GACF,CAAC;QACI,IAAI,sBAAsB,eAAe,GAC9C,SAAS;EAEb;EAEA,QAAQ,GAAG,eAAe,gBAAgB;EAC1C,SAAS,iBAAiB,oBAAoB,kBAAkB;EAEhE,IAAI,eAAe,GACjB,SAAS;EAGX,aAAa;GACX,QAAQ,IAAI,eAAe,gBAAgB;GAC3C,SAAS,oBAAoB,oBAAoB,kBAAkB;EACrE;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH;AAEA,SAAS,uBAAuB,UAA0B,YAA8B;CACtF,IAAI,CAAC,YAAY;CACjB,IAAI;CACJ,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;EAC7C,MAAM,MAAM,SAAS;EACrB,IAAI,CAAC,KAAK,IAAI;EACd,IAAI,IAAI,OAAO,WAAW,IAAI;GAC5B,sBAAsB;GACtB;EACF;CACF;CACA,OAAO;AACT;;;AClGA,IAAM,oCAAoC,UAAuC;CAC/E,MAAM,EAAE,kBAAkB,GAAG,qBAAqB;CAElD,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,EAAE,wBAAwB,iCAAiC,oBAAoB;CAErF,IAAI,CAAC,kBAAkB,OAAO;CAE9B,MAAM,QACJ,kBAAkB,IACd,EAAE,0BAA0B,EAAE,OAAO,gBAAgB,CAAC,IACtD,EAAE,eAAe;CAEvB,IAAI,8BACF,OAAO,oBAAC,8BAAD;EAA8B,GAAI;EAAc;CAAQ,CAAA;CAGjE,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,OAAD;GACE,eAAY;GACZ,aAAU;GACV,WAAU;GACV,eAAY;GACZ,MAAK;aAEJ;EACE,CAAA;CACF,CAAA;AAET;AAEA,IAAa,yBAAyB,MAAM,KAC1C,gCACF;;;AC5BA,IAAa,8BAA8B,EACzC,mBACA,YAAY,MACZ,kBACqC;CACrC,MAAM,EAAE,0BAA0B,aAAa,wBAAwB;CACvE,MAAM,EAAE,MAAM,sBAAsB,4BAA4B;CAEhE,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,0CAA0C,EACxD,sDAAsD,eAAe,UACvE,CAAC;EACD,eAAY;YAJd,CAME,qBAAC,QAAD;GACE,YAAW;GACX,eAAe,yBAAyB,iBAAiB;GACzD,SAAQ;aAHV,CAKE,oBAAC,aAAD,CAAc,CAAA,GACb,eAAe,YACZ,EAAE,oBAAoB,EAAE,OAAO,YAAY,CAAC,IAC5C,EAAE,iBAAiB,CACjB;MACR,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,4BAA4B;GAC1C,eAAe,SAAS;GACxB,SAAQ;aAER,oBAAC,WAAD,CAAY,CAAA;EACN,CAAA,CACL;;AAET;;;;;;;AC/CA,IAAM,sBAAsB,UAAiB;CAC3C,IAAI,iBAAiB,cAAc,MAAM,WAAW,GAClD,MAAM,eAAe;AAEzB;;;;;;;;;;;AAwBA,IAAa,kBAAkB,UAAkD;CAC/E,MAAM,EACJ,UACA,SAAS,YAAY,OACrB,aACA,iBACA,MACA,cAAc,MACd,WACA,gBACA,QACA,cACA,kBACA,YAAA,KACA,aAAa,OACb,GAAG,iBACD;CAEJ,MAAM,CAAC,iBAAiB,sBAAsB,SAA6B,IAAI;CAC/E,MAAM,iBAAiB,OAA2B,KAAA,CAAS;CAC3D,MAAM,wBAAwB,OAA2B,KAAA,CAAS;CAElE,MAAM,oBAAoB,OAAmB,KAAA,CAAS;CACtD,kBAAkB,gBAAgB;EAChC,MAAM,UAAU;EAEhB,IAAI,CAAC,WAAW,QAAQ,iBAAiB,MACvC;EAIF,MAAM,gBAAgB,QAAQ;EAE9B,MAAM,SACJ,QAAQ,eAAe,cAAc,YAAY,cAAc;EACjE,MAAM,gBAAgB,cAAc;EAEpC,IAAI,gBACF,eAAe,QAAQ,eAAe,SAAS;EAGjD,IAAI,WAAW;EAEf,IACE,eAAe,YAAY,UAC3B,sBAAsB,YAAY,eAElC;EACF,eAAe,UAAU;EACzB,sBAAsB,UAAU;EAGhC,IACE,gBAAgB,OAAO,SAAS,KAChC,OAAO,qBAAqB,cAC5B,iBAEA,iBAAiB;EAGnB,IAAI,SAAS,OAAO,SAAS,KAAK,OAAO,iBAAiB,cAAc,aACtE,aAAa;CAEjB;CAEA,gBAAgB;EACd,MAAM,gBAAgB,iBAAiB;EAEvC,IAAI,CAAC,eAAe;EAEpB,MAAM,uBAAuB,kBAAkB,UAAU;EAEzD,cAAc,iBAAiB,UAAU,gBAAgB,UAAU;EACnE,cAAc,iBAAiB,UAAU,gBAAgB,UAAU;EAOnE,MAAM,QAAQ,4BAA4B;GACxC,eAAe;EACjB,CAAC;EAED,aAAa;GACX,qBAAqB,KAAK;GAC1B,cAAc,oBAAoB,UAAU,gBAAgB,UAAU;GACtE,cAAc,oBAAoB,UAAU,gBAAgB,UAAU;EACxE;CACF,GAAG;EAAC;EAAa;EAAiB;CAAU,CAAC;CAE7C,gBAAgB;EACd,MAAM,gBAAgB,iBAAiB;EAEvC,IAAI,CAAC,eAAe;EAEpB,cAAc,iBAAiB,SAAS,oBAAoB,EAAE,SAAS,MAAM,CAAC;EAE9E,aAAa;GACX,cAAc,oBAAoB,SAAS,oBAAoB,UAAU;EAC3E;CACF,GAAG,CAAC,iBAAiB,UAAU,CAAC;CAEhC,OACE,qBAAC,WAAD;EAAW,GAAI;EAAc,KAAK;YAAlC;GACG;GACA;GACA;EACQ;;AAEf;;;;;;;;ACvHA,IAAM,6BAA6B,UAAgC;CACjE,MAAM,EAAE,gCAAgC,MAAM,gBAAgB,eAAe;CAE7E,MAAM,EAAE,eAAe,WAAW,uBAAuB,iBAAiB;CAE1E,MAAM,WADiB,iBACN,GAAgB,MAAM,QAAQ;CAC/C,MAAM,EAAE,WAAW,eAAe,iBAAiB;CACnD,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,SAAS,CAAC,MAAM,iBAAiB,iBAAiB;CAE1D,MAAM,kBAAkB,CAAC,aACrB,OAAO,OAAO,MAAM,EAAE,QACnB,EAAE,WAAW,WAAW,MAAM,OAAO,OAAO,MAAM,MAAM,CAAC,SAC5D,IACA,CAAC;CAEL,MAAM,iBAAiB,aACnB,OAAO,OAAO,MAAM,EAAE,QACnB,EAAE,WAAW,WAAW,MAAM,OAAO,OAAO,MAAM,MAAM,cAAc,QACzE,IACA,CAAC;CAGL,MAAM,EAAE,iBAAiB,yBADL,aAAa,iBAAiB,eACW;CAC7D,MAAM,gBAAgB,aAAa,SAAS;CAC5C,MAAM,qBAAqB,cACnB,uBAAuB,cAAc,CAAC,GAC5C,CAAC,cAAc,CAAC,CAClB;CAEA,MAAM,cAAc,cAEhB,aAAa,KACV,EAAE,YACA;EACC,IAAI,MAAM;EACV,UAAU,MAAM;EAChB,UAAU,MAAM;CAClB,EACJ,GACF,CAAC,YAAY,CACf;CAEA,gBAAgB;EACd,IAAI,iBAAiB,+BAA+B,eAAe;CACrE,GAAG;EAAC;EAAgB;EAA+B;CAAa,CAAC;CAEjE,IAAI,eAAe,kBAAkB,OACnC,OAAO;CAGT,IAAI,CAAC,iBAAiB,CAAC,+BACrB,OAAO;CAGT,OACE,qBAAC,OAAD;EACE,WAAW,KACT,8BACA,+CACA,EACE,sCAAsC,cACxC,CACF;EACA,eAAY;YARd;GAUG,YAAY,SAAS,KACpB,oBAAC,OAAD;IAAK,eAAY;cACf,oBAAC,aAAD;KAAa,WAAU;KAAkB;KAAa,MAAK;IAAM,CAAA;GAC9D,CAAA;GAEP,oBAAC,OAAD;IAAK,eAAY;IAAO,WAAU;cAChC,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,qBAAD,CAAsB,CAAA;IACnB,CAAA;GACF,CAAA;GACL,oBAAC,gBAAD,EAAA,UACE,oBAAC,QAAD;IACE,eAAY;IACZ,aAAU;IACV,eAAY;IACZ,MAAK;cAEJ;GACG,CAAA,EACQ,CAAA;EACb;;AAET;AAEA,IAAa,kBAAkB,MAAM,KACnC,yBACF;;;;;;;;AClGA,SAAS,+BACP,cACA,mBACA,mBACa;CACb,IAAI,eAAe,YAAY,GAAG,OAAO;CAGzC,KAAK,IAAI,IAAI,oBAAoB,GAAG,KAAK,GAAG,KAAK,GAAG;EAClD,MAAM,OAAO,kBAAkB;EAC/B,IAAI,uBAAuB,IAAI,GAC7B,OAAO,KAAK;CAEhB;CAIA,MAAM,UAAU,aAAI;CACpB,IAAI,SAAS;EACX,MAAM,IAAI,IAAI,KAAK,OAAO;EAC1B,OAAO,MAAM,EAAE,QAAQ,CAAC,IAAI,OAAO;CACrC;CACA,OAAO;AACT;AAEA,SAAS,4BACP,WACA,mBACA,gBACa;CACb,IAAI,uBAAuB,SAAS,GAAG,OAAO,UAAU;CAExD,OAAO,+BAA+B,WAAW,mBAAmB,cAAc;AACpF;;;;;AAMA,IAAM,eAAe;CAAE,MAAM;CAAM,SAAS;AAAM;AAElD,IAAa,4BAA4B,EACvC,sBACA,wBACoE;CACpE,MAAM,CAAC,OAAO,YAAY,SAGvB,YAAY;CAEf,MAAM,kBAAkB,aACrB,aAAgC;EAC/B,IAAI,wBAAwB,kBAAkB,WAAW,GAAG;GAC1D,SAAS,YAAY;GACrB;EACF;EAEA,MAAM,QAAQ,SAAS,QAAQ,MAA4B,KAAK,IAAI;EACpE,IAAI,MAAM,WAAW,GAAG;GACtB,SAAS,YAAY;GACrB;EACF;EAEA,MAAM,QAAQ,MAAM;EACpB,MAAM,aAAa,kBAAkB,WAAW,MAAM,EAAE,OAAO,MAAM,EAAE;EACvE,MAAM,OACJ,cAAc,IACV,4BAA4B,OAAO,mBAAmB,UAAU,IAChE;EAEN,MAAM,UAAU,SAAS;EACzB,UAAU,SAAS;GACjB,MAAM,WAAW,KAAK,MAAM,QAAQ,KAAK;GACzC,MAAM,WAAW,MAAM,QAAQ,KAAK;GACpC,IAAI,KAAK,YAAY,WAAW,aAAa,UAAU,OAAO;GAC9D,OAAO;IAAE;IAAM;GAAQ;EACzB,CAAC;CACH,GACA,CAAC,sBAAsB,iBAAiB,CAC1C;CAEA,OAAO;EACL,cAAc,MAAM;EACpB;EACA,kBAAkB,CAAC,CAAC,MAAM,QAAQ,MAAM;CAC1C;AACF;;;ACtGA,IAAa,mBAAmB,yBAAkC;CAChE,MAAM,CAAC,qBAAqB,0BAA0B,SAAuB;CAE7E,MAAM,EAAE,WAAW,eAAe,iBAAiB;CAEnD,gBAAgB;EACd,IAAI,CAAC,sBAAsB;EAC3B,MAAM,eAA6B,UAAU;GAC3C,MAAM,EAAE,SAAS,SAAS;GAE1B,IAAI,SAAS,YAAY,WAAW,MAAM,OAAO,OAAO,QACtD,uBAAuB,KAAA,CAAS;EAEpC;EAEA,OAAO,GAAG,eAAe,WAAW;EACpC,aAAa,OAAO,IAAI,eAAe,WAAW;CACpD,GAAG,CAAC,QAAQ,oBAAoB,CAAC;CAEjC,OAAO;EACL;EACA,wBAAwB,uBAAuB,yBAAyB,KAAA;CAC1E;AACF;;;ACtBA,IAAa,oBAAoB,EAAE,eAAuC;;;;CAIxE,MAAM,CAAC,eAAe,oBAAoB,SAAS,iBAAC,IAAI,KAAK,CAAC;CAC9D,MAAM,iBAAiB,OAA2B,KAAA,CAAS;CAE3D,gBAAgB;EAId,IAAI,CAHkB,UAAU,MAC7B,YAAY,QAAQ,OAAO,eAAe,OAC7C,GAEE,iBAAiB,iBAAC,IAAI,KAAK,CAAC;EAE9B,eAAe,UAAU,WAAW,IAAI;CAC1C,GAAG,CAAC,QAAQ,CAAC;CAEb,OAAO,EACL,cACF;AACF;;;ACvBA,SAAgB,0BACd,UACA,eACA,cACA;CACA,MAAM,CAAC,yBAAyB,8BAA8B,SAAS,KAAK;CAC5E,MAAM,CAAC,+BAA+B,oCACpC,SAAS,IAAI;;;;CAIf,MAAM,WAAW,OAAO,KAAK;CAE7B,MAAM,gBAAgB,OAAO,EAAE;CAC/B,MAAM,WAAW,OAAO,KAAK;CAE7B,gBAAgB;EACd,IAAI,cAAc;GAChB,2BAA2B,IAAI;GAC/B;EACF;EAEA,IAAI,CAAC,UAAU,QAAQ;EAEvB,MAAM,cAAc,SAAS,SAAS,SAAS;EAC/C,MAAM,gBAAgB,cAAc;EACpC,cAAc,UAAU,YAAY,MAAM;EAG1C,IAAI,YAAY,OAAO,eAAe;EAGtC,IAAI,SAAS,SAAS;EAGtB,IAAK,YAA6B,MAAM,OAAO,iBAAiB,SAAS,SAEvE,2BAA2B,IAAI;EAEjC,SAAS,UAAU;CACrB,GAAG;EAAC;EAAe;EAAU;CAAY,CAAC;CAE1C,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;ACjDA,IAAM,iCAAiC;CACrC,QAAQ;CACR,SAAS;AACX;AAEA,SAAgB,0BACd,UACA,kBACA;CACA,MAAM,wBAAwB,mBAAmB,IAAI;CACrD,MAAM,gCAAgC,OAAwB,KAAA,CAAS;CACvE,MAAM,wCAAwC,OAAwB,KAAA,CAAS;CAC/E,MAAM,4BAA4B,OAAO,CAAC;CAiE1C,OA/D0B,cAAc;EACtC,IAAI,CAAC,YAAY,CAAC,SAAS,QAAQ;GACjC,0BAA0B,UAAU;GACpC,OAAO;EACT;EAEA,MAAM,sBAAsB,WAAW;EAEvC,MAAM,gBACJ,qBAAqB,OAAO,sCAAsC,SAAS;EAa7E,MAAM,4BAA4B,eAAe,mBAAmB,IAChE,oBAAoB,SACpB,KAAA;EACJ,MAAM,6CAA6C,CAAC,EAClD,6BACA,+BAA+B;EAGjC,IAAI,iBAAiB,4CACnB,OAAO,0BAA0B;EAGnC,IAAI,CAAC,8BAA8B,SACjC,8BAA8B,UAAU;EAE1C,sCAAsC,UAAU;EAGhD,KACE,IAAI,wBAAwB,0BAA0B,SACtD,wBAAwB,SAAS,QACjC,yBAAyB,GAKzB,IAFE,SAAS,uBAAuB,OAAO,8BAA8B,SAAS,IAE3C;GACnC,0BAA0B,UAAU,wBAAwB;GAC5D,OAAO,0BAA0B;EACnC;EAIF,8BAA8B,UAAU;EACxC,0BAA0B,UAAU;EACpC,OAAO;CAIT,GAAG;EAAC;EAAuB;EAAU,UAAU;CAAM,CAE9C;AACT;;;ACxEA,IAAa,iCAAiC,EAC5C,UACA,gBACA,mCACyC;CACzC,MAAM,CAAC,iCAAiC,sCACtC,SAAS,KAAK;CAEhB,MAAM,6BAA6B,OAA2B,KAAA,CAAS;CAEvE,2BAA2B,WAAW,UAAiB;EACrD,IACE,CAAC,gCACD,CAAC,mCACD,MAAM,WAAW,QAEjB;EAGF,WAAW,gBAAgB,GAAG;CAChC;CAEA,gBAAgB;EACd,mCAAmC,IAAI;CACzC,GAAG,CAAC,QAAQ,CAAC;CAEb,gBAAgB;EACd,MAAM,eAAe,UAAiB;GACpC,2BAA2B,UAAU,KAAK;EAC5C;EAEA,MAAM,mBAAmB;GACvB,mCAAmC,KAAK;EAC1C;EAEA,IAAI,OAAO,WAAW,aAAa;GACjC,OAAO,iBAAiB,SAAS,WAAW;GAC5C,OAAO,iBAAiB,QAAQ,UAAU;EAC5C;EAEA,aAAa;GACX,OAAO,oBAAoB,SAAS,WAAW;GAC/C,OAAO,oBAAoB,QAAQ,UAAU;EAC/C;CACF,GAAG,CAAC,CAAC;AACP;;;ACnDA,SAAgB,6BACd,UACA,eACA;CACA,MAAM,wBAAwB,OAAO,EAAE;CACvC,MAAM,yBAAyB,OAAO,KAAK;CAE3C,SAAS,0BAA0B;EACjC,IAAI,YAAY,SAAS,SAAS,GAAG;GACnC,MAAM,cAAc,SAAS,SAAS,SAAS;GAE/C,IACG,YAA6B,MAAM,OAAO,iBAC3C,sBAAsB,YAAY,YAAY,IAC9C;IACA,sBAAsB,UAAU,YAAY;IAC5C,OAAO;GACT;EACF;EACA,OAAO;CACT;CAEA,gBAAgB;EACd,IAAI,YAAY,SAAS,UAAU,CAAC,uBAAuB,SAAS;GAClE,uBAAuB,UAAU;GACjC,wBAAwB;EAC1B;CAEF,GAAG,CAAC,UAAU,UAAU,MAAM,CAAC;CAE/B,OAAO;AACT;;;;;;;;;;;;;;;ACbA,IAAa,4CAA4C,EACvD,UACA,YACA,kBACyC;CACzC,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,MAAM,uCAAuC,aAC1C,qBAAwC;EACvC,IAAI,CAAC,aAAa;EAClB,MAAM,uBAAuB,iBAAiB;EAC9C,MAAM,sBAAsB,iBAAiB,MAAM,EAAE,EAAE;EACvD,IAAI,EAAE,wBAAwB,sBAAsB;EAEpD,MAAM,2BAA2B,IAAI,KAClC,qBAAsC,cAAc,CACvD,EAAE,QAAQ;EACV,MAAM,0BAA0B,IAAI,KACjC,oBAAqC,cAAc,CACtD,EAAE,QAAQ;EACV,MAAM,eAAe,IAAI,KAAK,YAAY,CAAC,EAAE,QAAQ;EAErD,MAAM,yBACJ,CAAC,CAAC,gBAAgB,2BAA2B;EAI/C,QACE,aACI,0BAJJ,CAAC,CAAC,gBAAgB,0BAA0B,eAKxC,sBACN;CACF,GACA;EAAC;EAAU;EAAY;CAAW,CACpC;CAEA,gBAAgB;EACd,IAAI,CAAC,aAAa,QAAQ,KAAK;CACjC,GAAG,CAAC,WAAW,CAAC;CAEhB,OAAO;EAAE;EAAM;CAAqC;AACtD;;;;;;;;AChCA,IAAa,yBAAyB,UAAsC;CAC1E,MAAM,EAAE,eAAA,kBAAgB,kBAAyB,oBAC/C,uBACF;CACA,MAAM,EAAE,sBAAsB,sBAAsB;CAEpD,MAAM,cAAc,iBAAiB,QAAQ,MAAM,cAAc;CACjE,MAAM,aAAa,eAAe;CAElC,MAAM,iBAAiB,yBAAyB;EAC9C;EACA;CACF,CAAC;CACD,MAAM,YAAY,oCAAoC;EACpD;EACA;EACA;CACF,CAAC;CAED,MAAM,eAAe,aAAa,UAAU,eAAe,eAAe;CAC1E,MAAM,mBAAmB,aACrB,UAAU,mBACV,eAAe;CAEnB,MAAM,mBAAmB,sBAAsB,QAAQ,MAAM,mBAAmB;CAChF,sBAAsB;EACpB,IAAI,CAAC,kBAAkB;EACvB,iBAAiB,UAAU,eAAe;EAC1C,aAAa;GACX,iBAAiB,UAAU;EAC7B;CACF,GAAG,CAAC,kBAAkB,eAAe,eAAe,CAAC;CAErD,IAAI,CAAC,oBAAoB,CAAC,gBAAgB,CAAC,iBAAe,OAAO;CAEjE,OAAO,oBAAC,iBAAD;EAAe,MAAM;EAAc,UAAA;CAAU,CAAA;AACtD;;;;;;ACpDA,IAAM,4BAA4B,UAA+B;CAC/D,MAAM,EAAE,SAAS,aAAa,UAAU;CACxC,MAAM,EAAE,SAAS;CAEjB,IAAI,SAAS,UAAU,OAAO;CAE9B,OACE,oBAAC,OAAD;EAAK,WAAU;EAA4B,eAAY;YACrD,oBAAC,OAAD;GAAK,WAAU;aACZ,aACC,oBAAC,OAAD;IACE,yBAAyB,EAAE,QAAQ,QAAQ,QAAQ,GAAG;IACtD,0BAAA;GACD,CAAA,IAED,oBAAC,QAAD,EAAA,UAAO,QAAQ,KAAW,CAAA;EAEzB,CAAA;CACF,CAAA;AAET;AAEA,IAAa,iBAAiB,MAAM,KAClC,wBACF;;;ACYA,SAAgB,sBAAsB,EACpC,sBACA,YACA,eACA,gBACA,uBAAuB,gBACvB,oBACA,UACA,8BACA,UACA,oBAAoB,gBACI;CACxB,MAAM,EACJ,eAAA,kBAAgB,eAChB,iBACA,kBAAkB,MAClB,gBAAgB,gBAChB,yBAAA,4BAA0B,4BACxB;CAEJ,MAAM,mBAAmB,CAAC;CAC1B,IAAI;CACJ,IAAI,kBAAkB,KAAA;CACtB,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS;EACpD,MAAM,UAAU,SAAS;EACzB,IAAI,uBAAuB,OAAO,GAChC,iBAAiB,KACf,oBAAC,iBAAD;GAAiB,cAAY;aAC3B,oBAAC,iBAAD;IACE,MAAM,QAAQ;IACd,YAAY,aAAa;IACzB,QAAQ,QAAQ;GACjB,CAAA;EACc,GANwB,GAAG,QAAQ,KAAK,YAAY,EAAE,GAMtD,CACnB;OACK,IAAI,eAAe,OAAO;OAC3B,iBACF,iBAAiB,KACf,oBAAC,iBAAD;IAAiB,cAAY;cAC3B,oBAAC,iBAAD,CAAkB,CAAA;GACH,GAFuB,OAEvB,CACnB;EAAA,OAEG,IAAI,QAAQ,SAAS,UAC1B,iBAAiB,KACf,oBAAC,iBAAD;GACE,cAAY;GACZ,mBAAiB,QAAQ;aAGzB,oBAAC,eAAD;IAAwB;IAAS,YAAY,aAAa;GAAa,CAAA;EACxD,GAHV,QAAQ,MAAM,QAAQ,WAAW,YAAY,CAGnC,CACnB;OACK;GACL,IAAI,CAAC,cACH,eAAe;GAEjB,MAAM,cAA0B,mBAAmB,QAAQ,OAAO;GAClE,MAAM,eACJ,eAAe,WAAW,8BAA8B;GAE1D,MAAM,uBAAuB,wBAAwB;IACnD,sBAAsB,sBAAsB;IAC5C,gBAAgB,CAAC,CAAC,cAAc,MAAM,aAAa,OAAO,QAAQ;IAClE,cAAc,sBAAsB;IACpC,mBAAmB,sBAAsB;IACzC;IACA;IACA,oBAAoB,sBAAsB;GAC5C,CAAC;GAED,iBAAiB,KACf,qBAAC,UAAD,EAAA,UAAA,CACG,wBAAwB,6BACvB,oBAAC,iBAAD;IAAiB,WAAU;cACzB,oBAAC,2BAAD,EACE,aAAa,sBAAsB,gBACpC,CAAA;GACc,CAAA,GAEnB,oBAAC,iBAAD;IACE,WAAW;IACX,cAAY;IACZ,mBAAiB,QAAQ;IACzB,eAAa;cAEb,oBAAC,SAAD;KACE,aAAa,6BAA6B,QAAQ,OAAO,CAAC;KAC1D,aAAa,CAAC,WAAW;KACT;KACA;KACP;KACT,QAAQ,SAAS,QAAQ,OAAO,CAAC;KACjC,GAAI;IACL,CAAA;GACc,CAAA,CACT,EAAA,GAxBK,QAAQ,MAAM,QAAQ,WAAW,YAAY,CAwBlD,CACZ;GACA,kBAAkB;EACpB;CACF;CACA,OAAO;AACT;;;ACxJA,IAAa,eACX,OACA,YACkB;CAClB,KAAK,IAAI,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK,GAC1C,IAAI,QAAQ,MAAM,EAAE,GAClB,OAAO,MAAM;AAKnB;;;ACPA,IAAa,qBAAqB,EAChC,UACA,gBAKA,cAEI,YAAY,YAAY,WAAW,SAAS,IAAI,QAAQ,IAAI,KAAK,QAAQ,SAAS,GACpF,CAAC,UAAU,SAAS,CACtB;;;ACdF,IAAM,6BAA6B;AAEnC,IAAM,iCAAiC;CACrC,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,OAAO;CAGT,OAAO,OAAO,WAAW,0BAA0B,EAAE;AACvD;AAEA,IAAM,4BAA4B,kBAA8B;CAC9D,IAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAChE,aAAa,KAAA;CAGf,MAAM,iBAAiB,OAAO,WAAW,0BAA0B;CACnE,MAAM,qBAAqB,cAAc;CAEzC,IAAI,OAAO,eAAe,qBAAqB,YAAY;EACzD,eAAe,iBAAiB,UAAU,YAAY;EACtD,aAAa,eAAe,oBAAoB,UAAU,YAAY;CACxE;CAEA,eAAe,YAAY,YAAY;CACvC,aAAa,eAAe,eAAe,YAAY;AACzD;AAEA,IAAa,mCACX,qBAAqB,0BAA0B,gCAAgC,KAAK;;;ACTtF,IAAM,yCACJ,UACG;CACH,MAAM,EACJ,+BACA,0BAA0B,OAC1B,SACA,eACE;CAEJ,MAAM,EAAE,SAAS,eAAe,WAAW,eAAe;CAC1D,MAAM,EAAE,WAAW,uBAAuB;CAC1C,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,CAAC,aAAa,kBAAkB,SAAS,eAAe,YAAY,KAAK,CAAC;CAChF,MAAM,CAAC,YAAY,iBAAiB,SAAS,QAAQ,eAAe,CAAC;CACrE,MAAM,gBAAgB,aAAa,oBAAoB;CAEvD,gBAAgB;EACd,MAAM,eAAe,UAAiB;GACpC,MAAM,6BAA6B,MAAM,QAAQ,eAAe;GAChE,MAAM,mBAAmB,MAAM,MAAM,OAAO,OAAO,MAAM;GAEzD,MAAM,eAAe,CAAC,CAAC;GACvB,MAAM,oBAAoB,CAAC,CAAC,MAAM,SAAS;GAI3C,IACE,iCACA,8BACA,oBALA,gBAAgB,CAAC,cAAc,mBAQ/B;GAGF,IAAI,MAAM,SAAS,eAEjB,gBAAgB,SAAS,OAAO,CAAC;QAC5B,IAAI,MAAM,SAAS,OAAO,QAAQ,IAAI;IAC3C,MAAM,gBAAgB,MAAM,SAAS,eAAe;IACpD,qBAAqB,gBAAgB,UAAU;GACjD;EACF;EACA,OAAO,GAAG,eAAe,WAAW;EAEpC,aAAa;GACX,OAAO,IAAI,eAAe,WAAW;EACvC;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,gBAAgB;EACd,IAAI,+BAA+B;GACjC,eAAe,CAAC;GAChB,cAAc,QAAQ,eAAe,CAAC;EACxC;CACF,GAAG,CAAC,+BAA+B,MAAM,CAAC;CAE1C,IAAI,iCAAiC,CAAC,yBAAyB,OAAO;CAEtE,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,6BAA6B;GAC3C,aAAU;GACV,UAAA;GACA,WAAU;GACV,eAAY;GACH;GACT,MAAK;GACL,SAAQ;aAER,oBAAC,eAAD,CAAgB,CAAA;EACV,CAAA,GACP,cAAc,KACb,oBAAC,OAAD;GACE,WAAU;GACV,eAAY;GACZ,MAAK;GACL,SAAQ;aAEP;EACI,CAAA,CAEN;;AAET;AAEA,IAAa,8BAA8B,MAAM,KAC/C,qCACF;;;AC3DA,IAAM,0BAA0B,aAC9B,GAAG,SAAS,OAAO,GAAG,SAAS,IAAI,MAAM,GAAG,GAAG,SAAS,SAAS,SAAS,IAAI,MAAM;AAEtF,IAAM,uBAAuB,YAC3B,SAAS,YAAY,UAAU,KAAK;AAEtC,IAAM,0BAA0B,UAAuC;CACrE,MAAM,EACJ,SACA,sBACA,uBAAuB,OACvB,aACA,eAAe,OACf,gBACA,sBAAsB,OACtB,0BAA0B,OAC1B,sBACA,6BAA6B,EAC3B,WAAW,0BAAA,KACX,GAAG,oCACD,CAAC,GACL,4BAA4B,QAAQ,QAAQ,GAC5C,UAAU,kBACV,eAAe,uBACf,+BACA,iBAAiB,OAAO,KAAK,eAAe,GAC5C,eAAA,IACA,WAAW,CAAC,GACZ,gBAAgB,OAChB,qBACA,iBAAiB,uBACjB,oBAAoB,OACpB,wBACA,8BACA,eACA,oBACA,QACA,aAAa,OACb,aAAa,UACX;CAEJ,MAAM,CAAC,aAAa,kBAAkB,MAAM,SAAgC,IAAI;CAChF,MAAM,CAAC,mBAAmB,wBACxB,MAAM,SAA4B,MAAM;CAC1C,MAAM,CAAC,sBAAsB,2BAC3B,MAAM,SAA+B,MAAM;CAC7C,MAAM,CAAC,+BAA+B,oCACpC,MAAM,SAAwB,IAAI;CACpC,MAAM,0BAA0B,MAAM,OAAO,YAAY;CACzD,MAAM,iCAAiC,MAAM,OAAO,EAAE;CACtD,MAAM,8BAA8B,MAAM,OAGvC;EACD,gBAAgB;EAChB,eAAe;CACjB,CAAC;CAED,MAAM,EAAE,kBAAkB,eAAe,aAAa;CAEtD,MAAM,iBADuB,2BACN,IAAuB,SAAS;CAEvD,MAAM,EACJ,qBAAA,wBAAsB,qBACtB,kBAAA,qBAAmB,kBACnB,sBAAA,yBAAuB,sBACvB,qBAAqB,MACrB,wBAAA,2BAAyB,wBACzB,kBAAA,qBAAmB,kBACnB,6BAAA,gCAA8B,6BAC9B,iBAAA,oBAAkB,iBAClB,4BAAA,+BAA6B,+BAC3B,oBAAoB;CAExB,MAAM,qBAAqB,sBAAsB;CACjD,MAAM,sBAAsB,MAAM,cAC1B,uBAAuB,QAAQ,GACrC,CAAC,QAAQ,CACX;CACA,MAAM,mBAAmB,MAAM,eACtB;EACL,gBAAgB,oBAAoB,SAAS,EAAE;EAC/C,eAAe,oBAAoB,SAAS,SAAS,SAAS,EAAE;CAClE,IACA,CAAC,QAAQ,CACX;CACA,MAAM,oBAAoB,sBAAsB;CAChD,MAAM,6BAA6B,CAAC,CAAC;CAGrC,MAAM,gCAAgC,yBAAyB;CAC/D,MAAM,6BAA6B,wBAAwB,WAAW,CAAC;CAEvE,MAAM,EACJ,gBACA,+BACA,UACA,gBACA,gBACE,uBAAuB;EACzB,2BACE,qBAAqB,8BAA8B;EACrD,yBAAyB,qBAAqB;EAC9C;EACA;EACA,aAAa,MAAM;EACnB;EACA;EACA,qBAAqB,MAAM;EAC3B;CACF,CAAC;CACD,MAAM,oCACJ,iCACA,CAAC,qBACD,CAAC,iCACD,CAAC;CAEH,MAAM,EAAE,MAAM,mCAAmC,8BAA8B;EAC7E;EACA;EACA,YAAY,CAAC,CAAC;EACd,aAAa,sBAAsB;CACrC,CAAC;CAED,YAAY;EACV,+BAA+B;EAC/B,qBAAqB;EACrB,iBAAiB,CAAC,CAAC,sBAAsB;CAC3C,CAAC;CAED,MAAM,EAAE,oBAAoB,UAAU,qBAAqB,oBAAoB;EAC7E;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,iBAAiB,kBAAkB;EACvC;EACA,WAAW,QAAQ,UAAU,EAAE,MAAM;CACvC,CAAC;CAED,MAAM,WAAW,uBAAuB;EACtC;EACA;EACA,sBAAsB;GACpB,gCAAgC,MAAM;GACtC,8BAA8B,MAAM;GACpC,uBAAuB,MAAM;GAC7B,YAAY,MAAM;GAClB,SAAS,MAAM;GACf;GACA,iBAAiB;GACjB,iBAAiB,MAAM;GACvB,iBAAiB,MAAM;GACvB,aAAa,MAAM;GACnB,aAAa,MAAM;GACnB,YAAY,MAAM;GAClB;GACA,YAAY,MAAM;GAClB,kBAAkB,MAAM;GACxB,YAAY,MAAM;GAClB;GACA;EACF;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,gCAAgC;EAC9B,gBAAgB,QAAQ;EACxB;EACA,WAAW,QAAQ,UAAU,EAAE,MAAM;EACrC;CACF,CAAC;CAED,MAAM,mBAAmB,eAAe,eAAe;CAEvD,MAAM,WAAW,MAAM,kBAAkB;EACvC,IAAI,kBACF,iBAAiB,YAAY;CAEjC,GAAG,CAAC,kBAAkB,YAAY,CAAC;CAEnC,MAAM,gBAAgB,MAAM,kBAAkB;EAC5C,IAAI,uBACF,sBAAsB,YAAY;CAEtC,GAAG,CAAC,uBAAuB,YAAY,CAAC;CAExC,MAAM,iCAAiC,MAAM,YAAY,YAAY;EACnE,IAAI,cAAc;GAChB,iCAAiC,mBAAmB;GACpD,qBAAqB,oBAAoB;GACzC,IAAI;IACF,MAAM,oBAAoB;GAC5B,SAAS,OAAO;IACd,iCAAiC,IAAI;IACrC,qBAAqB,MAAM;IAC3B,MAAM;GACR;GACA;EACF;EAEA,eAAe,EAAE,UAAU,eAAe,CAAC;CAC7C,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,sBAAsB;EAC1B,IACE,sBAAsB,wBACtB,gBACA,CAAC,aAAa,YACd,wBAAwB,+BAExB;EAGF,YAAY,SAAS,EAAE,KAAK,EAAE,CAAC;EAE/B,MAAM,mBAAmB,4BAA4B;GACnD,qBAAqB,WAAW;GAChC,YAAY,SAAS;IACnB,UAAU;IACV,KAAK,YAAY;GACnB,CAAC;EACH,CAAC;EAED,aAAa,qBAAqB,gBAAgB;CACpD,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,sBAAsB;EAC1B,IAAI,sBAAsB,eAAe,CAAC,aAAa,UACrD;EAGF,MAAM,iBAAiB;GACrB,YAAY,SAAS,EAAE,KAAK,YAAY,aAAa,CAAC;GACtD,iCAAiC,IAAI;GACrC,qBAAqB,MAAM;EAC7B;EAEA,MAAM,kBAAkB,WAAW,UAAU,GAAG;EAEhD,aAAa;GACX,aAAa,eAAe;EAC9B;CACF,GAAG,CAAC,mBAAmB,WAAW,CAAC;CAEnC,MAAM,sBAAsB;EAC1B,IAAI,CAAC,sBAAsB;GACzB,wBAAwB,MAAM;GAC9B;EACF;EAEA,MAAM,UAAU,aAAa,cAC3B,qBAAqB,qBAAqB,GAC5C;EACA,IAAI,CAAC,SAAS;GACZ,wBAAwB,oBAAoB;GAC5C;EACF;EAEA,MAAM,oBACJ,+BAA+B,YAAY;EAC7C,wBAAwB,oBAAoB,cAAc,MAAM;EAChE,IAAI;EAEJ,MAAM,mBAAmB,4BAA4B;GACnD,QAAQ,eAAe;IACrB,UAAU;IACV,OAAO;GACT,CAAC;GAED,IAAI,CAAC,qBAAqB,CAAC,aAAa,UAAU;IAChD,wBAAwB,MAAM;IAC9B;GACF;GAEA,kBAAkB,iBAAiB;IACjC,MAAM,cAAc,QAAQ,sBAAsB;IAClD,MAAM,WAAW,YAAY,sBAAsB;IACnD,MAAM,YACJ,YAAY,aACX,YAAY,MAAM,SAAS,QAC3B,YAAY,eAAe,YAAY,UAAU;IAEpD,YAAY,SAAS,EAAE,KAAK,KAAK,IAAI,WAAW,CAAC,EAAE,CAAC;IACpD,wBAAwB,MAAM;GAChC,GAAG,GAAG;EACR,CAAC;EAED,aAAa;GACX,qBAAqB,gBAAgB;GACrC,IAAI,iBACF,aAAa,eAAe;EAEhC;CAEF,GAAG;EAAC;EAAgB;EAAsB;CAAmB,CAAC;CAE9D,MAAM,gBAAgB;EACpB,wBAAwB,UAAU;CACpC,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,gBAAgB;EACpB,+BAA+B,UAAU;EACzC,4BAA4B,UAAU;CACxC,GAAG,CAAC,kBAAkB,mBAAmB,CAAC;CAE1C,MAAM,KAAK,YAAY;CAEvB,MAAM,0BAA0B,SAAS,WAAW,KAAK,CAAC;CAC1D,MAAM,kBAAkB,aACpB,sCAAsC,OACtC,+BAA+B;CAEnC,OACE,oBAAC,4BAAD;EACE,OAAO;GACL;GACA,mBAAmB;GACnB;EACF;YAEA,oBAAC,gCAAD,EAAA,UACE,qBAAC,wBAAD,EAAA,UAAA,CACE,qBAAC,uBAAD;GAAuB,IAAI;aAA3B;IACG,CAAC,cAAc,kCACd,oBAAC,8BAAD,EACE,aAAa,sBAAsB,gBACpC,CAAA;IAEH,oBAAC,uBAAD;KACwB;KACT;KACb,mBAAmB;IACpB,CAAA;IACD,oBAAC,OAAD;KACE,WAAW,KAAK,kBAAkB,eAAe,UAAU;KACjD;KACV,KAAK;KACL,UAAU;eAET,0BACC,oBAAC,uBAAD,EAAqB,UAAU,aAAa,WAAW,UAAY,CAAA,IAEnE,qBAAC,gBAAD;MACE,WAAU;MACV,eAAY;MACZ,aAAa,MAAM;MACnB,iBAAiB,gCAAgC,QAAQ,MAAM;MAC/D,MAAM,MAAM;MACZ,WAAW,QACT,MAAM,eAAe,MAAM,kCAC7B;MACA,QACE,oBAAC,OAAD;OAAK,WAAU;kBACX,MAAM,eACN,MAAM,uCAAuC,oBAAC,oBAAD,CAAmB,CAAA;MAC/D,GAHwC,mBAGxC;MAEP,cAAc;MACd,kBACE,sCAAsC,KAAA,IAAY;MAEpD,WAAW;MACX,GAAI;gBApBN;OAsBE,oBAAC,oBAAD;QAAoB,WAAU;kBAC3B;OACiB,CAAA;OACpB,oBAAC,mBAAD;QACE,+BAA+B;QACf;QACJ;OACb,CAAA;OAED,oBAAC,OAAD,CAAmB,GAAV,QAAU;MACL;;IAEf,CAAA;IACL,oBAAC,0BAAD;KACE,iBAAiB,sBAAsB;KACvC,kBAAkB,kBAAkB;IACrC,CAAA;IACD,oBAAC,+BAAD;KACiC;KAC/B,yBAAyB;KACzB,SAAS;KACG;IACb,CAAA;GACoB;MACvB,oBAAC,oBAAD,EAAkB,OAAO,mBAAqB,CAAA,CAC1B,EAAA,CAAA,EACQ,CAAA;CACN,CAAA;AAEhC;;;;;;;;;AAiGA,IAAa,eAAe,UAA4B;CACtD,MAAM,EAAE,qBAAqB,UAAU,kBACrC,wBAAwB,aAAa;CAEvC,MAAM,EACJ,SAAS,sBACT,OAAO,oBACP,UAAU,uBACV,GAAG,4BACD,uBAAuB,aAAa;CAExC,OACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,wBAAD;EACuB;EACX;EACK;EACf,GAAI;EACJ,GAAI;CACL,CAAA,EACa,CAAA;AAEpB;;;ACzkBA,IAAM,iBAAiB,MAAM;AAE7B,SAAgB,mBAAmB,eAAuB,mBAA2B;CACnF,OAAO,gBAAgB,oBAAoB;AAC7C;AAEA,SAAgB,wBAAwB,mBAA2B;CACjE,OAAO,iBAAiB;AAC1B;AAEA,IAAa,4BACX,sBACA,sBAEA,UAAU,UAAmC;CAC3C,MAAM,mBAAmB,MACtB,KAAK,SAAS;EACb,IAAI,CAAC,KAAK,eAAe,OAAO,KAAA;EAChC,OAAO,kBAAkB,mBAAmB,KAAK,eAAe,cAAc;CAChF,CAAC,EACA,QAAQ,QAAQ,CAAC,CAAC,GAAG;CACxB,qBAAqB,SAAS,WAC5B,OAAO,gBAAqC,CAC9C;AACF,GAAG,GAAG;AAOR,IAAa,QAAQ,EAAE,SAAS,GAAG,YAAsD;CACvF,IAAI,CAAC,SAAS,OAAO,oBAAA,YAAA,CAAI,CAAA;CAEzB,MAAM,UACJ,QAAQ,kBACN,mBAAmB,MAAM,oBAAoB,QAAQ,iBAAiB;CAE1E,MAAM,cAA0B,QAAQ,mBAAmB,QAAQ;CAEnE,OACE,oBAAC,OAAD;EACE,GAAI;EACJ,WACE,SAAS,eAAe,kBACxB,KAAK,uDAAuD,GACzD,iBAAiB,gBAAgB,YACpC,CAAC;CAEJ,CAAA;AAEL;AACA,IAAa,YAAU,EAAE,cAA4C;CACnE,MAAM,EAAE,kBAAA,qBAAmB,qBAA4B,oBACrD,8BACF;CAEA,OACE,qBAAA,YAAA,EAAA,UAAA,CACG,SAAS,MACT,SAAS,eAAe,sBACvB,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,oBAAD,CAAmB,CAAA;CAChB,CAAA,CAEP,EAAA,CAAA;AAEN;AACA,IAAa,oBAAoB,EAAE,cAA4C;CAC7E,MAAM,EAAE,qBAAA,wBAAsB,wBAA+B,oBAC3D,wBACF;CAEA,IACE,OAAO,SAAS,sBAAsB,eACtC,QAAQ,kBAAkB,SAAS,GAEnC,OAAO;CAET,OACE,oBAAA,YAAA,EAAA,UACG,yBACC,oBAAC,uBAAD,EAAqB,UAAU,SAAS,aAAa,WAAW,UAAY,CAAA,EAE9E,CAAA;AAEN;AAEA,IAAa,mBACX,eACA,OACA,oBACG;CACH,MAAM,EACJ,gCACA,8BACA,uBACA,eACA,sBACA,YACA,gBACA,cACA,mBACA,uBACA,SAAS,oBACT,gBACA,oBACA,eACA,mBACA,YACA,8BACA,yBACA,mBAAmB,aACnB,qBACA,YACA,mBACA,YACA,eACA,YACA,qBAAqB,GACrB,yBACA,gBACE;CAEJ,MAAM,qBAAqB,mBAAmB,eAAe,iBAAiB;CAE9E,IAAI,uBACF,OAAO,sBAAsB,aAAa,kBAAkB;CAG9D,MAAM,UAAU,YAAY;CAE5B,IAAI,CAAC,WAAW,eAAe,OAAO,GAAG,OAAO,oBAAC,OAAD,EAAK,OAAO,EAAE,QAAQ,MAAM,EAAQ,CAAA;CAEpF,IAAI,uBAAuB,OAAO,GAChC,OAAO,gBACL,oBAAC,eAAD;EAAe,MAAM,QAAQ;EAAM,QAAQ,QAAQ;CAAS,CAAA,IAC1D;CAGN,IAAI,QAAQ,SAAS,UACnB,OAAO,gBAAgB,oBAAC,eAAD,EAAwB,QAAU,CAAA,IAAI;CAa/D,OACE,qBAAA,YAAA,EAAA,UAAA,CAX2B,wBAAwB;EACnD;EACA,gBAAgB,uBAAuB;EACvC;EACA;EACA;EACA,iBAAiB,qBAAqB,YAAY,qBAAqB,KAAK,KAAA;EAC5E;CACF,CAIK,KACC,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,yBAAD,EAAyB,aAAa,mBAAqB,CAAA;CACxD,CAAA,GAEP,oBAAC,SAAD;EACkC;EAChC,oBAAoB,YAAY,SAAS;EACX;EAC9B,aAAa,6BAA6B,QAAQ,OAAO,CAAC;EAC9C;EACZ,aAAa,CAAC,mBAAmB,QAAQ,OAAO,EAAE;EAClC;EAChB,gBAAgB;EACP;EACT,SAAS;EACO;EACJ;EACS;EACrB,QAAQ,wBAAwB,QAAQ,OAAO,CAAC;EACpC;EACO;EACP;EACG;EACH;CACb,CAAA,CACD,EAAA,CAAA;AAEN;;;AC/LA,IAAa,gCAAgC,cAE3C,KAAA,CAAS;;;;AAKX,IAAa,yCAAyC,EACpD,UACA,YAIA,oBAAC,8BAA8B,UAA/B;CACS;CAEN;AACqC,CAAA;;;ACiI1C,SAAS,mCAAmC,GAAe;CACzD,IACE,EAAE,YAAY,mEACd,EAAE,YAAY,sCAEd,EAAE,yBAAyB;AAE/B;AAEA,SAAS,wCAAwC;CAC/C,gBAAgB;EACd,OAAO,iBAAiB,SAAS,kCAAkC;EACnE,aAAa;GACX,OAAO,oBAAoB,SAAS,kCAAkC;EACxE;CACF,GAAG,CAAC,CAAC;AACP;AAEA,SAAS,mBAAmB,SAAsB;CAChD,OAAO,QAAQ,sBAAsB,EAAE;AACzC;AAEA,SAAS,iBAAiB,UAA6B,IAAY;CACjE,OAAO,SAAS,WAAW,YAAY,QAAQ,OAAO,EAAE;AAC1D;AAEA,SAAS,iCACP,UACA,sBACA;CACA,IAAI,sBAAsB;EACxB,MAAM,QAAQ,iBAAiB,UAAU,oBAAoB;EAC7D,IAAI,UAAU,IACZ,OAAO;GAAE,OAAO;GAAU;EAAM;CAEpC;CACA,OAAO,SAAS,SAAS;AAC3B;AAEA,IAAM,qCACJ,UACG;CACH,MAAM,EACJ,gCACA,0BAA0B,CAAC,GAC3B,SACA,sBACA,8BACA,uBACA,mBACA,uBAAuB,MACvB,YACA,aACA,cACA,MACA,sBAAsB,OACtB,0BAA0B,OAC1B,sBACA,qBACA,aACA,UACA,eACA,+BACA,SAAS,6BACT,gBACA,eAAA,IACA,UACA,YAEA,WAAW,GACX,qBACA,YACA,oBAAoB,OACpB,wBACA,uBACA,+BAA+B,OAC/B,uBAAuB,OACvB,oBAAoB,OACpB,YACA,8BACA,eACA,8BAA8B,UAC9B,oBACA,QACA,eACE;CAEJ,MAAM,EAAE,YAAY,6BAA6B,GAAG,4BAClD;CAIF,sCAAsC;CAEtC,MAAM,EACJ,eAAA,kBAAgB,eAChB,qBAAA,wBAAsB,qBACtB,sBAAA,yBAAuB,sBACvB,gBAAgB,gBAChB,wBAAA,2BAAyB,wBACzB,kBAAA,qBAAmB,kBACnB,6BAAA,gCAA8B,6BAC9B,iBACA,4BAAA,+BAA6B,4BAC7B,yBAAA,4BAA0B,yBAC1B,gBAAgB,gCAAgC,cAC9C,oBAAoB,wBAAwB;CAChD,MAAM,qBAAqB,+BAA+B;CAE1D,MAAM,EAAE,QAAQ,kBAAkB,eAAe,wBAAwB;CAEzE,MAAM,uCADuB,2BACgB,IACzC,SACA;CACJ,MAAM,qBAAqB,sBAAsB;CAEjD,MAAM,WAAW,OAAuB,IAAI;CAE5C,MAAM,WAAW,cAAc,QAAQ,WAAW,GAAG,CAAC,OAAO,CAAC;CAE9D,MAAM,EAAE,MAAM,gCAAgC,yCAC5C,yCAAyC;EACvC,UAAU,sBAAsB;EAChC,YAAY,CAAC,CAAC;EACd,aAAa,sBAAsB,mBAAmB;CACxD,CAAC;CAEH,MAAM,EAAE,qBAAqB,2BAC3B,gBAAgB,oBAAoB;CAEtC,MAAM,oBAAoB,cAAc;EACtC,IAAI,OAAO,aAAa,aACtB,OAAO,CAAC;EAGV,IACE,wBACA,CAAC,uBACD,2BACA,CAAC,sBAED,OAAO;EAGT,OAAO,gBAAgB;GACrB,qBAAqB,CAAC;GACtB;GACA;GACA;GACA;GACA;GACA;GACA,QAAQ,OAAO,UAAU;EAC3B,CAAC;CAEH,GAAG;EACD;EACA;EACA;EACA;EACA;EACA,UAAU;EACV,OAAO;CACT,CAAC;;;;;;;CAQD,MAAM,+BAA+B,OAEnC,IAAI;CAEN,MAAM,iBAAiB,kBAAkB;EAAE;EAAU,WAAW,OAAO,MAAM;CAAG,CAAC;CAGjF,MAAM,0BAA0B,gBAAgB;EAC9C;EACA;EACA,UAAU,YAAY,CAAC;EACvB;CACF,CAAC;CAED,MAAM,+BAA+B,qBAAqB;EACxD;EACA;EACA,UAAU,YAAY,CAAC;EACvB;CACF,CAAC;CAED,MAAM,wBAAwB,cACtB,gBAAgB,iBAAiB,GACvC,CAAC,iBAAiB,CACpB;CAEA,MAAM,gBAAgB,eAAe;CACrC,MAAM,qBAAqB,cAEvB,kBAAkB,QAAoC,KAAK,SAAS,MAAM;EACxE,MAAM,QAAQ,cACZ,SACA,kBAAkB,IAAI,IACtB,kBAAkB,IAAI,IACtB,CAAC,mBACD,6BACF;EACA,IAAI,SAAS,QAAQ,IAAI,IAAI,QAAQ,MAAM;EAC3C,OAAO;CACT,GAAG,CAAC,CAAC,GAGP;EACE;EACA,kBAAkB;EAClB;EACA;CACF,CACF;CAEA,MAAM,EACJ,UACA,+BACA,yBACA,kCACA,+BACE,0BAA0B,mBAAmB,OAAO,QAAQ,YAAY;CAE5E,YAAY;EACV;EACA,qBAAqB,CAAC,CAAC;EACvB,iBAAiB,CAAC,CAAC,sBAAsB;CAC3C,CAAC;CAED,MAAM,iBAAiB,YAAY,YAAY;EAC7C,IAAI,cAAc;GAChB,MAAM,oBAAoB;GAC1B;EACF;EAEA,IAAI,SAAS,SACX,SAAS,QAAQ,cAAc,kBAAkB,SAAS,CAAC;EAG7D,2BAA2B,KAAK;CAElC,GAAG;EACD;EACA;EACA;EAEA,kBAAkB;EAClB;EACA;CACF,CAAC;CAED,8BAA8B;EAC5B;EACA;EACA;CACF,CAAC;CAED,MAAM,oBAAoB,0BACxB,mBACA,CAAC,oBACH;CAEA,MAAM,EAAE,kBAAkB,iBAAiB,EAAE,SAAS,CAAC;CAEvD,MAAM,4BAA4B,6BAChC,mBACA,OAAO,MACT;CAEA,gCAAgC;EAC9B,gBAAgB,QAAQ;EACxB;EACA,WAAW,OAAO;EAClB;CACF,CAAC;CAED,MAAM,sBAAsB,cAExB,yBACE,CACE,uCACC,aAAa,6BAA6B,UAAU,QAAQ,CAC/D,GACA,iBACF,GACF,CAAC,mBAAmB,oCAAoC,CAC1D;CACA,MAAM,gBAAgB,eAAwB;EAC5C,IAAI,gBAAgB,oBAClB,OAAO;EAGT,IAAI,0BAA0B,GAC5B,OAAO,aAAa,uCAAuC;EAG7D,OAAO,aAAa,uCAAuC;CAC7D;CAEA,MAAM,iBAAiB,aACpB,OAAO,GAAG,EAAE,mBAAmB,wBAC9B,kBAAkB,mBAAmB,OAAO,iBAAiB,GAAG,IAClE,CAAC,CACH;CAEA,MAAM,uBAAuB,eAAwB;EACnD,SAAS,UAAU;EACnB,iCAAiC,UAAU;EAE3C,IAAI,YAAY;GACd,gBAAgB,YAAY;GAC5B,6BAA6B,KAAK;EACpC;CACF;CACA,MAAM,oBAAoB,YAAqB;EAC7C,IAAI,SACF,WAAW,YAAY;CAE3B;CAEA,gBAAgB;EACd,IAAI;EACJ,IAAI,sBAAsB;GACxB,MAAM,QAAQ,iBAAiB,mBAAmB,oBAAoB;GACtE,IAAI,UAAU,IACZ,gBAAgB,iBAAiB;IAC/B,SAAS,SAAS,cAAc;KAAE,OAAO;KAAU;IAAM,CAAC;GAC5D,GAAG,CAAC;EAER;EACA,aAAa;GACX,aAAa,aAAa;EAC5B;CACF,GAAG,CAAC,sBAAsB,iBAAiB,CAAC;CAE5C,MAAM,KAAK,YAAY;CAEvB,IAAI,CAAC,mBAAmB,OAAO;CAE/B,MAAM,kBAAkB,aACpB,kDAAkD,OAClD,2CAA2C;CAE/C,OACE,oBAAC,uCAAD;EAAuC,OAAO,EAAE,eAAe;YAC7D,qBAAC,gCAAD,EAAA,UAAA,CACE,qBAAC,wBAAD,EAAA,UAAA,CACE,qBAAC,uBAAD;GAAuB,IAAI;aAA3B,CACG,CAAC,cAAc,kCACd,oBAAC,8BAAD,EACE,aAAa,sBAAsB,gBACpC,CAAA,GAEH,qBAAC,OAAD;IACE,WACE,eAAe,0BAA0B;cAF7C;KAKE,oBAAC,uBAAD;MACwB;MACtB,kBAAkB;MACC;KACpB,CAAA;KACD,oBAAC,UAAD;MACuB;MACrB,mBAAmB;MACD;MAClB,gBAAgB;MAChB,WAAU;MACV,YAAY;OACV;OACA,QAAA;OACA;OACA,GAAI,mBAAmB,EACrB,cACE,gCACE,oBAAC,iBAAD;QACiC;QACf;QACJ;OACb,CAAA,IACC,KACR;OACA,GAAG;MACL;MACgB;MAChB,SAAS;OACP;OACA;OACA;OACA;OACA,eAAA;OACA,sBAAsB,sBAAsB;OAC5C;OACA;OACA;OACA,cAAc,sBAAsB;OACpC,mBAAmB,sBAAsB;OACzC;OACA;OACA,SAAS;OACT;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA;OACA,oBAAoB,sBAAsB;OAC1C,yBAAA;OACA,aAAa;MACf;MACA,gBAAgB,wBAAwB,iBAAiB;MAC3C;MACd,oBAAoB;OAAE,QAAQ;OAAK,KAAK;MAAE;MAC1C,yBAAyB,iCACvB,mBACA,oBACF;MACA,aAAa;MACb,UAAU;MACV,eAAe;MAEL;MACV,KAAK;MACL,OAAO,EAAE,WAAW,SAAS;MAC7B,YAAY,kBAAkB;MAC9B,GAAI;MACJ,GAAK,wBAAwB,EAAE,YAAY,sBAAsB,IAAI,CAAC;MACtE,GAAK,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;KACnD,GARM,aAQN;KACD,oBAAC,0BAAD;MACE,iBAAiB,sBAAsB;MACvC,kBAAkB,2BAA2B;KAC9C,CAAA;KACD,oBAAC,+BAAD;MACiC;MAC/B,yBAAyB;MACzB,SAAS;MACG;KACb,CAAA;IACE;KACgB;MACvB,oBAAC,oBAAD,EAAkB,OAAO,mBAAqB,CAAA,CAC1B,EAAA,CAAA,GACrB,uBAAuB,oBAAC,uBAAD,EAAqB,SAAS,oBAAsB,CAAA,CAC9C,EAAA,CAAA;CACK,CAAA;AAE3C;;;;;AAgHA,SAAgB,uBAAuB,OAAoC;CACzE,MAAM,EAAE,qBAAqB,UAAU,kBAAkB,wBACvD,wBACF;CACA,MAAM,EACJ,SACA,sBACA,SACA,cACA,sBACA,aACA,kBACA,UAAU,iBACV,eACA,MACA,oBACA,WACE,uBAAuB,wBAAwB;CAEnD,MAAM,WAAW,MAAM,YAAY;CAEnC,OACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,mCAAD;EACW;EACT,sBAAsB,MAAM,wBAAwB;EACpD,SAAS,CAAC,CAAC;EACX,cAAc,CAAC,CAAC;EACM;EACD;EACrB,aAAa,CAAC,CAAC;EACf,kBAAkB,CAAC,CAAC;EACV;EACK;EACL;EACK;EACT;EACc;EACZ;EACR,GAAI;CACL,CAAA,EACa,CAAA;AAEpB;;;ACnwBA,IAAa,gBAAgB,KAAa,MAAc;CACtD,MAAM,OAAO,IAAI,WAAW,CAAC;CAE7B,IAAI,OAAO,MAAM,IAAI,GAAG,OAAO;CAE/B,IAAI,OAAO,SAAU,OAAO,OAAQ,OAAO,IAAI,OAAO,CAAC;CAEvD,IAAI,SAAU,QAAQ,QAAQ,OAAQ;EACpC,IAAI,IAAI,UAAU,IAAI,GACpB,MAAM;EAGR,MAAM,OAAO,IAAI,WAAW,IAAI,CAAC;EAEjC,IAAI,QAAS,QAAQ,OAAO,OAC1B,MAAM;EAGR,OAAO,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC;CACzC;CAEA,IAAI,MAAM,GACR,MAAM;CAGR,MAAM,OAAO,IAAI,WAAW,IAAI,CAAC;CAEjC,IAAI,QAAS,QAAQ,OAAO,OAC1B,MAAM;CAGR,OAAO;AACT;;;AC5BA,IAAM,mCAAiC,WAAkC,EACvE,SAAS,MAAM,QACjB;AAMA,IAAa,8BAA8B,qBAAuC;CAChF,MAAM,CAAC,mBAAmB,wBAAwB,SAAmB,CAAC,CAAC;CACvE,MAAM,EAAE,YAAY,cAClB,iBAAiB,OACjB,+BACF;CAEA,gBAAgB;EACd,MAAM,gBAAgB,QAAQ,KAAK,WACjC,OAAO,MAAM,uBACV,WAAW,EAAE,WAAW,MAAM,UAAU,KACxC,EAAE,gBAAgB;GACjB,sBAAsB,SAAS;IAC7B,IAAI,WAAW,OAAO,KAAK,OAAO,OAAO,IAAI;IAC7C,OAAO,KAAK,QAAQ,SAAS,SAAS,OAAO,IAAI;GACnD,CAAC;EACH,CACF,CACF;EAEA,aAAa;GACX,cAAc,SAAS,gBAAgB,YAAY,CAAC;EACtD;CACF,GAAG,CAAC,OAAO,CAAC;CACZ,OAAO;AACT;;;AClCA,IAAa,kCAAkC,gBAA6B;CAC1E,MAAM,EAAE,WAAW,eAAe,gCAAgC;CAElE,gBAAgB;EACd,MAAM,oBAAoB;GACxB,IAAI,aACF,YAAY;EAEhB;EAEA,OAAO,GAAG,wBAAwB,WAAW;EAE7C,aAAa;GACX,OAAO,IAAI,wBAAwB,WAAW;EAChD;CACF,GAAG,CAAC,QAAQ,WAAW,CAAC;AAC1B;;;ACAA,IAAM,kDAAkD;AACxD,IAAM,sDAAsD;;;;;AA8B5D,IAAM,wCACJ,SAEA,KAAK,KAAK,EAAE,YAAY,GAAG,aAAa,GACrC,QAAQ,UACX,EAAE;AAEJ,IAAa,wBACX,QACA,SACA,MACA,SACA,sBAKA,6BAAqC,iDACrC,wBACG;CACH,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EACJ,oBAAoB,EAAE,OAAO,UAAU,yBACrC,eAAe,sBAAsB;CACzC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,CAAC,UAAU,eAAe,SAAyB,CAAC,CAAC;CAC3D,MAAM,CAAC,aAAa,kBAAkB,SAAS,IAAI;CAKnD,MAAM,CAAC,iBAAiB,sBAAsB,SAC5C,KAAA,CACF;CACA,MAAM,CAAC,cAAc,mBAAmB,SAAkC,KAAA,CAAS;CACnF,MAAM,wBAAwB,OAA2B,KAAA,CAAS;CAElE,MAAM,2BACJ,6BAA6B,sDACzB,sDACC,8BAA8B;CAErC,MAAM,eAAe,cAAc,KAAK,UAAU,OAAO,GAAG,CAAC,OAAO,CAAC;CACrE,MAAM,aAAa,cAAc,KAAK,UAAU,IAAI,GAAG,CAAC,IAAI,CAAC;CAG7D,MAAM,gBAAgB,OAAO,YAAY,gBAAgB;EACvD,SAAS,IAAI;EACb,MAAM,SAAS,cAAc,WAAW,IAAI,SAAS;EACrD,MAAM,cAAc,WAAW;EAE/B,IAAI,cAAc,UAChB,YAAY,CAAC,CAAC;EAEhB,mBAAmB,SAA6B;EAEhD,IAAI;GACF,IAAI,qBAAqB;IACvB,MAAM,oBAAoB;KACxB,iBAAiB;KACN;KACX;KACA;IACF,CAAC;IAGD,mBAAmB,KAAA,CAAS;IAC5B,gBAAgB,KAAA,CAAS;GAC3B,OAAO;IACL,MAAM,aAAa;KACjB;KACA,GAAG;IACL;IAEA,MAAM,uBAAuB,MAAM,OAAO,cACxC,SACA,QAAQ,CAAC,GACT,YACA,EAAE,cAAc,KAAK,CACvB;IAEA,MAAM,cACJ,cAAc,WACV,qBAAqB,WACrB,OAAO,CAAC,GAAG,UAAU,GAAG,qBAAqB,QAAQ,GAAG,KAAK;IAEnE,YAAY,WAAW;IACvB,eAAe,qBAAqB,SAAS,WAAW,WAAW,SAAS,EAAE;IAM9E,MAAM,mBAAmB,qBAAqB;IAC9C,MAAM,sBAAsB,mBACvB,iBAAiB,SAClB,KAAA;IACJ,MAAM,mBAAmB,kBAAkB,OACvC,qCAAqC,iBAAiB,IAAI,IAC1D,KAAA;IAEJ,mBAAmB,mBAAmB;IACtC,gBAAgB,gBAAgB;IAGhC,IAAI,CAAC,UAAU,sBACb,qBAAqB,aAAa,aAAa;KAC7C,SAAS,uBAAuB;KAChC,MAAM,oBAAoB;IAC5B,CAAC;GAEL;EACF,SAAS,OAAO;GACd,QAAQ,KAAK,KAAK;GAClB,gBAAgB;IACd,SAAS;IACT,OAAO,iBAAiB,QAAQ,QAAQ,KAAA;IACxC,SAAS,cACL,EAAE,yBAAyB,IAC3B,EAAE,8BAA8B;IACpC,UAAU;IACV,cAAc,CAAC,cAAc;IAC7B,MAAM,cACF,iCACA;GACN,CAAC;GAED,IAAI,aACF,SAAS,KAA4C;EAEzD;EAEA,mBAAmB,IAAI;CACzB;CAEA,MAAM,kBAAkB,kBAAkB;EACxC,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,kBAAkB,CAAC,sBAAsB;EAC/C,MAAM,iCAAiC,sBAAsB,UACzD,MAAM,sBAAsB,UAC5B;EAEJ,IACE,CAAC,mBACD,iCAAiC,4BACjC,CAAC,OAED;EAGF,sBAAsB,UAAU;EAChC,cAAc,QAAQ;CACxB,GAAG;EAAC;EAAO;EAAe;CAAwB,CAAC;CAEnD,MAAM,qBAAqB,cAAc;CAEzC,gBAAgB;EACd,IAAI,OAAO,yBAAyB;EACpC,MAAM,EAAE,gBAAgB,OAAO,GAAG,wBAAwB,eAAe;EAEzE,aAAa;GACX,YAAY;EACd;CACF,GAAG,CAAC,QAAQ,eAAe,CAAC;CAE5B,gBAAgB;EACd,cAAc,QAAQ;CAExB,GAAG,CAAC,cAAc,UAAU,CAAC;CAS7B,OAAO;EACL;EACA,kBALuB,mBAAmB;EAM1C,eALoB,gBAAgB;EAMpC;EACA;EACA;CACF;AACF;;;;;;;;ACnOA,SAAgB,2BAA2B,EAAE,YAAqC;CAChF,IAAI,yBAAwC;CAE5C,KAAK,MAAM,WAAW,UAAU;EAC9B,IAAI,CAAC,gBAAgB,OAAO,GAAG;EAE/B,IAAI,OAAO,2BAA2B,UACpC;OAEA,yBAAyB;CAE7B;CAEA,OAAO;AACT;AAaA,IAAa,sBAAsB,EACjC,UACA,eACA,kCACA,WAC8B;CAE9B,MAAM,qBACJ,oCACA,SAAS,WAAW,YAAY,QAAQ,QAAQ,cAAc,GAAG;CAEnE,MAAM,gCAAgC,sBAAsB;CAC5D,MAAM,+BAA+B,uBAAuB;CAK5D,MAAM,yBAAyB,6BAA6B,IAAI;CAChE,MAAM,wBAAwB,gBAAgB,aAAa;CAE3D,IAAI,gCAAiC,0BAA0B,uBAC7D,OAAO;CAGT,MAAM,cAAc,CAAC,GAAG,QAAQ;CAGhC,IAAI,+BACF,YAAY,OAAO,oBAAoB,CAAC;CAK1C,IAAI,yBAAwC;CAC5C,IAAI,wBACF,yBAAyB,2BAA2B,EAAE,UAAU,YAAY,CAAC;CAI/E,YAAY,OACV,OAAO,2BAA2B,WAAW,yBAAyB,IAAI,GAC1E,GACA,aACF;CAEA,OAAO;AACT;;;;;;AAOA,IAAa,gCAAgC,SAAmC;CAC9E,MAAM,QAAQ,iBAAiB;EAAE,SAAS;EAAG;EAAM,WAAW;CAAY,CAAC;CAE3E,IAAI,OAAO,UAAU,UAAU,OAAO;CAEtC,OAAO,KAAK,IAAI,KAAK,MAAM;AAC7B;AAEA,IAAa,oBAAoB,EAC/B,SACA,MACA,gBAKI;CACJ,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,SAAiC;CAErC,IAAI,MAAM,QAAQ,IAAI,GACpB,SAAS,KAAK,YAAY;MACrB;EACL,IAAI,QAAQ;EACZ,KAAK,MAAM,OAAO,MAAM;GACtB,IAAI,UAAU,SAAS;IACrB;IACA;GACF;GAEA,IAAI,QAAQ,WACV,OAAO;GAGT,SAAS;GAET;EACF;CACF;CAEA,OAAO,SAAS,cAAc;AAChC;;;;AAKA,IAAa,kCAAkC,YAAyC;CACtF,IAAI,CAAC,SAAS,OAAO;CAErB,OAAO,OAAO,QAAQ,aAAa;AACrC;;;;AAKA,IAAa,mBAAmB,YAAqB;CACnD,IAAI,CAAC,SAAS,OAAO;CAIrB,OAAO,OAFY,QAAQ,MAAM,WAER,cAAc;AACzC;;;;AAKA,IAAa,qBAAqB,YAAqB;CACrD,IAAI,CAAC,SAAS,OAAO;CAIrB,OAAO,OAFY,QAAQ,MAAM,WAER,gBAAgB;AAC3C;;;AC5FA,IAAM,UAAU,EACd,eACA,OACA,kBACyC;CACzC,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;CAGzC,aAAa,aAAa;EACxB,MAAM,eAAe,SAAS,WAAW,YAAY,QAAQ,QAAQ,MAAM,GAAG;EAE9E,IAAI,eAAe,GAAG,OAAO;EAE7B,SAAS,OAAO,cAAc,CAAC;EAE/B,OAAO,CAAC,GAAG,QAAQ;CACrB,CAAC;AACH;AAEA,IAAa,oCAAoC;CAC/C,MAAM,EAAE,WAAW,eAAe;CAElC,MAAM,mBAAmB,aACtB,EACC,wCACA,eACA,OACA,SACA,kBACA,aACA,WACgC;EAChC,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;EAGzC,MAAM,cAAc,MAAM;EAC1B,MAAM,YAAY,MAAM;EAExB,IAAI,CAAC,eAAe,CAAC,WAAW;EAEhC,aAAa,oBAAoB;GAC/B,MAAM,gBAAgB,OAAO,QAAQ,aAAa,SAAS;GAC3D,MAAM,qBAAqB,gBAAgB,QAAQ,aAAa;GAChE,MAAM,gCAAgC,sBAAsB;GAE5D,MAAM,wBAAwB,gBAAgB,aAAa;GAC3D,MAAM,0BAA0B,kBAAkB,aAAa;GAE/D,MAAM,2BAA2B,+BAA+B,OAAO;GACvE,MAAM,yBAAyB,6BAA6B,IAAI;GAEhE,IAEG,4BAA4B,2BAA2B,CAAC,QAAQ,YAEhE,4BAA4B,CAAC,2BAA2B,QAAQ,YAEhE,0BAA0B,yBAE3B,oBAEC,CAAC,iCAAiC,CAAC,wCAEpC,OAAO;GAGT,OAAO,mBAAmB;IACxB,UAAU;IACV,eAAe;IACf,kCAAkC;IAClC;GACF,CAAC;EACH,CAAC;CACH,GACA,CAAC,MAAM,CACT;CAEA,MAAM,+BAA+B,YACnC,OAAO,EACL,wCACA,eACA,OACA,SACA,aACA,WAC4C;EAC5C,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;EAGzC,IAAI,CAAC,MAAM,SACT;EAGF,MAAM,UAAU,MAAM,WAAW;GAC/B;GACA,IAAI,MAAM,QAAQ;GAClB,MAAM,MAAM,QAAQ;EACtB,CAAC;EAED,MAAM,2BAA2B,+BAA+B,OAAO;EACvE,IAAI,kBAAkB,OAAO,KAAK,4BAA4B,CAAC,QAAQ,UACrE;EAGF,IAAI,CAAC,wCACH;EAGF,aAAa,aACX,mBAAmB;GACjB;GACA,eAAe;GACf;EACF,CAAC,CACH;CACF,GACA,CAAC,MAAM,CACT;CAEA,MAAM,mCAAmC,YACvC,OAAO,EACL,wCACA,eACA,OACA,aACA,WACgD;EAChD,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;EAGzC,IAAI,CAAC,MAAM,WAAW,CAAC,wCACrB;EAGF,MAAM,UAAU,MAAM,WAAW;GAC/B;GACA,IAAI,MAAM,QAAQ;GAClB,SAAS,MAAM,QAAQ,SAAS,QAC7B,YAAY,EAAE,MAAM,cAAc;IACjC,MAAM,SAAS,WAAW,MAAM;IAEhC,IAAI,QAAQ,WAAW,KAAK,MAAM;IAElC,OAAO;GACT,GACA,CAAC,CACH;GACA,MAAM,MAAM,QAAQ;EACtB,CAAC;EAGD,aAAa,aACX,mBAAmB;GACjB;GACA,eAAe;GACf;EACF,CAAC,CACH;CACF,GACA,CAAC,MAAM,CACT;CAEA,MAAM,uCAAuC,aAC1C,EACC,eACA,OACA,kBACoD;EACpD,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;EAGzC,aAAa,aACX,SAAS,QAAQ,YAAY,QAAQ,QAAQ,MAAM,SAAS,GAAG,CACjE;CACF,GACA,CAAC,CACH;CAEA,MAAM,sBAAsB,aACzB,EACC,OACA,SACA,kBACA,aACA,WACmC;EACnC,IACE,CAAC,MAAM,QAAQ,QACf,MAAM,OAAO,KAAK,OAAO,OAAO,UAChC,CAAC,MAAM,cAEP;EAGF,MAAM,cAAc,MAAM;EAC1B,MAAM,YAAY,MAAM;EAExB,MAAM,yBAAyB,6BAA6B,IAAI;EAChE,MAAM,2BAA2B,+BAA+B,OAAO;EAGvE,IAAK,CAAC,0BAA0B,CAAC,4BAA6B,kBAC5D;EAGF,MAAM,eAAe,iBAAiB;GAAE,SAAS;GAAG;GAAM,WAAW;EAAY,CAAC;EAElF,aAAa,oBAAoB;GAC/B,MAAM,gBAAgB,OAAO,QAAQ,aAAa,SAAS;GAE3D,MAAM,qBAAqB,gBAAgB,QAAQ,aAAa;GAChE,MAAM,gCAAgC,sBAAsB;GAE5D,MAAM,0BAA0B,kBAAkB,aAAa;GAC/D,MAAM,wBAAwB,gBAAgB,aAAa;GAE3D,MAAM,cAAc,CAAC,GAAG,eAAe;GAEvC,IAAI,+BACF,YAAY,OAAO,oBAAoB,CAAC;GAI1C,IACG,4BAA4B,2BAA2B,CAAC,QAAQ,YAChE,4BAA4B,CAAC,2BAA2B,QAAQ,UAEjE,OAAO;GAGT,IAAI,yBAAwC;GAK5C,IAAI,iBAAiB,KAAM,iBAAiB,MAAM,CAAC,uBACjD,yBAAyB,2BAA2B,EAAE,UAAU,YAAY,CAAC;GAG/E,MAAM,wBACJ,OAAO,2BAA2B,WAAW,yBAAyB,IAAI;GAE5E,YAAY,OAAO,uBAAuB,GAAG,aAAa;GAE1D,OAAO;EACT,CAAC;CACH,GACA,CAAC,MAAM,CACT;CAEA,MAAM,uBAAuB,aAC1B,MAAsC,OAAO,CAAC,GAC/C,CAAC,CACH;CAEA,MAAM,sBAAsB,aACzB,MAAqC,OAAO,CAAC,GAC9C,CAAC,CACH;CAEA,MAAM,uBAAuB,YAC3B,OAAO,EACL,eACA,OACA,SACA,aACA,WACoC;EACpC,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;EAGzC,IAAI,CAAC,MAAM,cAAc,CAAC,MAAM,cAC9B;EAGF,MAAM,UAAU,MAAM,WAAW;GAC/B;GACA,IAAI,MAAM;GACV,MAAM,MAAM;EACd,CAAC;EAED,MAAM,2BAA2B,+BAA+B,OAAO;EACvE,IAAI,kBAAkB,OAAO,KAAK,4BAA4B,CAAC,QAAQ,UACrE;EAGF,aAAa,aACX,mBAAmB;GACjB;GACA,eAAe;GACf;EACF,CAAC,CACH;CACF,GACA,CAAC,MAAM,CACT;CAEA,MAAM,yBAAyB,aAC5B,EAAE,eAAe,OAAO,kBAAoD;EAC3E,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;EAIzC,aAAa,aAAa,CAAC,GAAG,QAAQ,CAAC;CAIzC,GACA,CAAC,CACH;CAEA,MAAM,uBAAuB,aAC1B,EAAE,eAAe,OAAO,kBAAkD;EACzE,IAAI,OAAO,kBAAkB,YAC3B,OAAO,cAAc,aAAa,KAAK;EAGzC,aAAa,aAAa;GACxB,MAAM,eAAe,SAAS,WAC3B,YAAY,QAAQ,QAAQ,MAAM,SAAS,GAC9C;GAEA,IAAI,eAAe,MAAM,MAAM,SAAS;IACtC,MAAM,cAAc;IACpB,YAAY,cAAc,OAAO;KAC/B,GAAG,MAAM;KACT,QAAQ,MAAM,SAAS,UAAU,YAAY,cAAc,MAAM;KACjE,kBACE,MAAM,SAAS,oBACf,YAAY,cAAc,MAAM;IACpC;IAEA,OAAO,CAAC,GAAG,WAAW;GACxB;GAEA,OAAO;EACT,CAAC;CAKH,GACA,CAAC,CACH;CAEA,MAAM,4BAA4B,aAC/B,EAAE,OAAO,kBAAuD;EAC/D,aAAa,aAAa;GAaxB,OAZoB,SAAS,KAAK,YAAY;IAC5C,IAAI,CAAC,MAAM,MAAM,MAAM,CAAC,QAAQ,MAAM,QAAQ,MAAM,KAAK,KACvD,OAAO;IAIT,MAAM,aAAa;IACnB,WAAW,MAAM,QAAQ,MAAM,KAAK,IAAI,OAAO,MAAM;IAErD,OAAO;GACT,CAEO;EACT,CAAC;CACH,GACA,CAAC,CACH;CAEA,OAAO,eACE;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF;AACF;AA4BA,IAAa,2BAA2B,EACtC,wCACA,8BACA,SACA,kBACA,kBACA,kBACA,iBACA,oBACA,kBACA,kBACA,cACA,qBACA,sBACA,aACA,WACgD;CAChD,MAAM,WAAW,4BAA4B;CAE7C,MAAM,mCAAmC,OAA2B,KAAA,CAAS;CAE7E,MAAM,kCAAkC,OAA2B,KAAA,CAAS;CAE5E,gCAAgC,WAAW,UAAiB;EAC1D,+BAA+B;GAAE;GAAU;GAAO;EAAY,CAAC;CACjE;CAEA,iCAAiC,WAAW,UAAiB;EAC3D,QAAQ,MAAM,MAAd;GACE,KAAK;IACH,SAAS,iBAAiB;KACxB;KACA,eAAe;KACf;KACA;KACA;KACA;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,6BAA6B;KACpC;KACA,eAAe;KACf;KACA;KACA;KACA;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,iCAAiC;KACxC;KACA,eAAe;KACf;KACA;KACA;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,qCAAqC;KAC5C,eAAe;KACf;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,qBAAqB;KAC5B,eAAe;KACf;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,oBAAoB;KAC3B,eAAe;KACf;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,qBAAqB;KAC5B,eAAe;KACf;KACA;KACA;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,uBAAuB;KAC9B,eAAe;KACf;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,qBAAqB;KAC5B,eAAe;KACf;KACA;IACF,CAAC;IACD;GACF,KAAK;IACH,SAAS,0BAA0B;KAAE;KAAO;IAAY,CAAC;IACzD;GACF,KAAK;IACH,SAAS,oBAAoB;KAC3B;KACA;KACA;KACA;KACA;IACF,CAAC;IACD;GACF,SACE;EACJ;CACF;CAEA,MAAM,YAAY,aAAa,MAAa;EAC1C,iCAAiC,UAAU,CAAC;CAC9C,GAAG,CAAC,CAAC;CASL,OAAO;EACL,eARe,cAAc;GAC7B,IAAI,CAAC,8BAA8B,OAAO;GAC1C,QAAQ,MAAa;IACnB,gCAAgC,UAAU,CAAC;GAC7C;EACF,GAAG,CAAC,4BAA4B,CAGf;EACf,gBAAgB;CAClB;AACF;AAEA,IAAa,uBAAuB,YAAgC;CAClE,MAAM,EAAE,WAAW,eAAe;CAElC,gBAAgB;EAGd,OAFqB,OAAO,GAAG,OAAO,OAE/B,EAAa;CACtB,GAAG,CAAC,QAAQ,OAAO,CAAC;AACtB;;;;;;AC/mBA,IAAa,iBAAiB,UAAiD;CAC7E,MAAM,EAAE,UAAU,QAAQ,MAAM,UAAU,UAAU;CACpD,MAAM,EAAE,wBAAwB,eAAe,mBAAmB,oBAChE,oBAAoB,eAAe;CACrC,MAAM,EAAE,MAAM,sBAAsB,eAAe;CAEnD,IAAI,OACF,OAAO,oBAAC,uBAAD,EAA8B,MAAQ,CAAA;CAG/C,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,OAAD;GACE,cAAY,EAAE,mBAAmB;GACjC,WAAU;GACV,MAAK;aAEJ,UAAU,oBAAC,kBAAD,CAAmB,CAAA,IAAI;EAC/B,CAAA;CACF,CAAA;AAET;;;AC5BA,IAAa,gBAAgB,cAA8C,KAAA,CAAS;;;;AAKpF,IAAa,yBAAyB,EACpC,UACA,YAIA,oBAAC,cAAc,UAAf;CAA+B;CAC5B;AACqB,CAAA;AAG1B,IAAa,yBAAyB;CAEpC,OADqB,WAAW,aACzB;AACT;;;ACtBA,IAAM,mCAAiC,eAAsC;CAC3E,UAAU,UAAU;CACpB,aAAa,UAAU;AACzB;AAEA,IAAa,kBAAkB;CAC7B,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,UACA,uBACA,2BACA,aACA,qBACE,iBAAiB;CACrB,MAAM,oBAAoB,2BAA2B,gBAAgB;CACrE,MAAM,iBAAiB,MAAM,OAAiC,IAAI;CAClE,MAAM,gBAAgB,YAAY;CAElC,MAAM,CAAC,OAAO,YAAY,SAAkC,IAAI;CAChE,MAAM,EAAE,UAAU,gBAAgB,cAChC,iBAAiB,OACjB,+BACF;CAEA,gBAAgB;EACd,IAAI,CAAC,OAAO;EACZ,MAAM,iBAAiB,UAAyB;GAC9C,IAAI,MAAM,QAAQ,UAAU;IAC1B,MAAM,KAAK;IACX,iBAAiB,KAAK;GACxB;EACF;EAEA,SAAS,iBAAiB,WAAW,aAAa;EAClD,aAAa;GACX,SAAS,oBAAoB,WAAW,aAAa;EACvD;CACF,GAAG,CAAC,kBAAkB,KAAK,CAAC;CAE5B,OACE,qBAAC,OAAD;EAAK,WAAU;EAAuB,eAAY;EAAa,MAAK;YAApE,CACE,qBAAC,OAAD;GACE,WAAW,KAAK,uCAAuC,EACrD,+CAA+C,SACjD,CAAC;aAHH;IAKE,oBAAC,SAAD;KAAO,SAAS;eACd,oBAAC,gBAAD,EAAA,UAAiB,EAAE,QAAQ,EAAkB,CAAA;IACxC,CAAA;IACP,oBAAC,YAAD,CAAa,CAAA;IACb,oBAAC,SAAD;KACE,WAAU;KACV,eAAY;KACF;KACV,IAAI;KACJ,SAAS,EAAE,eAAe,oBAAoB;MAC5C,IACE,yBAEA,CAAC,cAAc,SAEf,CAAC,0BAA0B,SAAS,SAAS,aAAa,MAEzD,CAAC,eAAe,WAAW,kBAAkB,eAAe,UAE7D,iBAAiB,KAAK;KAE1B;KACA,WAAW,UAA+C;MACxD,IAAI,MAAM,OAAO,OACf,iBAAiB,OAAO,MAAM,OAAO,KAAK;WACrC,IAAI,CAAC,MAAM,OAAO,OACvB,iBAAiB,MAAM;KAE3B;KACA,SAAS,iBAAiB;KAC1B,aAAa,eAAe,EAAE,QAAQ;KACtC,KAAK;KACL,MAAK;KACL,OAAO;IACR,CAAA;IACA,eACC,oBAAC,QAAD;KACE,YAAW;KACX,cAAY,EAAE,mBAAmB;KACjC,UAAA;KACA,WAAU;KACV,eAAY;KACZ,UAAU,kBAAkB,SAAS;KACrC,eAAe;MACb,iBAAiB,MAAM;MACvB,OAAO,MAAM;KACf;KACA,KAAK;KACL,MAAK;KACL,SAAQ;eAER,oBAAC,aAAD,CAAc,CAAA;IACR,CAAA;GAEP;MACJ,YACC,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,kBAAkB;GAChC,WAAU;GACV,eAAY;GACZ,eAAe;IACb,OAAO,KAAK;IACZ,iBAAiB,KAAK;GACxB;GACA,MAAK;GACL,SAAQ;aAEP,EAAE,QAAQ;EACL,CAAA,CAEP;;AAET;;;AC/GA,IAAa,2BAA2B,EAAE,WAAyC;CACjF,MAAM,EAAE,qBAAqB,eAAe;CAC5C,MAAM,EAAE,gBAAgB,sBAAsB;CAO9C,OACE,oBAAC,iBAAD;EACE,SAAS;EACT,WAAU;EACA,UATG,kBAAkB;GACjC,iBAAiB,IAAI;GACrB,eAAe,aAAa,OAAO,CAAC,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;EAChE,GAAG;GAAC;GAAM;GAAkB;EAAW,CAMzB;CACX,CAAA;AAEL;AAMA,IAAa,2BAA2B,EACtC,WAC2C;CAC3C,MAAM,EACJ,SAAS,eACT,QACA,kBACA,qBACE,eAAe;CACnB,MAAM,EAAE,gBAAgB,sBAAsB;CAE9C,MAAM,UAAU,cAAc;EAC5B,MAAM,EAAE,SAAS,gBAAgB;EACjC,MAAM,OAAO,aAAa,QAAQ;EAClC,MAAM,KAAK,aAAa,MAAM;EAC9B,OAAO,OAAO,QAAQ,MAAM,EAAE;CAChC,GAAG,CAAC,QAAQ,IAAI,CAAC;CAEjB,MAAM,WAAW,YAAY,YAAY;EACvC,IAAI,CAAC,SAAS;EACd,MAAM,QAAQ,MAAM,qBAClB,KAAK,IACL,KAAA,GAAA,EAEF;EAEA,iBAAiB,eAAe,YAAY,EAAE,gBAAgB,KAAK,CAAC;EACpE,iBAAiB,OAAO;EACxB,eAAe,aAAa,OAAO,CAAC,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;CACnE,GAAG;EAAC;EAAS;EAAM;EAAkB;EAAkB;CAAW,CAAC;CAGnE,MAAM,0BAA0B,kBAAkB,KAAK,MAAO,CAAC,IAAI,CAAC;CAEpE,IAAI,CAAC,SAAS,OAAO;CAErB,OACE,oBAAC,iBAAD;EACE,QACE,QAAQ,QAAQ,eAAe,OAC/B,KAAK,OAAO,iBAAiB,eAAe,eAAe,EAAE,gBAAgB;EAEtE;EACT,WAAU;EACe;EACf;CACX,CAAA;AAEL;AAMA,IAAa,wBAAwB,EAAE,WAAsC;CAC3E,MAAM,EAAE,QAAQ,qBAAqB,eAAe;CACpD,MAAM,EAAE,gBAAgB,sBAAsB;CAC9C,MAAM,EAAE,+BAA+B,iBAAiB;CACxD,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,UAAU,kBAAkB;EAChC,MAAM,aAAa,OAAO,QAAQ,4BAA4B,EAC5D,SAAS,CAAC,OAAO,QAAkB,KAAK,EAAE,EAC5C,CAAC;EACD,WAAW,MAAM;EACjB,iBAAiB,UAAU;EAC3B,eAAe,aAAa,OAAO,CAAC,YAAY,GAAG,QAAQ,GAAG,KAAK,CAAC;CACtE,GAAG;EAAC;EAAQ;EAAM;EAAkB;EAAa;CAA0B,CAAC;CAE5E,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,UAAD;GACE,cAAY,EAAE,wCAAwC,EACpD,MAAM,KAAK,QAAQ,GACrB,CAAC;GACD,WAAU;GACV,eAAY;GACH;GACT,MAAK;aAPP,CASE,oBAAC,QAAD;IACE,UAAU,KAAK;IACf,UAAU,KAAK;IACf,MAAK;IACL,UAAU,KAAK,QAAQ,KAAK;GAC7B,CAAA,GACD,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eACZ,KAAK,QAAQ,KAAK,YAAY,KAAK;IACjC,CAAA,GACL,oBAAC,WAAD;KACE,aAAY;KACZ,WAAW,KAAK;IACjB,CAAA,CACE;KACC;;CACL,CAAA;AAET;AAKA,IAAa,2BAAuD;CAClE,UAAU;CACV,UAAU;CACV,OAAO;AACT;;;AC7IA,IAAa,6BAA6B,cAExC,KAAA,CAAS;;;;AAKX,IAAa,sCAAsC,EACjD,UACA,YAIA,oBAAC,2BAA2B,UAA5B;CACS;CAEN;AACkC,CAAA;AAGvC,IAAa,sCAAsC;CAEjD,OADqB,WAAW,0BACzB;AACT;;;AC3BA,IAAa,4CAA4C;CACvD,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,iBAAiB,8BAA8B;CACvD,OACE,oBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAEX,EAAE,2CAA2C,EAC5C,kBAAkB,aAAa,KACjC,CAAC;CACE,CAAA;AAET;;;ACTA,IAAM,+BAA6B,WAA8B;CAC/D,SAAS,MAAM;CACf,WAAW,MAAM;AACnB;AAEA,IAAa,qCAAqC;CAChD,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EACJ,qCAAA,wCAAsC,wCACpC,oBAAoB;CACxB,MAAM,EAAE,iBAAiB,8BAA8B;CACvD,MAAM,EAAE,SAAS,cAAc,cAC7B,aAAa,OACb,2BACF;CAEA,OACE,oBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAEX,YACC,oBAAC,uCAAD,CAAsC,CAAA,IACpC,CAAC,UACH,oBAAC,OAAD;GAAK,WAAU;aACZ,EAAE,oBAAoB;EACpB,CAAA,IACH;CACD,CAAA;AAET;;;AC1BA,IAAM,+BAA6B,eAAkC,EACnE,OAAO,UAAU,MACnB;AAQA,IAAa,0BAA0B,EACrC,qBAAqB,KACrB,sBAAsB,IACtB,oBAAoB,+BACa;CACjC,MAAM,EAAE,8BAAA,iCAA+B,iCACrC,oBAAoB;CAEtB,MAAM,EAAE,iBAAiB,8BAA8B;CACvD,MAAM,EAAE,UAAU,cAAc,aAAa,OAAO,2BAAyB;CAE7E,MAAM,mBAAmB,kBACvB,aAAa;CAGf,IAAI,CAAC,kBAAkB,OAAO;CAE9B,OACE,oBAAC,OAAD;EACE,WAAU;EACV,eAAY;YAEZ,qBAAC,yBAAD;GACE,oBAAoB;GACpB,0BAA0B,aAAa;GACvC,WAAW;aAHb,CAKG,OAAO,KAAK,MAAM,MACjB,oBAAC,kBAAD,EACQ,KAEP,GADM,wBAAwB,aAAa,KAAK,GAAG,GACnD,CACF,GACD,oBAAC,gCAAD,CAA+B,CAAA,CACR;;CACtB,CAAA;AAET;;;ACxDA,IAAa,iCAAiC;CAC5C,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,OAAD;EAAK,WAAU;YAAyC,EAAE,kBAAkB;CAAO,CAAA;AAEvF;;;ACRA,IAAa,kCAAkC;;;ACU/C,IAAM,+BAA6B,eAAkC;CACnE,WAAW,UAAU;CACrB,OAAO,UAAU;AACnB;AAIA,IAAa,uBAAuB,EAAE,mBAA6C;CACjF,MAAM,EACJ,wBAAA,2BAAyB,wBACzB,0BAAA,6BAA2B,0BAC3B,2BAAA,8BAA4B,8BAC1B,oBAAoB;CACxB,MAAM,EAAE,WAAW,UAAU,cAC3B,aAAa,OACb,2BACF;CAEA,IAAI,CAAC,SAAS,CAAC,WAAW,OAAO;CAEjC,OACE,oBAAC,oCAAD;EAAoC,OAAO,EAAE,aAAa;YACxD,qBAAC,OAAD;GACE,WAAU;GACV,eAAY;aAFd,CAIE,oBAAC,6BAAD,CAA4B,CAAA,GAC3B,OAAO,UAAU,YAChB,oBAAC,0BAAD,CAAyB,CAAA,IAEzB,oBAAC,4BAAD,CAA2B,CAAA,CAE1B;;CAC6B,CAAA;AAExC;;;ACpCA,IAAM,6BAA6B,eAAkC,EACnE,UAAU,UAAU,SACtB;AAMA,IAAM,4BAA4B,EAAE,aAA4C;CAC9E,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,qBAAqB,iBAAiB;CAC9C,MAAM,EAAE,aAAa,cAAc,OAAO,OAAO,yBAAyB;CAC1E,MAAM,QAAQ,qDAAqD,OAAO;CAiB1E,MAAM,gBAfc,eACX;EACL,8DAA8D,EAC5D,4DACF;EACA,8DAA8D,EAC5D,4DACF;EACA,2DAA2D,EACzD,yDACF;CACF,IACA,CAAC,CAAC,CAGkB,EAAY,UAAU,EAAE,KAAK;CACnD,OACE,oBAAC,QAAD;EACE,YAAW;EACX,cAAY,EAAE,8DAA8D,EAC1E,QAAQ,cACV,CAAC;EACD,gBAAc;EACd,WAAW,KAAK,yDAAyD,EACvE,iEAAiE,SACnE,CAAC;EAED,eAAe;GACb,IAAI,OAAO,UACT,iBAAiB,iBAAiB,OAAO,IAAI;QACxC;IACL,iBAAiB,eAAe,OAAO,IAAI;IAC3C,IAAI,iBAAiB,eAAe,CAAC,OAAO,OAAO,QACjD,OAAO,OAAO,iBAAiB,WAAW;GAC9C;EACF;EACA,MAAK;EACL,SAAQ;YAEP;CACK,GAdD,KAcC;AAEZ;AAEA,IAAa,4BAA4B;CACvC,MAAM,EAAE,2BAA2B,qBAAqB,iBAAiB;CAGzE,IAAI,iBAAiB,QAAQ,SAAS,GAAG,OAAO;CAEhD,OACE,oBAAC,OAAD;EAAK,WAAU;EAAkC,eAAY;YAC3D,oBAAC,OAAD;GACE,WAAU;GACV,eAAY;GACZ,KAAK;aAEJ,iBAAiB,QAAQ,KAAK,WAC7B,oBAAC,0BAAD,EAAoD,OAAS,GAA9B,OAAO,IAAuB,CAC9D;EACE,CAAA;CACF,CAAA;AAET;;;AC5EA,IAAa,+BAA+B;CAC1C,MAAM,EAAE,MAAM,sBAAsB;CACpC,OACE,oBAAC,OAAD;EAAK,WAAU;YACZ,EAAE,wBAAwB;CACxB,CAAA;AAET;;;ACPA,IAAM,mCAAiC,eAAsC;CAC3E,eAAe,UAAU,QAAQ,QAAQ,MAAM,EAAE,QAAQ;CACzD,UAAU,UAAU;CACpB,aAAa,UAAU;AACzB;AAEA,IAAa,sBAAsB;CACjC,MAAM,EAAE,MAAM,sBAAsB,kBAAkB;CACtD,MAAM,EACJ,qBAAA,wBAAsB,qBACtB,wBAAA,2BAAyB,wBACzB,qBAAA,wBAAsB,wBACpB,oBAAoB;CACxB,MAAM,EAAE,qBAAqB,iBAAiB;CAC9C,MAAM,EAAE,eAAe,UAAU,gBAAgB,cAC/C,iBAAiB,OACjB,+BACF;CAEA,OAAO,CAAC,WAAW,OACjB,qBAAC,OAAD;EAAK,cAAY,EAAE,qBAAqB;EAAG,WAAU;YAArD,CACE,oBAAC,uBAAD,CAAsB,CAAA,GACrB,CAAC,cACA,oBAAC,0BAAD,EAAuC,cAAgB,CAAA,IAEvD,cAAc,KAAK,WACjB,oBAAC,uBAAD,EAAuC,cAAc,OAAS,GAApC,OAAO,IAA6B,CAC/D,CAEA;;AAET;;;AC3BA,IAAM,mCACJ,eAC8C,EAAE,UAAU,UAAU,SAAS;AAa/E,IAAa,UAAU,EACrB,6BAA6B,aAC7B,UACA,wBAAwB,OACxB,kBACiB;CACjB,MAAM,EAAE,WAAA,cAAY,WAAkB,eAAA,kBAAgB,kBACpD,oBAAoB;CACtB,MAAM,eAAe,OAA8B,IAAI;CACvD,MAAM,4BAA4B,OAA8B,IAAI;CAEpE,MAAM,EAAE,qBAAqB,eAAe;CAE5C,MAAM,EAAE,aAAa,cAGnB,iBAAiB,OAAO,+BAA6B;CAEvD,OACE,oBAAC,uBAAD;EACE,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;GACA;EACF;YAEA,qBAAC,OAAD;GACE,WAAW,KAAK,oBAAoB,EAClC,4BAA4B,SAC9B,CAAC;GACD,eAAY;GACZ,KAAK;aALP,CAOE,oBAAC,aAAD,CAAY,CAAA,GACZ,oBAAC,iBAAD,CAAgB,CAAA,CACb;;CACgB,CAAA;AAE3B;;;AC1DA,IAAM,4BAA4B,EAChC,UACA,WACA,cAC4C;CAC5C,MAAM,EAAE,MAAM,sBAAsB,0BAA0B;CAE9D,MAAM,0BAA0B,YAAY,EAAE,WAAW;CAEzD,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,QAAD;GACE,YAAW;GACX,cAAY,EAAE,WAAW;GACzB,eAAY;GACZ,UAAU;GACD;GACT,MAAK;GACL,SAAQ;aAEP,YAAY,oBAAC,kBAAD,CAAmB,CAAA,IAAI;EAC9B,CAAA;CACL,CAAA;AAET;AAEA,IAAa,iBAAiB,MAAM,KAClC,wBACF;;;AC3BA,IAAa,+BACX,UACG;CACH,MAAM,EACJ,UACA,aACA,WACA,gBAAA,mBAAiB,gBACjB,cACA,YACE;CAEJ,OACE,qBAAA,YAAA,EAAA,UAAA;EACG,CAAC,WAAW;EACZ,eAAe,oBAAC,kBAAD;GAA2B;GAAW,SAAS;EAAe,CAAA;EAC7E,WAAW;CACZ,EAAA,CAAA;AAEN;AAEA,IAAa,oBAAoB,MAAM,KACrC,2BACF;;;AC9BA,IAAa,0BAA0B;CACrC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,YAAY,eAAe;CACnC,MAAM,EAAE,qBAAqB,oBAAoB;CACjD,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD;GAAK,WAAU;aAAyC,EAAE,OAAO;EAAO,CAAA,GACvE,WAAW,oBAAoB,oBAAC,kBAAD,CAAmB,CAAA,CAChD;;AAET;;;AC2BA,IAAM,kBAAkB,CAAC;AACzB,IAAM,kBAAkB,CAAC;AACzB,IAAM,eAAe,CAAC;AAEtB,IAAM,iCAAiC,eAAsC,EAC3E,gBAAgB,UAAU,SAC5B;AAuGA,IAAM,yBAAyB,UAA4B;CACzD,MAAM,EACJ,yCAAyC,MACzC,uBACA,qBACA,qBACA,qBAAA,wBAAsB,qBACtB,UAAU,CAAC,GACX,yBACA,mBAAmB,OACnB,kBACA,kBACA,iBACA,oBACA,kBACA,kBACA,cACA,qBACA,sBACA,SACA,YAAY,mBACZ,4BACA,gBACA,qBAAqB,OACrB,0BAA0B,MAC1B,oBAAoB,OACpB,OAAO,cACP,WAAW,CAAC,MACV;CAEJ,MAAM,WAAW,YAAY;CAE7B,MAAM,EACJ,SACA,oBACA,QACA,eACA,kBACA,kBACA,OACA,gCACE,eAAe,aAAa;CAChC,MAAM,EACJ,eAAA,kBAAgB,eAChB,kBAAA,qBAAmB,kBACnB,QAAA,YAAS,WACP,oBAAoB;CAExB,MAAM,iBAAiB,OAA8B,IAAI;CACzD,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,CAAC;CAG9D,MAAM,EAAE,mBAAmB,cACzB,iBAAiB,OACjB,6BACF;;;;;CAKA,MAAM,uBAAuB,OAC3B,UACA,aACA,yBACG;EACH,IAAI,CAAC,SAAS,QACZ;EAGF,IAAI,qBAAqB;GAEvB,IAAI,4BAA4B,SAAS,MACtC,SAAS,KAAK,OAAO,mBACxB;GAEA,IAAI,CAAC,2BACH,CAAC,6BAA6B,MAAM,OAAO,cAAc,EACvD,IAAI,oBACN,CAAC;GAGH,IAAI,2BAA2B;IAC7B,iBAAiB,2BAA2B,QAAQ;IAQpD,YANoB,mBAAmB;KACrC;KACA,eAAe;KACf,MAAM,qBAAqB;IAC7B,CAEY,CAAW;IACvB;GACF;EACF;EAEA,IAAI,yBACF,iBAAiB,SAAS,IAAI,QAAQ;CAE1C;;;;;CAMA,MAAM,cAAc,kBAAkB,uBAAuB,UAAU,QAAQ,CAAC,GAAG,CAAC,CAAC;CAErF,MAAM,EACJ,UACA,kBACA,eACA,aACA,cACA,gBACE,qBACF,QACA,WAAW,iBACX,QAAQ,cACR,WAAW,iBACX,sBACA,4BACA,mBACF;CAEA,MAAM,iBAAiB,wBACnB,sBAAsB,QAAQ,IAC9B;CAEJ,MAAM,EAAE,eAAe,mBAAmB,wBAAwB;EAChE;EAKA,SAAS;EACT;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;CAGR,CAAC;CAED,oBAAoB,iBAAiB,cAAc;CAGnD,+BAA+B,WAAW;CAE1C,gBAAgB;EACd,MAAM,eAAe,UAAiB;GACpC,IAAI,MAAM,QAAQ,SAAS,KACzB,iBAAiB;EAErB;EAEA,OAAO,GAAG,mBAAmB,WAAW;EACxC,OAAO,GAAG,kBAAkB,WAAW;EAEvC,aAAa;GACX,OAAO,IAAI,mBAAmB,WAAW;GACzC,OAAO,IAAI,kBAAkB,WAAW;EAC1C;CAEF,GAAG,CAAC,SAAS,GAAG,CAAC;CAEjB,MAAM,iBAAiB,SAAkB;EAWvC,OAAO,oBAAC,iBAAD;GATL,eAAe;GACf,SAAS;GAET;GACA;GACA;GACA;EAGwD,GAA7B,KAAK,GAAwB;CAC5D;CAGA,MAAM,YAAY,KAChB,eAAe,QAAQ,YACvB,OACA,eAAe,eAAe,0BAC9B,EACE,2BACE,+BAA+B,UAAU,UAAU,MAAM,KAAK,EAClE,CACF;CAEA,MAAM,kBAAkB,CAAC;CACzB,OACE,oBAAC,4BAAD;EACE,OAAO;GAAE;GAAU;GAAa;GAAc;EAAY;YAE1D,oBAAC,OAAD;GAAgB;GAAW,KAAK;aAC9B,qBAAC,uBAAD;IAAuB,IAAI,+BAA+B;cAA1D;KACE,oBAAC,mBAAD,CAAoB,CAAA;KACnB,qBAAqB,oBAAC,WAAD,CAAS,CAAA;KAC9B,mBACC,oBAAC,iBAAD;MACE,OAAO,mBAAmB;MAC1B,gBAAgB,qBAAqB,iBAAiB,KAAA;MACtD,SACE,CAAC,CAAC,mBAAmB,mBACrB,CAAC,UAAU,eAAe,EAAE,SAAS,mBAAmB,eAAe;MAE5D;gBAEZ,CAAC,gBAAgB,SAChB,oBAAC,uBAAD,EAAqB,UAAS,UAAW,CAAA,IAEzC,oBAAC,WAAD;OACe;OACb,WAAW,mBAAmB,oBAAoB;OACpC;iBAEb,iBACG,eAAe,gBAAgB,aAAa,IAC5C,eAAe,KAAK,YAAY,cAAc,OAAO,CAAC;MACjD,CAAA;KAEA,CAAA;KAEjB,oBAAC,oBAAD,EAAkB,OAAM,eAAgB,CAAA;IACnB;;EACpB,CAAA;CACqB,CAAA;AAEhC;;;;AAKA,IAAa,cAAc,MAAM,KAC/B,qBACF;;;ACvYA,IAAM,aAAa,CAAC;AAYpB,SAAgB,wBAA2B,EACzC,SACA,UACA,uBAAuB,CAAC,KAAK,KAKb;CAsBhB,OAAO,qBArBW,aACf,kBAAsC;EACrC,IAAI,CAAC,SAAS,OAAO;EAErB,MAAM,gBAAgB,qBAAqB,KAAK,OAC9C,QAAQ,GAAG,UAAU;GACnB,cAAc,SAAS,OAAO,CAAC;EACjC,CAAC,CACH;EAEA,aAAa,cAAc,SAAS,iBAAiB,aAAa,YAAY,CAAC;CACjF,GACA;EAAC;EAAS;EAAU;CAAoB,CASd,GANR,kBAAkB;EACpC,IAAI,CAAC,SAAS,OAAO,KAAA;EAErB,OAAO,SAAS,OAAO;CACzB,GAAG,CAAC,SAAS,QAAQ,CAEkB,CAAW;AACpD;;;AC7CA,IAAM,cAAY,MAAe,EAAE,MAAM;AACzC,IAAM,SAAqB,CAAC,gBAAgB;AAM5C,SAAgB,0BAA0B,SAAmB;CAC3D,OAAO,wBAAwB;EAAE;EAAS,UAAA;EAAU,sBAAsB;CAAK,CAAC;AAClF;;;ACTA,IAAM,cAAY,MAAe,EAAE,MAAM;AACzC,IAAM,OAAqB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAQA,SAAgB,uBAAuB,SAAmB;CACxD,OAAO,wBAAwB;EAAE;EAAS,UAAA;EAAU,sBAAsB;CAAK,CAAC;AAClF;;;AChBA,IAAa,qBAAqB,YAAqB;CACrD,MAAM,EAAE,WAAW,eAAe,mBAAmB;CAErD,MAAM,CAAC,OAAO,YAAY,SAAS,QAAQ,WAAW,CAAC;CAEvD,gBAAgB;EACd,MAAM,oBAAoB,SAAS,QAAQ,WAAW,CAAC;EAEvD,OAAO,GAAG,sCAAsC,WAAW;EAC3D,aAAa,OAAO,IAAI,sCAAsC,WAAW;CAE3E,GAAG,CAAC,KAAK,CAAC;CAEV,OAAO;AACT;;;ACKA,IAAM,oCAAoC;CACxC,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,EAAE,YAAY,0BAA0B;CAC9C,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,OAAO,YAAY,kBAAkB,OAAO;CACpD,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,OAAO;EACL,gBAAgB;EAChB,UAAU;EACV,SAAS,OAAO,MAA2C;GACzD,EAAE,gBAAgB;GAClB,IAAI;IACF,cAAc,IAAI;IAClB,IAAI,SAAS;KACX,MAAM,QAAQ,OAAO;KACrB,gBAAgB;MACd,SAAS,EACP,QACF;MACA,SAAS,6BAA6B;MACtC,SAAS,EAAE,iBAAiB;MAC5B,UAAU;MACV,MAAM;KACR,CAAC;IACH,OAAO;KACL,MAAM,QAAQ,KAAK;KACnB,gBAAgB;MACd,SAAS,EACP,QACF;MACA,SAAS,6BAA6B;MACtC,SAAS,EAAE,eAAe;MAC1B,UAAU;MACV,MAAM;KACR,CAAC;IACH;GACF,SAAS,OAAO;IACd,gBAAgB;KACd,SAAS,EACP,QACF;KACA,SAAS,6BAA6B;KACtC,OAAO,iBAAiB,QAAQ,wBAAQ,IAAI,MAAM,2BAA2B;KAC7E,SAAS,EAAE,sCAAsC;KACjD,UAAU;KACV,MAAM;IACR,CAAC;GACH,UAAU;IACR,cAAc,KAAK;GACrB;EACF;EACA,OAAO,UAAU,EAAE,QAAQ,IAAI,EAAE,MAAM;CACzC;AACF;AAEA,IAAM,uCAAuC;CAC3C,MAAM,EAAE,YAAY,0BAA0B;CAC9C,MAAM,EAAE,oBAAoB,mBAAmB;CAC/C,MAAM,aAAa,0BAA0B,OAAO;CACpD,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,OAAO;EACL,gBAAgB,OAAO,WAAW,gBAAgB;EAClD,UAAU;EACV,SAAS,OAAO,MAA2C;GACzD,EAAE,gBAAgB;GAClB,IAAI;IACF,cAAc,IAAI;IAClB,IAAI,WAAW,aAAa;KAC1B,MAAM,QAAQ,UAAU;KACxB,gBAAgB;MACd,SAAS,EACP,QACF;MACA,SAAS,6BAA6B;MACtC,SAAS,EAAE,oBAAoB;MAC/B,UAAU;MACV,MAAM;KACR,CAAC;IACH,OAAO;KACL,MAAM,QAAQ,QAAQ;KACtB,gBAAgB;MACd,SAAS,EACP,QACF;MACA,SAAS,6BAA6B;MACtC,SAAS,EAAE,kBAAkB;MAC7B,UAAU;MACV,MAAM;KACR,CAAC;IACH;GACF,SAAS,OAAO;IACd,gBAAgB;KACd,SAAS,EACP,QACF;KACA,SAAS,6BAA6B;KACtC,OAAO,iBAAiB,QAAQ,wBAAQ,IAAI,MAAM,2BAA2B;KAC7E,SAAS,EAAE,yCAAyC;KACpD,UAAU;KACV,MAAM;IACR,CAAC;GACH,UAAU;IACR,cAAc,KAAK;GACrB;EACF;EACA,OAAO,WAAW,cAAc,EAAE,WAAW,IAAI,EAAE,SAAS;CAC9D;AACF;AAYA,IAAM,sBAAoB;CACxB,UAAU;EACR,UAAU;GACR,MAAM,gBAAgB,+BAA+B;GAErD,OACE,oBAAC,mBAAD;IACE,cAAY,cAAc;IAC1B,eAAY;IACZ,MAAM;IACN,GAAI;cAEH,cAAc;GACE,CAAA;EAEvB;EACA,MAAM;GACJ,MAAM,EAAE,WAAW,eAAe;GAClC,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,EAAE,YAAY,0BAA0B;GAC9C,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;GAClD,MAAM,UAAU,uBAAuB,OAAO;GAC9C,MAAM,eAAe,OAAO,OAAO,WAAW,CAAC,CAAC,EAAE,MAC/C,WAAW,OAAO,MAAM,OAAO,OAAO,UAAU,OAAO,MAC1D;GAEA,MAAM,QAAQ,eAAe,EAAE,cAAc,IAAI,EAAE,YAAY;GAE/D,OACE,oBAAC,mBAAD;IACE,cAAY;IACZ,eAAY;IACZ,UAAU;IACV,MAAM;IACN,SAAS,YAAY;KACnB,IAAI;MACF,cAAc,IAAI;MAClB,MAAM,cAAc,OAAO,KAAK,QAAQ,MAAM,OAAO,EAAE,MAEpD,WAAW,WAAW,OAAO,MAChC;MAEA,IAAI,CAAC,aAAa;MAElB,IAAI,cAAc;OAChB,MAAM,QAAQ,UAAU,WAAW;OACnC,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS,6BAA6B;QACtC,SAAS,EAAE,gBAAgB;QAC3B,UAAU;QACV,MAAM;OACR,CAAC;MACH,OAAO;OACL,MAAM,QAAQ,QAAQ,aAAa,CAAC,CAAC;OACrC,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS,6BAA6B;QACtC,SAAS,EAAE,cAAc;QACzB,UAAU;QACV,MAAM;OACR,CAAC;MACH;KACF,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS,6BAA6B;OACtC,OACE,iBAAiB,QAAQ,wBAAQ,IAAI,MAAM,2BAA2B;OACxE,SAAS,EAAE,sBAAsB;OACjC,UAAU;OACV,MAAM;MACR,CAAC;KACH,UAAU;MACR,cAAc,KAAK;KACrB;IACF;cAEC;GACgB,CAAA;EAEvB;EACA,QAAQ;GACN,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,EAAE,YAAY,0BAA0B;GAC9C,MAAM,EAAE,WAAW,eAAe;GAClC,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;GAElD,MAAM,QAAQ,EAAE,eAAe;GAE/B,OACE,oBAAC,mBAAD;IACE,cAAY;IACZ,eAAY;IACZ,UAAU;IACV,MAAM;IACN,SAAS,OAAO,MAAM;KACpB,EAAE,gBAAgB;KAClB,IAAI;MACF,cAAc,IAAI;MAElB,MAAM,QAAQ,cAAc,CAAC,OAAO,MAAO,CAAC;MAC5C,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS,6BAA6B;OACtC,SAAS,EAAE,cAAc;OACzB,UAAU;OACV,MAAM;MACR,CAAC;KACH,SAAS,OAAO;MACd,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS,6BAA6B;OACtC,OACE,iBAAiB,QAAQ,wBAAQ,IAAI,MAAM,2BAA2B;OACxE,SAAS,EAAE,yBAAyB;OACpC,UAAU;OACV,MAAM;MACR,CAAC;KACH,UAAU;MACR,cAAc,KAAK;KACrB;IACF;IACO;IACP,SAAQ;cAEP;GACgB,CAAA;EAEvB;EACA,OAAO;GACL,MAAM,gBAAgB,4BAA4B;GAElD,OACE,oBAAC,mBAAD;IACE,cAAY,cAAc;IAC1B,eAAY;IACZ,MAAM;IACN,GAAI;cAEH,cAAc;GACE,CAAA;EAEvB;EACA,MAAM;GACJ,MAAM,EAAE,MAAM,sBAAsB;GACpC,MAAM,EAAE,oBAAoB,mBAAmB;GAC/C,MAAM,EAAE,YAAY,0BAA0B;GAC9C,MAAM,aAAa,0BAA0B,OAAO;GAKpD,MAAM,EAAE,WAAW,0BAA0B,EAAE,IAJ9B,6BAA6B,YAE5C,EAAE,WAAW,QAAQ,GAAI,CAEwB,EAAS,CAAC;GAC7D,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;GAElD,MAAM,QAAQ,WAAW,YAAY,EAAE,OAAO,IAAI,EAAE,KAAK;GAEzD,OACE,oBAAC,mBAAD;IACE,cAAY;IACZ,eAAY;IACZ,UAAU;IACV,MAAM;IACN,SAAS,OAAO,MAAM;KACpB,EAAE,gBAAgB;KAClB,IAAI,QAAsB;KAC1B,IAAI;MACF,cAAc,IAAI;MAClB,IAAI,WAAW,WAAW;OACxB,MAAM,QAAQ,MAAM;OACpB,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS,6BAA6B;QACtC,SAAS,EAAE,kBAAkB;QAC7B,UAAU;QACV,MAAM;OACR,CAAC;MACH,OAAO;OACL,MAAM,QAAQ,IAAI;OAClB,gBAAgB;QACd,SAAS,EACP,QACF;QACA,SAAS,6BAA6B;QACtC,SAAS,EAAE,gBAAgB;QAC3B,UAAU;QACV,MAAM;OACR,CAAC;MACH;KACF,SAAS,GAAG;MACV,QAAQ,aAAa,QAAQ,oBAAI,IAAI,MAAM,2BAA2B;MACtE,gBAAgB;OACd,SAAS,EACP,QACF;OACA,SAAS,6BAA6B;OACtC;OACA,SAAS,EAAE,wCAAwC;OACnD,UAAU;OACV,MAAM;MACR,CAAC;KACH,UAAU;MACR,IAAI,CAAC,OAAO,QAAQ,MAAM;MAC1B,cAAc,KAAK;KACrB;IACF;IACO;cAEN;GACgB,CAAA;EAEvB;CACF;CACA,OAAO;EACL,UAAU;GACR,MAAM,gBAAgB,+BAA+B;GAErD,OACE,oBAAC,QAAD;IACE,YAAW;IACX,cAAY,cAAc;IAC1B,UAAA;IACA,eAAY;IACZ,MAAK;IACL,SAAQ;IACR,GAAI;cAEJ,oBAAC,aAAD,CAAc,CAAA;GACR,CAAA;EAEZ;EACA,OAAO;GACL,MAAM,gBAAgB,4BAA4B;GAElD,OACE,oBAAC,QAAD;IACE,YAAW;IACX,cAAY,cAAc;IAC1B,UAAA;IACA,eAAY;IACZ,MAAK;IACL,SAAQ;IACR,GAAI;cAEJ,oBAAC,UAAD,CAAW,CAAA;GACL,CAAA;EAEZ;CACF;CACA,qBAAqB,YAA+B,GAAG,QAAQ;EAC7D,MAAM,EAAE,YAAY,0BAA0B;EAC9C,MAAM,EAAE,MAAM,sBAAsB;EAEpC,MAAM,WAAW,6BAA6B,YAAY,EAExD,WAAW,QAAQ,GACrB,CAAC;EACD,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAAE,IAAI,SAAS,CAAC;EAC5E,MAAM,eAAe,gBAAgB,UAAU,eAAe,EAAE;EAEhE,OACE,oBAAC,QAAD;GACE,YAAW;GACX,iBAAe;GACf,cAAY,EAAE,gCAAgC;GAC9C,gBAAc;GACd,UAAA;GACA,eAAY;GACZ,UAAU,MAAM;IACd,EAAE,gBAAgB;IAElB,OAAO,OAAO;GAChB;GACK;GACL,MAAK;GACL,SAAQ;aAER,oBAAC,UAAD,CAAW,CAAA;EACL,CAAA;CAEZ,CAAC;AACH;AAEA,oBAAkB,oBAAoB,cAAc;AAEpD,IAAa,0BAA+C;CAC1D;EACE,WAAW,oBAAkB;EAC7B,WAAW;CACb;CACA;EACE,WAAW,oBAAkB,MAAM;EACnC,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,oBAAkB,SAAS;EACtC,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,oBAAkB,SAAS;EACtC,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,oBAAkB,SAAS;EACtC,WAAW;EACX,MAAM;CACR;CACA;EACE,WAAW,oBAAkB,SAAS;EACtC,WAAW;EACX,MAAM;CACR;AACF;AAEA,IAAa,iCAAiC,qBAA0C;CACtF,MAAM,EAAE,YAAY,0BAA0B;CAC9C,MAAM,aAAa,0BAA0B,OAAO;CACpD,MAAM,cAAc,QAAQ,MAAM,gBAAgB;CAClD,MAAM,wBAAwB,OAAO,WAAW,SAAS;CACzD,MAAM,yBAAyB,yBAAyB,gBAAgB;CAExE,MAAM,kBAAkB,QAAQ,MAAM;CAEtC,OAAO,cAAc;EAsBnB,OArBiB,iBAAiB,QAAQ,WAAW;GACnD,IAAI,OAAO,cAAc,yBAAyB,OAAO;GAEzD,QAAQ,OAAO,MAAf;IACE,KAAK,WACH,OAAO;IACT,KAAK,QACH,OAAO,iBAAiB,SAAS,cAAc;IACjD,KAAK,OACH,OACE,0BAA0B,iBAAiB,SAAS,qBAAqB;IAE7E,KAAK,SACH,OAAO,iBAAiB,SAAS,eAAe;IAClD,KAAK,OACH,OAAO;IACT,SACE,OAAO;GACX;EACF,CAEO;CACT,GAAG;EAAC;EAAkB;EAAuB;EAAiB;CAAsB,CAAC;AACvF;;;AC5eA,IAAa,qCAA4E;CACvF,MAAM,EAAE,aAAa,uBAAuB,gBAAgB,oBAAoB;CAChF,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,YAAY,0BAA0B;CAC9C,MAAM,CAAC,kBAAkB,uBACvB,MAAM,SAAmC,IAAI;CAC/C,MAAM,CAAC,kBAAkB,uBAAuB,MAAM,SAAS,KAAK;CACpE,MAAM,WAAW,6BAA6B,YAAY,EAExD,WAAW,QAAQ,GACrB,CAAC;CACD,MAAM,EAAE,QAAQ,kBAAkB,0BAA0B,EAAE,IAAI,SAAS,CAAC;CAC5E,MAAM,eAAe,gBAAgB,UAAU,eAAe,EAAE;CAEhE,MAAM,mBAAmB,MAAM,kBAAkB;EAC/C,oBAAoB,IAAI;EACxB,QAAQ,MAAM;EAEd,4BAA4B;GAC1B,IAAI,CAAC,kBAAkB,aAAa;IAClC,oBAAoB,KAAK;IACzB;GACF;GAEA,iBAAiB,MAAM;GAEvB,4BAA4B;IAC1B,IAAI,SAAS,kBAAkB,kBAC7B,oBAAoB,KAAK;GAE7B,CAAC;EACH,CAAC;CACH,GAAG,CAAC,QAAQ,gBAAgB,CAAC;CAG7B,MAAM,EAAE,mBAAmB,gBAAgB,8BACzC,kBAFwB,8BAA8B,uBAEpC,CAAiB;CAErC,IAAI,eAAe,SAAS,kBAAkB,WAAW,GAEvD,OAAO;CAGT,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,+CAA+C,EAC7D,uDACE,gBAAgB,iBACpB,CAAC;EACD,eAAY;EACZ,sBAAsB;GACpB,oBAAoB,KAAK;EAC3B;YARF;GAUG,6BAA6B,kBAAkB,SAAS,KACvD,oBAAC,0BAA0B,WAA3B,EAAqC,KAAK,oBAAsB,CAAA;GAEjE,eAAe,KAAK,EAAE,WAAW,WAChC,oBAAC,WAAD,CAAuB,GAAP,IAAO,CACxB;GACD,oBAAC,sBAAD;IACE,cAAY,EAAE,sBAAsB;IACpC,WAAU;IACV,eAAY;IACZ,iBAAiB,eAAe;IAChC,IAAI,OAAO;IACX,SAAS;IACT,WAAU;IACQ;IAClB,UAAU;IACV,WAAA;cAEC,kBAAkB,KAAK,EAAE,WAAW,WACnC,oBAAC,WAAD,CAAuB,GAAP,IAAO,CACxB;GACmB,CAAA;EACnB;;AAET;AAEA,6BAA6B,eAAe,EAAE,gBAC5C,0BAA0B;AAE5B,6BAA6B,cAAc;;;AC5F3C,SAAgB,yBAAyB,EAAE,eAA8C;CACvF,MAAM,EAAE,GAAG,oBAAoB,sBAAsB,0BAA0B;CAE/E,MAAM,YAAY,aAAa;CAC/B,MAAM,sBACJ,aAAa,OAAO,SAAS,IAAI,UAAU,YAAY,IAAI,KAAA;CAE7D,MAAM,OAAO,cAET,cAAc;EACZ,kBAAkB;EAClB;EACA;EACA,yBAAyB;CAC3B,CAAC,GACH;EAAC;EAAqB;EAAG;CAAe,CAC1C;CAEA,IAAI,CAAC,MAAM,OAAO;CAElB,OACE,oBAAC,QAAD;EACE,WAAU;EACV,UAAU;YAET;CACG,CAAA;AAEV;;;ACHA,IAAM,4BAAoC;CACxC;CACA;CACA;CACA;AACF;AAsCA,SAAS,yBAAyB,YAAmD;CACnF,IAAI,CAAC,YAAY,OAAO;CAExB,IAAI,WAAW,SAAS,SAAS,OAAO;CACxC,IAAI,iBAAiB,UAAU,GAAG,OAAO;CACzC,IAAI,kBAAkB,UAAU,GAAG,OAAO;CAC1C,IAAI,kBAAkB,YAAY,yBAAuB,GAAG,OAAO;CACnE,IAAI,2BAA2B,UAAU,GAAG,OAAO;CACnD,IACE,kBAAkB,UAAU,KAC5B,iBAAiB,YAAY,yBAAuB,GAEpD,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,0BACP,MACA,OACA,GACQ;CACR,QAAQ,MAAR;EACE,KAAK,SACH,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC;EAClC,KAAK,SACH,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC;EAClC,KAAK,SACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,CAAC;EACzC,KAAK,QACH,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC;EACjC,KAAK,QACH,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC;EACjC,KAAK,eACH,OAAO,EAAE,wBAAwB;EACnC,SACE,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC;CACnC;AACF;AAeA,IAAa,2BAA2B,EACtC,eACA,uBACA,uBAC6D;CAC7D,MAAM,EAAE,WAAW,eAAe,yBAAyB;CAC3D,MAAM,EAAE,GAAG,iBAAiB,sBAAsB,yBAAyB;CAE3E,OAAO,cAAc;EACnB,IAAI,CAAC,eACH,OAAO;GAAE,MAAM,EAAE,gBAAgB;GAAG,MAAM;EAAiB;EAG7D,IAAI,cAAc,WAAW,YAAY,cAAc,SAAS,SAC9D,OAAO;GAAE,MAAM,EAAE,wBAAwB;GAAG,MAAM;EAAiB;EAGrE,MAAM,eAAe,cAAc,MAAM,OAAO,OAAO,MAAM;EAE7D,IAAI;EACJ,IAAI,cACF,iBAAiB,yBAA0B,cAAc;EAG3D,IAAI;EACJ,IAAI,cACF,aAAa,EAAE,KAAK;OACf,IAAI,CAAC,gBAAgB,qBAAqB,KAAA,KAAa,mBAAmB,GAC/E,aAAa,cAAc,MAAM,QAAQ,cAAc,MAAM;EAG/D,IAAI,iBAAiB,aAAa,GAChC,OAAO;GACL;GACA;GACA,MAAM,EAAE,iBAAiB;GACzB,MAAM;EACR;EAGF,IAAI,cAAc,MAChB,OAAO;GACL;GACA;GACA,MAAM,EAAE,MAAM;GACd,MAAM;EACR;EAGF,MAAM,cACJ,yBAAyB;GAAE,UAAU;GAAc,SAAS;EAAc,CAAC,KAC3E,cAAc;EAEhB,IAAI,cAAc,iBAChB,OAAO;GACL;GACA;GACA,MAAM,eAAe,EAAE,UAAU;GACjC,MAAM;EACR;EAGF,IAAI,cAAc,eAAe,cAAc,YAAY,QAAQ;GACjE,MAAM,cAAc,cAAc;GAElC,IAAI;GAEJ,MAAM,CAAC,mBAAmB;GAC1B,MAAM,sBAAsB,yBAAyB,eAAe;GAEpE,IACE,YAAY,OACT,eAAe,yBAAyB,UAAU,MAAM,mBAC3D,GAEA,cAAc;QAEd,cAAc;GAGhB,IAAI,OACF,gBAAgB,UACZ,SAAS,gBAAgB,SAAS,KAAK,KAAK,IAE5C,gBAEC,YAAY,WAAW,KACxB,gBAAgB,WAChB,gBAAgB,gBACZ,gBAAgB,YAAY,gBAAgB,QAC5C,OAEJ,0BAA0B,aAAa,YAAY,QAAQ,CAAC;GAGlE,IAAI,YAAY,WAAW,KAAK,OAAO,gBAAgB,aAAa,UAAU;IAG5E,MAAM,iBAAiB,GAFP,KAAK,MAAM,gBAAgB,WAAW,EAE5B,EAAQ,IADlB,KAAK,KAAK,gBAAgB,QAAQ,IAAI,IACT,SAAS,EAAE,SAAS,GAAG,GAAG;IACvE,QAAQ,KAAK,eAAe;GAC9B;GAEA,OAAO;IACL;IACA;IACA;IACA,MAAM;GACR;EACF;EAEA,IAAI,aACF,OAAO;GACL;GACA;GACA,MAAM;GACN,MAAM;EACR;EAGF,OAAO;GAAE,MAAM,EAAE,kBAAkB;GAAG,MAAM;EAAiB;CAC/D,GAAG;EACD,OAAO,MAAM;EACb;EACA;EACA;EACA;EACA;CACF,CAAC;AACH;;;AC7OA,IAAM,wBAAmF;CACvF,WAAW;CACX,MAAM;CACN,SAAS;CACT,MAAM;AACR;AAEA,IAAM,qBAEF;CACF,SAAS;CACT,OAAO;CACP,MAAM;CACN,OAAO;CACP,OAAO;CACP,MAAM;CACN,UAAU;CACV,aAAa;CACb,OAAO;CACP,OAAO;AACT;AAEA,IAAa,4BAA4B,EACvC,eACA,uBACA,uBACmC;CACnC,MAAM,EAAE,gBAAgB,YAAY,MAAM,SAAS,wBAAwB;EACzE;EACA;EACA;CACF,CAAC;CAED,MAAM,qBAAqB,iBACvB,sBAAsB,kBACtB,KAAA;CACJ,MAAM,kBAAkB,mBAAmB;CAE3C,OACE,qBAAC,OAAD;EACE,WAAW,KAAK,wCAAwC,GACrD,yCAAyC,SAAS,KACrD,CAAC;YAHH;GAKG,SAAS,WACR,qBAAA,YAAA,EAAA,UAAA,CACG,sBACC,oBAAC,QAAD;IACE,WAAW,KAAK,yDAAyD,GACtE,0DAA0D,mBACzD,eACJ,CAAC;cAED,oBAAC,oBAAD,CAAqB,CAAA;GACjB,CAAA,GAEP,cACC,qBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,YAAW,GACR;KAER,EAAA,CAAA;GAEH,mBAAmB,oBAAC,iBAAD,CAAkB,CAAA;GACtC,oBAAC,QAAD;IAAM,WAAU;cAA8C;GAAW,CAAA;EACtE;;AAET;;;AC9EA,IAAM,+BAA+B,UAAkC;CACrE,MAAM,EACJ,QACA,SACA,WAAW,kBAAkB,IAC7B,cACA,cACA,yBACA,aACA,uBACA,OACA,UAAU,uBACV,QACA,kBACA,QACA,aACE;CAEJ,MAAM,EACJ,SAAS,eACT,8BAAA,iCAA+B,iCAC7B,oBAAoB;CACxB,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,uBAAuB,OAAiC,IAAI;CAElE,MAAM,aACJ,gBAAgB,QAAQ,MAAM,SAAS,QAAQ,MAAM,SAAS,SAAS,IAAI,MAAM;CAEnF,MAAM,mBAAmB,MAA2C;EAClE,IAAI,uBACF,sBAAsB,CAAC;OAClB,IAAI,kBACT,iBAAiB,SAAS,QAAQ;EAEpC,IAAI,sBAAsB,SACxB,qBAAqB,QAAQ,KAAK;CAEtC;CAEA,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,qBAAC,UAAD;GACE,cAAY,EAAE,0CAA0C,EACtD,aAAa,gBAAgB,GAC/B,CAAC;GACD,iBAAe;GACf,WAAW,KACT,+BACA;IACE,sCAAsC;IACtC,uCAAuC;IACvC,uCACE,OAAO,WAAW,YAAY,SAAS;GAC3C,GACA,eACF;GACA,eAAY;GACZ,SAAS;GACT,KAAK;GACL,MAAK;aAlBP,CAoBE,oBAAC,QAAD;IACE,gBAAgB,yBAAyB;IACzC,UAAU;IACV,MAAK;IACL,UAAU;GACX,CAAA,GACD,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,qBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,oBAAC,QAAD,EAAA,UAAO,gBAAgB,MAAY,CAAA;OAClC,UAAU,oBAAC,SAAD,CAAU,CAAA;OACpB,SAAS,oBAAC,UAAD,CAAW,CAAA;MAClB;SACL,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,oBAAC,0BAAD,EAAuC,YAAc,CAAA,GACpD,OAAO,WAAW,YAAY,SAAS,KACtC,oBAAC,OAAD;OAAO,eAAY;OAAe,MAAK;OAAK,SAAQ;iBACjD;MACI,CAAA,CAEN;OACF;QACL,oBAAC,0BAAD;KACE,eAAe;KACQ;KACvB,kBAAkB,QAAQ,MAAM;IACjC,CAAA,CACE;KACC;MACR,oBAAC,gCAAD,CAA+B,CAAA,CAC5B;;AAET;;;;;AAMA,IAAa,oBAAoB,MAAM,KACrC,2BACF;;;AC9GA,IAAY,wBAAL,yBAAA,uBAAA;CACL,sBAAA,UAAA;CACA,sBAAA,eAAA;CACA,sBAAA,UAAA;;AACF,EAAA,CAAA,CAAA;AAQA,IAAa,4BAA4B,EACvC,SACA,kBAC+C;CAC/C,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,CAAC,uBAAuB,4BAA4B,SAExD;CAEF,MAAM,eAAe,aAClB,YACC,OAAO,QAAQ,WAAW,QAAQ,MAAM,OAAO,OAAO,KAAK,IAC7D,CAAC,MAAM,CACT;CAEA,gBAAgB;EAEd,IAAI,CAAC,aACH,yBAAyB,KAAA,CAAS;EAGpC,MAAM,mBAAmB,aAAa,WAAW;EACjD,IAAI,CAAC,aAAa,cAAc,CAAC,kBAAkB;EAEnD,MAAM,SAAS;GACb,OAAO,YAAY;GACnB,aAAa,YAAY,WAAW,QAAQ;EAC9C;EACA,MAAM,oBAAoB,QAAQ,uBAAuB,kBAAkB,MAAM;EACjF,MAAM,sBACJ,QAAQ,uBAAuB,oBAAoB,MAAM;EAC3D,yBACE,kBAAkB,SAAS,KACxB,kBAAkB,WAAW,KAAK,kBAAkB,GAAG,OAAO,OAAO,MAAM,KAAA,SAE1E,oBAAoB,SAAS,KAC1B,oBAAoB,WAAW,KAC9B,oBAAoB,GAAG,OAAO,OAAO,MAAM,KAAA,cAAA,MAGrD;CACF,GAAG;EAAC;EAAS;EAAQ;EAAc;CAAW,CAAC;CAE/C,gBAAgB;EACd,MAAM,oBAAoB,UAAiB;GAEzC,IAAI,CAAC,aAAa,MAAM,OAAO,GAC7B,OAAO,yBAAyB,KAAA,CAAS;GAE3C,OAAO,yBAAA,MAAmD;EAC5D;EAEA,QAAQ,GAAG,eAAe,gBAAgB;EAE1C,aAAa;GACX,QAAQ,IAAI,eAAe,gBAAgB;EAC7C;CACF,GAAG,CAAC,SAAS,YAAY,CAAC;CAE1B,gBAAgB;EACd,IAAI,CAAC,aAAa,WAAW,GAAG;EAChC,MAAM,0BAA0B,UAAiB;GAC/C,IACE,MAAM,MAAM,OAAO,OAAO,MAAM,MAChC,eACA,YAAY,OAAO,MAAM,2BAEzB,yBAAA,WAAwD;EAC5D;EAEA,MAAM,kBAAkB,UAAiB;GACvC,IAAI,MAAM,MAAM,OAAO,OAAO,MAAM,IAClC,yBAAA,MAAmD;EACvD;EAEA,QAAQ,GAAG,qBAAqB,sBAAsB;EACtD,QAAQ,GAAG,gBAAgB,cAAc;EAEzC,aAAa;GACX,QAAQ,IAAI,qBAAqB,sBAAsB;GACvD,QAAQ,IAAI,gBAAgB,cAAc;EAC5C;CACF,GAAG;EAAC;EAAS;EAAQ;EAAc;CAAW,CAAC;CAE/C,OAAO,EACL,sBACF;AACF;;;ACnCA,IAAM,yBAAyB,MAAM,cAAoC,EACvE,SAAS,KACX,CAAC;AAED,IAAa,kCAAkC,WAAW,sBAAsB;AAEhF,IAAa,mBAAmB,UAAgC;CAC9D,MAAM,EACJ,QACA,SACA,oBACA,yBAAA,4BAA0B,4BACxB;CACJ,MAAM,EAAE,mBAAA,sBAAoB,sBAA6B,oBAAoB;CAC7E,MAAM,EACJ,SAAS,eACT,QACA,sBACA,qBACE,eAAe,gBAAgB;CACnC,MAAM,EAAE,GAAG,iBAAiB,sBAAsB,gBAAgB;CAClE,MAAM,EAAE,cAAc,cAAc,4BAA4B,sBAAsB,EACpF,QACF,CAAC;CACD,MAAM,aAAa,0BAA0B,OAAO;CAEpD,MAAM,CAAC,aAAa,kBAAkB,SACpC,QAAQ,MAAM,SAAS,QAAQ,MAAM,SAAS,SAAS,EACzD;CACA,MAAM,CAAC,sBAAsB,2BAA2B,eACtD,0BAAwB,SAAS,GAAG,cAAc,oBAAoB,CACxE;CAEA,MAAM,CAAC,QAAQ,aAAa,SAAS,CAAC;CACtC,MAAM,EAAE,0BAA0B,yBAAyB;EACzD;EACA;CACF,CAAC;CAED,MAAM,WACJ,OAAO,WAAW,cAAc,eAAe,QAAQ,QAAQ,MAAM;CACvE,MAAM,EAAE,UAAU,kBAAkB,OAAO;CAE3C,gBAAgB;EACd,MAAM,eAAe,UAAiB;GACpC,IAAI,CAAC,MAAM,KAAK,OAAO,UAAU,CAAC;GAClC,IAAI,QAAQ,QAAQ,MAAM,KAAK,UAAU,CAAC;EAC5C;EAEA,OAAO,GAAG,0BAA0B,WAAW;EAC/C,aAAa,OAAO,IAAI,0BAA0B,WAAW;CAC/D,GAAG,CAAC,SAAS,MAAM,CAAC;CAEpB,gBAAgB;EACd,MAAM,eAAe,UAAiB;GACpC,IAAI,QAAQ,QAAQ,MAAM,KAAK;GAC/B,IAAI,MAAM,MAAM,OAAO,OAAO,MAAM,IAAI;GACxC,UAAU,QAAQ,YAAY,CAAC;EACjC;EACA,QAAQ,GAAG,4BAA4B,WAAW;EAClD,aAAa;GACX,QAAQ,IAAI,4BAA4B,WAAW;EACrD;CACF,GAAG,CAAC,SAAS,MAAM,CAAC;CAEpB,MAAM,qBAAqB,cAEvB,eAAe;EACb,IAAI,OACF,UAAU,CAAC;OAEX,UAAU,QAAQ,YAAY,CAAC;CAEnC,GAAG,GAAG,GACR,CAAC,SAAS,KAAK,CACjB;CAEA,gBAAgB;EACd,mBAAmB;EACnB,wBACE,0BAAwB,SAAS,GAAG,cAAc,oBAAoB,CACxE;EAEA,MAAM,eAAe,UAAiB;GAIpC,IAFE,MAAM,SAAS,2BAA2B,MAAM,OAAO,MAAM,QAAQ,QAAQ,KAE1C;GAErC,eACE,QAAQ,MAAM,eAAe,QAAQ,MAAM,eAAe,SAAS,EACrE;GACA,wBACE,0BAAwB,SAAS,GAAG,cAAc,oBAAoB,CACxE;GACA,mBAAmB;EACrB;EAEA,QAAQ,GAAG,eAAe,WAAW;EACrC,QAAQ,GAAG,mBAAmB,WAAW;EACzC,QAAQ,GAAG,mBAAmB,WAAW;EACzC,OAAO,GAAG,yBAAyB,WAAW;EAC9C,QAAQ,GAAG,qBAAqB,WAAW;EAC3C,QAAQ,GAAG,qBAAqB,WAAW;EAE3C,aAAa;GACX,QAAQ,IAAI,eAAe,WAAW;GACtC,QAAQ,IAAI,mBAAmB,WAAW;GAC1C,QAAQ,IAAI,mBAAmB,WAAW;GAC1C,OAAO,IAAI,yBAAyB,WAAW;GAC/C,QAAQ,IAAI,qBAAqB,WAAW;GAC5C,QAAQ,IAAI,qBAAqB,WAAW;EAC9C;CACF,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,6BAA6B,eAAe,EAAE,QAAQ,IAAI,CAAC,OAAO,CAAC;CAEzE,IAAI,CAAC,qBAAmB,OAAO;CAE/B,OACE,oBAAC,uBAAuB,UAAxB;EAAiC,OAAO;YACtC,oBAAC,qBAAD;GACE,GAAI;GACJ,QAAQ;GACM;GACA;GACW;GACZ;GACS;GACC;GAChB;GACP,QAAQ,CAAC,CAAC,WAAW;GACH;GACV;EACT,CAAA;CAC8B,CAAA;AAErC;;;ACnMA,IAAa,oBAAoB,EAC/B,mBACA,GAAG,YACwB;CAC3B,MAAM,EAAE,WAAW,eAAe;CAElC,MAAM,SAAS,yBAAyB;CAExC,MAAM,WAAW,aACd,eAA4B;EAC3B,SAAS,UAAU;EACnB,WAAW,UAAU;EACrB,aAAa,UAAU,QAAQ,GAAG,EAAE;EACpC,uBACG,OAAO,UAAU,UAAU,KAAK,OAAO,SAAS,sBAAuB;EAC1E,eAAe,UAAU;EACzB,cAAc,UAAU;EACxB,YAAY,UAAU;CACxB,IACA,CAAC,MAAM,CACT;CAEA,MAAM,EACJ,SACA,WACA,aACA,uBACA,eACA,cACA,eACE,cAAc,OAAO,OAAO,QAAQ;CAExC,MAAM,EAAE,cAAc,wBAAwB,sBAAsB,EAAE,QAAQ,CAAC;CAC/E,MAAM,EAAE,MAAM,sBAAsB,kBAAkB;CAEtD,MAAM,EAAE,cAAc,oBAAoB,sBAAsB;CAEhE,MAAM,cAAgD,YAClD,KAAA,IACC;EACC,UAAU,aAAa,MAAM;EAC7B,UAAU,aAAa,MAAM,QAAQ,aAAa,MAAM;CAC1D;CAEJ,MAAM,cAAc,cAAc;EAChC,IAAI,CAAC,cAAc,OAAO,CAAC;EAE3B,OAAO,aAAa,MAAM,GAAG,CAAC,EAAE,KAAK,iBAAiB;GACpD,IAAI,YAAY,MAAM,MAAM,KAAA;GAC5B,UAAU,YAAY,MAAM;GAE5B,UAAU,YAAY,MAAM,QAAQ,YAAY,KAAM;EACxD,EAAE;CACJ,GAAG,CAAC,YAAY,CAAC;CAEjB,gBAAgB;EACd,IAAI,CAAC,mBAAmB;EAExB,MAAM,QAAQ;EAEd,MAAM,UAAU,iBAAiB;GAC/B,MAAM;EACR,GAAG,GAAI;EAEP,aAAa,aAAa,OAAO;CACnC,GAAG,CAAC,iBAAiB,CAAC;CAEtB,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,qBAAC,UAAD;GACE,iBAAe,iBAAiB;GAChC,WAAW,KAAK,8BAA8B,EAC5C,2CACE,OAAO,sBAAsB,YACjC,CAAC;GACD,kBAAgB,OAAO;GACvB,eAAe,gBAAgB,MAAM;GACrC,MAAK;GACL,GAAI;aATN;IAWE,oBAAC,QAAD;KAAQ,MAAK;KAAK,GAAI;IAAc,CAAA;IACpC,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,oBAAC,QAAD;OAAM,WAAU;iBACb;MACG,CAAA,GACN,oBAAC,0BAAD;OACE,eAAe;OACf,kBAAkB,cAAc;MACjC,CAAA,CACE;SACL,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,qBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,oBAAC,aAAD;QAA0B;QAAa,MAAK;OAAM,CAAA,GAClD,oBAAC,QAAD;QAAM,WAAU;kBACb,EAAE,cAAc,EAAE,OAAO,WAAW,CAAC;OAClC,CAAA,CACH;UACL,oBAAC,WAAD;OACE,aAAY;OACZ,WAAW,aAAa;MACzB,CAAA,CACE;OACF;;IACJ,wBAAwB,KACvB,oBAAC,OAAD;KAAO,MAAK;KAAK,SAAQ;eACtB;IACI,CAAA;GAEH;;CACL,CAAA;AAET;;;ACtHA,IAAM,wBAAwB,cAAkC,KAAA,CAAS;AAEzE,IAAa,iCAAiC,WAAW,qBAAqB;AAE9E,IAAa,kBAAkB,EAC7B,QACA,4BACyB;CACzB,MAAM,EAAE,kBAAA,qBAAmB,qBAA4B,oBAAoB;CAE3E,OACE,oBAAC,sBAAsB,UAAvB;EAAgC,OAAO;YACrC,oBAAC,oBAAD,EAAkB,GAAI,sBAAwB,CAAA;CAChB,CAAA;AAEpC;;;ACxBA,IAAa,mCAAmC;CAC9C,MAAM,EAAE,MAAM,sBAAsB,4BAA4B;CAEhE,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,oBAAD,CAAqB,CAAA,GACrB,oBAAC,KAAD,EAAA,UAAI,EAAE,sCAAsC,EAAK,CAAA,CAC9C;;AAET;;;ACJA,IAAM,cAAY,eAAmC;CACnD,WAAW,UAAU,WAAW;CAChC,iBAAiB,UAAU;AAC7B;AAEA,IAAa,sCAAsC;CACjD,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,WAAW,oBAAoB,cAAc,OAAO,QAAQ,OAAO,UAAQ;CAEnF,IAAI,CAAC,gBAAgB,QAAQ,OAAO;CAEpC,OACE,qBAAC,UAAD;EACE,WAAW,KAAK,mCAAmC,EACjD,4CAA4C,UAC9C,CAAC;EACD,UAAU;EACV,eAAe,OAAO,QAAQ,OAAO;YALvC,CAOG,CAAC,aACA,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,aAAD,CAAc,CAAA,GACd,oBAAC,QAAD,EAAA,UACG,EAAE,+CAA+C,EAChD,OAAO,gBAAgB,OACzB,CAAC,EACG,CAAA,CACN,EAAA,CAAA,GAEH,aACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,kBAAD,CAAmB,CAAA,GACnB,oBAAC,QAAD,EAAA,UAAO,EAAE,uCAAuC,EAAQ,CAAA,CACxD,EAAA,CAAA,CAEE;;AAEZ;;;ACxCA,IAAM,cAAY,eAAmC,EACnD,eAAe,UAAU,WAAW,cACtC;AAEA,IAAa,mCAAmC;CAC9C,MAAM,EAAE,kBAAA,qBAAmB,qBAA4B,oBAAoB;CAC3E,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,kBAAkB,cAAc,OAAO,QAAQ,OAAO,UAAQ;CAEtE,IAAI,CAAC,eAAe,OAAO;CAE3B,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,oBAAD,CAAmB,CAAA;CAChB,CAAA;AAET;;;ACpBA,IAAa,yBAAyB;CACpC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,qBAAqB,oBAAoB;CACjD,MAAM,EAAE,iBAAiB,sBAAsB;CAC/C,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,OAAD;GAAK,WAAU;aAAwC,EAAE,SAAS;EAAO,CAAA,GACxE,gBAAgB,oBAAoB,oBAAC,kBAAD,CAAmB,CAAA,CACrD;;AAET;;;ACKA,IAAM,YAAY,eAAmC;CACnD,WAAW,UAAU,WAAW;CAChC,SAAS,UAAU;AACrB;AAEA,IAAM,kBAAmD,GAAG,SAAS,KAAK;AAM1E,IAAa,sBAAsB;CACjC,MAAM,EAAE,WAAW,eAAe;CAElC,gBAAgB;EACd,MAAM,+BAA+B;GACnC,IAAI,SAAS,oBAAoB,WAC/B,OAAO,QAAQ,SAAS;GAE1B,IAAI,SAAS,oBAAoB,UAC/B,OAAO,QAAQ,WAAW;EAE9B;EAEA,uBAAuB;EAEvB,SAAS,iBAAiB,oBAAoB,sBAAsB;EACpE,aAAa;GACX,OAAO,QAAQ,WAAW;GAC1B,SAAS,oBAAoB,oBAAoB,sBAAsB;EACzE;CACF,GAAG,CAAC,MAAM,CAAC;AACb;AAEA,IAAM,yBAAyB,kBAAiC;CAC9D,MAAM,CAAC,oBAAoB,yBAAyB,SAElD,CAAC,CAAC;CAEJ,gBAAgB;EAwBd,OAvBoB,cAAc,MAAM,uBACrC,UAAU,MAAM,UAChB,aAAa,oBAAoB;GAChC,IAAI,CAAC,iBAAiB;GAEtB,MAAM,kBAA8C,CAAC;GAErD,KAAK,MAAM,UAAU,aAAa;IAChC,IAAI,gBAAgB,SAAS,MAAM,GAAG;IAEtC,gBAAgB,OAAO,YAAY;KACjC,uBAAuB,OAAO;MAC5B,MAAM,OAAO,EAAE,GAAG,GAAG;MACrB,OAAO,KAAK,OAAO;MACnB,OAAO;KACT,CAAC;IACH;GACF;GAEA,sBAAsB,eAAe;EACvC,CAGK;CACT,CAAC;CAED,OAAO;AACT;AAEA,IAAa,cAAc,EAAE,oBAAqC;CAChE,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,MAAM,sBAAsB,YAAY;CAChD,MAAM,EACJ,kBAAkB,8BAA8B,kBAChD,4BAAA,+BAA6B,4BAC7B,gBAAA,mBAAiB,gBACjB,4BAAA,+BAA6B,4BAC7B,+BAAA,kCAAgC,kCAC9B,oBAAoB;CACxB,MAAM,EAAE,WAAW,YAAY,cAAc,OAAO,QAAQ,OAAO,QAAQ;CAE3E,MAAM,kBAAkB,sBAAsB,OAAO,OAAO;CAE5D,cAAc;CAEd,IAAI,aAAa,CAAC,QAAQ,QACxB,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,kBAAD,CAAmB,CAAA,GACnB,oBAAC,OAAD;GAAK,WAAU;aACb,oBAAC,iBAAD,CAAkB,CAAA;EACf,CAAA,CACF;;CAIT,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,kBAAD,CAAmB,CAAA;GAEnB,oBAAC,iCAAD,CAAgC,CAAA;GAChC,oBAAC,UAAD;IACE,cAAY,EAAE,kBAAkB;IAChC,sBAAsB,aAAa,YAAY,OAAO,QAAQ,aAAa;IAC3E,WAAU;IACV,YAAY;KACV,kBAAkB;KAClB,QAAQ;IACV;IACgB;IAChB,MAAM;IACN,cAAc,GAAG,WACf,oBAAC,kBAAD;KACU;KACR,uBAAuB,EACrB,mBAAmB,gBAAgB,OAAO,IAC5C;IACD,CAAA;IAEH,MAAK;IAGL,GAAI;GACL,CAAA;GACD,oBAAC,6BAAD,EAA6B,OAAM,cAAe,CAAA;EAC/C;;AAET;;;;;;;AC5HA,IAAa,0BACX,YACmB;CACnB,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,WAAW,aACd,UAAoC;EACnC,MAAM,gBAAgB,MAAM,cAAc,OAAO,wBAAwB;EAKzE,OAAO,EAAE,eAJa,SAAS,SAC3B,cAAc,OAAO,QAAQ,MAAM,IACnC,cAEmB;CACzB,GACA,CAAC,SAAS,MAAM,CAClB;CAEA,MAAM,EAAE,kBAAkB,cAAc,OAAO,cAAc,OAAO,QAAQ;CAE5E,OAAO;AACT;;;AClBA,IAAM,kBAAsE;CAC1E,OAAO;CACP,MAAM;CACN,SAAS;CACT,SAAS;CACT,SAAS;AACX;AAEA,IAAM,2BAA2B,EAAE,mBAA0C;CAC3E,IAAI,CAAC,aAAa,UAAU,OAAO;CAEnC,MAAM,OAAO,gBAAgB,aAAa,aAAa;CACvD,OACE,QACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,MAAD,CAAO,CAAA;CACJ,CAAA;AAGX;AAmBA,IAAa,eAAe,YAExB,EACE,WACA,gBACA,OAAO,yBACP,cACA,WACA,YAAY,OACZ,mBAEF,QACG;CACH,MAAM,EAAE,uBAAuB,mBAAmB;CAClD,MAAM,EAAE,MAAM,sBAAsB;CAEpC,MAAM,iBAAiB,EAAE,wCAAwC;EAC/D;EACA,OAAO,aAAa;CACtB,CAAC;CAED,MAAM,sBAAsB;EAC1B,IAAI,WAAW;GACb,UAAU;GACV;EACF;EAEA,mBAAmB,aAAa,EAAE;CACpC;CAEA,MAAM,eAAe,CAAC,aAAa;CAEnC,MAAM,WAAW,aAAa;CAC9B,MAAM,eAAe,aAAa,UAAU,cAAc;CAE1D,OACE,qBAAC,OAAD;EACE,WAAW,KACT,0BACA,kBAAkB,sCAAsC,kBACxD,oBAAoB,WAAW,uCAC/B,oBAAoB,UAAU,sCAC9B,YAAY,2BAA2B,YACvC,aAAa,aAAa,mCAC1B,SACF;EACA,eAAY;EACP;YAXP;GAaE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,QAAQ,oBAAC,MAAD,EAAoB,aAAe,CAAA,GAC5C,oBAAC,OAAD;KACE,eAAY;KACZ,aAAW;KACX,WAAU;KACV,MAAM,iBAAiB,cAAc,UAAU;eAE9C;IACE,CAAA,CACF;;GACJ,aAAa,WAAW,aAAa,QAAQ,SAAS,KACrD,oBAAC,OAAD;IAAK,WAAU;cACZ,aAAa,QAAQ,KAAK,QAAQ,UACjC,oBAAC,QAAD;KACE,YAAW;KACX,WAAU;KACV,cAAA;KAEA,eAAe;MACb,OAAO,QAAQ;KACjB;KACA,MAAK;KACL,SAAQ;eAEP,OAAO;IACF,GARD,KAQC,CACT;GACE,CAAA;IAEL,aAAa,iBACb,oBAAC,QAAD;IACE,YAAW;IACX,cAAY,EAAE,2BAA2B;IACzC,UAAA;IACA,WAAU;IACV,cAAA;IACA,SAAS;IACT,MAAK;IACL,SAAQ;cAER,oBAAC,WAAD,CAAY,CAAA;GACN,CAAA;EAEP;;AAET,CACF;AAEA,aAAa,cAAc;;;ACjF3B,IAAM,oBAAiF;CACrF,QAAQ;EAAE,GAAG;EAAM,GAAG;CAAO;CAC7B,MAAM;EAAE,GAAG;EAAS,GAAG;CAAK;CAC5B,OAAO;EAAE,GAAG;EAAQ,GAAG;CAAK;CAC5B,KAAK;EAAE,GAAG;EAAM,GAAG;CAAQ;AAC7B;AAEA,IAAM,oBAAoB;AAC1B,IAAM,yBAAyB;AAE/B,IAAM,eAAe,UACnB,UAAU,YAAY,UAAU,UAAU,UAAU,WAAW,UAAU;AAE3E,IAAM,4BACJ,cACA,sBACG;CACH,IAAI,CAAC,cAAc,OAAO;CAE1B,MAAM,oBAAoB,aAAa,UAAU;CACjD,IAAI,YAAY,iBAAiB,GAAG,OAAO;CAE3C,MAAM,kBAAkB,aAAa,OAAO,SAAS;CACrD,IAAI,YAAY,eAAe,GAAG,OAAO;CAEzC,OAAO;AACT;AAEA,IAAM,gBAAgB,iBAA+B,CAAC,aAAa;AAEnE,IAAM,gBAAgB,GAAwB,MAC5C,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,QAAQ,EAAE,SAAS,EAAE;;AAGzC,IAAa,cAA6B,eAAe,cAAc;CACrE,MAAM,YAAY,WAAW,MAAM;CACnC,IAAI,SAA8B;CAClC,KAAK,MAAM,gBAAgB,eAAe;EACxC,IAAI,aAAa,OAAO,WAAW;EACnC,IAAI,CAAC,UAAU,aAAa,YAAY,OAAO,WAC7C,SAAS;CAEb;CACA,OAAO;AACT;;AAGA,IAAa,cAA6B,eAAe,cAAc;CACrE,MAAM,YAAY,WAAW,MAAM;CACnC,IAAI,SAA8B;CAClC,KAAK,MAAM,gBAAgB,eAAe;EACxC,IAAI,aAAa,OAAO,WAAW;EACnC,IAAI,CAAC,UAAU,aAAa,YAAY,OAAO,WAC7C,SAAS;CAEb;CACA,OAAO;AACT;AAEA,IAAM,wBACJ,eACA,cACwB;CACxB,IAAI,SAA8B;CAClC,KAAK,MAAM,gBAAgB,eAAe;EACxC,IAAI,aAAa,OAAO,WAAW;EACnC,IAAI,CAAC,aAAa,YAAY,GAAG;EACjC,IAAI,CAAC,UAAU,aAAa,YAAY,OAAO,WAC7C,SAAS;CAEb;CACA,OAAO;AACT;AAEA,IAAM,oBACJ,eACA,MACA,cACwB;CACxB,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,SAA8B;CAClC,KAAK,MAAM,gBAAgB,eAAe;EACxC,IAAI,aAAa,OAAO,WAAW;EACnC,IAAI,aAAa,SAAS,MAAM;EAChC,IAAI,CAAC,UAAU,aAAa,YAAY,OAAO,WAC7C,SAAS;CAEb;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,yBACV,gBAA+B,gBAC/B,eAAe,cAAc;CAC5B,IAAI,cAAc,WAAW,GAAG,OAAO;CAEvC,MAAM,mBAAmB,qBAAqB,eAAe,IAAI;CAEjE,IAAI,CAAC,WACH,OAAO,oBAAoB,cAAc,eAAe,IAAI;CAI9D,IAAI,CADqB,cAAc,MAAM,EAAE,SAAS,OAAO,UAAU,EACpE,GACH,OAAO,oBAAoB,cAAc,eAAe,IAAI;CAG9D,IAAI,aAAa,SAAS,GAAG;EAG3B,MAAM,kBACJ,oBAAoB,iBAAiB,OAAO,UAAU,KAClD,mBACA,qBAAqB,eAAe,UAAU,EAAE;EACtD,IAAI,mBAAmB,gBAAgB,YAAY,UAAU,WAC3D,OAAO;EAET,OAAO;CACT;CAKA,MAAM,iBAAiB,iBAAiB,eAAe,UAAU,MAAM,UAAU,EAAE;CACnF,IAAI,gBAAgB,OAAO;CAG3B,IAAI,kBAAkB,OAAO;CAG7B,OAAO,cAAc,eAAe,SAAS,KAAK;AACpD;;AAGF,IAAM,kBAAkB,sBAAsB,UAAU;AAExD,IAAa,oBAAoB,EAC/B,WACA,YAAY,UACZ,eACA,QACA,eAAe,wBACf,OACA,WAAW,iBACX,oBAAoB,eACO;CAC3B,MAAM,EAAE,cAAc,wBAAwB,iBAC5C,oBAAoB;CACtB,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,oBAAoB,6BAA6B,mBAAmB;CAK5E,MAAM,iBAAiB,OAAsB,IAAI;CAKjD,MAAM,wBAAwB,OAAsB,IAAI;CACxD,MAAM,eAAe,OAA4B,IAAI;CACrD,MAAM,iBAAiB,OAAsB,IAAI;CACjD,MAAM,UAAU,OAA8B,IAAI;CAClD,MAAM,qBAAqB,OAA8B,IAAI;CAC7D,MAAM,uBAAuB,OAA2B,IAAI;CAE5D,IAAI,CAAC,qBAAqB,SACxB,qBAAqB,0BAAU,IAAI,IAAY;CAGjD,MAAM,CAAC,uBAAuB,4BAA4B,SACxD,IACF;CACA,MAAM,CAAC,iBAAiB,sBAAsB,SAA2B,OAAO;CAQhF,MAAM,gBAAgB,iBAAiB;EACrC,oBAAoB;EACpB;EACA,QAVqB,aACpB,iBAA+B;GAC9B,IAAI,yBAAyB,YAAY,GAAG,OAAO;GACnD,OAAO,SAAS,OAAO,YAAY,IAAI;EACzC,GACA,CAAC,MAAM,CAKC;EACR;CACF,CAAC;CAED,MAAM,UAAU,aACb,OAAe;EACd,qBAAqB,SAAS,OAAO,EAAE;EACvC,mBAAmB,EAAE;CACvB,GACA,CAAC,kBAAkB,CACrB;CAGA,gBAAgB;EACd,MAAM,kBAAkB,IAAI,IAAI,cAAc,KAAK,EAAE,SAAS,EAAE,CAAC;EAEjE,qBAAqB,SAAS,SAAS,OAAO;GAC5C,IAAI,CAAC,gBAAgB,IAAI,EAAE,GACzB,qBAAqB,SAAS,OAAO,EAAE;EAE3C,CAAC;CACH,GAAG,CAAC,aAAa,CAAC;CAElB,MAAM,0BAA0B,kBAAkB;EAChD,IAAI,sBAAsB,YAAY,MAAM;GAC1C,OAAO,aAAa,sBAAsB,OAAO;GACjD,sBAAsB,UAAU;EAClC;CACF,GAAG,CAAC,CAAC;CAGL,sBACc;EACV,wBAAwB;EACxB,IAAI,eAAe,YAAY,MAAM;GACnC,OAAO,aAAa,eAAe,OAAO;GAC1C,eAAe,UAAU;EAC3B;CACF,GACA,CAAC,uBAAuB,CAC1B;CAIA,gBAAgB;EACd,aAAa,UAAU,SAAS,eAAe,qBAAqB;CACtE,GAAG;EAAC;EAAuB;EAAe;CAAQ,CAAC;CA2BnD,gBAAgB;EAId,IAAI,oBAAoB,QAAQ;EAIhC,IAAI,CAAC,uBAAuB;GAC1B,MAAM,YAAY,SAAS,eAAe,IAAI;GAC9C,IAAI,WAAW;IACb,eAAe,UAAU,KAAK,IAAI;IAClC,yBAAyB,SAAS;IAClC,mBAAmB,OAAO;GAC5B;GACA;EACF;EAEA,MAAM,YAAY,SAAS,eAAe,qBAAqB;EAI/D,IAAI,CAAC,WAAW;GACd,wBAAwB;GACxB,mBAAmB,MAAM;GACzB,eAAe,UAAU,OAAO,iBAAiB;IAC/C,eAAe,UAAU;IACzB,eAAe,UAAU;IACzB,yBAAyB,IAAI;IAC7B,mBAAmB,OAAO;GAC5B,GAAG,iBAAiB;GACpB;EACF;EAKA,IAAI,UAAU,OAAO,sBAAsB,IAAI;GAC7C,wBAAwB;GACxB;EACF;EAEA,MAAM,mBAAmB,cAAc,MACpC,EAAE,SAAS,OAAO,sBAAsB,EAC3C;EAKA,MAAM,kBAAkB;GACtB,sBAAsB,UAAU;GAChC,mBAAmB,MAAM;GACzB,MAAM,aAAa,sBAAsB;GACzC,MAAM,aAAa;GACnB,eAAe,UAAU,OAAO,iBAAiB;IAC/C,eAAe,UAAU;IACzB,IAAI,YAAY;KAGd,qBAAqB,SAAS,OAAO,UAAU;KAC/C,mBAAmB,UAAU;IAC/B;IAIA,MAAM,OAAO,aAAa;IAC1B,IAAI,QAAQ,KAAK,OAAO,YAAY;KAClC,eAAe,UAAU,KAAK,IAAI;KAClC,yBAAyB,IAAI;KAC7B,mBAAmB,OAAO;IAC5B,OAAO;KACL,eAAe,UAAU;KACzB,yBAAyB,IAAI;KAC7B,mBAAmB,OAAO;IAC5B;GACF,GAAG,iBAAiB;EACtB;EAIA,IAAI,CAAC,kBAAkB;GACrB,wBAAwB;GACxB,UAAU;GACV;EACF;EAKA,IAAI,aAAa,uBAAuB,SAAS,GAAG;GAClD,wBAAwB;GACxB,UAAU;GACV;EACF;EAKA,MAAM,UAAU,eAAe,UAAU,KAAK,IAAI,IAAI,eAAe,UAAU;EAC/E,MAAM,YAAY,KAAK,IAAI,GAAG,eAAe,OAAO;EAEpD,IAAI,cAAc,GAAG;GAEnB,wBAAwB;GACxB,UAAU;EACZ,OAAO,IAAI,sBAAsB,YAAY,MAM3C,sBAAsB,UAAU,OAAO,WAAW,WAAW,SAAS;CAE1E,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,eAAe;CACrB,MAAM,wBAAwB,yBAAyB,cAAc,SAAS;CAE9E,gBAAgB;EACd,MAAM,UAAU,mBAAmB;EACnC,IAAI,CAAC,WAAW,CAAC,gBAAgB,oBAAoB,QAAQ;EAE7D,MAAM,qBAAqB;GACzB,IACE,CAAC,qBAAqB,WACtB,qBAAqB,QAAQ,IAAI,aAAa,EAAE,GAEhD;GAEF,qBAAqB,QAAQ,IAAI,aAAa,EAAE;GAChD,yBAAyB,aAAa,EAAE;EAC1C;EAEA,IAAI,OAAO,yBAAyB,aAAa;GAC/C,aAAa;GACb;EACF;EAEA,MAAM,WAAW,IAAI,sBAClB,YAAY;GACX,MAAM,CAAC,SAAS;GAChB,IAAI,CAAC,OAAO,gBAAgB;GAE5B,aAAa;GACb,SAAS,WAAW;EACtB,GACA;GACE,MAAM,QAAQ;GACd,WAAW;EACb,CACF;EAEA,SAAS,QAAQ,OAAO;EAExB,aAAa;GACX,SAAS,WAAW;EACtB;CACF,GAAG;EAAC;EAAc;EAA0B;CAAe,CAAC;CAE5D,IAAI,CAAC,cAAc,OAAO;CAE1B,OACE,qBAAC,OAAD;EACE,cAAY,EAAE,oBAAoB;EAClC,WAAW,KACT,+BACA,2CAA2C,yBAC3C,yCAAyC,qBACzC,SAAS,gCAAgC,SACzC,SACF;EACA,eAAY;EACZ,KAAK;EACL,MAAK;EACL,OACE;GACE,yCACE,kBAAkB,uBAAuB;GAC3C,yCACE,kBAAkB,uBAAuB;EAC7C;YAlBJ;GAqBE,oBAAC,OAAD;IACE,eAAA;IACA,WAAU;GACX,CAAA;GACD,oBAAC,uBAAD;IACE,gBAAgB;IAEF;IACd,iBAAiB,QAAQ,aAAa,EAAE;IACxC,MAAM,YAAY;KAChB,mBAAmB,UAAU;IAC/B;IACA,WAAW,CAAC,aAAa;IACR;GAClB,GARM,aAAa,EAQnB;GACD,oBAAC,OAAD;IACE,eAAA;IACA,WAAU;GACX,CAAA;EACE;;AAET;;;AC7hBA,IAAM,8BAA8B;AACpC,IAAM,4BAA4B;AAElC,IAAM,2BAA2B,iBAC/B,aAAa,aAAa,UAAU,cAAc;AAEpD,IAAM,oBAAoB,iBAA+B;CACvD,IAAI,CAAC,aAAa,UAAU,OAAO;CACnC,OAAO,GAAG,aAAa,SAAS,GAAG,YAAY,IAAI,aAAa,SAAS,MAAM,CAAC;AAClF;AAEA,IAAM,iCAAiC,cAA4B,YAAoB;CACrF,MAAM,gBAAgB,iBAAiB,YAAY;CAEnD,IAAI,eACF,OAAO,GAAG,cAAc,iBAAiB;CAG3C,OAAO,iBAAiB;AAC1B;AAOA,IAAM,wCAAyE,EAC7E,qBACI;AACN,IAAM,kCAAkE;AAExE,IAAa,yBAAyB,EACpC,gCAAgC,sCAChC,qBAAqB,gCACW;CAChC,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,gBAAgB,iBAAiB;CACvC,MAAM,CAAC,mBAAmB,wBAAwB,SAA+B,CAAC,CAAC;CACnF,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CACtD,MAAM,CAAC,oBAAoB,yBAAyB,SAAS,EAAE;CAC/D,MAAM,CAAC,uBAAuB,4BAA4B,SAAS,EAAE;CACrE,MAAM,iBAAiB,OAAO,KAAK;CACnC,MAAM,yBAAyB,uBAAO,IAAI,IAAY,CAAC;CACvD,MAAM,qBAAqB,OAA6C,IAAI;CAC5E,MAAM,oBAAoB,OAA6C,IAAI;CAE3E,MAAM,gBAAgB,kBAAkB;EACtC,IAAI,mBAAmB,SAAS;GAC9B,aAAa,mBAAmB,OAAO;GACvC,mBAAmB,UAAU;EAC/B;EAEA,IAAI,kBAAkB,SAAS;GAC7B,aAAa,kBAAkB,OAAO;GACtC,kBAAkB,UAAU;EAC9B;CACF,GAAG,CAAC,CAAC;CAEL,sBACc;EACV,cAAc;CAChB,GACA,CAAC,aAAa,CAChB;CAEA,gBAAgB;EACd,MAAM,yBAAyB,IAAI,IAAI,cAAc,KAAK,EAAE,SAAS,EAAE,CAAC;EAExE,uBAAuB,QAAQ,SAAS,OAAO;GAC7C,IAAI,CAAC,uBAAuB,IAAI,EAAE,GAChC,uBAAuB,QAAQ,OAAO,EAAE;EAE5C,CAAC;EAED,IAAI,CAAC,eAAe,SAAS;GAC3B,cAAc,SAAS,EAAE,SAAS;IAChC,uBAAuB,QAAQ,IAAI,EAAE;GACvC,CAAC;GACD,eAAe,UAAU;GACzB;EACF;EAEA,MAAM,oBAA0C,CAAC;EAEjD,cAAc,SAAS,iBAAiB;GACtC,IAAI,uBAAuB,QAAQ,IAAI,aAAa,EAAE,GAAG;GAEzD,uBAAuB,QAAQ,IAAI,aAAa,EAAE;GAClD,IAAI,CAAC,mBAAmB,YAAY,GAAG;GAEvC,MAAM,UAAU,EAAE,wCAAwC;IACxD;IACA,OAAO,aAAa;GACtB,CAAC;GAED,IAAI,CAAC,SAAS;GAGd,MAAM,sBAAsB,8BAA8B;IACxD,gBAFqB,8BAA8B,cAAc,OAEjE;IACA;IACA,mBAAmB;GACrB,CAAC;GAED,IAAI,CAAC,qBAAqB;GAE1B,kBAAkB,KAAK;IACrB,IAAI,aAAa;IACjB,SAAS;IACT,UAAU,wBAAwB,YAAY;GAChD,CAAC;EACH,CAAC;EAED,IAAI,CAAC,kBAAkB,QAAQ;EAE/B,sBAAsB,iBAAiB,CAAC,GAAG,cAAc,GAAG,iBAAiB,CAAC;CAChF,GAAG;EAAC;EAA+B;EAAoB;EAAe;CAAC,CAAC;CAExE,gBAAgB;EACd,IAAI,cAAc;EAElB,MAAM,mBAAmB,kBAAkB;EAC3C,IAAI,CAAC,kBAAkB;EAEvB,gBAAgB,IAAI;EACpB,cAAc;EACd,sBAAsB,EAAE;EACxB,yBAAyB,EAAE;EAE3B,mBAAmB,UAAU,iBAAiB;GAC5C,IAAI,iBAAiB,aAAa,aAChC,yBAAyB,iBAAiB,OAAO;QAEjD,sBAAsB,iBAAiB,OAAO;GAGhD,kBAAkB,UAAU,iBAAiB;IAC3C,sBAAsB,iBACpB,aAAa,QAAQ,EAAE,SAAS,OAAO,iBAAiB,EAAE,CAC5D;IACA,gBAAgB,KAAK;IACrB,kBAAkB,UAAU;GAC9B,GAAG,yBAAyB;GAE5B,mBAAmB,UAAU;EAC/B,GAAG,2BAA2B;CAChC,GAAG;EAAC;EAAmB;EAAe;CAAY,CAAC;CAEnD,OACE,qBAAC,gBAAD;EAAgB,eAAY;YAA5B,CACE,oBAAC,OAAD;GAAK,eAAY;GAAO,aAAU;GAAS,MAAK;aAC7C;EACE,CAAA,GACL,oBAAC,OAAD;GAAK,eAAY;GAAO,aAAU;GAAY,MAAK;aAChD;EACE,CAAA,CACS;;AAEpB;;;AClLA,IAAM,mCAAmC;AAEzC,IAAM,iCACJ,SACA,cACY;CACZ,MAAM,gBAAgB,QAAQ,MAAM;CAEpC,IAAI,CAAC,QAAQ,MAAM,CAAC,iBAAiB,kBAAkB,WACrD,OAAO;CAGT,OACE,QAAQ,SAAS,aACjB,QAAQ,SAAS,eACjB,QAAQ,SAAS,WACjB,QAAQ,SAAS,YACjB,QAAQ,WAAW,YACnB,QAAQ,WAAW;AAEvB;AAEA,IAAM,iBACJ,SACA,MACG,QAAQ,MAAM,MAAM,KAAK,KAAK,QAAQ,MAAM,MAAM,EAAE,WAAW;AASpE,IAAa,mCAAmC,EAC9C,gBACA,SACA,WACA,aAAa,YAC8B;CAC3C,MAAM,WAAW,qBAAqB;CACtC,MAAM,EAAE,MAAM,sBAAsB,iCAAiC;CACrE,MAAM,+BAA+B,OAAO,CAAC;CAC7C,MAAM,kBAAkB,OAAkD,KAAA,CAAS;CACnF,MAAM,yBAAyB,uBAAO,IAAI,IAAY,CAAC;CACvD,MAAM,8BAA8B,OAGjC;EACD,OAAO;EACP,aAAa;CACf,CAAC;CAED,MAAM,4BAA4B,kBAAkB;EAClD,MAAM,2BAA2B,4BAA4B;EAE7D,IAAI,yBAAyB,SAAS,GAAG;EAEzC,IAAI,yBAAyB,UAAU,GACrC,SACE,EAAE,6BAA6B,EAC7B,MAAM,yBAAyB,eAAe,EAAE,WAAW,EAC7D,CAAC,CACH;OAEA,SAAS,EAAE,0BAA0B,EAAE,OAAO,yBAAyB,MAAM,CAAC,CAAC;EAGjF,yBAAyB,QAAQ;EACjC,yBAAyB,cAAc;EACvC,6BAA6B,UAAU,KAAK,IAAI;CAClD,GAAG,CAAC,UAAU,CAAC,CAAC;CAEhB,MAAM,gBAAgB,kBAAkB;EACtC,IAAI,gBAAgB,SAAS;EAG7B,MAAM,+BADM,KAAK,IACoB,IAAM,6BAA6B;EAExE,IAAI,gCAAgC,kCAAkC;GACpE,0BAA0B;GAC1B;EACF;EAEA,gBAAgB,UAAU,iBAAiB;GACzC,gBAAgB,UAAU,KAAA;GAC1B,0BAA0B;EAC5B,GAAG,mCAAmC,4BAA4B;CACpE,GAAG,CAAC,yBAAyB,CAAC;CAE9B,sBACc;EACV,IAAI,gBAAgB,SAClB,aAAa,gBAAgB,OAAO;CAExC,GACA,CAAC,CACH;CAEA,gBAAgB;EACd,IAAI,CAAC,SACH;EAGF,MAAM,oBAAoB,UAAiB;GACzC,MAAM,UAAU,MAAM;GACtB,IAAI,CAAC,SAAS;GAEd,IACG,MAAM,OAAO,MAAM,QAAQ,QAAQ,OACpC,CAAC,8BAA8B,SAAS,SAAS,GAEjD;GAGF,MAAM,UAAU,CAAC,CAAC,QAAQ;GAC1B,MAAM,wBACJ,CAAC,CAAC,kBAAkB,QAAQ,cAAc;GAI5C,IAAI,EAH+B,cAAc,0BAGd,EAFF,CAAC,cAAc,CAAC,UAG/C;GAGF,IAAI,uBAAuB,QAAQ,IAAI,QAAQ,MAAM,EAAE,GACrD;GAGF,IAAI,QAAQ,IAAI;IACd,IAAI,uBAAuB,QAAQ,OAAO,KACxC,uBAAuB,QAAQ,MAAM;IAEvC,uBAAuB,QAAQ,IAAI,QAAQ,EAAE;GAC/C;GAEA,4BAA4B,QAAQ,SAAS;GAC7C,IAAI,CAAC,4BAA4B,QAAQ,aACvC,4BAA4B,QAAQ,cAAc,cAAc,SAAS,CAAC;GAG5E,cAAc;EAChB;EAEA,MAAM,eAAe,QAAQ,GAAG,eAAe,gBAAgB;EAE/D,aAAa;GACX,aAAa,YAAY;GACzB,IAAI,gBAAgB,SAAS;IAC3B,aAAa,gBAAgB,OAAO;IACpC,gBAAgB,UAAU,KAAA;GAC5B;EACF;CACF,GAAG;EAAC;EAAgB;EAAS;EAAW;EAAe;EAAG;CAAU,CAAC;AACvE;;;;;;;ACrJA,SAAgB,+BAA8C;CAC5D,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,SAAS,eAAe,MAAM,uBAAuB;CAC7D,MAAM,EAAE,cAAc,cAAc,MAAM,SAAS,QAAQ,CAAC;CAG5D,MAAM,CAAC,UAAU,eAAe,eAC9B,OAAO,OAAO,CAAC,GAAG,SAAS,OAAO,YAAY,CAAC,CAAC,CAClD;CAEA,gBAAgB;EACd,IAAI,CAAC,SAAS;EACd,MAAM,eAAe,QAAQ,GAAG,wBAAwB,UAAU;GAChE,aAAa,SAAS;IACpB,IAAI,CAAC,MAAM,MAAM,IAAI,OAAO;IAC5B,IAAI,KAAK,MAAM,KAAK,KAAK,OAAO;IAChC,OAAO,OAAO,OAAO,GAAG,MAAM,KAAK,KAAK,MAAM,KAAK,GAAG,IAAI;GAC5D,CAAC;EACH,CAAC;EACD,aAAa,aAAa,YAAY;CACxC,GAAG,CAAC,OAAO,CAAC;CAEZ,IAAI,CAAC,aAAa,OAAO;CASzB,IANE,gBAAgB,KACf,gBAAgB,KACf,OAAO,OAAO,SAAS,OAAO,WAAW,CAAC,CAAC,EAAE,MAC1C,EAAE,WAAW,MAAM,OAAO,OAAO,MAAM,EAC1C,GAIF,OADoB,OAAO,KAAK,QAAQ,EAAE,SAAS,IAC9B,EAAE,QAAQ,IAAI,EAAE,SAAS;CAGhD,OAAO,GAAG,EAAE,6BAA6B,EAAE,YAAY,CAAC,EAAE,IAAI,EAAE,6BAA6B,EAAE,aAAa,CAAC;AAC/G;;;ACtCA,IAAM,8BAA8B;CAClC,MAAM,EAAE,kBAAkB,uBAAuB,uBAAuB;CACxE,MAAM,EAAE,WAAW,eAAe,uBAAuB;CACzD,MAAM,EAAE,SAAS,CAAC,MAAM,iBAAiB,uBAAuB;CAChE,MAAM,mBAAmB,6BAA6B;CACtD,MAAM,kBAAkB,OAAO,OAAO,MAAM,EAAE,QAC3C,EAAE,WAAW,WAAW,MAAM,OAAO,OAAO,MAAM,MAAM,CAAC,SAC5D;CACA,MAAM,YAAY,eAAe,kBAAkB,SAAS,gBAAgB,SAAS;CAErF,IAAI,CAAC,aAAa,CAAC,kBAAkB,OAAO;CAE5C,OACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,QAAD;GACE,WAAU;aAGT,YAAY,oBAAC,uBAAD,CAAwB,CAAA,IAAI;EACrC,GAHC,YAAY,WAAW,SAGxB;CACH,CAAA;AAET;;;;AAcA,IAAa,iBAAiB,UAA8B;CAC1D,MAAM,EAAE,SAAS,eAAe,OAAO,eAAe,OAAO,kBAAkB;CAE/E,MAAM,EAAE,YAAY,uBAAuB;CAC3C,MAAM,EAAE,uBAAuB,oBAAoB;CACnD,MAAM,EAAE,cAAc,cAAc,4BAA4B,sBAAsB;EACpF;EACA;EACA;CACF,CAAC;CAED,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,oBAAC,OAAD;IAAK,WAAU;cACZ,sBAAsB,oBAAC,oBAAD,CAAqB,CAAA;GACzC,CAAA;GACL,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KAAK,WAAU;eAAyC;IAAkB,CAAA,GAC1E,oBAAC,uBAAD,CAAwB,CAAA,CACrB;;GACL,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,QAAD;KACE,WAAU;KACV,gBAAgB,yBAAyB;KACzC,UAAU;KACV,MAAK;KACL,UAAU;IACX,CAAA;GACE,CAAA;EACF;;AAET;;;ACvCA,IAAM,qBAAqB,aACzB,SAAS,WAAW,GAAG,IAAI,SAAS,MAAM,CAAC,IAAI;AACjD,IAAM,mBAAmB,UACvB,MAAM,QAAQ,WAAW,MAAM,QAAQ,OAAO,MAAM,QAAQ;AAO9D,IAAM,sBACJ,UACA,yBACG;CACH,MAAM,gBAAgB,SAAS,eAAe,QAAQ;CACtD,IAAI,CAAC,eAAe;CAEpB,MAAM,uBAAuB,cAAc,aAAa,UAAU;CAClE,IAAI,CAAC,sBACH,cAAc,aAAa,YAAY,IAAI;CAG7C,cAAc,MAAM;CAEpB,IAAI,CAAC,sBAAsB;EACzB,MAAM,uBAAuB,qBAAqB,QAAQ,IAAI,aAAa;EAC3E,IAAI,sBACF,qBAAqB,QAAQ;EAG/B,MAAM,mBAAmB;GACvB,cAAc,gBAAgB,UAAU;GACxC,qBAAqB,QAAQ,OAAO,aAAa;EACnD;EAEA,cAAc,iBAAiB,QAAQ,YAAY,EAAE,MAAM,KAAK,CAAC;EAEjE,qBAAqB,QAAQ,IAAI,eAAe;GAC9C,eAAe,cAAc,oBAAoB,QAAQ,UAAU;GACnE,sBAAsB;EACxB,CAAC;CACH;AACF;AAEA,IAAa,kBAAkB,EAC7B,WACA,cACA,SACA,WACA,WACA,GAAG,kBACsB;CACzB,MAAM,uBAAuB,uBAA4C,IAAI,IAAI,CAAC;CAElF,sBACc;EACV,qBAAqB,QAAQ,SAC1B,EAAE,SAAS,wBAAwB,kBAAkB;GACpD,QAAQ;GACR,IAAI,wBAAwB,cAAc,aAAa,UAAU,MAAM,MACrE,cAAc,gBAAgB,UAAU;EAE5C,CACF;EAEA,qBAAqB,QAAQ,MAAM;CACrC,GACA,CAAC,CACH;CAEA,IAAI,CAAC,UAAU,QAAQ,OAAO;CAE9B,MAAM,eAAe,OAA4C,aAAqB;EACpF,UAAU,KAAK;EACf,IAAI,MAAM,kBAAkB;EAG5B,mBAAmB,UAAU,oBAAoB;CACnD;CACA,MAAM,iBACJ,OACA,aACG;EACH,YAAY,KAAK;EACjB,IAAI,MAAM,oBAAoB,CAAC,gBAAgB,KAAK,GAAG;EAEvD,MAAM,eAAe;EACrB,mBAAmB,UAAU,oBAAoB;CACnD;CAEA,OACE,oBAAA,YAAA,EAAA,UACG,UAAU,KAAK,UAAU,UAAU;EAClC,MAAM,qBAAqB,kBAAkB,QAAQ;EACrD,MAAM,YACJ,eAAe,oBAAoB,KAAK,KAAK,WAAW;EAE1D,OACE,8BAAC,KAAD;GACE,GAAI;GACJ,WAAW,CAAC,kCAAkC,SAAS,EACpD,OAAO,OAAO,EACd,KAAK,GAAG;GACX,MAAM,IAAI;GACV,KAAK,GAAG,mBAAmB,GAAG;GAC9B,UAAU,UAAU,YAAY,OAAO,kBAAkB;GACzD,YAAY,UAAU,cAAc,OAAO,kBAAkB;EAG5D,GADA,SACA;CAEP,CAAC,EACD,CAAA;AAEN;;;AC/HA,IAAa,WAAW,EACtB,QACA,kBAAkB,MAClB,mBACmB;CACnB,MAAM,CAAC,aAAa,kBAAkB,SAAkC;EACtE,GAAG;EACH,iBAAiB;EACjB,cAAc;CAChB,CAAC;CAED,MAAM,CAAC,SAAS,cAAc,SAAkB;CAChD,MAAM,CAAC,OAAO,YAAY,SAAsB,CAAC,CAAC;CAClD,MAAM,CAAC,8BAA8B,mCAAmC,SAAS,CAAC,CAAC;CAEnF,MAAM,cAAe,OAAO,MAA0B,SAAS,CAAC;CAEhE,MAAM,cAAc,OAA+C,IAAI;CAEvE,MAAM,uBAAuB;EAC3B,IAAI,YAAY,SACd,OAAO,YAAY;EAErB,YAAY,UAAU,OAAO,eAAe;EAC5C,OAAO,YAAY;CACrB;CAEA,gBAAgB;EACd,IAAI,CAAC,QAAQ;EAEb,MAAM,UAAA;EAEN,MAAM,YAAY,OAAO,aAAa;EACtC,IAAI,CAAC,UAAU,SAAS,mBAAmB,GAGzC,OAAO,aAAa,qBAAqB,QAAQ,GAAG,WAAW;EAGjE,OAAO,QAAQ,sBAAsB;EACrC,OAAO,MAAM,sBAAsB;EACnC,OAAO,UAAU,sBAAsB;EACvC,OAAO,UAAU,WAAW;EAE5B,aAAa;GACX,OAAO,QAAQ,wBAAwB;GACvC,OAAO,MAAM,wBAAwB;GACrC,OAAO,UAAU,wBAAwB;GACzC,OAAO,UAAU,YAAY;EAC/B;CACF,GAAG,CAAC,MAAM,CAAC;CAEX,gBAAgB;EACd,SAAS,WAAW;EAEpB,MAAM,eAAe,UAAiB;GACpC,SAAS,MAAM,IAAI,SAAS,CAAC,CAAC;EAChC;EAEA,OAAO,GAAG,8BAA8B,WAAW;EACnD,aAAa,OAAO,IAAI,8BAA8B,WAAW;CAEnE,GAAG,CAAC,aAAa,MAAM,CAAC;CAExB,gBAAgB;EACd,IAAI,eAAe,OAAO,MAAM;EAEhC,IAAI,CAAC,cAAc;GACjB,MAAM,kBAAkB,OAAO,UAAU,SAAS,MAAM,GAAG,CAAC;GAC5D,eAAe,oBAAoB,eAAe,IAC9C,kBACA;EACN;EAEA,MAAM,aAAa,gBAAgB,IAAI,WAAW,EAAE,UAAU,aAAa,CAAC;EAE5E,WAAW,6BAA6B,MACtC,gBAAgB,oBAAoB;GAAE,GAAG;GAAgB;EAAE,EAAE,CAC/D;EAEA,WAAW,eAAe,EAAE,MAAM,eAAe;GAC/C,eAAe;IACb,GAAG;IACH,cAAc,gBAAgB;GAChC,CAAC;EACH,CAAC;CAEH,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,mBAAmB,YACvB,OACE,eACA,WAAgD,CAAC,GACjD,UACG;EACH,IAAI,SAAS,MAAM,gBAAgB,MAAM,eAAe;EAExD,IAAI,iBAAiB,OAAO,KAAK,QAAQ,EAAE,QACzC,MAAM,cAAc,MAAM;GAAE,OAAO;GAAM;EAAS,CAAC;EAGrD,WAAW,aAAa;CAC1B,GACA,CAAC,CACH;CAEA,gBAAgB;EACd,gCAAgC,CAAC,CAAC;CACpC,GAAG,CAAC,OAAO,MAAM,EAAE,CAAC;CAEpB,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;ACtIA,IAAa,kDAAkD;CAC7D,MAAM,EAAE,MAAM,sBAAsB;CACpC,MAAM,EAAE,WAAW,eAAe;CAClC,MAAM,EAAE,uBAAuB,uBAAuB,mBAAmB;CACzE,MAAM,kCAAkC,OAAsB,IAAI;CAElE,gBAAgB;EACd,IAAI,CAAC,KAAK,CAAC,QAAQ;EAEnB,MAAM,0CAA0C;GAC9C,IAAI,CAAC,gCAAgC,SAAS;GAC9C,mBAAmB,gCAAgC,OAAO;GAC1D,gCAAgC,UAAU;EAC5C;EAEA,MAAM,2BAA2B,EAAE,aAAmC;GACpE,IAAI,CAAC,QAAQ;IACX,IAAI,gCAAgC,SAAS;IAE7C,gCAAgC,UAAU,sBAAsB;KAC9D,UAAU;KACV,SAAS;KACT,SAAS,EAAE,sBAAsB;KACjC,UAAU;KACV,MAAM;IACR,CAAC;IACD;GACF;GAEA,kCAAkC;EACpC;EAEA,OAAO,GAAG,sBAAsB,uBAAuB;EAEvD,aAAa;GACX,OAAO,IAAI,sBAAsB,uBAAuB;GACxD,kCAAkC;EACpC;CACF,GAAG;EAAC;EAAuB;EAAQ;EAAoB;CAAC,CAAC;AAC3D;;;AC7CA,IAAa,wBAAwB,UAA4B;CAC/D,MAAM,EACJ,SACA,oBACA,QACA,eACA,gBACA,sBACA,8BACA,OACA,kBACA,kBACA,OACA,gCACE;CAEJ,MAAM,aAAa,SAAS;CAC5B,MAAM,qBAAqB,mBAAmB;CAC9C,MAAM,0BAA0B,mBAAmB;CACnD,MAAM,eAAe,GAAG,OAAO,WAAW,OAAO,KAAK,OAAO,cAAc,EAAE,SAC3E,OAAO,KAAK,OAAO,SAAS,EAAE,SAC7B,OAAO,cAAc,OAAO;IAC7B,OAAO,MAAM;CACf,MAAM,mBAAmB,MAAM;CA8B/B,OA5BsC,eAC7B;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAGK;AACT;;;ACzCA,IAAa,8BAAkD;CAC7D,MAAM,CAAC,OAAO,YAAY,SAAqD,IAAI;CACnF,MAAM,CAAC,iBAAiB,sBACtB,SAA4B,eAAe;CAE7C,OAAO;EACL;EACA;EACA;EACA;CACF;AACF;;;ACCA,IAAM,8CAA8C;CAClD,0CAA0C;CAC1C,OAAO;AACT;AAEA,IAAM,0CACH,iBACA,EAAE,cAAc,YAAY;CAG3B,IAFqB,4BAA4B,YAE7C,EAAa,SAAS,OAAO,GAC/B,OAAO,UAAU;CAGnB,IAAI,CAAC,aAAa,OAAO;CAEzB,OAAO,UAAU;AACnB;AAEF,IAAM,kCAAkC,EACtC,UACA,gCAGK;CACL,MAAM,cAAc,qBAAqB;CAOzC,OACE,oBAAC,mCAAD;EAAkD,eAP9B,cAElB,6BAA6B,uCAAuC,WAAW,GACjF,CAAC,aAAa,yBAAyB,CAIW;EAC/C;CACgC,CAAA;AAEvC;;;;;AA+BA,IAAa,QAAQ,UAAwC;CAC3D,MAAM,EACJ,UACA,QACA,eACA,iBACA,cACA,sBACA,2BACA,kBAAkB,+BAClB,QAAQ,mBACR,8BAA8B,UAC5B;CAEJ,MAAM,EACJ,SACA,gBACA,8BACA,OACA,kBACA,gBACE,QAAQ;EACV;EACA;EACA;CACF,CAAC;CAiBD,MAAM,mBAAmB,qBAAqB;EAC5C;EACA,oBAjByB,sBAiBzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA,kBAtBuB,cAErB,iCACA,IAAI,iBAAiB,EACnB,SAAS;GACP,IAAI,oBAAoB,MAAM;GAC9B,IAAI,iBAAiB,MAAM;GAC3B,IAAI,oBAAoB,MAAM;EAChC,EACF,CAAC,GACH,CAAC,QAAQ,6BAA6B,CAYtC;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,EAAE,uBAAA,0BAAwB,0BAAiC,oBAAoB;CAErF,IAAI,CAAC,YAAY,GAAG,OAAO;CAE3B,OACE,oBAAC,cAAD;EAAc,OAAO;YACnB,oBAAC,qBAAD;GAAqB,OAAO;aAC1B,oBAAC,4BAAD,EAAA,UACE,qBAAC,gCAAD;IAC6B;cAD7B;KAGE,oBAAC,uCAAD,CAAwC,CAAA;KACxC,oBAAC,yBAAD,CAAwB,CAAA;KACvB;IAC6B;MACN,CAAA;EACT,CAAA;CACT,CAAA;AAElB;;;;;;AC9JA,IAAa,uBAAuB,EAClC,QACA,SACA,iBACA,eAMI;CACJ,MAAM,CAAC,YAAY,iBAAiB,SAA4B,IAAI;CACpE,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,QAAQ;CAE7D,IAAI,SAAS,OAAO,eAAe,IACjC,kBAAkB,QAAQ;CAG5B,MAAM,CAAC,iBAAiB,SAAS,OAAO;CAExC,gBAAgB;EACd,MAAM,SAAS,IAAI,WAAW,QAAQ,KAAA,GAAW,aAAa;EAC9D,IAAI,0BAA0B;EAE9B,MAAM,oBAAoB,OACvB,YAAY,gBAAgB,eAAe,EAC3C,WAAW;GACV,IAAI,CAAC,yBAAyB,cAAc,MAAM;EACpD,CAAC;EAEH,aAAa;GACX,0BAA0B;GAC1B,cAAc,IAAI;GAClB,kBACG,WAAW,OAAO,eAAe,CAAC,EAClC,WAAW;IACV,QAAQ,IAAI,wBAAwB,eAAe,GAAG,kBAAkB;GAC1E,CAAC;EACL;CACF,GAAG;EAAC;EAAQ;EAAgB;EAAe;CAAe,CAAC;CAE3D,OAAO;AACT;;;AC5CA,IAAM,oBAAoB,UAA0C;CAClE,MAAM,EAAE,UAAU,QAAQ,eAAe;CAEzC,MAAM,EAAE,QAAQ,kBAAkB,uBAAuB,QAAQ;CAEjE,OACE,oBAAC,OAAD;EACE,WAAW,KAAK,wBAAwB,EACtC,qCAAqC,iBAAiB,WACxD,CAAC;EAEA;CACE,CAAA;AAET;;;;AAKA,IAAa,SAAS,MAAM,KAAK,gBAAgB"}