tweb/public/5.ba1afdc7cc4a96098edc.chun...

1 line
1.1 MiB
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"version":3,"sources":["webpack:///./src/helpers/cleanUsername.ts","webpack:///./src/lib/appManagers/appUsersManager.ts","webpack:///./src/lib/appManagers/appPeersManager.ts","webpack:///./src/lib/storages/dialogs.ts","webpack:///./src/lib/storages/filters.ts","webpack:///./src/lib/appManagers/appMessagesManager.ts","webpack:///./src/helpers/string/splitStringByLength.ts","webpack:///./src/lib/appManagers/appChatsManager.ts","webpack:///./src/components/peerTitle.ts","webpack:///./src/helpers/bytes/bytesFromHex.ts","webpack:///./src/lib/appManagers/appPhotosManager.ts","webpack:///./src/lib/appManagers/appProfileManager.ts","webpack:///./src/lib/appManagers/apiUpdatesManager.ts","webpack:///./src/lib/appManagers/appStickersManager.ts","webpack:///./src/lib/appManagers/appDocsManager.ts","webpack:///./src/lib/mtproto/serverTimeManager.ts","webpack:///./src/helpers/assumeType.ts","webpack:///./src/helpers/schedulers/debounce.ts","webpack:///./src/components/visibilityIntersector.ts","webpack:///./src/helpers/array/findAndSpliceAll.ts","webpack:///./src/components/lazyLoadQueue.ts","webpack:///./src/helpers/formatPhoneNumber.ts","webpack:///./src/helpers/dom/htmlToSpan.ts","webpack:///./src/lib/appManagers/appMessagesIdsManager.ts","webpack:///./src/helpers/dom/renderImageFromUrl.ts","webpack:///./src/helpers/windowSize.ts","webpack:///./src/helpers/callbackifyAll.ts","webpack:///./src/lib/appManagers/appReactionsManager.ts","webpack:///./src/lib/appManagers/appNotificationsManager.ts","webpack:///./src/helpers/files.ts","webpack:///./src/helpers/middleware.ts","webpack:///./src/helpers/fixBase64String.ts","webpack:///./src/helpers/object/safeReplaceObject.ts","webpack:///./src/components/preloader.ts","webpack:///./src/helpers/string/limitSymbols.ts","webpack:///./src/lib/appManagers/appAvatarsManager.ts","webpack:///./src/lib/calls/groupCallState.ts","webpack:///./src/helpers/callbackify.ts","webpack:///./src/lib/searchIndex.ts","webpack:///./src/lib/appManagers/appDraftsManager.ts","webpack:///./src/lib/calls/localConferenceDescription.ts","webpack:///./src/helpers/canvas/getTextWidth.ts","webpack:///./src/components/middleEllipsis.ts","webpack:///./src/lib/appManagers/appGroupCallsManager.ts","webpack:///./src/lib/calls/helpers/createMainStreamManager.ts","webpack:///./src/helpers/array/insertInDescendSortedArray.ts","webpack:///./src/lib/appManagers/appPollsManager.ts","webpack:///./src/lib/calls/helpers/stopTrack.ts","webpack:///./src/lib/calls/streamManager.ts","webpack:///./src/lib/calls/utils.ts","webpack:///./src/helpers/object/getObjectKeysAndSort.ts","webpack:///./src/helpers/slicedArray.ts","webpack:///./src/helpers/compareValue.ts","webpack:///./src/helpers/long/compareLong.ts","webpack:///./src/config/latinizeMap.ts","webpack:///./src/helpers/cleanSearchText.ts","webpack:///./src/helpers/heavyQueue.ts","webpack:///./src/helpers/blur.ts","webpack:///./src/helpers/number/numberThousandSplitter.ts","webpack:///./src/helpers/dom/htmlToDocumentFragment.ts","webpack:///./src/lib/calls/helpers/getStream.ts","webpack:///./src/lib/calls/helpers/getVideoConstraints.ts","webpack:///./src/lib/calls/constants.ts","webpack:///./src/lib/calls/sdpBuilder.ts","webpack:///./src/lib/calls/sdp/index.ts","webpack:///./src/helpers/string/splitStringByLimitWithRest.ts","webpack:///./src/helpers/uniqueNumberGenerator.ts","webpack:///./src/lib/calls/sdp/attributeSplitted.ts","webpack:///./src/lib/calls/sdp/mediaLineParts.ts","webpack:///./src/lib/calls/sdp/line.ts","webpack:///./src/lib/calls/sdp/attributeInner.ts","webpack:///./src/lib/calls/sdp/attributes.ts","webpack:///./src/lib/calls/sdp/mediaSection.ts","webpack:///./src/lib/calls/sdp/sessionSection.ts","webpack:///./src/lib/calls/sdp/utils.ts","webpack:///./src/helpers/bytes/bytesToHex.ts","webpack:///./src/lib/mtproto/referenceDatabase.ts","webpack:///./src/lib/calls/helpers/parseMediaSectionInfo.ts","webpack:///./src/lib/calls/helpers/parseSourceGroups.ts","webpack:///./src/helpers/array/filterUnique.ts","webpack:///./src/environment/vibrateSupport.ts","webpack:///./src/helpers/string/convertInputKeyToKey.ts","webpack:///./src/helpers/object/defineNotNumerableProperties.ts","webpack:///./src/lib/opusDecodeController.ts","webpack:///./src/environment/webmSupport.ts","webpack:///./src/helpers/object/safeReplaceArrayInObject.ts","webpack:///./src/lib/appManagers/appWebPagesManager.ts","webpack:///./src/environment/imageMimeTypesSupport.ts","webpack:///./src/helpers/audioAssetPlayer.ts","webpack:///./src/lib/calls/helpers/getScreenConstraints.ts","webpack:///./src/lib/calls/helpers/getScreenStream.ts","webpack:///./src/lib/calls/stringFromLineBuilder.ts","webpack:///./src/helpers/string/escapeRegExp.ts","webpack:///./src/lib/calls/groupCallConnectionInstance.ts","webpack:///./src/lib/calls/helpers/processMediaSection.ts","webpack:///./src/lib/calls/helpers/filterServerCodecs.ts","webpack:///./src/lib/calls/helpers/fixLocalOffer.ts","webpack:///./src/lib/calls/groupCallInstance.ts","webpack:///./src/lib/calls/callConnectionInstanceBase.ts","webpack:///./src/lib/calls/helpers/createPeerConnection.ts","webpack:///./src/lib/calls/helpers/createDataChannel.ts","webpack:///./src/helpers/formatCallDuration.ts","webpack:///./src/helpers/formatDuration.ts","webpack:///./src/environment/movSupport.ts","webpack:///./src/environment/videoMimeTypesSupport.ts","webpack:///./src/lib/calls/helpers/getStreamCached.ts","webpack:///./src/lib/calls/callInstanceBase.ts","webpack:///./src/lib/calls/helpers/getAudioConstraints.ts","webpack:///./src/environment/constraintSupport.ts"],"names":["cleanUsername","username","toLowerCase","appUsersManager","storage","appStateManager","storages","users","updateUsersStatuses","timestampNow","i","this","user","updateUserStatus","clear","setInterval","rootScope","addEventListener","addMultipleEventsListeners","update","userId","user_id","status","expires","serverTimeManager","serverTimeOffset","was_online","dispatchEvent","setUserToStateIfNeeded","updateUserPhoto","photo","photo_id","forceUserOnline","date","_","safeReplaceObject","toPeerId","console","warn","updateUserName","saveApiUser","first_name","last_name","e","getSelf","id","contactsIndex","indexObject","getUserSearchText","getState","then","state","storagesResults","length","setUserNameToCache","contactsList","Array","isArray","forEach","pushContact","contactsFillPromise","resolve","peerId","appPeersManager","isUser","toUserId","getFromCache","set","getUser","delete","init","usernames","isPeerNeeded","findAndSplice","getTopPeersPromises","createSearchIndex","undefined","Set","updatedContactsList","pushToState","cached","isFulfilled","promise","invokeApi","result","saveApiUsers","contacts","contact","onContactsModified","slice","Promise","resolvedPeer","processResolvedPeer","appChatsManager","saveApiChats","chats","getPeer","getPeerId","peer","phone","add","requestPeerSingle","releaseSinglePeer","pFlags","self","format","filter","Boolean","join","query","includeSaved","sortBy","fillContacts","_contactsList","results","search","has","sort","userId1","userId2","sortName1","sortName","sortName2","localeCompare","status1","getUserStatusForSort","myUserId","myId","indexOfAndSplice","testSelfSearch","unshift","getContacts","userIds","map","block","invokeApiSingle","getInputPeerById","value","apiUpdatesManager","processLocalUpdate","peer_id","getOutputPeer","blocked","index","clearBadChars","ignoreCase","latinize","includeTag","apiUsers","override","saved","oldUser","oldSearchUsername","searchUsername","min","initials","fullName","deleted","cleanSearchText","getAbbreviation","changedPhoto","changedTitle","wasContact","newContact","onContactUpdated","formatPhoneNumber","formatted","isObject","access_hash","key","args","isBot","support","today","Date","diff","getTime","getDate","dateEl","timeEl","bot","isRegularUser","isContact","allowMin","phone_number","vcard","eventTimestamp","timestamp","updatesState","syncLoading","importContacts","phones","error","Error","type","inputContacts","j","push","client_id","toString","importedContactsResult","imported","importedContact","topPeersCache","cachedTime","now","peers","offset","limit","hash","topPeers","categories","topPeer","requestPeer","rating","contactsBlocked","count","peerIds","u","concat","c","lat","long","accuracy_radius","background","self_expires","geo_point","updates","processUpdateMessage","entities","parseEntities","trim","path","URL","wrapUrl","url","pathname","err","invokeApiCacheable","q","cacheSeconds","my_results","filterUnique","p","curIsContact","popContact","offline","showPhone","getUserInput","add_phone_privacy_exception","restrictionReasons","restriction_reason","restricted","DialogColorsFg","DialogColors","DialogColorsMap","newMethod","originMethod","String","prototype","Number","hasRights","toChatId","isRestricted","getUserPhoto","getChatPhoto","chat","getChat","migrated_to","deactivated","plainText","onlyFirstName","_limitSymbols","title","split","wrapEmojiText","chatId","isChannel","channel_id","chat_id","getUserString","getChatString","isPeerId","charAt","peerParams","substr","isMegagroup","isBroadcast","reason","text","ignorePeerId","getInputPeer","getUserInputPeer","pic","idx","Math","abs","getDialogType","getChatTyped","noforwards","appMessagesManager","appDraftsManager","appNotificationsManager","appMessagesIdsManager","folders","onUpdateFolderPeers","folder_peers","folderPeer","folder_id","dialog","dropDialog","pinned","handleDialogUnpinning","generateIndexForDialog","pushDialog","scheduleHandleNewDialogs","onUpdateDialogPinned","folderId","getDialogOnly","onUpdatePinnedDialogs","handleOrder","order","pinnedOrders","reverse","newPinned","dialogs","getFolderDialogs","dialogsResult","applyDialogs","d","getCache","peerText","getPeerSearchText","dialogsIndex","onFilterUpdate","getCachedDialogs","processDialogForFilter","filterId","processDialogForFilters","indexKey","orderIndex","left","dropDialogOnDeletion","updateFolderPeers","updateDialogPinned","updatePinnedDialogs","freezeSaving","setDialogsFromState","bind","allDialogsLoaded","top_message","getServerMessageId","topMessage","saveMessages","saveDialog","getMessageByPeer","reloadConversation","loaded","0","1","setDialogsLoaded","savePinnedOrders","dialogsOffsetDate","dialogsNum","cachedResults","offsetDate","getOffsetDate","unreadMessagesCount","unreadDialogsCount","skipMigrated","folder","getFolder","migratedTo","filtersStorage","testDialogForFilter","pinnedIndex","pinnedPeerIds","indexOf","generateDialogIndex","generateDialogPinnedDateByIndex","pinned_peers","skipped","isPinned","filters","getDialogIndexKey","wasIndex","findIndex","wasDialog","wasDialogIndex","newDialogIndex","setDialogIndexInFilter","prepareFolderUnreadCountModifyingByDialog","splice","insertInDescendSortedArray","callbacks","callback","toggle","wasUnreadCount","getDialogUnreadCount","newUnreadCount","addMessagesCount","addDialogsCount","modifyFolderUnreadCount","max","dispatchUnreadTimeout","ctx","setTimeout","justReturn","message","topDate","generateDialogPinnedDate","channelId","channel","draft","foundIndex","pts","historyStorage","getHistoryStorage","messagesStorage","getMessagesStorage","history","incomingMessage","mid","getMessageFromStorage","is_outgoing","fromId","viaBotId","isAnyChat","newPts","getChannelState","ignoreOffsetDate","saveGlobalOffset","pos","setDialogToState","getDialogOffsetDate","savedGlobalOffsetDate","savedOffsetDate","isDialogsLoaded","clearDialogFromState","foundDialog","getDialog","wasPinned","keepLocal","dropped","dropDialogWithEvent","forEachReverse","messages","updatedDialogs","topPendingMessage","pendingTopMsgs","maxId","newUpdatesAfterReloadToHandle","saveUpdate","size","Object","keys","assign","kicked","wasDialogBefore","generateMessageId","wasTopMessage","generateTempMessageId","from_id","out","isOutgoing","log","migratedToPeer","migratedFromTo","migratedToFrom","read_inbox_max_id","read_outbox_max_id","saveDraft","isOut","unread","unread_count","isEnd","Bottom","insertSlice","setEnd","mergeReplyKeyboard","readMaxId","readOutboxMaxId","savePeerSettings","settings","notify_settings","addChannelState","defineNotNumerableProperties","getFilter","offsetIndex","ret","promises","fillContactsResult","reloadMissingDialogsPromise","reloadMissingPeerIds","all","getDialogs","realFolderId","curDialogStorage","indexStr","d1","d2","loadedAll","isEnoughDialogs","isTopEnd","getTopMessages","convertment","onUpdateDialogFilter","saveDialogFilter","onUpdateDialogFilterOrder","setOrderIndex","hasOwnProperty","updateDialogFilter","updateDialogFilters","oldFilters","copy","getDialogFilters","_filterId","find","updateDialogFilterOrder","reloadedPeerIds","excludePeerIds","includes","includePeerIds","exclude_archived","exclude_read","isDialogUnread","exclude_muted","isPeerLocalMuted","unread_mentions_count","broadcasts","groups","isAnyGroup","bots","non_contacts","config","pinned_infolder_count_max","reject","prepend","remove","flags","getOutputDialogFilter","bool","f","a","b","filterIncludedPinnedPeers","include_peers","reloadDialogs","inputPeer","reloadPromises","reloadPromise","overwrite","from","to","oldFilter","pendingByRandomId","pendingByMessageId","pendingAfterMsgs","tempFinalizeCallbacks","sendSmthLazyLoadQueue","needSingleMessages","Map","fetchSingleMessagesPromise","maxSeenId","newMessagesHandleTimeout","newMessagesToHandle","newDialogsToHandle","notificationsHandlePromise","notificationsToHandle","reloadConversationsPeers","logger","Debug","Log","Warn","groupedTempId","typings","unreadMentions","goToNextMentionPromises","batchUpdates","handleNewMessages","clearTimeout","handleNewDialogs","newMaxSeenId","obj","dialogsStorage","incrementMaxSeenId","handleNotifications","window","_peerId","idle","isIDLE","notifyPeerToHandle","getNotifyPeerSettings","muted","peerTypeNotifySettings","notifyAboutMessage","fwdCount","onUpdateMessageId","randomId","random_id","pendingData","tempId","threadId","finalizePendingMessageCallbacks","onUpdateNewMessage","getMessagePeer","isLocalThreadUpdate","threadKey","getThreadKey","threadsStorage","good","isInChat","ignoreExisting","pendingMessage","checkPendingMessage","updateMessageRepliesIfNeeded","findSlice","firstSlice","first","action","top_msg_id","handleNewMessage","inboxUnread","releaseUnreadCount","prepareDialogUnreadCountModifying","mentioned","modifyCachedMentions","setDialogTopMessage","notifyPeer","fwd_from","onUpdateMessageReactions","msg_id","reactions","recentReactions","recent_reactions","recentReaction","previousReactions","previousRecentReactions","deepEqual","show_previews","userReaction","pushBatchUpdate","batchUpdateReactions","local","setDialogToStateIfMessageIsTop","onUpdateDialogUnreadMark","unread_mark","onUpdateEditMessage","oldMessage","newMessage","handleEditedMessage","isTopMessage","clear_history","newReactions","grouped_id","onUpdateReadHistory","max_id","read_max_id","getObjectKeysAndSort","stillUnreadCount","still_unread_count","newUnreadMentionsCount","foundAffected","repliesKey","threadsToReplies","updateMessage","get","replyTo","reply_to","reply_to_top_id","reply_to_msg_id","cancel","setCount","getReadMaxIdIfUnread","threadKeyPart","onUpdateReadMessagesContents","mids","getMessageById","fixDialogUnreadMentionsIfNoMessage","media_unread","onUpdateChannelAvailableMessages","availableMinId","available_min_id","onUpdateDeleteMessages","clearCache","params","threadKeys","historyUpdated","handleDeletedMessages","threadsStorages","msgs","affected","onUpdateChannel","needDialog","historiesStorage","onUpdateChannelReload","onUpdateChannelMessageViews","views","batchUpdateViews","onUpdateServiceNotification","popup","messageId","inbox_date","media","hasUser","verified","pts_count","onUpdatePinnedMessages","missingMessages","wrapSingleMessage","finally","werePinned","pinnedMessages","hiddenPinnedMessages","onUpdateNotifySettings","onUpdateNewScheduledMessage","scheduledMessagesStorage","isScheduled","onUpdateDeleteScheduledMessages","batch","toDispatch","getMessagesFromMap","previousResults","changedResults","reactionCount","previousReactionCount","_reactionCount","reaction","chosen","updateMessageID","updateNewDiscussionMessage","updateNewMessage","updateNewChannelMessage","updateDialogUnreadMark","updateEditMessage","updateEditChannelMessage","updateMessageReactions","updateReadChannelDiscussionInbox","updateReadChannelDiscussionOutbox","updateReadHistoryInbox","updateReadHistoryOutbox","updateReadChannelInbox","updateReadChannelOutbox","updateChannelReadMessagesContents","updateReadMessagesContents","updateChannelAvailableMessages","updateDeleteMessages","updateDeleteChannelMessages","updateChannel","updateChannelReload","updateChannelMessageViews","updateServiceNotification","updatePinnedMessages","updatePinnedChannelMessages","updateNotifySettings","updateNewScheduledMessage","updateDeleteScheduledMessages","filterFunc","getScheduledMessagesStorage","webpage","appWebPagesManager","getWebPage","drop","poll","appPollsManager","pollToMessages","maxSeenMsgId","batchUpdatesDebounced","debounce","event","details","middleware","clean","messagesStorageByPeerId","groupedMessagesStorage","searchesStorage","threadsServiceMessagesIdsStorage","sendEntites","entity","callbackName","finalize","deferred","options","invokeAfterMessageIsSent","editMessage","parseMarkdown","schedule_date","scheduleDate","is_scheduled","newMedia","getInputEntities","no_webpage","noWebPage","handled","replyToMsgId","MAX_LENGTH","message_length_max","splitted","splitStringByLength","str","maxLength","lastSliceStartIndex","arrayIndex","cut","end","part","_arrayIndex","lastIndex","partLength","webPage","sendText","getPeerMigratedTo","generateOutgoingMessage","toggleError","on","send","sentRequestOptions","afterMessageId","sendAs","sendAsPeerId","apiPromise","invokeApiAfter","query_id","queryId","resultId","clear_draft","clearDraft","send_as","silent","wrapMessageEntities","seq","beforeMessageSending","file","attachType","apiFileName","fileType","mime_type","fileName","File","name","isDocument","Blob","caption","attributes","isPhoto","document","actionName","isVoiceMessage","attribute","voice","waveform","duration","isMedia","photoSize","w","width","h","height","location","sizes","cacheContext","appDownloadManager","getCacheContext","downloaded","objectURL","appPhotosManager","savePhoto","videoAttribute","round_message","isRoundMessage","supports_streaming","noSound","file_name","thumbs","thumb","blob","thumbCacheContext","appDocsManager","saveDoc","preloader","attachMethod","tryAgainOnFail","isUpload","sentDeferred","attachPromise","catch","uploaded","cancelPendingMessage","setTyping","uploadPromise","file_reference","inputMedia","load","thumbUploadPromise","upload","notifyAll","done","total","inputFile","force_file","addNotifyListener","progress","percents","floor","isGroupedItem","code","files","sendFile","sendFileDetails","groupId","o","invoke","multiMedia","multi_media","messageMedia","getMediaInput","doc","inputSingleMedia","inputs","contactPeerId","sendOther","getContactMediaInput","pollId","savePoll","total_voters","recent_voters","getPoll","getPhoto","getDoc","geo","geoPoint","address","provider","venue_id","venue_type","postAuthor","signatures","generateFromId","post_author","generateFlags","random","generateReplyHeader","via_bot_id","reply_markup","replyMarkup","replies","generateReplies","pending","replyToTopId","header","channelFull","appProfileManager","getCachedFullChat","linked_chat_id","comments","replies_pts","isAnonymousSending","post","originalMessage","fwdHeader","isUserHidden","from_name","userFull","getCachedFullUser","private_forward_name","channel_post","saved_from_msg_id","saved_from_peer","MAX_SAFE_INTEGER","admin_rights","anonymous","chatHistoryStorage","offset_date","offset_id","offset_peer","offsetPeerId","noErrorBox","resetPinnedOrder","telegramMeWebManager","setAuthorized","maxSeenIdIncremented","hasPrepend","noIdsDialogs","setFolderId","folderDialogs","dialogsLength","slicedDialogs","fromPeerId","dropCaptions","dropAuthor","newMessages","generateForwardHeader","group","from_peer","to_peer","with_my_score","withMyScore","drop_author","drop_media_captions","generateEmptyMessage","createMessageStorage","inputDialogPeer","getInputDialogPeerById","reloadConversationsPromise","inputDialogPeers","fullfillLeft","just_clear","revoke","affectedHistory","doFlushHistory","justClear","getHistory","historyResult","getChannelInput","s","m","ss","getPinnedMessage","getSearch","inputFilter","unpin","pm_oneside","unpinAll","unpinAllMessages","totalEntities","foundMessages","minMid","getMidsByAlbum","verify","isMessage","reply_to_mid","overwriting","msgId","savedFromPeerId","savedFromMid","savedFrom","fwdFromId","mediaContext","unsupported","ttl_seconds","originalDoc","messageKey","getMessageKeyForPendingWebPage","saveWebPage","migrateFrom","migrateTo","suffix","video_sizes","appGroupCallsManager","saveGroupCall","call","video","migrateChecks","saveMessage","apiEntities","fixEmoji","myEntities","mergeEntities","usingMids","plain","highlightWord","withoutMediaType","parts","hasAlbumKey","addPart","langKey","el","createElement","innerHTML","append","assumeType","usingFullAlbum","getMidsByMessage","albumText","getAlbumText","emoticon","question","rReply","game","stickerEmojiRaw","stickerEmoji","performer","actionWrapped","wrapMessageActionTextNew","limitSymbols","wrapPlainText","match","found","regExp","RegExp","escapeRegExp","exec","sortEntities","messageWrapped","wrapRichText","noLinebreaks","noLinks","noTextFormat","htmlToDocumentFragment","fragment","createDocumentFragment","senderTitle","classList","fromMe","getMessageSenderPeerIdOrName","element","peerTitle","fromName","onclick","href","setAttribute","unsafeMessage","langPackKey","getNameDivHTML","getPeerTitle","formatCallDuration","endsWith","wrapJoinVoiceChatAnchor","daysToStart","tomorrowDate","setDate","k","_args","IntlDateElement","day","month","year","t","pinnedMessage","fetchMessageReplyTo","isMessageIsTopMessage","dataset","dir","wrapMessageForReply","htmlToSpan","joined","anchorHTML","domain","langPack","wrapMessageActionTextNewUnsafe","botId","startParam","start_param","inviteToChannel","addChatUser","toggleDialogPin","pinned_dialogs_count_max","getPinnedOrders","getDialogPeer","read","hasChat","fromChat","kind","goodMedias","sticker","canMessageBeEdited","edit_time_limit","messageReplyMarkup","lastReplyMarkup","selective","maxOutId","single_use","hidden","canCache","func","foundMsgs","filtering","neededContents","neededDocTypes","excludeDocTypes","goodEntities","matchUrl","nextRate","backLimit","minDate","maxDate","offset_id_offset","next_rate","filterMessagesByInputFilter","method","min_date","max_date","add_offset","min_id","offsetId","offsetMessage","offset_rate","searchResult","foundCount","getDiscussionMessage","maxMessageId","serviceStartMessage","is_single","filterMessages","generateThreadServiceStartMessage","newDialogsHandlePromise","localMessageIds","creator","delete_messages","affectedMessages","force","triedToReadMaxId","readPromise","soundReset","getPeerString","readHistory","slicedArray","Top","fixUnreadMentionsCountIfNeeded","loadNextPromise","loadNextMentions","last","getUnreadMentions","mergeHistoryResult","minId","messagesMessages","msgIds","getNotifyPeerTypeSettings","getNotifySettings","getInputNotifyPeerById","threadMessage","broadcastEventName","finalizePendingMessage","muteUntil","mute_until","mute","mutePeer","canSendToUser","finalMessage","tempMessage","newPhoto","newDoc","newPhotoSize","oldCacheContext","downloadOptions","getPhotoDownloadOptions","fakeDownload","oldDoc","getInputFileName","polls","handleReleasingMessage","skipReadParticipants","skipReactionsList","emptyMessageReactionsList","next_offset","canViewMessageReadParticipants","getMessageReadParticipants","appReactionsManager","getMessageReactionsList","messageReactionsList","readParticipantsPeerIds","filteredReadParticipants","arr","some","combined","readPeerId","reactionsCount","readParticipants","nextOffset","participants_count","appConfig","chat_read_mark_size_threshold","chat_read_mark_expire_period","increment","notification","peerString","notificationMessage","noIncrement","tag","peerPhoto","getPeerPhoto","appAvatarsManager","loadAvatar","loadPromise","image","notify","canSendToPeer","isFetchIntervalNeeded","unsetEnd","Both","offsetIdOffset","haveSlice","sliceMe","fulfilled","fillHistoryStorage","constructSlice","topWasMeantToLoad","isBottomEnd","isHistoryResultEnd","requestHistory","oldestMessage","foundSlice","_historyResult","requestPromises","after","getMessagesResult","fetchSingleMessages","replyToPeerId","reply_to_peer_id","typing","timeout","smth","referenceDatabase","deleteContext","deleteWebPageFromPending","updatePollToMessage","groupedId","groupedStorage","albums","peerMessagesToHandle","deletedMids","noForwards","getElementCallback","newMap","peerIdStr","onChatUpdated","updateChannelParticipant","updateChatDefaultBannedRights","default_banned_rights","apiChats","saveApiChat","oldChat","rights","defaultRights","isThread","isCheckingRightsForSelf","megagroup","banned_rights","myFlags","post_messages","broadcast","until_date","getChannelInputPeer","getChatInputPeer","input","usersInputs","fwdLimit","fwd_limit","deleteChatUser","leaveChannel","leaveChat","deleteChannel","deleteChat","inputChatPhoto","about","participant","getParticipantPeerId","actor_id","qts","prev_participant","new_participant","kicked_by","editBanned","view_messages","kickFromChannel","messagesChats","enabled","migrateChat","available_reactions","invokeApiSingleProcess","processResult","sendAsPeers","weakMap","WeakMap","peerTitleWeakMap","querySelectorAll","PeerTitle","bytesFromHex","hexString","len","bytes","Uint8Array","ceil","start","parseInt","photos","context","oldPhoto","safeReplaceArrayInObject","saveContext","boxWidth","boxHeight","useBytes","pushDocumentSize","devicePixelRatio","bestPhotoSize","calcImageInBox","inputUser","photosResult","photoIds","isSticker","mimeType","jpegHeader","jpegTail","createObjectURL","num","getPreviewURLFromBytes","useBlur","getPreviewURLFromThumb","Image","renderImageFromUrl","noZoom","choosePhotoSize","boxSize","aspect","isFit","aspectCovered","style","ignoreCache","getImageFromStrippedThumb","queueId","onlyCache","thumb_size","dcId","dc_id","photoId","fullWidth","windowSize","fullHeight","download","getDownload","getInput","fullPhotoSize","downloadToDisc","AppProfileManager","usersFull","chatsFull","onUpdateUserTyping","typingsInPeer","cancelAction","getChatFull","onUpdatePeerBlocked","updateChatParticipants","participants","chatFull","updateChatParticipantAdd","_participants","inviter_id","version","updateChatParticipantDelete","updateUserTyping","updateChatUserTyping","updateChannelUserTyping","updatePeerBlocked","fullChat","updated","call_active","hasChatPhoto","chat_photo","refreshFullPeer","invalidateChannelParticipants","usersUserFull","full_user","profile_photo","getProfile","profile","getProfileByPeerId","getChannelFull","full_chat","exported_invite","link","exportedInvite","channelParticipant","fullChannel","processError","getChannelParticipants","cP","getTopPeers","ratingMap","processUserIds","updateResult","strippedThumb","stripped_thumb","previous","deletedList","reduce","acc","verifyParticipantForOnlineCount","chatInfo","channelParticipants","reduceParticipantsForOnlineCount","res","onlines","pendingPtsUpdates","pendingSeqUpdates","syncPending","channelStates","attached","debug","processOpts","seqStart","seq_start","forceGetDifference","processUpdate","toId","Proxy","target","saveUpdatesState","us","nextSeq","pendingUpdatesData","popPendingSeqUpdate","seqAwaiting","ptsAwaiting","curState","curPts","goodPts","goodIndex","getDifference","wasSyncing","pts_total_limit","differenceResult","other_updates","new_messages","apiMessage","nextState","intermediate_state","justAName","channelState","getChannelDifference","lastPtsUpdateTime","popPts","popSeq","popPendingPtsUpdate","newVersion","stateResult","setUpdatesProcessor","setProxy","fetch","ok","LOCAL_IDS_SET","appStickersManager","getStickerSetPromises","getStickersByEmoticonsPromises","sounds","getAnimatedEmojiStickerSet","updateNewStickerSet","stickerSet","stickerset","saveStickerSet","getGreetingStickersTimeout","getGreetingSticker","justPreload","getGreetingStickersPromise","getStickersByEmoticon","docs","greetingStickers","shift","downloadDoc","cachedSet","documents","refreshTime","useCache","saveStickers","getStickerSetInput","saveById","getStickerSet","getAnimatedEmojiSounds","emoji","animations","getAnimatedEmojiSoundsPromise","getAppConfig","emojies_sounds","sound","bytesStr","atob","file_reference_base64","charCodeAt","this_dc","invokeApiHashable","stickers","replace","isAnimation","cleanEmoji","pack","packs","preloadEmojiPromise","getAnimatedEmojiSticker","mediaSize","active","emojiSticker","toneIndex","animation","loadAnimationWorker","container","animationData","autoplay","loop","saveLottiePreview","canvas","once","preloadAnimatedEmojiStickerAnimation","soundDoc","getAnimatedEmojiSoundDocument","newSet","setToCache","needSave","installed_date","thumb_dc_id","isAnimated","animated","thumb_version","short_name","sets","covered","videos","archived","excludeFeatured","exclude_featured","foundSaved","cache","cover","allStickers","getAllStickers","includeOurStickers","preloadStickerSets","getRecentStickers","messagesStickers","installedSets","recentStickers","foundStickers","cachedStickersAnimated","cachedStickersStatic","iteratePacks","docId","docEmoticon","_doc","EXTENSION_MIME_TYPE_MAP","mov","gif","pdf","savingLottiePreview","downloading","onServiceWorkerFail","supportsStreaming","audioTitle","audioPerformer","alt","stickerSetInput","ext","pop","mappedMimeType","monthAsNumber","leadingZero","isServiceWorkerOnline","getFileURL","thumbSize","inputFileLocation","getFileDownloadOptions","preloadPhoto","tryNotToUseBytes","getThumbURL","originalPromise","isPlaySupported","reader","FileReader","onloadend","uint8","decode","readAsArrayBuffer","stickerCachedThumbs","toBlob","createDownloadAnchor","addTaskListener","task","payload","x","fn","ms","shouldRunFirst","shouldRunLast","waitingTimeout","waitingPromise","hadNewCall","_resolve","_reject","apply","_waitingTimeout","VisibilityIntersector","onVisibilityChange","items","locked","observer","IntersectionObserver","entries","changed","entry","isIntersecting","visible","getVisible","disconnect","targets","observe","unobserve","unlock","refresh","findAndSpliceAll","array","parallelLimit","queue","inProcess","lockPromise","unlockResolve","processQueue","throttle","_processQueue","item","loadItem","getItem","processItem","addElement","super","lock","intersector","unlockAndRefresh","div","intersectorTimeout","wasSeen","setProcessQueueTimeout","_queue","spliced","prefixes","maxPrefixLength","setPrefix","country","prefix","country_code","originalStr","countriesList","country_codes","prefixCountry","phoneCode","leftPattern","patterns","searchForPattern","pattern","mostMatchedPatternMatches","mostMatchedPattern","_pattern","patternMatches","symbol","html","span","AppMessagesIdsManager","tempNum","temp","MESSAGE_ID_OFFSET","MESSAGE_ID_INCREMENT","clearMessageId","toServer","l","used","loadedURLs","elem","HTMLImageElement","HTMLVideoElement","src","SVGImageElement","setAttributeNS","backgroundImage","isImage","loader","renderImageFromUrlPromise","visualViewport","innerWidth","innerHeight","callbackifyAll","values","SAVE_DOC_KEYS","REFERENCE_CONTEXT","availableReactions","getAvailableReactions","sendReactionPromises","lastSendingTimes","availableReaction","around_animation","static_icon","appear_animation","center_icon","messagesAvailableReactions","callbackify","inactive","activeAvailableReactions","getActiveAvailableReactions","unshiftQuickReaction","getQuickReaction","quickReaction","filteredChatAvailableReactions","unshiftQuickReactionInner","getAvailableReactionsForPeer","reactions_default","getReactionCached","onlyLocal","lastSendingTimeKey","myPeerId","chosenReactionIdx","chosenReaction","can_see_list","reactionCountIdx","indexes","promiseKey","editMessageUpdateIdx","editMessageUpdate","sendReaction","notificationsShown","notificationIndex","notificationsCount","soundsPlayed","vibrateSupport","peerSettings","notifyUsers","notifyChats","notifyBroadcasts","faviconEl","head","querySelector","titleBackup","titleChanged","stopped","pushInited","updateLocalSettings","updSettings","nodesktop","volume","novibrate","nopreview","nopush","needPush","isAvailable","registeredDevice","subscribe","unsubscribe","setSettings","nosound","notifications","checkMuteUntil","checkMuteUntilTimeout","closestMuteUntil","peerNotifySettings","requestPermission","Notification","removeEventListener","navigator","vibrate","mozVibrate","webkitVibrate","notificationsUiSupport","topMessagesDeferred","notifySoundEl","body","checkMuteUntilThrottled","stop","newVal","toggleToggler","tokenData","unregisterDevice","registerDevice","notificationData","period","custom","enable","resetTitle","setFavicon","clearInterval","titleInterval","getContext","beginPath","arc","PI","fillStyle","fill","fontSize","font","textBaseline","textAlign","fillText","toDataURL","getNotifyPeerTypePromise","inputKey","compare_sound","notifyContactsSignUp","prevFavicon","cloneNode","parentNode","replaceChild","notifySettings","isMuted","respectType","n","inputNotify","typeNotifySettings","getPeerLocalSettings","permission","data","testSound","icon","setLocalNotificationsDisabled","close","focus","onclose","show","hide","nextSoundAt","prevSoundVolume","filename","audio","hidePushNotifications","token_type","tokenType","token","tokenValue","other_uids","app_sandbox","secret","createPosterFromMedia","videoWidth","videoHeight","naturalWidth","naturalHeight","quality","aspectFitted","drawImage","createPosterFromVideo","onseeked","currentTime","onerror","createPosterForVideo","preloadVideo","race","onMediaLoad","readyState","HAVE_METADATA","useCanplayOnIos","getFilesFromEvent","onlyTypes","scanFiles","isDirectory","directoryReader","createReader","readEntries","itemFile","getAsFile","DataTransferItem","DragEvent","dataTransfer","clipboardData","originalEvent","webkitGetAsEntry","requestFile","accept","display","click","getMiddleware","cleanupObj","cleaned","additionalCallback","_cleanupObj","fixBase64String","toUrl","wasObject","newObject","ProgressivePreloader","detached","cancelable","streamable","onClick","contains","loadFunc","color","bold","constructContainer","construct","totalLength","downloadSvg","lastElementChild","cancelSvg","previousElementSibling","circle","firstElementChild","setProgress","startTime","onEnd","elapsedTime","delay","TRANSITION_TIME","detach","attach","parentElement","setManual","reset","useRafs","getTotalLength","strokeDasharray","limitFrom","savedAvatarURLs","getAvatarPromise","peerPhotoFileLocation","big","limitPart","img","onlyThumb","renderThumbPromise","thumbImage","animate","animationsEnabled","putAvatar","childElementCount","mutateElement","renderPromise","isDialog","isBig","getPeerColorById","avatarAvailable","avatarRendered","abbr","GROUP_CALL_STATE","SearchIndex","minChars","fullTexts","searchText","newFoundObjs","queryWords","queryWordsLength","fullText","what","foundChars","word","fullTextLength","drafts","getAllDraftPromise","updateDraftMessage","peerID","getKey","getAllDrafts","apiDraft","processApiDraft","draft1","draft2","rMessage","wrapDraftText","localDraft","saveOnServer","serverDraft","getDraft","draftsAreEqual","draftObj","isEmptyDraft","saveLocalDraft","emptyDraft","syncDraft","ConferenceEntry","port","direction","originalDirection","endpoint","connection","setDirection","transceiver","addTransceiver","source","sourceGroups","sources","isAnswer","generateSsrc","LocalConferenceDescription","sessionId","entriesByMid","entriesBySource","entriesByPeerId","setSource","setPeerId","isSending","sendEntry","recvEntry","createEntry","fromConference","conference","getTextWidth","measureText","testQueue","fontFamily","pendingTest","setTestQueue","testElement","getElementWidth","sizeType","mediaSizes","getBoundingClientRect","mapped","firstTime","textLength","multiplier","textWidth","elementWidth","textContent","fontWeight","newElementWidth","widthChanged","smallerText","smallerWidth","smallerTextLength","half","clamp","half1","half2","removeAttribute","capture","passive","MiddleEllipsisElement","HTMLElement","customElements","define","makeSsrcsFromParticipant","makeSsrcFromParticipant","audio_source","source_groups","presentation","groupCalls","nextOffsets","updateGroupCall","updateGroupCallParticipants","groupCallId","saveApiParticipants","groupCall","currentGroupCall","hangUp","audioAsset","nextOffsetsMap","setNextOffset","newNextOffset","skipCounterUpdating","getCachedParticipants","oldParticipant","hasLeft","can_self_unmute","isCurrentGroupCall","onParticipantUpdate","doNotDispatchParticipantUpdate","getGroupCall","modified","just_joined","apiParticipants","saveApiParticipant","isUpdatingMeInCurrentCall","isSharingAudio","raiseHand","raise_hand_rating","videoStopped","generateSelfVideo","connections","main","setMuted","getGroupCallInput","getInputPeerSelf","raise_hand","video_paused","videoPaused","video_stopped","presentation_paused","presentationPaused","participants_next_offset","oldCall","shouldUpdate","stopConnectingSound","playSoundWithTimeout","stopSound","cancelDelayedPlay","rejoin","joinVideo","streamManager","createAudio","constraints","getAudioConstraints","getVideoConstraints","stream","getStream","addStream","inputStream","MediaStream","createMainStreamManager","joinGroupCallInternal","bindPrefix","fixSafariAudio","CLOSED","setCurrentGroupCall","playSound","getGroupCallFull","connectionInstance","createConnectionInstance","createPeerConnection","negotiate","onTrack","iceConnectionState","startConnectingSound","getGroupCallParticipants","createDescription","createDataChannel","appendStreamToConference","handleUpdateGroupCallParticipants","updatingSdp","audioSource","mainSources","presentationSources","tsNow","prepareToSavingNextOffset","ids","groupCallParticipants","discard","changeUserMuted","getParticipantByPeerId","editParticipant","property","sortProperty","prev","next","updateMessagePoll","poll_id","saveResults","rQuestion","chosenIndexes","answer","correctAnswers","solution","solutionEntities","correct_answers","solution_entities","optionIds","answers","option","sendVote","votesList","closed","newPoll","getInputMediaPoll","stopTrack","track","AudioStreamAnalyser","streamSource","createMediaStreamSource","analyser","createAnalyser","gain","createGain","minDecibels","maxDecibels","smoothingTimeConstant","fftSize","connect","StreamManager","interval","getAmplitude","streamAnalyser","frequencyBinCount","getByteFrequencyData","analyse","counter","amplitudes","AudioContext","webkitAudioContext","outputStream","canCreateConferenceEntry","types","getTracks","addTrack","getSource","itemSource","removeTrack","finalizeAddingTrack","changeTimer","substring","oldTrack","timer","transceiverInit","streams","tracks","findEntry","createTransceiver","mediaTrackType","trackIdx","sender","replaceTrack","toTelegramSource","fromTelegramSource","scale","rms","sqrt","object","SliceEnd","compareValue","val1","val2","toExponential","str1","str2","str1Length","compareLong","sliceConstructor","getSliceConstructor","slices","None","side","deleteCount","flatten","lowerBound","upperBound","lowerIndex","upperIndex","foundSliceIndex","sliced","insertIndex","prevSlice","nextSlice","sliceOffset","findSliceOffset","sliceStart","sliceEnd","bottomWasMeantToLoad","topFulfilled","bottomFulfilled","SlicedArray","badCharsRe","trimRe","clearBadCharsAndTrim","latinizeString","ch","latinizeCh","hasTag","processSearchText","heavyQueue","processingQueue","addHeavyTask","processHeavyQueue","todo","performance","possiblePromise","process","realResult","timedChunk","isFilterAvailable","requireBlurPromise","fastBlurFunc","processBlurNext","radius","iterations","alpha","default","blurPromises","dataUri","onload","numberThousandSplitter","joiner","template","content","mediaDevices","getUserMedia","frameRate","GROUP_CALL_AMPLITUDE_ANALYSE_COUNT_MAX","GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS","WEBRTC_MEDIA_PORT","fixMediaLineType","mediaType","getConnectionTypeForMediaType","generateMediaFirstLine","payloadIds","connectionType","SDPBuilder","foundation","component","protocol","toUpperCase","priority","ip","generation","performCandidate","sId","bundleMids","bundle","transport","skipCandidates","ufrag","pwd","fingerprint","fingerprints","setup","candidates","candidate","addCandidate","streamName","addSource","ssrc","addMsid","ssrcGroup","semantics","isApplication","codec","isInactive","shouldBeSkipped","payloadTypes","addTransport","hdrexts","hdrext","uri","clockrate","channels","parameters","fbs","fb","subtype","addSsrc","addHeader","addSsrcEntry","addConference","SDP","session","mediaSections","lines","line","parsed","section","splitStringByLimitWithRest","separator","UniqueNumberGenerator","maxTries","_try","SDPAttributeSplitted","SDPMediaLineParts","missed","rest","nestedMap","makeAttributes","innerParts","fillAttributes","attributesMap","linesArray","mediaLineParts","exists","resultShouldBeArray","SDPSessionSection","parseSdp","createSection","sessionSection","lineStr","test","isIncorrectSdpLine","parseSdpLine","addSimulcast","sdp","generator","originalSsrcs","ssrcs","generate","ssrcs2","ssrcsStrLines","ssrc2","v","bytesToHex","contexts","links","originalPayload","refreshReference","postMessage","reference","getContexts","_context","getReferenceByLink","refreshEmojiesSoundsPromise","hex","newHex","newContext","parseMediaSectionInfo","clientInfo","lookupAttributeKeys","telegramSourceGroups","sdpLines","parseSourceGroups","raw","IS_VIBRATE_SUPPORTED","convertInputKeyToKey","names","props","writable","configurable","defineProperties","opusDecodeController","sampleRate","tasks","keepAlive","isPlaySupportedResult","canPlayType","wavWorker","Worker","page","onTaskEnd","worker","command","buffers","typedArray","buffer","loadWorker","loadWavWorker","terminateWorkers","executeNewTask","kill","terminate","decoderSampleRate","outputBufferSampleRate","wavBitDepth","wavSampleRate","pages","withWaveform","pushDecodeTask","dataBlob","IS_WEBM_SUPPORTED","photoTypeSet","webpages","pendingWebPages","updateWebPage","apiWebPage","oldWebPage","isUpdated","siteName","site_name","shortTitle","author","rTitle","contextHashtag","matches","shortDescriptionText","description","rDescription","contextSite","pendingSet","IMAGE_MIME_TYPES_SUPPORTED","AudioAssetPlayer","assets","assetName","play","Audio","pause","getScreenConstraints","skipAudio","getScreenStream","screenStream","getDisplayMedia","getVideoTracks","contentHint","StringFromLineBuilder","newLine","strs","negotiateThrottled","iceServers","iceTransportPolicy","bundlePolicy","rtcpMuxPolicy","iceCandidatePoolSize","dataChannel","maybeUpdateRemoteVideoConstraints","updateConstraintsInterval","localSdp","mainChannels","processedChannels","processed","sectionInfo","JSON","stringify","processMediaSection","audioChannel","videoChannel","useChannel","setEntrySource","setEntryPeerId","parse","groupCallInput","request","join_as","setData","extmap","performExtmap","filterServerCodecs","isNewConnection","getEntryByMid","originalOffer","createOffer","iceRestart","offer","hasMunged","skipAddingMulticast","mediaLine","localMLine","codecIds","newData","setPort","newSdp","newChannel","mungedSdp","fixLocalOffer","setLocalDescription","invokeJoinGroupCall","entriesToDelete","answerDescription","generateSdp","deleteEntry","signalingState","iceGatheringState","connectionState","setRemoteDescription","negotiating","updateConstraints","getTransceivers","setParameters","getParameters","degradationPreference","colibriClass","defaultConstraints","maxHeight","onStageEndpoints","minHeight","sendDataChannelData","saveInputVideoStream","safeAssign","isSpeakingMap","pinnedSources","participantsSsrcs","hadAutoPinnedSources","dispatchPinnedThrottled","pinnedSource","cleanup","MUTED","UNMUTED","MUTED_BY_ADMIN","CONNECTING","requestAudioSource","toggleMuted","getElement","clone","srcObject","raise","stopScreenSharing","addInputVideoStream","startScreenSharingPromise","startScreenSharingInternal","unpinSource","closeConnectionAndStream","isSharingScreen","startScreenSharing","startVideoSharingPromise","startVideoSharingInternal","appendToConference","isSharingVideo","stopVideoSharing","startVideoSharing","isDiscarded","tryAddTrack","getEntryBySource","oldSsrcs","pinSource","modifiedTypes","oldSsrc","oldSource","oldEntry","setEndpoint","RTCPeerConnection","dict","stopStream","closeConnection","negotiateInternal","CALL_DURATION_LANG_KEYS","showLast","modulus","formatDuration","strings","elements","VIDEO_MIME_TYPES_SUPPORTED","getStreamCached","_cache","screen","isScreen","player","hasInputTrackKind","noop","requestInputSource","isAudioGood","isVideoGood","onInputStream","isOutput","tagName","isVideo","elementEndpoint","useStream","paused","sinkId","outputDeviceId","setSinkId","appendChild","getAudioTracks","isClosing","channelCount","constraint","getSupportedConstraints","constraintSupported"],"mappings":"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IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,KAAK,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,KAAK,IAAK,KAAK,IAAK,KAAK,IAAK,KAAK,IAAK,KAAK,IAAK,KAAK,IAAK,KAAK,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,KAAK,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,IAAI,IAAK,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","file":"5.ba1afdc7cc4a96098edc.chunk.js","sourcesContent":["/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nexport default function cleanUsername(username: string) {\r\n return username && username.toLowerCase() || '';\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport filterUnique from \"../../helpers/array/filterUnique\";\nimport findAndSplice from \"../../helpers/array/findAndSplice\";\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport { CancellablePromise, deferredPromise } from \"../../helpers/cancellablePromise\";\nimport cleanSearchText from \"../../helpers/cleanSearchText\";\nimport cleanUsername from \"../../helpers/cleanUsername\";\nimport { formatFullSentTimeRaw, tsNow } from \"../../helpers/date\";\nimport { formatPhoneNumber } from \"../../helpers/formatPhoneNumber\";\nimport isObject from \"../../helpers/object/isObject\";\nimport safeReplaceObject from \"../../helpers/object/safeReplaceObject\";\nimport { isRestricted } from \"../../helpers/restrictions\";\nimport { Chat, ContactsResolvedPeer, InputContact, InputGeoPoint, InputMedia, InputPeer, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from \"../../layer\";\nimport I18n, { i18n, LangPackKey } from \"../langPack\";\n//import apiManager from '../mtproto/apiManager';\nimport apiManager from '../mtproto/mtprotoworker';\nimport { REPLIES_PEER_ID, SERVICE_PEER_ID } from \"../mtproto/mtproto_config\";\nimport serverTimeManager from \"../mtproto/serverTimeManager\";\nimport { RichTextProcessor } from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport SearchIndex from \"../searchIndex\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appChatsManager from \"./appChatsManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appStateManager from \"./appStateManager\";\n\nexport type User = MTUser.user;\nexport type TopPeerType = 'correspondents' | 'bots_inline';\nexport type MyTopPeer = {id: PeerId, rating: number};\n\nexport class AppUsersManager {\n private storage = appStateManager.storages.users;\n \n private users: {[userId: UserId]: User};\n private usernames: {[username: string]: UserId};\n private contactsIndex: SearchIndex<UserId>;\n private contactsFillPromise: CancellablePromise<AppUsersManager['contactsList']>;\n private contactsList: Set<UserId>;\n private updatedContactsList: boolean;\n \n private getTopPeersPromises: {[type in TopPeerType]?: Promise<MyTopPeer[]>};\n\n constructor() {\n this.clear(true);\n\n setInterval(this.updateUsersStatuses, 60000);\n\n rootScope.addEventListener('state_synchronized', this.updateUsersStatuses);\n\n rootScope.addMultipleEventsListeners({\n updateUserStatus: (update) => {\n const userId = update.user_id;\n const user = this.users[userId];\n if(user) {\n user.status = update.status;\n if(user.status) {\n if('expires' in user.status) {\n user.status.expires -= serverTimeManager.serverTimeOffset;\n }\n\n if('was_online' in user.status) {\n user.status.was_online -= serverTimeManager.serverTimeOffset;\n }\n }\n\n //user.sortStatus = this.getUserStatusForSort(user.status);\n rootScope.dispatchEvent('user_update', userId);\n this.setUserToStateIfNeeded(user);\n } //////else console.warn('No user by id:', userId);\n },\n\n updateUserPhoto: (update) => {\n const userId = update.user_id;\n const user = this.users[userId];\n if(user) {\n if((user.photo as UserProfilePhoto.userProfilePhoto)?.photo_id === (update.photo as UserProfilePhoto.userProfilePhoto)?.photo_id) {\n return;\n }\n\n this.forceUserOnline(userId, update.date);\n\n if(update.photo._ === 'userProfilePhotoEmpty') {\n delete user.photo;\n } else {\n user.photo = safeReplaceObject(user.photo, update.photo);\n }\n\n this.setUserToStateIfNeeded(user);\n\n rootScope.dispatchEvent('user_update', userId);\n rootScope.dispatchEvent('avatar_update', userId.toPeerId());\n } else console.warn('No user by id:', userId);\n },\n\n updateUserName: (update) => {\n const userId = update.user_id;\n const user = this.users[userId];\n if(user) {\n this.forceUserOnline(userId);\n \n this.saveApiUser({\n ...user, \n first_name: update.first_name,\n last_name: update.last_name,\n username: update.username\n }, true);\n }\n }\n });\n\n /* case 'updateContactLink':\n this.onContactUpdated(update.user_id, update.my_link._ === 'contactLinkContact');\n break; */\n\n rootScope.addEventListener('language_change', (e) => {\n const userId = this.getSelf().id;\n this.contactsIndex.indexObject(userId, this.getUserSearchText(userId));\n });\n\n appStateManager.getState().then((state) => {\n const users = appStateManager.storagesResults.users;\n if(users.length) {\n for(let i = 0, length = users.length; i < length; ++i) {\n const user = users[i];\n if(user) {\n this.users[user.id] = user;\n this.setUserNameToCache(user);\n }\n }\n }\n\n const contactsList = state.contactsList;\n if(contactsList && Array.isArray(contactsList)) {\n contactsList.forEach(userId => {\n this.pushContact(userId);\n });\n\n if(contactsList.length) {\n this.contactsFillPromise = deferredPromise();\n this.contactsFillPromise.resolve(this.contactsList);\n }\n }\n\n appStateManager.addEventListener('peerNeeded', (peerId) => {\n if(!appPeersManager.isUser(peerId)) {\n return;\n }\n \n const userId = peerId.toUserId();\n if(!this.storage.getFromCache(userId)) {\n this.storage.set({\n [userId]: this.getUser(userId)\n });\n }\n });\n\n appStateManager.addEventListener('peerUnneeded', (peerId) => {\n if(!appPeersManager.isUser(peerId)) {\n return;\n }\n\n const userId = peerId.toUserId();\n if(this.storage.getFromCache(userId)) {\n this.storage.delete(userId);\n }\n });\n });\n }\n\n public clear(init = false) {\n if(!init) {\n const users = appStateManager.storagesResults.users;\n for(const userId in this.users) {\n // const userId = +userId;\n if(!userId) continue;\n const peerId = userId.toPeerId();\n if(!appStateManager.isPeerNeeded(peerId)) {\n const user = this.users[userId];\n if(user.username) {\n delete this.usernames[cleanUsername(user.username)];\n }\n\n findAndSplice(users, (user) => user.id === userId);\n this.storage.delete(userId);\n delete this.users[userId];\n }\n }\n } else {\n this.users = {};\n this.usernames = {};\n }\n \n this.getTopPeersPromises = {};\n this.contactsIndex = this.createSearchIndex();\n this.contactsFillPromise = undefined;\n this.contactsList = new Set();\n this.updatedContactsList = false;\n }\n\n private onContactsModified() {\n const contactsList = [...this.contactsList];\n appStateManager.pushToState('contactsList', contactsList);\n }\n\n public fillContacts() {\n if(this.contactsFillPromise && this.updatedContactsList) {\n return {\n cached: this.contactsFillPromise.isFulfilled,\n promise: this.contactsFillPromise\n };\n }\n\n this.updatedContactsList = true;\n\n const promise = deferredPromise<Set<UserId>>();\n apiManager.invokeApi('contacts.getContacts').then((result) => {\n if(result._ === 'contacts.contacts') {\n this.contactsList.clear();\n \n this.saveApiUsers(result.users);\n\n result.contacts.forEach((contact) => {\n this.pushContact(contact.user_id);\n });\n\n this.onContactsModified();\n\n this.contactsFillPromise = promise;\n }\n\n promise.resolve(this.contactsList);\n }, () => {\n this.updatedContactsList = false;\n });\n\n return {\n cached: this.contactsFillPromise?.isFulfilled,\n promise: this.contactsFillPromise || (this.contactsFillPromise = promise)\n };\n }\n\n public resolveUsername(username: string): Promise<Chat | User> {\n if(username[0] === '@') {\n username = username.slice(1);\n }\n\n username = username.toLowerCase();\n if(this.usernames[username]) {\n return Promise.resolve(this.users[this.usernames[username]]);\n }\n\n return apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => {\n return this.processResolvedPeer(resolvedPeer);\n });\n }\n\n private processResolvedPeer(resolvedPeer: ContactsResolvedPeer.contactsResolvedPeer) {\n this.saveApiUsers(resolvedPeer.users);\n appChatsManager.saveApiChats(resolvedPeer.chats);\n\n return appPeersManager.getPeer(appPeersManager.getPeerId(resolvedPeer.peer)) as Chat | User;\n }\n\n public resolvePhone(phone: string) {\n return apiManager.invokeApi('contacts.resolvePhone', {phone}).then(resolvedPeer => {\n return this.processResolvedPeer(resolvedPeer) as User;\n });\n }\n\n public pushContact(id: UserId) {\n this.contactsList.add(id);\n this.contactsIndex.indexObject(id, this.getUserSearchText(id));\n appStateManager.requestPeerSingle(id.toPeerId(), 'contact');\n }\n\n public popContact(id: UserId) {\n this.contactsList.delete(id);\n this.contactsIndex.indexObject(id, ''); // delete search index\n appStateManager.releaseSinglePeer(id.toPeerId(), 'contact');\n }\n\n public getUserSearchText(id: UserId) {\n const user = this.users[id];\n if(!user) {\n return '';\n }\n\n const arr: string[] = [\n user.first_name,\n user.last_name,\n user.phone,\n user.username,\n user.pFlags.self ? I18n.format('SavedMessages', true) : '',\n user.pFlags.self ? 'Saved Messages' : ''\n ];\n\n return arr.filter(Boolean).join(' ');\n }\n\n public getContacts(query?: string, includeSaved = false, sortBy: 'name' | 'online' | 'none' = 'name') {\n return this.fillContacts().promise.then(_contactsList => {\n let contactsList = [..._contactsList];\n if(query) {\n const results = this.contactsIndex.search(query);\n const filteredContactsList = [...contactsList].filter(id => results.has(id));\n\n contactsList = filteredContactsList;\n }\n\n if(sortBy === 'name') {\n contactsList.sort((userId1, userId2) => {\n const sortName1 = (this.users[userId1] || {}).sortName || '';\n const sortName2 = (this.users[userId2] || {}).sortName || '';\n return sortName1.localeCompare(sortName2);\n });\n } else if(sortBy === 'online') {\n contactsList.sort((userId1, userId2) => {\n const status1 = appUsersManager.getUserStatusForSort(appUsersManager.getUser(userId1).status);\n const status2 = appUsersManager.getUserStatusForSort(appUsersManager.getUser(userId2).status);\n return status2 - status1;\n });\n }\n\n const myUserId = rootScope.myId.toUserId();\n indexOfAndSplice(contactsList, myUserId);\n if(includeSaved) {\n if(this.testSelfSearch(query)) {\n contactsList.unshift(myUserId);\n }\n }\n\n return contactsList;\n });\n }\n\n public getContactsPeerIds(\n query?: Parameters<AppUsersManager['getContacts']>[0], \n includeSaved?: Parameters<AppUsersManager['getContacts']>[1], \n sortBy?: Parameters<AppUsersManager['getContacts']>[2]) {\n return this.getContacts(query, includeSaved, sortBy).then(userIds => {\n return userIds.map(userId => userId.toPeerId(false));\n });\n }\n\n public toggleBlock(peerId: PeerId, block: boolean) {\n return apiManager.invokeApiSingle(block ? 'contacts.block' : 'contacts.unblock', {\n id: appPeersManager.getInputPeerById(peerId)\n }).then(value => {\n if(value) {\n apiUpdatesManager.processLocalUpdate({\n _: 'updatePeerBlocked',\n peer_id: appPeersManager.getOutputPeer(peerId),\n blocked: block\n });\n }\n\n return value;\n });\n }\n\n public testSelfSearch(query: string) {\n const user = this.getSelf();\n const index = this.createSearchIndex();\n index.indexObject(user.id, this.getUserSearchText(user.id));\n return index.search(query).has(user.id);\n }\n\n private createSearchIndex() {\n return new SearchIndex<UserId>({\n clearBadChars: true,\n ignoreCase: true,\n latinize: true,\n includeTag: true\n });\n }\n\n public saveApiUsers(apiUsers: MTUser[], override?: boolean) {\n if((apiUsers as any).saved) return;\n (apiUsers as any).saved = true;\n apiUsers.forEach((user) => this.saveApiUser(user, override));\n }\n\n private setUserNameToCache(user: MTUser.user, oldUser?: MTUser.user) {\n if(!oldUser || oldUser.username !== user.username) {\n if(oldUser?.username) {\n const oldSearchUsername = cleanUsername(oldUser.username);\n delete this.usernames[oldSearchUsername];\n }\n\n if(user.username) {\n const searchUsername = cleanUsername(user.username);\n this.usernames[searchUsername] = user.id;\n }\n }\n }\n\n public saveApiUser(user: MTUser, override?: boolean) {\n if(user._ === 'userEmpty') return;\n\n const userId = user.id;\n const oldUser = this.users[userId];\n\n // ! commented block can affect performance !\n // if(oldUser && !override) {\n // console.log('saveApiUser same');\n // return;\n // }\n\n if(user.pFlags === undefined) {\n user.pFlags = {};\n }\n\n if(user.pFlags.min && oldUser !== undefined) {\n return;\n }\n\n // * exclude from state\n // defineNotNumerableProperties(user, ['initials', 'num', 'rFirstName', 'rFullName', 'rPhone', 'sortName', 'sortStatus']);\n\n this.setUserNameToCache(user, oldUser);\n\n if(!oldUser \n || oldUser.initials === undefined \n || oldUser.sortName === undefined \n || oldUser.first_name !== user.first_name \n || oldUser.last_name !== user.last_name) {\n const fullName = user.first_name + (user.last_name ? ' ' + user.last_name : '');\n\n user.sortName = user.pFlags.deleted ? '' : cleanSearchText(fullName, false); \n user.initials = RichTextProcessor.getAbbreviation(fullName);\n } else {\n user.sortName = oldUser.sortName;\n user.initials = oldUser.initials;\n }\n\n if(user.status) {\n if((user.status as UserStatus.userStatusOnline).expires) {\n (user.status as UserStatus.userStatusOnline).expires -= serverTimeManager.serverTimeOffset;\n }\n\n if((user.status as UserStatus.userStatusOffline).was_online) {\n (user.status as UserStatus.userStatusOffline).was_online -= serverTimeManager.serverTimeOffset;\n }\n }\n\n //user.sortStatus = user.pFlags.bot ? -1 : this.getUserStatusForSort(user.status);\n\n let changedPhoto = false, changedTitle = false;\n if(oldUser === undefined) {\n this.users[userId] = user;\n } else {\n if(user.first_name !== oldUser.first_name \n || user.last_name !== oldUser.last_name \n || user.username !== oldUser.username) {\n changedTitle = true;\n }\n\n const oldPhotoId = (oldUser.photo as UserProfilePhoto.userProfilePhoto)?.photo_id;\n const newPhotoId = (user.photo as UserProfilePhoto.userProfilePhoto)?.photo_id;\n if(oldPhotoId !== newPhotoId) {\n changedPhoto = true;\n }\n\n /* if(user.pFlags.bot && user.bot_info_version !== oldUser.bot_info_version) {\n \n } */\n\n const wasContact = !!oldUser.pFlags.contact;\n const newContact = !!user.pFlags.contact;\n\n safeReplaceObject(oldUser, user);\n rootScope.dispatchEvent('user_update', userId);\n\n if(wasContact !== newContact) {\n this.onContactUpdated(userId, newContact, wasContact);\n }\n }\n\n if(changedPhoto) {\n rootScope.dispatchEvent('avatar_update', user.id.toPeerId());\n }\n\n if(changedTitle) {\n rootScope.dispatchEvent('peer_title_edit', user.id.toPeerId());\n }\n\n this.setUserToStateIfNeeded(user);\n }\n\n public setUserToStateIfNeeded(user: User) {\n if(appStateManager.isPeerNeeded(user.id.toPeerId())) {\n this.storage.set({\n [user.id]: user\n });\n }\n }\n\n public formatUserPhone(phone: string) {\n return '+' + formatPhoneNumber(phone).formatted;\n }\n\n public isUserOnlineVisible(id: UserId) {\n return this.getUserStatusForSort(id) > 3;\n }\n\n public getUserStatusForSort(status: User['status'] | UserId) {\n if(typeof(status) !== 'object') {\n status = this.getUser(status).status;\n }\n\n if(status) {\n const expires = status._ === 'userStatusOnline' ? status.expires : (status._ === 'userStatusOffline' ? status.was_online : 0);\n if(expires) {\n return expires;\n }\n\n /* const timeNow = tsNow(true);\n switch(status._) {\n case 'userStatusRecently':\n return timeNow - 86400 * 3;\n case 'userStatusLastWeek':\n return timeNow - 86400 * 7;\n case 'userStatusLastMonth':\n return timeNow - 86400 * 30;\n } */\n switch(status._) {\n case 'userStatusRecently':\n return 3;\n case 'userStatusLastWeek':\n return 2;\n case 'userStatusLastMonth':\n return 1;\n }\n }\n\n return 0;\n }\n\n public getUser(id: User | UserId) {\n if(isObject<User>(id)) {\n return id;\n }\n\n return this.users[id] || {id, pFlags: {deleted: true}, access_hash: ''} as User;\n }\n\n public getSelf() {\n return this.getUser(rootScope.myId);\n }\n\n public getUserStatusString(id: UserId): HTMLElement {\n let key: LangPackKey;\n let args: any[];\n\n switch(id) {\n case REPLIES_PEER_ID:\n key = 'Peer.RepliesNotifications';\n break;\n case SERVICE_PEER_ID:\n key = 'Peer.ServiceNotifications';\n break;\n default: {\n if(this.isBot(id)) {\n key = 'Bot';\n break;\n }\n\n const user = this.getUser(id);\n if(!user) {\n key = '' as any;\n break;\n }\n\n if(user.pFlags.support) {\n key = 'SupportStatus';\n break;\n }\n\n switch(user.status?._) {\n case 'userStatusRecently': {\n key = 'Lately';\n break;\n }\n \n case 'userStatusLastWeek': {\n key = 'WithinAWeek';\n break;\n }\n \n case 'userStatusLastMonth': {\n key = 'WithinAMonth';\n break;\n }\n \n case 'userStatusOffline': {\n const date = user.status.was_online;\n const today = new Date();\n const now = today.getTime() / 1000 | 0;\n \n const diff = now - date;\n if(diff < 60) {\n key = 'Peer.Status.justNow';\n } else if(diff < 3600) {\n key = 'Peer.Status.minAgo';\n const c = diff / 60 | 0;\n args = [c];\n } else if(diff < 86400 && today.getDate() === new Date(date * 1000).getDate()) {\n key = 'LastSeen.HoursAgo';\n const c = diff / 3600 | 0;\n args = [c];\n } else {\n key = 'Peer.Status.LastSeenAt';\n const {dateEl, timeEl} = formatFullSentTimeRaw(date);\n args = [dateEl, timeEl];\n }\n \n break;\n }\n \n case 'userStatusOnline': {\n key = 'Online';\n break;\n }\n \n default: {\n key = 'ALongTimeAgo';\n break;\n }\n }\n\n break;\n }\n }\n \n return i18n(key, args);\n }\n\n public isBot(id: UserId) {\n return this.users[id] && !!this.users[id].pFlags.bot;\n }\n\n public isContact(id: UserId) {\n return this.contactsList.has(id) || !!(this.users[id] && this.users[id].pFlags.contact);\n }\n \n public isRegularUser(id: UserId) {\n const user = this.users[id];\n return user && !this.isBot(id) && !user.pFlags.deleted && !user.pFlags.support;\n }\n\n public isNonContactUser(id: UserId) {\n return this.isRegularUser(id) && !this.isContact(id) && id.toPeerId() !== rootScope.myId;\n }\n\n public hasUser(id: UserId, allowMin?: boolean) {\n const user = this.users[id];\n return isObject(user) && (allowMin || !user.pFlags.min);\n }\n\n public canSendToUser(id: UserId) {\n const user = this.getUser(id);\n return !user.pFlags.deleted && user.id.toPeerId() !== REPLIES_PEER_ID;\n }\n\n public getUserPhoto(id: UserId) {\n const user = this.getUser(id);\n\n return user && user.photo || {\n _: 'userProfilePhotoEmpty'\n };\n }\n\n public getUserString(id: UserId) {\n const user = this.getUser(id);\n return 'u' + id + (user.access_hash ? '_' + user.access_hash : '');\n }\n\n public getUserInput(id: UserId): InputUser {\n const user = this.getUser(id);\n if(user.pFlags && user.pFlags.self) {\n return {_: 'inputUserSelf'};\n }\n\n return {\n _: 'inputUser',\n user_id: id,\n access_hash: user.access_hash\n };\n }\n\n public getUserInputPeer(id: UserId): InputPeer.inputPeerSelf | InputPeer.inputPeerUser {\n const user = this.getUser(id);\n if(user.pFlags && user.pFlags.self) {\n return {_: 'inputPeerSelf'};\n }\n\n return {\n _: 'inputPeerUser',\n user_id: id,\n access_hash: user.access_hash\n };\n }\n\n public getContactMediaInput(id: UserId): InputMedia.inputMediaContact {\n const user = this.getUser(id);\n\n return {\n _: 'inputMediaContact',\n first_name: user.first_name,\n last_name: user.last_name,\n phone_number: user.phone,\n vcard: '',\n user_id: id\n };\n }\n\n public updateUsersStatuses = () => {\n const timestampNow = tsNow(true);\n for(const i in this.users) {\n const user = this.users[i];\n this.updateUserStatus(user, timestampNow);\n }\n };\n\n public updateUserStatus(user: MTUser.user, timestampNow = tsNow(true)) {\n if(user.status &&\n user.status._ === 'userStatusOnline' &&\n user.status.expires < timestampNow) {\n user.status = {_: 'userStatusOffline', was_online: user.status.expires};\n rootScope.dispatchEvent('user_update', user.id);\n\n this.setUserToStateIfNeeded(user);\n }\n }\n\n public forceUserOnline(id: UserId, eventTimestamp?: number) {\n if(this.isBot(id)) {\n return;\n }\n\n const timestamp = tsNow(true);\n const onlineTimeFor = 60;\n if(eventTimestamp) {\n if((timestamp - eventTimestamp) >= onlineTimeFor) {\n return;\n }\n } else if(apiUpdatesManager.updatesState.syncLoading) {\n return;\n }\n\n const user = this.getUser(id);\n if(user &&\n user.status &&\n user.status._ !== 'userStatusOnline' &&\n user.status._ !== 'userStatusEmpty' &&\n !user.pFlags.support &&\n !user.pFlags.deleted) {\n\n user.status = {\n _: 'userStatusOnline',\n expires: timestamp + onlineTimeFor\n };\n \n //user.sortStatus = this.getUserStatusForSort(user.status);\n rootScope.dispatchEvent('user_update', id);\n\n this.setUserToStateIfNeeded(user);\n }\n }\n\n public importContact(first_name: string, last_name: string, phone: string) {\n return this.importContacts([{\n first_name,\n last_name,\n phones: [phone]\n }]).then(userIds => {\n if(!userIds.length) {\n const error = new Error();\n (error as any).type = 'NO_USER';\n throw error;\n }\n\n return userIds[0];\n });\n }\n\n public importContacts(contacts: {phones: string[], first_name: string, last_name: string}[]) {\n const inputContacts: InputContact[] = [];\n\n for(let i = 0; i < contacts.length; ++i) {\n for(let j = 0; j < contacts[i].phones.length; ++j) {\n inputContacts.push({\n _: 'inputPhoneContact',\n client_id: (i << 16 | j).toString(10),\n phone: contacts[i].phones[j],\n first_name: contacts[i].first_name,\n last_name: contacts[i].last_name\n });\n }\n }\n\n return apiManager.invokeApi('contacts.importContacts', {\n contacts: inputContacts\n }).then((importedContactsResult) => {\n this.saveApiUsers(importedContactsResult.users);\n\n const userIds = importedContactsResult.imported.map((importedContact) => {\n this.onContactUpdated(importedContact.user_id, true);\n return importedContact.user_id;\n });\n\n return userIds;\n });\n }\n\n public getTopPeers(type: TopPeerType) {\n if(this.getTopPeersPromises[type]) return this.getTopPeersPromises[type];\n\n return this.getTopPeersPromises[type] = appStateManager.getState().then((state) => {\n const cached = state.topPeersCache[type];\n if(cached && (cached.cachedTime + 86400e3) > Date.now() && cached.peers) {\n return cached.peers;\n }\n\n return apiManager.invokeApi('contacts.getTopPeers', {\n [type]: true,\n offset: 0,\n limit: 15,\n hash: '0'\n }).then((result) => {\n let topPeers: MyTopPeer[] = [];\n if(result._ === 'contacts.topPeers') {\n //console.log(result);\n this.saveApiUsers(result.users);\n appChatsManager.saveApiChats(result.chats);\n\n if(result.categories.length) {\n topPeers = result.categories[0].peers.map((topPeer) => {\n const peerId = appPeersManager.getPeerId(topPeer.peer);\n appStateManager.requestPeer(peerId, 'topPeer');\n return {id: peerId, rating: topPeer.rating};\n });\n }\n }\n \n state.topPeersCache[type] = {\n peers: topPeers,\n cachedTime: Date.now()\n };\n appStateManager.pushToState('topPeersCache', state.topPeersCache);\n \n return topPeers;\n });\n });\n }\n\n public getBlocked(offset = 0, limit = 0) {\n return apiManager.invokeApiSingle('contacts.getBlocked', {offset, limit}).then(contactsBlocked => {\n this.saveApiUsers(contactsBlocked.users);\n appChatsManager.saveApiChats(contactsBlocked.chats);\n const count = contactsBlocked._ === 'contacts.blocked' ? contactsBlocked.users.length + contactsBlocked.chats.length : contactsBlocked.count;\n\n const peerIds: PeerId[] = contactsBlocked.users.map(u => u.id.toPeerId()).concat(contactsBlocked.chats.map(c => c.id.toPeerId(true)));\n\n return {count, peerIds};\n });\n }\n\n public getLocated(\n lat: number, \n long: number,\n accuracy_radius: number,\n background: boolean = false,\n self_expires: number = 0\n ) {\n const geo_point: InputGeoPoint = {\n _: 'inputGeoPoint',\n lat,\n long,\n accuracy_radius\n };\n\n return apiManager.invokeApi('contacts.getLocated', {\n geo_point, \n background\n }).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates);\n return updates;\n });\n }\n\n /* public searchContacts(query: string, limit = 20) {\n return Promise.all([\n this.getContacts(query),\n apiManager.invokeApi('contacts.search', {\n q: query,\n limit\n })\n ]).then(results => {\n const [myContacts, peers] = results;\n\n this.saveApiUsers(peers.users);\n appChatsManager.saveApiChats(peers.chats);\n\n // * contacts.search returns duplicates in my_results\n const myResults = new Set(myContacts.concat(peers.my_results.map(p => appPeersManager.getPeerID(p))));\n\n const out = {\n my_results: [...myResults].slice(0, limit),\n results: peers.results.map(p => appPeersManager.getPeerID(p))\n };\n\n return out;\n });\n } */\n public searchContacts(query: string, limit = 20) {\n // handle 't.me/username' as 'username'\n const entities = RichTextProcessor.parseEntities(query);\n if(entities.length && entities[0].length === query.trim().length && entities[0]._ === 'messageEntityUrl') {\n try {\n const url = new URL(RichTextProcessor.wrapUrl(query).url);\n const path = url.pathname.slice(1);\n if(path) {\n query = path;\n }\n } catch(err) {}\n }\n\n return apiManager.invokeApiCacheable('contacts.search', {\n q: query,\n limit\n }, {cacheSeconds: 60}).then(peers => {\n this.saveApiUsers(peers.users);\n appChatsManager.saveApiChats(peers.chats);\n\n const out = {\n my_results: filterUnique(peers.my_results.map(p => appPeersManager.getPeerId(p))), // ! contacts.search returns duplicates in my_results\n results: peers.results.map(p => appPeersManager.getPeerId(p))\n };\n\n return out;\n });\n }\n\n private onContactUpdated(userId: UserId, isContact: boolean, curIsContact = this.isContact(userId)) {\n if(isContact !== curIsContact) {\n if(isContact) {\n this.pushContact(userId);\n } else {\n this.popContact(userId);\n }\n\n this.onContactsModified();\n\n rootScope.dispatchEvent('contacts_update', userId);\n }\n }\n\n public updateUsername(username: string) {\n return apiManager.invokeApi('account.updateUsername', {\n username\n }).then((user) => {\n this.saveApiUser(user);\n });\n }\n\n public setUserStatus(userId: UserId, offline: boolean) {\n if(this.isBot(userId)) {\n return;\n }\n\n const user = this.users[userId];\n if(user) {\n const status: UserStatus = offline ? {\n _: 'userStatusOffline',\n was_online: tsNow(true)\n } : {\n _: 'userStatusOnline',\n expires: tsNow(true) + 50\n };\n\n user.status = status;\n //user.sortStatus = this.getUserStatusForSort(user.status);\n rootScope.dispatchEvent('user_update', userId);\n\n this.setUserToStateIfNeeded(user);\n }\n }\n\n public addContact(userId: UserId, first_name: string, last_name: string, phone: string, showPhone?: true) {\n /* if(!userId) {\n return this.importContacts([{\n first_name,\n last_name,\n phones: [phone]\n }]);\n } */\n\n return apiManager.invokeApi('contacts.addContact', {\n id: this.getUserInput(userId),\n first_name,\n last_name,\n phone,\n add_phone_privacy_exception: showPhone\n }).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates, {override: true});\n\n this.onContactUpdated(userId, true);\n });\n }\n\n public deleteContacts(userIds: UserId[]) {\n return apiManager.invokeApi('contacts.deleteContacts', {\n id: userIds.map(userId => this.getUserInput(userId))\n }).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates, {override: true});\n\n userIds.forEach(userId => {\n this.onContactUpdated(userId, false);\n });\n });\n }\n\n public isRestricted(userId: UserId) {\n const user: MTUser.user = this.getUser(userId);\n const restrictionReasons = user.restriction_reason;\n\n return !!(user.pFlags.restricted && restrictionReasons && isRestricted(restrictionReasons));\n }\n}\n\nconst appUsersManager = new AppUsersManager();\nMOUNT_CLASS_TO.appUsersManager = appUsersManager;\nexport default appUsersManager\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport type { Chat, ChatPhoto, DialogPeer, InputChannel, InputDialogPeer, InputNotifyPeer, InputPeer, Peer, Update, User, UserProfilePhoto } from \"../../layer\";\r\nimport type { LangPackKey } from \"../langPack\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport I18n from '../langPack';\r\nimport { NULL_PEER_ID } from \"../mtproto/mtproto_config\";\r\nimport { getRestrictionReason } from \"../../helpers/restrictions\";\r\nimport isObject from \"../../helpers/object/isObject\";\r\nimport limitSymbols from \"../../helpers/string/limitSymbols\";\r\n\r\n// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC\r\n/*\r\n HTML-color IRC-color Description\r\n #c03d33 4 red\r\n #4fad2d 3 green\r\n #d09306 7 yellow\r\n #168acd 10 blue\r\n #8544d6 6 purple\r\n #cd4073 13 pink\r\n #2996ad 11 sea\r\n #ce671b 5 orange\r\n */\r\nconst DialogColorsFg = ['#fc5c51', '#0fb297', '#d09306', '#3d72ed', '#895dd5', '#cd4073', '#00c1a6', '#fa790f'];\r\nconst DialogColors = ['red', 'green', 'yellow', 'blue', 'violet', 'pink', 'cyan', 'orange'];\r\nconst DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];\r\n\r\nexport type PeerType = 'channel' | 'chat' | 'megagroup' | 'group' | 'saved';\r\nexport class AppPeersManager {\r\n /* public savePeerInstance(peerId: PeerId, instance: any) {\r\n if(peerId < 0) appChatsManager.saveApiChat(instance);\r\n else appUsersManager.saveApiUser(instance);\r\n } */\r\n\r\n public canPinMessage(peerId: PeerId) {\r\n return peerId.isUser() || appChatsManager.hasRights(peerId.toChatId(), 'pin_messages');\r\n }\r\n\r\n public getPeerPhoto(peerId: PeerId): UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto {\r\n if(this.isRestricted(peerId)) {\r\n return;\r\n }\r\n\r\n const photo = peerId.isUser() \r\n ? appUsersManager.getUserPhoto(peerId.toUserId())\r\n : appChatsManager.getChatPhoto(peerId.toChatId());\r\n\r\n return photo._ !== 'chatPhotoEmpty' && photo._ !== 'userProfilePhotoEmpty' ? photo : undefined;\r\n }\r\n\r\n public getPeerMigratedTo(peerId: PeerId) {\r\n if(peerId.isUser()) {\r\n return false;\r\n }\r\n\r\n const chat: Chat.chat = appChatsManager.getChat(peerId.toChatId());\r\n if(chat && chat.migrated_to && chat.pFlags.deactivated) {\r\n return this.getPeerId(chat.migrated_to as InputChannel.inputChannel);\r\n }\r\n \r\n return false;\r\n }\r\n\r\n public getPeerTitle(peerId: PeerId, plainText = false, onlyFirstName = false, _limitSymbols?: number) {\r\n if(!peerId) {\r\n peerId = rootScope.myId;\r\n }\r\n \r\n let title = '';\r\n if(peerId.isUser()) {\r\n const user = appUsersManager.getUser(peerId.toUserId());\r\n if(user.first_name) title += user.first_name;\r\n if(user.last_name && (!onlyFirstName || !title)) title += ' ' + user.last_name;\r\n \r\n if(!title) title = user.pFlags.deleted ? I18n.format('HiddenName', true) : user.username;\r\n else title = title.trim();\r\n } else {\r\n const chat: Chat.chat = appChatsManager.getChat(peerId.toChatId());\r\n title = chat.title;\r\n\r\n if(onlyFirstName) {\r\n title = title.split(' ')[0];\r\n }\r\n }\r\n\r\n if(_limitSymbols !== undefined) {\r\n title = limitSymbols(title, _limitSymbols, _limitSymbols);\r\n }\r\n \r\n return plainText ? title : RichTextProcessor.wrapEmojiText(title);\r\n }\r\n\r\n public getOutputPeer(peerId: PeerId): Peer {\r\n if(peerId.isUser()) {\r\n return {_: 'peerUser', user_id: peerId.toUserId()};\r\n }\r\n\r\n const chatId = peerId.toChatId();\r\n if(appChatsManager.isChannel(chatId)) {\r\n return {_: 'peerChannel', channel_id: chatId};\r\n }\r\n\r\n return {_: 'peerChat', chat_id: chatId};\r\n }\r\n\r\n public getPeerString(peerId: PeerId) {\r\n if(peerId.isUser()) {\r\n return appUsersManager.getUserString(peerId.toUserId());\r\n }\r\n return appChatsManager.getChatString(peerId.toChatId());\r\n }\r\n\r\n public getPeerUsername(peerId: PeerId): string {\r\n return this.getPeer(peerId).username || '';\r\n }\r\n\r\n public getPeer(peerId: PeerId) {\r\n return peerId.isUser()\r\n ? appUsersManager.getUser(peerId.toUserId())\r\n : appChatsManager.getChat(peerId.toChatId());\r\n }\r\n\r\n public getPeerId(peerId: {user_id: UserId} | {channel_id: ChatId} | {chat_id: ChatId} | InputPeer | PeerId | string): PeerId {\r\n if(peerId !== undefined && ((peerId as string).isPeerId ? (peerId as string).isPeerId() : false)) return peerId as PeerId;\r\n // if(typeof(peerId) === 'string' && /^[uc]/.test(peerId)) return peerId as PeerId;\r\n // if(typeof(peerId) === 'number') return peerId;\r\n else if(isObject(peerId)) {\r\n const userId = (peerId as Peer.peerUser).user_id;\r\n if(userId !== undefined) {\r\n return userId.toPeerId(false);\r\n }\r\n\r\n const chatId = (peerId as Peer.peerChannel).channel_id || (peerId as Peer.peerChat).chat_id;\r\n if(chatId !== undefined) {\r\n return chatId.toPeerId(true);\r\n }\r\n\r\n return rootScope.myId; // maybe it is an inputPeerSelf\r\n // } else if(!peerId) return 'u0';\r\n } else if(!peerId) return NULL_PEER_ID;\r\n \r\n const isUser = (peerId as string).charAt(0) === 'u';\r\n const peerParams = (peerId as string).substr(1).split('_');\r\n\r\n return isUser ? peerParams[0].toPeerId() : (peerParams[0] || '').toPeerId(true);\r\n }\r\n\r\n public getDialogPeer(peerId: PeerId): DialogPeer {\r\n return {\r\n _: 'dialogPeer',\r\n peer: this.getOutputPeer(peerId)\r\n };\r\n }\r\n\r\n public isChannel(peerId: PeerId): boolean {\r\n return !peerId.isUser() && appChatsManager.isChannel(peerId.toChatId());\r\n }\r\n\r\n public isMegagroup(peerId: PeerId) {\r\n return !peerId.isUser() && appChatsManager.isMegagroup(peerId.toChatId());\r\n }\r\n\r\n public isAnyGroup(peerId: PeerId): boolean {\r\n return !peerId.isUser() && !appChatsManager.isBroadcast(peerId.toChatId());\r\n }\r\n\r\n public isBroadcast(peerId: PeerId): boolean {\r\n return this.isChannel(peerId) && !this.isMegagroup(peerId);\r\n }\r\n\r\n public isBot(peerId: PeerId): boolean {\r\n return peerId.isUser() && appUsersManager.isBot(peerId.toUserId());\r\n }\r\n\r\n public isContact(peerId: PeerId): boolean {\r\n return peerId.isUser() && appUsersManager.isContact(peerId.toUserId());\r\n }\r\n\r\n public isUser(peerId: PeerId)/* : peerId is UserId */ {\r\n return +peerId >= 0;\r\n }\r\n \r\n public isAnyChat(peerId: PeerId) {\r\n return !this.isUser(peerId);\r\n }\r\n\r\n public isRestricted(peerId: PeerId) {\r\n return peerId.isUser() ? appUsersManager.isRestricted(peerId.toUserId()) : appChatsManager.isRestricted(peerId.toChatId());\r\n }\r\n\r\n public getRestrictionReasonText(peerId: PeerId) {\r\n const peer: Chat.channel | User.user = this.getPeer(peerId);\r\n const reason = peer.restriction_reason ? getRestrictionReason(peer.restriction_reason) : undefined;\r\n if(reason) {\r\n return reason.text;\r\n } else {\r\n return peerId.isUser() ? 'This user is restricted' : 'This chat is restricted';\r\n }\r\n }\r\n\r\n /* public getInputPeer(peerString: string): InputPeer {\r\n var firstChar = peerString.charAt(0);\r\n var peerParams = peerString.substr(1).split('_');\r\n let id = +peerParams[0];\r\n\r\n if(firstChar === 'u') {\r\n //appUsersManager.saveUserAccess(id, peerParams[1]);\r\n\r\n return {\r\n _: 'inputPeerUser',\r\n user_id: id,\r\n access_hash: peerParams[1]\r\n };\r\n } else if(firstChar === 'c' || firstChar === 's') {\r\n //appChatsManager.saveChannelAccess(id, peerParams[1]);\r\n if(firstChar === 's') {\r\n appChatsManager.saveIsMegagroup(id);\r\n }\r\n\r\n return {\r\n _: 'inputPeerChannel',\r\n channel_id: id,\r\n access_hash: peerParams[1] || '0'\r\n };\r\n } else {\r\n return {\r\n _: 'inputPeerChat',\r\n chat_id: id\r\n };\r\n }\r\n } */\r\n\r\n public getInputNotifyPeerById(peerId: PeerId, ignorePeerId: true): Exclude<InputNotifyPeer, InputNotifyPeer.inputNotifyPeer>;\r\n public getInputNotifyPeerById(peerId: PeerId, ignorePeerId?: false): InputNotifyPeer.inputNotifyPeer;\r\n public getInputNotifyPeerById(peerId: PeerId, ignorePeerId?: boolean): InputNotifyPeer {\r\n if(ignorePeerId) {\r\n if(peerId.isUser()) {\r\n return {_: 'inputNotifyUsers'};\r\n } else {\r\n if(this.isBroadcast(peerId)) {\r\n return {_: 'inputNotifyBroadcasts'};\r\n } else {\r\n return {_: 'inputNotifyChats'};\r\n }\r\n }\r\n } else {\r\n return {\r\n _: 'inputNotifyPeer', \r\n peer: this.getInputPeerById(peerId)\r\n };\r\n }\r\n }\r\n\r\n public getInputPeerById(peerId: PeerId): InputPeer {\r\n if(!peerId) {\r\n return {_: 'inputPeerEmpty'};\r\n }\r\n\r\n if(!peerId.isUser()) {\r\n const chatId = peerId.toChatId();\r\n return appChatsManager.getInputPeer(chatId);\r\n }\r\n\r\n const userId = peerId.toUserId();\r\n return appUsersManager.getUserInputPeer(userId);\r\n }\r\n\r\n public getInputPeerSelf(): InputPeer.inputPeerSelf {\r\n return {_: 'inputPeerSelf'};\r\n }\r\n\r\n public getInputDialogPeerById(peerId: PeerId | InputPeer): InputDialogPeer {\r\n return {\r\n _: 'inputDialogPeer',\r\n peer: isObject<InputPeer>(peerId) ? peerId : this.getInputPeerById(peerId)\r\n };\r\n }\r\n\r\n public getPeerColorById(peerId: PeerId, pic = true) {\r\n if(!peerId) return '';\r\n\r\n const idx = DialogColorsMap[Math.abs(+peerId) % 7];\r\n const color = (pic ? DialogColors : DialogColorsFg)[idx];\r\n return color;\r\n }\r\n\r\n public getPeerSearchText(peerId: PeerId) {\r\n let text: string;\r\n if(this.isUser(peerId)) {\r\n text = '%pu ' + appUsersManager.getUserSearchText(peerId.toUserId());\r\n } else {\r\n const chat = appChatsManager.getChat(peerId.toChatId());\r\n text = '%pg ' + (chat.title || '');\r\n }\r\n\r\n return text;\r\n }\r\n\r\n public getDialogType(peerId: PeerId): PeerType {\r\n if(this.isMegagroup(peerId)) {\r\n return 'megagroup';\r\n } else if(this.isChannel(peerId)) {\r\n return 'channel';\r\n } else if(!this.isUser(peerId)) {\r\n return 'group';\r\n } else {\r\n return peerId === rootScope.myId ? 'saved' : 'chat';\r\n }\r\n }\r\n\r\n public getDeleteButtonText(peerId: PeerId): LangPackKey {\r\n switch(this.getDialogType(peerId)) {\r\n case 'channel':\r\n return appChatsManager.hasRights(peerId.toChatId(), 'delete_chat') ? 'ChannelDelete' : 'ChatList.Context.LeaveChannel';\r\n\r\n case 'megagroup':\r\n case 'group':\r\n return appChatsManager.hasRights(peerId.toChatId(), 'delete_chat') ? 'DeleteMega' : 'ChatList.Context.LeaveGroup';\r\n \r\n default:\r\n return 'ChatList.Context.DeleteChat';\r\n }\r\n }\r\n\r\n public noForwards(peerId: PeerId) {\r\n if(peerId.isUser()) return false;\r\n else {\r\n const chat = appChatsManager.getChatTyped(peerId.toChatId());\r\n return !!(chat as Chat.chat).pFlags?.noforwards;\r\n }\r\n }\r\n}\r\n\r\nexport type IsPeerType = 'isChannel' | 'isMegagroup' | 'isAnyGroup' | 'isBroadcast' | 'isBot' | 'isContact' | 'isUser' | 'isAnyChat';\r\n\r\n[\r\n 'isChannel',\r\n 'isMegagroup',\r\n 'isAnyGroup',\r\n 'isBroadcast',\r\n 'isBot',\r\n 'isContact',\r\n 'isUser',\r\n 'isAnyChat',\r\n].forEach((value) => {\r\n const newMethod = Array.isArray(value) ? value[0] : value;\r\n const originMethod = Array.isArray(value) ? value[1] : value;\r\n // @ts-ignore\r\n String.prototype[newMethod] = function() {\r\n // @ts-ignore\r\n return appPeersManager[originMethod](this.toString());\r\n };\r\n\r\n // @ts-ignore\r\n Number.prototype[newMethod] = function() {\r\n // @ts-ignore\r\n return appPeersManager[originMethod](this);\r\n };\r\n});\r\n\r\ndeclare global {\r\n interface String {\r\n isChannel(): boolean;\r\n isMegagroup(): boolean;\r\n isAnyGroup(): boolean;\r\n isBroadcast(): boolean;\r\n isBot(): boolean;\r\n isContact(): boolean;\r\n isUser(): boolean;\r\n isAnyChat(): boolean;\r\n }\r\n\r\n interface Number {\r\n isChannel(): boolean;\r\n isMegagroup(): boolean;\r\n isAnyGroup(): boolean;\r\n isBroadcast(): boolean;\r\n isBot(): boolean;\r\n isContact(): boolean;\r\n isUser(): boolean;\r\n isAnyChat(): boolean;\r\n }\r\n}\r\n\r\nconst appPeersManager = new AppPeersManager();\r\nMOUNT_CLASS_TO.appPeersManager = appPeersManager;\r\nexport default appPeersManager;\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport type { Chat, DialogPeer, Message, MessagesPeerDialogs, Update } from \"../../layer\";\nimport type { AppChatsManager } from \"../appManagers/appChatsManager\";\nimport type { AppMessagesManager, Dialog, MyMessage } from \"../appManagers/appMessagesManager\";\nimport type { AppPeersManager } from \"../appManagers/appPeersManager\";\nimport type { AppUsersManager } from \"../appManagers/appUsersManager\";\nimport type { AppDraftsManager } from \"../appManagers/appDraftsManager\";\nimport type { AppNotificationsManager } from \"../appManagers/appNotificationsManager\";\nimport type { ApiUpdatesManager } from \"../appManagers/apiUpdatesManager\";\nimport type { ServerTimeManager } from \"../mtproto/serverTimeManager\";\nimport type { AppMessagesIdsManager } from \"../appManagers/appMessagesIdsManager\";\nimport { tsNow } from \"../../helpers/date\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport SearchIndex from \"../searchIndex\";\nimport rootScope from \"../rootScope\";\nimport { AppStateManager } from \"../appManagers/appStateManager\";\nimport { SliceEnd } from \"../../helpers/slicedArray\";\nimport { MyDialogFilter } from \"./filters\";\nimport { NULL_PEER_ID } from \"../mtproto/mtproto_config\";\nimport { NoneToVoidFunction } from \"../../types\";\nimport ctx from \"../../environment/ctx\";\nimport AppStorage from \"../storage\";\nimport type DATABASE_STATE from \"../../config/databases/state\";\nimport forEachReverse from \"../../helpers/array/forEachReverse\";\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport insertInDescendSortedArray from \"../../helpers/array/insertInDescendSortedArray\";\nimport defineNotNumerableProperties from \"../../helpers/object/defineNotNumerableProperties\";\nimport safeReplaceObject from \"../../helpers/object/safeReplaceObject\";\n\nexport type FolderDialog = {\n dialog: Dialog,\n index: number\n};\n\nexport type Folder = {\n dialogs: Dialog[],\n id: number,\n unreadMessagesCount: number,\n unreadDialogsCount: number,\n dispatchUnreadTimeout?: number\n};\n\nexport const GLOBAL_FOLDER_ID: number = undefined;\n\n// let spentTime = 0;\nexport default class DialogsStorage {\n private storage: AppStateManager['storages']['dialogs'];\n \n private dialogs: {[peerId: PeerId]: Dialog};\n\n private folders: {[folderId: number]: Folder} = {};\n\n private allDialogsLoaded: {[folder_id: number]: boolean};\n private dialogsOffsetDate: {[folder_id: number]: number};\n private pinnedOrders: {[folder_id: number]: PeerId[]};\n private dialogsNum: number;\n\n private dialogsIndex: SearchIndex<PeerId>;\n\n private cachedResults: {\n query: string,\n count: number,\n dialogs: Dialog[],\n folderId: number\n };\n\n constructor(\n private appMessagesManager: AppMessagesManager, \n private appChatsManager: AppChatsManager, \n private appPeersManager: AppPeersManager, \n private appUsersManager: AppUsersManager,\n private appDraftsManager: AppDraftsManager,\n private appNotificationsManager: AppNotificationsManager,\n private appStateManager: AppStateManager,\n private apiUpdatesManager: ApiUpdatesManager,\n private serverTimeManager: ServerTimeManager,\n private appMessagesIdsManager: AppMessagesIdsManager\n ) {\n this.storage = this.appStateManager.storages.dialogs;\n this.dialogs = this.storage.getCache();\n this.clear(true);\n\n rootScope.addEventListener('language_change', () => {\n const peerId = appUsersManager.getSelf().id.toPeerId(false);\n const dialog = this.getDialogOnly(peerId);\n if(dialog) {\n const peerText = appPeersManager.getPeerSearchText(peerId);\n this.dialogsIndex.indexObject(peerId, peerText);\n }\n });\n\n const onFilterUpdate = (filter: MyDialogFilter) => {\n const dialogs = this.getCachedDialogs(false);\n for(let i = 0; i < dialogs.length; ++i) {\n this.processDialogForFilter(dialogs[i], filter);\n }\n };\n\n rootScope.addEventListener('filter_order', () => {\n const dialogs = this.getCachedDialogs(false);\n for(const filterId in this.folders) {\n if(+filterId > 1) {\n delete this.folders[filterId];\n }\n }\n\n for(let i = 0; i < dialogs.length; ++i) {\n const dialog = dialogs[i];\n for(let i = 0; i <= 10; ++i) {\n const indexKey = `index_${i}` as ReturnType<DialogsStorage['getDialogIndexKey']>;\n dialog[indexKey] = undefined;\n }\n\n this.processDialogForFilters(dialog);\n }\n });\n\n rootScope.addEventListener('filter_update', onFilterUpdate);\n rootScope.addEventListener('filter_new', onFilterUpdate);\n\n rootScope.addEventListener('filter_delete', (filter) => {\n const dialogs = this.getCachedDialogs(false);\n\n const indexKey = `index_${filter.orderIndex}` as const;\n for(let i = 0; i < dialogs.length; ++i) {\n const dialog = dialogs[i];\n delete dialog[indexKey];\n }\n\n delete this.folders[filter.id];\n });\n\n rootScope.addEventListener('dialog_notify_settings', (dialog) => {\n this.processDialogForFilters(dialog);\n });\n\n rootScope.addEventListener('chat_update', (chatId) => {\n const chat: Chat.chat = this.appChatsManager.getChat(chatId);\n\n const peerId = chatId.toPeerId(true);\n if(chat.pFlags.left && this.getDialogOnly(peerId)) {\n this.dropDialogOnDeletion(peerId);\n }\n });\n\n rootScope.addMultipleEventsListeners({\n updateFolderPeers: this.onUpdateFolderPeers,\n\n updateDialogPinned: this.onUpdateDialogPinned,\n\n updatePinnedDialogs: this.onUpdatePinnedDialogs,\n });\n\n appStateManager.getState().then((state) => {\n this.pinnedOrders = state.pinnedOrders || {};\n if(!this.pinnedOrders[0]) this.pinnedOrders[0] = [];\n if(!this.pinnedOrders[1]) this.pinnedOrders[1] = [];\n \n const dialogs = appStateManager.storagesResults.dialogs;\n if(dialogs.length) {\n AppStorage.freezeSaving<typeof DATABASE_STATE>(this.setDialogsFromState.bind(this, dialogs), ['chats', 'dialogs', 'messages', 'users']);\n }\n\n this.allDialogsLoaded = state.allDialogsLoaded || {};\n });\n }\n\n private setDialogsFromState(dialogs: Dialog[]) {\n for(let i = 0, length = dialogs.length; i < length; ++i) {\n const dialog = dialogs[i];\n if(dialog) {\n // if(dialog.peerId !== SERVICE_PEER_ID) {\n dialog.top_message = this.appMessagesIdsManager.getServerMessageId(dialog.top_message); // * fix outgoing message to avoid copying dialog\n // }\n\n if(dialog.topMessage) {\n this.appMessagesManager.saveMessages([dialog.topMessage]);\n }\n\n for(let i = 0; i <= 10; ++i) {\n // @ts-ignore\n delete dialog[`index_${i}`];\n }\n\n this.saveDialog(dialog, undefined, true);\n\n // ! WARNING, убрать это когда нужно будет делать чтобы pending сообщения сохранялись\n const message = this.appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\n if(message.deleted) {\n this.appMessagesManager.reloadConversation(dialog.peerId);\n }\n }\n }\n }\n\n public isDialogsLoaded(folderId: number) {\n return !!this.allDialogsLoaded[folderId];\n }\n\n public setDialogsLoaded(folderId: number, loaded: boolean) {\n if(folderId === GLOBAL_FOLDER_ID && loaded) {\n this.allDialogsLoaded[0] = loaded;\n this.allDialogsLoaded[1] = loaded;\n } else {\n this.allDialogsLoaded[folderId] = loaded;\n }\n\n if(this.allDialogsLoaded[0] && this.allDialogsLoaded[1]) {\n this.allDialogsLoaded[GLOBAL_FOLDER_ID] = true;\n }\n\n this.appStateManager.pushToState('allDialogsLoaded', this.allDialogsLoaded);\n }\n\n public clear(init = false) {\n this.pinnedOrders = {\n 0: [],\n 1: []\n };\n\n if(!init) {\n const dialogs = this.appStateManager.storagesResults.dialogs;\n dialogs.length = 0;\n this.storage.clear();\n\n this.setDialogsLoaded(0, false);\n this.setDialogsLoaded(1, false);\n this.setDialogsLoaded(GLOBAL_FOLDER_ID, false);\n this.savePinnedOrders();\n } else {\n this.allDialogsLoaded = {};\n }\n\n this.folders = {};\n this.dialogsOffsetDate = {};\n this.dialogsNum = 0;\n this.dialogsIndex = new SearchIndex({\n clearBadChars: true,\n ignoreCase: true,\n latinize: true,\n includeTag: true\n });\n this.cachedResults = {\n query: '',\n count: 0,\n dialogs: [],\n folderId: 0\n };\n }\n\n public handleDialogUnpinning(dialog: Dialog, folderId: number) {\n delete dialog.pFlags.pinned;\n indexOfAndSplice(this.pinnedOrders[folderId], dialog.peerId);\n this.savePinnedOrders();\n }\n\n public savePinnedOrders() {\n this.appStateManager.pushToState('pinnedOrders', this.pinnedOrders);\n }\n\n public resetPinnedOrder(folderId: number) {\n this.pinnedOrders[folderId] = [];\n }\n\n public getPinnedOrders(folderId: number) {\n return this.pinnedOrders[folderId];\n }\n\n public getOffsetDate(folderId: number): number {\n const offsetDate = this.dialogsOffsetDate[folderId] || 0;\n if(folderId === GLOBAL_FOLDER_ID && !offsetDate) { // make request not from beginning if we have loaded some dialogs\n return Math.min(this.getOffsetDate(0), this.getOffsetDate(1));\n }\n\n return offsetDate;\n }\n\n public getFolder(id: number) {\n return this.folders[id] ?? (this.folders[id] = {dialogs: [], id, unreadMessagesCount: 0, unreadDialogsCount: 0});\n }\n\n public getFolderDialogs(id: number, skipMigrated = true): Dialog[] {\n if(id === GLOBAL_FOLDER_ID) { // * it won't be sorted\n return this.getCachedDialogs(skipMigrated);\n }\n\n const folder = this.getFolder(id);\n return skipMigrated ? folder.dialogs.filter(dialog => dialog.migratedTo === undefined) : folder.dialogs;\n }\n\n public getCachedDialogs(skipMigrated?: boolean) {\n return this.getFolderDialogs(0, skipMigrated).concat(this.getFolderDialogs(1, skipMigrated));\n }\n\n private setDialogIndexInFilter(dialog: Dialog, indexKey: ReturnType<DialogsStorage['getDialogIndexKey']>, filter: MyDialogFilter) {\n let index: number;\n\n if(this.appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) {\n const pinnedIndex = filter.pinnedPeerIds.indexOf(dialog.peerId);\n if(pinnedIndex !== -1) {\n index = this.generateDialogIndex(this.generateDialogPinnedDateByIndex(filter.pinned_peers.length - 1 - pinnedIndex), true);\n } else if(dialog.pFlags?.pinned) {\n index = this.generateIndexForDialog(dialog, true);\n } else {\n index = dialog.index;\n }\n }\n\n return dialog[indexKey] = index;\n }\n\n public getDialog(peerId: PeerId, folderId?: number, skipMigrated = true): [Dialog, number] | [] {\n const folders: Dialog[][] = [];\n\n if(folderId === undefined) {\n folders.push(this.getFolder(0).dialogs, this.getFolder(1).dialogs);\n } else {\n folders.push(this.getFolderDialogs(folderId, false));\n }\n\n for(let folder of folders) {\n let i = 0, skipped = 0;\n for(let length = folder.length; i < length; ++i) {\n const dialog = folder[i];\n if(dialog.peerId === peerId) {\n return [dialog, i - skipped];\n } else if(skipMigrated && dialog.migratedTo !== undefined) {\n ++skipped;\n }\n }\n }\n\n return [];\n }\n\n public getDialogOnly(peerId: PeerId) {\n return this.dialogs[peerId];\n }\n\n /*\n var date = Date.now() / 1000 | 0;\n var m = date * 0x10000;\n\n var k = (date + 1) * 0x10000;\n k - m;\n 65536\n */\n public generateDialogIndex(date?: number, isPinned?: boolean) {\n if(date === undefined) {\n date = tsNow(true) + this.serverTimeManager.serverTimeOffset;\n }\n\n return (date * 0x10000) + (isPinned ? 0 : ((++this.dialogsNum) & 0xFFFF));\n }\n\n public processDialogForFilters(dialog: Dialog) {\n // let perf = performance.now();\n const filters = this.appMessagesManager.filtersStorage.filters;\n for(const id in filters) {\n const filter = filters[id];\n this.processDialogForFilter(dialog, filter);\n }\n // spentTime += (performance.now() - perf);\n // console.log('generate index time:', spentTime);\n }\n\n public processDialogForFilter(dialog: Dialog, filter: MyDialogFilter) {\n const indexKey = this.getDialogIndexKey(filter.id);\n const folder = this.getFolder(filter.id);\n const dialogs = folder.dialogs;\n\n const wasIndex = dialogs.findIndex(d => d.peerId === dialog.peerId);\n const wasDialog = dialogs[wasIndex];\n const wasDialogIndex = wasDialog && wasDialog[indexKey];\n\n const newDialogIndex = this.setDialogIndexInFilter(dialog, indexKey, filter);\n\n if(wasDialogIndex === newDialogIndex) {\n return;\n }\n\n if((!wasDialogIndex && newDialogIndex) || (wasIndex && !newDialogIndex)) {\n this.prepareFolderUnreadCountModifyingByDialog(filter.id, dialog, !!newDialogIndex);\n }\n\n if(wasIndex !== -1) {\n dialogs.splice(wasIndex, 1);\n }\n\n if(newDialogIndex) {\n insertInDescendSortedArray(dialogs, dialog, indexKey, -1);\n }\n }\n\n public prepareDialogUnreadCountModifying(dialog: Dialog) {\n const callbacks: NoneToVoidFunction[] = [\n this.prepareFolderUnreadCountModifyingByDialog(dialog.folder_id, dialog)\n ];\n\n const filters = this.appMessagesManager.filtersStorage.filters;\n for(const id in filters) {\n const filter = filters[id];\n if(this.appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) {\n callbacks.push(this.prepareFolderUnreadCountModifyingByDialog(filter.id, dialog));\n }\n }\n\n return () => callbacks.forEach(callback => callback());\n }\n\n public prepareFolderUnreadCountModifyingByDialog(folderId: number, dialog: Dialog, toggle?: boolean) {\n const wasUnreadCount = this.appMessagesManager.getDialogUnreadCount(dialog);\n \n if(toggle !== undefined) {\n this.modifyFolderUnreadCount(folderId, toggle ? wasUnreadCount : -wasUnreadCount, wasUnreadCount ? (toggle ? 1 : -1) : 0);\n return;\n }\n\n return () => {\n const newUnreadCount = this.appMessagesManager.getDialogUnreadCount(dialog);\n const addMessagesCount = newUnreadCount - wasUnreadCount;\n const addDialogsCount = (newUnreadCount && !wasUnreadCount) || (!newUnreadCount && wasUnreadCount) ? (wasUnreadCount ? -1 : 1) : 0;\n this.modifyFolderUnreadCount(folderId, addMessagesCount, addDialogsCount);\n };\n }\n\n public modifyFolderUnreadCount(folderId: number, addMessagesCount: number, addDialogsCount: number) {\n if(!addMessagesCount && !addDialogsCount) {\n return;\n }\n\n const folder = this.getFolder(folderId);\n if(addMessagesCount) {\n folder.unreadMessagesCount = Math.max(0, folder.unreadMessagesCount + addMessagesCount);\n }\n \n if(addDialogsCount) {\n folder.unreadDialogsCount = Math.max(0, folder.unreadDialogsCount + addDialogsCount);\n }\n\n if(folder.dispatchUnreadTimeout === undefined) {\n folder.dispatchUnreadTimeout = ctx.setTimeout(() => {\n folder.dispatchUnreadTimeout = undefined;\n rootScope.dispatchEvent('folder_unread', folder);\n }, 0);\n }\n }\n\n public generateIndexForDialog(dialog: Dialog, justReturn = false, message?: MyMessage) {\n let topDate = 0, isPinned: boolean;\n if(dialog.pFlags.pinned && !justReturn) {\n topDate = this.generateDialogPinnedDate(dialog);\n isPinned = true;\n } else {\n if(!message) {\n message = this.appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\n }\n \n topDate = (message as Message.message).date || topDate;\n\n const channelId = this.appPeersManager.isChannel(dialog.peerId) && dialog.peerId.toChatId();\n if(channelId) {\n const channel: Chat.channel = this.appChatsManager.getChat(channelId);\n if(!topDate || (channel.date && channel.date > topDate)) {\n topDate = channel.date;\n }\n }\n \n if(dialog.draft?._ === 'draftMessage' && dialog.draft.date > topDate) {\n topDate = dialog.draft.date;\n }\n }\n\n if(!topDate) {\n topDate = tsNow(true);\n }\n\n const index = this.generateDialogIndex(topDate, isPinned);\n if(justReturn) {\n return index;\n }\n\n dialog.index = index;\n }\n\n public generateDialogPinnedDateByIndex(pinnedIndex: number) {\n return 0x7fff0000 + (pinnedIndex & 0xFFFF); // 0xFFFF - потому что в папках может быть бесконечное число пиннедов\n }\n\n public generateDialogPinnedDate(dialog: Dialog) {\n const order = this.pinnedOrders[dialog.folder_id];\n\n const foundIndex = order.indexOf(dialog.peerId);\n let pinnedIndex = foundIndex;\n if(foundIndex === -1) {\n pinnedIndex = order.push(dialog.peerId) - 1;\n this.savePinnedOrders();\n }\n\n return this.generateDialogPinnedDateByIndex(pinnedIndex);\n }\n\n /* public generateDialog(peerId: PeerId) {\n const dialog: Dialog = {\n _: 'dialog',\n pFlags: {},\n peer: this.appPeersManager.getOutputPeer(peerId),\n top_message: 0,\n read_inbox_max_id: 0,\n read_outbox_max_id: 0,\n unread_count: 0,\n unread_mentions_count: 0,\n notify_settings: {\n _: 'peerNotifySettings',\n },\n };\n\n return dialog;\n } */\n\n public setDialogToState(dialog: Dialog) {\n const {peerId, pts} = dialog;\n const historyStorage = this.appMessagesManager.getHistoryStorage(peerId);\n const messagesStorage = this.appMessagesManager.getMessagesStorage(peerId);\n const history = historyStorage.history.slice;\n let incomingMessage: MyMessage;\n for(let i = 0, length = history.length; i < length; ++i) {\n const mid = history[i];\n const message: MyMessage = this.appMessagesManager.getMessageFromStorage(messagesStorage, mid);\n if(!message.pFlags.is_outgoing && !message.deleted/* || peerId === SERVICE_PEER_ID */) {\n incomingMessage = message;\n \n const fromId = message.viaBotId || message.fromId;\n if(fromId !== peerId) {\n this.appStateManager.requestPeerSingle(fromId, 'topMessage', peerId);\n }\n \n break;\n }\n }\n\n dialog.topMessage = incomingMessage;\n\n // DO NOT TOUCH THESE LINES, SOME REAL MAGIC HERE.\n // * Read service chat when refreshing page with outgoing & getting new service outgoing message\n /* if(incomingMessage && dialog.read_inbox_max_id >= dialog.top_message) {\n dialog.unread_count = 0;\n }\n\n dialog.read_inbox_max_id = this.appMessagesIdsManager.clearMessageId(dialog.read_inbox_max_id);\n dialog.read_outbox_max_id = this.appMessagesIdsManager.clearMessageId(dialog.read_outbox_max_id); */\n // CAN TOUCH NOW\n\n if(peerId.isAnyChat() && pts) {\n const newPts = this.apiUpdatesManager.getChannelState(peerId.toChatId(), pts).pts;\n dialog.pts = newPts;\n }\n\n this.storage.set({\n [peerId]: dialog\n });\n\n this.appStateManager.requestPeerSingle(peerId, 'dialog');\n\n /* for(let id in this.appMessagesManager.filtersStorage.filters) {\n const filter = this.appMessagesManager.filtersStorage.filters[id];\n\n if(this.appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) {\n \n }\n } */\n }\n\n public pushDialog(dialog: Dialog, offsetDate?: number, ignoreOffsetDate?: boolean, saveGlobalOffset?: boolean) {\n const {folder_id, peerId} = dialog;\n const dialogs = this.getFolderDialogs(folder_id, false);\n const pos = dialogs.findIndex(d => d.peerId === peerId);\n if(pos !== -1) {\n dialogs.splice(pos, 1);\n }\n \n //if(!this.dialogs[peerId]) {\n this.dialogs[peerId] = dialog;\n \n this.setDialogToState(dialog);\n //}\n\n if(offsetDate === undefined) {\n offsetDate = this.getDialogOffsetDate(dialog);\n }\n\n this.processDialogForFilters(dialog);\n\n if(offsetDate && !dialog.pFlags.pinned) {\n if(saveGlobalOffset) {\n const savedGlobalOffsetDate = this.dialogsOffsetDate[GLOBAL_FOLDER_ID];\n if(!savedGlobalOffsetDate || offsetDate < savedGlobalOffsetDate) {\n this.dialogsOffsetDate[GLOBAL_FOLDER_ID] = offsetDate;\n }\n }\n\n const savedOffsetDate = this.dialogsOffsetDate[folder_id];\n if(!savedOffsetDate || offsetDate < savedOffsetDate) {\n // if(pos !== -1) {\n if(!ignoreOffsetDate && !this.isDialogsLoaded(folder_id)) {\n this.clearDialogFromState(dialog, true);\n return;\n }\n \n this.dialogsOffsetDate[folder_id] = offsetDate;\n }\n }\n\n if(pos === -1) {\n this.prepareFolderUnreadCountModifyingByDialog(folder_id, dialog, true);\n }\n\n /* const newPos = */insertInDescendSortedArray(dialogs, dialog, 'index', -1);\n /* if(pos !== -1 && pos !== newPos) {\n rootScope.dispatchEvent('dialog_order', {dialog, pos: newPos});\n } */\n }\n\n public dropDialog(peerId: PeerId): ReturnType<DialogsStorage['getDialog']> {\n const foundDialog = this.getDialog(peerId, undefined, false);\n const [dialog, index] = foundDialog;\n if(dialog) {\n delete this.dialogs[peerId];\n\n const folder = this.getFolder(dialog.folder_id);\n folder.dialogs.splice(index, 1);\n const wasPinned = indexOfAndSplice(this.pinnedOrders[dialog.folder_id], peerId) !== undefined;\n \n this.processDialogForFilters(dialog);\n\n this.dialogsIndex.indexObject(peerId, '');\n\n if(wasPinned) {\n this.savePinnedOrders();\n }\n\n this.clearDialogFromState(dialog, false);\n }\n\n return foundDialog;\n }\n\n public clearDialogFromState(dialog: Dialog, keepLocal: boolean) {\n const peerId = dialog.peerId;\n this.appStateManager.releaseSinglePeer(peerId, 'topMessage');\n this.appStateManager.releaseSinglePeer(peerId, 'dialog');\n this.storage.delete(peerId, keepLocal);\n }\n\n public dropDialogWithEvent(peerId: PeerId) {\n const dropped = this.dropDialog(peerId);\n if(dropped.length) {\n rootScope.dispatchEvent('dialog_drop', {peerId, dialog: dropped[0]});\n }\n\n return dropped;\n }\n\n /**\n * leaving chat, leaving channel, deleting private dialog\n */\n public dropDialogOnDeletion(peerId: PeerId) {\n this.dropDialogWithEvent(peerId);\n rootScope.dispatchEvent('peer_deleted', peerId);\n }\n\n public applyDialogs(dialogsResult: MessagesPeerDialogs.messagesPeerDialogs) {\n // * В эту функцию попадут только те диалоги, в которых есть read_inbox_max_id и read_outbox_max_id, в отличие от тех, что будут в getTopMessages\n\n // ! fix 'dialogFolder', maybe there is better way to do it, this only can happen by 'messages.getPinnedDialogs' by folder_id: 0\n forEachReverse(dialogsResult.dialogs, (dialog, idx) => {\n if(dialog._ === 'dialogFolder') {\n dialogsResult.dialogs.splice(idx, 1);\n }\n });\n\n this.appUsersManager.saveApiUsers(dialogsResult.users);\n this.appChatsManager.saveApiChats(dialogsResult.chats);\n this.appMessagesManager.saveMessages(dialogsResult.messages);\n\n // this.appMessagesManager.log('applyConversation', dialogsResult);\n\n const updatedDialogs: {[peerId: PeerId]: Dialog} = {};\n (dialogsResult.dialogs as Dialog[]).forEach((dialog) => {\n const peerId = this.appPeersManager.getPeerId(dialog.peer);\n let topMessage = dialog.top_message;\n\n const topPendingMessage = this.appMessagesManager.pendingTopMsgs[peerId];\n if(topPendingMessage) {\n if(!topMessage \n || (this.appMessagesManager.getMessageByPeer(peerId, topPendingMessage) as MyMessage).date > (this.appMessagesManager.getMessageByPeer(peerId, topMessage) as MyMessage).date) {\n dialog.top_message = topMessage = topPendingMessage;\n this.appMessagesManager.getHistoryStorage(peerId).maxId = topPendingMessage;\n }\n }\n\n /* const d = Object.assign({}, dialog);\n if(peerId === 239602833) {\n this.log.error('applyConversation lun', dialog, d);\n } */\n\n if(topMessage || (dialog.draft && dialog.draft._ === 'draftMessage')) {\n this.saveDialog(dialog);\n updatedDialogs[peerId] = dialog;\n } else {\n this.dropDialogWithEvent(peerId);\n }\n\n const updates = this.appMessagesManager.newUpdatesAfterReloadToHandle[peerId];\n if(updates !== undefined) {\n for(const update of updates) {\n updates.delete(update);\n this.apiUpdatesManager.saveUpdate(update);\n }\n\n if(!updates.size) {\n delete this.appMessagesManager.newUpdatesAfterReloadToHandle[peerId];\n }\n }\n });\n\n if(Object.keys(updatedDialogs).length) {\n rootScope.dispatchEvent('dialogs_multiupdate', updatedDialogs);\n }\n }\n\n public getDialogOffsetDate(dialog: Dialog) {\n return this.appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message).date || 0;\n }\n\n /**\n * Won't save migrated from peer, forbidden peers, left and kicked\n */\n public saveDialog(dialog: Dialog, folderId = dialog.folder_id ?? 0, ignoreOffsetDate?: boolean, saveGlobalOffset?: boolean) {\n const peerId = this.appPeersManager.getPeerId(dialog.peer);\n if(!peerId) {\n console.error('saveConversation no peerId???', dialog, folderId);\n return;\n }\n\n if(dialog._ !== 'dialog'/* || peerId === 239602833 */) {\n console.error('saveConversation not regular dialog', dialog, Object.assign({}, dialog));\n }\n \n const channelId = this.appPeersManager.isChannel(peerId) ? peerId.toChatId() : NULL_PEER_ID;\n\n if(peerId.isAnyChat()) {\n const chat: Chat = this.appChatsManager.getChat(peerId.toChatId());\n // ! chatForbidden stays for chat where you're kicked\n if(chat._ === 'channelForbidden' /* || chat._ === 'chatForbidden' */ || (chat as Chat.chat).pFlags.left || (chat as Chat.chat).pFlags.kicked) {\n return;\n }\n }\n\n const peerText = this.appPeersManager.getPeerSearchText(peerId);\n this.dialogsIndex.indexObject(peerId, peerText);\n\n const wasDialogBefore = this.getDialogOnly(peerId);\n\n let mid: number, message: MyMessage;\n if(dialog.top_message) {\n mid = this.appMessagesIdsManager.generateMessageId(dialog.top_message);//dialog.top_message;\n\n // preserve outgoing message\n const wasTopMessage = wasDialogBefore?.top_message && this.appMessagesManager.getMessageByPeer(peerId, wasDialogBefore.top_message) as MyMessage;\n if(wasTopMessage?.pFlags?.is_outgoing && wasDialogBefore.top_message >= mid) {\n mid = wasDialogBefore.top_message;\n }\n\n message = this.appMessagesManager.getMessageByPeer(peerId, mid);\n } else {\n mid = this.appMessagesManager.generateTempMessageId(peerId);\n message = {\n _: 'message',\n id: mid,\n mid,\n from_id: this.appPeersManager.getOutputPeer(this.appUsersManager.getSelf().id.toPeerId(false)),\n peer_id: this.appPeersManager.getOutputPeer(peerId),\n deleted: true,\n pFlags: {out: true},\n date: 0,\n message: ''\n };\n this.appMessagesManager.saveMessages([message], {isOutgoing: true});\n }\n\n if(!message?.pFlags) {\n this.appMessagesManager.log.error('saveConversation no message:', dialog, message);\n }\n\n if(!channelId && peerId.isAnyChat()) {\n const chat = this.appChatsManager.getChat(peerId.toChatId());\n if(chat && chat.migrated_to && chat.pFlags.deactivated) {\n const migratedToPeer = this.appPeersManager.getPeerId(chat.migrated_to);\n this.appMessagesManager.migratedFromTo[peerId] = migratedToPeer;\n this.appMessagesManager.migratedToFrom[migratedToPeer] = peerId;\n dialog.migratedTo = migratedToPeer;\n //return;\n }\n }\n\n dialog.top_message = mid;\n // dialog.unread_count = wasDialogBefore && dialog.read_inbox_max_id === this.appMessagesIdsManager.getServerMessageId(wasDialogBefore.read_inbox_max_id) ? wasDialogBefore.unread_count : dialog.unread_count;\n dialog.read_inbox_max_id = this.appMessagesIdsManager.generateMessageId(wasDialogBefore && !dialog.read_inbox_max_id ? wasDialogBefore.read_inbox_max_id : dialog.read_inbox_max_id);\n dialog.read_outbox_max_id = this.appMessagesIdsManager.generateMessageId(wasDialogBefore && !dialog.read_outbox_max_id ? wasDialogBefore.read_outbox_max_id : dialog.read_outbox_max_id);\n\n if(dialog.folder_id === undefined) {\n if(dialog._ === 'dialog') {\n // ! СЛОЖНО ! СМОТРИ В getTopMessages\n dialog.folder_id = wasDialogBefore ? wasDialogBefore.folder_id : folderId;\n }/* else if(dialog._ === 'dialogFolder') {\n dialog.folder_id = dialog.folder.id;\n } */\n }\n\n dialog.draft = this.appDraftsManager.saveDraft(peerId, 0, dialog.draft);\n dialog.peerId = peerId;\n\n // Because we saved message without dialog present\n if(message.pFlags.is_outgoing) {\n const isOut = message.pFlags.out;\n if(mid > dialog[isOut ? 'read_outbox_max_id' : 'read_inbox_max_id']) {\n message.pFlags.unread = true;\n\n if(!dialog.unread_count && !isOut) {\n ++dialog.unread_count;\n }\n } else {\n delete message.pFlags.unread;\n }\n }\n\n const historyStorage = this.appMessagesManager.getHistoryStorage(peerId);\n const slice = historyStorage.history.slice;\n /* if(historyStorage === undefined) { // warning\n historyStorage.history.push(mid);\n } else */if(!slice.length) {\n historyStorage.history.unshift(mid);\n historyStorage.count ||= 1;\n if(this.appMessagesManager.mergeReplyKeyboard(historyStorage, message)) {\n rootScope.dispatchEvent('history_reply_markup', {peerId});\n }\n } else if(!slice.isEnd(SliceEnd.Bottom)) { // * this will probably never happen, however, if it does, then it will fix slice with top_message\n const slice = historyStorage.history.insertSlice([mid]);\n slice.setEnd(SliceEnd.Bottom);\n historyStorage.count ||= 1;\n if(this.appMessagesManager.mergeReplyKeyboard(historyStorage, message)) {\n rootScope.dispatchEvent('history_reply_markup', {peerId});\n }\n }\n\n historyStorage.maxId = mid;\n historyStorage.readMaxId = dialog.read_inbox_max_id;\n historyStorage.readOutboxMaxId = dialog.read_outbox_max_id;\n\n this.appNotificationsManager.savePeerSettings({\n peerId, \n settings: dialog.notify_settings\n });\n\n if(channelId && dialog.pts) {\n this.apiUpdatesManager.addChannelState(channelId, dialog.pts);\n }\n\n this.generateIndexForDialog(dialog);\n\n defineNotNumerableProperties(dialog, [\n 'index_0',\n 'index_1',\n 'index_2',\n 'index_3',\n 'index_4',\n 'index_5',\n 'index_6',\n 'index_7',\n 'index_8',\n 'index_9',\n 'index_10'\n ]);\n\n if(wasDialogBefore) {\n safeReplaceObject(wasDialogBefore, dialog);\n }\n\n this.pushDialog(dialog, message.date, ignoreOffsetDate, saveGlobalOffset);\n }\n\n public getDialogIndexKey(filterId: number) {\n const indexStr = filterId > 1 ? \n `index_${this.appMessagesManager.filtersStorage.getFilter(filterId).orderIndex}` as const : \n 'index' as const;\n\n return indexStr;\n }\n\n public getDialogs(query = '', offsetIndex?: number, limit = 20, folderId = 0, skipMigrated = false): {\n cached: boolean,\n promise: Promise<{\n dialogs: Dialog[],\n count: number,\n isTopEnd: boolean,\n isEnd: boolean\n }>\n } {\n const ret: {\n cached: boolean,\n promise: Promise<{\n dialogs: Dialog[],\n count: number,\n isTopEnd: boolean,\n isEnd: boolean\n }>\n } = {} as any;\n\n if(folderId > 1) {\n const promises: Promise<any>[] = [];\n\n const fillContactsResult = this.appUsersManager.fillContacts();\n if(!fillContactsResult.cached) {\n promises.push(fillContactsResult.promise);\n }\n\n const reloadMissingDialogsPromise = this.appMessagesManager.filtersStorage.reloadMissingPeerIds(folderId);\n if(reloadMissingDialogsPromise) {\n promises.push(reloadMissingDialogsPromise);\n }\n\n if(promises.length) {\n ret.cached = false;\n ret.promise = Promise.all(promises).then(() => {\n return this.getDialogs(query, offsetIndex, limit, folderId, skipMigrated).promise;\n });\n\n return ret;\n }\n }\n\n // let's load only first pages by certain folderId. next pages will load without folder filtering\n const realFolderId = folderId > 1 || this.getOffsetDate(folderId) ? GLOBAL_FOLDER_ID : folderId;\n let curDialogStorage = this.getFolderDialogs(folderId, skipMigrated);\n\n const indexStr = this.getDialogIndexKey(folderId);\n\n if(query) {\n if(!limit || this.cachedResults.query !== query || this.cachedResults.folderId !== folderId) {\n this.cachedResults.query = query;\n this.cachedResults.folderId = folderId;\n\n const results = this.dialogsIndex.search(query);\n\n const dialogs: Dialog[] = [];\n for(const peerId in this.dialogs) {\n const dialog = this.dialogs[peerId];\n if(results.has(dialog.peerId) && dialog.folder_id === folderId) {\n dialogs.push(dialog);\n }\n }\n\n dialogs.sort((d1, d2) => d2[indexStr] - d1[indexStr]);\n this.cachedResults.dialogs = dialogs;\n this.cachedResults.count = dialogs.length;\n }\n\n curDialogStorage = this.cachedResults.dialogs;\n } else {\n this.cachedResults.query = '';\n }\n\n let offset = 0;\n if(offsetIndex > 0) {\n for(let length = curDialogStorage.length; offset < length; ++offset) {\n if(offsetIndex > curDialogStorage[offset][indexStr]) {\n break;\n }\n }\n }\n\n const loadedAll = this.isDialogsLoaded(realFolderId);\n const isEnoughDialogs = curDialogStorage.length >= (offset + limit);\n if(query || loadedAll || isEnoughDialogs) {\n const dialogs = curDialogStorage.slice(offset, offset + limit);\n ret.cached = true;\n ret.promise = Promise.resolve({\n dialogs,\n count: loadedAll ? curDialogStorage.length : null,\n isTopEnd: curDialogStorage.length && ((dialogs[0] && dialogs[0] === curDialogStorage[0]) || curDialogStorage[0][indexStr] < offsetIndex),\n isEnd: (query || loadedAll) && (offset + limit) >= curDialogStorage.length\n });\n\n return ret;\n }\n\n ret.cached = false;\n ret.promise = this.appMessagesManager.getTopMessages(limit, realFolderId).then(result => {\n //const curDialogStorage = this[folderId];\n if(skipMigrated) {\n curDialogStorage = this.getFolderDialogs(folderId, skipMigrated);\n }\n\n offset = 0;\n if(offsetIndex > 0) {\n for(let length = curDialogStorage.length; offset < length; ++offset) {\n if(offsetIndex > curDialogStorage[offset][indexStr]) {\n break;\n }\n }\n }\n\n //this.log.warn(offset, offset + limit, curDialogStorage.dialogs.length, this.dialogs.length);\n\n const dialogs = curDialogStorage.slice(offset, offset + limit);\n return {\n dialogs,\n count: result.count === undefined ? curDialogStorage.length : result.count,\n isTopEnd: curDialogStorage.length && ((dialogs[0] && dialogs[0] === curDialogStorage[0]) || curDialogStorage[0][indexStr] < offsetIndex),\n // isEnd: this.isDialogsLoaded(realFolderId) && (offset + limit) >= curDialogStorage.length\n isEnd: result.isEnd\n };\n });\n\n return ret;\n }\n\n // only 0 and 1 folders\n private onUpdateFolderPeers = (update: Update.updateFolderPeers) => {\n //this.log('updateFolderPeers', update);\n const peers = update.folder_peers;\n\n peers.forEach((folderPeer) => {\n const {folder_id, peer} = folderPeer;\n\n const peerId = this.appPeersManager.getPeerId(peer);\n const dialog = this.dropDialog(peerId)[0];\n if(dialog) {\n if(dialog.pFlags?.pinned) {\n this.handleDialogUnpinning(dialog, folder_id);\n }\n\n dialog.folder_id = folder_id;\n this.generateIndexForDialog(dialog);\n this.pushDialog(dialog); // need for simultaneously updatePinnedDialogs\n }\n\n this.appMessagesManager.scheduleHandleNewDialogs(peerId, dialog);\n });\n };\n\n private onUpdateDialogPinned = (update: Update.updateDialogPinned) => {\n const folderId = update.folder_id ?? 0;\n //this.log('updateDialogPinned', update);\n const peerId = this.appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer);\n const dialog = this.getDialogOnly(peerId);\n\n // этот код внизу никогда не сработает, в папках за пиннед отвечает updateDialogFilter\n /* if(update.folder_id > 1) {\n const filter = this.filtersStorage.filters[update.folder_id];\n if(update.pFlags.pinned) {\n filter.pinned_peers.unshift(peerId);\n } else {\n filter.pinned_peers.findAndSplice(p => p === peerId);\n }\n } */\n\n if(dialog) {\n if(!update.pFlags.pinned) {\n this.handleDialogUnpinning(dialog, folderId);\n } else { // means set\n dialog.pFlags.pinned = true;\n }\n\n this.generateIndexForDialog(dialog);\n } \n\n this.appMessagesManager.scheduleHandleNewDialogs(peerId, dialog);\n };\n\n private onUpdatePinnedDialogs = (update: Update.updatePinnedDialogs) => {\n const folderId = update.folder_id ?? 0;\n \n const handleOrder = (order: PeerId[]) => {\n this.pinnedOrders[folderId].length = 0;\n order.reverse(); // index must be higher\n order.forEach((peerId) => {\n newPinned[peerId] = true;\n \n const dialog = this.getDialogOnly(peerId);\n this.appMessagesManager.scheduleHandleNewDialogs(peerId, dialog);\n if(!dialog) {\n return;\n }\n \n dialog.pFlags.pinned = true;\n this.generateIndexForDialog(dialog);\n });\n \n const dialogs = this.getFolderDialogs(folderId, false);\n for(const dialog of dialogs) {\n if(!dialog.pFlags.pinned) {\n break;\n }\n\n const peerId = dialog.peerId;\n if(!newPinned[peerId]) {\n this.appMessagesManager.scheduleHandleNewDialogs(peerId);\n }\n }\n };\n\n //this.log('updatePinnedDialogs', update);\n const newPinned: {[peerId: PeerId]: true} = {};\n if(!update.order) {\n apiManager.invokeApi('messages.getPinnedDialogs', {\n folder_id: folderId\n }).then((dialogsResult) => {\n // * for test reordering and rendering\n // dialogsResult.dialogs.reverse();\n\n this.applyDialogs(dialogsResult);\n\n handleOrder(dialogsResult.dialogs.map(d => d.peerId));\n\n /* dialogsResult.dialogs.forEach((dialog) => {\n newPinned[dialog.peerId] = true;\n });\n\n this.dialogsStorage.getFolder(folderId).forEach((dialog) => {\n const peerId = dialog.peerId;\n if(dialog.pFlags.pinned && !newPinned[peerId]) {\n this.newDialogsToHandle[peerId] = {reload: true};\n this.scheduleHandleNewDialogs();\n }\n }); */\n });\n\n return;\n }\n\n //this.log('before order:', this.dialogsStorage[0].map(d => d.peerId));\n\n handleOrder(update.order.map(peer => this.appPeersManager.getPeerId((peer as DialogPeer.dialogPeer).peer)));\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { DialogFilter, Update } from \"../../layer\";\nimport type { Modify } from \"../../types\";\nimport type { AppPeersManager } from \"../appManagers/appPeersManager\";\nimport type { AppUsersManager } from \"../appManagers/appUsersManager\";\n//import type { ApiManagerProxy } from \"../mtproto/mtprotoworker\";\nimport type _rootScope from \"../rootScope\";\nimport type {AppMessagesManager, Dialog} from '../appManagers/appMessagesManager';\nimport type {AppNotificationsManager} from \"../appManagers/appNotificationsManager\";\nimport type { ApiUpdatesManager } from \"../appManagers/apiUpdatesManager\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport { AppStateManager } from \"../appManagers/appStateManager\";\nimport forEachReverse from \"../../helpers/array/forEachReverse\";\nimport copy from \"../../helpers/object/copy\";\nimport safeReplaceObject from \"../../helpers/object/safeReplaceObject\";\n\nexport type MyDialogFilter = Modify<DialogFilter, {\n /* pinned_peers: PeerId[],\n include_peers: PeerId[],\n exclude_peers: PeerId[], */\n pinnedPeerIds: PeerId[],\n includePeerIds: PeerId[],\n excludePeerIds: PeerId[]\n}>;\n\nconst convertment = [\n ['pinned_peers', 'pinnedPeerIds'], \n ['exclude_peers', 'excludePeerIds'], \n ['include_peers', 'includePeerIds']\n] as ['pinned_peers' | 'exclude_peers' | 'include_peers', 'pinnedPeerIds' | 'excludePeerIds' | 'includePeerIds'][];\n\n// ! because 0 index is 'All Chats'\nconst START_ORDER_INDEX = 1;\n\nexport default class FiltersStorage {\n public filters: {[filterId: string]: MyDialogFilter};\n private orderIndex: number;\n private reloadedPeerIds: Set<PeerId>;\n\n constructor(private appMessagesManager: AppMessagesManager,\n private appPeersManager: AppPeersManager, \n private appUsersManager: AppUsersManager, \n private appNotificationsManager: AppNotificationsManager, \n private appStateManager: AppStateManager,\n private apiUpdatesManager: ApiUpdatesManager, \n /* private apiManager: ApiManagerProxy, */ \n private rootScope: typeof _rootScope) {\n this.clear(true);\n this.filters = {};\n\n this.appStateManager.getState().then((state) => {\n safeReplaceObject(this.filters, state.filters);\n\n for(const filterId in this.filters) {\n const filter = this.filters[filterId];\n if(filter.hasOwnProperty('orderIndex') && filter.orderIndex >= this.orderIndex) {\n this.orderIndex = filter.orderIndex + 1;\n }\n\n /* this.appMessagesManager.dialogsStorage.folders[+filterId] = {\n dialogs: []\n }; */\n }\n });\n\n rootScope.addMultipleEventsListeners({\n updateDialogFilter: this.onUpdateDialogFilter,\n\n updateDialogFilters: (update) => {\n //console.warn('updateDialogFilters', update);\n\n const oldFilters = copy(this.filters);\n\n this.getDialogFilters(true).then(filters => {\n for(const _filterId in oldFilters) {\n const filterId = +_filterId;\n if(!filters.find(filter => filter.id === filterId)) { // * deleted\n this.onUpdateDialogFilter({_: 'updateDialogFilter', id: filterId});\n }\n }\n\n this.onUpdateDialogFilterOrder({_: 'updateDialogFilterOrder', order: filters.map(filter => filter.id)});\n });\n },\n\n updateDialogFilterOrder: this.onUpdateDialogFilterOrder\n });\n\n // delete peers when dialog is being dropped\n /* rootScope.addEventListener('peer_deleted', (peerId) => {\n for(const filterId in this.filters) {\n const filter = this.filters[filterId];\n let modified = false;\n [filter.pinned_peers, filter.include_peers, filter.exclude_peers].forEach(arr => {\n forEachReverse(arr, (inputPeer, idx) => {\n if(this.appPeersManager.getPeerId(inputPeer) === peerId) {\n arr.splice(idx, 1);\n modified = true;\n }\n });\n });\n\n if(modified) {\n this.saveDialogFilter(filter, true);\n }\n }\n }); */\n }\n\n public clear(init = false) {\n if(!init) {\n safeReplaceObject(this.filters, {});\n this.reloadedPeerIds.clear();\n } else {\n this.filters = {};\n this.reloadedPeerIds = new Set();\n }\n\n this.orderIndex = START_ORDER_INDEX;\n }\n\n private onUpdateDialogFilter = (update: Update.updateDialogFilter) => {\n if(update.filter) {\n this.saveDialogFilter(update.filter as any);\n } else if(this.filters[update.id]) { // Папка удалена\n //this.getDialogFilters(true);\n this.rootScope.dispatchEvent('filter_delete', this.filters[update.id]);\n delete this.filters[update.id];\n }\n\n this.appStateManager.pushToState('filters', this.filters);\n };\n\n private onUpdateDialogFilterOrder = (update: Update.updateDialogFilterOrder) => {\n //console.log('updateDialogFilterOrder', update);\n\n this.orderIndex = START_ORDER_INDEX;\n update.order.forEach((filterId, idx) => {\n const filter = this.filters[filterId];\n delete filter.orderIndex;\n this.setOrderIndex(filter);\n });\n\n this.rootScope.dispatchEvent('filter_order', update.order);\n\n this.appStateManager.pushToState('filters', this.filters);\n };\n\n public testDialogForFilter(dialog: Dialog, filter: MyDialogFilter) {\n const peerId = dialog.peerId;\n\n // * check whether dialog exists\n if(!this.appMessagesManager.getDialogOnly(peerId)) {\n return false;\n }\n\n // exclude_peers\n if(filter.excludePeerIds.includes(peerId)) {\n return false;\n }\n\n // include_peers\n if(filter.includePeerIds.includes(peerId)) {\n return true;\n }\n\n const pFlags = filter.pFlags;\n\n // exclude_archived\n if(pFlags.exclude_archived && dialog.folder_id === 1) {\n return false;\n }\n\n // exclude_read\n if(pFlags.exclude_read && !this.appMessagesManager.isDialogUnread(dialog)) {\n return false;\n }\n\n // exclude_muted\n if(pFlags.exclude_muted && this.appNotificationsManager.isPeerLocalMuted(peerId) && !(dialog.unread_mentions_count && dialog.unread_count)) {\n return false;\n }\n\n if(this.appPeersManager.isAnyChat(peerId)) {\n // broadcasts\n if(pFlags.broadcasts && this.appPeersManager.isBroadcast(peerId)) {\n return true;\n }\n\n // groups\n if(pFlags.groups && this.appPeersManager.isAnyGroup(peerId)) {\n return true;\n }\n } else {\n const userId = peerId.toUserId();\n \n // bots\n if(this.appUsersManager.isBot(userId)) {\n return !!pFlags.bots;\n }\n \n // non_contacts\n if(pFlags.non_contacts && !this.appUsersManager.isContact(userId)) {\n return true;\n }\n\n // contacts\n if(pFlags.contacts && this.appUsersManager.isContact(userId)) {\n return true;\n }\n }\n\n return false;\n }\n\n public testDialogForFilterId(dialog: Dialog, filterId: number) {\n return this.testDialogForFilter(dialog, this.filters[filterId]);\n }\n\n public getFilter(filterId: number) {\n return this.filters[filterId];\n }\n\n public toggleDialogPin(peerId: PeerId, filterId: number) {\n const filter = this.filters[filterId];\n\n const index = filter.pinnedPeerIds.indexOf(peerId);\n const wasPinned = index !== -1;\n\n if(wasPinned) {\n filter.pinned_peers.splice(index, 1);\n filter.pinnedPeerIds.splice(index, 1);\n }\n \n if(!wasPinned) {\n if(filter.pinned_peers.length >= this.rootScope.config.pinned_infolder_count_max) {\n return Promise.reject({type: 'PINNED_DIALOGS_TOO_MUCH'});\n }\n \n filter.pinned_peers.unshift(this.appPeersManager.getInputPeerById(peerId));\n filter.pinnedPeerIds.unshift(peerId);\n }\n \n return this.updateDialogFilter(filter);\n }\n\n public createDialogFilter(filter: MyDialogFilter, prepend?: boolean) {\n const maxId = Math.max(1, ...Object.keys(this.filters).map(i => +i));\n filter = copy(filter);\n filter.id = maxId + 1;\n return this.updateDialogFilter(filter, undefined, prepend);\n }\n\n public updateDialogFilter(filter: MyDialogFilter, remove = false, prepend = false) {\n const flags = remove ? 0 : 1;\n\n return apiManager.invokeApi('messages.updateDialogFilter', {\n flags,\n id: filter.id,\n filter: remove ? undefined : this.getOutputDialogFilter(filter)\n }).then((bool: boolean) => { // возможно нужна проверка и откат, если результат не ТРУ\n //console.log('updateDialogFilter bool:', bool);\n\n if(bool) {\n /* if(!this.filters[filter.id]) {\n this.saveDialogFilter(filter);\n }\n\n rootScope.$broadcast('filter_update', filter); */\n\n this.onUpdateDialogFilter({\n _: 'updateDialogFilter',\n id: filter.id,\n filter: remove ? undefined : filter as any\n });\n\n if(prepend) {\n const f: MyDialogFilter[] = [];\n for(const filterId in this.filters) {\n const filter = this.filters[filterId];\n ++filter.orderIndex;\n f.push(filter);\n }\n\n filter.orderIndex = START_ORDER_INDEX;\n\n const order = f.sort((a, b) => a.orderIndex - b.orderIndex).map(filter => filter.id);\n this.onUpdateDialogFilterOrder({\n _: 'updateDialogFilterOrder',\n order\n });\n }\n }\n\n return bool;\n });\n }\n\n public getOutputDialogFilter(filter: MyDialogFilter) {\n const c = copy(filter);\n /* convertment.forEach(([from, to]) => {\n c[from] = c[to].map((peerId) => this.appPeersManager.getInputPeerById(peerId));\n }); */\n\n this.filterIncludedPinnedPeers(filter);\n\n return c;\n }\n\n private filterIncludedPinnedPeers(filter: MyDialogFilter) {\n forEachReverse(filter.includePeerIds, (peerId, idx) => {\n if(filter.pinnedPeerIds.includes(peerId)) {\n filter.include_peers.splice(idx, 1);\n filter.includePeerIds.splice(idx, 1);\n }\n });\n }\n\n public reloadMissingPeerIds(filterId: number, type: 'pinned_peers' | 'include_peers' | 'exclude_peers' = 'pinned_peers') {\n const promises: Promise<any>[] = [];\n const filter = this.getFilter(filterId);\n const peers = filter && filter[type];\n if(peers?.length) {\n const reloadDialogs = peers.filter((inputPeer, idx) => {\n const peerId = this.appPeersManager.getPeerId(inputPeer);\n return !this.reloadedPeerIds.has(peerId) && !this.appMessagesManager.getDialogOnly(peerId);\n });\n\n if(reloadDialogs.length) {\n const reloadPromises = reloadDialogs.map(inputPeer => {\n const peerId = this.appPeersManager.getPeerId(inputPeer);\n const promise = this.appMessagesManager.reloadConversation(inputPeer);\n promise.then(() => {\n this.reloadedPeerIds.add(peerId);\n });\n return promise;\n });\n const reloadPromise = Promise.all(reloadPromises);\n promises.push(reloadPromise);\n }\n }\n\n return promises.length ? Promise.all(promises) : undefined;\n }\n\n public async getDialogFilters(overwrite = false): Promise<MyDialogFilter[]> {\n const keys = Object.keys(this.filters);\n if(keys.length && !overwrite) {\n return keys.map(filterId => this.filters[filterId]).sort((a, b) => a.orderIndex - b.orderIndex);\n }\n\n const filters: MyDialogFilter[] = await apiManager.invokeApiSingle('messages.getDialogFilters') as any;\n for(const filter of filters) {\n this.saveDialogFilter(filter, overwrite);\n }\n\n //console.log(this.filters);\n return filters;\n }\n\n public saveDialogFilter(filter: MyDialogFilter, update = true) {\n // defineNotNumerableProperties(filter, ['includePeerIds', 'excludePeerIds', 'pinnedPeerIds']);\n\n convertment.forEach(([from, to]) => {\n filter[to] = filter[from].map((peer) => this.appPeersManager.getPeerId(peer));\n });\n\n this.filterIncludedPinnedPeers(filter);\n \n filter.include_peers = filter.pinned_peers.concat(filter.include_peers);\n filter.includePeerIds = filter.pinnedPeerIds.concat(filter.includePeerIds);\n\n const oldFilter = this.filters[filter.id];\n if(oldFilter) {\n Object.assign(oldFilter, filter);\n } else {\n this.filters[filter.id] = filter;\n }\n \n this.setOrderIndex(filter);\n \n if(update) {\n this.rootScope.dispatchEvent('filter_update', filter);\n } else if(!oldFilter) {\n this.rootScope.dispatchEvent('filter_new', filter);\n }\n }\n\n public setOrderIndex(filter: MyDialogFilter) {\n if(filter.hasOwnProperty('orderIndex')) {\n if(filter.orderIndex >= this.orderIndex) {\n this.orderIndex = filter.orderIndex + 1;\n }\n } else {\n filter.orderIndex = this.orderIndex++ as DialogFilter['orderIndex'];\n }\n\n this.appStateManager.pushToState('filters', this.filters);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport { LazyLoadQueueBase } from \"../../components/lazyLoadQueue\";\nimport ProgressivePreloader from \"../../components/preloader\";\nimport { CancellablePromise, deferredPromise } from \"../../helpers/cancellablePromise\";\nimport { formatDateAccordingToTodayNew, formatTime, tsNow } from \"../../helpers/date\";\nimport { createPosterForVideo } from \"../../helpers/files\";\nimport { randomLong } from \"../../helpers/random\";\nimport { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs, InputChannel, InputDialogPeer, ReactionCount, MessagePeerReaction, MessagesSearchCounter, Peer, MessageReactions } from \"../../layer\";\nimport { ArgumentTypes, InvokeApiOptions } from \"../../types\";\nimport I18n, { FormatterArguments, i18n, join, langPack, LangPackKey, UNSUPPORTED_LANG_PACK_KEY, _i18n } from \"../langPack\";\nimport { logger, LogTypes } from \"../logger\";\nimport type { ApiFileManager } from '../mtproto/apiFileManager';\n//import apiManager from '../mtproto/apiManager';\nimport apiManager from '../mtproto/mtprotoworker';\nimport referenceDatabase, { ReferenceContext } from \"../mtproto/referenceDatabase\";\nimport serverTimeManager from \"../mtproto/serverTimeManager\";\nimport { RichTextProcessor } from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport DialogsStorage, { GLOBAL_FOLDER_ID } from \"../storages/dialogs\";\nimport FiltersStorage from \"../storages/filters\";\n//import { telegramMeWebService } from \"../mtproto/mtproto\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appChatsManager, { ChatRights } from \"./appChatsManager\";\nimport appDocsManager, { MyDocument } from \"./appDocsManager\";\nimport appDownloadManager from \"./appDownloadManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appPhotosManager, { MyPhoto } from \"./appPhotosManager\";\nimport appPollsManager from \"./appPollsManager\";\nimport appStateManager from \"./appStateManager\";\nimport appUsersManager from \"./appUsersManager\";\nimport appWebPagesManager from \"./appWebPagesManager\";\nimport appDraftsManager, { MyDraftMessage } from \"./appDraftsManager\";\nimport { getFileNameByLocation } from \"../../helpers/fileName\";\nimport appProfileManager from \"./appProfileManager\";\nimport DEBUG, { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport SlicedArray, { Slice, SliceEnd } from \"../../helpers/slicedArray\";\nimport appNotificationsManager, { NotifyOptions } from \"./appNotificationsManager\";\nimport PeerTitle from \"../../components/peerTitle\";\nimport htmlToDocumentFragment from \"../../helpers/dom/htmlToDocumentFragment\";\nimport htmlToSpan from \"../../helpers/dom/htmlToSpan\";\nimport { MUTE_UNTIL, NULL_PEER_ID, REPLIES_PEER_ID, SERVICE_PEER_ID } from \"../mtproto/mtproto_config\";\nimport formatCallDuration from \"../../helpers/formatCallDuration\";\nimport appAvatarsManager from \"./appAvatarsManager\";\nimport telegramMeWebManager from \"../mtproto/telegramMeWebManager\";\nimport { getMiddleware } from \"../../helpers/middleware\";\nimport assumeType from \"../../helpers/assumeType\";\nimport appMessagesIdsManager from \"./appMessagesIdsManager\";\nimport type { MediaSize } from \"../../helpers/mediaSizes\";\nimport IMAGE_MIME_TYPES_SUPPORTED from \"../../environment/imageMimeTypesSupport\";\nimport VIDEO_MIME_TYPES_SUPPORTED from \"../../environment/videoMimeTypesSupport\";\nimport './appGroupCallsManager';\nimport appGroupCallsManager from \"./appGroupCallsManager\";\nimport appReactionsManager from \"./appReactionsManager\";\nimport { getRestrictionReason, isRestricted } from \"../../helpers/restrictions\";\nimport copy from \"../../helpers/object/copy\";\nimport getObjectKeysAndSort from \"../../helpers/object/getObjectKeysAndSort\";\nimport forEachReverse from \"../../helpers/array/forEachReverse\";\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport deepEqual from \"../../helpers/object/deepEqual\";\nimport escapeRegExp from \"../../helpers/string/escapeRegExp\";\nimport limitSymbols from \"../../helpers/string/limitSymbols\";\nimport splitStringByLength from \"../../helpers/string/splitStringByLength\";\nimport debounce from \"../../helpers/schedulers/debounce\";\n\n//console.trace('include');\n// TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках\n\nconst APITIMEOUT = 0;\nconst DO_NOT_READ_HISTORY = false;\n\nexport type HistoryStorage = {\n count: number | null,\n history: SlicedArray<number>,\n\n maxId?: number,\n readPromise?: Promise<void>,\n readMaxId?: number,\n readOutboxMaxId?: number,\n triedToReadMaxId?: number,\n\n maxOutId?: number,\n replyMarkup?: Exclude<ReplyMarkup, ReplyMarkup.replyInlineMarkup>\n};\n\nexport type HistoryResult = {\n count: number,\n history: Slice<number>,\n offsetIdOffset?: number,\n};\n\nexport type Dialog = MTDialog.dialog;\n\nexport type MyMessage = Message.message | Message.messageService;\nexport type MyInputMessagesFilter = 'inputMessagesFilterEmpty' \n | 'inputMessagesFilterPhotos' \n | 'inputMessagesFilterPhotoVideo' \n | 'inputMessagesFilterVideo' \n | 'inputMessagesFilterDocument' \n | 'inputMessagesFilterVoice' \n | 'inputMessagesFilterRoundVoice' \n | 'inputMessagesFilterRoundVideo' \n | 'inputMessagesFilterMusic' \n | 'inputMessagesFilterUrl' \n | 'inputMessagesFilterMyMentions'\n | 'inputMessagesFilterChatPhotos'\n | 'inputMessagesFilterPinned';\n\nexport type PinnedStorage = Partial<{\n promise: Promise<PinnedStorage>,\n count: number,\n maxId: number\n}>;\nexport type MessagesStorage = Map<number, any>;\n\nexport type MyMessageActionType = Message.messageService['action']['_'];\n\ntype PendingAfterMsg = Partial<InvokeApiOptions & {\n afterMessageId: string,\n messageId: string\n}>;\n\ntype MapValueType<A> = A extends Map<any, infer V> ? V : never;\n\nexport type BatchUpdates = {\n 'messages_reactions': AppMessagesManager['batchUpdateReactions'],\n 'messages_views': AppMessagesManager['batchUpdateViews']\n};\n\nexport class AppMessagesManager {\n private messagesStorageByPeerId: {[peerId: string]: MessagesStorage};\n public groupedMessagesStorage: {[groupId: string]: MessagesStorage}; // will be used for albums\n private scheduledMessagesStorage: {[peerId: PeerId]: MessagesStorage};\n private historiesStorage: {\n [peerId: PeerId]: HistoryStorage\n };\n private threadsStorage: {\n [peerId: PeerId]: {\n [threadId: string]: HistoryStorage\n }\n };\n private searchesStorage: {\n [peerId: PeerId]: Partial<{\n [inputFilter in MyInputMessagesFilter]: {\n count?: number,\n history: number[]\n }\n }>\n };\n public pinnedMessages: {[peerId: PeerId]: PinnedStorage};\n\n public threadsServiceMessagesIdsStorage: {[peerId_threadId: string]: number};\n private threadsToReplies: {\n [peerId_threadId: string]: string;\n };\n\n private pendingByRandomId: {\n [randomId: string]: {\n peerId: PeerId,\n tempId: number,\n threadId: number,\n storage: MessagesStorage\n }\n } = {};\n private pendingByMessageId: {[mid: string]: Long} = {};\n private pendingAfterMsgs: {[peerId: PeerId]: PendingAfterMsg} = {};\n public pendingTopMsgs: {[peerId: PeerId]: number} = {};\n private tempFinalizeCallbacks: {\n [tempId: string]: {\n [callbackName: string]: Partial<{\n deferred: CancellablePromise<void>, \n callback: (message: any) => Promise<any>\n }>\n }\n } = {};\n \n private sendSmthLazyLoadQueue = new LazyLoadQueueBase(10);\n\n private needSingleMessages: Map<PeerId, Map<number, CancellablePromise<Message>>> = new Map();\n private fetchSingleMessagesPromise: Promise<void> = null;\n\n private maxSeenId = 0;\n\n public migratedFromTo: {[peerId: PeerId]: PeerId} = {};\n public migratedToFrom: {[peerId: PeerId]: PeerId} = {};\n\n private newMessagesHandleTimeout = 0;\n private newMessagesToHandle: {[peerId: PeerId]: Set<number>} = {};\n private newDialogsHandlePromise: Promise<any>;\n private newDialogsToHandle: {[peerId: PeerId]: Dialog} = {};\n public newUpdatesAfterReloadToHandle: {[peerId: PeerId]: Set<Update>} = {};\n\n private notificationsHandlePromise = 0;\n private notificationsToHandle: {[peerId: PeerId]: {\n fwdCount: number,\n fromId: PeerId,\n topMessage?: MyMessage\n }} = {};\n\n private reloadConversationsPromise: Promise<void>;\n private reloadConversationsPeers: Map<PeerId, {inputDialogPeer: InputDialogPeer, promise: CancellablePromise<Dialog>}> = new Map();\n\n public log = logger('MESSAGES', LogTypes.Error | LogTypes.Debug | LogTypes.Log | LogTypes.Warn);\n\n public dialogsStorage: DialogsStorage;\n public filtersStorage: FiltersStorage;\n\n private groupedTempId = 0;\n\n private typings: {[peerId: PeerId]: {action: SendMessageAction, timeout?: number}} = {};\n\n private middleware: ReturnType<typeof getMiddleware>;\n\n private unreadMentions: {[peerId: PeerId]: SlicedArray<number>} = {};\n private goToNextMentionPromises: {[peerId: PeerId]: Promise<any>} = {};\n \n private batchUpdates: {\n [k in keyof BatchUpdates]?: {\n callback: BatchUpdates[k],\n batch: ArgumentTypes<BatchUpdates[k]>[0]\n }\n } = {};\n private batchUpdatesDebounced: () => Promise<void>;\n\n constructor() {\n this.clear();\n\n rootScope.addMultipleEventsListeners({\n updateMessageID: this.onUpdateMessageId,\n\n updateNewDiscussionMessage: this.onUpdateNewMessage,\n updateNewMessage: this.onUpdateNewMessage,\n updateNewChannelMessage: this.onUpdateNewMessage,\n\n updateDialogUnreadMark: this.onUpdateDialogUnreadMark,\n\n updateEditMessage: this.onUpdateEditMessage,\n updateEditChannelMessage: this.onUpdateEditMessage,\n\n updateMessageReactions: this.onUpdateMessageReactions,\n\n updateReadChannelDiscussionInbox: this.onUpdateReadHistory,\n updateReadChannelDiscussionOutbox: this.onUpdateReadHistory,\n updateReadHistoryInbox: this.onUpdateReadHistory,\n updateReadHistoryOutbox: this.onUpdateReadHistory,\n updateReadChannelInbox: this.onUpdateReadHistory,\n updateReadChannelOutbox: this.onUpdateReadHistory,\n\n updateChannelReadMessagesContents: this.onUpdateReadMessagesContents,\n updateReadMessagesContents: this.onUpdateReadMessagesContents,\n\n updateChannelAvailableMessages: this.onUpdateChannelAvailableMessages,\n\n updateDeleteMessages: this.onUpdateDeleteMessages,\n updateDeleteChannelMessages: this.onUpdateDeleteMessages,\n\n updateChannel: this.onUpdateChannel,\n\n updateChannelReload: this.onUpdateChannelReload,\n\n updateChannelMessageViews: this.onUpdateChannelMessageViews,\n\n updateServiceNotification: this.onUpdateServiceNotification,\n\n updatePinnedMessages: this.onUpdatePinnedMessages,\n updatePinnedChannelMessages: this.onUpdatePinnedMessages,\n\n updateNotifySettings: this.onUpdateNotifySettings,\n\n updateNewScheduledMessage: this.onUpdateNewScheduledMessage,\n\n updateDeleteScheduledMessages: this.onUpdateDeleteScheduledMessages\n });\n\n // ! Invalidate notify settings, can optimize though\n rootScope.addEventListener('notify_peer_type_settings', ({key, settings}) => {\n const dialogs = this.dialogsStorage.getFolderDialogs(0).concat(this.dialogsStorage.getFolderDialogs(1));\n let filterFunc: (dialog: Dialog) => boolean;\n if(key === 'notifyUsers') filterFunc = (dialog) => dialog.peerId.isUser();\n else if(key === 'notifyBroadcasts') filterFunc = (dialog) => dialog.peerId.isBroadcast();\n else filterFunc = (dialog) => appPeersManager.isAnyGroup(dialog.peerId);\n\n dialogs\n .filter(filterFunc)\n .forEach(dialog => {\n rootScope.dispatchEvent('dialog_notify_settings', dialog);\n });\n });\n\n rootScope.addEventListener('webpage_updated', ({id, msgs}) => {\n msgs.forEach(({peerId, mid, isScheduled}) => {\n const storage = isScheduled ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId);\n const message = this.getMessageFromStorage(storage, mid) as Message.message;\n if(!message) return;\n message.media = {\n _: 'messageMediaWebPage', \n webpage: appWebPagesManager.getWebPage(id)\n };\n\n rootScope.dispatchEvent('message_edit', {\n storage,\n peerId,\n mid\n });\n });\n });\n\n rootScope.addEventListener('draft_updated', ({peerId, threadId, draft}) => {\n if(threadId) return;\n\n const dialog = this.getDialogOnly(peerId);\n if(dialog) {\n if(!threadId) {\n dialog.draft = draft;\n\n let drop = false;\n if(!draft && !appMessagesIdsManager.getServerMessageId(dialog.top_message)) {\n this.dialogsStorage.dropDialog(peerId);\n drop = true;\n } else {\n this.dialogsStorage.generateIndexForDialog(dialog);\n this.dialogsStorage.pushDialog(dialog);\n }\n\n rootScope.dispatchEvent('dialog_draft', {\n peerId,\n dialog,\n drop,\n draft,\n index: dialog.index\n });\n }\n } else {\n this.reloadConversation(peerId);\n }\n });\n\n rootScope.addEventListener('poll_update', ({poll}) => {\n const set = appPollsManager.pollToMessages[poll.id];\n if(set) {\n for(const key of set) {\n const [peerId, mid] = key.split('_');\n\n const message = this.getMessageByPeer(peerId.toPeerId(), +mid);\n this.setDialogToStateIfMessageIsTop(message);\n }\n }\n });\n \n appStateManager.getState().then(state => {\n if(state.maxSeenMsgId) {\n this.maxSeenId = state.maxSeenMsgId;\n }\n });\n\n this.batchUpdatesDebounced = debounce(() => {\n for(const event in this.batchUpdates) {\n const details = this.batchUpdates[event as keyof BatchUpdates];\n delete this.batchUpdates[event as keyof BatchUpdates];\n\n // @ts-ignore\n const result = details.callback(details.batch);\n if(result && (!(result instanceof Array) || result.length)) {\n // @ts-ignore\n rootScope.dispatchEvent(event as keyof BatchUpdates, result);\n }\n }\n }, 33, false, true);\n }\n\n public clear() {\n if(this.middleware) {\n this.middleware.clean();\n } else {\n this.middleware = getMiddleware();\n }\n\n this.messagesStorageByPeerId = {};\n this.groupedMessagesStorage = {};\n this.scheduledMessagesStorage = {};\n this.historiesStorage = {};\n this.threadsStorage = {};\n this.searchesStorage = {};\n this.pinnedMessages = {};\n this.threadsServiceMessagesIdsStorage = {};\n this.threadsToReplies = {};\n\n this.dialogsStorage && this.dialogsStorage.clear();\n this.filtersStorage && this.filtersStorage.clear();\n }\n\n public construct() {\n this.filtersStorage = new FiltersStorage(this, appPeersManager, appUsersManager, appNotificationsManager, appStateManager, apiUpdatesManager, /* apiManager, */ rootScope);\n this.dialogsStorage = new DialogsStorage(this, appChatsManager, appPeersManager, appUsersManager, appDraftsManager, appNotificationsManager, appStateManager, apiUpdatesManager, serverTimeManager, appMessagesIdsManager);\n }\n\n public getInputEntities(entities: MessageEntity[]) {\n const sendEntites = copy(entities);\n sendEntites.forEach((entity) => {\n if(entity._ === 'messageEntityMentionName') {\n (entity as any as MessageEntity.inputMessageEntityMentionName)._ = 'inputMessageEntityMentionName';\n (entity as any as MessageEntity.inputMessageEntityMentionName).user_id = appUsersManager.getUserInput(entity.user_id);\n }\n });\n return sendEntites;\n }\n\n public invokeAfterMessageIsSent(tempId: number, callbackName: string, callback: (message: any) => Promise<any>) {\n const finalize = this.tempFinalizeCallbacks[tempId] ?? (this.tempFinalizeCallbacks[tempId] = {});\n const obj = finalize[callbackName] ?? (finalize[callbackName] = {deferred: deferredPromise<void>()});\n\n obj.callback = callback;\n\n return obj.deferred;\n }\n\n public editMessage(message: any, text: string, options: Partial<{\n noWebPage: true,\n newMedia: any,\n scheduleDate: number,\n entities: MessageEntity[]\n }> = {}): Promise<void> {\n /* if(!this.canEditMessage(messageId)) {\n return Promise.reject({type: 'MESSAGE_EDIT_FORBIDDEN'});\n } */\n\n const {mid, peerId} = message;\n\n if(message.pFlags.is_outgoing) {\n return this.invokeAfterMessageIsSent(mid, 'edit', (message) => {\n //this.log('invoke editMessage callback', message);\n return this.editMessage(message, text, options);\n });\n }\n\n let entities = options.entities || [];\n if(text) {\n text = RichTextProcessor.parseMarkdown(text, entities);\n }\n\n const schedule_date = options.scheduleDate || (message.pFlags.is_scheduled ? message.date : undefined);\n return apiManager.invokeApi('messages.editMessage', {\n peer: appPeersManager.getInputPeerById(peerId),\n id: message.id,\n message: text,\n media: options.newMedia,\n entities: entities.length ? this.getInputEntities(entities) : undefined,\n no_webpage: options.noWebPage,\n schedule_date\n }).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates);\n }, (error) => {\n this.log.error('editMessage error:', error);\n \n if(error && error.type === 'MESSAGE_NOT_MODIFIED') {\n error.handled = true;\n return;\n }\n if(error && error.type === 'MESSAGE_EMPTY') {\n error.handled = true;\n }\n return Promise.reject(error);\n });\n }\n\n public sendText(peerId: PeerId, text: string, options: Partial<{\n entities: MessageEntity[],\n replyToMsgId: number,\n threadId: number,\n viaBotId: BotId,\n queryId: string,\n resultId: string,\n noWebPage: true,\n replyMarkup: ReplyMarkup,\n clearDraft: true,\n webPage: WebPage,\n scheduleDate: number,\n silent: true,\n sendAsPeerId: PeerId,\n }> = {}) {\n if(!text.trim()) {\n return Promise.resolve();\n }\n\n //this.checkSendOptions(options);\n\n if(options.threadId && !options.replyToMsgId) {\n options.replyToMsgId = options.threadId;\n }\n\n const MAX_LENGTH = rootScope.config.message_length_max;\n if(text.length > MAX_LENGTH) {\n const splitted = splitStringByLength(text, MAX_LENGTH);\n text = splitted[0];\n\n if(splitted.length > 1) {\n delete options.webPage;\n }\n\n for(let i = 1; i < splitted.length; ++i) {\n setTimeout(() => {\n this.sendText(peerId, splitted[i], options);\n }, i);\n }\n }\n\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\n\n let entities = options.entities || [];\n if(!options.viaBotId) {\n text = RichTextProcessor.parseMarkdown(text, entities);\n //entities = RichTextProcessor.mergeEntities(entities, RichTextProcessor.parseEntities(text));\n }\n\n let sendEntites = this.getInputEntities(entities);\n if(!sendEntites.length) {\n sendEntites = undefined;\n }\n\n const message = this.generateOutgoingMessage(peerId, options);\n message.entities = entities;\n message.message = text;\n\n const replyToMsgId = options.replyToMsgId ? appMessagesIdsManager.getServerMessageId(options.replyToMsgId) : undefined;\n const isChannel = appPeersManager.isChannel(peerId);\n\n if(options.webPage) {\n message.media = {\n _: 'messageMediaWebPage',\n webpage: options.webPage\n };\n }\n\n const toggleError = (on: boolean) => {\n if(on) {\n message.error = true;\n } else {\n delete message.error;\n }\n rootScope.dispatchEvent('messages_pending');\n };\n\n message.send = () => {\n toggleError(false);\n const sentRequestOptions: PendingAfterMsg = {};\n if(this.pendingAfterMsgs[peerId]) {\n sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;\n }\n\n const sendAs = options.sendAsPeerId ? appPeersManager.getInputPeerById(options.sendAsPeerId) : undefined\n let apiPromise: any;\n if(options.viaBotId) {\n apiPromise = apiManager.invokeApiAfter('messages.sendInlineBotResult', {\n peer: appPeersManager.getInputPeerById(peerId),\n random_id: message.random_id,\n reply_to_msg_id: replyToMsgId || undefined,\n query_id: options.queryId,\n id: options.resultId,\n clear_draft: options.clearDraft,\n send_as: sendAs\n }, sentRequestOptions);\n } else {\n apiPromise = apiManager.invokeApiAfter('messages.sendMessage', {\n no_webpage: options.noWebPage,\n peer: appPeersManager.getInputPeerById(peerId),\n message: text,\n random_id: message.random_id,\n reply_to_msg_id: replyToMsgId || undefined,\n entities: sendEntites,\n clear_draft: options.clearDraft,\n schedule_date: options.scheduleDate || undefined,\n silent: options.silent,\n send_as: sendAs\n }, sentRequestOptions);\n }\n\n /* function is<T>(value: any, condition: boolean): value is T {\n return condition;\n } */\n\n //this.log('sendText', message.mid);\n this.pendingAfterMsgs[peerId] = sentRequestOptions;\n\n return apiPromise.then((updates: Updates) => {\n //this.log('sendText sent', message.mid);\n //if(is<Updates.updateShortSentMessage>(updates, updates._ === 'updateShortSentMessage')) {\n if(updates._ === 'updateShortSentMessage') {\n //assumeType<Updates.updateShortSentMessage>(updates);\n\n // * fix copying object with promise\n const promise = message.promise;\n delete message.promise;\n const newMessage = copy(message);\n message.promise = promise;\n\n newMessage.date = updates.date;\n newMessage.id = updates.id;\n newMessage.media = updates.media;\n newMessage.entities = updates.entities;\n this.wrapMessageEntities(newMessage);\n if(updates.pFlags.out) {\n newMessage.pFlags.out = true;\n }\n\n // * override with new updates\n updates = {\n _: 'updates',\n users: [],\n chats: [],\n seq: 0,\n date: undefined,\n updates: [{\n _: 'updateMessageID',\n random_id: message.random_id,\n id: newMessage.id\n }, {\n _: options.scheduleDate ? 'updateNewScheduledMessage' : (isChannel ? 'updateNewChannelMessage' : 'updateNewMessage'),\n message: newMessage,\n pts: updates.pts,\n pts_count: updates.pts_count\n }]\n };\n } else if((updates as Updates.updates).updates) {\n (updates as Updates.updates).updates.forEach((update) => {\n if(update._ === 'updateDraftMessage') {\n update.local = true;\n }\n });\n }\n // Testing bad situations\n // var upd = angular.copy(updates)\n // updates.updates.splice(0, 1)\n\n apiUpdatesManager.processUpdateMessage(updates);\n\n // $timeout(function () {\n // ApiUpdatesManager.processUpdateMessage(upd)\n // }, 5000)\n message.promise.resolve();\n }, (error: any) => {\n toggleError(true);\n message.promise.reject(error);\n }).finally(() => {\n if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {\n delete this.pendingAfterMsgs[peerId];\n }\n });\n };\n\n this.beforeMessageSending(message, {\n isScheduled: !!options.scheduleDate || undefined, \n threadId: options.threadId,\n clearDraft: options.clearDraft\n });\n\n return message.promise;\n }\n\n public sendFile(peerId: PeerId, file: File | Blob | MyDocument, options: Partial<{\n isRoundMessage: true,\n isVoiceMessage: true,\n isGroupedItem: true,\n isMedia: true,\n\n replyToMsgId: number,\n sendAsPeerId: PeerId,\n threadId: number,\n groupId: string,\n caption: string,\n entities: MessageEntity[],\n width: number,\n height: number,\n objectURL: string,\n thumb: {\n blob: Blob,\n url: string,\n size: MediaSize\n },\n duration: number,\n background: true,\n silent: true,\n clearDraft: true,\n scheduleDate: number,\n noSound: boolean,\n\n waveform: Uint8Array,\n }> = {}) {\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\n\n //this.checkSendOptions(options);\n\n const message = this.generateOutgoingMessage(peerId, options);\n const replyToMsgId = options.replyToMsgId ? appMessagesIdsManager.getServerMessageId(options.replyToMsgId) : undefined;\n\n let attachType: 'document' | 'audio' | 'video' | 'voice' | 'photo', apiFileName: string;\n\n const fileType = 'mime_type' in file ? file.mime_type : file.type;\n const fileName = file instanceof File ? file.name : '';\n const isDocument = !(file instanceof File) && !(file instanceof Blob);\n let caption = options.caption || '';\n\n this.log('sendFile', file, fileType);\n\n const entities = options.entities || [];\n if(caption) {\n caption = RichTextProcessor.parseMarkdown(caption, entities);\n }\n\n const attributes: DocumentAttribute[] = [];\n\n const isPhoto = IMAGE_MIME_TYPES_SUPPORTED.has(fileType);\n\n let photo: MyPhoto, document: MyDocument;\n\n let actionName: Extract<SendMessageAction['_'], 'sendMessageUploadAudioAction' | 'sendMessageUploadDocumentAction' | 'sendMessageUploadPhotoAction' | 'sendMessageUploadVideoAction'>;\n if(isDocument) { // maybe it's a sticker or gif\n attachType = 'document';\n apiFileName = '';\n } else if(fileType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(fileType) >= 0) {\n attachType = 'audio';\n apiFileName = 'audio.' + (fileType.split('/')[1] === 'ogg' ? 'ogg' : 'mp3');\n actionName = 'sendMessageUploadAudioAction';\n\n if(options.isVoiceMessage) {\n attachType = 'voice';\n message.pFlags.media_unread = true;\n }\n\n let attribute: DocumentAttribute.documentAttributeAudio = {\n _: 'documentAttributeAudio',\n pFlags: {\n voice: options.isVoiceMessage\n },\n waveform: options.waveform,\n duration: options.duration || 0\n };\n\n attributes.push(attribute);\n } else if(!options.isMedia) {\n attachType = 'document';\n apiFileName = 'document.' + fileType.split('/')[1];\n actionName = 'sendMessageUploadDocumentAction';\n } else if(isPhoto) {\n attachType = 'photo';\n apiFileName = 'photo.' + fileType.split('/')[1];\n actionName = 'sendMessageUploadPhotoAction';\n\n const photoSize = {\n _: 'photoSize',\n w: options.width,\n h: options.height,\n type: 'full',\n location: null,\n size: file.size\n } as PhotoSize.photoSize;\n\n photo = {\n _: 'photo',\n id: '' + message.id,\n sizes: [photoSize],\n w: options.width,\n h: options.height\n } as any;\n\n const cacheContext = appDownloadManager.getCacheContext(photo, photoSize.type);\n cacheContext.downloaded = file.size;\n cacheContext.url = options.objectURL || '';\n \n photo = appPhotosManager.savePhoto(photo);\n } else if(VIDEO_MIME_TYPES_SUPPORTED.has(fileType)) {\n attachType = 'video';\n apiFileName = 'video.mp4';\n actionName = 'sendMessageUploadVideoAction';\n\n const videoAttribute: DocumentAttribute.documentAttributeVideo = {\n _: 'documentAttributeVideo',\n pFlags: {\n round_message: options.isRoundMessage,\n supports_streaming: true\n }, \n duration: options.duration,\n w: options.width,\n h: options.height\n };\n\n attributes.push(videoAttribute);\n\n // * must follow after video attribute\n if(options.noSound && \n file.size > (10 * 1024) && \n file.size < (10 * 1024 * 1024)) {\n attributes.push({\n _: 'documentAttributeAnimated'\n });\n }\n } else {\n attachType = 'document';\n apiFileName = 'document.' + fileType.split('/')[1];\n actionName = 'sendMessageUploadDocumentAction';\n }\n\n attributes.push({_: 'documentAttributeFilename', file_name: fileName || apiFileName});\n\n if((['document', 'video', 'audio', 'voice'] as (typeof attachType)[]).indexOf(attachType) !== -1 && !isDocument) {\n const thumbs: PhotoSize[] = [];\n document = {\n _: 'document',\n id: '' + message.id,\n duration: options.duration,\n attributes,\n w: options.width,\n h: options.height,\n thumbs,\n mime_type: fileType,\n size: file.size\n } as any;\n\n if(options.objectURL) {\n const cacheContext = appDownloadManager.getCacheContext(document);\n cacheContext.downloaded = file.size;\n cacheContext.url = options.objectURL;\n }\n\n let thumb: PhotoSize.photoSize;\n if(isPhoto) {\n attributes.push({\n _: 'documentAttributeImageSize',\n w: options.width,\n h: options.height\n });\n\n thumb = {\n _: 'photoSize',\n w: options.width,\n h: options.height,\n type: 'full',\n size: file.size\n };\n } else if(attachType === 'video') {\n if(options.thumb) {\n thumb = {\n _: 'photoSize',\n w: options.thumb.size.width,\n h: options.thumb.size.height,\n type: 'local-thumb',\n size: options.thumb.blob.size\n };\n\n const thumbCacheContext = appDownloadManager.getCacheContext(document, thumb.type);\n thumbCacheContext.downloaded = thumb.size;\n thumbCacheContext.url = options.thumb.url;\n }\n }\n\n if(thumb) {\n thumbs.push(thumb);\n }\n\n /* if(thumbs.length) {\n const thumb = thumbs[0] as PhotoSize.photoSize;\n const docThumb = appPhotosManager.getDocumentCachedThumb(document.id);\n docThumb.downloaded = thumb.size;\n docThumb.url = thumb.url;\n } */\n \n document = appDocsManager.saveDoc(document);\n }\n\n this.log('sendFile', attachType, apiFileName, file.type, options);\n\n const preloader = isDocument ? undefined : new ProgressivePreloader({\n attachMethod: 'prepend',\n tryAgainOnFail: false,\n isUpload: true\n });\n\n const sentDeferred = deferredPromise<InputMedia>();\n\n if(preloader) {\n preloader.attachPromise(sentDeferred);\n sentDeferred.cancel = () => {\n const error = new Error('Download canceled');\n error.name = 'AbortError';\n sentDeferred.reject(error);\n };\n\n sentDeferred.catch(err => {\n if(err.name === 'AbortError' && !uploaded) {\n this.log('cancelling upload', media);\n\n this.cancelPendingMessage(message.random_id);\n this.setTyping(peerId, {_: 'sendMessageCancelAction'});\n\n if(uploadPromise?.cancel) {\n uploadPromise.cancel();\n }\n }\n });\n }\n\n const media = isDocument ? undefined : {\n _: photo ? 'messageMediaPhoto' : 'messageMediaDocument',\n pFlags: {},\n preloader,\n photo,\n document,\n promise: sentDeferred\n };\n\n message.entities = entities;\n message.message = caption;\n message.media = isDocument ? {\n _: 'messageMediaDocument',\n pFlags: {},\n document: file \n } as MessageMedia.messageMediaDocument : media as any;\n\n const toggleError = (on: boolean) => {\n if(on) {\n message.error = true;\n } else {\n delete message.error;\n }\n\n rootScope.dispatchEvent('messages_pending');\n };\n\n let uploaded = false,\n uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;\n\n message.send = () => {\n if(isDocument) {\n const {id, access_hash, file_reference} = file as MyDocument;\n\n const inputMedia: InputMedia = {\n _: 'inputMediaDocument',\n id: {\n _: 'inputDocument',\n id,\n access_hash,\n file_reference\n }\n };\n \n sentDeferred.resolve(inputMedia);\n } else if(file instanceof File || file instanceof Blob) {\n const load = () => {\n if(!uploaded || message.error) {\n uploaded = false;\n uploadPromise = appDownloadManager.upload(file);\n sentDeferred.notifyAll({done: 0, total: file.size});\n }\n\n let thumbUploadPromise: typeof uploadPromise;\n if(attachType === 'video' && options.objectURL) {\n thumbUploadPromise = new Promise((resolve, reject) => {\n const thumbPromise = options.thumb && options.thumb.blob ? Promise.resolve(options.thumb) : createPosterForVideo(options.objectURL);\n thumbPromise.then(thumb => {\n if(!thumb) {\n resolve(null);\n } else {\n appDownloadManager.upload(thumb.blob).then(resolve, reject);\n }\n }, reject);\n });\n }\n \n uploadPromise && uploadPromise.then(async(inputFile) => {\n /* if(DEBUG) {\n this.log('appMessagesManager: sendFile uploaded:', inputFile);\n } */\n\n // @ts-ignore\n delete message.media.preloader;\n\n inputFile.name = apiFileName;\n uploaded = true;\n let inputMedia: InputMedia;\n switch(attachType) {\n case 'photo':\n inputMedia = {\n _: 'inputMediaUploadedPhoto', \n file: inputFile,\n };\n break;\n\n default:\n inputMedia = {\n _: 'inputMediaUploadedDocument', \n file: inputFile, \n mime_type: fileType, \n pFlags: {\n force_file: actionName === 'sendMessageUploadDocumentAction' ? true : undefined,\n // nosound_video: options.noSound ? true : undefined\n },\n attributes\n };\n }\n\n if(thumbUploadPromise) {\n try {\n const inputFile = await thumbUploadPromise;\n (inputMedia as InputMedia.inputMediaUploadedDocument).thumb = inputFile;\n } catch(err) {\n this.log.error('sendFile thumb upload error:', err);\n }\n }\n \n sentDeferred.resolve(inputMedia);\n }, (/* error */) => {\n toggleError(true);\n });\n \n uploadPromise.addNotifyListener((progress: {done: number, total: number}) => {\n /* if(DEBUG) {\n this.log('upload progress', progress);\n } */\n\n const percents = Math.max(1, Math.floor(100 * progress.done / progress.total));\n if(actionName) {\n this.setTyping(peerId, {_: actionName, progress: percents | 0});\n }\n sentDeferred.notifyAll(progress);\n });\n\n return sentDeferred;\n };\n\n if(options.isGroupedItem) {\n load();\n } else {\n this.sendSmthLazyLoadQueue.push({\n load\n });\n }\n }\n\n return sentDeferred;\n };\n\n this.beforeMessageSending(message, {\n isGroupedItem: options.isGroupedItem, \n isScheduled: !!options.scheduleDate || undefined, \n threadId: options.threadId,\n clearDraft: options.clearDraft\n });\n\n if(!options.isGroupedItem) {\n sentDeferred.then(inputMedia => {\n this.setTyping(peerId, {_: 'sendMessageCancelAction'});\n\n return apiManager.invokeApi('messages.sendMedia', {\n background: options.background,\n peer: appPeersManager.getInputPeerById(peerId),\n media: inputMedia,\n message: caption,\n random_id: message.random_id,\n reply_to_msg_id: replyToMsgId,\n schedule_date: options.scheduleDate,\n silent: options.silent,\n entities,\n clear_draft: options.clearDraft,\n send_as: options.sendAsPeerId ? appPeersManager.getInputPeerById(options.sendAsPeerId) : undefined\n }).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates);\n }, (error) => {\n if(attachType === 'photo' &&\n error.code === 400 &&\n (error.type === 'PHOTO_INVALID_DIMENSIONS' ||\n error.type === 'PHOTO_SAVE_FILE_INVALID')) {\n error.handled = true;\n attachType = 'document';\n message.send();\n return;\n }\n\n toggleError(true);\n throw error;\n });\n });\n\n sentDeferred.then(message.promise.resolve, message.promise.reject);\n }\n\n return {message, promise: sentDeferred};\n }\n\n public async sendAlbum(peerId: PeerId, files: File[], options: Partial<{\n isMedia: true,\n entities: MessageEntity[],\n replyToMsgId: number,\n sendAsPeerId: PeerId,\n threadId: number,\n caption: string,\n sendFileDetails: Partial<{\n duration: number,\n width: number,\n height: number,\n objectURL: string,\n thumbBlob: Blob,\n thumbURL: string\n }>[],\n silent: true,\n clearDraft: true,\n scheduleDate: number\n }> = {}) {\n //this.checkSendOptions(options);\n\n if(options.threadId && !options.replyToMsgId) {\n options.replyToMsgId = options.threadId;\n }\n\n if(files.length === 1) {\n return this.sendFile(peerId, files[0], {...options, ...options.sendFileDetails[0]});\n }\n\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\n const replyToMsgId = options.replyToMsgId ? appMessagesIdsManager.getServerMessageId(options.replyToMsgId) : undefined;\n\n let caption = options.caption || '';\n let entities = options.entities || [];\n if(caption) {\n caption = RichTextProcessor.parseMarkdown(caption, entities);\n }\n\n this.log('sendAlbum', files, options);\n\n const groupId = '' + ++this.groupedTempId;\n\n const messages = files.map((file, idx) => {\n const details = options.sendFileDetails[idx];\n const o: Parameters<AppMessagesManager['sendFile']>[2] = {\n isGroupedItem: true,\n isMedia: options.isMedia,\n scheduleDate: options.scheduleDate,\n silent: options.silent,\n replyToMsgId,\n threadId: options.threadId,\n sendAsPeerId: options.sendAsPeerId,\n groupId,\n ...details\n };\n\n if(idx === 0) {\n o.caption = caption;\n o.entities = entities;\n //o.replyToMsgId = replyToMsgId;\n }\n\n return this.sendFile(peerId, file, o).message;\n });\n\n if(options.clearDraft) {\n setTimeout(() => {\n appDraftsManager.clearDraft(peerId, options.threadId);\n }, 0);\n }\n \n // * test pending\n //return;\n\n const toggleError = (message: any, on: boolean) => {\n if(on) {\n message.error = true;\n } else {\n delete message.error;\n }\n\n rootScope.dispatchEvent('messages_pending');\n };\n\n const inputPeer = appPeersManager.getInputPeerById(peerId);\n const invoke = (multiMedia: InputSingleMedia[]) => {\n this.setTyping(peerId, {_: 'sendMessageCancelAction'});\n\n const deferred = deferredPromise<void>();\n this.sendSmthLazyLoadQueue.push({\n load: () => {\n return apiManager.invokeApi('messages.sendMultiMedia', {\n peer: inputPeer,\n multi_media: multiMedia,\n reply_to_msg_id: replyToMsgId,\n schedule_date: options.scheduleDate,\n silent: options.silent,\n clear_draft: options.clearDraft,\n send_as: options.sendAsPeerId ? appPeersManager.getInputPeerById(options.sendAsPeerId) : undefined\n }).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates);\n deferred.resolve();\n }, (error) => {\n messages.forEach(message => toggleError(message, true));\n deferred.reject(error);\n });\n }\n });\n\n return deferred;\n };\n\n const promises: Promise<InputSingleMedia>[] = messages.map((message) => {\n return (message.send() as Promise<InputMedia>).then((inputMedia) => {\n return apiManager.invokeApi('messages.uploadMedia', {\n peer: inputPeer,\n media: inputMedia\n });\n })\n .then(messageMedia => {\n let inputMedia: InputMedia;\n if(messageMedia._ === 'messageMediaPhoto') {\n const photo = appPhotosManager.savePhoto(messageMedia.photo);\n inputMedia = appPhotosManager.getMediaInput(photo);\n } else if(messageMedia._ === 'messageMediaDocument') {\n const doc = appDocsManager.saveDoc(messageMedia.document);\n inputMedia = appDocsManager.getMediaInput(doc);\n }\n\n const inputSingleMedia: InputSingleMedia = {\n _: 'inputSingleMedia',\n media: inputMedia,\n random_id: message.random_id,\n message: caption,\n entities\n };\n\n // * only 1 caption for all inputs\n if(caption) {\n caption = '';\n entities = [];\n }\n\n return inputSingleMedia;\n }).catch((err: any) => {\n if(err.name === 'AbortError') {\n return null;\n }\n\n this.log.error('sendAlbum upload item error:', err, message);\n toggleError(message, true);\n throw err;\n });\n });\n\n return Promise.all(promises).then(inputs => {\n return invoke(inputs.filter(Boolean));\n });\n }\n\n public sendContact(peerId: PeerId, contactPeerId: PeerId) {\n return this.sendOther(peerId, appUsersManager.getContactMediaInput(contactPeerId));\n }\n\n public sendOther(peerId: PeerId, inputMedia: InputMedia, options: Partial<{\n replyToMsgId: number,\n threadId: number,\n viaBotId: BotId,\n replyMarkup: ReplyMarkup,\n clearDraft: true,\n queryId: string\n resultId: string,\n scheduleDate: number,\n silent: true,\n geoPoint: GeoPoint,\n sendAsPeerId: PeerId,\n }> = {}) {\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\n\n //this.checkSendOptions(options);\n const message = this.generateOutgoingMessage(peerId, options);\n const replyToMsgId = options.replyToMsgId ? appMessagesIdsManager.getServerMessageId(options.replyToMsgId) : undefined;\n\n let media: MessageMedia;\n switch(inputMedia._) {\n case 'inputMediaPoll': {\n const pollId = '' + message.id;\n inputMedia.poll.id = pollId;\n appPollsManager.savePoll(inputMedia.poll, {\n _: 'pollResults',\n flags: 4,\n total_voters: 0,\n pFlags: {},\n recent_voters: []\n });\n\n const {poll, results} = appPollsManager.getPoll(pollId);\n media = {\n _: 'messageMediaPoll',\n poll,\n results\n };\n\n break;\n }\n\n case 'inputMediaPhoto': {\n media = {\n _: 'messageMediaPhoto',\n photo: appPhotosManager.getPhoto((inputMedia.id as InputPhoto.inputPhoto).id)\n };\n break;\n }\n\n case 'inputMediaDocument': {\n const doc = appDocsManager.getDoc((inputMedia.id as InputDocument.inputDocument).id);\n /* if(doc.sticker && doc.stickerSetInput) {\n appStickersManager.pushPopularSticker(doc.id);\n } */\n media = {\n _: 'messageMediaDocument',\n document: doc\n };\n break;\n }\n\n case 'inputMediaContact': {\n media = {\n _: 'messageMediaContact',\n phone_number: inputMedia.phone_number,\n first_name: inputMedia.first_name,\n last_name: inputMedia.last_name,\n user_id: inputMedia.user_id ?? '0',\n vcard: inputMedia.vcard\n };\n break;\n }\n\n case 'inputMediaGeoPoint': {\n media = {\n _: 'messageMediaGeo',\n geo: options.geoPoint\n };\n break;\n }\n\n case 'inputMediaVenue': {\n media = {\n _: 'messageMediaVenue',\n geo: options.geoPoint,\n title: inputMedia.title,\n address: inputMedia.address,\n provider: inputMedia.provider,\n venue_id: inputMedia.venue_id,\n venue_type: inputMedia.venue_type\n };\n break;\n }\n \n // @ts-ignore\n case 'messageMediaPending': {\n media = inputMedia;\n break;\n }\n }\n\n message.media = media;\n\n let toggleError = (on: boolean) => {\n /* const historyMessage = this.messagesForHistory[messageId];\n if (on) {\n message.error = true\n if (historyMessage) {\n historyMessage.error = true\n }\n } else {\n delete message.error\n if (historyMessage) {\n delete historyMessage.error\n }\n } */\n rootScope.dispatchEvent('messages_pending');\n };\n\n message.send = () => {\n const sentRequestOptions: PendingAfterMsg = {};\n if(this.pendingAfterMsgs[peerId]) {\n sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;\n }\n\n const sendAs = options.sendAsPeerId ? appPeersManager.getInputPeerById(options.sendAsPeerId) : undefined;\n let apiPromise: Promise<any>;\n if(options.viaBotId) {\n apiPromise = apiManager.invokeApiAfter('messages.sendInlineBotResult', {\n peer: appPeersManager.getInputPeerById(peerId),\n random_id: message.random_id,\n reply_to_msg_id: replyToMsgId || undefined,\n query_id: options.queryId,\n id: options.resultId,\n clear_draft: options.clearDraft,\n schedule_date: options.scheduleDate,\n silent: options.silent,\n send_as: sendAs\n }, sentRequestOptions);\n } else {\n apiPromise = apiManager.invokeApiAfter('messages.sendMedia', {\n peer: appPeersManager.getInputPeerById(peerId),\n media: inputMedia,\n random_id: message.random_id,\n reply_to_msg_id: replyToMsgId || undefined,\n message: '',\n clear_draft: options.clearDraft,\n schedule_date: options.scheduleDate,\n silent: options.silent,\n send_as: sendAs\n }, sentRequestOptions);\n }\n\n this.pendingAfterMsgs[peerId] = sentRequestOptions;\n\n return apiPromise.then((updates) => {\n if(updates.updates) {\n updates.updates.forEach((update: Update) => {\n if(update._ === 'updateDraftMessage') {\n update.local = true;\n }\n });\n }\n\n apiUpdatesManager.processUpdateMessage(updates);\n }, (error) => {\n toggleError(true);\n }).finally(() => {\n if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {\n delete this.pendingAfterMsgs[peerId];\n }\n });\n };\n\n this.beforeMessageSending(message, {\n isScheduled: !!options.scheduleDate || undefined, \n threadId: options.threadId,\n clearDraft: options.clearDraft\n });\n\n return message.promise;\n }\n\n /* private checkSendOptions(options: Partial<{\n scheduleDate: number\n }>) {\n if(options.scheduleDate) {\n const minTimestamp = (Date.now() / 1000 | 0) + 10;\n if(options.scheduleDate <= minTimestamp) {\n delete options.scheduleDate;\n }\n }\n } */\n\n private beforeMessageSending(message: Message.message, options: Partial<{\n isGroupedItem: true, \n isScheduled: true, \n threadId: number, \n clearDraft: true\n }> = {}) {\n const messageId = message.id;\n const peerId = this.getMessagePeer(message);\n const storage = options.isScheduled ? this.getScheduledMessagesStorage(peerId) : this.getMessagesStorage(peerId);\n\n if(options.isScheduled) {\n //if(!options.isGroupedItem) {\n this.saveMessages([message], {storage, isScheduled: true, isOutgoing: true});\n setTimeout(() => {\n rootScope.dispatchEvent('scheduled_new', {peerId, mid: messageId});\n }, 0);\n } else {\n /* if(options.threadId && this.threadsStorage[peerId]) {\n delete this.threadsStorage[peerId][options.threadId];\n } */\n const storages: HistoryStorage[] = [\n this.getHistoryStorage(peerId),\n options.threadId ? this.getHistoryStorage(peerId, options.threadId) : undefined\n ];\n\n for(const storage of storages) {\n if(storage) {\n storage.history.unshift(messageId);\n }\n }\n\n //if(!options.isGroupedItem) {\n this.saveMessages([message], {storage, isOutgoing: true});\n this.setDialogTopMessage(message);\n setTimeout(() => {\n rootScope.dispatchEvent('history_append', {storage, peerId, mid: messageId});\n }, 0);\n }\n\n this.pendingByRandomId[message.random_id] = {\n peerId, \n tempId: messageId, \n threadId: options.threadId, \n storage\n };\n\n if(!options.isGroupedItem && message.send) {\n setTimeout(() => {\n if(options.clearDraft) {\n appDraftsManager.clearDraft(peerId, options.threadId);\n }\n\n message.send();\n }, 0);\n }\n }\n\n private generateOutgoingMessage(peerId: PeerId, options: Partial<{\n scheduleDate: number,\n replyToMsgId: number,\n sendAsPeerId: PeerId, \n threadId: number,\n viaBotId: BotId,\n groupId: string,\n replyMarkup: ReplyMarkup,\n }>) {\n if(options.threadId && !options.replyToMsgId) {\n options.replyToMsgId = options.threadId;\n }\n\n let postAuthor: string;\n const isBroadcast = appPeersManager.isBroadcast(peerId);\n if(isBroadcast) {\n const chat = appPeersManager.getPeer(peerId) as Chat.channel;\n if(chat.pFlags.signatures) {\n const user = appUsersManager.getSelf();\n const fullName = user.first_name + (user.last_name ? ' ' + user.last_name : '');\n postAuthor = fullName;\n }\n }\n\n const message: Message.message = {\n _: 'message',\n id: this.generateTempMessageId(peerId),\n from_id: options.sendAsPeerId ? appPeersManager.getOutputPeer(options.sendAsPeerId) : this.generateFromId(peerId),\n peer_id: appPeersManager.getOutputPeer(peerId),\n post_author: postAuthor, \n pFlags: this.generateFlags(peerId),\n date: options.scheduleDate || (tsNow(true) + serverTimeManager.serverTimeOffset),\n message: '',\n grouped_id: options.groupId,\n random_id: randomLong(),\n reply_to: this.generateReplyHeader(options.replyToMsgId, options.threadId),\n via_bot_id: options.viaBotId,\n reply_markup: options.replyMarkup,\n replies: this.generateReplies(peerId),\n views: isBroadcast && 1,\n pending: true,\n promise: options.groupId === undefined ? deferredPromise() : undefined\n };\n\n return message;\n }\n\n private generateReplyHeader(replyToMsgId: number, replyToTopId?: number) {\n const header = {\n _: 'messageReplyHeader',\n reply_to_msg_id: replyToMsgId || replyToTopId,\n } as MessageReplyHeader;\n\n if(replyToTopId && header.reply_to_msg_id !== replyToTopId) {\n header.reply_to_top_id = replyToTopId;\n }\n\n return header;\n }\n\n private generateReplies(peerId: PeerId) {\n let replies: MessageReplies.messageReplies;\n if(appPeersManager.isBroadcast(peerId)) {\n const channelFull = appProfileManager.getCachedFullChat(peerId.toChatId()) as ChatFull.channelFull;\n if(channelFull?.linked_chat_id) {\n replies = {\n _: 'messageReplies',\n flags: 1,\n pFlags: {\n comments: true\n },\n channel_id: channelFull.linked_chat_id,\n replies: 0,\n replies_pts: 0\n };\n }\n }\n\n return replies;\n }\n\n /**\n * Generate correct from_id according to anonymous or broadcast\n */\n private generateFromId(peerId: PeerId) {\n if(peerId.isAnyChat() && (peerId.isBroadcast() || this.isAnonymousSending(peerId))) {\n return undefined;\n } else {\n return appPeersManager.getOutputPeer(appUsersManager.getSelf().id.toPeerId());\n }\n }\n\n private generateFlags(peerId: PeerId) {\n const pFlags: Message.message['pFlags'] = {};\n const fromId = appUsersManager.getSelf().id;\n if(peerId !== fromId) {\n pFlags.out = true;\n\n if(!appPeersManager.isChannel(peerId) && !appUsersManager.isBot(peerId)) {\n pFlags.unread = true;\n }\n }\n\n if(appPeersManager.isBroadcast(peerId)) {\n pFlags.post = true;\n }\n\n return pFlags;\n }\n\n private generateForwardHeader(peerId: PeerId, originalMessage: Message.message) {\n const myId = appUsersManager.getSelf().id.toPeerId();\n const fromId = originalMessage.fromId;\n if(fromId === myId && originalMessage.peerId === myId && !originalMessage.fwd_from) {\n return;\n }\n\n const fwdHeader: MessageFwdHeader.messageFwdHeader = {\n _: 'messageFwdHeader',\n flags: 0,\n date: originalMessage.date\n };\n\n let isUserHidden = false;\n if(originalMessage.fwd_from) {\n fwdHeader.from_id = originalMessage.fwd_from.from_id;\n fwdHeader.from_name = originalMessage.fwd_from.from_name;\n fwdHeader.post_author = originalMessage.fwd_from.post_author;\n } else {\n fwdHeader.post_author = originalMessage.post_author;\n \n if(fromId.isUser()) {\n const userFull = appProfileManager.getCachedFullUser(fromId.toUserId());\n if(userFull?.private_forward_name) {\n fwdHeader.from_name = userFull.private_forward_name;\n isUserHidden = true;\n }\n }\n\n if(!isUserHidden) {\n fwdHeader.from_id = appPeersManager.getOutputPeer(fromId);\n }\n }\n\n if(appPeersManager.isBroadcast(originalMessage.peerId)) {\n if(originalMessage.post_author) {\n fwdHeader.post_author = originalMessage.post_author;\n }\n\n fwdHeader.channel_post = originalMessage.id;\n }\n \n if(peerId === myId && !isUserHidden) {\n fwdHeader.saved_from_msg_id = originalMessage.id;\n fwdHeader.saved_from_peer = appPeersManager.getOutputPeer(originalMessage.peerId);\n }\n\n return fwdHeader;\n }\n\n public generateFakeAvatarMessage(peerId: PeerId, photo: Photo) {\n const maxId = Number.MAX_SAFE_INTEGER;\n const message: Message.messageService = {\n _: 'messageService',\n pFlags: {},\n action: {\n _: 'messageActionChannelEditPhoto',\n photo\n },\n id: maxId,\n peer_id: appPeersManager.getOutputPeer(peerId),\n mid: maxId,\n peerId,\n date: (photo as Photo.photo).date,\n fromId: peerId\n };\n\n this.getMessagesStorage(peerId).set(maxId, message);\n return message;\n }\n\n public isAnonymousSending(peerId: PeerId): boolean {\n return peerId.isAnyChat() && appPeersManager.getPeer(peerId).admin_rights?.pFlags?.anonymous;\n }\n\n public setDialogTopMessage(message: MyMessage, dialog: MTDialog.dialog = this.getDialogOnly(message.peerId)) {\n if(dialog) {\n dialog.top_message = message.mid;\n \n const historyStorage = this.getHistoryStorage(message.peerId);\n historyStorage.maxId = message.mid;\n\n this.dialogsStorage.generateIndexForDialog(dialog, false, message);\n\n this.scheduleHandleNewDialogs(message.peerId, dialog);\n }\n }\n\n public cancelPendingMessage(randomId: string) {\n const pendingData = this.pendingByRandomId[randomId];\n\n /* if(DEBUG) {\n this.log('cancelPendingMessage', randomId, pendingData);\n } */\n\n if(pendingData) {\n const {peerId, tempId, storage} = pendingData;\n const historyStorage = this.getHistoryStorage(peerId);\n\n apiUpdatesManager.processLocalUpdate({\n _: 'updateDeleteMessages',\n messages: [tempId],\n pts: undefined,\n pts_count: undefined\n });\n\n historyStorage.history.delete(tempId);\n\n delete this.pendingByRandomId[randomId];\n storage.delete(tempId);\n\n return true;\n }\n\n return false;\n }\n\n /* public async refreshConversations() {\n const limit = 200, outDialogs: Dialog[] = [];\n for(let folderId = 0; folderId < 2; ++folderId) {\n let offsetDate = 0;\n for(;;) {\n const {dialogs, isEnd} = await this.getTopMessages(limit, folderId, offsetDate);\n \n if(dialogs.length) {\n outDialogs.push(...dialogs as Dialog[]);\n const dialog = dialogs[dialogs.length - 1];\n\n // * get peerId and mid manually, because dialog can be migrated peer and it won't be saved\n const peerId = appPeersManager.getPeerId(dialog.peer);\n const mid = appMessagesIdsManager.generateMessageId(dialog.top_message);\n offsetDate = this.getMessageByPeer(peerId, mid).date;\n\n if(!offsetDate) {\n console.error('refreshConversations: got no offsetDate', dialog);\n break;\n }\n }\n \n if(isEnd) {\n break;\n }\n }\n }\n\n let obj: {[peerId: string]: Dialog} = {};\n outDialogs.forEach(dialog => {\n obj[dialog.peerId] = dialog;\n });\n rootScope.dispatchEvent('dialogs_multiupdate', obj);\n\n return outDialogs;\n } */\n\n public async fillConversations(): Promise<void> {\n const middleware = this.middleware.get();\n while(!this.dialogsStorage.isDialogsLoaded(GLOBAL_FOLDER_ID)) {\n const result = await this.getTopMessages(100, GLOBAL_FOLDER_ID);\n if(!middleware() || result.isEnd) {\n break;\n }\n }\n }\n\n /* public async getConversationsAll(query = '', folderId = 0) {\n const limit = 200, outDialogs: Dialog[] = [];\n for(; folderId < 2; ++folderId) {\n let offsetIndex = 0;\n for(;;) {\n const {dialogs} = await appMessagesManager.getConversations(query, offsetIndex, limit, folderId).promise;\n \n if(dialogs.length) {\n outDialogs.push(...dialogs);\n offsetIndex = dialogs[dialogs.length - 1].index || 0;\n } else {\n break;\n }\n }\n }\n\n return outDialogs;\n } */\n\n public getConversations(query = '', offsetIndex?: number, limit?: number, folderId = 0, skipMigrated?: boolean) {\n return this.dialogsStorage.getDialogs(query, offsetIndex, limit, folderId, skipMigrated);\n }\n\n public getReadMaxIdIfUnread(peerId: PeerId, threadId?: number) {\n const historyStorage = this.getHistoryStorage(peerId, threadId);\n if(threadId) {\n const chatHistoryStorage = this.getHistoryStorage(peerId);\n const readMaxId = Math.max(chatHistoryStorage.readMaxId ?? 0, historyStorage.readMaxId);\n const message = this.getMessageByPeer(peerId, historyStorage.maxId); // usually message is missing, so pFlags.out won't be there anyway\n return !message.pFlags.out && readMaxId < historyStorage.maxId ? readMaxId : 0;\n } else {\n const message = this.getMessageByPeer(peerId, historyStorage.maxId);\n const readMaxId = peerId.isUser() ? Math.max(historyStorage.readMaxId, historyStorage.readOutboxMaxId) : historyStorage.readMaxId;\n return !message.pFlags.out && readMaxId < historyStorage.maxId ? readMaxId : 0;\n }\n }\n\n // public lolSet = new Set();\n public getTopMessages(limit: number, folderId: number, offsetDate?: number) {\n //const dialogs = this.dialogsStorage.getFolder(folderId);\n let offsetId = 0;\n let offsetPeerId: PeerId;\n let offsetIndex = 0;\n\n if(offsetDate === undefined) {\n offsetDate = this.dialogsStorage.getOffsetDate(folderId);\n }\n\n if(offsetDate) {\n offsetIndex = offsetDate * 0x10000;\n offsetDate += serverTimeManager.serverTimeOffset;\n }\n\n const useLimit = 100;\n const middleware = this.middleware.get();\n\n // ! ВНИМАНИЕ: ОЧЕНЬ СЛОЖНАЯ ЛОГИКА:\n // ! если делать запрос сначала по папке 0, потом по папке 1, по индексу 0 в массиве будет один и тот же диалог, с dialog.pFlags.pinned, ЛОЛ???\n // ! т.е., с запросом folder_id: 1, и exclude_pinned: 0, в результате будут ещё и закреплённые с папки 0\n const params: MessagesGetDialogs = {\n folder_id: folderId,\n offset_date: offsetDate,\n offset_id: offsetId,\n offset_peer: appPeersManager.getInputPeerById(offsetPeerId),\n limit: useLimit,\n hash: '0'\n };\n\n return apiManager.invokeApiSingle('messages.getDialogs', params, {\n //timeout: APITIMEOUT,\n noErrorBox: true\n }).then((dialogsResult) => {\n if(!middleware() || dialogsResult._ === 'messages.dialogsNotModified') return null;\n\n if(DEBUG) {\n this.log('messages.getDialogs result:', dialogsResult.dialogs, {...dialogsResult.dialogs[0]});\n }\n\n /* if(!offsetDate) {\n telegramMeWebService.setAuthorized(true);\n } */\n\n // can reset pinned order here\n if(!offsetId && !offsetDate && !offsetPeerId && folderId !== GLOBAL_FOLDER_ID) {\n this.dialogsStorage.resetPinnedOrder(folderId);\n }\n\n if(!offsetDate) {\n telegramMeWebManager.setAuthorized(true);\n }\n\n appUsersManager.saveApiUsers(dialogsResult.users);\n appChatsManager.saveApiChats(dialogsResult.chats);\n this.saveMessages(dialogsResult.messages);\n\n /* if(folderId === 0 && !offsetDate) {\n const found = dialogsResult.dialogs.find(dialog => appPeersManager.getPeerId(dialog.peer) === -1325963535);\n if(!found) {\n debugger;\n }\n } */\n\n let maxSeenIdIncremented = offsetDate ? true : false;\n let hasPrepend = false;\n const noIdsDialogs: {[peerId: PeerId]: Dialog} = {};\n const setFolderId = folderId === GLOBAL_FOLDER_ID ? 0 : folderId;\n const saveGlobalOffset = folderId === GLOBAL_FOLDER_ID;\n forEachReverse((dialogsResult.dialogs as Dialog[]), dialog => {\n //const d = Object.assign({}, dialog);\n // ! нужно передавать folderId, так как по папке !== 0 нет свойства folder_id\n if(dialog.folder_id === undefined) {\n dialog.folder_id = setFolderId;\n }\n\n this.dialogsStorage.saveDialog(dialog, undefined, true, saveGlobalOffset);\n\n if(!maxSeenIdIncremented &&\n !appPeersManager.isChannel(dialog.peerId || appPeersManager.getPeerId(dialog.peer))) {\n this.incrementMaxSeenId(dialog.top_message);\n maxSeenIdIncremented = true;\n }\n\n if(dialog.peerId === undefined) {\n return;\n }\n\n // if(!folderId && !dialog.folder_id) {\n // this.lolSet.add(dialog.peerId);\n // }\n\n /* if(dialog.peerId === -1213511294) {\n this.log.error('lun bot', folderId, d);\n } */\n\n if(offsetIndex && dialog.index > offsetIndex) {\n this.scheduleHandleNewDialogs(dialog.peerId, dialog);\n hasPrepend = true;\n }\n\n // ! это может случиться, если запрос идёт не по папке 0, а по 1. почему-то read'ов нет\n // ! в итоге, чтобы получить 1 диалог, делается первый запрос по папке 0, потом запрос для архивных по папке 1, и потом ещё перезагрузка архивного диалога\n if(!appMessagesIdsManager.getServerMessageId(dialog.read_inbox_max_id) && !appMessagesIdsManager.getServerMessageId(dialog.read_outbox_max_id)) {\n noIdsDialogs[dialog.peerId] = dialog;\n\n this.log.error('noIdsDialogs', dialog, params);\n\n /* if(dialog.peerId === -1213511294) {\n this.log.error('lun bot', folderId);\n } */\n }\n });\n\n const keys = Object.keys(noIdsDialogs);\n if(keys.length) {\n //setTimeout(() => { // test bad situation\n const peerIds = keys.map(key => key.toPeerId());\n const promises = peerIds.map(peerId => this.reloadConversation(peerId));\n Promise.all(promises).then(() => {\n rootScope.dispatchEvent('dialogs_multiupdate', noIdsDialogs);\n \n for(let i = 0; i < peerIds.length; ++i) {\n rootScope.dispatchEvent('dialog_unread', {peerId: peerIds[i]});\n }\n });\n //}, 10e3);\n }\n\n const count = (dialogsResult as MessagesDialogs.messagesDialogsSlice).count;\n\n // exclude empty draft dialogs\n const folderDialogs = this.dialogsStorage.getFolderDialogs(folderId, false);\n let dialogsLength = 0;\n for(let i = 0, length = folderDialogs.length; i < length; ++i) {\n if(appMessagesIdsManager.getServerMessageId(folderDialogs[i].top_message)) {\n ++dialogsLength;\n }\n }\n\n const isEnd = /* limit > dialogsResult.dialogs.length || */ \n !count || \n dialogsLength >= count ||\n !dialogsResult.dialogs.length;\n if(isEnd) {\n this.dialogsStorage.setDialogsLoaded(folderId, true);\n }\n\n if(hasPrepend) {\n this.scheduleHandleNewDialogs();\n } else {\n rootScope.dispatchEvent('dialogs_multiupdate', {});\n }\n\n const dialogs = (dialogsResult as MessagesDialogs.messagesDialogsSlice).dialogs;\n const slicedDialogs = limit === useLimit ? dialogs : dialogs.slice(0, limit);\n return {\n isEnd: isEnd && slicedDialogs[slicedDialogs.length - 1] === dialogs[dialogs.length - 1], \n count, \n dialogs: slicedDialogs\n };\n });\n }\n\n public forwardMessages(peerId: PeerId, fromPeerId: PeerId, mids: number[], options: Partial<{\n withMyScore: true,\n silent: true,\n scheduleDate: number,\n dropAuthor: boolean,\n dropCaptions: boolean,\n sendAsPeerId: PeerId,\n }> = {}) {\n peerId = appPeersManager.getPeerMigratedTo(peerId) || peerId;\n mids = mids.slice().sort((a, b) => a - b);\n\n for(let i = 0, length = mids.length; i < length; ++i) {\n const mid = mids[i];\n const originalMessage: Message.message = this.getMessageByPeer(fromPeerId, mid);\n if(originalMessage.pFlags.is_outgoing) { // this can happen when forwarding a changelog\n this.sendText(peerId, originalMessage.message, {\n entities: originalMessage.entities,\n scheduleDate: options.scheduleDate,\n silent: options.silent\n });\n\n mids.splice(i--, 1);\n }\n }\n\n if(!mids.length) {\n return Promise.resolve();\n }\n\n if(options.dropCaptions) {\n options.dropAuthor = true;\n }\n\n const groups: {\n [groupId: string]: {\n tempId: string,\n messages: Message.message[]\n }\n } = {};\n\n const newMessages = mids.map(mid => {\n const originalMessage: Message.message = this.getMessageByPeer(fromPeerId, mid);\n const message: Message.message = this.generateOutgoingMessage(peerId, options);\n\n const keys: Array<keyof Message.message> = [\n 'entities', \n 'media', \n // 'reply_markup'\n ];\n\n if(!options.dropAuthor) {\n message.fwd_from = this.generateForwardHeader(peerId, originalMessage);\n keys.push('views', 'forwards');\n\n if(message.fwd_from?.from_name && peerId === rootScope.myId) {\n delete message.from_id;\n }\n }\n\n if(!options.dropCaptions || !originalMessage.media) {\n keys.push('message');\n }\n\n keys.forEach(key => {\n // @ts-ignore\n message[key] = originalMessage[key];\n });\n\n const document = (message.media as MessageMedia.messageMediaDocument)?.document as MyDocument;\n if(document) {\n const types: MyDocument['type'][] = ['round', 'voice'];\n if(types.includes(document.type)) {\n (message as MyMessage).pFlags.media_unread = true;\n }\n }\n\n if(originalMessage.grouped_id) {\n const group = groups[originalMessage.grouped_id] ?? (groups[originalMessage.grouped_id] = {tempId: '' + ++this.groupedTempId, messages: []});\n group.messages.push(message);\n }\n\n return message;\n });\n\n for(const groupId in groups) {\n const group = groups[groupId];\n if(group.messages.length > 1) {\n group.messages.forEach(message => {\n message.grouped_id = group.tempId;\n });\n }\n }\n\n newMessages.forEach(message => {\n this.beforeMessageSending(message, {\n isScheduled: !!options.scheduleDate || undefined\n });\n });\n\n const sentRequestOptions: PendingAfterMsg = {};\n if(this.pendingAfterMsgs[peerId]) {\n sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;\n }\n\n const promise = /* true ? Promise.resolve() : */apiManager.invokeApiAfter('messages.forwardMessages', {\n from_peer: appPeersManager.getInputPeerById(fromPeerId),\n id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid)),\n random_id: newMessages.map(message => message.random_id),\n to_peer: appPeersManager.getInputPeerById(peerId),\n with_my_score: options.withMyScore,\n silent: options.silent,\n schedule_date: options.scheduleDate,\n drop_author: options.dropAuthor,\n drop_media_captions: options.dropCaptions,\n send_as: options.sendAsPeerId ? appPeersManager.getInputPeerById(options.sendAsPeerId) : undefined\n }, sentRequestOptions).then((updates) => {\n this.log('forwardMessages updates:', updates);\n apiUpdatesManager.processUpdateMessage(updates);\n }).finally(() => {\n if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {\n delete this.pendingAfterMsgs[peerId];\n }\n });\n\n this.pendingAfterMsgs[peerId] = sentRequestOptions;\n return promise;\n }\n\n public generateEmptyMessage(mid: number): Message.messageEmpty {\n return {\n _: 'messageEmpty',\n id: appMessagesIdsManager.getServerMessageId(mid),\n mid,\n deleted: true,\n pFlags: {}\n };\n }\n\n public getMessageFromStorage(storage: MessagesStorage, mid: number) {\n return storage && storage.get(mid) || this.generateEmptyMessage(mid);\n }\n\n private createMessageStorage() {\n const storage: MessagesStorage = new Map();\n \n /* let num = 0;\n Object.defineProperty(storage, 'num', {\n get: () => ++num,\n set: (_num: number) => num = _num, \n enumerable: false\n });\n\n Object.defineProperty(storage, 'generateIndex', {\n value: (message: any) => {\n if(message.index === undefined) {\n message.index = (message.date * 0x10000) + (storage.num & 0xFFFF);\n }\n },\n enumerable: false\n }); */\n\n return storage;\n }\n\n public getMessagesStorage(peerId: PeerId) {\n return this.messagesStorageByPeerId[peerId] ?? (this.messagesStorageByPeerId[peerId] = this.createMessageStorage());\n }\n\n public getMessageById(messageId: number) {\n for(const peerId in this.messagesStorageByPeerId) {\n if(appPeersManager.isChannel(peerId.toPeerId())) {\n continue;\n }\n\n const message = this.messagesStorageByPeerId[peerId].get(messageId);\n if(message) {\n return message;\n }\n }\n\n return this.getMessageFromStorage(null, messageId);\n }\n\n public getMessageByPeer(peerId: PeerId, messageId: number) {\n if(!peerId) {\n return this.getMessageById(messageId);\n }\n\n return this.getMessageFromStorage(this.getMessagesStorage(peerId), messageId);\n }\n\n public getMessagePeer(message: any): PeerId {\n const toId = message.peer_id && appPeersManager.getPeerId(message.peer_id) || NULL_PEER_ID;\n\n return toId;\n }\n\n public getDialogByPeerId(peerId: PeerId): [Dialog, number] | [] {\n return this.dialogsStorage.getDialog(peerId);\n }\n\n public getDialogOnly(peerId: PeerId) {\n return this.dialogsStorage.getDialogOnly(peerId);\n }\n\n public reloadConversation(inputPeer?: PeerId | InputPeer): CancellablePromise<Dialog>;\n public reloadConversation(inputPeer: PeerId | InputPeer) {\n let promise: CancellablePromise<Dialog>;\n if(inputPeer !== undefined) {\n const peerId = appPeersManager.getPeerId(inputPeer);\n let obj = this.reloadConversationsPeers.get(peerId);\n if(obj) {\n promise = obj.promise;\n }\n\n if(promise) {\n return promise;\n }\n\n promise = deferredPromise();\n this.reloadConversationsPeers.set(peerId, obj = {\n inputDialogPeer: appPeersManager.getInputDialogPeerById(inputPeer),\n promise\n });\n }\n\n if(this.reloadConversationsPromise) {\n return promise || this.reloadConversationsPromise;\n }\n\n this.reloadConversationsPromise = new Promise((resolve, reject) => {\n setTimeout(() => {\n const inputDialogPeers: InputDialogPeer[] = [];\n const promises: {[peerId: string]: typeof promise} = {};\n for(const [peerId, {inputDialogPeer, promise}] of this.reloadConversationsPeers) {\n inputDialogPeers.push(inputDialogPeer);\n promises[peerId] = promise;\n }\n\n this.reloadConversationsPeers.clear();\n\n const fullfillLeft = () => {\n for(const peerId in promises) {\n promises[peerId].resolve(undefined);\n }\n };\n\n apiManager.invokeApi('messages.getPeerDialogs', {peers: inputDialogPeers}).then((result) => {\n this.dialogsStorage.applyDialogs(result);\n\n result.dialogs.forEach((dialog) => {\n const peerId = dialog.peerId;\n if(peerId) {\n promises[peerId].resolve(dialog as Dialog);\n delete promises[peerId];\n }\n });\n\n fullfillLeft();\n resolve();\n }, (err) => {\n fullfillLeft();\n reject(err);\n }).finally(() => {\n this.reloadConversationsPromise = null;\n\n if(this.reloadConversationsPeers.size) {\n this.reloadConversation();\n }\n });\n }, 0);\n });\n\n return promise || this.reloadConversationsPromise;\n }\n\n private doFlushHistory(peer: InputPeer, just_clear?: boolean, revoke?: boolean): Promise<true> {\n return apiManager.invokeApiSingle('messages.deleteHistory', {\n just_clear,\n revoke,\n peer,\n max_id: 0\n }).then((affectedHistory) => {\n apiUpdatesManager.processUpdateMessage({\n _: 'updateShort',\n update: {\n _: 'updatePts',\n pts: affectedHistory.pts,\n pts_count: affectedHistory.pts_count\n }\n });\n\n if(!affectedHistory.offset) {\n return true;\n }\n\n return this.doFlushHistory(peer, just_clear, revoke);\n });\n }\n\n public async flushHistory(peerId: PeerId, justClear?: boolean, revoke?: boolean) {\n if(appPeersManager.isChannel(peerId)) {\n const promise = this.getHistory(peerId, 0, 1);\n\n const historyResult = promise instanceof Promise ? await promise : promise;\n\n const channelId = peerId.toChatId();\n const maxId = historyResult.history[0] || 0;\n return apiManager.invokeApiSingle('channels.deleteHistory', {\n channel: appChatsManager.getChannelInput(channelId),\n max_id: appMessagesIdsManager.getServerMessageId(maxId)\n }).then((bool) => {\n if(bool) {\n apiUpdatesManager.processLocalUpdate({\n _: 'updateChannelAvailableMessages',\n channel_id: channelId,\n available_min_id: maxId\n });\n }\n\n return bool;\n });\n }\n\n return this.doFlushHistory(appPeersManager.getInputPeerById(peerId), justClear, revoke).then(() => {\n [\n this.historiesStorage, \n this.threadsStorage, \n this.searchesStorage, \n this.pinnedMessages,\n this.pendingAfterMsgs,\n this.pendingTopMsgs\n ].forEach(s => {\n delete s[peerId];\n });\n\n const m = this.needSingleMessages.get(peerId);\n if(m) {\n m.clear();\n }\n\n [\n this.messagesStorageByPeerId,\n this.scheduledMessagesStorage\n ].forEach(s => {\n const ss = s[peerId];\n if(ss) {\n ss.clear();\n }\n });\n \n if(justClear) {\n rootScope.dispatchEvent('dialog_flush', {peerId});\n } else {\n delete this.notificationsToHandle[peerId];\n delete this.typings[peerId];\n \n const c = this.reloadConversationsPeers.get(peerId);\n if(c) {\n this.reloadConversationsPeers.delete(peerId);\n c.promise.resolve(undefined);\n }\n\n this.dialogsStorage.dropDialogOnDeletion(peerId);\n }\n });\n }\n\n public onPeerDeleted(peerId: number) {\n\n }\n\n public hidePinnedMessages(peerId: PeerId) {\n return Promise.all([\n appStateManager.getState(),\n this.getPinnedMessage(peerId)\n ])\n .then(([state, pinned]) => {\n state.hiddenPinnedMessages[peerId] = pinned.maxId;\n rootScope.dispatchEvent('peer_pinned_hidden', {peerId, maxId: pinned.maxId});\n });\n }\n\n public getPinnedMessage(peerId: PeerId) {\n const p = this.pinnedMessages[peerId] ?? (this.pinnedMessages[peerId] = {});\n if(p.promise) return p.promise;\n else if(p.maxId) return Promise.resolve(p);\n\n return p.promise = this.getSearch({\n peerId, \n inputFilter: {_: 'inputMessagesFilterPinned'},\n maxId: 0,\n limit: 1\n }).then(result => {\n p.count = result.count;\n p.maxId = result.history[0]?.mid;\n return p;\n }).finally(() => {\n delete p.promise;\n });\n }\n\n public updatePinnedMessage(peerId: PeerId, mid: number, unpin?: boolean, silent?: boolean, pm_oneside?: boolean) {\n return apiManager.invokeApi('messages.updatePinnedMessage', {\n peer: appPeersManager.getInputPeerById(peerId),\n unpin,\n silent,\n pm_oneside,\n id: appMessagesIdsManager.getServerMessageId(mid)\n }).then(updates => {\n //this.log('pinned updates:', updates);\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public unpinAllMessages(peerId: PeerId): Promise<boolean> {\n return apiManager.invokeApiSingle('messages.unpinAllMessages', {\n peer: appPeersManager.getInputPeerById(peerId)\n }).then(affectedHistory => {\n apiUpdatesManager.processUpdateMessage({\n _: 'updateShort',\n update: {\n _: 'updatePts',\n pts: affectedHistory.pts,\n pts_count: affectedHistory.pts_count\n }\n });\n\n if(!affectedHistory.offset) {\n const storage = this.getMessagesStorage(peerId);\n storage.forEach((message) => {\n if(message.pFlags.pinned) {\n delete message.pFlags.pinned;\n }\n });\n\n rootScope.dispatchEvent('peer_pinned_messages', {peerId, unpinAll: true});\n delete this.pinnedMessages[peerId];\n\n return true;\n }\n\n return this.unpinAllMessages(peerId);\n });\n }\n\n public getAlbumText(grouped_id: string) {\n const group = this.groupedMessagesStorage[grouped_id];\n let foundMessages = 0, message: string, totalEntities: MessageEntity[], entities: MessageEntity[];\n for(const [mid, m] of group) {\n if(m.message) {\n if(++foundMessages > 1) break;\n message = m.message;\n totalEntities = m.totalEntities;\n entities = m.entities;\n }\n }\n\n if(foundMessages > 1) {\n message = undefined;\n totalEntities = undefined;\n entities = undefined;\n }\n\n return {message, entities, totalEntities};\n }\n\n public getGroupsFirstMessage(message: Message.message): Message.message {\n if(!message.grouped_id) return message;\n\n const storage = this.groupedMessagesStorage[message.grouped_id];\n let minMid = Number.MAX_SAFE_INTEGER;\n for(const [mid, message] of storage) {\n if(message.mid < minMid) {\n minMid = message.mid;\n }\n }\n\n return storage.get(minMid);\n }\n\n public getMidsByAlbum(grouped_id: string) {\n return getObjectKeysAndSort(this.groupedMessagesStorage[grouped_id], 'asc');\n //return Object.keys(this.groupedMessagesStorage[grouped_id]).map(id => +id).sort((a, b) => a - b);\n }\n\n public getMidsByMessage(message: Message) {\n if((message as Message.message)?.grouped_id) return this.getMidsByAlbum((message as Message.message).grouped_id);\n else return [message.mid];\n }\n\n public filterMessages(message: MyMessage, verify: (message: MyMessage) => boolean) {\n const out: MyMessage[] = [];\n if((message as Message.message).grouped_id) {\n const storage = this.groupedMessagesStorage[(message as Message.message).grouped_id];\n for(const [mid, message] of storage) {\n if(verify(message)) {\n out.push(message);\n }\n }\n } else {\n if(verify(message)) {\n out.push(message);\n }\n }\n\n return out;\n }\n\n public generateTempMessageId(peerId: PeerId) {\n const dialog = this.getDialogOnly(peerId);\n return appMessagesIdsManager.generateMessageId(dialog?.top_message || 0, true);\n }\n\n public saveMessage(message: Message, options: Partial<{\n storage: MessagesStorage,\n isScheduled: true,\n isOutgoing: true,\n //isNew: boolean, // * new - from update\n }> = {}) {\n if(message.pFlags === undefined) {\n message.pFlags = {};\n }\n\n if(message._ === 'messageEmpty') {\n message.deleted = true;\n return;\n }\n\n // * exclude from state\n // defineNotNumerableProperties(message, ['rReply', 'mid', 'savedFrom', 'fwdFromId', 'fromId', 'peerId', 'reply_to_mid', 'viaBotId']);\n\n const peerId = this.getMessagePeer(message);\n const storage = options.storage || this.getMessagesStorage(peerId);\n const isChannel = message.peer_id._ === 'peerChannel';\n const isBroadcast = isChannel && appChatsManager.isBroadcast(peerId.toChatId());\n const isMessage = message._ === 'message';\n\n if(options.isOutgoing) {\n message.pFlags.is_outgoing = true;\n }\n \n const mid = appMessagesIdsManager.generateMessageId(message.id);\n message.mid = mid;\n\n if(isMessage) {\n if(options.isScheduled) {\n message.pFlags.is_scheduled = true;\n }\n\n if(message.grouped_id) {\n const storage = this.groupedMessagesStorage[message.grouped_id] ?? (this.groupedMessagesStorage[message.grouped_id] = new Map());\n storage.set(mid, message);\n }\n\n if(message.via_bot_id) {\n // ! WARNING\n message.viaBotId = message.via_bot_id as any;\n }\n }\n\n const dialog = this.getDialogOnly(peerId);\n if(dialog && mid) {\n if(mid > dialog[message.pFlags.out\n ? 'read_outbox_max_id'\n : 'read_inbox_max_id']) {\n message.pFlags.unread = true;\n }\n }\n // this.log(dT(), 'msg unread', mid, apiMessage.pFlags.out, dialog && dialog[apiMessage.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id'])\n\n if(message.reply_to) {\n if(message.reply_to.reply_to_msg_id) {\n message.reply_to.reply_to_msg_id = message.reply_to_mid = appMessagesIdsManager.generateMessageId(message.reply_to.reply_to_msg_id);\n } \n\n if(message.reply_to.reply_to_top_id) message.reply_to.reply_to_top_id = appMessagesIdsManager.generateMessageId(message.reply_to.reply_to_top_id);\n }\n\n if(isMessage && message.replies) {\n if(message.replies.max_id) message.replies.max_id = appMessagesIdsManager.generateMessageId(message.replies.max_id);\n if(message.replies.read_max_id) message.replies.read_max_id = appMessagesIdsManager.generateMessageId(message.replies.read_max_id);\n }\n\n const overwriting = !!peerId;\n if(!overwriting) {\n message.date -= serverTimeManager.serverTimeOffset;\n }\n \n //storage.generateIndex(message);\n const myId = appUsersManager.getSelf().id.toPeerId();\n\n const fwdHeader = isMessage && (message as Message.message).fwd_from as MessageFwdHeader;\n\n message.peerId = peerId;\n if(peerId === myId/* && !message.from_id && !message.fwd_from */) {\n message.fromId = fwdHeader ? (fwdHeader.from_id ? appPeersManager.getPeerId(fwdHeader.from_id) : NULL_PEER_ID) : myId;\n } else {\n //message.fromId = message.pFlags.post || (!message.pFlags.out && !message.from_id) ? peerId : appPeersManager.getPeerId(message.from_id);\n message.fromId = message.pFlags.post || !message.from_id ? peerId : appPeersManager.getPeerId(message.from_id);\n }\n\n if(fwdHeader) {\n //if(peerId === myID) {\n if(fwdHeader.saved_from_msg_id) fwdHeader.saved_from_msg_id = appMessagesIdsManager.generateMessageId(fwdHeader.saved_from_msg_id);\n if(fwdHeader.channel_post) fwdHeader.channel_post = appMessagesIdsManager.generateMessageId(fwdHeader.channel_post);\n\n const peer = fwdHeader.saved_from_peer || fwdHeader.from_id;\n const msgId = fwdHeader.saved_from_msg_id || fwdHeader.channel_post;\n if(peer && msgId) {\n const savedFromPeerId = appPeersManager.getPeerId(peer);\n const savedFromMid = appMessagesIdsManager.generateMessageId(msgId);\n message.savedFrom = savedFromPeerId + '_' + savedFromMid;\n }\n\n /* if(peerId.isAnyChat() || peerId === myID) {\n message.fromId = appPeersManager.getPeerID(!message.from_id || deepEqual(message.from_id, fwdHeader.from_id) ? fwdHeader.from_id : message.from_id);\n } */\n /* } else {\n apiMessage.fwdPostID = fwdHeader.channel_post;\n } */\n\n message.fwdFromId = appPeersManager.getPeerId(fwdHeader.from_id);\n\n if(!overwriting) {\n fwdHeader.date -= serverTimeManager.serverTimeOffset;\n }\n }\n\n const mediaContext: ReferenceContext = {\n type: 'message',\n peerId,\n messageId: mid\n };\n\n /* if(isMessage) {\n const entities = message.entities;\n if(entities && entities.find(entity => entity._ === 'messageEntitySpoiler')) {\n message.media = {_: 'messageMediaUnsupported'};\n }\n } */\n\n if(isMessage && message.media) {\n let unsupported = false;\n switch(message.media._) {\n case 'messageMediaEmpty': {\n delete message.media;\n break;\n }\n\n case 'messageMediaPhoto': {\n if(message.media.ttl_seconds) {\n unsupported = true;\n } else {\n message.media.photo = appPhotosManager.savePhoto(message.media.photo, mediaContext);\n }\n\n if(!(message.media as MessageMedia.messageMediaPhoto).photo) { // * found this bug on test DC\n delete message.media;\n }\n \n break;\n }\n \n case 'messageMediaPoll': {\n const result = appPollsManager.savePoll(message.media.poll, message.media.results, message);\n message.media.poll = result.poll;\n message.media.results = result.results;\n break;\n }\n \n case 'messageMediaDocument': {\n if(message.media.ttl_seconds) {\n unsupported = true;\n } else {\n const originalDoc = message.media.document;\n message.media.document = appDocsManager.saveDoc(originalDoc, mediaContext); // 11.04.2020 warning\n\n if(!message.media.document && originalDoc._ !== 'documentEmpty') {\n unsupported = true;\n }\n }\n\n break;\n }\n \n case 'messageMediaWebPage': {\n const messageKey = appWebPagesManager.getMessageKeyForPendingWebPage(peerId, mid, options.isScheduled);\n message.media.webpage = appWebPagesManager.saveWebPage(message.media.webpage, messageKey, mediaContext);\n break;\n }\n \n /*case 'messageMediaGame':\n AppGamesManager.saveGame(apiMessage.media.game, apiMessage.mid, mediaContext);\n apiMessage.media.handleMessage = true;\n break; */\n\n case 'messageMediaInvoice': {\n unsupported = true;\n message.media = {_: 'messageMediaUnsupported'};\n break;\n }\n\n case 'messageMediaUnsupported': {\n unsupported = true;\n break;\n }\n }\n\n if(unsupported) {\n message.media = {_: 'messageMediaUnsupported'};\n message.message = '';\n delete message.entities;\n delete message.totalEntities;\n }\n }\n\n if(!isMessage && message.action) {\n const action = message.action as MessageAction;\n let migrateFrom: PeerId;\n let migrateTo: PeerId;\n const suffix = message.fromId === appUsersManager.getSelf().id ? 'You' : '';\n\n if((action as MessageAction.messageActionChatEditPhoto).photo) {\n (action as MessageAction.messageActionChatEditPhoto).photo = appPhotosManager.savePhoto((action as MessageAction.messageActionChatEditPhoto).photo, mediaContext);\n }\n\n if((action as any).document) {\n (action as any).document = appDocsManager.saveDoc((action as any).photo, mediaContext);\n }\n\n switch(action._) {\n //case 'messageActionChannelEditPhoto':\n case 'messageActionChatEditPhoto':\n // action.photo = appPhotosManager.savePhoto(action.photo, mediaContext);\n if((action.photo as Photo.photo)?.video_sizes) {\n // @ts-ignore\n action._ = isBroadcast ? 'messageActionChannelEditVideo' : 'messageActionChatEditVideo';\n } else {\n if(isBroadcast) { // ! messageActionChannelEditPhoto не существует в принципе, это используется для перевода.\n // @ts-ignore\n action._ = 'messageActionChannelEditPhoto';\n }\n }\n break;\n \n case 'messageActionGroupCall': {\n //assumeType<MessageAction.messageActionGroupCall>(action);\n\n appGroupCallsManager.saveGroupCall(action.call);\n\n let type: string;\n if(action.duration === undefined) {\n type = 'started';\n } else {\n type = 'ended'\n }\n\n if(!isBroadcast) {\n type += '_by' + suffix;\n }\n\n // @ts-ignore\n action.type = type;\n\n break;\n }\n\n case 'messageActionChatEditTitle':\n /* if(options.isNew) {\n const chat = appChatsManager.getChat(peerId.toChatId());\n chat.title = action.title;\n appChatsManager.saveApiChat(chat, true);\n } */\n \n if(isBroadcast) {\n // @ts-ignore\n action._ = 'messageActionChannelEditTitle';\n }\n break;\n\n case 'messageActionChatDeletePhoto':\n if(isBroadcast) {\n // @ts-ignore\n action._ = 'messageActionChannelDeletePhoto';\n }\n break;\n\n case 'messageActionChatAddUser':\n if(action.users.length === 1) {\n // @ts-ignore\n action.user_id = action.users[0];\n // @ts-ignore\n if(message.fromId === action.user_id) {\n if(isChannel) {\n // @ts-ignore\n action._ = 'messageActionChatJoined' + suffix;\n } else {\n // @ts-ignore\n action._ = 'messageActionChatReturn' + suffix;\n }\n }\n } else if(action.users.length > 1) {\n // @ts-ignore\n action._ = 'messageActionChatAddUsers';\n }\n break;\n\n case 'messageActionChatDeleteUser':\n if(message.fromId === action.user_id) {\n // @ts-ignore\n action._ = 'messageActionChatLeave' + suffix;\n }\n break;\n\n case 'messageActionChannelMigrateFrom':\n migrateFrom = action.chat_id.toPeerId(true);\n migrateTo = peerId;\n break\n\n case 'messageActionChatMigrateTo':\n migrateFrom = peerId;\n migrateTo = action.channel_id.toPeerId(true);\n break;\n\n case 'messageActionHistoryClear':\n //apiMessage.deleted = true;\n message.clear_history = true;\n delete message.pFlags.out;\n delete message.pFlags.unread;\n break;\n\n case 'messageActionPhoneCall':\n // @ts-ignore\n action.type = \n (action.pFlags.video ? 'video_' : '') +\n (action.duration !== undefined ? (message.pFlags.out ? 'out_' : 'in_') : '') +\n (\n action.duration !== undefined ? 'ok' : (\n action.reason._ === 'phoneCallDiscardReasonMissed'\n ? 'missed'\n : 'cancelled'\n )\n );\n break;\n }\n \n if(migrateFrom &&\n migrateTo &&\n !this.migratedFromTo[migrateFrom] &&\n !this.migratedToFrom[migrateTo]) {\n this.migrateChecks(migrateFrom, migrateTo);\n }\n }\n\n /* if(message.grouped_id) {\n if(!groups) {\n groups = new Set();\n }\n\n groups.add(message.grouped_id);\n } else {\n message.rReply = this.getRichReplyText(message);\n } */\n\n if(isMessage && message.message.length && !message.totalEntities) {\n this.wrapMessageEntities(message); \n }\n\n storage.set(mid, message);\n }\n\n public saveMessages(messages: any[], options: Partial<{\n storage: MessagesStorage,\n isScheduled: true,\n isOutgoing: true,\n //isNew: boolean, // * new - from update\n }> = {}) {\n if((messages as any).saved) return;\n (messages as any).saved = true;\n messages.forEach((message) => {\n this.saveMessage(message, options);\n });\n }\n\n private wrapMessageEntities(message: Message.message) {\n const apiEntities = message.entities ? message.entities.slice() : [];\n message.message = RichTextProcessor.fixEmoji(message.message, apiEntities);\n\n const myEntities = RichTextProcessor.parseEntities(message.message);\n message.totalEntities = RichTextProcessor.mergeEntities(apiEntities, myEntities); // ! only in this order, otherwise bold and emoji formatting won't work\n }\n\n public wrapMessageForReply(message: MyMessage | MyDraftMessage, text: string, usingMids: number[], plain: true, highlightWord?: string, withoutMediaType?: boolean): string;\n public wrapMessageForReply(message: MyMessage | MyDraftMessage, text?: string, usingMids?: number[], plain?: false, highlightWord?: string, withoutMediaType?: boolean): DocumentFragment;\n public wrapMessageForReply(message: MyMessage | MyDraftMessage, text: string = (message as Message.message).message, usingMids?: number[], plain?: boolean, highlightWord?: string, withoutMediaType?: boolean): DocumentFragment | string {\n const parts: (Node | string)[] = [];\n\n let hasAlbumKey = false;\n const addPart = (langKey: LangPackKey, part?: string | HTMLElement) => {\n if(langKey) {\n if(part === undefined && hasAlbumKey) {\n return;\n }\n \n part = plain ? I18n.format(langKey, true) : i18n(langKey);\n }\n \n if(plain) {\n parts.push(part);\n } else {\n const el = document.createElement('i');\n if(typeof(part) === 'string') el.innerHTML = part;\n else el.append(part);\n parts.push(el);\n }\n };\n\n const isRestricted = this.isRestricted(message as any);\n\n let entities = (message as Message.message).totalEntities;\n if((message as Message.message).media && !isRestricted) {\n assumeType<Message.message>(message);\n let usingFullAlbum = true;\n if(message.grouped_id) {\n if(usingMids) {\n const mids = this.getMidsByMessage(message);\n if(usingMids.length === mids.length) {\n for(const mid of mids) {\n if(!usingMids.includes(mid)) {\n usingFullAlbum = false;\n break;\n }\n }\n } else {\n usingFullAlbum = false;\n }\n }\n\n if(usingFullAlbum) {\n const albumText = this.getAlbumText(message.grouped_id);\n text = albumText.message;\n entities = albumText.totalEntities;\n\n if(!withoutMediaType) {\n addPart('AttachAlbum');\n hasAlbumKey = true;\n }\n }\n } else {\n usingFullAlbum = false;\n }\n\n if((!usingFullAlbum && !withoutMediaType) || !text) {\n const media = message.media;\n switch(media._) {\n case 'messageMediaPhoto':\n addPart('AttachPhoto');\n break;\n case 'messageMediaDice':\n addPart(undefined, plain ? media.emoticon : RichTextProcessor.wrapEmojiText(media.emoticon));\n break;\n case 'messageMediaVenue': {\n text = media.title;\n addPart('AttachLocation');\n break;\n }\n case 'messageMediaGeo':\n addPart('AttachLocation');\n break;\n case 'messageMediaGeoLive':\n addPart('AttachLiveLocation');\n break;\n case 'messageMediaPoll':\n addPart(undefined, plain ? '📊' + ' ' + (media.poll.question || 'poll') : media.poll.rReply);\n break;\n case 'messageMediaContact':\n addPart('AttachContact');\n break;\n case 'messageMediaGame': {\n const f = '🎮' + ' ' + media.game.title;\n addPart(undefined, plain ? f : RichTextProcessor.wrapEmojiText(f));\n break;\n }\n case 'messageMediaDocument': {\n const document = media.document as MyDocument;\n \n if(document.type === 'video') {\n addPart('AttachVideo');\n } else if(document.type === 'voice') {\n addPart('AttachAudio');\n } else if(document.type === 'gif') {\n addPart('AttachGif');\n } else if(document.type === 'round') {\n addPart('AttachRound');\n } else if(document.type === 'sticker') {\n if(document.stickerEmojiRaw) {\n addPart(undefined, (plain ? document.stickerEmojiRaw : document.stickerEmoji) + ' ');\n }\n \n addPart('AttachSticker');\n text = '';\n } else if(document.type === 'audio') {\n const attribute = document.attributes.find(attribute => attribute._ === 'documentAttributeAudio' && (attribute.title || attribute.performer)) as DocumentAttribute.documentAttributeAudio;\n const f = '🎵' + ' ' + (attribute ? [attribute.title, attribute.performer].filter(Boolean).join(' - ') : document.file_name);\n addPart(undefined, plain ? f : RichTextProcessor.wrapEmojiText(f));\n } else {\n addPart(undefined, plain ? document.file_name : RichTextProcessor.wrapEmojiText(document.file_name));\n }\n \n break;\n }\n\n case 'messageMediaUnsupported': {\n addPart(UNSUPPORTED_LANG_PACK_KEY);\n break;\n }\n \n default:\n //messageText += media._;\n ///////this.log.warn('Got unknown media type!', message);\n break;\n }\n }\n\n const length = parts.length;\n /* for(let i = 1; i < length; i += 2) {\n parts.splice(i, 0, ', ');\n } */\n\n if(text && length) {\n parts.push(', ');\n }\n }\n\n if((message as Message.messageService).action) {\n const actionWrapped = this.wrapMessageActionTextNew((message as Message.messageService), plain);\n if(actionWrapped) {\n addPart(undefined, actionWrapped);\n }\n }\n\n if(isRestricted) {\n text = getRestrictionReason((message as Message.message).restriction_reason).text;\n entities = [];\n }\n\n if(text) {\n text = limitSymbols(text, 100);\n\n if(!entities) {\n entities = [];\n }\n\n if(plain) {\n parts.push(RichTextProcessor.wrapPlainText(text, entities));\n } else {\n // let entities = RichTextProcessor.parseEntities(text.replace(/\\n/g, ' '));\n\n if(highlightWord) {\n highlightWord = highlightWord.trim();\n let found = false;\n let match: any;\n let regExp = new RegExp(escapeRegExp(highlightWord), 'gi');\n entities = entities.slice(); // fix leaving highlight entity\n while((match = regExp.exec(text)) !== null) {\n entities.push({_: 'messageEntityHighlight', length: highlightWord.length, offset: match.index});\n found = true;\n }\n \n if(found) {\n RichTextProcessor.sortEntities(entities);\n }\n }\n\n const messageWrapped = RichTextProcessor.wrapRichText(text, {\n noLinebreaks: true, \n entities, \n noLinks: true,\n noTextFormat: true\n });\n \n parts.push(htmlToDocumentFragment(messageWrapped) as any);\n }\n }\n\n if(plain) {\n return parts.join('');\n } else {\n const fragment = document.createDocumentFragment();\n fragment.append(...parts);\n return fragment;\n }\n }\n\n public wrapSenderToPeer(message: MyMessage) {\n const senderTitle: HTMLElement = document.createElement('span');\n senderTitle.classList.add('sender-title');\n \n const fromMe = message.fromId === rootScope.myId && message.peerId !== rootScope.myId;\n senderTitle.append(\n fromMe ? \n i18n('FromYou') : \n new PeerTitle({\n ...this.getMessageSenderPeerIdOrName(message),\n dialog: message.peerId === rootScope.myId\n }).element\n );\n\n if(appPeersManager.isAnyGroup(message.peerId) || fromMe) {\n const peerTitle = new PeerTitle({peerId: message.peerId}).element;\n senderTitle.append(' ➝ ', peerTitle);\n }\n\n return senderTitle;\n }\n\n public getMessageSenderPeerIdOrName(message: MyMessage) {\n if(message.fromId) {\n return {\n peerId: message.fromId\n };\n } else {\n return {\n fromName: (message as Message.message).fwd_from?.from_name\n };\n }\n }\n\n public wrapSentTime(message: MyMessage) {\n const el: HTMLElement = document.createElement('span');\n el.classList.add('sent-time');\n el.append(formatDateAccordingToTodayNew(new Date(message.date * 1000)));\n\n return el;\n }\n\n private wrapJoinVoiceChatAnchor(message: Message.messageService) {\n const action = message.action as MessageAction.messageActionInviteToGroupCall;\n const {onclick, url} = RichTextProcessor.wrapUrl(`tg://voicechat?chat_id=${message.peerId.toChatId()}&id=${action.call.id}&access_hash=${action.call.access_hash}`);\n if(!onclick) {\n return document.createElement('span');\n }\n \n const a = document.createElement('a');\n a.href = url;\n a.setAttribute('onclick', onclick + '(this)');\n\n return a;\n }\n\n private wrapMessageActionTextNewUnsafe(message: MyMessage, plain?: boolean) {\n const element: HTMLElement = plain ? undefined : document.createElement('span');\n const action = 'action' in message && message.action;\n\n // this.log('message action:', action);\n\n if((action as MessageAction.messageActionCustomAction).message) {\n const unsafeMessage = (action as MessageAction.messageActionCustomAction).message;\n if(plain) {\n return RichTextProcessor.wrapPlainText(unsafeMessage);\n } else {\n element.innerHTML = RichTextProcessor.wrapRichText(unsafeMessage, {noLinebreaks: true});\n return element;\n }\n } else {\n let _ = action._;\n //let suffix = '';\n let langPackKey: LangPackKey;\n let args: any[];\n\n const getNameDivHTML = (peerId: PeerId, plain: boolean) => {\n return plain ? appPeersManager.getPeerTitle(peerId, plain) : (new PeerTitle({peerId})).element;\n };\n\n switch(action._) {\n case 'messageActionPhoneCall': {\n _ += '.' + (action as any).type;\n\n args = [formatCallDuration(action.duration, plain)];\n break;\n }\n\n case 'messageActionGroupCall': {\n _ += '.' + (action as any).type;\n\n args = [];\n if(!_.endsWith('You') && !message.pFlags.post) {\n args.push(getNameDivHTML(message.fromId, plain));\n }\n\n if(action.duration !== undefined) {\n args.push(formatCallDuration(action.duration, plain));\n } else {\n args.push(this.wrapJoinVoiceChatAnchor(message as any));\n }\n\n break;\n }\n\n case 'messageActionInviteToGroupCall': {\n const peerIds = [message.fromId, action.users[0].toPeerId()];\n let a = 'Chat.Service.VoiceChatInvitation';\n const myId = appUsersManager.getSelf().id;\n if(peerIds[0] === myId) a += 'ByYou';\n else if(peerIds[1] === myId) a += 'ForYou';\n indexOfAndSplice(peerIds, myId);\n\n langPackKey = a as LangPackKey;\n args = peerIds.map(peerId => getNameDivHTML(peerId, plain));\n args.push(this.wrapJoinVoiceChatAnchor(message as any));\n break;\n }\n\n case 'messageActionGroupCallScheduled': {\n const today = new Date();\n const date = new Date(action.schedule_date * 1000);\n const daysToStart = (date.getTime() - today.getTime()) / 86400e3;\n const tomorrowDate = new Date(today);\n tomorrowDate.setDate(tomorrowDate.getDate() + 1);\n\n const isBroadcast = appPeersManager.isBroadcast(message.peerId);\n langPackKey = isBroadcast ? 'ChatList.Service.VoiceChatScheduled.Channel' : 'ChatList.Service.VoiceChatScheduled';\n args = [];\n const myId = appUsersManager.getSelf().id;\n if(message.fromId === myId) {\n langPackKey += 'You';\n } else if(!isBroadcast) {\n args.push(getNameDivHTML(message.fromId, plain));\n }\n\n let k: LangPackKey, _args: FormatterArguments = [];\n if(daysToStart < 1 && date.getDate() === today.getDate()) {\n k = 'TodayAtFormattedWithToday';\n } else if(daysToStart < 2 && date.getDate() === tomorrowDate.getDate()) {\n k = 'Time.TomorrowAt';\n } else {\n k = 'formatDateAtTime';\n _args.push(new I18n.IntlDateElement({\n date, \n options: {\n day: '2-digit',\n month: '2-digit',\n year: '2-digit'\n }\n }).element);\n }\n\n _args.push(formatTime(date));\n const t = i18n(k, _args);\n args.push(t);\n\n break;\n }\n\n case 'messageActionChatCreate': {\n const myId = appUsersManager.getSelf().id;\n if(message.fromId === myId) {\n _ += 'You';\n } else {\n args = [getNameDivHTML(message.fromId, plain)];\n }\n \n break;\n }\n\n case 'messageActionPinMessage': {\n const peerId = message.peerId;\n const pinnedMessage = this.getMessageByPeer(peerId, message.reply_to_mid);\n\n args = [\n getNameDivHTML(message.fromId, plain),\n ];\n \n if(pinnedMessage.deleted/* || true */) {\n langPackKey = 'ActionPinnedNoText';\n\n if(message.reply_to_mid) { // refresh original message\n this.fetchMessageReplyTo(message).then(originalMessage => {\n if(!originalMessage.deleted && !message.deleted) {\n rootScope.dispatchEvent('message_edit', {\n storage: this.getMessagesStorage(peerId),\n peerId: peerId,\n mid: message.mid\n });\n\n if(this.isMessageIsTopMessage(message)) {\n rootScope.dispatchEvent('dialogs_multiupdate', {\n [peerId]: this.getDialogOnly(peerId)\n });\n }\n }\n });\n }\n } else {\n const a = document.createElement('i');\n a.dataset.savedFrom = pinnedMessage.peerId + '_' + pinnedMessage.mid;\n a.dir = 'auto';\n a.append(this.wrapMessageForReply(pinnedMessage, undefined, undefined, plain as any));\n args.push(a);\n }\n\n break;\n }\n\n case 'messageActionChatJoinedByRequest': {\n const isBroadcast = appPeersManager.isBroadcast(message.peerId);\n if(message.pFlags.out) {\n langPackKey = isBroadcast ? 'RequestToJoinChannelApproved' : 'RequestToJoinGroupApproved';\n } else {\n langPackKey = isBroadcast ? 'ChatService.UserJoinedChannelByRequest' : 'ChatService.UserJoinedGroupByRequest';\n args = [getNameDivHTML(message.fromId, plain)];\n }\n break;\n }\n\n case 'messageActionContactSignUp':\n case 'messageActionChatReturn':\n case 'messageActionChatLeave':\n case 'messageActionChatJoined':\n case 'messageActionChatEditPhoto':\n case 'messageActionChatDeletePhoto':\n case 'messageActionChatEditVideo':\n case 'messageActionChatJoinedByLink':\n case 'messageActionChannelEditVideo':\n case 'messageActionChannelDeletePhoto': {\n args = [getNameDivHTML(message.fromId, plain)];\n break;\n }\n\n case 'messageActionChannelEditTitle':\n case 'messageActionChatEditTitle': {\n args = [];\n if(action._ === 'messageActionChatEditTitle') {\n args.push(getNameDivHTML(message.fromId, plain));\n }\n\n args.push(plain ? action.title : htmlToSpan(RichTextProcessor.wrapEmojiText(action.title)));\n break;\n }\n\n case 'messageActionChatDeleteUser':\n case 'messageActionChatAddUsers':\n case 'messageActionChatAddUser': {\n const users = (action as MessageAction.messageActionChatAddUser).users \n || [(action as MessageAction.messageActionChatDeleteUser).user_id];\n\n args = [getNameDivHTML(message.fromId, plain)];\n\n if(users.length > 1) {\n const joined = join(\n users.map((userId: UserId) => getNameDivHTML(userId.toPeerId(), plain)),\n false,\n plain\n );\n \n if(plain) {\n args.push(...joined);\n } else {\n const fragment = document.createElement('span');\n fragment.append(...joined);\n args.push(fragment);\n }\n } else {\n args.push(getNameDivHTML(users[0].toPeerId(), plain));\n }\n\n break;\n }\n\n case 'messageActionBotAllowed': {\n const anchorHTML = RichTextProcessor.wrapRichText(action.domain, {\n entities: [{\n _: 'messageEntityUrl',\n length: action.domain.length,\n offset: 0\n }]\n });\n\n const node = htmlToSpan(anchorHTML);\n\n args = [node];\n break;\n }\n\n default:\n langPackKey = (langPack[_] || `[${action._}]`) as any;\n break;\n }\n\n if(!langPackKey) {\n langPackKey = langPack[_];\n if(langPackKey === undefined) {\n langPackKey = '[' + _ + ']' as any;\n }\n }\n\n if(plain) {\n return I18n.format(langPackKey, true, args);\n } else {\n return _i18n(element, langPackKey, args);\n }\n\n //str = !langPackKey || langPackKey[0].toUpperCase() === langPackKey[0] ? langPackKey : getNameDivHTML(message.fromId) + langPackKey + (suffix ? ' ' : '');\n }\n }\n\n public wrapMessageActionTextNew(message: MyMessage, plain: true): string;\n public wrapMessageActionTextNew(message: MyMessage, plain?: false): HTMLElement;\n public wrapMessageActionTextNew(message: MyMessage, plain: boolean): HTMLElement | string;\n public wrapMessageActionTextNew(message: MyMessage, plain?: boolean): HTMLElement | string {\n try {\n return this.wrapMessageActionTextNewUnsafe(message, plain);\n } catch(err) {\n this.log.error('wrapMessageActionTextNewUnsafe error:', err);\n return plain ? '' : document.createElement('span');\n }\n }\n\n public reportMessages(peerId: PeerId, mids: number[], reason: ReportReason['_'], message?: string) {\n return apiManager.invokeApiSingle('messages.report', {\n peer: appPeersManager.getInputPeerById(peerId),\n id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid)),\n reason: {\n _: reason\n },\n message\n });\n }\n\n public startBot(botId: BotId, chatId?: ChatId, startParam?: string) {\n const peerId = chatId ? chatId.toPeerId(true) : botId.toPeerId();\n if(startParam) {\n const randomId = randomLong();\n\n return apiManager.invokeApi('messages.startBot', {\n bot: appUsersManager.getUserInput(botId),\n peer: appPeersManager.getInputPeerById(peerId),\n random_id: randomId,\n start_param: startParam\n }).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n const str = '/start';\n if(chatId) {\n let promise: Promise<void>;\n if(appChatsManager.isChannel(chatId)) {\n promise = appChatsManager.inviteToChannel(chatId, [botId]);\n } else {\n promise = appChatsManager.addChatUser(chatId, botId, 0);\n }\n\n return promise.catch((error) => {\n if(error && error.type == 'USER_ALREADY_PARTICIPANT') {\n error.handled = true;\n return;\n }\n\n throw error;\n }).then(() => {\n const bot = appUsersManager.getUser(botId);\n return this.sendText(peerId, str + '@' + bot.username);\n });\n }\n\n return this.sendText(peerId, str);\n }\n\n public editPeerFolders(peerIds: PeerId[], folderId: number) {\n apiManager.invokeApi('folders.editPeerFolders', {\n folder_peers: peerIds.map(peerId => {\n return {\n _: 'inputFolderPeer',\n peer: appPeersManager.getInputPeerById(peerId),\n folder_id: folderId\n };\n })\n }).then(updates => {\n //this.log('editPeerFolders updates:', updates);\n apiUpdatesManager.processUpdateMessage(updates); // WARNING! возможно тут нужно добавлять channelId, и вызывать апдейт для каждого канала отдельно\n });\n }\n\n public toggleDialogPin(peerId: PeerId, filterId?: number) {\n if(filterId > 1) {\n return this.filtersStorage.toggleDialogPin(peerId, filterId);\n }\n\n const dialog = this.getDialogOnly(peerId);\n if(!dialog) return Promise.reject();\n\n const pinned = dialog.pFlags?.pinned ? undefined : true;\n\n if(pinned) {\n const max = filterId === 1 ? rootScope.config.pinned_infolder_count_max : rootScope.config.pinned_dialogs_count_max;\n if(this.dialogsStorage.getPinnedOrders(filterId).length >= max) {\n return Promise.reject({type: 'PINNED_DIALOGS_TOO_MUCH'});\n }\n }\n\n return apiManager.invokeApi('messages.toggleDialogPin', {\n peer: appPeersManager.getInputDialogPeerById(peerId),\n pinned\n }).then(bool => {\n if(bool) {\n const pFlags: Update.updateDialogPinned['pFlags'] = pinned ? {pinned} : {};\n apiUpdatesManager.saveUpdate({\n _: 'updateDialogPinned',\n peer: appPeersManager.getDialogPeer(peerId),\n folder_id: filterId,\n pFlags\n });\n }\n });\n }\n\n public markDialogUnread(peerId: PeerId, read?: true) {\n const dialog = this.getDialogOnly(peerId);\n if(!dialog) return Promise.reject();\n\n const unread = read || dialog.pFlags?.unread_mark ? undefined : true;\n return apiManager.invokeApi('messages.markDialogUnread', {\n peer: appPeersManager.getInputDialogPeerById(peerId),\n unread\n }).then(bool => {\n if(bool) {\n const pFlags: Update.updateDialogUnreadMark['pFlags'] = unread ? {unread} : {};\n this.onUpdateDialogUnreadMark({\n _: 'updateDialogUnreadMark',\n peer: appPeersManager.getDialogPeer(peerId),\n pFlags\n });\n }\n });\n }\n\n public migrateChecks(migrateFrom: PeerId, migrateTo: PeerId) {\n if(!this.migratedFromTo[migrateFrom] &&\n !this.migratedToFrom[migrateTo] &&\n appChatsManager.hasChat(migrateTo.toChatId())) {\n const fromChat = appChatsManager.getChat(migrateFrom.toChatId());\n if(fromChat &&\n fromChat.migrated_to &&\n fromChat.migrated_to.channel_id === migrateTo.toChatId()) {\n this.migratedFromTo[migrateFrom] = migrateTo;\n this.migratedToFrom[migrateTo] = migrateFrom;\n\n //setTimeout(() => {\n rootScope.dispatchEvent('dialog_migrate', {migrateFrom, migrateTo});\n\n this.dialogsStorage.dropDialogWithEvent(migrateFrom);\n //}, 100);\n }\n }\n }\n\n private canMessageBeEdited(message: any, kind: 'text' | 'poll') {\n if(message.pFlags.is_outgoing) {\n return false;\n }\n\n const goodMedias = [\n 'messageMediaPhoto',\n 'messageMediaDocument',\n 'messageMediaWebPage'\n ];\n\n if(kind === 'poll') {\n goodMedias.push('messageMediaPoll');\n }\n\n if(message._ !== 'message' ||\n message.deleted ||\n message.fwd_from ||\n message.via_bot_id ||\n message.media && goodMedias.indexOf(message.media._) === -1 ||\n message.fromId && appUsersManager.isBot(message.fromId)) {\n return false;\n }\n \n if(message.media &&\n message.media._ === 'messageMediaDocument' &&\n (message.media.document.sticker || message.media.document.type === 'round')) {\n return false;\n }\n\n return true;\n }\n\n public canEditMessage(message: Message.message | Message.messageService, kind: 'text' | 'poll' = 'text') {\n if(!message || !this.canMessageBeEdited(message, kind)) {\n return false;\n }\n\n // * second rule for saved messages, because there is no 'out' flag\n if(/* message.pFlags.out || */this.getMessagePeer(message) === appUsersManager.getSelf().id) {\n return true;\n }\n\n if(!message.pFlags.out || (\n message.peer_id._ !== 'peerChannel' && \n message.date < (tsNow(true) - rootScope.config.edit_time_limit) && \n (message as Message.message).media?._ !== 'messageMediaPoll'\n )\n ) {\n return false;\n }\n\n return true;\n }\n\n public canDeleteMessage(message: MyMessage) {\n return message && (\n message.peerId.isUser() \n || message.pFlags.out \n || appChatsManager.getChat(message.peerId.toChatId())._ === 'chat' \n || appChatsManager.hasRights(message.peerId.toChatId(), 'delete_messages')\n ) && !message.pFlags.is_outgoing;\n }\n\n public getReplyKeyboard(peerId: PeerId) {\n return this.getHistoryStorage(peerId).replyMarkup;\n }\n\n public mergeReplyKeyboard(historyStorage: HistoryStorage, message: Message.messageService | Message.message) {\n // this.log('merge', message.mid, message.reply_markup, historyStorage.reply_markup)\n let messageReplyMarkup = (message as Message.message).reply_markup;\n if(!messageReplyMarkup &&\n !message.pFlags?.out &&\n !(message as Message.messageService).action) {\n return false;\n }\n\n if(messageReplyMarkup?._ === 'replyInlineMarkup') {\n return false;\n }\n\n const lastReplyMarkup = historyStorage.replyMarkup;\n if(messageReplyMarkup) {\n if(lastReplyMarkup && lastReplyMarkup.mid >= message.mid) {\n return false;\n }\n\n if(messageReplyMarkup.pFlags.selective) {\n return false;\n }\n\n if(historyStorage.maxOutId &&\n message.mid < historyStorage.maxOutId &&\n (messageReplyMarkup as ReplyMarkup.replyKeyboardMarkup | ReplyMarkup.replyKeyboardForceReply).pFlags.single_use) {\n (messageReplyMarkup as ReplyMarkup.replyKeyboardMarkup | ReplyMarkup.replyKeyboardForceReply).pFlags.hidden = true;\n }\n\n messageReplyMarkup.mid = message.mid;\n /* messageReplyMarkup = Object.assign({\n mid: message.mid\n }, messageReplyMarkup); */\n\n if(messageReplyMarkup._ !== 'replyKeyboardHide') {\n messageReplyMarkup.fromId = appPeersManager.getPeerId(message.from_id);\n }\n\n historyStorage.replyMarkup = messageReplyMarkup;\n // this.log('set', historyStorage.reply_markup)\n return true;\n }\n\n if(message.pFlags.out) {\n if(lastReplyMarkup) {\n assumeType<ReplyMarkup.replyKeyboardMarkup>(lastReplyMarkup);\n if(lastReplyMarkup.pFlags.single_use &&\n !lastReplyMarkup.pFlags.hidden &&\n (message.mid > lastReplyMarkup.mid || message.pFlags.is_outgoing) &&\n (message as Message.message).message) {\n lastReplyMarkup.pFlags.hidden = true;\n // this.log('set', historyStorage.reply_markup)\n return true;\n }\n } else if(!historyStorage.maxOutId ||\n message.mid > historyStorage.maxOutId) {\n historyStorage.maxOutId = message.mid;\n }\n }\n\n assumeType<Message.messageService>(message);\n if(message.action?._ === 'messageActionChatDeleteUser' &&\n (lastReplyMarkup\n ? message.action.user_id === (lastReplyMarkup as ReplyMarkup.replyKeyboardMarkup).fromId\n : appUsersManager.isBot(message.action.user_id)\n )\n ) {\n historyStorage.replyMarkup = {\n _: 'replyKeyboardHide',\n mid: message.mid,\n pFlags: {}\n };\n // this.log('set', historyStorage.reply_markup)\n return true;\n }\n\n return false;\n }\n\n public getSearchStorage(peerId: PeerId, inputFilter: MyInputMessagesFilter) {\n if(!this.searchesStorage[peerId]) this.searchesStorage[peerId] = {};\n if(!this.searchesStorage[peerId][inputFilter]) this.searchesStorage[peerId][inputFilter] = {history: []};\n return this.searchesStorage[peerId][inputFilter];\n }\n\n public getSearchCounters(peerId: PeerId, filters: MessagesFilter[], canCache = true): Promise<MessagesSearchCounter[]> {\n if(appPeersManager.isRestricted(peerId)) {\n return Promise.resolve(filters.map((filter) => {\n return {\n _: 'messages.searchCounter',\n pFlags: {},\n filter: filter,\n count: 0\n };\n }));\n }\n\n const func = (canCache ? apiManager.invokeApiCacheable : apiManager.invokeApi).bind(apiManager);\n return func('messages.getSearchCounters', {\n peer: appPeersManager.getInputPeerById(peerId),\n filters\n });\n }\n\n public filterMessagesByInputFilter(inputFilter: MyInputMessagesFilter, history: number[], storage: MessagesStorage, limit: number) {\n const foundMsgs: MyMessage[] = [];\n if(!history.length) {\n return foundMsgs;\n }\n\n let filtering = true;\n const neededContents: Partial<{\n [messageMediaType in MessageMedia['_']]: boolean\n }> & Partial<{\n avatar: boolean,\n url: boolean\n }> = {},\n neededDocTypes: MyDocument['type'][] = [], \n excludeDocTypes: MyDocument['type'][] = []/* ,\n neededFlags: string[] = [] */;\n\n switch(inputFilter) {\n case 'inputMessagesFilterPhotos':\n neededContents['messageMediaPhoto'] = true;\n break;\n\n case 'inputMessagesFilterPhotoVideo':\n neededContents['messageMediaPhoto'] = true;\n neededContents['messageMediaDocument'] = true;\n neededDocTypes.push('video');\n break;\n\n case 'inputMessagesFilterVideo':\n neededContents['messageMediaDocument'] = true;\n neededDocTypes.push('video');\n break;\n\n case 'inputMessagesFilterDocument':\n neededContents['messageMediaDocument'] = true;\n excludeDocTypes.push('video');\n break;\n\n case 'inputMessagesFilterVoice':\n neededContents['messageMediaDocument'] = true;\n neededDocTypes.push('voice');\n break;\n\n case 'inputMessagesFilterRoundVoice':\n neededContents['messageMediaDocument'] = true;\n neededDocTypes.push('round', 'voice');\n break;\n\n case 'inputMessagesFilterRoundVideo':\n neededContents['messageMediaDocument'] = true;\n neededDocTypes.push('round');\n break;\n\n case 'inputMessagesFilterMusic':\n neededContents['messageMediaDocument'] = true;\n neededDocTypes.push('audio');\n break;\n\n case 'inputMessagesFilterUrl':\n neededContents['url'] = true;\n break;\n\n case 'inputMessagesFilterChatPhotos':\n neededContents['avatar'] = true;\n break;\n\n /* case 'inputMessagesFilterPinned':\n neededFlags.push('pinned');\n break; */\n\n /* case 'inputMessagesFilterMyMentions':\n neededContents['mentioned'] = true;\n break; */\n\n default:\n filtering = false;\n break;\n /* return Promise.resolve({\n count: 0,\n next_rate: 0,\n history: [] as number[]\n }); */\n }\n\n if(!filtering) {\n return foundMsgs;\n }\n\n for(let i = 0, length = history.length; i < length; ++i) {\n const message: Message.message | Message.messageService = storage.get(history[i]);\n if(!message) continue;\n \n //|| (neededContents['mentioned'] && message.totalEntities.find((e: any) => e._ === 'messageEntityMention'));\n \n let found = false;\n if(message._ === 'message') {\n if(message.media && neededContents[message.media._]/* && !message.fwd_from */) {\n const doc = (message.media as MessageMedia.messageMediaDocument).document as MyDocument;\n if(doc && ((neededDocTypes.length && !neededDocTypes.includes(doc.type)) \n || excludeDocTypes.includes(doc.type))) {\n continue;\n }\n \n found = true;\n } else if(neededContents['url'] && message.message) {\n const goodEntities = ['messageEntityTextUrl', 'messageEntityUrl'];\n if((message.totalEntities as MessageEntity[]).find(e => goodEntities.includes(e._)) || RichTextProcessor.matchUrl(message.message)) {\n found = true;\n }\n }\n } else if(neededContents['avatar'] && \n message.action && \n ([\n 'messageActionChannelEditPhoto' as const, \n 'messageActionChatEditPhoto' as const, \n 'messageActionChannelEditVideo' as const, \n 'messageActionChatEditVideo' as const\n ] as MessageAction['_'][]).includes(message.action._)) {\n found = true;\n }/* else if(neededFlags.find(flag => message.pFlags[flag])) {\n found = true;\n } */\n \n if(found) {\n foundMsgs.push(message);\n if(foundMsgs.length >= limit) {\n break;\n }\n }\n }\n\n return foundMsgs;\n }\n\n public getSearch({peerId, query, inputFilter, maxId, limit, nextRate, backLimit, threadId, folderId, minDate, maxDate}: {\n peerId?: PeerId,\n maxId?: number,\n limit?: number,\n nextRate?: number,\n backLimit?: number,\n threadId?: number,\n folderId?: number,\n query?: string,\n inputFilter?: {\n _: MyInputMessagesFilter\n },\n minDate?: number,\n maxDate?: number\n }): Promise<{\n count: number,\n next_rate: number,\n offset_id_offset: number,\n history: MyMessage[]\n }> {\n if(appPeersManager.isRestricted(peerId)) {\n return Promise.resolve({\n count: 0,\n offset_id_offset: 0,\n next_rate: undefined,\n history: []\n });\n }\n\n if(!query) query = '';\n if(!inputFilter) inputFilter = {_: 'inputMessagesFilterEmpty'};\n if(limit === undefined) limit = 20;\n if(!nextRate) nextRate = 0;\n if(!backLimit) backLimit = 0;\n\n minDate = minDate ? minDate / 1000 | 0 : 0;\n maxDate = maxDate ? maxDate / 1000 | 0 : 0;\n\n let foundMsgs: MyMessage[] = [];\n\n //this.log('search', maxId);\n\n if(backLimit) {\n limit += backLimit;\n }\n\n //const beta = inputFilter._ === 'inputMessagesFilterPinned' && !backLimit;\n const beta = false;\n\n let storage: {\n count?: number;\n history: SlicedArray<number>;\n };\n\n // * костыль для limit 1, если нужно и получить сообщение, и узнать количество сообщений\n if(peerId && !backLimit && !maxId && !query && limit !== 1 && !threadId/* && inputFilter._ !== 'inputMessagesFilterPinned' */) {\n storage = beta ? \n this.getSearchStorage(peerId, inputFilter._) as any : \n this.getHistoryStorage(peerId);\n foundMsgs = this.filterMessagesByInputFilter(inputFilter._, storage.history.slice, this.getMessagesStorage(peerId), limit);\n }\n\n if(foundMsgs.length) {\n if(foundMsgs.length < limit && (beta ? storage.count !== storage.history.length : true)) {\n maxId = foundMsgs[foundMsgs.length - 1].mid;\n limit = limit - foundMsgs.length;\n } else {\n return Promise.resolve({\n count: beta ? storage.count : 0,\n next_rate: 0,\n offset_id_offset: 0,\n history: foundMsgs\n });\n }\n } else if(beta && storage?.count) {\n return Promise.resolve({\n count: storage.count,\n next_rate: 0,\n offset_id_offset: 0,\n history: []\n });\n }\n\n const canCache = false && (['inputMessagesFilterChatPhotos', 'inputMessagesFilterPinned'] as MyInputMessagesFilter[]).includes(inputFilter._);\n const method = (canCache ? apiManager.invokeApiCacheable : apiManager.invokeApi).bind(apiManager);\n\n let apiPromise: Promise<any>;\n if(peerId && !nextRate && folderId === undefined/* || !query */) {\n apiPromise = method('messages.search', {\n peer: appPeersManager.getInputPeerById(peerId),\n q: query || '',\n filter: inputFilter as any as MessagesFilter,\n min_date: minDate,\n max_date: maxDate,\n limit,\n offset_id: appMessagesIdsManager.getServerMessageId(maxId) || 0,\n add_offset: backLimit ? -backLimit : 0,\n max_id: 0,\n min_id: 0,\n hash: '',\n top_msg_id: appMessagesIdsManager.getServerMessageId(threadId) || 0\n }, {\n //timeout: APITIMEOUT,\n noErrorBox: true\n });\n } else {\n //var offsetDate = 0;\n let offsetPeerId: PeerId;\n let offsetId = 0;\n let offsetMessage = maxId && this.getMessageByPeer(peerId, maxId);\n\n if(offsetMessage && offsetMessage.date) {\n //offsetDate = offsetMessage.date + serverTimeManager.serverTimeOffset;\n offsetId = offsetMessage.id;\n offsetPeerId = this.getMessagePeer(offsetMessage);\n }\n\n apiPromise = method('messages.searchGlobal', {\n q: query,\n filter: inputFilter as any as MessagesFilter,\n min_date: minDate,\n max_date: maxDate,\n offset_rate: nextRate,\n offset_peer: appPeersManager.getInputPeerById(offsetPeerId),\n offset_id: offsetId,\n limit,\n folder_id: folderId\n }, {\n //timeout: APITIMEOUT,\n noErrorBox: true\n });\n }\n\n return apiPromise.then((searchResult: any) => {\n appUsersManager.saveApiUsers(searchResult.users);\n appChatsManager.saveApiChats(searchResult.chats);\n this.saveMessages(searchResult.messages);\n\n /* if(beta && storage && (!maxId || storage.history[storage.history.length - 1] === maxId)) {\n const storage = this.getSearchStorage(peerId, inputFilter._);\n const add = (searchResult.messages.map((m: any) => m.mid) as number[]).filter(mid => storage.history.indexOf(mid) === -1);\n storage.history.push(...add);\n storage.history.sort((a, b) => b - a);\n storage.count = searchResult.count;\n } */\n\n if(DEBUG) {\n this.log('getSearch result:', inputFilter, searchResult);\n }\n\n const foundCount: number = searchResult.count || (foundMsgs.length + searchResult.messages.length);\n\n searchResult.messages.forEach((message: MyMessage) => {\n const peerId = this.getMessagePeer(message);\n if(peerId.isAnyChat()) {\n const chat: Chat.chat = appChatsManager.getChat(peerId.toChatId());\n if(chat.migrated_to) {\n this.migrateChecks(peerId, (chat.migrated_to as InputChannel.inputChannel).channel_id.toPeerId(true));\n }\n }\n\n foundMsgs.push(message);\n });\n\n return {\n count: foundCount,\n offset_id_offset: searchResult.offset_id_offset || 0,\n next_rate: searchResult.next_rate,\n history: foundMsgs\n };\n });\n }\n\n public subscribeRepliesThread(peerId: PeerId, mid: number) {\n const repliesKey = peerId + '_' + mid;\n for(const threadKey in this.threadsToReplies) {\n if(this.threadsToReplies[threadKey] === repliesKey) return;\n }\n\n this.getDiscussionMessage(peerId, mid);\n }\n\n public generateThreadServiceStartMessage(message: Message.message | Message.messageService) {\n const threadKey = message.peerId + '_' + message.mid;\n if(this.threadsServiceMessagesIdsStorage[threadKey]) return;\n\n const maxMessageId = appMessagesIdsManager.getServerMessageId(Math.max(...this.getMidsByMessage(message)));\n const serviceStartMessage: Message.messageService = {\n _: 'messageService',\n pFlags: {\n is_single: true\n },\n id: appMessagesIdsManager.generateMessageId(maxMessageId, true),\n date: message.date,\n from_id: {_: 'peerUser', user_id: NULL_PEER_ID}/* message.from_id */,\n peer_id: message.peer_id,\n action: {\n _: 'messageActionDiscussionStarted'\n },\n reply_to: this.generateReplyHeader(message.id)\n };\n\n this.saveMessages([serviceStartMessage], {isOutgoing: true});\n this.threadsServiceMessagesIdsStorage[threadKey] = serviceStartMessage.mid;\n } \n\n public getDiscussionMessage(peerId: PeerId, mid: number) {\n return apiManager.invokeApiSingle('messages.getDiscussionMessage', {\n peer: appPeersManager.getInputPeerById(peerId),\n msg_id: appMessagesIdsManager.getServerMessageId(mid)\n }).then(result => {\n appChatsManager.saveApiChats(result.chats);\n appUsersManager.saveApiUsers(result.users);\n this.saveMessages(result.messages);\n\n const message = this.filterMessages(result.messages[0] as Message.message, message => !!(message as Message.message).replies)[0] as Message.message;\n const threadKey = message.peerId + '_' + message.mid;\n\n this.generateThreadServiceStartMessage(message);\n \n const historyStorage = this.getHistoryStorage(message.peerId, message.mid);\n result.max_id = historyStorage.maxId = appMessagesIdsManager.generateMessageId(result.max_id) || 0;\n result.read_inbox_max_id = historyStorage.readMaxId = appMessagesIdsManager.generateMessageId(result.read_inbox_max_id ?? message.mid);\n result.read_outbox_max_id = historyStorage.readOutboxMaxId = appMessagesIdsManager.generateMessageId(result.read_outbox_max_id) || 0;\n\n this.threadsToReplies[threadKey] = peerId + '_' + mid;\n\n return message;\n });\n }\n\n private handleNewMessage(peerId: PeerId, mid: number) {\n if(this.newMessagesToHandle[peerId] === undefined) {\n this.newMessagesToHandle[peerId] = new Set();\n }\n\n this.newMessagesToHandle[peerId].add(mid);\n if(!this.newMessagesHandleTimeout) {\n this.newMessagesHandleTimeout = window.setTimeout(this.handleNewMessages, 0);\n }\n }\n\n private handleNewMessages = () => {\n clearTimeout(this.newMessagesHandleTimeout);\n this.newMessagesHandleTimeout = 0;\n\n rootScope.dispatchEvent('history_multiappend', this.newMessagesToHandle);\n this.newMessagesToHandle = {};\n };\n\n private handleNewDialogs = () => {\n let newMaxSeenId = 0;\n const obj = this.newDialogsToHandle;\n for(const peerId in obj) {\n const dialog = obj[peerId];\n if(!dialog) {\n this.reloadConversation(peerId.toPeerId());\n delete obj[peerId];\n } else {\n this.dialogsStorage.pushDialog(dialog);\n if(!appPeersManager.isChannel(peerId.toPeerId())) {\n newMaxSeenId = Math.max(newMaxSeenId, dialog.top_message || 0);\n }\n }\n }\n\n //this.log('after order:', this.dialogsStorage[0].map(d => d.peerId));\n\n if(newMaxSeenId !== 0) {\n this.incrementMaxSeenId(newMaxSeenId);\n }\n\n rootScope.dispatchEvent('dialogs_multiupdate', obj);\n this.newDialogsToHandle = {};\n };\n\n public scheduleHandleNewDialogs(peerId?: PeerId, dialog?: Dialog) {\n if(peerId !== undefined) {\n this.newDialogsToHandle[peerId] = dialog;\n }\n\n if(this.newDialogsHandlePromise) return this.newDialogsHandlePromise;\n return this.newDialogsHandlePromise = new Promise<void>((resolve) => {\n setTimeout(() => {\n resolve();\n this.newDialogsHandlePromise = undefined;\n this.handleNewDialogs();\n }, 0);\n });\n }\n\n public deleteMessages(peerId: PeerId, mids: number[], revoke?: boolean) {\n let promise: Promise<any>;\n\n const localMessageIds = mids.map(mid => appMessagesIdsManager.getServerMessageId(mid));\n\n if(peerId.isAnyChat() && appPeersManager.isChannel(peerId)) {\n const channelId = peerId.toChatId();\n const channel: Chat.channel = appChatsManager.getChat(channelId);\n if(!channel.pFlags.creator && !channel.admin_rights?.pFlags?.delete_messages) {\n mids = mids.filter((mid) => {\n const message = this.getMessageByPeer(peerId, mid);\n return !!message.pFlags.out;\n });\n\n if(!mids.length) {\n return;\n }\n }\n\n promise = apiManager.invokeApi('channels.deleteMessages', {\n channel: appChatsManager.getChannelInput(channelId),\n id: localMessageIds\n }).then((affectedMessages) => {\n apiUpdatesManager.processLocalUpdate({\n _: 'updateDeleteChannelMessages',\n channel_id: channelId,\n messages: mids,\n pts: affectedMessages.pts,\n pts_count: affectedMessages.pts_count\n });\n });\n } else {\n promise = apiManager.invokeApi('messages.deleteMessages', {\n revoke,\n id: localMessageIds\n }).then((affectedMessages) => {\n apiUpdatesManager.processLocalUpdate({\n _: 'updateDeleteMessages',\n messages: mids,\n pts: affectedMessages.pts,\n pts_count: affectedMessages.pts_count\n });\n });\n }\n\n return promise;\n }\n\n public readHistory(peerId: PeerId, maxId = 0, threadId?: number, force = false) {\n if(DO_NOT_READ_HISTORY) {\n return Promise.resolve();\n }\n\n // console.trace('start read')\n this.log('readHistory:', peerId, maxId, threadId);\n if(!this.getReadMaxIdIfUnread(peerId, threadId) && !force) {\n this.log('readHistory: isn\\'t unread');\n return Promise.resolve();\n }\n\n const historyStorage = this.getHistoryStorage(peerId, threadId);\n\n if(historyStorage.triedToReadMaxId >= maxId) {\n return Promise.resolve();\n }\n\n let apiPromise: Promise<any>;\n if(threadId) {\n if(!historyStorage.readPromise) {\n apiPromise = apiManager.invokeApi('messages.readDiscussion', {\n peer: appPeersManager.getInputPeerById(peerId),\n msg_id: appMessagesIdsManager.getServerMessageId(threadId),\n read_max_id: appMessagesIdsManager.getServerMessageId(maxId)\n });\n }\n\n apiUpdatesManager.processLocalUpdate({\n _: 'updateReadChannelDiscussionInbox',\n channel_id: peerId.toChatId(),\n top_msg_id: threadId,\n read_max_id: maxId\n });\n } else if(appPeersManager.isChannel(peerId)) {\n if(!historyStorage.readPromise) {\n apiPromise = apiManager.invokeApi('channels.readHistory', {\n channel: appChatsManager.getChannelInput(peerId.toChatId()),\n max_id: appMessagesIdsManager.getServerMessageId(maxId)\n });\n }\n\n apiUpdatesManager.processLocalUpdate({\n _: 'updateReadChannelInbox',\n max_id: maxId,\n channel_id: peerId.toChatId(),\n still_unread_count: undefined,\n pts: undefined\n });\n } else {\n if(!historyStorage.readPromise) {\n apiPromise = apiManager.invokeApi('messages.readHistory', {\n peer: appPeersManager.getInputPeerById(peerId),\n max_id: appMessagesIdsManager.getServerMessageId(maxId)\n }).then((affectedMessages) => {\n apiUpdatesManager.processUpdateMessage({\n _: 'updateShort',\n update: {\n _: 'updatePts',\n pts: affectedMessages.pts,\n pts_count: affectedMessages.pts_count\n }\n });\n });\n }\n\n apiUpdatesManager.processLocalUpdate({\n _: 'updateReadHistoryInbox',\n max_id: maxId,\n peer: appPeersManager.getOutputPeer(peerId),\n still_unread_count: undefined,\n pts: undefined,\n pts_count: undefined\n });\n }\n\n appNotificationsManager.soundReset(appPeersManager.getPeerString(peerId));\n\n if(historyStorage.readPromise) {\n return historyStorage.readPromise;\n }\n\n historyStorage.triedToReadMaxId = maxId;\n\n apiPromise.finally(() => {\n delete historyStorage.readPromise;\n\n const {readMaxId} = historyStorage;\n this.log('readHistory: promise finally', maxId, readMaxId);\n\n if(readMaxId > maxId) {\n this.readHistory(peerId, readMaxId, threadId, true);\n }\n });\n\n return historyStorage.readPromise = apiPromise;\n }\n\n public readAllHistory(peerId: PeerId, threadId?: number, force = false) {\n const historyStorage = this.getHistoryStorage(peerId, threadId);\n if(historyStorage.maxId) {\n this.readHistory(peerId, historyStorage.maxId, threadId, force); // lol\n }\n }\n\n public fixDialogUnreadMentionsIfNoMessage(peerId: PeerId) {\n const dialog = this.getDialogOnly(peerId);\n if(dialog?.unread_mentions_count) {\n this.reloadConversation(peerId);\n }\n }\n\n public modifyCachedMentions(peerId: PeerId, mid: number, add: boolean) {\n const slicedArray = this.unreadMentions[peerId];\n if(!slicedArray) return;\n\n if(add) {\n if(slicedArray.first.isEnd(SliceEnd.Top)) {\n slicedArray.insertSlice([mid]);\n }\n } else {\n slicedArray.delete(mid);\n }\n }\n\n private fixUnreadMentionsCountIfNeeded(peerId: PeerId, slicedArray: SlicedArray<number>) {\n const dialog = this.getDialogOnly(peerId);\n if(!slicedArray.length && dialog?.unread_mentions_count) {\n this.reloadConversation(peerId);\n }\n }\n\n public goToNextMention(peerId: PeerId) {\n /* this.getUnreadMentions(peerId, 1, 2, 0).then(messages => {\n console.log(messages);\n }); */\n\n const promise = this.goToNextMentionPromises[peerId];\n if(promise) {\n return promise;\n }\n\n const slicedArray = this.unreadMentions[peerId] ?? (this.unreadMentions[peerId] = new SlicedArray());\n const length = slicedArray.length;\n const isTopEnd = slicedArray.first.isEnd(SliceEnd.Top);\n if(!length && isTopEnd) {\n this.fixUnreadMentionsCountIfNeeded(peerId, slicedArray);\n return Promise.resolve();\n }\n\n let loadNextPromise = Promise.resolve();\n if(!isTopEnd && length < 25) {\n loadNextPromise = this.loadNextMentions(peerId);\n }\n\n return this.goToNextMentionPromises[peerId] = loadNextPromise.then(() => {\n const last = slicedArray.last;\n const mid = last && last[last.length - 1];\n if(mid) {\n slicedArray.delete(mid);\n rootScope.dispatchEvent('history_focus', {peerId, mid});\n } else {\n this.fixUnreadMentionsCountIfNeeded(peerId, slicedArray);\n }\n }).finally(() => {\n delete this.goToNextMentionPromises[peerId];\n });\n }\n\n public loadNextMentions(peerId: PeerId) {\n const slicedArray = this.unreadMentions[peerId];\n const maxId = slicedArray.first[0] || 1;\n\n const backLimit = 50;\n const add_offset = -backLimit;\n const limit = backLimit;\n return this.getUnreadMentions(peerId, maxId, add_offset, limit).then(messages => {\n this.mergeHistoryResult(slicedArray, messages, maxId === 1 ? 0 : maxId, limit, add_offset);\n });\n }\n\n public getUnreadMentions(peerId: PeerId, offsetId: number, add_offset: number, limit: number, maxId = 0, minId = 0) {\n return apiManager.invokeApiSingle('messages.getUnreadMentions', {\n peer: appPeersManager.getInputPeerById(peerId),\n offset_id: appMessagesIdsManager.getServerMessageId(offsetId),\n add_offset,\n limit,\n max_id: appMessagesIdsManager.getServerMessageId(maxId),\n min_id: appMessagesIdsManager.getServerMessageId(minId)\n }).then(messagesMessages => {\n assumeType<Exclude<MessagesMessages, MessagesMessages.messagesMessagesNotModified>>(messagesMessages);\n appUsersManager.saveApiUsers(messagesMessages.users);\n appChatsManager.saveApiChats(messagesMessages.chats);\n this.saveMessages(messagesMessages.messages);\n\n return messagesMessages;\n });\n }\n\n public readMessages(peerId: PeerId, msgIds: number[]) {\n if(DO_NOT_READ_HISTORY) {\n return Promise.resolve();\n }\n\n if(!msgIds.length) {\n return Promise.resolve();\n }\n\n msgIds = msgIds.map(mid => appMessagesIdsManager.getServerMessageId(mid));\n let promise: Promise<any>, update: Update.updateChannelReadMessagesContents | Update.updateReadMessagesContents;\n if(peerId.isAnyChat() && appPeersManager.isChannel(peerId)) {\n const channelId = peerId.toChatId();\n\n update = {\n _: 'updateChannelReadMessagesContents',\n channel_id: channelId,\n messages: msgIds\n };\n\n promise = apiManager.invokeApi('channels.readMessageContents', {\n channel: appChatsManager.getChannelInput(channelId),\n id: msgIds\n });\n } else {\n update = {\n _: 'updateReadMessagesContents',\n messages: msgIds,\n pts: undefined,\n pts_count: undefined\n };\n\n promise = apiManager.invokeApi('messages.readMessageContents', {\n id: msgIds\n }).then((affectedMessages) => {\n (update as Update.updateReadMessagesContents).pts = affectedMessages.pts;\n (update as Update.updateReadMessagesContents).pts_count = affectedMessages.pts_count;\n apiUpdatesManager.processLocalUpdate(update);\n });\n }\n\n apiUpdatesManager.processLocalUpdate(update);\n\n return promise;\n }\n\n public getHistoryStorage(peerId: PeerId, threadId?: number) {\n if(threadId) {\n //threadId = this.getLocalMessageId(threadId);\n if(!this.threadsStorage[peerId]) this.threadsStorage[peerId] = {};\n return this.threadsStorage[peerId][threadId] ?? (this.threadsStorage[peerId][threadId] = {count: null, history: new SlicedArray()});\n }\n\n return this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {count: null, history: new SlicedArray()});\n }\n\n private getNotifyPeerSettings(peerId: PeerId) {\n return Promise.all([\n appNotificationsManager.getNotifyPeerTypeSettings(),\n appNotificationsManager.getNotifySettings(appPeersManager.getInputNotifyPeerById(peerId, true))\n ]).then(([_, peerTypeNotifySettings]) => {\n return {\n muted: appNotificationsManager.isPeerLocalMuted(peerId, true),\n peerTypeNotifySettings\n };\n });\n }\n\n private handleNotifications = () => {\n window.clearTimeout(this.notificationsHandlePromise);\n this.notificationsHandlePromise = 0;\n\n //var timeout = $rootScope.idle.isIDLE && StatusManager.isOtherDeviceActive() ? 30000 : 1000;\n //const timeout = 1000;\n\n for(const _peerId in this.notificationsToHandle) {\n const peerId = _peerId.toPeerId();\n if(rootScope.peerId === peerId && !rootScope.idle.isIDLE) {\n continue;\n }\n\n const notifyPeerToHandle = this.notificationsToHandle[peerId];\n this.getNotifyPeerSettings(peerId).then(({muted, peerTypeNotifySettings}) => {\n const topMessage = notifyPeerToHandle.topMessage;\n if(muted || !topMessage.pFlags.unread) {\n return;\n }\n\n //setTimeout(() => {\n if(topMessage.pFlags.unread) {\n this.notifyAboutMessage(topMessage, {\n fwdCount: notifyPeerToHandle.fwdCount,\n peerTypeNotifySettings\n });\n }\n //}, timeout);\n });\n }\n\n this.notificationsToHandle = {};\n };\n\n private onUpdateMessageId = (update: Update.updateMessageID) => {\n const randomId = update.random_id;\n const pendingData = this.pendingByRandomId[randomId];\n //this.log('AMM updateMessageID:', update, pendingData);\n if(pendingData) {\n const {peerId, tempId, threadId, storage} = pendingData;\n const mid = appMessagesIdsManager.generateMessageId(update.id);\n const message = this.getMessageFromStorage(storage, mid);\n if(!message.deleted) {\n [this.getHistoryStorage(peerId), threadId ? this.getHistoryStorage(peerId, threadId) : undefined]\n .filter(Boolean)\n .forEach(storage => {\n storage.history.delete(tempId);\n });\n\n this.finalizePendingMessageCallbacks(storage, tempId, message);\n } else {\n this.pendingByMessageId[mid] = randomId;\n }\n }\n };\n\n private onUpdateNewMessage = (update: Update.updateNewDiscussionMessage | Update.updateNewMessage | Update.updateNewChannelMessage) => {\n const message = update.message as MyMessage;\n const peerId = this.getMessagePeer(message);\n const storage = this.getMessagesStorage(peerId);\n const dialog = this.getDialogOnly(peerId);\n\n // * local update\n const isLocalThreadUpdate = update._ === 'updateNewDiscussionMessage';\n\n // * temporary save the message for info (peerId, reply mids...)\n this.saveMessages([message], {storage: new Map()});\n\n const threadKey = this.getThreadKey(message);\n const threadId = threadKey ? +threadKey.split('_')[1] : undefined;\n if(threadId && !isLocalThreadUpdate && this.threadsStorage[peerId] && this.threadsStorage[peerId][threadId]) {\n const update = {\n _: 'updateNewDiscussionMessage',\n message\n } as Update.updateNewDiscussionMessage;\n\n this.onUpdateNewMessage(update);\n }\n\n if(!dialog && !isLocalThreadUpdate) {\n let good = true;\n if(peerId.isAnyChat()) {\n good = appChatsManager.isInChat(peerId.toChatId());\n }\n\n if(good) {\n const set = this.newUpdatesAfterReloadToHandle[peerId] ?? (this.newUpdatesAfterReloadToHandle[peerId] = new Set());\n if(set.has(update)) {\n this.log.error('here we go again', peerId);\n return;\n }\n\n (update as any).ignoreExisting = true;\n set.add(update);\n this.scheduleHandleNewDialogs(peerId);\n }\n\n return;\n }\n\n /* if(update._ === 'updateNewChannelMessage') {\n const chat = appChatsManager.getChat(peerId.toChatId());\n if(chat.pFlags && (chat.pFlags.left || chat.pFlags.kicked)) {\n return;\n }\n } */\n\n this.saveMessages([message], {storage});\n // this.log.warn(dT(), 'message unread', message.mid, message.pFlags.unread)\n\n /* if((message as Message.message).grouped_id) {\n this.log('updateNewMessage', message);\n } */\n\n const pendingMessage = this.checkPendingMessage(message);\n const historyStorage = this.getHistoryStorage(peerId, isLocalThreadUpdate ? threadId : undefined);\n\n if(!isLocalThreadUpdate) {\n this.updateMessageRepliesIfNeeded(message);\n }\n\n // * so message can exist if reloadConversation came back earlier with mid\n const ignoreExisting: boolean = (update as any).ignoreExisting;\n const isExisting = !!historyStorage.history.findSlice(message.mid);\n if(isExisting) {\n if(!ignoreExisting) {\n return false;\n }\n } else {\n // * catch situation with disconnect. if message's id is lower than we already have (in bottom end slice), will sort it\n const firstSlice = historyStorage.history.first;\n if(firstSlice.isEnd(SliceEnd.Bottom)) {\n let i = 0;\n for(const length = firstSlice.length; i < length; ++i) {\n if(message.mid > firstSlice[i]) {\n break;\n }\n }\n\n firstSlice.splice(i, 0, message.mid);\n } else {\n historyStorage.history.unshift(message.mid);\n }\n\n if(historyStorage.count !== null) {\n historyStorage.count++;\n }\n }\n\n if(this.mergeReplyKeyboard(historyStorage, message)) {\n rootScope.dispatchEvent('history_reply_markup', {peerId});\n }\n\n const fromId = message.fromId;\n if(fromId.isUser() && !message.pFlags.out && message.from_id) {\n appUsersManager.forceUserOnline(fromId, message.date);\n\n const action: SendMessageAction = {\n _: 'sendMessageCancelAction'\n };\n\n let update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping;\n if(peerId.isUser()) {\n update = {\n _: 'updateUserTyping',\n action,\n user_id: fromId\n };\n } else if(appPeersManager.isChannel(peerId)) {\n update = {\n _: 'updateChannelUserTyping',\n action,\n channel_id: peerId.toChatId(),\n from_id: appPeersManager.getOutputPeer(fromId),\n top_msg_id: threadId ? appMessagesIdsManager.getServerMessageId(threadId) : undefined\n };\n } else {\n update = {\n _: 'updateChatUserTyping',\n action,\n chat_id: peerId.toChatId(),\n from_id: appPeersManager.getOutputPeer(fromId)\n };\n }\n\n apiUpdatesManager.processLocalUpdate(update);\n }\n\n if(!pendingMessage) {\n this.handleNewMessage(peerId, message.mid);\n }\n\n if(isLocalThreadUpdate) {\n return;\n }\n \n const inboxUnread = !message.pFlags.out && message.pFlags.unread;\n if(dialog) {\n if(inboxUnread && message.mid > dialog.top_message) {\n const releaseUnreadCount = this.dialogsStorage.prepareDialogUnreadCountModifying(dialog);\n\n ++dialog.unread_count;\n if(message.pFlags.mentioned) {\n ++dialog.unread_mentions_count;\n this.modifyCachedMentions(peerId, message.mid, true);\n }\n\n releaseUnreadCount();\n }\n\n if(message.mid >= dialog.top_message) {\n this.setDialogTopMessage(message, dialog);\n }\n }\n\n if(inboxUnread/* && ($rootScope.selectedPeerID != peerID || $rootScope.idle.isIDLE) */) {\n const notifyPeer = peerId;\n let notifyPeerToHandle = this.notificationsToHandle[notifyPeer];\n if(notifyPeerToHandle === undefined) {\n notifyPeerToHandle = this.notificationsToHandle[notifyPeer] = {\n fwdCount: 0,\n fromId: NULL_PEER_ID\n };\n }\n\n if(notifyPeerToHandle.fromId !== fromId) {\n notifyPeerToHandle.fromId = fromId;\n notifyPeerToHandle.fwdCount = 0;\n }\n\n if((message as Message.message).fwd_from) {\n ++notifyPeerToHandle.fwdCount;\n }\n\n notifyPeerToHandle.topMessage = message;\n\n if(!this.notificationsHandlePromise) {\n this.notificationsHandlePromise = window.setTimeout(this.handleNotifications, 0);\n }\n }\n };\n\n private onUpdateMessageReactions = (update: Update.updateMessageReactions) => {\n const {peer, msg_id, reactions} = update;\n const mid = appMessagesIdsManager.generateMessageId(msg_id);\n const peerId = appPeersManager.getPeerId(peer);\n const message: MyMessage = this.getMessageByPeer(peerId, mid);\n\n if(message._ !== 'message') {\n return;\n }\n\n const recentReactions = reactions?.recent_reactions;\n if(recentReactions?.length && message.pFlags.out) {\n const recentReaction = recentReactions[recentReactions.length - 1];\n const previousReactions = message.reactions;\n const previousRecentReactions = previousReactions?.recent_reactions;\n if(\n appPeersManager.getPeerId(recentReaction.peer_id) !== rootScope.myId && (\n !previousRecentReactions ||\n previousRecentReactions.length <= recentReactions.length\n ) && (\n !previousRecentReactions || \n !deepEqual(recentReaction, previousRecentReactions[previousRecentReactions.length - 1])\n )\n ) {\n this.getNotifyPeerSettings(peerId).then(({muted, peerTypeNotifySettings}) => {\n if(muted || !peerTypeNotifySettings.show_previews) return;\n this.notifyAboutMessage(message, {\n userReaction: recentReaction,\n peerTypeNotifySettings\n });\n });\n }\n }\n \n const key = message.peerId + '_' + message.mid;\n this.pushBatchUpdate('messages_reactions', this.batchUpdateReactions, key, () => copy(message.reactions));\n\n message.reactions = reactions;\n\n if(!update.local) {\n this.setDialogToStateIfMessageIsTop(message);\n }\n };\n\n private onUpdateDialogUnreadMark = (update: Update.updateDialogUnreadMark) => {\n //this.log('updateDialogUnreadMark', update);\n const peerId = appPeersManager.getPeerId((update.peer as DialogPeer.dialogPeer).peer);\n const dialog = this.getDialogOnly(peerId);\n\n if(!dialog) {\n this.scheduleHandleNewDialogs(peerId);\n } else {\n const releaseUnreadCount = this.dialogsStorage.prepareDialogUnreadCountModifying(dialog);\n\n if(!update.pFlags.unread) {\n delete dialog.pFlags.unread_mark;\n } else {\n dialog.pFlags.unread_mark = true;\n }\n\n releaseUnreadCount();\n rootScope.dispatchEvent('dialogs_multiupdate', {[peerId]: dialog});\n this.dialogsStorage.setDialogToState(dialog);\n }\n };\n\n private onUpdateEditMessage = (update: Update.updateEditMessage | Update.updateEditChannelMessage) => {\n const message = update.message as MyMessage;\n const peerId = this.getMessagePeer(message);\n const mid = appMessagesIdsManager.generateMessageId(message.id);\n const storage = this.getMessagesStorage(peerId);\n if(!storage.has(mid)) {\n // this.fixDialogUnreadMentionsIfNoMessage(peerId);\n return;\n }\n\n // console.trace(dT(), 'edit message', message)\n \n const oldMessage: Message = this.getMessageFromStorage(storage, mid);\n this.saveMessages([message], {storage});\n const newMessage: Message = this.getMessageFromStorage(storage, mid);\n\n this.handleEditedMessage(oldMessage, newMessage);\n\n const dialog = this.getDialogOnly(peerId);\n\n // if sender erased mention\n /* if(dialog.unread_mentions_count && (oldMessage as Message.message)?.pFlags?.mentioned && !message.pFlags.mentioned) {\n --dialog.unread_mentions_count;\n this.modifyCachedMentions(peerId, mid, false);\n } */\n\n const isTopMessage = dialog && dialog.top_message === mid;\n if((message as Message.messageService).clear_history) {\n if(isTopMessage) {\n rootScope.dispatchEvent('dialog_flush', {peerId});\n }\n } else {\n // no sense in dispatching message_edit since only reactions have changed\n if(oldMessage?._ === 'message' && !deepEqual(oldMessage.reactions, (newMessage as Message.message).reactions)) {\n const newReactions = (newMessage as Message.message).reactions;\n (newMessage as Message.message).reactions = oldMessage.reactions;\n apiUpdatesManager.processLocalUpdate({\n _: 'updateMessageReactions',\n peer: appPeersManager.getOutputPeer(peerId),\n msg_id: message.id,\n reactions: newReactions\n });\n\n return;\n }\n\n rootScope.dispatchEvent('message_edit', {\n storage,\n peerId,\n mid\n });\n\n if(isTopMessage || (message as Message.message).grouped_id) {\n const updatedDialogs: {[peerId: PeerId]: Dialog} = {};\n updatedDialogs[peerId] = dialog;\n rootScope.dispatchEvent('dialogs_multiupdate', updatedDialogs);\n this.dialogsStorage.setDialogToState(dialog);\n }\n }\n };\n\n private onUpdateReadHistory = (update: Update.updateReadChannelDiscussionInbox | Update.updateReadChannelDiscussionOutbox \n | Update.updateReadHistoryInbox | Update.updateReadHistoryOutbox \n | Update.updateReadChannelInbox | Update.updateReadChannelOutbox) => {\n const channelId = (update as Update.updateReadChannelInbox).channel_id;\n const maxId = appMessagesIdsManager.generateMessageId((update as Update.updateReadChannelInbox).max_id || (update as Update.updateReadChannelDiscussionInbox).read_max_id);\n const threadId = appMessagesIdsManager.generateMessageId((update as Update.updateReadChannelDiscussionInbox).top_msg_id);\n const peerId = channelId ? channelId.toPeerId(true) : appPeersManager.getPeerId((update as Update.updateReadHistoryInbox).peer);\n\n const isOut = update._ === 'updateReadHistoryOutbox' || update._ === 'updateReadChannelOutbox' || update._ === 'updateReadChannelDiscussionOutbox' ? true : undefined;\n\n const storage = this.getMessagesStorage(peerId);\n const history = getObjectKeysAndSort(storage, 'desc');\n const foundDialog = this.getDialogOnly(peerId);\n const stillUnreadCount = (update as Update.updateReadChannelInbox).still_unread_count;\n let newUnreadCount = 0;\n let newUnreadMentionsCount = 0;\n let foundAffected = false;\n\n //this.log.warn(dT(), 'read', peerId, isOut ? 'out' : 'in', maxId)\n\n const historyStorage = this.getHistoryStorage(peerId, threadId);\n\n if(peerId.isUser() && isOut) {\n appUsersManager.forceUserOnline(peerId);\n }\n\n if(threadId) {\n const repliesKey = this.threadsToReplies[peerId + '_' + threadId];\n if(repliesKey) {\n const [peerId, mid] = repliesKey.split('_');\n this.updateMessage(peerId.toPeerId(), +mid, 'replies_updated');\n }\n }\n\n const releaseUnreadCount = !threadId && foundDialog && this.dialogsStorage.prepareDialogUnreadCountModifying(foundDialog);\n\n for(let i = 0, length = history.length; i < length; i++) {\n const mid = history[i];\n if(mid > maxId) {\n continue;\n }\n \n const message: MyMessage = storage.get(mid);\n\n if(message.pFlags.out !== isOut) {\n continue;\n }\n\n if(!message.pFlags.unread) {\n break;\n }\n\n if(threadId) {\n const replyTo = message.reply_to;\n if(!replyTo || (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) !== threadId) {\n continue;\n }\n }\n \n // this.log.warn('read', messageId, message.pFlags.unread, message)\n if(message.pFlags.unread) {\n delete message.pFlags.unread;\n if(!foundAffected) {\n foundAffected = true;\n }\n\n if(!message.pFlags.out && !threadId && foundDialog) {\n if(stillUnreadCount === undefined) {\n newUnreadCount = --foundDialog.unread_count;\n }\n\n if(message.pFlags.mentioned) {\n newUnreadMentionsCount = --foundDialog.unread_mentions_count;\n this.modifyCachedMentions(peerId, message.mid, false);\n }\n }\n \n appNotificationsManager.cancel('msg' + mid);\n }\n }\n\n if(isOut) historyStorage.readOutboxMaxId = maxId;\n else historyStorage.readMaxId = maxId;\n\n if(!threadId && foundDialog) {\n if(isOut) foundDialog.read_outbox_max_id = maxId;\n else foundDialog.read_inbox_max_id = maxId;\n\n if(!isOut) {\n let setCount: number;\n if(stillUnreadCount !== undefined) {\n setCount = stillUnreadCount;\n } else if(newUnreadCount < 0 || !this.getReadMaxIdIfUnread(peerId)) {\n setCount = 0;\n } else if(newUnreadCount && foundDialog.top_message > maxId) {\n setCount = newUnreadCount;\n }\n\n if(setCount !== undefined) {\n foundDialog.unread_count = setCount;\n }\n\n if(newUnreadMentionsCount < 0 || !foundDialog.unread_count) {\n foundDialog.unread_mentions_count = 0;\n }\n }\n\n if(releaseUnreadCount) {\n releaseUnreadCount();\n }\n\n this.dialogsStorage.processDialogForFilters(foundDialog);\n \n rootScope.dispatchEvent('dialog_unread', {peerId});\n this.dialogsStorage.setDialogToState(foundDialog);\n }\n\n if(foundAffected) {\n rootScope.dispatchEvent('messages_read');\n }\n\n if(!threadId && channelId) {\n const threadKeyPart = peerId + '_';\n for(const threadKey in this.threadsToReplies) {\n if(threadKey.indexOf(threadKeyPart) === 0) {\n const [peerId, mid] = this.threadsToReplies[threadKey].split('_');\n rootScope.dispatchEvent('replies_updated', this.getMessageByPeer(peerId.toPeerId(), +mid));\n }\n }\n }\n };\n\n private onUpdateReadMessagesContents = (update: Update.updateChannelReadMessagesContents | Update.updateReadMessagesContents) => {\n const channelId = (update as Update.updateChannelReadMessagesContents).channel_id;\n const mids = (update as Update.updateReadMessagesContents).messages.map(id => appMessagesIdsManager.generateMessageId(id));\n const peerId = channelId ? channelId.toPeerId(true) : this.getMessageById(mids[0]).peerId;\n for(let i = 0, length = mids.length; i < length; ++i) {\n const mid = mids[i];\n const message: MyMessage = this.getMessageByPeer(peerId, mid);\n if(!message.deleted) {\n if(message.pFlags.media_unread) {\n delete message.pFlags.media_unread;\n this.setDialogToStateIfMessageIsTop(message);\n \n if(!message.pFlags.out && message.pFlags.mentioned) {\n this.modifyCachedMentions(peerId, mid, false);\n }\n }\n } else {\n this.fixDialogUnreadMentionsIfNoMessage(peerId);\n }\n }\n\n rootScope.dispatchEvent('messages_media_read', {peerId, mids});\n };\n\n private onUpdateChannelAvailableMessages = (update: Update.updateChannelAvailableMessages) => {\n const peerId = update.channel_id.toPeerId(true);\n const history = this.getHistoryStorage(peerId).history.slice;\n const availableMinId = appMessagesIdsManager.generateMessageId(update.available_min_id);\n const messages = history.filter(mid => mid <= availableMinId);\n\n (update as any as Update.updateDeleteChannelMessages).messages = messages;\n this.onUpdateDeleteMessages(update as any as Update.updateDeleteChannelMessages);\n };\n\n private onUpdateDeleteMessages = (update: Update.updateDeleteMessages | Update.updateDeleteChannelMessages) => {\n const channelId = (update as Update.updateDeleteChannelMessages).channel_id;\n //const messages = (update as any as Update.updateDeleteChannelMessages).messages;\n const messages = (update as any as Update.updateDeleteChannelMessages).messages.map(id => appMessagesIdsManager.generateMessageId(id));\n const peerId: PeerId = channelId ? channelId.toPeerId(true) : this.getMessageById(messages[0]).peerId;\n \n if(!peerId) {\n return;\n }\n\n apiManager.clearCache('messages.getSearchCounters', (params) => {\n return appPeersManager.getPeerId(params.peer) === peerId;\n });\n\n const threadKeys: Set<string> = new Set();\n for(const mid of messages) {\n const message = this.getMessageByPeer(peerId, mid);\n const threadKey = this.getThreadKey(message);\n if(threadKey && this.threadsStorage[peerId] && this.threadsStorage[peerId][+threadKey.split('_')[1]]) {\n threadKeys.add(threadKey);\n }\n }\n \n const historyUpdated = this.handleDeletedMessages(peerId, this.getMessagesStorage(peerId), messages);\n\n const threadsStorages = Array.from(threadKeys).map(threadKey => {\n const [peerId, mid] = threadKey.split('_');\n return this.getHistoryStorage(peerId.toPeerId(), +mid);\n });\n\n const historyStorage = this.getHistoryStorage(peerId);\n [historyStorage].concat(threadsStorages).forEach(historyStorage => {\n for(const mid of historyUpdated.msgs) {\n historyStorage.history.delete(mid);\n }\n \n if(historyUpdated.count && historyStorage.count) {\n historyStorage.count = Math.max(0, historyStorage.count - historyUpdated.count);\n }\n });\n\n rootScope.dispatchEvent('history_delete', {peerId, msgs: historyUpdated.msgs});\n\n const foundDialog = this.getDialogOnly(peerId);\n if(foundDialog) {\n const affected = historyUpdated.unreadMentions || historyUpdated.unread;\n const releaseUnreadCount = affected && this.dialogsStorage.prepareDialogUnreadCountModifying(foundDialog);\n \n if(historyUpdated.unread) {\n foundDialog.unread_count = Math.max(0, foundDialog.unread_count - historyUpdated.unread);\n }\n\n if(historyUpdated.unreadMentions) {\n foundDialog.unread_mentions_count = !foundDialog.unread_count ? 0 : Math.max(0, foundDialog.unread_mentions_count - historyUpdated.unreadMentions);\n }\n\n if(affected) {\n releaseUnreadCount();\n rootScope.dispatchEvent('dialog_unread', {peerId});\n }\n\n if(historyUpdated.msgs.has(foundDialog.top_message)) {\n const slice = historyStorage.history.first;\n if(slice.isEnd(SliceEnd.Bottom) && slice.length) {\n const mid = slice[0];\n const message = this.getMessageByPeer(peerId, mid);\n this.setDialogTopMessage(message, foundDialog);\n } else {\n this.reloadConversation(peerId);\n }\n }\n }\n };\n\n private onUpdateChannel = (update: Update.updateChannel) => {\n const channelId = update.channel_id;\n const peerId = channelId.toPeerId(true);\n const channel: Chat.channel = appChatsManager.getChat(channelId);\n\n const needDialog = appChatsManager.isInChat(channelId);\n \n const canViewHistory = !!channel.username || !channel.pFlags.left;\n const hasHistory = this.historiesStorage[peerId] !== undefined;\n \n if(canViewHistory !== hasHistory) {\n delete this.historiesStorage[peerId];\n rootScope.dispatchEvent('history_forbidden', peerId);\n }\n \n const dialog = this.getDialogOnly(peerId);\n if(!!dialog !== needDialog) {\n if(needDialog) {\n this.reloadConversation(peerId);\n } else {\n this.dialogsStorage.dropDialogOnDeletion(peerId);\n }\n }\n\n rootScope.dispatchEvent('channel_update', channelId);\n };\n\n private onUpdateChannelReload = (update: Update.updateChannelReload) => {\n const peerId = update.channel_id.toPeerId(true);\n\n this.dialogsStorage.dropDialog(peerId);\n\n delete this.historiesStorage[peerId];\n this.reloadConversation(peerId).then(() => {\n rootScope.dispatchEvent('history_reload', peerId);\n });\n };\n \n private onUpdateChannelMessageViews = (update: Update.updateChannelMessageViews) => {\n const views = update.views;\n const peerId = update.channel_id.toPeerId(true);\n const mid = appMessagesIdsManager.generateMessageId(update.id);\n const message: Message.message = this.getMessageByPeer(peerId, mid);\n if(!message.deleted && message.views !== undefined && message.views < views) {\n message.views = views;\n this.pushBatchUpdate('messages_views', this.batchUpdateViews, message.peerId + '_' + message.mid);\n this.setDialogToStateIfMessageIsTop(message);\n }\n };\n\n private onUpdateServiceNotification = (update: Update.updateServiceNotification) => {\n //this.log('updateServiceNotification', update);\n if(update.pFlags?.popup) {\n rootScope.dispatchEvent('service_notification', update);\n return;\n }\n \n const fromId = SERVICE_PEER_ID;\n const peerId = fromId;\n const messageId = this.generateTempMessageId(peerId);\n const message: Message.message = {\n _: 'message',\n id: messageId,\n from_id: appPeersManager.getOutputPeer(fromId),\n peer_id: appPeersManager.getOutputPeer(peerId),\n pFlags: {unread: true},\n date: (update.inbox_date || tsNow(true)) + serverTimeManager.serverTimeOffset,\n message: update.message,\n media: update.media,\n entities: update.entities\n };\n if(!appUsersManager.hasUser(fromId)) {\n appUsersManager.saveApiUsers([{\n _: 'user',\n id: fromId,\n pFlags: {verified: true},\n access_hash: '0',\n first_name: 'Telegram',\n phone: '42777'\n }]);\n }\n this.saveMessages([message], {isOutgoing: true});\n\n if(update.inbox_date) {\n this.pendingTopMsgs[peerId] = messageId;\n this.onUpdateNewMessage({\n _: 'updateNewMessage',\n message,\n pts: undefined,\n pts_count: undefined\n });\n }\n };\n\n private onUpdatePinnedMessages = (update: Update.updatePinnedMessages | Update.updatePinnedChannelMessages) => {\n const channelId = update._ === 'updatePinnedChannelMessages' ? update.channel_id : undefined;\n const peerId = channelId ? channelId.toPeerId(true) : appPeersManager.getPeerId((update as Update.updatePinnedMessages).peer);\n\n /* const storage = this.getSearchStorage(peerId, 'inputMessagesFilterPinned');\n if(storage.count !== storage.history.length) {\n if(storage.count !== undefined) {\n delete this.searchesStorage[peerId]['inputMessagesFilterPinned']; \n }\n\n rootScope.broadcast('peer_pinned_messages', peerId);\n break;\n } */\n\n const messages = update.messages.map(id => appMessagesIdsManager.generateMessageId(id)); \n\n const storage = this.getMessagesStorage(peerId);\n const missingMessages = messages.filter(mid => !storage.has(mid));\n const getMissingPromise = missingMessages.length ? Promise.all(missingMessages.map(mid => this.wrapSingleMessage(peerId, mid))) : Promise.resolve();\n getMissingPromise.finally(() => {\n const werePinned = update.pFlags?.pinned;\n if(werePinned) {\n for(const mid of messages) {\n //storage.history.push(mid);\n const message = storage.get(mid);\n message.pFlags.pinned = true;\n }\n\n /* if(this.pinnedMessages[peerId]?.maxId) {\n const maxMid = Math.max(...messages);\n this.pinnedMessages\n } */\n\n //storage.history.sort((a, b) => b - a);\n } else {\n for(const mid of messages) {\n //storage.history.findAndSplice(_mid => _mid === mid);\n const message = storage.get(mid);\n delete message.pFlags.pinned;\n }\n }\n\n /* const info = this.pinnedMessages[peerId];\n if(info) {\n info.count += messages.length * (werePinned ? 1 : -1);\n } */\n \n delete this.pinnedMessages[peerId];\n appStateManager.getState().then(state => {\n delete state.hiddenPinnedMessages[peerId];\n rootScope.dispatchEvent('peer_pinned_messages', {peerId, mids: messages, pinned: werePinned});\n });\n });\n };\n\n private onUpdateNotifySettings = (update: Update.updateNotifySettings) => {\n const {peer, notify_settings} = update;\n if(peer._ === 'notifyPeer') {\n const peerId = appPeersManager.getPeerId((peer as NotifyPeer.notifyPeer).peer);\n \n const dialog = this.getDialogOnly(peerId);\n if(dialog) {\n dialog.notify_settings = notify_settings;\n rootScope.dispatchEvent('dialog_notify_settings', dialog);\n this.dialogsStorage.setDialogToState(dialog);\n }\n }\n };\n\n private onUpdateNewScheduledMessage = (update: Update.updateNewScheduledMessage) => {\n const message = update.message as MyMessage;\n const peerId = this.getMessagePeer(message);\n\n const storage = this.scheduledMessagesStorage[peerId];\n if(storage) {\n const mid = appMessagesIdsManager.generateMessageId(message.id);\n\n const oldMessage = this.getMessageFromStorage(storage, mid);\n this.saveMessages([message], {storage, isScheduled: true});\n const newMessage = this.getMessageFromStorage(storage, mid);\n\n if(!oldMessage.deleted) {\n this.handleEditedMessage(oldMessage, newMessage);\n rootScope.dispatchEvent('message_edit', {storage, peerId, mid: message.mid});\n } else {\n const pendingMessage = this.checkPendingMessage(message);\n if(!pendingMessage) {\n rootScope.dispatchEvent('scheduled_new', {peerId, mid: message.mid});\n }\n }\n }\n };\n\n private onUpdateDeleteScheduledMessages = (update: Update.updateDeleteScheduledMessages) => {\n const peerId = appPeersManager.getPeerId(update.peer);\n\n const storage = this.scheduledMessagesStorage[peerId];\n if(storage) {\n const mids = update.messages.map(id => appMessagesIdsManager.generateMessageId(id));\n this.handleDeletedMessages(peerId, storage, mids);\n\n rootScope.dispatchEvent('scheduled_delete', {peerId, mids});\n }\n };\n\n public setDialogToStateIfMessageIsTop(message: MyMessage) {\n if(this.isMessageIsTopMessage(message)) {\n this.dialogsStorage.setDialogToState(this.getDialogOnly(message.peerId));\n }\n }\n\n public isMessageIsTopMessage(message: MyMessage) {\n const dialog = this.getDialogOnly(message.peerId);\n return dialog && dialog.top_message === message.mid;\n }\n\n private updateMessageRepliesIfNeeded(threadMessage: MyMessage) {\n try { // * на всякий случай, скорее всего это не понадобится\n const threadKey = this.getThreadKey(threadMessage);\n if(threadKey) {\n const repliesKey = this.threadsToReplies[threadKey];\n if(repliesKey) {\n const [peerId, mid] = repliesKey.split('_');\n\n this.updateMessage(peerId.toPeerId(), +mid, 'replies_updated');\n }\n }\n } catch(err) {\n this.log.error('incrementMessageReplies err', err, threadMessage);\n }\n }\n\n private getThreadKey(threadMessage: MyMessage) {\n let threadKey = '';\n if(threadMessage.peerId?.isAnyChat() && threadMessage.reply_to) {\n const threadId = threadMessage.reply_to.reply_to_top_id || threadMessage.reply_to.reply_to_msg_id;\n threadKey = threadMessage.peerId + '_' + threadId;\n }\n\n return threadKey;\n }\n\n public updateMessage(peerId: PeerId, mid: number, broadcastEventName?: 'replies_updated'): Promise<Message.message> {\n const promise: Promise<Message.message> = this.wrapSingleMessage(peerId, mid, true).then(() => {\n const message = this.getMessageByPeer(peerId, mid);\n\n if(broadcastEventName) {\n rootScope.dispatchEvent(broadcastEventName, message);\n }\n\n return message;\n });\n \n return promise;\n }\n\n private checkPendingMessage(message: MyMessage) {\n const randomId = this.pendingByMessageId[message.mid];\n let pendingMessage: ReturnType<AppMessagesManager['finalizePendingMessage']>;\n if(randomId) {\n const pendingData = this.pendingByRandomId[randomId];\n if(pendingMessage = this.finalizePendingMessage(randomId, message)) {\n rootScope.dispatchEvent('history_update', {storage: pendingData.storage, peerId: message.peerId, mid: message.mid});\n }\n\n delete this.pendingByMessageId[message.mid];\n }\n\n return pendingMessage;\n }\n\n public mutePeer(peerId: PeerId, muteUntil: number) {\n const settings: InputPeerNotifySettings = {\n _: 'inputPeerNotifySettings'\n };\n\n settings.mute_until = muteUntil;\n\n return appNotificationsManager.updateNotifySettings({\n _: 'inputNotifyPeer',\n peer: appPeersManager.getInputPeerById(peerId)\n }, settings);\n }\n\n public togglePeerMute(peerId: PeerId, mute?: boolean) {\n if(mute === undefined) {\n mute = !appNotificationsManager.isPeerLocalMuted(peerId, false);\n }\n\n return this.mutePeer(peerId, mute ? MUTE_UNTIL : 0);\n }\n\n public canSendToPeer(peerId: PeerId, threadId?: number, action: ChatRights = 'send_messages') {\n if(appPeersManager.isRestricted(peerId)) {\n return false;\n }\n \n if(peerId.isAnyChat()) {\n //const isChannel = appPeersManager.isChannel(peerId);\n const chat: Chat.chat = appChatsManager.getChat(peerId.toChatId());\n const hasRights = /* isChannel && */appChatsManager.hasRights(peerId.toChatId(), action, undefined, !!threadId); \n return /* !isChannel || */hasRights && (!chat.pFlags.left || !!threadId);\n } else {\n return appUsersManager.canSendToUser(peerId);\n }\n }\n\n public finalizePendingMessage(randomId: Long, finalMessage: MyMessage) {\n const pendingData = this.pendingByRandomId[randomId];\n // this.log('pdata', randomID, pendingData)\n\n if(pendingData) {\n const {peerId, tempId, threadId, storage} = pendingData;\n\n [this.getHistoryStorage(peerId), threadId ? this.getHistoryStorage(peerId, threadId) : undefined]\n .filter(Boolean)\n .forEach(storage => {\n storage.history.delete(tempId);\n });\n\n // this.log('pending', randomID, historyStorage.pending)\n\n const tempMessage: MyMessage = this.getMessageFromStorage(storage, tempId);\n if(!tempMessage.deleted) {\n delete finalMessage.pFlags.is_outgoing;\n delete finalMessage.pending;\n delete finalMessage.error;\n delete finalMessage.random_id;\n delete finalMessage.send;\n }\n\n rootScope.dispatchEvent('messages_pending');\n \n delete this.pendingByRandomId[randomId];\n\n this.finalizePendingMessageCallbacks(storage, tempId, finalMessage);\n\n return tempMessage;\n }\n }\n\n public finalizePendingMessageCallbacks(storage: MessagesStorage, tempId: number, message: MyMessage) {\n const callbacks = this.tempFinalizeCallbacks[tempId];\n //this.log.warn(callbacks, tempId);\n if(callbacks !== undefined) {\n for(const name in callbacks) {\n const {deferred, callback} = callbacks[name];\n //this.log(`finalizePendingMessageCallbacks: will invoke ${name} callback`);\n callback(message).then(deferred.resolve, deferred.reject);\n }\n\n delete this.tempFinalizeCallbacks[tempId];\n }\n\n // set cached url to media\n if((message as Message.message).media) {\n assumeType<Message.message>(message);\n const {photo: newPhoto, document: newDoc} = message.media as any;\n if(newPhoto) {\n const photo = appPhotosManager.getPhoto('' + tempId);\n if(/* photo._ !== 'photoEmpty' */photo) {\n const newPhotoSize = newPhoto.sizes[newPhoto.sizes.length - 1];\n const cacheContext = appDownloadManager.getCacheContext(newPhoto, newPhotoSize.type);\n const oldCacheContext = appDownloadManager.getCacheContext(photo, 'full');\n Object.assign(cacheContext, oldCacheContext);\n\n const photoSize = newPhoto.sizes[newPhoto.sizes.length - 1] as PhotoSize.photoSize;\n\n const downloadOptions = appPhotosManager.getPhotoDownloadOptions(newPhoto, photoSize);\n const fileName = getFileNameByLocation(downloadOptions.location);\n appDownloadManager.fakeDownload(fileName, oldCacheContext.url);\n }\n } else if(newDoc) {\n const oldDoc = appDocsManager.getDoc('' + tempId);\n if(oldDoc) {\n const oldCacheContext = appDownloadManager.getCacheContext(oldDoc);\n if(\n /* doc._ !== 'documentEmpty' && */\n oldDoc.type && \n oldDoc.type !== 'sticker' && \n oldDoc.mime_type !== 'image/gif' && \n oldCacheContext.url\n ) {\n const cacheContext = appDownloadManager.getCacheContext(newDoc);\n Object.assign(cacheContext, oldCacheContext);\n\n const fileName = appDocsManager.getInputFileName(newDoc);\n appDownloadManager.fakeDownload(fileName, oldCacheContext.url);\n }\n }\n } else if((message.media as MessageMedia.messageMediaPoll).poll) {\n delete appPollsManager.polls[tempId];\n delete appPollsManager.results[tempId];\n }\n }\n\n const tempMessage = this.getMessageFromStorage(storage, tempId);\n storage.delete(tempId);\n \n this.handleReleasingMessage(tempMessage, storage);\n\n rootScope.dispatchEvent('message_sent', {storage, tempId, tempMessage, mid: message.mid, message});\n }\n\n public incrementMaxSeenId(maxId: number) {\n if(!maxId || !(!this.maxSeenId || maxId > this.maxSeenId)) {\n return false;\n }\n\n this.maxSeenId = maxId;\n appStateManager.pushToState('maxSeenMsgId', maxId);\n\n apiManager.invokeApi('messages.receivedMessages', {\n max_id: appMessagesIdsManager.getServerMessageId(maxId)\n });\n }\n\n public getMessageReactionsListAndReadParticipants(\n message: Message.message, \n limit?: number, \n reaction?: string, \n offset?: string,\n skipReadParticipants?: boolean,\n skipReactionsList?: boolean\n ) {\n const emptyMessageReactionsList = {\n reactions: [] as MessagePeerReaction[],\n count: 0,\n next_offset: undefined as string\n };\n\n const canViewMessageReadParticipants = this.canViewMessageReadParticipants(message);\n if(canViewMessageReadParticipants && limit === undefined) {\n limit = 100;\n } else if(limit === undefined) {\n limit = 50;\n }\n\n return Promise.all([\n canViewMessageReadParticipants && !reaction && !skipReadParticipants ? this.getMessageReadParticipants(message.peerId, message.mid).catch(() => [] as UserId[]) : [] as UserId[],\n\n message.reactions?.recent_reactions?.length && !skipReactionsList ? appReactionsManager.getMessageReactionsList(message.peerId, message.mid, limit, reaction, offset).catch(err => emptyMessageReactionsList) : emptyMessageReactionsList\n ]).then(([userIds, messageReactionsList]) => {\n const readParticipantsPeerIds = userIds.map(userId => userId.toPeerId());\n \n const filteredReadParticipants = readParticipantsPeerIds.slice();\n forEachReverse(filteredReadParticipants, (peerId, idx, arr) => {\n if(messageReactionsList.reactions.some(reaction => appPeersManager.getPeerId(reaction.peer_id) === peerId)) {\n arr.splice(idx, 1);\n }\n });\n\n let combined: {peerId: PeerId, reaction?: string}[] = messageReactionsList.reactions.map(reaction => ({peerId: appPeersManager.getPeerId(reaction.peer_id), reaction: reaction.reaction}));\n combined = combined.concat(filteredReadParticipants.map(readPeerId => ({peerId: readPeerId})));\n \n return {\n reactions: messageReactionsList.reactions,\n reactionsCount: messageReactionsList.count,\n readParticipants: readParticipantsPeerIds,\n combined: combined,\n nextOffset: messageReactionsList.next_offset\n };\n });\n }\n\n public getMessageReadParticipants(peerId: PeerId, mid: number): Promise<UserId[]> {\n return apiManager.invokeApiSingle('messages.getMessageReadParticipants', {\n peer: appPeersManager.getInputPeerById(peerId),\n msg_id: appMessagesIdsManager.getServerMessageId(mid)\n }).then(userIds => { // ! convert long to number\n return userIds.map(userId => userId.toUserId());\n });\n }\n\n public canViewMessageReadParticipants(message: Message) {\n if(\n message._ !== 'message' || \n message.pFlags.is_outgoing || \n !message.pFlags.out || \n !appPeersManager.isAnyGroup(message.peerId)\n ) {\n return false;\n }\n\n const chat: Chat.chat | Chat.channel = appChatsManager.getChat(message.peerId.toChatId());\n return chat.participants_count < rootScope.appConfig.chat_read_mark_size_threshold && \n (tsNow(true) - message.date) < rootScope.appConfig.chat_read_mark_expire_period;\n }\n\n public incrementMessageViews(peerId: PeerId, mids: number[]) {\n if(!mids.length) {\n return;\n }\n\n return apiManager.invokeApiSingle('messages.getMessagesViews', {\n peer: appPeersManager.getInputPeerById(peerId),\n id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid)),\n increment: true\n }).then(views => {\n const updates: Update[] = new Array(mids.length);\n const channelId = peerId.toChatId();\n for(let i = 0, length = mids.length; i < length; ++i) {\n updates[i] = {\n _: 'updateChannelMessageViews',\n channel_id: channelId,\n id: mids[i],\n views: views.views[i].views\n };\n }\n\n apiUpdatesManager.processUpdateMessage({\n _: 'updates',\n updates,\n chats: views.chats,\n users: views.users\n });\n });\n }\n\n private notifyAboutMessage(message: MyMessage, options: Partial<{\n fwdCount: number,\n userReaction: MessagePeerReaction,\n peerTypeNotifySettings: PeerNotifySettings\n }> = {}) {\n const peerId = this.getMessagePeer(message);\n\n if(appPeersManager.isRestricted(peerId)) {\n return;\n }\n\n const isAnyChat = peerId.isAnyChat();\n const notification: NotifyOptions = {};\n const peerString = appPeersManager.getPeerString(peerId);\n let notificationMessage: string;\n\n if(options.peerTypeNotifySettings.show_previews) {\n if(message._ === 'message' && message.fwd_from && options.fwdCount) {\n notificationMessage = I18n.format('Notifications.Forwarded', true, [options.fwdCount]);\n } else {\n notificationMessage = this.wrapMessageForReply(message, undefined, undefined, true);\n\n if(options.userReaction) {\n const langPackKey: LangPackKey = /* isAnyChat ? 'Notification.Group.Reacted' : */'Notification.Contact.Reacted';\n const args: FormatterArguments = [\n RichTextProcessor.fixEmoji(options.userReaction.reaction), // can be plain heart\n notificationMessage\n ];\n \n /* if(isAnyChat) {\n args.unshift(appPeersManager.getPeerTitle(message.fromId, true));\n } */\n \n notificationMessage = I18n.format(langPackKey, true, args);\n }\n }\n } else {\n notificationMessage = I18n.format('Notifications.New', true);\n }\n\n if(options.userReaction) {\n notification.noIncrement = true;\n notification.silent = true;\n }\n\n notification.title = appPeersManager.getPeerTitle(peerId, true);\n if(isAnyChat && message.fromId !== message.peerId) {\n notification.title = appPeersManager.getPeerTitle(message.fromId, true) +\n ' @ ' +\n notification.title;\n }\n\n notification.title = RichTextProcessor.wrapPlainText(notification.title);\n\n notification.onclick = () => {\n rootScope.dispatchEvent('history_focus', {peerId, mid: message.mid});\n };\n\n notification.message = notificationMessage;\n notification.key = 'msg' + message.mid;\n notification.tag = peerString;\n notification.silent = true;//message.pFlags.silent || false;\n\n const peerPhoto = appPeersManager.getPeerPhoto(peerId);\n if(peerPhoto) {\n appAvatarsManager.loadAvatar(peerId, peerPhoto, 'photo_small').loadPromise.then(url => {\n if(message.pFlags.unread || options.userReaction) {\n notification.image = url;\n appNotificationsManager.notify(notification);\n }\n });\n } else {\n appNotificationsManager.notify(notification);\n }\n }\n\n public getScheduledMessagesStorage(peerId: PeerId) {\n return this.scheduledMessagesStorage[peerId] ?? (this.scheduledMessagesStorage[peerId] = this.createMessageStorage());\n }\n\n public getScheduledMessageByPeer(peerId: PeerId, mid: number) {\n return this.getMessageFromStorage(this.getScheduledMessagesStorage(peerId), mid);\n }\n\n public getScheduledMessages(peerId: PeerId): Promise<number[]> {\n if(!this.canSendToPeer(peerId)) return Promise.resolve([]);\n\n const storage = this.getScheduledMessagesStorage(peerId);\n if(storage.size) {\n return Promise.resolve([...storage.keys()]);\n }\n\n return apiManager.invokeApiSingle('messages.getScheduledHistory', {\n peer: appPeersManager.getInputPeerById(peerId),\n hash: ''\n }).then(historyResult => {\n if(historyResult._ !== 'messages.messagesNotModified') {\n appUsersManager.saveApiUsers(historyResult.users);\n appChatsManager.saveApiChats(historyResult.chats);\n \n const storage = this.getScheduledMessagesStorage(peerId);\n this.saveMessages(historyResult.messages, {storage, isScheduled: true});\n return [...storage.keys()];\n }\n \n return [];\n });\n }\n\n public sendScheduledMessages(peerId: PeerId, mids: number[]) {\n return apiManager.invokeApi('messages.sendScheduledMessages', {\n peer: appPeersManager.getInputPeerById(peerId),\n id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid))\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public deleteScheduledMessages(peerId: PeerId, mids: number[]) {\n return apiManager.invokeApi('messages.deleteScheduledMessages', {\n peer: appPeersManager.getInputPeerById(peerId),\n id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid))\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public getMessageWithReplies(message: Message.message) {\n if(message.peerId !== REPLIES_PEER_ID) {\n message = this.filterMessages(message, message => !!(message as Message.message).replies)[0] as any;\n if(!(message && message.replies && message.replies.pFlags.comments && message.replies.channel_id !== '777')) {\n return;\n }\n }\n\n return message;\n }\n\n public isFetchIntervalNeeded(peerId: PeerId) {\n return peerId.isAnyChat() && !appChatsManager.isInChat(peerId.toChatId());\n }\n\n public isRestricted(message: Message.message) {\n return !!(message.restriction_reason && isRestricted(message.restriction_reason));\n }\n\n public async getNewHistory(peerId: PeerId, threadId?: number) {\n if(!this.isFetchIntervalNeeded(peerId)) {\n return;\n }\n\n const historyStorage = this.getHistoryStorage(peerId, threadId);\n const slice = historyStorage.history.slice;\n if(!slice.isEnd(SliceEnd.Bottom)) {\n return;\n }\n\n delete historyStorage.maxId;\n slice.unsetEnd(SliceEnd.Bottom);\n\n // if there is no id - then request by first id because cannot request by id 0 with backLimit\n let historyResult = this.getHistory(peerId, slice[0] ?? 1, 0, 50, threadId);\n if(historyResult instanceof Promise) {\n historyResult = await historyResult;\n }\n\n for(let i = 0, length = historyResult.history.length; i < length; ++i) {\n this.handleNewMessage(peerId, historyResult.history[i]);\n }\n\n return historyStorage;\n }\n\n /**\n * * https://core.telegram.org/api/offsets, offset_id is inclusive\n */\n public getHistory(peerId: PeerId, maxId = 0, limit: number, backLimit?: number, threadId?: number): Promise<HistoryResult> | HistoryResult {\n const historyStorage = this.getHistoryStorage(peerId, threadId);\n\n if(appPeersManager.isRestricted(peerId)) {\n const first = historyStorage.history.first;\n first.setEnd(SliceEnd.Both);\n\n const slice = first.slice(0, 0);\n slice.setEnd(SliceEnd.Both);\n \n return {\n count: 0,\n history: slice,\n offsetIdOffset: 0\n };\n }\n\n let offset = 0;\n /* \n let offsetFound = true;\n\n if(maxId) {\n offsetFound = false;\n for(; offset < historyStorage.history.length; offset++) {\n if(maxId > historyStorage.history.slice[offset]) {\n offsetFound = true;\n break;\n }\n }\n }\n\n if(offsetFound && (\n historyStorage.count !== null && historyStorage.history.length === historyStorage.count ||\n historyStorage.history.length >= offset + limit\n )) {\n if(backLimit) {\n backLimit = Math.min(offset, backLimit);\n offset = Math.max(0, offset - backLimit);\n limit += backLimit;\n } else {\n limit = limit;\n }\n\n const history = historyStorage.history.slice.slice(offset, offset + limit);\n return {\n count: historyStorage.count,\n history: history,\n offsetIdOffset: offset\n };\n }\n\n if(offsetFound) {\n offset = 0;\n } */\n\n if(backLimit) {\n offset = -backLimit;\n limit += backLimit;\n\n /* return this.requestHistory(reqPeerId, maxId, limit, offset, undefined, threadId).then((historyResult) => {\n historyStorage.count = (historyResult as MessagesMessages.messagesMessagesSlice).count || historyResult.messages.length;\n\n const history = (historyResult.messages as MyMessage[]).map(message => message.mid);\n return {\n count: historyStorage.count,\n history,\n offsetIdOffset: (historyResult as MessagesMessages.messagesMessagesSlice).offset_id_offset || 0\n };\n }); */\n }\n\n const haveSlice = historyStorage.history.sliceMe(maxId, offset, limit);\n if(haveSlice && (haveSlice.slice.length === limit || (haveSlice.fulfilled & SliceEnd.Both) === SliceEnd.Both)) {\n return {\n count: historyStorage.count,\n history: haveSlice.slice,\n offsetIdOffset: haveSlice.offsetIdOffset\n }; \n }\n\n return this.fillHistoryStorage(peerId, maxId, limit, offset, historyStorage, threadId).then(() => {\n const slice = historyStorage.history.sliceMe(maxId, offset, limit);\n return {\n count: historyStorage.count,\n history: slice?.slice || historyStorage.history.constructSlice(),\n offsetIdOffset: slice?.offsetIdOffset || historyStorage.count\n };\n });\n }\n\n public isHistoryResultEnd(historyResult: Exclude<MessagesMessages, MessagesMessages.messagesMessagesNotModified>, limit: number, add_offset: number) {\n const {offset_id_offset, messages} = historyResult as MessagesMessages.messagesMessagesSlice;\n\n const count = (historyResult as MessagesMessages.messagesMessagesSlice).count || messages.length;\n const offsetIdOffset = offset_id_offset || 0;\n\n const topWasMeantToLoad = add_offset < 0 ? limit + add_offset : limit;\n\n const isTopEnd = offsetIdOffset >= (count - topWasMeantToLoad) || count < topWasMeantToLoad;\n const isBottomEnd = !offsetIdOffset || (add_offset < 0 && (offsetIdOffset + add_offset) <= 0);\n\n return {count, offsetIdOffset, isTopEnd, isBottomEnd};\n }\n\n public mergeHistoryResult(slicedArray: SlicedArray<number>, \n historyResult: Parameters<AppMessagesManager['isHistoryResultEnd']>[0], \n offset_id: number, \n limit: number, \n add_offset: number) {\n const {messages} = historyResult as MessagesMessages.messagesMessagesSlice;\n const isEnd = this.isHistoryResultEnd(historyResult, limit, add_offset);\n const {count, offsetIdOffset, isTopEnd, isBottomEnd} = isEnd;\n const mids = messages.map((message) => {\n return (message as MyMessage).mid;\n });\n\n // * add bound manually. \n // * offset_id will be inclusive only if there is 'add_offset' <= -1 (-1 - will only include the 'offset_id')\n // * check that offset_id is not 0\n if(offset_id && appMessagesIdsManager.getServerMessageId(offset_id) && !mids.includes(offset_id) && offsetIdOffset < count) {\n let i = 0;\n for(const length = mids.length; i < length; ++i) {\n if(offset_id > mids[i]) {\n break;\n }\n }\n\n mids.splice(i, 0, offset_id);\n }\n\n const slice = slicedArray.insertSlice(mids) || slicedArray.slice;\n if(isTopEnd) {\n slice.setEnd(SliceEnd.Top);\n }\n \n if(isBottomEnd) {\n slice.setEnd(SliceEnd.Bottom);\n }\n\n return {slice, mids, messages, ...isEnd};\n }\n\n public fillHistoryStorage(peerId: PeerId, offset_id: number, limit: number, add_offset: number, historyStorage: HistoryStorage, threadId?: number): Promise<void> {\n return this.requestHistory(peerId, offset_id, limit, add_offset, undefined, threadId).then((historyResult) => {\n const {count, isBottomEnd, slice, messages} = this.mergeHistoryResult(historyStorage.history, historyResult, offset_id, limit, add_offset);\n\n historyStorage.count = count;\n\n /* if(!maxId && historyResult.messages.length) {\n maxId = this.incrementMessageId((historyResult.messages[0] as MyMessage).mid, 1);\n }\n\n const wasTotalCount = historyStorage.history.length; */\n\n for(let i = 0, length = messages.length; i < length; ++i) {\n const message = messages[i] as MyMessage;\n if(this.mergeReplyKeyboard(historyStorage, message)) {\n rootScope.dispatchEvent('history_reply_markup', {peerId});\n }\n }\n\n if(isBottomEnd) {\n historyStorage.maxId = slice[0]; // ! WARNING\n }\n \n /* const isBackLimit = offset < 0 && -offset !== fullLimit;\n if(isBackLimit) {\n return;\n }\n\n const totalCount = historyStorage.history.length;\n fullLimit -= (totalCount - wasTotalCount);\n\n const migratedNextPeer = this.migratedFromTo[peerId];\n const migratedPrevPeer = this.migratedToFrom[peerId]\n const isMigrated = migratedNextPeer !== undefined || migratedPrevPeer !== undefined;\n\n if(isMigrated) {\n historyStorage.count = Math.max(historyStorage.count, totalCount) + 1;\n }\n\n if(fullLimit > 0) {\n maxId = historyStorage.history.slice[totalCount - 1];\n if(isMigrated) {\n if(!historyResult.messages.length) {\n if(migratedPrevPeer) {\n maxId = 0;\n peerId = migratedPrevPeer;\n } else {\n historyStorage.count = totalCount;\n return true;\n }\n }\n\n return this.fillHistoryStorage(peerId, maxId, fullLimit, historyStorage, threadId);\n } else if(totalCount < historyStorage.count) {\n return this.fillHistoryStorage(peerId, maxId, fullLimit, offset, historyStorage, threadId);\n }\n } */\n });\n }\n\n public requestHistory(peerId: PeerId, maxId: number, limit = 0, offset = 0, offsetDate = 0, threadId = 0): Promise<Exclude<MessagesMessages, MessagesMessages.messagesMessagesNotModified>> {\n //console.trace('requestHistory', peerId, maxId, limit, offset);\n\n //rootScope.broadcast('history_request');\n\n const options: any = {\n peer: appPeersManager.getInputPeerById(peerId),\n offset_id: appMessagesIdsManager.getServerMessageId(maxId) || 0,\n offset_date: offsetDate,\n add_offset: offset,\n limit,\n max_id: 0,\n min_id: 0,\n hash: 0\n };\n\n if(threadId) {\n options.msg_id = appMessagesIdsManager.getServerMessageId(threadId) || 0;\n }\n\n const promise: ReturnType<AppMessagesManager['requestHistory']> = apiManager.invokeApiSingle(threadId ? 'messages.getReplies' : 'messages.getHistory', options, {\n //timeout: APITIMEOUT,\n noErrorBox: true\n }) as any;\n\n return promise.then((historyResult) => {\n if(DEBUG) {\n this.log('requestHistory result:', peerId, historyResult, maxId, limit, offset);\n }\n\n appUsersManager.saveApiUsers(historyResult.users);\n appChatsManager.saveApiChats(historyResult.chats);\n this.saveMessages(historyResult.messages);\n\n if(appPeersManager.isChannel(peerId)) {\n apiUpdatesManager.addChannelState(peerId.toChatId(), (historyResult as MessagesMessages.messagesChannelMessages).pts);\n }\n\n let length = historyResult.messages.length, count = (historyResult as MessagesMessages.messagesMessagesSlice).count;\n if(length && historyResult.messages[length - 1].deleted) {\n historyResult.messages.splice(length - 1, 1);\n length--;\n count--;\n }\n\n // will load more history if last message is album grouped (because it can be not last item)\n // historyResult.messages: desc sorted\n const historyStorage = this.getHistoryStorage(peerId, threadId);\n const oldestMessage: Message.message = historyResult.messages[length - 1] as any;\n if(length && oldestMessage.grouped_id) {\n const foundSlice = historyStorage.history.findSlice(oldestMessage.mid);\n if(foundSlice && (foundSlice.slice.length + historyResult.messages.length) < count) {\n return this.requestHistory(peerId, oldestMessage.mid, 10, 0, offsetDate, threadId).then((_historyResult) => {\n return historyResult;\n });\n }\n }\n\n return historyResult;\n }, (error) => {\n switch (error.type) {\n case 'CHANNEL_PRIVATE':\n let channel = appChatsManager.getChat(peerId.toChatId());\n channel = {_: 'channelForbidden', access_hash: channel.access_hash, title: channel.title};\n apiUpdatesManager.processUpdateMessage({\n _: 'updates',\n updates: [{\n _: 'updateChannel',\n channel_id: peerId.toChatId()\n }],\n chats: [channel],\n users: []\n });\n break;\n }\n\n throw error;\n });\n }\n\n public fetchSingleMessages() {\n if(this.fetchSingleMessagesPromise) {\n return this.fetchSingleMessagesPromise;\n }\n\n return this.fetchSingleMessagesPromise = new Promise((resolve) => {\n setTimeout(() => {\n const requestPromises: Promise<void>[] = [];\n \n for(const [peerId, map] of this.needSingleMessages) {\n const mids = [...map.keys()];\n const msgIds: InputMessage[] = mids.map((mid) => {\n return {\n _: 'inputMessageID',\n id: appMessagesIdsManager.getServerMessageId(mid)\n };\n });\n \n let promise: Promise<MethodDeclMap['channels.getMessages']['res'] | MethodDeclMap['messages.getMessages']['res']>;\n if(peerId.isAnyChat() && appPeersManager.isChannel(peerId)) {\n promise = apiManager.invokeApiSingle('channels.getMessages', {\n channel: appChatsManager.getChannelInput(peerId.toChatId()),\n id: msgIds\n });\n } else {\n promise = apiManager.invokeApiSingle('messages.getMessages', {\n id: msgIds\n });\n }\n\n const after = promise.then(getMessagesResult => {\n assumeType<Exclude<MessagesMessages.messagesMessages, MessagesMessages.messagesMessagesNotModified>>(getMessagesResult);\n\n appUsersManager.saveApiUsers(getMessagesResult.users);\n appChatsManager.saveApiChats(getMessagesResult.chats);\n this.saveMessages(getMessagesResult.messages);\n\n for(let i = 0; i < getMessagesResult.messages.length; ++i) {\n const message = getMessagesResult.messages[i];\n const mid = appMessagesIdsManager.generateMessageId(message.id);\n const promise = map.get(mid);\n promise.resolve(getMessagesResult.messages[i]);\n map.delete(mid);\n }\n\n if(map.size) {\n for(const [mid, promise] of map) {\n promise.resolve(this.generateEmptyMessage(mid));\n }\n }\n }).finally(() => {\n rootScope.dispatchEvent('messages_downloaded', {peerId, mids});\n });\n \n requestPromises.push(after);\n }\n\n this.needSingleMessages.clear();\n\n Promise.all(requestPromises).finally(() => {\n this.fetchSingleMessagesPromise = null;\n if(this.needSingleMessages.size) this.fetchSingleMessages();\n resolve();\n });\n }, 0);\n });\n }\n\n public wrapSingleMessage(peerId: PeerId, mid: number, overwrite = false): Promise<Message> {\n const message = this.getMessageByPeer(peerId, mid);\n if(!message.deleted && !overwrite) {\n rootScope.dispatchEvent('messages_downloaded', {peerId, mids: [mid]});\n return Promise.resolve(message);\n } else {\n let map = this.needSingleMessages.get(peerId);\n if(!map) {\n this.needSingleMessages.set(peerId, map = new Map());\n }\n\n let promise = map.get(mid);\n if(promise) {\n return promise;\n }\n\n promise = deferredPromise();\n map.set(mid, promise);\n this.fetchSingleMessages();\n return promise;\n }\n }\n\n public fetchMessageReplyTo(message: MyMessage): Promise<Message> {\n if(!message.reply_to_mid) return Promise.resolve(this.generateEmptyMessage(0));\n const replyToPeerId = message.reply_to.reply_to_peer_id ? appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : message.peerId;\n return this.wrapSingleMessage(replyToPeerId, message.reply_to_mid).then(originalMessage => {\n if(originalMessage.deleted) { // ! чтобы не пыталось бесконечно загрузить удалённое сообщение\n delete message.reply_to_mid; // ! WARNING!\n }\n\n return originalMessage;\n });\n }\n\n public setTyping(peerId: PeerId, action: SendMessageAction, force?: boolean): Promise<boolean> {\n let typing = this.typings[peerId];\n if(!rootScope.myId || \n !peerId || \n !this.canSendToPeer(peerId) || \n peerId === rootScope.myId ||\n // (!force && deepEqual(typing?.action, action))\n (!force && typing?.action?._ === action._)\n ) {\n return Promise.resolve(false);\n }\n\n if(typing?.timeout) {\n clearTimeout(typing.timeout);\n }\n\n typing = this.typings[peerId] = {\n action\n };\n\n return apiManager.invokeApi('messages.setTyping', {\n peer: appPeersManager.getInputPeerById(peerId),\n action\n }).finally(() => {\n if(typing === this.typings[peerId]) {\n typing.timeout = window.setTimeout(() => {\n delete this.typings[peerId];\n }, 6000);\n }\n });\n }\n\n private handleReleasingMessage(message: MyMessage, storage: MessagesStorage) {\n const media = (message as Message.message).media;\n if(media) {\n const c = (media as MessageMedia.messageMediaWebPage).webpage as WebPage.webPage || media as MessageMedia.messageMediaPhoto | MessageMedia.messageMediaDocument;\n const smth: Photo.photo | MyDocument = (c as MessageMedia.messageMediaPhoto).photo as any || (c as MessageMedia.messageMediaDocument).document as any;\n\n if(smth?.file_reference) {\n referenceDatabase.deleteContext(smth.file_reference, {type: 'message', peerId: message.peerId, messageId: message.mid});\n }\n\n if('webpage' in media && media.webpage) {\n const isScheduled = this.getScheduledMessagesStorage(message.peerId) === storage;\n const messageKey = appWebPagesManager.getMessageKeyForPendingWebPage(message.peerId, message.mid, isScheduled);\n appWebPagesManager.deleteWebPageFromPending(media.webpage, messageKey);\n }\n\n if((media as MessageMedia.messageMediaPoll).poll) {\n appPollsManager.updatePollToMessage(message as Message.message, false);\n }\n }\n }\n\n private handleDeletedMessages(peerId: PeerId, storage: MessagesStorage, messages: number[]) {\n const history: {\n count: number, \n unread: number, \n unreadMentions: number, \n msgs: Set<number>,\n albums?: {[groupId: string]: Set<number>},\n } = {\n count: 0, \n unread: 0, \n unreadMentions: 0, \n msgs: new Set()\n };\n\n for(const mid of messages) {\n const message: MyMessage = this.getMessageFromStorage(storage, mid);\n if(message.deleted) {\n this.fixDialogUnreadMentionsIfNoMessage(peerId);\n continue;\n }\n\n this.handleReleasingMessage(message, storage);\n\n this.updateMessageRepliesIfNeeded(message);\n\n if(!message.pFlags.out && !message.pFlags.is_outgoing && message.pFlags.unread) {\n ++history.unread;\n appNotificationsManager.cancel('msg' + mid);\n\n if(message.pFlags.mentioned) {\n ++history.unreadMentions;\n this.modifyCachedMentions(peerId, mid, false);\n }\n }\n\n ++history.count;\n history.msgs.add(mid);\n\n message.deleted = true;\n\n const groupedId = (message as Message.message).grouped_id;\n if(groupedId) {\n const groupedStorage = this.groupedMessagesStorage[groupedId];\n if(groupedStorage) {\n groupedStorage.delete(mid);\n\n if(!history.albums) history.albums = {};\n (history.albums[groupedId] || (history.albums[groupedId] = new Set())).add(mid);\n\n if(!groupedStorage.size) {\n delete history.albums;\n delete this.groupedMessagesStorage[groupedId];\n }\n }\n }\n\n storage.delete(mid);\n\n const peerMessagesToHandle = this.newMessagesToHandle[peerId];\n if(peerMessagesToHandle && peerMessagesToHandle.has(mid)) {\n peerMessagesToHandle.delete(mid);\n }\n }\n\n if(history.albums) {\n for(const groupId in history.albums) {\n rootScope.dispatchEvent('album_edit', {peerId, groupId, deletedMids: [...history.albums[groupId]]});\n /* const mids = this.getMidsByAlbum(groupId);\n if(mids.length) {\n const mid = Math.max(...mids);\n rootScope.$broadcast('message_edit', {peerId, mid, justMedia: false});\n } */\n }\n }\n\n return history;\n }\n \n private handleEditedMessage(oldMessage: Message, newMessage: Message) {\n if(oldMessage._ === 'message') {\n if((oldMessage.media as MessageMedia.messageMediaWebPage)?.webpage) {\n const messageKey = appWebPagesManager.getMessageKeyForPendingWebPage(oldMessage.peerId, oldMessage.mid, !!oldMessage.pFlags.is_scheduled);\n appWebPagesManager.deleteWebPageFromPending((oldMessage.media as MessageMedia.messageMediaWebPage).webpage, messageKey);\n }\n }\n }\n\n public getMediaFromMessage(message: any) {\n return message.action ? \n message.action.photo : \n message.media && (\n message.media.photo || \n message.media.document || (\n message.media.webpage && (\n message.media.webpage.document || \n message.media.webpage.photo\n )\n )\n );\n }\n\n public isMentionUnread(message: MyMessage) {\n const doc = ((message as Message.message).media as MessageMedia.messageMediaDocument)?.document as MyDocument;\n return message.pFlags.media_unread && \n message.pFlags.mentioned && \n (\n !doc || \n !(['voice', 'round'] as MyDocument['type'][]).includes(doc.type)\n );\n }\n\n public getDialogUnreadCount(dialog: Dialog) {\n return dialog.unread_count || +!!dialog.pFlags.unread_mark;\n }\n\n public isDialogUnread(dialog: Dialog) {\n return !!this.getDialogUnreadCount(dialog);\n }\n\n public canForward(message: Message.message | Message.messageService) {\n return !(message as Message.message).pFlags.noforwards && !appPeersManager.noForwards(message.peerId);\n }\n\n private pushBatchUpdate<E extends keyof BatchUpdates, C extends BatchUpdates[E]>(\n event: E, \n callback: C, \n key: string, \n getElementCallback?: () => MapValueType<ArgumentTypes<C>[0]>\n ) {\n let details = this.batchUpdates[event];\n if(!details) {\n // @ts-ignore\n details = this.batchUpdates[event] = {\n callback,\n batch: new Map()\n };\n }\n\n if(!details.batch.has(key)) {\n // @ts-ignore\n details.batch.set(key, getElementCallback ? getElementCallback() : undefined);\n this.batchUpdatesDebounced();\n }\n }\n\n private getMessagesFromMap<T extends Map<any, any>>(map: T) {\n const newMap: Map<Message.message, MapValueType<T>> = new Map();\n for(const [key, value] of map) {\n const [peerIdStr, mid] = key.split('_');\n const message: Message.message | Message.messageEmpty = this.getMessageByPeer(peerIdStr.toPeerId(), +mid);\n if(message._ === 'messageEmpty') {\n continue;\n }\n\n newMap.set(message, value);\n }\n\n return newMap;\n }\n\n private batchUpdateViews = (batch: Map<string, undefined>) => {\n const toDispatch: {peerId: PeerId, mid: number, views: number}[] = [];\n\n const map = this.getMessagesFromMap(batch);\n for(const [message] of map) {\n toDispatch.push({\n peerId: message.peerId,\n mid: message.mid,\n views: message.views\n })\n }\n\n return toDispatch;\n };\n\n private batchUpdateReactions = (batch: Map<string, MessageReactions>) => {\n const toDispatch: {message: Message.message, changedResults: ReactionCount.reactionCount[]}[] = [];\n\n const map = this.getMessagesFromMap(batch);\n for(const [message, previousReactions] of map) {\n const results = message.reactions?.results ?? [];\n const previousResults = previousReactions?.results ?? [];\n const changedResults = results.filter(reactionCount => {\n const previousReactionCount = previousResults.find(_reactionCount => _reactionCount.reaction === reactionCount.reaction);\n return (\n message.pFlags.out && (\n !previousReactionCount || \n reactionCount.count > previousReactionCount.count\n )\n ) || (\n reactionCount.pFlags.chosen && (\n !previousReactionCount || \n !previousReactionCount.pFlags.chosen\n )\n );\n });\n\n toDispatch.push({message, changedResults});\n }\n\n return toDispatch;\n };\n}\n\nconst appMessagesManager = new AppMessagesManager();\nMOUNT_CLASS_TO.appMessagesManager = appMessagesManager;\nexport default appMessagesManager;\n","export default function splitStringByLength(str: string, maxLength: number) {\n if(str.length < maxLength) return [str];\n let length = 0, lastSliceStartIndex = 0, arrayIndex = 0;\n const delimiter = ' ';//'\\n';\n const out: string[] = [];\n\n const cut = (end?: number) => {\n let part = str.slice(lastSliceStartIndex, end);\n const _arrayIndex = arrayIndex++;\n if(part.length > maxLength) {\n let overflowPart = part.slice(maxLength);\n const splitted = splitStringByLength(overflowPart, maxLength);\n splitted.forEach(part => {\n out[arrayIndex++] = part;\n });\n\n part = part.slice(0, maxLength);\n }\n\n lastSliceStartIndex = end;\n length = 0;\n out[_arrayIndex] = (out[_arrayIndex] || '') + part;\n };\n\n let lastIndex = 0;\n do {\n let index = str.indexOf(delimiter, lastIndex);\n if(index === -1) {\n if(lastIndex !== (str.length - 1)) {\n cut();\n }\n\n break;\n }\n\n index += delimiter.length;\n\n const partLength = index - lastIndex;\n if((length + partLength) > maxLength) {\n cut(length);\n }\n \n lastIndex = index;\n length += partLength;\n } while(true);\n\n return out;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport copy from \"../../helpers/object/copy\";\nimport deepEqual from \"../../helpers/object/deepEqual\";\nimport isObject from \"../../helpers/object/isObject\";\nimport safeReplaceObject from \"../../helpers/object/safeReplaceObject\";\nimport { ChannelParticipant, ChannelsCreateChannel, Chat, ChatAdminRights, ChatBannedRights, ChatParticipant, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, Update, Updates } from \"../../layer\";\nimport apiManagerProxy from \"../mtproto/mtprotoworker\";\nimport apiManager from '../mtproto/mtprotoworker';\nimport { RichTextProcessor } from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appStateManager from \"./appStateManager\";\nimport appUsersManager from \"./appUsersManager\";\nimport { isRestricted } from \"../../helpers/restrictions\";\nimport findAndSplice from \"../../helpers/array/findAndSplice\";\n\nexport type Channel = Chat.channel;\nexport type ChatRights = keyof ChatBannedRights['pFlags'] | keyof ChatAdminRights['pFlags'] | 'change_type' | 'change_permissions' | 'delete_chat' | 'view_participants';\n\nexport class AppChatsManager {\n private storage = appStateManager.storages.chats;\n \n private chats: {[id: ChatId]: Chat.channel | Chat.chat | any};\n //private usernames: any;\n //private channelAccess: any;\n //private megagroups: {[id: number]: true};\n\n constructor() {\n this.clear(true);\n\n rootScope.addMultipleEventsListeners({\n /* updateChannel: (update) => {\n const channelId = update.channel_id;\n //console.log('updateChannel:', update);\n rootScope.broadcast('channel_settings', {channelId});\n }, */\n\n updateChannelParticipant: (update) => {\n apiManagerProxy.clearCache('channels.getParticipants', (params) => {\n return (params.channel as InputChannel.inputChannel).channel_id === update.channel_id;\n });\n },\n\n updateChatDefaultBannedRights: (update) => {\n const chatId = appPeersManager.getPeerId(update.peer).toChatId();\n const chat: Chat.chat = this.chats[chatId];\n if(chat) {\n chat.default_banned_rights = update.default_banned_rights;\n rootScope.dispatchEvent('chat_update', chatId);\n }\n }\n });\n\n appStateManager.getState().then((state) => {\n const chats = appStateManager.storagesResults.chats;\n if(chats.length) {\n for(let i = 0, length = chats.length; i < length; ++i) {\n const chat = chats[i];\n if(chat) {\n this.chats[chat.id] = chat;\n }\n }\n }\n\n appStateManager.addEventListener('peerNeeded', (peerId) => {\n if(peerId.isUser() || this.storage.getFromCache(peerId.toChatId())) {\n return;\n }\n\n this.storage.set({\n [peerId.toChatId()]: this.getChat(peerId.toChatId())\n });\n });\n\n appStateManager.addEventListener('peerUnneeded', (peerId) => {\n if(peerId.isUser() || !this.storage.getFromCache(peerId.toChatId())) {\n return;\n }\n\n this.storage.delete(peerId.toChatId());\n });\n });\n }\n\n public clear(init = false) {\n if(!init) {\n const chats = appStateManager.storagesResults.chats;\n for(const chatId in this.chats) {\n if(!chatId) continue;\n if(!appStateManager.isPeerNeeded(chatId.toPeerId(true))) {\n /* const chat = this.chats[chatId];\n if(chat.username) {\n delete this.usernames[cleanUsername(chat.username)];\n } */\n \n findAndSplice(chats, (chat) => chat.id === chatId);\n this.storage.delete(chatId);\n delete this.chats[chatId];\n }\n }\n } else {\n this.chats = {};\n }\n }\n\n public saveApiChats(apiChats: any[], override?: boolean) {\n if((apiChats as any).saved) return;\n (apiChats as any).saved = true;\n apiChats.forEach(chat => this.saveApiChat(chat, override));\n }\n\n public saveApiChat(chat: Chat, override?: boolean) {\n if(chat._ === 'chatEmpty') return;\n /* if(chat._ !== 'chat' && chat._ !== 'channel') {\n return;\n } */\n \n // * exclude from state\n // defineNotNumerableProperties(chat, ['rTitle', 'initials']);\n\n const oldChat: Exclude<Chat, Chat.chatEmpty> = this.chats[chat.id];\n\n /* if(oldChat && !override) {\n return;\n } */\n\n if((chat as Chat.chat).pFlags === undefined) {\n (chat as Chat.chat).pFlags = {};\n }\n\n if((chat as Chat.channel).pFlags.min && oldChat !== undefined) {\n return;\n }\n\n chat.initials = RichTextProcessor.getAbbreviation(chat.title);\n\n if(chat._ === 'channel' &&\n chat.participants_count === undefined &&\n oldChat !== undefined &&\n (oldChat as Chat.channel).participants_count) {\n chat.participants_count = (oldChat as Chat.channel).participants_count;\n }\n\n /* if(chat.username) {\n let searchUsername = searchIndexManager.cleanUsername(chat.username);\n this.usernames[searchUsername] = chat.id;\n } */\n\n let changedPhoto = false, changedTitle = false;\n if(oldChat === undefined) {\n this.chats[chat.id] = chat;\n } else {\n const oldPhotoId = ((oldChat as Chat.chat).photo as ChatPhoto.chatPhoto)?.photo_id;\n const newPhotoId = ((chat as Chat.chat).photo as ChatPhoto.chatPhoto)?.photo_id;\n if(oldPhotoId !== newPhotoId) {\n changedPhoto = true;\n }\n\n if(oldChat.title !== chat.title) {\n changedTitle = true;\n }\n\n safeReplaceObject(oldChat, chat);\n rootScope.dispatchEvent('chat_update', chat.id);\n }\n\n const peerId = chat.id.toPeerId(true);\n if(changedPhoto) {\n rootScope.dispatchEvent('avatar_update', peerId);\n }\n\n if(changedTitle) {\n rootScope.dispatchEvent('peer_title_edit', peerId);\n }\n\n if(appStateManager.isPeerNeeded(peerId)) {\n this.storage.set({\n [chat.id]: chat\n });\n }\n }\n\n public getChat(id: ChatId) {\n return this.chats[id] || {_: 'chatEmpty', id, deleted: true, access_hash: '', pFlags: {}/* this.channelAccess[id] */};\n }\n\n public getChatTyped(id: ChatId): Chat {\n return this.getChat(id);\n }\n\n public combineParticipantBannedRights(id: ChatId, rights: ChatBannedRights) {\n const chat: Chat.channel = this.getChat(id);\n\n if(chat.default_banned_rights) {\n rights = copy(rights);\n const defaultRights = chat.default_banned_rights.pFlags;\n for(let i in defaultRights) {\n // @ts-ignore\n rights.pFlags[i] = defaultRights[i];\n }\n }\n\n return rights;\n }\n\n /**\n * Check the user's ability to do an action in chat\n * @param id \n * @param action creator can still send messages to left channel. so this function shows server rights. see canSendToPeer for local rights in messages manager.\n * @param rights do not provide this parameter when checking rights for self\n * @param isThread \n * @returns \n */\n public hasRights(id: ChatId, action: ChatRights, rights?: ChatAdminRights | ChatBannedRights, isThread?: boolean) {\n const chat: Chat = this.getChat(id);\n if(chat._ === 'chatEmpty') return false;\n\n if((chat as Chat.chat).pFlags.deactivated && action !== 'view_messages') {\n return false;\n }\n\n const isCheckingRightsForSelf = rights === undefined;\n if((chat as Chat.chat).pFlags.creator && isCheckingRightsForSelf) {\n return true;\n }\n\n if(chat._ === 'chatForbidden' ||\n chat._ === 'channelForbidden' ||\n (chat as Chat.chat).pFlags.kicked ||\n (chat.pFlags.left && !(chat as Chat.channel).pFlags.megagroup)) {\n return false;\n }\n\n // const adminRights = chat.admin_rights;\n // const bannedRights = (chat as Chat.channel).banned_rights || chat.default_banned_rights;\n\n if(!rights) {\n rights = chat.admin_rights || (chat as Chat.channel).banned_rights || chat.default_banned_rights;\n\n if(!rights) {\n return false;\n }\n }\n\n let myFlags: Partial<{[flag in keyof ChatBannedRights['pFlags'] | keyof ChatAdminRights['pFlags']]: true}> = {};\n if(rights) {\n myFlags = rights.pFlags as any;\n }\n\n // const adminFlags = adminRights?.pFlags || {};\n // const bannedFlags = bannedRights?.pFlags || {};\n\n switch(action) {\n case 'embed_links':\n case 'send_games':\n case 'send_gifs':\n case 'send_inline':\n case 'send_media':\n case 'send_messages':\n case 'send_polls':\n case 'send_stickers': {\n if(!isThread && chat.pFlags.left) {\n return false;\n }\n\n if(rights._ === 'chatBannedRights' && myFlags[action]) {\n return false;\n }\n\n if(chat._ === 'channel') {\n if(!chat.pFlags.megagroup && !myFlags.post_messages) {\n return false;\n }\n }\n\n break;\n }\n\n // * revoke foreign messages\n case 'delete_messages':\n case 'manage_call': {\n return !!myFlags[action];\n }\n\n case 'pin_messages': {\n return rights._ === 'chatAdminRights' ? myFlags[action] || !!myFlags.post_messages : !myFlags[action];\n }\n\n // case 'change_info': {\n // return adminRights || isCheckingRightsForSelf ? adminFlags[action] : !myFlags[action];\n // }\n\n case 'change_info':\n case 'invite_users': {\n return rights._ === 'chatAdminRights' ? myFlags[action] : !myFlags[action];\n }\n\n // * only creator can do that\n case 'change_type':\n case 'delete_chat': {\n return false;\n }\n\n case 'ban_users':\n case 'change_permissions': {\n return rights._ === 'chatAdminRights' && !!myFlags['ban_users'];\n }\n\n case 'view_participants': {\n return !!(chat._ === 'chat' || !chat.pFlags.broadcast || chat.pFlags.creator || chat.admin_rights);\n }\n }\n\n return true;\n }\n\n public editChatDefaultBannedRights(id: ChatId, banned_rights: ChatBannedRights) {\n const chat: Chat.chat = this.getChat(id);\n if(chat.default_banned_rights) {\n if(chat.default_banned_rights.until_date === banned_rights.until_date && deepEqual(chat.default_banned_rights.pFlags, banned_rights.pFlags)) {\n return Promise.resolve();\n }\n }\n \n return apiManager.invokeApi('messages.editChatDefaultBannedRights', {\n peer: appPeersManager.getInputPeerById(id.toPeerId(true)),\n banned_rights\n }).then(this.onChatUpdated.bind(this, id));\n }\n\n /* public resolveUsername(username: string) {\n return this.usernames[username] || 0;\n } */\n\n /* public saveChannelAccess(id: ChatId, accessHash: string) {\n this.channelAccess[id] = accessHash;\n } */\n\n /* public saveIsMegagroup(id: ChatId) {\n this.megagroups[id] = true;\n } */\n\n public isChannel(id: ChatId) {\n const chat = this.chats[id];\n return !!(chat && (chat._ === 'channel' || chat._ === 'channelForbidden')/* || this.channelAccess[id] */);\n }\n\n public isMegagroup(id: ChatId) {\n /* if(this.megagroups[id]) {\n return true;\n } */\n\n const chat: Chat = this.chats[id];\n return !!(chat && chat._ === 'channel' && chat.pFlags.megagroup);\n }\n\n public isBroadcast(id: ChatId) {\n return this.isChannel(id) && !this.isMegagroup(id);\n }\n\n public isInChat(id: ChatId) {\n let good = true;\n const chat: Chat = this.getChat(id);\n if(chat._ === 'channelForbidden' \n || chat._ === 'chatForbidden' \n || chat._ === 'chatEmpty' \n || (chat as Chat.chat).pFlags.left \n || (chat as Chat.chat).pFlags.kicked \n || (chat as Chat.chat).pFlags.deactivated) {\n good = false;\n }\n\n return good;\n }\n\n public getChannelInput(id: ChatId): InputChannel {\n const chat: Chat = this.getChat(id);\n if(chat._ === 'chatEmpty' || !(chat as Chat.channel).access_hash) {\n return {\n _: 'inputChannelEmpty'\n };\n } else {\n return {\n _: 'inputChannel',\n channel_id: id,\n access_hash: (chat as Chat.channel).access_hash/* || this.channelAccess[id] */ || '0'\n };\n }\n }\n\n public getInputPeer(id: ChatId) {\n return this.isChannel(id) ? this.getChannelInputPeer(id) : this.getChatInputPeer(id);\n }\n\n public getChatInputPeer(id: ChatId): InputPeer.inputPeerChat {\n return {\n _: 'inputPeerChat',\n chat_id: id\n };\n }\n\n public getChannelInputPeer(id: ChatId): InputPeer.inputPeerChannel {\n return {\n _: 'inputPeerChannel',\n channel_id: id,\n access_hash: this.getChat(id).access_hash/* || this.channelAccess[id] */ || 0\n };\n }\n\n public hasChat(id: ChatId, allowMin?: true) {\n const chat = this.chats[id];\n return isObject(chat) && (allowMin || !chat.pFlags.min);\n }\n\n public getChatPhoto(id: ChatId) {\n const chat: Chat.chat = this.getChat(id);\n\n return chat && chat.photo || {\n _: 'chatPhotoEmpty'\n };\n }\n\n public getChatString(id: ChatId) {\n const chat = this.getChat(id);\n if(this.isChannel(id)) {\n return (this.isMegagroup(id) ? 's' : 'c') + id + '_' + chat.access_hash;\n }\n return 'g' + id;\n }\n\n /* public wrapForFull(id: number, fullChat: any) {\n const chatFull = copy(fullChat);\n const chat = this.getChat(id);\n\n if(!chatFull.participants_count) {\n chatFull.participants_count = chat.participants_count;\n }\n\n if(chatFull.participants &&\n chatFull.participants._ === 'chatParticipants') {\n chatFull.participants.participants = this.wrapParticipants(id, chatFull.participants.participants);\n }\n\n if(chatFull.about) {\n chatFull.rAbout = RichTextProcessor.wrapRichText(chatFull.about, {noLinebreaks: true});\n }\n\n //chatFull.peerString = this.getChatString(id);\n chatFull.chat = chat;\n\n return chatFull;\n }\n\n public wrapParticipants(id: number, participants: any[]) {\n const chat = this.getChat(id);\n const myId = appUsersManager.getSelf().id;\n if(this.isChannel(id)) {\n const isAdmin = chat.pFlags.creator;\n participants.forEach((participant) => {\n participant.canLeave = myId === participant.user_id;\n participant.canKick = isAdmin && participant._ === 'channelParticipant';\n\n // just for order by last seen\n participant.user = appUsersManager.getUser(participant.user_id);\n });\n } else {\n const isAdmin = chat.pFlags.creator || chat.pFlags.admins_enabled && chat.pFlags.admin;\n participants.forEach((participant) => {\n participant.canLeave = myId === participant.user_id;\n participant.canKick = !participant.canLeave && (\n chat.pFlags.creator ||\n participant._ === 'chatParticipant' && (isAdmin || myId === participant.inviter_id)\n );\n\n // just for order by last seen\n participant.user = appUsersManager.getUser(participant.user_id);\n });\n }\n\n return participants;\n } */\n\n public createChannel(options: ChannelsCreateChannel): Promise<ChatId> {\n return apiManager.invokeApi('channels.createChannel', options).then((updates) => {\n apiUpdatesManager.processUpdateMessage(updates);\n\n const channelId = (updates as any).chats[0].id;\n rootScope.dispatchEvent('history_focus', {peerId: channelId.toPeerId(true)});\n\n return channelId;\n });\n }\n\n public inviteToChannel(id: ChatId, userIds: UserId[]) {\n const input = this.getChannelInput(id);\n const usersInputs = userIds.map(u => appUsersManager.getUserInput(u));\n\n return apiManager.invokeApi('channels.inviteToChannel', {\n channel: input,\n users: usersInputs\n }).then(this.onChatUpdated.bind(this, id));\n }\n\n public createChat(title: string, userIds: UserId[]): Promise<ChatId> {\n return apiManager.invokeApi('messages.createChat', {\n users: userIds.map(u => appUsersManager.getUserInput(u)),\n title\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n\n const chatId = (updates as any as Updates.updates).chats[0].id;\n rootScope.dispatchEvent('history_focus', {peerId: chatId.toPeerId(true)});\n\n return chatId;\n });\n }\n\n private onChatUpdated = (chatId: ChatId, updates?: any) => {\n //console.log('onChatUpdated', chatId, updates);\n\n apiUpdatesManager.processUpdateMessage(updates);\n if(updates?.updates?.length && this.isChannel(chatId)) {\n rootScope.dispatchEvent('invalidate_participants', chatId);\n }\n };\n\n public leaveChannel(id: ChatId) {\n return apiManager.invokeApi('channels.leaveChannel', {\n channel: this.getChannelInput(id)\n }).then(this.onChatUpdated.bind(this, id));\n }\n\n public joinChannel(id: ChatId) {\n return apiManager.invokeApi('channels.joinChannel', {\n channel: this.getChannelInput(id)\n }).then(this.onChatUpdated.bind(this, id));\n }\n\n public addChatUser(id: ChatId, userId: UserId, fwdLimit = 100) {\n return apiManager.invokeApi('messages.addChatUser', {\n chat_id: id,\n user_id: appUsersManager.getUserInput(userId),\n fwd_limit: fwdLimit\n }).then(this.onChatUpdated.bind(this, id));\n }\n\n public deleteChatUser(id: ChatId, userId: UserId) {\n return apiManager.invokeApi('messages.deleteChatUser', {\n chat_id: id,\n user_id: appUsersManager.getUserInput(userId)\n }).then(this.onChatUpdated.bind(this, id));\n }\n\n public leaveChat(id: ChatId) {\n return this.deleteChatUser(id, appUsersManager.getSelf().id);\n }\n\n public leave(id: ChatId) {\n return this.isChannel(id) ? this.leaveChannel(id) : this.leaveChat(id);\n }\n\n public delete(id: ChatId) {\n return this.isChannel(id) ? this.deleteChannel(id) : this.deleteChat(id);\n }\n\n public deleteChannel(id: ChatId) {\n return apiManager.invokeApi('channels.deleteChannel', {\n channel: this.getChannelInput(id)\n }).then(this.onChatUpdated.bind(this, id));\n }\n\n public deleteChat(id: ChatId) {\n //return this.leaveChat(id).then(() => {\n return apiManager.invokeApi('messages.deleteChat', {\n chat_id: id\n });\n //});\n }\n\n public migrateChat(id: ChatId): Promise<ChatId> {\n const chat: Chat = this.getChat(id);\n if(chat._ === 'channel') return Promise.resolve(chat.id);\n return apiManager.invokeApi('messages.migrateChat', {\n chat_id: id\n }).then((updates) => {\n this.onChatUpdated(id, updates);\n const update: Update.updateChannel = (updates as Updates.updates).updates.find(u => u._ === 'updateChannel') as any;\n return update.channel_id;\n });\n }\n\n public updateUsername(id: ChatId, username: string) {\n return apiManager.invokeApi('channels.updateUsername', {\n channel: this.getChannelInput(id),\n username\n }).then((bool) => {\n if(bool) {\n const chat: Chat.channel = this.getChat(id);\n chat.username = username;\n }\n\n return bool;\n });\n }\n\n public editPhoto(id: ChatId, inputFile: InputFile) {\n const inputChatPhoto: InputChatPhoto = {\n _: 'inputChatUploadedPhoto',\n file: inputFile\n };\n\n let promise: any;\n if(this.isChannel(id)) {\n promise = apiManager.invokeApi('channels.editPhoto', {\n channel: this.getChannelInput(id),\n photo: inputChatPhoto\n });\n } else {\n promise = apiManager.invokeApi('messages.editChatPhoto', {\n chat_id: id,\n photo: inputChatPhoto\n });\n }\n\n return promise.then((updates: any) => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public editTitle(id: ChatId, title: string) {\n let promise: any;\n\n if(this.isChannel(id)) {\n promise = apiManager.invokeApi('channels.editTitle', {\n channel: this.getChannelInput(id),\n title\n });\n } else {\n promise = apiManager.invokeApi('messages.editChatTitle', {\n chat_id: id,\n title\n });\n }\n\n return promise.then((updates: any) => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public editAbout(id: ChatId, about: string) {\n const peerId = id.toPeerId(true);\n return apiManager.invokeApi('messages.editChatAbout', {\n peer: appPeersManager.getInputPeerById(peerId),\n about\n }).then(bool => {\n if(bool) {\n rootScope.dispatchEvent('peer_bio_edit', peerId);\n }\n\n return bool;\n });\n }\n\n public getParticipantPeerId(participant: ChannelParticipant | ChatParticipant): PeerId {\n const peerId = (participant as ChannelParticipant.channelParticipantBanned).peer ? \n appPeersManager.getPeerId((participant as ChannelParticipant.channelParticipantBanned).peer) : \n (participant as ChatParticipant.chatParticipant).user_id.toPeerId();\n return peerId;\n }\n\n public editBanned(id: ChatId, participant: PeerId | ChannelParticipant, banned_rights: ChatBannedRights) {\n const peerId = typeof(participant) !== 'object' ? participant : this.getParticipantPeerId(participant);\n return apiManager.invokeApi('channels.editBanned', {\n channel: this.getChannelInput(id),\n participant: appPeersManager.getInputPeerById(peerId),\n banned_rights\n }).then((updates) => {\n this.onChatUpdated(id, updates);\n\n if(typeof(participant) === 'object') {\n const timestamp = Date.now() / 1000 | 0;\n apiUpdatesManager.processLocalUpdate({\n _: 'updateChannelParticipant',\n channel_id: id,\n date: timestamp,\n actor_id: undefined,\n qts: undefined,\n user_id: peerId,\n prev_participant: participant,\n new_participant: Object.keys(banned_rights.pFlags).length ? {\n _: 'channelParticipantBanned',\n date: timestamp,\n banned_rights,\n kicked_by: appUsersManager.getSelf().id,\n peer: appPeersManager.getOutputPeer(peerId),\n pFlags: {}\n } : undefined\n });\n }\n });\n }\n\n public clearChannelParticipantBannedRights(id: ChatId, participant: PeerId | ChannelParticipant) {\n return this.editBanned(id, participant, {\n _: 'chatBannedRights',\n until_date: 0,\n pFlags: {}\n });\n }\n \n public kickFromChannel(id: ChatId, participant: PeerId | ChannelParticipant) {\n return this.editBanned(id, participant, {\n _: 'chatBannedRights',\n until_date: 0,\n pFlags: {\n view_messages: true\n }\n });\n }\n\n public kickFromChat(id: ChatId, participant: PeerId | ChannelParticipant) {\n if(this.isChannel(id)) return this.kickFromChannel(id, participant);\n else return this.deleteChatUser(id, (participant as PeerId).toUserId());\n }\n\n public resolveChannel(id: ChatId) {\n return apiManager.invokeApiSingle('channels.getChannels', {\n id: [{\n _: 'inputChannel',\n channel_id: id,\n access_hash: '0'\n }]\n }).then(messagesChats => {\n this.saveApiChats(messagesChats.chats);\n });\n }\n\n public togglePreHistoryHidden(id: ChatId, enabled: boolean) {\n return this.migrateChat(id).then(channelId => {\n return apiManager.invokeApi('channels.togglePreHistoryHidden', {\n channel: this.getChannelInput(channelId),\n enabled\n });\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public toggleSignatures(id: ChatId, enabled: boolean) {\n return apiManager.invokeApi('channels.toggleSignatures', {\n channel: this.getChannelInput(id),\n enabled\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public toggleNoForwards(id: ChatId, enabled: boolean) {\n return apiManager.invokeApi('messages.toggleNoForwards', {\n peer: this.getInputPeer(id),\n enabled\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public setChatAvailableReactions(id: ChatId, reactions: Array<string>) {\n return apiManager.invokeApi('messages.setChatAvailableReactions', {\n peer: this.getInputPeer(id),\n available_reactions: reactions\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public isRestricted(chatId: ChatId) {\n const chat: Chat.channel = this.getChat(chatId);\n const restrictionReasons = chat.restriction_reason;\n\n return !!(chat.pFlags.restricted && restrictionReasons && isRestricted(restrictionReasons));\n }\n\n public getSendAs(channelId: ChatId) {\n return apiManager.invokeApiSingleProcess({\n method: 'channels.getSendAs', \n params: {\n peer: this.getChannelInputPeer(channelId)\n },\n processResult: (sendAsPeers) => {\n appUsersManager.saveApiUsers(sendAsPeers.users);\n appChatsManager.saveApiChats(sendAsPeers.chats);\n\n return sendAsPeers.peers;\n }\n });\n }\n}\n\nconst appChatsManager = new AppChatsManager();\nMOUNT_CLASS_TO.appChatsManager = appChatsManager;\nexport default appChatsManager;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { i18n } from \"../lib/langPack\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport RichTextProcessor from \"../lib/richtextprocessor\";\r\nimport { NULL_PEER_ID } from \"../lib/mtproto/mtproto_config\";\r\nimport limitSymbols from \"../helpers/string/limitSymbols\";\r\n\r\nexport type PeerTitleOptions = {\r\n peerId?: PeerId,\r\n fromName?: string,\r\n plainText?: boolean,\r\n onlyFirstName?: boolean,\r\n dialog?: boolean,\r\n limitSymbols?: number\r\n};\r\n\r\nconst weakMap: WeakMap<HTMLElement, PeerTitle> = new WeakMap();\r\n\r\nMOUNT_CLASS_TO.peerTitleWeakMap = weakMap;\r\n\r\nrootScope.addEventListener('peer_title_edit', (peerId) => {\r\n const elements = Array.from(document.querySelectorAll(`.peer-title[data-peer-id=\"${peerId}\"]`)) as HTMLElement[];\r\n elements.forEach(element => {\r\n const peerTitle = weakMap.get(element);\r\n //console.log('in the summer silence i was doing nothing', peerTitle, peerId);\r\n\r\n if(peerTitle) {\r\n peerTitle.update();\r\n }\r\n });\r\n});\r\n\r\nexport default class PeerTitle {\r\n public element: HTMLElement;\r\n public peerId: PeerId;\r\n public fromName: string;\r\n public plainText = false;\r\n public onlyFirstName = false;\r\n public dialog = false;\r\n public limitSymbols: number;\r\n\r\n constructor(options: PeerTitleOptions) {\r\n this.element = document.createElement('span');\r\n this.element.classList.add('peer-title');\r\n this.element.setAttribute('dir', 'auto');\r\n \r\n this.update(options);\r\n weakMap.set(this.element, this);\r\n }\r\n\r\n public update(options?: PeerTitleOptions) {\r\n if(options) {\r\n for(let i in options) {\r\n // @ts-ignore\r\n this.element.dataset[i] = options[i] ? '' + (typeof(options[i]) === 'boolean' ? +options[i] : options[i]) : '0';\r\n // @ts-ignore\r\n this[i] = options[i];\r\n }\r\n }\r\n\r\n let fromName = this.fromName;\r\n if(fromName !== undefined) {\r\n if(this.limitSymbols !== undefined) {\r\n fromName = limitSymbols(fromName, this.limitSymbols, this.limitSymbols);\r\n }\r\n\r\n this.element.innerHTML = RichTextProcessor.wrapEmojiText(fromName);\r\n return;\r\n }\r\n\r\n if(this.peerId === undefined) {\r\n this.peerId = NULL_PEER_ID;\r\n }\r\n\r\n if(this.peerId !== rootScope.myId || !this.dialog) {\r\n if(this.peerId.isUser() && appUsersManager.getUser(this.peerId).pFlags.deleted) {\r\n replaceContent(this.element, i18n(this.onlyFirstName ? 'Deleted' : 'HiddenName'));\r\n } else {\r\n this.element.innerHTML = appPeersManager.getPeerTitle(this.peerId, this.plainText, this.onlyFirstName, this.limitSymbols);\r\n }\r\n } else {\r\n replaceContent(this.element, i18n(this.onlyFirstName ? 'Saved' : 'SavedMessages'));\r\n }\r\n }\r\n}\r\n","export default function bytesFromHex(hexString: string) {\n const len = hexString.length;\n const bytes = new Uint8Array(Math.ceil(len / 2));\n let start = 0;\n\n if(len % 2) { // read 0x581 as 0x0581\n bytes[start++] = parseInt(hexString.charAt(0), 16);\n }\n\n for(let i = start; i < len; i += 2) {\n bytes[start++] = parseInt(hexString.substr(i, 2), 16);\n }\n\n return bytes;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport type { DownloadOptions } from \"../mtproto/apiFileManager\";\nimport { CancellablePromise } from \"../../helpers/cancellablePromise\";\nimport { getFileNameByLocation } from \"../../helpers/fileName\";\nimport { IS_SAFARI } from \"../../environment/userAgent\";\nimport { InputFileLocation, InputMedia, InputPhoto, Photo, PhotoSize, PhotosPhotos } from \"../../layer\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport referenceDatabase, { ReferenceContext } from \"../mtproto/referenceDatabase\";\nimport { MyDocument } from \"./appDocsManager\";\nimport appDownloadManager, { ThumbCache } from \"./appDownloadManager\";\nimport appUsersManager from \"./appUsersManager\";\nimport blur from \"../../helpers/blur\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport { renderImageFromUrlPromise } from \"../../helpers/dom/renderImageFromUrl\";\nimport calcImageInBox from \"../../helpers/calcImageInBox\";\nimport { makeMediaSize, MediaSize } from \"../../helpers/mediaSizes\";\nimport windowSize from \"../../helpers/windowSize\";\nimport bytesFromHex from \"../../helpers/bytes/bytesFromHex\";\nimport isObject from \"../../helpers/object/isObject\";\nimport safeReplaceArrayInObject from \"../../helpers/object/safeReplaceArrayInObject\";\n\nexport type MyPhoto = Photo.photo;\n\n// TIMES = 2 DUE TO SIDEBAR AND CHAT\n//let TEST_FILE_REFERENCE = \"5440692274120994569\", TEST_FILE_REFERENCE_TIMES = 2;\n\nexport class AppPhotosManager {\n private photos: {\n [id: string]: MyPhoto\n } = {};\n\n private static jpegHeader = bytesFromHex('ffd8ffe000104a46494600010100000100010000ffdb004300281c1e231e19282321232d2b28303c64413c37373c7b585d4964918099968f808c8aa0b4e6c3a0aadaad8a8cc8ffcbdaeef5ffffff9bc1fffffffaffe6fdfff8ffdb0043012b2d2d3c353c76414176f8a58ca5f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8ffc00011080000000003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00');\n private static jpegTail = bytesFromHex('ffd9');\n \n public savePhoto(photo: Photo, context?: ReferenceContext) {\n if(photo._ === 'photoEmpty') return undefined;\n\n /* if(photo.id === TEST_FILE_REFERENCE) {\n console.warn('Testing FILE_REFERENCE_EXPIRED');\n const bytes = [2, 67, 175, 43, 190, 0, 0, 20, 62, 95, 111, 33, 45, 99, 220, 116, 218, 11, 167, 127, 213, 18, 127, 32, 243, 202, 117, 80, 30];\n //photo.file_reference = new Uint8Array(bytes);\n photo.file_reference = bytes;\n if(!--TEST_FILE_REFERENCE_TIMES) {\n TEST_FILE_REFERENCE = '';\n }\n } */\n\n const oldPhoto = this.photos[photo.id];\n if(photo.file_reference) { // * because we can have a new object w/o the file_reference while sending\n safeReplaceArrayInObject('file_reference', oldPhoto, photo);\n referenceDatabase.saveContext(photo.file_reference, context);\n }\n\n if(photo.sizes?.length) {\n const size = photo.sizes[photo.sizes.length - 1];\n if(size._ === 'photoSizeProgressive') {\n size.size = size.sizes[size.sizes.length - 1];\n }\n }\n\n if(oldPhoto) {\n return Object.assign(oldPhoto, photo);\n }\n\n return this.photos[photo.id] = photo;\n }\n \n public choosePhotoSize(photo: MyPhoto | MyDocument, boxWidth = 0, boxHeight = 0, useBytes = false, pushDocumentSize = false) {\n if(window.devicePixelRatio > 1) {\n boxWidth *= 2;\n boxHeight *= 2;\n }\n \n /*\n s\tbox\t100x100\n m\tbox\t320x320\n x\tbox\t800x800\n y\tbox\t1280x1280\n w\tbox\t2560x2560\n a\tcrop\t160x160\n b\tcrop\t320x320\n c\tcrop\t640x640\n d\tcrop\t1280x1280 */\n\n let bestPhotoSize: PhotoSize = {_: 'photoSizeEmpty', type: ''};\n let sizes = (photo as MyPhoto).sizes || (photo as MyDocument).thumbs as PhotoSize[];\n if(pushDocumentSize && sizes && photo._ === 'document') {\n sizes = sizes.concat({\n _: 'photoSize', \n w: (photo as MyDocument).w, \n h: (photo as MyDocument).h, \n size: (photo as MyDocument).size, \n type: undefined\n });\n }\n\n if(sizes?.length) {\n for(let i = 0, length = sizes.length; i < length; ++i) {\n const photoSize = sizes[i];\n if(!('w' in photoSize) && !('h' in photoSize)) continue;\n \n bestPhotoSize = photoSize;\n \n const size = calcImageInBox(photoSize.w, photoSize.h, boxWidth, boxHeight);\n if(size.width >= boxWidth || size.height >= boxHeight) {\n break;\n }\n }\n\n if(useBytes && bestPhotoSize._ === 'photoSizeEmpty' && sizes[0]._ === 'photoStrippedSize') {\n bestPhotoSize = sizes[0];\n }\n }\n \n return bestPhotoSize;\n }\n \n public getUserPhotos(userId: UserId, maxId: Photo.photo['id'] = '0', limit: number = 20) {\n const inputUser = appUsersManager.getUserInput(userId);\n return apiManager.invokeApiCacheable('photos.getUserPhotos', {\n user_id: inputUser,\n offset: 0,\n limit,\n max_id: maxId\n }, {cacheSeconds: 60}).then((photosResult) => {\n appUsersManager.saveApiUsers(photosResult.users);\n const photoIds = photosResult.photos.map((photo, idx) => {\n photosResult.photos[idx] = this.savePhoto(photo, {type: 'profilePhoto', peerId: userId.toPeerId()});\n return photo.id;\n });\n\n // ! WARNING !\n if(maxId !== '0' && maxId) {\n const idx = photoIds.indexOf(maxId);\n if(idx !== -1) {\n photoIds.splice(idx, 1);\n }\n }\n \n return {\n count: (photosResult as PhotosPhotos.photosPhotosSlice).count || photoIds.length,\n photos: photoIds\n };\n });\n }\n\n public getPreviewURLFromBytes(bytes: Uint8Array | number[], isSticker = false) {\n let arr: Uint8Array;\n if(!isSticker) {\n arr = new Uint8Array(AppPhotosManager.jpegHeader.concat(Array.from(bytes.slice(3)), AppPhotosManager.jpegTail));\n arr[164] = bytes[1];\n arr[166] = bytes[2];\n } else {\n arr = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n }\n\n let mimeType: string;\n if(isSticker) {\n mimeType = IS_SAFARI ? 'image/png' : 'image/webp';\n } else {\n mimeType = 'image/jpeg';\n }\n\n const blob = new Blob([arr], {type: mimeType});\n return URL.createObjectURL(blob);\n }\n\n /**\n * https://core.telegram.org/api/files#vector-thumbnails\n */\n public getPathFromPhotoPathSize(size: PhotoSize.photoPathSize) {\n const bytes = size.bytes;\n const lookup = \"AACAAAAHAAALMAAAQASTAVAAAZaacaaaahaaalmaaaqastava.az0123456789-,\";\n\n let path = 'M';\n for(let i = 0, length = bytes.length; i < length; ++i) {\n const num = bytes[i];\n\n if(num >= (128 + 64)) {\n path += lookup[num - 128 - 64];\n } else {\n if(num >= 128) {\n path += ',';\n } else if(num >= 64) {\n path += '-'; \n }\n path += '' + (num & 63);\n }\n }\n path += 'z';\n\n return path;\n }\n\n public getPreviewURLFromThumb(photo: MyPhoto | MyDocument, thumb: PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize, isSticker = false) {\n const cacheContext = appDownloadManager.getCacheContext(photo, thumb.type);\n return cacheContext.url || (cacheContext.url = this.getPreviewURLFromBytes(thumb.bytes, isSticker));\n }\n \n public getImageFromStrippedThumb(photo: MyPhoto | MyDocument, thumb: PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize, useBlur: boolean) {\n const url = this.getPreviewURLFromThumb(photo, thumb, false);\n\n const image = new Image();\n image.classList.add('thumbnail');\n\n const loadPromise = (useBlur ? blur(url) : Promise.resolve(url)).then(url => {\n return renderImageFromUrlPromise(image, url);\n });\n \n return {image, loadPromise};\n }\n \n public setAttachmentSize(\n photo: MyPhoto | MyDocument, \n element: HTMLElement | SVGForeignObjectElement, \n boxWidth: number, \n boxHeight: number, \n noZoom = true, \n message?: any,\n pushDocumentSize?: boolean,\n photoSize?: ReturnType<AppPhotosManager['choosePhotoSize']>\n ) {\n if(!photoSize) {\n photoSize = this.choosePhotoSize(photo, boxWidth, boxHeight, undefined, pushDocumentSize);\n }\n //console.log('setAttachmentSize', photo, photo.sizes[0].bytes, div);\n \n let size: MediaSize;\n const isDocument = photo._ === 'document';\n if(isDocument) {\n size = makeMediaSize((photo as MyDocument).w || (photoSize as PhotoSize.photoSize).w || 512, (photo as MyDocument).h || (photoSize as PhotoSize.photoSize).h || 512);\n } else {\n size = makeMediaSize((photoSize as PhotoSize.photoSize).w || 100, (photoSize as PhotoSize.photoSize).h || 100);\n }\n\n let boxSize = makeMediaSize(boxWidth, boxHeight);\n\n boxSize = size = size.aspect(boxSize, noZoom);\n\n let isFit = true;\n\n if(!isDocument || ['video', 'gif'].includes((photo as MyDocument).type)) {\n if(boxSize.width < 200 && boxSize.height < 200) { // make at least one side this big\n boxSize = size = size.aspectCovered(makeMediaSize(200, 200));\n }\n \n if(message && \n (message.message || \n message.reply_to_mid || \n message.media.webpage || \n (message.replies && message.replies.pFlags.comments && message.replies.channel_id !== 777)\n )\n ) { // make sure that bubble block is human-readable\n if(boxSize.width < 320) {\n boxSize = makeMediaSize(320, boxSize.height);\n isFit = false;\n }\n }\n \n if(isFit && boxSize.width < 120 && message) { // if image is too narrow\n boxSize = makeMediaSize(120, boxSize.height);\n isFit = false;\n }\n }\n\n // if(element instanceof SVGForeignObjectElement) {\n // element.setAttributeNS(null, 'width', '' + w);\n // element.setAttributeNS(null, 'height', '' + h);\n\n // //console.log('set dimensions to svg element:', element, w, h);\n // } else {\n element.style.width = boxSize.width + 'px';\n element.style.height = boxSize.height + 'px';\n // }\n \n return {photoSize, size, isFit};\n }\n\n public getStrippedThumbIfNeeded(photo: MyPhoto | MyDocument, cacheContext: ThumbCache, useBlur: boolean, ignoreCache = false): ReturnType<AppPhotosManager['getImageFromStrippedThumb']> {\n if(!cacheContext.downloaded || (['video', 'gif'] as MyDocument['type'][]).includes((photo as MyDocument).type) || ignoreCache) {\n if(photo._ === 'document' && cacheContext.downloaded && !ignoreCache) {\n return null;\n }\n\n const sizes = (photo as MyPhoto).sizes || (photo as MyDocument).thumbs;\n const thumb = sizes?.length ? sizes.find(size => size._ === 'photoStrippedSize') : null;\n if(thumb && ('bytes' in thumb)) {\n return this.getImageFromStrippedThumb(photo, thumb as any, useBlur);\n }\n }\n\n return null;\n }\n \n public getPhotoDownloadOptions(photo: MyPhoto | MyDocument, photoSize: PhotoSize, queueId?: number, onlyCache?: boolean): DownloadOptions {\n const isDocument = photo._ === 'document';\n\n if(!photoSize || photoSize._ === 'photoSizeEmpty') {\n //console.error('no photoSize by photo:', photo);\n throw new Error('photoSizeEmpty!');\n }\n \n // maybe it's a thumb\n const isPhoto = (photoSize._ === 'photoSize' || photoSize._ === 'photoSizeProgressive') && photo.access_hash && photo.file_reference;\n const location: InputFileLocation.inputPhotoFileLocation | InputFileLocation.inputDocumentFileLocation = {\n _: isDocument ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',\n id: photo.id,\n access_hash: photo.access_hash,\n file_reference: photo.file_reference,\n thumb_size: photoSize.type\n };\n\n return {\n dcId: photo.dc_id, \n location, \n size: isPhoto ? (photoSize as PhotoSize.photoSize).size : undefined, \n queueId, \n onlyCache\n };\n }\n\n /* public getPhotoURL(photo: MTPhoto | MTMyDocument, photoSize: MTPhotoSize) {\n const downloadOptions = this.getPhotoDownloadOptions(photo, photoSize);\n\n return {url: getFileURL('photo', downloadOptions), location: downloadOptions.location};\n } */\n\n /* public isDownloaded(media: any) {\n const isPhoto = media._ === 'photo';\n const photo = isPhoto ? this.getPhoto(media.id) : null;\n let isDownloaded: boolean;\n if(photo) {\n isDownloaded = photo.downloaded > 0;\n } else {\n const cachedThumb = this.getDocumentCachedThumb(media.id);\n isDownloaded = cachedThumb?.downloaded > 0;\n }\n\n return isDownloaded;\n } */\n \n public preloadPhoto(photoId: MyPhoto | MyDocument | string, photoSize?: PhotoSize, queueId?: number, onlyCache?: boolean): CancellablePromise<Blob> {\n const photo = this.getPhoto(photoId);\n\n // @ts-ignore\n if(!photo || photo._ === 'photoEmpty') {\n throw new Error('preloadPhoto photoEmpty!');\n }\n\n if(!photoSize) {\n const fullWidth = windowSize.width;\n const fullHeight = windowSize.height;\n \n photoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);\n }\n\n const cacheContext = appDownloadManager.getCacheContext(photo, photoSize.type);\n if(cacheContext.downloaded >= ('size' in photoSize ? photoSize.size : 0) && cacheContext.url) {\n return Promise.resolve() as any;\n }\n \n const downloadOptions = this.getPhotoDownloadOptions(photo, photoSize, queueId, onlyCache);\n const fileName = getFileNameByLocation(downloadOptions.location);\n\n let download = appDownloadManager.getDownload(fileName);\n if(download) {\n return download;\n }\n\n download = appDownloadManager.download(downloadOptions);\n download.then(blob => {\n if(!cacheContext.downloaded || cacheContext.downloaded < blob.size) {\n const url = URL.createObjectURL(blob);\n cacheContext.downloaded = blob.size;\n cacheContext.url = url;\n\n //console.log('wrote photo:', photo, photoSize, cacheContext, blob);\n }\n\n return blob;\n }).catch(() => {});\n\n return download;\n }\n \n public getPhoto(photoId: any/* MyPhoto | string */): MyPhoto {\n return isObject(photoId) ? photoId as MyPhoto : this.photos[photoId as any as string];\n }\n\n public getInput(photo: MyPhoto): InputPhoto.inputPhoto {\n return {\n _: 'inputPhoto',\n id: photo.id,\n access_hash: photo.access_hash,\n file_reference: photo.file_reference\n };\n }\n\n public getMediaInput(photo: MyPhoto): InputMedia.inputMediaPhoto {\n return {\n _: 'inputMediaPhoto',\n id: this.getInput(photo),\n ttl_seconds: 0\n };\n }\n\n public savePhotoFile(photo: MyPhoto | MyDocument, queueId?: number) {\n const fullPhotoSize = this.choosePhotoSize(photo, 0xFFFF, 0xFFFF);\n if(!(fullPhotoSize._ === 'photoSize' || fullPhotoSize._ === 'photoSizeProgressive')) {\n return;\n }\n\n const downloadOptions = this.getPhotoDownloadOptions(photo, fullPhotoSize, queueId);\n downloadOptions.fileName = 'photo' + photo.id + '.jpg';\n appDownloadManager.downloadToDisc(downloadOptions, downloadOptions.fileName);\n }\n}\n\nconst appPhotosManager = new AppPhotosManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appPhotosManager = appPhotosManager);\nexport default appPhotosManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport { tsNow } from \"../../helpers/date\";\nimport numberThousandSplitter from \"../../helpers/number/numberThousandSplitter\";\nimport { ChannelParticipantsFilter, ChannelsChannelParticipants, ChannelParticipant, Chat, ChatFull, ChatParticipants, ChatPhoto, ExportedChatInvite, InputChannel, InputFile, SendMessageAction, Update, UserFull, Photo, PhotoSize } from \"../../layer\";\nimport { LangPackKey, i18n } from \"../langPack\";\n//import apiManager from '../mtproto/apiManager';\nimport apiManager from '../mtproto/mtprotoworker';\nimport { RichTextProcessor } from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport SearchIndex from \"../searchIndex\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appChatsManager from \"./appChatsManager\";\nimport appMessagesIdsManager from \"./appMessagesIdsManager\";\nimport appNotificationsManager from \"./appNotificationsManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appPhotosManager from \"./appPhotosManager\";\nimport appUsersManager, { MyTopPeer, User } from \"./appUsersManager\";\n\nexport type UserTyping = Partial<{userId: UserId, action: SendMessageAction, timeout: number}>;\n\nexport class AppProfileManager {\n //private botInfos: any = {};\n private usersFull: {[id: UserId]: UserFull.userFull} = {};\n private chatsFull: {[id: ChatId]: ChatFull} = {};\n private typingsInPeer: {[peerId: PeerId]: UserTyping[]};\n\n constructor() {\n rootScope.addMultipleEventsListeners({\n updateChatParticipants: (update) => {\n const participants = update.participants;\n if(participants._ === 'chatParticipants') {\n const chatId = participants.chat_id;\n const chatFull = this.chatsFull[chatId] as ChatFull.chatFull;\n if(chatFull !== undefined) {\n chatFull.participants = participants;\n rootScope.dispatchEvent('chat_full_update', chatId);\n }\n }\n },\n\n updateChatParticipantAdd: (update) => {\n const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull;\n if(chatFull !== undefined) {\n const _participants = chatFull.participants as ChatParticipants.chatParticipants;\n const participants = _participants.participants || [];\n for(let i = 0, length = participants.length; i < length; i++) {\n if(participants[i].user_id === update.user_id) {\n return;\n }\n }\n\n participants.push({\n _: 'chatParticipant',\n user_id: update.user_id,\n inviter_id: update.inviter_id,\n date: tsNow(true)\n });\n\n _participants.version = update.version;\n rootScope.dispatchEvent('chat_full_update', update.chat_id);\n }\n },\n\n updateChatParticipantDelete: (update) => {\n const chatFull = this.chatsFull[update.chat_id] as ChatFull.chatFull;\n if(chatFull !== undefined) {\n const _participants = chatFull.participants as ChatParticipants.chatParticipants;\n const participants = _participants.participants || [];\n for(let i = 0, length = participants.length; i < length; i++) {\n if(participants[i].user_id === update.user_id) {\n participants.splice(i, 1);\n _participants.version = update.version;\n rootScope.dispatchEvent('chat_full_update', update.chat_id);\n return;\n }\n }\n }\n },\n\n updateUserTyping: this.onUpdateUserTyping,\n updateChatUserTyping: this.onUpdateUserTyping,\n updateChannelUserTyping: this.onUpdateUserTyping,\n\n updatePeerBlocked: this.onUpdatePeerBlocked\n });\n\n rootScope.addEventListener('chat_update', (chatId) => {\n const fullChat = this.chatsFull[chatId];\n const chat: Chat.chat | Chat.channel | Chat.chatForbidden | Chat.channelForbidden = appChatsManager.getChat(chatId);\n if(!fullChat || !chat) {\n return;\n }\n\n let updated = false;\n if(!!fullChat.call !== !!(chat as Chat.chat).pFlags?.call_active) {\n updated = true;\n }\n\n const {photo} = chat as Chat.chat;\n if(photo) {\n const hasChatPhoto = photo._ !== 'chatPhotoEmpty';\n const hasFullChatPhoto = !!(fullChat.chat_photo && fullChat.chat_photo._ !== 'photoEmpty'); // chat_photo can be missing\n if(\n hasChatPhoto !== hasFullChatPhoto || (\n hasChatPhoto && \n photo.photo_id !== fullChat.chat_photo?.id\n )\n ) {\n updated = true;\n }\n }\n\n if(updated) {\n this.refreshFullPeer(chatId.toPeerId(true));\n }\n });\n\n rootScope.addEventListener('channel_update', (chatId) => {\n this.refreshFullPeer(chatId.toPeerId(true));\n });\n\n // * genius\n rootScope.addEventListener('chat_full_update', (chatId) => {\n rootScope.dispatchEvent('peer_full_update', chatId.toPeerId(true));\n });\n \n // * genius\n rootScope.addEventListener('user_full_update', (userId) => {\n rootScope.dispatchEvent('peer_full_update', userId.toPeerId(false));\n });\n\n rootScope.addEventListener('invalidate_participants', (chatId) => {\n this.invalidateChannelParticipants(chatId);\n });\n\n this.typingsInPeer = {};\n }\n\n /* public saveBotInfo(botInfo: any) {\n const botId = botInfo && botInfo.user_id;\n if(!botId) {\n return null;\n }\n\n const commands: any = {};\n botInfo.commands.forEach((botCommand: any) => {\n commands[botCommand.command] = botCommand.description;\n });\n\n return this.botInfos[botId] = {\n id: botId,\n version: botInfo.version,\n shareText: botInfo.share_text,\n description: botInfo.description,\n commands: commands\n };\n } */\n\n public getProfile(id: UserId, override?: true) {\n if(this.usersFull[id] && !override) {\n return this.usersFull[id];\n }\n\n return apiManager.invokeApiSingleProcess({\n method: 'users.getFullUser', \n params: {\n id: appUsersManager.getUserInput(id)\n },\n processResult: (usersUserFull) => {\n appChatsManager.saveApiChats(usersUserFull.chats, true);\n appUsersManager.saveApiUsers(usersUserFull.users);\n\n const userFull = usersUserFull.full_user;\n const peerId = id.toPeerId(false);\n if(userFull.profile_photo) {\n userFull.profile_photo = appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId});\n }\n\n appNotificationsManager.savePeerSettings({\n peerId, \n settings: userFull.notify_settings\n });\n\n this.usersFull[id] = userFull;\n\n /* if(userFull.bot_info) {\n userFull.bot_info = this.saveBotInfo(userFull.bot_info) as any;\n } */\n\n //appMessagesManager.savePinnedMessage(id, userFull.pinned_msg_id);\n\n rootScope.dispatchEvent('user_full_update', id);\n return userFull;\n }\n });\n }\n\n public getProfileByPeerId(peerId: PeerId, override?: true) {\n if(appPeersManager.isAnyChat(peerId)) return this.getChatFull(peerId.toChatId(), override);\n else return this.getProfile(peerId.toUserId(), override);\n }\n\n public getCachedFullChat(chatId: ChatId) {\n return this.chatsFull[chatId];\n }\n\n public getCachedFullUser(userId: UserId) {\n return this.usersFull[userId];\n }\n\n public getCachedProfileByPeerId(peerId: PeerId) {\n return peerId.isUser() ? this.getCachedFullUser(peerId.toUserId()) : this.getCachedFullChat(peerId.toChatId());\n }\n\n public async getFullPhoto(peerId: PeerId) {\n const profile = await this.getProfileByPeerId(peerId);\n switch(profile._) {\n case 'userFull':\n return profile.profile_photo;\n case 'channelFull':\n case 'chatFull':\n return profile.chat_photo;\n }\n }\n\n /* public getPeerBots(peerId: PeerId) {\n var peerBots: any[] = [];\n if(peerId >= 0 && !appUsersManager.isBot(peerId) ||\n (appPeersManager.isChannel(peerId) && !appPeersManager.isMegagroup(peerId))) {\n return Promise.resolve(peerBots);\n }\n if(peerId >= 0) {\n return this.getProfile(peerId).then((userFull: any) => {\n var botInfo = userFull.bot_info;\n if(botInfo && botInfo._ !== 'botInfoEmpty') {\n peerBots.push(botInfo);\n }\n return peerBots;\n });\n }\n\n return this.getChatFull(peerId.toChatId()).then((chatFull: any) => {\n chatFull.bot_info.forEach((botInfo: any) => {\n peerBots.push(this.saveBotInfo(botInfo))\n });\n return peerBots;\n });\n } */\n\n public getChatFull(id: ChatId, override?: true) {\n if(appChatsManager.isChannel(id)) {\n return this.getChannelFull(id, override);\n }\n\n const fullChat = this.chatsFull[id] as ChatFull.chatFull;\n if(fullChat && !override) {\n const chat = appChatsManager.getChat(id);\n if(chat.version === (fullChat.participants as ChatParticipants.chatParticipants).version ||\n chat.pFlags.left) {\n return fullChat as ChatFull;\n }\n }\n \n return apiManager.invokeApiSingleProcess({\n method: 'messages.getFullChat', \n params: {\n chat_id: id\n },\n processResult: (result) => {\n appChatsManager.saveApiChats(result.chats, true);\n appUsersManager.saveApiUsers(result.users);\n const fullChat = result.full_chat as ChatFull.chatFull;\n const peerId = id.toPeerId(true);\n if(fullChat && fullChat.chat_photo && fullChat.chat_photo.id) {\n fullChat.chat_photo = appPhotosManager.savePhoto(fullChat.chat_photo, {type: 'profilePhoto', peerId});\n }\n\n //appMessagesManager.savePinnedMessage(peerId, fullChat.pinned_msg_id);\n appNotificationsManager.savePeerSettings({\n peerId, \n settings: fullChat.notify_settings\n });\n \n this.chatsFull[id] = fullChat;\n rootScope.dispatchEvent('chat_full_update', id);\n\n return fullChat;\n }\n });\n }\n\n public async getChatInviteLink(id: ChatId, force?: boolean) {\n const chatFull = await this.getChatFull(id);\n if(!force &&\n chatFull.exported_invite &&\n chatFull.exported_invite._ == 'chatInviteExported') {\n return chatFull.exported_invite.link;\n }\n \n return apiManager.invokeApi('messages.exportChatInvite', {\n peer: appPeersManager.getInputPeerById(id.toPeerId(true))\n }).then((exportedInvite) => {\n if(this.chatsFull[id] !== undefined) {\n this.chatsFull[id].exported_invite = exportedInvite;\n }\n\n return (exportedInvite as ExportedChatInvite.chatInviteExported).link;\n });\n }\n\n public getChannelParticipants(id: ChatId, filter: ChannelParticipantsFilter = {_: 'channelParticipantsRecent'}, limit = 200, offset = 0) {\n if(filter._ === 'channelParticipantsRecent') {\n const chat = appChatsManager.getChat(id);\n if(chat &&\n chat.pFlags && (\n chat.pFlags.kicked ||\n chat.pFlags.broadcast && !chat.pFlags.creator && !chat.admin_rights\n )) {\n return Promise.reject();\n }\n }\n\n return apiManager.invokeApiCacheable('channels.getParticipants', {\n channel: appChatsManager.getChannelInput(id),\n filter,\n offset,\n limit,\n hash: '0'\n }, {cacheSeconds: 60}).then(result => {\n appUsersManager.saveApiUsers((result as ChannelsChannelParticipants.channelsChannelParticipants).users);\n return result as ChannelsChannelParticipants.channelsChannelParticipants;\n });\n /* let maybeAddSelf = (participants: any[]) => {\n let chat = appChatsManager.getChat(id);\n let selfMustBeFirst = filter._ === 'channelParticipantsRecent' &&\n !offset &&\n !chat.pFlags.kicked &&\n !chat.pFlags.left;\n\n if(selfMustBeFirst) {\n participants = copy(participants);\n let myID = appUsersManager.getSelf().id;\n let myIndex = participants.findIndex(p => p.user_id === myID);\n let myParticipant;\n\n if(myIndex !== -1) {\n myParticipant = participants[myIndex];\n participants.splice(myIndex, 1);\n } else {\n myParticipant = {_: 'channelParticipantSelf', user_id: myID};\n }\n\n participants.unshift(myParticipant);\n }\n\n return participants;\n } */\n }\n\n public getChannelParticipant(id: ChatId, peerId: PeerId) {\n return apiManager.invokeApiSingle('channels.getParticipant', {\n channel: appChatsManager.getChannelInput(id),\n participant: appPeersManager.getInputPeerById(peerId),\n }).then(channelParticipant => {\n appUsersManager.saveApiUsers(channelParticipant.users);\n return channelParticipant.participant;\n });\n }\n\n public getChannelFull(id: ChatId, override?: true) {\n if(this.chatsFull[id] !== undefined && !override) {\n return this.chatsFull[id] as ChatFull.channelFull;\n }\n\n return apiManager.invokeApiSingleProcess({\n method: 'channels.getFullChannel', \n params: {\n channel: appChatsManager.getChannelInput(id)\n }, \n processResult: (result) => {\n const peerId = id.toPeerId(true);\n appChatsManager.saveApiChats(result.chats, true);\n appUsersManager.saveApiUsers(result.users);\n const fullChannel = result.full_chat as ChatFull.channelFull;\n if(fullChannel && fullChannel.chat_photo.id) {\n fullChannel.chat_photo = appPhotosManager.savePhoto(fullChannel.chat_photo, {type: 'profilePhoto', peerId});\n //appPhotosManager.savePhoto(fullChannel.chat_photo);\n }\n appNotificationsManager.savePeerSettings({\n peerId, \n settings: fullChannel.notify_settings\n });\n\n this.chatsFull[id] = fullChannel;\n rootScope.dispatchEvent('chat_full_update', id);\n\n return fullChannel;\n }, \n processError: (error) => {\n switch(error.type) {\n case 'CHANNEL_PRIVATE':\n let channel = appChatsManager.getChat(id);\n channel = {_: 'channelForbidden', access_hash: channel.access_hash, title: channel.title};\n apiUpdatesManager.processUpdateMessage({\n _: 'updates',\n updates: [{\n _: 'updateChannel',\n channel_id: id\n } as Update.updateChannel],\n chats: [channel],\n users: []\n });\n break;\n }\n\n throw error;\n }\n });\n }\n\n public getMentions(chatId: ChatId, query: string, threadId?: number): Promise<PeerId[]> {\n const processUserIds = (topPeers: MyTopPeer[]) => {\n const startsWithAt = query.charAt(0) === '@';\n if(startsWithAt) query = query.slice(1);\n /* const startsWithAt = query.charAt(0) === '@';\n if(startsWithAt) query = query.slice(1);\n \n const index = new SearchIndex<number>(!startsWithAt, !startsWithAt); */\n const index = new SearchIndex<PeerId>({\n ignoreCase: true\n });\n\n const ratingMap: Map<PeerId, number> = new Map();\n topPeers.forEach(peer => {\n index.indexObject(peer.id, appUsersManager.getUserSearchText(peer.id));\n ratingMap.set(peer.id, peer.rating);\n });\n\n const peerIds = Array.from(index.search(query));\n peerIds.sort((a, b) => ratingMap.get(b) - ratingMap.get(a));\n return peerIds;\n };\n\n let promise: Promise<PeerId[]>;\n if(appChatsManager.isChannel(chatId)) {\n promise = this.getChannelParticipants(chatId, {\n _: 'channelParticipantsMentions',\n q: query,\n top_msg_id: appMessagesIdsManager.getServerMessageId(threadId)\n }, 50, 0).then(cP => {\n return cP.participants.map(p => appChatsManager.getParticipantPeerId(p));\n });\n } else if(chatId) {\n promise = Promise.resolve(this.getChatFull(chatId)).then(chatFull => {\n return ((chatFull as ChatFull.chatFull).participants as ChatParticipants.chatParticipants).participants.map(p => p.user_id.toPeerId());\n });\n } else {\n promise = Promise.resolve([]);\n }\n\n return Promise.all([\n // [],\n appUsersManager.getTopPeers('bots_inline').catch(() => [] as MyTopPeer[]), \n promise\n ]).then(results => {\n const peers = results[0].concat(results[1].map(peerId => ({id: peerId, rating: 0})));\n\n return processUserIds(peers);\n });\n }\n\n public invalidateChannelParticipants(id: ChatId) {\n apiManager.clearCache('channels.getParticipants', (params) => (params.channel as InputChannel.inputChannel).channel_id === id);\n this.refreshFullPeer(id.toPeerId(true));\n }\n\n private refreshFullPeer(peerId: PeerId) {\n if(peerId.isUser()) {\n const userId = peerId.toUserId();\n delete this.usersFull[userId];\n rootScope.dispatchEvent('user_full_update', userId);\n } else {\n const chatId = peerId.toChatId();\n delete this.chatsFull[chatId];\n rootScope.dispatchEvent('chat_full_update', chatId);\n }\n\n // ! эта строчка будет создавать race condition:\n // ! запрос вернёт chat с установленным флагом call_not_empty, хотя сам апдейт уже будет применён\n // this.getProfileByPeerId(peerId, true);\n }\n\n public updateProfile(first_name?: string, last_name?: string, about?: string) {\n return apiManager.invokeApi('account.updateProfile', {\n first_name,\n last_name,\n about\n }).then(user => {\n appUsersManager.saveApiUser(user);\n\n if(about !== undefined) {\n const peerId = user.id.toPeerId();\n const userFull = this.usersFull[user.id];\n if(userFull) {\n userFull.about = about;\n }\n \n rootScope.dispatchEvent('peer_bio_edit', peerId);\n }\n \n return this.getProfile(rootScope.myId, true);\n });\n }\n\n public uploadProfilePhoto(inputFile: InputFile) {\n return apiManager.invokeApi('photos.uploadProfilePhoto', {\n file: inputFile\n }).then((updateResult) => {\n // ! sometimes can have no user in users\n const photo = updateResult.photo as Photo.photo;\n if(!updateResult.users.length) {\n const strippedThumb = photo.sizes.find(size => size._ === 'photoStrippedSize') as PhotoSize.photoStrippedSize;\n updateResult.users.push({\n ...appUsersManager.getSelf(), \n photo: {\n _: 'userProfilePhoto',\n dc_id: photo.dc_id,\n photo_id: photo.id,\n stripped_thumb: strippedThumb?.bytes,\n pFlags: {\n\n }\n }\n });\n }\n appUsersManager.saveApiUsers(updateResult.users);\n\n const myId = rootScope.myId;\n appPhotosManager.savePhoto(updateResult.photo, {\n type: 'profilePhoto',\n peerId: myId\n });\n\n const userId = myId.toUserId();\n apiUpdatesManager.processLocalUpdate({\n _: 'updateUserPhoto',\n user_id: userId,\n date: tsNow(true),\n photo: appUsersManager.getUser(userId).photo,\n previous: true\n });\n });\n }\n\n public deletePhotos(photoIds: string[]) {\n return apiManager.invokeApiSingle('photos.deletePhotos', {\n id: photoIds.map(photoId => {\n const photo = appPhotosManager.getPhoto(photoId);\n return appPhotosManager.getInput(photo);\n })\n }).then((deletedList) => {\n \n });\n }\n\n public getChatMembersString(chatId: ChatId) {\n const chat: Chat = appChatsManager.getChat(chatId);\n if(chat._ === 'chatForbidden') {\n return i18n('YouWereKicked');\n }\n\n const chatFull = this.chatsFull[chatId];\n let count: number;\n if(chatFull) {\n if(chatFull._ === 'channelFull') {\n count = chatFull.participants_count;\n } else {\n count = (chatFull.participants as ChatParticipants.chatParticipants).participants?.length;\n }\n } else {\n count = (chat as Chat.chat).participants_count || (chat as any).participants?.participants.length;\n }\n\n const isChannel = appChatsManager.isBroadcast(chatId);\n count = count || 1;\n\n let key: LangPackKey = isChannel ? 'Peer.Status.Subscribers' : 'Peer.Status.Member';\n return i18n(key, [numberThousandSplitter(count)]);\n }\n\n private verifyParticipantForOnlineCount(participant: {user_id: UserId}) {\n const user = appUsersManager.getUser(participant.user_id);\n return !!(user && user.status && user.status._ === 'userStatusOnline');\n }\n\n private reduceParticipantsForOnlineCount(participants: {user_id: UserId}[]) {\n return participants.reduce((acc, participant) => {\n return acc + +this.verifyParticipantForOnlineCount(participant);\n }, 0);\n }\n\n public async getOnlines(id: ChatId): Promise<number> {\n const minOnline = 1;\n if(appChatsManager.isBroadcast(id)) {\n return minOnline;\n }\n \n const chatInfo = await this.getChatFull(id);\n if(appChatsManager.isMegagroup(id)) {\n if((chatInfo as ChatFull.channelFull).participants_count <= 100) {\n const channelParticipants = await this.getChannelParticipants(id, {_: 'channelParticipantsRecent'}, 100);\n return this.reduceParticipantsForOnlineCount(channelParticipants.participants as ChannelParticipant.channelParticipant[]);\n }\n\n const res = await apiManager.invokeApiCacheable('messages.getOnlines', {\n peer: appChatsManager.getChannelInputPeer(id)\n }, {cacheSeconds: 60});\n\n const onlines = res.onlines ?? minOnline;\n return onlines;\n }\n\n const _participants = (chatInfo as ChatFull.chatFull).participants as ChatParticipants.chatParticipants;\n if(_participants?.participants) {\n return this.reduceParticipantsForOnlineCount(_participants.participants);\n } else {\n return minOnline;\n }\n }\n\n private onUpdateUserTyping = (update: Update.updateUserTyping | Update.updateChatUserTyping | Update.updateChannelUserTyping) => {\n const fromId = (update as Update.updateUserTyping).user_id ? \n (update as Update.updateUserTyping).user_id.toPeerId() : \n appPeersManager.getPeerId((update as Update.updateChatUserTyping).from_id);\n if(rootScope.myId === fromId || update.action._ === 'speakingInGroupCallAction') {\n return;\n }\n \n const peerId = appPeersManager.getPeerId(update);\n const typings = this.typingsInPeer[peerId] ?? (this.typingsInPeer[peerId] = []);\n let typing = typings.find(t => t.userId === fromId);\n\n const cancelAction = () => {\n delete typing.timeout;\n //typings.findAndSplice(t => t === typing);\n const idx = typings.indexOf(typing);\n if(idx !== -1) {\n typings.splice(idx, 1);\n }\n\n rootScope.dispatchEvent('peer_typings', {peerId, typings});\n\n if(!typings.length) {\n delete this.typingsInPeer[peerId];\n }\n };\n\n if(typing && typing.timeout !== undefined) {\n clearTimeout(typing.timeout);\n }\n\n if(update.action._ === 'sendMessageCancelAction') {\n if(!typing) {\n return;\n }\n\n cancelAction();\n return;\n }\n\n if(!typing) {\n typing = {\n userId: fromId\n };\n\n typings.push(typing);\n }\n\n //console.log('updateChatUserTyping', update, typings);\n \n typing.action = update.action;\n \n const hasUser = appUsersManager.hasUser(fromId);\n if(!hasUser) {\n // let's load user here\n if(update._ === 'updateChatUserTyping') {\n if(update.chat_id && appChatsManager.hasChat(update.chat_id) && !appChatsManager.isChannel(update.chat_id)) {\n Promise.resolve(this.getChatFull(update.chat_id)).then(() => {\n if(typing.timeout !== undefined && appUsersManager.hasUser(fromId)) {\n rootScope.dispatchEvent('peer_typings', {peerId, typings});\n }\n });\n }\n }\n \n //return;\n } else {\n appUsersManager.forceUserOnline(fromId);\n }\n\n typing.timeout = window.setTimeout(cancelAction, 6000);\n if(hasUser) {\n rootScope.dispatchEvent('peer_typings', {peerId, typings});\n }\n };\n\n private onUpdatePeerBlocked = (update: Update.updatePeerBlocked) => {\n const peerId = appPeersManager.getPeerId(update.peer_id);\n if(appPeersManager.isUser(peerId)) {\n const userId = peerId.toUserId();\n const userFull = this.usersFull[userId];\n if(userFull) {\n if(update.blocked) userFull.pFlags.blocked = true;\n else delete userFull.pFlags.blocked;\n }\n\n rootScope.dispatchEvent('user_full_update', userId);\n }\n\n rootScope.dispatchEvent('peer_block', {peerId, blocked: update.blocked});\n };\n\n public getPeerTypings(peerId: PeerId) {\n return this.typingsInPeer[peerId];\n }\n}\n\nconst appProfileManager = new AppProfileManager();\nMOUNT_CLASS_TO.appProfileManager = appProfileManager;\nexport default appProfileManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\n//import apiManager from '../mtproto/apiManager';\nimport DEBUG, { MOUNT_CLASS_TO } from '../../config/debug';\nimport { Message, MessageEntity, MessageFwdHeader, Peer, Update, Updates } from '../../layer';\nimport { logger, LogTypes } from '../logger';\nimport apiManager from '../mtproto/mtprotoworker';\nimport rootScope from '../rootScope';\n//import networkerFactory from '../mtproto/networkerFactory';\nimport appUsersManager from \"./appUsersManager\";\nimport appChatsManager from \"./appChatsManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appStateManager from './appStateManager';\nimport serverTimeManager from '../mtproto/serverTimeManager';\nimport assumeType from '../../helpers/assumeType';\nimport noop from '../../helpers/noop';\nimport RichTextProcessor from '../richtextprocessor';\nimport App from '../../config/app';\n\ntype UpdatesState = {\n pendingPtsUpdates: (Update & {pts: number, pts_count: number})[],\n pendingSeqUpdates?: {[seq: number]: {seq: number, date: number, updates: any[]}},\n syncPending: {\n seqAwaiting?: number,\n ptsAwaiting?: true,\n timeout: number\n },\n syncLoading: Promise<void>,\n\n seq?: number,\n pts?: number,\n date?: number,\n lastPtsUpdateTime?: number\n};\n\nconst SYNC_DELAY = 6;\n\nexport class ApiUpdatesManager {\n public updatesState: UpdatesState = {\n pendingPtsUpdates: [],\n pendingSeqUpdates: {},\n syncPending: null,\n syncLoading: null\n };\n\n private channelStates: {[channelId: ChatId]: UpdatesState} = {};\n private attached = false;\n\n private log = logger('UPDATES', LogTypes.Error | LogTypes.Warn | LogTypes.Log/* | LogTypes.Debug */);\n private debug = DEBUG;\n\n private setProxy() {\n const self = this;\n this.updatesState = new Proxy(this.updatesState, {\n set: function(target: ApiUpdatesManager['updatesState'], key: keyof ApiUpdatesManager['updatesState'], value: ApiUpdatesManager['updatesState'][typeof key]) {\n // @ts-ignore\n target[key] = value;\n self.saveUpdatesState();\n return true;\n }\n });\n }\n\n public saveUpdatesState() {\n const us = this.updatesState;\n appStateManager.pushToState('updates', {\n seq: us.seq,\n pts: us.pts,\n date: us.date\n });\n }\n\n private popPendingSeqUpdate() {\n const state = this.updatesState;\n const nextSeq = state.seq + 1;\n const pendingUpdatesData = state.pendingSeqUpdates[nextSeq];\n if(!pendingUpdatesData) {\n return false;\n }\n\n const updates = pendingUpdatesData.updates;\n for(let i = 0, length = updates.length; i < length; ++i) {\n this.saveUpdate(updates[i]);\n }\n\n state.seq = pendingUpdatesData.seq;\n if(pendingUpdatesData.date && state.date < pendingUpdatesData.date) {\n state.date = pendingUpdatesData.date;\n }\n delete state.pendingSeqUpdates[nextSeq];\n \n if(!this.popPendingSeqUpdate() &&\n state.syncPending &&\n state.syncPending.seqAwaiting &&\n state.seq >= state.syncPending.seqAwaiting) {\n if(!state.syncPending.ptsAwaiting) {\n clearTimeout(state.syncPending.timeout);\n state.syncPending = null;\n } else {\n delete state.syncPending.seqAwaiting;\n }\n }\n \n return true;\n }\n\n private popPendingPtsUpdate(channelId: ChatId) {\n const curState = channelId ? this.getChannelState(channelId) : this.updatesState;\n if(!curState.pendingPtsUpdates.length) {\n return false;\n }\n\n curState.pendingPtsUpdates.sort((a, b) => {\n return a.pts - b.pts;\n });\n // this.log('pop update', channelId, curState.pendingPtsUpdates)\n \n let curPts = curState.pts;\n let goodPts = 0;\n let goodIndex = 0;\n for(let i = 0, length = curState.pendingPtsUpdates.length; i < length; ++i) {\n const update = curState.pendingPtsUpdates[i];\n curPts += update.pts_count;\n if(curPts >= update.pts) {\n goodPts = update.pts;\n goodIndex = i;\n }\n }\n \n if(!goodPts) {\n return false;\n }\n \n this.debug && this.log.debug('pop pending pts updates', goodPts, curState.pendingPtsUpdates.slice(0, goodIndex + 1));\n \n curState.pts = goodPts;\n for(let i = 0; i <= goodIndex; ++i) {\n const update = curState.pendingPtsUpdates[i];\n\n // @ts-ignore\n this.saveUpdate(update);\n }\n curState.pendingPtsUpdates.splice(0, goodIndex + 1);\n \n if(!curState.pendingPtsUpdates.length && curState.syncPending) {\n if(!curState.syncPending.seqAwaiting) {\n clearTimeout(curState.syncPending.timeout);\n curState.syncPending = null;\n } else {\n delete curState.syncPending.ptsAwaiting;\n }\n }\n \n return true;\n }\n\n public forceGetDifference() {\n if(!this.updatesState.syncLoading) {\n this.getDifference();\n }\n }\n\n public processLocalUpdate(update: Update) {\n this.processUpdateMessage({\n _: 'updateShort',\n update\n } as Updates);\n }\n\n public processUpdateMessage = (updateMessage: any, options: Partial<{\n override: boolean\n }> = {}) => {\n // return forceGetDifference()\n const processOpts = {\n date: updateMessage.date,\n seq: updateMessage.seq,\n seqStart: updateMessage.seq_start,\n //ignoreSyncLoading: options.ignoreSyncLoading\n };\n\n this.debug && this.log.debug('processUpdateMessage', updateMessage);\n \n switch(updateMessage._) {\n case 'updatesTooLong':\n case 'new_session_created':\n this.forceGetDifference();\n break;\n \n case 'updateShort':\n this.processUpdate(updateMessage.update, processOpts);\n break;\n \n case 'updateShortMessage':\n case 'updateShortChatMessage': {\n assumeType<Updates.updateShortChatMessage | Updates.updateShortMessage>(updateMessage);\n this.debug && this.log.debug('updateShortMessage | updateShortChatMessage', {...updateMessage});\n const isOut = updateMessage.pFlags.out;\n const fromId = (updateMessage as Updates.updateShortChatMessage).from_id || (isOut ? rootScope.myId : (updateMessage as Updates.updateShortMessage).user_id);\n const toId = (updateMessage as Updates.updateShortChatMessage).chat_id\n ? (updateMessage as Updates.updateShortChatMessage).chat_id.toPeerId(true)\n : ((updateMessage as Updates.updateShortMessage).user_id.toPeerId(false) || rootScope.myId);\n \n this.processUpdate({\n _: 'updateNewMessage',\n message: {\n _: 'message',\n pFlags: updateMessage.pFlags,\n id: updateMessage.id,\n from_id: appPeersManager.getOutputPeer(fromId.toPeerId()),\n peer_id: appPeersManager.getOutputPeer(toId),\n date: updateMessage.date,\n message: updateMessage.message,\n fwd_from: updateMessage.fwd_from,\n reply_to: updateMessage.reply_to,\n entities: updateMessage.entities\n },\n pts: updateMessage.pts,\n pts_count: updateMessage.pts_count\n }, processOpts);\n break;\n }\n \n case 'updatesCombined':\n case 'updates':\n appUsersManager.saveApiUsers(updateMessage.users, options.override);\n appChatsManager.saveApiChats(updateMessage.chats, options.override);\n \n updateMessage.updates.forEach((update: Update) => {\n this.processUpdate(update, processOpts);\n });\n break;\n \n default:\n this.log.warn('Unknown update message', updateMessage);\n }\n };\n \n private getDifference(first = false): Promise<void> {\n // this.trace('Get full diff')\n const updatesState = this.updatesState;\n let wasSyncing = updatesState.syncLoading;\n if(!wasSyncing) {\n updatesState.pendingSeqUpdates = {};\n updatesState.pendingPtsUpdates = [];\n }\n \n if(updatesState.syncPending) {\n clearTimeout(updatesState.syncPending.timeout);\n updatesState.syncPending = null;\n }\n\n const promise = apiManager.invokeApi('updates.getDifference', {\n pts: updatesState.pts, \n pts_total_limit: first /* && false */? /* 50 */1200 : undefined,\n date: updatesState.date, \n qts: -1\n }, {\n timeout: 0x7fffffff\n }).then((differenceResult) => {\n this.debug && this.log.debug('Get diff result', differenceResult);\n\n if(differenceResult._ === 'updates.differenceEmpty') {\n this.debug && this.log.debug('apply empty diff', differenceResult.seq);\n updatesState.date = differenceResult.date;\n updatesState.seq = differenceResult.seq;\n return;\n }\n\n // ! SORRY I'M SORRY I'M SORRY\n if(first) {\n rootScope.dispatchEvent('state_synchronizing');\n }\n\n if(differenceResult._ !== 'updates.differenceTooLong') {\n appUsersManager.saveApiUsers(differenceResult.users);\n appChatsManager.saveApiChats(differenceResult.chats);\n\n // Should be first because of updateMessageID\n // this.log('applying', differenceResult.other_updates.length, 'other updates')\n \n differenceResult.other_updates.forEach((update) => {\n switch(update._) {\n case 'updateChannelTooLong':\n case 'updateNewChannelMessage':\n case 'updateEditChannelMessage':\n this.processUpdate(update);\n return;\n }\n \n this.saveUpdate(update);\n });\n\n // this.log('applying', differenceResult.new_messages.length, 'new messages')\n differenceResult.new_messages.forEach((apiMessage) => {\n this.saveUpdate({\n _: 'updateNewMessage',\n message: apiMessage,\n pts: updatesState.pts,\n pts_count: 0\n });\n });\n\n const nextState = differenceResult._ === 'updates.difference' ? differenceResult.state : differenceResult.intermediate_state;\n updatesState.seq = nextState.seq;\n updatesState.pts = nextState.pts;\n updatesState.date = nextState.date;\n } else {\n updatesState.pts = differenceResult.pts;\n updatesState.date = (Date.now() / 1000 | 0) + serverTimeManager.serverTimeOffset;\n delete updatesState.seq;\n \n this.channelStates = {};\n \n this.log.warn('getDifference:', differenceResult._);\n rootScope.dispatchEvent('state_cleared');\n }\n \n // this.log('apply diff', updatesState.seq, updatesState.pts)\n \n if(differenceResult._ === 'updates.differenceSlice') {\n return this.getDifference();\n } else {\n this.debug && this.log.debug('finished get diff');\n }\n });\n\n if(!wasSyncing) {\n this.justAName(updatesState, promise);\n }\n \n return promise;\n }\n\n private getChannelDifference(channelId: ChatId): Promise<void> {\n const channelState = this.getChannelState(channelId);\n const wasSyncing = channelState.syncLoading;\n if(!wasSyncing) {\n channelState.pendingPtsUpdates = [];\n }\n\n if(channelState.syncPending) {\n clearTimeout(channelState.syncPending.timeout);\n channelState.syncPending = null;\n }\n\n //this.log.trace('Get channel diff', appChatsManager.getChat(channelId), channelState.pts);\n const promise = apiManager.invokeApi('updates.getChannelDifference', {\n channel: appChatsManager.getChannelInput(channelId),\n filter: {_: 'channelMessagesFilterEmpty'},\n pts: channelState.pts,\n limit: 30\n }, {timeout: 0x7fffffff}).then((differenceResult) => {\n this.debug && this.log.debug('Get channel diff result', differenceResult)\n channelState.pts = 'pts' in differenceResult ? differenceResult.pts : undefined;\n \n if(differenceResult._ === 'updates.channelDifferenceEmpty') {\n this.debug && this.log.debug('apply channel empty diff', differenceResult);\n return;\n }\n \n if(differenceResult._ === 'updates.channelDifferenceTooLong') {\n this.debug && this.log.debug('channel diff too long', differenceResult);\n delete this.channelStates[channelId];\n\n this.saveUpdate({_: 'updateChannelReload', channel_id: channelId});\n return;\n }\n \n appUsersManager.saveApiUsers(differenceResult.users);\n appChatsManager.saveApiChats(differenceResult.chats);\n \n // Should be first because of updateMessageID\n this.debug && this.log.debug('applying', differenceResult.other_updates.length, 'channel other updates');\n differenceResult.other_updates.forEach((update) => {\n this.saveUpdate(update);\n });\n \n this.debug && this.log.debug('applying', differenceResult.new_messages.length, 'channel new messages');\n differenceResult.new_messages.forEach((apiMessage) => {\n this.saveUpdate({\n _: 'updateNewChannelMessage',\n message: apiMessage,\n pts: channelState.pts,\n pts_count: 0\n });\n });\n \n this.debug && this.log.debug('apply channel diff', channelState.pts);\n \n if(differenceResult._ === 'updates.channelDifference' &&\n !differenceResult.pFlags['final']) {\n return this.getChannelDifference(channelId);\n } else {\n this.debug && this.log.debug('finished channel get diff');\n }\n });\n\n if(!wasSyncing) {\n this.justAName(channelState, promise, channelId);\n }\n\n return promise;\n }\n\n private justAName(state: UpdatesState, promise: UpdatesState['syncLoading'], channelId?: ChatId) {\n state.syncLoading = promise;\n rootScope.dispatchEvent('state_synchronizing', channelId);\n\n promise.then(() => {\n state.syncLoading = null;\n rootScope.dispatchEvent('state_synchronized', channelId);\n }, () => {\n state.syncLoading = null;\n });\n }\n \n public addChannelState(channelId: ChatId, pts: number) {\n if(!pts) {\n throw new Error('Add channel state without pts ' + channelId);\n }\n\n if(!(channelId in this.channelStates)) {\n this.channelStates[channelId] = {\n pts,\n pendingPtsUpdates: [],\n syncPending: null,\n syncLoading: null\n };\n\n return true;\n }\n\n return false;\n }\n\n public getChannelState(channelId: ChatId, pts?: number) {\n if(this.channelStates[channelId] === undefined) {\n this.addChannelState(channelId, pts);\n }\n\n return this.channelStates[channelId];\n }\n\n private processUpdate(update: Update, options: Partial<{\n date: number,\n seq: number,\n seqStart: number/* ,\n ignoreSyncLoading: boolean */\n }> = {}) {\n let channelId: ChatId;\n switch(update._) {\n case 'updateNewChannelMessage':\n case 'updateEditChannelMessage':\n channelId = appPeersManager.getPeerId(update.message.peer_id).toChatId();\n break;\n /* case 'updateDeleteChannelMessages':\n channelId = update.channel_id;\n break; */\n case 'updateChannelTooLong':\n channelId = update.channel_id;\n if(!(channelId in this.channelStates)) {\n return false;\n }\n break;\n default:\n if('channel_id' in update && 'pts' in update) {\n channelId = update.channel_id;\n }\n break;\n }\n \n const {pts, pts_count} = update as Update.updateNewMessage;\n const curState = channelId ? this.getChannelState(channelId, pts) : this.updatesState;\n \n // this.log.log('process', channelId, curState.pts, update)\n \n if(curState.syncLoading/* && !options.ignoreSyncLoading */) {\n return false;\n }\n \n if(update._ === 'updateChannelTooLong') {\n if(!curState.lastPtsUpdateTime ||\n curState.lastPtsUpdateTime < (Date.now() - SYNC_DELAY)) {\n // this.log.trace('channel too long, get diff', channelId, update)\n this.getChannelDifference(channelId);\n }\n return false;\n }\n \n if(update._ === 'updateNewMessage' ||\n update._ === 'updateEditMessage' ||\n update._ === 'updateNewChannelMessage' ||\n update._ === 'updateEditChannelMessage') {\n const message = update.message as Message.message;\n const toPeerId = appPeersManager.getPeerId(message.peer_id);\n const fwdHeader: MessageFwdHeader.messageFwdHeader = message.fwd_from || {} as any;\n let reason: string;\n if(message.from_id && !appUsersManager.hasUser(appPeersManager.getPeerId(message.from_id), message.pFlags.post/* || channelId*/) && (reason = 'author') ||\n fwdHeader.from_id && !appUsersManager.hasUser(appPeersManager.getPeerId(fwdHeader.from_id), !!(fwdHeader.from_id as Peer.peerChannel).channel_id) && (reason = 'fwdAuthor') ||\n (fwdHeader.from_id as Peer.peerChannel)?.channel_id && !appChatsManager.hasChat((fwdHeader.from_id as Peer.peerChannel).channel_id, true) && (reason = 'fwdChannel') ||\n toPeerId.isUser() && !appUsersManager.hasUser(toPeerId) && (reason = 'toPeer User') ||\n toPeerId.isAnyChat() && !appChatsManager.hasChat(toPeerId.toChatId()) && (reason = 'toPeer Chat')) {\n this.log.warn('Not enough data for message update', toPeerId, reason, message);\n if(channelId && appChatsManager.hasChat(channelId)) {\n this.getChannelDifference(channelId);\n } else {\n this.forceGetDifference();\n }\n return false;\n }\n } else if(channelId && !appChatsManager.hasChat(channelId)) {\n // this.log.log('skip update, missing channel', channelId, update)\n return false;\n }\n \n let popPts: boolean;\n let popSeq: boolean;\n \n if(pts) {\n const newPts = curState.pts + (pts_count || 0);\n if(newPts < pts) {\n this.debug && this.log.warn('Pts hole', curState, update, channelId && appChatsManager.getChat(channelId));\n curState.pendingPtsUpdates.push(update as Update.updateNewMessage);\n if(!curState.syncPending && !curState.syncLoading) {\n curState.syncPending = {\n timeout: window.setTimeout(() => {\n curState.syncPending = null;\n\n if(curState.syncLoading) {\n return;\n }\n\n if(channelId) {\n this.getChannelDifference(channelId);\n } else {\n this.getDifference();\n }\n }, SYNC_DELAY)\n };\n }\n\n curState.syncPending.ptsAwaiting = true;\n return false;\n }\n\n if(pts > curState.pts) {\n curState.pts = pts;\n popPts = true;\n \n curState.lastPtsUpdateTime = Date.now();\n } else if(pts_count) {\n // this.log.warn('Duplicate update', update)\n return false;\n }\n\n if(channelId && options.date && this.updatesState.date < options.date) {\n this.updatesState.date = options.date;\n }\n } else if(!channelId && options.seq > 0) {\n const seq = options.seq;\n const seqStart = options.seqStart || seq;\n \n if(seqStart !== curState.seq + 1) {\n if(seqStart > curState.seq) {\n this.debug && this.log.warn('Seq hole', curState, curState.syncPending && curState.syncPending.seqAwaiting);\n \n if(curState.pendingSeqUpdates[seqStart] === undefined) {\n curState.pendingSeqUpdates[seqStart] = {seq, date: options.date, updates: []};\n }\n curState.pendingSeqUpdates[seqStart].updates.push(update);\n \n if(!curState.syncPending) {\n curState.syncPending = {\n timeout: window.setTimeout(() => {\n curState.syncPending = null;\n\n if(curState.syncLoading) {\n return;\n }\n\n this.getDifference();\n }, SYNC_DELAY)\n };\n }\n\n if(!curState.syncPending.seqAwaiting ||\n curState.syncPending.seqAwaiting < seqStart) {\n curState.syncPending.seqAwaiting = seqStart;\n }\n return false;\n }\n }\n \n if(curState.seq !== seq) {\n curState.seq = seq;\n if(options.date && curState.date < options.date) {\n curState.date = options.date;\n }\n\n popSeq = true;\n }\n }\n \n this.saveUpdate(update);\n \n if(popPts) {\n this.popPendingPtsUpdate(channelId);\n } else if(popSeq) {\n this.popPendingSeqUpdate();\n }\n }\n\n public saveUpdate(update: Update) {\n //this.debug && this.log('saveUpdate', update);\n rootScope.dispatchEvent(update._, update as any);\n }\n \n public attach() {\n if(this.attached) return;\n\n //return;\n\n this.log('attach');\n \n this.attached = true;\n\n appStateManager.getState().then(({updates: state}) => {\n const newVersion = appStateManager.newVersion/* || '0.8.6' */;\n\n //rootScope.broadcast('state_synchronizing');\n if(!state || !state.pts || !state.date/* || !state.seq */) { // seq can be undefined because of updates.differenceTooLong\n this.log('will get new state');\n\n this.updatesState.syncLoading = new Promise((resolve) => {\n apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult) => {\n this.updatesState.seq = stateResult.seq;\n this.updatesState.pts = stateResult.pts;\n this.updatesState.date = stateResult.date;\n this.saveUpdatesState();\n //setTimeout(() => {\n this.updatesState.syncLoading = null;\n resolve();\n //rootScope.broadcast('state_synchronized');\n //}, 1000);\n \n // ! for testing\n // updatesState.seq = 1\n // updatesState.pts = stateResult.pts - 5000\n // updatesState.date = 1\n // getDifference()\n });\n });\n } else {\n // ! for testing\n /* state.seq = 1;\n state.pts = state.pts - 15;\n state.date = 1; */\n // state.pts -= 100;\n\n /* state.date = 1628623682;\n state.pts = 2007500;\n state.seq = 503; */\n\n Object.assign(this.updatesState, state);\n \n this.log('will get difference', Object.assign({}, state));\n \n this.getDifference(true)/* .finally(() => {\n if(this.updatesState.syncLoading) {\n rootScope.broadcast('state_synchronizing');\n }\n }) */;\n }\n\n apiManager.setUpdatesProcessor(this.processUpdateMessage);\n\n // this.updatesState.syncLoading.then(() => {\n this.setProxy();\n // });\n\n if(newVersion) {\n this.updatesState.syncLoading.then(() => {\n fetch('changelogs/' + newVersion.split(' ')[0] + '.md')\n .then(res => (res.status === 200 && res.ok && res.text()) || Promise.reject())\n .then(text => {\n const pre = `**Telegram Web${App.suffix} was updated to version ${newVersion}**\\n\\n`;\n\n text = pre + text;\n\n const entities: MessageEntity[] = [];\n const message = RichTextProcessor.parseMarkdown(text, entities);\n\n const update: Update.updateServiceNotification = {\n _: 'updateServiceNotification',\n entities,\n message,\n type: 'local',\n pFlags: {},\n inbox_date: Date.now() / 1000 | 0,\n media: undefined\n };\n this.processLocalUpdate(update);\n })\n .catch(noop);\n });\n }\n });\n }\n}\n\nconst apiUpdatesManager = new ApiUpdatesManager();\nMOUNT_CLASS_TO.apiUpdatesManager = apiUpdatesManager;\nexport default apiUpdatesManager\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { Document, InputFileLocation, InputStickerSet, MessagesAllStickers, MessagesFeaturedStickers, MessagesFoundStickerSets, MessagesRecentStickers, MessagesStickers, MessagesStickerSet, PhotoSize, StickerPack, StickerSet, StickerSetCovered } from '../../layer';\nimport { Modify } from '../../types';\nimport apiManager from '../mtproto/mtprotoworker';\nimport rootScope from '../rootScope';\nimport appDocsManager, { MyDocument } from './appDocsManager';\nimport AppStorage from '../storage';\nimport { MOUNT_CLASS_TO } from '../../config/debug';\nimport DATABASE_STATE from '../../config/databases/state';\nimport lottieLoader from '../rlottie/lottieLoader';\nimport mediaSizes from '../../helpers/mediaSizes';\nimport { getEmojiToneIndex } from '../../vendor/emoji';\nimport RichTextProcessor from '../richtextprocessor';\nimport assumeType from '../../helpers/assumeType';\nimport fixBase64String from '../../helpers/fixBase64String';\nimport IS_WEBM_SUPPORTED from '../../environment/webmSupport';\nimport forEachReverse from '../../helpers/array/forEachReverse';\nimport findAndSplice from '../../helpers/array/findAndSplice';\n\nconst CACHE_TIME = 3600e3;\n\nconst EMOJI_SET_LOCAL_ID = 'emoji';\nconst EMOJI_ANIMATIONS_SET_LOCAL_ID = 'emojiAnimations';\nconst LOCAL_IDS_SET = new Set([\n EMOJI_SET_LOCAL_ID,\n EMOJI_ANIMATIONS_SET_LOCAL_ID\n]);\n\n// let TEST_FILE_REFERENCE_REFRESH = true;\n\nexport type MyStickerSetInput = {\n id: StickerSet.stickerSet['id'],\n access_hash?: StickerSet.stickerSet['access_hash']\n};\n\nexport type MyMessagesStickerSet = MessagesStickerSet.messagesStickerSet;\n\nexport class AppStickersManager {\n private storage = new AppStorage<Record<Long, MyMessagesStickerSet>, typeof DATABASE_STATE>(DATABASE_STATE, 'stickerSets');\n\n private getStickerSetPromises: {[setId: Long]: Promise<MyMessagesStickerSet>};\n private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>};\n\n private greetingStickers: Document.document[];\n private getGreetingStickersTimeout: number;\n private getGreetingStickersPromise: Promise<void>;\n\n private sounds: Record<string, MyDocument>;\n private getAnimatedEmojiSoundsPromise: Promise<void>;\n \n constructor() {\n this.getStickerSetPromises = {};\n this.getStickersByEmoticonsPromises = {}; \n this.sounds = {};\n\n this.getAnimatedEmojiStickerSet();\n\n rootScope.addMultipleEventsListeners({\n updateNewStickerSet: (update) => {\n const stickerSet = update.stickerset as MyMessagesStickerSet;\n this.saveStickerSet(stickerSet, stickerSet.set.id);\n rootScope.dispatchEvent('stickers_installed', stickerSet.set);\n }\n });\n\n this.getGreetingStickersTimeout = window.setTimeout(() => {\n this.getGreetingStickersTimeout = undefined;\n this.getGreetingSticker(true);\n }, 5000);\n }\n\n public getGreetingSticker(justPreload = false) {\n if(this.getGreetingStickersTimeout) {\n clearTimeout(this.getGreetingStickersTimeout);\n this.getGreetingStickersTimeout = undefined;\n }\n\n if(!this.getGreetingStickersPromise) {\n this.getGreetingStickersPromise = this.getStickersByEmoticon('👋⭐️', false).then(docs => {\n if(!docs.length) throw 'NO_STICKERS';\n this.greetingStickers = docs.slice() as Document.document[];\n this.greetingStickers.sort((a, b) => Math.random() - Math.random());\n });\n }\n \n return this.getGreetingStickersPromise.then(() => {\n let doc: Document.document;\n if(!justPreload) {\n doc = this.greetingStickers.shift();\n this.greetingStickers.push(doc);\n }\n\n appDocsManager.downloadDoc(this.greetingStickers[0]); // preload next sticker\n\n return doc;\n });\n }\n\n public saveStickers(docs: Document[]) {\n forEachReverse(docs, (doc, idx) => {\n doc = appDocsManager.saveDoc(doc);\n\n if(!doc) docs.splice(idx, 1);\n else docs[idx] = doc;\n });\n }\n\n public async getStickerSet(set: MyStickerSetInput, params: Partial<{\n overwrite: boolean,\n useCache: boolean,\n saveById: boolean\n }> = {}): Promise<MyMessagesStickerSet> {\n const id = set.id;\n if(this.getStickerSetPromises[id]) {\n return this.getStickerSetPromises[id];\n }\n\n return this.getStickerSetPromises[id] = new Promise(async(resolve) => {\n if(!params.overwrite) {\n // const perf = performance.now();\n const cachedSet = await this.storage.get(id);\n if(cachedSet && cachedSet.documents?.length && ((Date.now() - cachedSet.refreshTime) < CACHE_TIME || params.useCache)) {\n this.saveStickers(cachedSet.documents);\n resolve(cachedSet);\n delete this.getStickerSetPromises[id];\n // console.log('get sticker set from cache time', id, performance.now() - perf);\n return;\n }\n }\n\n try {\n const stickerSet = await apiManager.invokeApi('messages.getStickerSet', {\n stickerset: this.getStickerSetInput(set),\n hash: 0\n }) as MyMessagesStickerSet;\n \n const saveById = params.saveById ? id : stickerSet.set.id;\n this.saveStickerSet(stickerSet, saveById);\n \n resolve(stickerSet);\n } catch(err) {\n resolve(null);\n }\n \n delete this.getStickerSetPromises[id];\n });\n }\n\n public getAnimatedEmojiStickerSet() {\n return Promise.all([\n this.getStickerSet({id: EMOJI_SET_LOCAL_ID}, {saveById: true}),\n this.getStickerSet({id: EMOJI_ANIMATIONS_SET_LOCAL_ID}, {saveById: true}),\n this.getAnimatedEmojiSounds()\n ]).then(([emoji, animations]) => {\n return {emoji, animations};\n });\n }\n\n public getAnimatedEmojiSounds(overwrite?: boolean) {\n if(this.getAnimatedEmojiSoundsPromise && !overwrite) return this.getAnimatedEmojiSoundsPromise;\n const promise = this.getAnimatedEmojiSoundsPromise = Promise.resolve(apiManager.getAppConfig(overwrite)).then(appConfig => {\n if(this.getAnimatedEmojiSoundsPromise !== promise) {\n return;\n }\n\n for(const emoji in appConfig.emojies_sounds) {\n const sound = appConfig.emojies_sounds[emoji];\n const bytesStr = atob(fixBase64String(sound.file_reference_base64, false));\n const bytes = new Uint8Array(bytesStr.length);\n for(let i = 0, length = bytes.length; i < length; ++i) {\n bytes[i] = bytesStr[i].charCodeAt(0);\n }\n\n // if(TEST_FILE_REFERENCE_REFRESH) {\n // bytes[0] = bytes[1] = bytes[2] = bytes[3] = bytes[4] = 0;\n // sound.access_hash += '999';\n // }\n \n const doc = appDocsManager.saveDoc({\n _: 'document',\n pFlags: {},\n flags: 0,\n id: sound.id,\n access_hash: sound.access_hash,\n attributes: [{\n _: 'documentAttributeAudio',\n duration: 1,\n pFlags: {\n voice: true\n }\n }],\n date: 0,\n dc_id: rootScope.config.this_dc,\n file_reference: bytes,\n mime_type: 'audio/ogg',\n size: 1\n // size: 101010 // test loading everytime\n }, {\n type: 'emojiesSounds'\n });\n\n this.sounds[emoji] = doc;\n }\n\n // if(TEST_FILE_REFERENCE_REFRESH) {\n // TEST_FILE_REFERENCE_REFRESH = false;\n // }\n });\n\n return promise;\n }\n\n public async getRecentStickers(): Promise<Modify<MessagesRecentStickers.messagesRecentStickers, {\n stickers: Document[]\n }>> {\n const res = await apiManager.invokeApiHashable({\n method: 'messages.getRecentStickers',\n processResult: (res) => {\n assumeType<MessagesRecentStickers.messagesRecentStickers>(res);\n\n this.saveStickers(res.stickers);\n return res;\n }\n });\n\n return res;\n }\n\n private cleanEmoji(emoji: string) {\n return emoji.replace(/\\ufe0f/g, '').replace(/🏻|🏼|🏽|🏾|🏿/g, '');\n }\n\n public getAnimatedEmojiSticker(emoji: string, isAnimation?: boolean) {\n const stickerSet = this.storage.getFromCache(isAnimation ? EMOJI_ANIMATIONS_SET_LOCAL_ID : EMOJI_SET_LOCAL_ID);\n if(!stickerSet || !stickerSet.documents) return undefined;\n\n if(isAnimation) {\n if(['🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎'].includes(emoji)) {\n emoji = '❤️';\n }\n }\n\n emoji = this.cleanEmoji(emoji);\n const pack = stickerSet.packs.find(p => p.emoticon === emoji);\n return pack ? appDocsManager.getDoc(pack.documents[0]) : undefined;\n }\n\n public getAnimatedEmojiSoundDocument(emoji: string) {\n return this.sounds[this.cleanEmoji(emoji)];\n }\n\n public preloadAnimatedEmojiSticker(emoji: string, width?: number, height?: number) {\n const preloadEmojiPromise = this.getAnimatedEmojiStickerSet().then(() => {\n const doc = this.getAnimatedEmojiSticker(emoji);\n if(doc) {\n return appDocsManager.downloadDoc(doc)\n .then(async(blob) => {\n const mediaSize = mediaSizes.active.emojiSticker;\n const toneIndex = getEmojiToneIndex(emoji);\n const animation = await lottieLoader.loadAnimationWorker({\n container: undefined,\n animationData: blob,\n width: width ?? mediaSize.width,\n height: height ?? mediaSize.height,\n name: 'doc' + doc.id,\n autoplay: false,\n loop: false,\n toneIndex\n }, 'none');\n\n animation.addEventListener('firstFrame', () => {\n appDocsManager.saveLottiePreview(doc, animation.canvas, toneIndex);\n animation.remove();\n }, {once: true});\n });\n }\n });\n \n return Promise.all([\n preloadEmojiPromise,\n this.preloadAnimatedEmojiStickerAnimation(emoji)\n ]);\n }\n\n public preloadAnimatedEmojiStickerAnimation(emoji: string) {\n return this.getAnimatedEmojiStickerSet().then(() => {\n const doc = this.getAnimatedEmojiSticker(emoji, true);\n if(doc) {\n const soundDoc = this.getAnimatedEmojiSoundDocument(emoji);\n return Promise.all([\n appDocsManager.downloadDoc(doc),\n soundDoc ? appDocsManager.downloadDoc(soundDoc) : undefined\n ]);\n }\n });\n }\n \n public saveStickerSet(res: Omit<MessagesStickerSet.messagesStickerSet, '_'>, id: DocId) {\n //console.log('stickers save set', res);w\n\n const newSet: MessagesStickerSet = {\n _: 'messages.stickerSet',\n set: res.set,\n packs: res.packs,\n documents: res.documents as Document[]\n };\n \n let stickerSet = this.storage.getFromCache(id);\n if(stickerSet) {\n Object.assign(stickerSet, newSet);\n } else {\n stickerSet = this.storage.setToCache(id, newSet);\n }\n\n this.saveStickers(res.documents);\n \n //console.log('stickers wrote', this.stickerSets);\n const needSave = stickerSet.set.installed_date || LOCAL_IDS_SET.has(id as any);\n stickerSet.refreshTime = Date.now();\n this.storage.set({[id]: stickerSet}, !needSave);\n }\n\n public getStickerSetThumbDownloadOptions(stickerSet: StickerSet.stickerSet) {\n const thumb = stickerSet.thumbs.find(thumb => thumb._ === 'photoSize') as PhotoSize.photoSize;\n const dcId = stickerSet.thumb_dc_id;\n\n const isAnimated = stickerSet.pFlags?.animated;\n\n const input: InputFileLocation.inputStickerSetThumb = {\n _: 'inputStickerSetThumb',\n stickerset: this.getStickerSetInput(stickerSet),\n thumb_version: stickerSet.thumb_version\n };\n\n return {dcId, location: input, size: thumb.size, mimeType: isAnimated ? 'application/x-tgsticker' : 'image/webp'};\n }\n\n /* public getStickerSetThumbURL(stickerSet: MTStickerSet) {\n const thumb = stickerSet.thumb;\n const dcId = stickerSet.thumb_dc_id;\n\n const isAnimated = stickerSet.pFlags?.animated;\n\n const input: inputStickerSetThumb = {\n _: 'inputStickerSetThumb',\n stickerset: this.getStickerSetInput(stickerSet),\n volume_id: thumb.location.volume_id,\n local_id: thumb.location.local_id\n };\n\n const url = getFileURL('document', this.getStickerSetThumbDownloadOptions(stickerSet));\n return url;\n\n //return promise;\n } */\n\n public getStickerSetInput(set: MyStickerSetInput): InputStickerSet {\n if(set.id === EMOJI_SET_LOCAL_ID) {\n return {\n _: 'inputStickerSetAnimatedEmoji'\n };\n } else if(set.id === EMOJI_ANIMATIONS_SET_LOCAL_ID) {\n return {\n _: 'inputStickerSetAnimatedEmojiAnimations'\n };\n } else if(!set.access_hash) {\n return {\n _: 'inputStickerSetShortName',\n short_name: '' + set.id\n };\n } else {\n return {\n _: 'inputStickerSetID',\n id: set.id,\n access_hash: set.access_hash\n };\n }\n }\n\n public async getFeaturedStickers() {\n const res = await apiManager.invokeApiHashable({\n method: 'messages.getFeaturedStickers',\n processResult: (res) => {\n assumeType<MessagesFeaturedStickers.messagesFeaturedStickers>(res);\n\n forEachReverse(res.sets, (covered, idx, arr) => {\n if(covered.set.pFlags.videos && !IS_WEBM_SUPPORTED) {\n arr.splice(idx, 1);\n }\n });\n\n res.sets.forEach(covered => {\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\n });\n\n return res;\n }\n });\n\n return res.sets;\n }\n\n public async toggleStickerSet(set: StickerSet.stickerSet) {\n if(set.installed_date) {\n const res = await apiManager.invokeApi('messages.uninstallStickerSet', {\n stickerset: this.getStickerSetInput(set)\n });\n\n if(res) {\n delete set.installed_date;\n rootScope.dispatchEvent('stickers_deleted', set);\n this.storage.delete(set.id, true);\n return true;\n }\n } else {\n const res = await apiManager.invokeApi('messages.installStickerSet', {\n stickerset: this.getStickerSetInput(set),\n archived: false\n });\n\n if(res) {\n set.installed_date = Date.now() / 1000 | 0;\n rootScope.dispatchEvent('stickers_installed', set);\n return true;\n }\n }\n\n return false;\n }\n\n public async searchStickerSets(query: string, excludeFeatured = true) {\n const flags = excludeFeatured ? 1 : 0;\n const res = await apiManager.invokeApiHashable({\n method: 'messages.searchStickerSets', \n params: {\n flags,\n exclude_featured: excludeFeatured || undefined,\n q: query\n },\n processResult: (res) => {\n assumeType<MessagesFoundStickerSets.messagesFoundStickerSets>(res);\n\n forEachReverse(res.sets, (covered, idx, arr) => {\n if(covered.set.pFlags.videos && !IS_WEBM_SUPPORTED) {\n arr.splice(idx, 1);\n }\n });\n\n res.sets.forEach(covered => {\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\n });\n\n return res;\n }\n });\n\n const foundSaved: StickerSetCovered[] = [];\n const cache = this.storage.getCache();\n for(let id in cache) {\n const {set} = cache[id];\n\n if(set.title.toLowerCase().includes(query.toLowerCase()) && !res.sets.find(c => c.set.id === set.id)) {\n foundSaved.push({_: 'stickerSetCovered', set, cover: null});\n }\n }\n\n return res.sets.concat(foundSaved);\n }\n\n public getAllStickers() {\n return apiManager.invokeApiHashable({\n method: 'messages.getAllStickers', \n processResult: (allStickers) => {\n assumeType<MessagesAllStickers.messagesAllStickers>(allStickers);\n\n forEachReverse(allStickers.sets, (stickerSet, idx, arr) => {\n if(stickerSet.pFlags.videos && !IS_WEBM_SUPPORTED) {\n arr.splice(idx, 1);\n }\n });\n\n return allStickers;\n }\n });\n }\n\n public preloadStickerSets() {\n return this.getAllStickers().then(allStickers => {\n return Promise.all((allStickers as MessagesAllStickers.messagesAllStickers).sets.map(set => this.getStickerSet(set, {useCache: true})));\n });\n }\n\n // TODO: detect \"🤷\" by \"🤷‍♂️\"\n public getStickersByEmoticon(emoticon: string, includeOurStickers = true) {\n emoticon = RichTextProcessor.fixEmoji(emoticon);\n if(this.getStickersByEmoticonsPromises[emoticon]) return this.getStickersByEmoticonsPromises[emoticon];\n\n return this.getStickersByEmoticonsPromises[emoticon] = Promise.all([\n apiManager.invokeApiHashable({\n method: 'messages.getStickers', \n params: {\n emoticon\n },\n processResult: (stickers) => stickers\n }),\n includeOurStickers ? this.preloadStickerSets() : [],\n includeOurStickers ? this.getRecentStickers() : undefined\n ]).then(([messagesStickers, installedSets, recentStickers]) => {\n const foundStickers = (messagesStickers as MessagesStickers.messagesStickers).stickers.map(sticker => appDocsManager.saveDoc(sticker));\n const cachedStickersAnimated: Document.document[] = [], cachedStickersStatic: Document.document[] = [];\n\n //console.log('getStickersByEmoticon', messagesStickers, installedSets, recentStickers);\n\n const iteratePacks = (packs: StickerPack.stickerPack[]) => {\n for(const pack of packs) {\n const packEmoticon = RichTextProcessor.fixEmoji(pack.emoticon);\n if(packEmoticon.includes(emoticon)) {\n for(const docId of pack.documents) {\n const doc = appDocsManager.getDoc(docId);\n (doc.animated ? cachedStickersAnimated : cachedStickersStatic).push(doc);\n }\n }\n }\n };\n\n if(recentStickers) {\n iteratePacks(recentStickers.packs);\n const stickers = recentStickers.stickers;\n [cachedStickersAnimated, cachedStickersStatic].forEach(s => {\n s.sort((a, b) => stickers.indexOf(a) - stickers.indexOf(b));\n });\n }\n\n for(const set of installedSets) {\n iteratePacks(set.packs);\n }\n\n /* const entities = RichTextProcessor.parseEntities(emoticon);\n if(entities.length === 1) {\n [cachedStickersAnimated, cachedStickersStatic].forEach(s => {\n forEachReverse(s, (doc, idx) => {\n const docEmoticon = RichTextProcessor.fixEmoji(doc.stickerEmojiRaw);\n if(docEmoticon !== emoticon) {\n s.splice(idx, 1);\n }\n });\n });\n } */\n\n const stickers = [...new Set(cachedStickersAnimated.concat(cachedStickersStatic, foundStickers))]/* .filter(doc => !doc.animated) */;\n\n forEachReverse(stickers, (sticker, idx, arr) => {\n if(sticker.sticker === 3 && !IS_WEBM_SUPPORTED) {\n arr.splice(idx, 1);\n }\n });\n\n return stickers;\n });\n }\n\n public pushRecentSticker(doc: MyDocument) {\n const docEmoticon = RichTextProcessor.fixEmoji(doc.stickerEmojiRaw);\n for(const emoticon in this.getStickersByEmoticonsPromises) {\n const promise = this.getStickersByEmoticonsPromises[emoticon];\n promise.then(stickers => {\n const _doc = findAndSplice(stickers, _doc => _doc.id === doc.id);\n if(_doc) {\n stickers.unshift(_doc);\n } else if(emoticon.includes(docEmoticon)) {\n stickers.unshift(doc);\n }\n });\n }\n }\n}\n\nconst appStickersManager = new AppStickersManager();\nMOUNT_CLASS_TO.appStickersManager = appStickersManager;\nexport default appStickersManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport { FileURLType, getFileNameByLocation, getFileURL } from '../../helpers/fileName';\nimport { Document, InputFileLocation, InputMedia, PhotoSize } from '../../layer';\nimport referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';\nimport opusDecodeController from '../opusDecodeController';\nimport { RichTextProcessor } from '../richtextprocessor';\nimport appDownloadManager, { DownloadBlob } from './appDownloadManager';\nimport appPhotosManager from './appPhotosManager';\nimport blur from '../../helpers/blur';\nimport apiManager from '../mtproto/mtprotoworker';\nimport { MOUNT_CLASS_TO } from '../../config/debug';\nimport { getFullDate } from '../../helpers/date';\nimport rootScope from '../rootScope';\nimport IS_WEBP_SUPPORTED from '../../environment/webpSupport';\nimport IS_WEBM_SUPPORTED from '../../environment/webmSupport';\nimport defineNotNumerableProperties from '../../helpers/object/defineNotNumerableProperties';\nimport isObject from '../../helpers/object/isObject';\nimport safeReplaceArrayInObject from '../../helpers/object/safeReplaceArrayInObject';\n\nexport type MyDocument = Document.document;\n\n// TODO: если залить картинку файлом, а потом перезайти в диалог - превьюшка заново скачается\n\nconst EXTENSION_MIME_TYPE_MAP = {\n mov: 'video/quicktime',\n gif: 'image/gif',\n pdf: 'application/pdf',\n};\n\nexport class AppDocsManager {\n private docs: {[docId: DocId]: MyDocument} = {};\n private savingLottiePreview: {[docId: DocId]: true} = {};\n public downloading: Map<DocId, DownloadBlob> = new Map();\n\n constructor() {\n apiManager.onServiceWorkerFail = this.onServiceWorkerFail;\n }\n\n public onServiceWorkerFail = () => {\n for(const id in this.docs) {\n const doc = this.docs[id];\n\n if(doc.supportsStreaming) {\n delete doc.supportsStreaming;\n const cacheContext = appDownloadManager.getCacheContext(doc);\n delete cacheContext.url;\n }\n }\n };\n\n public saveDoc(doc: Document, context?: ReferenceContext): MyDocument {\n if(doc._ === 'documentEmpty') {\n return undefined;\n }\n\n const oldDoc = this.docs[doc.id];\n\n if(doc.file_reference) { // * because we can have a new object w/o the file_reference while sending\n safeReplaceArrayInObject('file_reference', oldDoc, doc);\n referenceDatabase.saveContext(doc.file_reference, context);\n }\n \n //console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);\n // if(oldDoc) {\n // //if(doc._ !== 'documentEmpty' && doc._ === d._) {\n // if(doc.thumbs) {\n // if(!oldDoc.thumbs) oldDoc.thumbs = doc.thumbs;\n // /* else if(apiDoc.thumbs[0].bytes && !d.thumbs[0].bytes) {\n // d.thumbs.unshift(apiDoc.thumbs[0]);\n // } else if(d.thumbs[0].url) { // fix for converted thumb in safari\n // apiDoc.thumbs[0] = d.thumbs[0];\n // } */\n // }\n\n // //}\n\n // return oldDoc;\n\n // //return Object.assign(d, apiDoc, context);\n // //return context ? Object.assign(d, context) : d;\n // }\n\n if(!oldDoc) {\n this.docs[doc.id] = doc;\n }\n\n // * exclude from state\n // defineNotNumerableProperties(doc, [/* 'thumbs', */'type', 'h', 'w', 'file_name', \n // 'file', 'duration', 'downloaded', 'url', 'audioTitle', \n // 'audioPerformer', 'sticker', 'stickerEmoji', 'stickerEmojiRaw', \n // 'stickerSetInput', 'stickerThumbConverted', 'animated', 'supportsStreaming']);\n\n for(let i = 0, length = doc.attributes.length; i < length; ++i) {\n const attribute = doc.attributes[i];\n switch(attribute._) {\n case 'documentAttributeFilename':\n doc.file_name = RichTextProcessor.wrapPlainText(attribute.file_name);\n doc.fileName = RichTextProcessor.wrapEmojiText(attribute.file_name);\n break;\n\n case 'documentAttributeAudio':\n doc.duration = attribute.duration;\n doc.audioTitle = RichTextProcessor.wrapEmojiText(attribute.title);\n doc.audioPerformer = RichTextProcessor.wrapEmojiText(attribute.performer);\n doc.type = attribute.pFlags.voice && doc.mime_type === 'audio/ogg' ? 'voice' : 'audio';\n /* if(apiDoc.type === 'audio') {\n apiDoc.supportsStreaming = true;\n } */\n break;\n\n case 'documentAttributeVideo':\n doc.duration = attribute.duration;\n doc.w = attribute.w;\n doc.h = attribute.h;\n //apiDoc.supportsStreaming = attribute.pFlags?.supports_streaming/* && apiDoc.size > 524288 */;\n if(/* apiDoc.thumbs && */attribute.pFlags.round_message) {\n doc.type = 'round';\n } else /* if(apiDoc.thumbs) */ {\n doc.type = 'video';\n }\n break;\n\n case 'documentAttributeSticker':\n if(attribute.alt !== undefined) {\n doc.stickerEmojiRaw = attribute.alt;\n doc.stickerEmoji = RichTextProcessor.wrapRichText(doc.stickerEmojiRaw, {noLinks: true, noLinebreaks: true});\n }\n\n if(attribute.stickerset) {\n if(attribute.stickerset._ === 'inputStickerSetEmpty') {\n delete attribute.stickerset;\n } else if(attribute.stickerset._ === 'inputStickerSetID') {\n doc.stickerSetInput = attribute.stickerset;\n }\n }\n\n // * there can be no thumbs, then it is a document\n if(/* apiDoc.thumbs && */doc.mime_type === 'image/webp' && (doc.thumbs || IS_WEBP_SUPPORTED)) {\n doc.type = 'sticker';\n doc.sticker = 1;\n } else if(doc.mime_type === 'video/webm') {\n if(!IS_WEBM_SUPPORTED) {\n return;\n }\n\n doc.type = 'sticker';\n doc.sticker = 3;\n doc.animated = true;\n }\n break;\n\n case 'documentAttributeImageSize':\n doc.type = 'photo';\n doc.w = attribute.w;\n doc.h = attribute.h;\n break;\n\n case 'documentAttributeAnimated':\n if((doc.mime_type === 'image/gif' || doc.mime_type === 'video/mp4')/* && apiDoc.thumbs */) {\n doc.type = 'gif';\n }\n\n doc.animated = true;\n break;\n }\n }\n \n if(!doc.mime_type) {\n const ext = (doc.file_name || '').split('.').pop();\n // @ts-ignore\n const mappedMimeType = ext && EXTENSION_MIME_TYPE_MAP[ext.toLowerCase()];\n if(mappedMimeType) {\n doc.mime_type = mappedMimeType;\n } else {\n switch(doc.type) {\n case 'gif':\n case 'video':\n case 'round':\n doc.mime_type = 'video/mp4';\n break;\n case 'sticker':\n doc.mime_type = 'image/webp';\n break;\n case 'audio':\n doc.mime_type = 'audio/mpeg';\n break;\n case 'voice':\n doc.mime_type = 'audio/ogg';\n break;\n default:\n doc.mime_type = 'application/octet-stream';\n break;\n }\n }\n } else if(doc.mime_type === EXTENSION_MIME_TYPE_MAP.pdf) {\n doc.type = 'pdf';\n } else if(doc.mime_type === EXTENSION_MIME_TYPE_MAP.gif) {\n doc.type = 'gif';\n }\n\n if(doc.type === 'voice' || doc.type === 'round') {\n // browser will identify extension\n doc.file_name = doc.fileName = doc.type + '_' + getFullDate(new Date(doc.date * 1000), {monthAsNumber: true, leadingZero: true}).replace(/[:\\.]/g, '-').replace(', ', '_');\n }\n\n if(apiManager.isServiceWorkerOnline()) {\n if((doc.type === 'gif' && doc.size > 8e6) || doc.type === 'audio' || doc.type === 'video'/* || doc.mime_type.indexOf('video/') === 0 */) {\n doc.supportsStreaming = true;\n \n const cacheContext = appDownloadManager.getCacheContext(doc);\n if(!cacheContext.url) {\n cacheContext.url = this.getFileURL(doc);\n }\n }\n }\n\n // for testing purposes\n // doc.supportsStreaming = false;\n // doc.url = ''; // * this will break upload urls\n \n if(!doc.file_name) {\n doc.file_name = doc.fileName = '';\n }\n\n if(doc.mime_type === 'application/x-tgsticker' && doc.file_name === 'AnimatedSticker.tgs') {\n doc.type = 'sticker';\n doc.animated = true;\n doc.sticker = 2;\n }\n\n /* if(!doc.url) {\n doc.url = this.getFileURL(doc);\n } */\n\n if(oldDoc) {\n return Object.assign(oldDoc, doc);\n }\n\n return doc;\n }\n \n public getDoc(docId: DocId | MyDocument): MyDocument {\n return isObject<MyDocument>(docId) ? docId : this.docs[docId];\n }\n\n public getMediaInput(doc: MyDocument): InputMedia.inputMediaDocument {\n return {\n _: 'inputMediaDocument',\n id: {\n _: 'inputDocument',\n id: doc.id,\n access_hash: doc.access_hash,\n file_reference: doc.file_reference\n },\n ttl_seconds: 0\n };\n }\n\n public getInput(doc: MyDocument, thumbSize?: string): InputFileLocation.inputDocumentFileLocation {\n return {\n _: 'inputDocumentFileLocation',\n id: doc.id,\n access_hash: doc.access_hash,\n file_reference: doc.file_reference,\n thumb_size: thumbSize\n };\n }\n\n public getFileDownloadOptions(doc: MyDocument, thumb?: PhotoSize.photoSize, queueId?: number, onlyCache?: boolean) {\n const inputFileLocation = this.getInput(doc, thumb?.type);\n\n let mimeType: string;\n if(thumb) {\n mimeType = doc.sticker ? 'image/webp' : 'image/jpeg'/* doc.mime_type */;\n } else {\n mimeType = doc.mime_type || 'application/octet-stream';\n }\n\n return {\n dcId: doc.dc_id, \n location: inputFileLocation, \n size: thumb ? thumb.size : doc.size, \n mimeType,\n fileName: doc.file_name,\n queueId,\n onlyCache\n };\n }\n\n public getFileURL(doc: MyDocument, download = false, thumb?: PhotoSize.photoSize) {\n let type: FileURLType;\n if(download) {\n type = 'download';\n } else if(thumb) {\n type = 'thumb';\n } else if(doc.supportsStreaming) {\n type = 'stream';\n } else {\n type = 'document';\n }\n\n return getFileURL(type, this.getFileDownloadOptions(doc, thumb));\n }\n\n public getThumbURL(doc: MyDocument, thumb: PhotoSize.photoSize | PhotoSize.photoCachedSize | PhotoSize.photoStrippedSize) {\n let promise: Promise<any> = Promise.resolve();\n\n const cacheContext = appDownloadManager.getCacheContext(doc, thumb.type);\n if(!cacheContext.url) {\n if('bytes' in thumb) {\n promise = blur(appPhotosManager.getPreviewURLFromBytes(thumb.bytes, !!doc.sticker)).then(url => {\n cacheContext.url = url;\n }) as any;\n } else {\n //return this.getFileURL(doc, false, thumb);\n promise = appPhotosManager.preloadPhoto(doc, thumb) as any;\n }\n }\n\n return {thumb, cacheContext, promise};\n }\n\n public getThumb(doc: MyDocument, tryNotToUseBytes = true) {\n const thumb = appPhotosManager.choosePhotoSize(doc, 0, 0, !tryNotToUseBytes);\n if(thumb._ === 'photoSizeEmpty') return null;\n return this.getThumbURL(doc, thumb as any);\n }\n\n public getInputFileName(doc: MyDocument, thumbSize?: string) {\n return getFileNameByLocation(this.getInput(doc, thumbSize), {fileName: doc.file_name});\n }\n\n public downloadDoc(doc: MyDocument, queueId?: number, onlyCache?: boolean): DownloadBlob {\n const fileName = this.getInputFileName(doc);\n\n let download: DownloadBlob = appDownloadManager.getDownload(fileName);\n if(download) {\n return download;\n }\n\n const downloadOptions = this.getFileDownloadOptions(doc, undefined, queueId, onlyCache);\n download = appDownloadManager.download(downloadOptions);\n this.downloading.set(doc.id, download);\n rootScope.dispatchEvent('download_start', doc.id);\n\n const cacheContext = appDownloadManager.getCacheContext(doc);\n const originalPromise = download;\n originalPromise.then((blob) => {\n cacheContext.url = URL.createObjectURL(blob);\n cacheContext.downloaded = blob.size;\n }, () => {}).finally(() => {\n this.downloading.delete(doc.id);\n });\n \n if(doc.type === 'voice' && !opusDecodeController.isPlaySupported()) {\n download = originalPromise.then(async(blob) => {\n const reader = new FileReader();\n \n await new Promise<void>((resolve, reject) => {\n reader.onloadend = (e) => {\n const uint8 = new Uint8Array(e.target.result as ArrayBuffer);\n //console.log('sending uint8 to decoder:', uint8);\n opusDecodeController.decode(uint8).then(result => {\n cacheContext.url = result.url;\n resolve();\n }, (err) => {\n delete cacheContext.downloaded;\n reject(err);\n });\n };\n \n reader.readAsArrayBuffer(blob);\n });\n \n return blob;\n });\n }\n\n download.then(() => {\n rootScope.dispatchEvent('document_downloaded', doc);\n });\n\n return download;\n }\n\n public isSavingLottiePreview(doc: MyDocument, toneIndex: number) {\n const key = doc.id + '-' + toneIndex;\n return !!this.savingLottiePreview[key];\n }\n\n public saveLottiePreview(doc: MyDocument, canvas: HTMLCanvasElement, toneIndex: number) {\n const key = doc.id + '-' + toneIndex;\n if(this.savingLottiePreview[key]/* || true */) return;\n\n if(!doc.stickerCachedThumbs) {\n defineNotNumerableProperties(doc, ['stickerCachedThumbs']);\n doc.stickerCachedThumbs = {};\n }\n\n const thumb = doc.stickerCachedThumbs[toneIndex];\n if(thumb && thumb.w >= canvas.width && thumb.h >= canvas.height) {\n return;\n }\n\n /* if(doc.thumbs.find(t => t._ === 'photoStrippedSize') \n || (doc.stickerCachedThumb || (doc.stickerSavedThumbWidth >= canvas.width && doc.stickerSavedThumbHeight >= canvas.height))) {\n return;\n } */\n\n this.savingLottiePreview[key] = true;\n canvas.toBlob((blob) => {\n //console.log('got lottie preview', doc, blob, URL.createObjectURL(blob));\n\n const thumb = {\n url: URL.createObjectURL(blob),\n w: canvas.width,\n h: canvas.height\n };\n\n doc.stickerCachedThumbs[toneIndex] = thumb;\n\n delete this.savingLottiePreview[key];\n \n /* const reader = new FileReader();\n reader.onloadend = (e) => {\n const uint8 = new Uint8Array(e.target.result as ArrayBuffer);\n const thumb: PhotoSize.photoStrippedSize = {\n _: 'photoStrippedSize',\n bytes: uint8,\n type: 'i'\n };\n\n doc.stickerSavedThumbWidth = canvas.width;\n doc.stickerSavedThumbHeight = canvas.width;\n\n defineNotNumerableProperties(thumb, ['url']);\n thumb.url = URL.createObjectURL(blob);\n doc.thumbs.findAndSplice(t => t._ === thumb._);\n doc.thumbs.unshift(thumb);\n\n if(!webpWorkerController.isWebpSupported()) {\n doc.pFlags.stickerThumbConverted = true;\n }\n\n delete this.savingLottiePreview[doc.id];\n };\n reader.readAsArrayBuffer(blob); */\n });\n }\n\n public saveDocFile(doc: MyDocument, queueId?: number) {\n /* const options = this.getFileDownloadOptions(doc, undefined, queueId);\n return appDownloadManager.downloadToDisc(options, doc.file_name); */\n const promise = this.downloadDoc(doc, queueId);\n promise.then(() => {\n const cacheContext = appDownloadManager.getCacheContext(doc);\n appDownloadManager.createDownloadAnchor(cacheContext.url, doc.file_name);\n });\n return promise;\n }\n}\n\nconst appDocsManager = new AppDocsManager();\nMOUNT_CLASS_TO.appDocsManager = appDocsManager;\nexport default appDocsManager;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport type { ApplyServerTimeOffsetTask } from './timeManager';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\n// import { tsNow } from '../../helpers/date';\r\nimport sessionStorage from '../sessionStorage';\r\nimport apiManager from './mtprotoworker';\r\n\r\nexport class ServerTimeManager {\r\n /* private midnightNoOffset: number;\r\n private midnightOffseted: Date;\r\n\r\n private midnightOffset: number; */\r\n\r\n public serverTimeOffset: number; // in seconds\r\n /* private timeParams: {\r\n midnightOffset: number,\r\n serverTimeOffset: number\r\n }; */\r\n\r\n constructor() {\r\n /* const timestampNow = tsNow(true);\r\n this.midnightNoOffset = timestampNow - (timestampNow % 86400);\r\n this.midnightOffseted = new Date();\r\n this.midnightOffseted.setHours(0, 0, 0, 0);\r\n \r\n this.midnightOffset = this.midnightNoOffset - (Math.floor(+this.midnightOffseted / 1000)); */\r\n\r\n this.serverTimeOffset = 0;\r\n /* this.timeParams = {\r\n midnightOffset: this.midnightOffset,\r\n serverTimeOffset: this.serverTimeOffset\r\n }; */\r\n\r\n sessionStorage.get('server_time_offset').then((to) => {\r\n if(to) {\r\n this.serverTimeOffset = to;\r\n // this.timeParams.serverTimeOffset = to;\r\n }\r\n });\r\n\r\n apiManager.addTaskListener('applyServerTimeOffset', (task: ApplyServerTimeOffsetTask) => {\r\n this.serverTimeOffset = task.payload;\r\n });\r\n }\r\n}\r\n\r\nconst serverTimeManager = new ServerTimeManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.serverTimeManager = serverTimeManager);\r\nexport default serverTimeManager;\r\n","export default function assumeType<T>(x: unknown): asserts x is T {\r\n return; // ¯\\_(ツ)_/¯\r\n}\r\n","// * Jolly Cobra's schedulers\r\n\r\nimport ctx from \"../../environment/ctx\";\r\nimport { AnyFunction, Awaited } from \"../../types\";\r\nimport noop from \"../noop\";\r\n\r\nexport type DebounceReturnType<F extends AnyFunction> = { \r\n (...args: Parameters<F>): Promise<Awaited<ReturnType<F>>>; \r\n clearTimeout(): void; \r\n};\r\n\r\nexport default function debounce<F extends AnyFunction>(\r\n fn: F,\r\n ms: number,\r\n shouldRunFirst = true,\r\n shouldRunLast = true,\r\n): DebounceReturnType<F> {\r\n let waitingTimeout: number;\r\n let waitingPromise: Promise<Awaited<ReturnType<F>>>, resolve: (result: any) => void, reject: () => void;\r\n let hadNewCall = false;\r\n\r\n const invoke = (args: Parameters<F>) => {\r\n const _resolve = resolve, _reject = reject;\r\n try {\r\n const result = fn.apply(null, args);\r\n _resolve(result);\r\n } catch(err) {\r\n console.error('debounce error', err);\r\n // @ts-ignore\r\n _reject(err);\r\n }\r\n };\r\n\r\n const debounce = (...args: Parameters<F>) => {\r\n if(!waitingPromise) waitingPromise = new Promise((_resolve, _reject) => (resolve = _resolve, reject = _reject));\r\n\r\n if(waitingTimeout) {\r\n clearTimeout(waitingTimeout);\r\n hadNewCall = true;\r\n reject();\r\n waitingPromise = new Promise((_resolve, _reject) => (resolve = _resolve, reject = _reject));\r\n } else if(shouldRunFirst) {\r\n invoke(args);\r\n hadNewCall = false;\r\n }\r\n\r\n const _waitingTimeout = ctx.setTimeout(() => {\r\n // will run if should run last or first but with new call\r\n if(shouldRunLast && (!shouldRunFirst || hadNewCall)) {\r\n invoke(args);\r\n }\r\n \r\n // if debounce was called during invoking\r\n if(waitingTimeout === _waitingTimeout) {\r\n waitingTimeout = waitingPromise = resolve = reject = undefined;\r\n hadNewCall = false;\r\n }\r\n }, ms);\r\n\r\n waitingTimeout = _waitingTimeout;\r\n waitingPromise.catch(noop);\r\n return waitingPromise;\r\n };\r\n\r\n debounce.clearTimeout = () => {\r\n if(waitingTimeout) {\r\n ctx.clearTimeout(waitingTimeout);\r\n reject();\r\n waitingTimeout = waitingPromise = resolve = reject = undefined;\r\n hadNewCall = false;\r\n }\r\n };\r\n\r\n return debounce;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\ntype TargetType = HTMLElement;\r\nexport type OnVisibilityChange = (target: TargetType, visible: boolean) => void;\r\n\r\nexport default class VisibilityIntersector {\r\n private observer: IntersectionObserver;\r\n private items: Map<TargetType, boolean> = new Map();\r\n private locked = false;\r\n\r\n constructor(onVisibilityChange: OnVisibilityChange) {\r\n this.observer = new IntersectionObserver((entries) => {\r\n if(this.locked) {\r\n return;\r\n }\r\n\r\n const changed: {target: TargetType, visible: boolean}[] = [];\r\n\r\n entries.forEach(entry => {\r\n const target = entry.target as TargetType;\r\n\r\n if(this.items.get(target) === entry.isIntersecting) {\r\n return;\r\n } else {\r\n this.items.set(target, entry.isIntersecting);\r\n }\r\n\r\n /* if(entry.isIntersecting) {\r\n console.log('ooo', entry);\r\n } */\r\n\r\n /* if(this.locked) {\r\n return;\r\n } */\r\n\r\n changed[entry.isIntersecting ? 'unshift' : 'push']({target, visible: entry.isIntersecting});\r\n\r\n //onVisibilityChange(target, entry.isIntersecting);\r\n });\r\n\r\n changed.forEach(smth => {\r\n onVisibilityChange(smth.target, smth.visible);\r\n });\r\n });\r\n }\r\n\r\n public getVisible() {\r\n const items: TargetType[] = [];\r\n this.items.forEach((value, key) => {\r\n if(value) {\r\n items.push(key);\r\n }\r\n });\r\n\r\n return items;\r\n }\r\n\r\n public clearVisible() {\r\n const visible = this.getVisible();\r\n for(const target of visible) {\r\n this.items.set(target, false);\r\n }\r\n }\r\n\r\n public isVisible(target: TargetType) {\r\n return this.items.get(target);\r\n }\r\n\r\n public disconnect() {\r\n this.observer.disconnect();\r\n this.items.clear();\r\n }\r\n\r\n public refresh() {\r\n this.observer.disconnect();\r\n\r\n //window.requestAnimationFrame(() => {\r\n const targets = [...this.items.keys()];\r\n for(const target of targets) {\r\n //this.items.set(target, false);\r\n this.observer.observe(target);\r\n }\r\n //});\r\n }\r\n\r\n public refreshVisible() {\r\n const visible = this.getVisible();\r\n for(const target of visible) {\r\n this.observer.unobserve(target);\r\n }\r\n\r\n for(const target of visible) {\r\n this.observer.observe(target);\r\n }\r\n }\r\n\r\n public observe(target: TargetType) {\r\n this.items.set(target, false);\r\n this.observer.observe(target);\r\n }\r\n\r\n public unobserve(target: TargetType) {\r\n this.observer.unobserve(target);\r\n this.items.delete(target);\r\n }\r\n\r\n public unlock() {\r\n this.locked = false;\r\n }\r\n\r\n public unlockAndRefresh() {\r\n this.unlock();\r\n this.refresh();\r\n }\r\n\r\n public lock() {\r\n this.locked = true;\r\n }\r\n}\r\n","export default function findAndSpliceAll<T>(array: Array<T>, verify: (value: T, index: number, arr: typeof array) => boolean) {\n const out: typeof array = [];\n let idx = -1;\n while((idx = array.findIndex(verify)) !== -1) {\n out.push(array.splice(idx, 1)[0]);\n }\n\n return out;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { logger, LogTypes } from \"../lib/logger\";\r\nimport VisibilityIntersector, { OnVisibilityChange } from \"./visibilityIntersector\";\r\nimport throttle from \"../helpers/schedulers/throttle\";\r\nimport findAndSpliceAll from \"../helpers/array/findAndSpliceAll\";\r\nimport indexOfAndSplice from \"../helpers/array/indexOfAndSplice\";\r\nimport findAndSplice from \"../helpers/array/findAndSplice\";\r\n\r\ntype LazyLoadElementBase = {\r\n load: () => Promise<any>\r\n};\r\n\r\ntype LazyLoadElement = Omit<LazyLoadElementBase, 'load'> & {\r\n load: (target?: HTMLElement) => Promise<any>,\r\n div: HTMLElement\r\n wasSeen?: boolean,\r\n};\r\n\r\nconst PARALLEL_LIMIT = 8;\r\n\r\nexport class LazyLoadQueueBase {\r\n public queueId = 0;\r\n protected queue: Array<LazyLoadElementBase> = [];\r\n protected inProcess: Set<LazyLoadElementBase> = new Set();\r\n\r\n protected lockPromise: Promise<void> = null;\r\n protected unlockResolve: () => void = null;\r\n\r\n protected log = logger('LL', LogTypes.Error);\r\n protected processQueue: () => void;\r\n\r\n constructor(protected parallelLimit = PARALLEL_LIMIT) {\r\n this.processQueue = throttle(() => this._processQueue(), 20, false);\r\n }\r\n\r\n public clear() {\r\n this.inProcess.clear(); // ацтеки забьются, будет плохо\r\n\r\n this.queue.length = 0;\r\n // unreachable code\r\n /* for(let item of this.inProcess) { \r\n this.lazyLoadMedia.push(item);\r\n } */\r\n }\r\n\r\n public lock() {\r\n if(this.lockPromise) return;\r\n\r\n //const perf = performance.now();\r\n this.lockPromise = new Promise((resolve, reject) => {\r\n this.unlockResolve = resolve;\r\n });\r\n\r\n /* if(DEBUG) {\r\n this.lockPromise.then(() => {\r\n this.log('was locked for:', performance.now() - perf);\r\n });\r\n } */\r\n }\r\n\r\n public unlock() {\r\n if(!this.unlockResolve) return;\r\n\r\n this.unlockResolve();\r\n this.unlockResolve = this.lockPromise = null;\r\n\r\n this.processQueue();\r\n }\r\n\r\n protected async processItem(item: LazyLoadElementBase) {\r\n if(this.lockPromise) {\r\n return;\r\n }\r\n\r\n this.inProcess.add(item);\r\n\r\n /* if(DEBUG) {\r\n this.log('will load media', this.lockPromise, item);\r\n } */\r\n\r\n try {\r\n //await new Promise((resolve) => setTimeout(resolve, 2e3));\r\n //await new Promise((resolve, reject) => window.requestAnimationFrame(() => window.requestAnimationFrame(resolve)));\r\n //await item.load(item.div);\r\n await this.loadItem(item);\r\n } catch(err) {\r\n if(!['NO_ENTRY_FOUND', 'STORAGE_OFFLINE'].includes(err as string)) {\r\n this.log.error('loadMediaQueue error:', err/* , item */);\r\n }\r\n }\r\n\r\n this.inProcess.delete(item);\r\n\r\n /* if(DEBUG) {\r\n this.log('loaded media', item);\r\n } */\r\n\r\n this.processQueue();\r\n }\r\n\r\n protected loadItem(item: LazyLoadElementBase) {\r\n return item.load();\r\n }\r\n\r\n protected getItem() {\r\n return this.queue.shift();\r\n }\r\n\r\n protected addElement(method: 'push' | 'unshift', el: LazyLoadElementBase) {\r\n this.queue[method](el);\r\n this.processQueue();\r\n }\r\n\r\n protected _processQueue(item?: LazyLoadElementBase) {\r\n if(!this.queue.length || this.lockPromise || (this.parallelLimit > 0 && this.inProcess.size >= this.parallelLimit)) return;\r\n\r\n //console.log('_processQueue start');\r\n let added = 0;\r\n do {\r\n if(item) {\r\n indexOfAndSplice(this.queue, item);\r\n } else {\r\n item = this.getItem();\r\n }\r\n \r\n if(item) {\r\n this.processItem(item);\r\n } else {\r\n break;\r\n }\r\n\r\n item = null;\r\n ++added;\r\n } while(this.inProcess.size < this.parallelLimit && this.queue.length);\r\n //console.log('_processQueue end, added', added, this.queue.length);\r\n }\r\n\r\n public push(el: LazyLoadElementBase) {\r\n this.addElement('push', el);\r\n }\r\n\r\n public unshift(el: LazyLoadElementBase) {\r\n this.addElement('unshift', el);\r\n }\r\n}\r\n\r\nexport class LazyLoadQueueIntersector extends LazyLoadQueueBase {\r\n protected queue: Array<LazyLoadElement> = [];\r\n protected inProcess: Set<LazyLoadElement> = new Set();\r\n\r\n public intersector: VisibilityIntersector;\r\n protected intersectorTimeout: number;\r\n\r\n constructor(protected parallelLimit = PARALLEL_LIMIT) {\r\n super(parallelLimit);\r\n }\r\n\r\n public lock() {\r\n super.lock();\r\n this.intersector.lock();\r\n }\r\n\r\n public unlock() {\r\n super.unlock();\r\n this.intersector.unlock();\r\n }\r\n\r\n public unlockAndRefresh() {\r\n super.unlock();\r\n this.intersector.unlockAndRefresh();\r\n }\r\n\r\n public clear() {\r\n super.clear();\r\n this.intersector.disconnect();\r\n }\r\n\r\n public refresh() {\r\n this.intersector.refresh();\r\n }\r\n\r\n protected loadItem(item: LazyLoadElement) {\r\n return item.load(item.div);\r\n }\r\n\r\n protected addElement(method: 'push' | 'unshift', el: LazyLoadElement) {\r\n const item = this.queue.find(i => i.div === el.div && i.load === el.load);\r\n if(item) {\r\n return false;\r\n } else {\r\n for(const item of this.inProcess) {\r\n if(item.div === el.div && item.load === el.load) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n this.queue[method](el);\r\n return true;\r\n }\r\n\r\n protected setProcessQueueTimeout() {\r\n if(!this.intersectorTimeout) {\r\n this.intersectorTimeout = window.setTimeout(() => {\r\n this.intersectorTimeout = 0;\r\n this.processQueue();\r\n }, 0);\r\n }\r\n }\r\n\r\n public push(el: LazyLoadElement) {\r\n super.push(el);\r\n }\r\n\r\n public unshift(el: LazyLoadElement) {\r\n super.unshift(el);\r\n }\r\n\r\n public unobserve(el: HTMLElement) {\r\n findAndSpliceAll(this.queue, (i) => i.div === el);\r\n\r\n this.intersector.unobserve(el);\r\n }\r\n}\r\n\r\nexport default class LazyLoadQueue extends LazyLoadQueueIntersector {\r\n constructor(protected parallelLimit = PARALLEL_LIMIT) {\r\n super(parallelLimit);\r\n\r\n this.intersector = new VisibilityIntersector(this.onVisibilityChange);\r\n }\r\n\r\n private onVisibilityChange = (target: HTMLElement, visible: boolean) => {\r\n if(visible) {\r\n /* if(DEBUG) {\r\n this.log('isIntersecting', target);\r\n } */\r\n\r\n // need for set element first if scrolled\r\n findAndSpliceAll(this.queue, (i) => i.div === target).forEach(item => {\r\n item.wasSeen = true;\r\n this.queue.unshift(item);\r\n //this.processQueue(item);\r\n });\r\n\r\n this.setProcessQueueTimeout();\r\n }\r\n };\r\n\r\n protected getItem() {\r\n return findAndSplice(this.queue, item => item.wasSeen);\r\n }\r\n\r\n public async processItem(item: LazyLoadElement) {\r\n await super.processItem(item);\r\n this.intersector.unobserve(item.div);\r\n }\r\n\r\n protected addElement(method: 'push' | 'unshift', el: LazyLoadElement) {\r\n const inserted = super.addElement(method, el);\r\n\r\n if(!inserted) return false;\r\n\r\n this.intersector.observe(el.div);\r\n /* if(el.wasSeen) {\r\n this.processQueue(el);\r\n } else */if(!el.hasOwnProperty('wasSeen')) {\r\n el.wasSeen = false;\r\n }\r\n \r\n return true;\r\n }\r\n}\r\n\r\nexport class LazyLoadQueueRepeat extends LazyLoadQueueIntersector {\r\n private _queue: Map<HTMLElement, LazyLoadElement> = new Map();\r\n\r\n constructor(protected parallelLimit = PARALLEL_LIMIT, protected onVisibilityChange?: OnVisibilityChange) {\r\n super(parallelLimit);\r\n\r\n this.intersector = new VisibilityIntersector((target, visible) => {\r\n const spliced = findAndSpliceAll(this.queue, (i) => i.div === target);\r\n if(visible) {\r\n const items = spliced.length ? spliced : [this._queue.get(target)];\r\n items.forEach(item => {\r\n this.queue.unshift(item || this._queue.get(target));\r\n });\r\n }\r\n \r\n this.onVisibilityChange && this.onVisibilityChange(target, visible);\r\n this.setProcessQueueTimeout();\r\n });\r\n }\r\n\r\n public clear() {\r\n super.clear();\r\n this._queue.clear();\r\n }\r\n\r\n /* public async processItem(item: LazyLoadElement) {\r\n //await super.processItem(item);\r\n await LazyLoadQueueBase.prototype.processItem.call(this, item);\r\n\r\n if(this.lazyLoadMedia.length) {\r\n this.processQueue();\r\n }\r\n } */\r\n\r\n public observe(el: LazyLoadElement) {\r\n this._queue.set(el.div, el);\r\n this.intersector.observe(el.div);\r\n }\r\n}\r\n\r\nexport class LazyLoadQueueRepeat2 extends LazyLoadQueueIntersector {\r\n constructor(protected parallelLimit = PARALLEL_LIMIT, protected onVisibilityChange?: OnVisibilityChange) {\r\n super(parallelLimit);\r\n\r\n this.intersector = new VisibilityIntersector((target, visible) => {\r\n const spliced = findAndSpliceAll(this.queue, (i) => i.div === target);\r\n if(visible && spliced.length) {\r\n spliced.forEach(item => {\r\n this.queue.unshift(item);\r\n });\r\n }\r\n \r\n this.onVisibilityChange && this.onVisibilityChange(target, visible);\r\n this.setProcessQueueTimeout();\r\n });\r\n }\r\n\r\n public observe(el: HTMLElement) {\r\n this.intersector.observe(el);\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { HelpCountry, HelpCountryCode } from \"../layer\";\nimport I18n from \"../lib/langPack\";\n\nlet sortedCountries: HelpCountry[];\ntype PrefixCountry = {country: HelpCountry, code: HelpCountryCode};\nconst prefixes: Map<string, PrefixCountry> = new Map();\nlet maxPrefixLength = 0;\nconst setPrefix = (country: HelpCountry, code: HelpCountryCode, prefix: string = '') => {\n prefix = code.country_code + prefix;\n /* if(prefixes.has(prefix)) {\n console.error('asdasdasd', prefixes.get(prefix), country, code);\n } */\n maxPrefixLength = Math.max(maxPrefixLength, prefix.length);\n prefixes.set(prefix, {country, code});\n};\n\nexport function formatPhoneNumber(originalStr: string): {\n formatted: string,\n country: HelpCountry,\n code: HelpCountryCode,\n leftPattern: string\n} {\n originalStr = originalStr || '';\n \n if(!prefixes.size) {\n I18n.countriesList.forEach(country => {\n country.country_codes.forEach(code => {\n if(code.prefixes) {\n code.prefixes.forEach(prefix => {\n setPrefix(country, code, prefix);\n });\n } else {\n setPrefix(country, code);\n }\n });\n });\n }\n\n // return {formatted: originalStr, country: undefined as any, leftPattern: ''};\n let str = originalStr.replace(/\\D/g, '');\n let phoneCode = str.slice(0, maxPrefixLength);\n \n ////console.log('str', str, phoneCode);\n // if(!sortedCountries) {\n // sortedCountries = I18n.countriesList.slice().sort((a, b) => b.country_codes[0].country_code.length - a.country_codes[0].country_code.length);\n // }\n \n // let country = sortedCountries.find((c) => {\n // return c.country_codes.find((c) => phoneCode.indexOf(c.replace(/\\D/g, '')) === 0);\n // });\n\n let prefixCountry: PrefixCountry;\n for(let i = phoneCode.length - 1; i >= 0; --i) { // lookup for country by prefix\n prefixCountry = prefixes.get(phoneCode.slice(0, i + 1));\n if(prefixCountry) {\n break;\n }\n }\n\n if(!prefixCountry) {\n return {\n formatted: str, \n country: undefined, \n code: undefined, \n leftPattern: ''\n };\n }\n\n // country = /* PhoneCodesMain[country.phoneCode] || */country;\n const country = prefixCountry.country;\n \n const patterns = prefixCountry.code.patterns || [];\n const searchForPattern = str.slice(prefixCountry.code.country_code.length); // splice country code\n let pattern = '', mostMatchedPatternMatches = 0, mostMatchedPattern = '';\n for(let i = patterns.length - 1; i >= 0; --i) {\n pattern = patterns[i];\n\n const _pattern = pattern.replace(/ /g, '');\n let patternMatches = 0;\n for(let k = 0, length = Math.min(searchForPattern.length, _pattern.length); k < length; ++k) {\n if(searchForPattern[k] === _pattern[k] || _pattern[k] === 'X') {\n ++patternMatches;\n } else {\n patternMatches = 0;\n break;\n }\n }\n\n if(patternMatches > mostMatchedPatternMatches) {\n mostMatchedPatternMatches = patternMatches;\n mostMatchedPattern = pattern;\n }\n }\n\n pattern = mostMatchedPattern || pattern;\n pattern = pattern.replace(/\\d/g, 'X');\n\n pattern = prefixCountry.code.country_code + ' ' + pattern;\n // let pattern = country.pattern || country.phoneCode;\n pattern.split('').forEach((symbol, idx) => {\n if(symbol === ' ' && str[idx] !== ' ' && str.length > idx) {\n str = str.slice(0, idx) + ' ' + str.slice(idx);\n }\n });\n \n /* if(country.pattern) {\n str = str.slice(0, country.pattern.length);\n } */\n\n let leftPattern = pattern && pattern.length > str.length ? pattern.slice(str.length) : '';\n if(leftPattern) {\n /* const length = str.length;\n leftPattern = leftPattern.split('').map((_, idx) => (length + idx).toString().slice(-1)).join(''); */\n leftPattern = leftPattern.replace(/X/g, '');\n // leftPattern = leftPattern.replace(/X/g, '0');\n }\n \n return {formatted: str, country, code: prefixCountry.code, leftPattern};\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function htmlToSpan(html: string) {\r\n const span = document.createElement('span');\r\n span.innerHTML = html;\r\n return span;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport class AppMessagesIdsManager {\r\n private static MESSAGE_ID_INCREMENT = 0x10000;\r\n private static MESSAGE_ID_OFFSET = 0xFFFFFFFF;\r\n\r\n private tempNum = 0;\r\n\r\n public generateMessageId(messageId: number, temp = false) {\r\n const q = AppMessagesIdsManager.MESSAGE_ID_OFFSET;\r\n const num = temp ? ++this.tempNum : 0;\r\n if(messageId >= q) {\r\n if(temp) {\r\n return messageId + (num & (AppMessagesIdsManager.MESSAGE_ID_INCREMENT - 1));\r\n }\r\n\r\n return messageId;\r\n }\r\n\r\n return q + (messageId * AppMessagesIdsManager.MESSAGE_ID_INCREMENT + (num & (AppMessagesIdsManager.MESSAGE_ID_INCREMENT - 1)));\r\n }\r\n\r\n /**\r\n * * will ignore outgoing offset\r\n */\r\n public getServerMessageId(messageId: number) {\r\n return this.clearMessageId(messageId, true);\r\n }\r\n\r\n public clearMessageId(messageId: number, toServer?: boolean) {\r\n const q = AppMessagesIdsManager.MESSAGE_ID_OFFSET;\r\n if(messageId < q) { // id 0 -> mid 0xFFFFFFFF, so 0xFFFFFFFF must convert to 0\r\n return messageId;\r\n }\r\n\r\n const l = AppMessagesIdsManager.MESSAGE_ID_INCREMENT - 1;\r\n const used = messageId & l;\r\n if(used !== l) {\r\n messageId -= used + 1;\r\n }\r\n\r\n return toServer ? (messageId - q) / AppMessagesIdsManager.MESSAGE_ID_INCREMENT : messageId;\r\n }\r\n\r\n public incrementMessageId(messageId: number, increment: number) {\r\n return this.generateMessageId(this.getServerMessageId(messageId) + increment);\r\n }\r\n}\r\n\r\nconst appMessagesIdsManager = new AppMessagesIdsManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appMessagesIdsManager = appMessagesIdsManager);\r\nexport default appMessagesIdsManager;\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\n// import { getHeavyAnimationPromise } from \"../../hooks/useHeavyAnimationCheck\";\n\nexport const loadedURLs: {[url: string]: boolean} = {};\nconst set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => {\n if(elem instanceof HTMLImageElement || elem instanceof HTMLVideoElement) elem.src = url;\n else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url);\n else elem.style.backgroundImage = 'url(' + url + ')';\n};\n\n// проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз.\nexport default function renderImageFromUrl(\n elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, \n url: string, \n callback?: (err?: Event) => void, \n useCache = true\n) {\n if(!url) {\n console.error('renderImageFromUrl: no url?', elem, url);\n callback && callback();\n return;\n }\n\n if(((loadedURLs[url]/* && false */) && useCache) || elem instanceof HTMLVideoElement) {\n if(elem) {\n set(elem, url);\n }\n \n callback && callback();\n // callback && getHeavyAnimationPromise().then(() => callback());\n } else {\n const isImage = elem instanceof HTMLImageElement;\n const loader = isImage ? elem as HTMLImageElement : new Image();\n //const loader = new Image();\n loader.src = url;\n //let perf = performance.now();\n loader.addEventListener('load', () => {\n if(!isImage && elem) {\n set(elem, url);\n }\n\n loadedURLs[url] = true;\n //console.log('onload:', url, performance.now() - perf);\n // TODO: переделать прогрузки аватаров до начала анимации, иначе с этим ожиданием они неприятно появляются\n // callback && getHeavyAnimationPromise().then(() => callback());\n callback && callback();\n }, {once: true});\n\n if(callback) {\n loader.addEventListener('error', (err) => {\n console.error('Render image from url failed:', err, url, loader);\n callback();\n });\n }\n }\n}\n\nexport function renderImageFromUrlPromise(elem: Parameters<typeof renderImageFromUrl>[0], url: string, useCache?: boolean) {\n return new Promise<Event>((resolve) => {\n renderImageFromUrl(elem, url, resolve, useCache);\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport class WindowSize {\n public width = 0;\n public height = 0;\n\n constructor() {\n // @ts-ignore\n const w: any = 'visualViewport' in window ? window.visualViewport : window;\n const set = () => {\n this.width = w.width || w.innerWidth;\n this.height = w.height || w.innerHeight;\n };\n w.addEventListener('resize', set);\n set();\n }\n}\n\nconst windowSize = new WindowSize();\nexport default windowSize;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport {Awaited} from '../types';\n\nexport default function callbackifyAll<T extends readonly unknown[] | [], R extends any>(\n values: T, \n callback: (result: { -readonly [P in keyof T]: Awaited<T[P]> }) => R\n): PromiseLike<R> | R {\n if(values.some(value => value instanceof Promise)) {\n return Promise.all(values).then(callback as any);\n } else {\n return callback(values as any);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport findAndSplice from \"../../helpers/array/findAndSplice\";\nimport assumeType from \"../../helpers/assumeType\";\nimport callbackify from \"../../helpers/callbackify\";\nimport callbackifyAll from \"../../helpers/callbackifyAll\";\nimport copy from \"../../helpers/object/copy\";\nimport { AvailableReaction, Message, MessagePeerReaction, MessagesAvailableReactions, Update, Updates } from \"../../layer\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport { ReferenceContext } from \"../mtproto/referenceDatabase\";\nimport rootScope from \"../rootScope\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appDocsManager from \"./appDocsManager\";\nimport appMessagesIdsManager from \"./appMessagesIdsManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appProfileManager from \"./appProfileManager\";\nimport appUsersManager from \"./appUsersManager\";\n\nconst SAVE_DOC_KEYS = [\n 'static_icon' as const,\n 'appear_animation' as const,\n 'select_animation' as const,\n 'activate_animation' as const,\n 'effect_animation' as const,\n 'around_animation' as const,\n 'center_icon' as const\n];\n\nconst REFERENCE_CONTEXT: ReferenceContext = {\n type: 'reactions'\n};\n\nexport class AppReactionsManager {\n private availableReactions: AvailableReaction[];\n private sendReactionPromises: Map<string, Promise<any>>;\n private lastSendingTimes: Map<string, number>;\n\n constructor() {\n rootScope.addEventListener('language_change', () => {\n this.availableReactions = undefined;\n this.getAvailableReactions();\n });\n\n this.sendReactionPromises = new Map();\n this.lastSendingTimes = new Map();\n\n setTimeout(() => {\n Promise.resolve(this.getAvailableReactions()).then(async(availableReactions) => {\n for(const availableReaction of availableReactions) {\n await Promise.all([\n availableReaction.around_animation && appDocsManager.downloadDoc(availableReaction.around_animation),\n availableReaction.static_icon && appDocsManager.downloadDoc(availableReaction.static_icon),\n availableReaction.appear_animation && appDocsManager.downloadDoc(availableReaction.appear_animation),\n availableReaction.center_icon && appDocsManager.downloadDoc(availableReaction.center_icon)\n ]);\n }\n });\n }, 7.5e3);\n }\n\n public getAvailableReactions() {\n if(this.availableReactions) return this.availableReactions;\n return apiManager.invokeApiSingleProcess({\n method: 'messages.getAvailableReactions',\n processResult: (messagesAvailableReactions) => {\n assumeType<MessagesAvailableReactions.messagesAvailableReactions>(messagesAvailableReactions);\n\n const availableReactions = this.availableReactions = messagesAvailableReactions.reactions;\n for(const reaction of availableReactions) {\n for(const key of SAVE_DOC_KEYS) {\n if(!reaction[key]) {\n continue;\n }\n \n reaction[key] = appDocsManager.saveDoc(reaction[key], REFERENCE_CONTEXT);\n }\n }\n\n return availableReactions;\n },\n params: {\n hash: 0\n }\n });\n }\n\n public getActiveAvailableReactions() {\n return callbackify(this.getAvailableReactions(), (availableReactions) => {\n return availableReactions.filter(availableReaction => !availableReaction.pFlags.inactive);\n });\n }\n\n public getAvailableReactionsForPeer(peerId: PeerId) {\n const activeAvailableReactions = this.getActiveAvailableReactions();\n if(peerId.isUser()) {\n return this.unshiftQuickReaction(activeAvailableReactions);\n }\n\n const chatFull = appProfileManager.getChatFull(peerId.toChatId());\n return callbackifyAll([activeAvailableReactions, chatFull, this.getQuickReaction()], ([activeAvailableReactions, chatFull, quickReaction]) => {\n const chatAvailableReactions = chatFull.available_reactions ?? [];\n\n const filteredChatAvailableReactions = chatAvailableReactions.map(reaction => {\n return activeAvailableReactions.find(availableReaction => availableReaction.reaction === reaction);\n }).filter(Boolean);\n\n return this.unshiftQuickReactionInner(filteredChatAvailableReactions, quickReaction);\n });\n }\n\n private unshiftQuickReactionInner(availableReactions: AvailableReaction.availableReaction[], quickReaction: AvailableReaction.availableReaction) {\n const availableReaction = findAndSplice(availableReactions, availableReaction => availableReaction.reaction === quickReaction.reaction);\n if(availableReaction) {\n availableReactions.unshift(availableReaction);\n }\n\n return availableReactions;\n }\n\n private unshiftQuickReaction(\n availableReactions: AvailableReaction.availableReaction[] | PromiseLike<AvailableReaction.availableReaction[]>, \n quickReaction: ReturnType<AppReactionsManager['getQuickReaction']> = this.getQuickReaction()\n ) {\n return callbackifyAll([\n availableReactions,\n quickReaction\n ], ([availableReactions, quickReaction]) => {\n return this.unshiftQuickReactionInner(availableReactions, quickReaction);\n });\n }\n\n public getAvailableReactionsByMessage(message: Message.message) {\n const peerId = (message.fwd_from?.channel_post && appPeersManager.isMegagroup(message.peerId) && message.fwdFromId) || message.peerId;\n return this.getAvailableReactionsForPeer(peerId);\n }\n\n public isReactionActive(reaction: string) {\n if(!this.availableReactions) return false;\n return !!this.availableReactions.find(availableReaction => availableReaction.reaction === reaction);\n }\n\n public getQuickReaction() {\n return callbackifyAll([\n apiManager.getAppConfig(),\n this.getAvailableReactions()\n ], ([appConfig, availableReactions]) => {\n return availableReactions.find(reaction => reaction.reaction === appConfig.reactions_default);\n });\n }\n\n public getReactionCached(reaction: string) {\n return this.availableReactions.find(availableReaction => availableReaction.reaction === reaction);\n }\n\n public getReaction(reaction: string) {\n return callbackify(this.getAvailableReactions(), () => {\n return this.getReactionCached(reaction);\n });\n }\n\n public getMessagesReactions(peerId: PeerId, mids: number[]) {\n return apiManager.invokeApiSingleProcess({\n method: 'messages.getMessagesReactions',\n params: {\n id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid)),\n peer: appPeersManager.getInputPeerById(peerId)\n },\n processResult: (updates) => {\n apiUpdatesManager.processUpdateMessage(updates);\n\n // const update = (updates as Updates.updates).updates.find(update => update._ === 'updateMessageReactions') as Update.updateMessageReactions;\n // return update.reactions;\n }\n });\n }\n\n public getMessageReactionsList(peerId: PeerId, mid: number, limit: number, reaction?: string, offset?: string) {\n return apiManager.invokeApiSingleProcess({\n method: 'messages.getMessageReactionsList',\n params: {\n peer: appPeersManager.getInputPeerById(peerId),\n id: appMessagesIdsManager.getServerMessageId(mid),\n limit,\n reaction,\n offset\n },\n processResult: (messageReactionsList) => {\n appUsersManager.saveApiUsers(messageReactionsList.users);\n return messageReactionsList;\n }\n });\n }\n\n public setDefaultReaction(reaction: string) {\n return apiManager.invokeApi('messages.setDefaultReaction', {reaction}).then(value => {\n if(value) {\n const appConfig = rootScope.appConfig;\n if(appConfig) {\n appConfig.reactions_default = reaction;\n } else { // if no config or loading it - overwrite\n apiManager.getAppConfig(true);\n }\n\n rootScope.dispatchEvent('quick_reaction', reaction);\n }\n\n return value;\n });\n }\n\n public sendReaction(message: Message.message, reaction?: string, onlyLocal?: boolean) {\n const lastSendingTimeKey = message.peerId + '_' + message.mid;\n const lastSendingTime = this.lastSendingTimes.get(lastSendingTimeKey);\n if(lastSendingTime) {\n return;\n } else {\n this.lastSendingTimes.set(lastSendingTimeKey, Date.now());\n setTimeout(() => {\n this.lastSendingTimes.delete(lastSendingTimeKey);\n }, 333);\n }\n\n const {peerId, mid} = message;\n const myPeerId = rootScope.myId;\n\n let reactions = onlyLocal ? message.reactions : copy(message.reactions);\n let chosenReactionIdx = reactions ? reactions.results.findIndex((reactionCount) => reactionCount.pFlags.chosen) : -1;\n let chosenReaction = chosenReactionIdx !== -1 && reactions.results[chosenReactionIdx];\n if(chosenReaction) { // clear current reaction\n --chosenReaction.count;\n delete chosenReaction.pFlags.chosen;\n\n if(reaction === chosenReaction.reaction) {\n reaction = undefined;\n }\n\n if(!chosenReaction.count) {\n reactions.results.splice(chosenReactionIdx, 1);\n }/* else {\n insertInDescendSortedArray(reactions.results, chosenReaction, 'count', chosenReactionIdx);\n } */\n\n if(reactions.recent_reactions) {\n findAndSplice(reactions.recent_reactions, (recentReaction) => appPeersManager.getPeerId(recentReaction.peer_id) === myPeerId);\n }\n\n if(!reactions.results.length) {\n reactions = undefined;\n }\n }\n\n if(reaction) {\n if(!reactions) {\n reactions/* = message.reactions */ = {\n _: 'messageReactions',\n results: [],\n pFlags: {}\n };\n\n if(!appPeersManager.isBroadcast(message.peerId)) {\n reactions.pFlags.can_see_list = true;\n }\n }\n\n let reactionCountIdx = reactions.results.findIndex((reactionCount) => reactionCount.reaction === reaction);\n let reactionCount = reactionCountIdx !== -1 && reactions.results[reactionCountIdx];\n if(!reactionCount) {\n reactionCount = {\n _: 'reactionCount',\n count: 0,\n reaction,\n pFlags: {}\n };\n\n reactionCountIdx = reactions.results.push(reactionCount) - 1;\n }\n\n ++reactionCount.count;\n reactionCount.pFlags.chosen = true;\n\n if(!reactions.recent_reactions && reactions.pFlags.can_see_list) {\n reactions.recent_reactions = [];\n }\n\n if(reactions.recent_reactions) {\n const userReaction: MessagePeerReaction = {\n _: 'messagePeerReaction',\n reaction,\n peer_id: appPeersManager.getOutputPeer(myPeerId)\n };\n\n if(!appPeersManager.isMegagroup(peerId)) {\n reactions.recent_reactions.push(userReaction);\n reactions.recent_reactions = reactions.recent_reactions.slice(-3);\n } else {\n reactions.recent_reactions.unshift(userReaction);\n reactions.recent_reactions = reactions.recent_reactions.slice(0, 3);\n }\n }\n\n // insertInDescendSortedArray(reactions.results, reactionCount, 'count', reactionCountIdx);\n }\n\n const availableReactions = this.availableReactions;\n if(reactions && availableReactions?.length) {\n const indexes: Map<string, number> = new Map();\n availableReactions.forEach((availableReaction, idx) => {\n indexes.set(availableReaction.reaction, idx);\n });\n\n reactions.results.sort((a, b) => {\n return (b.count - a.count) || (indexes.get(a.reaction) - indexes.get(b.reaction));\n });\n }\n\n if(onlyLocal) {\n message.reactions = reactions;\n rootScope.dispatchEvent('messages_reactions', [{message, changedResults: []}]);\n return Promise.resolve();\n }\n\n apiUpdatesManager.processLocalUpdate({\n _: 'updateMessageReactions',\n peer: message.peer_id,\n msg_id: message.id,\n reactions: reactions,\n local: true\n });\n\n const promiseKey = [peerId, mid].join('-');\n const msgId = appMessagesIdsManager.getServerMessageId(mid);\n const promise = apiManager.invokeApi('messages.sendReaction', {\n peer: appPeersManager.getInputPeerById(peerId),\n msg_id: msgId,\n reaction\n }).then((updates) => {\n assumeType<Updates.updates>(updates);\n \n const editMessageUpdateIdx = updates.updates.findIndex(update => update._ === 'updateEditMessage' || update._ === 'updateEditChannelMessage');\n if(editMessageUpdateIdx !== -1) {\n const editMessageUpdate = updates.updates[editMessageUpdateIdx] as Update.updateEditMessage | Update.updateEditChannelMessage;\n updates.updates[editMessageUpdateIdx] = {\n _: 'updateMessageReactions',\n msg_id: msgId,\n peer: appPeersManager.getOutputPeer(peerId),\n reactions: (editMessageUpdate.message as Message.message).reactions,\n pts: editMessageUpdate.pts,\n pts_count: editMessageUpdate.pts_count\n };\n }\n\n apiUpdatesManager.processUpdateMessage(updates);\n }).catch(err => {\n if(err.type === 'REACTION_INVALID' && this.sendReactionPromises.get(promiseKey) === promise) {\n this.sendReaction(message, chosenReaction?.reaction, true);\n }\n }).finally(() => {\n if(this.sendReactionPromises.get(promiseKey) === promise) {\n this.sendReactionPromises.delete(promiseKey);\n }\n });\n \n this.sendReactionPromises.set(promiseKey, promise);\n return promise;\n }\n}\n\nconst appReactionsManager = new AppReactionsManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appReactionsManager = appReactionsManager);\nexport default appReactionsManager;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { fontFamily } from \"../../components/middleEllipsis\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { CancellablePromise, deferredPromise } from \"../../helpers/cancellablePromise\";\r\nimport { tsNow } from \"../../helpers/date\";\r\nimport { IS_MOBILE } from \"../../environment/userAgent\";\r\nimport { InputNotifyPeer, InputPeerNotifySettings, NotifyPeer, PeerNotifySettings, Update } from \"../../layer\";\r\nimport I18n from \"../langPack\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport webPushApiManager, { PushSubscriptionNotify } from \"../mtproto/webPushApiManager\";\r\nimport rootScope from \"../rootScope\";\r\nimport stateStorage from \"../stateStorage\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appRuntimeManager from \"./appRuntimeManager\";\r\nimport appStateManager from \"./appStateManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport IS_VIBRATE_SUPPORTED from \"../../environment/vibrateSupport\";\r\nimport { MUTE_UNTIL } from \"../mtproto/mtproto_config\";\r\nimport throttle from \"../../helpers/schedulers/throttle\";\r\nimport deepEqual from \"../../helpers/object/deepEqual\";\r\nimport convertInputKeyToKey from \"../../helpers/string/convertInputKeyToKey\";\r\n\r\ntype MyNotification = Notification & {\r\n hidden?: boolean,\r\n show?: () => void,\r\n};\r\n\r\nexport type NotifyOptions = Partial<{\r\n tag: string;\r\n image: string;\r\n key: string;\r\n title: string;\r\n message: string;\r\n silent: boolean;\r\n onclick: () => void;\r\n noIncrement: boolean;\r\n}>;\r\n\r\nexport type NotificationSettings = {\r\n nodesktop: boolean,\r\n volume: number,\r\n novibrate: boolean,\r\n nopreview: boolean,\r\n nopush: boolean,\r\n nosound: boolean\r\n};\r\n\r\ntype ImSadAboutIt = Promise<PeerNotifySettings> | PeerNotifySettings;\r\nexport class AppNotificationsManager {\r\n private notificationsUiSupport: boolean;\r\n private notificationsShown: {[key: string]: MyNotification | true} = {};\r\n private notificationIndex = 0;\r\n private notificationsCount = 0;\r\n private soundsPlayed: {[tag: string]: number} = {};\r\n private vibrateSupport = IS_VIBRATE_SUPPORTED;\r\n private nextSoundAt: number;\r\n private prevSoundVolume: number;\r\n private peerSettings = {\r\n notifyPeer: {} as {[peerId: PeerId]: ImSadAboutIt},\r\n notifyUsers: null as ImSadAboutIt,\r\n notifyChats: null as ImSadAboutIt,\r\n notifyBroadcasts: null as ImSadAboutIt\r\n };\r\n //private exceptions: {[peerId: string]: PeerNotifySettings} = {};\r\n private notifyContactsSignUp: Promise<boolean>;\r\n private faviconEl: HTMLLinkElement = document.head.querySelector('link[rel=\"icon\"]');\r\n\r\n private titleBackup = document.title;\r\n private titleChanged = false;\r\n private titleInterval: number;\r\n private prevFavicon: string;\r\n private stopped = false;\r\n\r\n private settings: NotificationSettings = {} as any;\r\n\r\n private registeredDevice: any;\r\n private pushInited = false;\r\n\r\n private topMessagesDeferred: CancellablePromise<void>;\r\n\r\n private notifySoundEl: HTMLElement;\r\n\r\n private getNotifyPeerTypePromise: Promise<any>;\r\n\r\n private checkMuteUntilTimeout: number;\r\n private checkMuteUntilThrottled: () => void;\r\n\r\n constructor() {\r\n // @ts-ignore\r\n navigator.vibrate = navigator.vibrate || navigator.mozVibrate || navigator.webkitVibrate;\r\n\r\n this.notificationsUiSupport = ('Notification' in window) || ('mozNotification' in navigator);\r\n\r\n this.topMessagesDeferred = deferredPromise<void>();\r\n\r\n this.notifySoundEl = document.createElement('div');\r\n this.notifySoundEl.id = 'notify-sound';\r\n document.body.append(this.notifySoundEl);\r\n\r\n this.checkMuteUntilThrottled = throttle(this.checkMuteUntil, 1000, false);\r\n\r\n rootScope.addEventListener('instance_deactivated', () => {\r\n this.stop();\r\n });\r\n\r\n rootScope.addEventListener('instance_activated', () => {\r\n if(this.stopped) {\r\n this.start();\r\n }\r\n });\r\n\r\n rootScope.addEventListener('idle', (newVal) => {\r\n if(this.stopped) {\r\n return;\r\n }\r\n\r\n if(!newVal) {\r\n this.clear();\r\n }\r\n\r\n this.toggleToggler();\r\n });\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateNotifySettings: (update) => {\r\n const peerId = update.peer._ === 'notifyPeer' && appPeersManager.getPeerId(update.peer.peer);\r\n const key = update.peer._ !== 'notifyPeer' ? update.peer._ : undefined;\r\n this.savePeerSettings({\r\n key,\r\n peerId, \r\n settings: update.notify_settings\r\n });\r\n rootScope.dispatchEvent('notify_settings', update);\r\n }\r\n });\r\n\r\n rootScope.addEventListener('push_init', (tokenData) => {\r\n this.pushInited = true;\r\n if(!this.settings.nodesktop && !this.settings.nopush) {\r\n if(tokenData) {\r\n this.registerDevice(tokenData);\r\n } else {\r\n webPushApiManager.subscribe();\r\n }\r\n } else {\r\n this.unregisterDevice(tokenData);\r\n }\r\n });\r\n rootScope.addEventListener('push_subscribe', (tokenData) => {\r\n this.registerDevice(tokenData);\r\n });\r\n rootScope.addEventListener('push_unsubscribe', (tokenData) => {\r\n this.unregisterDevice(tokenData);\r\n });\r\n\r\n rootScope.addEventListener('dialogs_multiupdate', () => {\r\n //unregisterTopMsgs()\r\n this.topMessagesDeferred.resolve();\r\n }, {once: true});\r\n\r\n rootScope.addEventListener('push_notification_click', (notificationData) => {\r\n if(notificationData.action === 'push_settings') {\r\n /* this.topMessagesDeferred.then(() => {\r\n $modal.open({\r\n templateUrl: templateUrl('settings_modal'),\r\n controller: 'SettingsModalController',\r\n windowClass: 'settings_modal_window mobile_modal',\r\n backdrop: 'single'\r\n })\r\n }); */\r\n return;\r\n }\r\n\r\n if(notificationData.action === 'mute1d') {\r\n apiManager.invokeApi('account.updateDeviceLocked', {\r\n period: 86400\r\n }).then(() => {\r\n // var toastData = toaster.pop({\r\n // type: 'info',\r\n // body: _('push_action_mute1d_success'),\r\n // bodyOutputType: 'trustedHtml',\r\n // clickHandler: () => {\r\n // toaster.clear(toastData)\r\n // },\r\n // showCloseButton: false\r\n // })\r\n });\r\n\r\n return;\r\n }\r\n\r\n const peerId = notificationData.custom && notificationData.custom.peerId.toPeerId();\r\n console.log('click', notificationData, peerId);\r\n if(peerId) {\r\n this.topMessagesDeferred.then(() => {\r\n if(notificationData.custom.channel_id &&\r\n !appChatsManager.hasChat(notificationData.custom.channel_id)) {\r\n return;\r\n }\r\n\r\n if(peerId.isUser() && !appUsersManager.hasUser(peerId)) {\r\n return;\r\n }\r\n\r\n rootScope.dispatchEvent('history_focus', {\r\n peerId,\r\n mid: +notificationData.custom.msg_id\r\n });\r\n });\r\n }\r\n });\r\n }\r\n\r\n private toggleToggler(enable = rootScope.idle.isIDLE) {\r\n if(IS_MOBILE) return;\r\n\r\n const resetTitle = () => {\r\n this.titleChanged = false;\r\n document.title = this.titleBackup;\r\n this.setFavicon();\r\n };\r\n\r\n window.clearInterval(this.titleInterval);\r\n this.titleInterval = 0;\r\n\r\n if(!enable) {\r\n resetTitle();\r\n } else {\r\n this.titleInterval = window.setInterval(() => {\r\n const count = this.notificationsCount;\r\n if(!count) {\r\n this.toggleToggler(false);\r\n } else if(this.titleChanged) {\r\n resetTitle();\r\n } else {\r\n this.titleChanged = true;\r\n document.title = I18n.format('Notifications.Count', true, [count]);\r\n //this.setFavicon('assets/img/favicon_unread.ico');\r\n\r\n // fetch('assets/img/favicon.ico')\r\n // .then(res => res.blob())\r\n // .then(blob => {\r\n // const img = document.createElement('img');\r\n // img.src = URL.createObjectURL(blob);\r\n\r\n const canvas = document.createElement('canvas');\r\n canvas.width = 32 * window.devicePixelRatio;\r\n canvas.height = canvas.width;\r\n \r\n const ctx = canvas.getContext('2d');\r\n ctx.beginPath();\r\n ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, 2 * Math.PI, false);\r\n ctx.fillStyle = '#3390ec';\r\n ctx.fill();\r\n\r\n let fontSize = 24;\r\n let str = '' + count;\r\n if(count < 10) {\r\n fontSize = 22;\r\n } else if(count < 100) {\r\n fontSize = 20;\r\n } else {\r\n str = '99+';\r\n fontSize = 16;\r\n }\r\n\r\n fontSize *= window.devicePixelRatio;\r\n \r\n ctx.font = `700 ${fontSize}px ${fontFamily}`;\r\n ctx.textBaseline = 'middle';\r\n ctx.textAlign = 'center';\r\n ctx.fillStyle = 'white';\r\n ctx.fillText(str, canvas.width / 2, canvas.height * .5625);\r\n\r\n /* const ctx = canvas.getContext('2d');\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height); */\r\n \r\n this.setFavicon(canvas.toDataURL());\r\n // });\r\n }\r\n }, 1000);\r\n }\r\n }\r\n\r\n public updateLocalSettings = () => {\r\n Promise.all(['notify_nodesktop', 'notify_volume', 'notify_novibrate', 'notify_nopreview', 'notify_nopush'].map(k => stateStorage.get(k as any)))\r\n .then((updSettings) => {\r\n this.settings.nodesktop = updSettings[0];\r\n this.settings.volume = updSettings[1] === undefined ? 0.5 : updSettings[1];\r\n this.settings.novibrate = updSettings[2];\r\n this.settings.nopreview = updSettings[3];\r\n this.settings.nopush = updSettings[4];\r\n\r\n if(this.pushInited) {\r\n const needPush = !this.settings.nopush && !this.settings.nodesktop && webPushApiManager.isAvailable || false;\r\n const hasPush = this.registeredDevice !== false;\r\n if(needPush !== hasPush) {\r\n if(needPush) {\r\n webPushApiManager.subscribe();\r\n } else {\r\n webPushApiManager.unsubscribe();\r\n }\r\n }\r\n }\r\n\r\n webPushApiManager.setSettings(this.settings);\r\n });\r\n\r\n appStateManager.getState().then(state => {\r\n this.settings.nosound = !state.settings.notifications.sound;\r\n });\r\n }\r\n\r\n public getLocalSettings() {\r\n return this.settings;\r\n }\r\n\r\n public getNotifySettings(peer: InputNotifyPeer): ImSadAboutIt {\r\n let key: any = convertInputKeyToKey(peer._);\r\n let obj: any = this.peerSettings[key as NotifyPeer['_']];\r\n\r\n let peerId: PeerId;\r\n if(peer._ === 'inputNotifyPeer') {\r\n peerId = key = appPeersManager.getPeerId(peer.peer);\r\n obj = obj[key];\r\n }\r\n\r\n if(obj) {\r\n return obj;\r\n }\r\n\r\n return (obj || this.peerSettings)[key] = apiManager.invokeApi('account.getNotifySettings', {peer})\r\n .then(settings => {\r\n this.savePeerSettings({\r\n key,\r\n peerId, \r\n settings\r\n });\r\n \r\n return settings;\r\n });\r\n }\r\n\r\n public getNotifyPeerTypeSettings() {\r\n if(this.getNotifyPeerTypePromise) return this.getNotifyPeerTypePromise;\r\n\r\n const promises = (['inputNotifyBroadcasts', 'inputNotifyUsers', 'inputNotifyChats'] as Exclude<InputNotifyPeer['_'], 'inputNotifyPeer'>[])\r\n .map((inputKey) => {\r\n return this.getNotifySettings({_: inputKey});\r\n });\r\n\r\n return this.getNotifyPeerTypePromise = Promise.all(promises);\r\n }\r\n\r\n public updateNotifySettings(peer: InputNotifyPeer, settings: InputPeerNotifySettings) {\r\n //this.savePeerSettings(peerId, settings);\r\n\r\n /* const inputSettings: InputPeerNotifySettings = copy(settings) as any;\r\n inputSettings._ = 'inputPeerNotifySettings'; */\r\n\r\n return apiManager.invokeApi('account.updateNotifySettings', {\r\n peer,\r\n settings\r\n }).then(value => {\r\n if(value) {\r\n apiUpdatesManager.processLocalUpdate({\r\n _: 'updateNotifySettings', \r\n peer: {\r\n ...peer as any,\r\n _: convertInputKeyToKey(peer._)\r\n }, \r\n notify_settings: { // ! WOW, IT WORKS !\r\n ...settings,\r\n _: 'peerNotifySettings',\r\n }\r\n });\r\n }\r\n });\r\n }\r\n\r\n public getNotifyExceptions() {\r\n apiManager.invokeApi('account.getNotifyExceptions', {compare_sound: true})\r\n .then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public getContactSignUpNotification() {\r\n if(this.notifyContactsSignUp) return this.notifyContactsSignUp;\r\n return this.notifyContactsSignUp = apiManager.invokeApi('account.getContactSignUpNotification');\r\n }\r\n\r\n public setContactSignUpNotification(silent: boolean) {\r\n apiManager.invokeApi('account.setContactSignUpNotification', {silent})\r\n .then(value => {\r\n this.notifyContactsSignUp = Promise.resolve(!silent);\r\n });\r\n }\r\n\r\n private setFavicon(href: string = 'assets/img/favicon.ico') {\r\n if(this.prevFavicon === href) {\r\n return;\r\n }\r\n\r\n const link = this.faviconEl.cloneNode() as HTMLLinkElement;\r\n link.href = href;\r\n this.faviconEl.parentNode.replaceChild(link, this.faviconEl);\r\n this.faviconEl = link;\r\n\r\n this.prevFavicon = href;\r\n }\r\n\r\n private checkMuteUntil = () => {\r\n if(this.checkMuteUntilTimeout !== undefined) {\r\n clearTimeout(this.checkMuteUntilTimeout);\r\n this.checkMuteUntilTimeout = undefined;\r\n }\r\n\r\n const timestamp = tsNow(true);\r\n let closestMuteUntil = MUTE_UNTIL;\r\n for(const peerId in this.peerSettings.notifyPeer) {\r\n const peerNotifySettings = this.peerSettings.notifyPeer[peerId];\r\n if(peerNotifySettings instanceof Promise) {\r\n continue;\r\n }\r\n\r\n const muteUntil = peerNotifySettings.mute_until;\r\n if(!muteUntil) {\r\n continue;\r\n }\r\n\r\n if(muteUntil <= timestamp) {\r\n // ! do not delete it because peer's unique settings will be overwritten in getPeerLocalSettings with type's settings\r\n peerNotifySettings.mute_until = 0;\r\n\r\n rootScope.dispatchEvent('updateNotifySettings', {\r\n _: 'updateNotifySettings',\r\n peer: {\r\n _: 'notifyPeer',\r\n peer: appPeersManager.getOutputPeer(peerId.toPeerId())\r\n },\r\n notify_settings: peerNotifySettings\r\n });\r\n } else if(muteUntil < closestMuteUntil) {\r\n closestMuteUntil = muteUntil;\r\n }\r\n }\r\n\r\n const timeout = Math.min(1800e3, (closestMuteUntil - timestamp) * 1000);\r\n this.checkMuteUntilTimeout = window.setTimeout(this.checkMuteUntil, timeout);\r\n };\r\n\r\n public savePeerSettings({key, peerId, settings}: {\r\n key?: Exclude<NotifyPeer['_'], 'notifyPeer'>,\r\n peerId?: PeerId, \r\n settings: PeerNotifySettings\r\n }) {\r\n let obj: any;\r\n if(peerId) {\r\n key = peerId as any;\r\n obj = this.peerSettings['notifyPeer'];\r\n }\r\n \r\n (obj || this.peerSettings)[key] = settings;\r\n\r\n if(!peerId) {\r\n rootScope.dispatchEvent('notify_peer_type_settings', {key, settings});\r\n appStateManager.getState().then(state => {\r\n const notifySettings = state.notifySettings;\r\n notifySettings[key] = settings;\r\n appStateManager.pushToState('notifySettings', notifySettings);\r\n });\r\n } else {\r\n this.checkMuteUntilThrottled();\r\n }\r\n\r\n //rootScope.broadcast('notify_settings', {peerId: peerId});\r\n }\r\n\r\n public isMuted(peerNotifySettings: PeerNotifySettings) {\r\n return peerNotifySettings._ === 'peerNotifySettings' &&\r\n (peerNotifySettings.silent || (peerNotifySettings.mute_until !== undefined && (peerNotifySettings.mute_until * 1000) > tsNow()));\r\n }\r\n\r\n public getPeerMuted(peerId: PeerId) {\r\n const ret = this.getNotifySettings({_: 'inputNotifyPeer', peer: appPeersManager.getInputPeerById(peerId)});\r\n return (ret instanceof Promise ? ret : Promise.resolve(ret))\r\n .then((peerNotifySettings) => this.isMuted(peerNotifySettings));\r\n }\r\n\r\n public getPeerLocalSettings(peerId: PeerId, respectType = true): PeerNotifySettings {\r\n const n: PeerNotifySettings = {\r\n _: 'peerNotifySettings'\r\n };\r\n\r\n const notifySettings = this.peerSettings['notifyPeer'][peerId];\r\n //if(!notifySettings || (notifySettings instanceof Promise)) return false;\r\n if(notifySettings && !(notifySettings instanceof Promise)) {\r\n Object.assign(n, notifySettings);\r\n }\r\n\r\n if(respectType) {\r\n const inputNotify = appPeersManager.getInputNotifyPeerById(peerId, true);\r\n const key = convertInputKeyToKey(inputNotify._);\r\n const typeNotifySettings = this.peerSettings[key as NotifyPeer['_']];\r\n if(typeNotifySettings && !(typeNotifySettings instanceof Promise)) {\r\n for(let i in typeNotifySettings) {\r\n // @ts-ignore\r\n if(n[i] === undefined) {\r\n // @ts-ignore\r\n n[i] = typeNotifySettings[i];\r\n }\r\n }\r\n }\r\n }\r\n\r\n return n;\r\n }\r\n\r\n public isPeerLocalMuted(peerId: PeerId, respectType = true) {\r\n if(peerId === rootScope.myId) return false;\r\n\r\n const notifySettings = this.getPeerLocalSettings(peerId, respectType);\r\n return this.isMuted(notifySettings);\r\n }\r\n\r\n public start() {\r\n this.updateLocalSettings();\r\n rootScope.addEventListener('settings_updated', this.updateLocalSettings);\r\n webPushApiManager.start();\r\n\r\n if(!this.notificationsUiSupport) {\r\n return false;\r\n }\r\n\r\n if('Notification' in window && Notification.permission !== 'granted' && Notification.permission !== 'denied') {\r\n window.addEventListener('click', this.requestPermission);\r\n }\r\n\r\n try {\r\n if('onbeforeunload' in window) {\r\n window.addEventListener('beforeunload', this.clear);\r\n }\r\n } catch (e) {}\r\n }\r\n\r\n private stop() {\r\n this.clear();\r\n window.clearInterval(this.titleInterval);\r\n this.titleInterval = 0;\r\n this.setFavicon();\r\n this.stopped = true;\r\n }\r\n\r\n private requestPermission = () => {\r\n Notification.requestPermission();\r\n window.removeEventListener('click', this.requestPermission);\r\n };\r\n\r\n public notify(data: NotifyOptions) {\r\n //console.log('notify', data, rootScope.idle.isIDLE, this.notificationsUiSupport, this.stopped);\r\n \r\n if(this.stopped) {\r\n return;\r\n }\r\n\r\n // FFOS Notification blob src bug workaround\r\n /* if(Config.Navigator.ffos && !Config.Navigator.ffos2p) {\r\n data.image = 'https://telegram.org/img/t_logo.png'\r\n }\r\n else if (data.image && !angular.isString(data.image)) {\r\n if (Config.Navigator.ffos2p) {\r\n FileManager.getDataUrl(data.image, 'image/jpeg').then(function (url) {\r\n data.image = url\r\n notify(data)\r\n })\r\n return false\r\n } else {\r\n data.image = FileManager.getUrl(data.image, 'image/jpeg')\r\n }\r\n }\r\n else */ if(!data.image) {\r\n data.image = 'assets/img/logo_filled_rounded.png';\r\n }\r\n // console.log('notify image', data.image)\r\n\r\n if(!data.noIncrement) {\r\n ++this.notificationsCount;\r\n }\r\n\r\n if(!this.titleInterval) {\r\n this.toggleToggler();\r\n }\r\n\r\n const idx = ++this.notificationIndex;\r\n const key = data.key || 'k' + idx;\r\n this.notificationsShown[key] = true;\r\n\r\n const now = tsNow();\r\n if(this.settings.volume > 0 && !this.settings.nosound/* &&\r\n (\r\n !data.tag ||\r\n !this.soundsPlayed[data.tag] ||\r\n now > this.soundsPlayed[data.tag] + 60000\r\n ) */\r\n ) {\r\n this.testSound(this.settings.volume);\r\n this.soundsPlayed[data.tag] = now;\r\n }\r\n\r\n if(!this.notificationsUiSupport ||\r\n 'Notification' in window && Notification.permission !== 'granted') {\r\n return false;\r\n }\r\n\r\n if(this.settings.nodesktop) {\r\n if(this.vibrateSupport && !this.settings.novibrate) {\r\n navigator.vibrate([200, 100, 200]);\r\n return;\r\n }\r\n\r\n return;\r\n }\r\n\r\n let notification: MyNotification;\r\n\r\n if('Notification' in window) {\r\n try {\r\n if(data.tag) {\r\n for(let i in this.notificationsShown) {\r\n const notification = this.notificationsShown[i];\r\n if(typeof(notification) !== 'boolean' && notification.tag === data.tag) {\r\n notification.hidden = true;\r\n }\r\n }\r\n }\r\n\r\n notification = new Notification(data.title, {\r\n icon: data.image || '',\r\n body: data.message || '',\r\n tag: data.tag || '',\r\n silent: data.silent || false\r\n });\r\n\r\n //console.log('notify constructed notification');\r\n } catch(e) {\r\n this.notificationsUiSupport = false;\r\n webPushApiManager.setLocalNotificationsDisabled();\r\n return;\r\n }\r\n } /* else if('mozNotification' in navigator) {\r\n notification = navigator.mozNotification.createNotification(data.title, data.message || '', data.image || '')\r\n } else if(notificationsMsSiteMode) {\r\n window.external.msSiteModeClearIconOverlay()\r\n window.external.msSiteModeSetIconOverlay('img/icons/icon16.png', data.title)\r\n window.external.msSiteModeActivate()\r\n notification = {\r\n index: idx\r\n }\r\n } */ else {\r\n return;\r\n }\r\n\r\n notification.onclick = () => {\r\n notification.close();\r\n appRuntimeManager.focus();\r\n this.clear();\r\n if(data.onclick) {\r\n data.onclick();\r\n }\r\n };\r\n\r\n notification.onclose = () => {\r\n if(!notification.hidden) {\r\n delete this.notificationsShown[key];\r\n this.clear();\r\n }\r\n };\r\n\r\n if(notification.show) {\r\n notification.show();\r\n }\r\n this.notificationsShown[key] = notification;\r\n\r\n if(!IS_MOBILE) {\r\n setTimeout(() => {\r\n this.hide(key);\r\n }, 8000);\r\n }\r\n }\r\n\r\n public testSound(volume: number) {\r\n const now = tsNow();\r\n if(this.nextSoundAt && now < this.nextSoundAt && this.prevSoundVolume === volume) {\r\n return;\r\n }\r\n\r\n this.nextSoundAt = now + 1000;\r\n this.prevSoundVolume = volume;\r\n const filename = 'assets/audio/notification.mp3';\r\n const audio = document.createElement('audio');\r\n audio.autoplay = true;\r\n audio.setAttribute('mozaudiochannel', 'notification');\r\n audio.volume = volume;\r\n audio.innerHTML = `\r\n <source src=\"${filename}\" type=\"audio/mpeg\" />\r\n <embed hidden=\"true\" autostart=\"true\" loop=\"false\" volume=\"${volume * 100}\" src=\"${filename}\" />\r\n `;\r\n this.notifySoundEl.append(audio);\r\n\r\n audio.addEventListener('ended', () => {\r\n audio.remove();\r\n }, {once: true});\r\n }\r\n\r\n public cancel(key: string) {\r\n const notification = this.notificationsShown[key];\r\n if(notification) {\r\n if(this.notificationsCount > 0) {\r\n --this.notificationsCount;\r\n }\r\n\r\n try {\r\n if(typeof(notification) !== 'boolean' && notification.close) {\r\n notification.hidden = true;\r\n notification.close();\r\n }/* else if(notificationsMsSiteMode &&\r\n notification.index === notificationIndex) {\r\n window.external.msSiteModeClearIconOverlay()\r\n } */\r\n } catch(e) {}\r\n\r\n delete this.notificationsShown[key];\r\n }\r\n }\r\n\r\n private hide(key: string) {\r\n const notification = this.notificationsShown[key];\r\n if(notification && typeof(notification) !== 'boolean') {\r\n try {\r\n if(notification.close) {\r\n notification.hidden = true;\r\n notification.close();\r\n }\r\n } catch(e) {}\r\n }\r\n }\r\n\r\n public soundReset(tag: string) {\r\n delete this.soundsPlayed[tag];\r\n }\r\n\r\n public clear() {\r\n /* if(notificationsMsSiteMode) {\r\n window.external.msSiteModeClearIconOverlay()\r\n } else { */\r\n for(const i in this.notificationsShown) {\r\n const notification = this.notificationsShown[i];\r\n try {\r\n if(typeof(notification) !== 'boolean' && notification.close) {\r\n notification.close();\r\n }\r\n } catch(e) {}\r\n }\r\n /* } */\r\n this.notificationsShown = {};\r\n this.notificationsCount = 0;\r\n\r\n webPushApiManager.hidePushNotifications();\r\n }\r\n\r\n private registerDevice(tokenData: PushSubscriptionNotify) {\r\n if(this.registeredDevice && deepEqual(this.registeredDevice, tokenData)) {\r\n return false;\r\n }\r\n\r\n apiManager.invokeApi('account.registerDevice', {\r\n token_type: tokenData.tokenType,\r\n token: tokenData.tokenValue,\r\n other_uids: [],\r\n app_sandbox: false,\r\n secret: new Uint8Array()\r\n }).then(() => {\r\n this.registeredDevice = tokenData;\r\n }, (error) => {\r\n error.handled = true;\r\n });\r\n }\r\n\r\n private unregisterDevice(tokenData: PushSubscriptionNotify) {\r\n if(!this.registeredDevice) {\r\n return false;\r\n }\r\n\r\n apiManager.invokeApi('account.unregisterDevice', {\r\n token_type: tokenData.tokenType,\r\n token: tokenData.tokenValue,\r\n other_uids: []\r\n }).then(() => {\r\n this.registeredDevice = false;\r\n }, (error) => {\r\n error.handled = true;\r\n });\r\n }\r\n\r\n public getVibrateSupport() {\r\n return this.vibrateSupport\r\n }\r\n}\r\n\r\nconst appNotificationsManager = new AppNotificationsManager();\r\nMOUNT_CLASS_TO.appNotificationsManager = appNotificationsManager;\r\nexport default appNotificationsManager;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { makeMediaSize, MediaSize } from \"./mediaSizes\";\r\nimport { pause } from \"./schedulers/pause\";\r\nimport { IS_APPLE_MOBILE } from \"../environment/userAgent\";\r\n\r\nexport function scaleMediaElement(options: {\r\n media: CanvasImageSource, \r\n mediaSize: MediaSize, \r\n boxSize: MediaSize, \r\n quality?: number,\r\n mimeType?: 'image/jpeg' | 'image/png'\r\n}): Promise<{blob: Blob, size: MediaSize}> {\r\n return new Promise((resolve) => {\r\n const canvas = document.createElement('canvas');\r\n const size = options.mediaSize.aspectFitted(options.boxSize);\r\n canvas.width = size.width * window.devicePixelRatio;\r\n canvas.height = size.height * window.devicePixelRatio;\r\n const ctx = canvas.getContext('2d');\r\n ctx.drawImage(options.media, 0, 0, canvas.width, canvas.height);\r\n canvas.toBlob(blob => {\r\n resolve({blob, size});\r\n }, options.mimeType ?? 'image/jpeg', options.quality ?? 1);\r\n });\r\n}\r\n\r\nexport function preloadVideo(url: string): Promise<HTMLVideoElement> {\r\n return new Promise((resolve, reject) => {\r\n const video = document.createElement('video');\r\n video.volume = 0;\r\n video.addEventListener('loadedmetadata', () => resolve(video), {once: true});\r\n video.addEventListener('error', reject, {once: true});\r\n video.src = url;\r\n });\r\n}\r\n\r\nexport function createPosterFromMedia(media: HTMLVideoElement | HTMLImageElement) {\r\n let width: number, height: number;\r\n if(media instanceof HTMLVideoElement) {\r\n width = media.videoWidth;\r\n height = media.videoHeight;\r\n } else {\r\n width = media.naturalWidth;\r\n height = media.naturalHeight;\r\n }\r\n\r\n return scaleMediaElement({\r\n media, \r\n mediaSize: makeMediaSize(width, height), \r\n boxSize: makeMediaSize(320, 240),\r\n quality: .9\r\n });\r\n}\r\n\r\nexport function createPosterFromVideo(video: HTMLVideoElement): ReturnType<typeof scaleMediaElement> {\r\n return new Promise((resolve, reject) => {\r\n video.onseeked = () => {\r\n video.onseeked = () => {\r\n createPosterFromMedia(video).then(resolve);\r\n\r\n video.onseeked = undefined;\r\n };\r\n\r\n video.currentTime = 0;\r\n };\r\n \r\n video.onerror = reject;\r\n video.currentTime = Math.min(video.duration, 1);\r\n });\r\n}\r\n\r\nexport async function createPosterForVideo(url: string) {\r\n const video = await preloadVideo(url);\r\n\r\n return Promise.race([\r\n pause(2000) as Promise<undefined>,\r\n createPosterFromVideo(video),\r\n ]);\r\n}\r\n\r\nexport function onMediaLoad(media: HTMLMediaElement, readyState = media.HAVE_METADATA, useCanplayOnIos?: boolean) {\r\n return new Promise<void>((resolve) => {\r\n if(media.readyState >= readyState) {\r\n resolve();\r\n return;\r\n }\r\n\r\n media.addEventListener(IS_APPLE_MOBILE && !useCanplayOnIos ? 'loadeddata' : 'canplay', () => resolve(), {once: true});\r\n });\r\n}\r\n\r\nexport async function getFilesFromEvent(e: ClipboardEvent | DragEvent, onlyTypes = false): Promise<any[]> {\r\n const files: any[] = [];\r\n\r\n const scanFiles = async(entry: any, item: DataTransferItem) => {\r\n if(entry.isDirectory) {\r\n const directoryReader = entry.createReader();\r\n await new Promise<void>((resolve, reject) => {\r\n directoryReader.readEntries(async(entries: any) => {\r\n for(const entry of entries) {\r\n await scanFiles(entry, item);\r\n }\r\n\r\n resolve();\r\n });\r\n });\r\n } else if(entry) {\r\n if(onlyTypes) {\r\n files.push(entry.type);\r\n } else {\r\n const itemFile = item.getAsFile(); // * Safari can't handle entry.file with pasting\r\n const file = entry instanceof File ? \r\n entry : \r\n (\r\n entry instanceof DataTransferItem ? \r\n entry.getAsFile() : \r\n await new Promise((resolve, reject) => entry.file(resolve, (err: any) => resolve(itemFile)))\r\n );\r\n\r\n /* if(!onlyTypes) {\r\n console.log('getFilesFromEvent: got file', item, file);\r\n } */\r\n\r\n if(!file) return;\r\n files.push(file);\r\n }\r\n }\r\n };\r\n\r\n if(e instanceof DragEvent && e.dataTransfer.files && !e.dataTransfer.items) {\r\n for(let i = 0; i < e.dataTransfer.files.length; i++) {\r\n const file = e.dataTransfer.files[i];\r\n files.push(onlyTypes ? file.type : file);\r\n }\r\n } else {\r\n // @ts-ignore\r\n const items = (e.dataTransfer || e.clipboardData || e.originalEvent.clipboardData).items;\r\n\r\n const promises: Promise<any>[] = [];\r\n for(let i = 0; i < items.length; ++i) {\r\n const item: DataTransferItem = items[i];\r\n if(item.kind === 'file') {\r\n const entry = (onlyTypes ? item : item.webkitGetAsEntry()) || item.getAsFile();\r\n promises.push(scanFiles(entry, item));\r\n }\r\n }\r\n \r\n await Promise.all(promises);\r\n }\r\n\r\n /* if(!onlyTypes) {\r\n console.log('getFilesFromEvent: got files:', e, files);\r\n } */\r\n \r\n return files;\r\n}\r\n\r\nexport function requestFile(accept?: string) {\r\n const input = document.createElement('input');\r\n input.type = 'file';\r\n input.style.display = 'none';\r\n\r\n if(accept) {\r\n input.accept = accept;\r\n }\r\n\r\n document.body.append(input);\r\n\r\n const promise = new Promise<File>((resolve, reject) => {\r\n input.addEventListener('change', (e: any) => {\r\n const file: File = e.target.files[0];\r\n if(!file) {\r\n reject('NO_FILE_SELECTED');\r\n return;\r\n }\r\n \r\n resolve(file);\r\n }, {once: true});\r\n }).finally(() => {\r\n input.remove();\r\n });\r\n\r\n input.click();\r\n\r\n return promise;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n// * will change .cleaned and new instance will be created\r\nexport const getMiddleware = () => {\r\n let cleanupObj = {cleaned: false};\r\n return {\r\n clean: () => {\r\n cleanupObj.cleaned = true;\r\n cleanupObj = {cleaned: false};\r\n },\r\n get: (additionalCallback?: () => boolean) => {\r\n const _cleanupObj = cleanupObj;\r\n return () => {\r\n return !_cleanupObj.cleaned && (!additionalCallback || additionalCallback());\r\n };\r\n }\r\n };\r\n};\r\n","export default function fixBase64String(str: string, toUrl: boolean) {\n if(toUrl) {\n return str.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/\\=+$/, '');\n } else {\n return str.replace(/-/g, '+').replace(/_/g, '/');\n }\n}\n","export default function safeReplaceObject(wasObject: any, newObject: any) {\n if(!wasObject) {\n return newObject;\n }\n\n for(var key in wasObject) {\n if(!newObject.hasOwnProperty(key)) {\n delete wasObject[key];\n }\n }\n\n for(var key in newObject) {\n //if (newObject.hasOwnProperty(key)) { // useless\n wasObject[key] = newObject[key];\n //}\n }\n \n return wasObject;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { CancellablePromise } from \"../helpers/cancellablePromise\";\r\nimport SetTransition from \"./singleTransition\";\r\nimport { fastRaf } from \"../helpers/schedulers\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\r\nimport isInDOM from \"../helpers/dom/isInDOM\";\r\nimport safeAssign from \"../helpers/object/safeAssign\";\r\n\r\nconst TRANSITION_TIME = 200;\r\n\r\nexport default class ProgressivePreloader {\r\n public preloader: HTMLDivElement;\r\n public circle: SVGCircleElement;\r\n private cancelSvg: SVGSVGElement;\r\n private downloadSvg: HTMLElement;\r\n \r\n private tempId = 0;\r\n public detached = true;\r\n\r\n public promise: CancellablePromise<any> = null;\r\n\r\n public isUpload = false;\r\n private cancelable = true;\r\n private streamable = false;\r\n private tryAgainOnFail = true;\r\n private attachMethod: 'append' | 'prepend' = 'append';\r\n\r\n public loadFunc: (e?: Event) => {download: CancellablePromise<any>};\r\n\r\n public totalLength: number;\r\n\r\n constructor(options?: Partial<{\r\n isUpload: ProgressivePreloader['isUpload'],\r\n cancelable: ProgressivePreloader['cancelable'], \r\n streamable: ProgressivePreloader['streamable'], \r\n tryAgainOnFail: ProgressivePreloader['tryAgainOnFail'],\r\n attachMethod: ProgressivePreloader['attachMethod']\r\n }>) {\r\n if(options) {\r\n safeAssign(this, options);\r\n }\r\n }\r\n\r\n public constructContainer(options: Partial<{\r\n color: 'transparent',\r\n bold: boolean\r\n }> = {}) {\r\n if(!this.preloader) {\r\n this.preloader = document.createElement('div');\r\n this.preloader.classList.add('preloader-container');\r\n\r\n if(options.color) {\r\n this.preloader.classList.add('preloader-' + options.color);\r\n }\r\n\r\n if(options.bold) {\r\n this.preloader.classList.add('preloader-bold');\r\n }\r\n \r\n if(this.streamable) {\r\n this.preloader.classList.add('preloader-streamable');\r\n }\r\n }\r\n }\r\n\r\n public constructDownloadIcon() {\r\n this.constructContainer();\r\n }\r\n\r\n public construct() {\r\n this.construct = null;\r\n\r\n this.constructContainer();\r\n \r\n this.preloader.innerHTML = `\r\n <div class=\"you-spin-me-round\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-circular\" viewBox=\"${this.streamable ? '25 25 50 50' : '27 27 54 54'}\">\r\n <circle class=\"preloader-path-new\" cx=\"${this.streamable ? '50' : '54'}\" cy=\"${this.streamable ? '50' : '54'}\" r=\"${this.streamable ? 19 : 24}\" fill=\"none\" stroke-miterlimit=\"10\"/>\r\n </svg>\r\n </div>`;\r\n\r\n if(this.streamable) {\r\n this.totalLength = 118.61124420166016;\r\n } else {\r\n this.totalLength = 149.82473754882812;\r\n }\r\n\r\n if(this.cancelable) {\r\n this.preloader.innerHTML += `\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-close\" viewBox=\"0 0 24 24\">\r\n <g fill=\"none\" fill-rule=\"evenodd\">\r\n <polygon points=\"0 0 24 0 24 24 0 24\"/>\r\n <path fill=\"#000\" fill-rule=\"nonzero\" d=\"M5.20970461,5.38710056 L5.29289322,5.29289322 C5.65337718,4.93240926 6.22060824,4.90467972 6.61289944,5.20970461 L6.70710678,5.29289322 L12,10.585 L17.2928932,5.29289322 C17.6834175,4.90236893 18.3165825,4.90236893 18.7071068,5.29289322 C19.0976311,5.68341751 19.0976311,6.31658249 18.7071068,6.70710678 L13.415,12 L18.7071068,17.2928932 C19.0675907,17.6533772 19.0953203,18.2206082 18.7902954,18.6128994 L18.7071068,18.7071068 C18.3466228,19.0675907 17.7793918,19.0953203 17.3871006,18.7902954 L17.2928932,18.7071068 L12,13.415 L6.70710678,18.7071068 C6.31658249,19.0976311 5.68341751,19.0976311 5.29289322,18.7071068 C4.90236893,18.3165825 4.90236893,17.6834175 5.29289322,17.2928932 L10.585,12 L5.29289322,6.70710678 C4.93240926,6.34662282 4.90467972,5.77939176 5.20970461,5.38710056 L5.29289322,5.29289322 L5.20970461,5.38710056 Z\"/>\r\n </g>\r\n </svg>\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-download\" viewBox=\"0 0 24 24\">\r\n <g fill=\"none\" fill-rule=\"evenodd\">\r\n <polygon points=\"0 0 24 0 24 24 0 24\"/>\r\n <path fill=\"#000\" fill-rule=\"nonzero\" d=\"M5,19 L19,19 C19.5522847,19 20,19.4477153 20,20 C20,20.5128358 19.6139598,20.9355072 19.1166211,20.9932723 L19,21 L5,21 C4.44771525,21 4,20.5522847 4,20 C4,19.4871642 4.38604019,19.0644928 4.88337887,19.0067277 L5,19 L19,19 L5,19 Z M11.8833789,3.00672773 L12,3 C12.5128358,3 12.9355072,3.38604019 12.9932723,3.88337887 L13,4 L13,13.585 L16.2928932,10.2928932 C16.6533772,9.93240926 17.2206082,9.90467972 17.6128994,10.2097046 L17.7071068,10.2928932 C18.0675907,10.6533772 18.0953203,11.2206082 17.7902954,11.6128994 L17.7071068,11.7071068 L12.7071068,16.7071068 C12.3466228,17.0675907 11.7793918,17.0953203 11.3871006,16.7902954 L11.2928932,16.7071068 L6.29289322,11.7071068 C5.90236893,11.3165825 5.90236893,10.6834175 6.29289322,10.2928932 C6.65337718,9.93240926 7.22060824,9.90467972 7.61289944,10.2097046 L7.70710678,10.2928932 L11,13.585 L11,4 C11,3.48716416 11.3860402,3.06449284 11.8833789,3.00672773 L12,3 L11.8833789,3.00672773 Z\"/>\r\n </g>\r\n </svg>`;\r\n\r\n this.downloadSvg = this.preloader.lastElementChild as HTMLElement;\r\n this.cancelSvg = this.downloadSvg.previousElementSibling as any;\r\n } else {\r\n this.preloader.classList.add('preloader-swing');\r\n }\r\n \r\n this.circle = this.preloader.firstElementChild.firstElementChild.firstElementChild as SVGCircleElement;\r\n\r\n if(this.cancelable) {\r\n attachClickEvent(this.preloader, this.onClick);\r\n }\r\n }\r\n\r\n public onClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(this.preloader.classList.contains('manual')) {\r\n if(this.loadFunc) {\r\n this.loadFunc(e);\r\n }\r\n } else {\r\n if(this.promise && this.promise.cancel) {\r\n this.promise.cancel();\r\n }\r\n }\r\n };\r\n\r\n public setDownloadFunction(func: ProgressivePreloader['loadFunc']) {\r\n this.loadFunc = func;\r\n }\r\n\r\n public setManual() {\r\n this.preloader.classList.add('manual');\r\n this.setProgress(0);\r\n }\r\n\r\n public attachPromise(promise: CancellablePromise<any>) {\r\n if(this.isUpload && this.promise) return;\r\n\r\n this.promise = promise;\r\n\r\n const tempId = --this.tempId;\r\n const startTime = Date.now();\r\n\r\n const onEnd = (err: Error) => {\r\n promise.notify = promise.notifyAll = null;\r\n\r\n if(tempId !== this.tempId) {\r\n return;\r\n }\r\n\r\n const elapsedTime = Date.now() - startTime;\r\n\r\n //console.log('[PP]: end', this.detached, performance.now());\r\n\r\n if(!err && this.cancelable) {\r\n this.setProgress(100);\r\n\r\n const delay = TRANSITION_TIME * 0.75;\r\n\r\n if(elapsedTime < delay) {\r\n this.detach();\r\n } else {\r\n setTimeout(() => { // * wait for transition complete\r\n if(tempId === this.tempId) {\r\n this.detach();\r\n }\r\n }, delay);\r\n }\r\n } else {\r\n if(this.tryAgainOnFail) {\r\n this.attach(this.preloader.parentElement);\r\n fastRaf(() => {\r\n this.setManual();\r\n });\r\n } else {\r\n this.detach();\r\n }\r\n }\r\n \r\n this.promise = promise = null;\r\n };\r\n \r\n promise\r\n .then(() => onEnd(null))\r\n .catch((err) => onEnd(err));\r\n\r\n if(promise.addNotifyListener) {\r\n promise.addNotifyListener((details: {done: number, total: number}) => {\r\n /* if(details.done >= details.total) {\r\n onEnd();\r\n } */\r\n\r\n if(tempId !== this.tempId) return;\r\n\r\n //console.log('preloader download', promise, details);\r\n const percents = details.done / details.total * 100;\r\n this.setProgress(percents);\r\n });\r\n }\r\n }\r\n\r\n public attach(elem: Element, reset = false, promise?: CancellablePromise<any>) {\r\n if(this.construct) {\r\n this.construct();\r\n }\r\n\r\n if(this.preloader.parentElement) {\r\n this.preloader.classList.remove('manual');\r\n }\r\n\r\n this.detached = false;\r\n\r\n if(promise/* && false */) {\r\n this.attachPromise(promise);\r\n }\r\n\r\n if(this.detached || this.preloader.parentElement !== elem) {\r\n const useRafs = isInDOM(this.preloader) ? 1 : 2;\r\n if(this.preloader.parentElement !== elem) {\r\n elem[this.attachMethod](this.preloader);\r\n }\r\n\r\n SetTransition(this.preloader, 'is-visible', true, TRANSITION_TIME, undefined, useRafs);\r\n }\r\n\r\n if(this.cancelable && reset) {\r\n this.setProgress(0);\r\n }\r\n }\r\n \r\n public detach() {\r\n if(this.detached) {\r\n return;\r\n }\r\n //return;\r\n\r\n this.detached = true;\r\n\r\n //return;\r\n \r\n if(this.preloader && this.preloader.parentElement) {\r\n /* setTimeout(() => *///fastRaf(() => {\r\n /* if(!this.detached) return;\r\n this.detached = true; */\r\n\r\n // fastRaf(() => {\r\n //console.log('[PP]: detach after rAF', this.detached, performance.now());\r\n\r\n // if(!this.detached || !this.preloader.parentElement) {\r\n // return;\r\n // }\r\n\r\n SetTransition(this.preloader, 'is-visible', false, TRANSITION_TIME, () => {\r\n this.preloader.remove();\r\n }, 1);\r\n // });\r\n //})/* , 5e3) */;\r\n }\r\n }\r\n \r\n public setProgress(percents: number) {\r\n if(!this.totalLength && !isInDOM(this.circle)) {\r\n return;\r\n }\r\n \r\n if(percents === 0) {\r\n this.circle.style.strokeDasharray = '';\r\n return;\r\n }\r\n \r\n try {\r\n if(!this.totalLength) {\r\n this.totalLength = this.circle.getTotalLength();\r\n }\r\n\r\n //console.log('setProgress', (percents / 100 * totalLength));\r\n this.circle.style.strokeDasharray = '' + Math.max(5, percents / 100 * this.totalLength) + ', ' + this.totalLength;\r\n } catch(err) {}\r\n }\r\n}\r\n","export default function limitSymbols(str: string, length: number, limitFrom = length + 10) {\n str = str.trim();\n if(str.length > limitFrom) {\n str = str.slice(0, length)/* .replace(/\\s*$/, '') */ + '...';\n }\n\n return str;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport { renderImageFromUrlPromise } from \"../../helpers/dom/renderImageFromUrl\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport sequentialDom from \"../../helpers/sequentialDom\";\nimport { UserProfilePhoto, ChatPhoto, InputFileLocation } from \"../../layer\";\nimport { DownloadOptions } from \"../mtproto/apiFileManager\";\nimport { NULL_PEER_ID, REPLIES_PEER_ID } from \"../mtproto/mtproto_config\";\nimport RichTextProcessor from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport appDownloadManager from \"./appDownloadManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appPhotosManager from \"./appPhotosManager\";\nimport appUsersManager from \"./appUsersManager\";\n\ntype PeerPhotoSize = 'photo_small' | 'photo_big';\n\nexport class AppAvatarsManager {\n private savedAvatarURLs: {\n [peerId: PeerId]: {\n [size in PeerPhotoSize]?: string | Promise<string>\n }\n } = {};\n\n public isAvatarCached(peerId: PeerId) {\n return !!this.savedAvatarURLs[peerId];\n }\n \n public removeFromAvatarsCache(peerId: PeerId) {\n if(this.savedAvatarURLs[peerId]) {\n delete this.savedAvatarURLs[peerId];\n }\n }\n\n public loadAvatar(peerId: PeerId, photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, size: PeerPhotoSize) {\n const inputPeer = appPeersManager.getInputPeerById(peerId);\n\n let cached = false;\n let getAvatarPromise: Promise<string>;\n let saved = this.savedAvatarURLs[peerId];\n if(!saved || !saved[size]) {\n if(!saved) {\n saved = this.savedAvatarURLs[peerId] = {};\n }\n\n //console.warn('will invoke downloadSmallFile:', peerId);\n const peerPhotoFileLocation: InputFileLocation.inputPeerPhotoFileLocation = {\n _: 'inputPeerPhotoFileLocation', \n pFlags: {},\n peer: inputPeer, \n photo_id: photo.photo_id\n };\n\n const downloadOptions: DownloadOptions = {dcId: photo.dc_id, location: peerPhotoFileLocation};\n if(size === 'photo_big') {\n peerPhotoFileLocation.pFlags.big = true;\n downloadOptions.limitPart = 512 * 1024;\n }\n\n /* let str: string;\n const time = Date.now();\n if(peerId === 0) {\n str = `download avatar ${peerId}`;\n } */\n\n const promise = appDownloadManager.download(downloadOptions);\n getAvatarPromise = saved[size] = promise.then(blob => {\n return saved[size] = URL.createObjectURL(blob);\n\n /* if(str) {\n console.log(str, Date.now() / 1000, Date.now() - time);\n } */\n });\n } else if(typeof(saved[size]) !== 'string') {\n getAvatarPromise = saved[size] as Promise<any>;\n } else {\n getAvatarPromise = Promise.resolve(saved[size]);\n cached = true;\n }\n\n return {cached, loadPromise: getAvatarPromise};\n }\n\n public putAvatar(\n div: HTMLElement, \n peerId: PeerId, \n photo: UserProfilePhoto.userProfilePhoto | ChatPhoto.chatPhoto, \n size: PeerPhotoSize, \n img = new Image(), \n onlyThumb = false\n ) {\n let {cached, loadPromise} = this.loadAvatar(peerId, photo, size);\n\n img.classList.add('avatar-photo');\n\n let renderThumbPromise: Promise<void>;\n let callback: () => void;\n let thumbImage: HTMLImageElement;\n if(cached) {\n // смотри в misc.ts: renderImageFromUrl\n callback = () => {\n replaceContent(div, img);\n div.dataset.color = '';\n };\n } else {\n const animate = rootScope.settings.animationsEnabled;\n if(animate) {\n img.classList.add('fade-in');\n }\n\n if(size === 'photo_big') { // let's load small photo first\n const res = this.putAvatar(div, peerId, photo, 'photo_small');\n renderThumbPromise = res.loadPromise;\n thumbImage = res.thumbImage;\n } else if(photo.stripped_thumb) {\n thumbImage = new Image();\n div.classList.add('avatar-relative');\n thumbImage.classList.add('avatar-photo', 'avatar-photo-thumbnail');\n const url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb);\n renderThumbPromise = renderImageFromUrlPromise(thumbImage, url).then(() => {\n replaceContent(div, thumbImage);\n });\n }\n\n callback = () => {\n if(thumbImage) {\n div.append(img);\n } else {\n replaceContent(div, img);\n }\n\n setTimeout(() => {\n if(div.childElementCount) {\n sequentialDom.mutateElement(img, () => {\n div.dataset.color = '';\n \n if(animate) {\n img.classList.remove('fade-in');\n }\n\n if(thumbImage) {\n thumbImage.remove();\n }\n });\n }\n }, animate ? 200 : 0);\n };\n }\n\n const renderPromise = loadPromise\n .then((url) => renderImageFromUrlPromise(img, url/* , false */))\n .then(callback);\n\n return {\n cached, \n loadPromise: renderThumbPromise || renderPromise,\n thumbImage\n };\n }\n\n public s(div: HTMLElement, innerHTML: string, color: string, icon: string) {\n div.innerHTML = innerHTML;\n div.dataset.color = color;\n div.classList.remove('tgico-saved', 'tgico-deletedaccount', 'tgico-reply_filled');\n icon && div.classList.add(icon);\n }\n\n // peerId === peerId || title\n public putPhoto(div: HTMLElement, peerId: PeerId, isDialog = false, title = '', onlyThumb = false, isBig?: boolean) {\n const myId = rootScope.myId;\n \n //console.log('loadDialogPhoto location:', location, inputPeer);\n if(peerId === myId && isDialog) {\n this.s(div, '', '', 'tgico-saved');\n return;\n }\n \n if(peerId !== NULL_PEER_ID && peerId.isUser()) {\n const user = appUsersManager.getUser(peerId);\n if(user && user.pFlags && user.pFlags.deleted) {\n this.s(div, '', appPeersManager.getPeerColorById(peerId), 'tgico-deletedaccount');\n return;\n }\n }\n \n const photo = appPeersManager.getPeerPhoto(peerId);\n const avatarAvailable = !!photo;\n const avatarRendered = !!div.firstElementChild && !(div.firstElementChild as HTMLElement).classList.contains('emoji');\n if(!avatarAvailable || !avatarRendered || !this.savedAvatarURLs[peerId]) {\n let color = '';\n if(peerId && (peerId !== myId || !isDialog)) {\n color = appPeersManager.getPeerColorById(peerId);\n }\n\n if(peerId === REPLIES_PEER_ID) {\n this.s(div, '', color, 'tgico-reply_filled');\n return;\n }\n\n let abbr: string;\n if(!title) {\n const peer = appPeersManager.getPeer(peerId);\n abbr = peer.initials ?? '';\n } else {\n abbr = RichTextProcessor.getAbbreviation(title);\n }\n\n this.s(div, abbr, color, '');\n //return Promise.resolve(true);\n }\n\n if(avatarAvailable/* && false */) {\n const size: PeerPhotoSize = isBig ? 'photo_big' : 'photo_small';\n return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb);\n }\n }\n}\n\nconst appAvatarsManager = new AppAvatarsManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appAvatarsManager = appAvatarsManager);\nexport default appAvatarsManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nenum GROUP_CALL_STATE {\n UNMUTED,\n MUTED,\n MUTED_BY_ADMIN,\n CONNECTING,\n CLOSED\n}\n\nexport default GROUP_CALL_STATE;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport {Awaited} from '../types';\n\nexport default function callbackify<T extends Awaited<any>, R>(\n smth: T, \n callback: (result: Awaited<T>) => R\n): PromiseLike<R> | R {\n if(smth instanceof Promise) {\n return smth.then(callback);\n } else {\n return callback(smth as any);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport { processSearchText, ProcessSearchTextOptions } from '../helpers/cleanSearchText';\n\nexport default class SearchIndex<SearchWhat> {\n private fullTexts: Map<SearchWhat, string> = new Map();\n\n // minChars can be 0 because it requires at least one word (one symbol) to be found\n constructor(private options?: ProcessSearchTextOptions, private minChars = 0) {\n }\n\n public indexObject(id: SearchWhat, searchText: string) {\n /* if(searchIndex.fullTexts.hasOwnProperty(id)) {\n return false;\n } */\n\n if(this.options && searchText.trim()) {\n searchText = processSearchText(searchText, this.options);\n }\n\n if(!searchText) {\n this.fullTexts.delete(id);\n return false;\n }\n\n this.fullTexts.set(id, searchText);\n \n /* const shortIndexes = searchIndex.shortIndexes;\n searchText.split(' ').forEach((searchWord) => {\n let len = Math.min(searchWord.length, 3),\n wordPart, i;\n for(i = 1; i <= len; i++) {\n wordPart = searchWord.substr(0, i);\n if(shortIndexes[wordPart] === undefined) {\n shortIndexes[wordPart] = [id];\n } else {\n shortIndexes[wordPart].push(id);\n }\n }\n }); */\n }\n\n public search(query: string) {\n const fullTexts = this.fullTexts;\n //const shortIndexes = searchIndex.shortIndexes;\n\n if(this.options) {\n query = processSearchText(query, this.options);\n }\n\n const newFoundObjs: Array<{fullText: string, fullTextLength: number, what: SearchWhat, foundChars: number}> = [];\n const queryWords = query.split(' ');\n const queryWordsLength = queryWords.length;\n fullTexts.forEach((fullText, what) => {\n let found = true;\n let foundChars = 0;\n for(let i = 0; i < queryWordsLength; ++i) { // * verify that all words are found\n const word = queryWords[i];\n const idx = fullText.indexOf(word);\n if(idx === -1 || (idx !== 0 && fullText[idx - 1] !== ' ')) { // * search only from word beginning\n found = false;\n break;\n }\n\n foundChars += word.length;\n }\n\n if(found) {\n foundChars += queryWordsLength - 1;\n const fullTextLength = fullText.length;\n if(this.minChars <= foundChars || fullTextLength <= foundChars) {\n newFoundObjs.push({fullText, fullTextLength, what, foundChars});\n }\n }\n });\n\n newFoundObjs.sort((a, b) => a.fullTextLength - b.fullTextLength || b.foundChars - a.foundChars);\n\n //newFoundObjs.sort((a, b) => a.fullText.localeCompare(b.fullText));\n const newFoundObjs2: Set<SearchWhat> = new Set(newFoundObjs.map(o => o.what));\n\n /* const queryWords = query.split(' ');\n let foundArr: number[];\n for(let i = 0; i < queryWords.length; i++) {\n const newFound = shortIndexes[queryWords[i].substr(0, 3)];\n if(!newFound) {\n foundArr = [];\n break;\n }\n \n if(foundArr === undefined || foundArr.length > newFound.length) {\n foundArr = newFound;\n }\n }\n\n for(let j = 0; j < foundArr.length; j++) {\n let found = true;\n let searchText = fullTexts[foundArr[j]];\n for(let i = 0; i < queryWords.length; i++) {\n if(searchText.indexOf(queryWords[i]) === -1) {\n found = false;\n break;\n }\n }\n\n if(found) {\n newFoundObjs[foundArr[j]] = true;\n }\n } */\n\n return newFoundObjs2;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport rootScope from \"../rootScope\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport appMessagesManager from \"./appMessagesManager\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport RichTextProcessor from \"../richtextprocessor\";\r\nimport serverTimeManager from \"../mtproto/serverTimeManager\";\r\nimport { MessageEntity, DraftMessage, MessagesSaveDraft } from \"../../layer\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport { tsNow } from \"../../helpers/date\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport stateStorage from \"../stateStorage\";\r\nimport appMessagesIdsManager from \"./appMessagesIdsManager\";\r\nimport assumeType from \"../../helpers/assumeType\";\r\nimport isObject from \"../../helpers/object/isObject\";\r\nimport deepEqual from \"../../helpers/object/deepEqual\";\r\n\r\nexport type MyDraftMessage = DraftMessage.draftMessage;\r\n\r\nexport class AppDraftsManager {\r\n private drafts: {[peerIdAndThreadId: string]: MyDraftMessage} = {};\r\n private getAllDraftPromise: Promise<void> = null;\r\n\r\n constructor() {\r\n stateStorage.get('drafts').then(drafts => {\r\n this.drafts = drafts || {};\r\n });\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateDraftMessage: (update) => {\r\n const peerID = appPeersManager.getPeerId(update.peer);\r\n this.saveDraft(peerID, update.threadId, update.draft, {notify: true});\r\n }\r\n });\r\n }\r\n\r\n private getKey(peerId: PeerId, threadId?: number) {\r\n return '' + peerId + (threadId ? '_' + threadId : '');\r\n }\r\n\r\n public getDraft(peerId: PeerId, threadId?: number) {\r\n return this.drafts[this.getKey(peerId, threadId)];\r\n }\r\n\r\n public addMissedDialogs() {\r\n return this.getAllDrafts().then(() => {\r\n for(const key in this.drafts) {\r\n if(key.indexOf('_') !== -1) { // exclude threads\r\n continue;\r\n }\r\n\r\n const peerId = key.toPeerId();\r\n const dialog = appMessagesManager.getDialogOnly(peerId);\r\n if(!dialog) {\r\n appMessagesManager.reloadConversation(peerId);\r\n /* const dialog = appMessagesManager.generateDialog(peerId);\r\n dialog.draft = this.drafts[key];\r\n appMessagesManager.saveConversation(dialog);\r\n appMessagesManager.newDialogsToHandle[peerId] = dialog;\r\n appMessagesManager.scheduleHandleNewDialogs(); */\r\n }\r\n }\r\n });\r\n }\r\n\r\n public getAllDrafts() {\r\n return this.getAllDraftPromise || (\r\n this.getAllDraftPromise = apiManager.invokeApi('messages.getAllDrafts')\r\n .then((updates) => {\r\n const p = apiUpdatesManager.updatesState.syncLoading || Promise.resolve();\r\n p.then(() => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n })\r\n );\r\n }\r\n\r\n public saveDraft(peerId: PeerId, threadId: number, apiDraft: DraftMessage, options: Partial<{\r\n notify: boolean,\r\n force: boolean\r\n }> = {}) {\r\n const draft = this.processApiDraft(apiDraft);\r\n\r\n const key = this.getKey(peerId, threadId);\r\n if(draft) {\r\n this.drafts[key] = draft;\r\n } else {\r\n delete this.drafts[key];\r\n }\r\n\r\n stateStorage.set({\r\n drafts: this.drafts\r\n });\r\n\r\n if(options.notify) {\r\n // console.warn(dT(), 'save draft', peerId, apiDraft, options)\r\n rootScope.dispatchEvent('draft_updated', {\r\n peerId,\r\n threadId,\r\n draft,\r\n force: options.force\r\n });\r\n }\r\n\r\n return draft;\r\n }\r\n\r\n public draftsAreEqual(draft1: DraftMessage, draft2: DraftMessage) {\r\n if(typeof(draft1) !== typeof(draft2)) {\r\n return false;\r\n }\r\n\r\n if(!isObject(draft1)) {\r\n return true;\r\n }\r\n\r\n if(draft1._ !== draft2._) {\r\n return false;\r\n }\r\n \r\n if(draft1._ === 'draftMessage' && draft2._ === draft1._) {\r\n if(draft1.reply_to_msg_id !== draft2.reply_to_msg_id) {\r\n return false;\r\n }\r\n \r\n if(!deepEqual(draft1.entities, draft2.entities)) {\r\n return false;\r\n }\r\n \r\n if(draft1.message !== draft2.message) {\r\n return false;\r\n }\r\n \r\n if(draft1.pFlags.no_webpage !== draft2.pFlags.no_webpage) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public isEmptyDraft(draft: DraftMessage) {\r\n if(!draft || draft._ === 'draftMessageEmpty') {\r\n return true;\r\n }\r\n \r\n if(draft.reply_to_msg_id > 0) {\r\n return false;\r\n }\r\n \r\n if(!draft.message.length) {\r\n return true;\r\n }\r\n \r\n return false;\r\n }\r\n\r\n public processApiDraft(draft: DraftMessage): MyDraftMessage {\r\n if(!draft || draft._ !== 'draftMessage') {\r\n return undefined;\r\n }\r\n\r\n const myEntities = RichTextProcessor.parseEntities(draft.message);\r\n const apiEntities = draft.entities || [];\r\n const totalEntities = RichTextProcessor.mergeEntities(apiEntities.slice(), myEntities); // ! only in this order, otherwise bold and emoji formatting won't work\r\n\r\n draft.rMessage = RichTextProcessor.wrapDraftText(draft.message, {entities: totalEntities});\r\n //draft.rReply = appMessagesManager.getRichReplyText(draft);\r\n if(draft.reply_to_msg_id) {\r\n draft.reply_to_msg_id = appMessagesIdsManager.generateMessageId(draft.reply_to_msg_id);\r\n }\r\n\r\n return draft;\r\n }\r\n\r\n public async syncDraft(peerId: PeerId, threadId: number, localDraft?: DraftMessage, saveOnServer = true, force = false) {\r\n // console.warn(dT(), 'sync draft', peerID)\r\n const serverDraft = this.getDraft(peerId, threadId);\r\n if(this.draftsAreEqual(serverDraft, localDraft)) {\r\n // console.warn(dT(), 'equal drafts', localDraft, serverDraft)\r\n return true;\r\n }\r\n\r\n // console.warn(dT(), 'changed draft', localDraft, serverDraft)\r\n let params: MessagesSaveDraft = {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n message: ''\r\n };\r\n\r\n let draftObj: DraftMessage;\r\n if(this.isEmptyDraft(localDraft)) {\r\n draftObj = {_: 'draftMessageEmpty'};\r\n } else {\r\n assumeType<DraftMessage.draftMessage>(localDraft);\r\n let message = localDraft.message;\r\n let entities: MessageEntity[] = localDraft.entities;\r\n\r\n if(localDraft.reply_to_msg_id) {\r\n params.reply_to_msg_id = appMessagesIdsManager.getServerMessageId(localDraft.reply_to_msg_id);\r\n }\r\n\r\n if(entities?.length) {\r\n params.entities = appMessagesManager.getInputEntities(entities);\r\n }\r\n\r\n if(localDraft.pFlags.no_webpage) {\r\n params.no_webpage = localDraft.pFlags.no_webpage;\r\n }\r\n\r\n params.message = message;\r\n }\r\n\r\n const saveLocalDraft = draftObj || localDraft;\r\n saveLocalDraft.date = tsNow(true) + serverTimeManager.serverTimeOffset;\r\n\r\n this.saveDraft(peerId, threadId, saveLocalDraft, {notify: true, force});\r\n\r\n if(saveOnServer && !threadId) {\r\n return apiManager.invokeApi('messages.saveDraft', params);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public clearAllDrafts() {\r\n return apiManager.invokeApi('messages.clearAllDrafts').then(bool => {\r\n if(!bool) {\r\n return;\r\n }\r\n\r\n for(const combined in this.drafts) {\r\n const [peerId, threadId] = combined.split('_');\r\n rootScope.dispatchEvent('draft_updated', {\r\n peerId: peerId.toPeerId(),\r\n threadId: threadId ? +threadId : undefined,\r\n draft: undefined\r\n });\r\n }\r\n });\r\n }\r\n\r\n public clearDraft(peerId: PeerId, threadId: number) {\r\n const emptyDraft: DraftMessage.draftMessageEmpty = {\r\n _: 'draftMessageEmpty'\r\n };\r\n\r\n if(threadId) {\r\n this.syncDraft(peerId, threadId, emptyDraft as any, false, true);\r\n } else {\r\n this.saveDraft(peerId, threadId, emptyDraft, {notify: true, force: true}); \r\n }\r\n }\r\n\r\n public setDraft(peerId: PeerId, threadId: number, message: string, entities?: MessageEntity[]) {\r\n const draft: DraftMessage.draftMessage = {\r\n _: 'draftMessage',\r\n date: Date.now() / 1000 | 0,\r\n message,\r\n pFlags: {},\r\n entities\r\n };\r\n\r\n if(threadId) {\r\n this.syncDraft(peerId, threadId, draft, false, true);\r\n } else {\r\n this.saveDraft(peerId, threadId, draft, {notify: true, force: true}); \r\n }\r\n }\r\n}\r\n\r\nconst appDraftsManager = new AppDraftsManager();\r\nMOUNT_CLASS_TO.appDraftsManager = appDraftsManager;\r\nexport default appDraftsManager;\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport indexOfAndSplice from '../../helpers/array/indexOfAndSplice';\nimport safeAssign from '../../helpers/object/safeAssign';\nimport { GroupCallParticipantVideoSourceGroup } from '../../layer';\nimport { fixMediaLineType, SDPBuilder, WebRTCLineType, WEBRTC_MEDIA_PORT } from './sdpBuilder';\nimport { AudioCodec, GroupCallConnectionTransport, Ssrc, UpdateGroupCallConnectionData, VideoCodec } from './types';\n\nexport class ConferenceEntry {\n public source: number;\n public sourceGroups: GroupCallParticipantVideoSourceGroup[];\n public transceiver: RTCRtpTransceiver;\n public originalDirection: RTCRtpTransceiverDirection;\n public direction: RTCRtpTransceiverDirection;\n public port: string;\n public endpoint: string;\n public peerId: PeerId;\n \n public sendEntry: ConferenceEntry;\n public recvEntry: ConferenceEntry;\n\n constructor(public mid: string, public type: WebRTCLineType) {\n this.port = WEBRTC_MEDIA_PORT;\n }\n\n public setDirection(direction: RTCRtpTransceiverDirection) {\n if(!this.originalDirection) {\n this.originalDirection = direction;\n }\n\n return this.direction = direction;\n }\n\n public setPort(port: string) {\n return this.port = port;\n }\n\n public setEndpoint(endpoint: string) {\n return this.endpoint = endpoint;\n }\n\n public setPeerId(peerId: PeerId) {\n return this.peerId = peerId;\n }\n\n public createTransceiver(connection: RTCPeerConnection, init?: RTCRtpTransceiverInit) {\n if(init?.direction) {\n this.setDirection(init.direction);\n }\n\n return this.transceiver = connection.addTransceiver(fixMediaLineType(this.type), init);\n }\n\n public setSource(source: number | GroupCallParticipantVideoSourceGroup[]) {\n let sourceGroups: GroupCallParticipantVideoSourceGroup[];\n if(Array.isArray(source)) {\n if(!source[0]) return;\n sourceGroups = source;\n source = sourceGroups[0].sources[0];\n }\n\n this.sourceGroups = sourceGroups;\n return this.source = source;\n }\n\n public shouldBeSkipped(isAnswer?: boolean) {\n return isAnswer && this.direction === 'inactive';\n }\n}\n\nexport function generateSsrc(type: WebRTCLineType, source: number | GroupCallParticipantVideoSourceGroup[], endpoint?: string): Ssrc {\n let sourceGroups: GroupCallParticipantVideoSourceGroup[];\n if(Array.isArray(source)) {\n if(!source[0]) return;\n sourceGroups = source;\n source = sourceGroups[0].sources[0];\n }\n \n return {\n endpoint,\n type,\n source,\n sourceGroups,\n };\n}\n\nexport default class LocalConferenceDescription implements UpdateGroupCallConnectionData {\n public readonly sessionId: string;\n // public ssrcs: Ssrc[];\n public readonly transport: GroupCallConnectionTransport;\n public readonly audio?: AudioCodec;\n public readonly video: VideoCodec;\n public readonly screencast?: VideoCodec;\n \n private maxSeenId: number;\n public readonly entries: ConferenceEntry[];\n private entriesByMid: Map<ConferenceEntry['mid'], ConferenceEntry>;\n private entriesBySource: Map<ConferenceEntry['source'], ConferenceEntry>;\n private entriesByPeerId: Map<ConferenceEntry['peerId'], Set<ConferenceEntry>>;\n \n constructor(public connection: RTCPeerConnection) {\n this.sessionId = '' + Date.now();\n // this.ssrcs = [];\n this.maxSeenId = -1;\n this.entries = [];\n this.entriesByMid = new Map();\n this.entriesBySource = new Map();\n this.entriesByPeerId = new Map();\n }\n\n public setData(data: UpdateGroupCallConnectionData) {\n return safeAssign(this, data);\n }\n\n public createEntry(type: WebRTCLineType) {\n const mid = '' + ++this.maxSeenId;\n const entry = new ConferenceEntry(mid, type);\n this.entries.push(entry);\n this.entriesByMid.set(mid, entry);\n return entry;\n }\n\n public deleteEntry(entry: ConferenceEntry) {\n indexOfAndSplice(this.entries, entry);\n this.entriesByMid.delete(entry.mid);\n this.entriesBySource.delete(entry.source);\n\n const set = this.entriesByPeerId.get(entry.peerId);\n if(set) {\n set.delete(entry);\n if(!set.size) {\n this.entriesByPeerId.delete(entry.peerId);\n }\n }\n }\n\n public setEntrySource(entry: ConferenceEntry, source: Parameters<ConferenceEntry['setSource']>[0]) {\n entry.setSource(source);\n this.entriesBySource.set(entry.source, entry);\n }\n\n public setEntryPeerId(entry: ConferenceEntry, peerId: ConferenceEntry['peerId']) {\n entry.setPeerId(peerId);\n let set = this.entriesByPeerId.get(peerId);\n if(!set) {\n this.entriesByPeerId.set(peerId, set = new Set());\n }\n\n set.add(entry);\n }\n \n public findEntry(verify: Parameters<LocalConferenceDescription['entries']['find']>[0]) {\n return this.entries.find(verify);\n }\n\n public findFreeSendRecvEntry(type: WebRTCLineType, isSending: boolean) {\n let entry = this.entries.find(entry => {\n return entry.direction === 'sendrecv' && entry.type === type && !(isSending ? entry.sendEntry : entry.recvEntry);\n });\n\n if(!entry) {\n entry = this.createEntry(type);\n entry.setDirection('sendrecv');\n }\n\n return entry;\n }\n \n public getEntryByMid(mid: ConferenceEntry['mid']) {\n return this.entriesByMid.get(mid);\n }\n\n public getEntryBySource(source: ConferenceEntry['source']) {\n return this.entriesBySource.get(source);\n }\n\n public getEntriesByPeerId(peerId: ConferenceEntry['peerId']) {\n return this.entriesByPeerId.get(peerId);\n }\n\n public generateSdp(options: Omit<Parameters<SDPBuilder['addConference']>[0], 'conference'>) {\n return SDPBuilder.fromConference({\n conference: this,\n ...options\n });\n }\n}\n","\nlet context: CanvasRenderingContext2D;\n/**\n * Get the text width\n * @param {string} text\n * @param {string} font\n */\nexport default function getTextWidth(text: string, font: string) {\n //const perf = performance.now();\n if(!context) {\n const canvas = document.createElement('canvas');\n context = canvas.getContext('2d');\n context.font = font;\n }\n\n //context.font = font;\n const metrics = context.measureText(text);\n //console.log('getTextWidth perf:', performance.now() - perf);\n return metrics.width;\n //return Math.round(metrics.width);\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport getTextWidth from \"../helpers/canvas/getTextWidth\";\r\nimport mediaSizes, { MediaSize } from \"../helpers/mediaSizes\";\r\nimport clamp from \"../helpers/number/clamp\";\r\nimport { fastRaf } from \"../helpers/schedulers\";\r\n\r\n// Thanks to https://stackoverflow.com/a/49349813\r\n\r\n/**\r\n * Attibute modifier to create middle ellipsis\r\n * When the attribute value is left blank the ellipsis will be in the middle\r\n * When positive the attribute value will be used as a percentage\r\n * When negative the attribute value will be used as character index counted from the end\r\n * @example\r\n * <div data-middle-ellipsis>A Javascript solution to middle ellipsis</div>\r\n * <div data-middle-ellipsis=\"20\">A Javascript solution to middle ellipsis</div>\r\n * <div data-middle-ellipsis=\"-3\">A Javascript solution to middle ellipsis</div>\r\n */\r\nconst ellipsis = '…';\r\nconst map: Map<HTMLElement, {\r\n text: string,\r\n textLength: number,\r\n from: number,\r\n multiplier: number,\r\n font: string,\r\n textWidth: number,\r\n elementWidth: number\r\n}> = new Map();\r\n\r\nconst testQueue: Set<HTMLElement> = new Set();\r\nexport const fontFamily = 'Roboto, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif';\r\nconst fontSize = '16px';\r\nlet pendingTest = false;\r\n\r\nfunction setTestQueue() {\r\n if(pendingTest) {\r\n return;\r\n }\r\n\r\n pendingTest = true;\r\n fastRaf(() => {\r\n pendingTest = false;\r\n testQueueElements();\r\n });\r\n}\r\n\r\nfunction testQueueElements() {\r\n testQueue.forEach(testElement);\r\n testQueue.clear();\r\n}\r\n\r\nwindow.addEventListener('resize', () => {\r\n for(const [key] of map) {\r\n testQueue.add(key);\r\n }\r\n \r\n setTestQueue();\r\n}, {capture: true, passive: true});\r\n\r\nfunction getElementWidth(element: HTMLElement) {\r\n const type = element.dataset.sizeType;\r\n if(type) {\r\n const mediaSize = mediaSizes.active;\r\n // @ts-ignore\r\n const size: MediaSize = mediaSize[type];\r\n return size.width;\r\n } \r\n \r\n return element.getBoundingClientRect().width;\r\n}\r\n\r\nfunction testElement(element: HTMLElement) {\r\n //const perf = performance.now();\r\n // do not recalculate variables a second time\r\n let mapped = map.get(element);\r\n const firstTime = !mapped;\r\n\r\n let {text, textLength, from, multiplier, font, textWidth, elementWidth} = mapped || {};\r\n //console.log('[MEE] testElement got mapped', mapped);\r\n\r\n if(firstTime) {\r\n text = element.textContent;\r\n textLength = text.length;\r\n from = /* parseFloat(element.getAttribute(attributeName)) || */50;\r\n multiplier = from > 0 && from / 100;\r\n\r\n //const perf = performance.now();\r\n font = `${element.dataset.fontWeight || 400} ${fontSize} ${fontFamily}`;\r\n /* const computedStyle = window.getComputedStyle(elm, null);\r\n font = `${computedStyle.getPropertyValue('font-weight')} ${computedStyle.getPropertyValue('font-size')} ${computedStyle.getPropertyValue('font-family')}`; */\r\n //console.log('testMiddleEllipsis get computed style:', performance.now() - perf, font);\r\n\r\n textWidth = getTextWidth(text, font);\r\n //const perf = performance.now();\r\n elementWidth = getElementWidth(element);\r\n //console.log('testMiddleEllipsis get offsetWidth:', performance.now() - perf, font);\r\n mapped = {text, textLength, from, multiplier, font, textWidth, elementWidth};\r\n map.set(element, mapped);\r\n\r\n //console.log('[MEE] testElement map set', element);\r\n }\r\n \r\n const newElementWidth = getElementWidth(element);\r\n const widthChanged = firstTime || elementWidth !== newElementWidth;\r\n !firstTime && widthChanged && (mapped.elementWidth = elementWidth = newElementWidth);\r\n \r\n if(widthChanged) {\r\n if(textWidth > elementWidth) {\r\n element.setAttribute('title', text);\r\n let smallerText = text;\r\n let smallerWidth = elementWidth;\r\n while(smallerText.length > 3) {\r\n let smallerTextLength = smallerText.length;\r\n const half = multiplier &&\r\n clamp(multiplier * smallerTextLength << 0, 1, smallerTextLength - 2) ||\r\n Math.max(smallerTextLength + from - 1, 1);\r\n const half1 = smallerText.substr(0, half).replace(/\\s*$/,'');\r\n const half2 = smallerText.substr(half + 1).replace(/^\\s*/,'');\r\n smallerText = half1 + half2;\r\n smallerWidth = getTextWidth(smallerText + ellipsis, font);\r\n if(smallerWidth < elementWidth) {\r\n element.textContent = half1 + ellipsis + half2;\r\n break;\r\n }\r\n }\r\n\r\n // * set new width after cutting text\r\n mapped.elementWidth = getElementWidth(element);\r\n //mapped.textWidth = smallerWidth;\r\n } else {\r\n element.removeAttribute('title');\r\n }\r\n }\r\n\r\n //console.log('testMiddleEllipsis for element:', elm, performance.now() - perf);\r\n}\r\n\r\nexport class MiddleEllipsisElement extends HTMLElement {\r\n connectedCallback() {\r\n //console.log('[MEE]: connectedCallback before', map.has(this), testQueue.has(this), map.size, this.textContent, map);\r\n\r\n map.set(this, null);\r\n if(this.dataset.sizeType) {\r\n testElement(this);\r\n } else {\r\n testQueue.add(this);\r\n setTestQueue();\r\n }\r\n //testElement(this);\r\n\r\n //console.log('[MEE]: connectedCallback after', map.has(this), map.size, testQueue.has(this), testQueue.size);\r\n }\r\n\r\n disconnectedCallback() {\r\n const deleted = map.delete(this);\r\n testQueue.delete(this);\r\n //console.log('[MEE]: disconnectedCallback', deleted, map.has(this), map.size, this.textContent, map);\r\n }\r\n}\r\n\r\ncustomElements.define(\"middle-ellipsis-element\", MiddleEllipsisElement);\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport AudioAssetPlayer from \"../../helpers/audioAssetPlayer\";\nimport safeReplaceObject from \"../../helpers/object/safeReplaceObject\";\nimport { nextRandomUint } from \"../../helpers/random\";\nimport tsNow from \"../../helpers/tsNow\";\nimport { GroupCall, GroupCallParticipant, GroupCallParticipantVideo, GroupCallParticipantVideoSourceGroup, InputGroupCall, Peer, PhoneJoinGroupCall, PhoneJoinGroupCallPresentation, Update, Updates } from \"../../layer\";\nimport GroupCallInstance from \"../calls/groupCallInstance\";\nimport GROUP_CALL_STATE from \"../calls/groupCallState\";\nimport createMainStreamManager from \"../calls/helpers/createMainStreamManager\";\nimport { generateSsrc } from \"../calls/localConferenceDescription\";\nimport { WebRTCLineType } from \"../calls/sdpBuilder\";\nimport StreamManager from \"../calls/streamManager\";\nimport { Ssrc } from \"../calls/types\";\nimport { logger } from \"../logger\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport { NULL_PEER_ID } from \"../mtproto/mtproto_config\";\nimport rootScope from \"../rootScope\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appChatsManager from \"./appChatsManager\";\nimport appPeersManager from \"./appPeersManager\";\nimport appUsersManager from \"./appUsersManager\";\n\nexport type GroupCallId = GroupCall['id'];\nexport type MyGroupCall = GroupCall | InputGroupCall;\n\nexport type GroupCallConnectionType = 'main' | 'presentation';\n\nexport type JoinGroupCallJsonPayload = {\n fingerprints: {\n fingerprint: string;\n setup: string;\n hash: string;\n }[];\n pwd: string;\n ssrc: number;\n 'ssrc-groups': GroupCallParticipantVideoSourceGroup.groupCallParticipantVideoSourceGroup[];\n ufrag: string;\n};\n\nconst GET_PARTICIPANTS_LIMIT = 100;\n\nlet IS_MUTED = true;\n\nexport type GroupCallOutputSource = 'main' | 'presentation' | number;\n\nexport type GroupCallAudioAssetName = \"group_call_connect.mp3\" | \"group_call_end.mp3\" | \"group_call_start.mp3\" | \"voip_onallowtalk.mp3\";\n\nexport class AppGroupCallsManager {\n private log: ReturnType<typeof logger>;\n \n private groupCalls: Map<GroupCallId, MyGroupCall>;\n private participants: Map<GroupCallId, Map<PeerId, GroupCallParticipant>>;\n private nextOffsets: Map<GroupCallId, string>;\n \n // private audioAsset: AudioAsset;\n \n private currentGroupCall: GroupCallInstance;\n private connectionAudio: HTMLAudioElement;\n private doNotDispatchParticipantUpdate: PeerId;\n private audioAsset: AudioAssetPlayer<GroupCallAudioAssetName>;\n\n constructor() {\n this.log = logger('GROUP-CALLS');\n \n this.groupCalls = new Map();\n this.participants = new Map();\n this.nextOffsets = new Map();\n \n rootScope.addMultipleEventsListeners({\n updateGroupCall: (update) => {\n this.saveGroupCall(update.call, update.chat_id);\n },\n \n updateGroupCallParticipants: (update) => {\n this.saveGroupCall(update.call);\n \n // this.getGroupCallFull(update.call.id, true); // ! WARNING TEMP\n\n const groupCallId = update.call.id;\n this.saveApiParticipants(groupCallId, update.participants);\n }\n });\n\n rootScope.addEventListener('group_call_update', (groupCall) => {\n if(groupCall._ === 'groupCallDiscarded') {\n const {currentGroupCall} = this;\n if(currentGroupCall?.id === groupCall.id) {\n currentGroupCall.hangUp(false, false, true);\n }\n\n this.participants.delete(groupCall.id);\n }\n });\n\n this.audioAsset = new AudioAssetPlayer<GroupCallAudioAssetName>([\n 'group_call_connect.mp3',\n 'group_call_end.mp3',\n 'group_call_start.mp3',\n 'voip_onallowtalk.mp3'\n ]);\n }\n\n get groupCall() {\n return this.currentGroupCall;\n }\n\n public getCachedParticipants(groupCallId: GroupCallId) {\n let participants = this.participants.get(groupCallId);\n if(!participants) {\n this.participants.set(groupCallId, participants = new Map());\n }\n\n return participants;\n }\n\n private prepareToSavingNextOffset(groupCallId: GroupCallId) {\n const nextOffsetsMap = this.nextOffsets;\n\n const setNextOffset = (newNextOffset: string) => {\n if(nextOffsetsMap.get(groupCallId) === nextOffset) {\n nextOffsetsMap.set(groupCallId, newNextOffset);\n }\n };\n\n const nextOffset = nextOffsetsMap.get(groupCallId);\n return {\n nextOffset,\n setNextOffset\n };\n }\n\n public saveApiParticipant(groupCallId: GroupCallId, participant: GroupCallParticipant, skipCounterUpdating?: boolean) {\n const {currentGroupCall} = this;\n const participants = this.getCachedParticipants(groupCallId);\n\n const peerId = appPeersManager.getPeerId(participant.peer);\n\n const oldParticipant = participants.get(peerId);\n const hasLeft = participant.pFlags.left;\n if(!oldParticipant && hasLeft) {\n return;\n }\n\n // * fix missing flag\n if(!participant.pFlags.muted && !participant.pFlags.can_self_unmute) {\n participant.pFlags.can_self_unmute = true;\n }\n\n const isCurrentGroupCall = currentGroupCall?.id === groupCallId;\n\n if(oldParticipant) {\n safeReplaceObject(oldParticipant, participant);\n participant = oldParticipant;\n } else {\n participants.set(peerId, participant);\n }\n\n if(isCurrentGroupCall) {\n currentGroupCall.onParticipantUpdate(participant, this.doNotDispatchParticipantUpdate);\n }\n\n // if(!skipCounterUpdating) {\n const groupCall = this.getGroupCall(groupCallId);\n if(groupCall?._ === 'groupCall') {\n let modified = false;\n if(hasLeft) {\n --groupCall.participants_count;\n modified = true;\n } else if(participant.pFlags.just_joined && !oldParticipant && !participant.pFlags.self) {\n ++groupCall.participants_count;\n modified = true;\n }\n \n if(modified) {\n rootScope.dispatchEvent('group_call_update', groupCall);\n }\n }\n // }\n \n if(hasLeft) {\n participants.delete(peerId);\n }\n\n if(oldParticipant && this.doNotDispatchParticipantUpdate !== peerId) {\n rootScope.dispatchEvent('group_call_participant', {\n groupCallId,\n participant\n });\n }\n }\n\n public saveApiParticipants(groupCallId: GroupCallId, apiParticipants: GroupCallParticipant[], skipCounterUpdating?: boolean) {\n if((apiParticipants as any).saved) return;\n (apiParticipants as any).saved = true;\n apiParticipants.forEach(p => this.saveApiParticipant(groupCallId, p, skipCounterUpdating));\n }\n\n public async editParticipant(groupCallId: GroupCallId, participant: GroupCallParticipant, options: Partial<{\n muted: boolean,\n volume: number,\n raiseHand: boolean,\n videoStopped: boolean,\n videoPaused: boolean,\n presentationPaused: boolean\n }>) {\n if(!Object.keys(options).length) {\n return;\n }\n\n let processUpdate = true;\n if(participant) {\n const {currentGroupCall} = this;\n const isCurrentCall = currentGroupCall?.id === groupCallId;\n const isUpdatingMeInCurrentCall = isCurrentCall && participant.pFlags.self;\n\n if(isUpdatingMeInCurrentCall) {\n if(options.muted !== undefined && !currentGroupCall.isSharingAudio) {\n delete options.muted;\n\n if(!Object.keys(options).length) {\n return;\n }\n }\n }\n\n // if(isCurrentCall) {\n const muted = options.muted;\n if(muted !== undefined) {\n /* const isAdmin = appChatsManager.hasRights(currentGroupCall.chatId, 'manage_call');\n if(isAdmin) {\n if(muted) {\n participant.pFlags.muted = true;\n delete participant.pFlags.can_self_unmute;\n } else {\n participant.pFlags.can_self_unmute = true;\n }\n } else */if(participant.pFlags.self) {\n if(muted) {\n participant.pFlags.muted = true;\n } else if(participant.pFlags.can_self_unmute) {\n delete participant.pFlags.muted;\n }\n }/* else {\n if(muted) {\n participant.pFlags.muted_by_you = true;\n } else {\n delete participant.pFlags.muted_by_you;\n }\n } */\n }\n // }\n\n /* const a: [keyof GroupCallParticipant['pFlags'], keyof typeof options][] = [\n ['muted', 'muted']\n ];\n\n a.forEach(([key, optionKey]) => {\n const value = options[optionKey];\n if(value === undefined) {\n return;\n }\n\n if(value) {\n participant.pFlags[key] = true;\n } else {\n delete participant.pFlags[key];\n }\n }); */\n\n if(options.raiseHand !== undefined) {\n if(options.raiseHand) participant.raise_hand_rating = '1';\n else delete participant.raise_hand_rating;\n }\n\n if(isUpdatingMeInCurrentCall) {\n if(options.videoStopped !== undefined) {\n if(options.videoStopped) delete participant.video;\n else participant.video = this.generateSelfVideo(currentGroupCall.connections.main.sources.video);\n }\n\n if(!participant.pFlags.muted && participant.pFlags.can_self_unmute) {\n currentGroupCall.setMuted(false);\n }\n\n currentGroupCall.dispatchEvent('state', currentGroupCall.state);\n }\n\n rootScope.dispatchEvent('group_call_participant', {groupCallId, participant});\n\n /* if(participant.pFlags.self) {\n processUpdate = false;\n } */\n }\n\n const peerId = participant.pFlags.self ? NULL_PEER_ID : appPeersManager.getPeerId(participant.peer);\n const updates = await apiManager.invokeApiSingle('phone.editGroupCallParticipant', {\n call: appGroupCallsManager.getGroupCallInput(groupCallId),\n participant: peerId === NULL_PEER_ID ? appPeersManager.getInputPeerSelf() : appPeersManager.getInputPeerById(peerId),\n muted: options.muted,\n volume: options.volume,\n raise_hand: options.raiseHand,\n video_paused: options.videoPaused,\n video_stopped: options.videoStopped,\n presentation_paused: options.presentationPaused\n });\n \n // do not replace with peerId because it can be null\n if(!processUpdate) this.doNotDispatchParticipantUpdate = appPeersManager.getPeerId(participant.peer);\n apiUpdatesManager.processUpdateMessage(updates);\n if(!processUpdate) this.doNotDispatchParticipantUpdate = undefined;\n }\n \n public getGroupCall(id: GroupCallId) {\n return this.groupCalls.get(id);\n }\n\n public async getGroupCallFull(id: GroupCallId, override?: boolean): Promise<GroupCall> {\n const call = this.getGroupCall(id);\n if(call && call._ !== 'inputGroupCall' && !override) {\n return call;\n }\n\n const limit = this.getCachedParticipants(id).size ? 0 : GET_PARTICIPANTS_LIMIT;\n return apiManager.invokeApiSingleProcess({\n method: 'phone.getGroupCall',\n params: {\n call: this.getGroupCallInput(id),\n limit\n },\n processResult: (groupCall) => {\n // ? maybe I should save group call after participants so I can avoid passing the 'skipCounterUpdating' flag ?\n appUsersManager.saveApiUsers(groupCall.users);\n appChatsManager.saveApiChats(groupCall.chats);\n this.saveApiParticipants(id, groupCall.participants, true);\n const call = this.saveGroupCall(groupCall.call) as GroupCall;\n\n if(limit && this.nextOffsets.get(id) === undefined) {\n this.nextOffsets.set(id, groupCall.participants_next_offset);\n }\n\n return call;\n }\n });\n }\n \n public saveGroupCall(call: MyGroupCall, chatId?: ChatId) {\n const oldCall = this.groupCalls.get(call.id);\n const shouldUpdate = call._ !== 'inputGroupCall' && (!oldCall || oldCall._ !== 'groupCallDiscarded');\n if(oldCall) {\n if(shouldUpdate) {\n safeReplaceObject(oldCall, call);\n }\n \n call = oldCall;\n } else {\n this.groupCalls.set(call.id, call);\n }\n\n if(shouldUpdate) {\n rootScope.dispatchEvent('group_call_update', call as any);\n }\n\n return call;\n }\n \n public startConnectingSound() {\n this.stopConnectingSound();\n this.audioAsset.playSoundWithTimeout('group_call_connect.mp3', true, 2500);\n }\n \n public stopConnectingSound() {\n this.audioAsset.stopSound();\n this.audioAsset.cancelDelayedPlay();\n }\n\n public setCurrentGroupCall(groupCall: GroupCallInstance) {\n this.currentGroupCall = groupCall;\n\n if(groupCall) {\n rootScope.dispatchEvent('group_call_instance', groupCall);\n }\n /* TdLibController.clientUpdate({\n '@type': 'clientUpdateGroupCall',\n call\n }); */\n }\n\n public async createGroupCall(chatId: ChatId, scheduleDate?: number, title?: string) {\n const updates = await apiManager.invokeApi('phone.createGroupCall', {\n peer: appPeersManager.getInputPeerById(chatId.toPeerId(true)),\n random_id: nextRandomUint(32),\n schedule_date: scheduleDate,\n title\n });\n\n apiUpdatesManager.processUpdateMessage(updates);\n\n const update = (updates as Updates.updates).updates.find(update => update._ === 'updateGroupCall') as Update.updateGroupCall;\n return update.call;\n }\n \n public async joinGroupCall(chatId: ChatId, groupCallId: GroupCallId, muted = IS_MUTED, rejoin?: boolean, joinVideo?: boolean) {\n this.audioAsset.createAudio();\n\n this.log(`joinGroupCall chatId=${chatId} id=${groupCallId} muted=${muted} rejoin=${rejoin}`);\n \n let streamManager: StreamManager;\n if(rejoin) {\n streamManager = this.currentGroupCall.connections.main.streamManager;\n } else {\n streamManager = await createMainStreamManager(muted, joinVideo);\n }\n\n return this.joinGroupCallInternal(chatId, groupCallId, streamManager, muted, rejoin, joinVideo);\n }\n\n public async joinGroupCallInternal(chatId: ChatId, groupCallId: GroupCallId, streamManager: StreamManager, muted: boolean, rejoin = false, joinVideo?: boolean) {\n const log = this.log.bindPrefix('joinGroupCallInternal');\n log('start', groupCallId);\n\n const type: GroupCallConnectionType = 'main';\n\n let {currentGroupCall} = this;\n if(currentGroupCall && rejoin) {\n // currentGroupCall.connections.main.connection = connection;\n currentGroupCall.handleUpdateGroupCallParticipants = false;\n currentGroupCall.updatingSdp = false;\n log('update currentGroupCall', groupCallId, currentGroupCall);\n } else {\n currentGroupCall = new GroupCallInstance({\n chatId,\n id: groupCallId\n });\n\n currentGroupCall.fixSafariAudio();\n\n currentGroupCall.addEventListener('state', (state) => {\n if(this.currentGroupCall === currentGroupCall && state === GROUP_CALL_STATE.CLOSED) {\n this.setCurrentGroupCall(null);\n this.stopConnectingSound();\n this.audioAsset.playSound('group_call_end.mp3');\n rootScope.dispatchEvent('chat_update', currentGroupCall.chatId);\n }\n });\n\n currentGroupCall.groupCall = await this.getGroupCallFull(groupCallId);\n\n const connectionInstance = currentGroupCall.createConnectionInstance({\n streamManager,\n type,\n options: {\n type,\n isMuted: muted,\n joinVideo,\n rejoin\n }\n });\n\n const connection = connectionInstance.createPeerConnection();\n connection.addEventListener('negotiationneeded', () => {\n connectionInstance.negotiate();\n });\n\n connection.addEventListener('track', (event) => {\n log('ontrack', event);\n currentGroupCall.onTrack(event);\n });\n \n connection.addEventListener('iceconnectionstatechange', () => {\n currentGroupCall.dispatchEvent('state', currentGroupCall.state);\n \n const {iceConnectionState} = connection;\n if(iceConnectionState === 'disconnected' || iceConnectionState === 'checking' || iceConnectionState === 'new') {\n this.startConnectingSound();\n } else {\n this.stopConnectingSound();\n }\n \n switch(iceConnectionState) {\n case 'checking': {\n break;\n }\n \n case 'closed': {\n currentGroupCall.hangUp();\n break;\n }\n \n case 'completed': {\n break;\n }\n \n case 'connected': {\n if(!currentGroupCall.joined) {\n currentGroupCall.joined = true;\n this.audioAsset.playSound('group_call_start.mp3');\n \n this.getGroupCallParticipants(groupCallId).then(({participants}) => {\n this.saveApiParticipants(groupCallId, [...participants.values()]);\n });\n }\n \n break;\n }\n \n case 'disconnected': {\n break;\n }\n \n case 'failed': {\n //TODO: replace with ICE restart\n currentGroupCall.hangUp();\n // connection.restartIce();\n break;\n }\n \n case 'new': {\n break;\n }\n }\n });\n\n connectionInstance.createDescription();\n connectionInstance.createDataChannel();\n\n connectionInstance.appendStreamToConference();\n\n this.setCurrentGroupCall(currentGroupCall);\n log('set currentGroupCall', groupCallId, currentGroupCall);\n\n this.startConnectingSound();\n\n return connectionInstance.negotiate();\n }\n }\n \n public getGroupCallInput(id: GroupCallId): InputGroupCall {\n const groupCall = this.getGroupCall(id);\n return {\n _: 'inputGroupCall',\n id: groupCall.id,\n access_hash: groupCall.access_hash\n };\n }\n\n public generateSelfVideo(source: Ssrc, audioSource?: number): GroupCallParticipantVideo {\n return source && {\n _: 'groupCallParticipantVideo',\n pFlags: {},\n endpoint: '',\n source_groups: source.sourceGroups,\n audio_source: audioSource\n };\n }\n \n public generateSelfParticipant(): GroupCallParticipant {\n const mainSources = this.currentGroupCall.connections.main.sources;\n const presentationSources = this.currentGroupCall.connections.presentation?.sources;\n return {\n _: 'groupCallParticipant',\n pFlags: {\n can_self_unmute: true,\n self: true\n },\n source: mainSources.audio.source,\n video: this.generateSelfVideo(mainSources.video),\n presentation: presentationSources && this.generateSelfVideo(presentationSources.video, presentationSources.audio?.source),\n date: tsNow(true),\n peer: appPeersManager.getOutputPeer(rootScope.myId)\n };\n }\n\n public makeSsrcsFromParticipant = (participant: GroupCallParticipant) => {\n return [\n this.makeSsrcFromParticipant(participant, 'audio', participant.source),\n participant.video?.audio_source && this.makeSsrcFromParticipant(participant, 'audio', participant.video.audio_source),\n participant.video && this.makeSsrcFromParticipant(participant, 'video', participant.video.source_groups, participant.video.endpoint),\n participant.presentation?.audio_source && this.makeSsrcFromParticipant(participant, 'audio', participant.presentation.audio_source),\n participant.presentation && this.makeSsrcFromParticipant(participant, 'video', participant.presentation.source_groups, participant.presentation.endpoint)\n ].filter(Boolean);\n };\n\n public makeSsrcFromParticipant(participant: GroupCallParticipant, type: WebRTCLineType, source?: number | GroupCallParticipantVideoSourceGroup[], endpoint?: string): Ssrc {\n return generateSsrc(type, source, endpoint);\n }\n\n public async getGroupCallParticipants(id: GroupCallId) {\n const {nextOffset, setNextOffset} = this.prepareToSavingNextOffset(id);\n\n if(nextOffset !== '') {\n await apiManager.invokeApiSingleProcess({\n method: 'phone.getGroupParticipants', \n params: {\n call: this.getGroupCallInput(id),\n ids: [],\n sources: [],\n offset: nextOffset || '',\n limit: GET_PARTICIPANTS_LIMIT\n },\n processResult: (groupCallParticipants) => {\n const newNextOffset = groupCallParticipants.count === groupCallParticipants.participants.length ? '' : groupCallParticipants.next_offset;\n \n appChatsManager.saveApiChats(groupCallParticipants.chats);\n appUsersManager.saveApiUsers(groupCallParticipants.users);\n this.saveApiParticipants(id, groupCallParticipants.participants);\n \n setNextOffset(newNextOffset);\n }\n });\n }\n\n return {\n participants: this.getCachedParticipants(id),\n isEnd: this.nextOffsets.get(id) === ''\n };\n }\n\n public async hangUp(groupCallId: GroupCallId, discard = false, rejoin = false) {\n this.log(`hangUp start id=${groupCallId} discard=${discard} rejoin=${rejoin}`);\n const {currentGroupCall} = this;\n if(currentGroupCall?.id !== groupCallId) return;\n\n currentGroupCall.hangUp(discard, rejoin);\n }\n\n public toggleMuted(muted?: boolean) {\n return this.changeUserMuted(NULL_PEER_ID, muted);\n }\n \n public changeUserMuted(peerId: PeerId, muted?: boolean) {\n const {currentGroupCall} = this;\n if(!currentGroupCall) return;\n\n const participant = currentGroupCall.getParticipantByPeerId(peerId);\n if(NULL_PEER_ID === peerId && participant.pFlags.can_self_unmute) {\n muted = muted === undefined ? !participant.pFlags.muted : muted;\n }\n\n return this.editParticipant(currentGroupCall.id, participant, {muted});\n }\n}\n\nconst appGroupCallsManager = new AppGroupCallsManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appGroupCallsManager = appGroupCallsManager);\nexport default appGroupCallsManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS } from \"../constants\";\nimport StreamManager from \"../streamManager\";\nimport getAudioConstraints from \"./getAudioConstraints\";\nimport getStream from \"./getStream\";\nimport getVideoConstraints from \"./getVideoConstraints\";\n\nexport default async function createMainStreamManager(muted?: boolean, joinVideo?: boolean) {\n const constraints: MediaStreamConstraints = {\n audio: getAudioConstraints(),\n video: joinVideo && getVideoConstraints()\n };\n\n const streamManager = new StreamManager(GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS);\n \n try {\n const stream = await getStream(constraints, muted);\n streamManager.addStream(stream, 'input');\n } catch(err) {\n console.error('joinGroupCall getStream error', err, constraints);\n streamManager.inputStream = new MediaStream();\n }\n\n return streamManager;\n}\n","export default function insertInDescendSortedArray<T extends {[smth in K]?: number}, K extends keyof T>(array: Array<T>, element: T, property: K, pos?: number) {\n const sortProperty: number = element[property];\n\n if(pos === undefined) {\n pos = array.indexOf(element);\n if(pos !== -1) {\n const prev = array[pos - 1];\n const next = array[pos + 1];\n if((!prev || prev[property] >= sortProperty) && (!next || next[property] <= sortProperty)) {\n // console.warn('same pos', pos, sortProperty, prev, next);\n return pos;\n }\n \n array.splice(pos, 1);\n }\n }\n\n const len = array.length;\n if(!len || sortProperty <= array[len - 1][property]) {\n return array.push(element) - 1;\n } else if(sortProperty >= array[0][property]) {\n array.unshift(element);\n return 0;\n } else {\n for(let i = 0; i < len; i++) {\n if(sortProperty > array[i][property]) {\n array.splice(i, 0, element);\n return i;\n }\n }\n }\n\n console.error('wtf', array, element);\n return array.indexOf(element);\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport copy from \"../../helpers/object/copy\";\r\nimport { InputMedia, Message, MessageEntity, MessageMedia, Poll, PollResults } from \"../../layer\";\r\nimport { logger, LogTypes } from \"../logger\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appMessagesIdsManager from \"./appMessagesIdsManager\";\r\nimport appMessagesManager from './appMessagesManager';\r\nimport appPeersManager from './appPeersManager';\r\nimport appUsersManager from \"./appUsersManager\";\r\n\r\nexport class AppPollsManager {\r\n public polls: {[id: string]: Poll} = {};\r\n public results: {[id: string]: PollResults} = {};\r\n public pollToMessages: {[id: string]: Set<string>} = {};\r\n\r\n private log = logger('POLLS', LogTypes.Error);\r\n\r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updateMessagePoll: (update) => {\r\n this.log('updateMessagePoll:', update);\r\n\r\n let poll: Poll = update.poll || this.polls[update.poll_id];\r\n if(!poll) {\r\n return;\r\n }\r\n\r\n let results = update.results;\r\n const ret = this.savePoll(poll, results as any);\r\n poll = ret.poll;\r\n results = ret.results;\r\n \r\n rootScope.dispatchEvent('poll_update', {poll, results: results as any});\r\n }\r\n });\r\n }\r\n\r\n public savePoll(poll: Poll, results: PollResults, message?: Message.message) {\r\n if(message) {\r\n this.updatePollToMessage(message, true);\r\n }\r\n\r\n const id = poll.id;\r\n if(this.polls[id]) {\r\n poll = Object.assign(this.polls[id], poll);\r\n results = this.saveResults(poll, results);\r\n } else {\r\n this.polls[id] = poll;\r\n\r\n poll.rQuestion = RichTextProcessor.wrapEmojiText(poll.question);\r\n poll.rReply = RichTextProcessor.wrapEmojiText('📊') + ' ' + (poll.rQuestion || 'poll');\r\n poll.chosenIndexes = [];\r\n results = this.saveResults(poll, results);\r\n }\r\n\r\n return {poll, results};\r\n }\r\n\r\n public saveResults(poll: Poll, results: PollResults) {\r\n if(this.results[poll.id]) {\r\n results = Object.assign(this.results[poll.id], results);\r\n } else {\r\n this.results[poll.id] = results;\r\n }\r\n\r\n if(!results.pFlags.min) { // ! https://core.telegram.org/constructor/pollResults - min\r\n poll.chosenIndexes.length = 0;\r\n if(results?.results?.length) {\r\n results.results.forEach((answer, idx) => {\r\n if(answer.pFlags?.chosen) {\r\n poll.chosenIndexes.push(idx);\r\n }\r\n });\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n public getPoll(pollId: string): {poll: Poll, results: PollResults} {\r\n return {\r\n poll: this.polls[pollId], \r\n results: this.results[pollId]\r\n };\r\n }\r\n\r\n public getInputMediaPoll(poll: Poll, correctAnswers?: Uint8Array[], solution?: string, solutionEntities?: MessageEntity[]): InputMedia.inputMediaPoll {\r\n if(solution) {\r\n if(!solutionEntities) {\r\n solutionEntities = [];\r\n }\r\n\r\n solution = RichTextProcessor.parseMarkdown(solution, solutionEntities);\r\n } else {\r\n solution = undefined; // can be string here\r\n }\r\n\r\n return {\r\n _: 'inputMediaPoll',\r\n poll,\r\n correct_answers: correctAnswers,\r\n solution,\r\n solution_entities: solution ? solutionEntities : undefined\r\n };\r\n }\r\n\r\n public updatePollToMessage(message: Message.message, add: boolean) {\r\n const {id} = (message.media as MessageMedia.messageMediaPoll).poll;\r\n let set = this.pollToMessages[id];\r\n \r\n if(!add && !set) {\r\n return;\r\n }\r\n\r\n if(!set) {\r\n set = this.pollToMessages[id] = new Set();\r\n }\r\n\r\n const key = message.peerId + '_' + message.mid;\r\n if(add) set.add(key);\r\n else set.delete(key);\r\n\r\n if(!add && !set.size) {\r\n delete this.polls[id];\r\n delete this.results[id];\r\n delete this.pollToMessages[id];\r\n }\r\n }\r\n\r\n public sendVote(message: any, optionIds: number[]): Promise<void> {\r\n const poll: Poll = message.media.poll;\r\n\r\n const options: Uint8Array[] = optionIds.map(index => {\r\n return poll.answers[index].option;\r\n });\r\n \r\n const messageId = message.mid;\r\n const peerId = message.peerId;\r\n const inputPeer = appPeersManager.getInputPeerById(peerId);\r\n\r\n if(message.pFlags.is_outgoing) {\r\n return appMessagesManager.invokeAfterMessageIsSent(messageId, 'sendVote', (message) => {\r\n this.log('invoke sendVote callback');\r\n return this.sendVote(message, optionIds);\r\n });\r\n }\r\n\r\n return apiManager.invokeApi('messages.sendVote', {\r\n peer: inputPeer,\r\n msg_id: appMessagesIdsManager.getServerMessageId(message.mid),\r\n options\r\n }).then(updates => {\r\n this.log('sendVote updates:', updates);\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n });\r\n }\r\n\r\n public getResults(message: any) {\r\n const inputPeer = appPeersManager.getInputPeerById(message.peerId);\r\n\r\n return apiManager.invokeApi('messages.getPollResults', {\r\n peer: inputPeer,\r\n msg_id: appMessagesIdsManager.getServerMessageId(message.mid)\r\n }).then(updates => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n this.log('getResults updates:', updates);\r\n });\r\n }\r\n\r\n public getVotes(message: any, option?: Uint8Array, offset?: string, limit = 20) {\r\n return apiManager.invokeApi('messages.getPollVotes', {\r\n peer: appPeersManager.getInputPeerById(message.peerId),\r\n id: appMessagesIdsManager.getServerMessageId(message.mid),\r\n option,\r\n offset,\r\n limit\r\n }).then((votesList) => {\r\n this.log('getPollVotes messages:', votesList);\r\n\r\n appUsersManager.saveApiUsers(votesList.users);\r\n\r\n return votesList;\r\n });\r\n }\r\n\r\n public stopPoll(message: any) {\r\n const poll: Poll = message.media.poll;\r\n \r\n if(poll.pFlags.closed) return Promise.resolve();\r\n\r\n const newPoll = copy(poll);\r\n newPoll.pFlags.closed = true;\r\n return appMessagesManager.editMessage(message, undefined, {\r\n newMedia: this.getInputMediaPoll(newPoll)\r\n }).then(() => {\r\n //console.log('stopped poll');\r\n }, err => {\r\n this.log.error('stopPoll error:', err);\r\n });\r\n }\r\n}\r\n\r\nconst appPollsManager = new AppPollsManager();\r\nMOUNT_CLASS_TO.appPollsManager = appPollsManager;\r\nexport default appPollsManager;\r\n","import simulateEvent from \"../../../helpers/dom/dispatchEvent\";\n\nexport default function stopTrack(track: MediaStreamTrack) {\n track.stop();\n simulateEvent(track, 'ended');\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport { logger } from '../logger';\nimport rootScope from '../rootScope';\nimport { GROUP_CALL_AMPLITUDE_ANALYSE_COUNT_MAX } from './constants';\nimport stopTrack from './helpers/stopTrack';\nimport LocalConferenceDescription from './localConferenceDescription';\nimport { fixMediaLineType, WebRTCLineType } from './sdpBuilder';\nimport { getAmplitude, toTelegramSource } from './utils';\n\nexport type StreamItemBase = {\n type: 'input' | 'output',\n track: MediaStreamTrack,\n source: string,\n stream: MediaStream\n};\n\nexport type StreamItem = StreamAudioItem | StreamVideoItem;\n\nexport type StreamAudioItem = StreamItemBase & {kind: 'audio', streamAnalyser: AudioStreamAnalyser};\nexport type StreamVideoItem = StreamItemBase & {kind: 'video'};\n\nexport type StreamAmplitude = {\n type: \"input\" | \"output\";\n source: string;\n stream: MediaStream;\n track: MediaStreamTrack;\n value: number;\n};\n\nclass AudioStreamAnalyser {\n public analyser: AnalyserNode;\n public gain: GainNode;\n public streamSource: MediaStreamAudioSourceNode;\n\n constructor(context: AudioContext, stream: MediaStream) {\n const streamSource = this.streamSource = context.createMediaStreamSource(stream);\n const analyser = this.analyser = context.createAnalyser();\n const gain = this.gain = context.createGain();\n // const streamDestination = context.createMediaStreamDestination();\n \n analyser.minDecibels = -100;\n analyser.maxDecibels = -30;\n analyser.smoothingTimeConstant = 0.05;\n analyser.fftSize = 1024;\n \n // connect Web Audio API\n streamSource.connect(analyser);\n // analyser.connect(context.destination);\n }\n}\n\nexport default class StreamManager {\n private context: AudioContext;\n public outputStream: MediaStream;\n public inputStream: MediaStream;\n\n private timer: number;\n private counter: number;\n\n private items: StreamItem[];\n\n private log: ReturnType<typeof logger>;\n\n public direction: RTCRtpTransceiver['direction'];\n public canCreateConferenceEntry: boolean;\n public locked: boolean;\n public types: WebRTCLineType[];\n \n constructor(private interval?: number) {\n this.context = new (window.AudioContext || (window as any).webkitAudioContext)();\n this.items = [];\n this.outputStream = new MediaStream();\n this.inputStream = new MediaStream();\n this.counter = 0;\n this.log = logger('SM');\n this.direction = 'sendonly';\n this.canCreateConferenceEntry = true;\n // this.lol = true;\n this.types = ['audio', 'video'];\n }\n\n public addStream(stream: MediaStream, type: StreamItem['type']) {\n stream.getTracks().forEach(track => {\n this.addTrack(stream, track, type);\n });\n }\n\n public addTrack(stream: MediaStream, track: MediaStreamTrack, type: StreamItem['type']) {\n this.log('addTrack', type, track, stream);\n\n const {context, items, inputStream, outputStream} = this;\n const kind: StreamItem['kind'] = track.kind as any;\n const source = StreamManager.getSource(stream, type);\n \n // this.removeTrack(track);\n switch(type) {\n case 'input': {\n if(!inputStream) {\n this.inputStream = stream;\n } else {\n inputStream.addTrack(track);\n }\n\n break;\n }\n\n case 'output': {\n for(let i = 0; i < items.length; ++i) {\n const {track: t, type, source: itemSource} = items[i];\n if(itemSource === source && type === 'input') {\n items.splice(i, 1);\n outputStream.removeTrack(t);\n break;\n }\n }\n \n if(kind !== 'video') {\n outputStream.addTrack(track);\n }\n \n break;\n }\n }\n\n this.finalizeAddingTrack({\n type,\n source,\n stream,\n track,\n kind,\n streamAnalyser: kind === 'audio' ? new AudioStreamAnalyser(context, stream) : undefined\n });\n\n if(kind === 'audio' && this.interval) {\n this.changeTimer();\n }\n }\n\n private finalizeAddingTrack(item: StreamItem) {\n const {track} = item;\n track.addEventListener('ended', () => {\n this.removeTrack(track);\n }, {once: true});\n\n this.items.push(item);\n }\n\n public hasInputTrackKind(kind: StreamItem['kind']) {\n return this.items.find(item => item.type === 'input' && item.kind === kind);\n }\n\n public static getSource(stream: MediaStream, type: StreamItem['type']) {\n return type === 'input' ? (stream.source || stream.id) : '' + toTelegramSource(+stream.id.substring(6));\n }\n \n public removeTrack(track: MediaStreamTrack) {\n this.log('removeTrack', track);\n\n const {items} = this;\n \n let handled = false;\n for(let i = 0, length = items.length; !handled && i < length; ++i) {\n const {track: t, type} = items[i];\n switch(type) {\n case 'output': {\n if(t === track) {\n items.splice(i, 1);\n this.outputStream.removeTrack(track);\n handled = true;\n }\n\n break;\n }\n\n case 'input': {\n if(t === track) {\n items.splice(i, 1);\n this.inputStream.removeTrack(track);\n handled = true;\n }\n\n break;\n }\n }\n }\n \n if(track.kind === 'audio' && this.interval) {\n this.changeTimer();\n }\n }\n \n public replaceInputAudio(stream: MediaStream, oldTrack: MediaStreamTrack) {\n this.removeTrack(oldTrack);\n this.addStream(stream, 'input');\n }\n \n private changeTimer() {\n if(this.timer !== undefined) {\n clearInterval(this.timer);\n }\n \n if(this.items.length) {\n this.timer = window.setInterval(this.analyse, this.interval);\n }\n }\n \n public getAmplitude = (item: StreamAudioItem): StreamAmplitude => {\n const {streamAnalyser, stream, track, source, type} = item;\n const analyser = streamAnalyser.analyser;\n if(!analyser) return;\n \n const array = new Uint8Array(analyser.frequencyBinCount);\n analyser.getByteFrequencyData(array);\n const value = getAmplitude(array);\n \n return {\n type,\n source,\n stream,\n track,\n value\n };\n };\n \n public analyse = () => {\n const all = this.counter % 3 === 0;\n const filteredItems = all ? this.items : this.items.filter(x => x.type === 'input');\n const audioItems = filteredItems.filter(x => x.kind === 'audio') as StreamAudioItem[];\n const amplitudes = audioItems.slice(0, GROUP_CALL_AMPLITUDE_ANALYSE_COUNT_MAX).map(this.getAmplitude);\n if(++this.counter >= 1000) {\n this.counter = 0;\n }\n \n rootScope.dispatchEvent('group_call_amplitude', {\n amplitudes,\n type: all ? 'all' : 'input'\n });\n };\n\n /* public appendToConnection(connection: RTCPeerConnection) {\n if(this.inputStream) {\n this.inputStream.getTracks().forEach(track => {\n connection.log('addTrack', track);\n connection.addTrack(track, this.inputStream);\n\n if(track.kind === 'video') {\n track.enabled = true;\n }\n });\n }\n } */\n\n public appendToConference(conference: LocalConferenceDescription) {\n if(this.locked) {\n return;\n }\n \n const {inputStream, direction, canCreateConferenceEntry} = this;\n const transceiverInit: RTCRtpTransceiverInit = {direction, streams: [inputStream]};\n const types = this.types.map(type => {\n return [\n type, \n /* type === 'video' || type === 'screencast' ? \n {sendEncodings: [{maxBitrate: 2500000}], ...transceiverInit} : */\n transceiverInit\n ] as const;\n });\n\n const tracks = inputStream.getTracks();\n // const transceivers = conference.connection.getTransceivers();\n for(const [type, transceiverInit] of types) {\n let entry = conference.findEntry(entry => entry.direction === direction && entry.type === type);\n if(!entry) {\n if(!canCreateConferenceEntry) {\n continue;\n }\n\n entry = conference.createEntry(type);\n }\n /* const entry = conference.findFreeSendRecvEntry(type, true);\n if(!entry.transceiver) {\n entry.transceiver = transceivers.find(transceiver => transceiver.mid === entry.mid);\n } */\n\n let {transceiver} = entry;\n if(!transceiver) {\n transceiver = entry.createTransceiver(conference.connection, transceiverInit);\n\n /* if(this.isScreenSharingManager) {\n transceiver.sender.setParameters({\n ...transceiver.sender.getParameters(),\n degradationPreference: 'maintain-resolution'\n });\n } */\n }\n\n if(entry.direction !== transceiver.direction) {\n transceiver.direction = entry.direction;\n }\n\n const mediaTrackType = fixMediaLineType(type);\n const trackIdx = tracks.findIndex(track => track.kind === mediaTrackType);\n const track = trackIdx !== -1 ? tracks.splice(trackIdx, 1)[0] : undefined;\n const sender = transceiver.sender;\n if(sender.track === track) {\n continue;\n }\n\n // try { // ! don't use await here. it will wait for adding track and fake one won't be visible in startNegotiation.\n /* await */sender.replaceTrack(track).catch(err => {\n this.log.error(err);\n });\n // } catch(err) {\n\n // }\n }\n }\n\n public stop() {\n try {\n const tracks = this.inputStream.getTracks().concat(this.outputStream.getTracks());\n tracks.forEach(track => {\n stopTrack(track);\n });\n } catch(e) {\n this.log.error(e);\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\n/// NOTE: telegram returns sign source, while webrtc uses unsign source internally\n/// unsign => sign\nexport function toTelegramSource(source: number) {\n\treturn source << 0;\n}\n\n/// NOTE: telegram returns sign source, while webrtc uses unsign source internally\n/// sign => unsign\nexport function fromTelegramSource(source: number) {\n\treturn source >>> 0;\n}\n\nexport function getAmplitude(array: Uint8Array, scale = 3) {\n\tif(!array) return 0;\n\n\tconst {length} = array;\n\tlet total = 0;\n\tfor(let i = 0; i < length; ++i) {\n\t\ttotal += array[i] * array[i];\n\t}\n\tconst rms = Math.sqrt(total / length) / 255;\n\n\treturn Math.min(1, rms * scale);\n}\n","export default function getObjectKeysAndSort(object: {[key: string]: any}, sort: 'asc' | 'desc' = 'asc') {\n if(!object) return [];\n const ids = object instanceof Map ? [...object.keys()] : Object.keys(object).map(i => +i);\n if(sort === 'asc') return ids.sort((a, b) => a - b);\n else return ids.sort((a, b) => b - a);\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport compareValue from \"./compareValue\";\r\n\r\n/**\r\n * Descend sorted storage\r\n */\r\n\r\ntype ItemType = number | string;\r\n\r\nexport enum SliceEnd {\r\n None = 0,\r\n Top = 1,\r\n Bottom = 2,\r\n Both = SliceEnd.Top | SliceEnd.Bottom\r\n};\r\n\r\nexport interface Slice<T extends ItemType> extends Array<T> {\r\n //slicedArray: SlicedArray;\r\n end: SliceEnd;\r\n\r\n isEnd: (side: SliceEnd) => boolean;\r\n setEnd: (side: SliceEnd) => void;\r\n unsetEnd: (side: SliceEnd) => void;\r\n\r\n slice: (from?: number, to?: number) => Slice<T>;\r\n splice: (start: number, deleteCount: number, ...items: ItemType[]) => Slice<T>;\r\n}\r\n\r\nexport interface SliceConstructor<T extends ItemType> {\r\n // new(...items: T[]): Slice<T>;\r\n new(length: number): Slice<T>;\r\n}\r\n\r\nexport default class SlicedArray<T extends ItemType> {\r\n private slices: Slice<T>[]/* = [[7,6,5],[4,3,2],[1,0,-1]] */;\r\n private sliceConstructor: SliceConstructor<T>;\r\n \r\n constructor() {\r\n // @ts-ignore\r\n this.sliceConstructor = SlicedArray.getSliceConstructor(this);\r\n\r\n const first = this.constructSlice();\r\n //first.setEnd(SliceEnd.Bottom);\r\n this.slices = [first];\r\n }\r\n\r\n private static getSliceConstructor(slicedArray: SlicedArray<ItemType>) {\r\n return class Slice<T> extends Array<ItemType> implements Slice<T> {\r\n //slicedArray: SlicedArray;\r\n end: SliceEnd = SliceEnd.None;\r\n \r\n /* constructor(...items: ItemType[]) {\r\n super(...items);\r\n //this.slicedArray = slicedArray;\r\n } */\r\n \r\n isEnd(side: SliceEnd): boolean {\r\n if((this.end & side) === side) {\r\n return true;\r\n }/* else if(!this.slicedArray) {\r\n return false;\r\n } */\r\n \r\n let isEnd = false;\r\n if(side === SliceEnd.Top) {\r\n const slice = slicedArray.last;\r\n isEnd = slice.end & side ? this.includes(slice[slice.length - 1])/* || !slice.length */ : false;\r\n } else if(side === SliceEnd.Bottom) {\r\n const slice = slicedArray.first;\r\n isEnd = slice.end & side ? this.includes(slice[0])/* || !slice.length */ : false;\r\n } else if(side === SliceEnd.Both) {\r\n return this.isEnd(SliceEnd.Top) && this.isEnd(SliceEnd.Bottom);\r\n }\r\n\r\n if(isEnd) {\r\n this.setEnd(side);\r\n }\r\n \r\n return isEnd;\r\n }\r\n \r\n setEnd(side: SliceEnd) {\r\n this.end |= side;\r\n }\r\n\r\n unsetEnd(side: SliceEnd) {\r\n this.end &= ~side;\r\n }\r\n\r\n splice(start: number, deleteCount: number, ...items: ItemType[]) {\r\n const ret = super.splice(start, deleteCount, ...items);\r\n\r\n if(!this.length) {\r\n const slices = slicedArray.slices as ItemType[][];\r\n const idx = slices.indexOf(this);\r\n if(idx !== -1) {\r\n if(slices.length === 1) { // left empty slice without ends\r\n this.unsetEnd(SliceEnd.Both);\r\n } else { // delete this slice\r\n slices.splice(idx, 1);\r\n }\r\n }\r\n }\r\n\r\n return ret;\r\n }\r\n }\r\n }\r\n\r\n public constructSlice(...items: T[]) {\r\n //const slice = new Slice(this, ...items);\r\n // can't pass items directly to constructor because first argument is length\r\n const slice = new this.sliceConstructor(items.length);\r\n for(let i = 0, length = items.length; i < length; ++i) {\r\n slice[i] = items[i];\r\n }\r\n return slice;\r\n \r\n // ! code below will slow execution in 15 times\r\n /* const self = this;\r\n const p: Slice = new Proxy(slice, {\r\n get: function(target, name: any) {\r\n if(name === 'constructor') {\r\n const p = new Proxy(Slice, {\r\n construct: (target, args) => {\r\n return self.constructSlice(...args);\r\n }\r\n });\r\n\r\n return p;\r\n }\r\n\r\n return target[name];\r\n }\r\n });\r\n\r\n return p; */\r\n\r\n /*\r\n var p = slicedArray.constructSlice();\r\n p.length = 100000;\r\n p.fill(255);\r\n\r\n var a = new Array(100000);\r\n a.fill(255);\r\n\r\n var b = 0;\r\n var perf = performance.now();\r\n for(var i = 0; i < p.length; ++i) {\r\n b += p[i];\r\n }\r\n\r\n console.log('perf 1', performance.now() - perf);\r\n\r\n b = 0;\r\n perf = performance.now();\r\n for(var i = 0; i < a.length; ++i) {\r\n b += a[i];\r\n }\r\n\r\n console.log('perf 2', performance.now() - perf);\r\n */\r\n }\r\n\r\n public insertSlice(slice: T[], flatten = true) {\r\n if(!slice.length) {\r\n return;\r\n }\r\n\r\n const first = this.slices[0];\r\n if(!first.length) {\r\n first.push(...slice);\r\n return first;\r\n }\r\n\r\n const lowerBound = slice[slice.length - 1];\r\n const upperBound = slice[0];\r\n\r\n let foundSlice: Slice<T>, lowerIndex = -1, upperIndex = -1, foundSliceIndex = 0;\r\n for(; foundSliceIndex < this.slices.length; ++foundSliceIndex) {\r\n foundSlice = this.slices[foundSliceIndex];\r\n lowerIndex = foundSlice.indexOf(lowerBound);\r\n upperIndex = foundSlice.indexOf(upperBound);\r\n \r\n if(upperIndex !== -1 && -1 !== lowerIndex) {\r\n break;\r\n } else if(upperIndex !== -1 || -1 !== lowerIndex) {\r\n break;\r\n }\r\n }\r\n\r\n if(upperIndex !== -1 && -1 !== lowerIndex) {\r\n\r\n } else if(upperIndex !== -1) { // ([1, 2, 3] | [1, 2, 3, 4, 5]) -> [1, 2, 3, 4, 5]\r\n const sliced = slice.slice(foundSlice.length - upperIndex);\r\n foundSlice.push(...sliced);\r\n } else if(lowerIndex !== -1) { // ([1, 2, 3] | [-1, 0, 1]) -> [-1, 0, 1, 2, 3]\r\n const sliced = slice.slice(0, slice.length - lowerIndex - 1);\r\n foundSlice.unshift(...sliced);\r\n } else {\r\n let insertIndex = 0;\r\n for(const length = this.slices.length; insertIndex < length; ++insertIndex) { // * maybe should iterate from the end, could be faster ?\r\n const s = this.slices[insertIndex];\r\n if(compareValue(slice[0], s[0]) === 1) {\r\n break;\r\n }\r\n }\r\n\r\n this.slices.splice(insertIndex, 0, this.constructSlice(...slice));\r\n foundSliceIndex = insertIndex;\r\n }\r\n\r\n if(flatten) {\r\n return this.flatten(foundSliceIndex);\r\n }\r\n }\r\n\r\n private flatten(foundSliceIndex: number) {\r\n if(this.slices.length >= 2) {\r\n for(let i = 0, length = this.slices.length; i < (length - 1); ++i) {\r\n const prevSlice = this.slices[i];\r\n const nextSlice = this.slices[i + 1];\r\n \r\n const upperIndex = prevSlice.indexOf(nextSlice[0]);\r\n if(upperIndex !== -1) {\r\n prevSlice.setEnd(nextSlice.end);\r\n this.slices.splice(i + 1, 1);\r\n\r\n if(i < foundSliceIndex) {\r\n --foundSliceIndex;\r\n }\r\n\r\n --length; // respect array bounds\r\n --i; // repeat from the same place\r\n \r\n this.insertSlice(nextSlice, false);\r\n }\r\n }\r\n }\r\n\r\n return this.slices[foundSliceIndex];\r\n }\r\n\r\n // * \r\n \r\n get first() {\r\n return this.slices[0];\r\n }\r\n \r\n get last() {\r\n return this.slices[this.slices.length - 1];\r\n }\r\n\r\n get slice() {\r\n return this.first;\r\n }\r\n\r\n get length() {\r\n return this.slice.length;\r\n }\r\n\r\n public findSlice(item: T) {\r\n for(let i = 0, length = this.slices.length; i < length; ++i) {\r\n const slice = this.slices[i];\r\n const index = slice.indexOf(item);\r\n if(index !== -1) {\r\n return {slice, index};\r\n }\r\n }\r\n \r\n return undefined;\r\n }\r\n\r\n public findSliceOffset(maxId: T) {\r\n let slice: Slice<T>;\r\n for(let i = 0; i < this.slices.length; ++i) {\r\n let offset = 0;\r\n slice = this.slices[i];\r\n if(slice.length < 2) {\r\n continue;\r\n }\r\n \r\n for(; offset < slice.length; ++offset) {\r\n if(compareValue(maxId, slice[offset]) >= 0) {\r\n /* if(!offset) { // because can't find 3 in [[5,4], [2,1]]\r\n return undefined;\r\n } */\r\n\r\n return {\r\n slice, \r\n offset: maxId === slice[offset] ? offset : offset - 1\r\n };\r\n }\r\n }\r\n }\r\n\r\n if(slice && slice.isEnd(SliceEnd.Top)) {\r\n return {\r\n slice,\r\n offset: slice.length\r\n };\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n // * https://core.telegram.org/api/offsets\r\n public sliceMe(offsetId: T, add_offset: number, limit: number) {\r\n let slice = this.slice;\r\n let offset = 0;\r\n let sliceOffset = 0;\r\n\r\n if(offsetId) {\r\n const pos = this.findSliceOffset(offsetId);\r\n if(!pos) {\r\n return undefined;\r\n }\r\n\r\n slice = pos.slice;\r\n offset = sliceOffset = pos.offset;\r\n\r\n if(slice.includes(offsetId)) {\r\n sliceOffset += 1;\r\n }\r\n\r\n /* if(slice.includes(offsetId) && add_offset < 0) {\r\n add_offset += 1;\r\n } */\r\n }\r\n\r\n let sliceStart = Math.max(sliceOffset + add_offset, 0);\r\n let sliceEnd = sliceOffset + add_offset + limit;\r\n //const fixHalfBackLimit = add_offset && !(limit / add_offset % 2) && (sliceEnd % 2) ? 1 : 0;\r\n //sliceEnd += fixHalfBackLimit;\r\n\r\n const sliced = slice.slice(sliceStart, sliceEnd) as Slice<T>;\r\n\r\n const topWasMeantToLoad = add_offset < 0 ? limit + add_offset : limit;\r\n const bottomWasMeantToLoad = Math.abs(add_offset);\r\n\r\n // can use 'slice' here to check because if it's end, then 'sliced' is out of 'slice'\r\n // useful when there is only 1 message in chat on its reopening\r\n const topFulfilled = (slice.length - sliceOffset) >= topWasMeantToLoad || (slice.isEnd(SliceEnd.Top) ? (sliced.setEnd(SliceEnd.Top), true) : false);\r\n const bottomFulfilled = (sliceOffset - bottomWasMeantToLoad) >= 0 || (slice.isEnd(SliceEnd.Bottom) ? (sliced.setEnd(SliceEnd.Bottom), true) : false);\r\n\r\n //console.log('sliceMe', topFulfilled, bottomFulfilled);\r\n\r\n return {\r\n slice: sliced, \r\n offsetIdOffset: offset,\r\n fulfilled: SliceEnd.None | (topFulfilled && bottomFulfilled ? SliceEnd.Both : ((topFulfilled ? SliceEnd.Top : SliceEnd.None) | (bottomFulfilled ? SliceEnd.Bottom : SliceEnd.None)))\r\n };\r\n }\r\n\r\n public unshift(...items: T[]) {\r\n let slice = this.first;\r\n if(!slice.length) {\r\n slice.setEnd(SliceEnd.Bottom);\r\n } else if(!slice.isEnd(SliceEnd.Bottom)) {\r\n slice = this.constructSlice();\r\n slice.setEnd(SliceEnd.Bottom);\r\n this.slices.unshift(slice);\r\n }\r\n\r\n slice.unshift(...items);\r\n }\r\n\r\n public push(...items: T[]) {\r\n let slice = this.last;\r\n if(!slice.length) {\r\n slice.setEnd(SliceEnd.Top);\r\n } else if(!slice.isEnd(SliceEnd.Top)) {\r\n slice = this.constructSlice();\r\n slice.setEnd(SliceEnd.Top);\r\n this.slices.push(slice);\r\n }\r\n\r\n slice.push(...items);\r\n }\r\n\r\n public delete(item: T) {\r\n const found = this.findSlice(item);\r\n if(found) {\r\n found.slice.splice(found.index, 1);\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n}\r\n\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.SlicedArray = SlicedArray);\r\n","import compareLong from \"./long/compareLong\";\n\nexport default function compareValue(val1: string | number, val2: typeof val1) {\n if((val1 as number).toExponential) {\n const diff = (val1 as number) - (val2 as number);\n return diff < 0 ? -1 : (diff > 0 ? 1 : 0);\n }\n\n return compareLong(val1 as string, val2 as string);\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport default function compareLong(str1: string, str2: string) {\n const str1Length = str1.length;\n if(str1Length !== str2.length) {\n const diff = str1Length - str2.length;\n return diff < 0 ? -1 : (diff > 0 ? 1 : 0);\n }\n\n const maxPartLength = 15;\n for(let i = 0; i < str1Length; i += maxPartLength) {\n const v1 = +str1.slice(i, i + maxPartLength);\n const v2 = +str2.slice(i, i + maxPartLength);\n const diff = v1 - v2;\n if(diff) {\n return diff;\n }\n }\n\n return 0;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\n// From https://raw.githubusercontent.com/FGRibreau/latenize/master/latinize_map.js\nconst LatinizeMap: {[k: string]: string} = {'Á': 'A','Ă': 'A','Ắ': 'A','Ặ': 'A','Ằ': 'A','Ẳ': 'A','Ẵ': 'A','Ǎ': 'A','Â': 'A','Ấ': 'A','Ậ': 'A','Ầ': 'A','Ẩ': 'A','Ẫ': 'A','Ä': 'A','Ǟ': 'A','Ȧ': 'A','Ǡ': 'A','Ạ': 'A','Ȁ': 'A','À': 'A','Ả': 'A','Ȃ': 'A','Ā': 'A','Ą': 'A','Å': 'A','Ǻ': 'A','Ḁ': 'A','Ⱥ': 'A','Ã': 'A','Ꜳ': 'AA','Æ': 'AE','Ǽ': 'AE','Ǣ': 'AE','Ꜵ': 'AO','Ꜷ': 'AU','Ꜹ': 'AV','Ꜻ': 'AV','Ꜽ': 'AY','Ḃ': 'B','Ḅ': 'B','Ɓ': 'B','Ḇ': 'B','Ƀ': 'B','Ƃ': 'B','Ć': 'C','Č': 'C','Ç': 'C','Ḉ': 'C','Ĉ': 'C','Ċ': 'C','Ƈ': 'C','Ȼ': 'C','Ď': 'D','Ḑ': 'D','Ḓ': 'D','Ḋ': 'D','Ḍ': 'D','Ɗ': 'D','Ḏ': 'D','Dz': 'D','Dž': 'D','Đ': 'D','Ƌ': 'D','DZ': 'DZ','DŽ': 'DZ','É': 'E','Ĕ': 'E','Ě': 'E','Ȩ': 'E','Ḝ': 'E','Ê': 'E','Ế': 'E','Ệ': 'E','Ề': 'E','Ể': 'E','Ễ': 'E','Ḙ': 'E','Ë': 'E','Ė': 'E','Ẹ': 'E','Ȅ': 'E','È': 'E','Ẻ': 'E','Ȇ': 'E','Ē': 'E','Ḗ': 'E','Ḕ': 'E','Ę': 'E','Ɇ': 'E','Ẽ': 'E','Ḛ': 'E','': 'ET','Ḟ': 'F','Ƒ': 'F','Ǵ': 'G','Ğ': 'G','Ǧ': 'G','Ģ': 'G','Ĝ': 'G','Ġ': 'G','Ɠ': 'G','Ḡ': 'G','Ǥ': 'G','Ḫ': 'H','Ȟ': 'H','Ḩ': 'H','Ĥ': 'H','Ⱨ': 'H','Ḧ': 'H','Ḣ': 'H','Ḥ': 'H','Ħ': 'H','Í': 'I','Ĭ': 'I','Ǐ': 'I','Î': 'I','Ï': 'I','Ḯ': 'I','İ': 'I','Ị': 'I','Ȉ': 'I','Ì': 'I','Ỉ': 'I','Ȋ': 'I','Ī': 'I','Į': 'I','Ɨ': 'I','Ĩ': 'I','Ḭ': 'I','Ꝺ': 'D','Ꝼ': 'F','Ᵹ': 'G','Ꞃ': 'R','Ꞅ': 'S','Ꞇ': 'T','Ꝭ': 'IS','Ĵ': 'J','Ɉ': 'J','Ḱ': 'K','Ǩ': 'K','Ķ': 'K','Ⱪ': 'K','Ꝃ': 'K','Ḳ': 'K','Ƙ': 'K','Ḵ': 'K','Ꝁ': 'K','Ꝅ': 'K','Ĺ': 'L','Ƚ': 'L','Ľ': 'L','Ļ': 'L','Ḽ': 'L','Ḷ': 'L','Ḹ': 'L','Ⱡ': 'L','Ꝉ': 'L','Ḻ': 'L','Ŀ': 'L','Ɫ': 'L','Lj': 'L','Ł': 'L','LJ': 'LJ','Ḿ': 'M','Ṁ': 'M','Ṃ': 'M','Ɱ': 'M','Ń': 'N','Ň': 'N','Ņ': 'N','Ṋ': 'N','Ṅ': 'N','Ṇ': 'N','Ǹ': 'N','Ɲ': 'N','Ṉ': 'N','Ƞ': 'N','Nj': 'N','Ñ': 'N','NJ': 'NJ','Ó': 'O','Ŏ': 'O','Ǒ': 'O','Ô': 'O','Ố': 'O','Ộ': 'O','Ồ': 'O','Ổ': 'O','Ỗ': 'O','Ö': 'O','Ȫ': 'O','Ȯ': 'O','Ȱ': 'O','Ọ': 'O','Ő': 'O','Ȍ': 'O','Ò': 'O','Ỏ': 'O','Ơ': 'O','Ớ': 'O','Ợ': 'O','Ờ': 'O','Ở': 'O','Ỡ': 'O','Ȏ': 'O','Ꝋ': 'O','Ꝍ': 'O','Ō': 'O','Ṓ': 'O','Ṑ': 'O','Ɵ': 'O','Ǫ': 'O','Ǭ': 'O','Ø': 'O','Ǿ': 'O','Õ': 'O','Ṍ': 'O','Ṏ': 'O','Ȭ': 'O','Ƣ': 'OI','Ꝏ': 'OO','Ɛ': 'E','Ɔ': 'O','Ȣ': 'OU','Ṕ': 'P','Ṗ': 'P','Ꝓ': 'P','Ƥ': 'P','Ꝕ': 'P','Ᵽ': 'P','Ꝑ': 'P','Ꝙ': 'Q','Ꝗ': 'Q','Ŕ': 'R','Ř': 'R','Ŗ': 'R','Ṙ': 'R','Ṛ': 'R','Ṝ': 'R','Ȑ': 'R','Ȓ': 'R','Ṟ': 'R','Ɍ': 'R','Ɽ': 'R','Ꜿ': 'C','Ǝ': 'E','Ś': 'S','Ṥ': 'S','Š': 'S','Ṧ': 'S','Ş': 'S','Ŝ': 'S','Ș': 'S','Ṡ': 'S','Ṣ': 'S','Ṩ': 'S','ẞ': 'SS','Ť': 'T','Ţ': 'T','Ṱ': 'T','Ț': 'T','Ⱦ': 'T','Ṫ': 'T','Ṭ': 'T','Ƭ': 'T','Ṯ': 'T','Ʈ': 'T','Ŧ': 'T','Ɐ': 'A','Ꞁ': 'L','Ɯ': 'M','Ʌ': 'V','Ꜩ': 'TZ','Ú': 'U','Ŭ': 'U','Ǔ': 'U','Û': 'U','Ṷ': 'U','Ü': 'U','Ǘ': 'U','Ǚ': 'U','Ǜ': 'U','Ǖ': 'U','Ṳ': 'U','Ụ': 'U','Ű': 'U','Ȕ': 'U','Ù': 'U','Ủ': 'U','Ư': 'U','Ứ': 'U','Ự': 'U','Ừ': 'U','Ử': 'U','Ữ': 'U','Ȗ': 'U','Ū': 'U','Ṻ': 'U','Ų': 'U','Ů': 'U','Ũ': 'U','Ṹ': 'U','Ṵ': 'U','Ꝟ': 'V','Ṿ': 'V','Ʋ': 'V','Ṽ': 'V','Ꝡ': 'VY','Ẃ': 'W','Ŵ': 'W','Ẅ': 'W','Ẇ': 'W','Ẉ': 'W','Ẁ': 'W','Ⱳ': 'W','Ẍ': 'X','Ẋ': 'X','Ý': 'Y','Ŷ': 'Y','Ÿ': 'Y','Ẏ': 'Y','Ỵ': 'Y','Ỳ': 'Y','Ƴ': 'Y','Ỷ': 'Y','Ỿ': 'Y','Ȳ': 'Y','Ɏ': 'Y','Ỹ': 'Y','Ź': 'Z','Ž': 'Z','Ẑ': 'Z','Ⱬ': 'Z','Ż': 'Z','Ẓ': 'Z','Ȥ': 'Z','Ẕ': 'Z','Ƶ': 'Z','IJ': 'IJ','Œ': 'OE','ᴀ': 'A','ᴁ': 'AE','ʙ': 'B','ᴃ': 'B','': 'C','ᴅ': 'D','ᴇ': 'E','ꜰ': 'F','ɢ': 'G','ʛ': 'G','ʜ': 'H','ɪ': 'I','ʁ': 'R','ᴊ': 'J','ᴋ': 'K','ʟ': 'L','ᴌ': 'L','ᴍ': 'M','ɴ': 'N','': 'O','ɶ': 'OE','ᴐ': 'O','ᴕ': 'OU','ᴘ': 'P','ʀ': 'R','ᴎ': 'N','ᴙ': 'R','': 'S','ᴛ': 'T','ⱻ': 'E','ᴚ': 'R','': 'U','': 'V','': 'W','ʏ': 'Y','': 'Z','á': 'a','ă': 'a','ắ': 'a','ặ': 'a','ằ': 'a','ẳ': 'a','ẵ': 'a','ǎ': 'a','â': 'a','ấ': 'a','ậ': 'a','ầ': 'a','ẩ': 'a','ẫ': 'a','ä': 'a','ǟ': 'a','ȧ': 'a','ǡ': 'a','ạ': 'a','ȁ': 'a','à': 'a','ả': 'a','ȃ': 'a','ā': 'a','ą': 'a','ᶏ': 'a','ẚ': 'a','å': 'a','ǻ': 'a','ḁ': 'a','ⱥ': 'a','ã': 'a','ꜳ': 'aa','æ': 'ae','ǽ': 'ae','ǣ': 'ae','ꜵ': 'ao','ꜷ': 'au','ꜹ': 'av','ꜻ': 'av','ꜽ': 'ay','ḃ': 'b','ḅ': 'b','ɓ': 'b','ḇ': 'b','ᵬ': 'b','ᶀ': 'b','ƀ': 'b','ƃ': 'b','ɵ': 'o','ć': 'c','č': 'c','ç': 'c','ḉ': 'c','ĉ': 'c','ɕ': 'c','ċ': 'c','ƈ': 'c','ȼ': 'c','ď': 'd','ḑ': 'd','ḓ': 'd','ȡ': 'd','ḋ': 'd','ḍ': 'd','ɗ': 'd','ᶑ': 'd','ḏ': 'd','ᵭ': 'd','ᶁ': 'd','đ': 'd','ɖ': 'd','ƌ': 'd','ı': 'i','ȷ': 'j','ɟ': 'j','ʄ': 'j','dz': 'dz','dž': 'dz','é': 'e','ĕ': 'e','ě': 'e','ȩ': 'e','ḝ': 'e','ê': 'e','ế': 'e','ệ': 'e','ề': 'e','ể': 'e','ễ': 'e','ḙ': 'e','ë': 'e','ė': 'e','ẹ': 'e','ȅ': 'e','è': 'e','ẻ': 'e','ȇ': 'e','ē': 'e','ḗ': 'e','ḕ': 'e','ⱸ': 'e','ę': 'e','ᶒ': 'e','ɇ': 'e','ẽ': 'e','ḛ': 'e','ꝫ': 'et','ḟ': 'f','ƒ': 'f','ᵮ': 'f','ᶂ': 'f','ǵ': 'g','ğ': 'g','ǧ': 'g','ģ': 'g','ĝ': 'g','ġ': 'g','ɠ': 'g','ḡ': 'g','': 'g','ǥ': 'g','ḫ': 'h','ȟ': 'h','ḩ': 'h','ĥ': 'h','ⱨ': 'h','ḧ': 'h','ḣ': 'h','ḥ': 'h','ɦ': 'h','ẖ': 'h','ħ': 'h','ƕ': 'hv','í': 'i','ĭ': 'i','ǐ': 'i','î': 'i','ï': 'i','ḯ': 'i','ị': 'i','ȉ': 'i','ì': 'i','ỉ': 'i','ȋ': 'i','ī': 'i','į': 'i','ᶖ': 'i','ɨ': 'i','ĩ': 'i','ḭ': 'i','ꝺ': 'd','ꝼ': 'f','ᵹ': 'g','ꞃ': 'r','ꞅ': 's','ꞇ': 't','ꝭ': 'is','ǰ': 'j','ĵ': 'j','ʝ': 'j','ɉ': 'j','ḱ': 'k','ǩ': 'k','ķ': 'k','ⱪ': 'k','ꝃ': 'k','ḳ': 'k','ƙ': 'k','ḵ': 'k','ᶄ': 'k','ꝁ': 'k','ꝅ': 'k','ĺ': 'l','ƚ': 'l','ɬ': 'l','ľ': 'l','ļ': 'l','ḽ': 'l','ȴ': 'l','ḷ': 'l','ḹ': 'l','ⱡ': 'l','ꝉ': 'l','ḻ': 'l','ŀ': 'l','ɫ': 'l','ᶅ': 'l','ɭ': 'l','ł': 'l','lj': 'lj','ſ': 's','ẜ': 's','ẛ': 's','': 's','ḿ': 'm','ṁ': 'm','ṃ': 'm','ɱ': 'm','ᵯ': 'm','ᶆ': 'm','ń': 'n','ň': 'n','ņ': 'n','ṋ': 'n','ȵ': 'n','ṅ': 'n','ṇ': 'n','ǹ': 'n','ɲ': 'n','ṉ': 'n','ƞ': 'n','ᵰ': 'n','ᶇ': 'n','ɳ': 'n','ñ': 'n','nj': 'nj','ó': 'o','ŏ': 'o','ǒ': 'o','ô': 'o','ố': 'o','ộ': 'o','ồ': 'o','ổ': 'o','ỗ': 'o','ö': 'o','ȫ': 'o','ȯ': 'o','ȱ': 'o','ọ': 'o','ő': 'o','ȍ': 'o','ò': 'o','ỏ': 'o','ơ': 'o','ớ': 'o','ợ': 'o','ờ': 'o','ở': 'o','ỡ': 'o','ȏ': 'o','ꝋ': 'o','ꝍ': 'o','ⱺ': 'o','ō': 'o','ṓ': 'o','ṑ': 'o','ǫ': 'o','ǭ': 'o','ø': 'o','ǿ': 'o','õ': 'o','ṍ': 'o','ṏ': 'o','ȭ': 'o','ƣ': 'oi','ꝏ': 'oo','ɛ': 'e','ᶓ': 'e','ɔ': 'o','ᶗ': 'o','ȣ': 'ou','ṕ': 'p','ṗ': 'p','ꝓ': 'p','ƥ': 'p','ᵱ': 'p','ᶈ': 'p','ꝕ': 'p','ᵽ': 'p','ꝑ': 'p','ꝙ': 'q','ʠ': 'q','ɋ': 'q','ꝗ': 'q','ŕ': 'r','ř': 'r','ŗ': 'r','ṙ': 'r','ṛ': 'r','ṝ': 'r','ȑ': 'r','ɾ': 'r','ᵳ': 'r','ȓ': 'r','ṟ': 'r','ɼ': 'r','ᵲ': 'r','ᶉ': 'r','ɍ': 'r','ɽ': 'r','ↄ': 'c','ꜿ': 'c','ɘ': 'e','ɿ': 'r','ś': 's','ṥ': 's','š': 's','ṧ': 's','ş': 's','ŝ': 's','ș': 's','ṡ': 's','ṣ': 's','ṩ': 's','ʂ': 's','ᵴ': 's','ᶊ': 's','ȿ': 's','ɡ': 'g','ß': 'ss','': 'o','ᴓ': 'o','ᴝ': 'u','ť': 't','ţ': 't','ṱ': 't','ț': 't','ȶ': 't','ẗ': 't','ⱦ': 't','ṫ': 't','ṭ': 't','ƭ': 't','ṯ': 't','ᵵ': 't','ƫ': 't','ʈ': 't','ŧ': 't','ᵺ': 'th','ɐ': 'a','ᴂ': 'ae','ǝ': 'e','ᵷ': 'g','ɥ': 'h','ʮ': 'h','ʯ': 'h','ᴉ': 'i','ʞ': 'k','ꞁ': 'l','ɯ': 'm','ɰ': 'm','ᴔ': 'oe','ɹ': 'r','ɻ': 'r','ɺ': 'r','ⱹ': 'r','ʇ': 't','ʌ': 'v','ʍ': 'w','ʎ': 'y','ꜩ': 'tz','ú': 'u','ŭ': 'u','ǔ': 'u','û': 'u','ṷ': 'u','ü': 'u','ǘ': 'u','ǚ': 'u','ǜ': 'u','ǖ': 'u','ṳ': 'u','ụ': 'u','ű': 'u','ȕ': 'u','ù': 'u','ủ': 'u','ư': 'u','ứ': 'u','ự': 'u','ừ': 'u','ử': 'u','ữ': 'u','ȗ': 'u','ū': 'u','ṻ': 'u','ų': 'u','ᶙ': 'u','ů': 'u','ũ': 'u','ṹ': 'u','ṵ': 'u','ᵫ': 'ue','': 'um','ⱴ': 'v','ꝟ': 'v','ṿ': 'v','ʋ': 'v','': 'v','ⱱ': 'v','ṽ': 'v','ꝡ': 'vy','ẃ': 'w','ŵ': 'w','ẅ': 'w','ẇ': 'w','ẉ': 'w','ẁ': 'w','ⱳ': 'w','ẘ': 'w','ẍ': 'x','ẋ': 'x','ᶍ': 'x','ý': 'y','ŷ': 'y','ÿ': 'y','ẏ': 'y','ỵ': 'y','ỳ': 'y','ƴ': 'y','ỷ': 'y','ỿ': 'y','ȳ': 'y','ẙ': 'y','ɏ': 'y','ỹ': 'y','ź': 'z','ž': 'z','ẑ': 'z','ʑ': 'z','ⱬ': 'z','ż': 'z','ẓ': 'z','ȥ': 'z','ẕ': 'z','ᵶ': 'z','ᶎ': 'z','ʐ': 'z','ƶ': 'z','ɀ': 'z','ff': 'ff','ffi': 'ffi','ffl': 'ffl','fi': 'fi','fl': 'fl','ij': 'ij','œ': 'oe','st': 'st','ₐ': 'a','ₑ': 'e','ᵢ': 'i','ⱼ': 'j','ₒ': 'o','ᵣ': 'r','ᵤ': 'u','ᵥ': 'v','ₓ': 'x','Ё': 'YO', 'Й': 'I', 'Ц': 'TS', 'У': 'U', 'К': 'K', 'Е': 'E', 'Н': 'N', 'Г': 'G', 'Ш': 'SH', 'Щ': 'SCH', 'З': 'Z', 'Х': 'H', 'Ъ': '', 'ё': 'yo', 'й': 'i', 'ц': 'ts', 'у': 'u', 'к': 'k', 'е': 'e', 'н': 'n', 'г': 'g', 'ш': 'sh', 'щ': 'sch', 'з': 'z', 'х': 'h', 'ъ': '', 'Ф': 'F', 'Ы': 'I', 'В': 'V', 'А': 'A', 'П': 'P', 'Р': 'R', 'О': 'O', 'Л': 'L', 'Д': 'D', 'Ж': 'ZH', 'Э': 'E', 'ф': 'f', 'ы': 'i', 'в': 'v', 'а': 'a', 'п': 'p', 'р': 'r', 'о': 'o', 'л': 'l', 'д': 'd', 'ж': 'zh', 'э': 'e', 'Я': 'Ya', 'Ч': 'CH', 'С': 'S', 'М': 'M', 'И': 'I', 'Т': 'T', 'Ь': '', 'Б': 'B', 'Ю': 'YU', 'я': 'ya', 'ч': 'ch', 'с': 's', 'м': 'm', 'и': 'i', 'т': 't', 'ь': '', 'б': 'b', 'ю': 'yu'};\n\nexport default LatinizeMap;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/zhukov/webogram\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\n * https://github.com/zhukov/webogram/blob/master/LICENSE\n */\n\nimport LatinizeMap from \"../config/latinizeMap\";\n\nconst badCharsRe = /[`~!@#$%^&*()\\-_=+\\[\\]\\\\|{}'\";:\\/?.>,<]+/g;\nconst trimRe = /^\\s+|\\s$/g;\n\nexport function clearBadCharsAndTrim(text: string) {\n return text.replace(badCharsRe, '').replace(trimRe, '');\n}\n\nexport function latinizeString(text: string) {\n return text.replace(/[^A-Za-z0-9]/g, (ch) => {\n const latinizeCh = LatinizeMap[ch];\n return latinizeCh !== undefined ? latinizeCh : ch;\n });\n}\n\nexport default function cleanSearchText(text: string, latinize = true) {\n const hasTag = text.charAt(0) === '%';\n text = clearBadCharsAndTrim(text);\n if(latinize) text = latinizeString(text);\n \n text = text.toLowerCase();\n if(hasTag) text = '%' + text;\n\n return text;\n}\n\nexport type ProcessSearchTextOptions = Partial<{\n clearBadChars: boolean,\n latinize: boolean,\n ignoreCase: boolean,\n includeTag: boolean\n}>;\n\nexport function processSearchText(text: string, options: ProcessSearchTextOptions = {}) {\n const hasTag = options.includeTag && text.charAt(0) === '%';\n if(options.clearBadChars) text = clearBadCharsAndTrim(text);\n if(options.latinize) text = latinizeString(text);\n if(options.ignoreCase) text = text.toLowerCase();\n if(hasTag) text = '%' + text;\n return text;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { CancellablePromise, deferredPromise } from \"./cancellablePromise\";\r\nimport { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\r\nimport { fastRaf } from \"./schedulers\";\r\n\r\ntype HeavyQueue<T> = {\r\n items: any[], \r\n process: (...args: any[]) => T,\r\n context: any,\r\n promise?: CancellablePromise<ReturnType<HeavyQueue<T>['process']>[]>\r\n};\r\nconst heavyQueue: HeavyQueue<any>[] = [];\r\nlet processingQueue = false;\r\n\r\nexport default function addHeavyTask<T>(queue: HeavyQueue<T>, method: 'push' | 'unshift' = 'push') {\r\n if(!queue.items.length) {\r\n return Promise.resolve([]);\r\n }\r\n \r\n queue.promise = deferredPromise<T[]>();\r\n heavyQueue[method](queue);\r\n processHeavyQueue();\r\n\r\n return queue.promise;\r\n}\r\n\r\nfunction processHeavyQueue() {\r\n if(!processingQueue) {\r\n const queue = heavyQueue.shift();\r\n timedChunk(queue).finally(() => {\r\n processingQueue = false;\r\n if(heavyQueue.length) {\r\n processHeavyQueue();\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction timedChunk<T>(queue: HeavyQueue<T>) {\r\n if(!queue.items.length) {\r\n queue.promise.resolve([]);\r\n return Promise.resolve([]);\r\n }\r\n\r\n const todo = queue.items.slice();\r\n const results: T[] = [];\r\n\r\n return new Promise<T[]>((resolve, reject) => {\r\n const f = async() => {\r\n const start = performance.now();\r\n\r\n do {\r\n await getHeavyAnimationPromise();\r\n const possiblePromise = queue.process.apply(queue.context, todo.shift());\r\n let realResult: T;\r\n if(possiblePromise instanceof Promise) {\r\n try {\r\n realResult = await possiblePromise;\r\n } catch(err) {\r\n reject(err);\r\n return;\r\n }\r\n } else {\r\n realResult = possiblePromise;\r\n }\r\n\r\n results.push(realResult);\r\n } while(todo.length > 0 && (performance.now() - start) < 6);\r\n\r\n if(todo.length > 0) {\r\n fastRaf(f);\r\n //setTimeout(f, 25);\r\n } else {\r\n resolve(results);\r\n }\r\n };\r\n\r\n fastRaf(f);\r\n //setTimeout(f, 25);\r\n }).then(queue.promise.resolve, queue.promise.reject);\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type fastBlur from '../vendor/fastBlur';\r\nimport addHeavyTask from './heavyQueue';\r\n\r\nconst RADIUS = 2;\r\nconst ITERATIONS = 2;\r\n\r\nconst isFilterAvailable = 'filter' in (document.createElement('canvas').getContext('2d') || {});\r\nlet requireBlurPromise: Promise<any>;\r\nlet fastBlurFunc: typeof fastBlur;\r\nif(!isFilterAvailable) {\r\n requireBlurPromise = import('../vendor/fastBlur').then(m => {\r\n fastBlurFunc = m.default;\r\n });\r\n} else {\r\n requireBlurPromise = Promise.resolve();\r\n}\r\n\r\nfunction processBlurNext(img: HTMLImageElement, radius: number, iterations: number) {\r\n return new Promise<string>((resolve) => {\r\n const canvas = document.createElement('canvas');\r\n canvas.width = img.width;\r\n canvas.height = img.height;\r\n \r\n const ctx = canvas.getContext('2d', {alpha: false});\r\n if(isFilterAvailable) {\r\n ctx.filter = `blur(${radius}px)`;\r\n ctx.drawImage(img, -radius * 2, -radius * 2, canvas.width + radius * 4, canvas.height + radius * 4);\r\n } else {\r\n ctx.drawImage(img, 0, 0);\r\n fastBlurFunc(ctx, 0, 0, canvas.width, canvas.height, radius, iterations);\r\n }\r\n \r\n resolve(canvas.toDataURL());\r\n /* if(DEBUG) {\r\n console.log(`[blur] end, radius: ${radius}, iterations: ${iterations}, time: ${performance.now() - perf}`);\r\n } */\r\n\r\n /* canvas.toBlob(blob => {\r\n resolve(URL.createObjectURL(blob));\r\n \r\n if(DEBUG) {\r\n console.log(`[blur] end, radius: ${radius}, iterations: ${iterations}, time: ${performance.now() - perf}`);\r\n }\r\n }); */\r\n });\r\n}\r\n\r\nconst blurPromises: Map<string, Promise<string>> = new Map();\r\nconst CACHE_SIZE = 1000;\r\n\r\nexport default function blur(dataUri: string, radius: number = RADIUS, iterations: number = ITERATIONS) {\r\n if(!dataUri) {\r\n console.error('no dataUri for blur', dataUri);\r\n return Promise.resolve(dataUri);\r\n }\r\n\r\n if(blurPromises.size > CACHE_SIZE) {\r\n blurPromises.clear();\r\n }\r\n \r\n if(blurPromises.has(dataUri)) return blurPromises.get(dataUri);\r\n const promise = new Promise<string>((resolve) => {\r\n //return resolve(dataUri);\r\n requireBlurPromise.then(() => {\r\n const img = new Image();\r\n img.onload = () => {\r\n if(isFilterAvailable) {\r\n processBlurNext(img, radius, iterations).then(resolve);\r\n } else {\r\n addHeavyTask({\r\n items: [[img, radius, iterations]],\r\n context: null,\r\n process: processBlurNext\r\n }, 'unshift').then(results => {\r\n resolve(results[0]);\r\n });\r\n }\r\n };\r\n img.src = dataUri;\r\n\r\n /* addHeavyTask({\r\n items: [[dataUri, radius, iterations]],\r\n context: null,\r\n process: processBlur\r\n }, 'unshift').then(results => {\r\n resolve(results[0]);\r\n }); */\r\n });\r\n });\r\n\r\n blurPromises.set(dataUri, promise);\r\n\r\n return promise;\r\n}\r\n","export default function numberThousandSplitter(x: number, joiner = ' ') {\n const parts = x.toString().split(\".\");\n parts[0] = parts[0].replace(/\\B(?=(\\d{3})+(?!\\d))/g, joiner);\n return parts.join(\".\");\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function htmlToDocumentFragment(html: string) {\r\n var template = document.createElement('template');\r\n html = html.trim(); // Never return a text node of whitespace as the result\r\n template.innerHTML = html;\r\n return template.content;\r\n}\r\n","export default async function getStream(constraints: MediaStreamConstraints, muted: boolean) {\n // console.log('getStream', constraints);\n \n\tconst stream = await navigator.mediaDevices.getUserMedia(constraints);\n\tstream.getTracks().forEach(x => {\n\t\t/* x.onmute = x => {\n\t\t\tconsole.log('track.onmute', x);\n\t\t};\n\t\tx.onunmute = x => {\n\t\t\tconsole.log('track.onunmute', x);\n\t\t}; */\n\n\t\tx.enabled = !muted;\n\t});\n\n\t// console.log('getStream result', stream);\n\treturn stream;\n}\n\n(window as any).getStream = getStream;\n","export default function getVideoConstraints(): MediaTrackConstraints {\n return {\n width: {min: 1280, max: 1920/* , ideal: 1920 */},\n height: {min: 720, max: 1080/* , ideal: 1080 */},\n frameRate: {min: 24, max: 30}\n };\n}\n","export const GROUP_CALL_AMPLITUDE_ANALYSE_COUNT_MAX = 50;\nexport const GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS = 100;\nexport const GROUP_CALL_PARTICIPANTS_LOAD_LIMIT = 100;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nimport { IS_FIREFOX } from '../../environment/userAgent';\nimport LocalConferenceDescription, { ConferenceEntry } from './localConferenceDescription';\nimport StringFromLineBuilder from './stringFromLineBuilder';\nimport { GroupCallConnectionTransport, PayloadType, UpdateGroupCallConnectionData } from './types';\nimport { fromTelegramSource } from './utils';\n\n// screencast is for Peer-to-Peer only\nexport type WebRTCLineTypeTrue = 'video' | 'audio' | 'application';\nexport type WebRTCLineType = WebRTCLineTypeTrue | 'screencast';\n\nexport const WEBRTC_MEDIA_PORT = '9';\n\nexport function fixMediaLineType(mediaType: WebRTCLineType) {\n return mediaType === 'screencast' ? 'video' : mediaType;\n}\n\nexport function performCandidate(c: GroupCallConnectionTransport['candidates'][0]) {\n const arr: string[] = [];\n arr.push('a=candidate:');\n arr.push(`${c.foundation} ${c.component} ${c.protocol.toUpperCase()} ${c.priority} ${c.ip} ${c.port} typ ${c.type}`);\n if(c['rel-addr'] !== undefined) {\n arr.push(` raddr ${c['rel-addr']} rport ${c['rel-port']}`);\n }\n arr.push(` generation ${c.generation}`);\n return arr.join('');\n}\n\nexport function getConnectionTypeForMediaType(mediaType: WebRTCLineType) {\n // return mediaType === 'application' ? 'DTLS/SCTP' : 'RTP/SAVPF';\n return mediaType === 'application' ? 'DTLS/SCTP' : 'UDP/TLS/RTP/SAVPF';\n}\n\nexport function generateMediaFirstLine(mediaType: WebRTCLineType, port = WEBRTC_MEDIA_PORT, payloadIds: (string | number)[]) {\n const connectionType = getConnectionTypeForMediaType(mediaType);\n return `m=${fixMediaLineType(mediaType)} ${port} ${connectionType} ${payloadIds.join(' ')}`;\n}\n\ntype ConferenceData = UpdateGroupCallConnectionData | LocalConferenceDescription;\n\n// https://tools.ietf.org/id/draft-ietf-rtcweb-sdp-08.html\n// https://datatracker.ietf.org/doc/html/draft-roach-mmusic-unified-plan-00\nexport class SDPBuilder extends StringFromLineBuilder {\n public addCandidate(c: GroupCallConnectionTransport['candidates'][0]) {\n return this.add(performCandidate(c));\n }\n\n /* public addDataChannel(mid: string, transport: GroupCallConnectionTransport, isAnswer?: boolean) {\n this.add(\n 'm=application 9 UDP/DTLS/SCTP webrtc-datachannel',\n 'c=IN IP4 0.0.0.0',\n 'a=ice-options:trickle',\n `a=mid:${mid}`\n );\n\n // if(!isAnswer) {\n this.add('a=sendrecv');\n // }\n\n this.addTransport(transport, isAnswer);\n\n return this.add(\n 'a=sctp-port:5000',\n 'a=max-message-size:262144'\n );\n } */\n \n public addHeader(sId: string, bundleMids: string[]) {\n const bundle = bundleMids.join(' ');\n return this.add(\n 'v=0', // version\n `o=- ${sId} 2 IN IP4 0.0.0.0`, // sessionId, 2=sessionVersion\n 's=-', // name of the session\n 't=0 0', // time when session is valid\n 'a=extmap-allow-mixed',\n `a=group:BUNDLE ${bundle}`,\n 'a=ice-options:trickle',\n // 'a=ice-lite', // ice-lite: is a minimal version of the ICE specification, intended for servers running on a public IP address.\n 'a=msid-semantic:WMS *'\n );\n }\n \n public addTransport(transport: GroupCallConnectionTransport, skipCandidates?: boolean) {\n this.add(\n `a=ice-ufrag:${transport.ufrag}`,\n `a=ice-pwd:${transport.pwd}`,\n 'a=ice-options:trickle' // ! test\n );\n\n for(const fingerprint of transport.fingerprints) {\n this.add(\n `a=fingerprint:${fingerprint.hash} ${fingerprint.fingerprint}`,\n `a=setup:${fingerprint.setup}`\n );\n }\n\n if(!skipCandidates && transport.candidates) {\n for(const candidate of transport.candidates) {\n this.addCandidate(candidate);\n }\n }\n\n return this;\n }\n\n public addSsrc(entry: ConferenceEntry) {\n let streamName = 'stream';\n let {type, sourceGroups} = entry;\n\n // let source = ssrc.source ?? ssrc.sourceGroups[0].sources[0];\n // source = fromTelegramSource(source);\n const source = fromTelegramSource(entry.source);\n\n streamName += source;\n type += source as any;\n\n // streamName += mid;\n // type += mid as any;\n\n // streamName = type = entry.transceiver.receiver.track.id as any;\n\n const addMsid = () => {\n this.add(`a=msid:${streamName} ${type}`);\n };\n\n const addSource = (ssrc: number) => {\n this.add(\n `a=ssrc:${ssrc} cname:${streamName}`,\n `a=ssrc:${ssrc} msid:${streamName} ${type}`,\n `a=ssrc:${ssrc} mslabel:${streamName}`,\n `a=ssrc:${ssrc} label:${type}`\n );\n };\n\n addMsid();\n if(sourceGroups?.length) {\n sourceGroups.forEach(ssrcGroup => {\n if(ssrcGroup.sources.length) {\n const sources = ssrcGroup.sources.map(fromTelegramSource);\n this.add(`a=ssrc-group:${ssrcGroup.semantics} ${sources.join(' ')}`);\n sources.forEach(addSource);\n }\n });\n } else {\n addSource(source);\n }\n \n return this;\n }\n\n public addSsrcEntry(entry: ConferenceEntry, data: ConferenceData, isAnswer?: boolean) {\n const add = (...x: string[]) => this.add(...x);\n \n const {type, mid, direction, port} = entry;\n const transport = data.transport;\n\n /* if(type === 'application') {\n return this.addDataChannel(mid, transport, isAnswer);\n } */\n\n const isApplication = type === 'application';\n const codec = isApplication ? undefined : data[type];\n\n const isInactive = direction === 'inactive';\n if(entry.shouldBeSkipped(isAnswer)) {\n return add(\n `m=${fixMediaLineType(type)} 0 ${getConnectionTypeForMediaType(type)} 0`,\n `c=IN IP4 0.0.0.0`,\n `a=inactive`,\n `a=mid:${mid}`\n );\n }\n \n const payloadTypes = !isApplication ? codec['payload-types'] : [{id: 5000} as PayloadType];\n const ids = payloadTypes.map(type => type.id);\n add(\n generateMediaFirstLine(type, port, ids),\n 'c=IN IP4 0.0.0.0',\n `a=rtcp:${port} IN IP4 0.0.0.0`,\n );\n\n if(transport['rtcp-mux']) {\n add('a=rtcp-mux');\n }\n\n add(`a=mid:${mid}`);\n /* if(type === 'video') {\n add('b=AS:2500');\n } */\n\n let setDirection = direction;\n if(direction !== 'sendrecv' && isAnswer && !(isInactive || isApplication)) {\n setDirection = direction === 'sendonly' ? 'recvonly' : 'sendonly';\n }\n\n // a=bundle-only\n add(`a=${setDirection}`);\n \n // this.addTransport(transport, isAnswer);\n this.addTransport(transport);\n\n if(!isApplication) {\n const hdrexts = codec['rtp-hdrexts'];\n if(hdrexts?.length) {\n hdrexts.forEach(hdrext => {\n add(`a=extmap:${hdrext.id} ${hdrext.uri}`);\n });\n }\n \n payloadTypes.forEach(type => {\n add(`a=rtpmap:${type.id} ${type.name}/${type.clockrate}${type.channels && type.channels > 1 ? `/${type.channels}` : ''}`);\n \n const parameters = type.parameters;\n if(Array.isArray(parameters)) {\n if(parameters.length) {\n console.error('parameters is array???', parameters);\n }\n } else if(parameters && Object.keys(parameters).length) {\n const p: string[] = [];\n for(const i in parameters) {\n p.push(`${i}=${parameters[i]}`);\n }\n add(`a=fmtp:${type.id} ${p.join(';')}`);\n }\n \n const fbs = type['rtcp-fbs'];\n if(fbs?.length) {\n fbs.forEach(fb => {\n add(`a=rtcp-fb:${type.id} ${fb.type}${fb.subtype ? ' ' + fb.subtype : ''}`);\n });\n }\n });\n } else {\n add(`a=sctpmap:${payloadTypes[0].id} webrtc-datachannel 256`);\n }\n\n if(entry.source && (setDirection === 'sendonly' || setDirection === 'sendrecv')) {\n this.addSsrc(entry);\n }\n\n return this;\n }\n \n public addConference(options: {\n conference: LocalConferenceDescription, \n bundle: string[],\n entries: ConferenceEntry[],\n isAnswer?: boolean, \n }) {\n const {conference, entries, bundle, isAnswer} = options;\n this.addHeader(conference.sessionId, bundle);\n\n if(IS_FIREFOX) {\n this.addTransport(conference.transport); // support Firefox\n }\n\n for(const entry of entries) {\n // this.addSsrcEntry(entry, conference, isAnswer);\n this.addSsrcEntry((isAnswer ? entry.recvEntry || entry.sendEntry : entry.sendEntry || entry.recvEntry) || entry, conference, isAnswer);\n }\n\n return this;\n }\n \n public static fromConference(options: Parameters<SDPBuilder['addConference']>[0]) {\n return new SDPBuilder().addConference(options).finalize();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport SDPMediaSection from \"./mediaSection\";\nimport SDPSessionSection from \"./sessionSection\";\n\nexport type AttributeKey = 'group' | 'rtcp' | 'ice-ufrag' | \n 'ice-pwd' | 'ice-options' | 'fingerprint' | 'setup' | \n 'mid' | 'extmap' | 'sendonly' | 'msid' | 'rtcp-mux' | \n 'rtpmap' | 'rtcp-fb' | 'fmtp' | 'ssrc' | 'ssrc-group' |\n 'extmap-allow-mixed' | 'msid-semantic';\n\nexport type AttributeMap = {[k in AttributeKey]?: boolean};\n\nexport default class SDP {\n #session: SDPSessionSection;\n #media: SDPMediaSection[];\n\n constructor(session: SDP['session'], mediaSections: SDP['media']) {\n this.#session = session;\n this.#media = mediaSections;\n }\n\n public get session() {\n return this.#session;\n }\n\n public get media() {\n return this.#media;\n }\n\n public get bundle() {\n const bundleLine = this.session.lines.find(line => line.parsed?.key === 'group');\n return bundleLine.value.split(' ').slice(1);\n }\n\n toString() {\n return this.session.lines\n .concat(...this.media.map(section => section.lines))\n .map(line => line.toString()).join('\\r\\n') + '\\r\\n';\n }\n\n /* get buggedMedia() {\n const bundle = this.bundle;\n type A = {\n mid: SDPMediaSection['mid'],\n mediaType: SDPMediaSection['mediaType'],\n direction: SDPMediaSection['direction']\n };\n const out: A[] = [];\n for(let i = 0, length = this.media.length; i < length; ++i) {\n const section = this.media[i];\n const mid = section.mid;\n if(!bundle.includes(mid)) {\n out.push(section);\n }\n }\n\n return out;\n } */\n\n /* get mediaTypes() {\n return this.media.map((section) => {\n return {mid: section.oa.get('mid').oa, type: section.mediaType, direction: section.direction};\n });\n } */\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport default function splitStringByLimitWithRest(str: string, separator: string, limit: number) {\n const splitted = str.split(separator);\n const out: string[] = [];\n\n while(limit > 0 && splitted.length) {\n out.push(splitted.shift());\n --limit;\n }\n\n if(splitted.length) {\n out.push(splitted.join(separator));\n }\n\n return out;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport default class UniqueNumberGenerator {\n #set: Set<number>;\n #min: number;\n #max: number;\n\n constructor(min: number, max: number) {\n this.#set = new Set();\n this.#min = min;\n this.#max = max;\n }\n\n public generate() {\n const min = this.#min;\n const max = this.#max;\n const set = this.#set;\n\n const maxTries = max - min + 1;\n let value = Math.floor(min + maxTries * Math.random()), _try = 0;\n while(set.has(value)) {\n if(value < max) {\n ++value;\n } else {\n value = min;\n }\n\n if(++_try >= maxTries) {\n return null;\n }\n }\n\n set.add(value);\n return value;\n }\n\n public add(value: number) {\n this.#set.add(value);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { AttributeKey } from \".\";\n\nexport default class SDPAttributeSplitted {\n #key: AttributeKey;\n #value: string;\n\n // key = 'ssrc-group', value = 'SIM 1 2 3'\n constructor(key: AttributeKey, value: string) {\n this.#key = key;\n this.#value = value;\n }\n\n public get key() {\n return this.#key;\n }\n\n public get value() {\n return this.#value;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport default class SDPMediaLineParts {\n #type: 'audio' | 'video' | 'application';\n #port: string;\n #protocol: string;\n #ids: string[];\n\n constructor(\n type: SDPMediaLineParts['type'], \n port: SDPMediaLineParts['port'], \n protocol: SDPMediaLineParts['protocol'], \n ids: SDPMediaLineParts['ids']\n ) {\n this.#type = type;\n this.#port = port;\n this.#protocol = protocol;\n this.#ids = ids;\n }\n\n public get type() {\n return this.#type;\n }\n \n public get port() {\n return this.#port;\n }\n\n public get protocol() {\n return this.#protocol;\n }\n\n public get ids() {\n return this.#ids;\n }\n\n toString() {\n return this.type + ' ' + this.port + ' ' + this.protocol + ' ' + this.ids.join(' ');\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport splitStringByLimitWithRest from \"../../../helpers/string/splitStringByLimitWithRest\";\nimport SDPAttributeSplitted from \"./attributeSplitted\";\nimport SDPMediaLineParts from \"./mediaLineParts\";\n\nexport default class SDPLine {\n #key: 'm' | 'a' | 'o' | 'v' | 's' | 't' | 'c';\n #value: string;\n #mediaLineParts: SDPMediaLineParts;\n #parsed?: SDPAttributeSplitted;\n\n // key = 'a', value = 'ssrc-group:SIM 1 2 3'\n constructor(key: SDPLine['key'], value: string | SDPMediaLineParts | SDPAttributeSplitted) {\n this.#key = key;\n\n if(typeof(value) === 'string') {\n this.#value = value;\n\n if(key === 'm') {\n const splitted = value.split(' ');\n this.#mediaLineParts = new SDPMediaLineParts(splitted[0] as any, splitted[1], splitted[2], splitted.slice(3));\n } else {\n if(key === 'a') {\n const result = splitStringByLimitWithRest(value, ':', 1);\n value = result[0];\n this.#parsed = result.length === 1 ? new SDPAttributeSplitted(value as any, null) : new SDPAttributeSplitted(value as any, result[1]);\n }\n }\n } else {\n if(value instanceof SDPMediaLineParts) {\n this.#mediaLineParts = value;\n this.#value = value.toString();\n } else if(value instanceof SDPAttributeSplitted) {\n this.#parsed = value;\n this.#value = value.value ? `${value.key}:${value.value}` : value.key;\n }\n }\n }\n\n public get key() {\n return this.#key;\n }\n\n public get value() {\n return this.#value;\n }\n\n public get parsed() {\n return this.#parsed;\n }\n\n public get mediaLineParts() {\n return this.#mediaLineParts;\n }\n\n toString() {\n return `${this.key}=${this.value}`;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport splitStringByLimitWithRest from \"../../../helpers/string/splitStringByLimitWithRest\";\n\nexport default class SDPAttributeInner {\n #key: string;\n #lines: Array<string>;\n #prefix: string;\n #nestedMap: Map<string, SDPAttributeInner>;\n #missed: boolean;\n #keys: Array<string>;\n\n constructor(key: SDPAttributeInner['key'], lines: SDPAttributeInner['lines'], prefix: string = ':', missed = false) {\n this.#key = key;\n this.#lines = lines;\n this.#prefix = prefix;\n this.#missed = missed;\n this.#nestedMap = missed ? new Map() : null;\n this.#keys = missed ? [] : null;\n }\n\n public get lines() {\n return this.#lines;\n }\n\n public get value() {\n return this.#missed || !this.lines.length ? null : this.lines[0];\n }\n\n public get exists() {\n return !this.#missed;\n }\n\n public get key() {\n return this.#key;\n }\n\n public get keys() {\n SDPAttributeInner.fill(this);\n return this.#keys;\n }\n\n public forEach(callback: Parameters<Map<string, SDPAttributeInner>['forEach']>[0]) {\n SDPAttributeInner.fill(this);\n this.#nestedMap.forEach(callback);\n }\n\n public get(key: string) {\n SDPAttributeInner.fill(this);\n return this.#nestedMap.get(key) || new SDPAttributeInner(key, [], ':', true);\n }\n \n private static fill(attribute: SDPAttributeInner) {\n if(attribute.#nestedMap !== null) {\n return;\n }\n\n const map: Map<string, Array<string>> = new Map();\n attribute.lines.forEach(str => {\n const [key, rest] = splitStringByLimitWithRest(str, attribute.#prefix, 1);\n const values = map.get(key) || [];\n map.set(key, [...values, rest || '']);\n });\n \n const nestedMap = attribute.#nestedMap = SDPAttributeInner.makeAttributes(map);\n attribute.#keys = Array.from(nestedMap.keys());\n }\n\n private static makeAttributes(innerParts: Map<string, Array<string>>) {\n const out: Map<string, SDPAttributeInner> = new Map();\n \n innerParts.forEach((lines, key) => {\n out.set(key, new SDPAttributeInner(key, lines));\n });\n \n return out;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport SDPAttributeInner from \"./attributeInner\";\nimport SDPLine from \"./line\";\n\nexport default class SDPAttributes {\n #lines: SDPLine[];\n #attributes: Map<string, SDPAttributeInner>;\n\n constructor(lines: SDPLine[]) {\n this.#lines = lines;\n this.#attributes = new Map();\n SDPAttributes.fillAttributes(this);\n }\n\n public get(key: string) {\n return this.#attributes.get(key) || new SDPAttributeInner(key, [], ' ', true);\n }\n\n private static fillAttributes(attributes: SDPAttributes) {\n const attributesMap: Map<string, Array<string>> = new Map();\n attributes.#lines.forEach((line) => {\n if(line.key === 'a') {\n const {key, value} = line.parsed;\n\n let linesArray = attributesMap.get(key);\n if(!linesArray) {\n linesArray = [];\n attributesMap.set(key, linesArray);\n }\n \n linesArray.push(value || '');\n }\n });\n\n attributesMap.forEach((linesArray, key) => {\n attributes.#attributes.set(key, new SDPAttributeInner(key, linesArray, ' ', false));\n });\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { AttributeMap } from \".\";\nimport { NoExtraProperties } from \"../../../types\";\nimport SDPAttributes from \"./attributes\";\nimport SDPLine from \"./line\";\n\nexport type SDPMediaDirection = 'sendonly' | 'recvonly' | 'inactive' | 'sendrecv';\nexport default class SDPMediaSection {\n #lines: Array<SDPLine>;\n #mediaLine: SDPLine;\n #attributes: SDPAttributes;\n #direction: SDPMediaDirection;\n\n constructor(lines: Array<SDPLine>) {\n this.#lines = lines;\n this.#mediaLine = lines[0];\n this.#attributes = this.#direction = null;\n }\n\n public get lines() {\n return this.#lines;\n }\n\n public get mediaLine() {\n return this.#mediaLine;\n }\n\n public get mediaLineParts() {\n return this.#mediaLine.mediaLineParts;\n }\n\n public get mediaType() {\n return this.mediaLineParts.type;\n }\n\n public get direction() {\n if(!this.#direction) {\n const attributes = this.attributes;\n\n let direction: SDPMediaDirection;\n if(attributes.get('sendonly').exists) direction = 'sendonly';\n else if(attributes.get('recvonly').exists) direction = 'recvonly';\n else if(attributes.get('inactive').exists) direction = 'inactive';\n else direction = 'sendrecv';\n\n this.#direction = direction;\n }\n\n return this.#direction;\n }\n\n public get isSending() {\n return this.direction === 'sendrecv' || this.direction === 'sendonly';\n }\n\n public get isReceiving() {\n return this.direction === 'sendrecv' || this.direction === 'recvonly';\n }\n\n public get attributes() {\n this.#attributes || (this.#attributes = new SDPAttributes(this.lines));\n return this.#attributes;\n }\n\n public get mid() {\n return this.attributes.get('mid').value;\n }\n\n public lookupAttributeKeys<T extends AttributeMap>(keys: NoExtraProperties<AttributeMap, T>): {[k in keyof T]: T[k] extends true ? string : string[]} {\n const out: any = {};\n\n for(const key in keys) {\n const result = this.attributes.get(key);\n // @ts-ignore\n const resultShouldBeArray = !keys[key];\n if(!result) {\n out[key] = resultShouldBeArray ? [] : undefined;\n } else {\n out[key] = resultShouldBeArray ? result.lines : result.value;\n }\n }\n\n return out;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport SDPLine from \"./line\";\n\nexport default class SDPSessionSection {\n #lines: SDPLine[];\n #sessionId: string;\n\n constructor(lines: SDPLine[]) {\n this.#lines = lines;\n this.#sessionId = lines.filter(line => line.key === 'o').map(line => line.value.split(' ')[1])[0];\n }\n\n public get lines() {\n return this.#lines;\n }\n\n public get sessionId() {\n return this.#sessionId;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport SDP from \".\";\nimport splitStringByLimitWithRest from \"../../../helpers/string/splitStringByLimitWithRest\";\nimport UniqueNumberGenerator from \"../../../helpers/uniqueNumberGenerator\";\nimport SDPLine from \"./line\";\nimport SDPMediaSection from \"./mediaSection\";\nimport SDPSessionSection from \"./sessionSection\";\n\nexport function parseSdp(str: string) {\n function createSection() {\n if(sessionSection) {\n mediaSections.push(new SDPMediaSection(lines));\n } else {\n sessionSection = new SDPSessionSection(lines);\n }\n }\n\n let sessionSection: SDPSessionSection = null, mediaSections: SDPMediaSection[] = [], lines: SDPLine[] = [];\n str.split(/\\r?\\n/).forEach(lineStr => {\n if(!isIncorrectSdpLine(lineStr)) {\n const line = parseSdpLine(lineStr);\n if(line.key === 'm') {\n createSection();\n lines = [];\n }\n\n lines.push(line);\n }\n });\n\n createSection();\n return new SDP(sessionSection, mediaSections);\n}\n\nexport function isIncorrectSdpLine(str: string) {\n return /^[\\s\\xa0]*$/.test(str);\n}\n\nexport function parseSdpLine(str: string) {\n const splitted = splitStringByLimitWithRest(str, '=', 1);\n return new SDPLine(splitted[0] as any, splitted[1]);\n}\n\nexport function addSimulcast(sdp: SDP) {\n let generator: UniqueNumberGenerator;\n sdp.media.forEach((section, idx) => {\n if(section.mediaType === 'video' && section.isSending && !section.attributes.get('ssrc-group').get('SIM').exists) {\n if(!generator) {\n generator = new UniqueNumberGenerator(2, 4294967295);\n }\n\n const originalSsrcs = section.attributes.get('ssrc-group').get('FID').value.split(' ');\n const lines = section.lines;\n originalSsrcs.forEach(ssrc => generator.add(+ssrc)); // fix possible duplicates\n const ssrcs = [originalSsrcs[0], generator.generate(), generator.generate()];\n const ssrcs2 = [originalSsrcs[1], generator.generate(), generator.generate()];\n\n lines.push(parseSdpLine('a=ssrc-group:SIM ' + ssrcs.join(' ')));\n\n const ssrcsStrLines = section.attributes.get('ssrc').get(originalSsrcs[0]).lines;\n\n ssrcs.forEach((ssrc, idx) => {\n const ssrc2 = ssrcs2[idx];\n if(idx > 0) {\n lines.push(parseSdpLine('a=ssrc-group:FID ' + ssrc + ' ' + ssrc2));\n\n ssrcsStrLines.forEach(v => {\n lines.push(parseSdpLine('a=ssrc:' + ssrc + ' ' + v));\n });\n\n ssrcsStrLines.forEach(v => {\n lines.push(parseSdpLine('a=ssrc:' + ssrc2 + ' ' + v));\n });\n }\n });\n\n sdp.media[idx] = new SDPMediaSection(lines);\n }\n });\n\n return !!generator;\n}\n","export default function bytesToHex(bytes: ArrayLike<number>) {\n const length = bytes.length;\n const arr: string[] = new Array(length);\n for(let i = 0; i < length; ++i) {\n arr[i] = (bytes[i] < 16 ? '0' : '') + (bytes[i] || 0).toString(16);\n }\n return arr.join('');\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { RefreshReferenceTask, RefreshReferenceTaskResponse } from \"./apiFileManager\";\nimport appMessagesManager from \"../appManagers/appMessagesManager\";\nimport appStickersManager from \"../appManagers/appStickersManager\";\nimport { Photo } from \"../../layer\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport apiManager from \"./mtprotoworker\";\nimport assumeType from \"../../helpers/assumeType\";\nimport { logger } from \"../logger\";\nimport bytesToHex from \"../../helpers/bytes/bytesToHex\";\nimport deepEqual from \"../../helpers/object/deepEqual\";\n\nexport type ReferenceContext = ReferenceContext.referenceContextProfilePhoto | ReferenceContext.referenceContextMessage | ReferenceContext.referenceContextEmojiesSounds | ReferenceContext.referenceContextReactions;\nexport namespace ReferenceContext {\n export type referenceContextProfilePhoto = {\n type: 'profilePhoto',\n peerId: PeerId\n };\n\n export type referenceContextMessage = {\n type: 'message',\n peerId: PeerId,\n messageId: number\n };\n\n export type referenceContextEmojiesSounds = {\n type: 'emojiesSounds'\n };\n\n export type referenceContextReactions = {\n type: 'reactions'\n };\n}\n\nexport type ReferenceBytes = Photo.photo['file_reference'];\nexport type ReferenceContexts = Set<ReferenceContext>;\n\n//type ReferenceBytes = Uint8Array;\n\nclass ReferenceDatabase {\n private contexts: Map<ReferenceBytes, ReferenceContexts> = new Map();\n //private references: Map<ReferenceBytes, number[]> = new Map();\n private links: {[hex: string]: ReferenceBytes} = {};\n private log = logger('RD', undefined, true);\n private refreshEmojiesSoundsPromise: Promise<any>;\n\n constructor() {\n apiManager.addTaskListener('refreshReference', (task: RefreshReferenceTask) => {\n const originalPayload = task.payload;\n\n assumeType<RefreshReferenceTaskResponse>(task);\n task.originalPayload = originalPayload;\n\n this.refreshReference(originalPayload).then((bytes) => {\n task.payload = bytes;\n }, (err) => {\n task.error = err;\n }).then(() => apiManager.postMessage(task));\n });\n }\n\n public saveContext(reference: ReferenceBytes, context: ReferenceContext, contexts?: ReferenceContexts) {\n [contexts, reference] = this.getContexts(reference);\n if(!contexts) {\n contexts = new Set();\n this.contexts.set(reference, contexts);\n }\n \n this.links[bytesToHex(reference)] = reference;\n for(const _context of contexts) {\n if(deepEqual(_context, context)) {\n return;\n }\n }\n\n contexts.add(context);\n }\n\n public getReferenceByLink(reference: ReferenceBytes) {\n return this.links[bytesToHex(reference)];\n }\n\n public getContexts(reference: ReferenceBytes): [ReferenceContexts, ReferenceBytes] {\n const contexts = this.contexts.get(reference) || (reference = this.getReferenceByLink(reference) || reference, this.contexts.get(reference));\n return [contexts, reference];\n }\n\n public getContext(reference: ReferenceBytes): [ReferenceContext, ReferenceBytes] {\n const contexts = this.getContexts(reference);\n return contexts[0] ? [contexts[0].values().next().value, contexts[1]] : undefined;\n }\n\n public deleteContext(reference: ReferenceBytes, context: ReferenceContext, contexts?: ReferenceContexts) {\n [contexts, reference] = this.getContexts(reference);\n if(contexts) {\n for(const _context of contexts) {\n if(deepEqual(_context, context)) {\n contexts.delete(_context);\n if(!contexts.size) {\n this.contexts.delete(reference);\n delete this.links[bytesToHex(reference)];\n }\n return true;\n }\n }\n }\n\n return false;\n }\n\n public refreshReference(reference: ReferenceBytes, context?: ReferenceContext): Promise<Uint8Array | number[]> {\n this.log('refreshReference: start', reference.slice(), context);\n if(!context) {\n const c = this.getContext(reference);\n if(!c) {\n this.log('refreshReference: got no context for reference:', reference.slice());\n return Promise.reject('NO_CONTEXT');\n }\n\n [context, reference] = c;\n }\n\n let promise: Promise<any>;\n switch(context?.type) {\n case 'message': {\n promise = appMessagesManager.wrapSingleMessage(context.peerId, context.messageId, true);\n break; \n // .then(() => {\n // console.log('FILE_REFERENCE_EXPIRED: got message', context, appMessagesManager.getMessage((context as ReferenceContext.referenceContextMessage).messageId).media, reference);\n // });\n }\n\n case 'emojiesSounds': {\n promise = this.refreshEmojiesSoundsPromise || appStickersManager.getAnimatedEmojiSounds(true).then(() => {\n this.refreshEmojiesSoundsPromise = undefined;\n });\n break;\n }\n\n default: {\n this.log.warn('refreshReference: not implemented context', context);\n return Promise.reject();\n }\n }\n\n const hex = bytesToHex(reference);\n this.log('refreshReference: refreshing reference:', hex);\n return promise.then(() => {\n const newHex = bytesToHex(reference);\n this.log('refreshReference: refreshed, reference before:', hex, 'after:', newHex);\n if(hex !== newHex) {\n return reference;\n }\n\n this.deleteContext(reference, context);\n\n const newContext = this.getContext(reference);\n if(newContext) {\n return this.refreshReference(reference, newContext[0]);\n }\n\n this.log.error('refreshReference: no new context, reference before:', hex, 'after:', newHex, context);\n\n throw 'NO_NEW_CONTEXT';\n });\n }\n\n /* public replaceReference(oldReference: ReferenceBytes, newReference: ReferenceBytes) {\n const contexts = this.contexts.get(oldReference);\n if(contexts) {\n this.contexts.delete(oldReference);\n this.contexts.set(newReference, contexts);\n }\n } */\n}\n\nconst referenceDatabase = new ReferenceDatabase();\nMOUNT_CLASS_TO.referenceDatabase = referenceDatabase;\nexport default referenceDatabase;","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport SDP from \"../sdp\";\nimport SDPMediaSection from \"../sdp/mediaSection\";\nimport { toTelegramSource } from \"../utils\";\nimport { parseSourceGroups } from \"./parseSourceGroups\";\n\nexport default function parseMediaSectionInfo(sdp: SDP, channel: SDPMediaSection) {\n const clientInfo = channel.lookupAttributeKeys({\n 'ice-ufrag': true,\n 'ice-pwd': true,\n fingerprint: true,\n setup: true,\n ssrc: true,\n mid: true,\n 'ssrc-group': false\n });\n\n if(!clientInfo.fingerprint) { // support Firefox\n const line = sdp.session.lines.find(line => line.parsed?.key === 'fingerprint');\n clientInfo.fingerprint = line.parsed.value;\n }\n\n const telegramSourceGroups = parseSourceGroups(clientInfo['ssrc-group']);\n const [hash, fingerprint] = clientInfo.fingerprint.split(' ', 2);\n const ssrc = clientInfo.ssrc && toTelegramSource(+clientInfo.ssrc.split(' ', 1)[0]);\n // ssrc = telegramSourceGroups ? telegramSourceGroups[0].sources[0] : ssrc;\n\n return {\n raw: clientInfo,\n ufrag: clientInfo['ice-ufrag'],\n pwd: clientInfo['ice-pwd'],\n fingerprint: {\n fingerprint,\n setup: clientInfo.setup,\n hash\n },\n source: ssrc,\n sourceGroups: telegramSourceGroups,\n mid: clientInfo.mid\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { GroupCallParticipantVideoSourceGroup } from \"../../../layer\";\nimport { toTelegramSource } from \"../utils\";\n\nexport function parseSourceGroups(sdpLines: string[]) {\n const telegramSourceGroups = sdpLines.map(str => {\n const [semantics, ...rest] = str.split(' ');\n\n const sourceGroup: GroupCallParticipantVideoSourceGroup = {\n _: 'groupCallParticipantVideoSourceGroup',\n semantics,\n // sources: rest.map(ssrc => +ssrc)\n sources: rest.map(ssrc => toTelegramSource(+ssrc))\n };\n\n return sourceGroup;\n });\n\n /* const simIndex = telegramSourceGroups.findIndex(g => g.semantics === 'SIM');\n if(simIndex !== -1) {\n const sourceGroup = telegramSourceGroups.splice(simIndex, 1)[0];\n telegramSourceGroups.unshift(sourceGroup);\n } */\n\n return telegramSourceGroups.length ? telegramSourceGroups : undefined;\n}\n","export default function filterUnique<T extends Array<any>>(arr: T): T {\n return [...new Set(arr)] as T;\n}\n","const IS_VIBRATE_SUPPORTED = !!navigator?.vibrate;\n\nexport default IS_VIBRATE_SUPPORTED;\n","export default function convertInputKeyToKey<T extends string>(inputKey: string) {\n const str = inputKey.replace('input', '');\n return (str[0].toLowerCase() + str.slice(1)) as T;\n}\n","export default function defineNotNumerableProperties<T extends any>(obj: T, names: (keyof T)[]) {\n //const perf = performance.now();\n const props = {writable: true, configurable: true};\n const out: {[name in keyof T]?: typeof props} = {};\n names.forEach(name => {\n if(!obj.hasOwnProperty(name)) {\n out[name] = props;\n }\n });\n Object.defineProperties(obj, out);\n //console.log('defineNotNumerableProperties time:', performance.now() - perf);\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport { IS_SAFARI } from \"../environment/userAgent\";\r\nimport { logger, LogTypes } from \"./logger\";\r\n\r\ntype Result = {\r\n bytes: Uint8Array, \r\n waveform?: Uint8Array\r\n};\r\n\r\ntype Task = {\r\n pages: Uint8Array,\r\n withWaveform: boolean,\r\n waveform?: Uint8Array,\r\n callback: {resolve: (result: Result) => void, reject: (err: any) => void},\r\n timeout: number\r\n};\r\n\r\nexport class OpusDecodeController {\r\n private worker: Worker;\r\n private wavWorker : Worker;\r\n private sampleRate = 48000;\r\n private tasks: Array<Task> = [];\r\n private keepAlive = false;\r\n private isPlaySupportedResult: boolean;\r\n private log = logger('OPUS', LogTypes.Error);\r\n\r\n public isPlaySupported() {\r\n if(this.isPlaySupportedResult !== undefined) return this.isPlaySupportedResult;\r\n\r\n const audio = document.createElement('audio');\r\n return this.isPlaySupportedResult = !!(audio.canPlayType && audio.canPlayType('audio/ogg;').replace(/no/, ''))/* && false */;\r\n }\r\n\r\n public loadWavWorker() {\r\n if(this.wavWorker) return;\r\n\r\n this.wavWorker = new Worker('waveWorker.min.js');\r\n this.wavWorker.addEventListener('message', (e) => {\r\n const data = e.data;\r\n\r\n this.log('[WAV] got message:', data);\r\n if(data && data.page) {\r\n const bytes = data.page;\r\n this.onTaskEnd(this.tasks.shift(), bytes);\r\n }\r\n });\r\n }\r\n\r\n public loadWorker() {\r\n if(this.worker) return;\r\n\r\n this.worker = new Worker('decoderWorker.min.js');\r\n this.worker.addEventListener('message', (e) => {\r\n const data = e.data;\r\n \r\n this.log('[DECODER] got message', data);\r\n if(data.type === 'done') {\r\n //this.log('[DECODER] send done to wav');\r\n this.wavWorker.postMessage({command: 'done'});\r\n\r\n if(data.waveform) {\r\n this.tasks[0].waveform = data.waveform;\r\n }\r\n } else { // e.data contains decoded buffers as float32 values\r\n //this.log('[DECODER] send encode to wav');\r\n this.wavWorker.postMessage({\r\n command: 'encode',\r\n buffers: e.data\r\n }, IS_SAFARI ? undefined : data.map((typedArray: Uint8Array) => typedArray.buffer));\r\n }\r\n });\r\n }\r\n\r\n public setKeepAlive(keepAlive: boolean) {\r\n this.keepAlive = keepAlive;\r\n if(this.keepAlive) {\r\n this.loadWorker();\r\n this.loadWavWorker();\r\n } else if(!this.tasks.length) {\r\n this.terminateWorkers();\r\n }\r\n }\r\n\r\n public onTaskEnd(task: Task, result?: Uint8Array) {\r\n if(!result) {\r\n task.callback.reject('timeout');\r\n } else {\r\n clearTimeout(task.timeout);\r\n task.callback.resolve({bytes: result, waveform: task.waveform});\r\n }\r\n\r\n if(this.tasks.length) {\r\n this.executeNewTask(this.tasks[0]);\r\n }\r\n\r\n this.terminateWorkers();\r\n }\r\n\r\n public terminateWorkers(kill = false) {\r\n if((this.keepAlive || this.tasks.length) && !kill) return;\r\n\r\n if(this.worker) {\r\n this.worker.terminate();\r\n this.worker = null;\r\n }\r\n \r\n if(this.wavWorker) {\r\n this.wavWorker.terminate();\r\n this.wavWorker = null;\r\n }\r\n }\r\n\r\n public executeNewTask(task: Task) {\r\n this.worker.postMessage({ \r\n command: 'init',\r\n decoderSampleRate: this.sampleRate,\r\n outputBufferSampleRate: this.sampleRate\r\n });\r\n\r\n this.wavWorker.postMessage({ \r\n command: 'init',\r\n wavBitDepth: 16,\r\n wavSampleRate: this.sampleRate\r\n });\r\n\r\n //console.log('sending command to worker:', task);\r\n //setTimeout(() => {\r\n this.log('[DECODER] send decode');\r\n this.worker.postMessage({\r\n command: 'decode',\r\n pages: task.pages,\r\n waveform: task.withWaveform\r\n }, IS_SAFARI ? undefined : [task.pages.buffer]);\r\n //}, 1e3);\r\n\r\n task.timeout = window.setTimeout(() => {\r\n this.log.error('decode timeout'/* , task */);\r\n\r\n this.terminateWorkers(true);\r\n if(this.tasks.length) {\r\n this.loadWorker();\r\n this.loadWavWorker();\r\n }\r\n\r\n this.onTaskEnd(this.tasks.shift());\r\n }, 10e3);\r\n }\r\n\r\n public pushDecodeTask(pages: Uint8Array, withWaveform: boolean) {\r\n return new Promise<Result>((resolve, reject) => {\r\n const task = {\r\n pages,\r\n withWaveform,\r\n callback: {resolve, reject},\r\n timeout: 0\r\n };\r\n\r\n this.loadWorker();\r\n this.loadWavWorker();\r\n\r\n if(this.tasks.push(task) === 1) {\r\n this.executeNewTask(task);\r\n }\r\n });\r\n }\r\n\r\n public async decode(typedArray: Uint8Array, withWaveform = false) {\r\n return this.pushDecodeTask(typedArray, withWaveform).then(result => {\r\n const dataBlob = new Blob([result.bytes], {type: \"audio/wav\"});\r\n return {url: URL.createObjectURL(dataBlob), waveform: result.waveform};\r\n });\r\n }\r\n}\r\n\r\nconst opusDecodeController = new OpusDecodeController();\r\nMOUNT_CLASS_TO.opusDecodeController = opusDecodeController;\r\nexport default opusDecodeController;","import { IS_APPLE_MOBILE, IS_SAFARI } from \"./userAgent\";\n\nconst IS_WEBM_SUPPORTED = !!document.createElement('video').canPlayType('video/webm') && !IS_SAFARI && !IS_APPLE_MOBILE;\n\n(window as any).IS_WEBM_SUPPORTED = IS_WEBM_SUPPORTED;\nexport default IS_WEBM_SUPPORTED;\n","/**\n * Will be used for FILE_REFERENCE_EXPIRED\n * @param key \n * @param wasObject \n * @param newObject \n */\n export default function safeReplaceArrayInObject<K>(key: K, wasObject: any, newObject: any) {\n if('byteLength' in newObject[key]) { // Uint8Array\n newObject[key] = [...newObject[key]];\n }\n\n if(wasObject && wasObject[key] !== newObject[key]) {\n wasObject[key].length = newObject[key].length;\n (newObject[key] as any[]).forEach((v, i) => {\n wasObject[key][i] = v;\n });\n\n /* wasObject[key].set(newObject[key]); */\n newObject[key] = wasObject[key];\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport appPhotosManager from \"./appPhotosManager\";\r\nimport appDocsManager from \"./appDocsManager\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport { ReferenceContext } from \"../mtproto/referenceDatabase\";\r\nimport rootScope from \"../rootScope\";\r\nimport { WebPage } from \"../../layer\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport safeReplaceObject from \"../../helpers/object/safeReplaceObject\";\r\nimport limitSymbols from \"../../helpers/string/limitSymbols\";\r\n\r\nconst photoTypeSet = new Set(['photo', 'video', 'gif', 'document']);\r\n\r\ntype WebPageMessageKey = `${PeerId}_${number}`;\r\n\r\nexport class AppWebPagesManager {\r\n private webpages: {\r\n [webPageId: string]: WebPage\r\n } = {};\r\n private pendingWebPages: {\r\n [webPageId: string]: Set<WebPageMessageKey>\r\n } = {};\r\n \r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updateWebPage: (update) => {\r\n this.saveWebPage(update.webpage);\r\n }\r\n });\r\n }\r\n \r\n public saveWebPage(apiWebPage: WebPage, messageKey?: WebPageMessageKey, mediaContext?: ReferenceContext) {\r\n if(apiWebPage._ === 'webPageNotModified') return;\r\n const {id} = apiWebPage;\r\n\r\n const oldWebPage = this.webpages[id];\r\n const isUpdated = oldWebPage && \r\n oldWebPage._ === apiWebPage._ && \r\n (oldWebPage as WebPage.webPage).hash === (oldWebPage as WebPage.webPage).hash;\r\n\r\n if(apiWebPage._ === 'webPage') {\r\n if(apiWebPage.photo?._ === 'photo') {\r\n apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);\r\n } else {\r\n delete apiWebPage.photo;\r\n }\r\n \r\n if(apiWebPage.document?._ === 'document') {\r\n apiWebPage.document = appDocsManager.saveDoc(apiWebPage.document, mediaContext);\r\n } else {\r\n if(apiWebPage.type === 'document') {\r\n delete apiWebPage.type;\r\n }\r\n \r\n delete apiWebPage.document;\r\n }\r\n\r\n const siteName = apiWebPage.site_name;\r\n let shortTitle = apiWebPage.title || apiWebPage.author || siteName || '';\r\n if(siteName && shortTitle === siteName) {\r\n delete apiWebPage.site_name;\r\n }\r\n\r\n shortTitle = limitSymbols(shortTitle, 80, 100);\r\n\r\n apiWebPage.rTitle = RichTextProcessor.wrapRichText(shortTitle, {noLinks: true, noLinebreaks: true});\r\n let contextHashtag = '';\r\n if(siteName === 'GitHub') {\r\n const matches = apiWebPage.url.match(/(https?:\\/\\/github\\.com\\/[^\\/]+\\/[^\\/]+)/);\r\n if(matches) {\r\n contextHashtag = matches[0] + '/issues/{1}';\r\n }\r\n }\r\n\r\n // delete apiWebPage.description\r\n const shortDescriptionText = limitSymbols(apiWebPage.description || '', 150, 180);\r\n apiWebPage.rDescription = RichTextProcessor.wrapRichText(shortDescriptionText, {\r\n contextSite: siteName || 'external',\r\n contextHashtag: contextHashtag\r\n });\r\n\r\n if(!photoTypeSet.has(apiWebPage.type) &&\r\n !apiWebPage.description &&\r\n apiWebPage.photo) {\r\n apiWebPage.type = 'photo';\r\n }\r\n }\r\n \r\n let pendingSet = this.pendingWebPages[id];\r\n if(messageKey) {\r\n if(!pendingSet) pendingSet = this.pendingWebPages[id] = new Set();\r\n pendingSet.add(messageKey);\r\n }\r\n \r\n if(oldWebPage === undefined) {\r\n this.webpages[id] = apiWebPage;\r\n } else {\r\n safeReplaceObject(oldWebPage, apiWebPage);\r\n }\r\n \r\n if(!messageKey && pendingSet !== undefined && isUpdated) {\r\n const msgs: {peerId: PeerId, mid: number, isScheduled: boolean}[] = [];\r\n pendingSet.forEach((value) => {\r\n const [peerId, mid, isScheduled] = value.split('_');\r\n msgs.push({\r\n peerId: peerId.toPeerId(), \r\n mid: +mid, \r\n isScheduled: !!isScheduled\r\n });\r\n });\r\n\r\n rootScope.dispatchEvent('webpage_updated', {\r\n id,\r\n msgs\r\n });\r\n }\r\n\r\n return apiWebPage;\r\n }\r\n\r\n public getMessageKeyForPendingWebPage(peerId: PeerId, mid: number, isScheduled?: boolean): WebPageMessageKey {\r\n return peerId + '_' + mid + (isScheduled ? '_s' : '') as any;\r\n }\r\n\r\n public deleteWebPageFromPending(webPage: WebPage, messageKey: WebPageMessageKey) {\r\n const id = (webPage as WebPage.webPage).id;\r\n if(!id) return;\r\n\r\n const set = this.pendingWebPages[id];\r\n if(set && set.has(messageKey)) {\r\n set.delete(messageKey);\r\n\r\n if(!set.size) {\r\n delete this.pendingWebPages[id];\r\n }\r\n }\r\n }\r\n\r\n public getWebPage(id: WebPage.webPage['id']) {\r\n return this.webpages[id];\r\n }\r\n}\r\n\r\nconst appWebPagesManager = new AppWebPagesManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appWebPagesManager = appWebPagesManager);\r\nexport default appWebPagesManager;\r\n","import IS_WEBP_SUPPORTED from \"./webpSupport\";\n\nconst IMAGE_MIME_TYPES_SUPPORTED = new Set([\n 'image/jpeg',\n 'image/png',\n 'image/bmp'\n]);\n\nif(IS_WEBP_SUPPORTED) {\n IMAGE_MIME_TYPES_SUPPORTED.add('image/webp');\n}\n\nexport default IMAGE_MIME_TYPES_SUPPORTED;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nconst ASSETS_PATH = 'assets/audio/';\n\nexport default class AudioAssetPlayer<AssetName extends string> {\n private audio: HTMLAudioElement;\n private tempId: number;\n private assetName: AssetName;\n\n constructor(private assets: AssetName[]) {\n this.tempId = 0;\n }\n\n public playSound(name: AssetName, loop = false) {\n ++this.tempId;\n this.assetName = name;\n\n try {\n const audio = this.createAudio();\n audio.autoplay = true;\n audio.src = ASSETS_PATH + name;\n audio.loop = loop;\n audio.play();\n } catch(e) {\n console.error('playSound', name, e);\n }\n }\n\n public playSoundIfDifferent(name: AssetName, loop?: boolean) {\n if(this.assetName !== name) {\n this.playSound(name, loop);\n }\n }\n\n public createAudio() {\n let {audio} = this;\n if(audio) {\n return audio;\n }\n\n audio = this.audio = new Audio();\n audio.play();\n return audio;\n }\n\n public stopSound() {\n if(!this.audio) {\n return;\n }\n \n this.audio.pause();\n }\n\n public cancelDelayedPlay() {\n ++this.tempId;\n }\n\n public playSoundWithTimeout(name: AssetName, loop: boolean, timeout: number) {\n // timeout = 0;\n const tempId = ++this.tempId;\n setTimeout(() => {\n if(this.tempId !== tempId) {\n return;\n }\n\n this.playSound(name, loop);\n }, timeout);\n }\n}\n","export default function getScreenConstraints(skipAudio?: boolean) {\n const constraints: DisplayMediaStreamConstraints = {\n video: {\n // @ts-ignore\n // cursor: 'always',\n width: {max: 1920},\n height: {max: 1080},\n frameRate: {max: 30}\n }\n };\n\n if(!skipAudio) {\n constraints.audio = true;\n }\n\n return constraints;\n}\n","export default async function getScreenStream(constraints: DisplayMediaStreamConstraints) {\n const screenStream = await navigator.mediaDevices.getDisplayMedia(constraints);\n const track = screenStream.getVideoTracks()[0];\n track.contentHint = 'text';\n return screenStream;\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n * \n * Originally from:\n * https://github.com/evgeny-nadymov/telegram-react\n * Copyright (C) 2018 Evgeny Nadymov\n * https://github.com/evgeny-nadymov/telegram-react/blob/master/LICENSE\n */\n\nexport default class StringFromLineBuilder {\n private lines: string[];\n private newLine: string[];\n\n constructor(private joiner = '\\r\\n') {\n this.lines = [];\n this.newLine = [];\n }\n\n public add(...strs: string[]) {\n this.lines.push(...strs);\n return this;\n }\n\n public push(word: string) {\n this.newLine.push(word);\n return this;\n }\n \n public addJoined(separator = '') {\n this.add(this.newLine.join(separator));\n this.newLine = [];\n return this;\n }\n\n public join() {\n return this.lines.join(this.joiner);\n }\n\n public finalize() {\n return this.join() + this.joiner;\n }\n}\n","// credits to https://github.com/sindresorhus/escape-string-regexp/blob/master/index.js\nexport default function escapeRegExp(str: string) {\n return str\n .replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&')\n .replace(/-/g, '\\\\x2d');\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport forEachReverse from \"../../helpers/array/forEachReverse\";\nimport throttle from \"../../helpers/schedulers/throttle\";\nimport { Updates, PhoneJoinGroupCall, PhoneJoinGroupCallPresentation, Update } from \"../../layer\";\nimport apiUpdatesManager from \"../appManagers/apiUpdatesManager\";\nimport appGroupCallsManager, { GroupCallConnectionType, JoinGroupCallJsonPayload } from \"../appManagers/appGroupCallsManager\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport rootScope from \"../rootScope\";\nimport CallConnectionInstanceBase, { CallConnectionInstanceOptions } from \"./callConnectionInstanceBase\";\nimport GroupCallInstance from \"./groupCallInstance\";\nimport filterServerCodecs from \"./helpers/filterServerCodecs\";\nimport fixLocalOffer from \"./helpers/fixLocalOffer\";\nimport processMediaSection from \"./helpers/processMediaSection\";\nimport { ConferenceEntry } from \"./localConferenceDescription\";\nimport SDP from \"./sdp\";\nimport SDPMediaSection from \"./sdp/mediaSection\";\nimport { WebRTCLineType } from \"./sdpBuilder\";\nimport { UpdateGroupCallConnectionData } from \"./types\";\n\nexport default class GroupCallConnectionInstance extends CallConnectionInstanceBase {\n private groupCall: GroupCallInstance;\n public updateConstraints?: boolean;\n private type: GroupCallConnectionType;\n private options: {\n type: Extract<GroupCallConnectionType, 'main'>, \n isMuted?: boolean, \n joinVideo?: boolean, \n rejoin?: boolean\n } | {\n type: Extract<GroupCallConnectionType, 'presentation'>,\n };\n\n private updateConstraintsInterval: number;\n public negotiateThrottled: () => void;\n\n constructor(options: CallConnectionInstanceOptions & {\n groupCall: GroupCallConnectionInstance['groupCall'],\n type: GroupCallConnectionInstance['type'],\n options: GroupCallConnectionInstance['options'],\n }) {\n super(options);\n\n this.negotiateThrottled = throttle(this.negotiate.bind(this), 0, false);\n }\n\n public createPeerConnection() {\n return this.connection || super.createPeerConnection({ \n iceServers: [], \n iceTransportPolicy: 'all', \n bundlePolicy: 'max-bundle', \n rtcpMuxPolicy: 'require', \n iceCandidatePoolSize: 0, \n // sdpSemantics: \"unified-plan\", \n // extmapAllowMixed: true,\n });\n }\n\n public createDataChannel() {\n if(this.dataChannel) {\n return this.dataChannel;\n }\n\n const dataChannel = super.createDataChannel();\n\n dataChannel.addEventListener('open', () => {\n this.maybeUpdateRemoteVideoConstraints();\n });\n\n dataChannel.addEventListener('close', () => {\n if(this.updateConstraintsInterval) {\n clearInterval(this.updateConstraintsInterval);\n this.updateConstraintsInterval = undefined;\n }\n });\n\n return dataChannel;\n }\n\n public createDescription() {\n if(this.description) {\n return this.description;\n }\n\n const description = super.createDescription();\n\n /* const perType = 0;\n const types = ['audio' as const, 'video' as const];\n const count = types.length * perType;\n const init: RTCRtpTransceiverInit = {direction: 'recvonly'};\n types.forEach(type => {\n for(let i = 0; i < perType; ++i) {\n description.createEntry(type).createTransceiver(connection, init);\n }\n }); */\n\n return description;\n }\n\n public appendStreamToConference() {\n super.appendStreamToConference();/* .then(() => {\n currentGroupCall.connections.main.negotiating = false;\n this.startNegotiation({\n type: type,\n isMuted: muted,\n rejoin\n });\n }); */\n }\n\n private async invokeJoinGroupCall(localSdp: SDP, mainChannels: SDPMediaSection[], options: GroupCallConnectionInstance['options']) {\n const {groupCall, description} = this;\n const groupCallId = groupCall.id;\n\n const processedChannels = mainChannels.map(section => {\n const processed = processMediaSection(localSdp, section);\n\n this.sources[processed.entry.type as 'video' | 'audio'] = processed.entry;\n \n return processed;\n });\n\n let promise: Promise<Updates>;\n const audioChannel = processedChannels.find(channel => channel.media.mediaType === 'audio');\n const videoChannel = processedChannels.find(channel => channel.media.mediaType === 'video');\n let {source, params} = audioChannel || {};\n const useChannel = videoChannel || audioChannel;\n\n const channels: {[type in WebRTCLineType]?: typeof audioChannel} = {\n audio: audioChannel,\n video: videoChannel\n };\n\n description.entries.forEach(entry => {\n if(entry.direction === 'sendonly') {\n const channel = channels[entry.type];\n if(!channel) return;\n\n description.setEntrySource(entry, channel.sourceGroups || channel.source);\n description.setEntryPeerId(entry, rootScope.myId);\n }\n });\n\n // overwrite ssrc with audio in video params\n if(params !== useChannel.params) {\n const data: JoinGroupCallJsonPayload = JSON.parse(useChannel.params.data);\n // data.ssrc = source || data.ssrc - 1; // audio channel can be missed in screensharing\n if(source) data.ssrc = source;\n else delete data.ssrc;\n params = {\n _: 'dataJSON',\n data: JSON.stringify(data)\n };\n }\n \n const groupCallInput = appGroupCallsManager.getGroupCallInput(groupCallId);\n if(options.type === 'main') {\n const request: PhoneJoinGroupCall = {\n call: groupCallInput,\n join_as: {_: 'inputPeerSelf'},\n params,\n muted: options.isMuted,\n video_stopped: !options.joinVideo\n };\n\n promise = apiManager.invokeApi('phone.joinGroupCall', request);\n this.log(`[api] joinGroupCall id=${groupCallId}`, request);\n } else {\n const request: PhoneJoinGroupCallPresentation = {\n call: groupCallInput,\n params,\n };\n\n promise = apiManager.invokeApi('phone.joinGroupCallPresentation', request);\n this.log(`[api] joinGroupCallPresentation id=${groupCallId}`, request);\n }\n\n const updates = await promise;\n apiUpdatesManager.processUpdateMessage(updates);\n const update = (updates as Updates.updates).updates.find(update => update._ === 'updateGroupCallConnection') as Update.updateGroupCallConnection;\n\n const data: UpdateGroupCallConnectionData = JSON.parse(update.params.data);\n\n data.audio = data.audio || groupCall.connections.main.description.audio;\n description.setData(data);\n filterServerCodecs(mainChannels, data);\n\n return data;\n }\n\n protected async negotiateInternal() {\n const {connection, description} = this;\n const isNewConnection = connection.iceConnectionState === 'new' && !description.getEntryByMid('0').source;\n const log = this.log.bindPrefix('startNegotiation');\n log('start');\n \n const originalOffer = await connection.createOffer({iceRestart: false});\n\n if(isNewConnection && this.dataChannel) {\n const dataChannelEntry = description.createEntry('application');\n dataChannelEntry.setDirection('sendrecv');\n }\n\n const {sdp: localSdp, offer} = fixLocalOffer({\n offer: originalOffer, \n data: description\n });\n\n log('[sdp] setLocalDescription', offer.sdp);\n await connection.setLocalDescription(offer);\n\n const mainChannels = localSdp.media.filter(media => {\n return media.mediaType !== 'application' && media.isSending;\n });\n\n if(isNewConnection) {\n try {\n await this.invokeJoinGroupCall(localSdp, mainChannels, this.options);\n } catch(e) {\n this.log.error('[tdweb] joinGroupCall error', e);\n }\n }\n \n /* if(!data) {\n log('abort 0');\n this.closeConnectionAndStream(connection, streamManager);\n return;\n } */\n\n /* if(connection.iceConnectionState !== 'new') {\n log(`abort 1 connectionState=${connection.iceConnectionState}`);\n this.closeConnectionAndStream(connection, streamManager);\n return;\n } */\n /* if(this.currentGroupCall !== currentGroupCall || connectionHandler.connection !== connection) {\n log('abort', this.currentGroupCall, currentGroupCall);\n this.closeConnectionAndStream(connection, streamManager);\n return;\n } */\n \n const isAnswer = true;\n // const _bundleMids = bundleMids.slice();\n const entriesToDelete: ConferenceEntry[] = [];\n const bundle = localSdp.bundle;\n forEachReverse(bundle, (mid, idx, arr) => {\n const entry = description.getEntryByMid(mid);\n if(entry.shouldBeSkipped(isAnswer)) {\n arr.splice(idx, 1);\n entriesToDelete.push(entry);\n }\n });\n\n /* forEachReverse(description.entries, (entry, idx, arr) => {\n const mediaSection = _parsedSdp.media.find(section => section.oa.get('mid').oa === entry.mid);\n const deleted = !mediaSection;\n // const deleted = !_bundleMids.includes(entry.mid); // ! can't use it because certain mid can be missed in bundle\n if(deleted) {\n arr.splice(idx, 1);\n }\n }); */\n\n const entries = localSdp.media.map((section) => {\n const mid = section.mid;\n let entry = description.getEntryByMid(mid);\n if(!entry) {\n entry = new ConferenceEntry(mid, section.mediaType);\n entry.setDirection('inactive');\n }\n\n return entry;\n });\n\n const answerDescription: RTCSessionDescriptionInit = {\n type: 'answer',\n sdp: description.generateSdp({\n bundle, \n entries, \n isAnswer\n })\n };\n\n entriesToDelete.forEach(entry => {\n description.deleteEntry(entry);\n });\n\n log(`[sdp] setRemoteDescription signaling=${connection.signalingState} ice=${connection.iceConnectionState} gathering=${connection.iceGatheringState} connection=${connection.connectionState}`, answerDescription.sdp);\n await connection.setRemoteDescription(answerDescription);\n\n log('end');\n }\n\n public negotiate() {\n let promise = this.negotiating;\n if(promise) {\n return promise;\n }\n\n promise = super.negotiate();\n\n if(this.updateConstraints) {\n promise.then(() => {\n this.maybeUpdateRemoteVideoConstraints();\n this.updateConstraints = false;\n });\n }\n\n if(this.options.type === 'presentation') {\n promise.then(() => {\n this.connection.getTransceivers().find(transceiver => {\n if(transceiver.sender?.track?.kind === 'video') {\n transceiver.sender.setParameters({\n ...transceiver.sender.getParameters(),\n degradationPreference: 'maintain-resolution'\n });\n }\n });\n });\n }\n\n return promise;\n }\n\n public maybeUpdateRemoteVideoConstraints() {\n if(this.dataChannel.readyState !== 'open') {\n return;\n }\n\n this.log('maybeUpdateRemoteVideoConstraints');\n \n // * https://github.com/TelegramMessenger/tgcalls/blob/6f2746e04c9b040f8c8dfc64d916a1853d09c4ce/tgcalls/group/GroupInstanceCustomImpl.cpp#L2549\n type VideoConstraints = {minHeight?: number, maxHeight: number};\n const obj: {\n colibriClass: 'ReceiverVideoConstraints',\n constraints: {[endpoint: string]: VideoConstraints},\n defaultConstraints: VideoConstraints,\n onStageEndpoints: string[]\n } = {\n colibriClass: 'ReceiverVideoConstraints',\n constraints: {},\n defaultConstraints: {maxHeight: 0},\n onStageEndpoints: []\n };\n\n for(const entry of this.description.entries) {\n if(entry.direction !== 'recvonly' || entry.type !== 'video') {\n continue;\n }\n\n const {endpoint} = entry;\n obj.onStageEndpoints.push(endpoint);\n obj.constraints[endpoint] = {\n minHeight: 180,\n maxHeight: 720\n };\n }\n\n this.sendDataChannelData(obj);\n\n if(!obj.onStageEndpoints.length) {\n if(this.updateConstraintsInterval) {\n clearInterval(this.updateConstraintsInterval);\n this.updateConstraintsInterval = undefined;\n }\n } else if(!this.updateConstraintsInterval) {\n this.updateConstraintsInterval = window.setInterval(this.maybeUpdateRemoteVideoConstraints.bind(this), 5000);\n }\n }\n \n public addInputVideoStream(stream: MediaStream) {\n // const {sources} = this;\n // if(sources?.video) {\n // const source = this.sources.video.source;\n // stream.source = '' + source;\n this.groupCall.saveInputVideoStream(stream, this.type);\n // }\n\n this.streamManager.addStream(stream, 'input');\n this.appendStreamToConference(); // replace sender track\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { DataJSON } from \"../../../layer\";\nimport { JoinGroupCallJsonPayload } from \"../../appManagers/appGroupCallsManager\";\nimport SDP from \"../sdp\";\nimport { Ssrc } from \"../types\";\nimport parseMediaSectionInfo from \"./parseMediaSectionInfo\";\n\nexport default function processMediaSection(sdp: SDP, media: SDP['media'][0]) {\n const sectionInfo = parseMediaSectionInfo(sdp, media);\n\n const mediaType: Exclude<typeof media['mediaType'], 'application'> = media.mediaType as any;\n const entry: Ssrc = {\n source: sectionInfo.source,\n sourceGroups: sectionInfo.sourceGroups,\n type: mediaType\n };\n\n // do not change this value, otherwise onconnectionstatechange won't fire\n sectionInfo.fingerprint.setup = 'active';\n const payload: JoinGroupCallJsonPayload = {\n fingerprints: [sectionInfo.fingerprint],\n pwd: sectionInfo.pwd,\n ssrc: sectionInfo.source,\n 'ssrc-groups': sectionInfo.sourceGroups || [],\n ufrag: sectionInfo.ufrag\n };\n const paramsDataJson = JSON.stringify(payload);\n\n const params: DataJSON = {\n _: 'dataJSON',\n data: paramsDataJson\n };\n\n return {\n params, \n source: sectionInfo.source, \n media, \n sourceGroups: sectionInfo.sourceGroups, \n entry\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport forEachReverse from \"../../../helpers/array/forEachReverse\";\nimport SDPMediaSection from \"../sdp/mediaSection\";\nimport { UpdateGroupCallConnectionData, Codec } from \"../types\";\n\nexport default function filterServerCodecs(mainChannels: SDPMediaSection[], data: UpdateGroupCallConnectionData) {\n // ! Need to filter server's extmap for Firefox\n const performExtmap = (channel: typeof mainChannels[0]) => {\n const out: {[id: string]: string} = {};\n const extmap = channel.attributes.get('extmap');\n extmap.forEach((extmap) => {\n const id = extmap.key.split('/', 1)[0];\n out[id] = extmap.value;\n });\n\n return out;\n };\n\n const codecsToPerform: [Codec, 'audio' | 'video'][] = /* flatten([data, dataPresentation].filter(Boolean).map(data => {\n return */['audio' as const, 'video' as const].filter(type => data[type]).map(type => ([data[type], type]));\n // }));\n\n codecsToPerform.forEach(([codec, type]) => {\n const channel = mainChannels.find(line => line.mediaType === type);\n if(!channel) {\n return;\n }\n\n const extmap = performExtmap(channel);\n forEachReverse(codec[\"rtp-hdrexts\"], (value, index, arr) => {\n if(extmap[value.id] !== value.uri) {\n arr.splice(index, 1);\n console.log(`[sdp] filtered extmap:`, value, index, type);\n }\n });\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport forEachReverse from \"../../../helpers/array/forEachReverse\";\nimport copy from \"../../../helpers/object/copy\";\nimport { ConferenceEntry } from \"../localConferenceDescription\";\nimport { parseSdp, addSimulcast } from \"../sdp/utils\";\nimport { generateMediaFirstLine, SDPBuilder } from \"../sdpBuilder\";\nimport { UpdateGroupCallConnectionData } from \"../types\";\nimport parseMediaSectionInfo from \"./parseMediaSectionInfo\";\n\nexport default function fixLocalOffer(options: {\n offer: RTCSessionDescriptionInit, \n data: UpdateGroupCallConnectionData,\n skipAddingMulticast?: boolean\n // mids?: string[]\n}) {\n const {offer, data} = options;\n const sdp = parseSdp(offer.sdp);\n let hasMunged = false;\n\n if(!options.skipAddingMulticast) {\n hasMunged = addSimulcast(sdp) || hasMunged;\n }\n\n // const bundleLine = parsedSdp.session.lines.find(line => line.Ha?.key === 'group');\n // const bundleMids = bundleLine.value.split(' ').slice(1);\n\n forEachReverse(sdp.media, (section, idx, arr) => {\n // const mid = section.oa.get('mid').oa;\n\n // это может случиться при выключении и включении видео. почему-то появится секция уже удалённая\n // ! нельзя тут модифицировать локальное описание, будет критовать\n /* if(mids && !mids.includes(mid) && !bundleMids.includes(mid)) {\n console.error('wtf');\n hasMunged = true;\n arr.splice(idx, 1);\n return;\n } */\n\n if(/* section.mediaType !== 'video' || */section.isSending) {\n return;\n }\n\n if(section.mediaType === 'application') {\n return;\n }\n\n const mediaLine = section.mediaLine;\n const mediaLineParts = mediaLine.mediaLineParts;\n const mediaCodecIds = mediaLineParts.ids;\n const localMLine = mediaLine.toString();\n\n const codec = data[section.mediaType];\n const payloadTypes = codec['payload-types'];\n\n /* forEachReverse(payloadTypes, (payloadType, idx, arr) => {\n if(!mediaCodecIds.includes('' + payloadType.id) && section.mediaType === 'video') {\n // if(payloadType.name === 'H265') {\n console.warn('[sdp] filtered unsupported codec', payloadType, mediaCodecIds, section.mediaType);\n arr.splice(idx, 1);\n }\n }); */\n\n const codecIds = payloadTypes.map(payload => '' + payload.id);\n const correctMLine = generateMediaFirstLine(section.mediaType, undefined, codecIds);\n \n if(localMLine !== correctMLine) {\n const sectionInfo = parseMediaSectionInfo(sdp, section);\n\n let newData = {...data};\n newData.transport = copy(newData.transport);\n newData.transport.ufrag = sectionInfo.ufrag;\n newData.transport.pwd = sectionInfo.pwd;\n newData.transport.fingerprints = [sectionInfo.fingerprint];\n newData.transport.candidates = [];\n\n const entry = new ConferenceEntry(sectionInfo.mid, mediaLineParts.type);\n entry.setPort(mediaLineParts.port);\n sectionInfo.source && entry.setSource(sectionInfo.sourceGroups || sectionInfo.source);\n entry.setDirection(section.direction);\n\n const newSdp = new SDPBuilder().addSsrcEntry(entry, newData).finalize();\n\n const newChannel = parseSdp(newSdp).media[0];\n arr[idx] = newChannel;\n\n hasMunged = true;\n }\n });\n\n if(hasMunged) {\n const mungedSdp = sdp.toString();\n offer.sdp = mungedSdp;\n }\n\n return {offer, sdp/* , bundleMids */};\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { IS_SAFARI } from \"../../environment/userAgent\";\nimport indexOfAndSplice from \"../../helpers/array/indexOfAndSplice\";\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport throttle from \"../../helpers/schedulers/throttle\";\nimport { GroupCall, GroupCallParticipant, Updates } from \"../../layer\";\nimport apiUpdatesManager from \"../appManagers/apiUpdatesManager\";\nimport appGroupCallsManager, { GroupCallConnectionType, GroupCallId, GroupCallOutputSource } from \"../appManagers/appGroupCallsManager\";\nimport appPeersManager from \"../appManagers/appPeersManager\";\nimport { logger } from \"../logger\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport { NULL_PEER_ID } from \"../mtproto/mtproto_config\";\nimport rootScope from \"../rootScope\";\nimport CallInstanceBase, { TryAddTrackOptions } from \"./callInstanceBase\";\nimport GroupCallConnectionInstance from \"./groupCallConnectionInstance\";\nimport GROUP_CALL_STATE from \"./groupCallState\";\nimport getScreenConstraints from \"./helpers/getScreenConstraints\";\nimport getScreenStream from \"./helpers/getScreenStream\";\nimport getStream from \"./helpers/getStream\";\nimport getVideoConstraints from \"./helpers/getVideoConstraints\";\nimport stopTrack from \"./helpers/stopTrack\";\nimport localConferenceDescription from \"./localConferenceDescription\";\nimport { WebRTCLineType } from \"./sdpBuilder\";\nimport StreamManager from \"./streamManager\";\nimport { Ssrc } from \"./types\";\n\nexport default class GroupCallInstance extends CallInstanceBase<{\n state: (state: GROUP_CALL_STATE) => void,\n pinned: (source?: GroupCallOutputSource) => void,\n}> {\n public id: GroupCallId;\n public chatId: ChatId;\n public handleUpdateGroupCallParticipants: boolean;\n public updatingSdp: boolean;\n public isSpeakingMap: Map<any, any>;\n public connections: {[k in GroupCallConnectionType]?: GroupCallConnectionInstance};\n public groupCall: GroupCall;\n public participant: GroupCallParticipant;\n \n // will be set with negotiation\n public joined: boolean;\n \n private pinnedSources: Array<GroupCallOutputSource>;\n private participantsSsrcs: Map<PeerId, Ssrc[]>;\n private hadAutoPinnedSources: Set<GroupCallOutputSource>;\n private dispatchPinnedThrottled: () => void;\n private startVideoSharingPromise: Promise<void>;\n private startScreenSharingPromise: Promise<void>;\n\n constructor(options: {\n id: GroupCallInstance['id'],\n chatId: GroupCallInstance['chatId'],\n isSpeakingMap?: GroupCallInstance['isSpeakingMap'],\n connections?: GroupCallInstance['connections']\n }) {\n super();\n\n safeAssign(this, options);\n\n if(!this.log) {\n this.log = logger('GROUP-CALL');\n }\n\n if(!this.connections) {\n this.connections = {};\n }\n\n if(!this.isSpeakingMap) {\n this.isSpeakingMap = new Map();\n }\n\n this.pinnedSources = [];\n this.participantsSsrcs = new Map();\n this.hadAutoPinnedSources = new Set();\n this.dispatchPinnedThrottled = throttle(() => {\n this.dispatchEvent('pinned', this.pinnedSource);\n }, 0, false);\n\n this.addEventListener('state', (state) => {\n if(state === GROUP_CALL_STATE.CLOSED) {\n this.cleanup();\n }\n });\n }\n\n get connectionState() {\n return this.connections.main.connection.iceConnectionState;\n }\n\n get state() {\n const {connectionState} = this;\n if(connectionState === 'closed') {\n return GROUP_CALL_STATE.CLOSED;\n } else if(connectionState !== 'connected' && (!IS_SAFARI || connectionState !== 'completed')) {\n return GROUP_CALL_STATE.CONNECTING;\n } else {\n const {participant} = this;\n if(!participant.pFlags.can_self_unmute) {\n return GROUP_CALL_STATE.MUTED_BY_ADMIN;\n } else if(participant.pFlags.muted) {\n return GROUP_CALL_STATE.MUTED;\n } else {\n return GROUP_CALL_STATE.UNMUTED;\n }\n }\n }\n\n get participants() {\n return appGroupCallsManager.getCachedParticipants(this.id);\n }\n\n get isSharingScreen() {\n return !!this.connections.presentation;\n }\n\n get pinnedSource() {\n return this.pinnedSources[this.pinnedSources.length - 1];\n }\n\n public get isMuted() {\n return this.state !== GROUP_CALL_STATE.UNMUTED;\n }\n\n public get isClosing() {\n const {state} = this;\n return state === GROUP_CALL_STATE.CLOSED;\n }\n\n public get streamManager(): StreamManager {\n return this.connections.main.streamManager;\n }\n\n public get description(): localConferenceDescription {\n return this.connections.main.description;\n }\n\n public pinSource(source: GroupCallOutputSource) {\n indexOfAndSplice(this.pinnedSources, source);\n this.pinnedSources.push(source);\n this.dispatchPinnedThrottled();\n }\n\n public unpinSource(source: GroupCallOutputSource) {\n this.hadAutoPinnedSources.delete(source);\n indexOfAndSplice(this.pinnedSources, source);\n this.dispatchPinnedThrottled();\n }\n\n public unpinAll() {\n this.pinnedSources.length = 0;\n this.dispatchPinnedThrottled();\n }\n\n public getParticipantByPeerId(peerId: PeerId) {\n return NULL_PEER_ID === peerId ? this.participant : this.participants.get(peerId);\n }\n\n public toggleMuted() {\n return this.requestAudioSource(true).then(() => appGroupCallsManager.toggleMuted());\n }\n\n public getElement(endpoint: GroupCallOutputSource) {\n return super.getElement(endpoint);\n }\n\n public getVideoElementFromParticipantByType(participant: GroupCallParticipant, type: 'video' | 'presentation') {\n let source: GroupCallOutputSource;\n if(participant.pFlags.self) {\n const connectionType: GroupCallConnectionType = type === 'video' ? 'main' : 'presentation';\n source = connectionType;\n } else {\n const codec = participant[type];\n source = codec.source_groups[0].sources[0];\n }\n\n const element = this.getElement(source) as HTMLVideoElement;\n if(!element) return;\n\n const clone = element.cloneNode() as typeof element;\n clone.srcObject = element.srcObject;\n return {video: clone, source};\n }\n\n public createConnectionInstance(options: {\n streamManager: StreamManager,\n type: GroupCallConnectionType,\n options: GroupCallConnectionInstance['options'],\n }) {\n return this.connections[options.type] = new GroupCallConnectionInstance({\n groupCall: this,\n log: this.log.bindPrefix(options.type),\n ...options\n });\n }\n\n public changeRaiseHand(raise: boolean) {\n return appGroupCallsManager.editParticipant(this.id, this.participant, {raiseHand: raise});\n }\n\n public async startScreenSharingInternal() {\n try {\n const type: GroupCallConnectionType = 'presentation';\n\n const stream = await getScreenStream(getScreenConstraints());\n const streamManager = new StreamManager();\n \n const connectionInstance = this.createConnectionInstance({\n streamManager,\n type,\n options: {\n type\n }\n });\n \n const connection = connectionInstance.createPeerConnection();\n connection.addEventListener('negotiationneeded', () => {\n connectionInstance.negotiate();\n });\n\n stream.getVideoTracks()[0].addEventListener('ended', () => {\n if(this.connections.presentation) { // maybe user has stopped screensharing through browser's ui\n this.stopScreenSharing();\n }\n }, {once: true});\n \n connectionInstance.createDescription();\n connectionInstance.addInputVideoStream(stream);\n } catch(err) {\n this.log.error('start screen sharing error', err);\n }\n }\n\n public startScreenSharing() {\n return this.startScreenSharingPromise || (this.startScreenSharingPromise = this.startScreenSharingInternal().finally(() => {\n this.startScreenSharingPromise = undefined;\n }));\n }\n\n public stopScreenSharing() {\n const connectionInstance = this.connections.presentation;\n if(!connectionInstance) {\n return Promise.resolve();\n }\n\n delete this.connections.presentation;\n this.unpinSource('presentation');\n connectionInstance.closeConnectionAndStream(true);\n\n delete this.participant.presentation;\n appGroupCallsManager.saveApiParticipant(this.id, this.participant);\n\n return apiManager.invokeApi('phone.leaveGroupCallPresentation', {\n call: appGroupCallsManager.getGroupCallInput(this.id)\n }).then(updates => {\n apiUpdatesManager.processUpdateMessage(updates);\n });\n }\n\n public toggleScreenSharing() {\n if(this.isSharingScreen) {\n return this.stopScreenSharing();\n } else {\n return this.startScreenSharing();\n }\n }\n\n public async startVideoSharingInternal() {\n const constraints: MediaStreamConstraints = {\n video: getVideoConstraints()\n };\n\n try {\n const stream = await getStream(constraints, false);\n const connectionInstance = this.connections.main;\n connectionInstance.addInputVideoStream(stream);\n\n await appGroupCallsManager.editParticipant(this.id, this.participant, {\n videoPaused: false,\n videoStopped: false\n });\n } catch(err) {\n this.log.error('startVideoSharing error', err, constraints);\n }\n }\n\n public startVideoSharing() {\n return this.startVideoSharingPromise || (this.startVideoSharingPromise = this.startVideoSharingInternal().finally(() => {\n this.startVideoSharingPromise = undefined;\n }));\n }\n\n public async stopVideoSharing() {\n const connectionInstance = this.connections.main;\n const track = connectionInstance.streamManager.inputStream.getVideoTracks()[0];\n if(!track) {\n return;\n }\n\n stopTrack(track);\n connectionInstance.streamManager.appendToConference(connectionInstance.description); // clear sender track\n\n await appGroupCallsManager.editParticipant(this.id, this.participant, {\n videoStopped: true\n });\n }\n\n public toggleVideoSharing() {\n if(this.isSharingVideo) {\n return this.stopVideoSharing();\n } else {\n return this.startVideoSharing();\n }\n }\n\n public async hangUp(discard = false, rejoin = false, isDiscarded = false) {\n for(const type in this.connections) {\n const connection = this.connections[type as GroupCallConnectionType];\n connection.closeConnectionAndStream(!rejoin);\n }\n\n this.dispatchEvent('state', this.state);\n\n if(isDiscarded) {\n return;\n }\n \n if(!rejoin) {\n let promise: Promise<Updates>;\n const groupCallInput = appGroupCallsManager.getGroupCallInput(this.id);\n\n if(discard) {\n this.log(`[api] discardGroupCall id=${this.id}`);\n promise = apiManager.invokeApi('phone.discardGroupCall', {\n call: groupCallInput\n });\n } else if(this.joined) {\n this.log(`[api] leaveGroupCall id=${this.id}`);\n const connectionInstance = this.connections.main;\n promise = apiManager.invokeApi('phone.leaveGroupCall', {\n call: groupCallInput,\n source: connectionInstance.sources.audio.source\n });\n } else {\n this.log(`[api] id=${this.id} payload=null`);\n promise = apiManager.invokeApi('phone.joinGroupCall', {\n call: groupCallInput,\n join_as: {_: 'inputPeerSelf'},\n muted: true,\n video_stopped: true,\n params: {\n _: 'dataJSON',\n data: ''\n }\n });\n }\n\n const updates = await promise;\n apiUpdatesManager.processUpdateMessage(updates);\n }\n }\n\n public tryAddTrack(options: Omit<TryAddTrackOptions, 'streamManager'>) {\n const {description} = this;\n const source = super.tryAddTrack(options);\n \n if(options.type === 'output') {\n const entry = description.getEntryBySource(+source);\n const participant = this.participants.get(entry.peerId);\n if(participant) {\n rootScope.dispatchEvent('group_call_participant', {groupCallId: this.id, participant});\n }\n }\n\n return source;\n }\n\n public onParticipantUpdate(participant: GroupCallParticipant, doNotDispatchParticipantUpdate?: PeerId) {\n const connectionInstance = this.connections.main;\n const {connection, description} = connectionInstance;\n\n const peerId = appPeersManager.getPeerId(participant.peer);\n const hasLeft = !!participant.pFlags.left;\n const oldSsrcs = this.participantsSsrcs.get(peerId) || [];\n\n if(participant.presentation && !hasLeft) {\n const {source} = appGroupCallsManager.makeSsrcFromParticipant(participant, 'video', participant.presentation.source_groups, participant.presentation.endpoint);\n if(!this.hadAutoPinnedSources.has(source)) {\n this.hadAutoPinnedSources.add(source);\n this.pinSource(participant.pFlags.self ? 'presentation' : source);\n }\n }\n\n if(participant.pFlags.self) {\n this.participant = participant;\n\n if(connectionInstance.sources.audio.source !== participant.source) {\n this.hangUp();\n }\n\n let mute = false;\n if(!participant.pFlags.can_self_unmute) {\n this.stopScreenSharing();\n this.stopVideoSharing();\n mute = true;\n } else if(participant.pFlags.muted) {\n mute = true;\n }\n\n if(mute) {\n this.setMuted(true);\n }\n\n if(doNotDispatchParticipantUpdate !== peerId) {\n this.dispatchEvent('state', this.state);\n }\n\n return;\n }\n\n const ssrcs = hasLeft ? [] : appGroupCallsManager.makeSsrcsFromParticipant(participant);\n\n if(!hasLeft) {\n this.participantsSsrcs.set(peerId, ssrcs);\n } else {\n this.participantsSsrcs.delete(peerId);\n }\n\n // const TEST_OLD = false;\n\n const modifiedTypes: Set<WebRTCLineType> = new Set();\n oldSsrcs.forEach(oldSsrc => {\n const oldSource = oldSsrc.source;\n const newSsrc = ssrcs.find(ssrc => ssrc.source === oldSource);\n if(!newSsrc) {\n this.unpinSource(oldSource);\n\n const oldEntry = description.getEntryBySource(oldSource);\n if(oldEntry && oldEntry.direction !== 'inactive') {\n oldEntry.setDirection('inactive');\n modifiedTypes.add(oldEntry.type);\n }\n }\n });\n\n ssrcs.forEach(ssrc => {\n let entry = description.getEntryBySource(ssrc.source);\n if(entry) {\n if(entry.direction === 'inactive') {\n entry.setDirection(entry.originalDirection);\n modifiedTypes.add(entry.type);\n }\n\n return;\n }\n\n entry = description.createEntry(ssrc.type);\n description.setEntrySource(entry, ssrc.sourceGroups || ssrc.source);\n description.setEntryPeerId(entry, peerId);\n\n // if(TEST_OLD) {\n // description.bundleMids.push(entry.mid);\n // entry.setDirection('recvonly');\n // } else {\n ssrc.type === 'video' && entry.setEndpoint(ssrc.endpoint);\n entry.createTransceiver(connection, {direction: 'recvonly'});\n // }\n\n modifiedTypes.add(entry.type);\n });\n\n /* if(TEST_OLD) {\n this.setRemoteOffer({\n connection,\n description,\n ssrcs\n });\n } else */if(modifiedTypes.size) {\n if(modifiedTypes.has('video')) {\n connectionInstance.updateConstraints = true;\n }\n\n connectionInstance.negotiateThrottled();\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport safeAssign from \"../../helpers/object/safeAssign\";\nimport { logger } from \"../logger\";\nimport createDataChannel from \"./helpers/createDataChannel\";\nimport createPeerConnection from \"./helpers/createPeerConnection\";\nimport LocalConferenceDescription from \"./localConferenceDescription\";\nimport StreamManager from \"./streamManager\";\nimport { Ssrc } from \"./types\";\n\nexport type CallConnectionInstanceOptions = {\n streamManager: StreamManager,\n connection?: RTCPeerConnection,\n log?: ReturnType<typeof logger>\n};\n\nexport default abstract class CallConnectionInstanceBase {\n public connection: RTCPeerConnection;\n public streamManager: StreamManager;\n public dataChannel: RTCDataChannel;\n public description: LocalConferenceDescription;\n public sources: {\n audio: Ssrc,\n video?: Ssrc,\n };\n protected negotiating: Promise<void>;\n protected log: ReturnType<typeof logger>;\n\n constructor(options: CallConnectionInstanceOptions) {\n safeAssign(this, options);\n\n if(!this.log) {\n this.log = this.connection?.log || logger('CALL-CONNECTION-BASE');\n }\n\n this.sources = {} as any;\n }\n\n public createPeerConnection(config?: RTCConfiguration) {\n return this.connection || (this.connection = createPeerConnection(config, this.log.bindPrefix('connection')).connection);\n }\n\n public createDataChannel(dict?: RTCDataChannelInit) {\n return this.dataChannel || (this.dataChannel = createDataChannel(this.connection, dict, this.log.bindPrefix('data')));\n }\n\n public createDescription() {\n return this.description || (this.description = new LocalConferenceDescription(this.connection));\n }\n\n public appendStreamToConference() {\n return this.streamManager.appendToConference(this.description);\n }\n\n public closeConnection() {\n const {connection} = this;\n if(!connection) {\n return;\n }\n\n try {\n connection.log('close');\n connection.close();\n } catch(e) {\n this.log.error(e);\n }\n }\n\n public closeConnectionAndStream(stopStream: boolean) {\n this.closeConnection();\n stopStream && this.streamManager.stop();\n }\n\n protected abstract negotiateInternal(): CallConnectionInstanceBase['negotiating'];\n\n public negotiate() {\n let promise = this.negotiating;\n if(promise) {\n return promise;\n }\n\n return this.negotiating = this.negotiateInternal().finally(() => {\n this.negotiating = undefined;\n });\n }\n\n public sendDataChannelData(data: any) {\n if(this.dataChannel.readyState !== 'open') {\n return;\n }\n\n this.dataChannel.send(JSON.stringify(data));\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { Logger, logger } from \"../../logger\";\n\nexport default function createPeerConnection(config: RTCConfiguration, log?: Logger) {\n if(!log) {\n log = logger('RTCPeerConnection');\n }\n\n log('constructor');\n\n // @ts-ignore\n const connection = new RTCPeerConnection(config);\n connection.addEventListener('track', (event) => {\n log('ontrack', event);\n });\n connection.addEventListener('signalingstatechange', () => {\n log('onsignalingstatechange', connection.signalingState);\n });\n connection.addEventListener('connectionstatechange', () => {\n log('onconnectionstatechange', connection.connectionState);\n });\n connection.addEventListener('negotiationneeded', () => { // * will be fired every time input device changes\n log('onnegotiationneeded', connection.signalingState);\n });\n connection.addEventListener('icecandidate', (event) => {\n log('onicecandidate', event);\n });\n connection.addEventListener('iceconnectionstatechange', () => {\n log('oniceconnectionstatechange', connection.iceConnectionState);\n });\n connection.addEventListener('datachannel', () => {\n log('ondatachannel');\n });\n\n connection.log = log;\n\n return {connection};\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { Logger, logger } from \"../../logger\";\n\nexport default function createDataChannel(connection: RTCPeerConnection, dict?: RTCDataChannelInit, log?: Logger) {\n // return;\n\n if(!log) {\n log = logger('RTCDataChannel');\n }\n\n const channel = connection.createDataChannel('data', dict);\n\n channel.addEventListener('message', (e) => {\n log('onmessage', e);\n });\n channel.addEventListener('open', () => {\n log('onopen');\n });\n channel.addEventListener('close', () => {\n log('onclose');\n });\n\n channel.log = log;\n\n return channel;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport I18n, { i18n, join, LangPackKey } from \"../lib/langPack\";\r\nimport formatDuration, { DurationType } from \"./formatDuration\";\r\n\r\nconst CALL_DURATION_LANG_KEYS: {[type in DurationType]: LangPackKey} = {\r\n s: 'Seconds',\r\n m: 'Minutes',\r\n h: 'Hours',\r\n d: 'Days',\r\n w: 'Weeks'\r\n};\r\nexport default function formatCallDuration(duration: number, plain?: boolean) {\r\n const a = formatDuration(duration, 2);\r\n if(plain) {\r\n const strings = a.map(d => I18n.format(CALL_DURATION_LANG_KEYS[d.type], true, [d.duration]));\r\n return join(strings, false, plain);\r\n }\r\n\r\n const elements = a.map(d => i18n(CALL_DURATION_LANG_KEYS[d.type], [d.duration]));\r\n\r\n const fragment = document.createElement('span');\r\n fragment.append(...join(elements, false));\r\n\r\n return fragment;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport type DurationType = 's' | 'm' | 'h' | 'd' | 'w';\r\nexport default function formatDuration(duration: number, showLast = 2) {\r\n if(!duration) {\r\n duration = 1;\r\n }\r\n\r\n let d: {duration: number, type: DurationType}[] = [];\r\n const p = [\r\n {m: 1, t: 's'},\r\n {m: 60, t: 'm'}, \r\n {m: 60, t: 'h'}, \r\n {m: 24, t: 'd'}, \r\n {m: 7, t: 'w'}\r\n ] as Array<{m?: number, t: DurationType}>\r\n const s = 1;\r\n let t = s;\r\n p.forEach((o, idx) => {\r\n t *= o.m;\r\n\r\n if(duration < t) {\r\n return;\r\n }\r\n\r\n const modulus = p[idx === (p.length - 1) ? idx : idx + 1].m;\r\n d.push({\r\n duration: (duration / t % modulus | 0),\r\n type: o.t\r\n });\r\n });\r\n\r\n const out = d.slice(-showLast).reverse();\r\n for(let i = out.length - 1; i >= 0; --i) {\r\n if(out[i].duration === 0) {\r\n out.splice(i, 1);\r\n }\r\n }\r\n \r\n return out;\r\n}\r\n","import { IS_APPLE_MOBILE, IS_SAFARI } from \"./userAgent\";\n\n// mov is not supported in Chrome on macOS\nconst IS_MOV_SUPPORTED = !!document.createElement('video').canPlayType('video/quicktime') || IS_SAFARI || IS_APPLE_MOBILE;\n\nexport default IS_MOV_SUPPORTED;\n","import IS_MOV_SUPPORTED from \"./movSupport\";\n\nconst VIDEO_MIME_TYPES_SUPPORTED = new Set([\n 'image/gif', // have to display it as video\n 'video/mp4',\n 'video/webm'\n]);\n\nif(IS_MOV_SUPPORTED) {\n VIDEO_MIME_TYPES_SUPPORTED.add('video/quicktime');\n}\n\nexport default VIDEO_MIME_TYPES_SUPPORTED;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport getScreenStream from \"./getScreenStream\";\nimport getStream from \"./getStream\";\n\n/**\n * ! Use multiple constraints together only with first invoke\n */\nexport default function getStreamCached() {\n const _cache: {\n main: Partial<{\n audio: Promise<MediaStream>,\n video: Promise<MediaStream>\n }>,\n screen: Partial<{\n audio: Promise<MediaStream>,\n video: Promise<MediaStream>\n }>\n } = {\n main: {},\n screen: {}\n };\n\n return async(options: {\n isScreen: true, \n constraints: DisplayMediaStreamConstraints,\n } | {\n isScreen?: false,\n constraints: MediaStreamConstraints, \n muted: boolean\n }) => {\n const {isScreen, constraints} = options;\n const cache = _cache[isScreen ? 'screen' : 'main'];\n let promise: Promise<MediaStream> = cache[constraints.audio ? 'audio' : 'video'];\n\n if(!promise) {\n promise = (isScreen ? getScreenStream : getStream)(constraints, (options as any).muted);\n if(constraints.audio && !cache.audio) cache.audio = promise.finally(() => cache.audio = undefined);\n if(constraints.video && !cache.video) cache.video = promise.finally(() => cache.video = undefined);\n }\n\n try {\n return await promise;\n /* let out: Partial<{\n audio: MediaStream,\n video: MediaStream\n }> = {};\n\n await Promise.all([\n constraints.audio && cache.audio.then(stream => out.audio = stream),\n constraints.video && cache.video.then(stream => out.video = stream)\n ].filter(Boolean));\n\n return out; */\n } catch(err) {\n throw err;\n }\n };\n}\n\n(window as any).getStreamCached = getStreamCached;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport EventListenerBase, { EventListenerListeners } from \"../../helpers/eventListenerBase\";\nimport noop from \"../../helpers/noop\";\nimport { logger } from \"../logger\";\nimport getAudioConstraints from \"./helpers/getAudioConstraints\";\nimport getScreenConstraints from \"./helpers/getScreenConstraints\";\nimport getStreamCached from \"./helpers/getStreamCached\";\nimport getVideoConstraints from \"./helpers/getVideoConstraints\";\nimport stopTrack from \"./helpers/stopTrack\";\nimport LocalConferenceDescription from \"./localConferenceDescription\";\nimport StreamManager, { StreamItem } from \"./streamManager\";\n\nexport type TryAddTrackOptions = {\n stream: MediaStream, \n track: MediaStreamTrack, \n type: StreamItem['type'], \n source?: string\n};\n\nexport default abstract class CallInstanceBase<E extends EventListenerListeners> extends EventListenerBase<E> {\n protected log: ReturnType<typeof logger>;\n protected outputDeviceId: string;\n\n protected player: HTMLElement;\n protected elements: Map<string, HTMLMediaElement>;\n\n protected audio: HTMLAudioElement;\n // protected fixedSafariAudio: boolean;\n\n protected getStream: ReturnType<typeof getStreamCached>;\n\n constructor() {\n super(false);\n\n const player = this.player = document.createElement('div');\n player.classList.add('call-player');\n player.style.display = 'none';\n document.body.append(player);\n\n this.elements = new Map();\n\n // possible Safari fix\n const audio = this.audio = new Audio();\n audio.autoplay = true;\n audio.volume = 1.0;\n this.player.append(audio);\n this.elements.set('audio', audio);\n\n this.fixSafariAudio();\n\n this.getStream = getStreamCached();\n }\n\n public get isSharingAudio() {\n return !!this.streamManager.hasInputTrackKind('audio');\n }\n\n public get isSharingVideo() {\n return !!this.streamManager.hasInputTrackKind('video');\n }\n\n public abstract get isMuted(): boolean;\n public abstract get isClosing(): boolean;\n\n public fixSafariAudio() {\n // if(this.fixedSafariAudio) return;\n this.audio.play().catch(noop);\n // this.fixedSafariAudio = true;\n }\n\n public requestAudioSource(muted: boolean) {\n return this.requestInputSource(true, false, muted);\n }\n\n public requestInputSource(audio: boolean, video: boolean, muted: boolean) {\n const {streamManager} = this;\n if(streamManager) {\n const isAudioGood = !audio || this.isSharingAudio;\n const isVideoGood = !video || this.isSharingVideo;\n if(isAudioGood && isVideoGood) {\n return Promise.resolve();\n }\n }\n\n const constraints: MediaStreamConstraints = {\n audio: audio && getAudioConstraints(),\n video: video && getVideoConstraints()\n };\n \n return this.getStream({\n constraints, \n muted\n }).then((stream) => {\n this.onInputStream(stream);\n });\n }\n\n public requestScreen() {\n return this.getStream({\n isScreen: true,\n constraints: getScreenConstraints(true)\n }).then((stream) => {\n this.onInputStream(stream);\n });\n }\n\n public getElement(endpoint: number | string) {\n return this.elements.get('' + endpoint);\n }\n\n public abstract get streamManager(): StreamManager;\n public abstract get description(): LocalConferenceDescription;\n public abstract toggleMuted(): Promise<void>;\n\n public cleanup() {\n this.player.textContent = '';\n this.player.remove();\n this.elements.clear();\n\n // can have no connectionInstance but streamManager with input stream\n this.streamManager.stop();\n\n super.cleanup();\n }\n\n public onTrack(event: RTCTrackEvent) {\n this.tryAddTrack({\n stream: event.streams[0], \n track: event.track, \n type: 'output'\n });\n }\n\n public saveInputVideoStream(stream: MediaStream, type?: string) {\n const track = stream.getVideoTracks()[0];\n this.tryAddTrack({\n stream, \n track, \n type: 'input', \n source: type || 'main'\n });\n }\n \n public tryAddTrack({stream, track, type, source}: TryAddTrackOptions) {\n if(!source) {\n source = StreamManager.getSource(stream, type);\n }\n\n this.log('tryAddTrack', stream, track, type, source);\n\n const isOutput = type === 'output';\n\n const {player, elements, streamManager} = this;\n \n const tagName = track.kind as StreamItem['kind'];\n const isVideo = tagName === 'video';\n\n const elementEndpoint = isVideo ? source : tagName;\n let element = elements.get(elementEndpoint);\n\n if(isVideo) {\n track.addEventListener('ended', () => {\n this.log('[track] onended');\n elements.delete(elementEndpoint);\n // element.remove();\n }, {once: true});\n }\n \n if(isOutput) {\n streamManager.addTrack(stream, track, type);\n }\n\n const useStream = isVideo ? stream : streamManager.outputStream;\n if(!element) {\n element = document.createElement(tagName);\n element.autoplay = true;\n element.srcObject = useStream;\n element.volume = 1.0;\n\n if((element as any).sinkId !== 'undefined') {\n const {outputDeviceId} = this;\n if(outputDeviceId) {\n (element as any).setSinkId(outputDeviceId);\n }\n }\n \n if(!isVideo) {\n player.appendChild(element);\n } else {\n element.setAttribute('playsinline', 'true');\n element.muted = true;\n }\n // audio.play();\n\n elements.set(elementEndpoint, element);\n } else {\n if(element.paused) {\n element.play().catch(noop);\n }\n\n // ! EVEN IF MEDIASTREAM IS THE SAME NEW TRACK WON'T PLAY WITHOUT REPLACING IT WHEN NEW PARTICIPANT IS ENTERING !\n // if(element.srcObject !== useStream) {\n element.srcObject = useStream;\n // }\n }\n\n return source;\n }\n\n public setMuted(muted?: boolean) {\n this.streamManager.inputStream.getAudioTracks().forEach((track) => {\n if(track?.kind === 'audio') {\n track.enabled = muted === undefined ? !track.enabled : !muted;\n }\n });\n }\n\n protected onInputStream(stream: MediaStream): void {\n if(!this.isClosing) {\n const videoTracks = stream.getVideoTracks();\n if(videoTracks.length) {\n this.saveInputVideoStream(stream, 'main');\n }\n\n const {streamManager, description} = this;\n streamManager.addStream(stream, 'input');\n \n if(description) {\n streamManager.appendToConference(description);\n }\n } else { // if call is declined earlier than stream appears\n stream.getTracks().forEach(track => {\n stopTrack(track);\n });\n }\n }\n}\n","import constraintSupported, { MyMediaTrackSupportedConstraints } from \"../../../environment/constraintSupport\";\n\nexport default function getAudioConstraints(): MediaTrackConstraints {\n const constraints: MediaTrackConstraints = {\n channelCount: 2\n };\n\n const desirable: (keyof MyMediaTrackSupportedConstraints)[] = [\n 'noiseSuppression',\n 'echoCancellation',\n 'autoGainControl'\n ];\n\n desirable.forEach(constraint => {\n if(constraintSupported(constraint)) {\n // @ts-ignore\n constraints[constraint] = true;\n }\n });\n\n return constraints;\n}\n","export type MyMediaTrackSupportedConstraints = MediaTrackSupportedConstraints & {\n noiseSuppression?: boolean, \n autoGainControl?: boolean\n};\n\nexport default function constraintSupported(constraint: keyof MyMediaTrackSupportedConstraints) {\n return (!!navigator?.mediaDevices?.getSupportedConstraints() as any as MyMediaTrackSupportedConstraints)[constraint];\n}\n"],"sourceRoot":""}