zoriakinc-messaging
Version:
Angular Messaging Module
392 lines • 32.1 kB
JavaScript
/**
* @fileoverview added by tsickle
* Generated from: lib/chat-box/messaging.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Inject, Injectable, Injector } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { tap, map } from 'rxjs/operators';
import { stringify } from 'querystring';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common/http";
export class MessagingService {
/**
* @param {?} http
* @param {?} injector
* @param {?} config
*/
constructor(http, injector, config) {
this.http = http;
this.injector = injector;
this.config = config;
this.totalUnReadMsgsCountSource = new BehaviorSubject(0);
this.totalUnReadMsgsCount = this.totalUnReadMsgsCountSource.asObservable();
this.unReadMsgsCountsArraySource = new BehaviorSubject([]);
this.unReadMsgsCountsArray = this.unReadMsgsCountsArraySource.asObservable();
this.unreadMsgsIdsPairs = {};
this.isWebSocketReconnectingSource = new BehaviorSubject(false);
this.isWebSocketReconnecting = this.isWebSocketReconnectingSource.asObservable();
this.defaultMsgArrivalCallback = (/**
* @param {?} message
* @return {?}
*/
(message) => {
if (stringify(message.sender_user_id) in this.unreadMsgsIdsPairs) {
if (this.unreadMsgsIdsPairs[stringify(message.sender_user_id)].indexOf(message.id) > -1) {
return;
}
this.unreadMsgsIdsPairs[stringify(message.sender_user_id)].push(message.id);
}
else {
this.unreadMsgsIdsPairs[stringify(message.sender_user_id)] = [message.id];
}
this.incrementTotalUnReadMsgsCount();
/** @type {?} */
let unReadPairsArray = this.unReadMsgsCountsArraySource.getValue();
/** @type {?} */
const matchedPairIndex = unReadPairsArray.findIndex((/**
* @param {?} el
* @return {?}
*/
el => el.sender_user_id === message.sender_user_id));
if (matchedPairIndex !== -1)
unReadPairsArray[matchedPairIndex].count += 1;
else
unReadPairsArray.push({ sender_user_id: message.sender_user_id, count: 1 });
this.unReadMsgsCountsArraySource.next(unReadPairsArray);
console.log(unReadPairsArray);
});
console.log('inside service: ', config);
this.configObject = config;
this.authService = this.injector.get(config.auth);
if (config.push) {
this.pushService = this.injector.get(config.push);
}
console.log(this.authService);
console.log(this.pushService);
}
/**
* @param {?} config
* @return {?}
*/
initialize(config) {
this.configObject = config;
}
/**
* @param {?} newCount
* @return {?}
*/
setTotalUnReadMsgsCount(newCount) {
this.totalUnReadMsgsCountSource.next(newCount);
}
/**
* @param {?} pairs
* @return {?}
*/
setUnReadMsgsCountsArray(pairs) {
this.unReadMsgsCountsArraySource.next(pairs);
}
/**
* @return {?}
*/
incrementTotalUnReadMsgsCount() {
this.totalUnReadMsgsCountSource.next(this.totalUnReadMsgsCountSource.getValue() + 1);
}
/**
* @param {?} offset
* @param {?=} donor_id
* @return {?}
*/
list(offset, donor_id = null) {
/** @type {?} */
let chatUrl;
if (donor_id)
chatUrl = `${this.configObject.messages_url}${donor_id}/?limit=${this.configObject.messages_page_size}&offset=${offset}`;
else
chatUrl = `${this.configObject.messages_url}?limit=${this.configObject.messages_page_size}&offset=${offset}`;
return this.http.get(chatUrl).pipe(map((/**
* @param {?} resp
* @return {?}
*/
(resp) => {
return resp.results;
})));
}
/**
* @param {?} content
* @param {?=} donor_id
* @return {?}
*/
send_message(content, donor_id = null) {
this.ws.send(JSON.stringify({
content: content,
donor_id: donor_id
}));
}
/**
* @param {?=} onMessageCallback
* @return {?}
*/
startLiveChat(onMessageCallback = null) {
this.initializeUnReadMessagesCounts();
/** @type {?} */
const notificationCB = (/**
* @param {?} message
* @return {?}
*/
(message) => {
this.defaultMsgArrivalCallback(message);
if (onMessageCallback) {
onMessageCallback(message);
}
});
/** @type {?} */
const socketCB = (/**
* @param {?} event
* @return {?}
*/
(event) => {
/** @type {?} */
const message = JSON.parse(event.data).message;
notificationCB(message);
});
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
this.initializeAutoReconnectingWebSocket(socketCB);
else
this.setWebSocketCallbacks(socketCB);
if (this.pushService) {
this.setNotificationCallback(notificationCB);
}
}
/**
* @param {?} onMessageCB
* @return {?}
*/
initializeAutoReconnectingWebSocket(onMessageCB) {
this.closeLiveChat();
if (!this.authService.isAuthenticated()) {
return;
}
/** @type {?} */
const token = this.authService.getToken();
this.ws = new WebSocket(`${this.configObject.socket_url}?token=${token}`);
this.ws.onopen = (/**
* @return {?}
*/
() => this.isWebSocketReconnectingSource.next(false));
this.setWebSocketCallbacks(onMessageCB);
}
/**
* @private
* @param {?} onMessageCB
* @return {?}
*/
setWebSocketCallbacks(onMessageCB) {
this.ws.onmessage = onMessageCB;
this.ws.onclose = (/**
* @return {?}
*/
() => {
this.isWebSocketReconnectingSource.next(true);
setTimeout((/**
* @return {?}
*/
() => {
this.initializeAutoReconnectingWebSocket(onMessageCB);
}), 1000);
});
this.ws.onerror = (/**
* @param {?} error
* @return {?}
*/
(error) => {
// TODO: Check if authentication error, to stop reconnecting and do unauthenticated stuff
this.ws.close();
});
}
/**
* @private
* @return {?}
*/
initializeUnReadMessagesCounts() {
this.http.get(`${this.configObject.messages_url}unread_messages_count/`)
.subscribe((/**
* @param {?} countPairs
* @return {?}
*/
(countPairs) => {
this.setUnReadMsgsCountsArray(countPairs);
/** @type {?} */
let totalCount = 0;
countPairs.forEach((/**
* @param {?} pair
* @return {?}
*/
(pair) => {
totalCount += pair.count;
}));
this.setTotalUnReadMsgsCount(totalCount);
}));
}
/**
* @param {?} onMessageCallback
* @return {?}
*/
setNotificationCallback(onMessageCallback) {
/** @type {?} */
const notificationCB = (/**
* @param {?} notification
* @return {?}
*/
(notification) => {
// The following commented code was commented as the ws.readystate in most times while app in background doesn't
// detect that socket is not active anymore! So the if statement would be true and notification handler returns
// without doing anything, although the socket is not doing its job! We moved avoiding duplication to the
// component callback itself using message id
// The following commented code was commented as the ws.readystate in most times while app in background doesn't
// detect that socket is not active anymore! So the if statement would be true and notification handler returns
// without doing anything, although the socket is not doing its job! We moved avoiding duplication to the
// component callback itself using message id
// if(this.ws.readyState === this.ws.OPEN)
// return;
/** @type {?} */
const message = notification.additionalData.message_dict;
onMessageCallback(message);
});
// We commented the following code and instead set directly notification callback and check inside it while the
// websocket is closed or not, as sometimes (in iOS) onclose is not called when the socket is down in background app
// mode, so isWebSocketReconnecting will not update
// let self = this;
// this.notificationCallbackSubscription = this.isWebSocketReconnecting.subscribe({
// next(isClosed) {
// if(isClosed)
// self.pushService.setNotificationCallback(notificationCB);
// else self.pushService.removeNotificationCallback(notificationCB);
// },
// });
this.pushService.setNotificationCallback(notificationCB);
}
/**
* @return {?}
*/
removeOnMessageListener() {
if (this.ws) {
this.ws.onmessage = this.defaultMsgArrivalCallback;
}
if (this.pushService) {
this.pushService.setNotificationCallback(this.defaultMsgArrivalCallback);
}
}
/**
* @return {?}
*/
closeLiveChat() {
if (!this.ws)
return;
this.ws.onclose = (/**
* @param {?} event
* @return {?}
*/
(event) => {
delete this.ws;
});
this.ws.close();
}
/**
* @param {?=} donor_id
* @return {?}
*/
readAll(donor_id = null) {
/** @type {?} */
let readAllUrl;
if (donor_id)
readAllUrl = `${this.configObject.messages_url}${donor_id}/read_all/`;
else
readAllUrl = `${this.configObject.messages_url}read_all/`;
return this.http.patch(readAllUrl, {})
.pipe(tap((/**
* @param {?} event
* @return {?}
*/
event => this.setTotalUnReadMsgsCount(0))));
}
/**
* @param {?} donor_id
* @return {?}
*/
unreadLatest(donor_id) {
return this.http.patch(`${this.configObject.messages_url}${donor_id}/unread_latest/`, {});
}
}
MessagingService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
MessagingService.ctorParameters = () => [
{ type: HttpClient },
{ type: Injector },
{ type: undefined, decorators: [{ type: Inject, args: ['config',] }] }
];
/** @nocollapse */ MessagingService.ngInjectableDef = i0.ɵɵdefineInjectable({ factory: function MessagingService_Factory() { return new MessagingService(i0.ɵɵinject(i1.HttpClient), i0.ɵɵinject(i0.INJECTOR), i0.ɵɵinject("config")); }, token: MessagingService, providedIn: "root" });
if (false) {
/** @type {?} */
MessagingService.prototype.authService;
/** @type {?} */
MessagingService.prototype.pushService;
/** @type {?} */
MessagingService.prototype.ws;
/**
* @type {?}
* @private
*/
MessagingService.prototype.totalUnReadMsgsCountSource;
/** @type {?} */
MessagingService.prototype.totalUnReadMsgsCount;
/**
* @type {?}
* @private
*/
MessagingService.prototype.unReadMsgsCountsArraySource;
/** @type {?} */
MessagingService.prototype.unReadMsgsCountsArray;
/**
* @type {?}
* @private
*/
MessagingService.prototype.unreadMsgsIdsPairs;
/**
* @type {?}
* @private
*/
MessagingService.prototype.isWebSocketReconnectingSource;
/** @type {?} */
MessagingService.prototype.isWebSocketReconnecting;
/** @type {?} */
MessagingService.prototype.notificationCallbackSubscription;
/** @type {?} */
MessagingService.prototype.configObject;
/**
* @type {?}
* @private
*/
MessagingService.prototype.defaultMsgArrivalCallback;
/**
* @type {?}
* @private
*/
MessagingService.prototype.http;
/**
* @type {?}
* @private
*/
MessagingService.prototype.injector;
/**
* @type {?}
* @private
*/
MessagingService.prototype.config;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnaW5nLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly96b3JpYWtpbmMtbWVzc2FnaW5nLyIsInNvdXJjZXMiOlsibGliL2NoYXQtYm94L21lc3NhZ2luZy5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsT0FBTyxFQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQzNELE9BQU8sRUFBYSxlQUFlLEVBQWUsTUFBTSxNQUFNLENBQUM7QUFDL0QsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQ2hELE9BQU8sRUFBQyxHQUFHLEVBQUUsR0FBRyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLGFBQWEsQ0FBQzs7O0FBS3RDLE1BQU0sT0FBTyxnQkFBZ0I7Ozs7OztJQW9CM0IsWUFBb0IsSUFBZ0IsRUFBVyxRQUFrQixFQUE0QixNQUFXO1FBQXBGLFNBQUksR0FBSixJQUFJLENBQVk7UUFBVyxhQUFRLEdBQVIsUUFBUSxDQUFVO1FBQTRCLFdBQU0sR0FBTixNQUFNLENBQUs7UUFiaEcsK0JBQTBCLEdBQUcsSUFBSSxlQUFlLENBQU0sQ0FBQyxDQUFDLENBQUM7UUFDMUQseUJBQW9CLEdBQUcsSUFBSSxDQUFDLDBCQUEwQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXJFLGdDQUEyQixHQUFHLElBQUksZUFBZSxDQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQzVELDBCQUFxQixHQUFHLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUV2RSx1QkFBa0IsR0FBRyxFQUFFLENBQUM7UUFFeEIsa0NBQTZCLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDckUsNEJBQXVCLEdBQUcsSUFBSSxDQUFDLDZCQUE2QixDQUFDLFlBQVksRUFBRSxDQUFDO1FBcUIzRSw4QkFBeUI7Ozs7UUFBRyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQzlDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxJQUFJLENBQUMsa0JBQWtCLEVBQUU7Z0JBQ2hFLElBQUksSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFO29CQUN2RixPQUFPO2lCQUNSO2dCQUNELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQzthQUM3RTtpQkFBTTtnQkFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2FBQUU7WUFFckYsSUFBSSxDQUFDLDZCQUE2QixFQUFFLENBQUM7O2dCQUNqQyxnQkFBZ0IsR0FBZSxJQUFJLENBQUMsMkJBQTJCLENBQUMsUUFBUSxFQUFFOztrQkFDeEUsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUMsU0FBUzs7OztZQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLGNBQWMsS0FBSyxPQUFPLENBQUMsY0FBYyxFQUFDO1lBQ3ZHLElBQUcsZ0JBQWdCLEtBQUssQ0FBQyxDQUFDO2dCQUN4QixnQkFBZ0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUM7O2dCQUU5QyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBQyxjQUFjLEVBQUUsT0FBTyxDQUFDLGNBQWMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQztZQUU1RSxJQUFJLENBQUMsMkJBQTJCLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFDeEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ2hDLENBQUMsRUFBQztRQWxDQSxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3hDLElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDO1FBQzNCLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2xELElBQUksTUFBTSxDQUFDLElBQUksRUFBRTtZQUNmLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ25EO1FBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDOUIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDaEMsQ0FBQzs7Ozs7SUFJRCxVQUFVLENBQUMsTUFBTTtRQUNmLElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDO0lBQzdCLENBQUM7Ozs7O0lBcUJELHVCQUF1QixDQUFDLFFBQVE7UUFDOUIsSUFBSSxDQUFDLDBCQUEwQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNqRCxDQUFDOzs7OztJQUVELHdCQUF3QixDQUFDLEtBQUs7UUFDNUIsSUFBSSxDQUFDLDJCQUEyQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMvQyxDQUFDOzs7O0lBRUQsNkJBQTZCO1FBQzNCLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLDBCQUEwQixDQUFDLFFBQVEsRUFBRSxHQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7Ozs7OztJQUVELElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxHQUFDLElBQUk7O1lBQ3BCLE9BQU87UUFDWCxJQUFHLFFBQVE7WUFDVCxPQUFPLEdBQUcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksR0FBRyxRQUFRLFdBQVcsSUFBSSxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsV0FBVyxNQUFNLEVBQUUsQ0FBQzs7WUFFekgsT0FBTyxHQUFHLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLFVBQVUsSUFBSSxDQUFDLFlBQVksQ0FBQyxrQkFBa0IsV0FBVyxNQUFNLEVBQUUsQ0FBQztRQUMvRyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHOzs7O1FBQUMsQ0FBQyxJQUFTLEVBQUUsRUFBRTtZQUNuRCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDdEIsQ0FBQyxFQUFDLENBQUMsQ0FBQTtJQUNMLENBQUM7Ozs7OztJQUVELFlBQVksQ0FBQyxPQUFPLEVBQUUsUUFBUSxHQUFDLElBQUk7UUFDakMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUMxQixPQUFPLEVBQUMsT0FBTztZQUNmLFFBQVEsRUFBRSxRQUFRO1NBQ25CLENBQUMsQ0FBQyxDQUFDO0lBQ04sQ0FBQzs7Ozs7SUFFRCxhQUFhLENBQUMsaUJBQWlCLEdBQUMsSUFBSTtRQUNsQyxJQUFJLENBQUMsOEJBQThCLEVBQUUsQ0FBQzs7Y0FDaEMsY0FBYzs7OztRQUFHLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDakMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3hDLElBQUksaUJBQWlCLEVBQUU7Z0JBQ3JCLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFDO2FBQzVCO1FBQ0gsQ0FBQyxDQUFBOztjQUNLLFFBQVE7Ozs7UUFBRyxDQUFDLEtBQUssRUFBRSxFQUFFOztrQkFDbkIsT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU87WUFDOUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzFCLENBQUMsQ0FBQTtRQUVELElBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSTtZQUNoRCxJQUFJLENBQUMsbUNBQW1DLENBQUMsUUFBUSxDQUFDLENBQUM7O1lBRW5ELElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUV2QyxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDcEIsSUFBSSxDQUFDLHVCQUF1QixDQUFDLGNBQWMsQ0FBQyxDQUFDO1NBQzlDO0lBRUgsQ0FBQzs7Ozs7SUFFRCxtQ0FBbUMsQ0FBQyxXQUFXO1FBQzdDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLEVBQUUsRUFBRTtZQUN2QyxPQUFPO1NBQ1I7O2NBQ0ssS0FBSyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFFO1FBQ3pDLElBQUksQ0FBQyxFQUFFLEdBQUcsSUFBSSxTQUFTLENBQUMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsVUFBVSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQzFFLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTTs7O1FBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLDZCQUE2QixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQSxDQUFDO1FBQ3RFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMxQyxDQUFDOzs7Ozs7SUFFTyxxQkFBcUIsQ0FBQyxXQUFXO1FBQ3ZDLElBQUksQ0FBQyxFQUFFLENBQUMsU0FBUyxHQUFHLFdBQVcsQ0FBQztRQUNoQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU87OztRQUFHLEdBQUcsRUFBRTtZQUNyQixJQUFJLENBQUMsNkJBQTZCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzlDLFVBQVU7OztZQUFDLEdBQUcsRUFBRTtnQkFDZCxJQUFJLENBQUMsbUNBQW1DLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDeEQsQ0FBQyxHQUFFLElBQUksQ0FBQyxDQUFDO1FBQ1gsQ0FBQyxDQUFBLENBQUM7UUFDRixJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU87Ozs7UUFBRyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQzFCLHlGQUF5RjtZQUN6RixJQUFJLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2xCLENBQUMsQ0FBQSxDQUFDO0lBQ0osQ0FBQzs7Ozs7SUFFTyw4QkFBOEI7UUFDcEMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksd0JBQXdCLENBQUM7YUFDckUsU0FBUzs7OztRQUFDLENBQUMsVUFBaUIsRUFBRSxFQUFFO1lBQy9CLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxVQUFVLENBQUMsQ0FBQzs7Z0JBQ3RDLFVBQVUsR0FBRyxDQUFDO1lBQ2xCLFVBQVUsQ0FBQyxPQUFPOzs7O1lBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtnQkFDMUIsVUFBVSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUM7WUFDM0IsQ0FBQyxFQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsdUJBQXVCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDM0MsQ0FBQyxFQUFDLENBQUM7SUFDUCxDQUFDOzs7OztJQUVELHVCQUF1QixDQUFDLGlCQUFpQjs7Y0FDakMsY0FBYzs7OztRQUFHLENBQUMsWUFBWSxFQUFFLEVBQUU7WUFDdEMsZ0hBQWdIO1lBQ2hILCtHQUErRztZQUMvRyx5R0FBeUc7WUFDekcsNkNBQTZDOzs7Ozs7OztrQkFLdkMsT0FBTyxHQUFHLFlBQVksQ0FBQyxjQUFjLENBQUMsWUFBWTtZQUN4RCxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QixDQUFDLENBQUE7UUFFRCwrR0FBK0c7UUFDL0csb0hBQW9IO1FBQ3BILG1EQUFtRDtRQUVuRCxtQkFBbUI7UUFDbkIsbUZBQW1GO1FBQ25GLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsa0VBQWtFO1FBQ2xFLHdFQUF3RTtRQUN4RSxPQUFPO1FBQ1AsTUFBTTtRQUNOLElBQUksQ0FBQyxXQUFXLENBQUMsdUJBQXVCLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDM0QsQ0FBQzs7OztJQUVELHVCQUF1QjtRQUNyQixJQUFJLElBQUksQ0FBQyxFQUFFLEVBQUU7WUFDWCxJQUFJLENBQUMsRUFBRSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMseUJBQXlCLENBQUM7U0FDcEQ7UUFDRCxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDcEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsQ0FBQztTQUMxRTtJQUNILENBQUM7Ozs7SUFFRCxhQUFhO1FBQ1gsSUFBRyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQUUsT0FBTztRQUNwQixJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU87Ozs7UUFBRyxDQUFDLEtBQUssRUFBRSxFQUFFO1lBQzFCLE9BQU8sSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNqQixDQUFDLENBQUEsQ0FBQztRQUNGLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDbEIsQ0FBQzs7Ozs7SUFFRCxPQUFPLENBQUMsUUFBUSxHQUFDLElBQUk7O1lBQ2YsVUFBVTtRQUNkLElBQUcsUUFBUTtZQUFFLFVBQVUsR0FBRyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxHQUFHLFFBQVEsWUFBWSxDQUFDOztZQUM5RSxVQUFVLEdBQUcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksV0FBVyxDQUFDO1FBQy9ELE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQzthQUNuQyxJQUFJLENBQUMsR0FBRzs7OztRQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUN6RCxDQUFDOzs7OztJQUVELFlBQVksQ0FBQyxRQUFRO1FBQ25CLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksR0FBRyxRQUFRLGlCQUFpQixFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzVGLENBQUM7OztZQTlNRixVQUFVLFNBQUM7Z0JBQ1YsVUFBVSxFQUFFLE1BQU07YUFDbkI7Ozs7WUFOTyxVQUFVO1lBRlUsUUFBUTs0Q0E2QmtDLE1BQU0sU0FBQyxRQUFROzs7OztJQWxCbkYsdUNBQWlCOztJQUNqQix1Q0FBaUI7O0lBRWpCLDhCQUFjOzs7OztJQUVkLHNEQUFpRTs7SUFDakUsZ0RBQTZFOzs7OztJQUU3RSx1REFBbUU7O0lBQ25FLGlEQUErRTs7Ozs7SUFFL0UsOENBQWdDOzs7OztJQUVoQyx5REFBNEU7O0lBQzVFLG1EQUFtRjs7SUFFbkYsNERBQStDOztJQWEvQyx3Q0FBa0I7Ozs7O0lBTWxCLHFEQWtCRTs7Ozs7SUFuQ1UsZ0NBQXdCOzs7OztJQUFFLG9DQUEyQjs7Ozs7SUFBRSxrQ0FBcUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0luamVjdCwgSW5qZWN0YWJsZSwgSW5qZWN0b3J9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtPYnNlcnZhYmxlLCBCZWhhdmlvclN1YmplY3QsIFN1YnNjcmlwdGlvbn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge0h0dHBDbGllbnR9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7dGFwLCBtYXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7c3RyaW5naWZ5fSBmcm9tICdxdWVyeXN0cmluZyc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE1lc3NhZ2luZ1NlcnZpY2Uge1xuXG4gIGF1dGhTZXJ2aWNlOiBhbnk7XG4gIHB1c2hTZXJ2aWNlOiBhbnk7XG5cbiAgd3M6IFdlYlNvY2tldDtcblxuICBwcml2YXRlIHRvdGFsVW5SZWFkTXNnc0NvdW50U291cmNlID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KDApO1xuICBwdWJsaWMgdG90YWxVblJlYWRNc2dzQ291bnQgPSB0aGlzLnRvdGFsVW5SZWFkTXNnc0NvdW50U291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIHByaXZhdGUgdW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KFtdKTtcbiAgcHVibGljIHVuUmVhZE1zZ3NDb3VudHNBcnJheSA9IHRoaXMudW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIHByaXZhdGUgdW5yZWFkTXNnc0lkc1BhaXJzID0ge307XG5cbiAgcHJpdmF0ZSBpc1dlYlNvY2tldFJlY29ubmVjdGluZ1NvdXJjZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwdWJsaWMgaXNXZWJTb2NrZXRSZWNvbm5lY3RpbmcgPSB0aGlzLmlzV2ViU29ja2V0UmVjb25uZWN0aW5nU291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIG5vdGlmaWNhdGlvbkNhbGxiYWNrU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LCBwcml2YXRlICBpbmplY3RvcjogSW5qZWN0b3IsIEBJbmplY3QoJ2NvbmZpZycpIHByaXZhdGUgY29uZmlnOiBhbnkpIHtcbiAgICBjb25zb2xlLmxvZygnaW5zaWRlIHNlcnZpY2U6ICcsIGNvbmZpZyk7XG4gICAgdGhpcy5jb25maWdPYmplY3QgPSBjb25maWc7XG4gICAgdGhpcy5hdXRoU2VydmljZSA9IHRoaXMuaW5qZWN0b3IuZ2V0KGNvbmZpZy5hdXRoKTtcbiAgICBpZiAoY29uZmlnLnB1c2gpIHtcbiAgICAgIHRoaXMucHVzaFNlcnZpY2UgPSB0aGlzLmluamVjdG9yLmdldChjb25maWcucHVzaCk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKHRoaXMuYXV0aFNlcnZpY2UpO1xuICAgIGNvbnNvbGUubG9nKHRoaXMucHVzaFNlcnZpY2UpO1xuICB9XG5cbiAgY29uZmlnT2JqZWN0OiBhbnk7XG5cbiAgaW5pdGlhbGl6ZShjb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZ09iamVjdCA9IGNvbmZpZztcbiAgfVxuXG4gIHByaXZhdGUgZGVmYXVsdE1zZ0Fycml2YWxDYWxsYmFjayA9IChtZXNzYWdlKSA9PiB7XG4gICAgaWYgKHN0cmluZ2lmeShtZXNzYWdlLnNlbmRlcl91c2VyX2lkKSBpbiB0aGlzLnVucmVhZE1zZ3NJZHNQYWlycykge1xuICAgICAgaWYgKHRoaXMudW5yZWFkTXNnc0lkc1BhaXJzW3N0cmluZ2lmeShtZXNzYWdlLnNlbmRlcl91c2VyX2lkKV0uaW5kZXhPZihtZXNzYWdlLmlkKSA+IC0xKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMudW5yZWFkTXNnc0lkc1BhaXJzW3N0cmluZ2lmeShtZXNzYWdlLnNlbmRlcl91c2VyX2lkKV0ucHVzaChtZXNzYWdlLmlkKTtcbiAgICB9IGVsc2UgeyB0aGlzLnVucmVhZE1zZ3NJZHNQYWlyc1tzdHJpbmdpZnkobWVzc2FnZS5zZW5kZXJfdXNlcl9pZCldID0gW21lc3NhZ2UuaWRdOyB9XG5cbiAgICB0aGlzLmluY3JlbWVudFRvdGFsVW5SZWFkTXNnc0NvdW50KCk7XG4gICAgbGV0IHVuUmVhZFBhaXJzQXJyYXk6IEFycmF5PGFueT4gPSB0aGlzLnVuUmVhZE1zZ3NDb3VudHNBcnJheVNvdXJjZS5nZXRWYWx1ZSgpO1xuICAgIGNvbnN0IG1hdGNoZWRQYWlySW5kZXggPSB1blJlYWRQYWlyc0FycmF5LmZpbmRJbmRleChlbCA9PiBlbC5zZW5kZXJfdXNlcl9pZCA9PT0gbWVzc2FnZS5zZW5kZXJfdXNlcl9pZCk7XG4gICAgaWYobWF0Y2hlZFBhaXJJbmRleCAhPT0gLTEpXG4gICAgICB1blJlYWRQYWlyc0FycmF5W21hdGNoZWRQYWlySW5kZXhdLmNvdW50ICs9IDE7XG4gICAgZWxzZVxuICAgICAgdW5SZWFkUGFpcnNBcnJheS5wdXNoKHtzZW5kZXJfdXNlcl9pZDogbWVzc2FnZS5zZW5kZXJfdXNlcl9pZCwgY291bnQ6IDF9KTtcblxuICAgIHRoaXMudW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlLm5leHQodW5SZWFkUGFpcnNBcnJheSk7XG4gICAgY29uc29sZS5sb2codW5SZWFkUGFpcnNBcnJheSk7XG4gIH07XG4gIHNldFRvdGFsVW5SZWFkTXNnc0NvdW50KG5ld0NvdW50KSB7XG4gICAgdGhpcy50b3RhbFVuUmVhZE1zZ3NDb3VudFNvdXJjZS5uZXh0KG5ld0NvdW50KTtcbiAgfVxuXG4gIHNldFVuUmVhZE1zZ3NDb3VudHNBcnJheShwYWlycykge1xuICAgIHRoaXMudW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlLm5leHQocGFpcnMpO1xuICB9XG5cbiAgaW5jcmVtZW50VG90YWxVblJlYWRNc2dzQ291bnQoKSB7XG4gICAgdGhpcy50b3RhbFVuUmVhZE1zZ3NDb3VudFNvdXJjZS5uZXh0KHRoaXMudG90YWxVblJlYWRNc2dzQ291bnRTb3VyY2UuZ2V0VmFsdWUoKSsxKTtcbiAgfVxuXG4gIGxpc3Qob2Zmc2V0LCBkb25vcl9pZD1udWxsKTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICBsZXQgY2hhdFVybDtcbiAgICBpZihkb25vcl9pZClcbiAgICAgIGNoYXRVcmwgPSBgJHt0aGlzLmNvbmZpZ09iamVjdC5tZXNzYWdlc191cmx9JHtkb25vcl9pZH0vP2xpbWl0PSR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfcGFnZV9zaXplfSZvZmZzZXQ9JHtvZmZzZXR9YDtcbiAgICBlbHNlXG4gICAgICBjaGF0VXJsID0gYCR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfdXJsfT9saW1pdD0ke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3BhZ2Vfc2l6ZX0mb2Zmc2V0PSR7b2Zmc2V0fWA7XG4gICAgcmV0dXJuIHRoaXMuaHR0cC5nZXQoY2hhdFVybCkucGlwZShtYXAoKHJlc3A6IGFueSkgPT4ge1xuICAgICAgcmV0dXJuIHJlc3AucmVzdWx0cztcbiAgICB9KSlcbiAgfVxuXG4gIHNlbmRfbWVzc2FnZShjb250ZW50LCBkb25vcl9pZD1udWxsKSB7XG4gICAgdGhpcy53cy5zZW5kKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIGNvbnRlbnQ6Y29udGVudCxcbiAgICAgIGRvbm9yX2lkOiBkb25vcl9pZFxuICAgIH0pKTtcbiAgfVxuXG4gIHN0YXJ0TGl2ZUNoYXQob25NZXNzYWdlQ2FsbGJhY2s9bnVsbCkge1xuICAgIHRoaXMuaW5pdGlhbGl6ZVVuUmVhZE1lc3NhZ2VzQ291bnRzKCk7XG4gICAgY29uc3Qgbm90aWZpY2F0aW9uQ0IgPSAobWVzc2FnZSkgPT4ge1xuICAgICAgdGhpcy5kZWZhdWx0TXNnQXJyaXZhbENhbGxiYWNrKG1lc3NhZ2UpO1xuICAgICAgaWYgKG9uTWVzc2FnZUNhbGxiYWNrKSB7XG4gICAgICAgIG9uTWVzc2FnZUNhbGxiYWNrKG1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH07XG4gICAgY29uc3Qgc29ja2V0Q0IgPSAoZXZlbnQpID0+IHtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpLm1lc3NhZ2U7XG4gICAgICBub3RpZmljYXRpb25DQihtZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgaWYoIXRoaXMud3MgfHwgdGhpcy53cy5yZWFkeVN0YXRlICE9PSB0aGlzLndzLk9QRU4pXG4gICAgICB0aGlzLmluaXRpYWxpemVBdXRvUmVjb25uZWN0aW5nV2ViU29ja2V0KHNvY2tldENCKTtcbiAgICBlbHNlXG4gICAgICB0aGlzLnNldFdlYlNvY2tldENhbGxiYWNrcyhzb2NrZXRDQik7XG5cbiAgICBpZiAodGhpcy5wdXNoU2VydmljZSkge1xuICAgICAgdGhpcy5zZXROb3RpZmljYXRpb25DYWxsYmFjayhub3RpZmljYXRpb25DQik7XG4gICAgfVxuXG4gIH1cblxuICBpbml0aWFsaXplQXV0b1JlY29ubmVjdGluZ1dlYlNvY2tldChvbk1lc3NhZ2VDQikge1xuICAgIHRoaXMuY2xvc2VMaXZlQ2hhdCgpO1xuICAgIGlmICghdGhpcy5hdXRoU2VydmljZS5pc0F1dGhlbnRpY2F0ZWQoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB0b2tlbiA9IHRoaXMuYXV0aFNlcnZpY2UuZ2V0VG9rZW4oKTtcbiAgICB0aGlzLndzID0gbmV3IFdlYlNvY2tldChgJHt0aGlzLmNvbmZpZ09iamVjdC5zb2NrZXRfdXJsfT90b2tlbj0ke3Rva2VufWApO1xuICAgIHRoaXMud3Mub25vcGVuID0gKCkgPT4gdGhpcy5pc1dlYlNvY2tldFJlY29ubmVjdGluZ1NvdXJjZS5uZXh0KGZhbHNlKTtcbiAgICB0aGlzLnNldFdlYlNvY2tldENhbGxiYWNrcyhvbk1lc3NhZ2VDQik7XG4gIH1cblxuICBwcml2YXRlIHNldFdlYlNvY2tldENhbGxiYWNrcyhvbk1lc3NhZ2VDQikge1xuICAgIHRoaXMud3Mub25tZXNzYWdlID0gb25NZXNzYWdlQ0I7XG4gICAgdGhpcy53cy5vbmNsb3NlID0gKCkgPT4ge1xuICAgICAgdGhpcy5pc1dlYlNvY2tldFJlY29ubmVjdGluZ1NvdXJjZS5uZXh0KHRydWUpO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUF1dG9SZWNvbm5lY3RpbmdXZWJTb2NrZXQob25NZXNzYWdlQ0IpO1xuICAgICAgfSwgMTAwMCk7XG4gICAgfTtcbiAgICB0aGlzLndzLm9uZXJyb3IgPSAoZXJyb3IpID0+IHtcbiAgICAgIC8vIFRPRE86IENoZWNrIGlmIGF1dGhlbnRpY2F0aW9uIGVycm9yLCB0byBzdG9wIHJlY29ubmVjdGluZyBhbmQgZG8gdW5hdXRoZW50aWNhdGVkIHN0dWZmXG4gICAgICB0aGlzLndzLmNsb3NlKCk7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgaW5pdGlhbGl6ZVVuUmVhZE1lc3NhZ2VzQ291bnRzKCkge1xuICAgIHRoaXMuaHR0cC5nZXQoYCR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfdXJsfXVucmVhZF9tZXNzYWdlc19jb3VudC9gKVxuICAgICAgLnN1YnNjcmliZSgoY291bnRQYWlyczogYW55W10pID0+IHtcbiAgICAgICAgdGhpcy5zZXRVblJlYWRNc2dzQ291bnRzQXJyYXkoY291bnRQYWlycyk7XG4gICAgICAgIGxldCB0b3RhbENvdW50ID0gMDtcbiAgICAgICAgY291bnRQYWlycy5mb3JFYWNoKChwYWlyKSA9PiB7XG4gICAgICAgICAgdG90YWxDb3VudCArPSBwYWlyLmNvdW50O1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRUb3RhbFVuUmVhZE1zZ3NDb3VudCh0b3RhbENvdW50KTtcbiAgICAgIH0pO1xuICB9XG5cbiAgc2V0Tm90aWZpY2F0aW9uQ2FsbGJhY2sob25NZXNzYWdlQ2FsbGJhY2spIHtcbiAgICBjb25zdCBub3RpZmljYXRpb25DQiA9IChub3RpZmljYXRpb24pID0+IHtcbiAgICAgIC8vIFRoZSBmb2xsb3dpbmcgY29tbWVudGVkIGNvZGUgd2FzIGNvbW1lbnRlZCBhcyB0aGUgd3MucmVhZHlzdGF0ZSBpbiBtb3N0IHRpbWVzIHdoaWxlIGFwcCBpbiBiYWNrZ3JvdW5kIGRvZXNuJ3RcbiAgICAgIC8vIGRldGVjdCB0aGF0IHNvY2tldCBpcyBub3QgYWN0aXZlIGFueW1vcmUhIFNvIHRoZSBpZiBzdGF0ZW1lbnQgd291bGQgYmUgdHJ1ZSBhbmQgbm90aWZpY2F0aW9uIGhhbmRsZXIgcmV0dXJuc1xuICAgICAgLy8gd2l0aG91dCBkb2luZyBhbnl0aGluZywgYWx0aG91Z2ggdGhlIHNvY2tldCBpcyBub3QgZG9pbmcgaXRzIGpvYiEgV2UgbW92ZWQgYXZvaWRpbmcgZHVwbGljYXRpb24gdG8gdGhlXG4gICAgICAvLyBjb21wb25lbnQgY2FsbGJhY2sgaXRzZWxmIHVzaW5nIG1lc3NhZ2UgaWRcblxuICAgICAgLy8gaWYodGhpcy53cy5yZWFkeVN0YXRlID09PSB0aGlzLndzLk9QRU4pXG4gICAgICAvLyAgIHJldHVybjtcblxuICAgICAgY29uc3QgbWVzc2FnZSA9IG5vdGlmaWNhdGlvbi5hZGRpdGlvbmFsRGF0YS5tZXNzYWdlX2RpY3Q7XG4gICAgICBvbk1lc3NhZ2VDYWxsYmFjayhtZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgLy8gV2UgY29tbWVudGVkIHRoZSBmb2xsb3dpbmcgY29kZSBhbmQgaW5zdGVhZCBzZXQgZGlyZWN0bHkgbm90aWZpY2F0aW9uIGNhbGxiYWNrIGFuZCBjaGVjayBpbnNpZGUgaXQgd2hpbGUgdGhlXG4gICAgLy8gd2Vic29ja2V0IGlzIGNsb3NlZCBvciBub3QsIGFzIHNvbWV0aW1lcyAoaW4gaU9TKSBvbmNsb3NlIGlzIG5vdCBjYWxsZWQgd2hlbiB0aGUgc29ja2V0IGlzIGRvd24gaW4gYmFja2dyb3VuZCBhcHBcbiAgICAvLyBtb2RlLCBzbyBpc1dlYlNvY2tldFJlY29ubmVjdGluZyB3aWxsIG5vdCB1cGRhdGVcblxuICAgIC8vIGxldCBzZWxmID0gdGhpcztcbiAgICAvLyB0aGlzLm5vdGlmaWNhdGlvbkNhbGxiYWNrU3Vic2NyaXB0aW9uID0gdGhpcy5pc1dlYlNvY2tldFJlY29ubmVjdGluZy5zdWJzY3JpYmUoe1xuICAgIC8vICAgbmV4dChpc0Nsb3NlZCkge1xuICAgIC8vICAgICBpZihpc0Nsb3NlZClcbiAgICAvLyAgICAgICBzZWxmLnB1c2hTZXJ2aWNlLnNldE5vdGlmaWNhdGlvbkNhbGxiYWNrKG5vdGlmaWNhdGlvbkNCKTtcbiAgICAvLyAgICAgZWxzZSBzZWxmLnB1c2hTZXJ2aWNlLnJlbW92ZU5vdGlmaWNhdGlvbkNhbGxiYWNrKG5vdGlmaWNhdGlvbkNCKTtcbiAgICAvLyAgIH0sXG4gICAgLy8gfSk7XG4gICAgdGhpcy5wdXNoU2VydmljZS5zZXROb3RpZmljYXRpb25DYWxsYmFjayhub3RpZmljYXRpb25DQik7XG4gIH1cblxuICByZW1vdmVPbk1lc3NhZ2VMaXN0ZW5lcigpIHtcbiAgICBpZiAodGhpcy53cykge1xuICAgICAgdGhpcy53cy5vbm1lc3NhZ2UgPSB0aGlzLmRlZmF1bHRNc2dBcnJpdmFsQ2FsbGJhY2s7XG4gICAgfVxuICAgIGlmICh0aGlzLnB1c2hTZXJ2aWNlKSB7XG4gICAgICB0aGlzLnB1c2hTZXJ2aWNlLnNldE5vdGlmaWNhdGlvbkNhbGxiYWNrKHRoaXMuZGVmYXVsdE1zZ0Fycml2YWxDYWxsYmFjayk7XG4gICAgfVxuICB9XG5cbiAgY2xvc2VMaXZlQ2hhdCgpIHtcbiAgICBpZighdGhpcy53cykgcmV0dXJuO1xuICAgIHRoaXMud3Mub25jbG9zZSA9IChldmVudCkgPT4ge1xuICAgICAgZGVsZXRlIHRoaXMud3M7XG4gICAgfTtcbiAgICB0aGlzLndzLmNsb3NlKCk7XG4gIH1cblxuICByZWFkQWxsKGRvbm9yX2lkPW51bGwpIHtcbiAgICBsZXQgcmVhZEFsbFVybDtcbiAgICBpZihkb25vcl9pZCkgcmVhZEFsbFVybCA9IGAke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3VybH0ke2Rvbm9yX2lkfS9yZWFkX2FsbC9gO1xuICAgIGVsc2UgcmVhZEFsbFVybCA9IGAke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3VybH1yZWFkX2FsbC9gO1xuICAgIHJldHVybiB0aGlzLmh0dHAucGF0Y2gocmVhZEFsbFVybCwge30pXG4gICAgICAucGlwZSh0YXAoZXZlbnQgPT4gdGhpcy5zZXRUb3RhbFVuUmVhZE1zZ3NDb3VudCgwKSkpO1xuICB9XG5cbiAgdW5yZWFkTGF0ZXN0KGRvbm9yX2lkKSB7XG4gICAgcmV0dXJuIHRoaXMuaHR0cC5wYXRjaChgJHt0aGlzLmNvbmZpZ09iamVjdC5tZXNzYWdlc191cmx9JHtkb25vcl9pZH0vdW5yZWFkX2xhdGVzdC9gLCB7fSk7XG4gIH1cbn1cbiJdfQ==