@vkontakte/calls-sdk 2.8.9 → 2.8.10-dev.93a79a4b.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/CallsSDK.ts", "../src/abstract/BaseLogger.ts", "../src/classes/EventEmitter.ts", "../src/abstract/BaseSignaling.ts", "../src/enums/HangupType.ts", "../src/classes/HangupReason.ts", "../src/classes/Logger.ts", "../src/classes/ProducerCommandSerializationService.ts", "../src/enums/SignalingCommandType.ts", "../src/enums/FatalError.ts", "../src/enums/MediaOption.ts", "../src/enums/StatLog.ts", "../src/classes/codec/LibVPxDecoder.ts", "../src/classes/codec/WorkerBase.ts", "../src/classes/codec/WebCodecsDecoder.ts", "../src/classes/FpsMeter.ts", "../src/classes/screenshare/BaseStreamBuilder.ts", "../src/enums/UserType.ts", "../src/static/SimulcastInfo.ts", "../src/static/Polyfills.ts", "../src/static/Utils.ts", "../src/enums/Stat.ts", "../src/classes/transport/Statistics.ts", "../src/classes/stat/StatAggregator.ts", "../src/classes/stat/StatScreenShareFirstFrame.ts", "../src/classes/screenshare/BaseRenderer.ts", "../src/classes/screenshare/CanvasRenderer.ts", "../src/classes/screenshare/TrackGeneratorRenderer.ts", "../src/classes/screenshare/StreamBuilder.ts", "../src/classes/screenshare/Utils.ts", "../src/classes/screenshare/WebmBuilder.ts", "../src/classes/screenshare/ScreenCaptureReceiver.ts", "../src/utils/FastList.ts", "../src/classes/codec/LibVPxEncoder.ts", "../src/classes/codec/WebCodecsEncoder.ts", "../src/classes/screenshare/ScreenCongestionControl.ts", "../src/classes/screenshare/PacketHistory.ts", "../src/classes/screenshare/ScreenCaptureSender.ts", "../src/static/AuthData.ts", "../src/static/Params.ts", "../src/types/MediaSettings.ts", "../src/utils/Media.ts", "../src/classes/VideoEffectsFpsLimiter.ts", "../src/classes/MediaSource.ts", "../src/utils/NavigatorPermissions.ts", "../src/static/External.ts", "../src/static/LocalStorage.ts", "../src/static/WebRTCUtils.ts", "../src/static/ConversationDebugLogger.ts", "../src/utils/ArrayList.ts", "../src/utils/DebugStorage.ts", "../src/static/Debug.ts", "../src/types/LayoutUtils.ts", "../src/types/ParticipantStreamDescription.ts", "../src/utils/MsgPackerBufferUtils.ts", "../src/enums/SignalingTransportStat.ts", "../src/utils/P2Quantile.ts", "../src/utils/Welford.ts", "../src/utils/StatTracker.ts", "../src/enums/SignalingEvent.ts", "../src/enums/SignalingNotification.ts", "../src/enums/DataChannelLabel.ts", "../src/types/VideoSettings.ts", "../src/types/ServerSettings.ts", "../src/classes/stat/CodecStatsAggregator.ts", "../src/classes/transport/BaseTransport.ts", "../src/classes/transport/PerfStatReporter.ts", "../src/classes/stat/WeightedAverage.ts", "../src/classes/transport/DirectStatReporter.ts", "../src/classes/transport/DirectTransport.ts", "../src/enums/TrackId.ts", "../src/classes/asr/AsrReceiver.ts", "../src/classes/LocalNetworkRating.ts", "../src/classes/ParticipantIdRegistry.ts", "../src/classes/transport/ServerTransport.ts", "../src/classes/transport/Transport.ts", "../src/classes/stat/StatPings.ts", "../src/classes/stat/StatSignalingCommands.ts", "../src/enums/SignalingConnectionType.ts", "../src/static/SignalingCapabilities.ts", "../src/utils/LengthPrefixed.ts", "../src/utils/VariableLengthInteger.ts", "../src/types/WebTransport.ts", "../src/default/Signaling.ts", "../src/enums/CallDirection.ts", "../src/enums/CallType.ts", "../src/enums/ChatRoomEventType.ts", "../src/enums/ConversationFeature.ts", "../src/enums/ConversationOption.ts", "../src/enums/MuteState.ts", "../src/enums/ParticipantState.ts", "../src/enums/RoomsEventType.ts", "../src/enums/UpdateDisplayLayoutErrorReason.ts", "../src/enums/UserRole.ts", "../src/types/ExternalId.ts", "../src/types/WaitingHall.ts", "../src/utils/Conversation.ts", "../src/utils/Lz4.ts", "../src/classes/AudioFix.ts", "../src/classes/AudioOutput.ts", "../src/classes/DebugInfo.ts", "../src/classes/VolumeDetector.ts", "../src/classes/LocalVolumeDetector.ts", "../src/classes/SignalingActor.ts", "../src/classes/VolumesDetector.ts", "../src/classes/SpeakerDetector.ts", "../src/classes/SpecListener.ts", "../src/classes/stat/EventMetricsService.ts", "../src/classes/stat/StatFirstMediaReceived.ts", "../src/classes/Conversation.ts", "../src/static/ApiTransport.ts", "../src/abstract/BaseApi.ts", "../src/default/Api.ts", "../src/enums/RecordRole.ts", "../src/types/Participant.ts", "../src/utils/ArrayDequeue.ts", "../src/default/ApiExternal.ts"],
4
+ "sourcesContent": ["/**\n * CallsSDK\n */\n\nimport type { IEffect, VideoEffects } from '@vkontakte/calls-video-effects';\nimport type { EffectVoiceChange } from '@vkontakte/calls-audio-effects';\nimport type * as Vmoji from '@vkontakte/calls-vmoji';\nimport adapter from 'webrtc-adapter';\n\nimport BaseApi from './abstract/BaseApi';\nimport BaseLogger from './abstract/BaseLogger';\nimport { AddParticipantParams } from './abstract/BaseSignaling';\nimport Conversation from './classes/Conversation';\nimport HangupReason, { HangupReasonData, CustomError } from './classes/HangupReason';\nimport { MediaTrackKind } from './classes/MediaSource';\nimport { MAIN_ROOM_ID } from './constants/Rooms';\nimport { resetApiEndpoint } from './static/ApiTransport';\nimport { AudienceModeHandsResponse } from './types/AudienceMode';\nimport { TransportTopology } from './classes/transport/Transport';\nimport Api from './default/Api';\nimport Signaling from './default/Signaling';\nimport CallDirection from './enums/CallDirection';\nimport CallType from './enums/CallType';\nimport ChatRoomEventType from './enums/ChatRoomEventType';\nimport ConversationFeature from './enums/ConversationFeature';\nimport ConversationOption from './enums/ConversationOption';\nimport FatalError from './enums/FatalError';\nimport HangupType from './enums/HangupType';\nimport MediaOption from './enums/MediaOption';\nimport MuteState from './enums/MuteState';\nimport ParticipantState from './enums/ParticipantState';\nimport RecordRole from './enums/RecordRole';\nimport RoomsEventType from './enums/RoomsEventType';\nimport SignalingCommandType from './enums/SignalingCommandType';\nimport SignalingConnectionType from './enums/SignalingConnectionType';\nimport SignalingNotification from './enums/SignalingNotification';\nimport UserRole from './enums/UserRole';\nimport UserType from './enums/UserType';\nimport Debug, { DebugMessageType } from './static/Debug';\nimport { ParticipantStatus } from './static/External';\nimport { JSONArray, JSONObject, JSONType } from './static/Json';\nimport Params, { ParamsObject } from './static/Params';\nimport Utils from './static/Utils';\nimport WebRTCUtils, { BrowserName, FacingMode } from './static/WebRTCUtils';\nimport { IAsrData, IAsrStartParams, IAsrStopParams } from './types/Asr';\nimport { ConversationData } from './types/Conversation';\nimport { IFeaturesPerRole } from './types/ConversationFeature';\nimport ConversationParams from './types/ConversationParams';\nimport ConversationResponse from './types/ConversationResponse';\nimport {\n ExternalId,\n ExternalIdType,\n ExternalIdUtils,\n ExternalParticipant,\n ExternalParticipantId,\n ExternalParticipantListChunk,\n ExternalParticipantListMarker,\n ExternalParticipantListMarkers,\n ExternalUserId,\n} from './types/ExternalId';\nimport { IFeedbackExternal } from './types/Feedback';\nimport IceServer from './types/IceServer';\nimport MediaModifiers from './types/MediaModifiers';\nimport { IVideoDimentions, MediaSettings } from './types/MediaSettings';\nimport {\n IAddMovieParams,\n IMovieMetaData,\n IMoviePreview,\n IOnRemoteMovieData,\n ISharedMovieInfo,\n ISharedMovieState,\n ISharedMovieStateResponse,\n ISharedMovieStoppedInfo,\n IUpdateMovieData,\n} from './types/MovieShare';\nimport MuteStates, { IMuteParticipantInternalParams, IMuteParticipantParams } from './types/MuteStates';\nimport { IAPIBaseUrl, IApiEnv } from './types/Params';\nimport {\n CompositeUserId,\n IGetParticipantsParameters,\n OkUserId,\n ParticipantId,\n ParticipantListMarker,\n ParticipantListMarkers,\n ParticipantListType,\n ParticipantsStateList,\n ParticipantStateMapped,\n ParticipantStateData,\n ParticipantStateDataKey,\n ParticipantStateDataValue,\n} from './types/Participant';\nimport ParticipantLayout, { Layout, RequestKeyFrame, StopStream } from './types/ParticipantLayout';\nimport { ParticipantListChunkParameters } from './types/ParticipantListChunk';\nimport ParticipantPriority from './types/ParticipantPriority';\nimport { MediaType, ParticipantStreamDescription } from './types/ParticipantStreamDescription';\nimport { IRoomId, Room, RoomParticipantUpdate, Rooms, RoomsUpdate } from './types/Room';\nimport { ScreenCaptureSettings } from './types/ScreenCaptureSettings';\nimport SignalingMessage, { GetRoomsSignalingResponse, GetParticipantsSignalingResponse } from './types/SignalingMessage';\nimport { StatResult } from './types/Statistics';\nimport { IStartStreamData, IStopStreamData, IPublishStreamData } from './types/Streams';\nimport { WaitingHallResponse } from './types/WaitingHall';\nimport { ArrayDequeue } from './utils/ArrayDequeue';\nimport { ApiExternal } from './default/ApiExternal';\nimport AuthData from './static/AuthData';\nimport { VmojiError } from './types/Vmoji';\nimport { VolumeDetector } from './classes/VolumeDetector';\nimport { ConversationDebugLogger } from './static/ConversationDebugLogger';\nimport { FastStartHandler, FastStartParams } from './types/FastStart';\n\nlet _api: BaseApi;\nlet _externalLogger: BaseLogger | null = null;\n\n/**\n * Информация о текущем браузере\n */\nexport const browser = {\n /**\n * Возвращает все подключенные камеры\n */\n getCameras: WebRTCUtils.getCameras,\n /**\n * Возвращает все подключенные микрофоны\n */\n getMicrophones: WebRTCUtils.getMicrophones,\n /**\n * Возвращает все подключенные устройства вывода звука\n */\n getOutput: WebRTCUtils.getOutput,\n /**\n * Возвращает тип используемой камеры (передняя или задняя)\n */\n getVideoFacingMode: WebRTCUtils.getVideoFacingMode,\n /**\n * Есть ли у пользователя камера\n */\n hasCamera: WebRTCUtils.hasCamera,\n /**\n * Есть ли у пользователя микрофон\n */\n hasMicrophone: WebRTCUtils.hasMicrophone,\n /**\n * Возвращает сохраненную камеру пользователя, если она доступна\n */\n getSavedCamera: WebRTCUtils.getSavedCamera,\n /**\n * Возвращает сохраненный микрофон пользователя, если он доступен\n */\n getSavedMicrophone: WebRTCUtils.getSavedMicrophone,\n /**\n * Возвращает сохраненное устройство вывода\n */\n getSavedOutput: WebRTCUtils.getSavedOutput,\n /**\n * Проверяет получен ли доступ к камере\n */\n hasCameraPermission: WebRTCUtils.hasCameraPermission,\n /**\n * Проверяет получен ли доступ к микрофону\n */\n hasMicrophonePermission: WebRTCUtils.hasMicrophonePermission,\n /**\n * Проверяет получены ли разрешения, необходимые для текущего звонка\n */\n hasPermissions: WebRTCUtils.hasPermissions,\n /**\n * Запрашивает камеру и микрофон пользователя\n */\n getUserMedia: WebRTCUtils.getUserMedia,\n /**\n * Запрашивает камеру пользователя\n */\n getUserVideo: WebRTCUtils.getUserVideo,\n /**\n * Запрашивает микрофон пользователя\n */\n getUserAudio: WebRTCUtils.getUserAudio,\n /**\n * Устанавливает размер видео в стриме\n */\n setResolution: WebRTCUtils.setResolution,\n /**\n * Проверяет поддержку WebRTC браузером\n *\n * _Метод доступен до инициализации_\n */\n isBrowserSupported: WebRTCUtils.isBrowserSupported,\n /**\n * Проверяет поддержку трансляции экрана браузером\n *\n * _Метод доступен до инициализации_\n */\n isScreenCapturingSupported: WebRTCUtils.isScreenCapturingSupported,\n /**\n * Имя операционной системы\n *\n * _Метод доступен до инициализации_\n */\n os: WebRTCUtils.os,\n /**\n * Мобильный браузер или нет\n *\n * _Метод доступен до инициализации_\n */\n isMobile: WebRTCUtils.isMobile,\n /**\n * Имя браузера\n *\n * _Метод доступен до инициализации_\n */\n browserName: WebRTCUtils.browserName,\n /**\n * Версия браузера\n *\n * _Метод доступен до инициализации_\n */\n browserVersion: WebRTCUtils.browserVersion,\n /**\n * Если браузер основан на хроме - возвращает версию\n *\n * _Метод доступен до инициализации_\n */\n baseChromeVersion: WebRTCUtils.baseChromeVersion,\n /**\n * Возвращает AudioContext\n */\n getAudioContext: WebRTCUtils.getAudioContext,\n /**\n * Браузер поддерживает захват звука при трансляции экрана\n *\n * _Метод доступен до инициализации_\n */\n isAudioShareSupported: WebRTCUtils.isAudioShareSupported,\n};\n\n/**\n * Вспомогательные функции\n */\nexport const utils = {\n /**\n * Сравнивает маркеры для постраничного вывода участников звонка\n */\n participantMarkerCompare: Utils.participantMarkerCompare,\n};\n\nexport function setLogger(logger: BaseLogger): void {\n _externalLogger = logger;\n}\n\n/**\n * Устанавливает библиотеку видео эффектов\n *\n * @param effects Экземпляр класса `VideoEffects` из `@vkontakte/calls-video-effects`\n */\nexport function setVideoEffects(effects: VideoEffects): void {\n Params.videoEffects = effects;\n}\n\n/**\n * Устанавливает библиотеку аудио эффектов\n *\n * @param effects Экземпляр класса `EffectVoiceChange` из `@vkontakte/calls-audio-effects`\n */\nexport function setAudioEffects(effects: EffectVoiceChange): void {\n Params.audioEffects = effects;\n}\n\n/**\n * Устанавливает библиотеку вимоджи\n *\n * @param vmoji Экземпляр класса `Vmoji` из `@vkontakte/calls-vmoji`\n * @param sdk Экземпляр модуля `@vkontakte/calls-sdk`, нужен для проброски дебаг сообщений\n */\nexport function setVmoji(\n vmoji: typeof Vmoji,\n sdk: Parameters<typeof Vmoji.setSDK>[0] | null = null,\n renderingOptions: Partial<Vmoji.RenderingOptions> = {},\n protocolVersion: Vmoji.AnimojiVersion = 1,\n): void {\n Params.vmoji = vmoji;\n Params.vmojiOptions = {\n protocolVersion,\n renderingOptions,\n };\n\n if (sdk) {\n vmoji.setSDK(sdk);\n }\n}\n\n/**\n * Инициализирует библиотеку\n *\n * Метод должен быть вызван первым до любых других вызовов\n *\n * `SDK.browser` будет содержать актуальную информацию об устройствах только после вызова этого метода\n *\n * @param params Параметры инициализации\n */\nexport async function init(params: Partial<ParamsObject>): Promise<void> {\n Params.set(params);\n\n if (!_api) {\n _api = new Api();\n }\n\n // Если тут сделать @ifdef, адаптер выпилится полностью - оставляем\n adapter.disableLog(!Params.debug);\n Debug.toggle(Params.debug);\n\n Debug.log(`Calls SDK ${Params.sdkVersion}`, params);\n\n await WebRTCUtils.init();\n if (!WebRTCUtils.isBrowserSupported()) {\n throw new HangupReason(FatalError.UNSUPPORTED);\n }\n\n Debug.log('UserAgent:', navigator.userAgent);\n Debug.log('Screen resolution:', `${window.screen.width}x${window.screen.height}`);\n Debug.log('Permissions:', `Camera: ${WebRTCUtils.hasCameraPermission()}, Mic: ${WebRTCUtils.hasMicrophonePermission()}`);\n Debug.log('Simulcast:', `${params.simulcast} => ${Params.simulcast}`);\n}\n\n/**\n * Начать звонок другому пользователю\n *\n * @param externalId Внешние ID пользователей\n * @param mediaOptions Нужно ли включать камеру и микрофон\n * @param payload Дополнительные данные для передачи на сервер\n * @param joiningAllowed Создать токен комнаты для подключения по ссылке\n * @param requireAuthToJoin Запретить анонимам подключаться по ссылке (если поддерживается сервером)\n * @param onlyAdminCanShareMovie Только администратор может включать совметсный просмотр\n * @param onFastStart Функция для обработки быстрого старта\n */\nexport async function callTo(\n externalId?: ExternalId | ExternalId[],\n mediaOptions = [MediaOption.AUDIO],\n payload = '',\n joiningAllowed = false,\n requireAuthToJoin = false,\n onlyAdminCanShareMovie?: boolean,\n onFastStart?: FastStartHandler,\n): Promise<ConversationData> {\n let externalIds: ExternalId[] = [];\n\n if (Array.isArray(externalId)) {\n externalIds = externalId.length ? externalId : [];\n } else if (externalId) {\n externalIds = [externalId];\n }\n\n return callInternal([], CallType.USER, mediaOptions, payload, joiningAllowed, requireAuthToJoin, onlyAdminCanShareMovie, externalIds, onFastStart);\n}\n\nexport async function callInternal(\n ids: OkUserId[],\n type: CallType = CallType.USER,\n mediaOptions: MediaOption[],\n payload = '',\n joiningAllowed = false,\n requireAuthToJoin = false,\n onlyAdminCanShareMovie?: boolean,\n externalIds?: ExternalId[],\n onFastStart?: FastStartHandler,\n): Promise<ConversationData> {\n if (Conversation.current()) {\n Debug.error('There is already active call');\n throw new HangupReason(HangupType.FAILED);\n }\n const conversation = new Conversation(_api, _externalLogger);\n return conversation.onStart({\n opponentIds: ids,\n opponentType: type,\n mediaOptions,\n payload,\n joiningAllowed,\n requireAuthToJoin,\n onlyAdminCanShareMovie,\n externalIds,\n onFastStart,\n });\n}\n\n/**\n * Обработать пуш о входящем звонке\n *\n * Для любого входящего пуша нужно вызвать этот метод.\n * Если уже есть активный звонок, метод отправит \"занято\" вызывающему абоненту\n *\n * `acceptCall` и `declineCall` будут работать только после вызова `processPush`\n *\n * @param conversationId ID звонка\n * @param conversationParams conversationParams в base64\n */\nexport async function processPush(conversationId: string, conversationParams?: string): Promise<void> {\n return processPushInternal(conversationId, UserType.USER, undefined, conversationParams);\n}\n\nexport async function processPushInternal(\n conversationId: string,\n type: UserType = UserType.USER,\n peerId?: number,\n conversationParams?: string,\n wsEndpoint?: string,\n userId?: number,\n): Promise<void> {\n if (conversationId === Conversation.id()) {\n throw new Error('Push has already been processed');\n }\n\n // Прием звонка от имени группы в ОК требует этого\n if (userId) {\n _api.setUserId(userId);\n }\n\n const conversation = new Conversation(_api, _externalLogger);\n return conversation.onPush(conversationId, type, peerId, conversationParams, wsEndpoint);\n}\n\n\n\n\n/**\n * Авторизоваться для совершения звонков\n *\n * @param authToken Токен авторизации\n * @param apiBaseUrl Базовый адрес для API. Если не передан, то не меняет установленный\n */\nexport async function authorize(authToken?: string, apiBaseUrl?: IAPIBaseUrl): Promise<void> {\n if (authToken) {\n Params.authToken = authToken;\n }\n\n if (apiBaseUrl !== undefined && Params.apiBaseUrl !== apiBaseUrl) {\n Params.apiBaseUrl = apiBaseUrl;\n resetApiEndpoint();\n }\n\n return _api.authorize();\n}\n\n/**\n * Принять входящий звонок\n *\n * @param mediaOptions Нужно ли включать камеру и микрофон\n */\nexport async function acceptCall(mediaOptions = [MediaOption.AUDIO]): Promise<ConversationData> {\n const conversation = getConversationOrThrowException();\n return conversation.accept(mediaOptions);\n}\n\n/**\n * Отклонить входящий звонок\n */\nexport async function declineCall(): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.decline();\n }\n}\n\n/**\n * Присоединиться к активному звонку\n *\n * @param conversationId ID звонка\n * @param mediaOptions Нужно ли включать камеру и микрофон\n */\nexport async function joinCall(conversationId: string, mediaOptions = [MediaOption.AUDIO]): Promise<ConversationData> {\n return joinCallInternal(conversationId, mediaOptions);\n}\n\nexport async function joinCallInternal(conversationId: string, mediaOptions: MediaOption[], chatId?: string): Promise<ConversationData> {\n if (Conversation.current()) {\n Debug.error('There is already active call');\n throw new HangupReason(HangupType.FAILED);\n }\n const conversation = new Conversation(_api, _externalLogger);\n return conversation.onJoin({ conversationId, mediaOptions, chatId });\n}\n\n/**\n * Присоединиться к звонку по ссылке\n *\n * @param joinLink Токен комнаты\n * @param mediaOptions Нужно ли включать камеру и микрофон\n * @param anonymToken Токен анонимной авторизации\n * @param observedIds\n * @param payload\n */\nexport async function joinCallByLink(\n joinLink: string,\n mediaOptions = [MediaOption.AUDIO],\n anonymToken?: string,\n observedIds?: ExternalUserId[],\n payload?: string,\n): Promise<ConversationData> {\n if (Conversation.current()) {\n Debug.error('There is already active call');\n throw new HangupReason(HangupType.FAILED);\n }\n if (anonymToken) {\n Params.anonymToken = anonymToken;\n }\n const conversation = new Conversation(_api, _externalLogger);\n return conversation.onJoin({ joinLink, mediaOptions, observedIds, payload });\n}\n\n/**\n * Завершить текущий разговор\n */\nexport async function hangup(): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.hangup();\n } else {\n Conversation.hangupAfterInit();\n }\n}\n\n/**\n * Добавить собеседника в звонок\n *\n * @param externalIds Внешние ID пользователей\n * @param params Параметры\n */\nexport async function addParticipant(externalIds: ExternalId | ExternalId[], params?: AddParticipantParams): Promise<void> {\n const participants: ExternalId[] = Array.isArray(externalIds) ? externalIds : [externalIds];\n\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.addParticipant(participants, params);\n }\n}\n\n/**\n * @deprecated - используйте addParticipant\n * @param uids\n * @param params\n */\nexport async function addParticipantInternal(uids: OkUserId[], params?: AddParticipantParams) {\n const conversation = Conversation.current();\n if (conversation) {\n const composedUids = uids.map((uid) => Utils.composeUserId(uid));\n await conversation.addParticipantLegacy(composedUids, params);\n }\n}\n\n/**\n * Удалить собеседника из звонка\n *\n * @param externalId Внешний ID пользователя\n * @param ban Забанить пользователя\n */\nexport async function removeParticipant(externalId: ExternalId, ban = false): Promise<void> {\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n return removeParticipantInternal(uids[0], ban);\n}\n\n/**\n * @deprecated - используйте removeParticipant\n * @param uid\n * @param ban\n */\nexport async function removeParticipantInternal(uid: OkUserId, ban = false) {\n const conversation = Conversation.current();\n if (conversation) {\n try {\n await conversation.removeParticipant(Utils.composeUserId(uid), ban);\n } catch (err) {\n Debug.warn(`Failed to remove participant ${uid}. Perhaps he is no longer on the call. ${err}`);\n }\n }\n}\n\n/**\n * Изменить камеру на фронтальную или заднюю (для мобильных устройств)\n *\n * @param kind\n * @param facingMode\n */\nexport async function changeDevice(kind: 'videoinput', facingMode: FacingMode): Promise<void>;\n\n/**\n * Изменить камеру, микрофон или динамик\n *\n * @param kind Тип устройства для изменения (камера/микрофон/динамик)\n * @param deviceId ID устройства\n */\nexport async function changeDevice(kind: MediaDeviceKind, deviceId: string): Promise<void>;\n\n// NB: Не отмечать как @hidden – теряется документация по перегруженным методам\nexport async function changeDevice(kind: MediaDeviceKind, deviceIdOrFacingMode: string | FacingMode): Promise<void> {\n const conversation = Conversation.current();\n\n // facingMode\n if (kind === 'videoinput' && FacingMode.contains(deviceIdOrFacingMode)) {\n Params.videoFacingMode = deviceIdOrFacingMode as FacingMode;\n\n if (!conversation) {\n // Просто сохранили значение в параметры\n return;\n }\n\n if (WebRTCUtils.isMobile()) {\n // На телефонах Samsung нельзя запросить стрим с камеры, пока есть активный стрим с любой камеры\n // На всякий случай останавливаем трек на всех мобилах перед сменой камеры\n conversation.stopVideoTrack();\n }\n return conversation.changeDevice(kind);\n }\n\n // deviceId\n const device = await WebRTCUtils._saveDeviceId(kind, deviceIdOrFacingMode);\n if (!device) {\n throw new Error(`Device not found: ${deviceIdOrFacingMode}`);\n }\n if (conversation) {\n return conversation.changeDevice(kind);\n }\n}\n\n/**\n * Включить/выключить захват экрана\n *\n * @param stateOrSettings\n * state Включить или выключить захват экрана\n * settings Параметры захваты экрана\n */\nexport async function captureScreen(stateOrSettings: boolean | ScreenCaptureSettings): Promise<void> {\n const settings =\n typeof stateOrSettings === 'object'\n ? {\n ...stateOrSettings,\n fastScreenSharing: stateOrSettings.captureScreen && stateOrSettings.fastScreenSharing,\n captureAudio: stateOrSettings.captureScreen && stateOrSettings.captureAudio && Params.audioShare,\n }\n : {\n captureScreen: stateOrSettings,\n fastScreenSharing: false,\n captureAudio: false,\n };\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.toggleScreenCapturing(settings);\n }\n return Promise.reject();\n}\n\n/**\n * Включить/выключить передачу точек вимоджи\n *\n * @param state Включить или выключить\n */\nexport function captureVmoji(state: boolean) {\n const conversation = Conversation.current();\n if (conversation) {\n conversation.toggleAnimojiCapturing(state);\n }\n}\n\n/**\n * Позволяет установить кастомный стрим для видео\n * например для стрима из canvas, с наложением изображений\n *\n * @param stream Стрим\n * @param isScreen Является ли стрим разновидностью шаринга экрана\n * @hidden\n */\nexport async function setVideoStream(stream: MediaStream, isScreen = false): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.setVideoStream(stream, isScreen);\n }\n}\n\n/**\n * Включить или выключить свою камеру\n *\n * @param enabled\n */\nexport async function toggleLocalVideo(enabled: boolean): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.toggleLocalVideo(enabled);\n }\n}\n\n/**\n * Включить или выключить свой микрофон\n *\n * @param enabled\n */\nexport async function toggleLocalAudio(enabled: boolean): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.toggleLocalAudio(enabled);\n }\n}\n\n/**\n * Изменяет размеры локального видео\n *\n * @param resolution\n */\nexport async function setLocalResolution(resolution: { video: IVideoDimentions; effect?: IVideoDimentions }) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.setLocalResolution(resolution);\n }\n}\n\n/**\n * Изменяет качество отображаемых стримов - чем выше приоритет, тем лучше качество.\n * Не нужно передавать огромные числа - из приоритетов (0, 1, 2, 3) последний получит максимальное качество, а первый худшее.\n * Отрицательный приоритет выключит видео.\n *\n * @param priorities Список приоритетов\n * @deprecated Use updateDisplayLayout instead\n */\nexport async function changePriorities(priorities: ParticipantPriority[]): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.changePriorities(priorities);\n }\n}\n\n/**\n * Изменяет состояния пользователя в звонке (например, \"поднять руку\" или \"отошёл\")\n *\n * @param state Список состояний в виде ключ-значение. Максимальная длина ключей и значений - 5 символов. Пустые значения будут пропущены\n * @param externalId Внешний ID пользователя\n */\nexport async function changeParticipantState(state: ParticipantStateData, externalId?: ExternalId): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n let compositeUserId: CompositeUserId | undefined;\n\n if (externalId) {\n const [uid] = await _api.getOkIdsByExternalIds([externalId]);\n compositeUserId = Utils.composeParticipantId(uid, UserType.USER, externalId.deviceIdx);\n }\n\n await conversation.changeParticipantState(state, compositeUserId);\n }\n}\n\n/**\n * Принудительно опустить руки участников в текущем сессионном зале админа\n */\nexport async function putHandsDown(): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.putHandsDown();\n }\n}\n\n/**\n * Изменяет лейаут.\n * Также сообщает серверу каких участников звонка стримить на этот клиент\n *\n * @param layout Список приоритетов\n */\nexport async function updateDisplayLayout(layout: ParticipantLayout[]): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.updateDisplayLayout(layout);\n }\n}\n\n/**\n * Выдать или забрать роли в звонке пользователю\n *\n * @param externalId Внешний ID пользователя\n * @param roles Список ролей\n * @param revoke Забрать роли\n */\nexport async function grantRoles(externalId: ExternalId, roles: UserRole[], revoke = false): Promise<void> {\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n return grantRolesInternal(uids[0], ExternalIdUtils.getDeviceIdx(externalId), roles, revoke);\n}\n\nexport async function grantRolesInternal(uid: OkUserId, deviceIdx: number, roles: UserRole[], revoke = false) {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.grantRoles(Utils.composeParticipantId(uid, UserType.USER, deviceIdx), roles, revoke);\n }\n}\n\n/**\n * Выключить или выключить микрофон и/или камеру собеседнику (только если есть соответствующая роль)\n */\nexport async function muteParticipant({ externalId = null, muteStates, requestedMedia = [], roomId = MAIN_ROOM_ID }: IMuteParticipantParams): Promise<void> {\n let uid = null;\n if (externalId) {\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n uid = uids[0];\n }\n return muteParticipantInternal({\n uid,\n muteStates,\n requestedMedia,\n deviceIdx: ExternalIdUtils.getDeviceIdx(externalId),\n roomId,\n });\n}\n\nexport async function muteParticipantInternal({ uid = null, muteStates, requestedMedia = [], deviceIdx = 0, roomId = MAIN_ROOM_ID }: IMuteParticipantInternalParams) {\n const conversation = Conversation.current();\n if (conversation) {\n const participantId = uid ? Utils.composeParticipantId(uid, UserType.USER, deviceIdx) : null;\n await conversation.muteParticipant(participantId, muteStates, requestedMedia, roomId);\n }\n}\n\n/**\n * Закрепить/открепить выбранного собеседника у всех (только если есть соответствующая роль)\n *\n * @param externalId Внешний ID пользователя\n * @param unpin Открепить\n * @param roomId Идентификатор комнаты\n */\nexport async function pinParticipant(externalId: ExternalId, unpin = false, roomId: number | null = null): Promise<void> {\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n return pinParticipantInternal(uids[0], unpin, ExternalIdUtils.getDeviceIdx(externalId), roomId);\n}\n\nexport async function pinParticipantInternal(uid: OkUserId, unpin = false, deviceIdx = 0, roomId: number | null = null) {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.pinParticipant(Utils.composeParticipantId(uid, UserType.USER, deviceIdx), unpin, roomId);\n }\n}\n\n/**\n * Устанавливает настройки пользовательского медиа\n *\n * @param mediaModifiers\n */\nexport async function setMediaModifiers(mediaModifiers: MediaModifiers): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.updateMediaModifiers(mediaModifiers);\n }\n}\n\n/**\n * Автоматическое отключения принимаемых видео-потоков\n * в условиях плохого соединения\n *\n * @param enabled true - включить, false - отключить\n */\nexport async function enableVideoSuspend(enabled: boolean): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.enableVideoSuspend(enabled);\n }\n}\n\n/**\n * Режим, при котором будет предложено включить автоматическое\n * отключение приёма видео в условиях плохого соединения\n *\n * @param enabled true - включить, false - отключить\n */\nexport async function enableVideoSuspendSuggest(enabled: boolean): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.enableVideoSuspendSuggest(enabled);\n }\n}\n\n/**\n * Включить/выключить опции звонка\n *\n * @param changes\n */\nexport async function changeConversationOptions(changes: { [key in ConversationOption]?: boolean }): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.changeOptions(changes);\n }\n}\n\n/**\n * Отправить сообщение в чат\n *\n * @param message Сообщение\n * @param externalId Внешний ID пользователя (если не указано, отправит всем)\n */\nexport async function chatMessage(message: string, externalId: ExternalId | null = null): Promise<void> {\n let uid = null;\n if (externalId) {\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n uid = uids[0];\n }\n return chatMessageInternal(message, uid);\n}\n\nexport async function chatMessageInternal(message: string, uid: OkUserId | null = null) {\n const conversation = Conversation.current();\n if (conversation) {\n const participantId = uid ? Utils.composeUserId(uid) : null;\n await conversation.chatMessage(message, participantId);\n }\n}\n\n/**\n * Получить историю сообщений чата\n *\n * @param count Количество сообщений\n */\nexport async function chatHistory(count = 10) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.chatHistory(count);\n }\n}\n\n/**\n * Отправить произвольные данные собеседнику\n *\n * @param data Данные\n * @param externalId Внешний ID пользователя (если не указано, отправит всем)\n */\nexport async function customData(data: JSONObject, externalId: ExternalId | null = null): Promise<void> {\n let uid = null;\n if (externalId) {\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n uid = uids[0];\n }\n return customDataInternal(data, uid, ExternalIdUtils.getDeviceIdx(externalId));\n}\n\nexport async function customDataInternal(data: JSONObject, uid: OkUserId | null = null, deviceIdx = 0) {\n const conversation = Conversation.current();\n if (conversation) {\n const participantId = uid ? Utils.composeParticipantId(uid, UserType.USER, deviceIdx) : null;\n await conversation.customData(data, participantId);\n }\n}\n\n/**\n * Создать токен комнаты для подключения по ссылке\n *\n * @param payload Дополнительные данные для передачи на сервер\n * @param requireAuthToJoin Запретить анонимам подключаться по ссылке (если поддерживается сервером)\n * @param startConversationParameters Дополнительные параметры для создания звонка (например onlyAdminCanShareMovie)\n * @param waitForAdmin Включить режим ожидания админа в звонке, в звонок не попасть пока админ не войдет\n * @param closed создаёт звонок в \"завершенном\" стостоянии. Как когда мы создаём звонок по ссылке, но не заходим туда\n * @returns Токен комнаты\n */\nexport async function startConversation(\n payload = '',\n requireAuthToJoin = false,\n { onlyAdminCanShareMovie = false, waitForAdmin = false, closedConversation = false } = {},\n): Promise<string> {\n const conversation = await _api.createConversation(Utils.uuid(), payload, requireAuthToJoin, { onlyAdminCanShareMovie, waitForAdmin, closedConversation });\n return conversation.join_link as string;\n}\n\n/**\n * Создать токен комнаты в режиме Audience для подключения по ссылке\n *\n * @param payload Дополнительные данные для передачи на сервер\n * @param requireAuthToJoin Запретить анонимам подключаться по ссылке (если поддерживается сервером)\n * @param startConversationParameters Дополнительные параметры для создания звонка (например onlyAdminCanShareMovie)\n * @param speakerIds Список внешних ID пользователей, которые будут выступать в роли спикеров\n * @returns Токен комнаты\n */\nexport async function startAudienceConversation(\n payload = '',\n requireAuthToJoin = false,\n { onlyAdminCanShareMovie = false, audioOnly = false } = {},\n speakerIds: ExternalUserId[],\n): Promise<string> {\n const uids = ExternalIdUtils.fromIds(speakerIds);\n const okSpeakerIds: OkUserId[] = await _api.getOkIdsByExternalIds(uids);\n const conversation = await _api.createConversation(\n Utils.uuid(),\n payload,\n requireAuthToJoin,\n {\n onlyAdminCanShareMovie,\n audienceMode: true,\n audioOnly,\n },\n okSpeakerIds,\n );\n return conversation.join_link as string;\n}\n\n/**\n * Создать токен комнаты для подключения по ссылке к существующему звонку\n *\n * @returns Токен комнаты\n */\nexport async function createJoinLink(): Promise<string> {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.createJoinLink();\n }\n return Promise.reject();\n}\n\n/**\n * Удалить токен комнаты для подключения по ссылке\n */\nexport async function removeJoinLink(): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.removeJoinLink();\n }\n return Promise.reject();\n}\n\n/**\n * Получить токен анонимной авторизации для подключения к звонку по ссылке\n *\n * @param joinLink Токен комнаты\n * @param username Имя аниномного пользователя\n * @returns Токен авторизации\n */\nexport async function getAnonymTokenByLink(joinLink: string, username?: string): Promise<string> {\n return _api.getAnonymTokenByLink(joinLink, username);\n}\n\n/**\n * Устанавливает громкость звука собеседников\n * @param volume Уровень громкости [0..1]\n */\nexport function setVolume(volume: number) {\n const conversation = Conversation.current();\n if (conversation) {\n conversation.setVolume(volume);\n }\n}\n\n/**\n * Не использовать прямое P2P соединение, чтобы не отправлять в ICE-кандидатах персональные IP-адреса\n * @param enabled\n */\nexport function forceRelayPolicy(enabled: boolean) {\n Params.forceRelayPolicy = enabled;\n}\n\n/**\n * Начать трансляцию звонка\n * @param isRecord Записывать ли трансляцию\n * @param name Имя видеоролика\n * @param movieId ID видео\n * @param privacy\n * @param groupId\n * @param roomId\n */\nexport async function startStream(\n isRecord = false,\n name: string | null = null,\n movieId: string | null = null,\n privacy: 'PUBLIC' | 'FRIENDS' | 'DIRECT_LINK' = 'DIRECT_LINK',\n groupId: string | null = null,\n roomId: number | null = null,\n) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.startStream(isRecord, name, movieId, privacy, groupId, roomId);\n }\n return Promise.reject();\n}\n\n/**\n * Завершить трансляцию звонка\n * @param roomId\n * @param remove не сохранять запись звонка\n */\nexport async function stopStream(roomId: number | null = null, remove?: boolean) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.stopStream(roomId, remove);\n }\n return Promise.reject();\n}\n\n/**\n * Опубликовать трансляцию звонка\n * @param roomId\n */\nexport async function publishStream(roomId: number | null = null) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.publishStream(roomId);\n }\n return Promise.reject();\n}\n\n/**\n * Устанавливает роль участника в запись звонка\n * Если хотя бы у одного участника звонка выставлена роль, то в записи звонка будут\n * видны только те участники, у кого есть роль.\n * @param king участник показывается крупно в записи звонка (только один участник имеет такую роль)\n * @param pawns участник показывается в записи звонка\n * @param hideParticipantCount скрыть/показать количество невидимых участников\n * @param roomId комната\n */\nexport async function recordSetConf(king?: ExternalId, pawns?: ExternalId[], hideParticipantCount = false, roomId: number | null = null) {\n const conversation = Conversation.current();\n if (!conversation) {\n return Promise.reject();\n }\n\n let kingUid: ParticipantId | undefined;\n let pawnUids: ParticipantId[] | undefined;\n\n const externalIds: ExternalId[] = [];\n if (pawns?.length) {\n externalIds.push(...pawns);\n }\n if (king) {\n externalIds.push(king);\n }\n if (externalIds.length) {\n const participantIds = await _api.getParticipantIdsByExternalIds(externalIds);\n\n if (king) {\n kingUid = participantIds.get(king);\n participantIds.delete(king);\n }\n pawnUids = Array.from(participantIds.values());\n }\n\n // Non-decorative OK ids should be used\n return conversation.recordSetConf(kingUid, pawnUids, hideParticipantCount, roomId);\n}\n\n/**\n * Получить информацию о трансляции звонка\n */\nexport async function getStreamInfo() {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.getStreamInfo();\n }\n return Promise.reject();\n}\n\n/**\n * Добавляет видео/лайв в звонок\n *\n * @param params\n */\nexport async function addMovie(params: IAddMovieParams) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.addMovie(params);\n }\n return Promise.reject();\n}\n\n/**\n * Изменить видео/лайв в звонке\n *\n * @param params\n */\nexport async function updateMovie(params: IUpdateMovieData) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.updateMovie(params);\n }\n return Promise.reject();\n}\n\n/**\n * Удалить видео/лайв из звонка\n *\n * @param movieId Id Ролика\n */\nexport async function removeMovie(movieId: number) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.removeMovie(movieId);\n }\n return Promise.reject();\n}\n\n/**\n * Обновить сессионные залы\n * @param rooms id в случае обновления сессионного зала\n * @param assignRandomly рандомно назначить участников залов из свободных в соответствии с participantCount\n */\nexport async function updateRooms(rooms: Partial<Room>[], assignRandomly?: boolean) {\n const conversation = Conversation.current();\n if (conversation) {\n const update: SignalingMessage.Room[] = [];\n\n for (const room of rooms) {\n let addParticipantIds;\n let removeParticipantIds;\n\n if (room.addParticipantIds) {\n addParticipantIds = (await _api.getOkIdsByExternalIds(room.addParticipantIds)).map((id) => Utils.composeUserId(id));\n }\n\n if (room.removeParticipantIds) {\n removeParticipantIds = (await _api.getOkIdsByExternalIds(room.removeParticipantIds)).map((id) => Utils.composeUserId(id));\n }\n\n update.push({\n id: room.id,\n name: room.name,\n participantCount: room.participantCount,\n addParticipantIds,\n removeParticipantIds,\n countdownSec: room.countdownSec,\n });\n }\n\n return conversation.updateRooms(update, assignRandomly);\n }\n return Promise.reject();\n}\n\n/**\n * Активировать сессионные залы\n * @param roomIds\n * @param deactivate\n */\nexport async function activateRooms(roomIds: number[], deactivate: boolean) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.activateRooms(roomIds, deactivate);\n }\n return Promise.reject();\n}\n\n/**\n * Cменить сессионный зал\n * @param toRoomId\n * @param externalId\n */\nexport async function switchRoom(toRoomId: number | null = null, externalId: ExternalId | null = null) {\n const conversation = Conversation.current();\n if (!conversation) {\n return Promise.reject();\n }\n\n let uid;\n if (externalId) {\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n const deviceIdx = ExternalIdUtils.getDeviceIdx(externalId);\n uid = Utils.composeParticipantId(uids[0], UserType.USER, deviceIdx);\n }\n return conversation.switchRoom(toRoomId, uid);\n}\n\n/**\n * Удалить сессионные залы\n * @param roomIds\n */\nexport async function removeRooms(roomIds: number[]) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.removeRooms(roomIds);\n }\n return Promise.reject();\n}\n\n/**\n * Устанавливает интервал обновления статистики и вызова `onStatistics`\n *\n * @param value Значение в миллисекундах\n */\nexport function setStatisticsInterval(value: number) {\n Params.statisticsInterval = value;\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.updateStatisticsInterval();\n }\n}\n\n/**\n * Включить режим отладки\n *\n * @param enabled\n */\nexport function debug(enabled: boolean): void {\n adapter.disableLog(!enabled);\n Debug.toggle(enabled);\n}\n\n/**\n * Добавить сообщение в отладочный лог\n *\n * @param type Тип сообщения\n * @param args\n */\nexport function debugMessage(type: DebugMessageType, ...args: any[]): void {\n if (!Params.debugLog) {\n return;\n }\n Debug.send(type, '[external]', ...args);\n}\n\n/**\n * Отправляет клиенские логи по conversationId на сервер OK\n * @example можно посмотреть в examples/anonym/index.html\n */\nexport async function uploadDebugLogs(): Promise<void> {\n const id = ConversationDebugLogger.conversationId;\n if (!id) {\n Debug.error('[uploadDebugLogs]', 'No conversation id found');\n throw new Error('No conversation id found');\n }\n\n const logs = ConversationDebugLogger.collectLogs();\n\n if (logs.length === 0) {\n Debug.error('[uploadDebugLogs]', 'No logs found');\n throw new Error('No logs found');\n }\n\n const startTime = ConversationDebugLogger.startTime;\n const endTime = ConversationDebugLogger.endTime;\n\n try {\n return _api?.uploadDebugLogs(id, startTime, endTime, JSON.stringify(logs));\n } catch (err) {\n Debug.error('[uploadDebugLogs]', 'Error while uploading logs', err);\n throw new Error('Error while uploading logs', { cause: err });\n }\n}\n\n/**\n * Эффект локального видео\n *\n * @param effect\n */\nexport async function changeVideoEffect(effect: IEffect | null) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.videoEffect(effect);\n }\n}\n\n/**\n * Эффект локального аудио\n *\n * @param effect\n */\nexport async function changeAudioEffect(effects: string[], isPreset?: boolean) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.audioEffect(effects.length > 0 ? effects : null, isPreset);\n }\n}\n\n/**\n * Позволяет установить кастомный стрим для аудио\n *\n * @param stream Стрим\n * @hidden\n */\nexport async function setAudioStream(stream: MediaStream): Promise<void> {\n const conversation = Conversation.current();\n if (conversation) {\n await conversation.setAudioStream(stream);\n }\n}\n\n/**\n * Позволяет установить svg аватар для участника звонка\n *\n * @param {(string|ArrayBuffer)} svg - svg в незашифрованном (string)\n * или зашифрованном (ArrayBuffer) виде\n * @param {(ExternalId|null)} externalId - externalId внешнего участника звонка,\n * не требуется для текущего участника (текущего пользователя клиента)\n * @param {(string|null)} customKey - кастомный ключ расшифровки svg,\n * нужен только в случае присвоения участнику чужого аватара\n */\nexport async function setVmojiSvg(svg: string | ArrayBuffer, externalId: ExternalId | null = null, customKey: string | null = null) {\n const conversation = Conversation.current();\n if (!conversation) {\n return;\n }\n\n const decryptionKey = customKey ?? externalId?.id;\n let participantId = null;\n\n if (externalId) {\n // Для внешнего участника звонка\n const uids = await _api.getOkIdsByExternalIds([externalId]);\n const uid = uids[0];\n\n if (!uid) {\n throw new Error('Could not get user id to set animoji svg');\n }\n\n participantId = Utils.composeParticipantId(uid, UserType.USER, ExternalIdUtils.getDeviceIdx(externalId));\n }\n\n conversation.setAnimojiSvg(svg, participantId, decryptionKey);\n}\n\n/**\n * Позволяет установить цвет фона собственного vmoji\n *\n * @param {(RGBTuple|string)} fill - цвет в виде rgb-кортежа или hex-кода\n */\nexport function setVmojiFill(fill: Vmoji.RGBTuple | string) {\n const conversation = Conversation.current();\n if (!conversation) {\n return;\n }\n\n conversation.setAnimojiFill(fill);\n}\n\n/**\n * Получить состояние зала ожидания\n *\n * @param pageMarker Маркер страницы\n * @param count Количество элементов на странице\n * @param backward Получить результат в обратном порядке\n */\nexport async function getWaitingHall(pageMarker: string | null = null, count?: number, backward = false): Promise<WaitingHallResponse> {\n const conversation = getConversationOrThrowException();\n\n return conversation.getWaitingHall(pageMarker, count, backward);\n}\n\n/**\n * Получить список слушателей, запросивших повышение в комнате в режиме Audience\n */\nexport async function getAudienceModeHands(): Promise<AudienceModeHandsResponse> {\n const conversation = getConversationOrThrowException();\n\n return conversation.getAudienceModeHands();\n}\n\n/**\n * Разрешить/запретить пользователю войти из зала ожидания/стать спикером комнаты\n * в режиме Audience\n *\n * @param externalId Внешний ID пользователя\n * @param demote Запретить вход/отобрать права спикера\n */\nexport async function promoteParticipant(externalId?: ExternalId, demote = false): Promise<void> {\n const conversation = getConversationOrThrowException();\n let compositeUserId: CompositeUserId | undefined;\n\n if (externalId) {\n const [uid] = await _api.getOkIdsByExternalIds([externalId]);\n compositeUserId = Utils.composeUserId(uid);\n }\n\n return conversation.promoteParticipant(compositeUserId, demote);\n}\n\n/**\n * Запросить/отозвать запрос на получение права стать спикером в комнате в\n * режиме Audience\n *\n * @param demote Отозвать запрос\n */\nexport async function requestPromotion(demote = false): Promise<void> {\n const conversation = getConversationOrThrowException();\n\n return conversation.requestPromotion(demote);\n}\n\n/**\n * Согласиться/отказаться стать спикером в комнате в режиме Audience.\n *\n * @param reject Отказаться стать спикером\n */\nexport async function acceptPromotion(reject = false): Promise<void> {\n const conversation = getConversationOrThrowException();\n\n return conversation.acceptPromotion(reject);\n}\n\nexport async function getParticipantListChunk(participantListChunkParameters: ParticipantListChunkParameters) {\n const conversation = getConversationOrThrowException();\n return conversation.getParticipantListChunk(participantListChunkParameters);\n}\n\nexport async function getParticipants(parameters: IGetParticipantsParameters) {\n const conversation = getConversationOrThrowException();\n return conversation.getParticipants(parameters);\n}\n\nexport async function feedback(key: string) {\n const conversation = getConversationOrThrowException();\n return conversation.feedback(key);\n}\n\nexport function userFeedbackStats(userResponse: number, reason?: string, groupCallUsersCount?: number) {\n const conversation = getConversationOrThrowException();\n return conversation.userFeedbackStats(userResponse, reason, groupCallUsersCount);\n}\n\n/**\n * Логирует клиентское событие статистики\n *\n * @param eventType Тип события\n * @param eventData Дополнительные данные события\n * @param immediatelty Отправить ли событие немедленно\n */\nexport function logClientEvent(eventType: string, eventData: Record<string, string | number | boolean> = {}, immediately = false) {\n const conversation = Conversation.current();\n\n if (!conversation) {\n return;\n }\n\n conversation.sendClientEvent(eventType, eventData, immediately);\n}\n\nexport async function enableFeatureForRoles(feature: ConversationFeature, roles: UserRole[]) {\n const conversation = getConversationOrThrowException();\n return conversation.enableFeatureForRoles(feature, roles);\n}\n\nfunction getConversationOrThrowException() {\n const conversation = Conversation.current();\n if (!conversation) {\n throw new Error('Conversation not found');\n }\n return conversation;\n}\n\n/**\n * Удаляет записи истории звонков\n *\n * @param recordIds Идентификаторы записей истории\n */\nexport async function removeHistoryRecords(recordIds: number[]): Promise<void> {\n await _api.removeHistoryRecords(recordIds);\n}\n\n/**\n * Начинает текстовую расшифровку звонка\n */\nexport async function startAsr(params: IAsrStartParams): Promise<void> {\n const conversation = Conversation.current();\n\n if (conversation) {\n await conversation.startAsr(params);\n }\n}\n\n/**\n * Заканчивает текстовую расшифровку звонка\n */\nexport async function stopAsr(params?: IAsrStopParams): Promise<void> {\n const conversation = Conversation.current();\n\n if (conversation) {\n await conversation.stopAsr(params);\n }\n}\n\n/**\n * Запрашивает/отключает реал-тайм расшифровку звонка\n */\nexport async function requestAsr(request: boolean): Promise<void> {\n const conversation = Conversation.current();\n\n if (conversation) {\n await conversation.requestAsr(request);\n }\n}\n\nexport async function startUrlSharing(sharedUrl: string) {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.startUrlSharing(sharedUrl);\n }\n return Promise.reject();\n}\n\nexport async function stopUrlSharing() {\n const conversation = Conversation.current();\n if (conversation) {\n return conversation.stopUrlSharing();\n }\n return Promise.reject();\n}\n\n\n/**\n * Версия SDK\n */\nexport function version(): string {\n return Params.sdkVersion;\n}\n\nexport type {\n AddParticipantParams,\n AudienceModeHandsResponse,\n BrowserName,\n CompositeUserId,\n ConversationData,\n ConversationParams,\n ConversationResponse,\n CustomError,\n ExternalId,\n ExternalParticipant,\n ExternalParticipantListChunk,\n ExternalParticipantListMarker,\n ExternalParticipantListMarkers as ExternalParticipantMarkers,\n ExternalParticipantId,\n GetParticipantsSignalingResponse,\n GetRoomsSignalingResponse,\n HangupReasonData,\n IApiEnv,\n IAPIBaseUrl,\n IAsrStartParams,\n IAsrStopParams,\n IAsrData,\n IceServer,\n JSONArray,\n JSONObject,\n JSONType,\n Layout,\n MediaModifiers,\n MediaSettings,\n MuteStates,\n OkUserId,\n ParamsObject,\n ParticipantId,\n ParticipantLayout,\n ParticipantListMarkers,\n ParticipantListType,\n ParticipantPriority,\n ParticipantsStateList,\n ParticipantStateData,\n ParticipantStateDataKey,\n ParticipantStateMapped,\n ParticipantStreamDescription,\n ParticipantListChunkParameters,\n ParticipantListMarker,\n RequestKeyFrame,\n Rooms,\n IGetParticipantsParameters,\n ScreenCaptureSettings,\n SignalingMessage,\n StatResult,\n StopStream,\n WaitingHallResponse,\n IMovieMetaData,\n IVideoDimentions,\n IFeedbackExternal,\n ISharedMovieInfo,\n ISharedMovieStoppedInfo,\n ISharedMovieState,\n ISharedMovieStateResponse,\n IAddMovieParams,\n IOnRemoteMovieData,\n IMoviePreview,\n IRoomId,\n Room,\n RoomsUpdate,\n RoomParticipantUpdate,\n IUpdateMovieData,\n IFeaturesPerRole,\n IMuteParticipantParams,\n IMuteParticipantInternalParams,\n IStartStreamData,\n IStopStreamData,\n IPublishStreamData,\n VmojiError,\n FastStartHandler,\n FastStartParams,\n};\n\nexport {\n Api,\n AuthData,\n BaseLogger,\n CallDirection,\n CallType,\n ChatRoomEventType,\n ConversationOption,\n DebugMessageType,\n ExternalIdType,\n FacingMode,\n FatalError,\n HangupReason,\n HangupType,\n MediaOption,\n MediaTrackKind,\n MediaType,\n MuteState,\n ParticipantState,\n ParticipantStateDataValue,\n ParticipantStatus,\n RecordRole,\n Signaling,\n SignalingCommandType,\n SignalingConnectionType,\n SignalingNotification,\n UserRole,\n UserType,\n TransportTopology,\n RoomsEventType,\n ConversationFeature,\n ArrayDequeue,\n ApiExternal,\n VolumeDetector,\n};\n", "export default abstract class BaseLogger {\n log(name: string, value?: string, immediately = false): void {\n // Do nothing\n }\n\n destroy() {\n // Do nothing\n }\n}\n", "export default class EventEmitter {\n private _handlers: { [key: string]: Function[] } = {};\n private _listeners: { dispose: Function }[] = [];\n\n protected _triggerEvent(event: string, ...args: any[]) {\n if (!Object.hasOwn(this._handlers, event)) {\n return;\n }\n\n for (const handler of this._handlers[event]) {\n // setTimeout(handler, 0, ...args);\n\n // NB: Ситуация: пользователь входит в звонок с одной вкодки и тем же пользователем входит\n // в тот же звонок с другой вкладки. На первой вкладке его выкидывает из звонка.\n // Для собеседника это выглядит как выход из звонка и вход.\n // Но из-за setTimeout выход происходит после входа и всё ломается.\n // Вернул пока синхронную обрботку.\n\n handler.apply(this, args);\n }\n }\n\n addEventListener(event: string, listener: Function): { dispose: Function } {\n if (!(typeof listener === 'function')) {\n throw new Error('Listener should be a function');\n }\n\n if (!Object.hasOwn(this._handlers, event)) {\n this._handlers[event] = [];\n }\n\n this._handlers[event].push(listener);\n\n return {\n dispose: this.removeEventListener.bind(this, event, listener),\n };\n }\n\n removeEventListener(event: string, listener: Function): void {\n if (!Object.hasOwn(this._handlers, event)) {\n return;\n }\n\n if (!listener) {\n delete this._handlers[event];\n }\n\n const pos = this._handlers[event].indexOf(listener);\n if (pos >= 0) {\n this._handlers[event].splice(pos, 1);\n }\n }\n\n subscribe(instance: EventEmitter, event: string, callback: Function) {\n const subscription = instance.addEventListener(event, callback);\n this._listeners.push(subscription);\n }\n\n unsubscribe() {\n this._listeners.forEach((listener) => {\n listener.dispose();\n });\n }\n}\n", "import EventEmitter from '../classes/EventEmitter';\nimport { ParticipantIdRegistry } from '../classes/ParticipantIdRegistry';\nimport { StreamDescriptionString } from '../types/ParticipantStreamDescription';\nimport { PerfStatReport } from '../types/PerfStatReporter';\nimport { NetworkStatReport } from '../types/NetworkStatReport';\nimport { TransportTopology } from '../classes/transport/Transport';\nimport ConversationFeature from '../enums/ConversationFeature';\nimport ConversationOption from '../enums/ConversationOption';\nimport MediaOption from '../enums/MediaOption';\nimport SignalingConnectionType from '../enums/SignalingConnectionType';\nimport UserRole from '../enums/UserRole';\nimport { JSONObject } from '../static/Json';\nimport { IAsrStartParams, IAsrStopParams } from '../types/Asr';\nimport ConversationResponse from '../types/ConversationResponse';\nimport MediaModifiers from '../types/MediaModifiers';\nimport MediaSettings from '../types/MediaSettings';\nimport { IAddMovieParams, IUpdateMovieData } from '../types/MovieShare';\nimport MuteStates from '../types/MuteStates';\nimport { CompositeUserId, ParticipantId, ParticipantStateData } from '../types/Participant';\nimport { ParticipantLayout, RequestKeyFrame, StopStream } from '../types/ParticipantLayout';\nimport { ParticipantListChunkParameters } from '../types/ParticipantListChunk';\nimport SignalingMessage, { GetParticipantsSignalingResponse, GetRoomsSignalingResponse } from '../types/SignalingMessage';\nimport { SimulcastInfo } from '../types/SimulcastInfo';\nimport { ChangeSimulcast } from '../types/ChangeSimulcast';\nimport { IPublishStreamData, IRecordConfData, IStartStreamData, IStopStreamData } from '../types/Streams';\nimport { SharingStatReport } from '../classes/screenshare/SharingStatReport';\n\n/**\n * Параметры добавления пользователя в звонок\n */\nexport interface AddParticipantParams {\n /**\n * @deprecated\n */\n showChatHistory?: boolean;\n ttChat?: boolean;\n /**\n * Удалить юзера из бан-листа. Доступно только админу звонка\n */\n unban?: boolean;\n /**\n * JSON.stringify(\\{show_chat_history: boolean\\})\n */\n payload?: string;\n}\n\n/**\n * Should trigger SignalingEvent.NOTIFICATION on notification message and SignalingEvent.FAILED on error\n * https://wiki.odkl.ru/display/projects/Signaling+API#SignalingAPI-Notifications\n * @hidden\n */\nexport default abstract class BaseSignaling extends EventEmitter {\n // NB: `conversation` используется для правильного старта анонимных звонков\n abstract connect(connectionType: SignalingConnectionType, conversation?: ConversationResponse): Promise<SignalingMessage.Connection>;\n abstract close(): void;\n\n abstract hangup(reason: string): Promise<SignalingMessage | void>;\n abstract acceptCall(mediaSettings: MediaSettings): Promise<SignalingMessage>;\n\n abstract sendSdp(participantId: ParticipantId, sdp: RTCSessionDescriptionInit, extraPayload?: Record<string, any>): Promise<SignalingMessage>;\n\n abstract sendCandidate(participantId: ParticipantId, candidate: RTCIceCandidate): Promise<SignalingMessage>;\n abstract changeMediaSettings(mediaSettings: MediaSettings): Promise<SignalingMessage>;\n abstract changeParticipantState(state: ParticipantStateData, compositeUserId?: CompositeUserId): Promise<SignalingMessage>;\n abstract putHandsDown(): Promise<SignalingMessage>;\n\n abstract addParticipant(externalIds: CompositeUserId[], params?: AddParticipantParams): Promise<SignalingMessage>;\n abstract addParticipantLegacy(participantIds: CompositeUserId[], params?: AddParticipantParams): Promise<SignalingMessage>;\n abstract removeParticipant(participantId: CompositeUserId, ban?: boolean): Promise<SignalingMessage>;\n abstract allocateConsumer(description: RTCSessionDescription | null, capabilities: { [key: string]: number | boolean | string }): Promise<SignalingMessage>;\n abstract acceptProducer(description: RTCSessionDescriptionInit, ssrcs: string[]): Promise<SignalingMessage>;\n\n /**\n * @deprecated Use updateDisplayLayout instead\n */\n abstract changePriorities(priorities: { [key: string]: number }): Promise<SignalingMessage | void>;\n\n abstract updateDisplayLayout(layouts: { [streamDesc: StreamDescriptionString]: ParticipantLayout | StopStream | RequestKeyFrame }): Promise<SignalingMessage | void>;\n\n abstract addMovie(data: IAddMovieParams): Promise<SignalingMessage>;\n abstract updateMovie(data: IUpdateMovieData): Promise<SignalingMessage>;\n abstract removeMovie(data: any): Promise<SignalingMessage>;\n\n abstract startUrlSharing(sharedUrl: string): Promise<SignalingMessage>;\n abstract stopUrlSharing(): Promise<SignalingMessage>;\n\n abstract updateRooms(rooms: Record<any, any>[], assignRandomly?: boolean): Promise<SignalingMessage>;\n abstract activateRooms(roomIds: number[], deactivate: boolean): Promise<SignalingMessage>;\n abstract switchRoom(toRoomId: number | null, participantId?: ParticipantId): Promise<SignalingMessage>;\n abstract getRooms(withParticipants: boolean): Promise<GetRoomsSignalingResponse>;\n abstract removeRooms(roomIds: number[]): Promise<SignalingMessage>;\n\n abstract startStream(data: IStartStreamData): Promise<SignalingMessage>;\n abstract stopStream(data: IStopStreamData): Promise<SignalingMessage>;\n abstract publishStream(data: IPublishStreamData): Promise<SignalingMessage>;\n abstract recordSetConf(conf: IRecordConfData): Promise<SignalingMessage>;\n abstract getRecordStatus(): Promise<SignalingMessage>;\n\n abstract switchTopology(topology: TransportTopology, force?: boolean): Promise<SignalingMessage>;\n\n abstract reportPerfStat(report: PerfStatReport): Promise<SignalingMessage>;\n abstract reportSharingStat(report: SharingStatReport): Promise<SignalingMessage>;\n abstract reportNetworkStat(report: NetworkStatReport): Promise<SignalingMessage>;\n\n abstract chatMessage(message: string, participantId: CompositeUserId | null): Promise<SignalingMessage>;\n abstract chatHistory(count: number): Promise<SignalingMessage>;\n\n abstract customData(data: JSONObject, participantId: ParticipantId | null): Promise<SignalingMessage>;\n\n abstract grantRoles(participantId: ParticipantId, roles: UserRole[], revoke: boolean): Promise<SignalingMessage>;\n abstract muteParticipant(participantId: ParticipantId | null, muteStates: MuteStates, requestedMedia: MediaOption[], roomId: number | null): Promise<SignalingMessage>;\n abstract enableFeatureForRoles(feature: ConversationFeature, roles: UserRole[]): Promise<SignalingMessage>;\n abstract pinParticipant(participantId: ParticipantId, unpin: boolean, roomId: number | null): Promise<SignalingMessage>;\n abstract updateMediaModifiers(mediaModifiers: MediaModifiers): Promise<SignalingMessage>;\n abstract enableVideoSuspend(enabled: boolean): Promise<SignalingMessage>;\n abstract enableVideoSuspendSuggest(enabled: boolean): Promise<SignalingMessage>;\n abstract changeSimulcast(changeSimulcast: ChangeSimulcast): Promise<SignalingMessage>;\n abstract changeOptions(changes: { [key in ConversationOption]?: boolean }): Promise<SignalingMessage>;\n abstract getWaitingHall(fromId: SignalingMessage.WaitingParticipantId | null, count?: number, backward?: boolean): Promise<SignalingMessage>;\n abstract promoteParticipant(participantId?: CompositeUserId, demote?: boolean): Promise<SignalingMessage>;\n abstract requestPromotion(unrequest: boolean): Promise<SignalingMessage>;\n abstract acceptPromotion(reject: boolean): Promise<SignalingMessage>;\n abstract feedback(key: string): Promise<SignalingMessage>;\n abstract getHandQueue(): Promise<SignalingMessage>;\n abstract setProducerNotificationDataChannel(dataChannel: RTCDataChannel): void;\n abstract setProducerCommandDataChannel(dataChannel: RTCDataChannel): void;\n abstract useCommandDataChannel(status: boolean): void;\n abstract getParticipantListChunk(participantListChunkParameters: ParticipantListChunkParameters): Promise<SignalingMessage>;\n abstract getParticipants(externalIds: SignalingMessage.ExternalId[]): Promise<GetParticipantsSignalingResponse>;\n abstract getPeerId(): number | null;\n abstract startAsr(params: IAsrStartParams): Promise<SignalingMessage>;\n abstract stopAsr(params?: IAsrStopParams): Promise<SignalingMessage>;\n abstract requestAsr(request: boolean): Promise<SignalingMessage>;\n\n get ready() {\n return true;\n }\n\n setParticipantIdRegistry(participantIdRegistry: ParticipantIdRegistry) {\n // Do nothing\n }\n\n requestRealloc() {\n // Do nothing\n }\n\n setEndpoint(endpoint: string) {\n // Do nothing\n }\n\n setWebTransportEndpoint(endpoint: string | null) {\n // Do nothing\n }\n\n setConversationId(conversationId: string) {\n // Do nothing\n }\n\n readyToSend(isReady = true) {\n // Do nothing\n }\n\n cleanup() {\n // Do nothing\n }\n\n requestTestMode(consumerCommand: string, producerCommand: string | null) {\n // Do nothing\n }\n\n getNextCommandSequenceNumber(): number {\n return 0;\n }\n}\n", "/**\n * Статус завершения звонка\n */\nenum HangupType {\n // hangupType\n CANCELED = 'CANCELED',\n REJECTED = 'REJECTED',\n REMOVED = 'REMOVED',\n HUNGUP = 'HUNGUP',\n MISSED = 'MISSED',\n BUSY = 'BUSY',\n FAILED = 'FAILED',\n NETWORK_ERROR = 'NETWORK_ERROR',\n KILLED = 'KILLED',\n BANNED = 'BANNED',\n HAS_ACTIVE_CALL = 'HAS_ACTIVE_CALL',\n // callStatus\n CALLER_IS_BLOCKED = 'CALLER_IS_BLOCKED',\n NOT_FRIENDS = 'NOT_FRIENDS',\n CALLEE_IS_OFFLINE = 'CALLEE_IS_OFFLINE',\n CALLER_IS_REJECTED = 'CALLER_IS_REJECTED',\n UNKNOWN_ERROR = 'UNKNOWN_ERROR',\n UNSUPPORTED = 'UNSUPPORTED',\n OLD_VERSION = 'OLD_VERSION',\n SERVICE_DISABLED = 'SERVICE_DISABLED',\n SERVICE_UNAVAILABLE = 'SERVICE_UNAVAILABLE',\n EXTERNAL_API_ERROR = 'EXTERNAL_API_ERROR',\n SOCKET_CLOSED = 'SOCKET_CLOSED',\n ENDED = 'ENDED',\n KILLED_WITHOUT_DELETE = 'KILLED_WITHOUT_DELETE',\n ANOTHER_DEVICE = 'ANOTHER_DEVICE',\n NOT_FOUND = 'NOT_FOUND',\n VCHAT_DETAILED_ERROR = 'VCHAT_DETAILED_ERROR',\n TIMEOUT = 'TIMEOUT',\n /**\n * Количество участников превысило допустимый размер\n */\n PARTICIPANT_LIMIT_REACHED = 'PARTICIPANT_LIMIT_REACHED',\n /**\n * Проблемы при работе через FastStart\n */\n FAST_START_ERROR = 'FAST_START_ERROR',\n /**\n * Таймаут инициализации вызова – звонок не начался\n *\n * Этот статус означает, что вызов был инициирован, но к нему\n * ни один участник не подключился через WebSocket/WebTransport\n * в ожидаемый период времени. Обычно это происходит, когда:\n * - Устройства вызываемого находятся офлайн\n * - Проблемы с сетевым соединением мешают установить связь\n * - Приложение вызываемого не запущено или упало\n * - Брандмауэр или сетевые ограничения блокируют подключение\n */\n CALL_TIMEOUT = 'CALL_TIMEOUT',\n}\n\nexport default HangupType;\n", "import FatalError from '../enums/FatalError';\nimport HangupType from '../enums/HangupType';\n\n/**\n * Дополнительное сообщение об ошибке\n */\nexport interface CustomError {\n vchat_detailed_api_error: VChatDetailedApiError;\n}\n\ninterface VChatDetailedApiError {\n code: string;\n error_id: string;\n}\n\n/**\n * Сообщение о завершении звонка\n */\nexport interface HangupReasonData {\n message?: string;\n code?: number;\n remote?: boolean;\n custom_error?: CustomError;\n}\n\n/**\n * Сообщение о завершении звонка\n */\nexport default class HangupReason extends Error {\n /**\n * Текст ошибки\n */\n override readonly message: string;\n /**\n * Звонок завершился штатно\n */\n readonly hangup: HangupType;\n /**\n * Звонок завершился с ошибкой\n */\n readonly error: FatalError;\n /**\n * Код ошибки\n */\n readonly code: number;\n /**\n * Звонок завершился сервером\n */\n readonly remote: boolean;\n /**\n * Новый формат ошибок\n */\n readonly custom_error: CustomError | null;\n\n constructor(type: HangupType | FatalError, data?: HangupReasonData) {\n super();\n\n this.name = 'HangupReason';\n this.code = (data && data.code) || 0;\n this.remote = (data && data.remote) || false;\n this.custom_error = data?.custom_error ?? null;\n\n if (Object.values(HangupType).indexOf(type as HangupType) > -1) {\n this.hangup = type as HangupType;\n } else {\n this.error = type as FatalError;\n }\n\n const msg = [];\n if (this.error) {\n msg.push('error');\n }\n if (this.remote) {\n msg.push('remote');\n }\n if (this.code) {\n msg.push(`code: ${this.code}`);\n }\n if (data && data.message) {\n msg.push(`message: '${data.message}'`);\n }\n\n this.message = type + (msg.length ? ` (${msg.join(', ')})` : '');\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, HangupReason);\n }\n }\n}\n", "import BaseApi, { ClientEvent, ClientStats, LogItem } from '../abstract/BaseApi';\nimport BaseLogger from '../abstract/BaseLogger';\nimport StatLog from '../enums/StatLog';\n\n/**\n * Класс отвечает за отправку различной информации в сервис статистики (события, статистика и подобное)\n */\nexport default class Logger extends BaseLogger {\n private static _instance: Logger | null;\n private static _conversationIdProvider: (() => string | null) | null = null;\n\n static setConversationIdProvider(provider: () => string | null) {\n Logger._conversationIdProvider = provider;\n }\n\n static create(api: BaseApi, externalLogger: BaseLogger | null) {\n if (!Logger._instance) {\n Logger._instance = new Logger(api, externalLogger);\n }\n }\n\n static log(name: StatLog, value?: string, immediately = false): void {\n if (Logger._instance) {\n Logger._instance.log(name, value, immediately);\n }\n }\n\n static logCustom(name: StatLog, params: Record<string, string | number>, immediately = false): void {\n if (Logger._instance) {\n Logger._instance.logCustom(name, params, immediately);\n }\n }\n\n static logClientStats(params: Record<string, string | number | undefined | null>, immediately = false): void {\n if (Logger._instance) {\n Logger._instance.logClientStats(params, immediately);\n }\n }\n\n static logClientEvent(params: Record<string, string | number | undefined | null>, immediately = false): void {\n if (Logger._instance) {\n Logger._instance.logClientEvent(params, immediately);\n }\n }\n\n static destroy() {\n if (Logger._instance) {\n Logger._instance.destroy();\n }\n Logger._instance = null;\n }\n\n private readonly _externalLogger: BaseLogger | null;\n private readonly _api: BaseApi;\n private readonly _batchInterval = 3000;\n private _batchedLogItems: LogItem[] = [];\n private _batchedClientStats: ClientStats[] = [];\n private _batchedClientEvents: ClientEvent[] = [];\n private _batchTimeout: number | null = null;\n private _serverTimeDelta = 0;\n\n constructor(api: BaseApi, externalLogger: BaseLogger | null) {\n super();\n\n this._api = api;\n this._externalLogger = externalLogger;\n this._calculateServerTimeDelta();\n }\n\n override log(name: StatLog, value?: string, immediately = false) {\n const params: Record<string, string> = {};\n if (typeof value !== 'undefined') {\n params.param = value;\n }\n\n this._logInternal(name, params, immediately);\n\n if (this._externalLogger) {\n this._externalLogger.log(name, value, immediately);\n }\n }\n\n logCustom(name: string, params: Record<string, string | number>, immediately = false) {\n this._logInternal(name, params, immediately);\n }\n\n logClientStats(data: Record<string, string | number | undefined | null>, immediately = false) {\n const clientStats = Object.assign(data, {\n vcid: this._getConversationId(),\n timestamp: this._now(),\n });\n\n // Eliminating undefined values\n Object.keys(clientStats).forEach((key) => {\n if (clientStats[key] === undefined) {\n delete clientStats[key];\n }\n });\n\n this._batchedClientStats.push(clientStats as ClientStats);\n\n if (immediately || !this._batchTimeout) {\n this._sendBatch();\n }\n }\n\n logClientEvent(data: Record<string, string | number | undefined | null>, immediately = false) {\n const clientEvent = Object.assign(data, {\n vcid: this._getConversationId(),\n timestamp: this._now(),\n });\n\n this._batchedClientEvents.push(clientEvent as ClientEvent);\n\n if (immediately || !this._batchTimeout) {\n this._sendBatch();\n }\n }\n\n override destroy() {\n this._sendBatch();\n this._stopTimeout();\n\n if (this._externalLogger) {\n this._externalLogger.destroy();\n }\n }\n\n private _logInternal(operation: string, custom: Record<string, string | number>, immediately: boolean) {\n const data: LogItem = {\n type: 1,\n time: 0,\n operation,\n timestamp: this._now(),\n custom: Object.assign(custom, { vcid: this._getConversationId() }),\n uid: this._api.getUserId(),\n };\n\n this._batchedLogItems.push(data);\n\n if (immediately || !this._batchTimeout) {\n this._sendBatch();\n }\n }\n\n private _getConversationId(): string | null {\n if (Logger._conversationIdProvider) {\n try {\n return Logger._conversationIdProvider();\n } catch (e) {\n return null;\n }\n }\n return null;\n }\n\n private _sendBatch() {\n this._stopTimeout();\n let isStartTimeoutRequested = false;\n\n if (this._batchedLogItems.length > 0) {\n this._sendLogItems(this._batchedLogItems);\n this._batchedLogItems = [];\n isStartTimeoutRequested = true;\n }\n\n if (this._batchedClientStats.length > 0) {\n this._sendClientStats(this._batchedClientStats);\n this._batchedClientStats = [];\n isStartTimeoutRequested = true;\n }\n\n if (this._batchedClientEvents.length > 0) {\n this._sendClientEvents(this._batchedClientEvents);\n this._batchedClientEvents = [];\n isStartTimeoutRequested = true;\n }\n\n if (isStartTimeoutRequested) {\n this._startTimeout();\n }\n }\n\n private _startTimeout() {\n this._batchTimeout = window.setTimeout(() => this._sendBatch(), this._batchInterval);\n }\n\n private _stopTimeout() {\n if (this._batchTimeout) {\n clearTimeout(this._batchTimeout);\n this._batchTimeout = null;\n }\n }\n\n private _sendLogItems(data: LogItem[]) {\n this._api.log(data);\n }\n\n private _sendClientStats(data: ClientStats[]) {\n this._api.logClientStats(data);\n }\n\n private _sendClientEvents(data: ClientEvent[]) {\n this._api.logClientEvents(data);\n }\n\n private async _calculateServerTimeDelta() {\n try {\n const serverTime = await this._api.getServerTime();\n this._serverTimeDelta = Date.now() - serverTime;\n } catch (e) {}\n }\n\n private _now() {\n // Текущее время устройства пользователя с поправкой на серверное время\n return Date.now() - this._serverTimeDelta;\n }\n}\n", "import { Any, Arr, Int, Nil, ReadBuffer, Str, WriteBuffer, Bool } from 'messagepack';\nimport SignalingCommandType from '../enums/SignalingCommandType';\nimport Debug from '../static/Debug';\nimport { blobToArrayBuffer } from '../static/Polyfills';\nimport { isRequestKeyFrame, isStopStreaming } from '../types/LayoutUtils';\nimport { NetworkStatReport } from '../types/NetworkStatReport';\nimport ParticipantLayout, { RequestKeyFrame, StopStream } from '../types/ParticipantLayout';\nimport { ParticipantStreamDescription, serializeParticipantStreamDescription, StreamDescriptionString } from '../types/ParticipantStreamDescription';\nimport { RequestAsr } from '../types/RequestAsr';\nimport { EnableVideoSuspend } from '../types/EnableVideoSuspend';\nimport { EnableVideoSuspendSuggest } from '../types/EnableVideoSuspendSuggest';\nimport SignalingMessage from '../types/SignalingMessage';\nimport { createReadBuffer, createWriteBuffer } from '../utils/MsgPackerBufferUtils';\nimport { PerfStatReport } from '../types/PerfStatReporter';\nimport { ChangeSimulcast } from '../types/ChangeSimulcast';\nimport { SharingStatReport } from './screenshare/SharingStatReport';\nimport { ParticipantIdRegistry } from './ParticipantIdRegistry';\n\nconst UPDATE_DISPLAY_LAYOUT_CODE = 0;\nconst REPORT_PERF_STAT_CODE = 1;\nconst REPORT_SHARING_STAT_CODE = 2;\nconst REQUEST_ASR_CODE = 3;\nconst REPORT_NETWORK_STAT_CODE = 4;\nconst ENABLE_VIDEO_SUSPEND_CODE = 5;\nconst ENABLE_VIDEO_SUSPEND_SUGGEST_CODE = 6;\nconst CHANGE_SIMULCAST_CODE = 7;\n\nconst LAYOUT_DEFAULT = 0;\nconst LAYOUT_STOP_STREAM = 1;\nconst LAYOUT_REQUEST_KEY_FRAME = 2;\n\nconst BASE_VERSION = 0;\n\nconst RESPONSE_MESSAGE_TYPE = 0;\n\nconst FIT_TYPE_COVER = 0;\nconst FIT_TYPE_CONTAIN = 1;\n\nexport class ProducerCommandSerializationService {\n private participantIdRegistry: ParticipantIdRegistry | null = null;\n\n setParticipantIdRegistry(participantIdRegistry: ParticipantIdRegistry) {\n this.participantIdRegistry = participantIdRegistry;\n }\n\n serializeUpdateDisplayLayout(sequenceNumber: number, layouts: { [key: string]: ParticipantLayout | StopStream | RequestKeyFrame }): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, UPDATE_DISPLAY_LAYOUT_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n\n Nil.enc(writeBuffer, null); //reserved for isSnapshot\n\n const layoutBytesArray: ArrayBuffer[] = [];\n for (const streamDesc in layouts) {\n if (Object.hasOwn(layouts, streamDesc)) {\n this.writeLayout(layouts, streamDesc, layoutBytesArray);\n }\n }\n Arr.enc(writeBuffer, layoutBytesArray);\n\n Nil.enc(writeBuffer, null); //reserved for speaker layout\n\n return writeBuffer.ui8array().buffer;\n }\n\n private writeLayout(layouts: { [p: string]: ParticipantLayout | StopStream | RequestKeyFrame }, streamDesc: string, layoutBytesArray: ArrayBuffer[]) {\n const layout = layouts[streamDesc];\n const layoutBuffer = createWriteBuffer();\n\n this.writeStreamDesc(streamDesc, layoutBuffer);\n\n if (isStopStreaming(layout)) {\n Int.enc(layoutBuffer, LAYOUT_STOP_STREAM);\n } else if (isRequestKeyFrame(layout)) {\n Int.enc(layoutBuffer, LAYOUT_REQUEST_KEY_FRAME);\n } else {\n Int.enc(layoutBuffer, LAYOUT_DEFAULT);\n\n if (layout.priority !== undefined) {\n Int.enc(layoutBuffer, layout.priority);\n } else {\n Nil.enc(layoutBuffer, null);\n }\n\n if (layout.width !== undefined && layout.height !== undefined) {\n Int.enc(layoutBuffer, Math.round(layout.width));\n Int.enc(layoutBuffer, Math.round(layout.height));\n } else {\n Nil.enc(layoutBuffer, null);\n Nil.enc(layoutBuffer, null);\n }\n\n if (layout.fit !== undefined) {\n switch (layout.fit) {\n case 'cv':\n Int.enc(layoutBuffer, FIT_TYPE_COVER);\n break;\n case 'cn':\n Int.enc(layoutBuffer, FIT_TYPE_CONTAIN);\n break;\n default:\n Nil.enc(layoutBuffer, null);\n }\n } else {\n Nil.enc(layoutBuffer, null);\n }\n }\n\n layoutBytesArray.push(layoutBuffer.ui8array().buffer);\n }\n\n private writeStreamDesc(streamDesc: string, writeBuffer: WriteBuffer) {\n if (this.participantIdRegistry) {\n const compactId = this.participantIdRegistry.getCompactId(streamDesc);\n if (compactId !== undefined) {\n Int.enc(writeBuffer, compactId);\n return;\n }\n }\n Str.enc(writeBuffer, streamDesc);\n }\n\n serializePerfStatReport(sequenceNumber: number, report: PerfStatReport): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, REPORT_PERF_STAT_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n Int.enc(writeBuffer, report.framesDecoded);\n Int.enc(writeBuffer, report.framesReceived);\n return writeBuffer.ui8array().buffer;\n }\n\n serializeSharingStatReport(sequenceNumber: number, report: SharingStatReport): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, REPORT_SHARING_STAT_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n Int.enc(writeBuffer, report.minDelay);\n Int.enc(writeBuffer, report.maxDelay);\n Int.enc(writeBuffer, report.avgDelay);\n Int.enc(writeBuffer, report.largeDelayDuration);\n return writeBuffer.ui8array().buffer;\n }\n\n serializeRequestAsr(sequenceNumber: number, params: RequestAsr): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, REQUEST_ASR_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n Bool.enc(writeBuffer, params.request);\n return writeBuffer.ui8array().buffer;\n }\n\n serializeNetworkStatReport(sequenceNumber: number, report: NetworkStatReport): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, REPORT_NETWORK_STAT_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n Int.enc(writeBuffer, report.timestamp);\n Int.enc(writeBuffer, report.sendBitrate);\n return writeBuffer.ui8array().buffer;\n }\n\n serializeEnableVideoSuspend(sequenceNumber: number, params: EnableVideoSuspend): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, ENABLE_VIDEO_SUSPEND_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n Bool.enc(writeBuffer, params.enabled);\n return writeBuffer.ui8array().buffer;\n }\n\n serializeEnableVideoSuspendSuggest(sequenceNumber: number, params: EnableVideoSuspendSuggest): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, ENABLE_VIDEO_SUSPEND_SUGGEST_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n Bool.enc(writeBuffer, params.enabled);\n return writeBuffer.ui8array().buffer;\n }\n\n serializeChangeSimulcast(sequenceNumber: number, params: ChangeSimulcast): ArrayBuffer {\n const writeBuffer = createWriteBuffer();\n Int.enc(writeBuffer, CHANGE_SIMULCAST_CODE);\n Int.enc(writeBuffer, BASE_VERSION);\n Int.enc(writeBuffer, sequenceNumber);\n const streamCount = params.simulcastInfo.streams.length;\n Int.enc(writeBuffer, params.mediaSource);\n Int.enc(writeBuffer, streamCount);\n for (const stream of params.simulcastInfo.streams) {\n Str.enc(writeBuffer, stream.rid);\n Int.enc(writeBuffer, stream.width);\n Int.enc(writeBuffer, stream.height);\n Int.enc(writeBuffer, stream.fps);\n Int.enc(writeBuffer, stream.bitrate / 1000);\n }\n return writeBuffer.ui8array().buffer;\n }\n\n async deserializeCommandResponse(data: BufferSource | Blob): Promise<SignalingMessage | undefined> {\n let readBuffer;\n if (data instanceof Blob) {\n const arrayBuffer = 'arrayBuffer' in Blob.prototype ? await data.arrayBuffer() : await blobToArrayBuffer(data);\n readBuffer = createReadBuffer(arrayBuffer);\n } else {\n readBuffer = createReadBuffer(data);\n }\n const commandType = Int.dec(readBuffer);\n const version = Int.dec(readBuffer);\n if (version !== BASE_VERSION) {\n Debug.warn('Unsupported version for command type: ' + commandType + ', version ' + version);\n return undefined;\n }\n const messageType = Int.dec(readBuffer);\n if (messageType !== RESPONSE_MESSAGE_TYPE) {\n Debug.warn('Error code: ' + commandType + 'received for command type: ' + commandType + ', version ' + version);\n return undefined;\n }\n switch (commandType) {\n case UPDATE_DISPLAY_LAYOUT_CODE:\n return this.deserializeUpdateDisplayLayoutResponse(readBuffer);\n case REPORT_PERF_STAT_CODE:\n return this.deserializeReportPerfStatResponse(readBuffer);\n default:\n Debug.warn('unsupported command response commandType: ' + commandType);\n return undefined;\n }\n }\n\n private deserializeUpdateDisplayLayoutResponse(readBuffer: ReadBuffer): SignalingMessage {\n const sequence = Int.dec(readBuffer);\n const errors = Arr.dec(readBuffer) as BufferSource[];\n const errorCodeByParticipantId: { [key: StreamDescriptionString]: number } = {};\n errors.forEach((errorData) => {\n const errorReadBuffer = createReadBuffer(errorData);\n const streamDescValue = Any.dec(errorReadBuffer);\n if (typeof streamDescValue === 'string') {\n errorCodeByParticipantId[streamDescValue as string] = Int.dec(errorReadBuffer);\n } else {\n const compactedId = streamDescValue as number;\n const streamDesc = serializeParticipantStreamDescription(this.participantIdRegistry?.getStreamDescription(compactedId) as ParticipantStreamDescription);\n errorCodeByParticipantId[streamDesc] = Int.dec(errorReadBuffer);\n }\n });\n return {\n type: 'response',\n sequence,\n response: SignalingCommandType.UPDATE_DISPLAY_LAYOUT.toString(),\n errorCodeByParticipantId,\n };\n }\n\n private deserializeReportPerfStatResponse(readBuffer: ReadBuffer): SignalingMessage {\n const sequence = Int.dec(readBuffer);\n const estimatedPerformanceIndex = Int.dec(readBuffer);\n return {\n type: 'response',\n sequence,\n response: SignalingCommandType.REPORT_PERF_STAT.toString(),\n estimatedPerformanceIndex,\n };\n }\n}\n", "enum SignalingCommandType {\n RECOVER = 'recover',\n ACCEPT_CALL = 'accept-call',\n ADD_PARTICIPANT = 'add-participant',\n REMOVE_PARTICIPANT = 'remove-participant',\n HANGUP = 'hangup',\n TRANSMIT_DATA = 'transmit-data',\n ACCEPT_PRODUCER = 'accept-producer',\n ALLOCATE_CONSUMER = 'allocate-consumer',\n CHANGE_MEDIA_SETTINGS = 'change-media-settings',\n CHANGE_PARTICIPANT_STATE = 'change-participant-state',\n CHANGE_STREAM_PRIORITIES = 'change-streams-priorities',\n UPDATE_DISPLAY_LAYOUT = 'update-display-layout',\n REPORT_PERF_STAT = 'report-perf-stat',\n REPORT_SHARING_STAT = 'report-sharing-stat',\n REPORT_NETWORK_STAT = 'report-network-stat',\n RECORD_START = 'record-start',\n RECORD_STOP = 'record-stop',\n RECORD_PUBLISH = 'record-publish',\n RECORD_SET_CONF = 'record-set-conf',\n RECORD_GET_STATUS = 'record-get-status',\n SWITCH_MICRO = 'switch-micro',\n SWITCH_TOPOLOGY = 'switch-topology',\n REQUEST_REALLOC = 'request-realloc',\n CHAT_MESSAGE = 'chat-message',\n CHAT_HISTORY = 'chat-history',\n CUSTOM_DATA = 'custom-data',\n GRANT_ROLES = 'grant-roles',\n MUTE_PARTICIPANT = 'mute-participant',\n ENABLE_FEATURE_FOR_ROLES = 'enable-feature-for-roles',\n PIN_PARTICIPANT = 'pin-participant',\n UPDATE_MEDIA_MODIFIERS = 'update-media-modifiers',\n CHANGE_OPTIONS = 'change-options',\n GET_WAITING_HALL = 'get-waiting-hall',\n GET_PARTICIPANT_LIST_CHUNK = 'get-participant-list-chunk',\n GET_PARTICIPANTS = 'get-participants',\n PROMOTE_PARTICIPANT = 'promote-participant',\n REQUEST_TEST_MODE = 'request-test-mode',\n ADD_MOVIE = 'add-movie',\n UPDATE_MOVIE = 'update-movie',\n REMOVE_MOVIE = 'remove-movie',\n START_URL_SHARING = 'start-url-sharing',\n STOP_URL_SHARING = 'stop-url-sharing',\n GET_ROOMS = 'get-rooms',\n UPDATE_ROOMS = 'update-rooms',\n ACTIVATE_ROOMS = 'activate-rooms',\n REMOVE_ROOMS = 'remove-rooms',\n SWITCH_ROOM = 'switch-room',\n FEEDBACK = 'feedback',\n ASR_START = 'asr-start',\n ASR_STOP = 'asr-stop',\n REQUEST_ASR = 'request-asr',\n REQUEST_PROMOTION = 'request-promotion',\n ACCEPT_PROMOTION = 'accept-promotion',\n GET_HAND_QUEUE = 'get-hand-queue',\n ENABLE_VIDEO_SUSPEND = 'enable-video-suspend',\n ENABLE_VIDEO_SUSPEND_SUGGEST = 'enable-video-suspend-suggest',\n PUT_HANDS_DOWN = 'put-hands-down',\n CHANGE_SIMULCAST = 'change-simulcast',\n}\n\nexport default SignalingCommandType;\n", "/**\n * Типы ошибок\n */\nenum FatalError {\n // На будущее\n /**\n * Ошибка комбинированных разрешений на микрофон и камеру\n * Выбрасывается при отсутствии разрешений на оба устройства одновременно\n */\n MIC_CAMERA_PERMISSION = 'mic_camera',\n /**\n * Отсутствуют разрешения на доступ к камере\n * Выбрасывается при отказе пользователя в доступе к камере или системном запрете\n */\n CAMERA_PERMISSION = 'camera',\n /**\n * Отсутствуют разрешения на доступ к микрофону\n * Выбрасывается при отказе пользователя в доступе к микрофону или системном запрете\n */\n MIC_PERMISSION = 'mic',\n /**\n * Камера заблокирована другим приложением\n * Выбрасывается когда камера уже используется другим приложением\n */\n CAMERA_ACCESS = 'cameralock',\n /**\n * Микрофон заблокирован другим приложением\n * Выбрасывается когда микрофон уже используется другим приложением\n */\n MIC_ACCESS = 'miclock',\n /**\n * Микрофон не найден\n * Выбрасывается когда система не может найти доступный микрофон\n */\n MIC_NOT_FOUND = 'nomic',\n /**\n * Отсутствуют разрешения на доступ к экрану\n * Выбрасывается при отказе пользователя в доступе к скриншарингу\n */\n SCREEN_PERMISSION = 'screenpermission',\n /**\n * Общий сбой доступа к экрану\n * Выбрасывается при общих ошибках скриншаринга, кроме отказа в разрешении\n */\n SCREEN_ACCESS = 'screenlock',\n /**\n * Ошибка соединения\n * Выбрасывается при проблемах с сетевым соединением\n */\n CONNECTION = 'connection',\n /**\n * Сетевая ошибка\n * Выбрасывается при сетевых проблемах во время вызова\n */\n NETWORK = 'network',\n /**\n * Неизвестная ошибка\n * Выбрасывается как fallback для непредвиденных ошибок\n */\n UNKNOWN = 'unknown',\n /**\n * Браузер или окружение не поддерживаются\n * Выбрасывается при запуске в неподдерживаемом браузере или окружении\n */\n UNSUPPORTED = 'unsupported',\n /**\n * Сбой сигнализации (signaling)\n * Выбрасывается при ошибках соединения с сервером сигнализации\n */\n SIGNALING_FAILED = 'signalingfailed',\n /**\n * Ошибка API или отсутствует ключ API\n * Выбрасывается при ошибках вызова API или отсутствии API ключа\n */\n API = 'api',\n /**\n * Ошибка аутентификации\n * Выбрасывается при ошибках аутентификации API\n */\n AUTH = 'auth',\n /**\n * Медиа-ограничения слишком строгие\n * Выбрасывается когда запрошенные параметры медиа не могут быть удовлетворены\n */\n OVERCONSTRAINED = 'overconstrained',\n}\nexport default FatalError;\n", "/**\n * Тип медиаустройства\n */\nenum MediaOption {\n AUDIO = 'AUDIO',\n VIDEO = 'VIDEO',\n SCREEN_SHARING = 'SCREEN_SHARING',\n MOVIE_SHARING = 'MOVIE_SHARING',\n AUDIO_SHARING = 'AUDIO_SHARING',\n ANIMOJI = 'ANIMOJI',\n}\n\nexport default MediaOption;\n", "const enum StatLog {\n ACCEPT_CONCURRENT = 'callAcceptConcurrent', // video/audio\n ACCEPT_INCOMING = 'callAcceptIncoming', // video/audio\n ACCEPTED_OUTGOING = 'callAcceptedOutgoing', // video/audio\n ADD_PARTICIPANT = 'callAddParticipant',\n CALL_SPEC_ERROR = 'callSpecError', // ошибки WebRTC\n DECLINE_INCOMING = 'callDeclineIncoming',\n DEVICE_CHANGED = 'callDeviceChanged', // смена камеры video/audio/screen\n DEVICES = 'callDevices', // залогировать количество %d_%d\n ERROR = 'callError',\n HANGUP = 'callHangup',\n ICE_CONNECTION_STATE = 'callIceConnectionState', // state\n ICE_CONNECTION_TYPE = 'callIceConnectionType', // type\n ICE_RESTART = 'callIceRestart', // без параметров\n JOIN_CONVERSATION = 'callJoinConversation', // video/audio\n MEDIA_STATUS = 'callMediaStatus', // изменение video_1, audio_0\n OUTGOING_CALL = 'callStart', // video/audio\n OUTGOING_MULTIPARTY_CALL = 'callStartMultiparty', // video/audio\n PAT_ALLOCATED = 'patAllocate',\n PAT_DEALLOCATED = 'patDeallocate',\n PAT_ERROR = 'patError',\n PAT_OUTDATED_RESPONSE = 'patOutdatedResponse',\n PAT_WAITING_TIME_ERROR = 'patWaitingTimeError',\n POOR_CONNECTION = 'callPoorConnection', // video / audio\n PUSH = 'callPush', // busy / rejected / accepted\n RECONNECT = 'callReconnect', // measure\n RELAY_POLICY = 'callForceRelay', // 1 / 0\n REMOVE_PARTICIPANT = 'callRemoveParticipant',\n SOCKET_ACTION = 'callSocketAction',\n TOPOLOGY_CHANGE_REQUESTED = 'callTopologyChangeRequested',\n}\n\nexport default StatLog;\n", "import libvpx from '@vkontakte/libvpx';\nimport Debug from '../../static/Debug';\nimport IDecoder from './IDecoder';\nimport { MessageType } from './Types';\nimport WorkerBase from './WorkerBase';\n\nexport default class LibVPxDecoder extends WorkerBase implements IDecoder {\n async init(onFrameImage: (image: ImageData) => void, onFrameError: (error: unknown) => void, onKeyFrameRequested: () => void): Promise<void> {\n Debug.debug('LibVPxDecoder started');\n await this._createWorker(\n LibVPxDecoderWorker,\n (data: any) => {\n if (data.error) {\n Debug.warn('LibVPxDecoder', data.error);\n onFrameError(data.error);\n } else if (data.requestKeyFrame) {\n Debug.debug('LibVPxDecoder requests key frame');\n onKeyFrameRequested();\n } else {\n const imageData = new ImageData(new Uint8ClampedArray(data.data), data.width, data.height);\n onFrameImage(imageData);\n }\n },\n [libvpx, libvpx.getUrl],\n );\n }\n\n decodeFrame(timestamp: number, data: Uint8Array, isVP9: boolean, keyFrame?: boolean): void {\n this._sendToWorker(MessageType.FRAME, { timestamp, data: data.buffer, isVP9, keyFrame, debug: Debug.enabled() }, [data.buffer]);\n }\n\n destroy(): void {\n this._removeWorker();\n Debug.debug('LibVPxDecoder destroyed');\n }\n\n static override isBrowserSupported(): boolean {\n return 'WebAssembly' in window && 'Worker' in window;\n }\n}\n", "import StatLog from '../../enums/StatLog';\nimport Debug from '../../static/Debug';\nimport Logger from '../Logger';\nimport { MessageType } from './Types';\n\nexport default abstract class WorkerBase {\n protected _worker: Worker | null = null;\n\n protected async _createWorker(\n workerFunctionData: string,\n onFrame: (data: any) => void,\n workerArgs: any[] = [],\n initArgs: { [key: string]: any } = {},\n transfer: any /* Transferable */[] = [],\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n const dataArgs = workerArgs.join(',');\n const blob = new Blob([workerFunctionData, `exports.default(${dataArgs});`], { type: 'application/javascript; charset=utf-8' });\n const blobURL = window.URL.createObjectURL(blob);\n this._worker = new Worker(blobURL);\n this._worker.onmessage = (e) => {\n switch (e.data.type) {\n case MessageType.READY:\n resolve();\n break;\n\n case MessageType.ERROR:\n reject(e.data.error);\n break;\n\n case MessageType.FRAME:\n onFrame(e.data);\n break;\n\n case MessageType.DEBUG:\n Debug.debug(e.data.message);\n break;\n\n case MessageType.LOG_ERROR:\n Logger.log(StatLog.ERROR, e.data.message);\n break;\n }\n };\n this._sendToWorker(MessageType.INIT, initArgs, transfer);\n });\n }\n\n protected _removeWorker(): void {\n this._worker?.terminate();\n this._worker = null;\n }\n\n protected _sendToWorker(type: string, data: { [key: string]: any } = {}, transfer: any /* Transferable */[] = []): void {\n this._worker?.postMessage(Object.assign({ type }, data), transfer);\n }\n\n static isBrowserSupported(): boolean {\n throw new Error('Not implemented');\n }\n}\n", "import Debug from '../../static/Debug';\nimport WebRTCUtils from '../../static/WebRTCUtils';\nimport IDecoder from './IDecoder';\nimport { MessageType } from './Types';\nimport WorkerBase from './WorkerBase';\n\nexport default class WebCodecsDecoder extends WorkerBase implements IDecoder {\n async init(onFrameImage: (frame: VideoFrame) => void, onFrameError: (error: unknown) => void, onKeyFrameRequested: () => void): Promise<void> {\n Debug.debug('WebCodecsDecoder started');\n\n await this._createWorker(\n WebCodecsDecoderWorker,\n (data: any) => {\n if (data.error) {\n Debug.warn('WebCodecsDecoder', data.error);\n onFrameError(data.error);\n } else if (data.requestKeyFrame) {\n Debug.debug('WebCodecsDecoder requests key frame');\n onKeyFrameRequested();\n } else {\n onFrameImage(data.data);\n data.data.close();\n }\n // VideoFrame стал Transferable только в 92 хроме (актуально для старых сборок на электроне)\n // @see https://groups.google.com/a/chromium.org/g/blink-dev/c/THMWmD7JGFM/m/TM0tb0LdAwAJ\n },\n [WebRTCUtils.baseChromeVersion() >= 92 || WebRTCUtils.browserName() === 'Safari'],\n );\n }\n\n decodeFrame(timestamp: number, data: Uint8Array, isVP9: boolean, keyFrame = false): void {\n this._sendToWorker(MessageType.FRAME, { timestamp, data: data.buffer, isVP9, keyFrame }, [data.buffer]);\n }\n\n destroy(): void {\n this._removeWorker();\n Debug.debug('WebCodecsDecoder destroyed');\n }\n\n static override isBrowserSupported(): boolean {\n return (\n 'VideoDecoder' in window &&\n 'Worker' in window &&\n 'VideoFrame' in window &&\n // В сафари 17.4 на интеле не играет шара в VP9 https://jira.mvk.com/browse/CALL-22850\n !WebRTCUtils.isBrokenVP9Decoder() &&\n // В фф 130 добавили поддержку VideoDecoder, но в ряде сценариев он не умеет декодировать vp8\\9\n // https://jira.mvk.com/browse/CALL-25253\n WebRTCUtils.browserName() !== 'Firefox'\n );\n }\n}\n", "export default class FpsMeter {\n private _counter = 0;\n private _interval = 0;\n private _lastCalculationTime = Date.now();\n private readonly _onCalculated: Function | null = null;\n\n constructor(callback: Function | null = null, intervalMs = 0) {\n this._onCalculated = callback;\n if (intervalMs) {\n this._interval = window.setInterval(() => this.calculate(), intervalMs);\n }\n }\n\n increment(value = 1): void {\n this._counter += value;\n }\n\n calculate(): number {\n const now = Date.now();\n const ms = now - this._lastCalculationTime;\n const fps = Math.round((this._counter * 1000) / ms);\n\n this._counter = 0;\n this._lastCalculationTime = now;\n\n this._onCalculated?.(fps);\n return fps;\n }\n\n destroy() {\n window.clearInterval(this._interval);\n this._interval = 0;\n }\n}\n", "import { BitStream } from 'bit-buffer';\nimport Debug from '../../static/Debug';\nimport { ParticipantId } from '../../types/Participant';\nimport Statistics from '../transport/Statistics';\nimport { IScreenShareStat } from '../../types/ScreenSharingStat';\nimport { StatScreenShareFirstFrame } from '../stat/StatScreenShareFirstFrame';\nimport { FrameChunk } from './Utils';\n\nconst SEQUENCE_OVERFLOW = 65536;\n\nconst MARK_SCREENSHARE_FREEZE_DURATION = 'MARK_SCREENSHARE_FREEZE_DURATION';\n\nexport type IOnStat = (stat: IScreenShareStat) => void;\nexport type IOnStream = (stream: MediaStream) => void;\n\nexport abstract class BaseStreamBuilder {\n protected readonly _participantId: ParticipantId;\n protected readonly _onStream: IOnStream;\n protected readonly _onStat: IOnStat;\n protected readonly _onKeyFrameRequested?: VoidFunction;\n protected readonly _statScreenShareFirstFrame: StatScreenShareFirstFrame;\n\n protected _chunks: FrameChunk[] = [];\n\n protected constructor(participantId: ParticipantId, onStream: IOnStream, onStat: IOnStat, onKeyFrameRequested?: VoidFunction) {\n this._participantId = participantId;\n this._onStream = onStream;\n this._onStat = onStat;\n this._onKeyFrameRequested = onKeyFrameRequested;\n this._statScreenShareFirstFrame = new StatScreenShareFirstFrame(participantId);\n }\n\n appendChunk(chunk: FrameChunk): void {\n const size = this._chunks.length;\n\n if (chunk.start) {\n this._measureFreezeDuration(false);\n this._measureFreezeDuration(true);\n if (size) {\n Debug.warn('[FrameBuilder] Cleanup buffer', Array.prototype.slice.call(this._chunks));\n this._chunks = [];\n }\n } else {\n if (!size || (this._chunks[size - 1].sequence + 1) % SEQUENCE_OVERFLOW !== chunk.sequence) {\n Debug.warn('[FrameBuilder] Got incorrect chunk');\n return;\n }\n }\n\n this._chunks.push(chunk);\n\n if (chunk.end) {\n const frameData = this._processFrameData();\n const { width, height } = BaseStreamBuilder.getFrameSize(frameData);\n this._processFrame({\n timestamp: chunk.timestamp,\n frameData,\n isVP9: chunk.isVP9,\n keyframe: chunk.keyframe,\n width,\n height,\n });\n\n this._statScreenShareFirstFrame.measure(width, height);\n }\n }\n\n destroy() {\n Statistics.clearMark(MARK_SCREENSHARE_FREEZE_DURATION);\n Statistics.clearMark(Statistics.getMarkNameScreenshareFirstFrame(this._participantId));\n // Не забудь вызвать в реализациях\n this._chunks = [];\n }\n\n protected abstract _processFrame(frame: FrameData): void;\n\n private _processFrameData(): Uint8Array<ArrayBuffer> {\n const chunks = this._chunks;\n this._chunks = []; // Делаем синхронно, чтобы не получить лишних чанков, пока обрабатываем очередь\n\n const size = chunks.reduce((calc, current) => calc + current.data.byteLength, 0);\n const result = new Uint8Array(size);\n\n let offset = 0;\n for (const chunk of chunks) {\n result.set(new Uint8Array(chunk.data), offset);\n offset += chunk.data.byteLength;\n }\n\n return result;\n }\n\n static getFrameSize(frameData: Uint8Array<ArrayBuffer>): { width: number; height: number } {\n const result = { width: 0, height: 0 };\n const reader = new BitStream(frameData.buffer);\n reader.bigEndian = true;\n\n reader.index += 2; // frame marker\n\n const profileLowBit = reader.readBits(1);\n const profileHighBit = reader.readBits(1);\n const profile = (profileHighBit << 1) | profileLowBit;\n if (profile === 3) {\n reader.index++; // reserved_zero\n }\n\n const showExistingFrame = reader.readBits(1);\n if (showExistingFrame === 1) {\n return result;\n }\n\n const frameType = reader.readBits(1);\n if (frameType !== 0) {\n return result; // not key frame\n }\n\n reader.index++; // show_frame\n reader.index++; // error_resilient_mode\n // frame_sync_code\n reader.index += 24;\n // color_config\n if (profile >= 2) {\n reader.index++;\n }\n\n const colorSpace = reader.readBits(3);\n if (colorSpace !== 7 /* CS_RGB */) {\n reader.index++; // color_range\n if (profile === 1 || profile === 3) {\n reader.index += 3;\n }\n } else if (profile === 1 || profile === 3) {\n reader.index++;\n }\n\n // frame_size\n result.width = reader.readBits(16) + 1;\n result.height = reader.readBits(16) + 1;\n\n return result;\n }\n\n static isBrowserSupported(): boolean {\n throw new Error('Method `isBrowserSupported` is not implemented');\n }\n\n private _measureFreezeDuration(start: boolean) {\n if (start) {\n Statistics.setMark(MARK_SCREENSHARE_FREEZE_DURATION);\n return;\n }\n\n const duration = Statistics.measureMark(MARK_SCREENSHARE_FREEZE_DURATION);\n if (duration !== null && duration > 1000) {\n this._onStat({ freeze_duration: duration });\n }\n }\n}\n\nexport interface FrameData {\n timestamp: number;\n frameData: Uint8Array;\n isVP9: boolean;\n keyframe: boolean;\n width: number; // 0 if not keyframe\n height: number; // 0 if not keyframe\n}\n", "enum UserType {\n USER = 'USER',\n GROUP = 'GROUP',\n}\n\nexport default UserType;\n", "import { type SimulcastInfo as ISimulcastInfo } from '../types/SimulcastInfo';\nimport type { VideoBitrateSettings } from '../types/VideoSettings';\nimport Utils from './Utils';\n\nexport const SIMULCAST_DEFAULT = {\n HEIGHT: 720,\n WIDTH: 1280,\n BITRATE: 1_000_000,\n};\n\nexport const SIMULCAST_SCALABILITY_MODE = 'L1T2';\n\nconst BASE_BITRATES_ASC: VideoBitrateSettings[] = [\n { dimension: 320, bitrate: 180_000 },\n { dimension: 520, bitrate: 400_000 },\n { dimension: 640, bitrate: 500_000 },\n { dimension: 960, bitrate: 900_000 },\n { dimension: 1280, bitrate: 1_200_000 },\n { dimension: 1920, bitrate: 2_500_000 },\n { dimension: 2560, bitrate: 3_500_000 },\n { dimension: 3840, bitrate: 5_000_000 },\n];\n\nexport const MAP_RID_TO_SCALE_RESOLUTION_DOWN_BY: Record<string, number> = {\n h: 1,\n m: 2,\n l: 4,\n};\n\nexport function isEqualSimulcastInfo(si1: ISimulcastInfo | null, si2: ISimulcastInfo | null) {\n if (!si1 || !si2) {\n return si1 === si2;\n }\n if (si1.streams.length === si2.streams.length) {\n return si1.streams.every((stream, i) => Utils.isObjectsEquals(stream, si2.streams[i]));\n }\n return false;\n}\n\nexport function findBitrateAsc(maxDimension: number, bitrates: VideoBitrateSettings[]) {\n // assuming that bitrates table is sorted ASC by dimension\n for (const element of bitrates) {\n if (maxDimension <= element.dimension) {\n return element.bitrate;\n }\n }\n return length > 0 ? bitrates[length - 1].bitrate : BASE_BITRATES_ASC[0].bitrate;\n}\n\nexport function calculateSimulcastInfo(width = SIMULCAST_DEFAULT.WIDTH, height = SIMULCAST_DEFAULT.HEIGHT, bitrates = BASE_BITRATES_ASC) {\n // create new simulcastInfo, based on track size\n const rids: string[] = ['h', 'm', 'l'];\n const maxDimension = Math.max(width, height);\n\n // calc how many layers fit into current camera resolution (according to libwebrtc)\n let layers = 1;\n if (maxDimension >= 960) {\n layers = 3;\n } else if (maxDimension >= 480) {\n layers = 2;\n }\n const simulcastInfo: ISimulcastInfo = { streams: [] };\n const fps = 30;\n // TODO: calc bitrate by table formula\n let bitrate = findBitrateAsc(maxDimension, bitrates) ?? SIMULCAST_DEFAULT.BITRATE;\n for (let i = 0; i < layers; i++) {\n const rid = rids[i];\n simulcastInfo.streams.push({ rid, width, height, fps, bitrate });\n width = Math.round(width / 2);\n height = Math.round(height / 2);\n bitrate = findBitrateAsc(Math.max(width, height), bitrates) ?? Math.round(bitrate / 2);\n }\n\n return simulcastInfo;\n}\n\nexport function findScaleResolutionDownBy(rid?: string) {\n return rid ? (MAP_RID_TO_SCALE_RESOLUTION_DOWN_BY[rid] ?? 1) : 1;\n}\n", "export const fromEntries =\n typeof Object.fromEntries === 'function'\n ? Object.fromEntries\n : function <T extends Record<string, V>, V = unknown>(entries: Iterable<readonly [string, T]>): { [p: string]: T } {\n if (!entries || !entries[Symbol.iterator]) {\n throw new Error('Object.fromEntries() requires a single iterable argument');\n }\n const obj: { [p: string]: T } = {};\n for (const [key, value] of entries) {\n obj[key] = value;\n }\n return obj;\n };\n\n// Blob.prototype.arrayBuffer\nexport async function blobToArrayBuffer(data: Blob): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const fileReader = new FileReader();\n fileReader.onload = (event) => {\n resolve(event.target?.result as ArrayBuffer);\n };\n fileReader.onerror = reject;\n fileReader.readAsArrayBuffer(data);\n });\n}\n", "import { MediaTrackKind } from '../classes/MediaSource';\nimport UserType from '../enums/UserType';\nimport { ExternalParticipant, ExternalParticipantListMarker } from '../types/ExternalId';\nimport { CompositeUserId, OkUserId, Participant, ParticipantId, ParticipantStateMapped } from '../types/Participant';\nimport SignalingMessage from '../types/SignalingMessage';\nimport VideoSettings from '../types/VideoSettings';\nimport type { SimulcastInfo } from '../types/SimulcastInfo';\nimport { calculateSimulcastInfo, findScaleResolutionDownBy, SIMULCAST_SCALABILITY_MODE } from './SimulcastInfo';\nimport Debug from './Debug';\nimport Params from './Params';\nimport { fromEntries } from './Polyfills';\n\nexport const PARAMETERS_SEPARATOR = ':';\nexport const DEVICE_IDX_PARAMETER = 'd';\nconst IDEAL_BITS_PER_MACROBLOCK = 533;\nconst FMTP_PREFIX = 'a=fmtp:';\nconst SPS_PPS_IDR_IN_KEYFRAME_FLAG = 'sps-pps-idr-in-keyframe=1';\n\n/** @hidden */\nnamespace Utils {\n const lineSeparator = /[\\r\\n]+/;\n const separator = '\\r\\n';\n\n function getPayloadTypesForCodec(lines: string[], codec: string): string[] {\n const rtpmapLinePattern = new RegExp('a=rtpmap:(\\\\d+) ([a-zA-Z0-9-]+)\\\\/\\\\d+');\n let i;\n const result = [];\n for (i = 0; i < lines.length; ++i) {\n const matchResult = lines[i].match(rtpmapLinePattern);\n if (matchResult && matchResult.length === 3 && matchResult[2] === codec) {\n result.push(matchResult[1]);\n }\n }\n return result;\n }\n\n function setDefaultCodec(mLine: string, pTypesToRemove: string[], pTypesPriority: string[]) {\n const elements = mLine.split(' ');\n\n // Just copy the first three parameters; codec order starts on fourth.\n const newLine = elements.slice(0, 3);\n\n // Put target payloads first and copy in the rest.\n let i;\n for (i = 3; i < elements.length; i++) {\n if (pTypesPriority.includes(elements[i])) {\n newLine.push(elements[i]);\n }\n }\n for (i = 3; i < elements.length; i++) {\n if (!pTypesPriority.includes(elements[i]) && !pTypesToRemove.includes(elements[i])) {\n newLine.push(elements[i]);\n }\n }\n return newLine.join(' ');\n }\n\n function processMLines(lines: string[], mediaType: string, pTypesToRemove: string[], pTypesPriority: string[]) {\n let i;\n const prefix = 'm=' + mediaType;\n for (i = 0; i < lines.length; ++i) {\n if (lines[i].startsWith(prefix)) {\n lines[i] = setDefaultCodec(lines[i], pTypesToRemove, pTypesPriority);\n }\n }\n }\n\n function addH264spsPpsIdrInKeyframe(lines: string[], h264PTs: string[]) {\n const fmtpLinePattern = new RegExp(FMTP_PREFIX + '(\\\\d+)');\n for (let i = 0; i < lines.length; ++i) {\n const matchResult = lines[i].match(fmtpLinePattern);\n if (matchResult && matchResult.length === 2 && h264PTs.includes(matchResult[1])) {\n const flagSeparator = lines[i].trim() === FMTP_PREFIX + matchResult[1] ? ' ' : ';';\n lines[i] += flagSeparator + SPS_PPS_IDR_IN_KEYFRAME_FLAG;\n }\n }\n }\n\n function removeCodec(lines: string[], codec: string) {\n const pTypes = getPayloadTypesForCodec(lines, codec);\n if (!pTypes.length) {\n return;\n }\n\n const pTypesToRemove: string[] = pTypes.slice(0);\n // find linked rtx payload types\n const fmtpAptLinePattern = new RegExp(FMTP_PREFIX + '(\\\\d+) apt=(\\\\d+)');\n let i;\n for (i = 0; i < lines.length; ++i) {\n const matchResult = lines[i].match(fmtpAptLinePattern);\n if (matchResult && matchResult.length === 3 && pTypesToRemove.includes(matchResult[2])) {\n pTypesToRemove.push(matchResult[1]);\n }\n }\n\n // drop all mentions of codec and rtx payload types\n const dropLinePattern = new RegExp('a=(rtpmap|rtcp-fb|fmtp):(\\\\d+) .*');\n // iterate in reverse for easy removal\n i = lines.length;\n while (i--) {\n const matchResult = lines[i].match(dropLinePattern);\n if (matchResult && matchResult.length === 3 && pTypesToRemove.includes(matchResult[2])) {\n lines.splice(i, 1);\n }\n }\n\n processMLines(lines, 'video', pTypesToRemove, []);\n }\n\n function getPayloadTypesForCodecInSection(lines: string[], start: number, end: number, codec: string): string[] {\n const rtpmapLinePattern = new RegExp('a=rtpmap:(\\\\d+) ([a-zA-Z0-9-]+)\\\\/\\\\d+');\n let i;\n const pTypes = [];\n for (i = start; i < end; ++i) {\n const matchResult = lines[i].match(rtpmapLinePattern);\n if (matchResult && matchResult.length === 3 && matchResult[2] === codec) {\n pTypes.push(matchResult[1]);\n }\n }\n if (!pTypes.length) {\n return pTypes;\n }\n\n // find linked rtx payload types\n const fmtpAptLinePattern = new RegExp(FMTP_PREFIX + '(\\\\d+) apt=(\\\\d+)');\n for (i = start; i < end; ++i) {\n const matchResult = lines[i].match(fmtpAptLinePattern);\n if (matchResult && matchResult.length === 3 && pTypes.includes(matchResult[2])) {\n pTypes.push(matchResult[1]);\n }\n }\n return pTypes;\n }\n\n function removeCodecInSection(lines: string[], start: number, end: number, codec: string): number {\n const pTypesToRemove = getPayloadTypesForCodecInSection(lines, start, end, codec);\n if (!pTypesToRemove.length) {\n return end + 1;\n }\n\n // drop all mentions of codec and rtx payload types\n const dropLinePattern = new RegExp('a=(rtpmap|rtcp-fb|fmtp):(\\\\d+) .*');\n // iterate in reverse for easy removal\n let removed = 0;\n let i = end;\n while (i >= start) {\n const matchResult = lines[i].match(dropLinePattern);\n if (matchResult && matchResult.length === 3 && pTypesToRemove.includes(matchResult[2])) {\n lines.splice(i, 1);\n removed++;\n }\n i--;\n }\n\n // remove codec from mline:\n lines[start] = setDefaultCodec(lines[start], pTypesToRemove, []);\n\n return end - removed + 1;\n }\n\n function removeVideoCodec(lines: string[], codec: string, sdpOwner: 'remote' | 'local', type: 'encoder' | 'decoder') {\n let mStart = -1;\n let mEnd = -1;\n let isRecvSection = false;\n for (let i = 0; i < lines.length; ++i) {\n if (mStart >= 0 && lines[i].startsWith('m=')) {\n mEnd = i - 1;\n if (isRecvSection) {\n i = removeCodecInSection(lines, mStart, mEnd, codec);\n }\n mStart = -1;\n mEnd = -1;\n isRecvSection = false;\n }\n if (lines[i].startsWith('m=video')) {\n mStart = i;\n }\n if (mStart >= 0) {\n // inside video section\n const direction = (sdpOwner === 'remote' && type === 'encoder') || (sdpOwner === 'local' && type === 'decoder') ? 'recvonly' : 'sendonly';\n if (lines[i].startsWith(`a=${direction}`) || lines[i].startsWith('a=sendrecv')) {\n isRecvSection = true;\n }\n }\n }\n mEnd = lines.length - 1;\n if (mStart >= 0) {\n if (isRecvSection) {\n removeCodecInSection(lines, mStart, mEnd, codec);\n }\n }\n }\n\n function patchH264(lines: string[], preferH264: boolean, h264spsPpsIdrInKeyframe: boolean) {\n const h264PTs = getPayloadTypesForCodec(lines, 'H264');\n if (preferH264) {\n processMLines(lines, 'video', [], h264PTs);\n }\n if (h264spsPpsIdrInKeyframe) {\n addH264spsPpsIdrInKeyframe(lines, h264PTs);\n }\n }\n\n function patchVp9(lines: string[]) {\n const vp9PTs = getPayloadTypesForCodec(lines, 'VP9');\n processMLines(lines, 'video', [], vp9PTs);\n }\n\n export function patchLocalSDP(\n sdp: string,\n preferH264: boolean,\n brokenH264Decoder: boolean,\n preferVP9: boolean,\n h264spsPpsIdrInKeyframe: boolean,\n isAudioNack = false,\n preferRed = false,\n ): string {\n if (!preferH264 && !brokenH264Decoder && !preferVP9 && !preferRed && !isAudioNack && !h264spsPpsIdrInKeyframe) {\n return sdp;\n }\n\n /**\n * добавляет строки, необходимые для NACK-hack в блок с аудио\n * (начинается с `m=audio`). __ТОЛЬКО__ для `DirectTransport` и Chromium\n */\n function addNackAudioLines(lines: string[]): string[] {\n const addLines = ['a=rtcp-fb:111 nack', 'a=rtcp-fb:111 nack pli'];\n const prefix = 'a=rtcp-fb:111';\n const index = lines.findIndex((line) => line.startsWith(prefix));\n if (~index) {\n lines[index] = lines[index] + separator + addLines.join(separator);\n }\n return lines;\n }\n\n function patchRed(lines: string[]) {\n const redPTs = getPayloadTypesForCodec(lines, 'red');\n if (redPTs.length > 0) {\n processMLines(lines, 'audio', [], redPTs);\n }\n }\n\n const sdpLines = sdp.split(lineSeparator);\n if (brokenH264Decoder) {\n removeVideoCodec(sdpLines, 'H264', 'local', 'decoder');\n } else if (preferH264 || h264spsPpsIdrInKeyframe) {\n patchH264(sdpLines, preferH264, h264spsPpsIdrInKeyframe);\n }\n\n if (preferVP9) {\n patchVp9(sdpLines);\n }\n if (preferRed) {\n patchRed(sdpLines);\n }\n if (isAudioNack) {\n addNackAudioLines(sdpLines);\n }\n return sdpLines.join(separator);\n }\n\n export function patchRemoteSDP(\n sdp: string,\n oldDataChannelDescription: boolean,\n preferH264: boolean,\n brokenH264: boolean,\n preferVP9: boolean,\n brokenVP9Encoder: boolean,\n brokenVP9Decoder: boolean,\n ): string {\n if (oldDataChannelDescription) {\n sdp = sdp\n .replace('m=application 9 UDP/DTLS/SCTP webrtc-datachannel', 'm=application 9 DTLS/SCTP 5000')\n .replace('a=sctp-port:5000', 'a=sctpmap:5000 webrtc-datachannel 256');\n }\n\n const sdpLines = sdp.split(lineSeparator);\n\n if (brokenH264) {\n removeCodec(sdpLines, 'H264');\n } else if (preferH264) {\n patchH264(sdpLines, preferH264, false);\n }\n\n // ugly...\n if (brokenVP9Encoder && brokenVP9Decoder) {\n removeCodec(sdpLines, 'VP9');\n } else if (brokenVP9Encoder) {\n removeVideoCodec(sdpLines, 'VP9', 'remote', 'encoder');\n } else if (brokenVP9Decoder) {\n removeVideoCodec(sdpLines, 'VP9', 'remote', 'decoder');\n } else if (preferVP9) {\n patchVp9(sdpLines);\n }\n\n return sdpLines.join(separator);\n }\n\n export function getPeerIdString(peerId: SignalingMessage.PeerId) {\n return peerId ? `${peerId.type || 'WEB_SOCKET'}_${peerId.id}` : '_';\n }\n\n export function comparePeerId(peerId1: SignalingMessage.PeerId, peerId2: SignalingMessage.PeerId) {\n return peerId1 && peerId1.id === peerId2.id && (peerId1.type || 'WEB_SOCKET') === (peerId2.type || 'WEB_SOCKET');\n }\n\n export async function getPeerConnectionHostInfo(pc: RTCPeerConnection): Promise<{ local: any; remote: any }> {\n const _info: { local: any; remote: any } = { local: null, remote: null };\n\n if (!pc || !pc.getStats) {\n return _info;\n }\n\n try {\n const stats = await pc.getStats(null);\n let _pair: any = null;\n\n stats.forEach((stat: any) => {\n if (stat.type === 'transport' && stat.selectedCandidatePairId) {\n _pair = stats.get(stat.selectedCandidatePairId);\n } else if (stat.type === 'candidate-pair' && stat.state === 'succeeded' && !_pair) {\n if (!Object.hasOwn(stat, 'selected') || stat.selected) {\n _pair = stat;\n }\n }\n });\n\n if (_pair?.localCandidateId) {\n const candidate = stats.get(_pair.localCandidateId);\n if (candidate) {\n _info.local = {\n type: candidate.candidateType,\n ip: candidate.ip || candidate.ipAddress,\n port: candidate.port || candidate.portNumber,\n };\n }\n }\n\n if (_pair?.remoteCandidateId) {\n const candidate = stats.get(_pair.remoteCandidateId);\n if (candidate) {\n _info.remote = {\n type: candidate.candidateType,\n ip: candidate.ip || candidate.ipAddress,\n port: candidate.port || candidate.portNumber,\n };\n }\n }\n\n return _info;\n } catch (e: any) {\n return _info;\n }\n }\n\n const LEGACY_ID_PATTERN = /^[0-9]+$/;\n const COMPOSITE_ID_PATTERN = /^([gu])([0-9]+)$/;\n\n export function composeUserId(id: CompositeUserId | OkUserId, type: UserType = UserType.USER): CompositeUserId {\n const strId = String(id);\n if (COMPOSITE_ID_PATTERN.test(strId)) {\n Debug.warn(`Already composite id [${id}] type supplied [${type}]`);\n return strId;\n } else if (type === UserType.GROUP) {\n return 'g' + strId;\n } else if (type === UserType.USER) {\n return 'u' + strId;\n } else {\n Debug.warn(`Unknown type [${type}] for id [${id}]`);\n return strId.match(LEGACY_ID_PATTERN) ? 'u' + strId : strId;\n }\n }\n\n export function composeParticipantId(id: CompositeUserId | OkUserId, type: UserType, deviceIdx = 0): ParticipantId {\n const userId = composeUserId(id, type);\n return compose(userId, deviceIdx);\n }\n\n export function compose(compositeId: CompositeUserId, deviceIdx?: number): ParticipantId {\n return !deviceIdx ? compositeId : compositeId + PARAMETERS_SEPARATOR + DEVICE_IDX_PARAMETER + deviceIdx;\n }\n\n export function composeId(participant: SignalingMessage.Participant): ParticipantId {\n return composeParticipantId(participant.id, participant.idType || UserType.USER, participant.deviceIdx);\n }\n\n export function composeDecorativeId(participant: SignalingMessage.Participant): ParticipantId | undefined {\n if (!participant.decorativeUserId) {\n return undefined;\n }\n\n return composeParticipantId(participant.decorativeUserId, participant.idType || UserType.USER, participant.deviceIdx);\n }\n\n export function composeMessageId(message: SignalingMessage): ParticipantId {\n return message.participant ? composeId(message.participant) : composeParticipantId(message.participantId, message.participantType || UserType.USER, message.deviceIdx);\n }\n\n export function extractOkId(id: OkUserId | CompositeUserId | ParticipantId): OkUserId {\n if (typeof id === 'string') {\n return decomposeId(decomposeParticipantId(id).compositeUserId).id;\n }\n\n return id;\n }\n\n export function decomposeId(compositeId: CompositeUserId | OkUserId): { id: OkUserId; type: UserType } {\n const strId = String(compositeId);\n const match = strId.match(COMPOSITE_ID_PATTERN);\n\n if (match) {\n return { id: Number(match[2]), type: match[1] === 'g' ? UserType.GROUP : UserType.USER };\n } else {\n Debug.warn(`Unsupported compositeId [${compositeId}]`);\n return { id: Number(strId), type: UserType.USER };\n }\n }\n\n export function decomposeParticipantId(participantId: ParticipantId): { compositeUserId: CompositeUserId; deviceIdx: number } {\n const tokens = participantId.split(PARAMETERS_SEPARATOR + DEVICE_IDX_PARAMETER);\n return {\n compositeUserId: tokens[0],\n deviceIdx: tokens.length > 1 ? parseInt(tokens[1], 10) : 0,\n };\n }\n\n /*\n * Generates a RFC4122, version 4 ID uuid.\n * Example: \"92329D39-6F5C-4520-ABFC-AAB64544E172\"\n *\n * © Robert Kieffer, 2008\n * Dual licensed under the MIT and GPL licenses.\n * Latest version: http://www.broofa.com/Tools/Math.uuid.js\n * Information: http://www.broofa.com/blog/?p=151\n * Contact: robert@broofa.com\n */\n export function uuid(): string {\n const nativeUUID = window.crypto?.randomUUID?.();\n if (nativeUUID) {\n return nativeUUID;\n }\n\n const chars: string[] = '0123456789abcdefghijklmnopqrstuvwxyz'.split('');\n const result: string[] = new Array(36);\n let rnd = 0,\n r: number,\n i: number;\n\n for (i = 0; i < 36; i++) {\n if (i === 8 || i === 13 || i === 18 || i === 23) {\n result[i] = '-';\n } else if (i === 14) {\n result[i] = '4';\n } else {\n if (rnd <= 0x02) {\n rnd = (0x2000000 + Math.random() * 0x1000000) | 0;\n }\n r = rnd & 0xf;\n rnd = rnd >> 4;\n result[i] = chars[i === 19 ? (r & 0x3) | 0x8 : r];\n }\n }\n return result.join('');\n }\n\n export function debounce<F extends (...args: Parameters<F>) => ReturnType<F>>(func: F, ms: number) {\n let timeout: number;\n\n function wrapper(this: any, ..._args: Parameters<F>) {\n const _this = this;\n\n if (timeout) {\n window.clearTimeout(timeout);\n }\n\n timeout = window.setTimeout(() => {\n func.apply(_this, _args);\n }, ms);\n }\n\n return wrapper;\n }\n\n export function sdpFingerprint(sdp: string): bigint | null {\n if (!window.BigInt) {\n return null;\n }\n\n let fingerprintStr = '';\n const split: string[] = sdp.split('\\n');\n\n for (const s of split) {\n if (s.startsWith('a=fingerprint')) {\n const splitFp: string[] = s.split(' ');\n if (splitFp.length === 2) {\n fingerprintStr = splitFp[1];\n break;\n }\n }\n }\n\n if (!fingerprintStr) {\n return BigInt(-1);\n }\n\n const hexchunks: string[] = fingerprintStr.split(':');\n let result = BigInt(0);\n\n for (let i = Math.min(7, hexchunks.length - 1); i >= 0; i--) {\n const current = BigInt(parseInt(hexchunks[i], 16));\n result <<= BigInt(8);\n result |= current;\n }\n\n return BigInt.asIntN(64, result);\n }\n\n export async function delay(time: number) {\n return new Promise((resolve) => window.setTimeout(resolve, time));\n }\n\n export function applySettings(pc: RTCPeerConnection, videoSettings: VideoSettings, prevSettings: any) {\n const retSettings: any = [];\n pc.getSenders().forEach((s) => applyVideoTrackSettings(videoSettings, s, s.track, prevSettings, retSettings));\n return retSettings;\n }\n\n export function applyVideoTrackSettings(videoSettings: VideoSettings, s: RTCRtpSender, track: MediaStreamTrack | null, prevSettings: any, retSettings: any) {\n if (!RTCRtpSender.prototype.getParameters || !RTCRtpSender.prototype.setParameters) {\n return;\n }\n\n if (!videoSettings || !track || track.kind !== MediaTrackKind.video) {\n return;\n }\n\n const trackSettings = track.getSettings();\n if (!trackSettings) {\n return;\n }\n\n let targetBitrate: number | null = videoSettings.maxBitrateK ? videoSettings.maxBitrateK * 1024 : null;\n\n const trackWidth = trackSettings.width;\n const trackHeight = trackSettings.height;\n const targetScaleResolutionDownBy: number | null =\n trackWidth && trackHeight && videoSettings.maxDimension ? Math.max(1, Math.max(trackWidth, trackHeight) / videoSettings.maxDimension) : null;\n\n const targetMaxFramerate: number | null = videoSettings.maxFramerate || null;\n\n if (trackWidth && trackHeight && videoSettings.maxDimension) {\n if (videoSettings.maxDimension > Math.max(trackWidth, trackHeight)) {\n // server maxDim is larger than our local, so server specified bitrate is not applicable\n // recalc targetBitrate using ideal bits_per_macroblock\n const macroBlocks = Math.round((trackWidth * trackHeight) / 256);\n const bitrate = (Math.round((macroBlocks * IDEAL_BITS_PER_MACROBLOCK) / 10_000) + 1) * 10_000;\n // new bitrate shall not exceed server specified maxBitrate\n targetBitrate = targetBitrate === null ? bitrate : Math.min(bitrate, targetBitrate);\n }\n }\n\n const targetDegradationPreference: RTCDegradationPreference = videoSettings.degradationPreference || 'balanced';\n\n const prevTrackSettings = prevSettings[track.id];\n if (\n prevTrackSettings &&\n prevTrackSettings.bitrate === targetBitrate &&\n prevTrackSettings.scaleResolutionDownBy === targetScaleResolutionDownBy &&\n prevTrackSettings.maxFramerate === targetMaxFramerate &&\n prevTrackSettings.degradationPreference === targetDegradationPreference\n ) {\n retSettings[track.id] = prevTrackSettings;\n // getParameters is an expensive operation, we try to avoid it if settings have not changed\n return;\n }\n\n retSettings[track.id] = {\n bitrate: targetBitrate,\n scaleResolutionDownBy: targetScaleResolutionDownBy,\n maxFramerate: targetMaxFramerate,\n degradationPreference: targetDegradationPreference,\n };\n\n const senderParams = s.getParameters() as RTCRtpSendParameters;\n if (!senderParams.encodings) {\n // @ts-ignore\n senderParams.encodings = [{}]; // FF workaround\n }\n if (senderParams.encodings.length > 1 && trackWidth && trackHeight && videoSettings.maxDimension) {\n // simulcast\n const targetDimension = Math.round(videoSettings.maxDimension * 1.35);\n const trackDimension = Math.max(trackWidth, trackHeight);\n // from highest to lowest layer, but dont touch the lowest layer\n const simulcastInfo: SimulcastInfo = calculateSimulcastInfo(trackWidth, trackHeight, videoSettings?.bitrates?.generic);\n const layers = simulcastInfo.streams.length;\n Debug.log(\n `applyVideoTrackSettings: maxDim=${videoSettings.maxDimension} targetDim=${targetDimension} track=${trackWidth}x${trackHeight} sim=${JSON.stringify(simulcastInfo)}`,\n );\n senderParams.encodings.forEach((encoding, i) => {\n encoding.scaleResolutionDownBy = findScaleResolutionDownBy(encoding.rid);\n const dimension = Math.round(trackDimension / encoding.scaleResolutionDownBy);\n if (i < layers - 1) {\n encoding.active = dimension < targetDimension;\n } else if (i >= layers) {\n encoding.active = false; // fake layers\n } else {\n encoding.active = true; // the smallest layer\n }\n if (i < layers) {\n encoding.maxBitrate = simulcastInfo.streams[i].bitrate;\n } else {\n encoding.maxBitrate = 0;\n }\n encoding.scalabilityMode = SIMULCAST_SCALABILITY_MODE;\n });\n } else {\n senderParams.encodings.forEach((e) => {\n if (videoSettings?.scalabilityMode) {\n e.scalabilityMode = videoSettings.scalabilityMode;\n }\n if (targetBitrate) {\n e.maxBitrate = targetBitrate;\n } else {\n delete e.maxBitrate;\n }\n if (targetScaleResolutionDownBy) {\n e.scaleResolutionDownBy = targetScaleResolutionDownBy;\n } else {\n delete e.scaleResolutionDownBy;\n }\n if (targetMaxFramerate) {\n e.maxFramerate = targetMaxFramerate;\n } else {\n delete e.maxFramerate;\n }\n });\n }\n senderParams.degradationPreference = targetDegradationPreference;\n\n if (senderParams.encodings.length > 0) {\n s.setParameters?.(senderParams).catch((e) => {\n Debug.error('Failed to set sender parameters', senderParams, e);\n });\n const actualParams = s.getParameters() as RTCRtpSendParameters;\n Debug.log(`applyVideoTrackSettings: actual encodings= ${JSON.stringify(actualParams.encodings)}`);\n }\n }\n\n /**\n * Проверяет, есть ли в первом массиве хотя бы один элемент из второго массива\n * @param arr Где ищем\n * @param search Что ищем\n */\n export function includesOneOf(arr: string[], search: string | string[]): boolean {\n if (!Array.isArray(search)) {\n search = [search];\n }\n\n for (const item of search) {\n if (arr.includes(item)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Маппер клиентского состояния участника звонка\n * @param participant список участников звонка\n * @hidden\n */\n export function mapParticipantState(participant: Pick<SignalingMessage.Participant, 'participantState'>): ParticipantStateMapped {\n return Object.entries(participant.participantState?.state || {}).reduce<ParticipantStateMapped>((acc, [key, state]) => {\n if (participant.participantState) {\n acc[key] = {\n ts: participant.participantState.stateUpdateTs[key],\n state,\n };\n }\n return acc;\n }, {});\n }\n\n /**\n * мапает данные `participants` перед передачей клиенту\n * @hidden\n */\n export function mapSharedParticipants(participants: Participant[]): ExternalParticipant[] {\n const result = participants.map((participant) => {\n const externalParticipant: ExternalParticipant = {\n uid: participant.externalId,\n mediaSettings: participant.mediaSettings,\n status: participant.status,\n muteStates: participant.muteStates,\n unmuteOptions: participant.unmuteOptions,\n participantState: participant.participantState,\n markers: participant.markers,\n movieShareInfos: participant.movieShareInfos,\n roles: participant.roles,\n };\n return externalParticipant;\n });\n\n if (!Params.filterObservers) {\n return result;\n }\n return result.filter((participant) => !participant.uid.observer);\n }\n\n /**\n * сравнивает `participantState`\n */\n export function isEqualParticipantState(prev: ParticipantStateMapped, next: ParticipantStateMapped): boolean {\n const prevKeys = Object.keys(prev);\n const nextKeys = Object.keys(next);\n\n if (prevKeys.length !== nextKeys.length) {\n return false;\n }\n\n for (const key of prevKeys) {\n if (!Object.hasOwn(nextKeys, key)) {\n return false;\n }\n // сравнили значения\n if (prev[key].state !== next[key].state) {\n return false;\n }\n // сравнили timestamp\n if (prev[key].ts !== next[key].ts) {\n return false;\n }\n }\n\n return true;\n }\n\n export function isObjectsEquals<T extends string, K>(obj1: { [key in T]?: K }, obj2: { [key in T]?: K }, deep = false): boolean {\n const keys1 = Object.keys(obj1) as T[];\n const keys2 = Object.keys(obj2) as T[];\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (const key of keys1) {\n if (!Object.hasOwn(obj2, key)) {\n return false;\n }\n\n const left = obj1[key];\n const right = obj2[key];\n\n if (deep && isObject(left) && isObject(right)) {\n return isObjectsEquals(left, right, deep);\n }\n\n if (left !== right) {\n return false;\n }\n }\n\n return true;\n }\n\n export function isArraysEquals<T>(arr1: T[], arr2: T[]) {\n if (arr1.length !== arr2.length) {\n return false;\n }\n\n for (const item of arr1) {\n if (arr2.indexOf(item) < 0) {\n return false;\n }\n }\n\n return true;\n }\n\n export function isEmptyObject(obj: object) {\n return !Object.keys(obj).length;\n }\n\n /**\n * @see https://wiki.odkl.ru/pages/viewpage.action?spaceKey=VIDEO&title=Signaling+API#SignalingAPI-Постраничныйвыводпартисипантов\n * https://stash.odkl.ru/projects/ODKL/repos/odnoklassniki-webrtc/browse/src/main/java/one/webrtc/domain/conversation/ParticipantIndex.java#67-78\n */\n export function participantMarkerCompare(marker1: ExternalParticipantListMarker | undefined, marker2: ExternalParticipantListMarker | undefined) {\n if (!marker1 && !marker2) {\n return 0;\n }\n\n if (!marker1 || !marker2) {\n return marker1 ? -1 : 1;\n }\n\n return compareNumber(marker2.rank, marker1.rank) || compareNumber(marker1.ts, marker2.ts) || compareId(marker1, marker2);\n\n function compareId(markerA: ExternalParticipantListMarker, markerB: ExternalParticipantListMarker) {\n const typeToNumber = {\n [UserType.USER]: 0,\n [UserType.GROUP]: 1,\n };\n const { compositeUserId: compositeUserId1, deviceIdx: deviceIdx1 } = decomposeParticipantId(markerA.id);\n const { compositeUserId: compositeUserId2, deviceIdx: deviceIdx2 } = decomposeParticipantId(markerB.id);\n const { id: id1, type: type1 } = decomposeId(compositeUserId1);\n const { id: id2, type: type2 } = decomposeId(compositeUserId2);\n return compareNumber(typeToNumber[type1], typeToNumber[type2]) || compareNumber(id1, id2) || compareNumber(deviceIdx1, deviceIdx2);\n }\n\n function compareNumber(x: number, y: number): number {\n return x < y ? -1 : x === y ? 0 : 1;\n }\n }\n\n /** убирает все ключи со значением `V` на 1 уровне */\n export function objectFilterOutValues<T extends Record<string, V>, V = unknown>(obj: T, value?: unknown | unknown[]) {\n const filtered = Object.entries(obj).filter(([, val]) => {\n if (Array.isArray(value)) {\n return !value.includes(val);\n }\n return val !== value;\n });\n return fromEntries(filtered) as Partial<T>;\n }\n\n export function objectReduce<R, T extends object>(obj: T, callback: (acc: R, value: T[keyof T], key: keyof T) => R, initialValue: R): R {\n let currentValue = initialValue;\n for (const key in obj) {\n if (!Object.hasOwn(obj, key)) {\n continue;\n }\n currentValue = callback(currentValue, obj[key], key);\n }\n return currentValue;\n }\n\n export const setImmediate = (() => {\n let nextTimerId = 1;\n const timerIdToCallback: Record<number, VoidFunction> = {};\n let messageChannel: MessageChannel | null = null;\n if (typeof MessageChannel !== 'undefined') {\n messageChannel = new MessageChannel();\n messageChannel.port1.onmessage = (event) => {\n const timerId: number = event.data;\n if (timerIdToCallback[timerId]) {\n timerIdToCallback[timerId]();\n delete timerIdToCallback[timerId];\n }\n };\n }\n\n return function (fn: VoidFunction): VoidFunction {\n if (messageChannel && document.visibilityState === 'hidden') {\n // Use MessageChannel only when tab is hidden\n // to avoid setTimeout throttling and allow a browser to manage\n // CPU more efficently when tab is visible through setTimeout\n const _timerId = nextTimerId;\n nextTimerId = nextTimerId >= Number.MAX_SAFE_INTEGER ? 1 : nextTimerId + 1;\n timerIdToCallback[_timerId] = fn;\n messageChannel.port2.postMessage(_timerId);\n return () => {\n if (timerIdToCallback[_timerId]) {\n delete timerIdToCallback[_timerId];\n }\n };\n }\n const timerId = setTimeout(fn, 0);\n return () => clearTimeout(timerId);\n };\n })();\n\n export function isObject(obj: unknown): obj is object {\n return obj !== null && typeof obj === 'object' && !Array.isArray(obj);\n }\n\n export function patchSimulcastAnswerSdp(sdp: string, trans: RTCRtpTransceiver, width: number, height: number): string {\n function findVideoSection(lines: string[], mid: string) {\n let start = 0;\n let end = lines.length;\n let found = false;\n for (let i = 0; i < lines.length; i++) {\n if (!found && lines[i].startsWith('m=video')) {\n start = i;\n }\n if (lines[i].startsWith('a=mid:' + mid)) {\n found = true;\n }\n if (found) {\n if (lines[i].startsWith('m=')) {\n end = i;\n break;\n }\n }\n }\n return { start, end };\n }\n function patchSimulcastRidLine(lines: string[], start: number, end: number, rid: string | undefined, bw: number, w: string, h: string) {\n const targetRid = 'a=rid:' + rid + ' send';\n for (let i = start; i < end; i++) {\n const line = lines[i];\n if (line === targetRid) {\n const line2 = targetRid + ' max-width=' + w + ';max-height=' + h + ';max-br=' + bw;\n lines[i] = line2;\n }\n }\n }\n const sender = trans?.sender;\n if (sender && sender.track && trans.mid) {\n const lines = sdp.split(lineSeparator);\n const { start, end } = findVideoSection(lines, trans.mid);\n const senderParams = sender.getParameters() as RTCRtpSendParameters;\n if (senderParams.encodings) {\n senderParams.encodings.forEach((encoding) => {\n const rid = encoding.rid;\n const bw = encoding.maxBitrate as number;\n const scale = encoding.scaleResolutionDownBy;\n if (width && height && scale) {\n const w = '' + Math.round(width / scale);\n const h = '' + Math.round(height / scale);\n patchSimulcastRidLine(lines, start, end, rid, bw, w, h);\n }\n });\n return lines.join(separator);\n }\n }\n return sdp;\n }\n}\n\nexport default Utils;\n", "const enum Stat {\n CALL_FINISH = 'call_finish', // событие отправляемое в конце звонка\n CODEC_USAGE = 'codec_usage', // событие когда меняется кодек\n SIGNALING_CONNECTED = 'signaling_connected', // measure\n SCREENSHARE_FIRST_FRAME = 'screen_share_first_frame', // measure\n /** Объединение callFirstDataReceivedP2P и callFirstAudioMixDataReceived */\n FIRST_MEDIA_RECEIVED = 'first_media_received',\n CALL_DECLINED_OR_HANGED_LOCALLY = 'CallDeclinedOrHangedLocally',\n USER_FEEDBACK_RECEIVED = 'UserFeedbackReceived',\n CALL_START = 'call_start',\n\n SIGNALING_PING_SUMMARY = 'signaling_ping_summary',\n SIGNALING_COMMAND_SUMMARY = 'signaling_command_summary',\n\n WEBSOCKET_CONNECTED = 'websocket_connected',\n WEBSOCKET_RECONNECTED = 'websocket_reconnected',\n WEBSOCKET_FAILED_PINGS = 'websocket_failed_pings',\n WEBSOCKET_FAILED_EXCEPTION = 'websocket_failed_exception',\n WEBSOCKET_TIMEOUT = 'websocket_timeout',\n WEBSOCKET_RESTART = 'websocket_restart',\n\n WEBTRANSPORT_CONNECTED = 'webtransport_connected',\n WEBTRANSPORT_RECONNECTED = 'webtransport_reconnected',\n WEBTRANSPORT_FAILED_PINGS = 'webtransport_failed_pings',\n WEBTRANSPORT_FAILED_EXCEPTION = 'webtransport_failed_exception',\n WEBTRANSPORT_TIMEOUT = 'webtransport_timeout',\n WEBTRANSPORT_RESTART = 'webtransport_restart',\n}\n\nexport default Stat;\n", "import Utils from '../../static/Utils';\nimport WebRTCUtils from '../../static/WebRTCUtils';\nimport Stat from '../../enums/Stat';\nimport { ParticipantId } from '../../types/Participant';\nimport { StatItem, StatRtp, StatTransport } from '../../types/Statistics';\nimport { MediaTrackKind } from '../MediaSource';\n\nexport const NO_STAT_REQUEST_DELAY = 1000;\n\nfunction getValue(item: { [key: string]: any }, key: string, defaultValue: any = 0): any {\n return key in item && item[key] ? item[key] : defaultValue;\n}\n\nfunction orPredicate(...predicates: any) {\n return (object: any) => {\n for (const predicate of predicates) {\n if (predicate(object)) {\n return true;\n }\n }\n\n return false;\n };\n}\n\nfunction keyPredicate(key: string, value: string | number | boolean | undefined) {\n return (object: any) => {\n return object[key] === value;\n };\n}\n\nfunction keyReverseComparator(key: string) {\n return (left: Record<string, any>, right: Record<string, any>) => {\n return right[key] - left[key];\n };\n}\n\nfunction index<I extends Record<string, any>>(property: keyof I, items: I[]): Record<keyof I, I> {\n return items.reduce(\n (values, item: I) => {\n values[item[property]] = item;\n return values;\n },\n {} as Record<keyof I, I>,\n );\n}\n\nfunction distinctById(items: RTCStats[]): RTCStats[] {\n const tmp: Record<string, boolean> = {};\n const res = [];\n for (const item of items) {\n if (!tmp[item.id]) {\n tmp[item.id] = true;\n res.push(item);\n }\n }\n return res;\n}\n\nfunction withoutUndefined(obj: any) {\n return Object.keys(obj)\n .filter((key) => {\n return obj[key] !== undefined;\n })\n .map((key) => {\n return [key, obj[key]];\n })\n .reduce((values: any, pair: any) => {\n values[pair[0]] = Utils.isObject(pair[1]) ? withoutUndefined(pair[1]) : pair[1];\n\n return values;\n }, {});\n}\n\nfunction rtcStatsToArray(stats: RTCStatsReport[]): RTCStats[] {\n const result: RTCStats[] = [];\n for (const stat of stats) {\n stat.forEach((item) => result.push(item));\n }\n return result;\n}\n\n/**\n * Extracts all available RTCStats from the given peer connection\n * @hidden\n */\nasync function extractStats(pc: RTCPeerConnection): Promise<RTCStats[]> {\n const promisedStats: Promise<RTCStatsReport>[] = [];\n\n // @ts-ignore TS2774\n if (RTCRtpReceiver.prototype.getStats) {\n promisedStats.push(...pc.getReceivers().map((receiver) => receiver.getStats()));\n promisedStats.push(...pc.getSenders().map((sender) => sender.getStats()));\n } else {\n promisedStats.push(pc.getStats());\n }\n\n return Promise.all(promisedStats).then(rtcStatsToArray).then(distinctById);\n}\n\n/**\n * Extracts transport statistics from the gives stats\n * @hidden\n */\nfunction extractTransport(stats: RTCStats[]): StatTransport {\n const candidatePair = stats\n .filter(keyPredicate('type', 'candidate-pair'))\n .sort(keyReverseComparator('priority'))\n .find(orPredicate(keyPredicate('nominated', true), keyPredicate('selected', true))) as RTCIceCandidatePairStats;\n\n if (!candidatePair) {\n return {\n timestamp: 0,\n availableOutgoingBitrate: 0,\n totalRoundTripTime: 0,\n currentRoundTripTime: 0,\n bytesSent: 0,\n bytesReceived: 0,\n };\n }\n\n const transport: StatTransport = {\n timestamp: candidatePair.timestamp,\n availableOutgoingBitrate: candidatePair.availableOutgoingBitrate || 0,\n totalRoundTripTime: candidatePair.totalRoundTripTime || 0, // В ФФ нет totalRoundTripTime и currentRoundTripTime\n currentRoundTripTime: candidatePair.currentRoundTripTime || 0,\n bytesSent: candidatePair.bytesSent || 0,\n bytesReceived: candidatePair.bytesReceived || 0,\n };\n\n const remoteCandidate = stats.find(keyPredicate('id', candidatePair.remoteCandidateId)) as RTCIceCandidateStats;\n if (remoteCandidate) {\n Object.assign(transport, {\n remote: {\n type: remoteCandidate.candidateType,\n address: remoteCandidate.ip || remoteCandidate.address,\n port: remoteCandidate.port,\n protocol: remoteCandidate.protocol,\n },\n });\n }\n\n const localCandidate = stats.find(keyPredicate('id', candidatePair.localCandidateId)) as RTCIceCandidateStats;\n if (localCandidate) {\n Object.assign(transport, {\n local: {\n type: localCandidate.candidateType,\n address: localCandidate.ip || localCandidate.address,\n port: localCandidate.port,\n protocol: localCandidate.protocol,\n relayProtocol: localCandidate.relayProtocol,\n networkType: localCandidate.networkType,\n },\n });\n }\n\n return withoutUndefined(transport);\n}\n\n/**\n * Extracts media statistics from the given stats\n * @hidden\n */\nfunction extractRtps(stats: RTCStats[], ssrcMap: Record<string, string>, needToExtractRemote = false): StatRtp[] {\n const statsIndexed: Record<string, RTCStats> = index('id', stats);\n\n type IRTPStatsArray = (RTCInboundRtpStreamStats | RTCOutboundRtpStreamStats)[];\n\n let rtpStats = needToExtractRemote\n ? (stats.filter(orPredicate(keyPredicate('type', 'remote-inbound-rtp'))) as IRTPStatsArray)\n : (stats.filter(orPredicate(keyPredicate('type', 'inbound-rtp'), keyPredicate('type', 'outbound-rtp'))) as IRTPStatsArray);\n\n if (WebRTCUtils.browserName() === 'Firefox') {\n // Firefix reports stats for RTP and RTCP in two different records with the same SSRC id,\n // here we merged them into one\n\n rtpStats = Object.values(\n rtpStats.reduce((statMap: any, stat: any) => {\n if (!statMap[stat.ssrc]) {\n statMap[stat.ssrc] = stat;\n } else {\n const merged = Object.assign({}, statMap[stat.ssrc], stat);\n const remote = statMap[stat.ssrc].isRemote ? stat : statMap[stat.ssrc];\n\n merged.id = remote.id;\n merged.type = remote.type;\n\n delete merged.isRemote;\n delete merged.remoteId;\n\n statMap[merged.ssrc] = merged;\n }\n\n return statMap;\n }, {}),\n );\n }\n\n return rtpStats\n .map((stat) => {\n const ssrc = Number(stat.ssrc);\n const kind = stat.mediaType || stat.kind;\n const trackId = stat.remoteId || stat.trackId;\n const type = stat.type;\n const codecId = stat.codecId;\n\n if (!type || !ssrc || !kind) {\n return null;\n }\n\n const rtp: StatRtp = {\n ssrc,\n type,\n kind,\n bytesReceived: getValue(stat, 'bytesReceived'),\n bytesSent: getValue(stat, 'bytesSent'),\n headerBytesReceived: getValue(stat, 'headerBytesReceived'),\n headerBytesSent: getValue(stat, 'headerBytesSent'),\n jitter: getValue(stat, 'jitter'),\n packetsLost: getValue(stat, 'packetsLost'),\n packetsReceived: getValue(stat, 'packetsReceived'),\n packetsSent: getValue(stat, 'packetsSent'),\n fractionLost: getValue(stat, 'fractionLost'),\n pliCount: getValue(stat, 'pliCount'),\n firCount: getValue(stat, 'firCount'),\n nackCount: getValue(stat, 'nackCount'),\n userId: ssrcMap[ssrc],\n freezeCount: getValue(stat, 'freezeCount', 0),\n totalFreezesDuration: getValue(stat, 'totalFreezesDuration', 0),\n };\n\n const mid = 'mid' in stat && typeof stat.mid === 'string' ? stat.mid : undefined;\n const rid = 'rid' in stat && typeof stat.rid === 'string' ? stat.rid : undefined;\n if (mid) {\n rtp.mid = mid;\n }\n if (rid) {\n rtp.rid = rid;\n }\n\n if (kind === 'video') {\n const framesDecoded = getValue(stat, 'framesDecoded');\n const totalInterFrameDelay = getValue(stat, 'totalInterFrameDelay');\n const totalSquaredInterFrameDelay = getValue(stat, 'totalSquaredInterFrameDelay');\n const encoder = getValue(stat, 'encoderImplementation');\n const decoder = getValue(stat, 'decoderImplementation');\n if (encoder) {\n rtp.encoderImplementation = encoder;\n }\n if (decoder) {\n rtp.decoderImplementation = decoder;\n }\n rtp.interframeDelayVariance = (totalSquaredInterFrameDelay - (totalInterFrameDelay * totalInterFrameDelay) / framesDecoded) / framesDecoded;\n }\n\n if (kind === 'video' && rtp.type === 'outbound-rtp') {\n rtp.totalEncodeTime = getValue(stat, 'totalEncodeTime') ?? 0;\n }\n\n if (kind === 'audio') {\n rtp.totalSamplesReceived = getValue(stat, 'totalSamplesReceived');\n rtp.concealedSamples = getValue(stat, 'concealedSamples');\n rtp.insertedSamplesForDeceleration = getValue(stat, 'insertedSamplesForDeceleration');\n rtp.removedSamplesForAcceleration = getValue(stat, 'removedSamplesForAcceleration');\n rtp.silentConcealedSamples = getValue(stat, 'silentConcealedSamples');\n rtp.concealmentEvents = getValue(stat, 'concealmentEvents');\n rtp.totalAudioEnergy = getValue(stat, 'totalAudioEnergy');\n }\n\n if (codecId && statsIndexed[codecId]) {\n const codec = statsIndexed[codecId] as RTCCodecStats;\n rtp.clockRate = codec.clockRate;\n rtp.mimeType = codec.mimeType;\n if (kind === 'audio' && codec.sdpFmtpLine) {\n rtp.sdpFmtpLine = codec.sdpFmtpLine;\n }\n }\n\n if (trackId && statsIndexed[trackId]) {\n const track = statsIndexed[trackId] as RTCMediaStreamTrackStats;\n rtp.frameHeight = track.frameHeight;\n rtp.frameWidth = track.frameWidth;\n rtp.framesDecoded = track.framesDecoded;\n rtp.framesReceived = track.framesReceived;\n rtp.framesDropped = track.framesDropped;\n }\n\n return withoutUndefined(rtp);\n })\n .filter((value: any) => {\n return !!value;\n });\n}\n\n/**\n * Computes delta (the difference) between two stat reports.\n * @hidden\n */\nfunction delta(current: StatItem, previous: StatItem, needToExtractRemote = false): StatItem {\n if (!previous) {\n return current;\n }\n\n if (!previous.rtps || !current.rtps) {\n return current;\n }\n\n let currentRemoteRtps: Record<string, StatRtp> | undefined;\n let previousRemoteRtps: Record<string, StatRtp> | undefined;\n if (needToExtractRemote) {\n currentRemoteRtps = index('ssrc', current?.remoteRtps || []);\n previousRemoteRtps = index('ssrc', previous?.remoteRtps || []);\n }\n\n const currentRtps: Record<string, StatRtp> = index('ssrc', current.rtps);\n const previousRtps: Record<string, StatRtp> = index('ssrc', previous.rtps);\n const time = (current.timestamp - previous.timestamp) / 1000;\n\n if (!currentRtps || !previousRtps) {\n return current;\n }\n\n Object.keys(currentRtps).forEach((ssrc) => {\n const currentRtp = currentRtps[ssrc] as StatRtp;\n const previousRtp = previousRtps[ssrc] as StatRtp;\n\n if (!currentRtp || !previousRtp) {\n return;\n }\n\n if (currentRtp.bytesReceived && currentRtp.bytesReceived > previousRtp.bytesReceived) {\n currentRtp.bandwidth = Math.round((currentRtp.bytesReceived - previousRtp.bytesReceived) / time);\n currentRtp.bandwidth += Math.round((currentRtp.headerBytesReceived - previousRtp.headerBytesReceived) / time);\n }\n\n if (currentRtp.bytesSent && currentRtp.bytesSent > previousRtp.bytesSent) {\n currentRtp.bandwidth = Math.round((currentRtp.bytesSent - previousRtp.bytesSent) / time);\n currentRtp.bandwidth += Math.round((currentRtp.headerBytesSent - previousRtp.headerBytesSent) / time);\n }\n\n if (currentRtp.packetsReceived) {\n if (currentRtp.packetsReceived > previousRtp.packetsReceived || currentRtp.packetsLost > previousRtp.packetsLost) {\n const lost = currentRtp.packetsLost - previousRtp.packetsLost;\n const received = currentRtp.packetsReceived - previousRtp.packetsReceived;\n currentRtp.packetLoss = parseFloat(((100 * lost) / (lost + received)).toFixed(2));\n } else {\n currentRtp.packetLoss = 0;\n }\n }\n\n if (currentRtp.freezeCount > previousRtp.freezeCount) {\n currentRtp.freezeCountDelta = currentRtp.freezeCount - previousRtp.freezeCount;\n }\n\n if (currentRtp.totalFreezesDuration > previousRtp.totalFreezesDuration) {\n const diff = currentRtp.totalFreezesDuration - previousRtp.totalFreezesDuration;\n currentRtp.totalFreezesDurationDelta = diff;\n }\n\n if (currentRtp.framesDropped && previousRtp.framesDropped && currentRtp.framesDropped > previousRtp.framesDropped) {\n currentRtp.framesDroppedDelta = parseFloat(((currentRtp.framesDropped - previousRtp.framesDropped) / time).toFixed(0));\n }\n\n if (needToExtractRemote && currentRtp.type === 'outbound-rtp' && currentRtp.kind === MediaTrackKind.video) {\n const remoteRtp = currentRemoteRtps?.[ssrc];\n const previousRemoteRtp = previousRemoteRtps?.[ssrc];\n const getValueOrZero = (value?: number) => value ?? 0;\n\n const lost = Math.max(0, getValueOrZero(remoteRtp?.packetsLost) - getValueOrZero(previousRemoteRtp?.packetsLost));\n const sent = Math.max(1, currentRtp.packetsSent - previousRtp.packetsSent);\n current.transport.averageNetStat = {\n currentRoundTripTime: ((current.transport.currentRoundTripTime + previous.transport.currentRoundTripTime) / 2) * 1000,\n lostPercent: Math.round((lost / sent) * 100),\n };\n }\n });\n\n return current;\n}\n\nasync function collectStats(pc: RTCPeerConnection, previous: StatItem | null, ssrcMap: Record<string, string> = {}, needToExtractRemote = false): Promise<StatItem> {\n const stats = await extractStats(pc);\n const current: StatItem = {\n timestamp: Date.now(),\n transport: extractTransport(stats),\n rtps: extractRtps(stats, ssrcMap),\n };\n if (needToExtractRemote) {\n current.remoteRtps = extractRtps(stats, ssrcMap, true);\n }\n\n if (!previous) {\n // Если предыдущего значения нет, получим его\n await Utils.delay(NO_STAT_REQUEST_DELAY);\n return collectStats(pc, current, ssrcMap, needToExtractRemote);\n }\n\n return delta(current, previous, needToExtractRemote);\n}\n\nfunction setMark(name: string) {\n performance.clearMarks(name);\n performance.mark(name);\n}\n\nfunction clearMark(name: string) {\n performance.clearMarks(name);\n}\n\nfunction measureMark(name: string): null | number {\n const mark = performance.getEntriesByName(name)[0];\n\n if (typeof mark === 'undefined') {\n return null;\n }\n\n const diff = Math.round(performance.now() - mark.startTime);\n performance.clearMarks(name);\n\n return diff;\n}\n\nfunction getMarkNameScreenshareFirstFrame(uid: ParticipantId) {\n return `${Stat.SCREENSHARE_FIRST_FRAME}_${uidToString(uid)}`;\n}\n\nfunction uidToString(uid: ParticipantId) {\n return typeof uid === 'string' ? uid : JSON.stringify(uid);\n}\n\n// для тестов\nexport default {\n distinctById,\n rtcStatsToArray,\n extractTransport,\n extractRtps,\n delta,\n collectStats,\n setMark,\n clearMark,\n measureMark,\n getMarkNameScreenshareFirstFrame,\n};\n", "import { ICallStatLog } from '../../types/PerfStatReporter';\nimport { IEventualStatLog } from '../../types/IEventualStatLog';\nimport Logger from '../Logger';\nimport Statistics from '../transport/Statistics';\n\ntype ICallStatPickedData = Pick<\n ICallStatLog,\n 'call_topology' | 'remote_address' | 'transport' | 'remote_connection_type' | 'local_connection_type' | 'local_address' | 'network_type' | 'rtt'\n>;\n\nexport class StatAggregator {\n private static _instance: StatAggregator | null = null;\n\n private readonly _eventualLogs = new Set<IEventualStatLog>();\n\n static create() {\n StatAggregator._instance = new StatAggregator();\n }\n\n static logCallStat(params: ICallStatLog) {\n if (StatAggregator._instance?._eventualLogs.size) {\n for (const eventualStat of StatAggregator._instance._eventualLogs) {\n Object.assign(eventualStat, {\n call_topology: params.call_topology,\n local_address: params.local_address,\n local_connection_type: params.local_connection_type,\n network_type: params.network_type,\n remote_address: params.remote_address,\n remote_connection_type: params.remote_connection_type,\n transport: params.transport,\n });\n Logger.logClientStats(eventualStat);\n }\n StatAggregator._instance._eventualLogs.clear();\n }\n Logger.logClientStats(params);\n }\n\n /** @link https://wiki.odkl.ru/pages/viewpage.action?pageId=100892588 */\n static logEventualStat(params: IEventualStatLog) {\n if (params.value === undefined) {\n params.value = Statistics.measureMark(params.name);\n }\n if (params.value !== null) {\n StatAggregator._instance?._eventualLogs.add(params);\n }\n }\n\n static destroy() {\n StatAggregator._instance?._destroy();\n StatAggregator._instance = null;\n }\n\n private _destroy() {\n this._eventualLogs.clear();\n }\n}\n", "import Stat from '../../enums/Stat';\nimport { ParticipantId } from '../../types/Participant';\nimport Statistics from '../transport/Statistics';\nimport { StatAggregator } from './StatAggregator';\n\nexport class StatScreenShareFirstFrame {\n protected readonly _participantId: ParticipantId;\n protected _firstFrameReceived = false;\n\n constructor(participantId: ParticipantId) {\n this._participantId = participantId;\n }\n\n measure(width: number, height: number) {\n if (this._firstFrameReceived) {\n return;\n }\n\n this._firstFrameReceived = true;\n\n const markName = Statistics.getMarkNameScreenshareFirstFrame(this._participantId);\n const duration = Statistics.measureMark(markName);\n\n if (duration === null) {\n return;\n }\n\n StatAggregator.logEventualStat({ name: Stat.SCREENSHARE_FIRST_FRAME, value: duration, width, height });\n }\n}\n", "export default abstract class BaseRenderer {\n protected readonly _onStream: (stream: MediaStream) => void;\n\n protected constructor(onStream: (stream: MediaStream) => void) {\n this._onStream = onStream;\n }\n\n async drawFrame(frame: VideoFrame): Promise<void> {\n throw new Error('Method `drawFrame` is not supported by this implementation');\n }\n\n async drawImage(image: ImageData): Promise<void> {\n throw new Error('Method `drawImage` is not supported by this implementation');\n }\n\n abstract destroy(): void;\n\n static isBrowserSupported(): boolean {\n throw new Error('Method `isBrowserSupported` is not implemented');\n }\n}\n", "import Debug from '../../static/Debug';\nimport WebRTCUtils from '../../static/WebRTCUtils';\nimport BaseRenderer from './BaseRenderer';\n\nexport default class CanvasRenderer extends BaseRenderer {\n private readonly _useImageBitmap: boolean; // Старые сафари и ФФ не умеют ImageBitmap\n\n private _canvas: HTMLCanvasElement | null = null;\n private _canvasContext: CanvasRenderingContext2D | ImageBitmapRenderingContext | null = null;\n private _stream: CanvasCaptureMediaStream | null = null;\n private _track: CanvasCaptureMediaStreamTrack | null = null;\n\n constructor(onStream: (stream: MediaStream) => void) {\n super(onStream);\n Debug.debug('CanvasRenderer started');\n\n this._useImageBitmap = 'ImageBitmap' in window;\n }\n\n private _createStream(width: number, height: number) {\n if (this._canvas) {\n return;\n }\n\n this._canvas = document.createElement('canvas');\n this._canvas.width = width;\n this._canvas.height = height;\n\n this._canvas.style.pointerEvents = 'none';\n this._canvas.style.visibility = 'hidden';\n this._canvas.style.position = 'absolute';\n this._canvas.style.width = '160px';\n this._canvas.style.height = '90px';\n this._canvas.style.bottom = '0';\n this._canvas.style.right = '0';\n this._canvas.style.zIndex = '5000';\n document.body.appendChild(this._canvas);\n\n if (this._useImageBitmap) {\n this._canvasContext = this._canvas.getContext('bitmaprenderer');\n } else {\n this._canvasContext = this._canvas.getContext('2d');\n }\n\n // @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasCaptureMediaStreamTrack/requestFrame\n this._stream = this._canvas.captureStream(0) as CanvasCaptureMediaStream;\n this._track = this._stream.getVideoTracks()[0] as CanvasCaptureMediaStreamTrack;\n this._track.contentHint = 'text';\n }\n\n private _removeStream(): void {\n if (this._stream) {\n this._stream.getTracks().forEach((track: MediaStreamTrack) => track.stop());\n this._stream = null;\n this._track = null;\n }\n this._canvasContext = null;\n\n try {\n if (this._canvas) {\n document.body.removeChild(this._canvas);\n }\n } catch (e) {}\n this._canvas = null;\n }\n\n private _requestCanvasFrame() {\n if (this._track && this._track.requestFrame) {\n this._track.requestFrame();\n } else if (this._stream && this._stream.requestFrame) {\n // FF\n this._stream.requestFrame();\n }\n }\n\n private async _drawImage(image: ImageData | ImageBitmap): Promise<void> {\n if (!this._track) {\n this._createStream(image.width, image.height);\n this._onStream(this._stream as MediaStream);\n }\n\n // Обновляем размер канваса, т.к. бывает что первый кадр приходит не того размера\n const canvas = this._canvas as HTMLCanvasElement;\n canvas.width = image.width;\n canvas.height = image.height;\n\n if (this._useImageBitmap) {\n // NB: createImageBitmap можно вынести в воркер и оно даже работает\n // но в Firefox (mac, intel) и некоторых других браузерах течёт память.\n // Течёт она где-то после передачи ImageBitmap из воркера в рантайм\n // и transferable не помогает. В рантайме bitmap.close() не очищает память\n // у битмапа, полученного из воркера. Поэтому, оставляем здесь.\n // @see https://stackoverflow.com/questions/58856403/decode-images-in-web-worker/58863246#58863246\n\n let imageBitmap: ImageBitmap;\n if (image instanceof ImageBitmap) {\n imageBitmap = image;\n } else {\n const { width: w, height: h, data } = image;\n\n // Иногда в FF падает ошибка createImageBitmap: Failed to create internal image\n // валидируем ImageData\n const expected = w * h * 4;\n if (data.byteLength !== expected) {\n Debug.warn('Bad frame buffer', { w, h, got: data.byteLength, expected });\n return;\n }\n\n imageBitmap = await createImageBitmap(image, 0, 0, image.width, image.height);\n }\n\n // Судя по всему, контекст может быть очищен в removeStream до того, как обработается\n // await createImageBitmap выше. Для этого нужна эта проверка\n if (!this._canvasContext) {\n Debug.warn('Canvas context is null');\n imageBitmap.close();\n return;\n }\n\n const context = this._canvasContext as ImageBitmapRenderingContext;\n context.transferFromImageBitmap(imageBitmap);\n imageBitmap.close();\n } else {\n const context = this._canvasContext as CanvasRenderingContext2D;\n context.clearRect(0, 0, canvas.width, canvas.height);\n context.putImageData(image as ImageData, 0, 0);\n }\n this._requestCanvasFrame();\n }\n\n // NB: Safari 16.4 умеет вебкодеки, но не умеет в MediaStreamTrackGenerator - он использует этот метод\n override async drawFrame(frame: VideoFrame): Promise<void> {\n // Используем старый синтаксис frame.createImageBitmap() пока он доступен\n const image = 'createImageBitmap' in frame ? await frame.createImageBitmap() : await createImageBitmap(frame);\n await this._drawImage(image);\n // image.close() будет вызван в _drawImage\n }\n\n override async drawImage(image: ImageData): Promise<void> {\n await this._drawImage(image);\n }\n\n override destroy() {\n this._removeStream();\n Debug.debug('CanvasRenderer destroyed');\n }\n\n static override isBrowserSupported(): boolean {\n // В FF есть CanvasCaptureMediaStream, в остальных есть CanvasCaptureMediaStreamTrack\n return (\n ('CanvasCaptureMediaStream' in window || 'CanvasCaptureMediaStreamTrack' in window) &&\n // В сафари 15 сломан Canvas.captureStream()\n !(WebRTCUtils.browserName() === 'Safari' && Number(WebRTCUtils.browserVersion()) === 15) &&\n // В старом FF плохо работает ImageBitmapContext\n !(WebRTCUtils.browserName() === 'Firefox' && Number(WebRTCUtils.browserVersion()) < 60)\n );\n }\n}\n", "import Debug from '../../static/Debug';\nimport WebCodecsDecoder from '../codec/WebCodecsDecoder';\nimport { MediaTrackKind } from '../MediaSource';\nimport BaseRenderer from './BaseRenderer';\n\n// NB: Работает только с WebCodecsDecoder\nexport default class TrackGeneratorRenderer extends BaseRenderer {\n private readonly _generator: MediaStreamTrackGenerator;\n private readonly _writer: WritableStreamDefaultWriter;\n private readonly _stream: MediaStream;\n\n constructor(onStream: (stream: MediaStream) => void) {\n super(onStream);\n Debug.debug('TrackGeneratorRenderer started');\n\n this._generator = new MediaStreamTrackGenerator({ kind: MediaTrackKind.video });\n this._writer = this._generator.writable.getWriter();\n this._stream = new MediaStream([this._generator]);\n this._onStream(this._stream);\n }\n\n override async drawFrame(frame: VideoFrame) {\n await this._writer.write(frame);\n }\n\n override destroy() {\n this._writer.releaseLock();\n this._generator.writable.close().then(() => this._generator.stop());\n Debug.debug('TrackGeneratorRenderer destroyed');\n }\n\n static override isBrowserSupported(): boolean {\n return 'VideoFrame' in window && 'MediaStreamTrackGenerator' in window && WebCodecsDecoder.isBrowserSupported();\n }\n}\n", "import Debug from '../../static/Debug';\nimport Params from '../../static/Params';\nimport { ParticipantId } from '../../types/Participant';\nimport IDecoder from '../codec/IDecoder';\nimport LibVPxDecoder from '../codec/LibVPxDecoder';\nimport WebCodecsDecoder from '../codec/WebCodecsDecoder';\nimport FpsMeter from '../FpsMeter';\nimport BaseRenderer from './BaseRenderer';\nimport { BaseStreamBuilder, FrameData, IOnStat, IOnStream } from './BaseStreamBuilder';\nimport CanvasRenderer from './CanvasRenderer';\nimport TrackGeneratorRenderer from './TrackGeneratorRenderer';\n\nexport default class StreamBuilder extends BaseStreamBuilder {\n private _renderer: BaseRenderer;\n private _decoder: IDecoder;\n private _decoderReady = false;\n private _decoderBusy = false;\n private _decoderQueue: FrameData[] = [];\n private _fpsMeter: FpsMeter;\n\n constructor(participantId: ParticipantId, onStream: IOnStream, onStat: IOnStat, onKeyFrameRequested: VoidFunction) {\n super(participantId, onStream, onStat, onKeyFrameRequested);\n Debug.debug(`StreamBuilder started for participant [${participantId}]`);\n\n this._initFpsMeter();\n this._initRenderer();\n this._initDecoder();\n }\n\n protected _processFrame(frame: FrameData) {\n if (frame.keyframe) {\n // Очищаем очередь, если пришел опорник\n // это нужно когда кадров по сети приходит больше, чем мы успеваем декодировать\n this._decoderQueue = [];\n }\n this._decoderQueue.push(frame);\n this._decodeQueue();\n }\n\n private _initFpsMeter() {\n this._fpsMeter = new FpsMeter((fps: number) => Debug.log(`[StreamBuilder][${this._participantId}] fps: ${fps}`), 20_000);\n }\n\n /**\n * Инициализация рендерера\n * @param forceCanvasRenderer используется для принудительного создания CanvasRenderer, который работает с LibVPX\n */\n private _initRenderer(forceCanvasRenderer = false) {\n if (forceCanvasRenderer || !TrackGeneratorRenderer.isBrowserSupported()) {\n this._renderer = new CanvasRenderer(this._onStream);\n } else {\n this._renderer = new TrackGeneratorRenderer(this._onStream);\n }\n }\n\n /**\n * Инициализация декодера\n * @param forceLibVPXDecoder используется для принудительного создания LibVPXDecoder\n */\n private _initDecoder(forceLibVPXDecoder = false) {\n if (forceLibVPXDecoder || !WebCodecsDecoder.isBrowserSupported()) {\n this._decoder = new LibVPxDecoder();\n } else {\n this._decoder = new WebCodecsDecoder();\n }\n\n const onFrame = async (frame: VideoFrame | ImageData) => {\n this._decoderBusy = false;\n if ('VideoFrame' in window && frame instanceof VideoFrame) {\n await this._renderer.drawFrame(frame as VideoFrame);\n } else {\n await this._renderer.drawImage(frame as ImageData);\n }\n this._fpsMeter.increment();\n this._decodeQueue();\n };\n\n const onFrameError = (_error: unknown) => {\n this._decoderBusy = false;\n this._decodeQueue();\n\n if (\n this._decoder instanceof WebCodecsDecoder &&\n typeof _error === 'string' &&\n // Ошибка может возникать на некоторых платформах (Win10) и не давать возможность раскодировать VP9 через WebCodecsDecoder\n // (_error.includes('EncodingError: Decoding error') || _error.includes('EncodingError: Error during flush'))\n _error.includes('EncodingError')\n ) {\n this._switchToLibVPXDecoder();\n }\n };\n\n this._decoder.init(onFrame, onFrameError, this._onKeyFrameRequested).then(() => {\n this._decoderReady = true;\n this._decodeQueue();\n }); // TODO: catch\n }\n\n private _switchToLibVPXDecoder() {\n Debug.warn('StreamBuilder switch to LibVPX decoder');\n\n if (this._fpsMeter) {\n this._fpsMeter.destroy();\n }\n\n if (this._decoder) {\n this._decoderReady = false;\n this._decoderBusy = false;\n this._decoder.destroy();\n }\n\n if (this._renderer) {\n this._renderer.destroy();\n }\n\n this._initFpsMeter();\n this._initRenderer(true);\n this._initDecoder(true);\n }\n\n private _decodeQueue() {\n if (!this._decoderReady || this._decoderBusy) {\n return;\n }\n\n const frame = this._decoderQueue.shift();\n if (frame) {\n this._decoderBusy = true;\n this._decoder.decodeFrame(frame.timestamp, frame.frameData, frame.isVP9, frame.keyframe);\n }\n }\n\n override destroy() {\n super.destroy();\n this._fpsMeter.destroy();\n this._decoder.destroy();\n this._renderer.destroy();\n Debug.debug(`StreamBuilder destroyed for participant ${this._participantId}`);\n }\n\n static override isBrowserSupported(): boolean {\n return CanvasRenderer.isBrowserSupported() || TrackGeneratorRenderer.isBrowserSupported();\n }\n}\n", "const PROTOCOL_VERSION = 1;\nconst TYPE_KEYFRAME = 1;\nconst TYPE_CC_FEEDBACK = 2;\nconst SSRC_DEFAULT = 0;\n\nexport const HEADER_SIZE = 11; // Заголовок пакета 11 байт\n\nconst BIT_FRAME_START = 1; // 00000001\nconst BIT_FRAME_END = 2; // 00000010\nconst BIT_FRAME_KEY = 4; // 00000100\nconst BIT_FRAME_STOP = 8; // 00001000\n\nexport interface FrameChunkHeader {\n timestamp: number;\n start: boolean;\n end: boolean;\n keyframe: boolean;\n sequence: number;\n isVP9: boolean;\n eos: boolean;\n ssrc: number;\n}\n\nexport interface FrameChunk extends FrameChunkHeader {\n data: ArrayBuffer;\n}\n\nexport function wrapHeader(timestamp: number, start: boolean, end: boolean, keyframe: boolean, sequence: number, isVP9: boolean, data: ArrayBuffer | null): ArrayBuffer {\n let flags = 0;\n if (start) {\n flags |= BIT_FRAME_START;\n }\n if (end) {\n flags |= BIT_FRAME_END;\n }\n if (keyframe) {\n flags |= BIT_FRAME_KEY;\n }\n if (!data) {\n flags |= BIT_FRAME_STOP;\n }\n\n const header = new ArrayBuffer(HEADER_SIZE);\n const view = new DataView(header);\n view.setUint8(0, PROTOCOL_VERSION); // Protocol Version, 1 byte\n view.setUint16(1, sequence); // Sequence number, 2 bytes\n view.setUint32(3, timestamp); // timestampMS, 4 bytes\n view.setUint8(7, isVP9 ? 1 : 0); // Codec, 1 byte\n view.setUint16(8, SSRC_DEFAULT); // SSRC, 2 bytes\n view.setUint8(10, flags); // Flags, 1 byte\n\n if (!data) {\n return header;\n }\n\n const result = new Uint8Array(header.byteLength + data.byteLength);\n result.set(new Uint8Array(header), 0);\n result.set(new Uint8Array(data), header.byteLength);\n\n return result.buffer;\n}\n\nexport function parseChunk(data: ArrayBuffer): FrameChunk {\n const view = new DataView(data);\n\n const prototolVersion = view.getUint8(0); // Protocol Version, 1 byte\n const sequence = view.getUint16(1); // Sequence number, 2 bytes\n const timestamp = view.getUint32(3); // timestampMS, 4 bytes\n const isVP9 = view.getUint8(7) === 1; // Codec, 1 byte\n const ssrc = view.getUint16(8); // SSRC, 2 bytes\n const flags = view.getUint8(10); // Flags, 1 byte\n\n const start = !!(flags & BIT_FRAME_START);\n const end = !!(flags & BIT_FRAME_END);\n const keyframe = !!(flags & BIT_FRAME_KEY);\n const eos = !!(flags & BIT_FRAME_STOP);\n\n if (prototolVersion !== PROTOCOL_VERSION) {\n throw new Error(`Unexpected protocol version. Got ${prototolVersion}, expected ${PROTOCOL_VERSION}`);\n }\n\n return {\n timestamp,\n start,\n end,\n keyframe,\n sequence,\n isVP9,\n ssrc,\n eos,\n data: data.slice(HEADER_SIZE),\n };\n}\n\nexport function isKeyframeRequested(data?: ArrayBuffer): boolean {\n if (!data || !data.byteLength || data.byteLength !== 4) {\n return false;\n }\n const view = new DataView(data);\n\n const version = view.getUint8(0); // 1 byte version - версия протокола\n if (version !== PROTOCOL_VERSION) {\n return false;\n }\n\n const type = view.getUint8(1); // 1 byte type - тип пакета\n if (type !== TYPE_KEYFRAME) {\n return false;\n }\n\n const ssrc = view.getUint16(2); // 2 bytes ssrc\n if (ssrc !== SSRC_DEFAULT) {\n return false;\n }\n\n return true;\n}\n\nexport interface CcFeedback {\n seq: number; // original packet sequence\n ts2: number; // server timestamp\n}\n\nexport function parseCcFeedback(data?: ArrayBuffer): CcFeedback | null {\n if (!data || !data.byteLength || data.byteLength !== 10) {\n return null;\n }\n const view = new DataView(data);\n\n const version = view.getUint8(0); // 1 byte version - версия протокола\n if (version !== PROTOCOL_VERSION) {\n return null;\n }\n\n const type = view.getUint8(1); // 1 byte type - тип пакета\n if (type !== TYPE_CC_FEEDBACK) {\n return null;\n }\n\n const ssrc = view.getUint16(2); // 2 bytes ssrc\n if (ssrc !== SSRC_DEFAULT) {\n return null;\n }\n\n const seq = view.getUint16(4); // 2 bytes seq\n const ts2 = view.getUint32(6); // 4 bytes server timestamp\n\n return { seq, ts2 };\n}\n\nexport function prepareKeyFrameRequest(ssrc: number) {\n const buf = new ArrayBuffer(4);\n const view = new DataView(buf);\n\n view.setUint8(0, PROTOCOL_VERSION);\n view.setUint8(1, TYPE_KEYFRAME);\n view.setUint16(2, ssrc);\n\n return buf;\n}\n", "import * as EBML from 'simple-ebml-builder';\nimport Debug from '../../static/Debug';\nimport { ParticipantId } from '../../types/Participant';\nimport { BaseStreamBuilder, FrameData, IOnStat, IOnStream } from './BaseStreamBuilder';\n\nconst MAX_INT16 = 2 ** 15 - 1;\nconst TRACK_NUMBER = 1;\n\nconst MAX_BUFER_SIZE_SEC = 5;\nconst MIN_BUFER_SIZE_FOR_REMOVE_SEC = 5;\n\nenum Codec {\n VP8 = 'vp8',\n VP9 = 'vp9',\n}\n\nclass MediaBuffer {\n private readonly _mediaSource: MediaSource;\n private _codec: Codec;\n private _sourceBuffer: SourceBuffer | null = null;\n private _queue: EBML.EBMLData[] = []; // FIXME: переделать на fast list\n private _clearBufferTill = 0;\n\n constructor(codec: Codec) {\n this._mediaSource = new MediaSource();\n this._codec = codec;\n\n const onSourceopen = () => {\n this._mediaSource.removeEventListener('sourceopen', onSourceopen);\n this._initBuffer();\n this._handleQueue();\n };\n this._mediaSource.addEventListener('sourceopen', onSourceopen, false);\n }\n\n private _handleQueue() {\n if (!this._sourceBuffer || this._sourceBuffer.updating || !this._queue.length) {\n return;\n }\n\n if (this._clearBufferTill && this._sourceBuffer.buffered.length) {\n const start = this._sourceBuffer.buffered.start(0);\n if (start < this._clearBufferTill) {\n this._sourceBuffer.remove(start, this._clearBufferTill);\n Debug.debug(`[WebmBuilder] SourceBuffer cleanup from ${start} to ${this._clearBufferTill}`);\n }\n this._clearBufferTill = 0;\n return;\n }\n\n const queue = this._queue;\n this._queue = []; // Делаем синхронно, чтобы очередь не наполнялась пока мы её разгребаем\n const data = MediaBuffer._buildQueue(queue);\n this._sourceBuffer.appendBuffer(data);\n }\n\n private static _buildQueue(queue: EBML.EBMLData[]): Uint8Array {\n if (!queue.length) {\n return new Uint8Array();\n } else if (queue.length === 1) {\n return EBML.build(queue[0]);\n }\n\n const size = queue.reduce((acc: number, current: EBML.EBMLData) => acc + current.countSize(), 0);\n const result = new Uint8Array(size);\n let offset = 0;\n\n for (const element of queue) {\n const item = EBML.build(element);\n result.set(item, offset);\n offset += item.byteLength;\n }\n\n return result;\n }\n\n private _initBuffer() {\n this._sourceBuffer = this._mediaSource.addSourceBuffer(`video/webm; codecs=\"${this._codec}\"`);\n this._sourceBuffer.mode = 'sequence';\n // this._sourceBuffer.mode = 'segments';\n this._sourceBuffer.addEventListener('updateend', () => this._handleQueue());\n }\n\n changeType(codec: Codec) {\n this._codec = codec;\n return this._sourceBuffer?.changeType(codec);\n }\n\n append(data: EBML.EBMLData, flush = false) {\n this._queue.push(data);\n if (flush) {\n this._handleQueue();\n }\n }\n\n cleanup() {\n if (this._mediaSource?.readyState === 'open') {\n // Делаем abort() в начале сегмента, чтобы избежать фризов\n // @see https://github.com/google/shaka-player/issues/2566\n this._sourceBuffer?.abort();\n }\n\n const buffer = this._sourceBuffer?.buffered;\n const size = buffer?.length;\n\n if (!size) {\n return;\n }\n\n const start = buffer.start(0);\n const end = Math.max(0, buffer.end(size - 1) - MAX_BUFER_SIZE_SEC);\n\n if (end - start > MIN_BUFER_SIZE_FOR_REMOVE_SEC) {\n this._clearBufferTill = end;\n }\n }\n\n destroy() {\n this._queue = [];\n if (this._mediaSource.readyState === 'open') {\n this._sourceBuffer?.abort();\n this._mediaSource.endOfStream();\n }\n this._sourceBuffer = null;\n this._clearBufferTill = 0;\n }\n\n get codec() {\n return this._codec;\n }\n\n get mediaSource() {\n return this._mediaSource;\n }\n\n get buffered() {\n return this._sourceBuffer?.buffered;\n }\n}\n\nexport default class WebmBuilder extends BaseStreamBuilder {\n private _mediaBuffer: MediaBuffer | null = null;\n\n private _video: HTMLVideoElement | null = null;\n private _stream: MediaStream | null = null;\n\n private _earliestTimestamp = 0;\n private _clusterStartTime = 0;\n private _lastFrameTimestamp = 0;\n\n constructor(participantId: ParticipantId, onStream: IOnStream, onStat: IOnStat) {\n super(participantId, onStream, onStat);\n Debug.debug(`[WebmBuilder] started for participant [${participantId}]`);\n }\n\n private static _intToU16BE(u: number) {\n return new Uint8Array([u >> 8, u]);\n }\n\n private static _genWebmHeader(): EBML.EBMLData {\n return EBML.element(EBML.ID.EBML, [\n EBML.element(EBML.ID.EBMLVersion, EBML.number(1)),\n EBML.element(EBML.ID.EBMLReadVersion, EBML.number(1)),\n EBML.element(EBML.ID.EBMLMaxIDLength, EBML.number(4)),\n EBML.element(EBML.ID.EBMLMaxSizeLength, EBML.number(8)),\n EBML.element(EBML.ID.DocType, EBML.string('webm')),\n EBML.element(EBML.ID.DocTypeVersion, EBML.number(2)),\n EBML.element(EBML.ID.DocTypeReadVersion, EBML.number(2)),\n ]);\n }\n\n private static _genSegmentHeader(width: number, height: number, codec: Codec): EBML.EBMLData {\n const segmentInfo = EBML.element(EBML.ID.Info, [\n EBML.element(EBML.ID.TimecodeScale, EBML.number(1e6)),\n EBML.element(EBML.ID.MuxingApp, EBML.string('vk-webm-builder')),\n EBML.element(EBML.ID.WritingApp, EBML.string('vk-webm-builder')),\n ]);\n\n const videoProperties = [EBML.element(EBML.ID.PixelWidth, EBML.number(width)), EBML.element(EBML.ID.PixelHeight, EBML.number(height))];\n\n const tracks = EBML.element(\n EBML.ID.Tracks,\n EBML.element(EBML.ID.TrackEntry, [\n EBML.element(EBML.ID.TrackNumber, EBML.number(TRACK_NUMBER)),\n EBML.element(EBML.ID.TrackUID, EBML.number(TRACK_NUMBER)),\n EBML.element(EBML.ID.TrackType, EBML.number(1)),\n EBML.element(EBML.ID.FlagLacing, EBML.number(0)),\n // EBML.element(EBML.ID.DefaultDuration, EBML.number(1e7)), // 100fps\n // EBML.element(EBML.ID.DefaultDuration, EBML.number(4e7)), // 25fps\n EBML.element(EBML.ID.DefaultDuration, EBML.number(1e9)), // 1fps\n EBML.element(EBML.ID.CodecID, EBML.string(`V_${codec.toUpperCase()}`)),\n EBML.element(EBML.ID.Video, videoProperties),\n ]),\n );\n\n return EBML.unknownSizeElement(EBML.ID.Segment, [segmentInfo, tracks]);\n }\n\n private static _genClusterHeader(clusterStartTime: number): EBML.EBMLData {\n return EBML.unknownSizeElement(EBML.ID.Cluster, [EBML.element(EBML.ID.Timecode, EBML.number(Math.round(clusterStartTime)))]);\n }\n\n private _createVideo(codec: Codec) {\n this._mediaBuffer = new MediaBuffer(codec);\n\n this._video = document.createElement('video');\n this._video.autoplay = true;\n this._video.controls = false;\n this._video.muted = true;\n\n this._video.style.pointerEvents = 'none';\n this._video.style.visibility = 'hidden';\n this._video.style.position = 'absolute';\n this._video.style.width = '160px';\n this._video.style.height = '90px';\n this._video.style.bottom = '0';\n this._video.style.right = '0';\n this._video.style.zIndex = '5000';\n\n this._video.src = URL.createObjectURL(this._mediaBuffer.mediaSource);\n document.body.appendChild(this._video);\n\n const onPause = () => {\n if (this._video?.src) {\n Debug.warn(`[WebmBuilder] Video paused for participant [${this._participantId}], try to play again`);\n const buffer = this._video.seekable;\n if (buffer.length) {\n this._video.currentTime = buffer.end(buffer.length - 1) - 0.1;\n }\n this._video.play().catch(() => {});\n }\n };\n\n this._video.onpause = onPause;\n this._video.onwaiting = onPause;\n this._video.onstalled = onPause;\n this._video.onerror = () => Debug.warn(`[WebmBuilder] Video Error for participant [${this._participantId}]`, this._video?.error);\n\n // @ts-ignore TS2532: Object is possibly 'undefined'\n this._stream = this._video.captureStream();\n this._onStream(this._stream);\n }\n\n protected _processFrame(frame: FrameData) {\n const codec = frame.isVP9 ? Codec.VP9 : Codec.VP8;\n if (!this._mediaBuffer) {\n this._createVideo(codec);\n } else if (this._mediaBuffer.codec !== codec) {\n this._mediaBuffer.changeType(codec);\n }\n\n let time = frame.timestamp;\n if (time <= this._lastFrameTimestamp) {\n // Иногда приходят разные фреймы с одинаковым временем\n time = this._lastFrameTimestamp + 10;\n Debug.debug(`[WebmBuilder] Fixup timestamp for participant [${this._participantId}]`);\n }\n this._lastFrameTimestamp = time;\n\n if (!this._earliestTimestamp) {\n if (!frame.keyframe) {\n // Первым кадром обязательно должен быть опорник\n return;\n }\n\n this._earliestTimestamp = time;\n time = 0;\n } else {\n time -= this._earliestTimestamp;\n }\n\n if (frame.keyframe) {\n this._clusterStartTime = time;\n\n // NB: cleanup должен вызываться только в начале сегмента, т.к. он делает SourceBuffer.abort()\n this._mediaBuffer?.cleanup();\n\n Debug.debug(`[WebmBuilder] Segment header for participant [${this._participantId}]`);\n const webmHeader = WebmBuilder._genWebmHeader();\n this._mediaBuffer?.append(webmHeader);\n const segmentHeader = WebmBuilder._genSegmentHeader(frame.width, frame.height, codec);\n this._mediaBuffer?.append(segmentHeader);\n }\n\n let timecode = Math.round(time - this._clusterStartTime);\n if (timecode > MAX_INT16) {\n this._clusterStartTime = time;\n timecode = 0;\n }\n\n if (timecode === 0) {\n Debug.debug(`[WebmBuilder] Cluster header for participant [${this._participantId}]`);\n const cluster = WebmBuilder._genClusterHeader(this._clusterStartTime);\n this._mediaBuffer?.append(cluster);\n }\n\n const block = EBML.element(EBML.ID.SimpleBlock, [\n EBML.vintEncodedNumber(TRACK_NUMBER),\n EBML.bytes(WebmBuilder._intToU16BE(timecode)),\n EBML.number((frame.keyframe ? 1 : 0) << 7),\n EBML.bytes(frame.frameData),\n ]);\n this._mediaBuffer?.append(block, true);\n }\n\n override destroy() {\n super.destroy();\n\n if (this._video) {\n this._video.onpause = null;\n this._video.onwaiting = null;\n this._video.onstalled = null;\n this._video.onerror = null;\n\n this._video.pause();\n this._video.src = '';\n document.body.removeChild(this._video);\n }\n if (this._mediaBuffer) {\n this._mediaBuffer.destroy();\n this._mediaBuffer = null;\n }\n if (this._stream) {\n this._stream.getTracks().forEach((track: MediaStreamTrack) => track.stop());\n this._stream = null;\n }\n\n Debug.debug(`[WebmBuilder] destroyed for participant [${this._participantId}]`);\n }\n\n static override isBrowserSupported(): boolean {\n // В FF есть mozCaptureStream, но мы его не используем, т.к. в FF есть другие проблемы\n // @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/captureStream\n return (\n 'captureStream' in window.HTMLVideoElement?.prototype &&\n window.MediaSource?.isTypeSupported(`video/webm; codecs=\"${Codec.VP8}\"`) &&\n window.MediaSource?.isTypeSupported(`video/webm; codecs=\"${Codec.VP9}\"`)\n );\n }\n}\n", "import Debug from '../../static/Debug';\nimport Params from '../../static/Params';\nimport { ParticipantId } from '../../types/Participant';\nimport LibVPxDecoder from '../codec/LibVPxDecoder';\nimport WebCodecsDecoder from '../codec/WebCodecsDecoder';\nimport { ParticipantIdRegistry } from '../ParticipantIdRegistry';\nimport { BaseStreamBuilder, IOnStat, IOnStream } from './BaseStreamBuilder';\nimport StreamBuilder from './StreamBuilder';\nimport { parseChunk, prepareKeyFrameRequest } from './Utils';\nimport WebmBuilder from './WebmBuilder';\n\nexport default class ScreenCaptureReceiver {\n private readonly _datachannel: RTCDataChannel;\n private _participantIdRegistry: ParticipantIdRegistry | null = null;\n private _streamBuilders: Record<ParticipantId, BaseStreamBuilder> = {};\n private _onStream: Function = () => {};\n private _onEos: Function = () => {};\n private _onStat: IOnStat;\n\n constructor(\n datachannel: RTCDataChannel,\n participantIdRegistry: ParticipantIdRegistry,\n onStream: (streamId: string, stream: MediaStream) => void,\n onEos: (streamId: string) => void,\n onStat: IOnStat,\n ) {\n Debug.debug('ScreenCaptureReceiver started');\n\n this._datachannel = datachannel;\n this._participantIdRegistry = participantIdRegistry;\n this._onStream = onStream;\n this._onEos = onEos;\n this._onStat = onStat;\n\n this._datachannel.onmessage = (e) => this._onDataChannelMessage(e.data);\n }\n\n private _onDataChannelMessage(data: ArrayBuffer) {\n const chunk = parseChunk(data);\n const participantId = this._participantIdRegistry?.getStreamDescription(chunk.ssrc)?.participantId;\n if (!participantId) {\n Debug.warn(`Participant id for ssrc ${chunk.ssrc} not found in registry`);\n return;\n }\n\n if (chunk.eos) {\n // TODO: Андрей, почини EOS\n this.close(participantId);\n this._onEos(participantId);\n return;\n }\n\n let streamBuilder = this._streamBuilders[participantId];\n\n if (!streamBuilder) {\n const onStream: IOnStream = (stream) => this._onStream(participantId, stream);\n const onKeyFrameRequested = () => {\n this._requestKeyFrame(chunk.ssrc);\n };\n if (Params.screenShareWebmBuilder && WebmBuilder.isBrowserSupported()) {\n streamBuilder = new WebmBuilder(participantId, onStream, this._onStat);\n } else {\n streamBuilder = new StreamBuilder(participantId, onStream, this._onStat, onKeyFrameRequested);\n }\n this._streamBuilders[participantId] = streamBuilder;\n }\n\n streamBuilder.appendChunk(chunk);\n }\n\n /**\n * Отправить запрос ключевого кадра в datachannel.\n */\n private _requestKeyFrame(ssrc: number): void {\n if (!this._datachannel || this._datachannel.readyState !== 'open') {\n return;\n }\n\n try {\n const buf = prepareKeyFrameRequest(ssrc);\n this._datachannel.send(buf);\n Debug.debug(`ScreenCaptureReceiver request for keyframe for ssrc ${ssrc}`);\n } catch (error) {\n Debug.warn('Failed to send keyframe request', error);\n }\n }\n\n close(participantId: ParticipantId) {\n const streamBuilder = this._streamBuilders[participantId];\n if (streamBuilder) {\n streamBuilder.destroy();\n delete this._streamBuilders[participantId];\n }\n }\n\n destroy() {\n this._datachannel.onbufferedamountlow = null;\n this._datachannel.onmessage = null;\n this._onStream = () => {};\n Object.values(this._streamBuilders).forEach((streamBuilder) => streamBuilder.destroy());\n this._streamBuilders = {};\n this._participantIdRegistry = null;\n Debug.debug('ScreenCaptureReceiver destroyed');\n }\n\n static isBrowserSupported(): boolean {\n return (WebCodecsDecoder.isBrowserSupported() || LibVPxDecoder.isBrowserSupported()) && (StreamBuilder.isBrowserSupported() || WebmBuilder.isBrowserSupported());\n }\n}\n", "import IList from './IList';\n\nclass Item<T> {\n private _prev: Item<T> | null;\n private _next: Item<T> | null;\n private readonly _data: T;\n\n constructor(data: T, prev: Item<T> | null, next: Item<T> | null) {\n this._next = next;\n if (next) {\n next.prev = this;\n }\n\n this._prev = prev;\n if (prev) {\n prev.next = this;\n }\n\n this._data = data;\n }\n\n get prev(): Item<T> | null {\n return this._prev;\n }\n\n set prev(value: Item<T> | null) {\n this._prev = value;\n }\n\n get next(): Item<T> | null {\n return this._next;\n }\n\n set next(value: Item<T> | null) {\n this._next = value;\n }\n\n get data(): T {\n return this._data;\n }\n}\n\nexport class FastList<T = never> implements IList<T> {\n private _head: Item<T> | null = null;\n private _tail: Item<T> | null = null;\n private _length = 0;\n\n get length(): number {\n return this._length;\n }\n\n push(...data: T[]): void {\n for (const item of data) {\n this._tail = new Item(item, this._tail, null);\n if (!this._head) {\n this._head = this._tail;\n }\n this._length++;\n }\n }\n\n merge(data: FastList<T>): void {\n if (this._tail) {\n this._tail.next = data._head;\n }\n if (!this._head) {\n this._head = data._head;\n }\n this._tail = data._tail;\n this._length += data._length;\n data.clear();\n }\n\n shift(): T | null {\n if (!this._length || !this._head) {\n return null;\n }\n\n const result = this._head;\n this._head = result.next;\n\n if (this._head) {\n result.next = null;\n this._head.prev = null;\n }\n\n this._length--;\n if (this.length === 1) {\n this._tail = this._head;\n } else if (!this.length) {\n this._head = this._tail = null;\n }\n\n return result.data;\n }\n\n bisect(): void {\n if (this.length) {\n const center = this.length > 1 ? Math.floor(this.length / 2) : 1;\n for (let i = 0; i < center; i++) {\n this.shift();\n }\n }\n }\n\n head(): T | null {\n return this._head?.data || null;\n }\n\n tail(): T | null {\n return this._tail?.data || null;\n }\n\n clear(): void {\n this._head = null;\n this._tail = null;\n this._length = 0;\n }\n\n toString(): string {\n const result = [];\n let item = this._head;\n while (item !== null) {\n result.push(item.data);\n item = item.next;\n }\n if (!result.length) {\n return '';\n }\n return JSON.stringify(result, (key, value) => {\n if (value instanceof Error) {\n return String(value);\n }\n return value;\n });\n }\n}\n", "import libvpx from '@vkontakte/libvpx';\nimport Debug from '../../static/Debug';\nimport IEncoder, { FrameMessage } from './IEncoder';\nimport { EncodedVideoFrame, MessageType, OnFrameCallback } from './Types';\nimport WorkerBase from './WorkerBase';\n\nconst FRAME_READ_TIMEOUT = 1000;\n\nexport default class LibVPxEncoder extends WorkerBase implements IEncoder {\n private readonly _sourceTrack: MediaStreamTrack;\n private readonly _onFrame: OnFrameCallback;\n private readonly _useCongestionControl: boolean;\n private readonly _maxBitrate: number;\n private readonly _useImageCapture: boolean; // Сафари не умеет ImageCapture\n private _video: HTMLVideoElement | null = null;\n private _imageCapture: ImageCapture | null = null;\n private _canvas: HTMLCanvasElement | null = null;\n private _canvasCtx: CanvasRenderingContext2D | null = null;\n private _frameReadTimeout = 0;\n private _lastFrame: ImageBitmap | null = null;\n\n constructor(sourceTrack: MediaStreamTrack, onFrame: OnFrameCallback, useCongestionControl: boolean, maxBitrate: number) {\n super();\n this._sourceTrack = sourceTrack;\n this._onFrame = onFrame;\n this._useCongestionControl = useCongestionControl;\n this._maxBitrate = maxBitrate;\n\n // Проверка grabFrame нужна, так как в Safari завезли ImageCapture, но без этого метода\n this._useImageCapture = 'ImageCapture' in window && ImageCapture.prototype.grabFrame !== undefined && 'ImageBitmap' in window;\n\n // Если запустить скриншару пока в звонке никого нет и шарить вкладку хрома на которой ничего не происходит,\n // то трек становится muted и grabFrame не может его читать\n if (sourceTrack.readyState !== 'live' || !sourceTrack.enabled || sourceTrack.muted) {\n this._useImageCapture = false;\n }\n }\n\n private _createDom(): void {\n if (!this._canvas) {\n this._canvas = document.createElement('canvas');\n this._canvas.style.pointerEvents = 'none';\n this._canvas.style.visibility = 'hidden';\n this._canvas.style.position = 'absolute';\n this._canvas.style.width = '160px';\n this._canvas.style.height = '90px';\n this._canvas.style.bottom = '0';\n this._canvas.style.right = '160px';\n this._canvas.style.zIndex = '5000';\n this._canvasCtx = this._canvas.getContext('2d');\n document.body.appendChild(this._canvas);\n }\n\n if (!this._video && !this._useImageCapture) {\n this._video = document.createElement('video');\n this._video.controls = false;\n this._video.autoplay = false;\n this._video.preload = 'auto';\n this._video.muted = true;\n this._video.style.pointerEvents = 'none';\n this._video.style.visibility = 'hidden';\n this._video.style.position = 'absolute';\n this._video.style.width = '160px';\n this._video.style.height = '90px';\n this._video.style.bottom = '0';\n this._video.style.right = '0';\n this._video.style.zIndex = '5000';\n document.body.appendChild(this._video);\n }\n }\n\n private _removeDom(): void {\n try {\n if (this._canvas) {\n document.body.removeChild(this._canvas);\n }\n if (this._video) {\n document.body.removeChild(this._video);\n }\n } catch (e) {}\n\n this._canvasCtx = null;\n this._canvas = null;\n this._video = null;\n }\n\n private async _createStream(videoTrack: MediaStreamTrack): Promise<void> {\n if (!this._canvas) {\n throw new Error('Canvas not found');\n }\n\n if (!this._video && !this._useImageCapture) {\n throw new Error('Video element not found');\n }\n\n return new Promise((resolve, reject) => {\n if (this._useImageCapture) {\n this._imageCapture = new ImageCapture(videoTrack);\n resolve();\n } else {\n const video = this._video as HTMLVideoElement;\n video.srcObject = new MediaStream([videoTrack]);\n video.onloadeddata = (e) => resolve();\n video.onerror = () => reject(new Error('Video element error'));\n\n const playResult = video.play();\n const noAutoplay = () => reject(new Error('Autoplay is disabled'));\n if (playResult) {\n playResult.catch(noAutoplay);\n } else {\n noAutoplay();\n }\n }\n });\n }\n\n private _removeStream(): void {\n window.clearTimeout(this._frameReadTimeout);\n this._lastFrame?.close();\n\n if (this._video) {\n this._video.pause();\n this._video.srcObject = null;\n }\n if (this._imageCapture) {\n this._imageCapture = null;\n }\n }\n\n private _drawFrameVideo(): ImageData {\n if (!this._canvas || !this._canvasCtx || !this._video) {\n throw new Error('Fatal error');\n }\n\n // Safari autopause video element if browser's tab hidden\n // or inactive\n if (this._video.paused) {\n this._video.play();\n }\n\n const width = this._video.videoWidth;\n const height = this._video.videoHeight;\n this._canvas.width = this._video.width = width;\n this._canvas.height = this._video.height = height;\n\n this._canvasCtx.clearRect(0, 0, width, height);\n this._canvasCtx.drawImage(this._video, 0, 0, width, height);\n return this._canvasCtx.getImageData(0, 0, width, height);\n }\n\n private async _getFrameBitmap(): Promise<ImageBitmap> {\n if (!this._imageCapture) {\n throw new Error('Destroyed');\n }\n return this._imageCapture.grabFrame();\n }\n\n private _drawFrameData(imageBitmap: ImageBitmap): ImageData {\n if (!this._canvas || !this._canvasCtx) {\n throw new Error('Destroyed');\n }\n\n const width = imageBitmap.width;\n const height = imageBitmap.height;\n this._canvas.width = width;\n this._canvas.height = height;\n\n this._canvasCtx.clearRect(0, 0, width, height);\n this._canvasCtx.drawImage(imageBitmap, 0, 0, width, height);\n return this._canvasCtx?.getImageData(0, 0, width, height);\n }\n\n async init(): Promise<void> {\n this._createDom();\n\n const width = this._sourceTrack.getSettings().width as number;\n const height = this._sourceTrack.getSettings().height as number;\n Debug.debug(`LibVPxEncoder started ${width}x${height}, codec ${this.isVP9() ? 'VP9' : 'VP8'}`);\n\n await this._createStream(this._sourceTrack);\n await this._createWorker(\n LibVPxEncoderWorker,\n (data: FrameMessage) => {\n if (data.error) {\n this._onFrame(null, data.error);\n } else {\n this._onFrame({\n type: data.frameType,\n timestamp: data.timestamp,\n duration: data.duration,\n data: data.data,\n byteLength: data.data?.byteLength,\n width: data.width,\n height: data.height,\n } as EncodedVideoFrame);\n }\n },\n [libvpx, libvpx.getUrl, this._useCongestionControl, this._maxBitrate],\n { isVP9: this.isVP9(), debug: Debug.enabled() },\n );\n }\n\n private _encode(imageData: ImageData, keyFrame: boolean) {\n const buffer = imageData.data.buffer;\n this._sendToWorker(\n MessageType.FRAME,\n {\n width: imageData.width,\n height: imageData.height,\n imageData: buffer,\n keyFrame,\n },\n [buffer],\n );\n }\n\n private _requestFrameVideo(keyFrame: boolean) {\n const imageData = this._drawFrameVideo();\n this._encode(imageData, keyFrame);\n }\n\n private _requestFrameBitmap(keyFrame: boolean) {\n // Если запустить скриншару и шарить вкладку хрома на которой ничего не происходит,\n // то трек становится muted и grabFrame() реджектится. Чтобы данные уходили, по таймеру отправляем старый фрейм\n window.clearTimeout(this._frameReadTimeout);\n this._frameReadTimeout = window.setTimeout(() => {\n if (this._lastFrame) {\n const imageData = this._drawFrameData(this._lastFrame);\n this._encode(imageData, keyFrame);\n } else {\n this._onFrame(null);\n }\n }, FRAME_READ_TIMEOUT);\n\n this._getFrameBitmap()\n .then((imageBitmap) => {\n window.clearTimeout(this._frameReadTimeout);\n this._lastFrame?.close();\n this._lastFrame = imageBitmap;\n\n const imageData = this._drawFrameData(imageBitmap);\n this._encode(imageData, keyFrame);\n })\n .catch(() => {\n // Do nothing\n });\n }\n\n requestFrame(keyFrame = false): void {\n if (this._useImageCapture) {\n this._requestFrameBitmap(keyFrame);\n } else {\n this._requestFrameVideo(keyFrame);\n }\n }\n\n setBitrate(bitrate: number, useCbr: boolean, fps: number): void {\n this._sendToWorker(MessageType.SET_BITRATE, { bitrate, useCbr });\n }\n\n isVP9(): boolean {\n return false;\n }\n\n destroy() {\n this._removeWorker();\n this._removeStream();\n this._removeDom();\n Debug.debug('LibVPxEncoder destroyed');\n }\n\n static override isBrowserSupported(): boolean {\n return (\n 'WebAssembly' in window &&\n 'Worker' in window &&\n // В FF есть CanvasCaptureMediaStream, в остальных есть CanvasCaptureMediaStreamTrack\n ('CanvasCaptureMediaStream' in window || 'CanvasCaptureMediaStreamTrack' in window)\n );\n }\n}\n", "import Debug from '../../static/Debug';\nimport IEncoder, { FrameMessage } from './IEncoder';\nimport { EncodedVideoFrame, MessageType, OnFrameCallback } from './Types';\nimport WorkerBase from './WorkerBase';\n\nexport default class WebCodecsEncoder extends WorkerBase implements IEncoder {\n private readonly _sourceTrack: MediaStreamTrack;\n private readonly _trackProcessor: MediaStreamTrackProcessor;\n private readonly _onFrame: OnFrameCallback;\n private readonly _useCongestionControl: boolean;\n private readonly _maxBitrate: number;\n private readonly _useCbr: boolean;\n private readonly _frameRate: number;\n\n constructor(sourceTrack: MediaStreamTrack, onFrame: OnFrameCallback, useCongestionControl: boolean, maxBitrate: number, useCbr: boolean, frameRate: number) {\n super();\n this._sourceTrack = sourceTrack;\n this._onFrame = onFrame;\n this._useCongestionControl = useCongestionControl;\n this._maxBitrate = maxBitrate;\n this._useCbr = useCbr;\n this._frameRate = frameRate;\n this._trackProcessor = new MediaStreamTrackProcessor({ track: sourceTrack });\n }\n\n async init(): Promise<void> {\n const width = this._sourceTrack.getSettings().width as number;\n const height = this._sourceTrack.getSettings().height as number;\n const readable = this._trackProcessor.readable;\n\n Debug.debug(`WebCodecsEncoder started ${width}x${height}, codec ${this.isVP9() ? 'VP9' : 'VP8'}`);\n\n await this._createWorker(\n WebCodecsEncoderWorker,\n (data: FrameMessage) => {\n if (data.error) {\n this._onFrame(null, data.error);\n } else {\n this._onFrame({\n type: data.frameType,\n timestamp: data.timestamp,\n duration: data.duration,\n data: data.data,\n byteLength: data.data?.byteLength,\n width: data.width,\n height: data.height,\n } as EncodedVideoFrame);\n }\n },\n [],\n {\n readable,\n width,\n height,\n isVP9: this.isVP9(),\n framerate: this._frameRate,\n useCongestionControl: this._useCongestionControl,\n maxBitrate: this._maxBitrate,\n useCbr: this._useCbr,\n },\n [readable],\n );\n }\n\n requestFrame(keyFrame = false): void {\n this._sendToWorker(MessageType.FRAME, { keyFrame });\n }\n\n setBitrate(bitrate: number, useCbr: boolean, fps: number): void {\n this._sendToWorker(MessageType.SET_BITRATE, { bitrate, useCbr, fps });\n }\n\n isVP9(): boolean {\n return true;\n }\n\n destroy(): void {\n this._removeWorker();\n Debug.debug('WebCodecsEncoder destroyed');\n }\n\n static override isBrowserSupported(): boolean {\n return 'VideoEncoder' in window && 'Worker' in window && 'EncodedVideoChunk' in window && 'MediaStreamTrackProcessor' in window;\n }\n}\n", "import Debug from '../../static/Debug';\nimport { OnCongestionCallback } from '../codec/Types';\nimport { SharingStatReport } from './SharingStatReport';\n\nconst DEFAULT_DELAY_THRESHOLD = 2_100;\nconst FAST_DELAY_THRESHOLD = 600;\nconst SWITCH_UP_STEP = 1.2; // +20%\nconst SWITCH_DOWN_STEP = 0.8; // -20%\nconst SWITCH_DOWN_TIMEOUT_MS = 2_000;\nconst SWITCH_UP_TIMEOUT_MS = 8_000;\nconst SWITCH_UP_PENALTY_STEP = 8_000;\nconst PROBING_TIMEOUT_MS = 16_000;\nconst MAX_PENALTY = 4;\nconst LARGE_DELAY_STAT_THRESHOLD_MS = 2_000;\nenum Decision {\n NONE,\n UP,\n DOWN,\n}\n\nexport default class ScreenCongestionControl {\n private readonly _onCongestion: OnCongestionCallback;\n private readonly _ccEnabled: boolean;\n private readonly _fastSharing: boolean;\n private readonly _trendDelayThreshold: number;\n private readonly _highDelayThreshold: number;\n private readonly _targetFps: number;\n private _minBitrate: number;\n private _maxBitrate: number;\n private _targetBitrate: number;\n\n private _lastDown: number;\n private _lastUp: number;\n private _lastProbing: number;\n private _lastCheckDelay: number;\n private _upPenalty = 0;\n private _probing: boolean;\n private _delayAvgShort = -1;\n private _delayAvgLong = -1;\n\n // stats\n private _minDelay = Number.MAX_VALUE;\n private _maxDelay = 0;\n private _largeDelayDuration = 0;\n\n // calc fps\n private _lastFpsCalcMs: number;\n private _frames = 0;\n private _fps = 0;\n\n constructor(onCongestion: OnCongestionCallback, minBitrate: number, maxBitrate: number, ccEnabled: boolean, fastSharing: boolean, delayThreshold: number, targetFps: number) {\n this._onCongestion = onCongestion;\n this._ccEnabled = ccEnabled;\n this._minBitrate = minBitrate;\n this._maxBitrate = maxBitrate;\n this._fastSharing = fastSharing;\n this._targetFps = targetFps;\n if (delayThreshold > 0) {\n this._highDelayThreshold = delayThreshold;\n } else {\n this._highDelayThreshold = DEFAULT_DELAY_THRESHOLD;\n }\n if (fastSharing) {\n this._highDelayThreshold = FAST_DELAY_THRESHOLD;\n }\n this._trendDelayThreshold = Math.round(this._highDelayThreshold / 3);\n\n this._targetBitrate = this._maxBitrate;\n this._probing = false;\n\n const now = Date.now();\n this._lastDown = 0; // DOWN decision can be approved from the very start\n this._lastUp = now;\n this._lastProbing = now;\n this._lastCheckDelay = 0;\n this._lastFpsCalcMs = 0;\n }\n\n checkDelay(frameNum: number, delay: number, bitrateK: number): void {\n const now = Date.now();\n // is being called for every frame, can calc fps\n this._calcFps(now);\n // we need stats always, even when cc is not enabled\n this._calcDelay(delay, now);\n if (this._delayAvgShort <= 0 || this._delayAvgLong <= 0) {\n // нет статистики - не можем работать\n return;\n }\n if (!this._ccEnabled) {\n // cc not enabled, dont change bitrate\n return;\n }\n\n // make decision\n let decision = Decision.NONE;\n // решение принимаем по задержке - это главная метрика\n // насколько тренд (среднее по короткому окну) превышает текущую базу (среднее по длинному окну)\n const delayDelta = this._delayAvgShort - this._delayAvgLong;\n // насколько тренд превышает текущую базу в процентах\n const delayDeltaPercent = Math.round((Math.abs(delayDelta) * 100) / this._delayAvgLong);\n // проверяем также на абсолютное значение задержки - чтобы не реагировать на кратковременные всплески от опорников\n const isDelayTrend = delayDelta > 40 && delayDeltaPercent > 30 && this._delayAvgShort > this._trendDelayThreshold;\n const isHighDelay = this._delayAvgShort > this._highDelayThreshold;\n if (isDelayTrend || isHighDelay) {\n decision = Decision.DOWN;\n } else if (Math.abs(delayDelta) < 40 && delayDeltaPercent < 10 && !isHighDelay) {\n // изменения задержки небольшие - стабильная ситуация - можно повышать битрейт\n decision = Decision.UP;\n }\n\n // implement the decision\n const targetBitrateK = Math.round(this._targetBitrate / 1000);\n const currentBitrateK = bitrateK;\n if (frameNum % 20 === 0) {\n Debug.debug(\n `#${frameNum}: cc: delay=${delay} short=${this._delayAvgShort} long=${this._delayAvgLong} delta=${delayDelta} percent=${delayDeltaPercent} -> ${Decision[decision]} tr=${targetBitrateK} br=${bitrateK}`,\n );\n }\n // check switch down\n const elapsedDown = now - this._lastDown;\n if (decision === Decision.DOWN && elapsedDown > SWITCH_DOWN_TIMEOUT_MS) {\n if (this._probing) {\n // probing failed\n this._upPenalty = Math.min(++this._upPenalty, MAX_PENALTY);\n this._probing = false;\n }\n // network congestion, target -20% of current bitrate to clean network buffers\n let newBitrate = SWITCH_DOWN_STEP * currentBitrateK * 1000;\n if (newBitrate >= this._targetBitrate) {\n newBitrate = this._targetBitrate * SWITCH_DOWN_STEP;\n }\n newBitrate = Math.max(newBitrate, this._minBitrate);\n if (newBitrate < this._targetBitrate) {\n const newBitrateK = Math.round(newBitrate / 1000);\n const penaltySec = Math.round((this._upPenalty * SWITCH_UP_PENALTY_STEP) / 1000);\n Debug.log(\n `#${frameNum}: cc: delay=${delay} short=${this._delayAvgShort} long=${this._delayAvgLong} delta=${delayDelta} percent=${delayDeltaPercent} -> ${Decision[decision]}`,\n );\n Debug.log(`#${frameNum}: cc: DOWN delay=${delay} bitrate=${currentBitrateK} target=${targetBitrateK} -> newBitrate=${newBitrateK} penalty=${penaltySec}s`);\n // enable CBR - to limit size of key frames\n this._setBitrate(newBitrate, true);\n this._targetBitrate = newBitrate;\n }\n this._lastDown = now;\n }\n // check switch up\n const elapsedUp = now - this._lastUp;\n const switchUpTimeout = SWITCH_UP_TIMEOUT_MS + this._upPenalty * SWITCH_UP_PENALTY_STEP;\n if (decision === Decision.UP && elapsedUp > switchUpTimeout && elapsedDown > switchUpTimeout) {\n const newBitrate = Math.min(this._targetBitrate * SWITCH_UP_STEP, this._maxBitrate);\n if (newBitrate > this._targetBitrate) {\n const newBitrateK = Math.round(newBitrate / 1000);\n const targetK = Math.round(this._targetBitrate / 1000);\n const penaltySec = Math.round((this._upPenalty * SWITCH_UP_PENALTY_STEP) / 1000);\n Debug.log(\n `#${frameNum}: cc: delay=${delay} short=${this._delayAvgShort} long=${this._delayAvgLong} delta=${delayDelta} percent=${delayDeltaPercent} -> ${Decision[decision]}`,\n );\n Debug.log(`#${frameNum}: cc: UP bitrate=${currentBitrateK} target=${targetK} -> newBitrate=${newBitrateK} penalty=${penaltySec}s`);\n // disable CBR\n this._setBitrate(newBitrate, false);\n this._targetBitrate = newBitrate;\n this._probing = true;\n this._lastProbing = now;\n this._lastUp = now;\n }\n }\n // check probing\n const elapsedProbing = now - this._lastProbing;\n if (this._probing && elapsedProbing > PROBING_TIMEOUT_MS) {\n // successful probing\n this._probing = false;\n }\n // reset penalty\n const elapsedDownPenalty = now - this._lastDown;\n if (this._upPenalty > 0 && elapsedDownPenalty > 3 * switchUpTimeout) {\n Debug.log(`#${frameNum}: cc: UP reset penalty: oldPenalty=${this._upPenalty}`);\n this._upPenalty = 0;\n }\n }\n\n private _setBitrate(bitrate: number, useCbr: boolean) {\n if (this._fastSharing) {\n // always use CBR in fast sharing mode\n useCbr = true;\n }\n let fps = this._targetFps;\n if (this._fps > 0) {\n fps = this._fps;\n }\n this._onCongestion(bitrate, useCbr, fps);\n }\n\n private _calcDelay(delay: number, now: number): void {\n if (delay <= 0) {\n return;\n }\n if (this._delayAvgShort === -1) {\n this._delayAvgShort = delay;\n this._delayAvgLong = delay;\n }\n // считаем среднее значение по короткому окну - это тренд\n this._delayAvgShort = Math.round((this._delayAvgShort * 3 + delay) / 4);\n // считаем среднее значение по длинному окну - это база\n this._delayAvgLong = Math.round((this._delayAvgLong * 23 + delay) / 24);\n\n // calc external stats\n if (delay > 0 && delay < this._minDelay) {\n this._minDelay = delay;\n } else if (delay > this._maxDelay) {\n this._maxDelay = delay;\n }\n if (this._lastCheckDelay === 0) {\n this._lastCheckDelay = now;\n }\n if (delay > LARGE_DELAY_STAT_THRESHOLD_MS) {\n // calculate total large_delay duration\n const elapsed = now - this._lastCheckDelay;\n this._largeDelayDuration += elapsed;\n }\n this._lastCheckDelay = now;\n }\n\n reconfigure(minBitrate: number, maxBitrate: number): void {\n this._minBitrate = minBitrate;\n this._maxBitrate = maxBitrate;\n }\n\n getStat(): SharingStatReport | null {\n if (this._minDelay === Number.MAX_VALUE || this._maxDelay === 0 || this._delayAvgLong <= 0) {\n // there were no activity = no stats\n return null;\n }\n const report: SharingStatReport = { minDelay: this._minDelay, maxDelay: this._maxDelay, avgDelay: this._delayAvgLong, largeDelayDuration: this._largeDelayDuration };\n this._minDelay = Number.MAX_VALUE;\n this._maxDelay = 0;\n this._largeDelayDuration = 0;\n return report;\n }\n\n private _calcFps(now: number): void {\n this._frames++;\n const elapsed = now - this._lastFpsCalcMs;\n if (elapsed > 5_000) {\n this._lastFpsCalcMs = now;\n const oldFps = this._fps;\n const fps = (this._frames * 1000) / elapsed;\n // calc smoothed _fps, as [moving average]\n if (this._fps === 0) {\n this._fps = Math.round(fps);\n } else {\n // smoothed = (smoothed * a + value * b) / (a + b)\n this._fps = Math.round((this._fps * 3 + fps) / 4);\n }\n this._frames = 0;\n if (this._fps !== oldFps) {\n Debug.log(`cc: fps=${this._fps}`);\n }\n }\n }\n}\n", "type HistoryRecord = {\n // packet sent from client:\n seq: number;\n ts: number;\n size: number;\n sent: number; // time when sent\n start: boolean;\n end: boolean;\n // feedback from server:\n ts2: number;\n recv: number; // time when received\n};\n\n/**\n * Class calculates server bitrate and delay, based on server cc feedback\n * Ring buffer to keep sent packets info (HistoryRecord)\n * Packet info is updated when cc feedback is received from server\n */\nexport default class PacketHistory {\n // keep packet info in ring buffer\n private readonly _maxSize: number;\n private _size = 0;\n private readonly _buffer: (HistoryRecord | undefined)[];\n private _head = 0;\n private _tail = 0;\n\n constructor(maxSize: number) {\n this._maxSize = maxSize;\n this._buffer = new Array(maxSize);\n }\n\n add(seq: number, ts: number, size: number, start: boolean, end: boolean): number {\n if (this._tail === this._head && this._size > 0) {\n this._head = ++this._head % this._maxSize;\n }\n const index = this._tail;\n this._buffer[this._tail] = { seq, ts, size, sent: Date.now(), start, end, ts2: -1, recv: -1 };\n this._tail = ++this._tail % this._maxSize;\n this._size++;\n return index;\n }\n\n update(seq: number, ts2: number): HistoryRecord | null {\n const rec = this.get(seq);\n if (rec === null) {\n return null;\n }\n rec.ts2 = ts2;\n rec.recv = Date.now();\n return rec;\n }\n\n get(seq: number): HistoryRecord | null {\n let i = this._head;\n for (let iter = 0; iter < this._maxSize; iter++) {\n const current = this._buffer[i];\n if (seq === current?.seq) {\n return current;\n }\n i = ++i % this._maxSize;\n if (i === this._tail) {\n break;\n }\n }\n return null;\n }\n\n getServerBitrateK(windowMs: number): number {\n // reverse calc, starting from tail\n let bitrateK = 0;\n let size = 0;\n let start = -1;\n let end = -1;\n let i = this._tail;\n for (let iter = 0; iter < this._maxSize; iter++) {\n if (i > 0) {\n --i;\n } else {\n i = this._maxSize - 1;\n }\n const rec = this._buffer[i];\n if (!rec) {\n break;\n }\n if (end === -1) {\n end = rec.ts2;\n size = 0;\n }\n if (end >= 0) {\n size += rec.size;\n }\n start = rec.ts2;\n const elapsed = end - start;\n if (elapsed >= windowMs) {\n break;\n }\n if (i === this._head) {\n break;\n }\n }\n if (start >= 0 && end >= 0) {\n const elapsed = end - start;\n bitrateK = Math.round(elapsed > 0 ? (size * 8) / elapsed : 0);\n }\n return bitrateK;\n }\n\n getCurrentDelay(): number {\n let i = this._tail;\n for (let iter = 0; iter < this._maxSize; iter++) {\n if (i > 0) {\n --i;\n } else {\n i = this._maxSize - 1;\n }\n const rec = this._buffer[i];\n if (!rec) {\n break;\n }\n if (rec.recv >= 0 && rec.sent >= 0) {\n const delay = rec.recv - rec.sent;\n return delay;\n }\n if (i === this._head) {\n break;\n }\n }\n return 0;\n }\n\n getMaxBandwidth(): number {\n // find large frame and calculate bitrate within it\n // reverse calc, starting from tail\n let bitrateK = 0;\n let size = 0;\n let start = -1;\n let end = -1;\n let i = this._tail;\n for (let iter = 0; iter < this._maxSize; iter++) {\n if (i > 0) {\n --i;\n } else {\n i = this._maxSize - 1;\n }\n const current = this._buffer[i];\n if (!current) {\n continue;\n }\n if (end === -1 && current.end && !current.start) {\n end = current.ts2;\n size = 0;\n }\n if (start === -1 && end >= 0 && current.start && !current.end) {\n start = current.ts2;\n }\n if (start >= 0 && end >= 0) {\n const elapsed = end - start;\n bitrateK = elapsed > 0 ? (size * 8) / elapsed : 0;\n break;\n }\n // dont consider first block - increase size after the calculation\n if (end >= 0) {\n size += current.size;\n }\n if (i === this._head) {\n break;\n }\n }\n return Math.round(bitrateK);\n }\n\n clear() {\n this._buffer.fill(undefined);\n this._size = 0;\n this._head = 0;\n this._tail = 0;\n }\n}\n", "import BaseSignaling from '../../abstract/BaseSignaling';\nimport Debug from '../../static/Debug';\nimport Params from '../../static/Params';\nimport Utils from '../../static/Utils';\nimport { FastList } from '../../utils/FastList';\nimport IEncoder from '../codec/IEncoder';\nimport LibVPxEncoder from '../codec/LibVPxEncoder';\nimport { EncodedVideoFrame, EncodedVideoFrameChunk } from '../codec/Types';\nimport WebCodecsEncoder from '../codec/WebCodecsEncoder';\nimport FpsMeter from '../FpsMeter';\nimport { isKeyframeRequested, wrapHeader, HEADER_SIZE, CcFeedback, parseCcFeedback } from './Utils';\nimport ScreenCongestionControl from './ScreenCongestionControl';\nimport PacketHistory from './PacketHistory';\nimport { SharingStatReport } from './SharingStatReport';\n\nconst SEQUENCE_OVERFLOW = 65536;\nconst BITS_PER_MACROBLOCK_MIN = 50;\nconst BITS_PER_MACROBLOCK_MAX = 400;\nconst MAX_MIN_BITRATE = 1_000_000;\nconst MIN_MIN_BITRATE = 300_000;\nconst SEND_STAT_INTERVAL_MS = 30_000;\nconst FRAMERATE_REDUCED_DEBUGLOG_INTERVAL = 2_000;\n// Несмотря на то, что datachannel.bufferedAmount пустой, операционная система (или браузер)\n// имеют свой буфер на отправку в датаканал. На плохой сети чанки застревают в буфере.\n// Нужно следить за его наполнением и отправлять новые чанки только когда сервер ответит, что принял данные\nconst MAX_CHUNKS_IN_BUFFER = 5;\n\nlet sequence = 0; // Сохраняем sequence глобально даже между инстансами\n\nexport default class ScreenCaptureSender {\n private readonly _encoder: IEncoder;\n private readonly _datachannel: RTCDataChannel;\n private readonly _signaling: BaseSignaling;\n private readonly _fastSharing: boolean;\n private _destroyed = false;\n private _needKeyframe = true;\n private readonly DATA_SIZE: number;\n private _congestionControl: ScreenCongestionControl;\n private _frameNum = 0;\n private _width: number;\n private _height: number;\n private _feedback: PacketHistory = new PacketHistory(1024);\n private _lastSentFrameSeq = 0;\n private _lastDeliveredFrameSeq = 0;\n private _lastFrameDelay = 0;\n private _lastFramerateReduced = Date.now();\n private _lastSharingStat = Date.now();\n private readonly _congestionControlEnabled: boolean;\n private readonly _queue = new FastList<EncodedVideoFrameChunk>();\n private readonly _fpsMeter: FpsMeter;\n private readonly _maxFrameDelay;\n\n constructor(track: MediaStreamTrack, datachannel: RTCDataChannel, signaling: BaseSignaling, fastSharing: boolean) {\n Debug.debug('ScreenCaptureSender started');\n\n // Размер одного пакета датаканала без заголовка\n this.DATA_SIZE = Params.consumerScreenDataChannelPacketSize - HEADER_SIZE;\n this._datachannel = datachannel;\n this._signaling = signaling;\n this._fastSharing = fastSharing;\n\n this._congestionControlEnabled = Params.screenShareCongestionControl || this._fastSharing;\n this._width = track.getSettings().width as number;\n this._height = track.getSettings().height as number;\n this._maxFrameDelay = this._fastSharing ? Params.screenShareCongestionControlThreshold : Params.screenShareCongestionControlThreshold * 2;\n const frameRate = Params.getScreenFrameRate(this._fastSharing);\n const { minBitrate, maxBitrate } = this._calcMinMaxBitrate(this._width, this._height);\n const boundCallback = this._onCongestionCallback.bind(this);\n // always create congestion control - it is needed for sharing stats reporting\n Debug.log(\n `ScreenCaptureSender: CongestionControl: enabled=${this._congestionControlEnabled} minBitrate=${Math.round(minBitrate / 1000)}k maxBitrate=${Math.round(maxBitrate / 1000)}k delayThreshold=${Params.screenShareCongestionControlThreshold}`,\n );\n this._congestionControl = new ScreenCongestionControl(\n boundCallback,\n minBitrate,\n maxBitrate,\n this._congestionControlEnabled,\n this._fastSharing,\n Params.screenShareCongestionControlThreshold,\n frameRate,\n );\n\n const onFrame = (frame: EncodedVideoFrame | null, e?: string) => {\n if (this._destroyed) {\n return;\n }\n\n if (!frame) {\n Debug.warn('requestFrame failed, keyFrame: ' + this._needKeyframe, e);\n this._needKeyframe = true;\n this._handleQueue();\n return;\n }\n\n if (frame.width !== this._width || frame.height !== this._height) {\n this._width = frame.width;\n this._height = frame.height;\n this._onResize(this._width, this._height);\n }\n\n const chunks = this._sliceFrame(frame);\n this._queue.merge(chunks);\n this._handleQueue();\n this._sendSharingStat();\n };\n\n if (WebCodecsEncoder.isBrowserSupported()) {\n const useCbr = this._fastSharing;\n this._encoder = new WebCodecsEncoder(track, onFrame, this._congestionControlEnabled, maxBitrate, useCbr, frameRate);\n } else {\n this._encoder = new LibVPxEncoder(track, onFrame, this._congestionControlEnabled, maxBitrate);\n }\n\n this._datachannel.onmessage = (e) => {\n if (isKeyframeRequested(e.data)) {\n Debug.debug(`[${this._datachannel.label}] Requested keyframe`);\n this._needKeyframe = true;\n }\n const cc = parseCcFeedback(e.data);\n if (cc !== null) {\n this._checkCcFeedback(cc);\n }\n };\n\n this._encoder\n .init()\n .then(() => this._handleQueue())\n .catch((e) => Debug.warn('ScreenCaptureSender init failed', e));\n // TODO: Прокинуть ошибку наружу\n\n this._fpsMeter = new FpsMeter((fps: number) => Debug.log(`[ScreenCaptureSender] fps: ${fps}`), 5_000);\n }\n\n private _handleQueue(): void {\n if (this._destroyed) {\n return;\n }\n\n const chunk = this._queue.shift();\n if (!chunk) {\n // Очередь пустая\n const seqDiff = (this._lastSentFrameSeq - this._lastDeliveredFrameSeq + SEQUENCE_OVERFLOW) % SEQUENCE_OVERFLOW;\n if (seqDiff > MAX_CHUNKS_IN_BUFFER && this._lastFrameDelay > this._maxFrameDelay) {\n // большая задержка, наш поток не пролезает- уменьшение битрейта енкодеру не помогло, тогда пробуем уменьшить фпс\n // не вызываем _requestFrame(), тем самым уменьшаем фпс\n const now = Date.now();\n const elapsed = now - this._lastFramerateReduced;\n if (elapsed > FRAMERATE_REDUCED_DEBUGLOG_INTERVAL) {\n this._lastFramerateReduced = now;\n Debug.debug(`[ScreenCaptureSender] reduce framerate: delay=${this._lastFrameDelay} maxDelay=${this._maxFrameDelay}`);\n }\n } else {\n this._requestFrame();\n }\n return;\n }\n\n const result = this._sendFrameChunk(chunk);\n if (!result) {\n this._needKeyframe = this._needKeyframe || !this._cleanupQueue();\n Utils.setImmediate(() => this._handleQueue());\n return;\n }\n\n if (chunk.isLast) {\n // Отправили кадр\n this._frameNum++;\n this._fpsMeter.increment();\n\n if (chunk.isKey) {\n Debug.debug(`#${this._frameNum}: sharing: send keyframe size=${Math.round(chunk.frameSize / 1000)}k`);\n }\n\n // congestion control\n const delay = this._feedback.getCurrentDelay();\n const bitrateK = this._feedback.getServerBitrateK(2_000);\n if (delay > 0) {\n this._congestionControl.checkDelay(this._frameNum, delay, bitrateK);\n }\n } else {\n Utils.setImmediate(() => this._handleQueue());\n }\n }\n\n /**\n * Очищает очередь до опорного кадра\n * @returns Есть ли в очереди опорный кадр\n * @hidden\n */\n private _cleanupQueue(): boolean {\n let head = this._queue.head();\n while (head) {\n if (head.isFirst && head.isKey) {\n return true;\n }\n this._queue.shift();\n head = this._queue.head();\n }\n return false;\n }\n\n private _requestFrame(): void {\n if (this._destroyed) {\n return;\n }\n\n this._encoder.requestFrame(this._needKeyframe);\n this._needKeyframe = false;\n }\n\n private _sliceFrame(frame: EncodedVideoFrame): FastList<EncodedVideoFrameChunk> {\n const isKey = frame.type === 'key';\n const totalBytes = frame.data.byteLength;\n const result = new FastList<EncodedVideoFrameChunk>();\n\n for (let offset = 0; offset < totalBytes; offset += this.DATA_SIZE) {\n const data = frame.data.slice(offset, offset + this.DATA_SIZE);\n const isFirst = offset === 0;\n const isLast = totalBytes <= offset + data.byteLength;\n const wrapped = this._wrapHeader(frame.timestamp, isFirst, isLast, isKey, data);\n result.push({\n data: wrapped.data,\n sequence: wrapped.sequence,\n frameSize: totalBytes,\n isFirst,\n isLast,\n isKey,\n timestamp: frame.timestamp,\n });\n }\n\n return result;\n }\n\n private _wrapHeader(timestamp: number, start: boolean, end: boolean, keyframe: boolean, data: ArrayBuffer | null): { sequence: number; data: ArrayBuffer } {\n const wrapped = wrapHeader(timestamp, start, end, keyframe, sequence, this._encoder.isVP9(), data);\n const result = {\n sequence,\n data: wrapped,\n };\n sequence = (sequence + 1) % SEQUENCE_OVERFLOW;\n return result;\n }\n\n private _stopPacket(): ArrayBuffer {\n return this._wrapHeader(Date.now(), false, false, false, null).data;\n }\n\n private _sendFrameChunk(chunk: EncodedVideoFrameChunk): boolean {\n if (!this._datachannel || this._datachannel.readyState !== 'open') {\n // Канал закрылся\n return false;\n }\n\n // Бывает странный race condition, когда противоположная сторона закрывает канал, но мы об этом еще не знаем\n try {\n this._datachannel.send(chunk.data);\n // add new packet (chunk) to PacketHistory\n this._feedback.add(chunk.sequence, chunk.timestamp, chunk.data.byteLength, chunk.isFirst, chunk.isLast);\n if (chunk.isLast) {\n this._lastSentFrameSeq = chunk.sequence;\n }\n return true;\n } catch (e) {\n Debug.warn('Error sending chunk to DataChannel', e);\n return false;\n }\n }\n\n destroy() {\n this._queue.clear();\n this._fpsMeter.destroy();\n this._datachannel.onmessage = null;\n this._feedback.clear();\n if (this._datachannel.readyState === 'open') {\n this._datachannel.send(this._stopPacket());\n }\n this._destroyed = true;\n this._encoder.destroy();\n Debug.debug('ScreenCaptureSender destroyed');\n }\n\n static isBrowserSupported(): boolean {\n return WebCodecsEncoder.isBrowserSupported() || LibVPxEncoder.isBrowserSupported();\n }\n\n private _onCongestionCallback(bitrate: number, useCbr: boolean, fps: number): void {\n this._encoder.setBitrate(bitrate, useCbr, fps);\n }\n\n private _onResize(width: number, height: number): void {\n const { minBitrate, maxBitrate } = this._calcMinMaxBitrate(width, height);\n const minBitrateK = Math.round(minBitrate / 1000);\n const maxBitrateK = Math.round(maxBitrate / 1000);\n Debug.log(`cc: resize to ${width}x${height}, minBitrate=${minBitrateK} maxBitrate=${maxBitrateK}`);\n this._congestionControl.reconfigure(minBitrate, maxBitrate);\n }\n\n private _calcMinMaxBitrate(width: number, height: number) {\n if (width === undefined || width < 640) {\n width = 640;\n }\n if (height === undefined || height < 360) {\n height = 360;\n }\n const macroBlocks = (width * height) / 256;\n const minBitrate = Math.max(MIN_MIN_BITRATE, Math.min(MAX_MIN_BITRATE, Math.round(macroBlocks * BITS_PER_MACROBLOCK_MIN)));\n const maxBitrate = Math.round(macroBlocks * BITS_PER_MACROBLOCK_MAX);\n return { minBitrate, maxBitrate };\n }\n\n /**\n * Сервер сообщает, какие чанки он получил от клиента\n * @internal\n * @private\n */\n private _checkCcFeedback(cc: CcFeedback): void {\n const rec = this._feedback.update(cc.seq, cc.ts2);\n if (rec === null) {\n Debug.debug(`cc: update failed, seq=${cc.seq}`);\n } else if (rec.end) {\n this._lastDeliveredFrameSeq = rec.seq;\n const delay = rec.recv - rec.sent;\n if (delay > 0) {\n this._lastFrameDelay = delay;\n }\n this._handleQueue();\n }\n }\n\n private _sendSharingStat() {\n const now = Date.now();\n const elapsed = now - this._lastSharingStat;\n if (elapsed > SEND_STAT_INTERVAL_MS) {\n const report = this._congestionControl.getStat();\n if (report !== null) {\n Debug.debug(`cc: send stats: ${JSON.stringify(report)}`);\n this._signaling.reportSharingStat(report);\n }\n this._lastSharingStat = now;\n }\n }\n}\n", "export default abstract class AuthData {\n private static _sessionKey: string | undefined;\n private static _sessionSecretKey: string | undefined;\n private static _accessToken: string | undefined;\n\n static get sessionKey() {\n return AuthData._sessionKey;\n }\n\n static set sessionKey(value: string | undefined) {\n AuthData._sessionKey = value;\n }\n\n static get sessionSecretKey() {\n return AuthData._sessionSecretKey;\n }\n\n static set sessionSecretKey(value: string | undefined) {\n AuthData._sessionSecretKey = value;\n }\n\n static get accessToken() {\n return AuthData._accessToken;\n }\n\n static set accessToken(value: string | undefined) {\n AuthData._accessToken = value;\n }\n\n static isEmpty() {\n return !AuthData._sessionKey;\n }\n}\n", "import type { VideoEffects } from '@vkontakte/calls-video-effects';\nimport type { EffectVoiceChange } from '@vkontakte/calls-audio-effects';\nimport type * as Vmoji from '@vkontakte/calls-vmoji';\nimport { IAsrData } from '../types/Asr';\nimport { ConversationData } from '../types/Conversation';\nimport HangupReason from '../classes/HangupReason';\nimport { MediaTrackKind } from '../classes/MediaSource';\nimport ScreenCaptureReceiver from '../classes/screenshare/ScreenCaptureReceiver';\nimport ScreenCaptureSender from '../classes/screenshare/ScreenCaptureSender';\nimport ChatRoomEventType from '../enums/ChatRoomEventType';\nimport ConversationOption from '../enums/ConversationOption';\nimport FatalError from '../enums/FatalError';\nimport MediaOption from '../enums/MediaOption';\nimport RoomsEventType from '../enums/RoomsEventType';\nimport UserRole from '../enums/UserRole';\nimport { IFeaturesPerRole } from '../types/ConversationFeature';\nimport { ExternalId, ExternalParticipant, ExternalParticipantId, ExternalParticipantListChunk, ExternalParticipantListMarkers } from '../types/ExternalId';\nimport { IFeedbackExternal } from '../types/Feedback';\nimport IceServer from '../types/IceServer';\nimport MediaModifiers from '../types/MediaModifiers';\nimport MediaSettings from '../types/MediaSettings';\nimport { IOnRemoteMovieData, ISharedMovieInfo, ISharedMovieState, ISharedMovieStoppedInfo } from '../types/MovieShare';\nimport MuteStates from '../types/MuteStates';\nimport { ParticipantsStateList, ParticipantStateMapped } from '../types/Participant';\nimport { MediaType } from '../types/ParticipantStreamDescription';\nimport { IRoomId, Room, RoomParticipantUpdate, Rooms, RoomsUpdate } from '../types/Room';\nimport { IAPIBaseUrl, IApiEnv } from '../types/Params';\nimport SignalingMessage from '../types/SignalingMessage';\nimport { VmojiError } from '../types/Vmoji';\nimport AuthData from './AuthData';\nimport Debug, { DebugMessageType } from './Debug';\nimport { ParticipantStatus } from './External';\nimport { JSONObject } from './Json';\nimport { ParticipantCapabilities } from './SignalingCapabilities';\nimport Utils from './Utils';\nimport WebRTCUtils, { FacingMode } from './WebRTCUtils';\n\n/**\n * Параметры инициализации\n */\nexport type ParamsObject = {\n /** @hidden */\n platform: string;\n /** @hidden */\n clientStatsPlatform: string;\n /** @hidden */\n clientType: string;\n /** @hidden */\n externalUserType: string;\n /** @hidden */\n device: string;\n\n /**\n * API ключ приложения\n */\n apiKey: string;\n /** @hidden */\n apiEnv: IApiEnv;\n /**\n * Базовый урл для запросов к API одноклассников\n * Позволяет задать значение независимо от apiEnv\n * @hidden\n */\n apiBaseUrl: IAPIBaseUrl;\n /** @hidden */\n apiAuth?: {\n sessionKey?: string;\n sessionSecretKey?: string;\n accessToken?: string;\n };\n /**\n * Токен авторизации\n */\n authToken: string;\n /**\n * Токен анонимной авторизации\n */\n anonymToken: string;\n /**\n * Домен, чтобы попасть в тестовую группу. Для тестирования экспериментальных улучшений существуют отдельные сервера, чтобы собирать фидбек и уже потом раскатывать на всех юзеров. Если передать сюда специальный ключ, то конверсейшн будет обрабатываться на таком сервере.\n */\n domain: string;\n\n /**\n * Домен, куда будет ходить Ok api за данными\n * @hidden\n */\n externalDomain: string;\n\n /** @hidden */\n iceServers: IceServer[];\n /** @hidden */\n wssBase: string;\n /** @hidden */\n wtsBase: string;\n /** @hidden */\n wssToken: string;\n\n /** @hidden */\n signalingReconnectDelay: number;\n /** @hidden */\n signalingReconnectMaxDelay: number;\n /** @hidden */\n signalingReconnectMaxCount: number;\n /** @hidden */\n waitConnectionDelay: number;\n /** @hidden */\n waitResponseDelay: number;\n /** @hidden */\n waitMessageDelay: number;\n\n /** @hidden */\n waitAnotherTabDelay: number;\n\n /** @hidden */\n debugLog: boolean;\n /** @hidden */\n debug: boolean;\n\n /**\n * Выставляет таймаут в ms для fetch запросов от sdk\n * По умолчанию 5000 ms\n * @hidden\n */\n apiTimeout: number;\n /**\n * Количество ретраев прежде чем сбросить ошибку\n * @hidden\n */\n apiMaxAttempt: number;\n\n /**\n * Не отправлять в ICE-кандидатах персональные IP-адреса\n * @see [RTCIceTransportPolicy](https://www.w3.org/TR/webrtc/#rtcicetransportpolicy-enum)\n *\n * _По умолчанию: `false`_\n */\n forceRelayPolicy: boolean;\n /**\n * Минимальная ширина видео в пикселях\n *\n * _По умолчанию: `428`_\n */\n videoMinWidth: number;\n /**\n * Максимальная ширина видео в пикселях\n *\n * _По умолчанию: `1280`_\n */\n videoMaxWidth: number;\n /**\n * Минимальная высота видео в пикселях\n *\n * _По умолчанию: `240`_\n */\n videoMinHeight: number;\n /**\n * Максимальная высота видео в пикселях\n *\n * _По умолчанию: `720`_\n */\n videoMaxHeight: number;\n /**\n * Соотношение сторон видео\n *\n * _По умолчанию: `16/9`_\n */\n videoAspectRatio: number;\n /**\n * FPS видео\n *\n * _По умолчанию: `25`_\n */\n videoFrameRate: number;\n /**\n * Какую камеру получать с мобильного устройства\n *\n * _По умолчанию: `FacingMode.USER` для мобильных устройств и `null` для остальных_\n */\n videoFacingMode: FacingMode | null;\n /**\n * FPS трансляции экрана\n *\n * _По умолчанию: `15`_\n */\n screenFrameRate: number;\n /**\n * Вариант захвата экрана. Поддерживается в Chrome 107+\n * @see https://developer.chrome.com/docs/web-platform/screen-sharing-controls/\n * @hidden\n */\n displaySurface: DisplayCaptureSurfaceType;\n /**\n * Экземпляр класса `VideoEffects` из [`@vkontakte/calls-video-effects`](https://npmjs.com/package/@vkontakte/calls-video-effects)\n *\n * Можно установить позднее методом `setVideoEffects`\n */\n videoEffects: VideoEffects | null;\n /**\n * Экземпляр класса `AudioEffects` из [`@vkontakte/calls-audio-effects`](https://npmjs.com/package/@vkontakte/calls-audio-effects)\n *\n * Можно установить позднее методом `setAudioEffects`\n */\n audioEffects: EffectVoiceChange | null;\n /**\n * Максимальная ширина видео в пикселях для видео эффекта\n *\n * _По умолчанию: `640`_\n */\n videoEffectMaxWidth: number;\n /**\n * Максимальная высота видео в пикселях для видео эффекта\n *\n * _По умолчанию: `360`_\n */\n videoEffectMaxHeight: number;\n\n /**\n * Экземпляр класса `Vmoji` из [`@vkontakte/calls-vmoji`](https://npmjs.com/package/@vkontakte/calls-vmoji)\n *\n * Можно установить позднее методом `setVmoji`\n */\n vmoji: typeof Vmoji | null;\n\n /**\n * Настройки Vmoji\n */\n vmojiOptions: {\n protocolVersion: Vmoji.AnimojiVersion;\n renderingOptions: Partial<Vmoji.RenderingOptions>;\n } | null;\n\n /** @hidden */\n iceRestartWaitTime: number;\n\n /** @hidden */\n transportConnectionWaitTime: number;\n /**\n * Частота получения статистики в миллисекундах\n *\n * _По умолчанию: `5000`_\n */\n statisticsInterval: number;\n /**\n * Частота отправки сообщения bad-net в p2p звонке\n *\n * _По умолчанию: `20000`_\n * @hidden\n */\n networkStatisticsInterval: number;\n\n /**\n * Параметры детектора голоса\n *\n * @property **speakerLevelMultiplier**: _number_\n *\n * Множитель уровня громкости при переключении активного говорящего\n *\n * _По умолчанию: `1.8`_\n *\n * @property **smoothing**: _number_\n *\n * Значение сглаживания громкости [0..1]\n *\n * _По умолчанию: `0.8`_\n */\n voiceParams: { [key: string]: number };\n /** @hidden */\n specListenerParams: { [key: string]: number };\n\n /** @hidden */\n perfStatReportEnabled: boolean;\n /** @hidden */\n callStatReportEnabled: boolean;\n /**\n * Включает логирование событий продуктовой статистики.\n *\n * _По умолчанию: `false`_\n * @hidden\n */\n clientEventsLoggingEnabled: boolean;\n\n /**\n * Отдавать приоритет кодеку H264 для исходящего видео\n *\n * _По умолчанию: `false`_\n */\n preferH264: boolean;\n /**\n * Отдавать приоритет кодеку VP9 для исходящего видео,\n * если preferH264 тоже выставлен в true то первый приоритет будет у VP9, второй у H264\n *\n * _По умолчанию: `false`_\n */\n preferVP9: boolean;\n\n /** @hidden */\n audioNack: boolean;\n\n /**\n * Принимать параллельно видео с камеры и трансляцию экрана от одного и того же участника.\n * Работает только при приёме экрана через дата-канал.\n *\n * _По умолчанию: `true`_\n * @deprecated\n */\n producerScreenTrack: boolean;\n /**\n * Отдавать трансляцию экрана отдельным стримом.\n * Работает только при отправке экрана через дата-канал.\n *\n * _По умолчанию: `true`_\n * @deprecated\n */\n consumerScreenTrack: boolean;\n\n /**\n * @hidden\n * @deprecated\n */\n producerNotificationDataChannel: boolean;\n /**\n * @hidden\n * @deprecated\n */\n producerCommandDataChannel: boolean;\n /**\n * @hidden\n * @deprecated\n */\n consumerScreenDataChannel: boolean;\n /**\n * @hidden\n * @deprecated\n */\n producerScreenDataChannel: boolean;\n /** @hidden */\n asrDataChannel: boolean;\n\n /**\n * Размер пакета для отправки трансляции экрана в датаканал в байтах.\n * Максимальный размер пакета 65536 bytes в хроме, но по стандарту лучше максимум 16 Кб.\n * @hidden\n */\n consumerScreenDataChannelPacketSize: number;\n\n /** @hidden */\n screenShareWebmBuilder: boolean;\n\n /** @hidden */\n noiseSuppression: boolean;\n /**\n * Количество входящих видео-треков.\n *\n * Только для звонков с серверной топологией.\n * Для прямых peer-to-peer звонков эта настройка не используется.\n *\n * При значении 0 количество треков меняется динамически\n * в зависимости от количества участников звонка.\n *\n * При значении отличном от 0 количество треков фиксировано,\n * при этом клиент должен уведомлять сервер о том, каких участников звонка\n * он хочет видеть, через вызов updateDisplayLayout\n *\n * _По умолчанию: `30`_\n */\n videoTracksCount: number;\n /** @hidden */\n movieShare: boolean;\n /** @hidden */\n breakVideoPayloadTypes: boolean;\n /**\n * Включить звонки контактам\n *\n * _По умолчанию: `false`_\n * @hidden\n */\n useCallsToContacts: boolean;\n /**\n * Включить постраничный вывод участников. Работает только если включено videoTracksCount (слоты)\n *\n * _По умолчанию: `false`_\n */\n useParticipantListChunk: boolean;\n /**\n * Включить сессионные залы\n *\n * _По умолчанию: `false`_\n */\n useRooms: boolean;\n /**\n * Включить чат румы\n *\n * _По умолчанию: `false`_\n */\n useChatRooms: boolean;\n /**\n * Включить поддержку добавления участника в разговор\n */\n addParticipant: boolean;\n /**\n * Включает поддержку режима WAIT_FOR_ADMIN в звонках.\n */\n waitForAdminInGroupCalls: boolean;\n /**\n * Индекс участника для первого chunk'а который придет при установке соединения с сервером\n *\n * _По умолчанию: `0`_\n */\n participantListChunkInitIndex: number;\n /**\n * Количество участников которые придут в первом chunk'е при установке соединения с сервером\n * если параметр не проставлен то будет использоваться значение по умолчанию установленное на сервере\n */\n participantListChunkInitCount: number | null;\n /**\n * Включать RED-extension (redundancy) для групповых звонков\n *\n * _По умолчанию: `true`_\n * @deprecated\n */\n serverAudioRed: boolean;\n /**\n * Включать RED-extension (redundancy) для p2p звонков\n *\n * _По умолчанию: `true`_\n * @deprecated\n */\n p2pAudioRed: boolean;\n /**\n * Добавлять флаг spsPpsIdrInKeyframe для h264 кодека. В результате ключевые фреймы без sps и pps\n * не используются как ключевые. Решает проблему с артефактами на видео в случае потерь пакетов.\n * @hidden\n * @deprecated\n */\n h264spsPpsIdrInKeyframe: boolean;\n /**\n * Разрешить вход в звонок одним пользователем с разных устройств одновременно\n *\n * _По умолчанию: `false`_\n */\n joinFromMultipleDevices: boolean;\n\n /**\n * Фильтровать наблюдателей во всех колбэках\n * @hidden\n */\n filterObservers: boolean;\n\n /**\n * Отключить звук собеседников\n * @hidden\n */\n muteMode: boolean;\n\n /**\n * Сохранять (не удалять) аудио дорожки в стримах, поступающих клиенту\n * Позволяет клиенту получать и сохранять аудио данные\n * Внимание: может привести к \"двойному\" звуку при проигрывании\n * @hidden\n */\n preserveAudioTracks: boolean;\n\n /**\n * Использовать congestion control для шаринга\n * @hidden\n */\n screenShareCongestionControl: boolean;\n\n /**\n * Порог задержки (мс), выше которого включается congestion control для шаринга\n * @hidden\n */\n screenShareCongestionControlThreshold: number;\n\n /**\n * Включить возможность захвата звука при трансляции экрана\n *\n * _По умолчанию: `false`_\n */\n audioShare: boolean;\n\n /**\n * Включить поддержку динамического контента при трансляция экрана\n *\n * _По умолчанию: `false`_\n */\n fastScreenShare: boolean;\n\n /** @hidden */\n fastScreenShareFrameRate: number;\n /** @hidden */\n fastScreenShareWidth: number;\n /** @hidden */\n fastScreenShareHeight: number;\n\n /**\n * Включить отправку быстрой шары с клиента по RTP\n *\n * _По умолчанию: `false`_\n */\n consumerFastScreenShare: boolean;\n\n /**\n * Включает отправку сервером нотификации video-quality-update\n *\n * _По умолчанию: `false`_\n */\n consumerFastScreenShareQualityOnDemand: boolean;\n\n /**\n * Использовать новые правила allMute для админа\n */\n newMuteRules: boolean;\n\n /**\n * Включить поддержку приостановки видео в плохой сети.\n *\n * _По умолчанию: `false`_\n */\n videoSuspend: boolean;\n\n /**\n * Задержка обновления списка устройств после подключения/отключения камеры или микрофона\n * @hidden\n */\n enumerateDevicesDelay: number;\n\n /**\n * Включает логгирование статистики webrtc\n *\n * _По умолчанию: `false`_\n */\n enableLogPerfStatReport: boolean;\n\n /**\n * Поддержка переключения качества видео в зависимости от сети\n * Только для режима p2p\n *\n * _По умолчанию: `false`_\n */\n switchVideoAtBadNetwork: boolean;\n\n /**\n * Включает деградацию фпс для видео с камеры при низком фпс с включенными вирт фонами\n *\n * _По умолчанию: `false`_\n */\n enableVideoEffectsFpsDegradation: boolean;\n\n /**\n * Включить поддержку simulcast на отправке\n *\n * _По умолчанию: `false`_\n */\n simulcast: boolean;\n\n /**\n * Включить поддержку webtransport для сигналинга\n *\n * _По умолчанию: `false`_\n */\n webtransport: boolean;\n\n /**\n * Включить поддержку webtransport для сигналинга в FireFox\n * Отдельная ручка, так как есть проблемы сейчас с FF\n *\n * _По умолчанию: `false`_\n */\n webtransportFF: boolean;\n\n /**\n * Получен локальный стрим с камеры/микрофона\n */\n onLocalStream?: (stream: MediaStream | null, mediaSettings: MediaSettings) => void;\n /**\n * Локальный стрим изменился\n */\n onLocalStreamUpdate?: (mediaSettings: MediaSettings, kind: MediaTrackKind) => void;\n /**\n * Локальный стрим с экрана добавлен/удалён\n */\n onScreenStream?: (stream: MediaStream | null, mediaSettings: MediaSettings) => void;\n /**\n * Локальный стрим вимоджи добавлен/удалён\n */\n onVmojiStream?: (stream: MediaStream | null, mediaSettings: MediaSettings) => void;\n /**\n * Произошла ошибка вимоджи\n */\n onVmojiError?: (error: VmojiError) => void;\n /**\n * Изменился статус локального соединения\n */\n onLocalStatus?: (status: ParticipantStatus) => void;\n /**\n * Получен стрим собеседника.\n * Если сервер закончил стримить собеседника, вместо стрима будет передан null\n */\n onRemoteStream?: (userId: ExternalParticipantId, stream: MediaStream | null) => void;\n /**\n * Cтрим собеседника приостановлен/возобновлен.\n */\n onRemoteStreamSuspended?: (userId: ExternalParticipantId, mediaType: MediaType, suspended: boolean) => void;\n /**\n * Получен стрим с экрана собеседника.\n * Если сервер закончил стримить экран собеседника, вместо стрима будет передан null\n */\n onRemoteScreenStream?: (userId: ExternalParticipantId, stream: MediaStream | null) => void;\n /**\n * Получен стрим вимоджи собеседника.\n * Если сервер закончил стримить вимоджи собеседника, вместо стрима будет передан null\n */\n onRemoteVmojiStream?: (userId: ExternalParticipantId, stream: MediaStream | null) => void;\n /**\n * Получен стрим трансляция или мувик от собеседника.\n * Если сервер закончил стримить экран собеседника, вместо стрима будет передан null\n */\n onRemoteLive?: (userId: ExternalParticipantId, data: IOnRemoteMovieData) => void;\n /**\n * Получен собственный стрим трансляция или мувик.\n * Если сервер закончил стримить экран собеседника, вместо стрима будет передан null\n */\n onLocalLive?: (userId: ExternalParticipantId, data: IOnRemoteMovieData) => void;\n /**\n * Получено обновление стрима или лайва от собеседника.\n */\n onRemoteLiveUpdate?: (userId: ExternalParticipantId, data: ISharedMovieState) => void;\n /**\n * Получено обновление собственного стрима или лайва.\n */\n onLocalLiveUpdate?: (userId: ExternalParticipantId, data: ISharedMovieState) => void;\n /**\n * Начат звонок\n */\n onConversation?: (userId: ExternalParticipantId, mediaModifiers: MediaModifiers, muteStates: MuteStates, participants: ExternalParticipant[], rooms?: Rooms) => void;\n /**\n * Начальный список участников для постраничного звонка\n */\n onConversationParticipantListChunk?: (chunk: ExternalParticipantListChunk) => void;\n /**\n * Изменились данные стрима собеседника\n */\n onRemoteMediaSettings?: (userId: ExternalParticipantId, mediaSettings: MediaSettings, markers: ExternalParticipantListMarkers | null) => void;\n /**\n * Изменились данные стрима собеседника\n */\n onLocalMediaSettings?: (userId: ExternalParticipantId, mediaSettings: MediaSettings) => void;\n /**\n * Полученны данные по стримам (лайв/мувик) от собеседника\n */\n onRemoteSharedMovieInfo?: (userId: ExternalParticipantId, sharedMovieInfo: ISharedMovieInfo, roomId?: IRoomId) => void;\n /**\n * Полученны данные по остановленным стримам (лайв/мувик) от собеседника\n */\n onRemoteSharedMovieStoppedInfo?: (userId: ExternalParticipantId, sharedMovieStoppedInfo: ISharedMovieStoppedInfo, roomId?: IRoomId) => void;\n /**\n * Полученны данные по собственным стримам (лайв/мувик)\n */\n onLocalSharedMovieInfo?: (userId: ExternalParticipantId, sharedMovieInfo: ISharedMovieInfo, roomId?: IRoomId) => void;\n /**\n * Полученны данные по собственным остановленным стримам (лайв/мувик)\n */\n onLocalSharedMovieStoppedInfo?: (userId: ExternalParticipantId, sharedMovieStoppedInfo: ISharedMovieStoppedInfo, roomId?: IRoomId) => void;\n /**\n * Добавили участника\n */\n onParticipantAdded?: (userId: ExternalParticipantId, markers: ExternalParticipantListMarkers | null) => void;\n /**\n * Участник присоединился к звонку\n */\n onParticipantJoined?: (userId: ExternalParticipantId, markers: ExternalParticipantListMarkers) => void;\n /**\n * Получены данные по изменению локальных состояний со стороны админа\n * Например, принудительно опущена рука\n *\n * @param participantState Полный объект состояния участника, полученный от SDK/сервера.\n * @param global `true` – действие глобальное (для всех участников), `false` – действие локальное (только у текущего пользователя).\n */\n onLocalParticipantState?: (participantState: ParticipantStateMapped, global: boolean) => void;\n /**\n * Изменились данные состояний собеседника\n */\n onRemoteParticipantState?: (userId: ExternalParticipantId, participantState: ParticipantStateMapped, markers: ExternalParticipantListMarkers | null) => void;\n /**\n * Изменились данные состояний нескольких собеседников\n */\n onRemoteParticipantsState?: (stateList: ParticipantsStateList, roomId?: IRoomId) => void;\n /**\n * Изменился статус соединения собеседников\n */\n onRemoteStatus?: (userIds: ExternalParticipantId[], status: ParticipantStatus, data: any) => void;\n /**\n * Разрешения на доступы были запрошены в браузере\n */\n onPermissionsRequested?: () => void;\n /**\n * Ошибка получения трека с камеры или микрофона\n */\n onPermissionsError?: (error: FatalError, original: Error) => void;\n /**\n * Пользователь отключился от звонка\n */\n onRemoteRemoved?: (userId: ExternalParticipantId, markers: ExternalParticipantListMarkers | null) => void;\n /**\n * Изменилось состояние звонка\n */\n onCallState?: (isCallActive: boolean, canAddParticipants: boolean, conversation: ConversationData) => void;\n /**\n * Изменилось состояние камеры или микрофона\n */\n onDeviceSwitched?: (mediaOption: MediaOption, enabled: boolean) => void;\n /**\n * Изменились состояния устройств пользователя или разрешения включать камеру/микрофон\n */\n onMuteStates?: (\n muteStates: MuteStates,\n unmuteOptions: MediaOption[],\n mediaOptions: MediaOption[],\n muteAll: boolean,\n unmute: boolean,\n userId: ExternalParticipantId | null,\n adminId: ExternalParticipantId | null,\n stateUpdated?: boolean,\n requestedMedia?: MediaOption[],\n roomId?: number | null,\n ) => void;\n /**\n * Изменились роли собеседника в звонке\n */\n onRolesChanged?: (userId: ExternalParticipantId, roles: UserRole[], isInitial?: boolean) => void;\n /**\n * Изменились свои роли в звонке\n */\n onLocalRolesChanged?: (roles: UserRole[], isInitial?: boolean) => void;\n /**\n * Закрепляет/открепляет собеседника для всех\n */\n onPinnedParticipant?: (userId: ExternalParticipantId, unpin: boolean, markers: ExternalParticipantListMarkers | null, roomId?: number | null) => void;\n /**\n * Закрепляет/открепляет текущего пользователя у других собеседников\n */\n onLocalPin?: (unpin: boolean) => void;\n\n /**\n * Изменились опции звонка\n */\n onOptionsChanged?: (options: ConversationOption[]) => void;\n\n onRateNeeded?: Function;\n /**\n * Изменился говорящий в звонке\n */\n onSpeakerChanged?: (userId: ExternalParticipantId) => void;\n /**\n * Громкость собеседников\n */\n onVolumesDetected?: (volumes: { uid: ExternalParticipantId; volume: number }[]) => void;\n /**\n * Громкость своего микрофона\n */\n onLocalVolume?: (volume: number, isMicEnabled: boolean) => void;\n onJoinStatus?: Function;\n /**\n * Звонок был завершен\n */\n onHangup?: (type: HangupReason | Error, conversationId: string | null) => void;\n /**\n * Входящий звонок был принят мной\n */\n onCallAccepted?: () => void;\n /**\n * Исходящий звонок был принят кем-то\n * @param userId\n */\n onAcceptedCall?: (userId: ExternalParticipantId, capabilities: ParticipantCapabilities) => void;\n /**\n * Список устройств изменился\n */\n onDeviceChange?: () => void;\n onMultipartyChatCreated?: (conversation: ConversationData) => void;\n /**\n * Изменилась подпись звонка 1:1\n */\n onFingerprintChange?: (fingerprint: string) => void;\n /**\n * Требуется обновление токена\n */\n onTokenExpired?: () => void;\n /**\n * Получено сообщение чата\n */\n onChatMessage?: (message: string, from: ExternalParticipantId, direct: boolean) => void;\n /**\n * Получены данные от собеседника\n */\n onCustomData?: (data: JSONObject, from: ExternalParticipantId, direct: boolean) => void;\n /**\n * Начата трансляция/запись звонка\n */\n onRecordStarted?: (\n initiator: ExternalParticipantId,\n movieId: number,\n startTime: number,\n type: 'STREAM' | 'RECORD',\n externalMovieId?: string,\n externalOwnerId?: string,\n roomId?: number | null,\n ) => void;\n /**\n * Закончена трансляция/запись звонка\n */\n onRecordStopped?: (roomId: number | null, stopBy: ExternalParticipantId | null) => void;\n\n /**\n * Состояние своей сети\n *\n * @param rating Оценка качества соединения от 0 до 1\n */\n onLocalNetworkStatusChanged?: (rating: number) => void;\n\n /**\n * Состояние сети участников\n *\n * @param status Оценки качества соединения участников от 0 до 1\n */\n onNetworkStatusChanged?: (status: { uid: ExternalParticipantId; rating: number }[]) => void;\n /**\n * Получено отладочное сообщение. Работает только при выключенном режиме отладки\n */\n onDebugMessage?: (type: DebugMessageType, ...args: any[]) => void;\n /**\n * Статистика звонка\n */\n onStatistics?: (stats: {}) => void;\n /**\n * Ошибка воспроизведения звука\n */\n onAutoplayError?: () => void;\n /**\n * Изменилось состояние зала ожидания/зала в режиме Audience\n *\n * @param eventType Тип события\n * @param totalCount Количество ожидающих/слушателей\n * @param firstParticipants Первые несколько ожидающих в зале\n * @param addedParticipantIds Некоторое количество участников, добавленных в зал\n * @param removedParticipantIds Некоторое количество участников, убранных из зала\n */\n onChatRoomUpdated?: (\n eventType: ChatRoomEventType,\n totalCount: number,\n firstParticipants: ExternalId[],\n addedParticipantIds: ExternalId[],\n removedParticipantIds: ExternalId[],\n ) => void;\n /**\n * Получен микшированный аудио стрим.\n * @hidden\n * @param stream стрим от WebRTC\n */\n onRemoteMixedAudioStream?: (stream: MediaStream) => void;\n /**\n * Получена новая ссылка на звонок\n * @param joinLink токен присоединения к звонку\n */\n onJoinLinkChanged?: (joinLink: string) => void;\n /**\n * Получено обновление списка сессионных залов\n * @param updates список обновлений по залам\n */\n onRoomsUpdated?: (updates: Partial<Record<RoomsEventType, RoomsUpdate>>) => void;\n /**\n * Получено обновление сессионных зало\n * @param eventTypes список событий\n * @param roomId номер сессионного зала\n * @param room сессионный зал\n */\n onRoomUpdated?: (eventTypes: RoomsEventType[], roomId: number, room: Room | null, deactivate: boolean | null) => void;\n /**\n * Получение обновление списка участников в сессионном зале\n * @param update обновление списка участников\n */\n onRoomParticipantsUpdated?: (update: RoomParticipantUpdate) => void;\n /**\n * Получение информации о смене зала\n * @param roomId номер сессионного зала\n */\n onRoomSwitched?: (roomId: number | null) => void;\n /**\n * Установить id сессионного зала на старте звонка\n * @param roomId номер сессионного зала\n */\n onRoomStart?: (roomId: number | null) => void;\n /**\n * Получены новые реакции в звонке\n * @param feedback массив с реакциями\n */\n onFeedback?: (feedback: IFeedbackExternal[], roomId: number | null) => void;\n /**\n * Изменился список ролей, которым доступны ConversationFeatures\n *\n * @param featuresPerRole Объект вида ключ: ConversationFeature = значение: UserRole[]\n * (если ключ фичи отсутствует, или в ролях пустой массив, считаем фичу доступной для всех пользователей)\n */\n onFeaturesPerRoleChanged?: (featuresPerRole: IFeaturesPerRole) => void;\n /**\n * Изменился Vmoji-аватар пользователя\n * @param externalId Id пользователя, у которого изменился аватар\n */\n onParticipantVmojiUpdate?: (externalId: ExternalParticipantId) => void;\n /**\n * Начата текстовая расшифровка звонка\n * @param initiatorId Id пользователя, запустившего расшифровку звонка\n * @param movieId Id расшифровки\n * @param roomId Id комнаты\n */\n onAsrStarted?: (initiatorId: ExternalParticipantId, movieId: number, roomId: number | null) => void;\n /**\n * Закончена текстовая расшифровка звонка\n * @param roomId Id комнаты\n */\n onAsrStopped?: (roomId: number | null) => void;\n /**\n * Получена расшифровка речи\n * @param id Id пользователя, произнесшего реплику\n * @param text Текст расшифровки\n * @param timestamp Время расшифровки\n * @param duration Длительность реплики в расшифровке\n */\n onAsrTranscription?: (id: ExternalParticipantId, text: string, timestamp: number, duration: number) => void;\n /**\n * Установка начальных параметров текстовой расшифровки звонка. (Используется при входе в звонок/ смене комнаты)\n * @param data Начальная информация по ASR\n * @param roomId Id Комнаты\n */\n onAsrSet?: (data: IAsrData | null, roomId: number | null) => void;\n\n /**\n * Админ начал/остановил совместное использование стороннего web-приложения\n * @param userId id участника-админа\n * @param sharedUrl url страницы\n */\n onRemoteSharedUrl?: (userId: ExternalParticipantId, sharedUrl: string | undefined, roomId: IRoomId) => void;\n /**\n * Изменился id участника (деанонимизация)\n * @param prevId\n * @param newId\n */\n onParticipantIdChanged?: (prevId: ExternalParticipantId, newId: ExternalParticipantId) => void;\n /**\n * Предложение включить режим автоматического отключения приёма видео\n * в плохой сети\n * @param bandwidth текущая полоса пропускания, kbps\n */\n onVideoSuspendSuggest?: (bandwidth: number) => void;\n /**\n * @internal\n */\n onSignalingMessage?: (message: string | SignalingMessage) => void;\n\n /**\n * Одобрено повышение пользователя в зале ожидания/зале в режиме Audience\n *\n * @param adminParticipantId админ, одобривший повышение\n */\n onPromotionApproved?: (adminParticipantId: ExternalParticipantId) => void;\n /**\n * Участник повышен/разжалован в зале ожидания/зале в режиме Audience\n *\n * @param demoted участник разжалован\n */\n onPromoted?: (demoted: boolean) => void;\n /**\n * Собеседник подключился к сигналлингу\n */\n onPeerRegistered?: () => void;\n};\n\nexport default abstract class Params {\n private static _params: ParamsObject = {\n platform: 'WEB',\n clientStatsPlatform: '',\n clientType: 'PORTAL', // PORTAL, TAMTAM, YOULA, SHOWCASE, GROUP_CALL_WIDGET, VK, MAIL, PARATU\n externalUserType: '',\n device: 'browser',\n\n apiKey: '',\n authToken: '',\n anonymToken: '',\n apiEnv: 'AUTO',\n apiBaseUrl: null,\n domain: '',\n externalDomain: '',\n\n iceServers: [],\n wssBase: '',\n wtsBase: '',\n wssToken: '',\n\n signalingReconnectDelay: 1000,\n signalingReconnectMaxDelay: 5000,\n signalingReconnectMaxCount: 10,\n waitConnectionDelay: 10000,\n waitResponseDelay: 10000,\n waitMessageDelay: 15000,\n\n waitAnotherTabDelay: 200,\n\n debugLog: false,\n debug: false,\n\n apiTimeout: 5000,\n apiMaxAttempt: 10,\n\n forceRelayPolicy: false,\n\n videoMinWidth: 428,\n videoMinHeight: 240,\n videoMaxWidth: 1280,\n videoMaxHeight: 720,\n videoAspectRatio: 16 / 9,\n videoFrameRate: 25,\n screenFrameRate: 15,\n videoFacingMode: null,\n displaySurface: 'monitor',\n\n audioEffects: null,\n videoEffects: null,\n videoEffectMaxWidth: 640,\n videoEffectMaxHeight: 360,\n\n vmoji: null,\n vmojiOptions: null,\n\n iceRestartWaitTime: 20000,\n transportConnectionWaitTime: 5000,\n\n statisticsInterval: 5000,\n networkStatisticsInterval: 20000,\n\n perfStatReportEnabled: true,\n callStatReportEnabled: false,\n clientEventsLoggingEnabled: false,\n enableLogPerfStatReport: false,\n\n voiceParams: {\n smoothing: 0.8, // Значение сглаживания громкости [0..1]\n minFreq: 200, // Минимальная частота голоса в герцах\n maxFreq: 5000, // Максимальная частота голоса в герцах\n interval: 500, // Частота опроса громкости в миллисекундах\n threshold: 0.35, // Уровень при котором считается, что есть голос [0..1]\n speakerLevelMultiplier: 1.8, // Множитель громкости при котором присходит переключение на активного говорящего\n },\n\n specListenerParams: {\n connectionTimeout: 10000,\n volumeTimeout: 10000,\n },\n\n producerNotificationDataChannel: true,\n producerCommandDataChannel: true,\n consumerScreenDataChannel: true,\n producerScreenDataChannel: true,\n asrDataChannel: false,\n\n consumerScreenDataChannelPacketSize: 64 * 1024,\n\n screenShareWebmBuilder: false,\n\n noiseSuppression: true,\n\n preferH264: false,\n preferVP9: false,\n audioNack: true,\n consumerScreenTrack: true,\n producerScreenTrack: true,\n videoTracksCount: 30,\n movieShare: false,\n useCallsToContacts: false,\n useParticipantListChunk: false,\n useRooms: false,\n useChatRooms: false,\n addParticipant: false,\n waitForAdminInGroupCalls: false,\n participantListChunkInitIndex: 0,\n participantListChunkInitCount: null,\n serverAudioRed: true,\n p2pAudioRed: true,\n h264spsPpsIdrInKeyframe: true,\n breakVideoPayloadTypes: false,\n joinFromMultipleDevices: false,\n\n filterObservers: false,\n muteMode: false,\n preserveAudioTracks: false,\n audioShare: false,\n fastScreenShare: false,\n screenShareCongestionControl: false,\n screenShareCongestionControlThreshold: 2_100,\n consumerFastScreenShare: false,\n consumerFastScreenShareQualityOnDemand: false,\n\n fastScreenShareFrameRate: 24,\n fastScreenShareWidth: 1280,\n fastScreenShareHeight: 720,\n newMuteRules: false,\n videoSuspend: false,\n\n enumerateDevicesDelay: 2000,\n switchVideoAtBadNetwork: false,\n enableVideoEffectsFpsDegradation: false,\n simulcast: false,\n webtransport: false,\n webtransportFF: false,\n };\n\n static set(data: { [key: string]: any }) {\n if (Object.hasOwn(data, 'voiceParams')) {\n Object.assign(Params._params.voiceParams, data.voiceParams);\n delete data.voiceParams;\n }\n if (Object.hasOwn(data, 'specListenerParams')) {\n Object.assign(Params._params.specListenerParams, data.specListenerParams);\n delete data.specListenerParams;\n }\n if (Object.hasOwn(data, 'apiAuth')) {\n AuthData.accessToken = data.apiAuth.accessToken;\n AuthData.sessionKey = data.apiAuth.sessionKey;\n AuthData.sessionSecretKey = data.apiAuth.sessionSecretKey;\n }\n\n Object.assign(Params._params, Utils.objectFilterOutValues(data, undefined));\n }\n\n static get<N extends keyof ParamsObject>(name: N): ParamsObject[N] {\n return Params._params[name];\n }\n\n static get appName() {\n return 'ok.calls.sdk.js';\n }\n\n static get appVersion() {\n return 1.1; // FIXME: Возможно тут нужно передавать npm_package_version\n }\n\n static get sdkVersion() {\n // Перезапишется при сборке\n return process.env.npm_package_version as string;\n }\n\n static get debug() {\n return Params._params.debug;\n }\n\n static get protocolVersion() {\n return Params._params.joinFromMultipleDevices ? 6 : 5;\n }\n\n static get platform() {\n return Params._params.platform;\n }\n\n static set platform(value: string) {\n Params._params.platform = value;\n }\n\n static get clientStatsPlatform() {\n return Params._params.clientStatsPlatform;\n }\n\n static set clientStatsPlatform(value: string) {\n Params._params.clientStatsPlatform = value;\n }\n\n static get clientType() {\n return Params._params.clientType;\n }\n\n static set clientType(value: string) {\n Params._params.clientType = value;\n }\n\n static get externalUserType() {\n return Params._params.externalUserType;\n }\n\n static set externalUserType(value: string) {\n Params._params.externalUserType = value;\n }\n\n static get device() {\n return Params._params.device;\n }\n\n static get apiKey() {\n return Params._params.apiKey;\n }\n\n static get apiEnv(): IApiEnv {\n return Params._params.apiEnv;\n }\n\n static get apiBaseUrl(): IAPIBaseUrl {\n return Params._params.apiBaseUrl;\n }\n\n static set apiBaseUrl(apiBaseUrl: IAPIBaseUrl) {\n Params._params.apiBaseUrl = apiBaseUrl;\n }\n\n static apiEndpoint(apiEnv?: IApiEnv): string {\n switch (apiEnv ?? Params.apiEnv) {\n case 'AUTO':\n case 'PROD':\n return 'https://api.mycdn.me';\n case 'CALLS':\n return 'https://calls.okcdn.ru';\n case 'PROD_OK':\n return 'https://api.ok.ru';\n case 'TEST':\n return 'https://apitest.ok.ru/api';\n case 'VIDEOTEST':\n return 'https://videotestapi.ok.ru/api';\n case 'CALLSTEST':\n return 'https://calls-test.okcdn.ru/api';\n case 'CALLS_BETA':\n return 'https://api-beta.calls-test.oneme.ru/api';\n case 'CALLS_BENDER':\n return 'https://api-bender.calls-test.oneme.ru/api';\n case 'CALLS_MAMES':\n return 'https://api-mames.calls-test.oneme.ru/api';\n case 'CALLS_MARS':\n return 'https://api-mars.calls-test.oneme.ru/api';\n default:\n return Params._params.apiEnv;\n }\n }\n\n static get apiTimeout() {\n return Params._params.apiTimeout;\n }\n\n static get apiMaxAttempt() {\n return Params._params.apiMaxAttempt;\n }\n\n static get authToken() {\n return Params._params.authToken;\n }\n\n static set authToken(value: string) {\n Params._params.authToken = value;\n }\n\n static get anonymToken() {\n return Params._params.anonymToken;\n }\n\n static set anonymToken(value: string) {\n Params._params.anonymToken = value;\n }\n\n static get domain() {\n return Params._params.domain;\n }\n\n static get externalDomain() {\n return Params._params.externalDomain;\n }\n\n static get iceServers() {\n return Params._params.iceServers;\n }\n\n static set iceServers(value: IceServer[]) {\n Params._params.iceServers = value;\n }\n\n static get wssBase() {\n return Params._params.wssBase;\n }\n\n static set wssBase(value: string) {\n Params._params.wssBase = value;\n }\n\n static get wtsBase() {\n return Params._params.wtsBase;\n }\n\n static set wtsBase(value: string) {\n Params._params.wtsBase = value;\n }\n\n static get wssToken() {\n return Params._params.wssToken;\n }\n\n static set wssToken(value: string) {\n Params._params.wssToken = value;\n }\n\n static get signalingReconnectDelay() {\n return Params._params.signalingReconnectDelay;\n }\n\n static get signalingReconnectMaxDelay() {\n return Params._params.signalingReconnectMaxDelay;\n }\n\n static get signalingReconnectMaxCount() {\n return Params._params.signalingReconnectMaxCount;\n }\n\n static get waitConnectionDelay() {\n return Params._params.waitConnectionDelay;\n }\n\n static get waitResponseDelay() {\n return Params._params.waitResponseDelay;\n }\n\n static get waitMessageDelay() {\n return Params._params.waitMessageDelay;\n }\n\n static get waitAnotherTabDelay() {\n return Params._params.waitAnotherTabDelay;\n }\n\n static get debugLog() {\n return Params._params.debugLog;\n }\n\n static get forceRelayPolicy() {\n return Params._params.forceRelayPolicy;\n }\n\n static set forceRelayPolicy(value: boolean) {\n Params._params.forceRelayPolicy = value;\n }\n\n static get videoMinWidth() {\n return Params._params.videoMinWidth;\n }\n\n static get videoMaxWidth() {\n return Params._params.videoMaxWidth;\n }\n\n static set videoMaxWidth(value: number) {\n Params._params.videoMaxWidth = value;\n }\n\n static get videoMinHeight() {\n return Params._params.videoMinHeight;\n }\n\n static get videoMaxHeight() {\n return Params._params.videoMaxHeight;\n }\n\n static set videoMaxHeight(value: number) {\n Params._params.videoMaxHeight = value;\n }\n\n static get videoAspectRatio() {\n return Params._params.videoAspectRatio;\n }\n\n static get videoFrameRate() {\n return Params._params.videoFrameRate;\n }\n\n static get videoFacingMode() {\n return Params._params.videoFacingMode || (WebRTCUtils.isMobile() ? FacingMode.USER : null);\n }\n\n static set videoFacingMode(value: FacingMode | null) {\n Params._params.videoFacingMode = value;\n }\n\n static get displaySurface() {\n return Params._params.displaySurface;\n }\n\n static get audioEffects() {\n return Params._params.audioEffects;\n }\n\n static set audioEffects(value: EffectVoiceChange | null) {\n Params._params.audioEffects = value;\n Params._params.audioEffects?.setLogger((type: DebugMessageType, ...args: any[]) => Debug.send(type, ...args));\n }\n\n static get videoEffects() {\n return Params._params.videoEffects;\n }\n\n static set videoEffects(value: VideoEffects | null) {\n Params._params.videoEffects = value;\n Params._params.videoEffects?.setLogger((type: DebugMessageType, ...args: any[]) => Debug.send(type, ...args));\n }\n\n static get videoEffectMaxWidth() {\n return Params._params.videoEffectMaxWidth;\n }\n\n static set videoEffectMaxWidth(value: number) {\n Params._params.videoEffectMaxWidth = value;\n }\n\n static get videoEffectMaxHeight() {\n return Params._params.videoEffectMaxHeight;\n }\n\n static set videoEffectMaxHeight(value: number) {\n Params._params.videoEffectMaxHeight = value;\n }\n\n static get vmoji() {\n if (!Params._params.vmoji?.isBrowserSupported()) {\n return null;\n }\n return Params._params.vmoji;\n }\n\n static set vmoji(value: typeof Vmoji | null) {\n Params._params.vmoji = value;\n }\n\n static get vmojiOptions(): NonNullable<ParamsObject['vmojiOptions']> {\n return Params._params.vmojiOptions || { protocolVersion: 1, renderingOptions: {} };\n }\n\n static set vmojiOptions(value: ParamsObject['vmojiOptions']) {\n Params._params.vmojiOptions = value;\n }\n\n static get voiceParams() {\n return Params._params.voiceParams;\n }\n\n static get specListenerParams() {\n return Params._params.specListenerParams;\n }\n\n static get iceRestartWaitTime() {\n return Params._params.iceRestartWaitTime;\n }\n\n static get transportConnectionWaitTime() {\n return Params._params.transportConnectionWaitTime;\n }\n\n static get statisticsInterval() {\n return Params._params.statisticsInterval;\n }\n\n static set statisticsInterval(value: number) {\n Params._params.statisticsInterval = value;\n }\n\n static get networkStatisticsInterval() {\n return Params._params.networkStatisticsInterval;\n }\n\n static get perfStatReportEnabled() {\n return Params._params.perfStatReportEnabled;\n }\n\n static get callStatReportEnabled() {\n return Params._params.callStatReportEnabled;\n }\n\n static get clientEventsLoggingEnabled() {\n return Params._params.clientEventsLoggingEnabled;\n }\n\n static get enableLogPerfStatReport() {\n return Params._params.enableLogPerfStatReport;\n }\n\n static get producerNotificationDataChannel() {\n return Params._params.producerNotificationDataChannel;\n }\n\n static get producerCommandDataChannel() {\n return Params._params.producerCommandDataChannel;\n }\n\n static get consumerScreenDataChannel() {\n return Params._params.consumerScreenDataChannel && ScreenCaptureSender.isBrowserSupported(); // Не используем дата-канал для скриншаринга, если браузер не умеет\n }\n\n static get producerScreenDataChannel() {\n // Для работы нужен producerNotificationDataChannel\n return Params._params.producerScreenDataChannel && Params.producerNotificationDataChannel && ScreenCaptureReceiver.isBrowserSupported(); // Не используем дата-канал для скриншаринга, если браузер не умеет\n }\n\n static get asrDataChannel() {\n return Params._params.asrDataChannel && Params.producerNotificationDataChannel;\n }\n\n static get consumerScreenDataChannelPacketSize() {\n return Params._params.consumerScreenDataChannelPacketSize;\n }\n\n static get screenShareWebmBuilder() {\n return Params._params.screenShareWebmBuilder;\n }\n\n static get noiseSuppression() {\n return Params._params.noiseSuppression;\n }\n\n static set noiseSuppression(value: boolean) {\n Params._params.noiseSuppression = value;\n }\n\n static get preferH264() {\n return Params._params.preferH264;\n }\n\n static get preferVP9() {\n return Params._params.preferVP9;\n }\n\n static get audioNack() {\n return Params._params.audioNack;\n }\n\n static get consumerScreenTrack() {\n // Для работы нужен consumerScreenDataChannel\n return Params._params.consumerScreenTrack && Params.consumerScreenDataChannel;\n }\n\n static get producerScreenTrack() {\n return Params._params.producerScreenTrack;\n }\n\n static get movieShare() {\n return Params._params.movieShare && Params.videoTracksCount > 0;\n }\n\n static get videoTracksCount() {\n return Params.producerNotificationDataChannel ? Number(Params._params.videoTracksCount) : 0;\n }\n\n static get breakVideoPayloadTypes() {\n return Params._params.breakVideoPayloadTypes;\n }\n\n static get useCallsToContacts() {\n return Params._params.useCallsToContacts;\n }\n\n static get useParticipantListChunk() {\n return Params._params.useParticipantListChunk && Params.videoTracksCount > 0;\n }\n\n static get useRooms() {\n return Params._params.useRooms;\n }\n\n static get useChatRooms() {\n return Params._params.useChatRooms;\n }\n\n static get addParticipant() {\n return Params._params.addParticipant;\n }\n\n static get waitForAdminInGroupCalls() {\n return Params._params.waitForAdminInGroupCalls;\n }\n\n static get participantListChunkInitIndex() {\n return Params._params.participantListChunkInitIndex ?? 0;\n }\n\n static get participantListChunkInitCount() {\n return Params._params.participantListChunkInitCount ?? null;\n }\n\n static get serverAudioRed() {\n return Params._params.serverAudioRed;\n }\n\n static get p2pAudioRed() {\n return Params._params.p2pAudioRed;\n }\n\n static get h264spsPpsIdrInKeyframe() {\n return Params._params.h264spsPpsIdrInKeyframe;\n }\n\n static get filterObservers() {\n return Params._params.filterObservers;\n }\n\n static get muteMode() {\n return Params._params.muteMode;\n }\n\n static get preserveAudioTracks() {\n return Params._params.preserveAudioTracks;\n }\n\n static get audioShare() {\n return WebRTCUtils.isAudioShareSupported() && Params._params.audioShare;\n }\n\n static get fastScreenShare() {\n return Params._params.fastScreenShare;\n }\n\n static get screenShareCongestionControl() {\n return Params._params.screenShareCongestionControl;\n }\n\n static get screenShareCongestionControlThreshold() {\n return Params._params.screenShareCongestionControlThreshold;\n }\n\n static get fastScreenShareWidth() {\n return Params._params.fastScreenShareWidth;\n }\n\n static get fastScreenShareHeight() {\n return Params._params.fastScreenShareHeight;\n }\n\n static get consumerFastScreenShare() {\n return Params._params.consumerFastScreenShare;\n }\n\n static get consumerFastScreenShareQualityOnDemand() {\n return Params._params.consumerFastScreenShareQualityOnDemand;\n }\n\n static get newMuteRules() {\n return Params._params.newMuteRules;\n }\n\n static get videoSuspend() {\n return Params._params.videoSuspend;\n }\n\n static get enumerateDevicesDelay() {\n return Params._params.enumerateDevicesDelay;\n }\n\n static getScreenFrameRate(fastScreenShare: boolean): number {\n return fastScreenShare ? Params._params.fastScreenShareFrameRate : Params._params.screenFrameRate;\n }\n\n static get switchVideoAtBadNetwork() {\n return Params._params.switchVideoAtBadNetwork;\n }\n\n static get enableVideoEffectsFpsDegradation() {\n return Params._params.enableVideoEffectsFpsDegradation;\n }\n\n static get simulcast() {\n return Params._params.simulcast;\n }\n\n static set simulcast(value: boolean) {\n Params._params.simulcast = value;\n }\n\n static get webtransport() {\n return Params._params.webtransport;\n }\n\n static set webtransport(value: boolean) {\n Params._params.webtransport = value;\n }\n\n static get webtransportFF() {\n return Params._params.webtransportFF;\n }\n\n static set webtransportFF(value: boolean) {\n Params._params.webtransportFF = value;\n }\n\n static toJSON() {\n return {\n apiKey: Params._params.apiKey,\n apiEnv: Params._params.apiEnv,\n audioShare: Params._params.audioShare,\n useCallsToContacts: Params._params.useCallsToContacts,\n useParticipantListChunk: Params._params.useParticipantListChunk,\n useRooms: Params._params.useRooms,\n useChatRooms: Params._params.useChatRooms,\n addParticipant: Params._params.addParticipant,\n fastScreenShare: Params._params.fastScreenShare,\n participantListChunkInitCount: Params._params.participantListChunkInitCount,\n screenShareCongestionControl: Params._params.screenShareCongestionControl,\n screenShareCongestionControlThreshold: Params._params.screenShareCongestionControlThreshold,\n videoTracksCount: Params._params.videoTracksCount,\n asrDataChannel: Params._params.asrDataChannel,\n videoMaxHeight: Params._params.videoMaxHeight,\n videoMaxWidth: Params._params.videoMaxWidth,\n videoEffectMaxHeight: Params._params.videoEffectMaxHeight,\n videoEffectMaxWidth: Params._params.videoEffectMaxWidth,\n videoSuspend: Params._params.videoSuspend,\n debugLog: Params._params.debugLog,\n callStatReportEnabled: Params._params.callStatReportEnabled,\n joinFromMultipleDevices: Params._params.joinFromMultipleDevices,\n movieShare: Params._params.movieShare,\n newMuteRules: Params._params.newMuteRules,\n clientType: Params._params.clientType,\n clientStatsPlatform: Params._params.clientStatsPlatform,\n consumerScreenDataChannelPacketSize: Params._params.consumerScreenDataChannelPacketSize,\n switchVideoAtBadNetwork: Params._params.switchVideoAtBadNetwork,\n simulcast: Params._params.simulcast,\n webtransport: Params._params.webtransport,\n webtransportFF: Params._params.webtransportFF,\n };\n }\n}\n", "/**\n * Информация о текущих медиа настройках пользователя\n */\nexport type MediaSettings = {\n /**\n * Включен ли микрофон\n */\n isAudioEnabled: boolean;\n /**\n * Включена ли камера\n */\n isVideoEnabled: boolean;\n /**\n * Включена ли трансляция экрана\n */\n isScreenSharingEnabled: boolean;\n /**\n * Режим динамического контента при трансляция экрана (быстрая шара)\n */\n isFastScreenSharingEnabled: boolean;\n /**\n * Включена ли трансляция звука\n */\n isAudioSharingEnabled: boolean;\n /**\n * Включена ли трансляция вимоджи\n */\n isAnimojiEnabled: boolean;\n};\n\nexport default MediaSettings;\n\nexport function compareMediaSettings(ms1: MediaSettings, ms2: MediaSettings) {\n if (ms1.isAudioEnabled !== ms2.isAudioEnabled) {\n return false;\n }\n if (ms1.isVideoEnabled !== ms2.isVideoEnabled) {\n return false;\n }\n if (ms1.isScreenSharingEnabled !== ms2.isScreenSharingEnabled) {\n return false;\n }\n if (ms1.isFastScreenSharingEnabled !== ms2.isFastScreenSharingEnabled) {\n return false;\n }\n if (ms1.isAudioSharingEnabled !== ms2.isAudioSharingEnabled) {\n return false;\n }\n if (ms1.isAnimojiEnabled !== ms2.isAnimojiEnabled) {\n return false;\n }\n return true;\n}\n\nexport function createMediaSettingsWithDefaults(ms?: Partial<MediaSettings>): MediaSettings {\n return Object.assign(\n {\n isAudioEnabled: false,\n isVideoEnabled: false,\n isScreenSharingEnabled: false,\n isFastScreenSharingEnabled: false,\n isAudioSharingEnabled: false,\n isAnimojiEnabled: false,\n },\n ms || {},\n );\n}\n\n/**\n * Размеры видео\n */\nexport interface IVideoDimentions {\n width: number;\n height: number;\n}\n", "import Debug from '../static/Debug';\n\nexport const stopMediaStreamTrack = (track: MediaStreamTrack) => track.stop();\nexport const stopMediaStreamTracks = (stream: MediaStream) => stream.getTracks().forEach(stopMediaStreamTrack);\nexport const stopMediaStreamVideoTracks = (stream: MediaStream) => stream.getVideoTracks().forEach(stopMediaStreamTrack);\nexport const cloneVideoTrack = (stream: MediaStream) => stream.getVideoTracks()[0].clone();\nexport async function setVideoConstraints(track: MediaStreamTrack, constraints: MediaTrackConstraints): Promise<void> {\n try {\n const width = typeof constraints.width === 'number' ? constraints.width : undefined;\n const height = typeof constraints.height === 'number' ? constraints.height : undefined;\n await track.applyConstraints({\n ...constraints,\n ...(width && { width: { max: width, ideal: width } }),\n ...(height && { height: { max: height, ideal: height } }),\n });\n } catch (e) {\n Debug.warn('setVideoConstraints failed', e);\n }\n}\n", "import type { VideoEffects } from '@vkontakte/calls-video-effects';\nimport Debug from '../static/Debug';\nimport Params from '../static/Params';\nimport EventEmitter from './EventEmitter';\n\nexport enum VideoEffectsFpsLimiterEvent {\n FpsLimit = 'fps-limit',\n}\n\nexport class VideoEffectsFpsLimiter extends EventEmitter {\n // при 13 фпс еще более менее выглядит\n private readonly FPS_LIMITS = [13, 20, Math.max(Params.videoFrameRate, 25)] as const;\n private readonly THRESHOLD = 0.8; // 80%\n private readonly HISTORY_LENGTH = 10; // длина замера\n\n private _fpsMeterUnsubscribe: VoidFunction | null = null;\n private readonly _fpsHistory = {\n cursor: 0,\n arr: [] as number[],\n };\n private _fpsLimitCursor = this.FPS_LIMITS.length - 1;\n\n get fpsLimit() {\n return this.FPS_LIMITS[this._fpsLimitCursor];\n }\n\n watch(videoEffect: VideoEffects | null) {\n this._cleanup();\n try {\n if (videoEffect) {\n this._assertsVideoEffect(videoEffect);\n this._fpsMeterUnsubscribe = videoEffect.addFpsMeterListener(this._handleFpsMeter.bind(this));\n }\n } catch (e) {\n Debug.warn('VideoEffectsFpsLimiter error', e);\n }\n }\n\n private _handleFpsMeter(fps: number) {\n this._fpsHistory.arr[this._fpsHistory.cursor] = fps;\n this._fpsHistory.cursor = (this._fpsHistory.cursor + 1) % this.HISTORY_LENGTH;\n // пока только вниз опускаем, тк врятли компьютер начнет работать быстрее\n if (this._fpsHistory.arr.length === this.HISTORY_LENGTH && this._fpsLimitCursor) {\n const average = this._fpsHistory.arr.reduce((acc, fpsValue) => acc + fpsValue, 0) / this.HISTORY_LENGTH;\n const limit = this.FPS_LIMITS[this._fpsLimitCursor];\n if (average < limit * this.THRESHOLD) {\n this._fpsLimitCursor = Math.max(0, this._fpsLimitCursor - 1);\n }\n if (limit !== this.fpsLimit) {\n this._triggerEvent(VideoEffectsFpsLimiterEvent.FpsLimit, this.fpsLimit);\n }\n }\n }\n\n /** для совместимости со старыми версиями, где может не быть метода */\n private _assertsVideoEffect(videoEffect: VideoEffects): asserts videoEffect is VideoEffects {\n if (!('addFpsMeterListener' in videoEffect)) {\n throw new Error('Outdated VideoEffect version');\n }\n }\n\n override addEventListener(event: VideoEffectsFpsLimiterEvent, fn: (fpsLimit: number) => void): { dispose: Function } {\n return super.addEventListener(event, fn);\n }\n\n private _cleanup() {\n this._fpsMeterUnsubscribe?.();\n this._fpsMeterUnsubscribe = null;\n }\n\n destroy() {\n this._cleanup();\n super.unsubscribe();\n }\n}\n", "import type { IEffect } from '@vkontakte/calls-video-effects';\nimport EventEmitter from '../classes/EventEmitter';\nimport FatalError from '../enums/FatalError';\nimport MediaOption from '../enums/MediaOption';\nimport StatLog from '../enums/StatLog';\nimport Debug from '../static/Debug';\nimport Params from '../static/Params';\nimport WebRTCUtils, { IDeviceChangeOldDevices } from '../static/WebRTCUtils';\nimport MediaSettings, { createMediaSettingsWithDefaults, IVideoDimentions } from '../types/MediaSettings';\nimport { ScreenCaptureSettings } from '../types/ScreenCaptureSettings';\nimport { setVideoConstraints, stopMediaStreamTracks, stopMediaStreamVideoTracks } from '../utils/Media';\nimport Utils from '../static/Utils';\nimport HangupReason from './HangupReason';\nimport Logger from './Logger';\nimport { VideoEffectsFpsLimiter, VideoEffectsFpsLimiterEvent } from './VideoEffectsFpsLimiter';\n\nexport const enum MediaSourceEvent {\n SOURCE_CHANGED = 'SOURCE_CHANGED',\n SOURCE_READY = 'SOURCE_READY',\n TRACK_REPLACED = 'TRACK_REPLACED',\n SCREEN_STATUS = 'SCREEN_STATUS',\n ANIMOJI_STATUS = 'ANIMOJI_STATUS',\n}\n\n/**\n * Тип трека\n */\nexport const enum MediaTrackKind {\n 'audio' = 'audio',\n 'video' = 'video',\n 'screen' = 'screen',\n 'audioshare' = 'audioshare',\n}\n\ninterface AudioEffectParams {\n effects: string[];\n isPreset?: boolean;\n}\n\n/**\n * тип источника (для сервера)\n */\nexport enum MediaSourceType {\n CAMERA = 1,\n SCREEN = 2,\n}\n\nexport class MediaSource extends EventEmitter {\n /** Стрим с камеры и микрофона пользователя */\n protected _stream: MediaStream | null = null;\n private _screenTrack: MediaStreamTrack | null = null;\n private _audioShareTrack: MediaStreamTrack | null = null;\n private _screenShareTrack: MediaStreamTrack | null = null;\n /** Трек для отправки в медиа-канал. Может отличаться при скриншаринге в дата-канал */\n private _sendVideoTrack: MediaStreamTrack | null = null;\n /** Трек с камеры. В стриме будет другой трек при включенных видео эффектах */\n private _cameraVideoTrack: MediaStreamTrack | null = null;\n /** Трек с микрофона. В стриме будет другой трек при включенных аудио эффектах */\n private _micAudioTrack: MediaStreamTrack | null = null;\n /** Трек аудио эффектов. Не изменяется на протяжении всего времени */\n private _audioEffectsTrack: MediaStreamTrack | null = null;\n private _mediaSettings: MediaSettings = createMediaSettingsWithDefaults();\n private _videoStatusOnScreenCapturingEnabled = false;\n private _effect: IEffect | null = null;\n private _audioEffectParams: AudioEffectParams | null = null;\n private _onDeviceChange: CallableFunction;\n /** Состояние выключателя Animoji в UI */\n private _animojiEnabled = false;\n /** вычисляем низкую производительность видео эффектов */\n private readonly _videoEffectsFpsLimiter?: VideoEffectsFpsLimiter;\n\n constructor() {\n super();\n this._initDeviceChangeListener();\n if (Params.audioShare) {\n this._audioShareTrack = this.getSilentAudioShareTrack();\n }\n if (Params.enableVideoEffectsFpsDegradation) {\n this._videoEffectsFpsLimiter = new VideoEffectsFpsLimiter();\n this._videoEffectsFpsLimiter.addEventListener(VideoEffectsFpsLimiterEvent.FpsLimit, this.handleVideoEffectsLowFps.bind(this));\n }\n }\n\n get cameraVideoTrack() {\n return this._cameraVideoTrack;\n }\n\n set cameraVideoTrack(track: MediaStreamTrack | null) {\n if (this._cameraVideoTrack) {\n this._cameraVideoTrack.removeEventListener('mute', this.videoTrackMuteHandler);\n }\n\n this._cameraVideoTrack = track;\n\n if (this._cameraVideoTrack) {\n // safari при первом запросе видео трека иногда принудительно переводит его в состояние mute\n this._cameraVideoTrack.addEventListener('mute', this.videoTrackMuteHandler);\n }\n if (Params.consumerFastScreenShare) {\n this._screenShareTrack = this.getBlackScreenShareTrack();\n }\n }\n\n async request(mediaOptions = [MediaOption.AUDIO], needEmptyTracks = true): Promise<void> {\n if (this._stream) {\n return;\n }\n\n const needVideo = mediaOptions.includes(MediaOption.VIDEO);\n const needAudio = mediaOptions.includes(MediaOption.AUDIO);\n const needAnimoji = mediaOptions.includes(MediaOption.ANIMOJI);\n\n if (!WebRTCUtils.isBrowserSupported()) {\n throw new HangupReason(FatalError.UNSUPPORTED);\n }\n\n try {\n this._stream = await WebRTCUtils.getUserMedia(needVideo, needAudio, needEmptyTracks);\n this.cameraVideoTrack?.stop();\n this.cameraVideoTrack = this._stream.getVideoTracks()[0];\n this._micAudioTrack?.stop();\n this._micAudioTrack = this._stream.getAudioTracks()[0];\n this._audioEffectsTrack?.stop();\n this._mediaSettings.isVideoEnabled = (needVideo && this._stream.getVideoTracks().filter((track) => track.enabled).length > 0) || false;\n this._mediaSettings.isAudioEnabled = (needAudio && this._stream.getAudioTracks().filter((track) => track.enabled).length > 0) || false;\n this._mediaSettings.isAnimojiEnabled = (needAnimoji && !this._mediaSettings.isVideoEnabled) || false;\n this._animojiEnabled = needAnimoji; // Записываем начальное состояние выключателя вимоджи\n this._triggerEvent(MediaSourceEvent.SOURCE_READY);\n } catch (error: any) {\n throw new HangupReason(error);\n }\n }\n\n getStream(): MediaStream | null {\n return this._stream;\n }\n\n getScreenTrack(): MediaStreamTrack | null {\n return this._screenTrack;\n }\n\n getSendVideoTrack(noDataChannel = false): MediaStreamTrack | null {\n if (this._sendVideoTrack && !noDataChannel) {\n return this._sendVideoTrack;\n }\n\n if (!this._stream) {\n return null;\n }\n\n return this._stream.getVideoTracks()[0];\n }\n\n getSendAudioTrack(): MediaStreamTrack | null {\n const track = this._stream?.getAudioTracks().find((audio) => !audio.contentHint);\n return track || null;\n }\n\n get isAnimojiRequested(): boolean {\n return this._animojiEnabled && !this._mediaSettings.isVideoEnabled;\n }\n\n addTrackToPeerConnection(pc: RTCPeerConnection, observer: boolean, noDataChannel: boolean): void {\n const stream = this.getStream();\n const audio = this.getSendAudioTrack();\n const video = this.getSendVideoTrack(noDataChannel);\n\n if (!stream || (!audio && !video && !observer)) {\n throw new Error('No local stream found');\n }\n\n if (audio && !observer) {\n pc.addTrack(audio, stream);\n }\n\n if (video && !observer) {\n pc.addTrack(video, stream);\n }\n }\n\n getMediaSettings(): MediaSettings {\n return this._mediaSettings;\n }\n\n async changeDevice(kind: MediaDeviceKind): Promise<void> {\n switch (kind) {\n case 'videoinput':\n if (this._mediaSettings.isVideoEnabled) {\n return this._changeVideoInput();\n }\n break;\n case 'audioinput':\n if (this._mediaSettings.isAudioEnabled) {\n return this._changeAudioInput();\n }\n break;\n default:\n return Promise.reject(FatalError.UNKNOWN);\n }\n }\n\n /**\n * Освобождает все видео треки, полученные с камеры\n * На некоторых мобилках без этого нельзя переключить камеру\n * @internal\n */\n stopVideoTrack() {\n if (!this._mediaSettings.isVideoEnabled) {\n return;\n }\n this._stopEffect();\n if (this._stream) {\n stopMediaStreamVideoTracks(this._stream);\n }\n this.cameraVideoTrack?.stop();\n }\n\n /**\n * Установка кастомного стрима для видео, например внешний шаринг экрана\n * или стрим из canvas\n * Нужно для работы в electron, там устройства шаринга отдают сразу стрим\n * @hidden\n */\n async setVideoStream(stream: MediaStream, isScreen: boolean): Promise<void> {\n if (isScreen) {\n return this._changeScreen(false, false, stream);\n }\n return this._changeVideoInput(stream);\n }\n\n private _initDeviceChangeListener() {\n if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices || !navigator.mediaDevices.addEventListener) {\n return;\n }\n\n this._onDeviceChange = async (from: IDeviceChangeOldDevices) => {\n if (!this._stream) {\n return;\n }\n\n // NB: На маке есть устройства с deviceId: default. При подключении наушников/камеры, deviceId не меняется, но меняется groupId.\n // Здесь сохраненные устройства уже обновились с новым groupId после подключения наушников/камеры.\n const currentMic = WebRTCUtils.getSavedMicrophone();\n const currentCam = WebRTCUtils.getSavedCamera();\n\n const currentAudioLost = this._mediaSettings.isAudioEnabled && currentMic?.groupId !== from.microphone?.groupId;\n const currentVideoLost = this._mediaSettings.isVideoEnabled && currentCam?.groupId !== from.camera?.groupId;\n\n try {\n if (currentAudioLost) {\n await this._changeAudioInput();\n }\n if (currentVideoLost) {\n await this._changeVideoInput();\n }\n } catch (e) {}\n };\n\n WebRTCUtils.addEventListener('devicechange', this._onDeviceChange);\n }\n\n private _destroyDeviceChangeListener() {\n if (this._onDeviceChange) {\n WebRTCUtils.removeEventListener('devicechange', this._onDeviceChange);\n }\n }\n\n private async _changeVideoInput(stream?: MediaStream): Promise<void> {\n try {\n const logData = stream ? 'stream' : 'video';\n const currStream = stream || (await WebRTCUtils._getUserVideo(!!this._effect, this._frameRate));\n this.cameraVideoTrack?.stop();\n this.cameraVideoTrack = currStream.getVideoTracks()[0];\n\n if (!this._stream) {\n // Если стрима нет, значит разрешение выдали когда звонок уже закончился\n stopMediaStreamTracks(currStream);\n } else {\n if (!Params.consumerScreenTrack) {\n await this._disableScreenCapture();\n }\n const newTrack = await this._setEffect(this._effect, this.cameraVideoTrack);\n Logger.log(StatLog.DEVICE_CHANGED, logData);\n Debug.log('Video stream changed');\n await this._replaceLocalTrack(newTrack);\n this._mediaSettings.isVideoEnabled = true;\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.video });\n }\n } catch (e) {\n Logger.log(StatLog.ERROR, 'change_video');\n Debug.warn('Camera change failed', e);\n throw e;\n }\n }\n\n /**\n * Установка кастомного стрима для аудио, например аудио-трек вместо звука с микрофона.\n * Может использоваться для тестирования.\n */\n async setAudioStream(stream: MediaStream): Promise<void> {\n return this._changeAudioInput(stream);\n }\n\n private async _changeAudioInput(stream: MediaStream | null = null): Promise<void> {\n try {\n const currStream = stream || (await WebRTCUtils.getUserAudio());\n this._micAudioTrack?.stop();\n this._micAudioTrack = currStream.getAudioTracks()[0];\n if (!this._stream) {\n // Если стрима нет, значит разрешение выдали когда звонок уже закончился\n stopMediaStreamTracks(currStream);\n } else {\n const newTrack = (await this._applyAudioEffect()) as MediaStreamTrack;\n Logger.log(StatLog.DEVICE_CHANGED, 'audio');\n Debug.log('Audio stream changed', newTrack);\n await this._replaceLocalTrack(newTrack);\n this._mediaSettings.isAudioEnabled = true;\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.audio });\n }\n } catch (e) {\n Logger.log(StatLog.ERROR, 'change_audio');\n Debug.error('Microphone change failed', e);\n throw e;\n }\n }\n\n private async _changeScreen(fastScreenShare: boolean, audioShare: boolean, stream?: MediaStream): Promise<void> {\n try {\n stream = stream || (await WebRTCUtils.getScreenMedia(fastScreenShare, audioShare));\n\n if (!this._stream) {\n // Если стрима нет, значит разрешение выдали когда звонок уже закончился\n stopMediaStreamTracks(stream);\n } else {\n const newTrack = stream.getVideoTracks()[0];\n\n // NB: Лучше использовать MediaStream inactive event, но FF не умеет\n newTrack.addEventListener(\n 'ended',\n () => {\n // Выключаем трансляцию только если это системный вызов (завершили из браузерного окна)\n if (this._mediaSettings.isScreenSharingEnabled) {\n this.disableScreenCapturing();\n }\n },\n false,\n );\n\n if (!Params.consumerScreenTrack) {\n // тк экземпляр эффектов всего 1, не выключаем при шаринге на дата канале\n this._stopEffect();\n }\n Logger.log(StatLog.DEVICE_CHANGED, 'screen');\n Debug.log('Screen capturing started');\n\n this._screenTrack = newTrack;\n this._mediaSettings.isScreenSharingEnabled = true;\n this._mediaSettings.isFastScreenSharingEnabled = fastScreenShare;\n\n if (!Params.consumerScreenTrack) {\n this._videoStatusOnScreenCapturingEnabled = this._mediaSettings.isVideoEnabled;\n this._mediaSettings.isVideoEnabled = true;\n // Если работаем с дата-каналом, используем пустой трек для отправки\n this._sendVideoTrack = Params.consumerScreenDataChannel ? WebRTCUtils.getBlackMediaTrack(Params.videoMinWidth, Params.videoMinHeight) : newTrack;\n await this._replaceLocalTrack(newTrack, this._sendVideoTrack);\n }\n\n if (Params.consumerFastScreenShare && this._mediaSettings.isFastScreenSharingEnabled) {\n newTrack.contentHint = 'motion';\n this._screenShareTrack = newTrack;\n }\n\n if (stream.getAudioTracks().length > 0) {\n const _audioShareTrack = stream.getAudioTracks()[0];\n _audioShareTrack.contentHint = 'music';\n this._audioShareTrack = _audioShareTrack;\n await this._replaceLocalTrack(_audioShareTrack);\n\n this._mediaSettings.isAudioSharingEnabled = true;\n }\n\n if (audioShare && !this._mediaSettings.isAudioSharingEnabled) {\n Debug.debug('Audio share requested but not captured');\n }\n\n this._triggerEvent(MediaSourceEvent.SCREEN_STATUS, { track: newTrack });\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.screen });\n }\n } catch (e) {\n Logger.log(StatLog.ERROR, 'screen');\n Debug.warn('Screen capturing failed', e);\n throw e;\n }\n }\n\n private async _disableScreenCapture() {\n if (this._sendVideoTrack) {\n this._sendVideoTrack.stop();\n this._sendVideoTrack = null;\n }\n if (this._screenTrack) {\n this._screenTrack.stop();\n this._screenTrack = null;\n }\n if (this._screenShareTrack) {\n this._screenShareTrack.stop();\n this._screenShareTrack = this.getBlackScreenShareTrack();\n }\n await this.stopAudioShareTrack();\n\n if (this._mediaSettings.isScreenSharingEnabled) {\n this._mediaSettings.isScreenSharingEnabled = false;\n this._mediaSettings.isFastScreenSharingEnabled = false;\n this._triggerEvent(MediaSourceEvent.SCREEN_STATUS, { track: null });\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.screen });\n }\n }\n\n // оставлено для совместимости Params.consumerScreenTrack === false\n private async disableAudioShare() {\n await this.stopAudioShareTrack();\n this._triggerEvent(MediaSourceEvent.SCREEN_STATUS, { track: null });\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.audioshare });\n }\n\n private async stopAudioShareTrack() {\n if (this._audioShareTrack) {\n this._audioShareTrack.stop();\n const newTrack = this.getSilentAudioShareTrack();\n await this._replaceLocalTrack(newTrack);\n this._mediaSettings.isAudioSharingEnabled = false;\n }\n }\n\n private async _applyAudioEffect() {\n if (!Params.audioEffects || !this._audioEffectParams) {\n Params.audioEffects?.pause();\n return this._micAudioTrack;\n }\n\n if (!Params.audioEffects.isInitialized) {\n await Params.audioEffects.init();\n }\n\n Params.audioEffects.resume();\n // @ts-expect-error wrong types\n Params.audioEffects.setEffects(this._audioEffectParams.effects, this._audioEffectParams.isPreset);\n Params.audioEffects.setSource(this._micAudioTrack);\n const audioEffectsTrack = (Params.audioEffects.outputStream as MediaStream).getAudioTracks()[0];\n if (!this._audioEffectsTrack || this._audioEffectsTrack.id !== audioEffectsTrack.id) {\n this._audioEffectsTrack = audioEffectsTrack;\n }\n return this._audioEffectsTrack;\n }\n\n protected getSilentAudioShareTrack() {\n const newTrack = WebRTCUtils.getSilentMediaTrack();\n newTrack.contentHint = 'music';\n newTrack.stop();\n return newTrack;\n }\n\n protected getBlackScreenShareTrack() {\n const newTrack = WebRTCUtils.getBlackMediaTrack();\n newTrack.contentHint = 'motion';\n newTrack.stop();\n return newTrack;\n }\n\n protected async _replaceLocalTrack(newTrack: MediaStreamTrack, sendTrack?: MediaStreamTrack) {\n if (!this._stream) {\n return;\n }\n\n const oldTrack = this._stream.getTracks().find((track) => track.kind === newTrack.kind && track.contentHint === newTrack.contentHint);\n\n // Если исходящий трек не изменился - ничего не делаем\n if (oldTrack?.id === newTrack.id) {\n return;\n }\n\n if (oldTrack) {\n // Не останавливаем трек аудио эффектов, потому что он остается неизменным все время\n if (oldTrack !== this._audioEffectsTrack) {\n oldTrack.stop();\n }\n this._stream?.removeTrack(oldTrack);\n this._stream?.addTrack(newTrack);\n this._triggerEvent(MediaSourceEvent.TRACK_REPLACED, newTrack, sendTrack);\n } else {\n // Если трека не было, добавим - это аудиошара\n this._stream.addTrack(newTrack);\n this._triggerEvent(MediaSourceEvent.TRACK_REPLACED, newTrack, sendTrack);\n }\n }\n\n private async _setEffect(effect: IEffect | null, track: MediaStreamTrack): Promise<MediaStreamTrack> {\n this._videoEffectsFpsLimiter?.watch(Params.videoEffects);\n\n if (!Params.videoEffects) {\n return track;\n }\n try {\n return Params.videoEffects.setEffect(effect, track);\n } catch (e) {\n Debug.warn('Video effect failed', e);\n return track;\n }\n }\n\n private _stopEffect() {\n if (!Params.videoEffects) {\n return;\n }\n try {\n Params.videoEffects.stopEffect();\n } catch (e) {\n Debug.warn('Video effect failed', e);\n }\n }\n\n destroy(): void {\n this._destroyDeviceChangeListener();\n if (Params.videoEffects) {\n this._effect = null;\n Params.videoEffects.destroy();\n }\n if (Params.audioEffects) {\n Params.audioEffects.destroy();\n }\n if (this._stream) {\n stopMediaStreamTracks(this._stream);\n this._stream = null;\n }\n this.cameraVideoTrack?.stop();\n this._micAudioTrack?.stop();\n this._audioEffectsTrack?.stop();\n this._disableScreenCapture();\n\n const audioContext = WebRTCUtils.getAudioContext();\n audioContext?.suspend().catch((e) => Debug.error(e));\n this._videoEffectsFpsLimiter?.destroy();\n }\n\n async toggleScreenCapturing(settings: ScreenCaptureSettings) {\n if (settings.captureScreen) {\n await this._changeScreen(settings.fastScreenSharing, settings.captureAudio);\n return;\n }\n if (Params.consumerScreenTrack) {\n return this._disableScreenCapture();\n }\n if (!settings.captureAudio) {\n await this.disableAudioShare();\n }\n if (this._videoStatusOnScreenCapturingEnabled) {\n return this._changeVideoInput();\n }\n return this.toggleVideo(false);\n }\n\n async disableScreenCapturing() {\n return this.toggleScreenCapturing({\n captureScreen: false,\n fastScreenSharing: false,\n captureAudio: false,\n });\n }\n\n private videoTrackMuteHandler = () => {\n if (this._mediaSettings.isVideoEnabled) {\n this.toggleVideo(true);\n }\n };\n\n async toggleVideo(enabled: boolean) {\n if (!this._stream) {\n return;\n }\n\n if (!Params.consumerScreenTrack) {\n await this._disableScreenCapture();\n }\n\n this.cameraVideoTrack?.stop();\n\n let newTrack: MediaStreamTrack;\n if (enabled) {\n const stream = await WebRTCUtils._getUserVideo(!!this._effect, this._frameRate);\n this.cameraVideoTrack = stream.getVideoTracks()[0];\n newTrack = await this._setEffect(this._effect, this.cameraVideoTrack);\n } else {\n newTrack = WebRTCUtils.getBlackMediaTrack(Params.videoMinWidth, Params.videoMinHeight);\n this._stopEffect();\n }\n\n this._mediaSettings.isVideoEnabled = enabled;\n await this._replaceLocalTrack(newTrack);\n\n if (this._animojiEnabled) {\n // Если вимоджи в UI включен, рендерим его только при выключенной камере\n this._triggerEvent(MediaSourceEvent.ANIMOJI_STATUS, !enabled);\n return; // SOURCE_CHANGED ивент долетит в коллбеке onAnimojiSender\n }\n\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.video });\n }\n\n async toggleAudio(enabled: boolean) {\n if (!this._stream) {\n return;\n }\n\n this._micAudioTrack?.stop();\n\n const changeSource = async (track: MediaStreamTrack, isEnabled: boolean) => {\n await this._replaceLocalTrack(track);\n this._mediaSettings.isAudioEnabled = isEnabled;\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.audio });\n };\n\n if (enabled) {\n try {\n const stream = await WebRTCUtils.getUserAudio();\n this._micAudioTrack = stream.getAudioTracks()[0];\n\n changeSource((await this._applyAudioEffect()) as MediaStreamTrack, true);\n } catch (e: unknown) {\n Params.audioEffects?.pause();\n changeSource(WebRTCUtils.getSilentMediaTrack(), false);\n\n if (typeof e === 'string') {\n throw new Error(e);\n } else {\n throw e;\n }\n }\n } else {\n Params.audioEffects?.pause();\n changeSource(WebRTCUtils.getSilentMediaTrack(), false);\n }\n }\n\n toggleAnimojiCapturing(enabled: boolean) {\n this._animojiEnabled = enabled;\n if (!this._mediaSettings.isVideoEnabled) {\n // Включаем/выключаем вимоджи только при выключенной камере\n // По этому событию создается/уничтожается AnimojiSender в транспорте\n // и вызывается соответствующие коллбеки после получения/удаления стрима\n this._triggerEvent(MediaSourceEvent.ANIMOJI_STATUS, enabled);\n }\n }\n\n onAnimojiSender(created: boolean) {\n this._mediaSettings.isAnimojiEnabled = created;\n this._triggerEvent(MediaSourceEvent.SOURCE_CHANGED, { kind: MediaTrackKind.video });\n }\n\n async setResolution({ video, effect }: { video: IVideoDimentions; effect?: IVideoDimentions }) {\n // Не применяем к скриншаригну\n if (!Params.consumerScreenTrack && this._mediaSettings.isScreenSharingEnabled) {\n return;\n }\n\n // Не применяем, если камера выключена\n if (!this._mediaSettings.isVideoEnabled) {\n return;\n }\n\n if (!this._stream) {\n throw new Error('Local stream not found');\n }\n\n if (!this.cameraVideoTrack) {\n throw new Error('Local video track not found');\n }\n\n const dimensions = (this._effect && effect) || video;\n await this._applyVideoConstraints(this.cameraVideoTrack, dimensions);\n }\n\n getCameraVideoTrack() {\n return this.cameraVideoTrack;\n }\n\n async updateNoiseSuppression() {\n if (!this._stream || !this._mediaSettings.isAudioEnabled) {\n return;\n }\n\n const track = this._stream.getAudioTracks().find((audio) => !audio.contentHint);\n if (!track) {\n throw new Error('Local audio track not found');\n }\n\n if (!track.enabled) {\n return;\n }\n\n return track.applyConstraints({\n noiseSuppression: Params.noiseSuppression,\n });\n }\n\n async videoEffect(effect: IEffect | null) {\n if (!Params.videoEffects) {\n throw new Error('Video Effects library is not set');\n }\n\n if (!Params.consumerScreenTrack && this._mediaSettings.isScreenSharingEnabled) {\n throw new Error(\"Can't apply effect to screensharing\");\n }\n\n // TODO: Логировать в другой event\n Logger.log(StatLog.DEVICE_CHANGED, `effect_${effect?.effect || 'none'}`);\n\n if (!this._mediaSettings.isVideoEnabled) {\n this._effect = effect;\n return;\n }\n\n if (this._stream && effect !== this._effect && this.cameraVideoTrack) {\n const savedEffect = this._effect;\n this._effect = effect;\n\n try {\n const track = this.cameraVideoTrack.clone();\n const stream = new MediaStream([track]);\n\n await this._applyVideoConstraints(track);\n // Передаем текущий стрим при включении эффекта, чтобы не запрашивать заново с камеры\n await this._changeVideoInput(stream);\n } catch (e) {\n // Rollback\n this._effect = savedEffect;\n\n // Получаем новый трек и отключаем эффект\n const track = this.cameraVideoTrack.clone();\n const stream = new MediaStream([track]);\n await this._changeVideoInput(stream);\n throw e;\n }\n }\n }\n\n async audioEffect(audioEffectParams: AudioEffectParams | null) {\n if (!Params.audioEffects) {\n throw new Error('Audio Effects library is not set');\n }\n\n if (!this._mediaSettings.isAudioEnabled) {\n this._audioEffectParams = audioEffectParams;\n return;\n }\n\n if (\n this._stream &&\n ((!audioEffectParams && this._audioEffectParams) ||\n (audioEffectParams && !this._audioEffectParams) ||\n !Utils.isArraysEquals(audioEffectParams?.effects || [], this._audioEffectParams?.effects || [])) &&\n this._micAudioTrack\n ) {\n const savedEffect = this._audioEffectParams;\n this._audioEffectParams = audioEffectParams;\n\n try {\n const track = this._micAudioTrack.clone();\n const stream = new MediaStream([track]);\n\n // Передаем текущий стрим при включении эффекта, чтобы не запрашивать заново с микрофона\n await this._changeAudioInput(stream);\n } catch (e) {\n // Rollback\n this._audioEffectParams = savedEffect;\n\n // Получаем новый трек и отключаем эффект\n const track = this._micAudioTrack.clone();\n const stream = new MediaStream([track]);\n await this._changeAudioInput(stream);\n throw e;\n }\n }\n }\n\n getAudioShareTrack(): MediaStreamTrack | null {\n return this._audioShareTrack;\n }\n\n private handleVideoEffectsLowFps(fpsLimit: number) {\n if (this._mediaSettings.isVideoEnabled && this.cameraVideoTrack && fpsLimit < Params.videoFrameRate) {\n this._applyVideoConstraints(this.cameraVideoTrack).catch((e) => {\n Debug.warn('MediaSource handleVideoEffectsLowFps error', e);\n });\n }\n }\n\n private get _frameRate() {\n const limit = this._videoEffectsFpsLimiter?.fpsLimit ?? Params.videoFrameRate;\n return !!this._effect ? Math.min(limit, Params.videoFrameRate) : undefined;\n }\n\n private async _applyVideoConstraints(track: MediaStreamTrack, constraints?: MediaTrackConstraints) {\n await setVideoConstraints(track, {\n width: this._effect ? Params.videoEffectMaxWidth : Params.videoMaxWidth,\n height: this._effect ? Params.videoEffectMaxHeight : Params.videoMaxHeight,\n ...(this._frameRate && { frameRate: { ideal: this._frameRate } }),\n ...constraints,\n });\n }\n\n getScreenShareTrack(): MediaStreamTrack | null {\n return this._screenShareTrack;\n }\n}\n", "import Debug from '../static/Debug';\nimport WebRTCUtils from '../static/WebRTCUtils';\n\nenum PermissionStatusName {\n Video_Capture = 'video_capture',\n Audio_Capture = 'audio_capture',\n}\n\ntype Device = 'camera' | 'microphone';\ntype PermissionStatusState = typeof PermissionStatus.prototype.state;\ntype EventListener = (name: Device, state: PermissionStatusState) => void;\n\nexport class NavigatorPermissions {\n private _cameraPermissionStatus: PermissionStatus;\n private _microphonePermissionStatus: PermissionStatus;\n private _listener: EventListener;\n\n static isSupported() {\n return WebRTCUtils.browserName() !== 'Firefox' && 'permissions' in navigator && 'PermissionStatus' in window;\n }\n\n async init(listener: EventListener) {\n try {\n const [cameraPermissionStatus, microphonePermissionStatus] = await Promise.all([\n navigator.permissions.query({\n name: 'camera',\n }),\n navigator.permissions.query({\n name: 'microphone',\n }),\n ]);\n\n this._cameraPermissionStatus = cameraPermissionStatus;\n this._microphonePermissionStatus = microphonePermissionStatus;\n this._listener = listener;\n\n this._cameraPermissionStatus.onchange = (ev) => this.handlePermissionChange(ev);\n this._microphonePermissionStatus.onchange = (ev) => this.handlePermissionChange(ev);\n } catch (error) {\n Debug.warn('NavigatorPermissions init error', error);\n }\n }\n\n private handlePermissionChange(ev: Event) {\n const permissionStatus = ev.target;\n if (permissionStatus instanceof PermissionStatus) {\n const { name, state } = permissionStatus;\n switch (name) {\n case PermissionStatusName.Audio_Capture:\n this._listener('microphone', state);\n break;\n case PermissionStatusName.Video_Capture:\n this._listener('camera', state);\n break;\n }\n }\n }\n\n getPermissionState(device: Device): PermissionState | null {\n let permissionState: PermissionState | null = null;\n switch (device) {\n case 'camera':\n permissionState = this._cameraPermissionStatus.state;\n break;\n case 'microphone':\n permissionState = this._microphonePermissionStatus.state;\n break;\n }\n return permissionState;\n }\n}\n", "import { IAsrData } from '../types/Asr';\nimport { ConversationData } from '../types/Conversation';\nimport HangupReason from '../classes/HangupReason';\nimport { MediaTrackKind } from '../classes/MediaSource';\nimport { MediaType } from '../types/ParticipantStreamDescription';\nimport SignalingMessage from '../types/SignalingMessage';\nimport { StatResult } from '../types/Statistics';\nimport ChatRoomEventType from '../enums/ChatRoomEventType';\nimport ConversationOption from '../enums/ConversationOption';\nimport FatalError from '../enums/FatalError';\nimport MediaOption from '../enums/MediaOption';\nimport RoomsEventType from '../enums/RoomsEventType';\nimport UserRole from '../enums/UserRole';\nimport { IFeaturesPerRole } from '../types/ConversationFeature';\nimport { ExternalId, ExternalParticipant, ExternalParticipantId, ExternalParticipantListChunk, ExternalParticipantListMarkers } from '../types/ExternalId';\nimport { IFeedbackExternal } from '../types/Feedback';\nimport MediaModifiers from '../types/MediaModifiers';\nimport MediaSettings from '../types/MediaSettings';\nimport { IOnRemoteMovieData, ISharedMovieInfo, ISharedMovieState, ISharedMovieStoppedInfo } from '../types/MovieShare';\nimport MuteStates from '../types/MuteStates';\nimport { ParticipantsStateList, ParticipantStateMapped } from '../types/Participant';\nimport { IRoomId, Room, RoomParticipantUpdate, Rooms, RoomsUpdate } from '../types/Room';\nimport { VmojiError } from '../types/Vmoji';\nimport Debug, { DebugMessageType } from './Debug';\nimport { JSONObject } from './Json';\nimport Params, { ParamsObject } from './Params';\nimport { ParticipantCapabilities } from './SignalingCapabilities';\n\n/**\n * Статус собеседника\n */\nexport enum ParticipantStatus {\n WAITING_HALL = 'WAITING_HALL',\n WAIT_FOR_ADMIN = 'WAIT_FOR_ADMIN',\n WAITING = 'WAITING',\n CONNECTING = 'CONNECTING',\n CONNECTED = 'CONNECTED',\n RECONNECT = 'RECONNECT',\n ERROR = 'ERROR',\n HANGUP = 'HANGUP',\n PERMISSIONS = 'PERMISSIONS',\n}\n\nfunction _call(method: keyof ParamsObject, ...args: any) {\n const callable = Params.get(method);\n if (typeof callable === 'function') {\n setTimeout(callable, 0, ...args);\n }\n}\n\nfunction _callFilterExternalUser(method: keyof ParamsObject, userIds: ExternalId | ExternalId[], ...args: any) {\n if (Params.filterObservers) {\n if (Array.isArray(userIds)) {\n userIds = userIds.filter((userId) => !userId.observer);\n if (!userIds.length) {\n return;\n }\n } else if (userIds.observer) {\n return;\n }\n }\n\n _call(method, userIds, ...args);\n}\n\nfunction _cloneObj(data: object) {\n return Object.assign({}, data);\n}\n\nfunction _cloneArr<T>(data: T[]): T[] {\n return data.slice();\n}\n\n/**\n * Функции обратного вызова для передачи в параметрах инициализации\n * @hidden\n */\nnamespace External {\n /**\n * Получен локальный стрим с камеры/микрофона\n *\n * @param stream\n * @param mediaSettings\n */\n export function onLocalStream(stream: MediaStream | null, mediaSettings: MediaSettings) {\n _call('onLocalStream', stream, _cloneObj(mediaSettings));\n }\n\n /**\n * Локальный стрим с экрана добавлен/удалён\n *\n * @param stream\n * @param mediaSettings\n */\n export function onScreenStream(stream: MediaStream | null, mediaSettings: MediaSettings) {\n _call('onScreenStream', stream, _cloneObj(mediaSettings));\n }\n\n /**\n * Локальный стрим вимоджи добавлен/удалён\n *\n * @param stream\n * @param mediaSettings\n */\n export function onVmojiStream(stream: MediaStream | null, mediaSettings: MediaSettings) {\n _call('onVmojiStream', stream, _cloneObj(mediaSettings));\n }\n\n /**\n * Получена ошибка Vmoji\n *\n * @param error\n */\n export function onVmojiError(error: VmojiError) {\n _call('onVmojiError', error);\n }\n\n /**\n * Локальный стрим изменился\n *\n * @param mediaSettings\n * @param kind\n */\n export function onLocalStreamUpdate(mediaSettings: MediaSettings, kind: MediaTrackKind) {\n _call('onLocalStreamUpdate', _cloneObj(mediaSettings), kind);\n }\n\n /**\n * Изменился статус локального соединения\n *\n * @param status\n */\n export function onLocalStatus(status: ParticipantStatus) {\n Debug.debug('Local status:', status);\n _call('onLocalStatus', status);\n }\n\n /**\n * Получен стрим собеседника.\n * Если сервер закончил стримить собеседника, вместо стрима будет передан null\n *\n * @param userId\n * @param stream\n */\n export function onRemoteStream(userId: ExternalParticipantId, stream: MediaStream | null) {\n _callFilterExternalUser('onRemoteStream', userId, stream);\n }\n\n /**\n * Получен стрим лайв от собеседника.\n * Если сервер закончил стримить собеседника, вместо стрима будет передан null\n *\n * @param userId\n * @param data\n */\n export function onRemoteLive(userId: ExternalParticipantId, data: IOnRemoteMovieData) {\n _callFilterExternalUser('onRemoteLive', userId, data);\n }\n\n /**\n * Получен собственный стрим лайв.\n * Если сервер закончил стримить собеседника, вместо стрима будет передан null\n *\n * @param userId\n * @param data\n */\n export function onLocalLive(userId: ExternalParticipantId, data: IOnRemoteMovieData) {\n _callFilterExternalUser('onLocalLive', userId, data);\n }\n\n /**\n * Получено обновление стрима или лайва от собеседника.\n *\n * @param userId\n * @param data\n */\n export function onRemoteLiveUpdate(userId: ExternalParticipantId, data: ISharedMovieState) {\n _callFilterExternalUser('onRemoteLiveUpdate', userId, data);\n }\n\n /**\n * Получено обновление собственного стрима или лайва.\n *\n * @param userId\n * @param data\n */\n export function onLocalLiveUpdate(userId: ExternalParticipantId, data: ISharedMovieState) {\n _callFilterExternalUser('onLocalLiveUpdate', userId, data);\n }\n\n /**\n * Получен стрим с экрана собеседника.\n * Если сервер закончил стримить экран собеседника, вместо стрима будет передан null\n *\n * @param userId\n * @param stream\n */\n export function onRemoteScreenStream(userId: ExternalParticipantId, stream: MediaStream | null) {\n _callFilterExternalUser('onRemoteScreenStream', userId, stream);\n }\n\n /**\n * Получен стрим вимоджи собеседника.\n * Если сервер закончил стримить собеседника, вместо стрима будет передан null\n *\n * @param userId\n * @param stream\n */\n export function onRemoteVmojiStream(userId: ExternalParticipantId, stream: MediaStream | null) {\n _callFilterExternalUser('onRemoteVmojiStream', userId, stream);\n }\n\n /**\n * Cтрим собеседника приостановлен/возобновлен.\n *\n * @param userId\n * @param mediaType тип отключённого/включённого потока\n * @param suspended true - стрим был приостановлен, false - стрим был запущен\n */\n export function onRemoteStreamSuspended(userId: ExternalParticipantId, mediaType: MediaType, suspended: boolean) {\n _callFilterExternalUser('onRemoteStreamSuspended', userId, mediaType, suspended);\n }\n\n /**\n * Начат звонок\n *\n * @param userId Внешний ID текущего пользователя\n * @param mediaModifiers Текущие настройки пользовательского медиа\n * @param muteStates Состояние устройств при входе в звонок\n * @param participants Список участников звонка\n * @param rooms Список сессионных залов в звонке\n */\n export function onConversation(userId: ExternalParticipantId, mediaModifiers: MediaModifiers, muteStates: MuteStates, participants: ExternalParticipant[], rooms?: Rooms) {\n _callFilterExternalUser('onConversation', userId, _cloneObj(mediaModifiers), _cloneObj(muteStates), participants, rooms);\n }\n\n /**\n * Постраничные данные про участников при начале звонка\n * @param chunk\n */\n export function onConversationParticipantListChunk(chunk: ExternalParticipantListChunk) {\n if (chunk) {\n _call('onConversationParticipantListChunk', chunk);\n }\n }\n\n /**\n * Изменились данные стрима собеседника\n *\n * @param userId\n * @param mediaSettings\n * @param markers\n */\n export function onRemoteMediaSettings(userId: ExternalParticipantId, mediaSettings: MediaSettings, markers: ExternalParticipantListMarkers | null) {\n _callFilterExternalUser('onRemoteMediaSettings', userId, _cloneObj(mediaSettings), markers);\n }\n\n /**\n * Изменились данные собственного стрима\n *\n * @param userId\n * @param mediaSettings\n */\n export function onLocalMediaSettings(userId: ExternalParticipantId, mediaSettings: MediaSettings) {\n _callFilterExternalUser('onLocalMediaSettings', userId, _cloneObj(mediaSettings));\n }\n\n /**\n * Полученны данные по стримам (лайв/мувик) от собеседника\n *\n * @param userId\n * @param sharedMovieInfo\n * @param roomId\n */\n export function onRemoteSharedMovieInfo(userId: ExternalParticipantId, sharedMovieInfo: ISharedMovieInfo, roomId?: IRoomId) {\n _callFilterExternalUser('onRemoteSharedMovieInfo', userId, _cloneObj(sharedMovieInfo), roomId);\n }\n\n /**\n * Полученны данные по остановленным стримам (лайв/мувик) от собеседника\n *\n * @param userId\n * @param sharedMovieStoppedInfo\n * @param roomId\n */\n export function onRemoteSharedMovieStoppedInfo(userId: ExternalParticipantId, sharedMovieStoppedInfo: ISharedMovieStoppedInfo, roomId?: IRoomId) {\n _callFilterExternalUser('onRemoteSharedMovieStoppedInfo', userId, _cloneObj(sharedMovieStoppedInfo), roomId);\n }\n\n /**\n * Полученны данные по собственным стримам (лайв/мувик)\n *\n * @param userId\n * @param sharedMovieInfo\n * @param roomId\n */\n export function onLocalSharedMovieInfo(userId: ExternalParticipantId, sharedMovieInfo: ISharedMovieInfo, roomId?: IRoomId) {\n _callFilterExternalUser('onLocalSharedMovieInfo', userId, _cloneObj(sharedMovieInfo), roomId);\n }\n\n /**\n * Полученны данные по собственным остановленным стримам (лайв/мувик)\n *\n * @param userId\n * @param sharedMovieStoppedInfo\n * @param roomId\n */\n export function onLocalSharedMovieStoppedInfo(userId: ExternalParticipantId, sharedMovieStoppedInfo: ISharedMovieStoppedInfo, roomId?: IRoomId) {\n _callFilterExternalUser('onLocalSharedMovieStoppedInfo', userId, _cloneObj(sharedMovieStoppedInfo), roomId);\n }\n\n /**\n * Получены данные о совместном использовании стороннего web-приложения\n *\n * @param userId\n * @param sharedUrl\n * @param roomId\n */\n export function onRemoteSharedUrl(userId: ExternalParticipantId, sharedUrl: string | undefined, roomId: IRoomId) {\n _callFilterExternalUser('onRemoteSharedUrl', userId, sharedUrl, roomId);\n }\n\n /**\n * Добавили участника\n *\n * @param userId\n * @param markers\n */\n export function onParticipantAdded(userId: ExternalId, markers: ExternalParticipantListMarkers | null) {\n _callFilterExternalUser('onParticipantAdded', userId, markers);\n }\n\n /**\n * Участник подключился\n *\n * @param userId\n * @param markers\n */\n export function onParticipantJoined(userId: ExternalId, markers: ExternalParticipantListMarkers | null) {\n _callFilterExternalUser('onParticipantJoined', userId, markers);\n }\n\n export function onLocalParticipantState(participantState: ParticipantStateMapped, global: boolean = false) {\n _call('onLocalParticipantState', _cloneObj(participantState), global);\n }\n\n /**\n * Изменились данные состояний собеседника\n *\n * @param userId\n * @param participantState\n * @param markers\n */\n export function onRemoteParticipantState(userId: ExternalParticipantId, participantState: ParticipantStateMapped, markers: ExternalParticipantListMarkers | null) {\n _callFilterExternalUser('onRemoteParticipantState', userId, _cloneObj(participantState), markers);\n }\n\n /**\n * Изменились данные состояний нескольких собеседников\n *\n * @param stateList\n * @param roomId\n */\n export function onRemoteParticipantsState(stateList: ParticipantsStateList, roomId?: IRoomId) {\n _call('onRemoteParticipantsState', stateList, roomId);\n }\n\n /**\n * Изменился статус соединения собеседников\n *\n * @param userIds\n * @param status\n * @param data\n */\n export function onRemoteStatus(userIds: ExternalParticipantId[], status: ParticipantStatus, data: any = null) {\n Debug.debug('Remote status:', status, userIds);\n _callFilterExternalUser('onRemoteStatus', userIds, status, data);\n }\n\n /**\n * Разрешения на доступы были запрошены в браузере\n */\n export function onPermissionsRequested() {\n _call('onPermissionsRequested');\n }\n\n /**\n * Ошибка получения трека с камеры или микрофона\n *\n * @param error\n * @param original\n */\n export function onPermissionsError(error: FatalError, original: Error) {\n _call('onPermissionsError', error, original);\n }\n\n /**\n * Пользователь отключился от звонка\n *\n * @param userId\n * @param markers\n */\n export function onRemoteRemoved(userId: ExternalParticipantId, markers: ExternalParticipantListMarkers | null) {\n _callFilterExternalUser('onRemoteRemoved', userId, markers);\n }\n\n /**\n * Изменилось состояние звонка\n *\n * @param isCallActive Активен ли сейчас звонок\n * @param canAddParticipants Можно ли добавлять собеседников\n * @param conversation Информация о звонке\n */\n export function onCallState(isCallActive: boolean, canAddParticipants: boolean, conversation: ConversationData) {\n _call('onCallState', isCallActive, canAddParticipants, _cloneObj(conversation));\n }\n\n /**\n * Изменилось состояние камеры или микрофона\n *\n * @param mediaOption Тип устройства\n * @param enabled Включено или выключено\n */\n export function onDeviceSwitched(mediaOption: MediaOption, enabled: boolean) {\n _call('onDeviceSwitched', mediaOption, enabled);\n }\n\n /**\n * Изменились состояния устройств пользователя или разрешения включать камеру/микрофон\n *\n * @param muteStates Состояния устройств\n * @param unmuteOptions Разрешения включать устройства\n * @param mediaOptions Изменения состояний\n * @param muteAll Команда распространяется на всех участников звонка\n * @param unmute Разрешение включить устройство\n * @param userId Пользователь, для которого изменились разрешения или `null` для текущего пользователя\n * @param adminId Пользователь, который изменил разрешения\n * @param stateUpdated Если `true`, значит глобальное/персональное состояние изменилось и поля `muteStates`/`unmuteOptions` содержат обновления, если `false`, значит, эти поля не имеют значения\n * @param requestedMedia Какие устройства попросили включить участника\n * @param roomId ID сессионного зала или ничего в случае основного зала\n */\n export function onMuteStates(\n muteStates: MuteStates,\n unmuteOptions: MediaOption[],\n mediaOptions: MediaOption[],\n muteAll = false,\n unmute = false,\n userId: ExternalParticipantId | null = null,\n adminId: ExternalParticipantId | null = null,\n stateUpdated?: boolean,\n requestedMedia?: MediaOption[],\n roomId: number | null = null,\n ) {\n const _requestedMedia = requestedMedia ? _cloneArr(requestedMedia) : undefined;\n _call('onMuteStates', _cloneObj(muteStates), _cloneArr(unmuteOptions), _cloneArr(mediaOptions), muteAll, unmute, userId, adminId, stateUpdated, _requestedMedia, roomId);\n }\n\n /**\n * Изменились роли собеседника в звонке\n *\n * @param userId Внешний ID пользователя\n * @param roles Список ролей\n * @param isInitial Коллбек вызван при инициализации (переподключение в звонок, заранее назначенный админ)\n */\n export function onRolesChanged(userId: ExternalId, roles: UserRole[], isInitial = false) {\n _callFilterExternalUser('onRolesChanged', userId, _cloneArr(roles), isInitial);\n }\n\n /**\n * Изменились свои роли в звонке\n *\n * @param roles Список ролей\n * @param isInitial Коллбек вызван при инициализации (переподключение в звонок, заранее назначенный админ)\n */\n export function onLocalRolesChanged(roles: UserRole[], isInitial = false) {\n _call('onLocalRolesChanged', _cloneArr(roles), isInitial);\n }\n\n /**\n * Закрепляет/открепляет собеседника для всех\n *\n * @param userId Внешний ID пользователя\n * @param unpin Открепить или закрепить\n * @param markers\n * @param roomId ID сессионного зала или ничего в случае основного зала\n */\n export function onPinnedParticipant(userId: ExternalParticipantId, unpin: boolean, markers: ExternalParticipantListMarkers | null, roomId?: number | null) {\n _callFilterExternalUser('onPinnedParticipant', userId, unpin, markers, roomId);\n }\n\n /**\n * Закрепляет/открепляет текущего пользователя у других собеседников\n *\n * @param unpin Открепить или закрепить\n * @param roomId ID сессионного зала или ничего в случае основного зала\n */\n export function onLocalPin(unpin: boolean, roomId?: number | null) {\n _call('onLocalPin', unpin, roomId);\n }\n\n /**\n * Изменились опции звонка\n *\n * @param options Список опций звонка\n */\n export function onOptionsChanged(options: ConversationOption[]) {\n _call('onOptionsChanged', _cloneArr(options));\n }\n\n /**\n * Входящий звонок был принят мной\n */\n export function onCallAccepted() {\n _call('onCallAccepted');\n }\n\n /**\n * Исходящий звонок был принят кем-то\n * @param userId\n * @param capabilities\n */\n export function onAcceptedCall(userId: ExternalId, capabilities: ParticipantCapabilities) {\n _callFilterExternalUser('onAcceptedCall', userId, capabilities);\n }\n\n export function onRateNeeded() {\n _call('onRateNeeded');\n }\n\n /**\n * Изменился говорящий в звонке\n *\n * @param userId\n */\n export function onSpeakerChanged(userId: ExternalParticipantId) {\n _callFilterExternalUser('onSpeakerChanged', userId);\n }\n\n /**\n * Громкость собеседников\n *\n * @param volumes\n */\n export function onVolumesDetected(volumes: { uid: ExternalParticipantId; volume: number }[]) {\n _call('onVolumesDetected', _cloneArr(volumes));\n }\n\n /**\n * Громкость своего микрофона\n *\n * @param volume\n * @param isMicEnabled\n */\n export function onLocalVolume(volume: number, isMicEnabled: boolean) {\n _call('onLocalVolume', volume, isMicEnabled);\n }\n\n export function onJoinStatus(available: boolean, chatId: string) {\n _call('onJoinStatus', available, chatId);\n }\n\n /**\n * Звонок был завершен\n *\n * @param data Информация почему звонок завершился\n * @param conversationId ID звонка\n */\n export function onHangup(data: HangupReason, conversationId: string | null) {\n _call('onHangup', data, conversationId);\n }\n\n export function onMultipartyChatCreated(conversation: ConversationData) {\n _call('onMultipartyChatCreated', _cloneObj(conversation));\n }\n\n /**\n * Список устройств изменился\n */\n export function onDeviceChange() {\n _call('onDeviceChange');\n }\n\n /**\n * Изменилась подпись звонка 1:1\n */\n export function onFingerprintChange(fingerprint: string) {\n _call('onFingerprintChange', fingerprint);\n }\n\n /**\n * Требуется обновление токена\n */\n export function onTokenExpired() {\n _call('onTokenExpired');\n }\n\n /**\n * Получено сообщение чата\n *\n * @param message Сообщение\n * @param from ID отправителя\n * @param direct Личное сообщение или общее\n */\n export function onChatMessage(message: string, from: ExternalParticipantId, direct = false) {\n _call('onChatMessage', message, from, direct);\n }\n\n /**\n * Получены данные от собеседника\n *\n * @param data Данные\n * @param from ID отправителя\n * @param direct Личное сообщение или общее\n */\n export function onCustomData(data: JSONObject, from: ExternalParticipantId, direct = false) {\n _call('onCustomData', data, from, direct);\n }\n\n /**\n * Начата запись звонка\n *\n * @param initiator ID пользователя, начавшего запись\n * @param movieId ID ролика в который пишется звонок\n * @param startTime Время старта записи\n * @param type Тип записи\n * @param externalMovieId Внешний ID ролика\n * @param externalOwnerId Внешний ID пользователя/группы от которого ведётся трансляция\n * @param roomId ID зала в котором стартанула запись\n */\n export function onRecordStarted(\n initiator: ExternalParticipantId,\n movieId: number,\n startTime: number,\n type: 'STREAM' | 'RECORD',\n externalMovieId?: string,\n externalOwnerId?: string,\n roomId: number | null = null,\n ) {\n _call('onRecordStarted', initiator, movieId, startTime, type, externalMovieId, externalOwnerId, roomId);\n }\n\n /**\n * Закончена запись звонка\n * @param roomId ID зала в котором остановлена запись\n */\n export function onRecordStopped(roomId: number | null = null, stopBy: ExternalParticipantId | null) {\n _call('onRecordStopped', roomId, stopBy);\n }\n\n /**\n * Состояние своей сети\n *\n * @param rating Оценка качества соединения от 0 до 1\n */\n export function onLocalNetworkStatusChanged(rating: number) {\n _call('onLocalNetworkStatusChanged', rating);\n }\n\n /**\n * Состояние сети участников\n *\n * @param status Оценки качества соединения участников от 0 до 1\n */\n export function onNetworkStatusChanged(status: { uid: ExternalParticipantId; rating: number }[]) {\n _call('onNetworkStatusChanged', status);\n }\n\n /**\n * Получено отладочное сообщение. Работает только при выключенном режиме отладки\n *\n * @param type Тип сообщения\n * @param args\n */\n export function onDebugMessage(type: DebugMessageType, ...args: any[]) {\n _call('onDebugMessage', type, ...args);\n }\n\n /**\n * Статистика звонка\n *\n * @param connection Статистика соединения\n * @param memory Статистика памяти\n */\n export function onStatistics(connection: StatResult, memory: Record<string, number>) {\n const args = Object.assign({}, connection, { memory });\n _call('onStatistics', args);\n }\n\n /**\n * Ошибка воспроизведения звука\n */\n export function onAutoplayError() {\n _call('onAutoplayError');\n }\n\n /**\n * Изменилось состояние зала ожидания/зала в режиме Audience\n *\n * @param eventType\n * @param totalCount Количество ожидающих/слушателей\n * @param firstParticipants Первые несколько ожидающих в зале\n * @param addedParticipantIds Некоторое количество участников, добавленных в зал\n * @param removedParticipantIds Некоторое количество участников, убранных из зала\n */\n export function onChatRoomUpdated(\n eventType: ChatRoomEventType,\n totalCount: number,\n firstParticipants: ExternalId[],\n addedParticipantIds: ExternalId[],\n removedParticipantIds: ExternalId[],\n ) {\n _call('onChatRoomUpdated', eventType, totalCount, firstParticipants, addedParticipantIds, removedParticipantIds);\n }\n\n /**\n * Участник повышен/разжалован в зале ожидания/зале в режиме Audience\n *\n * @param demoted участник разжалован\n */\n export function onPromoted(demoted: boolean) {\n _call('onPromoted', demoted);\n }\n\n /**\n * Получен микшированный аудио стрим.\n *\n * @param stream стрим от WebRTC\n */\n export function onRemoteMixedAudioStream(stream: MediaStream) {\n _call('onRemoteMixedAudioStream', stream);\n }\n\n /**\n * Получена новая ссылка на звонок\n * @param joinLink токен присоединения к звонку\n */\n export function onJoinLinkChanged(joinLink: string | null) {\n _call('onJoinLinkChanged', joinLink);\n }\n\n /**\n * Получено обновление по сессионным залам\n * @param updates\n */\n export function onRoomsUpdated(updates: Partial<Record<RoomsEventType, RoomsUpdate>>) {\n _call('onRoomsUpdated', updates);\n }\n\n /**\n * Получено обновление по сессионному залу\n * @param eventTypes\n * @param roomId\n * @param room\n * @param deactivate\n */\n export function onRoomUpdated(eventTypes: RoomsEventType[], roomId: number, room: Room | null, deactivate: boolean | null) {\n _call('onRoomUpdated', eventTypes, roomId, room, deactivate);\n }\n\n /**\n * Получено обновление по участникам сессионного зала\n * @param update\n */\n export function onRoomParticipantsUpdated(update: RoomParticipantUpdate) {\n _call('onRoomParticipantsUpdated', update);\n }\n\n /**\n * Произошел переход в другой активный зал (или основной)\n * @param roomId\n */\n export function onRoomSwitched(roomId: number | null) {\n _call('onRoomSwitched', roomId);\n }\n\n /**\n * Установить id сессионного зала на старте звонка\n * @param roomId\n */\n export function onRoomStart(roomId: number | null) {\n _call('onRoomStart', roomId);\n }\n\n /**\n * Получена новая реакция\n */\n export function onFeedback(feedback: IFeedbackExternal[], roomId: number | null = null) {\n _call('onFeedback', feedback, roomId);\n }\n\n /**\n * Изменилось состояние пермиссий фич в звонке\n *\n * @param featuresPerRole Информация о доступных фичах по ролям\n */\n export function onFeaturesPerRoleChanged(featuresPerRole: IFeaturesPerRole) {\n _call('onFeaturesPerRoleChanged', featuresPerRole);\n }\n\n /**\n * Изменился Vmoji-аватар пользователя\n * @param externalId Id пользователя\n */\n export function onParticipantVmojiUpdate(externalId: ExternalParticipantId) {\n _call('onParticipantVmojiUpdate', externalId);\n }\n\n /**\n * Установка начальных параметров текстовой расшифровки звонка. (Используется при входе в звонок/ смене комнаты)\n * @param data Начальная информация по ASR\n * @param roomId Id Комнаты\n */\n export function onAsrSet(data: IAsrData | null, roomId: number | null) {\n _call('onAsrSet', data, roomId);\n }\n\n /**\n * Начата текстовая расшифровка звонка\n * @param initiatorId Id пользователя, запустившего расшифровку звонка\n * @param movieId Id расшифровки\n * @param roomId Id Комнаты\n */\n export function onAsrStarted(initiatorId: ExternalParticipantId, movieId: number, roomId: number | null) {\n _call('onAsrStarted', initiatorId, movieId, roomId);\n }\n\n /**\n * Закончена текстовая расшифровка звонка\n * @param roomId Id Комнаты\n */\n export function onAsrStopped(roomId: number | null) {\n _call('onAsrStopped', roomId);\n }\n\n export function onAsrTranscription(id: ExternalParticipantId, text: string, timestamp: number, duration: number) {\n _call('onAsrTranscription', id, text, timestamp, duration);\n }\n\n /**\n * Изменился id участника (деанонимизация)\n * @param prevId\n * @param newId\n */\n export function onParticipantIdChanged(prevId: ExternalParticipantId, newId: ExternalParticipantId) {\n _call('onParticipantIdChanged', prevId, newId);\n }\n\n export function onVideoSuspendSuggest(bandwidth: number) {\n _call('onVideoSuspendSuggest', bandwidth);\n }\n\n /**\n * @internal\n */\n export function onSignalingMessage(message: string | SignalingMessage) {\n _call('onSignalingMessage', typeof message === 'string' ? message : _cloneObj(message));\n }\n\n /**\n * Одобрено повышение пользователя в зеле ожидания/зале в режиме Audience\n *\n * @param adminParticipantId админ, одобривший повышение\n */\n export function onPromotionApproved(adminParticipantId: ExternalParticipantId) {\n _call('onPromotionApproved', adminParticipantId);\n }\n\n /**\n * Собеседник подключился к сигналлингу\n */\n export function onPeerRegistered() {\n _call('onPeerRegistered');\n }\n}\n\nexport default External;\n", "/**\n * LocalStorage\n */\n\n/**\n * Prefix for LocalStorage keys.\n * @type {string}\n * @hidden\n */\nconst LS_PREFIX = '_okcls_';\n\n/**\n * LocalStorage reference.\n * @hidden\n */\nconst storage: Storage | null = (() => {\n try {\n const id: string = Date.now().toString(),\n st: Storage = window.localStorage;\n let res = false;\n st.setItem(id, id);\n res = st.getItem(id) === id;\n st.removeItem(id);\n return res ? st : null;\n } catch (exception) {\n return null;\n }\n})();\n\n/**\n * Get item from storage.\n * @hidden\n */\nfunction _getItem(name: string): string | number | boolean | object | null {\n const item = storage ? storage.getItem(LS_PREFIX + name) : null;\n if (item === null) {\n return null;\n }\n\n try {\n return JSON.parse(item);\n } catch (e) {\n return null;\n }\n}\n\n/**\n * Set item to storage.\n * @hidden\n */\nfunction _setItem(name: string, value: string | number | boolean | object) {\n try {\n if (storage) {\n storage.setItem(LS_PREFIX + name, JSON.stringify(value));\n }\n } catch (e) {\n // Переполнение хранилища или нет доступа не запись\n }\n}\n\n/**\n * Remove item from storage.\n * @hidden\n */\nfunction _removeItem(name: string) {\n if (storage) {\n storage.removeItem(LS_PREFIX + name);\n }\n}\n\nnamespace LocalStorage {\n export function get(name: string): string | number | boolean | object | null {\n return _getItem(name) || null;\n }\n\n export function set(name: string, value: string | number | boolean | object) {\n _setItem(name, value);\n }\n\n export function remove(name: string) {\n _removeItem(name);\n }\n}\n\nexport default LocalStorage;\n", "/**\n * Вспомогательный плагин для работы с WebRTC\n */\n\nimport { MediaTrackKind } from '../classes/MediaSource';\nimport FatalError from '../enums/FatalError';\nimport StatLog from '../enums/StatLog';\nimport { IVideoDimentions } from '../types/MediaSettings';\nimport { setVideoConstraints } from '../utils/Media';\nimport Logger from '../classes/Logger';\nimport { NavigatorPermissions } from '../utils/NavigatorPermissions';\nimport Debug from './Debug';\nimport External from './External';\nimport LocalStorage from './LocalStorage';\nimport Params from './Params';\nimport Utils from './Utils';\n\nlet _enumerateDevicesPromise: Promise<MediaDeviceInfo[]> | null = null,\n _deviceChangeListener: VoidFunction | null = null,\n _navigatorPermissions: NavigatorPermissions | null = null,\n _cameras: MediaDeviceInfo[] = [],\n _microphones: MediaDeviceInfo[] = [],\n _output: MediaDeviceInfo[] = [],\n _savedCam: MediaDeviceInfo | null = null,\n _savedMic: MediaDeviceInfo | null = null,\n _savedOutput: MediaDeviceInfo | null = null,\n _cameraPermissionGranted = false,\n _microphonePermissionGranted = false,\n _blackMediaTrack: MediaStreamTrack,\n _blackCanvas: HTMLCanvasElement,\n _silentMediaTrack: MediaStreamTrack,\n _isMobile: boolean | null = null,\n _os = '',\n _osVersion: number | null = null,\n _browserData: any[] = [],\n _audioContext: AudioContext | null = null;\n\nconst av = navigator.appVersion,\n an = navigator.appName,\n ua = navigator.userAgent;\n\nconst eventListeners: { [key: string]: CallableFunction[] } = {};\n\n/**\n * Тип камеры мобильного устройства\n */\nexport enum FacingMode {\n /**\n * Фронтальная камера\n */\n USER = 'user',\n /**\n * Задняя камера\n */\n ENVIRONMENT = 'environment',\n // Пока непонятно как использовать - убираем\n // LEFT = 'left',\n // RIGHT = 'right',\n}\n\n/**\n * @internal\n */\nexport namespace FacingMode {\n export function contains(item: string | FacingMode) {\n return Object.values(FacingMode).includes(item as FacingMode);\n }\n}\n\n/**\n * @internal\n */\nexport interface IDeviceChangeOldDevices {\n camera: MediaDeviceInfo | null;\n microphone: MediaDeviceInfo | null;\n output: MediaDeviceInfo | null;\n}\n\n/**\n * Известные браузеры\n */\nexport type BrowserName = 'IE' | 'Edge' | 'Chrome' | 'Firefox' | 'Yandex' | 'Opera' | 'Sferum';\n\n/********************* MediaConstraints *********************/\n\n/**\n * Вспомогательный класс для формирования параметров, которые нужны для запроса камеры и микрофона.\n * @internal\n */\nclass MediaConstraints {\n protected audio: MediaTrackConstraints | boolean;\n protected video: MediaTrackConstraints | boolean;\n private readonly needVideo: boolean;\n private lastSimplifyWasReached: boolean;\n private readonly supportedConstraints: MediaTrackSupportedConstraints;\n\n constructor(\n audioDeviceId: boolean | string,\n videoDeviceId: boolean | string = false,\n videoMaxWidth = Params.videoMaxWidth,\n videoMaxHeight = Params.videoMaxHeight,\n frameRate = Params.videoFrameRate,\n ) {\n this.supportedConstraints = navigator.mediaDevices.getSupportedConstraints();\n let ac: MediaTrackConstraints | boolean = false;\n\n if (audioDeviceId) {\n ac = {\n noiseSuppression: Params.noiseSuppression,\n echoCancellation: true,\n autoGainControl: true,\n };\n\n const microphones = WebRTCUtils.getMicrophones();\n let aDevId;\n let aGroupId;\n if (_savedMic) {\n aGroupId = _savedMic.groupId;\n aDevId = _savedMic.deviceId;\n }\n if (typeof audioDeviceId === 'string') {\n const audioDevice = microphones.find((mic) => mic.deviceId === audioDeviceId);\n aGroupId = audioDevice?.groupId;\n aDevId = audioDeviceId;\n } else if (!_savedMic && WebRTCUtils.os() === 'MacOS') {\n // Не используем по-умолчанию iPhone в качестве микрофона\n // @see https://support.apple.com/ru-ru/guide/mac-help/mchl77879b8a/mac\n if (microphones.find((mic) => mic.label.includes('iPhone'))) {\n // Если в списке микрофонов есть iPhone, берем любой, кроме Virtual и iPhone\n const forcedMic = microphones.find((mic) => !mic.label.includes('Virtual') && !mic.label.includes('iPhone'));\n if (forcedMic) {\n aGroupId = forcedMic.groupId;\n aDevId = forcedMic.deviceId;\n }\n }\n }\n\n // Safari 17.1 почему-то временно выключил поддержку groupId\n if (aGroupId && this.supportedConstraints.groupId) {\n // Выбираем устройство по группе, т.к. для deviceId: default может меняться устройство\n ac.groupId = { exact: aGroupId };\n } else if (aDevId) {\n ac.deviceId = { exact: aDevId };\n }\n }\n\n let vc: MediaTrackConstraints | boolean = false;\n if (videoDeviceId) {\n vc = {\n width: { min: Params.videoMinWidth, max: videoMaxWidth, ideal: videoMaxWidth },\n height: { min: Params.videoMinHeight, max: videoMaxHeight, ideal: videoMaxHeight },\n aspectRatio: { ideal: Params.videoAspectRatio },\n frameRate: { ideal: frameRate },\n };\n\n const cameras = WebRTCUtils.getCameras();\n let vDevId;\n let vGroupId;\n if (_savedCam) {\n vGroupId = _savedCam.groupId;\n vDevId = _savedCam.deviceId;\n }\n if (typeof videoDeviceId === 'string') {\n const videoDevice = cameras.find((cam) => cam.deviceId === videoDeviceId);\n vGroupId = videoDevice?.groupId;\n vDevId = videoDeviceId;\n } else if (!_savedCam && WebRTCUtils.os() === 'MacOS') {\n // Не используем по-умолчанию iPhone в качестве камеры\n // @see https://support.apple.com/ru-ru/guide/mac-help/mchl77879b8a/mac\n if (cameras.find((cam) => cam.label.includes('iPhone'))) {\n // Если в списке камер есть iPhone, берем любую камеру, кроме Virtual и iPhone\n const forcedCamera = cameras.find((cam) => !cam.label.includes('Virtual') && !cam.label.includes('iPhone'));\n if (forcedCamera) {\n vGroupId = forcedCamera.groupId;\n vDevId = forcedCamera.deviceId;\n }\n }\n }\n\n // Safari 17.1 почему-то временно выключил поддержку groupId\n if (vGroupId && this.supportedConstraints.groupId) {\n vc.groupId = { exact: vGroupId };\n } else if (vDevId) {\n vc.deviceId = { exact: vDevId };\n }\n\n if (Params.videoFacingMode) {\n vc.facingMode = { ideal: Params.videoFacingMode };\n delete vc.deviceId;\n delete vc.groupId;\n }\n }\n\n this.audio = ac;\n this.video = vc;\n this.needVideo = !!vc;\n this.lastSimplifyWasReached = false;\n }\n\n /**\n * Возвращает нативные параметры для передачи в getUserMedia.\n */\n getNative(): MediaStreamConstraints {\n return Object.assign({}, { audio: this.audio, video: this.video });\n }\n\n /**\n * Метод упрощает параметры, чтобы попробовать сделать getUserMedia еще раз при ошибке.\n * Сначала убираются размеры, потом соотношения сторон.\n */\n simplify(): MediaConstraints {\n if (typeof this.video === 'object') {\n if (this.video.width || this.video.height) {\n delete this.video.width;\n delete this.video.height;\n } else if (this.video.aspectRatio) {\n delete this.video.aspectRatio;\n } else if (this.video.frameRate) {\n delete this.video.frameRate;\n } else if (this.video.deviceId || this.video.groupId || this.video.facingMode) {\n delete this.video.deviceId;\n delete this.video.groupId;\n delete this.video.facingMode;\n }\n }\n\n if (typeof this.audio === 'object') {\n if (this.audio.echoCancellation || this.audio.autoGainControl || this.audio.noiseSuppression) {\n delete this.audio.echoCancellation;\n delete this.audio.autoGainControl;\n delete this.audio.noiseSuppression;\n } else if (this.audio.deviceId || this.audio.groupId) {\n delete this.audio.deviceId;\n delete this.audio.groupId;\n }\n }\n\n // Сначала гасим видео если оно есть\n if (this.video === true && this.audio === true) {\n this.video = false;\n } else if (this.video === false && this.audio === true) {\n // Иначе выключаем микрофон\n this.audio = false;\n // Попробуем получить видео без аудио, если оно вообще нужно\n this.video = this.needVideo;\n } else if (this.video === true && this.audio === false) {\n this.video = false;\n }\n\n if (this.video && !Object.keys(this.video).length) {\n this.video = true;\n }\n if (this.audio && !Object.keys(this.audio).length) {\n this.audio = true;\n }\n\n if (!this.audio && !this.video) {\n // Если запрашивать getUserMedia без хотя бы одного параметра - будет ошибка\n // Потому ставим флаг на то, что больше упрощать некуда и принудительно\n // включаем запрос того девайса, который запрашивался изначально\n this.lastSimplifyWasReached = true;\n this.audio = !this.isVideoRequested();\n this.video = this.isVideoRequested();\n }\n\n return this;\n }\n\n /**\n * Проверяет, можно ли упростить параметры.\n */\n canSimplify(): boolean {\n const canVideo =\n (typeof this.video === 'object' &&\n (this.video.width || this.video.height || this.video.aspectRatio || this.video.frameRate || this.video.facingMode || this.video.deviceId || this.video.groupId)) ||\n this.video;\n const canAudio =\n (typeof this.audio === 'object' &&\n (this.audio.deviceId || this.audio.groupId || this.audio.noiseSuppression || this.audio.echoCancellation || this.audio.autoGainControl)) ||\n this.audio;\n\n return !!(canAudio || canVideo) && !this.lastSimplifyWasReached;\n }\n\n /**\n * Проверяет, есть ли параметры видео.\n */\n isVideo(): boolean {\n return !!this.video;\n }\n\n /**\n * Проверяет, есть ли параметры аудио.\n */\n isAudio(): boolean {\n return !!this.audio;\n }\n\n /**\n * Было ли запрошено включение камеры\n */\n isVideoRequested = (): boolean => this.needVideo;\n}\n\n/********************* /MediaConstraints *********************/\n\n/********************* ScreenConstraints *********************/\n\n/**\n * Вспомогательный класс для формирования параметров, которые нужны для запроса трансляции экрана.\n * @internal\n */\nexport class ScreenConstraints extends MediaConstraints {\n readonly captureController: CaptureController | null;\n\n constructor(width: number, height: number, frameRate: number, withAudioShare: boolean) {\n super(false, true);\n\n // Chrome 107+\n this.captureController = 'CaptureController' in window ? new CaptureController() : null;\n\n if (typeof this.video === 'object') {\n delete this.video.deviceId;\n delete this.video.groupId;\n delete this.video.aspectRatio;\n delete this.video.frameRate;\n delete this.video.facingMode;\n } else {\n this.video = {};\n }\n\n // @ts-ignore\n this.video.cursor = 'motion';\n this.video.width = width;\n this.video.height = height;\n this.video.frameRate = frameRate;\n this.video.displaySurface = Params.displaySurface;\n\n if (WebRTCUtils.browserName() === 'Safari') {\n const version = Number(WebRTCUtils.browserVersion());\n if (version === 16) {\n // @see https://stackoverflow.com/questions/74919985/webrtc-screenshare-video-quality-constraints-not-working-on-latest-version-of/75065525#75065525\n this.video.width = { max: width };\n this.video.height = { max: height };\n } else if (version === 17) {\n // Issue не найдено, но с указанием размеров скриншара всегда возвращается 640х480\n delete this.video.width;\n delete this.video.height;\n }\n }\n\n if (withAudioShare) {\n this.audio = {\n noiseSuppression: false,\n echoCancellation: false,\n autoGainControl: false,\n };\n }\n }\n\n override getNative(): MediaStreamConstraints {\n return Object.assign(super.getNative(), { systemAudio: 'exclude', controller: this.captureController });\n }\n}\n\n/********************* /ScreenConstraints *********************/\n\n/********************* MediaSourceLock *********************/\n\nclass MediaSourceLock {\n /** MediaSource занят при переключении камеры или микрофона */\n private static _lockId = 0;\n\n private _lockId = Math.round(Math.random() * 99_998) + 1;\n\n busy(): void {\n if (MediaSourceLock._lockId) {\n Logger.log(StatLog.ERROR, 'change_device');\n Debug.warn('Device change failed: MediaSource is busy');\n throw new Error('MediaSource is busy');\n }\n\n MediaSourceLock._lockId = this._lockId;\n }\n\n free(): void {\n if (MediaSourceLock._lockId === this._lockId) {\n MediaSourceLock._lockId = 0;\n }\n }\n}\n\n/********************* /MediaSourceLock *********************/\n\n/**\n * Обновляет список устройств\n * @internal\n */\nasync function _updateDevices(): Promise<void> {\n // Сбросим флаги, чтобы при обновлении проставить их снова\n _microphonePermissionGranted = false;\n _cameraPermissionGranted = false;\n\n _enumerateDevicesPromise = null;\n\n // Предыдущие сохраненные устройства, т.к. _getDevices их перезапишет актуальными\n const from: IDeviceChangeOldDevices = {\n camera: WebRTCUtils.getSavedCamera(),\n microphone: WebRTCUtils.getSavedMicrophone(),\n output: WebRTCUtils.getSavedOutput(),\n };\n await _getDevices();\n\n _fireEvent('devicechange', from);\n External.onDeviceChange();\n}\n\n/**\n * @internal\n */\nfunction _fireEvent(event: 'devicechange', ...data: unknown[]) {\n if (!eventListeners[event]) {\n return;\n }\n\n for (const fn of eventListeners[event]) {\n fn(...data);\n }\n}\n\n/**\n * Получает доступные устройства\n * @internal\n */\nasync function _getDevices(): Promise<MediaDeviceInfo[]> {\n if (_enumerateDevicesPromise) {\n return _enumerateDevicesPromise;\n }\n\n if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {\n return [];\n }\n\n // В iOS 11.x у mediaDevices нет метода addEventListener\n if (!_deviceChangeListener && navigator.mediaDevices.addEventListener) {\n // Задержка обновления списка устройств после подключения/отключения камеры или микрофона нужна в двух случаях:\n // 1. При подключении составного устройства (камеры с микрофоном), devicechange срабатывает дважды\n // 2. В Firefox почему-то при вызове enumerateDevices сразу после devicechange, в списке устройств не обновляются groupId\n _deviceChangeListener = Utils.debounce(_updateDevices, Params.enumerateDevicesDelay);\n navigator.mediaDevices.addEventListener('devicechange', _deviceChangeListener);\n }\n\n if (!_navigatorPermissions && NavigatorPermissions.isSupported()) {\n _navigatorPermissions = new NavigatorPermissions();\n await _navigatorPermissions.init((name, state) => {\n switch (state) {\n case 'denied':\n case 'prompt':\n _deviceChangeListener?.();\n break;\n }\n });\n }\n\n return (_enumerateDevicesPromise = navigator.mediaDevices\n .enumerateDevices()\n .then((devices) => {\n _cameras = devices.filter((device) => {\n if (device.kind === 'videoinput') {\n if (device.label) {\n _cameraPermissionGranted = true;\n }\n return true;\n }\n return false;\n });\n\n _microphones = devices.filter((device) => {\n if (device.kind === 'audioinput') {\n if (device.label) {\n _microphonePermissionGranted = true;\n } else if (WebRTCUtils.isMobile() && WebRTCUtils.browserName() === 'Firefox') {\n // В мобильном Firefox не проставляется label для микрофона, даже если разрешения даны\n _microphonePermissionGranted = _cameraPermissionGranted;\n }\n return true;\n }\n return false;\n });\n\n _output = devices.filter((device) => device.kind === 'audiooutput');\n\n // из за devicechange может возникнуть race, из за чего стейт LocalStorage\n // будет перетирать записанный в _updateSavedDevices deviceId\n const camDeviceId = _savedCam?.deviceId ?? LocalStorage.get('videoinput');\n const micDeviceId = _savedMic?.deviceId ?? LocalStorage.get('audioinput');\n const outputDeviceId = _savedOutput?.deviceId ?? LocalStorage.get('audiooutput');\n\n _savedCam =\n _cameras.find((device) => {\n return device.deviceId === camDeviceId;\n }) || null;\n\n _savedMic =\n _microphones.find((device) => {\n return device.deviceId === micDeviceId;\n }) || null;\n\n _savedOutput =\n _output.find((device) => {\n return device.deviceId === outputDeviceId;\n }) ||\n _output[0] ||\n null;\n\n _enumerateDevicesPromise = Promise.resolve(devices);\n return devices;\n })\n .catch(() => {\n _enumerateDevicesPromise = null;\n return [];\n }));\n}\n\n/**\n * Получение и кэширование версии операционной системы\n */\nasync function _getOsVersion(): Promise<void> {\n if (!('userAgentData' in navigator)) {\n return;\n }\n\n try {\n // @ts-ignore пока не затащим новый typescript с поддержкой типизации\n const { platformVersion } = await navigator.userAgentData.getHighEntropyValues(['platformVersion']);\n if (!platformVersion) {\n Debug.warn(`Can't to get OS version`);\n return;\n }\n\n // Берём только первую часть строки \"15.0.0\" → 15\n const major = parseInt(platformVersion.split('.')[0]);\n\n _osVersion = isNaN(major) ? null : major;\n } catch (error) {\n Debug.warn('Failed to get OS version', error);\n }\n}\n\n/**\n * Обновляет информацию о сохраненных устройствах после получения стрима, если устройства не были сохранены\n * @internal\n */\nfunction _updateSavedDevices(stream: MediaStream) {\n if (_savedCam && _savedMic) {\n return;\n }\n\n const findDevice = (devices: MediaDeviceInfo[], track: MediaStreamTrack) => {\n const deviceId = track.getSettings()?.deviceId;\n return devices.find((device) => device.deviceId === deviceId || device.label === track.label) || null;\n };\n\n stream?.getTracks().forEach((track) => {\n if (!_savedMic && track.kind === MediaTrackKind.audio) {\n _savedMic = findDevice(WebRTCUtils.getMicrophones(), track);\n } else if (!_savedCam && track.kind === MediaTrackKind.video) {\n _savedCam = findDevice(WebRTCUtils.getCameras(), track);\n }\n });\n}\n\n/**\n * Запрашивает камеру и микрофон пользователя\n * @internal\n */\nasync function _getUserMedia(mediaConstraints: MediaConstraints, lastError?: FatalError): Promise<MediaStream> {\n Debug.debug('Try to get media', JSON.parse(JSON.stringify(mediaConstraints.getNative())));\n\n const hasPermissions = (!mediaConstraints.isVideo() || WebRTCUtils.hasCameraPermission()) && (!mediaConstraints.isAudio() || WebRTCUtils.hasMicrophonePermission());\n\n if (!hasPermissions && !lastError) {\n External.onPermissionsRequested();\n }\n\n const mediaSouceLock = new MediaSourceLock();\n\n try {\n mediaSouceLock.busy();\n const stream = await navigator.mediaDevices.getUserMedia(mediaConstraints.getNative());\n mediaSouceLock.free();\n\n if (!hasPermissions) {\n await _updateDevices();\n }\n\n _updateSavedDevices(stream);\n return stream;\n } catch (e: any) {\n mediaSouceLock.free();\n\n Debug.error('getUserMedia error', e);\n\n switch (e.name) {\n case 'PermissionDeniedError':\n case 'PermissionDismissedError':\n case 'NotAllowedError':\n case 'SecurityError':\n case 'DOMException': // Странная ошибка валится когда есть доступ к микрофону, но нет к камере\n case 'NotFoundError': // Принято решение объединить ошибки, т.к. запрет на уровне системы иногда выгладит как отсутсвие\n // Нет разрешений на доступ к камере/микрофону\n lastError = mediaConstraints.isVideoRequested() ? FatalError.CAMERA_PERMISSION : FatalError.MIC_PERMISSION;\n break;\n\n case 'OverconstrainedError':\n // Просто запросим еще раз\n lastError = FatalError.OVERCONSTRAINED;\n break;\n\n case 'TypeError':\n lastError = FatalError.UNKNOWN;\n break;\n\n case 'AbortError':\n case 'NotReadableError':\n // Камера/микрофон заблокированы другим приложением\n lastError = mediaConstraints.isVideoRequested() ? FatalError.CAMERA_ACCESS : FatalError.MIC_ACCESS;\n break;\n\n case 'Error':\n // В сафари можно игнорить окно выбора экрана/окна для скриншары, в таком случае\n // getDisplayMedia висит в статусе pending, а navigator.mediaDevices заблокирован для других запросов\n // нужно показать пользователю что-то более осмысленное, чем просто \"ошибка\"\n if (e.message === 'MediaSource is busy') {\n lastError = mediaConstraints.isVideoRequested() ? FatalError.CAMERA_ACCESS : FatalError.MIC_ACCESS;\n break;\n }\n }\n\n if (mediaConstraints.canSimplify()) {\n return _getUserMedia(mediaConstraints.simplify(), lastError);\n }\n\n const error = lastError || FatalError.UNKNOWN;\n External.onPermissionsError(error, e);\n throw error;\n }\n}\n\n/**\n * Запрашивает трансляцию экрана\n * @internal\n */\nasync function _getDisplayMedia(mediaConstraints: ScreenConstraints): Promise<MediaStream> {\n Debug.debug('Try to get screen', JSON.parse(JSON.stringify(mediaConstraints.getNative())));\n\n const mediaSouceLock = new MediaSourceLock();\n\n try {\n mediaSouceLock.busy();\n\n const stream = await navigator.mediaDevices.getDisplayMedia(mediaConstraints.getNative());\n const track = stream?.getVideoTracks()[0];\n if (track) {\n const displaySurface = track.getSettings()?.displaySurface;\n Debug.debug(`Got display media track: ${track.id} (${displaySurface})`);\n\n track.contentHint = 'text';\n\n // Не фокусируемся на выбранное окно/вкладку\n if (mediaConstraints.captureController) {\n if (displaySurface === 'browser' || displaySurface === 'window') {\n try {\n mediaConstraints.captureController.setFocusBehavior('no-focus-change');\n } catch (e) {\n // Где-то падает со странными ошибками типа \"Failed to execute 'setFocusBehavior' on 'CaptureController': The window of opportunity for focus-decision is closed.\"\n Debug.warn('Failed to set focus behavior', e);\n }\n }\n }\n }\n\n return stream;\n } catch (e: any) {\n switch (e.name) {\n case 'PermissionDeniedError':\n case 'NotAllowedError':\n case 'SecurityError':\n // Запрос был отклонен\n throw FatalError.SCREEN_PERMISSION;\n\n default:\n throw FatalError.SCREEN_ACCESS;\n }\n } finally {\n mediaSouceLock.free();\n }\n}\n\n/**\n * Получает информацию о браузере\n * @internal\n */\nfunction _getBrowserInfo() {\n if (_browserData.length) {\n return _browserData;\n }\n\n _browserData = (() => {\n let tmp: RegExpMatchArray | null,\n isChromeBased = false,\n chromeVersion = 0,\n subVersion = '0';\n const M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\\/))\\/?\\s*(\\d+)/i) || [];\n\n if (/trident/i.test(M[1])) {\n tmp = /\\brv[ :]+(\\d+)/g.exec(ua);\n return ['IE', (tmp && tmp[1]) || 'Unknown', isChromeBased, chromeVersion, subVersion];\n }\n\n if (M[1] === 'Safari') {\n // Old Edge\n tmp = ua.match(/\\bEdge\\/(\\d+)/);\n if (tmp) {\n return ['Edge', tmp[1] || 'Unknown', isChromeBased, chromeVersion, subVersion];\n }\n\n // Chrome iOS\n tmp = ua.match(/\\bCriOS\\/(\\d+)/);\n if (tmp) {\n return ['Chrome', tmp[1], true, Number(tmp[1]), subVersion];\n }\n\n // Firefox iOS\n tmp = ua.match(/\\bFxiOS\\/(\\d+)/);\n if (tmp) {\n return ['Firefox', tmp[1], false, chromeVersion, subVersion];\n }\n\n // Yandex Browser iOS\n tmp = ua.match(/\\bYaBrowser\\/(\\d+)/);\n if (tmp) {\n return ['Yandex', tmp[1], false, chromeVersion, subVersion];\n }\n\n // Opera Touch iOS\n tmp = ua.match(/\\bOPT\\/(\\d+)/);\n if (tmp) {\n return ['Opera', tmp[1], false, chromeVersion, subVersion];\n }\n }\n\n if (M[1] === 'Chrome') {\n isChromeBased = true;\n chromeVersion = Number(M[2]);\n\n tmp = ua.match(/\\bOPR\\/(\\d+)/);\n if (tmp) {\n return ['Opera', tmp[1] || 'Unknown', isChromeBased, chromeVersion, subVersion];\n }\n\n tmp = ua.match(/\\bYaBrowser\\/(\\d+)/);\n if (tmp) {\n return ['Yandex', tmp[1] || 'Unknown', isChromeBased, chromeVersion, subVersion];\n }\n\n tmp = ua.match(/\\bSferum\\/((\\d+)(?:\\.\\d+)*)/);\n if (tmp) {\n // Для сферума отправляем полную версию, а не только первую цифру\n return ['Sferum', tmp[1] || 'Unknown', isChromeBased, chromeVersion, subVersion];\n }\n\n // New Edge\n tmp = ua.match(/\\bEdge?\\/(\\d+)/);\n if (tmp) {\n return ['Edge', tmp[1] || 'Unknown', isChromeBased, chromeVersion, subVersion];\n }\n\n // На домене ok.ru Opera почему-то отдаёт userAgent хрома\n if (typeof (window as any).opr !== 'undefined' && /^(.+\\.)?ok.ru$/.test(window.location.host)) {\n return ['Opera', 'Hidden', isChromeBased, chromeVersion, subVersion];\n }\n }\n\n tmp = ua.match(/version\\/(\\d+)(?:(?:\\.)(\\d+))?/i);\n if (tmp && tmp[2] !== undefined) {\n subVersion = tmp[2];\n }\n return [M[2] ? M[1] : an, (tmp && tmp[1]) || M[2] || av, isChromeBased, chromeVersion, subVersion];\n })();\n\n return _browserData;\n}\n\nnamespace WebRTCUtils {\n /**\n * До вызова этого метода бесполезно опрашивать другие публичные методы.\n * - Инициализирует устройства.\n * - Получает версию ОС\n */\n export async function init(): Promise<void> {\n await _getDevices();\n await _getOsVersion();\n }\n\n /**\n * Возвращает все подключенные камеры\n */\n export function getCameras(): MediaDeviceInfo[] {\n return _cameras;\n }\n\n /**\n * Возвращает все подключенные микрофоны\n */\n export function getMicrophones(): MediaDeviceInfo[] {\n return _microphones;\n }\n\n /**\n * Возвращает все подключенные динамики\n */\n export function getOutput(): MediaDeviceInfo[] {\n return _output;\n }\n\n /**\n * Есть ли у пользователя камера\n */\n export function hasCamera(): boolean {\n return _cameras.length > 0;\n }\n\n /**\n * Есть ли у пользователя микрофон\n */\n export function hasMicrophone(): boolean {\n return _microphones.length > 0;\n }\n\n /**\n * Возвращает сохраненную камеру пользователя, если она доступна\n */\n export function getSavedCamera(): MediaDeviceInfo | null {\n return _savedCam;\n }\n\n /**\n * Возвращает сохраненный микрофон пользователя, если он доступен\n */\n export function getSavedMicrophone(): MediaDeviceInfo | null {\n return _savedMic;\n }\n\n /**\n * Возвращает сохраненное устройство вывода\n */\n export function getSavedOutput(): MediaDeviceInfo | null {\n return _savedOutput;\n }\n\n /**\n * Возвращает тип используемой камеры (передняя или задняя)\n */\n export function getVideoFacingMode(): FacingMode | null {\n return Params.videoFacingMode;\n }\n\n /**\n * Проверяет получен ли доступ к камере\n */\n export function hasCameraPermission(): boolean {\n return _cameraPermissionGranted;\n }\n\n /**\n * Проверяет получен ли доступ к микрофону\n */\n export function hasMicrophonePermission(): boolean {\n return _microphonePermissionGranted;\n }\n\n export function getMicrophonePermissionState() {\n return _navigatorPermissions?.getPermissionState('microphone') ?? null;\n }\n\n /**\n * Проверяет получены ли разрешения, необходимые для текущего звонка\n */\n export function hasPermissions(needVideo = false): boolean {\n if (!hasMicrophonePermission()) {\n return false;\n }\n\n if (hasCamera() && needVideo) {\n return hasCameraPermission();\n }\n\n return true;\n }\n\n /**\n * Запрашивает камеру и микрофон пользователя\n *\n * @param needVideo Нужно ли видео\n * @param needAudio Нужно ли аудио\n * @param needEmptyTracks Добавлять ли в стрим пустые треки для отключенного видео/аудио\n */\n export async function getUserMedia(needVideo = false, needAudio = true, needEmptyTracks = true): Promise<MediaStream> {\n const audio = hasMicrophone() && needAudio;\n const video = hasCamera() && needVideo;\n let stream: MediaStream;\n\n if (!audio && !video) {\n // Звонок без камеры и микрофона\n stream = new MediaStream();\n } else {\n try {\n stream = await _getUserMedia(new MediaConstraints(audio, video));\n } catch (e) {\n stream = new MediaStream();\n }\n }\n\n if (!stream.getVideoTracks().length && needEmptyTracks) {\n stream.addTrack(WebRTCUtils.getBlackMediaTrack());\n }\n\n if (!stream.getAudioTracks().length && needEmptyTracks) {\n stream.addTrack(WebRTCUtils.getSilentMediaTrack());\n }\n\n return stream;\n }\n\n /**\n * Запрашивает трансляцию экрана пользователя с опциональным захватом звука\n */\n export async function getScreenMedia(fastScreenShare: boolean, withAudioShare: boolean): Promise<MediaStream> {\n const width = fastScreenShare && !Params.consumerFastScreenShare ? Params.fastScreenShareWidth : window.screen.width;\n const height = fastScreenShare && !Params.consumerFastScreenShare ? Params.fastScreenShareHeight : window.screen.height;\n const frameRate = Params.getScreenFrameRate(fastScreenShare);\n return _getDisplayMedia(new ScreenConstraints(width, height, frameRate, withAudioShare));\n }\n\n /**\n * Запрашивает камеру пользователя (приватный метод)\n *\n * @param effectEnabled Включен ли эффект видео\n * @internal\n */\n export async function _getUserVideo(effectEnabled = false, frameRate?: number): Promise<MediaStream> {\n const videoMaxWidth = effectEnabled ? Params.videoEffectMaxWidth : Params.videoMaxWidth;\n const videoMaxHeight = effectEnabled ? Params.videoEffectMaxHeight : Params.videoMaxHeight;\n\n return _getUserMedia(new MediaConstraints(false, true, videoMaxWidth, videoMaxHeight, frameRate));\n }\n\n /**\n * Запрашивает камеру пользователя\n *\n * @param deviceId ID устройства\n * @param resolution Размеры видео\n */\n export async function getUserVideo(deviceId?: string, resolution?: IVideoDimentions): Promise<MediaStream> {\n const width = resolution?.width || Params.videoMaxWidth;\n const height = resolution?.height || Params.videoMaxHeight;\n return _getUserMedia(new MediaConstraints(false, deviceId || true, width, height));\n }\n\n /**\n * Запрашивает микрофон пользователя\n *\n * @param deviceId ID устройства\n */\n export async function getUserAudio(deviceId?: string): Promise<MediaStream> {\n return _getUserMedia(new MediaConstraints(deviceId || true, false));\n }\n\n /**\n * Устанавливает размер видео в стриме\n *\n * @param stream\n * @param resolution\n */\n export async function setResolution(stream: MediaStream, resolution: IVideoDimentions): Promise<void> {\n const [track] = stream.getVideoTracks();\n if (!track) {\n throw new Error('Video track not found in stream');\n }\n return setVideoConstraints(track, resolution);\n }\n\n /**\n * Запоминает выбранное устройство\n * @internal\n */\n export async function _saveDeviceId(kind: MediaDeviceKind, deviceId: string): Promise<MediaDeviceInfo | null> {\n const devices = await _getDevices();\n const found = devices.find((device) => {\n return device.kind === kind && device.deviceId === deviceId;\n });\n if (found) {\n if (kind === 'videoinput') {\n _savedCam = found;\n } else if (kind === 'audioinput') {\n _savedMic = found;\n } else if (kind === 'audiooutput') {\n _savedOutput = found;\n }\n LocalStorage.set(kind, deviceId);\n return found;\n }\n return null;\n }\n\n /**\n * Возвращает фейковый аудио mediaTrack\n */\n export function getSilentMediaTrack(): MediaStreamTrack {\n if (!_silentMediaTrack || _silentMediaTrack.readyState === 'ended') {\n const context = WebRTCUtils.getAudioContext();\n const streamDest = context.createMediaStreamDestination();\n\n const volume = context.createGain();\n volume.gain.value = 0.00001;\n volume.connect(streamDest);\n volume.connect(context.destination);\n\n const oscillator = context.createOscillator();\n oscillator.type = 'sine';\n oscillator.frequency.value = 0;\n oscillator.connect(volume);\n oscillator.start();\n\n _silentMediaTrack = streamDest.stream.getAudioTracks()[0];\n }\n\n return Object.assign(_silentMediaTrack.clone(), { enabled: false });\n }\n\n /**\n * Возвращает фейковый видео mediaTrack\n */\n export function getBlackMediaTrack(width = Params.videoMinWidth, height = Params.videoMinHeight): MediaStreamTrack {\n // Create canvas\n if (!_blackCanvas) {\n _blackCanvas = document.createElement('canvas');\n }\n\n // Set canvas size\n _blackCanvas.width = width;\n _blackCanvas.height = height;\n\n // Fill canvas black\n const ctx = _blackCanvas.getContext('2d') as CanvasRenderingContext2D; // FF без этого падает, см: https://bugzilla.mozilla.org/show_bug.cgi?id=1388974\n ctx.rect(0, 0, width, height);\n ctx.fillStyle = 'black';\n ctx.fill();\n\n // Create track\n if (!_blackMediaTrack || _blackMediaTrack.readyState === 'ended') {\n // @ts-ignore\n const stream = _blackCanvas.captureStream(Params.videoFrameRate);\n _blackMediaTrack = stream.getVideoTracks()[0];\n }\n\n return Object.assign(_blackMediaTrack.clone(), { enabled: false });\n }\n\n /**\n * Проверяет поддержку WebRTC браузером\n */\n export function isBrowserSupported(): boolean {\n // Не поддерживаем старый Edge\n if (browserName() === 'Edge' && Number(browserVersion()) < 70) {\n return false;\n }\n try {\n const wnd: any = window;\n return (\n ('mediaDevices' in wnd.navigator &&\n 'getUserMedia' in wnd.navigator.mediaDevices &&\n wnd.RTCPeerConnection &&\n wnd.RTCIceCandidate &&\n wnd.RTCSessionDescription &&\n wnd.HTMLCanvasElement &&\n wnd.HTMLCanvasElement.prototype.captureStream &&\n wnd.RTCRtpSender &&\n wnd.RTCRtpSender.prototype.replaceTrack &&\n wnd.RTCRtpSender.prototype.getParameters &&\n 'sendBeacon' in navigator &&\n true) ||\n false\n );\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Проверяет поддержку шаринга экрана браузером\n */\n export function isScreenCapturingSupported(): boolean {\n return !!navigator.mediaDevices.getDisplayMedia;\n }\n\n /**\n * В некоторых браузерах H264 decoder сломан\n */\n export function isBrokenH264Decoder(): boolean {\n // https://jira.mvk.com/browse/CALL-6789\n const isSafariH264Broken = WebRTCUtils.browserName() === 'Safari' && WebRTCUtils.browserVersion() === '15' && WebRTCUtils.browserSubVersion() === '1';\n // https://jira.mvk.com/browse/CALL-23933\n const isOperaBroken = WebRTCUtils.browserName() === 'Opera';\n const isYandexBroken = WebRTCUtils.browserName() === 'Yandex';\n return isSafariH264Broken || isOperaBroken || isYandexBroken;\n }\n\n /**\n * В некоторых браузерах VP9 encoder сломан\n * В симулкасте вп9 енкодер ведет себя некорректно\n */\n export function isBrokenVP9Encoder(): boolean {\n return (WebRTCUtils.browserName() === 'Yandex' && WebRTCUtils.os() === 'Windows') || Params.simulcast;\n }\n\n /**\n * В некоторых браузерах VP9 decoder сломан\n */\n export function isBrokenVP9Decoder(): boolean {\n const safariIssue = WebRTCUtils.browserName() === 'Safari' && Number(WebRTCUtils.browserVersion()) === 17 && [4, 5, 6].includes(Number(WebRTCUtils.browserSubVersion()));\n const win10Issue = WebRTCUtils.os() === 'Windows' && WebRTCUtils.osVersion() === 10;\n\n return safariIssue || win10Issue;\n }\n\n /**\n * Изменился формат описания датаканала в SDP\n * @link https://blog.mozilla.org/webrtc/how-to-avoid-data-channel-breaking/\n */\n export function isOldDataChannelDescription(): boolean {\n return WebRTCUtils.browserName() === 'Firefox' && Number(WebRTCUtils.browserVersion()) < 60;\n }\n\n /**\n * Может ли браузер делать H264 приоритетным\n */\n export function canPreferH264(): boolean {\n // Мобильный хром не умеет\n return !(WebRTCUtils.baseChromeVersion() && WebRTCUtils.isMobile());\n }\n\n /**\n * Некоторые браузеры (Firefox, Safari) некорректно поддерживают симулкаст\n */\n export function isSimulcastSupportedByBrowser(): boolean {\n return !(WebRTCUtils.browserName() === 'Firefox' || WebRTCUtils.browserName() === 'Safari');\n }\n\n /**\n * Имя операционной системы\n */\n export function os(): string {\n if (!_os) {\n _os = (() => {\n const clientStrings: { [key: string]: RegExp } = {\n Windows: /Win/,\n Android: /Android/,\n OpenBSD: /OpenBSD/,\n SunOS: /SunOS/,\n Linux: /(Linux|X11)/,\n iPad: /(iPad)/,\n iPhone: /(iPhone)/,\n iPod: /(iPod)/,\n MacOS: /(MacPPC|MacIntel|Mac_PowerPC|Macintosh|Mac OS X)/,\n QNX: /QNX/,\n UNIX: /UNIX/,\n BeOS: /BeOS/,\n OS2: /OS\\/2/,\n Bot: /(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\\/Teoma|ia_archiver)/,\n };\n\n for (const name in clientStrings) {\n if (Object.hasOwn(clientStrings, name) && clientStrings[name].test(ua)) {\n return name;\n }\n }\n return 'Unknown';\n })();\n }\n return _os;\n }\n\n /**\n * Версия операционной системы\n */\n export function osVersion(): number | null | undefined {\n return _osVersion;\n }\n\n /**\n * Мобильный браузер или нет\n */\n export function isMobile(): boolean {\n if (_isMobile === null) {\n _isMobile = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(av);\n }\n return _isMobile;\n }\n\n /**\n * Имя браузера\n */\n export function browserName(): BrowserName | string {\n return _getBrowserInfo()[0];\n }\n\n /**\n * Версия браузера\n */\n export function browserVersion(): string {\n return _getBrowserInfo()[1];\n }\n\n /**\n * Если браузер основан на хроме - возвращает версию\n */\n export function baseChromeVersion(): number {\n return _getBrowserInfo()[3];\n }\n\n /**\n * Возвращает AudioContext\n */\n export function getAudioContext(): AudioContext {\n if (!_audioContext) {\n _audioContext = new (window.AudioContext || window.webkitAudioContext)();\n }\n // AudioContext может быть suspended политиками автоплея браузера. Принудительно запускаем его\n _audioContext.resume().catch(() => {\n Debug.warn('Failed to resume AudioContext');\n });\n return _audioContext;\n }\n\n /**\n * Возвращает подверсию браузера (если она есть)\n */\n export function browserSubVersion(): string {\n return _getBrowserInfo()[4];\n }\n\n /**\n * Браузер поддерживает захват звука при трансляции экрана\n */\n export function isAudioShareSupported(): boolean {\n return WebRTCUtils.baseChromeVersion() >= 105 && !WebRTCUtils.isMobile();\n }\n\n /**\n * @internal\n */\n export function addEventListener(event: 'devicechange', listener: CallableFunction) {\n if (!eventListeners[event]) {\n eventListeners[event] = [];\n }\n eventListeners[event].push(listener);\n }\n\n /**\n * @internal\n */\n export function removeEventListener(event: 'devicechange', listener?: CallableFunction) {\n if (!eventListeners[event]) {\n return;\n }\n\n if (!listener) {\n delete eventListeners[event];\n } else {\n const index = eventListeners[event].indexOf(listener);\n if (index > -1) {\n eventListeners[event].splice(index, 1);\n }\n }\n }\n}\n\nexport default WebRTCUtils;\n", "import { CurrentLogItem } from '../utils/DebugStorage';\nimport WebRTCUtils from './WebRTCUtils';\nimport Params from './Params';\n\nexport class ConversationDebugLogger {\n private static _list: CurrentLogItem[] = [];\n private static _conversationId: string | null = null;\n\n static get startTime() {\n return ConversationDebugLogger._list[0]?.t || 0;\n }\n\n static get endTime() {\n const list = ConversationDebugLogger._list;\n return list[list.length - 1]?.t || 0;\n }\n\n static startSession() {\n ConversationDebugLogger._list = [];\n }\n\n static get conversationId(): string | null {\n return ConversationDebugLogger._conversationId;\n }\n\n static set conversationId(conversationId: string | null) {\n ConversationDebugLogger._conversationId = conversationId;\n }\n\n static add(item: CurrentLogItem) {\n ConversationDebugLogger._list.push(item);\n }\n\n private static _createContextLogs() {\n const data = [\n [`Calls SDK ${Params.sdkVersion}`, Params.toJSON()],\n ['UserAgent:', navigator.userAgent],\n ['Screen resolution:', `${window.screen.width}x${window.screen.height}`],\n ['Permissions:', `Camera: ${WebRTCUtils.hasCameraPermission()}, Mic: ${WebRTCUtils.hasMicrophonePermission()}`],\n ];\n\n const date = new Date();\n const time = date.getTime();\n const humanTime = date.toLocaleString('ru-RU', { dateStyle: 'short', timeStyle: 'long' });\n\n return data.map((item) => {\n return {\n h: humanTime,\n t: time,\n l: 'LOG',\n d: item,\n };\n });\n }\n\n static collectLogs() {\n const list = ConversationDebugLogger._list;\n if (list.length === 0) {\n return [];\n }\n\n const contextLogs = ConversationDebugLogger._createContextLogs();\n\n return [...contextLogs, ...list];\n }\n}\n", "import IList from './IList';\n\nexport class ArrayList<T = never> implements IList<T> {\n private _items: T[] = [];\n\n get length(): number {\n return this._items.length;\n }\n\n push(...data: T[]): void {\n this._items.push(...data);\n }\n\n merge(data: ArrayList<T>): void {\n this._items.push(...data._items);\n }\n\n shift(): T | null {\n return this._items.shift() || null;\n }\n\n bisect(): void {\n const center = this.length > 1 ? Math.floor(this.length / 2) : 1;\n this._items = this._items.slice(center);\n }\n\n head(): T | null {\n return this._items[0] || null;\n }\n\n tail(): T | null {\n const len = this._items.length;\n return len ? this._items[len - 1] : null;\n }\n\n clear(): void {\n this._items = [];\n }\n\n toString(): string {\n if (!this._items.length) {\n return '';\n }\n return JSON.stringify(this._items, (key, value) => {\n if (value instanceof Error) {\n return String(value);\n }\n return value;\n });\n }\n}\n", "import { ConversationDebugLogger } from '../static/ConversationDebugLogger';\nimport { ArrayList } from './ArrayList';\nimport IList from './IList';\n\nconst MAX_STORAGE_BYTES = 2 * 1024 * 1024; // 2Mb для всех логов\nconst MAX_LOG_BYTES = 512 * 1024; // 512Kb для одного лога\nconst MIN_FREE_STORAGE = 100 * 1024; // Оставляем 100Kb свободного стораджа минимум\nconst MAX_SAVED_SESSIONS = 5; // Количество сессий для хранения\nconst STORAGE_PREFIX = '_okcls_logs_session_';\nconst SAVE_TIME_MS = 30000;\n\ntype SavedLogItem = {\n readonly key: string; // Ключ в сторадже\n readonly size: number; // Размер сжатых данных в сторадже\n readonly date: number; // Дата из ключа для сортировки\n};\n\nexport type CurrentLogItem = {\n readonly t: number; // Время\n readonly l: string; // Уровень лога\n readonly d: any[]; // Данные\n readonly h: string; // Время в человеческом формате\n};\n\nclass SavedLog {\n private readonly _items: SavedLogItem[] = [];\n private _itemsSize = 0;\n private _storageSize = MAX_STORAGE_BYTES;\n\n constructor() {\n try {\n const st = window.localStorage;\n for (const key of Object.keys(st)) {\n if (key.indexOf(STORAGE_PREFIX) !== 0) {\n continue;\n }\n\n const log = st.getItem(key) as string;\n if (!log) {\n // Удаляем пустой лог\n deleteLogFromStorage(key);\n continue;\n }\n\n const size = strSizeBytes(log); // Размер сжатого лога в сторадже\n this.add(key, size);\n }\n } catch (e) {\n console.error('Storage is blocked', e); // Don't use Debug.error() here\n this._storageSize = 0;\n }\n\n // Сортируем по дате\n this._items.sort((a, b) => a.date - b.date);\n this.cleanup(MIN_FREE_STORAGE);\n }\n\n get size() {\n return this._itemsSize;\n }\n\n get length() {\n return this._items.length;\n }\n\n get available() {\n return Math.max(this._storageSize - this._itemsSize, 0);\n }\n\n get items() {\n return this._items;\n }\n\n set storageSize(size: number) {\n this._storageSize = Math.min(size, this._storageSize, MAX_STORAGE_BYTES);\n }\n\n add(key: string, size: number) {\n const date = parseInt(key.replace(STORAGE_PREFIX, ''), 10);\n this._itemsSize += size;\n this._items.push({ key, size, date });\n }\n\n deleteOldestItem() {\n const log = this._items.shift();\n if (log) {\n deleteLogFromStorage(log.key);\n this._itemsSize -= log.size;\n }\n }\n\n cleanup(sizeNeeded: number) {\n while (this.length && (this.size > MAX_STORAGE_BYTES || this.length > MAX_SAVED_SESSIONS - 1 || this.size + sizeNeeded > this.available)) {\n this.deleteOldestItem();\n }\n }\n}\n\nfunction createLogName() {\n return `${STORAGE_PREFIX}${Date.now()}`;\n}\n\nfunction strSizeBytes(str: string): number {\n return new Blob([str]).size;\n}\n\nfunction deleteLogFromStorage(key: string) {\n try {\n window.localStorage.removeItem(key);\n } catch (e) {\n console.error('Failed to remove log from storage', e);\n }\n}\n\nfunction _writeLogToStorage() {\n const log = list.toString();\n\n // Нет доступного хранилища или лог пустой\n if (!savedLog.available || !log) {\n return;\n }\n\n const size = strSizeBytes(log);\n\n if (size > MAX_LOG_BYTES) {\n // Размер лога в памяти слишком большой\n list.bisect();\n _writeLogToStorage();\n return;\n }\n\n // Удаляем устаревшие записи лога\n savedLog.cleanup(MIN_FREE_STORAGE + size);\n\n try {\n window.localStorage.setItem(logName, log);\n } catch (e) {\n // Usually it's QuotaExceededError, but handle all errors\n console.warn('Failed to write log to storage', e);\n\n // Уменьшаем размер хранилища\n savedLog.storageSize = savedLog.size + size;\n savedLog.cleanup(MIN_FREE_STORAGE + size);\n\n if (savedLog.available >= MIN_FREE_STORAGE + size) {\n _writeLogToStorage();\n return;\n }\n\n // Обрезаем данные\n if (size > MIN_FREE_STORAGE) {\n list.bisect();\n _writeLogToStorage();\n return;\n }\n\n // Ничего не помогло, больше писать не можем\n savedLog.storageSize = 0;\n return;\n }\n\n // Если лог превысил размер, меняем имя лога и сбрасываем его в сохраненные\n if (size > MAX_LOG_BYTES) {\n savedLog.add(logName, size);\n logName = createLogName();\n list.clear();\n savedLog.cleanup(MIN_FREE_STORAGE);\n }\n}\n\nfunction flushLog() {\n if (!savedLog.available || !list.length) {\n return;\n }\n\n _writeLogToStorage();\n}\n\nfunction getLogs(noDownload = false): string {\n const result = [];\n try {\n const st = window.localStorage;\n for (const item of savedLog.items) {\n const log = st.getItem(item.key) as string;\n result.push(log);\n }\n const current = list.toString();\n if (current) {\n result.push(current);\n }\n } catch (e) {\n console.error('Storage is blocked', e); // Don't use Debug.error() here\n }\n\n const text = `[${result.join(',')}]`;\n if (noDownload) {\n return text;\n }\n\n const filename = `logs_${Date.now()}.json`;\n downloadLog(text, filename);\n return filename;\n}\n\nfunction downloadLog(data: string, name: string) {\n const a = document.createElement('a');\n const file = new Blob([data], { type: 'text/json' });\n a.href = URL.createObjectURL(file);\n a.download = name;\n a.click();\n}\n\nexport function add(level: string, args: any[]) {\n // Нет доступного хранилища\n if (!savedLog.available) {\n return;\n }\n\n const date = new Date();\n const logItem: CurrentLogItem = {\n t: date.getTime(),\n l: level,\n d: args,\n h: date.toLocaleString('ru-RU', { dateStyle: 'short', timeStyle: 'long' }),\n };\n list.push(logItem);\n ConversationDebugLogger.add(logItem);\n\n if (!saveLogTimeout) {\n // Сохраняем раз в SAVE_TIME_MS\n saveLogTimeout = window.setTimeout(() => {\n saveLogTimeout = null;\n flushLog();\n }, SAVE_TIME_MS);\n }\n}\n\nexport function init() {\n if (savedLog) {\n // Уже проинициализированы\n return;\n }\n\n savedLog = new SavedLog();\n list = new ArrayList();\n logName = createLogName();\n\n window.addEventListener('beforeunload', flushLog);\n}\n\nlet savedLog: SavedLog;\nlet list: IList<CurrentLogItem>;\nlet logName: string;\nlet saveLogTimeout: number | null = null;\n\n(window as any).__VKCallsSDKLogs__ = (noDownload = false) => {\n if (!savedLog) {\n // Если вызвали метод до инициализации\n init();\n }\n flushLog();\n return getLogs(noDownload);\n};\n", "import * as DebugStorage from '../utils/DebugStorage';\nimport External from './External';\nimport Params from './Params';\n\n/**\n * Тип отладочного сообщения\n */\nexport enum DebugMessageType {\n DEBUG = 'DEBUG',\n LOG = 'LOG',\n WARN = 'WARN',\n ERROR = 'ERROR',\n}\n\nnamespace Debug {\n const _prefix = '📞';\n const _onDebugMessage = (type: DebugMessageType, ...args: any[]) => {\n External.onDebugMessage(type, ...args);\n };\n let _enabled = false;\n\n const _wrap = (fn: Function, level: DebugMessageType) => {\n return (...args: any[]) => {\n fn(...args);\n DebugStorage.add(level, args);\n };\n };\n\n const _consoleDebug: Function = console.debug.bind(console, _prefix);\n const _consoleLog: Function = console.log.bind(console, _prefix);\n const _consoleWarn: Function = console.warn.bind(console, _prefix);\n const _consoleError: Function = console.error.bind(console, _prefix);\n\n const _externalDebug: Function = _onDebugMessage.bind(null, DebugMessageType.DEBUG);\n const _externalLog: Function = _onDebugMessage.bind(null, DebugMessageType.LOG);\n const _externalWarn: Function = _onDebugMessage.bind(null, DebugMessageType.WARN);\n const _externalError: Function = _onDebugMessage.bind(null, DebugMessageType.ERROR);\n\n export let debug: Function = _externalDebug;\n export let log: Function = _externalLog;\n export let warn: Function = _externalWarn;\n export let error: Function = _externalError;\n\n export function enabled() {\n return _enabled;\n }\n\n export function toggle(enable: boolean) {\n _enabled = enable;\n\n if (Params.debugLog) {\n DebugStorage.init();\n }\n\n if (enable) {\n debug = Params.debugLog ? _wrap(_consoleDebug, DebugMessageType.DEBUG) : _consoleDebug;\n log = Params.debugLog ? _wrap(_consoleLog, DebugMessageType.LOG) : _consoleLog;\n warn = Params.debugLog ? _wrap(_consoleWarn, DebugMessageType.WARN) : _consoleWarn;\n error = Params.debugLog ? _wrap(_consoleError, DebugMessageType.ERROR) : _consoleError;\n } else {\n debug = Params.debugLog ? _wrap(_externalDebug, DebugMessageType.DEBUG) : _externalDebug;\n log = Params.debugLog ? _wrap(_externalLog, DebugMessageType.LOG) : _externalLog;\n warn = Params.debugLog ? _wrap(_externalWarn, DebugMessageType.WARN) : _externalWarn;\n error = Params.debugLog ? _wrap(_externalError, DebugMessageType.ERROR) : _externalError;\n }\n }\n\n export function send(type: DebugMessageType, ...args: any[]) {\n switch (type) {\n case DebugMessageType.DEBUG:\n debug(...args);\n break;\n case DebugMessageType.LOG:\n log(...args);\n break;\n case DebugMessageType.WARN:\n warn(...args);\n break;\n case DebugMessageType.ERROR:\n error(...args);\n break;\n }\n }\n\n export function test(tag: string, ...args: any[]) {}\n}\n\nexport default Debug;\n", "import { Layout, RequestKeyFrame, StopStream } from './ParticipantLayout';\n\nexport const REQUEST_KEY_FRAME_CODE = 'kf';\n\nexport function isStopStreaming(layout: Layout | StopStream | RequestKeyFrame): layout is StopStream {\n return (layout as StopStream).stopStream;\n}\n\nexport function isRequestKeyFrame(layout: Layout | StopStream | RequestKeyFrame): layout is RequestKeyFrame {\n return (layout as RequestKeyFrame).keyFrameRequested;\n}\n\nexport function layoutToString(layout: Layout | StopStream | RequestKeyFrame) {\n if (isStopStreaming(layout)) {\n return 'ss';\n }\n\n if (isRequestKeyFrame(layout)) {\n return REQUEST_KEY_FRAME_CODE;\n }\n\n let result = '';\n if (layout.priority !== undefined) {\n result += 'p=' + layout.priority;\n }\n if (layout.width !== undefined && layout.height !== undefined) {\n if (result !== '') {\n result += ':';\n }\n result += 'sz=' + Math.round(layout.width) + 'x' + Math.round(layout.height);\n }\n if (layout.fit !== undefined) {\n if (result !== '') {\n result += ':';\n }\n result += 'fit=' + layout.fit;\n }\n return result;\n}\n", "import Utils, { DEVICE_IDX_PARAMETER, PARAMETERS_SEPARATOR } from '../static/Utils';\nimport { CompositeUserId, ParticipantId } from './Participant';\n\n/**\n * Тип пользовательского медиа\n */\nexport enum MediaType {\n CAMERA = 'CAMERA',\n SCREEN = 'SCREEN',\n STREAM = 'STREAM',\n MOVIE = 'MOVIE',\n ANIMOJI = 'ANIMOJI',\n SHARED_URL = 'SHARED_URL',\n}\n\nconst MEDIA_TYPE_PARAMETER = 's';\nconst MOVIE_ID_PARAMETER = 'm';\n\nexport function serializeParticipantStreamDescription(description: ParticipantStreamDescription): StreamDescriptionString {\n return (\n description.participantId +\n (description.mediaType ? PARAMETERS_SEPARATOR + MEDIA_TYPE_PARAMETER + description.mediaType : '') +\n (description.streamName ? PARAMETERS_SEPARATOR + MOVIE_ID_PARAMETER + description.streamName : '')\n );\n}\n\nexport function parseParticipantStreamDescription(descriptionString: StreamDescriptionString): ParticipantStreamDescription {\n const tokens = descriptionString.split(PARAMETERS_SEPARATOR);\n\n const userId = tokens.shift();\n if (!userId) {\n throw new Error('Illegal stream description: ' + descriptionString);\n }\n\n let mediaType: MediaType | null = null;\n let streamName: string | undefined;\n let deviceIdx = 0;\n\n for (const token of tokens) {\n switch (token.charAt(0)) {\n case MEDIA_TYPE_PARAMETER:\n mediaType = parseMediaType(token.slice(1));\n break;\n case MOVIE_ID_PARAMETER:\n streamName = token.slice(1);\n break;\n case DEVICE_IDX_PARAMETER:\n deviceIdx = Number.parseInt(token.slice(1), 10);\n break;\n default:\n throw new Error('Unexpected parameter type ' + token.charAt(0) + ' in stream description ' + descriptionString);\n }\n }\n\n const participantId = Utils.compose(userId, deviceIdx);\n return {\n participantId,\n mediaType,\n streamName,\n };\n}\n\nfunction parseMediaType(val: string): MediaType | null {\n for (const key of Object.keys(MediaType)) {\n if (key === val) {\n return MediaType[key as keyof typeof MediaType];\n }\n }\n return null;\n}\n\n// Содержит тип, id пользователя, девайс, mediaType и streamName\nexport type StreamDescriptionString = string;\n\nexport type ParticipantStreamDescription = {\n participantId: ParticipantId;\n mediaType: MediaType | null;\n streamName?: string;\n};\n", "/**\n * Fork from messagepack internals.\n * Package messagepack doesn't export createWriteBuffer and createReadBuffer methods.\n */\nexport function createWriteBuffer() {\n let view = new DataView(new ArrayBuffer(64));\n let n = 0;\n function need(x: number) {\n if (n + x > view.byteLength) {\n const arr = new Uint8Array(Math.max(n + x, view.byteLength + 64));\n arr.set(new Uint8Array(view.buffer.slice(0, n)));\n view = new DataView(arr.buffer);\n }\n }\n return {\n put(v: BufferSource) {\n need(v.byteLength);\n if (isArrayBufferView(v)) {\n const buffer = (v as ArrayBufferView).buffer;\n new Uint8Array(view.buffer).set(new Uint8Array(buffer), n);\n } else {\n new Uint8Array(view.buffer).set(new Uint8Array(v), n);\n }\n n += v.byteLength;\n },\n putI8(v: number) {\n need(1);\n view.setInt8(n, v);\n ++n;\n },\n putI16(v: number) {\n need(2);\n view.setInt16(n, v);\n n += 2;\n },\n putI32(v: number) {\n need(4);\n view.setInt32(n, v);\n n += 4;\n },\n putI64(v: number) {\n need(8);\n const neg = v < 0;\n if (neg) {\n v = -v;\n }\n let hi = (v / 0x100000000) | 0;\n let lo = v % 0x100000000 | 0;\n if (neg) {\n // 2s complement\n lo = (~lo + 1) | 0;\n hi = lo === 0 ? (~hi + 1) | 0 : ~hi;\n }\n view.setUint32(n, hi);\n view.setUint32(n + 4, lo);\n n += 8;\n },\n putUi8(v: number) {\n need(1);\n view.setUint8(n, v);\n ++n;\n },\n putUi16(v: number) {\n need(2);\n view.setUint16(n, v);\n n += 2;\n },\n putUi32(v: number) {\n need(4);\n view.setUint32(n, v);\n n += 4;\n },\n putUi64(v: number) {\n need(8);\n view.setUint32(n, (v / 0x100000000) | 0);\n view.setUint32(n + 4, v % 0x100000000);\n n += 8;\n },\n putF(v: number) {\n need(8);\n view.setFloat64(n, v);\n n += 8;\n },\n ui8array() {\n return new Uint8Array(view.buffer.slice(0, n));\n },\n };\n}\n\nfunction isArrayBufferView(v: BufferSource): v is ArrayBufferView {\n return (v as ArrayBufferView).buffer !== undefined;\n}\n\nexport function createReadBuffer(buf: BufferSource) {\n const view = ArrayBuffer.isView(buf) ? new DataView(buf.buffer, buf.byteOffset, buf.byteLength) : new DataView(buf);\n let n = 0;\n return {\n peek() {\n return view.getUint8(n);\n },\n get(len: number) {\n n += len;\n const off = view.byteOffset;\n return (view.buffer as ArrayBuffer).slice(off + n - len, off + n);\n },\n getI8() {\n return view.getInt8(n++);\n },\n getI16() {\n n += 2;\n return view.getInt16(n - 2);\n },\n getI32() {\n n += 4;\n return view.getInt32(n - 4);\n },\n getI64() {\n n += 8;\n const hi = view.getInt32(n - 8);\n const lo = view.getUint32(n - 4);\n return hi * 0x100000000 + lo;\n },\n getUi8() {\n return view.getUint8(n++);\n },\n getUi16() {\n n += 2;\n return view.getUint16(n - 2);\n },\n getUi32() {\n n += 4;\n return view.getUint32(n - 4);\n },\n getUi64() {\n n += 8;\n const hi = view.getUint32(n - 8);\n const lo = view.getUint32(n - 4);\n return hi * 0x100000000 + lo;\n },\n getF32() {\n n += 4;\n return view.getFloat32(n - 4);\n },\n getF64() {\n n += 8;\n return view.getFloat64(n - 8);\n },\n };\n}\n", "import Stat from './Stat';\n\nexport const enum SignalingTransportType {\n WEBSOCKET = 'ws',\n WEBTRANSPORT = 'wt',\n}\n\nexport const enum SignalingTransportStat {\n CONNECTED = 'connected',\n RECONNECTED = 'reconnected',\n FAILED_PINGS = 'failed_pings',\n FAILED_EXCEPTIONS = 'failed_exception',\n TIMEOUT = 'timeout',\n RESTART = 'restart',\n}\n\nexport const SOCKET_STAT: Record<SignalingTransportStat, { [SignalingTransportType.WEBSOCKET]: Stat; [SignalingTransportType.WEBTRANSPORT]: Stat }> = {\n [SignalingTransportStat.CONNECTED]: {\n [SignalingTransportType.WEBTRANSPORT]: Stat.WEBTRANSPORT_CONNECTED,\n [SignalingTransportType.WEBSOCKET]: Stat.WEBSOCKET_CONNECTED,\n },\n [SignalingTransportStat.RECONNECTED]: {\n [SignalingTransportType.WEBTRANSPORT]: Stat.WEBTRANSPORT_RECONNECTED,\n [SignalingTransportType.WEBSOCKET]: Stat.WEBSOCKET_RECONNECTED,\n },\n [SignalingTransportStat.FAILED_PINGS]: {\n [SignalingTransportType.WEBTRANSPORT]: Stat.WEBTRANSPORT_FAILED_PINGS,\n [SignalingTransportType.WEBSOCKET]: Stat.WEBSOCKET_FAILED_PINGS,\n },\n [SignalingTransportStat.FAILED_EXCEPTIONS]: {\n [SignalingTransportType.WEBTRANSPORT]: Stat.WEBTRANSPORT_FAILED_EXCEPTION,\n [SignalingTransportType.WEBSOCKET]: Stat.WEBSOCKET_FAILED_EXCEPTION,\n },\n [SignalingTransportStat.TIMEOUT]: {\n [SignalingTransportType.WEBTRANSPORT]: Stat.WEBTRANSPORT_TIMEOUT,\n [SignalingTransportType.WEBSOCKET]: Stat.WEBSOCKET_TIMEOUT,\n },\n [SignalingTransportStat.RESTART]: {\n [SignalingTransportType.WEBTRANSPORT]: Stat.WEBTRANSPORT_RESTART,\n [SignalingTransportType.WEBSOCKET]: Stat.WEBSOCKET_RESTART,\n },\n};\n", "/**\n * Класс, реализующий возможность найти медиану или другой персентиль не храня весь поток данных для расчета\n */\nexport class P2Quantile {\n // Оценивает один квантиль q \\in (0,1) по алгоритму P2\n private readonly q: number;\n private inits: number[] = []; // до 5 первых значений\n private n: number[] = [1, 2, 3, 4, 5]; // позиции маркеров\n private np: number[] = [1, 1, 1, 1, 1]; // желаемые позиции\n private qv: number[] = []; // высоты маркеров (значения)\n\n constructor(q: number) {\n if (!(q > 0 && q < 1)) throw new Error('q must be in (0,1)');\n this.q = q;\n }\n\n add(x: number) {\n if (this.inits.length < 5) {\n this.inits.push(x);\n if (this.inits.length === 5) this.bootstrap();\n return;\n }\n\n // Обновить маркеры\n // 1) найти k: позиция x относительно qv[]\n let k = 0;\n if (x < this.qv[0]) {\n this.qv[0] = x;\n k = 0;\n } else if (x >= this.qv[4]) {\n this.qv[4] = x;\n k = 3;\n } else {\n while (!(x < this.qv[k + 1])) k++;\n }\n\n // 2) инкремент реальных позиций\n for (let i = 0; i < 5; i++) this.n[i] += i <= k ? 0 : 1;\n\n // 3) обновить желаемые позиции\n this.np[0] = 1;\n this.np[1] += this.q / 2;\n this.np[2] += this.q;\n this.np[3] += (1 + this.q) / 2;\n this.np[4] += 1;\n\n // 5) попытаться сдвинуть внутренние маркеры 1..3\n for (let i = 1; i <= 3; i++) {\n const d = this.np[i] - this.n[i];\n if ((d >= 1 && this.n[i + 1] - this.n[i] > 1) || (d <= -1 && this.n[i] - this.n[i - 1] > 1)) {\n const sign = Math.sign(d);\n // параболическая интерполяция\n const qip =\n this.qv[i] +\n (sign / (this.n[i + 1] - this.n[i - 1])) *\n (((this.n[i] - this.n[i - 1] + sign) * (this.qv[i + 1] - this.qv[i])) / (this.n[i + 1] - this.n[i]) +\n ((this.n[i + 1] - this.n[i] - sign) * (this.qv[i] - this.qv[i - 1])) / (this.n[i] - this.n[i - 1]));\n\n // если qip внутри [qv[i-1], qv[i+1]] — принять, иначе линейный шаг\n if (qip > this.qv[i - 1] && qip < this.qv[i + 1]) {\n this.qv[i] = qip;\n } else {\n this.qv[i] = this.qv[i] + (sign * (this.qv[i + sign] - this.qv[i])) / (this.n[i + sign] - this.n[i]);\n }\n this.n[i] += sign;\n }\n }\n }\n\n value(): number {\n if (this.inits.length === 0) return NaN;\n if (this.inits.length < 5) {\n const sorted = [...this.inits].sort((a, b) => a - b);\n const pos = this.q * (sorted.length - 1);\n const i = Math.floor(pos);\n const frac = pos - i;\n return i + 1 < sorted.length ? sorted[i] * (1 - frac) + sorted[i + 1] * frac : sorted[i];\n }\n return this.qv[2]; // центральный маркер — целевой квантиль\n }\n\n private bootstrap() {\n this.inits.sort((a, b) => a - b);\n this.qv = this.inits.slice(0, 5);\n // инициализация желаемых позиций согласно оригиналу\n this.n = [1, 2, 3, 4, 5];\n this.np = [1, 1 + 2 * this.q, 1 + 4 * this.q, 3 + 2 * this.q, 5];\n }\n}\n", "/**\n * Класс, реализующий алгоритм для подсчета среднего налету без хранения чисел\n */\nexport class Welford {\n private n = 0;\n private mean = 0;\n\n public add(x: number) {\n this.n++;\n const delta = x - this.mean;\n this.mean += delta / this.n;\n }\n\n get avg() {\n return this.n ? this.mean : NaN;\n }\n}\n", "import { P2Quantile } from './P2Quantile';\nimport { Welford } from './Welford';\n\nexport class StatTracker {\n private count = 0;\n private minVal = Infinity;\n private maxVal = -Infinity;\n private mean = new Welford();\n private p50 = new P2Quantile(0.5);\n private p95 = new P2Quantile(0.95);\n\n add(x: number) {\n if (x < this.minVal) this.minVal = x;\n if (x > this.maxVal) this.maxVal = x;\n this.mean.add(x);\n this.p50.add(x);\n this.p95.add(x);\n\n this.count++;\n }\n\n snapshot() {\n return {\n min: this.minVal === Infinity ? NaN : this.minVal,\n max: this.maxVal === -Infinity ? NaN : this.maxVal,\n avg: +this.mean.avg.toFixed(),\n median: +this.p50.value().toFixed(),\n p95: +this.p95.value().toFixed(),\n count: this.count,\n };\n }\n\n get hasData() {\n return this.count > 0;\n }\n}\n", "const enum SignalingEvent {\n NOTIFICATION = 'NOTIFICATION',\n FAILED = 'FAILED',\n RECONNECT = 'RECONNECT',\n}\n\nexport default SignalingEvent;\n", "enum SignalingNotification {\n TRANSMITTED_DATA = 'transmitted-data',\n ACCEPTED_CALL = 'accepted-call',\n HUNGUP = 'hungup',\n PARTICIPANT_ADDED = 'participant-added',\n PARTICIPANT_JOINED = 'participant-joined',\n CLOSED_CONVERSATION = 'closed-conversation',\n MEDIA_SETTINGS_CHANGED = 'media-settings-changed',\n PARTICIPANT_STATE_CHANGED = 'participant-state-changed',\n PARTICIPANTS_STATE_CHANGED = 'participants-state-changed',\n RATE_CALL_DATA = 'rate-call-data',\n FEATURE_SET_CHANGED = 'feature-set-changed',\n TOPOLOGY_CHANGED = 'topology-changed',\n PRODUCER_UPDATED = 'producer-updated',\n CONSUMER_ANSWERED = 'consumer-answered',\n MULTIPARTY_CHAT_CREATED = 'multiparty-chat-created',\n FORCE_MEDIA_SETTINGS_CHANGE = 'force-media-settings-change',\n SETTINGS_UPDATE = 'settings-update',\n VIDEO_QUALITY_UPDATE = 'video-quality-update',\n REGISTERED_PEER = 'registered-peer',\n SWITCH_MICRO = 'switch-micro',\n RECORD_STARTED = 'record-started',\n RECORD_STOPPED = 'record-stopped',\n REALLOC_CON = 'realloc-con',\n AUDIO_ACTIVITY = 'audio-activity',\n SPEAKER_CHANGED = 'speaker-changed',\n STALLED_ACTIVITY = 'stalled-activity',\n CHAT_MESSAGE = 'chat-message',\n CUSTOM_DATA = 'custom-data',\n ROLES_CHANGED = 'roles-changed',\n MUTE_PARTICIPANT = 'mute-participant',\n PIN_PARTICIPANT = 'pin-participant',\n OPTIONS_CHANGED = 'options-changed',\n NETWORK_STATUS = 'network-status',\n PARTICIPANT_SOURCES_UPDATE = 'participant-sources-update',\n PROMOTE_PARTICIPANT = 'promote-participant',\n CHAT_ROOM_UPDATED = 'chat-room-updated',\n PROMOTION_APPROVED = 'promotion-approved',\n JOIN_LINK_CHANGED = 'join-link-changed',\n FEEDBACK = 'feedback',\n MOVIE_UPDATE_NOTIFICATION = 'movie-update-notification',\n MOVIE_SHARE_STARTED = 'movie-share-started',\n MOVIE_SHARE_STOPPED = 'movie-share-stopped',\n URL_SHARING_INFO_UPDATED = 'url-sharing-info-updated',\n ROOM_UPDATED = 'room-updated',\n ROOMS_UPDATED = 'rooms-updated',\n ROOM_PARTICIPANTS_UPDATED = 'room-participants-updated',\n FEATURES_PER_ROLE_CHANGED = 'features-per-role-changed',\n PARTICIPANT_ANIMOJI_CHANGED = 'participant-animoji-changed',\n ASR_STARTED = 'asr-started',\n ASR_STOPPED = 'asr-stopped',\n DECORATIVE_PARTICIPANT_ID_CHANGED = 'decorative-participant-id-changed',\n VIDEO_SUSPEND_SUGGEST = 'video-suspend-suggest',\n}\n\nexport default SignalingNotification;\n", "const enum DataChannelLabel {\n producerNotification = 'producerNotification',\n producerCommand = 'producerCommand',\n consumerScreenShare = 'consumerScreenShare',\n producerScreenShare = 'producerScreenShare',\n asr = 'asr',\n animoji = 'animoji',\n}\n\nexport default DataChannelLabel;\n", "import Utils from '../static/Utils';\n\nconst { isObject, isObjectsEquals } = Utils;\n\n/**\n * Настройки качества видео\n * @hidden\n */\nexport type VideoSettings = {\n /**\n * Макс битрейт в килобитах в секунду\n */\n maxBitrateK: number;\n\n /**\n * Макс высота/ширина кадра в пикселях\n */\n maxDimension: number;\n\n /**\n * Макс кадров в секунду\n */\n maxFramerate: number;\n\n /**\n * Настройка деградации - понижаем фпс или разрешение\n * https://www.w3.org/TR/mst-content-hint/#dom-rtcdegradationpreference\n */\n degradationPreference: RTCDegradationPreference;\n\n /**\n * Настройка временных слоев\n * https://www.w3.org/TR/webrtc-svc/\n */\n scalabilityMode: string;\n\n /**\n * Таблица с битрейтами в зависимости от разрешения\n */\n bitrates?: Record<'generic' | string, VideoBitrateSettings[]>;\n};\n\nexport default VideoSettings;\n\nexport function compareVideoSettings(vs1: VideoSettings | null, vs2: VideoSettings | null): boolean {\n if (vs1 === null || vs2 === null) {\n return vs1 === null && vs2 === null;\n }\n if (vs1.maxDimension !== vs2.maxDimension) {\n return false;\n }\n if (vs1.maxBitrateK !== vs2.maxBitrateK) {\n return false;\n }\n if (vs1.maxFramerate !== vs2.maxFramerate) {\n return false;\n }\n if (vs1.degradationPreference !== vs2.degradationPreference) {\n return false;\n }\n if (vs1.scalabilityMode !== vs2.scalabilityMode) {\n return false;\n }\n\n if (isObject(vs1.bitrates) && isObject(vs2.bitrates) && !isObjectsEquals(vs1.bitrates, vs2.bitrates, true)) {\n return false;\n } else if (vs1.bitrates !== vs2.bitrates) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Настройки временных слоев для режима масштабируемости\n * https://www.w3.org/TR/webrtc-svc/#scalabilitymodes*\n * 1, 2 и 3 слоя, чем хуже качество сети, тем больше нужно\n */\nexport enum VideoScalability {\n L1T1 = 'L1T1',\n L1T2 = 'L1T2',\n L1T3 = 'L1T3',\n}\n\n/**\n * Настройка битрейта под конкретное разрешение\n * @hidden\n */\nexport type VideoBitrateSettings = {\n dimension: number;\n bitrate: number;\n};\n", "import VideoSettings, { compareVideoSettings } from './VideoSettings';\n\n/**\n * Настройки полученные от сервера звонков\n * @hidden\n */\nexport type ServerSettings = {\n camera: VideoSettings | null;\n screenSharing: VideoSettings | null;\n fastScreenSharing: VideoSettings | null;\n};\n\nexport default ServerSettings;\n\nexport function compareServerSettings(ss1: ServerSettings, ss2: ServerSettings): boolean {\n if (!compareVideoSettings(ss1.camera, ss2.camera)) {\n return false;\n }\n if (!compareVideoSettings(ss1.screenSharing, ss2.screenSharing)) {\n return false;\n }\n if (!compareVideoSettings(ss1.fastScreenSharing, ss2.fastScreenSharing)) {\n return false;\n }\n return true;\n}\n\nexport function merge(ss: ServerSettings, other: ServerSettings) {\n return {\n camera: Object.assign({}, ss.camera, other.camera),\n screenSharing: Object.assign({}, ss.screenSharing, other.screenSharing),\n fastScreenSharing: Object.assign({}, ss.fastScreenSharing, other.fastScreenSharing),\n };\n}\n\nexport function createEmptyServerSettings(): ServerSettings {\n return { camera: null, screenSharing: null, fastScreenSharing: null };\n}\n\nexport function clone(ss: ServerSettings): ServerSettings {\n return {\n camera: Object.assign({}, ss.camera),\n screenSharing: Object.assign({}, ss.screenSharing),\n fastScreenSharing: Object.assign({}, ss.fastScreenSharing),\n };\n}\n", "import Stat from '../../enums/Stat';\nimport Params from '../../static/Params';\nimport { StatItem, StatRtp } from '../../types/Statistics';\nimport Logger from '../Logger';\nimport { TransportTopology } from '../transport/Transport';\n\nexport type CodecKind = 'audio' | 'video';\n\ninterface CodecUsage {\n kind: CodecKind;\n /** Для аудио всегда 0, держим в мс */\n totalEncodeTime: number;\n /** Составное имя из mimeType + ${encodeImplementation} */\n codecName: string;\n audioCodecParams?: string;\n topology: TransportTopology;\n}\n\n/**\n * Собирает стату по использованию кодеков в webrtc\n * Каждый раз когда обновляется кодек или завершается звонок,\n * отправляется репорт об использовании кодеков\n */\nexport class CodecStatsAggregator {\n private static _instance: CodecStatsAggregator | null = null;\n\n private readonly _codecUsages = new Map<CodecKind, CodecUsage>();\n private getCurrentTransportTopology: () => TransportTopology | undefined = () => undefined;\n\n static create(getCurrentTransportTopology: () => TransportTopology | undefined) {\n const instance: CodecStatsAggregator = new CodecStatsAggregator();\n instance.getCurrentTransportTopology = getCurrentTransportTopology;\n CodecStatsAggregator._instance = instance;\n }\n\n static reportUsage(stat: StatItem) {\n const instance = CodecStatsAggregator._instance;\n const transport = instance?.getCurrentTransportTopology();\n if (!instance || !transport) {\n return;\n }\n\n let outboundRtps = stat.rtps\n // аудио шара всегда содержит в себе `s` в конце mid\n .filter((rtp) => rtp.type === 'outbound-rtp' && !rtp.mid?.endsWith('s'));\n\n if (Params.simulcast) {\n /**\n * В режиме simulcast, мы просто суммируем totalEncodeTime\n */\n outboundRtps = outboundRtps.reduce<StatRtp[]>((acc, rtp) => {\n if (rtp.kind !== 'video') {\n return acc.concat(rtp);\n }\n\n const lastVideo = acc.find((item) => item.kind === 'video');\n if (lastVideo) {\n lastVideo.totalEncodeTime = (lastVideo.totalEncodeTime ?? 0) + (rtp.totalEncodeTime ?? 0);\n } else {\n acc.push(rtp);\n }\n return acc;\n }, []);\n }\n outboundRtps.forEach((rtp) => {\n const kind = rtp.kind;\n const mimeType = rtp.mimeType;\n if ((kind === 'audio' || kind === 'video') && mimeType) {\n const implementation = rtp.encoderImplementation;\n const codecName = [mimeType, 'encoder', implementation].filter(Boolean).join('/');\n instance.saveUsage({\n kind,\n codecName,\n totalEncodeTime: (rtp.totalEncodeTime ?? 0) * 1000,\n audioCodecParams: rtp.sdpFmtpLine,\n topology: transport,\n });\n }\n });\n }\n\n private saveUsage({ kind, codecName, totalEncodeTime, audioCodecParams, topology }: CodecUsage) {\n const prevUsage = this._codecUsages.get(kind);\n\n if (prevUsage && prevUsage.codecName !== codecName) {\n this.report(prevUsage);\n }\n\n if (prevUsage && prevUsage.codecName === codecName) {\n this._codecUsages.set(kind, {\n ...prevUsage,\n totalEncodeTime,\n topology,\n });\n return;\n }\n\n this._codecUsages.set(kind, {\n kind,\n codecName,\n audioCodecParams,\n totalEncodeTime,\n topology,\n });\n }\n\n private report(codecUsage: CodecUsage) {\n // не отправляем бесполезную стату\n if (codecUsage.kind === 'video' && codecUsage.totalEncodeTime === 0) {\n return;\n }\n\n const log: {\n name: string;\n value: number;\n codec_implementation: string;\n string_value?: string;\n call_topology: string;\n } = {\n name: Stat.CODEC_USAGE,\n codec_implementation: codecUsage.codecName,\n value: codecUsage.totalEncodeTime,\n call_topology: codecUsage.topology === TransportTopology.DIRECT ? 'D' : 'S',\n };\n\n if (codecUsage.audioCodecParams) {\n log.string_value = codecUsage.audioCodecParams;\n }\n\n Logger.logClientStats(log);\n }\n\n static destroy() {\n CodecStatsAggregator._instance?._destroy();\n CodecStatsAggregator._instance = null;\n }\n\n private _destroy() {\n // Отправляем последние\n this._codecUsages.forEach((codecUsage: CodecUsage) => {\n this.report(codecUsage);\n });\n this._codecUsages.clear();\n }\n}\n", "import BaseSignaling from '../../abstract/BaseSignaling';\nimport EventEmitter from '../EventEmitter';\nimport { MediaSource } from '../MediaSource';\nimport { TransportState } from './Transport';\n\nexport default abstract class BaseTransport extends EventEmitter {\n protected readonly _signaling: BaseSignaling;\n protected readonly _mediaSource: MediaSource;\n protected _state = TransportState.IDLE;\n protected _pc: RTCPeerConnection | null = null;\n\n protected constructor(signaling: BaseSignaling, mediaSource: MediaSource) {\n super();\n\n this._signaling = signaling;\n this._mediaSource = mediaSource;\n }\n\n getState(): TransportState {\n return this._state || TransportState.IDLE;\n }\n\n abstract close(error?: Error): void;\n}\n", "import BaseSignaling from '../../abstract/BaseSignaling';\nimport Debug from '../../static/Debug';\nimport Params from '../../static/Params';\nimport EventEmitter from '../EventEmitter';\nimport { NetworkStatReport } from '../../types/NetworkStatReport';\nimport { IScreenShareStat } from '../../types/ScreenSharingStat';\nimport { IOnStat } from '../screenshare/BaseStreamBuilder';\nimport { CallStatReport, ICallStatLog, PerfStatReport } from '../../types/PerfStatReporter';\nimport { IRemoteIceCandidateStat, StatResult } from '../../types/Statistics';\nimport { StatAggregator } from '../stat/StatAggregator';\nimport DirectTransport from './DirectTransport';\nimport ServerTransport from './ServerTransport';\nimport { TransportEvent, TransportState } from './Transport';\n\nconst ESTIMATED_PERFORMANCE_INDEX_KEY = 'videochat-epi';\nconst PERF_STAT_REPORT_INTERVAL_MILLIS = 5000;\nconst NETWORK_STAT_REPORT_INTERVAL_MILLIS = 500;\n\nexport default class PerfStatReporter extends EventEmitter {\n private _previousPerfStatReportTimestamp = 0;\n private _previousNetworkStatReportTimestamp = Date.now();\n private _previousCallStatReportTimestamp = Date.now();\n private _previousCallStatReport: CallStatReport | null = null;\n private _screenShareStats: IScreenShareStat[] = [];\n\n private _signaling: BaseSignaling;\n\n private readonly _directTopology: boolean;\n\n constructor(transport: ServerTransport | DirectTransport, signaling: BaseSignaling, directTopology = false) {\n super();\n\n this._signaling = signaling;\n this._directTopology = directTopology;\n\n this.subscribe(transport, TransportEvent.REMOTE_DATA_STATS, this._handleStats.bind(this));\n this.subscribe(transport, TransportEvent.SCREEN_SHARING_STAT, this._handleScreenSharingStat.bind(this));\n this.subscribe(transport, TransportEvent.STATE_CHANGED, this._handleTransportStateChanged.bind(this));\n }\n\n destroy() {\n this.unsubscribe();\n }\n\n static getEstimatedPerformanceIndex() {\n try {\n const index = parseInt(localStorage.getItem(ESTIMATED_PERFORMANCE_INDEX_KEY) || '', 10);\n return isNaN(index) ? 0 : index;\n } catch (e) {\n return 0;\n }\n }\n\n private async _handleStats(stats: StatResult) {\n if (!stats.inbound || !stats.inbound.rtps) {\n return;\n }\n\n const timestamp = Date.now();\n\n if (!this._directTopology && Params.perfStatReportEnabled && this._previousPerfStatReportTimestamp + PERF_STAT_REPORT_INTERVAL_MILLIS <= timestamp) {\n await this.reportPerfStats(stats);\n this._previousPerfStatReportTimestamp = timestamp;\n }\n\n const isTcp = stats.outbound.transport.local?.protocol === 'tcp';\n if (!this._directTopology && isTcp && this._previousNetworkStatReportTimestamp + NETWORK_STAT_REPORT_INTERVAL_MILLIS <= timestamp) {\n await this.reportNetworkStats(stats);\n this._previousNetworkStatReportTimestamp = timestamp;\n }\n\n if (Params.callStatReportEnabled && this._previousCallStatReportTimestamp + Params.statisticsInterval <= timestamp) {\n this._reportCallStats(stats);\n this._previousCallStatReportTimestamp = timestamp;\n }\n }\n\n private async reportPerfStats(stats: StatResult) {\n const report: PerfStatReport = stats.inbound.rtps.reduce(\n (sum, rtp) => {\n if (rtp.kind === 'video') {\n sum.framesDecoded += rtp.framesDecoded || 0;\n sum.framesReceived += rtp.framesReceived || 0;\n }\n return sum;\n },\n { framesDecoded: 0, framesReceived: 0 },\n );\n\n if (report.framesDecoded) {\n try {\n const response = await this._signaling.reportPerfStat(report);\n localStorage.setItem(ESTIMATED_PERFORMANCE_INDEX_KEY, response.estimatedPerformanceIndex);\n } catch (e) {\n // Do nothing\n }\n }\n }\n\n private async reportNetworkStats(stats: StatResult) {\n const report: NetworkStatReport = {\n timestamp: stats.outbound.transport.timestamp,\n sendBitrate: stats.outbound.rtps.reduce((result, rtp) => result + (rtp.bandwidth ?? 0) * 8, 0),\n };\n\n if (report.timestamp) {\n try {\n await this._signaling.reportNetworkStat(report);\n } catch (e) {\n // Do nothing\n }\n }\n }\n\n private _reportCallStats(stats: StatResult) {\n const callStatReport: CallStatReport = {\n call_topology: this._directTopology ? 'D' : 'S',\n stat_time_delta: 0,\n nack_received: 0,\n pli_received: 0,\n fir_received: 0,\n frames_dropped: 0,\n jitter_video: 0,\n jitter_audio: 0,\n interframe_delay_variance: 0,\n nack_sent: 0,\n pli_sent: 0,\n fir_sent: 0,\n total_audio_samples_received: 0,\n concealed_audio_samples: 0,\n silent_concealed_audio_samples: 0,\n inserted_audio_samples_for_deceleration: 0,\n removed_audio_samples_for_acceleration: 0,\n audio_concealment_events: 0,\n total_audio_energy: 0,\n inbound_video_count: 0,\n inbound_audio_count: 0,\n packets_lost_video: 0,\n packets_sent_video: 0,\n packets_lost_audio: 0,\n packets_sent_audio: 0,\n freeze_count: 0,\n total_freezes_duration: 0,\n rtt: Math.round(stats.inbound.transport.currentRoundTripTime * 1000),\n ss_freeze_count: 0,\n ss_total_freezes_duration: 0,\n local_address: mapStatAddress(stats.inbound.transport.local),\n local_connection_type: stats.inbound.transport.local?.type,\n network_type: stats.inbound.transport.local?.networkType,\n transport: stats.inbound.transport.local?.protocol,\n remote_address: mapStatAddress(stats.inbound.transport.remote),\n remote_connection_type: stats.inbound.transport.remote?.type,\n };\n\n if (!this._previousCallStatReport) {\n this._previousCallStatReport = Object.assign({}, callStatReport);\n }\n\n let isVideoInbound = false;\n let isAudioInbound = false;\n\n stats.inbound.rtps.reduce((sum, rtp) => {\n if (rtp.kind === 'video') {\n isVideoInbound = true;\n if (rtp.framesReceived) {\n // calculating averages here, so ignoring video tracks that did not receive any frames\n sum.jitter_video = (sum.jitter_video * sum.inbound_video_count) / (sum.inbound_video_count + 1) + (rtp.jitter * 1000) / (sum.inbound_video_count + 1);\n sum.interframe_delay_variance =\n (sum.interframe_delay_variance * sum.inbound_video_count) / (sum.inbound_video_count + 1) +\n ((rtp.interframeDelayVariance || 0) * 1000000) / (sum.inbound_video_count + 1); // DWH will remove digits after decimal point, so multiplying by 10^6\n sum.inbound_video_count++;\n }\n\n sum.frames_dropped += rtp.framesDropped || 0;\n sum.nack_sent += rtp.nackCount;\n sum.pli_sent += rtp.pliCount;\n sum.fir_sent += rtp.firCount;\n sum.freeze_count += rtp.freezeCountDelta || 0;\n sum.total_freezes_duration += rtp.totalFreezesDurationDelta || 0;\n } else {\n isAudioInbound = true;\n if (rtp.totalSamplesReceived) {\n // calculating averages here, so ignoring audio tracks that did not receive any audio samples\n sum.jitter_audio = (sum.jitter_audio * sum.inbound_audio_count) / (sum.inbound_audio_count + 1) + (rtp.jitter * 1000) / (sum.inbound_audio_count + 1);\n sum.total_audio_energy =\n (sum.total_audio_energy * sum.inbound_audio_count) / (sum.inbound_audio_count + 1) + (rtp.totalAudioEnergy || 0) / (sum.inbound_audio_count + 1);\n sum.inbound_audio_count++;\n }\n\n sum.total_audio_samples_received += rtp.totalSamplesReceived || 0;\n sum.inserted_audio_samples_for_deceleration += rtp.insertedSamplesForDeceleration || 0;\n sum.removed_audio_samples_for_acceleration += rtp.removedSamplesForAcceleration || 0;\n sum.concealed_audio_samples += rtp.concealedSamples || 0;\n sum.silent_concealed_audio_samples += rtp.silentConcealedSamples || 0;\n sum.audio_concealment_events += rtp.concealmentEvents || 0;\n }\n return sum;\n }, callStatReport);\n\n stats.outbound.rtps.reduce((sum, rtp) => {\n if (rtp.kind === 'video') {\n sum.nack_received += rtp.nackCount;\n sum.pli_received += rtp.pliCount;\n sum.fir_received += rtp.firCount;\n sum.packets_sent_video += rtp.packetsSent;\n } else {\n sum.packets_sent_audio += rtp.packetsSent;\n }\n return sum;\n }, callStatReport);\n\n stats.remoteInbound.rtps.reduce((sum, rtp) => {\n if (rtp.kind === 'video') {\n sum.packets_lost_video += rtp.packetsLost;\n } else {\n sum.packets_lost_audio += rtp.packetsLost;\n }\n return sum;\n }, callStatReport);\n\n while (this._screenShareStats.length) {\n const stat = this._screenShareStats.pop();\n if (stat?.freeze_duration) {\n callStatReport.ss_freeze_count += 1;\n callStatReport.ss_total_freezes_duration += stat.freeze_duration;\n }\n }\n\n const callStat: ICallStatLog = {\n call_topology: callStatReport.call_topology,\n stat_time_delta: Math.max(0, Date.now() - this._previousCallStatReportTimestamp),\n nack_sent: Math.max(0, callStatReport.nack_sent - this._previousCallStatReport.nack_sent),\n nack_received: Math.max(0, callStatReport.nack_received - this._previousCallStatReport.nack_received),\n pli_sent: Math.max(0, callStatReport.pli_sent - this._previousCallStatReport.pli_sent),\n pli_received: Math.max(0, callStatReport.pli_received - this._previousCallStatReport.pli_received),\n fir_sent: Math.max(0, callStatReport.fir_sent - this._previousCallStatReport.fir_sent),\n fir_received: Math.max(0, callStatReport.fir_received - this._previousCallStatReport.fir_received),\n frames_dropped: Math.max(0, callStatReport.frames_dropped - this._previousCallStatReport.frames_dropped),\n rtt: Math.max(0, callStatReport.rtt),\n };\n\n if (navigator.hardwareConcurrency) {\n callStat.cpu_hardware_concurrency = navigator.hardwareConcurrency;\n }\n\n if (isVideoInbound && !isUndefined(callStatReport.jitter_video)) {\n callStat.jitter_video = Math.round(callStatReport.jitter_video);\n }\n if (isAudioInbound && !isUndefined(callStatReport.jitter_audio)) {\n callStat.jitter_audio = Math.round(callStatReport.jitter_audio);\n }\n if (isVideoInbound && !isUndefined(callStatReport.interframe_delay_variance)) {\n callStat.interframe_delay_variance = callStatReport.interframe_delay_variance;\n }\n if (callStatReport.freeze_count && callStatReport.total_freezes_duration) {\n callStat.freeze_count = callStatReport.freeze_count;\n callStat.total_freezes_duration = Math.round(callStatReport.total_freezes_duration * 1000);\n }\n if (callStatReport.ss_freeze_count && callStatReport.ss_total_freezes_duration) {\n callStat.ss_freeze_count = callStatReport.ss_freeze_count;\n callStat.ss_total_freezes_duration = callStatReport.ss_total_freezes_duration;\n }\n if (isAudioInbound && !isUndefined(callStatReport.total_audio_samples_received)) {\n const totalSamplesDelta = Math.max(0, callStatReport.total_audio_samples_received - this._previousCallStatReport.total_audio_samples_received);\n const insertedSamplesDelta = Math.max(0, callStatReport.inserted_audio_samples_for_deceleration - this._previousCallStatReport.inserted_audio_samples_for_deceleration);\n const removedSamplesDelta = Math.max(0, callStatReport.removed_audio_samples_for_acceleration - this._previousCallStatReport.removed_audio_samples_for_acceleration);\n const concealedSamplesDelta = Math.max(0, callStatReport.concealed_audio_samples - this._previousCallStatReport.concealed_audio_samples);\n const silentConcealedSamplesDelta = Math.max(0, callStatReport.silent_concealed_audio_samples - this._previousCallStatReport.silent_concealed_audio_samples);\n const concealmentEventsDelta = Math.max(0, callStatReport.audio_concealment_events - this._previousCallStatReport.audio_concealment_events);\n\n // DWH will remove digits after decimal point, so additionally multiplying percentage by 10\n callStat.inserted_audio_samples_for_deceleration = noNaN((insertedSamplesDelta / totalSamplesDelta) * 1000);\n callStat.removed_audio_samples_for_acceleration = noNaN((removedSamplesDelta / totalSamplesDelta) * 1000);\n callStat.concealed_audio_samples = noNaN((concealedSamplesDelta / totalSamplesDelta) * 1000);\n callStat.concealed_silent_audio_samples = noNaN((silentConcealedSamplesDelta / totalSamplesDelta) * 1000);\n callStat.concealment_audio_avg_size = noNaN(concealedSamplesDelta / concealmentEventsDelta);\n\n callStat.total_audio_energy = callStatReport.total_audio_energy;\n }\n if (hasKeysValues(callStatReport, 'local_address', 'local_connection_type', 'network_type', 'transport')) {\n callStat.local_address = callStatReport.local_address;\n callStat.local_connection_type = callStatReport.local_connection_type;\n callStat.network_type = callStatReport.network_type;\n callStat.transport = callStatReport.transport;\n }\n if (hasKeysValues(callStatReport, 'remote_address', 'remote_connection_type')) {\n callStat.remote_address = callStatReport.remote_address;\n callStat.remote_connection_type = callStatReport.remote_connection_type;\n }\n\n const packetsSentVideoDelta = Math.max(0, callStatReport.packets_sent_video - this._previousCallStatReport.packets_sent_video);\n const packetsSentAudioDelta = Math.max(0, callStatReport.packets_sent_audio - this._previousCallStatReport.packets_sent_audio);\n\n if (packetsSentVideoDelta > 0) {\n const packetsLostVideoDelta = Math.max(0, callStatReport.packets_lost_video - this._previousCallStatReport.packets_lost_video);\n callStat.video_loss = noNaN((packetsLostVideoDelta / packetsSentVideoDelta) * 100);\n }\n if (packetsSentAudioDelta > 0) {\n const packetsLostAudioDelta = Math.max(0, callStatReport.packets_lost_audio - this._previousCallStatReport.packets_lost_audio);\n callStat.audio_loss = noNaN((packetsLostAudioDelta / packetsSentAudioDelta) * 100);\n }\n\n StatAggregator.logCallStat(callStat);\n if (Params.enableLogPerfStatReport) {\n Debug.log('Sent call stats', callStat);\n }\n\n this._previousCallStatReport = callStatReport;\n }\n\n private _handleScreenSharingStat: IOnStat = (stat) => {\n this._screenShareStats.push(stat);\n };\n\n private _handleTransportStateChanged = (state: TransportState) => {\n // Сбрасываем время начала отсчета при перезапуске интервала сбора статы.\n // Исключаем слишком большое значение stat_time_delta при долгом ожидании подключения.\n if ((this._directTopology && state === TransportState.CONNECTED) || (!this._directTopology && state === TransportState.OPENED)) {\n this._previousNetworkStatReportTimestamp = Date.now();\n this._previousCallStatReportTimestamp = Date.now();\n }\n };\n}\n\nfunction hasKeysValues<T extends object>(obj: T, ...keys: (keyof T)[]): boolean {\n for (const key of keys) {\n if (!Object.hasOwn(obj, key) || obj[key] === undefined) {\n return false;\n }\n }\n return true;\n}\n\nfunction mapStatAddress(stat?: IRemoteIceCandidateStat, includePort = false): string | undefined {\n if (!stat?.address) {\n return undefined;\n }\n\n return stat.address + (includePort ? `:${stat.port}` : '');\n}\n\nfunction isUndefined(value: unknown): value is undefined {\n return value === undefined;\n}\n\nfunction noNaN(value: number) {\n return Number.isNaN(value) ? 0 : value;\n}\n", "export class WeightedAverage {\n private readonly weightUp: number;\n private readonly weightDown: number;\n private value = NaN;\n\n constructor(weightUp: number, weightDown: number | null = null) {\n this.weightUp = weightUp;\n this.weightDown = weightDown ?? weightUp;\n }\n\n set(value: number): void {\n this.value = value;\n }\n\n update(value: number): number {\n this.value = this.getNext(value);\n return this.value;\n }\n\n getNext(value: number): number {\n if (isNaN(this.value)) {\n return value;\n }\n\n const weight = value < this.value ? this.weightDown : this.weightUp;\n return this.value * (1 - weight) + value * weight;\n }\n\n getValue(): number {\n return this.value;\n }\n}\n", "import BaseSignaling from '../../abstract/BaseSignaling';\nimport Debug from '../../static/Debug';\nimport Params from '../../static/Params';\nimport { StatResult } from '../../types/Statistics';\nimport EventEmitter from '../EventEmitter';\nimport { WeightedAverage } from '../stat/WeightedAverage';\nimport { TransportEvent } from './Transport';\n\nconst NETWORK_STAT_TOLERANCE = 0.8;\n\nconst RTT_WEIGHT = 0.25;\nconst LOSS_WEIGHT = 0.35;\n\nconst RTT_STEP = 85;\nconst RTT_STEP_WEIGHT = 0.1;\n\nconst LOSS_STEP = 1.5;\nconst LOSS_STEP_WEIGHT = 0.1;\n\nconst BITRATE_RATING_INFLUENCE_FACTOR = 1;\n\nconst GOOD_RATING_THRESHOLD = 0.6;\nconst BAD_RATING_THRESHOLD = 0.3;\n\ninterface NetworkStat {\n rtt: WeightedAverage | number;\n loss: WeightedAverage | number;\n bitrate: number;\n}\n\ninterface NetworkStatLocal extends NetworkStat {\n rtt: WeightedAverage;\n loss: WeightedAverage;\n}\n\ninterface NetworkStatRemote extends NetworkStat {\n rtt: number;\n loss: number;\n}\n\nenum NetworkState {\n GOOD = 'good',\n MEDIUM = 'medium',\n BAD = 'bad',\n}\n\nexport interface NetworkLimits {\n badNet: {\n rtt: number;\n loss: number;\n };\n goodNet: {\n rtt: number;\n loss: number;\n };\n}\n\nexport type SignalingNetworkStat = Partial<Omit<NetworkStatRemote, 'timestamp' | 'previousTimestamp'>>;\n\nexport default class DirectStatReporter extends EventEmitter {\n private readonly _signaling: BaseSignaling;\n private readonly _localNetworkStat: NetworkStatLocal;\n private readonly _remoteNetworkStat: NetworkStatRemote;\n private readonly _lastNetworkStat: Omit<NetworkStatRemote, 'bitrate'> & { date: number };\n private readonly _networkLimits: NetworkLimits = {\n badNet: {\n loss: 3,\n rtt: 1000,\n },\n goodNet: {\n loss: 0.5,\n rtt: 600,\n },\n };\n\n private _lastStatSentTimestamp = 0;\n private _currentState = NetworkState.GOOD;\n\n constructor(signaling: BaseSignaling) {\n super();\n this._signaling = signaling;\n\n this._localNetworkStat = {\n rtt: new WeightedAverage(RTT_WEIGHT, RTT_WEIGHT),\n loss: new WeightedAverage(LOSS_WEIGHT, LOSS_WEIGHT),\n bitrate: 0,\n };\n\n this._remoteNetworkStat = {\n rtt: 0,\n loss: 0,\n bitrate: 0,\n };\n\n this._lastNetworkStat = {\n rtt: 0,\n loss: 0,\n date: 0,\n };\n }\n\n private _calcRttRating(rtt: WeightedAverage | number): number {\n const rttValue = typeof rtt === 'number' ? rtt : rtt.getValue();\n let rating = 1.0;\n\n if (isNaN(rttValue)) {\n return rating;\n }\n\n const rttSteps = Math.round((rttValue - this._networkLimits.goodNet.rtt) / RTT_STEP);\n for (let i = 0; i < rttSteps; i++) {\n rating *= 1 - RTT_STEP_WEIGHT;\n }\n\n return rating;\n }\n\n private _calcLossRating(loss: WeightedAverage | number): number {\n const lossValue = typeof loss === 'number' ? loss : loss.getValue();\n let rating = 1.0;\n\n if (isNaN(lossValue)) {\n return rating;\n }\n\n const lossSteps = Math.round((lossValue - this._networkLimits.goodNet.loss) / LOSS_STEP);\n for (let i = 0; i < lossSteps; i++) {\n rating *= 1 - LOSS_STEP_WEIGHT;\n }\n\n return rating;\n }\n\n private _calcBitrateRating(bitrateA: number, bitrateB: number): number {\n if (!bitrateA || !bitrateB) {\n return 1;\n }\n\n const bitrateDiffFactor = Math.min(bitrateA, bitrateB) / Math.max(bitrateA, bitrateB);\n\n const rating = 1 - (1 - bitrateDiffFactor) * BITRATE_RATING_INFLUENCE_FACTOR;\n return Math.min(rating, 1);\n }\n\n private _calcUDPRating({ rtt, loss }: NetworkStat) {\n return this._calcRttRating(rtt) * this._calcLossRating(loss);\n }\n\n private _calcRating(localNetworkStat: NetworkStatLocal, remoteNetworkStat: NetworkStatRemote, isTcp: boolean) {\n if (!isTcp) {\n return this._calcUDPRating(localNetworkStat) * this._calcUDPRating(remoteNetworkStat);\n }\n\n return this._calcBitrateRating(localNetworkStat.bitrate, remoteNetworkStat.bitrate);\n }\n\n private _getNetworkState(rating: number): NetworkState {\n if (isNaN(rating) || rating >= GOOD_RATING_THRESHOLD) {\n return NetworkState.GOOD;\n }\n\n if (rating >= BAD_RATING_THRESHOLD) {\n return NetworkState.MEDIUM;\n }\n\n return NetworkState.BAD;\n }\n\n updateSettings(settings?: NetworkLimits) {\n Object.assign(this._networkLimits.badNet, settings?.badNet || {});\n Object.assign(this._networkLimits.goodNet, settings?.goodNet || {});\n }\n\n reportLocal(stats: StatResult) {\n if (!this._signaling.ready) {\n return;\n }\n\n const isTcp = stats.outbound.transport.local?.protocol === 'tcp';\n const rtt = Math.max(0, Math.round(stats.outbound.transport.currentRoundTripTime * 1000) || 0); // в миллисекундах, int\n const loss = stats.inbound.rtps.reduce((result, rtp) => Math.max(result, rtp.packetLoss || 0), 0); // в процентах, float\n\n const statToSend: Omit<NetworkStatRemote, 'bitrate'> & Partial<Pick<NetworkStatRemote, 'bitrate'>> = {\n rtt: this._localNetworkStat.rtt.update(rtt),\n loss: this._localNetworkStat.loss.update(loss),\n };\n\n if (isTcp) {\n // Битрейт нужен только для подсчета рейтинга при tcp соединении\n const bitrate = stats.outbound.rtps.reduce((result, rtp) => result + (rtp.bandwidth ?? 0) * 8, 0); // в битах, int\n statToSend.bitrate = bitrate;\n this._localNetworkStat.bitrate = bitrate;\n }\n\n const now = Date.now();\n const rating = this._calcRating(this._localNetworkStat, this._remoteNetworkStat, isTcp);\n const roundedRating = Math.max(Math.round(rating * 10) / 10, 0.1);\n const networkState = this._getNetworkState(roundedRating);\n\n if (\n isTcp || // если соединение по tcp, отправляем каждые statisticsInterval мс\n networkState !== this._currentState || // всегда отправляем, если изменилось текущее состояние\n now - this._lastStatSentTimestamp > Params.networkStatisticsInterval // всегда отправляем, если прошло networkStatisticsInterval мс\n ) {\n this._lastStatSentTimestamp = now;\n this._signaling\n .customData(\n {\n sdk: Object.assign({ type: 'bad-net' }, statToSend),\n },\n null,\n )\n .catch((e) => {\n // Не ждем выполнения команды и глушим ошибки, чтобы не вылетали наружу\n Debug.warn('Unable to send [bad-net]', e);\n });\n }\n\n this._currentState = networkState;\n this._triggerEvent(TransportEvent.NETWORK_STATUS, roundedRating);\n }\n\n reportRemote(stat?: SignalingNetworkStat) {\n const { rtt, loss, bitrate } = stat || {};\n this._remoteNetworkStat.rtt = rtt || 0;\n this._remoteNetworkStat.loss = loss || 0;\n this._remoteNetworkStat.bitrate = bitrate || 0;\n }\n}\n", "import type { AnimojiReceiver, AnimojiSender, AnimojiVersion } from '@vkontakte/calls-vmoji';\nimport BaseSignaling from '../../abstract/BaseSignaling';\nimport DataChannelLabel from '../../enums/DataChannelLabel';\nimport SignalingEvent from '../../enums/SignalingEvent';\nimport SignalingNotification from '../../enums/SignalingNotification';\nimport StatLog from '../../enums/StatLog';\nimport Debug from '../../static/Debug';\nimport External from '../../static/External';\nimport Params from '../../static/Params';\nimport Utils from '../../static/Utils';\nimport WebRTCUtils from '../../static/WebRTCUtils';\nimport { ParticipantId } from '../../types/Participant';\nimport ServerSettings, { compareServerSettings } from '../../types/ServerSettings';\nimport SignalingMessage from '../../types/SignalingMessage';\nimport { VideoScalability } from '../../types/VideoSettings';\nimport Logger from '../Logger';\nimport { MediaSource, MediaSourceEvent } from '../MediaSource';\nimport { StatItem, StatResult } from '../../types/Statistics';\nimport { CodecStatsAggregator } from '../stat/CodecStatsAggregator';\nimport BaseTransport from './BaseTransport';\nimport PerfStatReporter from './PerfStatReporter';\nimport Statistics from './Statistics';\nimport { TransportEvent, TransportState, TransportTopology } from './Transport';\nimport DirectStatReporter, { NetworkLimits, SignalingNetworkStat } from './DirectStatReporter';\n\nconst TIME_WITHOUT_UPDATE_VIDEO_FRAME = 30 * 1000; // 30 секунд\n\nexport default class DirectTransport extends BaseTransport {\n private readonly _participantId: ParticipantId;\n private readonly _isMaster: boolean;\n\n private _remoteSDP: Record<string, Required<RTCSessionDescriptionInit>> = {};\n private _remoteCandidates: Record<string, RTCIceCandidateInit[]> = {};\n private _lastRemoteSDP: RTCSessionDescriptionInit | null = null;\n private _animojiDataChannel: RTCDataChannel | null = null;\n private _animojiReceiver: AnimojiReceiver | null = null;\n private _animojiSender: AnimojiSender | null = null;\n private _remoteAnimojiVersion: AnimojiVersion = 1;\n private _isOpen = false;\n private _remotePeerId: string | null = null; // Is null if isMaster is false\n private _statInterval: number | null = null;\n private _settingsInterval: number | null = null;\n private _failedOnCreate: any = null;\n private _remoteStream: MediaStream | null = null;\n private _iceRestartTimeout: number | null = null;\n private _reconnectionTimeout: number | null = null;\n private _reconnectionPrevented = false;\n private _lastStat: StatItem;\n private _fingerprint: bigint | null = null;\n private _neverConnected = true;\n private _serverSettings: ServerSettings;\n private _prevConsumerSettings: any = {};\n\n private _networkLimitsForVideo = {\n bad: {\n loss: 4,\n rtt: 1000,\n },\n good: {\n loss: 2,\n rtt: 700,\n },\n };\n\n private _videoMaxDimensionsForNet = {\n worst: 320,\n bad: 640,\n good: 1280,\n };\n\n private _lastVideoMaxDimension: number = this._videoMaxDimensionsForNet.good;\n\n private _lastBadConnection = 0;\n\n private _perfStatReporter: PerfStatReporter;\n private _directStatReporter: DirectStatReporter;\n\n constructor(participantId: ParticipantId, isMaster: boolean, signaling: BaseSignaling, mediaSource: MediaSource, serverSettings: ServerSettings) {\n super(signaling, mediaSource);\n\n this._participantId = participantId;\n this._isMaster = isMaster;\n this._serverSettings = serverSettings;\n\n this._perfStatReporter = new PerfStatReporter(this, signaling, true);\n this._directStatReporter = new DirectStatReporter(signaling);\n\n this.subscribe(this._signaling, SignalingEvent.NOTIFICATION, this._onSignalingNotification.bind(this));\n this.subscribe(this._mediaSource, MediaSourceEvent.TRACK_REPLACED, this._onReplacedTrack.bind(this));\n this.subscribe(this._mediaSource, MediaSourceEvent.SOURCE_CHANGED, this._applySettings.bind(this));\n this.subscribe(this._directStatReporter, TransportEvent.NETWORK_STATUS, this._onNetworkStatus.bind(this));\n\n try {\n this._pc = new RTCPeerConnection({\n iceServers: Params.iceServers,\n iceTransportPolicy: Params.forceRelayPolicy ? 'relay' : 'all',\n });\n } catch (error: any) {\n Debug.error('Failed to create RTCPeerConnection:', error);\n this.close(error);\n return;\n }\n\n this._pc.onicecandidate = this._handleIceCandidate.bind(this);\n this._pc.ontrack = this._onAddTrack.bind(this);\n this._pc.oniceconnectionstatechange = this._onIceConnectionStateChange.bind(this);\n this._pc.onconnectionstatechange = this._onConnectionStateChange.bind(this);\n this._pc.onsignalingstatechange = this._onSignalingStateChange.bind(this);\n this._prevConsumerSettings = {};\n\n if (Params.vmoji) {\n this._createDataChannel(this._pc, DataChannelLabel.animoji, (dataChannel: RTCDataChannel) => {\n this._animojiDataChannel = dataChannel;\n this._animojiDataChannel.binaryType = 'arraybuffer';\n this._animojiReceiver?.setDataChannel(this._animojiDataChannel);\n this._animojiSender?.setDataChannel(this._animojiDataChannel);\n });\n }\n\n if (this._isMaster) {\n try {\n this._mediaSource.addTrackToPeerConnection(this._pc, false, true);\n this._applySettings();\n } catch (error) {\n Logger.log(StatLog.ERROR, 'addTrack-direct');\n Debug.error('Unable to add media source tracks', error, { participantId: this._participantId });\n\n this._failedOnCreate = error;\n\n return;\n }\n\n this._createOffer(false).catch((error: any) => {\n if (this._state === TransportState.IDLE) {\n this._failedOnCreate = error;\n } else {\n this.close(error);\n }\n });\n }\n\n this._startSettingsInterval();\n }\n\n get participantId(): ParticipantId {\n return this._participantId;\n }\n\n updateStatisticsInterval() {\n this._stopStatInterval();\n\n if (!this._isDeadConnection()) {\n this._startStatInterval();\n }\n }\n\n private _isDeadConnection(): boolean {\n return [TransportState.IDLE, TransportState.CLOSED, TransportState.FAILED].includes(this.getState());\n }\n\n async open(peerId: string | null = null) {\n if (this._isOpen) {\n Debug.warn('DirectTransport: Already opened', { participantId: this._participantId });\n return;\n }\n\n if (this._failedOnCreate) {\n this.close(this._failedOnCreate);\n return;\n }\n\n Debug.debug('DirectTransport: Open transport', { participantId: this._participantId });\n\n this._isOpen = true;\n this._remotePeerId = peerId;\n\n if (!this._isMaster) {\n try {\n this._mediaSource.addTrackToPeerConnection(this._pc as RTCPeerConnection, false, true);\n this._applySettings();\n } catch (error: any) {\n Logger.log(StatLog.ERROR, 'addTrack-direct');\n Debug.error('DirectTransport: Unable to add media source tracks', error, { participantId: this._participantId });\n\n this.close(error);\n return;\n }\n }\n\n // some of the classes that listen to transport state events rely on OPENED, so it has to be delivered;\n // at the same time this shouldn't be done after the \"await\" call below, as by the time waiting finishes the state may already be CONNECTED\n // (which from the client's point of view will look like an incorrect CONNECTED -> OPENED transition)\n this._setState(TransportState.OPENED);\n\n let sdpPeerId = peerId;\n if (!peerId) {\n const sdpPeerIds = Object.keys(this._remoteSDP);\n sdpPeerId = sdpPeerIds[sdpPeerIds.length - 1];\n }\n\n if (sdpPeerId && this._remoteSDP[sdpPeerId]) {\n try {\n await this._setRemoteDescription(sdpPeerId, this._remoteSDP[sdpPeerId]);\n } catch (e) {\n this.close();\n return;\n }\n }\n\n this._remoteSDP = {};\n this._remoteCandidates = {};\n }\n\n updateSettings(settings: ServerSettings) {\n if (compareServerSettings(settings, this._serverSettings)) {\n return;\n }\n this._serverSettings = settings;\n this._applySettings();\n }\n\n preventRestart() {\n this._reconnectionPrevented = true;\n }\n\n allowRestart() {\n this._reconnectionPrevented = false;\n }\n\n setAnimojiTransport(receiver: AnimojiReceiver, sender: AnimojiSender) {\n if (!Params.vmoji) {\n return;\n }\n\n this._animojiReceiver = receiver;\n this._animojiSender = sender;\n\n receiver.setParticipantId(this._participantId);\n\n if (this._animojiDataChannel) {\n receiver.setDataChannel(this._animojiDataChannel);\n sender.setDataChannel(this._animojiDataChannel);\n return;\n }\n }\n\n close(error?: Error) {\n if (!this._isOpen) {\n return;\n }\n\n this._isOpen = false;\n this._stopReconnection();\n\n if (this._remoteStream) {\n this._remoteStream.getTracks().forEach((track) => {\n track.stop();\n // Нужно при смене топологии\n this._triggerEvent(TransportEvent.REMOTE_TRACK_REMOVED, this._remoteStream, track);\n });\n this._remoteStream = null;\n }\n\n this._stopStatInterval();\n this._stopSettingsInterval();\n\n if (this._pc) {\n if (this._animojiDataChannel) {\n this._animojiDataChannel.onopen = null;\n this._animojiDataChannel.onmessage = null;\n this._animojiDataChannel.onerror = null;\n this._animojiDataChannel.close();\n }\n this._pc.onicecandidate = null;\n this._pc.ontrack = null;\n this._pc.oniceconnectionstatechange = null;\n this._pc.onconnectionstatechange = null;\n this._pc.onsignalingstatechange = null;\n this._pc.close();\n this._pc = null;\n }\n\n // Сбрасываем текущий рейтинг сети для восстановления индикатора\n this._onNetworkStatus(1.0);\n this.unsubscribe();\n\n if (error) {\n Debug.error('DirectTransport: Closed', error, { participantId: this._participantId });\n this._setState(TransportState.FAILED);\n } else {\n Debug.debug('DirectTransport: Closed', { participantId: this._participantId });\n this._setState(TransportState.CLOSED);\n }\n\n this._triggerEvent(TransportEvent.PEER_CONNECTION_CLOSED);\n }\n\n private _setState(state: TransportState) {\n if (this._state === state) {\n return;\n }\n\n Debug.debug(`DirectTransport: State changed to ${state}`, { participantId: this._participantId });\n\n this._state = state;\n this._triggerEvent(TransportEvent.STATE_CHANGED, state);\n }\n\n private _onSignalingNotification(message: SignalingMessage) {\n switch (message.notification) {\n case SignalingNotification.TRANSMITTED_DATA:\n this._handleTransmittedData(message as SignalingMessage.TransmittedData);\n break;\n\n case SignalingNotification.SETTINGS_UPDATE:\n this._directStatReporter.updateSettings(message.settings as NetworkLimits);\n break;\n\n case SignalingNotification.CUSTOM_DATA:\n // https://wiki.odkl.ru/pages/viewpage.action?pageId=82972422\n if (Object.hasOwn(message.data, 'sdk')) {\n this._directStatReporter.reportRemote(message.data?.sdk as SignalingNetworkStat);\n }\n break;\n }\n }\n\n private _handleTransmittedData(message: SignalingMessage.TransmittedData) {\n const data = message.data;\n const peerId = Utils.getPeerIdString(message.peerId);\n const participantId = Utils.composeMessageId(message);\n\n if (participantId !== this._participantId) {\n return;\n }\n\n // По спеке пустой data.candidate.candidate говорит о том, что кандидаты закончились\n // но Safari плевал на спеку, поэтому проверяем и не применяем таких кандидатов\n if (data.candidate && data.candidate.candidate) {\n this._addIceCandidate(peerId, data.candidate).catch(this.close.bind(this));\n } else if (data.sdp) {\n this._remoteAnimojiVersion = data.animojiVersion || 1;\n this._setRemoteDescription(peerId, data.sdp).catch(this.close.bind(this));\n }\n }\n\n private async _addIceCandidate(peerId: string, candidate: RTCIceCandidateInit): Promise<void> {\n if (this._isOpen && (!this._remotePeerId || this._remotePeerId === peerId) && this._pc && this._pc.remoteDescription) {\n Debug.debug('Add remote ice candidate', {\n participantId: this._participantId,\n candidate,\n });\n\n try {\n await this._pc.addIceCandidate(new RTCIceCandidate(candidate));\n } catch (e) {\n Logger.log(StatLog.ERROR, 'addIceCandidate-direct');\n Debug.error('Unable to add remote ice candidate', e, { participantId: this._participantId, candidate });\n throw e;\n }\n } else {\n Debug.debug('Cache remote ice candidate', {\n participantId: this._participantId,\n candidate,\n });\n\n this._remoteCandidates[peerId] = this._remoteCandidates[peerId] || [];\n this._remoteCandidates[peerId].push(candidate);\n }\n }\n\n private async _setRemoteCandidates(peerId: string) {\n if (!this._remoteCandidates[peerId]) {\n Debug.log(`No cached candidates found for peer ${peerId}`);\n return;\n }\n\n const candidates = this._remoteCandidates[peerId];\n this._remoteCandidates[peerId] = [];\n\n for (const candidate of candidates) {\n try {\n await this._addIceCandidate(peerId, candidate);\n } catch (e) {}\n }\n }\n\n private async _setRemoteDescription(peerId: string, sdp: Required<RTCSessionDescriptionInit>): Promise<void> {\n if (this._isOpen && (!this._remotePeerId || this._remotePeerId === peerId) && this._pc) {\n if (this._lastRemoteSDP?.sdp === sdp.sdp) {\n // Бывает, что бэк присылает тот же оффер второй раз.\n // Пока на бэке нет фикса, проверяем тут\n return;\n }\n this._lastRemoteSDP = sdp;\n\n sdp = DirectTransport._patchRemoteDescription(sdp);\n\n Debug.debug('Add remote description', {\n participantId: this._participantId,\n sdp,\n });\n\n this._calcFingerprint(sdp.sdp as string);\n\n try {\n await this._pc.setRemoteDescription(sdp);\n await this._setRemoteCandidates(peerId);\n this._processAnimojiProtocolVersion(this._remoteAnimojiVersion);\n } catch (e) {\n Logger.log(StatLog.ERROR, 'setRemoteDescription-direct');\n Debug.error('Unable to set remote description', e, { participantId: this._participantId, sdp });\n throw e;\n }\n } else {\n this._remoteSDP[peerId] = sdp;\n }\n }\n\n private _processAnimojiProtocolVersion(version: AnimojiVersion) {\n const versionToUse = Math.min(version, Params.vmojiOptions?.protocolVersion || 1) as AnimojiVersion;\n\n this._animojiSender?.setProtocolVersion(versionToUse);\n }\n\n private _onAddTrack(event: any) {\n Debug.debug('Added remote track', { participantId: this._participantId, kind: event.track.kind });\n\n if (!this._remoteStream) {\n this._remoteStream = new MediaStream([event.track]);\n this._remoteStream.onremovetrack = (e) => {\n this._triggerEvent(TransportEvent.REMOTE_TRACK_REMOVED, this._remoteStream, e.track);\n };\n } else {\n this._remoteStream.addTrack(event.track);\n }\n\n this._triggerEvent(TransportEvent.REMOTE_TRACK_ADDED, this._remoteStream, event.track);\n }\n\n private async _handleIceCandidate(event: RTCPeerConnectionIceEvent) {\n if (event.candidate && this._signaling.ready) {\n Debug.debug('Local ice candidate', { participantId: this._participantId, candidate: event.candidate });\n\n await this._signaling.sendCandidate(this._participantId, event.candidate);\n }\n }\n\n private _onSignalingStateChange() {\n Debug.debug(`DirectTransport: Signaling state changed to ${this._pc?.signalingState}`, { participantId: this._participantId });\n const extraPayload = {\n animojiVersion: Params.vmojiOptions.protocolVersion || 1,\n };\n\n switch (this._pc?.signalingState) {\n case 'have-local-offer':\n const sdp = this._pc.localDescription;\n if (sdp) {\n this._signaling.sendSdp(this._participantId, sdp, extraPayload).catch(this.close.bind(this));\n } else {\n this.close(new Error());\n }\n break;\n\n case 'have-remote-offer':\n this._createAnswer()\n .then((answer) => this._signaling.sendSdp(this._participantId, answer, extraPayload))\n .catch(this.close.bind(this));\n break;\n }\n }\n\n private _onIceConnectionStateChange() {\n Debug.debug(`DirectTransport: Ice Connection state changed to ${this._pc?.iceConnectionState}`, { participantId: this._participantId });\n\n switch (this._pc?.iceConnectionState) {\n // connectionState === 'connecting' плохо работает в сафари, поэтому проверяем по iceConnectionState\n case 'checking':\n const state = this.getState();\n if (state === TransportState.IDLE || state === TransportState.OPENED) {\n this._setState(TransportState.CONNECTING);\n } else {\n this._setState(TransportState.RECONNECTING);\n }\n break;\n }\n }\n\n private _onConnectionStateChange() {\n Debug.debug(`DirectTransport: Connection state changed to ${this._pc?.connectionState}`, { participantId: this._participantId });\n Logger.log(StatLog.ICE_CONNECTION_STATE, this._pc?.connectionState);\n\n switch (this._pc?.connectionState) {\n case 'connected':\n this._neverConnected = false;\n this._setState(TransportState.CONNECTED);\n this._stopReconnection();\n Utils.getPeerConnectionHostInfo(this._pc).then((data) => {\n if (data?.local) {\n Logger.log(StatLog.ICE_CONNECTION_TYPE, data.local.type);\n Debug.debug('Selected ICE candidates', data);\n }\n });\n this._startStatInterval(); // запуск и восстановление после disconnected\n break;\n\n case 'failed':\n case 'disconnected':\n if (this._reconnectionPrevented) {\n this.close(new Error(`Ice connection ${this._pc.connectionState}`));\n } else {\n this._setState(TransportState.RECONNECTING);\n this._startReconnection();\n }\n break;\n\n case 'closed':\n this.close(new Error('Ice connection closed'));\n break;\n }\n }\n\n private _startReconnection() {\n if (this._reconnectionTimeout || this._iceRestartTimeout) {\n return;\n }\n\n Debug.log('Waiting for reconnection...', { participantId: this._participantId });\n this._reconnectionTimeout = window.setTimeout(() => {\n this._reconnectionTimeout = null;\n // Если ещё никогда не подключались, меняем топологию\n if (this._neverConnected) {\n this._requestTopologySwitch();\n } else {\n this._startIceRestart();\n }\n }, Params.transportConnectionWaitTime);\n }\n\n private _requestTopologySwitch() {\n if (this._isMaster && this._signaling.ready) {\n Debug.log('Switch topology DIRECT to SERVER', { participantId: this._participantId });\n this._signaling.switchTopology(TransportTopology.SERVER);\n }\n }\n\n private _stopReconnection() {\n if (this._reconnectionTimeout) {\n clearTimeout(this._reconnectionTimeout);\n this._reconnectionTimeout = null;\n }\n\n if (this._iceRestartTimeout) {\n clearTimeout(this._iceRestartTimeout);\n this._iceRestartTimeout = null;\n }\n }\n\n private _startIceRestart() {\n if (this._isMaster) {\n Logger.log(StatLog.ICE_RESTART);\n Debug.log('Ice restart', { participantId: this._participantId });\n this._createOffer(true).catch(this.close.bind(this));\n } else {\n Debug.debug('Waiting for ice restart...', { participantId: this._participantId });\n }\n\n this._iceRestartTimeout = window.setTimeout(() => {\n this._iceRestartTimeout = null;\n Debug.error('Ice restart failed', { participantId: this._participantId });\n Logger.log(StatLog.ERROR, 'iceRestart-direct');\n this._requestTopologySwitch();\n }, Params.iceRestartWaitTime);\n }\n\n private async _createOffer(iceRestart: boolean): Promise<Required<RTCSessionDescriptionInit>> {\n const options = {\n iceRestart,\n offerToReceiveAudio: true,\n offerToReceiveVideo: true,\n };\n\n Debug.debug('Create offer', { participantId: this._participantId, options });\n\n let offer: Required<RTCSessionDescriptionInit>;\n try {\n offer = (await this._pc?.createOffer(options)) as Required<RTCSessionDescriptionInit>;\n Debug.debug('Created offer', { participantId: this._participantId, offer });\n offer = DirectTransport._patchLocalDescription(offer);\n } catch (error) {\n Debug.error('Unable to create offer', error, { participantId: this._participantId });\n Logger.log(StatLog.ERROR, 'createOffer-direct');\n\n throw error;\n }\n\n try {\n Debug.debug('Set local description', { participantId: this._participantId, offer });\n\n this._calcFingerprint(offer.sdp);\n await this._pc?.setLocalDescription(offer);\n return offer;\n } catch (error) {\n Debug.error('Unable to set local description', error, { participantId: this._participantId });\n Logger.log(StatLog.ERROR, 'setLocalDescription-direct');\n\n throw error;\n }\n }\n\n private async _createAnswer(): Promise<Required<RTCSessionDescriptionInit>> {\n Debug.debug('Create answer', { participantId: this._participantId });\n\n let answer: Required<RTCSessionDescriptionInit>;\n try {\n answer = (await this._pc?.createAnswer()) as Required<RTCSessionDescriptionInit>;\n Debug.debug('Created answer', { participantId: this._participantId, answer });\n answer = DirectTransport._patchLocalDescription(answer);\n } catch (error) {\n Debug.error('Unable to create answer', error, { participantId: this._participantId });\n Logger.log(StatLog.ERROR, 'createAnswer-direct');\n\n throw error;\n }\n\n try {\n Debug.debug('Set local description', { participantId: this._participantId, answer });\n\n this._calcFingerprint(answer.sdp);\n await this._pc?.setLocalDescription(answer);\n return answer;\n } catch (error) {\n Debug.error('Unable to set local description', error, { participantId: this._participantId });\n Logger.log(StatLog.ERROR, 'setLocalDescription-direct');\n\n throw error;\n }\n }\n\n private static _patchLocalDescription(description: Required<RTCSessionDescriptionInit>) {\n const isChromiumBased = !!WebRTCUtils.baseChromeVersion();\n description.sdp = Utils.patchLocalSDP(\n description.sdp,\n Params.preferH264 && WebRTCUtils.canPreferH264(),\n WebRTCUtils.isBrokenH264Decoder(),\n Params.preferVP9,\n Params.h264spsPpsIdrInKeyframe,\n isChromiumBased && Params.audioNack,\n Params.p2pAudioRed,\n );\n\n return description;\n }\n\n private static _patchRemoteDescription(description: Required<RTCSessionDescriptionInit>) {\n description.sdp = Utils.patchRemoteSDP(description.sdp, false, false, false, Params.preferVP9, WebRTCUtils.isBrokenVP9Encoder(), WebRTCUtils.isBrokenVP9Decoder());\n\n return description;\n }\n\n private _onReplacedTrack(newTrack: MediaStreamTrack) {\n if (this._pc) {\n this._pc.getSenders().forEach((sender) => {\n if (sender.track && sender.track.kind === newTrack.kind && sender.track.contentHint === newTrack.contentHint) {\n // Перед реплейсом нужно старый трек включить/выключить, иначе после замены не будет работать (в FF)\n // upd. 15.07.2024 проверил в FF - все работает без переключения старого трека, принял решение закомментировать, т. к. мешает работе аудио эффектов\n // sender.track.enabled = newTrack.enabled;\n sender.replaceTrack(newTrack).catch((error) => {\n Debug.error('DirectTransport: Unable to replace track', error, { participantId: this._participantId });\n Logger.log(StatLog.ERROR, 'replaceTrack-direct');\n });\n }\n });\n this._applySettings();\n }\n }\n\n private _startStatInterval() {\n if (this._statInterval) {\n return;\n }\n\n const inner = () => {\n if (this._isDeadConnection()) {\n this._stopStatInterval();\n return;\n }\n\n Statistics.collectStats(this._pc as RTCPeerConnection, this._lastStat, undefined, true).then((stat) => {\n this._lastStat = stat;\n CodecStatsAggregator.reportUsage(stat);\n const stats: StatResult = {\n inbound: {\n topology: TransportTopology.DIRECT,\n transport: stat.transport,\n rtps: stat.rtps.filter((rtp) => {\n if (rtp.type === 'inbound-rtp') {\n rtp.userId = this._participantId;\n return true;\n }\n return false;\n }),\n },\n outbound: {\n topology: TransportTopology.DIRECT,\n transport: stat.transport,\n rtps: stat.rtps.filter((rtp) => rtp.type === 'outbound-rtp'),\n },\n remoteInbound: {\n topology: TransportTopology.DIRECT,\n transport: stat.transport,\n rtps: stat.remoteRtps ?? [],\n },\n };\n\n this._checkPPTNetwork(stats);\n this._directStatReporter.reportLocal(stats);\n this._triggerEvent(TransportEvent.REMOTE_DATA_STATS, stats);\n this._statInterval = window.setTimeout(inner, Params.statisticsInterval);\n });\n };\n\n this._statInterval = window.setTimeout(inner, Params.statisticsInterval);\n }\n\n /**\n * Check SVC support\n * @see https://webrtc.internaut.com/mc/\n */\n private async _isSVCSupported(stats: StatResult, scalabilityMode: VideoScalability) {\n const track = this._mediaSource.getSendVideoTrack();\n const rtp = stats.outbound.rtps.find((item) => item.kind === 'video');\n if (!rtp?.mimeType || !rtp?.bandwidth || !track) {\n return false;\n }\n\n const trackSettings = track.getSettings();\n if (!trackSettings.width || !trackSettings.height || !trackSettings.frameRate) {\n return false;\n }\n\n const mediaConfig: MediaEncodingConfiguration = {\n // @ts-ignore https://developer.mozilla.org/en-US/docs/Web/API/MediaCapabilities/encodingInfo#type\n type: WebRTCUtils.browserName() === 'Firefox' ? 'transmission' : 'webrtc',\n video: {\n contentType: rtp.mimeType,\n width: trackSettings.width,\n height: trackSettings.height,\n bitrate: rtp.bandwidth,\n framerate: trackSettings.frameRate,\n scalabilityMode,\n },\n };\n\n try {\n const encodingInfo = await navigator.mediaCapabilities.encodingInfo(mediaConfig);\n return encodingInfo.supported || false;\n } catch (e: any) {\n Debug.warn('Failed to get encodingInfo', mediaConfig, e);\n return false;\n }\n }\n\n private async _checkPPTNetwork(stats: StatResult) {\n // ручка =)\n if (!Params.switchVideoAtBadNetwork || !stats.inbound.transport.averageNetStat) {\n return;\n }\n\n // в stats.inbound и stats.outbound transport одинаковый\n const { averageNetStat } = stats.inbound.transport;\n const isGoodConnection = averageNetStat.currentRoundTripTime <= this._networkLimitsForVideo.good.rtt && averageNetStat.lostPercent <= this._networkLimitsForVideo.good.loss; // хорошая сеть, снять ограничения на размер\n const isBadConnection = averageNetStat.currentRoundTripTime >= this._networkLimitsForVideo.bad.rtt || averageNetStat.lostPercent >= this._networkLimitsForVideo.bad.loss; // плохая сеть, ограничить размер\n const isLossfullConnection = averageNetStat.currentRoundTripTime < this._networkLimitsForVideo.bad.rtt; // используем при условиях высоких потерь\n\n let nextVideoMaxDimension = this._videoMaxDimensionsForNet.good;\n let scalabilityMode = VideoScalability.L1T1;\n if (isBadConnection) {\n this._lastBadConnection = Date.now(); // обновляем ts последнего \"плохого соединения\"\n\n if (isLossfullConnection) {\n // потери высокие, но rtt < 1000\n nextVideoMaxDimension = this._videoMaxDimensionsForNet.bad;\n scalabilityMode = VideoScalability.L1T2;\n } else {\n // потери высокие, и rtt >= 1000\n nextVideoMaxDimension = this._videoMaxDimensionsForNet.worst;\n scalabilityMode = VideoScalability.L1T3;\n }\n } else if (isGoodConnection) {\n // низкие потери и достаточно низкий rtt\n nextVideoMaxDimension = this._videoMaxDimensionsForNet.good;\n scalabilityMode = VideoScalability.L1T1;\n } // иначе оставляем как есть\n\n // надо обновлять не чаще чем раз в 30 сек, НО\n // в плохую переключать сразу, в хорошую через 30 сек\n const isNeedFrameUpdate = nextVideoMaxDimension < this._lastVideoMaxDimension || Date.now() - this._lastBadConnection > TIME_WITHOUT_UPDATE_VIDEO_FRAME;\n\n if (\n !isNeedFrameUpdate || // пока рано обновлять\n this._lastVideoMaxDimension === nextVideoMaxDimension // если значение такое же, не будем дергать обновление\n ) {\n return;\n }\n\n const videoSettings = this._serverSettings.camera;\n if (!videoSettings) {\n return;\n }\n\n const svc = await this._isSVCSupported(stats, scalabilityMode);\n if (!svc) {\n return;\n }\n\n Debug.debug('Switch outbound video frame size and scalabilityMode', {\n scalabilityMode,\n averageNetStat,\n nextVideoMaxDimension,\n });\n this._lastVideoMaxDimension = nextVideoMaxDimension;\n\n const nextSettings: ServerSettings = { ...this._serverSettings, camera: { ...videoSettings, scalabilityMode, maxDimension: this._lastVideoMaxDimension } };\n this.updateSettings(nextSettings);\n }\n\n private _stopStatInterval() {\n if (this._statInterval) {\n window.clearTimeout(this._statInterval);\n this._statInterval = null;\n }\n }\n\n private _onNetworkStatus(rating: number) {\n const statuses: Record<ParticipantId, number> = {};\n // Возвращаем '' для текущего пользователя, т.к. не знаем его ID\n statuses[this._participantId] = statuses[''] = rating;\n this._triggerEvent(TransportEvent.NETWORK_STATUS, statuses);\n }\n\n private _startSettingsInterval() {\n const INTERVAL = 2000;\n if (this._settingsInterval) {\n return;\n }\n\n const inner = () => {\n if (!this._pc) {\n this._stopSettingsInterval();\n return;\n }\n\n this._applySettings();\n this._settingsInterval = window.setTimeout(inner, INTERVAL);\n };\n\n this._settingsInterval = window.setTimeout(inner, INTERVAL);\n }\n\n private _stopSettingsInterval() {\n if (this._settingsInterval) {\n window.clearTimeout(this._settingsInterval);\n this._settingsInterval = null;\n }\n }\n\n private _calcFingerprint(sdp: string) {\n const fp = Utils.sdpFingerprint(sdp);\n if (fp === null) {\n Debug.warn('Fingerprint calculation is unsupported');\n return;\n }\n\n if (this._fingerprint === null) {\n this._fingerprint = fp;\n } else {\n External.onFingerprintChange((this._fingerprint ^ fp).toString());\n this._fingerprint = null;\n }\n }\n\n private _applySettings() {\n const videoSettings = this._mediaSource.getMediaSettings().isScreenSharingEnabled ? this._serverSettings.screenSharing : this._serverSettings.camera;\n if (videoSettings && this._pc?.connectionState === 'connected') {\n this._prevConsumerSettings = Utils.applySettings(this._pc, videoSettings, this._prevConsumerSettings);\n }\n }\n\n private _createDataChannel(connection: RTCPeerConnection, label: DataChannelLabel, callback: (dataChannel: RTCDataChannel) => void) {\n Debug.debug(`[${label}] data channel opening`);\n const dataChannel = connection.createDataChannel(label, {\n negotiated: true,\n id: 1,\n });\n dataChannel.onopen = () => {\n const state = dataChannel.readyState;\n if (state === 'open') {\n Debug.debug(`[${label}] data channel opened`);\n dataChannel.onerror = (e: Event) => {\n Debug.error(`[${label}] data channel error`, e);\n };\n\n callback(dataChannel);\n } else {\n Debug.error(`[${label}] data channel open failed, state [${state}]`);\n }\n };\n }\n}\n", "export const enum TrackId {\n AUDIO_MIX = 'audio-mix',\n PARTICIPANT_AGNOSTIC_TRACK_PREFIX = 'pat',\n}\n\nexport default TrackId;\n", "import Debug from '../../static/Debug';\nimport { AsrTranscription } from '../../types/Asr';\nimport { ParticipantIdRegistry } from '../ParticipantIdRegistry';\n\nconst HEADER_SIZE = 16;\n\nexport class AsrReceiver {\n private readonly _datachannel: RTCDataChannel;\n private readonly _participantIdRegistry: ParticipantIdRegistry;\n private readonly _asrCallback: (asr: AsrTranscription) => void;\n private readonly _textDecoder: TextDecoder;\n\n constructor(datachannel: RTCDataChannel, participantIdRegistry: ParticipantIdRegistry, callback: (asr: AsrTranscription) => void) {\n Debug.debug('AsrReceiver started');\n\n this._datachannel = datachannel;\n this._participantIdRegistry = participantIdRegistry;\n this._asrCallback = callback;\n this._textDecoder = new TextDecoder();\n\n this._datachannel.onmessage = (e) => this._onDataChannelMessage(e.data);\n }\n\n // 1 byte - version\n // 1 byte - message type\n // 2 bytes - sequencenum\n // 4 bytes - ssrc <идентификатор пользователя>\n // 4 bytes - timestampMS\n // 4 bytes - duration\n private static parse(data: ArrayBuffer) {\n const view = new DataView(data);\n\n const version = view.getUint8(0); // Protocol Version, 1 byte\n const type = view.getUint8(1); // message type, 1 byte\n if (type !== 0) {\n throw new Error(`Unsupported message type. Message type: ${type}`);\n }\n const sequence = view.getUint16(2); // sequence, 2 bytes\n const ssrc = view.getUint32(4); // SSRC, 4 bytes\n const timestamp = view.getUint32(8); // timestamp, 4 bytes\n const duration = view.getUint32(12); // duration, 4 bytes\n\n if (version !== 1) {\n throw new Error(`Unexpected protocol version. Got ${version}, expected 1`);\n }\n\n return {\n sequence,\n ssrc,\n timestamp,\n duration,\n data: data.slice(HEADER_SIZE),\n };\n }\n\n private _onDataChannelMessage(data: ArrayBuffer) {\n const chunk = AsrReceiver.parse(data);\n const participantId = this._participantIdRegistry?.getStreamDescription(chunk.ssrc)?.participantId;\n if (!participantId) {\n Debug.warn(`Participant id for ssrc ${chunk.ssrc} not found in registry`);\n return;\n }\n\n const asr = {\n participantId,\n text: this._textDecoder.decode(chunk.data),\n timestamp: chunk.timestamp,\n duration: chunk.duration,\n } as AsrTranscription;\n\n this._asrCallback(asr);\n }\n\n destroy() {\n this._datachannel.onmessage = null;\n }\n}\n", "export class LocalNetworkRating {\n private static _instance: LocalNetworkRating | null = null;\n private _value = 1;\n\n public static getInstance = () => {\n if (!this._instance) {\n this._instance = new LocalNetworkRating();\n }\n\n return this._instance;\n };\n\n public get value() {\n return this._value;\n }\n\n public set value(value: number) {\n this._value = value;\n }\n}\n", "import { decode } from 'messagepack';\nimport SignalingNotification from '../enums/SignalingNotification';\nimport TrackId from '../enums/TrackId';\nimport Debug from '../static/Debug';\nimport { ISharedMovieState, ISharedMovieStateResponse } from '../types/MovieShare';\nimport { ParticipantId } from '../types/Participant';\nimport { MediaType, parseParticipantStreamDescription, ParticipantStreamDescription } from '../types/ParticipantStreamDescription';\nimport SignalingMessage from '../types/SignalingMessage';\n\nexport class ParticipantIdRegistry {\n private streamDescriptionByCompactId: Map<number, ParticipantStreamDescription> = new Map<number, ParticipantStreamDescription>();\n private compactIdByStreamDescription: Map<string, number> = new Map<string, number>();\n\n getStreamDescription(compactedId: number): ParticipantStreamDescription | undefined {\n return this.streamDescriptionByCompactId.get(compactedId);\n }\n\n getCompactId(streamDescription: string): number | undefined {\n return this.compactIdByStreamDescription.get(streamDescription);\n }\n\n handleMessage(data: ArrayBuffer): SignalingMessage | null {\n const arr = new Uint8Array(data);\n const type = arr[0]; // First byte\n const payload = arr.subarray(1);\n\n switch (type) {\n case 1:\n const idsMap = decode<{ [key: string]: number }>(payload);\n Object.entries(idsMap).forEach(([descriptionString, compactedId]) => {\n const streamDescription = parseParticipantStreamDescription(descriptionString);\n this.streamDescriptionByCompactId.set(compactedId, streamDescription);\n this.compactIdByStreamDescription.set(descriptionString, compactedId);\n });\n return null;\n case 2:\n case 4:\n const compactedIds: number[] = decode(payload);\n const ids: ParticipantId[] = [];\n for (const compactId of compactedIds) {\n const streamDescription = this.getStreamDescription(compactId);\n if (streamDescription) {\n ids.push(streamDescription.participantId);\n }\n }\n if (type === 2) {\n return {\n type: 'notification',\n notification: SignalingNotification.AUDIO_ACTIVITY,\n activeParticipants: ids,\n };\n } else {\n return {\n type: 'notification',\n notification: SignalingNotification.STALLED_ACTIVITY,\n stalledParticipants: ids,\n };\n }\n case 3:\n const speaker: number = decode(payload);\n return {\n type: 'notification',\n notification: SignalingNotification.SPEAKER_CHANGED,\n speaker: this.getStreamDescription(speaker)?.participantId,\n };\n case 5:\n const decoded: number[] = decode(payload);\n return {\n type: 'notification',\n notification: SignalingNotification.VIDEO_QUALITY_UPDATE,\n quality: {\n maxBitrate: decoded[0],\n maxDimension: decoded[1],\n },\n mediaType: this._decodeMediaType(decoded[2]),\n };\n case 6:\n const compacted = decode<{ [key: number]: number }>(payload);\n const statuses: { [key: string]: number } = {};\n for (const [participant, status] of Object.entries(compacted)) {\n const participantId = this.getStreamDescription(Number(participant))?.participantId;\n if (participantId) {\n statuses[participantId] = status / 100;\n }\n }\n return {\n type: 'notification',\n notification: SignalingNotification.NETWORK_STATUS,\n statuses,\n };\n case 7:\n return this._createParticipantSourcesUpdateNotification(payload);\n // movie-update-notification (Изменения по мувику в совместном просмотре)\n case 8: {\n const compactedStateList = decode<ISharedMovieStateResponse[]>(payload);\n const stateList = compactedStateList.map<ISharedMovieState>((state) => {\n const [compactedParticipantId, gain, pause, offset, mute, liveStatus, startTimeMs] = state;\n\n return {\n participantId: this.getStreamDescription(compactedParticipantId)?.participantId as ParticipantId,\n gain,\n pause,\n offset,\n mute,\n liveStatus,\n startTimeMs,\n };\n });\n\n return {\n type: 'notification',\n notification: SignalingNotification.MOVIE_UPDATE_NOTIFICATION,\n data: stateList,\n };\n }\n case 9:\n // video-suspend-suggest\n // current bandwidth, kbps\n const bandwidth: number = decode(payload);\n return {\n type: 'notification',\n notification: SignalingNotification.VIDEO_SUSPEND_SUGGEST,\n bandwidth,\n };\n\n default:\n Debug.debug('unsupported message type: ' + type);\n return null;\n }\n }\n\n private _decodeMediaType(value: number): MediaType | null {\n if (value === null) {\n return null;\n }\n switch (value) {\n case 0:\n return MediaType.CAMERA;\n case 1:\n return MediaType.SCREEN;\n default:\n throw new Error(`Unsupported media type: ${value}`);\n }\n }\n\n private _createParticipantSourcesUpdateNotification(payload: Uint8Array) {\n const compacted = decode<{ [key: number]: (number | null)[] }>(payload);\n\n const participantUpdateInfos: SignalingMessage.ParticipantUpdateInfo[] = [];\n for (const [trackIdx, sourceUpdateInfo] of Object.entries(compacted)) {\n const compactParticipantId = sourceUpdateInfo[0];\n const rtpTimestampAsSigned32Int = sourceUpdateInfo[1];\n const sequenceNumber = sourceUpdateInfo[2];\n const fastScreenShare = !!sourceUpdateInfo[3];\n const suspend = sourceUpdateInfo[4] !== null ? !!sourceUpdateInfo[4] : undefined;\n\n let participantStreamDescription;\n if (compactParticipantId !== null) {\n participantStreamDescription = this.getStreamDescription(compactParticipantId);\n if (!participantStreamDescription) {\n Debug.error(`could not uncompress participant ID ${compactParticipantId}`);\n continue;\n }\n } else {\n participantStreamDescription = null;\n }\n\n if (sequenceNumber === null) {\n Debug.error('unexpected null sequenceNumber', trackIdx, sourceUpdateInfo);\n continue;\n }\n\n const streamId = TrackId.PARTICIPANT_AGNOSTIC_TRACK_PREFIX + '-' + trackIdx;\n // Messagepack decodes bits as if they represented signed 32-bit integer, while in this particular case unsigned 32-bit integer is received;\n // unsigned right shift \"converts\" value to unsigned int, while maintaining the same bit representation\n const rtpTimestamp = rtpTimestampAsSigned32Int ? rtpTimestampAsSigned32Int >>> 0 : null;\n participantUpdateInfos.push({ participantStreamDescription, streamId, rtpTimestamp, sequenceNumber, fastScreenShare, suspend });\n }\n\n return {\n type: 'notification',\n notification: SignalingNotification.PARTICIPANT_SOURCES_UPDATE,\n participantUpdateInfos,\n };\n }\n}\n", "import type { AnimojiReceiver, AnimojiSender } from '@vkontakte/calls-vmoji';\nimport BaseSignaling from '../../abstract/BaseSignaling';\nimport DataChannelLabel from '../../enums/DataChannelLabel';\nimport SignalingEvent from '../../enums/SignalingEvent';\nimport SignalingNotification from '../../enums/SignalingNotification';\nimport StatLog from '../../enums/StatLog';\nimport TrackId from '../../enums/TrackId';\nimport Debug from '../../static/Debug';\nimport Params from '../../static/Params';\nimport Utils from '../../static/Utils';\nimport WebRTCUtils from '../../static/WebRTCUtils';\nimport { AsrTranscription } from '../../types/Asr';\nimport { ParticipantId } from '../../types/Participant';\nimport ServerSettings, { compareServerSettings } from '../../types/ServerSettings';\nimport SignalingMessage from '../../types/SignalingMessage';\nimport type { SimulcastInfo } from '../../types/SimulcastInfo';\nimport { ChangeSimulcast } from '../../types/ChangeSimulcast';\nimport { AsrReceiver } from '../asr/AsrReceiver';\nimport { LocalNetworkRating } from '../LocalNetworkRating';\nimport Logger from '../Logger';\nimport { MediaSource, MediaSourceEvent, MediaTrackKind, MediaSourceType } from '../MediaSource';\nimport { ParticipantIdRegistry } from '../ParticipantIdRegistry';\nimport ScreenCaptureReceiver from '../screenshare/ScreenCaptureReceiver';\nimport ScreenCaptureSender from '../screenshare/ScreenCaptureSender';\nimport { StatItem } from '../../types/Statistics';\nimport { calculateSimulcastInfo, isEqualSimulcastInfo, findScaleResolutionDownBy, SIMULCAST_DEFAULT, SIMULCAST_SCALABILITY_MODE } from '../../static/SimulcastInfo';\nimport { CodecStatsAggregator } from '../stat/CodecStatsAggregator';\nimport BaseTransport from './BaseTransport';\nimport PerfStatReporter from './PerfStatReporter';\nimport Statistics from './Statistics';\nimport { TransportEvent, TransportState, TransportTopology } from './Transport';\n\nconst RTP_VIDEO_CLOCKRATE = 90;\nconst RTP_MAX_TIMESTAMP = 0xffffffff;\n\nexport default class ServerTransport extends BaseTransport {\n private _producerNotification: RTCDataChannel | null = null;\n private _producerCommand: RTCDataChannel | null = null;\n private _producerScreen: RTCDataChannel | null = null;\n private _consumerScreen: RTCDataChannel | null = null;\n private _asr: RTCDataChannel | null = null;\n private _animojiDataChannel: RTCDataChannel | null = null;\n private _animojiReceiver: AnimojiReceiver | null = null;\n private _animojiSender: AnimojiSender | null = null;\n private _isOpen = false;\n private _observer = false;\n private _reconnectionPrevented = false;\n private _statInterval: number | null = null;\n private _settingsInterval: number | null = null;\n private _monitorRtpShareInterval: number | null = null;\n private _statBytes: Record<string, { bytesReceived: number; stalled: boolean }> = {};\n private _ssrcMap: Record<string, ParticipantId> = {};\n private _ssrcMapUpdated = false;\n private _perfStatReporter: PerfStatReporter;\n private _producerOfferIsProcessing = false;\n private _producerNextOffer: string | null = null;\n private _lastStat: StatItem | null = null;\n private _serverSettings: ServerSettings;\n private _prevConsumerSettings: any = {};\n private _prevConsumerFastSharingSettings: any = {};\n private _asrTrack: AsrReceiver | null = null;\n private _captureSender: ScreenCaptureSender | null = null;\n private _captureReceiver: ScreenCaptureReceiver | null = null;\n private _participantIdRegistry: ParticipantIdRegistry | null = null;\n private _disabledSenders = new Set<RTCRtpSender>();\n private _rtpReceiversByStreamId: Record<string, RTCRtpReceiver> = {};\n private _producerSessionId = '';\n private _newAudioShareTrack: MediaStreamTrack | null = null;\n private _simulcastInfo: SimulcastInfo | null = null;\n\n constructor(signaling: BaseSignaling, mediaSource: MediaSource, serverSettings: ServerSettings) {\n super(signaling, mediaSource);\n\n this.subscribe(this._signaling, SignalingEvent.NOTIFICATION, this._onSignalingNotification.bind(this));\n this.subscribe(this._mediaSource, MediaSourceEvent.TRACK_REPLACED, this._onReplacedTrack.bind(this));\n this.subscribe(this._mediaSource, MediaSourceEvent.SOURCE_CHANGED, this._onSourcesChanged.bind(this));\n this.subscribe(this._mediaSource, MediaSourceEvent.SCREEN_STATUS, this._onScreenSharingStatus.bind(this));\n\n this._createPerfStatsReporter();\n this._serverSettings = serverSettings;\n\n Debug.debug('ServerTransport: Created');\n }\n\n updateStatisticsInterval() {\n this._stopStatInterval();\n\n const state = this.getState();\n if (state !== TransportState.IDLE && state !== TransportState.CLOSED && state !== TransportState.FAILED) {\n this._startStatInterval();\n }\n }\n\n open(observer = false) {\n if (this._isOpen) {\n Debug.log('ServerTransport: Already opened connections');\n return;\n }\n this._isOpen = true;\n this._observer = observer;\n\n this._openConnection();\n }\n\n override close(error?: Error) {\n if (!this._isOpen) {\n return;\n }\n\n this._isOpen = false;\n this._closeConnection();\n\n this.unsubscribe();\n\n if (error) {\n Debug.error('ServerTransport: Closed', error);\n this._setState(TransportState.FAILED);\n } else {\n Debug.debug('ServerTransport: Closed');\n this._setState(TransportState.CLOSED);\n }\n }\n\n removeParticipant(participantId: ParticipantId) {\n this._captureReceiver?.close(participantId);\n }\n\n preventRestart() {\n this._reconnectionPrevented = true;\n }\n\n allowRestart() {\n this._reconnectionPrevented = false;\n }\n\n updateSettings(settings: ServerSettings) {\n if (compareServerSettings(settings, this._serverSettings)) {\n return;\n }\n this._serverSettings = settings;\n this._applyConsumerSettings();\n }\n\n setAnimojiTransport(receiver: AnimojiReceiver, sender: AnimojiSender) {\n if (!Params.vmoji) {\n return;\n }\n\n this._animojiReceiver = receiver;\n this._animojiSender = sender;\n\n if (this._participantIdRegistry) {\n receiver.setParticipantIdRegistry(this._participantIdRegistry);\n }\n\n if (this._animojiDataChannel) {\n receiver.setDataChannel(this._animojiDataChannel);\n sender.setDataChannel(this._animojiDataChannel);\n return;\n }\n }\n\n async onCameraResolutionChanged() {\n if (Params.simulcast && WebRTCUtils.isSimulcastSupportedByBrowser()) {\n await this._changeSimulcastInfo(true, false);\n }\n }\n\n private _createPerfStatsReporter() {\n this._perfStatReporter?.destroy();\n this._perfStatReporter = new PerfStatReporter(this, this._signaling);\n }\n\n private _closeConnection() {\n this._stopStatInterval();\n this._stopSettingsInterval();\n this._stopMonitorRtpShareInterval();\n this._removeAsrTrack();\n this._removeCaptureSender();\n this._removeCaptureReceiver();\n this._simulcastInfo = null;\n\n if (this._pc) {\n this._rtpReceiversByStreamId = {};\n this._disabledSenders.forEach((s) => s.track?.stop());\n this._disabledSenders.clear();\n this._pc.ontrack = null;\n this._pc.onconnectionstatechange = null;\n this._pc.onsignalingstatechange = null;\n this._participantIdRegistry = null;\n ServerTransport._closeDataChannel(this._producerNotification);\n ServerTransport._closeDataChannel(this._producerCommand);\n ServerTransport._closeDataChannel(this._producerScreen);\n ServerTransport._closeDataChannel(this._consumerScreen);\n ServerTransport._closeDataChannel(this._asr);\n ServerTransport._closeDataChannel(this._animojiDataChannel);\n this._pc.close();\n this._pc = null;\n this._producerOfferIsProcessing = false;\n this._producerNextOffer = null;\n }\n\n this._triggerEvent(TransportEvent.PEER_CONNECTION_CLOSED);\n }\n\n private static _closeDataChannel(dataChannel: RTCDataChannel | null) {\n if (dataChannel) {\n dataChannel.onopen = null;\n dataChannel.onmessage = null;\n dataChannel.onerror = null;\n dataChannel.close();\n }\n }\n\n private _createDataChannel(connection: RTCPeerConnection, label: DataChannelLabel, callback: (dataChannel: RTCDataChannel) => void) {\n Debug.debug(`[${label}] data channel opening`);\n const dataChannel = connection.createDataChannel(label, { ordered: true });\n dataChannel.onopen = () => {\n const state = dataChannel.readyState;\n if (state === 'open') {\n Debug.debug(`[${label}] data channel opened`);\n callback(dataChannel);\n } else {\n Debug.error(`[${label}] data channel open failed, state [${state}]`);\n }\n };\n dataChannel.onerror = (e) => {\n const error = (e as RTCErrorEvent).error;\n Debug.error(`[${label}] data channel error`, error?.errorDetail, error?.message);\n };\n }\n\n private _openConnection(reconnect = false) {\n Debug.debug('ServerTransport: Open single connection');\n\n try {\n this._pc = new RTCPeerConnection();\n } catch (error: any) {\n Debug.error('Failed to create RTCPeerConnection:', error);\n this.close(error);\n return;\n }\n\n this._pc.ontrack = this._onAddTrack.bind(this, this._pc);\n // В сафари при подключении собеседника к звонку меняются статусы - чтобы не дёргалось, делаем debounce\n this._pc.onconnectionstatechange = Utils.debounce((e: any) => {\n if (this._pc) {\n this._onConnectionStateChange(this._pc, e);\n }\n }, 500);\n this._pc.onsignalingstatechange = ServerTransport._onSignalingStateChange.bind(this, this._pc);\n\n this._participantIdRegistry = new ParticipantIdRegistry();\n this._signaling.setParticipantIdRegistry(this._participantIdRegistry);\n if (Params.producerNotificationDataChannel) {\n this._createDataChannel(this._pc, DataChannelLabel.producerNotification, (dataChannel: RTCDataChannel) => {\n this._producerNotification = dataChannel;\n this._producerNotification.binaryType = 'arraybuffer';\n this._signaling.setProducerNotificationDataChannel(dataChannel);\n });\n }\n\n if (Params.producerCommandDataChannel) {\n this._signaling.useCommandDataChannel(true);\n this._createDataChannel(this._pc, DataChannelLabel.producerCommand, (dataChannel: RTCDataChannel) => {\n this._producerCommand = dataChannel;\n this._signaling.setProducerCommandDataChannel(dataChannel);\n });\n }\n\n if (Params.producerScreenDataChannel) {\n this._createDataChannel(this._pc, DataChannelLabel.producerScreenShare, (dataChannel: RTCDataChannel) => {\n this._producerScreen = dataChannel;\n this._producerScreen.binaryType = 'arraybuffer';\n this._createCaptureReceiver();\n });\n }\n\n if (Params.asrDataChannel) {\n this._createDataChannel(this._pc, DataChannelLabel.asr, (dataChannel: RTCDataChannel) => {\n this._asr = dataChannel;\n this._asr.binaryType = 'arraybuffer';\n\n this._removeAsrTrack();\n this._asrTrack = new AsrReceiver(dataChannel, this._participantIdRegistry as ParticipantIdRegistry, (asr: AsrTranscription) => {\n this._onAsrTranscription(asr);\n });\n });\n }\n\n if (Params.vmoji) {\n this._createDataChannel(this._pc, DataChannelLabel.animoji, (dataChannel: RTCDataChannel) => {\n this._animojiDataChannel = dataChannel;\n this._animojiDataChannel.binaryType = 'arraybuffer';\n this._animojiReceiver?.setDataChannel(dataChannel);\n this._animojiReceiver?.setParticipantIdRegistry(this._participantIdRegistry as ParticipantIdRegistry);\n this._animojiSender?.setDataChannel(dataChannel);\n this._animojiSender?.setProtocolVersion(Params.vmojiOptions.protocolVersion || 1);\n });\n }\n\n this._newAudioShareTrack = this._mediaSource.getAudioShareTrack();\n\n try {\n this._mediaSource.addTrackToPeerConnection(this._pc, this._observer, false);\n this._prevConsumerSettings = {};\n this._prevConsumerFastSharingSettings = {};\n this._applyConsumerSettings();\n } catch (error: any) {\n Debug.error('ServerTransport: Unable to add media source tracks', error);\n Logger.log(StatLog.ERROR, 'addTrack-single');\n this.close(error);\n return;\n }\n\n if (Params.consumerScreenDataChannel) {\n this._createDataChannel(this._pc, DataChannelLabel.consumerScreenShare, (dataChannel: RTCDataChannel) => {\n this._consumerScreen = dataChannel;\n this._consumerScreen.binaryType = 'arraybuffer';\n\n const screenTrack = this._mediaSource.getScreenTrack();\n if (screenTrack && (!Params.consumerFastScreenShare || !this._mediaSource.getMediaSettings().isFastScreenSharingEnabled)) {\n this._createCaptureSender(screenTrack);\n }\n });\n }\n\n if (!reconnect) {\n this._allocateConsumer();\n }\n\n this._setState(TransportState.OPENED);\n\n this._startStatInterval();\n this._startSettingsInterval();\n this._startMonitorRtpShareInterval();\n }\n\n private _removeAsrTrack() {\n this._asrTrack?.destroy();\n this._asrTrack = null;\n }\n\n private _reconnect() {\n // Не пересоздаем соединение, если оно создано и не подключено\n if (this.getState() !== TransportState.OPENED) {\n this._setState(TransportState.RECONNECTING);\n this._closeConnection();\n this._openConnection(true);\n }\n }\n\n private _signalActiveParticipants(participants: ParticipantId[]) {\n this._triggerEvent(TransportEvent.SIGNALLED_ACTIVE_PARTICIPANTS, participants);\n }\n\n private _signalStalledParticipants(participants: ParticipantId[]) {\n this._triggerEvent(TransportEvent.SIGNALLED_STALLED_PARTICIPANTS, participants);\n }\n\n private _signalSpeakerChanged(speaker: ParticipantId) {\n this._triggerEvent(TransportEvent.SIGNALLED_SPEAKER_CHANGED, speaker);\n }\n\n private _signalNetworkStatus(statuses: Record<ParticipantId, number>) {\n this._triggerEvent(TransportEvent.NETWORK_STATUS, statuses);\n }\n\n private _updateSSRCMap(description: Required<RTCSessionDescriptionInit>) {\n if (description) {\n description.sdp.split('\\n').forEach((line) => {\n const ssrcPattern = `a=ssrc:([0-9]+) label:(audio|video)-((?:[ug]?[\\\\d]+)|(?:mix)|(?:${TrackId.PARTICIPANT_AGNOSTIC_TRACK_PREFIX}-[0-9]+))`;\n const result = new RegExp(ssrcPattern).exec(line);\n if (result) {\n this._ssrcMap[result[1]] = result[3];\n this._ssrcMapUpdated = true;\n }\n });\n }\n }\n\n private _createCaptureSender(track: MediaStreamTrack) {\n const mediaSettings = this._mediaSource.getMediaSettings();\n if (!track || !Params.consumerScreenDataChannel || !this._consumerScreen || !mediaSettings.isScreenSharingEnabled) {\n return;\n }\n if (this._captureSender) {\n this._removeCaptureSender();\n }\n this._captureSender = new ScreenCaptureSender(track, this._consumerScreen, this._signaling, mediaSettings.isFastScreenSharingEnabled);\n }\n\n private _removeCaptureSender() {\n this._captureSender?.destroy();\n this._captureSender = null;\n }\n\n private _createCaptureReceiver() {\n if (!Params.producerScreenDataChannel || !this._producerScreen) {\n return;\n }\n if (this._captureReceiver) {\n this._removeCaptureReceiver();\n }\n this._captureReceiver = new ScreenCaptureReceiver(\n this._producerScreen,\n this._participantIdRegistry as ParticipantIdRegistry,\n (streamId, stream) => {\n this._triggerEvent(TransportEvent.REMOTE_STREAM_SECOND, streamId, stream);\n },\n (streamId) => {\n this._triggerEvent(TransportEvent.REMOTE_STREAM_SECOND, streamId, null);\n },\n (stat) => {\n this._triggerEvent(TransportEvent.SCREEN_SHARING_STAT, stat);\n },\n );\n }\n\n private _removeCaptureReceiver() {\n this._captureReceiver?.destroy();\n this._captureReceiver = null;\n }\n\n private _applyConsumerSettings() {\n const videoSettings =\n this._mediaSource.getMediaSettings().isScreenSharingEnabled && !Params.consumerScreenDataChannel ? this._serverSettings.screenSharing : this._serverSettings.camera;\n\n if (videoSettings && this._pc) {\n const appliedSettings: any = [];\n this._pc.getSenders().forEach((s) => {\n if (!s.track || s.track.kind !== MediaTrackKind.video || s.track.contentHint === 'motion') {\n return;\n }\n\n const videoUploadEnabled = !this._disabledSenders.has(s);\n const videoUploadNeeded = videoSettings.maxDimension !== 0;\n\n if (videoUploadEnabled && !videoUploadNeeded) {\n Debug.log('Disabling video upload');\n this._disabledSenders.add(s);\n s.replaceTrack(WebRTCUtils.getBlackMediaTrack()).catch((error) => {\n Debug.error('Could not disable video upload', error);\n });\n return;\n }\n\n const sendVideoTrack = this._mediaSource.getSendVideoTrack();\n if (!videoUploadEnabled && videoUploadNeeded && sendVideoTrack) {\n Debug.log('Enabling video upload');\n this._disabledSenders.delete(s);\n\n const blackTrack = s.track;\n // Перед реплейсом нужно старый трек включить/выключить, иначе после замены не будет работать (в FF)\n blackTrack.enabled = sendVideoTrack.enabled;\n\n s.replaceTrack(sendVideoTrack)\n .then(() => blackTrack.stop())\n .catch((error) => {\n Debug.error('Could not enable video upload', error);\n });\n }\n\n Utils.applyVideoTrackSettings(videoSettings, s, sendVideoTrack ?? s.track, this._prevConsumerSettings, appliedSettings);\n });\n this._prevConsumerSettings = appliedSettings;\n }\n\n if (this._mediaSource.getMediaSettings().isFastScreenSharingEnabled && Params.consumerFastScreenShare) {\n const fastScreenSettings = this._serverSettings.fastScreenSharing;\n\n if (fastScreenSettings && this._pc) {\n const appliedSettings: any = [];\n this._pc.getSenders().forEach((s) => {\n if (!s.track || s.track.kind !== MediaTrackKind.video || s.track.contentHint !== 'motion') {\n return;\n }\n\n Utils.applyVideoTrackSettings(fastScreenSettings, s, s.track, this._prevConsumerFastSharingSettings, appliedSettings);\n });\n this._prevConsumerFastSharingSettings = appliedSettings;\n }\n }\n }\n\n private _onScreenSharingStatus(event: { track: MediaStreamTrack | null }) {\n if (event.track) {\n if (!Params.consumerFastScreenShare || !this._mediaSource.getMediaSettings().isFastScreenSharingEnabled) {\n this._createCaptureSender(event.track);\n }\n } else {\n this._removeCaptureSender();\n }\n }\n\n private _setState(state: TransportState) {\n if (this._state === state) {\n return;\n }\n\n this._state = state;\n this._triggerEvent(TransportEvent.STATE_CHANGED, state);\n }\n\n private _startStatInterval() {\n if (this._statInterval) {\n return;\n }\n\n const inner = () => {\n if (!this._pc) {\n this._stopStatInterval();\n return;\n }\n\n this._collectStat()\n .then((stat: StatItem) => {\n this._reportStats(stat);\n this._detectStaleTracks(stat);\n CodecStatsAggregator.reportUsage(stat);\n })\n .catch(() => {\n // Do nothing\n });\n\n this._statInterval = window.setTimeout(inner, Params.statisticsInterval);\n };\n\n this._statInterval = window.setTimeout(inner, Params.statisticsInterval);\n }\n\n private _stopStatInterval() {\n if (this._statInterval) {\n window.clearTimeout(this._statInterval);\n this._statInterval = null;\n }\n this._statBytes = {};\n }\n\n private _startSettingsInterval() {\n const INTERVAL = 2000;\n\n if (this._settingsInterval) {\n return;\n }\n\n const inner = () => {\n if (!this._pc) {\n this._stopSettingsInterval();\n return;\n }\n\n this._applyConsumerSettings();\n this._settingsInterval = window.setTimeout(inner, INTERVAL);\n };\n\n this._settingsInterval = window.setTimeout(inner, INTERVAL);\n }\n\n private _stopSettingsInterval() {\n if (this._settingsInterval) {\n window.clearTimeout(this._settingsInterval);\n this._settingsInterval = null;\n }\n }\n\n private async _collectStat(): Promise<StatItem> {\n if (!this._pc) {\n return Promise.reject();\n }\n\n if (this._ssrcMapUpdated) {\n this._lastStat = null;\n this._ssrcMapUpdated = false;\n this._createPerfStatsReporter();\n }\n\n const stat = await Statistics.collectStats(this._pc, this._lastStat, this._ssrcMap, true);\n this._lastStat = stat;\n return stat;\n }\n\n private _reportStats(stat: StatItem) {\n this._triggerEvent(TransportEvent.REMOTE_DATA_STATS, {\n inbound: {\n topology: TransportTopology.SERVER,\n transport: stat.transport,\n rtps: stat.rtps.filter((rtp) => rtp.type === 'inbound-rtp'),\n },\n outbound: {\n topology: TransportTopology.SERVER,\n transport: stat.transport,\n rtps: stat.rtps.filter((rtp) => rtp.type === 'outbound-rtp'),\n },\n remoteInbound: {\n topology: TransportTopology.SERVER,\n transport: stat.transport,\n rtps: stat.remoteRtps ?? [],\n },\n });\n }\n\n private _detectStaleTracks(stat: StatItem) {\n const audioMixRtp = stat.rtps.find((rtp) => rtp.type === 'inbound-rtp' && rtp.kind === 'audio' && this._ssrcMap[rtp.ssrc] === 'mix');\n if (!audioMixRtp) {\n return;\n }\n\n const statId = TrackId.AUDIO_MIX;\n const oldValue = this._statBytes[statId];\n let stalled = false;\n\n if (oldValue) {\n const diff = audioMixRtp.bytesReceived - oldValue.bytesReceived;\n // Бывает, что даже на разорванном соединении откуда-то приходят пакеты по 3 байта - не берем их в расчет\n // При реконнекте трек может поменяться и разница будет отрицательная - не учитываем\n if (diff >= 0 && diff <= 5) {\n stalled = true;\n }\n\n if (oldValue.stalled !== stalled) {\n this._triggerEvent(TransportEvent.AUDIO_MIX_STALL, stalled);\n }\n }\n\n this._statBytes[statId] = { bytesReceived: audioMixRtp.bytesReceived, stalled };\n }\n\n private _allocateConsumer() {\n if (!this._signaling.ready) {\n return;\n }\n\n const capabilities = {\n estimatedPerformanceIndex: PerfStatReporter.getEstimatedPerformanceIndex(),\n audioMix: true,\n consumerUpdate: true,\n producerNotificationDataChannelVersion: Params.producerNotificationDataChannel ? 8 : 0,\n producerCommandDataChannelVersion: Params.producerCommandDataChannel ? 3 : 0,\n consumerScreenDataChannelVersion: Params.consumerScreenDataChannel ? 1 : 0,\n producerScreenDataChannelVersion: Params.producerScreenDataChannel ? 1 : 0,\n asrDataChannelVersion: Params.asrDataChannel ? 1 : 0,\n animojiDataChannelVersion: Params.vmoji ? Params.vmojiOptions.protocolVersion : 1,\n animojiBackendRender: !Params.vmojiOptions.renderingOptions.useFullClientRendering,\n onDemandTracks: true,\n unifiedPlan: true,\n singleSession: true,\n videoTracksCount: Params.videoTracksCount,\n red: Params.serverAudioRed,\n audioShare: Params.audioShare,\n fastScreenShare: Params.fastScreenShare,\n videoSuspend: Params.videoSuspend,\n simulcast: Params.simulcast && WebRTCUtils.isSimulcastSupportedByBrowser(),\n consumerFastScreenShare: Params.consumerFastScreenShare,\n consumerFastScreenShareQualityOnDemand: Params.consumerFastScreenShareQualityOnDemand,\n };\n\n if (!Params.videoTracksCount && !this._observer) {\n // TODO: Позже нужно вообще запретить установку параметра в ноль и спилить этот ворнинг\n Debug.warn('Setting videoTracksCount to 0 is deprecated');\n }\n\n this._signaling.allocateConsumer(null, capabilities);\n }\n\n private async _processOffer(offer: Required<RTCSessionDescriptionInit>): Promise<void> {\n if (!this._pc) {\n throw new Error('Interrupt allocation');\n }\n const isSimulcastSupported = Params.simulcast && WebRTCUtils.isSimulcastSupportedByBrowser();\n let simulcast = isSimulcastSupported;\n\n try {\n await this._pc.setRemoteDescription(offer);\n } catch (error) {\n Debug.error('[single] unable to set remote offer', error);\n Logger.log(StatLog.ERROR, 'setRemoteDescription-single');\n throw error;\n }\n\n // setup video simulcast transceiver, if needed\n const simTransceiver = this._findFirstSimTransceiver();\n if (isSimulcastSupported) {\n if (simTransceiver) {\n Debug.log(`_processOffer: caps.simulcast=${Params.simulcast} mid=${simTransceiver.mid} dir=${simTransceiver.direction}`);\n const stream: MediaStream | null = this._mediaSource.getStream();\n const success = await this._setupSimulcastTransceiver(stream, simTransceiver);\n Debug.log('_processOffer: simulcastInfo', success);\n if (!success) {\n Debug.log(`_processOffer: simulcast transceiver not found in server offer mid=${simTransceiver.mid}, disable simulcast`);\n simulcast = false;\n }\n } else {\n Debug.log('_processOffer: simulcast transceiver not found in server offer, disable simulcast');\n simulcast = false;\n }\n }\n\n let answer: Required<RTCSessionDescriptionInit>;\n try {\n await this._handleTracks();\n Debug.debug('[single] create local answer');\n\n if (!this._pc) {\n throw new Error('Interrupt allocation');\n }\n\n answer = (await this._pc.createAnswer()) as Required<RTCSessionDescriptionInit>;\n } catch (error) {\n Debug.error('[single] unable to create answer', error);\n Logger.log(StatLog.ERROR, 'createAnswer-single');\n\n throw error;\n }\n\n try {\n if (!this._pc) {\n throw new Error('Interrupt allocation');\n }\n\n // На серверной топологии нет смысла ставить H264 на первое место\n answer.sdp = Utils.patchLocalSDP(\n answer.sdp as string,\n false,\n WebRTCUtils.isBrokenH264Decoder(),\n false,\n Params.h264spsPpsIdrInKeyframe,\n // Не форсим RED, т.к. сервер всегда отправляет offer, а в answer порядок кодеков будет такой же\n );\n\n Debug.debug('[single] set local answer', { answer });\n await this._pc.setLocalDescription(answer);\n } catch (error) {\n Debug.error('[single] unable to set local answer', error);\n Logger.log(StatLog.ERROR, 'setLocalDescription-single');\n\n throw error;\n }\n\n // patch simulcast answer by adding rid attributes\n if (simulcast && simTransceiver) {\n answer.sdp = Utils.patchSimulcastAnswerSdp(answer.sdp, simTransceiver, SIMULCAST_DEFAULT.WIDTH, SIMULCAST_DEFAULT.HEIGHT);\n // stop null transceivers, such trans appears in simulcast mode and creates duplicate sender\n for (const trans of this._pc.getTransceivers()) {\n if (trans.mid === null) {\n trans.stop();\n }\n }\n }\n\n try {\n Debug.debug('[single] transmit local answer', { answer });\n this._updateSSRCMap(offer);\n\n await this._signaling.acceptProducer(answer, Object.keys(this._ssrcMap));\n Debug.debug('[single] remote offer has been processed');\n } catch (error) {\n Debug.warn('[single] unable to send local answer', error);\n Logger.log(StatLog.ERROR, 'acceptProducer');\n // NB: Не выбрасываем ошибку, продолжаем выполнение\n }\n\n // send changeSimulcast to report actual size and layers, force encodings setup\n if (simulcast) {\n await this._changeSimulcastInfo(true, true);\n }\n }\n\n private _findFirstSimTransceiver() {\n if (!this._pc) {\n return null;\n }\n for (const trans of this._pc.getTransceivers()) {\n const kind = trans.sender?.track ? trans.sender.track?.kind : trans.receiver?.track?.kind;\n if (!trans.sender || kind !== MediaTrackKind.video) {\n continue;\n }\n const params = trans.sender.getParameters() as RTCRtpSendParameters;\n if (!params.encodings || params.encodings.length <= 1) {\n continue;\n }\n return trans;\n }\n return null;\n }\n\n private async _setupSimulcastTransceiver(stream: MediaStream | null, transceiver: RTCRtpTransceiver) {\n if (!transceiver?.sender || !stream) {\n return null;\n }\n transceiver.direction = 'sendonly';\n const track = stream.getVideoTracks()[0];\n await transceiver.sender.replaceTrack(track);\n transceiver.sender.setStreams(stream);\n const params = transceiver.sender.getParameters() as RTCRtpSendParameters;\n if (!params.encodings || params.encodings.length <= 1) {\n // no simulcast in server offer\n Debug.log(`_setup:sim: mid=${transceiver.mid} dir=${transceiver.direction}: wrong encodings:${JSON.stringify(params.encodings)}`);\n return null;\n }\n // setup encodings, always use 3 std layers, otherwise sdp answer will be wrong\n const simulcastInfo: SimulcastInfo = calculateSimulcastInfo(SIMULCAST_DEFAULT.WIDTH, SIMULCAST_DEFAULT.HEIGHT, this._serverSettings.camera?.bitrates?.generic);\n let i = 0;\n let downBy = 1;\n for (const encoding of params.encodings) {\n encoding.scalabilityMode = SIMULCAST_SCALABILITY_MODE;\n encoding.active = true;\n if (i >= simulcastInfo.streams.length) {\n // signal that this layer is not used\n encoding.maxBitrate = 0;\n } else {\n encoding.maxBitrate = simulcastInfo.streams[i].bitrate;\n }\n encoding.scaleResolutionDownBy = downBy;\n downBy = downBy * 2;\n i++;\n }\n await transceiver.sender.setParameters(params);\n const s = track.getSettings();\n Debug.log(`_setup:sim: mid=${transceiver.mid} dir=${transceiver.direction} track=${s.width}x${s.height} encodings=${JSON.stringify(params.encodings)}`);\n return true;\n }\n\n private async _acceptProducer(sdp: string): Promise<void> {\n if (this._producerOfferIsProcessing) {\n this._producerNextOffer = sdp;\n Debug.debug('[single] wait until other remote offer is processed');\n return;\n }\n this._producerOfferIsProcessing = true;\n\n const offer: Required<RTCSessionDescriptionInit> = {\n type: 'offer',\n sdp: Utils.patchRemoteSDP(sdp, WebRTCUtils.isOldDataChannelDescription(), false, false, false, WebRTCUtils.isBrokenVP9Encoder(), WebRTCUtils.isBrokenVP9Decoder()),\n };\n\n Debug.debug('[single] set remote offer', { offer });\n\n if (!this._pc) {\n throw new Error('Interrupt allocation');\n }\n\n try {\n await this._processOffer(offer);\n\n this._producerOfferIsProcessing = false;\n\n if (this._producerNextOffer) {\n Debug.debug('[single] there is other unprocessed remote offer, process it');\n\n const nextOffer = this._producerNextOffer;\n this._producerNextOffer = null;\n\n await this._acceptProducer(nextOffer);\n }\n } catch (e: any) {\n this.close(e);\n }\n }\n\n private async _replaceScreenShareTrack() {\n const screenShareTransceiver = this._pc?.getTransceivers().find((item) => item.mid?.endsWith('s') && item?.receiver?.track.kind === MediaTrackKind.video);\n if (!screenShareTransceiver || !screenShareTransceiver.sender) {\n Debug.warn('Cannot find screenshare transceiver');\n return;\n }\n\n try {\n screenShareTransceiver.direction = 'sendonly';\n await screenShareTransceiver.sender.replaceTrack(this._mediaSource.getScreenShareTrack());\n } catch (e) {\n Debug.error('ServerTransport: Unable to replace track', e);\n }\n }\n\n private async _handleTracks() {\n if (this._observer) {\n return;\n }\n await this._handleAudioShareTrack();\n await this._handleScreenShareTrack();\n }\n\n private async _handleAudioShareTrack() {\n if (!this._newAudioShareTrack) {\n return;\n }\n\n //'s' suffix is reserved for audio share - to identify transceiver after adding new m-line\n const transceiver = this._pc?.getTransceivers().find((item) => item.mid?.endsWith('s') && item?.receiver?.track.kind === MediaTrackKind.audio);\n if (!transceiver || !transceiver.sender) {\n Debug.warn('Cannot find audioshare transceiver');\n return;\n }\n\n if (transceiver.sender.track !== null) {\n Debug.warn('Unexpected track assigned to audioshare');\n }\n\n try {\n transceiver.direction = 'sendonly';\n await transceiver.sender.replaceTrack(this._newAudioShareTrack);\n this._newAudioShareTrack = null;\n } catch (e) {\n Debug.error('ServerTransport: Unable to replace track', e);\n Logger.log(StatLog.ERROR, 'replaceTrack-single');\n }\n }\n\n private async _handleScreenShareTrack() {\n const screenShareTrack = this._mediaSource.getScreenShareTrack();\n if (!screenShareTrack) {\n return;\n }\n\n await this._replaceScreenShareTrack();\n }\n\n private async _onSignalingNotification(message: SignalingMessage) {\n if (!this._isOpen) {\n return;\n }\n\n switch (message.notification) {\n case SignalingNotification.PRODUCER_UPDATED:\n await this._onProducerUpdated(message as SignalingMessage.ProducerUpdated);\n break;\n case SignalingNotification.REALLOC_CON:\n this._reconnect();\n break;\n case SignalingNotification.AUDIO_ACTIVITY:\n this._signalActiveParticipants(message.activeParticipants);\n break;\n case SignalingNotification.SPEAKER_CHANGED:\n this._signalSpeakerChanged(message.speaker);\n break;\n case SignalingNotification.STALLED_ACTIVITY:\n this._signalStalledParticipants(message.stalledParticipants);\n break;\n case SignalingNotification.NETWORK_STATUS:\n this._signalNetworkStatus(message.statuses);\n break;\n }\n }\n\n private _onAsrTranscription(asr: AsrTranscription) {\n this._triggerEvent(TransportEvent.ASR_TRANSCRIPTION, asr);\n }\n\n private async _onProducerUpdated(message: SignalingMessage.ProducerUpdated) {\n // Пересоздаем пирконнекшен, если на сервере изменилась сессия\n if (this._producerSessionId && this._producerSessionId !== message.sessionId) {\n this._reconnect();\n }\n // Режим для нагрузочных тестов - отламываем видео чтобы уменьшить нагрузку на декодер на клиенте\n if (Params.breakVideoPayloadTypes) {\n Debug.log('test mode enabled, video switched off');\n this._signaling.requestTestMode('breakVideoPayloadTypes', null);\n }\n this._producerSessionId = message.sessionId;\n await this._acceptProducer(message.description);\n }\n\n private _onAddTrack(_pc: RTCPeerConnection, event: any) {\n Debug.debug('[single] remote track (added)', { track: event.track });\n\n const stream: MediaStream = event.streams[0];\n if (stream) {\n if (!stream.onremovetrack) {\n stream.onremovetrack = (e) => {\n this._triggerEvent(TransportEvent.REMOTE_TRACK_REMOVED, stream.id, stream, e.track);\n };\n }\n // В сафари после перезахода собеседника в звонок в этом событии приходит стрим без треков\n const trackInStream = stream.getTracks().find((track) => track.id === event.track.id);\n if (!trackInStream) {\n stream.addTrack(event.track);\n }\n this._rtpReceiversByStreamId[stream.id] = event.receiver;\n this._triggerEvent(TransportEvent.REMOTE_TRACK_ADDED, stream.id, stream, event.track);\n } else {\n Debug.error('[single] unable to get media stream from track event');\n }\n }\n\n static _onSignalingStateChange(pc: RTCPeerConnection, event: any) {\n Debug.debug('[single] signaling state changed', { state: pc.signalingState }, event);\n }\n\n private _onConnectionStateChange(pc: RTCPeerConnection, event: any) {\n Debug.debug('[single] connection state changed', { state: pc.connectionState }, event);\n Logger.log(StatLog.ICE_CONNECTION_STATE, pc.connectionState);\n\n switch (pc.connectionState) {\n case 'failed':\n if (this._reconnectionPrevented) {\n this.close(new Error('Ice connection failed'));\n } else {\n Logger.logCustom(StatLog.RECONNECT, { param: 1 });\n // При single session не ждем realloc-con, а сразу пересоздаем peerconnection\n this._reconnect();\n }\n break;\n\n case 'connecting':\n const state = this.getState();\n if (state === TransportState.IDLE || state === TransportState.OPENED) {\n this._setState(TransportState.CONNECTING);\n } else if (pc.iceConnectionState === 'checking') {\n this._setState(TransportState.RECONNECTING);\n }\n break;\n\n case 'disconnected':\n if (this._reconnectionPrevented) {\n this.close(new Error('Ice connection disconnected'));\n } else {\n this._setState(TransportState.RECONNECTING);\n }\n break;\n\n case 'connected':\n this._setState(TransportState.CONNECTED);\n Utils.getPeerConnectionHostInfo(pc).then((data) => {\n if (data?.local) {\n Logger.log(StatLog.ICE_CONNECTION_TYPE, data.local.type);\n Debug.debug('Selected ICE candidates', data);\n }\n });\n Logger.logCustom(StatLog.RECONNECT, { param: 0 });\n break;\n }\n }\n\n private _onReplacedTrack(newTrack: MediaStreamTrack, sendTrack?: MediaStreamTrack) {\n if (this._pc) {\n Debug.debug(`_onReplacedTrack: newTrack=${newTrack}, sendTrack=${sendTrack}`);\n if (Params.consumerScreenDataChannel && sendTrack) {\n newTrack = sendTrack;\n }\n\n const replaceTrack = (sender: RTCRtpSender, track: MediaStreamTrack) => {\n sender.replaceTrack(track).catch((error) => {\n Debug.error('ServerTransport: Unable to replace track', error);\n Logger.log(StatLog.ERROR, 'replaceTrack-single');\n });\n };\n\n Debug.log(`_onReplacedTrack: newTrack=${newTrack.getSettings().width}x${newTrack.getSettings().height}`);\n if (Params.simulcast && WebRTCUtils.isSimulcastSupportedByBrowser() && newTrack.kind === MediaTrackKind.video) {\n const videoTransceiver = this._pc\n ?.getTransceivers()\n .find((t) => t.direction === 'sendonly' && t.sender?.track?.kind === MediaTrackKind.video && t.sender.track.contentHint === newTrack.contentHint);\n const sender = videoTransceiver?.sender;\n if (sender?.track) {\n replaceTrack(sender, newTrack);\n if (newTrack.getSettings().width && newTrack.getSettings().height) {\n // _applyConsumerSettings will update encodings anyway, so we dont need to updateBitrates here\n this._changeSimulcastInfo(false, false);\n }\n } else {\n Debug.warn('_onReplacedTrack: simulcast video transceiver not found');\n }\n } else {\n const sender = this._pc\n ?.getSenders()\n .find((item) => item.track && item.track.kind === newTrack.kind && !this._disabledSenders.has(item) && item.track.contentHint === newTrack.contentHint);\n if (sender?.track) {\n // Перед реплейсом нужно старый трек включить/выключить, иначе после замены не будет работать (в FF)\n // upd. 15.07.2024 проверил в FF - все работает без переключения старого трека, принял решение закомментировать, т. к. мешает работе аудио эффектов\n // sender.track.enabled = newTrack.enabled;\n replaceTrack(sender, newTrack);\n } else if (newTrack.kind === MediaTrackKind.audio && newTrack.contentHint === 'music') {\n this._newAudioShareTrack = newTrack;\n }\n }\n }\n this._applyConsumerSettings();\n }\n\n private async _onSourcesChanged({ kind }: { kind: MediaTrackKind }) {\n if (kind === MediaTrackKind.screen && Params.consumerFastScreenShare && this._mediaSource.getMediaSettings().isFastScreenSharingEnabled) {\n await this._replaceScreenShareTrack();\n }\n\n this._applyConsumerSettings();\n }\n\n getStreamWaitingTimeMs(streamId: string, targetRtpTimestamp: number): number {\n if (!this._pc) {\n Logger.log(StatLog.PAT_WAITING_TIME_ERROR, 'noConnection');\n Debug.error('Cannot get stream waiting time, peer connection is not initialized');\n return 0;\n }\n if (!RTCRtpReceiver.prototype.getSynchronizationSources) {\n Logger.log(StatLog.PAT_WAITING_TIME_ERROR, 'oldBrowser');\n Debug.error('Cannot get stream waiting time, RTCRtpReceiver.getSynchronizationSources is not supported');\n return 0;\n }\n const receiver = this._rtpReceiversByStreamId[streamId];\n if (!receiver) {\n Logger.log(StatLog.PAT_WAITING_TIME_ERROR, 'noReceiver');\n Debug.error(`Cannot get stream waiting time, cannot find RTP receiver by stream ID: ${streamId}`);\n return 0;\n }\n const synchronizationSources = receiver.getSynchronizationSources();\n if (!synchronizationSources || !synchronizationSources.length) {\n // happens when given receiver has not received anything yet, and also randomly in Firefox\n Debug.log(`Cannot get stream waiting time, ${streamId} receiver has no synchronization sources`);\n return 0;\n }\n const synchronizationSource = synchronizationSources[0];\n const rtpTimestamp = synchronizationSource.rtpTimestamp;\n if (!Number.isInteger(rtpTimestamp)) {\n Logger.log(StatLog.PAT_WAITING_TIME_ERROR, 'timestampNotInteger');\n Debug.error(`Cannot get stream waiting time, ${streamId} receiver's RTP timestamp is not an integer: ${rtpTimestamp}`);\n return 0;\n }\n\n const rtpTimestampDiff = (targetRtpTimestamp - rtpTimestamp) & RTP_MAX_TIMESTAMP;\n const wallclockDiff = Math.ceil(rtpTimestampDiff / RTP_VIDEO_CLOCKRATE);\n return Math.min(100, Math.max(0, wallclockDiff));\n }\n\n private async _changeSimulcastInfo(setupEncodings: boolean, forceCommand: boolean) {\n // change simulcast layers bitrate, according to a new camera resolution\n const isVideoEnabled = this._mediaSource.getMediaSettings().isVideoEnabled;\n const transceiver = this._findFirstSimTransceiver();\n if (!Params.simulcast || !WebRTCUtils.isSimulcastSupportedByBrowser() || !isVideoEnabled || !transceiver || !transceiver.sender) {\n return;\n }\n // current camera stream\n const stream: MediaStream | null = this._mediaSource.getStream();\n if (!stream) {\n return;\n }\n const track = stream.getVideoTracks()[0];\n const width = track.getSettings().width;\n const height = track.getSettings().height;\n\n const simulcastInfo = calculateSimulcastInfo(width, height, this._serverSettings.camera?.bitrates?.generic);\n const isSimulcastChanged = forceCommand || !isEqualSimulcastInfo(this._simulcastInfo, simulcastInfo);\n if (!simulcastInfo.streams.length || !isSimulcastChanged) {\n return;\n }\n const senderParams = transceiver.sender.getParameters() as RTCRtpSendParameters;\n if (!senderParams.encodings) {\n // @ts-ignore\n senderParams.encodings = [{}]; // FF workaround\n }\n if (senderParams.encodings.length <= 1) {\n // no simulcast\n return;\n }\n\n Debug.log(`_changeSimulcastInfo: ${width}x${height} command: ${JSON.stringify(simulcastInfo)} `);\n if (setupEncodings) {\n // setup encodings bitrate\n // loop layers from highest to lowest\n let i = 0;\n for (const encoding of senderParams.encodings) {\n encoding.scaleResolutionDownBy = findScaleResolutionDownBy(encoding.rid);\n encoding.scalabilityMode = SIMULCAST_SCALABILITY_MODE;\n if (i >= simulcastInfo.streams.length) {\n encoding.maxBitrate = 0;\n encoding.active = false;\n } else {\n encoding.active = true;\n encoding.maxBitrate = simulcastInfo.streams[i].bitrate;\n }\n i++;\n }\n await transceiver.sender.setParameters?.(senderParams).catch((e) => {\n Debug.error('Failed to set sender parameters', senderParams, e);\n });\n Debug.log(`_changeSimulcastInfo: actual encodings: ${JSON.stringify(senderParams.encodings)} `);\n }\n\n // send command\n this._simulcastInfo = simulcastInfo;\n // send data-channel command\n if (simulcastInfo.streams) {\n const info: ChangeSimulcast = { mediaSource: MediaSourceType.CAMERA, simulcastInfo };\n await this._signaling.changeSimulcast(info);\n }\n }\n\n private async _monitorRtpShare() {\n const networkRating = LocalNetworkRating.getInstance().value;\n\n if (!this._mediaSource.getMediaSettings().isFastScreenSharingEnabled || !Params.consumerFastScreenShare || networkRating < 0.6) {\n return;\n }\n\n const sender = this._pc?.getSenders().find((sender) => sender.track?.kind === MediaTrackKind.video && sender.track?.contentHint === 'motion');\n\n if (!sender) {\n return;\n }\n\n const senderStats = await sender.getStats();\n\n senderStats.forEach((stat) => {\n if (\n stat.type === 'outbound-rtp' &&\n this._serverSettings.fastScreenSharing &&\n stat.frameWidth < this._serverSettings.fastScreenSharing.maxDimension &&\n stat.frameWidth < window.screen.width\n ) {\n const senderParams = sender.getParameters();\n senderParams.degradationPreference = 'maintain-resolution';\n sender.setParameters(senderParams);\n Debug.log(\n `\n degradationPreference updated for fast share RTP Sender \n Actual senderStats: ${JSON.stringify(stat)} \n serverSettings: ${JSON.stringify(this._serverSettings.fastScreenSharing)}\n `,\n );\n }\n });\n }\n\n private _startMonitorRtpShareInterval() {\n const INTERVAL = 5000;\n\n if (this._monitorRtpShareInterval) {\n return;\n }\n\n const inner = () => {\n if (!this._pc) {\n this._stopMonitorRtpShareInterval();\n return;\n }\n\n this._monitorRtpShare();\n this._monitorRtpShareInterval = window.setTimeout(inner, INTERVAL);\n };\n\n this._monitorRtpShareInterval = window.setTimeout(inner, INTERVAL);\n }\n\n private _stopMonitorRtpShareInterval() {\n if (this._monitorRtpShareInterval) {\n window.clearTimeout(this._monitorRtpShareInterval);\n this._monitorRtpShareInterval = null;\n }\n }\n}\n", "import type { AnimojiError, AnimojiSvgData, RGBTuple } from '@vkontakte/calls-vmoji';\nimport { AnimojiReceiver, AnimojiSender } from '@vkontakte/calls-vmoji';\nimport BaseSignaling from '../../abstract/BaseSignaling';\nimport SignalingEvent from '../../enums/SignalingEvent';\nimport SignalingNotification from '../../enums/SignalingNotification';\nimport StatLog from '../../enums/StatLog';\nimport Debug from '../../static/Debug';\nimport Params from '../../static/Params';\nimport Utils from '../../static/Utils';\nimport { AsrTranscription } from '../../types/Asr';\nimport { ParticipantId } from '../../types/Participant';\nimport ServerSettings from '../../types/ServerSettings';\nimport SignalingMessage from '../../types/SignalingMessage';\nimport EventEmitter from '../EventEmitter';\nimport Logger from '../Logger';\nimport { MediaSource, MediaSourceEvent } from '../MediaSource';\nimport { StatResult } from '../../types/Statistics';\nimport DirectTransport from './DirectTransport';\nimport ServerTransport from './ServerTransport';\n\nexport const enum TransportEvent {\n REMOTE_TRACK_ADDED = 'REMOTE_TRACK_ADDED',\n REMOTE_TRACK_REMOVED = 'REMOTE_TRACK_REMOVED',\n REMOTE_STREAM_SECOND = 'REMOTE_STREAM_SECOND',\n AUDIO_MIX_STALL = 'AUDIO_MIX_STALL',\n REMOTE_DATA_STATS = 'REMOTE_DATA_STATS',\n STATE_CHANGED = 'STATE_CHANGED',\n LOCAL_STATE_CHANGED = 'LOCAL_STATE_CHANGED',\n SIGNALLED_ACTIVE_PARTICIPANTS = 'SIGNALLED_ACTIVE_PARTICIPANTS',\n SIGNALLED_SPEAKER_CHANGED = 'SIGNALLED_SPEAKER_CHANGED',\n SIGNALLED_STALLED_PARTICIPANTS = 'SIGNALLED_STALLED_PARTICIPANTS',\n TOPOLOGY_CHANGED = 'TOPOLOGY_CHANGED',\n NETWORK_STATUS = 'NETWORK_STATUS',\n PEER_CONNECTION_CLOSED = 'PEER_CONNECTION_CLOSED',\n ASR_TRANSCRIPTION = 'ASR_TRANSCRIPTION',\n ANIMOJI_STREAM = 'ANIMOJI_STREAM',\n ANIMOJI_ERROR = 'ANIMOJI_ERROR',\n SCREEN_SHARING_STAT = 'SCREEN_SHARING_STAT',\n}\n\nexport const enum TransportState {\n IDLE = 'IDLE',\n OPENED = 'OPENED',\n CONNECTING = 'CONNECTING',\n RECONNECTING = 'RECONNECTING',\n CONNECTED = 'CONNECTED',\n CLOSED = 'CLOSED',\n FAILED = 'FAILED',\n}\n\nexport const enum TransportTopology {\n DIRECT = 'DIRECT',\n SERVER = 'SERVER',\n}\n\nexport class Transport extends EventEmitter {\n private readonly _signaling: BaseSignaling;\n private readonly _mediaSource: MediaSource;\n private _topology: TransportTopology;\n\n // IDs of participants which we have allocated and opened connection with\n private _allocated: ParticipantId[] = [];\n private _opened: ParticipantId[] = [];\n\n private _directTransport: DirectTransport | null = null; // Больше не поддерживаем p2p звонок больше чем на 2 участников\n private _serverTransport: ServerTransport | null = null;\n\n private _serverSettings: ServerSettings;\n\n private _dtListeners: { dispose: Function }[] = []; // direct\n private _stListeners: { dispose: Function }[] = []; // server\n\n private _states: Record<ParticipantId, TransportState> = {};\n private _localState: TransportState = TransportState.IDLE;\n\n private _animojiReceiver: AnimojiReceiver | null = null;\n private _animojiSender: AnimojiSender | null = null;\n\n constructor(topology: TransportTopology, signaling: BaseSignaling, mediaSource: MediaSource, serverSettings: ServerSettings) {\n super();\n\n this._signaling = signaling;\n this._mediaSource = mediaSource;\n this._topology = topology;\n this._serverSettings = serverSettings;\n\n this.subscribe(this._signaling, SignalingEvent.NOTIFICATION, this._onSignalingNotification.bind(this));\n this.subscribe(this._mediaSource, MediaSourceEvent.ANIMOJI_STATUS, this._onAnimojiStatus.bind(this));\n this.subscribe(this._mediaSource, MediaSourceEvent.SOURCE_CHANGED, this._onSourceChanged.bind(this));\n\n this._createAnimojiTransport();\n\n // Создаем серверный транспорт сразу, чтобы иметь возможность записывать звонок с одним участником\n if (topology === TransportTopology.SERVER) {\n this._serverTransport = this._createServerTransport();\n }\n }\n\n updateSettings(settings: ServerSettings) {\n Debug.log('Update transport settings', settings);\n\n this._serverSettings = settings;\n if (this._directTransport) {\n this._directTransport.updateSettings(settings);\n }\n if (this._serverTransport) {\n this._serverTransport.updateSettings(settings);\n }\n }\n\n updateStatisticsInterval() {\n if (this._directTransport) {\n this._directTransport.updateStatisticsInterval();\n }\n if (this._serverTransport) {\n this._serverTransport.updateStatisticsInterval();\n }\n }\n\n allocate(participantId: ParticipantId, isMaster = false) {\n Debug.log(`Trying allocate participant [${participantId}]`);\n\n if (this._allocated.indexOf(participantId) !== -1) {\n Debug.warn(`The participant [${participantId}] has already had allocated transport`);\n return;\n }\n\n this._allocated.push(participantId);\n\n if (this._topology === TransportTopology.DIRECT && !this._directTransport) {\n this._directTransport = this._createDirectTransport(participantId, isMaster);\n }\n\n if (this._topology === TransportTopology.SERVER && !this._serverTransport) {\n this._serverTransport = this._createServerTransport();\n }\n }\n\n open(participantIds: ParticipantId[], peerId: string | null = null, observer = false, force = false) {\n Debug.log('Trying open participant', { participantIds });\n\n let needOpen = force;\n for (const participantId of participantIds) {\n if (this._opened.indexOf(participantId) !== -1) {\n Debug.warn(`The participant [${participantId}] has already had opened transport`);\n continue;\n }\n\n if (this._allocated.indexOf(participantId) === -1) {\n Debug.warn(`The participant [${participantId}] has no allocated transport`);\n continue;\n }\n\n this._opened.push(participantId);\n needOpen = true;\n }\n\n if (!needOpen) {\n return;\n }\n\n if (this._topology === TransportTopology.DIRECT && this._directTransport) {\n this._directTransport.open(peerId); // TODO: await?\n }\n\n if (this._topology === TransportTopology.SERVER && this._serverTransport) {\n this._serverTransport.open(observer);\n // Server transport notify about its state only once,\n // so we need to set participants states manually\n this._setStates(participantIds, this._serverTransport.getState());\n this._setLocalState(this._serverTransport.getState());\n }\n\n Debug.debug('The transport has been opened', participantIds);\n }\n\n close(participantId: ParticipantId) {\n const allocatedIndex = this._allocated.indexOf(participantId);\n const openedIndex = this._opened.indexOf(participantId);\n\n if (allocatedIndex < 0) {\n Debug.warn(`The participant [${participantId}] transport has already deallocated`);\n }\n\n if (this._topology === TransportTopology.DIRECT && this._directTransport && openedIndex >= 0) {\n // Освобождаем direct transport только если он открыт\n // Нужно для кейса, когда в п2п звонок пригласили третьего участника, он еще не взял трубку и его удалили\n this._releaseDirectTransport();\n }\n\n if (this._topology === TransportTopology.SERVER) {\n this._serverTransport?.removeParticipant(participantId);\n this._setStates([participantId], TransportState.CLOSED);\n }\n\n if (openedIndex >= 0) {\n this._opened.splice(openedIndex, 1);\n }\n\n if (allocatedIndex >= 0) {\n this._allocated.splice(allocatedIndex, 1);\n }\n\n delete this._states[participantId];\n }\n\n destroy() {\n this.unsubscribe();\n\n for (const listener of this._dtListeners) {\n listener.dispose();\n }\n\n for (const listener of this._stListeners) {\n listener.dispose();\n }\n\n this._removeAnimojiTransport();\n Params.audioEffects?.destroy();\n\n this._directTransport?.close();\n this._directTransport = null;\n\n this._serverTransport?.close();\n this._serverTransport = null;\n\n this._allocated = [];\n this._opened = [];\n }\n\n getTopology() {\n return this._topology;\n }\n\n isAllocated(participantId: ParticipantId) {\n return this._allocated.indexOf(participantId) >= 0;\n }\n\n allocated() {\n return this._allocated.slice();\n }\n\n opened() {\n return this._opened.slice();\n }\n\n getState() {\n return this._topology === TransportTopology.SERVER ? this._serverTransport?.getState() : this._directTransport?.getState();\n }\n\n getStates() {\n return this._states;\n }\n\n setAnimojiSvg(participantId: ParticipantId, svgData: AnimojiSvgData) {\n if (Params.vmoji && svgData.isMe) {\n // Сохраняем для будущей генерации превью вимоджи\n Params.vmoji.AnimojiPreviewGenerator?.setSvgData(svgData);\n }\n\n // Исключаем вероятность попадания detached ArrayBuffer\n if (!(svgData.svg instanceof ArrayBuffer) || svgData.svg.byteLength !== 0) {\n this._animojiReceiver?.setParticipantSvg(participantId, svgData);\n }\n }\n\n setAnimojiFill(fill: RGBTuple | string) {\n this._animojiSender?.setFill(fill);\n }\n\n async onCameraResolutionChanged() {\n if (this._topology === TransportTopology.SERVER && this._serverTransport) {\n await this._serverTransport.onCameraResolutionChanged();\n }\n }\n\n private _setStates(participantIds: ParticipantId[], state: TransportState) {\n const changedParticipantIds = participantIds.filter((participantId) => {\n if (this._states[participantId] !== state) {\n this._states[participantId] = state;\n return true;\n }\n return false;\n });\n\n if (changedParticipantIds.length) {\n this._triggerEvent(TransportEvent.STATE_CHANGED, changedParticipantIds, state);\n }\n }\n\n private _setLocalState(state: TransportState) {\n if (this._localState === state) {\n return;\n }\n\n this._localState = state;\n this._triggerEvent(TransportEvent.LOCAL_STATE_CHANGED, state);\n }\n\n private _onSignalingNotification(message: SignalingMessage) {\n if (message.notification === SignalingNotification.TOPOLOGY_CHANGED) {\n return this._onTopologyChanged(message as SignalingMessage.TopologyChanged);\n }\n }\n\n private _onTopologyChanged(message: SignalingMessage.TopologyChanged) {\n if (message.topology === this._topology) {\n return;\n }\n\n Debug.log(`Topology changed ${this._topology} -> ${message.topology}`);\n Logger.log(StatLog.TOPOLOGY_CHANGE_REQUESTED, message.topology);\n\n this._topology = message.topology;\n\n if (this._topology === TransportTopology.SERVER) {\n if (this._serverTransport) {\n this._serverTransport.allowRestart();\n } else {\n this._serverTransport = this._createServerTransport();\n if (this._opened.length > 0) {\n this._directTransport?.preventRestart();\n this._serverTransport.open();\n }\n }\n }\n\n if (this._topology === TransportTopology.DIRECT) {\n const offerTo = message.offerTo || [];\n const offerToTypes = message.offerToTypes || [];\n const offerToDeviceIdxs = message.offerToDeviceIdxs || [];\n const offerToComposedId = offerTo.length && offerToTypes.length ? Utils.composeParticipantId(offerTo[0], offerToTypes[0], offerToDeviceIdxs[0]) : null;\n\n if (this._serverTransport) {\n this._serverTransport.preventRestart();\n }\n\n if (!this._allocated || this._allocated.length === 0) {\n Debug.error('Topology changed to DIRECT, but the list of allocated participants is empty');\n return;\n }\n\n if (this._allocated.length > 1) {\n Debug.warn('Topology changed to DIRECT, but the allocated participants count more then one');\n }\n\n const participantId = this._allocated[0];\n\n if (this._directTransport) {\n this._directTransport.allowRestart();\n } else {\n const isMaster = offerToComposedId === participantId;\n this._directTransport = this._createDirectTransport(participantId, isMaster);\n }\n\n if (this._opened.indexOf(participantId) >= 0) {\n this._directTransport.open();\n }\n }\n\n this._triggerEvent(TransportEvent.TOPOLOGY_CHANGED, this._topology);\n }\n\n private _createDirectTransport(participantId: ParticipantId, isMaster = false): DirectTransport {\n const transport = new DirectTransport(participantId, isMaster, this._signaling, this._mediaSource, this._serverSettings);\n // this._setLocalNoiseSuppression(true);\n\n if (this._dtListeners.length > 0) {\n Debug.warn(`The list of direct listeners for the participant [${participantId}] is not empty`);\n }\n\n this._dtListeners = [];\n this._dtListeners.push(\n transport.addEventListener(TransportEvent.REMOTE_TRACK_ADDED, this._onRemoteTrackAdded.bind(this, participantId)),\n transport.addEventListener(TransportEvent.REMOTE_TRACK_REMOVED, this._onRemoteTrackRemoved.bind(this, participantId)),\n transport.addEventListener(TransportEvent.REMOTE_DATA_STATS, this._onRemoteDataStats.bind(this)),\n transport.addEventListener(TransportEvent.STATE_CHANGED, this._onDirectTransportChanged.bind(this)),\n transport.addEventListener(TransportEvent.NETWORK_STATUS, this._onTransportNetworkStatus.bind(this)),\n transport.addEventListener(TransportEvent.PEER_CONNECTION_CLOSED, this._onPeerConnectionClosed.bind(this, TransportTopology.DIRECT)),\n );\n\n if (this._animojiReceiver && this._animojiSender) {\n transport.setAnimojiTransport(this._animojiReceiver, this._animojiSender);\n }\n\n return transport;\n }\n\n private _createServerTransport() {\n const transport = new ServerTransport(this._signaling, this._mediaSource, this._serverSettings);\n // FYI: Пока оставляем встроенный шумодав включенным даже для серверного звонка, т.к. решили, что он не мешает серверному шумодаву\n // this._setLocalNoiseSuppression(false);\n\n if (this._stListeners.length > 0) {\n Debug.warn('The list of server transport listeners is not empty');\n }\n\n this._stListeners = [];\n this._stListeners.push(\n transport.addEventListener(TransportEvent.REMOTE_TRACK_ADDED, this._onRemoteTrackAdded.bind(this)),\n transport.addEventListener(TransportEvent.REMOTE_TRACK_REMOVED, this._onRemoteTrackRemoved.bind(this)),\n transport.addEventListener(TransportEvent.AUDIO_MIX_STALL, this._onServerAudioMixStall.bind(this)),\n transport.addEventListener(TransportEvent.REMOTE_DATA_STATS, this._onRemoteDataStats.bind(this)),\n transport.addEventListener(TransportEvent.STATE_CHANGED, this._onServerTransportChanged.bind(this)),\n transport.addEventListener(TransportEvent.SIGNALLED_ACTIVE_PARTICIPANTS, this._onTransportActiveParticipants.bind(this)),\n transport.addEventListener(TransportEvent.SIGNALLED_SPEAKER_CHANGED, this._onTransportSpeakerChanged.bind(this)),\n transport.addEventListener(TransportEvent.SIGNALLED_STALLED_PARTICIPANTS, this._onTransportStalledParticipants.bind(this)),\n transport.addEventListener(TransportEvent.NETWORK_STATUS, this._onTransportNetworkStatus.bind(this)),\n transport.addEventListener(TransportEvent.REMOTE_STREAM_SECOND, this._onRemoteStreamSecond.bind(this)),\n transport.addEventListener(TransportEvent.PEER_CONNECTION_CLOSED, this._onPeerConnectionClosed.bind(this, TransportTopology.SERVER)),\n transport.addEventListener(TransportEvent.ASR_TRANSCRIPTION, this._onAsrTranscription.bind(this)),\n );\n\n if (this._animojiReceiver && this._animojiSender) {\n transport.setAnimojiTransport(this._animojiReceiver, this._animojiSender);\n }\n\n return transport;\n }\n\n private _releaseDirectTransport() {\n this._directTransport?.close();\n this._directTransport = null;\n\n for (const listener of this._dtListeners) {\n listener.dispose();\n }\n this._dtListeners = [];\n }\n\n private _releaseServerTransport() {\n this._serverTransport?.close();\n this._serverTransport = null;\n\n for (const listener of this._stListeners) {\n listener.dispose();\n }\n this._stListeners = [];\n }\n\n private _setLocalNoiseSuppression(enabled: boolean) {\n if (Params.noiseSuppression !== enabled) {\n Params.noiseSuppression = enabled;\n this._mediaSource?.updateNoiseSuppression();\n }\n }\n\n private _onDirectTransportChanged(state: TransportState) {\n const participantId = this._directTransport?.participantId as ParticipantId;\n\n if (state === TransportState.CONNECTED) {\n if (this._topology === TransportTopology.DIRECT) {\n // Switched from SERVER to DIRECT\n this._releaseServerTransport();\n }\n }\n\n if (state === TransportState.CLOSED || state === TransportState.FAILED) {\n this._releaseDirectTransport();\n\n if (this._topology === TransportTopology.DIRECT) {\n // Participant has left the conversation\n\n const openedIndex = this._opened.indexOf(participantId);\n if (openedIndex >= 0) {\n this._opened.splice(openedIndex, 1);\n }\n\n const allocatedIndex = this._allocated.indexOf(participantId);\n if (allocatedIndex >= 0) {\n this._allocated.splice(allocatedIndex, 1);\n }\n }\n }\n\n if (this._topology === TransportTopology.DIRECT && participantId) {\n this._setStates([participantId], state);\n this._setLocalState(state);\n }\n }\n\n private _onServerTransportChanged(state: TransportState) {\n const participantIds = this._opened.slice();\n\n if (state === TransportState.CONNECTED) {\n if (this._topology === TransportTopology.SERVER) {\n // Switched from DIRECT to SERVER\n this._releaseDirectTransport();\n }\n }\n\n if (state === TransportState.CLOSED || state === TransportState.FAILED) {\n this._releaseServerTransport();\n\n if (this._topology === TransportTopology.SERVER) {\n // All participant have left the conversation\n this._allocated = [];\n this._opened = [];\n }\n }\n\n if (this._topology === TransportTopology.SERVER) {\n this._setStates(participantIds, state);\n this._setLocalState(state);\n }\n }\n\n private _onTransportActiveParticipants(participantIds: ParticipantId[]) {\n if (this._topology === TransportTopology.SERVER) {\n this._triggerEvent(TransportEvent.SIGNALLED_ACTIVE_PARTICIPANTS, participantIds);\n }\n }\n\n private _onTransportStalledParticipants(participantIds: ParticipantId[]) {\n if (this._topology === TransportTopology.SERVER) {\n this._triggerEvent(TransportEvent.SIGNALLED_STALLED_PARTICIPANTS, participantIds);\n }\n }\n\n private _onTransportSpeakerChanged(participantId: ParticipantId) {\n if (this._topology === TransportTopology.SERVER) {\n this._triggerEvent(TransportEvent.SIGNALLED_SPEAKER_CHANGED, participantId);\n }\n }\n\n private _onTransportNetworkStatus(statuses: Record<ParticipantId, number>) {\n this._triggerEvent(TransportEvent.NETWORK_STATUS, statuses);\n }\n\n private _onRemoteStreamSecond(participantId: ParticipantId, stream: MediaStream | null) {\n this._triggerEvent(TransportEvent.REMOTE_STREAM_SECOND, participantId, stream);\n }\n\n private _onPeerConnectionClosed(topology: TransportTopology) {\n this._triggerEvent(TransportEvent.PEER_CONNECTION_CLOSED, topology);\n }\n\n private _onServerAudioMixStall(stalled: boolean) {\n if (this._topology === TransportTopology.SERVER) {\n this._triggerEvent(TransportEvent.AUDIO_MIX_STALL, stalled);\n }\n }\n\n private _onRemoteDataStats(stats: StatResult) {\n this._triggerEvent(TransportEvent.REMOTE_DATA_STATS, stats);\n }\n\n private _onRemoteTrackAdded(participantId: ParticipantId, stream: MediaStream, track: MediaStreamTrack) {\n this._triggerEvent(TransportEvent.REMOTE_TRACK_ADDED, participantId, stream, track);\n }\n\n private _onRemoteTrackRemoved(participantId: ParticipantId, stream: MediaStream, track: MediaStreamTrack) {\n this._triggerEvent(TransportEvent.REMOTE_TRACK_REMOVED, participantId, stream, track);\n }\n\n private _onAsrTranscription(asr: AsrTranscription) {\n this._triggerEvent(TransportEvent.ASR_TRANSCRIPTION, asr);\n }\n\n private _onSourceChanged() {\n const stream = this._mediaSource.getStream();\n if (stream) {\n // MediaStreamSourceNode не обновляется автоматически при обновлении треков в стриме,\n // поэтому при каждом обновлении стрима мы должны пересоздавать MediaStreamSourceNode\n this._animojiSender?.setStream(stream);\n }\n }\n\n private _onAnimojiStream(participantId: ParticipantId, stream: MediaStream | null) {\n this._triggerEvent(TransportEvent.ANIMOJI_STREAM, participantId, stream);\n }\n\n /** Обработчик, досылающий MediaSourceEvent.SOURCE_CHANGED событие до аллокации транспортов */\n private _onAnimojiStatus(enabled: boolean) {\n if (enabled) {\n this._animojiSender?.resume();\n } else {\n this._animojiSender?.pause();\n }\n this._mediaSource.onAnimojiSender(enabled);\n }\n\n private _createAnimojiTransport() {\n if (!Params.vmoji) {\n return;\n }\n\n this._animojiReceiver = new Params.vmoji.AnimojiReceiver(\n (streamId: ParticipantId, stream: MediaStream) => this._onAnimojiStream(streamId, stream),\n (streamId: ParticipantId) => this._onAnimojiStream(streamId, null),\n (error: AnimojiError) => {\n this._triggerEvent(TransportEvent.ANIMOJI_ERROR, error);\n },\n Params.vmojiOptions.renderingOptions,\n );\n\n const localStream = this._mediaSource.getStream();\n this._animojiSender = new Params.vmoji.AnimojiSender(localStream, this._signaling.getPeerId(), Params.vmojiOptions.protocolVersion, {\n requested: this._mediaSource.isAnimojiRequested,\n useAI: Params.vmojiOptions.renderingOptions.useAI,\n });\n this._animojiSender.onLocalData = (data: ArrayBuffer) => this._animojiReceiver?.receive(data);\n }\n\n private _removeAnimojiTransport() {\n this._animojiSender?.destroy();\n this._animojiSender = null;\n this._animojiReceiver?.destroy();\n this._animojiReceiver = null;\n }\n\n getStreamWaitingTimeMs(streamId: string, targetRtpTimestamp: number): number {\n if (this._topology !== TransportTopology.SERVER) {\n Logger.log(StatLog.PAT_WAITING_TIME_ERROR, 'wrongTopology');\n Debug.error(`Cannot get stream waiting time, incorrect topology: ${this._topology}`);\n return 0;\n }\n if (!this._serverTransport) {\n Logger.log(StatLog.PAT_WAITING_TIME_ERROR, 'noTransport');\n Debug.error('Cannot get stream waiting time, server transport is not initialized');\n return 0;\n }\n return this._serverTransport.getStreamWaitingTimeMs(streamId, targetRtpTimestamp);\n }\n}\n", "import { SignalingTransportType } from '../../enums/SignalingTransportStat';\nimport Stat from '../../enums/Stat';\nimport { StatTracker } from '../../utils/StatTracker';\nimport Logger from '../Logger';\nimport { TransportTopology } from '../transport/Transport';\n\nexport class StatPings {\n private static _instance?: StatPings;\n\n static create() {\n if (!StatPings._instance) {\n StatPings._instance = new StatPings();\n }\n }\n\n /**\n * Вызывать при входящем ping в сигналингу.\n * Будет произведен расчет времени между пингами.\n */\n static mark(transport: SignalingTransportType) {\n if (!StatPings._instance) {\n return;\n }\n\n const now = Date.now();\n\n // Интервал между приходами\n const prev = StatPings._instance.lastSeen[transport];\n if (typeof prev === 'number') {\n const delta = now - prev;\n if (delta >= 0) StatPings._instance.trackerByTransport[transport].add(delta);\n }\n\n StatPings._instance.lastSeen[transport] = now;\n }\n\n /** Отправляем данные в стату */\n static logMetrics(topology?: TransportTopology) {\n if (!StatPings._instance) {\n return;\n }\n\n [SignalingTransportType.WEBSOCKET, SignalingTransportType.WEBTRANSPORT].forEach((t) => {\n if (!StatPings._instance!.trackerByTransport[t].hasData) {\n return;\n }\n\n const snapshot = StatPings._instance!.trackerByTransport[t].snapshot();\n\n Logger.logClientStats({\n call_topology: topology === TransportTopology.DIRECT ? 'D' : 'S',\n\n name: Stat.SIGNALING_PING_SUMMARY,\n min_value: snapshot.min,\n max_value: snapshot.max,\n avg_value: snapshot.avg,\n median_value: snapshot.median,\n p95_value: snapshot.p95,\n values_count: snapshot.count,\n\n signaling_transport: t,\n });\n });\n }\n\n static destroy() {\n StatPings._instance?._destroy();\n }\n\n private trackerByTransport: Record<SignalingTransportType, StatTracker> = {\n ws: new StatTracker(),\n wt: new StatTracker(),\n };\n\n // для интервалов между приходами: время прошлого mark()\n private lastSeen: Partial<Record<SignalingTransportType, number>> = {};\n\n private _destroy() {\n this.trackerByTransport = {\n ws: new StatTracker(),\n wt: new StatTracker(),\n };\n this.lastSeen = {};\n }\n}\n", "import { SignalingTransportType } from '../../enums/SignalingTransportStat';\nimport Stat from '../../enums/Stat';\nimport { StatTracker } from '../../utils/StatTracker';\nimport Logger from '../Logger';\nimport { TransportTopology } from '../transport/Transport';\n\nexport class StatSignalingCommands {\n private static _instance?: StatSignalingCommands;\n\n static create() {\n if (!StatSignalingCommands._instance) {\n StatSignalingCommands._instance = new StatSignalingCommands();\n }\n }\n\n static mark(command: string, time: number, transport: SignalingTransportType) {\n if (!StatSignalingCommands._instance) {\n return;\n }\n\n const key = `${command}|${transport}`;\n\n let tracker: StatTracker;\n if (!StatSignalingCommands._instance.trackerByCommand.has(key)) {\n tracker = new StatTracker();\n StatSignalingCommands._instance.trackerByCommand.set(key, tracker);\n } else {\n tracker = StatSignalingCommands._instance.trackerByCommand.get(key) as StatTracker;\n }\n\n tracker.add(time);\n }\n\n /** Отправляем данные в стату */\n static logMetrics(topology?: TransportTopology) {\n if (!StatSignalingCommands._instance) {\n return;\n }\n\n for (const [key, tracker] of StatSignalingCommands._instance.trackerByCommand.entries()) {\n if (!tracker.hasData) {\n continue;\n }\n\n const [command, transport] = key.split('|');\n\n const snapshot = tracker.snapshot();\n\n Logger.logClientStats({\n call_topology: topology === TransportTopology.DIRECT ? 'D' : 'S',\n\n name: Stat.SIGNALING_COMMAND_SUMMARY,\n api_method: command,\n\n min_value: snapshot.min,\n max_value: snapshot.max,\n avg_value: snapshot.avg,\n median_value: snapshot.median,\n p95_value: snapshot.p95,\n values_count: snapshot.count,\n\n signaling_transport: transport,\n });\n }\n }\n\n static destroy() {\n StatSignalingCommands._instance?._destroy();\n }\n\n private trackerByCommand: Map<string, StatTracker> = new Map();\n\n private _destroy() {\n this.trackerByCommand.clear();\n }\n}\n", "enum SignalingConnectionType {\n START = 'start',\n ACCEPT = 'accept',\n JOIN = 'join',\n RETRY = 'retry',\n}\n\nexport default SignalingConnectionType;\n", "import Params from '../static/Params';\n\n/**\n * @see https://confluence.vk.team/display/VIDEOOK/Websocket+Capability+Flags\n */\nconst PREDICATES = {\n producerScreenTrack: () => Params.producerScreenTrack, // 0 - producer screen track,\n videoTracksCount: () => Params.videoTracksCount > 0, // 1 - participant-agnostic tracks,\n waitingHall: () => true, // 2 - waiting hall,\n filteredMessages: () => true, // 3 - filtered messages,\n consumerScreenTrack: () => Params.consumerScreenTrack, // 4 - consumer screen track,\n muteNotificationForAdmins: () => true, // 5 - mute notification for admins,\n movieShare: () => Params.movieShare, // 6 - support movie share,\n useParticipantListChunk: () => Params.useParticipantListChunk, // 7 - chunked participants,\n useRooms: () => Params.useRooms, // 8 - rooms,\n vmoji: () => !!Params.vmoji, // 9 - vmoji,\n useCallsToContacts: () => Params.useCallsToContacts, // 10 - calls to contacts,\n useChatRooms: () => Params.useChatRooms, // 11 - AUDIENCE_MODE,\n audienceModeHandUpTimestamps: () => false, // 12 - AUDIENCE_MODE_HAND_UP_TIMESTAMPS,\n animojiBackendRender: () => !Params.vmojiOptions.renderingOptions.useFullClientRendering, // 13 - ANIMOJI_BACKEND_RENDER,\n sessionStateUpdates: () => false, // 14 - SESSION_STATE_UPDATES,\n addParticipant: () => Params.addParticipant, // 15 - add participant,\n p2pRelay: () => false, // 16 p2p relay\n waitForAdmin: () => Params.waitForAdminInGroupCalls, // 17 - WAIT_FOR_ADMIN,\n} as const;\n\ntype ParticipantCapabilitiesKeys = keyof typeof PREDICATES;\nexport type ParticipantCapabilities = Record<ParticipantCapabilitiesKeys, boolean>;\n\nexport class SignalingCapabilities {\n public static getFlags(): string {\n const predicates = Object.values(PREDICATES);\n\n let flagsMask = 0;\n for (let i = 0; i < predicates.length; i++) {\n if (predicates[i]()) {\n flagsMask |= 1 << i;\n }\n }\n return flagsMask.toString(16).toUpperCase();\n }\n\n public static parseCapabilities(mask?: string): ParticipantCapabilities {\n const flags = parseInt(mask || '0', 16);\n\n return Object.keys(PREDICATES).reduce<ParticipantCapabilities>((acc, value, index) => {\n acc[value as ParticipantCapabilitiesKeys] = Boolean(flags & (1 << index));\n return acc;\n }, {} as ParticipantCapabilities);\n }\n}\n", "import * as fflate from 'fflate';\nimport { VariableLengthIntegerEncoder, VariableLengthIntegerDecoder } from './VariableLengthInteger';\n\n/**\n * Encodes a string into a Uint8Array, prepending the length of the string as a variable-length integer and optionally compressing it.\n */\nclass LengthPrefixedTextEncoder {\n private readonly encoder: TextEncoder;\n private readonly compression: string | null;\n private readonly lengthEncoder: VariableLengthIntegerEncoder;\n\n constructor(compression?: 'gzip' | 'deflate' | 'deflate-raw' | null) {\n this.encoder = new TextEncoder();\n this.lengthEncoder = new VariableLengthIntegerEncoder();\n this.compression = compression ?? null;\n }\n\n /**\n * Encodes the given string into a Uint8Array.\n *\n * @param data The string to encode.\n * @returns A Uint8Array containing the length-prefixed and optionally compressed encoded string.\n * @throws {RangeError} If the string length exceeds the maximum representable value.\n */\n encode(data: string): Uint8Array {\n let encodedData = this.encoder.encode(data);\n encodedData = this.compress(encodedData);\n const lengthPrefix = this.lengthEncoder.encode(encodedData.length);\n\n const result = new Uint8Array(lengthPrefix.length + encodedData.length);\n result.set(lengthPrefix);\n result.set(encodedData, lengthPrefix.length);\n return result;\n }\n\n private compress(data: Uint8Array): Uint8Array {\n if (!this.compression) {\n return data;\n }\n\n switch (this.compression) {\n case 'gzip':\n return fflate.gzipSync(data);\n case 'deflate':\n return fflate.zlibSync(data);\n case 'deflate-raw':\n return fflate.deflateSync(data);\n default:\n return data;\n }\n }\n}\n\n/**\n * Decodes a stream of Uint8Arrays into strings, where each string\n * is prefixed by its length as a variable-length integer and optionally decompressed.\n */\nclass LengthPrefixedTextDecoder {\n private readonly decoder: TextDecoder;\n private readonly compression: string | null;\n private readonly lengthDecoder: VariableLengthIntegerDecoder;\n private buffer: Uint8Array;\n private expectedLength: number | null;\n private offset: number;\n private lengthPrefixLength: number;\n\n constructor(compression?: 'gzip' | 'deflate' | 'deflate-raw' | null) {\n this.decoder = new TextDecoder();\n this.lengthDecoder = new VariableLengthIntegerDecoder();\n this.compression = compression ?? null;\n this.buffer = new Uint8Array(0);\n this.expectedLength = null;\n this.offset = 0;\n }\n\n /**\n * Decodes a Uint8Array into a list of strings.\n *\n * @param data The Uint8Array to decode.\n * @returns An array of decoded strings.\n */\n decode(data: Uint8Array): string[] {\n const decodedStrings: string[] = [];\n this.buffer = new Uint8Array([...this.buffer, ...data]);\n\n while (this.buffer.length > 0) {\n if (this.expectedLength === null) {\n this.expectedLength = this.readLength(this.buffer);\n if (this.expectedLength === null) {\n // Not enough data to read the length prefix yet.\n return decodedStrings;\n }\n this.offset = this.lengthPrefixLength;\n }\n\n if (this.buffer.length - this.offset < this.expectedLength) {\n // Not enough data to read the full message yet.\n return decodedStrings;\n }\n\n let messageData = this.buffer.subarray(this.offset, this.offset + this.expectedLength);\n messageData = this.decompress(messageData);\n decodedStrings.push(this.decoder.decode(messageData));\n\n this.buffer = this.buffer.subarray(this.offset + this.expectedLength);\n this.expectedLength = null;\n this.offset = 0;\n }\n return decodedStrings;\n }\n\n /**\n * Reads the length prefix from the beginning of the data.\n *\n * @param data The Uint8Array containing the length prefix.\n * @returns The length of the message, or null if there's not enough data to read the length.\n */\n private readLength(data: Uint8Array): number | null {\n if (data.length === 0) {\n return 0;\n }\n this.lengthPrefixLength = this.lengthDecoder.getNumBytesForLengthInteger(data);\n if (this.lengthPrefixLength < 0) {\n throw new Error('Invalid length prefix');\n }\n const len = this.lengthDecoder.decode(data.subarray(0, this.lengthPrefixLength));\n return len === null ? null : Number(len);\n }\n\n private decompress(data: Uint8Array): Uint8Array {\n if (!this.compression) {\n return data;\n }\n\n switch (this.compression) {\n case 'gzip':\n return fflate.gunzipSync(data);\n case 'deflate':\n return fflate.unzlibSync(data);\n case 'deflate-raw':\n return fflate.inflateSync(data);\n default:\n return data;\n }\n }\n}\n\nexport { LengthPrefixedTextEncoder, LengthPrefixedTextDecoder };\n", "const MAX_6_BIT = 63n;\nconst MAX_14_BIT = 16383n;\nconst MAX_30_BIT = 0x3fffffff;\nconst MAX_62_BIT = 4611686018427387903n;\n\nclass VariableLengthIntegerEncoder {\n /**\n * Encodes an integer using a variable-length integer encoding.\n * @param num The number to encode.\n * @returns A Uint8Array representing the encoded integer.\n */\n encode(num: number | bigint): Uint8Array {\n const n = typeof num === 'number' ? BigInt(num) : num;\n if (n <= MAX_6_BIT) {\n // 6 bits of usable data\n return new Uint8Array([Number(n)]);\n } else if (n <= MAX_14_BIT) {\n // 14 bits of usable data\n return new Uint8Array([0x40 | Number(n >> 8n), Number(n & 0xffn)]);\n } else if (n <= BigInt(MAX_30_BIT)) {\n // 30 bits of usable data\n return new Uint8Array([0x80 | Number(n >> 24n), Number((n >> 16n) & 0xffn), Number((n >> 8n) & 0xffn), Number(n & 0xffn)]);\n } else if (n <= MAX_62_BIT) {\n // 62 bits of usable data\n return new Uint8Array([\n 0xc0 | Number(n >> 56n),\n Number((n >> 48n) & 0xffn),\n Number((n >> 40n) & 0xffn),\n Number((n >> 32n) & 0xffn),\n Number((n >> 24n) & 0xffn),\n Number((n >> 16n) & 0xffn),\n Number((n >> 8n) & 0xffn),\n Number(n & 0xffn),\n ]);\n } else {\n throw new RangeError('Number is too large to encode using varint');\n }\n }\n}\n\nclass VariableLengthIntegerDecoder {\n /**\n * Decodes an integer from a Uint8Array using variable-length integer encoding.\n * @param data The Uint8Array to decode.\n * @returns The decoded integer.\n */\n decode(data: Uint8Array): bigint | null {\n const byteNum = this.getNumBytesForLengthInteger(data);\n if (byteNum < 0) {\n throw new Error('Invalid length prefix');\n }\n if (data.length < byteNum) {\n // Not enough data to decode integer\n return null;\n }\n\n let n = BigInt(0);\n switch (byteNum) {\n case 1: // 1-byte integer\n n = BigInt(data[0] & 0x3f);\n break;\n case 2: // 2-byte integer\n n = (BigInt(data[0] & 0x3f) << 8n) | BigInt(data[1]);\n break;\n case 4: // 4-byte integer\n n = (BigInt(data[0] & 0x3f) << 24n) | (BigInt(data[1]) << 16n) | (BigInt(data[2]) << 8n) | BigInt(data[3]);\n break;\n case 8: // 8-byte integer\n n =\n (BigInt(data[0] & 0x3f) << 56n) |\n (BigInt(data[1]) << 48n) |\n (BigInt(data[2]) << 40n) |\n (BigInt(data[3]) << 32n) |\n (BigInt(data[4]) << 24n) |\n (BigInt(data[5]) << 16n) |\n (BigInt(data[6]) << 8n) |\n BigInt(data[7]);\n break;\n }\n return n;\n }\n\n getNumBytesForLengthInteger(data: Uint8Array): number {\n const lengthPrefix = data[0] & 0xc0;\n if (lengthPrefix === 0x00) {\n return 1;\n } else if (lengthPrefix === 0x40) {\n return 2;\n } else if (lengthPrefix === 0x80) {\n return 4;\n } else if (lengthPrefix === 0xc0) {\n return 8;\n }\n return -1;\n }\n}\n\nexport { VariableLengthIntegerEncoder, VariableLengthIntegerDecoder };\n", "// #v-ifdef TARGET='nodejs'\n// #v-endif\n\nimport Params from '../static/Params';\nimport WebRTCUtils from '../static/WebRTCUtils';\nimport { LengthPrefixedTextEncoder, LengthPrefixedTextDecoder } from '../utils/LengthPrefixed';\nimport Debug from '../static/Debug';\n\ntype CompressionType = 'gzip' | 'deflate' | 'deflate-raw' | null;\n\nclass WebTransportEventual {\n private webTransport: WebTransport;\n private stream: WebTransportBidirectionalStream | null = null;\n private writer: WritableStreamDefaultWriter | null = null;\n private reader: ReadableStreamDefaultReader | null = null;\n private readonly url: string;\n private readonly options: WebTransportOptions;\n private readonly compression: CompressionType;\n\n private encoder;\n private decoder;\n\n onopen: ((this: WebTransportEventual, ev: Event) => any) | null = null;\n onmessage: ((this: WebTransportEventual, ev: MessageEvent) => any) | null = null;\n onerror: ((this: WebTransportEventual, ev: Event) => any) | null = null;\n onclose: ((this: WebTransportEventual, ev: CloseEvent) => any) | null = null;\n readyState: number = WebSocket.CONNECTING;\n\n constructor(url: string, options: WebTransportOptions = {}) {\n this.url = url;\n this.options = options;\n this.readyState = WebSocket.CONNECTING;\n this.compression = this.getCompressionTypeFromUrl(url);\n this.encoder = new LengthPrefixedTextEncoder(this.compression);\n this.decoder = new LengthPrefixedTextDecoder(this.compression);\n this.connect();\n }\n\n private getCompressionTypeFromUrl(url: string): 'gzip' | 'deflate' | 'deflate-raw' | null {\n try {\n const urlObj = new URL(url);\n const compression = urlObj.searchParams.get('compression');\n switch (compression) {\n case 'gzip':\n case 'deflate':\n case 'deflate-raw':\n return compression;\n default:\n return null;\n }\n } catch (e) {\n Debug.log('Exception while parsing compression', e);\n return null;\n }\n }\n\n private async connect() {\n try {\n this.webTransport = new WebTransport(this.url, { ...this.options });\n await this.webTransport.ready;\n\n Debug.debug('[WebTransport] WebTransport connected to ' + this.url);\n\n this.stream = await this.webTransport.createBidirectionalStream();\n this.writer = this.stream.writable.getWriter();\n this.reader = this.stream.readable.getReader();\n this.readyState = WebSocket.OPEN;\n this.onopen?.(new Event('open'));\n await this.readLoop();\n } catch (error) {\n Debug.error('[WebTransport] WebTransport connection failed. This will cause fallback to WebSocket', error);\n this.readyState = WebSocket.CLOSED;\n this.onerror?.(new Event('error'));\n this.onclose?.(new CloseEvent('close', { code: 1006, reason: 'Connection Failed' }));\n }\n }\n\n private async *readChunks() {\n if (!this.reader) return;\n\n try {\n while (true) {\n const { done, value } = await this.reader.read();\n if (done) break;\n if (value) yield value;\n }\n } finally {\n this.reader.releaseLock();\n }\n }\n\n private async readLoop() {\n if (!this.reader) {\n return;\n }\n\n try {\n // todo: заменить на чтение сразу из стрима, когда появится поддержка\n for await (const data of this.readChunks()) {\n const decodedStrings = this.decoder.decode(data);\n\n decodedStrings.forEach((decodedString: string) => {\n this.onmessage?.(new MessageEvent('message', { data: decodedString }));\n });\n }\n\n this.close(1000, 'Stream Closed');\n } catch (error) {\n Debug.error('[WebTransport] Stream read failed', error);\n this.readyState = WebSocket.CLOSED;\n this.onerror?.(new Event('error'));\n }\n }\n\n async send(data: string) {\n if (this.readyState !== WebSocket.OPEN) {\n Debug.warn('[WebTransport] Attempt to send data before webtransport is open');\n return;\n }\n\n if (!this.writer) {\n Debug.warn('[WebTransport] Attempt to send data before stream is ready');\n return;\n }\n\n try {\n await this.writer.ready;\n\n const chunk = this.encoder.encode(data);\n await this.writer.write(chunk);\n } catch (error) {\n Debug.error('[WebTransport] Failed to send data', error);\n this.onerror?.(new Event('error'));\n this.close(1006, 'Failed to send data');\n }\n }\n\n close(code = 1000, reason?: string) {\n if (this.readyState === WebSocket.CLOSED || this.readyState === WebSocket.CLOSING) {\n return;\n }\n\n this.readyState = WebSocket.CLOSING;\n\n this.reader?.cancel();\n\n try {\n this.webTransport.close();\n } catch (err) {\n Debug.warn('[WebTransport] already closed. Did we get a STOP_SENDING? ignore', err);\n }\n\n this.readyState = WebSocket.CLOSED;\n this.onclose?.(new CloseEvent('close', { code, reason }));\n\n this.webTransport.closed.then(() => {\n this.writer = null;\n this.reader = null;\n this.stream = null;\n });\n }\n\n static isBrowserSupported(): boolean {\n const isSupported = 'WebTransport' in window && typeof WebTransport === 'function';\n if (!isSupported) {\n return false;\n }\n\n // Для Firefox возвращаем только в случае ручка включена\n if (WebRTCUtils.browserName() === 'Firefox') {\n return Params.webtransportFF;\n }\n\n // Safari не поддержан\n if (WebRTCUtils.browserName() === 'Safari') {\n return false;\n }\n\n return true;\n }\n}\n\nexport { WebTransportEventual as WebTransport };\n", "import BaseSignaling, { AddParticipantParams } from '../abstract/BaseSignaling';\nimport HangupReason from '../classes/HangupReason';\nimport Logger from '../classes/Logger';\nimport { ParticipantIdRegistry } from '../classes/ParticipantIdRegistry';\nimport { ProducerCommandSerializationService } from '../classes/ProducerCommandSerializationService';\nimport { SharingStatReport } from '../classes/screenshare/SharingStatReport';\nimport { StatAggregator } from '../classes/stat/StatAggregator';\nimport { StatPings } from '../classes/stat/StatPings';\nimport { StatSignalingCommands } from '../classes/stat/StatSignalingCommands';\nimport Statistics from '../classes/transport/Statistics';\nimport { TransportTopology } from '../classes/transport/Transport';\nimport { MAIN_ROOM_ID } from '../constants/Rooms';\nimport ConversationFeature from '../enums/ConversationFeature';\nimport ConversationOption from '../enums/ConversationOption';\nimport FatalError from '../enums/FatalError';\nimport HangupType from '../enums/HangupType';\nimport MediaOption from '../enums/MediaOption';\nimport SignalingCommandType from '../enums/SignalingCommandType';\nimport SignalingConnectionType from '../enums/SignalingConnectionType';\nimport SignalingEvent from '../enums/SignalingEvent';\nimport SignalingNotification from '../enums/SignalingNotification';\nimport { SignalingTransportStat, SignalingTransportType, SOCKET_STAT } from '../enums/SignalingTransportStat';\nimport Stat from '../enums/Stat';\nimport StatLog from '../enums/StatLog';\nimport UserRole from '../enums/UserRole';\nimport Debug from '../static/Debug';\nimport External from '../static/External';\nimport { JSONObject } from '../static/Json';\nimport Params from '../static/Params';\nimport { SignalingCapabilities } from '../static/SignalingCapabilities';\nimport Utils from '../static/Utils';\nimport { IAsrStartParams, IAsrStopParams } from '../types/Asr';\nimport { ChangeSimulcast } from '../types/ChangeSimulcast';\nimport { EnableVideoSuspend } from '../types/EnableVideoSuspend';\nimport { EnableVideoSuspendSuggest } from '../types/EnableVideoSuspendSuggest';\nimport { IEventualStatLog } from '../types/IEventualStatLog';\nimport { layoutToString } from '../types/LayoutUtils';\nimport MediaModifiers from '../types/MediaModifiers';\nimport MediaSettings from '../types/MediaSettings';\nimport { IAddMovieParams, IUpdateMovieData } from '../types/MovieShare';\nimport MuteStates from '../types/MuteStates';\nimport { NetworkStatReport } from '../types/NetworkStatReport';\nimport { CompositeUserId, ParticipantId, ParticipantStateData } from '../types/Participant';\nimport ParticipantLayout, { RequestKeyFrame, StopStream } from '../types/ParticipantLayout';\nimport { ParticipantListChunkParameters } from '../types/ParticipantListChunk';\nimport { StreamDescriptionString } from '../types/ParticipantStreamDescription';\nimport { PerfStatReport } from '../types/PerfStatReporter';\nimport { RequestAsr } from '../types/RequestAsr';\nimport SignalingCommand from '../types/SignalingCommand';\nimport SignalingMessage, { GetParticipantsSignalingResponse, GetRoomsSignalingResponse, SignalingResponse, SignalingSuccessResponse } from '../types/SignalingMessage';\nimport { IPublishStreamData, IRecordConfData, IStartStreamData, IStopStreamData } from '../types/Streams';\nimport { WebTransport } from '../types/WebTransport';\n\nconst DATA_CHANNEL_STATE_OPEN: RTCDataChannelState = 'open';\n\nconst RESEND_COUNT = 10;\n\nconst FATAL_ERRORS = ['service-unavailable', 'conversation-ended', 'invalid-token'];\n\nexport default class Signaling extends BaseSignaling {\n private socket: WebSocket | WebTransport | null = null;\n protected sequence = 1;\n private lastStamp = 0;\n private websocketCommandsQueue: SignalingCommand[] = [];\n private datachannelCommandsQueue: SignalingCommand[] = [];\n private incomingCache: SignalingMessage[] = [];\n private responseHandlers: { [index: number]: SignalingCommand } = {};\n\n private connectionType: SignalingConnectionType;\n private reconnectCount = 0;\n private endpoint: string;\n private wtEndpoint: string | null = null;\n\n protected conversationResolve: Function | null = null;\n protected conversationReject: Function | null = null;\n\n private connected = false;\n private listenersReady = false;\n private postfix: string =\n '&platform=' +\n Params.platform +\n '&appVersion=' +\n Params.appVersion +\n '&version=' +\n Params.protocolVersion +\n '&device=' +\n Params.device +\n '&capabilities=' +\n SignalingCapabilities.getFlags();\n\n protected peerId: number | null = null;\n // Используется только в ТамТаме\n protected conversationId: string | null = null;\n\n private reconnectTimer = 0;\n private connectionMessageWaitTimer = 0;\n private doctorTimer = 0;\n\n private participantIdRegistry: ParticipantIdRegistry | null = null;\n private producerNotificationDataChannel: RTCDataChannel | null = null;\n private producerCommandDataChannel: RTCDataChannel | null = null;\n private producerCommandDataChannelEnabled = false;\n private producerCommandSerializationService = new ProducerCommandSerializationService();\n\n private static get RECONNECT_DELAY(): number {\n return Params.signalingReconnectDelay;\n }\n\n private static get RECONNECT_MAX_DELAY(): number {\n return Params.signalingReconnectMaxDelay;\n }\n\n private static get RECONNECT_MAX_COUNT(): number {\n return Params.signalingReconnectMaxCount;\n }\n\n private static get WAIT_CONNECTION_DELAY(): number {\n return Params.waitConnectionDelay;\n }\n\n private static get WAIT_RESPONSE_DELAY(): number {\n return Params.waitResponseDelay;\n }\n\n private static get WAIT_MESSAGE_DELAY(): number {\n return Params.waitMessageDelay;\n }\n\n override get ready() {\n return this.socket !== null;\n }\n\n override setEndpoint(endpoint: string) {\n this.endpoint = endpoint;\n }\n\n override setWebTransportEndpoint(endpoint: string | null) {\n this.wtEndpoint = endpoint;\n }\n\n override setConversationId(conversationId: string) {\n this.conversationId = conversationId;\n }\n\n override setParticipantIdRegistry(participantIdRegistry: ParticipantIdRegistry) {\n this.participantIdRegistry = participantIdRegistry;\n this.producerCommandSerializationService.setParticipantIdRegistry(participantIdRegistry);\n }\n\n override setProducerNotificationDataChannel(dataChannel: RTCDataChannel): void {\n this.producerNotificationDataChannel = dataChannel;\n this.producerNotificationDataChannel.onmessage = (event: MessageEvent) => {\n const notification = this.participantIdRegistry?.handleMessage(event.data);\n if (notification) {\n this._handleMessage(notification);\n }\n };\n }\n\n override setProducerCommandDataChannel(dataChannel: RTCDataChannel) {\n this.producerCommandDataChannel = dataChannel;\n this.producerCommandDataChannel.onmessage = (event: MessageEvent) => {\n this.producerCommandSerializationService\n .deserializeCommandResponse(event.data)\n .then((response) => {\n if (response) {\n this._handleMessage(response);\n }\n })\n .catch((reason) => {\n Debug.warn('[signaling] cannot parse message at producerCommandDataChannel', reason);\n });\n };\n this._handleCommandsQueue(this.datachannelCommandsQueue);\n }\n\n override useCommandDataChannel(status: boolean) {\n this.producerCommandDataChannelEnabled = status;\n }\n\n /**\n * Free used resources\n */\n override cleanup() {\n // close() нам не подходит, т.к. он вызывается в том числе когда умирает websocket\n // datachannel.onclose() тоже, т.к. хочется сохранить очередь команд между реконнектами\n this.datachannelCommandsQueue = [];\n this.incomingCache = [];\n }\n\n /**\n * Open a connection with a signaling server\n */\n override async connect(connectionType: SignalingConnectionType): Promise<SignalingMessage.Connection> {\n // Устанавливаем clientType только перед коннектом, т.к. он приходит из апи\n this.postfix += `&clientType=${Params.clientType}`;\n return new Promise((resolve: Function, reject: Function) => {\n if (this.socket && this.socket.readyState < WebSocket.CLOSING) {\n Logger.log(StatLog.SOCKET_ACTION, 'already_opened');\n reject(Error('Socket already opened'));\n return;\n }\n\n this.conversationResolve = (message: SignalingMessage.Connection) => {\n resolve(message);\n this.conversationResolve = null;\n this.conversationReject = null;\n };\n this.conversationReject = (error: Error) => {\n reject(error);\n this.conversationResolve = null;\n this.conversationReject = null;\n };\n\n this._connect(connectionType, this.isWebTransportAvailable());\n });\n }\n\n /**\n * Send a command to a signaling server\n */\n protected async _send<T extends SignalingSuccessResponse>(command: SignalingCommandType, params: any = {}, needResponse = true, retryCount = 0): Promise<T> {\n if (params.participantId) {\n const participantId = Utils.decomposeParticipantId(params.participantId);\n const userId = Utils.decomposeId(participantId.compositeUserId);\n params = Object.assign({}, params, {\n participantId: userId.id,\n participantType: userId.type,\n });\n if (participantId.deviceIdx) {\n params.deviceIdx = participantId.deviceIdx;\n }\n }\n\n return this._sendRaw<T>(command, params, needResponse, retryCount);\n }\n\n /**\n * Send a raw command to a signaling server\n */\n protected async _sendRaw<T extends SignalingSuccessResponse>(command: SignalingCommandType, params: any = {}, needResponse = true, retryCount = 0): Promise<T> {\n const sendNow = (signalingCommand: SignalingCommand) => {\n if (this._isDataChannelCommand(command)) {\n this.datachannelCommandsQueue.push(signalingCommand);\n if (this.producerCommandDataChannel?.readyState === DATA_CHANNEL_STATE_OPEN) {\n this._handleCommandsQueue(this.datachannelCommandsQueue);\n }\n } else {\n if (!this.socket) {\n Logger.log(StatLog.SOCKET_ACTION, 'not_opened');\n Debug.warn('[signaling] socket is not opened');\n signalingCommand.reject(new Error(`Socket not opened [${command}]`), true);\n return;\n }\n\n if (this.socket.readyState > WebSocket.OPEN) {\n Logger.log(StatLog.SOCKET_ACTION, 'invalid_state');\n Debug.warn(`[signaling] socket is not opened, state ${this.socket.readyState}`);\n }\n\n this.websocketCommandsQueue.push(signalingCommand);\n\n if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n this._handleCommandsQueue(this.websocketCommandsQueue);\n }\n }\n };\n\n return new Promise<T>((resolve, reject) => {\n const onError = (error: Error, force = false) => {\n if (!retryCount || force) {\n reject(error);\n } else {\n Debug.debug('[signaling] resending a signaling message', command, signalingCommand.sequence);\n retryCount--;\n sendNow(signalingCommand as SignalingCommand);\n }\n };\n\n const sequence = this.sequence++;\n const statMarkName = `${command}_${sequence}`;\n\n Statistics.setMark(statMarkName);\n\n const signalingCommand: SignalingCommand<T> = {\n sequence,\n name: command,\n statMarkName: statMarkName,\n params,\n responseTimer: 0,\n needResponse,\n resolve,\n reject: onError,\n };\n\n sendNow(signalingCommand as SignalingCommand);\n });\n }\n\n private _isDataChannelCommand(command: SignalingCommandType | string): boolean {\n if (!this.producerCommandDataChannelEnabled) {\n return false;\n }\n return (\n command === SignalingCommandType.UPDATE_DISPLAY_LAYOUT ||\n command === SignalingCommandType.REPORT_PERF_STAT ||\n command === SignalingCommandType.REPORT_SHARING_STAT ||\n command === SignalingCommandType.REQUEST_ASR ||\n command === SignalingCommandType.ENABLE_VIDEO_SUSPEND ||\n command === SignalingCommandType.ENABLE_VIDEO_SUSPEND_SUGGEST ||\n command === SignalingCommandType.REPORT_NETWORK_STAT ||\n command === SignalingCommandType.CHANGE_SIMULCAST\n );\n }\n\n override getNextCommandSequenceNumber(): number {\n return this.sequence;\n }\n\n override async hangup(reason: string): Promise<SignalingMessage | void> {\n return this._send(SignalingCommandType.HANGUP, { reason }).catch(() => {\n // Do nothing, just intercept error\n });\n }\n\n override async sendCandidate(participantId: ParticipantId, candidate: RTCIceCandidate): Promise<SignalingMessage> {\n return this._send(\n SignalingCommandType.TRANSMIT_DATA,\n {\n participantId,\n data: { candidate },\n },\n false,\n );\n }\n\n override async requestTestMode(consumerCommand: string, producerCommand: string | null): Promise<SignalingMessage> {\n // consumerCommand={command:\"data-set-link-params\", params:{\"bandwidth-kbps\":\"700\"} };\n return this._send(SignalingCommandType.REQUEST_TEST_MODE, {\n consumer: consumerCommand,\n producer: producerCommand,\n });\n }\n\n override async sendSdp(participantId: ParticipantId, sdp: RTCSessionDescriptionInit, extraPayload?: Record<string, any>): Promise<SignalingMessage> {\n const data = Object.assign({ sdp }, extraPayload);\n return this._send(SignalingCommandType.TRANSMIT_DATA, {\n participantId,\n data,\n });\n }\n\n override async acceptCall(mediaSettings: MediaSettings): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ACCEPT_CALL, { mediaSettings });\n }\n\n override async changeMediaSettings(mediaSettings: MediaSettings): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.CHANGE_MEDIA_SETTINGS, { mediaSettings }, true, RESEND_COUNT);\n }\n\n override async changeParticipantState(state: ParticipantStateData, compositeUserId?: CompositeUserId): Promise<SignalingMessage> {\n const data: Record<string, any> = {\n participantState: { state },\n };\n\n if (compositeUserId) {\n data.participantId = compositeUserId;\n }\n\n return this._sendRaw(SignalingCommandType.CHANGE_PARTICIPANT_STATE, data);\n }\n\n override async putHandsDown(): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.PUT_HANDS_DOWN);\n }\n\n override async addParticipant(externalIds: CompositeUserId[], params?: AddParticipantParams): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ADD_PARTICIPANT, { externalIds, ...params });\n }\n\n override async addParticipantLegacy(participantIds: CompositeUserId[], params?: AddParticipantParams): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ADD_PARTICIPANT, { participantIds, ...params });\n }\n\n override async removeParticipant(participantId: CompositeUserId, ban = false): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.REMOVE_PARTICIPANT, { participantId, ban });\n }\n\n override async allocateConsumer(description: RTCSessionDescription | null, capabilities: { [key: string]: number | boolean | string }): Promise<SignalingMessage> {\n const data: any = { capabilities };\n if (description) {\n data.description = description.sdp;\n }\n return this._send(SignalingCommandType.ALLOCATE_CONSUMER, data);\n }\n\n override async acceptProducer(description: RTCSessionDescriptionInit, ssrcs: string[]): Promise<SignalingMessage> {\n const params: any = { description: description.sdp };\n if (ssrcs) {\n params.ssrcs = ssrcs;\n }\n return this._send(SignalingCommandType.ACCEPT_PRODUCER, params);\n }\n\n /**\n * @deprecated Use updateDisplayLayout instead\n */\n override async changePriorities(priorities: { [key: string]: number }): Promise<SignalingMessage | void> {\n return this._send(SignalingCommandType.CHANGE_STREAM_PRIORITIES, { typedPriorities: priorities }).catch(() => {\n // Do nothing, just intercept error\n });\n }\n\n override async updateDisplayLayout(layouts: { [streamDesc: StreamDescriptionString]: ParticipantLayout | StopStream | RequestKeyFrame }): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.UPDATE_DISPLAY_LAYOUT, layouts);\n }\n\n override async addMovie(data: IAddMovieParams): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ADD_MOVIE, data);\n }\n\n override async updateMovie(data: IUpdateMovieData): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.UPDATE_MOVIE, data);\n }\n\n override async removeMovie(data: any): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.REMOVE_MOVIE, data);\n }\n\n startUrlSharing(sharedUrl: string): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.START_URL_SHARING, { sharedUrl });\n }\n\n stopUrlSharing(): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.STOP_URL_SHARING);\n }\n\n override async updateRooms(rooms: SignalingMessage.Room[], assignRandomly?: boolean): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.UPDATE_ROOMS, { rooms, assignRandomly });\n }\n\n override async activateRooms(roomIds: number[], deactivate: boolean): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ACTIVATE_ROOMS, { roomIds, deactivate });\n }\n\n override async switchRoom(toRoomId: number | null, participantId?: ParticipantId): Promise<SignalingMessage> {\n return this._sendRaw(SignalingCommandType.SWITCH_ROOM, { toRoomId, participantId });\n }\n\n override async getRooms(withParticipants: boolean): Promise<GetRoomsSignalingResponse> {\n return this._sendRaw(SignalingCommandType.GET_ROOMS, { withParticipants });\n }\n\n override async removeRooms(roomIds: number[]): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.REMOVE_ROOMS, { roomIds });\n }\n\n override async startStream(data: IStartStreamData): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.RECORD_START, data);\n }\n\n override async stopStream(data: IStopStreamData = { roomId: MAIN_ROOM_ID }): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.RECORD_STOP, data);\n }\n\n override async publishStream(data: IPublishStreamData = { roomId: MAIN_ROOM_ID }): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.RECORD_PUBLISH, data);\n }\n\n override async recordSetConf(conf: IRecordConfData = { hideParticipantCount: false, roomId: MAIN_ROOM_ID }): Promise<SignalingMessage> {\n const data: any = {\n options: {\n hideParticipantCount: conf.hideParticipantCount,\n },\n roomId: conf.roomId,\n };\n if (conf.king) {\n data.king = conf.king;\n }\n if (conf.pawns?.length) {\n data.pawns = conf.pawns.join(',');\n }\n\n return this._send(SignalingCommandType.RECORD_SET_CONF, data);\n }\n\n override async getRecordStatus(): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.RECORD_GET_STATUS);\n }\n\n override async switchTopology(topology: TransportTopology, force = false): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.SWITCH_TOPOLOGY, {\n topology,\n force,\n });\n }\n\n override async requestRealloc(): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.REQUEST_REALLOC);\n }\n\n override async reportPerfStat(report: PerfStatReport): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.REPORT_PERF_STAT, report);\n }\n\n override async reportSharingStat(report: SharingStatReport): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.REPORT_SHARING_STAT, report, false);\n }\n\n override async reportNetworkStat(report: NetworkStatReport): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.REPORT_NETWORK_STAT, report, false);\n }\n\n override async chatMessage(message: string, participantId: CompositeUserId | null = null): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.CHAT_MESSAGE, { message, participantId });\n }\n\n override async chatHistory(count: number): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.CHAT_HISTORY, { count });\n }\n\n override async customData(data: JSONObject, participantId: ParticipantId | null): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.CUSTOM_DATA, { data, participantId });\n }\n\n override async grantRoles(participantId: ParticipantId, roles: UserRole[], revoke: boolean): Promise<SignalingMessage> {\n const data: any = { participantId, roles };\n if (revoke) {\n data.revoke = true;\n }\n return this._sendRaw(SignalingCommandType.GRANT_ROLES, data);\n }\n\n override async muteParticipant(\n participantId: ParticipantId | null,\n muteStates: MuteStates,\n requestedMedia: MediaOption[],\n roomId: number | null = null,\n ): Promise<SignalingMessage> {\n return this._sendRaw(SignalingCommandType.MUTE_PARTICIPANT, { participantId, muteStates, requestedMedia, roomId });\n }\n\n override async enableFeatureForRoles(feature: ConversationFeature, roles: UserRole[]): Promise<SignalingMessage> {\n return this._sendRaw(SignalingCommandType.ENABLE_FEATURE_FOR_ROLES, { feature, roles });\n }\n\n override async pinParticipant(participantId: ParticipantId, unpin: boolean, roomId: number | null): Promise<SignalingMessage> {\n const data: any = { participantId, roomId };\n if (unpin) {\n data.unpin = true;\n }\n return this._sendRaw(SignalingCommandType.PIN_PARTICIPANT, data);\n }\n\n override async updateMediaModifiers(mediaModifiers: MediaModifiers): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.UPDATE_MEDIA_MODIFIERS, { mediaModifiers });\n }\n\n override async enableVideoSuspend(enabled: boolean): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ENABLE_VIDEO_SUSPEND, { enabled }, false);\n }\n\n override async enableVideoSuspendSuggest(enabled: boolean): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ENABLE_VIDEO_SUSPEND_SUGGEST, { enabled }, false);\n }\n\n override async changeSimulcast(changeSimulcast: ChangeSimulcast): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.CHANGE_SIMULCAST, changeSimulcast, false);\n }\n\n override async changeOptions(changes: { [key in ConversationOption]?: boolean }): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.CHANGE_OPTIONS, { options: changes });\n }\n\n override async getWaitingHall(fromId: SignalingMessage.WaitingParticipantId | null = null, count?: number, backward = false): Promise<SignalingMessage> {\n const data: any = {};\n if (fromId) {\n data.fromId = fromId;\n }\n if (count) {\n data.count = count;\n }\n if (backward) {\n data.backward = backward;\n }\n return this._send(SignalingCommandType.GET_WAITING_HALL, data);\n }\n\n override async promoteParticipant(participantId?: CompositeUserId, demote = false): Promise<SignalingMessage> {\n const data: any = {};\n if (participantId) {\n data.participantId = participantId;\n }\n if (demote) {\n data.demote = demote;\n }\n return this._sendRaw(SignalingCommandType.PROMOTE_PARTICIPANT, data);\n }\n\n override async requestPromotion(unrequest = false): Promise<SignalingMessage> {\n const data: any = {};\n if (unrequest) {\n data.unrequest = unrequest;\n }\n return this._send(SignalingCommandType.REQUEST_PROMOTION, data);\n }\n\n override async acceptPromotion(reject = false): Promise<SignalingMessage> {\n const data: any = {};\n if (reject) {\n data.reject = reject;\n }\n return this._send(SignalingCommandType.ACCEPT_PROMOTION, data);\n }\n\n override async feedback(key: string): Promise<SignalingMessage> {\n return this._sendRaw(SignalingCommandType.FEEDBACK, { key });\n }\n\n override async getHandQueue(): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.GET_HAND_QUEUE);\n }\n\n /**\n * Close a connection with a signaling server\n */\n override close(): void {\n if (this.socket && this.socket.readyState < WebSocket.CLOSING) {\n this._closeSocket();\n }\n\n this._stopWaitConnectionMessage();\n this._stopDoctor();\n clearTimeout(this.reconnectTimer);\n }\n\n /**\n * Этот метод нужен т.к. после получения сообщения \"connected\" устанавливается транспорт\n * и подписывается на сигналинг. Данные приходят очень быстро и транспорт пропускает\n * часть сообщений сигналинга. Этот метод вызывается вручную и сообщает о том,\n * что все подписчики готовы принимать сообщения от сигналинга.\n */\n override readyToSend(isReady = true) {\n this.listenersReady = isReady;\n this._handleCachedMessages();\n }\n\n override async getParticipantListChunk(participantListChunkParameters: ParticipantListChunkParameters): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.GET_PARTICIPANT_LIST_CHUNK, participantListChunkParameters);\n }\n\n override async getParticipants(externalIds: SignalingMessage.ExternalId[]): Promise<GetParticipantsSignalingResponse> {\n return this._send(SignalingCommandType.GET_PARTICIPANTS, {\n externalIds,\n });\n }\n\n override getPeerId() {\n return this.peerId;\n }\n\n override async startAsr(params: IAsrStartParams): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ASR_START, params);\n }\n\n async stopAsr(params?: IAsrStopParams): Promise<SignalingMessage> {\n return this._send(SignalingCommandType.ASR_STOP, params);\n }\n\n override async requestAsr(request: boolean): Promise<SignalingMessage> {\n return this._send(\n SignalingCommandType.REQUEST_ASR,\n {\n request,\n },\n false,\n );\n }\n\n protected _connect(connectionType: SignalingConnectionType, useWebTransport: boolean): void {\n if (this.socket && this.socket.readyState < WebSocket.CLOSING) {\n return;\n }\n\n this.connectionType = connectionType;\n\n let dynamicPostfix = '';\n if (connectionType) {\n dynamicPostfix += `&tgt=${connectionType}`;\n }\n if (connectionType === SignalingConnectionType.RETRY && this.lastStamp) {\n // @see https://wiki.odkl.ru/display/projects/Fast+recover\n dynamicPostfix += `&recoverTs=${this.lastStamp}`;\n }\n\n dynamicPostfix = setParticipantChunkInitParams(dynamicPostfix);\n\n if (useWebTransport) {\n dynamicPostfix += '&compression=deflate-raw';\n\n // todo: убрать в заголовки, когда появится в браузерах https://github.com/w3c/webtransport/pull/695\n dynamicPostfix += `&ua=${navigator.userAgent}`;\n\n Debug.debug('[signaling] connecting to wt ' + this.wtEndpoint + this.postfix + dynamicPostfix);\n\n this.socket = new WebTransport(this.wtEndpoint + this.postfix + dynamicPostfix);\n } else {\n Debug.debug('[signaling] connecting to ws ' + this.endpoint + this.postfix + dynamicPostfix);\n\n this.socket = new WebSocket(this.endpoint + this.postfix + dynamicPostfix);\n }\n\n this._markTransportStat(connectionType === SignalingConnectionType.RETRY ? SignalingTransportStat.RECONNECTED : SignalingTransportStat.CONNECTED);\n\n this.socket.onopen = this._onOpen.bind(this);\n this.socket.onmessage = this._onMessage.bind(this);\n this.socket.onerror = this._onError.bind(this);\n this.socket.onclose = this._onClose.bind(this);\n this._startDoctor();\n\n function setParticipantChunkInitParams(postfix: string): string {\n if (!Params.useParticipantListChunk) {\n return postfix;\n }\n const partIdx = Params.participantListChunkInitIndex;\n postfix += `&partIdx=${partIdx}`;\n const partCount = Params.participantListChunkInitCount;\n if (partCount !== null) {\n postfix += `&partCount=${partCount}`;\n }\n return postfix;\n }\n }\n\n protected _disconnect(code?: number): void {\n if (this.socket && this.socket.readyState < WebSocket.CLOSING) {\n this.socket.onopen = null;\n this.socket.onmessage = null;\n this.socket.onerror = null;\n this.socket.onclose = null;\n this.socket.close(code);\n this.socket = null;\n }\n\n this._stopWaitConnectionMessage();\n this._stopDoctor();\n clearTimeout(this.reconnectTimer);\n }\n\n private _onOpen(): void {\n Debug.debug('[signaling] socket opened');\n Logger.log(StatLog.SOCKET_ACTION, 'opened');\n this._waitConnectionMessage();\n this._startDoctor();\n\n this._logTransportStat(this.connectionType === SignalingConnectionType.RETRY ? SignalingTransportStat.RECONNECTED : SignalingTransportStat.CONNECTED);\n }\n\n private _onMessage(event: MessageEvent): void {\n this._startDoctor();\n\n if (event.data === 'ping') {\n StatPings.mark(this._getSocketType());\n this._markTransportStat(SignalingTransportStat.FAILED_PINGS);\n\n External.onSignalingMessage(event.data);\n if (this.socket && this.socket.readyState === WebSocket.OPEN) {\n this.socket.send('pong');\n }\n return;\n }\n\n try {\n const msg = JSON.parse(event.data);\n External.onSignalingMessage(msg);\n this._handleMessage(msg);\n } catch (e) {\n Logger.log(StatLog.SOCKET_ACTION, 'parse_error');\n Debug.error('[signaling] unable to parse message', e, event.data);\n }\n }\n\n protected _handleMessage(message: SignalingMessage) {\n switch (message.type) {\n case 'notification':\n if (message.notification === 'connection') {\n Debug.debug('[signaling] signaling connected', message);\n\n this.connected = true;\n this.reconnectCount = 0;\n this.endpoint = message.endpoint;\n\n if (message.peerId && this.peerId !== message.peerId.id) {\n this.postfix += `&peerId=${message.peerId.id}`;\n this.peerId = message.peerId.id;\n }\n\n this._stopWaitConnectionMessage();\n\n if (this.conversationResolve) {\n this.conversationResolve(message as SignalingMessage.Connection);\n } else {\n this._logTransportStat(SignalingTransportStat.RESTART);\n\n this._triggerEvent(SignalingEvent.RECONNECT, message);\n if (message.conversation.topology) {\n // Это костыль для обработки смены топологии во время реконнекта\n this._triggerEvent(SignalingEvent.NOTIFICATION, {\n type: 'notification',\n notification: SignalingNotification.TOPOLOGY_CHANGED,\n topology: message.conversation.topology,\n });\n }\n }\n\n if (this.lastStamp) {\n this._handleCachedMessages();\n }\n\n message.recoverMessages?.forEach((msg: SignalingMessage) => {\n /**\n * В случае восстановления соединения после смены webtransport на websocket\n * игнорируем сообщение о пире, так как это мы же. Если обработать,\n * то звонок завершится по ошибке Call accepted on other device\n */\n if (msg.notification === SignalingNotification.ACCEPTED_CALL && msg.peerId.id === this.peerId && msg.peerId.type === 'WEB_TRANSPORT') {\n return;\n }\n\n this._handleMessage(msg);\n });\n this._handleCommandsQueue(this.websocketCommandsQueue);\n } else if (!this.connected || !this.listenersReady) {\n this.incomingCache.push(message);\n } else {\n this._triggerEvent(SignalingEvent.NOTIFICATION, message);\n }\n break;\n\n case 'response':\n this._handleCommandResponse(true, message as SignalingSuccessResponse);\n break;\n\n case 'error':\n this._handleErrorMessage(message as SignalingResponse);\n break;\n\n default:\n Logger.log(StatLog.SOCKET_ACTION, 'unknown_message');\n Debug.warn('[signaling] unhandled message', message);\n }\n\n this.lastStamp = message.stamp || this.lastStamp;\n }\n\n private _handleErrorMessage(message: SignalingResponse) {\n Logger.log(StatLog.SOCKET_ACTION, `error-${message.error}`);\n\n const isFatalError = message.error ? FATAL_ERRORS.includes(message.error) : false;\n\n Debug.debug(`[signaling] error message [${message.sequence}]`, message);\n\n if (message.sequence && this.responseHandlers[message.sequence]) {\n this._handleCommandResponse(false, message as SignalingSuccessResponse);\n }\n\n switch (message.error) {\n case 'service-unavailable':\n const error = new HangupReason(HangupType.SERVICE_UNAVAILABLE, {\n message: `Conversation ended: ${message.error}`,\n remote: true,\n });\n\n if (this.conversationReject) {\n this.conversationReject(error);\n } else {\n this._triggerEvent(SignalingEvent.NOTIFICATION, {\n notification: SignalingNotification.CLOSED_CONVERSATION,\n reason: HangupType.SERVICE_UNAVAILABLE,\n });\n }\n break;\n\n case 'conversation-ended':\n if (this.conversationReject) {\n this.conversationReject(\n new HangupReason(message.reason || FatalError.SIGNALING_FAILED, {\n message: `Conversation ended: ${message.error}`,\n remote: true,\n }),\n );\n } else {\n this._triggerEvent(SignalingEvent.NOTIFICATION, {\n notification: SignalingNotification.CLOSED_CONVERSATION,\n reason: message.reason,\n });\n }\n break;\n\n case 'participant-not-found':\n // TODO: Возможно стоит обновить токен из _getConversationParams если он протух\n this._throwError(new Error(`Signaling error: ${message.error}`));\n break;\n\n case 'invalid-token':\n default:\n if (!isFatalError) {\n break;\n }\n\n if (this.connected) {\n this._throwError(new Error(`Signaling error: ${message.error}`));\n } else if (!message.sequence) {\n this.conversationReject?.(\n new HangupReason(message.reason || FatalError.SIGNALING_FAILED, {\n message: `Unable to connect to the signaling: ${message.error}`,\n remote: true,\n }),\n );\n this._closeSocket();\n }\n }\n }\n\n protected _handleCachedMessages(): void {\n const cachedMessages = [...this.incomingCache];\n this.incomingCache = []; // Делаем это синхронно, т.к. в _handleMessage мы пишем в incomingCache\n while (cachedMessages.length > 0) {\n const message = cachedMessages.shift() as SignalingMessage;\n this._handleMessage(message);\n }\n }\n\n private _throwError(error: object): void {\n this._triggerEvent(SignalingEvent.FAILED, error);\n }\n\n private _onError(event: Event): void {\n Logger.log(StatLog.SOCKET_ACTION, 'error');\n Debug.error('[signaling] signaling error', event);\n\n this._logTransportStat(SignalingTransportStat.FAILED_EXCEPTIONS, { string_value: JSON.stringify(event) });\n }\n\n protected _onClose(event: CloseEvent): void {\n Logger.log(StatLog.SOCKET_ACTION, 'closed');\n Debug.debug('[signaling] connection closed', {\n code: event.code,\n reason: event.reason,\n });\n this.connected = false;\n\n this._stopDoctor();\n\n if (this.socket && this.reconnectCount++ < Signaling.RECONNECT_MAX_COUNT) {\n this._reconnect();\n } else if (this.socket) {\n this._closeSocket(new HangupReason(HangupType.NETWORK_ERROR));\n }\n }\n\n protected _closeSocket(error: Error | null = null): void {\n if (!this.socket) {\n return;\n }\n\n this._disconnect();\n\n Object.values(this.responseHandlers).forEach((command) => {\n window.clearTimeout(command.responseTimer);\n if (error) {\n command.reject(new Error(`Connection closed. Command ${command.name}`), true);\n }\n });\n this.websocketCommandsQueue = [];\n this.responseHandlers = {};\n\n this.lastStamp = 0;\n\n if (error) {\n this._throwError(error);\n }\n }\n\n protected _reconnect(): void {\n const delay = Math.min(Signaling.RECONNECT_MAX_DELAY, Signaling.RECONNECT_DELAY * Math.pow(2, this.reconnectCount - 1));\n Debug.log(`[signaling] reconnect websocket after ${delay}ms (${this.reconnectCount})`);\n Logger.log(StatLog.SOCKET_ACTION, 'reconnect');\n this.reconnectTimer = window.setTimeout(this._connect.bind(this, SignalingConnectionType.RETRY, false), delay);\n }\n\n private _handleCommandResponse(status: boolean, message: SignalingSuccessResponse): void {\n if (!Object.hasOwn(this.responseHandlers, message.sequence)) {\n return;\n }\n const command = this.responseHandlers[message.sequence];\n window.clearTimeout(command.responseTimer);\n\n const delay = Statistics.measureMark(command.statMarkName);\n if (delay !== null) {\n StatSignalingCommands.mark(command.name, delay, this._getSocketType());\n }\n\n Debug.debug(`[signaling] command response [${message.sequence}]`, message);\n\n if (status) {\n delete this.responseHandlers[message.sequence];\n command.resolve(message);\n } else if (message.type === 'error') {\n delete this.responseHandlers[message.sequence];\n Logger.log(StatLog.SOCKET_ACTION, 'response-error');\n // Не ретраим отправку, если это сообщение об ошибке, а не таймаут\n command.reject(new Error(message.error || `Response error [${command.name}]`), true);\n } else if (this.socket?.readyState === WebSocket.OPEN) {\n delete this.responseHandlers[message.sequence];\n Logger.log(StatLog.SOCKET_ACTION, 'response-timeout');\n command.reject(new Error(message.error || `Response timeout [${command.name}]`));\n } else {\n // Мы в реконнекте, подождем еще\n command.responseTimer = window.setTimeout(() => this._handleCommandResponse(status, message), Signaling.WAIT_RESPONSE_DELAY);\n }\n }\n\n private _handleCommandsQueue(queue: SignalingCommand[]): void {\n while (queue.length > 0) {\n const command = queue.shift() as SignalingCommand;\n Debug.debug(`[signaling] command send [${command.sequence}]`, `'${command.name}'`, command.params);\n\n if (this._isDataChannelCommand(command.name)) {\n if (this.producerCommandDataChannel?.readyState !== DATA_CHANNEL_STATE_OPEN) {\n command.reject(new Error(`Invalid data channel state: ${this.producerCommandDataChannel?.readyState}`));\n return; // abort queue processing - we'll continue once the channel is opened again\n }\n\n this._startResponseTimer(command);\n\n const binary = this._serializeBinary(command);\n if (binary !== null) {\n this.producerCommandDataChannel.send(binary);\n }\n } else {\n if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {\n command.reject(new Error('Invalid state or socket already closed'));\n continue;\n }\n\n this._startResponseTimer(command);\n\n this.socket.send(this._serializeJson(command));\n }\n }\n }\n\n private _startResponseTimer(command: SignalingCommand): void {\n if (!command.needResponse) {\n command.resolve({\n type: 'response',\n sequence: command.sequence,\n response: command.name,\n } as SignalingSuccessResponse);\n\n return;\n }\n\n command.responseTimer = window.setTimeout(\n () =>\n this._handleCommandResponse(false, {\n response: command.name,\n sequence: command.sequence,\n type: 'timeout',\n }),\n Signaling.WAIT_RESPONSE_DELAY,\n );\n\n this.responseHandlers[command.sequence] = command;\n }\n\n private _serializeBinary(command: SignalingCommand): ArrayBuffer | null {\n switch (command.name) {\n case SignalingCommandType.UPDATE_DISPLAY_LAYOUT:\n return this.producerCommandSerializationService.serializeUpdateDisplayLayout(\n command.sequence,\n command.params as { [key: string]: ParticipantLayout | StopStream | RequestKeyFrame },\n );\n case SignalingCommandType.REPORT_PERF_STAT:\n return this.producerCommandSerializationService.serializePerfStatReport(command.sequence, command.params as PerfStatReport);\n case SignalingCommandType.REPORT_SHARING_STAT:\n return this.producerCommandSerializationService.serializeSharingStatReport(command.sequence, command.params as SharingStatReport);\n case SignalingCommandType.REQUEST_ASR:\n return this.producerCommandSerializationService.serializeRequestAsr(command.sequence, command.params as RequestAsr);\n case SignalingCommandType.REPORT_NETWORK_STAT:\n return this.producerCommandSerializationService.serializeNetworkStatReport(command.sequence, command.params as NetworkStatReport);\n case SignalingCommandType.ENABLE_VIDEO_SUSPEND:\n return this.producerCommandSerializationService.serializeEnableVideoSuspend(command.sequence, command.params as EnableVideoSuspend);\n case SignalingCommandType.ENABLE_VIDEO_SUSPEND_SUGGEST:\n return this.producerCommandSerializationService.serializeEnableVideoSuspendSuggest(command.sequence, command.params as EnableVideoSuspendSuggest);\n case SignalingCommandType.CHANGE_SIMULCAST:\n return this.producerCommandSerializationService.serializeChangeSimulcast(command.sequence, command.params as ChangeSimulcast);\n }\n Debug.warn('[signaling] cannot get binary data for data channel command: ' + command.name);\n return null;\n }\n\n private _serializeJson(command: SignalingCommand): string {\n let params;\n if (command.name === SignalingCommandType.UPDATE_DISPLAY_LAYOUT) {\n params = this._convertDisplayLayout(command.params);\n } else {\n params = command.params;\n }\n\n const message = Object.assign(\n {\n command: command.name,\n sequence: command.sequence,\n },\n params,\n );\n\n return JSON.stringify(message);\n }\n\n private _convertDisplayLayout(params: object): object {\n const layouts = params as { [streamDesc: string]: ParticipantLayout | StopStream | RequestKeyFrame };\n\n const serializedLayoutByStreamDescription: { [streamDesc: string]: string } = {};\n for (const streamDesc in layouts) {\n if (Object.hasOwn(layouts, streamDesc)) {\n serializedLayoutByStreamDescription[streamDesc] = layoutToString(layouts[streamDesc]);\n }\n }\n\n return { layouts: serializedLayoutByStreamDescription };\n }\n\n protected _waitConnectionMessage(): void {\n this.connectionMessageWaitTimer = window.setTimeout(() => {\n if (this.conversationReject) {\n this.conversationReject(\n new HangupReason(FatalError.SIGNALING_FAILED, {\n message: 'Unable to connect to the signaling: connection timeout',\n remote: true,\n }),\n );\n }\n }, Signaling.WAIT_CONNECTION_DELAY);\n }\n\n protected _stopWaitConnectionMessage(): void {\n window.clearTimeout(this.connectionMessageWaitTimer);\n this.connectionMessageWaitTimer = 0;\n }\n\n /**\n * Отвечает за timeout логику в WebSocket, если неполучаем никаких сообщений в течении WAIT_MESSAGE_DELAY, то запускаем реконнект\n */\n private _startDoctor(): void {\n this._stopDoctor();\n if (this.reconnectCount >= Signaling.RECONNECT_MAX_COUNT) {\n return;\n }\n\n this.doctorTimer = window.setTimeout(() => {\n if (this.isWebTransportAvailable()) {\n Debug.warn(`[signaling] socket is dead. Fallback to WebSocket. Trying to connect ${this.reconnectCount}`);\n } else {\n Debug.warn(`[signaling] socket is dead, trying to reconnect ${this.reconnectCount}`);\n }\n\n this._logTransportStat(SignalingTransportStat.FAILED_PINGS);\n\n this._disconnect(4000);\n this._connect(SignalingConnectionType.RETRY, false);\n this.reconnectCount++;\n }, Signaling.WAIT_MESSAGE_DELAY);\n }\n\n private _stopDoctor(): void {\n window.clearTimeout(this.doctorTimer);\n this.doctorTimer = 0;\n }\n\n private isWebTransportAvailable() {\n return WebTransport.isBrowserSupported() && this.wtEndpoint !== null && Params.webtransport;\n }\n\n // Вспомогательный метод для определения типа соединения\n private _getSocketType(): SignalingTransportType {\n return this.socket instanceof WebTransport ? SignalingTransportType.WEBTRANSPORT : SignalingTransportType.WEBSOCKET;\n }\n\n private _markTransportStat(event: SignalingTransportStat): void {\n const connectionType = this._getSocketType();\n const statEvent = SOCKET_STAT[event][connectionType];\n\n Statistics.setMark(statEvent);\n }\n\n private _logTransportStat(event: SignalingTransportStat, params?: Omit<IEventualStatLog, 'name' | 'value'>): void {\n const connectionType = this._getSocketType();\n const statEvent = SOCKET_STAT[event][connectionType];\n\n StatAggregator.logEventualStat({ name: statEvent, ...params });\n }\n}\n", "enum CallDirection {\n INCOMING = 'INCOMING',\n OUTGOING = 'OUTGOING',\n JOINING = 'JOINING',\n}\n\nexport default CallDirection;\n", "enum CallType {\n USER = 'USER',\n GROUP = 'GROUP',\n CHAT = 'CHAT',\n}\n\nexport default CallType;\n", "/**\n * Тип команды зала ожидания\n */\nenum ChatRoomEventType {\n ATTENDEE = 'ATTENDEE', // new Stereo attendee joined/left, new waiting hall participant joined/left\n HAND_UP = 'HAND_UP', // Stereo attendee rose/dropped hand\n}\n\nexport default ChatRoomEventType;\n", "/**\n * Возможности пользователя в звонке\n */\nconst enum ConversationFeature {\n ADD_PARTICIPANT = 'ADD_PARTICIPANT',\n RECORD = 'RECORD',\n MOVIE_SHARE = 'MOVIE_SHARE',\n}\n\nexport default ConversationFeature;\n", "/**\n * Опции звонка\n */\nenum ConversationOption {\n REQUIRE_AUTH_TO_JOIN = 'REQUIRE_AUTH_TO_JOIN',\n AUDIENCE_MODE = 'AUDIENCE_MODE', // Stereo chat room\n WAITING_HALL = 'WAITING_HALL', // Waiting Hall is ON\n WAIT_FOR_ADMIN = 'WAIT_FOR_ADMIN',\n ADMIN_IS_HERE = 'ADMIN_IS_HERE',\n ASR = 'ASR',\n FEEDBACK = 'FEEDBACK', // Reactions (default = off)\n RECURRING = 'RECURRING',\n}\n\nexport default ConversationOption;\n\nexport function compareOptions(oldOptions: ConversationOption[], newOptions: ConversationOption[]): boolean {\n if (oldOptions.length !== newOptions.length) {\n return false;\n }\n\n for (const option of oldOptions) {\n if (!newOptions.includes(option)) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function applyOptionChanges(options: ConversationOption[], changes: { [key in ConversationOption]?: boolean }): ConversationOption[] {\n const set = new Set(options);\n for (const [option, enabled] of Object.entries(changes)) {\n if (enabled) {\n set.add(option as ConversationOption);\n } else {\n set.delete(option as ConversationOption);\n }\n }\n return Array.from(set);\n}\n", "/**\n * Разрешение на включение устройства\n */\nenum MuteState {\n UNMUTE = 'UNMUTE',\n MUTE = 'MUTE',\n MUTE_PERMANENT = 'MUTE_PERMANENT',\n}\n\nexport default MuteState;\n", "enum ParticipantState {\n CALLED = 'CALLED',\n ACCEPTED = 'ACCEPTED',\n REJECTED = 'REJECTED',\n HUNGUP = 'HUNGUP',\n}\n\nexport default ParticipantState;\n", "/**\n * Тип обновления комнаты\n */\nenum RoomsEventType {\n UPDATE = 'UPDATE',\n REMOVE = 'REMOVE',\n ACTIVATE = 'ACTIVATE',\n // timer finished\n TIMEOUT = 'TIMEOUT',\n}\n\nexport default RoomsEventType;\n", "enum UpdateDisplayLayoutErrorReason {\n NO_AVAILABLE_TRACKS = 'no-available-tracks',\n UNKNOWN_ERROR = 'unknown-error',\n}\n\nexport default UpdateDisplayLayoutErrorReason;\n\nexport function getUpdateDisplayLayoutErrorReasonByCode(errorCode: number): UpdateDisplayLayoutErrorReason {\n switch (errorCode) {\n case 1:\n return UpdateDisplayLayoutErrorReason.NO_AVAILABLE_TRACKS;\n default:\n return UpdateDisplayLayoutErrorReason.UNKNOWN_ERROR;\n }\n}\n", "/**\n * Роль участника в звонке\n */\nenum UserRole {\n CREATOR = 'CREATOR',\n ADMIN = 'ADMIN',\n}\n\nexport default UserRole;\n\nexport function compareUserRoles(oldRoles: UserRole[], newRoles: UserRole[]): boolean {\n if (oldRoles.length !== newRoles.length) {\n return false;\n }\n\n for (const role of oldRoles) {\n if (!newRoles.includes(role)) {\n return false;\n }\n }\n\n return true;\n}\n", "import MediaOption from '../enums/MediaOption';\nimport UserRole from '../enums/UserRole';\nimport { ParticipantStatus } from '../static/External';\nimport MediaSettings from './MediaSettings';\nimport { ISharedMovieInfo } from './MovieShare';\nimport MuteStates from './MuteStates';\nimport { ParticipantListMarker, ParticipantListType, ParticipantStateMapped } from './Participant';\nimport SignalingMessage from './SignalingMessage';\n\n/**\n * Тип внешнего пользователя\n */\nexport enum ExternalIdType {\n USER = 'USER',\n ANONYM = 'ANONYM',\n GROUP = 'GROUP',\n}\n\nexport type ExternalUserId = string;\n\nexport namespace ExternalIdUtils {\n export function fromIds(ids: ExternalUserId[] | ExternalId[]): ExternalId[] {\n if (!ids.length) {\n return [];\n }\n\n if (typeof ids[0] === 'object') {\n return ids as ExternalId[];\n }\n\n return ids.map((id) => fromId(id as string));\n }\n\n export function fromId(id: ExternalUserId, type = ExternalIdType.USER, deviceIdx = 0): ExternalParticipantId {\n return { id, type, deviceIdx };\n }\n\n export function fromSignalingParticipant(participant: SignalingMessage.Participant, useDecorative = true): ExternalParticipantId | undefined {\n const externalId = useDecorative ? participant.decorativeExternalUserId : participant.externalId;\n const deviceIdx = participant.deviceIdx ?? 0;\n\n if (externalId) {\n return fromSignaling(externalId, deviceIdx);\n }\n }\n\n export function fromSignaling(signalingId: SignalingMessage.ExternalId, deviceIdx = 0): ExternalParticipantId {\n return {\n id: signalingId.id,\n type: signalingId.type === 'ANONYM' ? ExternalIdType.ANONYM : ExternalIdType.USER,\n deviceIdx,\n };\n }\n\n export function toSignaling(externalId: ExternalId): string {\n return externalId.id;\n }\n\n export function toString(externalId: ExternalId): ExternalIdString {\n const deviceIdx = (externalId as ExternalParticipantId).deviceIdx || 0;\n // Не используем JSON.stringify, т.к. он не гарантирует порядок полей в строке\n return `{\"id\":\"${externalId.id}\",\"type\":\"${externalId.type}\",\"deviceIdx\":${deviceIdx}}`;\n }\n\n export function fromIdToString(id: ExternalUserId, type = ExternalIdType.USER, deviceIdx = 0): ExternalIdString {\n return toString(fromId(id, type, deviceIdx));\n }\n\n export function fromString(stringId: ExternalIdString): ExternalParticipantId {\n try {\n return JSON.parse(stringId);\n } catch (e) {\n throw new Error(`Failed to parse ExternalId from string '${stringId}'`);\n }\n }\n\n export function compare(id1: ExternalParticipantId, id2: ExternalParticipantId): boolean {\n return id1.id === id2.id && id1.type === id2.type && id1.deviceIdx === id2.deviceIdx;\n }\n\n export function getDeviceIdx(externalId: ExternalId | null): number {\n return externalId?.deviceIdx || 0;\n }\n}\n\nexport type ExternalIdString = string;\n\n/**\n * Идентификатор внешнего пользователя\n */\nexport interface ExternalId {\n /**\n * ID пользователя\n */\n id: ExternalUserId;\n /**\n * Тип пользователя\n */\n type: ExternalIdType;\n /**\n * Пользователь является наблюдателем звонка\n * @hidden\n */\n observer?: boolean;\n /**\n * Индекс устройства (позволяет отличать участников, которые присоединяются к звонку под одной учётной записью с разных устройств)\n */\n deviceIdx?: number;\n}\n\n/**\n * Идентификатор участника звонка\n */\nexport interface ExternalParticipantId extends ExternalId {\n /**\n * Индекс устройства (позволяет отличать участников, которые присоединяются к звонку под одной учётной записью с разных устройств)\n */\n deviceIdx: number; // Отличие в том, что здесь он обязательный\n}\n\n/**\n * Маркер определяющий положение участника в списке\n */\nexport type ExternalParticipantListMarker = Required<ParticipantListMarker>;\n\n/**\n * Словарь сопоставляющий тип списка участников с маркером (положением участника в списке)\n */\nexport type ExternalParticipantListMarkers = Record<ParticipantListType, ExternalParticipantListMarker>;\n\n/**\n * Участник звонка\n */\nexport interface ExternalParticipant {\n /**\n * Идентификатор пользователя\n */\n uid: ExternalParticipantId;\n /**\n * Данные стрима\n */\n mediaSettings: MediaSettings;\n /**\n * Статус соединения\n */\n status: ParticipantStatus;\n /**\n * Клиентское состояние\n */\n participantState?: ParticipantStateMapped;\n /**\n * Состояние устройств пользователя установленное админом звонка\n */\n muteStates: MuteStates;\n /**\n * Разрешения на включение устройств\n */\n unmuteOptions: MediaOption[];\n markers: ExternalParticipantListMarkers | null;\n movieShareInfos?: ISharedMovieInfo[];\n roles: UserRole[];\n}\n\n/**\n * Позиция в чанке\n */\nexport interface ExternalParticipantListChunk {\n participants: ExternalParticipant[];\n countBefore: number;\n countAfter: number;\n markerFound: boolean;\n}\n", "import Debug from '../static/Debug';\nimport { ExternalId } from './ExternalId';\nimport SignalingMessage from './SignalingMessage';\nimport { IFeedback } from './Feedback';\n\nexport type ChatRoom = {\n totalCount: number; // total count of attendees\n firstParticipants?: SignalingMessage.WaitingParticipant[]; // relevant only if WAITING_HALL is set\n handCount?: number; // relevant only if AUDIENCE_MODE is set\n feedback?: IFeedback[]; // relevant only if AUDIENCE_MODE is set\n};\n\n/**\n * Ответ на запрос `getWaitingHall`\n */\nexport type WaitingHallResponse = {\n participants: ExternalId[];\n pageMarker: string | null;\n totalCount: number;\n};\n\nexport function waitingParticipantIdToString(id: SignalingMessage.WaitingParticipantId): string | null {\n try {\n return btoa(JSON.stringify(id));\n } catch (e) {\n Debug.warn('WaitingParticipant: failed convert to string', id, e);\n }\n return null;\n}\n\nexport function waitingParticipantIdFromString(id: string): SignalingMessage.WaitingParticipantId | null {\n try {\n return JSON.parse(atob(id)) as SignalingMessage.WaitingParticipantId;\n } catch (e) {\n Debug.warn('WaitingParticipant: failed convert from string', id, e);\n }\n return null;\n}\n", "import MediaOption from '../enums/MediaOption';\nimport MuteState from '../enums/MuteState';\nimport Utils from '../static/Utils';\nimport MediaSettings from '../types/MediaSettings';\nimport MuteStates from '../types/MuteStates';\nimport SignalingMessage from '../types/SignalingMessage';\n\nexport const getMediaOptionsByMuteState = (muteStates: MuteStates, value: MuteState): MediaOption[] => {\n return Utils.objectReduce(\n muteStates,\n (acc, muteState, mediaOption) => {\n if (muteState === value) {\n acc.push(mediaOption);\n }\n return acc;\n },\n [] as MediaOption[],\n );\n};\n\nexport function extractConnectionMuteStates(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant): MuteStates | undefined {\n if (connection.conversation?.muteStates) {\n return connection.conversation.muteStates;\n }\n if (connection.muteState && connection.muteOptions) {\n return connection.muteOptions.reduce<MuteStates>((acc, muteOption) => {\n acc[muteOption] = connection.muteState;\n return acc;\n }, {});\n }\n}\n\nfunction isMediaEnabled(mediaOption: MediaOption, mediaSettings: Partial<MediaSettings>) {\n // смотрим, только на такие же mediaOptions как в Conversation@_processMuteState\n switch (mediaOption) {\n case MediaOption.AUDIO:\n return !!mediaSettings.isAudioEnabled;\n case MediaOption.AUDIO_SHARING:\n return !!mediaSettings.isAudioSharingEnabled;\n case MediaOption.VIDEO:\n return !!mediaSettings.isVideoEnabled;\n case MediaOption.SCREEN_SHARING:\n return !!mediaSettings.isFastScreenSharingEnabled || !!mediaSettings.isScreenSharingEnabled;\n default:\n return false;\n }\n}\n\nfunction filterReconnectMuteStates(muteStates: MuteStates, mediaSettings: Partial<MediaSettings>) {\n return Utils.objectReduce<MuteStates, MuteStates>(\n muteStates,\n (acc, muteState, mediaOption) => {\n switch (muteState) {\n case MuteState.MUTE:\n case MuteState.MUTE_PERMANENT: {\n // если прилетает MUTE, но при этом медийка сервером считается включенной,\n // то это взаимоисключащая ситуация и мы просто получили повторный\n // стейт на реконнекте\n if (!isMediaEnabled(mediaOption, mediaSettings)) {\n acc[mediaOption] = muteState;\n }\n break;\n }\n default:\n acc[mediaOption] = muteState;\n break;\n }\n\n return acc;\n },\n {},\n );\n}\n\nexport function filterReconnectedParticipantMuteStates(participant: SignalingMessage.Participant): MuteStates {\n const { muteStates = {}, mediaSettings } = participant;\n return filterReconnectMuteStates(muteStates, mediaSettings);\n}\n\nexport function filterReconnectedConversationMuteStates(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant, muteStates: MuteStates): MuteStates {\n const meParticipant = connection.conversation.participants.find((participant) => {\n return Utils.comparePeerId(participant.peerId as SignalingMessage.PeerId, connection.peerId);\n });\n\n if (!meParticipant) {\n return muteStates;\n }\n\n const { mediaSettings } = meParticipant;\n\n return filterReconnectMuteStates(muteStates, mediaSettings);\n}\n", "export function lz4Decompress(input: Uint8Array, outputLength: number) {\n const output = new Uint8Array(outputLength);\n let inputPos = 0;\n let outputPos = 0;\n\n while (inputPos < input.length && outputPos < outputLength) {\n // Читаем токен (literal + match lengths)\n const token = input[inputPos++];\n let literalLen = token >> 4;\n let matchLen = token & 0x0f;\n\n // Декодируем длину литералов\n if (literalLen === 0x0f) {\n let byte;\n do {\n byte = input[inputPos++];\n literalLen += byte;\n } while (byte === 0xff);\n }\n\n // Копируем литералы\n for (let i = 0; i < literalLen; i++) {\n if (outputPos >= outputLength) {\n break;\n }\n\n output[outputPos++] = input[inputPos++];\n }\n\n if (inputPos >= input.length || outputPos >= outputLength) {\n break;\n }\n\n // Читаем смещение (2 байта, little-endian)\n const offset = input[inputPos] | (input[inputPos + 1] << 8);\n inputPos += 2;\n\n // Декодируем длину совпадения\n if (matchLen === 0x0f) {\n let byte;\n do {\n byte = input[inputPos++];\n matchLen += byte;\n } while (byte === 0xff);\n }\n matchLen += 4; // Минимальная длина совпадения\n\n // Копируем совпадения (back-reference)\n const startPos = outputPos - offset;\n for (let i = 0; i < matchLen; i++) {\n if (outputPos >= outputLength) {\n break;\n }\n output[outputPos++] = output[startPos + i];\n }\n }\n\n return output;\n}\n", "import StatLog from '../enums/StatLog';\nimport Debug from '../static/Debug';\nimport WebRTCUtils from '../static/WebRTCUtils';\nimport Logger from './Logger';\nimport { MediaSource, MediaTrackKind } from './MediaSource';\n\nexport default class AudioFix {\n private _fixNoPacketsApplied = false;\n private _fixNoPacketsChecked = false;\n\n // робовойс возникает из хрома, при этом клиент отправляет больше пакетов чем ожидаем (например 100/сек вместо 50/сек)\n private _fixTooManyPacketsApplied = false;\n private _fixTooManyPacketsSucceeded = false;\n private _fixTooManyPacketsFailed = false;\n private _fixTooManyPacketsTime: number;\n private _mediaSource: MediaSource;\n private _lastPacketsSent: number;\n private _lastPacketsSentTime: number;\n private _toggleAudioPromise: Promise<void> | null = null;\n\n private _fixNoPacketsAppliedVideo = false;\n\n constructor(mediaSource: MediaSource) {\n this._mediaSource = mediaSource;\n }\n\n private _fixAudioDeviceNoPackets(audioRtp: any): void {\n if (this._fixNoPacketsApplied && this._fixNoPacketsChecked) {\n return;\n }\n\n if (this._fixNoPacketsApplied && !this._fixNoPacketsChecked) {\n this._fixNoPacketsChecked = true;\n Logger.log(StatLog.ERROR, `audio_device_recover_${audioRtp.bandwidth ? 'success' : 'fail'}`);\n return;\n }\n\n if (!this._fixNoPacketsApplied && !audioRtp.bandwidth) {\n this._fixNoPacketsApplied = true;\n Logger.log(StatLog.ERROR, 'audio_device_recover');\n // Перезапросим устройство\n Debug.log('[AudioFix] Trying to fix RV (no packets)');\n this._toggleAudioPromise = this._mediaSource.toggleAudio(WebRTCUtils.getMicrophonePermissionState() !== 'denied');\n }\n }\n\n private _fixAudioDeviceTooManyPackets(audioRtp: any): void {\n if (this._fixTooManyPacketsSucceeded || this._fixTooManyPacketsFailed) {\n return;\n }\n\n const maxPacketsPerSec = 75;\n const now = Date.now();\n if (!this._lastPacketsSentTime) {\n if (audioRtp.packetsSent > 0) {\n this._lastPacketsSentTime = now;\n this._lastPacketsSent = audioRtp.packetsSent;\n }\n } else if (now - this._lastPacketsSentTime > 500) {\n const packetsPerSec = ((audioRtp.packetsSent - this._lastPacketsSent) * 1000) / (now - this._lastPacketsSentTime);\n this._lastPacketsSentTime = now;\n this._lastPacketsSent = audioRtp.packetsSent;\n if (this._fixTooManyPacketsApplied) {\n if (packetsPerSec > maxPacketsPerSec) {\n Debug.log('[AudioFix] Failed to fix RV');\n Logger.log(StatLog.ERROR, 'audio_device_recover_rv_fail');\n this._fixTooManyPacketsFailed = true;\n } else {\n if (now - this._fixTooManyPacketsTime > 60000) {\n Debug.log('[AudioFix] Fixed RV');\n Logger.log(StatLog.ERROR, 'audio_device_recover_rv_success');\n this._fixTooManyPacketsSucceeded = true;\n }\n }\n } else {\n if (packetsPerSec > maxPacketsPerSec) {\n this._fixTooManyPacketsApplied = true;\n Logger.log(StatLog.ERROR, 'audio_device_recover');\n // Перезапросим устройство\n Debug.log('[AudioFix] Trying to fix RV (too many packets)');\n this._mediaSource.toggleAudio(true);\n this._fixTooManyPacketsTime = now;\n }\n }\n }\n }\n\n fix(rtps: any[]) {\n if (!this._mediaSource) {\n return;\n }\n\n const audioRtp = rtps.find((item: any) => item.kind === MediaTrackKind.audio);\n if (!audioRtp) {\n return;\n }\n\n this._fixAudioDeviceNoPackets(audioRtp);\n this._fixAudioDeviceTooManyPackets(audioRtp);\n }\n\n /** важно вызывать ___после___ метода `fix()` */\n fixVideo(rtps: any[]) {\n if (!this._mediaSource || this._fixNoPacketsAppliedVideo || !this._toggleAudioPromise) {\n return;\n }\n\n const videoRtp = rtps.find((item) => item.kind === MediaTrackKind.video);\n if (videoRtp && !videoRtp.bandwidth) {\n this._fixNoPacketsAppliedVideo = true;\n this._toggleAudioPromise.then(() => {\n // проверяем, что не успели отключить камеру к этому моменту\n if (this._mediaSource.getMediaSettings().isVideoEnabled) {\n this._mediaSource.toggleVideo(true);\n }\n });\n }\n }\n}\n", "import StatLog from '../enums/StatLog';\nimport Debug from '../static/Debug';\nimport External from '../static/External';\nimport Params from '../static/Params';\nimport WebRTCUtils from '../static/WebRTCUtils';\nimport Logger from './Logger';\nimport { StatFirstMediaReceived } from './stat/StatFirstMediaReceived';\n\ntype ParticipantAudioOutput = {\n audioElement?: HTMLAudioElement;\n audioTrack?: MediaStreamTrack;\n};\n\ninterface IFeatures {\n setSinkId: boolean;\n}\n\nexport default class AudioOutput {\n protected _output: ParticipantAudioOutput | null = null;\n private _volume = 1;\n private readonly _features: IFeatures = {\n setSinkId: !!Audio.prototype.setSinkId,\n };\n private readonly _statFirstMediaReceived: StatFirstMediaReceived;\n\n constructor(statFirstMediaReceived: StatFirstMediaReceived) {\n this._statFirstMediaReceived = statFirstMediaReceived;\n }\n\n add(track: MediaStreamTrack) {\n // Остановим, если уже существует\n this.destroy();\n\n this._output = {};\n this._output.audioTrack = track;\n\n this._initAudioElement();\n }\n\n remove(track: MediaStreamTrack) {\n if (!this._output || this._output.audioTrack !== track) {\n return;\n }\n\n this.destroy();\n }\n\n get volume() {\n return this._volume;\n }\n\n set volume(volume: number) {\n this._volume = Math.max(0, Math.min(1, volume));\n\n if (this._output && this._output.audioElement) {\n this._output.audioElement.volume = this._volume;\n }\n }\n\n protected _initAudioElement() {\n if (Params.muteMode) {\n return;\n }\n\n if (!this._output?.audioTrack) {\n return;\n }\n\n // AudioElement\n const canAutoPlayAudio = WebRTCUtils.browserName() !== 'Safari' || WebRTCUtils.isMobile(); // В сафари на десктопе почему-то не играет audio элемент\n const audio = document.createElement(canAutoPlayAudio ? 'audio' : 'video');\n audio.muted = false;\n audio.volume = this._volume;\n audio.preload = 'auto';\n\n const onPlayFailed = () => {\n Debug.warn('[audio] Error on play audio');\n External.onAutoplayError();\n };\n\n const play = (newTrack: MediaStreamTrack) => {\n audio.srcObject = new MediaStream([newTrack]);\n audio.load();\n const playResult = audio.play();\n if (playResult) {\n playResult.catch(onPlayFailed);\n }\n };\n\n const recover = () => {\n Debug.debug('[audio] Recover audio playback');\n\n const currentTrack = this._output?.audioTrack;\n if (currentTrack) {\n play(currentTrack);\n } else {\n Debug.warn('[audio] Broken audio track');\n }\n };\n audio.onpause = recover;\n audio.onstalled = recover;\n audio.onerror = recover;\n audio.onloadeddata = () => {\n this._statFirstMediaReceived.measure();\n };\n\n play(this._output.audioTrack);\n this._output.audioElement = audio;\n\n // FIXME: В FF 116 добавили поддержку setSinkId, но она работает криво - появляется эхо. Не устанавливаем сохраненное устройство на старте, пока не починят\n // const deviceId = WebRTCUtils.getSavedOutput()?.deviceId;\n // if (deviceId) {\n // audio.setSinkId?.(deviceId).catch((e) => {\n // Debug.warn(`[audio] Failed to set output device '${deviceId}'`, e);\n // });\n // }\n }\n\n protected _stopAudioElement() {\n if (this._output?.audioElement) {\n this._output.audioElement.pause();\n this._output.audioElement.srcObject = null;\n }\n this._output?.audioTrack?.stop();\n }\n\n destroy() {\n if (!this._output) {\n return;\n }\n\n this._stopAudioElement();\n this._output = null;\n }\n\n /** изменяем устройство для воспроизведения аудио */\n async changeOutput() {\n try {\n if (!this._features.setSinkId) {\n throw new Error('Feature \"setSinkId\" is not supported');\n }\n\n if (!this._output?.audioElement) {\n // Еще не подключились собеседники\n return;\n }\n\n const output = WebRTCUtils.getSavedOutput();\n\n if (output) {\n await this._output.audioElement.setSinkId?.(output.deviceId);\n }\n } catch (error) {\n Logger.log(StatLog.ERROR, 'change_output');\n Debug.error('[audio] Output change failed', error);\n throw error;\n }\n }\n}\n", "import Debug from '../static/Debug';\nimport External from '../static/External';\nimport { Participant, ParticipantId } from '../types/Participant';\nimport { StatResult } from '../types/Statistics';\nimport EventEmitter from './EventEmitter';\n\nconst MAX_MEMORY_PERCENT_THRESHOLD = 90;\nconst LOG_MEMORY_PERCENT_THRESHOLD = 3;\n\nexport default class DebugInfo extends EventEmitter {\n private _lastMemoryStat = {\n percent: 0,\n bytes: 0,\n };\n\n onRemoteDataStats(stats: StatResult, participants: Record<ParticipantId, Participant>) {\n this._calcMemory();\n stats.inbound.rtps.map((item) => {\n const participant = (typeof item.userId === 'string' && participants[item.userId]) || null;\n // FIXME: Пришлось подхачить здесь ExternalId, чтобы наружу без изменения типов отдавать\n // @ts-ignore\n item.userId = participant?.externalId;\n });\n External.onStatistics(stats, this._lastMemoryStat);\n }\n\n _calcMemory() {\n const memory = window?.performance?.memory;\n if (!memory || !memory.usedJSHeapSize || !memory.jsHeapSizeLimit) {\n return;\n }\n\n const memoryPercent = Number(((100 * memory.usedJSHeapSize) / memory.jsHeapSizeLimit).toFixed(2));\n const memoryMiB = Number((memory.usedJSHeapSize / 1024 / 1024).toFixed(1));\n\n if (memoryPercent > MAX_MEMORY_PERCENT_THRESHOLD) {\n Debug.warn(`High memory usage: ${memoryPercent}% (${memoryMiB} MiB)`);\n } else if (!this._lastMemoryStat.percent || Math.abs(memoryPercent - this._lastMemoryStat.percent) >= LOG_MEMORY_PERCENT_THRESHOLD) {\n Debug.debug(`Memory usage: ${memoryPercent}% (${memoryMiB} MiB)`);\n this._lastMemoryStat.percent = memoryPercent;\n this._lastMemoryStat.bytes = memory.usedJSHeapSize;\n }\n }\n}\n", "import Params from '../static/Params';\nimport WebRTCUtils from '../static/WebRTCUtils';\n\nconst AUDIO_FREQUENCY = 44100;\n\nexport type VolumeLevel = {\n real: number;\n smoothed: number;\n};\n\nexport class VolumeDetector {\n private _analyser: AnalyserNode | null = null;\n private _gainNode: GainNode | null = null;\n private _fftBins: Uint8Array | null = null;\n private _mediaStreamSource: MediaStreamAudioSourceNode | null = null;\n private _lastSmoothedLevel = 0;\n private readonly _trackId: string;\n private readonly _track: MediaStreamTrack;\n private readonly _stream: MediaStream;\n\n constructor(id: string, track: MediaStreamTrack) {\n this._trackId = id;\n this._track = track;\n this._stream = new MediaStream([track]);\n\n try {\n const audioContext = WebRTCUtils.getAudioContext();\n\n // Без GainNode на фоновой вкладке в сафари перестает работать AnalyserNode\n // Чтобы работало, нужно выводить куда-то звук\n // Выводим его в условную тишину\n this._gainNode = audioContext.createGain();\n this._gainNode.gain.value = 0.00001;\n this._gainNode.connect(audioContext.destination);\n\n this._analyser = audioContext.createAnalyser();\n this._analyser.fftSize = 1024;\n this._analyser.smoothingTimeConstant = 0; // Сгладим сами в getLevel\n this._analyser.connect(this._gainNode);\n\n this._fftBins = new Uint8Array(this._analyser.frequencyBinCount);\n\n this._mediaStreamSource = audioContext.createMediaStreamSource(this._stream);\n this._mediaStreamSource.connect(this._analyser);\n } catch (e) {\n // Не поддерживается\n }\n }\n\n get track() {\n return this._track;\n }\n\n get trackId() {\n return this._trackId;\n }\n\n private _getBins(): Uint8Array {\n if (!this._fftBins || !this._analyser) {\n return new Uint8Array();\n }\n\n this._analyser.getByteFrequencyData(this._fftBins);\n\n const binFreqSize = AUDIO_FREQUENCY / this._fftBins.length,\n start = Math.ceil(Params.voiceParams.minFreq / binFreqSize),\n end = Math.floor(Params.voiceParams.maxFreq / binFreqSize);\n\n return this._fftBins.subarray(start, end);\n }\n\n getLevel(): VolumeLevel {\n const bins = this._getBins();\n const avg =\n bins.reduce((a, b) => {\n return a + b;\n }, 0) / bins.length;\n const real = avg / 255;\n // @see https://webaudio.github.io/web-audio-api/#smoothing-over-time\n const smoothed = this._lastSmoothedLevel * Params.voiceParams.smoothing + real * (1 - Params.voiceParams.smoothing);\n this._lastSmoothedLevel = smoothed;\n\n return { real, smoothed };\n }\n\n destroy() {\n if (this._mediaStreamSource) {\n this._mediaStreamSource.disconnect();\n this._mediaStreamSource = null;\n }\n if (this._gainNode) {\n this._gainNode.disconnect();\n this._gainNode = null;\n }\n if (this._analyser) {\n this._analyser.disconnect();\n this._analyser = null;\n this._fftBins = null;\n this._lastSmoothedLevel = 0;\n }\n this._stream.removeTrack(this._track);\n }\n}\n", "import External from '../static/External';\nimport Params from '../static/Params';\nimport MediaSettings from '../types/MediaSettings';\nimport EventEmitter from './EventEmitter';\nimport { MediaSource, MediaSourceEvent, MediaTrackKind } from './MediaSource';\nimport { VolumeDetector } from './VolumeDetector';\n\nexport default class LocalVolumeDetector extends EventEmitter {\n private _detector: VolumeDetector | null = null;\n private _interval: number | null = null;\n\n constructor(mediaSource: MediaSource) {\n super();\n\n const timer = () => {\n if (this._detector) {\n External.onLocalVolume(this._detector.getLevel().real, mediaSource.getMediaSettings().isAudioEnabled);\n }\n this._interval = window.setTimeout(timer, Params.voiceParams.interval);\n };\n this._interval = window.setTimeout(timer, Params.voiceParams.interval);\n\n const reinit = () => {\n const track = mediaSource.getSendAudioTrack();\n if (track) {\n this.init(track);\n }\n };\n\n this.subscribe(mediaSource, MediaSourceEvent.SOURCE_CHANGED, (data: { kind: MediaTrackKind }) => {\n if (data.kind === MediaTrackKind.audio && mediaSource.getMediaSettings().isAudioEnabled) {\n reinit();\n }\n });\n this.subscribe(mediaSource, MediaSourceEvent.SOURCE_READY, reinit);\n reinit();\n }\n\n private init(track: MediaStreamTrack) {\n this._stopDetector();\n // NB: Здесь остается ссылка на клонированный трек, даже если выключить микрофон\n this._detector = new VolumeDetector('local', track.clone());\n }\n\n private _stopDetector() {\n if (this._detector) {\n this._detector.track.stop();\n this._detector.destroy();\n this._detector = null;\n }\n }\n\n destroy() {\n this.unsubscribe();\n if (this._interval) {\n window.clearTimeout(this._interval);\n this._interval = null;\n }\n this._stopDetector();\n }\n}\n", "import Debug from '../static/Debug';\nimport SignalingMessage from '../types/SignalingMessage';\n\nexport class SignalingActor {\n private queue: SignalingMessage[] = [];\n private isProcessing = false;\n\n public constructor(private processor: (message: SignalingMessage) => Promise<unknown> | unknown) {}\n\n public add(message: SignalingMessage) {\n this.queue.push(message);\n this.processQueue();\n }\n\n private async processQueue() {\n if (this.isProcessing) {\n return;\n }\n\n this.isProcessing = true;\n\n while (this.queue.length) {\n const message = this.queue.shift();\n if (!message) {\n continue;\n }\n\n try {\n await this.processor(message);\n } catch (e) {\n Debug.error(`Can't process message ${JSON.stringify(message)}`);\n }\n }\n\n this.isProcessing = false;\n }\n}\n", "import TrackId from '../enums/TrackId';\nimport Params from '../static/Params';\nimport { ParticipantId } from '../types/Participant';\nimport EventEmitter from './EventEmitter';\nimport { MediaTrackKind } from './MediaSource';\nimport { Transport, TransportEvent, TransportTopology } from './transport/Transport';\nimport { VolumeDetector, VolumeLevel } from './VolumeDetector';\n\nexport const enum VolumesDetectorEvent {\n VOLUMES_DETECTED = 'VOLUMES_DETECTED',\n}\n\nexport class VolumesDetector extends EventEmitter {\n private _detector: VolumeDetector | null = null;\n private _interval: number | null = null;\n private _activeParticipants: ParticipantId[] | null;\n private _removedParticipants: ParticipantId[] | null;\n\n constructor(transport: Transport) {\n super();\n\n this.subscribe(transport, TransportEvent.REMOTE_TRACK_ADDED, this._onRemoteTrackAdded.bind(this));\n this.subscribe(transport, TransportEvent.REMOTE_TRACK_REMOVED, this._onRemoteTrackRemoved.bind(this));\n this.subscribe(transport, TransportEvent.SIGNALLED_ACTIVE_PARTICIPANTS, this._onSignalledActiveParticipants.bind(this));\n this.subscribe(transport, TransportEvent.TOPOLOGY_CHANGED, this._onTopologyChanged.bind(this));\n }\n\n destroy() {\n if (this._interval) {\n window.clearTimeout(this._interval);\n this._interval = null;\n }\n\n this.unsubscribe();\n\n this._detector?.destroy();\n this._detector = null;\n }\n\n private _onRemoteTrackAdded(trackId: string, stream: MediaStream, track: MediaStreamTrack) {\n if (track.kind !== MediaTrackKind.audio) {\n return;\n }\n\n // Смена топологии или реконнект - пересоздаём\n this._detector?.destroy();\n this._detector = new VolumeDetector(trackId, track);\n\n if (!this._interval) {\n const inner = () => {\n this._collectVolumes();\n this._interval = window.setTimeout(inner, Params.voiceParams.interval);\n };\n this._interval = window.setTimeout(inner, Params.voiceParams.interval);\n }\n }\n\n private _onRemoteTrackRemoved(participantId: ParticipantId, stream: MediaStream, track: MediaStreamTrack) {\n if (track.kind !== MediaTrackKind.audio) {\n return;\n }\n\n // При реконнекте сначала может добавиться новый трек, а потом удалиться старый\n if (!this._detector || this._detector.track !== track) {\n return;\n }\n\n this._detector.destroy();\n this._detector = null;\n }\n\n private _collectVolumes() {\n if (!this._detector) {\n return;\n }\n\n const volumes: Record<ParticipantId, VolumeLevel> = {};\n const trackId = this._detector.trackId;\n const level = this._detector.getLevel();\n\n // если используется микс - берём признак активности из сигналинга\n // а уровень громкости один для всех, по детекту громкости трека\n if (trackId === TrackId.AUDIO_MIX) {\n if (this._activeParticipants) {\n for (const participantId of this._activeParticipants) {\n volumes[participantId] = level;\n }\n }\n\n // посылаем уровень громкости 0, чтоб сообщить клиенту что кто-то прекратил говорить\n if (this._removedParticipants) {\n for (const participantId of this._removedParticipants) {\n volumes[participantId] = { real: 0, smoothed: 0 };\n }\n this._removedParticipants = null;\n }\n } else {\n volumes[trackId] = level;\n }\n\n this._triggerEvent(VolumesDetectorEvent.VOLUMES_DETECTED, volumes);\n }\n\n private _onSignalledActiveParticipants(participants: ParticipantId[]) {\n // ищем всех удаленных участников\n this._removedParticipants = this._activeParticipants?.filter((participantId) => !participants.includes(participantId)) ?? null;\n this._activeParticipants = participants;\n }\n\n private _onTopologyChanged(topology: TransportTopology) {\n if (topology === TransportTopology.DIRECT) {\n this._activeParticipants = null;\n this._removedParticipants = null;\n }\n }\n}\n", "import Params from '../static/Params';\nimport { ParticipantId } from '../types/Participant';\nimport EventEmitter from './EventEmitter';\nimport { Transport, TransportEvent, TransportTopology } from './transport/Transport';\nimport { VolumeLevel } from './VolumeDetector';\nimport { VolumesDetector, VolumesDetectorEvent } from './VolumesDetector';\n\nexport const enum SpeakerDetectorEvent {\n SPEAKER_CHANGED = 'SPEAKER_CHANGED',\n}\n\nexport class SpeakerDetector extends EventEmitter {\n private _speakerId: ParticipantId | null = null;\n private _serverSideSpeakerDetection = false;\n\n constructor(volumesDetector: VolumesDetector, transport: Transport, topology: TransportTopology) {\n super();\n this._serverSideSpeakerDetection = topology === TransportTopology.SERVER;\n\n this.subscribe(volumesDetector, VolumesDetectorEvent.VOLUMES_DETECTED, this._onVolumesDetected.bind(this));\n this.subscribe(transport, TransportEvent.SIGNALLED_SPEAKER_CHANGED, this._onServerSpeakerChanged.bind(this));\n this.subscribe(transport, TransportEvent.TOPOLOGY_CHANGED, this._onTopologyChanged.bind(this));\n }\n\n destroy() {\n this.unsubscribe();\n }\n\n _onVolumesDetected(volumes: { [key: string]: VolumeLevel }) {\n if (this._serverSideSpeakerDetection) {\n return; // speaker detection provided by server\n }\n\n let max = 0,\n maxId = null;\n\n Object.keys(volumes).forEach((participantId) => {\n const level = volumes[participantId].smoothed;\n if (level > max && level > Params.voiceParams.threshold) {\n max = level;\n maxId = participantId;\n }\n });\n\n if (maxId && maxId !== this._speakerId) {\n const currentSpeakerLevel = this._speakerId && Object.hasOwn(volumes, this._speakerId) ? volumes[this._speakerId].smoothed : 0;\n // Устанавливаем говорящего только если он громче предыдущего в N раз\n if (max > currentSpeakerLevel * Params.voiceParams.speakerLevelMultiplier) {\n this._speakerId = maxId;\n this._triggerEvent(SpeakerDetectorEvent.SPEAKER_CHANGED, maxId);\n }\n }\n }\n\n _onServerSpeakerChanged(speakerId: ParticipantId) {\n if (this._serverSideSpeakerDetection) {\n this._triggerEvent(SpeakerDetectorEvent.SPEAKER_CHANGED, speakerId);\n }\n }\n\n private _onTopologyChanged(topology: TransportTopology) {\n this._serverSideSpeakerDetection = topology === TransportTopology.SERVER;\n }\n}\n", "import StatLog from '../enums/StatLog';\nimport Debug from '../static/Debug';\nimport Params from '../static/Params';\nimport MediaSettings from '../types/MediaSettings';\nimport { Participant, ParticipantId } from '../types/Participant';\nimport EventEmitter from './EventEmitter';\nimport Logger from './Logger';\nimport { Transport, TransportEvent, TransportState } from './transport/Transport';\nimport { VolumeLevel } from './VolumeDetector';\nimport { VolumesDetector, VolumesDetectorEvent } from './VolumesDetector';\n\nexport default class SpecListener extends EventEmitter {\n private _transport: Transport;\n private _volumes: Record<ParticipantId, number> = {};\n private readonly _participants: Record<ParticipantId, Participant> = {};\n private _connectionTimeout = 0;\n private _volumeTimeout = 0;\n\n constructor(transport: Transport, volumesDetector: VolumesDetector, participants: Record<ParticipantId, Participant>) {\n super();\n\n this._transport = transport;\n this._participants = participants;\n\n this.subscribe(transport, TransportEvent.STATE_CHANGED, this._onTransportStateChanged.bind(this));\n this.subscribe(volumesDetector, VolumesDetectorEvent.VOLUMES_DETECTED, this._onVolumesDetected.bind(this));\n }\n\n destroy() {\n this.unsubscribe();\n\n if (this._connectionTimeout) {\n window.clearTimeout(this._connectionTimeout);\n }\n if (this._volumeTimeout) {\n window.clearTimeout(this._volumeTimeout);\n }\n }\n\n onChangeRemoteMediaSettings(participantId: ParticipantId, mediaSettings: MediaSettings) {\n // Participant has muted the mic so to ignore their volume in _onVolumeTimeout we set it to max value\n if (!mediaSettings.isAudioEnabled) {\n this._volumes[participantId] = 1;\n }\n\n // Participant has unmuted the mic so we reset their volume to zero to be able to detect volume absence\n if (mediaSettings.isAudioEnabled) {\n this._volumes[participantId] = 0;\n }\n }\n\n private _onTransportStateChanged(participantIds: ParticipantId[], state: TransportState) {\n if (state === TransportState.OPENED) {\n if (!this._connectionTimeout) {\n this._connectionTimeout = window.setTimeout(this._onConnectionTimeout.bind(this), Params.specListenerParams.connectionTimeout);\n }\n\n if (!this._volumeTimeout) {\n this._volumeTimeout = window.setTimeout(this._onVolumeTimeout.bind(this), Params.specListenerParams.volumeTimeout);\n }\n }\n\n if (state === TransportState.FAILED && this._connectionTimeout) {\n Debug.warn('Transport failed, send callSpecError');\n Logger.log(StatLog.CALL_SPEC_ERROR, `${this._transport.getTopology()}_CONNECTION_TIMEOUT`);\n }\n }\n\n private _onVolumesDetected(volumes: Record<ParticipantId, VolumeLevel>) {\n Object.keys(volumes).forEach((participantId) => {\n this._volumes[participantId] = Math.max(volumes[participantId].real, this._volumes[participantId] || 0);\n });\n }\n\n private _onConnectionTimeout() {\n const notConnected = (state: TransportState) => {\n return state !== TransportState.CONNECTED;\n };\n\n const thereIsNotConnected = () => {\n return Object.values(this._transport.getStates()).filter(notConnected).length > 0;\n };\n\n if (thereIsNotConnected()) {\n Debug.warn('There is not connected transport, send callSpecError');\n Logger.log(StatLog.CALL_SPEC_ERROR, `${this._transport.getTopology()}_CONNECTION_TIMEOUT`);\n }\n\n this._connectionTimeout = 0;\n }\n\n private _onVolumeTimeout() {\n const platforms: string[] = [];\n\n Object.keys(this._volumes).forEach((participantId) => {\n if (this._volumes[participantId] > 0) {\n return;\n }\n\n let platform = 'UNKNOWN';\n const participant = this._participants[participantId];\n if (participant && participant.platform) {\n platform = participant.platform;\n }\n\n if (platforms.indexOf(platform) < 0) {\n platforms.push(platform);\n Logger.log(StatLog.CALL_SPEC_ERROR, `${this._transport.getTopology()}_VOLUME_TIMEOUT_${platform}`);\n }\n });\n\n if (platforms.length) {\n Debug.warn('There is silent participant, send callSpecError');\n }\n\n this._volumeTimeout = 0;\n }\n}\n", "import HangupType from '../../enums/HangupType';\nimport Stat from '../../enums/Stat';\nimport HangupReason from '../HangupReason';\nimport Logger from '../Logger';\nimport { TransportTopology } from '../transport/Transport';\n\n/**\n * Класс для работы с событийными метриками, обертка для правильной отправки событий\n */\nexport class EventMetricsService {\n private static correctHangupReason(hangup: HangupType): string {\n switch (hangup) {\n case HangupType.HUNGUP:\n return 'hangup';\n case HangupType.CANCELED:\n return 'canceled';\n case HangupType.REJECTED:\n return 'rejected';\n case HangupType.BUSY:\n return 'busy';\n case HangupType.FAILED:\n return 'failed';\n case HangupType.MISSED:\n return 'missed';\n case HangupType.ANOTHER_DEVICE:\n return 'another_device';\n case HangupType.REMOVED:\n return 'removed';\n case HangupType.BANNED:\n return 'banned';\n case HangupType.VCHAT_DETAILED_ERROR:\n return 'error';\n default:\n return 'hangup';\n }\n }\n static sendHangupEvent(reason: HangupReason, topology?: TransportTopology) {\n const reasonToSendStat = [\n HangupType.HUNGUP,\n HangupType.CANCELED,\n HangupType.REJECTED,\n HangupType.FAILED,\n HangupType.BUSY,\n HangupType.MISSED,\n HangupType.ANOTHER_DEVICE,\n HangupType.REMOVED,\n HangupType.BANNED,\n HangupType.VCHAT_DETAILED_ERROR,\n ];\n\n if (!reasonToSendStat.includes(reason.hangup)) {\n return;\n }\n\n const errorCode = reason.custom_error?.vchat_detailed_api_error?.code;\n Logger.logClientStats({\n name: Stat.CALL_FINISH,\n reason: EventMetricsService.correctHangupReason(reason.hangup),\n call_topology: topology === TransportTopology.DIRECT ? 'D' : 'S',\n ...(errorCode && { string_value: errorCode }),\n });\n }\n}\n", "import Stat from '../../enums/Stat';\nimport Statistics from '../transport/Statistics';\nimport { TransportTopology } from '../transport/Transport';\nimport { StatAggregator } from './StatAggregator';\n\n/** связанный с операцией `first_media_received` тип логируемого звонка */\nenum ECallType {\n DirectOutgoing = 'direct_outgoing',\n DirectIncoming = 'direct_incoming',\n ServerIncoming = 'server_incoming',\n ServerJoinServer = 'server_join_server',\n ServerChangeTopology = 'server_change_topology',\n}\n\nexport class StatFirstMediaReceived {\n /** уже поставили засечку на приём звонка */\n protected _isCallMarked = false;\n protected _isFinished = false;\n protected _callType: ECallType | null = null;\n\n markAcceptCall(topology: TransportTopology) {\n this.mark(topology === TransportTopology.DIRECT ? ECallType.DirectIncoming : ECallType.ServerIncoming);\n }\n\n markAcceptedCall(topology?: TransportTopology) {\n if (topology !== TransportTopology.DIRECT) {\n return;\n }\n this.mark(ECallType.DirectOutgoing);\n }\n\n markParticipantJoined(topology: TransportTopology) {\n if (topology !== TransportTopology.DIRECT) {\n return;\n }\n this.mark(ECallType.ServerChangeTopology);\n }\n\n markOnJoin(topology: TransportTopology) {\n if (topology !== TransportTopology.SERVER) {\n return;\n }\n this.mark(ECallType.ServerJoinServer);\n }\n\n private mark(callType: ECallType) {\n if (!this._isCallMarked) {\n this._isCallMarked = true;\n\n this._callType = callType;\n Statistics.setMark(Stat.FIRST_MEDIA_RECEIVED);\n }\n }\n\n measure() {\n if (!this._isFinished) {\n this._isFinished = true;\n\n if (this._callType) {\n StatAggregator.logEventualStat({ name: Stat.FIRST_MEDIA_RECEIVED, call_type: this._callType });\n }\n }\n }\n}\n", "import type { IEffect } from '@vkontakte/calls-video-effects';\nimport type { AnimojiError, RGBTuple } from '@vkontakte/calls-vmoji';\nimport BaseApi from '../abstract/BaseApi';\nimport BaseLogger from '../abstract/BaseLogger';\nimport BaseSignaling, { AddParticipantParams } from '../abstract/BaseSignaling';\nimport { MAIN_ROOM_ID } from '../constants/Rooms';\nimport Signaling from '../default/Signaling';\nimport CallDirection from '../enums/CallDirection';\nimport CallType from '../enums/CallType';\nimport ChatRoomEventType from '../enums/ChatRoomEventType';\nimport ConversationFeature from '../enums/ConversationFeature';\nimport ConversationOption, { applyOptionChanges, compareOptions } from '../enums/ConversationOption';\nimport FatalError from '../enums/FatalError';\nimport HangupType from '../enums/HangupType';\nimport MediaOption from '../enums/MediaOption';\nimport MuteState from '../enums/MuteState';\nimport ParticipantState from '../enums/ParticipantState';\nimport RoomsEventType from '../enums/RoomsEventType';\nimport SignalingConnectionType from '../enums/SignalingConnectionType';\nimport SignalingEvent from '../enums/SignalingEvent';\nimport SignalingNotification from '../enums/SignalingNotification';\nimport Stat from '../enums/Stat';\nimport StatLog from '../enums/StatLog';\nimport TrackId from '../enums/TrackId';\nimport UpdateDisplayLayoutErrorReason, { getUpdateDisplayLayoutErrorReasonByCode } from '../enums/UpdateDisplayLayoutErrorReason';\nimport UserRole, { compareUserRoles } from '../enums/UserRole';\nimport UserType from '../enums/UserType';\nimport { ConversationDebugLogger } from '../static/ConversationDebugLogger';\nimport Debug from '../static/Debug';\nimport External, { ParticipantStatus } from '../static/External';\nimport { JSONObject } from '../static/Json';\nimport Params from '../static/Params';\nimport { SignalingCapabilities } from '../static/SignalingCapabilities';\nimport Utils from '../static/Utils';\nimport WebRTCUtils from '../static/WebRTCUtils';\nimport { AsrTranscription, IAsrStartParams, IAsrStopParams } from '../types/Asr';\nimport { AudienceModeHandsResponse } from '../types/AudienceMode';\nimport { ConversationData, ConversationOnStartParams, StartConversationParams } from '../types/Conversation';\nimport { IFeaturesPerRole } from '../types/ConversationFeature';\nimport ConversationParams, { ExternalConversationParams } from '../types/ConversationParams';\nimport ConversationResponse from '../types/ConversationResponse';\nimport {\n ExternalId,\n ExternalIdUtils,\n ExternalParticipant,\n ExternalParticipantId,\n ExternalParticipantListChunk,\n ExternalParticipantListMarkers,\n ExternalUserId,\n} from '../types/ExternalId';\nimport type { FastStartResponse, InternalCallerParams, InternalParams } from '../types/FastStart';\nimport { IFeedbackExternal } from '../types/Feedback';\nimport IceServer from '../types/IceServer';\nimport { isStopStreaming } from '../types/LayoutUtils';\nimport MediaModifiers from '../types/MediaModifiers';\nimport MediaSettings, { compareMediaSettings, createMediaSettingsWithDefaults, IVideoDimentions } from '../types/MediaSettings';\nimport { IAddMovieParams, IOnRemoteMovieData, ISharedMovieInfo, ISharedMovieStoppedInfo, IUpdateMovieData } from '../types/MovieShare';\nimport MuteStates from '../types/MuteStates';\nimport {\n CompositeUserId,\n IGetParticipantsParameters,\n OkUserId,\n Participant,\n ParticipantId,\n ParticipantListMarker,\n ParticipantListMarkers,\n ParticipantListType,\n ParticipantsStateList,\n ParticipantStateData,\n ParticipantStateMapped,\n} from '../types/Participant';\nimport { ParticipantLayout, RequestKeyFrame, StopStream } from '../types/ParticipantLayout';\nimport { ParticipantListChunkParameters } from '../types/ParticipantListChunk';\nimport ParticipantPriority from '../types/ParticipantPriority';\nimport {\n MediaType,\n parseParticipantStreamDescription,\n ParticipantStreamDescription,\n serializeParticipantStreamDescription,\n StreamDescriptionString,\n} from '../types/ParticipantStreamDescription';\nimport { IRoomId, Room, RoomParticipantUpdate, Rooms, RoomsUpdate } from '../types/Room';\nimport { ScreenCaptureSettings } from '../types/ScreenCaptureSettings';\nimport ServerSettings, { createEmptyServerSettings, merge } from '../types/ServerSettings';\nimport SignalingMessage, { GetRoomsSignalingResponse, RecordInfo } from '../types/SignalingMessage';\nimport { StatResult } from '../types/Statistics';\nimport { IStartStreamData } from '../types/Streams';\nimport { WaitingHallResponse, waitingParticipantIdFromString, waitingParticipantIdToString } from '../types/WaitingHall';\nimport { extractConnectionMuteStates, filterReconnectedConversationMuteStates, filterReconnectedParticipantMuteStates, getMediaOptionsByMuteState } from '../utils/Conversation';\nimport { lz4Decompress } from '../utils/Lz4';\nimport AudioFix from './AudioFix';\nimport AudioOutput from './AudioOutput';\nimport DebugInfo from './DebugInfo';\nimport EventEmitter from './EventEmitter';\nimport HangupReason from './HangupReason';\nimport { LocalNetworkRating } from './LocalNetworkRating';\nimport LocalVolumeDetector from './LocalVolumeDetector';\nimport Logger from './Logger';\nimport { MediaSource, MediaSourceEvent, MediaTrackKind } from './MediaSource';\nimport { SignalingActor } from './SignalingActor';\nimport { SpeakerDetector, SpeakerDetectorEvent } from './SpeakerDetector';\nimport SpecListener from './SpecListener';\nimport { CodecStatsAggregator } from './stat/CodecStatsAggregator';\nimport { EventMetricsService } from './stat/EventMetricsService';\nimport { StatAggregator } from './stat/StatAggregator';\nimport { StatFirstMediaReceived } from './stat/StatFirstMediaReceived';\nimport { StatPings } from './stat/StatPings';\nimport { StatSignalingCommands } from './stat/StatSignalingCommands';\nimport Statistics from './transport/Statistics';\nimport { Transport, TransportEvent, TransportState, TransportTopology } from './transport/Transport';\nimport { VolumeLevel } from './VolumeDetector';\nimport { VolumesDetector, VolumesDetectorEvent } from './VolumesDetector';\n\nconst COOLDOWN_QUEUE_CLEANUP_INTERVAL_MILLIS = 1000;\nconst COOLDOWN_QUEUE_EXPIRY_INTERVAL_MILLIS = 10000;\n\nconst enum ConversationState {\n IDLE = 'IDLE',\n PROCESSING = 'PROCESSING',\n ACTIVE = 'ACTIVE',\n CLOSE = 'CLOSE',\n}\n\nconst MAX_DEVICE_IDX = 15;\n\nexport default class Conversation extends EventEmitter {\n private readonly _api: BaseApi;\n private readonly _signaling: BaseSignaling;\n private readonly _signalingActor: SignalingActor;\n\n private _mediaSource: MediaSource | null = null;\n private _conversation: ConversationData | null = null;\n private _myLastRequestedLayouts: { [key: StreamDescriptionString]: ParticipantLayout } = {};\n\n private _state: ConversationState = ConversationState.IDLE;\n private _participantState: ParticipantState = ParticipantState.CALLED;\n\n private _participants: Record<ParticipantId, Participant> = {};\n private _pendingParticipants: Map<ParticipantId, Promise<Participant>> = new Map();\n\n private _transport: Transport | null = null;\n private _debugInfo: DebugInfo | null = null;\n\n private _volumesDetector: VolumesDetector | null = null;\n private _speakerDetector: SpeakerDetector | null = null;\n private _localVolumeDetector: LocalVolumeDetector | null = null;\n private _specListener: SpecListener | null = null;\n private _activeSpeakerId: ParticipantId | null = null;\n private _lastSignalledActiveSpeakerId: ParticipantId | null = null;\n\n private _isRealTimeAsrRequested = false;\n\n private _serverSettings: ServerSettings = createEmptyServerSettings();\n\n private static _current: Conversation | null;\n private static _activationMutex: boolean;\n private static _delayedHangup = false;\n\n private readonly _onUnload: () => void;\n\n private readonly _audioOutput: AudioOutput;\n\n private _lastStalled: Record<ParticipantId, boolean> = {};\n private _audioMixStalled = false;\n private _audioFix: AudioFix | null = null;\n\n // participant-agnostic tracks data structures\n private _streamByStreamId: Map<string, MediaStream> = new Map<string, MediaStream>();\n private _streamIdByStreamDescription: Map<StreamDescriptionString, string | null> = new Map<StreamDescriptionString, string | null>();\n private _streamWaitTimerByStreamDescription: Map<StreamDescriptionString, number> = new Map<StreamDescriptionString, number>();\n private _sequenceNumberByStreamDescription: Map<StreamDescriptionString, number> = new Map<StreamDescriptionString, number>();\n private _cooldownTimestampByStreamDescription: Map<StreamDescriptionString, number> = new Map<StreamDescriptionString, number>();\n private _cooldownQueueCleanupTimer: number | null = null;\n\n private readonly _statFirstMediaReceived: StatFirstMediaReceived;\n\n constructor(api: BaseApi, externalLogger: BaseLogger | null) {\n super();\n Logger.create(api, externalLogger);\n Logger.setConversationIdProvider(() => this._conversation?.id || null);\n\n StatAggregator.create();\n CodecStatsAggregator.create(() => this._transport?.getTopology());\n StatPings.create();\n StatSignalingCommands.create();\n\n this._api = api;\n this._signaling = new Signaling();\n this._signalingActor = new SignalingActor(this._onSignalingNotification.bind(this));\n\n this._onUnload = () => {\n if (this._conversation && this._api) {\n this._api.hangupConversation(this._conversation.id, this._state === ConversationState.IDLE ? HangupType.CANCELED : HangupType.HUNGUP);\n if (Params.clientEventsLoggingEnabled) {\n Logger.logClientEvent(\n {\n event_type: Stat.CALL_DECLINED_OR_HANGED_LOCALLY,\n reason: 'none',\n },\n true,\n );\n }\n }\n Logger.destroy();\n StatAggregator.destroy();\n CodecStatsAggregator.destroy();\n StatPings.destroy();\n StatSignalingCommands.destroy();\n };\n window.addEventListener('unload', this._onUnload);\n\n this._statFirstMediaReceived = new StatFirstMediaReceived();\n this._audioOutput = new AudioOutput(this._statFirstMediaReceived);\n\n if (Params.videoTracksCount > 0) {\n this._cooldownQueueCleanupTimer = window.setInterval(this._cleanupCooldownQueue.bind(this), COOLDOWN_QUEUE_CLEANUP_INTERVAL_MILLIS);\n }\n }\n\n static current(): Conversation | null {\n return Conversation._current;\n }\n\n static hangupAfterInit(): void {\n if (Conversation._activationMutex && !Conversation._current) {\n Conversation._delayedHangup = true;\n }\n }\n\n static id(): string | null {\n return Conversation._current?._conversation?.id || null;\n }\n\n async onStart({\n opponentIds,\n opponentType,\n mediaOptions,\n payload = '',\n joiningAllowed = false,\n requireAuthToJoin = false,\n onlyAdminCanShareMovie,\n externalIds,\n onFastStart,\n }: ConversationOnStartParams) {\n if (Conversation._activationMutex) {\n Logger.log(StatLog.ERROR, 'startCall');\n Debug.warn('Conversation: there is already running activation');\n throw new HangupReason(HangupType.FAILED);\n }\n\n const startedTime = Date.now();\n\n Conversation._activationMutex = true;\n ConversationDebugLogger.startSession();\n\n try {\n this._mediaSource = this._createMediaSource();\n await this._mediaSource.request(mediaOptions);\n\n const mediaSettings = this._mediaSource.getMediaSettings();\n\n if (opponentType === CallType.CHAT || (opponentIds && opponentIds.length > 1)) {\n this._logWithMediaSettings(StatLog.OUTGOING_MULTIPARTY_CALL, mediaSettings);\n } else {\n this._logWithMediaSettings(StatLog.OUTGOING_CALL, mediaSettings);\n }\n\n const connection = await this._startConversation({\n opponentIds,\n opponentType,\n direction: CallDirection.OUTGOING,\n mediaOptions,\n payload,\n joiningAllowed,\n requireAuthToJoin,\n onlyAdminCanShareMovie,\n externalIds,\n startedTime,\n onFastStart,\n });\n\n if (!this._conversation) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n this._participantState = ParticipantState.ACCEPTED;\n\n // Высылаем актуальные медиасеттинги\n this._changeMediaSettings(mediaSettings);\n\n await this._processConnection(connection);\n\n await this._allocateTransport();\n this._createSpeakerDetector();\n await this._createSpecListener();\n\n this._signaling.readyToSend();\n\n // проверяем, не сбросил ли вдруг пользователь звонок\n if (Conversation._delayedHangup) {\n throw new HangupReason(HangupType.CANCELED);\n }\n\n Debug.debug('Outgoing call', { opponentIds, opponentType, mediaOptions });\n\n await this._processConnectionSharedMovieInfo(connection);\n await this._processConversationUrlSharingInfo(connection);\n External.onLocalStream(this._mediaSource.getStream(), this._mediaSource.getMediaSettings());\n External.onConversation(this._conversation.externalId, this._conversation.mediaModifiers, this._getMuteStatesForCurrentRoom(), await this._getMainRoomParticipants());\n await this._onConversationParticipantListChunk(connection);\n await this._processPinnedParticipants(connection);\n External.onLocalStatus(ParticipantStatus.WAITING);\n\n this._toggleJoinAvailability();\n this._changeFeatureSet();\n this._changeNeedRate();\n\n Conversation._current = this;\n\n if (this._conversation.concurrent) {\n await this._acceptConcurrent();\n }\n\n return this._conversation;\n } catch (error: any) {\n this._close(error, 'Unable to start conversation');\n throw error;\n } finally {\n Conversation._activationMutex = false;\n }\n }\n\n async onJoin(joinArgs: { conversationId?: string; mediaOptions: MediaOption[]; chatId?: string; joinLink?: string; observedIds?: ExternalUserId[]; payload?: string }) {\n if (Conversation._activationMutex) {\n Logger.log(StatLog.ERROR, 'joinCall');\n Debug.warn('Conversation: there is already running activation');\n throw new HangupReason(HangupType.FAILED);\n }\n\n const startedTime = Date.now();\n\n Conversation._activationMutex = true;\n this._state = ConversationState.PROCESSING;\n ConversationDebugLogger.startSession();\n\n try {\n const observer = !!joinArgs.observedIds?.length;\n if (observer && Params.videoTracksCount > 0) {\n Debug.error('Observer mode: please set videoTracksCount=0');\n throw new HangupReason(HangupType.UNSUPPORTED);\n }\n\n this._mediaSource = this._createMediaSource();\n await this._mediaSource.request(joinArgs.mediaOptions, !observer);\n\n const mediaSettings = this._mediaSource.getMediaSettings();\n this._logWithMediaSettings(StatLog.JOIN_CONVERSATION, mediaSettings);\n\n const connection = await this._joinConversation(joinArgs, startedTime);\n\n if (!this._conversation) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n this._conversation.observer = observer;\n\n External.onLocalStream(this._mediaSource.getStream(), mediaSettings);\n\n if (this._conversation.waitForAdmin || this._conversation.waitingHall) {\n Debug.log(this._conversation.waitForAdmin ? 'Wait for admin' : 'In waiting hall');\n\n Conversation._current = this;\n\n Conversation._activationMutex = false;\n\n this._signaling.readyToSend();\n External.onLocalStatus(this._conversation.waitForAdmin ? ParticipantStatus.WAIT_FOR_ADMIN : ParticipantStatus.WAITING_HALL);\n\n return this._conversation;\n }\n\n return this._onJoinPart2(connection);\n } catch (error: any) {\n Conversation._activationMutex = false;\n this._close(error, 'Unable to join conversation');\n throw error;\n }\n }\n\n private async _onJoinPart2(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n Debug.debug('Join conversation part 2');\n Conversation._activationMutex = true;\n\n try {\n this._participantState = ParticipantState.ACCEPTED;\n\n if (!this._conversation || !this._mediaSource) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n this._statFirstMediaReceived.markOnJoin(this._conversation.topology);\n\n // Высылаем актуальные медиасеттинги\n if (!this._conversation.observer && !this._isAudienceModeListener()) {\n this._changeMediaSettings(this._mediaSource.getMediaSettings());\n }\n\n await this._processConnection(connection);\n\n await this._allocateTransport();\n this._createSpeakerDetector();\n await this._createSpecListener();\n\n this._signaling.readyToSend();\n\n if (this._state === ConversationState.CLOSE) {\n // Возможно, звонок уже завершился\n return this._conversation;\n }\n\n // проверяем, не сбросил ли вдруг пользователь звонок\n if (Conversation._delayedHangup) {\n throw new HangupReason(HangupType.CANCELED);\n }\n\n await this._processConnectionSharedMovieInfo(connection);\n await this._processConversationUrlSharingInfo(connection);\n await this._processConnectionAsrInfo(connection);\n\n const rooms = await this._extractExternalRoomsData(connection.rooms?.rooms, connection.rooms?.roomId);\n\n External.onConversation(\n this._conversation.externalId,\n this._conversation.mediaModifiers,\n this._getMuteStatesForCurrentRoom(),\n await this._getMainRoomParticipants(),\n rooms,\n );\n await this._onConversationParticipantListChunk(connection);\n await this._processPinnedParticipants(connection);\n External.onLocalStatus(ParticipantStatus.WAITING);\n\n this._toggleJoinAvailability();\n this._changeNeedRate();\n\n this._state = ConversationState.ACTIVE;\n this._changeFeatureSet();\n\n Conversation._current = this;\n\n const localParticipant = this._extractLocalParticipantFromConnection(connection);\n if (localParticipant) {\n const newState = Utils.mapParticipantState(localParticipant);\n const isNotEmpty = Object.keys(newState).length > 0;\n // не посылаем никаких сообщений, что не тригерить лишний раз клиент\n if (isNotEmpty) {\n External.onLocalParticipantState(newState);\n }\n }\n\n this._openTransport(Object.values(await this._getParticipants()), false);\n\n return this._conversation;\n } catch (error: any) {\n this._close(error, 'Unable to join conversation');\n throw error;\n } finally {\n Conversation._activationMutex = false;\n }\n }\n\n private async _extractExternalRooms(rooms: SignalingMessage.Room[]): Promise<Room[]> {\n const convertedRequests = rooms.map(this._convertRoomToExternal.bind(this));\n const convertedRooms = await Promise.all(convertedRequests);\n\n return convertedRooms.filter((room): room is Room => !!room);\n }\n\n private async _extractExternalRoomsData(rooms?: SignalingMessage.Room[], roomId?: number): Promise<Rooms | undefined> {\n if (!rooms || !rooms.length) {\n return;\n }\n\n const roomsData: Rooms = {\n rooms: await this._extractExternalRooms(rooms),\n };\n\n if (roomId) {\n roomsData.roomId = roomId;\n }\n\n return roomsData;\n }\n\n async onPush(conversationId: string, type: UserType = UserType.USER, peerId?: number, conversationParams?: string, wsEndpoint?: string) {\n // NB: передача peerId используется в ТамТам, так как мы отдельной командой\n // делаем recover звонка\n if (Conversation._activationMutex) {\n Debug.warn('Conversation: there is already running activation');\n throw new HangupReason(HangupType.REJECTED);\n }\n\n Conversation._activationMutex = true;\n\n try {\n const startTime = Date.now();\n const connection = await this._prepareConversation(conversationId, type, peerId, conversationParams, wsEndpoint);\n this._mediaSource = this._createMediaSource();\n\n if (!this._conversation) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n // Пуш запоздал и кто-то уже взял трубку на другом устройстве - called уже стал accepted - отклоняем\n const called = connection.conversation.participants.find((participant) => {\n return participant.state === ParticipantState.CALLED && participant.id === this._conversation?.userId;\n });\n\n if (!called) {\n Debug.log('Push rejected (there is an active call)');\n Logger.log(StatLog.PUSH, 'rejected');\n throw new HangupReason(HangupType.REJECTED);\n }\n\n ConversationDebugLogger.startSession();\n\n await this._processConnection(connection);\n\n this._extractConnectionUrlSharingInfo(connection);\n await this._allocateTransport();\n this._createSpeakerDetector();\n await this._createSpecListener();\n await this._processPinnedParticipants(connection);\n\n this._signaling.readyToSend();\n this._logCallStartEvent(startTime, CallDirection.INCOMING);\n Logger.log(StatLog.PUSH, 'accepted');\n\n Conversation._current = this;\n\n if (Conversation._delayedHangup) {\n throw new HangupReason(HangupType.CANCELED);\n }\n Conversation._activationMutex = false;\n } catch (error: any) {\n Conversation._activationMutex = false;\n this._close(error, 'Unable to handle inbound call push');\n throw error;\n }\n }\n\n private _isInWaitingHall(connection: SignalingMessage.Connection): boolean {\n if (!connection.conversation) {\n return false;\n }\n\n if (!connection.conversation.options.includes(ConversationOption.WAITING_HALL)) {\n return false;\n }\n\n return this._isRestricted(connection);\n }\n\n private _isWaitForAdmin(connection: SignalingMessage.Connection): boolean {\n if (!connection.conversation) {\n return false;\n }\n\n const waitForAdmin = connection.conversation.options.includes(ConversationOption.WAIT_FOR_ADMIN);\n const adminIsHere = connection.conversation.options.includes(ConversationOption.ADMIN_IS_HERE);\n\n if (!waitForAdmin || (waitForAdmin && adminIsHere)) {\n return false;\n }\n\n return this._isRestricted(connection);\n }\n\n private _isRestricted(connection: SignalingMessage.Connection) {\n const me = (connection.conversation.participants || []).find((participant) => Utils.comparePeerId(participant.peerId as SignalingMessage.PeerId, connection.peerId));\n return (me && me.restricted) || false;\n }\n\n private _isAudienceMode(connection: SignalingMessage.Connection) {\n return connection.conversation?.options?.includes(ConversationOption.AUDIENCE_MODE) || false;\n }\n\n private _isAudienceModeListener() {\n return this._conversation?.audienceMode && this._conversation?.restricted;\n }\n\n private async _acceptConcurrent() {\n if (!this._mediaSource || !this._conversation || !this._transport) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n this._state = ConversationState.PROCESSING;\n\n const mediaSettings = this._mediaSource.getMediaSettings();\n this._logWithMediaSettings(StatLog.ACCEPT_CONCURRENT, mediaSettings);\n Debug.debug('Concurrent call', {\n conversationId: this._conversation.id,\n });\n\n try {\n this._statFirstMediaReceived.markAcceptCall(this._transport.getTopology());\n await this._signaling.acceptCall(this._mediaSource.getMediaSettings());\n External.onCallAccepted();\n\n this._state = ConversationState.ACTIVE;\n this._participantState = ParticipantState.ACCEPTED;\n this._changeFeatureSet();\n\n this._openTransport(Object.values(await this._getParticipants()), true);\n } catch (error: any) {\n this._close(error, 'Unable to accept concurrent call');\n }\n }\n\n private async _getMainRoomParticipants() {\n const participants = await this._getParticipants();\n\n return Utils.mapSharedParticipants(Object.values(participants).filter((participant) => !participant.isInRoom));\n }\n\n private _decodeExternalConversationParams(encodedString: string): ConversationParams {\n const [originalLengthStr, base64Data] = encodedString.split(':');\n const originalLength = parseInt(originalLengthStr, 10);\n\n if (isNaN(originalLength)) {\n throw new Error('Invalid original length in prefix');\n }\n\n const binaryStr = atob(base64Data);\n const compressedBytes = new Uint8Array(binaryStr.length);\n for (let i = 0; i < binaryStr.length; i++) {\n compressedBytes[i] = binaryStr.charCodeAt(i);\n }\n\n try {\n const decompressedBytes = lz4Decompress(compressedBytes, originalLength);\n\n const jsonStr = decompressedBytes.reduce((acc, byte) => {\n acc += String.fromCharCode(byte);\n return acc;\n }, '');\n\n const { srcp, stne, tkn, trne, trnp, trnu, wse, wte } = JSON.parse(jsonStr) as ExternalConversationParams;\n\n return {\n token: tkn,\n endpoint: wse,\n wt_endpoint: wte,\n turn_server: {\n urls: trne.split(','),\n username: trnu,\n credential: trnp,\n },\n stun_server: {\n urls: stne.split(','),\n },\n client_type: srcp,\n };\n } catch (e: any) {\n this._close(e, \"Can't decompress conversation params\");\n throw e;\n }\n }\n\n private _logCallStartEvent(startTime: number, callType: CallDirection) {\n const callTypeMap = {\n [CallDirection.OUTGOING]: 'outgoing',\n [CallDirection.INCOMING]: 'incoming',\n [CallDirection.JOINING]: 'join',\n };\n\n StatAggregator.logEventualStat({\n name: Stat.CALL_START,\n value: Date.now() - startTime,\n string_value: JSON.stringify({ labels: [callTypeMap[callType], 'warmup_start'] }),\n });\n }\n\n async accept(mediaOptions: MediaOption[]) {\n if (this._state !== ConversationState.IDLE) {\n Logger.log(StatLog.ERROR, 'acceptIncoming');\n Debug.error('Unable to accept a call - invalid state');\n throw new Error('Unable to accept a call - invalid state');\n }\n\n if (!this._mediaSource || !this._conversation || !this._transport) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n this._state = ConversationState.PROCESSING;\n\n Debug.debug('Accept incoming call', mediaOptions);\n\n try {\n await this._mediaSource.request(mediaOptions);\n\n const mediaSettings = this._mediaSource.getMediaSettings();\n this._logWithMediaSettings(StatLog.ACCEPT_INCOMING, mediaSettings);\n\n // Высылаем актуальные медиасеттинги\n this._changeMediaSettings(mediaSettings);\n\n this._statFirstMediaReceived.markAcceptCall(this._transport.getTopology());\n await this._signaling.acceptCall(mediaSettings);\n\n this._participantState = ParticipantState.ACCEPTED;\n\n const muteStates = this._getMuteStatesForCurrentRoom();\n const muteMediaOptions = Object.keys(muteStates) as MediaOption[];\n if (muteMediaOptions.length) {\n this._onMuteParticipant({ muteStates, mediaOptions: muteMediaOptions, muteAll: true, stateUpdated: true });\n }\n this._registerParticipantLocalMuteState({ muteStates: this._conversation.muteStatesPersonal });\n\n const roomsResponse = await this._signaling.getRooms(this._isCallAdmin());\n\n if (roomsResponse.rooms?.rooms) {\n const cachedParticipants = await this._getParticipants();\n\n roomsResponse.rooms.rooms.forEach((room) => {\n room.participantIds?.forEach((id) => {\n if (!cachedParticipants[id]) {\n return;\n }\n\n cachedParticipants[id].isInRoom = true;\n });\n });\n }\n\n this._conversation.roomId = roomsResponse.rooms?.roomId || MAIN_ROOM_ID;\n const rooms = await this._extractExternalRoomsData(roomsResponse.rooms?.rooms, roomsResponse.rooms?.roomId);\n\n External.onCallAccepted();\n External.onLocalStream(this._mediaSource.getStream(), mediaSettings);\n External.onConversation(\n this._conversation.externalId,\n this._conversation.mediaModifiers,\n this._getMuteStatesForCurrentRoom(),\n await this._getMainRoomParticipants(),\n rooms,\n );\n if (Params.useParticipantListChunk) {\n const participantListChunk: SignalingMessage.ParticipantListChunk = await this._getInitialParticiapntListChunk();\n const cachedParticipants = await this._getParticipants();\n\n participantListChunk?.participants?.forEach((chunkParticipant) => {\n const participantId = Utils.composeId(chunkParticipant);\n const participant = cachedParticipants[participantId];\n if (participant) {\n participant.movieShareInfos = chunkParticipant.movieShareInfos;\n }\n });\n await this._onConversationParticipantListChunk({ participants: participantListChunk });\n }\n External.onLocalStatus(ParticipantStatus.WAITING);\n\n this._toggleJoinAvailability();\n this._changeNeedRate();\n\n this._state = ConversationState.ACTIVE;\n this._changeFeatureSet();\n this._openTransport(Object.values(await this._getParticipants()), true);\n\n await this._processConversationUrlSharingInfo();\n await this._processConnectionAsrInfo();\n\n return this._conversation;\n } catch (error: any) {\n this._close(error, 'Unable to accept call');\n throw error;\n }\n }\n\n async decline() {\n if (this._state !== ConversationState.IDLE) {\n Logger.log(StatLog.ERROR, 'declineIncoming');\n Debug.error('Unable to decline a call - invalid state');\n throw new Error('Unable to decline a call - invalid state');\n }\n\n this._state = ConversationState.PROCESSING;\n\n Debug.debug('Decline incoming call');\n this._logWithMediaSettings(StatLog.DECLINE_INCOMING, this._mediaSource?.getMediaSettings());\n\n this._participantState = ParticipantState.HUNGUP;\n\n if (this._signaling.ready) {\n await this._signaling.hangup(HangupType.REJECTED);\n }\n\n this._close(new HangupReason(HangupType.REJECTED));\n }\n\n async hangup() {\n Debug.debug('Hangup');\n\n const reason = this._state === ConversationState.ACTIVE ? HangupType.HUNGUP : HangupType.CANCELED;\n\n Logger.log(StatLog.HANGUP, reason);\n\n if (this._signaling.ready) {\n await this._signaling.hangup(reason);\n this._close(new HangupReason(reason));\n } else {\n External.onHangup(new HangupReason(HangupType.HUNGUP), this._conversation && this._conversation.id);\n }\n }\n\n async addParticipant(participantIds: ExternalId[], params?: AddParticipantParams) {\n if (!this._signaling.ready) {\n this._close(new HangupReason(HangupType.UNKNOWN_ERROR), 'Unable to add participant');\n return;\n }\n\n const message = await this._signaling.addParticipant(participantIds.map(ExternalIdUtils.toSignaling), params);\n let error: HangupType | null = null;\n if (message.type === 'error') {\n if (message.error === 'call-unfeasible') {\n error = message.status;\n } else {\n error = HangupType.UNKNOWN_ERROR;\n }\n }\n\n const participantsData: SignalingMessage.Participant[] = message.participants;\n if (!participantsData && message.rejectedParticipants) {\n throw new Error(message.rejectedParticipants[0].reason);\n }\n\n for (const data of participantsData) {\n await this._onAddParticipant(Utils.composeId(data), data, error);\n }\n }\n\n async addParticipantLegacy(participantIds: CompositeUserId[], params?: AddParticipantParams) {\n if (!this._signaling.ready) {\n this._close(new HangupReason(HangupType.UNKNOWN_ERROR), 'Unable to add participant');\n return;\n }\n\n const message = await this._signaling.addParticipantLegacy(participantIds, params);\n let error: HangupType | null = null;\n if (message.type === 'error') {\n if (message.error === 'call-unfeasible') {\n error = message.status;\n } else {\n error = HangupType.UNKNOWN_ERROR;\n }\n }\n\n const participantsData: SignalingMessage.Participant[] = message.participants;\n for (const data of participantsData) {\n await this._onAddParticipant(Utils.composeId(data), data, error);\n }\n }\n\n async removeParticipant(participantId: CompositeUserId, ban = false) {\n if (this._signaling.ready) {\n await this._signaling.removeParticipant(participantId, ban);\n this._onRemoveParticipant(participantId);\n }\n }\n\n setVolume(volume: number) {\n this._audioOutput.volume = volume;\n }\n\n updateStatisticsInterval() {\n if (this._transport) {\n this._transport.updateStatisticsInterval();\n }\n }\n\n private _openTransport(participants: Participant[], isMaster: boolean) {\n if (!this._transport) {\n return; // TODO: throw error?\n }\n\n const needOpen: ParticipantId[] = [];\n\n for (const participant of participants) {\n if (participant.state === ParticipantState.CALLED || participant.state === ParticipantState.ACCEPTED) {\n // Here we allocate transports for those participants\n // which were added after we received inbound call and\n // before we accepted it (see this::_onAddedParticipant).\n if (!this._transport.isAllocated(participant.id)) {\n this._transport.allocate(participant.id, isMaster);\n }\n }\n\n if (participant.state === ParticipantState.ACCEPTED) {\n needOpen.push(participant.id);\n }\n }\n\n if (needOpen.length) {\n this._transport.open(needOpen, null, !!this._conversation?.observer);\n } else if (this._transport.getTopology() === TransportTopology.SERVER) {\n // запускаем транспорт в случае сервера всегда\n this._forceOpenTransportForAloneInCall();\n }\n }\n\n private async _close(reason: HangupReason, errorText?: string) {\n if (errorText) {\n Debug.error(errorText, reason);\n }\n\n Debug.debug('Close conversation', reason);\n\n EventMetricsService.sendHangupEvent(reason, this._transport?.getTopology());\n CodecStatsAggregator.destroy();\n\n StatPings.logMetrics(this._transport?.getTopology());\n StatPings.destroy();\n StatSignalingCommands.logMetrics(this._transport?.getTopology());\n StatSignalingCommands.destroy();\n\n this._signaling.readyToSend(false);\n\n if (!reason.error) {\n Logger.log(StatLog.ERROR, reason.hangup);\n } else if (this._signaling.ready) {\n this._signaling.hangup(HangupType.FAILED);\n }\n\n Conversation._activationMutex = false;\n\n const conversationId = this._conversation && this._conversation.id;\n const failedStart: HangupType[] = [HangupType.CANCELED, HangupType.NOT_FRIENDS, HangupType.CALLEE_IS_OFFLINE, HangupType.CALLER_IS_BLOCKED, HangupType.CALLER_IS_REJECTED];\n\n if (failedStart.indexOf(reason.hangup) !== -1 || (reason.hangup === HangupType.REJECTED && !reason.remote)) {\n External.onHangup(reason, conversationId);\n this.destroy();\n return;\n }\n\n if (reason.hangup === HangupType.HUNGUP && (!reason.remote || this._isCalledState())) {\n External.onHangup(reason, conversationId);\n this.destroy();\n return;\n }\n\n if (reason.hangup === HangupType.MISSED && !reason.remote) {\n External.onHangup(reason, conversationId);\n this.destroy();\n return;\n }\n\n if (this._cooldownQueueCleanupTimer !== null) {\n window.clearInterval(this._cooldownQueueCleanupTimer);\n this._cooldownQueueCleanupTimer = null;\n }\n\n // Пытаемся применить пуш несуществующего звонка во время текущего звонка\n if ((reason.hangup === HangupType.SOCKET_CLOSED || reason.hangup === HangupType.NOT_FOUND) && Conversation._current && !this._conversation) {\n // TODO: Кажется, здесь можно обработать все ошибки применения пуша во время текущего звонка по наличию Conversation._current\n this._cleanupSignaling();\n this._cleanupMediaSource();\n return;\n }\n\n // Пуш существующего звонка во время текущего\n if (reason.hangup === HangupType.BUSY && !reason.remote) {\n this._cleanupSignaling();\n this._cleanupMediaSource();\n return;\n }\n\n this._state = ConversationState.CLOSE;\n this._participantState = ParticipantState.HUNGUP;\n this._changeFeatureSet();\n\n this._cleanupMediaSource();\n await this._cleanupParticipants();\n this._cleanupParticipantAgnosticStreams();\n this._cleanupTransport();\n this._cleanupSpeakerDetector();\n this._cleanupSpecListener();\n this._cleanupSignaling();\n this._api.cleanup();\n\n Logger.destroy();\n StatAggregator.destroy();\n this._conversation = null;\n this._myLastRequestedLayouts = {};\n Conversation._current = null;\n Conversation._delayedHangup = false;\n\n External.onHangup(reason || new HangupReason(HangupType.UNKNOWN_ERROR), conversationId);\n }\n\n async destroy() {\n const conversationId = this._conversation && this._conversation.id;\n\n Debug.debug('Destroy conversation', { conversationId });\n\n if (this._cooldownQueueCleanupTimer !== null) {\n window.clearInterval(this._cooldownQueueCleanupTimer);\n this._cooldownQueueCleanupTimer = null;\n }\n\n this._state = ConversationState.CLOSE;\n this._participantState = ParticipantState.HUNGUP;\n\n this._cleanupMediaSource();\n await this._cleanupParticipants();\n this._cleanupParticipantAgnosticStreams();\n this._cleanupTransport();\n this._cleanupSpeakerDetector();\n this._cleanupSpecListener();\n this._cleanupSignaling();\n this._api.cleanup();\n\n this._cleanupListeners();\n\n Logger.destroy();\n StatAggregator.destroy();\n this._conversation = null;\n this._myLastRequestedLayouts = {};\n Conversation._current = null;\n Conversation._delayedHangup = false;\n }\n\n private async _getConversationParams(conversationId: string): Promise<ConversationParams> {\n const params: ConversationParams = await this._api.getConversationParams(conversationId);\n Debug.debug('Api.getConversationParams', params);\n\n const iceServers: IceServer[] = [];\n const { turn_server, stun_server } = params;\n\n if (stun_server) {\n iceServers.push(stun_server);\n }\n if (turn_server && turn_server.urls) {\n // Иногда приходят несколько одинаковых - отфильтруем\n const urls = turn_server.urls.filter((item, index, arr) => arr.indexOf(item) === index);\n\n // Добавляем TCP TURN серверы на случай, если UDP не работает\n // urls.forEach((url) => urls.push(`${url}?transport=tcp`));\n\n // FF ругается \"Using five or more STUN/TURN servers causes problems\"\n // Не будем добавлять все TURN как TCP, оставим только один последний (!)\n urls.push(`${urls[urls.length - 1]}?transport=tcp`);\n\n // Не мутируем исходный объект\n iceServers.push({\n urls,\n username: turn_server.username,\n credential: turn_server.credential,\n });\n }\n\n Params.iceServers = iceServers;\n Params.wssBase = params.endpoint;\n if (params.wt_endpoint) {\n Params.wtsBase = params.wt_endpoint;\n }\n Params.wssToken = params.token;\n\n if (params.client_type) {\n Params.clientType = params.client_type;\n }\n\n if (params.external_user_type) {\n Params.externalUserType = params.external_user_type;\n }\n\n return params;\n }\n private _setConversationParams({ turn_server, stun_server, endpoint, wt_endpoint, token, client_type }: ConversationParams) {\n const iceServers: IceServer[] = [];\n\n if (stun_server) {\n iceServers.push(stun_server);\n }\n if (turn_server && turn_server.urls) {\n // Иногда приходят несколько одинаковых - отфильтруем\n const urls = turn_server.urls.filter((item, index, arr) => arr.indexOf(item) === index);\n\n // Добавляем TCP TURN серверы на случай, если UDP не работает\n // urls.forEach((url) => urls.push(`${url}?transport=tcp`));\n\n // FF ругается \"Using five or more STUN/TURN servers causes problems\"\n // Не будем добавлять все TURN как TCP, оставим только один последний (!)\n urls.push(`${urls[urls.length - 1]}?transport=tcp`);\n\n // Не мутируем исходный объект\n iceServers.push({\n urls,\n username: turn_server.username,\n credential: turn_server.credential,\n });\n }\n\n Params.iceServers = iceServers;\n Params.wssBase = endpoint;\n Params.wssToken = token;\n\n if (wt_endpoint) {\n Params.wtsBase = wt_endpoint;\n }\n\n if (client_type) {\n Params.clientType = client_type;\n }\n }\n\n private _addGeoParamsToEndpoint(endpoint: string, params: ConversationParams): string {\n if (params.isp_as_no) {\n endpoint += `&ispAsNo=${params.isp_as_no}`;\n }\n if (params.isp_as_org) {\n endpoint += `&ispAsOrg=${params.isp_as_org}`;\n }\n if (params.loc_cc) {\n endpoint += `&locCc=${params.loc_cc}`;\n }\n if (params.loc_reg) {\n endpoint += `&locReg=${params.loc_reg}`;\n }\n return endpoint;\n }\n\n /**\n * @throws ErrorEvent\n */\n private async _startConversation({\n opponentIds,\n opponentType,\n direction,\n mediaOptions,\n payload = '',\n joiningAllowed = false,\n requireAuthToJoin = false,\n onlyAdminCanShareMovie,\n externalIds,\n startedTime,\n onFastStart,\n }: StartConversationParams): Promise<SignalingMessage.Connection> {\n Statistics.setMark(Stat.SIGNALING_CONNECTED);\n const conversationId = Utils.uuid();\n\n Debug.debug('Conversation: start', { conversationId, opponentIds, opponentType, direction });\n\n const isVideo = mediaOptions.includes(MediaOption.VIDEO);\n let conversation: ConversationResponse;\n if (onFastStart) {\n const params: InternalParams = {\n deviceId: this._api.deviceId(),\n sdkVersion: Params.sdkVersion,\n clientAppKey: Params.apiKey,\n platform: Params.platform,\n protocolVersion: Params.protocolVersion,\n domainId: Params.domain,\n capabilities: SignalingCapabilities.getFlags(),\n };\n\n const internalParams = JSON.stringify(params);\n let fastStartResponse: FastStartResponse;\n try {\n fastStartResponse = await onFastStart({\n internalParams,\n conversationId,\n externalIds,\n opponentType,\n mediaOptions,\n isVideo,\n joiningAllowed,\n requireAuthToJoin,\n });\n if (!fastStartResponse.internalCallerParams) {\n throw new HangupReason(HangupType.FAST_START_ERROR, {\n message: JSON.stringify(fastStartResponse),\n });\n }\n } catch (err) {\n if (err instanceof Error) {\n throw new HangupReason(HangupType.FAST_START_ERROR, { message: err.message });\n } else {\n throw new HangupReason(HangupType.FAST_START_ERROR, { message: String(err) });\n }\n }\n\n try {\n const parsedInternalParams: InternalCallerParams = JSON.parse(fastStartResponse.internalCallerParams);\n\n conversation = {\n endpoint: parsedInternalParams.endpoint,\n wt_endpoint: parsedInternalParams.wtEndpoint,\n id: conversationId,\n is_concurrent: parsedInternalParams.isConcurrent,\n client_type: parsedInternalParams.clientType,\n rejected_participants: fastStartResponse.rejectedParticipants?.map((el) => ({ ...el, status: el.status as HangupType })),\n stun_server: parsedInternalParams.stun,\n turn_server: parsedInternalParams.turn,\n token: new URL(parsedInternalParams.endpoint).searchParams.get('token') ?? '',\n };\n Debug.debug('FastStart', conversation);\n } catch (error) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR, {\n message: 'Cannot parse internal params',\n });\n }\n } else {\n conversation = await this._api.startConversation(\n conversationId,\n opponentIds,\n opponentType,\n isVideo,\n payload,\n joiningAllowed,\n requireAuthToJoin,\n { onlyAdminCanShareMovie },\n externalIds,\n );\n Debug.debug('Api.startConversation', conversation);\n }\n\n this._setConversationParams(conversation);\n\n const connection = await this._connectSignaling(SignalingConnectionType.START, conversation);\n\n await this._setConversation(conversation, connection, direction);\n this._logCallStartEvent(startedTime, CallDirection.OUTGOING);\n return connection;\n }\n\n /**\n * @throws ErrorEvent\n */\n private async _joinConversation(\n joinArgs: {\n conversationId?: string;\n mediaOptions: MediaOption[];\n chatId?: string;\n joinLink?: string;\n observedIds?: string[];\n payload?: string;\n },\n startedTime: number,\n ): Promise<SignalingMessage.Connection> {\n Statistics.setMark(Stat.SIGNALING_CONNECTED);\n const { conversationId, mediaOptions, chatId, joinLink, observedIds, payload } = joinArgs;\n Debug.debug('Conversation: join', { conversationId, joinLink, observedIds });\n\n const isVideo = mediaOptions.includes(MediaOption.VIDEO);\n let conversation: ConversationResponse;\n if (conversationId) {\n conversation = await this._api.joinConversation(conversationId, isVideo, chatId);\n } else if (joinLink) {\n conversation = await this._api.joinConversationByLink(joinLink, isVideo, observedIds, payload);\n } else {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n Debug.debug('Api.joinConversation', conversation);\n\n this._setConversationParams(conversation);\n\n const connection = await this._connectSignaling(SignalingConnectionType.JOIN, conversation);\n\n await this._setConversation(conversation, connection, CallDirection.JOINING);\n this._logCallStartEvent(startedTime, CallDirection.JOINING);\n return connection;\n }\n\n /**\n * @throws ErrorEvent\n */\n private async _prepareConversation(\n conversationId: string,\n type: UserType = UserType.USER,\n peerId?: number,\n externalConversationParams?: string,\n wsEndpoint?: string,\n ): Promise<SignalingMessage.Connection> {\n Statistics.setMark(Stat.SIGNALING_CONNECTED);\n Debug.debug('Conversation: push', { conversationId, type, peerId });\n\n const userId = this._api.getUserId();\n if (!userId) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n let deviceIdx = 0;\n let endpoint = '';\n let wtEndpoint = '';\n\n const conversation: ConversationResponse = {\n id: conversationId,\n peerId,\n endpoint,\n wt_endpoint: wtEndpoint,\n is_concurrent: false,\n p2p_forbidden: false,\n device_idx: 0,\n token: '',\n };\n\n if (externalConversationParams) {\n const params = this._decodeExternalConversationParams(externalConversationParams);\n this._setConversationParams(params);\n endpoint = wsEndpoint ?? `${Params.wssBase}?userId=${userId}&entityType=${type}&deviceIdx=${deviceIdx}&conversationId=${conversationId}&token=${Params.wssToken}`;\n\n conversation.token = params.token;\n conversation.endpoint = endpoint;\n\n if (Params.wtsBase) {\n wtEndpoint = `${Params.wtsBase}?userId=${userId}&entityType=${type}&deviceIdx=${deviceIdx}&conversationId=${conversationId}&token=${Params.wssToken}`;\n conversation.wt_endpoint = wtEndpoint;\n }\n } else {\n const params = await this._getConversationParams(conversationId);\n deviceIdx = params.device_idx || 0;\n endpoint = wsEndpoint ?? `${Params.wssBase}?userId=${userId}&entityType=${type}&deviceIdx=${deviceIdx}&conversationId=${conversationId}&token=${Params.wssToken}`;\n endpoint = this._addGeoParamsToEndpoint(endpoint, params);\n\n conversation.token = params.token;\n conversation.endpoint = endpoint;\n conversation.device_idx = deviceIdx;\n\n if (Params.wtsBase) {\n wtEndpoint = `${Params.wtsBase}?userId=${userId}&entityType=${type}&deviceIdx=${deviceIdx}&conversationId=${conversationId}&token=${Params.wssToken}`;\n wtEndpoint = this._addGeoParamsToEndpoint(wtEndpoint, params);\n conversation.wt_endpoint = wtEndpoint;\n }\n }\n\n const connection = await this._connectSignaling(SignalingConnectionType.ACCEPT, conversation);\n\n if (\n Conversation._current &&\n (Conversation._current._participantState === ParticipantState.ACCEPTED || Conversation._current._participantState === ParticipantState.CALLED)\n ) {\n Debug.log('Push rejected (busy)');\n Logger.log(StatLog.PUSH, 'busy');\n if (this._signaling.ready) {\n this._signaling.hangup(HangupType.BUSY);\n }\n return Promise.reject(new HangupReason(HangupType.BUSY));\n }\n\n if (Conversation._current) {\n Conversation._current.destroy();\n Conversation._current = null;\n }\n\n await this._setConversation(conversation, connection, CallDirection.INCOMING, type);\n return connection;\n }\n\n private async _createParticipant(properties: Partial<Participant>, decorativeId?: CompositeUserId): Promise<Participant> {\n const participant: Participant = Object.assign(\n {\n id: null,\n externalId: null,\n mediaSettings: createMediaSettingsWithDefaults(),\n participantState: {},\n state: ParticipantState.CALLED,\n status: null,\n remoteStream: null,\n mediaSource: null,\n platform: null,\n clientType: null,\n roles: [],\n networkRating: 1,\n lastRequestedLayouts: {},\n muteStates: {},\n unmuteOptions: [],\n observedIds: [],\n isInRoom: false,\n markers: null,\n },\n properties,\n );\n\n if (!participant.externalId) {\n participant.externalId = await this._getParticipantId(decorativeId ?? participant.id);\n }\n\n this._api.cacheExternalId(decorativeId ?? participant.id, participant.externalId);\n\n if (decorativeId) {\n this._api.mapDecorativeId(decorativeId, participant.id);\n }\n\n if (participant.observedIds?.length) {\n participant.externalId.observer = true;\n }\n\n if (properties.markers) {\n participant.markers = this._denormalizeMarkers(participant.id, properties.markers);\n }\n return participant;\n }\n\n private async _getParticipantId(participantId: ParticipantId): Promise<ExternalParticipantId> {\n try {\n return await this._api.userId(participantId);\n } catch (e: any) {\n this._close(new HangupReason(HangupType.NETWORK_ERROR), e);\n throw e;\n }\n }\n\n private async _setConversation(conversation: ConversationResponse, connection: SignalingMessage.Connection, direction: CallDirection, type: UserType = UserType.USER) {\n const { participants } = connection.conversation;\n\n participants.forEach((p) => {\n const composedId = Utils.composeId(p);\n const externalId = ExternalIdUtils.fromSignalingParticipant(p, false);\n if (externalId) {\n this._api.cacheExternalId(composedId, externalId);\n\n const composedDecorativeId = Utils.composeDecorativeId(p);\n const decorativeExternalId = ExternalIdUtils.fromSignalingParticipant(p);\n if (composedDecorativeId && decorativeExternalId) {\n this._api.cacheExternalId(composedDecorativeId, decorativeExternalId);\n this._api.mapDecorativeId(p.decorativeUserId as CompositeUserId, p.id);\n }\n }\n });\n\n let userId = this._api.getUserId();\n const localParticipant = this._extractLocalParticipantFromConnection(connection);\n let deviceIdx = conversation.device_idx || 0;\n\n // В анонимной сеcсии может быть не установлено userId через API\n // Ищем в ответе сигналинга\n if (!userId) {\n if (!localParticipant) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n userId = Number(localParticipant.id);\n if (localParticipant.idType) {\n type = localParticipant.idType;\n }\n if (localParticipant.deviceIdx) {\n deviceIdx = localParticipant.deviceIdx;\n }\n this._api.setUserId(userId);\n }\n\n const compositeUserId = Utils.composeParticipantId(userId, type, deviceIdx);\n\n this._conversation = {\n userId,\n compositeUserId,\n externalId: (await this._getExternalIdByParticipantId(compositeUserId)) as ExternalParticipantId,\n acceptTime: connection.conversation.acceptTime,\n features: connection.conversation.features || [],\n featuresPerRole: connection.conversation.featuresPerRole,\n id: connection.conversation.id || conversation.id,\n participantsLimit: connection.conversation.participantsLimit || 30,\n topology: connection.conversation.topology || TransportTopology.DIRECT,\n direction,\n concurrent: connection.isConcurrent || conversation.is_concurrent || false,\n needRate: false,\n chatId: connection.conversation.multichatId,\n roles: localParticipant?.roles ?? [],\n recordsInfoByRoom: new Map(),\n asrInfoByRoom: new Map(),\n muteStates: new Map(),\n muteStatesPersonal: {},\n joinLink: conversation.join_link ?? connection.conversation.joinLink,\n pinnedParticipantIdByRoom: new Map(),\n mediaModifiers: connection.mediaModifiers,\n options: [], //connection.conversation.options,\n networkRating: 1,\n waitingHall: this._isInWaitingHall(connection),\n waitForAdmin: this._isWaitForAdmin(connection),\n observer: false,\n asrInfo: connection.conversation.asrInfo || null,\n roomId: connection.rooms?.roomId || MAIN_ROOM_ID,\n audienceMode: this._isAudienceMode(connection),\n restricted: this._isRestricted(connection),\n urlSharingInfoByRoom: new Map(),\n };\n\n ConversationDebugLogger.conversationId = connection.conversation.id || conversation.id;\n\n this._signaling.setConversationId(this._conversation.id);\n\n if (conversation.p2p_forbidden) {\n // Устанавливаем, только если включено - иначе оставляем как было\n Params.forceRelayPolicy = conversation.p2p_forbidden;\n }\n Logger.log(StatLog.RELAY_POLICY, Params.forceRelayPolicy ? '1' : '0');\n\n this._changeFeatureSet();\n this._changeFeaturesPerRole();\n this._logDevices();\n }\n\n private _updateConversation(connection: SignalingMessage.PromoteParticipant): void {\n if (!this._conversation) {\n throw new HangupReason(HangupType.UNKNOWN_ERROR);\n }\n\n this._conversation.acceptTime = connection.conversation.acceptTime;\n this._conversation.features = connection.conversation.features || [];\n this._conversation.featuresPerRole = connection.conversation.featuresPerRole;\n this._conversation.participantsLimit = connection.conversation.participantsLimit || 30;\n this._conversation.topology = connection.conversation.topology || TransportTopology.DIRECT;\n this._conversation.concurrent = connection.isConcurrent || false;\n this._conversation.chatId = connection.conversation.multichatId;\n this._conversation.mediaModifiers = connection.mediaModifiers;\n this._conversation.waitingHall = false;\n this._conversation.waitForAdmin = false;\n this._conversation.restricted = false;\n }\n\n private _createMediaSource(): MediaSource {\n const mediaSource = new MediaSource();\n\n this.subscribe(mediaSource, MediaSourceEvent.SOURCE_CHANGED, this._onLocalMediaStreamChanged.bind(this));\n this.subscribe(mediaSource, MediaSourceEvent.SCREEN_STATUS, this._onScreenSharingStatus.bind(this));\n this._audioFix = new AudioFix(mediaSource);\n\n return mediaSource;\n }\n\n private async _connectSignaling(type: SignalingConnectionType, conversation: ConversationResponse): Promise<SignalingMessage.Connection> {\n this._signaling.setEndpoint(conversation.endpoint);\n this._signaling.setWebTransportEndpoint(conversation.wt_endpoint ? conversation.wt_endpoint : null);\n\n this.subscribe(this._signaling, SignalingEvent.NOTIFICATION, (message: SignalingMessage) => this._signalingActor.add(message));\n this.subscribe(this._signaling, SignalingEvent.FAILED, this._onSignalingFailed.bind(this));\n this.subscribe(this._signaling, SignalingEvent.RECONNECT, this._onSignalingReconnect.bind(this));\n\n // Передаём `conversation` в сигналинг, нужен для правильного старта анонимных звонков в ТТ\n const connection = await this._signaling.connect(type, conversation);\n StatAggregator.logEventualStat({ name: Stat.SIGNALING_CONNECTED });\n\n return connection;\n }\n\n private async _processConnection(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n // важно сделать в первую очередь\n await this._registerConnectionParticipants(connection);\n this._processRooms(connection);\n this._processMuteStates(connection);\n this._processRecordInfos(connection);\n this._onOptionsChanged(connection.conversation.options);\n if (connection.chatRoom && connection.chatRoom.totalCount) {\n this._onChatRoomUpdated(ChatRoomEventType.ATTENDEE, connection.chatRoom.totalCount, connection.chatRoom.firstParticipants, null, null);\n }\n }\n\n private async _onConversationParticipantListChunk(connection: Pick<SignalingMessage.Connection | SignalingMessage.PromoteParticipant, 'participants'>) {\n const chunk = connection.participants;\n if (chunk) {\n External.onConversationParticipantListChunk(await this._participantListChunkToExternalChunk(this._createParticipantListChunk(chunk)));\n }\n }\n\n private _createParticipantListChunk(chunk?: Partial<SignalingMessage.ParticipantListChunk>): SignalingMessage.ParticipantListChunk {\n const defaults = { participants: [], countBefore: 0, countAfter: 0, markerFound: false } as SignalingMessage.ParticipantListChunk;\n\n return {\n ...defaults,\n ...chunk,\n };\n }\n\n private async _participantListChunkToExternalChunk(chunk: SignalingMessage.ParticipantListChunk): Promise<ExternalParticipantListChunk> {\n const cachedParticipants = await this._getParticipants();\n\n const externalParticipants = Utils.mapSharedParticipants(\n chunk.participants.reduce<Participant[]>((acc, chunkParticipant) => {\n const participantId = Utils.composeId(chunkParticipant);\n // TODO: Бывает странная ситуация, что в чанке партисипант есть, а в await this._getParticipants() его нет\n if (cachedParticipants[participantId]) {\n acc.push(cachedParticipants[participantId]);\n }\n\n return acc;\n }, []),\n );\n return {\n ...chunk,\n participants: externalParticipants,\n };\n }\n\n private async _registerConnectionParticipants(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n await this._registerParticipants(connection.conversation.participants);\n\n if (connection.participants?.participants) {\n await this._registerParticipants(connection.participants?.participants);\n }\n\n const rooms: SignalingMessage.Room[] = connection?.rooms?.rooms ?? [];\n for (const room of rooms) {\n await this._registerParticipants(room?.participants?.participants ?? [], true);\n }\n }\n\n private async _registerParticipants(participants: SignalingMessage.Participant[], isInRoom = false) {\n if (!this._conversation) {\n return;\n }\n\n const externalUserType = participants[0]?.externalId?.type;\n\n if (externalUserType) {\n Params.externalUserType = externalUserType;\n }\n\n const cachedParticipants = await this._getParticipants();\n\n for (const participant of participants) {\n const participantId = Utils.composeId(participant);\n\n Debug.test('Conversation:RegisterParticipant', participantId);\n\n // Это я\n if (this._isMe(participantId)) {\n this._conversation.roles = participant.roles || [];\n if (this._conversation.roles.length) {\n Debug.debug(`Local roles changed: ${participant.roles}`);\n External.onLocalRolesChanged(this._conversation.roles, true);\n }\n\n // Установим состояние локальных мьютов\n this._registerParticipantLocalMuteState(participant);\n continue;\n }\n\n if (participant.state === ParticipantState.HUNGUP || participant.state === ParticipantState.REJECTED) {\n if (cachedParticipants[participant.id]) {\n await this._removeParticipant(cachedParticipants[participant.id], HangupType.HUNGUP);\n }\n continue;\n }\n\n const decorativeId = Utils.composeDecorativeId(participant);\n this._registerParticipant(\n {\n id: participantId,\n externalId: ExternalIdUtils.fromSignalingParticipant(participant),\n mediaSettings: createMediaSettingsWithDefaults(participant.mediaSettings),\n participantState: Utils.mapParticipantState(participant),\n state: participant.state,\n roles: participant.roles || [],\n status: ParticipantStatus.WAITING,\n muteStates: participant.muteStates || {},\n unmuteOptions: participant.unmuteOptions || [],\n observedIds: participant.observedIds || [],\n markers: this._denormalizeMarkers(participantId, participant.markers),\n movieShareInfos: participant.movieShareInfos,\n isInRoom,\n },\n decorativeId,\n );\n\n // Проставим роли на старте\n\n const cachedParticipant = await this._getParticipant(participantId);\n if (cachedParticipant && participant.roles && participant.roles.length) {\n Debug.debug(`Roles for participant [${participantId}] changed: ${participant.roles}`);\n External.onRolesChanged(cachedParticipant.externalId, participant.roles, true);\n }\n }\n }\n\n /** Установим состояние локальных мьютов */\n private _registerParticipantLocalMuteState({ muteStates, unmuteOptions }: Pick<SignalingMessage.Participant, 'muteStates' | 'unmuteOptions'>) {\n if (!muteStates) {\n return;\n }\n\n const callback = async () => {\n // MUTE и MUTE_PERMANENT нужно разделить, тк их нельзя отправлять одновременно\n const mediaOptionsMute = getMediaOptionsByMuteState(muteStates, MuteState.MUTE);\n const mediaOptionsMutePermanent = getMediaOptionsByMuteState(muteStates, MuteState.MUTE_PERMANENT);\n\n for (const mediaOptions of [mediaOptionsMute, mediaOptionsMutePermanent]) {\n if (!mediaOptions.length) {\n continue;\n }\n await this._onMuteParticipant({ muteStates, unmuteOptions, mediaOptions, stateUpdated: true });\n }\n };\n\n // важно, чтобы локальные были выставлены после выставления глобальных\n Utils.setImmediate(() => callback().catch((e) => Debug.error(e)));\n }\n\n private _getStatusByTransportState(state: TransportState): ParticipantStatus | null {\n let status = null;\n if (state === TransportState.CONNECTED) {\n status = ParticipantStatus.CONNECTED;\n } else if (state === TransportState.CONNECTING || state === TransportState.OPENED) {\n status = ParticipantStatus.CONNECTING;\n } else if (state === TransportState.RECONNECTING) {\n status = ParticipantStatus.RECONNECT;\n }\n return status;\n }\n\n private _registerParticipantInCache(participant: Participant): Participant {\n this._participants[participant.id] = participant;\n return participant;\n }\n\n private async _getExistedParticipantByIdOrCreate(participantId: ParticipantId): Promise<Participant> {\n const cachedParticipants = await this._getParticipants();\n const participant = cachedParticipants[participantId];\n\n if (participant) {\n return participant;\n }\n\n const decorativeOkId = this._api.getDecorativeIdByInitialId(Utils.decomposeId(participantId).id);\n const decorativeId = decorativeOkId ? Utils.composeUserId(decorativeOkId) : undefined;\n return this._createParticipant({ id: participantId }, decorativeId);\n }\n\n private async _getExternalIdByParticipantId(participantId: ParticipantId): Promise<ExternalParticipantId | undefined> {\n if (this._isMe(participantId)) {\n return this._conversation?.externalId;\n }\n\n if (Params.useParticipantListChunk) {\n return (await this._getExistedParticipantByIdOrCreate(participantId)).externalId;\n }\n\n const cachedParticipants = await this._getParticipants();\n\n if (cachedParticipants[participantId]?.externalId) {\n return cachedParticipants[participantId].externalId;\n } else {\n // this._getParticipantId calls this._api.userId, which checks _externalUidsCache\n const externalId = await this._getParticipantId(participantId);\n this._api.cacheExternalId(participantId, externalId);\n return externalId;\n }\n }\n\n private async _registerParticipantAndSetMarkersIfChunkEnabled(participantId: ParticipantId, markers?: ParticipantListMarkers): Promise<Participant | undefined> {\n if (Params.useParticipantListChunk) {\n const participant = this._registerParticipantInCache(await this._getExistedParticipantByIdOrCreate(participantId));\n\n participant.markers = this._denormalizeMarkers(participant.id, markers);\n\n return participant;\n }\n\n const cachedParticipants = await this._getParticipants();\n\n return cachedParticipants[participantId];\n }\n\n private _warnParticipantNotInConversation(participantId: ParticipantId) {\n Debug.warn(`Participant [${participantId}] isn't in conversation`);\n }\n\n private _denormalizeMarkers(participantId: ParticipantId, markers?: ParticipantListMarkers): ExternalParticipantListMarkers | null {\n // To save traffic the server doesn't set `id` to marker\n // so here we decompress markers and set all necessary data\n // We need these data to correctly identify position of participant\n // in the list\n if (!markers) {\n return null;\n }\n\n const baseMarker = Object.values(markers).find((value) => {\n return 'ts' in value && 'rank' in value;\n }) as Required<Pick<ParticipantListMarker, 'ts' | 'rank'>>;\n\n return Object.entries(markers).reduce((externalMarkers, [listType, value]) => {\n externalMarkers[listType as ParticipantListType] = {\n ...baseMarker,\n ...value,\n id: participantId,\n };\n return externalMarkers;\n }, {} as ExternalParticipantListMarkers);\n }\n\n /**\n * Обрабатывает информацию о сессионных залах\n *\n * @param connection\n */\n private _processRooms(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n const roomId = connection.rooms?.roomId ?? MAIN_ROOM_ID;\n\n this._onRoomSwitched(roomId, true);\n }\n\n /** Обрабатывает информацию о мьютах в основном и сессионных залах */\n private _processMuteStates(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant, isReconnect = false) {\n const connectionMuteStates = extractConnectionMuteStates(connection);\n this._setMuteStatesForRoomId(connectionMuteStates, MAIN_ROOM_ID);\n\n for (const room of connection.rooms?.rooms ?? []) {\n this._setMuteStatesForRoomId(room.muteStates, room.id);\n }\n\n let muteStates = this._getMuteStatesForCurrentRoom();\n if (isReconnect) {\n muteStates = filterReconnectedConversationMuteStates(connection, muteStates);\n }\n const mediaOptions = Object.keys(muteStates) as MediaOption[];\n const roomId = this._conversation?.roomId;\n if (mediaOptions.length) {\n this._onMuteParticipant({ muteStates, mediaOptions, muteAll: true, stateUpdated: true, roomId }, isReconnect);\n }\n }\n\n /**\n * Обрабатывает информацию о записи/трансляции в основном и сессионных залах\n * @param connection\n * @private\n * @hidden\n */\n private _processRecordInfos(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n this._onRecordInfo(connection.conversation?.recordInfo ?? null);\n\n for (const room of connection.rooms?.rooms ?? []) {\n this._onRecordInfo(room.recordInfo ?? null, room.id);\n }\n }\n\n /**\n * Обрабатывает информацию об адмниских пинах в основном и сессионных залах\n * @param connection\n * @private\n * @hidden\n */\n private async _processPinnedParticipants(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n if (connection.conversation.pinnedParticipantId) {\n await this._onPinParticipant(connection.conversation.pinnedParticipantId);\n } else {\n this._conversation?.pinnedParticipantIdByRoom.delete(null);\n }\n\n for (const room of connection.rooms?.rooms ?? []) {\n if (room.pinnedParticipantId) {\n await this._onPinParticipant(room.pinnedParticipantId, false, undefined, room.id);\n } else {\n this._conversation?.pinnedParticipantIdByRoom.delete(room.id);\n }\n }\n }\n\n private async _allocateTransport() {\n if (!this._conversation || !this._mediaSource) {\n return;\n }\n\n this._transport = new Transport(this._conversation.topology, this._signaling, this._mediaSource, this._serverSettings);\n this._debugInfo = new DebugInfo();\n\n this.subscribe(this._transport, TransportEvent.STATE_CHANGED, this._onTransportStateChanged.bind(this));\n this.subscribe(this._transport, TransportEvent.LOCAL_STATE_CHANGED, this._onTransportLocalStateChanged.bind(this));\n this.subscribe(this._transport, TransportEvent.REMOTE_TRACK_ADDED, this._onRemoteTrackAdded.bind(this));\n this.subscribe(this._transport, TransportEvent.REMOTE_TRACK_REMOVED, this._onRemoteTrackRemoved.bind(this));\n this.subscribe(this._transport, TransportEvent.AUDIO_MIX_STALL, this._onAudioMixStall.bind(this));\n this.subscribe(this._transport, TransportEvent.REMOTE_DATA_STATS, this._onRemoteDataStats.bind(this));\n this.subscribe(this._transport, TransportEvent.SIGNALLED_STALLED_PARTICIPANTS, this._onRemoteSignalledStall.bind(this));\n this.subscribe(this._transport, TransportEvent.TOPOLOGY_CHANGED, this._onTopologyChanged.bind(this));\n this.subscribe(this._transport, TransportEvent.NETWORK_STATUS, this._onNetworkStatus.bind(this));\n this.subscribe(this._transport, TransportEvent.REMOTE_STREAM_SECOND, this._onRemoteStreamSecond.bind(this));\n this.subscribe(this._transport, TransportEvent.PEER_CONNECTION_CLOSED, this._onPeerConnectionClosed.bind(this));\n this.subscribe(this._transport, TransportEvent.ASR_TRANSCRIPTION, this._onAsrTranscription.bind(this));\n this.subscribe(this._transport, TransportEvent.ANIMOJI_STREAM, this._onAnimojiStream.bind(this));\n this.subscribe(this._transport, TransportEvent.ANIMOJI_ERROR, this._onAnimojiError.bind(this));\n\n const isMaster = this._conversation.direction === CallDirection.OUTGOING && !this._conversation.concurrent;\n\n const cachedParticipnats = await this._getParticipants();\n for (const participant of Object.values(cachedParticipnats)) {\n if (participant.state === ParticipantState.ACCEPTED || participant.state === ParticipantState.CALLED) {\n this._transport.allocate(participant.id, isMaster);\n }\n }\n }\n\n private _createSpeakerDetector() {\n if (this._transport && this._conversation) {\n this._volumesDetector = new VolumesDetector(this._transport);\n this.subscribe(this._volumesDetector, VolumesDetectorEvent.VOLUMES_DETECTED, this._onVolumesDetected.bind(this));\n this._speakerDetector = new SpeakerDetector(this._volumesDetector, this._transport, this._conversation.topology);\n this.subscribe(this._speakerDetector, SpeakerDetectorEvent.SPEAKER_CHANGED, this._onSpeakerChanged.bind(this));\n // NB: LocalVolumeDetector не будет работать, если вход в звонок был с выключенным микрофоном и заработает только после первого включения\n this._localVolumeDetector = new LocalVolumeDetector(this._mediaSource as MediaSource);\n }\n }\n\n private async _createSpecListener() {\n if (this._transport && this._volumesDetector) {\n this._specListener = new SpecListener(this._transport, this._volumesDetector, await this._getParticipants());\n }\n }\n\n private _logDevices() {\n const camerasCount = WebRTCUtils.getCameras().length,\n microphonesCount = WebRTCUtils.getMicrophones().length;\n Debug.debug(\n 'Cameras: ' +\n camerasCount +\n (WebRTCUtils.hasCameraPermission() ? '✔' : '✖') +\n ', Microphones: ' +\n microphonesCount +\n (WebRTCUtils.hasMicrophonePermission() ? '✔' : '✖'),\n );\n Logger.log(StatLog.DEVICES, `${camerasCount}_${microphonesCount}`);\n }\n\n private _logWithMediaSettings(stat: StatLog, mediaSettings?: MediaSettings) {\n Logger.log(stat, [mediaSettings?.isAudioEnabled && 'audio', mediaSettings?.isVideoEnabled && 'video'].filter(Boolean).join('_'));\n }\n\n private async _removeParticipant(participant: Participant, status: HangupType) {\n if (participant.state === ParticipantState.CALLED || participant.state === ParticipantState.ACCEPTED || this._state === ConversationState.CLOSE) {\n return;\n }\n\n if (participant.id === this._lastSignalledActiveSpeakerId) {\n this._lastSignalledActiveSpeakerId = null;\n }\n\n const cachedParticipants = await this._getParticipants();\n if (!cachedParticipants[participant.id]) {\n return;\n }\n\n if (status === HangupType.HUNGUP) {\n this._setParticipantsStatus([participant], ParticipantStatus.HANGUP);\n } else {\n this._setParticipantsStatus([participant], ParticipantStatus.ERROR, status);\n }\n\n participant.mediaSource?.disconnect();\n\n // Если был админский пин, то удаляем, но проверяем только главный и текущий залы. Для остальных залов\n // информация о пине обновится при переходе в зал\n if (this._conversation && this._conversation.pinnedParticipantIdByRoom.get(null) === participant.id) {\n this._conversation.pinnedParticipantIdByRoom.delete(null);\n }\n if (this._conversation && this._conversation.roomId && this._conversation.pinnedParticipantIdByRoom.get(this._conversation.roomId) === participant.id) {\n this._conversation.pinnedParticipantIdByRoom.delete(this._conversation.roomId);\n }\n\n // Освобождаем слот\n for (const [streamDescString, _layout] of Object.entries(participant.lastRequestedLayouts)) {\n this._streamIdByStreamDescription.delete(streamDescString);\n this._sequenceNumberByStreamDescription.delete(streamDescString);\n this._cooldownTimestampByStreamDescription.delete(streamDescString);\n if (this._streamWaitTimerByStreamDescription.has(streamDescString)) {\n window.clearTimeout(this._streamWaitTimerByStreamDescription.get(streamDescString));\n this._streamWaitTimerByStreamDescription.delete(streamDescString);\n }\n this._sendUpdateDisplayLayout({ [streamDescString]: { stopStream: true } }, false);\n }\n\n this._api.unmapDecorativeId(participant.id);\n delete cachedParticipants[participant.id];\n\n External.onRemoteRemoved(participant.externalId, participant.markers);\n }\n\n private _cleanupListeners(): void {\n this.unsubscribe();\n window.removeEventListener('unload', this._onUnload);\n }\n\n private _cleanupMediaSource(): void {\n if (this._mediaSource) {\n this._mediaSource.destroy();\n this._mediaSource = null;\n }\n }\n\n private async _cleanupParticipants(): Promise<void> {\n Object.values(await this._getParticipants()).forEach((participant) => {\n participant.remoteStream?.getTracks().forEach((track) => track.stop());\n participant.remoteAudioTrack?.stop();\n participant.secondStream?.getTracks().forEach((track) => track.stop());\n participant.mediaSource?.disconnect();\n });\n this._participants = {};\n\n if (this._audioOutput) {\n this._audioOutput.destroy();\n }\n }\n\n private _cleanupParticipantAgnosticStreams() {\n Debug.debug('cleaning up participant-agnostic streams');\n\n this._streamByStreamId.forEach((stream) => {\n stream.getTracks().forEach((track) => {\n track.stop();\n });\n });\n this._streamByStreamId = new Map<string, MediaStream>();\n\n this._streamWaitTimerByStreamDescription.forEach((timer) => {\n window.clearTimeout(timer);\n });\n this._streamWaitTimerByStreamDescription = new Map<StreamDescriptionString, number>();\n\n this._streamIdByStreamDescription = new Map<StreamDescriptionString, string | null>();\n this._sequenceNumberByStreamDescription = new Map<StreamDescriptionString, number>();\n this._cooldownTimestampByStreamDescription = new Map<StreamDescriptionString, number>();\n }\n\n private _cleanupTransport(): void {\n if (this._transport) {\n this._transport.destroy();\n this._transport = null;\n }\n if (this._debugInfo) {\n this._debugInfo = null;\n }\n }\n\n private _cleanupSpeakerDetector(): void {\n if (this._speakerDetector) {\n this._speakerDetector.destroy();\n this._speakerDetector = null;\n }\n if (this._volumesDetector) {\n this._volumesDetector.destroy();\n this._volumesDetector = null;\n }\n if (this._localVolumeDetector) {\n this._localVolumeDetector.destroy();\n this._localVolumeDetector = null;\n }\n }\n\n private _cleanupSpecListener(): void {\n if (this._specListener) {\n this._specListener.destroy();\n this._specListener = null;\n }\n }\n\n private _cleanupSignaling(): void {\n this._signaling.close();\n this._signaling.cleanup();\n }\n\n private async _onAddParticipant(participantId: ParticipantId, participantData: SignalingMessage.Participant, error: HangupType | null) {\n Debug.debug(`Add new participant [${participantId}]`);\n let participant = await this._getParticipant(participantId);\n if (participant && (participant.state === ParticipantState.ACCEPTED || participant.state === ParticipantState.CALLED)) {\n Debug.warn(`Participant [${participant.id}:${participant.state}] is already in conversation`);\n return;\n }\n\n if (!participant) {\n const decorativeId = Utils.composeDecorativeId(participantData);\n\n this._registerParticipant(\n {\n id: participantId,\n externalId: ExternalIdUtils.fromSignalingParticipant(participantData),\n mediaSettings: createMediaSettingsWithDefaults(participantData.mediaSettings),\n state: participantData.state,\n roles: participantData.roles || [],\n muteStates: participantData.muteStates || {},\n unmuteOptions: participantData.unmuteOptions || [],\n observedIds: participantData.observedIds || [],\n },\n decorativeId,\n );\n participant = await this._getParticipant(participantId);\n }\n\n this._setParticipantsStatus([participant], ParticipantStatus.WAITING);\n if (error) {\n participant.state = ParticipantState.HUNGUP;\n await this._removeParticipant(participant, error);\n } else if (this._transport) {\n participant.state = ParticipantState.CALLED;\n this._transport.allocate(participant.id, true);\n Logger.log(StatLog.ADD_PARTICIPANT);\n this._invokeRolesChangedCallbackIfNeeded(participant);\n }\n }\n\n private async _onRemoveParticipant(compositeUserId: CompositeUserId): Promise<void> {\n Debug.debug(`Remove participant [${compositeUserId}]`);\n\n const removedParticipants: Participant[] = [];\n const cachedParticipants = await this._getParticipants();\n // go over possible deviceIdx values as this is faster than iterating over all participants in large calls\n for (let deviceIdx = 0; deviceIdx <= MAX_DEVICE_IDX; deviceIdx++) {\n const participantId = Utils.compose(compositeUserId, deviceIdx);\n const participant = cachedParticipants[participantId];\n if (participant) {\n removedParticipants.push(participant);\n }\n }\n\n if (!removedParticipants.length) {\n this._warnParticipantNotInConversation(compositeUserId);\n return;\n }\n\n if (this._transport) {\n for (const removedParticipant of removedParticipants) {\n this._transport.close(removedParticipant.id);\n }\n }\n\n Logger.log(StatLog.REMOVE_PARTICIPANT);\n\n // NOTE: Participant is removed after signaling sends notification 'hungup'\n }\n\n async changeDevice(kind: MediaDeviceKind) {\n if (kind === 'audiooutput') {\n return this._audioOutput.changeOutput();\n } else if (this._mediaSource) {\n return this._mediaSource.changeDevice(kind);\n }\n return Promise.reject(FatalError.UNKNOWN);\n }\n\n stopVideoTrack() {\n return this._mediaSource?.stopVideoTrack();\n }\n\n async toggleScreenCapturing(settings: ScreenCaptureSettings) {\n if (this._mediaSource) {\n return this._mediaSource.toggleScreenCapturing(settings);\n }\n return Promise.reject(FatalError.UNKNOWN);\n }\n\n async disableScreenCapturing() {\n if (this._mediaSource) {\n return this._mediaSource.disableScreenCapturing();\n }\n return Promise.reject(FatalError.UNKNOWN);\n }\n\n toggleAnimojiCapturing(state: boolean) {\n if (this._mediaSource) {\n this._mediaSource.toggleAnimojiCapturing(state);\n }\n }\n\n setAnimojiSvg(\n /** svg в незашифрованном (string) или зашифрованном (ArrayBuffer) виде */\n svg: string | ArrayBuffer,\n /** participantId внешнего участника звонка, не требуется для текущего участника (текущего пользователя клиента) */\n participantId: ParticipantId | null = null,\n /** ключ расшифровки svg внешнего пользователя или кастомный ключ, не требуется для незашифрованных svg */\n decryptionKey: string | null = null,\n ) {\n if (!this._transport || !this._conversation) {\n return;\n }\n\n const isMe = !participantId;\n const pId = participantId ?? this._conversation.compositeUserId;\n\n if (svg instanceof ArrayBuffer) {\n // Нужен только для расшифровки\n const userId = decryptionKey ?? this._conversation.externalId.id;\n\n this._transport.setAnimojiSvg(pId, {\n svg,\n userId,\n isMe,\n });\n return;\n }\n\n this._transport.setAnimojiSvg(pId, { svg, isMe });\n }\n\n setAnimojiFill(fill: RGBTuple | string) {\n this._transport?.setAnimojiFill(fill);\n }\n\n async setVideoStream(stream: MediaStream, isScreen = false) {\n if (this._mediaSource) {\n return this._mediaSource.setVideoStream(stream, isScreen);\n }\n }\n\n async setAudioStream(stream: MediaStream) {\n if (this._mediaSource) {\n return this._mediaSource.setAudioStream(stream);\n }\n }\n\n async toggleLocalVideo(enabled: boolean) {\n if (this._mediaSource) {\n Logger.log(StatLog.MEDIA_STATUS, enabled ? 'video_1' : 'video_0');\n return this._mediaSource.toggleVideo(enabled);\n }\n }\n\n async toggleLocalAudio(enabled: boolean) {\n if (this._mediaSource) {\n Logger.log(StatLog.MEDIA_STATUS, enabled ? 'audio_1' : 'audio_0');\n return this._mediaSource.toggleAudio(enabled);\n }\n }\n\n /**\n * @deprecated Use updateDisplayLayout instead\n */\n async changePriorities(priorities: ParticipantPriority[]) {\n if (priorities.length < 2 || !this._signaling.ready) {\n return;\n }\n\n const typedPriorities: { [key: string]: number } = {};\n const strExternalPriorities: { [key: string]: number } = {};\n\n for (const item of priorities) {\n const externalId = typeof item.uid === 'object' ? (item.uid as ExternalParticipantId) : ExternalIdUtils.fromId(item.uid);\n const strExternalId = ExternalIdUtils.toString(externalId);\n strExternalPriorities[strExternalId] = item.priority;\n }\n\n const cachedParticipants = await this._getParticipants();\n\n for (const participant of Object.values(cachedParticipants)) {\n const strExternalId = ExternalIdUtils.toString(participant.externalId);\n if (Object.hasOwn(strExternalPriorities, strExternalId)) {\n typedPriorities[participant.id] = strExternalPriorities[strExternalId];\n }\n }\n\n await this._signaling.changePriorities(typedPriorities);\n }\n\n async changeParticipantState(state: ParticipantStateData, compositeUserId?: CompositeUserId) {\n for (const [key, value] of Object.entries(state)) {\n if (key.length > 5 || value.length > 5) {\n throw new Error('key/value max length is 5 chars, mappings with empty values (null or empty string) are discarded');\n }\n }\n\n if (compositeUserId && !this._isCallAdmin()) {\n // only admins can change others state\n compositeUserId = undefined;\n }\n\n await this._signaling.changeParticipantState(state, compositeUserId);\n }\n\n async putHandsDown() {\n this._checkAdminRole();\n await this._signaling.putHandsDown();\n }\n\n async requestKeyFrame(participantStreamDescription: ParticipantStreamDescription) {\n const layouts: { [key: StreamDescriptionString]: RequestKeyFrame } = {};\n layouts[serializeParticipantStreamDescription(participantStreamDescription)] = { keyFrameRequested: true };\n return this._signaling.updateDisplayLayout(layouts);\n }\n\n async requestTestMode(consumerCommand: string, producerCommand: string) {\n return this._signaling.requestTestMode(consumerCommand, producerCommand);\n }\n\n async updateDisplayLayout(layouts: ParticipantLayout[]) {\n if (layouts.length < 1 || !this._signaling.ready) {\n return;\n }\n\n Debug.log(`Update display layout request [${this._signaling.getNextCommandSequenceNumber()}]`, layouts);\n\n const layoutByStreamDescription: { [key: string]: ParticipantLayout | StopStream } = {};\n const cachedParticipants = await this._getParticipants();\n for (const layout of layouts) {\n const externalId = typeof layout.uid === 'object' ? (layout.uid as ExternalParticipantId) : ExternalIdUtils.fromId(layout.uid);\n\n const participantId = this._api.getCachedOkIdByExternalId(externalId);\n if (!participantId) {\n const strExternalId = ExternalIdUtils.toString(externalId);\n Debug.log(`Unknown participant external ID ${strExternalId}`);\n continue;\n }\n\n const streamDescString = serializeParticipantStreamDescription({ participantId, mediaType: layout.mediaType, streamName: layout.streamName });\n\n const participant = cachedParticipants[participantId];\n if (participant) {\n participant.lastRequestedLayouts[streamDescString] = layout;\n } else if (this._isMe(participantId)) {\n this._myLastRequestedLayouts[streamDescString] = layout;\n }\n\n if (isStopStreaming(layout)) {\n if (this._isMe(participantId)) {\n delete this._myLastRequestedLayouts[streamDescString];\n }\n if (this._streamIdByStreamDescription.has(streamDescString) && !this._cooldownTimestampByStreamDescription.has(streamDescString)) {\n this._cooldownTimestampByStreamDescription.set(streamDescString, Date.now());\n }\n } else {\n this._cooldownTimestampByStreamDescription.delete(streamDescString);\n\n if (!this._streamIdByStreamDescription.has(streamDescString) && Params.videoTracksCount > 0) {\n this._streamIdByStreamDescription.set(streamDescString, null);\n }\n\n layoutByStreamDescription[streamDescString] = layout;\n }\n\n if (layout.mediaType === MediaType.SCREEN && !isStopStreaming(layout)) {\n Statistics.setMark(Statistics.getMarkNameScreenshareFirstFrame(participantId));\n }\n }\n\n const cooldownIterator = this._cooldownTimestampByStreamDescription.keys();\n while (this._streamIdByStreamDescription.size > Params.videoTracksCount) {\n const cooldownElement = cooldownIterator.next();\n if (cooldownElement.done) {\n Debug.error(\n 'Cannot accommodate all streaming requests: ' +\n 'tracks available ' +\n Params.videoTracksCount +\n '; requested streams: ' +\n Array.from(this._streamIdByStreamDescription.keys()),\n );\n break;\n }\n\n await this._stopStreaming(cooldownElement.value);\n layoutByStreamDescription[cooldownElement.value] = { stopStream: true };\n }\n\n if (this._transport?.getTopology() !== TransportTopology.SERVER) {\n return;\n }\n\n await this._sendUpdateDisplayLayout(layoutByStreamDescription);\n }\n\n async feedback(key: string) {\n return this._signaling.feedback(key);\n }\n\n userFeedbackStats(userResponse: number, reason?: string, groupCallUsersCount?: number) {\n if (!this._conversation) {\n return;\n }\n\n if (!Params.clientEventsLoggingEnabled) {\n this._api.sendUserFeedbackStats(this._conversation.id, userResponse, reason, groupCallUsersCount);\n } else {\n const data = {\n event_type: Stat.USER_FEEDBACK_RECEIVED,\n user_response: userResponse,\n } as any;\n\n if (reason !== undefined) {\n data.reason = reason;\n }\n\n if (groupCallUsersCount !== undefined) {\n data.group_call_users_count = groupCallUsersCount;\n }\n\n Logger.logClientEvent(data, true);\n }\n }\n\n sendClientEvent(eventType: string, eventData: Record<string, string | number | boolean> = {}, immediately = false) {\n const event = {\n event_type: eventType,\n ...eventData,\n };\n\n Logger.logClientEvent(event, immediately);\n }\n\n private _changeMediaSettings = Utils.debounce(async (mediaSettings: MediaSettings) => {\n if (!this._signaling.ready) {\n return;\n }\n\n try {\n await this._signaling.changeMediaSettings(mediaSettings);\n } catch (e: any) {\n // TODO: Вернуть прежние медиасеттинги, если не удалось изменить (непонятно где их взять)\n Debug.warn('changeMediaSettings failed with error', e);\n\n if (e.message === 'chatRoom.maxShareCountExceeded') {\n return this.toggleScreenCapturing({\n captureScreen: false,\n fastScreenSharing: false,\n captureAudio: false,\n });\n }\n }\n }, 100);\n\n private async _stopStreaming(streamDescString: StreamDescriptionString) {\n this._cooldownTimestampByStreamDescription.delete(streamDescString);\n this._sequenceNumberByStreamDescription.set(streamDescString, this._signaling.getNextCommandSequenceNumber());\n\n if (this._streamWaitTimerByStreamDescription.has(streamDescString)) {\n Debug.log('Client asked to stop streaming before stream became available', streamDescString);\n window.clearTimeout(this._streamWaitTimerByStreamDescription.get(streamDescString));\n this._streamWaitTimerByStreamDescription.delete(streamDescString);\n }\n\n const streamId = this._streamIdByStreamDescription.get(streamDescString);\n if (streamId) {\n const cachedParticipants = await this._getParticipants();\n const streamDesc = parseParticipantStreamDescription(streamDescString);\n const participant = cachedParticipants[streamDesc.participantId];\n const localExternalId = this._conversation?.externalId as ExternalParticipantId;\n const isOwnerStream = this._isMe(streamDesc.participantId);\n\n if (participant || isOwnerStream) {\n switch (streamDesc.mediaType) {\n case MediaType.STREAM:\n case MediaType.MOVIE: {\n if (streamDesc.streamName) {\n const movieData: IOnRemoteMovieData = {\n stream: null,\n streamName: streamDesc.streamName,\n mediaType: streamDesc.mediaType,\n };\n\n if (isOwnerStream) {\n External.onLocalLive(localExternalId, movieData);\n } else {\n External.onRemoteLive(participant.externalId, movieData);\n }\n }\n break;\n }\n case MediaType.CAMERA: {\n External.onRemoteStream(participant.externalId, null);\n break;\n }\n\n case MediaType.SCREEN: {\n External.onRemoteScreenStream(participant.externalId, null);\n break;\n }\n }\n\n Logger.log(StatLog.PAT_DEALLOCATED);\n } else {\n Debug.log(`Cannot find participant to stop streaming: ${streamDesc.participantId}`);\n }\n }\n\n this._streamIdByStreamDescription.delete(streamDescString);\n }\n\n /**\n * @param layoutByStreamDescription\n * @param throwErrorOutside false используется при внутреннем обращении, когда обработка ошибки не нужна\n */\n private async _sendUpdateDisplayLayout(layoutByStreamDescription: { [key: StreamDescriptionString]: ParticipantLayout | StopStream }, throwErrorOutside = true) {\n if (Object.keys(layoutByStreamDescription).length === 0) {\n return;\n }\n\n Debug.log(`Update display layout send [${this._signaling.getNextCommandSequenceNumber()}]`, layoutByStreamDescription);\n\n let result: SignalingMessage | void;\n\n try {\n result = await this._signaling.updateDisplayLayout(layoutByStreamDescription);\n if (!result) {\n return;\n }\n } catch (error: any) {\n Debug.warn(`Failed to update display layout ${JSON.stringify(layoutByStreamDescription)}. ${error}`);\n\n if (throwErrorOutside) {\n throw error;\n }\n\n return;\n }\n\n const errorReasonByExternalId = [];\n const cachedParticipants = await this._getParticipants();\n for (const [streamDescriptionString, errorCode] of Object.entries(result.errorCodeByParticipantId || {})) {\n const streamDescription = parseParticipantStreamDescription(streamDescriptionString);\n const errorParticipant = cachedParticipants[streamDescription.participantId];\n if (errorParticipant) {\n let errorReason;\n if (typeof errorCode !== 'number') {\n Debug.warn(`Unexpected error code ${errorCode} received for participant ${streamDescription.participantId}`);\n errorReason = UpdateDisplayLayoutErrorReason.UNKNOWN_ERROR;\n } else {\n errorReason = getUpdateDisplayLayoutErrorReasonByCode(errorCode);\n }\n errorReasonByExternalId.push({ externalId: errorParticipant.externalId, errorReason });\n }\n }\n\n if (errorReasonByExternalId && errorReasonByExternalId.length) {\n Debug.warn('Could not allocate one or more participants', errorReasonByExternalId);\n\n if (throwErrorOutside) {\n throw new UpdateDisplayLayoutError('Could not allocate one or more participants', errorReasonByExternalId);\n }\n }\n }\n\n private async _cleanupCooldownQueue() {\n const layoutByStreamDescription: { [key: StreamDescriptionString]: StopStream } = {};\n\n const cooldownIterator = this._cooldownTimestampByStreamDescription.entries();\n do {\n const cooldownElement = cooldownIterator.next();\n if (cooldownElement.done) {\n break;\n }\n\n const entry = cooldownElement.value;\n const timestamp = entry[1];\n if (timestamp + COOLDOWN_QUEUE_EXPIRY_INTERVAL_MILLIS > Date.now()) {\n break;\n }\n\n const streamDescString = entry[0];\n await this._stopStreaming(streamDescString);\n\n layoutByStreamDescription[streamDescString] = { stopStream: true };\n } while (true);\n\n this._sendUpdateDisplayLayout(layoutByStreamDescription, false);\n }\n\n private _onParticipantSourcesUpdate(message: SignalingMessage.ParticipantSourcesUpdateNotification): void {\n if (this._conversation) {\n const participantUpdateInfos = message.participantUpdateInfos;\n Debug.log('Received participant sources update notification', participantUpdateInfos);\n for (const participantUpdateInfo of participantUpdateInfos) {\n this._waitForStreamIfNeeded(participantUpdateInfo);\n }\n }\n }\n\n private async _onParticipantPromoted(connection: SignalingMessage.PromoteParticipant) {\n if (this._conversation && this._conversation.audienceMode) {\n Debug.log('Promoted in audience mode', !connection.demote);\n this._conversation.restricted = connection.demote;\n this._processRecordInfos(connection);\n if (!connection.demote && this._mediaSource) {\n this._changeMediaSettings(this._mediaSource.getMediaSettings());\n }\n } else {\n Debug.log('Promoted in waiting hall', !connection.demote);\n\n if (connection.demote) {\n Debug.log('Kicked from waiting hall');\n this._close(new HangupReason(HangupType.REMOVED));\n } else {\n this._updateConversation(connection);\n await this._onJoinPart2(connection);\n }\n }\n External.onPromoted(connection.demote);\n }\n\n private async _onChatRoomUpdated(\n eventType: ChatRoomEventType,\n totalCount = 0,\n firstParticipants: SignalingMessage.WaitingParticipant[] = [],\n addedParticipantIds: CompositeUserId[] | null,\n removedParticipantIds: CompositeUserId[] | null,\n ) {\n Debug.log(`Chat room updated: ${eventType}`);\n\n const okUserIds: OkUserId[] = [];\n const okUserIdsAdded: OkUserId[] = [];\n const okUserIdsRemoved: OkUserId[] = [];\n const firstUserIds: OkUserId[] = [];\n\n const firstExternalIds: ExternalParticipantId[] = [];\n if (firstParticipants.length) {\n firstParticipants.forEach((participant) => {\n if (participant.externalId) {\n const externalId = ExternalIdUtils.fromSignaling(participant.externalId);\n firstExternalIds.push(externalId);\n this._api.cacheExternalId(participant.id.id, externalId);\n } else {\n const id = Utils.decomposeId(participant.id.id).id;\n okUserIds.push(id);\n firstUserIds.push(id);\n }\n });\n }\n if (addedParticipantIds?.length) {\n addedParticipantIds.forEach((added) => {\n const id = Utils.decomposeId(added).id;\n okUserIds.push(id);\n okUserIdsAdded.push(id);\n });\n }\n if (removedParticipantIds?.length) {\n removedParticipantIds.forEach((removed) => {\n const id = Utils.decomposeId(removed).id;\n okUserIds.push(id);\n okUserIdsRemoved.push(id);\n });\n }\n\n if (!okUserIds.length) {\n External.onChatRoomUpdated(eventType, totalCount, firstExternalIds, [], []);\n return;\n }\n\n if (firstUserIds.length) {\n const externalIds = await this._api.getExternalIdsByOkIds(firstUserIds);\n firstExternalIds.push(...externalIds);\n }\n\n const addedExternalIds = await this._api.getExternalIdsByOkIds(okUserIdsAdded);\n const removedExternalIds = await this._api.getExternalIdsByOkIds(okUserIdsRemoved);\n\n External.onChatRoomUpdated(eventType, totalCount, firstExternalIds, addedExternalIds, removedExternalIds);\n }\n\n private async _onSharedMovieUpdate(message: SignalingMessage.SharedMovieState) {\n const localExternalId = this._conversation?.externalId as ExternalParticipantId;\n\n for (const state of message.data) {\n const isMovieOwner = this._isMe(state.participantId);\n\n if (isMovieOwner) {\n External.onLocalLiveUpdate(localExternalId, state);\n } else {\n const externalId = await this._getExternalIdByParticipantId(state.participantId);\n if (externalId) {\n External.onRemoteLiveUpdate(externalId, state);\n }\n }\n }\n }\n\n private async _onSharedMovieInfoStarted(message: SignalingMessage.SharedMovieInfo) {\n Debug.log(`Shared movie started data received: ${message.notification}`);\n await this._processSharedMovieInfo(message.movieShareInfo, message.roomId);\n }\n\n private async _processSharedMovieInfos(movieShareInfos: ISharedMovieInfo[] | null | undefined, roomId: IRoomId = null) {\n if (movieShareInfos) {\n await Promise.all(movieShareInfos.map((movieShareInfo) => this._processSharedMovieInfo(movieShareInfo, roomId)));\n }\n }\n\n private async _processSharedMovieInfo(movieShareInfo: ISharedMovieInfo | null, roomId: IRoomId = null) {\n if (!movieShareInfo) {\n return;\n }\n\n const localExternalId = this._conversation?.externalId as ExternalParticipantId;\n const isMovieOwner = this._isMe(movieShareInfo.initiatorId);\n\n if (isMovieOwner) {\n External.onLocalSharedMovieInfo(localExternalId, movieShareInfo, roomId);\n } else {\n const externalId = await this._getExternalIdByParticipantId(movieShareInfo.initiatorId);\n if (externalId) {\n External.onRemoteSharedMovieInfo(externalId, movieShareInfo, roomId);\n }\n }\n }\n\n private async _processConnectionSharedMovieInfo(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n const me = connection.conversation.participants.find((participant) => this._isMe(Utils.composeId(participant)));\n await this._processSharedMovieInfos(me?.movieShareInfos, connection?.rooms?.roomId ?? null);\n }\n\n private async _processConnectionAsrInfo(connection?: SignalingMessage.Connection | SignalingMessage.PromoteParticipant) {\n const conversationAsrInfo = connection?.conversation.asrInfo ?? this._conversation?.asrInfo;\n if (conversationAsrInfo) {\n this._conversation?.asrInfoByRoom.set(null, conversationAsrInfo);\n }\n\n if (connection?.rooms?.rooms) {\n for (const room of connection.rooms.rooms) {\n if (room.asrInfo) {\n this._conversation?.asrInfoByRoom.set(room.id, room.asrInfo);\n }\n }\n }\n\n const roomId = connection?.rooms?.roomId ?? this._conversation?.roomId ?? MAIN_ROOM_ID;\n const asrInfo = this._conversation?.asrInfoByRoom.get(roomId);\n\n if (asrInfo) {\n const externalId = await this._getExternalIdByParticipantId(asrInfo.initiatorId);\n if (externalId) {\n External.onAsrSet(\n {\n externalId,\n movieId: asrInfo.movieId,\n },\n roomId,\n );\n }\n } else if (roomId) {\n External.onAsrSet(null, roomId);\n }\n }\n\n private async _processConversationUrlSharingInfo(connection?: SignalingMessage.Connection | SignalingMessage.PromoteParticipant): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n if (connection) {\n this._extractConnectionUrlSharingInfo(connection);\n }\n\n const { urlSharingInfoByRoom } = this._conversation;\n const roomId = this._conversation.roomId; // connection.rooms?.roomId ?? MAIN_ROOM_ID;\n const urlSharingInfo = urlSharingInfoByRoom.get(roomId);\n\n if (urlSharingInfo && !this._isMe(urlSharingInfo.initiatorId)) {\n const externalId = await this._getExternalIdByParticipantId(urlSharingInfo.initiatorId);\n if (externalId) {\n External.onRemoteSharedUrl(externalId, urlSharingInfo.sharedUrl, roomId);\n }\n }\n }\n\n private _extractConnectionUrlSharingInfo(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant): void {\n if (!this._conversation) {\n return;\n }\n\n const { urlSharingInfoByRoom } = this._conversation;\n\n if (connection.conversation.urlSharingInfo) {\n urlSharingInfoByRoom.set(null, connection.conversation.urlSharingInfo);\n } else {\n urlSharingInfoByRoom.delete(null);\n }\n\n if (connection.rooms?.rooms) {\n for (const room of connection.rooms.rooms) {\n if (room.urlSharingInfo) {\n urlSharingInfoByRoom.set(room.id, room.urlSharingInfo);\n } else {\n urlSharingInfoByRoom.delete(room.id);\n }\n }\n }\n }\n\n private async _onSharedMovieInfoStopped(message: SignalingMessage.SharedMovieStoppedInfo) {\n Debug.log(`Shared movie stopped data received: ${message.notification}`);\n\n const localExternalId = this._conversation?.externalId as ExternalParticipantId;\n const { initiatorId, movieId, source, roomId = MAIN_ROOM_ID } = message;\n\n const data: ISharedMovieStoppedInfo = {\n initiatorId,\n movieId,\n source,\n };\n\n const isMovieOwner = this._isMe(initiatorId);\n\n if (isMovieOwner) {\n External.onLocalSharedMovieStoppedInfo(localExternalId, data, roomId);\n } else {\n const externalId = await this._getExternalIdByParticipantId(initiatorId);\n if (externalId) {\n const cachedParticipants = await this._getParticipants();\n const participant = cachedParticipants[initiatorId];\n if (participant?.movieShareInfos) {\n participant.movieShareInfos = participant.movieShareInfos.filter((info) => info && info.movieId !== movieId);\n }\n\n External.onRemoteSharedMovieStoppedInfo(externalId, data, roomId);\n }\n }\n }\n\n private async _onUrlSharingInfoUpdated(message: SignalingMessage.UrlSharingInfo) {\n Debug.log(`Shared URL data received: ${message.notification}`);\n\n if (!this._conversation) {\n return;\n }\n\n const { urlSharingInfoByRoom, roomId: currentRoomId } = this._conversation;\n const { initiatorId, sharedUrl, roomId = MAIN_ROOM_ID } = message;\n\n if (sharedUrl) {\n urlSharingInfoByRoom.set(roomId, {\n sharedUrl,\n initiatorId,\n });\n } else {\n urlSharingInfoByRoom.delete(roomId);\n }\n\n if (!sharedUrl && roomId !== currentRoomId && urlSharingInfoByRoom.has(currentRoomId)) {\n // Stop from previous room has come after start\n return;\n }\n\n // stop could be made by server\n if (!sharedUrl || !this._isMe(initiatorId)) {\n const externalId = await this._getExternalIdByParticipantId(initiatorId);\n if (externalId) {\n External.onRemoteSharedUrl(externalId, sharedUrl, roomId);\n }\n }\n }\n\n private _onFeaturesPerRoleChanged(message: SignalingMessage.FeaturesPerRoleChanged) {\n Debug.log(`Features per role changed: ${message.notification}`);\n if (this._conversation) {\n this._conversation.featuresPerRole = message.featuresPerRole ?? {};\n }\n External.onFeaturesPerRoleChanged(message.featuresPerRole as IFeaturesPerRole);\n }\n\n private async _waitForStreamIfNeeded(participantUpdateInfo: SignalingMessage.ParticipantUpdateInfo) {\n // stop fast screen share receiving\n if (participantUpdateInfo.fastScreenShare && !participantUpdateInfo.participantStreamDescription) {\n const streamDesc = this._getStreamDescriptionById(participantUpdateInfo.streamId);\n if (streamDesc) {\n const participantStreamDesc = parseParticipantStreamDescription(streamDesc);\n const fastScreenShareParticipant = await this._getParticipant(participantStreamDesc.participantId);\n External.onRemoteScreenStream(fastScreenShareParticipant.externalId, null);\n return;\n }\n }\n\n const streamDescription = this._matchStreamDescription(participantUpdateInfo.participantStreamDescription);\n if (!streamDescription) {\n // streaming stopped\n return;\n }\n\n const { mediaType, participantId } = streamDescription;\n\n if (mediaType === MediaType.ANIMOJI) {\n // animoji will be received over datachannel\n return;\n }\n const participant = await this._getParticipant(participantId);\n\n if (Params.producerScreenDataChannel && mediaType === MediaType.SCREEN && !participantUpdateInfo.fastScreenShare) {\n // screenshare will be received over datachannel\n Debug.log('skipping participant-sources-update notification since screenshare will be received over datachannel');\n return;\n }\n\n const streamDescriptionString = serializeParticipantStreamDescription(streamDescription);\n\n const lastSentSequenceNumber = this._sequenceNumberByStreamDescription.get(streamDescriptionString);\n if (lastSentSequenceNumber && lastSentSequenceNumber > participantUpdateInfo.sequenceNumber) {\n Debug.warn(\n `Participant ${participantId} received outdated PAT response: ` +\n `sequence number ${participantUpdateInfo.sequenceNumber}; ` +\n `last sent sequence number for given participant is ${lastSentSequenceNumber}`,\n );\n Logger.log(StatLog.PAT_OUTDATED_RESPONSE);\n return;\n }\n\n // suspend/unsuspend stream\n if (participant && participantUpdateInfo.suspend !== undefined && mediaType) {\n Debug.debug(`participant-sources-update: mediaType=${mediaType}, suspend=${participantUpdateInfo.suspend}`);\n External.onRemoteStreamSuspended(participant.externalId, mediaType, participantUpdateInfo.suspend);\n }\n\n const streamId = participantUpdateInfo.streamId;\n const waitingTime = participantUpdateInfo.rtpTimestamp ? this._getWaitingTime(streamId, participantUpdateInfo.rtpTimestamp) : 0;\n if (waitingTime <= 0) {\n this._streamWaitTimerByStreamDescription.delete(streamDescriptionString);\n\n const localExternalId = this._conversation?.externalId as ExternalParticipantId;\n const isOwnerStream = this._isMe(participantId);\n\n if (!participant && !isOwnerStream) {\n Logger.log(StatLog.PAT_ERROR, 'participantMissing');\n Debug.error(`Could not find participant by ID: ${participantId}`);\n return;\n }\n\n const externalId = isOwnerStream ? localExternalId : participant.externalId;\n\n const stream = this._streamByStreamId.get(streamId);\n if (!stream) {\n Logger.log(StatLog.PAT_ERROR, 'streamNotFound');\n Debug.error(`Could not find stream by ID: ${streamId}`);\n return;\n }\n\n Logger.log(StatLog.PAT_ALLOCATED);\n this._streamIdByStreamDescription.set(streamDescriptionString, streamId);\n\n const msgMediaType = participantUpdateInfo.participantStreamDescription?.mediaType;\n if (msgMediaType === MediaType.STREAM || msgMediaType === MediaType.MOVIE) {\n if (participantUpdateInfo.participantStreamDescription?.streamName) {\n const movieData: IOnRemoteMovieData = {\n streamName: participantUpdateInfo.participantStreamDescription.streamName,\n stream,\n mediaType: msgMediaType,\n };\n\n if (isOwnerStream) {\n External.onLocalLive(externalId, movieData);\n } else {\n External.onRemoteLive(externalId, movieData);\n }\n }\n } else if (Params.producerScreenTrack && msgMediaType === MediaType.SCREEN) {\n External.onRemoteScreenStream(participant.externalId, stream);\n } else {\n // if parallel camera/screenshare is disabled and screenshare track is available, pass it to client instead of camera track\n if (!isOwnerStream) {\n const appliedStream = (Params.producerScreenTrack ? null : participant.secondStream) || stream;\n External.onRemoteStream(participant.externalId, appliedStream);\n }\n }\n } else {\n Debug.debug(`Waiting for ${waitingTime} until stream ${streamId} for ${streamDescriptionString} is switched`);\n const timer = window.setTimeout(this._waitForStreamIfNeeded.bind(this, participantUpdateInfo), waitingTime);\n this._streamWaitTimerByStreamDescription.set(streamDescriptionString, timer);\n }\n }\n\n private _getStreamDescriptionById(streamId: string): StreamDescriptionString | null {\n for (const [curStreamDesc, curStreamId] of this._streamIdByStreamDescription.entries()) {\n if (curStreamId === streamId) {\n return curStreamDesc;\n }\n }\n return null;\n }\n\n // TODO workaround for older clients; remove once all clients have migrated to screenTrack\n private _matchStreamDescription(streamDescription: ParticipantStreamDescription | null) {\n if (!streamDescription) {\n return null;\n }\n if (this._streamIdByStreamDescription.has(serializeParticipantStreamDescription(streamDescription))) {\n return streamDescription;\n }\n\n const participantId = streamDescription.participantId;\n if (!streamDescription.mediaType) {\n const cameraDescription = { participantId, mediaType: MediaType.CAMERA };\n if (this._streamIdByStreamDescription.has(serializeParticipantStreamDescription(cameraDescription))) {\n return cameraDescription;\n }\n\n const screenDescription = { participantId, mediaType: MediaType.SCREEN };\n if (this._streamIdByStreamDescription.has(serializeParticipantStreamDescription(screenDescription))) {\n return screenDescription;\n }\n } else {\n const legacyDescription: ParticipantStreamDescription = { participantId, mediaType: null };\n if (this._streamIdByStreamDescription.has(serializeParticipantStreamDescription(legacyDescription))) {\n return legacyDescription;\n }\n }\n\n Debug.error('Received unrequested allocation', streamDescription);\n return null;\n }\n\n private _getWaitingTime(streamId: string, targetRtpTimestamp: number): number {\n if (this._transport) {\n return this._transport.getStreamWaitingTimeMs(streamId, targetRtpTimestamp);\n } else {\n throw new Error('transport is not initialized');\n }\n }\n\n private _isCallAdmin() {\n if (!this._conversation) {\n return false;\n }\n return Utils.includesOneOf(this._conversation.roles, [UserRole.ADMIN, UserRole.CREATOR]);\n }\n\n private _checkAdminRole() {\n if (!this._conversation) {\n return;\n }\n if (!Utils.includesOneOf(this._conversation.roles, [UserRole.ADMIN, UserRole.CREATOR])) {\n throw new Error(\"You don't have the required permission\");\n }\n }\n\n private _isCalledState() {\n return this._participantState === ParticipantState.CALLED;\n }\n\n async grantRoles(participantId: ParticipantId, roles: UserRole[], revoke: boolean) {\n this._checkAdminRole();\n await this._signaling.grantRoles(participantId, roles, revoke);\n }\n\n async startAsr(params: IAsrStartParams) {\n await this._signaling.startAsr(params);\n }\n\n async stopAsr(params?: IAsrStopParams) {\n await this._signaling.stopAsr(params);\n }\n\n async requestAsr(request: boolean) {\n // Устанавливаем флаг для открытия транспорта после автоматического перехода на серверную топологию\n this._isRealTimeAsrRequested = request;\n\n await this._signaling.requestAsr(request);\n }\n\n async muteParticipant(participantId: ParticipantId | null = null, muteStates: MuteStates, requestedMedia: MediaOption[] = [], roomId: number | null = MAIN_ROOM_ID) {\n this._checkAdminRole();\n await this._signaling.muteParticipant(participantId, muteStates, requestedMedia, roomId);\n }\n\n async enableFeatureForRoles(feature: ConversationFeature, roles: UserRole[]) {\n await this._signaling.enableFeatureForRoles(feature, roles);\n }\n\n async pinParticipant(participantId: ParticipantId, unpin: boolean, roomId: number | null = MAIN_ROOM_ID) {\n this._checkAdminRole();\n await this._signaling.pinParticipant(participantId, unpin, roomId);\n\n // Обновляем состояние пина, так как админ совершающих пин не получает нотификацию\n this._conversation?.pinnedParticipantIdByRoom.set(roomId, unpin ? null : participantId);\n }\n\n async updateMediaModifiers(mediaModifiers: MediaModifiers) {\n if (this._signaling.ready && this._conversation) {\n this._conversation.mediaModifiers = mediaModifiers;\n await this._signaling.updateMediaModifiers(mediaModifiers);\n }\n }\n\n async enableVideoSuspend(enabled: boolean) {\n if (this._signaling.ready && this._conversation && this._transport?.getTopology() === TransportTopology.SERVER) {\n await this._signaling.enableVideoSuspend(enabled);\n }\n }\n\n async enableVideoSuspendSuggest(enabled: boolean) {\n if (this._signaling.ready && this._conversation && this._transport?.getTopology() === TransportTopology.SERVER) {\n await this._signaling.enableVideoSuspendSuggest(enabled);\n }\n }\n\n async changeOptions(changes: { [key in ConversationOption]?: boolean }) {\n if (this._signaling.ready && this._conversation) {\n this._checkAdminRole();\n await this._signaling.changeOptions(changes);\n const options = applyOptionChanges(this._conversation.options, changes);\n this._onOptionsChanged(options);\n }\n }\n\n /**\n * @see https://wiki.odkl.ru/pages/viewpage.action?pageId=89107473\n * @hidden\n */\n async getWaitingHall(pageMarker: string | null, count?: number, backward?: boolean): Promise<WaitingHallResponse> {\n if (!this._signaling) {\n return Promise.reject();\n }\n\n let fromId: SignalingMessage.WaitingParticipantId | null = null;\n if (pageMarker) {\n fromId = waitingParticipantIdFromString(pageMarker);\n if (fromId) {\n const decorativeId = this._api.getDecorativeIdByInitialId(fromId.id);\n fromId.id = decorativeId ? Utils.composeUserId(decorativeId) : fromId.id;\n }\n }\n\n const result = await this._signaling.getWaitingHall(fromId, count, backward);\n if (result.error) {\n // TODO: кажется, тут никогда не приходит ошибка\n return Promise.reject(result.message);\n }\n\n const participants: SignalingMessage.WaitingParticipant[] = result.participants || [];\n const { externalIds } = await this._resolveWaitingHallExternalIds(participants);\n let nextPageMarker: string | null = null;\n\n if (participants.length && result.hasMore) {\n nextPageMarker = waitingParticipantIdToString(participants[participants.length - 1].id);\n }\n\n return {\n participants: externalIds,\n pageMarker: nextPageMarker,\n totalCount: result.totalCount || 0,\n };\n }\n\n private async _resolveWaitingHallExternalIds(participants: SignalingMessage.WaitingParticipant[]) {\n const timestampsMap = new Map<CompositeUserId, number>();\n let timestamps: number[] = [];\n let externalIds: ExternalId[] = [];\n\n if (participants.length) {\n const uids: OkUserId[] = [];\n participants.forEach((participant) => {\n timestampsMap.set(participant.id.id, participant.id.addedTs);\n\n if (participant.externalId) {\n const externalId = ExternalIdUtils.fromSignaling(participant.externalId);\n timestamps.push(participant.id.addedTs);\n externalIds.push(externalId);\n this._api.cacheExternalId(participant.id.id, externalId);\n } else {\n uids.push(Utils.decomposeId(participant.id.id).id);\n }\n });\n\n if (uids.length && !externalIds.length) {\n // Если в сигналинге не было externalId, получим из апи\n externalIds = await this._api.getExternalIdsByOkIds(uids);\n\n timestamps = externalIds.map((externalId) => {\n const compositeId = this._api.getCachedOkIdByExternalId(externalId);\n const cachedTimestamp = compositeId ? timestampsMap.get(compositeId) : undefined;\n // Если по каким-то причинам не выйдет получить ts, вернем текущее время\n return cachedTimestamp || Date.now();\n });\n }\n }\n return { externalIds, timestamps };\n }\n\n async getAudienceModeHands(): Promise<AudienceModeHandsResponse> {\n if (!this._signaling.ready) {\n throw new Error('Signaling is not ready');\n }\n\n const result = await this._signaling.getHandQueue();\n if (result.error) {\n return Promise.reject(result.message);\n }\n\n const participants: SignalingMessage.WaitingParticipant[] = result.participants || [];\n const { externalIds, timestamps } = await this._resolveWaitingHallExternalIds(participants);\n return {\n timestamps,\n participants: externalIds,\n totalCount: result.totalCount || 0,\n };\n }\n\n async promoteParticipant(participantId?: CompositeUserId, demote?: boolean): Promise<void> {\n if (this._signaling && this._conversation) {\n try {\n if (!Utils.includesOneOf(this._conversation.options, [ConversationOption.WAITING_HALL, ConversationOption.AUDIENCE_MODE])) {\n throw new Error('Unable to promote a participant in the conversation with current options');\n }\n this._checkAdminRole();\n if (!participantId && demote) {\n throw new Error('participantId is required');\n }\n await this._signaling.promoteParticipant(participantId, demote);\n } catch (err) {\n Debug.warn(`Failed to promote participant ${participantId}. ${err}`);\n throw err;\n }\n }\n }\n\n async requestPromotion(unrequest = false): Promise<void> {\n if (this._signaling.ready) {\n await this._signaling.requestPromotion(unrequest);\n }\n }\n\n async acceptPromotion(reject = false): Promise<void> {\n if (this._signaling.ready) {\n await this._signaling.acceptPromotion(reject);\n }\n }\n\n async chatMessage(message: string, participantId: CompositeUserId | null = null) {\n if (this._signaling.ready) {\n await this._signaling.chatMessage(message, participantId);\n }\n }\n\n async chatHistory(count: number) {\n if (this._signaling.ready) {\n const data = await this._signaling.chatHistory(count);\n for (let i = data.messages.length - 1; i >= 0; i--) {\n const message = data.messages[i];\n await this._onChatMessage(message);\n }\n }\n }\n\n async customData(data: JSONObject, participantId: ParticipantId | null = null) {\n if (this._signaling.ready) {\n await this._signaling.customData(data, participantId);\n }\n }\n\n async createJoinLink() {\n if (this._conversation) {\n const result = await this._api.createJoinLink(this._conversation.id);\n const link = result.join_link;\n if (link) {\n this._conversation.joinLink = link;\n return link;\n }\n }\n return Promise.reject();\n }\n\n async removeJoinLink() {\n if (this._conversation) {\n const result = await this._api.removeJoinLink(this._conversation.id);\n if (result.success) {\n delete this._conversation.joinLink;\n return;\n }\n }\n return Promise.reject();\n }\n\n async addMovie({ movieId, gain, metadata, lang }: IAddMovieParams): Promise<{ movieId: number; streamType: string }> {\n const data: IAddMovieParams = {\n movieId,\n lang,\n };\n\n if (gain || gain === 0) {\n data.gain = gain;\n }\n\n if (metadata) {\n data.metadata = metadata;\n }\n\n const result = await this._signaling.addMovie(data);\n if (result.error) {\n throw new Error(result.error);\n }\n return {\n movieId: result.movieId,\n streamType: result.streamType,\n };\n }\n\n async updateMovie(params: IUpdateMovieData): Promise<void> {\n const result = await this._signaling.updateMovie(params);\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async removeMovie(movieId: number): Promise<void> {\n const data = {\n movieId,\n };\n\n const result = await this._signaling.removeMovie(data);\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async startUrlSharing(sharedUrl: string): Promise<void> {\n const result = await this._signaling.startUrlSharing(sharedUrl);\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async stopUrlSharing(): Promise<void> {\n const result = await this._signaling.stopUrlSharing();\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async updateRooms(rooms: SignalingMessage.Room[], assignRandomly?: boolean): Promise<void> {\n const result = await this._signaling.updateRooms(rooms, assignRandomly);\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async activateRooms(roomIds: number[], deactivate: boolean): Promise<void> {\n const result = await this._signaling.activateRooms(roomIds, deactivate);\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async switchRoom(toRoomId: number | null, participantId?: ParticipantId): Promise<void> {\n const result = await this._signaling.switchRoom(toRoomId, participantId);\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async removeRooms(roomIds: number[]): Promise<void> {\n const result = await this._signaling.removeRooms(roomIds);\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async startStream(\n isRecord = false,\n name: string | null = null,\n movieId: string | null = null,\n privacy: 'PUBLIC' | 'FRIENDS' | 'DIRECT_LINK' = 'DIRECT_LINK',\n groupId: string | null = null,\n roomId: number | null = MAIN_ROOM_ID,\n ) {\n const data: IStartStreamData = {\n movieId,\n name,\n privacy,\n groupId,\n roomId,\n streamMovie: !isRecord,\n };\n const result = await this._signaling.startStream(data);\n if (result.error) {\n return Promise.reject(result.message);\n }\n }\n\n async stopStream(roomId: number | null = MAIN_ROOM_ID, remove?: boolean) {\n const result = await this._signaling.stopStream({ roomId, ...(remove && { remove }) });\n\n if (result.error) {\n return Promise.reject();\n }\n }\n\n async publishStream(roomId: number | null = MAIN_ROOM_ID) {\n const result = await this._signaling.publishStream({ roomId });\n\n if (result.error) {\n return Promise.reject();\n }\n }\n\n async recordSetConf(king?: ParticipantId, pawns?: ParticipantId[], hideParticipantCount = false, roomId: number | null = MAIN_ROOM_ID): Promise<void> {\n const result = await this._signaling.recordSetConf({\n king,\n pawns,\n hideParticipantCount,\n roomId,\n });\n if (result.error) {\n throw new Error(result.error);\n }\n }\n\n async getStreamInfo() {\n const result = await this._signaling.getRecordStatus();\n return {\n movieId: result.recordMovieId,\n preview: result.recordMoviePreviewUrl,\n };\n }\n\n async setLocalResolution({ video, effect }: { video: IVideoDimentions; effect?: IVideoDimentions }) {\n if (video.width < Params.videoMinWidth || video.height < Params.videoMinHeight) {\n throw new Error('Sizes received are less than the `videoMinWidth` or `videoMinHeight`');\n }\n\n if (effect) {\n if (effect.width < Params.videoMinWidth || effect.height < Params.videoMinHeight) {\n throw new Error('Sizes of effect received are less than the `videoMinWidth` or `videoMinHeight`');\n }\n\n Params.videoEffectMaxHeight = effect.height;\n Params.videoEffectMaxWidth = effect.width;\n }\n\n Params.videoMaxWidth = video.width;\n Params.videoMaxHeight = video.height;\n\n Debug.debug('Set local video resolution:', `video ${video.width}x${video.height}` + (effect ? `, effect ${effect.width}x${effect.height}` : ''));\n\n if (this._mediaSource) {\n await this._mediaSource.setResolution({ video, effect });\n if (this._transport) {\n await this._transport.onCameraResolutionChanged();\n }\n }\n }\n\n async videoEffect(effect: IEffect | null) {\n return this._mediaSource?.videoEffect(effect);\n }\n\n async audioEffect(effects: string[] | null, isPreset?: boolean) {\n return this._mediaSource?.audioEffect(effects ? { effects, isPreset } : null);\n }\n\n _convertExternalIdsToServerExternalIds(externalIds: ExternalId[]) {\n return externalIds.map((externalId) => {\n return { id: externalId.id, type: Params.externalUserType } as SignalingMessage.ExternalId;\n });\n }\n\n async getParticipants(parameters: IGetParticipantsParameters): Promise<ExternalParticipant[]> {\n const serverExternalIds = this._convertExternalIdsToServerExternalIds(parameters.externalIds);\n const result = await this._signaling.getParticipants(serverExternalIds);\n if (result.error) {\n throw new Error(result.error);\n }\n const rawParticipants = result.participants;\n const transportState = this._transport?.getState() as TransportState;\n return Promise.all(\n rawParticipants.map(async (participant) => {\n const participantId = Utils.composeId(participant);\n return this._createParticipant(\n {\n id: participantId,\n externalId: ExternalIdUtils.fromSignalingParticipant(participant),\n mediaSettings: createMediaSettingsWithDefaults(participant.mediaSettings),\n participantState: Utils.mapParticipantState(participant),\n state: participant.state,\n roles: participant.roles || [],\n status: this._getStatusByTransportState(transportState) ?? ParticipantStatus.WAITING,\n muteStates: participant.muteStates || {},\n unmuteOptions: participant.unmuteOptions || [],\n observedIds: participant.observedIds || [],\n markers: this._denormalizeMarkers(participantId, participant.markers),\n },\n participant.decorativeUserId,\n );\n }),\n ).then(Utils.mapSharedParticipants);\n }\n\n async getParticipantListChunk(participantListChunkParameters: ParticipantListChunkParameters): Promise<ExternalParticipantListChunk> {\n Debug.log('Request participant list chunk', participantListChunkParameters);\n const result = await this._signaling.getParticipantListChunk(participantListChunkParameters);\n if (result.error) {\n throw new Error(result.error);\n }\n\n const chunk: SignalingMessage.ParticipantListChunk = this._createParticipantListChunk(result.chunk);\n const cachedParticipants = await this._getParticipants();\n\n const newParticipants = chunk.participants.filter((chunkParticipant) => {\n const participantId = Utils.composeId(chunkParticipant);\n return !cachedParticipants[participantId];\n });\n await this._registerParticipants(newParticipants);\n\n const transportState = this._transport?.getState() as TransportState;\n chunk.participants.forEach((chunkParticipant) => {\n const participantId = Utils.composeId(chunkParticipant);\n const participant = cachedParticipants[participantId];\n participant.status = this._getStatusByTransportState(transportState) ?? ParticipantStatus.WAITING;\n participant.movieShareInfos = chunkParticipant.movieShareInfos;\n Object.assign(participant.mediaSettings, createMediaSettingsWithDefaults(chunkParticipant.mediaSettings));\n Object.assign(participant.muteStates, chunkParticipant.muteStates);\n participant.unmuteOptions = chunkParticipant.unmuteOptions ?? participant.unmuteOptions;\n\n this._openTransport([participant], true);\n });\n\n return this._participantListChunkToExternalChunk(chunk);\n }\n\n private async _getInitialParticiapntListChunk() {\n const fromIdx = Params.participantListChunkInitIndex;\n const count = Params.participantListChunkInitCount;\n const listType = 'GRID';\n const response = await this._signaling.getParticipantListChunk({\n listType,\n fromIdx,\n count,\n });\n Debug.debug('Get initial participant list chunk', response.chunk);\n return response.chunk;\n }\n\n private _onLocalMediaStreamChanged(event: { kind: MediaTrackKind }) {\n if (!this._conversation || !this._mediaSource) {\n return;\n }\n\n const mediaSettings = this._mediaSource.getMediaSettings();\n Debug.debug('Local media stream changed', mediaSettings);\n\n if (event.kind === MediaTrackKind.audio && this._mediaSource) {\n // reset audio fixer\n this._audioFix = new AudioFix(this._mediaSource);\n }\n\n External.onLocalStreamUpdate(mediaSettings, event.kind);\n\n if (!this._conversation?.waitingHall && !this._conversation?.observer && !this._isAudienceModeListener()) {\n this._changeMediaSettings(mediaSettings);\n }\n }\n\n private _onScreenSharingStatus(event: { track: MediaStreamTrack | null }) {\n const mediaSettings = this._mediaSource?.getMediaSettings() as MediaSettings;\n Debug.log('Screen sharing changed', event.track, mediaSettings);\n\n if (Params.consumerScreenTrack) {\n const stream = event.track ? new MediaStream([event.track]) : null;\n External.onScreenStream(stream, mediaSettings);\n }\n }\n\n private async _changeRemoteMediaSettings(participantId: ParticipantId, mediaSettings: MediaSettings): Promise<void> {\n Debug.debug(`Remote media settings changed [${participantId}]`, mediaSettings);\n const localExternalId = this._conversation?.externalId;\n const isMe = this._isMe(participantId);\n\n if (isMe && localExternalId) {\n // TODO: когда СП был привязан к медиасеттингам, потом вынесли его оттуда, а код остался. Скорее всего это не используется нигде.\n External.onLocalMediaSettings(localExternalId, mediaSettings);\n return;\n }\n\n const participant = await this._getParticipant(participantId);\n\n if (!participant) {\n this._warnParticipantNotInConversation(participantId);\n return;\n }\n\n participant.mediaSettings = mediaSettings;\n\n // Media settings might come before UI is initialized\n if (this._state === ConversationState.ACTIVE) {\n External.onRemoteMediaSettings(participant.externalId, mediaSettings, participant.markers);\n }\n\n if (this._specListener) {\n this._specListener.onChangeRemoteMediaSettings(participantId, mediaSettings);\n }\n }\n\n private _extractLocalParticipantFromConnection(connection: SignalingMessage.Connection | SignalingMessage.PromoteParticipant): SignalingMessage.Participant | undefined {\n const userId = this._api.getUserId();\n const me = (connection.conversation.participants || []).find(\n (participant) => participant.id === userId || Utils.comparePeerId(participant.peerId as SignalingMessage.PeerId, connection.peerId),\n );\n return me;\n }\n\n private _changeLocalParticipantState(participantState: ParticipantStateMapped): void {\n Debug.debug('Local participant state force changed by admin', participantState);\n\n if (this._state === ConversationState.ACTIVE) {\n External.onLocalParticipantState(participantState);\n }\n }\n\n private async _changeRemoteParticipantState(participantId: ParticipantId, participantState?: ParticipantStateMapped): Promise<void> {\n Debug.debug(`Remote participant state changed [${participantId}]`, participantState);\n\n const participant = await this._getParticipant(participantId);\n if (!participant) {\n this._warnParticipantNotInConversation(participantId);\n return;\n }\n\n participant.participantState = participantState || {};\n\n if (this._state === ConversationState.ACTIVE) {\n External.onRemoteParticipantState(participant.externalId, participant.participantState, participant.markers);\n }\n }\n\n private async _changeMultipleParticipantState(stateMap: Map<ParticipantId, ParticipantStateMapped>, roomId?: IRoomId): Promise<void> {\n Debug.debug('Multiple participants state changed', stateMap);\n const stateList: ParticipantsStateList = [];\n let myState: ParticipantStateMapped | undefined;\n const cachedParticipants = await this._getParticipants();\n\n stateMap.forEach((state, participantId) => {\n if (this._isMe(participantId)) {\n myState = state;\n } else {\n const participant = cachedParticipants[participantId];\n if (!participant) {\n this._warnParticipantNotInConversation(participantId);\n return;\n }\n participant.participantState = state;\n stateList.push({\n externalId: participant.externalId,\n participantState: { ...state },\n markers: participant.markers,\n });\n }\n });\n\n if (this._state === ConversationState.ACTIVE) {\n if (myState) {\n External.onLocalParticipantState(myState, true);\n }\n if (stateList.length) {\n External.onRemoteParticipantsState(stateList, roomId);\n }\n }\n }\n\n private _invokeRolesChangedCallbackIfNeeded(participant: Participant): void {\n if (this._state !== ConversationState.ACTIVE) {\n return;\n }\n\n if (participant.roles && participant.roles.length) {\n Debug.debug(`Roles for participant [${participant.id}] changed: ${participant.roles}`);\n External.onRolesChanged(participant.externalId, participant.roles, true);\n }\n }\n\n private _onSignalingNotification(message: SignalingMessage) {\n switch (message.notification) {\n case SignalingNotification.ACCEPTED_CALL:\n return this._onAcceptedCall(message as SignalingMessage.AcceptedCall);\n\n case SignalingNotification.HUNGUP:\n return this._onHungup(message as SignalingMessage.Hungup);\n\n case SignalingNotification.PARTICIPANT_ADDED:\n return this._onAddedParticipant(message as SignalingMessage.ParticipantAdded);\n\n case SignalingNotification.PARTICIPANT_JOINED:\n return this._onJoinedParticipant(message as SignalingMessage.ParticipantJoined);\n\n case SignalingNotification.CLOSED_CONVERSATION:\n return this._onClosedConversation(message as SignalingMessage.ClosedConversation);\n\n case SignalingNotification.MEDIA_SETTINGS_CHANGED:\n return this._onMediaSettingsChanged(message as SignalingMessage.MediaSettingsChanged);\n\n case SignalingNotification.PARTICIPANT_STATE_CHANGED:\n return this._onParticipantStateChanged(message as SignalingMessage.ParticipantStateChanged);\n\n case SignalingNotification.PARTICIPANTS_STATE_CHANGED:\n return this._onParticipantsStateChanged(message as SignalingMessage.ParticipantsStateChanged);\n\n case SignalingNotification.RATE_CALL_DATA:\n return this._onNeedRate();\n\n case SignalingNotification.FEATURE_SET_CHANGED:\n return this._onFeatureSetChanged(message as SignalingMessage.FeatureSetChanged);\n\n case SignalingNotification.MULTIPARTY_CHAT_CREATED:\n return this._onMultipartyChatCreated(message as SignalingMessage.MultipartyChatCreated);\n\n case SignalingNotification.FORCE_MEDIA_SETTINGS_CHANGE:\n return this._onForceMediaSettingsChange(message as SignalingMessage.ForceMediaSettingsChange);\n\n case SignalingNotification.SETTINGS_UPDATE:\n return this._onSettingsUpdate(message as SignalingMessage.SettingsUpdate);\n\n case SignalingNotification.VIDEO_QUALITY_UPDATE:\n return this._onVideoQualityUpdate(message as SignalingMessage.VideoQualityUpdate);\n\n case SignalingNotification.REGISTERED_PEER:\n return this._onPeerRegistered(message as SignalingMessage.RegisteredPeer);\n\n case SignalingNotification.SWITCH_MICRO:\n return this._onMicSwitched(message as SignalingMessage.SwitchMicro);\n\n case SignalingNotification.CHAT_MESSAGE:\n return this._onChatMessage(message as SignalingMessage.ChatMessage);\n\n case SignalingNotification.CUSTOM_DATA:\n return this._onCustomData(message as SignalingMessage.CustomData);\n\n case SignalingNotification.RECORD_STARTED:\n return this._onRecordInfo(message.recordInfo, message.roomId);\n\n case SignalingNotification.RECORD_STOPPED:\n return this._onStopRecordInfo(message as SignalingMessage.RecordStopped, message.roomId);\n\n case SignalingNotification.ROLES_CHANGED:\n return this._onRolesChanged(message.participantId, message.roles || []);\n\n case SignalingNotification.MUTE_PARTICIPANT:\n return this._onMuteParticipant(message as SignalingMessage.MuteParticipant);\n\n case SignalingNotification.PIN_PARTICIPANT:\n return this._onPinParticipant(message.participantId, message.unpin, message.markers, message.roomId);\n\n case SignalingNotification.OPTIONS_CHANGED:\n return this._onOptionsChanged(message.options || []);\n\n case SignalingNotification.PARTICIPANT_SOURCES_UPDATE:\n return this._onParticipantSourcesUpdate(message as SignalingMessage.ParticipantSourcesUpdateNotification);\n\n case SignalingNotification.PROMOTE_PARTICIPANT:\n return this._onParticipantPromoted(message as SignalingMessage.PromoteParticipant);\n\n case SignalingNotification.CHAT_ROOM_UPDATED:\n // https://wiki.odkl.ru/display/projects/Signaling+API#SignalingAPI-chat-room-updated\n return this._onChatRoomUpdated(message.eventType, message.totalCount, message.firstParticipants, message.addedParticipantIds, message.removedParticipantIds);\n\n case SignalingNotification.JOIN_LINK_CHANGED:\n return this._onJoinLinkChanged(message as SignalingMessage.JoinLinkChanged);\n\n case SignalingNotification.FEEDBACK:\n return this._onFeedback(message as SignalingMessage.Feedback);\n\n case SignalingNotification.MOVIE_UPDATE_NOTIFICATION:\n return this._onSharedMovieUpdate(message as SignalingMessage.SharedMovieState);\n\n case SignalingNotification.MOVIE_SHARE_STARTED:\n return this._onSharedMovieInfoStarted(message as SignalingMessage.SharedMovieInfo);\n\n case SignalingNotification.MOVIE_SHARE_STOPPED:\n return this._onSharedMovieInfoStopped(message as SignalingMessage.SharedMovieStoppedInfo);\n\n case SignalingNotification.URL_SHARING_INFO_UPDATED:\n return this._onUrlSharingInfoUpdated(message as SignalingMessage.UrlSharingInfo);\n\n case SignalingNotification.ROOMS_UPDATED:\n return this._onRoomsUpdated(message as SignalingMessage.RoomsUpdated);\n\n case SignalingNotification.ROOM_UPDATED:\n return this._onRoomUpdated(message as SignalingMessage.RoomUpdated);\n\n case SignalingNotification.ROOM_PARTICIPANTS_UPDATED:\n return this._onRoomParticipantsUpdated(message as SignalingMessage.RoomParticipantsUpdated);\n\n case SignalingNotification.FEATURES_PER_ROLE_CHANGED: {\n return this._onFeaturesPerRoleChanged(message as SignalingMessage.FeaturesPerRoleChanged);\n }\n\n case SignalingNotification.PARTICIPANT_ANIMOJI_CHANGED: {\n return this._onParticipantAnimojiChanged(message as SignalingMessage.ParticipantAnimojiChanged);\n }\n\n case SignalingNotification.ASR_STARTED: {\n return this._onAsrStart(message as SignalingMessage.AsrStartNotification);\n }\n\n case SignalingNotification.ASR_STOPPED: {\n return this._onAsrStop(message as SignalingMessage.AsrStopNotification);\n }\n\n case SignalingNotification.PROMOTION_APPROVED: {\n return this._onPromotionApproved(message as SignalingMessage.PromotionApproved);\n }\n\n case SignalingNotification.DECORATIVE_PARTICIPANT_ID_CHANGED: {\n return this._onDecorativeParticipantIdChanged(message as SignalingMessage.DecorativeParticipantIdChanged);\n }\n\n case SignalingNotification.VIDEO_SUSPEND_SUGGEST: {\n return this._onVideoSuspendSuggest(message as SignalingMessage.VideoSuspendSuggest);\n }\n }\n }\n\n private async _onPromotionApproved(message: SignalingMessage.PromotionApproved) {\n const externalId = await this._getExternalIdByParticipantId(message.adminId);\n\n if (!externalId) {\n this._warnParticipantNotInConversation(message.adminId);\n return;\n }\n\n External.onPromotionApproved(externalId);\n }\n\n private async _onSignalingReconnect(connection: SignalingMessage.Connection) {\n if (!this._conversation) {\n return;\n }\n\n if (connection.conversation.acceptTime) {\n this._conversation.acceptTime = connection.conversation.acceptTime;\n }\n\n if (connection.conversation.participantsLimit) {\n this._conversation.participantsLimit = connection.conversation.participantsLimit;\n }\n\n if (connection.conversation.features) {\n this._conversation.features = connection.conversation.features;\n this._conversation.featuresPerRole = connection.conversation.featuresPerRole;\n this._changeFeatureSet();\n this._changeFeaturesPerRole();\n }\n\n await this._processPinnedParticipants(connection);\n\n if (connection.conversation.state) {\n // TODO: Обработать state !== ACTIVE\n }\n\n let localMuteStatesCallback: VoidFunction | null = null;\n\n if (connection.conversation.participants) {\n // Собеседники, которые были до реконнекта\n const oldParticipantIds = Object.keys(await this._getParticipants());\n // Собеседники, которые пришли с реконнектом\n const newParticipantIds: ParticipantId[] = [];\n\n // Проверим, не добавились ли собеседники\n for (const newParticipant of connection.conversation.participants) {\n const newPid = Utils.composeId(newParticipant);\n const newRoles = newParticipant.roles || [];\n if (this._isMe(newPid)) {\n // Это я\n if (!compareUserRoles(this._conversation.roles, newRoles)) {\n this._onRolesChanged(newPid, newRoles);\n }\n // Установим состояние локальных мьютов\n localMuteStatesCallback = () => {\n this._registerParticipantLocalMuteState({\n muteStates: filterReconnectedParticipantMuteStates(newParticipant),\n unmuteOptions: newParticipant.unmuteOptions,\n });\n };\n continue;\n }\n\n newParticipantIds.push(newPid);\n\n const participant = await this._getParticipant(newPid);\n if (!participant) {\n // В старом списке нет такого - добавляем\n await this._onJoinedParticipant({\n participantId: newParticipant.id,\n participant: newParticipant,\n mediaSettings: newParticipant.mediaSettings,\n });\n } else {\n const ms = createMediaSettingsWithDefaults(newParticipant.mediaSettings);\n if (!compareMediaSettings(ms, participant.mediaSettings)) {\n // В старом списке такой есть, но изменились медиасеттинги\n await this._changeRemoteMediaSettings(newPid, ms);\n }\n\n const newState = Utils.mapParticipantState(newParticipant);\n const oldState = participant.participantState;\n if (!Utils.isEqualParticipantState(newState, oldState)) {\n // В старом списке такой есть, но изменились состояния\n await this._changeRemoteParticipantState(newPid, newState);\n }\n\n if (!compareUserRoles(newRoles, participant.roles)) {\n // В старом списке такой есть, но изменились роли\n this._onRolesChanged(participant.id, newRoles);\n }\n }\n }\n\n const cachedParticipants = await this._getParticipants();\n // Проверим, не удалились ли собеседники\n for (const oldPid of oldParticipantIds) {\n /**\n * @todo `cachedParticipants[oldPid]` нужно так как бывают случаи, что в нем уже не оказывается объекта\n * на момент, когда мы тут. Убрать это условие после перехода на синхронный стейт партисипантов\n */\n if (newParticipantIds.indexOf(oldPid) < 0 && cachedParticipants[oldPid]) {\n // В новом списке нет такого собеседника - удаляем\n this._removeParticipant(cachedParticipants[oldPid], HangupType.HUNGUP);\n }\n }\n }\n\n // сменим комнату, если нужно\n const nextRoomId = connection.rooms?.roomId ?? MAIN_ROOM_ID;\n // todo: рефакторинг Conversation на более мелкие части\n // Сейчас иногда в this.conversation оказывается null в этом месте\n if (!this._conversation) {\n Debug.warn('Conversation is empty, but should be filled');\n return;\n }\n\n const isRoomSwitched = this._conversation.roomId !== nextRoomId;\n if (isRoomSwitched) {\n await this._onRoomSwitched(nextRoomId);\n } else {\n this._processMuteStates(connection, true);\n }\n\n localMuteStatesCallback?.();\n\n this._processRecordInfos(connection);\n this._onOptionsChanged(connection.conversation.options);\n }\n\n private _onSignalingFailed(error: any): void {\n Debug.error('Signaling failed', error);\n this._close(error);\n }\n\n private async _onAcceptedCall(message: SignalingMessage.AcceptedCall): Promise<void> {\n const participantId = Utils.composeMessageId(message);\n const peerId = Utils.getPeerIdString(message.peerId);\n\n Debug.debug(`Participant accepted call [${participantId}]`);\n\n this._statFirstMediaReceived.markAcceptedCall(this._transport?.getTopology());\n\n if (this._conversation && this._isMe(participantId)) {\n this._close(new HangupReason(HangupType.MISSED), 'Call accepted on other device');\n return;\n }\n\n let participant = await this._getParticipant(participantId);\n if (!participant) {\n const decorativeOkId = this._api.getDecorativeIdByInitialId(participantId);\n const decorativeId = decorativeOkId ? Utils.composeUserId(decorativeOkId, message.participantType) : undefined;\n\n participant = this._registerParticipantInCache(\n await this._createParticipant(\n {\n id: participantId,\n mediaSettings: createMediaSettingsWithDefaults(message.mediaSettings),\n },\n decorativeId,\n ),\n );\n }\n\n participant.state = ParticipantState.ACCEPTED;\n participant.mediaSettings = createMediaSettingsWithDefaults(message.mediaSettings);\n this._logWithMediaSettings(StatLog.ACCEPTED_OUTGOING, participant.mediaSettings);\n\n if (\n this._conversation &&\n this._conversation.direction === CallDirection.OUTGOING &&\n (this._state === ConversationState.IDLE || this._state === ConversationState.PROCESSING)\n ) {\n this._state = ConversationState.ACTIVE;\n this._changeFeatureSet();\n }\n\n // If we haven't accept call yet, we cannot open transport\n // because we haven't requested local media stream yet.\n // So we postpone opening until we accept the call\n if (this._state === ConversationState.ACTIVE && this._transport) {\n this._transport.open([participant.id], peerId);\n }\n\n await this._changeRemoteMediaSettings(participantId, participant.mediaSettings);\n await this._changeRemoteParticipantState(participantId);\n const mediaOptions = Object.keys(participant.muteStates) as MediaOption[];\n if (mediaOptions.length) {\n this._onMuteParticipant({ muteStates: participant.muteStates, mediaOptions, stateUpdated: true, participantId });\n }\n if (this._state === ConversationState.ACTIVE) {\n External.onAcceptedCall(participant.externalId, SignalingCapabilities.parseCapabilities(message.capabilities));\n }\n }\n\n private async _onHungup(message: SignalingMessage.Hungup): Promise<void> {\n Debug.debug(`Participant hungup [${message.participantId}]`, { reason: message.reason });\n\n const participantId = Utils.composeMessageId(message);\n if (this._conversation && this._isMe(participantId)) {\n this._close(new HangupReason(message.reason, { remote: true }));\n return;\n }\n\n await this._registerParticipantAndSetMarkersIfChunkEnabled(participantId, message.markers);\n const participant = await this._getParticipant(participantId);\n if (!participant) {\n this._warnParticipantNotInConversation(participantId);\n return;\n }\n\n if (this._transport) {\n this._transport.close(participantId);\n }\n\n participant.state = message.reason === HangupType.REJECTED ? ParticipantState.REJECTED : ParticipantState.HUNGUP;\n\n if (this._state !== ConversationState.CLOSE) {\n this._removeParticipant(participant, HangupType.HUNGUP);\n }\n }\n\n private async _onAddedParticipant(message: SignalingMessage.ParticipantAdded): Promise<void> {\n Debug.debug(`Participant added [${message.participantId}]`);\n\n const participantId = Utils.composeMessageId(message);\n let participant = await this._getParticipant(participantId);\n if (participant && participant.state !== ParticipantState.HUNGUP && participant.state !== ParticipantState.REJECTED) {\n Debug.debug(`Participant [${participantId}] is already in conversation and is active`);\n return;\n }\n\n if (!participant) {\n const { participant: sigParticipant } = message;\n const decorativeId = sigParticipant.decorativeUserId;\n this._registerParticipant(\n {\n id: participantId,\n externalId: ExternalIdUtils.fromSignalingParticipant(sigParticipant),\n mediaSettings: createMediaSettingsWithDefaults(sigParticipant.mediaSettings),\n state: sigParticipant.state,\n participantState: Utils.mapParticipantState(sigParticipant),\n roles: sigParticipant.roles || [],\n muteStates: sigParticipant.muteStates || {},\n unmuteOptions: sigParticipant.unmuteOptions || [],\n observedIds: sigParticipant.observedIds || [],\n },\n decorativeId,\n );\n\n participant = await this._getParticipant(participantId);\n }\n\n participant.state = ParticipantState.CALLED;\n participant.mediaSettings = createMediaSettingsWithDefaults(message.participant?.mediaSettings);\n participant.participantState = Utils.mapParticipantState(message.participant);\n participant.roles = message.participant?.roles || [];\n\n this._setParticipantsStatus([participant], ParticipantStatus.WAITING);\n\n // If we haven't accept call yet, we cannot allocate transport\n // because we haven't requested local media stream yet.\n // So we postpone allocation until we accept the call\n if (this._state !== ConversationState.IDLE && this._transport) {\n this._transport.allocate(participant.id, true);\n }\n\n External.onParticipantAdded(participant.externalId, participant.markers);\n await this._changeRemoteMediaSettings(participantId, participant.mediaSettings);\n await this._changeRemoteParticipantState(participantId, participant.participantState);\n this._invokeRolesChangedCallbackIfNeeded(participant);\n }\n\n private async _onJoinedParticipant(message: SignalingMessage.ParticipantJoined): Promise<void> {\n Debug.debug(`Participant joined [${message.participantId}]`);\n this._statFirstMediaReceived.markParticipantJoined(this._transport?.getTopology() as TransportTopology);\n\n const participantId = Utils.composeMessageId(message);\n let participant = await this._getParticipant(participantId);\n if (participant && participant.state === ParticipantState.ACCEPTED) {\n Debug.warn(`Participant [${participantId}] is already in conversation and is active`);\n return;\n }\n\n if (!participant) {\n const { participant: sigParticipant } = message;\n const decorativeId = sigParticipant.decorativeUserId;\n this._registerParticipant(\n {\n id: participantId,\n externalId: ExternalIdUtils.fromSignalingParticipant(sigParticipant),\n mediaSettings: createMediaSettingsWithDefaults(sigParticipant.mediaSettings),\n state: sigParticipant.state,\n participantState: Utils.mapParticipantState(sigParticipant),\n roles: sigParticipant.roles || [],\n muteStates: sigParticipant.muteStates || {},\n movieShareInfos: sigParticipant.movieShareInfos,\n unmuteOptions: sigParticipant.unmuteOptions || [],\n observedIds: sigParticipant.observedIds || [],\n markers: this._denormalizeMarkers(participantId, sigParticipant.markers),\n },\n decorativeId,\n );\n\n participant = await this._getParticipant(participantId);\n }\n\n if (\n this._conversation &&\n this._conversation.direction === CallDirection.OUTGOING &&\n (this._state === ConversationState.IDLE || this._state === ConversationState.PROCESSING)\n ) {\n this._state = ConversationState.ACTIVE;\n this._changeFeatureSet();\n }\n\n participant.state = ParticipantState.ACCEPTED;\n participant.mediaSettings = createMediaSettingsWithDefaults(message.mediaSettings);\n participant.participantState = Utils.mapParticipantState(message.participant);\n participant.roles = message.participant.roles || [];\n\n if (this._transport?.isAllocated(participant.id)) {\n this._setParticipantsStatus([participant], ParticipantStatus.CONNECTED);\n } else {\n this._setParticipantsStatus([participant], ParticipantStatus.WAITING);\n }\n\n // If we haven't accept call yet, we cannot allocate transport\n // because we haven't requested local media stream yet.\n // So we postpone allocation until we accept the call\n if (this._state !== ConversationState.IDLE && this._transport) {\n if (!this._transport.isAllocated(participant.id)) {\n this._transport.allocate(participant.id, true);\n }\n this._transport.open([participant.id], null, !!this._conversation?.observer);\n }\n\n External.onParticipantJoined(participant.externalId, participant.markers);\n await this._changeRemoteMediaSettings(participantId, participant.mediaSettings);\n await this._changeRemoteParticipantState(participantId, participant.participantState);\n this._invokeRolesChangedCallbackIfNeeded(participant);\n const mediaOptions = Object.keys(participant.muteStates) as MediaOption[];\n if (mediaOptions.length) {\n this._onMuteParticipant({ muteStates: participant.muteStates, mediaOptions, stateUpdated: true, participantId });\n }\n await this._processSharedMovieInfos(participant.movieShareInfos);\n }\n\n private _onClosedConversation(message: SignalingMessage.ClosedConversation): void {\n this._toggleJoinAvailability();\n this._close(new HangupReason(message.reason, { remote: true }));\n }\n\n private async _onMediaSettingsChanged(message: SignalingMessage.MediaSettingsChanged): Promise<void> {\n const participantId = Utils.composeMessageId(message);\n await this._registerParticipantAndSetMarkersIfChunkEnabled(participantId, message.markers);\n await this._changeRemoteMediaSettings(participantId, createMediaSettingsWithDefaults(message.mediaSettings));\n }\n\n private async _onParticipantStateChanged(message: SignalingMessage.ParticipantStateChanged): Promise<void> {\n const participantId = Utils.composeMessageId(message);\n const nextState = Utils.mapParticipantState(message);\n\n if (this._isMe(participantId)) {\n this._changeLocalParticipantState(nextState);\n } else {\n await this._registerParticipantAndSetMarkersIfChunkEnabled(participantId, message.markers);\n await this._changeRemoteParticipantState(participantId, nextState);\n }\n }\n\n private async _onParticipantsStateChanged(message: SignalingMessage.ParticipantsStateChanged): Promise<void> {\n // participants also may contain current user\n const { participants, roomId } = message;\n const registerMarkersPromises = participants.map(({ id, markers }) => this._registerParticipantAndSetMarkersIfChunkEnabled(id, markers));\n await Promise.all(registerMarkersPromises);\n\n const stateMap: Map<ParticipantId, ParticipantStateMapped> = new Map();\n const idPromises: Promise<[CompositeUserId, undefined | ParticipantStateMapped]>[] = participants.map(({ id, participantState }) =>\n this._getExternalIdByParticipantId(id).then((externalId) => {\n return [id, externalId && Utils.mapParticipantState({ participantState })];\n }),\n );\n\n try {\n const results = await Promise.all(idPromises);\n results.forEach(([id, stateMapped]) => {\n if (stateMapped) {\n stateMap.set(id, stateMapped);\n }\n });\n await this._changeMultipleParticipantState(stateMap, roomId);\n } catch (err) {\n Debug.warn(`_onParticipantsStateChanged: Failed to get external ids. ${err}`);\n }\n }\n\n private _onNeedRate(): void {\n if (this._conversation) {\n this._conversation.needRate = true;\n this._changeNeedRate();\n }\n }\n\n private _onFeatureSetChanged(message: SignalingMessage.FeatureSetChanged): void {\n if (this._conversation) {\n this._conversation.features = message.features;\n this._changeFeatureSet();\n }\n }\n\n private _onMultipartyChatCreated(message: SignalingMessage.MultipartyChatCreated): void {\n if (this._conversation) {\n this._conversation.chatId = message.chatId;\n this._toggleJoinAvailability();\n External.onMultipartyChatCreated(this._conversation);\n }\n }\n\n private async _onForceMediaSettingsChange(message: SignalingMessage.ForceMediaSettingsChange) {\n if (!this._mediaSource) {\n return;\n }\n\n const mediaSettings = this._mediaSource.getMediaSettings();\n const newMediaSettings = createMediaSettingsWithDefaults(message.mediaSettings);\n if (mediaSettings.isAudioEnabled !== newMediaSettings.isAudioEnabled) {\n await this._mediaSource.toggleAudio(newMediaSettings.isAudioEnabled);\n }\n if (mediaSettings.isVideoEnabled !== newMediaSettings.isVideoEnabled) {\n await this._mediaSource.toggleVideo(newMediaSettings.isVideoEnabled);\n }\n if (Params.consumerScreenTrack && mediaSettings.isScreenSharingEnabled !== newMediaSettings.isScreenSharingEnabled) {\n await this._mediaSource.toggleScreenCapturing({\n captureScreen: newMediaSettings.isScreenSharingEnabled,\n fastScreenSharing: newMediaSettings.isFastScreenSharingEnabled,\n captureAudio: newMediaSettings.isAudioSharingEnabled,\n });\n }\n }\n\n private _onSettingsUpdate(message: SignalingMessage.SettingsUpdate) {\n Debug.debug('Got settings update notification', message);\n\n const delta: ServerSettings = { camera: message.camera, screenSharing: message.screenSharing, fastScreenSharing: message.fastScreenSharing };\n this._serverSettings = merge(this._serverSettings, delta);\n\n if (this._transport) {\n this._transport.updateSettings(this._serverSettings);\n }\n }\n\n private _onVideoQualityUpdate(message: SignalingMessage.VideoQualityUpdate) {\n Debug.debug('Got video quality update notification', message);\n\n const maxBitrateK = Math.round(message.quality.maxBitrate / 1024);\n const maxDimension = message.quality.maxDimension;\n const videoSettings = { maxBitrateK, maxDimension };\n\n let delta: ServerSettings;\n if (message.mediaType && message.mediaType === MediaType.SCREEN) {\n delta = { camera: null, screenSharing: null, fastScreenSharing: Object.assign({}, this._serverSettings.fastScreenSharing, videoSettings) };\n } else {\n delta = { camera: Object.assign({}, this._serverSettings.camera, videoSettings), screenSharing: null, fastScreenSharing: null };\n }\n this._serverSettings = merge(this._serverSettings, delta);\n\n if (this._transport) {\n this._transport.updateSettings(this._serverSettings);\n }\n }\n\n private async _onPeerRegistered(message: SignalingMessage.RegisteredPeer): Promise<void> {\n const participantId = Utils.composeMessageId(message);\n const participant = await this._getParticipant(participantId);\n if (participant) {\n participant.clientType = message.clientType;\n participant.platform = message.platform;\n }\n // Используется только в p2p для учета статистики\n External.onPeerRegistered();\n }\n\n private async _onMicSwitched(message: SignalingMessage.SwitchMicro): Promise<void> {\n External.onDeviceSwitched(MediaOption.AUDIO, !message.mute);\n await this.toggleLocalAudio(!message.mute);\n }\n\n private async _onChatMessage(message: SignalingMessage.ChatMessage): Promise<void> {\n const participantId = Utils.composeMessageId(message);\n const externalId = await this._getExternalIdByParticipantId(participantId);\n\n if (!externalId) {\n this._warnParticipantNotInConversation(participantId);\n return;\n }\n\n External.onChatMessage(message.message, externalId, message.direct);\n }\n\n private async _onCustomData(message: SignalingMessage.CustomData): Promise<void> {\n // Внутренние события типа плохой сети на p2p\n if (Object.hasOwn(message.data, 'sdk')) {\n return;\n }\n\n const participantId = Utils.composeMessageId(message);\n const externalId = await this._getExternalIdByParticipantId(participantId);\n\n if (!externalId) {\n this._warnParticipantNotInConversation(participantId);\n return;\n }\n\n External.onCustomData(message.data, externalId, message.direct);\n }\n\n private async _onRecordInfo(recordInfo: RecordInfo | null, roomId: number | null = MAIN_ROOM_ID): Promise<void> {\n if (!this._conversation || !recordInfo) {\n return;\n }\n\n const existingRecordInfo = this._conversation.recordsInfoByRoom.get(roomId);\n\n const isChanged = existingRecordInfo?.recordMovieId !== recordInfo?.recordMovieId || existingRecordInfo?.recordStartTime !== recordInfo?.recordStartTime;\n\n if (isChanged) {\n this._conversation.recordsInfoByRoom.set(roomId, recordInfo);\n\n const externalId = await this._getExternalIdByParticipantId(recordInfo.initiator);\n if (externalId) {\n External.onRecordStarted(\n externalId,\n recordInfo.recordMovieId,\n recordInfo.recordStartTime,\n recordInfo.recordType,\n recordInfo.recordExternalMovieId,\n recordInfo.recordExternalOwnerId,\n roomId,\n );\n } else {\n this._warnParticipantNotInConversation(recordInfo.initiator);\n }\n }\n }\n\n private async _onStopRecordInfo({ participant, recordMovieId }: SignalingMessage.RecordStopped, roomId: number | null = MAIN_ROOM_ID): Promise<void> {\n if (!this._conversation) {\n return;\n }\n const recordInfo = this._conversation.recordsInfoByRoom.get(roomId);\n if (!recordInfo || recordInfo.recordMovieId !== recordMovieId) {\n return;\n }\n\n this._conversation.recordsInfoByRoom.set(roomId, null);\n\n if (participant) {\n const externalIdStopBy = await this._getExternalIdByParticipantId(participant);\n External.onRecordStopped(roomId, externalIdStopBy ?? null);\n } else {\n External.onRecordStopped(roomId, null);\n }\n }\n\n private async _changePinnedParticipantForRoom(): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n const roomId = this._conversation.roomId;\n const pinnedParticipantId = this._conversation.pinnedParticipantIdByRoom.get(roomId);\n if (pinnedParticipantId && !this._isMe(pinnedParticipantId)) {\n const externalId = await this._getExternalIdByParticipantId(pinnedParticipantId);\n if (externalId) {\n External.onPinnedParticipant(externalId, false, null, roomId);\n }\n }\n }\n\n async _changeRecordInfoForRoom(): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n const roomId = this._conversation.roomId;\n const recordInfo = this._conversation.recordsInfoByRoom.get(roomId);\n\n if (recordInfo) {\n const externalId = await this._getExternalIdByParticipantId(recordInfo.initiator);\n if (externalId) {\n External.onRecordStarted(\n externalId,\n recordInfo.recordMovieId,\n recordInfo.recordStartTime,\n recordInfo.recordType,\n recordInfo.recordExternalMovieId,\n recordInfo.recordExternalOwnerId,\n roomId,\n );\n } else {\n this._warnParticipantNotInConversation(recordInfo.initiator);\n }\n } else {\n External.onRecordStopped(roomId, null);\n }\n }\n\n private async _changeAsrInfoForRoom(): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n const roomId = this._conversation.roomId;\n const asrInfo = this._conversation.asrInfoByRoom.get(roomId);\n if (asrInfo) {\n const externalId = await this._getExternalIdByParticipantId(asrInfo.initiatorId);\n if (externalId) {\n External.onAsrSet(\n {\n externalId,\n movieId: asrInfo.movieId,\n },\n roomId,\n );\n }\n } else {\n External.onAsrSet(null, roomId);\n }\n }\n\n private async _changeUrlSharingInfoForRoom(): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n const { roomId } = this._conversation;\n const { urlSharingInfoByRoom } = this._conversation;\n const urlSharingInfo = urlSharingInfoByRoom.get(roomId);\n\n // this method is called when user moves to room, so he can not be an initiator\n if (urlSharingInfo) {\n const externalId = await this._getExternalIdByParticipantId(urlSharingInfo.initiatorId);\n if (externalId) {\n External.onRemoteSharedUrl(externalId, urlSharingInfo.sharedUrl, roomId);\n }\n }\n }\n\n private async _onParticipantAnimojiChanged(message: SignalingMessage.ParticipantAnimojiChanged): Promise<void> {\n if (this._conversation) {\n const externalId = await this._getExternalIdByParticipantId(message.participantId);\n\n if (!externalId) {\n this._warnParticipantNotInConversation(message.participantId);\n return;\n }\n\n External.onParticipantVmojiUpdate(externalId);\n }\n }\n\n private async _onAsrStart(message: SignalingMessage.AsrStartNotification) {\n if (!this._conversation) {\n return;\n }\n\n const asrInfo = message.asrInfo;\n const roomId = message.roomId || MAIN_ROOM_ID;\n\n this._conversation.asrInfoByRoom.set(roomId, asrInfo);\n\n const externalId = await this._getExternalIdByParticipantId(asrInfo.initiatorId);\n\n if (!externalId) {\n this._warnParticipantNotInConversation(asrInfo.initiatorId);\n return;\n }\n\n External.onAsrStarted(externalId, asrInfo.movieId, roomId);\n }\n\n private _onAsrStop(message: SignalingMessage.AsrStopNotification) {\n if (!this._conversation) {\n return;\n }\n\n const roomId = message.roomId || MAIN_ROOM_ID;\n\n if (roomId === MAIN_ROOM_ID) {\n this._conversation.asrInfo = null;\n }\n this._conversation.asrInfoByRoom.delete(roomId);\n\n External.onAsrStopped(roomId);\n }\n\n private async _onAsrTranscription(asr: AsrTranscription): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n const externalId = await this._getExternalIdByParticipantId(asr.participantId);\n\n if (!externalId) {\n this._warnParticipantNotInConversation(asr.participantId);\n return;\n }\n\n External.onAsrTranscription(externalId, asr.text, asr.timestamp, asr.duration);\n }\n\n private async _onRolesChanged(participantId: ParticipantId, roles: UserRole[]): Promise<void> {\n if (this._conversation && this._isMe(participantId) && !compareUserRoles(this._conversation.roles, roles)) {\n Debug.debug(`Local roles changed: ${roles}`);\n this._conversation.roles = roles;\n External.onLocalRolesChanged(roles);\n\n // При изменении ролей пользователя нужно перепроверить только перамамьюты\n this._processMuteState({\n mediaOptions: getMediaOptionsByMuteState(this._getMuteStatesForCurrentRoom(), MuteState.MUTE_PERMANENT),\n stateUpdated: true, // включаем насильно, чтобы админам возвращался пермамьют\n });\n\n if (Utils.includesOneOf(roles, [UserRole.ADMIN, UserRole.CREATOR])) {\n // Если стал админом, то запрашиваем информацию по залам\n this._refreshRooms(true);\n } else if (!roles.length) {\n // Если потерял админство, то возвращаем в основной зал\n this._onRoomSwitched(MAIN_ROOM_ID);\n }\n\n return;\n }\n\n const participant = await this._getParticipant(participantId);\n if (participant && !compareUserRoles(participant.roles, roles)) {\n Debug.debug(`Roles for participant [${participantId}] changed: ${roles}`);\n participant.roles = roles;\n External.onRolesChanged(participant.externalId, roles);\n }\n }\n\n /**\n * Клиент должен немедленно выключить микрофон и/или камеру\n */\n private async _onMuteParticipant(message: SignalingMessage.MuteParticipant, isReconnect = false): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n const { muteAll, muteStates = {}, unmuteOptions = [], mediaOptions = [], roomId = MAIN_ROOM_ID } = message;\n\n // Админы получают изменения состояний других участников\n if (message.participantId && !this._isMe(message.participantId)) {\n if (!this._isCallAdmin()) {\n Debug.warn(`Not admin got mute states for participant [${message.participantId}]`);\n return;\n }\n\n const participant = await this._getParticipant(message.participantId);\n if (participant) {\n Debug.debug(`Mute states for participant [${message.participantId}] changed`, muteStates);\n const adminExternalId = message.adminId ? await this._getExternalIdByParticipantId(message.adminId) : null;\n External.onMuteStates(\n muteStates,\n unmuteOptions,\n mediaOptions,\n muteAll,\n message.unmute,\n participant.externalId,\n adminExternalId,\n message.stateUpdated,\n message.requestedMedia,\n message.roomId,\n );\n }\n return;\n }\n\n if (!message.requestedMedia?.length) {\n if (muteAll && !isReconnect) {\n // на рекконектах мы обновляем состояние комнаты в _processMuteStates\n this._setMuteStatesForRoomId(muteStates, roomId);\n } else if (!muteAll) {\n this._conversation.muteStatesPersonal = muteStates;\n }\n }\n\n // Если мьют отправлял я, не выключаю камеру себе\n if (message.adminId && this._isMe(message.adminId)) {\n // нужно сообщить себе о текущем состоянии звонка\n if (muteAll) {\n External.onMuteStates(\n muteStates,\n unmuteOptions,\n mediaOptions,\n muteAll,\n message.unmute,\n null,\n this._conversation.externalId,\n message.stateUpdated,\n message.requestedMedia,\n message.roomId,\n );\n }\n return;\n }\n\n await this._processMuteState({\n mediaOptions,\n muteAll,\n unmute: message.unmute,\n adminId: message.adminId,\n stateUpdated: message.stateUpdated,\n requestedMedia: message.requestedMedia,\n roomId: message.roomId,\n unmuteOptions,\n muteStates,\n });\n }\n\n private _changeMuteStatesForRoom(roomId: IRoomId, prevRoomId: IRoomId): void {\n if (!this._conversation) {\n return;\n }\n\n const prevRoomMuteStates = this._getMuteStatesForRoomId(prevRoomId);\n const roomMuteStates = this._getMuteStatesForRoomId(roomId);\n const prevMediaOptions = Object.keys(prevRoomMuteStates);\n const mediaOptions = Object.keys(roomMuteStates);\n\n this._processMuteState({\n mediaOptions: Array.from(new Set([...prevMediaOptions, ...mediaOptions])) as MediaOption[],\n roomId,\n muteAll: true,\n stateUpdated: true,\n });\n }\n\n private async _processMuteState(message: Partial<SignalingMessage.MuteParticipant>): Promise<void> {\n if (!this._conversation || !this._mediaSource || this._participantState !== ParticipantState.ACCEPTED) {\n return;\n }\n\n const { mediaOptions = [], muteAll, unmute, stateUpdated, requestedMedia, roomId = MAIN_ROOM_ID, unmuteOptions = [] } = message;\n const adminExternalId = message.adminId ? await this._getExternalIdByParticipantId(message.adminId) : null;\n // Сохраним оригинальные стейты, но отправить можем другие (например для админа)\n const muteStates = Object.assign({}, message.muteStates ?? this._getMuteStatesForRoomId(roomId));\n const mediaSettings = this._mediaSource.getMediaSettings();\n const muteEntries = Object.entries(muteStates) as [MediaOption, MuteState][];\n\n // Отключаем устройства, если нужно\n for (const [mediaOption, muteState] of muteEntries) {\n // Если участиник админ, то реагировать на эти события не нужно\n const isMuteAllForAdmin = Params.newMuteRules && this._isCallAdmin() && muteAll;\n\n if ((muteState !== MuteState.MUTE && muteState !== MuteState.MUTE_PERMANENT) || isMuteAllForAdmin) {\n continue;\n }\n\n // Для админов сбрасываем MUTE_PERMANENT, т.к. они могут размьютиться всегда\n if (\n this._isCallAdmin() &&\n muteState === MuteState.MUTE_PERMANENT &&\n // если общий мьют => нужно донести инфу до клиента\n !muteAll\n ) {\n muteStates[mediaOption] = MuteState.MUTE;\n }\n\n if (!mediaOptions.includes(mediaOption) || unmute) {\n // Стейт есть, но он не менялся - ничего не делаем\n continue;\n }\n\n switch (mediaOption) {\n case MediaOption.VIDEO:\n if (mediaSettings.isVideoEnabled) {\n External.onDeviceSwitched(MediaOption.VIDEO, false);\n await this.toggleLocalVideo(false);\n }\n break;\n\n case MediaOption.AUDIO:\n if (mediaSettings.isAudioEnabled) {\n External.onDeviceSwitched(MediaOption.AUDIO, false);\n await this.toggleLocalAudio(false);\n }\n break;\n\n case MediaOption.SCREEN_SHARING:\n if (mediaSettings.isScreenSharingEnabled) {\n External.onDeviceSwitched(MediaOption.SCREEN_SHARING, false);\n await this.disableScreenCapturing();\n }\n break;\n case MediaOption.AUDIO_SHARING:\n if (mediaSettings.isAudioSharingEnabled) {\n External.onDeviceSwitched(MediaOption.AUDIO_SHARING, false);\n await this.toggleScreenCapturing({\n captureScreen: mediaSettings.isScreenSharingEnabled,\n fastScreenSharing: mediaSettings.isFastScreenSharingEnabled,\n captureAudio: false,\n });\n }\n break;\n }\n }\n\n External.onMuteStates(muteStates, unmuteOptions, mediaOptions, muteAll, unmute, null, adminExternalId, stateUpdated, requestedMedia, roomId);\n }\n\n private async _onPinParticipant(participantId: ParticipantId, unpin = false, markers?: ParticipantListMarkers, roomId: number | null = MAIN_ROOM_ID): Promise<void> {\n if (!this._conversation) {\n return;\n }\n\n const pinnedParticipantId = this._conversation.pinnedParticipantIdByRoom.get(roomId);\n if (pinnedParticipantId && pinnedParticipantId !== participantId) {\n // Отпиним припиненого, если пришел в параметрах другой\n if (this._isMe(pinnedParticipantId)) {\n External.onLocalPin(true, roomId);\n } else {\n const externalId = await this._getExternalIdByParticipantId(pinnedParticipantId);\n if (externalId) {\n External.onPinnedParticipant(externalId, true, this._denormalizeMarkers(participantId, markers), roomId);\n }\n }\n }\n\n if (this._isMe(participantId)) {\n External.onLocalPin(unpin, roomId);\n } else {\n const externalId = await this._getExternalIdByParticipantId(participantId);\n if (externalId) {\n External.onPinnedParticipant(externalId, unpin, this._denormalizeMarkers(participantId, markers), roomId);\n }\n }\n this._conversation.pinnedParticipantIdByRoom.set(roomId, unpin ? null : participantId);\n }\n\n private _onOptionsChanged(options: ConversationOption[]): void {\n if (this._conversation && !compareOptions(this._conversation.options, options)) {\n this._conversation.options = options;\n External.onOptionsChanged(options);\n\n if (options.includes(ConversationOption.ADMIN_IS_HERE)) {\n if (this._conversation.restricted && this._conversation.waitingHall) {\n External.onLocalStatus(ParticipantStatus.WAITING_HALL);\n }\n } else if (options.includes(ConversationOption.WAIT_FOR_ADMIN)) {\n if (this._conversation.restricted) {\n External.onLocalStatus(ParticipantStatus.WAIT_FOR_ADMIN);\n }\n }\n }\n }\n\n private async _onNetworkStatus(statuses: Record<ParticipantId, number>): Promise<void> {\n if (this._conversation) {\n const changed: { uid: ExternalParticipantId; rating: number }[] = [];\n const cachedParticipants = await this._getParticipants();\n for (const [participantId, status] of Object.entries(statuses)) {\n let lastStatus: number;\n if (this._isMe(participantId) || participantId === '') {\n // DirectTransport возвращает '' для текущего пользователя\n lastStatus = this._conversation.networkRating;\n } else if (cachedParticipants[participantId]) {\n lastStatus = cachedParticipants[participantId].networkRating;\n } else {\n continue;\n }\n if (lastStatus !== status) {\n if (this._isMe(participantId) || participantId === '') {\n this._conversation.networkRating = status;\n LocalNetworkRating.getInstance().value = status;\n External.onLocalNetworkStatusChanged(status);\n } else {\n const participant = cachedParticipants[participantId];\n participant.networkRating = status;\n changed.push({ uid: participant.externalId, rating: status });\n }\n }\n }\n if (changed.length === 0) {\n return;\n }\n\n Debug.log('Received network status update: ', statuses);\n External.onNetworkStatusChanged(changed);\n }\n }\n\n private async _onRemoteStreamSecond(participantId: ParticipantId, stream: MediaStream | null): Promise<void> {\n const participant = await this._getParticipant(participantId);\n if (!participant) {\n return;\n }\n\n if (Params.producerScreenTrack) {\n External.onRemoteScreenStream(participant.externalId, stream);\n return;\n }\n\n participant.secondStream = stream;\n\n if (Params.videoTracksCount > 0) {\n const streamDescription = participantId; // in legacy non-screenTrack mode participantId IS the stream description\n\n if (!this._streamIdByStreamDescription.has(streamDescription)) {\n Debug.error('Received remote stream notification for a participant that has no track associated with it', streamDescription);\n return;\n }\n\n // NULL stream ID means streaming was requested, but server hasn't returned stream ID yet\n const streamId = this._streamIdByStreamDescription.get(streamDescription);\n if (!streamId || this._streamWaitTimerByStreamDescription.has(streamDescription)) {\n // if \"main\" stream is pending, just memorize current stream - it will be applied once waiting is finished;\n // otherwise if secondary stream is started and stopped before \"main\" stream is available, we'll have nothing to show to the user\n Debug.log('Delaying secondary stream start/stop until main stream becomes available', streamDescription);\n return;\n }\n\n const participantAgnosticStream = this._streamByStreamId.get(streamId);\n if (!participantAgnosticStream) {\n Logger.log(StatLog.PAT_ERROR, 'streamNotFound');\n Debug.error(`Could not find stream by ID: ${streamId}`);\n return;\n }\n\n External.onRemoteStream(participant.externalId, participant.secondStream || participantAgnosticStream);\n } else {\n const newStream = stream || participant.remoteStream;\n if (newStream) {\n External.onRemoteStream(participant.externalId, newStream);\n }\n }\n }\n\n /**\n * Коллбек, вызывающийся при получении/остановке стрима от AnimojiReceiver\n * @param participantId - участник, к которому относится стрим\n * @param stream - стрим анимированного аватара, null в случае остановки стрима\n */\n private async _onAnimojiStream(participantId: ParticipantId, stream: MediaStream | null): Promise<void> {\n if (this._isMe(participantId) && this._mediaSource) {\n // Если стрим наш, подменяем трек нашей камеры\n External.onVmojiStream(stream, this._mediaSource.getMediaSettings());\n return;\n }\n\n const participant = await this._getParticipant(participantId);\n if (!participant) {\n return;\n }\n\n External.onRemoteVmojiStream(participant.externalId, stream);\n }\n\n /**\n * Коллбек, вызывающийся при получении ошибки от AnimojiReceiver\n * @param error - ошибка рендеринга Vmoji\n */\n private async _onAnimojiError(error: AnimojiError) {\n try {\n const externalId = await this._getExternalIdByParticipantId(error.participantId);\n if (externalId) {\n delete (error as any).participantId;\n External.onVmojiError({\n ...error,\n externalId,\n });\n }\n } catch (e) {\n Debug.warn('_onAnimojiError failed', e);\n }\n }\n\n private _onPeerConnectionClosed(topology: TransportTopology): void {\n if (topology === TransportTopology.SERVER) {\n this._cleanupParticipantAgnosticStreams();\n }\n }\n\n private _changeFeatureSet(): void {\n if (this._conversation) {\n const isCallActive = this._state === ConversationState.ACTIVE;\n const canAddParticipants = this._conversation.features.includes(ConversationFeature.ADD_PARTICIPANT);\n External.onCallState(isCallActive, canAddParticipants, this._conversation);\n }\n }\n\n private _changeFeaturesPerRole(): void {\n if (this._conversation) {\n External.onFeaturesPerRoleChanged(this._conversation.featuresPerRole ?? {});\n }\n }\n\n private _changeNeedRate(): void {\n if (this._conversation && this._conversation.needRate) {\n External.onRateNeeded();\n }\n }\n\n private async _onVolumesDetected(volumes: Record<ParticipantId, VolumeLevel>) {\n const result: { uid: ExternalParticipantId; volume: number }[] = [];\n for (const [participantId, volume] of Object.entries(volumes)) {\n const participant = await this._getParticipant(participantId);\n if (participant && participant.externalId) {\n result.push({\n uid: participant.externalId,\n volume: volume.real,\n });\n }\n }\n External.onVolumesDetected(result);\n }\n\n private async _onSpeakerChanged(activeSpeakerId: ParticipantId): Promise<void> {\n this._activeSpeakerId = activeSpeakerId;\n\n const participant = await this._getParticipant(activeSpeakerId);\n if (participant && this._lastSignalledActiveSpeakerId !== activeSpeakerId) {\n External.onSpeakerChanged(participant.externalId);\n this._lastSignalledActiveSpeakerId = activeSpeakerId;\n }\n }\n\n private async _onTransportStateChanged(participantIds: ParticipantId[], state: TransportState) {\n Debug.debug(`Transport state has changed: ${state}`, participantIds);\n\n const status = this._getStatusByTransportState(state);\n\n if (!status) {\n return;\n }\n\n const cachedParticipants = await this._getParticipants();\n const participants = participantIds.reduce((result: Participant[], participantId) => {\n if (participantId in cachedParticipants) {\n const participant = cachedParticipants[participantId];\n result.push(participant);\n\n if (state === TransportState.CONNECTED) {\n if (!participant.remoteStream) {\n if (participant.mediaSettings) {\n this._changeRemoteMediaSettings(participantId, participant.mediaSettings);\n }\n this._changeRemoteParticipantState(participantId, participant.participantState);\n }\n this._updateDisplayLayoutFromCache(participantId);\n }\n } else {\n this._warnParticipantNotInConversation(participantId);\n }\n\n return result;\n }, []);\n\n if (!participants.length) {\n return;\n }\n\n this._setParticipantsStatus(participants, status);\n }\n\n private async _onTransportLocalStateChanged(state: TransportState) {\n Debug.debug(`Local transport state has changed: ${state}`);\n\n if (state === TransportState.CONNECTED) {\n External.onLocalStatus(ParticipantStatus.CONNECTED);\n if (this._transport?.getTopology() === TransportTopology.SERVER) {\n const myLayouts = Object.values(this._myLastRequestedLayouts);\n await this.updateDisplayLayout(myLayouts);\n }\n }\n\n if (state === TransportState.CONNECTING) {\n External.onLocalStatus(ParticipantStatus.CONNECTING);\n }\n\n if (state === TransportState.RECONNECTING) {\n External.onLocalStatus(ParticipantStatus.RECONNECT);\n }\n\n if (state === TransportState.FAILED) {\n if (this._transport && this._transport.allocated().length === 0) {\n if (this._signaling.ready) {\n await this._signaling.hangup(HangupType.FAILED);\n }\n this._close(new HangupReason(HangupType.FAILED), 'Transport failed');\n }\n }\n }\n\n private async _onRemoteTrackAdded(participantId: ParticipantId | string, stream: MediaStream, track: MediaStreamTrack): Promise<void> {\n if (participantId.endsWith(TrackId.AUDIO_MIX)) {\n Debug.debug('Remote audio mix track added');\n this._audioOutput.add(track);\n External.onRemoteMixedAudioStream(stream);\n } else if (participantId.startsWith(TrackId.PARTICIPANT_AGNOSTIC_TRACK_PREFIX)) {\n Debug.debug(`Participant-agnostic track added: ${participantId}`);\n this._streamByStreamId.set(participantId, stream);\n } else {\n Debug.debug(`Remote track added on the participant [${participantId}]`, { kind: track.kind });\n\n let participant = await this._getParticipant(participantId);\n\n if (!participant) {\n const decorativeOkId = this._api.getDecorativeIdByInitialId(participantId);\n const decorativeId = decorativeOkId ? Utils.composeUserId(decorativeOkId) : undefined;\n Debug.warn(`Conversation: track added before participant [id: ${participantId}, decorativeId: ${decorativeId}]`);\n this._registerParticipant(\n {\n id: participantId,\n },\n decorativeId,\n );\n participant = await this._getParticipant(participantId);\n this._setParticipantsStatus([participant], ParticipantStatus.WAITING);\n if (this._activeSpeakerId === participantId && this._lastSignalledActiveSpeakerId !== participantId) {\n External.onSpeakerChanged(participant.externalId);\n this._lastSignalledActiveSpeakerId = participantId;\n }\n }\n\n if (this._transport && !this._transport.isAllocated(participant.id)) {\n this._transport.allocate(participant.id, false);\n }\n\n if (track.kind === MediaTrackKind.audio) {\n this._audioOutput.add(track);\n\n if (!Params.preserveAudioTracks) {\n // Удаляем аудио трек из стрима, т.к. он играет через AudioOutput и в стриме не нужен\n // Актуально для Direct транспорта и включенных observedIds, где нет микса\n participant.remoteAudioTrack = track;\n stream.removeTrack(track); // NB: Почему-то на стриме не срабатывает onremovetrack\n }\n }\n\n if (participant.remoteStream !== stream && stream.getTracks().length) {\n participant.remoteStream = stream;\n\n if (participant.secondStream) {\n // Мы можем получить шару через датаканал раньше, чем трек в медиаканале\n // Это хак для того, чтобы не применять трек из медиаканала поверх шары\n return;\n }\n\n External.onRemoteStream(participant.externalId, stream);\n }\n\n // Media settings might come before remote track is added\n if (participant.mediaSettings) {\n this._changeRemoteMediaSettings(participantId, participant.mediaSettings);\n }\n }\n }\n\n private _onRemoteTrackRemoved(participantId: ParticipantId, stream: MediaStream, track: MediaStreamTrack): void {\n Debug.debug(`[${participantId}] remote track (removed)`, { track });\n switch (track.kind) {\n case MediaTrackKind.audio:\n this._removeAudioTrack(participantId, stream, track);\n break;\n case MediaTrackKind.video:\n case MediaTrackKind.screen:\n this._removeVideoTrack(participantId, stream, track);\n break;\n }\n }\n\n private async _removeAudioTrack(participantId: ParticipantId | string, stream: MediaStream, track: MediaStreamTrack) {\n if (participantId !== TrackId.AUDIO_MIX) {\n const participant = await this._getParticipant(participantId);\n if (!participant) {\n return;\n }\n\n // При реконнекте сначала может добавиться новый трек, а потом удалиться старый\n if (participant.remoteStream && participant.remoteStream !== stream) {\n return;\n }\n }\n\n this._audioOutput.remove(track);\n }\n\n private _removeVideoTrack(_participantId: ParticipantId, _stream: MediaStream, _track: MediaStreamTrack) {\n // От выкидывания видеотреков пока отказались\n }\n\n private _onTopologyChanged(topology: TransportTopology) {\n if (topology === TransportTopology.DIRECT) {\n this._onRemoteSignalledStall([]);\n this._onAudioMixStall(false);\n }\n if (this._conversation) {\n this._conversation.topology = topology;\n this._changeFeatureSet();\n\n this._forceOpenTransportForAloneInCall();\n }\n }\n\n private _onAudioMixStall(stalled: boolean) {\n if (this._audioMixStalled !== stalled) {\n this._audioMixStalled = stalled;\n\n Debug.debug('Audio mix stalled:', stalled);\n External.onLocalStatus(stalled ? ParticipantStatus.RECONNECT : ParticipantStatus.CONNECTED);\n }\n }\n\n private async _onRemoteSignalledStall(stalledParticipants: ParticipantId[]) {\n const newStalled: Record<ParticipantId, boolean> = {};\n const reconnect: Participant[] = [];\n const connected: Participant[] = [];\n\n Debug.debug('Participants stalled:', stalledParticipants);\n const cachedParticipants = await this._getParticipants();\n\n for (const pid of stalledParticipants) {\n newStalled[pid] = true;\n if (!this._lastStalled[pid]) {\n // changed state !stalled -> stalled\n const participant = cachedParticipants[pid];\n if (participant) {\n reconnect.push(participant);\n }\n }\n delete this._lastStalled[pid];\n }\n\n // items remaining in _lastStalled have transitioned from stalled to !stalled\n for (const pid of Object.keys(this._lastStalled)) {\n const participant = cachedParticipants[pid];\n if (participant) {\n connected.push(participant);\n }\n }\n\n if (reconnect.length) {\n this._setParticipantsStatus(reconnect, ParticipantStatus.RECONNECT);\n }\n if (connected.length) {\n this._setParticipantsStatus(connected, ParticipantStatus.CONNECTED);\n }\n\n this._lastStalled = newStalled;\n }\n\n private async _onRemoteDataStats(stats: StatResult) {\n if (this._debugInfo) {\n this._debugInfo.onRemoteDataStats(stats, await this._getParticipants());\n }\n\n this._fixAudioDevice(stats.outbound.rtps);\n this._fixVideoDevice(stats.outbound.rtps);\n }\n\n private _fixAudioDevice(rtps: any[]): void {\n if (!WebRTCUtils.hasMicrophone() || !this._audioFix || !this._mediaSource?.getMediaSettings().isAudioEnabled) {\n return;\n }\n\n this._audioFix.fix(rtps);\n }\n\n private _fixVideoDevice(rtps: any[]): void {\n if (!WebRTCUtils.hasCamera() || !this._audioFix || !this._mediaSource?.getMediaSettings().isVideoEnabled) {\n return;\n }\n\n this._audioFix.fixVideo(rtps);\n }\n\n private _toggleJoinAvailability(): void {\n const chatId = this._conversation && this._conversation.chatId;\n const available = (chatId && this._state !== ConversationState.CLOSE) || false;\n\n if (chatId) {\n Debug.debug('Toggle join availability', { available, chatId });\n External.onJoinStatus(available, chatId);\n }\n }\n\n private async _updateDisplayLayoutFromCache(participantId: ParticipantId) {\n // TODO: move layouts to data channel\n if (this._transport?.getTopology() !== TransportTopology.SERVER) {\n return;\n }\n\n const participant = await this._getParticipant(participantId);\n if (participant && participant.lastRequestedLayouts && Object.keys(participant.lastRequestedLayouts).length) {\n await this.updateDisplayLayout(Object.values(participant.lastRequestedLayouts));\n }\n }\n\n private _setParticipantsStatus(participants: Participant[], status: ParticipantStatus, data: any = null) {\n if (!participants.length) {\n return;\n }\n\n const externalIds = participants.reduce((result: ExternalParticipantId[], participant) => {\n if (participant.status !== status) {\n participant.status = status;\n result.push(participant.externalId);\n }\n return result;\n }, []);\n\n if (!externalIds.length) {\n return;\n }\n\n External.onRemoteStatus(externalIds, status, data);\n }\n\n private _onJoinLinkChanged(message: SignalingMessage.JoinLinkChanged) {\n if (this._conversation && message.joinLink) {\n this._conversation.joinLink = message.joinLink;\n }\n\n External.onJoinLinkChanged(message.joinLink);\n }\n\n private async _onRoomsUpdated(message: SignalingMessage.RoomsUpdated) {\n if (this._isCalledState()) {\n return;\n }\n\n const updates: Partial<Record<RoomsEventType, RoomsUpdate>> = {};\n\n for (const eventType of Object.keys(RoomsEventType) as RoomsEventType[]) {\n const update = message.updates[eventType];\n\n if (!update) {\n continue;\n }\n\n updates[eventType as RoomsEventType] = {\n rooms: await Promise.all(update?.rooms?.map(this._convertRoomToExternal.bind(this)) || []),\n roomIds: update?.roomIds,\n deactivated: update?.deactivated,\n } as RoomsUpdate;\n }\n\n External.onRoomsUpdated(updates);\n }\n\n private async _onRoomUpdated(message: SignalingMessage.RoomUpdated) {\n const room = await this._convertRoomToExternal(message.room || null);\n\n if (message.events.some((event) => event === RoomsEventType.UPDATE)) {\n if (message.muteStates !== undefined) {\n this._setMuteStatesForRoomId(message.muteStates, message.roomId);\n }\n\n if (message.recordInfo !== undefined) {\n this._conversation?.recordsInfoByRoom.set(message.roomId, message.recordInfo);\n }\n\n if (message.asrInfo !== undefined) {\n this._conversation?.asrInfoByRoom.set(message.roomId, message.asrInfo);\n }\n }\n\n if (!this._isCalledState()) {\n External.onRoomUpdated(message.events, message.roomId, room, message.deactivate || null);\n }\n }\n\n private async _convertRoomToExternal(room: SignalingMessage.Room | null): Promise<Room | null> {\n if (!room) {\n return null;\n }\n\n const participantIds = (await Promise.all(room.participantIds?.map((id) => this._getExternalIdByParticipantId(id)) || [])) as ExternalParticipantId[];\n const addParticipantIds = (await Promise.all(room.addParticipantIds?.map((id) => this._getExternalIdByParticipantId(id)) || [])) as ExternalParticipantId[];\n const removeParticipantIds = (await Promise.all(room.removeParticipantIds?.map?.((id) => this._getExternalIdByParticipantId(id)) || [])) as ExternalParticipantId[];\n const pinnedParticipantId = room.pinnedParticipantId ? ((await this._getExternalIdByParticipantId(room.pinnedParticipantId)) as ExternalParticipantId) : undefined;\n\n return {\n id: room.id as number,\n name: room.name as string,\n participantCount: room.participantCount as number,\n participantIds,\n addParticipantIds,\n removeParticipantIds,\n participants: room.participants?.participants ? await this._participantListChunkToExternalChunk(room.participants) : undefined,\n active: room.active,\n muteStates: room.muteStates,\n pinnedParticipantId,\n countdownSec: room.countdownSec,\n timeoutMs: room.timeoutMs,\n };\n }\n\n private async _onRoomParticipantsUpdated(message: SignalingMessage.RoomParticipantsUpdated) {\n const transportState = this._transport?.getState() as TransportState;\n const roomId = message.roomId ?? MAIN_ROOM_ID;\n\n const addedOkIds = message.addedParticipantIds?.map((id) => Utils.decomposeId(id).id) || [];\n const addedParticipantIds = await this._api.getExternalIdsByOkIds(addedOkIds);\n\n let resultParticipants = message.addedParticipants;\n if (addedParticipantIds.length && resultParticipants?.length !== addedParticipantIds.length && !this._isCalledState()) {\n const serverExternalIds = this._convertExternalIdsToServerExternalIds(addedParticipantIds);\n const result = await this._signaling.getParticipants(serverExternalIds);\n resultParticipants = result.participants;\n }\n\n const addedParticipants = await Promise.all(\n resultParticipants?.map(async (participant) => {\n const participantId = Utils.composeId(participant);\n return this._createParticipant(\n {\n id: participantId,\n externalId: ExternalIdUtils.fromSignalingParticipant(participant),\n mediaSettings: createMediaSettingsWithDefaults(participant.mediaSettings),\n participantState: Utils.mapParticipantState(participant),\n state: participant.state,\n roles: participant.roles || [],\n status: this._getStatusByTransportState(transportState) ?? ParticipantStatus.WAITING,\n muteStates: participant.muteStates || {},\n unmuteOptions: participant.unmuteOptions || [],\n observedIds: participant.observedIds || [],\n markers: this._denormalizeMarkers(participantId, participant.markers),\n isInRoom: roomId !== MAIN_ROOM_ID,\n },\n participant.decorativeUserId,\n );\n }) || [],\n );\n\n let isRoomChanged = false;\n for (const participant of addedParticipants) {\n if (participant.id === this._conversation?.compositeUserId) {\n isRoomChanged = true;\n }\n\n this._registerParticipantInCache(participant);\n }\n\n if (this._transport?.getState() === TransportState.IDLE && !this._isCalledState()) {\n this._openTransport(addedParticipants, true);\n }\n\n let removedParticipantIds: ExternalParticipantId[] = [];\n const removedParticipantsIdsPromises: Promise<ExternalParticipantId>[] = [];\n if (message?.removedParticipantMarkers) {\n for (const participantMarker of message.removedParticipantMarkers) {\n if (participantMarker.GRID?.id) {\n const id = this._getExternalIdByParticipantId(participantMarker.GRID.id) as Promise<ExternalParticipantId>;\n removedParticipantsIdsPromises.push(id);\n }\n }\n\n removedParticipantIds = await Promise.all(removedParticipantsIdsPromises);\n }\n\n if (isRoomChanged) {\n await this._onRoomSwitched(roomId);\n }\n\n if (removedParticipantIds) {\n const pinnedParticipantId = this._conversation?.pinnedParticipantIdByRoom.get(roomId);\n\n if (pinnedParticipantId) {\n const pinnedParticipantExternalId = await this._getExternalIdByParticipantId(pinnedParticipantId);\n if (pinnedParticipantExternalId) {\n for (const removedParticipantId of removedParticipantIds) {\n if (ExternalIdUtils.compare(pinnedParticipantExternalId, removedParticipantId)) {\n this._conversation?.pinnedParticipantIdByRoom.delete(roomId);\n break;\n }\n }\n }\n }\n }\n\n const update: RoomParticipantUpdate = {\n roomId,\n participantCount: message.participantCount,\n addedParticipantIds,\n addedParticipants: Utils.mapSharedParticipants(addedParticipants),\n removedParticipantMarkers: message?.removedParticipantMarkers,\n removedParticipantIds,\n };\n\n if (!this._isCalledState()) {\n External.onRoomParticipantsUpdated(update);\n }\n }\n\n /**\n * @param roomId\n * @param isStartEvent в случае true будет отправлено стартовое событие установки id сессионного зала\n * @private\n */\n private async _onRoomSwitched(roomId: number | null, isStartEvent = false) {\n if (!this._conversation) {\n return;\n }\n\n if (this._conversation.roomId === roomId) {\n return;\n }\n\n const prevRoomId = this._conversation.roomId;\n this._conversation.roomId = roomId;\n\n if (isStartEvent && !this._isCalledState()) {\n External.onRoomStart(roomId);\n return;\n }\n\n // Сообщаем клиенту о том, что изменился сессионный зал\n if (!this._isCalledState()) {\n External.onRoomSwitched(roomId);\n }\n\n if (roomId !== null && !this._isCallAdmin()) {\n // если не админ и идем не в основной зал, то возможно не знаем актуальные мьюты и трансляции\n await this._refreshRooms(false);\n }\n\n this._changePinnedParticipantForRoom();\n this._changeRecordInfoForRoom();\n this._changeMuteStatesForRoom(roomId, prevRoomId);\n await this._changeAsrInfoForRoom();\n await this._changeUrlSharingInfoForRoom();\n }\n\n private async _refreshRooms(withParticipants: boolean) {\n let response: GetRoomsSignalingResponse | undefined;\n if (!this._isCalledState()) {\n response = await this._signaling.getRooms(withParticipants);\n }\n const rooms = response?.rooms?.rooms ?? [];\n const externalRooms: Room[] = [];\n\n for (const room of rooms) {\n const roomId = room.id ?? MAIN_ROOM_ID;\n this._setMuteStatesForRoomId(room.muteStates, roomId);\n this._conversation?.recordsInfoByRoom.set(roomId, room.recordInfo ?? null);\n this._conversation?.pinnedParticipantIdByRoom.set(roomId, room.pinnedParticipantId ?? null);\n\n if (room.asrInfo) {\n this._conversation?.asrInfoByRoom.set(roomId, room.asrInfo);\n }\n\n if (room.urlSharingInfo) {\n this._conversation?.urlSharingInfoByRoom.set(roomId, room.urlSharingInfo);\n } else {\n this._conversation?.urlSharingInfoByRoom.delete(roomId);\n }\n\n if (withParticipants) {\n const cachedParticipants = await this._getParticipants();\n await this._registerParticipants(room?.participants?.participants?.filter((item) => !cachedParticipants[Utils.composeId(item)]) || [], true);\n\n const externalRoom = await this._convertRoomToExternal(room);\n if (externalRoom) {\n externalRooms.push(externalRoom);\n }\n }\n }\n\n if (externalRooms.length && !this._isCalledState()) {\n External.onRoomsUpdated({\n [RoomsEventType.UPDATE]: {\n rooms: externalRooms,\n },\n });\n }\n }\n\n /** получили из сингналинга сообщение о реакции пользователей */\n private async _onFeedback(message: SignalingMessage.Feedback) {\n const feedback: IFeedbackExternal[] = [];\n\n for (const f of message.feedback) {\n const externalFeedback: IFeedbackExternal = { ...f, items: [] };\n for (const item of f.items) {\n const externalId = await this._getExternalIdByParticipantId(item.participantId);\n if (externalId) {\n externalFeedback.items.push({ ...item, participantId: externalId });\n } else {\n this._warnParticipantNotInConversation(item.participantId);\n }\n }\n feedback.push(externalFeedback);\n }\n\n External.onFeedback(feedback, message.roomId);\n }\n\n private async _onDecorativeParticipantIdChanged(message: SignalingMessage.DecorativeParticipantIdChanged) {\n if (!this._conversation || !message.decorativeParticipantId || !message.decorativeExternalParticipantId) {\n return;\n }\n\n /**\n * participantId - OK id mapped to \"contact\" - anonimized external user\n * decorativeParticipantId - OK id mapped to real external user\n * decorativeExternalParticipantId - identity with id of \"real\" (deanonimized) external user\n */\n const { participantId, decorativeParticipantId, decorativeExternalParticipantId } = message;\n const isMe = this._isMe(participantId);\n\n Debug.debug(`Decorative participant id changed [${participantId}]`, message);\n\n const externalId = await this._getExternalIdByParticipantId(participantId);\n\n if (!externalId) {\n this._warnParticipantNotInConversation(participantId);\n return;\n }\n\n const newExternalId = ExternalIdUtils.fromSignaling(decorativeExternalParticipantId, externalId.deviceIdx);\n\n External.onParticipantIdChanged(externalId, newExternalId);\n\n // All further notifications will continue to come with previous 'internal participant id'\n // so we can leave participantId in _participants and other places as is\n\n this._api.cacheExternalId(decorativeParticipantId, newExternalId);\n this._api.mapDecorativeId(decorativeParticipantId, participantId);\n\n if (isMe) {\n this._conversation.externalId = newExternalId;\n } else {\n // old external id is not used anymore\n const participants = await this._getParticipants();\n participants[participantId].externalId = newExternalId;\n }\n }\n\n private _onVideoSuspendSuggest(message: SignalingMessage.VideoSuspendSuggest) {\n if (!this._conversation || this._conversation.topology !== TransportTopology.SERVER) {\n return;\n }\n\n Debug.debug('Video suspend suggested', message);\n External.onVideoSuspendSuggest(message.bandwidth);\n }\n\n private _isMe(participantId: ParticipantId) {\n return participantId === this._conversation?.compositeUserId;\n }\n\n private _getMuteStatesForRoomId(roomId: number | null = MAIN_ROOM_ID): MuteStates {\n return this._conversation?.muteStates.get(roomId) ?? {};\n }\n\n private _getMuteStatesForCurrentRoom(): MuteStates {\n return this._getMuteStatesForRoomId(this._conversation?.roomId);\n }\n\n private _setMuteStatesForRoomId(muteStates: MuteStates = {}, roomId: number | null = MAIN_ROOM_ID) {\n this._conversation?.muteStates.set(roomId, muteStates);\n }\n\n private _forceOpenTransportForAloneInCall() {\n // Откроет транспорт, когда это необходимо для работы функционала, если он еще не был открыт (например если в звонке один участник)\n // Не открываем, если мы в статусе входящего звонка\n\n if (this._transport?.getTopology() === TransportTopology.SERVER && this._transport?.getState() === TransportState.IDLE && !this._isCalledState()) {\n this._transport.open(this._transport.allocated(), null, !!this._conversation?.observer, true);\n }\n }\n\n private _registerParticipant(properties: Partial<Participant> & Pick<Participant, 'id'>, decorativeId?: CompositeUserId) {\n this._pendingParticipants.set(properties.id, this._createParticipant(properties, decorativeId));\n }\n\n private async _getParticipants() {\n if (this._pendingParticipants.size) {\n const pendingPromises = Array.from(this._pendingParticipants.values());\n const participants = await Promise.all(pendingPromises);\n\n for (const participant of participants) {\n this._pendingParticipants.delete(participant.id);\n this._participants[participant.id] = participant;\n }\n }\n\n return this._participants;\n }\n\n private async _getParticipant(id: ParticipantId) {\n const cachedParticipants = await this._getParticipants();\n\n return cachedParticipants[id];\n }\n}\n\nexport class UpdateDisplayLayoutError extends Error {\n readonly participantErrors: { externalId: ExternalParticipantId; errorReason: UpdateDisplayLayoutErrorReason }[];\n\n constructor(m: string, participantErrors: { externalId: ExternalParticipantId; errorReason: UpdateDisplayLayoutErrorReason }[]) {\n super(m);\n Object.setPrototypeOf(this, UpdateDisplayLayoutError.prototype); // restore prototype chain\n this.participantErrors = participantErrors;\n }\n}\n", "import HangupType from '../enums/HangupType';\nimport HangupReason from '../classes/HangupReason';\nimport { IAPIBaseUrl, IApiEnv } from '../types/Params';\nimport AuthData from './AuthData';\nimport Debug from './Debug';\nimport Params from './Params';\n\nlet _endpoint: string | null = null;\nlet _resolveEndpointPromise: Promise<string> | null = null;\n\nexport function resetApiEndpoint() {\n _endpoint = null;\n _resolveEndpointPromise = null;\n}\n\n/**\n * Убираем слэш на конце\n */\nfunction sanitizeApiBaseUrl(url: IAPIBaseUrl) {\n return url?.endsWith('/') ? url.slice(0, -1) : url;\n}\n\nexport async function _resolveApiEndpoint(apiBaseUrl: IAPIBaseUrl = null, apiEnv?: IApiEnv): Promise<string> {\n // apiBaseUrl является самым приоритетным вариантом\n const baseEndpoint = sanitizeApiBaseUrl(apiBaseUrl ?? Params.apiBaseUrl);\n if (baseEndpoint) {\n return baseEndpoint;\n }\n\n if ((apiEnv ?? Params.apiEnv) !== 'AUTO') {\n return Params.apiEndpoint(apiEnv);\n }\n\n try {\n // Не забудь в CSP политику connect-src добавить https://dns.google и https://api.bnnapp.com для Украины\n // Магия с base64 технически не нужна, но решил хоть немного спрятать в коде адреса\n // btoa('https://dns.google/resolve?name=video._endpoint.ok.ru&type=TXT')\n const url = atob('aHR0cHM6Ly9kbnMuZ29vZ2xlL3Jlc29sdmU/bmFtZT12aWRlby5fZW5kcG9pbnQub2sucnUmdHlwZT1UWFQ=');\n const response = await fetch(url, {\n method: 'GET',\n mode: 'cors',\n cache: 'no-cache',\n });\n const json = await response.json();\n const endpoint = json?.Answer[0]?.data;\n if (!endpoint) {\n throw new Error('Wrong DNS response');\n }\n\n Debug.debug('Resolved API endpoint', endpoint);\n return endpoint;\n } catch (e) {\n Debug.warn('Failed to resolve API endpoint using DNS, default is used', e);\n return Params.apiEndpoint(apiEnv);\n }\n}\n\nasync function _resolveAndSetApiEndpointIfNeed(): Promise<string> {\n if (_endpoint) {\n return _endpoint;\n }\n\n if (_resolveEndpointPromise) {\n return _resolveEndpointPromise;\n }\n\n _resolveEndpointPromise = _resolveApiEndpoint();\n _endpoint = await _resolveEndpointPromise;\n _resolveEndpointPromise = null;\n return _endpoint;\n}\n\nexport async function sendBeakon(method: string, params: { [key: string]: any } = {}, noSession = false) {\n if (!window.Blob || !window.navigator.sendBeacon) {\n return;\n }\n\n await _resolveAndSetApiEndpointIfNeed();\n\n const query = _prepareQuery(method, params, noSession);\n const blob = new window.Blob([query], { type: 'application/x-www-form-urlencoded' });\n window.navigator.sendBeacon(`${_endpoint}/fb.do`, blob);\n}\n\nexport async function request(method: string, params: { [key: string]: any } = {}, noSession = false, customEndpoint?: string) {\n await _resolveAndSetApiEndpointIfNeed();\n\n const query = _prepareQuery(method, params, noSession);\n return _executeRemoteRequest(query, customEndpoint);\n}\n\nasync function _executeRemoteRequest(query: string, customEndpoint?: string) {\n const url = `${customEndpoint ?? _endpoint}/fb.do`;\n\n const abortController = new AbortController();\n\n const timeoutId = setTimeout(() => abortController.abort(new HangupReason(HangupType.NETWORK_ERROR)), Params.apiTimeout);\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: query,\n signal: abortController.signal,\n });\n\n clearTimeout(timeoutId);\n\n const responseText = await response.text();\n let responseJson: any;\n\n try {\n responseJson = JSON.parse(responseText);\n } catch {\n responseJson = { result: responseText };\n }\n\n if (!response.ok || Object.hasOwn(responseJson, 'error_msg')) {\n throw responseJson;\n }\n\n return responseJson;\n}\n\nexport async function sendFormData(url: string, data: FormData) {\n try {\n const response = await fetch(url, {\n method: 'POST',\n body: data,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const text = await response.text();\n Debug.debug('Form data sent successfully', text);\n } catch (e) {\n Debug.warn('Failed to send form data', e);\n throw e;\n }\n}\n\nfunction _prepareQuery(method: string, params: { [key: string]: any } = {}, noSession = false) {\n params.method = method;\n params.format = 'JSON';\n if (!params.application_key) {\n params.application_key = Params.apiKey;\n }\n\n if (!noSession) {\n if (AuthData.sessionKey) {\n params.session_key = AuthData.sessionKey;\n } else if (AuthData.accessToken) {\n params.access_token = AuthData.accessToken;\n }\n }\n\n for (const [key, param] of Object.entries(params)) {\n if (typeof param === 'object') {\n params[key] = JSON.stringify(param);\n }\n }\n\n let query = '';\n for (const [key, param] of Object.entries(params)) {\n if (query) {\n query += '&';\n }\n query += `${key}=${encodeURIComponent(param)}`;\n }\n\n return query;\n}\n", "import CallType from '../enums/CallType';\nimport HangupType from '../enums/HangupType';\nimport { ConversationData } from '../types/Conversation';\nimport ConversationParams from '../types/ConversationParams';\nimport ConversationResponse from '../types/ConversationResponse';\nimport { ExternalId, ExternalParticipantId, ExternalUserId } from '../types/ExternalId';\nimport { CompositeUserId, OkUserId, ParticipantId } from '../types/Participant';\n\nexport type ClientStats = {\n vcid: ConversationData['id'] | null;\n [k: string]: string | number | null;\n};\n\nexport type ClientEvent = {\n timestamp: number;\n call_topology: 'D' | 'S';\n event_type: string;\n vcid: ConversationData['id'] | null;\n [k: string]: string | number | boolean | null;\n};\n\nexport type LogItem = {\n count?: number;\n custom: ClientStats;\n data?: string[];\n groups?: string[];\n network?: string;\n operation: string;\n time: 0;\n timestamp: number;\n type: 1;\n uid: OkUserId | null;\n};\n\nexport default abstract class BaseApi {\n abstract authorize(): Promise<void>;\n\n abstract userId(participantId: ParticipantId): Promise<ExternalParticipantId>;\n\n abstract deviceId(): string;\n\n abstract createConversation(\n conversationId: string,\n payload?: string,\n requireAuthToJoin?: boolean,\n createConversationParameters?: { onlyAdminCanShareMovie?: boolean; audienceMode?: boolean; audioOnly?: boolean; waitForAdmin?: boolean; closedConversation?: boolean },\n speakerIds?: OkUserId[],\n ): Promise<ConversationResponse>;\n abstract startConversation(\n conversationId: string,\n ids?: OkUserId[],\n type?: CallType,\n isVideo?: boolean,\n payload?: string,\n joiningAllowed?: boolean,\n requireAuthToJoin?: boolean,\n createConversationParameters?: { onlyAdminCanShareMovie?: boolean },\n externalIds?: ExternalId[],\n ): Promise<ConversationResponse>;\n abstract joinConversation(conversationId: string, isVideo?: boolean, chatId?: string): Promise<ConversationResponse>;\n async createJoinLink(conversationId: string): Promise<{ join_link: string }> {\n // Do nothing\n return { join_link: 'nop' };\n }\n async removeJoinLink(conversationId: string): Promise<{ success: boolean }> {\n // Do nothing\n return { success: true };\n }\n async getAnonymTokenByLink(joinLink: string, username?: string): Promise<string> {\n // Do nothing\n return '';\n }\n abstract joinConversationByLink(joinLink: string, isVideo?: boolean, observedIds?: ExternalUserId[], payload?: string): Promise<ConversationResponse>;\n\n abstract getConversationParams(conversationId?: string): Promise<ConversationParams>;\n\n abstract getUserId(): OkUserId | null;\n abstract setUserId(userId: OkUserId): void;\n\n /**\n * method: log.externalLog\n */\n log(items: LogItem[]): void {\n // Do nothing\n }\n\n /**\n * method: vchat.clientStats\n */\n logClientStats(items: ClientStats[]): void {\n // Do nothing\n }\n\n /**\n * method: vchat.clientEvents\n */\n logClientEvents(items: ClientEvent[]): void {\n // Do nothing\n }\n\n abstract uploadDebugLogs(conversationId: string, startTime: number, endTime: number, log: string): Promise<void>;\n\n abstract getOkIdsByExternalIds(externalIds: ExternalId[]): Promise<OkUserId[]>;\n\n abstract getParticipantIdsByExternalIds(externalIds: ExternalId[]): Promise<Map<ExternalId, ParticipantId>>;\n\n abstract getExternalIdsByOkIds(uids: OkUserId[]): Promise<ExternalParticipantId[]>;\n\n getCachedOkIdByExternalId(externalId: ExternalId): ParticipantId | null {\n return null;\n }\n\n cacheExternalId(compositeId: OkUserId | CompositeUserId | ParticipantId, externalId: ExternalParticipantId): void {\n // Do nothing\n }\n\n mapDecorativeId(decorativeId: OkUserId | CompositeUserId | ParticipantId, okId: OkUserId | CompositeUserId): void {\n // Do nothing\n }\n\n unmapDecorativeId(decorativeId: OkUserId | CompositeUserId | ParticipantId): void {\n // Do nothing\n }\n\n getDecorativeIdByInitialId(okId: OkUserId | CompositeUserId | ParticipantId): OkUserId | undefined {\n return undefined;\n }\n\n replaceByInitialIdIdIfExists(id: OkUserId | CompositeUserId | ParticipantId): OkUserId {\n return typeof id === 'string' ? parseInt(id, 10) : id;\n }\n\n hangupConversation(conversationId: string, reason: HangupType = HangupType.HUNGUP): void {\n // Do nothing\n }\n\n sendUserFeedbackStats(conversationId: string, userResponse: number, reason?: string, groupCallUsersCount?: number): void {\n // Do nothing\n }\n\n async removeHistoryRecords(recordIds: number[]): Promise<void> {\n // Do nothing\n return;\n }\n\n async getServerTime(): Promise<number> {\n return Date.now();\n }\n\n cleanup(): void {\n // Do nothing\n }\n\n\n}\n", "import BaseApi, { ClientEvent, ClientStats, LogItem } from '../abstract/BaseApi';\nimport HangupReason, { CustomError, HangupReasonData } from '../classes/HangupReason';\nimport CallType from '../enums/CallType';\nimport FatalError from '../enums/FatalError';\nimport HangupType from '../enums/HangupType';\nimport Stat from '../enums/Stat';\nimport UserType from '../enums/UserType';\nimport * as ApiTransport from '../static/ApiTransport';\nimport AuthData from '../static/AuthData';\nimport Debug from '../static/Debug';\nimport External from '../static/External';\nimport LocalStorage from '../static/LocalStorage';\nimport Params from '../static/Params';\nimport { SignalingCapabilities } from '../static/SignalingCapabilities';\nimport Utils from '../static/Utils';\nimport ConversationParams from '../types/ConversationParams';\nimport ConversationResponse from '../types/ConversationResponse';\nimport { ExternalId, ExternalIdString, ExternalIdType, ExternalIdUtils, ExternalParticipantId, ExternalUserId } from '../types/ExternalId';\nimport { GetLogUploadUrlParams } from '../types/GetLogUploadUrlParams';\nimport { GetLogUploadUrlResponse } from '../types/GetLogUploadUrlResponse';\nimport { CompositeUserId, OkUserId, ParticipantId } from '../types/Participant';\n\nconst enum ApiConversationError {\n SERVICE_UNAVAILABLE = 2,\n REQUEST = 4,\n NOT_FOUND = 300,\n VCHAT_SERVICE_DISABLED = 1101,\n TARGET_USER_UNAVAILABLE = 1102,\n FRIENDSHIP_REQUIRED = 1103,\n VCHAT_YOULA_API_ERROR = 1104,\n VCHAT_VK_API_ERROR = 1106,\n VCHAT_CALLER_IS_REJECTED = 1113,\n VCHAT_DETAILED_ERROR = 1114,\n}\n\nconst enum SessionError {\n PARAM_SESSION_EXPIRED = 102,\n PARAM_SESSION_KEY = 103,\n PARAM_SIGNATURE = 104,\n AUTH_LOGIN = 401,\n}\n\nconst RETRY_MULTIPLIER_MS = 700;\nconst RETRY_MAX_TIME_MS = 3000;\n\nexport default class Api extends BaseApi {\n private _userId: OkUserId | null = null;\n private _uuid: string;\n // TODO: Проблема в том, что одному OkUserId может соответствовать несколько ExternalParticipantId\n private _externalUidsCache = new Map<OkUserId, ExternalIdString>(); // key: decomposed okId, value: externalId (from ExternalIdUtils.toString)\n private _decorativeIdToInitialId = new Map<OkUserId, OkUserId>();\n private _initialIdToDecorativeId = new Map<OkUserId, OkUserId>();\n\n private async _callUnsafe(method: string, data: any = {}, noSession = false): Promise<any> {\n const apiCall: any = async (attempt: number) => {\n try {\n return await ApiTransport.request(method, data, noSession);\n } catch (error: any) {\n if (!Object.hasOwn(error, 'error_msg')) {\n attempt++;\n const details = Object.getOwnPropertyNames(error).map((key) => `${key}: ${JSON.stringify(error[key])}`);\n Debug.debug(`${method} network error, attempt ${attempt}: ${details.join('\\n ')}`);\n if (attempt < Params.apiMaxAttempt) {\n await Utils.delay(Math.min(attempt * RETRY_MULTIPLIER_MS, RETRY_MAX_TIME_MS));\n return apiCall(attempt);\n }\n }\n\n Debug.warn(method, 'error', error);\n throw error; // Будет обработана дальше\n }\n };\n return apiCall(0);\n }\n\n protected async _call(method: string, data: any = {}, noSession = false): Promise<any> {\n try {\n return await this._callUnsafe(method, data, noSession);\n } catch (error: any) {\n Debug.warn('Api call error', error);\n let type: HangupType | FatalError = FatalError.API;\n\n switch (error.error_code) {\n case SessionError.PARAM_SESSION_EXPIRED:\n case SessionError.PARAM_SESSION_KEY:\n case SessionError.PARAM_SIGNATURE:\n await this.authorize();\n return this._callUnsafe(method, data, noSession);\n }\n\n const hangupReasonData: HangupReasonData = { message: error.error_msg, code: error.error_code };\n\n if (error instanceof HangupReason) {\n throw error;\n }\n\n if (error.custom_error) {\n hangupReasonData.custom_error = error.custom_error;\n }\n\n if (isApiError(error)) {\n switch (error.error_code) {\n case ApiConversationError.VCHAT_SERVICE_DISABLED:\n type = HangupType.SERVICE_DISABLED;\n break;\n\n case ApiConversationError.REQUEST:\n if (error.error_msg.includes('participants.limit.exceeded')) {\n type = HangupType.PARTICIPANT_LIMIT_REACHED;\n }\n break;\n\n case ApiConversationError.NOT_FOUND:\n type = HangupType.NOT_FOUND;\n break;\n\n case ApiConversationError.TARGET_USER_UNAVAILABLE:\n type = HangupType.CALLEE_IS_OFFLINE;\n break;\n\n case ApiConversationError.FRIENDSHIP_REQUIRED:\n type = HangupType.NOT_FRIENDS;\n break;\n\n case ApiConversationError.VCHAT_YOULA_API_ERROR:\n case ApiConversationError.VCHAT_VK_API_ERROR:\n type = HangupType.EXTERNAL_API_ERROR;\n break;\n\n case ApiConversationError.VCHAT_CALLER_IS_REJECTED:\n type = HangupType.CALLER_IS_REJECTED;\n break;\n\n case ApiConversationError.VCHAT_DETAILED_ERROR:\n type = HangupType.VCHAT_DETAILED_ERROR;\n break;\n\n case ApiConversationError.SERVICE_UNAVAILABLE:\n type = HangupType.SERVICE_UNAVAILABLE;\n break;\n }\n }\n\n throw new HangupReason(type, hangupReasonData);\n }\n }\n\n override async userId(participantId: ParticipantId): Promise<ExternalParticipantId> {\n let okId: OkUserId = Utils.extractOkId(participantId);\n\n if (AuthData.isEmpty()) {\n return ExternalIdUtils.fromId(String(okId));\n }\n\n // Анонимная сессия\n if (!this._externalUidsCache.has(okId)) {\n await this._getExternalIdsByOkIds([okId]);\n }\n\n const decorativeOkId = this.getDecorativeIdByInitialId(okId);\n if (decorativeOkId) {\n okId = decorativeOkId;\n }\n\n return ExternalIdUtils.fromString(this._externalUidsCache.get(okId) as ExternalIdString);\n }\n\n override async authorize(): Promise<void> {\n this._ensureUuid();\n\n if (!Params.apiKey) {\n throw new HangupReason(FatalError.API, {\n message: 'Required argument apiAppKey not passed',\n });\n }\n\n const session: any = {\n session_data: {\n version: 2,\n device_id: this._uuid,\n client_version: Params.appVersion,\n client_type: 'SDK_JS',\n },\n };\n\n if (Params.authToken) {\n session.session_data.auth_token = Params.authToken;\n session.session_data.version = 3;\n }\n\n return this._callUnsafe('auth.anonymLogin', session, true)\n .then((response: any) => {\n if (response.uid) {\n this._userId = Number(response.uid);\n }\n AuthData.sessionKey = response.session_key;\n AuthData.sessionSecretKey = response.session_secret_key;\n })\n .catch((error) => {\n if (error.error_code === SessionError.AUTH_LOGIN) {\n External.onTokenExpired();\n }\n throw new HangupReason(FatalError.AUTH, { message: error.error_msg, code: error.error_code });\n });\n }\n\n override log(items: LogItem[]): void {\n const data = {\n collector: 'ok.mobile.apps.video', // TODO: Возможно, коллектор нужен другой\n data: JSON.stringify({\n application: `${Params.appName}:${Params.sdkVersion}`, // Попадает в Version\n platform: Params.platform, // Попадёт во FlashVersion\n items,\n }),\n };\n ApiTransport.sendBeakon('log.externalLog', data);\n }\n\n override logClientStats(items: ClientStats[]): void {\n const data = {\n app_version: String(Params.appVersion),\n sdk_type: 'WEB', // Тип платформы SDK, захардкожено\n sdk_version: Params.sdkVersion,\n version: 1, // Версия схемы сообщения, захардкожено\n items,\n } as any;\n\n if (Params.clientStatsPlatform) {\n data.platform = Params.clientStatsPlatform;\n }\n\n const dataRaw = {\n data: JSON.stringify(data),\n };\n\n /**\n * Бекенд присылает 200 в любой ситуации, нужно читать тело.\n * В теле есть ошибки если есть проблемы со статой\n */\n if (process.env.DEBUG) {\n ApiTransport.request('vchat.clientStats', dataRaw)\n .then((response) => {\n if (response !== null && typeof response === 'object' && 'items_responses' in response && Array.isArray(response.items_responses)) {\n response.items_responses.forEach((item: unknown) => {\n if (item !== null && typeof item === 'object' && 'errors' in item) {\n Debug.error('[vchat.clientStats]', item);\n }\n });\n }\n })\n .catch((error) => {\n Debug.error('[vchat.clientStats]', error);\n });\n return;\n }\n\n ApiTransport.sendBeakon('vchat.clientStats', dataRaw);\n }\n\n override logClientEvents(items: ClientEvent[]): void {\n const data = {\n app_version: String(Params.appVersion),\n sdk_type: 'WEB', // Тип платформы SDK, захардкожено\n sdk_version: Params.sdkVersion,\n version: 1, // Версия схемы сообщения, захардкожено\n items,\n } as any;\n\n if (Params.clientStatsPlatform) {\n data.platform = Params.clientStatsPlatform;\n }\n\n const dataRaw = {\n data: JSON.stringify(data),\n };\n\n ApiTransport.sendBeakon('vchat.clientEvents', dataRaw);\n }\n\n override async uploadDebugLogs(conversationId: string, startTime: number, endTime: number, log: string): Promise<void> {\n const data: GetLogUploadUrlParams = {\n conversationId,\n webrtcPlatform: Params.platform,\n startTime,\n endTime,\n };\n\n const uploadUrl: GetLogUploadUrlResponse = await this._callUnsafe('vchat.getLogUploadUrl', data);\n\n const formData = new FormData();\n const logFile = new Blob([log], { type: 'application/json' });\n formData.append('file', logFile, 'log.json');\n\n const parsedUrl = new URL(uploadUrl.upload_url);\n parsedUrl.searchParams.append('size', logFile.size.toString());\n\n return ApiTransport.sendFormData(parsedUrl.toString(), formData);\n }\n\n override async joinConversation(conversationId: string, isVideo = false, chatId?: string): Promise<ConversationResponse> {\n const data: any = {\n conversationId,\n isVideo,\n protocolVersion: Params.protocolVersion,\n capabilities: SignalingCapabilities.getFlags(),\n };\n\n if (chatId) {\n data.chatId = chatId;\n }\n\n return this._call('vchat.joinConversation', data);\n }\n\n override async createConversation(\n conversationId: string,\n payload = '',\n requireAuthToJoin = false,\n {\n onlyAdminCanShareMovie,\n audienceMode,\n audioOnly,\n waitForAdmin,\n closedConversation,\n }: {\n onlyAdminCanShareMovie?: boolean;\n audienceMode?: boolean;\n audioOnly?: boolean;\n waitForAdmin?: boolean;\n closedConversation?: boolean;\n } = {},\n speakerIds?: OkUserId[],\n ): Promise<ConversationResponse> {\n const data: any = this._preareStartConversationData({\n conversationId,\n isVideo: false,\n joiningAllowed: true,\n payload,\n requireAuthToJoin,\n onlyAdminCanShareMovie,\n waitForAdmin,\n closedConversation,\n audienceMode,\n audioOnly,\n speakerIds,\n });\n\n return this._startConversation(data);\n }\n\n override async startConversation(\n conversationId: string,\n ids?: OkUserId[],\n type?: CallType,\n isVideo = false,\n payload = '',\n joiningAllowed = false,\n requireAuthToJoin = false,\n { onlyAdminCanShareMovie, waitForAdmin }: { onlyAdminCanShareMovie?: boolean; waitForAdmin?: boolean } = {},\n externalIds?: ExternalId[],\n ): Promise<ConversationResponse> {\n const data: any = this._preareStartConversationData({\n conversationId,\n isVideo,\n joiningAllowed,\n payload,\n requireAuthToJoin,\n onlyAdminCanShareMovie,\n waitForAdmin,\n externalIds,\n });\n\n if (ids && ids.length) {\n switch (type) {\n case CallType.USER:\n data.uids = ids.join(',');\n break;\n case CallType.GROUP:\n data.gid = ids[0];\n break;\n case CallType.CHAT:\n data.chatId = ids[0];\n break;\n }\n }\n\n return this._startConversation(data);\n }\n\n protected _ensureUuid() {\n if (!this._uuid) {\n let uuid = LocalStorage.get('uuid');\n if (!uuid) {\n uuid = Utils.uuid();\n LocalStorage.set('uuid', uuid);\n }\n this._uuid = String(uuid);\n }\n }\n\n override deviceId(): string {\n this._ensureUuid();\n return this._uuid;\n }\n\n private _preareStartConversationData({\n conversationId,\n isVideo,\n payload = '',\n joiningAllowed = false,\n requireAuthToJoin = false,\n onlyAdminCanShareMovie,\n waitForAdmin,\n audienceMode = false,\n audioOnly = false,\n speakerIds = [],\n closedConversation = false,\n externalIds,\n }: {\n conversationId: string;\n isVideo: boolean;\n payload: string;\n joiningAllowed: boolean;\n requireAuthToJoin: boolean;\n onlyAdminCanShareMovie?: boolean;\n waitForAdmin?: boolean;\n audienceMode?: boolean;\n audioOnly?: boolean;\n speakerIds?: OkUserId[];\n externalIds?: ExternalId[];\n closedConversation?: boolean;\n }) {\n const data: any = {\n conversationId,\n isVideo,\n protocolVersion: Params.protocolVersion,\n };\n\n if (joiningAllowed) {\n data.createJoinLink = true;\n }\n\n if (payload) {\n data.payload = payload;\n }\n\n if (Params.domain) {\n data.domainId = Params.domain;\n }\n\n if (Params.externalDomain) {\n data.externalDomain = Params.externalDomain;\n }\n\n if (requireAuthToJoin) {\n data.requireAuthToJoin = true;\n }\n\n if (onlyAdminCanShareMovie !== undefined) {\n data.onlyAdminCanShareMovie = onlyAdminCanShareMovie;\n }\n\n if (waitForAdmin !== undefined) {\n data.waitForAdmin = waitForAdmin;\n }\n\n if (audienceMode) {\n data.audienceMode = audienceMode;\n }\n\n if (audioOnly) {\n data.audioOnly = audioOnly;\n }\n\n if (speakerIds.length) {\n const speakerUserIds = speakerIds.map((id) => Utils.composeUserId(id));\n data.speakerIds = speakerUserIds.join(',');\n }\n\n if (closedConversation) {\n data.closed = closedConversation;\n }\n\n if (externalIds) {\n data.externalIds = externalIds.map(ExternalIdUtils.toSignaling).join(',');\n }\n\n return data;\n }\n\n private async _startConversation(data: object): Promise<ConversationResponse> {\n return this._call('vchat.startConversation', data);\n }\n\n override async createJoinLink(conversationId: string): Promise<{ join_link: string }> {\n return this._call('vchat.createJoinLink', {\n conversationId,\n });\n }\n\n override async removeJoinLink(conversationId: string): Promise<{ success: boolean }> {\n return this._call('vchat.removeJoinLink', {\n conversationId,\n });\n }\n\n override async getAnonymTokenByLink(joinLink: string, username?: string): Promise<string> {\n const data: any = { joinLink };\n\n if (username) {\n data.anonymName = username;\n }\n\n const response = await this._call('vchat.getAnonymTokenByLink', data);\n this._userId = Number(response.uid);\n\n return response.token;\n }\n\n // Этот метод возвращает не ConversationResponse, но необходимые поля там есть\n override async joinConversationByLink(joinLink: string, isVideo = false, observedIds?: ExternalUserId[], payload?: string): Promise<ConversationResponse> {\n const data: any = {\n joinLink,\n isVideo,\n protocolVersion: Params.protocolVersion,\n capabilities: SignalingCapabilities.getFlags(),\n };\n\n if (observedIds?.length) {\n data.observedIds = observedIds.join(',');\n }\n if (Params.anonymToken) {\n data.anonymToken = Params.anonymToken;\n }\n if (payload) {\n data.payload = payload;\n }\n\n return this._call('vchat.joinConversationByLink', data);\n }\n\n /**\n * NB: Не сохраняет порядок возвращаемых ID\n * Этот метод принимает именно ExternalId, т.к. для OkUserId не принципиально наличие deviceIdx\n * @hidden\n */\n override async getOkIdsByExternalIds(externalIds: ExternalId[]): Promise<OkUserId[]> {\n const result: OkUserId[] = [];\n const requestData: { id: ExternalUserId; ok_anonym: boolean }[] = [];\n const requestedExternalIds = new Map<ExternalUserId, ExternalIdString>(); // NB: Здесь не поддерживается deviceId\n\n const cachedOkIds = Array.from(this._externalUidsCache.keys());\n const cachedExternalIds = Array.from(this._externalUidsCache.values());\n\n for (const externalId of externalIds) {\n const stringId = ExternalIdUtils.toString(externalId);\n const index = cachedExternalIds.indexOf(stringId);\n if (index > -1) {\n // Signaling AND OK API require initially added id\n result.push(this.replaceByInitialIdIdIfExists(cachedOkIds[index]));\n } else {\n requestedExternalIds.set(String(externalId.id), stringId);\n requestData.push({\n id: externalId.id,\n ok_anonym: externalId.type === ExternalIdType.ANONYM,\n });\n }\n }\n\n if (!requestData.length) {\n // Все найдены в кэше\n return result;\n }\n\n const response: { ids: { ok_user_id: number; external_user_id: { id: ExternalUserId; ok_anonym: boolean } }[] } = await this._call('vchat.getOkIdsByExternalIds', {\n externalIds: requestData,\n });\n\n response.ids.forEach((item, i) => {\n const uid = Number(item.ok_user_id);\n const externalId = String(item.external_user_id.id);\n if (requestedExternalIds.has(externalId)) {\n // TODO: CALL-16391 Do we need to replace here ??? We get decorativeId which is not used anywhere\n // TODO: Тут в кэш всегда будет установлено значение с нулевым deviceIdx, что неверно\n this.cacheExternalId(uid, ExternalIdUtils.fromString(requestedExternalIds.get(externalId) as ExternalIdString));\n result.push(uid);\n }\n });\n\n return result;\n }\n\n override async getParticipantIdsByExternalIds(externalIds: ExternalId[]): Promise<Map<ExternalId, ParticipantId>> {\n await this.getOkIdsByExternalIds(externalIds); // precache ids\n\n const result = new Map<ExternalId, ParticipantId>();\n const cachedOkIds = Array.from(this._externalUidsCache.keys());\n const cachedExternalIds = Array.from(this._externalUidsCache.values());\n\n for (const externalId of externalIds) {\n const stringId = ExternalIdUtils.toString(externalId);\n const index = cachedExternalIds.indexOf(stringId);\n if (index > -1) {\n // Signaling AND OK API require initially added id\n const participantId = Utils.composeParticipantId(this.replaceByInitialIdIdIfExists(cachedOkIds[index]), UserType.USER, externalId.deviceIdx);\n result.set(externalId, participantId);\n }\n }\n\n return result;\n }\n\n /**\n * NB: Не сохраняет порядок возвращаемых ID\n * @hidden\n */\n override async getExternalIdsByOkIds(uids: OkUserId[]): Promise<ExternalParticipantId[]> {\n const result: ExternalParticipantId[] = [];\n const requestUids: OkUserId[] = [];\n\n for (const uid of uids) {\n if (this._externalUidsCache.has(uid)) {\n const decorativeId = this.getDecorativeIdByInitialId(uid);\n const cachedStringId = this._externalUidsCache.get(decorativeId ?? uid) as ExternalIdString;\n result.push(ExternalIdUtils.fromString(cachedStringId));\n } else {\n requestUids.push(uid);\n }\n }\n\n if (!requestUids.length) {\n // Все найдены в кэше\n return result;\n }\n\n const response = await this._getExternalIdsByOkIds(requestUids);\n\n return Array.from(response.values());\n }\n\n override getCachedOkIdByExternalId(externalId: ExternalId): ParticipantId | null {\n const cachedOkIds = Array.from(this._externalUidsCache.keys());\n const cachedExternalIds = Array.from(this._externalUidsCache.values());\n\n const stringId = ExternalIdUtils.toString(externalId);\n const index = cachedExternalIds.indexOf(stringId);\n\n if (index > -1) {\n // Signaling AND OK API require initially added id\n return Utils.composeParticipantId(this.replaceByInitialIdIdIfExists(cachedOkIds[index]), UserType.USER, externalId.deviceIdx);\n }\n return index > -1 ? Utils.composeParticipantId(cachedOkIds[index], UserType.USER, externalId.deviceIdx) : null;\n }\n\n override cacheExternalId(participantId: OkUserId | CompositeUserId | ParticipantId, externalId: ExternalParticipantId): void {\n const okId = Utils.extractOkId(participantId);\n this._externalUidsCache.set(okId, ExternalIdUtils.toString(externalId));\n }\n\n override mapDecorativeId(decorativeId: OkUserId | CompositeUserId | ParticipantId, initialId: OkUserId | CompositeUserId | ParticipantId): void {\n const decorativeOkId = Utils.extractOkId(decorativeId);\n const okId = Utils.extractOkId(initialId);\n\n this._decorativeIdToInitialId.set(decorativeOkId, okId);\n this._initialIdToDecorativeId.set(okId, decorativeOkId);\n }\n\n override unmapDecorativeId(initialId: OkUserId | CompositeUserId | ParticipantId): void {\n const okId = Utils.extractOkId(initialId);\n const decorativeId = this.getDecorativeIdByInitialId(okId);\n\n if (decorativeId) {\n this._decorativeIdToInitialId.delete(decorativeId);\n }\n\n this._initialIdToDecorativeId.delete(okId);\n }\n\n override getDecorativeIdByInitialId(initialId: OkUserId | CompositeUserId | ParticipantId): OkUserId | undefined {\n const okId = Utils.extractOkId(initialId);\n return this._initialIdToDecorativeId.get(okId);\n }\n\n override replaceByInitialIdIdIfExists(id: OkUserId | CompositeUserId | ParticipantId): OkUserId {\n const okId = Utils.extractOkId(id);\n return this._decorativeIdToInitialId.get(okId) ?? okId;\n }\n\n override async getConversationParams(conversationId?: string): Promise<ConversationParams> {\n const data: any = {};\n if (Params.anonymToken) {\n data.anonymToken = Params.anonymToken;\n }\n if (conversationId) {\n data.conversationId = conversationId;\n }\n return this._call('vchat.getConversationParams', data);\n }\n\n override getUserId(): OkUserId | null {\n return this._userId;\n }\n\n override setUserId(userId: OkUserId): void {\n this._userId = userId;\n }\n\n override hangupConversation(conversationId: string, reason: HangupType = HangupType.HUNGUP): void {\n const data: any = {\n conversationId,\n reason,\n };\n if (Params.anonymToken) {\n data.anonymToken = Params.anonymToken;\n }\n ApiTransport.sendBeakon('vchat.hangupConversation', data);\n }\n\n override sendUserFeedbackStats(conversationId: string, userResponse: number, reason?: string, groupCallUsersCount?: number): void {\n const data = {\n collector: 'app.vchat.events.product',\n data: JSON.stringify({\n application: `${Params.appName}:${Params.sdkVersion}`, // Попадает в Version\n platform: Params.platform, // Попадёт во FlashVersion\n items: [\n {\n type: 1, // захардкожено по документации https://wiki.odkl.ru/pages/viewpage.action?pageId=156277585\n operation: Stat.USER_FEEDBACK_RECEIVED,\n timestamp: Date.now(),\n custom: {\n vcid: conversationId,\n user_response: userResponse,\n reason,\n group_call_users_count: groupCallUsersCount,\n },\n },\n ],\n }),\n };\n\n ApiTransport.sendBeakon('log.externalLog', data);\n }\n\n override async removeHistoryRecords(recordIds: number[]): Promise<void> {\n await this._call('vchat.removeHistoryRecords', {\n recordIds: recordIds.join(','),\n });\n }\n\n override cleanup(): void {\n // TODO: Пока откатил эту очистку. Предположительно она чинит какой-то перезаход в анонимный звонок, но это не точно.\n // Она точно ломает повторный входящий звонок в ВК, т.к. userId очищается и в ссылку для сигналинга нечего подставлять\n // this._userId = null;\n\n this._decorativeIdToInitialId = new Map();\n this._initialIdToDecorativeId = new Map();\n }\n\n // Принимает decomposed okIds\n // Возвращает сразу строковые представления ExternalIdUtils.toString\n private async _getExternalIdsByOkIds(uids: OkUserId[]): Promise<Map<OkUserId, ExternalParticipantId>> {\n const result = new Map<OkUserId, ExternalParticipantId>();\n\n // check if we have decorative ids\n uids = uids.map((okId) => this.getDecorativeIdByInitialId(okId) ?? okId);\n\n try {\n const response = await this._call('vchat.getExternalIdsByOkIds', {\n uids: uids.join(','),\n });\n\n const processResult = (externalIds: { [key: string]: string }, type: ExternalIdType) => {\n for (const [uid, externalUid] of Object.entries(externalIds)) {\n const okUserId = Number(uid);\n const externalId = ExternalIdUtils.fromId(externalUid, type);\n result.set(okUserId, externalId);\n // TODO: Тут в кэш будет установлено значение с нулевым deviceIdx, что неверно\n this.cacheExternalId(okUserId, externalId);\n }\n };\n\n if (response.external_ids) {\n processResult(response.external_ids, ExternalIdType.USER);\n }\n\n if (response.anonym_ids) {\n processResult(response.anonym_ids, ExternalIdType.ANONYM);\n }\n\n // Странная ситуация, когда vchat.getExternalIdsByOkIds не вернул пользователя\n for (const uid of uids) {\n const okUserId = Number(uid); // На всякий случай, приведем к числу\n if (!result.has(okUserId)) {\n const externalParticipantId = ExternalIdUtils.fromId(String(okUserId));\n result.set(okUserId, externalParticipantId);\n // TODO: Тут в кэш будет установлено значение с нулевым deviceIdx, что неверно\n this.cacheExternalId(okUserId, externalParticipantId);\n }\n }\n\n return result;\n } catch (e) {\n return result;\n }\n }\n\n override async getServerTime(): Promise<number> {\n const response = await this._call('system.getInfo');\n return response.serverTime;\n }\n\n\n}\n\ninterface ApiError {\n error_code: number;\n error_msg: string;\n error_data?: unknown;\n custom_error?: CustomError;\n}\n\nfunction isApiError(err: unknown): err is ApiError {\n return typeof err === 'object' && err !== null && 'error_code' in err && 'error_msg' in err;\n}\n", "/**\n * Роль участника в записи звонке.\n * Если выставлена хотя бы на одном участнике, то в записи звонка видны только те участники звонка,\n * у которых есть роль.\n */\nenum RecordRole {\n KING = 'KING', // участник показывается крупно в записи звонка\n PAWN = 'PAWN', // участник показывается в записи звонка\n}\n\nexport default RecordRole;\n", "import MediaOption from '../enums/MediaOption';\nimport ParticipantState from '../enums/ParticipantState';\nimport UserRole from '../enums/UserRole';\nimport { ParticipantStatus } from '../static/External';\nimport MediaSettings from '../types/MediaSettings';\nimport { ExternalId, ExternalParticipantId, ExternalParticipantListMarkers } from './ExternalId';\nimport { ISharedMovieInfo } from './MovieShare';\nimport MuteStates from './MuteStates';\nimport ParticipantLayout from './ParticipantLayout';\nimport { StreamDescriptionString } from './ParticipantStreamDescription';\n\n/**\n * Уникально идентифицирует пользователя или группу\n */\nexport type CompositeUserId = string;\n\n/**\n * Уникально идентифицирует участника звонка\n * (одному пользователю могут соответствовать несколько участников, в случае если пользователь зашёл в звонок с нескольких устройств)\n * Включает композитный id и постфикс с номером устройства, если он не равен 0\n */\nexport type ParticipantId = string;\n\nexport type OkUserId = number;\n\n/**\n * Тип списка участников в звонке\n */\nexport type ParticipantListType = 'GRID' | 'SIDE' | 'ADMIN';\n\n/**\n * Маркер определяющий положение участника в списке\n */\nexport interface ParticipantListMarker {\n rank?: number; // server-calculated synthetic value - first criterion for sorting participants (DESC)\n ts?: number; // sorting timestamp - second criterion for sorting participants (ASC)\n id?: CompositeUserId; // participant ID - third (and actually fourth) criterion for sorting participants (ASC); sorted first by one-letter prefix (participant type, 'u' < 'g') and second - by long participant id - numerically!\n}\n\n/**\n * Маркеры определяющие положения участников в списке\n */\nexport type ParticipantListMarkers = Record<ParticipantListType, ParticipantListMarker>;\n\n/**\n * Стейт участника звонка\n */\nexport interface ParticipantStateMapped {\n [key: string]: {\n state: string;\n ts: number;\n };\n}\n\n/**\n * Состояния участников звонка\n */\nexport type ParticipantsStateList = {\n externalId: ExternalParticipantId;\n participantState: ParticipantStateMapped;\n markers: ExternalParticipantListMarkers | null;\n}[];\n\nexport interface Participant {\n /**\n * string representation\n */\n id: ParticipantId;\n /**\n * If user has 'decorative external id' it will be set as externalId\n */\n externalId: ExternalParticipantId;\n mediaSettings: MediaSettings;\n state: ParticipantState;\n status: ParticipantStatus;\n remoteStream?: MediaStream | null;\n remoteAudioTrack?: MediaStreamTrack | null;\n secondStream?: MediaStream | null;\n mediaSource?: MediaStreamAudioSourceNode | null;\n platform: string;\n clientType: string;\n roles: UserRole[];\n participantState: ParticipantStateMapped;\n networkRating: number;\n lastRequestedLayouts: { [key: StreamDescriptionString]: ParticipantLayout };\n muteStates: MuteStates;\n unmuteOptions: MediaOption[];\n observedIds: CompositeUserId[];\n markers: ExternalParticipantListMarkers | null;\n movieShareInfos?: ISharedMovieInfo[];\n isInRoom?: boolean;\n}\n\nexport interface IGetParticipantsParameters {\n externalIds: ExternalId[];\n}\n\nexport type ParticipantStateDataKey = 'hand' | 'drat';\n\nexport enum ParticipantStateDataValue {\n OFF = '0',\n ON = '1',\n}\n\n/**\n * Список состояний в виде ключ-значение. Максимальная длина ключей и значений - 5 символов. Пустые значения будут пропущены\n */\nexport type ParticipantStateData = Partial<Record<ParticipantStateDataKey, ParticipantStateDataValue>>;\n", "export class ArrayDequeue<T = any> {\n /** очередь */\n private readonly _queue: (T | null)[];\n /** курсор для чтения */\n private _readCursor: number;\n /** курсор для записи */\n private _writeCursor: number;\n /** подвинуть курсор чтения */\n private _moveReadCursor: boolean;\n /** сколько осталось в очереди элементов */\n private _left: number;\n\n constructor(length: number) {\n this._queue = new Array(length).fill(null);\n this._readCursor = this._writeCursor = this._left = 0;\n this._moveReadCursor = false;\n }\n\n /** возвращает длину, переданную в конструктор */\n get length() {\n return this._queue.length;\n }\n\n /** возвращает текущую длину очереди */\n get left() {\n return this._left;\n }\n\n toArray() {\n return Array.from(this._queue);\n }\n\n /** добавить элемент в очередь */\n add(element: T) {\n if (this._moveReadCursor) {\n this._readCursor = this.nextCursor(this._readCursor);\n }\n\n if (this._queue[this._writeCursor] === null) {\n this._left += 1;\n }\n\n this._queue[this._writeCursor] = element;\n this._writeCursor = this.nextCursor(this._writeCursor);\n this._moveReadCursor = this._writeCursor === this._readCursor;\n }\n\n /** вычисляет значение след курсора по кругу */\n private nextCursor(curr: number) {\n return (curr + 1) % this._queue.length;\n }\n\n /** получить следующий элемент */\n next(): T | null {\n const el = this._queue[this._readCursor];\n if (el) {\n this._moveReadCursor = false;\n this._queue[this._readCursor] = null;\n this._readCursor = this.nextCursor(this._readCursor);\n this._left -= 1;\n }\n return el;\n }\n}\n", "import Params from '../static/Params';\nimport Utils from '../static/Utils';\nimport { request, _resolveApiEndpoint } from '../static/ApiTransport';\nimport HangupType from '../enums/HangupType';\nimport { IAPIBaseUrl, IApiEnv } from '../types/Params';\n\ninterface ISession {\n session_data: {\n device_id: string;\n client_version: number;\n client_type: string;\n auth_token: string;\n version: number;\n };\n application_key: string;\n}\n\nnamespace IAuthorizeResponse {\n export interface Success {\n activated_profile: boolean;\n api_server: string;\n session_key: string;\n session_secret_key: string;\n uid: string;\n }\n\n export interface Fail {\n error_code: number;\n error_data: unknown;\n error_msg: string;\n }\n}\n\ntype IAuthorizeResult = IAuthorizeResponse.Fail | IAuthorizeResponse.Success;\n\nexport class ApiExternal {\n private readonly _uuid: string;\n private readonly _apiKey: string;\n private readonly _callToken: string;\n private readonly _apiEnv: IApiEnv;\n private readonly _baseApiUrl: IAPIBaseUrl;\n\n private _sessionKey: string;\n\n constructor(apiEvn: IApiEnv, apiKey: string, callToken: string, baseApiUrl: IAPIBaseUrl = null) {\n this._uuid = Utils.uuid();\n this._apiKey = apiKey;\n this._callToken = callToken;\n this._apiEnv = apiEvn;\n this._baseApiUrl = baseApiUrl;\n }\n\n async authorize(): Promise<boolean> {\n const session: ISession = {\n session_data: {\n device_id: this._uuid,\n client_version: Params.appVersion,\n client_type: 'SDK_JS',\n auth_token: this._callToken,\n version: 3,\n },\n application_key: this._apiKey,\n };\n\n const endpoint = await _resolveApiEndpoint(this._baseApiUrl, this._apiEnv);\n const result = (await request('auth.anonymLogin', session, true, endpoint)) as IAuthorizeResult;\n\n if (Utils.isObject(result) && !('error_msg' in result)) {\n this._sessionKey = result.session_key;\n return true;\n }\n return false;\n }\n\n async hangupConversation(conversationId: string): Promise<void> {\n const data = {\n conversationId,\n reason: HangupType.HUNGUP,\n application_key: this._apiKey,\n session_key: this._sessionKey,\n };\n\n const endpoint = await _resolveApiEndpoint(this._baseApiUrl, this._apiEnv);\n await request('vchat.hangupConversation', data, true, endpoint);\n }\n}\n"],
5
+ "mappings": ";;;;;;0tBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,SAAAE,GAAA,gBAAAC,GAAA,iBAAAC,GAAA,aAAAC,GAAA,eAAAC,GAAA,kBAAAC,GAAA,aAAAC,GAAA,sBAAAC,GAAA,wBAAAC,GAAA,uBAAAC,GAAA,qBAAAC,GAAA,mBAAAC,GAAA,eAAAC,GAAA,eAAAC,GAAA,iBAAAC,EAAA,eAAAC,EAAA,gBAAAC,GAAA,mBAAAC,GAAA,cAAAC,GAAA,cAAAC,GAAA,qBAAAC,EAAA,8BAAAC,GAAA,sBAAAC,GAAA,eAAAC,GAAA,mBAAAC,GAAA,cAAAC,GAAA,yBAAAC,EAAA,4BAAAC,GAAA,0BAAAC,EAAA,sBAAAC,GAAA,aAAAC,GAAA,aAAAC,GAAA,mBAAAC,GAAA,eAAAC,GAAA,oBAAAC,GAAA,kBAAAC,GAAA,aAAAC,GAAA,mBAAAC,GAAA,2BAAAC,GAAA,cAAAC,GAAA,YAAAC,GAAA,iBAAAC,GAAA,WAAAC,GAAA,kBAAAC,GAAA,iBAAAC,GAAA,sBAAAC,GAAA,8BAAAC,GAAA,iBAAAC,GAAA,2BAAAC,GAAA,qBAAAC,GAAA,sBAAAC,GAAA,gBAAAC,GAAA,gBAAAC,GAAA,wBAAAC,GAAA,mBAAAC,GAAA,eAAAC,GAAA,uBAAAC,GAAA,UAAAC,GAAA,iBAAAC,GAAA,gBAAAC,GAAA,0BAAAC,GAAA,uBAAAC,GAAA,8BAAAC,GAAA,aAAAC,GAAA,qBAAAC,GAAA,yBAAAC,GAAA,yBAAAC,GAAA,4BAAAC,GAAA,oBAAAC,GAAA,kBAAAC,GAAA,mBAAAC,GAAA,eAAAC,GAAA,uBAAAC,GAAA,WAAAC,GAAA,SAAAC,GAAA,aAAAC,GAAA,mBAAAC,GAAA,qBAAAC,GAAA,mBAAAC,GAAA,oBAAAC,GAAA,4BAAAC,GAAA,mBAAAC,GAAA,2BAAAC,GAAA,gBAAAC,GAAA,wBAAAC,GAAA,uBAAAC,GAAA,kBAAAC,GAAA,iBAAAC,GAAA,kBAAAC,GAAA,yBAAAC,GAAA,mBAAAC,GAAA,gBAAAC,GAAA,sBAAAC,GAAA,8BAAAC,GAAA,gBAAAC,GAAA,eAAAC,GAAA,qBAAAC,GAAA,oBAAAC,GAAA,mBAAAC,GAAA,uBAAAC,GAAA,cAAAC,GAAA,sBAAAC,GAAA,0BAAAC,GAAA,oBAAAC,GAAA,mBAAAC,GAAA,aAAAC,GAAA,iBAAAC,GAAA,gBAAAC,GAAA,cAAAC,GAAA,aAAAC,GAAA,8BAAAC,GAAA,sBAAAC,GAAA,gBAAAC,GAAA,oBAAAC,GAAA,YAAAC,GAAA,eAAAC,GAAA,mBAAAC,GAAA,eAAAC,GAAA,qBAAAC,GAAA,qBAAAC,GAAA,wBAAAC,GAAA,gBAAAC,GAAA,gBAAAC,GAAA,oBAAAC,GAAA,sBAAAC,GAAA,UAAAC,GAAA,YAAAC,KAAA,eAAAC,GAAAjI,IAOA,IAAAkI,GAAoB,8BCPpB,IAA8BC,GAA9B,KAAyC,CACrC,IAAIC,EAAcC,EAAgBC,EAAc,GAAa,CAE7D,CAEA,SAAU,CAEV,CACJ,ECRA,IAAqBC,GAArB,KAAkC,CAAlC,cACIC,EAAA,KAAQ,YAA2C,CAAC,GACpDA,EAAA,KAAQ,aAAsC,CAAC,GAErC,cAAcC,KAAkBC,EAAa,CACnD,GAAK,OAAO,OAAO,KAAK,UAAWD,CAAK,EAIxC,QAAWE,KAAW,KAAK,UAAUF,CAAK,EAStCE,EAAQ,MAAM,KAAMD,CAAI,CAEhC,CAEA,iBAAiBD,EAAeG,EAA2C,CACvE,GAAM,OAAOA,GAAa,WACtB,MAAM,IAAI,MAAM,+BAA+B,EAGnD,OAAK,OAAO,OAAO,KAAK,UAAWH,CAAK,IACpC,KAAK,UAAUA,CAAK,EAAI,CAAC,GAG7B,KAAK,UAAUA,CAAK,EAAE,KAAKG,CAAQ,EAE5B,CACH,QAAS,KAAK,oBAAoB,KAAK,KAAMH,EAAOG,CAAQ,CAChE,CACJ,CAEA,oBAAoBH,EAAeG,EAA0B,CACzD,GAAI,CAAC,OAAO,OAAO,KAAK,UAAWH,CAAK,EACpC,OAGCG,GACD,OAAO,KAAK,UAAUH,CAAK,EAG/B,IAAMI,EAAM,KAAK,UAAUJ,CAAK,EAAE,QAAQG,CAAQ,EAC9CC,GAAO,GACP,KAAK,UAAUJ,CAAK,EAAE,OAAOI,EAAK,CAAC,CAE3C,CAEA,UAAUC,EAAwBL,EAAeM,EAAoB,CACjE,IAAMC,EAAeF,EAAS,iBAAiBL,EAAOM,CAAQ,EAC9D,KAAK,WAAW,KAAKC,CAAY,CACrC,CAEA,aAAc,CACV,KAAK,WAAW,QAASJ,GAAa,CAClCA,EAAS,QAAQ,CACrB,CAAC,CACL,CACJ,ECZA,IAA8BK,GAA9B,cAAoDC,EAAa,CAmF7D,IAAI,OAAQ,CACR,MAAO,EACX,CAEA,yBAAyBC,EAA8C,CAEvE,CAEA,gBAAiB,CAEjB,CAEA,YAAYC,EAAkB,CAE9B,CAEA,wBAAwBA,EAAyB,CAEjD,CAEA,kBAAkBC,EAAwB,CAE1C,CAEA,YAAYC,EAAU,GAAM,CAE5B,CAEA,SAAU,CAEV,CAEA,gBAAgBC,EAAyBC,EAAgC,CAEzE,CAEA,8BAAuC,CACnC,MAAO,EACX,CACJ,EC1KA,IAAKC,SAEDA,GAAA,SAAW,WACXA,GAAA,SAAW,WACXA,GAAA,QAAU,UACVA,GAAA,OAAS,SACTA,GAAA,OAAS,SACTA,GAAA,KAAO,OACPA,GAAA,OAAS,SACTA,GAAA,cAAgB,gBAChBA,GAAA,OAAS,SACTA,GAAA,OAAS,SACTA,GAAA,gBAAkB,kBAElBA,GAAA,kBAAoB,oBACpBA,GAAA,YAAc,cACdA,GAAA,kBAAoB,oBACpBA,GAAA,mBAAqB,qBACrBA,GAAA,cAAgB,gBAChBA,GAAA,YAAc,cACdA,GAAA,YAAc,cACdA,GAAA,iBAAmB,mBACnBA,GAAA,oBAAsB,sBACtBA,GAAA,mBAAqB,qBACrBA,GAAA,cAAgB,gBAChBA,GAAA,MAAQ,QACRA,GAAA,sBAAwB,wBACxBA,GAAA,eAAiB,iBACjBA,GAAA,UAAY,YACZA,GAAA,qBAAuB,uBACvBA,GAAA,QAAU,UAIVA,GAAA,0BAA4B,4BAI5BA,GAAA,iBAAmB,mBAYnBA,GAAA,aAAe,eAlDdA,SAAA,IAqDEC,EAAQD,GC5Bf,IAAqBE,EAArB,MAAqBC,UAAqB,KAAM,CA0B5C,YAAYC,EAA+BC,EAAyB,CAChE,MAAM,EAvBVC,EAAA,KAAkB,WAIlBA,EAAA,KAAS,UAITA,EAAA,KAAS,SAITA,EAAA,KAAS,QAITA,EAAA,KAAS,UAITA,EAAA,KAAS,gBAKL,KAAK,KAAO,eACZ,KAAK,KAAQD,GAAQA,EAAK,MAAS,EACnC,KAAK,OAAUA,GAAQA,EAAK,QAAW,GACvC,KAAK,aAAeA,GAAM,cAAgB,KAEtC,OAAO,OAAOE,CAAU,EAAE,QAAQH,CAAkB,EAAI,GACxD,KAAK,OAASA,EAEd,KAAK,MAAQA,EAGjB,IAAMI,EAAM,CAAC,EACT,KAAK,OACLA,EAAI,KAAK,OAAO,EAEhB,KAAK,QACLA,EAAI,KAAK,QAAQ,EAEjB,KAAK,MACLA,EAAI,KAAK,SAAS,KAAK,IAAI,EAAE,EAE7BH,GAAQA,EAAK,SACbG,EAAI,KAAK,aAAaH,EAAK,OAAO,GAAG,EAGzC,KAAK,QAAUD,GAAQI,EAAI,OAAS,KAAKA,EAAI,KAAK,IAAI,CAAC,IAAM,IAEzD,MAAM,mBACN,MAAM,kBAAkB,KAAML,CAAY,CAElD,CACJ,ECjFA,IAAqBM,GAArB,MAAqBA,WAAeC,EAAW,CAsD3C,YAAYC,EAAcC,EAAmC,CACzD,MAAM,EAVVC,EAAA,KAAiB,mBACjBA,EAAA,KAAiB,QACjBA,EAAA,KAAiB,iBAAiB,KAClCA,EAAA,KAAQ,mBAA8B,CAAC,GACvCA,EAAA,KAAQ,sBAAqC,CAAC,GAC9CA,EAAA,KAAQ,uBAAsC,CAAC,GAC/CA,EAAA,KAAQ,gBAA+B,MACvCA,EAAA,KAAQ,mBAAmB,GAKvB,KAAK,KAAOF,EACZ,KAAK,gBAAkBC,EACvB,KAAK,0BAA0B,CACnC,CAxDA,OAAO,0BAA0BE,EAA+B,CAC5DL,GAAO,wBAA0BK,CACrC,CAEA,OAAO,OAAOH,EAAcC,EAAmC,CACtDH,GAAO,YACRA,GAAO,UAAY,IAAIA,GAAOE,EAAKC,CAAc,EAEzD,CAEA,OAAO,IAAIG,EAAeC,EAAgBC,EAAc,GAAa,CAC7DR,GAAO,WACPA,GAAO,UAAU,IAAIM,EAAMC,EAAOC,CAAW,CAErD,CAEA,OAAO,UAAUF,EAAeG,EAAyCD,EAAc,GAAa,CAC5FR,GAAO,WACPA,GAAO,UAAU,UAAUM,EAAMG,EAAQD,CAAW,CAE5D,CAEA,OAAO,eAAeC,EAA4DD,EAAc,GAAa,CACrGR,GAAO,WACPA,GAAO,UAAU,eAAeS,EAAQD,CAAW,CAE3D,CAEA,OAAO,eAAeC,EAA4DD,EAAc,GAAa,CACrGR,GAAO,WACPA,GAAO,UAAU,eAAeS,EAAQD,CAAW,CAE3D,CAEA,OAAO,SAAU,CACTR,GAAO,WACPA,GAAO,UAAU,QAAQ,EAE7BA,GAAO,UAAY,IACvB,CAmBS,IAAIM,EAAeC,EAAgBC,EAAc,GAAO,CAC7D,IAAMC,EAAiC,CAAC,EACpC,OAAOF,EAAU,MACjBE,EAAO,MAAQF,GAGnB,KAAK,aAAaD,EAAMG,EAAQD,CAAW,EAEvC,KAAK,iBACL,KAAK,gBAAgB,IAAIF,EAAMC,EAAOC,CAAW,CAEzD,CAEA,UAAUF,EAAcG,EAAyCD,EAAc,GAAO,CAClF,KAAK,aAAaF,EAAMG,EAAQD,CAAW,CAC/C,CAEA,eAAeE,EAA0DF,EAAc,GAAO,CAC1F,IAAMG,EAAc,OAAO,OAAOD,EAAM,CACpC,KAAM,KAAK,mBAAmB,EAC9B,UAAW,KAAK,KAAK,CACzB,CAAC,EAGD,OAAO,KAAKC,CAAW,EAAE,QAASC,GAAQ,CAClCD,EAAYC,CAAG,IAAM,QACrB,OAAOD,EAAYC,CAAG,CAE9B,CAAC,EAED,KAAK,oBAAoB,KAAKD,CAA0B,GAEpDH,GAAe,CAAC,KAAK,gBACrB,KAAK,WAAW,CAExB,CAEA,eAAeE,EAA0DF,EAAc,GAAO,CAC1F,IAAMK,EAAc,OAAO,OAAOH,EAAM,CACpC,KAAM,KAAK,mBAAmB,EAC9B,UAAW,KAAK,KAAK,CACzB,CAAC,EAED,KAAK,qBAAqB,KAAKG,CAA0B,GAErDL,GAAe,CAAC,KAAK,gBACrB,KAAK,WAAW,CAExB,CAES,SAAU,CACf,KAAK,WAAW,EAChB,KAAK,aAAa,EAEd,KAAK,iBACL,KAAK,gBAAgB,QAAQ,CAErC,CAEQ,aAAaM,EAAmBC,EAAyCP,EAAsB,CACnG,IAAME,EAAgB,CAClB,KAAM,EACN,KAAM,EACN,UAAAI,EACA,UAAW,KAAK,KAAK,EACrB,OAAQ,OAAO,OAAOC,EAAQ,CAAE,KAAM,KAAK,mBAAmB,CAAE,CAAC,EACjE,IAAK,KAAK,KAAK,UAAU,CAC7B,EAEA,KAAK,iBAAiB,KAAKL,CAAI,GAE3BF,GAAe,CAAC,KAAK,gBACrB,KAAK,WAAW,CAExB,CAEQ,oBAAoC,CACxC,GAAIR,GAAO,wBACP,GAAI,CACA,OAAOA,GAAO,wBAAwB,CAC1C,MAAY,CACR,OAAO,IACX,CAEJ,OAAO,IACX,CAEQ,YAAa,CACjB,KAAK,aAAa,EAClB,IAAIgB,EAA0B,GAE1B,KAAK,iBAAiB,OAAS,IAC/B,KAAK,cAAc,KAAK,gBAAgB,EACxC,KAAK,iBAAmB,CAAC,EACzBA,EAA0B,IAG1B,KAAK,oBAAoB,OAAS,IAClC,KAAK,iBAAiB,KAAK,mBAAmB,EAC9C,KAAK,oBAAsB,CAAC,EAC5BA,EAA0B,IAG1B,KAAK,qBAAqB,OAAS,IACnC,KAAK,kBAAkB,KAAK,oBAAoB,EAChD,KAAK,qBAAuB,CAAC,EAC7BA,EAA0B,IAG1BA,GACA,KAAK,cAAc,CAE3B,CAEQ,eAAgB,CACpB,KAAK,cAAgB,OAAO,WAAW,IAAM,KAAK,WAAW,EAAG,KAAK,cAAc,CACvF,CAEQ,cAAe,CACf,KAAK,gBACL,aAAa,KAAK,aAAa,EAC/B,KAAK,cAAgB,KAE7B,CAEQ,cAAcN,EAAiB,CACnC,KAAK,KAAK,IAAIA,CAAI,CACtB,CAEQ,iBAAiBA,EAAqB,CAC1C,KAAK,KAAK,eAAeA,CAAI,CACjC,CAEQ,kBAAkBA,EAAqB,CAC3C,KAAK,KAAK,gBAAgBA,CAAI,CAClC,CAEA,MAAc,2BAA4B,CACtC,GAAI,CACA,IAAMO,EAAa,MAAM,KAAK,KAAK,cAAc,EACjD,KAAK,iBAAmB,KAAK,IAAI,EAAIA,CACzC,MAAY,CAAC,CACjB,CAEQ,MAAO,CAEX,OAAO,KAAK,IAAI,EAAI,KAAK,gBAC7B,CACJ,EAjNIb,EADiBJ,GACF,aACfI,EAFiBJ,GAEF,0BAAwD,MAF3E,IAAqBkB,EAArBlB,GCPA,IAAAmB,EAAuE,uBCAvE,IAAKC,QACDA,EAAA,QAAU,UACVA,EAAA,YAAc,cACdA,EAAA,gBAAkB,kBAClBA,EAAA,mBAAqB,qBACrBA,EAAA,OAAS,SACTA,EAAA,cAAgB,gBAChBA,EAAA,gBAAkB,kBAClBA,EAAA,kBAAoB,oBACpBA,EAAA,sBAAwB,wBACxBA,EAAA,yBAA2B,2BAC3BA,EAAA,yBAA2B,4BAC3BA,EAAA,sBAAwB,wBACxBA,EAAA,iBAAmB,mBACnBA,EAAA,oBAAsB,sBACtBA,EAAA,oBAAsB,sBACtBA,EAAA,aAAe,eACfA,EAAA,YAAc,cACdA,EAAA,eAAiB,iBACjBA,EAAA,gBAAkB,kBAClBA,EAAA,kBAAoB,oBACpBA,EAAA,aAAe,eACfA,EAAA,gBAAkB,kBAClBA,EAAA,gBAAkB,kBAClBA,EAAA,aAAe,eACfA,EAAA,aAAe,eACfA,EAAA,YAAc,cACdA,EAAA,YAAc,cACdA,EAAA,iBAAmB,mBACnBA,EAAA,yBAA2B,2BAC3BA,EAAA,gBAAkB,kBAClBA,EAAA,uBAAyB,yBACzBA,EAAA,eAAiB,iBACjBA,EAAA,iBAAmB,mBACnBA,EAAA,2BAA6B,6BAC7BA,EAAA,iBAAmB,mBACnBA,EAAA,oBAAsB,sBACtBA,EAAA,kBAAoB,oBACpBA,EAAA,UAAY,YACZA,EAAA,aAAe,eACfA,EAAA,aAAe,eACfA,EAAA,kBAAoB,oBACpBA,EAAA,iBAAmB,mBACnBA,EAAA,UAAY,YACZA,EAAA,aAAe,eACfA,EAAA,eAAiB,iBACjBA,EAAA,aAAe,eACfA,EAAA,YAAc,cACdA,EAAA,SAAW,WACXA,EAAA,UAAY,YACZA,EAAA,SAAW,WACXA,EAAA,YAAc,cACdA,EAAA,kBAAoB,oBACpBA,EAAA,iBAAmB,mBACnBA,EAAA,eAAiB,iBACjBA,EAAA,qBAAuB,uBACvBA,EAAA,6BAA+B,+BAC/BA,EAAA,eAAiB,iBACjBA,EAAA,iBAAmB,mBA1DlBA,QAAA,IA6DEC,EAAQD,GC1Df,IAAKE,QAMDA,EAAA,sBAAwB,aAKxBA,EAAA,kBAAoB,SAKpBA,EAAA,eAAiB,MAKjBA,EAAA,cAAgB,aAKhBA,EAAA,WAAa,UAKbA,EAAA,cAAgB,QAKhBA,EAAA,kBAAoB,mBAKpBA,EAAA,cAAgB,aAKhBA,EAAA,WAAa,aAKbA,EAAA,QAAU,UAKVA,EAAA,QAAU,UAKVA,EAAA,YAAc,cAKdA,EAAA,iBAAmB,kBAKnBA,EAAA,IAAM,MAKNA,EAAA,KAAO,OAKPA,EAAA,gBAAkB,kBAjFjBA,QAAA,IAmFEC,GAAQD,GCnFf,IAAKE,QACDA,EAAA,MAAQ,QACRA,EAAA,MAAQ,QACRA,EAAA,eAAiB,iBACjBA,EAAA,cAAgB,gBAChBA,EAAA,cAAgB,gBAChBA,EAAA,QAAU,UANTA,QAAA,IASEC,GAAQD,GCZf,IAAWE,SACPA,GAAA,kBAAoB,uBACpBA,GAAA,gBAAkB,qBAClBA,GAAA,kBAAoB,uBACpBA,GAAA,gBAAkB,qBAClBA,GAAA,gBAAkB,gBAClBA,GAAA,iBAAmB,sBACnBA,GAAA,eAAiB,oBACjBA,GAAA,QAAU,cACVA,GAAA,MAAQ,YACRA,GAAA,OAAS,aACTA,GAAA,qBAAuB,yBACvBA,GAAA,oBAAsB,wBACtBA,GAAA,YAAc,iBACdA,GAAA,kBAAoB,uBACpBA,GAAA,aAAe,kBACfA,GAAA,cAAgB,YAChBA,GAAA,yBAA2B,sBAC3BA,GAAA,cAAgB,cAChBA,GAAA,gBAAkB,gBAClBA,GAAA,UAAY,WACZA,GAAA,sBAAwB,sBACxBA,GAAA,uBAAyB,sBACzBA,GAAA,gBAAkB,qBAClBA,GAAA,KAAO,WACPA,GAAA,UAAY,gBACZA,GAAA,aAAe,iBACfA,GAAA,mBAAqB,wBACrBA,GAAA,cAAgB,mBAChBA,GAAA,0BAA4B,8BA7BrBA,SAAA,IAgCJC,EAAQD,GChCf,IAAAE,GAAmB,iCCKnB,IAA8BC,GAA9B,KAAyC,CAAzC,cACIC,EAAA,KAAU,UAAyB,MAEnC,MAAgB,cACZC,EACAC,EACAC,EAAoB,CAAC,EACrBC,EAAmC,CAAC,EACpCC,EAAqC,CAAC,EACzB,CACb,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACpC,IAAMC,EAAWL,EAAW,KAAK,GAAG,EAC9BM,EAAO,IAAI,KAAK,CAACR,EAAoB,mBAAmBO,CAAQ,IAAI,EAAG,CAAE,KAAM,uCAAwC,CAAC,EACxHE,EAAU,OAAO,IAAI,gBAAgBD,CAAI,EAC/C,KAAK,QAAU,IAAI,OAAOC,CAAO,EACjC,KAAK,QAAQ,UAAaC,GAAM,CAC5B,OAAQA,EAAE,KAAK,KAAM,CACjB,YACIL,EAAQ,EACR,MAEJ,YACIC,EAAOI,EAAE,KAAK,KAAK,EACnB,MAEJ,YACIT,EAAQS,EAAE,IAAI,EACd,MAEJ,YACIC,EAAM,MAAMD,EAAE,KAAK,OAAO,EAC1B,MAEJ,gBACIE,EAAO,IAAIC,EAAQ,MAAOH,EAAE,KAAK,OAAO,EACxC,KACR,CACJ,EACA,KAAK,qBAAgCP,EAAUC,CAAQ,CAC3D,CAAC,CACL,CAEU,eAAsB,CAC5B,KAAK,SAAS,UAAU,EACxB,KAAK,QAAU,IACnB,CAEU,cAAcU,EAAcC,EAA+B,CAAC,EAAGX,EAAqC,CAAC,EAAS,CACpH,KAAK,SAAS,YAAY,OAAO,OAAO,CAAE,KAAAU,CAAK,EAAGC,CAAI,EAAGX,CAAQ,CACrE,CAEA,OAAO,oBAA8B,CACjC,MAAM,IAAI,MAAM,iBAAiB,CACrC,CACJ,EDrDA,IAAqBY,GAArB,cAA2CC,EAA+B,CACtE,MAAM,KAAKC,EAA0CC,EAAwCC,EAAgD,CACzIC,EAAM,MAAM,uBAAuB,EACnC,MAAM,KAAK,cACP,slEACCC,GAAc,CACX,GAAIA,EAAK,MACLD,EAAM,KAAK,gBAAiBC,EAAK,KAAK,EACtCH,EAAaG,EAAK,KAAK,UAChBA,EAAK,gBACZD,EAAM,MAAM,kCAAkC,EAC9CD,EAAoB,MACjB,CACH,IAAMG,EAAY,IAAI,UAAU,IAAI,kBAAkBD,EAAK,IAAI,EAAGA,EAAK,MAAOA,EAAK,MAAM,EACzFJ,EAAaK,CAAS,CAC1B,CACJ,EACA,CAAC,GAAAC,QAAQ,GAAAA,QAAO,MAAM,CAC1B,CACJ,CAEA,YAAYC,EAAmBH,EAAkBI,EAAgBC,EAA0B,CACvF,KAAK,sBAAiC,CAAE,UAAAF,EAAW,KAAMH,EAAK,OAAQ,MAAAI,EAAO,SAAAC,EAAU,MAAON,EAAM,QAAQ,CAAE,EAAG,CAACC,EAAK,MAAM,CAAC,CAClI,CAEA,SAAgB,CACZ,KAAK,cAAc,EACnBD,EAAM,MAAM,yBAAyB,CACzC,CAEA,OAAgB,oBAA8B,CAC1C,MAAO,gBAAiB,QAAU,WAAY,MAClD,CACJ,EEjCA,IAAqBO,GAArB,cAA8CC,EAA+B,CACzE,MAAM,KAAKC,EAA2CC,EAAwCC,EAAgD,CAC1IC,EAAM,MAAM,0BAA0B,EAEtC,MAAM,KAAK,cACP,kvEACCC,GAAc,CACPA,EAAK,OACLD,EAAM,KAAK,mBAAoBC,EAAK,KAAK,EACzCH,EAAaG,EAAK,KAAK,GAChBA,EAAK,iBACZD,EAAM,MAAM,qCAAqC,EACjDD,EAAoB,IAEpBF,EAAaI,EAAK,IAAI,EACtBA,EAAK,KAAK,MAAM,EAIxB,EACA,CAACC,EAAY,kBAAkB,GAAK,IAAMA,EAAY,YAAY,IAAM,QAAQ,CACpF,CACJ,CAEA,YAAYC,EAAmBF,EAAkBG,EAAgBC,EAAW,GAAa,CACrF,KAAK,sBAAiC,CAAE,UAAAF,EAAW,KAAMF,EAAK,OAAQ,MAAAG,EAAO,SAAAC,CAAS,EAAG,CAACJ,EAAK,MAAM,CAAC,CAC1G,CAEA,SAAgB,CACZ,KAAK,cAAc,EACnBD,EAAM,MAAM,4BAA4B,CAC5C,CAEA,OAAgB,oBAA8B,CAC1C,MACI,iBAAkB,QAClB,WAAY,QACZ,eAAgB,QAEhB,CAACE,EAAY,mBAAmB,GAGhCA,EAAY,YAAY,IAAM,SAEtC,CACJ,ECnDA,IAAqBI,GAArB,KAA8B,CAM1B,YAAYC,EAA4B,KAAMC,EAAa,EAAG,CAL9DC,EAAA,KAAQ,WAAW,GACnBA,EAAA,KAAQ,YAAY,GACpBA,EAAA,KAAQ,uBAAuB,KAAK,IAAI,GACxCA,EAAA,KAAiB,gBAAiC,MAG9C,KAAK,cAAgBF,EACjBC,IACA,KAAK,UAAY,OAAO,YAAY,IAAM,KAAK,UAAU,EAAGA,CAAU,EAE9E,CAEA,UAAUE,EAAQ,EAAS,CACvB,KAAK,UAAYA,CACrB,CAEA,WAAoB,CAChB,IAAMC,EAAM,KAAK,IAAI,EACfC,EAAKD,EAAM,KAAK,qBAChBE,EAAM,KAAK,MAAO,KAAK,SAAW,IAAQD,CAAE,EAElD,YAAK,SAAW,EAChB,KAAK,qBAAuBD,EAE5B,KAAK,gBAAgBE,CAAG,EACjBA,CACX,CAEA,SAAU,CACN,OAAO,cAAc,KAAK,SAAS,EACnC,KAAK,UAAY,CACrB,CACJ,ECjCA,IAAAC,GAA0B,sBCA1B,IAAKC,QACDA,EAAA,KAAO,OACPA,EAAA,MAAQ,QAFPA,QAAA,IAKEC,GAAQD,GCDR,IAAME,GAAoB,CAC7B,OAAQ,IACR,MAAO,KACP,QAAS,GACb,EAEaC,GAA6B,OAEpCC,GAA4C,CAC9C,CAAE,UAAW,IAAK,QAAS,IAAQ,EACnC,CAAE,UAAW,IAAK,QAAS,GAAQ,EACnC,CAAE,UAAW,IAAK,QAAS,GAAQ,EACnC,CAAE,UAAW,IAAK,QAAS,GAAQ,EACnC,CAAE,UAAW,KAAM,QAAS,IAAU,EACtC,CAAE,UAAW,KAAM,QAAS,IAAU,EACtC,CAAE,UAAW,KAAM,QAAS,IAAU,EACtC,CAAE,UAAW,KAAM,QAAS,GAAU,CAC1C,EAEaC,GAA8D,CACvE,EAAG,EACH,EAAG,EACH,EAAG,CACP,EAEO,SAASC,GAAqBC,EAA4BC,EAA4B,CACzF,MAAI,CAACD,GAAO,CAACC,EACFD,IAAQC,EAEfD,EAAI,QAAQ,SAAWC,EAAI,QAAQ,OAC5BD,EAAI,QAAQ,MAAM,CAACE,EAAQC,IAAMC,EAAM,gBAAgBF,EAAQD,EAAI,QAAQE,CAAC,CAAC,CAAC,EAElF,EACX,CAEO,SAASE,GAAeC,EAAsBC,EAAkC,CAEnF,QAAWC,KAAWD,EAClB,GAAID,GAAgBE,EAAQ,UACxB,OAAOA,EAAQ,QAGvB,OAAO,OAAS,EAAID,EAAS,OAAS,CAAC,EAAE,QAAUV,GAAkB,CAAC,EAAE,OAC5E,CAEO,SAASY,GAAuBC,EAAQf,GAAkB,MAAOgB,EAAShB,GAAkB,OAAQY,EAAWV,GAAmB,CAErI,IAAMe,EAAiB,CAAC,IAAK,IAAK,GAAG,EAC/BN,EAAe,KAAK,IAAII,EAAOC,CAAM,EAGvCE,EAAS,EACTP,GAAgB,IAChBO,EAAS,EACFP,GAAgB,MACvBO,EAAS,GAEb,IAAMC,EAAgC,CAAE,QAAS,CAAC,CAAE,EAC9CC,EAAM,GAERC,EAAUX,GAAeC,EAAcC,CAAQ,GAAKZ,GAAkB,QAC1E,QAASQ,EAAI,EAAGA,EAAIU,EAAQV,IAAK,CAC7B,IAAMc,EAAML,EAAKT,CAAC,EAClBW,EAAc,QAAQ,KAAK,CAAE,IAAAG,EAAK,MAAAP,EAAO,OAAAC,EAAQ,IAAAI,EAAK,QAAAC,CAAQ,CAAC,EAC/DN,EAAQ,KAAK,MAAMA,EAAQ,CAAC,EAC5BC,EAAS,KAAK,MAAMA,EAAS,CAAC,EAC9BK,EAAUX,GAAe,KAAK,IAAIK,EAAOC,CAAM,EAAGJ,CAAQ,GAAK,KAAK,MAAMS,EAAU,CAAC,CACzF,CAEA,OAAOF,CACX,CAEO,SAASI,GAA0BD,EAAc,CACpD,OAAOA,EAAOnB,GAAoCmB,CAAG,GAAK,EAAK,CACnE,CC9EO,IAAME,GACT,OAAO,OAAO,aAAgB,WACxB,OAAO,YACP,SAAoDC,EAA6D,CAC7G,GAAI,CAACA,GAAW,CAACA,EAAQ,OAAO,QAAQ,EACpC,MAAM,IAAI,MAAM,0DAA0D,EAE9E,IAAMC,EAA0B,CAAC,EACjC,OAAW,CAACC,EAAKC,CAAK,IAAKH,EACvBC,EAAIC,CAAG,EAAIC,EAEf,OAAOF,CACX,EAGV,eAAsBG,GAAkBC,EAAkC,CACtE,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACpC,IAAMC,EAAa,IAAI,WACvBA,EAAW,OAAUC,GAAU,CAC3BH,EAAQG,EAAM,QAAQ,MAAqB,CAC/C,EACAD,EAAW,QAAUD,EACrBC,EAAW,kBAAkBH,CAAI,CACrC,CAAC,CACL,CCZO,IAAMK,GAAuB,IACvBC,GAAuB,IAC9BC,GAA4B,IAC5BC,GAAc,UACdC,GAA+B,4BAG3BC,QAAV,CACI,IAAMC,EAAgB,UAChBC,EAAY;AAAA,EAElB,SAASC,EAAwBC,EAAiBC,EAAyB,CACvE,IAAMC,EAAoB,IAAI,OAAO,wCAAwC,EACzEC,EACEC,EAAS,CAAC,EAChB,IAAKD,EAAI,EAAGA,EAAIH,EAAM,OAAQ,EAAEG,EAAG,CAC/B,IAAME,EAAcL,EAAMG,CAAC,EAAE,MAAMD,CAAiB,EAChDG,GAAeA,EAAY,SAAW,GAAKA,EAAY,CAAC,IAAMJ,GAC9DG,EAAO,KAAKC,EAAY,CAAC,CAAC,CAElC,CACA,OAAOD,CACX,CAEA,SAASE,EAAgBC,EAAeC,EAA0BC,EAA0B,CACxF,IAAMC,EAAWH,EAAM,MAAM,GAAG,EAG1BI,EAAUD,EAAS,MAAM,EAAG,CAAC,EAG/BP,EACJ,IAAKA,EAAI,EAAGA,EAAIO,EAAS,OAAQP,IACzBM,EAAe,SAASC,EAASP,CAAC,CAAC,GACnCQ,EAAQ,KAAKD,EAASP,CAAC,CAAC,EAGhC,IAAKA,EAAI,EAAGA,EAAIO,EAAS,OAAQP,IACzB,CAACM,EAAe,SAASC,EAASP,CAAC,CAAC,GAAK,CAACK,EAAe,SAASE,EAASP,CAAC,CAAC,GAC7EQ,EAAQ,KAAKD,EAASP,CAAC,CAAC,EAGhC,OAAOQ,EAAQ,KAAK,GAAG,CAC3B,CAEA,SAASC,EAAcZ,EAAiBa,EAAmBL,EAA0BC,EAA0B,CAC3G,IAAIN,EACEW,EAAS,KAAOD,EACtB,IAAKV,EAAI,EAAGA,EAAIH,EAAM,OAAQ,EAAEG,EACxBH,EAAMG,CAAC,EAAE,WAAWW,CAAM,IAC1Bd,EAAMG,CAAC,EAAIG,EAAgBN,EAAMG,CAAC,EAAGK,EAAgBC,CAAc,EAG/E,CAEA,SAASM,EAA2Bf,EAAiBgB,EAAmB,CACpE,IAAMC,EAAkB,IAAI,OAAOvB,GAAc,QAAQ,EACzD,QAASS,EAAI,EAAGA,EAAIH,EAAM,OAAQ,EAAEG,EAAG,CACnC,IAAME,EAAcL,EAAMG,CAAC,EAAE,MAAMc,CAAe,EAClD,GAAIZ,GAAeA,EAAY,SAAW,GAAKW,EAAQ,SAASX,EAAY,CAAC,CAAC,EAAG,CAC7E,IAAMa,EAAgBlB,EAAMG,CAAC,EAAE,KAAK,IAAMT,GAAcW,EAAY,CAAC,EAAI,IAAM,IAC/EL,EAAMG,CAAC,GAAKe,EAAgBvB,EAChC,CACJ,CACJ,CAEA,SAASwB,EAAYnB,EAAiBC,EAAe,CACjD,IAAMmB,EAASrB,EAAwBC,EAAOC,CAAK,EACnD,GAAI,CAACmB,EAAO,OACR,OAGJ,IAAMZ,EAA2BY,EAAO,MAAM,CAAC,EAEzCC,EAAqB,IAAI,OAAO3B,GAAc,mBAAmB,EACnES,EACJ,IAAKA,EAAI,EAAGA,EAAIH,EAAM,OAAQ,EAAEG,EAAG,CAC/B,IAAME,EAAcL,EAAMG,CAAC,EAAE,MAAMkB,CAAkB,EACjDhB,GAAeA,EAAY,SAAW,GAAKG,EAAe,SAASH,EAAY,CAAC,CAAC,GACjFG,EAAe,KAAKH,EAAY,CAAC,CAAC,CAE1C,CAGA,IAAMiB,EAAkB,IAAI,OAAO,mCAAmC,EAGtE,IADAnB,EAAIH,EAAM,OACHG,KAAK,CACR,IAAME,EAAcL,EAAMG,CAAC,EAAE,MAAMmB,CAAe,EAC9CjB,GAAeA,EAAY,SAAW,GAAKG,EAAe,SAASH,EAAY,CAAC,CAAC,GACjFL,EAAM,OAAOG,EAAG,CAAC,CAEzB,CAEAS,EAAcZ,EAAO,QAASQ,EAAgB,CAAC,CAAC,CACpD,CAEA,SAASe,EAAiCvB,EAAiBwB,EAAeC,EAAaxB,EAAyB,CAC5G,IAAMC,EAAoB,IAAI,OAAO,wCAAwC,EACzEC,EACEiB,EAAS,CAAC,EAChB,IAAKjB,EAAIqB,EAAOrB,EAAIsB,EAAK,EAAEtB,EAAG,CAC1B,IAAME,EAAcL,EAAMG,CAAC,EAAE,MAAMD,CAAiB,EAChDG,GAAeA,EAAY,SAAW,GAAKA,EAAY,CAAC,IAAMJ,GAC9DmB,EAAO,KAAKf,EAAY,CAAC,CAAC,CAElC,CACA,GAAI,CAACe,EAAO,OACR,OAAOA,EAIX,IAAMC,EAAqB,IAAI,OAAO3B,GAAc,mBAAmB,EACvE,IAAKS,EAAIqB,EAAOrB,EAAIsB,EAAK,EAAEtB,EAAG,CAC1B,IAAME,EAAcL,EAAMG,CAAC,EAAE,MAAMkB,CAAkB,EACjDhB,GAAeA,EAAY,SAAW,GAAKe,EAAO,SAASf,EAAY,CAAC,CAAC,GACzEe,EAAO,KAAKf,EAAY,CAAC,CAAC,CAElC,CACA,OAAOe,CACX,CAEA,SAASM,EAAqB1B,EAAiBwB,EAAeC,EAAaxB,EAAuB,CAC9F,IAAMO,EAAiBe,EAAiCvB,EAAOwB,EAAOC,EAAKxB,CAAK,EAChF,GAAI,CAACO,EAAe,OAChB,OAAOiB,EAAM,EAIjB,IAAMH,EAAkB,IAAI,OAAO,mCAAmC,EAElEK,EAAU,EACVxB,EAAIsB,EACR,KAAOtB,GAAKqB,GAAO,CACf,IAAMnB,EAAcL,EAAMG,CAAC,EAAE,MAAMmB,CAAe,EAC9CjB,GAAeA,EAAY,SAAW,GAAKG,EAAe,SAASH,EAAY,CAAC,CAAC,IACjFL,EAAM,OAAOG,EAAG,CAAC,EACjBwB,KAEJxB,GACJ,CAGA,OAAAH,EAAMwB,CAAK,EAAIlB,EAAgBN,EAAMwB,CAAK,EAAGhB,EAAgB,CAAC,CAAC,EAExDiB,EAAME,EAAU,CAC3B,CAEA,SAASC,EAAiB5B,EAAiBC,EAAe4B,EAA8BC,EAA6B,CACjH,IAAIC,EAAS,GACTC,EAAO,GACPC,EAAgB,GACpB,QAAS9B,EAAI,EAAGA,EAAIH,EAAM,OAAQ,EAAEG,EAahC,GAZI4B,GAAU,GAAK/B,EAAMG,CAAC,EAAE,WAAW,IAAI,IACvC6B,EAAO7B,EAAI,EACP8B,IACA9B,EAAIuB,EAAqB1B,EAAO+B,EAAQC,EAAM/B,CAAK,GAEvD8B,EAAS,GACTC,EAAO,GACPC,EAAgB,IAEhBjC,EAAMG,CAAC,EAAE,WAAW,SAAS,IAC7B4B,EAAS5B,GAET4B,GAAU,EAAG,CAEb,IAAMG,EAAaL,IAAa,UAAYC,IAAS,WAAeD,IAAa,SAAWC,IAAS,UAAa,WAAa,YAC3H9B,EAAMG,CAAC,EAAE,WAAW,KAAK+B,CAAS,EAAE,GAAKlC,EAAMG,CAAC,EAAE,WAAW,YAAY,KACzE8B,EAAgB,GAExB,CAEJD,EAAOhC,EAAM,OAAS,EAClB+B,GAAU,GACNE,GACAP,EAAqB1B,EAAO+B,EAAQC,EAAM/B,CAAK,CAG3D,CAEA,SAASkC,EAAUnC,EAAiBoC,EAAqBC,EAAkC,CACvF,IAAMrB,EAAUjB,EAAwBC,EAAO,MAAM,EACjDoC,GACAxB,EAAcZ,EAAO,QAAS,CAAC,EAAGgB,CAAO,EAEzCqB,GACAtB,EAA2Bf,EAAOgB,CAAO,CAEjD,CAEA,SAASsB,EAAStC,EAAiB,CAC/B,IAAMuC,EAASxC,EAAwBC,EAAO,KAAK,EACnDY,EAAcZ,EAAO,QAAS,CAAC,EAAGuC,CAAM,CAC5C,CAEO,SAASC,EACZC,EACAL,EACAM,EACAC,EACAN,EACAO,EAAc,GACdC,EAAY,GACN,CACN,GAAI,CAACT,GAAc,CAACM,GAAqB,CAACC,GAAa,CAACE,GAAa,CAACD,GAAe,CAACP,EAClF,OAAOI,EAOX,SAASK,EAAkB9C,EAA2B,CAClD,IAAM+C,GAAW,CAAC,qBAAsB,wBAAwB,EAC1DjC,GAAS,gBACTkC,GAAQhD,EAAM,UAAWiD,IAASA,GAAK,WAAWnC,EAAM,CAAC,EAC/D,MAAI,CAACkC,KACDhD,EAAMgD,EAAK,EAAIhD,EAAMgD,EAAK,EAAIlD,EAAYiD,GAAS,KAAKjD,CAAS,GAE9DE,CACX,CAEA,SAASkD,EAASlD,EAAiB,CAC/B,IAAMmD,GAASpD,EAAwBC,EAAO,KAAK,EAC/CmD,GAAO,OAAS,GAChBvC,EAAcZ,EAAO,QAAS,CAAC,EAAGmD,EAAM,CAEhD,CAEA,IAAMC,GAAWX,EAAI,MAAM5C,CAAa,EACxC,OAAI6C,EACAd,EAAiBwB,GAAU,OAAQ,QAAS,SAAS,GAC9ChB,GAAcC,IACrBF,EAAUiB,GAAUhB,EAAYC,CAAuB,EAGvDM,GACAL,EAASc,EAAQ,EAEjBP,GACAK,EAASE,EAAQ,EAEjBR,GACAE,EAAkBM,EAAQ,EAEvBA,GAAS,KAAKtD,CAAS,CAClC,CAnDOF,GAAS,cAAA4C,EAqDT,SAASa,EACZZ,EACAa,EACAlB,EACAmB,EACAZ,EACAa,EACAC,EACM,CACFH,IACAb,EAAMA,EACD,QAAQ,mDAAoD,gCAAgC,EAC5F,QAAQ,mBAAoB,uCAAuC,GAG5E,IAAMW,EAAWX,EAAI,MAAM5C,CAAa,EAExC,OAAI0D,EACApC,EAAYiC,EAAU,MAAM,EACrBhB,GACPD,EAAUiB,EAAUhB,EAAY,EAAK,EAIrCoB,GAAoBC,EACpBtC,EAAYiC,EAAU,KAAK,EACpBI,EACP5B,EAAiBwB,EAAU,MAAO,SAAU,SAAS,EAC9CK,EACP7B,EAAiBwB,EAAU,MAAO,SAAU,SAAS,EAC9CT,GACPL,EAASc,CAAQ,EAGdA,EAAS,KAAKtD,CAAS,CAClC,CAnCOF,GAAS,eAAAyD,EAqCT,SAASK,EAAgBC,EAAiC,CAC7D,OAAOA,EAAS,GAAGA,EAAO,MAAQ,YAAY,IAAIA,EAAO,EAAE,GAAK,GACpE,CAFO/D,GAAS,gBAAA8D,EAIT,SAASE,EAAcC,EAAkCC,EAAkC,CAC9F,OAAOD,GAAWA,EAAQ,KAAOC,EAAQ,KAAOD,EAAQ,MAAQ,iBAAmBC,EAAQ,MAAQ,aACvG,CAFOlE,GAAS,cAAAgE,EAIhB,eAAsBG,EAA0BC,EAA6D,CACzG,IAAMC,EAAqC,CAAE,MAAO,KAAM,OAAQ,IAAK,EAEvE,GAAI,CAACD,GAAM,CAACA,EAAG,SACX,OAAOC,EAGX,GAAI,CACA,IAAMC,EAAQ,MAAMF,EAAG,SAAS,IAAI,EAChCG,EAAa,KAYjB,GAVAD,EAAM,QAASE,GAAc,CACrBA,EAAK,OAAS,aAAeA,EAAK,wBAClCD,EAAQD,EAAM,IAAIE,EAAK,uBAAuB,EACvCA,EAAK,OAAS,kBAAoBA,EAAK,QAAU,aAAe,CAACD,IACpE,CAAC,OAAO,OAAOC,EAAM,UAAU,GAAKA,EAAK,YACzCD,EAAQC,EAGpB,CAAC,EAEGD,GAAO,iBAAkB,CACzB,IAAME,EAAYH,EAAM,IAAIC,EAAM,gBAAgB,EAC9CE,IACAJ,EAAM,MAAQ,CACV,KAAMI,EAAU,cAChB,GAAIA,EAAU,IAAMA,EAAU,UAC9B,KAAMA,EAAU,MAAQA,EAAU,UACtC,EAER,CAEA,GAAIF,GAAO,kBAAmB,CAC1B,IAAME,EAAYH,EAAM,IAAIC,EAAM,iBAAiB,EAC/CE,IACAJ,EAAM,OAAS,CACX,KAAMI,EAAU,cAChB,GAAIA,EAAU,IAAMA,EAAU,UAC9B,KAAMA,EAAU,MAAQA,EAAU,UACtC,EAER,CAEA,OAAOJ,CACX,MAAiB,CACb,OAAOA,CACX,CACJ,CA/CArE,GAAsB,0BAAAmE,EAiDtB,IAAMO,GAAoB,WACpBC,GAAuB,mBAEtB,SAASC,GAAcC,EAAgC3C,EAAiB4C,GAAS,KAAuB,CAC3G,IAAMC,EAAQ,OAAOF,CAAE,EACvB,OAAIF,GAAqB,KAAKI,CAAK,GAC/BC,EAAM,KAAK,yBAAyBH,CAAE,oBAAoB3C,CAAI,GAAG,EAC1D6C,GACA7C,IAAS4C,GAAS,MAClB,IAAMC,EACN7C,IAAS4C,GAAS,KAClB,IAAMC,GAEbC,EAAM,KAAK,iBAAiB9C,CAAI,aAAa2C,CAAE,GAAG,EAC3CE,EAAM,MAAML,EAAiB,EAAI,IAAMK,EAAQA,EAE9D,CAbO/E,GAAS,cAAA4E,GAeT,SAASK,EAAqBJ,EAAgC3C,EAAgBgD,EAAY,EAAkB,CAC/G,IAAMC,EAASP,GAAcC,EAAI3C,CAAI,EACrC,OAAOkD,GAAQD,EAAQD,CAAS,CACpC,CAHOlF,GAAS,qBAAAiF,EAKT,SAASG,GAAQC,EAA8BH,EAAmC,CACrF,OAAQA,EAA0BG,EAAc1F,GAAuBC,GAAuBsF,EAA1EG,CACxB,CAFOrF,GAAS,QAAAoF,GAIT,SAASE,EAAUC,EAA0D,CAChF,OAAON,EAAqBM,EAAY,GAAIA,EAAY,QAAUT,GAAS,KAAMS,EAAY,SAAS,CAC1G,CAFOvF,GAAS,UAAAsF,EAIT,SAASE,GAAoBD,EAAsE,CACtG,GAAKA,EAAY,iBAIjB,OAAON,EAAqBM,EAAY,iBAAkBA,EAAY,QAAUT,GAAS,KAAMS,EAAY,SAAS,CACxH,CANOvF,GAAS,oBAAAwF,GAQT,SAASC,GAAiBC,EAA0C,CACvE,OAAOA,EAAQ,YAAcJ,EAAUI,EAAQ,WAAW,EAAIT,EAAqBS,EAAQ,cAAeA,EAAQ,iBAAmBZ,GAAS,KAAMY,EAAQ,SAAS,CACzK,CAFO1F,GAAS,iBAAAyF,GAIT,SAASE,GAAYd,EAA0D,CAClF,OAAI,OAAOA,GAAO,SACPe,GAAYC,GAAuBhB,CAAE,EAAE,eAAe,EAAE,GAG5DA,CACX,CANO7E,GAAS,YAAA2F,GAQT,SAASC,GAAYP,EAA2E,CACnG,IAAMN,EAAQ,OAAOM,CAAW,EAC1BS,EAAQf,EAAM,MAAMJ,EAAoB,EAE9C,OAAImB,EACO,CAAE,GAAI,OAAOA,EAAM,CAAC,CAAC,EAAG,KAAMA,EAAM,CAAC,IAAM,IAAMhB,GAAS,MAAQA,GAAS,IAAK,GAEvFE,EAAM,KAAK,4BAA4BK,CAAW,GAAG,EAC9C,CAAE,GAAI,OAAON,CAAK,EAAG,KAAMD,GAAS,IAAK,EAExD,CAVO9E,GAAS,YAAA4F,GAYT,SAASC,GAAuBE,EAAuF,CAC1H,IAAMC,EAASD,EAAc,MAAMpG,GAAuBC,EAAoB,EAC9E,MAAO,CACH,gBAAiBoG,EAAO,CAAC,EACzB,UAAWA,EAAO,OAAS,EAAI,SAASA,EAAO,CAAC,EAAG,EAAE,EAAI,CAC7D,CACJ,CANOhG,GAAS,uBAAA6F,GAkBT,SAASI,IAAe,CAC3B,IAAMC,EAAa,OAAO,QAAQ,aAAa,EAC/C,GAAIA,EACA,OAAOA,EAGX,IAAMC,EAAkB,uCAAuC,MAAM,EAAE,EACjE3F,EAAmB,IAAI,MAAM,EAAE,EACjC4F,EAAM,EACNC,EACA9F,EAEJ,IAAKA,EAAI,EAAGA,EAAI,GAAIA,IACZA,IAAM,GAAKA,IAAM,IAAMA,IAAM,IAAMA,IAAM,GACzCC,EAAOD,CAAC,EAAI,IACLA,IAAM,GACbC,EAAOD,CAAC,EAAI,KAER6F,GAAO,IACPA,EAAO,SAAY,KAAK,OAAO,EAAI,SAAa,GAEpDC,EAAID,EAAM,GACVA,EAAMA,GAAO,EACb5F,EAAOD,CAAC,EAAI4F,EAAM5F,IAAM,GAAM8F,EAAI,EAAO,EAAMA,CAAC,GAGxD,OAAO7F,EAAO,KAAK,EAAE,CACzB,CA3BOR,GAAS,KAAAiG,GA6BT,SAASK,GAA8DC,EAASC,EAAY,CAC/F,IAAIC,EAEJ,SAASC,KAAsBC,EAAsB,CACjD,IAAMC,EAAQ,KAEVH,GACA,OAAO,aAAaA,CAAO,EAG/BA,EAAU,OAAO,WAAW,IAAM,CAC9BF,EAAK,MAAMK,EAAOD,CAAK,CAC3B,EAAGH,CAAE,CACT,CAEA,OAAOE,CACX,CAhBO1G,GAAS,SAAAsG,GAkBT,SAASO,GAAehE,EAA4B,CACvD,GAAI,CAAC,OAAO,OACR,OAAO,KAGX,IAAIiE,EAAiB,GACfC,EAAkBlE,EAAI,MAAM;AAAA,CAAI,EAEtC,QAAWmE,KAAKD,EACZ,GAAIC,EAAE,WAAW,eAAe,EAAG,CAC/B,IAAMC,EAAoBD,EAAE,MAAM,GAAG,EACrC,GAAIC,EAAQ,SAAW,EAAG,CACtBH,EAAiBG,EAAQ,CAAC,EAC1B,KACJ,CACJ,CAGJ,GAAI,CAACH,EACD,OAAO,OAAO,EAAE,EAGpB,IAAMI,EAAsBJ,EAAe,MAAM,GAAG,EAChDtG,EAAS,OAAO,CAAC,EAErB,QAASD,EAAI,KAAK,IAAI,EAAG2G,EAAU,OAAS,CAAC,EAAG3G,GAAK,EAAGA,IAAK,CACzD,IAAM4G,EAAU,OAAO,SAASD,EAAU3G,CAAC,EAAG,EAAE,CAAC,EACjDC,IAAW,OAAO,CAAC,EACnBA,GAAU2G,CACd,CAEA,OAAO,OAAO,OAAO,GAAI3G,CAAM,CACnC,CAhCOR,GAAS,eAAA6G,GAkChB,eAAsBO,GAAMC,EAAc,CACtC,OAAO,IAAI,QAASC,GAAY,OAAO,WAAWA,EAASD,CAAI,CAAC,CACpE,CAFArH,GAAsB,MAAAoH,GAIf,SAASG,GAAcnD,EAAuBoD,EAA8BC,EAAmB,CAClG,IAAMC,EAAmB,CAAC,EAC1B,OAAAtD,EAAG,WAAW,EAAE,QAAS4C,GAAMW,GAAwBH,EAAeR,EAAGA,EAAE,MAAOS,EAAcC,CAAW,CAAC,EACrGA,CACX,CAJO1H,GAAS,cAAAuH,GAMT,SAASI,GAAwBH,EAA8BR,EAAiBY,EAAgCH,EAAmBC,EAAkB,CAKxJ,GAJI,CAAC,aAAa,UAAU,eAAiB,CAAC,aAAa,UAAU,eAIjE,CAACF,GAAiB,CAACI,GAASA,EAAM,OAAS,QAC3C,OAGJ,IAAMC,EAAgBD,EAAM,YAAY,EACxC,GAAI,CAACC,EACD,OAGJ,IAAIC,EAA+BN,EAAc,YAAcA,EAAc,YAAc,KAAO,KAE5FO,EAAaF,EAAc,MAC3BG,EAAcH,EAAc,OAC5BI,GACFF,GAAcC,GAAeR,EAAc,aAAe,KAAK,IAAI,EAAG,KAAK,IAAIO,EAAYC,CAAW,EAAIR,EAAc,YAAY,EAAI,KAEtIU,EAAoCV,EAAc,cAAgB,KAExE,GAAIO,GAAcC,GAAeR,EAAc,cACvCA,EAAc,aAAe,KAAK,IAAIO,EAAYC,CAAW,EAAG,CAGhE,IAAMG,GAAc,KAAK,MAAOJ,EAAaC,EAAe,GAAG,EACzDI,IAAW,KAAK,MAAOD,GAActI,GAA6B,GAAM,EAAI,GAAK,IAEvFiI,EAAgBA,IAAkB,KAAOM,GAAU,KAAK,IAAIA,GAASN,CAAa,CACtF,CAGJ,IAAMO,GAAwDb,EAAc,uBAAyB,WAE/Fc,GAAoBb,EAAaG,EAAM,EAAE,EAC/C,GACIU,IACAA,GAAkB,UAAYR,GAC9BQ,GAAkB,wBAA0BL,IAC5CK,GAAkB,eAAiBJ,GACnCI,GAAkB,wBAA0BD,GAC9C,CACEX,EAAYE,EAAM,EAAE,EAAIU,GAExB,MACJ,CAEAZ,EAAYE,EAAM,EAAE,EAAI,CACpB,QAASE,EACT,sBAAuBG,GACvB,aAAcC,EACd,sBAAuBG,EAC3B,EAEA,IAAME,GAAevB,EAAE,cAAc,EAKrC,GAJKuB,GAAa,YAEdA,GAAa,UAAY,CAAC,CAAC,CAAC,GAE5BA,GAAa,UAAU,OAAS,GAAKR,GAAcC,GAAeR,EAAc,aAAc,CAE9F,IAAMgB,GAAkB,KAAK,MAAMhB,EAAc,aAAe,IAAI,EAC9DiB,GAAiB,KAAK,IAAIV,EAAYC,CAAW,EAEjDU,GAA+BC,GAAuBZ,EAAYC,EAAaR,GAAe,UAAU,OAAO,EAC/GoB,GAASF,GAAc,QAAQ,OACrC1D,EAAM,IACF,mCAAmCwC,EAAc,YAAY,cAAcgB,EAAe,UAAUT,CAAU,IAAIC,CAAW,QAAQ,KAAK,UAAUU,EAAa,CAAC,EACtK,EACAH,GAAa,UAAU,QAAQ,CAACM,GAAUtI,KAAM,CAC5CsI,GAAS,sBAAwBC,GAA0BD,GAAS,GAAG,EACvE,IAAME,GAAY,KAAK,MAAMN,GAAiBI,GAAS,qBAAqB,EACxEtI,GAAIqI,GAAS,EACbC,GAAS,OAASE,GAAYP,GACvBjI,IAAKqI,GACZC,GAAS,OAAS,GAElBA,GAAS,OAAS,GAElBtI,GAAIqI,GACJC,GAAS,WAAaH,GAAc,QAAQnI,EAAC,EAAE,QAE/CsI,GAAS,WAAa,EAE1BA,GAAS,gBAAkBG,EAC/B,CAAC,CACL,MACIT,GAAa,UAAU,QAASU,IAAM,CAC9BzB,GAAe,kBACfyB,GAAE,gBAAkBzB,EAAc,iBAElCM,EACAmB,GAAE,WAAanB,EAEf,OAAOmB,GAAE,WAEThB,GACAgB,GAAE,sBAAwBhB,GAE1B,OAAOgB,GAAE,sBAETf,EACAe,GAAE,aAAef,EAEjB,OAAOe,GAAE,YAEjB,CAAC,EAIL,GAFAV,GAAa,sBAAwBF,GAEjCE,GAAa,UAAU,OAAS,EAAG,CACnCvB,EAAE,gBAAgBuB,EAAY,EAAE,MAAOU,IAAM,CACzCjE,EAAM,MAAM,kCAAmCuD,GAAcU,EAAC,CAClE,CAAC,EACD,IAAMC,GAAelC,EAAE,cAAc,EACrChC,EAAM,IAAI,8CAA8C,KAAK,UAAUkE,GAAa,SAAS,CAAC,EAAE,CACpG,CACJ,CAvHOlJ,GAAS,wBAAA2H,GA8HT,SAASwB,GAAcC,EAAeC,EAAoC,CACxE,MAAM,QAAQA,CAAM,IACrBA,EAAS,CAACA,CAAM,GAGpB,QAAWC,KAAQD,EACf,GAAID,EAAI,SAASE,CAAI,EACjB,MAAO,GAIf,MAAO,EACX,CAZOtJ,GAAS,cAAAmJ,GAmBT,SAASI,GAAoBhE,EAA6F,CAC7H,OAAO,OAAO,QAAQA,EAAY,kBAAkB,OAAS,CAAC,CAAC,EAAE,OAA+B,CAACiE,EAAK,CAACC,EAAKC,CAAK,KACzGnE,EAAY,mBACZiE,EAAIC,CAAG,EAAI,CACP,GAAIlE,EAAY,iBAAiB,cAAckE,CAAG,EAClD,MAAAC,CACJ,GAEGF,GACR,CAAC,CAAC,CACT,CAVOxJ,GAAS,oBAAAuJ,GAgBT,SAASI,GAAsBC,EAAoD,CACtF,IAAMpJ,EAASoJ,EAAa,IAAKrE,IACoB,CAC7C,IAAKA,EAAY,WACjB,cAAeA,EAAY,cAC3B,OAAQA,EAAY,OACpB,WAAYA,EAAY,WACxB,cAAeA,EAAY,cAC3B,iBAAkBA,EAAY,iBAC9B,QAASA,EAAY,QACrB,gBAAiBA,EAAY,gBAC7B,MAAOA,EAAY,KACvB,EAEH,EAED,OAAKsE,EAAO,gBAGLrJ,EAAO,OAAQ+E,GAAgB,CAACA,EAAY,IAAI,QAAQ,EAFpD/E,CAGf,CApBOR,GAAS,sBAAA2J,GAyBT,SAASG,GAAwBC,EAA8BC,EAAuC,CACzG,IAAMC,EAAW,OAAO,KAAKF,CAAI,EAC3BG,EAAW,OAAO,KAAKF,CAAI,EAEjC,GAAIC,EAAS,SAAWC,EAAS,OAC7B,MAAO,GAGX,QAAWT,KAAOQ,EASd,GARI,CAAC,OAAO,OAAOC,EAAUT,CAAG,GAI5BM,EAAKN,CAAG,EAAE,QAAUO,EAAKP,CAAG,EAAE,OAI9BM,EAAKN,CAAG,EAAE,KAAOO,EAAKP,CAAG,EAAE,GAC3B,MAAO,GAIf,MAAO,EACX,CAvBOzJ,GAAS,wBAAA8J,GAyBT,SAASK,GAAqCC,EAA0BC,EAA0BC,EAAO,GAAgB,CAC5H,IAAMC,EAAQ,OAAO,KAAKH,CAAI,EACxBI,EAAQ,OAAO,KAAKH,CAAI,EAE9B,GAAIE,EAAM,SAAWC,EAAM,OACvB,MAAO,GAGX,QAAWf,KAAOc,EAAO,CACrB,GAAI,CAAC,OAAO,OAAOF,EAAMZ,CAAG,EACxB,MAAO,GAGX,IAAMgB,EAAOL,EAAKX,CAAG,EACfiB,EAAQL,EAAKZ,CAAG,EAEtB,GAAIa,GAAQK,GAASF,CAAI,GAAKE,GAASD,CAAK,EACxC,OAAOP,GAAgBM,EAAMC,EAAOJ,CAAI,EAG5C,GAAIG,IAASC,EACT,MAAO,EAEf,CAEA,MAAO,EACX,CA1BO1K,GAAS,gBAAAmK,GA4BT,SAASS,GAAkBC,EAAWC,EAAW,CACpD,GAAID,EAAK,SAAWC,EAAK,OACrB,MAAO,GAGX,QAAWxB,KAAQuB,EACf,GAAIC,EAAK,QAAQxB,CAAI,EAAI,EACrB,MAAO,GAIf,MAAO,EACX,CAZOtJ,GAAS,eAAA4K,GAcT,SAASG,GAAcC,EAAa,CACvC,MAAO,CAAC,OAAO,KAAKA,CAAG,EAAE,MAC7B,CAFOhL,GAAS,cAAA+K,GAQT,SAASE,GAAyBC,EAAoDC,EAAoD,CAC7I,GAAI,CAACD,GAAW,CAACC,EACb,MAAO,GAGX,GAAI,CAACD,GAAW,CAACC,EACb,OAAOD,EAAU,GAAK,EAG1B,OAAOE,EAAcD,EAAQ,KAAMD,EAAQ,IAAI,GAAKE,EAAcF,EAAQ,GAAIC,EAAQ,EAAE,GAAKE,EAAUH,EAASC,CAAO,EAEvH,SAASE,EAAUC,EAAwCC,EAAwC,CAC/F,IAAMC,EAAe,CACjB,CAAC1G,GAAS,IAAI,EAAG,EACjB,CAACA,GAAS,KAAK,EAAG,CACtB,EACM,CAAE,gBAAiB2G,EAAkB,UAAWC,CAAW,EAAI7F,GAAuByF,EAAQ,EAAE,EAChG,CAAE,gBAAiBK,GAAkB,UAAWC,CAAW,EAAI/F,GAAuB0F,EAAQ,EAAE,EAChG,CAAE,GAAIM,GAAK,KAAMC,EAAM,EAAIlG,GAAY6F,CAAgB,EACvD,CAAE,GAAIM,GAAK,KAAMC,EAAM,EAAIpG,GAAY+F,EAAgB,EAC7D,OAAOP,EAAcI,EAAaM,EAAK,EAAGN,EAAaQ,EAAK,CAAC,GAAKZ,EAAcS,GAAKE,EAAG,GAAKX,EAAcM,EAAYE,CAAU,CACrI,CAEA,SAASR,EAAca,EAAWC,EAAmB,CACjD,OAAOD,EAAIC,EAAI,GAAKD,IAAMC,EAAI,EAAI,CACtC,CACJ,CA1BOlM,GAAS,yBAAAiL,GA6BT,SAASkB,GAAgEnB,EAAQoB,EAA6B,CACjH,IAAMC,EAAW,OAAO,QAAQrB,CAAG,EAAE,OAAO,CAAC,CAAC,CAAEsB,CAAG,IAC3C,MAAM,QAAQF,CAAK,EACZ,CAACA,EAAM,SAASE,CAAG,EAEvBA,IAAQF,CAClB,EACD,OAAOG,GAAYF,CAAQ,CAC/B,CAROrM,GAAS,sBAAAmM,GAUT,SAASK,EAAkCxB,EAAQyB,EAA0DC,EAAoB,CACpI,IAAIC,EAAeD,EACnB,QAAWjD,KAAOuB,EACT,OAAO,OAAOA,EAAKvB,CAAG,IAG3BkD,EAAeF,EAASE,EAAc3B,EAAIvB,CAAG,EAAGA,CAAG,GAEvD,OAAOkD,CACX,CATO3M,GAAS,aAAAwM,EAWHxM,GAAA,cAAgB,IAAM,CAC/B,IAAI4M,EAAc,EACZC,EAAkD,CAAC,EACrDC,EAAwC,KAC5C,OAAI,OAAO,eAAmB,MAC1BA,EAAiB,IAAI,eACrBA,EAAe,MAAM,UAAaC,GAAU,CACxC,IAAMC,EAAkBD,EAAM,KAC1BF,EAAkBG,CAAO,IACzBH,EAAkBG,CAAO,EAAE,EAC3B,OAAOH,EAAkBG,CAAO,EAExC,GAGG,SAAUC,EAAgC,CAC7C,GAAIH,GAAkB,SAAS,kBAAoB,SAAU,CAIzD,IAAMI,EAAWN,EACjB,OAAAA,EAAcA,GAAe,OAAO,iBAAmB,EAAIA,EAAc,EACzEC,EAAkBK,CAAQ,EAAID,EAC9BH,EAAe,MAAM,YAAYI,CAAQ,EAClC,IAAM,CACLL,EAAkBK,CAAQ,GAC1B,OAAOL,EAAkBK,CAAQ,CAEzC,CACJ,CACA,IAAMF,EAAU,WAAWC,EAAI,CAAC,EAChC,MAAO,IAAM,aAAaD,CAAO,CACrC,CACJ,GAAG,EAEI,SAASrC,GAASK,EAA6B,CAClD,OAAOA,IAAQ,MAAQ,OAAOA,GAAQ,UAAY,CAAC,MAAM,QAAQA,CAAG,CACxE,CAFOhL,GAAS,SAAA2K,GAIT,SAASwC,GAAwBtK,EAAauK,EAA0BC,EAAeC,EAAwB,CAClH,SAASC,EAAiBnN,EAAiBoN,EAAa,CACpD,IAAI5L,GAAQ,EACRC,EAAMzB,EAAM,OACZqN,GAAQ,GACZ,QAASlN,GAAI,EAAGA,GAAIH,EAAM,OAAQG,KAO9B,GANI,CAACkN,IAASrN,EAAMG,EAAC,EAAE,WAAW,SAAS,IACvCqB,GAAQrB,IAERH,EAAMG,EAAC,EAAE,WAAW,SAAWiN,CAAG,IAClCC,GAAQ,IAERA,IACIrN,EAAMG,EAAC,EAAE,WAAW,IAAI,EAAG,CAC3BsB,EAAMtB,GACN,KACJ,CAGR,MAAO,CAAE,MAAAqB,GAAO,IAAAC,CAAI,CACxB,CACA,SAAS6L,EAAsBtN,EAAiBwB,EAAeC,GAAa8L,EAAyBC,GAAYC,GAAWC,GAAW,CACnI,IAAMC,GAAY,SAAWJ,EAAM,QACnC,QAASpN,GAAIqB,EAAOrB,GAAIsB,GAAKtB,KAEzB,GADaH,EAAMG,EAAC,IACPwN,GAAW,CACpB,IAAMC,GAAQD,GAAY,cAAgBF,GAAI,eAAiBC,GAAI,WAAaF,GAChFxN,EAAMG,EAAC,EAAIyN,EACf,CAER,CACA,IAAMC,EAASb,GAAO,OACtB,GAAIa,GAAUA,EAAO,OAASb,EAAM,IAAK,CACrC,IAAMhN,EAAQyC,EAAI,MAAM5C,CAAa,EAC/B,CAAE,MAAA2B,EAAO,IAAAC,EAAI,EAAI0L,EAAiBnN,EAAOgN,EAAM,GAAG,EAClD7E,EAAe0F,EAAO,cAAc,EAC1C,GAAI1F,EAAa,UACb,OAAAA,EAAa,UAAU,QAASM,IAAa,CACzC,IAAM8E,GAAM9E,GAAS,IACf+E,GAAK/E,GAAS,WACdqF,GAAQrF,GAAS,sBACvB,GAAIwE,GAASC,GAAUY,GAAO,CAC1B,IAAML,GAAI,GAAK,KAAK,MAAMR,EAAQa,EAAK,EACjCJ,GAAI,GAAK,KAAK,MAAMR,EAASY,EAAK,EACxCR,EAAsBtN,EAAOwB,EAAOC,GAAK8L,GAAKC,GAAIC,GAAGC,EAAC,CAC1D,CACJ,CAAC,EACM1N,EAAM,KAAKF,CAAS,CAEnC,CACA,OAAO2C,CACX,CAnDO7C,GAAS,wBAAAmN,KA11BVnN,QAAA,KAg5BV,IAAOmO,EAAQnO,GCn6Bf,IAAWoO,QACPA,EAAA,YAAc,cACdA,EAAA,YAAc,cACdA,EAAA,oBAAsB,sBACtBA,EAAA,wBAA0B,2BAE1BA,EAAA,qBAAuB,uBACvBA,EAAA,gCAAkC,8BAClCA,EAAA,uBAAyB,uBACzBA,EAAA,WAAa,aAEbA,EAAA,uBAAyB,yBACzBA,EAAA,0BAA4B,4BAE5BA,EAAA,oBAAsB,sBACtBA,EAAA,sBAAwB,wBACxBA,EAAA,uBAAyB,yBACzBA,EAAA,2BAA6B,6BAC7BA,EAAA,kBAAoB,oBACpBA,EAAA,kBAAoB,oBAEpBA,EAAA,uBAAyB,yBACzBA,EAAA,yBAA2B,2BAC3BA,EAAA,0BAA4B,4BAC5BA,EAAA,8BAAgC,gCAChCA,EAAA,qBAAuB,uBACvBA,EAAA,qBAAuB,uBA1BhBA,QAAA,IA6BJC,EAAQD,GCtBR,IAAME,GAAwB,IAErC,SAASC,GAASC,EAA8BC,EAAaC,EAAoB,EAAQ,CACrF,OAAOD,KAAOD,GAAQA,EAAKC,CAAG,EAAID,EAAKC,CAAG,EAAIC,CAClD,CAEA,SAASC,MAAeC,EAAiB,CACrC,OAAQC,GAAgB,CACpB,QAAWC,KAAaF,EACpB,GAAIE,EAAUD,CAAM,EAChB,MAAO,GAIf,MAAO,EACX,CACJ,CAEA,SAASE,GAAaN,EAAaO,EAA8C,CAC7E,OAAQH,GACGA,EAAOJ,CAAG,IAAMO,CAE/B,CAEA,SAASC,GAAqBR,EAAa,CACvC,MAAO,CAACS,EAA2BC,IACxBA,EAAMV,CAAG,EAAIS,EAAKT,CAAG,CAEpC,CAEA,SAASW,GAAqCC,EAAmBC,EAAgC,CAC7F,OAAOA,EAAM,OACT,CAACC,EAAQf,KACLe,EAAOf,EAAKa,CAAQ,CAAC,EAAIb,EAClBe,GAEX,CAAC,CACL,CACJ,CAEA,SAASC,GAAaF,EAA+B,CACjD,IAAMG,EAA+B,CAAC,EAChCC,EAAM,CAAC,EACb,QAAWlB,KAAQc,EACVG,EAAIjB,EAAK,EAAE,IACZiB,EAAIjB,EAAK,EAAE,EAAI,GACfkB,EAAI,KAAKlB,CAAI,GAGrB,OAAOkB,CACX,CAEA,SAASC,GAAiBC,EAAU,CAChC,OAAO,OAAO,KAAKA,CAAG,EACjB,OAAQnB,GACEmB,EAAInB,CAAG,IAAM,MACvB,EACA,IAAKA,GACK,CAACA,EAAKmB,EAAInB,CAAG,CAAC,CACxB,EACA,OAAO,CAACc,EAAaM,KAClBN,EAAOM,EAAK,CAAC,CAAC,EAAIC,EAAM,SAASD,EAAK,CAAC,CAAC,EAAIF,GAAiBE,EAAK,CAAC,CAAC,EAAIA,EAAK,CAAC,EAEvEN,GACR,CAAC,CAAC,CACb,CAEA,SAASQ,GAAgBC,EAAqC,CAC1D,IAAMC,EAAqB,CAAC,EAC5B,QAAWC,KAAQF,EACfE,EAAK,QAAS1B,GAASyB,EAAO,KAAKzB,CAAI,CAAC,EAE5C,OAAOyB,CACX,CAMA,eAAeE,GAAaC,EAA4C,CACpE,IAAMC,EAA2C,CAAC,EAGlD,OAAI,eAAe,UAAU,UACzBA,EAAc,KAAK,GAAGD,EAAG,aAAa,EAAE,IAAKE,GAAaA,EAAS,SAAS,CAAC,CAAC,EAC9ED,EAAc,KAAK,GAAGD,EAAG,WAAW,EAAE,IAAKG,GAAWA,EAAO,SAAS,CAAC,CAAC,GAExEF,EAAc,KAAKD,EAAG,SAAS,CAAC,EAG7B,QAAQ,IAAIC,CAAa,EAAE,KAAKN,EAAe,EAAE,KAAKP,EAAY,CAC7E,CAMA,SAASgB,GAAiBR,EAAkC,CACxD,IAAMS,EAAgBT,EACjB,OAAOjB,GAAa,OAAQ,gBAAgB,CAAC,EAC7C,KAAKE,GAAqB,UAAU,CAAC,EACrC,KAAKN,GAAYI,GAAa,YAAa,EAAI,EAAGA,GAAa,WAAY,EAAI,CAAC,CAAC,EAEtF,GAAI,CAAC0B,EACD,MAAO,CACH,UAAW,EACX,yBAA0B,EAC1B,mBAAoB,EACpB,qBAAsB,EACtB,UAAW,EACX,cAAe,CACnB,EAGJ,IAAMC,EAA2B,CAC7B,UAAWD,EAAc,UACzB,yBAA0BA,EAAc,0BAA4B,EACpE,mBAAoBA,EAAc,oBAAsB,EACxD,qBAAsBA,EAAc,sBAAwB,EAC5D,UAAWA,EAAc,WAAa,EACtC,cAAeA,EAAc,eAAiB,CAClD,EAEME,EAAkBX,EAAM,KAAKjB,GAAa,KAAM0B,EAAc,iBAAiB,CAAC,EAClFE,GACA,OAAO,OAAOD,EAAW,CACrB,OAAQ,CACJ,KAAMC,EAAgB,cACtB,QAASA,EAAgB,IAAMA,EAAgB,QAC/C,KAAMA,EAAgB,KACtB,SAAUA,EAAgB,QAC9B,CACJ,CAAC,EAGL,IAAMC,EAAiBZ,EAAM,KAAKjB,GAAa,KAAM0B,EAAc,gBAAgB,CAAC,EACpF,OAAIG,GACA,OAAO,OAAOF,EAAW,CACrB,MAAO,CACH,KAAME,EAAe,cACrB,QAASA,EAAe,IAAMA,EAAe,QAC7C,KAAMA,EAAe,KACrB,SAAUA,EAAe,SACzB,cAAeA,EAAe,cAC9B,YAAaA,EAAe,WAChC,CACJ,CAAC,EAGEjB,GAAiBe,CAAS,CACrC,CAMA,SAASG,GAAYb,EAAmBc,EAAiCC,EAAsB,GAAkB,CAC7G,IAAMC,EAAyC5B,GAAM,KAAMY,CAAK,EAI5DiB,EAAWF,EACRf,EAAM,OAAOrB,GAAYI,GAAa,OAAQ,oBAAoB,CAAC,CAAC,EACpEiB,EAAM,OAAOrB,GAAYI,GAAa,OAAQ,aAAa,EAAGA,GAAa,OAAQ,cAAc,CAAC,CAAC,EAE1G,OAAImC,EAAY,YAAY,IAAM,YAI9BD,EAAW,OAAO,OACdA,EAAS,OAAO,CAACE,EAAcjB,IAAc,CACzC,GAAI,CAACiB,EAAQjB,EAAK,IAAI,EAClBiB,EAAQjB,EAAK,IAAI,EAAIA,MAClB,CACH,IAAMkB,EAAS,OAAO,OAAO,CAAC,EAAGD,EAAQjB,EAAK,IAAI,EAAGA,CAAI,EACnDmB,EAASF,EAAQjB,EAAK,IAAI,EAAE,SAAWA,EAAOiB,EAAQjB,EAAK,IAAI,EAErEkB,EAAO,GAAKC,EAAO,GACnBD,EAAO,KAAOC,EAAO,KAErB,OAAOD,EAAO,SACd,OAAOA,EAAO,SAEdD,EAAQC,EAAO,IAAI,EAAIA,CAC3B,CAEA,OAAOD,CACX,EAAG,CAAC,CAAC,CACT,GAGGF,EACF,IAAKf,GAAS,CACX,IAAMoB,EAAO,OAAOpB,EAAK,IAAI,EACvBqB,EAAOrB,EAAK,WAAaA,EAAK,KAC9BsB,EAAUtB,EAAK,UAAYA,EAAK,QAChCuB,EAAOvB,EAAK,KACZwB,EAAUxB,EAAK,QAErB,GAAI,CAACuB,GAAQ,CAACH,GAAQ,CAACC,EACnB,OAAO,KAGX,IAAMI,EAAe,CACjB,KAAAL,EACA,KAAAG,EACA,KAAAF,EACA,cAAehD,GAAS2B,EAAM,eAAe,EAC7C,UAAW3B,GAAS2B,EAAM,WAAW,EACrC,oBAAqB3B,GAAS2B,EAAM,qBAAqB,EACzD,gBAAiB3B,GAAS2B,EAAM,iBAAiB,EACjD,OAAQ3B,GAAS2B,EAAM,QAAQ,EAC/B,YAAa3B,GAAS2B,EAAM,aAAa,EACzC,gBAAiB3B,GAAS2B,EAAM,iBAAiB,EACjD,YAAa3B,GAAS2B,EAAM,aAAa,EACzC,aAAc3B,GAAS2B,EAAM,cAAc,EAC3C,SAAU3B,GAAS2B,EAAM,UAAU,EACnC,SAAU3B,GAAS2B,EAAM,UAAU,EACnC,UAAW3B,GAAS2B,EAAM,WAAW,EACrC,OAAQY,EAAQQ,CAAI,EACpB,YAAa/C,GAAS2B,EAAM,cAAe,CAAC,EAC5C,qBAAsB3B,GAAS2B,EAAM,uBAAwB,CAAC,CAClE,EAEM0B,EAAM,QAAS1B,GAAQ,OAAOA,EAAK,KAAQ,SAAWA,EAAK,IAAM,OACjE2B,EAAM,QAAS3B,GAAQ,OAAOA,EAAK,KAAQ,SAAWA,EAAK,IAAM,OAQvE,GAPI0B,IACAD,EAAI,IAAMC,GAEVC,IACAF,EAAI,IAAME,GAGVN,IAAS,QAAS,CAClB,IAAMO,EAAgBvD,GAAS2B,EAAM,eAAe,EAC9C6B,EAAuBxD,GAAS2B,EAAM,sBAAsB,EAC5D8B,EAA8BzD,GAAS2B,EAAM,6BAA6B,EAC1E+B,GAAU1D,GAAS2B,EAAM,uBAAuB,EAChDgC,GAAU3D,GAAS2B,EAAM,uBAAuB,EAClD+B,KACAN,EAAI,sBAAwBM,IAE5BC,KACAP,EAAI,sBAAwBO,IAEhCP,EAAI,yBAA2BK,EAA+BD,EAAuBA,EAAwBD,GAAiBA,CAClI,CAgBA,GAdIP,IAAS,SAAWI,EAAI,OAAS,iBACjCA,EAAI,gBAAkBpD,GAAS2B,EAAM,iBAAiB,GAAK,GAG3DqB,IAAS,UACTI,EAAI,qBAAuBpD,GAAS2B,EAAM,sBAAsB,EAChEyB,EAAI,iBAAmBpD,GAAS2B,EAAM,kBAAkB,EACxDyB,EAAI,+BAAiCpD,GAAS2B,EAAM,gCAAgC,EACpFyB,EAAI,8BAAgCpD,GAAS2B,EAAM,+BAA+B,EAClFyB,EAAI,uBAAyBpD,GAAS2B,EAAM,wBAAwB,EACpEyB,EAAI,kBAAoBpD,GAAS2B,EAAM,mBAAmB,EAC1DyB,EAAI,iBAAmBpD,GAAS2B,EAAM,kBAAkB,GAGxDwB,GAAWV,EAAaU,CAAO,EAAG,CAClC,IAAMS,EAAQnB,EAAaU,CAAO,EAClCC,EAAI,UAAYQ,EAAM,UACtBR,EAAI,SAAWQ,EAAM,SACjBZ,IAAS,SAAWY,EAAM,cAC1BR,EAAI,YAAcQ,EAAM,YAEhC,CAEA,GAAIX,GAAWR,EAAaQ,CAAO,EAAG,CAClC,IAAMY,EAAQpB,EAAaQ,CAAO,EAClCG,EAAI,YAAcS,EAAM,YACxBT,EAAI,WAAaS,EAAM,WACvBT,EAAI,cAAgBS,EAAM,cAC1BT,EAAI,eAAiBS,EAAM,eAC3BT,EAAI,cAAgBS,EAAM,aAC9B,CAEA,OAAOzC,GAAiBgC,CAAG,CAC/B,CAAC,EACA,OAAQ3C,GACE,CAAC,CAACA,CACZ,CACT,CAMA,SAASqD,GAAMC,EAAmBC,EAAoBxB,EAAsB,GAAiB,CAKzF,GAJI,CAACwB,GAID,CAACA,EAAS,MAAQ,CAACD,EAAQ,KAC3B,OAAOA,EAGX,IAAIE,EACAC,EACA1B,IACAyB,EAAoBpD,GAAM,OAAQkD,GAAS,YAAc,CAAC,CAAC,EAC3DG,EAAqBrD,GAAM,OAAQmD,GAAU,YAAc,CAAC,CAAC,GAGjE,IAAMG,EAAuCtD,GAAM,OAAQkD,EAAQ,IAAI,EACjEK,EAAwCvD,GAAM,OAAQmD,EAAS,IAAI,EACnEK,GAAQN,EAAQ,UAAYC,EAAS,WAAa,IAExD,MAAI,CAACG,GAAe,CAACC,GAIrB,OAAO,KAAKD,CAAW,EAAE,QAASpB,GAAS,CACvC,IAAMuB,EAAaH,EAAYpB,CAAI,EAC7BwB,EAAcH,EAAarB,CAAI,EAErC,GAAI,GAACuB,GAAc,CAACC,GAcpB,IAVID,EAAW,eAAiBA,EAAW,cAAgBC,EAAY,gBACnED,EAAW,UAAY,KAAK,OAAOA,EAAW,cAAgBC,EAAY,eAAiBF,CAAI,EAC/FC,EAAW,WAAa,KAAK,OAAOA,EAAW,oBAAsBC,EAAY,qBAAuBF,CAAI,GAG5GC,EAAW,WAAaA,EAAW,UAAYC,EAAY,YAC3DD,EAAW,UAAY,KAAK,OAAOA,EAAW,UAAYC,EAAY,WAAaF,CAAI,EACvFC,EAAW,WAAa,KAAK,OAAOA,EAAW,gBAAkBC,EAAY,iBAAmBF,CAAI,GAGpGC,EAAW,gBACX,GAAIA,EAAW,gBAAkBC,EAAY,iBAAmBD,EAAW,YAAcC,EAAY,YAAa,CAC9G,IAAMC,EAAOF,EAAW,YAAcC,EAAY,YAC5CE,EAAWH,EAAW,gBAAkBC,EAAY,gBAC1DD,EAAW,WAAa,YAAa,IAAME,GAASA,EAAOC,IAAW,QAAQ,CAAC,CAAC,CACpF,MACIH,EAAW,WAAa,EAQhC,GAJIA,EAAW,YAAcC,EAAY,cACrCD,EAAW,iBAAmBA,EAAW,YAAcC,EAAY,aAGnED,EAAW,qBAAuBC,EAAY,qBAAsB,CACpE,IAAMG,EAAOJ,EAAW,qBAAuBC,EAAY,qBAC3DD,EAAW,0BAA4BI,CAC3C,CAMA,GAJIJ,EAAW,eAAiBC,EAAY,eAAiBD,EAAW,cAAgBC,EAAY,gBAChGD,EAAW,mBAAqB,aAAaA,EAAW,cAAgBC,EAAY,eAAiBF,GAAM,QAAQ,CAAC,CAAC,GAGrH7B,GAAuB8B,EAAW,OAAS,gBAAkBA,EAAW,OAAS,QAAsB,CACvG,IAAMK,EAAYV,IAAoBlB,CAAI,EACpC6B,EAAoBV,IAAqBnB,CAAI,EAC7C8B,EAAkBpE,GAAmBA,GAAS,EAE9C+D,EAAO,KAAK,IAAI,EAAGK,EAAeF,GAAW,WAAW,EAAIE,EAAeD,GAAmB,WAAW,CAAC,EAC1GE,EAAO,KAAK,IAAI,EAAGR,EAAW,YAAcC,EAAY,WAAW,EACzER,EAAQ,UAAU,eAAiB,CAC/B,sBAAwBA,EAAQ,UAAU,qBAAuBC,EAAS,UAAU,sBAAwB,EAAK,IACjH,YAAa,KAAK,MAAOQ,EAAOM,EAAQ,GAAG,CAC/C,CACJ,EACJ,CAAC,EAEMf,CACX,CAEA,eAAegB,GAAalD,EAAuBmC,EAA2BzB,EAAkC,CAAC,EAAGC,EAAsB,GAA0B,CAChK,IAAMf,EAAQ,MAAMG,GAAaC,CAAE,EAC7BkC,EAAoB,CACtB,UAAW,KAAK,IAAI,EACpB,UAAW9B,GAAiBR,CAAK,EACjC,KAAMa,GAAYb,EAAOc,CAAO,CACpC,EAKA,OAJIC,IACAuB,EAAQ,WAAazB,GAAYb,EAAOc,EAAS,EAAI,GAGpDyB,EAMEF,GAAMC,EAASC,EAAUxB,CAAmB,GAJ/C,MAAMjB,EAAM,MAAMxB,EAAqB,EAChCgF,GAAalD,EAAIkC,EAASxB,EAASC,CAAmB,EAIrE,CAEA,SAASwC,GAAQC,EAAc,CAC3B,YAAY,WAAWA,CAAI,EAC3B,YAAY,KAAKA,CAAI,CACzB,CAEA,SAASC,GAAUD,EAAc,CAC7B,YAAY,WAAWA,CAAI,CAC/B,CAEA,SAASE,GAAYF,EAA6B,CAC9C,IAAMG,EAAO,YAAY,iBAAiBH,CAAI,EAAE,CAAC,EAEjD,GAAI,OAAOG,EAAS,IAChB,OAAO,KAGX,IAAMV,EAAO,KAAK,MAAM,YAAY,IAAI,EAAIU,EAAK,SAAS,EAC1D,mBAAY,WAAWH,CAAI,EAEpBP,CACX,CAEA,SAASW,GAAiCC,EAAoB,CAC1D,MAAO,GAAGC,EAAK,uBAAuB,IAAIC,GAAYF,CAAG,CAAC,EAC9D,CAEA,SAASE,GAAYF,EAAoB,CACrC,OAAO,OAAOA,GAAQ,SAAWA,EAAM,KAAK,UAAUA,CAAG,CAC7D,CAGA,IAAOG,GAAQ,CACX,aAAAxE,GACA,gBAAAO,GACA,iBAAAS,GACA,YAAAK,GACA,MAAAwB,GACA,aAAAiB,GACA,QAAAC,GACA,UAAAE,GACA,YAAAC,GACA,iCAAAE,EACJ,EChbO,IAAMK,GAAN,MAAMA,EAAe,CAArB,cAGHC,EAAA,KAAiB,gBAAgB,IAAI,KAErC,OAAO,QAAS,CACZD,GAAe,UAAY,IAAIA,EACnC,CAEA,OAAO,YAAYE,EAAsB,CACrC,GAAIF,GAAe,WAAW,cAAc,KAAM,CAC9C,QAAWG,KAAgBH,GAAe,UAAU,cAChD,OAAO,OAAOG,EAAc,CACxB,cAAeD,EAAO,cACtB,cAAeA,EAAO,cACtB,sBAAuBA,EAAO,sBAC9B,aAAcA,EAAO,aACrB,eAAgBA,EAAO,eACvB,uBAAwBA,EAAO,uBAC/B,UAAWA,EAAO,SACtB,CAAC,EACDE,EAAO,eAAeD,CAAY,EAEtCH,GAAe,UAAU,cAAc,MAAM,CACjD,CACAI,EAAO,eAAeF,CAAM,CAChC,CAGA,OAAO,gBAAgBA,EAA0B,CACzCA,EAAO,QAAU,SACjBA,EAAO,MAAQG,GAAW,YAAYH,EAAO,IAAI,GAEjDA,EAAO,QAAU,MACjBF,GAAe,WAAW,cAAc,IAAIE,CAAM,CAE1D,CAEA,OAAO,SAAU,CACbF,GAAe,WAAW,SAAS,EACnCA,GAAe,UAAY,IAC/B,CAEQ,UAAW,CACf,KAAK,cAAc,MAAM,CAC7B,CACJ,EA7CIC,EADSD,GACM,YAAmC,MAD/C,IAAMM,GAANN,GCLA,IAAMO,GAAN,KAAgC,CAInC,YAAYC,EAA8B,CAH1CC,EAAA,KAAmB,kBACnBA,EAAA,KAAU,sBAAsB,IAG5B,KAAK,eAAiBD,CAC1B,CAEA,QAAQE,EAAeC,EAAgB,CACnC,GAAI,KAAK,oBACL,OAGJ,KAAK,oBAAsB,GAE3B,IAAMC,EAAWC,GAAW,iCAAiC,KAAK,cAAc,EAC1EC,EAAWD,GAAW,YAAYD,CAAQ,EAE5CE,IAAa,MAIjBC,GAAe,gBAAgB,CAAE,KAAMC,EAAK,wBAAyB,MAAOF,EAAU,MAAAJ,EAAO,OAAAC,CAAO,CAAC,CACzG,CACJ,ERrBA,IAAMM,GAAoB,MAEpBC,GAAmC,mCAKnBC,GAAf,MAAeC,CAAkB,CAS1B,YAAYC,EAA8BC,EAAqBC,EAAiBC,EAAoC,CAR9HC,EAAA,KAAmB,kBACnBA,EAAA,KAAmB,aACnBA,EAAA,KAAmB,WACnBA,EAAA,KAAmB,wBACnBA,EAAA,KAAmB,8BAEnBA,EAAA,KAAU,UAAwB,CAAC,GAG/B,KAAK,eAAiBJ,EACtB,KAAK,UAAYC,EACjB,KAAK,QAAUC,EACf,KAAK,qBAAuBC,EAC5B,KAAK,2BAA6B,IAAIE,GAA0BL,CAAa,CACjF,CAEA,YAAYM,EAAyB,CACjC,IAAMC,EAAO,KAAK,QAAQ,OAE1B,GAAID,EAAM,MACN,KAAK,uBAAuB,EAAK,EACjC,KAAK,uBAAuB,EAAI,EAC5BC,IACAC,EAAM,KAAK,gCAAiC,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO,CAAC,EACpF,KAAK,QAAU,CAAC,WAGhB,CAACD,IAAS,KAAK,QAAQA,EAAO,CAAC,EAAE,SAAW,GAAKX,KAAsBU,EAAM,SAAU,CACvFE,EAAM,KAAK,oCAAoC,EAC/C,MACJ,CAKJ,GAFA,KAAK,QAAQ,KAAKF,CAAK,EAEnBA,EAAM,IAAK,CACX,IAAMG,EAAY,KAAK,kBAAkB,EACnC,CAAE,MAAAC,EAAO,OAAAC,CAAO,EAAIZ,EAAkB,aAAaU,CAAS,EAClE,KAAK,cAAc,CACf,UAAWH,EAAM,UACjB,UAAAG,EACA,MAAOH,EAAM,MACb,SAAUA,EAAM,SAChB,MAAAI,EACA,OAAAC,CACJ,CAAC,EAED,KAAK,2BAA2B,QAAQD,EAAOC,CAAM,CACzD,CACJ,CAEA,SAAU,CACNC,GAAW,UAAUf,EAAgC,EACrDe,GAAW,UAAUA,GAAW,iCAAiC,KAAK,cAAc,CAAC,EAErF,KAAK,QAAU,CAAC,CACpB,CAIQ,mBAA6C,CACjD,IAAMC,EAAS,KAAK,QACpB,KAAK,QAAU,CAAC,EAEhB,IAAMN,EAAOM,EAAO,OAAO,CAACC,EAAMC,IAAYD,EAAOC,EAAQ,KAAK,WAAY,CAAC,EACzEC,EAAS,IAAI,WAAWT,CAAI,EAE9BU,EAAS,EACb,QAAWX,KAASO,EAChBG,EAAO,IAAI,IAAI,WAAWV,EAAM,IAAI,EAAGW,CAAM,EAC7CA,GAAUX,EAAM,KAAK,WAGzB,OAAOU,CACX,CAEA,OAAO,aAAaP,EAAuE,CACvF,IAAMO,EAAS,CAAE,MAAO,EAAG,OAAQ,CAAE,EAC/BE,EAAS,IAAI,aAAUT,EAAU,MAAM,EAC7CS,EAAO,UAAY,GAEnBA,EAAO,OAAS,EAEhB,IAAMC,EAAgBD,EAAO,SAAS,CAAC,EAEjCE,EADiBF,EAAO,SAAS,CAAC,GACL,EAAKC,EAWxC,OAVIC,IAAY,GACZF,EAAO,QAGeA,EAAO,SAAS,CAAC,IACjB,GAIRA,EAAO,SAAS,CAAC,IACjB,IAIlBA,EAAO,QACPA,EAAO,QAEPA,EAAO,OAAS,GAEZE,GAAW,GACXF,EAAO,QAGQA,EAAO,SAAS,CAAC,IACjB,GACfA,EAAO,SACHE,IAAY,GAAKA,IAAY,KAC7BF,EAAO,OAAS,KAEbE,IAAY,GAAKA,IAAY,IACpCF,EAAO,QAIXF,EAAO,MAAQE,EAAO,SAAS,EAAE,EAAI,EACrCF,EAAO,OAASE,EAAO,SAAS,EAAE,EAAI,GAE/BF,CACX,CAEA,OAAO,oBAA8B,CACjC,MAAM,IAAI,MAAM,gDAAgD,CACpE,CAEQ,uBAAuBK,EAAgB,CAC3C,GAAIA,EAAO,CACPT,GAAW,QAAQf,EAAgC,EACnD,MACJ,CAEA,IAAMyB,EAAWV,GAAW,YAAYf,EAAgC,EACpEyB,IAAa,MAAQA,EAAW,KAChC,KAAK,QAAQ,CAAE,gBAAiBA,CAAS,CAAC,CAElD,CACJ,ES7JA,IAA8BC,GAA9B,KAA2C,CAG7B,YAAYC,EAAyC,CAF/DC,EAAA,KAAmB,aAGf,KAAK,UAAYD,CACrB,CAEA,MAAM,UAAUE,EAAkC,CAC9C,MAAM,IAAI,MAAM,4DAA4D,CAChF,CAEA,MAAM,UAAUC,EAAiC,CAC7C,MAAM,IAAI,MAAM,4DAA4D,CAChF,CAIA,OAAO,oBAA8B,CACjC,MAAM,IAAI,MAAM,gDAAgD,CACpE,CACJ,EChBA,IAAqBC,GAArB,cAA4CC,EAAa,CAQrD,YAAYC,EAAyC,CACjD,MAAMA,CAAQ,EARlBC,EAAA,KAAiB,mBAEjBA,EAAA,KAAQ,UAAoC,MAC5CA,EAAA,KAAQ,iBAAgF,MACxFA,EAAA,KAAQ,UAA2C,MACnDA,EAAA,KAAQ,SAA+C,MAInDC,EAAM,MAAM,wBAAwB,EAEpC,KAAK,gBAAkB,gBAAiB,MAC5C,CAEQ,cAAcC,EAAeC,EAAgB,CAC7C,KAAK,UAIT,KAAK,QAAU,SAAS,cAAc,QAAQ,EAC9C,KAAK,QAAQ,MAAQD,EACrB,KAAK,QAAQ,OAASC,EAEtB,KAAK,QAAQ,MAAM,cAAgB,OACnC,KAAK,QAAQ,MAAM,WAAa,SAChC,KAAK,QAAQ,MAAM,SAAW,WAC9B,KAAK,QAAQ,MAAM,MAAQ,QAC3B,KAAK,QAAQ,MAAM,OAAS,OAC5B,KAAK,QAAQ,MAAM,OAAS,IAC5B,KAAK,QAAQ,MAAM,MAAQ,IAC3B,KAAK,QAAQ,MAAM,OAAS,OAC5B,SAAS,KAAK,YAAY,KAAK,OAAO,EAElC,KAAK,gBACL,KAAK,eAAiB,KAAK,QAAQ,WAAW,gBAAgB,EAE9D,KAAK,eAAiB,KAAK,QAAQ,WAAW,IAAI,EAItD,KAAK,QAAU,KAAK,QAAQ,cAAc,CAAC,EAC3C,KAAK,OAAS,KAAK,QAAQ,eAAe,EAAE,CAAC,EAC7C,KAAK,OAAO,YAAc,OAC9B,CAEQ,eAAsB,CACtB,KAAK,UACL,KAAK,QAAQ,UAAU,EAAE,QAASC,GAA4BA,EAAM,KAAK,CAAC,EAC1E,KAAK,QAAU,KACf,KAAK,OAAS,MAElB,KAAK,eAAiB,KAEtB,GAAI,CACI,KAAK,SACL,SAAS,KAAK,YAAY,KAAK,OAAO,CAE9C,MAAY,CAAC,CACb,KAAK,QAAU,IACnB,CAEQ,qBAAsB,CACtB,KAAK,QAAU,KAAK,OAAO,aAC3B,KAAK,OAAO,aAAa,EAClB,KAAK,SAAW,KAAK,QAAQ,cAEpC,KAAK,QAAQ,aAAa,CAElC,CAEA,MAAc,WAAWC,EAA+C,CAC/D,KAAK,SACN,KAAK,cAAcA,EAAM,MAAOA,EAAM,MAAM,EAC5C,KAAK,UAAU,KAAK,OAAsB,GAI9C,IAAMC,EAAS,KAAK,QAIpB,GAHAA,EAAO,MAAQD,EAAM,MACrBC,EAAO,OAASD,EAAM,OAElB,KAAK,gBAAiB,CAQtB,IAAIE,EACJ,GAAIF,aAAiB,YACjBE,EAAcF,MACX,CACH,GAAM,CAAE,MAAOG,EAAG,OAAQC,EAAG,KAAAC,CAAK,EAAIL,EAIhCM,EAAWH,EAAIC,EAAI,EACzB,GAAIC,EAAK,aAAeC,EAAU,CAC9BV,EAAM,KAAK,mBAAoB,CAAE,EAAAO,EAAG,EAAAC,EAAG,IAAKC,EAAK,WAAY,SAAAC,CAAS,CAAC,EACvE,MACJ,CAEAJ,EAAc,MAAM,kBAAkBF,EAAO,EAAG,EAAGA,EAAM,MAAOA,EAAM,MAAM,CAChF,CAIA,GAAI,CAAC,KAAK,eAAgB,CACtBJ,EAAM,KAAK,wBAAwB,EACnCM,EAAY,MAAM,EAClB,MACJ,CAEgB,KAAK,eACb,wBAAwBA,CAAW,EAC3CA,EAAY,MAAM,CACtB,KAAO,CACH,IAAMK,EAAU,KAAK,eACrBA,EAAQ,UAAU,EAAG,EAAGN,EAAO,MAAOA,EAAO,MAAM,EACnDM,EAAQ,aAAaP,EAAoB,EAAG,CAAC,CACjD,CACA,KAAK,oBAAoB,CAC7B,CAGA,MAAe,UAAUQ,EAAkC,CAEvD,IAAMR,EAAQ,sBAAuBQ,EAAQ,MAAMA,EAAM,kBAAkB,EAAI,MAAM,kBAAkBA,CAAK,EAC5G,MAAM,KAAK,WAAWR,CAAK,CAE/B,CAEA,MAAe,UAAUA,EAAiC,CACtD,MAAM,KAAK,WAAWA,CAAK,CAC/B,CAES,SAAU,CACf,KAAK,cAAc,EACnBJ,EAAM,MAAM,0BAA0B,CAC1C,CAEA,OAAgB,oBAA8B,CAE1C,OACK,6BAA8B,QAAU,kCAAmC,SAE5E,EAAEa,EAAY,YAAY,IAAM,UAAY,OAAOA,EAAY,eAAe,CAAC,IAAM,KAErF,EAAEA,EAAY,YAAY,IAAM,WAAa,OAAOA,EAAY,eAAe,CAAC,EAAI,GAE5F,CACJ,ECvJA,IAAqBC,GAArB,cAAoDC,EAAa,CAK7D,YAAYC,EAAyC,CACjD,MAAMA,CAAQ,EALlBC,EAAA,KAAiB,cACjBA,EAAA,KAAiB,WACjBA,EAAA,KAAiB,WAIbC,EAAM,MAAM,gCAAgC,EAE5C,KAAK,WAAa,IAAI,0BAA0B,CAAE,YAA2B,CAAC,EAC9E,KAAK,QAAU,KAAK,WAAW,SAAS,UAAU,EAClD,KAAK,QAAU,IAAI,YAAY,CAAC,KAAK,UAAU,CAAC,EAChD,KAAK,UAAU,KAAK,OAAO,CAC/B,CAEA,MAAe,UAAUC,EAAmB,CACxC,MAAM,KAAK,QAAQ,MAAMA,CAAK,CAClC,CAES,SAAU,CACf,KAAK,QAAQ,YAAY,EACzB,KAAK,WAAW,SAAS,MAAM,EAAE,KAAK,IAAM,KAAK,WAAW,KAAK,CAAC,EAClED,EAAM,MAAM,kCAAkC,CAClD,CAEA,OAAgB,oBAA8B,CAC1C,MAAO,eAAgB,QAAU,8BAA+B,QAAUE,GAAiB,mBAAmB,CAClH,CACJ,ECtBA,IAAqBC,GAArB,cAA2CC,EAAkB,CAQzD,YAAYC,EAA8BC,EAAqBC,EAAiBC,EAAmC,CAC/G,MAAMH,EAAeC,EAAUC,EAAQC,CAAmB,EAR9DC,EAAA,KAAQ,aACRA,EAAA,KAAQ,YACRA,EAAA,KAAQ,gBAAgB,IACxBA,EAAA,KAAQ,eAAe,IACvBA,EAAA,KAAQ,gBAA6B,CAAC,GACtCA,EAAA,KAAQ,aAIJC,EAAM,MAAM,0CAA0CL,CAAa,GAAG,EAEtE,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,aAAa,CACtB,CAEU,cAAcM,EAAkB,CAClCA,EAAM,WAGN,KAAK,cAAgB,CAAC,GAE1B,KAAK,cAAc,KAAKA,CAAK,EAC7B,KAAK,aAAa,CACtB,CAEQ,eAAgB,CACpB,KAAK,UAAY,IAAIC,GAAUC,GAAgBH,EAAM,IAAI,mBAAmB,KAAK,cAAc,UAAUG,CAAG,EAAE,EAAG,GAAM,CAC3H,CAMQ,cAAcC,EAAsB,GAAO,CAC3CA,GAAuB,CAACC,GAAuB,mBAAmB,EAClE,KAAK,UAAY,IAAIC,GAAe,KAAK,SAAS,EAElD,KAAK,UAAY,IAAID,GAAuB,KAAK,SAAS,CAElE,CAMQ,aAAaE,EAAqB,GAAO,CACzCA,GAAsB,CAACC,GAAiB,mBAAmB,EAC3D,KAAK,SAAW,IAAIC,GAEpB,KAAK,SAAW,IAAID,GAGxB,IAAME,EAAU,MAAOT,GAAkC,CACrD,KAAK,aAAe,GAChB,eAAgB,QAAUA,aAAiB,WAC3C,MAAM,KAAK,UAAU,UAAUA,CAAmB,EAElD,MAAM,KAAK,UAAU,UAAUA,CAAkB,EAErD,KAAK,UAAU,UAAU,EACzB,KAAK,aAAa,CACtB,EAEMU,EAAgBC,GAAoB,CACtC,KAAK,aAAe,GACpB,KAAK,aAAa,EAGd,KAAK,oBAAoBJ,IACzB,OAAOI,GAAW,UAGlBA,EAAO,SAAS,eAAe,GAE/B,KAAK,uBAAuB,CAEpC,EAEA,KAAK,SAAS,KAAKF,EAASC,EAAc,KAAK,oBAAoB,EAAE,KAAK,IAAM,CAC5E,KAAK,cAAgB,GACrB,KAAK,aAAa,CACtB,CAAC,CACL,CAEQ,wBAAyB,CAC7BX,EAAM,KAAK,wCAAwC,EAE/C,KAAK,WACL,KAAK,UAAU,QAAQ,EAGvB,KAAK,WACL,KAAK,cAAgB,GACrB,KAAK,aAAe,GACpB,KAAK,SAAS,QAAQ,GAGtB,KAAK,WACL,KAAK,UAAU,QAAQ,EAG3B,KAAK,cAAc,EACnB,KAAK,cAAc,EAAI,EACvB,KAAK,aAAa,EAAI,CAC1B,CAEQ,cAAe,CACnB,GAAI,CAAC,KAAK,eAAiB,KAAK,aAC5B,OAGJ,IAAMC,EAAQ,KAAK,cAAc,MAAM,EACnCA,IACA,KAAK,aAAe,GACpB,KAAK,SAAS,YAAYA,EAAM,UAAWA,EAAM,UAAWA,EAAM,MAAOA,EAAM,QAAQ,EAE/F,CAES,SAAU,CACf,MAAM,QAAQ,EACd,KAAK,UAAU,QAAQ,EACvB,KAAK,SAAS,QAAQ,EACtB,KAAK,UAAU,QAAQ,EACvBD,EAAM,MAAM,2CAA2C,KAAK,cAAc,EAAE,CAChF,CAEA,OAAgB,oBAA8B,CAC1C,OAAOM,GAAe,mBAAmB,GAAKD,GAAuB,mBAAmB,CAC5F,CACJ,ECpHO,SAASQ,GAAWC,EAAmBC,EAAgBC,EAAcC,EAAmBC,EAAkBC,EAAgBC,EAAuC,CACpK,IAAIC,EAAQ,EACRN,IACAM,GAAS,GAETL,IACAK,GAAS,GAETJ,IACAI,GAAS,GAERD,IACDC,GAAS,GAGb,IAAMC,EAAS,IAAI,YAAY,EAAW,EACpCC,EAAO,IAAI,SAASD,CAAM,EAQhC,GAPAC,EAAK,SAAS,EAAG,CAAgB,EACjCA,EAAK,UAAU,EAAGL,CAAQ,EAC1BK,EAAK,UAAU,EAAGT,CAAS,EAC3BS,EAAK,SAAS,EAAGJ,EAAQ,EAAI,CAAC,EAC9BI,EAAK,UAAU,EAAG,CAAY,EAC9BA,EAAK,SAAS,GAAIF,CAAK,EAEnB,CAACD,EACD,OAAOE,EAGX,IAAME,EAAS,IAAI,WAAWF,EAAO,WAAaF,EAAK,UAAU,EACjE,OAAAI,EAAO,IAAI,IAAI,WAAWF,CAAM,EAAG,CAAC,EACpCE,EAAO,IAAI,IAAI,WAAWJ,CAAI,EAAGE,EAAO,UAAU,EAE3CE,EAAO,MAClB,CAEO,SAASC,GAAWL,EAA+B,CACtD,IAAMG,EAAO,IAAI,SAASH,CAAI,EAExBM,EAAkBH,EAAK,SAAS,CAAC,EACjCL,EAAWK,EAAK,UAAU,CAAC,EAC3BT,EAAYS,EAAK,UAAU,CAAC,EAC5BJ,EAAQI,EAAK,SAAS,CAAC,IAAM,EAC7BI,EAAOJ,EAAK,UAAU,CAAC,EACvBF,EAAQE,EAAK,SAAS,EAAE,EAExBR,EAAQ,CAAC,EAAEM,EAAQ,GACnBL,EAAM,CAAC,EAAEK,EAAQ,GACjBJ,EAAW,CAAC,EAAEI,EAAQ,GACtBO,EAAM,CAAC,EAAEP,EAAQ,GAEvB,GAAIK,IAAoB,EACpB,MAAM,IAAI,MAAM,oCAAoCA,CAAe,cAAgC,EAGvG,MAAO,CACH,UAAAZ,EACA,MAAAC,EACA,IAAAC,EACA,SAAAC,EACA,SAAAC,EACA,MAAAC,EACA,KAAAQ,EACA,IAAAC,EACA,KAAMR,EAAK,MAAM,EAAW,CAChC,CACJ,CAEO,SAASS,GAAoBT,EAA6B,CAC7D,GAAI,CAACA,GAAQ,CAACA,EAAK,YAAcA,EAAK,aAAe,EACjD,MAAO,GAEX,IAAMG,EAAO,IAAI,SAASH,CAAI,EAa9B,MAVI,EADYG,EAAK,SAAS,CAAC,IACf,GAIHA,EAAK,SAAS,CAAC,IACf,GAIAA,EAAK,UAAU,CAAC,IAChB,EAKjB,CAOO,SAASO,GAAgBV,EAAuC,CACnE,GAAI,CAACA,GAAQ,CAACA,EAAK,YAAcA,EAAK,aAAe,GACjD,OAAO,KAEX,IAAMG,EAAO,IAAI,SAASH,CAAI,EAa9B,GAXgBG,EAAK,SAAS,CAAC,IACf,GAIHA,EAAK,SAAS,CAAC,IACf,GAIAA,EAAK,UAAU,CAAC,IAChB,EACT,OAAO,KAGX,IAAMQ,EAAMR,EAAK,UAAU,CAAC,EACtBS,EAAMT,EAAK,UAAU,CAAC,EAE5B,MAAO,CAAE,IAAAQ,EAAK,IAAAC,CAAI,CACtB,CAEO,SAASC,GAAuBN,EAAc,CACjD,IAAMO,EAAM,IAAI,YAAY,CAAC,EACvBX,EAAO,IAAI,SAASW,CAAG,EAE7B,OAAAX,EAAK,SAAS,EAAG,CAAgB,EACjCA,EAAK,SAAS,EAAG,CAAa,EAC9BA,EAAK,UAAU,EAAGI,CAAI,EAEfO,CACX,CC/JA,IAAAC,EAAsB,mCAKtB,IAAMC,GAAY,GAAK,GAAK,EACtBC,GAAe,EAEfC,GAAqB,EACrBC,GAAgC,EAOtC,IAAMC,GAAN,MAAMC,CAAY,CAOd,YAAYC,EAAc,CAN1BC,EAAA,KAAiB,gBACjBA,EAAA,KAAQ,UACRA,EAAA,KAAQ,gBAAqC,MAC7CA,EAAA,KAAQ,SAA0B,CAAC,GACnCA,EAAA,KAAQ,mBAAmB,GAGvB,KAAK,aAAe,IAAI,YACxB,KAAK,OAASD,EAEd,IAAME,EAAe,IAAM,CACvB,KAAK,aAAa,oBAAoB,aAAcA,CAAY,EAChE,KAAK,YAAY,EACjB,KAAK,aAAa,CACtB,EACA,KAAK,aAAa,iBAAiB,aAAcA,EAAc,EAAK,CACxE,CAEQ,cAAe,CACnB,GAAI,CAAC,KAAK,eAAiB,KAAK,cAAc,UAAY,CAAC,KAAK,OAAO,OACnE,OAGJ,GAAI,KAAK,kBAAoB,KAAK,cAAc,SAAS,OAAQ,CAC7D,IAAMC,EAAQ,KAAK,cAAc,SAAS,MAAM,CAAC,EAC7CA,EAAQ,KAAK,mBACb,KAAK,cAAc,OAAOA,EAAO,KAAK,gBAAgB,EACtDC,EAAM,MAAM,2CAA2CD,CAAK,OAAO,KAAK,gBAAgB,EAAE,GAE9F,KAAK,iBAAmB,EACxB,MACJ,CAEA,IAAME,EAAQ,KAAK,OACnB,KAAK,OAAS,CAAC,EACf,IAAMC,EAAOP,EAAY,YAAYM,CAAK,EAC1C,KAAK,cAAc,aAAaC,CAAI,CACxC,CAEA,OAAe,YAAYD,EAAoC,CAC3D,GAAKA,EAAM,QAEJ,GAAIA,EAAM,SAAW,EACxB,OAAY,QAAMA,EAAM,CAAC,CAAC,MAF1B,QAAO,IAAI,WAKf,IAAME,EAAOF,EAAM,OAAO,CAACG,EAAaC,IAA2BD,EAAMC,EAAQ,UAAU,EAAG,CAAC,EACzFC,EAAS,IAAI,WAAWH,CAAI,EAC9BI,EAAS,EAEb,QAAWC,KAAWP,EAAO,CACzB,IAAMQ,EAAY,QAAMD,CAAO,EAC/BF,EAAO,IAAIG,EAAMF,CAAM,EACvBA,GAAUE,EAAK,UACnB,CAEA,OAAOH,CACX,CAEQ,aAAc,CAClB,KAAK,cAAgB,KAAK,aAAa,gBAAgB,uBAAuB,KAAK,MAAM,GAAG,EAC5F,KAAK,cAAc,KAAO,WAE1B,KAAK,cAAc,iBAAiB,YAAa,IAAM,KAAK,aAAa,CAAC,CAC9E,CAEA,WAAWV,EAAc,CACrB,YAAK,OAASA,EACP,KAAK,eAAe,WAAWA,CAAK,CAC/C,CAEA,OAAOM,EAAqBQ,EAAQ,GAAO,CACvC,KAAK,OAAO,KAAKR,CAAI,EACjBQ,GACA,KAAK,aAAa,CAE1B,CAEA,SAAU,CACF,KAAK,cAAc,aAAe,QAGlC,KAAK,eAAe,MAAM,EAG9B,IAAMC,EAAS,KAAK,eAAe,SAC7BR,EAAOQ,GAAQ,OAErB,GAAI,CAACR,EACD,OAGJ,IAAMJ,EAAQY,EAAO,MAAM,CAAC,EACtBC,EAAM,KAAK,IAAI,EAAGD,EAAO,IAAIR,EAAO,CAAC,EAAIU,EAAkB,EAE7DD,EAAMb,EAAQe,KACd,KAAK,iBAAmBF,EAEhC,CAEA,SAAU,CACN,KAAK,OAAS,CAAC,EACX,KAAK,aAAa,aAAe,SACjC,KAAK,eAAe,MAAM,EAC1B,KAAK,aAAa,YAAY,GAElC,KAAK,cAAgB,KACrB,KAAK,iBAAmB,CAC5B,CAEA,IAAI,OAAQ,CACR,OAAO,KAAK,MAChB,CAEA,IAAI,aAAc,CACd,OAAO,KAAK,YAChB,CAEA,IAAI,UAAW,CACX,OAAO,KAAK,eAAe,QAC/B,CACJ,EAEqBG,GAArB,MAAqBC,UAAoBC,EAAkB,CAUvD,YAAYC,EAA8BC,EAAqBC,EAAiB,CAC5E,MAAMF,EAAeC,EAAUC,CAAM,EAVzCvB,EAAA,KAAQ,eAAmC,MAE3CA,EAAA,KAAQ,SAAkC,MAC1CA,EAAA,KAAQ,UAA8B,MAEtCA,EAAA,KAAQ,qBAAqB,GAC7BA,EAAA,KAAQ,oBAAoB,GAC5BA,EAAA,KAAQ,sBAAsB,GAI1BG,EAAM,MAAM,0CAA0CkB,CAAa,GAAG,CAC1E,CAEA,OAAe,YAAYG,EAAW,CAClC,OAAO,IAAI,WAAW,CAACA,GAAK,EAAGA,CAAC,CAAC,CACrC,CAEA,OAAe,gBAAgC,CAC3C,OAAY,UAAa,KAAG,KAAM,CACzB,UAAa,KAAG,YAAkB,SAAO,CAAC,CAAC,EAC3C,UAAa,KAAG,gBAAsB,SAAO,CAAC,CAAC,EAC/C,UAAa,KAAG,gBAAsB,SAAO,CAAC,CAAC,EAC/C,UAAa,KAAG,kBAAwB,SAAO,CAAC,CAAC,EACjD,UAAa,KAAG,QAAc,SAAO,MAAM,CAAC,EAC5C,UAAa,KAAG,eAAqB,SAAO,CAAC,CAAC,EAC9C,UAAa,KAAG,mBAAyB,SAAO,CAAC,CAAC,CAC3D,CAAC,CACL,CAEA,OAAe,kBAAkBC,EAAeC,EAAgB3B,EAA6B,CACzF,IAAM4B,EAAmB,UAAa,KAAG,KAAM,CACtC,UAAa,KAAG,cAAoB,SAAO,GAAG,CAAC,EAC/C,UAAa,KAAG,UAAgB,SAAO,iBAAiB,CAAC,EACzD,UAAa,KAAG,WAAiB,SAAO,iBAAiB,CAAC,CACnE,CAAC,EAEKC,EAAkB,CAAM,UAAa,KAAG,WAAiB,SAAOH,CAAK,CAAC,EAAQ,UAAa,KAAG,YAAkB,SAAOC,CAAM,CAAC,CAAC,EAE/HG,EAAc,UACX,KAAG,OACH,UAAa,KAAG,WAAY,CACxB,UAAa,KAAG,YAAkB,SAAOC,EAAY,CAAC,EACtD,UAAa,KAAG,SAAe,SAAOA,EAAY,CAAC,EACnD,UAAa,KAAG,UAAgB,SAAO,CAAC,CAAC,EACzC,UAAa,KAAG,WAAiB,SAAO,CAAC,CAAC,EAG1C,UAAa,KAAG,gBAAsB,SAAO,GAAG,CAAC,EACjD,UAAa,KAAG,QAAc,SAAO,KAAK/B,EAAM,YAAY,CAAC,EAAE,CAAC,EAChE,UAAa,KAAG,MAAO6B,CAAe,CAC/C,CAAC,CACL,EAEA,OAAY,qBAAwB,KAAG,QAAS,CAACD,EAAaE,CAAM,CAAC,CACzE,CAEA,OAAe,kBAAkBE,EAAyC,CACtE,OAAY,qBAAwB,KAAG,QAAS,CAAM,UAAa,KAAG,SAAe,SAAO,KAAK,MAAMA,CAAgB,CAAC,CAAC,CAAC,CAAC,CAC/H,CAEQ,aAAahC,EAAc,CAC/B,KAAK,aAAe,IAAIF,GAAYE,CAAK,EAEzC,KAAK,OAAS,SAAS,cAAc,OAAO,EAC5C,KAAK,OAAO,SAAW,GACvB,KAAK,OAAO,SAAW,GACvB,KAAK,OAAO,MAAQ,GAEpB,KAAK,OAAO,MAAM,cAAgB,OAClC,KAAK,OAAO,MAAM,WAAa,SAC/B,KAAK,OAAO,MAAM,SAAW,WAC7B,KAAK,OAAO,MAAM,MAAQ,QAC1B,KAAK,OAAO,MAAM,OAAS,OAC3B,KAAK,OAAO,MAAM,OAAS,IAC3B,KAAK,OAAO,MAAM,MAAQ,IAC1B,KAAK,OAAO,MAAM,OAAS,OAE3B,KAAK,OAAO,IAAM,IAAI,gBAAgB,KAAK,aAAa,WAAW,EACnE,SAAS,KAAK,YAAY,KAAK,MAAM,EAErC,IAAMiC,EAAU,IAAM,CAClB,GAAI,KAAK,QAAQ,IAAK,CAClB7B,EAAM,KAAK,+CAA+C,KAAK,cAAc,sBAAsB,EACnG,IAAMW,EAAS,KAAK,OAAO,SACvBA,EAAO,SACP,KAAK,OAAO,YAAcA,EAAO,IAAIA,EAAO,OAAS,CAAC,EAAI,IAE9D,KAAK,OAAO,KAAK,EAAE,MAAM,IAAM,CAAC,CAAC,CACrC,CACJ,EAEA,KAAK,OAAO,QAAUkB,EACtB,KAAK,OAAO,UAAYA,EACxB,KAAK,OAAO,UAAYA,EACxB,KAAK,OAAO,QAAU,IAAM7B,EAAM,KAAK,8CAA8C,KAAK,cAAc,IAAK,KAAK,QAAQ,KAAK,EAG/H,KAAK,QAAU,KAAK,OAAO,cAAc,EACzC,KAAK,UAAU,KAAK,OAAO,CAC/B,CAEU,cAAc8B,EAAkB,CACtC,IAAMlC,EAAQkC,EAAM,MAAQ,MAAY,MACnC,KAAK,aAEC,KAAK,aAAa,QAAUlC,GACnC,KAAK,aAAa,WAAWA,CAAK,EAFlC,KAAK,aAAaA,CAAK,EAK3B,IAAImC,EAAOD,EAAM,UAQjB,GAPIC,GAAQ,KAAK,sBAEbA,EAAO,KAAK,oBAAsB,GAClC/B,EAAM,MAAM,kDAAkD,KAAK,cAAc,GAAG,GAExF,KAAK,oBAAsB+B,EAEtB,KAAK,mBASNA,GAAQ,KAAK,uBATa,CAC1B,GAAI,CAACD,EAAM,SAEP,OAGJ,KAAK,mBAAqBC,EAC1BA,EAAO,CACX,CAIA,GAAID,EAAM,SAAU,CAChB,KAAK,kBAAoBC,EAGzB,KAAK,cAAc,QAAQ,EAE3B/B,EAAM,MAAM,iDAAiD,KAAK,cAAc,GAAG,EACnF,IAAMgC,EAAahB,EAAY,eAAe,EAC9C,KAAK,cAAc,OAAOgB,CAAU,EACpC,IAAMC,EAAgBjB,EAAY,kBAAkBc,EAAM,MAAOA,EAAM,OAAQlC,CAAK,EACpF,KAAK,cAAc,OAAOqC,CAAa,CAC3C,CAEA,IAAIC,EAAW,KAAK,MAAMH,EAAO,KAAK,iBAAiB,EAMvD,GALIG,EAAWC,KACX,KAAK,kBAAoBJ,EACzBG,EAAW,GAGXA,IAAa,EAAG,CAChBlC,EAAM,MAAM,iDAAiD,KAAK,cAAc,GAAG,EACnF,IAAMoC,EAAUpB,EAAY,kBAAkB,KAAK,iBAAiB,EACpE,KAAK,cAAc,OAAOoB,CAAO,CACrC,CAEA,IAAMC,EAAa,UAAa,KAAG,YAAa,CACvC,oBAAkBV,EAAY,EAC9B,QAAMX,EAAY,YAAYkB,CAAQ,CAAC,EACvC,UAAQJ,EAAM,SAAW,EAAI,IAAM,CAAC,EACpC,QAAMA,EAAM,SAAS,CAC9B,CAAC,EACD,KAAK,cAAc,OAAOO,EAAO,EAAI,CACzC,CAES,SAAU,CACf,MAAM,QAAQ,EAEV,KAAK,SACL,KAAK,OAAO,QAAU,KACtB,KAAK,OAAO,UAAY,KACxB,KAAK,OAAO,UAAY,KACxB,KAAK,OAAO,QAAU,KAEtB,KAAK,OAAO,MAAM,EAClB,KAAK,OAAO,IAAM,GAClB,SAAS,KAAK,YAAY,KAAK,MAAM,GAErC,KAAK,eACL,KAAK,aAAa,QAAQ,EAC1B,KAAK,aAAe,MAEpB,KAAK,UACL,KAAK,QAAQ,UAAU,EAAE,QAASC,GAA4BA,EAAM,KAAK,CAAC,EAC1E,KAAK,QAAU,MAGnBtC,EAAM,MAAM,4CAA4C,KAAK,cAAc,GAAG,CAClF,CAEA,OAAgB,oBAA8B,CAG1C,MACI,kBAAmB,OAAO,kBAAkB,WAC5C,OAAO,aAAa,gBAAgB,0BAAmC,GACvE,OAAO,aAAa,gBAAgB,0BAAmC,CAE/E,CACJ,ECxUA,IAAqBuC,GAArB,KAA2C,CAQvC,YACIC,EACAC,EACAC,EACAC,EACAC,EACF,CAbFC,EAAA,KAAiB,gBACjBA,EAAA,KAAQ,yBAAuD,MAC/DA,EAAA,KAAQ,kBAA4D,CAAC,GACrEA,EAAA,KAAQ,YAAsB,IAAM,CAAC,GACrCA,EAAA,KAAQ,SAAmB,IAAM,CAAC,GAClCA,EAAA,KAAQ,WASJC,EAAM,MAAM,+BAA+B,EAE3C,KAAK,aAAeN,EACpB,KAAK,uBAAyBC,EAC9B,KAAK,UAAYC,EACjB,KAAK,OAASC,EACd,KAAK,QAAUC,EAEf,KAAK,aAAa,UAAaG,GAAM,KAAK,sBAAsBA,EAAE,IAAI,CAC1E,CAEQ,sBAAsBC,EAAmB,CAC7C,IAAMC,EAAQC,GAAWF,CAAI,EACvBG,EAAgB,KAAK,wBAAwB,qBAAqBF,EAAM,IAAI,GAAG,cACrF,GAAI,CAACE,EAAe,CAChBL,EAAM,KAAK,2BAA2BG,EAAM,IAAI,wBAAwB,EACxE,MACJ,CAEA,GAAIA,EAAM,IAAK,CAEX,KAAK,MAAME,CAAa,EACxB,KAAK,OAAOA,CAAa,EACzB,MACJ,CAEA,IAAIC,EAAgB,KAAK,gBAAgBD,CAAa,EAEtD,GAAI,CAACC,EAAe,CAChB,IAAMV,EAAuBW,GAAW,KAAK,UAAUF,EAAeE,CAAM,EACtEC,EAAsB,IAAM,CAC9B,KAAK,iBAAiBL,EAAM,IAAI,CACpC,EACIM,EAAO,wBAA0BC,GAAY,mBAAmB,EAChEJ,EAAgB,IAAII,GAAYL,EAAeT,EAAU,KAAK,OAAO,EAErEU,EAAgB,IAAIK,GAAcN,EAAeT,EAAU,KAAK,QAASY,CAAmB,EAEhG,KAAK,gBAAgBH,CAAa,EAAIC,CAC1C,CAEAA,EAAc,YAAYH,CAAK,CACnC,CAKQ,iBAAiBS,EAAoB,CACzC,GAAI,GAAC,KAAK,cAAgB,KAAK,aAAa,aAAe,QAI3D,GAAI,CACA,IAAMC,EAAMC,GAAuBF,CAAI,EACvC,KAAK,aAAa,KAAKC,CAAG,EAC1Bb,EAAM,MAAM,uDAAuDY,CAAI,EAAE,CAC7E,OAASG,EAAO,CACZf,EAAM,KAAK,kCAAmCe,CAAK,CACvD,CACJ,CAEA,MAAMV,EAA8B,CAChC,IAAMC,EAAgB,KAAK,gBAAgBD,CAAa,EACpDC,IACAA,EAAc,QAAQ,EACtB,OAAO,KAAK,gBAAgBD,CAAa,EAEjD,CAEA,SAAU,CACN,KAAK,aAAa,oBAAsB,KACxC,KAAK,aAAa,UAAY,KAC9B,KAAK,UAAY,IAAM,CAAC,EACxB,OAAO,OAAO,KAAK,eAAe,EAAE,QAASC,GAAkBA,EAAc,QAAQ,CAAC,EACtF,KAAK,gBAAkB,CAAC,EACxB,KAAK,uBAAyB,KAC9BN,EAAM,MAAM,iCAAiC,CACjD,CAEA,OAAO,oBAA8B,CACjC,OAAQgB,GAAiB,mBAAmB,GAAKC,GAAc,mBAAmB,KAAON,GAAc,mBAAmB,GAAKD,GAAY,mBAAmB,EAClK,CACJ,EC1GA,IAAMQ,GAAN,KAAc,CAKV,YAAYC,EAASC,EAAsBC,EAAsB,CAJjEC,EAAA,KAAQ,SACRA,EAAA,KAAQ,SACRA,EAAA,KAAiB,SAGb,KAAK,MAAQD,EACTA,IACAA,EAAK,KAAO,MAGhB,KAAK,MAAQD,EACTA,IACAA,EAAK,KAAO,MAGhB,KAAK,MAAQD,CACjB,CAEA,IAAI,MAAuB,CACvB,OAAO,KAAK,KAChB,CAEA,IAAI,KAAKI,EAAuB,CAC5B,KAAK,MAAQA,CACjB,CAEA,IAAI,MAAuB,CACvB,OAAO,KAAK,KAChB,CAEA,IAAI,KAAKA,EAAuB,CAC5B,KAAK,MAAQA,CACjB,CAEA,IAAI,MAAU,CACV,OAAO,KAAK,KAChB,CACJ,EAEaC,GAAN,KAA8C,CAA9C,cACHF,EAAA,KAAQ,QAAwB,MAChCA,EAAA,KAAQ,QAAwB,MAChCA,EAAA,KAAQ,UAAU,GAElB,IAAI,QAAiB,CACjB,OAAO,KAAK,OAChB,CAEA,QAAQH,EAAiB,CACrB,QAAWM,KAAQN,EACf,KAAK,MAAQ,IAAID,GAAKO,EAAM,KAAK,MAAO,IAAI,EACvC,KAAK,QACN,KAAK,MAAQ,KAAK,OAEtB,KAAK,SAEb,CAEA,MAAMN,EAAyB,CACvB,KAAK,QACL,KAAK,MAAM,KAAOA,EAAK,OAEtB,KAAK,QACN,KAAK,MAAQA,EAAK,OAEtB,KAAK,MAAQA,EAAK,MAClB,KAAK,SAAWA,EAAK,QACrBA,EAAK,MAAM,CACf,CAEA,OAAkB,CACd,GAAI,CAAC,KAAK,SAAW,CAAC,KAAK,MACvB,OAAO,KAGX,IAAMO,EAAS,KAAK,MACpB,YAAK,MAAQA,EAAO,KAEhB,KAAK,QACLA,EAAO,KAAO,KACd,KAAK,MAAM,KAAO,MAGtB,KAAK,UACD,KAAK,SAAW,EAChB,KAAK,MAAQ,KAAK,MACV,KAAK,SACb,KAAK,MAAQ,KAAK,MAAQ,MAGvBA,EAAO,IAClB,CAEA,QAAe,CACX,GAAI,KAAK,OAAQ,CACb,IAAMC,EAAS,KAAK,OAAS,EAAI,KAAK,MAAM,KAAK,OAAS,CAAC,EAAI,EAC/D,QAASC,EAAI,EAAGA,EAAID,EAAQC,IACxB,KAAK,MAAM,CAEnB,CACJ,CAEA,MAAiB,CACb,OAAO,KAAK,OAAO,MAAQ,IAC/B,CAEA,MAAiB,CACb,OAAO,KAAK,OAAO,MAAQ,IAC/B,CAEA,OAAc,CACV,KAAK,MAAQ,KACb,KAAK,MAAQ,KACb,KAAK,QAAU,CACnB,CAEA,UAAmB,CACf,IAAMF,EAAS,CAAC,EACZD,EAAO,KAAK,MAChB,KAAOA,IAAS,MACZC,EAAO,KAAKD,EAAK,IAAI,EACrBA,EAAOA,EAAK,KAEhB,OAAKC,EAAO,OAGL,KAAK,UAAUA,EAAQ,CAACG,EAAKN,IAC5BA,aAAiB,MACV,OAAOA,CAAK,EAEhBA,CACV,EAPU,EAQf,CACJ,ECxIA,IAAAO,GAAmB,iCAMnB,IAAMC,GAAqB,IAENC,GAArB,cAA2CC,EAA+B,CAatE,YAAYC,EAA+BC,EAA0BC,EAA+BC,EAAoB,CACpH,MAAM,EAbVC,EAAA,KAAiB,gBACjBA,EAAA,KAAiB,YACjBA,EAAA,KAAiB,yBACjBA,EAAA,KAAiB,eACjBA,EAAA,KAAiB,oBACjBA,EAAA,KAAQ,SAAkC,MAC1CA,EAAA,KAAQ,gBAAqC,MAC7CA,EAAA,KAAQ,UAAoC,MAC5CA,EAAA,KAAQ,aAA8C,MACtDA,EAAA,KAAQ,oBAAoB,GAC5BA,EAAA,KAAQ,aAAiC,MAIrC,KAAK,aAAeJ,EACpB,KAAK,SAAWC,EAChB,KAAK,sBAAwBC,EAC7B,KAAK,YAAcC,EAGnB,KAAK,iBAAmB,iBAAkB,QAAU,aAAa,UAAU,YAAc,QAAa,gBAAiB,QAInHH,EAAY,aAAe,QAAU,CAACA,EAAY,SAAWA,EAAY,SACzE,KAAK,iBAAmB,GAEhC,CAEQ,YAAmB,CAClB,KAAK,UACN,KAAK,QAAU,SAAS,cAAc,QAAQ,EAC9C,KAAK,QAAQ,MAAM,cAAgB,OACnC,KAAK,QAAQ,MAAM,WAAa,SAChC,KAAK,QAAQ,MAAM,SAAW,WAC9B,KAAK,QAAQ,MAAM,MAAQ,QAC3B,KAAK,QAAQ,MAAM,OAAS,OAC5B,KAAK,QAAQ,MAAM,OAAS,IAC5B,KAAK,QAAQ,MAAM,MAAQ,QAC3B,KAAK,QAAQ,MAAM,OAAS,OAC5B,KAAK,WAAa,KAAK,QAAQ,WAAW,IAAI,EAC9C,SAAS,KAAK,YAAY,KAAK,OAAO,GAGtC,CAAC,KAAK,QAAU,CAAC,KAAK,mBACtB,KAAK,OAAS,SAAS,cAAc,OAAO,EAC5C,KAAK,OAAO,SAAW,GACvB,KAAK,OAAO,SAAW,GACvB,KAAK,OAAO,QAAU,OACtB,KAAK,OAAO,MAAQ,GACpB,KAAK,OAAO,MAAM,cAAgB,OAClC,KAAK,OAAO,MAAM,WAAa,SAC/B,KAAK,OAAO,MAAM,SAAW,WAC7B,KAAK,OAAO,MAAM,MAAQ,QAC1B,KAAK,OAAO,MAAM,OAAS,OAC3B,KAAK,OAAO,MAAM,OAAS,IAC3B,KAAK,OAAO,MAAM,MAAQ,IAC1B,KAAK,OAAO,MAAM,OAAS,OAC3B,SAAS,KAAK,YAAY,KAAK,MAAM,EAE7C,CAEQ,YAAmB,CACvB,GAAI,CACI,KAAK,SACL,SAAS,KAAK,YAAY,KAAK,OAAO,EAEtC,KAAK,QACL,SAAS,KAAK,YAAY,KAAK,MAAM,CAE7C,MAAY,CAAC,CAEb,KAAK,WAAa,KAClB,KAAK,QAAU,KACf,KAAK,OAAS,IAClB,CAEA,MAAc,cAAcK,EAA6C,CACrE,GAAI,CAAC,KAAK,QACN,MAAM,IAAI,MAAM,kBAAkB,EAGtC,GAAI,CAAC,KAAK,QAAU,CAAC,KAAK,iBACtB,MAAM,IAAI,MAAM,yBAAyB,EAG7C,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACpC,GAAI,KAAK,iBACL,KAAK,cAAgB,IAAI,aAAaF,CAAU,EAChDC,EAAQ,MACL,CACH,IAAME,EAAQ,KAAK,OACnBA,EAAM,UAAY,IAAI,YAAY,CAACH,CAAU,CAAC,EAC9CG,EAAM,aAAgBC,GAAMH,EAAQ,EACpCE,EAAM,QAAU,IAAMD,EAAO,IAAI,MAAM,qBAAqB,CAAC,EAE7D,IAAMG,EAAaF,EAAM,KAAK,EACxBG,EAAa,IAAMJ,EAAO,IAAI,MAAM,sBAAsB,CAAC,EAC7DG,EACAA,EAAW,MAAMC,CAAU,EAE3BA,EAAW,CAEnB,CACJ,CAAC,CACL,CAEQ,eAAsB,CAC1B,OAAO,aAAa,KAAK,iBAAiB,EAC1C,KAAK,YAAY,MAAM,EAEnB,KAAK,SACL,KAAK,OAAO,MAAM,EAClB,KAAK,OAAO,UAAY,MAExB,KAAK,gBACL,KAAK,cAAgB,KAE7B,CAEQ,iBAA6B,CACjC,GAAI,CAAC,KAAK,SAAW,CAAC,KAAK,YAAc,CAAC,KAAK,OAC3C,MAAM,IAAI,MAAM,aAAa,EAK7B,KAAK,OAAO,QACZ,KAAK,OAAO,KAAK,EAGrB,IAAMC,EAAQ,KAAK,OAAO,WACpBC,EAAS,KAAK,OAAO,YAC3B,YAAK,QAAQ,MAAQ,KAAK,OAAO,MAAQD,EACzC,KAAK,QAAQ,OAAS,KAAK,OAAO,OAASC,EAE3C,KAAK,WAAW,UAAU,EAAG,EAAGD,EAAOC,CAAM,EAC7C,KAAK,WAAW,UAAU,KAAK,OAAQ,EAAG,EAAGD,EAAOC,CAAM,EACnD,KAAK,WAAW,aAAa,EAAG,EAAGD,EAAOC,CAAM,CAC3D,CAEA,MAAc,iBAAwC,CAClD,GAAI,CAAC,KAAK,cACN,MAAM,IAAI,MAAM,WAAW,EAE/B,OAAO,KAAK,cAAc,UAAU,CACxC,CAEQ,eAAeC,EAAqC,CACxD,GAAI,CAAC,KAAK,SAAW,CAAC,KAAK,WACvB,MAAM,IAAI,MAAM,WAAW,EAG/B,IAAMF,EAAQE,EAAY,MACpBD,EAASC,EAAY,OAC3B,YAAK,QAAQ,MAAQF,EACrB,KAAK,QAAQ,OAASC,EAEtB,KAAK,WAAW,UAAU,EAAG,EAAGD,EAAOC,CAAM,EAC7C,KAAK,WAAW,UAAUC,EAAa,EAAG,EAAGF,EAAOC,CAAM,EACnD,KAAK,YAAY,aAAa,EAAG,EAAGD,EAAOC,CAAM,CAC5D,CAEA,MAAM,MAAsB,CACxB,KAAK,WAAW,EAEhB,IAAMD,EAAQ,KAAK,aAAa,YAAY,EAAE,MACxCC,EAAS,KAAK,aAAa,YAAY,EAAE,OAC/CE,EAAM,MAAM,yBAAyBH,CAAK,IAAIC,CAAM,WAAW,KAAK,MAAM,EAAI,MAAQ,KAAK,EAAE,EAE7F,MAAM,KAAK,cAAc,KAAK,YAAY,EAC1C,MAAM,KAAK,cACP;AAAA,EACCG,GAAuB,CAChBA,EAAK,MACL,KAAK,SAAS,KAAMA,EAAK,KAAK,EAE9B,KAAK,SAAS,CACV,KAAMA,EAAK,UACX,UAAWA,EAAK,UAChB,SAAUA,EAAK,SACf,KAAMA,EAAK,KACX,WAAYA,EAAK,MAAM,WACvB,MAAOA,EAAK,MACZ,OAAQA,EAAK,MACjB,CAAsB,CAE9B,EACA,CAAC,GAAAC,QAAQ,GAAAA,QAAO,OAAQ,KAAK,sBAAuB,KAAK,WAAW,EACpE,CAAE,MAAO,KAAK,MAAM,EAAG,MAAOF,EAAM,QAAQ,CAAE,CAClD,CACJ,CAEQ,QAAQG,EAAsBC,EAAmB,CACrD,IAAMC,EAASF,EAAU,KAAK,OAC9B,KAAK,sBAED,CACI,MAAOA,EAAU,MACjB,OAAQA,EAAU,OAClB,UAAWE,EACX,SAAAD,CACJ,EACA,CAACC,CAAM,CACX,CACJ,CAEQ,mBAAmBD,EAAmB,CAC1C,IAAMD,EAAY,KAAK,gBAAgB,EACvC,KAAK,QAAQA,EAAWC,CAAQ,CACpC,CAEQ,oBAAoBA,EAAmB,CAG3C,OAAO,aAAa,KAAK,iBAAiB,EAC1C,KAAK,kBAAoB,OAAO,WAAW,IAAM,CAC7C,GAAI,KAAK,WAAY,CACjB,IAAMD,EAAY,KAAK,eAAe,KAAK,UAAU,EACrD,KAAK,QAAQA,EAAWC,CAAQ,CACpC,MACI,KAAK,SAAS,IAAI,CAE1B,EAAGtB,EAAkB,EAErB,KAAK,gBAAgB,EAChB,KAAMiB,GAAgB,CACnB,OAAO,aAAa,KAAK,iBAAiB,EAC1C,KAAK,YAAY,MAAM,EACvB,KAAK,WAAaA,EAElB,IAAMI,EAAY,KAAK,eAAeJ,CAAW,EACjD,KAAK,QAAQI,EAAWC,CAAQ,CACpC,CAAC,EACA,MAAM,IAAM,CAEb,CAAC,CACT,CAEA,aAAaA,EAAW,GAAa,CAC7B,KAAK,iBACL,KAAK,oBAAoBA,CAAQ,EAEjC,KAAK,mBAAmBA,CAAQ,CAExC,CAEA,WAAWE,EAAiBC,EAAiBC,EAAmB,CAC5D,KAAK,4BAAuC,CAAE,QAAAF,EAAS,OAAAC,CAAO,CAAC,CACnE,CAEA,OAAiB,CACb,MAAO,EACX,CAEA,SAAU,CACN,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChBP,EAAM,MAAM,yBAAyB,CACzC,CAEA,OAAgB,oBAA8B,CAC1C,MACI,gBAAiB,QACjB,WAAY,SAEX,6BAA8B,QAAU,kCAAmC,OAEpF,CACJ,EClRA,IAAqBS,GAArB,cAA8CC,EAA+B,CASzE,YAAYC,EAA+BC,EAA0BC,EAA+BC,EAAoBC,EAAiBC,EAAmB,CACxJ,MAAM,EATVC,EAAA,KAAiB,gBACjBA,EAAA,KAAiB,mBACjBA,EAAA,KAAiB,YACjBA,EAAA,KAAiB,yBACjBA,EAAA,KAAiB,eACjBA,EAAA,KAAiB,WACjBA,EAAA,KAAiB,cAIb,KAAK,aAAeN,EACpB,KAAK,SAAWC,EAChB,KAAK,sBAAwBC,EAC7B,KAAK,YAAcC,EACnB,KAAK,QAAUC,EACf,KAAK,WAAaC,EAClB,KAAK,gBAAkB,IAAI,0BAA0B,CAAE,MAAOL,CAAY,CAAC,CAC/E,CAEA,MAAM,MAAsB,CACxB,IAAMO,EAAQ,KAAK,aAAa,YAAY,EAAE,MACxCC,EAAS,KAAK,aAAa,YAAY,EAAE,OACzCC,EAAW,KAAK,gBAAgB,SAEtCC,EAAM,MAAM,4BAA4BH,CAAK,IAAIC,CAAM,WAAW,KAAK,MAAM,EAAI,MAAQ,KAAK,EAAE,EAEhG,MAAM,KAAK,cACP;AAAA,EACCG,GAAuB,CAChBA,EAAK,MACL,KAAK,SAAS,KAAMA,EAAK,KAAK,EAE9B,KAAK,SAAS,CACV,KAAMA,EAAK,UACX,UAAWA,EAAK,UAChB,SAAUA,EAAK,SACf,KAAMA,EAAK,KACX,WAAYA,EAAK,MAAM,WACvB,MAAOA,EAAK,MACZ,OAAQA,EAAK,MACjB,CAAsB,CAE9B,EACA,CAAC,EACD,CACI,SAAAF,EACA,MAAAF,EACA,OAAAC,EACA,MAAO,KAAK,MAAM,EAClB,UAAW,KAAK,WAChB,qBAAsB,KAAK,sBAC3B,WAAY,KAAK,YACjB,OAAQ,KAAK,OACjB,EACA,CAACC,CAAQ,CACb,CACJ,CAEA,aAAaG,EAAW,GAAa,CACjC,KAAK,sBAAiC,CAAE,SAAAA,CAAS,CAAC,CACtD,CAEA,WAAWC,EAAiBT,EAAiBU,EAAmB,CAC5D,KAAK,4BAAuC,CAAE,QAAAD,EAAS,OAAAT,EAAQ,IAAAU,CAAI,CAAC,CACxE,CAEA,OAAiB,CACb,MAAO,EACX,CAEA,SAAgB,CACZ,KAAK,cAAc,EACnBJ,EAAM,MAAM,4BAA4B,CAC5C,CAEA,OAAgB,oBAA8B,CAC1C,MAAO,iBAAkB,QAAU,WAAY,QAAU,sBAAuB,QAAU,8BAA+B,MAC7H,CACJ,EChFA,IAAMK,GAA0B,KAC1BC,GAAuB,IACvBC,GAAiB,IACjBC,GAAmB,GACnBC,GAAyB,IACzBC,GAAuB,IACvBC,GAAyB,IACzBC,GAAqB,KACrBC,GAAc,EACdC,GAAgC,IACjCC,QACDA,IAAA,eACAA,IAAA,WACAA,IAAA,eAHCA,QAAA,IAMgBC,GAArB,KAA6C,CA8BzC,YAAYC,EAAoCC,EAAoBC,EAAoBC,EAAoBC,EAAsBC,EAAwBC,EAAmB,CA7B7KC,EAAA,KAAiB,iBACjBA,EAAA,KAAiB,cACjBA,EAAA,KAAiB,gBACjBA,EAAA,KAAiB,wBACjBA,EAAA,KAAiB,uBACjBA,EAAA,KAAiB,cACjBA,EAAA,KAAQ,eACRA,EAAA,KAAQ,eACRA,EAAA,KAAQ,kBAERA,EAAA,KAAQ,aACRA,EAAA,KAAQ,WACRA,EAAA,KAAQ,gBACRA,EAAA,KAAQ,mBACRA,EAAA,KAAQ,aAAa,GACrBA,EAAA,KAAQ,YACRA,EAAA,KAAQ,iBAAiB,IACzBA,EAAA,KAAQ,gBAAgB,IAGxBA,EAAA,KAAQ,YAAY,OAAO,WAC3BA,EAAA,KAAQ,YAAY,GACpBA,EAAA,KAAQ,sBAAsB,GAG9BA,EAAA,KAAQ,kBACRA,EAAA,KAAQ,UAAU,GAClBA,EAAA,KAAQ,OAAO,GAGX,KAAK,cAAgBP,EACrB,KAAK,WAAaG,EAClB,KAAK,YAAcF,EACnB,KAAK,YAAcC,EACnB,KAAK,aAAeE,EACpB,KAAK,WAAaE,EACdD,EAAiB,EACjB,KAAK,oBAAsBA,EAE3B,KAAK,oBAAsBjB,GAE3BgB,IACA,KAAK,oBAAsBf,IAE/B,KAAK,qBAAuB,KAAK,MAAM,KAAK,oBAAsB,CAAC,EAEnE,KAAK,eAAiB,KAAK,YAC3B,KAAK,SAAW,GAEhB,IAAMmB,EAAM,KAAK,IAAI,EACrB,KAAK,UAAY,EACjB,KAAK,QAAUA,EACf,KAAK,aAAeA,EACpB,KAAK,gBAAkB,EACvB,KAAK,eAAiB,CAC1B,CAEA,WAAWC,EAAkBC,EAAeC,EAAwB,CAChE,IAAMH,EAAM,KAAK,IAAI,EASrB,GAPA,KAAK,SAASA,CAAG,EAEjB,KAAK,WAAWE,EAAOF,CAAG,EACtB,KAAK,gBAAkB,GAAK,KAAK,eAAiB,GAIlD,CAAC,KAAK,WAEN,OAIJ,IAAII,EAAW,EAGTC,EAAa,KAAK,eAAiB,KAAK,cAExCC,EAAoB,KAAK,MAAO,KAAK,IAAID,CAAU,EAAI,IAAO,KAAK,aAAa,EAEhFE,EAAeF,EAAa,IAAMC,EAAoB,IAAM,KAAK,eAAiB,KAAK,qBACvFE,EAAc,KAAK,eAAiB,KAAK,oBAC3CD,GAAgBC,EAChBJ,EAAW,EACJ,KAAK,IAAIC,CAAU,EAAI,IAAMC,EAAoB,IAAM,CAACE,IAE/DJ,EAAW,GAIf,IAAMK,EAAiB,KAAK,MAAM,KAAK,eAAiB,GAAI,EACtDC,EAAkBP,EACpBF,EAAW,KAAO,GAClBU,EAAM,MACF,IAAIV,CAAQ,eAAeC,CAAK,UAAU,KAAK,cAAc,SAAS,KAAK,aAAa,UAAUG,CAAU,YAAYC,CAAiB,OAAOhB,GAASc,CAAQ,CAAC,OAAOK,CAAc,OAAON,CAAQ,EAC1M,EAGJ,IAAMS,EAAcZ,EAAM,KAAK,UAC/B,GAAII,IAAa,GAAiBQ,EAAc5B,GAAwB,CAChE,KAAK,WAEL,KAAK,WAAa,KAAK,IAAI,EAAE,KAAK,WAAYI,EAAW,EACzD,KAAK,SAAW,IAGpB,IAAIyB,GAAa9B,GAAmB2B,EAAkB,IAKtD,GAJIG,IAAc,KAAK,iBACnBA,GAAa,KAAK,eAAiB9B,IAEvC8B,GAAa,KAAK,IAAIA,GAAY,KAAK,WAAW,EAC9CA,GAAa,KAAK,eAAgB,CAClC,IAAMC,GAAc,KAAK,MAAMD,GAAa,GAAI,EAC1CE,GAAa,KAAK,MAAO,KAAK,WAAa7B,GAA0B,GAAI,EAC/EyB,EAAM,IACF,IAAIV,CAAQ,eAAeC,CAAK,UAAU,KAAK,cAAc,SAAS,KAAK,aAAa,UAAUG,CAAU,YAAYC,CAAiB,OAAOhB,GAASc,CAAQ,CAAC,EACtK,EACAO,EAAM,IAAI,IAAIV,CAAQ,oBAAoBC,CAAK,YAAYQ,CAAe,WAAWD,CAAc,kBAAkBK,EAAW,YAAYC,EAAU,GAAG,EAEzJ,KAAK,YAAYF,GAAY,EAAI,EACjC,KAAK,eAAiBA,EAC1B,CACA,KAAK,UAAYb,CACrB,CAEA,IAAMgB,EAAYhB,EAAM,KAAK,QACvBiB,EAAkBhC,GAAuB,KAAK,WAAaC,GACjE,GAAIkB,IAAa,GAAeY,EAAYC,GAAmBL,EAAcK,EAAiB,CAC1F,IAAMJ,GAAa,KAAK,IAAI,KAAK,eAAiB/B,GAAgB,KAAK,WAAW,EAClF,GAAI+B,GAAa,KAAK,eAAgB,CAClC,IAAMC,GAAc,KAAK,MAAMD,GAAa,GAAI,EAC1CK,GAAU,KAAK,MAAM,KAAK,eAAiB,GAAI,EAC/CH,EAAa,KAAK,MAAO,KAAK,WAAa7B,GAA0B,GAAI,EAC/EyB,EAAM,IACF,IAAIV,CAAQ,eAAeC,CAAK,UAAU,KAAK,cAAc,SAAS,KAAK,aAAa,UAAUG,CAAU,YAAYC,CAAiB,OAAOhB,GAASc,CAAQ,CAAC,EACtK,EACAO,EAAM,IAAI,IAAIV,CAAQ,oBAAoBS,CAAe,WAAWQ,EAAO,kBAAkBJ,EAAW,YAAYC,CAAU,GAAG,EAEjI,KAAK,YAAYF,GAAY,EAAK,EAClC,KAAK,eAAiBA,GACtB,KAAK,SAAW,GAChB,KAAK,aAAeb,EACpB,KAAK,QAAUA,CACnB,CACJ,CAEA,IAAMmB,EAAiBnB,EAAM,KAAK,aAC9B,KAAK,UAAYmB,EAAiBhC,KAElC,KAAK,SAAW,IAGpB,IAAMiC,EAAqBpB,EAAM,KAAK,UAClC,KAAK,WAAa,GAAKoB,EAAqB,EAAIH,IAChDN,EAAM,IAAI,IAAIV,CAAQ,sCAAsC,KAAK,UAAU,EAAE,EAC7E,KAAK,WAAa,EAE1B,CAEQ,YAAYoB,EAAiBC,EAAiB,CAC9C,KAAK,eAELA,EAAS,IAEb,IAAIC,EAAM,KAAK,WACX,KAAK,KAAO,IACZA,EAAM,KAAK,MAEf,KAAK,cAAcF,EAASC,EAAQC,CAAG,CAC3C,CAEQ,WAAWrB,EAAeF,EAAmB,CACjD,GAAI,EAAAE,GAAS,GAqBb,IAlBI,KAAK,iBAAmB,KACxB,KAAK,eAAiBA,EACtB,KAAK,cAAgBA,GAGzB,KAAK,eAAiB,KAAK,OAAO,KAAK,eAAiB,EAAIA,GAAS,CAAC,EAEtE,KAAK,cAAgB,KAAK,OAAO,KAAK,cAAgB,GAAKA,GAAS,EAAE,EAGlEA,EAAQ,GAAKA,EAAQ,KAAK,UAC1B,KAAK,UAAYA,EACVA,EAAQ,KAAK,YACpB,KAAK,UAAYA,GAEjB,KAAK,kBAAoB,IACzB,KAAK,gBAAkBF,GAEvBE,EAAQb,GAA+B,CAEvC,IAAMmC,EAAUxB,EAAM,KAAK,gBAC3B,KAAK,qBAAuBwB,CAChC,CACA,KAAK,gBAAkBxB,EAC3B,CAEA,YAAYP,EAAoBC,EAA0B,CACtD,KAAK,YAAcD,EACnB,KAAK,YAAcC,CACvB,CAEA,SAAoC,CAChC,GAAI,KAAK,YAAc,OAAO,WAAa,KAAK,YAAc,GAAK,KAAK,eAAiB,EAErF,OAAO,KAEX,IAAM+B,EAA4B,CAAE,SAAU,KAAK,UAAW,SAAU,KAAK,UAAW,SAAU,KAAK,cAAe,mBAAoB,KAAK,mBAAoB,EACnK,YAAK,UAAY,OAAO,UACxB,KAAK,UAAY,EACjB,KAAK,oBAAsB,EACpBA,CACX,CAEQ,SAASzB,EAAmB,CAChC,KAAK,UACL,IAAMwB,EAAUxB,EAAM,KAAK,eAC3B,GAAIwB,EAAU,IAAO,CACjB,KAAK,eAAiBxB,EACtB,IAAM0B,EAAS,KAAK,KACdH,EAAO,KAAK,QAAU,IAAQC,EAEhC,KAAK,OAAS,EACd,KAAK,KAAO,KAAK,MAAMD,CAAG,EAG1B,KAAK,KAAO,KAAK,OAAO,KAAK,KAAO,EAAIA,GAAO,CAAC,EAEpD,KAAK,QAAU,EACX,KAAK,OAASG,GACdf,EAAM,IAAI,WAAW,KAAK,IAAI,EAAE,CAExC,CACJ,CACJ,ECjPA,IAAqBgB,GAArB,KAAmC,CAQ/B,YAAYC,EAAiB,CAN7BC,EAAA,KAAiB,YACjBA,EAAA,KAAQ,QAAQ,GAChBA,EAAA,KAAiB,WACjBA,EAAA,KAAQ,QAAQ,GAChBA,EAAA,KAAQ,QAAQ,GAGZ,KAAK,SAAWD,EAChB,KAAK,QAAU,IAAI,MAAMA,CAAO,CACpC,CAEA,IAAIE,EAAaC,EAAYC,EAAcC,EAAgBC,EAAsB,CACzE,KAAK,QAAU,KAAK,OAAS,KAAK,MAAQ,IAC1C,KAAK,MAAQ,EAAE,KAAK,MAAQ,KAAK,UAErC,IAAMC,EAAQ,KAAK,MACnB,YAAK,QAAQ,KAAK,KAAK,EAAI,CAAE,IAAAL,EAAK,GAAAC,EAAI,KAAAC,EAAM,KAAM,KAAK,IAAI,EAAG,MAAAC,EAAO,IAAAC,EAAK,IAAK,GAAI,KAAM,EAAG,EAC5F,KAAK,MAAQ,EAAE,KAAK,MAAQ,KAAK,SACjC,KAAK,QACEC,CACX,CAEA,OAAOL,EAAaM,EAAmC,CACnD,IAAMC,EAAM,KAAK,IAAIP,CAAG,EACxB,OAAIO,IAAQ,KACD,MAEXA,EAAI,IAAMD,EACVC,EAAI,KAAO,KAAK,IAAI,EACbA,EACX,CAEA,IAAIP,EAAmC,CACnC,IAAIQ,EAAI,KAAK,MACb,QAASC,EAAO,EAAGA,EAAO,KAAK,SAAUA,IAAQ,CAC7C,IAAMC,EAAU,KAAK,QAAQF,CAAC,EAC9B,GAAIR,IAAQU,GAAS,IACjB,OAAOA,EAGX,GADAF,EAAI,EAAEA,EAAI,KAAK,SACXA,IAAM,KAAK,MACX,KAER,CACA,OAAO,IACX,CAEA,kBAAkBG,EAA0B,CAExC,IAAIC,EAAW,EACXV,EAAO,EACPC,EAAQ,GACRC,EAAM,GACNI,EAAI,KAAK,MACb,QAASC,EAAO,EAAGA,EAAO,KAAK,SAAUA,IAAQ,CACzCD,EAAI,EACJ,EAAEA,EAEFA,EAAI,KAAK,SAAW,EAExB,IAAMD,EAAM,KAAK,QAAQC,CAAC,EAgB1B,GAfI,CAACD,IAGDH,IAAQ,KACRA,EAAMG,EAAI,IACVL,EAAO,GAEPE,GAAO,IACPF,GAAQK,EAAI,MAEhBJ,EAAQI,EAAI,IACIH,EAAMD,GACPQ,IAGXH,IAAM,KAAK,MACX,KAER,CACA,GAAIL,GAAS,GAAKC,GAAO,EAAG,CACxB,IAAMS,EAAUT,EAAMD,EACtBS,EAAW,KAAK,MAAMC,EAAU,EAAKX,EAAO,EAAKW,EAAU,CAAC,CAChE,CACA,OAAOD,CACX,CAEA,iBAA0B,CACtB,IAAIJ,EAAI,KAAK,MACb,QAASC,EAAO,EAAGA,EAAO,KAAK,SAAUA,IAAQ,CACzCD,EAAI,EACJ,EAAEA,EAEFA,EAAI,KAAK,SAAW,EAExB,IAAMD,EAAM,KAAK,QAAQC,CAAC,EAC1B,GAAI,CAACD,EACD,MAEJ,GAAIA,EAAI,MAAQ,GAAKA,EAAI,MAAQ,EAE7B,OADcA,EAAI,KAAOA,EAAI,KAGjC,GAAIC,IAAM,KAAK,MACX,KAER,CACA,MAAO,EACX,CAEA,iBAA0B,CAGtB,IAAII,EAAW,EACXV,EAAO,EACPC,EAAQ,GACRC,EAAM,GACNI,EAAI,KAAK,MACb,QAASC,EAAO,EAAGA,EAAO,KAAK,SAAUA,IAAQ,CACzCD,EAAI,EACJ,EAAEA,EAEFA,EAAI,KAAK,SAAW,EAExB,IAAME,EAAU,KAAK,QAAQF,CAAC,EAC9B,GAAKE,EAUL,IAPIN,IAAQ,IAAMM,EAAQ,KAAO,CAACA,EAAQ,QACtCN,EAAMM,EAAQ,IACdR,EAAO,GAEPC,IAAU,IAAMC,GAAO,GAAKM,EAAQ,OAAS,CAACA,EAAQ,MACtDP,EAAQO,EAAQ,KAEhBP,GAAS,GAAKC,GAAO,EAAG,CACxB,IAAMS,EAAUT,EAAMD,EACtBS,EAAWC,EAAU,EAAKX,EAAO,EAAKW,EAAU,EAChD,KACJ,CAKA,GAHIT,GAAO,IACPF,GAAQQ,EAAQ,MAEhBF,IAAM,KAAK,MACX,MAER,CACA,OAAO,KAAK,MAAMI,CAAQ,CAC9B,CAEA,OAAQ,CACJ,KAAK,QAAQ,KAAK,MAAS,EAC3B,KAAK,MAAQ,EACb,KAAK,MAAQ,EACb,KAAK,MAAQ,CACjB,CACJ,EClKA,IAAME,GAAoB,MACpBC,GAA0B,GAC1BC,GAA0B,IAC1BC,GAAkB,IAClBC,GAAkB,IAClBC,GAAwB,IACxBC,GAAsC,IAItCC,GAAuB,EAEzBC,GAAW,EAEMC,GAArB,KAAyC,CAuBrC,YAAYC,EAAyBC,EAA6BC,EAA0BC,EAAsB,CAtBlHC,EAAA,KAAiB,YACjBA,EAAA,KAAiB,gBACjBA,EAAA,KAAiB,cACjBA,EAAA,KAAiB,gBACjBA,EAAA,KAAQ,aAAa,IACrBA,EAAA,KAAQ,gBAAgB,IACxBA,EAAA,KAAiB,aACjBA,EAAA,KAAQ,sBACRA,EAAA,KAAQ,YAAY,GACpBA,EAAA,KAAQ,UACRA,EAAA,KAAQ,WACRA,EAAA,KAAQ,YAA2B,IAAIC,GAAc,IAAI,GACzDD,EAAA,KAAQ,oBAAoB,GAC5BA,EAAA,KAAQ,yBAAyB,GACjCA,EAAA,KAAQ,kBAAkB,GAC1BA,EAAA,KAAQ,wBAAwB,KAAK,IAAI,GACzCA,EAAA,KAAQ,mBAAmB,KAAK,IAAI,GACpCA,EAAA,KAAiB,6BACjBA,EAAA,KAAiB,SAAS,IAAIE,IAC9BF,EAAA,KAAiB,aACjBA,EAAA,KAAiB,kBAGbG,EAAM,MAAM,6BAA6B,EAGzC,KAAK,UAAYC,EAAO,oCAAsC,GAC9D,KAAK,aAAeP,EACpB,KAAK,WAAaC,EAClB,KAAK,aAAeC,EAEpB,KAAK,0BAA4BK,EAAO,8BAAgC,KAAK,aAC7E,KAAK,OAASR,EAAM,YAAY,EAAE,MAClC,KAAK,QAAUA,EAAM,YAAY,EAAE,OACnC,KAAK,eAAiB,KAAK,aAAeQ,EAAO,sCAAwCA,EAAO,sCAAwC,EACxI,IAAMC,EAAYD,EAAO,mBAAmB,KAAK,YAAY,EACvD,CAAE,WAAAE,EAAY,WAAAC,CAAW,EAAI,KAAK,mBAAmB,KAAK,OAAQ,KAAK,OAAO,EAC9EC,EAAgB,KAAK,sBAAsB,KAAK,IAAI,EAE1DL,EAAM,IACF,mDAAmD,KAAK,yBAAyB,eAAe,KAAK,MAAMG,EAAa,GAAI,CAAC,gBAAgB,KAAK,MAAMC,EAAa,GAAI,CAAC,oBAAoBH,EAAO,qCAAqC,EAC9O,EACA,KAAK,mBAAqB,IAAIK,GAC1BD,EACAF,EACAC,EACA,KAAK,0BACL,KAAK,aACLH,EAAO,sCACPC,CACJ,EAEA,IAAMK,EAAU,CAACC,EAAiCC,IAAe,CAC7D,GAAI,KAAK,WACL,OAGJ,GAAI,CAACD,EAAO,CACRR,EAAM,KAAK,kCAAoC,KAAK,cAAeS,CAAC,EACpE,KAAK,cAAgB,GACrB,KAAK,aAAa,EAClB,MACJ,EAEID,EAAM,QAAU,KAAK,QAAUA,EAAM,SAAW,KAAK,WACrD,KAAK,OAASA,EAAM,MACpB,KAAK,QAAUA,EAAM,OACrB,KAAK,UAAU,KAAK,OAAQ,KAAK,OAAO,GAG5C,IAAME,EAAS,KAAK,YAAYF,CAAK,EACrC,KAAK,OAAO,MAAME,CAAM,EACxB,KAAK,aAAa,EAClB,KAAK,iBAAiB,CAC1B,EAEA,GAAIC,GAAiB,mBAAmB,EAAG,CACvC,IAAMC,EAAS,KAAK,aACpB,KAAK,SAAW,IAAID,GAAiBlB,EAAOc,EAAS,KAAK,0BAA2BH,EAAYQ,EAAQV,CAAS,CACtH,MACI,KAAK,SAAW,IAAIW,GAAcpB,EAAOc,EAAS,KAAK,0BAA2BH,CAAU,EAGhG,KAAK,aAAa,UAAaK,GAAM,CAC7BK,GAAoBL,EAAE,IAAI,IAC1BT,EAAM,MAAM,IAAI,KAAK,aAAa,KAAK,sBAAsB,EAC7D,KAAK,cAAgB,IAEzB,IAAMe,EAAKC,GAAgBP,EAAE,IAAI,EAC7BM,IAAO,MACP,KAAK,iBAAiBA,CAAE,CAEhC,EAEA,KAAK,SACA,KAAK,EACL,KAAK,IAAM,KAAK,aAAa,CAAC,EAC9B,MAAON,GAAMT,EAAM,KAAK,kCAAmCS,CAAC,CAAC,EAGlE,KAAK,UAAY,IAAIQ,GAAUC,GAAgBlB,EAAM,IAAI,8BAA8BkB,CAAG,EAAE,EAAG,GAAK,CACxG,CAEQ,cAAqB,CACzB,GAAI,KAAK,WACL,OAGJ,IAAMC,EAAQ,KAAK,OAAO,MAAM,EAChC,GAAI,CAACA,EAAO,CAGR,IADiB,KAAK,kBAAoB,KAAK,uBAAyBpC,IAAqBA,GAC/EO,IAAwB,KAAK,gBAAkB,KAAK,eAAgB,CAG9E,IAAM8B,EAAM,KAAK,IAAI,EACLA,EAAM,KAAK,sBACb/B,KACV,KAAK,sBAAwB+B,EAC7BpB,EAAM,MAAM,iDAAiD,KAAK,eAAe,aAAa,KAAK,cAAc,EAAE,EAE3H,MACI,KAAK,cAAc,EAEvB,MACJ,CAGA,GAAI,CADW,KAAK,gBAAgBmB,CAAK,EAC5B,CACT,KAAK,cAAgB,KAAK,eAAiB,CAAC,KAAK,cAAc,EAC/DE,EAAM,aAAa,IAAM,KAAK,aAAa,CAAC,EAC5C,MACJ,CAEA,GAAIF,EAAM,OAAQ,CAEd,KAAK,YACL,KAAK,UAAU,UAAU,EAErBA,EAAM,OACNnB,EAAM,MAAM,IAAI,KAAK,SAAS,iCAAiC,KAAK,MAAMmB,EAAM,UAAY,GAAI,CAAC,GAAG,EAIxG,IAAMG,EAAQ,KAAK,UAAU,gBAAgB,EACvCC,EAAW,KAAK,UAAU,kBAAkB,GAAK,EACnDD,EAAQ,GACR,KAAK,mBAAmB,WAAW,KAAK,UAAWA,EAAOC,CAAQ,CAE1E,MACIF,EAAM,aAAa,IAAM,KAAK,aAAa,CAAC,CAEpD,CAOQ,eAAyB,CAC7B,IAAIG,EAAO,KAAK,OAAO,KAAK,EAC5B,KAAOA,GAAM,CACT,GAAIA,EAAK,SAAWA,EAAK,MACrB,MAAO,GAEX,KAAK,OAAO,MAAM,EAClBA,EAAO,KAAK,OAAO,KAAK,CAC5B,CACA,MAAO,EACX,CAEQ,eAAsB,CACtB,KAAK,aAIT,KAAK,SAAS,aAAa,KAAK,aAAa,EAC7C,KAAK,cAAgB,GACzB,CAEQ,YAAYhB,EAA4D,CAC5E,IAAMiB,EAAQjB,EAAM,OAAS,MACvBkB,EAAalB,EAAM,KAAK,WACxBmB,EAAS,IAAI5B,GAEnB,QAAS6B,EAAS,EAAGA,EAASF,EAAYE,GAAU,KAAK,UAAW,CAChE,IAAMC,EAAOrB,EAAM,KAAK,MAAMoB,EAAQA,EAAS,KAAK,SAAS,EACvDE,EAAUF,IAAW,EACrBG,EAASL,GAAcE,EAASC,EAAK,WACrCG,EAAU,KAAK,YAAYxB,EAAM,UAAWsB,EAASC,EAAQN,EAAOI,CAAI,EAC9EF,EAAO,KAAK,CACR,KAAMK,EAAQ,KACd,SAAUA,EAAQ,SAClB,UAAWN,EACX,QAAAI,EACA,OAAAC,EACA,MAAAN,EACA,UAAWjB,EAAM,SACrB,CAAC,CACL,CAEA,OAAOmB,CACX,CAEQ,YAAYM,EAAmBC,EAAgBC,EAAcC,EAAmBP,EAAmE,CACvJ,IAAMG,EAAUK,GAAWJ,EAAWC,EAAOC,EAAKC,EAAU7C,GAAU,KAAK,SAAS,MAAM,EAAGsC,CAAI,EAC3FF,EAAS,CACX,SAAApC,GACA,KAAMyC,CACV,EACA,OAAAzC,IAAYA,GAAW,GAAKR,GACrB4C,CACX,CAEQ,aAA2B,CAC/B,OAAO,KAAK,YAAY,KAAK,IAAI,EAAG,GAAO,GAAO,GAAO,IAAI,EAAE,IACnE,CAEQ,gBAAgBR,EAAwC,CAC5D,GAAI,CAAC,KAAK,cAAgB,KAAK,aAAa,aAAe,OAEvD,MAAO,GAIX,GAAI,CACA,YAAK,aAAa,KAAKA,EAAM,IAAI,EAEjC,KAAK,UAAU,IAAIA,EAAM,SAAUA,EAAM,UAAWA,EAAM,KAAK,WAAYA,EAAM,QAASA,EAAM,MAAM,EAClGA,EAAM,SACN,KAAK,kBAAoBA,EAAM,UAE5B,EACX,OAAS,EAAG,CACR,OAAAnB,EAAM,KAAK,qCAAsC,CAAC,EAC3C,EACX,CACJ,CAEA,SAAU,CACN,KAAK,OAAO,MAAM,EAClB,KAAK,UAAU,QAAQ,EACvB,KAAK,aAAa,UAAY,KAC9B,KAAK,UAAU,MAAM,EACjB,KAAK,aAAa,aAAe,QACjC,KAAK,aAAa,KAAK,KAAK,YAAY,CAAC,EAE7C,KAAK,WAAa,GAClB,KAAK,SAAS,QAAQ,EACtBA,EAAM,MAAM,+BAA+B,CAC/C,CAEA,OAAO,oBAA8B,CACjC,OAAOW,GAAiB,mBAAmB,GAAKE,GAAc,mBAAmB,CACrF,CAEQ,sBAAsByB,EAAiB1B,EAAiBM,EAAmB,CAC/E,KAAK,SAAS,WAAWoB,EAAS1B,EAAQM,CAAG,CACjD,CAEQ,UAAUqB,EAAeC,EAAsB,CACnD,GAAM,CAAE,WAAArC,EAAY,WAAAC,CAAW,EAAI,KAAK,mBAAmBmC,EAAOC,CAAM,EAClEC,EAAc,KAAK,MAAMtC,EAAa,GAAI,EAC1CuC,EAAc,KAAK,MAAMtC,EAAa,GAAI,EAChDJ,EAAM,IAAI,iBAAiBuC,CAAK,IAAIC,CAAM,gBAAgBC,CAAW,eAAeC,CAAW,EAAE,EACjG,KAAK,mBAAmB,YAAYvC,EAAYC,CAAU,CAC9D,CAEQ,mBAAmBmC,EAAeC,EAAgB,EAClDD,IAAU,QAAaA,EAAQ,OAC/BA,EAAQ,MAERC,IAAW,QAAaA,EAAS,OACjCA,EAAS,KAEb,IAAMG,EAAeJ,EAAQC,EAAU,IACjCrC,EAAa,KAAK,IAAIhB,GAAiB,KAAK,IAAID,GAAiB,KAAK,MAAMyD,EAAc3D,EAAuB,CAAC,CAAC,EACnHoB,EAAa,KAAK,MAAMuC,EAAc1D,EAAuB,EACnE,MAAO,CAAE,WAAAkB,EAAY,WAAAC,CAAW,CACpC,CAOQ,iBAAiBW,EAAsB,CAC3C,IAAM6B,EAAM,KAAK,UAAU,OAAO7B,EAAG,IAAKA,EAAG,GAAG,EAChD,GAAI6B,IAAQ,KACR5C,EAAM,MAAM,0BAA0Be,EAAG,GAAG,EAAE,UACvC6B,EAAI,IAAK,CAChB,KAAK,uBAAyBA,EAAI,IAClC,IAAMtB,EAAQsB,EAAI,KAAOA,EAAI,KACzBtB,EAAQ,IACR,KAAK,gBAAkBA,GAE3B,KAAK,aAAa,CACtB,CACJ,CAEQ,kBAAmB,CACvB,IAAMF,EAAM,KAAK,IAAI,EAErB,GADgBA,EAAM,KAAK,iBACbhC,GAAuB,CACjC,IAAMyD,EAAS,KAAK,mBAAmB,QAAQ,EAC3CA,IAAW,OACX7C,EAAM,MAAM,mBAAmB,KAAK,UAAU6C,CAAM,CAAC,EAAE,EACvD,KAAK,WAAW,kBAAkBA,CAAM,GAE5C,KAAK,iBAAmBzB,CAC5B,CACJ,CACJ,ECtVA,IAA8B0B,GAA9B,MAA8BA,EAAS,CAKnC,WAAW,YAAa,CACpB,OAAOA,GAAS,WACpB,CAEA,WAAW,WAAWC,EAA2B,CAC7CD,GAAS,YAAcC,CAC3B,CAEA,WAAW,kBAAmB,CAC1B,OAAOD,GAAS,iBACpB,CAEA,WAAW,iBAAiBC,EAA2B,CACnDD,GAAS,kBAAoBC,CACjC,CAEA,WAAW,aAAc,CACrB,OAAOD,GAAS,YACpB,CAEA,WAAW,YAAYC,EAA2B,CAC9CD,GAAS,aAAeC,CAC5B,CAEA,OAAO,SAAU,CACb,MAAO,CAACD,GAAS,WACrB,CACJ,EA/BIE,EAD0BF,GACX,eACfE,EAF0BF,GAEX,qBACfE,EAH0BF,GAGX,gBAHnB,IAA8BG,GAA9BH,GCm9BA,IAA8BI,EAA9B,MAA8BA,CAAO,CA0IjC,OAAO,IAAIC,EAA8B,CACjC,OAAO,OAAOA,EAAM,aAAa,IACjC,OAAO,OAAOD,EAAO,QAAQ,YAAaC,EAAK,WAAW,EAC1D,OAAOA,EAAK,aAEZ,OAAO,OAAOA,EAAM,oBAAoB,IACxC,OAAO,OAAOD,EAAO,QAAQ,mBAAoBC,EAAK,kBAAkB,EACxE,OAAOA,EAAK,oBAEZ,OAAO,OAAOA,EAAM,SAAS,IAC7BC,GAAS,YAAcD,EAAK,QAAQ,YACpCC,GAAS,WAAaD,EAAK,QAAQ,WACnCC,GAAS,iBAAmBD,EAAK,QAAQ,kBAG7C,OAAO,OAAOD,EAAO,QAASG,EAAM,sBAAsBF,EAAM,MAAS,CAAC,CAC9E,CAEA,OAAO,IAAkCG,EAA0B,CAC/D,OAAOJ,EAAO,QAAQI,CAAI,CAC9B,CAEA,WAAW,SAAU,CACjB,MAAO,iBACX,CAEA,WAAW,YAAa,CACpB,MAAO,IACX,CAEA,WAAW,YAAa,CAEpB,MAAO,uBACX,CAEA,WAAW,OAAQ,CACf,OAAOJ,EAAO,QAAQ,KAC1B,CAEA,WAAW,iBAAkB,CACzB,OAAOA,EAAO,QAAQ,wBAA0B,EAAI,CACxD,CAEA,WAAW,UAAW,CAClB,OAAOA,EAAO,QAAQ,QAC1B,CAEA,WAAW,SAASK,EAAe,CAC/BL,EAAO,QAAQ,SAAWK,CAC9B,CAEA,WAAW,qBAAsB,CAC7B,OAAOL,EAAO,QAAQ,mBAC1B,CAEA,WAAW,oBAAoBK,EAAe,CAC1CL,EAAO,QAAQ,oBAAsBK,CACzC,CAEA,WAAW,YAAa,CACpB,OAAOL,EAAO,QAAQ,UAC1B,CAEA,WAAW,WAAWK,EAAe,CACjCL,EAAO,QAAQ,WAAaK,CAChC,CAEA,WAAW,kBAAmB,CAC1B,OAAOL,EAAO,QAAQ,gBAC1B,CAEA,WAAW,iBAAiBK,EAAe,CACvCL,EAAO,QAAQ,iBAAmBK,CACtC,CAEA,WAAW,QAAS,CAChB,OAAOL,EAAO,QAAQ,MAC1B,CAEA,WAAW,QAAS,CAChB,OAAOA,EAAO,QAAQ,MAC1B,CAEA,WAAW,QAAkB,CACzB,OAAOA,EAAO,QAAQ,MAC1B,CAEA,WAAW,YAA0B,CACjC,OAAOA,EAAO,QAAQ,UAC1B,CAEA,WAAW,WAAWM,EAAyB,CAC3CN,EAAO,QAAQ,WAAaM,CAChC,CAEA,OAAO,YAAYC,EAA0B,CACzC,OAAQA,GAAUP,EAAO,OAAQ,CAC7B,IAAK,OACL,IAAK,OACD,MAAO,uBACX,IAAK,QACD,MAAO,yBACX,IAAK,UACD,MAAO,oBACX,IAAK,OACD,MAAO,4BACX,IAAK,YACD,MAAO,iCACX,IAAK,YACD,MAAO,kCACX,IAAK,aACD,MAAO,2CACX,IAAK,eACD,MAAO,6CACX,IAAK,cACD,MAAO,4CACX,IAAK,aACD,MAAO,2CACX,QACI,OAAOA,EAAO,QAAQ,MAC9B,CACJ,CAEA,WAAW,YAAa,CACpB,OAAOA,EAAO,QAAQ,UAC1B,CAEA,WAAW,eAAgB,CACvB,OAAOA,EAAO,QAAQ,aAC1B,CAEA,WAAW,WAAY,CACnB,OAAOA,EAAO,QAAQ,SAC1B,CAEA,WAAW,UAAUK,EAAe,CAChCL,EAAO,QAAQ,UAAYK,CAC/B,CAEA,WAAW,aAAc,CACrB,OAAOL,EAAO,QAAQ,WAC1B,CAEA,WAAW,YAAYK,EAAe,CAClCL,EAAO,QAAQ,YAAcK,CACjC,CAEA,WAAW,QAAS,CAChB,OAAOL,EAAO,QAAQ,MAC1B,CAEA,WAAW,gBAAiB,CACxB,OAAOA,EAAO,QAAQ,cAC1B,CAEA,WAAW,YAAa,CACpB,OAAOA,EAAO,QAAQ,UAC1B,CAEA,WAAW,WAAWK,EAAoB,CACtCL,EAAO,QAAQ,WAAaK,CAChC,CAEA,WAAW,SAAU,CACjB,OAAOL,EAAO,QAAQ,OAC1B,CAEA,WAAW,QAAQK,EAAe,CAC9BL,EAAO,QAAQ,QAAUK,CAC7B,CAEA,WAAW,SAAU,CACjB,OAAOL,EAAO,QAAQ,OAC1B,CAEA,WAAW,QAAQK,EAAe,CAC9BL,EAAO,QAAQ,QAAUK,CAC7B,CAEA,WAAW,UAAW,CAClB,OAAOL,EAAO,QAAQ,QAC1B,CAEA,WAAW,SAASK,EAAe,CAC/BL,EAAO,QAAQ,SAAWK,CAC9B,CAEA,WAAW,yBAA0B,CACjC,OAAOL,EAAO,QAAQ,uBAC1B,CAEA,WAAW,4BAA6B,CACpC,OAAOA,EAAO,QAAQ,0BAC1B,CAEA,WAAW,4BAA6B,CACpC,OAAOA,EAAO,QAAQ,0BAC1B,CAEA,WAAW,qBAAsB,CAC7B,OAAOA,EAAO,QAAQ,mBAC1B,CAEA,WAAW,mBAAoB,CAC3B,OAAOA,EAAO,QAAQ,iBAC1B,CAEA,WAAW,kBAAmB,CAC1B,OAAOA,EAAO,QAAQ,gBAC1B,CAEA,WAAW,qBAAsB,CAC7B,OAAOA,EAAO,QAAQ,mBAC1B,CAEA,WAAW,UAAW,CAClB,OAAOA,EAAO,QAAQ,QAC1B,CAEA,WAAW,kBAAmB,CAC1B,OAAOA,EAAO,QAAQ,gBAC1B,CAEA,WAAW,iBAAiBK,EAAgB,CACxCL,EAAO,QAAQ,iBAAmBK,CACtC,CAEA,WAAW,eAAgB,CACvB,OAAOL,EAAO,QAAQ,aAC1B,CAEA,WAAW,eAAgB,CACvB,OAAOA,EAAO,QAAQ,aAC1B,CAEA,WAAW,cAAcK,EAAe,CACpCL,EAAO,QAAQ,cAAgBK,CACnC,CAEA,WAAW,gBAAiB,CACxB,OAAOL,EAAO,QAAQ,cAC1B,CAEA,WAAW,gBAAiB,CACxB,OAAOA,EAAO,QAAQ,cAC1B,CAEA,WAAW,eAAeK,EAAe,CACrCL,EAAO,QAAQ,eAAiBK,CACpC,CAEA,WAAW,kBAAmB,CAC1B,OAAOL,EAAO,QAAQ,gBAC1B,CAEA,WAAW,gBAAiB,CACxB,OAAOA,EAAO,QAAQ,cAC1B,CAEA,WAAW,iBAAkB,CACzB,OAAOA,EAAO,QAAQ,kBAAoBQ,EAAY,SAAS,SAAsB,KACzF,CAEA,WAAW,gBAAgBH,EAA0B,CACjDL,EAAO,QAAQ,gBAAkBK,CACrC,CAEA,WAAW,gBAAiB,CACxB,OAAOL,EAAO,QAAQ,cAC1B,CAEA,WAAW,cAAe,CACtB,OAAOA,EAAO,QAAQ,YAC1B,CAEA,WAAW,aAAaK,EAAiC,CACrDL,EAAO,QAAQ,aAAeK,EAC9BL,EAAO,QAAQ,cAAc,UAAU,CAACS,KAA2BC,IAAgBC,EAAM,KAAKF,EAAM,GAAGC,CAAI,CAAC,CAChH,CAEA,WAAW,cAAe,CACtB,OAAOV,EAAO,QAAQ,YAC1B,CAEA,WAAW,aAAaK,EAA4B,CAChDL,EAAO,QAAQ,aAAeK,EAC9BL,EAAO,QAAQ,cAAc,UAAU,CAACS,KAA2BC,IAAgBC,EAAM,KAAKF,EAAM,GAAGC,CAAI,CAAC,CAChH,CAEA,WAAW,qBAAsB,CAC7B,OAAOV,EAAO,QAAQ,mBAC1B,CAEA,WAAW,oBAAoBK,EAAe,CAC1CL,EAAO,QAAQ,oBAAsBK,CACzC,CAEA,WAAW,sBAAuB,CAC9B,OAAOL,EAAO,QAAQ,oBAC1B,CAEA,WAAW,qBAAqBK,EAAe,CAC3CL,EAAO,QAAQ,qBAAuBK,CAC1C,CAEA,WAAW,OAAQ,CACf,OAAKL,EAAO,QAAQ,OAAO,mBAAmB,EAGvCA,EAAO,QAAQ,MAFX,IAGf,CAEA,WAAW,MAAMK,EAA4B,CACzCL,EAAO,QAAQ,MAAQK,CAC3B,CAEA,WAAW,cAA0D,CACjE,OAAOL,EAAO,QAAQ,cAAgB,CAAE,gBAAiB,EAAG,iBAAkB,CAAC,CAAE,CACrF,CAEA,WAAW,aAAaK,EAAqC,CACzDL,EAAO,QAAQ,aAAeK,CAClC,CAEA,WAAW,aAAc,CACrB,OAAOL,EAAO,QAAQ,WAC1B,CAEA,WAAW,oBAAqB,CAC5B,OAAOA,EAAO,QAAQ,kBAC1B,CAEA,WAAW,oBAAqB,CAC5B,OAAOA,EAAO,QAAQ,kBAC1B,CAEA,WAAW,6BAA8B,CACrC,OAAOA,EAAO,QAAQ,2BAC1B,CAEA,WAAW,oBAAqB,CAC5B,OAAOA,EAAO,QAAQ,kBAC1B,CAEA,WAAW,mBAAmBK,EAAe,CACzCL,EAAO,QAAQ,mBAAqBK,CACxC,CAEA,WAAW,2BAA4B,CACnC,OAAOL,EAAO,QAAQ,yBAC1B,CAEA,WAAW,uBAAwB,CAC/B,OAAOA,EAAO,QAAQ,qBAC1B,CAEA,WAAW,uBAAwB,CAC/B,OAAOA,EAAO,QAAQ,qBAC1B,CAEA,WAAW,4BAA6B,CACpC,OAAOA,EAAO,QAAQ,0BAC1B,CAEA,WAAW,yBAA0B,CACjC,OAAOA,EAAO,QAAQ,uBAC1B,CAEA,WAAW,iCAAkC,CACzC,OAAOA,EAAO,QAAQ,+BAC1B,CAEA,WAAW,4BAA6B,CACpC,OAAOA,EAAO,QAAQ,0BAC1B,CAEA,WAAW,2BAA4B,CACnC,OAAOA,EAAO,QAAQ,2BAA6BY,GAAoB,mBAAmB,CAC9F,CAEA,WAAW,2BAA4B,CAEnC,OAAOZ,EAAO,QAAQ,2BAA6BA,EAAO,iCAAmCa,GAAsB,mBAAmB,CAC1I,CAEA,WAAW,gBAAiB,CACxB,OAAOb,EAAO,QAAQ,gBAAkBA,EAAO,+BACnD,CAEA,WAAW,qCAAsC,CAC7C,OAAOA,EAAO,QAAQ,mCAC1B,CAEA,WAAW,wBAAyB,CAChC,OAAOA,EAAO,QAAQ,sBAC1B,CAEA,WAAW,kBAAmB,CAC1B,OAAOA,EAAO,QAAQ,gBAC1B,CAEA,WAAW,iBAAiBK,EAAgB,CACxCL,EAAO,QAAQ,iBAAmBK,CACtC,CAEA,WAAW,YAAa,CACpB,OAAOL,EAAO,QAAQ,UAC1B,CAEA,WAAW,WAAY,CACnB,OAAOA,EAAO,QAAQ,SAC1B,CAEA,WAAW,WAAY,CACnB,OAAOA,EAAO,QAAQ,SAC1B,CAEA,WAAW,qBAAsB,CAE7B,OAAOA,EAAO,QAAQ,qBAAuBA,EAAO,yBACxD,CAEA,WAAW,qBAAsB,CAC7B,OAAOA,EAAO,QAAQ,mBAC1B,CAEA,WAAW,YAAa,CACpB,OAAOA,EAAO,QAAQ,YAAcA,EAAO,iBAAmB,CAClE,CAEA,WAAW,kBAAmB,CAC1B,OAAOA,EAAO,gCAAkC,OAAOA,EAAO,QAAQ,gBAAgB,EAAI,CAC9F,CAEA,WAAW,wBAAyB,CAChC,OAAOA,EAAO,QAAQ,sBAC1B,CAEA,WAAW,oBAAqB,CAC5B,OAAOA,EAAO,QAAQ,kBAC1B,CAEA,WAAW,yBAA0B,CACjC,OAAOA,EAAO,QAAQ,yBAA2BA,EAAO,iBAAmB,CAC/E,CAEA,WAAW,UAAW,CAClB,OAAOA,EAAO,QAAQ,QAC1B,CAEA,WAAW,cAAe,CACtB,OAAOA,EAAO,QAAQ,YAC1B,CAEA,WAAW,gBAAiB,CACxB,OAAOA,EAAO,QAAQ,cAC1B,CAEA,WAAW,0BAA2B,CAClC,OAAOA,EAAO,QAAQ,wBAC1B,CAEA,WAAW,+BAAgC,CACvC,OAAOA,EAAO,QAAQ,+BAAiC,CAC3D,CAEA,WAAW,+BAAgC,CACvC,OAAOA,EAAO,QAAQ,+BAAiC,IAC3D,CAEA,WAAW,gBAAiB,CACxB,OAAOA,EAAO,QAAQ,cAC1B,CAEA,WAAW,aAAc,CACrB,OAAOA,EAAO,QAAQ,WAC1B,CAEA,WAAW,yBAA0B,CACjC,OAAOA,EAAO,QAAQ,uBAC1B,CAEA,WAAW,iBAAkB,CACzB,OAAOA,EAAO,QAAQ,eAC1B,CAEA,WAAW,UAAW,CAClB,OAAOA,EAAO,QAAQ,QAC1B,CAEA,WAAW,qBAAsB,CAC7B,OAAOA,EAAO,QAAQ,mBAC1B,CAEA,WAAW,YAAa,CACpB,OAAOQ,EAAY,sBAAsB,GAAKR,EAAO,QAAQ,UACjE,CAEA,WAAW,iBAAkB,CACzB,OAAOA,EAAO,QAAQ,eAC1B,CAEA,WAAW,8BAA+B,CACtC,OAAOA,EAAO,QAAQ,4BAC1B,CAEA,WAAW,uCAAwC,CAC/C,OAAOA,EAAO,QAAQ,qCAC1B,CAEA,WAAW,sBAAuB,CAC9B,OAAOA,EAAO,QAAQ,oBAC1B,CAEA,WAAW,uBAAwB,CAC/B,OAAOA,EAAO,QAAQ,qBAC1B,CAEA,WAAW,yBAA0B,CACjC,OAAOA,EAAO,QAAQ,uBAC1B,CAEA,WAAW,wCAAyC,CAChD,OAAOA,EAAO,QAAQ,sCAC1B,CAEA,WAAW,cAAe,CACtB,OAAOA,EAAO,QAAQ,YAC1B,CAEA,WAAW,cAAe,CACtB,OAAOA,EAAO,QAAQ,YAC1B,CAEA,WAAW,uBAAwB,CAC/B,OAAOA,EAAO,QAAQ,qBAC1B,CAEA,OAAO,mBAAmBc,EAAkC,CACxD,OAAOA,EAAkBd,EAAO,QAAQ,yBAA2BA,EAAO,QAAQ,eACtF,CAEA,WAAW,yBAA0B,CACjC,OAAOA,EAAO,QAAQ,uBAC1B,CAEA,WAAW,kCAAmC,CAC1C,OAAOA,EAAO,QAAQ,gCAC1B,CAEA,WAAW,WAAY,CACnB,OAAOA,EAAO,QAAQ,SAC1B,CAEA,WAAW,UAAUK,EAAgB,CACjCL,EAAO,QAAQ,UAAYK,CAC/B,CAEA,WAAW,cAAe,CACtB,OAAOL,EAAO,QAAQ,YAC1B,CAEA,WAAW,aAAaK,EAAgB,CACpCL,EAAO,QAAQ,aAAeK,CAClC,CAEA,WAAW,gBAAiB,CACxB,OAAOL,EAAO,QAAQ,cAC1B,CAEA,WAAW,eAAeK,EAAgB,CACtCL,EAAO,QAAQ,eAAiBK,CACpC,CAEA,OAAO,QAAS,CACZ,MAAO,CACH,OAAQL,EAAO,QAAQ,OACvB,OAAQA,EAAO,QAAQ,OACvB,WAAYA,EAAO,QAAQ,WAC3B,mBAAoBA,EAAO,QAAQ,mBACnC,wBAAyBA,EAAO,QAAQ,wBACxC,SAAUA,EAAO,QAAQ,SACzB,aAAcA,EAAO,QAAQ,aAC7B,eAAgBA,EAAO,QAAQ,eAC/B,gBAAiBA,EAAO,QAAQ,gBAChC,8BAA+BA,EAAO,QAAQ,8BAC9C,6BAA8BA,EAAO,QAAQ,6BAC7C,sCAAuCA,EAAO,QAAQ,sCACtD,iBAAkBA,EAAO,QAAQ,iBACjC,eAAgBA,EAAO,QAAQ,eAC/B,eAAgBA,EAAO,QAAQ,eAC/B,cAAeA,EAAO,QAAQ,cAC9B,qBAAsBA,EAAO,QAAQ,qBACrC,oBAAqBA,EAAO,QAAQ,oBACpC,aAAcA,EAAO,QAAQ,aAC7B,SAAUA,EAAO,QAAQ,SACzB,sBAAuBA,EAAO,QAAQ,sBACtC,wBAAyBA,EAAO,QAAQ,wBACxC,WAAYA,EAAO,QAAQ,WAC3B,aAAcA,EAAO,QAAQ,aAC7B,WAAYA,EAAO,QAAQ,WAC3B,oBAAqBA,EAAO,QAAQ,oBACpC,oCAAqCA,EAAO,QAAQ,oCACpD,wBAAyBA,EAAO,QAAQ,wBACxC,UAAWA,EAAO,QAAQ,UAC1B,aAAcA,EAAO,QAAQ,aAC7B,eAAgBA,EAAO,QAAQ,cACnC,CACJ,CACJ,EA1uBIe,EAD0Bf,EACX,UAAwB,CACnC,SAAU,MACV,oBAAqB,GACrB,WAAY,SACZ,iBAAkB,GAClB,OAAQ,UAER,OAAQ,GACR,UAAW,GACX,YAAa,GACb,OAAQ,OACR,WAAY,KACZ,OAAQ,GACR,eAAgB,GAEhB,WAAY,CAAC,EACb,QAAS,GACT,QAAS,GACT,SAAU,GAEV,wBAAyB,IACzB,2BAA4B,IAC5B,2BAA4B,GAC5B,oBAAqB,IACrB,kBAAmB,IACnB,iBAAkB,KAElB,oBAAqB,IAErB,SAAU,GACV,MAAO,GAEP,WAAY,IACZ,cAAe,GAEf,iBAAkB,GAElB,cAAe,IACf,eAAgB,IAChB,cAAe,KACf,eAAgB,IAChB,iBAAkB,GAAK,EACvB,eAAgB,GAChB,gBAAiB,GACjB,gBAAiB,KACjB,eAAgB,UAEhB,aAAc,KACd,aAAc,KACd,oBAAqB,IACrB,qBAAsB,IAEtB,MAAO,KACP,aAAc,KAEd,mBAAoB,IACpB,4BAA6B,IAE7B,mBAAoB,IACpB,0BAA2B,IAE3B,sBAAuB,GACvB,sBAAuB,GACvB,2BAA4B,GAC5B,wBAAyB,GAEzB,YAAa,CACT,UAAW,GACX,QAAS,IACT,QAAS,IACT,SAAU,IACV,UAAW,IACX,uBAAwB,GAC5B,EAEA,mBAAoB,CAChB,kBAAmB,IACnB,cAAe,GACnB,EAEA,gCAAiC,GACjC,2BAA4B,GAC5B,0BAA2B,GAC3B,0BAA2B,GAC3B,eAAgB,GAEhB,oCAAqC,GAAK,KAE1C,uBAAwB,GAExB,iBAAkB,GAElB,WAAY,GACZ,UAAW,GACX,UAAW,GACX,oBAAqB,GACrB,oBAAqB,GACrB,iBAAkB,GAClB,WAAY,GACZ,mBAAoB,GACpB,wBAAyB,GACzB,SAAU,GACV,aAAc,GACd,eAAgB,GAChB,yBAA0B,GAC1B,8BAA+B,EAC/B,8BAA+B,KAC/B,eAAgB,GAChB,YAAa,GACb,wBAAyB,GACzB,uBAAwB,GACxB,wBAAyB,GAEzB,gBAAiB,GACjB,SAAU,GACV,oBAAqB,GACrB,WAAY,GACZ,gBAAiB,GACjB,6BAA8B,GAC9B,sCAAuC,KACvC,wBAAyB,GACzB,uCAAwC,GAExC,yBAA0B,GAC1B,qBAAsB,KACtB,sBAAuB,IACvB,aAAc,GACd,aAAc,GAEd,sBAAuB,IACvB,wBAAyB,GACzB,iCAAkC,GAClC,UAAW,GACX,aAAc,GACd,eAAgB,EACpB,GAxIJ,IAA8BgB,EAA9BhB,ECn7BO,SAASiB,GAAqBC,EAAoBC,EAAoB,CAgBzE,MAfI,EAAAD,EAAI,iBAAmBC,EAAI,gBAG3BD,EAAI,iBAAmBC,EAAI,gBAG3BD,EAAI,yBAA2BC,EAAI,wBAGnCD,EAAI,6BAA+BC,EAAI,4BAGvCD,EAAI,wBAA0BC,EAAI,uBAGlCD,EAAI,mBAAqBC,EAAI,iBAIrC,CAEO,SAASC,GAAgCC,EAA4C,CACxF,OAAO,OAAO,OACV,CACI,eAAgB,GAChB,eAAgB,GAChB,uBAAwB,GACxB,2BAA4B,GAC5B,sBAAuB,GACvB,iBAAkB,EACtB,EACAA,GAAM,CAAC,CACX,CACJ,CChEO,IAAMC,GAAwBC,GAA4BA,EAAM,KAAK,EAC/DC,GAAyBC,GAAwBA,EAAO,UAAU,EAAE,QAAQH,EAAoB,EAChGI,GAA8BD,GAAwBA,EAAO,eAAe,EAAE,QAAQH,EAAoB,EAEvH,eAAsBK,GAAoBC,EAAyBC,EAAmD,CAClH,GAAI,CACA,IAAMC,EAAQ,OAAOD,EAAY,OAAU,SAAWA,EAAY,MAAQ,OACpEE,EAAS,OAAOF,EAAY,QAAW,SAAWA,EAAY,OAAS,OAC7E,MAAMD,EAAM,iBAAiB,CACzB,GAAGC,EACH,GAAIC,GAAS,CAAE,MAAO,CAAE,IAAKA,EAAO,MAAOA,CAAM,CAAE,EACnD,GAAIC,GAAU,CAAE,OAAQ,CAAE,IAAKA,EAAQ,MAAOA,CAAO,CAAE,CAC3D,CAAC,CACL,OAAS,EAAG,CACRC,EAAM,KAAK,6BAA8B,CAAC,CAC9C,CACJ,CCTO,IAAMC,GAAN,cAAqCC,EAAa,CAAlD,kCAEHC,EAAA,KAAiB,aAAa,CAAC,GAAI,GAAI,KAAK,IAAIC,EAAO,eAAgB,EAAE,CAAC,GAC1ED,EAAA,KAAiB,YAAY,IAC7BA,EAAA,KAAiB,iBAAiB,IAElCA,EAAA,KAAQ,uBAA4C,MACpDA,EAAA,KAAiB,cAAc,CAC3B,OAAQ,EACR,IAAK,CAAC,CACV,GACAA,EAAA,KAAQ,kBAAkB,KAAK,WAAW,OAAS,GAEnD,IAAI,UAAW,CACX,OAAO,KAAK,WAAW,KAAK,eAAe,CAC/C,CAEA,MAAME,EAAkC,CACpC,KAAK,SAAS,EACd,GAAI,CACIA,IACA,KAAK,oBAAoBA,CAAW,EACpC,KAAK,qBAAuBA,EAAY,oBAAoB,KAAK,gBAAgB,KAAK,IAAI,CAAC,EAEnG,OAASC,EAAG,CACRC,EAAM,KAAK,+BAAgCD,CAAC,CAChD,CACJ,CAEQ,gBAAgBE,EAAa,CAIjC,GAHA,KAAK,YAAY,IAAI,KAAK,YAAY,MAAM,EAAIA,EAChD,KAAK,YAAY,QAAU,KAAK,YAAY,OAAS,GAAK,KAAK,eAE3D,KAAK,YAAY,IAAI,SAAW,KAAK,gBAAkB,KAAK,gBAAiB,CAC7E,IAAMC,EAAU,KAAK,YAAY,IAAI,OAAO,CAACC,EAAKC,IAAaD,EAAMC,EAAU,CAAC,EAAI,KAAK,eACnFC,EAAQ,KAAK,WAAW,KAAK,eAAe,EAC9CH,EAAUG,EAAQ,KAAK,YACvB,KAAK,gBAAkB,KAAK,IAAI,EAAG,KAAK,gBAAkB,CAAC,GAE3DA,IAAU,KAAK,UACf,KAAK,cAAc,YAAsC,KAAK,QAAQ,CAE9E,CACJ,CAGQ,oBAAoBP,EAAgE,CACxF,GAAI,EAAE,wBAAyBA,GAC3B,MAAM,IAAI,MAAM,8BAA8B,CAEtD,CAES,iBAAiBQ,EAAoCC,EAAuD,CACjH,OAAO,MAAM,iBAAiBD,EAAOC,CAAE,CAC3C,CAEQ,UAAW,CACf,KAAK,uBAAuB,EAC5B,KAAK,qBAAuB,IAChC,CAEA,SAAU,CACN,KAAK,SAAS,EACd,MAAM,YAAY,CACtB,CACJ,EC/CO,IAAWC,QACdA,EAAA,MAAU,QACVA,EAAA,MAAU,QACVA,EAAA,OAAW,SACXA,EAAA,WAAe,aAJDA,QAAA,IAoBX,IAAMC,GAAN,cAA0BC,EAAa,CAwB1C,aAAc,CACV,MAAM,EAvBVC,EAAA,KAAU,UAA8B,MACxCA,EAAA,KAAQ,eAAwC,MAChDA,EAAA,KAAQ,mBAA4C,MACpDA,EAAA,KAAQ,oBAA6C,MAErDA,EAAA,KAAQ,kBAA2C,MAEnDA,EAAA,KAAQ,oBAA6C,MAErDA,EAAA,KAAQ,iBAA0C,MAElDA,EAAA,KAAQ,qBAA8C,MACtDA,EAAA,KAAQ,iBAAgCC,GAAgC,GACxED,EAAA,KAAQ,uCAAuC,IAC/CA,EAAA,KAAQ,UAA0B,MAClCA,EAAA,KAAQ,qBAA+C,MACvDA,EAAA,KAAQ,mBAERA,EAAA,KAAQ,kBAAkB,IAE1BA,EAAA,KAAiB,2BAofjBA,EAAA,KAAQ,wBAAwB,IAAM,CAC9B,KAAK,eAAe,gBACpB,KAAK,YAAY,EAAI,CAE7B,GApfI,KAAK,0BAA0B,EAC3BE,EAAO,aACP,KAAK,iBAAmB,KAAK,yBAAyB,GAEtDA,EAAO,mCACP,KAAK,wBAA0B,IAAIC,GACnC,KAAK,wBAAwB,6BAAuD,KAAK,yBAAyB,KAAK,IAAI,CAAC,EAEpI,CAEA,IAAI,kBAAmB,CACnB,OAAO,KAAK,iBAChB,CAEA,IAAI,iBAAiBC,EAAgC,CAC7C,KAAK,mBACL,KAAK,kBAAkB,oBAAoB,OAAQ,KAAK,qBAAqB,EAGjF,KAAK,kBAAoBA,EAErB,KAAK,mBAEL,KAAK,kBAAkB,iBAAiB,OAAQ,KAAK,qBAAqB,EAE1EF,EAAO,0BACP,KAAK,kBAAoB,KAAK,yBAAyB,EAE/D,CAEA,MAAM,QAAQG,EAAe,CAACC,GAAY,KAAK,EAAGC,EAAkB,GAAqB,CACrF,GAAI,KAAK,QACL,OAGJ,IAAMC,EAAYH,EAAa,SAASC,GAAY,KAAK,EACnDG,EAAYJ,EAAa,SAASC,GAAY,KAAK,EACnDI,EAAcL,EAAa,SAASC,GAAY,OAAO,EAE7D,GAAI,CAACK,EAAY,mBAAmB,EAChC,MAAM,IAAIC,EAAaC,GAAW,WAAW,EAGjD,GAAI,CACA,KAAK,QAAU,MAAMF,EAAY,aAAaH,EAAWC,EAAWF,CAAe,EACnF,KAAK,kBAAkB,KAAK,EAC5B,KAAK,iBAAmB,KAAK,QAAQ,eAAe,EAAE,CAAC,EACvD,KAAK,gBAAgB,KAAK,EAC1B,KAAK,eAAiB,KAAK,QAAQ,eAAe,EAAE,CAAC,EACrD,KAAK,oBAAoB,KAAK,EAC9B,KAAK,eAAe,eAAkBC,GAAa,KAAK,QAAQ,eAAe,EAAE,OAAQJ,GAAUA,EAAM,OAAO,EAAE,OAAS,GAAM,GACjI,KAAK,eAAe,eAAkBK,GAAa,KAAK,QAAQ,eAAe,EAAE,OAAQL,GAAUA,EAAM,OAAO,EAAE,OAAS,GAAM,GACjI,KAAK,eAAe,iBAAoBM,GAAe,CAAC,KAAK,eAAe,gBAAmB,GAC/F,KAAK,gBAAkBA,EACvB,KAAK,cAAc,cAA6B,CACpD,OAASI,EAAY,CACjB,MAAM,IAAIF,EAAaE,CAAK,CAChC,CACJ,CAEA,WAAgC,CAC5B,OAAO,KAAK,OAChB,CAEA,gBAA0C,CACtC,OAAO,KAAK,YAChB,CAEA,kBAAkBC,EAAgB,GAAgC,CAC9D,OAAI,KAAK,iBAAmB,CAACA,EAClB,KAAK,gBAGX,KAAK,QAIH,KAAK,QAAQ,eAAe,EAAE,CAAC,EAH3B,IAIf,CAEA,mBAA6C,CAEzC,OADc,KAAK,SAAS,eAAe,EAAE,KAAMC,GAAU,CAACA,EAAM,WAAW,GAC/D,IACpB,CAEA,IAAI,oBAA8B,CAC9B,OAAO,KAAK,iBAAmB,CAAC,KAAK,eAAe,cACxD,CAEA,yBAAyBC,EAAuBC,EAAmBH,EAA8B,CAC7F,IAAMI,EAAS,KAAK,UAAU,EACxBH,EAAQ,KAAK,kBAAkB,EAC/BI,EAAQ,KAAK,kBAAkBL,CAAa,EAElD,GAAI,CAACI,GAAW,CAACH,GAAS,CAACI,GAAS,CAACF,EACjC,MAAM,IAAI,MAAM,uBAAuB,EAGvCF,GAAS,CAACE,GACVD,EAAG,SAASD,EAAOG,CAAM,EAGzBC,GAAS,CAACF,GACVD,EAAG,SAASG,EAAOD,CAAM,CAEjC,CAEA,kBAAkC,CAC9B,OAAO,KAAK,cAChB,CAEA,MAAM,aAAaE,EAAsC,CACrD,OAAQA,EAAM,CACV,IAAK,aACD,GAAI,KAAK,eAAe,eACpB,OAAO,KAAK,kBAAkB,EAElC,MACJ,IAAK,aACD,GAAI,KAAK,eAAe,eACpB,OAAO,KAAK,kBAAkB,EAElC,MACJ,QACI,OAAO,QAAQ,OAAOR,GAAW,OAAO,CAChD,CACJ,CAOA,gBAAiB,CACR,KAAK,eAAe,iBAGzB,KAAK,YAAY,EACb,KAAK,SACLS,GAA2B,KAAK,OAAO,EAE3C,KAAK,kBAAkB,KAAK,EAChC,CAQA,MAAM,eAAeH,EAAqBI,EAAkC,CACxE,OAAIA,EACO,KAAK,cAAc,GAAO,GAAOJ,CAAM,EAE3C,KAAK,kBAAkBA,CAAM,CACxC,CAEQ,2BAA4B,CAC5B,CAAC,UAAU,cAAgB,CAAC,UAAU,aAAa,kBAAoB,CAAC,UAAU,aAAa,mBAInG,KAAK,gBAAkB,MAAOK,GAAkC,CAC5D,GAAI,CAAC,KAAK,QACN,OAKJ,IAAMC,EAAad,EAAY,mBAAmB,EAC5Ce,EAAaf,EAAY,eAAe,EAExCgB,EAAmB,KAAK,eAAe,gBAAkBF,GAAY,UAAYD,EAAK,YAAY,QAClGI,EAAmB,KAAK,eAAe,gBAAkBF,GAAY,UAAYF,EAAK,QAAQ,QAEpG,GAAI,CACIG,GACA,MAAM,KAAK,kBAAkB,EAE7BC,GACA,MAAM,KAAK,kBAAkB,CAErC,MAAY,CAAC,CACjB,EAEAjB,EAAY,iBAAiB,eAAgB,KAAK,eAAe,EACrE,CAEQ,8BAA+B,CAC/B,KAAK,iBACLA,EAAY,oBAAoB,eAAgB,KAAK,eAAe,CAE5E,CAEA,MAAc,kBAAkBQ,EAAqC,CACjE,GAAI,CACA,IAAMU,EAAUV,EAAS,SAAW,QAC9BW,EAAaX,GAAW,MAAMR,EAAY,cAAc,CAAC,CAAC,KAAK,QAAS,KAAK,UAAU,EAI7F,GAHA,KAAK,kBAAkB,KAAK,EAC5B,KAAK,iBAAmBmB,EAAW,eAAe,EAAE,CAAC,EAEjD,CAAC,KAAK,QAENC,GAAsBD,CAAU,MAC7B,CACE5B,EAAO,qBACR,MAAM,KAAK,sBAAsB,EAErC,IAAM8B,EAAW,MAAM,KAAK,WAAW,KAAK,QAAS,KAAK,gBAAgB,EAC1EC,EAAO,IAAIC,EAAQ,eAAgBL,CAAO,EAC1CM,EAAM,IAAI,sBAAsB,EAChC,MAAM,KAAK,mBAAmBH,CAAQ,EACtC,KAAK,eAAe,eAAiB,GACrC,KAAK,cAAc,iBAAiC,CAAE,KAAM,OAAqB,CAAC,CACtF,CACJ,OAASI,EAAG,CACR,MAAAH,EAAO,IAAIC,EAAQ,MAAO,cAAc,EACxCC,EAAM,KAAK,uBAAwBC,CAAC,EAC9BA,CACV,CACJ,CAMA,MAAM,eAAejB,EAAoC,CACrD,OAAO,KAAK,kBAAkBA,CAAM,CACxC,CAEA,MAAc,kBAAkBA,EAA6B,KAAqB,CAC9E,GAAI,CACA,IAAMW,EAAaX,GAAW,MAAMR,EAAY,aAAa,EAG7D,GAFA,KAAK,gBAAgB,KAAK,EAC1B,KAAK,eAAiBmB,EAAW,eAAe,EAAE,CAAC,EAC/C,CAAC,KAAK,QAENC,GAAsBD,CAAU,MAC7B,CACH,IAAME,EAAY,MAAM,KAAK,kBAAkB,EAC/CC,EAAO,IAAIC,EAAQ,eAAgB,OAAO,EAC1CC,EAAM,IAAI,uBAAwBH,CAAQ,EAC1C,MAAM,KAAK,mBAAmBA,CAAQ,EACtC,KAAK,eAAe,eAAiB,GACrC,KAAK,cAAc,iBAAiC,CAAE,KAAM,OAAqB,CAAC,CACtF,CACJ,OAASI,EAAG,CACR,MAAAH,EAAO,IAAIC,EAAQ,MAAO,cAAc,EACxCC,EAAM,MAAM,2BAA4BC,CAAC,EACnCA,CACV,CACJ,CAEA,MAAc,cAAcC,EAA0BC,EAAqBnB,EAAqC,CAC5G,GAAI,CAGA,GAFAA,EAASA,GAAW,MAAMR,EAAY,eAAe0B,EAAiBC,CAAU,EAE5E,CAAC,KAAK,QAENP,GAAsBZ,CAAM,MACzB,CACH,IAAMa,EAAWb,EAAO,eAAe,EAAE,CAAC,EAsC1C,GAnCAa,EAAS,iBACL,QACA,IAAM,CAEE,KAAK,eAAe,wBACpB,KAAK,uBAAuB,CAEpC,EACA,EACJ,EAEK9B,EAAO,qBAER,KAAK,YAAY,EAErB+B,EAAO,IAAIC,EAAQ,eAAgB,QAAQ,EAC3CC,EAAM,IAAI,0BAA0B,EAEpC,KAAK,aAAeH,EACpB,KAAK,eAAe,uBAAyB,GAC7C,KAAK,eAAe,2BAA6BK,EAE5CnC,EAAO,sBACR,KAAK,qCAAuC,KAAK,eAAe,eAChE,KAAK,eAAe,eAAiB,GAErC,KAAK,gBAAkBA,EAAO,0BAA4BS,EAAY,mBAAmBT,EAAO,cAAeA,EAAO,cAAc,EAAI8B,EACxI,MAAM,KAAK,mBAAmBA,EAAU,KAAK,eAAe,GAG5D9B,EAAO,yBAA2B,KAAK,eAAe,6BACtD8B,EAAS,YAAc,SACvB,KAAK,kBAAoBA,GAGzBb,EAAO,eAAe,EAAE,OAAS,EAAG,CACpC,IAAMoB,EAAmBpB,EAAO,eAAe,EAAE,CAAC,EAClDoB,EAAiB,YAAc,QAC/B,KAAK,iBAAmBA,EACxB,MAAM,KAAK,mBAAmBA,CAAgB,EAE9C,KAAK,eAAe,sBAAwB,EAChD,CAEID,GAAc,CAAC,KAAK,eAAe,uBACnCH,EAAM,MAAM,wCAAwC,EAGxD,KAAK,cAAc,gBAAgC,CAAE,MAAOH,CAAS,CAAC,EACtE,KAAK,cAAc,iBAAiC,CAAE,KAAM,QAAsB,CAAC,CACvF,CACJ,OAASI,EAAG,CACR,MAAAH,EAAO,IAAIC,EAAQ,MAAO,QAAQ,EAClCC,EAAM,KAAK,0BAA2BC,CAAC,EACjCA,CACV,CACJ,CAEA,MAAc,uBAAwB,CAC9B,KAAK,kBACL,KAAK,gBAAgB,KAAK,EAC1B,KAAK,gBAAkB,MAEvB,KAAK,eACL,KAAK,aAAa,KAAK,EACvB,KAAK,aAAe,MAEpB,KAAK,oBACL,KAAK,kBAAkB,KAAK,EAC5B,KAAK,kBAAoB,KAAK,yBAAyB,GAE3D,MAAM,KAAK,oBAAoB,EAE3B,KAAK,eAAe,yBACpB,KAAK,eAAe,uBAAyB,GAC7C,KAAK,eAAe,2BAA6B,GACjD,KAAK,cAAc,gBAAgC,CAAE,MAAO,IAAK,CAAC,EAClE,KAAK,cAAc,iBAAiC,CAAE,KAAM,QAAsB,CAAC,EAE3F,CAGA,MAAc,mBAAoB,CAC9B,MAAM,KAAK,oBAAoB,EAC/B,KAAK,cAAc,gBAAgC,CAAE,MAAO,IAAK,CAAC,EAClE,KAAK,cAAc,iBAAiC,CAAE,KAAM,YAA0B,CAAC,CAC3F,CAEA,MAAc,qBAAsB,CAChC,GAAI,KAAK,iBAAkB,CACvB,KAAK,iBAAiB,KAAK,EAC3B,IAAMJ,EAAW,KAAK,yBAAyB,EAC/C,MAAM,KAAK,mBAAmBA,CAAQ,EACtC,KAAK,eAAe,sBAAwB,EAChD,CACJ,CAEA,MAAc,mBAAoB,CAC9B,GAAI,CAAC9B,EAAO,cAAgB,CAAC,KAAK,mBAC9B,OAAAA,EAAO,cAAc,MAAM,EACpB,KAAK,eAGXA,EAAO,aAAa,eACrB,MAAMA,EAAO,aAAa,KAAK,EAGnCA,EAAO,aAAa,OAAO,EAE3BA,EAAO,aAAa,WAAW,KAAK,mBAAmB,QAAS,KAAK,mBAAmB,QAAQ,EAChGA,EAAO,aAAa,UAAU,KAAK,cAAc,EACjD,IAAMsC,EAAqBtC,EAAO,aAAa,aAA6B,eAAe,EAAE,CAAC,EAC9F,OAAI,CAAC,KAAK,oBAAsB,KAAK,mBAAmB,KAAOsC,EAAkB,MAC7E,KAAK,mBAAqBA,GAEvB,KAAK,kBAChB,CAEU,0BAA2B,CACjC,IAAMR,EAAWrB,EAAY,oBAAoB,EACjD,OAAAqB,EAAS,YAAc,QACvBA,EAAS,KAAK,EACPA,CACX,CAEU,0BAA2B,CACjC,IAAMA,EAAWrB,EAAY,mBAAmB,EAChD,OAAAqB,EAAS,YAAc,SACvBA,EAAS,KAAK,EACPA,CACX,CAEA,MAAgB,mBAAmBA,EAA4BS,EAA8B,CACzF,GAAI,CAAC,KAAK,QACN,OAGJ,IAAMC,EAAW,KAAK,QAAQ,UAAU,EAAE,KAAMtC,GAAUA,EAAM,OAAS4B,EAAS,MAAQ5B,EAAM,cAAgB4B,EAAS,WAAW,EAGhIU,GAAU,KAAOV,EAAS,KAI1BU,GAEIA,IAAa,KAAK,oBAClBA,EAAS,KAAK,EAElB,KAAK,SAAS,YAAYA,CAAQ,EAClC,KAAK,SAAS,SAASV,CAAQ,EAC/B,KAAK,cAAc,iBAAiCA,EAAUS,CAAS,IAGvE,KAAK,QAAQ,SAAST,CAAQ,EAC9B,KAAK,cAAc,iBAAiCA,EAAUS,CAAS,GAE/E,CAEA,MAAc,WAAWE,EAAwBvC,EAAoD,CAGjG,GAFA,KAAK,yBAAyB,MAAMF,EAAO,YAAY,EAEnD,CAACA,EAAO,aACR,OAAOE,EAEX,GAAI,CACA,OAAOF,EAAO,aAAa,UAAUyC,EAAQvC,CAAK,CACtD,OAASgC,EAAG,CACR,OAAAD,EAAM,KAAK,sBAAuBC,CAAC,EAC5BhC,CACX,CACJ,CAEQ,aAAc,CAClB,GAAKF,EAAO,aAGZ,GAAI,CACAA,EAAO,aAAa,WAAW,CACnC,OAAS,EAAG,CACRiC,EAAM,KAAK,sBAAuB,CAAC,CACvC,CACJ,CAEA,SAAgB,CACZ,KAAK,6BAA6B,EAC9BjC,EAAO,eACP,KAAK,QAAU,KACfA,EAAO,aAAa,QAAQ,GAE5BA,EAAO,cACPA,EAAO,aAAa,QAAQ,EAE5B,KAAK,UACL6B,GAAsB,KAAK,OAAO,EAClC,KAAK,QAAU,MAEnB,KAAK,kBAAkB,KAAK,EAC5B,KAAK,gBAAgB,KAAK,EAC1B,KAAK,oBAAoB,KAAK,EAC9B,KAAK,sBAAsB,EAENpB,EAAY,gBAAgB,GACnC,QAAQ,EAAE,MAAOyB,GAAMD,EAAM,MAAMC,CAAC,CAAC,EACnD,KAAK,yBAAyB,QAAQ,CAC1C,CAEA,MAAM,sBAAsBQ,EAAiC,CACzD,GAAIA,EAAS,cAAe,CACxB,MAAM,KAAK,cAAcA,EAAS,kBAAmBA,EAAS,YAAY,EAC1E,MACJ,CACA,OAAI1C,EAAO,oBACA,KAAK,sBAAsB,GAEjC0C,EAAS,cACV,MAAM,KAAK,kBAAkB,EAE7B,KAAK,qCACE,KAAK,kBAAkB,EAE3B,KAAK,YAAY,EAAK,EACjC,CAEA,MAAM,wBAAyB,CAC3B,OAAO,KAAK,sBAAsB,CAC9B,cAAe,GACf,kBAAmB,GACnB,aAAc,EAClB,CAAC,CACL,CAQA,MAAM,YAAYC,EAAkB,CAChC,GAAI,CAAC,KAAK,QACN,OAGC3C,EAAO,qBACR,MAAM,KAAK,sBAAsB,EAGrC,KAAK,kBAAkB,KAAK,EAE5B,IAAI8B,EACJ,GAAIa,EAAS,CACT,IAAM1B,EAAS,MAAMR,EAAY,cAAc,CAAC,CAAC,KAAK,QAAS,KAAK,UAAU,EAC9E,KAAK,iBAAmBQ,EAAO,eAAe,EAAE,CAAC,EACjDa,EAAW,MAAM,KAAK,WAAW,KAAK,QAAS,KAAK,gBAAgB,CACxE,MACIA,EAAWrB,EAAY,mBAAmBT,EAAO,cAAeA,EAAO,cAAc,EACrF,KAAK,YAAY,EAMrB,GAHA,KAAK,eAAe,eAAiB2C,EACrC,MAAM,KAAK,mBAAmBb,CAAQ,EAElC,KAAK,gBAAiB,CAEtB,KAAK,cAAc,iBAAiC,CAACa,CAAO,EAC5D,MACJ,CAEA,KAAK,cAAc,iBAAiC,CAAE,KAAM,OAAqB,CAAC,CACtF,CAEA,MAAM,YAAYA,EAAkB,CAChC,GAAI,CAAC,KAAK,QACN,OAGJ,KAAK,gBAAgB,KAAK,EAE1B,IAAMC,EAAe,MAAO1C,EAAyB2C,IAAuB,CACxE,MAAM,KAAK,mBAAmB3C,CAAK,EACnC,KAAK,eAAe,eAAiB2C,EACrC,KAAK,cAAc,iBAAiC,CAAE,KAAM,OAAqB,CAAC,CACtF,EAEA,GAAIF,EACA,GAAI,CACA,IAAM1B,EAAS,MAAMR,EAAY,aAAa,EAC9C,KAAK,eAAiBQ,EAAO,eAAe,EAAE,CAAC,EAE/C2B,EAAc,MAAM,KAAK,kBAAkB,EAAwB,EAAI,CAC3E,OAASV,EAAY,CAIjB,MAHAlC,EAAO,cAAc,MAAM,EAC3B4C,EAAanC,EAAY,oBAAoB,EAAG,EAAK,EAEjD,OAAOyB,GAAM,SACP,IAAI,MAAMA,CAAC,EAEXA,CAEd,MAEAlC,EAAO,cAAc,MAAM,EAC3B4C,EAAanC,EAAY,oBAAoB,EAAG,EAAK,CAE7D,CAEA,uBAAuBkC,EAAkB,CACrC,KAAK,gBAAkBA,EAClB,KAAK,eAAe,gBAIrB,KAAK,cAAc,iBAAiCA,CAAO,CAEnE,CAEA,gBAAgBG,EAAkB,CAC9B,KAAK,eAAe,iBAAmBA,EACvC,KAAK,cAAc,iBAAiC,CAAE,KAAM,OAAqB,CAAC,CACtF,CAEA,MAAM,cAAc,CAAE,MAAA5B,EAAO,OAAAuB,CAAO,EAA2D,CAO3F,GALI,CAACzC,EAAO,qBAAuB,KAAK,eAAe,wBAKnD,CAAC,KAAK,eAAe,eACrB,OAGJ,GAAI,CAAC,KAAK,QACN,MAAM,IAAI,MAAM,wBAAwB,EAG5C,GAAI,CAAC,KAAK,iBACN,MAAM,IAAI,MAAM,6BAA6B,EAGjD,IAAM+C,EAAc,KAAK,SAAWN,GAAWvB,EAC/C,MAAM,KAAK,uBAAuB,KAAK,iBAAkB6B,CAAU,CACvE,CAEA,qBAAsB,CAClB,OAAO,KAAK,gBAChB,CAEA,MAAM,wBAAyB,CAC3B,GAAI,CAAC,KAAK,SAAW,CAAC,KAAK,eAAe,eACtC,OAGJ,IAAM7C,EAAQ,KAAK,QAAQ,eAAe,EAAE,KAAMY,GAAU,CAACA,EAAM,WAAW,EAC9E,GAAI,CAACZ,EACD,MAAM,IAAI,MAAM,6BAA6B,EAGjD,GAAKA,EAAM,QAIX,OAAOA,EAAM,iBAAiB,CAC1B,iBAAkBF,EAAO,gBAC7B,CAAC,CACL,CAEA,MAAM,YAAYyC,EAAwB,CACtC,GAAI,CAACzC,EAAO,aACR,MAAM,IAAI,MAAM,kCAAkC,EAGtD,GAAI,CAACA,EAAO,qBAAuB,KAAK,eAAe,uBACnD,MAAM,IAAI,MAAM,qCAAqC,EAMzD,GAFA+B,EAAO,IAAIC,EAAQ,eAAgB,UAAUS,GAAQ,QAAU,MAAM,EAAE,EAEnE,CAAC,KAAK,eAAe,eAAgB,CACrC,KAAK,QAAUA,EACf,MACJ,CAEA,GAAI,KAAK,SAAWA,IAAW,KAAK,SAAW,KAAK,iBAAkB,CAClE,IAAMO,EAAc,KAAK,QACzB,KAAK,QAAUP,EAEf,GAAI,CACA,IAAMvC,EAAQ,KAAK,iBAAiB,MAAM,EACpCe,EAAS,IAAI,YAAY,CAACf,CAAK,CAAC,EAEtC,MAAM,KAAK,uBAAuBA,CAAK,EAEvC,MAAM,KAAK,kBAAkBe,CAAM,CACvC,OAASiB,EAAG,CAER,KAAK,QAAUc,EAGf,IAAM9C,EAAQ,KAAK,iBAAiB,MAAM,EACpCe,EAAS,IAAI,YAAY,CAACf,CAAK,CAAC,EACtC,YAAM,KAAK,kBAAkBe,CAAM,EAC7BiB,CACV,CACJ,CACJ,CAEA,MAAM,YAAYe,EAA6C,CAC3D,GAAI,CAACjD,EAAO,aACR,MAAM,IAAI,MAAM,kCAAkC,EAGtD,GAAI,CAAC,KAAK,eAAe,eAAgB,CACrC,KAAK,mBAAqBiD,EAC1B,MACJ,CAEA,GACI,KAAK,UACH,CAACA,GAAqB,KAAK,oBACxBA,GAAqB,CAAC,KAAK,oBAC5B,CAACC,EAAM,eAAeD,GAAmB,SAAW,CAAC,EAAG,KAAK,oBAAoB,SAAW,CAAC,CAAC,IAClG,KAAK,eACP,CACE,IAAMD,EAAc,KAAK,mBACzB,KAAK,mBAAqBC,EAE1B,GAAI,CACA,IAAM/C,EAAQ,KAAK,eAAe,MAAM,EAClCe,EAAS,IAAI,YAAY,CAACf,CAAK,CAAC,EAGtC,MAAM,KAAK,kBAAkBe,CAAM,CACvC,OAASiB,EAAG,CAER,KAAK,mBAAqBc,EAG1B,IAAM9C,EAAQ,KAAK,eAAe,MAAM,EAClCe,EAAS,IAAI,YAAY,CAACf,CAAK,CAAC,EACtC,YAAM,KAAK,kBAAkBe,CAAM,EAC7BiB,CACV,CACJ,CACJ,CAEA,oBAA8C,CAC1C,OAAO,KAAK,gBAChB,CAEQ,yBAAyBiB,EAAkB,CAC3C,KAAK,eAAe,gBAAkB,KAAK,kBAAoBA,EAAWnD,EAAO,gBACjF,KAAK,uBAAuB,KAAK,gBAAgB,EAAE,MAAOkC,GAAM,CAC5DD,EAAM,KAAK,6CAA8CC,CAAC,CAC9D,CAAC,CAET,CAEA,IAAY,YAAa,CACrB,IAAMkB,EAAQ,KAAK,yBAAyB,UAAYpD,EAAO,eAC/D,OAAS,KAAK,QAAU,KAAK,IAAIoD,EAAOpD,EAAO,cAAc,EAAI,MACrE,CAEA,MAAc,uBAAuBE,EAAyBmD,EAAqC,CAC/F,MAAMC,GAAoBpD,EAAO,CAC7B,MAAO,KAAK,QAAUF,EAAO,oBAAsBA,EAAO,cAC1D,OAAQ,KAAK,QAAUA,EAAO,qBAAuBA,EAAO,eAC5D,GAAI,KAAK,YAAc,CAAE,UAAW,CAAE,MAAO,KAAK,UAAW,CAAE,EAC/D,GAAGqD,CACP,CAAC,CACL,CAEA,qBAA+C,CAC3C,OAAO,KAAK,iBAChB,CACJ,ECjyBO,IAAME,GAAN,KAA2B,CAA3B,cACHC,EAAA,KAAQ,2BACRA,EAAA,KAAQ,+BACRA,EAAA,KAAQ,aAER,OAAO,aAAc,CACjB,OAAOC,EAAY,YAAY,IAAM,WAAa,gBAAiB,WAAa,qBAAsB,MAC1G,CAEA,MAAM,KAAKC,EAAyB,CAChC,GAAI,CACA,GAAM,CAACC,EAAwBC,CAA0B,EAAI,MAAM,QAAQ,IAAI,CAC3E,UAAU,YAAY,MAAM,CACxB,KAAM,QACV,CAAC,EACD,UAAU,YAAY,MAAM,CACxB,KAAM,YACV,CAAC,CACL,CAAC,EAED,KAAK,wBAA0BD,EAC/B,KAAK,4BAA8BC,EACnC,KAAK,UAAYF,EAEjB,KAAK,wBAAwB,SAAYG,GAAO,KAAK,uBAAuBA,CAAE,EAC9E,KAAK,4BAA4B,SAAYA,GAAO,KAAK,uBAAuBA,CAAE,CACtF,OAASC,EAAO,CACZC,EAAM,KAAK,kCAAmCD,CAAK,CACvD,CACJ,CAEQ,uBAAuBD,EAAW,CACtC,IAAMG,EAAmBH,EAAG,OAC5B,GAAIG,aAA4B,iBAAkB,CAC9C,GAAM,CAAE,KAAAC,EAAM,MAAAC,CAAM,EAAIF,EACxB,OAAQC,EAAM,CACV,IAAK,gBACD,KAAK,UAAU,aAAcC,CAAK,EAClC,MACJ,IAAK,gBACD,KAAK,UAAU,SAAUA,CAAK,EAC9B,KACR,CACJ,CACJ,CAEA,mBAAmBC,EAAwC,CACvD,IAAIC,EAA0C,KAC9C,OAAQD,EAAQ,CACZ,IAAK,SACDC,EAAkB,KAAK,wBAAwB,MAC/C,MACJ,IAAK,aACDA,EAAkB,KAAK,4BAA4B,MACnD,KACR,CACA,OAAOA,CACX,CACJ,ECvCO,IAAKC,QACRA,EAAA,aAAe,eACfA,EAAA,eAAiB,iBACjBA,EAAA,QAAU,UACVA,EAAA,WAAa,aACbA,EAAA,UAAY,YACZA,EAAA,UAAY,YACZA,EAAA,MAAQ,QACRA,EAAA,OAAS,SACTA,EAAA,YAAc,cATNA,QAAA,IAYZ,SAASC,EAAMC,KAA+BC,EAAW,CACrD,IAAMC,EAAWC,EAAO,IAAIH,CAAM,EAC9B,OAAOE,GAAa,YACpB,WAAWA,EAAU,EAAG,GAAGD,CAAI,CAEvC,CAEA,SAASG,GAAwBJ,EAA4BK,KAAuCJ,EAAW,CAC3G,GAAIE,EAAO,iBACP,GAAI,MAAM,QAAQE,CAAO,GAErB,GADAA,EAAUA,EAAQ,OAAQC,GAAW,CAACA,EAAO,QAAQ,EACjD,CAACD,EAAQ,OACT,eAEGA,EAAQ,SACf,OAIRN,EAAMC,EAAQK,EAAS,GAAGJ,CAAI,CAClC,CAEA,SAASM,GAAUC,EAAc,CAC7B,OAAO,OAAO,OAAO,CAAC,EAAGA,CAAI,CACjC,CAEA,SAASC,GAAaD,EAAgB,CAClC,OAAOA,EAAK,MAAM,CACtB,CAMA,IAAUE,QAAV,CAOW,SAASC,EAAcC,EAA4BC,EAA8B,CACpFd,EAAM,gBAAiBa,EAAQL,GAAUM,CAAa,CAAC,CAC3D,CAFOH,GAAS,cAAAC,EAUT,SAASG,EAAeF,EAA4BC,EAA8B,CACrFd,EAAM,iBAAkBa,EAAQL,GAAUM,CAAa,CAAC,CAC5D,CAFOH,GAAS,eAAAI,EAUT,SAASC,EAAcH,EAA4BC,EAA8B,CACpFd,EAAM,gBAAiBa,EAAQL,GAAUM,CAAa,CAAC,CAC3D,CAFOH,GAAS,cAAAK,EAST,SAASC,EAAaC,EAAmB,CAC5ClB,EAAM,eAAgBkB,CAAK,CAC/B,CAFOP,GAAS,aAAAM,EAUT,SAASE,EAAoBL,EAA8BM,EAAsB,CACpFpB,EAAM,sBAAuBQ,GAAUM,CAAa,EAAGM,CAAI,CAC/D,CAFOT,GAAS,oBAAAQ,EAST,SAASE,EAAcC,EAA2B,CACrDC,EAAM,MAAM,gBAAiBD,CAAM,EACnCtB,EAAM,gBAAiBsB,CAAM,CACjC,CAHOX,GAAS,cAAAU,EAYT,SAASG,EAAejB,EAA+BM,EAA4B,CACtFR,GAAwB,iBAAkBE,EAAQM,CAAM,CAC5D,CAFOF,GAAS,eAAAa,EAWT,SAASC,EAAalB,EAA+BE,EAA0B,CAClFJ,GAAwB,eAAgBE,EAAQE,CAAI,CACxD,CAFOE,GAAS,aAAAc,EAWT,SAASC,EAAYnB,EAA+BE,EAA0B,CACjFJ,GAAwB,cAAeE,EAAQE,CAAI,CACvD,CAFOE,GAAS,YAAAe,EAUT,SAASC,EAAmBpB,EAA+BE,EAAyB,CACvFJ,GAAwB,qBAAsBE,EAAQE,CAAI,CAC9D,CAFOE,GAAS,mBAAAgB,EAUT,SAASC,EAAkBrB,EAA+BE,EAAyB,CACtFJ,GAAwB,oBAAqBE,EAAQE,CAAI,CAC7D,CAFOE,GAAS,kBAAAiB,EAWT,SAASC,EAAqBtB,EAA+BM,EAA4B,CAC5FR,GAAwB,uBAAwBE,EAAQM,CAAM,CAClE,CAFOF,GAAS,qBAAAkB,EAWT,SAASC,EAAoBvB,EAA+BM,EAA4B,CAC3FR,GAAwB,sBAAuBE,EAAQM,CAAM,CACjE,CAFOF,GAAS,oBAAAmB,EAWT,SAASC,EAAwBxB,EAA+ByB,EAAsBC,EAAoB,CAC7G5B,GAAwB,0BAA2BE,EAAQyB,EAAWC,CAAS,CACnF,CAFOtB,GAAS,wBAAAoB,EAaT,SAASG,EAAe3B,EAA+B4B,EAAgCC,EAAwBC,GAAqCC,GAAe,CACtKjC,GAAwB,iBAAkBE,EAAQC,GAAU2B,CAAc,EAAG3B,GAAU4B,CAAU,EAAGC,GAAcC,EAAK,CAC3H,CAFO3B,GAAS,eAAAuB,EAQT,SAASK,EAAmCC,EAAqC,CAChFA,GACAxC,EAAM,qCAAsCwC,CAAK,CAEzD,CAJO7B,GAAS,mCAAA4B,EAaT,SAASE,EAAsBlC,EAA+BO,EAA8B4B,EAAgD,CAC/IrC,GAAwB,wBAAyBE,EAAQC,GAAUM,CAAa,EAAG4B,CAAO,CAC9F,CAFO/B,GAAS,sBAAA8B,EAUT,SAASE,GAAqBpC,EAA+BO,EAA8B,CAC9FT,GAAwB,uBAAwBE,EAAQC,GAAUM,CAAa,CAAC,CACpF,CAFOH,GAAS,qBAAAgC,GAWT,SAASC,GAAwBrC,EAA+BsC,EAAmCC,EAAkB,CACxHzC,GAAwB,0BAA2BE,EAAQC,GAAUqC,CAAe,EAAGC,CAAM,CACjG,CAFOnC,GAAS,wBAAAiC,GAWT,SAASG,GAA+BxC,EAA+ByC,EAAiDF,EAAkB,CAC7IzC,GAAwB,iCAAkCE,EAAQC,GAAUwC,CAAsB,EAAGF,CAAM,CAC/G,CAFOnC,GAAS,+BAAAoC,GAWT,SAASE,EAAuB1C,EAA+BsC,EAAmCC,EAAkB,CACvHzC,GAAwB,yBAA0BE,EAAQC,GAAUqC,CAAe,EAAGC,CAAM,CAChG,CAFOnC,GAAS,uBAAAsC,EAWT,SAASC,GAA8B3C,EAA+ByC,EAAiDF,EAAkB,CAC5IzC,GAAwB,gCAAiCE,EAAQC,GAAUwC,CAAsB,EAAGF,CAAM,CAC9G,CAFOnC,GAAS,8BAAAuC,GAWT,SAASC,EAAkB5C,EAA+B6C,EAA+BN,EAAiB,CAC7GzC,GAAwB,oBAAqBE,EAAQ6C,EAAWN,CAAM,CAC1E,CAFOnC,GAAS,kBAAAwC,EAUT,SAASE,GAAmB9C,EAAoBmC,EAAgD,CACnGrC,GAAwB,qBAAsBE,EAAQmC,CAAO,CACjE,CAFO/B,GAAS,mBAAA0C,GAUT,SAASC,GAAoB/C,EAAoBmC,EAAgD,CACpGrC,GAAwB,sBAAuBE,EAAQmC,CAAO,CAClE,CAFO/B,GAAS,oBAAA2C,GAIT,SAASC,GAAwBC,EAA0CC,EAAkB,GAAO,CACvGzD,EAAM,0BAA2BQ,GAAUgD,CAAgB,EAAGC,CAAM,CACxE,CAFO9C,GAAS,wBAAA4C,GAWT,SAASG,GAAyBnD,EAA+BiD,EAA0Cd,EAAgD,CAC9JrC,GAAwB,2BAA4BE,EAAQC,GAAUgD,CAAgB,EAAGd,CAAO,CACpG,CAFO/B,GAAS,yBAAA+C,GAUT,SAASC,GAA0BC,EAAkCd,EAAkB,CAC1F9C,EAAM,4BAA6B4D,EAAWd,CAAM,CACxD,CAFOnC,GAAS,0BAAAgD,GAWT,SAASE,GAAevD,EAAkCgB,EAA2Bb,EAAY,KAAM,CAC1Gc,EAAM,MAAM,iBAAkBD,EAAQhB,CAAO,EAC7CD,GAAwB,iBAAkBC,EAASgB,EAAQb,CAAI,CACnE,CAHOE,GAAS,eAAAkD,GAQT,SAASC,IAAyB,CACrC9D,EAAM,wBAAwB,CAClC,CAFOW,GAAS,uBAAAmD,GAUT,SAASC,GAAmB7C,EAAmB8C,EAAiB,CACnEhE,EAAM,qBAAsBkB,EAAO8C,CAAQ,CAC/C,CAFOrD,GAAS,mBAAAoD,GAUT,SAASE,GAAgB1D,EAA+BmC,EAAgD,CAC3GrC,GAAwB,kBAAmBE,EAAQmC,CAAO,CAC9D,CAFO/B,GAAS,gBAAAsD,GAWT,SAASC,GAAYC,EAAuBC,EAA6BC,EAAgC,CAC5GrE,EAAM,cAAemE,EAAcC,EAAoB5D,GAAU6D,CAAY,CAAC,CAClF,CAFO1D,GAAS,YAAAuD,GAUT,SAASI,GAAiBC,EAA0BC,EAAkB,CACzExE,EAAM,mBAAoBuE,EAAaC,CAAO,CAClD,CAFO7D,GAAS,iBAAA2D,GAkBT,SAASG,GACZrC,EACAsC,EACAC,EACAC,GAAU,GACVC,GAAS,GACTtE,GAAuC,KACvCuE,GAAwC,KACxCC,GACAC,GACAlC,GAAwB,KAC1B,CACE,IAAMmC,GAAkBD,GAAiBtE,GAAUsE,EAAc,EAAI,OACrEhF,EAAM,eAAgBQ,GAAU4B,CAAU,EAAG1B,GAAUgE,CAAa,EAAGhE,GAAUiE,CAAY,EAAGC,GAASC,GAAQtE,GAAQuE,GAASC,GAAcE,GAAiBnC,EAAM,CAC3K,CAdOnC,GAAS,aAAA8D,GAuBT,SAASS,GAAe3E,EAAoB4E,EAAmBC,EAAY,GAAO,CACrF/E,GAAwB,iBAAkBE,EAAQG,GAAUyE,CAAK,EAAGC,CAAS,CACjF,CAFOzE,GAAS,eAAAuE,GAUT,SAASG,GAAoBF,EAAmBC,EAAY,GAAO,CACtEpF,EAAM,sBAAuBU,GAAUyE,CAAK,EAAGC,CAAS,CAC5D,CAFOzE,GAAS,oBAAA0E,GAYT,SAASC,GAAoB/E,EAA+BgF,EAAgB7C,EAAgDI,GAAwB,CACvJzC,GAAwB,sBAAuBE,EAAQgF,EAAO7C,EAASI,EAAM,CACjF,CAFOnC,GAAS,oBAAA2E,GAUT,SAASE,GAAWD,EAAgBzC,EAAwB,CAC/D9C,EAAM,aAAcuF,EAAOzC,CAAM,CACrC,CAFOnC,GAAS,WAAA6E,GAST,SAASC,GAAiBC,EAA+B,CAC5D1F,EAAM,mBAAoBU,GAAUgF,CAAO,CAAC,CAChD,CAFO/E,GAAS,iBAAA8E,GAOT,SAASE,IAAiB,CAC7B3F,EAAM,gBAAgB,CAC1B,CAFOW,GAAS,eAAAgF,GAST,SAASC,GAAerF,EAAoBsF,EAAuC,CACtFxF,GAAwB,iBAAkBE,EAAQsF,CAAY,CAClE,CAFOlF,GAAS,eAAAiF,GAIT,SAASE,IAAe,CAC3B9F,EAAM,cAAc,CACxB,CAFOW,GAAS,aAAAmF,GAST,SAASC,EAAiBxF,EAA+B,CAC5DF,GAAwB,mBAAoBE,CAAM,CACtD,CAFOI,GAAS,iBAAAoF,EAST,SAASC,GAAkBC,EAA2D,CACzFjG,EAAM,oBAAqBU,GAAUuF,CAAO,CAAC,CACjD,CAFOtF,GAAS,kBAAAqF,GAUT,SAASE,GAAcC,EAAgBC,EAAuB,CACjEpG,EAAM,gBAAiBmG,EAAQC,CAAY,CAC/C,CAFOzF,GAAS,cAAAuF,GAIT,SAASG,GAAaC,EAAoBC,EAAgB,CAC7DvG,EAAM,eAAgBsG,EAAWC,CAAM,CAC3C,CAFO5F,GAAS,aAAA0F,GAUT,SAASG,GAAS/F,EAAoBgG,EAA+B,CACxEzG,EAAM,WAAYS,EAAMgG,CAAc,CAC1C,CAFO9F,GAAS,SAAA6F,GAIT,SAASE,EAAwBrC,EAAgC,CACpErE,EAAM,0BAA2BQ,GAAU6D,CAAY,CAAC,CAC5D,CAFO1D,GAAS,wBAAA+F,EAOT,SAASC,GAAiB,CAC7B3G,EAAM,gBAAgB,CAC1B,CAFOW,GAAS,eAAAgG,EAOT,SAASC,EAAoBC,EAAqB,CACrD7G,EAAM,sBAAuB6G,CAAW,CAC5C,CAFOlG,GAAS,oBAAAiG,EAOT,SAASE,GAAiB,CAC7B9G,EAAM,gBAAgB,CAC1B,CAFOW,GAAS,eAAAmG,EAWT,SAASC,EAAcC,EAAiBC,EAA6BC,EAAS,GAAO,CACxFlH,EAAM,gBAAiBgH,EAASC,EAAMC,CAAM,CAChD,CAFOvG,GAAS,cAAAoG,EAWT,SAASI,EAAa1G,EAAkBwG,EAA6BC,EAAS,GAAO,CACxFlH,EAAM,eAAgBS,EAAMwG,EAAMC,CAAM,CAC5C,CAFOvG,GAAS,aAAAwG,EAeT,SAASC,EACZC,EACAC,EACAC,EACAC,GACAC,GACAC,GACA5E,GAAwB,KAC1B,CACE9C,EAAM,kBAAmBqH,EAAWC,EAASC,EAAWC,GAAMC,GAAiBC,GAAiB5E,EAAM,CAC1G,CAVOnC,GAAS,gBAAAyG,EAgBT,SAASO,EAAgB7E,EAAwB,KAAM8E,EAAsC,CAChG5H,EAAM,kBAAmB8C,EAAQ8E,CAAM,CAC3C,CAFOjH,GAAS,gBAAAgH,EAST,SAASE,EAA4BC,EAAgB,CACxD9H,EAAM,8BAA+B8H,CAAM,CAC/C,CAFOnH,GAAS,4BAAAkH,EAST,SAASE,GAAuBzG,EAA0D,CAC7FtB,EAAM,yBAA0BsB,CAAM,CAC1C,CAFOX,GAAS,uBAAAoH,GAUT,SAASC,EAAeR,KAA2BtH,EAAa,CACnEF,EAAM,iBAAkBwH,EAAM,GAAGtH,CAAI,CACzC,CAFOS,GAAS,eAAAqH,EAUT,SAASC,GAAaC,EAAwBC,EAAgC,CACjF,IAAMjI,EAAO,OAAO,OAAO,CAAC,EAAGgI,EAAY,CAAE,OAAAC,CAAO,CAAC,EACrDnI,EAAM,eAAgBE,CAAI,CAC9B,CAHOS,GAAS,aAAAsH,GAQT,SAASG,IAAkB,CAC9BpI,EAAM,iBAAiB,CAC3B,CAFOW,GAAS,gBAAAyH,GAaT,SAASC,GACZC,EACAC,EACAC,EACAC,GACAC,GACF,CACE1I,EAAM,oBAAqBsI,EAAWC,EAAYC,EAAmBC,GAAqBC,EAAqB,CACnH,CARO/H,GAAS,kBAAA0H,GAeT,SAASM,GAAWC,EAAkB,CACzC5I,EAAM,aAAc4I,CAAO,CAC/B,CAFOjI,GAAS,WAAAgI,GAST,SAASE,GAAyBhI,EAAqB,CAC1Db,EAAM,2BAA4Ba,CAAM,CAC5C,CAFOF,GAAS,yBAAAkI,GAQT,SAASC,GAAkBC,EAAyB,CACvD/I,EAAM,oBAAqB+I,CAAQ,CACvC,CAFOpI,GAAS,kBAAAmI,GAQT,SAASE,GAAeC,EAAuD,CAClFjJ,EAAM,iBAAkBiJ,CAAO,CACnC,CAFOtI,GAAS,eAAAqI,GAWT,SAASE,GAAcC,EAA8BrG,EAAgBsG,EAAmBC,GAA4B,CACvHrJ,EAAM,gBAAiBmJ,EAAYrG,EAAQsG,EAAMC,EAAU,CAC/D,CAFO1I,GAAS,cAAAuI,GAQT,SAASI,GAA0BC,EAA+B,CACrEvJ,EAAM,4BAA6BuJ,CAAM,CAC7C,CAFO5I,GAAS,0BAAA2I,GAQT,SAASE,GAAe1G,EAAuB,CAClD9C,EAAM,iBAAkB8C,CAAM,CAClC,CAFOnC,GAAS,eAAA6I,GAQT,SAASC,GAAY3G,EAAuB,CAC/C9C,EAAM,cAAe8C,CAAM,CAC/B,CAFOnC,GAAS,YAAA8I,GAOT,SAASC,GAAWC,EAA+B7G,EAAwB,KAAM,CACpF9C,EAAM,aAAc2J,EAAU7G,CAAM,CACxC,CAFOnC,GAAS,WAAA+I,GAST,SAASE,GAAyBC,EAAmC,CACxE7J,EAAM,2BAA4B6J,CAAe,CACrD,CAFOlJ,GAAS,yBAAAiJ,GAQT,SAASE,GAAyBC,EAAmC,CACxE/J,EAAM,2BAA4B+J,CAAU,CAChD,CAFOpJ,GAAS,yBAAAmJ,GAST,SAASE,GAASvJ,EAAuBqC,EAAuB,CACnE9C,EAAM,WAAYS,EAAMqC,CAAM,CAClC,CAFOnC,GAAS,SAAAqJ,GAUT,SAASC,GAAaC,EAAoC5C,EAAiBxE,EAAuB,CACrG9C,EAAM,eAAgBkK,EAAa5C,EAASxE,CAAM,CACtD,CAFOnC,GAAS,aAAAsJ,GAQT,SAASE,GAAarH,EAAuB,CAChD9C,EAAM,eAAgB8C,CAAM,CAChC,CAFOnC,GAAS,aAAAwJ,GAIT,SAASC,GAAmBC,EAA2BC,EAAcC,EAAmBC,GAAkB,CAC7GxK,EAAM,qBAAsBqK,EAAIC,EAAMC,EAAWC,EAAQ,CAC7D,CAFO7J,GAAS,mBAAAyJ,GAST,SAASK,GAAuBC,EAA+BC,EAA8B,CAChG3K,EAAM,yBAA0B0K,EAAQC,CAAK,CACjD,CAFOhK,GAAS,uBAAA8J,GAIT,SAASG,GAAsBC,EAAmB,CACrD7K,EAAM,wBAAyB6K,CAAS,CAC5C,CAFOlK,GAAS,sBAAAiK,GAOT,SAASE,GAAmB9D,EAAoC,CACnEhH,EAAM,qBAAsB,OAAOgH,GAAY,SAAWA,EAAUxG,GAAUwG,CAAO,CAAC,CAC1F,CAFOrG,GAAS,mBAAAmK,GAST,SAASC,GAAoBC,EAA2C,CAC3EhL,EAAM,sBAAuBgL,CAAkB,CACnD,CAFOrK,GAAS,oBAAAoK,GAOT,SAASE,IAAmB,CAC/BjL,EAAM,kBAAkB,CAC5B,CAFOW,GAAS,iBAAAsK,KAzxBVtK,QAAA,KA8xBV,IAAOuK,EAAQvK,GCl2Bf,IAAMwK,GAAY,UAMZC,IAA2B,IAAM,CACnC,GAAI,CACA,IAAMC,EAAa,KAAK,IAAI,EAAE,SAAS,EACnCC,EAAc,OAAO,aACrBC,EAAM,GACV,OAAAD,EAAG,QAAQD,EAAIA,CAAE,EACjBE,EAAMD,EAAG,QAAQD,CAAE,IAAMA,EACzBC,EAAG,WAAWD,CAAE,EACTE,EAAMD,EAAK,IACtB,MAAoB,CAChB,OAAO,IACX,CACJ,GAAG,EAMH,SAASE,GAASC,EAAyD,CACvE,IAAMC,EAAON,GAAUA,GAAQ,QAAQD,GAAYM,CAAI,EAAI,KAC3D,GAAIC,IAAS,KACT,OAAO,KAGX,GAAI,CACA,OAAO,KAAK,MAAMA,CAAI,CAC1B,MAAY,CACR,OAAO,IACX,CACJ,CAMA,SAASC,GAASF,EAAcG,EAA2C,CACvE,GAAI,CACIR,IACAA,GAAQ,QAAQD,GAAYM,EAAM,KAAK,UAAUG,CAAK,CAAC,CAE/D,MAAY,CAEZ,CACJ,CAMA,SAASC,GAAYJ,EAAc,CAC3BL,IACAA,GAAQ,WAAWD,GAAYM,CAAI,CAE3C,CAEA,IAAUK,OAAV,CACW,SAASC,EAAIN,EAAyD,CACzE,OAAOD,GAASC,CAAI,GAAK,IAC7B,CAFOK,EAAS,IAAAC,EAIT,SAASC,EAAIP,EAAcG,EAA2C,CACzED,GAASF,EAAMG,CAAK,CACxB,CAFOE,EAAS,IAAAE,EAIT,SAASC,EAAOR,EAAc,CACjCI,GAAYJ,CAAI,CACpB,CAFOK,EAAS,OAAAG,IATVH,QAAA,KAcV,IAAOI,GAAQJ,GCnEf,IAAIK,GAA8D,KAC9DC,GAA6C,KAC7CC,GAAqD,KACrDC,GAA8B,CAAC,EAC/BC,GAAkC,CAAC,EACnCC,GAA6B,CAAC,EAC9BC,GAAoC,KACpCC,GAAoC,KACpCC,GAAuC,KACvCC,GAA2B,GAC3BC,GAA+B,GAC/BC,GACAC,GACAC,GACAC,GAA4B,KAC5BC,GAAM,GACNC,GAA4B,KAC5BC,GAAsB,CAAC,EACvBC,GAAqC,KAEnCC,GAAK,UAAU,WACjBC,GAAK,UAAU,QACfC,GAAK,UAAU,UAEbC,GAAwD,CAAC,EAKnDC,QAIRA,EAAA,KAAO,OAIPA,EAAA,YAAc,cARNA,QAAA,KAiBKA,GAAV,CACI,SAASC,EAASC,EAA2B,CAChD,OAAO,OAAO,OAAOF,CAAU,EAAE,SAASE,CAAkB,CAChE,CAFOF,EAAS,SAAAC,IADHD,QAAA,KA0BjB,IAAMG,GAAN,KAAuB,CAOnB,YACIC,EACAC,EAAkC,GAClCC,EAAgBC,EAAO,cACvBC,EAAiBD,EAAO,eACxBE,EAAYF,EAAO,eACrB,CAZFG,EAAA,KAAU,SACVA,EAAA,KAAU,SACVA,EAAA,KAAiB,aACjBA,EAAA,KAAQ,0BACRA,EAAA,KAAiB,wBA+MjBA,EAAA,wBAAmB,IAAe,KAAK,WAtMnC,KAAK,qBAAuB,UAAU,aAAa,wBAAwB,EAC3E,IAAIC,EAAsC,GAE1C,GAAIP,EAAe,CACfO,EAAK,CACD,iBAAkBJ,EAAO,iBACzB,iBAAkB,GAClB,gBAAiB,EACrB,EAEA,IAAMK,EAAcC,GAAY,eAAe,EAC3CC,EACAC,EAKJ,GAJI/B,KACA+B,EAAW/B,GAAU,QACrB8B,EAAS9B,GAAU,UAEnB,OAAOoB,GAAkB,SAEzBW,EADoBH,EAAY,KAAMI,GAAQA,EAAI,WAAaZ,CAAa,GACpD,QACxBU,EAASV,UACF,CAACpB,IAAa6B,GAAY,GAAG,IAAM,SAGtCD,EAAY,KAAMI,GAAQA,EAAI,MAAM,SAAS,QAAQ,CAAC,EAAG,CAEzD,IAAMC,EAAYL,EAAY,KAAMI,GAAQ,CAACA,EAAI,MAAM,SAAS,SAAS,GAAK,CAACA,EAAI,MAAM,SAAS,QAAQ,CAAC,EACvGC,IACAF,EAAWE,EAAU,QACrBH,EAASG,EAAU,SAE3B,CAIAF,GAAY,KAAK,qBAAqB,QAEtCJ,EAAG,QAAU,CAAE,MAAOI,CAAS,EACxBD,IACPH,EAAG,SAAW,CAAE,MAAOG,CAAO,EAEtC,CAEA,IAAII,EAAsC,GAC1C,GAAIb,EAAe,CACfa,EAAK,CACD,MAAO,CAAE,IAAKX,EAAO,cAAe,IAAKD,EAAe,MAAOA,CAAc,EAC7E,OAAQ,CAAE,IAAKC,EAAO,eAAgB,IAAKC,EAAgB,MAAOA,CAAe,EACjF,YAAa,CAAE,MAAOD,EAAO,gBAAiB,EAC9C,UAAW,CAAE,MAAOE,CAAU,CAClC,EAEA,IAAMU,EAAUN,GAAY,WAAW,EACnCO,EACAC,EAKJ,GAJItC,KACAsC,EAAWtC,GAAU,QACrBqC,EAASrC,GAAU,UAEnB,OAAOsB,GAAkB,SAEzBgB,EADoBF,EAAQ,KAAMG,GAAQA,EAAI,WAAajB,CAAa,GAChD,QACxBe,EAASf,UACF,CAACtB,IAAa8B,GAAY,GAAG,IAAM,SAGtCM,EAAQ,KAAMG,GAAQA,EAAI,MAAM,SAAS,QAAQ,CAAC,EAAG,CAErD,IAAMC,EAAeJ,EAAQ,KAAMG,GAAQ,CAACA,EAAI,MAAM,SAAS,SAAS,GAAK,CAACA,EAAI,MAAM,SAAS,QAAQ,CAAC,EACtGC,IACAF,EAAWE,EAAa,QACxBH,EAASG,EAAa,SAE9B,CAIAF,GAAY,KAAK,qBAAqB,QACtCH,EAAG,QAAU,CAAE,MAAOG,CAAS,EACxBD,IACPF,EAAG,SAAW,CAAE,MAAOE,CAAO,GAG9Bb,EAAO,kBACPW,EAAG,WAAa,CAAE,MAAOX,EAAO,eAAgB,EAChD,OAAOW,EAAG,SACV,OAAOA,EAAG,QAElB,CAEA,KAAK,MAAQP,EACb,KAAK,MAAQO,EACb,KAAK,UAAY,CAAC,CAACA,EACnB,KAAK,uBAAyB,EAClC,CAKA,WAAoC,CAChC,OAAO,OAAO,OAAO,CAAC,EAAG,CAAE,MAAO,KAAK,MAAO,MAAO,KAAK,KAAM,CAAC,CACrE,CAMA,UAA6B,CACzB,OAAI,OAAO,KAAK,OAAU,WAClB,KAAK,MAAM,OAAS,KAAK,MAAM,QAC/B,OAAO,KAAK,MAAM,MAClB,OAAO,KAAK,MAAM,QACX,KAAK,MAAM,YAClB,OAAO,KAAK,MAAM,YACX,KAAK,MAAM,UAClB,OAAO,KAAK,MAAM,WACX,KAAK,MAAM,UAAY,KAAK,MAAM,SAAW,KAAK,MAAM,cAC/D,OAAO,KAAK,MAAM,SAClB,OAAO,KAAK,MAAM,QAClB,OAAO,KAAK,MAAM,aAItB,OAAO,KAAK,OAAU,WAClB,KAAK,MAAM,kBAAoB,KAAK,MAAM,iBAAmB,KAAK,MAAM,kBACxE,OAAO,KAAK,MAAM,iBAClB,OAAO,KAAK,MAAM,gBAClB,OAAO,KAAK,MAAM,mBACX,KAAK,MAAM,UAAY,KAAK,MAAM,WACzC,OAAO,KAAK,MAAM,SAClB,OAAO,KAAK,MAAM,UAKtB,KAAK,QAAU,IAAQ,KAAK,QAAU,GACtC,KAAK,MAAQ,GACN,KAAK,QAAU,IAAS,KAAK,QAAU,IAE9C,KAAK,MAAQ,GAEb,KAAK,MAAQ,KAAK,WACX,KAAK,QAAU,IAAQ,KAAK,QAAU,KAC7C,KAAK,MAAQ,IAGb,KAAK,OAAS,CAAC,OAAO,KAAK,KAAK,KAAK,EAAE,SACvC,KAAK,MAAQ,IAEb,KAAK,OAAS,CAAC,OAAO,KAAK,KAAK,KAAK,EAAE,SACvC,KAAK,MAAQ,IAGb,CAAC,KAAK,OAAS,CAAC,KAAK,QAIrB,KAAK,uBAAyB,GAC9B,KAAK,MAAQ,CAAC,KAAK,iBAAiB,EACpC,KAAK,MAAQ,KAAK,iBAAiB,GAGhC,IACX,CAKA,aAAuB,CACnB,IAAMM,EACD,OAAO,KAAK,OAAU,WAClB,KAAK,MAAM,OAAS,KAAK,MAAM,QAAU,KAAK,MAAM,aAAe,KAAK,MAAM,WAAa,KAAK,MAAM,YAAc,KAAK,MAAM,UAAY,KAAK,MAAM,UAC3J,KAAK,MAMT,MAAO,CAAC,EAJH,OAAO,KAAK,OAAU,WAClB,KAAK,MAAM,UAAY,KAAK,MAAM,SAAW,KAAK,MAAM,kBAAoB,KAAK,MAAM,kBAAoB,KAAK,MAAM,kBAC3H,KAAK,OAEaA,IAAa,CAAC,KAAK,sBAC7C,CAKA,SAAmB,CACf,MAAO,CAAC,CAAC,KAAK,KAClB,CAKA,SAAmB,CACf,MAAO,CAAC,CAAC,KAAK,KAClB,CAMJ,EAUaC,GAAN,cAAgCtB,EAAiB,CAGpD,YAAYuB,EAAeC,EAAgBlB,EAAmBmB,EAAyB,CACnF,MAAM,GAAO,EAAI,EAHrBlB,EAAA,KAAS,qBAML,QAAK,kBAAoB,sBAAuB,OAAS,IAAI,kBAAsB,KAE/E,OAAO,KAAK,OAAU,UACtB,OAAO,KAAK,MAAM,SAClB,OAAO,KAAK,MAAM,QAClB,OAAO,KAAK,MAAM,YAClB,OAAO,KAAK,MAAM,UAClB,OAAO,KAAK,MAAM,YAElB,KAAK,MAAQ,CAAC,EAIlB,KAAK,MAAM,OAAS,SACpB,KAAK,MAAM,MAAQgB,EACnB,KAAK,MAAM,OAASC,EACpB,KAAK,MAAM,UAAYlB,EACvB,KAAK,MAAM,eAAiBF,EAAO,eAE/BM,GAAY,YAAY,IAAM,SAAU,CACxC,IAAMgB,EAAU,OAAOhB,GAAY,eAAe,CAAC,EAC/CgB,IAAY,IAEZ,KAAK,MAAM,MAAQ,CAAE,IAAKH,CAAM,EAChC,KAAK,MAAM,OAAS,CAAE,IAAKC,CAAO,GAC3BE,IAAY,KAEnB,OAAO,KAAK,MAAM,MAClB,OAAO,KAAK,MAAM,OAE1B,CAEID,IACA,KAAK,MAAQ,CACT,iBAAkB,GAClB,iBAAkB,GAClB,gBAAiB,EACrB,EAER,CAES,WAAoC,CACzC,OAAO,OAAO,OAAO,MAAM,UAAU,EAAG,CAAE,YAAa,UAAW,WAAY,KAAK,iBAAkB,CAAC,CAC1G,CACJ,EAMME,GAAN,MAAMA,EAAgB,CAAtB,cAIIpB,EAAA,KAAQ,UAAU,KAAK,MAAM,KAAK,OAAO,EAAI,KAAM,EAAI,GAEvD,MAAa,CACT,GAAIoB,GAAgB,QAChB,MAAAC,EAAO,IAAIC,EAAQ,MAAO,eAAe,EACzCC,EAAM,KAAK,2CAA2C,EAChD,IAAI,MAAM,qBAAqB,EAGzCH,GAAgB,QAAU,KAAK,OACnC,CAEA,MAAa,CACLA,GAAgB,UAAY,KAAK,UACjCA,GAAgB,QAAU,EAElC,CACJ,EAnBIpB,EAFEoB,GAEa,UAAU,GAF7B,IAAMI,GAANJ,GA6BA,eAAeK,IAAgC,CAE3ChD,GAA+B,GAC/BD,GAA2B,GAE3BT,GAA2B,KAG3B,IAAM2D,EAAgC,CAClC,OAAQvB,GAAY,eAAe,EACnC,WAAYA,GAAY,mBAAmB,EAC3C,OAAQA,GAAY,eAAe,CACvC,EACA,MAAMwB,GAAY,EAElBC,GAAW,eAAgBF,CAAI,EAC/BG,EAAS,eAAe,CAC5B,CAKA,SAASD,GAAWE,KAA0BC,EAAiB,CAC3D,GAAK1C,GAAeyC,CAAK,EAIzB,QAAWE,KAAM3C,GAAeyC,CAAK,EACjCE,EAAG,GAAGD,CAAI,CAElB,CAMA,eAAeJ,IAA0C,CACrD,OAAI5D,KAIA,CAAC,UAAU,cAAgB,CAAC,UAAU,aAAa,iBAC5C,CAAC,GAIR,CAACC,IAAyB,UAAU,aAAa,mBAIjDA,GAAwBiE,EAAM,SAASR,GAAgB5B,EAAO,qBAAqB,EACnF,UAAU,aAAa,iBAAiB,eAAgB7B,EAAqB,GAG7E,CAACC,IAAyBiE,GAAqB,YAAY,IAC3DjE,GAAwB,IAAIiE,GAC5B,MAAMjE,GAAsB,KAAK,CAACkE,EAAMC,IAAU,CAC9C,OAAQA,EAAO,CACX,IAAK,SACL,IAAK,SACDpE,KAAwB,EACxB,KACR,CACJ,CAAC,GAGGD,GAA2B,UAAU,aACxC,iBAAiB,EACjB,KAAMsE,GAAY,CACfnE,GAAWmE,EAAQ,OAAQC,GACnBA,EAAO,OAAS,cACZA,EAAO,QACP9D,GAA2B,IAExB,IAEJ,EACV,EAEDL,GAAekE,EAAQ,OAAQC,GACvBA,EAAO,OAAS,cACZA,EAAO,MACP7D,GAA+B,GACxB0B,GAAY,SAAS,GAAKA,GAAY,YAAY,IAAM,YAE/D1B,GAA+BD,IAE5B,IAEJ,EACV,EAEDJ,GAAUiE,EAAQ,OAAQC,GAAWA,EAAO,OAAS,aAAa,EAIlE,IAAMC,EAAclE,IAAW,UAAYmE,GAAa,IAAI,YAAY,EAClEC,EAAcnE,IAAW,UAAYkE,GAAa,IAAI,YAAY,EAClEE,EAAiBnE,IAAc,UAAYiE,GAAa,IAAI,aAAa,EAE/E,OAAAnE,GACIH,GAAS,KAAMoE,GACJA,EAAO,WAAaC,CAC9B,GAAK,KAEVjE,GACIH,GAAa,KAAMmE,GACRA,EAAO,WAAaG,CAC9B,GAAK,KAEVlE,GACIH,GAAQ,KAAMkE,GACHA,EAAO,WAAaI,CAC9B,GACDtE,GAAQ,CAAC,GACT,KAEJL,GAA2B,QAAQ,QAAQsE,CAAO,EAC3CA,CACX,CAAC,EACA,MAAM,KACHtE,GAA2B,KACpB,CAAC,EACX,GACT,CAKA,eAAe4E,IAA+B,CAC1C,GAAM,kBAAmB,UAIzB,GAAI,CAEA,GAAM,CAAE,gBAAAC,CAAgB,EAAI,MAAM,UAAU,cAAc,qBAAqB,CAAC,iBAAiB,CAAC,EAClG,GAAI,CAACA,EAAiB,CAClBrB,EAAM,KAAK,yBAAyB,EACpC,MACJ,CAGA,IAAMsB,EAAQ,SAASD,EAAgB,MAAM,GAAG,EAAE,CAAC,CAAC,EAEpD7D,GAAa,MAAM8D,CAAK,EAAI,KAAOA,CACvC,OAASC,EAAO,CACZvB,EAAM,KAAK,2BAA4BuB,CAAK,CAChD,CACJ,CAMA,SAASC,GAAoBC,EAAqB,CAC9C,GAAI3E,IAAaC,GACb,OAGJ,IAAM2E,EAAa,CAACZ,EAA4Ba,IAA4B,CACxE,IAAMC,EAAWD,EAAM,YAAY,GAAG,SACtC,OAAOb,EAAQ,KAAMC,GAAWA,EAAO,WAAaa,GAAYb,EAAO,QAAUY,EAAM,KAAK,GAAK,IACrG,EAEAF,GAAQ,UAAU,EAAE,QAASE,GAAU,CAC/B,CAAC5E,IAAa4E,EAAM,OAAS,QAC7B5E,GAAY2E,EAAW9C,GAAY,eAAe,EAAG+C,CAAK,EACnD,CAAC7E,IAAa6E,EAAM,OAAS,UACpC7E,GAAY4E,EAAW9C,GAAY,WAAW,EAAG+C,CAAK,EAE9D,CAAC,CACL,CAMA,eAAeE,GAAcC,EAAoCC,EAA8C,CAC3G/B,EAAM,MAAM,mBAAoB,KAAK,MAAM,KAAK,UAAU8B,EAAiB,UAAU,CAAC,CAAC,CAAC,EAExF,IAAME,GAAkB,CAACF,EAAiB,QAAQ,GAAKlD,GAAY,oBAAoB,KAAO,CAACkD,EAAiB,QAAQ,GAAKlD,GAAY,wBAAwB,GAE7J,CAACoD,GAAkB,CAACD,GACpBzB,EAAS,uBAAuB,EAGpC,IAAM2B,EAAiB,IAAIhC,GAE3B,GAAI,CACAgC,EAAe,KAAK,EACpB,IAAMR,EAAS,MAAM,UAAU,aAAa,aAAaK,EAAiB,UAAU,CAAC,EACrF,OAAAG,EAAe,KAAK,EAEfD,GACD,MAAM9B,GAAe,EAGzBsB,GAAoBC,CAAM,EACnBA,CACX,OAASS,EAAQ,CAKb,OAJAD,EAAe,KAAK,EAEpBjC,EAAM,MAAM,qBAAsBkC,CAAC,EAE3BA,EAAE,KAAM,CACZ,IAAK,wBACL,IAAK,2BACL,IAAK,kBACL,IAAK,gBACL,IAAK,eACL,IAAK,gBAEDH,EAAYD,EAAiB,iBAAiB,EAAIK,GAAW,kBAAoBA,GAAW,eAC5F,MAEJ,IAAK,uBAEDJ,EAAYI,GAAW,gBACvB,MAEJ,IAAK,YACDJ,EAAYI,GAAW,QACvB,MAEJ,IAAK,aACL,IAAK,mBAEDJ,EAAYD,EAAiB,iBAAiB,EAAIK,GAAW,cAAgBA,GAAW,WACxF,MAEJ,IAAK,QAID,GAAID,EAAE,UAAY,sBAAuB,CACrCH,EAAYD,EAAiB,iBAAiB,EAAIK,GAAW,cAAgBA,GAAW,WACxF,KACJ,CACR,CAEA,GAAIL,EAAiB,YAAY,EAC7B,OAAOD,GAAcC,EAAiB,SAAS,EAAGC,CAAS,EAG/D,IAAMR,EAAQQ,GAAaI,GAAW,QACtC,MAAA7B,EAAS,mBAAmBiB,EAAOW,CAAC,EAC9BX,CACV,CACJ,CAMA,eAAea,GAAiBN,EAA2D,CACvF9B,EAAM,MAAM,oBAAqB,KAAK,MAAM,KAAK,UAAU8B,EAAiB,UAAU,CAAC,CAAC,CAAC,EAEzF,IAAMG,EAAiB,IAAIhC,GAE3B,GAAI,CACAgC,EAAe,KAAK,EAEpB,IAAMR,EAAS,MAAM,UAAU,aAAa,gBAAgBK,EAAiB,UAAU,CAAC,EAClFH,EAAQF,GAAQ,eAAe,EAAE,CAAC,EACxC,GAAIE,EAAO,CACP,IAAMU,EAAiBV,EAAM,YAAY,GAAG,eAM5C,GALA3B,EAAM,MAAM,4BAA4B2B,EAAM,EAAE,KAAKU,CAAc,GAAG,EAEtEV,EAAM,YAAc,OAGhBG,EAAiB,oBACbO,IAAmB,WAAaA,IAAmB,UACnD,GAAI,CACAP,EAAiB,kBAAkB,iBAAiB,iBAAiB,CACzE,OAASI,EAAG,CAERlC,EAAM,KAAK,+BAAgCkC,CAAC,CAChD,CAGZ,CAEA,OAAOT,CACX,OAAS,EAAQ,CACb,OAAQ,EAAE,KAAM,CACZ,IAAK,wBACL,IAAK,kBACL,IAAK,gBAED,MAAMU,GAAW,kBAErB,QACI,MAAMA,GAAW,aACzB,CACJ,QAAE,CACEF,EAAe,KAAK,CACxB,CACJ,CAMA,SAASK,IAAkB,CACvB,OAAI7E,GAAa,SAIjBA,IAAgB,IAAM,CAClB,IAAI8E,EACAC,EAAgB,GAChBC,EAAgB,EAChBC,EAAa,IACXC,EAAI9E,GAAG,MAAM,8DAA8D,GAAK,CAAC,EAEvF,GAAI,WAAW,KAAK8E,EAAE,CAAC,CAAC,EACpB,OAAAJ,EAAM,kBAAkB,KAAK1E,EAAE,EACxB,CAAC,KAAO0E,GAAOA,EAAI,CAAC,GAAM,UAAWC,EAAeC,EAAeC,CAAU,EAGxF,GAAIC,EAAE,CAAC,IAAM,SAAU,CAGnB,GADAJ,EAAM1E,GAAG,MAAM,eAAe,EAC1B0E,EACA,MAAO,CAAC,OAAQA,EAAI,CAAC,GAAK,UAAWC,EAAeC,EAAeC,CAAU,EAKjF,GADAH,EAAM1E,GAAG,MAAM,gBAAgB,EAC3B0E,EACA,MAAO,CAAC,SAAUA,EAAI,CAAC,EAAG,GAAM,OAAOA,EAAI,CAAC,CAAC,EAAGG,CAAU,EAK9D,GADAH,EAAM1E,GAAG,MAAM,gBAAgB,EAC3B0E,EACA,MAAO,CAAC,UAAWA,EAAI,CAAC,EAAG,GAAOE,EAAeC,CAAU,EAK/D,GADAH,EAAM1E,GAAG,MAAM,oBAAoB,EAC/B0E,EACA,MAAO,CAAC,SAAUA,EAAI,CAAC,EAAG,GAAOE,EAAeC,CAAU,EAK9D,GADAH,EAAM1E,GAAG,MAAM,cAAc,EACzB0E,EACA,MAAO,CAAC,QAASA,EAAI,CAAC,EAAG,GAAOE,EAAeC,CAAU,CAEjE,CAEA,GAAIC,EAAE,CAAC,IAAM,SAAU,CAKnB,GAJAH,EAAgB,GAChBC,EAAgB,OAAOE,EAAE,CAAC,CAAC,EAE3BJ,EAAM1E,GAAG,MAAM,cAAc,EACzB0E,EACA,MAAO,CAAC,QAASA,EAAI,CAAC,GAAK,UAAWC,EAAeC,EAAeC,CAAU,EAIlF,GADAH,EAAM1E,GAAG,MAAM,oBAAoB,EAC/B0E,EACA,MAAO,CAAC,SAAUA,EAAI,CAAC,GAAK,UAAWC,EAAeC,EAAeC,CAAU,EAInF,GADAH,EAAM1E,GAAG,MAAM,6BAA6B,EACxC0E,EAEA,MAAO,CAAC,SAAUA,EAAI,CAAC,GAAK,UAAWC,EAAeC,EAAeC,CAAU,EAKnF,GADAH,EAAM1E,GAAG,MAAM,gBAAgB,EAC3B0E,EACA,MAAO,CAAC,OAAQA,EAAI,CAAC,GAAK,UAAWC,EAAeC,EAAeC,CAAU,EAIjF,GAAI,OAAQ,OAAe,IAAQ,KAAe,iBAAiB,KAAK,OAAO,SAAS,IAAI,EACxF,MAAO,CAAC,QAAS,SAAUF,EAAeC,EAAeC,CAAU,CAE3E,CAEA,OAAAH,EAAM1E,GAAG,MAAM,iCAAiC,EAC5C0E,GAAOA,EAAI,CAAC,IAAM,SAClBG,EAAaH,EAAI,CAAC,GAEf,CAACI,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAI/E,GAAK2E,GAAOA,EAAI,CAAC,GAAMI,EAAE,CAAC,GAAKhF,GAAI6E,EAAeC,EAAeC,CAAU,CACrG,GAAG,GAEIjF,EACX,CAEA,IAAUmB,QAAV,CAMI,eAAsBgE,GAAsB,CACxC,MAAMxC,GAAY,EAClB,MAAMgB,GAAc,CACxB,CAHAxC,GAAsB,KAAAgE,EAQf,SAASC,GAAgC,CAC5C,OAAOlG,EACX,CAFOiC,GAAS,WAAAiE,EAOT,SAASC,GAAoC,CAChD,OAAOlG,EACX,CAFOgC,GAAS,eAAAkE,EAOT,SAASC,GAA+B,CAC3C,OAAOlG,EACX,CAFO+B,GAAS,UAAAmE,EAOT,SAASC,GAAqB,CACjC,OAAOrG,GAAS,OAAS,CAC7B,CAFOiC,GAAS,UAAAoE,EAOT,SAASC,GAAyB,CACrC,OAAOrG,GAAa,OAAS,CACjC,CAFOgC,GAAS,cAAAqE,EAOT,SAASC,GAAyC,CACrD,OAAOpG,EACX,CAFO8B,GAAS,eAAAsE,EAOT,SAASC,GAA6C,CACzD,OAAOpG,EACX,CAFO6B,GAAS,mBAAAuE,EAOT,SAASC,GAAyC,CACrD,OAAOpG,EACX,CAFO4B,GAAS,eAAAwE,EAOT,SAASC,GAAwC,CACpD,OAAO/E,EAAO,eAClB,CAFOM,GAAS,mBAAAyE,EAOT,SAASC,GAA+B,CAC3C,OAAOrG,EACX,CAFO2B,GAAS,oBAAA0E,EAOT,SAASC,GAAmC,CAC/C,OAAOrG,EACX,CAFO0B,GAAS,wBAAA2E,EAIT,SAASC,GAA+B,CAC3C,OAAO9G,IAAuB,mBAAmB,YAAY,GAAK,IACtE,CAFOkC,GAAS,6BAAA4E,EAOT,SAASxB,EAAeyB,EAAY,GAAgB,CACvD,OAAKF,EAAwB,EAIzBP,EAAU,GAAKS,EACRH,EAAoB,EAGxB,GAPI,EAQf,CAVO1E,GAAS,eAAAoD,EAmBhB,eAAsB0B,EAAaD,EAAY,GAAOE,GAAY,GAAMC,GAAkB,GAA4B,CAClH,IAAMC,GAAQZ,EAAc,GAAKU,GAC3BG,GAAQd,EAAU,GAAKS,EACzBhC,EAEJ,GAAI,CAACoC,IAAS,CAACC,GAEXrC,EAAS,IAAI,gBAEb,IAAI,CACAA,EAAS,MAAMI,GAAc,IAAI3D,GAAiB2F,GAAOC,EAAK,CAAC,CACnE,MAAY,CACRrC,EAAS,IAAI,WACjB,CAGJ,MAAI,CAACA,EAAO,eAAe,EAAE,QAAUmC,IACnCnC,EAAO,SAAS7C,GAAY,mBAAmB,CAAC,EAGhD,CAAC6C,EAAO,eAAe,EAAE,QAAUmC,IACnCnC,EAAO,SAAS7C,GAAY,oBAAoB,CAAC,EAG9C6C,CACX,CAzBA7C,GAAsB,aAAA8E,EA8BtB,eAAsBK,EAAeC,EAA0BrE,GAA+C,CAC1G,IAAMF,GAAQuE,GAAmB,CAAC1F,EAAO,wBAA0BA,EAAO,qBAAuB,OAAO,OAAO,MACzGoB,GAASsE,GAAmB,CAAC1F,EAAO,wBAA0BA,EAAO,sBAAwB,OAAO,OAAO,OAC3GE,GAAYF,EAAO,mBAAmB0F,CAAe,EAC3D,OAAO5B,GAAiB,IAAI5C,GAAkBC,GAAOC,GAAQlB,GAAWmB,EAAc,CAAC,CAC3F,CALAf,GAAsB,eAAAmF,EAatB,eAAsBE,EAAcC,EAAgB,GAAO1F,GAA0C,CACjG,IAAMH,GAAgB6F,EAAgB5F,EAAO,oBAAsBA,EAAO,cACpEC,GAAiB2F,EAAgB5F,EAAO,qBAAuBA,EAAO,eAE5E,OAAOuD,GAAc,IAAI3D,GAAiB,GAAO,GAAMG,GAAeE,GAAgBC,EAAS,CAAC,CACpG,CALAI,GAAsB,cAAAqF,EAatB,eAAsBE,GAAavC,EAAmBwC,GAAqD,CACvG,IAAM3E,GAAQ2E,IAAY,OAAS9F,EAAO,cACpCoB,GAAS0E,IAAY,QAAU9F,EAAO,eAC5C,OAAOuD,GAAc,IAAI3D,GAAiB,GAAO0D,GAAY,GAAMnC,GAAOC,EAAM,CAAC,CACrF,CAJAd,GAAsB,aAAAuF,GAWtB,eAAsBE,GAAazC,EAAyC,CACxE,OAAOC,GAAc,IAAI3D,GAAiB0D,GAAY,GAAM,EAAK,CAAC,CACtE,CAFAhD,GAAsB,aAAAyF,GAUtB,eAAsBC,GAAc7C,EAAqB2C,GAA6C,CAClG,GAAM,CAACzC,EAAK,EAAIF,EAAO,eAAe,EACtC,GAAI,CAACE,GACD,MAAM,IAAI,MAAM,iCAAiC,EAErD,OAAO4C,GAAoB5C,GAAOyC,EAAU,CAChD,CANAxF,GAAsB,cAAA0F,GAYtB,eAAsBE,EAAcC,EAAuB7C,GAAmD,CAE1G,IAAM8C,IADU,MAAMtE,GAAY,GACZ,KAAMW,IACjBA,GAAO,OAAS0D,GAAQ1D,GAAO,WAAaa,EACtD,EACD,OAAI8C,IACID,IAAS,aACT3H,GAAY4H,GACLD,IAAS,aAChB1H,GAAY2H,GACLD,IAAS,gBAChBzH,GAAe0H,IAEnBzD,GAAa,IAAIwD,EAAM7C,EAAQ,EACxB8C,IAEJ,IACX,CAjBA9F,GAAsB,cAAA4F,EAsBf,SAASG,IAAwC,CACpD,GAAI,CAACtH,IAAqBA,GAAkB,aAAe,QAAS,CAChE,IAAMuH,EAAUhG,GAAY,gBAAgB,EACtCiG,GAAaD,EAAQ,6BAA6B,EAElDE,GAASF,EAAQ,WAAW,EAClCE,GAAO,KAAK,MAAQ,KACpBA,GAAO,QAAQD,EAAU,EACzBC,GAAO,QAAQF,EAAQ,WAAW,EAElC,IAAMG,GAAaH,EAAQ,iBAAiB,EAC5CG,GAAW,KAAO,OAClBA,GAAW,UAAU,MAAQ,EAC7BA,GAAW,QAAQD,EAAM,EACzBC,GAAW,MAAM,EAEjB1H,GAAoBwH,GAAW,OAAO,eAAe,EAAE,CAAC,CAC5D,CAEA,OAAO,OAAO,OAAOxH,GAAkB,MAAM,EAAG,CAAE,QAAS,EAAM,CAAC,CACtE,CApBOuB,GAAS,oBAAA+F,GAyBT,SAASK,EAAmBvF,EAAQnB,EAAO,cAAeoB,GAASpB,EAAO,eAAkC,CAE1GlB,KACDA,GAAe,SAAS,cAAc,QAAQ,GAIlDA,GAAa,MAAQqC,EACrBrC,GAAa,OAASsC,GAGtB,IAAMuF,GAAM7H,GAAa,WAAW,IAAI,EACxC,OAAA6H,GAAI,KAAK,EAAG,EAAGxF,EAAOC,EAAM,EAC5BuF,GAAI,UAAY,QAChBA,GAAI,KAAK,GAGL,CAAC9H,IAAoBA,GAAiB,aAAe,WAGrDA,GADeC,GAAa,cAAckB,EAAO,cAAc,EACrC,eAAe,EAAE,CAAC,GAGzC,OAAO,OAAOnB,GAAiB,MAAM,EAAG,CAAE,QAAS,EAAM,CAAC,CACrE,CAxBOyB,GAAS,mBAAAoG,EA6BT,SAASE,IAA8B,CAE1C,GAAIC,GAAY,IAAM,QAAU,OAAOC,GAAe,CAAC,EAAI,GACvD,MAAO,GAEX,GAAI,CACA,IAAMC,EAAW,OACjB,MACK,iBAAkBA,EAAI,WACnB,iBAAkBA,EAAI,UAAU,cAChCA,EAAI,mBACJA,EAAI,iBACJA,EAAI,uBACJA,EAAI,mBACJA,EAAI,kBAAkB,UAAU,eAChCA,EAAI,cACJA,EAAI,aAAa,UAAU,cAC3BA,EAAI,aAAa,UAAU,eAC3B,eAAgB,WAChB,IACJ,EAER,MAAY,CACR,MAAO,EACX,CACJ,CAzBOzG,GAAS,mBAAAsG,GA8BT,SAASI,IAAsC,CAClD,MAAO,CAAC,CAAC,UAAU,aAAa,eACpC,CAFO1G,GAAS,2BAAA0G,GAOT,SAASC,IAA+B,CAE3C,IAAMC,EAAqB5G,GAAY,YAAY,IAAM,UAAYA,GAAY,eAAe,IAAM,MAAQA,GAAY,kBAAkB,IAAM,IAE5I6G,GAAgB7G,GAAY,YAAY,IAAM,QAC9C8G,GAAiB9G,GAAY,YAAY,IAAM,SACrD,OAAO4G,GAAsBC,IAAiBC,EAClD,CAPO9G,GAAS,oBAAA2G,GAaT,SAASI,IAA8B,CAC1C,OAAQ/G,GAAY,YAAY,IAAM,UAAYA,GAAY,GAAG,IAAM,WAAcN,EAAO,SAChG,CAFOM,GAAS,mBAAA+G,GAOT,SAASC,IAA8B,CAC1C,IAAMC,EAAcjH,GAAY,YAAY,IAAM,UAAY,OAAOA,GAAY,eAAe,CAAC,IAAM,IAAM,CAAC,EAAG,EAAG,CAAC,EAAE,SAAS,OAAOA,GAAY,kBAAkB,CAAC,CAAC,EACjKkH,GAAalH,GAAY,GAAG,IAAM,WAAaA,GAAY,UAAU,IAAM,GAEjF,OAAOiH,GAAeC,EAC1B,CALOlH,GAAS,mBAAAgH,GAWT,SAASG,IAAuC,CACnD,OAAOnH,GAAY,YAAY,IAAM,WAAa,OAAOA,GAAY,eAAe,CAAC,EAAI,EAC7F,CAFOA,GAAS,4BAAAmH,GAOT,SAASC,IAAyB,CAErC,MAAO,EAAEpH,GAAY,kBAAkB,GAAKA,GAAY,SAAS,EACrE,CAHOA,GAAS,cAAAoH,GAQT,SAASC,IAAyC,CACrD,MAAO,EAAErH,GAAY,YAAY,IAAM,WAAaA,GAAY,YAAY,IAAM,SACtF,CAFOA,GAAS,8BAAAqH,GAOT,SAASC,IAAa,CACzB,OAAK3I,KACDA,IAAO,IAAM,CACT,IAAM4I,EAA2C,CAC7C,QAAS,MACT,QAAS,UACT,QAAS,UACT,MAAO,QACP,MAAO,cACP,KAAM,SACN,OAAQ,WACR,KAAM,SACN,MAAO,mDACP,IAAK,MACL,KAAM,OACN,KAAM,OACN,IAAK,QACL,IAAK,8EACT,EAEA,QAAWvF,MAAQuF,EACf,GAAI,OAAO,OAAOA,EAAevF,EAAI,GAAKuF,EAAcvF,EAAI,EAAE,KAAK/C,EAAE,EACjE,OAAO+C,GAGf,MAAO,SACX,GAAG,GAEArD,EACX,CA7BOqB,GAAS,GAAAsH,GAkCT,SAASE,IAAuC,CACnD,OAAO5I,EACX,CAFOoB,GAAS,UAAAwH,GAOT,SAASC,IAAoB,CAChC,OAAI/I,KAAc,OACdA,GAAY,4CAA4C,KAAKK,EAAE,GAE5DL,EACX,CALOsB,GAAS,SAAAyH,GAUT,SAASlB,IAAoC,CAChD,OAAO7C,GAAgB,EAAE,CAAC,CAC9B,CAFO1D,GAAS,YAAAuG,GAOT,SAASC,IAAyB,CACrC,OAAO9C,GAAgB,EAAE,CAAC,CAC9B,CAFO1D,GAAS,eAAAwG,GAOT,SAASkB,IAA4B,CACxC,OAAOhE,GAAgB,EAAE,CAAC,CAC9B,CAFO1D,GAAS,kBAAA0H,GAOT,SAASC,IAAgC,CAC5C,OAAK7I,KACDA,GAAgB,IAAK,OAAO,cAAgB,OAAO,qBAGvDA,GAAc,OAAO,EAAE,MAAM,IAAM,CAC/BsC,EAAM,KAAK,+BAA+B,CAC9C,CAAC,EACMtC,EACX,CATOkB,GAAS,gBAAA2H,GAcT,SAASC,IAA4B,CACxC,OAAOlE,GAAgB,EAAE,CAAC,CAC9B,CAFO1D,GAAS,kBAAA4H,GAOT,SAASC,IAAiC,CAC7C,OAAO7H,GAAY,kBAAkB,GAAK,KAAO,CAACA,GAAY,SAAS,CAC3E,CAFOA,GAAS,sBAAA6H,GAOT,SAASC,GAAiBnG,EAAuBoG,GAA4B,CAC3E7I,GAAeyC,CAAK,IACrBzC,GAAeyC,CAAK,EAAI,CAAC,GAE7BzC,GAAeyC,CAAK,EAAE,KAAKoG,EAAQ,CACvC,CALO/H,GAAS,iBAAA8H,GAUT,SAASE,GAAoBrG,EAAuBoG,GAA6B,CACpF,GAAK7I,GAAeyC,CAAK,EAIzB,GAAI,CAACoG,GACD,OAAO7I,GAAeyC,CAAK,MACxB,CACH,IAAMsG,GAAQ/I,GAAeyC,CAAK,EAAE,QAAQoG,EAAQ,EAChDE,GAAQ,IACR/I,GAAeyC,CAAK,EAAE,OAAOsG,GAAO,CAAC,CAE7C,CACJ,CAbOjI,GAAS,oBAAAgI,KA/dVhI,QAAA,KA+eV,IAAOkI,EAAQlI,GCrwCR,IAAMmI,GAAN,MAAMA,EAAwB,CAIjC,WAAW,WAAY,CACnB,OAAOA,GAAwB,MAAM,CAAC,GAAG,GAAK,CAClD,CAEA,WAAW,SAAU,CACjB,IAAMC,EAAOD,GAAwB,MACrC,OAAOC,EAAKA,EAAK,OAAS,CAAC,GAAG,GAAK,CACvC,CAEA,OAAO,cAAe,CAClBD,GAAwB,MAAQ,CAAC,CACrC,CAEA,WAAW,gBAAgC,CACvC,OAAOA,GAAwB,eACnC,CAEA,WAAW,eAAeE,EAA+B,CACrDF,GAAwB,gBAAkBE,CAC9C,CAEA,OAAO,IAAIC,EAAsB,CAC7BH,GAAwB,MAAM,KAAKG,CAAI,CAC3C,CAEA,OAAe,oBAAqB,CAChC,IAAMC,EAAO,CACT,CAAC,aAAaC,EAAO,UAAU,GAAIA,EAAO,OAAO,CAAC,EAClD,CAAC,aAAc,UAAU,SAAS,EAClC,CAAC,qBAAsB,GAAG,OAAO,OAAO,KAAK,IAAI,OAAO,OAAO,MAAM,EAAE,EACvE,CAAC,eAAgB,WAAWC,EAAY,oBAAoB,CAAC,UAAUA,EAAY,wBAAwB,CAAC,EAAE,CAClH,EAEMC,EAAO,IAAI,KACXC,EAAOD,EAAK,QAAQ,EACpBE,EAAYF,EAAK,eAAe,QAAS,CAAE,UAAW,QAAS,UAAW,MAAO,CAAC,EAExF,OAAOH,EAAK,IAAKD,IACN,CACH,EAAGM,EACHD,EACA,EAAG,MACH,EAAGL,CACP,EACH,CACL,CAEA,OAAO,aAAc,CACjB,IAAMF,EAAOD,GAAwB,MACrC,OAAIC,EAAK,SAAW,EACT,CAAC,EAKL,CAAC,GAFYD,GAAwB,mBAAmB,EAEvC,GAAGC,CAAI,CACnC,CACJ,EA5DIS,EADSV,GACM,QAA0B,CAAC,GAC1CU,EAFSV,GAEM,kBAAiC,MAF7C,IAAMW,GAANX,GCFA,IAAMY,GAAN,KAA+C,CAA/C,cACHC,EAAA,KAAQ,SAAc,CAAC,GAEvB,IAAI,QAAiB,CACjB,OAAO,KAAK,OAAO,MACvB,CAEA,QAAQC,EAAiB,CACrB,KAAK,OAAO,KAAK,GAAGA,CAAI,CAC5B,CAEA,MAAMA,EAA0B,CAC5B,KAAK,OAAO,KAAK,GAAGA,EAAK,MAAM,CACnC,CAEA,OAAkB,CACd,OAAO,KAAK,OAAO,MAAM,GAAK,IAClC,CAEA,QAAe,CACX,IAAMC,EAAS,KAAK,OAAS,EAAI,KAAK,MAAM,KAAK,OAAS,CAAC,EAAI,EAC/D,KAAK,OAAS,KAAK,OAAO,MAAMA,CAAM,CAC1C,CAEA,MAAiB,CACb,OAAO,KAAK,OAAO,CAAC,GAAK,IAC7B,CAEA,MAAiB,CACb,IAAMC,EAAM,KAAK,OAAO,OACxB,OAAOA,EAAM,KAAK,OAAOA,EAAM,CAAC,EAAI,IACxC,CAEA,OAAc,CACV,KAAK,OAAS,CAAC,CACnB,CAEA,UAAmB,CACf,OAAK,KAAK,OAAO,OAGV,KAAK,UAAU,KAAK,OAAQ,CAACC,EAAKC,IACjCA,aAAiB,MACV,OAAOA,CAAK,EAEhBA,CACV,EAPU,EAQf,CACJ,EC9CA,IAAMC,GAAoB,EAAI,KAAO,KAC/BC,GAAgB,IAAM,KACtBC,GAAmB,IAAM,KACzBC,GAAqB,EACrBC,GAAiB,uBACjBC,GAAe,IAefC,GAAN,KAAe,CAKX,aAAc,CAJdC,EAAA,KAAiB,SAAyB,CAAC,GAC3CA,EAAA,KAAQ,aAAa,GACrBA,EAAA,KAAQ,eAAeP,IAGnB,GAAI,CACA,IAAMQ,EAAK,OAAO,aAClB,QAAWC,KAAO,OAAO,KAAKD,CAAE,EAAG,CAC/B,GAAIC,EAAI,QAAQL,EAAc,IAAM,EAChC,SAGJ,IAAMM,EAAMF,EAAG,QAAQC,CAAG,EAC1B,GAAI,CAACC,EAAK,CAENC,GAAqBF,CAAG,EACxB,QACJ,CAEA,IAAMG,EAAOC,GAAaH,CAAG,EAC7B,KAAK,IAAID,EAAKG,CAAI,CACtB,CACJ,OAASE,EAAG,CACR,QAAQ,MAAM,qBAAsBA,CAAC,EACrC,KAAK,aAAe,CACxB,CAGA,KAAK,OAAO,KAAK,CAACC,EAAGC,IAAMD,EAAE,KAAOC,EAAE,IAAI,EAC1C,KAAK,QAAQd,EAAgB,CACjC,CAEA,IAAI,MAAO,CACP,OAAO,KAAK,UAChB,CAEA,IAAI,QAAS,CACT,OAAO,KAAK,OAAO,MACvB,CAEA,IAAI,WAAY,CACZ,OAAO,KAAK,IAAI,KAAK,aAAe,KAAK,WAAY,CAAC,CAC1D,CAEA,IAAI,OAAQ,CACR,OAAO,KAAK,MAChB,CAEA,IAAI,YAAYU,EAAc,CAC1B,KAAK,aAAe,KAAK,IAAIA,EAAM,KAAK,aAAcZ,EAAiB,CAC3E,CAEA,IAAIS,EAAaG,EAAc,CAC3B,IAAMK,EAAO,SAASR,EAAI,QAAQL,GAAgB,EAAE,EAAG,EAAE,EACzD,KAAK,YAAcQ,EACnB,KAAK,OAAO,KAAK,CAAE,IAAAH,EAAK,KAAAG,EAAM,KAAAK,CAAK,CAAC,CACxC,CAEA,kBAAmB,CACf,IAAMP,EAAM,KAAK,OAAO,MAAM,EAC1BA,IACAC,GAAqBD,EAAI,GAAG,EAC5B,KAAK,YAAcA,EAAI,KAE/B,CAEA,QAAQQ,EAAoB,CACxB,KAAO,KAAK,SAAW,KAAK,KAAOlB,IAAqB,KAAK,OAASG,GAAqB,GAAK,KAAK,KAAOe,EAAa,KAAK,YAC1H,KAAK,iBAAiB,CAE9B,CACJ,EAEA,SAASC,IAAgB,CACrB,MAAO,GAAGf,EAAc,GAAG,KAAK,IAAI,CAAC,EACzC,CAEA,SAASS,GAAaO,EAAqB,CACvC,OAAO,IAAI,KAAK,CAACA,CAAG,CAAC,EAAE,IAC3B,CAEA,SAAST,GAAqBF,EAAa,CACvC,GAAI,CACA,OAAO,aAAa,WAAWA,CAAG,CACtC,OAASK,EAAG,CACR,QAAQ,MAAM,oCAAqCA,CAAC,CACxD,CACJ,CAEA,SAASO,IAAqB,CAC1B,IAAMX,EAAMY,GAAK,SAAS,EAG1B,GAAI,CAACC,GAAS,WAAa,CAACb,EACxB,OAGJ,IAAME,EAAOC,GAAaH,CAAG,EAE7B,GAAIE,EAAOX,GAAe,CAEtBqB,GAAK,OAAO,EACZD,GAAmB,EACnB,MACJ,CAGAE,GAAS,QAAQrB,GAAmBU,CAAI,EAExC,GAAI,CACA,OAAO,aAAa,QAAQY,GAASd,CAAG,CAC5C,OAAS,EAAG,CAQR,GANA,QAAQ,KAAK,iCAAkC,CAAC,EAGhDa,GAAS,YAAcA,GAAS,KAAOX,EACvCW,GAAS,QAAQrB,GAAmBU,CAAI,EAEpCW,GAAS,WAAarB,GAAmBU,EAAM,CAC/CS,GAAmB,EACnB,MACJ,CAGA,GAAIT,EAAOV,GAAkB,CACzBoB,GAAK,OAAO,EACZD,GAAmB,EACnB,MACJ,CAGAE,GAAS,YAAc,EACvB,MACJ,CAGIX,EAAOX,KACPsB,GAAS,IAAIC,GAASZ,CAAI,EAC1BY,GAAUL,GAAc,EACxBG,GAAK,MAAM,EACXC,GAAS,QAAQrB,EAAgB,EAEzC,CAEA,SAASuB,IAAW,CACZ,CAACF,GAAS,WAAa,CAACD,GAAK,QAIjCD,GAAmB,CACvB,CAEA,SAASK,GAAQC,EAAa,GAAe,CACzC,IAAMC,EAAS,CAAC,EAChB,GAAI,CACA,IAAMpB,EAAK,OAAO,aAClB,QAAWqB,KAAQN,GAAS,MAAO,CAC/B,IAAMb,EAAMF,EAAG,QAAQqB,EAAK,GAAG,EAC/BD,EAAO,KAAKlB,CAAG,CACnB,CACA,IAAMoB,EAAUR,GAAK,SAAS,EAC1BQ,GACAF,EAAO,KAAKE,CAAO,CAE3B,OAAShB,EAAG,CACR,QAAQ,MAAM,qBAAsBA,CAAC,CACzC,CAEA,IAAMiB,EAAO,IAAIH,EAAO,KAAK,GAAG,CAAC,IACjC,GAAID,EACA,OAAOI,EAGX,IAAMC,EAAW,QAAQ,KAAK,IAAI,CAAC,QACnC,OAAAC,GAAYF,EAAMC,CAAQ,EACnBA,CACX,CAEA,SAASC,GAAYC,EAAcC,EAAc,CAC7C,IAAMpB,EAAI,SAAS,cAAc,GAAG,EAC9BqB,EAAO,IAAI,KAAK,CAACF,CAAI,EAAG,CAAE,KAAM,WAAY,CAAC,EACnDnB,EAAE,KAAO,IAAI,gBAAgBqB,CAAI,EACjCrB,EAAE,SAAWoB,EACbpB,EAAE,MAAM,CACZ,CAEO,SAASsB,GAAIC,EAAeC,EAAa,CAE5C,GAAI,CAAChB,GAAS,UACV,OAGJ,IAAMN,EAAO,IAAI,KACXuB,EAA0B,CAC5B,EAAGvB,EAAK,QAAQ,EAChB,EAAGqB,EACH,EAAGC,EACH,EAAGtB,EAAK,eAAe,QAAS,CAAE,UAAW,QAAS,UAAW,MAAO,CAAC,CAC7E,EACAK,GAAK,KAAKkB,CAAO,EACjBC,GAAwB,IAAID,CAAO,EAE9BE,KAEDA,GAAiB,OAAO,WAAW,IAAM,CACrCA,GAAiB,KACjBjB,GAAS,CACb,EAAGpB,EAAY,EAEvB,CAEO,SAASsC,IAAO,CACfpB,KAKJA,GAAW,IAAIjB,GACfgB,GAAO,IAAIsB,GACXpB,GAAUL,GAAc,EAExB,OAAO,iBAAiB,eAAgBM,EAAQ,EACpD,CAEA,IAAIF,GACAD,GACAE,GACAkB,GAAgC,KAEnC,OAAe,mBAAqB,CAACf,EAAa,MAC1CJ,IAEDoB,GAAK,EAETlB,GAAS,EACFC,GAAQC,CAAU,GC9PtB,IAAKkB,QACRA,EAAA,MAAQ,QACRA,EAAA,IAAM,MACNA,EAAA,KAAO,OACPA,EAAA,MAAQ,QAJAA,QAAA,IAOFC,OAAV,CACI,IAAMC,EAAU,KACVC,EAAkB,CAACC,MAA2BC,IAAgB,CAChEC,EAAS,eAAeF,GAAM,GAAGC,CAAI,CACzC,EACIE,EAAW,GAETC,EAAQ,CAACC,GAAcC,IAClB,IAAIL,KAAgB,CACvBI,GAAG,GAAGJ,EAAI,EACGM,GAAID,EAAOL,EAAI,CAChC,EAGEO,EAA0B,QAAQ,MAAM,KAAK,QAASV,CAAO,EAC7DW,EAAwB,QAAQ,IAAI,KAAK,QAASX,CAAO,EACzDY,EAAyB,QAAQ,KAAK,KAAK,QAASZ,CAAO,EAC3Da,EAA0B,QAAQ,MAAM,KAAK,QAASb,CAAO,EAE7Dc,EAA2Bb,EAAgB,KAAK,KAAM,OAAsB,EAC5Ec,EAAyBd,EAAgB,KAAK,KAAM,KAAoB,EACxEe,EAA0Bf,EAAgB,KAAK,KAAM,MAAqB,EAC1EgB,EAA2BhB,EAAgB,KAAK,KAAM,OAAsB,EAEvEF,EAAA,MAAkBe,EAClBf,EAAA,IAAgBgB,EAChBhB,EAAA,KAAiBiB,EACjBjB,EAAA,MAAkBkB,EAEtB,SAASC,GAAU,CACtB,OAAOb,CACX,CAFON,EAAS,QAAAmB,EAIT,SAASC,GAAOC,GAAiB,CACpCf,EAAWe,GAEPC,EAAO,UACMC,GAAK,EAGlBF,IACArB,EAAA,MAAQsB,EAAO,SAAWf,EAAMI,EAAe,OAAsB,EAAIA,EACzEX,EAAA,IAAMsB,EAAO,SAAWf,EAAMK,EAAa,KAAoB,EAAIA,EACnEZ,EAAA,KAAOsB,EAAO,SAAWf,EAAMM,EAAc,MAAqB,EAAIA,EACtEb,EAAA,MAAQsB,EAAO,SAAWf,EAAMO,EAAe,OAAsB,EAAIA,IAEzEd,EAAA,MAAQsB,EAAO,SAAWf,EAAMQ,EAAgB,OAAsB,EAAIA,EAC1Ef,EAAA,IAAMsB,EAAO,SAAWf,EAAMS,EAAc,KAAoB,EAAIA,EACpEhB,EAAA,KAAOsB,EAAO,SAAWf,EAAMU,EAAe,MAAqB,EAAIA,EACvEjB,EAAA,MAAQsB,EAAO,SAAWf,EAAMW,EAAgB,OAAsB,EAAIA,EAElF,CAlBOlB,EAAS,OAAAoB,GAoBT,SAASI,GAAKrB,MAA2BC,EAAa,CACzD,OAAQD,GAAM,CACV,IAAK,WACDH,EAAA,OAAM,GAAGI,CAAI,EACb,MACJ,IAAK,SACDJ,EAAA,KAAI,GAAGI,CAAI,EACX,MACJ,IAAK,UACDJ,EAAA,MAAK,GAAGI,CAAI,EACZ,MACJ,IAAK,WACDJ,EAAA,OAAM,GAAGI,CAAI,EACb,KACR,CACJ,CAfOJ,EAAS,KAAAwB,GAiBT,SAASC,GAAKC,MAAgBtB,EAAa,CAAC,CAA5CJ,EAAS,KAAAyB,KAtEVzB,QAAA,KAyEV,IAAO2B,EAAQ3B,GCrFR,IAAM4B,GAAyB,KAE/B,SAASC,GAAgBC,EAAqE,CACjG,OAAQA,EAAsB,UAClC,CAEO,SAASC,GAAkBD,EAA0E,CACxG,OAAQA,EAA2B,iBACvC,CAEO,SAASE,GAAeF,EAA+C,CAC1E,GAAID,GAAgBC,CAAM,EACtB,MAAO,KAGX,GAAIC,GAAkBD,CAAM,EACxB,OAAOF,GAGX,IAAIK,EAAS,GACb,OAAIH,EAAO,WAAa,SACpBG,GAAU,KAAOH,EAAO,UAExBA,EAAO,QAAU,QAAaA,EAAO,SAAW,SAC5CG,IAAW,KACXA,GAAU,KAEdA,GAAU,MAAQ,KAAK,MAAMH,EAAO,KAAK,EAAI,IAAM,KAAK,MAAMA,EAAO,MAAM,GAE3EA,EAAO,MAAQ,SACXG,IAAW,KACXA,GAAU,KAEdA,GAAU,OAASH,EAAO,KAEvBG,CACX,CChCO,IAAKC,QACRA,EAAA,OAAS,SACTA,EAAA,OAAS,SACTA,EAAA,OAAS,SACTA,EAAA,MAAQ,QACRA,EAAA,QAAU,UACVA,EAAA,WAAa,aANLA,QAAA,IASNC,GAAuB,IACvBC,GAAqB,IAEpB,SAASC,GAAsCC,EAAoE,CACtH,OACIA,EAAY,eACXA,EAAY,UAAYC,GAAuBJ,GAAuBG,EAAY,UAAY,KAC9FA,EAAY,WAAaC,GAAuBH,GAAqBE,EAAY,WAAa,GAEvG,CAEO,SAASE,GAAkCC,EAA0E,CACxH,IAAMC,EAASD,EAAkB,MAAMF,EAAoB,EAErDI,EAASD,EAAO,MAAM,EAC5B,GAAI,CAACC,EACD,MAAM,IAAI,MAAM,+BAAiCF,CAAiB,EAGtE,IAAIG,EAA8B,KAC9BC,EACAC,EAAY,EAEhB,QAAWC,KAASL,EAChB,OAAQK,EAAM,OAAO,CAAC,EAAG,CACrB,KAAKZ,GACDS,EAAYI,GAAeD,EAAM,MAAM,CAAC,CAAC,EACzC,MACJ,KAAKX,GACDS,EAAaE,EAAM,MAAM,CAAC,EAC1B,MACJ,KAAKE,GACDH,EAAY,OAAO,SAASC,EAAM,MAAM,CAAC,EAAG,EAAE,EAC9C,MACJ,QACI,MAAM,IAAI,MAAM,6BAA+BA,EAAM,OAAO,CAAC,EAAI,0BAA4BN,CAAiB,CACtH,CAIJ,MAAO,CACH,cAFkBS,EAAM,QAAQP,EAAQG,CAAS,EAGjD,UAAAF,EACA,WAAAC,CACJ,CACJ,CAEA,SAASG,GAAeG,EAA+B,CACnD,QAAWC,KAAO,OAAO,KAAKlB,EAAS,EACnC,GAAIkB,IAAQD,EACR,OAAOjB,GAAUkB,CAA6B,EAGtD,OAAO,IACX,CCjEO,SAASC,IAAoB,CAChC,IAAIC,EAAO,IAAI,SAAS,IAAI,YAAY,EAAE,CAAC,EACvCC,EAAI,EACR,SAASC,EAAKC,EAAW,CACrB,GAAIF,EAAIE,EAAIH,EAAK,WAAY,CACzB,IAAMI,EAAM,IAAI,WAAW,KAAK,IAAIH,EAAIE,EAAGH,EAAK,WAAa,EAAE,CAAC,EAChEI,EAAI,IAAI,IAAI,WAAWJ,EAAK,OAAO,MAAM,EAAGC,CAAC,CAAC,CAAC,EAC/CD,EAAO,IAAI,SAASI,EAAI,MAAM,CAClC,CACJ,CACA,MAAO,CACH,IAAIC,EAAiB,CAEjB,GADAH,EAAKG,EAAE,UAAU,EACbC,GAAkBD,CAAC,EAAG,CACtB,IAAME,EAAUF,EAAsB,OACtC,IAAI,WAAWL,EAAK,MAAM,EAAE,IAAI,IAAI,WAAWO,CAAM,EAAGN,CAAC,CAC7D,MACI,IAAI,WAAWD,EAAK,MAAM,EAAE,IAAI,IAAI,WAAWK,CAAC,EAAGJ,CAAC,EAExDA,GAAKI,EAAE,UACX,EACA,MAAMA,EAAW,CACbH,EAAK,CAAC,EACNF,EAAK,QAAQC,EAAGI,CAAC,EACjB,EAAEJ,CACN,EACA,OAAOI,EAAW,CACdH,EAAK,CAAC,EACNF,EAAK,SAASC,EAAGI,CAAC,EAClBJ,GAAK,CACT,EACA,OAAOI,EAAW,CACdH,EAAK,CAAC,EACNF,EAAK,SAASC,EAAGI,CAAC,EAClBJ,GAAK,CACT,EACA,OAAOI,EAAW,CACdH,EAAK,CAAC,EACN,IAAMM,EAAMH,EAAI,EACZG,IACAH,EAAI,CAACA,GAET,IAAII,EAAMJ,EAAI,WAAe,EACzBK,EAAKL,EAAI,WAAc,EACvBG,IAEAE,EAAM,CAACA,EAAK,EAAK,EACjBD,EAAKC,IAAO,EAAK,CAACD,EAAK,EAAK,EAAI,CAACA,GAErCT,EAAK,UAAUC,EAAGQ,CAAE,EACpBT,EAAK,UAAUC,EAAI,EAAGS,CAAE,EACxBT,GAAK,CACT,EACA,OAAOI,EAAW,CACdH,EAAK,CAAC,EACNF,EAAK,SAASC,EAAGI,CAAC,EAClB,EAAEJ,CACN,EACA,QAAQI,EAAW,CACfH,EAAK,CAAC,EACNF,EAAK,UAAUC,EAAGI,CAAC,EACnBJ,GAAK,CACT,EACA,QAAQI,EAAW,CACfH,EAAK,CAAC,EACNF,EAAK,UAAUC,EAAGI,CAAC,EACnBJ,GAAK,CACT,EACA,QAAQI,EAAW,CACfH,EAAK,CAAC,EACNF,EAAK,UAAUC,EAAII,EAAI,WAAe,CAAC,EACvCL,EAAK,UAAUC,EAAI,EAAGI,EAAI,UAAW,EACrCJ,GAAK,CACT,EACA,KAAKI,EAAW,CACZH,EAAK,CAAC,EACNF,EAAK,WAAWC,EAAGI,CAAC,EACpBJ,GAAK,CACT,EACA,UAAW,CACP,OAAO,IAAI,WAAWD,EAAK,OAAO,MAAM,EAAGC,CAAC,CAAC,CACjD,CACJ,CACJ,CAEA,SAASK,GAAkBD,EAAuC,CAC9D,OAAQA,EAAsB,SAAW,MAC7C,CAEO,SAASM,GAAiBC,EAAmB,CAChD,IAAMZ,EAAO,YAAY,OAAOY,CAAG,EAAI,IAAI,SAASA,EAAI,OAAQA,EAAI,WAAYA,EAAI,UAAU,EAAI,IAAI,SAASA,CAAG,EAC9GX,EAAI,EACR,MAAO,CACH,MAAO,CACH,OAAOD,EAAK,SAASC,CAAC,CAC1B,EACA,IAAIY,EAAa,CACbZ,GAAKY,EACL,IAAMC,EAAMd,EAAK,WACjB,OAAQA,EAAK,OAAuB,MAAMc,EAAMb,EAAIY,EAAKC,EAAMb,CAAC,CACpE,EACA,OAAQ,CACJ,OAAOD,EAAK,QAAQC,GAAG,CAC3B,EACA,QAAS,CACL,OAAAA,GAAK,EACED,EAAK,SAASC,EAAI,CAAC,CAC9B,EACA,QAAS,CACL,OAAAA,GAAK,EACED,EAAK,SAASC,EAAI,CAAC,CAC9B,EACA,QAAS,CACLA,GAAK,EACL,IAAMQ,EAAKT,EAAK,SAASC,EAAI,CAAC,EACxBS,EAAKV,EAAK,UAAUC,EAAI,CAAC,EAC/B,OAAOQ,EAAK,WAAcC,CAC9B,EACA,QAAS,CACL,OAAOV,EAAK,SAASC,GAAG,CAC5B,EACA,SAAU,CACN,OAAAA,GAAK,EACED,EAAK,UAAUC,EAAI,CAAC,CAC/B,EACA,SAAU,CACN,OAAAA,GAAK,EACED,EAAK,UAAUC,EAAI,CAAC,CAC/B,EACA,SAAU,CACNA,GAAK,EACL,IAAMQ,EAAKT,EAAK,UAAUC,EAAI,CAAC,EACzBS,EAAKV,EAAK,UAAUC,EAAI,CAAC,EAC/B,OAAOQ,EAAK,WAAcC,CAC9B,EACA,QAAS,CACL,OAAAT,GAAK,EACED,EAAK,WAAWC,EAAI,CAAC,CAChC,EACA,QAAS,CACL,OAAAA,GAAK,EACED,EAAK,WAAWC,EAAI,CAAC,CAChC,CACJ,CACJ,C/ClIA,IAAMc,GAA6B,EAC7BC,GAAwB,EACxBC,GAA2B,EAC3BC,GAAmB,EACnBC,GAA2B,EAC3BC,GAA4B,EAC5BC,GAAoC,EACpCC,GAAwB,EAExBC,GAAiB,EACjBC,GAAqB,EACrBC,GAA2B,EAE3BC,GAAe,EAEfC,GAAwB,EAExBC,GAAiB,EACjBC,GAAmB,EAEZC,GAAN,KAA0C,CAA1C,cACHC,EAAA,KAAQ,wBAAsD,MAE9D,yBAAyBC,EAA8C,CACnE,KAAK,sBAAwBA,CACjC,CAEA,6BAA6BC,EAAwBC,EAA2F,CAC5I,IAAMC,EAAcC,GAAkB,EACtC,MAAI,IAAID,EAAapB,EAA0B,EAC/C,MAAI,IAAIoB,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EAEnC,MAAI,IAAIE,EAAa,IAAI,EAEzB,IAAME,EAAkC,CAAC,EACzC,QAAWC,KAAcJ,EACjB,OAAO,OAAOA,EAASI,CAAU,GACjC,KAAK,YAAYJ,EAASI,EAAYD,CAAgB,EAG9D,aAAI,IAAIF,EAAaE,CAAgB,EAErC,MAAI,IAAIF,EAAa,IAAI,EAElBA,EAAY,SAAS,EAAE,MAClC,CAEQ,YAAYD,EAA4EI,EAAoBD,EAAiC,CACjJ,IAAME,EAASL,EAAQI,CAAU,EAC3BE,EAAeJ,GAAkB,EAIvC,GAFA,KAAK,gBAAgBE,EAAYE,CAAY,EAEzCC,GAAgBF,CAAM,EACtB,MAAI,IAAIC,EAAchB,EAAkB,UACjCkB,GAAkBH,CAAM,EAC/B,MAAI,IAAIC,EAAcf,EAAwB,UAE9C,MAAI,IAAIe,EAAcjB,EAAc,EAEhCgB,EAAO,WAAa,OACpB,MAAI,IAAIC,EAAcD,EAAO,QAAQ,EAErC,MAAI,IAAIC,EAAc,IAAI,EAG1BD,EAAO,QAAU,QAAaA,EAAO,SAAW,QAChD,MAAI,IAAIC,EAAc,KAAK,MAAMD,EAAO,KAAK,CAAC,EAC9C,MAAI,IAAIC,EAAc,KAAK,MAAMD,EAAO,MAAM,CAAC,IAE/C,MAAI,IAAIC,EAAc,IAAI,EAC1B,MAAI,IAAIA,EAAc,IAAI,GAG1BD,EAAO,MAAQ,OACf,OAAQA,EAAO,IAAK,CAChB,IAAK,KACD,MAAI,IAAIC,EAAcZ,EAAc,EACpC,MACJ,IAAK,KACD,MAAI,IAAIY,EAAcX,EAAgB,EACtC,MACJ,QACI,MAAI,IAAIW,EAAc,IAAI,CAClC,MAEA,MAAI,IAAIA,EAAc,IAAI,EAIlCH,EAAiB,KAAKG,EAAa,SAAS,EAAE,MAAM,CACxD,CAEQ,gBAAgBF,EAAoBH,EAA0B,CAClE,GAAI,KAAK,sBAAuB,CAC5B,IAAMQ,EAAY,KAAK,sBAAsB,aAAaL,CAAU,EACpE,GAAIK,IAAc,OAAW,CACzB,MAAI,IAAIR,EAAaQ,CAAS,EAC9B,MACJ,CACJ,CACA,MAAI,IAAIR,EAAaG,CAAU,CACnC,CAEA,wBAAwBL,EAAwBW,EAAqC,CACjF,IAAMT,EAAcC,GAAkB,EACtC,aAAI,IAAID,EAAanB,EAAqB,EAC1C,MAAI,IAAImB,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EACnC,MAAI,IAAIE,EAAaS,EAAO,aAAa,EACzC,MAAI,IAAIT,EAAaS,EAAO,cAAc,EACnCT,EAAY,SAAS,EAAE,MAClC,CAEA,2BAA2BF,EAAwBW,EAAwC,CACvF,IAAMT,EAAcC,GAAkB,EACtC,aAAI,IAAID,EAAalB,EAAwB,EAC7C,MAAI,IAAIkB,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EACnC,MAAI,IAAIE,EAAaS,EAAO,QAAQ,EACpC,MAAI,IAAIT,EAAaS,EAAO,QAAQ,EACpC,MAAI,IAAIT,EAAaS,EAAO,QAAQ,EACpC,MAAI,IAAIT,EAAaS,EAAO,kBAAkB,EACvCT,EAAY,SAAS,EAAE,MAClC,CAEA,oBAAoBF,EAAwBY,EAAiC,CACzE,IAAMV,EAAcC,GAAkB,EACtC,aAAI,IAAID,EAAajB,EAAgB,EACrC,MAAI,IAAIiB,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EACnC,OAAK,IAAIE,EAAaU,EAAO,OAAO,EAC7BV,EAAY,SAAS,EAAE,MAClC,CAEA,2BAA2BF,EAAwBW,EAAwC,CACvF,IAAMT,EAAcC,GAAkB,EACtC,aAAI,IAAID,EAAahB,EAAwB,EAC7C,MAAI,IAAIgB,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EACnC,MAAI,IAAIE,EAAaS,EAAO,SAAS,EACrC,MAAI,IAAIT,EAAaS,EAAO,WAAW,EAChCT,EAAY,SAAS,EAAE,MAClC,CAEA,4BAA4BF,EAAwBY,EAAyC,CACzF,IAAMV,EAAcC,GAAkB,EACtC,aAAI,IAAID,EAAaf,EAAyB,EAC9C,MAAI,IAAIe,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EACnC,OAAK,IAAIE,EAAaU,EAAO,OAAO,EAC7BV,EAAY,SAAS,EAAE,MAClC,CAEA,mCAAmCF,EAAwBY,EAAgD,CACvG,IAAMV,EAAcC,GAAkB,EACtC,aAAI,IAAID,EAAad,EAAiC,EACtD,MAAI,IAAIc,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EACnC,OAAK,IAAIE,EAAaU,EAAO,OAAO,EAC7BV,EAAY,SAAS,EAAE,MAClC,CAEA,yBAAyBF,EAAwBY,EAAsC,CACnF,IAAMV,EAAcC,GAAkB,EACtC,MAAI,IAAID,EAAab,EAAqB,EAC1C,MAAI,IAAIa,EAAaT,EAAY,EACjC,MAAI,IAAIS,EAAaF,CAAc,EACnC,IAAMa,EAAcD,EAAO,cAAc,QAAQ,OACjD,MAAI,IAAIV,EAAaU,EAAO,WAAW,EACvC,MAAI,IAAIV,EAAaW,CAAW,EAChC,QAAWC,KAAUF,EAAO,cAAc,QACtC,MAAI,IAAIV,EAAaY,EAAO,GAAG,EAC/B,MAAI,IAAIZ,EAAaY,EAAO,KAAK,EACjC,MAAI,IAAIZ,EAAaY,EAAO,MAAM,EAClC,MAAI,IAAIZ,EAAaY,EAAO,GAAG,EAC/B,MAAI,IAAIZ,EAAaY,EAAO,QAAU,GAAI,EAE9C,OAAOZ,EAAY,SAAS,EAAE,MAClC,CAEA,MAAM,2BAA2Ba,EAAkE,CAC/F,IAAIC,EACJ,GAAID,aAAgB,KAAM,CACtB,IAAME,EAAc,gBAAiB,KAAK,UAAY,MAAMF,EAAK,YAAY,EAAI,MAAMG,GAAkBH,CAAI,EAC7GC,EAAaG,GAAiBF,CAAW,CAC7C,MACID,EAAaG,GAAiBJ,CAAI,EAEtC,IAAMK,EAAc,MAAI,IAAIJ,CAAU,EAChCK,EAAU,MAAI,IAAIL,CAAU,EAClC,GAAIK,IAAY5B,GAAc,CAC1B6B,EAAM,KAAK,yCAA2CF,EAAc,aAAeC,CAAO,EAC1F,MACJ,CAEA,GADoB,MAAI,IAAIL,CAAU,IAClBtB,GAAuB,CACvC4B,EAAM,KAAK,eAAiBF,EAAc,8BAAgCA,EAAc,aAAeC,CAAO,EAC9G,MACJ,CACA,OAAQD,EAAa,CACjB,KAAKtC,GACD,OAAO,KAAK,uCAAuCkC,CAAU,EACjE,KAAKjC,GACD,OAAO,KAAK,kCAAkCiC,CAAU,EAC5D,QACIM,EAAM,KAAK,6CAA+CF,CAAW,EACrE,MACR,CACJ,CAEQ,uCAAuCJ,EAA0C,CACrF,IAAMO,EAAW,MAAI,IAAIP,CAAU,EAC7BQ,EAAS,MAAI,IAAIR,CAAU,EAC3BS,EAAuE,CAAC,EAC9E,OAAAD,EAAO,QAASE,GAAc,CAC1B,IAAMC,EAAkBR,GAAiBO,CAAS,EAC5CE,EAAkB,MAAI,IAAID,CAAe,EAC/C,GAAI,OAAOC,GAAoB,SAC3BH,EAAyBG,CAAyB,EAAI,MAAI,IAAID,CAAe,MAC1E,CACH,IAAME,EAAcD,EACdvB,EAAayB,GAAsC,KAAK,uBAAuB,qBAAqBD,CAAW,CAAiC,EACtJJ,EAAyBpB,CAAU,EAAI,MAAI,IAAIsB,CAAe,CAClE,CACJ,CAAC,EACM,CACH,KAAM,WACN,SAAAJ,EACA,SAAUQ,EAAqB,sBAAsB,SAAS,EAC9D,yBAAAN,CACJ,CACJ,CAEQ,kCAAkCT,EAA0C,CAChF,IAAMO,EAAW,MAAI,IAAIP,CAAU,EAC7BgB,EAA4B,MAAI,IAAIhB,CAAU,EACpD,MAAO,CACH,KAAM,WACN,SAAAO,EACA,SAAUQ,EAAqB,iBAAiB,SAAS,EACzD,0BAAAC,CACJ,CACJ,CACJ,EgDvPO,IAAMC,GAAyI,CACjJ,UAAmC,CAC/B,GAAsCC,EAAK,uBAC3C,GAAmCA,EAAK,mBAC7C,EACC,YAAqC,CACjC,GAAsCA,EAAK,yBAC3C,GAAmCA,EAAK,qBAC7C,EACC,aAAsC,CAClC,GAAsCA,EAAK,0BAC3C,GAAmCA,EAAK,sBAC7C,EACC,iBAA2C,CACvC,GAAsCA,EAAK,8BAC3C,GAAmCA,EAAK,0BAC7C,EACC,QAAiC,CAC7B,GAAsCA,EAAK,qBAC3C,GAAmCA,EAAK,iBAC7C,EACC,QAAiC,CAC7B,GAAsCA,EAAK,qBAC3C,GAAmCA,EAAK,iBAC7C,CACJ,ECtCO,IAAMC,GAAN,KAAiB,CAQpB,YAAYC,EAAW,CANvBC,EAAA,KAAiB,KACjBA,EAAA,KAAQ,QAAkB,CAAC,GAC3BA,EAAA,KAAQ,IAAc,CAAC,EAAG,EAAG,EAAG,EAAG,CAAC,GACpCA,EAAA,KAAQ,KAAe,CAAC,EAAG,EAAG,EAAG,EAAG,CAAC,GACrCA,EAAA,KAAQ,KAAe,CAAC,GAGpB,GAAI,EAAED,EAAI,GAAKA,EAAI,GAAI,MAAM,IAAI,MAAM,oBAAoB,EAC3D,KAAK,EAAIA,CACb,CAEA,IAAIE,EAAW,CACX,GAAI,KAAK,MAAM,OAAS,EAAG,CACvB,KAAK,MAAM,KAAKA,CAAC,EACb,KAAK,MAAM,SAAW,GAAG,KAAK,UAAU,EAC5C,MACJ,CAIA,IAAIC,EAAI,EACR,GAAID,EAAI,KAAK,GAAG,CAAC,EACb,KAAK,GAAG,CAAC,EAAIA,EACbC,EAAI,UACGD,GAAK,KAAK,GAAG,CAAC,EACrB,KAAK,GAAG,CAAC,EAAIA,EACbC,EAAI,MAEJ,MAAO,EAAED,EAAI,KAAK,GAAGC,EAAI,CAAC,IAAIA,IAIlC,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAK,KAAK,EAAEA,CAAC,GAAKA,GAAKD,EAAI,EAAI,EAGtD,KAAK,GAAG,CAAC,EAAI,EACb,KAAK,GAAG,CAAC,GAAK,KAAK,EAAI,EACvB,KAAK,GAAG,CAAC,GAAK,KAAK,EACnB,KAAK,GAAG,CAAC,IAAM,EAAI,KAAK,GAAK,EAC7B,KAAK,GAAG,CAAC,GAAK,EAGd,QAASC,EAAI,EAAGA,GAAK,EAAGA,IAAK,CACzB,IAAMC,EAAI,KAAK,GAAGD,CAAC,EAAI,KAAK,EAAEA,CAAC,EAC/B,GAAKC,GAAK,GAAK,KAAK,EAAED,EAAI,CAAC,EAAI,KAAK,EAAEA,CAAC,EAAI,GAAOC,GAAK,IAAM,KAAK,EAAED,CAAC,EAAI,KAAK,EAAEA,EAAI,CAAC,EAAI,EAAI,CACzF,IAAME,EAAO,KAAK,KAAKD,CAAC,EAElBE,EACF,KAAK,GAAGH,CAAC,EACRE,GAAQ,KAAK,EAAEF,EAAI,CAAC,EAAI,KAAK,EAAEA,EAAI,CAAC,KAC9B,KAAK,EAAEA,CAAC,EAAI,KAAK,EAAEA,EAAI,CAAC,EAAIE,IAAS,KAAK,GAAGF,EAAI,CAAC,EAAI,KAAK,GAAGA,CAAC,IAAO,KAAK,EAAEA,EAAI,CAAC,EAAI,KAAK,EAAEA,CAAC,IAC3F,KAAK,EAAEA,EAAI,CAAC,EAAI,KAAK,EAAEA,CAAC,EAAIE,IAAS,KAAK,GAAGF,CAAC,EAAI,KAAK,GAAGA,EAAI,CAAC,IAAO,KAAK,EAAEA,CAAC,EAAI,KAAK,EAAEA,EAAI,CAAC,IAGxGG,EAAM,KAAK,GAAGH,EAAI,CAAC,GAAKG,EAAM,KAAK,GAAGH,EAAI,CAAC,EAC3C,KAAK,GAAGA,CAAC,EAAIG,EAEb,KAAK,GAAGH,CAAC,EAAI,KAAK,GAAGA,CAAC,EAAKE,GAAQ,KAAK,GAAGF,EAAIE,CAAI,EAAI,KAAK,GAAGF,CAAC,IAAO,KAAK,EAAEA,EAAIE,CAAI,EAAI,KAAK,EAAEF,CAAC,GAEtG,KAAK,EAAEA,CAAC,GAAKE,CACjB,CACJ,CACJ,CAEA,OAAgB,CACZ,GAAI,KAAK,MAAM,SAAW,EAAG,MAAO,KACpC,GAAI,KAAK,MAAM,OAAS,EAAG,CACvB,IAAME,EAAS,CAAC,GAAG,KAAK,KAAK,EAAE,KAAK,CAAC,EAAGC,IAAM,EAAIA,CAAC,EAC7CC,EAAM,KAAK,GAAKF,EAAO,OAAS,GAChCJ,EAAI,KAAK,MAAMM,CAAG,EAClBC,EAAOD,EAAMN,EACnB,OAAOA,EAAI,EAAII,EAAO,OAASA,EAAOJ,CAAC,GAAK,EAAIO,GAAQH,EAAOJ,EAAI,CAAC,EAAIO,EAAOH,EAAOJ,CAAC,CAC3F,CACA,OAAO,KAAK,GAAG,CAAC,CACpB,CAEQ,WAAY,CAChB,KAAK,MAAM,KAAK,CAACQ,EAAGH,IAAMG,EAAIH,CAAC,EAC/B,KAAK,GAAK,KAAK,MAAM,MAAM,EAAG,CAAC,EAE/B,KAAK,EAAI,CAAC,EAAG,EAAG,EAAG,EAAG,CAAC,EACvB,KAAK,GAAK,CAAC,EAAG,EAAI,EAAI,KAAK,EAAG,EAAI,EAAI,KAAK,EAAG,EAAI,EAAI,KAAK,EAAG,CAAC,CACnE,CACJ,ECrFO,IAAMI,GAAN,KAAc,CAAd,cACHC,EAAA,KAAQ,IAAI,GACZA,EAAA,KAAQ,OAAO,GAER,IAAIC,EAAW,CAClB,KAAK,IACL,IAAMC,EAAQD,EAAI,KAAK,KACvB,KAAK,MAAQC,EAAQ,KAAK,CAC9B,CAEA,IAAI,KAAM,CACN,OAAO,KAAK,EAAI,KAAK,KAAO,GAChC,CACJ,ECbO,IAAMC,GAAN,KAAkB,CAAlB,cACHC,EAAA,KAAQ,QAAQ,GAChBA,EAAA,KAAQ,SAAS,KACjBA,EAAA,KAAQ,SAAS,MACjBA,EAAA,KAAQ,OAAO,IAAIC,IACnBD,EAAA,KAAQ,MAAM,IAAIE,GAAW,EAAG,GAChCF,EAAA,KAAQ,MAAM,IAAIE,GAAW,GAAI,GAEjC,IAAIC,EAAW,CACPA,EAAI,KAAK,SAAQ,KAAK,OAASA,GAC/BA,EAAI,KAAK,SAAQ,KAAK,OAASA,GACnC,KAAK,KAAK,IAAIA,CAAC,EACf,KAAK,IAAI,IAAIA,CAAC,EACd,KAAK,IAAI,IAAIA,CAAC,EAEd,KAAK,OACT,CAEA,UAAW,CACP,MAAO,CACH,IAAK,KAAK,SAAW,IAAW,IAAM,KAAK,OAC3C,IAAK,KAAK,SAAW,KAAY,IAAM,KAAK,OAC5C,IAAK,CAAC,KAAK,KAAK,IAAI,QAAQ,EAC5B,OAAQ,CAAC,KAAK,IAAI,MAAM,EAAE,QAAQ,EAClC,IAAK,CAAC,KAAK,IAAI,MAAM,EAAE,QAAQ,EAC/B,MAAO,KAAK,KAChB,CACJ,CAEA,IAAI,SAAU,CACV,OAAO,KAAK,MAAQ,CACxB,CACJ,ECnCA,IAAWC,QACPA,EAAA,aAAe,eACfA,EAAA,OAAS,SACTA,EAAA,UAAY,YAHLA,QAAA,IAMJC,GAAQD,GCNf,IAAKE,QACDA,EAAA,iBAAmB,mBACnBA,EAAA,cAAgB,gBAChBA,EAAA,OAAS,SACTA,EAAA,kBAAoB,oBACpBA,EAAA,mBAAqB,qBACrBA,EAAA,oBAAsB,sBACtBA,EAAA,uBAAyB,yBACzBA,EAAA,0BAA4B,4BAC5BA,EAAA,2BAA6B,6BAC7BA,EAAA,eAAiB,iBACjBA,EAAA,oBAAsB,sBACtBA,EAAA,iBAAmB,mBACnBA,EAAA,iBAAmB,mBACnBA,EAAA,kBAAoB,oBACpBA,EAAA,wBAA0B,0BAC1BA,EAAA,4BAA8B,8BAC9BA,EAAA,gBAAkB,kBAClBA,EAAA,qBAAuB,uBACvBA,EAAA,gBAAkB,kBAClBA,EAAA,aAAe,eACfA,EAAA,eAAiB,iBACjBA,EAAA,eAAiB,iBACjBA,EAAA,YAAc,cACdA,EAAA,eAAiB,iBACjBA,EAAA,gBAAkB,kBAClBA,EAAA,iBAAmB,mBACnBA,EAAA,aAAe,eACfA,EAAA,YAAc,cACdA,EAAA,cAAgB,gBAChBA,EAAA,iBAAmB,mBACnBA,EAAA,gBAAkB,kBAClBA,EAAA,gBAAkB,kBAClBA,EAAA,eAAiB,iBACjBA,EAAA,2BAA6B,6BAC7BA,EAAA,oBAAsB,sBACtBA,EAAA,kBAAoB,oBACpBA,EAAA,mBAAqB,qBACrBA,EAAA,kBAAoB,oBACpBA,EAAA,SAAW,WACXA,EAAA,0BAA4B,4BAC5BA,EAAA,oBAAsB,sBACtBA,EAAA,oBAAsB,sBACtBA,EAAA,yBAA2B,2BAC3BA,EAAA,aAAe,eACfA,EAAA,cAAgB,gBAChBA,EAAA,0BAA4B,4BAC5BA,EAAA,0BAA4B,4BAC5BA,EAAA,4BAA8B,8BAC9BA,EAAA,YAAc,cACdA,EAAA,YAAc,cACdA,EAAA,kCAAoC,oCACpCA,EAAA,sBAAwB,wBApDvBA,QAAA,IAuDEC,EAAQD,GCvDf,IAAWE,QACPA,EAAA,qBAAuB,uBACvBA,EAAA,gBAAkB,kBAClBA,EAAA,oBAAsB,sBACtBA,EAAA,oBAAsB,sBACtBA,EAAA,IAAM,MACNA,EAAA,QAAU,UANHA,QAAA,IASJC,GAAQD,GCPf,GAAM,CAAE,SAAAE,GAAU,gBAAAC,EAAgB,EAAIC,EA0C/B,SAASC,GAAqBC,EAA2BC,EAAoC,CAChG,OAAID,IAAQ,MAAQC,IAAQ,KACjBD,IAAQ,MAAQC,IAAQ,KAE/BD,EAAI,eAAiBC,EAAI,cAGzBD,EAAI,cAAgBC,EAAI,aAGxBD,EAAI,eAAiBC,EAAI,cAGzBD,EAAI,wBAA0BC,EAAI,uBAGlCD,EAAI,kBAAoBC,EAAI,iBAI5BL,GAASI,EAAI,QAAQ,GAAKJ,GAASK,EAAI,QAAQ,GAAK,CAACJ,GAAgBG,EAAI,SAAUC,EAAI,SAAU,EAAI,EAC9F,GACAD,EAAI,WAAaC,EAAI,QAKpC,CCzDO,SAASC,GAAsBC,EAAqBC,EAA8B,CAOrF,MANI,GAACC,GAAqBF,EAAI,OAAQC,EAAI,MAAM,GAG5C,CAACC,GAAqBF,EAAI,cAAeC,EAAI,aAAa,GAG1D,CAACC,GAAqBF,EAAI,kBAAmBC,EAAI,iBAAiB,EAI1E,CAEO,SAASE,GAAMC,EAAoBC,EAAuB,CAC7D,MAAO,CACH,OAAQ,OAAO,OAAO,CAAC,EAAGD,EAAG,OAAQC,EAAM,MAAM,EACjD,cAAe,OAAO,OAAO,CAAC,EAAGD,EAAG,cAAeC,EAAM,aAAa,EACtE,kBAAmB,OAAO,OAAO,CAAC,EAAGD,EAAG,kBAAmBC,EAAM,iBAAiB,CACtF,CACJ,CAEO,SAASC,IAA4C,CACxD,MAAO,CAAE,OAAQ,KAAM,cAAe,KAAM,kBAAmB,IAAK,CACxE,CCdO,IAAMC,GAAN,MAAMA,EAAqB,CAA3B,cAGHC,EAAA,KAAiB,eAAe,IAAI,KACpCA,EAAA,KAAQ,8BAAmE,IAAG,IAE9E,OAAO,OAAOC,EAAkE,CAC5E,IAAMC,EAAiC,IAAIH,GAC3CG,EAAS,4BAA8BD,EACvCF,GAAqB,UAAYG,CACrC,CAEA,OAAO,YAAYC,EAAgB,CAC/B,IAAMD,EAAWH,GAAqB,UAChCK,EAAYF,GAAU,4BAA4B,EACxD,GAAI,CAACA,GAAY,CAACE,EACd,OAGJ,IAAIC,EAAeF,EAAK,KAEnB,OAAQG,GAAQA,EAAI,OAAS,gBAAkB,CAACA,EAAI,KAAK,SAAS,GAAG,CAAC,EAEvEC,EAAO,YAIPF,EAAeA,EAAa,OAAkB,CAACG,EAAKF,IAAQ,CACxD,GAAIA,EAAI,OAAS,QACb,OAAOE,EAAI,OAAOF,CAAG,EAGzB,IAAMG,EAAYD,EAAI,KAAME,GAASA,EAAK,OAAS,OAAO,EAC1D,OAAID,EACAA,EAAU,iBAAmBA,EAAU,iBAAmB,IAAMH,EAAI,iBAAmB,GAEvFE,EAAI,KAAKF,CAAG,EAETE,CACX,EAAG,CAAC,CAAC,GAETH,EAAa,QAASC,GAAQ,CAC1B,IAAMK,EAAOL,EAAI,KACXM,EAAWN,EAAI,SACrB,IAAKK,IAAS,SAAWA,IAAS,UAAYC,EAAU,CACpD,IAAMC,EAAiBP,EAAI,sBACrBQ,EAAY,CAACF,EAAU,UAAWC,CAAc,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAChFX,EAAS,UAAU,CACf,KAAAS,EACA,UAAAG,EACA,iBAAkBR,EAAI,iBAAmB,GAAK,IAC9C,iBAAkBA,EAAI,YACtB,SAAUF,CACd,CAAC,CACL,CACJ,CAAC,CACL,CAEQ,UAAU,CAAE,KAAAO,EAAM,UAAAG,EAAW,gBAAAC,EAAiB,iBAAAC,EAAkB,SAAAC,CAAS,EAAe,CAC5F,IAAMC,EAAY,KAAK,aAAa,IAAIP,CAAI,EAM5C,GAJIO,GAAaA,EAAU,YAAcJ,GACrC,KAAK,OAAOI,CAAS,EAGrBA,GAAaA,EAAU,YAAcJ,EAAW,CAChD,KAAK,aAAa,IAAIH,EAAM,CACxB,GAAGO,EACH,gBAAAH,EACA,SAAAE,CACJ,CAAC,EACD,MACJ,CAEA,KAAK,aAAa,IAAIN,EAAM,CACxB,KAAAA,EACA,UAAAG,EACA,iBAAAE,EACA,gBAAAD,EACA,SAAAE,CACJ,CAAC,CACL,CAEQ,OAAOE,EAAwB,CAEnC,GAAIA,EAAW,OAAS,SAAWA,EAAW,kBAAoB,EAC9D,OAGJ,IAAMC,EAMF,CACA,KAAMC,EAAK,YACX,qBAAsBF,EAAW,UACjC,MAAOA,EAAW,gBAClB,cAAeA,EAAW,WAAa,SAA2B,IAAM,GAC5E,EAEIA,EAAW,mBACXC,EAAI,aAAeD,EAAW,kBAGlCG,EAAO,eAAeF,CAAG,CAC7B,CAEA,OAAO,SAAU,CACbrB,GAAqB,WAAW,SAAS,EACzCA,GAAqB,UAAY,IACrC,CAEQ,UAAW,CAEf,KAAK,aAAa,QAASoB,GAA2B,CAClD,KAAK,OAAOA,CAAU,CAC1B,CAAC,EACD,KAAK,aAAa,MAAM,CAC5B,CACJ,EAxHInB,EADSD,GACM,YAAyC,MADrD,IAAMwB,GAANxB,GClBP,IAA8ByB,GAA9B,cAAoDC,EAAa,CAMnD,YAAYC,EAA0BC,EAA0B,CACtE,MAAM,EANVC,EAAA,KAAmB,cACnBA,EAAA,KAAmB,gBACnBA,EAAA,KAAU,iBACVA,EAAA,KAAU,MAAgC,MAKtC,KAAK,WAAaF,EAClB,KAAK,aAAeC,CACxB,CAEA,UAA2B,CACvB,OAAO,KAAK,QAAU,MAC1B,CAGJ,ECTA,IAAME,GAAkC,gBAClCC,GAAmC,IACnCC,GAAsC,IAEvBC,GAArB,cAA8CC,EAAa,CAWvD,YAAYC,EAA8CC,EAA0BC,EAAiB,GAAO,CACxG,MAAM,EAXVC,EAAA,KAAQ,mCAAmC,GAC3CA,EAAA,KAAQ,sCAAsC,KAAK,IAAI,GACvDA,EAAA,KAAQ,mCAAmC,KAAK,IAAI,GACpDA,EAAA,KAAQ,0BAAiD,MACzDA,EAAA,KAAQ,oBAAwC,CAAC,GAEjDA,EAAA,KAAQ,cAERA,EAAA,KAAiB,mBA2RjBA,EAAA,KAAQ,2BAAqCC,GAAS,CAClD,KAAK,kBAAkB,KAAKA,CAAI,CACpC,GAEAD,EAAA,KAAQ,+BAAgCE,GAA0B,EAGzD,KAAK,iBAAmBA,IAAU,aAA8B,CAAC,KAAK,iBAAmBA,IAAU,YACpG,KAAK,oCAAsC,KAAK,IAAI,EACpD,KAAK,iCAAmC,KAAK,IAAI,EAEzD,GAjSI,KAAK,WAAaJ,EAClB,KAAK,gBAAkBC,EAEvB,KAAK,UAAUF,sBAA6C,KAAK,aAAa,KAAK,IAAI,CAAC,EACxF,KAAK,UAAUA,wBAA+C,KAAK,yBAAyB,KAAK,IAAI,CAAC,EACtG,KAAK,UAAUA,kBAAyC,KAAK,6BAA6B,KAAK,IAAI,CAAC,CACxG,CAEA,SAAU,CACN,KAAK,YAAY,CACrB,CAEA,OAAO,8BAA+B,CAClC,GAAI,CACA,IAAMM,EAAQ,SAAS,aAAa,QAAQX,EAA+B,GAAK,GAAI,EAAE,EACtF,OAAO,MAAMW,CAAK,EAAI,EAAIA,CAC9B,MAAY,CACR,MAAO,EACX,CACJ,CAEA,MAAc,aAAaC,EAAmB,CAC1C,GAAI,CAACA,EAAM,SAAW,CAACA,EAAM,QAAQ,KACjC,OAGJ,IAAMC,EAAY,KAAK,IAAI,EAEvB,CAAC,KAAK,iBAAmBC,EAAO,uBAAyB,KAAK,iCAAmCb,IAAoCY,IACrI,MAAM,KAAK,gBAAgBD,CAAK,EAChC,KAAK,iCAAmCC,GAG5C,IAAME,EAAQH,EAAM,SAAS,UAAU,OAAO,WAAa,MACvD,CAAC,KAAK,iBAAmBG,GAAS,KAAK,oCAAsCb,IAAuCW,IACpH,MAAM,KAAK,mBAAmBD,CAAK,EACnC,KAAK,oCAAsCC,GAG3CC,EAAO,uBAAyB,KAAK,iCAAmCA,EAAO,oBAAsBD,IACrG,KAAK,iBAAiBD,CAAK,EAC3B,KAAK,iCAAmCC,EAEhD,CAEA,MAAc,gBAAgBD,EAAmB,CAC7C,IAAMI,EAAyBJ,EAAM,QAAQ,KAAK,OAC9C,CAACK,EAAKC,KACEA,EAAI,OAAS,UACbD,EAAI,eAAiBC,EAAI,eAAiB,EAC1CD,EAAI,gBAAkBC,EAAI,gBAAkB,GAEzCD,GAEX,CAAE,cAAe,EAAG,eAAgB,CAAE,CAC1C,EAEA,GAAID,EAAO,cACP,GAAI,CACA,IAAMG,EAAW,MAAM,KAAK,WAAW,eAAeH,CAAM,EAC5D,aAAa,QAAQhB,GAAiCmB,EAAS,yBAAyB,CAC5F,MAAY,CAEZ,CAER,CAEA,MAAc,mBAAmBP,EAAmB,CAChD,IAAMI,EAA4B,CAC9B,UAAWJ,EAAM,SAAS,UAAU,UACpC,YAAaA,EAAM,SAAS,KAAK,OAAO,CAACQ,EAAQF,IAAQE,GAAUF,EAAI,WAAa,GAAK,EAAG,CAAC,CACjG,EAEA,GAAIF,EAAO,UACP,GAAI,CACA,MAAM,KAAK,WAAW,kBAAkBA,CAAM,CAClD,MAAY,CAEZ,CAER,CAEQ,iBAAiBJ,EAAmB,CACxC,IAAMS,EAAiC,CACnC,cAAe,KAAK,gBAAkB,IAAM,IAC5C,gBAAiB,EACjB,cAAe,EACf,aAAc,EACd,aAAc,EACd,eAAgB,EAChB,aAAc,EACd,aAAc,EACd,0BAA2B,EAC3B,UAAW,EACX,SAAU,EACV,SAAU,EACV,6BAA8B,EAC9B,wBAAyB,EACzB,+BAAgC,EAChC,wCAAyC,EACzC,uCAAwC,EACxC,yBAA0B,EAC1B,mBAAoB,EACpB,oBAAqB,EACrB,oBAAqB,EACrB,mBAAoB,EACpB,mBAAoB,EACpB,mBAAoB,EACpB,mBAAoB,EACpB,aAAc,EACd,uBAAwB,EACxB,IAAK,KAAK,MAAMT,EAAM,QAAQ,UAAU,qBAAuB,GAAI,EACnE,gBAAiB,EACjB,0BAA2B,EAC3B,cAAeU,GAAeV,EAAM,QAAQ,UAAU,KAAK,EAC3D,sBAAuBA,EAAM,QAAQ,UAAU,OAAO,KACtD,aAAcA,EAAM,QAAQ,UAAU,OAAO,YAC7C,UAAWA,EAAM,QAAQ,UAAU,OAAO,SAC1C,eAAgBU,GAAeV,EAAM,QAAQ,UAAU,MAAM,EAC7D,uBAAwBA,EAAM,QAAQ,UAAU,QAAQ,IAC5D,EAEK,KAAK,0BACN,KAAK,wBAA0B,OAAO,OAAO,CAAC,EAAGS,CAAc,GAGnE,IAAIE,EAAiB,GACjBC,EAAiB,GA6DrB,IA3DAZ,EAAM,QAAQ,KAAK,OAAO,CAACK,EAAKC,KACxBA,EAAI,OAAS,SACbK,EAAiB,GACbL,EAAI,iBAEJD,EAAI,aAAgBA,EAAI,aAAeA,EAAI,qBAAwBA,EAAI,oBAAsB,GAAMC,EAAI,OAAS,KAASD,EAAI,oBAAsB,GACnJA,EAAI,0BACCA,EAAI,0BAA4BA,EAAI,qBAAwBA,EAAI,oBAAsB,IACrFC,EAAI,yBAA2B,GAAK,KAAYD,EAAI,oBAAsB,GAChFA,EAAI,uBAGRA,EAAI,gBAAkBC,EAAI,eAAiB,EAC3CD,EAAI,WAAaC,EAAI,UACrBD,EAAI,UAAYC,EAAI,SACpBD,EAAI,UAAYC,EAAI,SACpBD,EAAI,cAAgBC,EAAI,kBAAoB,EAC5CD,EAAI,wBAA0BC,EAAI,2BAA6B,IAE/DM,EAAiB,GACbN,EAAI,uBAEJD,EAAI,aAAgBA,EAAI,aAAeA,EAAI,qBAAwBA,EAAI,oBAAsB,GAAMC,EAAI,OAAS,KAASD,EAAI,oBAAsB,GACnJA,EAAI,mBACCA,EAAI,mBAAqBA,EAAI,qBAAwBA,EAAI,oBAAsB,IAAMC,EAAI,kBAAoB,IAAMD,EAAI,oBAAsB,GAClJA,EAAI,uBAGRA,EAAI,8BAAgCC,EAAI,sBAAwB,EAChED,EAAI,yCAA2CC,EAAI,gCAAkC,EACrFD,EAAI,wCAA0CC,EAAI,+BAAiC,EACnFD,EAAI,yBAA2BC,EAAI,kBAAoB,EACvDD,EAAI,gCAAkCC,EAAI,wBAA0B,EACpED,EAAI,0BAA4BC,EAAI,mBAAqB,GAEtDD,GACRI,CAAc,EAEjBT,EAAM,SAAS,KAAK,OAAO,CAACK,EAAKC,KACzBA,EAAI,OAAS,SACbD,EAAI,eAAiBC,EAAI,UACzBD,EAAI,cAAgBC,EAAI,SACxBD,EAAI,cAAgBC,EAAI,SACxBD,EAAI,oBAAsBC,EAAI,aAE9BD,EAAI,oBAAsBC,EAAI,YAE3BD,GACRI,CAAc,EAEjBT,EAAM,cAAc,KAAK,OAAO,CAACK,EAAKC,KAC9BA,EAAI,OAAS,QACbD,EAAI,oBAAsBC,EAAI,YAE9BD,EAAI,oBAAsBC,EAAI,YAE3BD,GACRI,CAAc,EAEV,KAAK,kBAAkB,QAAQ,CAClC,IAAMZ,EAAO,KAAK,kBAAkB,IAAI,EACpCA,GAAM,kBACNY,EAAe,iBAAmB,EAClCA,EAAe,2BAA6BZ,EAAK,gBAEzD,CAEA,IAAMgB,EAAyB,CAC3B,cAAeJ,EAAe,cAC9B,gBAAiB,KAAK,IAAI,EAAG,KAAK,IAAI,EAAI,KAAK,gCAAgC,EAC/E,UAAW,KAAK,IAAI,EAAGA,EAAe,UAAY,KAAK,wBAAwB,SAAS,EACxF,cAAe,KAAK,IAAI,EAAGA,EAAe,cAAgB,KAAK,wBAAwB,aAAa,EACpG,SAAU,KAAK,IAAI,EAAGA,EAAe,SAAW,KAAK,wBAAwB,QAAQ,EACrF,aAAc,KAAK,IAAI,EAAGA,EAAe,aAAe,KAAK,wBAAwB,YAAY,EACjG,SAAU,KAAK,IAAI,EAAGA,EAAe,SAAW,KAAK,wBAAwB,QAAQ,EACrF,aAAc,KAAK,IAAI,EAAGA,EAAe,aAAe,KAAK,wBAAwB,YAAY,EACjG,eAAgB,KAAK,IAAI,EAAGA,EAAe,eAAiB,KAAK,wBAAwB,cAAc,EACvG,IAAK,KAAK,IAAI,EAAGA,EAAe,GAAG,CACvC,EAuBA,GArBI,UAAU,sBACVI,EAAS,yBAA2B,UAAU,qBAG9CF,GAAkB,CAACG,GAAYL,EAAe,YAAY,IAC1DI,EAAS,aAAe,KAAK,MAAMJ,EAAe,YAAY,GAE9DG,GAAkB,CAACE,GAAYL,EAAe,YAAY,IAC1DI,EAAS,aAAe,KAAK,MAAMJ,EAAe,YAAY,GAE9DE,GAAkB,CAACG,GAAYL,EAAe,yBAAyB,IACvEI,EAAS,0BAA4BJ,EAAe,2BAEpDA,EAAe,cAAgBA,EAAe,yBAC9CI,EAAS,aAAeJ,EAAe,aACvCI,EAAS,uBAAyB,KAAK,MAAMJ,EAAe,uBAAyB,GAAI,GAEzFA,EAAe,iBAAmBA,EAAe,4BACjDI,EAAS,gBAAkBJ,EAAe,gBAC1CI,EAAS,0BAA4BJ,EAAe,2BAEpDG,GAAkB,CAACE,GAAYL,EAAe,4BAA4B,EAAG,CAC7E,IAAMM,EAAoB,KAAK,IAAI,EAAGN,EAAe,6BAA+B,KAAK,wBAAwB,4BAA4B,EACvIO,EAAuB,KAAK,IAAI,EAAGP,EAAe,wCAA0C,KAAK,wBAAwB,uCAAuC,EAChKQ,EAAsB,KAAK,IAAI,EAAGR,EAAe,uCAAyC,KAAK,wBAAwB,sCAAsC,EAC7JS,EAAwB,KAAK,IAAI,EAAGT,EAAe,wBAA0B,KAAK,wBAAwB,uBAAuB,EACjIU,EAA8B,KAAK,IAAI,EAAGV,EAAe,+BAAiC,KAAK,wBAAwB,8BAA8B,EACrJW,EAAyB,KAAK,IAAI,EAAGX,EAAe,yBAA2B,KAAK,wBAAwB,wBAAwB,EAG1II,EAAS,wCAA0CQ,GAAOL,EAAuBD,EAAqB,GAAI,EAC1GF,EAAS,uCAAyCQ,GAAOJ,EAAsBF,EAAqB,GAAI,EACxGF,EAAS,wBAA0BQ,GAAOH,EAAwBH,EAAqB,GAAI,EAC3FF,EAAS,+BAAiCQ,GAAOF,EAA8BJ,EAAqB,GAAI,EACxGF,EAAS,2BAA6BQ,GAAMH,EAAwBE,CAAsB,EAE1FP,EAAS,mBAAqBJ,EAAe,kBACjD,CACIa,GAAcb,EAAgB,gBAAiB,wBAAyB,eAAgB,WAAW,IACnGI,EAAS,cAAgBJ,EAAe,cACxCI,EAAS,sBAAwBJ,EAAe,sBAChDI,EAAS,aAAeJ,EAAe,aACvCI,EAAS,UAAYJ,EAAe,WAEpCa,GAAcb,EAAgB,iBAAkB,wBAAwB,IACxEI,EAAS,eAAiBJ,EAAe,eACzCI,EAAS,uBAAyBJ,EAAe,wBAGrD,IAAMc,EAAwB,KAAK,IAAI,EAAGd,EAAe,mBAAqB,KAAK,wBAAwB,kBAAkB,EACvHe,EAAwB,KAAK,IAAI,EAAGf,EAAe,mBAAqB,KAAK,wBAAwB,kBAAkB,EAE7H,GAAIc,EAAwB,EAAG,CAC3B,IAAME,EAAwB,KAAK,IAAI,EAAGhB,EAAe,mBAAqB,KAAK,wBAAwB,kBAAkB,EAC7HI,EAAS,WAAaQ,GAAOI,EAAwBF,EAAyB,GAAG,CACrF,CACA,GAAIC,EAAwB,EAAG,CAC3B,IAAME,EAAwB,KAAK,IAAI,EAAGjB,EAAe,mBAAqB,KAAK,wBAAwB,kBAAkB,EAC7HI,EAAS,WAAaQ,GAAOK,EAAwBF,EAAyB,GAAG,CACrF,CAEAG,GAAe,YAAYd,CAAQ,EAC/BX,EAAO,yBACP0B,EAAM,IAAI,kBAAmBf,CAAQ,EAGzC,KAAK,wBAA0BJ,CACnC,CAcJ,EAEA,SAASa,GAAgCO,KAAWC,EAA4B,CAC5E,QAAWC,KAAOD,EACd,GAAI,CAAC,OAAO,OAAOD,EAAKE,CAAG,GAAKF,EAAIE,CAAG,IAAM,OACzC,MAAO,GAGf,MAAO,EACX,CAEA,SAASrB,GAAeb,EAAgCmC,EAAc,GAA2B,CAC7F,GAAKnC,GAAM,QAIX,OAAOA,EAAK,SAAWmC,EAAc,IAAInC,EAAK,IAAI,GAAK,GAC3D,CAEA,SAASiB,GAAYmB,EAAoC,CACrD,OAAOA,IAAU,MACrB,CAEA,SAASZ,GAAMY,EAAe,CAC1B,OAAO,OAAO,MAAMA,CAAK,EAAI,EAAIA,CACrC,CC3VO,IAAMC,GAAN,KAAsB,CAKzB,YAAYC,EAAkBC,EAA4B,KAAM,CAJhEC,EAAA,KAAiB,YACjBA,EAAA,KAAiB,cACjBA,EAAA,KAAQ,QAAQ,KAGZ,KAAK,SAAWF,EAChB,KAAK,WAAaC,GAAcD,CACpC,CAEA,IAAIG,EAAqB,CACrB,KAAK,MAAQA,CACjB,CAEA,OAAOA,EAAuB,CAC1B,YAAK,MAAQ,KAAK,QAAQA,CAAK,EACxB,KAAK,KAChB,CAEA,QAAQA,EAAuB,CAC3B,GAAI,MAAM,KAAK,KAAK,EAChB,OAAOA,EAGX,IAAMC,EAASD,EAAQ,KAAK,MAAQ,KAAK,WAAa,KAAK,SAC3D,OAAO,KAAK,OAAS,EAAIC,GAAUD,EAAQC,CAC/C,CAEA,UAAmB,CACf,OAAO,KAAK,KAChB,CACJ,ECrBA,IAAMC,GAAa,IACbC,GAAc,IAEdC,GAAW,GACXC,GAAkB,GAElBC,GAAY,IACZC,GAAmB,GAEnBC,GAAkC,EAElCC,GAAwB,GACxBC,GAAuB,GAqC7B,IAAqBC,GAArB,cAAgDC,EAAa,CAmBzD,YAAYC,EAA0B,CAClC,MAAM,EAnBVC,EAAA,KAAiB,cACjBA,EAAA,KAAiB,qBACjBA,EAAA,KAAiB,sBACjBA,EAAA,KAAiB,oBACjBA,EAAA,KAAiB,iBAAgC,CAC7C,OAAQ,CACJ,KAAM,EACN,IAAK,GACT,EACA,QAAS,CACL,KAAM,GACN,IAAK,GACT,CACJ,GAEAA,EAAA,KAAQ,yBAAyB,GACjCA,EAAA,KAAQ,gBAAgB,QAIpB,KAAK,WAAaD,EAElB,KAAK,kBAAoB,CACrB,IAAK,IAAIE,GAAgBC,GAAYA,EAAU,EAC/C,KAAM,IAAID,GAAgBE,GAAaA,EAAW,EAClD,QAAS,CACb,EAEA,KAAK,mBAAqB,CACtB,IAAK,EACL,KAAM,EACN,QAAS,CACb,EAEA,KAAK,iBAAmB,CACpB,IAAK,EACL,KAAM,EACN,KAAM,CACV,CACJ,CAEQ,eAAeC,EAAuC,CAC1D,IAAMC,EAAW,OAAOD,GAAQ,SAAWA,EAAMA,EAAI,SAAS,EAC1DE,EAAS,EAEb,GAAI,MAAMD,CAAQ,EACd,OAAOC,EAGX,IAAMC,EAAW,KAAK,OAAOF,EAAW,KAAK,eAAe,QAAQ,KAAOG,EAAQ,EACnF,QAASC,EAAI,EAAGA,EAAIF,EAAUE,IAC1BH,GAAU,EAAII,GAGlB,OAAOJ,CACX,CAEQ,gBAAgBK,EAAwC,CAC5D,IAAMC,EAAY,OAAOD,GAAS,SAAWA,EAAOA,EAAK,SAAS,EAC9DL,EAAS,EAEb,GAAI,MAAMM,CAAS,EACf,OAAON,EAGX,IAAMO,EAAY,KAAK,OAAOD,EAAY,KAAK,eAAe,QAAQ,MAAQE,EAAS,EACvF,QAASL,EAAI,EAAGA,EAAII,EAAWJ,IAC3BH,GAAU,EAAIS,GAGlB,OAAOT,CACX,CAEQ,mBAAmBU,EAAkBC,EAA0B,CACnE,GAAI,CAACD,GAAY,CAACC,EACd,MAAO,GAKX,IAAMX,EAAS,GAAK,EAFM,KAAK,IAAIU,EAAUC,CAAQ,EAAI,KAAK,IAAID,EAAUC,CAAQ,GAEvCC,GAC7C,OAAO,KAAK,IAAIZ,EAAQ,CAAC,CAC7B,CAEQ,eAAe,CAAE,IAAAF,EAAK,KAAAO,CAAK,EAAgB,CAC/C,OAAO,KAAK,eAAeP,CAAG,EAAI,KAAK,gBAAgBO,CAAI,CAC/D,CAEQ,YAAYQ,EAAoCC,EAAsCC,EAAgB,CAC1G,OAAKA,EAIE,KAAK,mBAAmBF,EAAiB,QAASC,EAAkB,OAAO,EAHvE,KAAK,eAAeD,CAAgB,EAAI,KAAK,eAAeC,CAAiB,CAI5F,CAEQ,iBAAiBd,EAA8B,CACnD,OAAI,MAAMA,CAAM,GAAKA,GAAUgB,GACpB,OAGPhB,GAAUiB,GACH,SAGJ,KACX,CAEA,eAAeC,EAA0B,CACrC,OAAO,OAAO,KAAK,eAAe,OAAQA,GAAU,QAAU,CAAC,CAAC,EAChE,OAAO,OAAO,KAAK,eAAe,QAASA,GAAU,SAAW,CAAC,CAAC,CACtE,CAEA,YAAYC,EAAmB,CAC3B,GAAI,CAAC,KAAK,WAAW,MACjB,OAGJ,IAAMJ,EAAQI,EAAM,SAAS,UAAU,OAAO,WAAa,MACrDrB,EAAM,KAAK,IAAI,EAAG,KAAK,MAAMqB,EAAM,SAAS,UAAU,qBAAuB,GAAI,GAAK,CAAC,EACvFd,EAAOc,EAAM,QAAQ,KAAK,OAAO,CAACC,EAAQC,IAAQ,KAAK,IAAID,EAAQC,EAAI,YAAc,CAAC,EAAG,CAAC,EAE1FC,EAA+F,CACjG,IAAK,KAAK,kBAAkB,IAAI,OAAOxB,CAAG,EAC1C,KAAM,KAAK,kBAAkB,KAAK,OAAOO,CAAI,CACjD,EAEA,GAAIU,EAAO,CAEP,IAAMQ,EAAUJ,EAAM,SAAS,KAAK,OAAO,CAACC,EAAQC,IAAQD,GAAUC,EAAI,WAAa,GAAK,EAAG,CAAC,EAChGC,EAAW,QAAUC,EACrB,KAAK,kBAAkB,QAAUA,CACrC,CAEA,IAAMC,EAAM,KAAK,IAAI,EACfxB,EAAS,KAAK,YAAY,KAAK,kBAAmB,KAAK,mBAAoBe,CAAK,EAChFU,EAAgB,KAAK,IAAI,KAAK,MAAMzB,EAAS,EAAE,EAAI,GAAI,EAAG,EAC1D0B,EAAe,KAAK,iBAAiBD,CAAa,GAGpDV,GACAW,IAAiB,KAAK,eACtBF,EAAM,KAAK,uBAAyBG,EAAO,6BAE3C,KAAK,uBAAyBH,EAC9B,KAAK,WACA,WACG,CACI,IAAK,OAAO,OAAO,CAAE,KAAM,SAAU,EAAGF,CAAU,CACtD,EACA,IACJ,EACC,MAAOM,GAAM,CAEVC,EAAM,KAAK,2BAA4BD,CAAC,CAC5C,CAAC,GAGT,KAAK,cAAgBF,EACrB,KAAK,+BAA6CD,CAAa,CACnE,CAEA,aAAaK,EAA6B,CACtC,GAAM,CAAE,IAAAhC,EAAK,KAAAO,EAAM,QAAAkB,CAAQ,EAAIO,GAAQ,CAAC,EACxC,KAAK,mBAAmB,IAAMhC,GAAO,EACrC,KAAK,mBAAmB,KAAOO,GAAQ,EACvC,KAAK,mBAAmB,QAAUkB,GAAW,CACjD,CACJ,EC3MA,IAAMQ,GAAkC,GAAK,IAExBC,GAArB,MAAqBC,UAAwBC,EAAc,CAkDvD,YAAYC,EAA8BC,EAAmBC,EAA0BC,EAA0BC,EAAgC,CAC7I,MAAMF,EAAWC,CAAW,EAlDhCE,EAAA,KAAiB,kBACjBA,EAAA,KAAiB,aAEjBA,EAAA,KAAQ,aAAkE,CAAC,GAC3EA,EAAA,KAAQ,oBAA2D,CAAC,GACpEA,EAAA,KAAQ,iBAAmD,MAC3DA,EAAA,KAAQ,sBAA6C,MACrDA,EAAA,KAAQ,mBAA2C,MACnDA,EAAA,KAAQ,iBAAuC,MAC/CA,EAAA,KAAQ,wBAAwC,GAChDA,EAAA,KAAQ,UAAU,IAClBA,EAAA,KAAQ,gBAA+B,MACvCA,EAAA,KAAQ,gBAA+B,MACvCA,EAAA,KAAQ,oBAAmC,MAC3CA,EAAA,KAAQ,kBAAuB,MAC/BA,EAAA,KAAQ,gBAAoC,MAC5CA,EAAA,KAAQ,qBAAoC,MAC5CA,EAAA,KAAQ,uBAAsC,MAC9CA,EAAA,KAAQ,yBAAyB,IACjCA,EAAA,KAAQ,aACRA,EAAA,KAAQ,eAA8B,MACtCA,EAAA,KAAQ,kBAAkB,IAC1BA,EAAA,KAAQ,mBACRA,EAAA,KAAQ,wBAA6B,CAAC,GAEtCA,EAAA,KAAQ,yBAAyB,CAC7B,IAAK,CACD,KAAM,EACN,IAAK,GACT,EACA,KAAM,CACF,KAAM,EACN,IAAK,GACT,CACJ,GAEAA,EAAA,KAAQ,4BAA4B,CAChC,MAAO,IACP,IAAK,IACL,KAAM,IACV,GAEAA,EAAA,KAAQ,yBAAiC,KAAK,0BAA0B,MAExEA,EAAA,KAAQ,qBAAqB,GAE7BA,EAAA,KAAQ,qBACRA,EAAA,KAAQ,uBAKJ,KAAK,eAAiBL,EACtB,KAAK,UAAYC,EACjB,KAAK,gBAAkBG,EAEvB,KAAK,kBAAoB,IAAIE,GAAiB,KAAMJ,EAAW,EAAI,EACnE,KAAK,oBAAsB,IAAIK,GAAmBL,CAAS,EAE3D,KAAK,UAAU,KAAK,WAAYM,GAAe,aAAc,KAAK,yBAAyB,KAAK,IAAI,CAAC,EACrG,KAAK,UAAU,KAAK,8BAA+C,KAAK,iBAAiB,KAAK,IAAI,CAAC,EACnG,KAAK,UAAU,KAAK,8BAA+C,KAAK,eAAe,KAAK,IAAI,CAAC,EACjG,KAAK,UAAU,KAAK,qCAAoD,KAAK,iBAAiB,KAAK,IAAI,CAAC,EAExG,GAAI,CACA,KAAK,IAAM,IAAI,kBAAkB,CAC7B,WAAYC,EAAO,WACnB,mBAAoBA,EAAO,iBAAmB,QAAU,KAC5D,CAAC,CACL,OAASC,EAAY,CACjBC,EAAM,MAAM,sCAAuCD,CAAK,EACxD,KAAK,MAAMA,CAAK,EAChB,MACJ,CAkBA,GAhBA,KAAK,IAAI,eAAiB,KAAK,oBAAoB,KAAK,IAAI,EAC5D,KAAK,IAAI,QAAU,KAAK,YAAY,KAAK,IAAI,EAC7C,KAAK,IAAI,2BAA6B,KAAK,4BAA4B,KAAK,IAAI,EAChF,KAAK,IAAI,wBAA0B,KAAK,yBAAyB,KAAK,IAAI,EAC1E,KAAK,IAAI,uBAAyB,KAAK,wBAAwB,KAAK,IAAI,EACxE,KAAK,sBAAwB,CAAC,EAE1BD,EAAO,OACP,KAAK,mBAAmB,KAAK,IAAKG,GAAiB,QAAUC,GAAgC,CACzF,KAAK,oBAAsBA,EAC3B,KAAK,oBAAoB,WAAa,cACtC,KAAK,kBAAkB,eAAe,KAAK,mBAAmB,EAC9D,KAAK,gBAAgB,eAAe,KAAK,mBAAmB,CAChE,CAAC,EAGD,KAAK,UAAW,CAChB,GAAI,CACA,KAAK,aAAa,yBAAyB,KAAK,IAAK,GAAO,EAAI,EAChE,KAAK,eAAe,CACxB,OAASH,EAAO,CACZI,EAAO,IAAIC,EAAQ,MAAO,iBAAiB,EAC3CJ,EAAM,MAAM,oCAAqCD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EAE9F,KAAK,gBAAkBA,EAEvB,MACJ,CAEA,KAAK,aAAa,EAAK,EAAE,MAAOA,GAAe,CACvC,KAAK,SAAW,OAChB,KAAK,gBAAkBA,EAEvB,KAAK,MAAMA,CAAK,CAExB,CAAC,CACL,CAEA,KAAK,uBAAuB,CAChC,CAEA,IAAI,eAA+B,CAC/B,OAAO,KAAK,cAChB,CAEA,0BAA2B,CACvB,KAAK,kBAAkB,EAElB,KAAK,kBAAkB,GACxB,KAAK,mBAAmB,CAEhC,CAEQ,mBAA6B,CACjC,MAAO,yBAAkE,EAAE,SAAS,KAAK,SAAS,CAAC,CACvG,CAEA,MAAM,KAAKM,EAAwB,KAAM,CACrC,GAAI,KAAK,QAAS,CACdL,EAAM,KAAK,kCAAmC,CAAE,cAAe,KAAK,cAAe,CAAC,EACpF,MACJ,CAEA,GAAI,KAAK,gBAAiB,CACtB,KAAK,MAAM,KAAK,eAAe,EAC/B,MACJ,CAOA,GALAA,EAAM,MAAM,kCAAmC,CAAE,cAAe,KAAK,cAAe,CAAC,EAErF,KAAK,QAAU,GACf,KAAK,cAAgBK,EAEjB,CAAC,KAAK,UACN,GAAI,CACA,KAAK,aAAa,yBAAyB,KAAK,IAA0B,GAAO,EAAI,EACrF,KAAK,eAAe,CACxB,OAASN,EAAY,CACjBI,EAAO,IAAIC,EAAQ,MAAO,iBAAiB,EAC3CJ,EAAM,MAAM,qDAAsDD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EAE/G,KAAK,MAAMA,CAAK,EAChB,MACJ,CAMJ,KAAK,kBAA+B,EAEpC,IAAIO,EAAYD,EAChB,GAAI,CAACA,EAAQ,CACT,IAAME,EAAa,OAAO,KAAK,KAAK,UAAU,EAC9CD,EAAYC,EAAWA,EAAW,OAAS,CAAC,CAChD,CAEA,GAAID,GAAa,KAAK,WAAWA,CAAS,EACtC,GAAI,CACA,MAAM,KAAK,sBAAsBA,EAAW,KAAK,WAAWA,CAAS,CAAC,CAC1E,MAAY,CACR,KAAK,MAAM,EACX,MACJ,CAGJ,KAAK,WAAa,CAAC,EACnB,KAAK,kBAAoB,CAAC,CAC9B,CAEA,eAAeE,EAA0B,CACjCC,GAAsBD,EAAU,KAAK,eAAe,IAGxD,KAAK,gBAAkBA,EACvB,KAAK,eAAe,EACxB,CAEA,gBAAiB,CACb,KAAK,uBAAyB,EAClC,CAEA,cAAe,CACX,KAAK,uBAAyB,EAClC,CAEA,oBAAoBE,EAA2BC,EAAuB,CAClE,GAAKb,EAAO,QAIZ,KAAK,iBAAmBY,EACxB,KAAK,eAAiBC,EAEtBD,EAAS,iBAAiB,KAAK,cAAc,EAEzC,KAAK,qBAAqB,CAC1BA,EAAS,eAAe,KAAK,mBAAmB,EAChDC,EAAO,eAAe,KAAK,mBAAmB,EAC9C,MACJ,CACJ,CAEA,MAAMZ,EAAe,CACZ,KAAK,UAIV,KAAK,QAAU,GACf,KAAK,kBAAkB,EAEnB,KAAK,gBACL,KAAK,cAAc,UAAU,EAAE,QAASa,GAAU,CAC9CA,EAAM,KAAK,EAEX,KAAK,qCAAmD,KAAK,cAAeA,CAAK,CACrF,CAAC,EACD,KAAK,cAAgB,MAGzB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAEvB,KAAK,MACD,KAAK,sBACL,KAAK,oBAAoB,OAAS,KAClC,KAAK,oBAAoB,UAAY,KACrC,KAAK,oBAAoB,QAAU,KACnC,KAAK,oBAAoB,MAAM,GAEnC,KAAK,IAAI,eAAiB,KAC1B,KAAK,IAAI,QAAU,KACnB,KAAK,IAAI,2BAA6B,KACtC,KAAK,IAAI,wBAA0B,KACnC,KAAK,IAAI,uBAAyB,KAClC,KAAK,IAAI,MAAM,EACf,KAAK,IAAM,MAIf,KAAK,iBAAiB,CAAG,EACzB,KAAK,YAAY,EAEbb,GACAC,EAAM,MAAM,0BAA2BD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EACpF,KAAK,kBAA+B,IAEpCC,EAAM,MAAM,0BAA2B,CAAE,cAAe,KAAK,cAAe,CAAC,EAC7E,KAAK,kBAA+B,GAGxC,KAAK,sCAAmD,EAC5D,CAEQ,UAAUa,EAAuB,CACjC,KAAK,SAAWA,IAIpBb,EAAM,MAAM,qCAAqCa,CAAK,GAAI,CAAE,cAAe,KAAK,cAAe,CAAC,EAEhG,KAAK,OAASA,EACd,KAAK,8BAA4CA,CAAK,EAC1D,CAEQ,yBAAyBC,EAA2B,CACxD,OAAQA,EAAQ,aAAc,CAC1B,KAAKC,EAAsB,iBACvB,KAAK,uBAAuBD,CAA2C,EACvE,MAEJ,KAAKC,EAAsB,gBACvB,KAAK,oBAAoB,eAAeD,EAAQ,QAAyB,EACzE,MAEJ,KAAKC,EAAsB,YAEnB,OAAO,OAAOD,EAAQ,KAAM,KAAK,GACjC,KAAK,oBAAoB,aAAaA,EAAQ,MAAM,GAA2B,EAEnF,KACR,CACJ,CAEQ,uBAAuBA,EAA2C,CACtE,IAAME,EAAOF,EAAQ,KACfT,EAASY,EAAM,gBAAgBH,EAAQ,MAAM,EAC7BG,EAAM,iBAAiBH,CAAO,IAE9B,KAAK,iBAMvBE,EAAK,WAAaA,EAAK,UAAU,UACjC,KAAK,iBAAiBX,EAAQW,EAAK,SAAS,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,EAClEA,EAAK,MACZ,KAAK,sBAAwBA,EAAK,gBAAkB,EACpD,KAAK,sBAAsBX,EAAQW,EAAK,GAAG,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,GAEhF,CAEA,MAAc,iBAAiBX,EAAgBa,EAA+C,CAC1F,GAAI,KAAK,UAAY,CAAC,KAAK,eAAiB,KAAK,gBAAkBb,IAAW,KAAK,KAAO,KAAK,IAAI,kBAAmB,CAClHL,EAAM,MAAM,2BAA4B,CACpC,cAAe,KAAK,eACpB,UAAAkB,CACJ,CAAC,EAED,GAAI,CACA,MAAM,KAAK,IAAI,gBAAgB,IAAI,gBAAgBA,CAAS,CAAC,CACjE,OAASC,EAAG,CACR,MAAAhB,EAAO,IAAIC,EAAQ,MAAO,wBAAwB,EAClDJ,EAAM,MAAM,qCAAsCmB,EAAG,CAAE,cAAe,KAAK,eAAgB,UAAAD,CAAU,CAAC,EAChGC,CACV,CACJ,MACInB,EAAM,MAAM,6BAA8B,CACtC,cAAe,KAAK,eACpB,UAAAkB,CACJ,CAAC,EAED,KAAK,kBAAkBb,CAAM,EAAI,KAAK,kBAAkBA,CAAM,GAAK,CAAC,EACpE,KAAK,kBAAkBA,CAAM,EAAE,KAAKa,CAAS,CAErD,CAEA,MAAc,qBAAqBb,EAAgB,CAC/C,GAAI,CAAC,KAAK,kBAAkBA,CAAM,EAAG,CACjCL,EAAM,IAAI,uCAAuCK,CAAM,EAAE,EACzD,MACJ,CAEA,IAAMe,EAAa,KAAK,kBAAkBf,CAAM,EAChD,KAAK,kBAAkBA,CAAM,EAAI,CAAC,EAElC,QAAWa,KAAaE,EACpB,GAAI,CACA,MAAM,KAAK,iBAAiBf,EAAQa,CAAS,CACjD,MAAY,CAAC,CAErB,CAEA,MAAc,sBAAsBb,EAAgBgB,EAAyD,CACzG,GAAI,KAAK,UAAY,CAAC,KAAK,eAAiB,KAAK,gBAAkBhB,IAAW,KAAK,IAAK,CACpF,GAAI,KAAK,gBAAgB,MAAQgB,EAAI,IAGjC,OAEJ,KAAK,eAAiBA,EAEtBA,EAAMlC,EAAgB,wBAAwBkC,CAAG,EAEjDrB,EAAM,MAAM,yBAA0B,CAClC,cAAe,KAAK,eACpB,IAAAqB,CACJ,CAAC,EAED,KAAK,iBAAiBA,EAAI,GAAa,EAEvC,GAAI,CACA,MAAM,KAAK,IAAI,qBAAqBA,CAAG,EACvC,MAAM,KAAK,qBAAqBhB,CAAM,EACtC,KAAK,+BAA+B,KAAK,qBAAqB,CAClE,OAASc,EAAG,CACR,MAAAhB,EAAO,IAAIC,EAAQ,MAAO,6BAA6B,EACvDJ,EAAM,MAAM,mCAAoCmB,EAAG,CAAE,cAAe,KAAK,eAAgB,IAAAE,CAAI,CAAC,EACxFF,CACV,CACJ,MACI,KAAK,WAAWd,CAAM,EAAIgB,CAElC,CAEQ,+BAA+BC,EAAyB,CAC5D,IAAMC,EAAe,KAAK,IAAID,EAASxB,EAAO,cAAc,iBAAmB,CAAC,EAEhF,KAAK,gBAAgB,mBAAmByB,CAAY,CACxD,CAEQ,YAAYC,EAAY,CAC5BxB,EAAM,MAAM,qBAAsB,CAAE,cAAe,KAAK,eAAgB,KAAMwB,EAAM,MAAM,IAAK,CAAC,EAE3F,KAAK,cAMN,KAAK,cAAc,SAASA,EAAM,KAAK,GALvC,KAAK,cAAgB,IAAI,YAAY,CAACA,EAAM,KAAK,CAAC,EAClD,KAAK,cAAc,cAAiBL,GAAM,CACtC,KAAK,qCAAmD,KAAK,cAAeA,EAAE,KAAK,CACvF,GAKJ,KAAK,mCAAiD,KAAK,cAAeK,EAAM,KAAK,CACzF,CAEA,MAAc,oBAAoBA,EAAkC,CAC5DA,EAAM,WAAa,KAAK,WAAW,QACnCxB,EAAM,MAAM,sBAAuB,CAAE,cAAe,KAAK,eAAgB,UAAWwB,EAAM,SAAU,CAAC,EAErG,MAAM,KAAK,WAAW,cAAc,KAAK,eAAgBA,EAAM,SAAS,EAEhF,CAEQ,yBAA0B,CAC9BxB,EAAM,MAAM,+CAA+C,KAAK,KAAK,cAAc,GAAI,CAAE,cAAe,KAAK,cAAe,CAAC,EAC7H,IAAMyB,EAAe,CACjB,eAAgB3B,EAAO,aAAa,iBAAmB,CAC3D,EAEA,OAAQ,KAAK,KAAK,eAAgB,CAC9B,IAAK,mBACD,IAAMuB,EAAM,KAAK,IAAI,iBACjBA,EACA,KAAK,WAAW,QAAQ,KAAK,eAAgBA,EAAKI,CAAY,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,EAE3F,KAAK,MAAM,IAAI,KAAO,EAE1B,MAEJ,IAAK,oBACD,KAAK,cAAc,EACd,KAAMC,GAAW,KAAK,WAAW,QAAQ,KAAK,eAAgBA,EAAQD,CAAY,CAAC,EACnF,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,EAChC,KACR,CACJ,CAEQ,6BAA8B,CAGlC,OAFAzB,EAAM,MAAM,oDAAoD,KAAK,KAAK,kBAAkB,GAAI,CAAE,cAAe,KAAK,cAAe,CAAC,EAE9H,KAAK,KAAK,mBAAoB,CAElC,IAAK,WACD,IAAMa,EAAQ,KAAK,SAAS,EACxBA,IAAU,QAAuBA,IAAU,SAC3C,KAAK,sBAAmC,EAExC,KAAK,wBAAqC,EAE9C,KACR,CACJ,CAEQ,0BAA2B,CAI/B,OAHAb,EAAM,MAAM,gDAAgD,KAAK,KAAK,eAAe,GAAI,CAAE,cAAe,KAAK,cAAe,CAAC,EAC/HG,EAAO,IAAIC,EAAQ,qBAAsB,KAAK,KAAK,eAAe,EAE1D,KAAK,KAAK,gBAAiB,CAC/B,IAAK,YACD,KAAK,gBAAkB,GACvB,KAAK,qBAAkC,EACvC,KAAK,kBAAkB,EACvBa,EAAM,0BAA0B,KAAK,GAAG,EAAE,KAAMD,GAAS,CACjDA,GAAM,QACNb,EAAO,IAAIC,EAAQ,oBAAqBY,EAAK,MAAM,IAAI,EACvDhB,EAAM,MAAM,0BAA2BgB,CAAI,EAEnD,CAAC,EACD,KAAK,mBAAmB,EACxB,MAEJ,IAAK,SACL,IAAK,eACG,KAAK,uBACL,KAAK,MAAM,IAAI,MAAM,kBAAkB,KAAK,IAAI,eAAe,EAAE,CAAC,GAElE,KAAK,wBAAqC,EAC1C,KAAK,mBAAmB,GAE5B,MAEJ,IAAK,SACD,KAAK,MAAM,IAAI,MAAM,uBAAuB,CAAC,EAC7C,KACR,CACJ,CAEQ,oBAAqB,CACrB,KAAK,sBAAwB,KAAK,qBAItChB,EAAM,IAAI,8BAA+B,CAAE,cAAe,KAAK,cAAe,CAAC,EAC/E,KAAK,qBAAuB,OAAO,WAAW,IAAM,CAChD,KAAK,qBAAuB,KAExB,KAAK,gBACL,KAAK,uBAAuB,EAE5B,KAAK,iBAAiB,CAE9B,EAAGF,EAAO,2BAA2B,EACzC,CAEQ,wBAAyB,CACzB,KAAK,WAAa,KAAK,WAAW,QAClCE,EAAM,IAAI,mCAAoC,CAAE,cAAe,KAAK,cAAe,CAAC,EACpF,KAAK,WAAW,uBAAuC,EAE/D,CAEQ,mBAAoB,CACpB,KAAK,uBACL,aAAa,KAAK,oBAAoB,EACtC,KAAK,qBAAuB,MAG5B,KAAK,qBACL,aAAa,KAAK,kBAAkB,EACpC,KAAK,mBAAqB,KAElC,CAEQ,kBAAmB,CACnB,KAAK,WACLG,EAAO,IAAIC,EAAQ,WAAW,EAC9BJ,EAAM,IAAI,cAAe,CAAE,cAAe,KAAK,cAAe,CAAC,EAC/D,KAAK,aAAa,EAAI,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC,GAEnDA,EAAM,MAAM,6BAA8B,CAAE,cAAe,KAAK,cAAe,CAAC,EAGpF,KAAK,mBAAqB,OAAO,WAAW,IAAM,CAC9C,KAAK,mBAAqB,KAC1BA,EAAM,MAAM,qBAAsB,CAAE,cAAe,KAAK,cAAe,CAAC,EACxEG,EAAO,IAAIC,EAAQ,MAAO,mBAAmB,EAC7C,KAAK,uBAAuB,CAChC,EAAGN,EAAO,kBAAkB,CAChC,CAEA,MAAc,aAAa6B,EAAmE,CAC1F,IAAMC,EAAU,CACZ,WAAAD,EACA,oBAAqB,GACrB,oBAAqB,EACzB,EAEA3B,EAAM,MAAM,eAAgB,CAAE,cAAe,KAAK,eAAgB,QAAA4B,CAAQ,CAAC,EAE3E,IAAIC,EACJ,GAAI,CACAA,EAAS,MAAM,KAAK,KAAK,YAAYD,CAAO,EAC5C5B,EAAM,MAAM,gBAAiB,CAAE,cAAe,KAAK,eAAgB,MAAA6B,CAAM,CAAC,EAC1EA,EAAQ1C,EAAgB,uBAAuB0C,CAAK,CACxD,OAAS9B,EAAO,CACZ,MAAAC,EAAM,MAAM,yBAA0BD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EACnFI,EAAO,IAAIC,EAAQ,MAAO,oBAAoB,EAExCL,CACV,CAEA,GAAI,CACA,OAAAC,EAAM,MAAM,wBAAyB,CAAE,cAAe,KAAK,eAAgB,MAAA6B,CAAM,CAAC,EAElF,KAAK,iBAAiBA,EAAM,GAAG,EAC/B,MAAM,KAAK,KAAK,oBAAoBA,CAAK,EAClCA,CACX,OAAS9B,EAAO,CACZ,MAAAC,EAAM,MAAM,kCAAmCD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EAC5FI,EAAO,IAAIC,EAAQ,MAAO,4BAA4B,EAEhDL,CACV,CACJ,CAEA,MAAc,eAA8D,CACxEC,EAAM,MAAM,gBAAiB,CAAE,cAAe,KAAK,cAAe,CAAC,EAEnE,IAAI0B,EACJ,GAAI,CACAA,EAAU,MAAM,KAAK,KAAK,aAAa,EACvC1B,EAAM,MAAM,iBAAkB,CAAE,cAAe,KAAK,eAAgB,OAAA0B,CAAO,CAAC,EAC5EA,EAASvC,EAAgB,uBAAuBuC,CAAM,CAC1D,OAAS3B,EAAO,CACZ,MAAAC,EAAM,MAAM,0BAA2BD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EACpFI,EAAO,IAAIC,EAAQ,MAAO,qBAAqB,EAEzCL,CACV,CAEA,GAAI,CACA,OAAAC,EAAM,MAAM,wBAAyB,CAAE,cAAe,KAAK,eAAgB,OAAA0B,CAAO,CAAC,EAEnF,KAAK,iBAAiBA,EAAO,GAAG,EAChC,MAAM,KAAK,KAAK,oBAAoBA,CAAM,EACnCA,CACX,OAAS3B,EAAO,CACZ,MAAAC,EAAM,MAAM,kCAAmCD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EAC5FI,EAAO,IAAIC,EAAQ,MAAO,4BAA4B,EAEhDL,CACV,CACJ,CAEA,OAAe,uBAAuB+B,EAAkD,CACpF,IAAMC,EAAkB,CAAC,CAACC,EAAY,kBAAkB,EACxD,OAAAF,EAAY,IAAMb,EAAM,cACpBa,EAAY,IACZhC,EAAO,YAAckC,EAAY,cAAc,EAC/CA,EAAY,oBAAoB,EAChClC,EAAO,UACPA,EAAO,wBACPiC,GAAmBjC,EAAO,UAC1BA,EAAO,WACX,EAEOgC,CACX,CAEA,OAAe,wBAAwBA,EAAkD,CACrF,OAAAA,EAAY,IAAMb,EAAM,eAAea,EAAY,IAAK,GAAO,GAAO,GAAOhC,EAAO,UAAWkC,EAAY,mBAAmB,EAAGA,EAAY,mBAAmB,CAAC,EAE1JF,CACX,CAEQ,iBAAiBG,EAA4B,CAC7C,KAAK,MACL,KAAK,IAAI,WAAW,EAAE,QAAStB,GAAW,CAClCA,EAAO,OAASA,EAAO,MAAM,OAASsB,EAAS,MAAQtB,EAAO,MAAM,cAAgBsB,EAAS,aAI7FtB,EAAO,aAAasB,CAAQ,EAAE,MAAOlC,GAAU,CAC3CC,EAAM,MAAM,2CAA4CD,EAAO,CAAE,cAAe,KAAK,cAAe,CAAC,EACrGI,EAAO,IAAIC,EAAQ,MAAO,qBAAqB,CACnD,CAAC,CAET,CAAC,EACD,KAAK,eAAe,EAE5B,CAEQ,oBAAqB,CACzB,GAAI,KAAK,cACL,OAGJ,IAAM8B,EAAQ,IAAM,CAChB,GAAI,KAAK,kBAAkB,EAAG,CAC1B,KAAK,kBAAkB,EACvB,MACJ,CAEAC,GAAW,aAAa,KAAK,IAA0B,KAAK,UAAW,OAAW,EAAI,EAAE,KAAMC,GAAS,CACnG,KAAK,UAAYA,EACjBC,GAAqB,YAAYD,CAAI,EACrC,IAAME,EAAoB,CACtB,QAAS,CACL,kBACA,UAAWF,EAAK,UAChB,KAAMA,EAAK,KAAK,OAAQG,GAChBA,EAAI,OAAS,eACbA,EAAI,OAAS,KAAK,eACX,IAEJ,EACV,CACL,EACA,SAAU,CACN,kBACA,UAAWH,EAAK,UAChB,KAAMA,EAAK,KAAK,OAAQG,GAAQA,EAAI,OAAS,cAAc,CAC/D,EACA,cAAe,CACX,kBACA,UAAWH,EAAK,UAChB,KAAMA,EAAK,YAAc,CAAC,CAC9B,CACJ,EAEA,KAAK,iBAAiBE,CAAK,EAC3B,KAAK,oBAAoB,YAAYA,CAAK,EAC1C,KAAK,kCAAgDA,CAAK,EAC1D,KAAK,cAAgB,OAAO,WAAWJ,EAAOpC,EAAO,kBAAkB,CAC3E,CAAC,CACL,EAEA,KAAK,cAAgB,OAAO,WAAWoC,EAAOpC,EAAO,kBAAkB,CAC3E,CAMA,MAAc,gBAAgBwC,EAAmBE,EAAmC,CAChF,IAAM5B,EAAQ,KAAK,aAAa,kBAAkB,EAC5C2B,EAAMD,EAAM,SAAS,KAAK,KAAMG,GAASA,EAAK,OAAS,OAAO,EACpE,GAAI,CAACF,GAAK,UAAY,CAACA,GAAK,WAAa,CAAC3B,EACtC,MAAO,GAGX,IAAM8B,EAAgB9B,EAAM,YAAY,EACxC,GAAI,CAAC8B,EAAc,OAAS,CAACA,EAAc,QAAU,CAACA,EAAc,UAChE,MAAO,GAGX,IAAMC,EAA0C,CAE5C,KAAMX,EAAY,YAAY,IAAM,UAAY,eAAiB,SACjE,MAAO,CACH,YAAaO,EAAI,SACjB,MAAOG,EAAc,MACrB,OAAQA,EAAc,OACtB,QAASH,EAAI,UACb,UAAWG,EAAc,UACzB,gBAAAF,CACJ,CACJ,EAEA,GAAI,CAEA,OADqB,MAAM,UAAU,kBAAkB,aAAaG,CAAW,GAC3D,WAAa,EACrC,OAASxB,EAAQ,CACb,OAAAnB,EAAM,KAAK,6BAA8B2C,EAAaxB,CAAC,EAChD,EACX,CACJ,CAEA,MAAc,iBAAiBmB,EAAmB,CAE9C,GAAI,CAACxC,EAAO,yBAA2B,CAACwC,EAAM,QAAQ,UAAU,eAC5D,OAIJ,GAAM,CAAE,eAAAM,CAAe,EAAIN,EAAM,QAAQ,UACnCO,EAAmBD,EAAe,sBAAwB,KAAK,uBAAuB,KAAK,KAAOA,EAAe,aAAe,KAAK,uBAAuB,KAAK,KACjKE,EAAkBF,EAAe,sBAAwB,KAAK,uBAAuB,IAAI,KAAOA,EAAe,aAAe,KAAK,uBAAuB,IAAI,KAC9JG,EAAuBH,EAAe,qBAAuB,KAAK,uBAAuB,IAAI,IAE/FI,EAAwB,KAAK,0BAA0B,KACvDR,SAuBJ,GAtBIM,GACA,KAAK,mBAAqB,KAAK,IAAI,EAE/BC,GAEAC,EAAwB,KAAK,0BAA0B,IACvDR,EAAkB,SAGlBQ,EAAwB,KAAK,0BAA0B,MACvDR,EAAkB,SAEfK,IAEPG,EAAwB,KAAK,0BAA0B,KACvDR,EAAkB,QAQlB,EAHsBQ,EAAwB,KAAK,wBAA0B,KAAK,IAAI,EAAI,KAAK,mBAAqB/D,KAIpH,KAAK,yBAA2B+D,EAEhC,OAGJ,IAAMC,EAAgB,KAAK,gBAAgB,OAM3C,GALI,CAACA,GAKD,CADQ,MAAM,KAAK,gBAAgBX,EAAOE,CAAe,EAEzD,OAGJxC,EAAM,MAAM,uDAAwD,CAChE,gBAAAwC,EACA,eAAAI,EACA,sBAAAI,CACJ,CAAC,EACD,KAAK,uBAAyBA,EAE9B,IAAME,EAA+B,CAAE,GAAG,KAAK,gBAAiB,OAAQ,CAAE,GAAGD,EAAe,gBAAAT,EAAiB,aAAc,KAAK,sBAAuB,CAAE,EACzJ,KAAK,eAAeU,CAAY,CACpC,CAEQ,mBAAoB,CACpB,KAAK,gBACL,OAAO,aAAa,KAAK,aAAa,EACtC,KAAK,cAAgB,KAE7B,CAEQ,iBAAiBC,EAAgB,CACrC,IAAMC,EAA0C,CAAC,EAEjDA,EAAS,KAAK,cAAc,EAAIA,EAAS,EAAE,EAAID,EAC/C,KAAK,+BAA6CC,CAAQ,CAC9D,CAEQ,wBAAyB,CAE7B,GAAI,KAAK,kBACL,OAGJ,IAAMlB,EAAQ,IAAM,CAChB,GAAI,CAAC,KAAK,IAAK,CACX,KAAK,sBAAsB,EAC3B,MACJ,CAEA,KAAK,eAAe,EACpB,KAAK,kBAAoB,OAAO,WAAWA,EAAO,GAAQ,CAC9D,EAEA,KAAK,kBAAoB,OAAO,WAAWA,EAAO,GAAQ,CAC9D,CAEQ,uBAAwB,CACxB,KAAK,oBACL,OAAO,aAAa,KAAK,iBAAiB,EAC1C,KAAK,kBAAoB,KAEjC,CAEQ,iBAAiBb,EAAa,CAClC,IAAMgC,EAAKpC,EAAM,eAAeI,CAAG,EACnC,GAAIgC,IAAO,KAAM,CACbrD,EAAM,KAAK,wCAAwC,EACnD,MACJ,CAEI,KAAK,eAAiB,KACtB,KAAK,aAAeqD,GAEpBC,EAAS,qBAAqB,KAAK,aAAeD,GAAI,SAAS,CAAC,EAChE,KAAK,aAAe,KAE5B,CAEQ,gBAAiB,CACrB,IAAMJ,EAAgB,KAAK,aAAa,iBAAiB,EAAE,uBAAyB,KAAK,gBAAgB,cAAgB,KAAK,gBAAgB,OAC1IA,GAAiB,KAAK,KAAK,kBAAoB,cAC/C,KAAK,sBAAwBhC,EAAM,cAAc,KAAK,IAAKgC,EAAe,KAAK,qBAAqB,EAE5G,CAEQ,mBAAmBM,EAA+BC,EAAyBC,EAAiD,CAChIzD,EAAM,MAAM,IAAIwD,CAAK,wBAAwB,EAC7C,IAAMtD,EAAcqD,EAAW,kBAAkBC,EAAO,CACpD,WAAY,GACZ,GAAI,CACR,CAAC,EACDtD,EAAY,OAAS,IAAM,CACvB,IAAMW,EAAQX,EAAY,WACtBW,IAAU,QACVb,EAAM,MAAM,IAAIwD,CAAK,uBAAuB,EAC5CtD,EAAY,QAAWiB,GAAa,CAChCnB,EAAM,MAAM,IAAIwD,CAAK,uBAAwBrC,CAAC,CAClD,EAEAsC,EAASvD,CAAW,GAEpBF,EAAM,MAAM,IAAIwD,CAAK,sCAAsC3C,CAAK,GAAG,CAE3E,CACJ,CACJ,EC74BO,IAAW6C,QACdA,EAAA,UAAY,YACZA,EAAA,kCAAoC,MAFtBA,QAAA,IAKXC,GAAQD,GCDf,IAAME,GAAc,GAEPC,GAAN,MAAMC,CAAY,CAMrB,YAAYC,EAA6BC,EAA8CC,EAA2C,CALlIC,EAAA,KAAiB,gBACjBA,EAAA,KAAiB,0BACjBA,EAAA,KAAiB,gBACjBA,EAAA,KAAiB,gBAGbC,EAAM,MAAM,qBAAqB,EAEjC,KAAK,aAAeJ,EACpB,KAAK,uBAAyBC,EAC9B,KAAK,aAAeC,EACpB,KAAK,aAAe,IAAI,YAExB,KAAK,aAAa,UAAaG,GAAM,KAAK,sBAAsBA,EAAE,IAAI,CAC1E,CAQA,OAAe,MAAMC,EAAmB,CACpC,IAAMC,EAAO,IAAI,SAASD,CAAI,EAExBE,EAAUD,EAAK,SAAS,CAAC,EACzBE,EAAOF,EAAK,SAAS,CAAC,EAC5B,GAAIE,IAAS,EACT,MAAM,IAAI,MAAM,2CAA2CA,CAAI,EAAE,EAErE,IAAMC,EAAWH,EAAK,UAAU,CAAC,EAC3BI,EAAOJ,EAAK,UAAU,CAAC,EACvBK,EAAYL,EAAK,UAAU,CAAC,EAC5BM,EAAWN,EAAK,UAAU,EAAE,EAElC,GAAIC,IAAY,EACZ,MAAM,IAAI,MAAM,oCAAoCA,CAAO,cAAc,EAG7E,MAAO,CACH,SAAAE,EACA,KAAAC,EACA,UAAAC,EACA,SAAAC,EACA,KAAMP,EAAK,MAAMT,EAAW,CAChC,CACJ,CAEQ,sBAAsBS,EAAmB,CAC7C,IAAMQ,EAAQf,EAAY,MAAMO,CAAI,EAC9BS,EAAgB,KAAK,wBAAwB,qBAAqBD,EAAM,IAAI,GAAG,cACrF,GAAI,CAACC,EAAe,CAChBX,EAAM,KAAK,2BAA2BU,EAAM,IAAI,wBAAwB,EACxE,MACJ,CAEA,IAAME,EAAM,CACR,cAAAD,EACA,KAAM,KAAK,aAAa,OAAOD,EAAM,IAAI,EACzC,UAAWA,EAAM,UACjB,SAAUA,EAAM,QACpB,EAEA,KAAK,aAAaE,CAAG,CACzB,CAEA,SAAU,CACN,KAAK,aAAa,UAAY,IAClC,CACJ,EC5EO,IAAMC,GAAN,MAAMA,EAAmB,CAAzB,cAEHC,EAAA,KAAQ,SAAS,GAUjB,IAAW,OAAQ,CACf,OAAO,KAAK,MAChB,CAEA,IAAW,MAAMC,EAAe,CAC5B,KAAK,OAASA,CAClB,CACJ,EAlBID,EADSD,GACM,YAAuC,MAGtDC,EAJSD,GAIK,cAAc,KACnBA,GAAK,YACNA,GAAK,UAAY,IAAIA,IAGlBA,GAAK,YATb,IAAMG,GAANH,GCAP,IAAAI,GAAuB,uBAShB,IAAMC,GAAN,KAA4B,CAA5B,cACHC,EAAA,KAAQ,+BAA0E,IAAI,KACtFA,EAAA,KAAQ,+BAAoD,IAAI,KAEhE,qBAAqBC,EAA+D,CAChF,OAAO,KAAK,6BAA6B,IAAIA,CAAW,CAC5D,CAEA,aAAaC,EAA+C,CACxD,OAAO,KAAK,6BAA6B,IAAIA,CAAiB,CAClE,CAEA,cAAcC,EAA4C,CACtD,IAAMC,EAAM,IAAI,WAAWD,CAAI,EACzBE,EAAOD,EAAI,CAAC,EACZE,EAAUF,EAAI,SAAS,CAAC,EAE9B,OAAQC,EAAM,CACV,IAAK,GACD,IAAME,KAAS,WAAkCD,CAAO,EACxD,cAAO,QAAQC,CAAM,EAAE,QAAQ,CAAC,CAACC,EAAmBP,CAAW,IAAM,CACjE,IAAMC,EAAoBO,GAAkCD,CAAiB,EAC7E,KAAK,6BAA6B,IAAIP,EAAaC,CAAiB,EACpE,KAAK,6BAA6B,IAAIM,EAAmBP,CAAW,CACxE,CAAC,EACM,KACX,IAAK,GACL,IAAK,GACD,IAAMS,KAAyB,WAAOJ,CAAO,EACvCK,EAAuB,CAAC,EAC9B,QAAWC,KAAaF,EAAc,CAClC,IAAMR,EAAoB,KAAK,qBAAqBU,CAAS,EACzDV,GACAS,EAAI,KAAKT,EAAkB,aAAa,CAEhD,CACA,OAAIG,IAAS,EACF,CACH,KAAM,eACN,aAAcQ,EAAsB,eACpC,mBAAoBF,CACxB,EAEO,CACH,KAAM,eACN,aAAcE,EAAsB,iBACpC,oBAAqBF,CACzB,EAER,IAAK,GACD,IAAMG,KAAkB,WAAOR,CAAO,EACtC,MAAO,CACH,KAAM,eACN,aAAcO,EAAsB,gBACpC,QAAS,KAAK,qBAAqBC,CAAO,GAAG,aACjD,EACJ,IAAK,GACD,IAAMC,KAAoB,WAAOT,CAAO,EACxC,MAAO,CACH,KAAM,eACN,aAAcO,EAAsB,qBACpC,QAAS,CACL,WAAYE,EAAQ,CAAC,EACrB,aAAcA,EAAQ,CAAC,CAC3B,EACA,UAAW,KAAK,iBAAiBA,EAAQ,CAAC,CAAC,CAC/C,EACJ,IAAK,GACD,IAAMC,KAAY,WAAkCV,CAAO,EACrDW,EAAsC,CAAC,EAC7C,OAAW,CAACC,EAAaC,CAAM,IAAK,OAAO,QAAQH,CAAS,EAAG,CAC3D,IAAMI,EAAgB,KAAK,qBAAqB,OAAOF,CAAW,CAAC,GAAG,cAClEE,IACAH,EAASG,CAAa,EAAID,EAAS,IAE3C,CACA,MAAO,CACH,KAAM,eACN,aAAcN,EAAsB,eACpC,SAAAI,CACJ,EACJ,IAAK,GACD,OAAO,KAAK,4CAA4CX,CAAO,EAEnE,IAAK,GAAG,CAEJ,IAAMe,KADqB,WAAoCf,CAAO,EACjC,IAAwBgB,GAAU,CACnE,GAAM,CAACC,EAAwBC,GAAMC,GAAOC,GAAQC,EAAMC,GAAYC,CAAW,EAAIP,EAErF,MAAO,CACH,cAAe,KAAK,qBAAqBC,CAAsB,GAAG,cAClE,KAAAC,GACA,MAAAC,GACA,OAAAC,GACA,KAAAC,EACA,WAAAC,GACA,YAAAC,CACJ,CACJ,CAAC,EAED,MAAO,CACH,KAAM,eACN,aAAchB,EAAsB,0BACpC,KAAMQ,CACV,CACJ,CACA,IAAK,GAGD,IAAMS,KAAoB,WAAOxB,CAAO,EACxC,MAAO,CACH,KAAM,eACN,aAAcO,EAAsB,sBACpC,UAAAiB,CACJ,EAEJ,QACI,OAAAC,EAAM,MAAM,6BAA+B1B,CAAI,EACxC,IACf,CACJ,CAEQ,iBAAiB2B,EAAiC,CACtD,GAAIA,IAAU,KACV,OAAO,KAEX,OAAQA,EAAO,CACX,IAAK,GACD,eACJ,IAAK,GACD,eACJ,QACI,MAAM,IAAI,MAAM,2BAA2BA,CAAK,EAAE,CAC1D,CACJ,CAEQ,4CAA4C1B,EAAqB,CACrE,IAAMU,KAAY,WAA6CV,CAAO,EAEhE2B,EAAmE,CAAC,EAC1E,OAAW,CAACC,EAAUC,CAAgB,IAAK,OAAO,QAAQnB,CAAS,EAAG,CAClE,IAAMoB,EAAuBD,EAAiB,CAAC,EACzCE,EAA4BF,EAAiB,CAAC,EAC9CG,EAAiBH,EAAiB,CAAC,EACnCI,EAAkB,CAAC,CAACJ,EAAiB,CAAC,EACtCK,EAAUL,EAAiB,CAAC,IAAM,KAAO,CAAC,CAACA,EAAiB,CAAC,EAAI,OAEnEM,EACJ,GAAIL,IAAyB,MAEzB,GADAK,EAA+B,KAAK,qBAAqBL,CAAoB,EACzE,CAACK,EAA8B,CAC/BV,EAAM,MAAM,uCAAuCK,CAAoB,EAAE,EACzE,QACJ,OAEAK,EAA+B,KAGnC,GAAIH,IAAmB,KAAM,CACzBP,EAAM,MAAM,iCAAkCG,EAAUC,CAAgB,EACxE,QACJ,CAEA,IAAMO,EAAWC,GAAQ,kCAAoC,IAAMT,EAG7DU,EAAeP,EAA4BA,IAA8B,EAAI,KACnFJ,EAAuB,KAAK,CAAE,6BAAAQ,EAA8B,SAAAC,EAAU,aAAAE,EAAc,eAAAN,EAAgB,gBAAAC,EAAiB,QAAAC,CAAQ,CAAC,CAClI,CAEA,MAAO,CACH,KAAM,eACN,aAAc3B,EAAsB,2BACpC,uBAAAoB,CACJ,CACJ,CACJ,ECzJA,IAAMY,GAAsB,GACtBC,GAAoB,WAELC,GAArB,MAAqBC,UAAwBC,EAAc,CAmCvD,YAAYC,EAA0BC,EAA0BC,EAAgC,CAC5F,MAAMF,EAAWC,CAAW,EAnChCE,EAAA,KAAQ,wBAA+C,MACvDA,EAAA,KAAQ,mBAA0C,MAClDA,EAAA,KAAQ,kBAAyC,MACjDA,EAAA,KAAQ,kBAAyC,MACjDA,EAAA,KAAQ,OAA8B,MACtCA,EAAA,KAAQ,sBAA6C,MACrDA,EAAA,KAAQ,mBAA2C,MACnDA,EAAA,KAAQ,iBAAuC,MAC/CA,EAAA,KAAQ,UAAU,IAClBA,EAAA,KAAQ,YAAY,IACpBA,EAAA,KAAQ,yBAAyB,IACjCA,EAAA,KAAQ,gBAA+B,MACvCA,EAAA,KAAQ,oBAAmC,MAC3CA,EAAA,KAAQ,2BAA0C,MAClDA,EAAA,KAAQ,aAA0E,CAAC,GACnFA,EAAA,KAAQ,WAA0C,CAAC,GACnDA,EAAA,KAAQ,kBAAkB,IAC1BA,EAAA,KAAQ,qBACRA,EAAA,KAAQ,6BAA6B,IACrCA,EAAA,KAAQ,qBAAoC,MAC5CA,EAAA,KAAQ,YAA6B,MACrCA,EAAA,KAAQ,mBACRA,EAAA,KAAQ,wBAA6B,CAAC,GACtCA,EAAA,KAAQ,mCAAwC,CAAC,GACjDA,EAAA,KAAQ,YAAgC,MACxCA,EAAA,KAAQ,iBAA6C,MACrDA,EAAA,KAAQ,mBAAiD,MACzDA,EAAA,KAAQ,yBAAuD,MAC/DA,EAAA,KAAQ,mBAAmB,IAAI,KAC/BA,EAAA,KAAQ,0BAA0D,CAAC,GACnEA,EAAA,KAAQ,qBAAqB,IAC7BA,EAAA,KAAQ,sBAA+C,MACvDA,EAAA,KAAQ,iBAAuC,MAK3C,KAAK,UAAU,KAAK,WAAYC,GAAe,aAAc,KAAK,yBAAyB,KAAK,IAAI,CAAC,EACrG,KAAK,UAAU,KAAK,8BAA+C,KAAK,iBAAiB,KAAK,IAAI,CAAC,EACnG,KAAK,UAAU,KAAK,8BAA+C,KAAK,kBAAkB,KAAK,IAAI,CAAC,EACpG,KAAK,UAAU,KAAK,6BAA8C,KAAK,uBAAuB,KAAK,IAAI,CAAC,EAExG,KAAK,yBAAyB,EAC9B,KAAK,gBAAkBF,EAEvBG,EAAM,MAAM,0BAA0B,CAC1C,CAEA,0BAA2B,CACvB,KAAK,kBAAkB,EAEvB,IAAMC,EAAQ,KAAK,SAAS,EACxBA,IAAU,QAAuBA,IAAU,UAAyBA,IAAU,UAC9E,KAAK,mBAAmB,CAEhC,CAEA,KAAKC,EAAW,GAAO,CACnB,GAAI,KAAK,QAAS,CACdF,EAAM,IAAI,6CAA6C,EACvD,MACJ,CACA,KAAK,QAAU,GACf,KAAK,UAAYE,EAEjB,KAAK,gBAAgB,CACzB,CAES,MAAMC,EAAe,CACrB,KAAK,UAIV,KAAK,QAAU,GACf,KAAK,iBAAiB,EAEtB,KAAK,YAAY,EAEbA,GACAH,EAAM,MAAM,0BAA2BG,CAAK,EAC5C,KAAK,kBAA+B,IAEpCH,EAAM,MAAM,yBAAyB,EACrC,KAAK,kBAA+B,GAE5C,CAEA,kBAAkBI,EAA8B,CAC5C,KAAK,kBAAkB,MAAMA,CAAa,CAC9C,CAEA,gBAAiB,CACb,KAAK,uBAAyB,EAClC,CAEA,cAAe,CACX,KAAK,uBAAyB,EAClC,CAEA,eAAeC,EAA0B,CACjCC,GAAsBD,EAAU,KAAK,eAAe,IAGxD,KAAK,gBAAkBA,EACvB,KAAK,uBAAuB,EAChC,CAEA,oBAAoBE,EAA2BC,EAAuB,CAClE,GAAKC,EAAO,QAIZ,KAAK,iBAAmBF,EACxB,KAAK,eAAiBC,EAElB,KAAK,wBACLD,EAAS,yBAAyB,KAAK,sBAAsB,EAG7D,KAAK,qBAAqB,CAC1BA,EAAS,eAAe,KAAK,mBAAmB,EAChDC,EAAO,eAAe,KAAK,mBAAmB,EAC9C,MACJ,CACJ,CAEA,MAAM,2BAA4B,CAC1BC,EAAO,WAAaC,EAAY,8BAA8B,GAC9D,MAAM,KAAK,qBAAqB,GAAM,EAAK,CAEnD,CAEQ,0BAA2B,CAC/B,KAAK,mBAAmB,QAAQ,EAChC,KAAK,kBAAoB,IAAIC,GAAiB,KAAM,KAAK,UAAU,CACvE,CAEQ,kBAAmB,CACvB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,eAAiB,KAElB,KAAK,MACL,KAAK,wBAA0B,CAAC,EAChC,KAAK,iBAAiB,QAASC,GAAMA,EAAE,OAAO,KAAK,CAAC,EACpD,KAAK,iBAAiB,MAAM,EAC5B,KAAK,IAAI,QAAU,KACnB,KAAK,IAAI,wBAA0B,KACnC,KAAK,IAAI,uBAAyB,KAClC,KAAK,uBAAyB,KAC9BnB,EAAgB,kBAAkB,KAAK,qBAAqB,EAC5DA,EAAgB,kBAAkB,KAAK,gBAAgB,EACvDA,EAAgB,kBAAkB,KAAK,eAAe,EACtDA,EAAgB,kBAAkB,KAAK,eAAe,EACtDA,EAAgB,kBAAkB,KAAK,IAAI,EAC3CA,EAAgB,kBAAkB,KAAK,mBAAmB,EAC1D,KAAK,IAAI,MAAM,EACf,KAAK,IAAM,KACX,KAAK,2BAA6B,GAClC,KAAK,mBAAqB,MAG9B,KAAK,sCAAmD,CAC5D,CAEA,OAAe,kBAAkBoB,EAAoC,CAC7DA,IACAA,EAAY,OAAS,KACrBA,EAAY,UAAY,KACxBA,EAAY,QAAU,KACtBA,EAAY,MAAM,EAE1B,CAEQ,mBAAmBC,EAA+BC,EAAyBC,EAAiD,CAChIhB,EAAM,MAAM,IAAIe,CAAK,wBAAwB,EAC7C,IAAMF,EAAcC,EAAW,kBAAkBC,EAAO,CAAE,QAAS,EAAK,CAAC,EACzEF,EAAY,OAAS,IAAM,CACvB,IAAMZ,EAAQY,EAAY,WACtBZ,IAAU,QACVD,EAAM,MAAM,IAAIe,CAAK,uBAAuB,EAC5CC,EAASH,CAAW,GAEpBb,EAAM,MAAM,IAAIe,CAAK,sCAAsCd,CAAK,GAAG,CAE3E,EACAY,EAAY,QAAWI,GAAM,CACzB,IAAMd,EAASc,EAAoB,MACnCjB,EAAM,MAAM,IAAIe,CAAK,uBAAwBZ,GAAO,YAAaA,GAAO,OAAO,CACnF,CACJ,CAEQ,gBAAgBe,EAAY,GAAO,CACvClB,EAAM,MAAM,yCAAyC,EAErD,GAAI,CACA,KAAK,IAAM,IAAI,iBACnB,OAASG,EAAY,CACjBH,EAAM,MAAM,sCAAuCG,CAAK,EACxD,KAAK,MAAMA,CAAK,EAChB,MACJ,CAEA,KAAK,IAAI,QAAU,KAAK,YAAY,KAAK,KAAM,KAAK,GAAG,EAEvD,KAAK,IAAI,wBAA0BgB,EAAM,SAAUF,GAAW,CACtD,KAAK,KACL,KAAK,yBAAyB,KAAK,IAAKA,CAAC,CAEjD,EAAG,GAAG,EACN,KAAK,IAAI,uBAAyBxB,EAAgB,wBAAwB,KAAK,KAAM,KAAK,GAAG,EAE7F,KAAK,uBAAyB,IAAI2B,GAClC,KAAK,WAAW,yBAAyB,KAAK,sBAAsB,EAChEX,EAAO,iCACP,KAAK,mBAAmB,KAAK,IAAKY,GAAiB,qBAAuBR,GAAgC,CACtG,KAAK,sBAAwBA,EAC7B,KAAK,sBAAsB,WAAa,cACxC,KAAK,WAAW,mCAAmCA,CAAW,CAClE,CAAC,EAGDJ,EAAO,6BACP,KAAK,WAAW,sBAAsB,EAAI,EAC1C,KAAK,mBAAmB,KAAK,IAAKY,GAAiB,gBAAkBR,GAAgC,CACjG,KAAK,iBAAmBA,EACxB,KAAK,WAAW,8BAA8BA,CAAW,CAC7D,CAAC,GAGDJ,EAAO,2BACP,KAAK,mBAAmB,KAAK,IAAKY,GAAiB,oBAAsBR,GAAgC,CACrG,KAAK,gBAAkBA,EACvB,KAAK,gBAAgB,WAAa,cAClC,KAAK,uBAAuB,CAChC,CAAC,EAGDJ,EAAO,gBACP,KAAK,mBAAmB,KAAK,IAAKY,GAAiB,IAAMR,GAAgC,CACrF,KAAK,KAAOA,EACZ,KAAK,KAAK,WAAa,cAEvB,KAAK,gBAAgB,EACrB,KAAK,UAAY,IAAIS,GAAYT,EAAa,KAAK,uBAAkDU,GAA0B,CAC3H,KAAK,oBAAoBA,CAAG,CAChC,CAAC,CACL,CAAC,EAGDd,EAAO,OACP,KAAK,mBAAmB,KAAK,IAAKY,GAAiB,QAAUR,GAAgC,CACzF,KAAK,oBAAsBA,EAC3B,KAAK,oBAAoB,WAAa,cACtC,KAAK,kBAAkB,eAAeA,CAAW,EACjD,KAAK,kBAAkB,yBAAyB,KAAK,sBAA+C,EACpG,KAAK,gBAAgB,eAAeA,CAAW,EAC/C,KAAK,gBAAgB,mBAAmBJ,EAAO,aAAa,iBAAmB,CAAC,CACpF,CAAC,EAGL,KAAK,oBAAsB,KAAK,aAAa,mBAAmB,EAEhE,GAAI,CACA,KAAK,aAAa,yBAAyB,KAAK,IAAK,KAAK,UAAW,EAAK,EAC1E,KAAK,sBAAwB,CAAC,EAC9B,KAAK,iCAAmC,CAAC,EACzC,KAAK,uBAAuB,CAChC,OAASN,EAAY,CACjBH,EAAM,MAAM,qDAAsDG,CAAK,EACvEqB,EAAO,IAAIC,EAAQ,MAAO,iBAAiB,EAC3C,KAAK,MAAMtB,CAAK,EAChB,MACJ,CAEIM,EAAO,2BACP,KAAK,mBAAmB,KAAK,IAAKY,GAAiB,oBAAsBR,GAAgC,CACrG,KAAK,gBAAkBA,EACvB,KAAK,gBAAgB,WAAa,cAElC,IAAMa,EAAc,KAAK,aAAa,eAAe,EACjDA,IAAgB,CAACjB,EAAO,yBAA2B,CAAC,KAAK,aAAa,iBAAiB,EAAE,6BACzF,KAAK,qBAAqBiB,CAAW,CAE7C,CAAC,EAGAR,GACD,KAAK,kBAAkB,EAG3B,KAAK,kBAA+B,EAEpC,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,CACvC,CAEQ,iBAAkB,CACtB,KAAK,WAAW,QAAQ,EACxB,KAAK,UAAY,IACrB,CAEQ,YAAa,CAEb,KAAK,SAAS,IAAM,WACpB,KAAK,wBAAqC,EAC1C,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EAAI,EAEjC,CAEQ,0BAA0BS,EAA+B,CAC7D,KAAK,8CAA4DA,CAAY,CACjF,CAEQ,2BAA2BA,EAA+B,CAC9D,KAAK,+CAA6DA,CAAY,CAClF,CAEQ,sBAAsBC,EAAwB,CAClD,KAAK,0CAAwDA,CAAO,CACxE,CAEQ,qBAAqBC,EAAyC,CAClE,KAAK,+BAA6CA,CAAQ,CAC9D,CAEQ,eAAeC,EAAkD,CACjEA,GACAA,EAAY,IAAI,MAAM;AAAA,CAAI,EAAE,QAASC,GAAS,CAC1C,IAAMC,EAAc,mEAAmEC,GAAQ,iCAAiC,YAC1HC,EAAS,IAAI,OAAOF,CAAW,EAAE,KAAKD,CAAI,EAC5CG,IACA,KAAK,SAASA,EAAO,CAAC,CAAC,EAAIA,EAAO,CAAC,EACnC,KAAK,gBAAkB,GAE/B,CAAC,CAET,CAEQ,qBAAqBC,EAAyB,CAClD,IAAMC,EAAgB,KAAK,aAAa,iBAAiB,EACrD,CAACD,GAAS,CAAC1B,EAAO,2BAA6B,CAAC,KAAK,iBAAmB,CAAC2B,EAAc,yBAGvF,KAAK,gBACL,KAAK,qBAAqB,EAE9B,KAAK,eAAiB,IAAIC,GAAoBF,EAAO,KAAK,gBAAiB,KAAK,WAAYC,EAAc,0BAA0B,EACxI,CAEQ,sBAAuB,CAC3B,KAAK,gBAAgB,QAAQ,EAC7B,KAAK,eAAiB,IAC1B,CAEQ,wBAAyB,CACzB,CAAC3B,EAAO,2BAA6B,CAAC,KAAK,kBAG3C,KAAK,kBACL,KAAK,uBAAuB,EAEhC,KAAK,iBAAmB,IAAI6B,GACxB,KAAK,gBACL,KAAK,uBACL,CAACC,EAAUC,IAAW,CAClB,KAAK,qCAAmDD,EAAUC,CAAM,CAC5E,EACCD,GAAa,CACV,KAAK,qCAAmDA,EAAU,IAAI,CAC1E,EACCE,GAAS,CACN,KAAK,oCAAkDA,CAAI,CAC/D,CACJ,EACJ,CAEQ,wBAAyB,CAC7B,KAAK,kBAAkB,QAAQ,EAC/B,KAAK,iBAAmB,IAC5B,CAEQ,wBAAyB,CAC7B,IAAMC,EACF,KAAK,aAAa,iBAAiB,EAAE,wBAA0B,CAACjC,EAAO,0BAA4B,KAAK,gBAAgB,cAAgB,KAAK,gBAAgB,OAEjK,GAAIiC,GAAiB,KAAK,IAAK,CAC3B,IAAMC,EAAuB,CAAC,EAC9B,KAAK,IAAI,WAAW,EAAE,QAAS/B,GAAM,CACjC,GAAI,CAACA,EAAE,OAASA,EAAE,MAAM,OAAS,SAAwBA,EAAE,MAAM,cAAgB,SAC7E,OAGJ,IAAMgC,EAAqB,CAAC,KAAK,iBAAiB,IAAIhC,CAAC,EACjDiC,EAAoBH,EAAc,eAAiB,EAEzD,GAAIE,GAAsB,CAACC,EAAmB,CAC1C7C,EAAM,IAAI,wBAAwB,EAClC,KAAK,iBAAiB,IAAIY,CAAC,EAC3BA,EAAE,aAAaF,EAAY,mBAAmB,CAAC,EAAE,MAAOP,GAAU,CAC9DH,EAAM,MAAM,iCAAkCG,CAAK,CACvD,CAAC,EACD,MACJ,CAEA,IAAM2C,EAAiB,KAAK,aAAa,kBAAkB,EAC3D,GAAI,CAACF,GAAsBC,GAAqBC,EAAgB,CAC5D9C,EAAM,IAAI,uBAAuB,EACjC,KAAK,iBAAiB,OAAOY,CAAC,EAE9B,IAAMmC,EAAanC,EAAE,MAErBmC,EAAW,QAAUD,EAAe,QAEpClC,EAAE,aAAakC,CAAc,EACxB,KAAK,IAAMC,EAAW,KAAK,CAAC,EAC5B,MAAO5C,GAAU,CACdH,EAAM,MAAM,gCAAiCG,CAAK,CACtD,CAAC,CACT,CAEAgB,EAAM,wBAAwBuB,EAAe9B,EAAGkC,GAAkBlC,EAAE,MAAO,KAAK,sBAAuB+B,CAAe,CAC1H,CAAC,EACD,KAAK,sBAAwBA,CACjC,CAEA,GAAI,KAAK,aAAa,iBAAiB,EAAE,4BAA8BlC,EAAO,wBAAyB,CACnG,IAAMuC,EAAqB,KAAK,gBAAgB,kBAEhD,GAAIA,GAAsB,KAAK,IAAK,CAChC,IAAML,EAAuB,CAAC,EAC9B,KAAK,IAAI,WAAW,EAAE,QAAS/B,GAAM,CAC7B,CAACA,EAAE,OAASA,EAAE,MAAM,OAAS,SAAwBA,EAAE,MAAM,cAAgB,UAIjFO,EAAM,wBAAwB6B,EAAoBpC,EAAGA,EAAE,MAAO,KAAK,iCAAkC+B,CAAe,CACxH,CAAC,EACD,KAAK,iCAAmCA,CAC5C,CACJ,CACJ,CAEQ,uBAAuBM,EAA2C,CAClEA,EAAM,OACF,CAACxC,EAAO,yBAA2B,CAAC,KAAK,aAAa,iBAAiB,EAAE,6BACzE,KAAK,qBAAqBwC,EAAM,KAAK,EAGzC,KAAK,qBAAqB,CAElC,CAEQ,UAAUhD,EAAuB,CACjC,KAAK,SAAWA,IAIpB,KAAK,OAASA,EACd,KAAK,8BAA4CA,CAAK,EAC1D,CAEQ,oBAAqB,CACzB,GAAI,KAAK,cACL,OAGJ,IAAMiD,EAAQ,IAAM,CAChB,GAAI,CAAC,KAAK,IAAK,CACX,KAAK,kBAAkB,EACvB,MACJ,CAEA,KAAK,aAAa,EACb,KAAMT,GAAmB,CACtB,KAAK,aAAaA,CAAI,EACtB,KAAK,mBAAmBA,CAAI,EAC5BU,GAAqB,YAAYV,CAAI,CACzC,CAAC,EACA,MAAM,IAAM,CAEb,CAAC,EAEL,KAAK,cAAgB,OAAO,WAAWS,EAAOzC,EAAO,kBAAkB,CAC3E,EAEA,KAAK,cAAgB,OAAO,WAAWyC,EAAOzC,EAAO,kBAAkB,CAC3E,CAEQ,mBAAoB,CACpB,KAAK,gBACL,OAAO,aAAa,KAAK,aAAa,EACtC,KAAK,cAAgB,MAEzB,KAAK,WAAa,CAAC,CACvB,CAEQ,wBAAyB,CAG7B,GAAI,KAAK,kBACL,OAGJ,IAAMyC,EAAQ,IAAM,CAChB,GAAI,CAAC,KAAK,IAAK,CACX,KAAK,sBAAsB,EAC3B,MACJ,CAEA,KAAK,uBAAuB,EAC5B,KAAK,kBAAoB,OAAO,WAAWA,EAAO,GAAQ,CAC9D,EAEA,KAAK,kBAAoB,OAAO,WAAWA,EAAO,GAAQ,CAC9D,CAEQ,uBAAwB,CACxB,KAAK,oBACL,OAAO,aAAa,KAAK,iBAAiB,EAC1C,KAAK,kBAAoB,KAEjC,CAEA,MAAc,cAAkC,CAC5C,GAAI,CAAC,KAAK,IACN,OAAO,QAAQ,OAAO,EAGtB,KAAK,kBACL,KAAK,UAAY,KACjB,KAAK,gBAAkB,GACvB,KAAK,yBAAyB,GAGlC,IAAMT,EAAO,MAAMW,GAAW,aAAa,KAAK,IAAK,KAAK,UAAW,KAAK,SAAU,EAAI,EACxF,YAAK,UAAYX,EACVA,CACX,CAEQ,aAAaA,EAAgB,CACjC,KAAK,kCAAgD,CACjD,QAAS,CACL,kBACA,UAAWA,EAAK,UAChB,KAAMA,EAAK,KAAK,OAAQY,GAAQA,EAAI,OAAS,aAAa,CAC9D,EACA,SAAU,CACN,kBACA,UAAWZ,EAAK,UAChB,KAAMA,EAAK,KAAK,OAAQY,GAAQA,EAAI,OAAS,cAAc,CAC/D,EACA,cAAe,CACX,kBACA,UAAWZ,EAAK,UAChB,KAAMA,EAAK,YAAc,CAAC,CAC9B,CACJ,CAAC,CACL,CAEQ,mBAAmBA,EAAgB,CACvC,IAAMa,EAAcb,EAAK,KAAK,KAAMY,GAAQA,EAAI,OAAS,eAAiBA,EAAI,OAAS,SAAW,KAAK,SAASA,EAAI,IAAI,IAAM,KAAK,EACnI,GAAI,CAACC,EACD,OAGJ,IAAMC,EAAStB,GAAQ,UACjBuB,EAAW,KAAK,WAAWD,CAAM,EACnCE,EAAU,GAEd,GAAID,EAAU,CACV,IAAME,EAAOJ,EAAY,cAAgBE,EAAS,cAG9CE,GAAQ,GAAKA,GAAQ,IACrBD,EAAU,IAGVD,EAAS,UAAYC,GACrB,KAAK,gCAA8CA,CAAO,CAElE,CAEA,KAAK,WAAWF,CAAM,EAAI,CAAE,cAAeD,EAAY,cAAe,QAAAG,CAAQ,CAClF,CAEQ,mBAAoB,CACxB,GAAI,CAAC,KAAK,WAAW,MACjB,OAGJ,IAAME,EAAe,CACjB,0BAA2BhD,GAAiB,6BAA6B,EACzE,SAAU,GACV,eAAgB,GAChB,uCAAwCF,EAAO,gCAAkC,EAAI,EACrF,kCAAmCA,EAAO,2BAA6B,EAAI,EAC3E,iCAAkCA,EAAO,0BAA4B,EAAI,EACzE,iCAAkCA,EAAO,0BAA4B,EAAI,EACzE,sBAAuBA,EAAO,eAAiB,EAAI,EACnD,0BAA2BA,EAAO,MAAQA,EAAO,aAAa,gBAAkB,EAChF,qBAAsB,CAACA,EAAO,aAAa,iBAAiB,uBAC5D,eAAgB,GAChB,YAAa,GACb,cAAe,GACf,iBAAkBA,EAAO,iBACzB,IAAKA,EAAO,eACZ,WAAYA,EAAO,WACnB,gBAAiBA,EAAO,gBACxB,aAAcA,EAAO,aACrB,UAAWA,EAAO,WAAaC,EAAY,8BAA8B,EACzE,wBAAyBD,EAAO,wBAChC,uCAAwCA,EAAO,sCACnD,EAEI,CAACA,EAAO,kBAAoB,CAAC,KAAK,WAElCT,EAAM,KAAK,6CAA6C,EAG5D,KAAK,WAAW,iBAAiB,KAAM2D,CAAY,CACvD,CAEA,MAAc,cAAcC,EAA2D,CACnF,GAAI,CAAC,KAAK,IACN,MAAM,IAAI,MAAM,sBAAsB,EAE1C,IAAMC,EAAuBpD,EAAO,WAAaC,EAAY,8BAA8B,EACvFoD,EAAYD,EAEhB,GAAI,CACA,MAAM,KAAK,IAAI,qBAAqBD,CAAK,CAC7C,OAASzD,EAAO,CACZ,MAAAH,EAAM,MAAM,sCAAuCG,CAAK,EACxDqB,EAAO,IAAIC,EAAQ,MAAO,6BAA6B,EACjDtB,CACV,CAGA,IAAM4D,EAAiB,KAAK,yBAAyB,EACrD,GAAIF,EACA,GAAIE,EAAgB,CAChB/D,EAAM,IAAI,iCAAiCS,EAAO,SAAS,QAAQsD,EAAe,GAAG,QAAQA,EAAe,SAAS,EAAE,EACvH,IAAMvB,EAA6B,KAAK,aAAa,UAAU,EACzDwB,EAAU,MAAM,KAAK,2BAA2BxB,EAAQuB,CAAc,EAC5E/D,EAAM,IAAI,+BAAgCgE,CAAO,EAC5CA,IACDhE,EAAM,IAAI,sEAAsE+D,EAAe,GAAG,qBAAqB,EACvHD,EAAY,GAEpB,MACI9D,EAAM,IAAI,mFAAmF,EAC7F8D,EAAY,GAIpB,IAAIG,EACJ,GAAI,CAIA,GAHA,MAAM,KAAK,cAAc,EACzBjE,EAAM,MAAM,8BAA8B,EAEtC,CAAC,KAAK,IACN,MAAM,IAAI,MAAM,sBAAsB,EAG1CiE,EAAU,MAAM,KAAK,IAAI,aAAa,CAC1C,OAAS9D,EAAO,CACZ,MAAAH,EAAM,MAAM,mCAAoCG,CAAK,EACrDqB,EAAO,IAAIC,EAAQ,MAAO,qBAAqB,EAEzCtB,CACV,CAEA,GAAI,CACA,GAAI,CAAC,KAAK,IACN,MAAM,IAAI,MAAM,sBAAsB,EAI1C8D,EAAO,IAAM9C,EAAM,cACf8C,EAAO,IACP,GACAvD,EAAY,oBAAoB,EAChC,GACAD,EAAO,uBAEX,EAEAT,EAAM,MAAM,4BAA6B,CAAE,OAAAiE,CAAO,CAAC,EACnD,MAAM,KAAK,IAAI,oBAAoBA,CAAM,CAC7C,OAAS9D,EAAO,CACZ,MAAAH,EAAM,MAAM,sCAAuCG,CAAK,EACxDqB,EAAO,IAAIC,EAAQ,MAAO,4BAA4B,EAEhDtB,CACV,CAGA,GAAI2D,GAAaC,EAAgB,CAC7BE,EAAO,IAAM9C,EAAM,wBAAwB8C,EAAO,IAAKF,EAAgBG,GAAkB,MAAOA,GAAkB,MAAM,EAExH,QAAWC,KAAS,KAAK,IAAI,gBAAgB,EACrCA,EAAM,MAAQ,MACdA,EAAM,KAAK,CAGvB,CAEA,GAAI,CACAnE,EAAM,MAAM,iCAAkC,CAAE,OAAAiE,CAAO,CAAC,EACxD,KAAK,eAAeL,CAAK,EAEzB,MAAM,KAAK,WAAW,eAAeK,EAAQ,OAAO,KAAK,KAAK,QAAQ,CAAC,EACvEjE,EAAM,MAAM,0CAA0C,CAC1D,OAASG,EAAO,CACZH,EAAM,KAAK,uCAAwCG,CAAK,EACxDqB,EAAO,IAAIC,EAAQ,MAAO,gBAAgB,CAE9C,CAGIqC,GACA,MAAM,KAAK,qBAAqB,GAAM,EAAI,CAElD,CAEQ,0BAA2B,CAC/B,GAAI,CAAC,KAAK,IACN,OAAO,KAEX,QAAWK,KAAS,KAAK,IAAI,gBAAgB,EAAG,CAC5C,IAAMC,EAAOD,EAAM,QAAQ,MAAQA,EAAM,OAAO,OAAO,KAAOA,EAAM,UAAU,OAAO,KACrF,GAAI,CAACA,EAAM,QAAUC,IAAS,QAC1B,SAEJ,IAAMC,EAASF,EAAM,OAAO,cAAc,EAC1C,GAAI,GAACE,EAAO,WAAaA,EAAO,UAAU,QAAU,GAGpD,OAAOF,CACX,CACA,OAAO,IACX,CAEA,MAAc,2BAA2B3B,EAA4B8B,EAAgC,CACjG,GAAI,CAACA,GAAa,QAAU,CAAC9B,EACzB,OAAO,KAEX8B,EAAY,UAAY,WACxB,IAAMnC,EAAQK,EAAO,eAAe,EAAE,CAAC,EACvC,MAAM8B,EAAY,OAAO,aAAanC,CAAK,EAC3CmC,EAAY,OAAO,WAAW9B,CAAM,EACpC,IAAM6B,EAASC,EAAY,OAAO,cAAc,EAChD,GAAI,CAACD,EAAO,WAAaA,EAAO,UAAU,QAAU,EAEhD,OAAArE,EAAM,IAAI,mBAAmBsE,EAAY,GAAG,QAAQA,EAAY,SAAS,qBAAqB,KAAK,UAAUD,EAAO,SAAS,CAAC,EAAE,EACzH,KAGX,IAAME,EAA+BC,GAAuBN,GAAkB,MAAOA,GAAkB,OAAQ,KAAK,gBAAgB,QAAQ,UAAU,OAAO,EACzJO,EAAI,EACJC,EAAS,EACb,QAAWC,KAAYN,EAAO,UAC1BM,EAAS,gBAAkBC,GAC3BD,EAAS,OAAS,GACdF,GAAKF,EAAc,QAAQ,OAE3BI,EAAS,WAAa,EAEtBA,EAAS,WAAaJ,EAAc,QAAQE,CAAC,EAAE,QAEnDE,EAAS,sBAAwBD,EACjCA,EAASA,EAAS,EAClBD,IAEJ,MAAMH,EAAY,OAAO,cAAcD,CAAM,EAC7C,IAAMzD,EAAIuB,EAAM,YAAY,EAC5B,OAAAnC,EAAM,IAAI,mBAAmBsE,EAAY,GAAG,QAAQA,EAAY,SAAS,UAAU1D,EAAE,KAAK,IAAIA,EAAE,MAAM,cAAc,KAAK,UAAUyD,EAAO,SAAS,CAAC,EAAE,EAC/I,EACX,CAEA,MAAc,gBAAgBQ,EAA4B,CACtD,GAAI,KAAK,2BAA4B,CACjC,KAAK,mBAAqBA,EAC1B7E,EAAM,MAAM,qDAAqD,EACjE,MACJ,CACA,KAAK,2BAA6B,GAElC,IAAM4D,EAA6C,CAC/C,KAAM,QACN,IAAKzC,EAAM,eAAe0D,EAAKnE,EAAY,4BAA4B,EAAG,GAAO,GAAO,GAAOA,EAAY,mBAAmB,EAAGA,EAAY,mBAAmB,CAAC,CACrK,EAIA,GAFAV,EAAM,MAAM,4BAA6B,CAAE,MAAA4D,CAAM,CAAC,EAE9C,CAAC,KAAK,IACN,MAAM,IAAI,MAAM,sBAAsB,EAG1C,GAAI,CAKA,GAJA,MAAM,KAAK,cAAcA,CAAK,EAE9B,KAAK,2BAA6B,GAE9B,KAAK,mBAAoB,CACzB5D,EAAM,MAAM,8DAA8D,EAE1E,IAAM8E,EAAY,KAAK,mBACvB,KAAK,mBAAqB,KAE1B,MAAM,KAAK,gBAAgBA,CAAS,CACxC,CACJ,OAAS7D,EAAQ,CACb,KAAK,MAAMA,CAAC,CAChB,CACJ,CAEA,MAAc,0BAA2B,CACrC,IAAM8D,EAAyB,KAAK,KAAK,gBAAgB,EAAE,KAAMC,GAASA,EAAK,KAAK,SAAS,GAAG,GAAKA,GAAM,UAAU,MAAM,OAAS,OAAoB,EACxJ,GAAI,CAACD,GAA0B,CAACA,EAAuB,OAAQ,CAC3D/E,EAAM,KAAK,qCAAqC,EAChD,MACJ,CAEA,GAAI,CACA+E,EAAuB,UAAY,WACnC,MAAMA,EAAuB,OAAO,aAAa,KAAK,aAAa,oBAAoB,CAAC,CAC5F,OAAS9D,EAAG,CACRjB,EAAM,MAAM,2CAA4CiB,CAAC,CAC7D,CACJ,CAEA,MAAc,eAAgB,CACtB,KAAK,YAGT,MAAM,KAAK,uBAAuB,EAClC,MAAM,KAAK,wBAAwB,EACvC,CAEA,MAAc,wBAAyB,CACnC,GAAI,CAAC,KAAK,oBACN,OAIJ,IAAMqD,EAAc,KAAK,KAAK,gBAAgB,EAAE,KAAMU,GAASA,EAAK,KAAK,SAAS,GAAG,GAAKA,GAAM,UAAU,MAAM,OAAS,OAAoB,EAC7I,GAAI,CAACV,GAAe,CAACA,EAAY,OAAQ,CACrCtE,EAAM,KAAK,oCAAoC,EAC/C,MACJ,CAEIsE,EAAY,OAAO,QAAU,MAC7BtE,EAAM,KAAK,yCAAyC,EAGxD,GAAI,CACAsE,EAAY,UAAY,WACxB,MAAMA,EAAY,OAAO,aAAa,KAAK,mBAAmB,EAC9D,KAAK,oBAAsB,IAC/B,OAASrD,EAAG,CACRjB,EAAM,MAAM,2CAA4CiB,CAAC,EACzDO,EAAO,IAAIC,EAAQ,MAAO,qBAAqB,CACnD,CACJ,CAEA,MAAc,yBAA0B,CACX,KAAK,aAAa,oBAAoB,GAK/D,MAAM,KAAK,yBAAyB,CACxC,CAEA,MAAc,yBAAyBwD,EAA2B,CAC9D,GAAK,KAAK,QAIV,OAAQA,EAAQ,aAAc,CAC1B,KAAKC,EAAsB,iBACvB,MAAM,KAAK,mBAAmBD,CAA2C,EACzE,MACJ,KAAKC,EAAsB,YACvB,KAAK,WAAW,EAChB,MACJ,KAAKA,EAAsB,eACvB,KAAK,0BAA0BD,EAAQ,kBAAkB,EACzD,MACJ,KAAKC,EAAsB,gBACvB,KAAK,sBAAsBD,EAAQ,OAAO,EAC1C,MACJ,KAAKC,EAAsB,iBACvB,KAAK,2BAA2BD,EAAQ,mBAAmB,EAC3D,MACJ,KAAKC,EAAsB,eACvB,KAAK,qBAAqBD,EAAQ,QAAQ,EAC1C,KACR,CACJ,CAEQ,oBAAoB1D,EAAuB,CAC/C,KAAK,kCAAgDA,CAAG,CAC5D,CAEA,MAAc,mBAAmB0D,EAA2C,CAEpE,KAAK,oBAAsB,KAAK,qBAAuBA,EAAQ,WAC/D,KAAK,WAAW,EAGhBxE,EAAO,yBACPT,EAAM,IAAI,uCAAuC,EACjD,KAAK,WAAW,gBAAgB,yBAA0B,IAAI,GAElE,KAAK,mBAAqBiF,EAAQ,UAClC,MAAM,KAAK,gBAAgBA,EAAQ,WAAW,CAClD,CAEQ,YAAYE,EAAwBlC,EAAY,CACpDjD,EAAM,MAAM,gCAAiC,CAAE,MAAOiD,EAAM,KAAM,CAAC,EAEnE,IAAMT,EAAsBS,EAAM,QAAQ,CAAC,EACvCT,GACKA,EAAO,gBACRA,EAAO,cAAiBvB,GAAM,CAC1B,KAAK,qCAAmDuB,EAAO,GAAIA,EAAQvB,EAAE,KAAK,CACtF,GAGkBuB,EAAO,UAAU,EAAE,KAAML,GAAUA,EAAM,KAAOc,EAAM,MAAM,EAAE,GAEhFT,EAAO,SAASS,EAAM,KAAK,EAE/B,KAAK,wBAAwBT,EAAO,EAAE,EAAIS,EAAM,SAChD,KAAK,mCAAiDT,EAAO,GAAIA,EAAQS,EAAM,KAAK,GAEpFjD,EAAM,MAAM,sDAAsD,CAE1E,CAEA,OAAO,wBAAwBoF,EAAuBnC,EAAY,CAC9DjD,EAAM,MAAM,mCAAoC,CAAE,MAAOoF,EAAG,cAAe,EAAGnC,CAAK,CACvF,CAEQ,yBAAyBmC,EAAuBnC,EAAY,CAIhE,OAHAjD,EAAM,MAAM,oCAAqC,CAAE,MAAOoF,EAAG,eAAgB,EAAGnC,CAAK,EACrFzB,EAAO,IAAIC,EAAQ,qBAAsB2D,EAAG,eAAe,EAEnDA,EAAG,gBAAiB,CACxB,IAAK,SACG,KAAK,uBACL,KAAK,MAAM,IAAI,MAAM,uBAAuB,CAAC,GAE7C5D,EAAO,UAAUC,EAAQ,UAAW,CAAE,MAAO,CAAE,CAAC,EAEhD,KAAK,WAAW,GAEpB,MAEJ,IAAK,aACD,IAAMxB,EAAQ,KAAK,SAAS,EACxBA,IAAU,QAAuBA,IAAU,SAC3C,KAAK,sBAAmC,EACjCmF,EAAG,qBAAuB,YACjC,KAAK,wBAAqC,EAE9C,MAEJ,IAAK,eACG,KAAK,uBACL,KAAK,MAAM,IAAI,MAAM,6BAA6B,CAAC,EAEnD,KAAK,wBAAqC,EAE9C,MAEJ,IAAK,YACD,KAAK,qBAAkC,EACvCjE,EAAM,0BAA0BiE,CAAE,EAAE,KAAMC,GAAS,CAC3CA,GAAM,QACN7D,EAAO,IAAIC,EAAQ,oBAAqB4D,EAAK,MAAM,IAAI,EACvDrF,EAAM,MAAM,0BAA2BqF,CAAI,EAEnD,CAAC,EACD7D,EAAO,UAAUC,EAAQ,UAAW,CAAE,MAAO,CAAE,CAAC,EAChD,KACR,CACJ,CAEQ,iBAAiB6D,EAA4BC,EAA8B,CAC/E,GAAI,KAAK,IAAK,CACVvF,EAAM,MAAM,8BAA8BsF,CAAQ,eAAeC,CAAS,EAAE,EACxE9E,EAAO,2BAA6B8E,IACpCD,EAAWC,GAGf,IAAMC,EAAe,CAAChF,EAAsB2B,IAA4B,CACpE3B,EAAO,aAAa2B,CAAK,EAAE,MAAOhC,GAAU,CACxCH,EAAM,MAAM,2CAA4CG,CAAK,EAC7DqB,EAAO,IAAIC,EAAQ,MAAO,qBAAqB,CACnD,CAAC,CACL,EAGA,GADAzB,EAAM,IAAI,8BAA8BsF,EAAS,YAAY,EAAE,KAAK,IAAIA,EAAS,YAAY,EAAE,MAAM,EAAE,EACnG7E,EAAO,WAAaC,EAAY,8BAA8B,GAAK4E,EAAS,OAAS,QAAsB,CAI3G,IAAM9E,EAHmB,KAAK,KACxB,gBAAgB,EACjB,KAAMiF,GAAMA,EAAE,YAAc,YAAcA,EAAE,QAAQ,OAAO,OAAS,SAAwBA,EAAE,OAAO,MAAM,cAAgBH,EAAS,WAAW,GACnH,OAC7B9E,GAAQ,OACRgF,EAAahF,EAAQ8E,CAAQ,EACzBA,EAAS,YAAY,EAAE,OAASA,EAAS,YAAY,EAAE,QAEvD,KAAK,qBAAqB,GAAO,EAAK,GAG1CtF,EAAM,KAAK,yDAAyD,CAE5E,KAAO,CACH,IAAMQ,EAAS,KAAK,KACd,WAAW,EACZ,KAAMwE,GAASA,EAAK,OAASA,EAAK,MAAM,OAASM,EAAS,MAAQ,CAAC,KAAK,iBAAiB,IAAIN,CAAI,GAAKA,EAAK,MAAM,cAAgBM,EAAS,WAAW,EACtJ9E,GAAQ,MAIRgF,EAAahF,EAAQ8E,CAAQ,EACtBA,EAAS,OAAS,SAAwBA,EAAS,cAAgB,UAC1E,KAAK,oBAAsBA,EAEnC,CACJ,CACA,KAAK,uBAAuB,CAChC,CAEA,MAAc,kBAAkB,CAAE,KAAAlB,CAAK,EAA6B,CAC5DA,IAAS,UAAyB3D,EAAO,yBAA2B,KAAK,aAAa,iBAAiB,EAAE,4BACzG,MAAM,KAAK,yBAAyB,EAGxC,KAAK,uBAAuB,CAChC,CAEA,uBAAuB8B,EAAkBmD,EAAoC,CACzE,GAAI,CAAC,KAAK,IACN,OAAAlE,EAAO,IAAIC,EAAQ,uBAAwB,cAAc,EACzDzB,EAAM,MAAM,oEAAoE,EACzE,EAEX,GAAI,CAAC,eAAe,UAAU,0BAC1B,OAAAwB,EAAO,IAAIC,EAAQ,uBAAwB,YAAY,EACvDzB,EAAM,MAAM,2FAA2F,EAChG,EAEX,IAAMO,EAAW,KAAK,wBAAwBgC,CAAQ,EACtD,GAAI,CAAChC,EACD,OAAAiB,EAAO,IAAIC,EAAQ,uBAAwB,YAAY,EACvDzB,EAAM,MAAM,0EAA0EuC,CAAQ,EAAE,EACzF,EAEX,IAAMoD,EAAyBpF,EAAS,0BAA0B,EAClE,GAAI,CAACoF,GAA0B,CAACA,EAAuB,OAEnD,OAAA3F,EAAM,IAAI,mCAAmCuC,CAAQ,0CAA0C,EACxF,EAGX,IAAMqD,EADwBD,EAAuB,CAAC,EACX,aAC3C,GAAI,CAAC,OAAO,UAAUC,CAAY,EAC9B,OAAApE,EAAO,IAAIC,EAAQ,uBAAwB,qBAAqB,EAChEzB,EAAM,MAAM,mCAAmCuC,CAAQ,gDAAgDqD,CAAY,EAAE,EAC9G,EAGX,IAAMC,EAAoBH,EAAqBE,EAAgBrG,GACzDuG,EAAgB,KAAK,KAAKD,EAAmBvG,EAAmB,EACtE,OAAO,KAAK,IAAI,IAAK,KAAK,IAAI,EAAGwG,CAAa,CAAC,CACnD,CAEA,MAAc,qBAAqBC,EAAyBC,EAAuB,CAE/E,IAAMC,EAAiB,KAAK,aAAa,iBAAiB,EAAE,eACtD3B,EAAc,KAAK,yBAAyB,EAClD,GAAI,CAAC7D,EAAO,WAAa,CAACC,EAAY,8BAA8B,GAAK,CAACuF,GAAkB,CAAC3B,GAAe,CAACA,EAAY,OACrH,OAGJ,IAAM9B,EAA6B,KAAK,aAAa,UAAU,EAC/D,GAAI,CAACA,EACD,OAEJ,IAAML,EAAQK,EAAO,eAAe,EAAE,CAAC,EACjC0D,EAAQ/D,EAAM,YAAY,EAAE,MAC5BgE,EAAShE,EAAM,YAAY,EAAE,OAE7BoC,EAAgBC,GAAuB0B,EAAOC,EAAQ,KAAK,gBAAgB,QAAQ,UAAU,OAAO,EACpGC,EAAqBJ,GAAgB,CAACK,GAAqB,KAAK,eAAgB9B,CAAa,EACnG,GAAI,CAACA,EAAc,QAAQ,QAAU,CAAC6B,EAClC,OAEJ,IAAME,EAAehC,EAAY,OAAO,cAAc,EAKtD,GAJKgC,EAAa,YAEdA,EAAa,UAAY,CAAC,CAAC,CAAC,GAE5B,EAAAA,EAAa,UAAU,QAAU,GAMrC,IADAtG,EAAM,IAAI,yBAAyBkG,CAAK,IAAIC,CAAM,aAAa,KAAK,UAAU5B,CAAa,CAAC,GAAG,EAC3FwB,EAAgB,CAGhB,IAAItB,EAAI,EACR,QAAWE,KAAY2B,EAAa,UAChC3B,EAAS,sBAAwB4B,GAA0B5B,EAAS,GAAG,EACvEA,EAAS,gBAAkBC,GACvBH,GAAKF,EAAc,QAAQ,QAC3BI,EAAS,WAAa,EACtBA,EAAS,OAAS,KAElBA,EAAS,OAAS,GAClBA,EAAS,WAAaJ,EAAc,QAAQE,CAAC,EAAE,SAEnDA,IAEJ,MAAMH,EAAY,OAAO,gBAAgBgC,CAAY,EAAE,MAAOrF,GAAM,CAChEjB,EAAM,MAAM,kCAAmCsG,EAAcrF,CAAC,CAClE,CAAC,EACDjB,EAAM,IAAI,2CAA2C,KAAK,UAAUsG,EAAa,SAAS,CAAC,GAAG,CAClG,CAKA,GAFA,KAAK,eAAiB/B,EAElBA,EAAc,QAAS,CACvB,IAAMiC,EAAwB,CAAE,cAAqC,cAAAjC,CAAc,EACnF,MAAM,KAAK,WAAW,gBAAgBiC,CAAI,CAC9C,EACJ,CAEA,MAAc,kBAAmB,CAC7B,IAAMC,EAAgBC,GAAmB,YAAY,EAAE,MAEvD,GAAI,CAAC,KAAK,aAAa,iBAAiB,EAAE,4BAA8B,CAACjG,EAAO,yBAA2BgG,EAAgB,GACvH,OAGJ,IAAMjG,EAAS,KAAK,KAAK,WAAW,EAAE,KAAMA,GAAWA,EAAO,OAAO,OAAS,SAAwBA,EAAO,OAAO,cAAgB,QAAQ,EAE5I,GAAI,CAACA,EACD,QAGgB,MAAMA,EAAO,SAAS,GAE9B,QAASiC,GAAS,CAC1B,GACIA,EAAK,OAAS,gBACd,KAAK,gBAAgB,mBACrBA,EAAK,WAAa,KAAK,gBAAgB,kBAAkB,cACzDA,EAAK,WAAa,OAAO,OAAO,MAClC,CACE,IAAM6D,EAAe9F,EAAO,cAAc,EAC1C8F,EAAa,sBAAwB,sBACrC9F,EAAO,cAAc8F,CAAY,EACjCtG,EAAM,IACF;AAAA;AAAA,0CAEsB,KAAK,UAAUyC,CAAI,CAAC;AAAA,sCACxB,KAAK,UAAU,KAAK,gBAAgB,iBAAiB,CAAC;AAAA,qBAE5E,CACJ,CACJ,CAAC,CACL,CAEQ,+BAAgC,CAGpC,GAAI,KAAK,yBACL,OAGJ,IAAMS,EAAQ,IAAM,CAChB,GAAI,CAAC,KAAK,IAAK,CACX,KAAK,6BAA6B,EAClC,MACJ,CAEA,KAAK,iBAAiB,EACtB,KAAK,yBAA2B,OAAO,WAAWA,EAAO,GAAQ,CACrE,EAEA,KAAK,yBAA2B,OAAO,WAAWA,EAAO,GAAQ,CACrE,CAEQ,8BAA+B,CAC/B,KAAK,2BACL,OAAO,aAAa,KAAK,wBAAwB,EACjD,KAAK,yBAA2B,KAExC,CACJ,EC/qCO,IAAWyD,QACdA,EAAA,OAAS,SACTA,EAAA,OAAS,SAFKA,QAAA,IAKLC,GAAN,cAAwBC,EAAa,CAuBxC,YAAYC,EAA6BC,EAA0BC,EAA0BC,EAAgC,CACzH,MAAM,EAvBVC,EAAA,KAAiB,cACjBA,EAAA,KAAiB,gBACjBA,EAAA,KAAQ,aAGRA,EAAA,KAAQ,aAA8B,CAAC,GACvCA,EAAA,KAAQ,UAA2B,CAAC,GAEpCA,EAAA,KAAQ,mBAA2C,MACnDA,EAAA,KAAQ,mBAA2C,MAEnDA,EAAA,KAAQ,mBAERA,EAAA,KAAQ,eAAwC,CAAC,GACjDA,EAAA,KAAQ,eAAwC,CAAC,GAEjDA,EAAA,KAAQ,UAAiD,CAAC,GAC1DA,EAAA,KAAQ,cAA8B,QAEtCA,EAAA,KAAQ,mBAA2C,MACnDA,EAAA,KAAQ,iBAAuC,MAK3C,KAAK,WAAaH,EAClB,KAAK,aAAeC,EACpB,KAAK,UAAYF,EACjB,KAAK,gBAAkBG,EAEvB,KAAK,UAAU,KAAK,WAAYE,GAAe,aAAc,KAAK,yBAAyB,KAAK,IAAI,CAAC,EACrG,KAAK,UAAU,KAAK,8BAA+C,KAAK,iBAAiB,KAAK,IAAI,CAAC,EACnG,KAAK,UAAU,KAAK,8BAA+C,KAAK,iBAAiB,KAAK,IAAI,CAAC,EAEnG,KAAK,wBAAwB,EAGzBL,IAAa,WACb,KAAK,iBAAmB,KAAK,uBAAuB,EAE5D,CAEA,eAAeM,EAA0B,CACrCC,EAAM,IAAI,4BAA6BD,CAAQ,EAE/C,KAAK,gBAAkBA,EACnB,KAAK,kBACL,KAAK,iBAAiB,eAAeA,CAAQ,EAE7C,KAAK,kBACL,KAAK,iBAAiB,eAAeA,CAAQ,CAErD,CAEA,0BAA2B,CACnB,KAAK,kBACL,KAAK,iBAAiB,yBAAyB,EAE/C,KAAK,kBACL,KAAK,iBAAiB,yBAAyB,CAEvD,CAEA,SAASE,EAA8BC,EAAW,GAAO,CAGrD,GAFAF,EAAM,IAAI,gCAAgCC,CAAa,GAAG,EAEtD,KAAK,WAAW,QAAQA,CAAa,IAAM,GAAI,CAC/CD,EAAM,KAAK,oBAAoBC,CAAa,uCAAuC,EACnF,MACJ,CAEA,KAAK,WAAW,KAAKA,CAAa,EAE9B,KAAK,YAAc,UAA4B,CAAC,KAAK,mBACrD,KAAK,iBAAmB,KAAK,uBAAuBA,EAAeC,CAAQ,GAG3E,KAAK,YAAc,UAA4B,CAAC,KAAK,mBACrD,KAAK,iBAAmB,KAAK,uBAAuB,EAE5D,CAEA,KAAKC,EAAiCC,EAAwB,KAAMC,EAAW,GAAOC,EAAQ,GAAO,CACjGN,EAAM,IAAI,0BAA2B,CAAE,eAAAG,CAAe,CAAC,EAEvD,IAAII,EAAWD,EACf,QAAWL,KAAiBE,EAAgB,CACxC,GAAI,KAAK,QAAQ,QAAQF,CAAa,IAAM,GAAI,CAC5CD,EAAM,KAAK,oBAAoBC,CAAa,oCAAoC,EAChF,QACJ,CAEA,GAAI,KAAK,WAAW,QAAQA,CAAa,IAAM,GAAI,CAC/CD,EAAM,KAAK,oBAAoBC,CAAa,8BAA8B,EAC1E,QACJ,CAEA,KAAK,QAAQ,KAAKA,CAAa,EAC/BM,EAAW,EACf,CAEKA,IAID,KAAK,YAAc,UAA4B,KAAK,kBACpD,KAAK,iBAAiB,KAAKH,CAAM,EAGjC,KAAK,YAAc,UAA4B,KAAK,mBACpD,KAAK,iBAAiB,KAAKC,CAAQ,EAGnC,KAAK,WAAWF,EAAgB,KAAK,iBAAiB,SAAS,CAAC,EAChE,KAAK,eAAe,KAAK,iBAAiB,SAAS,CAAC,GAGxDH,EAAM,MAAM,gCAAiCG,CAAc,EAC/D,CAEA,MAAMF,EAA8B,CAChC,IAAMO,EAAiB,KAAK,WAAW,QAAQP,CAAa,EACtDQ,EAAc,KAAK,QAAQ,QAAQR,CAAa,EAElDO,EAAiB,GACjBR,EAAM,KAAK,oBAAoBC,CAAa,qCAAqC,EAGjF,KAAK,YAAc,UAA4B,KAAK,kBAAoBQ,GAAe,GAGvF,KAAK,wBAAwB,EAG7B,KAAK,YAAc,WACnB,KAAK,kBAAkB,kBAAkBR,CAAa,EACtD,KAAK,WAAW,CAACA,CAAa,EAAG,QAAqB,GAGtDQ,GAAe,GACf,KAAK,QAAQ,OAAOA,EAAa,CAAC,EAGlCD,GAAkB,GAClB,KAAK,WAAW,OAAOA,EAAgB,CAAC,EAG5C,OAAO,KAAK,QAAQP,CAAa,CACrC,CAEA,SAAU,CACN,KAAK,YAAY,EAEjB,QAAWS,KAAY,KAAK,aACxBA,EAAS,QAAQ,EAGrB,QAAWA,KAAY,KAAK,aACxBA,EAAS,QAAQ,EAGrB,KAAK,wBAAwB,EAC7BC,EAAO,cAAc,QAAQ,EAE7B,KAAK,kBAAkB,MAAM,EAC7B,KAAK,iBAAmB,KAExB,KAAK,kBAAkB,MAAM,EAC7B,KAAK,iBAAmB,KAExB,KAAK,WAAa,CAAC,EACnB,KAAK,QAAU,CAAC,CACpB,CAEA,aAAc,CACV,OAAO,KAAK,SAChB,CAEA,YAAYV,EAA8B,CACtC,OAAO,KAAK,WAAW,QAAQA,CAAa,GAAK,CACrD,CAEA,WAAY,CACR,OAAO,KAAK,WAAW,MAAM,CACjC,CAEA,QAAS,CACL,OAAO,KAAK,QAAQ,MAAM,CAC9B,CAEA,UAAW,CACP,OAAO,KAAK,YAAc,SAA2B,KAAK,kBAAkB,SAAS,EAAI,KAAK,kBAAkB,SAAS,CAC7H,CAEA,WAAY,CACR,OAAO,KAAK,OAChB,CAEA,cAAcA,EAA8BW,EAAyB,CAC7DD,EAAO,OAASC,EAAQ,MAExBD,EAAO,MAAM,yBAAyB,WAAWC,CAAO,GAIxD,EAAEA,EAAQ,eAAe,cAAgBA,EAAQ,IAAI,aAAe,IACpE,KAAK,kBAAkB,kBAAkBX,EAAeW,CAAO,CAEvE,CAEA,eAAeC,EAAyB,CACpC,KAAK,gBAAgB,QAAQA,CAAI,CACrC,CAEA,MAAM,2BAA4B,CAC1B,KAAK,YAAc,UAA4B,KAAK,kBACpD,MAAM,KAAK,iBAAiB,0BAA0B,CAE9D,CAEQ,WAAWV,EAAiCW,EAAuB,CACvE,IAAMC,EAAwBZ,EAAe,OAAQF,GAC7C,KAAK,QAAQA,CAAa,IAAMa,GAChC,KAAK,QAAQb,CAAa,EAAIa,EACvB,IAEJ,EACV,EAEGC,EAAsB,QACtB,KAAK,cAAc,gBAA8BA,EAAuBD,CAAK,CAErF,CAEQ,eAAeA,EAAuB,CACtC,KAAK,cAAgBA,IAIzB,KAAK,YAAcA,EACnB,KAAK,cAAc,sBAAoCA,CAAK,EAChE,CAEQ,yBAAyBE,EAA2B,CACxD,GAAIA,EAAQ,eAAiBC,EAAsB,iBAC/C,OAAO,KAAK,mBAAmBD,CAA2C,CAElF,CAEQ,mBAAmBA,EAA2C,CAClE,GAAIA,EAAQ,WAAa,KAAK,UAqB9B,IAjBAhB,EAAM,IAAI,oBAAoB,KAAK,SAAS,OAAOgB,EAAQ,QAAQ,EAAE,EACrEE,EAAO,IAAIC,EAAQ,0BAA2BH,EAAQ,QAAQ,EAE9D,KAAK,UAAYA,EAAQ,SAErB,KAAK,YAAc,WACf,KAAK,iBACL,KAAK,iBAAiB,aAAa,GAEnC,KAAK,iBAAmB,KAAK,uBAAuB,EAChD,KAAK,QAAQ,OAAS,IACtB,KAAK,kBAAkB,eAAe,EACtC,KAAK,iBAAiB,KAAK,KAKnC,KAAK,YAAc,SAA0B,CAC7C,IAAMI,EAAUJ,EAAQ,SAAW,CAAC,EAC9BK,EAAeL,EAAQ,cAAgB,CAAC,EACxCM,EAAoBN,EAAQ,mBAAqB,CAAC,EAClDO,EAAoBH,EAAQ,QAAUC,EAAa,OAASG,EAAM,qBAAqBJ,EAAQ,CAAC,EAAGC,EAAa,CAAC,EAAGC,EAAkB,CAAC,CAAC,EAAI,KAMlJ,GAJI,KAAK,kBACL,KAAK,iBAAiB,eAAe,EAGrC,CAAC,KAAK,YAAc,KAAK,WAAW,SAAW,EAAG,CAClDtB,EAAM,MAAM,6EAA6E,EACzF,MACJ,CAEI,KAAK,WAAW,OAAS,GACzBA,EAAM,KAAK,gFAAgF,EAG/F,IAAMC,EAAgB,KAAK,WAAW,CAAC,EAEvC,GAAI,KAAK,iBACL,KAAK,iBAAiB,aAAa,MAChC,CACH,IAAMC,EAAWqB,IAAsBtB,EACvC,KAAK,iBAAmB,KAAK,uBAAuBA,EAAeC,CAAQ,CAC/E,CAEI,KAAK,QAAQ,QAAQD,CAAa,GAAK,GACvC,KAAK,iBAAiB,KAAK,CAEnC,CAEA,KAAK,cAAc,mBAAiC,KAAK,SAAS,EACtE,CAEQ,uBAAuBA,EAA8BC,EAAW,GAAwB,CAC5F,IAAMuB,EAAY,IAAIC,GAAgBzB,EAAeC,EAAU,KAAK,WAAY,KAAK,aAAc,KAAK,eAAe,EAGvH,OAAI,KAAK,aAAa,OAAS,GAC3BF,EAAM,KAAK,qDAAqDC,CAAa,gBAAgB,EAGjG,KAAK,aAAe,CAAC,EACrB,KAAK,aAAa,KACdwB,EAAU,iBAAiB,qBAAmC,KAAK,oBAAoB,KAAK,KAAMxB,CAAa,CAAC,EAChHwB,EAAU,iBAAiB,uBAAqC,KAAK,sBAAsB,KAAK,KAAMxB,CAAa,CAAC,EACpHwB,EAAU,iBAAiB,oBAAkC,KAAK,mBAAmB,KAAK,IAAI,CAAC,EAC/FA,EAAU,iBAAiB,gBAA8B,KAAK,0BAA0B,KAAK,IAAI,CAAC,EAClGA,EAAU,iBAAiB,iBAA+B,KAAK,0BAA0B,KAAK,IAAI,CAAC,EACnGA,EAAU,iBAAiB,yBAAuC,KAAK,wBAAwB,KAAK,KAAM,QAAwB,CAAC,CACvI,EAEI,KAAK,kBAAoB,KAAK,gBAC9BA,EAAU,oBAAoB,KAAK,iBAAkB,KAAK,cAAc,EAGrEA,CACX,CAEQ,wBAAyB,CAC7B,IAAMA,EAAY,IAAIE,GAAgB,KAAK,WAAY,KAAK,aAAc,KAAK,eAAe,EAI9F,OAAI,KAAK,aAAa,OAAS,GAC3B3B,EAAM,KAAK,qDAAqD,EAGpE,KAAK,aAAe,CAAC,EACrB,KAAK,aAAa,KACdyB,EAAU,iBAAiB,qBAAmC,KAAK,oBAAoB,KAAK,IAAI,CAAC,EACjGA,EAAU,iBAAiB,uBAAqC,KAAK,sBAAsB,KAAK,IAAI,CAAC,EACrGA,EAAU,iBAAiB,kBAAgC,KAAK,uBAAuB,KAAK,IAAI,CAAC,EACjGA,EAAU,iBAAiB,oBAAkC,KAAK,mBAAmB,KAAK,IAAI,CAAC,EAC/FA,EAAU,iBAAiB,gBAA8B,KAAK,0BAA0B,KAAK,IAAI,CAAC,EAClGA,EAAU,iBAAiB,gCAA8C,KAAK,+BAA+B,KAAK,IAAI,CAAC,EACvHA,EAAU,iBAAiB,4BAA0C,KAAK,2BAA2B,KAAK,IAAI,CAAC,EAC/GA,EAAU,iBAAiB,iCAA+C,KAAK,gCAAgC,KAAK,IAAI,CAAC,EACzHA,EAAU,iBAAiB,iBAA+B,KAAK,0BAA0B,KAAK,IAAI,CAAC,EACnGA,EAAU,iBAAiB,uBAAqC,KAAK,sBAAsB,KAAK,IAAI,CAAC,EACrGA,EAAU,iBAAiB,yBAAuC,KAAK,wBAAwB,KAAK,KAAM,QAAwB,CAAC,EACnIA,EAAU,iBAAiB,oBAAkC,KAAK,oBAAoB,KAAK,IAAI,CAAC,CACpG,EAEI,KAAK,kBAAoB,KAAK,gBAC9BA,EAAU,oBAAoB,KAAK,iBAAkB,KAAK,cAAc,EAGrEA,CACX,CAEQ,yBAA0B,CAC9B,KAAK,kBAAkB,MAAM,EAC7B,KAAK,iBAAmB,KAExB,QAAWf,KAAY,KAAK,aACxBA,EAAS,QAAQ,EAErB,KAAK,aAAe,CAAC,CACzB,CAEQ,yBAA0B,CAC9B,KAAK,kBAAkB,MAAM,EAC7B,KAAK,iBAAmB,KAExB,QAAWA,KAAY,KAAK,aACxBA,EAAS,QAAQ,EAErB,KAAK,aAAe,CAAC,CACzB,CAEQ,0BAA0BkB,EAAkB,CAC5CjB,EAAO,mBAAqBiB,IAC5BjB,EAAO,iBAAmBiB,EAC1B,KAAK,cAAc,uBAAuB,EAElD,CAEQ,0BAA0Bd,EAAuB,CACrD,IAAMb,EAAgB,KAAK,kBAAkB,cAS7C,GAPIa,IAAU,aACN,KAAK,YAAc,UAEnB,KAAK,wBAAwB,GAIjCA,IAAU,UAAyBA,IAAU,YAC7C,KAAK,wBAAwB,EAEzB,KAAK,YAAc,UAA0B,CAG7C,IAAML,EAAc,KAAK,QAAQ,QAAQR,CAAa,EAClDQ,GAAe,GACf,KAAK,QAAQ,OAAOA,EAAa,CAAC,EAGtC,IAAMD,EAAiB,KAAK,WAAW,QAAQP,CAAa,EACxDO,GAAkB,GAClB,KAAK,WAAW,OAAOA,EAAgB,CAAC,CAEhD,CAGA,KAAK,YAAc,UAA4BP,IAC/C,KAAK,WAAW,CAACA,CAAa,EAAGa,CAAK,EACtC,KAAK,eAAeA,CAAK,EAEjC,CAEQ,0BAA0BA,EAAuB,CACrD,IAAMX,EAAiB,KAAK,QAAQ,MAAM,EAEtCW,IAAU,aACN,KAAK,YAAc,UAEnB,KAAK,wBAAwB,GAIjCA,IAAU,UAAyBA,IAAU,YAC7C,KAAK,wBAAwB,EAEzB,KAAK,YAAc,WAEnB,KAAK,WAAa,CAAC,EACnB,KAAK,QAAU,CAAC,IAIpB,KAAK,YAAc,WACnB,KAAK,WAAWX,EAAgBW,CAAK,EACrC,KAAK,eAAeA,CAAK,EAEjC,CAEQ,+BAA+BX,EAAiC,CAChE,KAAK,YAAc,UACnB,KAAK,cAAc,gCAA8CA,CAAc,CAEvF,CAEQ,gCAAgCA,EAAiC,CACjE,KAAK,YAAc,UACnB,KAAK,cAAc,iCAA+CA,CAAc,CAExF,CAEQ,2BAA2BF,EAA8B,CACzD,KAAK,YAAc,UACnB,KAAK,cAAc,4BAA0CA,CAAa,CAElF,CAEQ,0BAA0B4B,EAAyC,CACvE,KAAK,cAAc,iBAA+BA,CAAQ,CAC9D,CAEQ,sBAAsB5B,EAA8B6B,EAA4B,CACpF,KAAK,cAAc,uBAAqC7B,EAAe6B,CAAM,CACjF,CAEQ,wBAAwBrC,EAA6B,CACzD,KAAK,cAAc,yBAAuCA,CAAQ,CACtE,CAEQ,uBAAuBsC,EAAkB,CACzC,KAAK,YAAc,UACnB,KAAK,cAAc,kBAAgCA,CAAO,CAElE,CAEQ,mBAAmBC,EAAmB,CAC1C,KAAK,cAAc,oBAAkCA,CAAK,CAC9D,CAEQ,oBAAoB/B,EAA8B6B,EAAqBG,EAAyB,CACpG,KAAK,cAAc,qBAAmChC,EAAe6B,EAAQG,CAAK,CACtF,CAEQ,sBAAsBhC,EAA8B6B,EAAqBG,EAAyB,CACtG,KAAK,cAAc,uBAAqChC,EAAe6B,EAAQG,CAAK,CACxF,CAEQ,oBAAoBC,EAAuB,CAC/C,KAAK,cAAc,oBAAkCA,CAAG,CAC5D,CAEQ,kBAAmB,CACvB,IAAMJ,EAAS,KAAK,aAAa,UAAU,EACvCA,GAGA,KAAK,gBAAgB,UAAUA,CAAM,CAE7C,CAEQ,iBAAiB7B,EAA8B6B,EAA4B,CAC/E,KAAK,cAAc,iBAA+B7B,EAAe6B,CAAM,CAC3E,CAGQ,iBAAiBF,EAAkB,CACnCA,EACA,KAAK,gBAAgB,OAAO,EAE5B,KAAK,gBAAgB,MAAM,EAE/B,KAAK,aAAa,gBAAgBA,CAAO,CAC7C,CAEQ,yBAA0B,CAC9B,GAAI,CAACjB,EAAO,MACR,OAGJ,KAAK,iBAAmB,IAAIA,EAAO,MAAM,gBACrC,CAACwB,EAAyBL,IAAwB,KAAK,iBAAiBK,EAAUL,CAAM,EACvFK,GAA4B,KAAK,iBAAiBA,EAAU,IAAI,EAChEC,GAAwB,CACrB,KAAK,cAAc,gBAA8BA,CAAK,CAC1D,EACAzB,EAAO,aAAa,gBACxB,EAEA,IAAM0B,EAAc,KAAK,aAAa,UAAU,EAChD,KAAK,eAAiB,IAAI1B,EAAO,MAAM,cAAc0B,EAAa,KAAK,WAAW,UAAU,EAAG1B,EAAO,aAAa,gBAAiB,CAChI,UAAW,KAAK,aAAa,mBAC7B,MAAOA,EAAO,aAAa,iBAAiB,KAChD,CAAC,EACD,KAAK,eAAe,YAAe2B,GAAsB,KAAK,kBAAkB,QAAQA,CAAI,CAChG,CAEQ,yBAA0B,CAC9B,KAAK,gBAAgB,QAAQ,EAC7B,KAAK,eAAiB,KACtB,KAAK,kBAAkB,QAAQ,EAC/B,KAAK,iBAAmB,IAC5B,CAEA,uBAAuBH,EAAkBI,EAAoC,CACzE,OAAI,KAAK,YAAc,UACnBrB,EAAO,IAAIC,EAAQ,uBAAwB,eAAe,EAC1DnB,EAAM,MAAM,uDAAuD,KAAK,SAAS,EAAE,EAC5E,GAEN,KAAK,iBAKH,KAAK,iBAAiB,uBAAuBmC,EAAUI,CAAkB,GAJ5ErB,EAAO,IAAIC,EAAQ,uBAAwB,aAAa,EACxDnB,EAAM,MAAM,qEAAqE,EAC1E,EAGf,CACJ,EC1mBO,IAAMwC,GAAN,MAAMA,EAAU,CAAhB,cA+DHC,EAAA,KAAQ,qBAAkE,CACtE,GAAI,IAAIC,GACR,GAAI,IAAIA,EACZ,GAGAD,EAAA,KAAQ,WAA4D,CAAC,GAlErE,OAAO,QAAS,CACPD,GAAU,YACXA,GAAU,UAAY,IAAIA,GAElC,CAMA,OAAO,KAAKG,EAAmC,CAC3C,GAAI,CAACH,GAAU,UACX,OAGJ,IAAMI,EAAM,KAAK,IAAI,EAGfC,EAAOL,GAAU,UAAU,SAASG,CAAS,EACnD,GAAI,OAAOE,GAAS,SAAU,CAC1B,IAAMC,EAAQF,EAAMC,EAChBC,GAAS,GAAGN,GAAU,UAAU,mBAAmBG,CAAS,EAAE,IAAIG,CAAK,CAC/E,CAEAN,GAAU,UAAU,SAASG,CAAS,EAAIC,CAC9C,CAGA,OAAO,WAAWG,EAA8B,CACvCP,GAAU,WAIf,UAAsE,EAAE,QAASQ,GAAM,CACnF,GAAI,CAACR,GAAU,UAAW,mBAAmBQ,CAAC,EAAE,QAC5C,OAGJ,IAAMC,EAAWT,GAAU,UAAW,mBAAmBQ,CAAC,EAAE,SAAS,EAErEE,EAAO,eAAe,CAClB,cAAeH,IAAa,SAA2B,IAAM,IAE7D,KAAMI,EAAK,uBACX,UAAWF,EAAS,IACpB,UAAWA,EAAS,IACpB,UAAWA,EAAS,IACpB,aAAcA,EAAS,OACvB,UAAWA,EAAS,IACpB,aAAcA,EAAS,MAEvB,oBAAqBD,CACzB,CAAC,CACL,CAAC,CACL,CAEA,OAAO,SAAU,CACbR,GAAU,WAAW,SAAS,CAClC,CAUQ,UAAW,CACf,KAAK,mBAAqB,CACtB,GAAI,IAAIE,GACR,GAAI,IAAIA,EACZ,EACA,KAAK,SAAW,CAAC,CACrB,CACJ,EA7EID,EADSD,GACM,aADZ,IAAMY,GAANZ,GCAA,IAAMa,GAAN,MAAMA,EAAsB,CAA5B,cAgEHC,EAAA,KAAQ,mBAA6C,IAAI,KA7DzD,OAAO,QAAS,CACPD,GAAsB,YACvBA,GAAsB,UAAY,IAAIA,GAE9C,CAEA,OAAO,KAAKE,EAAiBC,EAAcC,EAAmC,CAC1E,GAAI,CAACJ,GAAsB,UACvB,OAGJ,IAAMK,EAAM,GAAGH,CAAO,IAAIE,CAAS,GAE/BE,EACCN,GAAsB,UAAU,iBAAiB,IAAIK,CAAG,EAIzDC,EAAUN,GAAsB,UAAU,iBAAiB,IAAIK,CAAG,GAHlEC,EAAU,IAAIC,GACdP,GAAsB,UAAU,iBAAiB,IAAIK,EAAKC,CAAO,GAKrEA,EAAQ,IAAIH,CAAI,CACpB,CAGA,OAAO,WAAWK,EAA8B,CAC5C,GAAKR,GAAsB,UAI3B,OAAW,CAACK,EAAKC,CAAO,IAAKN,GAAsB,UAAU,iBAAiB,QAAQ,EAAG,CACrF,GAAI,CAACM,EAAQ,QACT,SAGJ,GAAM,CAACJ,EAASE,CAAS,EAAIC,EAAI,MAAM,GAAG,EAEpCI,EAAWH,EAAQ,SAAS,EAElCI,EAAO,eAAe,CAClB,cAAeF,IAAa,SAA2B,IAAM,IAE7D,KAAMG,EAAK,0BACX,WAAYT,EAEZ,UAAWO,EAAS,IACpB,UAAWA,EAAS,IACpB,UAAWA,EAAS,IACpB,aAAcA,EAAS,OACvB,UAAWA,EAAS,IACpB,aAAcA,EAAS,MAEvB,oBAAqBL,CACzB,CAAC,CACL,CACJ,CAEA,OAAO,SAAU,CACbJ,GAAsB,WAAW,SAAS,CAC9C,CAIQ,UAAW,CACf,KAAK,iBAAiB,MAAM,CAChC,CACJ,EApEIC,EADSD,GACM,aADZ,IAAMY,GAANZ,GCNP,IAAKa,QACDA,EAAA,MAAQ,QACRA,EAAA,OAAS,SACTA,EAAA,KAAO,OACPA,EAAA,MAAQ,QAJPA,QAAA,IAOEC,GAAQD,GCFf,IAAME,GAAa,CACf,oBAAqB,IAAMC,EAAO,oBAClC,iBAAkB,IAAMA,EAAO,iBAAmB,EAClD,YAAa,IAAM,GACnB,iBAAkB,IAAM,GACxB,oBAAqB,IAAMA,EAAO,oBAClC,0BAA2B,IAAM,GACjC,WAAY,IAAMA,EAAO,WACzB,wBAAyB,IAAMA,EAAO,wBACtC,SAAU,IAAMA,EAAO,SACvB,MAAO,IAAM,CAAC,CAACA,EAAO,MACtB,mBAAoB,IAAMA,EAAO,mBACjC,aAAc,IAAMA,EAAO,aAC3B,6BAA8B,IAAM,GACpC,qBAAsB,IAAM,CAACA,EAAO,aAAa,iBAAiB,uBAClE,oBAAqB,IAAM,GAC3B,eAAgB,IAAMA,EAAO,eAC7B,SAAU,IAAM,GAChB,aAAc,IAAMA,EAAO,wBAC/B,EAKaC,GAAN,KAA4B,CAC/B,OAAc,UAAmB,CAC7B,IAAMC,EAAa,OAAO,OAAOH,EAAU,EAEvCI,EAAY,EAChB,QAASC,EAAI,EAAGA,EAAIF,EAAW,OAAQE,IAC/BF,EAAWE,CAAC,EAAE,IACdD,GAAa,GAAKC,GAG1B,OAAOD,EAAU,SAAS,EAAE,EAAE,YAAY,CAC9C,CAEA,OAAc,kBAAkBE,EAAwC,CACpE,IAAMC,EAAQ,SAASD,GAAQ,IAAK,EAAE,EAEtC,OAAO,OAAO,KAAKN,EAAU,EAAE,OAAgC,CAACQ,EAAKC,EAAOC,KACxEF,EAAIC,CAAoC,EAAI,GAAQF,EAAS,GAAKG,GAC3DF,GACR,CAAC,CAA4B,CACpC,CACJ,EClDA,IAAAG,GAAwB,sBCAxB,IAAMC,GAAY,IACZC,GAAa,OAEnB,IAAMC,GAAa,qBAEbC,GAAN,KAAmC,CAM/B,OAAOC,EAAkC,CACrC,IAAMC,EAAI,OAAOD,GAAQ,SAAW,OAAOA,CAAG,EAAIA,EAClD,GAAIC,GAAKC,GAEL,OAAO,IAAI,WAAW,CAAC,OAAOD,CAAC,CAAC,CAAC,EAC9B,GAAIA,GAAKE,GAEZ,OAAO,IAAI,WAAW,CAAC,GAAO,OAAOF,GAAK,EAAE,EAAG,OAAOA,EAAI,KAAK,CAAC,CAAC,EAC9D,GAAIA,GAAK,OAAO,UAAU,EAE7B,OAAO,IAAI,WAAW,CAAC,IAAO,OAAOA,GAAK,GAAG,EAAG,OAAQA,GAAK,IAAO,KAAK,EAAG,OAAQA,GAAK,GAAM,KAAK,EAAG,OAAOA,EAAI,KAAK,CAAC,CAAC,EACtH,GAAIA,GAAKH,GAEZ,OAAO,IAAI,WAAW,CAClB,IAAO,OAAOG,GAAK,GAAG,EACtB,OAAQA,GAAK,IAAO,KAAK,EACzB,OAAQA,GAAK,IAAO,KAAK,EACzB,OAAQA,GAAK,IAAO,KAAK,EACzB,OAAQA,GAAK,IAAO,KAAK,EACzB,OAAQA,GAAK,IAAO,KAAK,EACzB,OAAQA,GAAK,GAAM,KAAK,EACxB,OAAOA,EAAI,KAAK,CACpB,CAAC,EAED,MAAM,IAAI,WAAW,4CAA4C,CAEzE,CACJ,EAEMG,GAAN,KAAmC,CAM/B,OAAOC,EAAiC,CACpC,IAAMC,EAAU,KAAK,4BAA4BD,CAAI,EACrD,GAAIC,EAAU,EACV,MAAM,IAAI,MAAM,uBAAuB,EAE3C,GAAID,EAAK,OAASC,EAEd,OAAO,KAGX,IAAIL,EAAI,OAAO,CAAC,EAChB,OAAQK,EAAS,CACb,IAAK,GACDL,EAAI,OAAOI,EAAK,CAAC,EAAI,EAAI,EACzB,MACJ,IAAK,GACDJ,EAAK,OAAOI,EAAK,CAAC,EAAI,EAAI,GAAK,GAAM,OAAOA,EAAK,CAAC,CAAC,EACnD,MACJ,IAAK,GACDJ,EAAK,OAAOI,EAAK,CAAC,EAAI,EAAI,GAAK,IAAQ,OAAOA,EAAK,CAAC,CAAC,GAAK,IAAQ,OAAOA,EAAK,CAAC,CAAC,GAAK,GAAM,OAAOA,EAAK,CAAC,CAAC,EACzG,MACJ,IAAK,GACDJ,EACK,OAAOI,EAAK,CAAC,EAAI,EAAI,GAAK,IAC1B,OAAOA,EAAK,CAAC,CAAC,GAAK,IACnB,OAAOA,EAAK,CAAC,CAAC,GAAK,IACnB,OAAOA,EAAK,CAAC,CAAC,GAAK,IACnB,OAAOA,EAAK,CAAC,CAAC,GAAK,IACnB,OAAOA,EAAK,CAAC,CAAC,GAAK,IACnB,OAAOA,EAAK,CAAC,CAAC,GAAK,GACpB,OAAOA,EAAK,CAAC,CAAC,EAClB,KACR,CACA,OAAOJ,CACX,CAEA,4BAA4BI,EAA0B,CAClD,IAAME,EAAeF,EAAK,CAAC,EAAI,IAC/B,OAAIE,IAAiB,EACV,EACAA,IAAiB,GACjB,EACAA,IAAiB,IACjB,EACAA,IAAiB,IACjB,EAEJ,EACX,CACJ,EDzFA,IAAMC,GAAN,KAAgC,CAK5B,YAAYC,EAAyD,CAJrEC,EAAA,KAAiB,WACjBA,EAAA,KAAiB,eACjBA,EAAA,KAAiB,iBAGb,KAAK,QAAU,IAAI,YACnB,KAAK,cAAgB,IAAIC,GACzB,KAAK,YAAcF,GAAe,IACtC,CASA,OAAOG,EAA0B,CAC7B,IAAIC,EAAc,KAAK,QAAQ,OAAOD,CAAI,EAC1CC,EAAc,KAAK,SAASA,CAAW,EACvC,IAAMC,EAAe,KAAK,cAAc,OAAOD,EAAY,MAAM,EAE3DE,EAAS,IAAI,WAAWD,EAAa,OAASD,EAAY,MAAM,EACtE,OAAAE,EAAO,IAAID,CAAY,EACvBC,EAAO,IAAIF,EAAaC,EAAa,MAAM,EACpCC,CACX,CAEQ,SAASH,EAA8B,CAC3C,GAAI,CAAC,KAAK,YACN,OAAOA,EAGX,OAAQ,KAAK,YAAa,CACtB,IAAK,OACD,OAAc,YAASA,CAAI,EAC/B,IAAK,UACD,OAAc,YAASA,CAAI,EAC/B,IAAK,cACD,OAAc,eAAYA,CAAI,EAClC,QACI,OAAOA,CACf,CACJ,CACJ,EAMMI,GAAN,KAAgC,CAS5B,YAAYP,EAAyD,CARrEC,EAAA,KAAiB,WACjBA,EAAA,KAAiB,eACjBA,EAAA,KAAiB,iBACjBA,EAAA,KAAQ,UACRA,EAAA,KAAQ,kBACRA,EAAA,KAAQ,UACRA,EAAA,KAAQ,sBAGJ,KAAK,QAAU,IAAI,YACnB,KAAK,cAAgB,IAAIO,GACzB,KAAK,YAAcR,GAAe,KAClC,KAAK,OAAS,IAAI,WAAW,CAAC,EAC9B,KAAK,eAAiB,KACtB,KAAK,OAAS,CAClB,CAQA,OAAOG,EAA4B,CAC/B,IAAMM,EAA2B,CAAC,EAGlC,IAFA,KAAK,OAAS,IAAI,WAAW,CAAC,GAAG,KAAK,OAAQ,GAAGN,CAAI,CAAC,EAE/C,KAAK,OAAO,OAAS,GAAG,CAC3B,GAAI,KAAK,iBAAmB,KAAM,CAE9B,GADA,KAAK,eAAiB,KAAK,WAAW,KAAK,MAAM,EAC7C,KAAK,iBAAmB,KAExB,OAAOM,EAEX,KAAK,OAAS,KAAK,kBACvB,CAEA,GAAI,KAAK,OAAO,OAAS,KAAK,OAAS,KAAK,eAExC,OAAOA,EAGX,IAAIC,EAAc,KAAK,OAAO,SAAS,KAAK,OAAQ,KAAK,OAAS,KAAK,cAAc,EACrFA,EAAc,KAAK,WAAWA,CAAW,EACzCD,EAAe,KAAK,KAAK,QAAQ,OAAOC,CAAW,CAAC,EAEpD,KAAK,OAAS,KAAK,OAAO,SAAS,KAAK,OAAS,KAAK,cAAc,EACpE,KAAK,eAAiB,KACtB,KAAK,OAAS,CAClB,CACA,OAAOD,CACX,CAQQ,WAAWN,EAAiC,CAChD,GAAIA,EAAK,SAAW,EAChB,MAAO,GAGX,GADA,KAAK,mBAAqB,KAAK,cAAc,4BAA4BA,CAAI,EACzE,KAAK,mBAAqB,EAC1B,MAAM,IAAI,MAAM,uBAAuB,EAE3C,IAAMQ,EAAM,KAAK,cAAc,OAAOR,EAAK,SAAS,EAAG,KAAK,kBAAkB,CAAC,EAC/E,OAAOQ,IAAQ,KAAO,KAAO,OAAOA,CAAG,CAC3C,CAEQ,WAAWR,EAA8B,CAC7C,GAAI,CAAC,KAAK,YACN,OAAOA,EAGX,OAAQ,KAAK,YAAa,CACtB,IAAK,OACD,OAAc,cAAWA,CAAI,EACjC,IAAK,UACD,OAAc,cAAWA,CAAI,EACjC,IAAK,cACD,OAAc,eAAYA,CAAI,EAClC,QACI,OAAOA,CACf,CACJ,CACJ,EEvIA,IAAMS,GAAN,KAA2B,CAkBvB,YAAYC,EAAaC,EAA+B,CAAC,EAAG,CAjB5DC,EAAA,KAAQ,gBACRA,EAAA,KAAQ,SAAiD,MACzDA,EAAA,KAAQ,SAA6C,MACrDA,EAAA,KAAQ,SAA6C,MACrDA,EAAA,KAAiB,OACjBA,EAAA,KAAiB,WACjBA,EAAA,KAAiB,eAEjBA,EAAA,KAAQ,WACRA,EAAA,KAAQ,WAERA,EAAA,cAAkE,MAClEA,EAAA,iBAA4E,MAC5EA,EAAA,eAAmE,MACnEA,EAAA,eAAwE,MACxEA,EAAA,kBAAqB,UAAU,YAG3B,KAAK,IAAMF,EACX,KAAK,QAAUC,EACf,KAAK,WAAa,UAAU,WAC5B,KAAK,YAAc,KAAK,0BAA0BD,CAAG,EACrD,KAAK,QAAU,IAAIG,GAA0B,KAAK,WAAW,EAC7D,KAAK,QAAU,IAAIC,GAA0B,KAAK,WAAW,EAC7D,KAAK,QAAQ,CACjB,CAEQ,0BAA0BJ,EAAwD,CACtF,GAAI,CAEA,IAAMK,EADS,IAAI,IAAIL,CAAG,EACC,aAAa,IAAI,aAAa,EACzD,OAAQK,EAAa,CACjB,IAAK,OACL,IAAK,UACL,IAAK,cACD,OAAOA,EACX,QACI,OAAO,IACf,CACJ,OAAS,EAAG,CACR,OAAAC,EAAM,IAAI,sCAAuC,CAAC,EAC3C,IACX,CACJ,CAEA,MAAc,SAAU,CACpB,GAAI,CACA,KAAK,aAAe,IAAI,aAAa,KAAK,IAAK,CAAE,GAAG,KAAK,OAAQ,CAAC,EAClE,MAAM,KAAK,aAAa,MAExBA,EAAM,MAAM,4CAA8C,KAAK,GAAG,EAElE,KAAK,OAAS,MAAM,KAAK,aAAa,0BAA0B,EAChE,KAAK,OAAS,KAAK,OAAO,SAAS,UAAU,EAC7C,KAAK,OAAS,KAAK,OAAO,SAAS,UAAU,EAC7C,KAAK,WAAa,UAAU,KAC5B,KAAK,SAAS,IAAI,MAAM,MAAM,CAAC,EAC/B,MAAM,KAAK,SAAS,CACxB,OAASC,EAAO,CACZD,EAAM,MAAM,uFAAwFC,CAAK,EACzG,KAAK,WAAa,UAAU,OAC5B,KAAK,UAAU,IAAI,MAAM,OAAO,CAAC,EACjC,KAAK,UAAU,IAAI,WAAW,QAAS,CAAE,KAAM,KAAM,OAAQ,mBAAoB,CAAC,CAAC,CACvF,CACJ,CAEA,MAAe,YAAa,CACxB,GAAK,KAAK,OAEV,GAAI,CACA,OAAa,CACT,GAAM,CAAE,KAAAC,EAAM,MAAAC,CAAM,EAAI,MAAM,KAAK,OAAO,KAAK,EAC/C,GAAID,EAAM,MACNC,IAAO,MAAMA,EACrB,CACJ,QAAE,CACE,KAAK,OAAO,YAAY,CAC5B,CACJ,CAEA,MAAc,UAAW,CACrB,GAAK,KAAK,OAIV,GAAI,CAEA,cAAiBC,KAAQ,KAAK,WAAW,EACd,KAAK,QAAQ,OAAOA,CAAI,EAEhC,QAASC,GAA0B,CAC9C,KAAK,YAAY,IAAI,aAAa,UAAW,CAAE,KAAMA,CAAc,CAAC,CAAC,CACzE,CAAC,EAGL,KAAK,MAAM,IAAM,eAAe,CACpC,OAASJ,EAAO,CACZD,EAAM,MAAM,oCAAqCC,CAAK,EACtD,KAAK,WAAa,UAAU,OAC5B,KAAK,UAAU,IAAI,MAAM,OAAO,CAAC,CACrC,CACJ,CAEA,MAAM,KAAKG,EAAc,CACrB,GAAI,KAAK,aAAe,UAAU,KAAM,CACpCJ,EAAM,KAAK,iEAAiE,EAC5E,MACJ,CAEA,GAAI,CAAC,KAAK,OAAQ,CACdA,EAAM,KAAK,4DAA4D,EACvE,MACJ,CAEA,GAAI,CACA,MAAM,KAAK,OAAO,MAElB,IAAMM,EAAQ,KAAK,QAAQ,OAAOF,CAAI,EACtC,MAAM,KAAK,OAAO,MAAME,CAAK,CACjC,OAASL,EAAO,CACZD,EAAM,MAAM,qCAAsCC,CAAK,EACvD,KAAK,UAAU,IAAI,MAAM,OAAO,CAAC,EACjC,KAAK,MAAM,KAAM,qBAAqB,CAC1C,CACJ,CAEA,MAAMM,EAAO,IAAMC,EAAiB,CAChC,GAAI,OAAK,aAAe,UAAU,QAAU,KAAK,aAAe,UAAU,SAI1E,MAAK,WAAa,UAAU,QAE5B,KAAK,QAAQ,OAAO,EAEpB,GAAI,CACA,KAAK,aAAa,MAAM,CAC5B,OAASC,EAAK,CACVT,EAAM,KAAK,mEAAoES,CAAG,CACtF,CAEA,KAAK,WAAa,UAAU,OAC5B,KAAK,UAAU,IAAI,WAAW,QAAS,CAAE,KAAAF,EAAM,OAAAC,CAAO,CAAC,CAAC,EAExD,KAAK,aAAa,OAAO,KAAK,IAAM,CAChC,KAAK,OAAS,KACd,KAAK,OAAS,KACd,KAAK,OAAS,IAClB,CAAC,EACL,CAEA,OAAO,oBAA8B,CAEjC,MADoB,iBAAkB,QAAU,OAAO,cAAiB,WAMpEE,EAAY,YAAY,IAAM,UACvBC,EAAO,eAIdD,EAAY,YAAY,IAAM,SATvB,EAcf,CACJ,EC/HA,IAAME,GAA+C,OAE/CC,GAAe,GAEfC,GAAe,CAAC,sBAAuB,qBAAsB,eAAe,EAE7DC,GAArB,MAAqBC,UAAkBC,EAAc,CAArD,kCACIC,EAAA,KAAQ,SAA0C,MAClDA,EAAA,KAAU,WAAW,GACrBA,EAAA,KAAQ,YAAY,GACpBA,EAAA,KAAQ,yBAA6C,CAAC,GACtDA,EAAA,KAAQ,2BAA+C,CAAC,GACxDA,EAAA,KAAQ,gBAAoC,CAAC,GAC7CA,EAAA,KAAQ,mBAA0D,CAAC,GAEnEA,EAAA,KAAQ,kBACRA,EAAA,KAAQ,iBAAiB,GACzBA,EAAA,KAAQ,YACRA,EAAA,KAAQ,aAA4B,MAEpCA,EAAA,KAAU,sBAAuC,MACjDA,EAAA,KAAU,qBAAsC,MAEhDA,EAAA,KAAQ,YAAY,IACpBA,EAAA,KAAQ,iBAAiB,IACzBA,EAAA,KAAQ,UACJ,aACAC,EAAO,SACP,eACAA,EAAO,WACP,YACAA,EAAO,gBACP,WACAA,EAAO,OACP,iBACAC,GAAsB,SAAS,GAEnCF,EAAA,KAAU,SAAwB,MAElCA,EAAA,KAAU,iBAAgC,MAE1CA,EAAA,KAAQ,iBAAiB,GACzBA,EAAA,KAAQ,6BAA6B,GACrCA,EAAA,KAAQ,cAAc,GAEtBA,EAAA,KAAQ,wBAAsD,MAC9DA,EAAA,KAAQ,kCAAyD,MACjEA,EAAA,KAAQ,6BAAoD,MAC5DA,EAAA,KAAQ,oCAAoC,IAC5CA,EAAA,KAAQ,sCAAsC,IAAIG,IAElD,WAAmB,iBAA0B,CACzC,OAAOF,EAAO,uBAClB,CAEA,WAAmB,qBAA8B,CAC7C,OAAOA,EAAO,0BAClB,CAEA,WAAmB,qBAA8B,CAC7C,OAAOA,EAAO,0BAClB,CAEA,WAAmB,uBAAgC,CAC/C,OAAOA,EAAO,mBAClB,CAEA,WAAmB,qBAA8B,CAC7C,OAAOA,EAAO,iBAClB,CAEA,WAAmB,oBAA6B,CAC5C,OAAOA,EAAO,gBAClB,CAEA,IAAa,OAAQ,CACjB,OAAO,KAAK,SAAW,IAC3B,CAES,YAAYG,EAAkB,CACnC,KAAK,SAAWA,CACpB,CAES,wBAAwBA,EAAyB,CACtD,KAAK,WAAaA,CACtB,CAES,kBAAkBC,EAAwB,CAC/C,KAAK,eAAiBA,CAC1B,CAES,yBAAyBC,EAA8C,CAC5E,KAAK,sBAAwBA,EAC7B,KAAK,oCAAoC,yBAAyBA,CAAqB,CAC3F,CAES,mCAAmCC,EAAmC,CAC3E,KAAK,gCAAkCA,EACvC,KAAK,gCAAgC,UAAaC,GAAwB,CACtE,IAAMC,EAAe,KAAK,uBAAuB,cAAcD,EAAM,IAAI,EACrEC,GACA,KAAK,eAAeA,CAAY,CAExC,CACJ,CAES,8BAA8BF,EAA6B,CAChE,KAAK,2BAA6BA,EAClC,KAAK,2BAA2B,UAAaC,GAAwB,CACjE,KAAK,oCACA,2BAA2BA,EAAM,IAAI,EACrC,KAAME,GAAa,CACZA,GACA,KAAK,eAAeA,CAAQ,CAEpC,CAAC,EACA,MAAOC,GAAW,CACfC,EAAM,KAAK,iEAAkED,CAAM,CACvF,CAAC,CACT,EACA,KAAK,qBAAqB,KAAK,wBAAwB,CAC3D,CAES,sBAAsBE,EAAiB,CAC5C,KAAK,kCAAoCA,CAC7C,CAKS,SAAU,CAGf,KAAK,yBAA2B,CAAC,EACjC,KAAK,cAAgB,CAAC,CAC1B,CAKA,MAAe,QAAQC,EAA+E,CAElG,YAAK,SAAW,eAAeb,EAAO,UAAU,GACzC,IAAI,QAAQ,CAACc,EAAmBC,IAAqB,CACxD,GAAI,KAAK,QAAU,KAAK,OAAO,WAAa,UAAU,QAAS,CAC3DC,EAAO,IAAIC,EAAQ,cAAe,gBAAgB,EAClDF,EAAO,MAAM,uBAAuB,CAAC,EACrC,MACJ,CAEA,KAAK,oBAAuBG,GAAyC,CACjEJ,EAAQI,CAAO,EACf,KAAK,oBAAsB,KAC3B,KAAK,mBAAqB,IAC9B,EACA,KAAK,mBAAsBC,GAAiB,CACxCJ,EAAOI,CAAK,EACZ,KAAK,oBAAsB,KAC3B,KAAK,mBAAqB,IAC9B,EAEA,KAAK,SAASN,EAAgB,KAAK,wBAAwB,CAAC,CAChE,CAAC,CACL,CAKA,MAAgB,MAA0CO,EAA+BC,EAAc,CAAC,EAAGC,EAAe,GAAMC,EAAa,EAAe,CACxJ,GAAIF,EAAO,cAAe,CACtB,IAAMG,EAAgBC,EAAM,uBAAuBJ,EAAO,aAAa,EACjEK,EAASD,EAAM,YAAYD,EAAc,eAAe,EAC9DH,EAAS,OAAO,OAAO,CAAC,EAAGA,EAAQ,CAC/B,cAAeK,EAAO,GACtB,gBAAiBA,EAAO,IAC5B,CAAC,EACGF,EAAc,YACdH,EAAO,UAAYG,EAAc,UAEzC,CAEA,OAAO,KAAK,SAAYJ,EAASC,EAAQC,EAAcC,CAAU,CACrE,CAKA,MAAgB,SAA6CH,EAA+BC,EAAc,CAAC,EAAGC,EAAe,GAAMC,EAAa,EAAe,CAC3J,IAAMI,EAAWC,GAAuC,CACpD,GAAI,KAAK,sBAAsBR,CAAO,EAClC,KAAK,yBAAyB,KAAKQ,CAAgB,EAC/C,KAAK,4BAA4B,aAAenC,IAChD,KAAK,qBAAqB,KAAK,wBAAwB,MAExD,CACH,GAAI,CAAC,KAAK,OAAQ,CACduB,EAAO,IAAIC,EAAQ,cAAe,YAAY,EAC9CN,EAAM,KAAK,kCAAkC,EAC7CiB,EAAiB,OAAO,IAAI,MAAM,sBAAsBR,CAAO,GAAG,EAAG,EAAI,EACzE,MACJ,CAEI,KAAK,OAAO,WAAa,UAAU,OACnCJ,EAAO,IAAIC,EAAQ,cAAe,eAAe,EACjDN,EAAM,KAAK,2CAA2C,KAAK,OAAO,UAAU,EAAE,GAGlF,KAAK,uBAAuB,KAAKiB,CAAgB,EAE7C,KAAK,QAAU,KAAK,OAAO,aAAe,UAAU,MACpD,KAAK,qBAAqB,KAAK,sBAAsB,CAE7D,CACJ,EAEA,OAAO,IAAI,QAAW,CAACd,EAASC,IAAW,CACvC,IAAMc,EAAU,CAACV,EAAcW,EAAQ,KAAU,CACzC,CAACP,GAAcO,EACff,EAAOI,CAAK,GAEZR,EAAM,MAAM,4CAA6CS,EAASQ,EAAiB,QAAQ,EAC3FL,IACAI,EAAQC,CAAoC,EAEpD,EAEMG,EAAW,KAAK,WAChBC,EAAe,GAAGZ,CAAO,IAAIW,CAAQ,GAE3CE,GAAW,QAAQD,CAAY,EAE/B,IAAMJ,EAAwC,CAC1C,SAAAG,EACA,KAAMX,EACN,aAAcY,EACd,OAAAX,EACA,cAAe,EACf,aAAAC,EACA,QAAAR,EACA,OAAQe,CACZ,EAEAF,EAAQC,CAAoC,CAChD,CAAC,CACL,CAEQ,sBAAsBR,EAAiD,CAC3E,OAAK,KAAK,kCAINA,IAAYc,EAAqB,uBACjCd,IAAYc,EAAqB,kBACjCd,IAAYc,EAAqB,qBACjCd,IAAYc,EAAqB,aACjCd,IAAYc,EAAqB,sBACjCd,IAAYc,EAAqB,8BACjCd,IAAYc,EAAqB,qBACjCd,IAAYc,EAAqB,iBAV1B,EAYf,CAES,8BAAuC,CAC5C,OAAO,KAAK,QAChB,CAEA,MAAe,OAAOxB,EAAkD,CACpE,OAAO,KAAK,MAAMwB,EAAqB,OAAQ,CAAE,OAAAxB,CAAO,CAAC,EAAE,MAAM,IAAM,CAEvE,CAAC,CACL,CAEA,MAAe,cAAcc,EAA8BW,EAAuD,CAC9G,OAAO,KAAK,MACRD,EAAqB,cACrB,CACI,cAAAV,EACA,KAAM,CAAE,UAAAW,CAAU,CACtB,EACA,EACJ,CACJ,CAEA,MAAe,gBAAgBC,EAAyBC,EAA2D,CAE/G,OAAO,KAAK,MAAMH,EAAqB,kBAAmB,CACtD,SAAUE,EACV,SAAUC,CACd,CAAC,CACL,CAEA,MAAe,QAAQb,EAA8Bc,EAAgCC,EAA+D,CAChJ,IAAMC,EAAO,OAAO,OAAO,CAAE,IAAAF,CAAI,EAAGC,CAAY,EAChD,OAAO,KAAK,MAAML,EAAqB,cAAe,CAClD,cAAAV,EACA,KAAAgB,CACJ,CAAC,CACL,CAEA,MAAe,WAAWC,EAAyD,CAC/E,OAAO,KAAK,MAAMP,EAAqB,YAAa,CAAE,cAAAO,CAAc,CAAC,CACzE,CAEA,MAAe,oBAAoBA,EAAyD,CACxF,OAAO,KAAK,MAAMP,EAAqB,sBAAuB,CAAE,cAAAO,CAAc,EAAG,GAAM/C,EAAY,CACvG,CAEA,MAAe,uBAAuBgD,EAA6BC,EAA8D,CAC7H,IAAMH,EAA4B,CAC9B,iBAAkB,CAAE,MAAAE,CAAM,CAC9B,EAEA,OAAIC,IACAH,EAAK,cAAgBG,GAGlB,KAAK,SAAST,EAAqB,yBAA0BM,CAAI,CAC5E,CAEA,MAAe,cAA0C,CACrD,OAAO,KAAK,MAAMN,EAAqB,cAAc,CACzD,CAEA,MAAe,eAAeU,EAAgCvB,EAA0D,CACpH,OAAO,KAAK,MAAMa,EAAqB,gBAAiB,CAAE,YAAAU,EAAa,GAAGvB,CAAO,CAAC,CACtF,CAEA,MAAe,qBAAqBwB,EAAmCxB,EAA0D,CAC7H,OAAO,KAAK,MAAMa,EAAqB,gBAAiB,CAAE,eAAAW,EAAgB,GAAGxB,CAAO,CAAC,CACzF,CAEA,MAAe,kBAAkBG,EAAgCsB,EAAM,GAAkC,CACrG,OAAO,KAAK,MAAMZ,EAAqB,mBAAoB,CAAE,cAAAV,EAAe,IAAAsB,CAAI,CAAC,CACrF,CAEA,MAAe,iBAAiBC,EAA2CC,EAAuF,CAC9J,IAAMR,EAAY,CAAE,aAAAQ,CAAa,EACjC,OAAID,IACAP,EAAK,YAAcO,EAAY,KAE5B,KAAK,MAAMb,EAAqB,kBAAmBM,CAAI,CAClE,CAEA,MAAe,eAAeO,EAAwCE,EAA4C,CAC9G,IAAM5B,EAAc,CAAE,YAAa0B,EAAY,GAAI,EACnD,OAAIE,IACA5B,EAAO,MAAQ4B,GAEZ,KAAK,MAAMf,EAAqB,gBAAiBb,CAAM,CAClE,CAKA,MAAe,iBAAiB6B,EAAyE,CACrG,OAAO,KAAK,MAAMhB,EAAqB,yBAA0B,CAAE,gBAAiBgB,CAAW,CAAC,EAAE,MAAM,IAAM,CAE9G,CAAC,CACL,CAEA,MAAe,oBAAoBC,EAAiI,CAChK,OAAO,KAAK,MAAMjB,EAAqB,sBAAuBiB,CAAO,CACzE,CAEA,MAAe,SAASX,EAAkD,CACtE,OAAO,KAAK,MAAMN,EAAqB,UAAWM,CAAI,CAC1D,CAEA,MAAe,YAAYA,EAAmD,CAC1E,OAAO,KAAK,MAAMN,EAAqB,aAAcM,CAAI,CAC7D,CAEA,MAAe,YAAYA,EAAsC,CAC7D,OAAO,KAAK,MAAMN,EAAqB,aAAcM,CAAI,CAC7D,CAEA,gBAAgBY,EAA8C,CAC1D,OAAO,KAAK,MAAMlB,EAAqB,kBAAmB,CAAE,UAAAkB,CAAU,CAAC,CAC3E,CAEA,gBAA4C,CACxC,OAAO,KAAK,MAAMlB,EAAqB,gBAAgB,CAC3D,CAEA,MAAe,YAAYmB,EAAgCC,EAAqD,CAC5G,OAAO,KAAK,MAAMpB,EAAqB,aAAc,CAAE,MAAAmB,EAAO,eAAAC,CAAe,CAAC,CAClF,CAEA,MAAe,cAAcC,EAAmBC,EAAgD,CAC5F,OAAO,KAAK,MAAMtB,EAAqB,eAAgB,CAAE,QAAAqB,EAAS,WAAAC,CAAW,CAAC,CAClF,CAEA,MAAe,WAAWC,EAAyBjC,EAA0D,CACzG,OAAO,KAAK,SAASU,EAAqB,YAAa,CAAE,SAAAuB,EAAU,cAAAjC,CAAc,CAAC,CACtF,CAEA,MAAe,SAASkC,EAA+D,CACnF,OAAO,KAAK,SAASxB,EAAqB,UAAW,CAAE,iBAAAwB,CAAiB,CAAC,CAC7E,CAEA,MAAe,YAAYH,EAA8C,CACrE,OAAO,KAAK,MAAMrB,EAAqB,aAAc,CAAE,QAAAqB,CAAQ,CAAC,CACpE,CAEA,MAAe,YAAYf,EAAmD,CAC1E,OAAO,KAAK,MAAMN,EAAqB,aAAcM,CAAI,CAC7D,CAEA,MAAe,WAAWA,EAAwB,CAAE,OAAQ,IAAa,EAA8B,CACnG,OAAO,KAAK,MAAMN,EAAqB,YAAaM,CAAI,CAC5D,CAEA,MAAe,cAAcA,EAA2B,CAAE,OAAQ,IAAa,EAA8B,CACzG,OAAO,KAAK,MAAMN,EAAqB,eAAgBM,CAAI,CAC/D,CAEA,MAAe,cAAcmB,EAAwB,CAAE,qBAAsB,GAAO,OAAQ,IAAa,EAA8B,CACnI,IAAMnB,EAAY,CACd,QAAS,CACL,qBAAsBmB,EAAK,oBAC/B,EACA,OAAQA,EAAK,MACjB,EACA,OAAIA,EAAK,OACLnB,EAAK,KAAOmB,EAAK,MAEjBA,EAAK,OAAO,SACZnB,EAAK,MAAQmB,EAAK,MAAM,KAAK,GAAG,GAG7B,KAAK,MAAMzB,EAAqB,gBAAiBM,CAAI,CAChE,CAEA,MAAe,iBAA6C,CACxD,OAAO,KAAK,MAAMN,EAAqB,iBAAiB,CAC5D,CAEA,MAAe,eAAe0B,EAA6B9B,EAAQ,GAAkC,CACjG,OAAO,KAAK,MAAMI,EAAqB,gBAAiB,CACpD,SAAA0B,EACA,MAAA9B,CACJ,CAAC,CACL,CAEA,MAAe,gBAA4C,CACvD,OAAO,KAAK,MAAMI,EAAqB,eAAe,CAC1D,CAEA,MAAe,eAAe2B,EAAmD,CAC7E,OAAO,KAAK,MAAM3B,EAAqB,iBAAkB2B,CAAM,CACnE,CAEA,MAAe,kBAAkBA,EAAsD,CACnF,OAAO,KAAK,MAAM3B,EAAqB,oBAAqB2B,EAAQ,EAAK,CAC7E,CAEA,MAAe,kBAAkBA,EAAsD,CACnF,OAAO,KAAK,MAAM3B,EAAqB,oBAAqB2B,EAAQ,EAAK,CAC7E,CAEA,MAAe,YAAY3C,EAAiBM,EAAwC,KAAiC,CACjH,OAAO,KAAK,MAAMU,EAAqB,aAAc,CAAE,QAAAhB,EAAS,cAAAM,CAAc,CAAC,CACnF,CAEA,MAAe,YAAYsC,EAA0C,CACjE,OAAO,KAAK,MAAM5B,EAAqB,aAAc,CAAE,MAAA4B,CAAM,CAAC,CAClE,CAEA,MAAe,WAAWtB,EAAkBhB,EAAgE,CACxG,OAAO,KAAK,MAAMU,EAAqB,YAAa,CAAE,KAAAM,EAAM,cAAAhB,CAAc,CAAC,CAC/E,CAEA,MAAe,WAAWA,EAA8BuC,EAAmBC,EAA4C,CACnH,IAAMxB,EAAY,CAAE,cAAAhB,EAAe,MAAAuC,CAAM,EACzC,OAAIC,IACAxB,EAAK,OAAS,IAEX,KAAK,SAASN,EAAqB,YAAaM,CAAI,CAC/D,CAEA,MAAe,gBACXhB,EACAyC,EACAC,EACAC,EAAwB,KACC,CACzB,OAAO,KAAK,SAASjC,EAAqB,iBAAkB,CAAE,cAAAV,EAAe,WAAAyC,EAAY,eAAAC,EAAgB,OAAAC,CAAO,CAAC,CACrH,CAEA,MAAe,sBAAsBC,EAA8BL,EAA8C,CAC7G,OAAO,KAAK,SAAS7B,EAAqB,yBAA0B,CAAE,QAAAkC,EAAS,MAAAL,CAAM,CAAC,CAC1F,CAEA,MAAe,eAAevC,EAA8B6C,EAAgBF,EAAkD,CAC1H,IAAM3B,EAAY,CAAE,cAAAhB,EAAe,OAAA2C,CAAO,EAC1C,OAAIE,IACA7B,EAAK,MAAQ,IAEV,KAAK,SAASN,EAAqB,gBAAiBM,CAAI,CACnE,CAEA,MAAe,qBAAqB8B,EAA2D,CAC3F,OAAO,KAAK,MAAMpC,EAAqB,uBAAwB,CAAE,eAAAoC,CAAe,CAAC,CACrF,CAEA,MAAe,mBAAmBC,EAA6C,CAC3E,OAAO,KAAK,MAAMrC,EAAqB,qBAAsB,CAAE,QAAAqC,CAAQ,EAAG,EAAK,CACnF,CAEA,MAAe,0BAA0BA,EAA6C,CAClF,OAAO,KAAK,MAAMrC,EAAqB,6BAA8B,CAAE,QAAAqC,CAAQ,EAAG,EAAK,CAC3F,CAEA,MAAe,gBAAgBC,EAA6D,CACxF,OAAO,KAAK,MAAMtC,EAAqB,iBAAkBsC,EAAiB,EAAK,CACnF,CAEA,MAAe,cAAcC,EAA+E,CACxG,OAAO,KAAK,MAAMvC,EAAqB,eAAgB,CAAE,QAASuC,CAAQ,CAAC,CAC/E,CAEA,MAAe,eAAeC,EAAuD,KAAMZ,EAAgBa,EAAW,GAAkC,CACpJ,IAAMnC,EAAY,CAAC,EACnB,OAAIkC,IACAlC,EAAK,OAASkC,GAEdZ,IACAtB,EAAK,MAAQsB,GAEba,IACAnC,EAAK,SAAWmC,GAEb,KAAK,MAAMzC,EAAqB,iBAAkBM,CAAI,CACjE,CAEA,MAAe,mBAAmBhB,EAAiCoD,EAAS,GAAkC,CAC1G,IAAMpC,EAAY,CAAC,EACnB,OAAIhB,IACAgB,EAAK,cAAgBhB,GAErBoD,IACApC,EAAK,OAASoC,GAEX,KAAK,SAAS1C,EAAqB,oBAAqBM,CAAI,CACvE,CAEA,MAAe,iBAAiBqC,EAAY,GAAkC,CAC1E,IAAMrC,EAAY,CAAC,EACnB,OAAIqC,IACArC,EAAK,UAAYqC,GAEd,KAAK,MAAM3C,EAAqB,kBAAmBM,CAAI,CAClE,CAEA,MAAe,gBAAgBzB,EAAS,GAAkC,CACtE,IAAMyB,EAAY,CAAC,EACnB,OAAIzB,IACAyB,EAAK,OAASzB,GAEX,KAAK,MAAMmB,EAAqB,iBAAkBM,CAAI,CACjE,CAEA,MAAe,SAASsC,EAAwC,CAC5D,OAAO,KAAK,SAAS5C,EAAqB,SAAU,CAAE,IAAA4C,CAAI,CAAC,CAC/D,CAEA,MAAe,cAA0C,CACrD,OAAO,KAAK,MAAM5C,EAAqB,cAAc,CACzD,CAKS,OAAc,CACf,KAAK,QAAU,KAAK,OAAO,WAAa,UAAU,SAClD,KAAK,aAAa,EAGtB,KAAK,2BAA2B,EAChC,KAAK,YAAY,EACjB,aAAa,KAAK,cAAc,CACpC,CAQS,YAAY6C,EAAU,GAAM,CACjC,KAAK,eAAiBA,EACtB,KAAK,sBAAsB,CAC/B,CAEA,MAAe,wBAAwBC,EAA2F,CAC9H,OAAO,KAAK,MAAM9C,EAAqB,2BAA4B8C,CAA8B,CACrG,CAEA,MAAe,gBAAgBpC,EAAuF,CAClH,OAAO,KAAK,MAAMV,EAAqB,iBAAkB,CACrD,YAAAU,CACJ,CAAC,CACL,CAES,WAAY,CACjB,OAAO,KAAK,MAChB,CAEA,MAAe,SAASvB,EAAoD,CACxE,OAAO,KAAK,MAAMa,EAAqB,UAAWb,CAAM,CAC5D,CAEA,MAAM,QAAQA,EAAoD,CAC9D,OAAO,KAAK,MAAMa,EAAqB,SAAUb,CAAM,CAC3D,CAEA,MAAe,WAAW4D,EAA6C,CACnE,OAAO,KAAK,MACR/C,EAAqB,YACrB,CACI,QAAA+C,CACJ,EACA,EACJ,CACJ,CAEU,SAASpE,EAAyCqE,EAAgC,CACxF,GAAI,KAAK,QAAU,KAAK,OAAO,WAAa,UAAU,QAClD,OAGJ,KAAK,eAAiBrE,EAEtB,IAAIsE,EAAiB,GACjBtE,IACAsE,GAAkB,QAAQtE,CAAc,IAExCA,IAAmBuE,GAAwB,OAAS,KAAK,YAEzDD,GAAkB,cAAc,KAAK,SAAS,IAGlDA,EAAiBE,EAA8BF,CAAc,EAEzDD,GACAC,GAAkB,2BAGlBA,GAAkB,OAAO,UAAU,SAAS,GAE5CxE,EAAM,MAAM,gCAAkC,KAAK,WAAa,KAAK,QAAUwE,CAAc,EAE7F,KAAK,OAAS,IAAIG,GAAa,KAAK,WAAa,KAAK,QAAUH,CAAc,IAE9ExE,EAAM,MAAM,gCAAkC,KAAK,SAAW,KAAK,QAAUwE,CAAc,EAE3F,KAAK,OAAS,IAAI,UAAU,KAAK,SAAW,KAAK,QAAUA,CAAc,GAG7E,KAAK,mBAAmBtE,IAAmBuE,GAAwB,+BAA6E,EAEhJ,KAAK,OAAO,OAAS,KAAK,QAAQ,KAAK,IAAI,EAC3C,KAAK,OAAO,UAAY,KAAK,WAAW,KAAK,IAAI,EACjD,KAAK,OAAO,QAAU,KAAK,SAAS,KAAK,IAAI,EAC7C,KAAK,OAAO,QAAU,KAAK,SAAS,KAAK,IAAI,EAC7C,KAAK,aAAa,EAElB,SAASC,EAA8BE,EAAyB,CAC5D,GAAI,CAACvF,EAAO,wBACR,OAAOuF,EAEX,IAAMC,EAAUxF,EAAO,8BACvBuF,GAAW,YAAYC,CAAO,GAC9B,IAAMC,EAAYzF,EAAO,8BACzB,OAAIyF,IAAc,OACdF,GAAW,cAAcE,CAAS,IAE/BF,CACX,CACJ,CAEU,YAAYG,EAAqB,CACnC,KAAK,QAAU,KAAK,OAAO,WAAa,UAAU,UAClD,KAAK,OAAO,OAAS,KACrB,KAAK,OAAO,UAAY,KACxB,KAAK,OAAO,QAAU,KACtB,KAAK,OAAO,QAAU,KACtB,KAAK,OAAO,MAAMA,CAAI,EACtB,KAAK,OAAS,MAGlB,KAAK,2BAA2B,EAChC,KAAK,YAAY,EACjB,aAAa,KAAK,cAAc,CACpC,CAEQ,SAAgB,CACpB/E,EAAM,MAAM,2BAA2B,EACvCK,EAAO,IAAIC,EAAQ,cAAe,QAAQ,EAC1C,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAElB,KAAK,kBAAkB,KAAK,iBAAmBmE,GAAwB,+BAA6E,CACxJ,CAEQ,WAAW7E,EAA2B,CAG1C,GAFA,KAAK,aAAa,EAEdA,EAAM,OAAS,OAAQ,CACvBoF,GAAU,KAAK,KAAK,eAAe,CAAC,EACpC,KAAK,iCAAsD,EAE3DC,EAAS,mBAAmBrF,EAAM,IAAI,EAClC,KAAK,QAAU,KAAK,OAAO,aAAe,UAAU,MACpD,KAAK,OAAO,KAAK,MAAM,EAE3B,MACJ,CAEA,GAAI,CACA,IAAMsF,EAAM,KAAK,MAAMtF,EAAM,IAAI,EACjCqF,EAAS,mBAAmBC,CAAG,EAC/B,KAAK,eAAeA,CAAG,CAC3B,OAASC,EAAG,CACR9E,EAAO,IAAIC,EAAQ,cAAe,aAAa,EAC/CN,EAAM,MAAM,sCAAuCmF,EAAGvF,EAAM,IAAI,CACpE,CACJ,CAEU,eAAeW,EAA2B,CAChD,OAAQA,EAAQ,KAAM,CAClB,IAAK,eACGA,EAAQ,eAAiB,cACzBP,EAAM,MAAM,kCAAmCO,CAAO,EAEtD,KAAK,UAAY,GACjB,KAAK,eAAiB,EACtB,KAAK,SAAWA,EAAQ,SAEpBA,EAAQ,QAAU,KAAK,SAAWA,EAAQ,OAAO,KACjD,KAAK,SAAW,WAAWA,EAAQ,OAAO,EAAE,GAC5C,KAAK,OAASA,EAAQ,OAAO,IAGjC,KAAK,2BAA2B,EAE5B,KAAK,oBACL,KAAK,oBAAoBA,CAAsC,GAE/D,KAAK,2BAAgD,EAErD,KAAK,cAAc6E,GAAe,UAAW7E,CAAO,EAChDA,EAAQ,aAAa,UAErB,KAAK,cAAc6E,GAAe,aAAc,CAC5C,KAAM,eACN,aAAcC,EAAsB,iBACpC,SAAU9E,EAAQ,aAAa,QACnC,CAAC,GAIL,KAAK,WACL,KAAK,sBAAsB,EAG/BA,EAAQ,iBAAiB,QAAS2E,GAA0B,CAMpDA,EAAI,eAAiBG,EAAsB,eAAiBH,EAAI,OAAO,KAAO,KAAK,QAAUA,EAAI,OAAO,OAAS,iBAIrH,KAAK,eAAeA,CAAG,CAC3B,CAAC,EACD,KAAK,qBAAqB,KAAK,sBAAsB,GAC9C,CAAC,KAAK,WAAa,CAAC,KAAK,eAChC,KAAK,cAAc,KAAK3E,CAAO,EAE/B,KAAK,cAAc6E,GAAe,aAAc7E,CAAO,EAE3D,MAEJ,IAAK,WACD,KAAK,uBAAuB,GAAMA,CAAmC,EACrE,MAEJ,IAAK,QACD,KAAK,oBAAoBA,CAA4B,EACrD,MAEJ,QACIF,EAAO,IAAIC,EAAQ,cAAe,iBAAiB,EACnDN,EAAM,KAAK,gCAAiCO,CAAO,CAC3D,CAEA,KAAK,UAAYA,EAAQ,OAAS,KAAK,SAC3C,CAEQ,oBAAoBA,EAA4B,CACpDF,EAAO,IAAIC,EAAQ,cAAe,SAASC,EAAQ,KAAK,EAAE,EAE1D,IAAM+E,EAAe/E,EAAQ,MAAQvB,GAAa,SAASuB,EAAQ,KAAK,EAAI,GAQ5E,OANAP,EAAM,MAAM,8BAA8BO,EAAQ,QAAQ,IAAKA,CAAO,EAElEA,EAAQ,UAAY,KAAK,iBAAiBA,EAAQ,QAAQ,GAC1D,KAAK,uBAAuB,GAAOA,CAAmC,EAGlEA,EAAQ,MAAO,CACnB,IAAK,sBACD,IAAMC,EAAQ,IAAI+E,EAAaC,EAAW,oBAAqB,CAC3D,QAAS,uBAAuBjF,EAAQ,KAAK,GAC7C,OAAQ,EACZ,CAAC,EAEG,KAAK,mBACL,KAAK,mBAAmBC,CAAK,EAE7B,KAAK,cAAc4E,GAAe,aAAc,CAC5C,aAAcC,EAAsB,oBACpC,OAAQG,EAAW,mBACvB,CAAC,EAEL,MAEJ,IAAK,qBACG,KAAK,mBACL,KAAK,mBACD,IAAID,EAAahF,EAAQ,QAAUkF,GAAW,iBAAkB,CAC5D,QAAS,uBAAuBlF,EAAQ,KAAK,GAC7C,OAAQ,EACZ,CAAC,CACL,EAEA,KAAK,cAAc6E,GAAe,aAAc,CAC5C,aAAcC,EAAsB,oBACpC,OAAQ9E,EAAQ,MACpB,CAAC,EAEL,MAEJ,IAAK,wBAED,KAAK,YAAY,IAAI,MAAM,oBAAoBA,EAAQ,KAAK,EAAE,CAAC,EAC/D,MAEJ,IAAK,gBACL,QACI,GAAI,CAAC+E,EACD,MAGA,KAAK,UACL,KAAK,YAAY,IAAI,MAAM,oBAAoB/E,EAAQ,KAAK,EAAE,CAAC,EACvDA,EAAQ,WAChB,KAAK,qBACD,IAAIgF,EAAahF,EAAQ,QAAUkF,GAAW,iBAAkB,CAC5D,QAAS,uCAAuClF,EAAQ,KAAK,GAC7D,OAAQ,EACZ,CAAC,CACL,EACA,KAAK,aAAa,EAE9B,CACJ,CAEU,uBAA8B,CACpC,IAAMmF,EAAiB,CAAC,GAAG,KAAK,aAAa,EAE7C,IADA,KAAK,cAAgB,CAAC,EACfA,EAAe,OAAS,GAAG,CAC9B,IAAMnF,EAAUmF,EAAe,MAAM,EACrC,KAAK,eAAenF,CAAO,CAC/B,CACJ,CAEQ,YAAYC,EAAqB,CACrC,KAAK,cAAc4E,GAAe,OAAQ5E,CAAK,CACnD,CAEQ,SAASZ,EAAoB,CACjCS,EAAO,IAAIC,EAAQ,cAAe,OAAO,EACzCN,EAAM,MAAM,8BAA+BJ,CAAK,EAEhD,KAAK,qCAA4D,CAAE,aAAc,KAAK,UAAUA,CAAK,CAAE,CAAC,CAC5G,CAEU,SAASA,EAAyB,CACxCS,EAAO,IAAIC,EAAQ,cAAe,QAAQ,EAC1CN,EAAM,MAAM,gCAAiC,CACzC,KAAMJ,EAAM,KACZ,OAAQA,EAAM,MAClB,CAAC,EACD,KAAK,UAAY,GAEjB,KAAK,YAAY,EAEb,KAAK,QAAU,KAAK,iBAAmBV,EAAU,oBACjD,KAAK,WAAW,EACT,KAAK,QACZ,KAAK,aAAa,IAAIqG,EAAaC,EAAW,aAAa,CAAC,CAEpE,CAEU,aAAahF,EAAsB,KAAY,CAChD,KAAK,SAIV,KAAK,YAAY,EAEjB,OAAO,OAAO,KAAK,gBAAgB,EAAE,QAASC,GAAY,CACtD,OAAO,aAAaA,EAAQ,aAAa,EACrCD,GACAC,EAAQ,OAAO,IAAI,MAAM,8BAA8BA,EAAQ,IAAI,EAAE,EAAG,EAAI,CAEpF,CAAC,EACD,KAAK,uBAAyB,CAAC,EAC/B,KAAK,iBAAmB,CAAC,EAEzB,KAAK,UAAY,EAEbD,GACA,KAAK,YAAYA,CAAK,EAE9B,CAEU,YAAmB,CACzB,IAAMmF,EAAQ,KAAK,IAAIzG,EAAU,oBAAqBA,EAAU,gBAAkB,KAAK,IAAI,EAAG,KAAK,eAAiB,CAAC,CAAC,EACtHc,EAAM,IAAI,yCAAyC2F,CAAK,OAAO,KAAK,cAAc,GAAG,EACrFtF,EAAO,IAAIC,EAAQ,cAAe,WAAW,EAC7C,KAAK,eAAiB,OAAO,WAAW,KAAK,SAAS,KAAK,KAAMmE,GAAwB,MAAO,EAAK,EAAGkB,CAAK,CACjH,CAEQ,uBAAuB1F,EAAiBM,EAAyC,CACrF,GAAI,CAAC,OAAO,OAAO,KAAK,iBAAkBA,EAAQ,QAAQ,EACtD,OAEJ,IAAME,EAAU,KAAK,iBAAiBF,EAAQ,QAAQ,EACtD,OAAO,aAAaE,EAAQ,aAAa,EAEzC,IAAMkF,EAAQrE,GAAW,YAAYb,EAAQ,YAAY,EACrDkF,IAAU,MACVC,GAAsB,KAAKnF,EAAQ,KAAMkF,EAAO,KAAK,eAAe,CAAC,EAGzE3F,EAAM,MAAM,iCAAiCO,EAAQ,QAAQ,IAAKA,CAAO,EAErEN,GACA,OAAO,KAAK,iBAAiBM,EAAQ,QAAQ,EAC7CE,EAAQ,QAAQF,CAAO,GAChBA,EAAQ,OAAS,SACxB,OAAO,KAAK,iBAAiBA,EAAQ,QAAQ,EAC7CF,EAAO,IAAIC,EAAQ,cAAe,gBAAgB,EAElDG,EAAQ,OAAO,IAAI,MAAMF,EAAQ,OAAS,mBAAmBE,EAAQ,IAAI,GAAG,EAAG,EAAI,GAC5E,KAAK,QAAQ,aAAe,UAAU,MAC7C,OAAO,KAAK,iBAAiBF,EAAQ,QAAQ,EAC7CF,EAAO,IAAIC,EAAQ,cAAe,kBAAkB,EACpDG,EAAQ,OAAO,IAAI,MAAMF,EAAQ,OAAS,qBAAqBE,EAAQ,IAAI,GAAG,CAAC,GAG/EA,EAAQ,cAAgB,OAAO,WAAW,IAAM,KAAK,uBAAuBR,EAAQM,CAAO,EAAGrB,EAAU,mBAAmB,CAEnI,CAEQ,qBAAqB2G,EAAiC,CAC1D,KAAOA,EAAM,OAAS,GAAG,CACrB,IAAMpF,EAAUoF,EAAM,MAAM,EAG5B,GAFA7F,EAAM,MAAM,6BAA6BS,EAAQ,QAAQ,IAAK,IAAIA,EAAQ,IAAI,IAAKA,EAAQ,MAAM,EAE7F,KAAK,sBAAsBA,EAAQ,IAAI,EAAG,CAC1C,GAAI,KAAK,4BAA4B,aAAe3B,GAAyB,CACzE2B,EAAQ,OAAO,IAAI,MAAM,+BAA+B,KAAK,4BAA4B,UAAU,EAAE,CAAC,EACtG,MACJ,CAEA,KAAK,oBAAoBA,CAAO,EAEhC,IAAMqF,EAAS,KAAK,iBAAiBrF,CAAO,EACxCqF,IAAW,MACX,KAAK,2BAA2B,KAAKA,CAAM,CAEnD,KAAO,CACH,GAAI,CAAC,KAAK,QAAU,KAAK,OAAO,aAAe,UAAU,KAAM,CAC3DrF,EAAQ,OAAO,IAAI,MAAM,wCAAwC,CAAC,EAClE,QACJ,CAEA,KAAK,oBAAoBA,CAAO,EAEhC,KAAK,OAAO,KAAK,KAAK,eAAeA,CAAO,CAAC,CACjD,CACJ,CACJ,CAEQ,oBAAoBA,EAAiC,CACzD,GAAI,CAACA,EAAQ,aAAc,CACvBA,EAAQ,QAAQ,CACZ,KAAM,WACN,SAAUA,EAAQ,SAClB,SAAUA,EAAQ,IACtB,CAA6B,EAE7B,MACJ,CAEAA,EAAQ,cAAgB,OAAO,WAC3B,IACI,KAAK,uBAAuB,GAAO,CAC/B,SAAUA,EAAQ,KAClB,SAAUA,EAAQ,SAClB,KAAM,SACV,CAAC,EACLvB,EAAU,mBACd,EAEA,KAAK,iBAAiBuB,EAAQ,QAAQ,EAAIA,CAC9C,CAEQ,iBAAiBA,EAA+C,CACpE,OAAQA,EAAQ,KAAM,CAClB,KAAKc,EAAqB,sBACtB,OAAO,KAAK,oCAAoC,6BAC5Cd,EAAQ,SACRA,EAAQ,MACZ,EACJ,KAAKc,EAAqB,iBACtB,OAAO,KAAK,oCAAoC,wBAAwBd,EAAQ,SAAUA,EAAQ,MAAwB,EAC9H,KAAKc,EAAqB,oBACtB,OAAO,KAAK,oCAAoC,2BAA2Bd,EAAQ,SAAUA,EAAQ,MAA2B,EACpI,KAAKc,EAAqB,YACtB,OAAO,KAAK,oCAAoC,oBAAoBd,EAAQ,SAAUA,EAAQ,MAAoB,EACtH,KAAKc,EAAqB,oBACtB,OAAO,KAAK,oCAAoC,2BAA2Bd,EAAQ,SAAUA,EAAQ,MAA2B,EACpI,KAAKc,EAAqB,qBACtB,OAAO,KAAK,oCAAoC,4BAA4Bd,EAAQ,SAAUA,EAAQ,MAA4B,EACtI,KAAKc,EAAqB,6BACtB,OAAO,KAAK,oCAAoC,mCAAmCd,EAAQ,SAAUA,EAAQ,MAAmC,EACpJ,KAAKc,EAAqB,iBACtB,OAAO,KAAK,oCAAoC,yBAAyBd,EAAQ,SAAUA,EAAQ,MAAyB,CACpI,CACA,OAAAT,EAAM,KAAK,gEAAkES,EAAQ,IAAI,EAClF,IACX,CAEQ,eAAeA,EAAmC,CACtD,IAAIC,EACAD,EAAQ,OAASc,EAAqB,sBACtCb,EAAS,KAAK,sBAAsBD,EAAQ,MAAM,EAElDC,EAASD,EAAQ,OAGrB,IAAMF,EAAU,OAAO,OACnB,CACI,QAASE,EAAQ,KACjB,SAAUA,EAAQ,QACtB,EACAC,CACJ,EAEA,OAAO,KAAK,UAAUH,CAAO,CACjC,CAEQ,sBAAsBG,EAAwB,CAClD,IAAM8B,EAAU9B,EAEVqF,EAAwE,CAAC,EAC/E,QAAWC,KAAcxD,EACjB,OAAO,OAAOA,EAASwD,CAAU,IACjCD,EAAoCC,CAAU,EAAIC,GAAezD,EAAQwD,CAAU,CAAC,GAI5F,MAAO,CAAE,QAASD,CAAoC,CAC1D,CAEU,wBAA+B,CACrC,KAAK,2BAA6B,OAAO,WAAW,IAAM,CAClD,KAAK,oBACL,KAAK,mBACD,IAAIR,EAAaE,GAAW,iBAAkB,CAC1C,QAAS,yDACT,OAAQ,EACZ,CAAC,CACL,CAER,EAAGvG,EAAU,qBAAqB,CACtC,CAEU,4BAAmC,CACzC,OAAO,aAAa,KAAK,0BAA0B,EACnD,KAAK,2BAA6B,CACtC,CAKQ,cAAqB,CACzB,KAAK,YAAY,EACb,OAAK,gBAAkBA,EAAU,uBAIrC,KAAK,YAAc,OAAO,WAAW,IAAM,CACnC,KAAK,wBAAwB,EAC7Bc,EAAM,KAAK,wEAAwE,KAAK,cAAc,EAAE,EAExGA,EAAM,KAAK,mDAAmD,KAAK,cAAc,EAAE,EAGvF,KAAK,gCAAqD,EAE1D,KAAK,YAAY,GAAI,EACrB,KAAK,SAASyE,GAAwB,MAAO,EAAK,EAClD,KAAK,gBACT,EAAGvF,EAAU,kBAAkB,EACnC,CAEQ,aAAoB,CACxB,OAAO,aAAa,KAAK,WAAW,EACpC,KAAK,YAAc,CACvB,CAEQ,yBAA0B,CAC9B,OAAOyF,GAAa,mBAAmB,GAAK,KAAK,aAAe,MAAQtF,EAAO,YACnF,CAGQ,gBAAyC,CAC7C,OAAO,KAAK,kBAAkBsF,YAClC,CAEQ,mBAAmB/E,EAAqC,CAC5D,IAAMM,EAAiB,KAAK,eAAe,EACrCgG,EAAYC,GAAYvG,CAAK,EAAEM,CAAc,EAEnDoB,GAAW,QAAQ4E,CAAS,CAChC,CAEQ,kBAAkBtG,EAA+Bc,EAAyD,CAC9G,IAAMR,EAAiB,KAAK,eAAe,EACrCgG,EAAYC,GAAYvG,CAAK,EAAEM,CAAc,EAEnDkG,GAAe,gBAAgB,CAAE,KAAMF,EAAW,GAAGxF,CAAO,CAAC,CACjE,CACJ,ECprCA,IAAK2F,QACDA,EAAA,SAAW,WACXA,EAAA,SAAW,WACXA,EAAA,QAAU,UAHTA,QAAA,IAMEC,GAAQD,GCNf,IAAKE,QACDA,EAAA,KAAO,OACPA,EAAA,MAAQ,QACRA,EAAA,KAAO,OAHNA,QAAA,IAMEC,GAAQD,GCHf,IAAKE,QACDA,EAAA,SAAW,WACXA,EAAA,QAAU,UAFTA,QAAA,IAKEC,GAAQD,GCLf,IAAWE,QACPA,EAAA,gBAAkB,kBAClBA,EAAA,OAAS,SACTA,EAAA,YAAc,cAHPA,QAAA,IAMJC,GAAQD,GCNf,IAAKE,QACDA,EAAA,qBAAuB,uBACvBA,EAAA,cAAgB,gBAChBA,EAAA,aAAe,eACfA,EAAA,eAAiB,iBACjBA,EAAA,cAAgB,gBAChBA,EAAA,IAAM,MACNA,EAAA,SAAW,WACXA,EAAA,UAAY,YARXA,QAAA,IAWEC,GAAQD,GAER,SAASE,GAAeC,EAAkCC,EAA2C,CACxG,GAAID,EAAW,SAAWC,EAAW,OACjC,MAAO,GAGX,QAAWC,KAAUF,EACjB,GAAI,CAACC,EAAW,SAASC,CAAM,EAC3B,MAAO,GAIf,MAAO,EACX,CAEO,SAASC,GAAmBC,EAA+BC,EAA0E,CACxI,IAAMC,EAAM,IAAI,IAAIF,CAAO,EAC3B,OAAW,CAACF,EAAQK,CAAO,IAAK,OAAO,QAAQF,CAAO,EAC9CE,EACAD,EAAI,IAAIJ,CAA4B,EAEpCI,EAAI,OAAOJ,CAA4B,EAG/C,OAAO,MAAM,KAAKI,CAAG,CACzB,CCrCA,IAAKE,QACDA,EAAA,OAAS,SACTA,EAAA,KAAO,OACPA,EAAA,eAAiB,iBAHhBA,QAAA,IAMEC,GAAQD,GCTf,IAAKE,QACDA,EAAA,OAAS,SACTA,EAAA,SAAW,WACXA,EAAA,SAAW,WACXA,EAAA,OAAS,SAJRA,QAAA,IAOEC,EAAQD,GCJf,IAAKE,QACDA,EAAA,OAAS,SACTA,EAAA,OAAS,SACTA,EAAA,SAAW,WAEXA,EAAA,QAAU,UALTA,QAAA,IAQEC,GAAQD,GCXf,IAAKE,QACDA,EAAA,oBAAsB,sBACtBA,EAAA,cAAgB,gBAFfA,QAAA,IAKEC,GAAQD,GAER,SAASE,GAAwCC,EAAmD,CACvG,OAAQA,EAAW,CACf,IAAK,GACD,MAAO,sBACX,QACI,MAAO,eACf,CACJ,CCXA,IAAKC,QACDA,EAAA,QAAU,UACVA,EAAA,MAAQ,QAFPA,QAAA,IAKEC,GAAQD,GAER,SAASE,GAAiBC,EAAsBC,EAA+B,CAClF,GAAID,EAAS,SAAWC,EAAS,OAC7B,MAAO,GAGX,QAAWC,KAAQF,EACf,GAAI,CAACC,EAAS,SAASC,CAAI,EACvB,MAAO,GAIf,MAAO,EACX,CCVO,IAAKC,QACRA,EAAA,KAAO,OACPA,EAAA,OAAS,SACTA,EAAA,MAAQ,QAHAA,QAAA,IAQKC,MAAV,CACI,SAASC,EAAQC,EAAoD,CACxE,OAAKA,EAAI,OAIL,OAAOA,EAAI,CAAC,GAAM,SACXA,EAGJA,EAAI,IAAKC,GAAOC,EAAOD,CAAY,CAAC,EAPhC,CAAC,CAQhB,CAVOH,EAAS,QAAAC,EAYT,SAASG,EAAOD,EAAoBE,EAAO,OAAqBC,EAAY,EAA0B,CACzG,MAAO,CAAE,GAAAH,EAAI,KAAAE,EAAM,UAAAC,CAAU,CACjC,CAFON,EAAS,OAAAI,EAIT,SAASG,EAAyBC,EAA2CC,EAAgB,GAAyC,CACzI,IAAMC,EAAaD,EAAgBD,EAAY,yBAA2BA,EAAY,WAChFF,EAAYE,EAAY,WAAa,EAE3C,GAAIE,EACA,OAAOC,EAAcD,EAAYJ,CAAS,CAElD,CAPON,EAAS,yBAAAO,EAST,SAASI,EAAcC,EAA0CN,EAAY,EAA0B,CAC1G,MAAO,CACH,GAAIM,EAAY,GAChB,KAAMA,EAAY,OAAS,SAAW,SAAwB,OAC9D,UAAAN,CACJ,CACJ,CANON,EAAS,cAAAW,EAQT,SAASE,EAAYH,EAAgC,CACxD,OAAOA,EAAW,EACtB,CAFOV,EAAS,YAAAa,EAIT,SAASC,EAASJ,EAA0C,CAC/D,IAAMJ,EAAaI,EAAqC,WAAa,EAErE,MAAO,UAAUA,EAAW,EAAE,aAAaA,EAAW,IAAI,iBAAiBJ,CAAS,GACxF,CAJON,EAAS,SAAAc,EAMT,SAASC,EAAeZ,EAAoBE,EAAO,OAAqBC,EAAY,EAAqB,CAC5G,OAAOQ,EAASV,EAAOD,EAAIE,EAAMC,CAAS,CAAC,CAC/C,CAFON,EAAS,eAAAe,EAIT,SAASC,EAAWC,EAAmD,CAC1E,GAAI,CACA,OAAO,KAAK,MAAMA,CAAQ,CAC9B,MAAY,CACR,MAAM,IAAI,MAAM,2CAA2CA,CAAQ,GAAG,CAC1E,CACJ,CANOjB,EAAS,WAAAgB,EAQT,SAASE,EAAQC,EAA4BC,EAAqC,CACrF,OAAOD,EAAI,KAAOC,EAAI,IAAMD,EAAI,OAASC,EAAI,MAAQD,EAAI,YAAcC,EAAI,SAC/E,CAFOpB,EAAS,QAAAkB,EAIT,SAASG,EAAaX,EAAuC,CAChE,OAAOA,GAAY,WAAa,CACpC,CAFOV,EAAS,aAAAqB,IA5DHrB,MAAA,KCCV,SAASsB,GAA6BC,EAA0D,CACnG,GAAI,CACA,OAAO,KAAK,KAAK,UAAUA,CAAE,CAAC,CAClC,OAASC,EAAG,CACRC,EAAM,KAAK,+CAAgDF,EAAIC,CAAC,CACpE,CACA,OAAO,IACX,CAEO,SAASE,GAA+BH,EAA0D,CACrG,GAAI,CACA,OAAO,KAAK,MAAM,KAAKA,CAAE,CAAC,CAC9B,OAASC,EAAG,CACRC,EAAM,KAAK,iDAAkDF,EAAIC,CAAC,CACtE,CACA,OAAO,IACX,CC9BO,IAAMG,GAA6B,CAACC,EAAwBC,IACxDC,EAAM,aACTF,EACA,CAACG,EAAKC,EAAWC,KACTD,IAAcH,GACdE,EAAI,KAAKE,CAAW,EAEjBF,GAEX,CAAC,CACL,EAGG,SAASG,GAA4BC,EAAuG,CAC/I,GAAIA,EAAW,cAAc,WACzB,OAAOA,EAAW,aAAa,WAEnC,GAAIA,EAAW,WAAaA,EAAW,YACnC,OAAOA,EAAW,YAAY,OAAmB,CAACJ,EAAKK,KACnDL,EAAIK,CAAU,EAAID,EAAW,UACtBJ,GACR,CAAC,CAAC,CAEb,CAEA,SAASM,GAAeJ,EAA0BK,EAAuC,CAErF,OAAQL,EAAa,CACjB,KAAKM,GAAY,MACb,MAAO,CAAC,CAACD,EAAc,eAC3B,KAAKC,GAAY,cACb,MAAO,CAAC,CAACD,EAAc,sBAC3B,KAAKC,GAAY,MACb,MAAO,CAAC,CAACD,EAAc,eAC3B,KAAKC,GAAY,eACb,MAAO,CAAC,CAACD,EAAc,4BAA8B,CAAC,CAACA,EAAc,uBACzE,QACI,MAAO,EACf,CACJ,CAEA,SAASE,GAA0BZ,EAAwBU,EAAuC,CAC9F,OAAOR,EAAM,aACTF,EACA,CAACG,EAAKC,EAAWC,IAAgB,CAC7B,OAAQD,EAAW,CACf,KAAKS,GAAU,KACf,KAAKA,GAAU,eAAgB,CAItBJ,GAAeJ,EAAaK,CAAa,IAC1CP,EAAIE,CAAW,EAAID,GAEvB,KACJ,CACA,QACID,EAAIE,CAAW,EAAID,EACnB,KACR,CAEA,OAAOD,CACX,EACA,CAAC,CACL,CACJ,CAEO,SAASW,GAAuCC,EAAuD,CAC1G,GAAM,CAAE,WAAAf,EAAa,CAAC,EAAG,cAAAU,CAAc,EAAIK,EAC3C,OAAOH,GAA0BZ,EAAYU,CAAa,CAC9D,CAEO,SAASM,GAAwCT,EAA+EP,EAAoC,CACvK,IAAMiB,EAAgBV,EAAW,aAAa,aAAa,KAAMQ,GACtDb,EAAM,cAAca,EAAY,OAAmCR,EAAW,MAAM,CAC9F,EAED,GAAI,CAACU,EACD,OAAOjB,EAGX,GAAM,CAAE,cAAAU,CAAc,EAAIO,EAE1B,OAAOL,GAA0BZ,EAAYU,CAAa,CAC9D,CC3FO,SAASQ,GAAcC,EAAmBC,EAAsB,CACnE,IAAMC,EAAS,IAAI,WAAWD,CAAY,EACtCE,EAAW,EACXC,EAAY,EAEhB,KAAOD,EAAWH,EAAM,QAAUI,EAAYH,GAAc,CAExD,IAAMI,EAAQL,EAAMG,GAAU,EAC1BG,EAAaD,GAAS,EACtBE,EAAWF,EAAQ,GAGvB,GAAIC,IAAe,GAAM,CACrB,IAAIE,EACJ,GACIA,EAAOR,EAAMG,GAAU,EACvBG,GAAcE,QACTA,IAAS,IACtB,CAGA,QAASC,EAAI,EAAGA,EAAIH,GACZ,EAAAF,GAAaH,GADWQ,IAK5BP,EAAOE,GAAW,EAAIJ,EAAMG,GAAU,EAG1C,GAAIA,GAAYH,EAAM,QAAUI,GAAaH,EACzC,MAIJ,IAAMS,EAASV,EAAMG,CAAQ,EAAKH,EAAMG,EAAW,CAAC,GAAK,EAIzD,GAHAA,GAAY,EAGRI,IAAa,GAAM,CACnB,IAAIC,EACJ,GACIA,EAAOR,EAAMG,GAAU,EACvBI,GAAYC,QACPA,IAAS,IACtB,CACAD,GAAY,EAGZ,IAAMI,EAAWP,EAAYM,EAC7B,QAASD,EAAI,EAAGA,EAAIF,GACZ,EAAAH,GAAaH,GADSQ,IAI1BP,EAAOE,GAAW,EAAIF,EAAOS,EAAWF,CAAC,CAEjD,CAEA,OAAOP,CACX,CCpDA,IAAqBU,GAArB,KAA8B,CAgB1B,YAAYC,EAA0B,CAftCC,EAAA,KAAQ,uBAAuB,IAC/BA,EAAA,KAAQ,uBAAuB,IAG/BA,EAAA,KAAQ,4BAA4B,IACpCA,EAAA,KAAQ,8BAA8B,IACtCA,EAAA,KAAQ,2BAA2B,IACnCA,EAAA,KAAQ,0BACRA,EAAA,KAAQ,gBACRA,EAAA,KAAQ,oBACRA,EAAA,KAAQ,wBACRA,EAAA,KAAQ,sBAA4C,MAEpDA,EAAA,KAAQ,4BAA4B,IAGhC,KAAK,aAAeD,CACxB,CAEQ,yBAAyBE,EAAqB,CAClD,GAAI,OAAK,sBAAwB,KAAK,sBAItC,IAAI,KAAK,sBAAwB,CAAC,KAAK,qBAAsB,CACzD,KAAK,qBAAuB,GAC5BC,EAAO,IAAIC,EAAQ,MAAO,wBAAwBF,EAAS,UAAY,UAAY,MAAM,EAAE,EAC3F,MACJ,CAEI,CAAC,KAAK,sBAAwB,CAACA,EAAS,YACxC,KAAK,qBAAuB,GAC5BC,EAAO,IAAIC,EAAQ,MAAO,sBAAsB,EAEhDC,EAAM,IAAI,0CAA0C,EACpD,KAAK,oBAAsB,KAAK,aAAa,YAAYC,EAAY,6BAA6B,IAAM,QAAQ,GAExH,CAEQ,8BAA8BJ,EAAqB,CACvD,GAAI,KAAK,6BAA+B,KAAK,yBACzC,OAGJ,IAAMK,EAAmB,GACnBC,EAAM,KAAK,IAAI,EACrB,GAAI,CAAC,KAAK,qBACFN,EAAS,YAAc,IACvB,KAAK,qBAAuBM,EAC5B,KAAK,iBAAmBN,EAAS,qBAE9BM,EAAM,KAAK,qBAAuB,IAAK,CAC9C,IAAMC,GAAkBP,EAAS,YAAc,KAAK,kBAAoB,KAASM,EAAM,KAAK,sBAC5F,KAAK,qBAAuBA,EAC5B,KAAK,iBAAmBN,EAAS,YAC7B,KAAK,0BACDO,EAAgBF,GAChBF,EAAM,IAAI,6BAA6B,EACvCF,EAAO,IAAIC,EAAQ,MAAO,8BAA8B,EACxD,KAAK,yBAA2B,IAE5BI,EAAM,KAAK,uBAAyB,MACpCH,EAAM,IAAI,qBAAqB,EAC/BF,EAAO,IAAIC,EAAQ,MAAO,iCAAiC,EAC3D,KAAK,4BAA8B,IAIvCK,EAAgBF,IAChB,KAAK,0BAA4B,GACjCJ,EAAO,IAAIC,EAAQ,MAAO,sBAAsB,EAEhDC,EAAM,IAAI,gDAAgD,EAC1D,KAAK,aAAa,YAAY,EAAI,EAClC,KAAK,uBAAyBG,EAG1C,CACJ,CAEA,IAAIE,EAAa,CACb,GAAI,CAAC,KAAK,aACN,OAGJ,IAAMR,EAAWQ,EAAK,KAAMC,GAAcA,EAAK,OAAS,OAAoB,EACvET,IAIL,KAAK,yBAAyBA,CAAQ,EACtC,KAAK,8BAA8BA,CAAQ,EAC/C,CAGA,SAASQ,EAAa,CAClB,GAAI,CAAC,KAAK,cAAgB,KAAK,2BAA6B,CAAC,KAAK,oBAC9D,OAGJ,IAAME,EAAWF,EAAK,KAAMC,GAASA,EAAK,OAAS,OAAoB,EACnEC,GAAY,CAACA,EAAS,YACtB,KAAK,0BAA4B,GACjC,KAAK,oBAAoB,KAAK,IAAM,CAE5B,KAAK,aAAa,iBAAiB,EAAE,gBACrC,KAAK,aAAa,YAAY,EAAI,CAE1C,CAAC,EAET,CACJ,ECrGA,IAAqBC,GAArB,KAAiC,CAQ7B,YAAYC,EAAgD,CAP5DC,EAAA,KAAU,UAAyC,MACnDA,EAAA,KAAQ,UAAU,GAClBA,EAAA,KAAiB,YAAuB,CACpC,UAAW,CAAC,CAAC,MAAM,UAAU,SACjC,GACAA,EAAA,KAAiB,2BAGb,KAAK,wBAA0BD,CACnC,CAEA,IAAIE,EAAyB,CAEzB,KAAK,QAAQ,EAEb,KAAK,QAAU,CAAC,EAChB,KAAK,QAAQ,WAAaA,EAE1B,KAAK,kBAAkB,CAC3B,CAEA,OAAOA,EAAyB,CACxB,CAAC,KAAK,SAAW,KAAK,QAAQ,aAAeA,GAIjD,KAAK,QAAQ,CACjB,CAEA,IAAI,QAAS,CACT,OAAO,KAAK,OAChB,CAEA,IAAI,OAAOC,EAAgB,CACvB,KAAK,QAAU,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGA,CAAM,CAAC,EAE1C,KAAK,SAAW,KAAK,QAAQ,eAC7B,KAAK,QAAQ,aAAa,OAAS,KAAK,QAEhD,CAEU,mBAAoB,CAK1B,GAJIC,EAAO,UAIP,CAAC,KAAK,SAAS,WACf,OAIJ,IAAMC,EAAmBC,EAAY,YAAY,IAAM,UAAYA,EAAY,SAAS,EAClFC,EAAQ,SAAS,cAAcF,EAAmB,QAAU,OAAO,EACzEE,EAAM,MAAQ,GACdA,EAAM,OAAS,KAAK,QACpBA,EAAM,QAAU,OAEhB,IAAMC,EAAe,IAAM,CACvBC,EAAM,KAAK,6BAA6B,EACxCC,EAAS,gBAAgB,CAC7B,EAEMC,EAAQC,GAA+B,CACzCL,EAAM,UAAY,IAAI,YAAY,CAACK,CAAQ,CAAC,EAC5CL,EAAM,KAAK,EACX,IAAMM,EAAaN,EAAM,KAAK,EAC1BM,GACAA,EAAW,MAAML,CAAY,CAErC,EAEMM,EAAU,IAAM,CAClBL,EAAM,MAAM,gCAAgC,EAE5C,IAAMM,EAAe,KAAK,SAAS,WAC/BA,EACAJ,EAAKI,CAAY,EAEjBN,EAAM,KAAK,4BAA4B,CAE/C,EACAF,EAAM,QAAUO,EAChBP,EAAM,UAAYO,EAClBP,EAAM,QAAUO,EAChBP,EAAM,aAAe,IAAM,CACvB,KAAK,wBAAwB,QAAQ,CACzC,EAEAI,EAAK,KAAK,QAAQ,UAAU,EAC5B,KAAK,QAAQ,aAAeJ,CAShC,CAEU,mBAAoB,CACtB,KAAK,SAAS,eACd,KAAK,QAAQ,aAAa,MAAM,EAChC,KAAK,QAAQ,aAAa,UAAY,MAE1C,KAAK,SAAS,YAAY,KAAK,CACnC,CAEA,SAAU,CACD,KAAK,UAIV,KAAK,kBAAkB,EACvB,KAAK,QAAU,KACnB,CAGA,MAAM,cAAe,CACjB,GAAI,CACA,GAAI,CAAC,KAAK,UAAU,UAChB,MAAM,IAAI,MAAM,sCAAsC,EAG1D,GAAI,CAAC,KAAK,SAAS,aAEf,OAGJ,IAAMS,EAASV,EAAY,eAAe,EAEtCU,GACA,MAAM,KAAK,QAAQ,aAAa,YAAYA,EAAO,QAAQ,CAEnE,OAASC,EAAO,CACZ,MAAAC,EAAO,IAAIC,EAAQ,MAAO,eAAe,EACzCV,EAAM,MAAM,+BAAgCQ,CAAK,EAC3CA,CACV,CACJ,CACJ,ECxJA,IAAMG,GAA+B,GAC/BC,GAA+B,EAEhBC,GAArB,cAAuCC,EAAa,CAApD,kCACIC,EAAA,KAAQ,kBAAkB,CACtB,QAAS,EACT,MAAO,CACX,GAEA,kBAAkBC,EAAmBC,EAAkD,CACnF,KAAK,YAAY,EACjBD,EAAM,QAAQ,KAAK,IAAKE,GAAS,CAC7B,IAAMC,EAAe,OAAOD,EAAK,QAAW,UAAYD,EAAaC,EAAK,MAAM,GAAM,KAGtFA,EAAK,OAASC,GAAa,UAC/B,CAAC,EACDC,EAAS,aAAaJ,EAAO,KAAK,eAAe,CACrD,CAEA,aAAc,CACV,IAAMK,EAAS,QAAQ,aAAa,OACpC,GAAI,CAACA,GAAU,CAACA,EAAO,gBAAkB,CAACA,EAAO,gBAC7C,OAGJ,IAAMC,EAAgB,QAAS,IAAMD,EAAO,eAAkBA,EAAO,iBAAiB,QAAQ,CAAC,CAAC,EAC1FE,EAAY,QAAQF,EAAO,eAAiB,KAAO,MAAM,QAAQ,CAAC,CAAC,EAErEC,EAAgBX,GAChBa,EAAM,KAAK,sBAAsBF,CAAa,MAAMC,CAAS,OAAO,GAC7D,CAAC,KAAK,gBAAgB,SAAW,KAAK,IAAID,EAAgB,KAAK,gBAAgB,OAAO,GAAKV,MAClGY,EAAM,MAAM,iBAAiBF,CAAa,MAAMC,CAAS,OAAO,EAChE,KAAK,gBAAgB,QAAUD,EAC/B,KAAK,gBAAgB,MAAQD,EAAO,eAE5C,CACJ,ECxCA,IAAMI,GAAkB,MAOXC,GAAN,KAAqB,CAUxB,YAAYC,EAAYC,EAAyB,CATjDC,EAAA,KAAQ,YAAiC,MACzCA,EAAA,KAAQ,YAA6B,MACrCA,EAAA,KAAQ,WAA8B,MACtCA,EAAA,KAAQ,qBAAwD,MAChEA,EAAA,KAAQ,qBAAqB,GAC7BA,EAAA,KAAiB,YACjBA,EAAA,KAAiB,UACjBA,EAAA,KAAiB,WAGb,KAAK,SAAWF,EAChB,KAAK,OAASC,EACd,KAAK,QAAU,IAAI,YAAY,CAACA,CAAK,CAAC,EAEtC,GAAI,CACA,IAAME,EAAeC,EAAY,gBAAgB,EAKjD,KAAK,UAAYD,EAAa,WAAW,EACzC,KAAK,UAAU,KAAK,MAAQ,KAC5B,KAAK,UAAU,QAAQA,EAAa,WAAW,EAE/C,KAAK,UAAYA,EAAa,eAAe,EAC7C,KAAK,UAAU,QAAU,KACzB,KAAK,UAAU,sBAAwB,EACvC,KAAK,UAAU,QAAQ,KAAK,SAAS,EAErC,KAAK,SAAW,IAAI,WAAW,KAAK,UAAU,iBAAiB,EAE/D,KAAK,mBAAqBA,EAAa,wBAAwB,KAAK,OAAO,EAC3E,KAAK,mBAAmB,QAAQ,KAAK,SAAS,CAClD,MAAY,CAEZ,CACJ,CAEA,IAAI,OAAQ,CACR,OAAO,KAAK,MAChB,CAEA,IAAI,SAAU,CACV,OAAO,KAAK,QAChB,CAEQ,UAAuB,CAC3B,GAAI,CAAC,KAAK,UAAY,CAAC,KAAK,UACxB,OAAO,IAAI,WAGf,KAAK,UAAU,qBAAqB,KAAK,QAAQ,EAEjD,IAAME,EAAcP,GAAkB,KAAK,SAAS,OAChDQ,EAAQ,KAAK,KAAKC,EAAO,YAAY,QAAUF,CAAW,EAC1DG,EAAM,KAAK,MAAMD,EAAO,YAAY,QAAUF,CAAW,EAE7D,OAAO,KAAK,SAAS,SAASC,EAAOE,CAAG,CAC5C,CAEA,UAAwB,CACpB,IAAMC,EAAO,KAAK,SAAS,EAKrBC,EAHFD,EAAK,OAAO,CAAC,EAAGE,IACL,EAAIA,EACZ,CAAC,EAAIF,EAAK,OACE,IAEbG,EAAW,KAAK,mBAAqBL,EAAO,YAAY,UAAYG,GAAQ,EAAIH,EAAO,YAAY,WACzG,YAAK,mBAAqBK,EAEnB,CAAE,KAAAF,EAAM,SAAAE,CAAS,CAC5B,CAEA,SAAU,CACF,KAAK,qBACL,KAAK,mBAAmB,WAAW,EACnC,KAAK,mBAAqB,MAE1B,KAAK,YACL,KAAK,UAAU,WAAW,EAC1B,KAAK,UAAY,MAEjB,KAAK,YACL,KAAK,UAAU,WAAW,EAC1B,KAAK,UAAY,KACjB,KAAK,SAAW,KAChB,KAAK,mBAAqB,GAE9B,KAAK,QAAQ,YAAY,KAAK,MAAM,CACxC,CACJ,EC/FA,IAAqBC,GAArB,cAAiDC,EAAa,CAI1D,YAAYC,EAA0B,CAClC,MAAM,EAJVC,EAAA,KAAQ,YAAmC,MAC3CA,EAAA,KAAQ,YAA2B,MAK/B,IAAMC,EAAQ,IAAM,CACZ,KAAK,WACLC,EAAS,cAAc,KAAK,UAAU,SAAS,EAAE,KAAMH,EAAY,iBAAiB,EAAE,cAAc,EAExG,KAAK,UAAY,OAAO,WAAWE,EAAOE,EAAO,YAAY,QAAQ,CACzE,EACA,KAAK,UAAY,OAAO,WAAWF,EAAOE,EAAO,YAAY,QAAQ,EAErE,IAAMC,EAAS,IAAM,CACjB,IAAMC,EAAQN,EAAY,kBAAkB,EACxCM,GACA,KAAK,KAAKA,CAAK,CAEvB,EAEA,KAAK,UAAUN,mBAA+CO,GAAmC,CACzFA,EAAK,OAAS,SAAwBP,EAAY,iBAAiB,EAAE,gBACrEK,EAAO,CAEf,CAAC,EACD,KAAK,UAAUL,iBAA4CK,CAAM,EACjEA,EAAO,CACX,CAEQ,KAAKC,EAAyB,CAClC,KAAK,cAAc,EAEnB,KAAK,UAAY,IAAIE,GAAe,QAASF,EAAM,MAAM,CAAC,CAC9D,CAEQ,eAAgB,CAChB,KAAK,YACL,KAAK,UAAU,MAAM,KAAK,EAC1B,KAAK,UAAU,QAAQ,EACvB,KAAK,UAAY,KAEzB,CAEA,SAAU,CACN,KAAK,YAAY,EACb,KAAK,YACL,OAAO,aAAa,KAAK,SAAS,EAClC,KAAK,UAAY,MAErB,KAAK,cAAc,CACvB,CACJ,ECzDO,IAAMG,GAAN,KAAqB,CAIjB,YAAoBC,EAAsE,CAAtE,eAAAA,EAH3BC,EAAA,KAAQ,QAA4B,CAAC,GACrCA,EAAA,KAAQ,eAAe,GAE2E,CAE3F,IAAIC,EAA2B,CAClC,KAAK,MAAM,KAAKA,CAAO,EACvB,KAAK,aAAa,CACtB,CAEA,MAAc,cAAe,CACzB,GAAI,MAAK,aAMT,KAFA,KAAK,aAAe,GAEb,KAAK,MAAM,QAAQ,CACtB,IAAMA,EAAU,KAAK,MAAM,MAAM,EACjC,GAAKA,EAIL,GAAI,CACA,MAAM,KAAK,UAAUA,CAAO,CAChC,MAAY,CACRC,EAAM,MAAM,yBAAyB,KAAK,UAAUD,CAAO,CAAC,EAAE,CAClE,CACJ,CAEA,KAAK,aAAe,GACxB,CACJ,ECxBO,IAAME,GAAN,cAA8BC,EAAa,CAM9C,YAAYC,EAAsB,CAC9B,MAAM,EANVC,EAAA,KAAQ,YAAmC,MAC3CA,EAAA,KAAQ,YAA2B,MACnCA,EAAA,KAAQ,uBACRA,EAAA,KAAQ,wBAKJ,KAAK,UAAUD,uBAA8C,KAAK,oBAAoB,KAAK,IAAI,CAAC,EAChG,KAAK,UAAUA,yBAAgD,KAAK,sBAAsB,KAAK,IAAI,CAAC,EACpG,KAAK,UAAUA,kCAAyD,KAAK,+BAA+B,KAAK,IAAI,CAAC,EACtH,KAAK,UAAUA,qBAA4C,KAAK,mBAAmB,KAAK,IAAI,CAAC,CACjG,CAEA,SAAU,CACF,KAAK,YACL,OAAO,aAAa,KAAK,SAAS,EAClC,KAAK,UAAY,MAGrB,KAAK,YAAY,EAEjB,KAAK,WAAW,QAAQ,EACxB,KAAK,UAAY,IACrB,CAEQ,oBAAoBE,EAAiBC,EAAqBC,EAAyB,CACvF,GAAIA,EAAM,OAAS,UAKnB,KAAK,WAAW,QAAQ,EACxB,KAAK,UAAY,IAAIC,GAAeH,EAASE,CAAK,EAE9C,CAAC,KAAK,WAAW,CACjB,IAAME,EAAQ,IAAM,CAChB,KAAK,gBAAgB,EACrB,KAAK,UAAY,OAAO,WAAWA,EAAOC,EAAO,YAAY,QAAQ,CACzE,EACA,KAAK,UAAY,OAAO,WAAWD,EAAOC,EAAO,YAAY,QAAQ,CACzE,CACJ,CAEQ,sBAAsBC,EAA8BL,EAAqBC,EAAyB,CAClGA,EAAM,OAAS,UAKf,CAAC,KAAK,WAAa,KAAK,UAAU,QAAUA,IAIhD,KAAK,UAAU,QAAQ,EACvB,KAAK,UAAY,MACrB,CAEQ,iBAAkB,CACtB,GAAI,CAAC,KAAK,UACN,OAGJ,IAAMK,EAA8C,CAAC,EAC/CP,EAAU,KAAK,UAAU,QACzBQ,EAAQ,KAAK,UAAU,SAAS,EAItC,GAAIR,IAAYS,GAAQ,UAAW,CAC/B,GAAI,KAAK,oBACL,QAAWH,KAAiB,KAAK,oBAC7BC,EAAQD,CAAa,EAAIE,EAKjC,GAAI,KAAK,qBAAsB,CAC3B,QAAWF,KAAiB,KAAK,qBAC7BC,EAAQD,CAAa,EAAI,CAAE,KAAM,EAAG,SAAU,CAAE,EAEpD,KAAK,qBAAuB,IAChC,CACJ,MACIC,EAAQP,CAAO,EAAIQ,EAGvB,KAAK,cAAc,mBAAuCD,CAAO,CACrE,CAEQ,+BAA+BG,EAA+B,CAElE,KAAK,qBAAuB,KAAK,qBAAqB,OAAQJ,GAAkB,CAACI,EAAa,SAASJ,CAAa,CAAC,GAAK,KAC1H,KAAK,oBAAsBI,CAC/B,CAEQ,mBAAmBC,EAA6B,CAChDA,IAAa,WACb,KAAK,oBAAsB,KAC3B,KAAK,qBAAuB,KAEpC,CACJ,ECxGO,IAAMC,GAAN,cAA8BC,EAAa,CAI9C,YAAYC,EAAkCC,EAAsBC,EAA6B,CAC7F,MAAM,EAJVC,EAAA,KAAQ,aAAmC,MAC3CA,EAAA,KAAQ,8BAA8B,IAIlC,KAAK,4BAA8BD,IAAa,SAEhD,KAAK,UAAUF,qBAAwD,KAAK,mBAAmB,KAAK,IAAI,CAAC,EACzG,KAAK,UAAUC,8BAAqD,KAAK,wBAAwB,KAAK,IAAI,CAAC,EAC3G,KAAK,UAAUA,qBAA4C,KAAK,mBAAmB,KAAK,IAAI,CAAC,CACjG,CAEA,SAAU,CACN,KAAK,YAAY,CACrB,CAEA,mBAAmBG,EAAyC,CACxD,GAAI,KAAK,4BACL,OAGJ,IAAIC,EAAM,EACNC,EAAQ,KAUZ,GARA,OAAO,KAAKF,CAAO,EAAE,QAASG,GAAkB,CAC5C,IAAMC,EAAQJ,EAAQG,CAAa,EAAE,SACjCC,EAAQH,GAAOG,EAAQC,EAAO,YAAY,YAC1CJ,EAAMG,EACNF,EAAQC,EAEhB,CAAC,EAEGD,GAASA,IAAU,KAAK,WAAY,CACpC,IAAMI,EAAsB,KAAK,YAAc,OAAO,OAAON,EAAS,KAAK,UAAU,EAAIA,EAAQ,KAAK,UAAU,EAAE,SAAW,EAEzHC,EAAMK,EAAsBD,EAAO,YAAY,yBAC/C,KAAK,WAAaH,EAClB,KAAK,cAAc,kBAAsCA,CAAK,EAEtE,CACJ,CAEA,wBAAwBK,EAA0B,CAC1C,KAAK,6BACL,KAAK,cAAc,kBAAsCA,CAAS,CAE1E,CAEQ,mBAAmBT,EAA6B,CACpD,KAAK,4BAA8BA,IAAa,QACpD,CACJ,ECpDA,IAAqBU,GAArB,cAA0CC,EAAa,CAOnD,YAAYC,EAAsBC,EAAkCC,EAAkD,CAClH,MAAM,EAPVC,EAAA,KAAQ,cACRA,EAAA,KAAQ,WAA0C,CAAC,GACnDA,EAAA,KAAiB,gBAAoD,CAAC,GACtEA,EAAA,KAAQ,qBAAqB,GAC7BA,EAAA,KAAQ,iBAAiB,GAKrB,KAAK,WAAaH,EAClB,KAAK,cAAgBE,EAErB,KAAK,UAAUF,kBAAyC,KAAK,yBAAyB,KAAK,IAAI,CAAC,EAChG,KAAK,UAAUC,qBAAwD,KAAK,mBAAmB,KAAK,IAAI,CAAC,CAC7G,CAEA,SAAU,CACN,KAAK,YAAY,EAEb,KAAK,oBACL,OAAO,aAAa,KAAK,kBAAkB,EAE3C,KAAK,gBACL,OAAO,aAAa,KAAK,cAAc,CAE/C,CAEA,4BAA4BG,EAA8BC,EAA8B,CAE/EA,EAAc,iBACf,KAAK,SAASD,CAAa,EAAI,GAI/BC,EAAc,iBACd,KAAK,SAASD,CAAa,EAAI,EAEvC,CAEQ,yBAAyBE,EAAiCC,EAAuB,CACjFA,IAAU,WACL,KAAK,qBACN,KAAK,mBAAqB,OAAO,WAAW,KAAK,qBAAqB,KAAK,IAAI,EAAGC,EAAO,mBAAmB,iBAAiB,GAG5H,KAAK,iBACN,KAAK,eAAiB,OAAO,WAAW,KAAK,iBAAiB,KAAK,IAAI,EAAGA,EAAO,mBAAmB,aAAa,IAIrHD,IAAU,UAAyB,KAAK,qBACxCE,EAAM,KAAK,sCAAsC,EACjDC,EAAO,IAAIC,EAAQ,gBAAiB,GAAG,KAAK,WAAW,YAAY,CAAC,qBAAqB,EAEjG,CAEQ,mBAAmBC,EAA6C,CACpE,OAAO,KAAKA,CAAO,EAAE,QAASR,GAAkB,CAC5C,KAAK,SAASA,CAAa,EAAI,KAAK,IAAIQ,EAAQR,CAAa,EAAE,KAAM,KAAK,SAASA,CAAa,GAAK,CAAC,CAC1G,CAAC,CACL,CAEQ,sBAAuB,CAC3B,IAAMS,EAAgBN,GACXA,IAAU,YAIV,OAAO,OAAO,KAAK,WAAW,UAAU,CAAC,EAAE,OAAOM,CAAY,EAAE,OAAS,IAIhFJ,EAAM,KAAK,sDAAsD,EACjEC,EAAO,IAAIC,EAAQ,gBAAiB,GAAG,KAAK,WAAW,YAAY,CAAC,qBAAqB,GAG7F,KAAK,mBAAqB,CAC9B,CAEQ,kBAAmB,CACvB,IAAMG,EAAsB,CAAC,EAE7B,OAAO,KAAK,KAAK,QAAQ,EAAE,QAASV,GAAkB,CAClD,GAAI,KAAK,SAASA,CAAa,EAAI,EAC/B,OAGJ,IAAIW,EAAW,UACTC,EAAc,KAAK,cAAcZ,CAAa,EAChDY,GAAeA,EAAY,WAC3BD,EAAWC,EAAY,UAGvBF,EAAU,QAAQC,CAAQ,EAAI,IAC9BD,EAAU,KAAKC,CAAQ,EACvBL,EAAO,IAAIC,EAAQ,gBAAiB,GAAG,KAAK,WAAW,YAAY,CAAC,mBAAmBI,CAAQ,EAAE,EAEzG,CAAC,EAEGD,EAAU,QACVL,EAAM,KAAK,iDAAiD,EAGhE,KAAK,eAAiB,CAC1B,CACJ,EC5GO,IAAMQ,GAAN,MAAMC,CAAoB,CAC7B,OAAe,oBAAoBC,EAA4B,CAC3D,OAAQA,EAAQ,CACZ,KAAKC,EAAW,OACZ,MAAO,SACX,KAAKA,EAAW,SACZ,MAAO,WACX,KAAKA,EAAW,SACZ,MAAO,WACX,KAAKA,EAAW,KACZ,MAAO,OACX,KAAKA,EAAW,OACZ,MAAO,SACX,KAAKA,EAAW,OACZ,MAAO,SACX,KAAKA,EAAW,eACZ,MAAO,iBACX,KAAKA,EAAW,QACZ,MAAO,UACX,KAAKA,EAAW,OACZ,MAAO,SACX,KAAKA,EAAW,qBACZ,MAAO,QACX,QACI,MAAO,QACf,CACJ,CACA,OAAO,gBAAgBC,EAAsBC,EAA8B,CAcvE,GAAI,CAbqB,CACrBF,EAAW,OACXA,EAAW,SACXA,EAAW,SACXA,EAAW,OACXA,EAAW,KACXA,EAAW,OACXA,EAAW,eACXA,EAAW,QACXA,EAAW,OACXA,EAAW,oBACf,EAEsB,SAASC,EAAO,MAAM,EACxC,OAGJ,IAAME,EAAYF,EAAO,cAAc,0BAA0B,KACjEG,EAAO,eAAe,CAClB,KAAMC,EAAK,YACX,OAAQP,EAAoB,oBAAoBG,EAAO,MAAM,EAC7D,cAAeC,IAAa,SAA2B,IAAM,IAC7D,GAAIC,GAAa,CAAE,aAAcA,CAAU,CAC/C,CAAC,CACL,CACJ,EChDO,IAAMG,GAAN,KAA6B,CAA7B,cAEHC,EAAA,KAAU,gBAAgB,IAC1BA,EAAA,KAAU,cAAc,IACxBA,EAAA,KAAU,YAA8B,MAExC,eAAeC,EAA6B,CACxC,KAAK,KAAKA,IAAa,SAA2B,kBAA2B,iBAAwB,CACzG,CAEA,iBAAiBA,EAA8B,CACvCA,IAAa,UAGjB,KAAK,KAAK,iBAAwB,CACtC,CAEA,sBAAsBA,EAA6B,CAC3CA,IAAa,UAGjB,KAAK,KAAK,wBAA8B,CAC5C,CAEA,WAAWA,EAA6B,CAChCA,IAAa,UAGjB,KAAK,KAAK,oBAA0B,CACxC,CAEQ,KAAKC,EAAqB,CACzB,KAAK,gBACN,KAAK,cAAgB,GAErB,KAAK,UAAYA,EACjBC,GAAW,QAAQC,EAAK,oBAAoB,EAEpD,CAEA,SAAU,CACD,KAAK,cACN,KAAK,YAAc,GAEf,KAAK,WACLC,GAAe,gBAAgB,CAAE,KAAMD,EAAK,qBAAsB,UAAW,KAAK,SAAU,CAAC,EAGzG,CACJ,ECkDA,IAAME,GAAyC,IACzCC,GAAwC,IAS9C,IAAMC,GAAiB,GAEFC,EAArB,MAAqBA,UAAqBC,EAAa,CAmDnD,YAAYC,EAAcC,EAAmC,CACzD,MAAM,EAnDVC,EAAA,KAAiB,QACjBA,EAAA,KAAiB,cACjBA,EAAA,KAAiB,mBAEjBA,EAAA,KAAQ,eAAmC,MAC3CA,EAAA,KAAQ,gBAAyC,MACjDA,EAAA,KAAQ,0BAAiF,CAAC,GAE1FA,EAAA,KAAQ,SAA4B,QACpCA,EAAA,KAAQ,oBAAsCC,EAAiB,QAE/DD,EAAA,KAAQ,gBAAoD,CAAC,GAC7DA,EAAA,KAAQ,uBAAiE,IAAI,KAE7EA,EAAA,KAAQ,aAA+B,MACvCA,EAAA,KAAQ,aAA+B,MAEvCA,EAAA,KAAQ,mBAA2C,MACnDA,EAAA,KAAQ,mBAA2C,MACnDA,EAAA,KAAQ,uBAAmD,MAC3DA,EAAA,KAAQ,gBAAqC,MAC7CA,EAAA,KAAQ,mBAAyC,MACjDA,EAAA,KAAQ,gCAAsD,MAE9DA,EAAA,KAAQ,0BAA0B,IAElCA,EAAA,KAAQ,kBAAkCE,GAA0B,GAMpEF,EAAA,KAAiB,aAEjBA,EAAA,KAAiB,gBAEjBA,EAAA,KAAQ,eAA+C,CAAC,GACxDA,EAAA,KAAQ,mBAAmB,IAC3BA,EAAA,KAAQ,YAA6B,MAGrCA,EAAA,KAAQ,oBAA8C,IAAI,KAC1DA,EAAA,KAAQ,+BAA4E,IAAI,KACxFA,EAAA,KAAQ,sCAA4E,IAAI,KACxFA,EAAA,KAAQ,qCAA2E,IAAI,KACvFA,EAAA,KAAQ,wCAA8E,IAAI,KAC1FA,EAAA,KAAQ,6BAA4C,MAEpDA,EAAA,KAAiB,2BAuqEjBA,EAAA,KAAQ,uBAAuBG,EAAM,SAAS,MAAOC,GAAiC,CAClF,GAAK,KAAK,WAAW,MAIrB,GAAI,CACA,MAAM,KAAK,WAAW,oBAAoBA,CAAa,CAC3D,OAASC,EAAQ,CAIb,GAFAC,EAAM,KAAK,wCAAyCD,CAAC,EAEjDA,EAAE,UAAY,iCACd,OAAO,KAAK,sBAAsB,CAC9B,cAAe,GACf,kBAAmB,GACnB,aAAc,EAClB,CAAC,CAET,CACJ,EAAG,GAAG,GAtrEFE,EAAO,OAAOT,EAAKC,CAAc,EACjCQ,EAAO,0BAA0B,IAAM,KAAK,eAAe,IAAM,IAAI,EAErEC,GAAe,OAAO,EACtBC,GAAqB,OAAO,IAAM,KAAK,YAAY,YAAY,CAAC,EAChEC,GAAU,OAAO,EACjBC,GAAsB,OAAO,EAE7B,KAAK,KAAOb,EACZ,KAAK,WAAa,IAAIc,GACtB,KAAK,gBAAkB,IAAIC,GAAe,KAAK,yBAAyB,KAAK,IAAI,CAAC,EAElF,KAAK,UAAY,IAAM,CACf,KAAK,eAAiB,KAAK,OAC3B,KAAK,KAAK,mBAAmB,KAAK,cAAc,GAAI,KAAK,SAAW,OAAyBC,EAAW,SAAWA,EAAW,MAAM,EAChIC,EAAO,4BACPR,EAAO,eACH,CACI,WAAYS,EAAK,gCACjB,OAAQ,MACZ,EACA,EACJ,GAGRT,EAAO,QAAQ,EACfC,GAAe,QAAQ,EACvBC,GAAqB,QAAQ,EAC7BC,GAAU,QAAQ,EAClBC,GAAsB,QAAQ,CAClC,EACA,OAAO,iBAAiB,SAAU,KAAK,SAAS,EAEhD,KAAK,wBAA0B,IAAIM,GACnC,KAAK,aAAe,IAAIC,GAAY,KAAK,uBAAuB,EAE5DH,EAAO,iBAAmB,IAC1B,KAAK,2BAA6B,OAAO,YAAY,KAAK,sBAAsB,KAAK,IAAI,EAAGI,EAAsC,EAE1I,CAEA,OAAO,SAA+B,CAClC,OAAOvB,EAAa,QACxB,CAEA,OAAO,iBAAwB,CACvBA,EAAa,kBAAoB,CAACA,EAAa,WAC/CA,EAAa,eAAiB,GAEtC,CAEA,OAAO,IAAoB,CACvB,OAAOA,EAAa,UAAU,eAAe,IAAM,IACvD,CAEA,MAAM,QAAQ,CACV,YAAAwB,EACA,aAAAC,EACA,aAAAC,EACA,QAAAC,EAAU,GACV,eAAAC,EAAiB,GACjB,kBAAAC,EAAoB,GACpB,uBAAAC,EACA,YAAAC,EACA,YAAAC,CACJ,EAA8B,CAC1B,GAAIhC,EAAa,iBACb,MAAAW,EAAO,IAAIsB,EAAQ,MAAO,WAAW,EACrCvB,EAAM,KAAK,mDAAmD,EACxD,IAAIwB,EAAahB,EAAW,MAAM,EAG5C,IAAMiB,EAAc,KAAK,IAAI,EAE7BnC,EAAa,iBAAmB,GAChCoC,GAAwB,aAAa,EAErC,GAAI,CACA,KAAK,aAAe,KAAK,mBAAmB,EAC5C,MAAM,KAAK,aAAa,QAAQV,CAAY,EAE5C,IAAMlB,EAAgB,KAAK,aAAa,iBAAiB,EAErDiB,IAAiBY,GAAS,MAASb,GAAeA,EAAY,OAAS,EACvE,KAAK,sBAAsBS,EAAQ,yBAA0BzB,CAAa,EAE1E,KAAK,sBAAsByB,EAAQ,cAAezB,CAAa,EAGnE,IAAM8B,EAAa,MAAM,KAAK,mBAAmB,CAC7C,YAAAd,EACA,aAAAC,EACA,UAAWc,GAAc,SACzB,aAAAb,EACA,QAAAC,EACA,eAAAC,EACA,kBAAAC,EACA,uBAAAC,EACA,YAAAC,EACA,YAAAI,EACA,YAAAH,CACJ,CAAC,EAED,GAAI,CAAC,KAAK,cACN,MAAM,IAAIE,EAAahB,EAAW,aAAa,EAiBnD,GAdA,KAAK,kBAAoBb,EAAiB,SAG1C,KAAK,qBAAqBG,CAAa,EAEvC,MAAM,KAAK,mBAAmB8B,CAAU,EAExC,MAAM,KAAK,mBAAmB,EAC9B,KAAK,uBAAuB,EAC5B,MAAM,KAAK,oBAAoB,EAE/B,KAAK,WAAW,YAAY,EAGxBtC,EAAa,eACb,MAAM,IAAIkC,EAAahB,EAAW,QAAQ,EAG9C,OAAAR,EAAM,MAAM,gBAAiB,CAAE,YAAAc,EAAa,aAAAC,EAAc,aAAAC,CAAa,CAAC,EAExE,MAAM,KAAK,kCAAkCY,CAAU,EACvD,MAAM,KAAK,mCAAmCA,CAAU,EACxDE,EAAS,cAAc,KAAK,aAAa,UAAU,EAAG,KAAK,aAAa,iBAAiB,CAAC,EAC1FA,EAAS,eAAe,KAAK,cAAc,WAAY,KAAK,cAAc,eAAgB,KAAK,6BAA6B,EAAG,MAAM,KAAK,yBAAyB,CAAC,EACpK,MAAM,KAAK,oCAAoCF,CAAU,EACzD,MAAM,KAAK,2BAA2BA,CAAU,EAChDE,EAAS,uBAAuC,EAEhD,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EAErBxC,EAAa,SAAW,KAEpB,KAAK,cAAc,YACnB,MAAM,KAAK,kBAAkB,EAG1B,KAAK,aAChB,OAASyC,EAAY,CACjB,WAAK,OAAOA,EAAO,8BAA8B,EAC3CA,CACV,QAAE,CACEzC,EAAa,iBAAmB,EACpC,CACJ,CAEA,MAAM,OAAO0C,EAA0J,CACnK,GAAI1C,EAAa,iBACb,MAAAW,EAAO,IAAIsB,EAAQ,MAAO,UAAU,EACpCvB,EAAM,KAAK,mDAAmD,EACxD,IAAIwB,EAAahB,EAAW,MAAM,EAG5C,IAAMiB,EAAc,KAAK,IAAI,EAE7BnC,EAAa,iBAAmB,GAChC,KAAK,OAAS,aACdoC,GAAwB,aAAa,EAErC,GAAI,CACA,IAAMO,EAAW,CAAC,CAACD,EAAS,aAAa,OACzC,GAAIC,GAAYxB,EAAO,iBAAmB,EACtC,MAAAT,EAAM,MAAM,8CAA8C,EACpD,IAAIwB,EAAahB,EAAW,WAAW,EAGjD,KAAK,aAAe,KAAK,mBAAmB,EAC5C,MAAM,KAAK,aAAa,QAAQwB,EAAS,aAAc,CAACC,CAAQ,EAEhE,IAAMnC,EAAgB,KAAK,aAAa,iBAAiB,EACzD,KAAK,sBAAsByB,EAAQ,kBAAmBzB,CAAa,EAEnE,IAAM8B,EAAa,MAAM,KAAK,kBAAkBI,EAAUP,CAAW,EAErE,GAAI,CAAC,KAAK,cACN,MAAM,IAAID,EAAahB,EAAW,aAAa,EAMnD,OAJA,KAAK,cAAc,SAAWyB,EAE9BH,EAAS,cAAc,KAAK,aAAa,UAAU,EAAGhC,CAAa,EAE/D,KAAK,cAAc,cAAgB,KAAK,cAAc,aACtDE,EAAM,IAAI,KAAK,cAAc,aAAe,iBAAmB,iBAAiB,EAEhFV,EAAa,SAAW,KAExBA,EAAa,iBAAmB,GAEhC,KAAK,WAAW,YAAY,EAC5BwC,EAAS,cAAc,KAAK,cAAc,4CAAgF,EAEnH,KAAK,eAGT,KAAK,aAAaF,CAAU,CACvC,OAASG,EAAY,CACjB,MAAAzC,EAAa,iBAAmB,GAChC,KAAK,OAAOyC,EAAO,6BAA6B,EAC1CA,CACV,CACJ,CAEA,MAAc,aAAaH,EAA+E,CACtG5B,EAAM,MAAM,0BAA0B,EACtCV,EAAa,iBAAmB,GAEhC,GAAI,CAGA,GAFA,KAAK,kBAAoBK,EAAiB,SAEtC,CAAC,KAAK,eAAiB,CAAC,KAAK,aAC7B,MAAM,IAAI6B,EAAahB,EAAW,aAAa,EAkBnD,GAfA,KAAK,wBAAwB,WAAW,KAAK,cAAc,QAAQ,EAG/D,CAAC,KAAK,cAAc,UAAY,CAAC,KAAK,wBAAwB,GAC9D,KAAK,qBAAqB,KAAK,aAAa,iBAAiB,CAAC,EAGlE,MAAM,KAAK,mBAAmBoB,CAAU,EAExC,MAAM,KAAK,mBAAmB,EAC9B,KAAK,uBAAuB,EAC5B,MAAM,KAAK,oBAAoB,EAE/B,KAAK,WAAW,YAAY,EAExB,KAAK,SAAW,QAEhB,OAAO,KAAK,cAIhB,GAAItC,EAAa,eACb,MAAM,IAAIkC,EAAahB,EAAW,QAAQ,EAG9C,MAAM,KAAK,kCAAkCoB,CAAU,EACvD,MAAM,KAAK,mCAAmCA,CAAU,EACxD,MAAM,KAAK,0BAA0BA,CAAU,EAE/C,IAAMM,EAAQ,MAAM,KAAK,0BAA0BN,EAAW,OAAO,MAAOA,EAAW,OAAO,MAAM,EAEpGE,EAAS,eACL,KAAK,cAAc,WACnB,KAAK,cAAc,eACnB,KAAK,6BAA6B,EAClC,MAAM,KAAK,yBAAyB,EACpCI,CACJ,EACA,MAAM,KAAK,oCAAoCN,CAAU,EACzD,MAAM,KAAK,2BAA2BA,CAAU,EAChDE,EAAS,uBAAuC,EAEhD,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EAErB,KAAK,OAAS,SACd,KAAK,kBAAkB,EAEvBxC,EAAa,SAAW,KAExB,IAAM6C,EAAmB,KAAK,uCAAuCP,CAAU,EAC/E,GAAIO,EAAkB,CAClB,IAAMC,EAAWvC,EAAM,oBAAoBsC,CAAgB,EACxC,OAAO,KAAKC,CAAQ,EAAE,OAAS,GAG9CN,EAAS,wBAAwBM,CAAQ,CAEjD,CAEA,YAAK,eAAe,OAAO,OAAO,MAAM,KAAK,iBAAiB,CAAC,EAAG,EAAK,EAEhE,KAAK,aAChB,OAASL,EAAY,CACjB,WAAK,OAAOA,EAAO,6BAA6B,EAC1CA,CACV,QAAE,CACEzC,EAAa,iBAAmB,EACpC,CACJ,CAEA,MAAc,sBAAsB4C,EAAiD,CACjF,IAAMG,EAAoBH,EAAM,IAAI,KAAK,uBAAuB,KAAK,IAAI,CAAC,EAG1E,OAFuB,MAAM,QAAQ,IAAIG,CAAiB,GAEpC,OAAQC,GAAuB,CAAC,CAACA,CAAI,CAC/D,CAEA,MAAc,0BAA0BJ,EAAiCK,EAA6C,CAClH,GAAI,CAACL,GAAS,CAACA,EAAM,OACjB,OAGJ,IAAMM,EAAmB,CACrB,MAAO,MAAM,KAAK,sBAAsBN,CAAK,CACjD,EAEA,OAAIK,IACAC,EAAU,OAASD,GAGhBC,CACX,CAEA,MAAM,OAAOC,EAAwBC,EAAiBC,GAAS,KAAMC,EAAiBC,EAA6BC,EAAqB,CAGpI,GAAIxD,EAAa,iBACb,MAAAU,EAAM,KAAK,mDAAmD,EACxD,IAAIwB,EAAahB,EAAW,QAAQ,EAG9ClB,EAAa,iBAAmB,GAEhC,GAAI,CACA,IAAMyD,EAAY,KAAK,IAAI,EACrBnB,EAAa,MAAM,KAAK,qBAAqBa,EAAgBC,EAAME,EAAQC,EAAoBC,CAAU,EAG/G,GAFA,KAAK,aAAe,KAAK,mBAAmB,EAExC,CAAC,KAAK,cACN,MAAM,IAAItB,EAAahB,EAAW,aAAa,EAQnD,GAAI,CAJWoB,EAAW,aAAa,aAAa,KAAMoB,GAC/CA,EAAY,QAAUrD,EAAiB,QAAUqD,EAAY,KAAO,KAAK,eAAe,MAClG,EAGG,MAAAhD,EAAM,IAAI,yCAAyC,EACnDC,EAAO,IAAIsB,EAAQ,KAAM,UAAU,EAC7B,IAAIC,EAAahB,EAAW,QAAQ,EAmB9C,GAhBAkB,GAAwB,aAAa,EAErC,MAAM,KAAK,mBAAmBE,CAAU,EAExC,KAAK,iCAAiCA,CAAU,EAChD,MAAM,KAAK,mBAAmB,EAC9B,KAAK,uBAAuB,EAC5B,MAAM,KAAK,oBAAoB,EAC/B,MAAM,KAAK,2BAA2BA,CAAU,EAEhD,KAAK,WAAW,YAAY,EAC5B,KAAK,mBAAmBmB,EAAWlB,GAAc,QAAQ,EACzD5B,EAAO,IAAIsB,EAAQ,KAAM,UAAU,EAEnCjC,EAAa,SAAW,KAEpBA,EAAa,eACb,MAAM,IAAIkC,EAAahB,EAAW,QAAQ,EAE9ClB,EAAa,iBAAmB,EACpC,OAASyC,EAAY,CACjB,MAAAzC,EAAa,iBAAmB,GAChC,KAAK,OAAOyC,EAAO,oCAAoC,EACjDA,CACV,CACJ,CAEQ,iBAAiBH,EAAkD,CAKvE,MAJI,CAACA,EAAW,cAIZ,CAACA,EAAW,aAAa,QAAQ,SAASqB,GAAmB,YAAY,EAClE,GAGJ,KAAK,cAAcrB,CAAU,CACxC,CAEQ,gBAAgBA,EAAkD,CACtE,GAAI,CAACA,EAAW,aACZ,MAAO,GAGX,IAAMsB,EAAetB,EAAW,aAAa,QAAQ,SAASqB,GAAmB,cAAc,EACzFE,EAAcvB,EAAW,aAAa,QAAQ,SAASqB,GAAmB,aAAa,EAE7F,MAAI,CAACC,GAAiBA,GAAgBC,EAC3B,GAGJ,KAAK,cAAcvB,CAAU,CACxC,CAEQ,cAAcA,EAAyC,CAC3D,IAAMwB,GAAMxB,EAAW,aAAa,cAAgB,CAAC,GAAG,KAAMoB,GAAgBnD,EAAM,cAAcmD,EAAY,OAAmCpB,EAAW,MAAM,CAAC,EACnK,OAAQwB,GAAMA,EAAG,YAAe,EACpC,CAEQ,gBAAgBxB,EAAyC,CAC7D,OAAOA,EAAW,cAAc,SAAS,SAASqB,GAAmB,aAAa,GAAK,EAC3F,CAEQ,yBAA0B,CAC9B,OAAO,KAAK,eAAe,cAAgB,KAAK,eAAe,UACnE,CAEA,MAAc,mBAAoB,CAC9B,GAAI,CAAC,KAAK,cAAgB,CAAC,KAAK,eAAiB,CAAC,KAAK,WACnD,MAAM,IAAIzB,EAAahB,EAAW,aAAa,EAGnD,KAAK,OAAS,aAEd,IAAMV,EAAgB,KAAK,aAAa,iBAAiB,EACzD,KAAK,sBAAsByB,EAAQ,kBAAmBzB,CAAa,EACnEE,EAAM,MAAM,kBAAmB,CAC3B,eAAgB,KAAK,cAAc,EACvC,CAAC,EAED,GAAI,CACA,KAAK,wBAAwB,eAAe,KAAK,WAAW,YAAY,CAAC,EACzE,MAAM,KAAK,WAAW,WAAW,KAAK,aAAa,iBAAiB,CAAC,EACrE8B,EAAS,eAAe,EAExB,KAAK,OAAS,SACd,KAAK,kBAAoBnC,EAAiB,SAC1C,KAAK,kBAAkB,EAEvB,KAAK,eAAe,OAAO,OAAO,MAAM,KAAK,iBAAiB,CAAC,EAAG,EAAI,CAC1E,OAASoC,EAAY,CACjB,KAAK,OAAOA,EAAO,kCAAkC,CACzD,CACJ,CAEA,MAAc,0BAA2B,CACrC,IAAMsB,EAAe,MAAM,KAAK,iBAAiB,EAEjD,OAAOxD,EAAM,sBAAsB,OAAO,OAAOwD,CAAY,EAAE,OAAQL,GAAgB,CAACA,EAAY,QAAQ,CAAC,CACjH,CAEQ,kCAAkCM,EAA2C,CACjF,GAAM,CAACC,EAAmBC,CAAU,EAAIF,EAAc,MAAM,GAAG,EACzDG,EAAiB,SAASF,EAAmB,EAAE,EAErD,GAAI,MAAME,CAAc,EACpB,MAAM,IAAI,MAAM,mCAAmC,EAGvD,IAAMC,EAAY,KAAKF,CAAU,EAC3BG,EAAkB,IAAI,WAAWD,EAAU,MAAM,EACvD,QAASE,EAAI,EAAGA,EAAIF,EAAU,OAAQE,IAClCD,EAAgBC,CAAC,EAAIF,EAAU,WAAWE,CAAC,EAG/C,GAAI,CAGA,IAAMC,EAFoBC,GAAcH,EAAiBF,CAAc,EAErC,OAAO,CAACM,GAAKC,MAC3CD,IAAO,OAAO,aAAaC,EAAI,EACxBD,IACR,EAAE,EAEC,CAAE,KAAAE,EAAM,KAAAC,EAAM,IAAAC,EAAK,KAAAC,EAAM,KAAAC,EAAM,KAAAC,EAAM,IAAAC,EAAK,IAAAC,EAAI,EAAI,KAAK,MAAMX,CAAO,EAE1E,MAAO,CACH,MAAOM,EACP,SAAUI,EACV,YAAaC,GACb,YAAa,CACT,KAAMJ,EAAK,MAAM,GAAG,EACpB,SAAUE,EACV,WAAYD,CAChB,EACA,YAAa,CACT,KAAMH,EAAK,MAAM,GAAG,CACxB,EACA,YAAaD,CACjB,CACJ,OAASlE,EAAQ,CACb,WAAK,OAAOA,EAAG,sCAAsC,EAC/CA,CACV,CACJ,CAEQ,mBAAmBgD,EAAmB0B,EAAyB,CACnE,IAAMC,EAAc,CAChB,CAAC7C,GAAc,QAAQ,EAAG,WAC1B,CAACA,GAAc,QAAQ,EAAG,WAC1B,CAACA,GAAc,OAAO,EAAG,MAC7B,EAEA3B,GAAe,gBAAgB,CAC3B,KAAMQ,EAAK,WACX,MAAO,KAAK,IAAI,EAAIqC,EACpB,aAAc,KAAK,UAAU,CAAE,OAAQ,CAAC2B,EAAYD,CAAQ,EAAG,cAAc,CAAE,CAAC,CACpF,CAAC,CACL,CAEA,MAAM,OAAOzD,EAA6B,CACtC,GAAI,KAAK,SAAW,OAChB,MAAAf,EAAO,IAAIsB,EAAQ,MAAO,gBAAgB,EAC1CvB,EAAM,MAAM,yCAAyC,EAC/C,IAAI,MAAM,yCAAyC,EAG7D,GAAI,CAAC,KAAK,cAAgB,CAAC,KAAK,eAAiB,CAAC,KAAK,WACnD,MAAM,IAAIwB,EAAahB,EAAW,aAAa,EAGnD,KAAK,OAAS,aAEdR,EAAM,MAAM,uBAAwBgB,CAAY,EAEhD,GAAI,CACA,MAAM,KAAK,aAAa,QAAQA,CAAY,EAE5C,IAAMlB,EAAgB,KAAK,aAAa,iBAAiB,EACzD,KAAK,sBAAsByB,EAAQ,gBAAiBzB,CAAa,EAGjE,KAAK,qBAAqBA,CAAa,EAEvC,KAAK,wBAAwB,eAAe,KAAK,WAAW,YAAY,CAAC,EACzE,MAAM,KAAK,WAAW,WAAWA,CAAa,EAE9C,KAAK,kBAAoBH,EAAiB,SAE1C,IAAMgF,EAAa,KAAK,6BAA6B,EAC/CC,EAAmB,OAAO,KAAKD,CAAU,EAC3CC,EAAiB,QACjB,KAAK,mBAAmB,CAAE,WAAAD,EAAY,aAAcC,EAAkB,QAAS,GAAM,aAAc,EAAK,CAAC,EAE7G,KAAK,mCAAmC,CAAE,WAAY,KAAK,cAAc,kBAAmB,CAAC,EAE7F,IAAMC,EAAgB,MAAM,KAAK,WAAW,SAAS,KAAK,aAAa,CAAC,EAExE,GAAIA,EAAc,OAAO,MAAO,CAC5B,IAAMC,EAAqB,MAAM,KAAK,iBAAiB,EAEvDD,EAAc,MAAM,MAAM,QAASvC,GAAS,CACxCA,EAAK,gBAAgB,QAASyC,GAAO,CAC5BD,EAAmBC,CAAE,IAI1BD,EAAmBC,CAAE,EAAE,SAAW,GACtC,CAAC,CACL,CAAC,CACL,CAEA,KAAK,cAAc,OAASF,EAAc,OAAO,QAAU,KAC3D,IAAM3C,EAAQ,MAAM,KAAK,0BAA0B2C,EAAc,OAAO,MAAOA,EAAc,OAAO,MAAM,EAW1G,GATA/C,EAAS,eAAe,EACxBA,EAAS,cAAc,KAAK,aAAa,UAAU,EAAGhC,CAAa,EACnEgC,EAAS,eACL,KAAK,cAAc,WACnB,KAAK,cAAc,eACnB,KAAK,6BAA6B,EAClC,MAAM,KAAK,yBAAyB,EACpCI,CACJ,EACIzB,EAAO,wBAAyB,CAChC,IAAMuE,EAA8D,MAAM,KAAK,gCAAgC,EACzGF,EAAqB,MAAM,KAAK,iBAAiB,EAEvDE,GAAsB,cAAc,QAASC,GAAqB,CAC9D,IAAMC,EAAgBrF,EAAM,UAAUoF,CAAgB,EAChDjC,EAAc8B,EAAmBI,CAAa,EAChDlC,IACAA,EAAY,gBAAkBiC,EAAiB,gBAEvD,CAAC,EACD,MAAM,KAAK,oCAAoC,CAAE,aAAcD,CAAqB,CAAC,CACzF,CACA,OAAAlD,EAAS,uBAAuC,EAEhD,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EAErB,KAAK,OAAS,SACd,KAAK,kBAAkB,EACvB,KAAK,eAAe,OAAO,OAAO,MAAM,KAAK,iBAAiB,CAAC,EAAG,EAAI,EAEtE,MAAM,KAAK,mCAAmC,EAC9C,MAAM,KAAK,0BAA0B,EAE9B,KAAK,aAChB,OAASC,EAAY,CACjB,WAAK,OAAOA,EAAO,uBAAuB,EACpCA,CACV,CACJ,CAEA,MAAM,SAAU,CACZ,GAAI,KAAK,SAAW,OAChB,MAAA9B,EAAO,IAAIsB,EAAQ,MAAO,iBAAiB,EAC3CvB,EAAM,MAAM,0CAA0C,EAChD,IAAI,MAAM,0CAA0C,EAG9D,KAAK,OAAS,aAEdA,EAAM,MAAM,uBAAuB,EACnC,KAAK,sBAAsBuB,EAAQ,iBAAkB,KAAK,cAAc,iBAAiB,CAAC,EAE1F,KAAK,kBAAoB5B,EAAiB,OAEtC,KAAK,WAAW,OAChB,MAAM,KAAK,WAAW,OAAOa,EAAW,QAAQ,EAGpD,KAAK,OAAO,IAAIgB,EAAahB,EAAW,QAAQ,CAAC,CACrD,CAEA,MAAM,QAAS,CACXR,EAAM,MAAM,QAAQ,EAEpB,IAAMmF,EAAS,KAAK,SAAW,SAA2B3E,EAAW,OAASA,EAAW,SAEzFP,EAAO,IAAIsB,EAAQ,OAAQ4D,CAAM,EAE7B,KAAK,WAAW,OAChB,MAAM,KAAK,WAAW,OAAOA,CAAM,EACnC,KAAK,OAAO,IAAI3D,EAAa2D,CAAM,CAAC,GAEpCrD,EAAS,SAAS,IAAIN,EAAahB,EAAW,MAAM,EAAG,KAAK,eAAiB,KAAK,cAAc,EAAE,CAE1G,CAEA,MAAM,eAAe4E,EAA8BC,EAA+B,CAC9E,GAAI,CAAC,KAAK,WAAW,MAAO,CACxB,KAAK,OAAO,IAAI7D,EAAahB,EAAW,aAAa,EAAG,2BAA2B,EACnF,MACJ,CAEA,IAAM8E,EAAU,MAAM,KAAK,WAAW,eAAeF,EAAe,IAAIG,EAAgB,WAAW,EAAGF,CAAM,EACxGtD,EAA2B,KAC3BuD,EAAQ,OAAS,UACbA,EAAQ,QAAU,kBAClBvD,EAAQuD,EAAQ,OAEhBvD,EAAQvB,EAAW,eAI3B,IAAMgF,EAAmDF,EAAQ,aACjE,GAAI,CAACE,GAAoBF,EAAQ,qBAC7B,MAAM,IAAI,MAAMA,EAAQ,qBAAqB,CAAC,EAAE,MAAM,EAG1D,QAAWG,KAAQD,EACf,MAAM,KAAK,kBAAkB3F,EAAM,UAAU4F,CAAI,EAAGA,EAAM1D,CAAK,CAEvE,CAEA,MAAM,qBAAqBqD,EAAmCC,EAA+B,CACzF,GAAI,CAAC,KAAK,WAAW,MAAO,CACxB,KAAK,OAAO,IAAI7D,EAAahB,EAAW,aAAa,EAAG,2BAA2B,EACnF,MACJ,CAEA,IAAM8E,EAAU,MAAM,KAAK,WAAW,qBAAqBF,EAAgBC,CAAM,EAC7EtD,EAA2B,KAC3BuD,EAAQ,OAAS,UACbA,EAAQ,QAAU,kBAClBvD,EAAQuD,EAAQ,OAEhBvD,EAAQvB,EAAW,eAI3B,IAAMgF,EAAmDF,EAAQ,aACjE,QAAWG,KAAQD,EACf,MAAM,KAAK,kBAAkB3F,EAAM,UAAU4F,CAAI,EAAGA,EAAM1D,CAAK,CAEvE,CAEA,MAAM,kBAAkBmD,EAAgCQ,EAAM,GAAO,CAC7D,KAAK,WAAW,QAChB,MAAM,KAAK,WAAW,kBAAkBR,EAAeQ,CAAG,EAC1D,KAAK,qBAAqBR,CAAa,EAE/C,CAEA,UAAUS,EAAgB,CACtB,KAAK,aAAa,OAASA,CAC/B,CAEA,0BAA2B,CACnB,KAAK,YACL,KAAK,WAAW,yBAAyB,CAEjD,CAEQ,eAAetC,EAA6BuC,EAAmB,CACnE,GAAI,CAAC,KAAK,WACN,OAGJ,IAAMC,EAA4B,CAAC,EAEnC,QAAW7C,KAAeK,GAClBL,EAAY,QAAUrD,EAAiB,QAAUqD,EAAY,QAAUrD,EAAiB,YAInF,KAAK,WAAW,YAAYqD,EAAY,EAAE,GAC3C,KAAK,WAAW,SAASA,EAAY,GAAI4C,CAAQ,GAIrD5C,EAAY,QAAUrD,EAAiB,UACvCkG,EAAS,KAAK7C,EAAY,EAAE,EAIhC6C,EAAS,OACT,KAAK,WAAW,KAAKA,EAAU,KAAM,CAAC,CAAC,KAAK,eAAe,QAAQ,EAC5D,KAAK,WAAW,YAAY,IAAM,UAEzC,KAAK,kCAAkC,CAE/C,CAEA,MAAc,OAAOV,EAAsBW,EAAoB,CACvDA,GACA9F,EAAM,MAAM8F,EAAWX,CAAM,EAGjCnF,EAAM,MAAM,qBAAsBmF,CAAM,EAExCY,GAAoB,gBAAgBZ,EAAQ,KAAK,YAAY,YAAY,CAAC,EAC1EhF,GAAqB,QAAQ,EAE7BC,GAAU,WAAW,KAAK,YAAY,YAAY,CAAC,EACnDA,GAAU,QAAQ,EAClBC,GAAsB,WAAW,KAAK,YAAY,YAAY,CAAC,EAC/DA,GAAsB,QAAQ,EAE9B,KAAK,WAAW,YAAY,EAAK,EAE5B8E,EAAO,MAED,KAAK,WAAW,OACvB,KAAK,WAAW,OAAO3E,EAAW,MAAM,EAFxCP,EAAO,IAAIsB,EAAQ,MAAO4D,EAAO,MAAM,EAK3C7F,EAAa,iBAAmB,GAEhC,IAAMmD,EAAiB,KAAK,eAAiB,KAAK,cAAc,GAGhE,GAFkC,CAACjC,EAAW,SAAUA,EAAW,YAAaA,EAAW,kBAAmBA,EAAW,kBAAmBA,EAAW,kBAAkB,EAEzJ,QAAQ2E,EAAO,MAAM,IAAM,IAAOA,EAAO,SAAW3E,EAAW,UAAY,CAAC2E,EAAO,OAAS,CACxGrD,EAAS,SAASqD,EAAQ1C,CAAc,EACxC,KAAK,QAAQ,EACb,MACJ,CAEA,GAAI0C,EAAO,SAAW3E,EAAW,SAAW,CAAC2E,EAAO,QAAU,KAAK,eAAe,GAAI,CAClFrD,EAAS,SAASqD,EAAQ1C,CAAc,EACxC,KAAK,QAAQ,EACb,MACJ,CAEA,GAAI0C,EAAO,SAAW3E,EAAW,QAAU,CAAC2E,EAAO,OAAQ,CACvDrD,EAAS,SAASqD,EAAQ1C,CAAc,EACxC,KAAK,QAAQ,EACb,MACJ,CAQA,GANI,KAAK,6BAA+B,OACpC,OAAO,cAAc,KAAK,0BAA0B,EACpD,KAAK,2BAA6B,OAIjC0C,EAAO,SAAW3E,EAAW,eAAiB2E,EAAO,SAAW3E,EAAW,YAAclB,EAAa,UAAY,CAAC,KAAK,cAAe,CAExI,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,MACJ,CAGA,GAAI6F,EAAO,SAAW3E,EAAW,MAAQ,CAAC2E,EAAO,OAAQ,CACrD,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,MACJ,CAEA,KAAK,OAAS,QACd,KAAK,kBAAoBxF,EAAiB,OAC1C,KAAK,kBAAkB,EAEvB,KAAK,oBAAoB,EACzB,MAAM,KAAK,qBAAqB,EAChC,KAAK,mCAAmC,EACxC,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,KAAK,QAAQ,EAElBM,EAAO,QAAQ,EACfC,GAAe,QAAQ,EACvB,KAAK,cAAgB,KACrB,KAAK,wBAA0B,CAAC,EAChCZ,EAAa,SAAW,KACxBA,EAAa,eAAiB,GAE9BwC,EAAS,SAASqD,GAAU,IAAI3D,EAAahB,EAAW,aAAa,EAAGiC,CAAc,CAC1F,CAEA,MAAM,SAAU,CACZ,IAAMA,EAAiB,KAAK,eAAiB,KAAK,cAAc,GAEhEzC,EAAM,MAAM,uBAAwB,CAAE,eAAAyC,CAAe,CAAC,EAElD,KAAK,6BAA+B,OACpC,OAAO,cAAc,KAAK,0BAA0B,EACpD,KAAK,2BAA6B,MAGtC,KAAK,OAAS,QACd,KAAK,kBAAoB9C,EAAiB,OAE1C,KAAK,oBAAoB,EACzB,MAAM,KAAK,qBAAqB,EAChC,KAAK,mCAAmC,EACxC,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,KAAK,QAAQ,EAElB,KAAK,kBAAkB,EAEvBM,EAAO,QAAQ,EACfC,GAAe,QAAQ,EACvB,KAAK,cAAgB,KACrB,KAAK,wBAA0B,CAAC,EAChCZ,EAAa,SAAW,KACxBA,EAAa,eAAiB,EAClC,CAEA,MAAc,uBAAuBmD,EAAqD,CACtF,IAAM4C,EAA6B,MAAM,KAAK,KAAK,sBAAsB5C,CAAc,EACvFzC,EAAM,MAAM,4BAA6BqF,CAAM,EAE/C,IAAMW,EAA0B,CAAC,EAC3B,CAAE,YAAAC,EAAa,YAAAC,CAAY,EAAIb,EAKrC,GAHIa,GACAF,EAAW,KAAKE,CAAW,EAE3BD,GAAeA,EAAY,KAAM,CAEjC,IAAME,EAAOF,EAAY,KAAK,OAAO,CAACG,EAAMC,EAAOC,IAAQA,EAAI,QAAQF,CAAI,IAAMC,CAAK,EAOtFF,EAAK,KAAK,GAAGA,EAAKA,EAAK,OAAS,CAAC,CAAC,gBAAgB,EAGlDH,EAAW,KAAK,CACZ,KAAAG,EACA,SAAUF,EAAY,SACtB,WAAYA,EAAY,UAC5B,CAAC,CACL,CAEA,OAAAxF,EAAO,WAAauF,EACpBvF,EAAO,QAAU4E,EAAO,SACpBA,EAAO,cACP5E,EAAO,QAAU4E,EAAO,aAE5B5E,EAAO,SAAW4E,EAAO,MAErBA,EAAO,cACP5E,EAAO,WAAa4E,EAAO,aAG3BA,EAAO,qBACP5E,EAAO,iBAAmB4E,EAAO,oBAG9BA,CACX,CACQ,uBAAuB,CAAE,YAAAY,EAAa,YAAAC,EAAa,SAAAK,EAAU,YAAAC,EAAa,MAAAC,EAAO,YAAAC,CAAY,EAAuB,CACxH,IAAMV,EAA0B,CAAC,EAKjC,GAHIE,GACAF,EAAW,KAAKE,CAAW,EAE3BD,GAAeA,EAAY,KAAM,CAEjC,IAAME,EAAOF,EAAY,KAAK,OAAO,CAACG,EAAMC,EAAOC,IAAQA,EAAI,QAAQF,CAAI,IAAMC,CAAK,EAOtFF,EAAK,KAAK,GAAGA,EAAKA,EAAK,OAAS,CAAC,CAAC,gBAAgB,EAGlDH,EAAW,KAAK,CACZ,KAAAG,EACA,SAAUF,EAAY,SACtB,WAAYA,EAAY,UAC5B,CAAC,CACL,CAEAxF,EAAO,WAAauF,EACpBvF,EAAO,QAAU8F,EACjB9F,EAAO,SAAWgG,EAEdD,IACA/F,EAAO,QAAU+F,GAGjBE,IACAjG,EAAO,WAAaiG,EAE5B,CAEQ,wBAAwBH,EAAkBlB,EAAoC,CAClF,OAAIA,EAAO,YACPkB,GAAY,YAAYlB,EAAO,SAAS,IAExCA,EAAO,aACPkB,GAAY,aAAalB,EAAO,UAAU,IAE1CA,EAAO,SACPkB,GAAY,UAAUlB,EAAO,MAAM,IAEnCA,EAAO,UACPkB,GAAY,WAAWlB,EAAO,OAAO,IAElCkB,CACX,CAKA,MAAc,mBAAmB,CAC7B,YAAAzF,EACA,aAAAC,EACA,UAAA4F,EACA,aAAA3F,EACA,QAAAC,EAAU,GACV,eAAAC,EAAiB,GACjB,kBAAAC,EAAoB,GACpB,uBAAAC,EACA,YAAAC,EACA,YAAAI,EACA,YAAAH,CACJ,EAAkE,CAC9DsF,GAAW,QAAQlG,EAAK,mBAAmB,EAC3C,IAAM+B,EAAiB5C,EAAM,KAAK,EAElCG,EAAM,MAAM,sBAAuB,CAAE,eAAAyC,EAAgB,YAAA3B,EAAa,aAAAC,EAAc,UAAA4F,CAAU,CAAC,EAE3F,IAAME,EAAU7F,EAAa,SAAS8F,GAAY,KAAK,EACnDC,EACJ,GAAIzF,EAAa,CACb,IAAM+D,GAAyB,CAC3B,SAAU,KAAK,KAAK,SAAS,EAC7B,WAAY5E,EAAO,WACnB,aAAcA,EAAO,OACrB,SAAUA,EAAO,SACjB,gBAAiBA,EAAO,gBACxB,SAAUA,EAAO,OACjB,aAAcuG,GAAsB,SAAS,CACjD,EAEMC,GAAiB,KAAK,UAAU5B,EAAM,EACxC6B,GACJ,GAAI,CAWA,GAVAA,GAAoB,MAAM5F,EAAY,CAClC,eAAA2F,GACA,eAAAxE,EACA,YAAApB,EACA,aAAAN,EACA,aAAAC,EACA,QAAA6F,EACA,eAAA3F,EACA,kBAAAC,CACJ,CAAC,EACG,CAAC+F,GAAkB,qBACnB,MAAM,IAAI1F,EAAahB,EAAW,iBAAkB,CAChD,QAAS,KAAK,UAAU0G,EAAiB,CAC7C,CAAC,CAET,OAASC,EAAK,CACV,MAAIA,aAAe,MACT,IAAI3F,EAAahB,EAAW,iBAAkB,CAAE,QAAS2G,EAAI,OAAQ,CAAC,EAEtE,IAAI3F,EAAahB,EAAW,iBAAkB,CAAE,QAAS,OAAO2G,CAAG,CAAE,CAAC,CAEpF,CAEA,GAAI,CACA,IAAMC,EAA6C,KAAK,MAAMF,GAAkB,oBAAoB,EAEpGH,EAAe,CACX,SAAUK,EAAqB,SAC/B,YAAaA,EAAqB,WAClC,GAAI3E,EACJ,cAAe2E,EAAqB,aACpC,YAAaA,EAAqB,WAClC,sBAAuBF,GAAkB,sBAAsB,IAAKG,KAAQ,CAAE,GAAGA,GAAI,OAAQA,GAAG,MAAqB,EAAE,EACvH,YAAaD,EAAqB,KAClC,YAAaA,EAAqB,KAClC,MAAO,IAAI,IAAIA,EAAqB,QAAQ,EAAE,aAAa,IAAI,OAAO,GAAK,EAC/E,EACApH,EAAM,MAAM,YAAa+G,CAAY,CACzC,MAAgB,CACZ,MAAM,IAAIvF,EAAahB,EAAW,cAAe,CAC7C,QAAS,8BACb,CAAC,CACL,CACJ,MACIuG,EAAe,MAAM,KAAK,KAAK,kBAC3BtE,EACA3B,EACAC,EACA8F,EACA5F,EACAC,EACAC,EACA,CAAE,uBAAAC,CAAuB,EACzBC,CACJ,EACArB,EAAM,MAAM,wBAAyB+G,CAAY,EAGrD,KAAK,uBAAuBA,CAAY,EAExC,IAAMnF,EAAa,MAAM,KAAK,kBAAkB0F,GAAwB,MAAOP,CAAY,EAE3F,aAAM,KAAK,iBAAiBA,EAAcnF,EAAY+E,CAAS,EAC/D,KAAK,mBAAmBlF,EAAaI,GAAc,QAAQ,EACpDD,CACX,CAKA,MAAc,kBACVI,EAQAP,EACoC,CACpCmF,GAAW,QAAQlG,EAAK,mBAAmB,EAC3C,GAAM,CAAE,eAAA+B,EAAgB,aAAAzB,EAAc,OAAAuG,EAAQ,SAAAC,EAAU,YAAAC,EAAa,QAAAxG,CAAQ,EAAIe,EACjFhC,EAAM,MAAM,qBAAsB,CAAE,eAAAyC,EAAgB,SAAA+E,EAAU,YAAAC,CAAY,CAAC,EAE3E,IAAMZ,EAAU7F,EAAa,SAAS8F,GAAY,KAAK,EACnDC,EACJ,GAAItE,EACAsE,EAAe,MAAM,KAAK,KAAK,iBAAiBtE,EAAgBoE,EAASU,CAAM,UACxEC,EACPT,EAAe,MAAM,KAAK,KAAK,uBAAuBS,EAAUX,EAASY,EAAaxG,CAAO,MAE7F,OAAM,IAAIO,EAAahB,EAAW,aAAa,EAGnDR,EAAM,MAAM,uBAAwB+G,CAAY,EAEhD,KAAK,uBAAuBA,CAAY,EAExC,IAAMnF,EAAa,MAAM,KAAK,kBAAkB0F,GAAwB,KAAMP,CAAY,EAE1F,aAAM,KAAK,iBAAiBA,EAAcnF,EAAYC,GAAc,OAAO,EAC3E,KAAK,mBAAmBJ,EAAaI,GAAc,OAAO,EACnDD,CACX,CAKA,MAAc,qBACVa,EACAC,EAAiBC,GAAS,KAC1BC,EACA8E,EACA5E,EACoC,CACpC8D,GAAW,QAAQlG,EAAK,mBAAmB,EAC3CV,EAAM,MAAM,qBAAsB,CAAE,eAAAyC,EAAgB,KAAAC,EAAM,OAAAE,CAAO,CAAC,EAElE,IAAM+E,EAAS,KAAK,KAAK,UAAU,EACnC,GAAI,CAACA,EACD,MAAM,IAAInG,EAAahB,EAAW,aAAa,EAGnD,IAAIoH,EAAY,EACZrB,EAAW,GACXsB,EAAa,GAEXd,EAAqC,CACvC,GAAItE,EACJ,OAAAG,EACA,SAAA2D,EACA,YAAasB,EACb,cAAe,GACf,cAAe,GACf,WAAY,EACZ,MAAO,EACX,EAEA,GAAIH,EAA4B,CAC5B,IAAMrC,EAAS,KAAK,kCAAkCqC,CAA0B,EAChF,KAAK,uBAAuBrC,CAAM,EAClCkB,EAAWzD,GAAc,GAAGrC,EAAO,OAAO,WAAWkH,CAAM,eAAejF,CAAI,cAAckF,CAAS,mBAAmBnF,CAAc,UAAUhC,EAAO,QAAQ,GAE/JsG,EAAa,MAAQ1B,EAAO,MAC5B0B,EAAa,SAAWR,EAEpB9F,EAAO,UACPoH,EAAa,GAAGpH,EAAO,OAAO,WAAWkH,CAAM,eAAejF,CAAI,cAAckF,CAAS,mBAAmBnF,CAAc,UAAUhC,EAAO,QAAQ,GACnJsG,EAAa,YAAcc,EAEnC,KAAO,CACH,IAAMxC,EAAS,MAAM,KAAK,uBAAuB5C,CAAc,EAC/DmF,EAAYvC,EAAO,YAAc,EACjCkB,EAAWzD,GAAc,GAAGrC,EAAO,OAAO,WAAWkH,CAAM,eAAejF,CAAI,cAAckF,CAAS,mBAAmBnF,CAAc,UAAUhC,EAAO,QAAQ,GAC/J8F,EAAW,KAAK,wBAAwBA,EAAUlB,CAAM,EAExD0B,EAAa,MAAQ1B,EAAO,MAC5B0B,EAAa,SAAWR,EACxBQ,EAAa,WAAaa,EAEtBnH,EAAO,UACPoH,EAAa,GAAGpH,EAAO,OAAO,WAAWkH,CAAM,eAAejF,CAAI,cAAckF,CAAS,mBAAmBnF,CAAc,UAAUhC,EAAO,QAAQ,GACnJoH,EAAa,KAAK,wBAAwBA,EAAYxC,CAAM,EAC5D0B,EAAa,YAAcc,EAEnC,CAEA,IAAMjG,EAAa,MAAM,KAAK,kBAAkB0F,GAAwB,OAAQP,CAAY,EAE5F,OACIzH,EAAa,WACZA,EAAa,SAAS,oBAAsBK,EAAiB,UAAYL,EAAa,SAAS,oBAAsBK,EAAiB,SAEvIK,EAAM,IAAI,sBAAsB,EAChCC,EAAO,IAAIsB,EAAQ,KAAM,MAAM,EAC3B,KAAK,WAAW,OAChB,KAAK,WAAW,OAAOf,EAAW,IAAI,EAEnC,QAAQ,OAAO,IAAIgB,EAAahB,EAAW,IAAI,CAAC,IAGvDlB,EAAa,WACbA,EAAa,SAAS,QAAQ,EAC9BA,EAAa,SAAW,MAG5B,MAAM,KAAK,iBAAiByH,EAAcnF,EAAYC,GAAc,SAAUa,CAAI,EAC3Ed,EACX,CAEA,MAAc,mBAAmBkG,EAAkCC,EAAsD,CACrH,IAAM/E,EAA2B,OAAO,OACpC,CACI,GAAI,KACJ,WAAY,KACZ,cAAegF,GAAgC,EAC/C,iBAAkB,CAAC,EACnB,MAAOrI,EAAiB,OACxB,OAAQ,KACR,aAAc,KACd,YAAa,KACb,SAAU,KACV,WAAY,KACZ,MAAO,CAAC,EACR,cAAe,EACf,qBAAsB,CAAC,EACvB,WAAY,CAAC,EACb,cAAe,CAAC,EAChB,YAAa,CAAC,EACd,SAAU,GACV,QAAS,IACb,EACAmI,CACJ,EAEA,OAAK9E,EAAY,aACbA,EAAY,WAAa,MAAM,KAAK,kBAAkB+E,GAAgB/E,EAAY,EAAE,GAGxF,KAAK,KAAK,gBAAgB+E,GAAgB/E,EAAY,GAAIA,EAAY,UAAU,EAE5E+E,GACA,KAAK,KAAK,gBAAgBA,EAAc/E,EAAY,EAAE,EAGtDA,EAAY,aAAa,SACzBA,EAAY,WAAW,SAAW,IAGlC8E,EAAW,UACX9E,EAAY,QAAU,KAAK,oBAAoBA,EAAY,GAAI8E,EAAW,OAAO,GAE9E9E,CACX,CAEA,MAAc,kBAAkBkC,EAA8D,CAC1F,GAAI,CACA,OAAO,MAAM,KAAK,KAAK,OAAOA,CAAa,CAC/C,OAASnF,EAAQ,CACb,WAAK,OAAO,IAAIyB,EAAahB,EAAW,aAAa,EAAGT,CAAC,EACnDA,CACV,CACJ,CAEA,MAAc,iBAAiBgH,EAAoCnF,EAAyC+E,EAA0BjE,EAAiBC,GAAS,KAAM,CAClK,GAAM,CAAE,aAAAU,CAAa,EAAIzB,EAAW,aAEpCyB,EAAa,QAAS4E,GAAM,CACxB,IAAMC,EAAarI,EAAM,UAAUoI,CAAC,EAC9BE,EAAa5C,EAAgB,yBAAyB0C,EAAG,EAAK,EACpE,GAAIE,EAAY,CACZ,KAAK,KAAK,gBAAgBD,EAAYC,CAAU,EAEhD,IAAMC,EAAuBvI,EAAM,oBAAoBoI,CAAC,EAClDI,EAAuB9C,EAAgB,yBAAyB0C,CAAC,EACnEG,GAAwBC,IACxB,KAAK,KAAK,gBAAgBD,EAAsBC,CAAoB,EACpE,KAAK,KAAK,gBAAgBJ,EAAE,iBAAqCA,EAAE,EAAE,EAE7E,CACJ,CAAC,EAED,IAAIN,EAAS,KAAK,KAAK,UAAU,EAC3BxF,EAAmB,KAAK,uCAAuCP,CAAU,EAC3EgG,EAAYb,EAAa,YAAc,EAI3C,GAAI,CAACY,EAAQ,CACT,GAAI,CAACxF,EACD,MAAM,IAAIX,EAAahB,EAAW,aAAa,EAEnDmH,EAAS,OAAOxF,EAAiB,EAAE,EAC/BA,EAAiB,SACjBO,EAAOP,EAAiB,QAExBA,EAAiB,YACjByF,EAAYzF,EAAiB,WAEjC,KAAK,KAAK,UAAUwF,CAAM,CAC9B,CAEA,IAAMW,EAAkBzI,EAAM,qBAAqB8H,EAAQjF,EAAMkF,CAAS,EAE1E,KAAK,cAAgB,CACjB,OAAAD,EACA,gBAAAW,EACA,WAAa,MAAM,KAAK,8BAA8BA,CAAe,EACrE,WAAY1G,EAAW,aAAa,WACpC,SAAUA,EAAW,aAAa,UAAY,CAAC,EAC/C,gBAAiBA,EAAW,aAAa,gBACzC,GAAIA,EAAW,aAAa,IAAMmF,EAAa,GAC/C,kBAAmBnF,EAAW,aAAa,mBAAqB,GAChE,SAAUA,EAAW,aAAa,UAAY,SAC9C,UAAA+E,EACA,WAAY/E,EAAW,cAAgBmF,EAAa,eAAiB,GACrE,SAAU,GACV,OAAQnF,EAAW,aAAa,YAChC,MAAOO,GAAkB,OAAS,CAAC,EACnC,kBAAmB,IAAI,IACvB,cAAe,IAAI,IACnB,WAAY,IAAI,IAChB,mBAAoB,CAAC,EACrB,SAAU4E,EAAa,WAAanF,EAAW,aAAa,SAC5D,0BAA2B,IAAI,IAC/B,eAAgBA,EAAW,eAC3B,QAAS,CAAC,EACV,cAAe,EACf,YAAa,KAAK,iBAAiBA,CAAU,EAC7C,aAAc,KAAK,gBAAgBA,CAAU,EAC7C,SAAU,GACV,QAASA,EAAW,aAAa,SAAW,KAC5C,OAAQA,EAAW,OAAO,QAAU,KACpC,aAAc,KAAK,gBAAgBA,CAAU,EAC7C,WAAY,KAAK,cAAcA,CAAU,EACzC,qBAAsB,IAAI,GAC9B,EAEAF,GAAwB,eAAiBE,EAAW,aAAa,IAAMmF,EAAa,GAEpF,KAAK,WAAW,kBAAkB,KAAK,cAAc,EAAE,EAEnDA,EAAa,gBAEbtG,EAAO,iBAAmBsG,EAAa,eAE3C9G,EAAO,IAAIsB,EAAQ,aAAcd,EAAO,iBAAmB,IAAM,GAAG,EAEpE,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,CACrB,CAEQ,oBAAoBmB,EAAuD,CAC/E,GAAI,CAAC,KAAK,cACN,MAAM,IAAIJ,EAAahB,EAAW,aAAa,EAGnD,KAAK,cAAc,WAAaoB,EAAW,aAAa,WACxD,KAAK,cAAc,SAAWA,EAAW,aAAa,UAAY,CAAC,EACnE,KAAK,cAAc,gBAAkBA,EAAW,aAAa,gBAC7D,KAAK,cAAc,kBAAoBA,EAAW,aAAa,mBAAqB,GACpF,KAAK,cAAc,SAAWA,EAAW,aAAa,UAAY,SAClE,KAAK,cAAc,WAAaA,EAAW,cAAgB,GAC3D,KAAK,cAAc,OAASA,EAAW,aAAa,YACpD,KAAK,cAAc,eAAiBA,EAAW,eAC/C,KAAK,cAAc,YAAc,GACjC,KAAK,cAAc,aAAe,GAClC,KAAK,cAAc,WAAa,EACpC,CAEQ,oBAAkC,CACtC,IAAM2G,EAAc,IAAIC,GAExB,YAAK,UAAUD,mBAA8C,KAAK,2BAA2B,KAAK,IAAI,CAAC,EACvG,KAAK,UAAUA,kBAA6C,KAAK,uBAAuB,KAAK,IAAI,CAAC,EAClG,KAAK,UAAY,IAAIE,GAASF,CAAW,EAElCA,CACX,CAEA,MAAc,kBAAkB7F,EAA+BqE,EAA0E,CACrI,KAAK,WAAW,YAAYA,EAAa,QAAQ,EACjD,KAAK,WAAW,wBAAwBA,EAAa,YAAcA,EAAa,YAAc,IAAI,EAElG,KAAK,UAAU,KAAK,WAAY2B,GAAe,aAAepD,GAA8B,KAAK,gBAAgB,IAAIA,CAAO,CAAC,EAC7H,KAAK,UAAU,KAAK,WAAYoD,GAAe,OAAQ,KAAK,mBAAmB,KAAK,IAAI,CAAC,EACzF,KAAK,UAAU,KAAK,WAAYA,GAAe,UAAW,KAAK,sBAAsB,KAAK,IAAI,CAAC,EAG/F,IAAM9G,EAAa,MAAM,KAAK,WAAW,QAAQc,EAAMqE,CAAY,EACnE,OAAA7G,GAAe,gBAAgB,CAAE,KAAMQ,EAAK,mBAAoB,CAAC,EAE1DkB,CACX,CAEA,MAAc,mBAAmBA,EAA+E,CAE5G,MAAM,KAAK,gCAAgCA,CAAU,EACrD,KAAK,cAAcA,CAAU,EAC7B,KAAK,mBAAmBA,CAAU,EAClC,KAAK,oBAAoBA,CAAU,EACnC,KAAK,kBAAkBA,EAAW,aAAa,OAAO,EAClDA,EAAW,UAAYA,EAAW,SAAS,YAC3C,KAAK,mBAAmB+G,GAAkB,SAAU/G,EAAW,SAAS,WAAYA,EAAW,SAAS,kBAAmB,KAAM,IAAI,CAE7I,CAEA,MAAc,oCAAoCA,EAAqG,CACnJ,IAAMgH,EAAQhH,EAAW,aACrBgH,GACA9G,EAAS,mCAAmC,MAAM,KAAK,qCAAqC,KAAK,4BAA4B8G,CAAK,CAAC,CAAC,CAE5I,CAEQ,4BAA4BA,EAA+F,CAG/H,MAAO,CACH,GAHa,CAAE,aAAc,CAAC,EAAG,YAAa,EAAG,WAAY,EAAG,YAAa,EAAM,EAInF,GAAGA,CACP,CACJ,CAEA,MAAc,qCAAqCA,EAAqF,CACpI,IAAM9D,EAAqB,MAAM,KAAK,iBAAiB,EAEjD+D,EAAuBhJ,EAAM,sBAC/B+I,EAAM,aAAa,OAAsB,CAAC7E,EAAKkB,IAAqB,CAChE,IAAMC,EAAgBrF,EAAM,UAAUoF,CAAgB,EAEtD,OAAIH,EAAmBI,CAAa,GAChCnB,EAAI,KAAKe,EAAmBI,CAAa,CAAC,EAGvCnB,CACX,EAAG,CAAC,CAAC,CACT,EACA,MAAO,CACH,GAAG6E,EACH,aAAcC,CAClB,CACJ,CAEA,MAAc,gCAAgCjH,EAA+E,CACzH,MAAM,KAAK,sBAAsBA,EAAW,aAAa,YAAY,EAEjEA,EAAW,cAAc,cACzB,MAAM,KAAK,sBAAsBA,EAAW,cAAc,YAAY,EAG1E,IAAMM,EAAiCN,GAAY,OAAO,OAAS,CAAC,EACpE,QAAWU,KAAQJ,EACf,MAAM,KAAK,sBAAsBI,GAAM,cAAc,cAAgB,CAAC,EAAG,EAAI,CAErF,CAEA,MAAc,sBAAsBe,EAA8CyF,EAAW,GAAO,CAChG,GAAI,CAAC,KAAK,cACN,OAGJ,IAAMC,EAAmB1F,EAAa,CAAC,GAAG,YAAY,KAElD0F,IACAtI,EAAO,iBAAmBsI,GAG9B,IAAMjE,EAAqB,MAAM,KAAK,iBAAiB,EAEvD,QAAW9B,KAAeK,EAAc,CACpC,IAAM6B,EAAgBrF,EAAM,UAAUmD,CAAW,EAKjD,GAHAhD,EAAM,KAAK,mCAAoCkF,CAAa,EAGxD,KAAK,MAAMA,CAAa,EAAG,CAC3B,KAAK,cAAc,MAAQlC,EAAY,OAAS,CAAC,EAC7C,KAAK,cAAc,MAAM,SACzBhD,EAAM,MAAM,wBAAwBgD,EAAY,KAAK,EAAE,EACvDlB,EAAS,oBAAoB,KAAK,cAAc,MAAO,EAAI,GAI/D,KAAK,mCAAmCkB,CAAW,EACnD,QACJ,CAEA,GAAIA,EAAY,QAAUrD,EAAiB,QAAUqD,EAAY,QAAUrD,EAAiB,SAAU,CAC9FmF,EAAmB9B,EAAY,EAAE,GACjC,MAAM,KAAK,mBAAmB8B,EAAmB9B,EAAY,EAAE,EAAGxC,EAAW,MAAM,EAEvF,QACJ,CAEA,IAAMuH,EAAelI,EAAM,oBAAoBmD,CAAW,EAC1D,KAAK,qBACD,CACI,GAAIkC,EACJ,WAAYK,EAAgB,yBAAyBvC,CAAW,EAChE,cAAegF,GAAgChF,EAAY,aAAa,EACxE,iBAAkBnD,EAAM,oBAAoBmD,CAAW,EACvD,MAAOA,EAAY,MACnB,MAAOA,EAAY,OAAS,CAAC,EAC7B,iBACA,WAAYA,EAAY,YAAc,CAAC,EACvC,cAAeA,EAAY,eAAiB,CAAC,EAC7C,YAAaA,EAAY,aAAe,CAAC,EACzC,QAAS,KAAK,oBAAoBkC,EAAelC,EAAY,OAAO,EACpE,gBAAiBA,EAAY,gBAC7B,SAAA8F,CACJ,EACAf,CACJ,EAIA,IAAMiB,EAAoB,MAAM,KAAK,gBAAgB9D,CAAa,EAC9D8D,GAAqBhG,EAAY,OAASA,EAAY,MAAM,SAC5DhD,EAAM,MAAM,0BAA0BkF,CAAa,cAAclC,EAAY,KAAK,EAAE,EACpFlB,EAAS,eAAekH,EAAkB,WAAYhG,EAAY,MAAO,EAAI,EAErF,CACJ,CAGQ,mCAAmC,CAAE,WAAA2B,EAAY,cAAAsE,CAAc,EAAuE,CAC1I,GAAI,CAACtE,EACD,OAGJ,IAAMuE,EAAW,SAAY,CAEzB,IAAMC,EAAmBC,GAA2BzE,EAAY0E,GAAU,IAAI,EACxEC,EAA4BF,GAA2BzE,EAAY0E,GAAU,cAAc,EAEjG,QAAWrI,IAAgB,CAACmI,EAAkBG,CAAyB,EAC9DtI,EAAa,QAGlB,MAAM,KAAK,mBAAmB,CAAE,WAAA2D,EAAY,cAAAsE,EAAe,aAAAjI,EAAc,aAAc,EAAK,CAAC,CAErG,EAGAnB,EAAM,aAAa,IAAMqJ,EAAS,EAAE,MAAOnJ,GAAMC,EAAM,MAAMD,CAAC,CAAC,CAAC,CACpE,CAEQ,2BAA2BwJ,EAAiD,CAChF,IAAIC,EAAS,KACb,OAAID,IAAU,YACVC,EAAS,YACFD,IAAU,cAA6BA,IAAU,SACxDC,EAAS,aACFD,IAAU,iBACjBC,EAAS,aAENA,CACX,CAEQ,4BAA4BxG,EAAuC,CACvE,YAAK,cAAcA,EAAY,EAAE,EAAIA,EAC9BA,CACX,CAEA,MAAc,mCAAmCkC,EAAoD,CAEjG,IAAMlC,GADqB,MAAM,KAAK,iBAAiB,GAChBkC,CAAa,EAEpD,GAAIlC,EACA,OAAOA,EAGX,IAAMyG,EAAiB,KAAK,KAAK,2BAA2B5J,EAAM,YAAYqF,CAAa,EAAE,EAAE,EACzF6C,EAAe0B,EAAiB5J,EAAM,cAAc4J,CAAc,EAAI,OAC5E,OAAO,KAAK,mBAAmB,CAAE,GAAIvE,CAAc,EAAG6C,CAAY,CACtE,CAEA,MAAc,8BAA8B7C,EAA0E,CAClH,GAAI,KAAK,MAAMA,CAAa,EACxB,OAAO,KAAK,eAAe,WAG/B,GAAIzE,EAAO,wBACP,OAAQ,MAAM,KAAK,mCAAmCyE,CAAa,GAAG,WAG1E,IAAMJ,EAAqB,MAAM,KAAK,iBAAiB,EAEvD,GAAIA,EAAmBI,CAAa,GAAG,WACnC,OAAOJ,EAAmBI,CAAa,EAAE,WACtC,CAEH,IAAMiD,EAAa,MAAM,KAAK,kBAAkBjD,CAAa,EAC7D,YAAK,KAAK,gBAAgBA,EAAeiD,CAAU,EAC5CA,CACX,CACJ,CAEA,MAAc,gDAAgDjD,EAA8BwE,EAAoE,CAC5J,GAAIjJ,EAAO,wBAAyB,CAChC,IAAMuC,EAAc,KAAK,4BAA4B,MAAM,KAAK,mCAAmCkC,CAAa,CAAC,EAEjH,OAAAlC,EAAY,QAAU,KAAK,oBAAoBA,EAAY,GAAI0G,CAAO,EAE/D1G,CACX,CAIA,OAF2B,MAAM,KAAK,iBAAiB,GAE7BkC,CAAa,CAC3C,CAEQ,kCAAkCA,EAA8B,CACpElF,EAAM,KAAK,gBAAgBkF,CAAa,yBAAyB,CACrE,CAEQ,oBAAoBA,EAA8BwE,EAAyE,CAK/H,GAAI,CAACA,EACD,OAAO,KAGX,IAAMC,EAAa,OAAO,OAAOD,CAAO,EAAE,KAAME,GACrC,OAAQA,GAAS,SAAUA,CACrC,EAED,OAAO,OAAO,QAAQF,CAAO,EAAE,OAAO,CAACG,EAAiB,CAACC,EAAUF,CAAK,KACpEC,EAAgBC,CAA+B,EAAI,CAC/C,GAAGH,EACH,GAAGC,EACH,GAAI1E,CACR,EACO2E,GACR,CAAC,CAAmC,CAC3C,CAOQ,cAAcjI,EAA+E,CACjG,IAAMW,EAASX,EAAW,OAAO,QAAU,KAE3C,KAAK,gBAAgBW,EAAQ,EAAI,CACrC,CAGQ,mBAAmBX,EAA+EmI,EAAc,GAAO,CAC3H,IAAMC,EAAuBC,GAA4BrI,CAAU,EACnE,KAAK,wBAAwBoI,EAAsB,IAAY,EAE/D,QAAW1H,KAAQV,EAAW,OAAO,OAAS,CAAC,EAC3C,KAAK,wBAAwBU,EAAK,WAAYA,EAAK,EAAE,EAGzD,IAAIqC,EAAa,KAAK,6BAA6B,EAC/CoF,IACApF,EAAauF,GAAwCtI,EAAY+C,CAAU,GAE/E,IAAM3D,EAAe,OAAO,KAAK2D,CAAU,EACrCpC,EAAS,KAAK,eAAe,OAC/BvB,EAAa,QACb,KAAK,mBAAmB,CAAE,WAAA2D,EAAY,aAAA3D,EAAc,QAAS,GAAM,aAAc,GAAM,OAAAuB,CAAO,EAAGwH,CAAW,CAEpH,CAQQ,oBAAoBnI,EAA+E,CACvG,KAAK,cAAcA,EAAW,cAAc,YAAc,IAAI,EAE9D,QAAWU,KAAQV,EAAW,OAAO,OAAS,CAAC,EAC3C,KAAK,cAAcU,EAAK,YAAc,KAAMA,EAAK,EAAE,CAE3D,CAQA,MAAc,2BAA2BV,EAA+E,CAChHA,EAAW,aAAa,oBACxB,MAAM,KAAK,kBAAkBA,EAAW,aAAa,mBAAmB,EAExE,KAAK,eAAe,0BAA0B,OAAO,IAAI,EAG7D,QAAWU,KAAQV,EAAW,OAAO,OAAS,CAAC,EACvCU,EAAK,oBACL,MAAM,KAAK,kBAAkBA,EAAK,oBAAqB,GAAO,OAAWA,EAAK,EAAE,EAEhF,KAAK,eAAe,0BAA0B,OAAOA,EAAK,EAAE,CAGxE,CAEA,MAAc,oBAAqB,CAC/B,GAAI,CAAC,KAAK,eAAiB,CAAC,KAAK,aAC7B,OAGJ,KAAK,WAAa,IAAI6H,GAAU,KAAK,cAAc,SAAU,KAAK,WAAY,KAAK,aAAc,KAAK,eAAe,EACrH,KAAK,WAAa,IAAIC,GAEtB,KAAK,UAAU,KAAK,2BAA0C,KAAK,yBAAyB,KAAK,IAAI,CAAC,EACtG,KAAK,UAAU,KAAK,iCAAgD,KAAK,8BAA8B,KAAK,IAAI,CAAC,EACjH,KAAK,UAAU,KAAK,gCAA+C,KAAK,oBAAoB,KAAK,IAAI,CAAC,EACtG,KAAK,UAAU,KAAK,kCAAiD,KAAK,sBAAsB,KAAK,IAAI,CAAC,EAC1G,KAAK,UAAU,KAAK,6BAA4C,KAAK,iBAAiB,KAAK,IAAI,CAAC,EAChG,KAAK,UAAU,KAAK,+BAA8C,KAAK,mBAAmB,KAAK,IAAI,CAAC,EACpG,KAAK,UAAU,KAAK,4CAA2D,KAAK,wBAAwB,KAAK,IAAI,CAAC,EACtH,KAAK,UAAU,KAAK,8BAA6C,KAAK,mBAAmB,KAAK,IAAI,CAAC,EACnG,KAAK,UAAU,KAAK,4BAA2C,KAAK,iBAAiB,KAAK,IAAI,CAAC,EAC/F,KAAK,UAAU,KAAK,kCAAiD,KAAK,sBAAsB,KAAK,IAAI,CAAC,EAC1G,KAAK,UAAU,KAAK,oCAAmD,KAAK,wBAAwB,KAAK,IAAI,CAAC,EAC9G,KAAK,UAAU,KAAK,+BAA8C,KAAK,oBAAoB,KAAK,IAAI,CAAC,EACrG,KAAK,UAAU,KAAK,4BAA2C,KAAK,iBAAiB,KAAK,IAAI,CAAC,EAC/F,KAAK,UAAU,KAAK,2BAA0C,KAAK,gBAAgB,KAAK,IAAI,CAAC,EAE7F,IAAMxE,EAAW,KAAK,cAAc,YAAc/D,GAAc,UAAY,CAAC,KAAK,cAAc,WAE1FwI,EAAqB,MAAM,KAAK,iBAAiB,EACvD,QAAWrH,KAAe,OAAO,OAAOqH,CAAkB,GAClDrH,EAAY,QAAUrD,EAAiB,UAAYqD,EAAY,QAAUrD,EAAiB,SAC1F,KAAK,WAAW,SAASqD,EAAY,GAAI4C,CAAQ,CAG7D,CAEQ,wBAAyB,CACzB,KAAK,YAAc,KAAK,gBACxB,KAAK,iBAAmB,IAAI0E,GAAgB,KAAK,UAAU,EAC3D,KAAK,UAAU,KAAK,oCAAyD,KAAK,mBAAmB,KAAK,IAAI,CAAC,EAC/G,KAAK,iBAAmB,IAAIC,GAAgB,KAAK,iBAAkB,KAAK,WAAY,KAAK,cAAc,QAAQ,EAC/G,KAAK,UAAU,KAAK,mCAAwD,KAAK,kBAAkB,KAAK,IAAI,CAAC,EAE7G,KAAK,qBAAuB,IAAIC,GAAoB,KAAK,YAA2B,EAE5F,CAEA,MAAc,qBAAsB,CAC5B,KAAK,YAAc,KAAK,mBACxB,KAAK,cAAgB,IAAIC,GAAa,KAAK,WAAY,KAAK,iBAAkB,MAAM,KAAK,iBAAiB,CAAC,EAEnH,CAEQ,aAAc,CAClB,IAAMC,EAAeC,EAAY,WAAW,EAAE,OAC1CC,EAAmBD,EAAY,eAAe,EAAE,OACpD3K,EAAM,MACF,YACI0K,GACCC,EAAY,oBAAoB,EAAI,IAAM,KAC3C,kBACAC,GACCD,EAAY,wBAAwB,EAAI,IAAM,IACvD,EACA1K,EAAO,IAAIsB,EAAQ,QAAS,GAAGmJ,CAAY,IAAIE,CAAgB,EAAE,CACrE,CAEQ,sBAAsBC,EAAe/K,EAA+B,CACxEG,EAAO,IAAI4K,EAAM,CAAC/K,GAAe,gBAAkB,QAASA,GAAe,gBAAkB,OAAO,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,CAAC,CACnI,CAEA,MAAc,mBAAmBkD,EAA0BwG,EAAoB,CAC3E,GAAIxG,EAAY,QAAUrD,EAAiB,QAAUqD,EAAY,QAAUrD,EAAiB,UAAY,KAAK,SAAW,QACpH,OAGAqD,EAAY,KAAO,KAAK,gCACxB,KAAK,8BAAgC,MAGzC,IAAM8B,EAAqB,MAAM,KAAK,iBAAiB,EACvD,GAAKA,EAAmB9B,EAAY,EAAE,EAItC,CAAIwG,IAAWhJ,EAAW,OACtB,KAAK,uBAAuB,CAACwC,CAAW,UAA2B,EAEnE,KAAK,uBAAuB,CAACA,CAAW,UAA4BwG,CAAM,EAG9ExG,EAAY,aAAa,WAAW,EAIhC,KAAK,eAAiB,KAAK,cAAc,0BAA0B,IAAI,IAAI,IAAMA,EAAY,IAC7F,KAAK,cAAc,0BAA0B,OAAO,IAAI,EAExD,KAAK,eAAiB,KAAK,cAAc,QAAU,KAAK,cAAc,0BAA0B,IAAI,KAAK,cAAc,MAAM,IAAMA,EAAY,IAC/I,KAAK,cAAc,0BAA0B,OAAO,KAAK,cAAc,MAAM,EAIjF,OAAW,CAAC8H,EAAkBC,CAAO,IAAK,OAAO,QAAQ/H,EAAY,oBAAoB,EACrF,KAAK,6BAA6B,OAAO8H,CAAgB,EACzD,KAAK,mCAAmC,OAAOA,CAAgB,EAC/D,KAAK,sCAAsC,OAAOA,CAAgB,EAC9D,KAAK,oCAAoC,IAAIA,CAAgB,IAC7D,OAAO,aAAa,KAAK,oCAAoC,IAAIA,CAAgB,CAAC,EAClF,KAAK,oCAAoC,OAAOA,CAAgB,GAEpE,KAAK,yBAAyB,CAAE,CAACA,CAAgB,EAAG,CAAE,WAAY,EAAK,CAAE,EAAG,EAAK,EAGrF,KAAK,KAAK,kBAAkB9H,EAAY,EAAE,EAC1C,OAAO8B,EAAmB9B,EAAY,EAAE,EAExClB,EAAS,gBAAgBkB,EAAY,WAAYA,EAAY,OAAO,EACxE,CAEQ,mBAA0B,CAC9B,KAAK,YAAY,EACjB,OAAO,oBAAoB,SAAU,KAAK,SAAS,CACvD,CAEQ,qBAA4B,CAC5B,KAAK,eACL,KAAK,aAAa,QAAQ,EAC1B,KAAK,aAAe,KAE5B,CAEA,MAAc,sBAAsC,CAChD,OAAO,OAAO,MAAM,KAAK,iBAAiB,CAAC,EAAE,QAASA,GAAgB,CAClEA,EAAY,cAAc,UAAU,EAAE,QAASgI,GAAUA,EAAM,KAAK,CAAC,EACrEhI,EAAY,kBAAkB,KAAK,EACnCA,EAAY,cAAc,UAAU,EAAE,QAASgI,GAAUA,EAAM,KAAK,CAAC,EACrEhI,EAAY,aAAa,WAAW,CACxC,CAAC,EACD,KAAK,cAAgB,CAAC,EAElB,KAAK,cACL,KAAK,aAAa,QAAQ,CAElC,CAEQ,oCAAqC,CACzChD,EAAM,MAAM,0CAA0C,EAEtD,KAAK,kBAAkB,QAASiL,GAAW,CACvCA,EAAO,UAAU,EAAE,QAASD,GAAU,CAClCA,EAAM,KAAK,CACf,CAAC,CACL,CAAC,EACD,KAAK,kBAAoB,IAAI,IAE7B,KAAK,oCAAoC,QAASE,GAAU,CACxD,OAAO,aAAaA,CAAK,CAC7B,CAAC,EACD,KAAK,oCAAsC,IAAI,IAE/C,KAAK,6BAA+B,IAAI,IACxC,KAAK,mCAAqC,IAAI,IAC9C,KAAK,sCAAwC,IAAI,GACrD,CAEQ,mBAA0B,CAC1B,KAAK,aACL,KAAK,WAAW,QAAQ,EACxB,KAAK,WAAa,MAElB,KAAK,aACL,KAAK,WAAa,KAE1B,CAEQ,yBAAgC,CAChC,KAAK,mBACL,KAAK,iBAAiB,QAAQ,EAC9B,KAAK,iBAAmB,MAExB,KAAK,mBACL,KAAK,iBAAiB,QAAQ,EAC9B,KAAK,iBAAmB,MAExB,KAAK,uBACL,KAAK,qBAAqB,QAAQ,EAClC,KAAK,qBAAuB,KAEpC,CAEQ,sBAA6B,CAC7B,KAAK,gBACL,KAAK,cAAc,QAAQ,EAC3B,KAAK,cAAgB,KAE7B,CAEQ,mBAA0B,CAC9B,KAAK,WAAW,MAAM,EACtB,KAAK,WAAW,QAAQ,CAC5B,CAEA,MAAc,kBAAkBhG,EAA8BiG,EAA+CpJ,EAA0B,CACnI/B,EAAM,MAAM,wBAAwBkF,CAAa,GAAG,EACpD,IAAIlC,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAC1D,GAAIlC,IAAgBA,EAAY,QAAUrD,EAAiB,UAAYqD,EAAY,QAAUrD,EAAiB,QAAS,CACnHK,EAAM,KAAK,gBAAgBgD,EAAY,EAAE,IAAIA,EAAY,KAAK,8BAA8B,EAC5F,MACJ,CAEA,GAAI,CAACA,EAAa,CACd,IAAM+E,EAAelI,EAAM,oBAAoBsL,CAAe,EAE9D,KAAK,qBACD,CACI,GAAIjG,EACJ,WAAYK,EAAgB,yBAAyB4F,CAAe,EACpE,cAAenD,GAAgCmD,EAAgB,aAAa,EAC5E,MAAOA,EAAgB,MACvB,MAAOA,EAAgB,OAAS,CAAC,EACjC,WAAYA,EAAgB,YAAc,CAAC,EAC3C,cAAeA,EAAgB,eAAiB,CAAC,EACjD,YAAaA,EAAgB,aAAe,CAAC,CACjD,EACApD,CACJ,EACA/E,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,CAC1D,CAEA,KAAK,uBAAuB,CAAClC,CAAW,WAA4B,EAChEjB,GACAiB,EAAY,MAAQrD,EAAiB,OACrC,MAAM,KAAK,mBAAmBqD,EAAajB,CAAK,GACzC,KAAK,aACZiB,EAAY,MAAQrD,EAAiB,OACrC,KAAK,WAAW,SAASqD,EAAY,GAAI,EAAI,EAC7C/C,EAAO,IAAIsB,EAAQ,eAAe,EAClC,KAAK,oCAAoCyB,CAAW,EAE5D,CAEA,MAAc,qBAAqBsF,EAAiD,CAChFtI,EAAM,MAAM,uBAAuBsI,CAAe,GAAG,EAErD,IAAM8C,EAAqC,CAAC,EACtCtG,EAAqB,MAAM,KAAK,iBAAiB,EAEvD,QAAS8C,EAAY,EAAGA,GAAavI,GAAgBuI,IAAa,CAC9D,IAAM1C,EAAgBrF,EAAM,QAAQyI,EAAiBV,CAAS,EACxD5E,EAAc8B,EAAmBI,CAAa,EAChDlC,GACAoI,EAAoB,KAAKpI,CAAW,CAE5C,CAEA,GAAI,CAACoI,EAAoB,OAAQ,CAC7B,KAAK,kCAAkC9C,CAAe,EACtD,MACJ,CAEA,GAAI,KAAK,WACL,QAAW+C,KAAsBD,EAC7B,KAAK,WAAW,MAAMC,EAAmB,EAAE,EAInDpL,EAAO,IAAIsB,EAAQ,kBAAkB,CAGzC,CAEA,MAAM,aAAa+J,EAAuB,CACtC,OAAIA,IAAS,cACF,KAAK,aAAa,aAAa,EAC/B,KAAK,aACL,KAAK,aAAa,aAAaA,CAAI,EAEvC,QAAQ,OAAOC,GAAW,OAAO,CAC5C,CAEA,gBAAiB,CACb,OAAO,KAAK,cAAc,eAAe,CAC7C,CAEA,MAAM,sBAAsBC,EAAiC,CACzD,OAAI,KAAK,aACE,KAAK,aAAa,sBAAsBA,CAAQ,EAEpD,QAAQ,OAAOD,GAAW,OAAO,CAC5C,CAEA,MAAM,wBAAyB,CAC3B,OAAI,KAAK,aACE,KAAK,aAAa,uBAAuB,EAE7C,QAAQ,OAAOA,GAAW,OAAO,CAC5C,CAEA,uBAAuBhC,EAAgB,CAC/B,KAAK,cACL,KAAK,aAAa,uBAAuBA,CAAK,CAEtD,CAEA,cAEIkC,EAEAvG,EAAsC,KAEtCwG,EAA+B,KACjC,CACE,GAAI,CAAC,KAAK,YAAc,CAAC,KAAK,cAC1B,OAGJ,IAAMC,EAAO,CAACzG,EACR0G,EAAM1G,GAAiB,KAAK,cAAc,gBAEhD,GAAIuG,aAAe,YAAa,CAE5B,IAAM9D,EAAS+D,GAAiB,KAAK,cAAc,WAAW,GAE9D,KAAK,WAAW,cAAcE,EAAK,CAC/B,IAAAH,EACA,OAAA9D,EACA,KAAAgE,CACJ,CAAC,EACD,MACJ,CAEA,KAAK,WAAW,cAAcC,EAAK,CAAE,IAAAH,EAAK,KAAAE,CAAK,CAAC,CACpD,CAEA,eAAeE,EAAyB,CACpC,KAAK,YAAY,eAAeA,CAAI,CACxC,CAEA,MAAM,eAAeZ,EAAqBa,EAAW,GAAO,CACxD,GAAI,KAAK,aACL,OAAO,KAAK,aAAa,eAAeb,EAAQa,CAAQ,CAEhE,CAEA,MAAM,eAAeb,EAAqB,CACtC,GAAI,KAAK,aACL,OAAO,KAAK,aAAa,eAAeA,CAAM,CAEtD,CAEA,MAAM,iBAAiBc,EAAkB,CACrC,GAAI,KAAK,aACL,OAAA9L,EAAO,IAAIsB,EAAQ,aAAcwK,EAAU,UAAY,SAAS,EACzD,KAAK,aAAa,YAAYA,CAAO,CAEpD,CAEA,MAAM,iBAAiBA,EAAkB,CACrC,GAAI,KAAK,aACL,OAAA9L,EAAO,IAAIsB,EAAQ,aAAcwK,EAAU,UAAY,SAAS,EACzD,KAAK,aAAa,YAAYA,CAAO,CAEpD,CAKA,MAAM,iBAAiBC,EAAmC,CACtD,GAAIA,EAAW,OAAS,GAAK,CAAC,KAAK,WAAW,MAC1C,OAGJ,IAAMC,EAA6C,CAAC,EAC9CC,EAAmD,CAAC,EAE1D,QAAW9F,KAAQ4F,EAAY,CAC3B,IAAM7D,EAAa,OAAO/B,EAAK,KAAQ,SAAYA,EAAK,IAAgCb,EAAgB,OAAOa,EAAK,GAAG,EACjH+F,EAAgB5G,EAAgB,SAAS4C,CAAU,EACzD+D,EAAsBC,CAAa,EAAI/F,EAAK,QAChD,CAEA,IAAMtB,EAAqB,MAAM,KAAK,iBAAiB,EAEvD,QAAW9B,KAAe,OAAO,OAAO8B,CAAkB,EAAG,CACzD,IAAMqH,EAAgB5G,EAAgB,SAASvC,EAAY,UAAU,EACjE,OAAO,OAAOkJ,EAAuBC,CAAa,IAClDF,EAAgBjJ,EAAY,EAAE,EAAIkJ,EAAsBC,CAAa,EAE7E,CAEA,MAAM,KAAK,WAAW,iBAAiBF,CAAe,CAC1D,CAEA,MAAM,uBAAuB1C,EAA6BjB,EAAmC,CACzF,OAAW,CAAC8D,EAAKxC,CAAK,IAAK,OAAO,QAAQL,CAAK,EAC3C,GAAI6C,EAAI,OAAS,GAAKxC,EAAM,OAAS,EACjC,MAAM,IAAI,MAAM,kGAAkG,EAItHtB,GAAmB,CAAC,KAAK,aAAa,IAEtCA,EAAkB,QAGtB,MAAM,KAAK,WAAW,uBAAuBiB,EAAOjB,CAAe,CACvE,CAEA,MAAM,cAAe,CACjB,KAAK,gBAAgB,EACrB,MAAM,KAAK,WAAW,aAAa,CACvC,CAEA,MAAM,gBAAgB+D,EAA4D,CAC9E,IAAMC,EAA+D,CAAC,EACtE,OAAAA,EAAQC,GAAsCF,CAA4B,CAAC,EAAI,CAAE,kBAAmB,EAAK,EAClG,KAAK,WAAW,oBAAoBC,CAAO,CACtD,CAEA,MAAM,gBAAgBE,EAAyBC,EAAyB,CACpE,OAAO,KAAK,WAAW,gBAAgBD,EAAiBC,CAAe,CAC3E,CAEA,MAAM,oBAAoBH,EAA8B,CACpD,GAAIA,EAAQ,OAAS,GAAK,CAAC,KAAK,WAAW,MACvC,OAGJtM,EAAM,IAAI,kCAAkC,KAAK,WAAW,6BAA6B,CAAC,IAAKsM,CAAO,EAEtG,IAAMI,EAA+E,CAAC,EAChF5H,EAAqB,MAAM,KAAK,iBAAiB,EACvD,QAAW6H,KAAUL,EAAS,CAC1B,IAAMnE,EAAa,OAAOwE,EAAO,KAAQ,SAAYA,EAAO,IAAgCpH,EAAgB,OAAOoH,EAAO,GAAG,EAEvHzH,EAAgB,KAAK,KAAK,0BAA0BiD,CAAU,EACpE,GAAI,CAACjD,EAAe,CAChB,IAAMiH,EAAgB5G,EAAgB,SAAS4C,CAAU,EACzDnI,EAAM,IAAI,mCAAmCmM,CAAa,EAAE,EAC5D,QACJ,CAEA,IAAMrB,EAAmByB,GAAsC,CAAE,cAAArH,EAAe,UAAWyH,EAAO,UAAW,WAAYA,EAAO,UAAW,CAAC,EAEtI3J,EAAc8B,EAAmBI,CAAa,EAChDlC,EACAA,EAAY,qBAAqB8H,CAAgB,EAAI6B,EAC9C,KAAK,MAAMzH,CAAa,IAC/B,KAAK,wBAAwB4F,CAAgB,EAAI6B,GAGjDC,GAAgBD,CAAM,GAClB,KAAK,MAAMzH,CAAa,GACxB,OAAO,KAAK,wBAAwB4F,CAAgB,EAEpD,KAAK,6BAA6B,IAAIA,CAAgB,GAAK,CAAC,KAAK,sCAAsC,IAAIA,CAAgB,GAC3H,KAAK,sCAAsC,IAAIA,EAAkB,KAAK,IAAI,CAAC,IAG/E,KAAK,sCAAsC,OAAOA,CAAgB,EAE9D,CAAC,KAAK,6BAA6B,IAAIA,CAAgB,GAAKrK,EAAO,iBAAmB,GACtF,KAAK,6BAA6B,IAAIqK,EAAkB,IAAI,EAGhE4B,EAA0B5B,CAAgB,EAAI6B,GAG9CA,EAAO,YAAc,UAAoB,CAACC,GAAgBD,CAAM,GAChE/F,GAAW,QAAQA,GAAW,iCAAiC1B,CAAa,CAAC,CAErF,CAEA,IAAM2H,EAAmB,KAAK,sCAAsC,KAAK,EACzE,KAAO,KAAK,6BAA6B,KAAOpM,EAAO,kBAAkB,CACrE,IAAMqM,EAAkBD,EAAiB,KAAK,EAC9C,GAAIC,EAAgB,KAAM,CACtB9M,EAAM,MACF,+DAEIS,EAAO,iBACP,wBACA,MAAM,KAAK,KAAK,6BAA6B,KAAK,CAAC,CAC3D,EACA,KACJ,CAEA,MAAM,KAAK,eAAeqM,EAAgB,KAAK,EAC/CJ,EAA0BI,EAAgB,KAAK,EAAI,CAAE,WAAY,EAAK,CAC1E,CAEI,KAAK,YAAY,YAAY,IAAM,UAIvC,MAAM,KAAK,yBAAyBJ,CAAyB,CACjE,CAEA,MAAM,SAASN,EAAa,CACxB,OAAO,KAAK,WAAW,SAASA,CAAG,CACvC,CAEA,kBAAkBW,EAAsB5H,EAAiB6H,EAA8B,CACnF,GAAK,KAAK,cAIV,GAAI,CAACvM,EAAO,2BACR,KAAK,KAAK,sBAAsB,KAAK,cAAc,GAAIsM,EAAc5H,EAAQ6H,CAAmB,MAC7F,CACH,IAAMvH,EAAO,CACT,WAAY/E,EAAK,uBACjB,cAAeqM,CACnB,EAEI5H,IAAW,SACXM,EAAK,OAASN,GAGd6H,IAAwB,SACxBvH,EAAK,uBAAyBuH,GAGlC/M,EAAO,eAAewF,EAAM,EAAI,CACpC,CACJ,CAEA,gBAAgBwH,EAAmBC,EAAuD,CAAC,EAAGC,EAAc,GAAO,CAC/G,IAAMC,EAAQ,CACV,WAAYH,EACZ,GAAGC,CACP,EAEAjN,EAAO,eAAemN,EAAOD,CAAW,CAC5C,CAuBA,MAAc,eAAerC,EAA2C,CAWpE,GAVA,KAAK,sCAAsC,OAAOA,CAAgB,EAClE,KAAK,mCAAmC,IAAIA,EAAkB,KAAK,WAAW,6BAA6B,CAAC,EAExG,KAAK,oCAAoC,IAAIA,CAAgB,IAC7D9K,EAAM,IAAI,gEAAiE8K,CAAgB,EAC3F,OAAO,aAAa,KAAK,oCAAoC,IAAIA,CAAgB,CAAC,EAClF,KAAK,oCAAoC,OAAOA,CAAgB,GAGnD,KAAK,6BAA6B,IAAIA,CAAgB,EACzD,CACV,IAAMhG,EAAqB,MAAM,KAAK,iBAAiB,EACjDuI,EAAaC,GAAkCxC,CAAgB,EAC/D9H,EAAc8B,EAAmBuI,EAAW,aAAa,EACzDE,EAAkB,KAAK,eAAe,WACtCC,EAAgB,KAAK,MAAMH,EAAW,aAAa,EAEzD,GAAIrK,GAAewK,EAAe,CAC9B,OAAQH,EAAW,UAAW,CAC1B,aACA,YAAsB,CAClB,GAAIA,EAAW,WAAY,CACvB,IAAMI,EAAgC,CAClC,OAAQ,KACR,WAAYJ,EAAW,WACvB,UAAWA,EAAW,SAC1B,EAEIG,EACA1L,EAAS,YAAYyL,EAAiBE,CAAS,EAE/C3L,EAAS,aAAakB,EAAY,WAAYyK,CAAS,CAE/D,CACA,KACJ,CACA,aAAuB,CACnB3L,EAAS,eAAekB,EAAY,WAAY,IAAI,EACpD,KACJ,CAEA,aAAuB,CACnBlB,EAAS,qBAAqBkB,EAAY,WAAY,IAAI,EAC1D,KACJ,CACJ,CAEA/C,EAAO,IAAIsB,EAAQ,eAAe,CACtC,MACIvB,EAAM,IAAI,8CAA8CqN,EAAW,aAAa,EAAE,CAE1F,CAEA,KAAK,6BAA6B,OAAOvC,CAAgB,CAC7D,CAMA,MAAc,yBAAyB4B,EAA+FgB,EAAoB,GAAM,CAC5J,GAAI,OAAO,KAAKhB,CAAyB,EAAE,SAAW,EAClD,OAGJ1M,EAAM,IAAI,+BAA+B,KAAK,WAAW,6BAA6B,CAAC,IAAK0M,CAAyB,EAErH,IAAIiB,EAEJ,GAAI,CAEA,GADAA,EAAS,MAAM,KAAK,WAAW,oBAAoBjB,CAAyB,EACxE,CAACiB,EACD,MAER,OAAS5L,EAAY,CAGjB,GAFA/B,EAAM,KAAK,mCAAmC,KAAK,UAAU0M,CAAyB,CAAC,KAAK3K,CAAK,EAAE,EAE/F2L,EACA,MAAM3L,EAGV,MACJ,CAEA,IAAM6L,EAA0B,CAAC,EAC3B9I,EAAqB,MAAM,KAAK,iBAAiB,EACvD,OAAW,CAAC+I,EAAyBC,CAAS,IAAK,OAAO,QAAQH,EAAO,0BAA4B,CAAC,CAAC,EAAG,CACtG,IAAMI,EAAoBT,GAAkCO,CAAuB,EAC7EG,EAAmBlJ,EAAmBiJ,EAAkB,aAAa,EAC3E,GAAIC,EAAkB,CAClB,IAAIC,EACA,OAAOH,GAAc,UACrB9N,EAAM,KAAK,yBAAyB8N,CAAS,6BAA6BC,EAAkB,aAAa,EAAE,EAC3GE,EAAcC,GAA+B,eAE7CD,EAAcE,GAAwCL,CAAS,EAEnEF,EAAwB,KAAK,CAAE,WAAYI,EAAiB,WAAY,YAAAC,CAAY,CAAC,CACzF,CACJ,CAEA,GAAIL,GAA2BA,EAAwB,SACnD5N,EAAM,KAAK,8CAA+C4N,CAAuB,EAE7EF,GACA,MAAM,IAAIU,GAAyB,8CAA+CR,CAAuB,CAGrH,CAEA,MAAc,uBAAwB,CAClC,IAAMlB,EAA4E,CAAC,EAE7EG,EAAmB,KAAK,sCAAsC,QAAQ,EAC5E,EAAG,CACC,IAAMC,EAAkBD,EAAiB,KAAK,EAC9C,GAAIC,EAAgB,KAChB,MAGJ,IAAMuB,EAAQvB,EAAgB,MAE9B,GADkBuB,EAAM,CAAC,EACTC,GAAwC,KAAK,IAAI,EAC7D,MAGJ,IAAMxD,EAAmBuD,EAAM,CAAC,EAChC,MAAM,KAAK,eAAevD,CAAgB,EAE1C4B,EAA0B5B,CAAgB,EAAI,CAAE,WAAY,EAAK,CACrE,OAAS,IAET,KAAK,yBAAyB4B,EAA2B,EAAK,CAClE,CAEQ,4BAA4BpH,EAAsE,CACtG,GAAI,KAAK,cAAe,CACpB,IAAMiJ,EAAyBjJ,EAAQ,uBACvCtF,EAAM,IAAI,mDAAoDuO,CAAsB,EACpF,QAAWC,KAAyBD,EAChC,KAAK,uBAAuBC,CAAqB,CAEzD,CACJ,CAEA,MAAc,uBAAuB5M,EAAiD,CAC9E,KAAK,eAAiB,KAAK,cAAc,cACzC5B,EAAM,IAAI,4BAA6B,CAAC4B,EAAW,MAAM,EACzD,KAAK,cAAc,WAAaA,EAAW,OAC3C,KAAK,oBAAoBA,CAAU,EAC/B,CAACA,EAAW,QAAU,KAAK,cAC3B,KAAK,qBAAqB,KAAK,aAAa,iBAAiB,CAAC,IAGlE5B,EAAM,IAAI,2BAA4B,CAAC4B,EAAW,MAAM,EAEpDA,EAAW,QACX5B,EAAM,IAAI,0BAA0B,EACpC,KAAK,OAAO,IAAIwB,EAAahB,EAAW,OAAO,CAAC,IAEhD,KAAK,oBAAoBoB,CAAU,EACnC,MAAM,KAAK,aAAaA,CAAU,IAG1CE,EAAS,WAAWF,EAAW,MAAM,CACzC,CAEA,MAAc,mBACVqL,EACAwB,EAAa,EACbC,EAA2D,CAAC,EAC5DC,EACAC,EACF,CACE5O,EAAM,IAAI,sBAAsBiN,CAAS,EAAE,EAE3C,IAAM4B,EAAwB,CAAC,EACzBC,EAA6B,CAAC,EAC9BC,EAA+B,CAAC,EAChCC,EAA2B,CAAC,EAE5BC,EAA4C,CAAC,EA6BnD,GA5BIP,EAAkB,QAClBA,EAAkB,QAAS1L,GAAgB,CACvC,GAAIA,EAAY,WAAY,CACxB,IAAMmF,EAAa5C,EAAgB,cAAcvC,EAAY,UAAU,EACvEiM,EAAiB,KAAK9G,CAAU,EAChC,KAAK,KAAK,gBAAgBnF,EAAY,GAAG,GAAImF,CAAU,CAC3D,KAAO,CACH,IAAMpD,EAAKlF,EAAM,YAAYmD,EAAY,GAAG,EAAE,EAAE,GAChD6L,EAAU,KAAK9J,CAAE,EACjBiK,EAAa,KAAKjK,CAAE,CACxB,CACJ,CAAC,EAED4J,GAAqB,QACrBA,EAAoB,QAASO,GAAU,CACnC,IAAMnK,EAAKlF,EAAM,YAAYqP,CAAK,EAAE,GACpCL,EAAU,KAAK9J,CAAE,EACjB+J,EAAe,KAAK/J,CAAE,CAC1B,CAAC,EAED6J,GAAuB,QACvBA,EAAsB,QAASO,GAAY,CACvC,IAAMpK,EAAKlF,EAAM,YAAYsP,CAAO,EAAE,GACtCN,EAAU,KAAK9J,CAAE,EACjBgK,EAAiB,KAAKhK,CAAE,CAC5B,CAAC,EAGD,CAAC8J,EAAU,OAAQ,CACnB/M,EAAS,kBAAkBmL,EAAWwB,EAAYQ,EAAkB,CAAC,EAAG,CAAC,CAAC,EAC1E,MACJ,CAEA,GAAID,EAAa,OAAQ,CACrB,IAAM3N,EAAc,MAAM,KAAK,KAAK,sBAAsB2N,CAAY,EACtEC,EAAiB,KAAK,GAAG5N,CAAW,CACxC,CAEA,IAAM+N,EAAmB,MAAM,KAAK,KAAK,sBAAsBN,CAAc,EACvEO,EAAqB,MAAM,KAAK,KAAK,sBAAsBN,CAAgB,EAEjFjN,EAAS,kBAAkBmL,EAAWwB,EAAYQ,EAAkBG,EAAkBC,CAAkB,CAC5G,CAEA,MAAc,qBAAqB/J,EAA4C,CAC3E,IAAMiI,EAAkB,KAAK,eAAe,WAE5C,QAAWhE,KAASjE,EAAQ,KAGxB,GAFqB,KAAK,MAAMiE,EAAM,aAAa,EAG/CzH,EAAS,kBAAkByL,EAAiBhE,CAAK,MAC9C,CACH,IAAMpB,EAAa,MAAM,KAAK,8BAA8BoB,EAAM,aAAa,EAC3EpB,GACArG,EAAS,mBAAmBqG,EAAYoB,CAAK,CAErD,CAER,CAEA,MAAc,0BAA0BjE,EAA2C,CAC/EtF,EAAM,IAAI,uCAAuCsF,EAAQ,YAAY,EAAE,EACvE,MAAM,KAAK,wBAAwBA,EAAQ,eAAgBA,EAAQ,MAAM,CAC7E,CAEA,MAAc,yBAAyBgK,EAAwD/M,EAAkB,KAAM,CAC/G+M,GACA,MAAM,QAAQ,IAAIA,EAAgB,IAAKC,GAAmB,KAAK,wBAAwBA,EAAgBhN,CAAM,CAAC,CAAC,CAEvH,CAEA,MAAc,wBAAwBgN,EAAyChN,EAAkB,KAAM,CACnG,GAAI,CAACgN,EACD,OAGJ,IAAMhC,EAAkB,KAAK,eAAe,WAG5C,GAFqB,KAAK,MAAMgC,EAAe,WAAW,EAGtDzN,EAAS,uBAAuByL,EAAiBgC,EAAgBhN,CAAM,MACpE,CACH,IAAM4F,EAAa,MAAM,KAAK,8BAA8BoH,EAAe,WAAW,EAClFpH,GACArG,EAAS,wBAAwBqG,EAAYoH,EAAgBhN,CAAM,CAE3E,CACJ,CAEA,MAAc,kCAAkCX,EAA+E,CAC3H,IAAMwB,EAAKxB,EAAW,aAAa,aAAa,KAAMoB,GAAgB,KAAK,MAAMnD,EAAM,UAAUmD,CAAW,CAAC,CAAC,EAC9G,MAAM,KAAK,yBAAyBI,GAAI,gBAAiBxB,GAAY,OAAO,QAAU,IAAI,CAC9F,CAEA,MAAc,0BAA0BA,EAAgF,CACpH,IAAM4N,EAAsB5N,GAAY,aAAa,SAAW,KAAK,eAAe,QAKpF,GAJI4N,GACA,KAAK,eAAe,cAAc,IAAI,KAAMA,CAAmB,EAG/D5N,GAAY,OAAO,MACnB,QAAWU,KAAQV,EAAW,MAAM,MAC5BU,EAAK,SACL,KAAK,eAAe,cAAc,IAAIA,EAAK,GAAIA,EAAK,OAAO,EAKvE,IAAMC,EAASX,GAAY,OAAO,QAAU,KAAK,eAAe,QAAU,KACpE6N,EAAU,KAAK,eAAe,cAAc,IAAIlN,CAAM,EAE5D,GAAIkN,EAAS,CACT,IAAMtH,EAAa,MAAM,KAAK,8BAA8BsH,EAAQ,WAAW,EAC3EtH,GACArG,EAAS,SACL,CACI,WAAAqG,EACA,QAASsH,EAAQ,OACrB,EACAlN,CACJ,CAER,MAAWA,GACPT,EAAS,SAAS,KAAMS,CAAM,CAEtC,CAEA,MAAc,mCAAmCX,EAA+F,CAC5I,GAAI,CAAC,KAAK,cACN,OAGAA,GACA,KAAK,iCAAiCA,CAAU,EAGpD,GAAM,CAAE,qBAAA8N,CAAqB,EAAI,KAAK,cAChCnN,EAAS,KAAK,cAAc,OAC5BoN,EAAiBD,EAAqB,IAAInN,CAAM,EAEtD,GAAIoN,GAAkB,CAAC,KAAK,MAAMA,EAAe,WAAW,EAAG,CAC3D,IAAMxH,EAAa,MAAM,KAAK,8BAA8BwH,EAAe,WAAW,EAClFxH,GACArG,EAAS,kBAAkBqG,EAAYwH,EAAe,UAAWpN,CAAM,CAE/E,CACJ,CAEQ,iCAAiCX,EAAqF,CAC1H,GAAI,CAAC,KAAK,cACN,OAGJ,GAAM,CAAE,qBAAA8N,CAAqB,EAAI,KAAK,cAQtC,GANI9N,EAAW,aAAa,eACxB8N,EAAqB,IAAI,KAAM9N,EAAW,aAAa,cAAc,EAErE8N,EAAqB,OAAO,IAAI,EAGhC9N,EAAW,OAAO,MAClB,QAAWU,KAAQV,EAAW,MAAM,MAC5BU,EAAK,eACLoN,EAAqB,IAAIpN,EAAK,GAAIA,EAAK,cAAc,EAErDoN,EAAqB,OAAOpN,EAAK,EAAE,CAInD,CAEA,MAAc,0BAA0BgD,EAAkD,CACtFtF,EAAM,IAAI,uCAAuCsF,EAAQ,YAAY,EAAE,EAEvE,IAAMiI,EAAkB,KAAK,eAAe,WACtC,CAAE,YAAAqC,EAAa,QAAAC,EAAS,OAAAC,EAAQ,OAAAvN,EAAS,IAAa,EAAI+C,EAE1DG,EAAgC,CAClC,YAAAmK,EACA,QAAAC,EACA,OAAAC,CACJ,EAIA,GAFqB,KAAK,MAAMF,CAAW,EAGvC9N,EAAS,8BAA8ByL,EAAiB9H,EAAMlD,CAAM,MACjE,CACH,IAAM4F,EAAa,MAAM,KAAK,8BAA8ByH,CAAW,EACvE,GAAIzH,EAAY,CAEZ,IAAMnF,GADqB,MAAM,KAAK,iBAAiB,GAChB4M,CAAW,EAC9C5M,GAAa,kBACbA,EAAY,gBAAkBA,EAAY,gBAAgB,OAAQ+M,GAASA,GAAQA,EAAK,UAAYF,CAAO,GAG/G/N,EAAS,+BAA+BqG,EAAY1C,EAAMlD,CAAM,CACpE,CACJ,CACJ,CAEA,MAAc,yBAAyB+C,EAA0C,CAG7E,GAFAtF,EAAM,IAAI,6BAA6BsF,EAAQ,YAAY,EAAE,EAEzD,CAAC,KAAK,cACN,OAGJ,GAAM,CAAE,qBAAAoK,EAAsB,OAAQM,CAAc,EAAI,KAAK,cACvD,CAAE,YAAAJ,EAAa,UAAAK,EAAW,OAAA1N,EAAS,IAAa,EAAI+C,EAW1D,GATI2K,EACAP,EAAqB,IAAInN,EAAQ,CAC7B,UAAA0N,EACA,YAAAL,CACJ,CAAC,EAEDF,EAAqB,OAAOnN,CAAM,EAGlC,GAAC0N,GAAa1N,IAAWyN,GAAiBN,EAAqB,IAAIM,CAAa,KAMhF,CAACC,GAAa,CAAC,KAAK,MAAML,CAAW,GAAG,CACxC,IAAMzH,EAAa,MAAM,KAAK,8BAA8ByH,CAAW,EACnEzH,GACArG,EAAS,kBAAkBqG,EAAY8H,EAAW1N,CAAM,CAEhE,CACJ,CAEQ,0BAA0B+C,EAAkD,CAChFtF,EAAM,IAAI,8BAA8BsF,EAAQ,YAAY,EAAE,EAC1D,KAAK,gBACL,KAAK,cAAc,gBAAkBA,EAAQ,iBAAmB,CAAC,GAErExD,EAAS,yBAAyBwD,EAAQ,eAAmC,CACjF,CAEA,MAAc,uBAAuBkJ,EAA+D,CAEhG,GAAIA,EAAsB,iBAAmB,CAACA,EAAsB,6BAA8B,CAC9F,IAAMnB,EAAa,KAAK,0BAA0BmB,EAAsB,QAAQ,EAChF,GAAInB,EAAY,CACZ,IAAM6C,EAAwB5C,GAAkCD,CAAU,EACpE8C,EAA6B,MAAM,KAAK,gBAAgBD,EAAsB,aAAa,EACjGpO,EAAS,qBAAqBqO,EAA2B,WAAY,IAAI,EACzE,MACJ,CACJ,CAEA,IAAMpC,EAAoB,KAAK,wBAAwBS,EAAsB,4BAA4B,EACzG,GAAI,CAACT,EAED,OAGJ,GAAM,CAAE,UAAAqC,EAAW,cAAAlL,CAAc,EAAI6I,EAErC,GAAIqC,IAAc,UAEd,OAEJ,IAAMpN,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAE5D,GAAIzE,EAAO,2BAA6B2P,IAAc,UAAoB,CAAC5B,EAAsB,gBAAiB,CAE9GxO,EAAM,IAAI,sGAAsG,EAChH,MACJ,CAEA,IAAM6N,EAA0BtB,GAAsCwB,CAAiB,EAEjFsC,EAAyB,KAAK,mCAAmC,IAAIxC,CAAuB,EAClG,GAAIwC,GAA0BA,EAAyB7B,EAAsB,eAAgB,CACzFxO,EAAM,KACF,eAAekF,CAAa,oDACLsJ,EAAsB,cAAc,wDACD6B,CAAsB,EACpF,EACApQ,EAAO,IAAIsB,EAAQ,qBAAqB,EACxC,MACJ,CAGIyB,GAAewL,EAAsB,UAAY,QAAa4B,IAC9DpQ,EAAM,MAAM,yCAAyCoQ,CAAS,aAAa5B,EAAsB,OAAO,EAAE,EAC1G1M,EAAS,wBAAwBkB,EAAY,WAAYoN,EAAW5B,EAAsB,OAAO,GAGrG,IAAM8B,EAAW9B,EAAsB,SACjC+B,EAAc/B,EAAsB,aAAe,KAAK,gBAAgB8B,EAAU9B,EAAsB,YAAY,EAAI,EAC9H,GAAI+B,GAAe,EAAG,CAClB,KAAK,oCAAoC,OAAO1C,CAAuB,EAEvE,IAAMN,EAAkB,KAAK,eAAe,WACtCC,EAAgB,KAAK,MAAMtI,CAAa,EAE9C,GAAI,CAAClC,GAAe,CAACwK,EAAe,CAChCvN,EAAO,IAAIsB,EAAQ,UAAW,oBAAoB,EAClDvB,EAAM,MAAM,qCAAqCkF,CAAa,EAAE,EAChE,MACJ,CAEA,IAAMiD,EAAaqF,EAAgBD,EAAkBvK,EAAY,WAE3DiI,EAAS,KAAK,kBAAkB,IAAIqF,CAAQ,EAClD,GAAI,CAACrF,EAAQ,CACThL,EAAO,IAAIsB,EAAQ,UAAW,gBAAgB,EAC9CvB,EAAM,MAAM,gCAAgCsQ,CAAQ,EAAE,EACtD,MACJ,CAEArQ,EAAO,IAAIsB,EAAQ,aAAa,EAChC,KAAK,6BAA6B,IAAIsM,EAAyByC,CAAQ,EAEvE,IAAME,EAAehC,EAAsB,8BAA8B,UACzE,GAAIgC,IAAiB,UAAoBA,IAAiB,SACtD,GAAIhC,EAAsB,8BAA8B,WAAY,CAChE,IAAMf,EAAgC,CAClC,WAAYe,EAAsB,6BAA6B,WAC/D,OAAAvD,EACA,UAAWuF,CACf,EAEIhD,EACA1L,EAAS,YAAYqG,EAAYsF,CAAS,EAE1C3L,EAAS,aAAaqG,EAAYsF,CAAS,CAEnD,UACOhN,EAAO,qBAAuB+P,IAAiB,SACtD1O,EAAS,qBAAqBkB,EAAY,WAAYiI,CAAM,UAGxD,CAACuC,EAAe,CAChB,IAAMiD,GAAiBhQ,EAAO,oBAAsB,KAAOuC,EAAY,eAAiBiI,EACxFnJ,EAAS,eAAekB,EAAY,WAAYyN,CAAa,CACjE,CAER,KAAO,CACHzQ,EAAM,MAAM,eAAeuQ,CAAW,iBAAiBD,CAAQ,QAAQzC,CAAuB,cAAc,EAC5G,IAAM3C,EAAQ,OAAO,WAAW,KAAK,uBAAuB,KAAK,KAAMsD,CAAqB,EAAG+B,CAAW,EAC1G,KAAK,oCAAoC,IAAI1C,EAAyB3C,CAAK,CAC/E,CACJ,CAEQ,0BAA0BoF,EAAkD,CAChF,OAAW,CAACI,EAAeC,CAAW,IAAK,KAAK,6BAA6B,QAAQ,EACjF,GAAIA,IAAgBL,EAChB,OAAOI,EAGf,OAAO,IACX,CAGQ,wBAAwB3C,EAAwD,CACpF,GAAI,CAACA,EACD,OAAO,KAEX,GAAI,KAAK,6BAA6B,IAAIxB,GAAsCwB,CAAiB,CAAC,EAC9F,OAAOA,EAGX,IAAM7I,EAAgB6I,EAAkB,cACxC,GAAKA,EAAkB,UAUhB,CACH,IAAM6C,EAAkD,CAAE,cAAA1L,EAAe,UAAW,IAAK,EACzF,GAAI,KAAK,6BAA6B,IAAIqH,GAAsCqE,CAAiB,CAAC,EAC9F,OAAOA,CAEf,KAfkC,CAC9B,IAAMC,EAAoB,CAAE,cAAA3L,EAAe,kBAA4B,EACvE,GAAI,KAAK,6BAA6B,IAAIqH,GAAsCsE,CAAiB,CAAC,EAC9F,OAAOA,EAGX,IAAMC,EAAoB,CAAE,cAAA5L,EAAe,kBAA4B,EACvE,GAAI,KAAK,6BAA6B,IAAIqH,GAAsCuE,CAAiB,CAAC,EAC9F,OAAOA,CAEf,CAOA,OAAA9Q,EAAM,MAAM,kCAAmC+N,CAAiB,EACzD,IACX,CAEQ,gBAAgBuC,EAAkBS,EAAoC,CAC1E,GAAI,KAAK,WACL,OAAO,KAAK,WAAW,uBAAuBT,EAAUS,CAAkB,EAE1E,MAAM,IAAI,MAAM,8BAA8B,CAEtD,CAEQ,cAAe,CACnB,OAAK,KAAK,cAGHlR,EAAM,cAAc,KAAK,cAAc,MAAO,CAACmR,GAAS,MAAOA,GAAS,OAAO,CAAC,EAF5E,EAGf,CAEQ,iBAAkB,CACtB,GAAK,KAAK,eAGN,CAACnR,EAAM,cAAc,KAAK,cAAc,MAAO,CAACmR,GAAS,MAAOA,GAAS,OAAO,CAAC,EACjF,MAAM,IAAI,MAAM,wCAAwC,CAEhE,CAEQ,gBAAiB,CACrB,OAAO,KAAK,oBAAsBrR,EAAiB,MACvD,CAEA,MAAM,WAAWuF,EAA8B+L,EAAmBC,EAAiB,CAC/E,KAAK,gBAAgB,EACrB,MAAM,KAAK,WAAW,WAAWhM,EAAe+L,EAAOC,CAAM,CACjE,CAEA,MAAM,SAAS7L,EAAyB,CACpC,MAAM,KAAK,WAAW,SAASA,CAAM,CACzC,CAEA,MAAM,QAAQA,EAAyB,CACnC,MAAM,KAAK,WAAW,QAAQA,CAAM,CACxC,CAEA,MAAM,WAAW8L,EAAkB,CAE/B,KAAK,wBAA0BA,EAE/B,MAAM,KAAK,WAAW,WAAWA,CAAO,CAC5C,CAEA,MAAM,gBAAgBjM,EAAsC,KAAMP,EAAwByM,EAAgC,CAAC,EAAG7O,EAAwB,KAAc,CAChK,KAAK,gBAAgB,EACrB,MAAM,KAAK,WAAW,gBAAgB2C,EAAeP,EAAYyM,EAAgB7O,CAAM,CAC3F,CAEA,MAAM,sBAAsB8O,EAA8BJ,EAAmB,CACzE,MAAM,KAAK,WAAW,sBAAsBI,EAASJ,CAAK,CAC9D,CAEA,MAAM,eAAe/L,EAA8BoM,EAAgB/O,EAAwB,KAAc,CACrG,KAAK,gBAAgB,EACrB,MAAM,KAAK,WAAW,eAAe2C,EAAeoM,EAAO/O,CAAM,EAGjE,KAAK,eAAe,0BAA0B,IAAIA,EAAQ+O,EAAQ,KAAOpM,CAAa,CAC1F,CAEA,MAAM,qBAAqBqM,EAAgC,CACnD,KAAK,WAAW,OAAS,KAAK,gBAC9B,KAAK,cAAc,eAAiBA,EACpC,MAAM,KAAK,WAAW,qBAAqBA,CAAc,EAEjE,CAEA,MAAM,mBAAmBxF,EAAkB,CACnC,KAAK,WAAW,OAAS,KAAK,eAAiB,KAAK,YAAY,YAAY,IAAM,UAClF,MAAM,KAAK,WAAW,mBAAmBA,CAAO,CAExD,CAEA,MAAM,0BAA0BA,EAAkB,CAC1C,KAAK,WAAW,OAAS,KAAK,eAAiB,KAAK,YAAY,YAAY,IAAM,UAClF,MAAM,KAAK,WAAW,0BAA0BA,CAAO,CAE/D,CAEA,MAAM,cAAcyF,EAAoD,CACpE,GAAI,KAAK,WAAW,OAAS,KAAK,cAAe,CAC7C,KAAK,gBAAgB,EACrB,MAAM,KAAK,WAAW,cAAcA,CAAO,EAC3C,IAAMC,EAAUC,GAAmB,KAAK,cAAc,QAASF,CAAO,EACtE,KAAK,kBAAkBC,CAAO,CAClC,CACJ,CAMA,MAAM,eAAeE,EAA2BC,EAAgBC,EAAkD,CAC9G,GAAI,CAAC,KAAK,WACN,OAAO,QAAQ,OAAO,EAG1B,IAAIC,EAAuD,KAC3D,GAAIH,IACAG,EAASC,GAA+BJ,CAAU,EAC9CG,GAAQ,CACR,IAAM/J,EAAe,KAAK,KAAK,2BAA2B+J,EAAO,EAAE,EACnEA,EAAO,GAAK/J,EAAelI,EAAM,cAAckI,CAAY,EAAI+J,EAAO,EAC1E,CAGJ,IAAMnE,EAAS,MAAM,KAAK,WAAW,eAAemE,EAAQF,EAAOC,CAAQ,EAC3E,GAAIlE,EAAO,MAEP,OAAO,QAAQ,OAAOA,EAAO,OAAO,EAGxC,IAAMtK,EAAsDsK,EAAO,cAAgB,CAAC,EAC9E,CAAE,YAAAtM,CAAY,EAAI,MAAM,KAAK,+BAA+BgC,CAAY,EAC1E2O,EAAgC,KAEpC,OAAI3O,EAAa,QAAUsK,EAAO,UAC9BqE,EAAiBC,GAA6B5O,EAAaA,EAAa,OAAS,CAAC,EAAE,EAAE,GAGnF,CACH,aAAchC,EACd,WAAY2Q,EACZ,WAAYrE,EAAO,YAAc,CACrC,CACJ,CAEA,MAAc,+BAA+BtK,EAAqD,CAC9F,IAAM6O,EAAgB,IAAI,IACtBC,EAAuB,CAAC,EACxB9Q,EAA4B,CAAC,EAEjC,GAAIgC,EAAa,OAAQ,CACrB,IAAM+O,EAAmB,CAAC,EAC1B/O,EAAa,QAASL,GAAgB,CAGlC,GAFAkP,EAAc,IAAIlP,EAAY,GAAG,GAAIA,EAAY,GAAG,OAAO,EAEvDA,EAAY,WAAY,CACxB,IAAMmF,EAAa5C,EAAgB,cAAcvC,EAAY,UAAU,EACvEmP,EAAW,KAAKnP,EAAY,GAAG,OAAO,EACtC3B,EAAY,KAAK8G,CAAU,EAC3B,KAAK,KAAK,gBAAgBnF,EAAY,GAAG,GAAImF,CAAU,CAC3D,MACIiK,EAAK,KAAKvS,EAAM,YAAYmD,EAAY,GAAG,EAAE,EAAE,EAAE,CAEzD,CAAC,EAEGoP,EAAK,QAAU,CAAC/Q,EAAY,SAE5BA,EAAc,MAAM,KAAK,KAAK,sBAAsB+Q,CAAI,EAExDD,EAAa9Q,EAAY,IAAK8G,GAAe,CACzC,IAAMkK,EAAc,KAAK,KAAK,0BAA0BlK,CAAU,EAGlE,OAFwBkK,EAAcH,EAAc,IAAIG,CAAW,EAAI,SAE7C,KAAK,IAAI,CACvC,CAAC,EAET,CACA,MAAO,CAAE,YAAAhR,EAAa,WAAA8Q,CAAW,CACrC,CAEA,MAAM,sBAA2D,CAC7D,GAAI,CAAC,KAAK,WAAW,MACjB,MAAM,IAAI,MAAM,wBAAwB,EAG5C,IAAMxE,EAAS,MAAM,KAAK,WAAW,aAAa,EAClD,GAAIA,EAAO,MACP,OAAO,QAAQ,OAAOA,EAAO,OAAO,EAGxC,IAAMtK,EAAsDsK,EAAO,cAAgB,CAAC,EAC9E,CAAE,YAAAtM,EAAa,WAAA8Q,CAAW,EAAI,MAAM,KAAK,+BAA+B9O,CAAY,EAC1F,MAAO,CACH,WAAA8O,EACA,aAAc9Q,EACd,WAAYsM,EAAO,YAAc,CACrC,CACJ,CAEA,MAAM,mBAAmBzI,EAAiCoN,EAAiC,CACvF,GAAI,KAAK,YAAc,KAAK,cACxB,GAAI,CACA,GAAI,CAACzS,EAAM,cAAc,KAAK,cAAc,QAAS,CAACoD,GAAmB,aAAcA,GAAmB,aAAa,CAAC,EACpH,MAAM,IAAI,MAAM,0EAA0E,EAG9F,GADA,KAAK,gBAAgB,EACjB,CAACiC,GAAiBoN,EAClB,MAAM,IAAI,MAAM,2BAA2B,EAE/C,MAAM,KAAK,WAAW,mBAAmBpN,EAAeoN,CAAM,CAClE,OAASnL,EAAK,CACV,MAAAnH,EAAM,KAAK,iCAAiCkF,CAAa,KAAKiC,CAAG,EAAE,EAC7DA,CACV,CAER,CAEA,MAAM,iBAAiBoL,EAAY,GAAsB,CACjD,KAAK,WAAW,OAChB,MAAM,KAAK,WAAW,iBAAiBA,CAAS,CAExD,CAEA,MAAM,gBAAgBC,EAAS,GAAsB,CAC7C,KAAK,WAAW,OAChB,MAAM,KAAK,WAAW,gBAAgBA,CAAM,CAEpD,CAEA,MAAM,YAAYlN,EAAiBJ,EAAwC,KAAM,CACzE,KAAK,WAAW,OAChB,MAAM,KAAK,WAAW,YAAYI,EAASJ,CAAa,CAEhE,CAEA,MAAM,YAAY0M,EAAe,CAC7B,GAAI,KAAK,WAAW,MAAO,CACvB,IAAMnM,EAAO,MAAM,KAAK,WAAW,YAAYmM,CAAK,EACpD,QAAS,EAAInM,EAAK,SAAS,OAAS,EAAG,GAAK,EAAG,IAAK,CAChD,IAAMH,EAAUG,EAAK,SAAS,CAAC,EAC/B,MAAM,KAAK,eAAeH,CAAO,CACrC,CACJ,CACJ,CAEA,MAAM,WAAWG,EAAkBP,EAAsC,KAAM,CACvE,KAAK,WAAW,OAChB,MAAM,KAAK,WAAW,WAAWO,EAAMP,CAAa,CAE5D,CAEA,MAAM,gBAAiB,CACnB,GAAI,KAAK,cAAe,CAEpB,IAAMuN,GADS,MAAM,KAAK,KAAK,eAAe,KAAK,cAAc,EAAE,GAC/C,UACpB,GAAIA,EACA,YAAK,cAAc,SAAWA,EACvBA,CAEf,CACA,OAAO,QAAQ,OAAO,CAC1B,CAEA,MAAM,gBAAiB,CACnB,GAAI,KAAK,gBACU,MAAM,KAAK,KAAK,eAAe,KAAK,cAAc,EAAE,GACxD,QAAS,CAChB,OAAO,KAAK,cAAc,SAC1B,MACJ,CAEJ,OAAO,QAAQ,OAAO,CAC1B,CAEA,MAAM,SAAS,CAAE,QAAA5C,EAAS,KAAA6C,EAAM,SAAAC,EAAU,KAAAC,CAAK,EAAsE,CACjH,IAAMnN,EAAwB,CAC1B,QAAAoK,EACA,KAAA+C,CACJ,GAEIF,GAAQA,IAAS,KACjBjN,EAAK,KAAOiN,GAGZC,IACAlN,EAAK,SAAWkN,GAGpB,IAAMhF,EAAS,MAAM,KAAK,WAAW,SAASlI,CAAI,EAClD,GAAIkI,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,EAEhC,MAAO,CACH,QAASA,EAAO,QAChB,WAAYA,EAAO,UACvB,CACJ,CAEA,MAAM,YAAYtI,EAAyC,CACvD,IAAMsI,EAAS,MAAM,KAAK,WAAW,YAAYtI,CAAM,EACvD,GAAIsI,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,YAAYkC,EAAgC,CAC9C,IAAMpK,EAAO,CACT,QAAAoK,CACJ,EAEMlC,EAAS,MAAM,KAAK,WAAW,YAAYlI,CAAI,EACrD,GAAIkI,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,gBAAgBsC,EAAkC,CACpD,IAAMtC,EAAS,MAAM,KAAK,WAAW,gBAAgBsC,CAAS,EAC9D,GAAItC,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,gBAAgC,CAClC,IAAMA,EAAS,MAAM,KAAK,WAAW,eAAe,EACpD,GAAIA,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,YAAYzL,EAAgC2Q,EAAyC,CACvF,IAAMlF,EAAS,MAAM,KAAK,WAAW,YAAYzL,EAAO2Q,CAAc,EACtE,GAAIlF,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,cAAcmF,EAAmBC,EAAoC,CACvE,IAAMpF,EAAS,MAAM,KAAK,WAAW,cAAcmF,EAASC,CAAU,EACtE,GAAIpF,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,WAAWqF,EAAyB9N,EAA8C,CACpF,IAAMyI,EAAS,MAAM,KAAK,WAAW,WAAWqF,EAAU9N,CAAa,EACvE,GAAIyI,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,YAAYmF,EAAkC,CAChD,IAAMnF,EAAS,MAAM,KAAK,WAAW,YAAYmF,CAAO,EACxD,GAAInF,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,YACFsF,EAAW,GACXC,EAAsB,KACtBrD,EAAyB,KACzBsD,EAAgD,cAChDC,EAAyB,KACzB7Q,EAAwB,KAC1B,CACE,IAAMkD,EAAyB,CAC3B,QAAAoK,EACA,KAAAqD,EACA,QAAAC,EACA,QAAAC,EACA,OAAA7Q,EACA,YAAa,CAAC0Q,CAClB,EACMtF,EAAS,MAAM,KAAK,WAAW,YAAYlI,CAAI,EACrD,GAAIkI,EAAO,MACP,OAAO,QAAQ,OAAOA,EAAO,OAAO,CAE5C,CAEA,MAAM,WAAWpL,EAAwB,KAAc8Q,EAAkB,CAGrE,IAFe,MAAM,KAAK,WAAW,WAAW,CAAE,OAAA9Q,EAAQ,GAAI8Q,GAAU,CAAE,OAAAA,CAAO,CAAG,CAAC,GAE1E,MACP,OAAO,QAAQ,OAAO,CAE9B,CAEA,MAAM,cAAc9Q,EAAwB,KAAc,CAGtD,IAFe,MAAM,KAAK,WAAW,cAAc,CAAE,OAAAA,CAAO,CAAC,GAElD,MACP,OAAO,QAAQ,OAAO,CAE9B,CAEA,MAAM,cAAc+Q,EAAsBC,EAAyBC,EAAuB,GAAOjR,EAAwB,KAA6B,CAClJ,IAAMoL,EAAS,MAAM,KAAK,WAAW,cAAc,CAC/C,KAAA2F,EACA,MAAAC,EACA,qBAAAC,EACA,OAAAjR,CACJ,CAAC,EACD,GAAIoL,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,CAEpC,CAEA,MAAM,eAAgB,CAClB,IAAMA,EAAS,MAAM,KAAK,WAAW,gBAAgB,EACrD,MAAO,CACH,QAASA,EAAO,cAChB,QAASA,EAAO,qBACpB,CACJ,CAEA,MAAM,mBAAmB,CAAE,MAAA8F,EAAO,OAAAC,CAAO,EAA2D,CAChG,GAAID,EAAM,MAAQhT,EAAO,eAAiBgT,EAAM,OAAShT,EAAO,eAC5D,MAAM,IAAI,MAAM,sEAAsE,EAG1F,GAAIiT,EAAQ,CACR,GAAIA,EAAO,MAAQjT,EAAO,eAAiBiT,EAAO,OAASjT,EAAO,eAC9D,MAAM,IAAI,MAAM,gFAAgF,EAGpGA,EAAO,qBAAuBiT,EAAO,OACrCjT,EAAO,oBAAsBiT,EAAO,KACxC,CAEAjT,EAAO,cAAgBgT,EAAM,MAC7BhT,EAAO,eAAiBgT,EAAM,OAE9BzT,EAAM,MAAM,8BAA+B,SAASyT,EAAM,KAAK,IAAIA,EAAM,MAAM,IAAMC,EAAS,YAAYA,EAAO,KAAK,IAAIA,EAAO,MAAM,GAAK,GAAG,EAE3I,KAAK,eACL,MAAM,KAAK,aAAa,cAAc,CAAE,MAAAD,EAAO,OAAAC,CAAO,CAAC,EACnD,KAAK,YACL,MAAM,KAAK,WAAW,0BAA0B,EAG5D,CAEA,MAAM,YAAYA,EAAwB,CACtC,OAAO,KAAK,cAAc,YAAYA,CAAM,CAChD,CAEA,MAAM,YAAYC,EAA0BC,EAAoB,CAC5D,OAAO,KAAK,cAAc,YAAYD,EAAU,CAAE,QAAAA,EAAS,SAAAC,CAAS,EAAI,IAAI,CAChF,CAEA,uCAAuCvS,EAA2B,CAC9D,OAAOA,EAAY,IAAK8G,IACb,CAAE,GAAIA,EAAW,GAAI,KAAM1H,EAAO,gBAAiB,EAC7D,CACL,CAEA,MAAM,gBAAgBoT,EAAwE,CAC1F,IAAMC,EAAoB,KAAK,uCAAuCD,EAAW,WAAW,EACtFlG,EAAS,MAAM,KAAK,WAAW,gBAAgBmG,CAAiB,EACtE,GAAInG,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,EAEhC,IAAMoG,EAAkBpG,EAAO,aACzBqG,EAAiB,KAAK,YAAY,SAAS,EACjD,OAAO,QAAQ,IACXD,EAAgB,IAAI,MAAO/Q,GAAgB,CACvC,IAAMkC,EAAgBrF,EAAM,UAAUmD,CAAW,EACjD,OAAO,KAAK,mBACR,CACI,GAAIkC,EACJ,WAAYK,EAAgB,yBAAyBvC,CAAW,EAChE,cAAegF,GAAgChF,EAAY,aAAa,EACxE,iBAAkBnD,EAAM,oBAAoBmD,CAAW,EACvD,MAAOA,EAAY,MACnB,MAAOA,EAAY,OAAS,CAAC,EAC7B,OAAQ,KAAK,2BAA2BgR,CAAc,GAAK,UAC3D,WAAYhR,EAAY,YAAc,CAAC,EACvC,cAAeA,EAAY,eAAiB,CAAC,EAC7C,YAAaA,EAAY,aAAe,CAAC,EACzC,QAAS,KAAK,oBAAoBkC,EAAelC,EAAY,OAAO,CACxE,EACAA,EAAY,gBAChB,CACJ,CAAC,CACL,EAAE,KAAKnD,EAAM,qBAAqB,CACtC,CAEA,MAAM,wBAAwBoU,EAAuG,CACjIjU,EAAM,IAAI,iCAAkCiU,CAA8B,EAC1E,IAAMtG,EAAS,MAAM,KAAK,WAAW,wBAAwBsG,CAA8B,EAC3F,GAAItG,EAAO,MACP,MAAM,IAAI,MAAMA,EAAO,KAAK,EAGhC,IAAM/E,EAA+C,KAAK,4BAA4B+E,EAAO,KAAK,EAC5F7I,EAAqB,MAAM,KAAK,iBAAiB,EAEjDoP,EAAkBtL,EAAM,aAAa,OAAQ3D,GAAqB,CACpE,IAAMC,EAAgBrF,EAAM,UAAUoF,CAAgB,EACtD,MAAO,CAACH,EAAmBI,CAAa,CAC5C,CAAC,EACD,MAAM,KAAK,sBAAsBgP,CAAe,EAEhD,IAAMF,EAAiB,KAAK,YAAY,SAAS,EACjD,OAAApL,EAAM,aAAa,QAAS3D,GAAqB,CAC7C,IAAMC,EAAgBrF,EAAM,UAAUoF,CAAgB,EAChDjC,EAAc8B,EAAmBI,CAAa,EACpDlC,EAAY,OAAS,KAAK,2BAA2BgR,CAAc,GAAK,UACxEhR,EAAY,gBAAkBiC,EAAiB,gBAC/C,OAAO,OAAOjC,EAAY,cAAegF,GAAgC/C,EAAiB,aAAa,CAAC,EACxG,OAAO,OAAOjC,EAAY,WAAYiC,EAAiB,UAAU,EACjEjC,EAAY,cAAgBiC,EAAiB,eAAiBjC,EAAY,cAE1E,KAAK,eAAe,CAACA,CAAW,EAAG,EAAI,CAC3C,CAAC,EAEM,KAAK,qCAAqC4F,CAAK,CAC1D,CAEA,MAAc,iCAAkC,CAC5C,IAAMuL,EAAU1T,EAAO,8BACjBmR,EAAQnR,EAAO,8BAEf2T,EAAW,MAAM,KAAK,WAAW,wBAAwB,CAC3D,SAFa,OAGb,QAAAD,EACA,MAAAvC,CACJ,CAAC,EACD,OAAA5R,EAAM,MAAM,qCAAsCoU,EAAS,KAAK,EACzDA,EAAS,KACpB,CAEQ,2BAA2BhH,EAAiC,CAChE,GAAI,CAAC,KAAK,eAAiB,CAAC,KAAK,aAC7B,OAGJ,IAAMtN,EAAgB,KAAK,aAAa,iBAAiB,EACzDE,EAAM,MAAM,6BAA8BF,CAAa,EAEnDsN,EAAM,OAAS,SAAwB,KAAK,eAE5C,KAAK,UAAY,IAAI3E,GAAS,KAAK,YAAY,GAGnD3G,EAAS,oBAAoBhC,EAAesN,EAAM,IAAI,EAElD,CAAC,KAAK,eAAe,aAAe,CAAC,KAAK,eAAe,UAAY,CAAC,KAAK,wBAAwB,GACnG,KAAK,qBAAqBtN,CAAa,CAE/C,CAEQ,uBAAuBsN,EAA2C,CACtE,IAAMtN,EAAgB,KAAK,cAAc,iBAAiB,EAG1D,GAFAE,EAAM,IAAI,yBAA0BoN,EAAM,MAAOtN,CAAa,EAE1DW,EAAO,oBAAqB,CAC5B,IAAMwK,EAASmC,EAAM,MAAQ,IAAI,YAAY,CAACA,EAAM,KAAK,CAAC,EAAI,KAC9DtL,EAAS,eAAemJ,EAAQnL,CAAa,CACjD,CACJ,CAEA,MAAc,2BAA2BoF,EAA8BpF,EAA6C,CAChHE,EAAM,MAAM,kCAAkCkF,CAAa,IAAKpF,CAAa,EAC7E,IAAMyN,EAAkB,KAAK,eAAe,WAG5C,GAFa,KAAK,MAAMrI,CAAa,GAEzBqI,EAAiB,CAEzBzL,EAAS,qBAAqByL,EAAiBzN,CAAa,EAC5D,MACJ,CAEA,IAAMkD,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAE5D,GAAI,CAAClC,EAAa,CACd,KAAK,kCAAkCkC,CAAa,EACpD,MACJ,CAEAlC,EAAY,cAAgBlD,EAGxB,KAAK,SAAW,UAChBgC,EAAS,sBAAsBkB,EAAY,WAAYlD,EAAekD,EAAY,OAAO,EAGzF,KAAK,eACL,KAAK,cAAc,4BAA4BkC,EAAepF,CAAa,CAEnF,CAEQ,uCAAuC8B,EAAyH,CACpK,IAAM+F,EAAS,KAAK,KAAK,UAAU,EAInC,OAHY/F,EAAW,aAAa,cAAgB,CAAC,GAAG,KACnDoB,GAAgBA,EAAY,KAAO2E,GAAU9H,EAAM,cAAcmD,EAAY,OAAmCpB,EAAW,MAAM,CACtI,CAEJ,CAEQ,6BAA6ByS,EAAgD,CACjFrU,EAAM,MAAM,iDAAkDqU,CAAgB,EAE1E,KAAK,SAAW,UAChBvS,EAAS,wBAAwBuS,CAAgB,CAEzD,CAEA,MAAc,8BAA8BnP,EAA8BmP,EAA0D,CAChIrU,EAAM,MAAM,qCAAqCkF,CAAa,IAAKmP,CAAgB,EAEnF,IAAMrR,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAC5D,GAAI,CAAClC,EAAa,CACd,KAAK,kCAAkCkC,CAAa,EACpD,MACJ,CAEAlC,EAAY,iBAAmBqR,GAAoB,CAAC,EAEhD,KAAK,SAAW,UAChBvS,EAAS,yBAAyBkB,EAAY,WAAYA,EAAY,iBAAkBA,EAAY,OAAO,CAEnH,CAEA,MAAc,gCAAgCsR,EAAsD/R,EAAiC,CACjIvC,EAAM,MAAM,sCAAuCsU,CAAQ,EAC3D,IAAMC,EAAmC,CAAC,EACtCC,EACE1P,EAAqB,MAAM,KAAK,iBAAiB,EAEvDwP,EAAS,QAAQ,CAAC/K,EAAOrE,IAAkB,CACvC,GAAI,KAAK,MAAMA,CAAa,EACxBsP,EAAUjL,MACP,CACH,IAAMvG,EAAc8B,EAAmBI,CAAa,EACpD,GAAI,CAAClC,EAAa,CACd,KAAK,kCAAkCkC,CAAa,EACpD,MACJ,CACAlC,EAAY,iBAAmBuG,EAC/BgL,EAAU,KAAK,CACX,WAAYvR,EAAY,WACxB,iBAAkB,CAAE,GAAGuG,CAAM,EAC7B,QAASvG,EAAY,OACzB,CAAC,CACL,CACJ,CAAC,EAEG,KAAK,SAAW,WACZwR,GACA1S,EAAS,wBAAwB0S,EAAS,EAAI,EAE9CD,EAAU,QACVzS,EAAS,0BAA0ByS,EAAWhS,CAAM,EAGhE,CAEQ,oCAAoCS,EAAgC,CACpE,KAAK,SAAW,UAIhBA,EAAY,OAASA,EAAY,MAAM,SACvChD,EAAM,MAAM,0BAA0BgD,EAAY,EAAE,cAAcA,EAAY,KAAK,EAAE,EACrFlB,EAAS,eAAekB,EAAY,WAAYA,EAAY,MAAO,EAAI,EAE/E,CAEQ,yBAAyBsC,EAA2B,CACxD,OAAQA,EAAQ,aAAc,CAC1B,KAAKmP,EAAsB,cACvB,OAAO,KAAK,gBAAgBnP,CAAwC,EAExE,KAAKmP,EAAsB,OACvB,OAAO,KAAK,UAAUnP,CAAkC,EAE5D,KAAKmP,EAAsB,kBACvB,OAAO,KAAK,oBAAoBnP,CAA4C,EAEhF,KAAKmP,EAAsB,mBACvB,OAAO,KAAK,qBAAqBnP,CAA6C,EAElF,KAAKmP,EAAsB,oBACvB,OAAO,KAAK,sBAAsBnP,CAA8C,EAEpF,KAAKmP,EAAsB,uBACvB,OAAO,KAAK,wBAAwBnP,CAAgD,EAExF,KAAKmP,EAAsB,0BACvB,OAAO,KAAK,2BAA2BnP,CAAmD,EAE9F,KAAKmP,EAAsB,2BACvB,OAAO,KAAK,4BAA4BnP,CAAoD,EAEhG,KAAKmP,EAAsB,eACvB,OAAO,KAAK,YAAY,EAE5B,KAAKA,EAAsB,oBACvB,OAAO,KAAK,qBAAqBnP,CAA6C,EAElF,KAAKmP,EAAsB,wBACvB,OAAO,KAAK,yBAAyBnP,CAAiD,EAE1F,KAAKmP,EAAsB,4BACvB,OAAO,KAAK,4BAA4BnP,CAAoD,EAEhG,KAAKmP,EAAsB,gBACvB,OAAO,KAAK,kBAAkBnP,CAA0C,EAE5E,KAAKmP,EAAsB,qBACvB,OAAO,KAAK,sBAAsBnP,CAA8C,EAEpF,KAAKmP,EAAsB,gBACvB,OAAO,KAAK,kBAAkBnP,CAA0C,EAE5E,KAAKmP,EAAsB,aACvB,OAAO,KAAK,eAAenP,CAAuC,EAEtE,KAAKmP,EAAsB,aACvB,OAAO,KAAK,eAAenP,CAAuC,EAEtE,KAAKmP,EAAsB,YACvB,OAAO,KAAK,cAAcnP,CAAsC,EAEpE,KAAKmP,EAAsB,eACvB,OAAO,KAAK,cAAcnP,EAAQ,WAAYA,EAAQ,MAAM,EAEhE,KAAKmP,EAAsB,eACvB,OAAO,KAAK,kBAAkBnP,EAA2CA,EAAQ,MAAM,EAE3F,KAAKmP,EAAsB,cACvB,OAAO,KAAK,gBAAgBnP,EAAQ,cAAeA,EAAQ,OAAS,CAAC,CAAC,EAE1E,KAAKmP,EAAsB,iBACvB,OAAO,KAAK,mBAAmBnP,CAA2C,EAE9E,KAAKmP,EAAsB,gBACvB,OAAO,KAAK,kBAAkBnP,EAAQ,cAAeA,EAAQ,MAAOA,EAAQ,QAASA,EAAQ,MAAM,EAEvG,KAAKmP,EAAsB,gBACvB,OAAO,KAAK,kBAAkBnP,EAAQ,SAAW,CAAC,CAAC,EAEvD,KAAKmP,EAAsB,2BACvB,OAAO,KAAK,4BAA4BnP,CAAgE,EAE5G,KAAKmP,EAAsB,oBACvB,OAAO,KAAK,uBAAuBnP,CAA8C,EAErF,KAAKmP,EAAsB,kBAEvB,OAAO,KAAK,mBAAmBnP,EAAQ,UAAWA,EAAQ,WAAYA,EAAQ,kBAAmBA,EAAQ,oBAAqBA,EAAQ,qBAAqB,EAE/J,KAAKmP,EAAsB,kBACvB,OAAO,KAAK,mBAAmBnP,CAA2C,EAE9E,KAAKmP,EAAsB,SACvB,OAAO,KAAK,YAAYnP,CAAoC,EAEhE,KAAKmP,EAAsB,0BACvB,OAAO,KAAK,qBAAqBnP,CAA4C,EAEjF,KAAKmP,EAAsB,oBACvB,OAAO,KAAK,0BAA0BnP,CAA2C,EAErF,KAAKmP,EAAsB,oBACvB,OAAO,KAAK,0BAA0BnP,CAAkD,EAE5F,KAAKmP,EAAsB,yBACvB,OAAO,KAAK,yBAAyBnP,CAA0C,EAEnF,KAAKmP,EAAsB,cACvB,OAAO,KAAK,gBAAgBnP,CAAwC,EAExE,KAAKmP,EAAsB,aACvB,OAAO,KAAK,eAAenP,CAAuC,EAEtE,KAAKmP,EAAsB,0BACvB,OAAO,KAAK,2BAA2BnP,CAAmD,EAE9F,KAAKmP,EAAsB,0BACvB,OAAO,KAAK,0BAA0BnP,CAAkD,EAG5F,KAAKmP,EAAsB,4BACvB,OAAO,KAAK,6BAA6BnP,CAAqD,EAGlG,KAAKmP,EAAsB,YACvB,OAAO,KAAK,YAAYnP,CAAgD,EAG5E,KAAKmP,EAAsB,YACvB,OAAO,KAAK,WAAWnP,CAA+C,EAG1E,KAAKmP,EAAsB,mBACvB,OAAO,KAAK,qBAAqBnP,CAA6C,EAGlF,KAAKmP,EAAsB,kCACvB,OAAO,KAAK,kCAAkCnP,CAA0D,EAG5G,KAAKmP,EAAsB,sBACvB,OAAO,KAAK,uBAAuBnP,CAA+C,CAE1F,CACJ,CAEA,MAAc,qBAAqBA,EAA6C,CAC5E,IAAM6C,EAAa,MAAM,KAAK,8BAA8B7C,EAAQ,OAAO,EAE3E,GAAI,CAAC6C,EAAY,CACb,KAAK,kCAAkC7C,EAAQ,OAAO,EACtD,MACJ,CAEAxD,EAAS,oBAAoBqG,CAAU,CAC3C,CAEA,MAAc,sBAAsBvG,EAAyC,CACzE,GAAI,CAAC,KAAK,cACN,OAGAA,EAAW,aAAa,aACxB,KAAK,cAAc,WAAaA,EAAW,aAAa,YAGxDA,EAAW,aAAa,oBACxB,KAAK,cAAc,kBAAoBA,EAAW,aAAa,mBAG/DA,EAAW,aAAa,WACxB,KAAK,cAAc,SAAWA,EAAW,aAAa,SACtD,KAAK,cAAc,gBAAkBA,EAAW,aAAa,gBAC7D,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,GAGhC,MAAM,KAAK,2BAA2BA,CAAU,EAE5CA,EAAW,aAAa,MAI5B,IAAI8S,EAA+C,KAEnD,GAAI9S,EAAW,aAAa,aAAc,CAEtC,IAAM+S,EAAoB,OAAO,KAAK,MAAM,KAAK,iBAAiB,CAAC,EAE7DC,EAAqC,CAAC,EAG5C,QAAWC,KAAkBjT,EAAW,aAAa,aAAc,CAC/D,IAAMkT,EAASjV,EAAM,UAAUgV,CAAc,EACvCE,EAAWF,EAAe,OAAS,CAAC,EAC1C,GAAI,KAAK,MAAMC,CAAM,EAAG,CAEfE,GAAiB,KAAK,cAAc,MAAOD,CAAQ,GACpD,KAAK,gBAAgBD,EAAQC,CAAQ,EAGzCL,EAA0B,IAAM,CAC5B,KAAK,mCAAmC,CACpC,WAAYO,GAAuCJ,CAAc,EACjE,cAAeA,EAAe,aAClC,CAAC,CACL,EACA,QACJ,CAEAD,EAAkB,KAAKE,CAAM,EAE7B,IAAM9R,EAAc,MAAM,KAAK,gBAAgB8R,CAAM,EACrD,GAAI,CAAC9R,EAED,MAAM,KAAK,qBAAqB,CAC5B,cAAe6R,EAAe,GAC9B,YAAaA,EACb,cAAeA,EAAe,aAClC,CAAC,MACE,CACH,IAAMK,EAAKlN,GAAgC6M,EAAe,aAAa,EAClEM,GAAqBD,EAAIlS,EAAY,aAAa,GAEnD,MAAM,KAAK,2BAA2B8R,EAAQI,CAAE,EAGpD,IAAM9S,EAAWvC,EAAM,oBAAoBgV,CAAc,EACnDO,EAAWpS,EAAY,iBACxBnD,EAAM,wBAAwBuC,EAAUgT,CAAQ,GAEjD,MAAM,KAAK,8BAA8BN,EAAQ1S,CAAQ,EAGxD4S,GAAiBD,EAAU/R,EAAY,KAAK,GAE7C,KAAK,gBAAgBA,EAAY,GAAI+R,CAAQ,CAErD,CACJ,CAEA,IAAMjQ,EAAqB,MAAM,KAAK,iBAAiB,EAEvD,QAAWuQ,KAAUV,EAKbC,EAAkB,QAAQS,CAAM,EAAI,GAAKvQ,EAAmBuQ,CAAM,GAElE,KAAK,mBAAmBvQ,EAAmBuQ,CAAM,EAAG7U,EAAW,MAAM,CAGjF,CAGA,IAAM8U,EAAa1T,EAAW,OAAO,QAAU,KAG/C,GAAI,CAAC,KAAK,cAAe,CACrB5B,EAAM,KAAK,6CAA6C,EACxD,MACJ,CAEuB,KAAK,cAAc,SAAWsV,EAEjD,MAAM,KAAK,gBAAgBA,CAAU,EAErC,KAAK,mBAAmB1T,EAAY,EAAI,EAG5C8S,IAA0B,EAE1B,KAAK,oBAAoB9S,CAAU,EACnC,KAAK,kBAAkBA,EAAW,aAAa,OAAO,CAC1D,CAEQ,mBAAmBG,EAAkB,CACzC/B,EAAM,MAAM,mBAAoB+B,CAAK,EACrC,KAAK,OAAOA,CAAK,CACrB,CAEA,MAAc,gBAAgBuD,EAAuD,CACjF,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EAC9C1C,EAAS/C,EAAM,gBAAgByF,EAAQ,MAAM,EAMnD,GAJAtF,EAAM,MAAM,8BAA8BkF,CAAa,GAAG,EAE1D,KAAK,wBAAwB,iBAAiB,KAAK,YAAY,YAAY,CAAC,EAExE,KAAK,eAAiB,KAAK,MAAMA,CAAa,EAAG,CACjD,KAAK,OAAO,IAAI1D,EAAahB,EAAW,MAAM,EAAG,+BAA+B,EAChF,MACJ,CAEA,IAAIwC,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAC1D,GAAI,CAAClC,EAAa,CACd,IAAMyG,EAAiB,KAAK,KAAK,2BAA2BvE,CAAa,EACnE6C,EAAe0B,EAAiB5J,EAAM,cAAc4J,EAAgBnE,EAAQ,eAAe,EAAI,OAErGtC,EAAc,KAAK,4BACf,MAAM,KAAK,mBACP,CACI,GAAIkC,EACJ,cAAe8C,GAAgC1C,EAAQ,aAAa,CACxE,EACAyC,CACJ,CACJ,CACJ,CAEA/E,EAAY,MAAQrD,EAAiB,SACrCqD,EAAY,cAAgBgF,GAAgC1C,EAAQ,aAAa,EACjF,KAAK,sBAAsB/D,EAAQ,kBAAmByB,EAAY,aAAa,EAG3E,KAAK,eACL,KAAK,cAAc,YAAcnB,GAAc,WAC9C,KAAK,SAAW,QAA0B,KAAK,SAAW,gBAE3D,KAAK,OAAS,SACd,KAAK,kBAAkB,GAMvB,KAAK,SAAW,UAA4B,KAAK,YACjD,KAAK,WAAW,KAAK,CAACmB,EAAY,EAAE,EAAGJ,CAAM,EAGjD,MAAM,KAAK,2BAA2BsC,EAAelC,EAAY,aAAa,EAC9E,MAAM,KAAK,8BAA8BkC,CAAa,EACtD,IAAMlE,EAAe,OAAO,KAAKgC,EAAY,UAAU,EACnDhC,EAAa,QACb,KAAK,mBAAmB,CAAE,WAAYgC,EAAY,WAAY,aAAAhC,EAAc,aAAc,GAAM,cAAAkE,CAAc,CAAC,EAE/G,KAAK,SAAW,UAChBpD,EAAS,eAAekB,EAAY,WAAYgE,GAAsB,kBAAkB1B,EAAQ,YAAY,CAAC,CAErH,CAEA,MAAc,UAAUA,EAAiD,CACrEtF,EAAM,MAAM,uBAAuBsF,EAAQ,aAAa,IAAK,CAAE,OAAQA,EAAQ,MAAO,CAAC,EAEvF,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EACpD,GAAI,KAAK,eAAiB,KAAK,MAAMJ,CAAa,EAAG,CACjD,KAAK,OAAO,IAAI1D,EAAa8D,EAAQ,OAAQ,CAAE,OAAQ,EAAK,CAAC,CAAC,EAC9D,MACJ,CAEA,MAAM,KAAK,gDAAgDJ,EAAeI,EAAQ,OAAO,EACzF,IAAMtC,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAC5D,GAAI,CAAClC,EAAa,CACd,KAAK,kCAAkCkC,CAAa,EACpD,MACJ,CAEI,KAAK,YACL,KAAK,WAAW,MAAMA,CAAa,EAGvClC,EAAY,MAAQsC,EAAQ,SAAW9E,EAAW,SAAWb,EAAiB,SAAWA,EAAiB,OAEtG,KAAK,SAAW,SAChB,KAAK,mBAAmBqD,EAAaxC,EAAW,MAAM,CAE9D,CAEA,MAAc,oBAAoB8E,EAA2D,CACzFtF,EAAM,MAAM,sBAAsBsF,EAAQ,aAAa,GAAG,EAE1D,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EAChDtC,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAC1D,GAAIlC,GAAeA,EAAY,QAAUrD,EAAiB,QAAUqD,EAAY,QAAUrD,EAAiB,SAAU,CACjHK,EAAM,MAAM,gBAAgBkF,CAAa,4CAA4C,EACrF,MACJ,CAEA,GAAI,CAAClC,EAAa,CACd,GAAM,CAAE,YAAauS,CAAe,EAAIjQ,EAClCyC,EAAewN,EAAe,iBACpC,KAAK,qBACD,CACI,GAAIrQ,EACJ,WAAYK,EAAgB,yBAAyBgQ,CAAc,EACnE,cAAevN,GAAgCuN,EAAe,aAAa,EAC3E,MAAOA,EAAe,MACtB,iBAAkB1V,EAAM,oBAAoB0V,CAAc,EAC1D,MAAOA,EAAe,OAAS,CAAC,EAChC,WAAYA,EAAe,YAAc,CAAC,EAC1C,cAAeA,EAAe,eAAiB,CAAC,EAChD,YAAaA,EAAe,aAAe,CAAC,CAChD,EACAxN,CACJ,EAEA/E,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,CAC1D,CAEAlC,EAAY,MAAQrD,EAAiB,OACrCqD,EAAY,cAAgBgF,GAAgC1C,EAAQ,aAAa,aAAa,EAC9FtC,EAAY,iBAAmBnD,EAAM,oBAAoByF,EAAQ,WAAW,EAC5EtC,EAAY,MAAQsC,EAAQ,aAAa,OAAS,CAAC,EAEnD,KAAK,uBAAuB,CAACtC,CAAW,WAA4B,EAKhE,KAAK,SAAW,QAA0B,KAAK,YAC/C,KAAK,WAAW,SAASA,EAAY,GAAI,EAAI,EAGjDlB,EAAS,mBAAmBkB,EAAY,WAAYA,EAAY,OAAO,EACvE,MAAM,KAAK,2BAA2BkC,EAAelC,EAAY,aAAa,EAC9E,MAAM,KAAK,8BAA8BkC,EAAelC,EAAY,gBAAgB,EACpF,KAAK,oCAAoCA,CAAW,CACxD,CAEA,MAAc,qBAAqBsC,EAA4D,CAC3FtF,EAAM,MAAM,uBAAuBsF,EAAQ,aAAa,GAAG,EAC3D,KAAK,wBAAwB,sBAAsB,KAAK,YAAY,YAAY,CAAsB,EAEtG,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EAChDtC,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAC1D,GAAIlC,GAAeA,EAAY,QAAUrD,EAAiB,SAAU,CAChEK,EAAM,KAAK,gBAAgBkF,CAAa,4CAA4C,EACpF,MACJ,CAEA,GAAI,CAAClC,EAAa,CACd,GAAM,CAAE,YAAauS,CAAe,EAAIjQ,EAClCyC,EAAewN,EAAe,iBACpC,KAAK,qBACD,CACI,GAAIrQ,EACJ,WAAYK,EAAgB,yBAAyBgQ,CAAc,EACnE,cAAevN,GAAgCuN,EAAe,aAAa,EAC3E,MAAOA,EAAe,MACtB,iBAAkB1V,EAAM,oBAAoB0V,CAAc,EAC1D,MAAOA,EAAe,OAAS,CAAC,EAChC,WAAYA,EAAe,YAAc,CAAC,EAC1C,gBAAiBA,EAAe,gBAChC,cAAeA,EAAe,eAAiB,CAAC,EAChD,YAAaA,EAAe,aAAe,CAAC,EAC5C,QAAS,KAAK,oBAAoBrQ,EAAeqQ,EAAe,OAAO,CAC3E,EACAxN,CACJ,EAEA/E,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,CAC1D,CAGI,KAAK,eACL,KAAK,cAAc,YAAcrD,GAAc,WAC9C,KAAK,SAAW,QAA0B,KAAK,SAAW,gBAE3D,KAAK,OAAS,SACd,KAAK,kBAAkB,GAG3BmB,EAAY,MAAQrD,EAAiB,SACrCqD,EAAY,cAAgBgF,GAAgC1C,EAAQ,aAAa,EACjFtC,EAAY,iBAAmBnD,EAAM,oBAAoByF,EAAQ,WAAW,EAC5EtC,EAAY,MAAQsC,EAAQ,YAAY,OAAS,CAAC,EAE9C,KAAK,YAAY,YAAYtC,EAAY,EAAE,EAC3C,KAAK,uBAAuB,CAACA,CAAW,aAA8B,EAEtE,KAAK,uBAAuB,CAACA,CAAW,WAA4B,EAMpE,KAAK,SAAW,QAA0B,KAAK,aAC1C,KAAK,WAAW,YAAYA,EAAY,EAAE,GAC3C,KAAK,WAAW,SAASA,EAAY,GAAI,EAAI,EAEjD,KAAK,WAAW,KAAK,CAACA,EAAY,EAAE,EAAG,KAAM,CAAC,CAAC,KAAK,eAAe,QAAQ,GAG/ElB,EAAS,oBAAoBkB,EAAY,WAAYA,EAAY,OAAO,EACxE,MAAM,KAAK,2BAA2BkC,EAAelC,EAAY,aAAa,EAC9E,MAAM,KAAK,8BAA8BkC,EAAelC,EAAY,gBAAgB,EACpF,KAAK,oCAAoCA,CAAW,EACpD,IAAMhC,EAAe,OAAO,KAAKgC,EAAY,UAAU,EACnDhC,EAAa,QACb,KAAK,mBAAmB,CAAE,WAAYgC,EAAY,WAAY,aAAAhC,EAAc,aAAc,GAAM,cAAAkE,CAAc,CAAC,EAEnH,MAAM,KAAK,yBAAyBlC,EAAY,eAAe,CACnE,CAEQ,sBAAsBsC,EAAoD,CAC9E,KAAK,wBAAwB,EAC7B,KAAK,OAAO,IAAI9D,EAAa8D,EAAQ,OAAQ,CAAE,OAAQ,EAAK,CAAC,CAAC,CAClE,CAEA,MAAc,wBAAwBA,EAA+D,CACjG,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EACpD,MAAM,KAAK,gDAAgDJ,EAAeI,EAAQ,OAAO,EACzF,MAAM,KAAK,2BAA2BJ,EAAe8C,GAAgC1C,EAAQ,aAAa,CAAC,CAC/G,CAEA,MAAc,2BAA2BA,EAAkE,CACvG,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EAC9CkQ,EAAY3V,EAAM,oBAAoByF,CAAO,EAE/C,KAAK,MAAMJ,CAAa,EACxB,KAAK,6BAA6BsQ,CAAS,GAE3C,MAAM,KAAK,gDAAgDtQ,EAAeI,EAAQ,OAAO,EACzF,MAAM,KAAK,8BAA8BJ,EAAesQ,CAAS,EAEzE,CAEA,MAAc,4BAA4BlQ,EAAmE,CAEzG,GAAM,CAAE,aAAAjC,EAAc,OAAAd,CAAO,EAAI+C,EAC3BmQ,EAA0BpS,EAAa,IAAI,CAAC,CAAE,GAAA0B,EAAI,QAAA2E,CAAQ,IAAM,KAAK,gDAAgD3E,EAAI2E,CAAO,CAAC,EACvI,MAAM,QAAQ,IAAI+L,CAAuB,EAEzC,IAAMnB,EAAuD,IAAI,IAC3DoB,EAA+ErS,EAAa,IAAI,CAAC,CAAE,GAAA0B,EAAI,iBAAAsP,CAAiB,IAC1H,KAAK,8BAA8BtP,CAAE,EAAE,KAAMoD,GAClC,CAACpD,EAAIoD,GAActI,EAAM,oBAAoB,CAAE,iBAAAwU,CAAiB,CAAC,CAAC,CAC5E,CACL,EAEA,GAAI,EACgB,MAAM,QAAQ,IAAIqB,CAAU,GACpC,QAAQ,CAAC,CAAC3Q,EAAI4Q,CAAW,IAAM,CAC/BA,GACArB,EAAS,IAAIvP,EAAI4Q,CAAW,CAEpC,CAAC,EACD,MAAM,KAAK,gCAAgCrB,EAAU/R,CAAM,CAC/D,OAAS4E,EAAK,CACVnH,EAAM,KAAK,4DAA4DmH,CAAG,EAAE,CAChF,CACJ,CAEQ,aAAoB,CACpB,KAAK,gBACL,KAAK,cAAc,SAAW,GAC9B,KAAK,gBAAgB,EAE7B,CAEQ,qBAAqB7B,EAAmD,CACxE,KAAK,gBACL,KAAK,cAAc,SAAWA,EAAQ,SACtC,KAAK,kBAAkB,EAE/B,CAEQ,yBAAyBA,EAAuD,CAChF,KAAK,gBACL,KAAK,cAAc,OAASA,EAAQ,OACpC,KAAK,wBAAwB,EAC7BxD,EAAS,wBAAwB,KAAK,aAAa,EAE3D,CAEA,MAAc,4BAA4BwD,EAAoD,CAC1F,GAAI,CAAC,KAAK,aACN,OAGJ,IAAMxF,EAAgB,KAAK,aAAa,iBAAiB,EACnD8V,EAAmB5N,GAAgC1C,EAAQ,aAAa,EAC1ExF,EAAc,iBAAmB8V,EAAiB,gBAClD,MAAM,KAAK,aAAa,YAAYA,EAAiB,cAAc,EAEnE9V,EAAc,iBAAmB8V,EAAiB,gBAClD,MAAM,KAAK,aAAa,YAAYA,EAAiB,cAAc,EAEnEnV,EAAO,qBAAuBX,EAAc,yBAA2B8V,EAAiB,wBACxF,MAAM,KAAK,aAAa,sBAAsB,CAC1C,cAAeA,EAAiB,uBAChC,kBAAmBA,EAAiB,2BACpC,aAAcA,EAAiB,qBACnC,CAAC,CAET,CAEQ,kBAAkBtQ,EAA0C,CAChEtF,EAAM,MAAM,mCAAoCsF,CAAO,EAEvD,IAAMuQ,EAAwB,CAAE,OAAQvQ,EAAQ,OAAQ,cAAeA,EAAQ,cAAe,kBAAmBA,EAAQ,iBAAkB,EAC3I,KAAK,gBAAkBwQ,GAAM,KAAK,gBAAiBD,CAAK,EAEpD,KAAK,YACL,KAAK,WAAW,eAAe,KAAK,eAAe,CAE3D,CAEQ,sBAAsBvQ,EAA8C,CACxEtF,EAAM,MAAM,wCAAyCsF,CAAO,EAE5D,IAAMyQ,EAAc,KAAK,MAAMzQ,EAAQ,QAAQ,WAAa,IAAI,EAC1D0Q,EAAe1Q,EAAQ,QAAQ,aAC/B2Q,EAAgB,CAAE,YAAAF,EAAa,aAAAC,CAAa,EAE9CH,EACAvQ,EAAQ,WAAaA,EAAQ,YAAc,SAC3CuQ,EAAQ,CAAE,OAAQ,KAAM,cAAe,KAAM,kBAAmB,OAAO,OAAO,CAAC,EAAG,KAAK,gBAAgB,kBAAmBI,CAAa,CAAE,EAEzIJ,EAAQ,CAAE,OAAQ,OAAO,OAAO,CAAC,EAAG,KAAK,gBAAgB,OAAQI,CAAa,EAAG,cAAe,KAAM,kBAAmB,IAAK,EAElI,KAAK,gBAAkBH,GAAM,KAAK,gBAAiBD,CAAK,EAEpD,KAAK,YACL,KAAK,WAAW,eAAe,KAAK,eAAe,CAE3D,CAEA,MAAc,kBAAkBvQ,EAAyD,CACrF,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EAC9CtC,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EACxDlC,IACAA,EAAY,WAAasC,EAAQ,WACjCtC,EAAY,SAAWsC,EAAQ,UAGnCxD,EAAS,iBAAiB,CAC9B,CAEA,MAAc,eAAewD,EAAsD,CAC/ExD,EAAS,iBAAiBgF,GAAY,MAAO,CAACxB,EAAQ,IAAI,EAC1D,MAAM,KAAK,iBAAiB,CAACA,EAAQ,IAAI,CAC7C,CAEA,MAAc,eAAeA,EAAsD,CAC/E,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EAC9C6C,EAAa,MAAM,KAAK,8BAA8BjD,CAAa,EAEzE,GAAI,CAACiD,EAAY,CACb,KAAK,kCAAkCjD,CAAa,EACpD,MACJ,CAEApD,EAAS,cAAcwD,EAAQ,QAAS6C,EAAY7C,EAAQ,MAAM,CACtE,CAEA,MAAc,cAAcA,EAAqD,CAE7E,GAAI,OAAO,OAAOA,EAAQ,KAAM,KAAK,EACjC,OAGJ,IAAMJ,EAAgBrF,EAAM,iBAAiByF,CAAO,EAC9C6C,EAAa,MAAM,KAAK,8BAA8BjD,CAAa,EAEzE,GAAI,CAACiD,EAAY,CACb,KAAK,kCAAkCjD,CAAa,EACpD,MACJ,CAEApD,EAAS,aAAawD,EAAQ,KAAM6C,EAAY7C,EAAQ,MAAM,CAClE,CAEA,MAAc,cAAc4Q,EAA+B3T,EAAwB,KAA6B,CAC5G,GAAI,CAAC,KAAK,eAAiB,CAAC2T,EACxB,OAGJ,IAAMC,EAAqB,KAAK,cAAc,kBAAkB,IAAI5T,CAAM,EAI1E,GAFkB4T,GAAoB,gBAAkBD,GAAY,eAAiBC,GAAoB,kBAAoBD,GAAY,gBAE1H,CACX,KAAK,cAAc,kBAAkB,IAAI3T,EAAQ2T,CAAU,EAE3D,IAAM/N,EAAa,MAAM,KAAK,8BAA8B+N,EAAW,SAAS,EAC5E/N,EACArG,EAAS,gBACLqG,EACA+N,EAAW,cACXA,EAAW,gBACXA,EAAW,WACXA,EAAW,sBACXA,EAAW,sBACX3T,CACJ,EAEA,KAAK,kCAAkC2T,EAAW,SAAS,CAEnE,CACJ,CAEA,MAAc,kBAAkB,CAAE,YAAAlT,EAAa,cAAAoT,CAAc,EAAmC7T,EAAwB,KAA6B,CACjJ,GAAI,CAAC,KAAK,cACN,OAEJ,IAAM2T,EAAa,KAAK,cAAc,kBAAkB,IAAI3T,CAAM,EAClE,GAAI,GAAC2T,GAAcA,EAAW,gBAAkBE,GAMhD,GAFA,KAAK,cAAc,kBAAkB,IAAI7T,EAAQ,IAAI,EAEjDS,EAAa,CACb,IAAMqT,EAAmB,MAAM,KAAK,8BAA8BrT,CAAW,EAC7ElB,EAAS,gBAAgBS,EAAQ8T,GAAoB,IAAI,CAC7D,MACIvU,EAAS,gBAAgBS,EAAQ,IAAI,CAE7C,CAEA,MAAc,iCAAiD,CAC3D,GAAI,CAAC,KAAK,cACN,OAGJ,IAAMA,EAAS,KAAK,cAAc,OAC5B+T,EAAsB,KAAK,cAAc,0BAA0B,IAAI/T,CAAM,EACnF,GAAI+T,GAAuB,CAAC,KAAK,MAAMA,CAAmB,EAAG,CACzD,IAAMnO,EAAa,MAAM,KAAK,8BAA8BmO,CAAmB,EAC3EnO,GACArG,EAAS,oBAAoBqG,EAAY,GAAO,KAAM5F,CAAM,CAEpE,CACJ,CAEA,MAAM,0BAA0C,CAC5C,GAAI,CAAC,KAAK,cACN,OAGJ,IAAMA,EAAS,KAAK,cAAc,OAC5B2T,EAAa,KAAK,cAAc,kBAAkB,IAAI3T,CAAM,EAElE,GAAI2T,EAAY,CACZ,IAAM/N,EAAa,MAAM,KAAK,8BAA8B+N,EAAW,SAAS,EAC5E/N,EACArG,EAAS,gBACLqG,EACA+N,EAAW,cACXA,EAAW,gBACXA,EAAW,WACXA,EAAW,sBACXA,EAAW,sBACX3T,CACJ,EAEA,KAAK,kCAAkC2T,EAAW,SAAS,CAEnE,MACIpU,EAAS,gBAAgBS,EAAQ,IAAI,CAE7C,CAEA,MAAc,uBAAuC,CACjD,GAAI,CAAC,KAAK,cACN,OAGJ,IAAMA,EAAS,KAAK,cAAc,OAC5BkN,EAAU,KAAK,cAAc,cAAc,IAAIlN,CAAM,EAC3D,GAAIkN,EAAS,CACT,IAAMtH,EAAa,MAAM,KAAK,8BAA8BsH,EAAQ,WAAW,EAC3EtH,GACArG,EAAS,SACL,CACI,WAAAqG,EACA,QAASsH,EAAQ,OACrB,EACAlN,CACJ,CAER,MACIT,EAAS,SAAS,KAAMS,CAAM,CAEtC,CAEA,MAAc,8BAA8C,CACxD,GAAI,CAAC,KAAK,cACN,OAGJ,GAAM,CAAE,OAAAA,CAAO,EAAI,KAAK,cAClB,CAAE,qBAAAmN,CAAqB,EAAI,KAAK,cAChCC,EAAiBD,EAAqB,IAAInN,CAAM,EAGtD,GAAIoN,EAAgB,CAChB,IAAMxH,EAAa,MAAM,KAAK,8BAA8BwH,EAAe,WAAW,EAClFxH,GACArG,EAAS,kBAAkBqG,EAAYwH,EAAe,UAAWpN,CAAM,CAE/E,CACJ,CAEA,MAAc,6BAA6B+C,EAAoE,CAC3G,GAAI,KAAK,cAAe,CACpB,IAAM6C,EAAa,MAAM,KAAK,8BAA8B7C,EAAQ,aAAa,EAEjF,GAAI,CAAC6C,EAAY,CACb,KAAK,kCAAkC7C,EAAQ,aAAa,EAC5D,MACJ,CAEAxD,EAAS,yBAAyBqG,CAAU,CAChD,CACJ,CAEA,MAAc,YAAY7C,EAAgD,CACtE,GAAI,CAAC,KAAK,cACN,OAGJ,IAAMmK,EAAUnK,EAAQ,QAClB/C,EAAS+C,EAAQ,QAAU,KAEjC,KAAK,cAAc,cAAc,IAAI/C,EAAQkN,CAAO,EAEpD,IAAMtH,EAAa,MAAM,KAAK,8BAA8BsH,EAAQ,WAAW,EAE/E,GAAI,CAACtH,EAAY,CACb,KAAK,kCAAkCsH,EAAQ,WAAW,EAC1D,MACJ,CAEA3N,EAAS,aAAaqG,EAAYsH,EAAQ,QAASlN,CAAM,CAC7D,CAEQ,WAAW+C,EAA+C,CAC9D,GAAI,CAAC,KAAK,cACN,OAGJ,IAAM/C,EAAS+C,EAAQ,QAAU,KAE7B/C,IAAW,OACX,KAAK,cAAc,QAAU,MAEjC,KAAK,cAAc,cAAc,OAAOA,CAAM,EAE9CT,EAAS,aAAaS,CAAM,CAChC,CAEA,MAAc,oBAAoBgU,EAAsC,CACpE,GAAI,CAAC,KAAK,cACN,OAGJ,IAAMpO,EAAa,MAAM,KAAK,8BAA8BoO,EAAI,aAAa,EAE7E,GAAI,CAACpO,EAAY,CACb,KAAK,kCAAkCoO,EAAI,aAAa,EACxD,MACJ,CAEAzU,EAAS,mBAAmBqG,EAAYoO,EAAI,KAAMA,EAAI,UAAWA,EAAI,QAAQ,CACjF,CAEA,MAAc,gBAAgBrR,EAA8B+L,EAAkC,CAC1F,GAAI,KAAK,eAAiB,KAAK,MAAM/L,CAAa,GAAK,CAAC8P,GAAiB,KAAK,cAAc,MAAO/D,CAAK,EAAG,CACvGjR,EAAM,MAAM,wBAAwBiR,CAAK,EAAE,EAC3C,KAAK,cAAc,MAAQA,EAC3BnP,EAAS,oBAAoBmP,CAAK,EAGlC,KAAK,kBAAkB,CACnB,aAAc7H,GAA2B,KAAK,6BAA6B,EAAGC,GAAU,cAAc,EACtG,aAAc,EAClB,CAAC,EAEGxJ,EAAM,cAAcoR,EAAO,CAACD,GAAS,MAAOA,GAAS,OAAO,CAAC,EAE7D,KAAK,cAAc,EAAI,EACfC,EAAM,QAEd,KAAK,gBAAgB,IAAY,EAGrC,MACJ,CAEA,IAAMjO,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EACxDlC,GAAe,CAACgS,GAAiBhS,EAAY,MAAOiO,CAAK,IACzDjR,EAAM,MAAM,0BAA0BkF,CAAa,cAAc+L,CAAK,EAAE,EACxEjO,EAAY,MAAQiO,EACpBnP,EAAS,eAAekB,EAAY,WAAYiO,CAAK,EAE7D,CAKA,MAAc,mBAAmB3L,EAA2CyE,EAAc,GAAsB,CAC5G,GAAI,CAAC,KAAK,cACN,OAGJ,GAAM,CAAE,QAAAyM,EAAS,WAAA7R,EAAa,CAAC,EAAG,cAAAsE,EAAgB,CAAC,EAAG,aAAAjI,EAAe,CAAC,EAAG,OAAAuB,EAAS,IAAa,EAAI+C,EAGnG,GAAIA,EAAQ,eAAiB,CAAC,KAAK,MAAMA,EAAQ,aAAa,EAAG,CAC7D,GAAI,CAAC,KAAK,aAAa,EAAG,CACtBtF,EAAM,KAAK,8CAA8CsF,EAAQ,aAAa,GAAG,EACjF,MACJ,CAEA,IAAMtC,EAAc,MAAM,KAAK,gBAAgBsC,EAAQ,aAAa,EACpE,GAAItC,EAAa,CACbhD,EAAM,MAAM,gCAAgCsF,EAAQ,aAAa,YAAaX,CAAU,EACxF,IAAM8R,EAAkBnR,EAAQ,QAAU,MAAM,KAAK,8BAA8BA,EAAQ,OAAO,EAAI,KACtGxD,EAAS,aACL6C,EACAsE,EACAjI,EACAwV,EACAlR,EAAQ,OACRtC,EAAY,WACZyT,EACAnR,EAAQ,aACRA,EAAQ,eACRA,EAAQ,MACZ,CACJ,CACA,MACJ,CAYA,GAVKA,EAAQ,gBAAgB,SACrBkR,GAAW,CAACzM,EAEZ,KAAK,wBAAwBpF,EAAYpC,CAAM,EACvCiU,IACR,KAAK,cAAc,mBAAqB7R,IAK5CW,EAAQ,SAAW,KAAK,MAAMA,EAAQ,OAAO,EAAG,CAE5CkR,GACA1U,EAAS,aACL6C,EACAsE,EACAjI,EACAwV,EACAlR,EAAQ,OACR,KACA,KAAK,cAAc,WACnBA,EAAQ,aACRA,EAAQ,eACRA,EAAQ,MACZ,EAEJ,MACJ,CAEA,MAAM,KAAK,kBAAkB,CACzB,aAAAtE,EACA,QAAAwV,EACA,OAAQlR,EAAQ,OAChB,QAASA,EAAQ,QACjB,aAAcA,EAAQ,aACtB,eAAgBA,EAAQ,eACxB,OAAQA,EAAQ,OAChB,cAAA2D,EACA,WAAAtE,CACJ,CAAC,CACL,CAEQ,yBAAyBpC,EAAiBmU,EAA2B,CACzE,GAAI,CAAC,KAAK,cACN,OAGJ,IAAMC,EAAqB,KAAK,wBAAwBD,CAAU,EAC5DE,EAAiB,KAAK,wBAAwBrU,CAAM,EACpDsU,EAAmB,OAAO,KAAKF,CAAkB,EACjD3V,EAAe,OAAO,KAAK4V,CAAc,EAE/C,KAAK,kBAAkB,CACnB,aAAc,MAAM,KAAK,IAAI,IAAI,CAAC,GAAGC,EAAkB,GAAG7V,CAAY,CAAC,CAAC,EACxE,OAAAuB,EACA,QAAS,GACT,aAAc,EAClB,CAAC,CACL,CAEA,MAAc,kBAAkB+C,EAAmE,CAC/F,GAAI,CAAC,KAAK,eAAiB,CAAC,KAAK,cAAgB,KAAK,oBAAsB3F,EAAiB,SACzF,OAGJ,GAAM,CAAE,aAAAqB,EAAe,CAAC,EAAG,QAAAwV,EAAS,OAAAM,EAAQ,aAAAC,EAAc,eAAA3F,EAAgB,OAAA7O,EAAS,KAAc,cAAA0G,EAAgB,CAAC,CAAE,EAAI3D,EAClHmR,EAAkBnR,EAAQ,QAAU,MAAM,KAAK,8BAA8BA,EAAQ,OAAO,EAAI,KAEhGX,EAAa,OAAO,OAAO,CAAC,EAAGW,EAAQ,YAAc,KAAK,wBAAwB/C,CAAM,CAAC,EACzFzC,EAAgB,KAAK,aAAa,iBAAiB,EACnDkX,EAAc,OAAO,QAAQrS,CAAU,EAG7C,OAAW,CAACsS,EAAaC,CAAS,IAAKF,EAAa,CAEhD,IAAMG,EAAoB1W,EAAO,cAAgB,KAAK,aAAa,GAAK+V,EAExE,GAAK,EAAAU,IAAc7N,GAAU,MAAQ6N,IAAc7N,GAAU,gBAAmB8N,KAM5E,KAAK,aAAa,GAClBD,IAAc7N,GAAU,gBAExB,CAACmN,IAED7R,EAAWsS,CAAW,EAAI5N,GAAU,MAGpC,GAACrI,EAAa,SAASiW,CAAW,GAAKH,IAK3C,OAAQG,EAAa,CACjB,KAAKnQ,GAAY,MACThH,EAAc,iBACdgC,EAAS,iBAAiBgF,GAAY,MAAO,EAAK,EAClD,MAAM,KAAK,iBAAiB,EAAK,GAErC,MAEJ,KAAKA,GAAY,MACThH,EAAc,iBACdgC,EAAS,iBAAiBgF,GAAY,MAAO,EAAK,EAClD,MAAM,KAAK,iBAAiB,EAAK,GAErC,MAEJ,KAAKA,GAAY,eACThH,EAAc,yBACdgC,EAAS,iBAAiBgF,GAAY,eAAgB,EAAK,EAC3D,MAAM,KAAK,uBAAuB,GAEtC,MACJ,KAAKA,GAAY,cACThH,EAAc,wBACdgC,EAAS,iBAAiBgF,GAAY,cAAe,EAAK,EAC1D,MAAM,KAAK,sBAAsB,CAC7B,cAAehH,EAAc,uBAC7B,kBAAmBA,EAAc,2BACjC,aAAc,EAClB,CAAC,GAEL,KACR,CACJ,CAEAgC,EAAS,aAAa6C,EAAYsE,EAAejI,EAAcwV,EAASM,EAAQ,KAAML,EAAiBM,EAAc3F,EAAgB7O,CAAM,CAC/I,CAEA,MAAc,kBAAkB2C,EAA8BoM,EAAQ,GAAO5H,EAAkCnH,EAAwB,KAA6B,CAChK,GAAI,CAAC,KAAK,cACN,OAGJ,IAAM+T,EAAsB,KAAK,cAAc,0BAA0B,IAAI/T,CAAM,EACnF,GAAI+T,GAAuBA,IAAwBpR,EAE/C,GAAI,KAAK,MAAMoR,CAAmB,EAC9BxU,EAAS,WAAW,GAAMS,CAAM,MAC7B,CACH,IAAM4F,EAAa,MAAM,KAAK,8BAA8BmO,CAAmB,EAC3EnO,GACArG,EAAS,oBAAoBqG,EAAY,GAAM,KAAK,oBAAoBjD,EAAewE,CAAO,EAAGnH,CAAM,CAE/G,CAGJ,GAAI,KAAK,MAAM2C,CAAa,EACxBpD,EAAS,WAAWwP,EAAO/O,CAAM,MAC9B,CACH,IAAM4F,EAAa,MAAM,KAAK,8BAA8BjD,CAAa,EACrEiD,GACArG,EAAS,oBAAoBqG,EAAYmJ,EAAO,KAAK,oBAAoBpM,EAAewE,CAAO,EAAGnH,CAAM,CAEhH,CACA,KAAK,cAAc,0BAA0B,IAAIA,EAAQ+O,EAAQ,KAAOpM,CAAa,CACzF,CAEQ,kBAAkBuM,EAAqC,CACvD,KAAK,eAAiB,CAAC2F,GAAe,KAAK,cAAc,QAAS3F,CAAO,IACzE,KAAK,cAAc,QAAUA,EAC7B3P,EAAS,iBAAiB2P,CAAO,EAE7BA,EAAQ,SAASxO,GAAmB,aAAa,EAC7C,KAAK,cAAc,YAAc,KAAK,cAAc,aACpDnB,EAAS,4BAA4C,EAElD2P,EAAQ,SAASxO,GAAmB,cAAc,GACrD,KAAK,cAAc,YACnBnB,EAAS,8BAA8C,EAIvE,CAEA,MAAc,iBAAiBuV,EAAwD,CACnF,GAAI,KAAK,cAAe,CACpB,IAAMC,EAA4D,CAAC,EAC7DxS,EAAqB,MAAM,KAAK,iBAAiB,EACvD,OAAW,CAACI,EAAesE,CAAM,IAAK,OAAO,QAAQ6N,CAAQ,EAAG,CAC5D,IAAIE,EACJ,GAAI,KAAK,MAAMrS,CAAa,GAAKA,IAAkB,GAE/CqS,EAAa,KAAK,cAAc,sBACzBzS,EAAmBI,CAAa,EACvCqS,EAAazS,EAAmBI,CAAa,EAAE,kBAE/C,UAEJ,GAAIqS,IAAe/N,EACf,GAAI,KAAK,MAAMtE,CAAa,GAAKA,IAAkB,GAC/C,KAAK,cAAc,cAAgBsE,EACnCgO,GAAmB,YAAY,EAAE,MAAQhO,EACzC1H,EAAS,4BAA4B0H,CAAM,MACxC,CACH,IAAMxG,EAAc8B,EAAmBI,CAAa,EACpDlC,EAAY,cAAgBwG,EAC5B8N,EAAQ,KAAK,CAAE,IAAKtU,EAAY,WAAY,OAAQwG,CAAO,CAAC,CAChE,CAER,CACA,GAAI8N,EAAQ,SAAW,EACnB,OAGJtX,EAAM,IAAI,mCAAoCqX,CAAQ,EACtDvV,EAAS,uBAAuBwV,CAAO,CAC3C,CACJ,CAEA,MAAc,sBAAsBpS,EAA8B+F,EAA2C,CACzG,IAAMjI,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAC5D,GAAKlC,EAIL,IAAIvC,EAAO,oBAAqB,CAC5BqB,EAAS,qBAAqBkB,EAAY,WAAYiI,CAAM,EAC5D,MACJ,CAIA,GAFAjI,EAAY,aAAeiI,EAEvBxK,EAAO,iBAAmB,EAAG,CAC7B,IAAMsN,EAAoB7I,EAE1B,GAAI,CAAC,KAAK,6BAA6B,IAAI6I,CAAiB,EAAG,CAC3D/N,EAAM,MAAM,6FAA8F+N,CAAiB,EAC3H,MACJ,CAGA,IAAMuC,EAAW,KAAK,6BAA6B,IAAIvC,CAAiB,EACxE,GAAI,CAACuC,GAAY,KAAK,oCAAoC,IAAIvC,CAAiB,EAAG,CAG9E/N,EAAM,IAAI,2EAA4E+N,CAAiB,EACvG,MACJ,CAEA,IAAM0J,EAA4B,KAAK,kBAAkB,IAAInH,CAAQ,EACrE,GAAI,CAACmH,EAA2B,CAC5BxX,EAAO,IAAIsB,EAAQ,UAAW,gBAAgB,EAC9CvB,EAAM,MAAM,gCAAgCsQ,CAAQ,EAAE,EACtD,MACJ,CAEAxO,EAAS,eAAekB,EAAY,WAAYA,EAAY,cAAgByU,CAAyB,CACzG,KAAO,CACH,IAAMC,EAAYzM,GAAUjI,EAAY,aACpC0U,GACA5V,EAAS,eAAekB,EAAY,WAAY0U,CAAS,CAEjE,EACJ,CAOA,MAAc,iBAAiBxS,EAA8B+F,EAA2C,CACpG,GAAI,KAAK,MAAM/F,CAAa,GAAK,KAAK,aAAc,CAEhDpD,EAAS,cAAcmJ,EAAQ,KAAK,aAAa,iBAAiB,CAAC,EACnE,MACJ,CAEA,IAAMjI,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EACvDlC,GAILlB,EAAS,oBAAoBkB,EAAY,WAAYiI,CAAM,CAC/D,CAMA,MAAc,gBAAgBlJ,EAAqB,CAC/C,GAAI,CACA,IAAMoG,EAAa,MAAM,KAAK,8BAA8BpG,EAAM,aAAa,EAC3EoG,IACA,OAAQpG,EAAc,cACtBD,EAAS,aAAa,CAClB,GAAGC,EACH,WAAAoG,CACJ,CAAC,EAET,OAASpI,EAAG,CACRC,EAAM,KAAK,yBAA0BD,CAAC,CAC1C,CACJ,CAEQ,wBAAwB4X,EAAmC,CAC3DA,IAAa,UACb,KAAK,mCAAmC,CAEhD,CAEQ,mBAA0B,CAC9B,GAAI,KAAK,cAAe,CACpB,IAAMC,EAAe,KAAK,SAAW,SAC/BC,EAAqB,KAAK,cAAc,SAAS,SAASC,GAAoB,eAAe,EACnGhW,EAAS,YAAY8V,EAAcC,EAAoB,KAAK,aAAa,CAC7E,CACJ,CAEQ,wBAA+B,CAC/B,KAAK,eACL/V,EAAS,yBAAyB,KAAK,cAAc,iBAAmB,CAAC,CAAC,CAElF,CAEQ,iBAAwB,CACxB,KAAK,eAAiB,KAAK,cAAc,UACzCA,EAAS,aAAa,CAE9B,CAEA,MAAc,mBAAmBiW,EAA6C,CAC1E,IAAMpK,EAA2D,CAAC,EAClE,OAAW,CAACzI,EAAeS,CAAM,IAAK,OAAO,QAAQoS,CAAO,EAAG,CAC3D,IAAM/U,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EACxDlC,GAAeA,EAAY,YAC3B2K,EAAO,KAAK,CACR,IAAK3K,EAAY,WACjB,OAAQ2C,EAAO,IACnB,CAAC,CAET,CACA7D,EAAS,kBAAkB6L,CAAM,CACrC,CAEA,MAAc,kBAAkBqK,EAA+C,CAC3E,KAAK,iBAAmBA,EAExB,IAAMhV,EAAc,MAAM,KAAK,gBAAgBgV,CAAe,EAC1DhV,GAAe,KAAK,gCAAkCgV,IACtDlW,EAAS,iBAAiBkB,EAAY,UAAU,EAChD,KAAK,8BAAgCgV,EAE7C,CAEA,MAAc,yBAAyB5S,EAAiCmE,EAAuB,CAC3FvJ,EAAM,MAAM,gCAAgCuJ,CAAK,GAAInE,CAAc,EAEnE,IAAMoE,EAAS,KAAK,2BAA2BD,CAAK,EAEpD,GAAI,CAACC,EACD,OAGJ,IAAM1E,EAAqB,MAAM,KAAK,iBAAiB,EACjDzB,EAAe+B,EAAe,OAAO,CAACuI,EAAuBzI,IAAkB,CACjF,GAAIA,KAAiBJ,EAAoB,CACrC,IAAM9B,EAAc8B,EAAmBI,CAAa,EACpDyI,EAAO,KAAK3K,CAAW,EAEnBuG,IAAU,cACLvG,EAAY,eACTA,EAAY,eACZ,KAAK,2BAA2BkC,EAAelC,EAAY,aAAa,EAE5E,KAAK,8BAA8BkC,EAAelC,EAAY,gBAAgB,GAElF,KAAK,8BAA8BkC,CAAa,EAExD,MACI,KAAK,kCAAkCA,CAAa,EAGxD,OAAOyI,CACX,EAAG,CAAC,CAAC,EAEAtK,EAAa,QAIlB,KAAK,uBAAuBA,EAAcmG,CAAM,CACpD,CAEA,MAAc,8BAA8BD,EAAuB,CAG/D,GAFAvJ,EAAM,MAAM,sCAAsCuJ,CAAK,EAAE,EAErDA,IAAU,cACVzH,EAAS,yBAAyC,EAC9C,KAAK,YAAY,YAAY,IAAM,UAA0B,CAC7D,IAAMmW,EAAY,OAAO,OAAO,KAAK,uBAAuB,EAC5D,MAAM,KAAK,oBAAoBA,CAAS,CAC5C,CAGA1O,IAAU,cACVzH,EAAS,0BAA0C,EAGnDyH,IAAU,gBACVzH,EAAS,yBAAyC,EAGlDyH,IAAU,UACN,KAAK,YAAc,KAAK,WAAW,UAAU,EAAE,SAAW,IACtD,KAAK,WAAW,OAChB,MAAM,KAAK,WAAW,OAAO/I,EAAW,MAAM,EAElD,KAAK,OAAO,IAAIgB,EAAahB,EAAW,MAAM,EAAG,kBAAkB,EAG/E,CAEA,MAAc,oBAAoB0E,EAAuC+F,EAAqBD,EAAwC,CAClI,GAAI9F,EAAc,SAASgT,GAAQ,SAAS,EACxClY,EAAM,MAAM,8BAA8B,EAC1C,KAAK,aAAa,IAAIgL,CAAK,EAC3BlJ,EAAS,yBAAyBmJ,CAAM,UACjC/F,EAAc,WAAWgT,GAAQ,iCAAiC,EACzElY,EAAM,MAAM,qCAAqCkF,CAAa,EAAE,EAChE,KAAK,kBAAkB,IAAIA,EAAe+F,CAAM,MAC7C,CACHjL,EAAM,MAAM,0CAA0CkF,CAAa,IAAK,CAAE,KAAM8F,EAAM,IAAK,CAAC,EAE5F,IAAIhI,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAE1D,GAAI,CAAClC,EAAa,CACd,IAAMyG,EAAiB,KAAK,KAAK,2BAA2BvE,CAAa,EACnE6C,EAAe0B,EAAiB5J,EAAM,cAAc4J,CAAc,EAAI,OAC5EzJ,EAAM,KAAK,qDAAqDkF,CAAa,mBAAmB6C,CAAY,GAAG,EAC/G,KAAK,qBACD,CACI,GAAI7C,CACR,EACA6C,CACJ,EACA/E,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EACtD,KAAK,uBAAuB,CAAClC,CAAW,WAA4B,EAChE,KAAK,mBAAqBkC,GAAiB,KAAK,gCAAkCA,IAClFpD,EAAS,iBAAiBkB,EAAY,UAAU,EAChD,KAAK,8BAAgCkC,EAE7C,CAiBA,GAfI,KAAK,YAAc,CAAC,KAAK,WAAW,YAAYlC,EAAY,EAAE,GAC9D,KAAK,WAAW,SAASA,EAAY,GAAI,EAAK,EAG9CgI,EAAM,OAAS,UACf,KAAK,aAAa,IAAIA,CAAK,EAEtBvK,EAAO,sBAGRuC,EAAY,iBAAmBgI,EAC/BC,EAAO,YAAYD,CAAK,IAI5BhI,EAAY,eAAiBiI,GAAUA,EAAO,UAAU,EAAE,OAAQ,CAGlE,GAFAjI,EAAY,aAAeiI,EAEvBjI,EAAY,aAGZ,OAGJlB,EAAS,eAAekB,EAAY,WAAYiI,CAAM,CAC1D,CAGIjI,EAAY,eACZ,KAAK,2BAA2BkC,EAAelC,EAAY,aAAa,CAEhF,CACJ,CAEQ,sBAAsBkC,EAA8B+F,EAAqBD,EAA+B,CAE5G,OADAhL,EAAM,MAAM,IAAIkF,CAAa,2BAA4B,CAAE,MAAA8F,CAAM,CAAC,EAC1DA,EAAM,KAAM,CAChB,YACI,KAAK,kBAAkB9F,EAAe+F,EAAQD,CAAK,EACnD,MACJ,YACA,aACI,KAAK,kBAAkB9F,EAAe+F,EAAQD,CAAK,EACnD,KACR,CACJ,CAEA,MAAc,kBAAkB9F,EAAuC+F,EAAqBD,EAAyB,CACjH,GAAI9F,IAAkBgT,GAAQ,UAAW,CACrC,IAAMlV,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EAM5D,GALI,CAAClC,GAKDA,EAAY,cAAgBA,EAAY,eAAiBiI,EACzD,MAER,CAEA,KAAK,aAAa,OAAOD,CAAK,CAClC,CAEQ,kBAAkBmN,EAA+BC,EAAsBC,EAA0B,CAEzG,CAEQ,mBAAmBV,EAA6B,CAChDA,IAAa,WACb,KAAK,wBAAwB,CAAC,CAAC,EAC/B,KAAK,iBAAiB,EAAK,GAE3B,KAAK,gBACL,KAAK,cAAc,SAAWA,EAC9B,KAAK,kBAAkB,EAEvB,KAAK,kCAAkC,EAE/C,CAEQ,iBAAiBW,EAAkB,CACnC,KAAK,mBAAqBA,IAC1B,KAAK,iBAAmBA,EAExBtY,EAAM,MAAM,qBAAsBsY,CAAO,EACzCxW,EAAS,cAAcwW,yBAAmE,EAElG,CAEA,MAAc,wBAAwBC,EAAsC,CACxE,IAAMC,EAA6C,CAAC,EAC9CC,EAA2B,CAAC,EAC5BC,EAA2B,CAAC,EAElC1Y,EAAM,MAAM,wBAAyBuY,CAAmB,EACxD,IAAMzT,EAAqB,MAAM,KAAK,iBAAiB,EAEvD,QAAW6T,KAAOJ,EAAqB,CAEnC,GADAC,EAAWG,CAAG,EAAI,GACd,CAAC,KAAK,aAAaA,CAAG,EAAG,CAEzB,IAAM3V,EAAc8B,EAAmB6T,CAAG,EACtC3V,GACAyV,EAAU,KAAKzV,CAAW,CAElC,CACA,OAAO,KAAK,aAAa2V,CAAG,CAChC,CAGA,QAAWA,KAAO,OAAO,KAAK,KAAK,YAAY,EAAG,CAC9C,IAAM3V,EAAc8B,EAAmB6T,CAAG,EACtC3V,GACA0V,EAAU,KAAK1V,CAAW,CAElC,CAEIyV,EAAU,QACV,KAAK,uBAAuBA,aAAsC,EAElEC,EAAU,QACV,KAAK,uBAAuBA,aAAsC,EAGtE,KAAK,aAAeF,CACxB,CAEA,MAAc,mBAAmBI,EAAmB,CAC5C,KAAK,YACL,KAAK,WAAW,kBAAkBA,EAAO,MAAM,KAAK,iBAAiB,CAAC,EAG1E,KAAK,gBAAgBA,EAAM,SAAS,IAAI,EACxC,KAAK,gBAAgBA,EAAM,SAAS,IAAI,CAC5C,CAEQ,gBAAgBC,EAAmB,CACnC,CAAClO,EAAY,cAAc,GAAK,CAAC,KAAK,WAAa,CAAC,KAAK,cAAc,iBAAiB,EAAE,gBAI9F,KAAK,UAAU,IAAIkO,CAAI,CAC3B,CAEQ,gBAAgBA,EAAmB,CACnC,CAAClO,EAAY,UAAU,GAAK,CAAC,KAAK,WAAa,CAAC,KAAK,cAAc,iBAAiB,EAAE,gBAI1F,KAAK,UAAU,SAASkO,CAAI,CAChC,CAEQ,yBAAgC,CACpC,IAAMtR,EAAS,KAAK,eAAiB,KAAK,cAAc,OAClDuR,EAAavR,GAAU,KAAK,SAAW,SAA4B,GAErEA,IACAvH,EAAM,MAAM,2BAA4B,CAAE,UAAA8Y,EAAW,OAAAvR,CAAO,CAAC,EAC7DzF,EAAS,aAAagX,EAAWvR,CAAM,EAE/C,CAEA,MAAc,8BAA8BrC,EAA8B,CAEtE,GAAI,KAAK,YAAY,YAAY,IAAM,SACnC,OAGJ,IAAMlC,EAAc,MAAM,KAAK,gBAAgBkC,CAAa,EACxDlC,GAAeA,EAAY,sBAAwB,OAAO,KAAKA,EAAY,oBAAoB,EAAE,QACjG,MAAM,KAAK,oBAAoB,OAAO,OAAOA,EAAY,oBAAoB,CAAC,CAEtF,CAEQ,uBAAuBK,EAA6BmG,EAA2B/D,EAAY,KAAM,CACrG,GAAI,CAACpC,EAAa,OACd,OAGJ,IAAMhC,EAAcgC,EAAa,OAAO,CAACsK,EAAiC3K,KAClEA,EAAY,SAAWwG,IACvBxG,EAAY,OAASwG,EACrBmE,EAAO,KAAK3K,EAAY,UAAU,GAE/B2K,GACR,CAAC,CAAC,EAEAtM,EAAY,QAIjBS,EAAS,eAAeT,EAAamI,EAAQ/D,CAAI,CACrD,CAEQ,mBAAmBH,EAA2C,CAC9D,KAAK,eAAiBA,EAAQ,WAC9B,KAAK,cAAc,SAAWA,EAAQ,UAG1CxD,EAAS,kBAAkBwD,EAAQ,QAAQ,CAC/C,CAEA,MAAc,gBAAgBA,EAAwC,CAClE,GAAI,KAAK,eAAe,EACpB,OAGJ,IAAMyT,EAAwD,CAAC,EAE/D,QAAW9L,KAAa,OAAO,KAAK+L,EAAc,EAAuB,CACrE,IAAMC,EAAS3T,EAAQ,QAAQ2H,CAAS,EAEnCgM,IAILF,EAAQ9L,CAA2B,EAAI,CACnC,MAAO,MAAM,QAAQ,IAAIgM,GAAQ,OAAO,IAAI,KAAK,uBAAuB,KAAK,IAAI,CAAC,GAAK,CAAC,CAAC,EACzF,QAASA,GAAQ,QACjB,YAAaA,GAAQ,WACzB,EACJ,CAEAnX,EAAS,eAAeiX,CAAO,CACnC,CAEA,MAAc,eAAezT,EAAuC,CAChE,IAAMhD,EAAO,MAAM,KAAK,uBAAuBgD,EAAQ,MAAQ,IAAI,EAE/DA,EAAQ,OAAO,KAAM8H,GAAUA,IAAU4L,GAAe,MAAM,IAC1D1T,EAAQ,aAAe,QACvB,KAAK,wBAAwBA,EAAQ,WAAYA,EAAQ,MAAM,EAG/DA,EAAQ,aAAe,QACvB,KAAK,eAAe,kBAAkB,IAAIA,EAAQ,OAAQA,EAAQ,UAAU,EAG5EA,EAAQ,UAAY,QACpB,KAAK,eAAe,cAAc,IAAIA,EAAQ,OAAQA,EAAQ,OAAO,GAIxE,KAAK,eAAe,GACrBxD,EAAS,cAAcwD,EAAQ,OAAQA,EAAQ,OAAQhD,EAAMgD,EAAQ,YAAc,IAAI,CAE/F,CAEA,MAAc,uBAAuBhD,EAA0D,CAC3F,GAAI,CAACA,EACD,OAAO,KAGX,IAAM8C,EAAkB,MAAM,QAAQ,IAAI9C,EAAK,gBAAgB,IAAKyC,GAAO,KAAK,8BAA8BA,CAAE,CAAC,GAAK,CAAC,CAAC,EAClHmU,EAAqB,MAAM,QAAQ,IAAI5W,EAAK,mBAAmB,IAAKyC,GAAO,KAAK,8BAA8BA,CAAE,CAAC,GAAK,CAAC,CAAC,EACxHoU,EAAwB,MAAM,QAAQ,IAAI7W,EAAK,sBAAsB,MAAOyC,GAAO,KAAK,8BAA8BA,CAAE,CAAC,GAAK,CAAC,CAAC,EAChIuR,EAAsBhU,EAAK,oBAAwB,MAAM,KAAK,8BAA8BA,EAAK,mBAAmB,EAA+B,OAEzJ,MAAO,CACH,GAAIA,EAAK,GACT,KAAMA,EAAK,KACX,iBAAkBA,EAAK,iBACvB,eAAA8C,EACA,kBAAA8T,EACA,qBAAAC,EACA,aAAc7W,EAAK,cAAc,aAAe,MAAM,KAAK,qCAAqCA,EAAK,YAAY,EAAI,OACrH,OAAQA,EAAK,OACb,WAAYA,EAAK,WACjB,oBAAAgU,EACA,aAAchU,EAAK,aACnB,UAAWA,EAAK,SACpB,CACJ,CAEA,MAAc,2BAA2BgD,EAAmD,CACxF,IAAM0O,EAAiB,KAAK,YAAY,SAAS,EAC3CzR,EAAS+C,EAAQ,QAAU,KAE3B8T,EAAa9T,EAAQ,qBAAqB,IAAKP,GAAOlF,EAAM,YAAYkF,CAAE,EAAE,EAAE,GAAK,CAAC,EACpF4J,EAAsB,MAAM,KAAK,KAAK,sBAAsByK,CAAU,EAExEC,EAAqB/T,EAAQ,kBACjC,GAAIqJ,EAAoB,QAAU0K,GAAoB,SAAW1K,EAAoB,QAAU,CAAC,KAAK,eAAe,EAAG,CACnH,IAAMmF,EAAoB,KAAK,uCAAuCnF,CAAmB,EAEzF0K,GADe,MAAM,KAAK,WAAW,gBAAgBvF,CAAiB,GAC1C,YAChC,CAEA,IAAMwF,EAAoB,MAAM,QAAQ,IACpCD,GAAoB,IAAI,MAAOrW,GAAgB,CAC3C,IAAMkC,EAAgBrF,EAAM,UAAUmD,CAAW,EACjD,OAAO,KAAK,mBACR,CACI,GAAIkC,EACJ,WAAYK,EAAgB,yBAAyBvC,CAAW,EAChE,cAAegF,GAAgChF,EAAY,aAAa,EACxE,iBAAkBnD,EAAM,oBAAoBmD,CAAW,EACvD,MAAOA,EAAY,MACnB,MAAOA,EAAY,OAAS,CAAC,EAC7B,OAAQ,KAAK,2BAA2BgR,CAAc,GAAK,UAC3D,WAAYhR,EAAY,YAAc,CAAC,EACvC,cAAeA,EAAY,eAAiB,CAAC,EAC7C,YAAaA,EAAY,aAAe,CAAC,EACzC,QAAS,KAAK,oBAAoBkC,EAAelC,EAAY,OAAO,EACpE,SAAUT,IAAW,IACzB,EACAS,EAAY,gBAChB,CACJ,CAAC,GAAK,CAAC,CACX,EAEIuW,EAAgB,GACpB,QAAWvW,KAAesW,EAClBtW,EAAY,KAAO,KAAK,eAAe,kBACvCuW,EAAgB,IAGpB,KAAK,4BAA4BvW,CAAW,EAG5C,KAAK,YAAY,SAAS,IAAM,QAAuB,CAAC,KAAK,eAAe,GAC5E,KAAK,eAAesW,EAAmB,EAAI,EAG/C,IAAI1K,EAAiD,CAAC,EAChD4K,EAAmE,CAAC,EAC1E,GAAIlU,GAAS,0BAA2B,CACpC,QAAWmU,KAAqBnU,EAAQ,0BACpC,GAAImU,EAAkB,MAAM,GAAI,CAC5B,IAAM1U,EAAK,KAAK,8BAA8B0U,EAAkB,KAAK,EAAE,EACvED,EAA+B,KAAKzU,CAAE,CAC1C,CAGJ6J,EAAwB,MAAM,QAAQ,IAAI4K,CAA8B,CAC5E,CAMA,GAJID,GACA,MAAM,KAAK,gBAAgBhX,CAAM,EAGjCqM,EAAuB,CACvB,IAAM0H,EAAsB,KAAK,eAAe,0BAA0B,IAAI/T,CAAM,EAEpF,GAAI+T,EAAqB,CACrB,IAAMoD,EAA8B,MAAM,KAAK,8BAA8BpD,CAAmB,EAChG,GAAIoD,GACA,QAAWC,KAAwB/K,EAC/B,GAAIrJ,EAAgB,QAAQmU,EAA6BC,CAAoB,EAAG,CAC5E,KAAK,eAAe,0BAA0B,OAAOpX,CAAM,EAC3D,KACJ,EAGZ,CACJ,CAEA,IAAM0W,EAAgC,CAClC,OAAA1W,EACA,iBAAkB+C,EAAQ,iBAC1B,oBAAAqJ,EACA,kBAAmB9O,EAAM,sBAAsByZ,CAAiB,EAChE,0BAA2BhU,GAAS,0BACpC,sBAAAsJ,CACJ,EAEK,KAAK,eAAe,GACrB9M,EAAS,0BAA0BmX,CAAM,CAEjD,CAOA,MAAc,gBAAgB1W,EAAuBqX,EAAe,GAAO,CAKvE,GAJI,CAAC,KAAK,eAIN,KAAK,cAAc,SAAWrX,EAC9B,OAGJ,IAAMmU,EAAa,KAAK,cAAc,OAGtC,GAFA,KAAK,cAAc,OAASnU,EAExBqX,GAAgB,CAAC,KAAK,eAAe,EAAG,CACxC9X,EAAS,YAAYS,CAAM,EAC3B,MACJ,CAGK,KAAK,eAAe,GACrBT,EAAS,eAAeS,CAAM,EAG9BA,IAAW,MAAQ,CAAC,KAAK,aAAa,GAEtC,MAAM,KAAK,cAAc,EAAK,EAGlC,KAAK,gCAAgC,EACrC,KAAK,yBAAyB,EAC9B,KAAK,yBAAyBA,EAAQmU,CAAU,EAChD,MAAM,KAAK,sBAAsB,EACjC,MAAM,KAAK,6BAA6B,CAC5C,CAEA,MAAc,cAAcmD,EAA2B,CACnD,IAAIzF,EACC,KAAK,eAAe,IACrBA,EAAW,MAAM,KAAK,WAAW,SAASyF,CAAgB,GAE9D,IAAM3X,EAAQkS,GAAU,OAAO,OAAS,CAAC,EACnC0F,EAAwB,CAAC,EAE/B,QAAWxX,KAAQJ,EAAO,CACtB,IAAMK,EAASD,EAAK,IAAM,KAe1B,GAdA,KAAK,wBAAwBA,EAAK,WAAYC,CAAM,EACpD,KAAK,eAAe,kBAAkB,IAAIA,EAAQD,EAAK,YAAc,IAAI,EACzE,KAAK,eAAe,0BAA0B,IAAIC,EAAQD,EAAK,qBAAuB,IAAI,EAEtFA,EAAK,SACL,KAAK,eAAe,cAAc,IAAIC,EAAQD,EAAK,OAAO,EAG1DA,EAAK,eACL,KAAK,eAAe,qBAAqB,IAAIC,EAAQD,EAAK,cAAc,EAExE,KAAK,eAAe,qBAAqB,OAAOC,CAAM,EAGtDsX,EAAkB,CAClB,IAAM/U,EAAqB,MAAM,KAAK,iBAAiB,EACvD,MAAM,KAAK,sBAAsBxC,GAAM,cAAc,cAAc,OAAQ8D,GAAS,CAACtB,EAAmBjF,EAAM,UAAUuG,CAAI,CAAC,CAAC,GAAK,CAAC,EAAG,EAAI,EAE3I,IAAM2T,EAAe,MAAM,KAAK,uBAAuBzX,CAAI,EACvDyX,GACAD,EAAc,KAAKC,CAAY,CAEvC,CACJ,CAEID,EAAc,QAAU,CAAC,KAAK,eAAe,GAC7ChY,EAAS,eAAe,CACpB,CAACkX,GAAe,MAAM,EAAG,CACrB,MAAOc,CACX,CACJ,CAAC,CAET,CAGA,MAAc,YAAYxU,EAAoC,CAC1D,IAAM0U,EAAgC,CAAC,EAEvC,QAAWC,KAAK3U,EAAQ,SAAU,CAC9B,IAAM4U,EAAsC,CAAE,GAAGD,EAAG,MAAO,CAAC,CAAE,EAC9D,QAAW7T,KAAQ6T,EAAE,MAAO,CACxB,IAAM9R,EAAa,MAAM,KAAK,8BAA8B/B,EAAK,aAAa,EAC1E+B,EACA+R,EAAiB,MAAM,KAAK,CAAE,GAAG9T,EAAM,cAAe+B,CAAW,CAAC,EAElE,KAAK,kCAAkC/B,EAAK,aAAa,CAEjE,CACA4T,EAAS,KAAKE,CAAgB,CAClC,CAEApY,EAAS,WAAWkY,EAAU1U,EAAQ,MAAM,CAChD,CAEA,MAAc,kCAAkCA,EAA0D,CACtG,GAAI,CAAC,KAAK,eAAiB,CAACA,EAAQ,yBAA2B,CAACA,EAAQ,gCACpE,OAQJ,GAAM,CAAE,cAAAJ,EAAe,wBAAAiV,EAAyB,gCAAAC,CAAgC,EAAI9U,EAC9EqG,EAAO,KAAK,MAAMzG,CAAa,EAErClF,EAAM,MAAM,sCAAsCkF,CAAa,IAAKI,CAAO,EAE3E,IAAM6C,EAAa,MAAM,KAAK,8BAA8BjD,CAAa,EAEzE,GAAI,CAACiD,EAAY,CACb,KAAK,kCAAkCjD,CAAa,EACpD,MACJ,CAEA,IAAMmV,EAAgB9U,EAAgB,cAAc6U,EAAiCjS,EAAW,SAAS,EAUzG,GARArG,EAAS,uBAAuBqG,EAAYkS,CAAa,EAKzD,KAAK,KAAK,gBAAgBF,EAAyBE,CAAa,EAChE,KAAK,KAAK,gBAAgBF,EAAyBjV,CAAa,EAE5DyG,EACA,KAAK,cAAc,WAAa0O,MAC7B,CAEH,IAAMhX,EAAe,MAAM,KAAK,iBAAiB,EACjDA,EAAa6B,CAAa,EAAE,WAAamV,CAC7C,CACJ,CAEQ,uBAAuB/U,EAA+C,CACtE,CAAC,KAAK,eAAiB,KAAK,cAAc,WAAa,WAI3DtF,EAAM,MAAM,0BAA2BsF,CAAO,EAC9CxD,EAAS,sBAAsBwD,EAAQ,SAAS,EACpD,CAEQ,MAAMJ,EAA8B,CACxC,OAAOA,IAAkB,KAAK,eAAe,eACjD,CAEQ,wBAAwB3C,EAAwB,KAA0B,CAC9E,OAAO,KAAK,eAAe,WAAW,IAAIA,CAAM,GAAK,CAAC,CAC1D,CAEQ,8BAA2C,CAC/C,OAAO,KAAK,wBAAwB,KAAK,eAAe,MAAM,CAClE,CAEQ,wBAAwBoC,EAAyB,CAAC,EAAGpC,EAAwB,KAAc,CAC/F,KAAK,eAAe,WAAW,IAAIA,EAAQoC,CAAU,CACzD,CAEQ,mCAAoC,CAIpC,KAAK,YAAY,YAAY,IAAM,UAA4B,KAAK,YAAY,SAAS,IAAM,QAAuB,CAAC,KAAK,eAAe,GAC3I,KAAK,WAAW,KAAK,KAAK,WAAW,UAAU,EAAG,KAAM,CAAC,CAAC,KAAK,eAAe,SAAU,EAAI,CAEpG,CAEQ,qBAAqBmD,EAA4DC,EAAgC,CACrH,KAAK,qBAAqB,IAAID,EAAW,GAAI,KAAK,mBAAmBA,EAAYC,CAAY,CAAC,CAClG,CAEA,MAAc,kBAAmB,CAC7B,GAAI,KAAK,qBAAqB,KAAM,CAChC,IAAMuS,EAAkB,MAAM,KAAK,KAAK,qBAAqB,OAAO,CAAC,EAC/DjX,EAAe,MAAM,QAAQ,IAAIiX,CAAe,EAEtD,QAAWtX,KAAeK,EACtB,KAAK,qBAAqB,OAAOL,EAAY,EAAE,EAC/C,KAAK,cAAcA,EAAY,EAAE,EAAIA,CAE7C,CAEA,OAAO,KAAK,aAChB,CAEA,MAAc,gBAAgB+B,EAAmB,CAG7C,OAF2B,MAAM,KAAK,iBAAiB,GAE7BA,CAAE,CAChC,CACJ,EArzKIrF,EA7BiBJ,EA6BF,YACfI,EA9BiBJ,EA8BF,oBACfI,EA/BiBJ,EA+BF,iBAAiB,IA/BpC,IAAqBib,EAArBjb,EAo1Ka8O,GAAN,MAAMoM,UAAiC,KAAM,CAGhD,YAAYC,EAAWC,EAAyG,CAC5H,MAAMD,CAAC,EAHX/a,EAAA,KAAS,qBAIL,OAAO,eAAe,KAAM8a,EAAyB,SAAS,EAC9D,KAAK,kBAAoBE,CAC7B,CACJ,ECl9KA,IAAIC,GAA2B,KAC3BC,GAAkD,KAE/C,SAASC,IAAmB,CAC/BF,GAAY,KACZC,GAA0B,IAC9B,CAKA,SAASE,GAAmBC,EAAkB,CAC1C,OAAOA,GAAK,SAAS,GAAG,EAAIA,EAAI,MAAM,EAAG,EAAE,EAAIA,CACnD,CAEA,eAAsBC,GAAoBC,EAA0B,KAAMC,EAAmC,CAEzG,IAAMC,EAAeL,GAAmBG,GAAcG,EAAO,UAAU,EACvE,GAAID,EACA,OAAOA,EAGX,IAAKD,GAAUE,EAAO,UAAY,OAC9B,OAAOA,EAAO,YAAYF,CAAM,EAGpC,GAAI,CAIA,IAAMH,EAAM,KAAK,sFAAsF,EAOjGM,GADO,MALI,MAAM,MAAMN,EAAK,CAC9B,OAAQ,MACR,KAAM,OACN,MAAO,UACX,CAAC,GAC2B,KAAK,IACV,OAAO,CAAC,GAAG,KAClC,GAAI,CAACM,EACD,MAAM,IAAI,MAAM,oBAAoB,EAGxC,OAAAC,EAAM,MAAM,wBAAyBD,CAAQ,EACtCA,CACX,OAASE,EAAG,CACR,OAAAD,EAAM,KAAK,4DAA6DC,CAAC,EAClEH,EAAO,YAAYF,CAAM,CACpC,CACJ,CAEA,eAAeM,IAAmD,CAC9D,OAAIb,IAIAC,KAIJA,GAA0BI,GAAoB,EAC9CL,GAAY,MAAMC,GAClBA,GAA0B,KACnBD,GACX,CAEA,eAAsBc,GAAWC,EAAgBC,EAAiC,CAAC,EAAGC,EAAY,GAAO,CACrG,GAAI,CAAC,OAAO,MAAQ,CAAC,OAAO,UAAU,WAClC,OAGJ,MAAMJ,GAAgC,EAEtC,IAAMK,EAAQC,GAAcJ,EAAQC,EAAQC,CAAS,EAC/CG,EAAO,IAAI,OAAO,KAAK,CAACF,CAAK,EAAG,CAAE,KAAM,mCAAoC,CAAC,EACnF,OAAO,UAAU,WAAW,GAAGlB,EAAS,SAAUoB,CAAI,CAC1D,CAEA,eAAsBC,GAAQN,EAAgBC,EAAiC,CAAC,EAAGC,EAAY,GAAOK,EAAyB,CAC3H,MAAMT,GAAgC,EAEtC,IAAMK,EAAQC,GAAcJ,EAAQC,EAAQC,CAAS,EACrD,OAAOM,GAAsBL,EAAOI,CAAc,CACtD,CAEA,eAAeC,GAAsBL,EAAeI,EAAyB,CACzE,IAAMlB,EAAM,GAAGkB,GAAkBtB,EAAS,SAEpCwB,EAAkB,IAAI,gBAEtBC,EAAY,WAAW,IAAMD,EAAgB,MAAM,IAAIE,EAAaC,EAAW,aAAa,CAAC,EAAGlB,EAAO,UAAU,EAEjHmB,EAAW,MAAM,MAAMxB,EAAK,CAC9B,OAAQ,OACR,QAAS,CACL,eAAgB,mCACpB,EACA,KAAMc,EACN,OAAQM,EAAgB,MAC5B,CAAC,EAED,aAAaC,CAAS,EAEtB,IAAMI,EAAe,MAAMD,EAAS,KAAK,EACrCE,EAEJ,GAAI,CACAA,EAAe,KAAK,MAAMD,CAAY,CAC1C,MAAQ,CACJC,EAAe,CAAE,OAAQD,CAAa,CAC1C,CAEA,GAAI,CAACD,EAAS,IAAM,OAAO,OAAOE,EAAc,WAAW,EACvD,MAAMA,EAGV,OAAOA,CACX,CAEA,eAAsBC,GAAa3B,EAAa4B,EAAgB,CAC5D,GAAI,CACA,IAAMJ,EAAW,MAAM,MAAMxB,EAAK,CAC9B,OAAQ,OACR,KAAM4B,CACV,CAAC,EAED,GAAI,CAACJ,EAAS,GACV,MAAM,IAAI,MAAM,uBAAuBA,EAAS,MAAM,EAAE,EAG5D,IAAMK,EAAO,MAAML,EAAS,KAAK,EACjCjB,EAAM,MAAM,8BAA+BsB,CAAI,CACnD,OAAS,EAAG,CACR,MAAAtB,EAAM,KAAK,2BAA4B,CAAC,EAClC,CACV,CACJ,CAEA,SAASQ,GAAcJ,EAAgBC,EAAiC,CAAC,EAAGC,EAAY,GAAO,CAC3FD,EAAO,OAASD,EAChBC,EAAO,OAAS,OACXA,EAAO,kBACRA,EAAO,gBAAkBP,EAAO,QAG/BQ,IACGiB,GAAS,WACTlB,EAAO,YAAckB,GAAS,WACvBA,GAAS,cAChBlB,EAAO,aAAekB,GAAS,cAIvC,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQpB,CAAM,EACxC,OAAOoB,GAAU,WACjBpB,EAAOmB,CAAG,EAAI,KAAK,UAAUC,CAAK,GAI1C,IAAIlB,EAAQ,GACZ,OAAW,CAACiB,EAAKC,CAAK,IAAK,OAAO,QAAQpB,CAAM,EACxCE,IACAA,GAAS,KAEbA,GAAS,GAAGiB,CAAG,IAAI,mBAAmBC,CAAK,CAAC,GAGhD,OAAOlB,CACX,CC5IA,IAA8BmB,GAA9B,KAAsC,CA0BlC,MAAM,eAAeC,EAAwD,CAEzE,MAAO,CAAE,UAAW,KAAM,CAC9B,CACA,MAAM,eAAeA,EAAuD,CAExE,MAAO,CAAE,QAAS,EAAK,CAC3B,CACA,MAAM,qBAAqBC,EAAkBC,EAAoC,CAE7E,MAAO,EACX,CAWA,IAAIC,EAAwB,CAE5B,CAKA,eAAeA,EAA4B,CAE3C,CAKA,gBAAgBA,EAA4B,CAE5C,CAUA,0BAA0BC,EAA8C,CACpE,OAAO,IACX,CAEA,gBAAgBC,EAAyDD,EAAyC,CAElH,CAEA,gBAAgBE,EAA0DC,EAAwC,CAElH,CAEA,kBAAkBD,EAAgE,CAElF,CAEA,2BAA2BC,EAAwE,CAEnG,CAEA,6BAA6BC,EAA0D,CACnF,OAAO,OAAOA,GAAO,SAAW,SAASA,EAAI,EAAE,EAAIA,CACvD,CAEA,mBAAmBR,EAAwBS,EAAqBC,EAAW,OAAc,CAEzF,CAEA,sBAAsBV,EAAwBW,EAAsBF,EAAiBG,EAAoC,CAEzH,CAEA,MAAM,qBAAqBC,EAAoC,CAG/D,CAEA,MAAM,eAAiC,CACnC,OAAO,KAAK,IAAI,CACpB,CAEA,SAAgB,CAEhB,CAGJ,EChHA,IAAMC,GAAsB,IACtBC,GAAoB,IAELC,GAArB,cAAiCC,EAAQ,CAAzC,kCACIC,EAAA,KAAQ,UAA2B,MACnCA,EAAA,KAAQ,SAERA,EAAA,KAAQ,qBAAqB,IAAI,KACjCA,EAAA,KAAQ,2BAA2B,IAAI,KACvCA,EAAA,KAAQ,2BAA2B,IAAI,KAEvC,MAAc,YAAYC,EAAgBC,EAAY,CAAC,EAAGC,EAAY,GAAqB,CACvF,IAAMC,EAAe,MAAOC,GAAoB,CAC5C,GAAI,CACA,OAAO,MAAmBC,GAAQL,EAAQC,EAAMC,CAAS,CAC7D,OAASI,EAAY,CACjB,GAAI,CAAC,OAAO,OAAOA,EAAO,WAAW,EAAG,CACpCF,IACA,IAAMG,EAAU,OAAO,oBAAoBD,CAAK,EAAE,IAAKE,GAAQ,GAAGA,CAAG,KAAK,KAAK,UAAUF,EAAME,CAAG,CAAC,CAAC,EAAE,EAEtG,GADAC,EAAM,MAAM,GAAGT,CAAM,2BAA2BI,CAAO,KAAKG,EAAQ,KAAK;AAAA,GAAM,CAAC,EAAE,EAC9EH,EAAUM,EAAO,cACjB,aAAMC,EAAM,MAAM,KAAK,IAAIP,EAAUT,GAAqBC,EAAiB,CAAC,EACrEO,EAAQC,CAAO,CAE9B,CAEA,MAAAK,EAAM,KAAKT,EAAQ,QAASM,CAAK,EAC3BA,CACV,CACJ,EACA,OAAOH,EAAQ,CAAC,CACpB,CAEA,MAAgB,MAAMH,EAAgBC,EAAY,CAAC,EAAGC,EAAY,GAAqB,CACnF,GAAI,CACA,OAAO,MAAM,KAAK,YAAYF,EAAQC,EAAMC,CAAS,CACzD,OAASI,EAAY,CACjBG,EAAM,KAAK,iBAAkBH,CAAK,EAClC,IAAIM,EAAgCC,GAAW,IAE/C,OAAQP,EAAM,WAAY,CACtB,IAAK,KACL,IAAK,KACL,IAAK,KACD,aAAM,KAAK,UAAU,EACd,KAAK,YAAYN,EAAQC,EAAMC,CAAS,CACvD,CAEA,IAAMY,EAAqC,CAAE,QAASR,EAAM,UAAW,KAAMA,EAAM,UAAW,EAE9F,GAAIA,aAAiBS,EACjB,MAAMT,EAOV,GAJIA,EAAM,eACNQ,EAAiB,aAAeR,EAAM,cAGtCU,GAAWV,CAAK,EAChB,OAAQA,EAAM,WAAY,CACtB,IAAK,MACDM,EAAOK,EAAW,iBAClB,MAEJ,IAAK,GACGX,EAAM,UAAU,SAAS,6BAA6B,IACtDM,EAAOK,EAAW,2BAEtB,MAEJ,IAAK,KACDL,EAAOK,EAAW,UAClB,MAEJ,IAAK,MACDL,EAAOK,EAAW,kBAClB,MAEJ,IAAK,MACDL,EAAOK,EAAW,YAClB,MAEJ,IAAK,MACL,IAAK,MACDL,EAAOK,EAAW,mBAClB,MAEJ,IAAK,MACDL,EAAOK,EAAW,mBAClB,MAEJ,IAAK,MACDL,EAAOK,EAAW,qBAClB,MAEJ,IAAK,GACDL,EAAOK,EAAW,oBAClB,KACR,CAGJ,MAAM,IAAIF,EAAaH,EAAME,CAAgB,CACjD,CACJ,CAEA,MAAe,OAAOI,EAA8D,CAChF,IAAIC,EAAiBR,EAAM,YAAYO,CAAa,EAEpD,GAAIE,GAAS,QAAQ,EACjB,OAAOC,EAAgB,OAAO,OAAOF,CAAI,CAAC,EAIzC,KAAK,mBAAmB,IAAIA,CAAI,GACjC,MAAM,KAAK,uBAAuB,CAACA,CAAI,CAAC,EAG5C,IAAMG,EAAiB,KAAK,2BAA2BH,CAAI,EAC3D,OAAIG,IACAH,EAAOG,GAGJD,EAAgB,WAAW,KAAK,mBAAmB,IAAIF,CAAI,CAAqB,CAC3F,CAEA,MAAe,WAA2B,CAGtC,GAFA,KAAK,YAAY,EAEb,CAACT,EAAO,OACR,MAAM,IAAIK,EAAaF,GAAW,IAAK,CACnC,QAAS,wCACb,CAAC,EAGL,IAAMU,EAAe,CACjB,aAAc,CACV,QAAS,EACT,UAAW,KAAK,MAChB,eAAgBb,EAAO,WACvB,YAAa,QACjB,CACJ,EAEA,OAAIA,EAAO,YACPa,EAAQ,aAAa,WAAab,EAAO,UACzCa,EAAQ,aAAa,QAAU,GAG5B,KAAK,YAAY,mBAAoBA,EAAS,EAAI,EACpD,KAAMC,GAAkB,CACjBA,EAAS,MACT,KAAK,QAAU,OAAOA,EAAS,GAAG,GAEtCJ,GAAS,WAAaI,EAAS,YAC/BJ,GAAS,iBAAmBI,EAAS,kBACzC,CAAC,EACA,MAAOlB,GAAU,CACd,MAAIA,EAAM,aAAe,KACrBmB,EAAS,eAAe,EAEtB,IAAIV,EAAaF,GAAW,KAAM,CAAE,QAASP,EAAM,UAAW,KAAMA,EAAM,UAAW,CAAC,CAChG,CAAC,CACT,CAES,IAAIoB,EAAwB,CACjC,IAAMzB,EAAO,CACT,UAAW,uBACX,KAAM,KAAK,UAAU,CACjB,YAAa,GAAGS,EAAO,OAAO,IAAIA,EAAO,UAAU,GACnD,SAAUA,EAAO,SACjB,MAAAgB,CACJ,CAAC,CACL,EACaC,GAAW,kBAAmB1B,CAAI,CACnD,CAES,eAAeyB,EAA4B,CAChD,IAAMzB,EAAO,CACT,YAAa,OAAOS,EAAO,UAAU,EACrC,SAAU,MACV,YAAaA,EAAO,WACpB,QAAS,EACT,MAAAgB,CACJ,EAEIhB,EAAO,sBACPT,EAAK,SAAWS,EAAO,qBAG3B,IAAMkB,EAAU,CACZ,KAAM,KAAK,UAAU3B,CAAI,CAC7B,EAuBa0B,GAAW,oBAAqBC,CAAO,CACxD,CAES,gBAAgBF,EAA4B,CACjD,IAAMzB,EAAO,CACT,YAAa,OAAOS,EAAO,UAAU,EACrC,SAAU,MACV,YAAaA,EAAO,WACpB,QAAS,EACT,MAAAgB,CACJ,EAEIhB,EAAO,sBACPT,EAAK,SAAWS,EAAO,qBAG3B,IAAMkB,EAAU,CACZ,KAAM,KAAK,UAAU3B,CAAI,CAC7B,EAEa0B,GAAW,qBAAsBC,CAAO,CACzD,CAEA,MAAe,gBAAgBC,EAAwBC,EAAmBC,EAAiBC,EAA4B,CACnH,IAAM/B,EAA8B,CAChC,eAAA4B,EACA,eAAgBnB,EAAO,SACvB,UAAAoB,EACA,QAAAC,CACJ,EAEME,EAAqC,MAAM,KAAK,YAAY,wBAAyBhC,CAAI,EAEzFiC,EAAW,IAAI,SACfC,EAAU,IAAI,KAAK,CAACH,CAAG,EAAG,CAAE,KAAM,kBAAmB,CAAC,EAC5DE,EAAS,OAAO,OAAQC,EAAS,UAAU,EAE3C,IAAMC,EAAY,IAAI,IAAIH,EAAU,UAAU,EAC9C,OAAAG,EAAU,aAAa,OAAO,OAAQD,EAAQ,KAAK,SAAS,CAAC,EAEzCE,GAAaD,EAAU,SAAS,EAAGF,CAAQ,CACnE,CAEA,MAAe,iBAAiBL,EAAwBS,EAAU,GAAOC,EAAgD,CACrH,IAAMtC,EAAY,CACd,eAAA4B,EACA,QAAAS,EACA,gBAAiB5B,EAAO,gBACxB,aAAc8B,GAAsB,SAAS,CACjD,EAEA,OAAID,IACAtC,EAAK,OAASsC,GAGX,KAAK,MAAM,yBAA0BtC,CAAI,CACpD,CAEA,MAAe,mBACX4B,EACAY,EAAU,GACVC,EAAoB,GACpB,CACI,uBAAAC,EACA,aAAAC,EACA,UAAAC,EACA,aAAAC,EACA,mBAAAC,CACJ,EAMI,CAAC,EACLC,EAC6B,CAC7B,IAAM/C,EAAY,KAAK,6BAA6B,CAChD,eAAA4B,EACA,QAAS,GACT,eAAgB,GAChB,QAAAY,EACA,kBAAAC,EACA,uBAAAC,EACA,aAAAG,EACA,mBAAAC,EACA,aAAAH,EACA,UAAAC,EACA,WAAAG,CACJ,CAAC,EAED,OAAO,KAAK,mBAAmB/C,CAAI,CACvC,CAEA,MAAe,kBACX4B,EACAoB,EACArC,EACA0B,EAAU,GACVG,EAAU,GACVS,EAAiB,GACjBR,EAAoB,GACpB,CAAE,uBAAAC,EAAwB,aAAAG,CAAa,EAAkE,CAAC,EAC1GK,EAC6B,CAC7B,IAAMlD,EAAY,KAAK,6BAA6B,CAChD,eAAA4B,EACA,QAAAS,EACA,eAAAY,EACA,QAAAT,EACA,kBAAAC,EACA,uBAAAC,EACA,aAAAG,EACA,YAAAK,CACJ,CAAC,EAED,GAAIF,GAAOA,EAAI,OACX,OAAQrC,EAAM,CACV,KAAKwC,GAAS,KACVnD,EAAK,KAAOgD,EAAI,KAAK,GAAG,EACxB,MACJ,KAAKG,GAAS,MACVnD,EAAK,IAAMgD,EAAI,CAAC,EAChB,MACJ,KAAKG,GAAS,KACVnD,EAAK,OAASgD,EAAI,CAAC,EACnB,KACR,CAGJ,OAAO,KAAK,mBAAmBhD,CAAI,CACvC,CAEU,aAAc,CACpB,GAAI,CAAC,KAAK,MAAO,CACb,IAAIoD,EAAOC,GAAa,IAAI,MAAM,EAC7BD,IACDA,EAAO1C,EAAM,KAAK,EAClB2C,GAAa,IAAI,OAAQD,CAAI,GAEjC,KAAK,MAAQ,OAAOA,CAAI,CAC5B,CACJ,CAES,UAAmB,CACxB,YAAK,YAAY,EACV,KAAK,KAChB,CAEQ,6BAA6B,CACjC,eAAAxB,EACA,QAAAS,EACA,QAAAG,EAAU,GACV,eAAAS,EAAiB,GACjB,kBAAAR,EAAoB,GACpB,uBAAAC,EACA,aAAAG,EACA,aAAAF,EAAe,GACf,UAAAC,EAAY,GACZ,WAAAG,EAAa,CAAC,EACd,mBAAAD,EAAqB,GACrB,YAAAI,CACJ,EAaG,CACC,IAAMlD,EAAY,CACd,eAAA4B,EACA,QAAAS,EACA,gBAAiB5B,EAAO,eAC5B,EAsCA,GApCIwC,IACAjD,EAAK,eAAiB,IAGtBwC,IACAxC,EAAK,QAAUwC,GAGf/B,EAAO,SACPT,EAAK,SAAWS,EAAO,QAGvBA,EAAO,iBACPT,EAAK,eAAiBS,EAAO,gBAG7BgC,IACAzC,EAAK,kBAAoB,IAGzB0C,IAA2B,SAC3B1C,EAAK,uBAAyB0C,GAG9BG,IAAiB,SACjB7C,EAAK,aAAe6C,GAGpBF,IACA3C,EAAK,aAAe2C,GAGpBC,IACA5C,EAAK,UAAY4C,GAGjBG,EAAW,OAAQ,CACnB,IAAMO,EAAiBP,EAAW,IAAKQ,GAAO7C,EAAM,cAAc6C,CAAE,CAAC,EACrEvD,EAAK,WAAasD,EAAe,KAAK,GAAG,CAC7C,CAEA,OAAIR,IACA9C,EAAK,OAAS8C,GAGdI,IACAlD,EAAK,YAAckD,EAAY,IAAI9B,EAAgB,WAAW,EAAE,KAAK,GAAG,GAGrEpB,CACX,CAEA,MAAc,mBAAmBA,EAA6C,CAC1E,OAAO,KAAK,MAAM,0BAA2BA,CAAI,CACrD,CAEA,MAAe,eAAe4B,EAAwD,CAClF,OAAO,KAAK,MAAM,uBAAwB,CACtC,eAAAA,CACJ,CAAC,CACL,CAEA,MAAe,eAAeA,EAAuD,CACjF,OAAO,KAAK,MAAM,uBAAwB,CACtC,eAAAA,CACJ,CAAC,CACL,CAEA,MAAe,qBAAqB4B,EAAkBC,EAAoC,CACtF,IAAMzD,EAAY,CAAE,SAAAwD,CAAS,EAEzBC,IACAzD,EAAK,WAAayD,GAGtB,IAAMlC,EAAW,MAAM,KAAK,MAAM,6BAA8BvB,CAAI,EACpE,YAAK,QAAU,OAAOuB,EAAS,GAAG,EAE3BA,EAAS,KACpB,CAGA,MAAe,uBAAuBiC,EAAkBnB,EAAU,GAAOqB,EAAgClB,EAAiD,CACtJ,IAAMxC,EAAY,CACd,SAAAwD,EACA,QAAAnB,EACA,gBAAiB5B,EAAO,gBACxB,aAAc8B,GAAsB,SAAS,CACjD,EAEA,OAAImB,GAAa,SACb1D,EAAK,YAAc0D,EAAY,KAAK,GAAG,GAEvCjD,EAAO,cACPT,EAAK,YAAcS,EAAO,aAE1B+B,IACAxC,EAAK,QAAUwC,GAGZ,KAAK,MAAM,+BAAgCxC,CAAI,CAC1D,CAOA,MAAe,sBAAsBkD,EAAgD,CACjF,IAAMS,EAAqB,CAAC,EACtBC,EAA4D,CAAC,EAC7DC,EAAuB,IAAI,IAE3BC,EAAc,MAAM,KAAK,KAAK,mBAAmB,KAAK,CAAC,EACvDC,EAAoB,MAAM,KAAK,KAAK,mBAAmB,OAAO,CAAC,EAErE,QAAWC,KAAcd,EAAa,CAClC,IAAMe,EAAW7C,EAAgB,SAAS4C,CAAU,EAC9CE,EAAQH,EAAkB,QAAQE,CAAQ,EAC5CC,EAAQ,GAERP,EAAO,KAAK,KAAK,6BAA6BG,EAAYI,CAAK,CAAC,CAAC,GAEjEL,EAAqB,IAAI,OAAOG,EAAW,EAAE,EAAGC,CAAQ,EACxDL,EAAY,KAAK,CACb,GAAII,EAAW,GACf,UAAWA,EAAW,OAAS,QACnC,CAAC,EAET,CAEA,OAAKJ,EAAY,SAKiG,MAAM,KAAK,MAAM,8BAA+B,CAC9J,YAAaA,CACjB,CAAC,GAEQ,IAAI,QAAQ,CAACO,EAAMC,IAAM,CAC9B,IAAMC,EAAM,OAAOF,EAAK,UAAU,EAC5BH,EAAa,OAAOG,EAAK,iBAAiB,EAAE,EAC9CN,EAAqB,IAAIG,CAAU,IAGnC,KAAK,gBAAgBK,EAAKjD,EAAgB,WAAWyC,EAAqB,IAAIG,CAAU,CAAqB,CAAC,EAC9GL,EAAO,KAAKU,CAAG,EAEvB,CAAC,EAEMV,CACX,CAEA,MAAe,+BAA+BT,EAAoE,CAC9G,MAAM,KAAK,sBAAsBA,CAAW,EAE5C,IAAMS,EAAS,IAAI,IACbG,EAAc,MAAM,KAAK,KAAK,mBAAmB,KAAK,CAAC,EACvDC,EAAoB,MAAM,KAAK,KAAK,mBAAmB,OAAO,CAAC,EAErE,QAAWC,KAAcd,EAAa,CAClC,IAAMe,EAAW7C,EAAgB,SAAS4C,CAAU,EAC9CE,EAAQH,EAAkB,QAAQE,CAAQ,EAChD,GAAIC,EAAQ,GAAI,CAEZ,IAAMjD,EAAgBP,EAAM,qBAAqB,KAAK,6BAA6BoD,EAAYI,CAAK,CAAC,EAAGI,GAAS,KAAMN,EAAW,SAAS,EAC3IL,EAAO,IAAIK,EAAY/C,CAAa,CACxC,CACJ,CAEA,OAAO0C,CACX,CAMA,MAAe,sBAAsBY,EAAoD,CACrF,IAAMZ,EAAkC,CAAC,EACnCa,EAA0B,CAAC,EAEjC,QAAWH,KAAOE,EACd,GAAI,KAAK,mBAAmB,IAAIF,CAAG,EAAG,CAClC,IAAMI,EAAe,KAAK,2BAA2BJ,CAAG,EAClDK,EAAiB,KAAK,mBAAmB,IAAID,GAAgBJ,CAAG,EACtEV,EAAO,KAAKvC,EAAgB,WAAWsD,CAAc,CAAC,CAC1D,MACIF,EAAY,KAAKH,CAAG,EAI5B,GAAI,CAACG,EAAY,OAEb,OAAOb,EAGX,IAAMpC,EAAW,MAAM,KAAK,uBAAuBiD,CAAW,EAE9D,OAAO,MAAM,KAAKjD,EAAS,OAAO,CAAC,CACvC,CAES,0BAA0ByC,EAA8C,CAC7E,IAAMF,EAAc,MAAM,KAAK,KAAK,mBAAmB,KAAK,CAAC,EACvDC,EAAoB,MAAM,KAAK,KAAK,mBAAmB,OAAO,CAAC,EAE/DE,EAAW7C,EAAgB,SAAS4C,CAAU,EAC9CE,EAAQH,EAAkB,QAAQE,CAAQ,EAEhD,OAAIC,EAAQ,GAEDxD,EAAM,qBAAqB,KAAK,6BAA6BoD,EAAYI,CAAK,CAAC,EAAGI,GAAS,KAAMN,EAAW,SAAS,EAEzHE,EAAQ,GAAKxD,EAAM,qBAAqBoD,EAAYI,CAAK,EAAGI,GAAS,KAAMN,EAAW,SAAS,EAAI,IAC9G,CAES,gBAAgB/C,EAA2D+C,EAAyC,CACzH,IAAM9C,EAAOR,EAAM,YAAYO,CAAa,EAC5C,KAAK,mBAAmB,IAAIC,EAAME,EAAgB,SAAS4C,CAAU,CAAC,CAC1E,CAES,gBAAgBS,EAA0DE,EAA6D,CAC5I,IAAMtD,EAAiBX,EAAM,YAAY+D,CAAY,EAC/CvD,EAAOR,EAAM,YAAYiE,CAAS,EAExC,KAAK,yBAAyB,IAAItD,EAAgBH,CAAI,EACtD,KAAK,yBAAyB,IAAIA,EAAMG,CAAc,CAC1D,CAES,kBAAkBsD,EAA6D,CACpF,IAAMzD,EAAOR,EAAM,YAAYiE,CAAS,EAClCF,EAAe,KAAK,2BAA2BvD,CAAI,EAErDuD,GACA,KAAK,yBAAyB,OAAOA,CAAY,EAGrD,KAAK,yBAAyB,OAAOvD,CAAI,CAC7C,CAES,2BAA2ByD,EAA6E,CAC7G,IAAMzD,EAAOR,EAAM,YAAYiE,CAAS,EACxC,OAAO,KAAK,yBAAyB,IAAIzD,CAAI,CACjD,CAES,6BAA6BqC,EAA0D,CAC5F,IAAMrC,EAAOR,EAAM,YAAY6C,CAAE,EACjC,OAAO,KAAK,yBAAyB,IAAIrC,CAAI,GAAKA,CACtD,CAEA,MAAe,sBAAsBU,EAAsD,CACvF,IAAM5B,EAAY,CAAC,EACnB,OAAIS,EAAO,cACPT,EAAK,YAAcS,EAAO,aAE1BmB,IACA5B,EAAK,eAAiB4B,GAEnB,KAAK,MAAM,8BAA+B5B,CAAI,CACzD,CAES,WAA6B,CAClC,OAAO,KAAK,OAChB,CAES,UAAU4E,EAAwB,CACvC,KAAK,QAAUA,CACnB,CAES,mBAAmBhD,EAAwBiD,EAAqB7D,EAAW,OAAc,CAC9F,IAAMhB,EAAY,CACd,eAAA4B,EACA,OAAAiD,CACJ,EACIpE,EAAO,cACPT,EAAK,YAAcS,EAAO,aAEjBiB,GAAW,2BAA4B1B,CAAI,CAC5D,CAES,sBAAsB4B,EAAwBkD,EAAsBD,EAAiBE,EAAoC,CAC9H,IAAM/E,EAAO,CACT,UAAW,2BACX,KAAM,KAAK,UAAU,CACjB,YAAa,GAAGS,EAAO,OAAO,IAAIA,EAAO,UAAU,GACnD,SAAUA,EAAO,SACjB,MAAO,CACH,CACI,KAAM,EACN,UAAWuE,EAAK,uBAChB,UAAW,KAAK,IAAI,EACpB,OAAQ,CACJ,KAAMpD,EACN,cAAekD,EACf,OAAAD,EACA,uBAAwBE,CAC5B,CACJ,CACJ,CACJ,CAAC,CACL,EAEarD,GAAW,kBAAmB1B,CAAI,CACnD,CAEA,MAAe,qBAAqBiF,EAAoC,CACpE,MAAM,KAAK,MAAM,6BAA8B,CAC3C,UAAWA,EAAU,KAAK,GAAG,CACjC,CAAC,CACL,CAES,SAAgB,CAKrB,KAAK,yBAA2B,IAAI,IACpC,KAAK,yBAA2B,IAAI,GACxC,CAIA,MAAc,uBAAuBV,EAAiE,CAClG,IAAMZ,EAAS,IAAI,IAGnBY,EAAOA,EAAK,IAAKrD,GAAS,KAAK,2BAA2BA,CAAI,GAAKA,CAAI,EAEvE,GAAI,CACA,IAAMK,EAAW,MAAM,KAAK,MAAM,8BAA+B,CAC7D,KAAMgD,EAAK,KAAK,GAAG,CACvB,CAAC,EAEKW,EAAgB,CAAChC,EAAwCvC,IAAyB,CACpF,OAAW,CAAC0D,EAAKc,CAAW,IAAK,OAAO,QAAQjC,CAAW,EAAG,CAC1D,IAAMkC,EAAW,OAAOf,CAAG,EACrBL,EAAa5C,EAAgB,OAAO+D,EAAaxE,CAAI,EAC3DgD,EAAO,IAAIyB,EAAUpB,CAAU,EAE/B,KAAK,gBAAgBoB,EAAUpB,CAAU,CAC7C,CACJ,EAEIzC,EAAS,cACT2D,EAAc3D,EAAS,mBAAiC,EAGxDA,EAAS,YACT2D,EAAc3D,EAAS,mBAAiC,EAI5D,QAAW8C,KAAOE,EAAM,CACpB,IAAMa,EAAW,OAAOf,CAAG,EAC3B,GAAI,CAACV,EAAO,IAAIyB,CAAQ,EAAG,CACvB,IAAMC,EAAwBjE,EAAgB,OAAO,OAAOgE,CAAQ,CAAC,EACrEzB,EAAO,IAAIyB,EAAUC,CAAqB,EAE1C,KAAK,gBAAgBD,EAAUC,CAAqB,CACxD,CACJ,CAEA,OAAO1B,CACX,MAAY,CACR,OAAOA,CACX,CACJ,CAEA,MAAe,eAAiC,CAE5C,OADiB,MAAM,KAAK,MAAM,gBAAgB,GAClC,UACpB,CAGJ,EASA,SAAS5C,GAAWuE,EAA+B,CAC/C,OAAO,OAAOA,GAAQ,UAAYA,IAAQ,MAAQ,eAAgBA,GAAO,cAAeA,CAC5F,CClzBA,IAAKC,QACDA,EAAA,KAAO,OACPA,EAAA,KAAO,OAFNA,QAAA,IAKEC,GAAQD,GCyFR,IAAKE,QACRA,EAAA,IAAM,IACNA,EAAA,GAAK,IAFGA,QAAA,ICnGL,IAAMC,GAAN,KAA4B,CAY/B,YAAYC,EAAgB,CAV5BC,EAAA,KAAiB,UAEjBA,EAAA,KAAQ,eAERA,EAAA,KAAQ,gBAERA,EAAA,KAAQ,mBAERA,EAAA,KAAQ,SAGJ,KAAK,OAAS,IAAI,MAAMD,CAAM,EAAE,KAAK,IAAI,EACzC,KAAK,YAAc,KAAK,aAAe,KAAK,MAAQ,EACpD,KAAK,gBAAkB,EAC3B,CAGA,IAAI,QAAS,CACT,OAAO,KAAK,OAAO,MACvB,CAGA,IAAI,MAAO,CACP,OAAO,KAAK,KAChB,CAEA,SAAU,CACN,OAAO,MAAM,KAAK,KAAK,MAAM,CACjC,CAGA,IAAIE,EAAY,CACR,KAAK,kBACL,KAAK,YAAc,KAAK,WAAW,KAAK,WAAW,GAGnD,KAAK,OAAO,KAAK,YAAY,IAAM,OACnC,KAAK,OAAS,GAGlB,KAAK,OAAO,KAAK,YAAY,EAAIA,EACjC,KAAK,aAAe,KAAK,WAAW,KAAK,YAAY,EACrD,KAAK,gBAAkB,KAAK,eAAiB,KAAK,WACtD,CAGQ,WAAWC,EAAc,CAC7B,OAAQA,EAAO,GAAK,KAAK,OAAO,MACpC,CAGA,MAAiB,CACb,IAAMC,EAAK,KAAK,OAAO,KAAK,WAAW,EACvC,OAAIA,IACA,KAAK,gBAAkB,GACvB,KAAK,OAAO,KAAK,WAAW,EAAI,KAChC,KAAK,YAAc,KAAK,WAAW,KAAK,WAAW,EACnD,KAAK,OAAS,GAEXA,CACX,CACJ,EC5BO,IAAMC,GAAN,KAAkB,CASrB,YAAYC,EAAiBC,EAAgBC,EAAmBC,EAA0B,KAAM,CARhGC,EAAA,KAAiB,SACjBA,EAAA,KAAiB,WACjBA,EAAA,KAAiB,cACjBA,EAAA,KAAiB,WACjBA,EAAA,KAAiB,eAEjBA,EAAA,KAAQ,eAGJ,KAAK,MAAQC,EAAM,KAAK,EACxB,KAAK,QAAUJ,EACf,KAAK,WAAaC,EAClB,KAAK,QAAUF,EACf,KAAK,YAAcG,CACvB,CAEA,MAAM,WAA8B,CAChC,IAAMG,EAAoB,CACtB,aAAc,CACV,UAAW,KAAK,MAChB,eAAgBC,EAAO,WACvB,YAAa,SACb,WAAY,KAAK,WACjB,QAAS,CACb,EACA,gBAAiB,KAAK,OAC1B,EAEMC,EAAW,MAAMC,GAAoB,KAAK,YAAa,KAAK,OAAO,EACnEC,EAAU,MAAMC,GAAQ,mBAAoBL,EAAS,GAAME,CAAQ,EAEzE,OAAIH,EAAM,SAASK,CAAM,GAAK,EAAE,cAAeA,IAC3C,KAAK,YAAcA,EAAO,YACnB,IAEJ,EACX,CAEA,MAAM,mBAAmBE,EAAuC,CAC5D,IAAMC,EAAO,CACT,eAAAD,EACA,OAAQE,EAAW,OACnB,gBAAiB,KAAK,QACtB,YAAa,KAAK,WACtB,EAEMN,EAAW,MAAMC,GAAoB,KAAK,YAAa,KAAK,OAAO,EACzE,MAAME,GAAQ,2BAA4BE,EAAM,GAAML,CAAQ,CAClE,CACJ,EpHwBA,IAAIO,GACAC,GAAqC,KAK5BC,GAAU,CAInB,WAAYC,EAAY,WAIxB,eAAgBA,EAAY,eAI5B,UAAWA,EAAY,UAIvB,mBAAoBA,EAAY,mBAIhC,UAAWA,EAAY,UAIvB,cAAeA,EAAY,cAI3B,eAAgBA,EAAY,eAI5B,mBAAoBA,EAAY,mBAIhC,eAAgBA,EAAY,eAI5B,oBAAqBA,EAAY,oBAIjC,wBAAyBA,EAAY,wBAIrC,eAAgBA,EAAY,eAI5B,aAAcA,EAAY,aAI1B,aAAcA,EAAY,aAI1B,aAAcA,EAAY,aAI1B,cAAeA,EAAY,cAM3B,mBAAoBA,EAAY,mBAMhC,2BAA4BA,EAAY,2BAMxC,GAAIA,EAAY,GAMhB,SAAUA,EAAY,SAMtB,YAAaA,EAAY,YAMzB,eAAgBA,EAAY,eAM5B,kBAAmBA,EAAY,kBAI/B,gBAAiBA,EAAY,gBAM7B,sBAAuBA,EAAY,qBACvC,EAKaC,GAAQ,CAIjB,yBAA0BC,EAAM,wBACpC,EAEO,SAASC,GAAUC,EAA0B,CAChDN,GAAkBM,CACtB,CAOO,SAASC,GAAgBC,EAA6B,CACzDC,EAAO,aAAeD,CAC1B,CAOO,SAASE,GAAgBF,EAAkC,CAC9DC,EAAO,aAAeD,CAC1B,CAQO,SAASG,GACZC,EACAC,EAAiD,KACjDC,EAAoD,CAAC,EACrDC,EAAwC,EACpC,CACJN,EAAO,MAAQG,EACfH,EAAO,aAAe,CAClB,gBAAAM,EACA,iBAAAD,CACJ,EAEID,GACAD,EAAM,OAAOC,CAAG,CAExB,CAWA,eAAsBG,GAAKC,EAA8C,CAcrE,GAbAR,EAAO,IAAIQ,CAAM,EAEZlB,KACDA,GAAO,IAAImB,IAIf,GAAAC,QAAQ,WAAW,CAACV,EAAO,KAAK,EAChCW,EAAM,OAAOX,EAAO,KAAK,EAEzBW,EAAM,IAAI,aAAaX,EAAO,UAAU,GAAIQ,CAAM,EAElD,MAAMf,EAAY,KAAK,EACnB,CAACA,EAAY,mBAAmB,EAChC,MAAM,IAAImB,EAAaC,GAAW,WAAW,EAGjDF,EAAM,IAAI,aAAc,UAAU,SAAS,EAC3CA,EAAM,IAAI,qBAAsB,GAAG,OAAO,OAAO,KAAK,IAAI,OAAO,OAAO,MAAM,EAAE,EAChFA,EAAM,IAAI,eAAgB,WAAWlB,EAAY,oBAAoB,CAAC,UAAUA,EAAY,wBAAwB,CAAC,EAAE,EACvHkB,EAAM,IAAI,aAAc,GAAGH,EAAO,SAAS,OAAOR,EAAO,SAAS,EAAE,CACxE,CAaA,eAAsBc,GAClBC,EACAC,EAAe,CAACC,GAAY,KAAK,EACjCC,EAAU,GACVC,EAAiB,GACjBC,EAAoB,GACpBC,EACAC,EACyB,CACzB,IAAIC,EAA4B,CAAC,EAEjC,OAAI,MAAM,QAAQR,CAAU,EACxBQ,EAAcR,EAAW,OAASA,EAAa,CAAC,EACzCA,IACPQ,EAAc,CAACR,CAAU,GAGtBS,GAAa,CAAC,EAAGC,GAAS,KAAMT,EAAcE,EAASC,EAAgBC,EAAmBC,EAAwBE,EAAaD,CAAW,CACrJ,CAEA,eAAsBE,GAClBE,EACAC,EAAiBF,GAAS,KAC1BT,EACAE,EAAU,GACVC,EAAiB,GACjBC,EAAoB,GACpBC,EACAE,EACAD,EACyB,CACzB,GAAIM,EAAa,QAAQ,EACrB,MAAAjB,EAAM,MAAM,8BAA8B,EACpC,IAAIC,EAAaiB,EAAW,MAAM,EAG5C,OADqB,IAAID,EAAatC,GAAMC,EAAe,EACvC,QAAQ,CACxB,YAAamC,EACb,aAAcC,EACd,aAAAX,EACA,QAAAE,EACA,eAAAC,EACA,kBAAAC,EACA,uBAAAC,EACA,YAAAE,EACA,YAAAD,CACJ,CAAC,CACL,CAaA,eAAsBQ,GAAYC,EAAwBC,EAA4C,CAClG,OAAOC,GAAoBF,EAAgBG,GAAS,KAAM,OAAWF,CAAkB,CAC3F,CAEA,eAAsBC,GAClBF,EACAJ,EAAiBO,GAAS,KAC1BC,EACAH,EACAI,EACAC,EACa,CACb,GAAIN,IAAmBH,EAAa,GAAG,EACnC,MAAM,IAAI,MAAM,iCAAiC,EAIrD,OAAIS,GACA/C,GAAK,UAAU+C,CAAM,EAGJ,IAAIT,EAAatC,GAAMC,EAAe,EACvC,OAAOwC,EAAgBJ,EAAMQ,EAAQH,EAAoBI,CAAU,CAC3F,CAWA,eAAsBE,GAAUC,EAAoBC,EAAyC,CACzF,OAAID,IACAvC,EAAO,UAAYuC,GAGnBC,IAAe,QAAaxC,EAAO,aAAewC,IAClDxC,EAAO,WAAawC,EACpBC,GAAiB,GAGdnD,GAAK,UAAU,CAC1B,CAOA,eAAsBoD,GAAW1B,EAAe,CAACC,GAAY,KAAK,EAA8B,CAE5F,OADqB0B,GAAgC,EACjC,OAAO3B,CAAY,CAC3C,CAKA,eAAsB4B,IAA6B,CAC/C,IAAMC,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,OAAOA,EAAa,QAAQ,CAEpC,CAQA,eAAsBC,GAASf,EAAwBf,EAAe,CAACC,GAAY,KAAK,EAA8B,CAClH,OAAO8B,GAAiBhB,EAAgBf,CAAY,CACxD,CAEA,eAAsB+B,GAAiBhB,EAAwBf,EAA6BgC,EAA4C,CACpI,GAAIpB,EAAa,QAAQ,EACrB,MAAAjB,EAAM,MAAM,8BAA8B,EACpC,IAAIC,EAAaiB,EAAW,MAAM,EAG5C,OADqB,IAAID,EAAatC,GAAMC,EAAe,EACvC,OAAO,CAAE,eAAAwC,EAAgB,aAAAf,EAAc,OAAAgC,CAAO,CAAC,CACvE,CAWA,eAAsBC,GAClBC,EACAlC,EAAe,CAACC,GAAY,KAAK,EACjCkC,EACAC,EACAlC,EACyB,CACzB,GAAIU,EAAa,QAAQ,EACrB,MAAAjB,EAAM,MAAM,8BAA8B,EACpC,IAAIC,EAAaiB,EAAW,MAAM,EAE5C,OAAIsB,IACAnD,EAAO,YAAcmD,GAEJ,IAAIvB,EAAatC,GAAMC,EAAe,EACvC,OAAO,CAAE,SAAA2D,EAAU,aAAAlC,EAAc,YAAAoC,EAAa,QAAAlC,CAAQ,CAAC,CAC/E,CAKA,eAAsBmC,IAAwB,CAC1C,IAAMR,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,OAAOA,EAAa,OAAO,EAE3BjB,EAAa,gBAAgB,CAErC,CAQA,eAAsB0B,GAAe/B,EAAwCf,EAA8C,CACvH,IAAM+C,EAA6B,MAAM,QAAQhC,CAAW,EAAIA,EAAc,CAACA,CAAW,EAEpFsB,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,eAAeU,EAAc/C,CAAM,CAE9D,CAOA,eAAsBgD,GAAuBC,EAAkBjD,EAA+B,CAC1F,IAAMqC,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EAAc,CACd,IAAMa,EAAeD,EAAK,IAAKE,GAAQhE,EAAM,cAAcgE,CAAG,CAAC,EAC/D,MAAMd,EAAa,qBAAqBa,EAAclD,CAAM,CAChE,CACJ,CAQA,eAAsBoD,GAAkB7C,EAAwB8C,EAAM,GAAsB,CACxF,IAAMJ,EAAO,MAAMnE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,EAC1D,OAAO+C,GAA0BL,EAAK,CAAC,EAAGI,CAAG,CACjD,CAOA,eAAsBC,GAA0BH,EAAeE,EAAM,GAAO,CACxE,IAAMhB,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,GAAI,CACA,MAAMA,EAAa,kBAAkBlD,EAAM,cAAcgE,CAAG,EAAGE,CAAG,CACtE,OAASE,EAAK,CACVpD,EAAM,KAAK,gCAAgCgD,CAAG,0CAA0CI,CAAG,EAAE,CACjG,CAER,CAmBA,eAAsBC,GAAaC,EAAuBC,EAA0D,CAChH,IAAMrB,EAAejB,EAAa,QAAQ,EAG1C,GAAIqC,IAAS,cAAgBE,GAAW,SAASD,CAAoB,EAGjE,OAFAlE,EAAO,gBAAkBkE,EAEpBrB,GAKDpD,EAAY,SAAS,GAGrBoD,EAAa,eAAe,EAEzBA,EAAa,aAAaoB,CAAI,GARjC,OAaR,GAAI,CADW,MAAMxE,EAAY,cAAcwE,EAAMC,CAAoB,EAErE,MAAM,IAAI,MAAM,qBAAqBA,CAAoB,EAAE,EAE/D,GAAIrB,EACA,OAAOA,EAAa,aAAaoB,CAAI,CAE7C,CASA,eAAsBG,GAAcC,EAAiE,CACjG,IAAMC,EACF,OAAOD,GAAoB,SACrB,CACI,GAAGA,EACH,kBAAmBA,EAAgB,eAAiBA,EAAgB,kBACpE,aAAcA,EAAgB,eAAiBA,EAAgB,cAAgBrE,EAAO,UAC1F,EACA,CACI,cAAeqE,EACf,kBAAmB,GACnB,aAAc,EAClB,EACJxB,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,sBAAsByB,CAAQ,EAE/C,QAAQ,OAAO,CAC1B,CAOO,SAASC,GAAaC,EAAgB,CACzC,IAAM3B,EAAejB,EAAa,QAAQ,EACtCiB,GACAA,EAAa,uBAAuB2B,CAAK,CAEjD,CAUA,eAAsBC,GAAeC,EAAqBC,EAAW,GAAsB,CACvF,IAAM9B,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,eAAe6B,EAAQC,CAAQ,CAE1D,CAOA,eAAsBC,GAAiBC,EAAiC,CACpE,IAAMhC,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,iBAAiBgC,CAAO,CAEnD,CAOA,eAAsBC,GAAiBD,EAAiC,CACpE,IAAMhC,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,iBAAiBgC,CAAO,CAEnD,CAOA,eAAsBE,GAAmBC,EAAoE,CACzG,IAAMnC,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,OAAOA,EAAa,mBAAmBmC,CAAU,CAEzD,CAUA,eAAsBC,GAAiBC,EAAkD,CACrF,IAAMrC,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,iBAAiBqC,CAAU,CAEtD,CAQA,eAAsBC,GAAuBX,EAA6BzD,EAAwC,CAC9G,IAAM8B,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EAAc,CACd,IAAIuC,EAEJ,GAAIrE,EAAY,CACZ,GAAM,CAAC4C,CAAG,EAAI,MAAMrE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,EAC3DqE,EAAkBzF,EAAM,qBAAqBgE,EAAKzB,GAAS,KAAMnB,EAAW,SAAS,CACzF,CAEA,MAAM8B,EAAa,uBAAuB2B,EAAOY,CAAe,CACpE,CACJ,CAKA,eAAsBC,IAA8B,CAChD,IAAMxC,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,aAAa,CAExC,CAQA,eAAsByC,GAAoBC,EAA4C,CAClF,IAAM1C,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,oBAAoB0C,CAAM,CAErD,CASA,eAAsBC,GAAWzE,EAAwB0E,EAAmBC,EAAS,GAAsB,CACvG,IAAMjC,EAAO,MAAMnE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,EAC1D,OAAO4E,GAAmBlC,EAAK,CAAC,EAAGmC,EAAgB,aAAa7E,CAAU,EAAG0E,EAAOC,CAAM,CAC9F,CAEA,eAAsBC,GAAmBhC,EAAekC,EAAmBJ,EAAmBC,EAAS,GAAO,CAC1G,IAAM7C,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,WAAWlD,EAAM,qBAAqBgE,EAAKzB,GAAS,KAAM2D,CAAS,EAAGJ,EAAOC,CAAM,CAE9G,CAKA,eAAsBI,GAAgB,CAAE,WAAA/E,EAAa,KAAM,WAAAgF,EAAY,eAAAC,EAAiB,CAAC,EAAG,OAAAC,EAAS,IAAa,EAA0C,CACxJ,IAAItC,EAAM,KACV,OAAI5C,IAEA4C,GADa,MAAMrE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,GAC/C,CAAC,GAETmF,GAAwB,CAC3B,IAAAvC,EACA,WAAAoC,EACA,eAAAC,EACA,UAAWJ,EAAgB,aAAa7E,CAAU,EAClD,OAAAkF,CACJ,CAAC,CACL,CAEA,eAAsBC,GAAwB,CAAE,IAAAvC,EAAM,KAAM,WAAAoC,EAAY,eAAAC,EAAiB,CAAC,EAAG,UAAAH,EAAY,EAAG,OAAAI,EAAS,IAAa,EAAmC,CACjK,IAAMpD,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EAAc,CACd,IAAMsD,EAAgBxC,EAAMhE,EAAM,qBAAqBgE,EAAKzB,GAAS,KAAM2D,CAAS,EAAI,KACxF,MAAMhD,EAAa,gBAAgBsD,EAAeJ,EAAYC,EAAgBC,CAAM,CACxF,CACJ,CASA,eAAsBG,GAAerF,EAAwBsF,EAAQ,GAAOJ,EAAwB,KAAqB,CACrH,IAAMxC,EAAO,MAAMnE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,EAC1D,OAAOuF,GAAuB7C,EAAK,CAAC,EAAG4C,EAAOT,EAAgB,aAAa7E,CAAU,EAAGkF,CAAM,CAClG,CAEA,eAAsBK,GAAuB3C,EAAe0C,EAAQ,GAAOR,EAAY,EAAGI,EAAwB,KAAM,CACpH,IAAMpD,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,eAAelD,EAAM,qBAAqBgE,EAAKzB,GAAS,KAAM2D,CAAS,EAAGQ,EAAOJ,CAAM,CAElH,CAOA,eAAsBM,GAAkBC,EAA+C,CACnF,IAAM3D,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,qBAAqB2D,CAAc,CAE9D,CAQA,eAAsBC,GAAmB5B,EAAiC,CACtE,IAAMhC,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,mBAAmBgC,CAAO,CAErD,CAQA,eAAsB6B,GAA0B7B,EAAiC,CAC7E,IAAMhC,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,0BAA0BgC,CAAO,CAE5D,CAOA,eAAsB8B,GAA0BC,EAAmE,CAC/G,IAAM/D,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,cAAc+D,CAAO,CAEhD,CAQA,eAAsBC,GAAYC,EAAiB/F,EAAgC,KAAqB,CACpG,IAAI4C,EAAM,KACV,OAAI5C,IAEA4C,GADa,MAAMrE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,GAC/C,CAAC,GAETgG,GAAoBD,EAASnD,CAAG,CAC3C,CAEA,eAAsBoD,GAAoBD,EAAiBnD,EAAuB,KAAM,CACpF,IAAMd,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EAAc,CACd,IAAMsD,EAAgBxC,EAAMhE,EAAM,cAAcgE,CAAG,EAAI,KACvD,MAAMd,EAAa,YAAYiE,EAASX,CAAa,CACzD,CACJ,CAOA,eAAsBa,GAAYC,EAAQ,GAAI,CAC1C,IAAMpE,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,OAAOA,EAAa,YAAYoE,CAAK,CAE7C,CAQA,eAAsBC,GAAWC,EAAkBpG,EAAgC,KAAqB,CACpG,IAAI4C,EAAM,KACV,OAAI5C,IAEA4C,GADa,MAAMrE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,GAC/C,CAAC,GAETqG,GAAmBD,EAAMxD,EAAKiC,EAAgB,aAAa7E,CAAU,CAAC,CACjF,CAEA,eAAsBqG,GAAmBD,EAAkBxD,EAAuB,KAAMkC,EAAY,EAAG,CACnG,IAAMhD,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EAAc,CACd,IAAMsD,EAAgBxC,EAAMhE,EAAM,qBAAqBgE,EAAKzB,GAAS,KAAM2D,CAAS,EAAI,KACxF,MAAMhD,EAAa,WAAWsE,EAAMhB,CAAa,CACrD,CACJ,CAYA,eAAsBkB,GAClBnG,EAAU,GACVE,EAAoB,GACpB,CAAE,uBAAAC,EAAyB,GAAO,aAAAiG,EAAe,GAAO,mBAAAC,EAAqB,EAAM,EAAI,CAAC,EACzE,CAEf,OADqB,MAAMjI,GAAK,mBAAmBK,EAAM,KAAK,EAAGuB,EAASE,EAAmB,CAAE,uBAAAC,EAAwB,aAAAiG,EAAc,mBAAAC,CAAmB,CAAC,GACrI,SACxB,CAWA,eAAsBC,GAClBtG,EAAU,GACVE,EAAoB,GACpB,CAAE,uBAAAC,EAAyB,GAAO,UAAAoG,EAAY,EAAM,EAAI,CAAC,EACzDC,EACe,CACf,IAAMjE,EAAOmC,EAAgB,QAAQ8B,CAAU,EACzCC,EAA2B,MAAMrI,GAAK,sBAAsBmE,CAAI,EAYtE,OAXqB,MAAMnE,GAAK,mBAC5BK,EAAM,KAAK,EACXuB,EACAE,EACA,CACI,uBAAAC,EACA,aAAc,GACd,UAAAoG,CACJ,EACAE,CACJ,GACoB,SACxB,CAOA,eAAsBC,IAAkC,CACpD,IAAM/E,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,eAAe,EAEhC,QAAQ,OAAO,CAC1B,CAKA,eAAsBgF,IAAgC,CAClD,IAAMhF,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,eAAe,EAEhC,QAAQ,OAAO,CAC1B,CASA,eAAsBiF,GAAqB5E,EAAkB6E,EAAoC,CAC7F,OAAOzI,GAAK,qBAAqB4D,EAAU6E,CAAQ,CACvD,CAMO,SAASC,GAAUC,EAAgB,CACtC,IAAMpF,EAAejB,EAAa,QAAQ,EACtCiB,GACAA,EAAa,UAAUoF,CAAM,CAErC,CAMO,SAASC,GAAiBrD,EAAkB,CAC/C7E,EAAO,iBAAmB6E,CAC9B,CAWA,eAAsBsD,GAClBC,EAAW,GACXC,EAAsB,KACtBC,EAAyB,KACzBC,EAAgD,cAChDC,EAAyB,KACzBvC,EAAwB,KAC1B,CACE,IAAMpD,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,YAAYuF,EAAUC,EAAMC,EAASC,EAASC,EAASvC,CAAM,EAE9E,QAAQ,OAAO,CAC1B,CAOA,eAAsBwC,GAAWxC,EAAwB,KAAMyC,EAAkB,CAC7E,IAAM7F,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,WAAWoD,EAAQyC,CAAM,EAE1C,QAAQ,OAAO,CAC1B,CAMA,eAAsBC,GAAc1C,EAAwB,KAAM,CAC9D,IAAMpD,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,cAAcoD,CAAM,EAErC,QAAQ,OAAO,CAC1B,CAWA,eAAsB2C,GAAcC,EAAmBC,EAAsBC,EAAuB,GAAO9C,EAAwB,KAAM,CACrI,IAAMpD,EAAejB,EAAa,QAAQ,EAC1C,GAAI,CAACiB,EACD,OAAO,QAAQ,OAAO,EAG1B,IAAImG,EACAC,EAEE1H,EAA4B,CAAC,EAOnC,GANIuH,GAAO,QACPvH,EAAY,KAAK,GAAGuH,CAAK,EAEzBD,GACAtH,EAAY,KAAKsH,CAAI,EAErBtH,EAAY,OAAQ,CACpB,IAAM2H,EAAiB,MAAM5J,GAAK,+BAA+BiC,CAAW,EAExEsH,IACAG,EAAUE,EAAe,IAAIL,CAAI,EACjCK,EAAe,OAAOL,CAAI,GAE9BI,EAAW,MAAM,KAAKC,EAAe,OAAO,CAAC,CACjD,CAGA,OAAOrG,EAAa,cAAcmG,EAASC,EAAUF,EAAsB9C,CAAM,CACrF,CAKA,eAAsBkD,IAAgB,CAClC,IAAMtG,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,cAAc,EAE/B,QAAQ,OAAO,CAC1B,CAOA,eAAsBuG,GAAS5I,EAAyB,CACpD,IAAMqC,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,SAASrC,CAAM,EAEhC,QAAQ,OAAO,CAC1B,CAOA,eAAsB6I,GAAY7I,EAA0B,CACxD,IAAMqC,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,YAAYrC,CAAM,EAEnC,QAAQ,OAAO,CAC1B,CAOA,eAAsB8I,GAAYhB,EAAiB,CAC/C,IAAMzF,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,YAAYyF,CAAO,EAEpC,QAAQ,OAAO,CAC1B,CAOA,eAAsBiB,GAAYC,EAAwBC,EAA0B,CAChF,IAAM5G,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EAAc,CACd,IAAM6G,EAAkC,CAAC,EAEzC,QAAWC,KAAQH,EAAO,CACtB,IAAII,EACAC,EAEAF,EAAK,oBACLC,GAAqB,MAAMtK,GAAK,sBAAsBqK,EAAK,iBAAiB,GAAG,IAAKG,GAAOnK,EAAM,cAAcmK,CAAE,CAAC,GAGlHH,EAAK,uBACLE,GAAwB,MAAMvK,GAAK,sBAAsBqK,EAAK,oBAAoB,GAAG,IAAKG,GAAOnK,EAAM,cAAcmK,CAAE,CAAC,GAG5HJ,EAAO,KAAK,CACR,GAAIC,EAAK,GACT,KAAMA,EAAK,KACX,iBAAkBA,EAAK,iBACvB,kBAAAC,EACA,qBAAAC,EACA,aAAcF,EAAK,YACvB,CAAC,CACL,CAEA,OAAO9G,EAAa,YAAY6G,EAAQD,CAAc,CAC1D,CACA,OAAO,QAAQ,OAAO,CAC1B,CAOA,eAAsBM,GAAcC,EAAmBC,EAAqB,CACxE,IAAMpH,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,cAAcmH,EAASC,CAAU,EAElD,QAAQ,OAAO,CAC1B,CAOA,eAAsBC,GAAWC,EAA0B,KAAMpJ,EAAgC,KAAM,CACnG,IAAM8B,EAAejB,EAAa,QAAQ,EAC1C,GAAI,CAACiB,EACD,OAAO,QAAQ,OAAO,EAG1B,IAAIc,EACJ,GAAI5C,EAAY,CACZ,IAAM0C,EAAO,MAAMnE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,EACpD8E,EAAYD,EAAgB,aAAa7E,CAAU,EACzD4C,EAAMhE,EAAM,qBAAqB8D,EAAK,CAAC,EAAGvB,GAAS,KAAM2D,CAAS,CACtE,CACA,OAAOhD,EAAa,WAAWsH,EAAUxG,CAAG,CAChD,CAMA,eAAsByG,GAAYJ,EAAmB,CACjD,IAAMnH,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,YAAYmH,CAAO,EAEpC,QAAQ,OAAO,CAC1B,CAOO,SAASK,GAAsBC,EAAe,CACjDtK,EAAO,mBAAqBsK,EAC5B,IAAMzH,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,OAAOA,EAAa,yBAAyB,CAErD,CAOO,SAAS0H,GAAM1F,EAAwB,CAC1C,GAAAnE,QAAQ,WAAW,CAACmE,CAAO,EAC3BlE,EAAM,OAAOkE,CAAO,CACxB,CAQO,SAAS2F,GAAa7I,KAA2B8I,EAAmB,CAClEzK,EAAO,UAGZW,EAAM,KAAKgB,EAAM,aAAc,GAAG8I,CAAI,CAC1C,CAMA,eAAsBC,IAAiC,CACnD,IAAMZ,EAAKa,GAAwB,eACnC,GAAI,CAACb,EACD,MAAAnJ,EAAM,MAAM,oBAAqB,0BAA0B,EACrD,IAAI,MAAM,0BAA0B,EAG9C,IAAMiK,EAAOD,GAAwB,YAAY,EAEjD,GAAIC,EAAK,SAAW,EAChB,MAAAjK,EAAM,MAAM,oBAAqB,eAAe,EAC1C,IAAI,MAAM,eAAe,EAGnC,IAAMkK,EAAYF,GAAwB,UACpCG,EAAUH,GAAwB,QAExC,GAAI,CACA,OAAOrL,IAAM,gBAAgBwK,EAAIe,EAAWC,EAAS,KAAK,UAAUF,CAAI,CAAC,CAC7E,OAAS7G,EAAK,CACV,MAAApD,EAAM,MAAM,oBAAqB,6BAA8BoD,CAAG,EAC5D,IAAI,MAAM,6BAA8B,CAAE,MAAOA,CAAI,CAAC,CAChE,CACJ,CAOA,eAAsBgH,GAAkBC,EAAwB,CAC5D,IAAMnI,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,OAAOA,EAAa,YAAYmI,CAAM,CAE9C,CAOA,eAAsBC,GAAkBlL,EAAmBmL,EAAoB,CAC3E,IAAMrI,EAAejB,EAAa,QAAQ,EAC1C,GAAIiB,EACA,OAAOA,EAAa,YAAY9C,EAAQ,OAAS,EAAIA,EAAU,KAAMmL,CAAQ,CAErF,CAQA,eAAsBC,GAAezG,EAAoC,CACrE,IAAM7B,EAAejB,EAAa,QAAQ,EACtCiB,GACA,MAAMA,EAAa,eAAe6B,CAAM,CAEhD,CAYA,eAAsB0G,GAAYC,EAA2BtK,EAAgC,KAAMuK,EAA2B,KAAM,CAChI,IAAMzI,EAAejB,EAAa,QAAQ,EAC1C,GAAI,CAACiB,EACD,OAGJ,IAAM0I,EAAgBD,GAAavK,GAAY,GAC3CoF,EAAgB,KAEpB,GAAIpF,EAAY,CAGZ,IAAM4C,GADO,MAAMrE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,GACzC,CAAC,EAElB,GAAI,CAAC4C,EACD,MAAM,IAAI,MAAM,0CAA0C,EAG9DwC,EAAgBxG,EAAM,qBAAqBgE,EAAKzB,GAAS,KAAM0D,EAAgB,aAAa7E,CAAU,CAAC,CAC3G,CAEA8B,EAAa,cAAcwI,EAAKlF,EAAeoF,CAAa,CAChE,CAOO,SAASC,GAAaC,EAA+B,CACxD,IAAM5I,EAAejB,EAAa,QAAQ,EACrCiB,GAILA,EAAa,eAAe4I,CAAI,CACpC,CASA,eAAsBC,GAAeC,EAA4B,KAAM1E,EAAgB2E,EAAW,GAAqC,CAGnI,OAFqBjJ,GAAgC,EAEjC,eAAegJ,EAAY1E,EAAO2E,CAAQ,CAClE,CAKA,eAAsBC,IAA2D,CAG7E,OAFqBlJ,GAAgC,EAEjC,qBAAqB,CAC7C,CASA,eAAsBmJ,GAAmB/K,EAAyBgL,EAAS,GAAsB,CAC7F,IAAMlJ,EAAeF,GAAgC,EACjDyC,EAEJ,GAAIrE,EAAY,CACZ,GAAM,CAAC4C,CAAG,EAAI,MAAMrE,GAAK,sBAAsB,CAACyB,CAAU,CAAC,EAC3DqE,EAAkBzF,EAAM,cAAcgE,CAAG,CAC7C,CAEA,OAAOd,EAAa,mBAAmBuC,EAAiB2G,CAAM,CAClE,CAQA,eAAsBC,GAAiBD,EAAS,GAAsB,CAGlE,OAFqBpJ,GAAgC,EAEjC,iBAAiBoJ,CAAM,CAC/C,CAOA,eAAsBE,GAAgBC,EAAS,GAAsB,CAGjE,OAFqBvJ,GAAgC,EAEjC,gBAAgBuJ,CAAM,CAC9C,CAEA,eAAsBC,GAAwBC,EAAgE,CAE1G,OADqBzJ,GAAgC,EACjC,wBAAwByJ,CAA8B,CAC9E,CAEA,eAAsBC,GAAgBC,EAAwC,CAE1E,OADqB3J,GAAgC,EACjC,gBAAgB2J,CAAU,CAClD,CAEA,eAAsBC,GAASC,EAAa,CAExC,OADqB7J,GAAgC,EACjC,SAAS6J,CAAG,CACpC,CAEO,SAASC,GAAkBC,EAAsBC,EAAiBC,EAA8B,CAEnG,OADqBjK,GAAgC,EACjC,kBAAkB+J,EAAcC,EAAQC,CAAmB,CACnF,CASO,SAASC,GAAeC,EAAmBC,EAAuD,CAAC,EAAGC,EAAc,GAAO,CAC9H,IAAMnK,EAAejB,EAAa,QAAQ,EAErCiB,GAILA,EAAa,gBAAgBiK,EAAWC,EAAWC,CAAW,CAClE,CAEA,eAAsBC,GAAsBC,EAA8BzH,EAAmB,CAEzF,OADqB9C,GAAgC,EACjC,sBAAsBuK,EAASzH,CAAK,CAC5D,CAEA,SAAS9C,IAAkC,CACvC,IAAME,EAAejB,EAAa,QAAQ,EAC1C,GAAI,CAACiB,EACD,MAAM,IAAI,MAAM,wBAAwB,EAE5C,OAAOA,CACX,CAOA,eAAsBsK,GAAqBC,EAAoC,CAC3E,MAAM9N,GAAK,qBAAqB8N,CAAS,CAC7C,CAKA,eAAsBC,GAAS7M,EAAwC,CACnE,IAAMqC,EAAejB,EAAa,QAAQ,EAEtCiB,GACA,MAAMA,EAAa,SAASrC,CAAM,CAE1C,CAKA,eAAsB8M,GAAQ9M,EAAwC,CAClE,IAAMqC,EAAejB,EAAa,QAAQ,EAEtCiB,GACA,MAAMA,EAAa,QAAQrC,CAAM,CAEzC,CAKA,eAAsB+M,GAAWC,EAAiC,CAC9D,IAAM3K,EAAejB,EAAa,QAAQ,EAEtCiB,GACA,MAAMA,EAAa,WAAW2K,CAAO,CAE7C,CAEA,eAAsBC,GAAgBC,EAAmB,CACrD,IAAM7K,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,gBAAgB6K,CAAS,EAE1C,QAAQ,OAAO,CAC1B,CAEA,eAAsBC,IAAiB,CACnC,IAAM9K,EAAejB,EAAa,QAAQ,EAC1C,OAAIiB,EACOA,EAAa,eAAe,EAEhC,QAAQ,OAAO,CAC1B,CAMO,SAAS+K,IAAkB,CAC9B,OAAO5N,EAAO,UAClB",
6
+ "names": ["CallsSDK_exports", "__export", "Api", "ApiExternal", "ArrayDequeue", "AuthData", "BaseLogger", "CallDirection_default", "CallType_default", "ChatRoomEventType_default", "ConversationFeature_default", "ConversationOption_default", "DebugMessageType", "ExternalIdType", "FacingMode", "FatalError_default", "HangupReason", "HangupType_default", "MediaOption_default", "MediaTrackKind", "MediaType", "MuteState_default", "ParticipantState_default", "ParticipantStateDataValue", "ParticipantStatus", "RecordRole_default", "RoomsEventType_default", "Signaling", "SignalingCommandType_default", "SignalingConnectionType_default", "SignalingNotification_default", "TransportTopology", "UserRole_default", "UserType_default", "VolumeDetector", "acceptCall", "acceptPromotion", "activateRooms", "addMovie", "addParticipant", "addParticipantInternal", "authorize", "browser", "callInternal", "callTo", "captureScreen", "captureVmoji", "changeAudioEffect", "changeConversationOptions", "changeDevice", "changeParticipantState", "changePriorities", "changeVideoEffect", "chatHistory", "chatMessage", "chatMessageInternal", "createJoinLink", "customData", "customDataInternal", "debug", "debugMessage", "declineCall", "enableFeatureForRoles", "enableVideoSuspend", "enableVideoSuspendSuggest", "feedback", "forceRelayPolicy", "getAnonymTokenByLink", "getAudienceModeHands", "getParticipantListChunk", "getParticipants", "getStreamInfo", "getWaitingHall", "grantRoles", "grantRolesInternal", "hangup", "init", "joinCall", "joinCallByLink", "joinCallInternal", "logClientEvent", "muteParticipant", "muteParticipantInternal", "pinParticipant", "pinParticipantInternal", "processPush", "processPushInternal", "promoteParticipant", "publishStream", "putHandsDown", "recordSetConf", "removeHistoryRecords", "removeJoinLink", "removeMovie", "removeParticipant", "removeParticipantInternal", "removeRooms", "requestAsr", "requestPromotion", "setAudioEffects", "setAudioStream", "setLocalResolution", "setLogger", "setMediaModifiers", "setStatisticsInterval", "setVideoEffects", "setVideoStream", "setVmoji", "setVmojiFill", "setVmojiSvg", "setVolume", "startAsr", "startAudienceConversation", "startConversation", "startStream", "startUrlSharing", "stopAsr", "stopStream", "stopUrlSharing", "switchRoom", "toggleLocalAudio", "toggleLocalVideo", "updateDisplayLayout", "updateMovie", "updateRooms", "uploadDebugLogs", "userFeedbackStats", "utils", "version", "__toCommonJS", "import_webrtc_adapter", "BaseLogger", "name", "value", "immediately", "EventEmitter", "__publicField", "event", "args", "handler", "listener", "pos", "instance", "callback", "subscription", "BaseSignaling", "EventEmitter", "participantIdRegistry", "endpoint", "conversationId", "isReady", "consumerCommand", "producerCommand", "HangupType", "HangupType_default", "HangupReason", "_HangupReason", "type", "data", "__publicField", "HangupType_default", "msg", "_Logger", "BaseLogger", "api", "externalLogger", "__publicField", "provider", "name", "value", "immediately", "params", "data", "clientStats", "key", "clientEvent", "operation", "custom", "isStartTimeoutRequested", "serverTime", "Logger", "import_messagepack", "SignalingCommandType", "SignalingCommandType_default", "FatalError", "FatalError_default", "MediaOption", "MediaOption_default", "StatLog", "StatLog_default", "import_libvpx", "WorkerBase", "__publicField", "workerFunctionData", "onFrame", "workerArgs", "initArgs", "transfer", "resolve", "reject", "dataArgs", "blob", "blobURL", "e", "Debug_default", "Logger", "StatLog_default", "type", "data", "LibVPxDecoder", "WorkerBase", "onFrameImage", "onFrameError", "onKeyFrameRequested", "Debug_default", "data", "imageData", "libvpx", "timestamp", "isVP9", "keyFrame", "WebCodecsDecoder", "WorkerBase", "onFrameImage", "onFrameError", "onKeyFrameRequested", "Debug_default", "data", "WebRTCUtils_default", "timestamp", "isVP9", "keyFrame", "FpsMeter", "callback", "intervalMs", "__publicField", "value", "now", "ms", "fps", "import_bit_buffer", "UserType", "UserType_default", "SIMULCAST_DEFAULT", "SIMULCAST_SCALABILITY_MODE", "BASE_BITRATES_ASC", "MAP_RID_TO_SCALE_RESOLUTION_DOWN_BY", "isEqualSimulcastInfo", "si1", "si2", "stream", "i", "Utils_default", "findBitrateAsc", "maxDimension", "bitrates", "element", "calculateSimulcastInfo", "width", "height", "rids", "layers", "simulcastInfo", "fps", "bitrate", "rid", "findScaleResolutionDownBy", "fromEntries", "entries", "obj", "key", "value", "blobToArrayBuffer", "data", "resolve", "reject", "fileReader", "event", "PARAMETERS_SEPARATOR", "DEVICE_IDX_PARAMETER", "IDEAL_BITS_PER_MACROBLOCK", "FMTP_PREFIX", "SPS_PPS_IDR_IN_KEYFRAME_FLAG", "Utils", "lineSeparator", "separator", "getPayloadTypesForCodec", "lines", "codec", "rtpmapLinePattern", "i", "result", "matchResult", "setDefaultCodec", "mLine", "pTypesToRemove", "pTypesPriority", "elements", "newLine", "processMLines", "mediaType", "prefix", "addH264spsPpsIdrInKeyframe", "h264PTs", "fmtpLinePattern", "flagSeparator", "removeCodec", "pTypes", "fmtpAptLinePattern", "dropLinePattern", "getPayloadTypesForCodecInSection", "start", "end", "removeCodecInSection", "removed", "removeVideoCodec", "sdpOwner", "type", "mStart", "mEnd", "isRecvSection", "direction", "patchH264", "preferH264", "h264spsPpsIdrInKeyframe", "patchVp9", "vp9PTs", "patchLocalSDP", "sdp", "brokenH264Decoder", "preferVP9", "isAudioNack", "preferRed", "addNackAudioLines", "addLines", "index", "line", "patchRed", "redPTs", "sdpLines", "patchRemoteSDP", "oldDataChannelDescription", "brokenH264", "brokenVP9Encoder", "brokenVP9Decoder", "getPeerIdString", "peerId", "comparePeerId", "peerId1", "peerId2", "getPeerConnectionHostInfo", "pc", "_info", "stats", "_pair", "stat", "candidate", "LEGACY_ID_PATTERN", "COMPOSITE_ID_PATTERN", "composeUserId", "id", "UserType_default", "strId", "Debug_default", "composeParticipantId", "deviceIdx", "userId", "compose", "compositeId", "composeId", "participant", "composeDecorativeId", "composeMessageId", "message", "extractOkId", "decomposeId", "decomposeParticipantId", "match", "participantId", "tokens", "uuid", "nativeUUID", "chars", "rnd", "r", "debounce", "func", "ms", "timeout", "wrapper", "_args", "_this", "sdpFingerprint", "fingerprintStr", "split", "s", "splitFp", "hexchunks", "current", "delay", "time", "resolve", "applySettings", "videoSettings", "prevSettings", "retSettings", "applyVideoTrackSettings", "track", "trackSettings", "targetBitrate", "trackWidth", "trackHeight", "targetScaleResolutionDownBy", "targetMaxFramerate", "macroBlocks", "bitrate", "targetDegradationPreference", "prevTrackSettings", "senderParams", "targetDimension", "trackDimension", "simulcastInfo", "calculateSimulcastInfo", "layers", "encoding", "findScaleResolutionDownBy", "dimension", "SIMULCAST_SCALABILITY_MODE", "e", "actualParams", "includesOneOf", "arr", "search", "item", "mapParticipantState", "acc", "key", "state", "mapSharedParticipants", "participants", "Params", "isEqualParticipantState", "prev", "next", "prevKeys", "nextKeys", "isObjectsEquals", "obj1", "obj2", "deep", "keys1", "keys2", "left", "right", "isObject", "isArraysEquals", "arr1", "arr2", "isEmptyObject", "obj", "participantMarkerCompare", "marker1", "marker2", "compareNumber", "compareId", "markerA", "markerB", "typeToNumber", "compositeUserId1", "deviceIdx1", "compositeUserId2", "deviceIdx2", "id1", "type1", "id2", "type2", "x", "y", "objectFilterOutValues", "value", "filtered", "val", "fromEntries", "objectReduce", "callback", "initialValue", "currentValue", "nextTimerId", "timerIdToCallback", "messageChannel", "event", "timerId", "fn", "_timerId", "patchSimulcastAnswerSdp", "trans", "width", "height", "findVideoSection", "mid", "found", "patchSimulcastRidLine", "rid", "bw", "w", "h", "targetRid", "line2", "sender", "scale", "Utils_default", "Stat", "Stat_default", "NO_STAT_REQUEST_DELAY", "getValue", "item", "key", "defaultValue", "orPredicate", "predicates", "object", "predicate", "keyPredicate", "value", "keyReverseComparator", "left", "right", "index", "property", "items", "values", "distinctById", "tmp", "res", "withoutUndefined", "obj", "pair", "Utils_default", "rtcStatsToArray", "stats", "result", "stat", "extractStats", "pc", "promisedStats", "receiver", "sender", "extractTransport", "candidatePair", "transport", "remoteCandidate", "localCandidate", "extractRtps", "ssrcMap", "needToExtractRemote", "statsIndexed", "rtpStats", "WebRTCUtils_default", "statMap", "merged", "remote", "ssrc", "kind", "trackId", "type", "codecId", "rtp", "mid", "rid", "framesDecoded", "totalInterFrameDelay", "totalSquaredInterFrameDelay", "encoder", "decoder", "codec", "track", "delta", "current", "previous", "currentRemoteRtps", "previousRemoteRtps", "currentRtps", "previousRtps", "time", "currentRtp", "previousRtp", "lost", "received", "diff", "remoteRtp", "previousRemoteRtp", "getValueOrZero", "sent", "collectStats", "setMark", "name", "clearMark", "measureMark", "mark", "getMarkNameScreenshareFirstFrame", "uid", "Stat_default", "uidToString", "Statistics_default", "_StatAggregator", "__publicField", "params", "eventualStat", "Logger", "Statistics_default", "StatAggregator", "StatScreenShareFirstFrame", "participantId", "__publicField", "width", "height", "markName", "Statistics_default", "duration", "StatAggregator", "Stat_default", "SEQUENCE_OVERFLOW", "MARK_SCREENSHARE_FREEZE_DURATION", "BaseStreamBuilder", "_BaseStreamBuilder", "participantId", "onStream", "onStat", "onKeyFrameRequested", "__publicField", "StatScreenShareFirstFrame", "chunk", "size", "Debug_default", "frameData", "width", "height", "Statistics_default", "chunks", "calc", "current", "result", "offset", "reader", "profileLowBit", "profile", "start", "duration", "BaseRenderer", "onStream", "__publicField", "frame", "image", "CanvasRenderer", "BaseRenderer", "onStream", "__publicField", "Debug_default", "width", "height", "track", "image", "canvas", "imageBitmap", "w", "h", "data", "expected", "context", "frame", "WebRTCUtils_default", "TrackGeneratorRenderer", "BaseRenderer", "onStream", "__publicField", "Debug_default", "frame", "WebCodecsDecoder", "StreamBuilder", "BaseStreamBuilder", "participantId", "onStream", "onStat", "onKeyFrameRequested", "__publicField", "Debug_default", "frame", "FpsMeter", "fps", "forceCanvasRenderer", "TrackGeneratorRenderer", "CanvasRenderer", "forceLibVPXDecoder", "WebCodecsDecoder", "LibVPxDecoder", "onFrame", "onFrameError", "_error", "wrapHeader", "timestamp", "start", "end", "keyframe", "sequence", "isVP9", "data", "flags", "header", "view", "result", "parseChunk", "prototolVersion", "ssrc", "eos", "isKeyframeRequested", "parseCcFeedback", "seq", "ts2", "prepareKeyFrameRequest", "buf", "EBML", "MAX_INT16", "TRACK_NUMBER", "MAX_BUFER_SIZE_SEC", "MIN_BUFER_SIZE_FOR_REMOVE_SEC", "MediaBuffer", "_MediaBuffer", "codec", "__publicField", "onSourceopen", "start", "Debug_default", "queue", "data", "size", "acc", "current", "result", "offset", "element", "item", "flush", "buffer", "end", "MAX_BUFER_SIZE_SEC", "MIN_BUFER_SIZE_FOR_REMOVE_SEC", "WebmBuilder", "_WebmBuilder", "BaseStreamBuilder", "participantId", "onStream", "onStat", "u", "width", "height", "segmentInfo", "videoProperties", "tracks", "TRACK_NUMBER", "clusterStartTime", "onPause", "frame", "time", "webmHeader", "segmentHeader", "timecode", "MAX_INT16", "cluster", "block", "track", "ScreenCaptureReceiver", "datachannel", "participantIdRegistry", "onStream", "onEos", "onStat", "__publicField", "Debug_default", "e", "data", "chunk", "parseChunk", "participantId", "streamBuilder", "stream", "onKeyFrameRequested", "Params", "WebmBuilder", "StreamBuilder", "ssrc", "buf", "prepareKeyFrameRequest", "error", "WebCodecsDecoder", "LibVPxDecoder", "Item", "data", "prev", "next", "__publicField", "value", "FastList", "item", "result", "center", "i", "key", "import_libvpx", "FRAME_READ_TIMEOUT", "LibVPxEncoder", "WorkerBase", "sourceTrack", "onFrame", "useCongestionControl", "maxBitrate", "__publicField", "videoTrack", "resolve", "reject", "video", "e", "playResult", "noAutoplay", "width", "height", "imageBitmap", "Debug_default", "data", "libvpx", "imageData", "keyFrame", "buffer", "bitrate", "useCbr", "fps", "WebCodecsEncoder", "WorkerBase", "sourceTrack", "onFrame", "useCongestionControl", "maxBitrate", "useCbr", "frameRate", "__publicField", "width", "height", "readable", "Debug_default", "data", "keyFrame", "bitrate", "fps", "DEFAULT_DELAY_THRESHOLD", "FAST_DELAY_THRESHOLD", "SWITCH_UP_STEP", "SWITCH_DOWN_STEP", "SWITCH_DOWN_TIMEOUT_MS", "SWITCH_UP_TIMEOUT_MS", "SWITCH_UP_PENALTY_STEP", "PROBING_TIMEOUT_MS", "MAX_PENALTY", "LARGE_DELAY_STAT_THRESHOLD_MS", "Decision", "ScreenCongestionControl", "onCongestion", "minBitrate", "maxBitrate", "ccEnabled", "fastSharing", "delayThreshold", "targetFps", "__publicField", "now", "frameNum", "delay", "bitrateK", "decision", "delayDelta", "delayDeltaPercent", "isDelayTrend", "isHighDelay", "targetBitrateK", "currentBitrateK", "Debug_default", "elapsedDown", "newBitrate", "newBitrateK", "penaltySec", "elapsedUp", "switchUpTimeout", "targetK", "elapsedProbing", "elapsedDownPenalty", "bitrate", "useCbr", "fps", "elapsed", "report", "oldFps", "PacketHistory", "maxSize", "__publicField", "seq", "ts", "size", "start", "end", "index", "ts2", "rec", "i", "iter", "current", "windowMs", "bitrateK", "elapsed", "SEQUENCE_OVERFLOW", "BITS_PER_MACROBLOCK_MIN", "BITS_PER_MACROBLOCK_MAX", "MAX_MIN_BITRATE", "MIN_MIN_BITRATE", "SEND_STAT_INTERVAL_MS", "FRAMERATE_REDUCED_DEBUGLOG_INTERVAL", "MAX_CHUNKS_IN_BUFFER", "sequence", "ScreenCaptureSender", "track", "datachannel", "signaling", "fastSharing", "__publicField", "PacketHistory", "FastList", "Debug_default", "Params", "frameRate", "minBitrate", "maxBitrate", "boundCallback", "ScreenCongestionControl", "onFrame", "frame", "e", "chunks", "WebCodecsEncoder", "useCbr", "LibVPxEncoder", "isKeyframeRequested", "cc", "parseCcFeedback", "FpsMeter", "fps", "chunk", "now", "Utils_default", "delay", "bitrateK", "head", "isKey", "totalBytes", "result", "offset", "data", "isFirst", "isLast", "wrapped", "timestamp", "start", "end", "keyframe", "wrapHeader", "bitrate", "width", "height", "minBitrateK", "maxBitrateK", "macroBlocks", "rec", "report", "_AuthData", "value", "__publicField", "AuthData", "_Params", "data", "AuthData", "Utils_default", "name", "value", "apiBaseUrl", "apiEnv", "WebRTCUtils_default", "type", "args", "Debug_default", "ScreenCaptureSender", "ScreenCaptureReceiver", "fastScreenShare", "__publicField", "Params", "compareMediaSettings", "ms1", "ms2", "createMediaSettingsWithDefaults", "ms", "stopMediaStreamTrack", "track", "stopMediaStreamTracks", "stream", "stopMediaStreamVideoTracks", "setVideoConstraints", "track", "constraints", "width", "height", "Debug_default", "VideoEffectsFpsLimiter", "EventEmitter", "__publicField", "Params", "videoEffect", "e", "Debug_default", "fps", "average", "acc", "fpsValue", "limit", "event", "fn", "MediaTrackKind", "MediaSource", "EventEmitter", "__publicField", "createMediaSettingsWithDefaults", "Params", "VideoEffectsFpsLimiter", "track", "mediaOptions", "MediaOption_default", "needEmptyTracks", "needVideo", "needAudio", "needAnimoji", "WebRTCUtils_default", "HangupReason", "FatalError_default", "error", "noDataChannel", "audio", "pc", "observer", "stream", "video", "kind", "stopMediaStreamVideoTracks", "isScreen", "from", "currentMic", "currentCam", "currentAudioLost", "currentVideoLost", "logData", "currStream", "stopMediaStreamTracks", "newTrack", "Logger", "StatLog_default", "Debug_default", "e", "fastScreenShare", "audioShare", "_audioShareTrack", "audioEffectsTrack", "sendTrack", "oldTrack", "effect", "settings", "enabled", "changeSource", "isEnabled", "created", "dimensions", "savedEffect", "audioEffectParams", "Utils_default", "fpsLimit", "limit", "constraints", "setVideoConstraints", "NavigatorPermissions", "__publicField", "WebRTCUtils_default", "listener", "cameraPermissionStatus", "microphonePermissionStatus", "ev", "error", "Debug_default", "permissionStatus", "name", "state", "device", "permissionState", "ParticipantStatus", "_call", "method", "args", "callable", "Params", "_callFilterExternalUser", "userIds", "userId", "_cloneObj", "data", "_cloneArr", "External", "onLocalStream", "stream", "mediaSettings", "onScreenStream", "onVmojiStream", "onVmojiError", "error", "onLocalStreamUpdate", "kind", "onLocalStatus", "status", "Debug_default", "onRemoteStream", "onRemoteLive", "onLocalLive", "onRemoteLiveUpdate", "onLocalLiveUpdate", "onRemoteScreenStream", "onRemoteVmojiStream", "onRemoteStreamSuspended", "mediaType", "suspended", "onConversation", "mediaModifiers", "muteStates", "participants", "rooms", "onConversationParticipantListChunk", "chunk", "onRemoteMediaSettings", "markers", "onLocalMediaSettings", "onRemoteSharedMovieInfo", "sharedMovieInfo", "roomId", "onRemoteSharedMovieStoppedInfo", "sharedMovieStoppedInfo", "onLocalSharedMovieInfo", "onLocalSharedMovieStoppedInfo", "onRemoteSharedUrl", "sharedUrl", "onParticipantAdded", "onParticipantJoined", "onLocalParticipantState", "participantState", "global", "onRemoteParticipantState", "onRemoteParticipantsState", "stateList", "onRemoteStatus", "onPermissionsRequested", "onPermissionsError", "original", "onRemoteRemoved", "onCallState", "isCallActive", "canAddParticipants", "conversation", "onDeviceSwitched", "mediaOption", "enabled", "onMuteStates", "unmuteOptions", "mediaOptions", "muteAll", "unmute", "adminId", "stateUpdated", "requestedMedia", "_requestedMedia", "onRolesChanged", "roles", "isInitial", "onLocalRolesChanged", "onPinnedParticipant", "unpin", "onLocalPin", "onOptionsChanged", "options", "onCallAccepted", "onAcceptedCall", "capabilities", "onRateNeeded", "onSpeakerChanged", "onVolumesDetected", "volumes", "onLocalVolume", "volume", "isMicEnabled", "onJoinStatus", "available", "chatId", "onHangup", "conversationId", "onMultipartyChatCreated", "onDeviceChange", "onFingerprintChange", "fingerprint", "onTokenExpired", "onChatMessage", "message", "from", "direct", "onCustomData", "onRecordStarted", "initiator", "movieId", "startTime", "type", "externalMovieId", "externalOwnerId", "onRecordStopped", "stopBy", "onLocalNetworkStatusChanged", "rating", "onNetworkStatusChanged", "onDebugMessage", "onStatistics", "connection", "memory", "onAutoplayError", "onChatRoomUpdated", "eventType", "totalCount", "firstParticipants", "addedParticipantIds", "removedParticipantIds", "onPromoted", "demoted", "onRemoteMixedAudioStream", "onJoinLinkChanged", "joinLink", "onRoomsUpdated", "updates", "onRoomUpdated", "eventTypes", "room", "deactivate", "onRoomParticipantsUpdated", "update", "onRoomSwitched", "onRoomStart", "onFeedback", "feedback", "onFeaturesPerRoleChanged", "featuresPerRole", "onParticipantVmojiUpdate", "externalId", "onAsrSet", "onAsrStarted", "initiatorId", "onAsrStopped", "onAsrTranscription", "id", "text", "timestamp", "duration", "onParticipantIdChanged", "prevId", "newId", "onVideoSuspendSuggest", "bandwidth", "onSignalingMessage", "onPromotionApproved", "adminParticipantId", "onPeerRegistered", "External_default", "LS_PREFIX", "storage", "id", "st", "res", "_getItem", "name", "item", "_setItem", "value", "_removeItem", "LocalStorage", "get", "set", "remove", "LocalStorage_default", "_enumerateDevicesPromise", "_deviceChangeListener", "_navigatorPermissions", "_cameras", "_microphones", "_output", "_savedCam", "_savedMic", "_savedOutput", "_cameraPermissionGranted", "_microphonePermissionGranted", "_blackMediaTrack", "_blackCanvas", "_silentMediaTrack", "_isMobile", "_os", "_osVersion", "_browserData", "_audioContext", "av", "an", "ua", "eventListeners", "FacingMode", "contains", "item", "MediaConstraints", "audioDeviceId", "videoDeviceId", "videoMaxWidth", "Params", "videoMaxHeight", "frameRate", "__publicField", "ac", "microphones", "WebRTCUtils", "aDevId", "aGroupId", "mic", "forcedMic", "vc", "cameras", "vDevId", "vGroupId", "cam", "forcedCamera", "canVideo", "ScreenConstraints", "width", "height", "withAudioShare", "version", "_MediaSourceLock", "Logger", "StatLog_default", "Debug_default", "MediaSourceLock", "_updateDevices", "from", "_getDevices", "_fireEvent", "External_default", "event", "data", "fn", "Utils_default", "NavigatorPermissions", "name", "state", "devices", "device", "camDeviceId", "LocalStorage_default", "micDeviceId", "outputDeviceId", "_getOsVersion", "platformVersion", "major", "error", "_updateSavedDevices", "stream", "findDevice", "track", "deviceId", "_getUserMedia", "mediaConstraints", "lastError", "hasPermissions", "mediaSouceLock", "e", "FatalError_default", "_getDisplayMedia", "displaySurface", "_getBrowserInfo", "tmp", "isChromeBased", "chromeVersion", "subVersion", "M", "init", "getCameras", "getMicrophones", "getOutput", "hasCamera", "hasMicrophone", "getSavedCamera", "getSavedMicrophone", "getSavedOutput", "getVideoFacingMode", "hasCameraPermission", "hasMicrophonePermission", "getMicrophonePermissionState", "needVideo", "getUserMedia", "needAudio", "needEmptyTracks", "audio", "video", "getScreenMedia", "fastScreenShare", "_getUserVideo", "effectEnabled", "getUserVideo", "resolution", "getUserAudio", "setResolution", "setVideoConstraints", "_saveDeviceId", "kind", "found", "getSilentMediaTrack", "context", "streamDest", "volume", "oscillator", "getBlackMediaTrack", "ctx", "isBrowserSupported", "browserName", "browserVersion", "wnd", "isScreenCapturingSupported", "isBrokenH264Decoder", "isSafariH264Broken", "isOperaBroken", "isYandexBroken", "isBrokenVP9Encoder", "isBrokenVP9Decoder", "safariIssue", "win10Issue", "isOldDataChannelDescription", "canPreferH264", "isSimulcastSupportedByBrowser", "os", "clientStrings", "osVersion", "isMobile", "baseChromeVersion", "getAudioContext", "browserSubVersion", "isAudioShareSupported", "addEventListener", "listener", "removeEventListener", "index", "WebRTCUtils_default", "_ConversationDebugLogger", "list", "conversationId", "item", "data", "Params", "WebRTCUtils_default", "date", "time", "humanTime", "__publicField", "ConversationDebugLogger", "ArrayList", "__publicField", "data", "center", "len", "key", "value", "MAX_STORAGE_BYTES", "MAX_LOG_BYTES", "MIN_FREE_STORAGE", "MAX_SAVED_SESSIONS", "STORAGE_PREFIX", "SAVE_TIME_MS", "SavedLog", "__publicField", "st", "key", "log", "deleteLogFromStorage", "size", "strSizeBytes", "e", "a", "b", "date", "sizeNeeded", "createLogName", "str", "_writeLogToStorage", "list", "savedLog", "logName", "flushLog", "getLogs", "noDownload", "result", "item", "current", "text", "filename", "downloadLog", "data", "name", "file", "add", "level", "args", "logItem", "ConversationDebugLogger", "saveLogTimeout", "init", "ArrayList", "DebugMessageType", "Debug", "_prefix", "_onDebugMessage", "type", "args", "External_default", "_enabled", "_wrap", "fn", "level", "add", "_consoleDebug", "_consoleLog", "_consoleWarn", "_consoleError", "_externalDebug", "_externalLog", "_externalWarn", "_externalError", "enabled", "toggle", "enable", "Params", "init", "send", "test", "tag", "Debug_default", "REQUEST_KEY_FRAME_CODE", "isStopStreaming", "layout", "isRequestKeyFrame", "layoutToString", "result", "MediaType", "MEDIA_TYPE_PARAMETER", "MOVIE_ID_PARAMETER", "serializeParticipantStreamDescription", "description", "PARAMETERS_SEPARATOR", "parseParticipantStreamDescription", "descriptionString", "tokens", "userId", "mediaType", "streamName", "deviceIdx", "token", "parseMediaType", "DEVICE_IDX_PARAMETER", "Utils_default", "val", "key", "createWriteBuffer", "view", "n", "need", "x", "arr", "v", "isArrayBufferView", "buffer", "neg", "hi", "lo", "createReadBuffer", "buf", "len", "off", "UPDATE_DISPLAY_LAYOUT_CODE", "REPORT_PERF_STAT_CODE", "REPORT_SHARING_STAT_CODE", "REQUEST_ASR_CODE", "REPORT_NETWORK_STAT_CODE", "ENABLE_VIDEO_SUSPEND_CODE", "ENABLE_VIDEO_SUSPEND_SUGGEST_CODE", "CHANGE_SIMULCAST_CODE", "LAYOUT_DEFAULT", "LAYOUT_STOP_STREAM", "LAYOUT_REQUEST_KEY_FRAME", "BASE_VERSION", "RESPONSE_MESSAGE_TYPE", "FIT_TYPE_COVER", "FIT_TYPE_CONTAIN", "ProducerCommandSerializationService", "__publicField", "participantIdRegistry", "sequenceNumber", "layouts", "writeBuffer", "createWriteBuffer", "layoutBytesArray", "streamDesc", "layout", "layoutBuffer", "isStopStreaming", "isRequestKeyFrame", "compactId", "report", "params", "streamCount", "stream", "data", "readBuffer", "arrayBuffer", "blobToArrayBuffer", "createReadBuffer", "commandType", "version", "Debug_default", "sequence", "errors", "errorCodeByParticipantId", "errorData", "errorReadBuffer", "streamDescValue", "compactedId", "serializeParticipantStreamDescription", "SignalingCommandType_default", "estimatedPerformanceIndex", "SOCKET_STAT", "Stat_default", "P2Quantile", "q", "__publicField", "x", "k", "i", "d", "sign", "qip", "sorted", "b", "pos", "frac", "a", "Welford", "__publicField", "x", "delta", "StatTracker", "__publicField", "Welford", "P2Quantile", "x", "SignalingEvent", "SignalingEvent_default", "SignalingNotification", "SignalingNotification_default", "DataChannelLabel", "DataChannelLabel_default", "isObject", "isObjectsEquals", "Utils_default", "compareVideoSettings", "vs1", "vs2", "compareServerSettings", "ss1", "ss2", "compareVideoSettings", "merge", "ss", "other", "createEmptyServerSettings", "_CodecStatsAggregator", "__publicField", "getCurrentTransportTopology", "instance", "stat", "transport", "outboundRtps", "rtp", "Params", "acc", "lastVideo", "item", "kind", "mimeType", "implementation", "codecName", "totalEncodeTime", "audioCodecParams", "topology", "prevUsage", "codecUsage", "log", "Stat_default", "Logger", "CodecStatsAggregator", "BaseTransport", "EventEmitter", "signaling", "mediaSource", "__publicField", "ESTIMATED_PERFORMANCE_INDEX_KEY", "PERF_STAT_REPORT_INTERVAL_MILLIS", "NETWORK_STAT_REPORT_INTERVAL_MILLIS", "PerfStatReporter", "EventEmitter", "transport", "signaling", "directTopology", "__publicField", "stat", "state", "index", "stats", "timestamp", "Params", "isTcp", "report", "sum", "rtp", "response", "result", "callStatReport", "mapStatAddress", "isVideoInbound", "isAudioInbound", "callStat", "isUndefined", "totalSamplesDelta", "insertedSamplesDelta", "removedSamplesDelta", "concealedSamplesDelta", "silentConcealedSamplesDelta", "concealmentEventsDelta", "noNaN", "hasKeysValues", "packetsSentVideoDelta", "packetsSentAudioDelta", "packetsLostVideoDelta", "packetsLostAudioDelta", "StatAggregator", "Debug_default", "obj", "keys", "key", "includePort", "value", "WeightedAverage", "weightUp", "weightDown", "__publicField", "value", "weight", "RTT_WEIGHT", "LOSS_WEIGHT", "RTT_STEP", "RTT_STEP_WEIGHT", "LOSS_STEP", "LOSS_STEP_WEIGHT", "BITRATE_RATING_INFLUENCE_FACTOR", "GOOD_RATING_THRESHOLD", "BAD_RATING_THRESHOLD", "DirectStatReporter", "EventEmitter", "signaling", "__publicField", "WeightedAverage", "RTT_WEIGHT", "LOSS_WEIGHT", "rtt", "rttValue", "rating", "rttSteps", "RTT_STEP", "i", "RTT_STEP_WEIGHT", "loss", "lossValue", "lossSteps", "LOSS_STEP", "LOSS_STEP_WEIGHT", "bitrateA", "bitrateB", "BITRATE_RATING_INFLUENCE_FACTOR", "localNetworkStat", "remoteNetworkStat", "isTcp", "GOOD_RATING_THRESHOLD", "BAD_RATING_THRESHOLD", "settings", "stats", "result", "rtp", "statToSend", "bitrate", "now", "roundedRating", "networkState", "Params", "e", "Debug_default", "stat", "TIME_WITHOUT_UPDATE_VIDEO_FRAME", "DirectTransport", "_DirectTransport", "BaseTransport", "participantId", "isMaster", "signaling", "mediaSource", "serverSettings", "__publicField", "PerfStatReporter", "DirectStatReporter", "SignalingEvent_default", "Params", "error", "Debug_default", "DataChannelLabel_default", "dataChannel", "Logger", "StatLog_default", "peerId", "sdpPeerId", "sdpPeerIds", "settings", "compareServerSettings", "receiver", "sender", "track", "state", "message", "SignalingNotification_default", "data", "Utils_default", "candidate", "e", "candidates", "sdp", "version", "versionToUse", "event", "extraPayload", "answer", "iceRestart", "options", "offer", "description", "isChromiumBased", "WebRTCUtils_default", "newTrack", "inner", "Statistics_default", "stat", "CodecStatsAggregator", "stats", "rtp", "scalabilityMode", "item", "trackSettings", "mediaConfig", "averageNetStat", "isGoodConnection", "isBadConnection", "isLossfullConnection", "nextVideoMaxDimension", "videoSettings", "nextSettings", "rating", "statuses", "fp", "External_default", "connection", "label", "callback", "TrackId", "TrackId_default", "HEADER_SIZE", "AsrReceiver", "_AsrReceiver", "datachannel", "participantIdRegistry", "callback", "__publicField", "Debug_default", "e", "data", "view", "version", "type", "sequence", "ssrc", "timestamp", "duration", "chunk", "participantId", "asr", "_LocalNetworkRating", "__publicField", "value", "LocalNetworkRating", "import_messagepack", "ParticipantIdRegistry", "__publicField", "compactedId", "streamDescription", "data", "arr", "type", "payload", "idsMap", "descriptionString", "parseParticipantStreamDescription", "compactedIds", "ids", "compactId", "SignalingNotification_default", "speaker", "decoded", "compacted", "statuses", "participant", "status", "participantId", "stateList", "state", "compactedParticipantId", "gain", "pause", "offset", "mute", "liveStatus", "startTimeMs", "bandwidth", "Debug_default", "value", "participantUpdateInfos", "trackIdx", "sourceUpdateInfo", "compactParticipantId", "rtpTimestampAsSigned32Int", "sequenceNumber", "fastScreenShare", "suspend", "participantStreamDescription", "streamId", "TrackId_default", "rtpTimestamp", "RTP_VIDEO_CLOCKRATE", "RTP_MAX_TIMESTAMP", "ServerTransport", "_ServerTransport", "BaseTransport", "signaling", "mediaSource", "serverSettings", "__publicField", "SignalingEvent_default", "Debug_default", "state", "observer", "error", "participantId", "settings", "compareServerSettings", "receiver", "sender", "Params", "WebRTCUtils_default", "PerfStatReporter", "s", "dataChannel", "connection", "label", "callback", "e", "reconnect", "Utils_default", "ParticipantIdRegistry", "DataChannelLabel_default", "AsrReceiver", "asr", "Logger", "StatLog_default", "screenTrack", "participants", "speaker", "statuses", "description", "line", "ssrcPattern", "TrackId_default", "result", "track", "mediaSettings", "ScreenCaptureSender", "ScreenCaptureReceiver", "streamId", "stream", "stat", "videoSettings", "appliedSettings", "videoUploadEnabled", "videoUploadNeeded", "sendVideoTrack", "blackTrack", "fastScreenSettings", "event", "inner", "CodecStatsAggregator", "Statistics_default", "rtp", "audioMixRtp", "statId", "oldValue", "stalled", "diff", "capabilities", "offer", "isSimulcastSupported", "simulcast", "simTransceiver", "success", "answer", "SIMULCAST_DEFAULT", "trans", "kind", "params", "transceiver", "simulcastInfo", "calculateSimulcastInfo", "i", "downBy", "encoding", "SIMULCAST_SCALABILITY_MODE", "sdp", "nextOffer", "screenShareTransceiver", "item", "message", "SignalingNotification_default", "_pc", "pc", "data", "newTrack", "sendTrack", "replaceTrack", "t", "targetRtpTimestamp", "synchronizationSources", "rtpTimestamp", "rtpTimestampDiff", "wallclockDiff", "setupEncodings", "forceCommand", "isVideoEnabled", "width", "height", "isSimulcastChanged", "isEqualSimulcastInfo", "senderParams", "findScaleResolutionDownBy", "info", "networkRating", "LocalNetworkRating", "TransportTopology", "Transport", "EventEmitter", "topology", "signaling", "mediaSource", "serverSettings", "__publicField", "SignalingEvent_default", "settings", "Debug_default", "participantId", "isMaster", "participantIds", "peerId", "observer", "force", "needOpen", "allocatedIndex", "openedIndex", "listener", "Params", "svgData", "fill", "state", "changedParticipantIds", "message", "SignalingNotification_default", "Logger", "StatLog_default", "offerTo", "offerToTypes", "offerToDeviceIdxs", "offerToComposedId", "Utils_default", "transport", "DirectTransport", "ServerTransport", "enabled", "statuses", "stream", "stalled", "stats", "track", "asr", "streamId", "error", "localStream", "data", "targetRtpTimestamp", "_StatPings", "__publicField", "StatTracker", "transport", "now", "prev", "delta", "topology", "t", "snapshot", "Logger", "Stat_default", "StatPings", "_StatSignalingCommands", "__publicField", "command", "time", "transport", "key", "tracker", "StatTracker", "topology", "snapshot", "Logger", "Stat_default", "StatSignalingCommands", "SignalingConnectionType", "SignalingConnectionType_default", "PREDICATES", "Params", "SignalingCapabilities", "predicates", "flagsMask", "i", "mask", "flags", "acc", "value", "index", "fflate", "MAX_6_BIT", "MAX_14_BIT", "MAX_62_BIT", "VariableLengthIntegerEncoder", "num", "n", "MAX_6_BIT", "MAX_14_BIT", "VariableLengthIntegerDecoder", "data", "byteNum", "lengthPrefix", "LengthPrefixedTextEncoder", "compression", "__publicField", "VariableLengthIntegerEncoder", "data", "encodedData", "lengthPrefix", "result", "LengthPrefixedTextDecoder", "VariableLengthIntegerDecoder", "decodedStrings", "messageData", "len", "WebTransportEventual", "url", "options", "__publicField", "LengthPrefixedTextEncoder", "LengthPrefixedTextDecoder", "compression", "Debug_default", "error", "done", "value", "data", "decodedString", "chunk", "code", "reason", "err", "WebRTCUtils_default", "Params", "DATA_CHANNEL_STATE_OPEN", "RESEND_COUNT", "FATAL_ERRORS", "Signaling", "_Signaling", "BaseSignaling", "__publicField", "Params", "SignalingCapabilities", "ProducerCommandSerializationService", "endpoint", "conversationId", "participantIdRegistry", "dataChannel", "event", "notification", "response", "reason", "Debug_default", "status", "connectionType", "resolve", "reject", "Logger", "StatLog_default", "message", "error", "command", "params", "needResponse", "retryCount", "participantId", "Utils_default", "userId", "sendNow", "signalingCommand", "onError", "force", "sequence", "statMarkName", "Statistics_default", "SignalingCommandType_default", "candidate", "consumerCommand", "producerCommand", "sdp", "extraPayload", "data", "mediaSettings", "state", "compositeUserId", "externalIds", "participantIds", "ban", "description", "capabilities", "ssrcs", "priorities", "layouts", "sharedUrl", "rooms", "assignRandomly", "roomIds", "deactivate", "toRoomId", "withParticipants", "conf", "topology", "report", "count", "roles", "revoke", "muteStates", "requestedMedia", "roomId", "feature", "unpin", "mediaModifiers", "enabled", "changeSimulcast", "changes", "fromId", "backward", "demote", "unrequest", "key", "isReady", "participantListChunkParameters", "request", "useWebTransport", "dynamicPostfix", "SignalingConnectionType_default", "setParticipantChunkInitParams", "WebTransportEventual", "postfix", "partIdx", "partCount", "code", "StatPings", "External_default", "msg", "e", "SignalingEvent_default", "SignalingNotification_default", "isFatalError", "HangupReason", "HangupType_default", "FatalError_default", "cachedMessages", "delay", "StatSignalingCommands", "queue", "binary", "serializedLayoutByStreamDescription", "streamDesc", "layoutToString", "statEvent", "SOCKET_STAT", "StatAggregator", "CallDirection", "CallDirection_default", "CallType", "CallType_default", "ChatRoomEventType", "ChatRoomEventType_default", "ConversationFeature", "ConversationFeature_default", "ConversationOption", "ConversationOption_default", "compareOptions", "oldOptions", "newOptions", "option", "applyOptionChanges", "options", "changes", "set", "enabled", "MuteState", "MuteState_default", "ParticipantState", "ParticipantState_default", "RoomsEventType", "RoomsEventType_default", "UpdateDisplayLayoutErrorReason", "UpdateDisplayLayoutErrorReason_default", "getUpdateDisplayLayoutErrorReasonByCode", "errorCode", "UserRole", "UserRole_default", "compareUserRoles", "oldRoles", "newRoles", "role", "ExternalIdType", "ExternalIdUtils", "fromIds", "ids", "id", "fromId", "type", "deviceIdx", "fromSignalingParticipant", "participant", "useDecorative", "externalId", "fromSignaling", "signalingId", "toSignaling", "toString", "fromIdToString", "fromString", "stringId", "compare", "id1", "id2", "getDeviceIdx", "waitingParticipantIdToString", "id", "e", "Debug_default", "waitingParticipantIdFromString", "getMediaOptionsByMuteState", "muteStates", "value", "Utils_default", "acc", "muteState", "mediaOption", "extractConnectionMuteStates", "connection", "muteOption", "isMediaEnabled", "mediaSettings", "MediaOption_default", "filterReconnectMuteStates", "MuteState_default", "filterReconnectedParticipantMuteStates", "participant", "filterReconnectedConversationMuteStates", "meParticipant", "lz4Decompress", "input", "outputLength", "output", "inputPos", "outputPos", "token", "literalLen", "matchLen", "byte", "i", "offset", "startPos", "AudioFix", "mediaSource", "__publicField", "audioRtp", "Logger", "StatLog_default", "Debug_default", "WebRTCUtils_default", "maxPacketsPerSec", "now", "packetsPerSec", "rtps", "item", "videoRtp", "AudioOutput", "statFirstMediaReceived", "__publicField", "track", "volume", "Params", "canAutoPlayAudio", "WebRTCUtils_default", "audio", "onPlayFailed", "Debug_default", "External_default", "play", "newTrack", "playResult", "recover", "currentTrack", "output", "error", "Logger", "StatLog_default", "MAX_MEMORY_PERCENT_THRESHOLD", "LOG_MEMORY_PERCENT_THRESHOLD", "DebugInfo", "EventEmitter", "__publicField", "stats", "participants", "item", "participant", "External_default", "memory", "memoryPercent", "memoryMiB", "Debug_default", "AUDIO_FREQUENCY", "VolumeDetector", "id", "track", "__publicField", "audioContext", "WebRTCUtils_default", "binFreqSize", "start", "Params", "end", "bins", "real", "b", "smoothed", "LocalVolumeDetector", "EventEmitter", "mediaSource", "__publicField", "timer", "External_default", "Params", "reinit", "track", "data", "VolumeDetector", "SignalingActor", "processor", "__publicField", "message", "Debug_default", "VolumesDetector", "EventEmitter", "transport", "__publicField", "trackId", "stream", "track", "VolumeDetector", "inner", "Params", "participantId", "volumes", "level", "TrackId_default", "participants", "topology", "SpeakerDetector", "EventEmitter", "volumesDetector", "transport", "topology", "__publicField", "volumes", "max", "maxId", "participantId", "level", "Params", "currentSpeakerLevel", "speakerId", "SpecListener", "EventEmitter", "transport", "volumesDetector", "participants", "__publicField", "participantId", "mediaSettings", "participantIds", "state", "Params", "Debug_default", "Logger", "StatLog_default", "volumes", "notConnected", "platforms", "platform", "participant", "EventMetricsService", "_EventMetricsService", "hangup", "HangupType_default", "reason", "topology", "errorCode", "Logger", "Stat_default", "StatFirstMediaReceived", "__publicField", "topology", "callType", "Statistics_default", "Stat_default", "StatAggregator", "COOLDOWN_QUEUE_CLEANUP_INTERVAL_MILLIS", "COOLDOWN_QUEUE_EXPIRY_INTERVAL_MILLIS", "MAX_DEVICE_IDX", "_Conversation", "EventEmitter", "api", "externalLogger", "__publicField", "ParticipantState_default", "createEmptyServerSettings", "Utils_default", "mediaSettings", "e", "Debug_default", "Logger", "StatAggregator", "CodecStatsAggregator", "StatPings", "StatSignalingCommands", "Signaling", "SignalingActor", "HangupType_default", "Params", "Stat_default", "StatFirstMediaReceived", "AudioOutput", "COOLDOWN_QUEUE_CLEANUP_INTERVAL_MILLIS", "opponentIds", "opponentType", "mediaOptions", "payload", "joiningAllowed", "requireAuthToJoin", "onlyAdminCanShareMovie", "externalIds", "onFastStart", "StatLog_default", "HangupReason", "startedTime", "ConversationDebugLogger", "CallType_default", "connection", "CallDirection_default", "External_default", "error", "joinArgs", "observer", "rooms", "localParticipant", "newState", "convertedRequests", "room", "roomId", "roomsData", "conversationId", "type", "UserType_default", "peerId", "conversationParams", "wsEndpoint", "startTime", "participant", "ConversationOption_default", "waitForAdmin", "adminIsHere", "me", "participants", "encodedString", "originalLengthStr", "base64Data", "originalLength", "binaryStr", "compressedBytes", "i", "jsonStr", "lz4Decompress", "acc", "byte", "srcp", "stne", "tkn", "trne", "trnp", "trnu", "wse", "wte", "callType", "callTypeMap", "muteStates", "muteMediaOptions", "roomsResponse", "cachedParticipants", "id", "participantListChunk", "chunkParticipant", "participantId", "reason", "participantIds", "params", "message", "ExternalIdUtils", "participantsData", "data", "ban", "volume", "isMaster", "needOpen", "errorText", "EventMetricsService", "iceServers", "turn_server", "stun_server", "urls", "item", "index", "arr", "endpoint", "wt_endpoint", "token", "client_type", "direction", "Statistics_default", "isVideo", "MediaOption_default", "conversation", "SignalingCapabilities", "internalParams", "fastStartResponse", "err", "parsedInternalParams", "el", "SignalingConnectionType_default", "chatId", "joinLink", "observedIds", "externalConversationParams", "userId", "deviceIdx", "wtEndpoint", "properties", "decorativeId", "createMediaSettingsWithDefaults", "p", "composedId", "externalId", "composedDecorativeId", "decorativeExternalId", "compositeUserId", "mediaSource", "MediaSource", "AudioFix", "SignalingEvent_default", "ChatRoomEventType_default", "chunk", "externalParticipants", "isInRoom", "externalUserType", "cachedParticipant", "unmuteOptions", "callback", "mediaOptionsMute", "getMediaOptionsByMuteState", "MuteState_default", "mediaOptionsMutePermanent", "state", "status", "decorativeOkId", "markers", "baseMarker", "value", "externalMarkers", "listType", "isReconnect", "connectionMuteStates", "extractConnectionMuteStates", "filterReconnectedConversationMuteStates", "Transport", "DebugInfo", "cachedParticipnats", "VolumesDetector", "SpeakerDetector", "LocalVolumeDetector", "SpecListener", "camerasCount", "WebRTCUtils_default", "microphonesCount", "stat", "streamDescString", "_layout", "track", "stream", "timer", "participantData", "removedParticipants", "removedParticipant", "kind", "FatalError_default", "settings", "svg", "decryptionKey", "isMe", "pId", "fill", "isScreen", "enabled", "priorities", "typedPriorities", "strExternalPriorities", "strExternalId", "key", "participantStreamDescription", "layouts", "serializeParticipantStreamDescription", "consumerCommand", "producerCommand", "layoutByStreamDescription", "layout", "isStopStreaming", "cooldownIterator", "cooldownElement", "userResponse", "groupCallUsersCount", "eventType", "eventData", "immediately", "event", "streamDesc", "parseParticipantStreamDescription", "localExternalId", "isOwnerStream", "movieData", "throwErrorOutside", "result", "errorReasonByExternalId", "streamDescriptionString", "errorCode", "streamDescription", "errorParticipant", "errorReason", "UpdateDisplayLayoutErrorReason_default", "getUpdateDisplayLayoutErrorReasonByCode", "UpdateDisplayLayoutError", "entry", "COOLDOWN_QUEUE_EXPIRY_INTERVAL_MILLIS", "participantUpdateInfos", "participantUpdateInfo", "totalCount", "firstParticipants", "addedParticipantIds", "removedParticipantIds", "okUserIds", "okUserIdsAdded", "okUserIdsRemoved", "firstUserIds", "firstExternalIds", "added", "removed", "addedExternalIds", "removedExternalIds", "movieShareInfos", "movieShareInfo", "conversationAsrInfo", "asrInfo", "urlSharingInfoByRoom", "urlSharingInfo", "initiatorId", "movieId", "source", "info", "currentRoomId", "sharedUrl", "participantStreamDesc", "fastScreenShareParticipant", "mediaType", "lastSentSequenceNumber", "streamId", "waitingTime", "msgMediaType", "appliedStream", "curStreamDesc", "curStreamId", "legacyDescription", "cameraDescription", "screenDescription", "targetRtpTimestamp", "UserRole_default", "roles", "revoke", "request", "requestedMedia", "feature", "unpin", "mediaModifiers", "changes", "options", "applyOptionChanges", "pageMarker", "count", "backward", "fromId", "waitingParticipantIdFromString", "nextPageMarker", "waitingParticipantIdToString", "timestampsMap", "timestamps", "uids", "compositeId", "demote", "unrequest", "reject", "link", "gain", "metadata", "lang", "assignRandomly", "roomIds", "deactivate", "toRoomId", "isRecord", "name", "privacy", "groupId", "remove", "king", "pawns", "hideParticipantCount", "video", "effect", "effects", "isPreset", "parameters", "serverExternalIds", "rawParticipants", "transportState", "participantListChunkParameters", "newParticipants", "fromIdx", "response", "participantState", "stateMap", "stateList", "myState", "SignalingNotification_default", "localMuteStatesCallback", "oldParticipantIds", "newParticipantIds", "newParticipant", "newPid", "newRoles", "compareUserRoles", "filterReconnectedParticipantMuteStates", "ms", "compareMediaSettings", "oldState", "oldPid", "nextRoomId", "sigParticipant", "nextState", "registerMarkersPromises", "idPromises", "stateMapped", "newMediaSettings", "delta", "merge", "maxBitrateK", "maxDimension", "videoSettings", "recordInfo", "existingRecordInfo", "recordMovieId", "externalIdStopBy", "pinnedParticipantId", "asr", "muteAll", "adminExternalId", "prevRoomId", "prevRoomMuteStates", "roomMuteStates", "prevMediaOptions", "unmute", "stateUpdated", "muteEntries", "mediaOption", "muteState", "isMuteAllForAdmin", "compareOptions", "statuses", "changed", "lastStatus", "LocalNetworkRating", "participantAgnosticStream", "newStream", "topology", "isCallActive", "canAddParticipants", "ConversationFeature_default", "volumes", "activeSpeakerId", "myLayouts", "TrackId_default", "_participantId", "_stream", "_track", "stalled", "stalledParticipants", "newStalled", "reconnect", "connected", "pid", "stats", "rtps", "available", "updates", "RoomsEventType_default", "update", "addParticipantIds", "removeParticipantIds", "addedOkIds", "resultParticipants", "addedParticipants", "isRoomChanged", "removedParticipantsIdsPromises", "participantMarker", "pinnedParticipantExternalId", "removedParticipantId", "isStartEvent", "withParticipants", "externalRooms", "externalRoom", "feedback", "f", "externalFeedback", "decorativeParticipantId", "decorativeExternalParticipantId", "newExternalId", "pendingPromises", "Conversation", "_UpdateDisplayLayoutError", "m", "participantErrors", "_endpoint", "_resolveEndpointPromise", "resetApiEndpoint", "sanitizeApiBaseUrl", "url", "_resolveApiEndpoint", "apiBaseUrl", "apiEnv", "baseEndpoint", "Params", "endpoint", "Debug_default", "e", "_resolveAndSetApiEndpointIfNeed", "sendBeakon", "method", "params", "noSession", "query", "_prepareQuery", "blob", "request", "customEndpoint", "_executeRemoteRequest", "abortController", "timeoutId", "HangupReason", "HangupType_default", "response", "responseText", "responseJson", "sendFormData", "data", "text", "AuthData", "key", "param", "BaseApi", "conversationId", "joinLink", "username", "items", "externalId", "compositeId", "decorativeId", "okId", "id", "reason", "HangupType_default", "userResponse", "groupCallUsersCount", "recordIds", "RETRY_MULTIPLIER_MS", "RETRY_MAX_TIME_MS", "Api", "BaseApi", "__publicField", "method", "data", "noSession", "apiCall", "attempt", "request", "error", "details", "key", "Debug_default", "Params", "Utils_default", "type", "FatalError_default", "hangupReasonData", "HangupReason", "isApiError", "HangupType_default", "participantId", "okId", "AuthData", "ExternalIdUtils", "decorativeOkId", "session", "response", "External_default", "items", "sendBeakon", "dataRaw", "conversationId", "startTime", "endTime", "log", "uploadUrl", "formData", "logFile", "parsedUrl", "sendFormData", "isVideo", "chatId", "SignalingCapabilities", "payload", "requireAuthToJoin", "onlyAdminCanShareMovie", "audienceMode", "audioOnly", "waitForAdmin", "closedConversation", "speakerIds", "ids", "joiningAllowed", "externalIds", "CallType_default", "uuid", "LocalStorage_default", "speakerUserIds", "id", "joinLink", "username", "observedIds", "result", "requestData", "requestedExternalIds", "cachedOkIds", "cachedExternalIds", "externalId", "stringId", "index", "item", "i", "uid", "UserType_default", "uids", "requestUids", "decorativeId", "cachedStringId", "initialId", "userId", "reason", "userResponse", "groupCallUsersCount", "Stat_default", "recordIds", "processResult", "externalUid", "okUserId", "externalParticipantId", "err", "RecordRole", "RecordRole_default", "ParticipantStateDataValue", "ArrayDequeue", "length", "__publicField", "element", "curr", "el", "ApiExternal", "apiEvn", "apiKey", "callToken", "baseApiUrl", "__publicField", "Utils_default", "session", "Params", "endpoint", "_resolveApiEndpoint", "result", "request", "conversationId", "data", "HangupType_default", "_api", "_externalLogger", "browser", "WebRTCUtils_default", "utils", "Utils_default", "setLogger", "logger", "setVideoEffects", "effects", "Params", "setAudioEffects", "setVmoji", "vmoji", "sdk", "renderingOptions", "protocolVersion", "init", "params", "Api", "adapter", "Debug_default", "HangupReason", "FatalError_default", "callTo", "externalId", "mediaOptions", "MediaOption_default", "payload", "joiningAllowed", "requireAuthToJoin", "onlyAdminCanShareMovie", "onFastStart", "externalIds", "callInternal", "CallType_default", "ids", "type", "Conversation", "HangupType_default", "processPush", "conversationId", "conversationParams", "processPushInternal", "UserType_default", "peerId", "wsEndpoint", "userId", "authorize", "authToken", "apiBaseUrl", "resetApiEndpoint", "acceptCall", "getConversationOrThrowException", "declineCall", "conversation", "joinCall", "joinCallInternal", "chatId", "joinCallByLink", "joinLink", "anonymToken", "observedIds", "hangup", "addParticipant", "participants", "addParticipantInternal", "uids", "composedUids", "uid", "removeParticipant", "ban", "removeParticipantInternal", "err", "changeDevice", "kind", "deviceIdOrFacingMode", "FacingMode", "captureScreen", "stateOrSettings", "settings", "captureVmoji", "state", "setVideoStream", "stream", "isScreen", "toggleLocalVideo", "enabled", "toggleLocalAudio", "setLocalResolution", "resolution", "changePriorities", "priorities", "changeParticipantState", "compositeUserId", "putHandsDown", "updateDisplayLayout", "layout", "grantRoles", "roles", "revoke", "grantRolesInternal", "ExternalIdUtils", "deviceIdx", "muteParticipant", "muteStates", "requestedMedia", "roomId", "muteParticipantInternal", "participantId", "pinParticipant", "unpin", "pinParticipantInternal", "setMediaModifiers", "mediaModifiers", "enableVideoSuspend", "enableVideoSuspendSuggest", "changeConversationOptions", "changes", "chatMessage", "message", "chatMessageInternal", "chatHistory", "count", "customData", "data", "customDataInternal", "startConversation", "waitForAdmin", "closedConversation", "startAudienceConversation", "audioOnly", "speakerIds", "okSpeakerIds", "createJoinLink", "removeJoinLink", "getAnonymTokenByLink", "username", "setVolume", "volume", "forceRelayPolicy", "startStream", "isRecord", "name", "movieId", "privacy", "groupId", "stopStream", "remove", "publishStream", "recordSetConf", "king", "pawns", "hideParticipantCount", "kingUid", "pawnUids", "participantIds", "getStreamInfo", "addMovie", "updateMovie", "removeMovie", "updateRooms", "rooms", "assignRandomly", "update", "room", "addParticipantIds", "removeParticipantIds", "id", "activateRooms", "roomIds", "deactivate", "switchRoom", "toRoomId", "removeRooms", "setStatisticsInterval", "value", "debug", "debugMessage", "args", "uploadDebugLogs", "ConversationDebugLogger", "logs", "startTime", "endTime", "changeVideoEffect", "effect", "changeAudioEffect", "isPreset", "setAudioStream", "setVmojiSvg", "svg", "customKey", "decryptionKey", "setVmojiFill", "fill", "getWaitingHall", "pageMarker", "backward", "getAudienceModeHands", "promoteParticipant", "demote", "requestPromotion", "acceptPromotion", "reject", "getParticipantListChunk", "participantListChunkParameters", "getParticipants", "parameters", "feedback", "key", "userFeedbackStats", "userResponse", "reason", "groupCallUsersCount", "logClientEvent", "eventType", "eventData", "immediately", "enableFeatureForRoles", "feature", "removeHistoryRecords", "recordIds", "startAsr", "stopAsr", "requestAsr", "request", "startUrlSharing", "sharedUrl", "stopUrlSharing", "version"]
7
+ }