UNPKG

zoriakinc-messaging

Version:

Angular Messaging Module

392 lines 32.1 kB
/** * @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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnaW5nLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly96b3JpYWtpbmMtbWVzc2FnaW5nLyIsInNvdXJjZXMiOlsibGliL2NoYXQtYm94L21lc3NhZ2luZy5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsT0FBTyxFQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQzNELE9BQU8sRUFBYSxlQUFlLEVBQWUsTUFBTSxNQUFNLENBQUM7QUFDL0QsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQ2hELE9BQU8sRUFBQyxHQUFHLEVBQUUsR0FBRyxFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLGFBQWEsQ0FBQzs7O0FBS3RDLE1BQU0sT0FBTyxnQkFBZ0I7Ozs7OztJQW9CM0IsWUFBb0IsSUFBZ0IsRUFBVyxRQUFrQixFQUE0QixNQUFXO1FBQXBGLFNBQUksR0FBSixJQUFJLENBQVk7UUFBVyxhQUFRLEdBQVIsUUFBUSxDQUFVO1FBQTRCLFdBQU0sR0FBTixNQUFNLENBQUs7UUFiaEcsK0JBQTBCLEdBQUcsSUFBSSxlQUFlLENBQU0sQ0FBQyxDQUFDLENBQUM7UUFDMUQseUJBQW9CLEdBQUcsSUFBSSxDQUFDLDBCQUEwQixDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXJFLGdDQUEyQixHQUFHLElBQUksZUFBZSxDQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQzVELDBCQUFxQixHQUFHLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUV2RSx1QkFBa0IsR0FBRyxFQUFFLENBQUM7UUFFeEIsa0NBQTZCLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDckUsNEJBQXVCLEdBQUcsSUFBSSxDQUFDLDZCQUE2QixDQUFDLFlBQVksRUFBRSxDQUFDO1FBcUIzRSw4QkFBeUI7Ozs7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LENBQUMsQ0FBQztJQUN6RCxDQUFDOzs7OztJQUVELFlBQVksQ0FBQyxRQUFRO1FBQ25CLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksR0FBRyxRQUFRLGlCQUFpQixFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzVGLENBQUM7OztZQTlNRixVQUFVLFNBQUM7Z0JBQ1YsVUFBVSxFQUFFLE1BQU07YUFDbkI7Ozs7WUFOTyxVQUFVO1lBRlUsUUFBUTs0Q0E2QmtDLE1BQU0sU0FBQyxRQUFROzs7OztJQWxCbkYsdUNBQWlCOztJQUNqQix1Q0FBaUI7O0lBRWpCLDhCQUFjOzs7OztJQUVkLHNEQUFpRTs7SUFDakUsZ0RBQTZFOzs7OztJQUU3RSx1REFBbUU7O0lBQ25FLGlEQUErRTs7Ozs7SUFFL0UsOENBQWdDOzs7OztJQUVoQyx5REFBNEU7O0lBQzVFLG1EQUFtRjs7SUFFbkYsNERBQStDOztJQWEvQyx3Q0FBa0I7Ozs7O0lBTWxCLHFEQWtCRTs7Ozs7SUFuQ1UsZ0NBQXdCOzs7OztJQUFFLG9DQUEyQjs7Ozs7SUFBRSxrQ0FBcUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0luamVjdCwgSW5qZWN0YWJsZSwgSW5qZWN0b3J9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtPYnNlcnZhYmxlLCBCZWhhdmlvclN1YmplY3QsIFN1YnNjcmlwdGlvbn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge0h0dHBDbGllbnR9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7dGFwLCBtYXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7c3RyaW5naWZ5fSBmcm9tICdxdWVyeXN0cmluZyc7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE1lc3NhZ2luZ1NlcnZpY2Uge1xuXG4gIGF1dGhTZXJ2aWNlOiBhbnk7XG4gIHB1c2hTZXJ2aWNlOiBhbnk7XG5cbiAgd3M6IFdlYlNvY2tldDtcblxuICBwcml2YXRlIHRvdGFsVW5SZWFkTXNnc0NvdW50U291cmNlID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KDApO1xuICBwdWJsaWMgdG90YWxVblJlYWRNc2dzQ291bnQgPSB0aGlzLnRvdGFsVW5SZWFkTXNnc0NvdW50U291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIHByaXZhdGUgdW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KFtdKTtcbiAgcHVibGljIHVuUmVhZE1zZ3NDb3VudHNBcnJheSA9IHRoaXMudW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIHByaXZhdGUgdW5yZWFkTXNnc0lkc1BhaXJzID0ge307XG5cbiAgcHJpdmF0ZSBpc1dlYlNvY2tldFJlY29ubmVjdGluZ1NvdXJjZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4oZmFsc2UpO1xuICBwdWJsaWMgaXNXZWJTb2NrZXRSZWNvbm5lY3RpbmcgPSB0aGlzLmlzV2ViU29ja2V0UmVjb25uZWN0aW5nU291cmNlLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIG5vdGlmaWNhdGlvbkNhbGxiYWNrU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LCBwcml2YXRlICBpbmplY3RvcjogSW5qZWN0b3IsIEBJbmplY3QoJ2NvbmZpZycpIHByaXZhdGUgY29uZmlnOiBhbnkpIHtcbiAgICBjb25zb2xlLmxvZygnaW5zaWRlIHNlcnZpY2U6ICcsIGNvbmZpZyk7XG4gICAgdGhpcy5jb25maWdPYmplY3QgPSBjb25maWc7XG4gICAgdGhpcy5hdXRoU2VydmljZSA9IHRoaXMuaW5qZWN0b3IuZ2V0KGNvbmZpZy5hdXRoKTtcbiAgICBpZiAoY29uZmlnLnB1c2gpIHtcbiAgICAgIHRoaXMucHVzaFNlcnZpY2UgPSB0aGlzLmluamVjdG9yLmdldChjb25maWcucHVzaCk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKHRoaXMuYXV0aFNlcnZpY2UpO1xuICAgIGNvbnNvbGUubG9nKHRoaXMucHVzaFNlcnZpY2UpO1xuICB9XG5cbiAgY29uZmlnT2JqZWN0OiBhbnk7XG5cbiAgaW5pdGlhbGl6ZShjb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZ09iamVjdCA9IGNvbmZpZztcbiAgfVxuXG4gIHByaXZhdGUgZGVmYXVsdE1zZ0Fycml2YWxDYWxsYmFjayA9IChtZXNzYWdlKSA9PiB7XG4gICAgaWYgKHN0cmluZ2lmeShtZXNzYWdlLnNlbmRlcl91c2VyX2lkKSBpbiB0aGlzLnVucmVhZE1zZ3NJZHNQYWlycykge1xuICAgICAgaWYgKHRoaXMudW5yZWFkTXNnc0lkc1BhaXJzW3N0cmluZ2lmeShtZXNzYWdlLnNlbmRlcl91c2VyX2lkKV0uaW5kZXhPZihtZXNzYWdlLmlkKSA+IC0xKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRoaXMudW5yZWFkTXNnc0lkc1BhaXJzW3N0cmluZ2lmeShtZXNzYWdlLnNlbmRlcl91c2VyX2lkKV0ucHVzaChtZXNzYWdlLmlkKTtcbiAgICB9IGVsc2UgeyB0aGlzLnVucmVhZE1zZ3NJZHNQYWlyc1tzdHJpbmdpZnkobWVzc2FnZS5zZW5kZXJfdXNlcl9pZCldID0gW21lc3NhZ2UuaWRdOyB9XG5cbiAgICB0aGlzLmluY3JlbWVudFRvdGFsVW5SZWFkTXNnc0NvdW50KCk7XG4gICAgbGV0IHVuUmVhZFBhaXJzQXJyYXk6IEFycmF5PGFueT4gPSB0aGlzLnVuUmVhZE1zZ3NDb3VudHNBcnJheVNvdXJjZS5nZXRWYWx1ZSgpO1xuICAgIGNvbnN0IG1hdGNoZWRQYWlySW5kZXggPSB1blJlYWRQYWlyc0FycmF5LmZpbmRJbmRleChlbCA9PiBlbC5zZW5kZXJfdXNlcl9pZCA9PT0gbWVzc2FnZS5zZW5kZXJfdXNlcl9pZCk7XG4gICAgaWYobWF0Y2hlZFBhaXJJbmRleCAhPT0gLTEpXG4gICAgICB1blJlYWRQYWlyc0FycmF5W21hdGNoZWRQYWlySW5kZXhdLmNvdW50ICs9IDE7XG4gICAgZWxzZVxuICAgICAgdW5SZWFkUGFpcnNBcnJheS5wdXNoKHtzZW5kZXJfdXNlcl9pZDogbWVzc2FnZS5zZW5kZXJfdXNlcl9pZCwgY291bnQ6IDF9KTtcblxuICAgIHRoaXMudW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlLm5leHQodW5SZWFkUGFpcnNBcnJheSk7XG4gICAgY29uc29sZS5sb2codW5SZWFkUGFpcnNBcnJheSk7XG4gIH07XG4gIHNldFRvdGFsVW5SZWFkTXNnc0NvdW50KG5ld0NvdW50KSB7XG4gICAgdGhpcy50b3RhbFVuUmVhZE1zZ3NDb3VudFNvdXJjZS5uZXh0KG5ld0NvdW50KTtcbiAgfVxuXG4gIHNldFVuUmVhZE1zZ3NDb3VudHNBcnJheShwYWlycykge1xuICAgIHRoaXMudW5SZWFkTXNnc0NvdW50c0FycmF5U291cmNlLm5leHQocGFpcnMpO1xuICB9XG5cbiAgaW5jcmVtZW50VG90YWxVblJlYWRNc2dzQ291bnQoKSB7XG4gICAgdGhpcy50b3RhbFVuUmVhZE1zZ3NDb3VudFNvdXJjZS5uZXh0KHRoaXMudG90YWxVblJlYWRNc2dzQ291bnRTb3VyY2UuZ2V0VmFsdWUoKSsxKTtcbiAgfVxuXG4gIGxpc3Qob2Zmc2V0LCBkb25vcl9pZD1udWxsKTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICBsZXQgY2hhdFVybDtcbiAgICBpZihkb25vcl9pZClcbiAgICAgIGNoYXRVcmwgPSBgJHt0aGlzLmNvbmZpZ09iamVjdC5tZXNzYWdlc191cmx9JHtkb25vcl9pZH0vP2xpbWl0PSR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfcGFnZV9zaXplfSZvZmZzZXQ9JHtvZmZzZXR9YDtcbiAgICBlbHNlXG4gICAgICBjaGF0VXJsID0gYCR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfdXJsfT9saW1pdD0ke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3BhZ2Vfc2l6ZX0mb2Zmc2V0PSR7b2Zmc2V0fWA7XG4gICAgcmV0dXJuIHRoaXMuaHR0cC5nZXQoY2hhdFVybCkucGlwZShtYXAoKHJlc3A6IGFueSkgPT4ge1xuICAgICAgcmV0dXJuIHJlc3AucmVzdWx0cztcbiAgICB9KSlcbiAgfVxuXG4gIHNlbmRfbWVzc2FnZShjb250ZW50LCBkb25vcl9pZD1udWxsKSB7XG4gICAgdGhpcy53cy5zZW5kKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIGNvbnRlbnQ6Y29udGVudCxcbiAgICAgIGRvbm9yX2lkOiBkb25vcl9pZFxuICAgIH0pKTtcbiAgfVxuXG4gIHN0YXJ0TGl2ZUNoYXQob25NZXNzYWdlQ2FsbGJhY2s9bnVsbCkge1xuICAgIHRoaXMuaW5pdGlhbGl6ZVVuUmVhZE1lc3NhZ2VzQ291bnRzKCk7XG4gICAgY29uc3Qgbm90aWZpY2F0aW9uQ0IgPSAobWVzc2FnZSkgPT4ge1xuICAgICAgdGhpcy5kZWZhdWx0TXNnQXJyaXZhbENhbGxiYWNrKG1lc3NhZ2UpO1xuICAgICAgaWYgKG9uTWVzc2FnZUNhbGxiYWNrKSB7XG4gICAgICAgIG9uTWVzc2FnZUNhbGxiYWNrKG1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH07XG4gICAgY29uc3Qgc29ja2V0Q0IgPSAoZXZlbnQpID0+IHtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpLm1lc3NhZ2U7XG4gICAgICBub3RpZmljYXRpb25DQihtZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgaWYoIXRoaXMud3MgfHwgdGhpcy53cy5yZWFkeVN0YXRlICE9PSB0aGlzLndzLk9QRU4pXG4gICAgICB0aGlzLmluaXRpYWxpemVBdXRvUmVjb25uZWN0aW5nV2ViU29ja2V0KHNvY2tldENCKTtcbiAgICBlbHNlXG4gICAgICB0aGlzLnNldFdlYlNvY2tldENhbGxiYWNrcyhzb2NrZXRDQik7XG5cbiAgICBpZiAodGhpcy5wdXNoU2VydmljZSkge1xuICAgICAgdGhpcy5zZXROb3RpZmljYXRpb25DYWxsYmFjayhub3RpZmljYXRpb25DQik7XG4gICAgfVxuXG4gIH1cblxuICBpbml0aWFsaXplQXV0b1JlY29ubmVjdGluZ1dlYlNvY2tldChvbk1lc3NhZ2VDQikge1xuICAgIHRoaXMuY2xvc2VMaXZlQ2hhdCgpO1xuICAgIGlmICghdGhpcy5hdXRoU2VydmljZS5pc0F1dGhlbnRpY2F0ZWQoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCB0b2tlbiA9IHRoaXMuYXV0aFNlcnZpY2UuZ2V0VG9rZW4oKTtcbiAgICB0aGlzLndzID0gbmV3IFdlYlNvY2tldChgJHt0aGlzLmNvbmZpZ09iamVjdC5zb2NrZXRfdXJsfT90b2tlbj0ke3Rva2VufWApO1xuICAgIHRoaXMud3Mub25vcGVuID0gKCkgPT4gdGhpcy5pc1dlYlNvY2tldFJlY29ubmVjdGluZ1NvdXJjZS5uZXh0KGZhbHNlKTtcbiAgICB0aGlzLnNldFdlYlNvY2tldENhbGxiYWNrcyhvbk1lc3NhZ2VDQik7XG4gIH1cblxuICBwcml2YXRlIHNldFdlYlNvY2tldENhbGxiYWNrcyhvbk1lc3NhZ2VDQikge1xuICAgIHRoaXMud3Mub25tZXNzYWdlID0gb25NZXNzYWdlQ0I7XG4gICAgdGhpcy53cy5vbmNsb3NlID0gKCkgPT4ge1xuICAgICAgdGhpcy5pc1dlYlNvY2tldFJlY29ubmVjdGluZ1NvdXJjZS5uZXh0KHRydWUpO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZUF1dG9SZWNvbm5lY3RpbmdXZWJTb2NrZXQob25NZXNzYWdlQ0IpO1xuICAgICAgfSwgMTAwMCk7XG4gICAgfTtcbiAgICB0aGlzLndzLm9uZXJyb3IgPSAoZXJyb3IpID0+IHtcbiAgICAgIC8vIFRPRE86IENoZWNrIGlmIGF1dGhlbnRpY2F0aW9uIGVycm9yLCB0byBzdG9wIHJlY29ubmVjdGluZyBhbmQgZG8gdW5hdXRoZW50aWNhdGVkIHN0dWZmXG4gICAgICB0aGlzLndzLmNsb3NlKCk7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgaW5pdGlhbGl6ZVVuUmVhZE1lc3NhZ2VzQ291bnRzKCkge1xuICAgIHRoaXMuaHR0cC5nZXQoYCR7dGhpcy5jb25maWdPYmplY3QubWVzc2FnZXNfdXJsfXVucmVhZF9tZXNzYWdlc19jb3VudC9gKVxuICAgICAgLnN1YnNjcmliZSgoY291bnRQYWlyczogYW55W10pID0+IHtcbiAgICAgICAgdGhpcy5zZXRVblJlYWRNc2dzQ291bnRzQXJyYXkoY291bnRQYWlycyk7XG4gICAgICAgIGxldCB0b3RhbENvdW50ID0gMDtcbiAgICAgICAgY291bnRQYWlycy5mb3JFYWNoKChwYWlyKSA9PiB7XG4gICAgICAgICAgdG90YWxDb3VudCArPSBwYWlyLmNvdW50O1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRUb3RhbFVuUmVhZE1zZ3NDb3VudCh0b3RhbENvdW50KTtcbiAgICAgIH0pO1xuICB9XG5cbiAgc2V0Tm90aWZpY2F0aW9uQ2FsbGJhY2sob25NZXNzYWdlQ2FsbGJhY2spIHtcbiAgICBjb25zdCBub3RpZmljYXRpb25DQiA9IChub3RpZmljYXRpb24pID0+IHtcbiAgICAgIC8vIFRoZSBmb2xsb3dpbmcgY29tbWVudGVkIGNvZGUgd2FzIGNvbW1lbnRlZCBhcyB0aGUgd3MucmVhZHlzdGF0ZSBpbiBtb3N0IHRpbWVzIHdoaWxlIGFwcCBpbiBiYWNrZ3JvdW5kIGRvZXNuJ3RcbiAgICAgIC8vIGRldGVjdCB0aGF0IHNvY2tldCBpcyBub3QgYWN0aXZlIGFueW1vcmUhIFNvIHRoZSBpZiBzdGF0ZW1lbnQgd291bGQgYmUgdHJ1ZSBhbmQgbm90aWZpY2F0aW9uIGhhbmRsZXIgcmV0dXJuc1xuICAgICAgLy8gd2l0aG91dCBkb2luZyBhbnl0aGluZywgYWx0aG91Z2ggdGhlIHNvY2tldCBpcyBub3QgZG9pbmcgaXRzIGpvYiEgV2UgbW92ZWQgYXZvaWRpbmcgZHVwbGljYXRpb24gdG8gdGhlXG4gICAgICAvLyBjb21wb25lbnQgY2FsbGJhY2sgaXRzZWxmIHVzaW5nIG1lc3NhZ2UgaWRcblxuICAgICAgLy8gaWYodGhpcy53cy5yZWFkeVN0YXRlID09PSB0aGlzLndzLk9QRU4pXG4gICAgICAvLyAgIHJldHVybjtcblxuICAgICAgY29uc3QgbWVzc2FnZSA9IG5vdGlmaWNhdGlvbi5hZGRpdGlvbmFsRGF0YS5tZXNzYWdlX2RpY3Q7XG4gICAgICBvbk1lc3NhZ2VDYWxsYmFjayhtZXNzYWdlKTtcbiAgICB9O1xuXG4gICAgLy8gV2UgY29tbWVudGVkIHRoZSBmb2xsb3dpbmcgY29kZSBhbmQgaW5zdGVhZCBzZXQgZGlyZWN0bHkgbm90aWZpY2F0aW9uIGNhbGxiYWNrIGFuZCBjaGVjayBpbnNpZGUgaXQgd2hpbGUgdGhlXG4gICAgLy8gd2Vic29ja2V0IGlzIGNsb3NlZCBvciBub3QsIGFzIHNvbWV0aW1lcyAoaW4gaU9TKSBvbmNsb3NlIGlzIG5vdCBjYWxsZWQgd2hlbiB0aGUgc29ja2V0IGlzIGRvd24gaW4gYmFja2dyb3VuZCBhcHBcbiAgICAvLyBtb2RlLCBzbyBpc1dlYlNvY2tldFJlY29ubmVjdGluZyB3aWxsIG5vdCB1cGRhdGVcblxuICAgIC8vIGxldCBzZWxmID0gdGhpcztcbiAgICAvLyB0aGlzLm5vdGlmaWNhdGlvbkNhbGxiYWNrU3Vic2NyaXB0aW9uID0gdGhpcy5pc1dlYlNvY2tldFJlY29ubmVjdGluZy5zdWJzY3JpYmUoe1xuICAgIC8vICAgbmV4dChpc0Nsb3NlZCkge1xuICAgIC8vICAgICBpZihpc0Nsb3NlZClcbiAgICAvLyAgICAgICBzZWxmLnB1c2hTZXJ2aWNlLnNldE5vdGlmaWNhdGlvbkNhbGxiYWNrKG5vdGlmaWNhdGlvbkNCKTtcbiAgICAvLyAgICAgZWxzZSBzZWxmLnB1c2hTZXJ2aWNlLnJlbW92ZU5vdGlmaWNhdGlvbkNhbGxiYWNrKG5vdGlmaWNhdGlvbkNCKTtcbiAgICAvLyAgIH0sXG4gICAgLy8gfSk7XG4gICAgdGhpcy5wdXNoU2VydmljZS5zZXROb3RpZmljYXRpb25DYWxsYmFjayhub3RpZmljYXRpb25DQik7XG4gIH1cblxuICByZW1vdmVPbk1lc3NhZ2VMaXN0ZW5lcigpIHtcbiAgICBpZiAodGhpcy53cykge1xuICAgICAgdGhpcy53cy5vbm1lc3NhZ2UgPSB0aGlzLmRlZmF1bHRNc2dBcnJpdmFsQ2FsbGJhY2s7XG4gICAgfVxuICAgIGlmICh0aGlzLnB1c2hTZXJ2aWNlKSB7XG4gICAgICB0aGlzLnB1c2hTZXJ2aWNlLnNldE5vdGlmaWNhdGlvbkNhbGxiYWNrKHRoaXMuZGVmYXVsdE1zZ0Fycml2YWxDYWxsYmFjayk7XG4gICAgfVxuICB9XG5cbiAgY2xvc2VMaXZlQ2hhdCgpIHtcbiAgICBpZighdGhpcy53cykgcmV0dXJuO1xuICAgIHRoaXMud3Mub25jbG9zZSA9IChldmVudCkgPT4ge1xuICAgICAgZGVsZXRlIHRoaXMud3M7XG4gICAgfTtcbiAgICB0aGlzLndzLmNsb3NlKCk7XG4gIH1cblxuICByZWFkQWxsKGRvbm9yX2lkPW51bGwpIHtcbiAgICBsZXQgcmVhZEFsbFVybDtcbiAgICBpZihkb25vcl9pZCkgcmVhZEFsbFVybCA9IGAke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3VybH0ke2Rvbm9yX2lkfS9yZWFkX2FsbC9gO1xuICAgIGVsc2UgcmVhZEFsbFVybCA9IGAke3RoaXMuY29uZmlnT2JqZWN0Lm1lc3NhZ2VzX3VybH1yZWFkX2FsbC9gO1xuICAgIHJldHVybiB0aGlzLmh0dHAucGF0Y2gocmVhZEFsbFVybCwge30pXG4gICAgICAucGlwZSh0YXAoZXZlbnQgPT4gdGhpcy5zZXRUb3RhbFVuUmVhZE1zZ3NDb3VudCgwKSkpO1xuICB9XG5cbiAgdW5yZWFkTGF0ZXN0KGRvbm9yX2lkKSB7XG4gICAgcmV0dXJuIHRoaXMuaHR0cC5wYXRjaChgJHt0aGlzLmNvbmZpZ09iamVjdC5tZXNzYWdlc191cmx9JHtkb25vcl9pZH0vdW5yZWFkX2xhdGVzdC9gLCB7fSk7XG4gIH1cbn1cbiJdfQ==