@iotize/ionic
Version:
Iotize specific building blocks on top of @ionic/angular.
314 lines • 49.6 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { Component, EventEmitter, Input, Output, ViewChild, } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { deepCopy } from '@iotize/common/utility';
import { TapValueEditorContainerComponent } from '@iotize/ionic';
import { NumberConverter, TapStreamReader, TapStreamWriter, } from '@iotize/tap/client/impl';
import { variableDataTypeToByteSize, } from '@iotize/tap/data';
import { VariableType } from '@iotize/tap/service/impl/variable';
import { BehaviorSubject, NEVER, Subject } from 'rxjs';
import { switchMap, takeUntil } from 'rxjs/operators';
import { MonitoringAppGenComponent } from '../../metadata/decorators';
import { TapVariableBitsEditorInfoModalComponent } from './tap-variable-bits-editor-info-modal/tap-variable-bits-editor-info-modal.component';
import * as i0 from "@angular/core";
import * as i1 from "@ionic/angular";
import * as i2 from "@angular/common";
import * as i3 from "@iotize/ionic";
let TapVariableBitsEditorComponent = class TapVariableBitsEditorComponent {
set variable(variable) {
this._variableChange.next(variable);
}
set bitsTemplate(template) {
template = sanitizeBitsTemplateParameter(template);
this._bitsTemplate = template;
if (template) {
this.bitsArrayEditable = deepCopy(template);
}
else {
this.bitsArrayEditable = [];
}
this._restoreLastValueReceived();
}
set value(v) {
if (v === undefined) {
v = 0;
}
this._setRawValue(v);
}
constructor(modalController) {
this.modalController = modalController;
this.bitsArrayEditable = [];
this._variableChange = new BehaviorSubject(undefined);
this.dataSuccessfullyUpdated = new EventEmitter();
this.showHelpButton = true;
this.bitOffColor = 'danger';
this.bitOnColor = 'success';
this.editable = true;
this.editButtonsColor = 'primary';
this.numberByteLength = 4;
this.destroyed = new Subject();
this.loaded = false;
this.onSaving = false;
this.editMode = false;
}
ngOnDestroy() {
this.destroyed.next();
}
ngOnInit() {
this._variableChange
.pipe(switchMap((variable) => {
if (variable) {
return variable.values;
}
else {
return NEVER;
}
}), takeUntil(this.destroyed))
.subscribe((rawVariableValue) => {
this._setRawValue(rawVariableValue);
});
}
_setRawValue(value) {
const rawValue = this._valueToBuffer(value);
this.rawStored = rawValue;
if (!this.editMode) {
this.rawToView(rawValue);
this.loaded = true;
}
}
rawToView(rawVariableValue) {
const tapStreamReader = TapStreamReader.fromArray(rawVariableValue);
if (this.bitsArrayEditable.length === 0) {
this._initBitsTemplate(rawVariableValue);
}
const bitSize = rawVariableValue.length * 8 - 1;
this.bitsArrayEditable.forEach((row) => {
for (let bit of row) {
const bitPosition = this._bitIndexToBufferPosition(bitSize, bit.index);
tapStreamReader.setBitPosition(bitPosition);
bit.value = tapStreamReader.readBoolean(1);
}
});
}
_initBitsTemplate(raw) {
let template = this._bitsTemplate;
if (!Array.isArray(template)) {
template = [[]];
for (let i = 0; i < raw.length * 8; i++) {
template[0].push({
description: 'No description',
label: i.toString(),
index: i,
});
}
}
for (let i = 0; i < template.length; i++) {
this.bitsArrayEditable.push([]);
for (let bit of template[i]) {
this.bitsArrayEditable[i].push({
...bit,
});
}
}
}
cancelEdit() {
this.editMode = false;
this._restoreLastValueReceived();
}
onEditMode() {
this.editMode = true;
}
async onClickEdit(bit) {
bit.value = !bit.value;
}
async onSaveEdit(variable) {
try {
if (!variable) {
return;
}
const variableByteLength = this.getNumberByteLength();
const bufferValue = this._userInputToBuffer(variableByteLength);
this.editMode = false;
this.onSaving = true;
if (typeof variable.writeRaw === 'function') {
await variable.writeRaw(bufferValue);
}
else {
const decodedValue = variable.converter
? variable.converter.decode(bufferValue)
: bufferValue;
await variable.write(decodedValue);
}
this.dataSuccessfullyUpdated.next('Data successfully updated !');
}
catch (error) {
this._restoreLastValueReceived();
this.ctx.error = error;
}
this.onSaving = false;
}
getNumberByteLength() {
return this.numberByteLength
? this.numberByteLength
: this._guessDataLength();
}
_restoreLastValueReceived() {
if (this.rawStored) {
this.rawToView(this.rawStored);
}
}
_valueToBuffer(value) {
if (typeof value === 'number') {
const variableByteLength = this.getNumberByteLength();
if (variableByteLength > 4) {
throw new Error(`Variable on ${variableByteLength} bytes are not supported.`);
}
else if (variableByteLength === 0) {
return new Uint8Array([]);
}
else {
const converter = new NumberConverter({
sizeOf: (variableByteLength * 8),
signed: false,
leastSignificantBitFirst: false,
});
return converter.encode(value);
}
}
else {
return value;
}
}
_bitIndexToBufferPosition(bitLength, index) {
return this.msb ? index : bitLength - index;
}
_userInputToBuffer(byteLength) {
const tapStreamWriter = TapStreamWriter.create(byteLength);
const bitLength = byteLength * 8 - 1;
this.bitsArrayEditable.forEach((row) => {
for (let bit of row) {
tapStreamWriter.setBitPosition(this._bitIndexToBufferPosition(bitLength, bit.index));
tapStreamWriter.writeBoolean(bit.value || false, 1);
}
});
tapStreamWriter.setBitPosition(bitLength);
const result = tapStreamWriter.toBytes;
console.log('DEBUG USER INPUT TO BUFFER', bitLength, deepCopy(this.bitsArrayEditable), 'result', result);
if (result.length !== byteLength) {
console.warn(`TapVariableBitsEditorComponent encoded value to write does not have the expected byte length of ${byteLength} bytes:`, result);
}
return result;
}
/**
* @deprecated use numberByteLength parameter instead
* @param variable
* @returns
*/
_guessDataLength(variable = this._variableChange.value) {
if (!variable) {
console.warn(`Cannot guess data length, variable is not set yet`);
return 0;
}
const tapVariableConfig = variable
.config;
const quantity = tapVariableConfig?.length || 1;
let unit;
if (tapVariableConfig?.dataType === undefined) {
// TODO fix with API change
console.warn(`TapVariableBitsEditorComponent failed to guess variable size. use 1 byte size. It may trigger error if size is not valid.`, variable);
unit = VariableType.Data.UINT32;
}
else {
unit = tapVariableConfig.dataType;
}
const length = quantity * variableDataTypeToByteSize(unit);
return length;
}
async showInfo() {
this._infoModal = this.modalController.create({
component: TapVariableBitsEditorInfoModalComponent,
componentProps: {
bitOnColor: this.bitOnColor,
bitOffColor: this.bitOffColor,
rows: this.bitsArrayEditable,
},
});
try {
const modal = await await this._infoModal;
modal.present();
await modal.onDidDismiss();
}
finally {
this._infoModal = undefined;
}
}
};
/** @nocollapse */ TapVariableBitsEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapVariableBitsEditorComponent, deps: [{ token: i1.ModalController }], target: i0.ɵɵFactoryTarget.Component });
/** @nocollapse */ TapVariableBitsEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: TapVariableBitsEditorComponent, selector: "tap-variable-bits-editor", inputs: { variable: "variable", showHelpButton: "showHelpButton", bitOffColor: "bitOffColor", bitOnColor: "bitOnColor", editable: "editable", editButtonsColor: "editButtonsColor", msb: "msb", numberByteLength: "numberByteLength", bitsTemplate: "bitsTemplate", value: "value" }, outputs: { dataSuccessfullyUpdated: "dataSuccessfullyUpdated" }, viewQueries: [{ propertyName: "ctx", first: true, predicate: ["ctx"], descendants: true }], ngImport: i0, template: "<tap-value-editor-container\n #ctx\n [variable]=\"_variableChange.value\"\n [showEditButton]=\"false\"\n [showSubmitButton]=\"false\"\n [lines]=\"'none'\"\n *ngIf=\"bitsArrayEditable.length > 0; else noBitsTemplate\"\n>\n <ion-grid id=\"ionGrid\">\n <ion-row *ngFor=\"let row of bitsArrayEditable\" class=\"row-bits\">\n <div class=\"bit-div\" *ngFor=\"let bit of row\">\n <ion-fab-button\n (click)=\"onClickEdit(bit)\"\n class=\"fab-row\"\n size=\"small\"\n [color]=\"\n (bit.value && !bit.reverse) || (!bit.value && bit.reverse)\n ? bitOnColor\n : bitOffColor\n \"\n [disabled]=\"!editMode\"\n >\n </ion-fab-button>\n <ion-label class=\"label-under\">\n {{ bit.label }}\n </ion-label>\n </div>\n </ion-row>\n <ion-item lines=\"none\" *ngIf=\"editable || showHelpButton\">\n <ion-buttons id=\"buttonsBottom\">\n <ion-button\n fill=\"clear\"\n (click)=\"showInfo()\"\n [color]=\"editButtonsColor\"\n *ngIf=\"showHelpButton\"\n >\n <ion-icon\n class=\"button-edit-icon\"\n name=\"information-circle\"\n ></ion-icon>\n </ion-button>\n <ng-container *ngIf=\"editable\">\n <ion-button\n [color]=\"editButtonsColor\"\n fill=\"clear\"\n [disabled]=\"onSaving\"\n (click)=\"onEditMode()\"\n *ngIf=\"!editMode\"\n >\n <ion-icon class=\"button-edit-icon\" name=\"pencil\"></ion-icon>\n </ion-button>\n <ion-button\n fill=\"clear\"\n (click)=\"cancelEdit()\"\n *ngIf=\"editMode\"\n [color]=\"editButtonsColor\"\n >\n <ion-icon class=\"button-edit-icon\" name=\"close\"></ion-icon>\n </ion-button>\n <ion-button\n fill=\"clear\"\n [color]=\"editButtonsColor\"\n [disabled]=\"!editMode\"\n (click)=\"onSaveEdit(_variableChange.value)\"\n *ngIf=\"!onSaving; else saveLoader\"\n >\n <ion-icon class=\"button-edit-icon\" name=\"save\"></ion-icon>\n </ion-button>\n <ng-template #saveLoader>\n <ion-spinner\n [color]=\"editButtonsColor\"\n name=\"crescent\"\n ></ion-spinner> </ng-template\n ></ng-container>\n </ion-buttons>\n </ion-item>\n </ion-grid>\n</tap-value-editor-container>\n<ng-template #noBitsTemplate>\n <ion-progress-bar type=\"indeterminate\"></ion-progress-bar>\n</ng-template>\n", styles: [".checkbox-bit{--border-radius: 5px }ion-label{opacity:1!important}ion-checkbox{opacity:1!important}.fab-row{height:2em;width:2em;margin:.3vw}.row-bits{display:flex;justify-content:center}.icon-bit{font-size:2.3em}ion-fab-button{opacity:1!important}.button-edit-icon{font-size:2em}.span-description{white-space:pre-line!important}.bit-label-info{font-weight:500}.bit-div{text-align:center;margin:2px}.label-under{writing-mode:vertical-lr;transform:rotate(180deg);margin:auto;font-family:system-ui;padding-left:4px}#buttonsBottom{margin:auto}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.TapValueEditorContainerComponent, selector: "tap-value-editor-container", inputs: ["button", "variable", "inputOptions", "showRefreshButton", "showSubmitButton", "showEditButton", "error", "lines", "modalEdition", "value"], outputs: ["submit", "refresh"] }, { kind: "component", type: i1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i1.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i1.IonFabButton, selector: "ion-fab-button", inputs: ["activated", "closeIcon", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "show", "size", "target", "translucent", "type"] }, { kind: "component", type: i1.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i1.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i1.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i1.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i1.IonProgressBar, selector: "ion-progress-bar", inputs: ["buffer", "color", "mode", "reversed", "type", "value"] }, { kind: "component", type: i1.IonRow, selector: "ion-row" }, { kind: "component", type: i1.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }] });
TapVariableBitsEditorComponent = __decorate([
MonitoringAppGenComponent({
constraints: {
isNumber: 'YES',
isArray: 'NO',
},
events: [
{
name: 'submit',
dataType: 'number',
},
],
}),
__metadata("design:paramtypes", [ModalController])
], TapVariableBitsEditorComponent);
export { TapVariableBitsEditorComponent };
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: TapVariableBitsEditorComponent, decorators: [{
type: Component,
args: [{ selector: 'tap-variable-bits-editor', template: "<tap-value-editor-container\n #ctx\n [variable]=\"_variableChange.value\"\n [showEditButton]=\"false\"\n [showSubmitButton]=\"false\"\n [lines]=\"'none'\"\n *ngIf=\"bitsArrayEditable.length > 0; else noBitsTemplate\"\n>\n <ion-grid id=\"ionGrid\">\n <ion-row *ngFor=\"let row of bitsArrayEditable\" class=\"row-bits\">\n <div class=\"bit-div\" *ngFor=\"let bit of row\">\n <ion-fab-button\n (click)=\"onClickEdit(bit)\"\n class=\"fab-row\"\n size=\"small\"\n [color]=\"\n (bit.value && !bit.reverse) || (!bit.value && bit.reverse)\n ? bitOnColor\n : bitOffColor\n \"\n [disabled]=\"!editMode\"\n >\n </ion-fab-button>\n <ion-label class=\"label-under\">\n {{ bit.label }}\n </ion-label>\n </div>\n </ion-row>\n <ion-item lines=\"none\" *ngIf=\"editable || showHelpButton\">\n <ion-buttons id=\"buttonsBottom\">\n <ion-button\n fill=\"clear\"\n (click)=\"showInfo()\"\n [color]=\"editButtonsColor\"\n *ngIf=\"showHelpButton\"\n >\n <ion-icon\n class=\"button-edit-icon\"\n name=\"information-circle\"\n ></ion-icon>\n </ion-button>\n <ng-container *ngIf=\"editable\">\n <ion-button\n [color]=\"editButtonsColor\"\n fill=\"clear\"\n [disabled]=\"onSaving\"\n (click)=\"onEditMode()\"\n *ngIf=\"!editMode\"\n >\n <ion-icon class=\"button-edit-icon\" name=\"pencil\"></ion-icon>\n </ion-button>\n <ion-button\n fill=\"clear\"\n (click)=\"cancelEdit()\"\n *ngIf=\"editMode\"\n [color]=\"editButtonsColor\"\n >\n <ion-icon class=\"button-edit-icon\" name=\"close\"></ion-icon>\n </ion-button>\n <ion-button\n fill=\"clear\"\n [color]=\"editButtonsColor\"\n [disabled]=\"!editMode\"\n (click)=\"onSaveEdit(_variableChange.value)\"\n *ngIf=\"!onSaving; else saveLoader\"\n >\n <ion-icon class=\"button-edit-icon\" name=\"save\"></ion-icon>\n </ion-button>\n <ng-template #saveLoader>\n <ion-spinner\n [color]=\"editButtonsColor\"\n name=\"crescent\"\n ></ion-spinner> </ng-template\n ></ng-container>\n </ion-buttons>\n </ion-item>\n </ion-grid>\n</tap-value-editor-container>\n<ng-template #noBitsTemplate>\n <ion-progress-bar type=\"indeterminate\"></ion-progress-bar>\n</ng-template>\n", styles: [".checkbox-bit{--border-radius: 5px }ion-label{opacity:1!important}ion-checkbox{opacity:1!important}.fab-row{height:2em;width:2em;margin:.3vw}.row-bits{display:flex;justify-content:center}.icon-bit{font-size:2.3em}ion-fab-button{opacity:1!important}.button-edit-icon{font-size:2em}.span-description{white-space:pre-line!important}.bit-label-info{font-weight:500}.bit-div{text-align:center;margin:2px}.label-under{writing-mode:vertical-lr;transform:rotate(180deg);margin:auto;font-family:system-ui;padding-left:4px}#buttonsBottom{margin:auto}\n"] }]
}], ctorParameters: function () { return [{ type: i1.ModalController }]; }, propDecorators: { ctx: [{
type: ViewChild,
args: ['ctx']
}], dataSuccessfullyUpdated: [{
type: Output
}], variable: [{
type: Input
}], showHelpButton: [{
type: Input
}], bitOffColor: [{
type: Input
}], bitOnColor: [{
type: Input
}], editable: [{
type: Input
}], editButtonsColor: [{
type: Input
}], msb: [{
type: Input
}], numberByteLength: [{
type: Input
}], bitsTemplate: [{
type: Input
}], value: [{
type: Input
}] } });
export function sanitizeBitsTemplateParameter(template) {
if (Array.isArray(template) &&
template.length > 0 &&
!Array.isArray(template[0])) {
template = [template];
}
if (template && !Array.isArray(template)) {
template = [];
}
if (template) {
template = template.filter((row) => {
return !!row && Array.isArray(row);
});
template.forEach((row, index) => {
template[index] = row.filter((item) => {
return !!item && typeof item === 'object';
});
});
}
return template;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFwLXZhcmlhYmxlLWJpdHMtZWRpdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9tb25pdG9yaW5nL3NyYy9saWIvdWktY29tcG9uZW50cy90YXAtdmFyaWFibGUtYml0cy1lZGl0b3IvdGFwLXZhcmlhYmxlLWJpdHMtZWRpdG9yLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2lvdGl6ZS1pb25pYy9tb25pdG9yaW5nL3NyYy9saWIvdWktY29tcG9uZW50cy90YXAtdmFyaWFibGUtYml0cy1lZGl0b3IvdGFwLXZhcmlhYmxlLWJpdHMtZWRpdG9yLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksRUFFWixLQUFLLEVBR0wsTUFBTSxFQUNOLFNBQVMsR0FDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDakQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2xELE9BQU8sRUFBRSxnQ0FBZ0MsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNqRSxPQUFPLEVBQ0wsZUFBZSxFQUNmLGVBQWUsRUFDZixlQUFlLEdBQ2hCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxFQUdMLDBCQUEwQixHQUMzQixNQUFNLGtCQUFrQixDQUFDO0FBRTFCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUseUJBQXlC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S0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7UUFDdkIsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQ25CLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFDM0I7UUFDQSxRQUFRLEdBQUcsQ0FBQyxRQUFvQyxDQUFDLENBQUM7S0FDbkQ7SUFDRCxJQUFJLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUU7UUFDeEMsUUFBUSxHQUFHLEVBQUUsQ0FBQztLQUNmO0lBQ0QsSUFBSSxRQUFRLEVBQUU7UUFDWixRQUFRLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQ2pDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3JDLENBQUMsQ0FBQyxDQUFDO1FBQ0gsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUM5QixRQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO2dCQUN0QyxPQUFPLENBQUMsQ0FBQyxJQUFJLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxDQUFDO1lBQzVDLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7S0FDSjtJQUNELE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE1vZGFsQ29udHJvbGxlciB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyJztcbmltcG9ydCB7IGRlZXBDb3B5IH0gZnJvbSAnQGlvdGl6ZS9jb21tb24vdXRpbGl0eSc7XG5pbXBvcnQgeyBUYXBWYWx1ZUVkaXRvckNvbnRhaW5lckNvbXBvbmVudCB9IGZyb20gJ0Bpb3RpemUvaW9uaWMnO1xuaW1wb3J0IHtcbiAgTnVtYmVyQ29udmVydGVyLFxuICBUYXBTdHJlYW1SZWFkZXIsXG4gIFRhcFN0cmVhbVdyaXRlcixcbn0gZnJvbSAnQGlvdGl6ZS90YXAvY2xpZW50L2ltcGwnO1xuaW1wb3J0IHtcbiAgQWJzdHJhY3RWYXJpYWJsZSxcbiAgVGFwVmFyaWFibGUsXG4gIHZhcmlhYmxlRGF0YVR5cGVUb0J5dGVTaXplLFxufSBmcm9tICdAaW90aXplL3RhcC9kYXRhJztcbmltcG9ydCB7IEtleVR5cGVUeXBlIH0gZnJvbSAnQGlvdGl6ZS90YXAvZGF0YS9saWIvdXRpbGl0eS9lZGl0YWJsZS1kYXRhLXN0cmVhbSc7XG5pbXBvcnQgeyBWYXJpYWJsZVR5cGUgfSBmcm9tICdAaW90aXplL3RhcC9zZXJ2aWNlL2ltcGwvdmFyaWFibGUnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBORVZFUiwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgc3dpdGNoTWFwLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBNb25pdG9yaW5nQXBwR2VuQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vbWV0YWRhdGEvZGVjb3JhdG9ycyc7XG5pbXBvcnQgeyBCaXQsIEJpdFRlbXBsYXRlIH0gZnJvbSAnLi9kZWZpbml0aW9ucyc7XG5pbXBvcnQgeyBUYXBWYXJpYWJsZUJpdHNFZGl0b3JJbmZvTW9kYWxDb21wb25lbnQgfSBmcm9tICcuL3RhcC12YXJpYWJsZS1iaXRzLWVkaXRvci1pbmZvLW1vZGFsL3RhcC12YXJpYWJsZS1iaXRzLWVkaXRvci1pbmZvLW1vZGFsLmNvbXBvbmVudCc7XG5cbkBNb25pdG9yaW5nQXBwR2VuQ29tcG9uZW50KHtcbiAgY29uc3RyYWludHM6IHtcbiAgICBpc051bWJlcjogJ1lFUycsXG4gICAgaXNBcnJheTogJ05PJyxcbiAgfSxcbiAgZXZlbnRzOiBbXG4gICAge1xuICAgICAgbmFtZTogJ3N1Ym1pdCcsXG4gICAgICBkYXRhVHlwZTogJ251bWJlcicsXG4gICAgfSxcbiAgXSxcbn0pXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0YXAtdmFyaWFibGUtYml0cy1lZGl0b3InLFxuICB0ZW1wbGF0ZVVybDogJy4vdGFwLXZhcmlhYmxlLWJpdHMtZWRpdG9yLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vdGFwLXZhcmlhYmxlLWJpdHMtZWRpdG9yLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIFRhcFZhcmlhYmxlQml0c0VkaXRvckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgQFZpZXdDaGlsZCgnY3R4JykgY3R4ITogVGFwVmFsdWVFZGl0b3JDb250YWluZXJDb21wb25lbnQ7XG5cbiAgYml0c0FycmF5RWRpdGFibGU6IEJpdFtdW10gPSBbXTtcblxuICBfdmFyaWFibGVDaGFuZ2UgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFxuICAgIEFic3RyYWN0VmFyaWFibGU8bnVtYmVyIHwgVWludDhBcnJheT4gfCB1bmRlZmluZWRcbiAgPih1bmRlZmluZWQpO1xuXG4gIEBPdXRwdXQoKSBkYXRhU3VjY2Vzc2Z1bGx5VXBkYXRlZCA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuXG4gIEBJbnB1dCgpXG4gIHNldCB2YXJpYWJsZSh2YXJpYWJsZTogQWJzdHJhY3RWYXJpYWJsZTxudW1iZXIgfCBVaW50OEFycmF5PiB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMuX3ZhcmlhYmxlQ2hhbmdlLm5leHQodmFyaWFibGUpO1xuICB9XG5cbiAgQElucHV0KCkgc2hvd0hlbHBCdXR0b24gPSB0cnVlO1xuXG4gIEBJbnB1dCgpXG4gIGJpdE9mZkNvbG9yOiBzdHJpbmcgPSAnZGFuZ2VyJztcblxuICBASW5wdXQoKVxuICBiaXRPbkNvbG9yOiBzdHJpbmcgPSAnc3VjY2Vzcyc7XG5cbiAgQElucHV0KClcbiAgZWRpdGFibGUgPSB0cnVlO1xuXG4gIEBJbnB1dCgpXG4gIGVkaXRCdXR0b25zQ29sb3I/OiBzdHJpbmcgPSAncHJpbWFyeSc7XG5cbiAgQElucHV0KCkgbXNiPzogYm9vbGVhbjtcblxuICBASW5wdXQoKSBudW1iZXJCeXRlTGVuZ3RoOiAxIHwgMiB8IDQgPSA0O1xuXG4gIEBJbnB1dCgpXG4gIHNldCBiaXRzVGVtcGxhdGUodGVtcGxhdGU6IEJpdFRlbXBsYXRlW11bXSB8IHVuZGVmaW5lZCkge1xuICAgIHRlbXBsYXRlID0gc2FuaXRpemVCaXRzVGVtcGxhdGVQYXJhbWV0ZXIodGVtcGxhdGUpO1xuICAgIHRoaXMuX2JpdHNUZW1wbGF0ZSA9IHRlbXBsYXRlO1xuICAgIGlmICh0ZW1wbGF0ZSkge1xuICAgICAgdGhpcy5iaXRzQXJyYXlFZGl0YWJsZSA9IGRlZXBDb3B5KHRlbXBsYXRlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5iaXRzQXJyYXlFZGl0YWJsZSA9IFtdO1xuICAgIH1cbiAgICB0aGlzLl9yZXN0b3JlTGFzdFZhbHVlUmVjZWl2ZWQoKTtcbiAgfVxuXG4gIEBJbnB1dCgpXG4gIHNldCB2YWx1ZSh2OiBudW1iZXIgfCBVaW50OEFycmF5IHwgdW5kZWZpbmVkKSB7XG4gICAgaWYgKHYgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdiA9IDA7XG4gICAgfVxuICAgIHRoaXMuX3NldFJhd1ZhbHVlKHYpO1xuICB9XG5cbiAgcHJpdmF0ZSBfYml0c1RlbXBsYXRlOiBCaXRUZW1wbGF0ZVtdW10gfCB1bmRlZmluZWQ7XG5cbiAgcHJpdmF0ZSBkZXN0cm95ZWQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIGxvYWRlZDogYm9vbGVhbiA9IGZhbHNlO1xuICBvblNhdmluZzogYm9vbGVhbiA9IGZhbHNlO1xuICBlZGl0TW9kZTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIHJhd1N0b3JlZD86IFVpbnQ4QXJyYXk7XG5cbiAgcHJpdmF0ZSBfaW5mb01vZGFsPzogUHJvbWlzZTxIVE1MSW9uTW9kYWxFbGVtZW50PjtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIG1vZGFsQ29udHJvbGxlcjogTW9kYWxDb250cm9sbGVyKSB7fVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveWVkLm5leHQoKTtcbiAgfVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMuX3ZhcmlhYmxlQ2hhbmdlXG4gICAgICAucGlwZShcbiAgICAgICAgc3dpdGNoTWFwKCh2YXJpYWJsZSkgPT4ge1xuICAgICAgICAgIGlmICh2YXJpYWJsZSkge1xuICAgICAgICAgICAgcmV0dXJuIHZhcmlhYmxlLnZhbHVlcztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIE5FVkVSO1xuICAgICAgICAgIH1cbiAgICAgICAgfSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3llZClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKHJhd1ZhcmlhYmxlVmFsdWUpID0+IHtcbiAgICAgICAgdGhpcy5fc2V0UmF3VmFsdWUocmF3VmFyaWFibGVWYWx1ZSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgX3NldFJhd1ZhbHVlKHZhbHVlOiBVaW50OEFycmF5IHwgbnVtYmVyKSB7XG4gICAgY29uc3QgcmF3VmFsdWUgPSB0aGlzLl92YWx1ZVRvQnVmZmVyKHZhbHVlKTtcbiAgICB0aGlzLnJhd1N0b3JlZCA9IHJhd1ZhbHVlO1xuICAgIGlmICghdGhpcy5lZGl0TW9kZSkge1xuICAgICAgdGhpcy5yYXdUb1ZpZXcocmF3VmFsdWUpO1xuICAgICAgdGhpcy5sb2FkZWQgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcmF3VG9WaWV3KHJhd1ZhcmlhYmxlVmFsdWU6IFVpbnQ4QXJyYXkpIHtcbiAgICBjb25zdCB0YXBTdHJlYW1SZWFkZXIgPSBUYXBTdHJlYW1SZWFkZXIuZnJvbUFycmF5KHJhd1ZhcmlhYmxlVmFsdWUpO1xuICAgIGlmICh0aGlzLmJpdHNBcnJheUVkaXRhYmxlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5faW5pdEJpdHNUZW1wbGF0ZShyYXdWYXJpYWJsZVZhbHVlKTtcbiAgICB9XG4gICAgY29uc3QgYml0U2l6ZSA9IHJhd1ZhcmlhYmxlVmFsdWUubGVuZ3RoICogOCAtIDE7XG4gICAgdGhpcy5iaXRzQXJyYXlFZGl0YWJsZS5mb3JFYWNoKChyb3cpID0+IHtcbiAgICAgIGZvciAobGV0IGJpdCBvZiByb3cpIHtcbiAgICAgICAgY29uc3QgYml0UG9zaXRpb24gPSB0aGlzLl9iaXRJbmRleFRvQnVmZmVyUG9zaXRpb24oYml0U2l6ZSwgYml0LmluZGV4KTtcbiAgICAgICAgdGFwU3RyZWFtUmVhZGVyLnNldEJpdFBvc2l0aW9uKGJpdFBvc2l0aW9uKTtcbiAgICAgICAgYml0LnZhbHVlID0gdGFwU3RyZWFtUmVhZGVyLnJlYWRCb29sZWFuKDEpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfaW5pdEJpdHNUZW1wbGF0ZShyYXc6IFVpbnQ4QXJyYXkpIHtcbiAgICBsZXQgdGVtcGxhdGUgPSB0aGlzLl9iaXRzVGVtcGxhdGU7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHRlbXBsYXRlKSkge1xuICAgICAgdGVtcGxhdGUgPSBbW11dO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByYXcubGVuZ3RoICogODsgaSsrKSB7XG4gICAgICAgIHRlbXBsYXRlWzBdLnB1c2goe1xuICAgICAgICAgIGRlc2NyaXB0aW9uOiAnTm8gZGVzY3JpcHRpb24nLFxuICAgICAgICAgIGxhYmVsOiBpLnRvU3RyaW5nKCksXG4gICAgICAgICAgaW5kZXg6IGksXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRlbXBsYXRlLmxlbmd0aDsgaSsrKSB7XG4gICAgICB0aGlzLmJpdHNBcnJheUVkaXRhYmxlLnB1c2goW10pO1xuICAgICAgZm9yIChsZXQgYml0IG9mIHRlbXBsYXRlW2ldKSB7XG4gICAgICAgIHRoaXMuYml0c0FycmF5RWRpdGFibGVbaV0ucHVzaCh7XG4gICAgICAgICAgLi4uYml0LFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjYW5jZWxFZGl0KCkge1xuICAgIHRoaXMuZWRpdE1vZGUgPSBmYWxzZTtcbiAgICB0aGlzLl9yZXN0b3JlTGFzdFZhbHVlUmVjZWl2ZWQoKTtcbiAgfVxuXG4gIG9uRWRpdE1vZGUoKSB7XG4gICAgdGhpcy5lZGl0TW9kZSA9IHRydWU7XG4gIH1cblxuICBhc3luYyBvbkNsaWNrRWRpdChiaXQ6IEJpdCkge1xuICAgIGJpdC52YWx1ZSA9ICFiaXQudmFsdWU7XG4gIH1cblxuICBhc3luYyBvblNhdmVFZGl0KFxuICAgIHZhcmlhYmxlOiBBYnN0cmFjdFZhcmlhYmxlPG51bWJlciB8IFVpbnQ4QXJyYXk+IHwgdW5kZWZpbmVkXG4gICkge1xuICAgIHRyeSB7XG4gICAgICBpZiAoIXZhcmlhYmxlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHZhcmlhYmxlQnl0ZUxlbmd0aCA9IHRoaXMuZ2V0TnVtYmVyQnl0ZUxlbmd0aCgpO1xuICAgICAgY29uc3QgYnVmZmVyVmFsdWUgPSB0aGlzLl91c2VySW5wdXRUb0J1ZmZlcih2YXJpYWJsZUJ5dGVMZW5ndGgpO1xuICAgICAgdGhpcy5lZGl0TW9kZSA9IGZhbHNlO1xuICAgICAgdGhpcy5vblNhdmluZyA9IHRydWU7XG4gICAgICBpZiAodHlwZW9mIHZhcmlhYmxlLndyaXRlUmF3ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGF3YWl0IHZhcmlhYmxlLndyaXRlUmF3KGJ1ZmZlclZhbHVlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGRlY29kZWRWYWx1ZSA9IHZhcmlhYmxlLmNvbnZlcnRlclxuICAgICAgICAgID8gdmFyaWFibGUuY29udmVydGVyLmRlY29kZShidWZmZXJWYWx1ZSlcbiAgICAgICAgICA6IGJ1ZmZlclZhbHVlO1xuICAgICAgICBhd2FpdCB2YXJpYWJsZS53cml0ZShkZWNvZGVkVmFsdWUpO1xuICAgICAgfVxuICAgICAgdGhpcy5kYXRhU3VjY2Vzc2Z1bGx5VXBkYXRlZC5uZXh0KCdEYXRhIHN1Y2Nlc3NmdWxseSB1cGRhdGVkICEnKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhpcy5fcmVzdG9yZUxhc3RWYWx1ZVJlY2VpdmVkKCk7XG4gICAgICB0aGlzLmN0eC5lcnJvciA9IGVycm9yIGFzIEVycm9yO1xuICAgIH1cbiAgICB0aGlzLm9uU2F2aW5nID0gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIGdldE51bWJlckJ5dGVMZW5ndGgoKSB7XG4gICAgcmV0dXJuIHRoaXMubnVtYmVyQnl0ZUxlbmd0aFxuICAgICAgPyB0aGlzLm51bWJlckJ5dGVMZW5ndGhcbiAgICAgIDogdGhpcy5fZ3Vlc3NEYXRhTGVuZ3RoKCk7XG4gIH1cblxuICBwcml2YXRlIF9yZXN0b3JlTGFzdFZhbHVlUmVjZWl2ZWQoKSB7XG4gICAgaWYgKHRoaXMucmF3U3RvcmVkKSB7XG4gICAgICB0aGlzLnJhd1RvVmlldyh0aGlzLnJhd1N0b3JlZCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfdmFsdWVUb0J1ZmZlcih2YWx1ZTogbnVtYmVyIHwgVWludDhBcnJheSkge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgICBjb25zdCB2YXJpYWJsZUJ5dGVMZW5ndGggPSB0aGlzLmdldE51bWJlckJ5dGVMZW5ndGgoKTtcbiAgICAgIGlmICh2YXJpYWJsZUJ5dGVMZW5ndGggPiA0KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgVmFyaWFibGUgb24gJHt2YXJpYWJsZUJ5dGVMZW5ndGh9IGJ5dGVzIGFyZSBub3Qgc3VwcG9ydGVkLmBcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSBpZiAodmFyaWFibGVCeXRlTGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiBuZXcgVWludDhBcnJheShbXSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBjb252ZXJ0ZXIgPSBuZXcgTnVtYmVyQ29udmVydGVyKHtcbiAgICAgICAgICBzaXplT2Y6ICh2YXJpYWJsZUJ5dGVMZW5ndGggKiA4KSBhcyA4IHwgMTYgfCAzMixcbiAgICAgICAgICBzaWduZWQ6IGZhbHNlLFxuICAgICAgICAgIGxlYXN0U2lnbmlmaWNhbnRCaXRGaXJzdDogZmFsc2UsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gY29udmVydGVyLmVuY29kZSh2YWx1ZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9iaXRJbmRleFRvQnVmZmVyUG9zaXRpb24oYml0TGVuZ3RoOiBudW1iZXIsIGluZGV4OiBudW1iZXIpIHtcbiAgICByZXR1cm4gdGhpcy5tc2IgPyBpbmRleCA6IGJpdExlbmd0aCAtIGluZGV4O1xuICB9XG5cbiAgcHJpdmF0ZSBfdXNlcklucHV0VG9CdWZmZXIoYnl0ZUxlbmd0aDogbnVtYmVyKTogVWludDhBcnJheSB7XG4gICAgY29uc3QgdGFwU3RyZWFtV3JpdGVyID0gVGFwU3RyZWFtV3JpdGVyLmNyZWF0ZShieXRlTGVuZ3RoKTtcbiAgICBjb25zdCBiaXRMZW5ndGggPSBieXRlTGVuZ3RoICogOCAtIDE7XG4gICAgdGhpcy5iaXRzQXJyYXlFZGl0YWJsZS5mb3JFYWNoKChyb3cpID0+IHtcbiAgICAgIGZvciAobGV0IGJpdCBvZiByb3cpIHtcbiAgICAgICAgdGFwU3RyZWFtV3JpdGVyLnNldEJpdFBvc2l0aW9uKFxuICAgICAgICAgIHRoaXMuX2JpdEluZGV4VG9CdWZmZXJQb3NpdGlvbihiaXRMZW5ndGgsIGJpdC5pbmRleClcbiAgICAgICAgKTtcbiAgICAgICAgdGFwU3RyZWFtV3JpdGVyLndyaXRlQm9vbGVhbihiaXQudmFsdWUgfHwgZmFsc2UsIDEpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRhcFN0cmVhbVdyaXRlci5zZXRCaXRQb3NpdGlvbihiaXRMZW5ndGgpO1xuICAgIGNvbnN0IHJlc3VsdCA9IHRhcFN0cmVhbVdyaXRlci50b0J5dGVzO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgJ0RFQlVHIFVTRVIgSU5QVVQgVE8gQlVGRkVSJyxcbiAgICAgIGJpdExlbmd0aCxcbiAgICAgIGRlZXBDb3B5KHRoaXMuYml0c0FycmF5RWRpdGFibGUpLFxuICAgICAgJ3Jlc3VsdCcsXG4gICAgICByZXN1bHRcbiAgICApO1xuICAgIGlmIChyZXN1bHQubGVuZ3RoICE9PSBieXRlTGVuZ3RoKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgIGBUYXBWYXJpYWJsZUJpdHNFZGl0b3JDb21wb25lbnQgZW5jb2RlZCB2YWx1ZSB0byB3cml0ZSBkb2VzIG5vdCBoYXZlIHRoZSBleHBlY3RlZCBieXRlIGxlbmd0aCBvZiAke2J5dGVMZW5ndGh9IGJ5dGVzOmAsXG4gICAgICAgIHJlc3VsdFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgbnVtYmVyQnl0ZUxlbmd0aCBwYXJhbWV0ZXIgaW5zdGVhZFxuICAgKiBAcGFyYW0gdmFyaWFibGVcbiAgICogQHJldHVybnNcbiAgICovXG4gIHByaXZhdGUgX2d1ZXNzRGF0YUxlbmd0aCh2YXJpYWJsZSA9IHRoaXMuX3ZhcmlhYmxlQ2hhbmdlLnZhbHVlKTogbnVtYmVyIHtcbiAgICBpZiAoIXZhcmlhYmxlKSB7XG4gICAgICBjb25zb2xlLndhcm4oYENhbm5vdCBndWVzcyBkYXRhIGxlbmd0aCwgdmFyaWFibGUgaXMgbm90IHNldCB5ZXRgKTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBjb25zdCB0YXBWYXJpYWJsZUNvbmZpZyA9ICh2YXJpYWJsZSBhcyBUYXBWYXJpYWJsZTx1bmtub3duLCBLZXlUeXBlVHlwZT4pXG4gICAgICAuY29uZmlnO1xuICAgIGNvbnN0IHF1YW50aXR5ID0gdGFwVmFyaWFibGVDb25maWc/Lmxlbmd0aCB8fCAxO1xuICAgIGxldCB1bml0OiBWYXJpYWJsZVR5cGUuRGF0YTtcbiAgICBpZiAodGFwVmFyaWFibGVDb25maWc/LmRhdGFUeXBlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIC8vIFRPRE8gZml4IHdpdGggQVBJIGNoYW5nZVxuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBgVGFwVmFyaWFibGVCaXRzRWRpdG9yQ29tcG9uZW50IGZhaWxlZCB0byBndWVzcyB2YXJpYWJsZSBzaXplLiB1c2UgMSBieXRlIHNpemUuIEl0IG1heSB0cmlnZ2VyIGVycm9yIGlmIHNpemUgaXMgbm90IHZhbGlkLmAsXG4gICAgICAgIHZhcmlhYmxlXG4gICAgICApO1xuICAgICAgdW5pdCA9IFZhcmlhYmxlVHlwZS5EYXRhLlVJTlQzMjtcbiAgICB9IGVsc2Uge1xuICAgICAgdW5pdCA9IHRhcFZhcmlhYmxlQ29uZmlnLmRhdGFUeXBlO1xuICAgIH1cbiAgICBjb25zdCBsZW5ndGggPSBxdWFudGl0eSAqIHZhcmlhYmxlRGF0YVR5cGVUb0J5dGVTaXplKHVuaXQpO1xuICAgIHJldHVybiBsZW5ndGg7XG4gIH1cblxuICBhc3luYyBzaG93SW5mbygpIHtcbiAgICB0aGlzLl9pbmZvTW9kYWwgPSB0aGlzLm1vZGFsQ29udHJvbGxlci5jcmVhdGUoe1xuICAgICAgY29tcG9uZW50OiBUYXBWYXJpYWJsZUJpdHNFZGl0b3JJbmZvTW9kYWxDb21wb25lbnQsXG4gICAgICBjb21wb25lbnRQcm9wczoge1xuICAgICAgICBiaXRPbkNvbG9yOiB0aGlzLmJpdE9uQ29sb3IsXG4gICAgICAgIGJpdE9mZkNvbG9yOiB0aGlzLmJpdE9mZkNvbG9yLFxuICAgICAgICByb3dzOiB0aGlzLmJpdHNBcnJheUVkaXRhYmxlLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbW9kYWwgPSBhd2FpdCBhd2FpdCB0aGlzLl9pbmZvTW9kYWw7XG4gICAgICBtb2RhbC5wcmVzZW50KCk7XG4gICAgICBhd2FpdCBtb2RhbC5vbkRpZERpc21pc3MoKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5faW5mb01vZGFsID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemVCaXRzVGVtcGxhdGVQYXJhbWV0ZXIoXG4gIHRlbXBsYXRlOiBCaXRUZW1wbGF0ZVtdW10gfCB1bmRlZmluZWRcbik6IEJpdFRlbXBsYXRlW11bXSB8IHVuZGVmaW5lZCB7XG4gIGlmIChcbiAgICBBcnJheS5pc0FycmF5KHRlbXBsYXRlKSAmJlxuICAgIHRlbXBsYXRlLmxlbmd0aCA+IDAgJiZcbiAgICAhQXJyYXkuaXNBcnJheSh0ZW1wbGF0ZVswXSlcbiAgKSB7XG4gICAgdGVtcGxhdGUgPSBbdGVtcGxhdGUgYXMgdW5rbm93biBhcyBCaXRUZW1wbGF0ZVtdXTtcbiAgfVxuICBpZiAodGVtcGxhdGUgJiYgIUFycmF5LmlzQXJyYXkodGVtcGxhdGUpKSB7XG4gICAgdGVtcGxhdGUgPSBbXTtcbiAgfVxuICBpZiAodGVtcGxhdGUpIHtcbiAgICB0ZW1wbGF0ZSA9IHRlbXBsYXRlLmZpbHRlcigocm93KSA9PiB7XG4gICAgICByZXR1cm4gISFyb3cgJiYgQXJyYXkuaXNBcnJheShyb3cpO1xuICAgIH0pO1xuICAgIHRlbXBsYXRlLmZvckVhY2goKHJvdywgaW5kZXgpID0+IHtcbiAgICAgIHRlbXBsYXRlISFbaW5kZXhdID0gcm93LmZpbHRlcigoaXRlbSkgPT4ge1xuICAgICAgICByZXR1cm4gISFpdGVtICYmIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JztcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIHJldHVybiB0ZW1wbGF0ZTtcbn1cbiIsIjx0YXAtdmFsdWUtZWRpdG9yLWNvbnRhaW5lclxuICAjY3R4XG4gIFt2YXJpYWJsZV09XCJfdmFyaWFibGVDaGFuZ2UudmFsdWVcIlxuICBbc2hvd0VkaXRCdXR0b25dPVwiZmFsc2VcIlxuICBbc2hvd1N1Ym1pdEJ1dHRvbl09XCJmYWxzZVwiXG4gIFtsaW5lc109XCInbm9uZSdcIlxuICAqbmdJZj1cImJpdHNBcnJheUVkaXRhYmxlLmxlbmd0aCA+IDA7IGVsc2Ugbm9CaXRzVGVtcGxhdGVcIlxuPlxuICA8aW9uLWdyaWQgaWQ9XCJpb25HcmlkXCI+XG4gICAgPGlvbi1yb3cgKm5nRm9yPVwibGV0IHJvdyBvZiBiaXRzQXJyYXlFZGl0YWJsZVwiIGNsYXNzPVwicm93LWJpdHNcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJiaXQtZGl2XCIgKm5nRm9yPVwibGV0IGJpdCBvZiByb3dcIj5cbiAgICAgICAgPGlvbi1mYWItYnV0dG9uXG4gICAgICAgICAgKGNsaWNrKT1cIm9uQ2xpY2tFZGl0KGJpdClcIlxuICAgICAgICAgIGNsYXNzPVwiZmFiLXJvd1wiXG4gICAgICAgICAgc2l6ZT1cInNtYWxsXCJcbiAgICAgICAgICBbY29sb3JdPVwiXG4gICAgICAgICAgICAoYml0LnZhbHVlICYmICFiaXQucmV2ZXJzZSkgfHwgKCFiaXQudmFsdWUgJiYgYml0LnJldmVyc2UpXG4gICAgICAgICAgICAgID8gYml0T25Db2xvclxuICAgICAgICAgICAgICA6IGJpdE9mZkNvbG9yXG4gICAgICAgICAgXCJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiIWVkaXRNb2RlXCJcbiAgICAgICAgPlxuICAgICAgICA8L2lvbi1mYWItYnV0dG9uPlxuICAgICAgICA8aW9uLWxhYmVsIGNsYXNzPVwibGFiZWwtdW5kZXJcIj5cbiAgICAgICAgICB7eyBiaXQubGFiZWwgfX1cbiAgICAgICAgPC9pb24tbGFiZWw+XG4gICAgICA8L2Rpdj5cbiAgICA8L2lvbi1yb3c+XG4gICAgPGlvbi1pdGVtIGxpbmVzPVwibm9uZVwiICpuZ0lmPVwiZWRpdGFibGUgfHwgc2hvd0hlbHBCdXR0b25cIj5cbiAgICAgIDxpb24tYnV0dG9ucyBpZD1cImJ1dHRvbnNCb3R0b21cIj5cbiAgICAgICAgPGlvbi1idXR0b25cbiAgICAgICAgICBmaWxsPVwiY2xlYXJcIlxuICAgICAgICAgIChjbGljayk9XCJzaG93SW5mbygpXCJcbiAgICAgICAgICBbY29sb3JdPVwiZWRpdEJ1dHRvbnNDb2xvclwiXG4gICAgICAgICAgKm5nSWY9XCJzaG93SGVscEJ1dHRvblwiXG4gICAgICAgID5cbiAgICAgICAgICA8aW9uLWljb25cbiAgICAgICAgICAgIGNsYXNzPVwiYnV0dG9uLWVkaXQtaWNvblwiXG4gICAgICAgICAgICBuYW1lPVwiaW5mb3JtYXRpb24tY2lyY2xlXCJcbiAgICAgICAgICA+PC9pb24taWNvbj5cbiAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZWRpdGFibGVcIj5cbiAgICAgICAgICA8aW9uLWJ1dHRvblxuICAgICAgICAgICAgW2NvbG9yXT1cImVkaXRCdXR0b25zQ29sb3JcIlxuICAgICAgICAgICAgZmlsbD1cImNsZWFyXCJcbiAgICAgICAgICAgIFtkaXNhYmxlZF09XCJvblNhdmluZ1wiXG4gICAgICAgICAgICAoY2xpY2spPVwib25FZGl0TW9kZSgpXCJcbiAgICAgICAgICAgICpuZ0lmPVwiIWVkaXRNb2RlXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8aW9uLWljb24gY2xhc3M9XCJidXR0b24tZWRpdC1pY29uXCIgbmFtZT1cInBlbmNpbFwiPjwvaW9uLWljb24+XG4gICAgICAgICAgPC9pb24tYnV0dG9uPlxuICAgICAgICAgIDxpb24tYnV0dG9uXG4gICAgICAgICAgICBmaWxsPVwiY2xlYXJcIlxuICAgICAgICAgICAgKGNsaWNrKT1cImNhbmNlbEVkaXQoKVwiXG4gICAgICAgICAgICAqbmdJZj1cImVkaXRNb2RlXCJcbiAgICAgICAgICAgIFtjb2xvcl09XCJlZGl0QnV0dG9uc0NvbG9yXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8aW9uLWljb24gY2xhc3M9XCJidXR0b24tZWRpdC1pY29uXCIgbmFtZT1cImNsb3NlXCI+PC9pb24taWNvbj5cbiAgICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgICAgPGlvbi1idXR0b25cbiAgICAgICAgICAgIGZpbGw9XCJjbGVhclwiXG4gICAgICAgICAgICBbY29sb3JdPVwiZWRpdEJ1dHRvbnNDb2xvclwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWVkaXRNb2RlXCJcbiAgICAgICAgICAgIChjbGljayk9XCJvblNhdmVFZGl0KF92YXJpYWJsZUNoYW5nZS52YWx1ZSlcIlxuICAgICAgICAgICAgKm5nSWY9XCIhb25TYXZpbmc7IGVsc2Ugc2F2ZUxvYWRlclwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPGlvbi1pY29uIGNsYXNzPVwiYnV0dG9uLWVkaXQtaWNvblwiIG5hbWU9XCJzYXZlXCI+PC9pb24taWNvbj5cbiAgICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgICAgPG5nLXRlbXBsYXRlICNzYXZlTG9hZGVyPlxuICAgICAgICAgICAgPGlvbi1zcGlubmVyXG4gICAgICAgICAgICAgIFtjb2xvcl09XCJlZGl0QnV0dG9uc0NvbG9yXCJcbiAgICAgICAgICAgICAgbmFtZT1cImNyZXNjZW50XCJcbiAgICAgICAgICAgID48L2lvbi1zcGlubmVyPiA8L25nLXRlbXBsYXRlXG4gICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvaW9uLWJ1dHRvbnM+XG4gICAgPC9pb24taXRlbT5cbiAgPC9pb24tZ3JpZD5cbjwvdGFwLXZhbHVlLWVkaXRvci1jb250YWluZXI+XG48bmctdGVtcGxhdGUgI25vQml0c1RlbXBsYXRlPlxuICA8aW9uLXByb2dyZXNzLWJhciB0eXBlPVwiaW5kZXRlcm1pbmF0ZVwiPjwvaW9uLXByb2dyZXNzLWJhcj5cbjwvbmctdGVtcGxhdGU+XG4iXX0=