@pazznetwork/ngx-chat
Version:
[](https://travis-ci.com/pazznetwork/ngx-chat) [](https://coveralls.io/github/pazzn
154 lines • 26.8 kB
JavaScript
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==