zoriakinc-messaging
Version:
Angular Messaging Module
460 lines • 34.5 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";
var MessagingService = /** @class */ (function () {
function MessagingService(http, injector, config) {
var _this = this;
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 {?}
*/
function (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 {?} */
var unReadPairsArray = _this.unReadMsgsCountsArraySource.getValue();
/** @type {?} */
var matchedPairIndex = unReadPairsArray.findIndex((/**
* @param {?} el
* @return {?}
*/
function (el) { return 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 {?}
*/
MessagingService.prototype.initialize = /**
* @param {?} config
* @return {?}
*/
function (config) {
this.configObject = config;
};
/**
* @param {?} newCount
* @return {?}
*/
MessagingService.prototype.setTotalUnReadMsgsCount = /**
* @param {?} newCount
* @return {?}
*/
function (newCount) {
this.totalUnReadMsgsCountSource.next(newCount);
};
/**
* @param {?} pairs
* @return {?}
*/
MessagingService.prototype.setUnReadMsgsCountsArray = /**
* @param {?} pairs
* @return {?}
*/
function (pairs) {
this.unReadMsgsCountsArraySource.next(pairs);
};
/**
* @return {?}
*/
MessagingService.prototype.incrementTotalUnReadMsgsCount = /**
* @return {?}
*/
function () {
this.totalUnReadMsgsCountSource.next(this.totalUnReadMsgsCountSource.getValue() + 1);
};
/**
* @param {?} offset
* @param {?=} donor_id
* @return {?}
*/
MessagingService.prototype.list = /**
* @param {?} offset
* @param {?=} donor_id
* @return {?}
*/
function (offset, donor_id) {
if (donor_id === void 0) { donor_id = null; }
/** @type {?} */
var 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 {?}
*/
function (resp) {
return resp.results;
})));
};
/**
* @param {?} content
* @param {?=} donor_id
* @return {?}
*/
MessagingService.prototype.send_message = /**
* @param {?} content
* @param {?=} donor_id
* @return {?}
*/
function (content, donor_id) {
if (donor_id === void 0) { donor_id = null; }
this.ws.send(JSON.stringify({
content: content,
donor_id: donor_id
}));
};
/**
* @param {?=} onMessageCallback
* @return {?}
*/
MessagingService.prototype.startLiveChat = /**
* @param {?=} onMessageCallback
* @return {?}
*/
function (onMessageCallback) {
var _this = this;
if (onMessageCallback === void 0) { onMessageCallback = null; }
this.initializeUnReadMessagesCounts();
/** @type {?} */
var notificationCB = (/**
* @param {?} message
* @return {?}
*/
function (message) {
_this.defaultMsgArrivalCallback(message);
if (onMessageCallback) {
onMessageCallback(message);
}
});
/** @type {?} */
var socketCB = (/**
* @param {?} event
* @return {?}
*/
function (event) {
/** @type {?} */
var 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 {?}
*/
MessagingService.prototype.initializeAutoReconnectingWebSocket = /**
* @param {?} onMessageCB
* @return {?}
*/
function (onMessageCB) {
var _this = this;
this.closeLiveChat();
if (!this.authService.isAuthenticated()) {
return;
}
/** @type {?} */
var token = this.authService.getToken();
this.ws = new WebSocket(this.configObject.socket_url + "?token=" + token);
this.ws.onopen = (/**
* @return {?}
*/
function () { return _this.isWebSocketReconnectingSource.next(false); });
this.setWebSocketCallbacks(onMessageCB);
};
/**
* @private
* @param {?} onMessageCB
* @return {?}
*/
MessagingService.prototype.setWebSocketCallbacks = /**
* @private
* @param {?} onMessageCB
* @return {?}
*/
function (onMessageCB) {
var _this = this;
this.ws.onmessage = onMessageCB;
this.ws.onclose = (/**
* @return {?}
*/
function () {
_this.isWebSocketReconnectingSource.next(true);
setTimeout((/**
* @return {?}
*/
function () {
_this.initializeAutoReconnectingWebSocket(onMessageCB);
}), 1000);
});
this.ws.onerror = (/**
* @param {?} error
* @return {?}
*/
function (error) {
// TODO: Check if authentication error, to stop reconnecting and do unauthenticated stuff
_this.ws.close();
});
};
/**
* @private
* @return {?}
*/
MessagingService.prototype.initializeUnReadMessagesCounts = /**
* @private
* @return {?}
*/
function () {
var _this = this;
this.http.get(this.configObject.messages_url + "unread_messages_count/")
.subscribe((/**
* @param {?} countPairs
* @return {?}
*/
function (countPairs) {
_this.setUnReadMsgsCountsArray(countPairs);
/** @type {?} */
var totalCount = 0;
countPairs.forEach((/**
* @param {?} pair
* @return {?}
*/
function (pair) {
totalCount += pair.count;
}));
_this.setTotalUnReadMsgsCount(totalCount);
}));
};
/**
* @param {?} onMessageCallback
* @return {?}
*/
MessagingService.prototype.setNotificationCallback = /**
* @param {?} onMessageCallback
* @return {?}
*/
function (onMessageCallback) {
/** @type {?} */
var notificationCB = (/**
* @param {?} notification
* @return {?}
*/
function (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 {?} */
var 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 {?}
*/
MessagingService.prototype.removeOnMessageListener = /**
* @return {?}
*/
function () {
if (this.ws) {
this.ws.onmessage = this.defaultMsgArrivalCallback;
}
if (this.pushService) {
this.pushService.setNotificationCallback(this.defaultMsgArrivalCallback);
}
};
/**
* @return {?}
*/
MessagingService.prototype.closeLiveChat = /**
* @return {?}
*/
function () {
var _this = this;
if (!this.ws)
return;
this.ws.onclose = (/**
* @param {?} event
* @return {?}
*/
function (event) {
delete _this.ws;
});
this.ws.close();
};
/**
* @param {?=} donor_id
* @return {?}
*/
MessagingService.prototype.readAll = /**
* @param {?=} donor_id
* @return {?}
*/
function (donor_id) {
var _this = this;
if (donor_id === void 0) { donor_id = null; }
/** @type {?} */
var 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 {?}
*/
function (event) { return _this.setTotalUnReadMsgsCount(0); })));
};
/**
* @param {?} donor_id
* @return {?}
*/
MessagingService.prototype.unreadLatest = /**
* @param {?} donor_id
* @return {?}
*/
function (donor_id) {
return this.http.patch("" + this.configObject.messages_url + donor_id + "/unread_latest/", {});
};
MessagingService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
MessagingService.ctorParameters = function () { return [
{ 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" });
return MessagingService;
}());
export { MessagingService };
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnaW5nLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly96b3JpYWtpbmMtbWVzc2FnaW5nLyIsInNvdXJjZXMiOlsibGliL2NoYXQtYm94L21lc3NhZ2luZy5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsT0FBTyxFQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQzNELE9BQU8sRUFBYSxlQUFlLEVBQWUsTUFBTSxNQUFNLENBQUM7QUFDL0QsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQ2hELE9BQU8sRUFBQyxHQUFHLEVBQUUsR0FBRyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLGFBQWEsQ0FBQzs7O0FBRXRDO0lBdUJFLDBCQUFvQixJQUFnQixFQUFXLFFBQWtCLEVBQTRCLE1BQVc7UUFBeEcsaUJBU0M7UUFUbUIsU0FBSSxHQUFKLElBQUksQ0FBWTtRQUFXLGFBQVEsR0FBUixRQUFRLENBQVU7UUFBNEIsV0FBTSxHQUFOLE1BQU0sQ0FBSztRQWJoRywrQkFBMEIsR0FBRyxJQUFJLGVBQWUsQ0FBTSxDQUFDLENBQUMsQ0FBQztRQUMxRCx5QkFBb0IsR0FBRyxJQUFJLENBQUMsMEJBQTBCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFFckUsZ0NBQTJCLEdBQUcsSUFBSSxlQUFlLENBQU0sRUFBRSxDQUFDLENBQUM7UUFDNUQsMEJBQXFCLEdBQUcsSUFBSSxDQUFDLDJCQUEyQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXZFLHVCQUFrQixHQUFHLEVBQUUsQ0FBQztRQUV4QixrQ0FBNkIsR0FBRyxJQUFJLGVBQWUsQ0FBVSxLQUFLLENBQUMsQ0FBQztRQUNyRSw0QkFBdUIsR0FBRyxJQUFJLENBQUMsNkJBQTZCLENBQUMsWUFBWSxFQUFFLENBQUM7UUFxQjNFLDhCQUF5Qjs7OztRQUFHLFVBQUMs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Q0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDO2FBQ25DLElBQUksQ0FBQyxHQUFHOzs7O1FBQUMsVUFBQSxLQUFLLElBQUksT0FBQSxLQUFJLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxDQUFDLEVBQS9CLENBQStCLEVBQUMsQ0FBQyxDQUFDO0lBQ3pELENBQUM7Ozs7O0lBRUQsdUNBQVk7Ozs7SUFBWixVQUFhLFFBQVE7UUFDbkIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxHQUFHLFFBQVEsb0JBQWlCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDNUYsQ0FBQzs7Z0JBOU1GLFVBQVUsU0FBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkI7Ozs7Z0JBTk8sVUFBVTtnQkFGVSxRQUFRO2dEQTZCa0MsTUFBTSxTQUFDLFFBQVE7OzsyQkE3QnJGO0NBcU5DLEFBL01ELElBK01DO1NBNU1ZLGdCQUFnQjs7O0lBRTNCLHVDQUFpQjs7SUFDakIsdUNBQWlCOztJQUVqQiw4QkFBYzs7Ozs7SUFFZCxzREFBaUU7O0lBQ2pFLGdEQUE2RTs7Ozs7SUFFN0UsdURBQW1FOztJQUNuRSxpREFBK0U7Ozs7O0lBRS9FLDhDQUFnQzs7Ozs7SUFFaEMseURBQTRFOztJQUM1RSxtREFBbUY7O0lBRW5GLDREQUErQzs7SUFhL0Msd0NBQWtCOzs7OztJQU1sQixxREFrQkU7Ozs7O0lBbkNVLGdDQUF3Qjs7Ozs7SUFBRSxvQ0FBMkI7Ozs7O0lBQUUsa0NBQXFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtJbmplY3QsIEluamVjdGFibGUsIEluamVjdG9yfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7T2JzZXJ2YWJsZSwgQmVoYXZpb3JTdWJqZWN0LCBTdWJzY3JpcHRpb259IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtIdHRwQ2xpZW50fSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQge3RhcCwgbWFwfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge3N0cmluZ2lmeX0gZnJvbSAncXVlcnlzdHJpbmcnO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBNZXNzYWdpbmdTZXJ2aWNlIHtcblxuICBhdXRoU2VydmljZTogYW55O1xuICBwdXNoU2VydmljZTogYW55O1xuXG4gIHdzOiBXZWJTb2NrZXQ7XG5cbiAgcHJpdmF0ZSB0b3RhbFVuUmVhZE1zZ3NDb3VudFNvdXJjZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8YW55PigwKTtcbiAgcHVibGljIHRvdGFsVW5SZWFkTXNnc0NvdW50ID0gdGhpcy50b3RhbFVuUmVhZE1zZ3NDb3VudFNvdXJjZS5hc09ic2VydmFibGUoKTtcblxuICBwcml2YXRlIHVuUmVhZE1zZ3NDb3VudHNBcnJheVNvdXJjZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8YW55PihbXSk7XG4gIHB1YmxpYyB1blJlYWRNc2dzQ291bnRzQXJyYXkgPSB0aGlzLnVuUmVhZE1zZ3NDb3VudHNBcnJheVNvdXJjZS5hc09ic2VydmFibGUoKTtcblxuICBwcml2YXRlIHVucmVhZE1zZ3NJZHNQYWlycyA9IHt9O1xuXG4gIHByaXZhdGUgaXNXZWJTb2NrZXRSZWNvbm5lY3RpbmdTb3VyY2UgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcbiAgcHVibGljIGlzV2ViU29ja2V0UmVjb25uZWN0aW5nID0gdGhpcy5pc1dlYlNvY2tldFJlY29ubmVjdGluZ1NvdXJjZS5hc09ic2VydmFibGUoKTtcblxuICBub3RpZmljYXRpb25DYWxsYmFja1N1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgaHR0cDogSHR0cENsaWVudCwgcHJpdmF0ZSAgaW5qZWN0b3I6IEluamVjdG9yLCBASW5qZWN0KCdjb25maWcnKSBwcml2YXRlIGNvbmZpZzogYW55KSB7XG4gICAgY29uc29sZS5sb2coJ2luc2lkZSBzZXJ2aWNlOiAnLCBjb25maWcpO1xuICAgIHRoaXMuY29uZmlnT2JqZWN0ID0gY29uZmlnO1xuICAgIHRoaXMuYXV0aFNlcnZpY2UgPSB0aGlzLmluamVjdG9yLmdldChjb25maWcuYXV0aCk7XG4gICAgaWYgKGNvbmZpZy5wdXNoKSB7XG4gICAgICB0aGlzLnB1c2hTZXJ2aWNlID0gdGhpcy5pbmplY3Rvci5nZXQoY29uZmlnLnB1c2gpO1xuICAgIH1cbiAgICBjb25zb2xlLmxvZyh0aGlzLmF1dGhTZXJ2aWNlKTtcbiAgICBjb25zb2xlLmxvZyh0aGlzLnB1c2hTZXJ2aWNlKTtcbiAgfVxuXG4gIGNvbmZpZ09iamVjdDogYW55O1xuXG4gIGluaXRpYWxpemUoY29uZmlnKSB7XG4gICAgdGhpcy5jb25maWdPYmplY3QgPSBjb25maWc7XG4gIH1cblxuICBwcml2YXRlIGRlZmF1bHRNc2dBcnJpdmFsQ2FsbGJhY2sgPSAobWVzc2FnZSkgPT4ge1xuICAgIGlmIChzdHJpbmdpZnkobWVzc2FnZS5zZW5kZXJfdXNlcl9pZCkgaW4gdGhpcy51bnJlYWRNc2dzSWRzUGFpcnMpIHtcbiAgICAgIGlmICh0aGlzLnVucmVhZE1zZ3NJZHNQYWlyc1tzdHJpbmdpZnkobWVzc2FnZS5zZW5kZXJfdXNlcl9pZCldLmluZGV4T2YobWVzc2FnZS5pZCkgPiAtMSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB0aGlzLnVucmVhZE1zZ3NJZHNQYWlyc1tzdHJpbmdpZnkobWVzc2FnZS5zZW5kZXJfdXNlcl9pZCldLnB1c2gobWVzc2FnZS5pZCk7XG4gICAgfSBlbHNlIHsgdGhpcy51bnJlYWRNc2dzSWRzUGFpcnNbc3RyaW5naWZ5KG1lc3NhZ2Uuc2VuZGVyX3VzZXJfaWQpXSA9IFttZXNzYWdlLmlkXTsgfVxuXG4gICAgdGhpcy5pbmNyZW1lbnRUb3RhbFVuUmVhZE1zZ3NDb3VudCgpO1xuICAgIGxldCB1blJlYWRQYWlyc0FycmF5OiBBcnJheTxhbnk+ID0gdGhpcy51blJlYWRNc2dzQ291bnRzQXJyYXlTb3VyY2UuZ2V0VmFsdWUoKTtcbiAgICBjb25zdCBtYXRjaGVkUGFpckluZGV4ID0gdW5SZWFkUGFpcnNBcnJheS5maW5kSW5kZXgoZWwgPT4gZWwuc2VuZGVyX3VzZXJfaWQgPT09IG1lc3NhZ2Uuc2VuZGVyX3VzZXJfaWQpO1xuICAgIGlmKG1hdGNoZWRQYWlySW5kZXggIT09IC0xKVxuICAgICAgdW5SZWFkUGFpcnNBcnJheVttYXRjaGVkUGFpckluZGV4XS5jb3VudCArPSAxO1xuICAgIGVsc2VcbiAgICAgIHVuUmVhZFBhaXJzQXJyYXkucHVzaCh7c2VuZGVyX3VzZXJfaWQ6IG1lc3NhZ2Uuc2VuZGVyX3VzZXJfaWQsIGNvdW50OiAxfSk7XG5cbiAgICB0aGlzLnVuUmVhZE1zZ3NDb3VudHNBcnJheVNvdXJjZS5uZXh0KHVuUmVhZFBhaXJzQXJyYXkpO1xuICAgIGNvbnNvbGUubG9nKHVuUmVhZFBhaXJzQXJyYXkpO1xuICB9O1xuICBzZXRUb3RhbFVuUmVhZE1zZ3NDb3VudChuZXdDb3VudCkge1xuICAgIHRoaXMudG90YWxVblJlYWRNc2dzQ291bnRTb3VyY2UubmV4dChuZXdDb3VudCk7XG4gIH1cblxuICBzZXRVblJlYWRNc2dzQ291bnRzQXJyYXkocGFpcnMpIHtcbiAgICB0aGlzLnVuUmVhZE1zZ3NDb3VudHNBcnJheVNvdXJjZS5uZXh0KHBhaXJzKTtcbiAgfVxuXG4gIGluY3JlbWVudFRvdGFsVW5SZWFkTXNnc0NvdW50KCkge1xuICAgIHRoaXMudG90YWxVblJlYWRNc2dzQ291bnRTb3VyY2UubmV4dCh0aGlzLnRvdGFsVW5SZWFkTXNnc0NvdW50U291cmNlLmdldFZhbHVlKCkrMSk7XG4gIH1cblxuICBsaXN0KG9mZnNldCwgZG9ub3JfaWQ9bnVsbCk6IE9ic2VydmFibGU8YW55PiB7XG4gICAgbGV0IGNoYXRVcmw7XG4gICAgaWYoZG9ub3JfaWQpXG4gICAgICBjaGF0VXJsID0gYCR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfdXJsfSR7ZG9ub3JfaWR9Lz9saW1pdD0ke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3BhZ2Vfc2l6ZX0mb2Zmc2V0PSR7b2Zmc2V0fWA7XG4gICAgZWxzZVxuICAgICAgY2hhdFVybCA9IGAke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3VybH0/bGltaXQ9JHt0aGlzLmNvbmZpZ09iamVjdC5tZXNzYWdlc19wYWdlX3NpemV9Jm9mZnNldD0ke29mZnNldH1gO1xuICAgIHJldHVybiB0aGlzLmh0dHAuZ2V0KGNoYXRVcmwpLnBpcGUobWFwKChyZXNwOiBhbnkpID0+IHtcbiAgICAgIHJldHVybiByZXNwLnJlc3VsdHM7XG4gICAgfSkpXG4gIH1cblxuICBzZW5kX21lc3NhZ2UoY29udGVudCwgZG9ub3JfaWQ9bnVsbCkge1xuICAgIHRoaXMud3Muc2VuZChKU09OLnN0cmluZ2lmeSh7XG4gICAgICBjb250ZW50OmNvbnRlbnQsXG4gICAgICBkb25vcl9pZDogZG9ub3JfaWRcbiAgICB9KSk7XG4gIH1cblxuICBzdGFydExpdmVDaGF0KG9uTWVzc2FnZUNhbGxiYWNrPW51bGwpIHtcbiAgICB0aGlzLmluaXRpYWxpemVVblJlYWRNZXNzYWdlc0NvdW50cygpO1xuICAgIGNvbnN0IG5vdGlmaWNhdGlvbkNCID0gKG1lc3NhZ2UpID0+IHtcbiAgICAgIHRoaXMuZGVmYXVsdE1zZ0Fycml2YWxDYWxsYmFjayhtZXNzYWdlKTtcbiAgICAgIGlmIChvbk1lc3NhZ2VDYWxsYmFjaykge1xuICAgICAgICBvbk1lc3NhZ2VDYWxsYmFjayhtZXNzYWdlKTtcbiAgICAgIH1cbiAgICB9O1xuICAgIGNvbnN0IHNvY2tldENCID0gKGV2ZW50KSA9PiB7XG4gICAgICBjb25zdCBtZXNzYWdlID0gSlNPTi5wYXJzZShldmVudC5kYXRhKS5tZXNzYWdlO1xuICAgICAgbm90aWZpY2F0aW9uQ0IobWVzc2FnZSk7XG4gICAgfTtcblxuICAgIGlmKCF0aGlzLndzIHx8IHRoaXMud3MucmVhZHlTdGF0ZSAhPT0gdGhpcy53cy5PUEVOKVxuICAgICAgdGhpcy5pbml0aWFsaXplQXV0b1JlY29ubmVjdGluZ1dlYlNvY2tldChzb2NrZXRDQik7XG4gICAgZWxzZVxuICAgICAgdGhpcy5zZXRXZWJTb2NrZXRDYWxsYmFja3Moc29ja2V0Q0IpO1xuXG4gICAgaWYgKHRoaXMucHVzaFNlcnZpY2UpIHtcbiAgICAgIHRoaXMuc2V0Tm90aWZpY2F0aW9uQ2FsbGJhY2sobm90aWZpY2F0aW9uQ0IpO1xuICAgIH1cblxuICB9XG5cbiAgaW5pdGlhbGl6ZUF1dG9SZWNvbm5lY3RpbmdXZWJTb2NrZXQob25NZXNzYWdlQ0IpIHtcbiAgICB0aGlzLmNsb3NlTGl2ZUNoYXQoKTtcbiAgICBpZiAoIXRoaXMuYXV0aFNlcnZpY2UuaXNBdXRoZW50aWNhdGVkKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgdG9rZW4gPSB0aGlzLmF1dGhTZXJ2aWNlLmdldFRva2VuKCk7XG4gICAgdGhpcy53cyA9IG5ldyBXZWJTb2NrZXQoYCR7dGhpcy5jb25maWdPYmplY3Quc29ja2V0X3VybH0/dG9rZW49JHt0b2tlbn1gKTtcbiAgICB0aGlzLndzLm9ub3BlbiA9ICgpID0+IHRoaXMuaXNXZWJTb2NrZXRSZWNvbm5lY3RpbmdTb3VyY2UubmV4dChmYWxzZSk7XG4gICAgdGhpcy5zZXRXZWJTb2NrZXRDYWxsYmFja3Mob25NZXNzYWdlQ0IpO1xuICB9XG5cbiAgcHJpdmF0ZSBzZXRXZWJTb2NrZXRDYWxsYmFja3Mob25NZXNzYWdlQ0IpIHtcbiAgICB0aGlzLndzLm9ubWVzc2FnZSA9IG9uTWVzc2FnZUNCO1xuICAgIHRoaXMud3Mub25jbG9zZSA9ICgpID0+IHtcbiAgICAgIHRoaXMuaXNXZWJTb2NrZXRSZWNvbm5lY3RpbmdTb3VyY2UubmV4dCh0cnVlKTtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLmluaXRpYWxpemVBdXRvUmVjb25uZWN0aW5nV2ViU29ja2V0KG9uTWVzc2FnZUNCKTtcbiAgICAgIH0sIDEwMDApO1xuICAgIH07XG4gICAgdGhpcy53cy5vbmVycm9yID0gKGVycm9yKSA9PiB7XG4gICAgICAvLyBUT0RPOiBDaGVjayBpZiBhdXRoZW50aWNhdGlvbiBlcnJvciwgdG8gc3RvcCByZWNvbm5lY3RpbmcgYW5kIGRvIHVuYXV0aGVudGljYXRlZCBzdHVmZlxuICAgICAgdGhpcy53cy5jbG9zZSgpO1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGluaXRpYWxpemVVblJlYWRNZXNzYWdlc0NvdW50cygpIHtcbiAgICB0aGlzLmh0dHAuZ2V0KGAke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3VybH11bnJlYWRfbWVzc2FnZXNfY291bnQvYClcbiAgICAgIC5zdWJzY3JpYmUoKGNvdW50UGFpcnM6IGFueVtdKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0VW5SZWFkTXNnc0NvdW50c0FycmF5KGNvdW50UGFpcnMpO1xuICAgICAgICBsZXQgdG90YWxDb3VudCA9IDA7XG4gICAgICAgIGNvdW50UGFpcnMuZm9yRWFjaCgocGFpcikgPT4ge1xuICAgICAgICAgIHRvdGFsQ291bnQgKz0gcGFpci5jb3VudDtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc2V0VG90YWxVblJlYWRNc2dzQ291bnQodG90YWxDb3VudCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHNldE5vdGlmaWNhdGlvbkNhbGxiYWNrKG9uTWVzc2FnZUNhbGxiYWNrKSB7XG4gICAgY29uc3Qgbm90aWZpY2F0aW9uQ0IgPSAobm90aWZpY2F0aW9uKSA9PiB7XG4gICAgICAvLyBUaGUgZm9sbG93aW5nIGNvbW1lbnRlZCBjb2RlIHdhcyBjb21tZW50ZWQgYXMgdGhlIHdzLnJlYWR5c3RhdGUgaW4gbW9zdCB0aW1lcyB3aGlsZSBhcHAgaW4gYmFja2dyb3VuZCBkb2Vzbid0XG4gICAgICAvLyBkZXRlY3QgdGhhdCBzb2NrZXQgaXMgbm90IGFjdGl2ZSBhbnltb3JlISBTbyB0aGUgaWYgc3RhdGVtZW50IHdvdWxkIGJlIHRydWUgYW5kIG5vdGlmaWNhdGlvbiBoYW5kbGVyIHJldHVybnNcbiAgICAgIC8vIHdpdGhvdXQgZG9pbmcgYW55dGhpbmcsIGFsdGhvdWdoIHRoZSBzb2NrZXQgaXMgbm90IGRvaW5nIGl0cyBqb2IhIFdlIG1vdmVkIGF2b2lkaW5nIGR1cGxpY2F0aW9uIHRvIHRoZVxuICAgICAgLy8gY29tcG9uZW50IGNhbGxiYWNrIGl0c2VsZiB1c2luZyBtZXNzYWdlIGlkXG5cbiAgICAgIC8vIGlmKHRoaXMud3MucmVhZHlTdGF0ZSA9PT0gdGhpcy53cy5PUEVOKVxuICAgICAgLy8gICByZXR1cm47XG5cbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSBub3RpZmljYXRpb24uYWRkaXRpb25hbERhdGEubWVzc2FnZV9kaWN0O1xuICAgICAgb25NZXNzYWdlQ2FsbGJhY2sobWVzc2FnZSk7XG4gICAgfTtcblxuICAgIC8vIFdlIGNvbW1lbnRlZCB0aGUgZm9sbG93aW5nIGNvZGUgYW5kIGluc3RlYWQgc2V0IGRpcmVjdGx5IG5vdGlmaWNhdGlvbiBjYWxsYmFjayBhbmQgY2hlY2sgaW5zaWRlIGl0IHdoaWxlIHRoZVxuICAgIC8vIHdlYnNvY2tldCBpcyBjbG9zZWQgb3Igbm90LCBhcyBzb21ldGltZXMgKGluIGlPUykgb25jbG9zZSBpcyBub3QgY2FsbGVkIHdoZW4gdGhlIHNvY2tldCBpcyBkb3duIGluIGJhY2tncm91bmQgYXBwXG4gICAgLy8gbW9kZSwgc28gaXNXZWJTb2NrZXRSZWNvbm5lY3Rpbmcgd2lsbCBub3QgdXBkYXRlXG5cbiAgICAvLyBsZXQgc2VsZiA9IHRoaXM7XG4gICAgLy8gdGhpcy5ub3RpZmljYXRpb25DYWxsYmFja1N1YnNjcmlwdGlvbiA9IHRoaXMuaXNXZWJTb2NrZXRSZWNvbm5lY3Rpbmcuc3Vic2NyaWJlKHtcbiAgICAvLyAgIG5leHQoaXNDbG9zZWQpIHtcbiAgICAvLyAgICAgaWYoaXNDbG9zZWQpXG4gICAgLy8gICAgICAgc2VsZi5wdXNoU2VydmljZS5zZXROb3RpZmljYXRpb25DYWxsYmFjayhub3RpZmljYXRpb25DQik7XG4gICAgLy8gICAgIGVsc2Ugc2VsZi5wdXNoU2VydmljZS5yZW1vdmVOb3RpZmljYXRpb25DYWxsYmFjayhub3RpZmljYXRpb25DQik7XG4gICAgLy8gICB9LFxuICAgIC8vIH0pO1xuICAgIHRoaXMucHVzaFNlcnZpY2Uuc2V0Tm90aWZpY2F0aW9uQ2FsbGJhY2sobm90aWZpY2F0aW9uQ0IpO1xuICB9XG5cbiAgcmVtb3ZlT25NZXNzYWdlTGlzdGVuZXIoKSB7XG4gICAgaWYgKHRoaXMud3MpIHtcbiAgICAgIHRoaXMud3Mub25tZXNzYWdlID0gdGhpcy5kZWZhdWx0TXNnQXJyaXZhbENhbGxiYWNrO1xuICAgIH1cbiAgICBpZiAodGhpcy5wdXNoU2VydmljZSkge1xuICAgICAgdGhpcy5wdXNoU2VydmljZS5zZXROb3RpZmljYXRpb25DYWxsYmFjayh0aGlzLmRlZmF1bHRNc2dBcnJpdmFsQ2FsbGJhY2spO1xuICAgIH1cbiAgfVxuXG4gIGNsb3NlTGl2ZUNoYXQoKSB7XG4gICAgaWYoIXRoaXMud3MpIHJldHVybjtcbiAgICB0aGlzLndzLm9uY2xvc2UgPSAoZXZlbnQpID0+IHtcbiAgICAgIGRlbGV0ZSB0aGlzLndzO1xuICAgIH07XG4gICAgdGhpcy53cy5jbG9zZSgpO1xuICB9XG5cbiAgcmVhZEFsbChkb25vcl9pZD1udWxsKSB7XG4gICAgbGV0IHJlYWRBbGxVcmw7XG4gICAgaWYoZG9ub3JfaWQpIHJlYWRBbGxVcmwgPSBgJHt0aGlzLmNvbmZpZ09iamVjdC5tZXNzYWdlc191cmx9JHtkb25vcl9pZH0vcmVhZF9hbGwvYDtcbiAgICBlbHNlIHJlYWRBbGxVcmwgPSBgJHt0aGlzLmNvbmZpZ09iamVjdC5tZXNzYWdlc191cmx9cmVhZF9hbGwvYDtcbiAgICByZXR1cm4gdGhpcy5odHRwLnBhdGNoKHJlYWRBbGxVcmwsIHt9KVxuICAgICAgLnBpcGUodGFwKGV2ZW50ID0+IHRoaXMuc2V0VG90YWxVblJlYWRNc2dzQ291bnQoMCkpKTtcbiAgfVxuXG4gIHVucmVhZExhdGVzdChkb25vcl9pZCkge1xuICAgIHJldHVybiB0aGlzLmh0dHAucGF0Y2goYCR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfdXJsfSR7ZG9ub3JfaWR9L3VucmVhZF9sYXRlc3QvYCwge30pO1xuICB9XG59XG4iXX0=