UNPKG

@pazznetwork/ngx-chat

Version:

[![Build status](https://api.travis-ci.com/pazznetwork/ngx-chat.svg?branch=master)](https://travis-ci.com/pazznetwork/ngx-chat) [![Coverage](https://coveralls.io/repos/github/pazznetwork/ngx-chat/badge.svg?branch=master)](https://coveralls.io/github/pazzn

154 lines 26.8 kB
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()); } async checkForUnreadCountChange(recipient) { if (this.chatMessageListRegistry.isChatOpen(recipient)) { this.jidToLastReadTimestamp.set(recipient.jidBare.toString(), await this.entityTimePlugin.getNow()); await this.persistLastSeenDates(); } this.updateContactUnreadMessageState(recipient); } async onBeforeOnline() { const fetchedDates = await 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()); } async fetchLastSeenDates() { const entries = await 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; } async persistLastSeenDates() { const lastReadNodeBuilder = new LastReadEntriesNodeBuilder(); for (const [jid, date] of this.jidToLastReadTimestamp) { lastReadNodeBuilder.addLastReadNode(jid, date.toString()); } await 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW5yZWFkLW1lc3NhZ2UtY291bnQucGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9hZGFwdGVycy94bXBwL3BsdWdpbnMvdW5yZWFkLW1lc3NhZ2UtY291bnQucGx1Z2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFbkMsT0FBTyxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFxQyxNQUFNLE1BQU0sQ0FBQztBQUNoRyxPQUFPLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxvQkFBb0IsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdkYsT0FBTyxFQUFFLFNBQVMsRUFBVyxNQUFNLDBCQUEwQixDQUFDO0FBRTlELE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRTVFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRW5FLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBSzVELE1BQU0sK0JBQStCLEdBQUcsMkJBQTJCLENBQUM7QUFDcEUsTUFBTSxlQUFlLEdBQUcsU0FBUyxDQUFDO0FBQ2xDLE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQztBQUs3QixNQUFNLDBCQUEyQixTQUFRLHFCQUFxQjtJQUE5RDs7UUFFWSxrQkFBYSxHQUFHLEVBQWUsQ0FBQztJQVk1QyxDQUFDO0lBVkcsZUFBZSxDQUFDLEdBQVcsRUFBRSxJQUFZO1FBQ3JDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUNuQixHQUFHLENBQUMsUUFBUSxFQUFFLEVBQUMsR0FBRyxFQUFFLElBQUksRUFBQyxDQUFDLENBQzdCLENBQUM7SUFDTixDQUFDO0lBRUQsUUFBUTtRQUNKLE9BQU8sR0FBRyxD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QUFFO1lBQ3ZELE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdELElBQUksQ0FBQyxlQUFlLENBQUMsc0JBQXNCLENBQUMsQ0FBQztTQUNoRDtJQUNMLENBQUM7SUFFTyxlQUFlLENBQUMsWUFBb0M7UUFDeEQsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxJQUFJLFlBQVksRUFBRTtZQUNwQyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzdELElBQUksQ0FBQyxlQUFlLElBQUksZUFBZSxHQUFHLElBQUksRUFBRTtnQkFDNUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7YUFDOUM7U0FDSjtJQUNMLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHhtbCB9IGZyb20gJ0B4bXBwL2NsaWVudCc7XG5pbXBvcnQgeyBFbGVtZW50IH0gZnJvbSAnbHR4JztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgY29tYmluZUxhdGVzdCwgbWVyZ2UsIE9ic2VydmFibGUsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBkZWxheSwgZGlzdGluY3RVbnRpbENoYW5nZWQsIG1hcCwgc2hhcmUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBEaXJlY3Rpb24sIE1lc3NhZ2UgfSBmcm9tICcuLi8uLi8uLi8uLi9jb3JlL21lc3NhZ2UnO1xuaW1wb3J0IHsgUmVjaXBpZW50IH0gZnJvbSAnLi4vLi4vLi4vLi4vY29yZS9yZWNpcGllbnQnO1xuaW1wb3J0IHsgZmluZFNvcnRlZEluc2VydGlvbkluZGV4TGFzdCB9IGZyb20gJy4uLy4uLy4uLy4uL2NvcmUvdXRpbHMtYXJyYXknO1xuaW1wb3J0IHsgQ2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnlTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vY2hhdC1tZXNzYWdlLWxpc3QtcmVnaXN0cnkuc2VydmljZSc7XG5pbXBvcnQgeyBBYnN0cmFjdFN0YW56YUJ1aWxkZXIgfSBmcm9tICcuLi9hYnN0cmFjdC1zdGFuemEtYnVpbGRlcic7XG5pbXBvcnQgeyBYbXBwQ2hhdEFkYXB0ZXIgfSBmcm9tICcuLi94bXBwLWNoYXQtYWRhcHRlci5zZXJ2aWNlJztcbmltcG9ydCB7IEFic3RyYWN0WG1wcFBsdWdpbiB9IGZyb20gJy4vYWJzdHJhY3QteG1wcC1wbHVnaW4nO1xuaW1wb3J0IHsgRW50aXR5VGltZVBsdWdpbiB9IGZyb20gJy4vZW50aXR5LXRpbWUucGx1Z2luJztcbmltcG9ydCB7IE11bHRpVXNlckNoYXRQbHVnaW4gfSBmcm9tICcuL211bHRpLXVzZXItY2hhdC9tdWx0aS11c2VyLWNoYXQucGx1Z2luJztcbmltcG9ydCB7IFB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4gfSBmcm9tICcuL3B1Ymxpc2gtc3Vic2NyaWJlLnBsdWdpbic7XG5cbmNvbnN0IFNUT1JBR0VfTkdYX0NIQVRfTEFTVF9SRUFEX0RBVEUgPSAnbmd4Y2hhdDp1bnJlYWRtZXNzYWdlZGF0ZSc7XG5jb25zdCB3cmFwcGVyTm9kZU5hbWUgPSAnZW50cmllcyc7XG5jb25zdCBub2RlTmFtZSA9ICdsYXN0LXJlYWQnO1xuXG5leHBvcnQgdHlwZSBKaWRUb051bWJlciA9IE1hcDxzdHJpbmcsIG51bWJlcj47XG50eXBlIEppZFRvTGFzdFJlYWRUaW1lc3RhbXAgPSBNYXA8c3RyaW5nLCBudW1iZXI+O1xuXG5jbGFzcyBMYXN0UmVhZEVudHJpZXNOb2RlQnVpbGRlciBleHRlbmRzIEFic3RyYWN0U3RhbnphQnVpbGRlciB7XG5cbiAgICBwcml2YXRlIGxhc3RSZWFkTm9kZXMgPSBbXSBhcyBFbGVtZW50W107XG5cbiAgICBhZGRMYXN0UmVhZE5vZGUoamlkOiBzdHJpbmcsIGRhdGU6IHN0cmluZykge1xuICAgICAgICB0aGlzLmxhc3RSZWFkTm9kZXMucHVzaChcbiAgICAgICAgICAgIHhtbChub2RlTmFtZSwge2ppZCwgZGF0ZX0pLFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHRvU3RhbnphKCk6IEVsZW1lbnQge1xuICAgICAgICByZXR1cm4geG1sKHdyYXBwZXJOb2RlTmFtZSwge30sIC4uLnRoaXMubGFzdFJlYWROb2Rlcyk7XG4gICAgfVxuXG59XG5cbi8qKlxuICogVW5vZmZpY2lhbCBwbHVnaW4gdXNpbmcgWEVQLTAxNjMgLyBQdWJTdWIgdG8gdHJhY2sgY291bnQgb2YgdW5yZWFkIG1lc3NhZ2VzIHBlciByZWNpcGllbnRcbiAqXG4gKiBJdCBwdWJsaXNoZXMgZW50cmllcyB0byBhIHByaXZhdGUgUHViU3ViLU5vZGUgJ25neGNoYXQ6dW5yZWFkbWVzc2FnZWRhdGUnXG4gKiBUaGUgc3RvcmVkIGVsZW1lbnRzIGxvb2sgbGlrZSB0aGlzOlxuICogPGl0ZW0gaWQ9XCJjdXJyZW50XCI+XG4gKiAgICAgPGVudHJpZXM+XG4gKiAgICAgICAgIDxsYXN0LXJlYWQgamlkPVwidXNlcjFAaG9zdDEudGxkXCIgZGF0ZT1cIjE1NDY0MTkwNTA1ODRcIi8+XG4gKiAgICAgICAgIDxsYXN0LXJlYWQgamlkPVwidXNlcjJAaG9zdDEudGxkXCIgZGF0ZT1cIjE1NDY0MTkwNTAwMDBcIi8+XG4gKiAgICAgPC9lbnRyaWVzPlxuICogPC9pdGVtPlxuICovXG5leHBvcnQgY2xhc3MgVW5yZWFkTWVzc2FnZUNvdW50UGx1Z2luIGV4dGVuZHMgQWJzdHJhY3RYbXBwUGx1Z2luIHtcblxuICAgIC8qKlxuICAgICAqIGFscmVhZHkgZGVib3VuY2VkIHRvIHByZXZlbnQgdGhlIGlzc3VlcyBkZXNjcmliZWQgaW4ge0BsaW5rIFVucmVhZE1lc3NhZ2VDb3VudFBsdWdpbi5qaWRUb1VucmVhZENvdW50JH0uXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IHVucmVhZE1lc3NhZ2VDb3VudFN1bSQ6IE9ic2VydmFibGU8bnVtYmVyPjtcbiAgICAvKipcbiAgICAgKiBlbWl0cyBhcyBzb29uIGFzIHRoZSB1bnJlYWQgbWVzc2FnZSBjb3VudCBjaGFuZ2VzLCB5b3UgbWlnaHQgd2FudCB0byBkZWJvdW5jZSBpdCB3aXRoIGUuZy4gaGFsZiBhIGEgc2Vjb25kLCBhc1xuICAgICAqIG5ldyBtZXNzYWdlcyBtaWdodCBiZSBhY2tub3dsZWRnZWQgaW4gYW5vdGhlciBzZXNzaW9uLlxuICAgICAqL1xuICAgIHB1YmxpYyByZWFkb25seSBqaWRUb1VucmVhZENvdW50JDogQmVoYXZpb3JTdWJqZWN0PEppZFRvTnVtYmVyPiA9IG5ldyBCZWhhdmlvclN1YmplY3QobmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKSk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBqaWRUb0xhc3RSZWFkVGltZXN0YW1wOiBKaWRUb0xhc3RSZWFkVGltZXN0YW1wID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlY2lwaWVudElkVG9NZXNzYWdlU3Vic2NyaXB0aW9uID0gbmV3IE1hcDxzdHJpbmcsIFN1YnNjcmlwdGlvbj4oKTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIGNoYXRTZXJ2aWNlOiBYbXBwQ2hhdEFkYXB0ZXIsXG4gICAgICAgIHByaXZhdGUgY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnk6IENoYXRNZXNzYWdlTGlzdFJlZ2lzdHJ5U2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBwdWJsaXNoU3Vic2NyaWJlUGx1Z2luOiBQdWJsaXNoU3Vic2NyaWJlUGx1Z2luLFxuICAgICAgICBwcml2YXRlIGVudGl0eVRpbWVQbHVnaW46IEVudGl0eVRpbWVQbHVnaW4sXG4gICAgICAgIHByaXZhdGUgbXVsdGlVc2VyQ2hhdFBsdWdpbjogTXVsdGlVc2VyQ2hhdFBsdWdpbixcbiAgICApIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLmNoYXRNZXNzYWdlTGlzdFJlZ2lzdHJ5LmNoYXRPcGVuZWQkXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBkZWxheSgwKSwgLy8gcHJldmVudCAnRXhwcmVzc2lvbiBoYXMgY2hhbmdlZCBhZnRlciBpdCB3YXMgY2hlY2tlZCdcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5zdWJzY3JpYmUocmVjaXBpZW50ID0+IHRoaXMuY2hlY2tGb3JVbnJlYWRDb3VudENoYW5nZShyZWNpcGllbnQpKTtcblxuICAgICAgICBtZXJnZShcbiAgICAgICAgICAgIG11bHRpVXNlckNoYXRQbHVnaW4ucm9vbXMkLFxuICAgICAgICAgICAgdGhpcy5jaGF0U2VydmljZS5jb250YWN0Q3JlYXRlZCQucGlwZShtYXAoY29udGFjdCA9PiBbY29udGFjdF0pKSxcbiAgICAgICAgKS5zdWJzY3JpYmUocmVjaXBpZW50cyA9PiB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHJlY2lwaWVudCBvZiByZWNpcGllbnRzKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgamlkID0gcmVjaXBpZW50LmppZEJhcmUudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMucmVjaXBpZW50SWRUb01lc3NhZ2VTdWJzY3JpcHRpb24uaGFzKGppZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbWVzc2FnZXMkOiBTdWJqZWN0PE1lc3NhZ2U+ID0gcmVjaXBpZW50Lm1lc3NhZ2VzJDtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdXBkYXRlVW5yZWFkQ291bnRTdWJzY3JpcHRpb24gPSBtZXNzYWdlcyRcbiAgICAgICAgICAgICAgICAgICAgICAgIC5waXBlKGRlYm91bmNlVGltZSgyMCkpXG4gICAgICAgICAgICAgICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuY2hlY2tGb3JVbnJlYWRDb3VudENoYW5nZShyZWNpcGllbnQpKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWNpcGllbnRJZFRvTWVzc2FnZVN1YnNjcmlwdGlvbi5zZXQoamlkLCB1cGRhdGVVbnJlYWRDb3VudFN1YnNjcmlwdGlvbik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnB1Ymxpc2hTdWJzY3JpYmVQbHVnaW4ucHVibGlzaCRcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50KSA9PiB0aGlzLmhhbmRsZVB1YlN1YkV2ZW50KGV2ZW50KSk7XG5cbiAgICAgICAgdGhpcy51bnJlYWRNZXNzYWdlQ291bnRTdW0kID0gY29tYmluZUxhdGVzdChbdGhpcy5qaWRUb1VucmVhZENvdW50JCwgdGhpcy5jaGF0U2VydmljZS5ibG9ja2VkQ29udGFjdElkcyRdKVxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgZGVib3VuY2VUaW1lKDIwKSxcbiAgICAgICAgICAgICAgICBtYXAoKFtqaWRUb1VucmVhZENvdW50LCBibG9ja2VkQ29udGFjdElkU2V0XSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBsZXQgc3VtID0gMDtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBbcmVjaXBpZW50SmlkLCBjb3VudF0gb2YgamlkVG9VbnJlYWRDb3VudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFibG9ja2VkQ29udGFjdElkU2V0LmhhcyhyZWNpcGllbnRKaWQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtICs9IGNvdW50O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzdW07XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgICAgICAgICAgICAgICBzaGFyZSgpLFxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGNoZWNrRm9yVW5yZWFkQ291bnRDaGFuZ2UocmVjaXBpZW50OiBSZWNpcGllbnQpIHtcbiAgICAgICAgaWYgKHRoaXMuY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnkuaXNDaGF0T3BlbihyZWNpcGllbnQpKSB7XG4gICAgICAgICAgICB0aGlzLmppZFRvTGFzdFJlYWRUaW1lc3RhbXAuc2V0KHJlY2lwaWVudC5qaWRCYXJlLnRvU3RyaW5nKCksIGF3YWl0IHRoaXMuZW50aXR5VGltZVBsdWdpbi5nZXROb3coKSk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnBlcnNpc3RMYXN0U2VlbkRhdGVzKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy51cGRhdGVDb250YWN0VW5yZWFkTWVzc2FnZVN0YXRlKHJlY2lwaWVudCk7XG4gICAgfVxuXG4gICAgYXN5bmMgb25CZWZvcmVPbmxpbmUoKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgICAgY29uc3QgZmV0Y2hlZERhdGVzID0gYXdhaXQgdGhpcy5mZXRjaExhc3RTZWVuRGF0ZXMoKTtcbiAgICAgICAgdGhpcy5tZXJnZUppZFRvRGF0ZXMoZmV0Y2hlZERhdGVzKTtcbiAgICB9XG5cbiAgICBvbk9mZmxpbmUoKSB7XG4gICAgICAgIGZvciAoY29uc3Qgc3Vic2NyaXB0aW9uIG9mIHRoaXMucmVjaXBpZW50SWRUb01lc3NhZ2VTdWJzY3JpcHRpb24udmFsdWVzKCkpIHtcbiAgICAgICAgICAgIHN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVjaXBpZW50SWRUb01lc3NhZ2VTdWJzY3JpcHRpb24uY2xlYXIoKTtcbiAgICAgICAgdGhpcy5qaWRUb0xhc3RSZWFkVGltZXN0YW1wLmNsZWFyKCk7XG4gICAgICAgIHRoaXMuamlkVG9VbnJlYWRDb3VudCQubmV4dChuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGZldGNoTGFzdFNlZW5EYXRlcygpOiBQcm9taXNlPEppZFRvTGFzdFJlYWRUaW1lc3RhbXA+IHtcbiAgICAgICAgY29uc3QgZW50cmllcyA9IGF3YWl0IHRoaXMucHVibGlzaFN1YnNjcmliZVBsdWdpbi5yZXRyaWV2ZU5vZGVJdGVtcyhTVE9SQUdFX05HWF9DSEFUX0xBU1RfUkVBRF9EQVRFKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucGFyc2VMYXN0U2VlbkRhdGVzKGVudHJpZXMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgcGFyc2VMYXN0U2VlbkRhdGVzKHRvcExldmVsRWxlbWVudHM6IEVsZW1lbnRbXSk6IEppZFRvTGFzdFJlYWRUaW1lc3RhbXAge1xuICAgICAgICBjb25zdCByZXN1bHQ6IEppZFRvTGFzdFJlYWRUaW1lc3RhbXAgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuXG4gICAgICAgIGlmICh0b3BMZXZlbEVsZW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgY29uc3QgW2l0ZW1FbGVtZW50XSA9IHRvcExldmVsRWxlbWVudHM7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGxhc3RSZWFkRW50cnkgb2YgaXRlbUVsZW1lbnQuZ2V0Q2hpbGQod3JhcHBlck5vZGVOYW1lKS5nZXRDaGlsZHJlbihub2RlTmFtZSkpIHtcbiAgICAgICAgICAgICAgICBjb25zdCB7amlkLCBkYXRlfSA9IGxhc3RSZWFkRW50cnkuYXR0cnM7XG4gICAgICAgICAgICAgICAgaWYgKCFpc05hTihkYXRlKSkge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQuc2V0KGppZCwgZGF0ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICB1cGRhdGVDb250YWN0VW5yZWFkTWVzc2FnZVN0YXRlKHJlY2lwaWVudDogUmVjaXBpZW50KSB7XG4gICAgICAgIGNvbnN0IGNvbnRhY3RKaWQgPSByZWNpcGllbnQuamlkQmFyZS50b1N0cmluZygpO1xuICAgICAgICBjb25zdCBsYXN0UmVhZERhdGUgPSB0aGlzLmppZFRvTGFzdFJlYWRUaW1lc3RhbXAuZ2V0KGNvbnRhY3RKaWQpIHx8IDA7XG4gICAgICAgIGNvbnN0IGNvbnRhY3RVbnJlYWRNZXNzYWdlQ291bnQgPSB0aGlzLmNhbGN1bGF0ZVVucmVhZE1lc3NhZ2VDb3VudChyZWNpcGllbnQsIGxhc3RSZWFkRGF0ZSk7XG4gICAgICAgIGNvbnN0IGppZFRvQ291bnQgPSB0aGlzLmppZFRvVW5yZWFkQ291bnQkLmdldFZhbHVlKCk7XG4gICAgICAgIGlmIChqaWRUb0NvdW50LmdldChjb250YWN0SmlkKSAhPT0gY29udGFjdFVucmVhZE1lc3NhZ2VDb3VudCkge1xuICAgICAgICAgICAgdGhpcy5qaWRUb1VucmVhZENvdW50JC5uZXh0KGppZFRvQ291bnQuc2V0KGNvbnRhY3RKaWQsIGNvbnRhY3RVbnJlYWRNZXNzYWdlQ291bnQpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgY2FsY3VsYXRlVW5yZWFkTWVzc2FnZUNvdW50KHJlY2lwaWVudDogUmVjaXBpZW50LCBsYXN0UmVhZFRpbWVzdGFtcDogbnVtYmVyKSB7XG4gICAgICAgIGNvbnN0IGZpcnN0VW5yZWFkTWVzc2FnZUluZGV4ID0gZmluZFNvcnRlZEluc2VydGlvbkluZGV4TGFzdChsYXN0UmVhZFRpbWVzdGFtcCwgcmVjaXBpZW50Lm1lc3NhZ2VzLFxuICAgICAgICAgICAgbWVzc2FnZSA9PiBtZXNzYWdlLmRhdGV0aW1lLmdldFRpbWUoKSk7XG4gICAgICAgIHJldHVybiByZWNpcGllbnQubWVzc2FnZXMuc2xpY2UoZmlyc3RVbnJlYWRNZXNzYWdlSW5kZXgpXG4gICAgICAgICAgICAuZmlsdGVyKG1lc3NhZ2UgPT4gbWVzc2FnZS5kaXJlY3Rpb24gPT09IERpcmVjdGlvbi5pbilcbiAgICAgICAgICAgIC5sZW5ndGg7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBwZXJzaXN0TGFzdFNlZW5EYXRlcygpIHtcbiAgICAgICAgY29uc3QgbGFzdFJlYWROb2RlQnVpbGRlciA9IG5ldyBMYXN0UmVhZEVudHJpZXNOb2RlQnVpbGRlcigpO1xuICAgICAgICBmb3IgKGNvbnN0IFtqaWQsIGRhdGVdIG9mIHRoaXMuamlkVG9MYXN0UmVhZFRpbWVzdGFtcCkge1xuICAgICAgICAgICAgbGFzdFJlYWROb2RlQnVpbGRlci5hZGRMYXN0UmVhZE5vZGUoamlkLCBkYXRlLnRvU3RyaW5nKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5wdWJsaXNoU3Vic2NyaWJlUGx1Z2luLnN0b3JlUHJpdmF0ZVBheWxvYWRQZXJzaXN0ZW50KFxuICAgICAgICAgICAgU1RPUkFHRV9OR1hfQ0hBVF9MQVNUX1JFQURfREFURSxcbiAgICAgICAgICAgICdjdXJyZW50JyxcbiAgICAgICAgICAgIGxhc3RSZWFkTm9kZUJ1aWxkZXIudG9TdGFuemEoKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBoYW5kbGVQdWJTdWJFdmVudChldmVudDogRWxlbWVudCkge1xuICAgICAgICBjb25zdCBpdGVtcyA9IGV2ZW50LmdldENoaWxkKCdpdGVtcycpO1xuICAgICAgICBjb25zdCBpdGVtc05vZGUgPSBpdGVtcyAmJiBpdGVtcy5hdHRycy5ub2RlO1xuICAgICAgICBjb25zdCBpdGVtID0gaXRlbXMgJiYgaXRlbXMuZ2V0Q2hpbGRyZW4oJ2l0ZW0nKTtcbiAgICAgICAgaWYgKGl0ZW1zTm9kZSA9PT0gU1RPUkFHRV9OR1hfQ0hBVF9MQVNUX1JFQURfREFURSAmJiBpdGVtKSB7XG4gICAgICAgICAgICBjb25zdCBwdWJsaXNoZWRMYXN0SmlkVG9EYXRlID0gdGhpcy5wYXJzZUxhc3RTZWVuRGF0ZXMoaXRlbSk7XG4gICAgICAgICAgICB0aGlzLm1lcmdlSmlkVG9EYXRlcyhwdWJsaXNoZWRMYXN0SmlkVG9EYXRlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgbWVyZ2VKaWRUb0RhdGVzKG5ld0ppZFRvRGF0ZTogSmlkVG9MYXN0UmVhZFRpbWVzdGFtcCkge1xuICAgICAgICBmb3IgKGNvbnN0IFtqaWQsIGRhdGVdIG9mIG5ld0ppZFRvRGF0ZSkge1xuICAgICAgICAgICAgY29uc3Qgb2xkTGFzdFJlYWREYXRlID0gdGhpcy5qaWRUb0xhc3RSZWFkVGltZXN0YW1wLmdldChqaWQpO1xuICAgICAgICAgICAgaWYgKCFvbGRMYXN0UmVhZERhdGUgfHwgb2xkTGFzdFJlYWREYXRlIDwgZGF0ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuamlkVG9MYXN0UmVhZFRpbWVzdGFtcC5zZXQoamlkLCBkYXRlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cbiJdfQ==