@iotize/ionic
Version:
Iotize specific building blocks on top of @ionic/angular.
355 lines • 68.6 kB
JavaScript
import { Component, EventEmitter, Input, Output, } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { ToastController } from '@ionic/angular';
import { CurrentDeviceService, LibError, PendingCallManager, TapInfoCacheService, TapInfoConfigService, TapInfoDAOService, TapInfoRequestService, isTapResultCodeError, } from '@iotize/ionic';
import { ResultCode } from '@iotize/tap/client/api';
import { filter, first } from 'rxjs/operators';
import { debug } from '../debug';
import { TapConfigItemStateService } from '../tap-config-item-state.service';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "@iotize/ionic";
import * as i3 from "@ionic/angular";
import * as i4 from "../tap-config-item-state.service";
import * as i5 from "@angular/common";
import * as i6 from "@iotize/app-common";
import * as i7 from "../tap-request-error-to-string.pipe";
import * as i8 from "../tap-resource-enum-translate.pipe";
import * as i9 from "../list-enum-values.pipe";
export class TapConfigItemComponent {
set info(configOrKey) {
this._resetErrors();
let config;
if (typeof configOrKey === 'object') {
const defaultConfig = this.tapInfoConfigService.findByKey(configOrKey);
if (defaultConfig) {
config = { ...defaultConfig, ...configOrKey };
}
else {
config = configOrKey;
}
}
else {
config = this.tapInfoConfigService.findByKey({
key: configOrKey,
});
if (!config) {
console.warn(`Failed to find configuration with key "${configOrKey}"`);
return;
}
}
this.onConfigChange(config);
this.updateDisplayValue();
// this.fetchValueIfRequired();
}
get info() {
return this.config;
}
get originalValue() {
return this.config.resolvedValue?.value;
}
isEdited() {
return this.field.value !== this.originalValue;
}
get config() {
if (!this._config) {
throw LibError.componentArgumentRequired('TapConfigItemComponent', 'info');
}
return this._config;
}
get inputOptions() {
return this.info.input || {};
}
get isEditable() {
return (this._config?.editable &&
this.editable &&
(!this.readError ||
!isTapResultCodeError(this.readError, ResultCode.NOT_IMPLEMENTED)));
}
constructor(formBuilder, tapService, toastController, infoResolver, tapInfoDAOService, tapInfoCacheService, tapConfigItemState, tapInfoConfigService) {
this.tapService = tapService;
this.toastController = toastController;
this.infoResolver = infoResolver;
this.tapInfoDAOService = tapInfoDAOService;
this.tapInfoCacheService = tapInfoCacheService;
this.tapConfigItemState = tapConfigItemState;
this.tapInfoConfigService = tapInfoConfigService;
this.focusOut = new EventEmitter();
this.onSubmit = new EventEmitter();
this.refresh = false;
this.editMode = false;
this.globalSubmit = false;
this.loading = false;
this.placeholder = '';
this.ressourceAvailable = true;
const form = formBuilder.nonNullable.group({
field: [''],
});
this.field = form.controls.field;
this.pendingCallManager = PendingCallManager.create(this.tapService);
}
_resetErrors() {
this.setReadError(undefined);
this.writeError = undefined;
this.ressourceAvailable = true;
}
get pendingEditCall() {
return this.pendingCallManager.pendingCall;
}
onConfigChange(config) {
this._valueSubscription?.unsubscribe();
this._cancelChangeSubscription?.unsubscribe();
this._config = config;
this._cancelChangeSubscription = this.tapConfigItemState
.getPendingChangeForKey(config)
.subscribe((v) => {
if (v === undefined) {
this.setFieldValue(this.originalValue, {
emitEvent: false,
});
}
});
this.initializeConfig();
if (config.input && config.input.type === 'password') {
this.setDisplayValue('');
}
if (config.input?.formValidators) {
this.field.setValidators(config.input.formValidators);
}
this._valueSubscription = this.tapInfoCacheService
.infoChange(config)
.subscribe((newValue) => {
config.resolvedValue = newValue;
if (newValue.error !== undefined) {
this.setReadError(newValue.error);
}
else {
this.setReadError(undefined);
if (newValue.value !== undefined) {
this.setDisplayValue(newValue.value);
this.setFieldValue(newValue.value);
}
else {
this.displayedValue = undefined;
}
}
});
}
initializeConfig() {
if (this.config.init) {
this.config
.init(this.tapService, this.config, this.infoResolver)
.catch((err) => {
this.setReadError(err);
});
}
}
setWriteError(error) {
this.writeError = error;
}
setReadError(error) {
this.readError = error;
this.ressourceAvailable = error
? !isTapResultCodeError(error, ResultCode.NOT_IMPLEMENTED)
: true;
}
ngOnInit() {
this._formValueSubscription = this.field.valueChanges.subscribe((newValue) => {
if (this.isEdited()) {
this.tapConfigItemState.setPendingChange(this.info, newValue);
}
else {
this.tapConfigItemState.removePendingChange(this.info);
}
});
}
ngOnDestroy() {
this._valueSubscription?.unsubscribe();
this._formValueSubscription?.unsubscribe();
this._cancelChangeSubscription?.unsubscribe();
this.pendingCallManager.destroy();
}
submit($event) {
if (!this.globalSubmit) {
debug('submit', $event);
this.field.updateValueAndValidity();
if (!this.field.valid) {
this.writeError = new Error('Invalid value');
return;
}
// this.onSubmit.emit(event);
const value = this.getFieldValue();
// debug(`Creating call new value:`, value, `valid: ${this.field.valid}`)
const call = async () => {
await this.tapInfoDAOService.put(this.info, value);
if (this.info.getValue) {
this.tapInfoDAOService.get(this.info).catch((err) => { });
}
return value;
};
this.runCall(call);
}
}
runCall(call) {
this.loading = true;
this.pendingCallManager
.exec(call)
.then(async (value) => {
await this.showToast('Value saved!', 'success');
this.config.resolvedValue = {
loadDate: new Date(),
value: value,
};
this.writeError = undefined;
this.editMode = false;
this.updateDisplayValue();
})
.catch((err) => {
this.setWriteError(err);
this.field.setErrors({
write: err.message,
});
})
.finally(() => {
this.loading = false;
});
}
onValueClick($event) {
$event.preventDefault();
if (this.isEditable) {
this.editMode = true;
}
}
async explainPendingCall() {
await this.showToast('Please reconnect your Tap to save pending changes');
}
onFocusOut() {
this.focusOut.emit(this.field.value);
}
cancelEdit($event) {
debug(this.config.key, 'cancel edit', $event);
if (this.globalSubmit) {
this.restaureValue();
}
else {
this.writeError = undefined;
if (this.pendingCallManager.hasPendingCall()) {
this.pendingCallManager.cancel();
}
else {
this.editMode = false;
this.restaureValue();
}
}
}
getFieldValue() {
let fieldValue = this.field.value;
if (this.config.editFormatter) {
fieldValue = this.config.editFormatter.read(fieldValue);
}
return fieldValue;
}
async showToast(msg, color) {
const toast = await this.toastController.create({
message: msg,
duration: 2000,
position: 'bottom',
color: color,
});
await toast.present();
}
refreshValue() {
return this._execRefreshKey();
}
_execRefreshKey() {
return this.infoResolver.refreshKey(this.config);
}
restaureValue() {
this.setFieldValue(this.originalValue);
this.tapConfigItemState.removePendingChange(this.config);
}
setFieldValue(value, options) {
const formattedValue = this.config.editFormatter
? this.config.editFormatter.write(value)
: value;
debug(this.config.key, 'setFieldValue with', formattedValue);
this.field.setValue(formattedValue, options);
}
updateDisplayValue() {
if (this.config.resolvedValue) {
if (this.config.resolvedValue.error) {
this.displayedValue = this.config.resolvedValue.error.message;
}
else {
const value = this.config.resolvedValue.value;
this.setDisplayValue(value);
this.setFieldValue(value);
}
}
else {
debug(this.config.key, 'Value is not loaded yet', this.config.resolvedValue);
this.displayedValue = undefined;
}
}
setDisplayValue(value) {
if (value instanceof Error) {
return value.message;
}
else {
let stringValue;
if (this.config.viewFormatter) {
stringValue = this.config.viewFormatter(value);
}
else if (typeof value === 'object') {
stringValue = JSON.stringify(value);
}
else if (this.config.input?.type === 'select') {
stringValue =
this.getSelectedOption(value)?.text ||
(value !== undefined ? value.toString() : '');
}
else {
stringValue = value !== undefined ? value.toString() : '';
}
// debug(`${this.config.key} setDisplayValue with`, stringValue);
this.displayedValue = stringValue;
return stringValue;
}
}
getSelectedOption(value) {
return this.config.input?.options?.find((option) => option.key === value);
}
get selectedOption() {
return this.getSelectedOption(this.config.resolvedValue?.value);
}
async fetchValue() {
if (this.config.getValue) {
this.infoResolver.refreshKey(this.config);
const result = await this.tapInfoCacheService
.infoChange(this.config)
.pipe(filter((v) => !!v.loadDate), first())
.toPromise();
}
}
}
/** @nocollapse */ TapConfigItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemComponent, deps: [{ token: i1.FormBuilder }, { token: i2.CurrentDeviceService }, { token: i3.ToastController }, { token: i2.TapInfoRequestService }, { token: i2.TapInfoDAOService }, { token: i2.TapInfoCacheService }, { token: i4.TapConfigItemStateService }, { token: i2.TapInfoConfigService }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TapConfigItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TapConfigItemComponent, selector: "tap-config-item", inputs: { editable: "editable", info: "info", refresh: "refresh", editMode: "editMode", globalSubmit: "globalSubmit" }, outputs: { focusOut: "focusOut", onSubmit: "onSubmit" }, ngImport: i0, template: "<ion-item *ngIf=\"_config\" [lines]=\"isEditable ? '' : 'none'\">\n <ion-skeleton-text\n animated\n *ngIf=\"\n displayedValue === undefined && readError === undefined;\n else valueFetchedTemplate\n \"\n ></ion-skeleton-text>\n <ng-template #valueFetchedTemplate>\n <ng-container\n *ngIf=\"ressourceAvailable; else ressourceNotAvailableTemplate\"\n >\n <ng-container *ngIf=\"!editMode || !isEditable; else editModeTemplate\">\n <ion-text\n color=\"warning\"\n class=\"read-value-error\"\n (click)=\"onValueClick($event)\"\n [class]=\"isEditable ? 'cell' : ''\"\n *ngIf=\"readError; else noReadErrorTemplate\"\n >\n <ion-icon name=\"alert-circle\"></ion-icon>\n {{ readError | tapRequestErrorToString }}\n </ion-text>\n <ng-template #noReadErrorTemplate>\n <ng-container [ngSwitch]=\"inputOptions.type\">\n <ng-container *ngSwitchCase=\"'toggle'\">\n <ion-toggle [disabled]=\"true\" [checked]=\"field.value\"></ion-toggle\n ></ng-container>\n <div\n (click)=\"onValueClick($event)\"\n *ngSwitchCase=\"'select'\"\n class=\"item-value\"\n [class]=\"isEditable ? 'cell' : ''\"\n >\n <ion-icon\n *ngIf=\"selectedOption?.icon\"\n [name]=\"selectedOption?.icon\"\n ></ion-icon>\n <ion-text class=\"tap-config-item-value\">\n {{ displayedValue }}\n </ion-text>\n </div>\n <ion-text\n (click)=\"onValueClick($event)\"\n class=\"item-value tap-config-item-value\"\n *ngSwitchDefault\n [class]=\"isEditable ? 'cell' : ''\"\n >\n {{ displayedValue }}\n </ion-text>\n </ng-container>\n </ng-template>\n </ng-container>\n <ng-template #editModeTemplate>\n <ng-container [ngSwitch]=\"inputOptions.type\">\n <ion-toggle\n *ngSwitchCase=\"'toggle'\"\n [disabled]=\"loading || !!pendingEditCall\"\n [formControl]=\"field\"\n ></ion-toggle>\n <ion-select\n style=\"max-width: 100% !important\"\n *ngSwitchCase=\"'select'\"\n [formControl]=\"field\"\n [multiple]=\"inputOptions.multiple\"\n >\n <ion-select-option\n *ngFor=\"let option of inputOptions.options\"\n [value]=\"option.key\"\n >\n <ion-icon *ngIf=\"option.icon\" [name]=\"option.icon\"></ion-icon>\n {{ option.text }}\n </ion-select-option>\n <ion-select-option\n *ngFor=\"let enumValue of inputOptions.enum?.data | listEnumValues\"\n [value]=\"enumValue\"\n >\n <ion-icon\n [name]=\"\n enumValue\n | tapResourceEnumTranslate : 'icon' : inputOptions.enum\n | async\n \"\n ></ion-icon>\n {{\n enumValue\n | tapResourceEnumTranslate : 'title' : inputOptions.enum\n | async\n }}\n </ion-select-option>\n </ion-select>\n <ion-input\n *ngSwitchDefault\n (keydown.enter)=\"submit($event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n [disabled]=\"!!pendingEditCall\"\n [maxlength]=\"inputOptions.maxLength\"\n [minlength]=\"inputOptions.minLength\"\n [max]=\"inputOptions.max\"\n [min]=\"inputOptions.min\"\n [pattern]=\"inputOptions.pattern\"\n [placeholder]=\"placeholder\"\n [type]=\"inputOptions.type\"\n appAutofocus\n class=\"cellInput\"\n [formControl]=\"field\"\n >\n </ion-input>\n </ng-container>\n </ng-template>\n <ion-buttons slot=\"end\">\n <ion-button\n (click)=\"explainPendingCall()\"\n *ngIf=\"pendingEditCall\"\n [disabled]=\"false\"\n color=\"warning\"\n >\n <ion-icon name=\"alert-circle\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"editMode = true\"\n *ngIf=\"!globalSubmit && !editMode && info.putValue\"\n >\n <ion-icon name=\"create\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"submit($event)\"\n *ngIf=\"!globalSubmit && editMode && !pendingEditCall\"\n [disabled]=\"loading || pendingEditCall\"\n >\n <ion-icon name=\"send\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"cancelEdit()\"\n *ngIf=\"isEditable && editMode && (!globalSubmit || isEdited())\"\n color=\"quaternary\"\n [disabled]=\"loading\"\n >\n <ion-icon name=\"close\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"refreshValue()\"\n *ngIf=\"refresh && info.getValue && !editMode\"\n [disabled]=\"loading\"\n >\n <ion-icon name=\"sync\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-spinner *ngIf=\"loading\" slot=\"end\"></ion-spinner>\n </ng-container>\n <ng-template #ressourceNotAvailableTemplate>\n <ion-text color=\"warning\" class=\"read-value-error\">\n <ion-icon name=\"alert-circle\"></ion-icon>\n Not available with your firmware version or Tap model\n </ion-text>\n </ng-template>\n </ng-template>\n</ion-item>\n<ion-item *ngIf=\"writeError\">\n <ion-text color=\"danger\" class=\"tap-config-item-error\">\n <ion-icon name=\"alert-circle\"></ion-icon>\n Failed to write value: {{ writeError | tapRequestErrorToString }}\n </ion-text>\n</ion-item>\n<app-common-form-error-item\n [formControlRef]=\"field\"\n></app-common-form-error-item>\n", styles: [".cell{border:2px solid transparent;padding:11px 0;width:100%;height:100%}.cell:hover{cursor:pointer;border:2px dashed #c8c8c8}ion-item{--padding-start: 0px}.cellInput{border:2px solid transparent;padding:11px 20px;width:100%;height:100%}ion-select{min-width:150px}.read-value-error{font-weight:700}ion-buttons{margin-inline-start:5px}.item-value,ion-select,ion-input{font-weight:700;font-weight:1.05em}\n"], dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i5.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i5.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i3.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: i3.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i3.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i3.IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "debounce", "disabled", "enterkeyhint", "inputmode", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: i3.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i3.IonSelect, selector: "ion-select", inputs: ["cancelText", "compareWith", "disabled", "interface", "interfaceOptions", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "value"] }, { kind: "component", type: i3.IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: i3.IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: i3.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i3.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i3.IonToggle, selector: "ion-toggle", inputs: ["checked", "color", "disabled", "enableOnOffLabels", "mode", "name", "value"] }, { kind: "directive", type: i3.BooleanValueAccessor, selector: "ion-checkbox,ion-toggle" }, { kind: "directive", type: i3.SelectValueAccessor, selector: "ion-range, ion-select, ion-radio-group, ion-segment, ion-datetime" }, { kind: "directive", type: i3.TextValueAccessor, selector: "ion-input:not([type=number]),ion-textarea,ion-searchbar" }, { kind: "directive", type: i2.AutoFocusDirective, selector: "[appAutofocus]", inputs: ["appAutoFocus"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinLengthValidator, selector: "[minlength][formControlName],[minlength][formControl],[minlength][ngModel]", inputs: ["minlength"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i6.FormErrorItemComponent, selector: "app-common-form-error-item", inputs: ["formControlRef"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i7.TapRequestErrorToStringPipe, name: "tapRequestErrorToString" }, { kind: "pipe", type: i8.TapResourceEnumTranslatePipe, name: "tapResourceEnumTranslate" }, { kind: "pipe", type: i9.ListEnumValuesPipe, name: "listEnumValues" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapConfigItemComponent, decorators: [{
type: Component,
args: [{ selector: 'tap-config-item', template: "<ion-item *ngIf=\"_config\" [lines]=\"isEditable ? '' : 'none'\">\n <ion-skeleton-text\n animated\n *ngIf=\"\n displayedValue === undefined && readError === undefined;\n else valueFetchedTemplate\n \"\n ></ion-skeleton-text>\n <ng-template #valueFetchedTemplate>\n <ng-container\n *ngIf=\"ressourceAvailable; else ressourceNotAvailableTemplate\"\n >\n <ng-container *ngIf=\"!editMode || !isEditable; else editModeTemplate\">\n <ion-text\n color=\"warning\"\n class=\"read-value-error\"\n (click)=\"onValueClick($event)\"\n [class]=\"isEditable ? 'cell' : ''\"\n *ngIf=\"readError; else noReadErrorTemplate\"\n >\n <ion-icon name=\"alert-circle\"></ion-icon>\n {{ readError | tapRequestErrorToString }}\n </ion-text>\n <ng-template #noReadErrorTemplate>\n <ng-container [ngSwitch]=\"inputOptions.type\">\n <ng-container *ngSwitchCase=\"'toggle'\">\n <ion-toggle [disabled]=\"true\" [checked]=\"field.value\"></ion-toggle\n ></ng-container>\n <div\n (click)=\"onValueClick($event)\"\n *ngSwitchCase=\"'select'\"\n class=\"item-value\"\n [class]=\"isEditable ? 'cell' : ''\"\n >\n <ion-icon\n *ngIf=\"selectedOption?.icon\"\n [name]=\"selectedOption?.icon\"\n ></ion-icon>\n <ion-text class=\"tap-config-item-value\">\n {{ displayedValue }}\n </ion-text>\n </div>\n <ion-text\n (click)=\"onValueClick($event)\"\n class=\"item-value tap-config-item-value\"\n *ngSwitchDefault\n [class]=\"isEditable ? 'cell' : ''\"\n >\n {{ displayedValue }}\n </ion-text>\n </ng-container>\n </ng-template>\n </ng-container>\n <ng-template #editModeTemplate>\n <ng-container [ngSwitch]=\"inputOptions.type\">\n <ion-toggle\n *ngSwitchCase=\"'toggle'\"\n [disabled]=\"loading || !!pendingEditCall\"\n [formControl]=\"field\"\n ></ion-toggle>\n <ion-select\n style=\"max-width: 100% !important\"\n *ngSwitchCase=\"'select'\"\n [formControl]=\"field\"\n [multiple]=\"inputOptions.multiple\"\n >\n <ion-select-option\n *ngFor=\"let option of inputOptions.options\"\n [value]=\"option.key\"\n >\n <ion-icon *ngIf=\"option.icon\" [name]=\"option.icon\"></ion-icon>\n {{ option.text }}\n </ion-select-option>\n <ion-select-option\n *ngFor=\"let enumValue of inputOptions.enum?.data | listEnumValues\"\n [value]=\"enumValue\"\n >\n <ion-icon\n [name]=\"\n enumValue\n | tapResourceEnumTranslate : 'icon' : inputOptions.enum\n | async\n \"\n ></ion-icon>\n {{\n enumValue\n | tapResourceEnumTranslate : 'title' : inputOptions.enum\n | async\n }}\n </ion-select-option>\n </ion-select>\n <ion-input\n *ngSwitchDefault\n (keydown.enter)=\"submit($event)\"\n (keydown.escape)=\"cancelEdit($event)\"\n [disabled]=\"!!pendingEditCall\"\n [maxlength]=\"inputOptions.maxLength\"\n [minlength]=\"inputOptions.minLength\"\n [max]=\"inputOptions.max\"\n [min]=\"inputOptions.min\"\n [pattern]=\"inputOptions.pattern\"\n [placeholder]=\"placeholder\"\n [type]=\"inputOptions.type\"\n appAutofocus\n class=\"cellInput\"\n [formControl]=\"field\"\n >\n </ion-input>\n </ng-container>\n </ng-template>\n <ion-buttons slot=\"end\">\n <ion-button\n (click)=\"explainPendingCall()\"\n *ngIf=\"pendingEditCall\"\n [disabled]=\"false\"\n color=\"warning\"\n >\n <ion-icon name=\"alert-circle\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"editMode = true\"\n *ngIf=\"!globalSubmit && !editMode && info.putValue\"\n >\n <ion-icon name=\"create\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"submit($event)\"\n *ngIf=\"!globalSubmit && editMode && !pendingEditCall\"\n [disabled]=\"loading || pendingEditCall\"\n >\n <ion-icon name=\"send\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"cancelEdit()\"\n *ngIf=\"isEditable && editMode && (!globalSubmit || isEdited())\"\n color=\"quaternary\"\n [disabled]=\"loading\"\n >\n <ion-icon name=\"close\"></ion-icon>\n </ion-button>\n <ion-button\n (click)=\"refreshValue()\"\n *ngIf=\"refresh && info.getValue && !editMode\"\n [disabled]=\"loading\"\n >\n <ion-icon name=\"sync\"></ion-icon>\n </ion-button>\n </ion-buttons>\n <ion-spinner *ngIf=\"loading\" slot=\"end\"></ion-spinner>\n </ng-container>\n <ng-template #ressourceNotAvailableTemplate>\n <ion-text color=\"warning\" class=\"read-value-error\">\n <ion-icon name=\"alert-circle\"></ion-icon>\n Not available with your firmware version or Tap model\n </ion-text>\n </ng-template>\n </ng-template>\n</ion-item>\n<ion-item *ngIf=\"writeError\">\n <ion-text color=\"danger\" class=\"tap-config-item-error\">\n <ion-icon name=\"alert-circle\"></ion-icon>\n Failed to write value: {{ writeError | tapRequestErrorToString }}\n </ion-text>\n</ion-item>\n<app-common-form-error-item\n [formControlRef]=\"field\"\n></app-common-form-error-item>\n", styles: [".cell{border:2px solid transparent;padding:11px 0;width:100%;height:100%}.cell:hover{cursor:pointer;border:2px dashed #c8c8c8}ion-item{--padding-start: 0px}.cellInput{border:2px solid transparent;padding:11px 20px;width:100%;height:100%}ion-select{min-width:150px}.read-value-error{font-weight:700}ion-buttons{margin-inline-start:5px}.item-value,ion-select,ion-input{font-weight:700;font-weight:1.05em}\n"] }]
}], ctorParameters: function () { return [{ type: i1.FormBuilder }, { type: i2.CurrentDeviceService }, { type: i3.ToastController }, { type: i2.TapInfoRequestService }, { type: i2.TapInfoDAOService }, { type: i2.TapInfoCacheService }, { type: i4.TapConfigItemStateService }, { type: i2.TapInfoConfigService }]; }, propDecorators: { focusOut: [{
type: Output
}], onSubmit: [{
type: Output
}], editable: [{
type: Input
}], info: [{
type: Input
}], refresh: [{
type: Input
}], editMode: [{
type: Input
}], globalSubmit: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9jb25maWcvc3JjL2xpYi90YXAtY29uZmlnLWl0ZW0vdGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9jb25maWcvc3JjL2xpYi90YXAtY29uZmlnLWl0ZW0vdGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFHTCxNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFtQixXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDakQsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixRQUFRLEVBQ1Isa0JBQWtCLEVBR2xCLG1CQUFtQixFQUNuQixvQkFBb0IsRUFDcEIsaUJBQWlCLEVBRWpCLHFCQUFxQixFQUVyQixvQkFBb0IsR0FDckIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRXBELE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDL0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQzs7Ozs7Ozs7Ozs7QUFTN0UsTUFBTSxPQUFPLHNCQUFzQjtJQVdqQyxJQUFhLElBQUksQ0FBQyxXQUErQztRQUMvRCxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDcEIsSUFBSSxNQUFnQyxDQUFDO1FB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QUFVO1FBQ2QsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRTtZQUN4QixJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDMUMsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsbUJBQW1CO2lCQUMxQyxVQUFVLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztpQkFDdkIsSUFBSSxDQUNILE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFDM0IsS0FBSyxFQUFFLENBQ1I7aUJBQ0EsU0FBUyxFQUFFLENBQUM7U0FDaEI7SUFDSCxDQUFDOzt1SUEzWFUsc0JBQXNCOzJIQUF0QixzQkFBc0Isd09DckNuQyx5OUxBdUtBOzRGRGxJYSxzQkFBc0I7a0JBTGxDLFNBQVM7K0JBQ0UsaUJBQWlCO29WQU9qQixRQUFRO3NCQUFqQixNQUFNO2dCQUNHLFFBQVE7c0JBQWpCLE1BQU07Z0JBS0UsUUFBUTtzQkFBaEIsS0FBSztnQkFFTyxJQUFJO3NCQUFoQixLQUFLO2dCQXdCRyxPQUFPO3NCQUFmLEtBQUs7Z0JBRUcsUUFBUTtzQkFBaEIsS0FBSztnQkFFRyxZQUFZO3NCQUFwQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUJ1aWxkZXIgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBUb2FzdENvbnRyb2xsZXIgfSBmcm9tICdAaW9uaWMvYW5ndWxhcic7XG5pbXBvcnQge1xuICBDdXJyZW50RGV2aWNlU2VydmljZSxcbiAgTGliRXJyb3IsXG4gIFBlbmRpbmdDYWxsTWFuYWdlcixcbiAgVGFwQ29uZmlnSXRlbSxcbiAgVGFwSW5mbyxcbiAgVGFwSW5mb0NhY2hlU2VydmljZSxcbiAgVGFwSW5mb0NvbmZpZ1NlcnZpY2UsXG4gIFRhcEluZm9EQU9TZXJ2aWNlLFxuICBUYXBJbmZvSG9sZGVyLFxuICBUYXBJbmZvUmVxdWVzdFNlcnZpY2UsXG4gIFRhcFJlc291cmNlS2V5LFxuICBpc1RhcFJlc3VsdENvZGVFcnJvcixcbn0gZnJvbSAnQGlvdGl6ZS9pb25pYyc7XG5pbXBvcnQgeyBSZXN1bHRDb2RlIH0gZnJvbSAnQGlvdGl6ZS90YXAvY2xpZW50L2FwaSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGZpbHRlciwgZmlyc3QgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBkZWJ1ZyB9IGZyb20gJy4uL2RlYnVnJztcbmltcG9ydCB7IFRhcENvbmZpZ0l0ZW1TdGF0ZVNlcnZpY2UgfSBmcm9tICcuLi90YXAtY29uZmlnLWl0ZW0tc3RhdGUuc2VydmljZSc7XG5cbnR5cGUgQ29sb3JUeXBlID0gYW55O1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0YXAtY29uZmlnLWl0ZW0nLFxuICB0ZW1wbGF0ZVVybDogJy4vdGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vdGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIFRhcENvbmZpZ0l0ZW1Db21wb25lbnQ8VmFsdWVUeXBlID0gYW55PlxuICBpbXBsZW1lbnRzIE9uRGVzdHJveSwgT25Jbml0XG57XG4gIEBPdXRwdXQoKSBmb2N1c091dDogRXZlbnRFbWl0dGVyPG51bWJlcj4gPSBuZXcgRXZlbnRFbWl0dGVyPG51bWJlcj4oKTtcbiAgQE91dHB1dCgpIG9uU3VibWl0OiBFdmVudEVtaXR0ZXI8e1xuICAgIHRhcmdldDogeyB2YWx1ZTogc3RyaW5nIH07XG4gIH0+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBwZW5kaW5nQ2FsbE1hbmFnZXI6IFBlbmRpbmdDYWxsTWFuYWdlcjtcblxuICBASW5wdXQoKSBlZGl0YWJsZT86IGJvb2xlYW47XG5cbiAgQElucHV0KCkgc2V0IGluZm8oY29uZmlnT3JLZXk6IFRhcENvbmZpZ0l0ZW08VmFsdWVUeXBlPiB8IFRhcEluZm8pIHtcbiAgICB0aGlzLl9yZXNldEVycm9ycygpO1xuICAgIGxldCBjb25maWc6IFRhcENvbmZpZ0l0ZW08VmFsdWVUeXBlPjtcbiAgICBpZiAodHlwZW9mIGNvbmZpZ09yS2V5ID09PSAnb2JqZWN0Jykge1xuICAgICAgY29uc3QgZGVmYXVsdENvbmZpZyA9IHRoaXMudGFwSW5mb0NvbmZpZ1NlcnZpY2UuZmluZEJ5S2V5KGNvbmZpZ09yS2V5KTtcbiAgICAgIGlmIChkZWZhdWx0Q29uZmlnKSB7XG4gICAgICAgIGNvbmZpZyA9IHsgLi4uZGVmYXVsdENvbmZpZywgLi4uY29uZmlnT3JLZXkgfTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbmZpZyA9IGNvbmZpZ09yS2V5O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBjb25maWcgPSB0aGlzLnRhcEluZm9Db25maWdTZXJ2aWNlLmZpbmRCeUtleSh7XG4gICAgICAgIGtleTogY29uZmlnT3JLZXkgYXMgVGFwUmVzb3VyY2VLZXksXG4gICAgICB9KSE7XG4gICAgICBpZiAoIWNvbmZpZykge1xuICAgICAgICBjb25zb2xlLndhcm4oYEZhaWxlZCB0byBmaW5kIGNvbmZpZ3VyYXRpb24gd2l0aCBrZXkgXCIke2NvbmZpZ09yS2V5fVwiYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5vbkNvbmZpZ0NoYW5nZShjb25maWcpO1xuICAgIHRoaXMudXBkYXRlRGlzcGxheVZhbHVlKCk7XG4gICAgLy8gdGhpcy5mZXRjaFZhbHVlSWZSZXF1aXJlZCgpO1xuICB9XG5cbiAgQElucHV0KCkgcmVmcmVzaCA9IGZhbHNlO1xuXG4gIEBJbnB1dCgpIGVkaXRNb2RlID0gZmFsc2U7XG5cbiAgQElucHV0KCkgZ2xvYmFsU3VibWl0ID0gZmFsc2U7XG5cbiAgZ2V0IGluZm8oKTogVGFwQ29uZmlnSXRlbTxWYWx1ZVR5cGU+IHtcbiAgICByZXR1cm4gdGhpcy5jb25maWc7XG4gIH1cblxuICBnZXQgb3JpZ2luYWxWYWx1ZSgpOiBWYWx1ZVR5cGUgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5yZXNvbHZlZFZhbHVlPy52YWx1ZTtcbiAgfVxuXG4gIHByaXZhdGUgX3ZhbHVlU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uO1xuICBwcml2YXRlIF9mb3JtVmFsdWVTdWJzY3JpcHRpb24/OiBTdWJzY3JpcHRpb247XG4gIHByaXZhdGUgX2NhbmNlbENoYW5nZVN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcblxuICBfY29uZmlnPzogVGFwQ29uZmlnSXRlbTxWYWx1ZVR5cGU+O1xuICBsb2FkaW5nID0gZmFsc2U7XG4gIHJlYWRFcnJvcj86IEVycm9yO1xuICB3cml0ZUVycm9yPzogRXJyb3I7XG5cbiAgcGxhY2Vob2xkZXIgPSAnJztcblxuICBkaXNwbGF5ZWRWYWx1ZT86IHN0cmluZztcblxuICBmaWVsZDogQWJzdHJhY3RDb250cm9sO1xuXG4gIHJlc3NvdXJjZUF2YWlsYWJsZSA9IHRydWU7XG5cbiAgaXNFZGl0ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuZmllbGQudmFsdWUgIT09IHRoaXMub3JpZ2luYWxWYWx1ZTtcbiAgfVxuXG4gIGdldCBjb25maWcoKTogVGFwQ29uZmlnSXRlbTxWYWx1ZVR5cGU+IHtcbiAgICBpZiAoIXRoaXMuX2NvbmZpZykge1xuICAgICAgdGhyb3cgTGliRXJyb3IuY29tcG9uZW50QXJndW1lbnRSZXF1aXJlZChcbiAgICAgICAgJ1RhcENvbmZpZ0l0ZW1Db21wb25lbnQnLFxuICAgICAgICAnaW5mbydcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9jb25maWc7XG4gIH1cblxuICBnZXQgaW5wdXRPcHRpb25zKCkge1xuICAgIHJldHVybiB0aGlzLmluZm8uaW5wdXQgfHwge307XG4gIH1cblxuICBnZXQgaXNFZGl0YWJsZSgpIHtcbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy5fY29uZmlnPy5lZGl0YWJsZSAmJlxuICAgICAgdGhpcy5lZGl0YWJsZSAmJlxuICAgICAgKCF0aGlzLnJlYWRFcnJvciB8fFxuICAgICAgICAhaXNUYXBSZXN1bHRDb2RlRXJyb3IodGhpcy5yZWFkRXJyb3IsIFJlc3VsdENvZGUuTk9UX0lNUExFTUVOVEVEKSlcbiAgICApO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgZm9ybUJ1aWxkZXI6IEZvcm1CdWlsZGVyLFxuICAgIHByaXZhdGUgdGFwU2VydmljZTogQ3VycmVudERldmljZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0b2FzdENvbnRyb2xsZXI6IFRvYXN0Q29udHJvbGxlcixcbiAgICBwcml2YXRlIGluZm9SZXNvbHZlcjogVGFwSW5mb1JlcXVlc3RTZXJ2aWNlLFxuICAgIHByaXZhdGUgdGFwSW5mb0RBT1NlcnZpY2U6IFRhcEluZm9EQU9TZXJ2aWNlLFxuICAgIHByaXZhdGUgdGFwSW5mb0NhY2hlU2VydmljZTogVGFwSW5mb0NhY2hlU2VydmljZSxcbiAgICBwcml2YXRlIHRhcENvbmZpZ0l0ZW1TdGF0ZTogVGFwQ29uZmlnSXRlbVN0YXRlU2VydmljZSxcbiAgICBwcml2YXRlIHRhcEluZm9Db25maWdTZXJ2aWNlOiBUYXBJbmZvQ29uZmlnU2VydmljZVxuICApIHtcbiAgICBjb25zdCBmb3JtID0gZm9ybUJ1aWxkZXIubm9uTnVsbGFibGUuZ3JvdXAoe1xuICAgICAgZmllbGQ6IFsnJ10sXG4gICAgfSk7XG4gICAgdGhpcy5maWVsZCA9IGZvcm0uY29udHJvbHMuZmllbGQ7XG4gICAgdGhpcy5wZW5kaW5nQ2FsbE1hbmFnZXIgPSBQZW5kaW5nQ2FsbE1hbmFnZXIuY3JlYXRlKHRoaXMudGFwU2VydmljZSk7XG4gIH1cblxuICBwcml2YXRlIF9yZXNldEVycm9ycygpIHtcbiAgICB0aGlzLnNldFJlYWRFcnJvcih1bmRlZmluZWQpO1xuICAgIHRoaXMud3JpdGVFcnJvciA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLnJlc3NvdXJjZUF2YWlsYWJsZSA9IHRydWU7XG4gIH1cblxuICBnZXQgcGVuZGluZ0VkaXRDYWxsKCkge1xuICAgIHJldHVybiB0aGlzLnBlbmRpbmdDYWxsTWFuYWdlci5wZW5kaW5nQ2FsbDtcbiAgfVxuXG4gIHByaXZhdGUgb25Db25maWdDaGFuZ2UoY29uZmlnOiBUYXBDb25maWdJdGVtPGFueT4pIHtcbiAgICB0aGlzLl92YWx1ZVN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLl9jYW5jZWxDaGFuZ2VTdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5fY29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMuX2NhbmNlbENoYW5nZVN1YnNjcmlwdGlvbiA9IHRoaXMudGFwQ29uZmlnSXRlbVN0YXRlXG4gICAgICAuZ2V0UGVuZGluZ0NoYW5nZUZvcktleShjb25maWcpXG4gICAgICAuc3Vic2NyaWJlKCh2KSA9PiB7XG4gICAgICAgIGlmICh2ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICB0aGlzLnNldEZpZWxkVmFsdWUodGhpcy5vcmlnaW5hbFZhbHVlLCB7XG4gICAgICAgICAgICBlbWl0RXZlbnQ6IGZhbHNlLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB0aGlzLmluaXRpYWxpemVDb25maWcoKTtcbiAgICBpZiAoY29uZmlnLmlucHV0ICYmIGNvbmZpZy5pbnB1dC50eXBlID09PSAncGFzc3dvcmQnKSB7XG4gICAgICB0aGlzLnNldERpc3BsYXlWYWx1ZSgnJyBhcyBhbnkpO1xuICAgIH1cbiAgICBpZiAoY29uZmlnLmlucHV0Py5mb3JtVmFsaWRhdG9ycykge1xuICAgICAgdGhpcy5maWVsZC5zZXRWYWxpZGF0b3JzKGNvbmZpZy5pbnB1dC5mb3JtVmFsaWRhdG9ycyk7XG4gICAgfVxuICAgIHRoaXMuX3ZhbHVlU3Vic2NyaXB0aW9uID0gdGhpcy50YXBJbmZvQ2FjaGVTZXJ2aWNlXG4gICAgICAuaW5mb0NoYW5nZShjb25maWcpXG4gICAgICAuc3Vic2NyaWJlKChuZXdWYWx1ZTogVGFwSW5mb0hvbGRlcikgPT4ge1xuICAgICAgICBjb25maWcucmVzb2x2ZWRWYWx1ZSA9IG5ld1ZhbHVlO1xuICAgICAgICBpZiAobmV3VmFsdWUuZXJyb3IgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRoaXMuc2V0UmVhZEVycm9yKG5ld1ZhbHVlLmVycm9yKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLnNldFJlYWRFcnJvcih1bmRlZmluZWQpO1xuICAgICAgICAgIGlmIChuZXdWYWx1ZS52YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLnNldERpc3BsYXlWYWx1ZShuZXdWYWx1ZS52YWx1ZSk7XG4gICAgICAgICAgICB0aGlzLnNldEZpZWxkVmFsdWUobmV3VmFsdWUudmFsdWUpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmRpc3BsYXllZFZhbHVlID0gdW5kZWZpbmVkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICBpbml0aWFsaXplQ29uZmlnKCkge1xuICAgIGlmICh0aGlzLmNvbmZpZy5pbml0KSB7XG4gICAgICB0aGlzLmNvbmZpZ1xuICAgICAgICAuaW5pdCh0aGlzLnRhcFNlcnZpY2UsIHRoaXMuY29uZmlnLCB0aGlzLmluZm9SZXNvbHZlcilcbiAgICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgICB0aGlzLnNldFJlYWRFcnJvcihlcnIpO1xuICAgICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzZXRXcml0ZUVycm9yKGVycm9yOiBFcnJvcikge1xuICAgIHRoaXMud3JpdGVFcnJvciA9IGVycm9yO1xuICB9XG5cbiAgc2V0UmVhZEVycm9yKGVycm9yOiBFcnJvciB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMucmVhZEVycm9yID0gZXJyb3I7XG4gICAgdGhpcy5yZXNzb3VyY2VBdmFpbGFibGUgPSBlcnJvclxuICAgICAgPyAhaXNUYXBSZXN1bHRDb2RlRXJyb3IoZXJyb3IsIFJlc3VsdENvZGUuTk9UX0lNUExFTUVOVEVEKVxuICAgICAgOiB0cnVlO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy5fZm9ybVZhbHVlU3Vic2NyaXB0aW9uID0gdGhpcy5maWVsZC52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKFxuICAgICAgKG5ld1ZhbHVlKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmlzRWRpdGVkKCkpIHtcbiAgICAgICAgICB0aGlzLnRhcENvbmZpZ0l0ZW1TdGF0ZS5zZXRQZW5kaW5nQ2hhbmdlKHRoaXMuaW5mbywgbmV3VmFsdWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMudGFwQ29uZmlnSXRlbVN0YXRlLnJlbW92ZVBlbmRpbmdDaGFuZ2UodGhpcy5pbmZvKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLl92YWx1ZVN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLl9mb3JtVmFsdWVTdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5fY2FuY2VsQ2hhbmdlU3Vic2NyaXB0aW9uPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMucGVuZGluZ0NhbGxNYW5hZ2VyLmRlc3Ryb3koKTtcbiAgfVxuXG4gIHN1Ym1pdCgkZXZlbnQ6IEV2ZW50KSB7XG4gICAgaWYgKCF0aGlzLmdsb2JhbFN1Ym1pdCkge1xuICAgICAgZGVidWcoJ3N1Ym1pdCcsICRldmVudCk7XG4gICAgICB0aGlzLmZpZWxkLnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoKTtcbiAgICAgIGlmICghdGhpcy5maWVsZC52YWxpZCkge1xuICAgICAgICB0aGlzLndyaXRlRXJyb3IgPSBuZXcgRXJyb3IoJ0ludmFsaWQgdmFsdWUnKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgLy8gdGhpcy5vblN1Ym1pdC5lbWl0KGV2ZW50KTtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5nZXRGaWVsZFZhbHVlKCk7XG4gICAgICAvLyBkZWJ1ZyhgQ3JlYXRpbmcgY2FsbCBuZXcgdmFsdWU6YCwgdmFsdWUsIGB2YWxpZDogJHt0aGlzLmZpZWxkLnZhbGlkfWApXG4gICAgICBjb25zdCBjYWxsOiAoKSA9PiBQcm9taXNlPGFueT4gPSBhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMudGFwSW5mb0RBT1NlcnZpY2UucHV0KHRoaXMuaW5mbywgdmFsdWUpO1xuICAgICAgICBpZiAodGhpcy5pbmZvLmdldFZhbHVlKSB7XG4gICAgICAgICAgdGhpcy50YXBJbmZvREFPU2VydmljZS5nZXQodGhpcy5pbmZvKS5jYXRjaCgoZXJyKSA9PiB7fSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgfTtcbiAgICAgIHRoaXMucnVuQ2FsbChjYWxsKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJ1bkNhbGwoY2FsbDogKCkgPT4gUHJvbWlzZTxhbnk+KSB7XG4gICAgdGhpcy5sb2FkaW5nID0gdHJ1ZTtcbiAgICB0aGlzLnBlbmRpbmdDYWxsTWFuYWdlclxuICAgICAgLmV4ZWMoY2FsbClcbiAgICAgIC50aGVuKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICBhd2FpdCB0aGlzLnNob3dUb2FzdCgnVmFsdWUgc2F2ZWQhJywgJ3N1Y2Nlc3MnKTtcbiAgICAgICAgdGhpcy5jb25maWcucmVzb2x2ZWRWYWx1ZSA9IHtcbiAgICAgICAgICBsb2FkRGF0ZTogbmV3IERhdGUoKSxcbiAgICAgICAgICB2YWx1ZTogdmFsdWUsXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMud3JpdGVFcnJvciA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5lZGl0TW9kZSA9IGZhbHNlO1xuICAgICAgICB0aGlzLnVwZGF0ZURpc3BsYXlWYWx1ZSgpO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaCgoZXJyKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0V3JpdGVFcnJvcihlcnIpO1xuICAgICAgICB0aGlzLmZpZWxkLnNldEVycm9ycyh7XG4gICAgICAgICAgd3JpdGU6IGVyci5tZXNzYWdlLFxuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgIHRoaXMubG9hZGluZyA9IGZhbHNlO1xuICAgICAgfSk7XG4gIH1cblxuICBvblZhbHVlQ2xpY2soJGV2ZW50OiBDdXN0b21FdmVudCkge1xuICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGlmICh0aGlzLmlzRWRpdGFibGUpIHtcbiAgICAgIHRoaXMuZWRpdE1vZGUgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGV4cGxhaW5QZW5kaW5nQ2FsbCgpIHtcbiAgICBhd2FpdCB0aGlzLnNob3dUb2FzdCgnUGxlYXNlIHJlY29ubmVjdCB5b3VyIFRhcCB0byBzYXZlIHBlbmRpbmcgY2hhbmdlcycpO1xuICB9XG5cbiAgb25Gb2N1c091dCgpIHtcbiAgICB0aGlzLmZvY3VzT3V0LmVtaXQodGhpcy5maWVsZC52YWx1ZSk7XG4gIH1cblxuICBjYW5jZWxFZGl0KCRldmVudD86IGFueSkge1xuICAgIGRlYnVnKHRoaXMuY29uZmlnLmtleSwgJ2NhbmNlbCBlZGl0JywgJGV2ZW50KTtcbiAgICBpZiAodGhpcy5nbG9iYWxTdWJtaXQpIHtcbiAgICAgIHRoaXMucmVzdGF1cmVWYWx1ZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLndyaXRlRXJyb3IgPSB1bmRlZmluZWQ7XG4gICAgICBpZiAodGhpcy5wZW5kaW5nQ2FsbE1hbmFnZXIuaGFzUGVuZGluZ0NhbGwoKSkge1xuICAgICAgICB0aGlzLnBlbmRpbmdDYWxsTWFuYWdlci5jYW5jZWwoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuZWRpdE1vZGUgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5yZXN0YXVyZVZhbHVlKCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0RmllbGRWYWx1ZSgpOiBhbnkge1xuICAgIGxldCBmaWVsZFZhbHVlID0gdGhpcy5maWVsZC52YWx1ZTtcbiAgICBpZiAodGhpcy5jb25maWcuZWRpdEZvcm1hdHRlcikge1xuICAgICAgZmllbGRWYWx1ZSA9IHRoaXMuY29uZmlnLmVkaXRGb3JtYXR0ZXIucmVhZChmaWVsZFZhbHVlKTtcbiAgICB9XG4gICAgcmV0dXJuIGZpZWxkVmFsdWU7XG4gIH1cblxuICBhc3luYyBzaG93VG9hc3QobXNnOiBzdHJpbmcsIGNvbG9yPzogQ29sb3JUeXBlKSB7XG4gICAgY29uc3QgdG9hc3QgPSBhd2FpdCB0aGlzLnRvYXN0Q29udHJvbGxlci5jcmVhdGUoe1xuICAgICAgbWVzc2FnZTogbXNnLFxuICAgICAgZHVyYXRpb246IDIwMDAsXG4gICAgICBwb3NpdGlvbjogJ2JvdHRvbScsXG4gICAgICBjb2xvcjogY29sb3IsXG4gICAgfSk7XG4gICAgYXdhaXQgdG9hc3QucHJlc2VudCgpO1xuICB9XG5cbiAgcmVmcmVzaFZhbHVlKCkge1xuICAgIHJldHVybiB0aGlzLl9leGVjUmVmcmVzaEtleSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBfZXhlY1JlZnJlc2hLZXkoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW5mb1Jlc29sdmVyLnJlZnJlc2hLZXkodGhpcy5jb25maWcpO1xuICB9XG5cbiAgcmVzdGF1cmVWYWx1ZSgpIHtcbiAgICB0aGlzLnNldEZpZWxkVmFsdWUodGhpcy5vcmlnaW5hbFZhbHVlKTtcbiAgICB0aGlzLnRhcENvbmZpZ0l0ZW1TdGF0ZS5yZW1vdmVQZW5kaW5nQ2hhbmdlKHRoaXMuY29uZmlnKTtcbiAgfVxuXG4gIHNldEZpZWxkVmFsdWUoXG4gICAgdmFsdWU6IFZhbHVlVHlwZSB8IHVuZGVmaW5lZCxcbiAgICBvcHRpb25zPzoge1xuICAgICAgZW1pdEV2ZW50PzogYm9vbGVhbjtcbiAgICB9XG4gICkge1xuICAgIGNvbnN0IGZvcm1hdHRlZFZhbHVlID0gdGhpcy5jb25maWcuZWRpdEZvcm1hdHRlclxuICAgICAgPyB0aGlzLmNvbmZpZy5lZGl0Rm9ybWF0dGVyLndyaXRlKHZhbHVlKVxuICAgICAgOiB2YWx1ZTtcbiAgICBkZWJ1Zyh0aGlzLmNvbmZpZy5rZXksICdzZXRGaWVsZFZhbHVlIHdpdGgnLCBmb3JtYXR0ZWRWYWx1ZSk7XG4gICAgdGhpcy5maWVsZC5zZXRWYWx1ZShmb3JtYXR0ZWRWYWx1ZSwgb3B0aW9ucyk7XG4gIH1cblxuICB1cGRhdGVEaXNwbGF5VmFsdWUoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnJlc29sdmVkVmFsdWUpIHtcbiAgICAgIGlmICh0aGlzLmNvbmZpZy5yZXNvbHZlZFZhbHVlLmVycm9yKSB7XG4gICAgICAgIHRoaXMuZGlzcGxheWVkVmFsdWUgPSB0aGlzLmNvbmZpZy5yZXNvbHZlZFZhbHVlLmVycm9yLm1lc3NhZ2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuY29uZmlnLnJlc29sdmVkVmFsdWUudmFsdWU7XG4gICAgICAgIHRoaXMuc2V0RGlzcGxheVZhbHVlKHZhbHVlKTtcbiAgICAgICAgdGhpcy5zZXRGaWVsZFZhbHVlKHZhbHVlKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZGVidWcoXG4gICAgICAgIHRoaXMuY29uZmlnLmtleSxcbiAgICAgICAgJ1ZhbHVlIGlzIG5vdCBsb2FkZWQgeWV0JyxcbiAgICAgICAgdGhpcy5jb25maWcucmVzb2x2ZWRWYWx1ZVxuICAgICAgKTtcbiAgICAgIHRoaXMuZGlzcGxheWVkVmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgc2V0RGlzcGxheVZhbHVlKHZhbHVlOiBWYWx1ZVR5cGUpOiBzdHJpbmcge1xuICAgIGlmICh2YWx1ZSBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICByZXR1cm4gdmFsdWUubWVzc2FnZTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IHN0cmluZ1ZhbHVlOiBzdHJpbmc7XG4gICAgICBpZiAodGhpcy5jb25maWcudmlld0Zvcm1hdHRlcikge1xuICAgICAgICBzdHJpbmdWYWx1ZSA9IHRoaXMuY29uZmlnLnZpZXdGb3JtYXR0ZXIodmFsdWUpO1xuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIHN0cmluZ1ZhbHVlID0gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLmNvbmZpZy5pbnB1dD8udHlwZSA9PT0gJ3NlbGVjdCcpIHtcbiAgICAgICAgc3RyaW5nVmFsdWUgPVxuICAgICAgICAgIHRoaXMuZ2V0U2VsZWN0ZWRPcHRpb24odmFsdWUpPy50ZXh0IHx8XG4gICAgICAgICAgKHZhbHVlICE9PSB1bmRlZmluZWQgPyAodmFsdWUgYXMgYW55KS50b1N0cmluZygpIDogJycpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RyaW5nVmFsdWUgPSB2YWx1ZSAhPT0gdW5kZWZpbmVkID8gKHZhbHVlIGFzIGFueSkudG9TdHJpbmcoKSA6ICcnO1xuICAgICAgfVxuICAgICAgLy8gZGVidWcoYCR7dGhpcy5jb25maWcua2V5fSBzZXREaXNwbGF5VmFsdWUgd2l0aGAsIHN0cmluZ1ZhbHVlKTtcbiAgICAgIHRoaXMuZGlzcGxheWVkVmFsdWUgPSBzdHJpbmdWYWx1ZTtcbiAgICAgIHJldHVybiBzdHJpbmdWYWx1ZTtcbiAgICB9XG4gIH1cblxuICBnZXRTZWxlY3RlZE9wdGlvbih2YWx1ZTogVmFsdWVUeXBlKSB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmlucHV0Py5vcHRpb25zPy5maW5kKChvcHRpb24pID0+IG9wdGlvbi5rZXkgPT09IHZhbHVlKTtcbiAgfVxuXG4gIGdldCBzZWxlY3RlZE9wdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRTZWxlY3RlZE9wdGlvbih0aGlzLmNvbmZpZy5yZXNvbHZlZFZhbHVlPy52YWx1ZSk7XG4gIH1cblxuICBhc3luYyBmZXRjaFZhbHVlKCkge1xuICAgIGlmICh0aGlzLmNvbmZpZy5nZXRWYWx1ZSkge1xuICAgICAgdGhpcy5pbmZvUmVzb2x2ZXIucmVmcmVzaEtleSh0aGlzLmNvbmZpZyk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLnRhcEluZm9DYWNoZVNlcnZpY2VcbiAgICAgICAgLmluZm9DaGFuZ2UodGhpcy5jb25maWcpXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgIGZpbHRlcigodikgPT4gISF2LmxvYWREYXRlKSxcbiAgICAgICAgICBmaXJzdCgpXG4gICAgICAgIClcbiAgICAgICAgLnRvUHJvbWlzZSgpO1xuICAgIH1cbiAgfVxufVxuIiwiPGlvbi1pdGVtICpuZ0lmPVwiX2NvbmZpZ1wiIFtsaW5lc109XCJpc0VkaXRhYmxlID8gJycgOiAnbm9uZSdcIj5cbiAgPGlvbi1za2VsZXRvbi10ZXh0XG4gICAgYW5pbWF0ZWRcbiAgICAqbmdJZj1cIlxuICAgICAgZGlzcGxheWVkVmFsdWUgPT09IHVuZGVmaW5lZCAmJiByZWFkRXJyb3IgPT09IHVuZGVmaW5lZDtcbiAgICAgIGVsc2UgdmFsdWVGZXRjaGVkVGVtcGxhdGVcbiAgICBcIlxuICA+PC9pb24tc2tlbGV0b24tdGV4dD5cbiAgPG5nLXRlbXBsYXRlICN2YWx1ZUZldGNoZWRUZW1wbGF0ZT5cbiAgICA8bmctY29udGFpbmVyXG4gICAgICAqbmdJZj1cInJlc3NvdXJjZUF2YWlsYWJsZTsgZWxzZSByZXNzb3VyY2VOb3RBdmFpbGFibGVUZW1wbGF0ZVwiXG4gICAgPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFlZGl0TW9kZSB8fCAhaXNFZGl0YWJsZTsgZWxzZSBlZGl0TW9kZVRlbXBsYXRlXCI+XG4gICAgICAgIDxpb24tdGV4dFxuICAgICAgICAgIGNvbG9yPVwid2FybmluZ1wiXG4gICAgICAgICAgY2xhc3M9XCJyZWFkLXZhbHVlLWVycm9yXCJcbiAgICAgICAgICAoY2xpY2spPVwib25WYWx1ZUNsaWNrKCRldmVudClcIlxuICAgICAgICAgIFtjbGFzc109XCJpc0VkaXRhYmxlID8gJ2NlbGwnIDogJydcIlxuICAgICAgICAgICpuZ0lmPVwicmVhZEVycm9yOyBlbHNlIG5vUmVhZEVycm9yVGVtcGxhdGVcIlxuICAgICAgICA+XG4gICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJhbGVydC1jaXJjbGVcIj48L2lvbi1pY29uPlxuICAgICAgICAgIHt7IHJlYWRFcnJvciB8IHRhcFJlcXVlc3RFcnJvclRvU3RyaW5nIH19XG4gICAgICAgIDwvaW9uLXRleHQ+XG4gICAgICAgIDxuZy10ZW1wbGF0ZSAjbm9SZWFkRXJyb3JUZW1wbGF0ZT5cbiAgICAgICAgICA8bmctY29udGFpbmVyIFtuZ1N3aXRjaF09XCJpbnB1dE9wdGlvbnMudHlwZVwiPlxuICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdTd2l0Y2hDYXNlPVwiJ3RvZ2dsZSdcIj5cbiAgICAgICAgICAgICAgPGlvbi10b2dnbGUgW2Rpc2FibGVkXT1cInRydWVcIiBbY2hlY2tlZF09XCJmaWVsZC52YWx1ZVwiPjwvaW9uLXRvZ2dsZVxuICAgICAgICAgICAgPjwvbmctY29udGFpbmVyPlxuICAgICAgICAgICAgPGRpdlxuICAgICAgICAgICAgICAoY2xpY2spPVwib25WYWx1ZUNsaWNrKCRldmVudClcIlxuICAgICAgICAgICAgICAqbmdTd2l0Y2hDYXNlPVwiJ3NlbGVjdCdcIlxuICAgICAgICAgICAgICBjbGFzcz1cIml0ZW0tdmFsdWVcIlxuICAgICAgICAgICAgICBbY2xhc3NdPVwiaXNFZGl0YWJsZSA/ICdjZWxsJyA6ICcnXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGlvbi1pY29uXG4gICAgICAgICAgICAgICAgKm5nSWY9XCJzZWxlY3RlZE9wdGlvbj8uaWNvblwiXG4gICAgICAgICAgICAgICAgW25hbWVdPVwic2VsZWN0ZWRPcHRpb24/Lmljb25cIlxuICAgICAgICAgICAgICA+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgPGlvbi10ZXh0IGNsYXNzPVwidGFwLWNvbmZpZy1pdGVtLXZhbHVlXCI+XG4gICAgICAgICAgICAgICAge3sgZGlzcGxheWVkVmFsdWUgfX1cbiAgICAgICAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGlvbi10ZXh0XG4gICAgICAgICAgICAgIChjbGljayk9XCJvblZhbHVlQ2xpY2soJGV2ZW50KVwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiaXRlbS12YWx1ZSB0YXAtY29uZmlnLWl0ZW0tdmFsdWVcIlxuICAgICAgICAgICAgICAqbmdTd2l0Y2hEZWZhdWx0XG4gICAgICAgICAgICAgIFtjbGFzc109XCJpc0VkaXRhYmxlID8gJ2NlbGwnIDogJydcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICB7eyBkaXNwbGF5ZWRWYWx1ZSB9fVxuICAgICAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPG5nLXRlbXBsYXRlICNlZGl0TW9kZVRlbXBsYXRlPlxuICAgICAgICA8bmctY29udGFpbmVyIFtuZ1N3aXRjaF09XCJpbnB1dE9wdGlvbnMudHlwZVwiPlxuICAgICAgICAgIDxpb24tdG9nZ2xlXG4gICAgICAgICAgICAqbmdTd2l0Y2hDYXNlPVwiJ3RvZ2dsZSdcIlxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cImxvYWRpbmcgfHwgISFwZW5kaW5nRWRpdENhbGxcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImZpZWxkXCJcbiAgICAgICAgICA+PC9pb24tdG9nZ2xlPlxuICAgICAgICAgIDxpb24tc2VsZWN0XG4gICAgICAgICAgICBzdHlsZT1cIm1heC13aWR0aDogMTAwJSAhaW1wb3J0YW50XCJcbiAgICAgICAgICAgICpuZ1N3aXRjaENhc2U9XCInc2VsZWN0J1wiXG4gICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwiZmllbGRcIlxuICAgICAgICAgICAgW211bHRpcGxlXT1cImlucHV0T3B0aW9ucy5tdWx0aXBsZVwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPGlvbi1zZWxlY3Qtb3B0aW9uXG4gICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBvcHRpb24gb2YgaW5wdXRPcHRpb25zLm9wdGlvbnNcIlxuICAgICAgICAgICAgICBbdmFsdWVdPVwib3B0aW9uLmtleVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxpb24taWNvbiAqbmdJZj1cIm9wdGlvbi5pY29uXCIgW25hbWVdPVwib3B0aW9uLmljb25cIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICB7eyBvcHRpb24udGV4dCB9fVxuICAgICAgICAgICAgPC9pb24tc2VsZWN0LW9wdGlvbj5cbiAgICAgICAgICAgIDxpb24tc2VsZWN0LW9wdGlvblxuICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgZW51bVZhbHVlIG9mIGlucHV0T3B0aW9ucy5lbnVtPy5kYXRhIHwgbGlzdEVudW1WYWx1ZXNcIlxuICAgICAgICAgICAgICBbdmFsdWVdPVwiZW51bVZhbHVlXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGlvbi1pY29uXG4gICAgICAgICAgICAgICAgW25hbWVdPVwiXG4gICAgICAgICAgICAgICAgICBlbnVtVmFsdWVcbiAgICAgICAgICAgICAgICAgICAgfCB0YXBSZXNvdXJjZUVudW1UcmFuc2xhdGUgOiAnaWNvbicgOiBpbnB1dE9wdGlvbnMuZW51bVxuICAgICAgICAgICAgICAgICAgICB8IGFzeW5jXG4gICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgPjwvaW9uLWljb24+XG4gICAgICAgICAgICAgIHt7XG4gICAgICAgICAgICAgICAgZW51bVZhbHVlXG4gICAgICAgICAgICAgICAgICB8IHRhcFJlc291cmNlRW51bVRyYW5zbGF0ZSA6ICd0aXRsZScgOiBpbnB1dE9wdGlvbnMuZW51bVxuICAgICAgICAgICAgICAgICAgfCBhc3luY1xuICAgICAgICAgICAgICB9fVxuICAgICAgICAgICAgPC9pb24tc2VsZWN0LW9wdGlvbj5cbiAgICAgICAgICA8L2lvbi1zZWxlY3Q+XG4gICAgICAgICAgPGlvbi1pbnB1dFxuICAgICAgICAgICAgKm5nU3dpdGNoRGVmYXVsdFxuICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwic3VibWl0KCRldmVudClcIlxuICAgICAgICAgICAgKGtleWRvd24uZXNjYXBlKT1cImNhbmNlbEVkaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiISFwZW5kaW5nRWRpdENhbGxcIlxuICAgICAgICAgICAgW21heGxlbmd0aF09XCJpbnB1dE9wdGlvbnMubWF4TGVuZ3RoXCJcbiAgICAgICAgICAgIFttaW5sZW5ndGhdPVwiaW5wdXRPcHRpb25zLm1pbkxlbmd0aFwiXG4gICAgICAgICAgICBbbWF4XT1cImlucHV0T3B0aW9ucy5tYXhcIlxuICAgICAgICAgICAgW21pbl09XCJpbnB1dE9wdGlvbnMubWluXCJcbiAgICAgICAgICAgIFtwYXR0ZXJuXT1cImlucHV0T3B0aW9ucy5wYXR0ZXJuXCJcbiAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJwbGFjZWhvbGRlclwiXG4gICAgICAgICAgICBbdHlwZV09XCJpbnB1dE9wdGlvbnMudHlwZVwiXG4gICAgICAgICAgICBhcHBBdXRvZm9jdXNcbiAgICAgICAgICAgIGNsYXNzPVwiY2VsbElucHV0XCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJmaWVsZFwiXG4gICAgICAgICAgPlxuICAgICAgICAgIDwvaW9uLWlucHV0PlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8aW9uLWJ1dHRvbnMgc2xvdD1cImVuZFwiPlxuICAgICAgICA8aW9uLWJ1dHRvblxuICAgICAgICAgIChjbGljayk9XCJleHBsYWluUGVuZGluZ0NhbGwoKVwiXG4gICAgICAgICAgKm5nSWY9XCJwZW5kaW5nRWRpdENhbGxcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJmYWxzZVwiXG4gICAgICAgICAgY29sb3I9XCJ3YXJuaW5nXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwiYWxlcnQtY2lyY2xlXCI+PC9pb24taWNvbj5cbiAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICA8aW9uLWJ1dHRvblxuICAgICAgICAgIChjbGljayk9XCJlZGl0TW9kZSA9IHRydWVcIlxuICAgICAgICAgICpuZ0lmPVwiIWdsb2JhbFN1Ym1pdCAmJiAhZWRpdE1vZGUgJiYgaW5mby5wdXRWYWx1ZVwiXG4gICAgICAgID5cbiAgICAgICAgICA8aW9uLWljb24gbmFtZT1cImNyZWF0ZVwiPjwvaW9uLWljb24+XG4gICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgPGlvbi1idXR0b25cbiAgICAgICAgICAoY2xpY2spPVwic3VibWl0KCRldmVudClcIlxuICAgICAgICAgICpuZ0lmPVwiIWdsb2JhbFN1Ym1pdCAmJiBlZGl0TW9kZSAmJiAhcGVuZGluZ0VkaXRDYWxsXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwibG9hZGluZyB8fCBwZW5kaW5nRWRpdENhbGxcIlxuICAgICAgICA+XG4gICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJzZW5kXCI+PC9pb24taWNvbj5cbiAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICA8aW9uLWJ1dHRvblxuICAgICAgICAgIChjbGljayk9XCJjYW5jZWxFZGl0KClcIlxuICAgICAgICAgICpuZ0lmPVwiaXNFZGl0YWJsZSAmJiBlZGl0TW9kZSAmJiAoIWdsb2JhbFN1Ym1pdCB8fCBpc0VkaXRlZCgpKVwiXG4gICAgICAgICAgY29sb3I9XCJxdWF0ZXJuYXJ5XCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwibG9hZGluZ1wiXG4gICAgICAgID5cbiAgICAgICAgICA8aW9uLWljb24gbmFtZT1cImNsb3NlXCI+PC9pb24taWNvbj5cbiAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICA8aW9uLWJ1dHRvblxuICAgICAgICAgIChjbGljayk9XCJyZWZyZXNoVmFsdWUoKVwiXG4gICAgICAgICAgKm5nSWY9XCJyZWZyZXNoICYmIGluZm8uZ2V0VmFsdWUgJiYgIWVkaXRNb2RlXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwibG9hZGluZ1wiXG4gICAgICAgID5cbiAgICAgICAgICA8aW9uLWljb24gbmFtZT1cInN5bmNcIj48L2lvbi1pY29uPlxuICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICA8L2lvbi1idXR0b25zPlxuICAgICAgPGlvbi1zcGlubmVyICpuZ0lmPVwibG9hZGluZ1wiIHNsb3Q9XCJlbmRcIj48L2lvbi1zcGlubmVyPlxuICAgIDwvbmctY29udGFpbmVyPlxuICAgIDxuZy10ZW1wbGF0ZSAjcmVzc291cmNlTm90QXZhaWxhYmxlVGVtcGxhdGU+XG4gICAgICA8aW9uLXRleHQgY29sb3I9XCJ3YXJuaW5nXCIgY2xhc3M9XCJyZWFkLXZhbHVlLWVycm9yXCI+XG4gICAgICAgIDxpb24taWNvbiBuYW1lPVwiYWxlcnQtY2lyY2xlXCI+PC9pb24taWNvbj5cbiAgICAgICAgTm90IGF2YWlsYWJsZSB3aXRoIHlvdXIgZmlybXdhcmUgdmVyc2lvbiBvciBUYXAgbW9kZWxcbiAgICAgIDwvaW9uLXRleHQ+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgPC9uZy10ZW1wbGF0ZT5cbjwvaW9uLWl0ZW0+XG48aW9uLWl0ZW0gKm5nSWY9XCJ3cml0ZUVycm9yXCI+XG4gIDxpb24tdGV4dCBjb2xvcj1cImRhbmdlclwiIGNsYXNzPVwidGFwLWNvbmZpZy1pdGVtLWVycm9yXCI+XG4gICAgPGlvbi1pY29uIG5hbWU9XCJhbGVydC1jaXJjbGVcIj48L2lvbi1pY29uPlxuICAgIEZhaWxlZCB0byB3cml0ZSB2YWx1ZToge3sgd3JpdGVFcnJvciB8IHRhcFJlcXVlc3RFcnJvclRvU3RyaW5nIH19XG4gIDwvaW9uLXRleHQ+XG48L2lvbi1pdGVtPlxuPGFwcC1jb21tb24tZm9ybS1lcnJvci1pdGVtXG4gIFtmb3JtQ29udHJvbFJlZl09XCJmaWVsZFwiXG4+PC9hcHAtY29tbW9uLWZvcm0tZXJyb3ItaXRlbT5cbiJdfQ==