zoriakinc-messaging
Version:
Angular Messaging Module
380 lines • 40.6 kB
JavaScript
/**
* @fileoverview added by tsickle
* Generated from: lib/chat-box/chat-box.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, Input, ViewChild, ViewChildren, ElementRef, QueryList } from '@angular/core';
import { MessagingService } from './messaging.service';
import { forkJoin } from 'rxjs';
import { map } from 'rxjs/operators';
export class ChatBoxComponent {
/**
* @param {?} messagingService
*/
constructor(messagingService) {
this.messagingService = messagingService;
this.messageList = [];
this.groupedMessageList = [];
this.GROUP_MIN_RANGE_IN_MINUTES = 20;
this.isFullScreenMode = false;
this.showSenderName = true;
this.replyContent = '';
if (this.messagingService.configObject.theme_color) {
document.documentElement.style
.setProperty('--theme-color', this.messagingService.configObject.theme_color);
}
this.isFullScreenMode = this.messagingService.configObject.full_screen_mode;
if (this.isFullScreenMode) {
document.documentElement.style
.setProperty('--window-width', '100%');
}
if ('show_sender_name' in this.messagingService.configObject) {
this.showSenderName = this.messagingService.configObject.show_sender_name;
}
// https://stackoverflow.com/a/48216423
this.isLoading = true;
}
/**
* @return {?}
*/
ngOnInit() {
/** @type {?} */
const readAllRequest = this.messagingService.readAll(this.donor_id);
readAllRequest.subscribe();
/** @type {?} */
const loadMessagesRequest = this.loadMessages(0);
loadMessagesRequest.subscribe((/**
* @param {?} list
* @return {?}
*/
(list) => {
this.messageList = list;
this.addNewMessagesPage(list);
}));
forkJoin(readAllRequest, loadMessagesRequest).subscribe((/**
* @return {?}
*/
() => this.isLoading = false));
/** @type {?} */
const onMessageCallback = (/**
* @param {?} message
* @return {?}
*/
(message) => {
if (this.messageList.some((/**
* @param {?} el
* @return {?}
*/
el => el.id === message.id))) {
return;
}
if (!this.recipient_user_id || (parseInt(message.sender_user_id) === parseInt(this.recipient_user_id))
|| (parseInt(message.recipient_user_id) === parseInt(this.recipient_user_id))) {
this.addNewMessage(Object.assign({ id: message.id, content: message.content, created_at: message.created_at, is_self_message: message.sender_user_id === this.user_id }, !message.is_donor_message && { sender_display_name: this.user_display_name }));
this.messageList.push(message);
// TODO: read this message not all!
this.messagingService.readAll(this.donor_id)
.subscribe();
}
});
this.messagingService.startLiveChat(onMessageCallback);
}
/**
* @return {?}
*/
loadMore() {
this.isLoading = true;
/** @type {?} */
const loadingSubscription = this.loadMessages(this.messageList.length)
.subscribe((/**
* @param {?} list
* @return {?}
*/
(list) => {
this.messageList = list.concat(this.messageList);
this.addNewMessagesPage(list);
this.isLoading = false;
loadingSubscription.unsubscribe();
}));
}
/**
* @param {?} offset
* @return {?}
*/
loadMessages(offset) {
/** @type {?} */
const self = this;
return this.messagingService.list(offset, this.donor_id)
.pipe(map((/**
* @param {?} list
* @return {?}
*/
(list) => {
list.reverse();
return list.map((/**
* @param {?} message
* @return {?}
*/
message => {
return {
id: message.id,
content: message.content,
created_at: message.created_at,
is_self_message: message.sender === self.user_id,
sender_display_name: message.sender_display_name
};
}));
})));
}
/**
* @return {?}
*/
ngAfterViewInit() {
this.chatContainerElement.nativeElement.style.height = this.height || 'calc(100vh - 500px)';
if (this.msgDivs && this.msgDivs.last) {
this.msgDivs.last.nativeElement.focus();
}
this.msgDivs.changes.subscribe((/**
* @return {?}
*/
() => {
if (this.msgDivs && this.msgDivs.last) {
this.msgDivs.last.nativeElement.focus();
}
}));
}
/**
* @param {?} msg
* @return {?}
*/
addNewMessage(msg) {
if (this.latestMsgDatetime && (new Date(msg.created_at.toString()).getTime()
- this.latestMsgDatetime.getTime()) / 60000 < this.GROUP_MIN_RANGE_IN_MINUTES) {
this.groupedMessageList[this.groupedMessageList.length - 1].push(msg);
}
else {
this.groupedMessageList.push([msg]);
}
this.latestMsgDatetime = new Date(msg.created_at.toString());
}
/**
* @param {?} msgList
* @return {?}
*/
addNewMessagesPage(msgList) {
if (this.msgDivs && this.msgDivs.first) {
/** @type {?} */
const firstDiv = this.msgDivs.first;
/** @type {?} */
const onNewPageAdded = (/**
* @return {?}
*/
() => {
firstDiv.nativeElement.scrollIntoView(true);
this.msgsContainer.nativeElement.scrollBy(0, -90);
});
this.msgsContainer.nativeElement.addEventListener('DOMNodeInserted', onNewPageAdded, false);
setTimeout((/**
* @return {?}
*/
() => this.msgsContainer.nativeElement.removeEventListener('DOMNodeInserted', onNewPageAdded, false)));
}
/** @type {?} */
const groupingObj = this.groupByTime(msgList);
if (groupingObj) {
this.groupedMessageList = groupingObj.groupedList.concat(this.groupedMessageList);
this.latestMsgDatetime = groupingObj.latestMsgDatetime;
}
}
/**
* @param {?} msgList
* @return {?}
*/
groupByTime(msgList) {
if (!msgList.length) {
return;
}
/** @type {?} */
let groupedList = [];
/** @type {?} */
let adjacentList = [];
/** @type {?} */
let latestMsgDatetime = new Date(msgList[0].created_at.toString());
msgList.forEach((/**
* @param {?} message
* @return {?}
*/
(message) => {
if ((new Date(message.created_at.toString()).getTime() - latestMsgDatetime.getTime()) / 60000 < this.GROUP_MIN_RANGE_IN_MINUTES) {
adjacentList.push(message);
latestMsgDatetime = new Date(message.created_at.toString());
}
else {
groupedList.push(adjacentList);
adjacentList = [message];
latestMsgDatetime = new Date(message.created_at.toString());
}
}));
groupedList.push(adjacentList);
return {
groupedList,
latestMsgDatetime
};
}
/**
* @return {?}
*/
reply() {
this.messagingService.send_message(this.replyContent, this.donor_id);
this.replyContent = '';
this.msgInput.nativeElement.addEventListener('focusout', this.focusOnInputAgain.bind(this));
}
/**
* @param {?} event
* @return {?}
*/
focusOnInputAgain(event) {
setTimeout((/**
* @return {?}
*/
() => {
this.msgInput.nativeElement.focus();
this.msgInput.nativeElement.removeEventListener('focusout', this.focusOnInputAgain.bind(this));
}));
}
/**
* @param {?} event
* @return {?}
*/
onScroll(event) {
if (event.target.scrollTop === 0) {
this.loadMore();
}
}
/**
* @param {?} date
* @return {?}
*/
isToday(date) {
date = new Date(date.toString());
/** @type {?} */
const today = new Date();
return date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
}
/**
* @param {?} date
* @return {?}
*/
isYesterday(date) {
date = new Date(date.toString());
/** @type {?} */
let toBeYesterday = new Date();
toBeYesterday.setDate(toBeYesterday.getDate() - 1);
/** @type {?} */
const yesterday = toBeYesterday;
return date.getDate() === yesterday.getDate() &&
date.getMonth() === yesterday.getMonth() &&
date.getFullYear() === yesterday.getFullYear();
}
/**
* @param {?} date
* @return {?}
*/
isWeekDay(date) {
if (this.isToday(date) || this.isYesterday(date)) {
return false;
}
/** @type {?} */
let weekAgo = new Date();
weekAgo.setDate(weekAgo.getDate() - 7);
return new Date(date.toString()) > weekAgo;
}
/**
* @param {?} date
* @return {?}
*/
getDayName(date) {
return new Date(date.toString()).toLocaleString('en-us', { weekday: 'short' });
}
/**
* @return {?}
*/
ngOnDestroy() {
this.messagingService.removeOnMessageListener();
}
}
ChatBoxComponent.decorators = [
{ type: Component, args: [{
selector: 'lib-chat-box',
template: "<div class=\"chatbox\" #chatContainer>\n\n <div *ngIf=\"recipient_display_name && !isFullScreenMode\" class=\"chat-header\">\n <span class=\"avatar\">\n <mat-icon *ngIf=\"!recipient_avatar_src\" class=\"avatar__icon\">person</mat-icon>\n <img *ngIf=\"recipient_avatar_src\" [src]=\"recipient_avatar_src\" class=\"avatar__img\">\n </span>\n <span class=\"name\">\n {{recipient_display_name}}\n </span>\n </div>\n\n <div class=\"messages\" #msgsContainer (scroll)=\"onScroll($event)\">\n <div *ngFor=\"let group of groupedMessageList\">\n <div class=\"messages-group\">\n <div class=\"messages-group-label\">\n <div class=\"hr-sect\" *ngIf=\"isToday(group[0]?.created_at)\">\n <span style=\"padding: 0 10px;\">{{group[0]?.created_at | date: 'shortTime'}}</span>\n </div>\n <div class=\"hr-sect\" *ngIf=\"isYesterday(group[0]?.created_at)\">\n <span style=\"padding: 0 10px;\">Yesterday {{group[0]?.created_at | date: 'shortTime'}}</span>\n </div>\n <div class=\"hr-sect\" *ngIf=\"isWeekDay(group[0]?.created_at)\">\n <span style=\"padding: 0 10px;\">{{group[0]?.created_at | date: 'EEEE'}} {{group[0]?.created_at | date: 'shortTime'}}</span>\n </div>\n <div class=\"hr-sect\" *ngIf=\"!isToday(group[0]?.created_at) &&\n !isYesterday(group[0]?.created_at) &&\n !isWeekDay(group[0]?.created_at)\">\n <span style=\"padding: 0 10px;\"> {{group[0]?.created_at | date: 'MMM d, y, h:mm a'}}</span>\n </div>\n </div>\n <div tabindex=\"1\" class=\"message-div\" #msgDiv *ngFor=\"let message of group\">\n <div class=\"text-icon\" [class.self-messages]=\"message.is_self_message\">\n <span class=\"avatar\" *ngIf=\"!message.is_self_message\">\n <mat-icon class=\"avatar__icon\">person</mat-icon>\n <img *ngIf=\"recipient_avatar_src\" [src]=\"recipient_avatar_src\" class=\"avatar__img\">\n </span>\n <div>\n <div class=\"sender-name\" *ngIf=\"message.is_self_message && this.showSenderName\">\n {{message.sender_display_name}}\n </div>\n <p class=\"message-item\">\n {{message.content}}\n </p>\n </div>\n <span class=\"avatar\" style=\"vertical-align: middle;\" *ngIf=\"message.is_self_message\">\n <mat-icon>person</mat-icon>\n <img *ngIf=\"sender_avatar_src\" [src]=\"sender_avatar_src\" class=\"avatar__img\">\n </span>\n\n <!--<div class=\"timeform\">-->\n <!--<mat-icon>date</mat-icon> <span class=\"timestamp\">at {{message.created_at | date : 'dd/MM/yyyy' }}</span>-->\n <!--</div>-->\n </div>\n </div>\n </div>\n </div>\n\n </div>\n\n <div class=\"input-container\">\n <mat-form-field>\n <textarea #msgInput matInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"2\"\n cdkAutosizeMaxRows=\"5\"\n (keyup.enter)=\"reply()\" placeholder=\"Type a message..\" [(ngModel)]=\"replyContent\">\n </textarea>\n </mat-form-field>\n\n <div class=\"button-wrap\">\n <button mat-raised-button\n color=\"primary\"\n class=\"replyBtn\"\n (click)=\"reply()\">\n Send\n </button>\n </div>\n </div>\n\n</div>\n",
styles: [":root{--theme-color:#3498db;--window-width:90%}.chatbox{width:var(--window-width,90%);display:flex;flex-direction:column;margin:0 auto;border-radius:5px 5px 0 0;background-color:#fff;box-shadow:0 2px 4px 0 rgba(0,0,0,.2)}.chatbox .chat-header{height:120px;padding:20px;text-align:center;border-radius:5px 5px 0 0;background:#3498db;color:#fff}.chatbox .chat-header .avatar{margin:0 0 10px;width:55px;min-width:55px;height:55px;min-height:55px;text-align:center!important;background-color:#fff!important;vertical-align:middle;color:#000!important}.chatbox .chat-header .name{font-size:20px;font-style:oblique;font-weight:700;display:block}.chatbox .messages{flex:1;overflow:auto;padding:50px 16px 6px;background-color:#fafafa;box-shadow:inset 0 2px 2px rgba(0,0,0,.1)}.chatbox .messages .messages-group{margin-bottom:10px}.chatbox .messages .messages-group .messages-group-label{text-align:center;margin-bottom:10px}.chatbox .messages .messages-group .messages-group-label .hr-sect{display:flex;flex-basis:100%;align-items:center;margin:8px 0}.chatbox .messages .messages-group .messages-group-label .hr-sect::after,.chatbox .messages .messages-group .messages-group-label .hr-sect::before{content:\"\";flex-grow:1;background:rgba(0,0,0,.1);height:1.5px;font-size:0;line-height:0;margin:0 8px}.chatbox .messages .messages-group .message-div{padding:1px;outline:0}.chatbox .messages .message-item{background-color:#ccc;padding:8px;border-radius:14px;margin-top:0;margin-bottom:0}.chatbox .messages .text-icon{display:flex;flex-direction:row;justify-content:flex-start}.chatbox .messages .self-messages{justify-content:flex-end}.chatbox .messages .self-messages .sender-name{font-size:14px;font-weight:700;margin:2px 5px;text-align:right}.chatbox .messages .self-messages p{color:#fff;background-color:var(--theme-color,#3498db);white-space:pre-line}.chatbox .messages .avatar{margin:0 5px;width:25px;min-width:25px;height:25px;min-height:25px;text-align:center!important;background-color:#fff!important;vertical-align:middle;color:#000!important}.chatbox .input-container{display:flex;flex-direction:row;align-items:center;width:100%;margin:0 auto;background-color:#fff;box-shadow:0 2px 4px 0 rgba(0,0,0,.2);border-radius:0 0 5px 5px;padding:8px;vertical-align:middle;border-top:1px solid #ebebeb}.chatbox .input-container mat-form-field{flex:1}.chatbox .input-container mat-form-field textarea{width:100%}.chatbox .input-container .button-wrap{margin:4px}.chatbox .input-container .button-wrap button{width:70px;margin-left:20px}"]
}] }
];
/** @nocollapse */
ChatBoxComponent.ctorParameters = () => [
{ type: MessagingService }
];
ChatBoxComponent.propDecorators = {
msgDivs: [{ type: ViewChildren, args: ['msgDiv',] }],
msgsContainer: [{ type: ViewChild, args: ['msgsContainer', { static: false },] }],
chatContainerElement: [{ type: ViewChild, args: ['chatContainer', { static: false },] }],
sender_avatar_src: [{ type: Input }],
recipient_avatar_src: [{ type: Input }],
recipient_display_name: [{ type: Input }],
donor_id: [{ type: Input }],
user_display_name: [{ type: Input }],
user_id: [{ type: Input }],
recipient_user_id: [{ type: Input }],
height: [{ type: Input }],
msgInput: [{ type: ViewChild, args: ['msgInput', { static: false },] }]
};
if (false) {
/** @type {?} */
ChatBoxComponent.prototype.msgDivs;
/** @type {?} */
ChatBoxComponent.prototype.msgsContainer;
/** @type {?} */
ChatBoxComponent.prototype.chatContainerElement;
/** @type {?} */
ChatBoxComponent.prototype.sender_avatar_src;
/** @type {?} */
ChatBoxComponent.prototype.recipient_avatar_src;
/** @type {?} */
ChatBoxComponent.prototype.recipient_display_name;
/** @type {?} */
ChatBoxComponent.prototype.donor_id;
/** @type {?} */
ChatBoxComponent.prototype.user_display_name;
/** @type {?} */
ChatBoxComponent.prototype.user_id;
/** @type {?} */
ChatBoxComponent.prototype.recipient_user_id;
/** @type {?} */
ChatBoxComponent.prototype.height;
/** @type {?} */
ChatBoxComponent.prototype.messageList;
/** @type {?} */
ChatBoxComponent.prototype.groupedMessageList;
/** @type {?} */
ChatBoxComponent.prototype.latestMsgDatetime;
/** @type {?} */
ChatBoxComponent.prototype.GROUP_MIN_RANGE_IN_MINUTES;
/** @type {?} */
ChatBoxComponent.prototype.isFullScreenMode;
/** @type {?} */
ChatBoxComponent.prototype.showSenderName;
/** @type {?} */
ChatBoxComponent.prototype.isLoading;
/** @type {?} */
ChatBoxComponent.prototype.replyContent;
/** @type {?} */
ChatBoxComponent.prototype.msgInput;
/**
* @type {?}
* @private
*/
ChatBoxComponent.prototype.messagingService;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhdC1ib3guY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vem9yaWFraW5jLW1lc3NhZ2luZy8iLCJzb3VyY2VzIjpbImxpYi9jaGF0LWJveC9jaGF0LWJveC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULEtBQUssRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLFVBQVUsRUFDVixTQUFTLEVBRVYsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFDLGdCQUFnQixFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDckQsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUM5QixPQUFPLEVBQUMsR0FBRyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFRbkMsTUFBTSxPQUFPLGdCQUFnQjs7OztJQThCM0IsWUFBb0IsZ0JBQWtDO1FBQWxDLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFmdEQsZ0JBQVcsR0FBcUIsRUFBRSxDQUFDO1FBRW5DLHVCQUFrQixHQUF1QixFQUFFLENBQUM7UUFHNUMsK0JBQTBCLEdBQUcsRUFBRSxDQUFDO1FBQ2hDLHFCQUFnQixHQUFHLEtBQUssQ0FBQztRQUN6QixtQkFBYyxHQUFHLElBQUksQ0FBQztRQUl0QixpQkFBWSxHQUFHLEVBQUUsQ0FBQztRQUtoQixJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFO1lBQ2xELFFBQVEsQ0FBQyxlQUFlLENBQUMsS0FBSztpQkFDM0IsV0FBVyxDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1NBQ2pGO1FBQ0QsSUFBSSxDQUFDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsZ0JBQWdCLENBQUM7UUFDNUUsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7WUFDdkIs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SUFDNUMsNkNBQXdCOztJQUV4QixzREFBZ0M7O0lBQ2hDLDRDQUF5Qjs7SUFDekIsMENBQXNCOztJQUV0QixxQ0FBVTs7SUFFVix3Q0FBa0I7O0lBRWxCLG9DQUE2RDs7Ozs7SUFFakQsNENBQTBDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBJbnB1dCxcbiAgVmlld0NoaWxkLFxuICBWaWV3Q2hpbGRyZW4sXG4gIEVsZW1lbnRSZWYsXG4gIFF1ZXJ5TGlzdCxcbiAgT25Jbml0LCBPbkRlc3Ryb3lcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1ByZXZpZXdNZXNzYWdlfSBmcm9tICcuLi9tb2RlbHMnO1xuaW1wb3J0IHtNZXNzYWdpbmdTZXJ2aWNlfSBmcm9tICcuL21lc3NhZ2luZy5zZXJ2aWNlJztcbmltcG9ydCB7Zm9ya0pvaW59IGZyb20gJ3J4anMnO1xuaW1wb3J0IHttYXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7U2VydmVyTWVzc2FnZX0gZnJvbSAnLi4vbW9kZWxzJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbGliLWNoYXQtYm94JyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NoYXQtYm94LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vY2hhdC1ib3guY29tcG9uZW50LnNjc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBDaGF0Qm94Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuXG4gIEBWaWV3Q2hpbGRyZW4oJ21zZ0RpdicpIG1zZ0RpdnM6IFF1ZXJ5TGlzdDxFbGVtZW50UmVmPjtcbiAgQFZpZXdDaGlsZCgnbXNnc0NvbnRhaW5lcicsIHtzdGF0aWM6IGZhbHNlfSkgbXNnc0NvbnRhaW5lcjogRWxlbWVudFJlZjtcbiAgQFZpZXdDaGlsZCgnY2hhdENvbnRhaW5lcicsIHtzdGF0aWM6IGZhbHNlfSkgY2hhdENvbnRhaW5lckVsZW1lbnQ6IEVsZW1lbnRSZWY7XG5cbiAgQElucHV0KCkgc2VuZGVyX2F2YXRhcl9zcmM6IHN0cmluZztcbiAgQElucHV0KCkgcmVjaXBpZW50X2F2YXRhcl9zcmM6IG51bWJlcjtcbiAgQElucHV0KCkgcmVjaXBpZW50X2Rpc3BsYXlfbmFtZTogc3RyaW5nO1xuICBASW5wdXQoKSBkb25vcl9pZDogc3RyaW5nO1xuICBASW5wdXQoKSB1c2VyX2Rpc3BsYXlfbmFtZTogc3RyaW5nO1xuICBASW5wdXQoKSB1c2VyX2lkOiBudW1iZXI7XG4gIEBJbnB1dCgpIHJlY2lwaWVudF91c2VyX2lkOiBzdHJpbmc7XG4gIEBJbnB1dCgpIGhlaWdodDogc3RyaW5nO1xuXG4gIG1lc3NhZ2VMaXN0OiBQcmV2aWV3TWVzc2FnZVtdID0gW107XG5cbiAgZ3JvdXBlZE1lc3NhZ2VMaXN0OiBQcmV2aWV3TWVzc2FnZVtdW10gPSBbXTtcbiAgbGF0ZXN0TXNnRGF0ZXRpbWU6IERhdGU7XG5cbiAgR1JPVVBfTUlOX1JBTkdFX0lOX01JTlVURVMgPSAyMDtcbiAgaXNGdWxsU2NyZWVuTW9kZSA9IGZhbHNlO1xuICBzaG93U2VuZGVyTmFtZSA9IHRydWU7XG5cbiAgaXNMb2FkaW5nO1xuXG4gIHJlcGx5Q29udGVudCA9ICcnO1xuXG4gIEBWaWV3Q2hpbGQoJ21zZ0lucHV0Jywge3N0YXRpYzogZmFsc2V9KSBtc2dJbnB1dDogRWxlbWVudFJlZjtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIG1lc3NhZ2luZ1NlcnZpY2U6IE1lc3NhZ2luZ1NlcnZpY2UpIHtcbiAgICBpZiAodGhpcy5tZXNzYWdpbmdTZXJ2aWNlLmNvbmZpZ09iamVjdC50aGVtZV9jb2xvcikge1xuICAgICAgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlXG4gICAgICAgIC5zZXRQcm9wZXJ0eSgnLS10aGVtZS1jb2xvcicsIHRoaXMubWVzc2FnaW5nU2VydmljZS5jb25maWdPYmplY3QudGhlbWVfY29sb3IpO1xuICAgIH1cbiAgICB0aGlzLmlzRnVsbFNjcmVlbk1vZGUgPSB0aGlzLm1lc3NhZ2luZ1NlcnZpY2UuY29uZmlnT2JqZWN0LmZ1bGxfc2NyZWVuX21vZGU7XG4gICAgaWYgKHRoaXMuaXNGdWxsU2NyZWVuTW9kZSkge1xuICAgICAgICBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGVcbiAgICAgICAgICAuc2V0UHJvcGVydHkoJy0td2luZG93LXdpZHRoJywgJzEwMCUnKTtcbiAgICB9XG5cbiAgICBpZiAoJ3Nob3dfc2VuZGVyX25hbWUnIGluIHRoaXMubWVzc2FnaW5nU2VydmljZS5jb25maWdPYmplY3QpIHtcbiAgICAgIHRoaXMuc2hvd1NlbmRlck5hbWUgPSB0aGlzLm1lc3NhZ2luZ1NlcnZpY2UuY29uZmlnT2JqZWN0LnNob3dfc2VuZGVyX25hbWU7XG4gICAgfVxuXG4gICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzQ4MjE2NDIzXG4gICAgdGhpcy5pc0xvYWRpbmcgPSB0cnVlO1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG5cbiAgICBjb25zdCByZWFkQWxsUmVxdWVzdCA9IHRoaXMubWVzc2FnaW5nU2VydmljZS5yZWFkQWxsKHRoaXMuZG9ub3JfaWQpO1xuICAgIHJlYWRBbGxSZXF1ZXN0LnN1YnNjcmliZSgpO1xuXG4gICAgY29uc3QgbG9hZE1lc3NhZ2VzUmVxdWVzdCA9IHRoaXMubG9hZE1lc3NhZ2VzKDApO1xuICAgIGxvYWRNZXNzYWdlc1JlcXVlc3Quc3Vic2NyaWJlKChsaXN0OiBQcmV2aWV3TWVzc2FnZVtdKSA9PiB7XG4gICAgICB0aGlzLm1lc3NhZ2VMaXN0ID0gbGlzdDtcbiAgICAgIHRoaXMuYWRkTmV3TWVzc2FnZXNQYWdlKGxpc3QpO1xuICAgIH0pO1xuXG4gICAgZm9ya0pvaW4ocmVhZEFsbFJlcXVlc3QsIGxvYWRNZXNzYWdlc1JlcXVlc3QpLnN1YnNjcmliZSgoKSA9PiB0aGlzLmlzTG9hZGluZyA9IGZhbHNlKTtcblxuICAgIGNvbnN0IG9uTWVzc2FnZUNhbGxiYWNrID0gKG1lc3NhZ2UpID0+IHtcbiAgICAgIGlmICh0aGlzLm1lc3NhZ2VMaXN0LnNvbWUoZWwgPT4gZWwuaWQgPT09IG1lc3NhZ2UuaWQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICghdGhpcy5yZWNpcGllbnRfdXNlcl9pZCB8fCAocGFyc2VJbnQobWVzc2FnZS5zZW5kZXJfdXNlcl9pZCkgPT09IHBhcnNlSW50KHRoaXMucmVjaXBpZW50X3VzZXJfaWQpKVxuICAgICAgICB8fCAocGFyc2VJbnQobWVzc2FnZS5yZWNpcGllbnRfdXNlcl9pZCkgPT09IHBhcnNlSW50KHRoaXMucmVjaXBpZW50X3VzZXJfaWQpKSkge1xuICAgICAgICB0aGlzLmFkZE5ld01lc3NhZ2Uoe1xuICAgICAgICAgIGlkOiBtZXNzYWdlLmlkLFxuICAgICAgICAgIGNvbnRlbnQ6IG1lc3NhZ2UuY29udGVudCxcbiAgICAgICAgICBjcmVhdGVkX2F0OiBtZXNzYWdlLmNyZWF0ZWRfYXQsXG4gICAgICAgICAgaXNfc2VsZl9tZXNzYWdlOiBtZXNzYWdlLnNlbmRlcl91c2VyX2lkID09PSB0aGlzLnVzZXJfaWQsXG4gICAgICAgICAgLi4uIW1lc3NhZ2UuaXNfZG9ub3JfbWVzc2FnZSAmJiB7c2VuZGVyX2Rpc3BsYXlfbmFtZTogdGhpcy51c2VyX2Rpc3BsYXlfbmFtZX1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMubWVzc2FnZUxpc3QucHVzaChtZXNzYWdlKTtcbiAgICAgICAgLy8gVE9ETzogcmVhZCB0aGlzIG1lc3NhZ2Ugbm90IGFsbCFcbiAgICAgICAgdGhpcy5tZXNzYWdpbmdTZXJ2aWNlLnJlYWRBbGwodGhpcy5kb25vcl9pZClcbiAgICAgICAgICAuc3Vic2NyaWJlKCk7XG4gICAgICB9XG4gICAgfTtcbiAgICB0aGlzLm1lc3NhZ2luZ1NlcnZpY2Uuc3RhcnRMaXZlQ2hhdChvbk1lc3NhZ2VDYWxsYmFjayk7XG4gIH1cblxuICBsb2FkTW9yZSgpIHtcbiAgICB0aGlzLmlzTG9hZGluZyA9IHRydWU7XG4gICAgY29uc3QgbG9hZGluZ1N1YnNjcmlwdGlvbiA9IHRoaXMubG9hZE1lc3NhZ2VzKHRoaXMubWVzc2FnZUxpc3QubGVuZ3RoKVxuICAgICAgLnN1YnNjcmliZSgobGlzdDogUHJldmlld01lc3NhZ2VbXSkgPT4ge1xuICAgICAgICB0aGlzLm1lc3NhZ2VMaXN0ID0gbGlzdC5jb25jYXQodGhpcy5tZXNzYWdlTGlzdCk7XG4gICAgICAgIHRoaXMuYWRkTmV3TWVzc2FnZXNQYWdlKGxpc3QpO1xuICAgICAgICB0aGlzLmlzTG9hZGluZyA9IGZhbHNlO1xuICAgICAgICBsb2FkaW5nU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIGxvYWRNZXNzYWdlcyhvZmZzZXQpIHtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICByZXR1cm4gdGhpcy5tZXNzYWdpbmdTZXJ2aWNlLmxpc3Qob2Zmc2V0LCB0aGlzLmRvbm9yX2lkKVxuICAgICAgLnBpcGUobWFwKChsaXN0OiBTZXJ2ZXJNZXNzYWdlW10pID0+IHtcbiAgICAgICAgbGlzdC5yZXZlcnNlKCk7XG4gICAgICAgIHJldHVybiBsaXN0Lm1hcChtZXNzYWdlID0+IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGlkOiBtZXNzYWdlLmlkLFxuICAgICAgICAgICAgICBjb250ZW50OiBtZXNzYWdlLmNvbnRlbnQsXG4gICAgICAgICAgICAgIGNyZWF0ZWRfYXQ6IG1lc3NhZ2UuY3JlYXRlZF9hdCxcbiAgICAgICAgICAgICAgaXNfc2VsZl9tZXNzYWdlOiBtZXNzYWdlLnNlbmRlciA9PT0gc2VsZi51c2VyX2lkLFxuICAgICAgICAgICAgICBzZW5kZXJfZGlzcGxheV9uYW1lOiBtZXNzYWdlLnNlbmRlcl9kaXNwbGF5X25hbWVcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgfSkpO1xuICB9XG5cblxuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgdGhpcy5jaGF0Q29udGFpbmVyRWxlbWVudC5uYXRpdmVFbGVtZW50LnN0eWxlLmhlaWdodCA9IHRoaXMuaGVpZ2h0IHx8ICdjYWxjKDEwMHZoIC0gNTAwcHgpJztcblxuICAgIGlmICh0aGlzLm1zZ0RpdnMgJiYgdGhpcy5tc2dEaXZzLmxhc3QpIHtcbiAgICAgIHRoaXMubXNnRGl2cy5sYXN0Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcbiAgICB9XG4gICAgdGhpcy5tc2dEaXZzLmNoYW5nZXMuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIGlmICh0aGlzLm1zZ0RpdnMgJiYgdGhpcy5tc2dEaXZzLmxhc3QpIHtcbiAgICAgICAgdGhpcy5tc2dEaXZzLmxhc3QubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgYWRkTmV3TWVzc2FnZShtc2cpIHtcbiAgICBpZiAodGhpcy5sYXRlc3RNc2dEYXRldGltZSAmJiAobmV3IERhdGUobXNnLmNyZWF0ZWRfYXQudG9TdHJpbmcoKSkuZ2V0VGltZSgpXG4gICAgICAtIHRoaXMubGF0ZXN0TXNnRGF0ZXRpbWUuZ2V0VGltZSgpKSAvIDYwMDAwIDwgdGhpcy5HUk9VUF9NSU5fUkFOR0VfSU5fTUlOVVRFUykge1xuICAgICAgdGhpcy5ncm91cGVkTWVzc2FnZUxpc3RbdGhpcy5ncm91cGVkTWVzc2FnZUxpc3QubGVuZ3RoIC0gMV0ucHVzaChtc2cpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmdyb3VwZWRNZXNzYWdlTGlzdC5wdXNoKFttc2ddKTtcbiAgICB9XG4gICAgdGhpcy5sYXRlc3RNc2dEYXRldGltZSA9IG5ldyBEYXRlKG1zZy5jcmVhdGVkX2F0LnRvU3RyaW5nKCkpO1xuICB9XG5cbiAgYWRkTmV3TWVzc2FnZXNQYWdlKG1zZ0xpc3Q6IFByZXZpZXdNZXNzYWdlW10pIHtcbiAgICBpZiAodGhpcy5tc2dEaXZzICYmIHRoaXMubXNnRGl2cy5maXJzdCkge1xuICAgICAgY29uc3QgZmlyc3REaXYgPSB0aGlzLm1zZ0RpdnMuZmlyc3Q7XG4gICAgICBjb25zdCBvbk5ld1BhZ2VBZGRlZCA9ICgpID0+IHtcbiAgICAgICAgZmlyc3REaXYubmF0aXZlRWxlbWVudC5zY3JvbGxJbnRvVmlldyh0cnVlKTtcbiAgICAgICAgdGhpcy5tc2dzQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsQnkoMCwgLTkwKTtcbiAgICAgIH07XG4gICAgICB0aGlzLm1zZ3NDb250YWluZXIubmF0aXZlRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Ob2RlSW5zZXJ0ZWQnLCBvbk5ld1BhZ2VBZGRlZCwgZmFsc2UpO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLm1zZ3NDb250YWluZXIubmF0aXZlRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdET01Ob2RlSW5zZXJ0ZWQnLCBvbk5ld1BhZ2VBZGRlZCwgZmFsc2UpKTtcbiAgICB9XG5cbiAgICBjb25zdCBncm91cGluZ09iaiA9IHRoaXMuZ3JvdXBCeVRpbWUobXNnTGlzdCk7XG4gICAgaWYgKGdyb3VwaW5nT2JqKSB7XG4gICAgICB0aGlzLmdyb3VwZWRNZXNzYWdlTGlzdCA9IGdyb3VwaW5nT2JqLmdyb3VwZWRMaXN0LmNvbmNhdCh0aGlzLmdyb3VwZWRNZXNzYWdlTGlzdCk7XG4gICAgICB0aGlzLmxhdGVzdE1zZ0RhdGV0aW1lID0gZ3JvdXBpbmdPYmoubGF0ZXN0TXNnRGF0ZXRpbWU7XG4gICAgfVxuXG4gIH1cblxuICBncm91cEJ5VGltZShtc2dMaXN0OiBQcmV2aWV3TWVzc2FnZVtdKSB7XG4gICAgaWYgKCFtc2dMaXN0Lmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgZ3JvdXBlZExpc3QgPSBbXTtcbiAgICBsZXQgYWRqYWNlbnRMaXN0ID0gW107XG4gICAgbGV0IGxhdGVzdE1zZ0RhdGV0aW1lID0gbmV3IERhdGUobXNnTGlzdFswXS5jcmVhdGVkX2F0LnRvU3RyaW5nKCkpO1xuICAgIG1zZ0xpc3QuZm9yRWFjaCgobWVzc2FnZSkgPT4ge1xuICAgICAgaWYgKChuZXcgRGF0ZShtZXNzYWdlLmNyZWF0ZWRfYXQudG9TdHJpbmcoKSkuZ2V0VGltZSgpIC0gbGF0ZXN0TXNnRGF0ZXRpbWUuZ2V0VGltZSgpKSAvIDYwMDAwIDwgdGhpcy5HUk9VUF9NSU5fUkFOR0VfSU5fTUlOVVRFUykge1xuICAgICAgICBhZGphY2VudExpc3QucHVzaChtZXNzYWdlKTtcbiAgICAgICAgbGF0ZXN0TXNnRGF0ZXRpbWUgPSBuZXcgRGF0ZShtZXNzYWdlLmNyZWF0ZWRfYXQudG9TdHJpbmcoKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBncm91cGVkTGlzdC5wdXNoKGFkamFjZW50TGlzdCk7XG4gICAgICAgIGFkamFjZW50TGlzdCA9IFttZXNzYWdlXTtcbiAgICAgICAgbGF0ZXN0TXNnRGF0ZXRpbWUgPSBuZXcgRGF0ZShtZXNzYWdlLmNyZWF0ZWRfYXQudG9TdHJpbmcoKSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZ3JvdXBlZExpc3QucHVzaChhZGphY2VudExpc3QpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGdyb3VwZWRMaXN0LFxuICAgICAgbGF0ZXN0TXNnRGF0ZXRpbWVcbiAgICB9O1xuICB9XG5cbiAgcmVwbHkoKSB7XG4gICAgdGhpcy5tZXNzYWdpbmdTZXJ2aWNlLnNlbmRfbWVzc2FnZSh0aGlzLnJlcGx5Q29udGVudCwgdGhpcy5kb25vcl9pZCk7XG4gICAgdGhpcy5yZXBseUNvbnRlbnQgPSAnJztcbiAgICB0aGlzLm1zZ0lucHV0Lm5hdGl2ZUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXNvdXQnLCB0aGlzLmZvY3VzT25JbnB1dEFnYWluLmJpbmQodGhpcykpO1xuICB9XG5cbiAgZm9jdXNPbklucHV0QWdhaW4oZXZlbnQpIHtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMubXNnSW5wdXQubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgICAgdGhpcy5tc2dJbnB1dC5uYXRpdmVFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2ZvY3Vzb3V0JywgdGhpcy5mb2N1c09uSW5wdXRBZ2Fpbi5iaW5kKHRoaXMpKTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uU2Nyb2xsKGV2ZW50OiBhbnkpIHtcbiAgICBpZiAoZXZlbnQudGFyZ2V0LnNjcm9sbFRvcCA9PT0gMCkge1xuICAgICAgdGhpcy5sb2FkTW9yZSgpO1xuICAgIH1cbiAgfVxuXG4gIGlzVG9kYXkoZGF0ZSkge1xuICAgIGRhdGUgPSBuZXcgRGF0ZShkYXRlLnRvU3RyaW5nKCkpO1xuICAgIGNvbnN0IHRvZGF5ID0gbmV3IERhdGUoKTtcbiAgICByZXR1cm4gZGF0ZS5nZXREYXRlKCkgPT09IHRvZGF5LmdldERhdGUoKSAmJlxuICAgICAgZGF0ZS5nZXRNb250aCgpID09PSB0b2RheS5nZXRNb250aCgpICYmXG4gICAgICBkYXRlLmdldEZ1bGxZZWFyKCkgPT09IHRvZGF5LmdldEZ1bGxZZWFyKCk7XG4gIH1cblxuICBpc1llc3RlcmRheShkYXRlKSB7XG4gICAgZGF0ZSA9IG5ldyBEYXRlKGRhdGUudG9TdHJpbmcoKSk7XG4gICAgbGV0IHRvQmVZZXN0ZXJkYXkgPSBuZXcgRGF0ZSgpO1xuICAgIHRvQmVZZXN0ZXJkYXkuc2V0RGF0ZSh0b0JlWWVzdGVyZGF5LmdldERhdGUoKSAtIDEpO1xuICAgIGNvbnN0IHllc3RlcmRheSA9IHRvQmVZZXN0ZXJkYXk7XG4gICAgcmV0dXJuIGRhdGUuZ2V0RGF0ZSgpID09PSB5ZXN0ZXJkYXkuZ2V0RGF0ZSgpICYmXG4gICAgICBkYXRlLmdldE1vbnRoKCkgPT09IHllc3RlcmRheS5nZXRNb250aCgpICYmXG4gICAgICBkYXRlLmdldEZ1bGxZZWFyKCkgPT09IHllc3RlcmRheS5nZXRGdWxsWWVhcigpO1xuICB9XG5cbiAgaXNXZWVrRGF5KGRhdGUpIHtcbiAgICBpZiAodGhpcy5pc1RvZGF5KGRhdGUpIHx8IHRoaXMuaXNZZXN0ZXJkYXkoZGF0ZSkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgbGV0IHdlZWtBZ28gPSBuZXcgRGF0ZSgpO1xuICAgIHdlZWtBZ28uc2V0RGF0ZSh3ZWVrQWdvLmdldERhdGUoKSAtIDcpO1xuICAgIHJldHVybiBuZXcgRGF0ZShkYXRlLnRvU3RyaW5nKCkpID4gd2Vla0FnbztcbiAgfVxuXG4gIGdldERheU5hbWUoZGF0ZSkge1xuICAgIHJldHVybiBuZXcgRGF0ZShkYXRlLnRvU3RyaW5nKCkpLnRvTG9jYWxlU3RyaW5nKCdlbi11cycsIHt3ZWVrZGF5OiAnc2hvcnQnIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5tZXNzYWdpbmdTZXJ2aWNlLnJlbW92ZU9uTWVzc2FnZUxpc3RlbmVyKCk7XG4gIH1cblxufVxuIl19