UNPKG

ngx-endpoints

Version:

A library to dynamically load data from http endpoints / urls in angular

536 lines (526 loc) 41 kB
import { __awaiter, __generator, __extends } from 'tslib'; import { Injectable, NgModule, defineInjectable, inject } from '@angular/core'; import { HttpClient, HttpHeaders, HttpClientModule } from '@angular/common/http'; import { catchError } from 'rxjs/operators'; import { throwError, BehaviorSubject } from 'rxjs'; import { parseUrl, stringify } from 'query-string'; import { relativism } from 'moment-relativism'; import * as moment_ from 'moment'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ /** @type {?} */ var moment = moment_; var NgxEndpointService = /** @class */ (function () { function NgxEndpointService(_http) { this._http = _http; } /** * @return {?} */ NgxEndpointService.prototype.ngOnInit = /** * @return {?} */ function () { }; /** * Gets data via http client * @param endPointUrl url that will be requested */ /** * Gets data via http client * @template T * @param {?} endPointUrl url that will be requested * @param {?} httpheaders * @return {?} */ NgxEndpointService.prototype.getData = /** * Gets data via http client * @template T * @param {?} endPointUrl url that will be requested * @param {?} httpheaders * @return {?} */ function (endPointUrl, httpheaders) { return __awaiter(this, void 0, void 0, function () { var headers, key; return __generator(this, function (_a) { switch (_a.label) { case 0: headers = new HttpHeaders(); // tslint:disable-next-line:forin // tslint:disable-next-line:forin for (key in httpheaders) { headers = headers.append(key, httpheaders[key]); } return [4 /*yield*/, this._http.get(endPointUrl, { headers: headers }).pipe(catchError(function (err) { console.log('Cannot request data from ' + endPointUrl, err); return throwError(err); })).toPromise()]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * Conversion method for relative dates in querystrings * @param endPointUrl return endpointurl with converted dates in querystring */ /** * Conversion method for relative dates in querystrings * @param {?} endPointUrl return endpointurl with converted dates in querystring * @param {?} momentjsformat * @return {?} */ NgxEndpointService.prototype.convertDatesInURL = /** * Conversion method for relative dates in querystrings * @param {?} endPointUrl return endpointurl with converted dates in querystring * @param {?} momentjsformat * @return {?} */ function (endPointUrl, momentjsformat) { /** @type {?} */ var urlObject = parseUrl(endPointUrl); for (var propertyName in urlObject.query) { if (urlObject.query[propertyName].startsWith('now')) { /** @type {?} */ var dateResult = relativism(urlObject.query[propertyName]); urlObject.query[propertyName] = moment(dateResult).format(momentjsformat); } } /** @type {?} */ var stringified = stringify(urlObject.query); endPointUrl = urlObject.url + '?' + stringified; return endPointUrl; }; NgxEndpointService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ NgxEndpointService.ctorParameters = function () { return [ { type: HttpClient } ]; }; /** @nocollapse */ NgxEndpointService.ngInjectableDef = defineInjectable({ factory: function NgxEndpointService_Factory() { return new NgxEndpointService(inject(HttpClient)); }, token: NgxEndpointService, providedIn: "root" }); return NgxEndpointService; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ /** * Basic class that is used for the initial generation of the endpoints */ var /** * Basic class that is used for the initial generation of the endpoints */ NgxEndPointData = /** @class */ (function () { function NgxEndPointData() { /** * disable endpoint */ this.active = true; /** * Additional Headers (Api-Key, Basic Auth, Content-Type etc.) */ this.requestOptions = new Object(); /** * Additional Headers (Api-Key, Basic Auth, Content-Type etc.) */ this.live = false; /** * Wait Interval between 2 live requests */ this.liveinterval = 10000; /** * If relative dates are used in querystring or specific query you can use this feature */ this.convertDates = false; /** * Replaces the relative date with the date in this output format in the querystring */ this.convertDatesOutputFormat = ''; } return NgxEndPointData; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ /** * @template T */ var NgxEndPoint = /** @class */ (function () { function NgxEndPoint(endpointservice, _endpoint) { this.endpointservice = endpointservice; this._endpoint = _endpoint; /** * data stores the last requested data as Behaviorsubject that can be subscribed. */ this.data = new BehaviorSubject(null); /** * if a request is already pending no additional request should be made to the datasource */ this.requestPending = new BehaviorSubject(false); /** * Is the endpoint alive and returns data ? */ this.isAlive = new BehaviorSubject(false); /** * Delivering internal process information */ this.events = new BehaviorSubject(''); /** * for live sources this option will be used to stop the process */ this.running = true; this.endpoint = _endpoint; Object.assign(this.data, new Array()); } /** * Requests data from an http source * Optionally converts relative dates (now-1d) into readable urls by DatesOutputFormat * Adds the result of the request to BehaviorSubject data that can be subscribed */ /** * Requests data from an http source * Optionally converts relative dates (now-1d) into readable urls by DatesOutputFormat * Adds the result of the request to BehaviorSubject data that can be subscribed * @return {?} */ NgxEndPoint.prototype.requestData = /** * Requests data from an http source * Optionally converts relative dates (now-1d) into readable urls by DatesOutputFormat * Adds the result of the request to BehaviorSubject data that can be subscribed * @return {?} */ function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.requestInternal()]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * @return {?} */ NgxEndPoint.prototype.requestInternal = /** * @return {?} */ function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!!this.requestPending.getValue()) return [3 /*break*/, 2]; this.addEvent('requesting data from endpoint', this.endpoint); this.requestPending.next(true); this.convertDates(this.endpoint.convertDates); return [4 /*yield*/, this.request()]; case 1: _a.sent(); this.requestPending.next(false); return [3 /*break*/, 3]; case 2: this.addEvent('a request is pending', this.endpoint); _a.label = 3; case 3: return [2 /*return*/]; } }); }); }; /** * @param {?} conversion * @return {?} */ NgxEndPoint.prototype.convertDates = /** * @param {?} conversion * @return {?} */ function (conversion) { if (conversion) { this.endpoint.endPointUrl = this.endpointservice.convertDatesInURL(this.endpoint.endPointUrl, this.endpoint.convertDatesOutputFormat); this.addEvent('converted endpointurl', this.endpoint); } }; /** * @return {?} */ NgxEndPoint.prototype.request = /** * @return {?} */ function () { return __awaiter(this, void 0, void 0, function () { var currentData, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this.endpointservice.getData(this.endpoint.endPointUrl, this.endpoint.requestOptions)]; case 1: currentData = _a.sent(); if (!this.isAlive.getValue() && currentData != null) { this.isAlive.next(true); this.addEvent('endpoint is alive', this.endpoint); } this.data.next(currentData); this.addEvent('updated data', this.endpoint); return [3 /*break*/, 3]; case 2: error_1 = _a.sent(); this.addEvent(error_1, this.endpoint); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; /** * @param {?} item * @param {?} endpointdata * @return {?} */ NgxEndPoint.prototype.addEvent = /** * @param {?} item * @param {?} endpointdata * @return {?} */ function (item, endpointdata) { this.events.next(JSON.stringify({ event: item, endpoint: endpointdata })); }; NgxEndPoint.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ NgxEndPoint.ctorParameters = function () { return [ { type: NgxEndpointService }, { type: NgxEndPointData } ]; }; /** @nocollapse */ NgxEndPoint.ngInjectableDef = defineInjectable({ factory: function NgxEndPoint_Factory() { return new NgxEndPoint(inject(NgxEndpointService), inject(NgxEndPointData)); }, token: NgxEndPoint, providedIn: "root" }); return NgxEndPoint; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ /** * @template T */ var NgxLiveEndPoint = /** @class */ (function (_super) { __extends(NgxLiveEndPoint, _super); function NgxLiveEndPoint(endpointservice, endpoint) { var _this = _super.call(this, endpointservice, endpoint) || this; _this.endpointservice = endpointservice; _this.endpoint = endpoint; return _this; } /** * Requests data from an http source * Optionally converts relative dates (now-1d) into readable urls by DatesOutputFormat * Adds the result of the request to BehaviorSubject data that can be subscribed */ /** * Requests data from an http source * Optionally converts relative dates (now-1d) into readable urls by DatesOutputFormat * Adds the result of the request to BehaviorSubject data that can be subscribed * @return {?} */ NgxLiveEndPoint.prototype.requestData = /** * Requests data from an http source * Optionally converts relative dates (now-1d) into readable urls by DatesOutputFormat * Adds the result of the request to BehaviorSubject data that can be subscribed * @return {?} */ function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: this.running = true; return [4 /*yield*/, this.refreshData()]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * internal function to wait before next live request will be made */ /** * internal function to wait before next live request will be made * @param {?} ms * @return {?} */ NgxLiveEndPoint.prototype.sleep = /** * internal function to wait before next live request will be made * @param {?} ms * @return {?} */ function (ms) { return new Promise(function (resolve) { return setTimeout(resolve, ms); }); }; /** * internal function to run live requests in loop */ /** * internal function to run live requests in loop * @return {?} */ NgxLiveEndPoint.prototype.refreshData = /** * internal function to run live requests in loop * @return {?} */ function () { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this.running) return [3 /*break*/, 3]; return [4 /*yield*/, this.requestInternal()]; case 1: _a.sent(); return [4 /*yield*/, this.sleep(this.endpoint.liveinterval)]; case 2: _a.sent(); return [3 /*break*/, 0]; case 3: return [2 /*return*/]; } }); }); }; NgxLiveEndPoint.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ NgxLiveEndPoint.ctorParameters = function () { return [ { type: NgxEndpointService }, { type: NgxEndPointData } ]; }; /** @nocollapse */ NgxLiveEndPoint.ngInjectableDef = defineInjectable({ factory: function NgxLiveEndPoint_Factory() { return new NgxLiveEndPoint(inject(NgxEndpointService), inject(NgxEndPointData)); }, token: NgxLiveEndPoint, providedIn: "root" }); return NgxLiveEndPoint; }(NgxEndPoint)); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ /** * @template T */ var NgxEndPointDataProviderService = /** @class */ (function () { function NgxEndPointDataProviderService(endpointservice) { this.endpointservice = endpointservice; this.endpoints = new Array(); } /** * Creates an NgxEndPoint and stores it in an array for proceeding * @param NgxEndPointData endpointitem (basic json object) * @returns the created NgxEndPoint for further proceeding */ /** * Creates an NgxEndPoint and stores it in an array for proceeding * @param {?} endpointitem * @return {?} the created NgxEndPoint for further proceeding */ NgxEndPointDataProviderService.prototype.addEndPoint = /** * Creates an NgxEndPoint and stores it in an array for proceeding * @param {?} endpointitem * @return {?} the created NgxEndPoint for further proceeding */ function (endpointitem) { if (!endpointitem.endPointId) { console.log('No endPointId provided. Please attach an endpointId'); throw new Error('No endPointId provided. Please attach an endpointId'); } if (this.endpoints.find(function (x) { return x.endpoint.endPointId === endpointitem.endPointId; })) { throw new Error('An endpoint with id ' + endpointitem.endPointId + ' has been already added. Please choose another id.'); } /** @type {?} */ var endpoint; if (endpointitem.live) { endpoint = new NgxLiveEndPoint(this.endpointservice, endpointitem); } else { endpoint = new NgxEndPoint(this.endpointservice, endpointitem); } this.endpoints.push(endpoint); return endpoint; }; /** * Deletes a certain NgxEndPoint from endpoints array * Stops running live requests * @param endPointId Id of the specific NgxEndPoint */ /** * Deletes a certain NgxEndPoint from endpoints array * Stops running live requests * @param {?} endPointId Id of the specific NgxEndPoint * @return {?} */ NgxEndPointDataProviderService.prototype.destroyEndPoint = /** * Deletes a certain NgxEndPoint from endpoints array * Stops running live requests * @param {?} endPointId Id of the specific NgxEndPoint * @return {?} */ function (endPointId) { if (this.endpoints && this.endpoints.length > 0) { /** @type {?} */ var index = this.endpoints.findIndex(function (x) { return x.endpoint.endPointId === endPointId; }); this.endpoints[index].running = false; this.endpoints.splice(index, 1); } }; NgxEndPointDataProviderService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] } ]; /** @nocollapse */ NgxEndPointDataProviderService.ctorParameters = function () { return [ { type: NgxEndpointService } ]; }; /** @nocollapse */ NgxEndPointDataProviderService.ngInjectableDef = defineInjectable({ factory: function NgxEndPointDataProviderService_Factory() { return new NgxEndPointDataProviderService(inject(NgxEndpointService)); }, token: NgxEndPointDataProviderService, providedIn: "root" }); return NgxEndPointDataProviderService; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ var NgxEndpointsModule = /** @class */ (function () { function NgxEndpointsModule() { } NgxEndpointsModule.decorators = [ { type: NgModule, args: [{ declarations: [], imports: [HttpClientModule], exports: [ HttpClientModule ], providers: [NgxEndpointService, NgxEndPointDataProviderService, NgxEndPoint, NgxLiveEndPoint] },] } ]; return NgxEndpointsModule; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc */ export { NgxEndpointsModule, NgxEndPointDataProviderService, NgxLiveEndPoint, NgxEndPoint, NgxEndpointService, NgxEndPointData }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWVuZHBvaW50cy5qcy5tYXAiLCJzb3VyY2VzIjpbIm5nOi8vbmd4LWVuZHBvaW50cy9saWIvbmd4LWVuZHBvaW50cy9uZ3gtZW5kcG9pbnRzLnNlcnZpY2UudHMiLCJuZzovL25neC1lbmRwb2ludHMvbGliL25neC1lbmRwb2ludHMvbmd4LWVuZHBvaW50LmZvcm1hdC50cyIsIm5nOi8vbmd4LWVuZHBvaW50cy9saWIvbmd4LWVuZHBvaW50cy9uZ3gtZW5kcG9pbnRzLnRzIiwibmc6Ly9uZ3gtZW5kcG9pbnRzL2xpYi9uZ3gtZW5kcG9pbnRzL25neC1saXZlLWVuZC1wb2ludHMvbmd4LWxpdmUtZW5kLXBvaW50cy50cyIsIm5nOi8vbmd4LWVuZHBvaW50cy9saWIvbmd4LWVuZHBvaW50cy9uZ3gtZW5kcG9pbnRzLWRhdGEtcHJvdmlkZXIuc2VydmljZS50cyIsIm5nOi8vbmd4LWVuZHBvaW50cy9saWIvbmd4LWVuZHBvaW50cy5tb2R1bGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBIdHRwQ2xpZW50LCBIdHRwSGVhZGVycyB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IGNhdGNoRXJyb3IgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyB0aHJvd0Vycm9yLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0ICogYXMgcXVlcnlTdHJpbmcgZnJvbSAncXVlcnktc3RyaW5nJztcbmltcG9ydCAqIGFzIG1vbWVudFJlbGF0aXZpc20gZnJvbSAnbW9tZW50LXJlbGF0aXZpc20nO1xuaW1wb3J0ICogYXMgbW9tZW50XyBmcm9tICdtb21lbnQnO1xuY29uc3QgbW9tZW50ID0gbW9tZW50XztcbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE5neEVuZHBvaW50U2VydmljZSBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIF9odHRwOiBIdHRwQ2xpZW50KSB7IH1cblxuICBuZ09uSW5pdCgpIHtcbiAgfVxuICAvKipcbiAgICogR2V0cyBkYXRhIHZpYSBodHRwIGNsaWVudFxuICAgKiBAcGFyYW0gZW5kUG9pbnRVcmwgdXJsIHRoYXQgd2lsbCBiZSByZXF1ZXN0ZWRcbiAgICovXG4gIGFzeW5jIGdldERhdGE8VD4oZW5kUG9pbnRVcmw6IHN0cmluZywgaHR0cGhlYWRlcnM6IE9iamVjdCk6IFByb21pc2U8VD4ge1xuICAgIGxldCBoZWFkZXJzID0gbmV3IEh0dHBIZWFkZXJzKCk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOmZvcmluXG5cbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6Zm9yaW5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBodHRwaGVhZGVycykge1xuICAgICAgaGVhZGVycyA9IGhlYWRlcnMuYXBwZW5kKGtleSwgaHR0cGhlYWRlcnNba2V5XSk7XG4gICAgfVxuICAgIHJldHVybiBhd2FpdCB0aGlzLl9odHRwLmdldDxUPihlbmRQb2ludFVybCwgeyBoZWFkZXJzOiBoZWFkZXJzIH0pLnBpcGU8VD4oXG4gICAgICBjYXRjaEVycm9yKChlcnIpID0+IHtcbiAgICAgICAgY29uc29sZS5sb2coJ0Nhbm5vdCByZXF1ZXN0IGRhdGEgZnJvbSAnICsgZW5kUG9pbnRVcmwsIGVycik7XG4gICAgICAgIHJldHVybiB0aHJvd0Vycm9yKGVycik7XG4gICAgfSlcbiAgICApLnRvUHJvbWlzZSgpO1xuICB9XG4gIC8qKlxuICAgKiBDb252ZXJzaW9uIG1ldGhvZCBmb3IgcmVsYXRpdmUgZGF0ZXMgaW4gcXVlcnlzdHJpbmdzXG4gICAqIEBwYXJhbSBlbmRQb2ludFVybCByZXR1cm4gZW5kcG9pbnR1cmwgd2l0aCBjb252ZXJ0ZWQgZGF0ZXMgaW4gcXVlcnlzdHJpbmdcbiAgICovXG4gIGNvbnZlcnREYXRlc0luVVJMKGVuZFBvaW50VXJsOiBzdHJpbmcsIG1vbWVudGpzZm9ybWF0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHVybE9iamVjdCA9IHF1ZXJ5U3RyaW5nLnBhcnNlVXJsKGVuZFBvaW50VXJsKTtcbiAgICBmb3IgKGNvbnN0IHByb3BlcnR5TmFtZSBpbiB1cmxPYmplY3QucXVlcnkpIHtcbiAgICAgIGlmICh1cmxPYmplY3QucXVlcnlbcHJvcGVydHlOYW1lXS5zdGFydHNXaXRoKCdub3cnKSkge1xuICAgICAgICBjb25zdCBkYXRlUmVzdWx0ID0gbW9tZW50UmVsYXRpdmlzbS5yZWxhdGl2aXNtKHVybE9iamVjdC5xdWVyeVtwcm9wZXJ0eU5hbWVdKTtcbiAgICAgICAgdXJsT2JqZWN0LnF1ZXJ5W3Byb3BlcnR5TmFtZV0gPSBtb21lbnQoZGF0ZVJlc3VsdCkuZm9ybWF0KG1vbWVudGpzZm9ybWF0KTtcbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3Qgc3RyaW5naWZpZWQgPSBxdWVyeVN0cmluZy5zdHJpbmdpZnkodXJsT2JqZWN0LnF1ZXJ5KTtcbiAgICBlbmRQb2ludFVybCA9IHVybE9iamVjdC51cmwgKyAnPycgKyBzdHJpbmdpZmllZDtcbiAgICByZXR1cm4gZW5kUG9pbnRVcmw7XG4gIH1cblxufVxuIiwiICAvKipcbiAgKiBCYXNpYyBjbGFzcyB0aGF0IGlzIHVzZWQgZm9yIHRoZSBpbml0aWFsIGdlbmVyYXRpb24gb2YgdGhlIGVuZHBvaW50c1xuICAqL1xuZXhwb3J0IGNsYXNzIE5neEVuZFBvaW50RGF0YSB7XG4gICAvKipcbiAgKiBUaXRsZSBvZiB0aGUgZW5kcG9pbnRcbiAgKi9cbiAgICB0aXRsZTogc3RyaW5nO1xuICAvKipcbiAgKiBJZCBmb3IgbGF0ZXIgaWRlbnRpZmljYXRpb24gb2YgdGhlIGVuZHBvaW50XG4gICovXG4gICAgZW5kUG9pbnRJZDogTm9uTnVsbGFibGU8bnVtYmVyPjtcbiAgLyoqXG4gICogZGlzYWJsZSBlbmRwb2ludFxuICAqL1xuICAgIGFjdGl2ZSA9IHRydWU7XG4gIC8qKlxuICAqIEh0dHAgVXJsIHRoYXQgd2lsbCBiZSByZXF1ZXN0ZWQgYnkgRW5kcG9pbnQgKEh0dHAuR2V0KVxuICAqL1xuICAgIGVuZFBvaW50VXJsOiBzdHJpbmc7XG4gIC8qKlxuICAqIEFkZGl0aW9uYWwgSGVhZGVycyAoQXBpLUtleSwgQmFzaWMgQXV0aCwgQ29udGVudC1UeXBlIGV0Yy4pXG4gICovXG4gICAgcmVxdWVzdE9wdGlvbnMgPz0gbmV3IE9iamVjdCgpO1xuICAvKipcbiAgKiBBZGRpdGlvbmFsIEhlYWRlcnMgKEFwaS1LZXksIEJhc2ljIEF1dGgsIENvbnRlbnQtVHlwZSBldGMuKVxuICAqL1xuICAgIGxpdmUgPz0gZmFsc2U7XG4gIC8qKlxuICAqIFdhaXQgSW50ZXJ2YWwgYmV0d2VlbiAyIGxpdmUgcmVxdWVzdHNcbiAgKi9cbiAgICBsaXZlaW50ZXJ2YWwgPz0gMTAwMDA7XG4gIC8qKlxuICAqIElmIHJlbGF0aXZlIGRhdGVzIGFyZSB1c2VkIGluIHF1ZXJ5c3RyaW5nIG9yIHNwZWNpZmljIHF1ZXJ5IHlvdSBjYW4gdXNlIHRoaXMgZmVhdHVyZVxuICAqL1xuICAgIGNvbnZlcnREYXRlcyA/PSBmYWxzZTtcbiAgLyoqXG4gICogUmVwbGFjZXMgdGhlIHJlbGF0aXZlIGRhdGUgd2l0aCB0aGUgZGF0ZSBpbiB0aGlzIG91dHB1dCBmb3JtYXQgaW4gdGhlIHF1ZXJ5c3RyaW5nXG4gICovXG4gICAgY29udmVydERhdGVzT3V0cHV0Rm9ybWF0ID89ICcnO1xufVxuIiwiaW1wb3J0IHsgTmd4RW5kcG9pbnRTZXJ2aWNlIH0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzLnNlcnZpY2UnO1xuaW1wb3J0IHsgTmd4RW5kUG9pbnREYXRhIH0gZnJvbSAnLi9uZ3gtZW5kcG9pbnQuZm9ybWF0JztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQ29tcG9uZW50LCBJbmplY3RhYmxlLCBDb21wb25lbnRSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgTmd4RW5kUG9pbnQ8VD4ge1xuICAvKipcbiAgKiByYXcgZGF0YSB0aGF0IGlzIHVzZWQgZm9yIGxhdGVyIGlkZW50aWZpY2F0aW9uIG9mIHRoZSBlbmRwb2ludFxuICAqL1xuICBwdWJsaWMgZW5kcG9pbnQ6IE5neEVuZFBvaW50RGF0YTtcbiAgLyoqXG4gICogZGF0YSBzdG9yZXMgdGhlIGxhc3QgcmVxdWVzdGVkIGRhdGEgYXMgQmVoYXZpb3JzdWJqZWN0IHRoYXQgY2FuIGJlIHN1YnNjcmliZWQuXG4gICovXG4gIHB1YmxpYyBkYXRhID0gbmV3IEJlaGF2aW9yU3ViamVjdDxUPihudWxsKTtcbiAgLyoqXG4gICogaWYgYSByZXF1ZXN0IGlzIGFscmVhZHkgcGVuZGluZyBubyBhZGRpdGlvbmFsIHJlcXVlc3Qgc2hvdWxkIGJlIG1hZGUgdG8gdGhlIGRhdGFzb3VyY2VcbiAgKi9cbiAgcHVibGljIHJlcXVlc3RQZW5kaW5nID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KGZhbHNlKTtcbiAgLyoqXG4gICogSXMgdGhlIGVuZHBvaW50IGFsaXZlIGFuZCByZXR1cm5zIGRhdGEgP1xuICAqL1xuICBwdWJsaWMgaXNBbGl2ZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8YW55PihmYWxzZSk7XG4gIC8qKlxuICAqIERlbGl2ZXJpbmcgaW50ZXJuYWwgcHJvY2VzcyBpbmZvcm1hdGlvblxuICAqL1xuICBwdWJsaWMgZXZlbnRzID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmc+KCcnKTtcbiAgLyoqXG4gICogZm9yIGxpdmUgc291cmNlcyB0aGlzIG9wdGlvbiB3aWxsIGJlIHVzZWQgdG8gc3RvcCB0aGUgcHJvY2Vzc1xuICAqL1xuICBwdWJsaWMgcnVubmluZyA9IHRydWU7XG4gIGNvbnN0cnVjdG9yKHB1YmxpYyBlbmRwb2ludHNlcnZpY2U6IE5neEVuZHBvaW50U2VydmljZSwgcHJvdGVjdGVkIF9lbmRwb2ludDogTmd4RW5kUG9pbnREYXRhKSB7XG4gICAgdGhpcy5lbmRwb2ludCA9IF9lbmRwb2ludDtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMuZGF0YSwgbmV3IEFycmF5PGFueT4oKSk7XG4gIH1cblxuICAvKipcbiAgKiBSZXF1ZXN0cyBkYXRhIGZyb20gYW4gaHR0cCBzb3VyY2VcbiAgKiBPcHRpb25hbGx5IGNvbnZlcnRzIHJlbGF0aXZlIGRhdGVzIChub3ctMWQpIGludG8gcmVhZGFibGUgdXJscyBieSBEYXRlc091dHB1dEZvcm1hdFxuICAqIEFkZHMgdGhlIHJlc3VsdCBvZiB0aGUgcmVxdWVzdCB0byBCZWhhdmlvclN1YmplY3QgZGF0YSB0aGF0IGNhbiBiZSBzdWJzY3JpYmVkXG4gICovXG4gIHB1YmxpYyBhc3luYyByZXF1ZXN0RGF0YSgpIHtcbiAgICBhd2FpdCB0aGlzLnJlcXVlc3RJbnRlcm5hbCgpO1xuICB9XG5cblxuICBwcm90ZWN0ZWQgYXN5bmMgcmVxdWVzdEludGVybmFsKCkge1xuICAgIGlmICghdGhpcy5yZXF1ZXN0UGVuZGluZy5nZXRWYWx1ZSgpKSB7XG4gICAgICB0aGlzLmFkZEV2ZW50KCdyZXF1ZXN0aW5nIGRhdGEgZnJvbSBlbmRwb2ludCcsIHRoaXMuZW5kcG9pbnQpO1xuICAgICAgdGhpcy5yZXF1ZXN0UGVuZGluZy5uZXh0KHRydWUpO1xuICAgICAgdGhpcy5jb252ZXJ0RGF0ZXModGhpcy5lbmRwb2ludC5jb252ZXJ0RGF0ZXMpO1xuICAgICAgYXdhaXQgdGhpcy5yZXF1ZXN0KCk7XG4gICAgICB0aGlzLnJlcXVlc3RQZW5kaW5nLm5leHQoZmFsc2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmFkZEV2ZW50KCdhIHJlcXVlc3QgaXMgcGVuZGluZycsIHRoaXMuZW5kcG9pbnQpO1xuXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjb252ZXJ0RGF0ZXMoY29udmVyc2lvbikge1xuICAgIGlmIChjb252ZXJzaW9uKSB7XG4gICAgICB0aGlzLmVuZHBvaW50LmVuZFBvaW50VXJsID0gdGhpcy5lbmRwb2ludHNlcnZpY2UuY29udmVydERhdGVzSW5VUkwodGhpcy5lbmRwb2ludC5lbmRQb2ludFVybCwgdGhpcy5lbmRwb2ludC5jb252ZXJ0RGF0ZXNPdXRwdXRGb3JtYXQpO1xuICAgICAgdGhpcy5hZGRFdmVudCgnY29udmVydGVkIGVuZHBvaW50dXJsJywgdGhpcy5lbmRwb2ludCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyByZXF1ZXN0KCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjdXJyZW50RGF0YSA9IGF3YWl0IHRoaXMuZW5kcG9pbnRzZXJ2aWNlLmdldERhdGE8VD4odGhpcy5lbmRwb2ludC5lbmRQb2ludFVybCwgdGhpcy5lbmRwb2ludC5yZXF1ZXN0T3B0aW9ucyk7XG4gICAgICBpZiAoIXRoaXMuaXNBbGl2ZS5nZXRWYWx1ZSgpICYmIGN1cnJlbnREYXRhICE9IG51bGwpIHtcbiAgICAgICAgdGhpcy5pc0FsaXZlLm5leHQodHJ1ZSk7XG4gICAgICAgIHRoaXMuYWRkRXZlbnQoJ2VuZHBvaW50IGlzIGFsaXZlJywgdGhpcy5lbmRwb2ludCk7XG4gICAgICB9XG4gICAgICB0aGlzLmRhdGEubmV4dChjdXJyZW50RGF0YSk7XG4gICAgICB0aGlzLmFkZEV2ZW50KCd1cGRhdGVkIGRhdGEnLCB0aGlzLmVuZHBvaW50KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5hZGRFdmVudChlcnJvciwgdGhpcy5lbmRwb2ludCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRFdmVudChpdGVtOiBhbnksIGVuZHBvaW50ZGF0YTogTmd4RW5kUG9pbnREYXRhKSB7XG5cbiAgICB0aGlzLmV2ZW50cy5uZXh0KEpTT04uc3RyaW5naWZ5KHtldmVudDogaXRlbSwgZW5kcG9pbnQ6IGVuZHBvaW50ZGF0YX0pKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgIE9uRGVzdHJveSwgQ29tcG9uZW50LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyAgTmd4RW5kcG9pbnRTZXJ2aWNlIH0gZnJvbSAnLi4vbmd4LWVuZHBvaW50cy5zZXJ2aWNlJztcbmltcG9ydCB7ICBOZ3hFbmRQb2ludCB9IGZyb20gJy4uL25neC1lbmRwb2ludHMnO1xuaW1wb3J0IHsgIE5neEVuZFBvaW50RGF0YSB9IGZyb20gJy4uL25neC1lbmRwb2ludC5mb3JtYXQnO1xuXG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE5neExpdmVFbmRQb2ludDxUPiBleHRlbmRzIE5neEVuZFBvaW50PFQ+IHtcbiAgY29uc3RydWN0b3IocHVibGljIGVuZHBvaW50c2VydmljZTogTmd4RW5kcG9pbnRTZXJ2aWNlLCBwdWJsaWMgZW5kcG9pbnQ6IE5neEVuZFBvaW50RGF0YSkge1xuICAgIHN1cGVyKGVuZHBvaW50c2VydmljZSwgZW5kcG9pbnQpO1xuICB9XG4gIC8qKlxuICAqIFJlcXVlc3RzIGRhdGEgZnJvbSBhbiBodHRwIHNvdXJjZVxuICAqIE9wdGlvbmFsbHkgY29udmVydHMgcmVsYXRpdmUgZGF0ZXMgKG5vdy0xZCkgaW50byByZWFkYWJsZSB1cmxzIGJ5IERhdGVzT3V0cHV0Rm9ybWF0XG4gICogQWRkcyB0aGUgcmVzdWx0IG9mIHRoZSByZXF1ZXN0IHRvIEJlaGF2aW9yU3ViamVjdCBkYXRhIHRoYXQgY2FuIGJlIHN1YnNjcmliZWRcbiAgKi9cbiAgcHVibGljIGFzeW5jIHJlcXVlc3REYXRhKCkge1xuICAgdGhpcy5ydW5uaW5nID0gdHJ1ZTtcbiAgIGF3YWl0IHRoaXMucmVmcmVzaERhdGEoKTtcbiAgfVxuXG4gIC8qKlxuICAqIGludGVybmFsIGZ1bmN0aW9uIHRvIHdhaXQgYmVmb3JlIG5leHQgbGl2ZSByZXF1ZXN0IHdpbGwgYmUgbWFkZVxuICAqL1xuICBwcml2YXRlIHNsZWVwKG1zKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xuICB9XG4gIC8qKlxuICAqIGludGVybmFsIGZ1bmN0aW9uIHRvIHJ1biBsaXZlIHJlcXVlc3RzIGluIGxvb3BcbiAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZWZyZXNoRGF0YSgpIHtcbiAgICB3aGlsZSAodGhpcy5ydW5uaW5nKSB7XG4gICAgICBhd2FpdCB0aGlzLnJlcXVlc3RJbnRlcm5hbCgpO1xuICAgICAgYXdhaXQgIHRoaXMuc2xlZXAodGhpcy5lbmRwb2ludC5saXZlaW50ZXJ2YWwpO1xuICAgIH1cbiB9XG59XG4iLCJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOZ3hFbmRQb2ludCB9IGZyb20gJy4vbmd4LWVuZHBvaW50cyc7XG5pbXBvcnQgeyBOZ3hMaXZlRW5kUG9pbnQgfSBmcm9tICcuL25neC1saXZlLWVuZC1wb2ludHMvbmd4LWxpdmUtZW5kLXBvaW50cyc7XG5pbXBvcnQgeyBOZ3hFbmRQb2ludERhdGEgfSBmcm9tICcuL25neC1lbmRwb2ludC5mb3JtYXQnO1xuaW1wb3J0IHsgTmd4RW5kcG9pbnRTZXJ2aWNlIH0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzLnNlcnZpY2UnO1xuaW1wb3J0IHsgQXJndW1lbnRPdXRPZlJhbmdlRXJyb3IgfSBmcm9tICdyeGpzJztcbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIE5neEVuZFBvaW50RGF0YVByb3ZpZGVyU2VydmljZTxUIGV4dGVuZHMgTmd4RW5kUG9pbnQ8YW55Pj4ge1xuICBwdWJsaWMgZW5kcG9pbnRzID0gbmV3IEFycmF5PFQ+KCk7XG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgZW5kcG9pbnRzZXJ2aWNlOiBOZ3hFbmRwb2ludFNlcnZpY2UpIHsgfVxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBOZ3hFbmRQb2ludCBhbmQgc3RvcmVzIGl0IGluIGFuIGFycmF5IGZvciBwcm9jZWVkaW5nXG4gICAqIEBwYXJhbSBOZ3hFbmRQb2ludERhdGEgZW5kcG9pbnRpdGVtIChiYXNpYyBqc29uIG9iamVjdClcbiAgICogQHJldHVybnMgdGhlIGNyZWF0ZWQgTmd4RW5kUG9pbnQgZm9yIGZ1cnRoZXIgcHJvY2VlZGluZ1xuICAgKi9cbiAgYWRkRW5kUG9pbnQoZW5kcG9pbnRpdGVtOiBOZ3hFbmRQb2ludERhdGEpOiBOZ3hFbmRQb2ludDxhbnk+IHtcbiAgICBpZiAoIWVuZHBvaW50aXRlbS5lbmRQb2ludElkKSB7XG4gICAgICBjb25zb2xlLmxvZygnTm8gZW5kUG9pbnRJZCBwcm92aWRlZC4gUGxlYXNlIGF0dGFjaCBhbiBlbmRwb2ludElkJyk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIGVuZFBvaW50SWQgcHJvdmlkZWQuIFBsZWFzZSBhdHRhY2ggYW4gZW5kcG9pbnRJZCcpO1xuICAgIH1cbiAgICBpZiAodGhpcy5lbmRwb2ludHMuZmluZCh4ID0+IHguZW5kcG9pbnQuZW5kUG9pbnRJZCA9PT0gZW5kcG9pbnRpdGVtLmVuZFBvaW50SWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FuIGVuZHBvaW50IHdpdGggaWQgJyArIGVuZHBvaW50aXRlbS5lbmRQb2ludElkICsgJyBoYXMgYmVlbiBhbHJlYWR5IGFkZGVkLiBQbGVhc2UgY2hvb3NlIGFub3RoZXIgaWQuJyk7XG4gICAgfVxuICAgIGxldCBlbmRwb2ludDtcbiAgICBpZiAoZW5kcG9pbnRpdGVtLmxpdmUpIHtcbiAgICAgIGVuZHBvaW50ID0gbmV3IE5neExpdmVFbmRQb2ludCh0aGlzLmVuZHBvaW50c2VydmljZSwgZW5kcG9pbnRpdGVtKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZW5kcG9pbnQgPSBuZXcgTmd4RW5kUG9pbnQodGhpcy5lbmRwb2ludHNlcnZpY2UsIGVuZHBvaW50aXRlbSk7XG4gICAgfVxuICAgIHRoaXMuZW5kcG9pbnRzLnB1c2goZW5kcG9pbnQpO1xuICAgIHJldHVybiBlbmRwb2ludDtcbiAgfVxuICAvKipcbiAgICogRGVsZXRlcyBhIGNlcnRhaW4gTmd4RW5kUG9pbnQgZnJvbSBlbmRwb2ludHMgYXJyYXlcbiAgICogU3RvcHMgcnVubmluZyBsaXZlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSBlbmRQb2ludElkIElkIG9mIHRoZSBzcGVjaWZpYyBOZ3hFbmRQb2ludFxuICAgKi9cbiAgZGVzdHJveUVuZFBvaW50KGVuZFBvaW50SWQ6IG51bWJlcikge1xuICAgIGlmICh0aGlzLmVuZHBvaW50cyAmJiB0aGlzLmVuZHBvaW50cy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBpbmRleCA9IHRoaXMuZW5kcG9pbnRzLmZpbmRJbmRleCh4ID0+IHguZW5kcG9pbnQuZW5kUG9pbnRJZCA9PT0gZW5kUG9pbnRJZCk7XG4gICAgICB0aGlzLmVuZHBvaW50c1tpbmRleF0ucnVubmluZyA9IGZhbHNlO1xuICAgICAgdGhpcy5lbmRwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gIH1cblxuXG5cbn1cbiIsImltcG9ydCB7IE5nTW9kdWxlLCBNb2R1bGVXaXRoUHJvdmlkZXJzICB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSHR0cENsaWVudE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IE5neEVuZFBvaW50RGF0YVByb3ZpZGVyU2VydmljZX0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzL25neC1lbmRwb2ludHMtZGF0YS1wcm92aWRlci5zZXJ2aWNlJztcbmltcG9ydCB7IE5neEVuZHBvaW50U2VydmljZX0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzL25neC1lbmRwb2ludHMuc2VydmljZSc7XG5pbXBvcnQgeyBOZ3hFbmRQb2ludH0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzL25neC1lbmRwb2ludHMnO1xuaW1wb3J0IHsgTmd4TGl2ZUVuZFBvaW50fSBmcm9tICcuL25neC1lbmRwb2ludHMvbmd4LWxpdmUtZW5kLXBvaW50cy9uZ3gtbGl2ZS1lbmQtcG9pbnRzJztcbkBOZ01vZHVsZSh7XG4gIGRlY2xhcmF0aW9uczogW10sXG4gIGltcG9ydHM6IFtIdHRwQ2xpZW50TW9kdWxlXSxcbiAgZXhwb3J0czogW1xuICAgIEh0dHBDbGllbnRNb2R1bGVcbiAgXSxcbiAgcHJvdmlkZXJzOiBbTmd4RW5kcG9pbnRTZXJ2aWNlLCBOZ3hFbmRQb2ludERhdGFQcm92aWRlclNlcnZpY2UsIE5neEVuZFBvaW50LCBOZ3hMaXZlRW5kUG9pbnRdXG59KVxuZXhwb3J0IGNsYXNzIE5neEVuZHBvaW50c01vZHVsZSB7IH1cbiJdLCJuYW1lcyI6WyJxdWVyeVN0cmluZy5wYXJzZVVybCIsIm1vbWVudFJlbGF0aXZpc20ucmVsYXRpdmlzbSIsInF1ZXJ5U3RyaW5nLnN0cmluZ2lmeSIsInRzbGliXzEuX19leHRlbmRzIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7OztJQU9NLE1BQU0sR0FBRyxPQUFPO0FBQ3RCO0lBTUUsNEJBQW9CLEtBQWlCO1FBQWpCLFVBQUssR0FBTCxLQUFLLENBQVk7S0FBSzs7OztJQUUxQyxxQ0FBUTs7O0lBQVI7S0FDQzs7Ozs7Ozs7Ozs7O0lBS0ssb0NBQU87Ozs7Ozs7SUFBYixVQUFpQixXQUFtQixFQUFFLFdBQW1COzs7Ozs7d0JBQ25ELE9BQU8sR0FBRyxJQUFJLFdBQVcsRUFBRTs7O3dCQUkvQixLQUFXLEdBQUcsSUFBSSxXQUFXLEVBQUU7NEJBQzdCLE9BQU8sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQzt5QkFDakQ7d0JBQ00scUJBQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUksV0FBVyxFQUFFLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsSUFBSSxDQUNwRSxVQUFVLENBQUMsVUFBQyxHQUFHO2dDQUNiLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLEdBQUcsV0FBVyxFQUFFLEdBQUcsQ0FBQyxDQUFD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