UNPKG

@iotize/ionic

Version:

Iotize specific building blocks on top of @ionic/angular.

256 lines 39.2 kB
import { ChangeDetectorRef, Component, EventEmitter, Input, NgZone, Output, } from '@angular/core'; import { AlertController, ModalController } from '@ionic/angular'; import { isCodeError } from '@iotize/common/error'; import { TapClientError } from '@iotize/tap/client/impl'; import { BehaviorSubject, merge, of, Subject } from 'rxjs'; import { filter, shareReplay, startWith, switchMap, tap } from 'rxjs/operators'; import { CurrentDeviceService } from '../current-device.service'; import { LibError } from '../errors'; import { isNfcTapRequiredError } from '../nfc/utility'; import { PendingCallManager } from '../pending-call-manager'; import { TapValueEditorModalComponent } from '../tap-value-editor-modal/tap-value-editor-modal.component'; import * as i0 from "@angular/core"; import * as i1 from "@ionic/angular"; import * as i2 from "../current-device.service"; import * as i3 from "@angular/common"; function isTapNotConnectedError(err) { return (isNfcTapRequiredError(err) || isCodeError(TapClientError.Code.NotConnectedError, err)); } export class TapValueEditorContainerComponent { alertDialog; tapService; changeDetectorRef; ngZone; modalController; button = false; set variable(v) { this.variableChange.next(v); } inputOptions = { type: 'text', }; /** * Show refresh button */ showRefreshButton = false; /** * Show submit button */ showSubmitButton = false; /** * Show edit button */ showEditButton = false; /** * Enable edition mode */ editModeChange = new BehaviorSubject(false); loadingChange = new BehaviorSubject(false); /** * Error to display */ error; lines = 'none'; modalEdition = false; /** * Force value to display */ set value(v) { this.forceValueChange.next(v); } submit = new EventEmitter(); refresh = new EventEmitter(); pendingSubmitValue; valueToSubmit; lastReadValue; variableChange = new BehaviorSubject(undefined); variableValuesStream = this.variableChange.pipe(filter((v) => !!v), switchMap((v) => v.values), tap((v) => { this.lastReadValue = v; })); forceValueChange = new Subject(); valueToDisplay = this.editModeChange.pipe(switchMap((editMode) => { if (editMode || this.pendingSubmitValue !== undefined) { return of(this.valueToSubmit); } else { const lastValue = this.variableChange.value?.valueSnapshot; return merge(this.variableValuesStream.pipe(startWith(lastValue)), this.forceValueChange); } }), shareReplay(1)); pendingCallManager; destroyed = new Subject(); constructor(alertDialog, tapService, changeDetectorRef, ngZone, modalController) { this.alertDialog = alertDialog; this.tapService = tapService; this.changeDetectorRef = changeDetectorRef; this.ngZone = ngZone; this.modalController = modalController; } ngOnInit() { this.pendingCallManager = PendingCallManager.create(this.tapService); this.pendingCallManager.pendingCallResult.subscribe((error) => { this.pendingSubmitValue = undefined; this.valueToSubmit = undefined; this.editModeChange.next(false); this.error = error; this.changeDetectorRef.detectChanges(); }); } // hasValueChanged(value: any) { // return this._lastValueFromDevice !== value; // } submitValue() { if (this.valueToSubmit === undefined) { console.warn('No value to submit yet'); return; } this._submitValue(this.valueToSubmit); } async notifyValueChange(newValue, forceWrite = false) { if (forceWrite || this.lastReadValue !== newValue) { await this._submitValue(newValue); } } async openErrorDialog(error) { const dialog = await this.alertDialog.create({ header: 'Error', message: error.message, buttons: ['Ok'], }); await dialog.present(); } async explainWaitForSubmit() { const alertDialog = await this.alertDialog.create({ header: 'Value not sent yet', message: 'New value will be sent to the device once you are reconnected', buttons: ['Ok'], }); await alertDialog.present(); } async _submitValue(newValue) { this.submit.emit(newValue); // OLD System const variable = this.variableChange.value; if (!variable) { this.error = LibError.componentArgumentRequired(this.constructor.name, 'variable'); return; } if (!this.pendingCallManager) { return; } console.log(`[${variable.id}]`, 'Submit value', newValue); await this.startAction(this.pendingCallManager .exec(async () => { const result = await variable.write(newValue); this.editModeChange.next(false); this.forceValueChange.next(newValue); this.error = undefined; this.pendingSubmitValue = undefined; return result; }) .catch((err) => { if (!isTapNotConnectedError(err)) { console.warn(`[${variable.id}]`, `onSubmit value "${newValue}" error`, err); this.error = err; } else { this.pendingSubmitValue = newValue; this.valueToSubmit = newValue; this.editModeChange.next(false); } })); } async refreshValue() { this.refresh.next(undefined); const variable = this.variableChange.value; if (variable) { await this.startAction(variable .read() .then((newValue) => { this.forceValueChange.next(newValue); }) .catch((err) => { console.log(err); })); } } async enableEditMode() { this.modalEdition ? this.showEditModal() : this.editModeChange.next(true); } async showEditModal() { const lastValue = this.variableChange.value?.valueSnapshot; const modal = await this.modalController.create({ component: TapValueEditorModalComponent, componentProps: { inputOptions: this.inputOptions, value: lastValue, }, }); await modal.present(); const result = await modal.onDidDismiss(); if (result) { if (result.role === 'submit') { const newValue = result.data.value; await this.notifyValueChange(newValue); } } } async startAction(actions) { this.ngZone.run(async () => { this.loadingChange.next(true); try { return await actions; } catch (err) { console.warn('action failed', err); } finally { this.loadingChange.next(false); } }); } ngOnDestroy() { this.destroyed.next(); this.destroyed.complete(); this.pendingCallManager?.destroy(); } cancelEdit() { this.pendingCallManager?.cancel(); this.error = undefined; this.pendingSubmitValue = undefined; this.valueToSubmit = undefined; this.editModeChange.next(false); } /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TapValueEditorContainerComponent, deps: [{ token: i1.AlertController }, { token: i2.CurrentDeviceService }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component }); /** @nocollapse */ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: TapValueEditorContainerComponent, selector: "tap-value-editor-container", inputs: { button: "button", variable: "variable", inputOptions: "inputOptions", showRefreshButton: "showRefreshButton", showSubmitButton: "showSubmitButton", showEditButton: "showEditButton", error: "error", lines: "lines", modalEdition: "modalEdition", value: "value" }, outputs: { submit: "submit", refresh: "refresh" }, ngImport: i0, template: "<ion-item\n style=\"pointer-events: auto\"\n [lines]=\"lines\"\n [button]=\"button\"\n [ngClass]=\"{ 'item-input': editModeChange.value }\"\n>\n <ng-content></ng-content>\n <ion-buttons\n slot=\"end\"\n *ngIf=\"\n showEditButton ||\n showRefreshButton ||\n error ||\n pendingSubmitValue !== undefined\n \"\n >\n <ion-button\n (click)=\"explainWaitForSubmit(); $event.stopPropagation()\"\n *ngIf=\"pendingSubmitValue !== undefined\"\n [disabled]=\"false\"\n color=\"warning\"\n >\n <ion-icon name=\"alert-circle\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"enableEditMode(); $event.stopPropagation()\"\n class=\"btn-enable-edit-mode\"\n *ngIf=\"\n pendingSubmitValue === undefined &&\n showEditButton &&\n !editModeChange.value\n \"\n >\n <ion-icon name=\"create\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"submitValue(); $event.stopPropagation()\"\n *ngIf=\"\n showSubmitButton &&\n editModeChange.value &&\n pendingSubmitValue === undefined\n \"\n [disabled]=\"loadingChange | async\"\n class=\"btn-submit-value\"\n >\n <ion-icon name=\"send\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"cancelEdit(); $event.stopPropagation()\"\n *ngIf=\"editModeChange.value || pendingSubmitValue !== undefined\"\n [disabled]=\"loadingChange | async\"\n class=\"btn-close-edit-mode\"\n >\n <ion-icon name=\"close\"></ion-icon>\n </ion-button>\n <ion-button\n *ngIf=\"showRefreshButton\"\n (click)=\"refreshValue(); $event.stopPropagation()\"\n [disabled]=\"loadingChange | async\"\n class=\"btn-refresh-value\"\n >\n <ion-icon name=\"sync\"></ion-icon>\n </ion-button>\n <ion-button\n *ngIf=\"error\"\n (click)=\"openErrorDialog(error); $event.stopPropagation()\"\n class=\"btn-show-error\"\n >\n <ion-icon slot=\"end\" name=\"alert-circle\" color=\"danger\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-spinner *ngIf=\"loadingChange | async\" slot=\"end\"></ion-spinner>\n</ion-item>\n", styles: ["ion-buttons[slot=end]{margin-inline-start:6px}ion-item{--ion-item-background: transparent;--color: initial}\n"], dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i1.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: TapValueEditorContainerComponent, decorators: [{ type: Component, args: [{ selector: 'tap-value-editor-container', template: "<ion-item\n style=\"pointer-events: auto\"\n [lines]=\"lines\"\n [button]=\"button\"\n [ngClass]=\"{ 'item-input': editModeChange.value }\"\n>\n <ng-content></ng-content>\n <ion-buttons\n slot=\"end\"\n *ngIf=\"\n showEditButton ||\n showRefreshButton ||\n error ||\n pendingSubmitValue !== undefined\n \"\n >\n <ion-button\n (click)=\"explainWaitForSubmit(); $event.stopPropagation()\"\n *ngIf=\"pendingSubmitValue !== undefined\"\n [disabled]=\"false\"\n color=\"warning\"\n >\n <ion-icon name=\"alert-circle\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"enableEditMode(); $event.stopPropagation()\"\n class=\"btn-enable-edit-mode\"\n *ngIf=\"\n pendingSubmitValue === undefined &&\n showEditButton &&\n !editModeChange.value\n \"\n >\n <ion-icon name=\"create\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"submitValue(); $event.stopPropagation()\"\n *ngIf=\"\n showSubmitButton &&\n editModeChange.value &&\n pendingSubmitValue === undefined\n \"\n [disabled]=\"loadingChange | async\"\n class=\"btn-submit-value\"\n >\n <ion-icon name=\"send\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"cancelEdit(); $event.stopPropagation()\"\n *ngIf=\"editModeChange.value || pendingSubmitValue !== undefined\"\n [disabled]=\"loadingChange | async\"\n class=\"btn-close-edit-mode\"\n >\n <ion-icon name=\"close\"></ion-icon>\n </ion-button>\n <ion-button\n *ngIf=\"showRefreshButton\"\n (click)=\"refreshValue(); $event.stopPropagation()\"\n [disabled]=\"loadingChange | async\"\n class=\"btn-refresh-value\"\n >\n <ion-icon name=\"sync\"></ion-icon>\n </ion-button>\n <ion-button\n *ngIf=\"error\"\n (click)=\"openErrorDialog(error); $event.stopPropagation()\"\n class=\"btn-show-error\"\n >\n <ion-icon slot=\"end\" name=\"alert-circle\" color=\"danger\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-spinner *ngIf=\"loadingChange | async\" slot=\"end\"></ion-spinner>\n</ion-item>\n", styles: ["ion-buttons[slot=end]{margin-inline-start:6px}ion-item{--ion-item-background: transparent;--color: initial}\n"] }] }], ctorParameters: () => [{ type: i1.AlertController }, { type: i2.CurrentDeviceService }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i1.ModalController }], propDecorators: { button: [{ type: Input }], variable: [{ type: Input }], inputOptions: [{ type: Input }], showRefreshButton: [{ type: Input }], showSubmitButton: [{ type: Input }], showEditButton: [{ type: Input }], error: [{ type: Input }], lines: [{ type: Input }], modalEdition: [{ type: Input }], value: [{ type: Input }], submit: [{ type: Output }], refresh: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLXZhbHVlLWVkaXRvci1jb250YWluZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvaW90aXplLWlvbmljL3NyYy9saWIvdGFwLXZhbHVlLWVkaXRvci1jb250YWluZXIvdGFwLXZhbHVlLWVkaXRvci1jb250YWluZXIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvaW90aXplLWlvbmljL3NyYy9saWIvdGFwLXZhbHVlLWVkaXRvci1jb250YWluZXIvdGFwLXZhbHVlLWVkaXRvci1jb250YWluZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFDTCxNQUFNLEVBR04sTUFBTSxHQUNQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBYyxFQUFFLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDaEYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDakUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVyQyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx5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LHNwRUF5RUE7OzRGRHRDYSxnQ0FBZ0M7a0JBTDVDLFNBQVM7K0JBQ0UsNEJBQTRCOzBNQUs3QixNQUFNO3NCQUFkLEtBQUs7Z0JBRU8sUUFBUTtzQkFBcEIsS0FBSztnQkFNRyxZQUFZO3NCQUFwQixLQUFLO2dCQU9HLGlCQUFpQjtzQkFBekIsS0FBSztnQkFLRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBS0csY0FBYztzQkFBdEIsS0FBSztnQkFZRyxLQUFLO3NCQUFiLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBS08sS0FBSztzQkFBakIsS0FBSztnQkFJSSxNQUFNO3NCQUFmLE1BQU07Z0JBRUcsT0FBTztzQkFBaEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE5nWm9uZSxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE91dHB1dCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBbGVydENvbnRyb2xsZXIsIE1vZGFsQ29udHJvbGxlciB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyJztcbmltcG9ydCB7IGlzQ29kZUVycm9yIH0gZnJvbSAnQGlvdGl6ZS9jb21tb24vZXJyb3InO1xuaW1wb3J0IHsgVGFwQ2xpZW50RXJyb3IgfSBmcm9tICdAaW90aXplL3RhcC9jbGllbnQvaW1wbCc7XG5pbXBvcnQgeyBFZGl0YWJsZVZhbHVlRGF0YVN0cmVhbUludGVyZmFjZSB9IGZyb20gJ0Bpb3RpemUvdGFwL2RhdGEnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBtZXJnZSwgT2JzZXJ2YWJsZSwgb2YsIFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZpbHRlciwgc2hhcmVSZXBsYXksIHN0YXJ0V2l0aCwgc3dpdGNoTWFwLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBDdXJyZW50RGV2aWNlU2VydmljZSB9IGZyb20gJy4uL2N1cnJlbnQtZGV2aWNlLnNlcnZpY2UnO1xuaW1wb3J0IHsgTGliRXJyb3IgfSBmcm9tICcuLi9lcnJvcnMnO1xuaW1wb3J0IHsgSW5saW5lRWRpdG9yQ29tcG9uZW50IH0gZnJvbSAnLi4vaW5saW5lLWVkaXRvci9pbmxpbmUtZWRpdG9yLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBpc05mY1RhcFJlcXVpcmVkRXJyb3IgfSBmcm9tICcuLi9uZmMvdXRpbGl0eSc7XG5pbXBvcnQgeyBQZW5kaW5nQ2FsbE1hbmFnZXIgfSBmcm9tICcuLi9wZW5kaW5nLWNhbGwtbWFuYWdlcic7XG5pbXBvcnQgeyBUYXBWYWx1ZUVkaXRvck1vZGFsQ29tcG9uZW50IH0gZnJvbSAnLi4vdGFwLXZhbHVlLWVkaXRvci1tb2RhbC90YXAtdmFsdWUtZWRpdG9yLW1vZGFsLmNvbXBvbmVudCc7XG5cbmZ1bmN0aW9uIGlzVGFwTm90Q29ubmVjdGVkRXJyb3IoZXJyOiBFcnJvcikge1xuICByZXR1cm4gKFxuICAgIGlzTmZjVGFwUmVxdWlyZWRFcnJvcihlcnIpIHx8XG4gICAgaXNDb2RlRXJyb3IoVGFwQ2xpZW50RXJyb3IuQ29kZS5Ob3RDb25uZWN0ZWRFcnJvciwgZXJyKVxuICApO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0YXAtdmFsdWUtZWRpdG9yLWNvbnRhaW5lcicsXG4gIHRlbXBsYXRlVXJsOiAnLi90YXAtdmFsdWUtZWRpdG9yLWNvbnRhaW5lci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3RhcC12YWx1ZS1lZGl0b3ItY29udGFpbmVyLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIFRhcFZhbHVlRWRpdG9yQ29udGFpbmVyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBASW5wdXQoKSBidXR0b246IGJvb2xlYW4gPSBmYWxzZTtcblxuICBASW5wdXQoKSBzZXQgdmFyaWFibGUoXG4gICAgdjogRWRpdGFibGVWYWx1ZURhdGFTdHJlYW1JbnRlcmZhY2U8dW5rbm93biwgYW55PiB8IHVuZGVmaW5lZFxuICApIHtcbiAgICB0aGlzLnZhcmlhYmxlQ2hhbmdlLm5leHQodik7XG4gIH1cblxuICBASW5wdXQoKSBpbnB1dE9wdGlvbnM6IElubGluZUVkaXRvckNvbXBvbmVudC5JbnB1dE9wdGlvbnMgfCBhbnkgPSB7XG4gICAgdHlwZTogJ3RleHQnLFxuICB9O1xuXG4gIC8qKlxuICAgKiBTaG93IHJlZnJlc2ggYnV0dG9uXG4gICAqL1xuICBASW5wdXQoKSBzaG93UmVmcmVzaEJ1dHRvbiA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBTaG93IHN1Ym1pdCBidXR0b25cbiAgICovXG4gIEBJbnB1dCgpIHNob3dTdWJtaXRCdXR0b24gPSBmYWxzZTtcblxuICAvKipcbiAgICogU2hvdyBlZGl0IGJ1dHRvblxuICAgKi9cbiAgQElucHV0KCkgc2hvd0VkaXRCdXR0b24gPSBmYWxzZTtcblxuICAvKipcbiAgICogRW5hYmxlIGVkaXRpb24gbW9kZVxuICAgKi9cbiAgZWRpdE1vZGVDaGFuZ2UgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KGZhbHNlKTtcblxuICBsb2FkaW5nQ2hhbmdlID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG5cbiAgLyoqXG4gICAqIEVycm9yIHRvIGRpc3BsYXlcbiAgICovXG4gIEBJbnB1dCgpIGVycm9yPzogRXJyb3I7XG5cbiAgQElucHV0KCkgbGluZXMgPSAnbm9uZSc7XG5cbiAgQElucHV0KCkgbW9kYWxFZGl0aW9uOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIEZvcmNlIHZhbHVlIHRvIGRpc3BsYXlcbiAgICovXG4gIEBJbnB1dCgpIHNldCB2YWx1ZSh2OiBhbnkpIHtcbiAgICB0aGlzLmZvcmNlVmFsdWVDaGFuZ2UubmV4dCh2KTtcbiAgfVxuXG4gIEBPdXRwdXQoKSBzdWJtaXQgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuICBAT3V0cHV0KCkgcmVmcmVzaCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIHBlbmRpbmdTdWJtaXRWYWx1ZT86IGFueTtcblxuICB2YWx1ZVRvU3VibWl0PzogYW55O1xuXG4gIGxhc3RSZWFkVmFsdWU/OiBhbnk7XG5cbiAgcHJpdmF0ZSB2YXJpYWJsZUNoYW5nZSA9IG5ldyBCZWhhdmlvclN1YmplY3Q8XG4gICAgRWRpdGFibGVWYWx1ZURhdGFTdHJlYW1JbnRlcmZhY2U8dW5rbm93biwgYW55PiB8IHVuZGVmaW5lZFxuICA+KHVuZGVmaW5lZCk7XG5cbiAgcHVibGljIHZhcmlhYmxlVmFsdWVzU3RyZWFtOiBPYnNlcnZhYmxlPGFueT4gPSB0aGlzLnZhcmlhYmxlQ2hhbmdlLnBpcGUoXG4gICAgZmlsdGVyKCh2KSA9PiAhIXYpLFxuICAgIHN3aXRjaE1hcCgodikgPT4gdiEudmFsdWVzKSxcbiAgICB0YXAoKHYpID0+IHtcbiAgICAgIHRoaXMubGFzdFJlYWRWYWx1ZSA9IHY7XG4gICAgfSlcbiAgKTtcblxuICBmb3JjZVZhbHVlQ2hhbmdlID0gbmV3IFN1YmplY3Q8YW55PigpO1xuXG4gIHZhbHVlVG9EaXNwbGF5ID0gdGhpcy5lZGl0TW9kZUNoYW5nZS5waXBlKFxuICAgIHN3aXRjaE1hcCgoZWRpdE1vZGUpID0+IHtcbiAgICAgIGlmIChlZGl0TW9kZSB8fCB0aGlzLnBlbmRpbmdTdWJtaXRWYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBvZih0aGlzLnZhbHVlVG9TdWJtaXQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgbGFzdFZhbHVlID0gdGhpcy52YXJpYWJsZUNoYW5nZS52YWx1ZT8udmFsdWVTbmFwc2hvdDtcbiAgICAgICAgcmV0dXJuIG1lcmdlKFxuICAgICAgICAgIHRoaXMudmFyaWFibGVWYWx1ZXNTdHJlYW0ucGlwZShzdGFydFdpdGgobGFzdFZhbHVlKSksXG4gICAgICAgICAgdGhpcy5mb3JjZVZhbHVlQ2hhbmdlXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSksXG4gICAgc2hhcmVSZXBsYXkoMSlcbiAgKTtcblxuICBwcml2YXRlIHBlbmRpbmdDYWxsTWFuYWdlcj86IFBlbmRpbmdDYWxsTWFuYWdlcjtcblxuICBwcml2YXRlIGRlc3Ryb3llZCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBhbGVydERpYWxvZzogQWxlcnRDb250cm9sbGVyLFxuICAgIHByaXZhdGUgdGFwU2VydmljZTogQ3VycmVudERldmljZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBjaGFuZ2VEZXRlY3RvclJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZSxcbiAgICBwcml2YXRlIG1vZGFsQ29udHJvbGxlcjogTW9kYWxDb250cm9sbGVyXG4gICkge31cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLnBlbmRpbmdDYWxsTWFuYWdlciA9IFBlbmRpbmdDYWxsTWFuYWdlci5jcmVhdGUodGhpcy50YXBTZXJ2aWNlKTtcblxuICAgIHRoaXMucGVuZGluZ0NhbGxNYW5hZ2VyLnBlbmRpbmdDYWxsUmVzdWx0LnN1YnNjcmliZSgoZXJyb3IpID0+IHtcbiAgICAgIHRoaXMucGVuZGluZ1N1Ym1pdFZhbHVlID0gdW5kZWZpbmVkO1xuICAgICAgdGhpcy52YWx1ZVRvU3VibWl0ID0gdW5kZWZpbmVkO1xuICAgICAgdGhpcy5lZGl0TW9kZUNoYW5nZS5uZXh0KGZhbHNlKTtcbiAgICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcbiAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gaGFzVmFsdWVDaGFuZ2VkKHZhbHVlOiBhbnkpIHtcbiAgLy8gICByZXR1cm4gdGhpcy5fbGFzdFZhbHVlRnJvbURldmljZSAhPT0gdmFsdWU7XG4gIC8vIH1cblxuICBzdWJtaXRWYWx1ZSgpIHtcbiAgICBpZiAodGhpcy52YWx1ZVRvU3VibWl0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnNvbGUud2FybignTm8gdmFsdWUgdG8gc3VibWl0IHlldCcpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLl9zdWJtaXRWYWx1ZSh0aGlzLnZhbHVlVG9TdWJtaXQpO1xuICB9XG5cbiAgYXN5bmMgbm90aWZ5VmFsdWVDaGFuZ2UobmV3VmFsdWU6IGFueSwgZm9yY2VXcml0ZSA9IGZhbHNlKSB7XG4gICAgaWYgKGZvcmNlV3JpdGUgfHwgdGhpcy5sYXN0UmVhZFZhbHVlICE9PSBuZXdWYWx1ZSkge1xuICAgICAgYXdhaXQgdGhpcy5fc3VibWl0VmFsdWUobmV3VmFsdWUpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIG9wZW5FcnJvckRpYWxvZyhlcnJvcjogRXJyb3IpIHtcbiAgICBjb25zdCBkaWFsb2cgPSBhd2FpdCB0aGlzLmFsZXJ0RGlhbG9nLmNyZWF0ZSh7XG4gICAgICBoZWFkZXI6ICdFcnJvcicsXG4gICAgICBtZXNzYWdlOiBlcnJvci5tZXNzYWdlLFxuICAgICAgYnV0dG9uczogWydPayddLFxuICAgIH0pO1xuICAgIGF3YWl0IGRpYWxvZy5wcmVzZW50KCk7XG4gIH1cblxuICBhc3luYyBleHBsYWluV2FpdEZvclN1Ym1pdCgpIHtcbiAgICBjb25zdCBhbGVydERpYWxvZyA9IGF3YWl0IHRoaXMuYWxlcnREaWFsb2cuY3JlYXRlKHtcbiAgICAgIGhlYWRlcjogJ1ZhbHVlIG5vdCBzZW50IHlldCcsXG4gICAgICBtZXNzYWdlOiAnTmV3IHZhbHVlIHdpbGwgYmUgc2VudCB0byB0aGUgZGV2aWNlIG9uY2UgeW91IGFyZSByZWNvbm5lY3RlZCcsXG4gICAgICBidXR0b25zOiBbJ09rJ10sXG4gICAgfSk7XG4gICAgYXdhaXQgYWxlcnREaWFsb2cucHJlc2VudCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBfc3VibWl0VmFsdWUobmV3VmFsdWU6IGFueSkge1xuICAgIHRoaXMuc3VibWl0LmVtaXQobmV3VmFsdWUpO1xuICAgIC8vIE9MRCBTeXN0ZW1cbiAgICBjb25zdCB2YXJpYWJsZSA9IHRoaXMudmFyaWFibGVDaGFuZ2UudmFsdWU7XG4gICAgaWYgKCF2YXJpYWJsZSkge1xuICAgICAgdGhpcy5lcnJvciA9IExpYkVycm9yLmNvbXBvbmVudEFyZ3VtZW50UmVxdWlyZWQoXG4gICAgICAgIHRoaXMuY29uc3RydWN0b3IubmFtZSxcbiAgICAgICAgJ3ZhcmlhYmxlJ1xuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnBlbmRpbmdDYWxsTWFuYWdlcikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zb2xlLmxvZyhgWyR7dmFyaWFibGUuaWR9XWAsICdTdWJtaXQgdmFsdWUnLCBuZXdWYWx1ZSk7XG4gICAgYXdhaXQgdGhpcy5zdGFydEFjdGlvbihcbiAgICAgIHRoaXMucGVuZGluZ0NhbGxNYW5hZ2VyXG4gICAgICAgIC5leGVjKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB2YXJpYWJsZS53cml0ZShuZXdWYWx1ZSk7XG4gICAgICAgICAgdGhpcy5lZGl0TW9kZUNoYW5nZS5uZXh0KGZhbHNlKTtcbiAgICAgICAgICB0aGlzLmZvcmNlVmFsdWVDaGFuZ2UubmV4dChuZXdWYWx1ZSk7XG4gICAgICAgICAgdGhpcy5lcnJvciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB0aGlzLnBlbmRpbmdTdWJtaXRWYWx1ZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9KVxuICAgICAgICAuY2F0Y2goKGVycjogYW55KSA9PiB7XG4gICAgICAgICAgaWYgKCFpc1RhcE5vdENvbm5lY3RlZEVycm9yKGVycikpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgYFske3ZhcmlhYmxlLmlkfV1gLFxuICAgICAgICAgICAgICBgb25TdWJtaXQgdmFsdWUgXCIke25ld1ZhbHVlfVwiIGVycm9yYCxcbiAgICAgICAgICAgICAgZXJyXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5lcnJvciA9IGVycjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5wZW5kaW5nU3VibWl0VmFsdWUgPSBuZXdWYWx1ZTtcbiAgICAgICAgICAgIHRoaXMudmFsdWVUb1N1Ym1pdCA9IG5ld1ZhbHVlO1xuICAgICAgICAgICAgdGhpcy5lZGl0TW9kZUNoYW5nZS5uZXh0KGZhbHNlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyByZWZyZXNoVmFsdWUoKSB7XG4gICAgdGhpcy5yZWZyZXNoLm5leHQodW5kZWZpbmVkKTtcbiAgICBjb25zdCB2YXJpYWJsZSA9IHRoaXMudmFyaWFibGVDaGFuZ2UudmFsdWU7XG4gICAgaWYgKHZhcmlhYmxlKSB7XG4gICAgICBhd2FpdCB0aGlzLnN0YXJ0QWN0aW9uKFxuICAgICAgICB2YXJpYWJsZVxuICAgICAgICAgIC5yZWFkKClcbiAgICAgICAgICAudGhlbigobmV3VmFsdWU6IGFueSkgPT4ge1xuICAgICAgICAgICAgdGhpcy5mb3JjZVZhbHVlQ2hhbmdlLm5leHQobmV3VmFsdWUpO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLmNhdGNoKChlcnI6IGFueSkgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5sb2coZXJyKTtcbiAgICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBlbmFibGVFZGl0TW9kZSgpIHtcbiAgICB0aGlzLm1vZGFsRWRpdGlvbiA/IHRoaXMuc2hvd0VkaXRNb2RhbCgpIDogdGhpcy5lZGl0TW9kZUNoYW5nZS5uZXh0KHRydWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzaG93RWRpdE1vZGFsKCkge1xuICAgIGNvbnN0IGxhc3RWYWx1ZSA9IHRoaXMudmFyaWFibGVDaGFuZ2UudmFsdWU/LnZhbHVlU25hcHNob3Q7XG5cbiAgICBjb25zdCBtb2RhbCA9IGF3YWl0IHRoaXMubW9kYWxDb250cm9sbGVyLmNyZWF0ZSh7XG4gICAgICBjb21wb25lbnQ6IFRhcFZhbHVlRWRpdG9yTW9kYWxDb21wb25lbnQsXG4gICAgICBjb21wb25lbnRQcm9wczoge1xuICAgICAgICBpbnB1dE9wdGlvbnM6IHRoaXMuaW5wdXRPcHRpb25zLFxuICAgICAgICB2YWx1ZTogbGFzdFZhbHVlLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBhd2FpdCBtb2RhbC5wcmVzZW50KCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgbW9kYWwub25EaWREaXNtaXNzKCk7XG4gICAgaWYgKHJlc3VsdCkge1xuICAgICAgaWYgKHJlc3VsdC5yb2xlID09PSAnc3VibWl0Jykge1xuICAgICAgICBjb25zdCBuZXdWYWx1ZSA9IHJlc3VsdC5kYXRhLnZhbHVlO1xuICAgICAgICBhd2FpdCB0aGlzLm5vdGlmeVZhbHVlQ2hhbmdlKG5ld1ZhbHVlKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHN0YXJ0QWN0aW9uKGFjdGlvbnM6IFByb21pc2U8YW55Pik6IFByb21pc2U8YW55PiB7XG4gICAgdGhpcy5uZ1pvbmUucnVuKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMubG9hZGluZ0NoYW5nZS5uZXh0KHRydWUpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGFjdGlvbnM7XG4gICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ2FjdGlvbiBmYWlsZWQnLCBlcnIpO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5sb2FkaW5nQ2hhbmdlLm5leHQoZmFsc2UpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5kZXN0cm95ZWQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveWVkLmNvbXBsZXRlKCk7XG4gICAgdGhpcy5wZW5kaW5nQ2FsbE1hbmFnZXI/LmRlc3Ryb3koKTtcbiAgfVxuXG4gIGNhbmNlbEVkaXQoKSB7XG4gICAgdGhpcy5wZW5kaW5nQ2FsbE1hbmFnZXI/LmNhbmNlbCgpO1xuICAgIHRoaXMuZXJyb3IgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5wZW5kaW5nU3VibWl0VmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgdGhpcy52YWx1ZVRvU3VibWl0ID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuZWRpdE1vZGVDaGFuZ2UubmV4dChmYWxzZSk7XG4gIH1cbn1cbiIsIjxpb24taXRlbVxuICBzdHlsZT1cInBvaW50ZXItZXZlbnRzOiBhdXRvXCJcbiAgW2xpbmVzXT1cImxpbmVzXCJcbiAgW2J1dHRvbl09XCJidXR0b25cIlxuICBbbmdDbGFzc109XCJ7ICdpdGVtLWlucHV0JzogZWRpdE1vZGVDaGFuZ2UudmFsdWUgfVwiXG4+XG4gIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cbiAgPGlvbi1idXR0b25zXG4gICAgc2xvdD1cImVuZFwiXG4gICAgKm5nSWY9XCJcbiAgICAgIHNob3dFZGl0QnV0dG9uIHx8XG4gICAgICBzaG93UmVmcmVzaEJ1dHRvbiB8fFxuICAgICAgZXJyb3IgfHxcbiAgICAgIHBlbmRpbmdTdWJtaXRWYWx1ZSAhPT0gdW5kZWZpbmVkXG4gICAgXCJcbiAgPlxuICAgIDxpb24tYnV0dG9uXG4gICAgICAoY2xpY2spPVwiZXhwbGFpbldhaXRGb3JTdWJtaXQoKTsgJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgICpuZ0lmPVwicGVuZGluZ1N1Ym1pdFZhbHVlICE9PSB1bmRlZmluZWRcIlxuICAgICAgW2Rpc2FibGVkXT1cImZhbHNlXCJcbiAgICAgIGNvbG9yPVwid2FybmluZ1wiXG4gICAgPlxuICAgICAgPGlvbi1pY29uIG5hbWU9XCJhbGVydC1jaXJjbGVcIj48L2lvbi1pY29uPlxuICAgIDwvaW9uLWJ1dHRvbj5cbiAgICA8aW9uLWJ1dHRvblxuICAgICAgKGNsaWNrKT1cImVuYWJsZUVkaXRNb2RlKCk7ICRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgICBjbGFzcz1cImJ0bi1lbmFibGUtZWRpdC1tb2RlXCJcbiAgICAgICpuZ0lmPVwiXG4gICAgICAgIHBlbmRpbmdTdWJtaXRWYWx1ZSA9PT0gdW5kZWZpbmVkICYmXG4gICAgICAgIHNob3dFZGl0QnV0dG9uICYmXG4gICAgICAgICFlZGl0TW9kZUNoYW5nZS52YWx1ZVxuICAgICAgXCJcbiAgICA+XG4gICAgICA8aW9uLWljb24gbmFtZT1cImNyZWF0ZVwiPjwvaW9uLWljb24+XG4gICAgPC9pb24tYnV0dG9uPlxuICAgIDxpb24tYnV0dG9uXG4gICAgICAoY2xpY2spPVwic3VibWl0VmFsdWUoKTsgJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgICpuZ0lmPVwiXG4gICAgICAgIHNob3dTdWJtaXRCdXR0b24gJiZcbiAgICAgICAgZWRpdE1vZGVDaGFuZ2UudmFsdWUgJiZcbiAgICAgICAgcGVuZGluZ1N1Ym1pdFZhbHVlID09PSB1bmRlZmluZWRcbiAgICAgIFwiXG4gICAgICBbZGlzYWJsZWRdPVwibG9hZGluZ0NoYW5nZSB8IGFzeW5jXCJcbiAgICAgIGNsYXNzPVwiYnRuLXN1Ym1pdC12YWx1ZVwiXG4gICAgPlxuICAgICAgPGlvbi1pY29uIG5hbWU9XCJzZW5kXCI+PC9pb24taWNvbj5cbiAgICA8L2lvbi1idXR0b24+XG4gICAgPGlvbi1idXR0b25cbiAgICAgIChjbGljayk9XCJjYW5jZWxFZGl0KCk7ICRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiXG4gICAgICAqbmdJZj1cImVkaXRNb2RlQ2hhbmdlLnZhbHVlIHx8IHBlbmRpbmdTdWJtaXRWYWx1ZSAhPT0gdW5kZWZpbmVkXCJcbiAgICAgIFtkaXNhYmxlZF09XCJsb2FkaW5nQ2hhbmdlIHwgYXN5bmNcIlxuICAgICAgY2xhc3M9XCJidG4tY2xvc2UtZWRpdC1tb2RlXCJcbiAgICA+XG4gICAgICA8aW9uLWljb24gbmFtZT1cImNsb3NlXCI+PC9pb24taWNvbj5cbiAgICA8L2lvbi1idXR0b24+XG4gICAgPGlvbi1idXR0b25cbiAgICAgICpuZ0lmPVwic2hvd1JlZnJlc2hCdXR0b25cIlxuICAgICAgKGNsaWNrKT1cInJlZnJlc2hWYWx1ZSgpOyAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIlxuICAgICAgW2Rpc2FibGVkXT1cImxvYWRpbmdDaGFuZ2UgfCBhc3luY1wiXG4gICAgICBjbGFzcz1cImJ0bi1yZWZyZXNoLXZhbHVlXCJcbiAgICA+XG4gICAgICA8aW9uLWljb24gbmFtZT1cInN5bmNcIj48L2lvbi1pY29uPlxuICAgIDwvaW9uLWJ1dHRvbj5cbiAgICA8aW9uLWJ1dHRvblxuICAgICAgKm5nSWY9XCJlcnJvclwiXG4gICAgICAoY2xpY2spPVwib3BlbkVycm9yRGlhbG9nKGVycm9yKTsgJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCJcbiAgICAgIGNsYXNzPVwiYnRuLXNob3ctZXJyb3JcIlxuICAgID5cbiAgICAgIDxpb24taWNvbiBzbG90PVwiZW5kXCIgbmFtZT1cImFsZXJ0LWNpcmNsZVwiIGNvbG9yPVwiZGFuZ2VyXCI+PC9pb24taWNvbj5cbiAgICA8L2lvbi1idXR0b24+XG4gIDwvaW9uLWJ1dHRvbnM+XG4gIDxpb24tc3Bpbm5lciAqbmdJZj1cImxvYWRpbmdDaGFuZ2UgfCBhc3luY1wiIHNsb3Q9XCJlbmRcIj48L2lvbi1zcGlubmVyPlxuPC9pb24taXRlbT5cbiJdfQ==