ngx-endpoints
Version:
A library to dynamically load data from http endpoints / urls in angular
392 lines (382 loc) • 33.9 kB
JavaScript
import { __awaiter } 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 {?} */
const moment = moment_;
class NgxEndpointService {
/**
* @param {?} _http
*/
constructor(_http) {
this._http = _http;
}
/**
* @return {?}
*/
ngOnInit() {
}
/**
* Gets data via http client
* @template T
* @param {?} endPointUrl url that will be requested
* @param {?} httpheaders
* @return {?}
*/
getData(endPointUrl, httpheaders) {
return __awaiter(this, void 0, void 0, function* () {
/** @type {?} */
let headers = new HttpHeaders();
// tslint:disable-next-line:forin
// tslint:disable-next-line:forin
for (const key in httpheaders) {
headers = headers.append(key, httpheaders[key]);
}
return yield this._http.get(endPointUrl, { headers: headers }).pipe(catchError((err) => {
console.log('Cannot request data from ' + endPointUrl, err);
return throwError(err);
})).toPromise();
});
}
/**
* Conversion method for relative dates in querystrings
* @param {?} endPointUrl return endpointurl with converted dates in querystring
* @param {?} momentjsformat
* @return {?}
*/
convertDatesInURL(endPointUrl, momentjsformat) {
/** @type {?} */
const urlObject = parseUrl(endPointUrl);
for (const propertyName in urlObject.query) {
if (urlObject.query[propertyName].startsWith('now')) {
/** @type {?} */
const dateResult = relativism(urlObject.query[propertyName]);
urlObject.query[propertyName] = moment(dateResult).format(momentjsformat);
}
}
/** @type {?} */
const stringified = stringify(urlObject.query);
endPointUrl = urlObject.url + '?' + stringified;
return endPointUrl;
}
}
NgxEndpointService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
NgxEndpointService.ctorParameters = () => [
{ type: HttpClient }
];
/** @nocollapse */ NgxEndpointService.ngInjectableDef = defineInjectable({ factory: function NgxEndpointService_Factory() { return new NgxEndpointService(inject(HttpClient)); }, token: NgxEndpointService, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc
*/
/**
* Basic class that is used for the initial generation of the endpoints
*/
class NgxEndPointData {
constructor() {
/**
* 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 = '';
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc
*/
/**
* @template T
*/
class NgxEndPoint {
/**
* @param {?} endpointservice
* @param {?} _endpoint
*/
constructor(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
* @return {?}
*/
requestData() {
return __awaiter(this, void 0, void 0, function* () {
yield this.requestInternal();
});
}
/**
* @return {?}
*/
requestInternal() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.requestPending.getValue()) {
this.addEvent('requesting data from endpoint', this.endpoint);
this.requestPending.next(true);
this.convertDates(this.endpoint.convertDates);
yield this.request();
this.requestPending.next(false);
}
else {
this.addEvent('a request is pending', this.endpoint);
}
});
}
/**
* @param {?} conversion
* @return {?}
*/
convertDates(conversion) {
if (conversion) {
this.endpoint.endPointUrl = this.endpointservice.convertDatesInURL(this.endpoint.endPointUrl, this.endpoint.convertDatesOutputFormat);
this.addEvent('converted endpointurl', this.endpoint);
}
}
/**
* @return {?}
*/
request() {
return __awaiter(this, void 0, void 0, function* () {
try {
/** @type {?} */
const currentData = yield this.endpointservice.getData(this.endpoint.endPointUrl, this.endpoint.requestOptions);
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);
}
catch (error) {
this.addEvent(error, this.endpoint);
}
});
}
/**
* @param {?} item
* @param {?} endpointdata
* @return {?}
*/
addEvent(item, endpointdata) {
this.events.next(JSON.stringify({ event: item, endpoint: endpointdata }));
}
}
NgxEndPoint.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
NgxEndPoint.ctorParameters = () => [
{ type: NgxEndpointService },
{ type: NgxEndPointData }
];
/** @nocollapse */ NgxEndPoint.ngInjectableDef = defineInjectable({ factory: function NgxEndPoint_Factory() { return new NgxEndPoint(inject(NgxEndpointService), inject(NgxEndPointData)); }, token: NgxEndPoint, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc
*/
/**
* @template T
*/
class NgxLiveEndPoint extends NgxEndPoint {
/**
* @param {?} endpointservice
* @param {?} endpoint
*/
constructor(endpointservice, endpoint) {
super(endpointservice, endpoint);
this.endpointservice = endpointservice;
this.endpoint = endpoint;
}
/**
* 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 {?}
*/
requestData() {
return __awaiter(this, void 0, void 0, function* () {
this.running = true;
yield this.refreshData();
});
}
/**
* internal function to wait before next live request will be made
* @param {?} ms
* @return {?}
*/
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* internal function to run live requests in loop
* @return {?}
*/
refreshData() {
return __awaiter(this, void 0, void 0, function* () {
while (this.running) {
yield this.requestInternal();
yield this.sleep(this.endpoint.liveinterval);
}
});
}
}
NgxLiveEndPoint.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
NgxLiveEndPoint.ctorParameters = () => [
{ type: NgxEndpointService },
{ type: NgxEndPointData }
];
/** @nocollapse */ NgxLiveEndPoint.ngInjectableDef = defineInjectable({ factory: function NgxLiveEndPoint_Factory() { return new NgxLiveEndPoint(inject(NgxEndpointService), inject(NgxEndPointData)); }, token: NgxLiveEndPoint, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc
*/
/**
* @template T
*/
class NgxEndPointDataProviderService {
/**
* @param {?} endpointservice
*/
constructor(endpointservice) {
this.endpointservice = endpointservice;
this.endpoints = new Array();
}
/**
* Creates an NgxEndPoint and stores it in an array for proceeding
* @param {?} endpointitem
* @return {?} the created NgxEndPoint for further proceeding
*/
addEndPoint(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(x => x.endpoint.endPointId === endpointitem.endPointId)) {
throw new Error('An endpoint with id ' + endpointitem.endPointId + ' has been already added. Please choose another id.');
}
/** @type {?} */
let 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
* @return {?}
*/
destroyEndPoint(endPointId) {
if (this.endpoints && this.endpoints.length > 0) {
/** @type {?} */
const index = this.endpoints.findIndex(x => x.endpoint.endPointId === endPointId);
this.endpoints[index].running = false;
this.endpoints.splice(index, 1);
}
}
}
NgxEndPointDataProviderService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
NgxEndPointDataProviderService.ctorParameters = () => [
{ type: NgxEndpointService }
];
/** @nocollapse */ NgxEndPointDataProviderService.ngInjectableDef = defineInjectable({ factory: function NgxEndPointDataProviderService_Factory() { return new NgxEndPointDataProviderService(inject(NgxEndpointService)); }, token: NgxEndPointDataProviderService, providedIn: "root" });
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,uselessCode} checked by tsc
*/
class NgxEndpointsModule {
}
NgxEndpointsModule.decorators = [
{ type: NgModule, args: [{
declarations: [],
imports: [HttpClientModule],
exports: [
HttpClientModule
],
providers: [NgxEndpointService, NgxEndPointDataProviderService, NgxEndPoint, NgxLiveEndPoint]
},] }
];
/**
* @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+IHguZW5kcG9pbnQuZW5kUG9pbnRJZCA9PT0gZW5kUG9pbnRJZCk7XG4gICAgICB0aGlzLmVuZHBvaW50c1tpbmRleF0ucnVubmluZyA9IGZhbHNlO1xuICAgICAgdGhpcy5lbmRwb2ludHMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gIH1cblxuXG5cbn1cbiIsImltcG9ydCB7IE5nTW9kdWxlLCBNb2R1bGVXaXRoUHJvdmlkZXJzICB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSHR0cENsaWVudE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IE5neEVuZFBvaW50RGF0YVByb3ZpZGVyU2VydmljZX0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzL25neC1lbmRwb2ludHMtZGF0YS1wcm92aWRlci5zZXJ2aWNlJztcbmltcG9ydCB7IE5neEVuZHBvaW50U2VydmljZX0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzL25neC1lbmRwb2ludHMuc2VydmljZSc7XG5pbXBvcnQgeyBOZ3hFbmRQb2ludH0gZnJvbSAnLi9uZ3gtZW5kcG9pbnRzL25neC1lbmRwb2ludHMnO1xuaW1wb3J0IHsgTmd4TGl2ZUVuZFBvaW50fSBmcm9tICcuL25neC1lbmRwb2ludHMvbmd4LWxpdmUtZW5kLXBvaW50cy9uZ3gtbGl2ZS1lbmQtcG9pbnRzJztcbkBOZ01vZHVsZSh7XG4gIGRlY2xhcmF0aW9uczogW10sXG4gIGltcG9ydHM6IFtIdHRwQ2xpZW50TW9kdWxlXSxcbiAgZXhwb3J0czogW1xuICAgIEh0dHBDbGllbnRNb2R1bGVcbiAgXSxcbiAgcHJvdmlkZXJzOiBbTmd4RW5kcG9pbnRTZXJ2aWNlLCBOZ3hFbmRQb2ludERhdGFQcm92aWRlclNlcnZpY2UsIE5neEVuZFBvaW50LCBOZ3hMaXZlRW5kUG9pbnRdXG59KVxuZXhwb3J0IGNsYXNzIE5neEVuZHBvaW50c01vZHVsZSB7IH1cbiJdLCJuYW1lcyI6WyJxdWVyeVN0cmluZy5wYXJzZVVybCIsIm1vbWVudFJlbGF0aXZpc20ucmVsYXRpdmlzbSIsInF1ZXJ5U3RyaW5nLnN0cmluZ2lmeSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7TUFPTSxNQUFNLEdBQUcsT0FBTztBQUl0QixNQUFhLGtCQUFrQjs7OztJQUc3QixZQUFvQixLQUFpQjtRQUFqQixVQUFLLEdBQUwsS0FBSyxDQUFZO0tBQUs7Ozs7SUFFMUMsUUFBUTtLQUNQOzs7Ozs7OztJQUtLLE9BQU8sQ0FBSSxXQUFtQixFQUFFLFdBQW1COzs7Z0JBQ25ELE9BQU8sR0FBRyxJQUFJLFdBQVcsRUFBRTs7O1lBSS9CLEtBQUssTUFBTSxHQUFHLElBQUksV0FBVyxFQUFFO2dCQUM3QixPQUFPLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDakQ7WUFDRCxPQUFPLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUksV0FBVyxFQUFFLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsSUFBSSxDQUNwRSxVQUFVLENBQUMsQ0FBQyxHQUFHO2dCQUNiLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLEdBQUcsV0FBVyxFQUFFLEdBQUcsQ0FBQyxDQUFDO2dCQUM1RCxPQUFPLFVBQVUsQ0FBQyxHQUFH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