UNPKG

ngx-logger

Version:

[![npm version](https://badge.fury.io/js/ngx-logger.svg)](https://www.npmjs.com/package/ngx-logger)

238 lines 31.8 kB
import { HttpHeaders, HttpParams, HttpRequest, HttpResponse } from '@angular/common/http'; import { Injectable, Optional } from '@angular/core'; import { BehaviorSubject, isObservable, of, throwError, timer } from 'rxjs'; import { catchError, concatMap, filter, map, take } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common/http"; export class NGXLoggerServerService { constructor(httpBackend, ngZone) { this.httpBackend = httpBackend; this.ngZone = ngZone; this.serverCallsQueue = []; this.flushingQueue = new BehaviorSubject(false); } ngOnDestroy() { if (this.flushingQueue) { this.flushingQueue.complete(); this.flushingQueue = null; } if (this.addToQueueTimer) { this.addToQueueTimer.unsubscribe(); this.addToQueueTimer = null; } } /** * Transforms an error object into a readable string (taking only the stack) * This is needed because JSON.stringify would return "{}" * @param err the error object * @returns The stack of the error */ secureErrorObject(err) { return err?.stack; } /** * Transforms the additional parameters to avoid any json error when sending the data to the server * Basically it just replaces unstringifiable object to a string mentioning an error * @param additional The additional data to be sent * @returns The additional data secured */ secureAdditionalParameters(additional) { if (additional === null || additional === undefined) { return null; } return additional.map((next, idx) => { try { if (next instanceof Error) { return this.secureErrorObject(next); } // We just want to make sure the JSON can be parsed, we do not want to actually change the type if (typeof next === 'object') { JSON.stringify(next); } return next; } catch (e) { return `The additional[${idx}] value could not be parsed using JSON.stringify().`; } }); } /** * Transforms the message so that it can be sent to the server * @param message the message to be sent * @returns the message secured */ secureMessage(message) { try { if (message instanceof Error) { return this.secureErrorObject(message); } if (typeof message !== 'string') { message = JSON.stringify(message, null, 2); } } catch (e) { message = 'The provided "message" value could not be parsed with JSON.stringify().'; } return message; } /** * Edits HttpRequest object before sending request to server * @param httpRequest default request object * @returns altered httprequest */ alterHttpRequest(httpRequest) { return httpRequest; } /** * Sends request to server * @param url * @param logContent * @param options * @returns */ logOnServer(url, logContent, options) { if (!this.httpBackend) { console.error('NGXLogger : Can\'t log on server because HttpBackend is not provided. You need to import HttpClientModule'); return of(null); } // HttpBackend skips all HttpInterceptors // They may log errors using this service causing circular calls let defaultRequest = new HttpRequest('POST', url, logContent, options || {}); let finalRequest = of(defaultRequest); const alteredRequest = this.alterHttpRequest(defaultRequest); if (isObservable(alteredRequest)) { finalRequest = alteredRequest; } else if (alteredRequest) { finalRequest = of(alteredRequest); } else { console.warn('NGXLogger : alterHttpRequest returned an invalid request. Using default one instead'); } return finalRequest.pipe(concatMap(req => { if (!req) { console.warn('NGXLogger : alterHttpRequest returned an invalid request (observable). Using default one instead'); return this.httpBackend.handle(defaultRequest); } return this.httpBackend.handle(req); }), filter(e => e instanceof HttpResponse), map((httpResponse) => httpResponse.body)); } /** * Customise the data sent to the API * @param metadata the data provided by NGXLogger * @returns the data that will be sent to the API in the body */ customiseRequestBody(metadata) { // In our API the body is not customised return metadata; } /** * Flush the queue of the logger * @param config */ flushQueue(config) { this.flushingQueue.next(true); // If a timer was set, we cancel it because the queue is flushed if (this.addToQueueTimer) { this.addToQueueTimer.unsubscribe(); this.addToQueueTimer = null; } if (!!this.serverCallsQueue && this.serverCallsQueue.length > 0) { this.sendToServerAction(this.serverCallsQueue, config); } this.serverCallsQueue = []; this.flushingQueue.next(false); } sendToServerAction(metadata, config) { let requestBody; const secureMetadata = (pMetadata) => { // Copying metadata locally because we don't want to change the object for the caller const securedMetadata = { ...pMetadata }; securedMetadata.additional = this.secureAdditionalParameters(securedMetadata.additional); securedMetadata.message = this.secureMessage(securedMetadata.message); return securedMetadata; }; if (Array.isArray(metadata)) { requestBody = []; metadata.forEach(m => { requestBody.push(secureMetadata(m)); }); } else { requestBody = secureMetadata(metadata); } // Allow users to customise the data sent to the API requestBody = this.customiseRequestBody(requestBody); const headers = config.customHttpHeaders || new HttpHeaders(); if (!headers.has('Content-Type')) { headers.set('Content-Type', 'application/json'); } const logOnServerAction = () => { this.logOnServer(config.serverLoggingUrl, requestBody, { headers, params: config.customHttpParams || new HttpParams(), responseType: config.httpResponseType || 'json', withCredentials: config.withCredentials || false, }).pipe(catchError(err => { // Do not use NGXLogger here because this could cause an infinite loop console.error('NGXLogger: Failed to log on server', err); return throwError(err); })).subscribe(); }; if (config.serverCallsOutsideNgZone === true) { if (!this.ngZone) { console.error('NGXLogger: NgZone is not provided and serverCallsOutsideNgZone is set to true'); return; } this.ngZone.runOutsideAngular(logOnServerAction); } else { logOnServerAction(); } } /** * Sends the content to be logged to the server according to the config * @param metadata * @param config */ sendToServer(metadata, config) { // If there is no batch mode in the config, we send the log call straight to the server as usual if ((!config.serverCallsBatchSize || config.serverCallsBatchSize <= 0) && (!config.serverCallsTimer || config.serverCallsTimer <= 0)) { this.sendToServerAction(metadata, config); return; } const addLogToQueueAction = () => { this.serverCallsQueue.push({ ...metadata }); // Flush queue when size is reached if (!!config.serverCallsBatchSize && this.serverCallsQueue.length > config.serverCallsBatchSize) { this.flushQueue(config); } // Call timer only if it is in the config and timer is not already running if (config.serverCallsTimer > 0 && !this.addToQueueTimer) { this.addToQueueTimer = timer(config.serverCallsTimer).subscribe(_ => { this.flushQueue(config); }); } }; // If queue is being flushed, we need to wait for it to finish before adding other calls if (this.flushingQueue.value === true) { this.flushingQueue.pipe(filter(fq => fq === false), take(1)).subscribe(_ => { addLogToQueueAction(); }); } else { addLogToQueueAction(); } } } /** @nocollapse */ /** @nocollapse */ NGXLoggerServerService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: NGXLoggerServerService, deps: [{ token: i1.HttpBackend, optional: true }, { token: i0.NgZone, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); /** @nocollapse */ /** @nocollapse */ NGXLoggerServerService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: NGXLoggerServerService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: NGXLoggerServerService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.HttpBackend, decorators: [{ type: Optional }] }, { type: i0.NgZone, decorators: [{ type: Optional }] }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZlci9zZXJ2ZXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWUsV0FBVyxFQUFFLFVBQVUsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdkcsT0FBTyxFQUFFLFVBQVUsRUFBcUIsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxlQUFlLEVBQTRCLFlBQVksRUFBRSxFQUFFLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0RyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFNMUUsTUFBTSxPQUFPLHNCQUFzQjtJQUtqQyxZQUNpQyxXQUF3QixFQUN4QixNQUFjO1FBRGQsZ0JBQVcsR0FBWCxXQUFXLENBQWE7UUFDeEIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQU5yQyxxQkFBZ0IsR0FBeUIsRUFBRSxDQUFDO1FBQzVDLGtCQUFhLEdBQTZCLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBTTNFLENBQUM7SUFFTCxXQUFXO1FBQ1QsSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ3RCLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLENBQUM7U0FDM0I7UUFDRCxJQUFJLElBQUksQ0FBQyxlQUFlLEVBQUU7WUFDeEIsSUFBSSxDQUFDLGVBQWUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNuQyxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQztTQUM3QjtJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNPLGlCQUFpQixDQUFDLEdBQVU7UUFDcEMsT0FBTyxHQUFHLEVBQUUsS0FBSyxDQUFDO0lBQ3BCLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNPLDBCQUEwQixDQUFDLFVBQWlCO1FBQ3BELElBQUksVUFBVSxLQUFLLElBQUksSUFBSSxVQUFVLEtBQUssU0FBUyxFQUFFO1lBQ25ELE9BQU8sSUFBSSxDQUFDO1NBQ2I7UUFFRCxPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxFQUFFLEVBQUU7WUFDbEMsSUFBSTtnQkFDRixJQUFJLElBQUksWUFBWSxLQUFLLEVBQUU7b0JBQ3pCLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUNyQztnQkFDRCwrRkFBK0Y7Z0JBQy9GLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxFQUFFO29CQUM1QixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO2lCQUN0QjtnQkFFRCxPQUFPLElBQUksQ0FBQzthQUNiO1lBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ1YsT0FBTyxrQkFBa0IsR0FBRyxxREFBcUQsQ0FBQzthQUNuRjtRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7O09BSUc7SUFDTyxhQUFhLENBQUMsT0FBWTtRQUNsQyxJQUFJO1lBQ0YsSUFBSSxPQUFPLFlBQVksS0FBSyxFQUFFO2dCQUM1QixPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsQ0FBQzthQUN4QztZQUVELElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFO2dCQUMvQixPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO2FBQzVDO1NBQ0Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE9BQU8sR0FBRyx5RUFBeUUsQ0FBQztTQUNyRjtRQUVELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFRDs7OztPQUlHO0lBQ08sZ0JBQWdCLENBQUMsV0FBNkI7UUFDdEQsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNPLFdBQVcsQ0FDbkIsR0FBVyxFQUNYLFVBQWUsRUFDZixPQU1DO1FBR0QsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDckIsT0FBTyxDQUFDLEtBQUssQ0FBQywyR0FBMkcsQ0FBQyxDQUFDO1lBQzNILE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ2pCO1FBRUQseUNBQXlDO1FBQ3pDLGdFQUFnRTtRQUNoRSxJQUFJLGNBQWMsR0FBRyxJQUFJLFdBQVcsQ0FBTSxNQUFNLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxPQUFPLElBQUksRUFBRSxDQUFDLENBQUM7UUFDbEYsSUFBSSxZQUFZLEdBQWlDLEVBQUUsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUVwRSxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFN0QsSUFBSSxZQUFZLENBQUMsY0FBYyxDQUFDLEVBQUU7WUFDaEMsWUFBWSxHQUFHLGNBQWMsQ0FBQztTQUMvQjthQUFNLElBQUksY0FBYyxFQUFFO1lBQ3pCLFlBQVksR0FBRyxFQUFFLENBQUMsY0FBYyxDQUFDLENBQUM7U0FDbkM7YUFBTTtZQUNMLE9BQU8sQ0FBQyxJQUFJLENBQUMscUZBQXFGLENBQUMsQ0FBQztTQUNyRztRQUVELE9BQU8sWUFBWSxDQUFDLElBQUksQ0FDdEIsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBQ2QsSUFBSSxDQUFDLEdBQUcsRUFBRTtnQkFDUixPQUFPLENBQUMsSUFBSSxDQUFDLGtHQUFrRyxDQUFDLENBQUM7Z0JBQ2pILE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUE7YUFDL0M7WUFDRCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3RDLENBQUMsQ0FBQyxFQUNGLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsWUFBWSxZQUFZLENBQUMsRUFDdEMsR0FBRyxDQUF5QixDQUFDLFlBQStCLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FDcEYsQ0FBQztJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ08sb0JBQW9CLENBQUMsUUFBbUQ7UUFDaEYsd0NBQXdDO1FBQ3hDLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxVQUFVLENBQUMsTUFBd0I7UUFDeEMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFOUIsZ0VBQWdFO1FBQ2hFLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUN4QixJQUFJLENBQUMsZUFBZSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDO1NBQzdCO1FBRUQsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLGdCQUFnQixJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQy9ELElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsTUFBTSxDQUFDLENBQUM7U0FDeEQ7UUFDRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBRTNCLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFUyxrQkFBa0IsQ0FBQyxRQUFtRCxFQUFFLE1BQXdCO1FBQ3hHLElBQUksV0FBZ0IsQ0FBQztRQUVyQixNQUFNLGNBQWMsR0FBRyxDQUFDLFNBQTZCLEVBQUUsRUFBRTtZQUN2RCxxRkFBcUY7WUFDckYsTUFBTSxlQUFlLEdBQXVCLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQztZQUM3RCxlQUFlLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxlQUFlLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDekYsZUFBZSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN0RSxPQUFPLGVBQWUsQ0FBQztRQUN6QixDQUFDLENBQUE7UUFFRCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUU7WUFDM0IsV0FBVyxHQUFHLEVBQUUsQ0FBQztZQUNqQixRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUNuQixXQUFXLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3RDLENBQUMsQ0FBQyxDQUFBO1NBQ0g7YUFBTTtZQUNMLFdBQVcsR0FBRyxjQUFjLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDeEM7UUFFRCxvREFBb0Q7UUFDcEQsV0FBVyxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVyRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsaUJBQWlCLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUM5RCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsRUFBRTtZQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1NBQ2pEO1FBRUQsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLEVBQUU7WUFDN0IsSUFBSSxDQUFDLFdBQVcsQ0FDZCxNQUFNLENBQUMsZ0JBQWdCLEVBQ3ZCLFdBQVcsRUFDWDtnQkFDRSxPQUFPO2dCQUNQLE1BQU0sRUFBRSxNQUFNLENBQUMsZ0JBQWdCLElBQUksSUFBSSxVQUFVLEVBQUU7Z0JBQ25ELFlBQVksRUFBRSxNQUFNLENBQUMsZ0JBQWdCLElBQUksTUFBTTtnQkFDL0MsZUFBZSxFQUFFLE1BQU0sQ0FBQyxlQUFlLElBQUksS0FBSzthQUNqRCxDQUNGLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDdEIsdUVBQXVFO2dCQUN2RSxPQUFPLENBQUMsS0FBSyxDQUFDLG9DQUFvQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUN6RCxPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN6QixDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2xCLENBQUMsQ0FBQztRQUVGLElBQUksTUFBTSxDQUFDLHdCQUF3QixLQUFLLElBQUksRUFBRTtZQUM1QyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRTtnQkFDaEIsT0FBTyxDQUFDLEtBQUssQ0FBQywrRUFBK0UsQ0FBQyxDQUFDO2dCQUMvRixPQUFPO2FBQ1I7WUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDLENBQUM7U0FDbEQ7YUFBTTtZQUNMLGlCQUFpQixFQUFFLENBQUM7U0FDckI7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLFlBQVksQ0FBQyxRQUE0QixFQUFFLE1BQXdCO1FBQ3hFLGdHQUFnRztRQUNoRyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsb0JBQW9CLElBQUksTUFBTSxDQUFDLG9CQUFvQixJQUFJLENBQUMsQ0FBQztZQUNwRSxDQUFDLENBQUMsTUFBTSxDQUFDLGdCQUFnQixJQUFJLE1BQU0sQ0FBQyxnQkFBZ0IsSUFBSSxDQUFDLENBQUMsRUFBRTtZQUM1RCxJQUFJLENBQUMsa0JBQWtCLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzFDLE9BQU87U0FDUjtRQUVELE1BQU0sbUJBQW1CLEdBQUcsR0FBRyxFQUFFO1lBQy9CLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFFNUMsbUNBQW1DO1lBQ25DLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxvQkFBb0IsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxvQkFBb0IsRUFBRTtnQkFDL0YsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQzthQUN6QjtZQUNELDBFQUEwRTtZQUMxRSxJQUFJLE1BQU0sQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFO2dCQUN4RCxJQUFJLENBQUMsZUFBZSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUU7b0JBQ2xFLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzFCLENBQUMsQ0FBQyxDQUFDO2FBQ0o7UUFDSCxDQUFDLENBQUM7UUFFRix3RkFBd0Y7UUFDeEYsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssS0FBSyxJQUFJLEVBQUU7WUFDckMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQ3JCLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxLQUFLLENBQUMsRUFDMUIsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUNSLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUNkLG1CQUFtQixFQUFFLENBQUM7WUFDeEIsQ0FBQyxDQUFDLENBQUM7U0FDSjthQUFNO1lBQ0wsbUJBQW1CLEVBQUUsQ0FBQztTQUN2QjtJQUNILENBQUM7O3lKQTNRVSxzQkFBc0I7NkpBQXRCLHNCQUFzQjsyRkFBdEIsc0JBQXNCO2tCQURsQyxVQUFVOzswQkFPTixRQUFROzswQkFDUixRQUFRIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSHR0cEJhY2tlbmQsIEh0dHBIZWFkZXJzLCBIdHRwUGFyYW1zLCBIdHRwUmVxdWVzdCwgSHR0cFJlc3BvbnNlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xyXG5pbXBvcnQgeyBJbmplY3RhYmxlLCBOZ1pvbmUsIE9uRGVzdHJveSwgT3B0aW9uYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBTdWJzY3JpcHRpb24sIGlzT2JzZXJ2YWJsZSwgb2YsIHRocm93RXJyb3IsIHRpbWVyIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGNhdGNoRXJyb3IsIGNvbmNhdE1hcCwgZmlsdGVyLCBtYXAsIHRha2UgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XHJcbmltcG9ydCB7IElOR1hMb2dnZXJDb25maWcgfSBmcm9tICcuLi9jb25maWcvaWNvbmZpZyc7XHJcbmltcG9ydCB7IElOR1hMb2dnZXJNZXRhZGF0YSB9IGZyb20gJy4uL21ldGFkYXRhL2ltZXRhZGF0YSc7XHJcbmltcG9ydCB7IElOR1hMb2dnZXJTZXJ2ZXJTZXJ2aWNlIH0gZnJvbSAnLi9pc2VydmVyLnNlcnZpY2UnO1xyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgTkdYTG9nZ2VyU2VydmVyU2VydmljZSBpbXBsZW1lbnRzIElOR1hMb2dnZXJTZXJ2ZXJTZXJ2aWNlLCBPbkRlc3Ryb3kge1xyXG4gIHByb3RlY3RlZCBzZXJ2ZXJDYWxsc1F1ZXVlOiBJTkdYTG9nZ2VyTWV0YWRhdGFbXSA9IFtdO1xyXG4gIHByb3RlY3RlZCBmbHVzaGluZ1F1ZXVlOiBCZWhhdmlvclN1YmplY3Q8Ym9vbGVhbj4gPSBuZXcgQmVoYXZpb3JTdWJqZWN0KGZhbHNlKTtcclxuICBwcm90ZWN0ZWQgYWRkVG9RdWV1ZVRpbWVyOiBTdWJzY3JpcHRpb247XHJcblxyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgQE9wdGlvbmFsKCkgcHJvdGVjdGVkIHJlYWRvbmx5IGh0dHBCYWNrZW5kOiBIdHRwQmFja2VuZCxcclxuICAgIEBPcHRpb25hbCgpIHByb3RlY3RlZCByZWFkb25seSBuZ1pvbmU6IE5nWm9uZSxcclxuICApIHsgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmZsdXNoaW5nUXVldWUpIHtcclxuICAgICAgdGhpcy5mbHVzaGluZ1F1ZXVlLmNvbXBsZXRlKCk7XHJcbiAgICAgIHRoaXMuZmx1c2hpbmdRdWV1ZSA9IG51bGw7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5hZGRUb1F1ZXVlVGltZXIpIHtcclxuICAgICAgdGhpcy5hZGRUb1F1ZXVlVGltZXIudW5zdWJzY3JpYmUoKTtcclxuICAgICAgdGhpcy5hZGRUb1F1ZXVlVGltZXIgPSBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVHJhbnNmb3JtcyBhbiBlcnJvciBvYmplY3QgaW50byBhIHJlYWRhYmxlIHN0cmluZyAodGFraW5nIG9ubHkgdGhlIHN0YWNrKVxyXG4gICAqIFRoaXMgaXMgbmVlZGVkIGJlY2F1c2UgSlNPTi5zdHJpbmdpZnkgd291bGQgcmV0dXJuIFwie31cIlxyXG4gICAqIEBwYXJhbSBlcnIgdGhlIGVycm9yIG9iamVjdFxyXG4gICAqIEByZXR1cm5zIFRoZSBzdGFjayBvZiB0aGUgZXJyb3JcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgc2VjdXJlRXJyb3JPYmplY3QoZXJyOiBFcnJvcik6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gZXJyPy5zdGFjaztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRyYW5zZm9ybXMgdGhlIGFkZGl0aW9uYWwgcGFyYW1ldGVycyB0byBhdm9pZCBhbnkganNvbiBlcnJvciB3aGVuIHNlbmRpbmcgdGhlIGRhdGEgdG8gdGhlIHNlcnZlclxyXG4gICAqIEJhc2ljYWxseSBpdCBqdXN0IHJlcGxhY2VzIHVuc3RyaW5naWZpYWJsZSBvYmplY3QgdG8gYSBzdHJpbmcgbWVudGlvbmluZyBhbiBlcnJvclxyXG4gICAqIEBwYXJhbSBhZGRpdGlvbmFsIFRoZSBhZGRpdGlvbmFsIGRhdGEgdG8gYmUgc2VudFxyXG4gICAqIEByZXR1cm5zIFRoZSBhZGRpdGlvbmFsIGRhdGEgc2VjdXJlZFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBzZWN1cmVBZGRpdGlvbmFsUGFyYW1ldGVycyhhZGRpdGlvbmFsOiBhbnlbXSk6IGFueVtdIHtcclxuICAgIGlmIChhZGRpdGlvbmFsID09PSBudWxsIHx8IGFkZGl0aW9uYWwgPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gYWRkaXRpb25hbC5tYXAoKG5leHQsIGlkeCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGlmIChuZXh0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgICAgIHJldHVybiB0aGlzLnNlY3VyZUVycm9yT2JqZWN0KG5leHQpO1xyXG4gICAgICAgIH1cclxuICAgICAgICAvLyBXZSBqdXN0IHdhbnQgdG8gbWFrZSBzdXJlIHRoZSBKU09OIGNhbiBiZSBwYXJzZWQsIHdlIGRvIG5vdCB3YW50IHRvIGFjdHVhbGx5IGNoYW5nZSB0aGUgdHlwZVxyXG4gICAgICAgIGlmICh0eXBlb2YgbmV4dCA9PT0gJ29iamVjdCcpIHtcclxuICAgICAgICAgIEpTT04uc3RyaW5naWZ5KG5leHQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIG5leHQ7XHJcbiAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICByZXR1cm4gYFRoZSBhZGRpdGlvbmFsWyR7aWR4fV0gdmFsdWUgY291bGQgbm90IGJlIHBhcnNlZCB1c2luZyBKU09OLnN0cmluZ2lmeSgpLmA7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVHJhbnNmb3JtcyB0aGUgbWVzc2FnZSBzbyB0aGF0IGl0IGNhbiBiZSBzZW50IHRvIHRoZSBzZXJ2ZXJcclxuICAgKiBAcGFyYW0gbWVzc2FnZSB0aGUgbWVzc2FnZSB0byBiZSBzZW50XHJcbiAgICogQHJldHVybnMgdGhlIG1lc3NhZ2Ugc2VjdXJlZFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBzZWN1cmVNZXNzYWdlKG1lc3NhZ2U6IGFueSk6IHN0cmluZyB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAobWVzc2FnZSBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc2VjdXJlRXJyb3JPYmplY3QobWVzc2FnZSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0eXBlb2YgbWVzc2FnZSAhPT0gJ3N0cmluZycpIHtcclxuICAgICAgICBtZXNzYWdlID0gSlNPTi5zdHJpbmdpZnkobWVzc2FnZSwgbnVsbCwgMik7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgbWVzc2FnZSA9ICdUaGUgcHJvdmlkZWQgXCJtZXNzYWdlXCIgdmFsdWUgY291bGQgbm90IGJlIHBhcnNlZCB3aXRoIEpTT04uc3RyaW5naWZ5KCkuJztcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gbWVzc2FnZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVkaXRzIEh0dHBSZXF1ZXN0IG9iamVjdCBiZWZvcmUgc2VuZGluZyByZXF1ZXN0IHRvIHNlcnZlclxyXG4gICAqIEBwYXJhbSBodHRwUmVxdWVzdCBkZWZhdWx0IHJlcXVlc3Qgb2JqZWN0XHJcbiAgICogQHJldHVybnMgYWx0ZXJlZCBodHRwcmVxdWVzdFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBhbHRlckh0dHBSZXF1ZXN0KGh0dHBSZXF1ZXN0OiBIdHRwUmVxdWVzdDxhbnk+KTogSHR0cFJlcXVlc3Q8YW55PiB8IE9ic2VydmFibGU8SHR0cFJlcXVlc3Q8YW55Pj4ge1xyXG4gICAgcmV0dXJuIGh0dHBSZXF1ZXN0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2VuZHMgcmVxdWVzdCB0byBzZXJ2ZXJcclxuICAgKiBAcGFyYW0gdXJsIFxyXG4gICAqIEBwYXJhbSBsb2dDb250ZW50IFxyXG4gICAqIEBwYXJhbSBvcHRpb25zIFxyXG4gICAqIEByZXR1cm5zIFxyXG4gICAqL1xyXG4gIHByb3RlY3RlZCBsb2dPblNlcnZlcihcclxuICAgIHVybDogc3RyaW5nLFxyXG4gICAgbG9nQ29udGVudDogYW55LFxyXG4gICAgb3B0aW9uczoge1xyXG4gICAgICBoZWFkZXJzPzogSHR0cEhlYWRlcnM7XHJcbiAgICAgIHJlcG9ydFByb2dyZXNzPzogYm9vbGVhbjtcclxuICAgICAgcGFyYW1zPzogSHR0cFBhcmFtcztcclxuICAgICAgcmVzcG9uc2VUeXBlPzogJ2FycmF5YnVmZmVyJyB8ICdibG9iJyB8ICdqc29uJyB8ICd0ZXh0JztcclxuICAgICAgd2l0aENyZWRlbnRpYWxzPzogYm9vbGVhbjtcclxuICAgIH0sXHJcbiAgKTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuXHJcbiAgICBpZiAoIXRoaXMuaHR0cEJhY2tlbmQpIHtcclxuICAgICAgY29uc29sZS5lcnJvcignTkdYTG9nZ2VyIDogQ2FuXFwndCBsb2cgb24gc2VydmVyIGJlY2F1c2UgSHR0cEJhY2tlbmQgaXMgbm90IHByb3ZpZGVkLiBZb3UgbmVlZCB0byBpbXBvcnQgSHR0cENsaWVudE1vZHVsZScpO1xyXG4gICAgICByZXR1cm4gb2YobnVsbCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSHR0cEJhY2tlbmQgc2tpcHMgYWxsIEh0dHBJbnRlcmNlcHRvcnNcclxuICAgIC8vIFRoZXkgbWF5IGxvZyBlcnJvcnMgdXNpbmcgdGhpcyBzZXJ2aWNlIGNhdXNpbmcgY2lyY3VsYXIgY2FsbHNcclxuICAgIGxldCBkZWZhdWx0UmVxdWVzdCA9IG5ldyBIdHRwUmVxdWVzdDxhbnk+KCdQT1NUJywgdXJsLCBsb2dDb250ZW50LCBvcHRpb25zIHx8IHt9KTtcclxuICAgIGxldCBmaW5hbFJlcXVlc3Q6IE9ic2VydmFibGU8SHR0cFJlcXVlc3Q8YW55Pj4gPSBvZihkZWZhdWx0UmVxdWVzdCk7XHJcblxyXG4gICAgY29uc3QgYWx0ZXJlZFJlcXVlc3QgPSB0aGlzLmFsdGVySHR0cFJlcXVlc3QoZGVmYXVsdFJlcXVlc3QpO1xyXG5cclxuICAgIGlmIChpc09ic2VydmFibGUoYWx0ZXJlZFJlcXVlc3QpKSB7XHJcbiAgICAgIGZpbmFsUmVxdWVzdCA9IGFsdGVyZWRSZXF1ZXN0O1xyXG4gICAgfSBlbHNlIGlmIChhbHRlcmVkUmVxdWVzdCkge1xyXG4gICAgICBmaW5hbFJlcXVlc3QgPSBvZihhbHRlcmVkUmVxdWVzdCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zb2xlLndhcm4oJ05HWExvZ2dlciA6IGFsdGVySHR0cFJlcXVlc3QgcmV0dXJuZWQgYW4gaW52YWxpZCByZXF1ZXN0LiBVc2luZyBkZWZhdWx0IG9uZSBpbnN0ZWFkJyk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGZpbmFsUmVxdWVzdC5waXBlKFxyXG4gICAgICBjb25jYXRNYXAocmVxID0+IHtcclxuICAgICAgICBpZiAoIXJlcSkge1xyXG4gICAgICAgICAgY29uc29sZS53YXJuKCdOR1hMb2dnZXIgOiBhbHRlckh0dHBSZXF1ZXN0IHJldHVybmVkIGFuIGludmFsaWQgcmVxdWVzdCAob2JzZXJ2YWJsZSkuIFVzaW5nIGRlZmF1bHQgb25lIGluc3RlYWQnKTtcclxuICAgICAgICAgIHJldHVybiB0aGlzLmh0dHBCYWNrZW5kLmhhbmRsZShkZWZhdWx0UmVxdWVzdClcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuaHR0cEJhY2tlbmQuaGFuZGxlKHJlcSk7XHJcbiAgICAgIH0pLFxyXG4gICAgICBmaWx0ZXIoZSA9PiBlIGluc3RhbmNlb2YgSHR0cFJlc3BvbnNlKSxcclxuICAgICAgbWFwPEh0dHBSZXNwb25zZTxhbnk+LCBhbnk+KChodHRwUmVzcG9uc2U6IEh0dHBSZXNwb25zZTxhbnk+KSA9PiBodHRwUmVzcG9uc2UuYm9keSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDdXN0b21pc2UgdGhlIGRhdGEgc2VudCB0byB0aGUgQVBJXHJcbiAgICogQHBhcmFtIG1ldGFkYXRhIHRoZSBkYXRhIHByb3ZpZGVkIGJ5IE5HWExvZ2dlclxyXG4gICAqIEByZXR1cm5zIHRoZSBkYXRhIHRoYXQgd2lsbCBiZSBzZW50IHRvIHRoZSBBUEkgaW4gdGhlIGJvZHlcclxuICAgKi9cclxuICBwcm90ZWN0ZWQgY3VzdG9taXNlUmVxdWVzdEJvZHkobWV0YWRhdGE6IElOR1hMb2dnZXJNZXRhZGF0YSB8IElOR1hMb2dnZXJNZXRhZGF0YVtdKTogYW55IHtcclxuICAgIC8vIEluIG91ciBBUEkgdGhlIGJvZHkgaXMgbm90IGN1c3RvbWlzZWRcclxuICAgIHJldHVybiBtZXRhZGF0YTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEZsdXNoIHRoZSBxdWV1ZSBvZiB0aGUgbG9nZ2VyXHJcbiAgICogQHBhcmFtIGNvbmZpZyBcclxuICAgKi9cclxuICBwdWJsaWMgZmx1c2hRdWV1ZShjb25maWc6IElOR1hMb2dnZXJDb25maWcpOiB2b2lkIHtcclxuICAgIHRoaXMuZmx1c2hpbmdRdWV1ZS5uZXh0KHRydWUpO1xyXG5cclxuICAgIC8vIElmIGEgdGltZXIgd2FzIHNldCwgd2UgY2FuY2VsIGl0IGJlY2F1c2UgdGhlIHF1ZXVlIGlzIGZsdXNoZWRcclxuICAgIGlmICh0aGlzLmFkZFRvUXVldWVUaW1lcikge1xyXG4gICAgICB0aGlzLmFkZFRvUXVldWVUaW1lci51bnN1YnNjcmliZSgpO1xyXG4gICAgICB0aGlzLmFkZFRvUXVldWVUaW1lciA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCEhdGhpcy5zZXJ2ZXJDYWxsc1F1ZXVlICYmIHRoaXMuc2VydmVyQ2FsbHNRdWV1ZS5sZW5ndGggPiAwKSB7XHJcbiAgICAgIHRoaXMuc2VuZFRvU2VydmVyQWN0aW9uKHRoaXMuc2VydmVyQ2FsbHNRdWV1ZSwgY29uZmlnKTtcclxuICAgIH1cclxuICAgIHRoaXMuc2VydmVyQ2FsbHNRdWV1ZSA9IFtdO1xyXG5cclxuICAgIHRoaXMuZmx1c2hpbmdRdWV1ZS5uZXh0KGZhbHNlKTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBzZW5kVG9TZXJ2ZXJBY3Rpb24obWV0YWRhdGE6IElOR1hMb2dnZXJNZXRhZGF0YSB8IElOR1hMb2dnZXJNZXRhZGF0YVtdLCBjb25maWc6IElOR1hMb2dnZXJDb25maWcpOiB2b2lkIHtcclxuICAgIGxldCByZXF1ZXN0Qm9keTogYW55O1xyXG5cclxuICAgIGNvbnN0IHNlY3VyZU1ldGFkYXRhID0gKHBNZXRhZGF0YTogSU5HWExvZ2dlck1ldGFkYXRhKSA9PiB7XHJcbiAgICAgIC8vIENvcHlpbmcgbWV0YWRhdGEgbG9jYWxseSBiZWNhdXNlIHdlIGRvbid0IHdhbnQgdG8gY2hhbmdlIHRoZSBvYmplY3QgZm9yIHRoZSBjYWxsZXJcclxuICAgICAgY29uc3Qgc2VjdXJlZE1ldGFkYXRhOiBJTkdYTG9nZ2VyTWV0YWRhdGEgPSB7IC4uLnBNZXRhZGF0YSB9O1xyXG4gICAgICBzZWN1cmVkTWV0YWRhdGEuYWRkaXRpb25hbCA9IHRoaXMuc2VjdXJlQWRkaXRpb25hbFBhcmFtZXRlcnMoc2VjdXJlZE1ldGFkYXRhLmFkZGl0aW9uYWwpO1xyXG4gICAgICBzZWN1cmVkTWV0YWRhdGEubWVzc2FnZSA9IHRoaXMuc2VjdXJlTWVzc2FnZShzZWN1cmVkTWV0YWRhdGEubWVzc2FnZSk7XHJcbiAgICAgIHJldHVybiBzZWN1cmVkTWV0YWRhdGE7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobWV0YWRhdGEpKSB7XHJcbiAgICAgIHJlcXVlc3RCb2R5ID0gW107XHJcbiAgICAgIG1ldGFkYXRhLmZvckVhY2gobSA9PiB7XHJcbiAgICAgICAgcmVxdWVzdEJvZHkucHVzaChzZWN1cmVNZXRhZGF0YShtKSk7XHJcbiAgICAgIH0pXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXF1ZXN0Qm9keSA9IHNlY3VyZU1ldGFkYXRhKG1ldGFkYXRhKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGxvdyB1c2VycyB0byBjdXN0b21pc2UgdGhlIGRhdGEgc2VudCB0byB0aGUgQVBJXHJcbiAgICByZXF1ZXN0Qm9keSA9IHRoaXMuY3VzdG9taXNlUmVxdWVzdEJvZHkocmVxdWVzdEJvZHkpO1xyXG5cclxuICAgIGNvbnN0IGhlYWRlcnMgPSBjb25maWcuY3VzdG9tSHR0cEhlYWRlcnMgfHwgbmV3IEh0dHBIZWFkZXJzKCk7XHJcbiAgICBpZiAoIWhlYWRlcnMuaGFzKCdDb250ZW50LVR5cGUnKSkge1xyXG4gICAgICBoZWFkZXJzLnNldCgnQ29udGVudC1UeXBlJywgJ2FwcGxpY2F0aW9uL2pzb24nKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBsb2dPblNlcnZlckFjdGlvbiA9ICgpID0+IHtcclxuICAgICAgdGhpcy5sb2dPblNlcnZlcihcclxuICAgICAgICBjb25maWcuc2VydmVyTG9nZ2luZ1VybCxcclxuICAgICAgICByZXF1ZXN0Qm9keSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBoZWFkZXJzLFxyXG4gICAgICAgICAgcGFyYW1zOiBjb25maWcuY3VzdG9tSHR0cFBhcmFtcyB8fCBuZXcgSHR0cFBhcmFtcygpLFxyXG4gICAgICAgICAgcmVzcG9uc2VUeXBlOiBjb25maWcuaHR0cFJlc3BvbnNlVHlwZSB8fCAnanNvbicsXHJcbiAgICAgICAgICB3aXRoQ3JlZGVudGlhbHM6IGNvbmZpZy53aXRoQ3JlZGVudGlhbHMgfHwgZmFsc2UsXHJcbiAgICAgICAgfSxcclxuICAgICAgKS5waXBlKGNhdGNoRXJyb3IoZXJyID0+IHtcclxuICAgICAgICAvLyBEbyBub3QgdXNlIE5HWExvZ2dlciBoZXJlIGJlY2F1c2UgdGhpcyBjb3VsZCBjYXVzZSBhbiBpbmZpbml0ZSBsb29wIFxyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ05HWExvZ2dlcjogRmFpbGVkIHRvIGxvZyBvbiBzZXJ2ZXInLCBlcnIpO1xyXG4gICAgICAgIHJldHVybiB0aHJvd0Vycm9yKGVycik7XHJcbiAgICAgIH0pKS5zdWJzY3JpYmUoKTtcclxuICAgIH07XHJcblxyXG4gICAgaWYgKGNvbmZpZy5zZXJ2ZXJDYWxsc091dHNpZGVOZ1pvbmUgPT09IHRydWUpIHtcclxuICAgICAgaWYgKCF0aGlzLm5nWm9uZSkge1xyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ05HWExvZ2dlcjogTmdab25lIGlzIG5vdCBwcm92aWRlZCBhbmQgc2VydmVyQ2FsbHNPdXRzaWRlTmdab25lIGlzIHNldCB0byB0cnVlJyk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKGxvZ09uU2VydmVyQWN0aW9uKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZ09uU2VydmVyQWN0aW9uKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZW5kcyB0aGUgY29udGVudCB0byBiZSBsb2dnZWQgdG8gdGhlIHNlcnZlciBhY2NvcmRpbmcgdG8gdGhlIGNvbmZpZ1xyXG4gICAqIEBwYXJhbSBtZXRhZGF0YSBcclxuICAgKiBAcGFyYW0gY29uZmlnIFxyXG4gICAqL1xyXG4gIHB1YmxpYyBzZW5kVG9TZXJ2ZXIobWV0YWRhdGE6IElOR1hMb2dnZXJNZXRhZGF0YSwgY29uZmlnOiBJTkdYTG9nZ2VyQ29uZmlnKTogdm9pZCB7XHJcbiAgICAvLyBJZiB0aGVyZSBpcyBubyBiYXRjaCBtb2RlIGluIHRoZSBjb25maWcsIHdlIHNlbmQgdGhlIGxvZyBjYWxsIHN0cmFpZ2h0IHRvIHRoZSBzZXJ2ZXIgYXMgdXN1YWxcclxuICAgIGlmICgoIWNvbmZpZy5zZXJ2ZXJDYWxsc0JhdGNoU2l6ZSB8fCBjb25maWcuc2VydmVyQ2FsbHNCYXRjaFNpemUgPD0gMCkgJiZcclxuICAgICAgKCFjb25maWcuc2VydmVyQ2FsbHNUaW1lciB8fCBjb25maWcuc2VydmVyQ2FsbHNUaW1lciA8PSAwKSkge1xyXG4gICAgICB0aGlzLnNlbmRUb1NlcnZlckFjdGlvbihtZXRhZGF0YSwgY29uZmlnKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGFkZExvZ1RvUXVldWVBY3Rpb24gPSAoKSA9PiB7XHJcbiAgICAgIHRoaXMuc2VydmVyQ2FsbHNRdWV1ZS5wdXNoKHsgLi4ubWV0YWRhdGEgfSk7XHJcblxyXG4gICAgICAvLyBGbHVzaCBxdWV1ZSB3aGVuIHNpemUgaXMgcmVhY2hlZFxyXG4gICAgICBpZiAoISFjb25maWcuc2VydmVyQ2FsbHNCYXRjaFNpemUgJiYgdGhpcy5zZXJ2ZXJDYWxsc1F1ZXVlLmxlbmd0aCA+IGNvbmZpZy5zZXJ2ZXJDYWxsc0JhdGNoU2l6ZSkge1xyXG4gICAgICAgIHRoaXMuZmx1c2hRdWV1ZShjb25maWcpO1xyXG4gICAgICB9XHJcbiAgICAgIC8vIENhbGwgdGltZXIgb25seSBpZiBpdCBpcyBpbiB0aGUgY29uZmlnIGFuZCB0aW1lciBpcyBub3QgYWxyZWFkeSBydW5uaW5nXHJcbiAgICAgIGlmIChjb25maWcuc2VydmVyQ2FsbHNUaW1lciA+IDAgJiYgIXRoaXMuYWRkVG9RdWV1ZVRpbWVyKSB7XHJcbiAgICAgICAgdGhpcy5hZGRUb1F1ZXVlVGltZXIgPSB0aW1lcihjb25maWcuc2VydmVyQ2FsbHNUaW1lcikuc3Vic2NyaWJlKF8gPT4ge1xyXG4gICAgICAgICAgdGhpcy5mbHVzaFF1ZXVlKGNvbmZpZyk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgLy8gSWYgcXVldWUgaXMgYmVpbmcgZmx1c2hlZCwgd2UgbmVlZCB0byB3YWl0IGZvciBpdCB0byBmaW5pc2ggYmVmb3JlIGFkZGluZyBvdGhlciBjYWxsc1xyXG4gICAgaWYgKHRoaXMuZmx1c2hpbmdRdWV1ZS52YWx1ZSA9PT0gdHJ1ZSkge1xyXG4gICAgICB0aGlzLmZsdXNoaW5nUXVldWUucGlwZShcclxuICAgICAgICBmaWx0ZXIoZnEgPT4gZnEgPT09IGZhbHNlKSxcclxuICAgICAgICB0YWtlKDEpLFxyXG4gICAgICApLnN1YnNjcmliZShfID0+IHtcclxuICAgICAgICBhZGRMb2dUb1F1ZXVlQWN0aW9uKCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgYWRkTG9nVG9RdWV1ZUFjdGlvbigpO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0=