UNPKG

@hsaadawy/ngx-chat

Version:
163 lines 27.9 kB
import { __awaiter } from "tslib"; import { xml } from '@xmpp/client'; import { BehaviorSubject, combineLatest, merge } from 'rxjs'; import { debounceTime, delay, distinctUntilChanged, map, share } from 'rxjs/operators'; import { Direction } from '../../../../core/message'; import { findSortedInsertionIndexLast } from '../../../../core/utils-array'; import { AbstractStanzaBuilder } from '../abstract-stanza-builder'; import { AbstractXmppPlugin } from './abstract-xmpp-plugin'; const STORAGE_NGX_CHAT_LAST_READ_DATE = 'ngxchat:unreadmessagedate'; const wrapperNodeName = 'entries'; const nodeName = 'last-read'; class LastReadEntriesNodeBuilder extends AbstractStanzaBuilder { constructor() { super(...arguments); this.lastReadNodes = []; } addLastReadNode(jid, date) { this.lastReadNodes.push(xml(nodeName, { jid, date })); } toStanza() { return xml(wrapperNodeName, {}, this.lastReadNodes); } } /** * Unofficial plugin using XEP-0163 / PubSub to track count of unread messages per recipient * * It publishes entries to a private PubSub-Node 'ngxchat:unreadmessagedate' * The stored elements look like this: * <item id="current"> * <entries> * <last-read jid="user1@host1.tld" date="1546419050584"/> * <last-read jid="user2@host1.tld" date="1546419050000"/> * </entries> * </item> */ export class UnreadMessageCountPlugin extends AbstractXmppPlugin { constructor(chatService, chatMessageListRegistry, publishSubscribePlugin, entityTimePlugin, multiUserChatPlugin) { super(); this.chatService = chatService; this.chatMessageListRegistry = chatMessageListRegistry; this.publishSubscribePlugin = publishSubscribePlugin; this.entityTimePlugin = entityTimePlugin; this.multiUserChatPlugin = multiUserChatPlugin; /** * emits as soon as the unread message count changes, you might want to debounce it with e.g. half a a second, as * new messages might be acknowledged in another session. */ this.jidToUnreadCount$ = new BehaviorSubject(new Map()); this.jidToLastReadTimestamp = new Map(); this.recipientIdToMessageSubscription = new Map(); this.chatMessageListRegistry.chatOpened$ .pipe(delay(0)) .subscribe(recipient => this.checkForUnreadCountChange(recipient)); merge(multiUserChatPlugin.rooms$, this.chatService.contactCreated$.pipe(map(contact => [contact]))).subscribe(recipients => { for (const recipient of recipients) { const jid = recipient.jidBare.toString(); if (!this.recipientIdToMessageSubscription.has(jid)) { const messages$ = recipient.messages$; const updateUnreadCountSubscription = messages$ .pipe(debounceTime(20)) .subscribe(() => this.checkForUnreadCountChange(recipient)); this.recipientIdToMessageSubscription.set(jid, updateUnreadCountSubscription); } } }); this.publishSubscribePlugin.publish$ .subscribe((event) => this.handlePubSubEvent(event)); this.unreadMessageCountSum$ = combineLatest([this.jidToUnreadCount$, this.chatService.blockedContactIds$]) .pipe(debounceTime(20), map(([jidToUnreadCount, blockedContactIdSet]) => { let sum = 0; for (const [recipientJid, count] of jidToUnreadCount) { if (!blockedContactIdSet.has(recipientJid)) { sum += count; } } return sum; }), distinctUntilChanged(), share()); } checkForUnreadCountChange(recipient) { return __awaiter(this, void 0, void 0, function* () { if (this.chatMessageListRegistry.isChatOpen(recipient)) { this.jidToLastReadTimestamp.set(recipient.jidBare.toString(), yield this.entityTimePlugin.getNow()); yield this.persistLastSeenDates(); } this.updateContactUnreadMessageState(recipient); }); } onBeforeOnline() { return __awaiter(this, void 0, void 0, function* () { const fetchedDates = yield this.fetchLastSeenDates(); this.mergeJidToDates(fetchedDates); }); } onOffline() { for (const subscription of this.recipientIdToMessageSubscription.values()) { subscription.unsubscribe(); } this.recipientIdToMessageSubscription.clear(); this.jidToLastReadTimestamp.clear(); this.jidToUnreadCount$.next(new Map()); } fetchLastSeenDates() { return __awaiter(this, void 0, void 0, function* () { const entries = yield this.publishSubscribePlugin.retrieveNodeItems(STORAGE_NGX_CHAT_LAST_READ_DATE); return this.parseLastSeenDates(entries); }); } parseLastSeenDates(topLevelElements) { const result = new Map(); if (topLevelElements.length === 1) { const [itemElement] = topLevelElements; for (const lastReadEntry of itemElement.getChild(wrapperNodeName).getChildren(nodeName)) { const { jid, date } = lastReadEntry.attrs; if (!isNaN(date)) { result.set(jid, date); } } } return result; } updateContactUnreadMessageState(recipient) { const contactJid = recipient.jidBare.toString(); const lastReadDate = this.jidToLastReadTimestamp.get(contactJid) || 0; const contactUnreadMessageCount = this.calculateUnreadMessageCount(recipient, lastReadDate); const jidToCount = this.jidToUnreadCount$.getValue(); if (jidToCount.get(contactJid) !== contactUnreadMessageCount) { this.jidToUnreadCount$.next(jidToCount.set(contactJid, contactUnreadMessageCount)); } } calculateUnreadMessageCount(recipient, lastReadTimestamp) { const firstUnreadMessageIndex = findSortedInsertionIndexLast(lastReadTimestamp, recipient.messages, message => message.datetime.getTime()); return recipient.messages.slice(firstUnreadMessageIndex) .filter(message => message.direction === Direction.in) .length; } persistLastSeenDates() { return __awaiter(this, void 0, void 0, function* () { const lastReadNodeBuilder = new LastReadEntriesNodeBuilder(); for (const [jid, date] of this.jidToLastReadTimestamp) { lastReadNodeBuilder.addLastReadNode(jid, date.toString()); } yield this.publishSubscribePlugin.storePrivatePayloadPersistent(STORAGE_NGX_CHAT_LAST_READ_DATE, 'current', lastReadNodeBuilder.toStanza()); }); } handlePubSubEvent(event) { const items = event.getChild('items'); const itemsNode = items && items.attrs.node; const item = items && items.getChildren('item'); if (itemsNode === STORAGE_NGX_CHAT_LAST_READ_DATE && item) { const publishedLastJidToDate = this.parseLastSeenDates(item); this.mergeJidToDates(publishedLastJidToDate); } } mergeJidToDates(newJidToDate) { for (const [jid, date] of newJidToDate) { const oldLastReadDate = this.jidToLastReadTimestamp.get(jid); if (!oldLastReadDate || oldLastReadDate < date) { this.jidToLastReadTimestamp.set(jid, date); } } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW5yZWFkLW1lc3NhZ2UtY291bnQucGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvcGF6em5ldHdvcmsvbmd4LWNoYXQvc3JjL2xpYi9zZXJ2aWNlcy9hZGFwdGVycy94bXBwL3BsdWdpbnMvdW5yZWFkLW1lc3NhZ2UtY291bnQucGx1Z2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRW5DLE9BQU8sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBcUMsTUFBTSxNQUFNLENBQUM7QUFDaEcsT0FBTyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3ZGLE9BQU8sRUFBRSxTQUFTLEVBQVcsTUFBTSwwQkFBMEIsQ0FBQztBQUU5RCxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUU1RSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVuRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUs1RCxNQUFNLCtCQUErQixHQUFHLDJCQUEyQixDQUFDO0FBQ3BFLE1BQU0sZUFBZSxHQUFHLFNBQVMsQ0FBQztBQUNsQyxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUM7QUFLN0IsTUFBTSwwQkFBMkIsU0FBUSxxQkFBcUI7SUFBOUQ7O1FBRVksa0JBQWEsR0FBRyxFQUFlLENBQUM7SUFZNUMsQ0FBQztJQVZHLGVBQWUsQ0FBQyxHQUFXLEVBQUUsSUFBWTtRQUNyQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FDbkIsR0FBRyxDQUFDLFFBQVEsRUFBRSxFQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUM3QixDQUFDO0lB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QUErQixJQUFJLElBQUksRUFBRTtZQUN2RCxNQUFNLHNCQUFzQixHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM3RCxJQUFJLENBQUMsZUFBZSxDQUFDLHNCQUFzQixDQUFDLENBQUM7U0FDaEQ7SUFDTCxDQUFDO0lBRU8sZUFBZSxDQUFDLFlBQW9DO1FBQ3hELEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsSUFBSSxZQUFZLEVBQUU7WUFDcEMsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3RCxJQUFJLENBQUMsZUFBZSxJQUFJLGVBQWUsR0FBRyxJQUFJLEVBQUU7Z0JBQzVDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO2FBQzlDO1NBQ0o7SUFDTCxDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB4bWwgfSBmcm9tICdAeG1wcC9jbGllbnQnO1xyXG5pbXBvcnQgeyBFbGVtZW50IH0gZnJvbSAnbHR4JztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBtZXJnZSwgT2JzZXJ2YWJsZSwgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgZGVsYXksIGRpc3RpbmN0VW50aWxDaGFuZ2VkLCBtYXAsIHNoYXJlIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBEaXJlY3Rpb24sIE1lc3NhZ2UgfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL21lc3NhZ2UnO1xyXG5pbXBvcnQgeyBSZWNpcGllbnQgfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL3JlY2lwaWVudCc7XHJcbmltcG9ydCB7IGZpbmRTb3J0ZWRJbnNlcnRpb25JbmRleExhc3QgfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL3V0aWxzLWFycmF5JztcclxuaW1wb3J0IHsgQ2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnlTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vY2hhdC1tZXNzYWdlLWxpc3QtcmVnaXN0cnkuc2VydmljZSc7XHJcbmltcG9ydCB7IEFic3RyYWN0U3RhbnphQnVpbGRlciB9IGZyb20gJy4uL2Fic3RyYWN0LXN0YW56YS1idWlsZGVyJztcclxuaW1wb3J0IHsgWG1wcENoYXRBZGFwdGVyIH0gZnJvbSAnLi4veG1wcC1jaGF0LWFkYXB0ZXIuc2VydmljZSc7XHJcbmltcG9ydCB7IEFic3RyYWN0WG1wcFBsdWdpbiB9IGZyb20gJy4vYWJzdHJhY3QteG1wcC1wbHVnaW4nO1xyXG5pbXBvcnQgeyBFbnRpdHlUaW1lUGx1Z2luIH0gZnJvbSAnLi9lbnRpdHktdGltZS5wbHVnaW4nO1xyXG5pbXBvcnQgeyBNdWx0aVVzZXJDaGF0UGx1Z2luIH0gZnJvbSAnLi9tdWx0aS11c2VyLWNoYXQucGx1Z2luJztcclxuaW1wb3J0IHsgUHVibGlzaFN1YnNjcmliZVBsdWdpbiB9IGZyb20gJy4vcHVibGlzaC1zdWJzY3JpYmUucGx1Z2luJztcclxuXHJcbmNvbnN0IFNUT1JBR0VfTkdYX0NIQVRfTEFTVF9SRUFEX0RBVEUgPSAnbmd4Y2hhdDp1bnJlYWRtZXNzYWdlZGF0ZSc7XHJcbmNvbnN0IHdyYXBwZXJOb2RlTmFtZSA9ICdlbnRyaWVzJztcclxuY29uc3Qgbm9kZU5hbWUgPSAnbGFzdC1yZWFkJztcclxuXHJcbmV4cG9ydCB0eXBlIEppZFRvTnVtYmVyID0gTWFwPHN0cmluZywgbnVtYmVyPjtcclxudHlwZSBKaWRUb0xhc3RSZWFkVGltZXN0YW1wID0gTWFwPHN0cmluZywgbnVtYmVyPjtcclxuXHJcbmNsYXNzIExhc3RSZWFkRW50cmllc05vZGVCdWlsZGVyIGV4dGVuZHMgQWJzdHJhY3RTdGFuemFCdWlsZGVyIHtcclxuXHJcbiAgICBwcml2YXRlIGxhc3RSZWFkTm9kZXMgPSBbXSBhcyBFbGVtZW50W107XHJcblxyXG4gICAgYWRkTGFzdFJlYWROb2RlKGppZDogc3RyaW5nLCBkYXRlOiBzdHJpbmcpIHtcclxuICAgICAgICB0aGlzLmxhc3RSZWFkTm9kZXMucHVzaChcclxuICAgICAgICAgICAgeG1sKG5vZGVOYW1lLCB7amlkLCBkYXRlfSksXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICB0b1N0YW56YSgpOiBFbGVtZW50IHtcclxuICAgICAgICByZXR1cm4geG1sKHdyYXBwZXJOb2RlTmFtZSwge30sIHRoaXMubGFzdFJlYWROb2Rlcyk7XHJcbiAgICB9XHJcblxyXG59XHJcblxyXG4vKipcclxuICogVW5vZmZpY2lhbCBwbHVnaW4gdXNpbmcgWEVQLTAxNjMgLyBQdWJTdWIgdG8gdHJhY2sgY291bnQgb2YgdW5yZWFkIG1lc3NhZ2VzIHBlciByZWNpcGllbnRcclxuICpcclxuICogSXQgcHVibGlzaGVzIGVudHJpZXMgdG8gYSBwcml2YXRlIFB1YlN1Yi1Ob2RlICduZ3hjaGF0OnVucmVhZG1lc3NhZ2VkYXRlJ1xyXG4gKiBUaGUgc3RvcmVkIGVsZW1lbnRzIGxvb2sgbGlrZSB0aGlzOlxyXG4gKiA8aXRlbSBpZD1cImN1cnJlbnRcIj5cclxuICogICAgIDxlbnRyaWVzPlxyXG4gKiAgICAgICAgIDxsYXN0LXJlYWQgamlkPVwidXNlcjFAaG9zdDEudGxkXCIgZGF0ZT1cIjE1NDY0MTkwNTA1ODRcIi8+XHJcbiAqICAgICAgICAgPGxhc3QtcmVhZCBqaWQ9XCJ1c2VyMkBob3N0MS50bGRcIiBkYXRlPVwiMTU0NjQxOTA1MDAwMFwiLz5cclxuICogICAgIDwvZW50cmllcz5cclxuICogPC9pdGVtPlxyXG4gKi9cclxuZXhwb3J0IGNsYXNzIFVucmVhZE1lc3NhZ2VDb3VudFBsdWdpbiBleHRlbmRzIEFic3RyYWN0WG1wcFBsdWdpbiB7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBhbHJlYWR5IGRlYm91bmNlZCB0byBwcmV2ZW50IHRoZSBpc3N1ZXMgZGVzY3JpYmVkIGluIHtAbGluayBVbnJlYWRNZXNzYWdlQ291bnRQbHVnaW4uamlkVG9VbnJlYWRDb3VudCR9LlxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgcmVhZG9ubHkgdW5yZWFkTWVzc2FnZUNvdW50U3VtJDogT2JzZXJ2YWJsZTxudW1iZXI+O1xyXG4gICAgLyoqXHJcbiAgICAgKiBlbWl0cyBhcyBzb29uIGFzIHRoZSB1bnJlYWQgbWVzc2FnZSBjb3VudCBjaGFuZ2VzLCB5b3UgbWlnaHQgd2FudCB0byBkZWJvdW5jZSBpdCB3aXRoIGUuZy4gaGFsZiBhIGEgc2Vjb25kLCBhc1xyXG4gICAgICogbmV3IG1lc3NhZ2VzIG1pZ2h0IGJlIGFja25vd2xlZGdlZCBpbiBhbm90aGVyIHNlc3Npb24uXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyByZWFkb25seSBqaWRUb1VucmVhZENvdW50JDogQmVoYXZpb3JTdWJqZWN0PEppZFRvTnVtYmVyPiA9IG5ldyBCZWhhdmlvclN1YmplY3QobmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKSk7XHJcbiAgICBwcml2YXRlIHJlYWRvbmx5IGppZFRvTGFzdFJlYWRUaW1lc3RhbXA6IEppZFRvTGFzdFJlYWRUaW1lc3RhbXAgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xyXG4gICAgcHJpdmF0ZSByZWFkb25seSByZWNpcGllbnRJZFRvTWVzc2FnZVN1YnNjcmlwdGlvbiA9IG5ldyBNYXA8c3RyaW5nLCBTdWJzY3JpcHRpb24+KCk7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHJpdmF0ZSBjaGF0U2VydmljZTogWG1wcENoYXRBZGFwdGVyLFxyXG4gICAgICAgIHByaXZhdGUgY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnk6IENoYXRNZXNzYWdlTGlzdFJlZ2lzdHJ5U2VydmljZSxcclxuICAgICAgICBwcml2YXRlIHB1Ymxpc2hTdWJzY3JpYmVQbHVnaW46IFB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4sXHJcbiAgICAgICAgcHJpdmF0ZSBlbnRpdHlUaW1lUGx1Z2luOiBFbnRpdHlUaW1lUGx1Z2luLFxyXG4gICAgICAgIHByaXZhdGUgbXVsdGlVc2VyQ2hhdFBsdWdpbjogTXVsdGlVc2VyQ2hhdFBsdWdpbixcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKCk7XHJcblxyXG4gICAgICAgIHRoaXMuY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnkuY2hhdE9wZW5lZCRcclxuICAgICAgICAgICAgLnBpcGUoXHJcbiAgICAgICAgICAgICAgICBkZWxheSgwKSwgLy8gcHJldmVudCAnRXhwcmVzc2lvbiBoYXMgY2hhbmdlZCBhZnRlciBpdCB3YXMgY2hlY2tlZCdcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKHJlY2lwaWVudCA9PiB0aGlzLmNoZWNrRm9yVW5yZWFkQ291bnRDaGFuZ2UocmVjaXBpZW50KSk7XHJcblxyXG4gICAgICAgIG1lcmdlKFxyXG4gICAgICAgICAgICBtdWx0aVVzZXJDaGF0UGx1Z2luLnJvb21zJCxcclxuICAgICAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jb250YWN0Q3JlYXRlZCQucGlwZShtYXAoY29udGFjdCA9PiBbY29udGFjdF0pKSxcclxuICAgICAgICApLnN1YnNjcmliZShyZWNpcGllbnRzID0+IHtcclxuICAgICAgICAgICAgZm9yIChjb25zdCByZWNpcGllbnQgb2YgcmVjaXBpZW50cykge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgamlkID0gcmVjaXBpZW50LmppZEJhcmUudG9TdHJpbmcoKTtcclxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5yZWNpcGllbnRJZFRvTWVzc2FnZVN1YnNjcmlwdGlvbi5oYXMoamlkKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2VzJDogU3ViamVjdDxNZXNzYWdlPiA9IHJlY2lwaWVudC5tZXNzYWdlcyQ7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdXBkYXRlVW5yZWFkQ291bnRTdWJzY3JpcHRpb24gPSBtZXNzYWdlcyRcclxuICAgICAgICAgICAgICAgICAgICAgICAgLnBpcGUoZGVib3VuY2VUaW1lKDIwKSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLmNoZWNrRm9yVW5yZWFkQ291bnRDaGFuZ2UocmVjaXBpZW50KSk7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWNpcGllbnRJZFRvTWVzc2FnZVN1YnNjcmlwdGlvbi5zZXQoamlkLCB1cGRhdGVVbnJlYWRDb3VudFN1YnNjcmlwdGlvbik7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5wdWJsaXNoU3Vic2NyaWJlUGx1Z2luLnB1Ymxpc2gkXHJcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50KSA9PiB0aGlzLmhhbmRsZVB1YlN1YkV2ZW50KGV2ZW50KSk7XHJcblxyXG4gICAgICAgIHRoaXMudW5yZWFkTWVzc2FnZUNvdW50U3VtJCA9IGNvbWJpbmVMYXRlc3QoW3RoaXMuamlkVG9VbnJlYWRDb3VudCQsIHRoaXMuY2hhdFNlcnZpY2UuYmxvY2tlZENvbnRhY3RJZHMkXSlcclxuICAgICAgICAgICAgLnBpcGUoXHJcbiAgICAgICAgICAgICAgICBkZWJvdW5jZVRpbWUoMjApLFxyXG4gICAgICAgICAgICAgICAgbWFwKChbamlkVG9VbnJlYWRDb3VudCwgYmxvY2tlZENvbnRhY3RJZFNldF0pID0+IHtcclxuICAgICAgICAgICAgICAgICAgICBsZXQgc3VtID0gMDtcclxuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtyZWNpcGllbnRKaWQsIGNvdW50XSBvZiBqaWRUb1VucmVhZENvdW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghYmxvY2tlZENvbnRhY3RJZFNldC5oYXMocmVjaXBpZW50SmlkKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtICs9IGNvdW50O1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzdW07XHJcbiAgICAgICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCksXHJcbiAgICAgICAgICAgICAgICBzaGFyZSgpLFxyXG4gICAgICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgYXN5bmMgY2hlY2tGb3JVbnJlYWRDb3VudENoYW5nZShyZWNpcGllbnQ6IFJlY2lwaWVudCkge1xyXG4gICAgICAgIGlmICh0aGlzLmNoYXRNZXNzYWdlTGlzdFJlZ2lzdHJ5LmlzQ2hhdE9wZW4ocmVjaXBpZW50KSkge1xyXG4gICAgICAgICAgICB0aGlzLmppZFRvTGFzdFJlYWRUaW1lc3RhbXAuc2V0KHJlY2lwaWVudC5qaWRCYXJlLnRvU3RyaW5nKCksIGF3YWl0IHRoaXMuZW50aXR5VGltZVBsdWdpbi5nZXROb3coKSk7XHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucGVyc2lzdExhc3RTZWVuRGF0ZXMoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy51cGRhdGVDb250YWN0VW5yZWFkTWVzc2FnZVN0YXRlKHJlY2lwaWVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgb25CZWZvcmVPbmxpbmUoKTogUHJvbWlzZTxhbnk+IHtcclxuICAgICAgICBjb25zdCBmZXRjaGVkRGF0ZXMgPSBhd2FpdCB0aGlzLmZldGNoTGFzdFNlZW5EYXRlcygpO1xyXG4gICAgICAgIHRoaXMubWVyZ2VKaWRUb0RhdGVzKGZldGNoZWREYXRlcyk7XHJcbiAgICB9XHJcblxyXG4gICAgb25PZmZsaW5lKCkge1xyXG4gICAgICAgIGZvciAoY29uc3Qgc3Vic2NyaXB0aW9uIG9mIHRoaXMucmVjaXBpZW50SWRUb01lc3NhZ2VTdWJzY3JpcHRpb24udmFsdWVzKCkpIHtcclxuICAgICAgICAgICAgc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMucmVjaXBpZW50SWRUb01lc3NhZ2VTdWJzY3JpcHRpb24uY2xlYXIoKTtcclxuICAgICAgICB0aGlzLmppZFRvTGFzdFJlYWRUaW1lc3RhbXAuY2xlYXIoKTtcclxuICAgICAgICB0aGlzLmppZFRvVW5yZWFkQ291bnQkLm5leHQobmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBhc3luYyBmZXRjaExhc3RTZWVuRGF0ZXMoKTogUHJvbWlzZTxKaWRUb0xhc3RSZWFkVGltZXN0YW1wPiB7XHJcbiAgICAgICAgY29uc3QgZW50cmllcyA9IGF3YWl0IHRoaXMucHVibGlzaFN1YnNjcmliZVBsdWdpbi5yZXRyaWV2ZU5vZGVJdGVtcyhTVE9SQUdFX05HWF9DSEFUX0xBU1RfUkVBRF9EQVRFKTtcclxuICAgICAgICByZXR1cm4gdGhpcy5wYXJzZUxhc3RTZWVuRGF0ZXMoZW50cmllcyk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBwYXJzZUxhc3RTZWVuRGF0ZXModG9wTGV2ZWxFbGVtZW50czogRWxlbWVudFtdKTogSmlkVG9MYXN0UmVhZFRpbWVzdGFtcCB7XHJcbiAgICAgICAgY29uc3QgcmVzdWx0OiBKaWRUb0xhc3RSZWFkVGltZXN0YW1wID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcclxuXHJcbiAgICAgICAgaWYgKHRvcExldmVsRWxlbWVudHMubGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IFtpdGVtRWxlbWVudF0gPSB0b3BMZXZlbEVsZW1lbnRzO1xyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGxhc3RSZWFkRW50cnkgb2YgaXRlbUVsZW1lbnQuZ2V0Q2hpbGQod3JhcHBlck5vZGVOYW1lKS5nZXRDaGlsZHJlbihub2RlTmFtZSkpIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHtqaWQsIGRhdGV9ID0gbGFzdFJlYWRFbnRyeS5hdHRycztcclxuICAgICAgICAgICAgICAgIGlmICghaXNOYU4oZGF0ZSkpIHtcclxuICAgICAgICAgICAgICAgICAgICByZXN1bHQuc2V0KGppZCwgZGF0ZSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9XHJcblxyXG4gICAgdXBkYXRlQ29udGFjdFVucmVhZE1lc3NhZ2VTdGF0ZShyZWNpcGllbnQ6IFJlY2lwaWVudCkge1xyXG4gICAgICAgIGNvbnN0IGNvbnRhY3RKaWQgPSByZWNpcGllbnQuamlkQmFyZS50b1N0cmluZygpO1xyXG4gICAgICAgIGNvbnN0IGxhc3RSZWFkRGF0ZSA9IHRoaXMuamlkVG9MYXN0UmVhZFRpbWVzdGFtcC5nZXQoY29udGFjdEppZCkgfHwgMDtcclxuICAgICAgICBjb25zdCBjb250YWN0VW5yZWFkTWVzc2FnZUNvdW50ID0gdGhpcy5jYWxjdWxhdGVVbnJlYWRNZXNzYWdlQ291bnQocmVjaXBpZW50LCBsYXN0UmVhZERhdGUpO1xyXG4gICAgICAgIGNvbnN0IGppZFRvQ291bnQgPSB0aGlzLmppZFRvVW5yZWFkQ291bnQkLmdldFZhbHVlKCk7XHJcbiAgICAgICAgaWYgKGppZFRvQ291bnQuZ2V0KGNvbnRhY3RKaWQpICE9PSBjb250YWN0VW5yZWFkTWVzc2FnZUNvdW50KSB7XHJcbiAgICAgICAgICAgIHRoaXMuamlkVG9VbnJlYWRDb3VudCQubmV4dChqaWRUb0NvdW50LnNldChjb250YWN0SmlkLCBjb250YWN0VW5yZWFkTWVzc2FnZUNvdW50KSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgY2FsY3VsYXRlVW5yZWFkTWVzc2FnZUNvdW50KHJlY2lwaWVudDogUmVjaXBpZW50LCBsYXN0UmVhZFRpbWVzdGFtcDogbnVtYmVyKSB7XHJcbiAgICAgICAgY29uc3QgZmlyc3RVbnJlYWRNZXNzYWdlSW5kZXggPSBmaW5kU29ydGVkSW5zZXJ0aW9uSW5kZXhMYXN0KGxhc3RSZWFkVGltZXN0YW1wLCByZWNpcGllbnQubWVzc2FnZXMsXHJcbiAgICAgICAgICAgIG1lc3NhZ2UgPT4gbWVzc2FnZS5kYXRldGltZS5nZXRUaW1lKCkpO1xyXG4gICAgICAgIHJldHVybiByZWNpcGllbnQubWVzc2FnZXMuc2xpY2UoZmlyc3RVbnJlYWRNZXNzYWdlSW5kZXgpXHJcbiAgICAgICAgICAgIC5maWx0ZXIobWVzc2FnZSA9PiBtZXNzYWdlLmRpcmVjdGlvbiA9PT0gRGlyZWN0aW9uLmluKVxyXG4gICAgICAgICAgICAubGVuZ3RoO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgYXN5bmMgcGVyc2lzdExhc3RTZWVuRGF0ZXMoKSB7XHJcbiAgICAgICAgY29uc3QgbGFzdFJlYWROb2RlQnVpbGRlciA9IG5ldyBMYXN0UmVhZEVudHJpZXNOb2RlQnVpbGRlcigpO1xyXG4gICAgICAgIGZvciAoY29uc3QgW2ppZCwgZGF0ZV0gb2YgdGhpcy5qaWRUb0xhc3RSZWFkVGltZXN0YW1wKSB7XHJcbiAgICAgICAgICAgIGxhc3RSZWFkTm9kZUJ1aWxkZXIuYWRkTGFzdFJlYWROb2RlKGppZCwgZGF0ZS50b1N0cmluZygpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGF3YWl0IHRoaXMucHVibGlzaFN1YnNjcmliZVBsdWdpbi5zdG9yZVByaXZhdGVQYXlsb2FkUGVyc2lzdGVudChcclxuICAgICAgICAgICAgU1RPUkFHRV9OR1hfQ0hBVF9MQVNUX1JFQURfREFURSxcclxuICAgICAgICAgICAgJ2N1cnJlbnQnLFxyXG4gICAgICAgICAgICBsYXN0UmVhZE5vZGVCdWlsZGVyLnRvU3RhbnphKCkpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaGFuZGxlUHViU3ViRXZlbnQoZXZlbnQ6IEVsZW1lbnQpIHtcclxuICAgICAgICBjb25zdCBpdGVtcyA9IGV2ZW50LmdldENoaWxkKCdpdGVtcycpO1xyXG4gICAgICAgIGNvbnN0IGl0ZW1zTm9kZSA9IGl0ZW1zICYmIGl0ZW1zLmF0dHJzLm5vZGU7XHJcbiAgICAgICAgY29uc3QgaXRlbSA9IGl0ZW1zICYmIGl0ZW1zLmdldENoaWxkcmVuKCdpdGVtJyk7XHJcbiAgICAgICAgaWYgKGl0ZW1zTm9kZSA9PT0gU1RPUkFHRV9OR1hfQ0hBVF9MQVNUX1JFQURfREFURSAmJiBpdGVtKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHB1Ymxpc2hlZExhc3RKaWRUb0RhdGUgPSB0aGlzLnBhcnNlTGFzdFNlZW5EYXRlcyhpdGVtKTtcclxuICAgICAgICAgICAgdGhpcy5tZXJnZUppZFRvRGF0ZXMocHVibGlzaGVkTGFzdEppZFRvRGF0ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgbWVyZ2VKaWRUb0RhdGVzKG5ld0ppZFRvRGF0ZTogSmlkVG9MYXN0UmVhZFRpbWVzdGFtcCkge1xyXG4gICAgICAgIGZvciAoY29uc3QgW2ppZCwgZGF0ZV0gb2YgbmV3SmlkVG9EYXRlKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IG9sZExhc3RSZWFkRGF0ZSA9IHRoaXMuamlkVG9MYXN0UmVhZFRpbWVzdGFtcC5nZXQoamlkKTtcclxuICAgICAgICAgICAgaWYgKCFvbGRMYXN0UmVhZERhdGUgfHwgb2xkTGFzdFJlYWREYXRlIDwgZGF0ZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5qaWRUb0xhc3RSZWFkVGltZXN0YW1wLnNldChqaWQsIGRhdGUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG59XHJcbiJdfQ==