@iotize/ionic
Version:
Iotize specific building blocks on top of @ionic/angular.
372 lines • 69.5 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 {
tapService;
toastController;
infoResolver;
tapInfoDAOService;
tapInfoCacheService;
tapConfigItemState;
tapInfoConfigService;
focusOut = new EventEmitter();
onSubmit = new EventEmitter();
pendingCallManager;
editable;
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();
}
refresh = false;
editMode = false;
globalSubmit = false;
get info() {
return this.config;
}
get originalValue() {
return this.config.resolvedValue?.value;
}
_valueSubscription;
_formValueSubscription;
_cancelChangeSubscription;
_config;
loading = false;
readError;
writeError;
placeholder = '';
displayedValue;
field;
ressourceAvailable = true;
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;
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 */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", 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 */ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", 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: ["autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearInputIcon", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "spellcheck", "step", "type", "value"] }, { kind: "component", type: i3.IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: i3.IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "required", "selectedText", "shape", "toggleIcon", "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: ["alignment", "checked", "color", "disabled", "enableOnOffLabels", "errorText", "helperText", "justify", "labelPlacement", "mode", "name", "required", "value"] }, { kind: "directive", type: i3.BooleanValueAccessor, selector: "ion-checkbox,ion-toggle" }, { kind: "directive", type: i3.SelectValueAccessor, selector: "ion-select, ion-radio-group, ion-segment, ion-datetime" }, { kind: "directive", type: i3.TextValueAccessor, selector: "ion-input:not([type=number]),ion-input-otp[type=text],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: "18.2.14", 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: () => [{ 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9jb25maWcvc3JjL2xpYi90YXAtY29uZmlnLWl0ZW0vdGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9jb25maWcvc3JjL2xpYi90YXAtY29uZmlnLWl0ZW0vdGFwLWNvbmZpZy1pdGVtLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFHTCxNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFtQixXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDakQsT0FBTyxFQUNMLG9CQUFvQixFQUNwQixRQUFRLEVBQ1Isa0JBQWtCLEVBR2xCLG1CQUFtQixFQUNuQixvQkFBb0IsRUFDcEIsaUJBQWlCLEVBRWpCLHFCQUFxQixFQUVyQixvQkFBb0IsR0FDckIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRXBELE9BQU8sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDL0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqQyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQzs7Ozs7Ozs7Ozs7QUFTN0UsTUFBTSxPQUFPLHNCQUFzQjtJQStGdkI7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFsR0EsUUFBUSxHQUF5QixJQUFJLFlBQVksRUFBVSxDQUFDO0lBQzVELFFB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QUFzQjsrR0FBdEIsc0JBQXNCLHdPQ3JDbkMseTlMQXVLQTs7NEZEbElhLHNCQUFzQjtrQkFMbEMsU0FBUzsrQkFDRSxpQkFBaUI7a1VBT2pCLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csUUFBUTtzQkFBakIsTUFBTTtnQkFLRSxRQUFRO3NCQUFoQixLQUFLO2dCQUVPLElBQUk7c0JBQWhCLEtBQUs7Z0JBd0JHLE9BQU87c0JBQWYsS0FBSztnQkFFRyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBGb3JtQnVpbGRlciB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IFRvYXN0Q29udHJvbGxlciB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyJztcbmltcG9ydCB7XG4gIEN1cnJlbnREZXZpY2VTZXJ2aWNlLFxuICBMaWJFcnJvcixcbiAgUGVuZGluZ0NhbGxNYW5hZ2VyLFxuICBUYXBDb25maWdJdGVtLFxuICBUYXBJbmZvLFxuICBUYXBJbmZvQ2FjaGVTZXJ2aWNlLFxuICBUYXBJbmZvQ29uZmlnU2VydmljZSxcbiAgVGFwSW5mb0RBT1NlcnZpY2UsXG4gIFRhcEluZm9Ib2xkZXIsXG4gIFRhcEluZm9SZXF1ZXN0U2VydmljZSxcbiAgVGFwUmVzb3VyY2VLZXksXG4gIGlzVGFwUmVzdWx0Q29kZUVycm9yLFxufSBmcm9tICdAaW90aXplL2lvbmljJztcbmltcG9ydCB7IFJlc3VsdENvZGUgfSBmcm9tICdAaW90aXplL3RhcC9jbGllbnQvYXBpJztcbmltcG9ydCB7IFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmlsdGVyLCBmaXJzdCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IGRlYnVnIH0gZnJvbSAnLi4vZGVidWcnO1xuaW1wb3J0IHsgVGFwQ29uZmlnSXRlbVN0YXRlU2VydmljZSB9IGZyb20gJy4uL3RhcC1jb25maWctaXRlbS1zdGF0ZS5zZXJ2aWNlJztcblxudHlwZSBDb2xvclR5cGUgPSBhbnk7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3RhcC1jb25maWctaXRlbScsXG4gIHRlbXBsYXRlVXJsOiAnLi90YXAtY29uZmlnLWl0ZW0uY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi90YXAtY29uZmlnLWl0ZW0uY29tcG9uZW50LnNjc3MnXSxcbn0pXG5leHBvcnQgY2xhc3MgVGFwQ29uZmlnSXRlbUNvbXBvbmVudDxWYWx1ZVR5cGUgPSBhbnk+XG4gIGltcGxlbWVudHMgT25EZXN0cm95LCBPbkluaXRcbntcbiAgQE91dHB1dCgpIGZvY3VzT3V0OiBFdmVudEVtaXR0ZXI8bnVtYmVyPiA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuICBAT3V0cHV0KCkgb25TdWJtaXQ6IEV2ZW50RW1pdHRlcjx7XG4gICAgdGFyZ2V0OiB7IHZhbHVlOiBzdHJpbmcgfTtcbiAgfT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gIHBlbmRpbmdDYWxsTWFuYWdlcjogUGVuZGluZ0NhbGxNYW5hZ2VyO1xuXG4gIEBJbnB1dCgpIGVkaXRhYmxlPzogYm9vbGVhbjtcblxuICBASW5wdXQoKSBzZXQgaW5mbyhjb25maWdPcktleTogVGFwQ29uZmlnSXRlbTxWYWx1ZVR5cGU+IHwgVGFwSW5mbykge1xuICAgIHRoaXMuX3Jlc2V0RXJyb3JzKCk7XG4gICAgbGV0IGNvbmZpZzogVGFwQ29uZmlnSXRlbTxWYWx1ZVR5cGU+O1xuICAgIGlmICh0eXBlb2YgY29uZmlnT3JLZXkgPT09ICdvYmplY3QnKSB7XG4gICAgICBjb25zdCBkZWZhdWx0Q29uZmlnID0gdGhpcy50YXBJbmZvQ29uZmlnU2VydmljZS5maW5kQnlLZXkoY29uZmlnT3JLZXkpO1xuICAgICAgaWYgKGRlZmF1bHRDb25maWcpIHtcbiAgICAgICAgY29uZmlnID0geyAuLi5kZWZhdWx0Q29uZmlnLCAuLi5jb25maWdPcktleSB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uZmlnID0gY29uZmlnT3JLZXk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbmZpZyA9IHRoaXMudGFwSW5mb0NvbmZpZ1NlcnZpY2UuZmluZEJ5S2V5KHtcbiAgICAgICAga2V5OiBjb25maWdPcktleSBhcyBUYXBSZXNvdXJjZUtleSxcbiAgICAgIH0pITtcbiAgICAgIGlmICghY29uZmlnKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgRmFpbGVkIHRvIGZpbmQgY29uZmlndXJhdGlvbiB3aXRoIGtleSBcIiR7Y29uZmlnT3JLZXl9XCJgKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICB0aGlzLm9uQ29uZmlnQ2hhbmdlKGNvbmZpZyk7XG4gICAgdGhpcy51cGRhdGVEaXNwbGF5VmFsdWUoKTtcbiAgICAvLyB0aGlzLmZldGNoVmFsdWVJZlJlcXVpcmVkKCk7XG4gIH1cblxuICBASW5wdXQoKSByZWZyZXNoID0gZmFsc2U7XG5cbiAgQElucHV0KCkgZWRpdE1vZGUgPSBmYWxzZTtcblxuICBASW5wdXQoKSBnbG9iYWxTdWJtaXQgPSBmYWxzZTtcblxuICBnZXQgaW5mbygpOiBUYXBDb25maWdJdGVtPFZhbHVlVHlwZT4ge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZztcbiAgfVxuXG4gIGdldCBvcmlnaW5hbFZhbHVlKCk6IFZhbHVlVHlwZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLnJlc29sdmVkVmFsdWU/LnZhbHVlO1xuICB9XG5cbiAgcHJpdmF0ZSBfdmFsdWVTdWJzY3JpcHRpb24/OiBTdWJzY3JpcHRpb247XG4gIHByaXZhdGUgX2Zvcm1WYWx1ZVN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBfY2FuY2VsQ2hhbmdlU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uO1xuXG4gIF9jb25maWc/OiBUYXBDb25maWdJdGVtPFZhbHVlVHlwZT47XG4gIGxvYWRpbmcgPSBmYWxzZTtcbiAgcmVhZEVycm9yPzogRXJyb3I7XG4gIHdyaXRlRXJyb3I/OiBFcnJvcjtcblxuICBwbGFjZWhvbGRlciA9ICcnO1xuXG4gIGRpc3BsYXllZFZhbHVlPzogc3RyaW5nO1xuXG4gIGZpZWxkOiBBYnN0cmFjdENvbnRyb2w7XG5cbiAgcmVzc291cmNlQXZhaWxhYmxlID0gdHJ1ZTtcblxuICBpc0VkaXRlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5maWVsZC52YWx1ZSAhPT0gdGhpcy5vcmlnaW5hbFZhbHVlO1xuICB9XG5cbiAgZ2V0IGNvbmZpZygpOiBUYXBDb25maWdJdGVtPFZhbHVlVHlwZT4ge1xuICAgIGlmICghdGhpcy5fY29uZmlnKSB7XG4gICAgICB0aHJvdyBMaWJFcnJvci5jb21wb25lbnRBcmd1bWVudFJlcXVpcmVkKFxuICAgICAgICAnVGFwQ29uZmlnSXRlbUNvbXBvbmVudCcsXG4gICAgICAgICdpbmZvJ1xuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2NvbmZpZztcbiAgfVxuXG4gIGdldCBpbnB1dE9wdGlvbnMoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW5mby5pbnB1dCB8fCB7fTtcbiAgfVxuXG4gIGdldCBpc0VkaXRhYmxlKCkge1xuICAgIHJldHVybiAoXG4gICAgICB0aGlzLl9jb25maWc/LmVkaXRhYmxlICYmXG4gICAgICB0aGlzLmVkaXRhYmxlICYmXG4gICAgICAoIXRoaXMucmVhZEVycm9yIHx8XG4gICAgICAgICFpc1RhcFJlc3VsdENvZGVFcnJvcih0aGlzLnJlYWRFcnJvciwgUmVzdWx0Q29kZS5OT1RfSU1QTEVNRU5URUQpKVxuICAgICk7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihcbiAgICBmb3JtQnVpbGRlcjogRm9ybUJ1aWxkZXIsXG4gICAgcHJpdmF0ZSB0YXBTZXJ2aWNlOiBDdXJyZW50RGV2aWNlU2VydmljZSxcbiAgICBwcml2YXRlIHRvYXN0Q29udHJvbGxlcjogVG9hc3RDb250cm9sbGVyLFxuICAgIHByaXZhdGUgaW5mb1Jlc29sdmVyOiBUYXBJbmZvUmVxdWVzdFNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0YXBJbmZvREFPU2VydmljZTogVGFwSW5mb0RBT1NlcnZpY2UsXG4gICAgcHJpdmF0ZSB0YXBJbmZvQ2FjaGVTZXJ2aWNlOiBUYXBJbmZvQ2FjaGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgdGFwQ29uZmlnSXRlbVN0YXRlOiBUYXBDb25maWdJdGVtU3RhdGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgdGFwSW5mb0NvbmZpZ1NlcnZpY2U6IFRhcEluZm9Db25maWdTZXJ2aWNlXG4gICkge1xuICAgIGNvbnN0IGZvcm0gPSBmb3JtQnVpbGRlci5ub25OdWxsYWJsZS5ncm91cCh7XG4gICAgICBmaWVsZDogWycnXSxcbiAgICB9KTtcbiAgICB0aGlzLmZpZWxkID0gZm9ybS5jb250cm9scy5maWVsZDtcbiAgICB0aGlzLnBlbmRpbmdDYWxsTWFuYWdlciA9IFBlbmRpbmdDYWxsTWFuYWdlci5jcmVhdGUodGhpcy50YXBTZXJ2aWNlKTtcbiAgfVxuXG4gIHByaXZhdGUgX3Jlc2V0RXJyb3JzKCkge1xuICAgIHRoaXMuc2V0UmVhZEVycm9yKHVuZGVmaW5lZCk7XG4gICAgdGhpcy53cml0ZUVycm9yID0gdW5kZWZpbmVkO1xuICAgIHRoaXMucmVzc291cmNlQXZhaWxhYmxlID0gdHJ1ZTtcbiAgfVxuXG4gIGdldCBwZW5kaW5nRWRpdENhbGwoKSB7XG4gICAgcmV0dXJuIHRoaXMucGVuZGluZ0NhbGxNYW5hZ2VyLnBlbmRpbmdDYWxsO1xuICB9XG5cbiAgcHJpdmF0ZSBvbkNvbmZpZ0NoYW5nZShjb25maWc6IFRhcENvbmZpZ0l0ZW08YW55Pikge1xuICAgIHRoaXMuX3ZhbHVlU3Vic2NyaXB0aW9uPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuX2NhbmNlbENoYW5nZVN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLl9jb25maWcgPSBjb25maWc7XG4gICAgdGhpcy5fY2FuY2VsQ2hhbmdlU3Vic2NyaXB0aW9uID0gdGhpcy50YXBDb25maWdJdGVtU3RhdGVcbiAgICAgIC5nZXRQZW5kaW5nQ2hhbmdlRm9yS2V5KGNvbmZpZylcbiAgICAgIC5zdWJzY3JpYmUoKHYpID0+IHtcbiAgICAgICAgaWYgKHYgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRoaXMuc2V0RmllbGRWYWx1ZSh0aGlzLm9yaWdpbmFsVmFsdWUsIHtcbiAgICAgICAgICAgIGVtaXRFdmVudDogZmFsc2UsXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIHRoaXMuaW5pdGlhbGl6ZUNvbmZpZygpO1xuICAgIGlmIChjb25maWcuaW5wdXQgJiYgY29uZmlnLmlucHV0LnR5cGUgPT09ICdwYXNzd29yZCcpIHtcbiAgICAgIHRoaXMuc2V0RGlzcGxheVZhbHVlKCcnIGFzIGFueSk7XG4gICAgfVxuICAgIGlmIChjb25maWcuaW5wdXQ/LmZvcm1WYWxpZGF0b3JzKSB7XG4gICAgICB0aGlzLmZpZWxkLnNldFZhbGlkYXRvcnMoY29uZmlnLmlucHV0LmZvcm1WYWxpZGF0b3JzKTtcbiAgICB9XG4gICAgdGhpcy5fdmFsdWVTdWJzY3JpcHRpb24gPSB0aGlzLnRhcEluZm9DYWNoZVNlcnZpY2VcbiAgICAgIC5pbmZvQ2hhbmdlKGNvbmZpZylcbiAgICAgIC5zdWJzY3JpYmUoKG5ld1ZhbHVlOiBUYXBJbmZvSG9sZGVyKSA9PiB7XG4gICAgICAgIGNvbmZpZy5yZXNvbHZlZFZhbHVlID0gbmV3VmFsdWU7XG4gICAgICAgIGlmIChuZXdWYWx1ZS5lcnJvciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgdGhpcy5zZXRSZWFkRXJyb3IobmV3VmFsdWUuZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuc2V0UmVhZEVycm9yKHVuZGVmaW5lZCk7XG4gICAgICAgICAgaWYgKG5ld1ZhbHVlLnZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0RGlzcGxheVZhbHVlKG5ld1ZhbHVlLnZhbHVlKTtcbiAgICAgICAgICAgIHRoaXMuc2V0RmllbGRWYWx1ZShuZXdWYWx1ZS52YWx1ZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZGlzcGxheWVkVmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgfVxuXG4gIGluaXRpYWxpemVDb25maWcoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmluaXQpIHtcbiAgICAgIHRoaXMuY29uZmlnXG4gICAgICAgIC5pbml0KHRoaXMudGFwU2VydmljZSwgdGhpcy5jb25maWcsIHRoaXMuaW5mb1Jlc29sdmVyKVxuICAgICAgICAuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgIHRoaXMuc2V0UmVhZEVycm9yKGVycik7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHNldFdyaXRlRXJyb3IoZXJyb3I6IEVycm9yKSB7XG4gICAgdGhpcy53cml0ZUVycm9yID0gZXJyb3I7XG4gIH1cblxuICBzZXRSZWFkRXJyb3IoZXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5yZWFkRXJyb3IgPSBlcnJvcjtcbiAgICB0aGlzLnJlc3NvdXJjZUF2YWlsYWJsZSA9IGVycm9yXG4gICAgICA/ICFpc1RhcFJlc3VsdENvZGVFcnJvcihlcnJvciwgUmVzdWx0Q29kZS5OT1RfSU1QTEVNRU5URUQpXG4gICAgICA6IHRydWU7XG4gIH1cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLl9mb3JtVmFsdWVTdWJzY3JpcHRpb24gPSB0aGlzLmZpZWxkLnZhbHVlQ2hhbmdlcy5zdWJzY3JpYmUoXG4gICAgICAobmV3VmFsdWUpID0+IHtcbiAgICAgICAgaWYgKHRoaXMuaXNFZGl0ZWQoKSkge1xuICAgICAgICAgIHRoaXMudGFwQ29uZmlnSXRlbVN0YXRlLnNldFBlbmRpbmdDaGFuZ2UodGhpcy5pbmZvLCBuZXdWYWx1ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy50YXBDb25maWdJdGVtU3RhdGUucmVtb3ZlUGVuZGluZ0NoYW5nZSh0aGlzLmluZm8pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuX3ZhbHVlU3Vic2NyaXB0aW9uPy51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuX2Zvcm1WYWx1ZVN1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcbiAgICB0aGlzLl9jYW5jZWxDaGFuZ2VTdWJzY3JpcHRpb24/LnVuc3Vic2NyaWJlKCk7XG4gICAgdGhpcy5wZW5kaW5nQ2FsbE1hbmFnZXIuZGVzdHJveSgpO1xuICB9XG5cbiAgc3VibWl0KCRldmVudDogRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMuZ2xvYmFsU3VibWl0KSB7XG4gICAgICBkZWJ1Zygnc3VibWl0JywgJGV2ZW50KTtcbiAgICAgIHRoaXMuZmllbGQudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xuICAgICAgaWYgKCF0aGlzLmZpZWxkLnZhbGlkKSB7XG4gICAgICAgIHRoaXMud3JpdGVFcnJvciA9IG5ldyBFcnJvcignSW52YWxpZCB2YWx1ZScpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICAvLyB0aGlzLm9uU3VibWl0LmVtaXQoZXZlbnQpO1xuICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLmdldEZpZWxkVmFsdWUoKTtcbiAgICAgIC8vIGRlYnVnKGBDcmVhdGluZyBjYWxsIG5ldyB2YWx1ZTpgLCB2YWx1ZSwgYHZhbGlkOiAke3RoaXMuZmllbGQudmFsaWR9YClcbiAgICAgIGNvbnN0IGNhbGw6ICgpID0+IFByb21pc2U8YW55PiA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy50YXBJbmZvREFPU2VydmljZS5wdXQodGhpcy5pbmZvLCB2YWx1ZSk7XG4gICAgICAgIGlmICh0aGlzLmluZm8uZ2V0VmFsdWUpIHtcbiAgICAgICAgICB0aGlzLnRhcEluZm9EQU9TZXJ2aWNlLmdldCh0aGlzLmluZm8pLmNhdGNoKChlcnIpID0+IHt9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICB9O1xuICAgICAgdGhpcy5ydW5DYWxsKGNhbGwpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcnVuQ2FsbChjYWxsOiAoKSA9PiBQcm9taXNlPGFueT4pIHtcbiAgICB0aGlzLmxvYWRpbmcgPSB0cnVlO1xuICAgIHRoaXMucGVuZGluZ0NhbGxNYW5hZ2VyXG4gICAgICAuZXhlYyhjYWxsKVxuICAgICAgLnRoZW4oYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMuc2hvd1RvYXN0KCdWYWx1ZSBzYXZlZCEnLCAnc3VjY2VzcycpO1xuICAgICAgICB0aGlzLmNvbmZpZy5yZXNvbHZlZFZhbHVlID0ge1xuICAgICAgICAgIGxvYWREYXRlOiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIHZhbHVlOiB2YWx1ZSxcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy53cml0ZUVycm9yID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLmVkaXRNb2RlID0gZmFsc2U7XG4gICAgICAgIHRoaXMudXBkYXRlRGlzcGxheVZhbHVlKCk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlcnIpID0+IHtcbiAgICAgICAgdGhpcy5zZXRXcml0ZUVycm9yKGVycik7XG4gICAgICAgIHRoaXMuZmllbGQuc2V0RXJyb3JzKHtcbiAgICAgICAgICB3cml0ZTogZXJyLm1lc3NhZ2UsXG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgdGhpcy5sb2FkaW5nID0gZmFsc2U7XG4gICAgICB9KTtcbiAgfVxuXG4gIG9uVmFsdWVDbGljaygkZXZlbnQ6IEN1c3RvbUV2ZW50KSB7XG4gICAgJGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgaWYgKHRoaXMuaXNFZGl0YWJsZSkge1xuICAgICAgdGhpcy5lZGl0TW9kZSA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZXhwbGFpblBlbmRpbmdDYWxsKCkge1xuICAgIGF3YWl0IHRoaXMuc2hvd1RvYXN0KCdQbGVhc2UgcmVjb25uZWN0IHlvdXIgVGFwIHRvIHNhdmUgcGVuZGluZyBjaGFuZ2VzJyk7XG4gIH1cblxuICBvbkZvY3VzT3V0KCkge1xuICAgIHRoaXMuZm9jdXNPdXQuZW1pdCh0aGlzLmZpZWxkLnZhbHVlKTtcbiAgfVxuXG4gIGNhbmNlbEVkaXQoJGV2ZW50PzogYW55KSB7XG4gICAgZGVidWcodGhpcy5jb25maWcua2V5LCAnY2FuY2VsIGVkaXQnLCAkZXZlbnQpO1xuICAgIGlmICh0aGlzLmdsb2JhbFN1Ym1pdCkge1xuICAgICAgdGhpcy5yZXN0YXVyZVZhbHVlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMud3JpdGVFcnJvciA9IHVuZGVmaW5lZDtcbiAgICAgIGlmICh0aGlzLnBlbmRpbmdDYWxsTWFuYWdlci5oYXNQZW5kaW5nQ2FsbCgpKSB7XG4gICAgICAgIHRoaXMucGVuZGluZ0NhbGxNYW5hZ2VyLmNhbmNlbCgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5lZGl0TW9kZSA9IGZhbHNlO1xuICAgICAgICB0aGlzLnJlc3RhdXJlVmFsdWUoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBnZXRGaWVsZFZhbHVlKCk6IGFueSB7XG4gICAgbGV0IGZpZWxkVmFsdWUgPSB0aGlzLmZpZWxkLnZhbHVlO1xuICAgIGlmICh0aGlzLmNvbmZpZy5lZGl0Rm9ybWF0dGVyKSB7XG4gICAgICBmaWVsZFZhbHVlID0gdGhpcy5jb25maWcuZWRpdEZvcm1hdHRlci5yZWFkKGZpZWxkVmFsdWUpO1xuICAgIH1cbiAgICByZXR1cm4gZmllbGRWYWx1ZTtcbiAgfVxuXG4gIGFzeW5jIHNob3dUb2FzdChtc2c6IHN0cmluZywgY29sb3I/OiBDb2xvclR5cGUpIHtcbiAgICBjb25zdCB0b2FzdCA9IGF3YWl0IHRoaXMudG9hc3RDb250cm9sbGVyLmNyZWF0ZSh7XG4gICAgICBtZXNzYWdlOiBtc2csXG4gICAgICBkdXJhdGlvbjogMjAwMCxcbiAgICAgIHBvc2l0aW9uOiAnYm90dG9tJyxcbiAgICAgIGNvbG9yOiBjb2xvcixcbiAgICB9KTtcbiAgICBhd2FpdCB0b2FzdC5wcmVzZW50KCk7XG4gIH1cblxuICByZWZyZXNoVmFsdWUoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2V4ZWNSZWZyZXNoS2V5KCk7XG4gIH1cblxuICBwcml2YXRlIF9leGVjUmVmcmVzaEtleSgpIHtcbiAgICByZXR1cm4gdGhpcy5pbmZvUmVzb2x2ZXIucmVmcmVzaEtleSh0aGlzLmNvbmZpZyk7XG4gIH1cblxuICByZXN0YXVyZVZhbHVlKCkge1xuICAgIHRoaXMuc2V0RmllbGRWYWx1ZSh0aGlzLm9yaWdpbmFsVmFsdWUpO1xuICAgIHRoaXMudGFwQ29uZmlnSXRlbVN0YXRlLnJlbW92ZVBlbmRpbmdDaGFuZ2UodGhpcy5jb25maWcpO1xuICB9XG5cbiAgc2V0RmllbGRWYWx1ZShcbiAgICB2YWx1ZTogVmFsdWVUeXBlIHwgdW5kZWZpbmVkLFxuICAgIG9wdGlvbnM/OiB7XG4gICAgICBlbWl0RXZlbnQ/OiBib29sZWFuO1xuICAgIH1cbiAgKSB7XG4gICAgY29uc3QgZm9ybWF0dGVkVmFsdWUgPSB0aGlzLmNvbmZpZy5lZGl0Rm9ybWF0dGVyXG4gICAgICA/IHRoaXMuY29uZmlnLmVkaXRGb3JtYXR0ZXIud3JpdGUodmFsdWUpXG4gICAgICA6IHZhbHVlO1xuICAgIGRlYnVnKHRoaXMuY29uZmlnLmtleSwgJ3NldEZpZWxkVmFsdWUgd2l0aCcsIGZvcm1hdHRlZFZhbHVlKTtcbiAgICB0aGlzLmZpZWxkLnNldFZhbHVlKGZvcm1hdHRlZFZhbHVlLCBvcHRpb25zKTtcbiAgfVxuXG4gIHVwZGF0ZURpc3BsYXlWYWx1ZSgpIHtcbiAgICBpZiAodGhpcy5jb25maWcucmVzb2x2ZWRWYWx1ZSkge1xuICAgICAgaWYgKHRoaXMuY29uZmlnLnJlc29sdmVkVmFsdWUuZXJyb3IpIHtcbiAgICAgICAgdGhpcy5kaXNwbGF5ZWRWYWx1ZSA9IHRoaXMuY29uZmlnLnJlc29sdmVkVmFsdWUuZXJyb3IubWVzc2FnZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5jb25maWcucmVzb2x2ZWRWYWx1ZS52YWx1ZTtcbiAgICAgICAgdGhpcy5zZXREaXNwbGF5VmFsdWUodmFsdWUpO1xuICAgICAgICB0aGlzLnNldEZpZWxkVmFsdWUodmFsdWUpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1ZyhcbiAgICAgICAgdGhpcy5jb25maWcua2V5LFxuICAgICAgICAnVmFsdWUgaXMgbm90IGxvYWRlZCB5ZXQnLFxuICAgICAgICB0aGlzLmNvbmZpZy5yZXNvbHZlZFZhbHVlXG4gICAgICApO1xuICAgICAgdGhpcy5kaXNwbGF5ZWRWYWx1ZSA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICBzZXREaXNwbGF5VmFsdWUodmFsdWU6IFZhbHVlVHlwZSk6IHN0cmluZyB7XG4gICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIHJldHVybiB2YWx1ZS5tZXNzYWdlO1xuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgc3RyaW5nVmFsdWU6IHN0cmluZztcbiAgICAgIGlmICh0aGlzLmNvbmZpZy52aWV3Rm9ybWF0dGVyKSB7XG4gICAgICAgIHN0cmluZ1ZhbHVlID0gdGhpcy5jb25maWcudmlld0Zvcm1hdHRlcih2YWx1ZSk7XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgc3RyaW5nVmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuY29uZmlnLmlucHV0Py50eXBlID09PSAnc2VsZWN0Jykge1xuICAgICAgICBzdHJpbmdWYWx1ZSA9XG4gICAgICAgICAgdGhpcy5nZXRTZWxlY3RlZE9wdGlvbih2YWx1ZSk/LnRleHQgfHxcbiAgICAgICAgICAodmFsdWUgIT09IHVuZGVmaW5lZCA/ICh2YWx1ZSBhcyBhbnkpLnRvU3RyaW5nKCkgOiAnJyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdHJpbmdWYWx1ZSA9IHZhbHVlICE9PSB1bmRlZmluZWQgPyAodmFsdWUgYXMgYW55KS50b1N0cmluZygpIDogJyc7XG4gICAgICB9XG4gICAgICAvLyBkZWJ1ZyhgJHt0aGlzLmNvbmZpZy5rZXl9IHNldERpc3BsYXlWYWx1ZSB3aXRoYCwgc3RyaW5nVmFsdWUpO1xuICAgICAgdGhpcy5kaXNwbGF5ZWRWYWx1ZSA9IHN0cmluZ1ZhbHVlO1xuICAgICAgcmV0dXJuIHN0cmluZ1ZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIGdldFNlbGVjdGVkT3B0aW9uKHZhbHVlOiBWYWx1ZVR5cGUpIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuaW5wdXQ/Lm9wdGlvbnM/LmZpbmQoKG9wdGlvbikgPT4gb3B0aW9uLmtleSA9PT0gdmFsdWUpO1xuICB9XG5cbiAgZ2V0IHNlbGVjdGVkT3B0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLmdldFNlbGVjdGVkT3B0aW9uKHRoaXMuY29uZmlnLnJlc29sdmVkVmFsdWU/LnZhbHVlKTtcbiAgfVxuXG4gIGFzeW5jIGZldGNoVmFsdWUoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmdldFZhbHVlKSB7XG4gICAgICB0aGlzLmluZm9SZXNvbHZlci5yZWZyZXNoS2V5KHRoaXMuY29uZmlnKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMudGFwSW5mb0NhY2hlU2VydmljZVxuICAgICAgICAuaW5mb0NoYW5nZSh0aGlzLmNvbmZpZylcbiAgICAgICAgLnBpcGUoXG4gICAgICAgICAgZmlsdGVyKCh2KSA9PiAhIXYubG9hZERhdGUpLFxuICAgICAgICAgIGZpcnN0KClcbiAgICAgICAgKVxuICAgICAgICAudG9Qcm9taXNlKCk7XG4gICAgfVxuICB9XG59XG4iLCI8aW9uLWl0ZW0gKm5nSWY9XCJfY29uZmlnXCIgW2xpbmVzXT1cImlzRWRpdGFibGUgPyAnJyA6ICdub25lJ1wiPlxuICA8aW9uLXNrZWxldG9uLXRleHRcbiAgICBhbmltYXRlZFxuICAgICpuZ0lmPVwiXG4gICAgICBkaXNwbGF5ZWRWYWx1ZSA9PT0gdW5kZWZpbmVkICYmIHJlYWRFcnJvciA9PT0gdW5kZWZpbmVkO1xuICAgICAgZWxzZSB2YWx1ZUZldGNoZWRUZW1wbGF0ZVxuICAgIFwiXG4gID48L2lvbi1za2VsZXRvbi10ZXh0PlxuICA8bmctdGVtcGxhdGUgI3ZhbHVlRmV0Y2hlZFRlbXBsYXRlPlxuICAgIDxuZy1jb250YWluZXJcbiAgICAgICpuZ0lmPVwicmVzc291cmNlQXZhaWxhYmxlOyBlbHNlIHJlc3NvdXJjZU5vdEF2YWlsYWJsZVRlbXBsYXRlXCJcbiAgICA+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWVkaXRNb2RlIHx8ICFpc0VkaXRhYmxlOyBlbHNlIGVkaXRNb2RlVGVtcGxhdGVcIj5cbiAgICAgICAgPGlvbi10ZXh0XG4gICAgICAgICAgY29sb3I9XCJ3YXJuaW5nXCJcbiAgICAgICAgICBjbGFzcz1cInJlYWQtdmFsdWUtZXJyb3JcIlxuICAgICAgICAgIChjbGljayk9XCJvblZhbHVlQ2xpY2soJGV2ZW50KVwiXG4gICAgICAgICAgW2NsYXNzXT1cImlzRWRpdGFibGUgPyAnY2VsbCcgOiAnJ1wiXG4gICAgICAgICAgKm5nSWY9XCJyZWFkRXJyb3I7IGVsc2Ugbm9SZWFkRXJyb3JUZW1wbGF0ZVwiXG4gICAgICAgID5cbiAgICAgICAgICA8aW9uLWljb24gbmFtZT1cImFsZXJ0LWNpcmNsZVwiPjwvaW9uLWljb24+XG4gICAgICAgICAge3sgcmVhZEVycm9yIHwgdGFwUmVxdWVzdEVycm9yVG9TdHJpbmcgfX1cbiAgICAgICAgPC9pb24tdGV4dD5cbiAgICAgICAgPG5nLXRlbXBsYXRlICNub1JlYWRFcnJvclRlbXBsYXRlPlxuICAgICAgICAgIDxuZy1jb250YWluZXIgW25nU3dpdGNoXT1cImlucHV0T3B0aW9ucy50eXBlXCI+XG4gICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1N3aXRjaENhc2U9XCIndG9nZ2xlJ1wiPlxuICAgICAgICAgICAgICA8aW9uLXRvZ2dsZSBbZGlzYWJsZWRdPVwidHJ1ZVwiIFtjaGVja2VkXT1cImZpZWxkLnZhbHVlXCI+PC9pb24tdG9nZ2xlXG4gICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8ZGl2XG4gICAgICAgICAgICAgIChjbGljayk9XCJvblZhbHVlQ2xpY2soJGV2ZW50KVwiXG4gICAgICAgICAgICAgICpuZ1N3aXRjaENhc2U9XCInc2VsZWN0J1wiXG4gICAgICAgICAgICAgIGNsYXNzPVwiaXRlbS12YWx1ZVwiXG4gICAgICAgICAgICAgIFtjbGFzc109XCJpc0VkaXRhYmxlID8gJ2NlbGwnIDogJydcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8aW9uLWljb25cbiAgICAgICAgICAgICAgICAqbmdJZj1cInNlbGVjdGVkT3B0aW9uPy5pY29uXCJcbiAgICAgICAgICAgICAgICBbbmFtZV09XCJzZWxlY3RlZE9wdGlvbj8uaWNvblwiXG4gICAgICAgICAgICAgID48L2lvbi1pY29uPlxuICAgICAgICAgICAgICA8aW9uLXRleHQgY2xhc3M9XCJ0YXAtY29uZmlnLWl0ZW0tdmFsdWVcIj5cbiAgICAgICAgICAgICAgICB7eyBkaXNwbGF5ZWRWYWx1ZSB9fVxuICAgICAgICAgICAgICA8L2lvbi10ZXh0PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8aW9uLXRleHRcbiAgICAgICAgICAgICAgKGNsaWNrKT1cIm9uVmFsdWVDbGljaygkZXZlbnQpXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJpdGVtLXZhbHVlIHRhcC1jb25maWctaXRlbS12YWx1ZVwiXG4gICAgICAgICAgICAgICpuZ1N3aXRjaERlZmF1bHRcbiAgICAgICAgICAgICAgW2NsYXNzXT1cImlzRWRpdGFibGUgPyAnY2VsbCcgOiAnJ1wiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7IGRpc3BsYXllZFZhbHVlIH19XG4gICAgICAgICAgICA8L2lvbi10ZXh0PlxuICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8bmctdGVtcGxhdGUgI2VkaXRNb2RlVGVtcGxhdGU+XG4gICAgICAgIDxuZy1jb250YWluZXIgW25nU3dpdGNoXT1cImlucHV0T3B0aW9ucy50eXBlXCI+XG4gICAgICAgICAgPGlvbi10b2dnbGVcbiAgICAgICAgICAgICpuZ1N3aXRjaENhc2U9XCIndG9nZ2xlJ1wiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwibG9hZGluZyB8fCAhIXBlbmRpbmdFZGl0Q2FsbFwiXG4gICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwiZmllbGRcIlxuICAgICAgICAgID48L2lvbi10b2dnbGU+XG4gICAgICAgICAgPGlvbi1zZWxlY3RcbiAgICAgICAgICAgIHN0eWxlPVwibWF4LXdpZHRoOiAxMDAlICFpbXBvcnRhbnRcIlxuICAgICAgICAgICAgKm5nU3dpdGNoQ2FzZT1cIidzZWxlY3QnXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJmaWVsZFwiXG4gICAgICAgICAgICBbbXVsdGlwbGVdPVwiaW5wdXRPcHRpb25zLm11bHRpcGxlXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8aW9uLXNlbGVjdC1vcHRpb25cbiAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IG9wdGlvbiBvZiBpbnB1dE9wdGlvbnMub3B0aW9uc1wiXG4gICAgICAgICAgICAgIFt2YWx1ZV09XCJvcHRpb24ua2V5XCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGlvbi1pY29uICpuZ0lmPVwib3B0aW9uLmljb25cIiBbbmFtZV09XCJvcHRpb24uaWNvblwiPjwvaW9uLWljb24+XG4gICAgICAgICAgICAgIHt7IG9wdGlvbi50ZXh0IH19XG4gICAgICAgICAgICA8L2lvbi1zZWxlY3Qtb3B0aW9uPlxuICAgICAgICAgICAgPGlvbi1zZWxlY3Qtb3B0aW9uXG4gICAgICAgICAgICAgICpuZ0Zvcj1cImxldCBlbnVtVmFsdWUgb2YgaW5wdXRPcHRpb25zLmVudW0/LmRhdGEgfCBsaXN0RW51bVZhbHVlc1wiXG4gICAgICAgICAgICAgIFt2YWx1ZV09XCJlbnVtVmFsdWVcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8aW9uLWljb25cbiAgICAgICAgICAgICAgICBbbmFtZV09XCJcbiAgICAgICAgICAgICAgICAgIGVudW1WYWx1ZVxuICAgICAgICAgICAgICAgICAgICB8IHRhcFJlc291cmNlRW51bVRyYW5zbGF0ZSA6ICdpY29uJyA6IGlucHV0T3B0aW9ucy5lbnVtXG4gICAgICAgICAgICAgICAgICAgIHwgYXN5bmNcbiAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICA+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAge3tcbiAgICAgICAgICAgICAgICBlbnVtVmFsdWVcbiAgICAgICAgICAgICAgICAgIHwgdGFwUmVzb3VyY2VFbnVtVHJhbnNsYXRlIDogJ3RpdGxlJyA6IGlucHV0T3B0aW9ucy5lbnVtXG4gICAgICAgICAgICAgICAgICB8IGFzeW5jXG4gICAgICAgICAgICAgIH19XG4gICAgICAgICAgICA8L2lvbi1zZWxlY3Qtb3B0aW9uPlxuICAgICAgICAgIDwvaW9uLXNlbGVjdD5cbiAgICAgICAgICA8aW9uLWlucHV0XG4gICAgICAgICAgICAqbmdTd2l0Y2hEZWZhdWx0XG4gICAgICAgICAgICAoa2V5ZG93bi5lbnRlcik9XCJzdWJtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAoa2V5ZG93bi5lc2NhcGUpPVwiY2FuY2VsRWRpdCgkZXZlbnQpXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhIXBlbmRpbmdFZGl0Q2FsbFwiXG4gICAgICAgICAgICBbbWF4bGVuZ3RoXT1cImlucHV0T3B0aW9ucy5tYXhMZW5ndGhcIlxuICAgICAgICAgICAgW21pbmxlbmd0aF09XCJpbnB1dE9wdGlvbnMubWluTGVuZ3RoXCJcbiAgICAgICAgICAgIFttYXhdPVwiaW5wdXRPcHRpb25zLm1heFwiXG4gICAgICAgICAgICBbbWluXT1cImlucHV0T3B0aW9ucy5taW5cIlxuICAgICAgICAgICAgW3BhdHRlcm5dPVwiaW5wdXRPcHRpb25zLnBhdHRlcm5cIlxuICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cInBsYWNlaG9sZGVyXCJcbiAgICAgICAgICAgIFt0eXBlXT1cImlucHV0T3B0aW9ucy50eXBlXCJcbiAgICAgICAgICAgIGFwcEF1dG9mb2N1c1xuICAgICAgICAgICAgY2xhc3M9XCJjZWxsSW5wdXRcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImZpZWxkXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgPC9pb24taW5wdXQ+XG4gICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgPC9uZy10ZW1wbGF0ZT5cbiAgICAgIDxpb24tYnV0dG9ucyBzbG90PVwiZW5kXCI+XG4gICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cImV4cGxhaW5QZW5kaW5nQ2FsbCgpXCJcbiAgICAgICAgICAqbmdJZj1cInBlbmRpbmdFZGl0Q2FsbFwiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cImZhbHNlXCJcbiAgICAgICAgICBjb2xvcj1cIndhcm5pbmdcIlxuICAgICAgICA+XG4gICAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJhbGVydC1jaXJjbGVcIj48L2lvbi1pY29uPlxuICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cImVkaXRNb2RlID0gdHJ1ZVwiXG4gICAgICAgICAgKm5nSWY9XCIhZ2xvYmFsU3VibWl0ICYmICFlZGl0TW9kZSAmJiBpbmZvLnB1dFZhbHVlXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwiY3JlYXRlXCI+PC9pb24taWNvbj5cbiAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICA8aW9uLWJ1dHRvblxuICAgICAgICAgIChjbGljayk9XCJzdWJtaXQoJGV2ZW50KVwiXG4gICAgICAgICAgKm5nSWY9XCIhZ2xvYmFsU3VibWl0ICYmIGVkaXRNb2RlICYmICFwZW5kaW5nRWRpdENhbGxcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJsb2FkaW5nIHx8IHBlbmRpbmdFZGl0Q2FsbFwiXG4gICAgICAgID5cbiAgICAgICAgICA8aW9uLWljb24gbmFtZT1cInNlbmRcIj48L2lvbi1pY29uPlxuICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cImNhbmNlbEVkaXQoKVwiXG4gICAgICAgICAgKm5nSWY9XCJpc0VkaXRhYmxlICYmIGVkaXRNb2RlICYmICghZ2xvYmFsU3VibWl0IHx8IGlzRWRpdGVkKCkpXCJcbiAgICAgICAgICBjb2xvcj1cInF1YXRlcm5hcnlcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJsb2FkaW5nXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwiY2xvc2VcIj48L2lvbi1pY29uPlxuICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cInJlZnJlc2hWYWx1ZSgpXCJcbiAgICAgICAgICAqbmdJZj1cInJlZnJlc2ggJiYgaW5mby5nZXRWYWx1ZSAmJiAhZWRpdE1vZGVcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCJsb2FkaW5nXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxpb24taWNvbiBuYW1lPVwic3luY1wiPjwvaW9uLWljb24+XG4gICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgIDwvaW9uLWJ1dHRvbnM+XG4gICAgICA8aW9uLXNwaW5uZXIgKm5nSWY9XCJsb2FkaW5nXCIgc2xvdD1cImVuZFwiPjwvaW9uLXNwaW5uZXI+XG4gICAgPC9uZy1jb250YWluZXI+XG4gICAgPG5nLXRlbXBsYXRlICNyZXNzb3VyY2VOb3RBdmFpbGFibGVUZW1wbGF0ZT5cbiAgICAgIDxpb24tdGV4dCBjb2xvcj1cIndhcm5pbmdcIiBjbGFzcz1cInJlYWQtdmFsdWUtZXJyb3JcIj5cbiAgICAgICAgPGlvbi1pY29uIG5hbWU9XCJhbGVydC1jaXJjbGVcIj48L2lvbi1pY29uPlxuICAgICAgICBOb3QgYXZhaWxhYmxlIHdpdGggeW91ciBmaXJtd2FyZSB2ZXJzaW9uIG9yIFRhcCBtb2RlbFxuICAgICAgPC9pb24tdGV4dD5cbiAgICA8L25nLXRlbXBsYXRlPlxuICA8L25nLXRlbXBsYXRlPlxuPC9pb24taXRlbT5cbjxpb24taXRlbSAqbmdJZj1cIndyaXRlRXJyb3JcIj5cbiAgPGlvbi10ZXh0IGNvbG9yPVwiZGFuZ2VyXCIgY2xhc3M9XCJ0YXAtY29uZmlnLWl0ZW0tZXJyb3JcIj5cbiAgICA8aW9uLWljb24gbmFtZT1cImFsZXJ0LWNpcmNsZVwiPjwvaW9uLWljb24+XG4gICAgRmFpbGVkIHRvIHdyaXRlIHZhbHVlOiB7eyB3cml0ZUVycm9yIHwgdGFwUmVxdWVzdEVycm9yVG9TdHJpbmcgfX1cbiAgPC9pb24tdGV4dD5cbjwvaW9uLWl0ZW0+XG48YXBwLWNvbW1vbi1mb3JtLWVycm9yLWl0ZW1cbiAgW2Zvcm1Db250cm9sUmVmXT1cImZpZWxkXCJcbj48L2FwcC1jb21tb24tZm9ybS1lcnJvci1pdGVtPlxuIl19