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

95 lines 24.7 kB
import { Component, Inject, Input, Optional, ViewChild } from '@angular/core'; import { Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { Direction } from '../../core/message'; import { CONTACT_CLICK_HANDLER_TOKEN } from '../../hooks/chat-contact-click-handler'; import { CHAT_SERVICE_TOKEN } from '../../services/chat-service'; import { ChatMessageInputComponent } from '../chat-message-input/chat-message-input.component'; import { ChatMessageListComponent } from '../chat-message-list/chat-message-list.component'; import { FILE_UPLOAD_HANDLER_TOKEN } from '../../hooks/file-upload-handler'; import * as i0 from "@angular/core"; import * as i1 from "../../services/chat-list-state.service"; import * as i2 from "@angular/common"; import * as i3 from "../chat-message-input/chat-message-input.component"; import * as i4 from "../chat-message-list/chat-message-list.component"; import * as i5 from "../chat-filedrop/file-drop.component"; import * as i6 from "../chat-window-frame/chat-window-frame.component"; import * as i7 from "../chat-avatar/chat-avatar.component"; export class ChatWindowComponent { constructor(chatService, chatListService, fileUploadHandler, contactClickHandler) { this.chatService = chatService; this.chatListService = chatListService; this.fileUploadHandler = fileUploadHandler; this.contactClickHandler = contactClickHandler; this.ngDestroy = new Subject(); } ngOnInit() { const messages$ = this.chatWindowState.recipient.messages$; messages$ .pipe(filter(message => message.direction === Direction.in), takeUntil(this.ngDestroy)) .subscribe(() => { this.chatWindowState.isCollapsed = false; }); } ngOnDestroy() { this.ngDestroy.next(); this.ngDestroy.complete(); } onClickHeader() { this.chatWindowState.isCollapsed = !this.chatWindowState.isCollapsed; } onClickClose() { this.chatListService.closeChat(this.chatWindowState.recipient); } sendMessage() { this.messageInput.onSendMessage(); } afterSendMessage() { this.contactMessageList.scheduleScrollToLastMessage(); } async uploadFile(file) { const url = await this.fileUploadHandler.upload(file); this.chatService.sendMessage(this.chatWindowState.recipient, url); } onFocus() { this.messageInput.focus(); } onActionClick(chatAction) { chatAction.onClick({ contact: this.chatWindowState.recipient.jidBare.toString(), chatWindow: this, }); } onContactClick($event) { if (this.contactClickHandler && !this.chatWindowState.isCollapsed) { $event.stopPropagation(); this.contactClickHandler.onClick(this.chatWindowState.recipient); } } } ChatWindowComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ChatWindowComponent, deps: [{ token: CHAT_SERVICE_TOKEN }, { token: i1.ChatListStateService }, { token: FILE_UPLOAD_HANDLER_TOKEN }, { token: CONTACT_CLICK_HANDLER_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Component }); ChatWindowComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: ChatWindowComponent, selector: "ngx-chat-window", inputs: { chatWindowState: "chatWindowState" }, viewQueries: [{ propertyName: "messageInput", first: true, predicate: ChatMessageInputComponent, descendants: true }, { propertyName: "contactMessageList", first: true, predicate: ChatMessageListComponent, descendants: true }], ngImport: i0, template: "<ngx-chat-window-frame\n (headerClick)=\"onClickHeader()\"\n (closeClick)=\"onClickClose()\">\n\n <ng-container class=\"window-header-content\">\n <div class=\"chat-contact-avatar-wrapper\"\n (click)=\"onContactClick($event)\"\n >\n <ngx-chat-avatar [imageUrl]=\"chatWindowState.recipient.avatar\"></ngx-chat-avatar>\n </div>\n\n <div class=\"header-middle\">\n\n <div class=\"chat-contact-name-wrapper\"\n [title]=\"chatWindowState.recipient.name\"\n >\n <span [ngClass]=\"{'has-click-handler': !chatWindowState.isCollapsed && !!this.contactClickHandler}\"\n (click)=\"onContactClick($event)\">\n {{chatWindowState.recipient.name}}\n </span>\n </div>\n\n <div class=\"chat-contact-status-wrapper\"\n *ngIf=\"!chatWindowState.isCollapsed && chatWindowState.recipient.recipientType === 'contact'\"\n >\n <span class=\"chat-contact-status\">\n {{chatService.translations.presence[chatWindowState.recipient.presence$ | async]}}\n </span>\n </div>\n\n </div>\n </ng-container>\n\n <ngx-chat-filedrop\n *ngIf=\"!chatWindowState.isCollapsed\"\n class=\"window-content\"\n [enabled]=\"fileUploadHandler.isUploadSupported()\"\n (fileUpload)=\"uploadFile($event)\"\n [dropMessage]=\"chatService.translations.dropMessage\">\n <div (click)=\"onFocus()\">\n <ngx-chat-message-list\n [recipient]=\"chatWindowState.recipient\"\n [showAvatars]=\"false\"></ngx-chat-message-list>\n <div class=\"chat-input-container\">\n <ngx-chat-message-input\n [recipient]=\"chatWindowState.recipient\"\n (messageSent)=\"afterSendMessage()\"\n ></ngx-chat-message-input>\n <div *ngFor=\"let action of chatService.chatActions\"\n (click)=\"onActionClick(action)\"\n class=\"chat-action\"\n [ngClass]=\"action.cssClass\"\n [innerHTML]=\"action.html\">\n </div>\n </div>\n </div>\n </ngx-chat-filedrop>\n\n</ngx-chat-window-frame>\n", styles: ["@keyframes ngx-chat-message-in{0%{transform:translate(50px);opacity:0}to{transform:none;opacity:1}}@keyframes ngx-chat-message-out{0%{transform:translate(-50px);opacity:0}to{transform:none;opacity:1}}*{box-sizing:border-box;margin:0;padding:0;font-family:Helvetica,Arial,serif}.chat-contact-avatar-wrapper{min-width:2em;width:2em;min-height:2em;height:2em}.header-middle{flex-grow:1;flex-shrink:1;padding:0 .5em;white-space:nowrap;overflow:hidden;font-size:.8em;line-height:1.2;height:100%;display:flex;flex-direction:column;justify-content:space-around}.chat-contact-name-wrapper,.chat-contact-status-wrapper{text-overflow:ellipsis;overflow:hidden;display:block}.has-click-handler:hover{text-decoration:underline}.chat-contact-status{color:#999}.window-content{text-align:left;padding:0;min-height:5em;display:flex;flex-direction:column;overflow-x:hidden;overflow-y:auto}.chat-input-container{display:flex;padding:.5em;border-top:1px solid #e1e1e1;background:#fff;cursor:text}.chat-action{cursor:pointer;align-self:center;text-align:center}.chat-window-send{background-color:#fff;border-color:#fff;color:#000;width:1.5em}.chat-window-send:active{border:none}ngx-chat-message-input{flex-grow:1}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.ChatMessageInputComponent, selector: "ngx-chat-message-input", inputs: ["recipient"], outputs: ["messageSent"] }, { kind: "component", type: i4.ChatMessageListComponent, selector: "ngx-chat-message-list", inputs: ["recipient", "showAvatars"] }, { kind: "component", type: i5.FileDropComponent, selector: "ngx-chat-filedrop", inputs: ["dropMessage", "enabled"], outputs: ["fileUpload"] }, { kind: "component", type: i6.ChatWindowFrameComponent, selector: "ngx-chat-window-frame", outputs: ["closeClick", "headerClick"] }, { kind: "component", type: i7.ChatAvatarComponent, selector: "ngx-chat-avatar", inputs: ["imageUrl"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ChatWindowComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-chat-window', template: "<ngx-chat-window-frame\n (headerClick)=\"onClickHeader()\"\n (closeClick)=\"onClickClose()\">\n\n <ng-container class=\"window-header-content\">\n <div class=\"chat-contact-avatar-wrapper\"\n (click)=\"onContactClick($event)\"\n >\n <ngx-chat-avatar [imageUrl]=\"chatWindowState.recipient.avatar\"></ngx-chat-avatar>\n </div>\n\n <div class=\"header-middle\">\n\n <div class=\"chat-contact-name-wrapper\"\n [title]=\"chatWindowState.recipient.name\"\n >\n <span [ngClass]=\"{'has-click-handler': !chatWindowState.isCollapsed && !!this.contactClickHandler}\"\n (click)=\"onContactClick($event)\">\n {{chatWindowState.recipient.name}}\n </span>\n </div>\n\n <div class=\"chat-contact-status-wrapper\"\n *ngIf=\"!chatWindowState.isCollapsed && chatWindowState.recipient.recipientType === 'contact'\"\n >\n <span class=\"chat-contact-status\">\n {{chatService.translations.presence[chatWindowState.recipient.presence$ | async]}}\n </span>\n </div>\n\n </div>\n </ng-container>\n\n <ngx-chat-filedrop\n *ngIf=\"!chatWindowState.isCollapsed\"\n class=\"window-content\"\n [enabled]=\"fileUploadHandler.isUploadSupported()\"\n (fileUpload)=\"uploadFile($event)\"\n [dropMessage]=\"chatService.translations.dropMessage\">\n <div (click)=\"onFocus()\">\n <ngx-chat-message-list\n [recipient]=\"chatWindowState.recipient\"\n [showAvatars]=\"false\"></ngx-chat-message-list>\n <div class=\"chat-input-container\">\n <ngx-chat-message-input\n [recipient]=\"chatWindowState.recipient\"\n (messageSent)=\"afterSendMessage()\"\n ></ngx-chat-message-input>\n <div *ngFor=\"let action of chatService.chatActions\"\n (click)=\"onActionClick(action)\"\n class=\"chat-action\"\n [ngClass]=\"action.cssClass\"\n [innerHTML]=\"action.html\">\n </div>\n </div>\n </div>\n </ngx-chat-filedrop>\n\n</ngx-chat-window-frame>\n", styles: ["@keyframes ngx-chat-message-in{0%{transform:translate(50px);opacity:0}to{transform:none;opacity:1}}@keyframes ngx-chat-message-out{0%{transform:translate(-50px);opacity:0}to{transform:none;opacity:1}}*{box-sizing:border-box;margin:0;padding:0;font-family:Helvetica,Arial,serif}.chat-contact-avatar-wrapper{min-width:2em;width:2em;min-height:2em;height:2em}.header-middle{flex-grow:1;flex-shrink:1;padding:0 .5em;white-space:nowrap;overflow:hidden;font-size:.8em;line-height:1.2;height:100%;display:flex;flex-direction:column;justify-content:space-around}.chat-contact-name-wrapper,.chat-contact-status-wrapper{text-overflow:ellipsis;overflow:hidden;display:block}.has-click-handler:hover{text-decoration:underline}.chat-contact-status{color:#999}.window-content{text-align:left;padding:0;min-height:5em;display:flex;flex-direction:column;overflow-x:hidden;overflow-y:auto}.chat-input-container{display:flex;padding:.5em;border-top:1px solid #e1e1e1;background:#fff;cursor:text}.chat-action{cursor:pointer;align-self:center;text-align:center}.chat-window-send{background-color:#fff;border-color:#fff;color:#000;width:1.5em}.chat-window-send:active{border:none}ngx-chat-message-input{flex-grow:1}\n"] }] }], ctorParameters: function () { return [{ type: undefined, decorators: [{ type: Inject, args: [CHAT_SERVICE_TOKEN] }] }, { type: i1.ChatListStateService }, { type: undefined, decorators: [{ type: Inject, args: [FILE_UPLOAD_HANDLER_TOKEN] }] }, { type: undefined, decorators: [{ type: Inject, args: [CONTACT_CLICK_HANDLER_TOKEN] }, { type: Optional }] }]; }, propDecorators: { chatWindowState: [{ type: Input }], messageInput: [{ type: ViewChild, args: [ChatMessageInputComponent] }], contactMessageList: [{ type: ViewChild, args: [ChatMessageListComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC13aW5kb3cuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL2NoYXQtd2luZG93L2NoYXQtd2luZG93LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9jaGF0LXdpbmRvdy9jaGF0LXdpbmRvdy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQXFCLFFBQVEsRUFBRSxTQUFTLEVBQUMsTUFBTSxlQUFlLENBQUM7QUFDL0YsT0FBTyxFQUFhLE9BQU8sRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUN6QyxPQUFPLEVBQUMsTUFBTSxFQUFFLFNBQVMsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ2pELE9BQU8sRUFBQyxTQUFTLEVBQVUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0RCxPQUFPLEVBQTBCLDJCQUEyQixFQUFDLE1BQU0sd0NBQXdDLENBQUM7QUFFNUcsT0FBTyxFQUFDLGtCQUFrQixFQUFjLE1BQU0sNkJBQTZCLENBQUM7QUFDNUUsT0FBTyxFQUFDLHlCQUF5QixFQUFDLE1BQU0sb0RBQW9ELENBQUM7QUFDN0YsT0FBTyxFQUFDLHdCQUF3QixFQUFDLE1BQU0sa0RBQWtELENBQUM7QUFDMUYsT0FBTyxFQUFDLHlCQUF5QixFQUFvQixNQUFNLGlDQUFpQyxDQUFDOzs7Ozs7Ozs7QUFTN0YsTUFBTSxPQUFPLG1CQUFtQjtJQWE1QixZQUN5QyxXQUF3QixFQUM1QyxlQUFxQyxFQUNWLGlCQUFvQyxFQUN0QixtQkFBNEM7UUFIakUsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDNUMsb0JBQWUsR0FBZixlQUFlLENBQXNCO1FBQ1Ysc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQUN0Qix3QkFBbUIsR0FBbkIsbUJBQW1CLENBQXlC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b3ksIE9uSW5pdCwgT3B0aW9uYWwsIFZpZXdDaGlsZH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge09ic2VydmFibGUsIFN1YmplY3R9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtmaWx0ZXIsIHRha2VVbnRpbH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtEaXJlY3Rpb24sIE1lc3NhZ2V9IGZyb20gJy4uLy4uL2NvcmUvbWVzc2FnZSc7XG5pbXBvcnQge0NoYXRDb250YWN0Q2xpY2tIYW5kbGVyLCBDT05UQUNUX0NMSUNLX0hBTkRMRVJfVE9LRU59IGZyb20gJy4uLy4uL2hvb2tzL2NoYXQtY29udGFjdC1jbGljay1oYW5kbGVyJztcbmltcG9ydCB7Q2hhdExpc3RTdGF0ZVNlcnZpY2UsIENoYXRXaW5kb3dTdGF0ZX0gZnJvbSAnLi4vLi4vc2VydmljZXMvY2hhdC1saXN0LXN0YXRlLnNlcnZpY2UnO1xuaW1wb3J0IHtDSEFUX1NFUlZJQ0VfVE9LRU4sIENoYXRTZXJ2aWNlfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9jaGF0LXNlcnZpY2UnO1xuaW1wb3J0IHtDaGF0TWVzc2FnZUlucHV0Q29tcG9uZW50fSBmcm9tICcuLi9jaGF0LW1lc3NhZ2UtaW5wdXQvY2hhdC1tZXNzYWdlLWlucHV0LmNvbXBvbmVudCc7XG5pbXBvcnQge0NoYXRNZXNzYWdlTGlzdENvbXBvbmVudH0gZnJvbSAnLi4vY2hhdC1tZXNzYWdlLWxpc3QvY2hhdC1tZXNzYWdlLWxpc3QuY29tcG9uZW50JztcbmltcG9ydCB7RklMRV9VUExPQURfSEFORExFUl9UT0tFTiwgRmlsZVVwbG9hZEhhbmRsZXJ9IGZyb20gJy4uLy4uL2hvb2tzL2ZpbGUtdXBsb2FkLWhhbmRsZXInO1xuaW1wb3J0IHtSb29tTWVzc2FnZX0gZnJvbSAnLi4vLi4vc2VydmljZXMvYWRhcHRlcnMveG1wcC9wbHVnaW5zL211bHRpLXVzZXItY2hhdC9yb29tLW1lc3NhZ2UnO1xuaW1wb3J0IHtDaGF0QWN0aW9ufSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9hZGFwdGVycy94bXBwL3htcHAtY2hhdC1hZGFwdGVyLnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogJ25neC1jaGF0LXdpbmRvdycsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2NoYXQtd2luZG93LmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsnLi9jaGF0LXdpbmRvdy5jb21wb25lbnQubGVzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBDaGF0V2luZG93Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgY2hhdFdpbmRvd1N0YXRlOiBDaGF0V2luZG93U3RhdGU7XG5cbiAgICBAVmlld0NoaWxkKENoYXRNZXNzYWdlSW5wdXRDb21wb25lbnQpXG4gICAgcHJpdmF0ZSByZWFkb25seSBtZXNzYWdlSW5wdXQ6IENoYXRNZXNzYWdlSW5wdXRDb21wb25lbnQ7XG5cbiAgICBAVmlld0NoaWxkKENoYXRNZXNzYWdlTGlzdENvbXBvbmVudClcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbnRhY3RNZXNzYWdlTGlzdDogQ2hhdE1lc3NhZ2VMaXN0Q29tcG9uZW50O1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBuZ0Rlc3Ryb3kgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIEBJbmplY3QoQ0hBVF9TRVJWSUNFX1RPS0VOKSByZWFkb25seSBjaGF0U2VydmljZTogQ2hhdFNlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgY2hhdExpc3RTZXJ2aWNlOiBDaGF0TGlzdFN0YXRlU2VydmljZSxcbiAgICAgICAgQEluamVjdChGSUxFX1VQTE9BRF9IQU5ETEVSX1RPS0VOKSByZWFkb25seSBmaWxlVXBsb2FkSGFuZGxlcjogRmlsZVVwbG9hZEhhbmRsZXIsXG4gICAgICAgIEBJbmplY3QoQ09OVEFDVF9DTElDS19IQU5ETEVSX1RPS0VOKSBAT3B0aW9uYWwoKSByZWFkb25seSBjb250YWN0Q2xpY2tIYW5kbGVyOiBDaGF0Q29udGFjdENsaWNrSGFuZGxlcixcbiAgICApIHtcbiAgICB9XG5cbiAgICBuZ09uSW5pdCgpIHtcbiAgICAgICAgY29uc3QgbWVzc2FnZXMkOiBPYnNlcnZhYmxlPFJvb21NZXNzYWdlIHwgTWVzc2FnZT4gPSB0aGlzLmNoYXRXaW5kb3dTdGF0ZS5yZWNpcGllbnQubWVzc2FnZXMkO1xuICAgICAgICBtZXNzYWdlcyRcbiAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgIGZpbHRlcihtZXNzYWdlID0+IG1lc3NhZ2UuZGlyZWN0aW9uID09PSBEaXJlY3Rpb24uaW4pLFxuICAgICAgICAgICAgICAgIHRha2VVbnRpbCh0aGlzLm5nRGVzdHJveSksXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYXRXaW5kb3dTdGF0ZS5pc0NvbGxhcHNlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgbmdPbkRlc3Ryb3koKSB7XG4gICAgICAgIHRoaXMubmdEZXN0cm95Lm5leHQoKTtcbiAgICAgICAgdGhpcy5uZ0Rlc3Ryb3kuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgb25DbGlja0hlYWRlcigpIHtcbiAgICAgICAgdGhpcy5jaGF0V2luZG93U3RhdGUuaXNDb2xsYXBzZWQgPSAhdGhpcy5jaGF0V2luZG93U3RhdGUuaXNDb2xsYXBzZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIG9uQ2xpY2tDbG9zZSgpIHtcbiAgICAgICAgdGhpcy5jaGF0TGlzdFNlcnZpY2UuY2xvc2VDaGF0KHRoaXMuY2hhdFdpbmRvd1N0YXRlLnJlY2lwaWVudCk7XG4gICAgfVxuXG4gICAgc2VuZE1lc3NhZ2UoKSB7XG4gICAgICAgIHRoaXMubWVzc2FnZUlucHV0Lm9uU2VuZE1lc3NhZ2UoKTtcbiAgICB9XG5cbiAgICBhZnRlclNlbmRNZXNzYWdlKCkge1xuICAgICAgICB0aGlzLmNvbnRhY3RNZXNzYWdlTGlzdC5zY2hlZHVsZVNjcm9sbFRvTGFzdE1lc3NhZ2UoKTtcbiAgICB9XG5cbiAgICBhc3luYyB1cGxvYWRGaWxlKGZpbGU6IEZpbGUpIHtcbiAgICAgICAgY29uc3QgdXJsID0gYXdhaXQgdGhpcy5maWxlVXBsb2FkSGFuZGxlci51cGxvYWQoZmlsZSk7XG4gICAgICAgIHRoaXMuY2hhdFNlcnZpY2Uuc2VuZE1lc3NhZ2UodGhpcy5jaGF0V2luZG93U3RhdGUucmVjaXBpZW50LCB1cmwpO1xuICAgIH1cblxuICAgIG9uRm9jdXMoKSB7XG4gICAgICAgIHRoaXMubWVzc2FnZUlucHV0LmZvY3VzKCk7XG4gICAgfVxuXG4gICAgb25BY3Rpb25DbGljayhjaGF0QWN0aW9uOiBDaGF0QWN0aW9uPHRoaXM+KSB7XG4gICAgICAgIGNoYXRBY3Rpb24ub25DbGljayh7XG4gICAgICAgICAgICBjb250YWN0OiB0aGlzLmNoYXRXaW5kb3dTdGF0ZS5yZWNpcGllbnQuamlkQmFyZS50b1N0cmluZygpLFxuICAgICAgICAgICAgY2hhdFdpbmRvdzogdGhpcyxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgb25Db250YWN0Q2xpY2soJGV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgICAgIGlmICh0aGlzLmNvbnRhY3RDbGlja0hhbmRsZXIgJiYgIXRoaXMuY2hhdFdpbmRvd1N0YXRlLmlzQ29sbGFwc2VkKSB7XG4gICAgICAgICAgICAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICB0aGlzLmNvbnRhY3RDbGlja0hhbmRsZXIub25DbGljayh0aGlzLmNoYXRXaW5kb3dTdGF0ZS5yZWNpcGllbnQpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiPG5neC1jaGF0LXdpbmRvdy1mcmFtZVxuICAgICAgICAoaGVhZGVyQ2xpY2spPVwib25DbGlja0hlYWRlcigpXCJcbiAgICAgICAgKGNsb3NlQ2xpY2spPVwib25DbGlja0Nsb3NlKClcIj5cblxuICAgIDxuZy1jb250YWluZXIgY2xhc3M9XCJ3aW5kb3ctaGVhZGVyLWNvbnRlbnRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImNoYXQtY29udGFjdC1hdmF0YXItd3JhcHBlclwiXG4gICAgICAgICAgICAgKGNsaWNrKT1cIm9uQ29udGFjdENsaWNrKCRldmVudClcIlxuICAgICAgICA+XG4gICAgICAgICAgICA8bmd4LWNoYXQtYXZhdGFyIFtpbWFnZVVybF09XCJjaGF0V2luZG93U3RhdGUucmVjaXBpZW50LmF2YXRhclwiPjwvbmd4LWNoYXQtYXZhdGFyPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiaGVhZGVyLW1pZGRsZVwiPlxuXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY2hhdC1jb250YWN0LW5hbWUtd3JhcHBlclwiXG4gICAgICAgICAgICAgICAgIFt0aXRsZV09XCJjaGF0V2luZG93U3RhdGUucmVjaXBpZW50Lm5hbWVcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxzcGFuIFtuZ0NsYXNzXT1cInsnaGFzLWNsaWNrLWhhbmRsZXInOiAhY2hhdFdpbmRvd1N0YXRlLmlzQ29sbGFwc2VkICYmICEhdGhpcy5jb250YWN0Q2xpY2tIYW5kbGVyfVwiXG4gICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uQ29udGFjdENsaWNrKCRldmVudClcIj5cbiAgICAgICAgICAgICAgICAgICAge3tjaGF0V2luZG93U3RhdGUucmVjaXBpZW50Lm5hbWV9fVxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY2hhdC1jb250YWN0LXN0YXR1cy13cmFwcGVyXCJcbiAgICAgICAgICAgICAgICAgKm5nSWY9XCIhY2hhdFdpbmRvd1N0YXRlLmlzQ29sbGFwc2VkICYmIGNoYXRXaW5kb3dTdGF0ZS5yZWNpcGllbnQucmVjaXBpZW50VHlwZSA9PT0gJ2NvbnRhY3QnXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImNoYXQtY29udGFjdC1zdGF0dXNcIj5cbiAgICAgICAgICAgICAgICAgICAge3tjaGF0U2VydmljZS50cmFuc2xhdGlvbnMucHJlc2VuY2VbY2hhdFdpbmRvd1N0YXRlLnJlY2lwaWVudC5wcmVzZW5jZSQgfCBhc3luY119fVxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDwvZGl2PlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPG5neC1jaGF0LWZpbGVkcm9wXG4gICAgICAgICAgICAqbmdJZj1cIiFjaGF0V2luZG93U3RhdGUuaXNDb2xsYXBzZWRcIlxuICAgICAgICAgICAgY2xhc3M9XCJ3aW5kb3ctY29udGVudFwiXG4gICAgICAgICAgICBbZW5hYmxlZF09XCJmaWxlVXBsb2FkSGFuZGxlci5pc1VwbG9hZFN1cHBvcnRlZCgpXCJcbiAgICAgICAgICAgIChmaWxlVXBsb2FkKT1cInVwbG9hZEZpbGUoJGV2ZW50KVwiXG4gICAgICAgICAgICBbZHJvcE1lc3NhZ2VdPVwiY2hhdFNlcnZpY2UudHJhbnNsYXRpb25zLmRyb3BNZXNzYWdlXCI+XG4gICAgICAgIDxkaXYgKGNsaWNrKT1cIm9uRm9jdXMoKVwiPlxuICAgICAgICAgICAgPG5neC1jaGF0LW1lc3NhZ2UtbGlzdFxuICAgICAgICAgICAgICAgICAgICBbcmVjaXBpZW50XT1cImNoYXRXaW5kb3dTdGF0ZS5yZWNpcGllbnRcIlxuICAgICAgICAgICAgICAgICAgICBbc2hvd0F2YXRhcnNdPVwiZmFsc2VcIj48L25neC1jaGF0LW1lc3NhZ2UtbGlzdD5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjaGF0LWlucHV0LWNvbnRhaW5lclwiPlxuICAgICAgICAgICAgICAgIDxuZ3gtY2hhdC1tZXNzYWdlLWlucHV0XG4gICAgICAgICAgICAgICAgICAgICAgICBbcmVjaXBpZW50XT1cImNoYXRXaW5kb3dTdGF0ZS5yZWNpcGllbnRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKG1lc3NhZ2VTZW50KT1cImFmdGVyU2VuZE1lc3NhZ2UoKVwiXG4gICAgICAgICAgICAgICAgPjwvbmd4LWNoYXQtbWVzc2FnZS1pbnB1dD5cbiAgICAgICAgICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBhY3Rpb24gb2YgY2hhdFNlcnZpY2UuY2hhdEFjdGlvbnNcIlxuICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uQWN0aW9uQ2xpY2soYWN0aW9uKVwiXG4gICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImNoYXQtYWN0aW9uXCJcbiAgICAgICAgICAgICAgICAgICAgIFtuZ0NsYXNzXT1cImFjdGlvbi5jc3NDbGFzc1wiXG4gICAgICAgICAgICAgICAgICAgICBbaW5uZXJIVE1MXT1cImFjdGlvbi5odG1sXCI+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9uZ3gtY2hhdC1maWxlZHJvcD5cblxuPC9uZ3gtY2hhdC13aW5kb3ctZnJhbWU+XG4iXX0=