@hsaadawy/ngx-chat
Version:
232 lines • 39.6 kB
JavaScript
import { __awaiter } from "tslib";
import { ChangeDetectorRef, Component, Inject, Input, Optional, Output, EventEmitter, ViewChild, ViewChildren, } from '@angular/core';
import { Subject } from 'rxjs';
import { debounceTime, filter, takeUntil } from 'rxjs/operators';
import { Direction } from '../../core/message';
import { BlockPlugin } from '../../services/adapters/xmpp/plugins/block.plugin';
import { MessageArchivePlugin } from '../../services/adapters/xmpp/plugins/message-archive.plugin';
import { ChatListStateService } from '../../services/chat-list-state.service';
import { ChatMessageListRegistryService } from '../../services/chat-message-list-registry.service';
import { CHAT_SERVICE_TOKEN } from '../../services/chat-service';
import { ContactFactoryService } from '../../services/contact-factory.service';
import { REPORT_USER_INJECTION_TOKEN } from '../../services/report-user-service';
import { ChatMessageComponent } from '../chat-message/chat-message.component';
var SubscriptionAction;
(function (SubscriptionAction) {
SubscriptionAction[SubscriptionAction["PENDING_REQUEST"] = 0] = "PENDING_REQUEST";
SubscriptionAction[SubscriptionAction["SHOW_BLOCK_ACTIONS"] = 1] = "SHOW_BLOCK_ACTIONS";
SubscriptionAction[SubscriptionAction["NO_PENDING_REQUEST"] = 2] = "NO_PENDING_REQUEST";
})(SubscriptionAction || (SubscriptionAction = {}));
export class ChatMessageListComponent {
constructor(chatListService, chatService, chatMessageListRegistry, reportUserService, changeDetectorRef, contactFactory) {
this.chatListService = chatListService;
this.chatService = chatService;
this.chatMessageListRegistry = chatMessageListRegistry;
this.reportUserService = reportUserService;
this.changeDetectorRef = changeDetectorRef;
this.contactFactory = contactFactory;
this.Reply = new EventEmitter();
this.Direction = Direction;
this.SubscriptionAction = SubscriptionAction;
this.subscriptionAction = SubscriptionAction.NO_PENDING_REQUEST;
this.onTop$ = new Subject();
this.ngDestroy = new Subject();
this.isAtBottom = true;
this.bottomLeftAt = 0;
this.oldestVisibleMessageBeforeLoading = null;
this.blockPlugin = this.chatService.getPlugin(BlockPlugin);
}
ngOnInit() {
return __awaiter(this, void 0, void 0, function* () {
this.onTop$
.pipe(filter(event => event.isIntersecting), debounceTime(1000))
.subscribe(() => this.loadOlderMessagesBeforeViewport());
if (this.recipient.recipientType === 'contact') {
this.recipient.pendingIn$
.pipe(filter(pendingIn => pendingIn === true), takeUntil(this.ngDestroy))
.subscribe(() => {
this.subscriptionAction = SubscriptionAction.PENDING_REQUEST;
this.scheduleScrollToLastMessage();
});
}
this.chatMessageListRegistry.incrementOpenWindowCount(this.recipient);
});
}
ngAfterViewInit() {
return __awaiter(this, void 0, void 0, function* () {
this.chatMessageViewChildrenList.changes
.subscribe(() => {
if (this.oldestVisibleMessageBeforeLoading) {
this.scrollToMessage(this.oldestVisibleMessageBeforeLoading);
}
this.oldestVisibleMessageBeforeLoading = null;
});
const messages$ = this.recipient.messages$;
messages$
.pipe(debounceTime(10), filter(() => this.isNearBottom()), takeUntil(this.ngDestroy))
.subscribe((_) => this.scheduleScrollToLastMessage());
if (this.recipient.messages.length < 10) {
yield this.loadMessages(); // in case insufficient old messages are displayed
}
this.scheduleScrollToLastMessage();
});
}
ngOnChanges(changes) {
const contact = changes.contact;
if (contact && contact.previousValue && contact.currentValue) {
this.chatMessageListRegistry.decrementOpenWindowCount(contact.previousValue);
this.chatMessageListRegistry.incrementOpenWindowCount(contact.currentValue);
}
if (contact && contact.currentValue) {
this.scheduleScrollToLastMessage();
}
}
ngOnDestroy() {
this.ngDestroy.next();
this.chatMessageListRegistry.decrementOpenWindowCount(this.recipient);
}
acceptSubscriptionRequest(event) {
event.preventDefault();
if (this.subscriptionAction === SubscriptionAction.PENDING_REQUEST) {
this.chatService.addContact(this.recipient.jidBare.toString());
this.subscriptionAction = SubscriptionAction.NO_PENDING_REQUEST;
this.scheduleScrollToLastMessage();
}
}
denySubscriptionRequest(event) {
event.preventDefault();
if (this.subscriptionAction === SubscriptionAction.PENDING_REQUEST) {
this.chatService.removeContact(this.recipient.jidBare.toString());
this.subscriptionAction = SubscriptionAction.SHOW_BLOCK_ACTIONS;
this.scheduleScrollToLastMessage();
}
}
scheduleScrollToLastMessage() {
setTimeout(() => this.scrollToLastMessage(), 0);
}
scrollToLastMessage() {
if (this.chatMessageAreaElement) {
this.chatMessageAreaElement.nativeElement.scrollTop = this.chatMessageAreaElement.nativeElement.scrollHeight;
this.isAtBottom = true; // in some browsers the intersection observer does not emit when scrolling programmatically
}
}
scrollToMessage(message) {
if (this.chatMessageAreaElement) {
const htmlIdAttribute = 'message-' + message.id;
const messageElement = document.getElementById(htmlIdAttribute);
messageElement.scrollIntoView(false);
}
}
blockContact($event) {
$event.preventDefault();
this.blockPlugin.blockJid(this.recipient.jidBare.toString());
this.chatListService.closeChat(this.recipient);
this.subscriptionAction = SubscriptionAction.NO_PENDING_REQUEST;
}
blockContactAndReport($event) {
if (this.recipient.recipientType !== 'contact') {
return;
}
$event.preventDefault();
this.reportUserService.reportUser(this.recipient);
this.blockContact($event);
}
dismissBlockOptions($event) {
$event.preventDefault();
this.subscriptionAction = SubscriptionAction.NO_PENDING_REQUEST;
}
subscriptionActionShown() {
if (this.recipient.recipientType !== 'contact') {
return false;
}
return this.subscriptionAction === SubscriptionAction.PENDING_REQUEST
|| (this.blockPlugin.supportsBlock$.getValue() === true && this.subscriptionAction === SubscriptionAction.SHOW_BLOCK_ACTIONS);
}
loadOlderMessagesBeforeViewport() {
return __awaiter(this, void 0, void 0, function* () {
if (this.isLoadingHistory() || this.isNearBottom()) {
return;
}
try {
this.oldestVisibleMessageBeforeLoading = this.recipient.oldestMessage;
yield this.loadMessages();
}
catch (e) {
this.oldestVisibleMessageBeforeLoading = null;
}
});
}
loadMessages() {
return __awaiter(this, void 0, void 0, function* () {
try {
// improve performance when loading lots of old messages
this.changeDetectorRef.detach();
yield this.chatService.getPlugin(MessageArchivePlugin).loadMostRecentUnloadedMessages(this.recipient);
}
finally {
this.changeDetectorRef.reattach();
}
});
}
onBottom(event) {
this.isAtBottom = event.isIntersecting;
if (event.isIntersecting) {
this.isAtBottom = true;
}
else {
this.isAtBottom = false;
this.bottomLeftAt = Date.now();
}
}
isNearBottom() {
return this.isAtBottom || Date.now() - this.bottomLeftAt < 1000;
}
isLoadingHistory() {
return !!this.oldestVisibleMessageBeforeLoading;
}
getOrCreateContactWithFullJid(message) {
if (this.recipient.recipientType === 'contact') {
// this is not a multi user chat, just use recipient as contact
return this.recipient;
}
const roomMessage = message;
let matchingContact = this.chatService.contacts$.getValue().find(contact => contact.jidFull.equals(roomMessage.from));
if (!matchingContact) {
matchingContact = this.contactFactory.createContact(roomMessage.from.toString(), roomMessage.from.resource);
this.chatService.contacts$.next([matchingContact].concat(this.chatService.contacts$.getValue()));
}
this.chatService.contacts$.getValue().forEach(a => {
if (matchingContact.jidFull.resource === a.jidFull.local) {
matchingContact.name = a.name;
}
});
return matchingContact;
}
sendReply(event) {
debugger;
this.Reply.emit(event);
}
}
ChatMessageListComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-chat-message-list',
template: "<div class=\"chat-messages\" #messageArea>\r\n\r\n <div class=\"chat-messages-start\" (ngxChatIntersectionObserver)=\"onTop$.next($event)\"></div>\r\n\r\n <ng-container *ngFor=\"let dateMessagesGroup of recipient.dateMessagesGroups\">\r\n <div class=\"chat-messages-date-group\">{{dateMessagesGroup.date |\r\n date:chatService.translations.dateFormat:undefined:chatService.translations.locale}}</div>\r\n <ngx-chat-message *ngFor=\"let message of dateMessagesGroup.messages\" (ReplySent)=\"sendReply($event)\"\r\n [id]=\"'message-' + message.id\" [class.chat-message--in]=\"message.direction === Direction.in\"\r\n [class.chat-message--out]=\"message.direction === Direction.out\"\r\n [contact]=\"getOrCreateContactWithFullJid(message)\"\r\n [nick]=\"message.direction === Direction.in ? getOrCreateContactWithFullJid(message).name : ''\"\r\n [avatar]=\"getOrCreateContactWithFullJid(message).avatar\" [message]=\"message\" [showAvatars]=\"showAvatars\">\r\n </ngx-chat-message>\r\n </ng-container>\r\n\r\n <div class=\"chat-messages-empty\" *ngIf=\"recipient.messages.length === 0\">\r\n {{chatService.translations.noMessages}}\r\n </div>\r\n\r\n <ngx-chat-message-simple [direction]=\"Direction.in\" [avatar]=\"showAvatars ? recipient.avatar : undefined\"\r\n [footerHidden]=\"true\" *ngIf=\"subscriptionActionShown()\">\r\n <span>\r\n {{chatService.translations.subscriptionRequestMessage}}\r\n </span>\r\n <ul class=\"chat-presence-subscription-actions\">\r\n <li>\r\n <span class=\"action-disabled\"\r\n *ngIf=\"subscriptionAction === SubscriptionAction.SHOW_BLOCK_ACTIONS\">{{chatService.translations.acceptSubscriptionRequest}}</span>\r\n\r\n <a *ngIf=\"subscriptionAction === SubscriptionAction.PENDING_REQUEST\"\r\n (click)=\"acceptSubscriptionRequest($event)\"\r\n href=\"#\">{{chatService.translations.acceptSubscriptionRequest}}</a>\r\n </li>\r\n\r\n <li>\r\n <span class=\"action-disabled\"\r\n *ngIf=\"subscriptionAction === SubscriptionAction.SHOW_BLOCK_ACTIONS\">{{chatService.translations.denySubscriptionRequest}}</span>\r\n\r\n <a *ngIf=\"subscriptionAction === SubscriptionAction.PENDING_REQUEST\"\r\n (click)=\"denySubscriptionRequest($event)\"\r\n href=\"#\">{{chatService.translations.denySubscriptionRequest}}</a>\r\n </li>\r\n </ul>\r\n <ul class=\"deny-actions\"\r\n *ngIf=\"(blockPlugin.supportsBlock$ | async) === true && subscriptionAction === SubscriptionAction.SHOW_BLOCK_ACTIONS\">\r\n <li>\r\n <a (click)=\"blockContact($event)\" href=\"#\">{{chatService.translations.block}}</a>\r\n </li>\r\n <li *ngIf=\"reportUserService\">\r\n <a (click)=\"blockContactAndReport($event)\" href=\"#\">{{chatService.translations.blockAndReport}}</a>\r\n </li>\r\n <li>\r\n <a (click)=\"dismissBlockOptions($event)\" href=\"#\">{{chatService.translations.dismiss}}</a>\r\n </li>\r\n </ul>\r\n </ngx-chat-message-simple>\r\n\r\n <div class=\"chat-messages-end\" (ngxChatIntersectionObserver)=\"onBottom($event)\"></div>\r\n\r\n</div>\r\n",
styles: [":host.chat-message--out{align-self:flex-end}:host.chat-message--in{align-self:flex-start}.chat-messages{display:flex;flex-direction:column;min-height:10em;max-height:20em;overflow-y:scroll}.chat-messages-date-group{font-size:.7em;font-style:italic;margin:.5em 0;text-align:center}ngx-chat-message,ngx-chat-message-simple{max-width:76%;align-self:flex-start;animation-duration:1.5s;animation-timing-function:cubic-bezier(.16,1,.3,1)}ngx-chat-message.chat-message--in,ngx-chat-message-simple.chat-message--in{animation-name:ngx-chat-message-in}ngx-chat-message.chat-message--out,ngx-chat-message-simple.chat-message--out{animation-name:ngx-chat-message-out}.chat-messages-empty{text-align:center;font-size:1.5em;color:#999;margin-top:1em;margin-bottom:1em}.chat-presence-subscription-actions,.deny-actions{list-style:none;padding:0;margin:1em 0 0}.chat-presence-subscription-actions a,.deny-actions a,.chat-presence-subscription-actions a:visited,.deny-actions a:visited{color:#198cff}.deny-actions{margin-top:1em}.action-disabled{color:#999}.chat-messages-start{min-height:5px;height:5px;margin-top:5px}.chat-messages-end{min-height:5px;height:5px;margin-bottom:5px}\n"]
},] }
];
ChatMessageListComponent.ctorParameters = () => [
{ type: ChatListStateService },
{ type: undefined, decorators: [{ type: Inject, args: [CHAT_SERVICE_TOKEN,] }] },
{ type: ChatMessageListRegistryService },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [REPORT_USER_INJECTION_TOKEN,] }] },
{ type: ChangeDetectorRef },
{ type: ContactFactoryService }
];
ChatMessageListComponent.propDecorators = {
Reply: [{ type: Output }],
recipient: [{ type: Input }],
showAvatars: [{ type: Input }],
chatMessageAreaElement: [{ type: ViewChild, args: ['messageArea',] }],
chatMessageViewChildrenList: [{ type: ViewChildren, args: [ChatMessageComponent,] }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1tZXNzYWdlLWxpc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvcGF6em5ldHdvcmsvbmd4LWNoYXQvc3JjL2xpYi9jb21wb25lbnRzL2NoYXQtbWVzc2FnZS1saXN0L2NoYXQtbWVzc2FnZS1saXN0LmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUVILGlCQUFpQixFQUNqQixTQUFTLEVBRVQsTUFBTSxFQUNOLEtBQUssRUFJTCxRQUFRLEVBQ1IsTUFBTSxFQUVOLFlBQVksRUFFWixTQUFTLEVBQ1QsWUFBWSxHQUNmLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBVyxNQUFNLG9CQUFvQixDQUFDO0FBRXhELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxtREFBbUQsQ0FBQztBQUNoRixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSw2REFBNkQsQ0FBQztBQUVuRyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUM5RSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsTUFBTSxtREFBbUQsQ0FBQztBQUNuRyxPQUFPLEVBQUUsa0JBQWtCLEVBQWUsTUFBTSw2QkFBNkIsQ0FBQztBQUM5RSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUMvRSxPQUFPLEVBQUUsMkJBQTJCLEVBQXFCLE1BQU0sb0NBQW9DLENBQUM7QUFDcEcsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFFOUUsSUFBSyxrQkFJSjtBQUpELFdBQUssa0JBQWtCO0lBQ25CLGlGQUFl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QyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUE7SUFDMUIsQ0FBQzs7O1lBclBKLFNBQVMsU0FBQztnQkFDUCxRQUFRLEVBQUUsdUJBQXVCO2dCQUNqQywyNUdBQWlEOzthQUVwRDs7O1lBakJRLG9CQUFvQjs0Q0ErQ3BCLE1BQU0sU0FBQyxrQkFBa0I7WUE5Q3pCLDhCQUE4Qjs0Q0FnRDlCLFFBQVEsWUFBSSxNQUFNLFNBQUMsMkJBQTJCO1lBeEVuRCxpQkFBaUI7WUEwQloscUJBQXFCOzs7b0JBaUJ6QixNQUFNO3dCQUVOLEtBQUs7MEJBR0wsS0FBSztxQ0FHTCxTQUFTLFNBQUMsYUFBYTswQ0FHdkIsWUFBWSxTQUFDLG9CQUFvQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgICBBZnRlclZpZXdJbml0LFxyXG4gICAgQ2hhbmdlRGV0ZWN0b3JSZWYsXHJcbiAgICBDb21wb25lbnQsXHJcbiAgICBFbGVtZW50UmVmLFxyXG4gICAgSW5qZWN0LFxyXG4gICAgSW5wdXQsXHJcbiAgICBPbkNoYW5nZXMsXHJcbiAgICBPbkRlc3Ryb3ksXHJcbiAgICBPbkluaXQsXHJcbiAgICBPcHRpb25hbCxcclxuICAgIE91dHB1dCxcclxuICAgIFF1ZXJ5TGlzdCxcclxuICAgIEV2ZW50RW1pdHRlcixcclxuICAgIFNpbXBsZUNoYW5nZXMsXHJcbiAgICBWaWV3Q2hpbGQsXHJcbiAgICBWaWV3Q2hpbGRyZW4sXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBmaWx0ZXIsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgRGlyZWN0aW9uLCBNZXNzYWdlIH0gZnJvbSAnLi4vLi4vY29yZS9tZXNzYWdlJztcclxuaW1wb3J0IHsgUmVjaXBpZW50IH0gZnJvbSAnLi4vLi4vY29yZS9yZWNpcGllbnQnO1xyXG5pbXBvcnQgeyBCbG9ja1BsdWdpbiB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FkYXB0ZXJzL3htcHAvcGx1Z2lucy9ibG9jay5wbHVnaW4nO1xyXG5pbXBvcnQgeyBNZXNzYWdlQXJjaGl2ZVBsdWdpbiB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2FkYXB0ZXJzL3htcHAvcGx1Z2lucy9tZXNzYWdlLWFyY2hpdmUucGx1Z2luJztcclxuaW1wb3J0IHsgUm9vbU1lc3NhZ2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9hZGFwdGVycy94bXBwL3BsdWdpbnMvbXVsdGktdXNlci1jaGF0LnBsdWdpbic7XHJcbmltcG9ydCB7IENoYXRMaXN0U3RhdGVTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvY2hhdC1saXN0LXN0YXRlLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBDaGF0TWVzc2FnZUxpc3RSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9jaGF0LW1lc3NhZ2UtbGlzdC1yZWdpc3RyeS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgQ0hBVF9TRVJWSUNFX1RPS0VOLCBDaGF0U2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2NoYXQtc2VydmljZSc7XHJcbmltcG9ydCB7IENvbnRhY3RGYWN0b3J5U2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2NvbnRhY3QtZmFjdG9yeS5zZXJ2aWNlJztcclxuaW1wb3J0IHsgUkVQT1JUX1VTRVJfSU5KRUNUSU9OX1RPS0VOLCBSZXBvcnRVc2VyU2VydmljZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL3JlcG9ydC11c2VyLXNlcnZpY2UnO1xyXG5pbXBvcnQgeyBDaGF0TWVzc2FnZUNvbXBvbmVudCB9IGZyb20gJy4uL2NoYXQtbWVzc2FnZS9jaGF0LW1lc3NhZ2UuY29tcG9uZW50JztcclxuXHJcbmVudW0gU3Vic2NyaXB0aW9uQWN0aW9uIHtcclxuICAgIFBFTkRJTkdfUkVRVUVTVCxcclxuICAgIFNIT1dfQkxPQ0tfQUNUSU9OUyxcclxuICAgIE5PX1BFTkRJTkdfUkVRVUVTVCxcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgICBzZWxlY3RvcjogJ25neC1jaGF0LW1lc3NhZ2UtbGlzdCcsXHJcbiAgICB0ZW1wbGF0ZVVybDogJy4vY2hhdC1tZXNzYWdlLWxpc3QuY29tcG9uZW50Lmh0bWwnLFxyXG4gICAgc3R5bGVVcmxzOiBbJy4vY2hhdC1tZXNzYWdlLWxpc3QuY29tcG9uZW50Lmxlc3MnXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIENoYXRNZXNzYWdlTGlzdENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95LCBPbkNoYW5nZXMsIEFmdGVyVmlld0luaXQge1xyXG5cclxuICAgIEBPdXRwdXQoKVxyXG4gICAgcHVibGljIFJlcGx5ID0gbmV3IEV2ZW50RW1pdHRlcjx2b2lkPigpO1xyXG4gICAgQElucHV0KClcclxuICAgIHJlY2lwaWVudDogUmVjaXBpZW50O1xyXG5cclxuICAgIEBJbnB1dCgpXHJcbiAgICBzaG93QXZhdGFyczogYm9vbGVhbjtcclxuXHJcbiAgICBAVmlld0NoaWxkKCdtZXNzYWdlQXJlYScpXHJcbiAgICBjaGF0TWVzc2FnZUFyZWFFbGVtZW50OiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcclxuXHJcbiAgICBAVmlld0NoaWxkcmVuKENoYXRNZXNzYWdlQ29tcG9uZW50KVxyXG4gICAgY2hhdE1lc3NhZ2VWaWV3Q2hpbGRyZW5MaXN0OiBRdWVyeUxpc3Q8Q2hhdE1lc3NhZ2VDb21wb25lbnQ+O1xyXG5cclxuICAgIERpcmVjdGlvbiA9IERpcmVjdGlvbjtcclxuICAgIFN1YnNjcmlwdGlvbkFjdGlvbiA9IFN1YnNjcmlwdGlvbkFjdGlvbjtcclxuICAgIGJsb2NrUGx1Z2luOiBCbG9ja1BsdWdpbjtcclxuICAgIHN1YnNjcmlwdGlvbkFjdGlvbiA9IFN1YnNjcmlwdGlvbkFjdGlvbi5OT19QRU5ESU5HX1JFUVVFU1Q7XHJcbiAgICBvblRvcCQgPSBuZXcgU3ViamVjdDxJbnRlcnNlY3Rpb25PYnNlcnZlckVudHJ5PigpO1xyXG5cclxuICAgIHByaXZhdGUgbmdEZXN0cm95ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuICAgIHByaXZhdGUgaXNBdEJvdHRvbSA9IHRydWU7XHJcbiAgICBwcml2YXRlIGJvdHRvbUxlZnRBdCA9IDA7XHJcbiAgICBwcml2YXRlIG9sZGVzdFZpc2libGVNZXNzYWdlQmVmb3JlTG9hZGluZzogTWVzc2FnZSA9IG51bGw7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHVibGljIGNoYXRMaXN0U2VydmljZTogQ2hhdExpc3RTdGF0ZVNlcnZpY2UsXHJcbiAgICAgICAgQEluamVjdChDSEFUX1NFUlZJQ0VfVE9LRU4pIHB1YmxpYyBjaGF0U2VydmljZTogQ2hhdFNlcnZpY2UsXHJcbiAgICAgICAgcHJpdmF0ZSBjaGF0TWVzc2FnZUxpc3RSZWdpc3RyeTogQ2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnlTZXJ2aWNlLFxyXG4gICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoUkVQT1JUX1VTRVJfSU5KRUNUSU9OX1RPS0VOKSBwdWJsaWMgcmVwb3J0VXNlclNlcnZpY2U6IFJlcG9ydFVzZXJTZXJ2aWNlLFxyXG4gICAgICAgIHByaXZhdGUgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmLFxyXG4gICAgICAgIHByaXZhdGUgY29udGFjdEZhY3Rvcnk6IENvbnRhY3RGYWN0b3J5U2VydmljZSxcclxuICAgICkge1xyXG4gICAgICAgIHRoaXMuYmxvY2tQbHVnaW4gPSB0aGlzLmNoYXRTZXJ2aWNlLmdldFBsdWdpbihCbG9ja1BsdWdpbik7XHJcbiAgICB9XHJcblxyXG4gICAgYXN5bmMgbmdPbkluaXQoKSB7XHJcblxyXG4gICAgICAgIHRoaXMub25Ub3AkXHJcbiAgICAgICAgICAgIC5waXBlKGZpbHRlcihldmVudCA9PiBldmVudC5pc0ludGVyc2VjdGluZyksIGRlYm91bmNlVGltZSgxMDAwKSlcclxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLmxvYWRPbGRlck1lc3NhZ2VzQmVmb3JlVmlld3BvcnQoKSk7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLnJlY2lwaWVudC5yZWNpcGllbnRUeXBlID09PSAnY29udGFjdCcpIHtcclxuICAgICAgICAgICAgdGhpcy5yZWNpcGllbnQucGVuZGluZ0luJFxyXG4gICAgICAgICAgICAgICAgLnBpcGUoXHJcbiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHBlbmRpbmdJbiA9PiBwZW5kaW5nSW4gPT09IHRydWUpLFxyXG4gICAgICAgICAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLm5nRGVzdHJveSksXHJcbiAgICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLnN1YnNjcmlwdGlvbkFjdGlvbiA9IFN1YnNjcmlwdGlvbkFjdGlvbi5QRU5ESU5HX1JFUVVFU1Q7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zY2hlZHVsZVNjcm9sbFRvTGFzdE1lc3NhZ2UoKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5jaGF0TWVzc2FnZUxpc3RSZWdpc3RyeS5pbmNyZW1lbnRPcGVuV2luZG93Q291bnQodGhpcy5yZWNpcGllbnQpO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcclxuICAgICAgICB0aGlzLmNoYXRNZXNzYWdlVmlld0NoaWxkcmVuTGlzdC5jaGFuZ2VzXHJcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMub2xkZXN0VmlzaWJsZU1lc3NhZ2VCZWZvcmVMb2FkaW5nKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zY3JvbGxUb01lc3NhZ2UodGhpcy5vbGRlc3RWaXNpYmxlTWVzc2FnZUJlZm9yZUxvYWRpbmcpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgdGhpcy5vbGRlc3RWaXNpYmxlTWVzc2FnZUJlZm9yZUxvYWRpbmcgPSBudWxsO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgY29uc3QgbWVzc2FnZXMkOiBPYnNlcnZhYmxlPE1lc3NhZ2U+ID0gdGhpcy5yZWNpcGllbnQubWVzc2FnZXMkO1xyXG4gICAgICAgIG1lc3NhZ2VzJFxyXG4gICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgIGRlYm91bmNlVGltZSgxMCksXHJcbiAgICAgICAgICAgICAgICBmaWx0ZXIoKCkgPT4gdGhpcy5pc05lYXJCb3R0b20oKSksXHJcbiAgICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5uZ0Rlc3Ryb3kpLFxyXG4gICAgICAgICAgICApXHJcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKF8pID0+IHRoaXMuc2NoZWR1bGVTY3JvbGxUb0xhc3RNZXNzYWdlKCkpO1xyXG5cclxuICAgICAgICBpZiAodGhpcy5yZWNpcGllbnQubWVzc2FnZXMubGVuZ3RoIDwgMTApIHtcclxuICAgICAgICAgICAgYXdhaXQgdGhpcy5sb2FkTWVzc2FnZXMoKTsgLy8gaW4gY2FzZSBpbnN1ZmZpY2llbnQgb2xkIG1lc3NhZ2VzIGFyZSBkaXNwbGF5ZWRcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5zY2hlZHVsZVNjcm9sbFRvTGFzdE1lc3NhZ2UoKTtcclxuICAgIH1cclxuXHJcbiAgICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcbiAgICAgICAgY29uc3QgY29udGFjdCA9IGNoYW5nZXMuY29udGFjdDtcclxuXHJcbiAgICAgICAgaWYgKGNvbnRhY3QgJiYgY29udGFjdC5wcmV2aW91c1ZhbHVlICYmIGNvbnRhY3QuY3VycmVudFZhbHVlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnkuZGVjcmVtZW50T3BlbldpbmRvd0NvdW50KGNvbnRhY3QucHJldmlvdXNWYWx1ZSk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hhdE1lc3NhZ2VMaXN0UmVnaXN0cnkuaW5jcmVtZW50T3BlbldpbmRvd0NvdW50KGNvbnRhY3QuY3VycmVudFZhbHVlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChjb250YWN0ICYmIGNvbnRhY3QuY3VycmVudFZhbHVlKSB7XHJcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGVTY3JvbGxUb0xhc3RNZXNzYWdlKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMubmdEZXN0cm95Lm5leHQoKTtcclxuICAgICAgICB0aGlzLmNoYXRNZXNzYWdlTGlzdFJlZ2lzdHJ5LmRlY3JlbWVudE9wZW5XaW5kb3dDb3VudCh0aGlzLnJlY2lwaWVudCk7XHJcbiAgICB9XHJcblxyXG4gICAgYWNjZXB0U3Vic2NyaXB0aW9uUmVxdWVzdChldmVudDogRXZlbnQpIHtcclxuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIGlmICh0aGlzLnN1YnNjcmlwdGlvbkFjdGlvbiA9PT0gU3Vic2NyaXB0aW9uQWN0aW9uLlBFTkRJTkdfUkVRVUVTVCkge1xyXG4gICAgICAgICAgICB0aGlzLmNoYXRTZXJ2aWNlLmFkZENvbnRhY3QodGhpcy5yZWNpcGllbnQuamlkQmFyZS50b1N0cmluZygpKTtcclxuICAgICAgICAgICAgdGhpcy5zdWJzY3JpcHRpb25BY3Rpb24gPSBTdWJzY3JpcHRpb25BY3Rpb24uTk9fUEVORElOR19SRVFVRVNUO1xyXG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlU2Nyb2xsVG9MYXN0TWVzc2FnZSgpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBkZW55U3Vic2NyaXB0aW9uUmVxdWVzdChldmVudDogRXZlbnQpIHtcclxuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIGlmICh0aGlzLnN1YnNjcmlwdGlvbkFjdGlvbiA9PT0gU3Vic2NyaXB0aW9uQWN0aW9uLlBFTkRJTkdfUkVRVUVTVCkge1xyXG4gICAgICAgICAgICB0aGlzLmNoYXRTZXJ2aWNlLnJlbW92ZUNvbnRhY3QodGhpcy5yZWNpcGllbnQuamlkQmFyZS50b1N0cmluZygpKTtcclxuICAgICAgICAgICAgdGhpcy5zdWJzY3JpcHRpb25BY3Rpb24gPSBTdWJzY3JpcHRpb25BY3Rpb24uU0hPV19CTE9DS19BQ1RJT05TO1xyXG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlU2Nyb2xsVG9MYXN0TWVzc2FnZSgpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBzY2hlZHVsZVNjcm9sbFRvTGFzdE1lc3NhZ2UoKSB7XHJcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnNjcm9sbFRvTGFzdE1lc3NhZ2UoKSwgMCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBzY3JvbGxUb0xhc3RNZXNzYWdlKCkge1xyXG4gICAgICAgIGlmICh0aGlzLmNoYXRNZXNzYWdlQXJlYUVsZW1lbnQpIHtcclxuICAgICAgICAgICAgdGhpcy5jaGF0TWVzc2FnZUFyZWFFbGVtZW50Lm5hdGl2ZUVsZW1lbnQuc2Nyb2xsVG9wID0gdGhpcy5jaGF0TWVzc2FnZUFyZWFFbGVtZW50Lm5hdGl2ZUVsZW1lbnQuc2Nyb2xsSGVpZ2h0O1xyXG4gICAgICAgICAgICB0aGlzLmlzQXRCb3R0b20gPSB0cnVlOyAvLyBpbiBzb21lIGJyb3dzZXJzIHRoZSBpbnRlcnNlY3Rpb24gb2JzZXJ2ZXIgZG9lcyBub3QgZW1pdCB3aGVuIHNjcm9sbGluZyBwcm9ncmFtbWF0aWNhbGx5XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgc2Nyb2xsVG9NZXNzYWdlKG1lc3NhZ2U6IE1lc3NhZ2UpIHtcclxuICAgICAgICBpZiAodGhpcy5jaGF0TWVzc2FnZUFyZWFFbGVtZW50KSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGh0bWxJZEF0dHJpYnV0ZSA9ICdtZXNzYWdlLScgKyBtZXNzYWdlLmlkO1xyXG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlRWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGh0bWxJZEF0dHJpYnV0ZSk7XHJcbiAgICAgICAgICAgIG1lc3NhZ2VFbGVtZW50LnNjcm9sbEludG9WaWV3KGZhbHNlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgYmxvY2tDb250YWN0KCRldmVudDogTW91c2VFdmVudCkge1xyXG4gICAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIHRoaXMuYmxvY2tQbHVnaW4uYmxvY2tKaWQodGhpcy5yZWNpcGllbnQuamlkQmFyZS50b1N0cmluZygpKTtcclxuICAgICAgICB0aGlzLmNoYXRMaXN0U2VydmljZS5jbG9zZUNoYXQodGhpcy5yZWNpcGllbnQpO1xyXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9uQWN0aW9uID0gU3Vic2NyaXB0aW9uQWN0aW9uLk5PX1BFTkRJTkdfUkVRVUVTVDtcclxuICAgIH1cclxuXHJcbiAgICBibG9ja0NvbnRhY3RBbmRSZXBvcnQoJGV2ZW50OiBNb3VzZUV2ZW50KSB7XHJcbiAgICAgICAgaWYgKHRoaXMucmVjaXBpZW50LnJlY2lwaWVudFR5cGUgIT09ICdjb250YWN0Jykge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIHRoaXMucmVwb3J0VXNlclNlcnZpY2UucmVwb3J0VXNlcih0aGlzLnJlY2lwaWVudCk7XHJcbiAgICAgICAgdGhpcy5ibG9ja0NvbnRhY3QoJGV2ZW50KTtcclxuICAgIH1cclxuXHJcbiAgICBkaXNtaXNzQmxvY2tPcHRpb25zKCRldmVudDogTW91c2VFdmVudCkge1xyXG4gICAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIHRoaXMuc3Vic2NyaXB0aW9uQWN0aW9uID0gU3Vic2NyaXB0aW9uQWN0aW9uLk5PX1BFTkRJTkdfUkVRVUVTVDtcclxuICAgIH1cclxuXHJcbiAgICBzdWJzY3JpcHRpb25BY3Rpb25TaG93bigpIHtcclxuICAgICAgICBpZiAodGhpcy5yZWNpcGllbnQucmVjaXBpZW50VHlwZSAhPT0gJ2NvbnRhY3QnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3Vic2NyaXB0aW9uQWN0aW9uID09PSBTdWJzY3JpcHRpb25BY3Rpb24uUEVORElOR19SRVFVRVNUXHJcbiAgICAgICAgICAgIHx8ICh0aGlzLmJsb2NrUGx1Z2luLnN1cHBvcnRzQmxvY2skLmdldFZhbHVlKCkgPT09IHRydWUgJiYgdGhpcy5zdWJzY3JpcHRpb25BY3Rpb24gPT09IFN1YnNjcmlwdGlvbkFjdGlvbi5TSE9XX0JMT0NLX0FDVElPTlMpO1xyXG4gICAgfVxyXG5cclxuICAgIGFzeW5jIGxvYWRPbGRlck1lc3NhZ2VzQmVmb3JlVmlld3BvcnQoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuaXNMb2FkaW5nSGlzdG9yeSgpIHx8IHRoaXMuaXNOZWFyQm90dG9tKCkpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgdGhpcy5vbGRlc3RWaXNpYmxlTWVzc2FnZUJlZm9yZUxvYWRpbmcgPSB0aGlzLnJlY2lwaWVudC5vbGRlc3RNZXNzYWdlO1xyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLmxvYWRNZXNzYWdlcygpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgICAgdGhpcy5vbGRlc3RWaXNpYmxlTWVzc2FnZUJlZm9yZUxvYWRpbmcgPSBudWxsO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGFzeW5jIGxvYWRNZXNzYWdlcygpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAvLyBpbXByb3ZlIHBlcmZvcm1hbmNlIHdoZW4gbG9hZGluZyBsb3RzIG9mIG9sZCBtZXNzYWdlc1xyXG4gICAgICAgICAgICB0aGlzLmNoYW5nZURldGVjdG9yUmVmLmRldGFjaCgpO1xyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNoYXRTZXJ2aWNlLmdldFBsdWdpbihNZXNzYWdlQXJjaGl2ZVBsdWdpbikubG9hZE1vc3RSZWNlbnRVbmxvYWRlZE1lc3NhZ2VzKHRoaXMucmVjaXBpZW50KTtcclxuICAgICAgICB9IGZpbmFsbHkge1xyXG4gICAgICAgICAgICB0aGlzLmNoYW5nZURldGVjdG9yUmVmLnJlYXR0YWNoKCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIG9uQm90dG9tKGV2ZW50OiBJbnRlcnNlY3Rpb25PYnNlcnZlckVudHJ5KSB7XHJcbiAgICAgICAgdGhpcy5pc0F0Qm90dG9tID0gZXZlbnQuaXNJbnRlcnNlY3Rpbmc7XHJcblxyXG4gICAgICAgIGlmIChldmVudC5pc0ludGVyc2VjdGluZykge1xyXG4gICAgICAgICAgICB0aGlzLmlzQXRCb3R0b20gPSB0cnVlO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMuaXNBdEJvdHRvbSA9IGZhbHNlO1xyXG4gICAgICAgICAgICB0aGlzLmJvdHRvbUxlZnRBdCA9IERhdGUubm93KCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgaXNOZWFyQm90dG9tKCkge1xyXG4gICAgICAgIHJldHVybiB0aGlzLmlzQXRCb3R0b20gfHwgRGF0ZS5ub3coKSAtIHRoaXMuYm90dG9tTGVmdEF0IDwgMTAwMDtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGlzTG9hZGluZ0hpc3RvcnkoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgcmV0dXJuICEhdGhpcy5vbGRlc3RWaXNpYmxlTWVzc2FnZUJlZm9yZUxvYWRpbmc7XHJcbiAgICB9XHJcblxyXG4gICAgZ2V0T3JDcmVhdGVDb250YWN0V2l0aEZ1bGxKaWQobWVzc2FnZTogTWVzc2FnZSB8IFJvb21NZXNzYWdlKTogUmVjaXBpZW50IHtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMucmVjaXBpZW50LnJlY2lwaWVudFR5cGUgPT09ICdjb250YWN0Jykge1xyXG4gICAgICAgICAgICAvLyB0aGlzIGlzIG5vdCBhIG11bHRpIHVzZXIgY2hhdCwganVzdCB1c2UgcmVjaXBpZW50IGFzIGNvbnRhY3RcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVjaXBpZW50O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3Qgcm9vbU1lc3NhZ2UgPSBtZXNzYWdlIGFzIFJvb21NZXNzYWdlO1xyXG5cclxuICAgICAgICBsZXQgbWF0Y2hpbmdDb250YWN0ID0gdGhpcy5jaGF0U2VydmljZS5jb250YWN0cyQuZ2V0VmFsdWUoKS5maW5kKFxyXG4gICAgICAgICAgICBjb250YWN0ID0+IGNvbnRhY3QuamlkRnVsbC5lcXVhbHMocm9vbU1lc3NhZ2UuZnJvbSksXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgaWYgKCFtYXRjaGluZ0NvbnRhY3QpIHtcclxuICAgICAgICAgICAgbWF0Y2hpbmdDb250YWN0ID0gdGhpcy5jb250YWN0RmFjdG9yeS5jcmVhdGVDb250YWN0KHJvb21NZXNzYWdlLmZyb20udG9TdHJpbmcoKSwgcm9vbU1lc3NhZ2UuZnJvbS5yZXNvdXJjZSk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hhdFNlcnZpY2UuY29udGFjdHMkLm5leHQoW21hdGNoaW5nQ29udGFjdF0uY29uY2F0KHRoaXMuY2hhdFNlcnZpY2UuY29udGFjdHMkLmdldFZhbHVlKCkpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuY2hhdFNlcnZpY2UuY29udGFjdHMkLmdldFZhbHVlKCkuZm9yRWFjaChhID0+IHtcclxuXHJcbiAgICAgICAgICAgIGlmIChtYXRjaGluZ0NvbnRhY3QuamlkRnVsbC5yZXNvdXJjZSA9PT0gYS5qaWRGdWxsLmxvY2FsKSB7XHJcbiAgICAgICAgICAgICAgICBtYXRjaGluZ0NvbnRhY3QubmFtZSA9IGEubmFtZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pXHJcbiAgICAgICAgcmV0dXJuIG1hdGNoaW5nQ29udGFjdDtcclxuICAgIH1cclxuXHJcblxyXG4gICAgc2VuZFJlcGx5KGV2ZW50KSB7XHJcbiAgICAgICAgZGVidWdnZXJcclxuICAgICAgICB0aGlzLlJlcGx5LmVtaXQoZXZlbnQpXHJcbiAgICB9XHJcbn1cclxuIl19