@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
239 lines • 43.2 kB
JavaScript
import { Component, forwardRef, Input } from '@angular/core';
import { FormBuilder, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { DateFormatService, gettext, OptionsService } from '@c8y/ngx-components';
import { isEmpty } from 'lodash-es';
import { throttleTime } from 'rxjs/operators';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "@c8y/ngx-components";
import * as i3 from "ngx-bootstrap/datepicker";
import * as i4 from "ngx-bootstrap/timepicker";
export class OperationSchedulerComponent {
set _minutesAhead(minutes) {
if (minutes && minutes > this.MINUTES_AHEAD_DEFAULT) {
this.minutesAhead = minutes;
}
}
constructor(formBuilder, options, dateFormatService) {
this.formBuilder = formBuilder;
this.options = options;
this.dateFormatService = dateFormatService;
this.placeholder = gettext('Start date');
this.delayErrors = null;
this.pickerErrors = null;
this.DELAY_SECONDS_DEFAULT = 1;
this.MIN_DELAY_SECONDS_DEFAULT = 0.001;
this.MAX_DELAY_SECONDS_DEFAULT = 3600;
this.MINUTES_AHEAD_DEFAULT = 5;
this.isDelayInSeconds = true;
this.minutesAhead = this.MINUTES_AHEAD_DEFAULT;
this.DELAY_KEY_CATEGORY = 'device-control';
this.MAX_DELAY_KEY_NAME = 'bulkoperation.maxcreationramp';
this.MIN_DELAY_KEY_NAME = 'bulkoperation.creationramp';
this.currentUnit = 'seconds';
}
ngOnInit() {
this.minDate = new Date();
this.initialDate = new Date(this.minDate.setMinutes(this.minDate.getMinutes() + this.minutesAhead));
this.fgOperationScheduler = this.formBuilder.group({
picker: ['', [Validators.required, this.dateValidation]],
time: ['', [Validators.required, this.timeValidation]],
delay: ['', [Validators.required]],
unit: ['seconds']
});
this.fgOperationScheduler.patchValue({
picker: this.initialDate,
time: this.initialDate,
delay: this.DELAY_SECONDS_DEFAULT
});
// Due to the validation of picker and time it could be possible that value changes
// are emitted more than once. Therefore we throttle the emits.
const valueChanges$ = this.fgOperationScheduler.valueChanges.pipe(throttleTime(100));
this.subscription = valueChanges$.subscribe(data => {
this.delayErrors = this.fgOperationScheduler.controls.delay.errors;
this.pickerErrors = this.fgOperationScheduler.controls.picker.errors;
this.convertDelayHandler(data.unit);
this.emitData(data);
});
this.updateDelayValidation();
this.dateInputFormat = this.dateFormatService.getDateFormat();
}
ngOnDestroy() {
if (this.subscription && !this.subscription.closed) {
this.subscription.unsubscribe();
}
}
writeValue(value) {
if (value) {
this.fgOperationScheduler.patchValue({
picker: value.scheduledDate,
time: value.scheduledDate,
delay: value.delayInSeconds > 1 ? value.delayInSeconds : value.delayInSeconds * 1000,
unit: value.delayInSeconds > 1 ? 'seconds' : 'milliseconds'
});
}
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
if (this.fgOperationScheduler?.disabled === isDisabled) {
return;
}
isDisabled ? this.fgOperationScheduler.disable() : this.fgOperationScheduler.enable();
}
validate() {
if (this.fgOperationScheduler.invalid) {
return {
...this.fgOperationScheduler.controls.picker.errors,
...this.fgOperationScheduler.controls.time.errors,
...this.fgOperationScheduler.controls.delay.errors
};
}
}
registerOnValidatorChange(fn) {
this.onValidatorChanged = fn;
}
markAsTouched() {
if (this.onTouched) {
this.onTouched();
}
}
convertDelayHandler(unit) {
if (this.currentUnit === unit) {
return;
}
this.currentUnit = unit;
this.convertDelay(this.currentUnit);
// update validator on delay control to make sure that
// switching from minutes to seconds or vice versa does not harm validation.
this.fgOperationScheduler.controls.delay.setValidators([
Validators.required,
Validators.min(this.minDelay),
Validators.max(this.maxDelay)
]);
this.fgOperationScheduler.controls.delay.updateValueAndValidity();
}
emitData(data) {
if (this.onValidatorChanged) {
this.onValidatorChanged();
}
if (data.picker && data.time) {
data.picker = this.combineDateAndTime(data.picker, data.time);
}
this.convertDelay(this.currentUnit);
data.delayInSeconds = this.delayInSeconds;
if (this.onChange) {
this.onChange({
delayInSeconds: data.delayInSeconds,
scheduledDate: data.picker
});
}
}
async updateDelayValidation() {
const minSystem = await this.options.getSystemOption(this.DELAY_KEY_CATEGORY, this.MIN_DELAY_KEY_NAME);
const maxSystem = await this.options.getSystemOption(this.DELAY_KEY_CATEGORY, this.MAX_DELAY_KEY_NAME);
this.maxDelay = maxSystem ? Number(maxSystem) : this.MAX_DELAY_SECONDS_DEFAULT;
this.minDelay = minSystem ? Number(minSystem) : this.MIN_DELAY_SECONDS_DEFAULT;
this.fgOperationScheduler
.get('delay')
.setValidators([
Validators.required,
Validators.min(this.minDelay),
Validators.max(this.maxDelay)
]);
this.fgOperationScheduler.updateValueAndValidity();
}
convertDelay(unit) {
this.delayInSeconds = this.fgOperationScheduler.controls.delay.value;
if (unit === 'seconds' && !this.isDelayInSeconds) {
this.maxDelay = this.maxDelay / 1000;
this.minDelay = this.minDelay / 1000;
this.isDelayInSeconds = true;
}
if (unit === 'milliseconds') {
this.delayInSeconds = this.fgOperationScheduler.controls.delay.value / 1000;
if (this.isDelayInSeconds) {
this.maxDelay = this.maxDelay * 1000;
this.minDelay = this.minDelay * 1000;
this.isDelayInSeconds = false;
}
}
}
combineDateAndTime(date, time) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes());
}
dateValidation(fControl) {
if (fControl.value) {
const date = fControl.value;
fControl.parent.get('time').setValue(date);
return date >= new Date()
? null
: {
dateValidation: true
};
}
return { dateValidation: true };
}
timeValidation(fControl) {
if (fControl.value) {
const date = fControl.value;
const result = date >= new Date()
? null
: {
dateValidation: true
};
const picker = fControl.parent.get('picker');
if (result) {
picker.setErrors(result);
picker.markAsTouched();
return result;
}
if (picker && picker.errors && picker.errors.dateValidation) {
delete picker.errors.dateValidation;
if (isEmpty(picker.errors)) {
picker.setErrors(null);
return result;
}
picker.setErrors(picker.errors);
}
return result;
}
return { dateValidation: true };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OperationSchedulerComponent, deps: [{ token: i1.FormBuilder }, { token: i2.OptionsService }, { token: i2.DateFormatService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: OperationSchedulerComponent, selector: "c8y-operation-scheduler", inputs: { _minutesAhead: ["minutesAhead", "_minutesAhead"] }, providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
},
{
provide: NG_VALIDATORS,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
}
], ngImport: i0, template: "<div [formGroup]=\"fgOperationScheduler\">\n <div class=\"form-group\">\n <label translate>Start date</label>\n <div class=\"datetime-picker\">\n <c8y-form-group class=\"datepicker\">\n <input\n class=\"form-control\"\n placeholder=\"{{ placeholder | translate }}\"\n required\n formControlName=\"picker\"\n [bsConfig]=\"{ customTodayClass: 'today', dateInputFormat: dateInputFormat }\"\n [minDate]=\"minDate\"\n bsDatepicker\n (blur)=\"markAsTouched()\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'dateValidation'\"\n [text]=\"'Select time in the future.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n <timepicker\n class=\"form-group\"\n [showSpinners]=\"false\"\n [showMeridian]=\"false\"\n formControlName=\"time\"\n (blur)=\"markAsTouched()\"\n ></timepicker>\n </div>\n </div>\n <div class=\"form-group\">\n <c8y-form-group [hasError]=\"delayErrors\">\n <label translate>Delay</label>\n <div class=\"input-group\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} 15\"\n type=\"number\"\n required\n formControlName=\"delay\"\n (blur)=\"markAsTouched()\"\n />\n <div class=\"input-group-btn\">\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control m-r-sm-32 m-r-xs-56\"\n [attr.aria-label]=\"'Delay units' | translate\"\n formControlName=\"unit\"\n (blur)=\"markAsTouched()\"\n >\n <option\n value=\"seconds\"\n translate\n >\n Seconds\n </option>\n <option\n value=\"milliseconds\"\n translate\n >\n Milliseconds\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n </c8y-form-group>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i2.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.BsDatepickerDirective, selector: "[bsDatepicker]", inputs: ["placement", "triggers", "outsideClick", "container", "outsideEsc", "isDisabled", "minDate", "maxDate", "minMode", "daysDisabled", "datesDisabled", "datesEnabled", "dateCustomClasses", "dateTooltipTexts", "isOpen", "bsValue", "bsConfig"], outputs: ["onShown", "onHidden", "bsValueChange"], exportAs: ["bsDatepicker"] }, { kind: "directive", type: i3.BsDatepickerInputDirective, selector: "input[bsDatepicker]" }, { kind: "component", type: i4.TimepickerComponent, selector: "timepicker", inputs: ["hourStep", "minuteStep", "secondsStep", "readonlyInput", "disabled", "mousewheel", "arrowkeys", "showSpinners", "showMeridian", "showMinutes", "showSeconds", "meridians", "min", "max", "hoursPlaceholder", "minutesPlaceholder", "secondsPlaceholder"], outputs: ["isValid", "meridianChange"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OperationSchedulerComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-operation-scheduler', providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
},
{
provide: NG_VALIDATORS,
multi: true,
useExisting: forwardRef(() => OperationSchedulerComponent)
}
], template: "<div [formGroup]=\"fgOperationScheduler\">\n <div class=\"form-group\">\n <label translate>Start date</label>\n <div class=\"datetime-picker\">\n <c8y-form-group class=\"datepicker\">\n <input\n class=\"form-control\"\n placeholder=\"{{ placeholder | translate }}\"\n required\n formControlName=\"picker\"\n [bsConfig]=\"{ customTodayClass: 'today', dateInputFormat: dateInputFormat }\"\n [minDate]=\"minDate\"\n bsDatepicker\n (blur)=\"markAsTouched()\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'dateValidation'\"\n [text]=\"'Select time in the future.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n <timepicker\n class=\"form-group\"\n [showSpinners]=\"false\"\n [showMeridian]=\"false\"\n formControlName=\"time\"\n (blur)=\"markAsTouched()\"\n ></timepicker>\n </div>\n </div>\n <div class=\"form-group\">\n <c8y-form-group [hasError]=\"delayErrors\">\n <label translate>Delay</label>\n <div class=\"input-group\">\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} 15\"\n type=\"number\"\n required\n formControlName=\"delay\"\n (blur)=\"markAsTouched()\"\n />\n <div class=\"input-group-btn\">\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control m-r-sm-32 m-r-xs-56\"\n [attr.aria-label]=\"'Delay units' | translate\"\n formControlName=\"unit\"\n (blur)=\"markAsTouched()\"\n >\n <option\n value=\"seconds\"\n translate\n >\n Seconds\n </option>\n <option\n value=\"milliseconds\"\n translate\n >\n Milliseconds\n </option>\n </select>\n <span></span>\n </div>\n </div>\n </div>\n </c8y-form-group>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.OptionsService }, { type: i2.DateFormatService }], propDecorators: { _minutesAhead: [{
type: Input,
args: ['minutesAhead']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlcmF0aW9uLXNjaGVkdWxlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9vcGVyYXRpb25zL2J1bGstb3BlcmF0aW9uLXNjaGVkdWxlci9vcGVyYXRpb24tc2NoZWR1bGVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL29wZXJhdGlvbnMvYnVsay1vcGVyYXRpb24tc2NoZWR1bGVyL29wZXJhdGlvbi1zY2hlZHVsZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUNoRixPQUFPLEVBRUwsV0FBVyxFQUdYLGFBQWEsRUFDYixpQkFBaUIsRUFHakIsVUFBVSxFQUNYLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUNqRixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRXBDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7O0FBbUI5QyxNQUFNLE9BQU8sMkJBQTJCO0lBR3RDLElBQTJCLGFBQWEsQ0FBQyxPQUFlO1FBQ3RELElBQUksT0FBTyxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUNwRCxJQUFJLENBQUMsWUFBWSxHQUFHLE9BQU8sQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztJQTZCRCxZQUNVLFdBQXdCLEVBQ3hCLE9BQXVCLEVBQ3ZCLGlCQUFvQztRQUZwQyxnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQUN4QixZQUFPLEdBQVAsT0FBTyxDQUFnQjtRQUN2QixzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBOUI5QyxnQkFBVyxHQUFXLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FB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LCBmb3J3YXJkUmVmLCBJbnB1dCwgT25EZXN0cm95LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIENvbnRyb2xWYWx1ZUFjY2Vzc29yLFxuICBGb3JtQnVpbGRlcixcbiAgRm9ybUNvbnRyb2wsXG4gIEZvcm1Hcm91cCxcbiAgTkdfVkFMSURBVE9SUyxcbiAgTkdfVkFMVUVfQUNDRVNTT1IsXG4gIFZhbGlkYXRpb25FcnJvcnMsXG4gIFZhbGlkYXRvcixcbiAgVmFsaWRhdG9yc1xufSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBEYXRlRm9ybWF0U2VydmljZSwgZ2V0dGV4dCwgT3B0aW9uc1NlcnZpY2UgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IGlzRW1wdHkgfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyB0aHJvdHRsZVRpbWUgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBPcGVyYXRpb25TY2hlZHVsZSB9IGZyb20gJy4vb3BlcmF0aW9uLXNjaGVkdWxlLmludGVyZmFjZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1vcGVyYXRpb24tc2NoZWR1bGVyJyxcbiAgdGVtcGxhdGVVcmw6ICdvcGVyYXRpb24tc2NoZWR1bGVyLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICBtdWx0aTogdHJ1ZSxcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IE9wZXJhdGlvblNjaGVkdWxlckNvbXBvbmVudClcbiAgICB9LFxuICAgIHtcbiAgICAgIHByb3ZpZGU6IE5HX1ZBTElEQVRPUlMsXG4gICAgICBtdWx0aTogdHJ1ZSxcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IE9wZXJhdGlvblNjaGVkdWxlckNvbXBvbmVudClcbiAgICB9XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgT3BlcmF0aW9uU2NoZWR1bGVyQ29tcG9uZW50XG4gIGltcGxlbWVudHMgQ29udHJvbFZhbHVlQWNjZXNzb3IsIFZhbGlkYXRvciwgT25Jbml0LCBPbkRlc3Ryb3lcbntcbiAgQElucHV0KCdtaW51dGVzQWhlYWQnKSBzZXQgX21pbnV0ZXNBaGVhZChtaW51dGVzOiBudW1iZXIpIHtcbiAgICBpZiAobWludXRlcyAmJiBtaW51dGVzID4gdGhpcy5NSU5VVEVTX0FIRUFEX0RFRkFVTFQpIHtcbiAgICAgIHRoaXMubWludXRlc0FoZWFkID0gbWludXRlcztcbiAgICB9XG4gIH1cblxuICBwbGFjZWhvbGRlcjogc3RyaW5nID0gZ2V0dGV4dCgnU3RhcnQgZGF0ZScpO1xuICBmZ09wZXJhdGlvblNjaGVkdWxlcjogRm9ybUdyb3VwO1xuICBtaW5EYXRlOiBEYXRlO1xuICBtaW5EZWxheTogbnVtYmVyO1xuICBtYXhEZWxheTogbnVtYmVyO1xuICBkZWxheUVycm9yczogVmFsaWRhdGlvbkVycm9ycyA9IG51bGw7XG4gIHBpY2tlckVycm9yczogVmFsaWRhdGlvbkVycm9ycyA9IG51bGw7XG4gIGRhdGVJbnB1dEZvcm1hdDogc3RyaW5nO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgREVMQVlfU0VDT05EU19ERUZBVUxUOiBudW1iZXIgPSAxO1xuICBwcml2YXRlIHJlYWRvbmx5IE1JTl9ERUxBWV9TRUNPTkRTX0RFRkFVTFQ6IG51bWJlciA9IDAuMDAxO1xuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9ERUxBWV9TRUNPTkRTX0RFRkFVTFQ6IG51bWJlciA9IDM2MDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgTUlOVVRFU19BSEVBRF9ERUZBVUxUOiBudW1iZXIgPSA1O1xuICBwcml2YXRlIGlzRGVsYXlJblNlY29uZHMgPSB0cnVlO1xuICBwcml2YXRlIG1pbnV0ZXNBaGVhZDogbnVtYmVyID0gdGhpcy5NSU5VVEVTX0FIRUFEX0RFRkFVTFQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVMQVlfS0VZX0NBVEVHT1JZID0gJ2RldmljZS1jb250cm9sJztcbiAgcHJpdmF0ZSByZWFkb25seSBNQVhfREVMQVlfS0VZX05BTUUgPSAnYnVsa29wZXJhdGlvbi5tYXhjcmVhdGlvbnJhbXAnO1xuICBwcml2YXRlIHJlYWRvbmx5IE1JTl9ERUxBWV9LRVlfTkFNRSA9ICdidWxrb3BlcmF0aW9uLmNyZWF0aW9ucmFtcCc7XG4gIHByaXZhdGUgY3VycmVudFVuaXQgPSAnc2Vjb25kcyc7XG4gIHByaXZhdGUgZGVsYXlJblNlY29uZHM6IG51bWJlcjtcbiAgcHJpdmF0ZSBpbml0aWFsRGF0ZTogRGF0ZTtcbiAgcHJpdmF0ZSBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcblxuICBwcml2YXRlIG9uQ2hhbmdlOiAobmFtZSkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBvblRvdWNoZWQ6ICgpID0+IHZvaWQ7XG4gIHByaXZhdGUgb25WYWxpZGF0b3JDaGFuZ2VkOiAoKSA9PiB2b2lkO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgZm9ybUJ1aWxkZXI6IEZvcm1CdWlsZGVyLFxuICAgIHByaXZhdGUgb3B0aW9uczogT3B0aW9uc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBkYXRlRm9ybWF0U2VydmljZTogRGF0ZUZvcm1hdFNlcnZpY2VcbiAgKSB7fVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMubWluRGF0ZSA9IG5ldyBEYXRlKCk7XG4gICAgdGhpcy5pbml0aWFsRGF0ZSA9IG5ldyBEYXRlKFxuICAgICAgdGhpcy5taW5EYXRlLnNldE1pbnV0ZXModGhpcy5taW5EYXRlLmdldE1pbnV0ZXMoKSArIHRoaXMubWludXRlc0FoZWFkKVxuICAgICk7XG5cbiAgICB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyID0gdGhpcy5mb3JtQnVpbGRlci5ncm91cCh7XG4gICAgICBwaWNrZXI6IFsnJywgW1ZhbGlkYXRvcnMucmVxdWlyZWQsIHRoaXMuZGF0ZVZhbGlkYXRpb25dXSxcbiAgICAgIHRpbWU6IFsnJywgW1ZhbGlkYXRvcnMucmVxdWlyZWQsIHRoaXMudGltZVZhbGlkYXRpb25dXSxcbiAgICAgIGRlbGF5OiBbJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXV0sXG4gICAgICB1bml0OiBbJ3NlY29uZHMnXVxuICAgIH0pO1xuXG4gICAgdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5wYXRjaFZhbHVlKHtcbiAgICAgIHBpY2tlcjogdGhpcy5pbml0aWFsRGF0ZSxcbiAgICAgIHRpbWU6IHRoaXMuaW5pdGlhbERhdGUsXG4gICAgICBkZWxheTogdGhpcy5ERUxBWV9TRUNPTkRTX0RFRkFVTFRcbiAgICB9KTtcblxuICAgIC8vIER1ZSB0byB0aGUgdmFsaWRhdGlvbiBvZiBwaWNrZXIgYW5kIHRpbWUgaXQgY291bGQgYmUgcG9zc2libGUgdGhhdCB2YWx1ZSBjaGFuZ2VzXG4gICAgLy8gYXJlIGVtaXR0ZWQgbW9yZSB0aGFuIG9uY2UuIFRoZXJlZm9yZSB3ZSB0aHJvdHRsZSB0aGUgZW1pdHMuXG4gICAgY29uc3QgdmFsdWVDaGFuZ2VzJCA9IHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIudmFsdWVDaGFuZ2VzLnBpcGUodGhyb3R0bGVUaW1lKDEwMCkpO1xuICAgIHRoaXMuc3Vic2NyaXB0aW9uID0gdmFsdWVDaGFuZ2VzJC5zdWJzY3JpYmUoZGF0YSA9PiB7XG4gICAgICB0aGlzLmRlbGF5RXJyb3JzID0gdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5jb250cm9scy5kZWxheS5lcnJvcnM7XG4gICAgICB0aGlzLnBpY2tlckVycm9ycyA9IHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuY29udHJvbHMucGlja2VyLmVycm9ycztcbiAgICAgIHRoaXMuY29udmVydERlbGF5SGFuZGxlcihkYXRhLnVuaXQpO1xuICAgICAgdGhpcy5lbWl0RGF0YShkYXRhKTtcbiAgICB9KTtcblxuICAgIHRoaXMudXBkYXRlRGVsYXlWYWxpZGF0aW9uKCk7XG4gICAgdGhpcy5kYXRlSW5wdXRGb3JtYXQgPSB0aGlzLmRhdGVGb3JtYXRTZXJ2aWNlLmdldERhdGVGb3JtYXQoKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIGlmICh0aGlzLnN1YnNjcmlwdGlvbiAmJiAhdGhpcy5zdWJzY3JpcHRpb24uY2xvc2VkKSB7XG4gICAgICB0aGlzLnN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIH1cbiAgfVxuXG4gIHdyaXRlVmFsdWUodmFsdWU6IE9wZXJhdGlvblNjaGVkdWxlKTogdm9pZCB7XG4gICAgaWYgKHZhbHVlKSB7XG4gICAgICB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLnBhdGNoVmFsdWUoe1xuICAgICAgICBwaWNrZXI6IHZhbHVlLnNjaGVkdWxlZERhdGUsXG4gICAgICAgIHRpbWU6IHZhbHVlLnNjaGVkdWxlZERhdGUsXG4gICAgICAgIGRlbGF5OiB2YWx1ZS5kZWxheUluU2Vjb25kcyA+IDEgPyB2YWx1ZS5kZWxheUluU2Vjb25kcyA6IHZhbHVlLmRlbGF5SW5TZWNvbmRzICogMTAwMCxcbiAgICAgICAgdW5pdDogdmFsdWUuZGVsYXlJblNlY29uZHMgPiAxID8gJ3NlY29uZHMnIDogJ21pbGxpc2Vjb25kcydcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46IGFueSk6IHZvaWQge1xuICAgIHRoaXMub25DaGFuZ2UgPSBmbjtcbiAgfVxuXG4gIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLm9uVG91Y2hlZCA9IGZuO1xuICB9XG5cbiAgc2V0RGlzYWJsZWRTdGF0ZT8oaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICh0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyPy5kaXNhYmxlZCA9PT0gaXNEaXNhYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpc0Rpc2FibGVkID8gdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5kaXNhYmxlKCkgOiB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmVuYWJsZSgpO1xuICB9XG5cbiAgdmFsaWRhdGUoKTogVmFsaWRhdGlvbkVycm9ycyB7XG4gICAgaWYgKHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuaW52YWxpZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4udGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5jb250cm9scy5waWNrZXIuZXJyb3JzLFxuICAgICAgICAuLi50aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmNvbnRyb2xzLnRpbWUuZXJyb3JzLFxuICAgICAgICAuLi50aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmNvbnRyb2xzLmRlbGF5LmVycm9yc1xuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICByZWdpc3Rlck9uVmFsaWRhdG9yQ2hhbmdlKGZuOiBhbnkpIHtcbiAgICB0aGlzLm9uVmFsaWRhdG9yQ2hhbmdlZCA9IGZuO1xuICB9XG5cbiAgbWFya0FzVG91Y2hlZCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5vblRvdWNoZWQpIHtcbiAgICAgIHRoaXMub25Ub3VjaGVkKCk7XG4gICAgfVxuICB9XG5cbiAgY29udmVydERlbGF5SGFuZGxlcih1bml0OiBzdHJpbmcpIHtcbiAgICBpZiAodGhpcy5jdXJyZW50VW5pdCA9PT0gdW5pdCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuY3VycmVudFVuaXQgPSB1bml0O1xuXG4gICAgdGhpcy5jb252ZXJ0RGVsYXkodGhpcy5jdXJyZW50VW5pdCk7XG5cbiAgICAvLyB1cGRhdGUgdmFsaWRhdG9yIG9uIGRlbGF5IGNvbnRyb2wgdG8gbWFrZSBzdXJlIHRoYXRcbiAgICAvLyBzd2l0Y2hpbmcgZnJvbSBtaW51dGVzIHRvIHNlY29uZHMgb3IgdmljZSB2ZXJzYSBkb2VzIG5vdCBoYXJtIHZhbGlkYXRpb24uXG4gICAgdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5jb250cm9scy5kZWxheS5zZXRWYWxpZGF0b3JzKFtcbiAgICAgIFZhbGlkYXRvcnMucmVxdWlyZWQsXG4gICAgICBWYWxpZGF0b3JzLm1pbih0aGlzLm1pbkRlbGF5KSxcbiAgICAgIFZhbGlkYXRvcnMubWF4KHRoaXMubWF4RGVsYXkpXG4gICAgXSk7XG4gICAgdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5jb250cm9scy5kZWxheS51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7XG4gIH1cblxuICBlbWl0RGF0YShkYXRhOiB7IGRlbGF5SW5TZWNvbmRzOiBudW1iZXI7IHBpY2tlcjogRGF0ZTsgdGltZT86IERhdGU7IGRlbGF5PzogbnVtYmVyIH0pIHtcbiAgICBpZiAodGhpcy5vblZhbGlkYXRvckNoYW5nZWQpIHtcbiAgICAgIHRoaXMub25WYWxpZGF0b3JDaGFuZ2VkKCk7XG4gICAgfVxuXG4gICAgaWYgKGRhdGEucGlja2VyICYmIGRhdGEudGltZSkge1xuICAgICAgZGF0YS5waWNrZXIgPSB0aGlzLmNvbWJpbmVEYXRlQW5kVGltZShkYXRhLnBpY2tlciwgZGF0YS50aW1lKTtcbiAgICB9XG5cbiAgICB0aGlzLmNvbnZlcnREZWxheSh0aGlzLmN1cnJlbnRVbml0KTtcbiAgICBkYXRhLmRlbGF5SW5TZWNvbmRzID0gdGhpcy5kZWxheUluU2Vjb25kcztcblxuICAgIGlmICh0aGlzLm9uQ2hhbmdlKSB7XG4gICAgICB0aGlzLm9uQ2hhbmdlKHtcbiAgICAgICAgZGVsYXlJblNlY29uZHM6IGRhdGEuZGVsYXlJblNlY29uZHMsXG4gICAgICAgIHNjaGVkdWxlZERhdGU6IGRhdGEucGlja2VyXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHVwZGF0ZURlbGF5VmFsaWRhdGlvbigpIHtcbiAgICBjb25zdCBtaW5TeXN0ZW0gPSBhd2FpdCB0aGlzLm9wdGlvbnMuZ2V0U3lzdGVtT3B0aW9uKFxuICAgICAgdGhpcy5ERUxBWV9LRVlfQ0FURUdPUlksXG4gICAgICB0aGlzLk1JTl9ERUxBWV9LRVlfTkFNRVxuICAgICk7XG4gICAgY29uc3QgbWF4U3lzdGVtID0gYXdhaXQgdGhpcy5vcHRpb25zLmdldFN5c3RlbU9wdGlvbihcbiAgICAgIHRoaXMuREVMQVlfS0VZX0NBVEVHT1JZLFxuICAgICAgdGhpcy5NQVhfREVMQVlfS0VZX05BTUVcbiAgICApO1xuXG4gICAgdGhpcy5tYXhEZWxheSA9IG1heFN5c3RlbSA/IE51bWJlcihtYXhTeXN0ZW0pIDogdGhpcy5NQVhfREVMQVlfU0VDT05EU19ERUZBVUxUO1xuICAgIHRoaXMubWluRGVsYXkgPSBtaW5TeXN0ZW0gPyBOdW1iZXIobWluU3lzdGVtKSA6IHRoaXMuTUlOX0RFTEFZX1NFQ09ORFNfREVGQVVMVDtcblxuICAgIHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXJcbiAgICAgIC5nZXQoJ2RlbGF5JylcbiAgICAgIC5zZXRWYWxpZGF0b3JzKFtcbiAgICAgICAgVmFsaWRhdG9ycy5yZXF1aXJlZCxcbiAgICAgICAgVmFsaWRhdG9ycy5taW4odGhpcy5taW5EZWxheSksXG4gICAgICAgIFZhbGlkYXRvcnMubWF4KHRoaXMubWF4RGVsYXkpXG4gICAgICBdKTtcbiAgICB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoKTtcbiAgfVxuXG4gIHByaXZhdGUgY29udmVydERlbGF5KHVuaXQ6IHN0cmluZykge1xuICAgIHRoaXMuZGVsYXlJblNlY29uZHMgPSB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmNvbnRyb2xzLmRlbGF5LnZhbHVlO1xuXG4gICAgaWYgKHVuaXQgPT09ICdzZWNvbmRzJyAmJiAhdGhpcy5pc0RlbGF5SW5TZWNvbmRzKSB7XG4gICAgICB0aGlzLm1heERlbGF5ID0gdGhpcy5tYXhEZWxheSAvIDEwMDA7XG4gICAgICB0aGlzLm1pbkRlbGF5ID0gdGhpcy5taW5EZWxheSAvIDEwMDA7XG4gICAgICB0aGlzLmlzRGVsYXlJblNlY29uZHMgPSB0cnVlO1xuICAgIH1cblxuICAgIGlmICh1bml0ID09PSAnbWlsbGlzZWNvbmRzJykge1xuICAgICAgdGhpcy5kZWxheUluU2Vjb25kcyA9IHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuY29udHJvbHMuZGVsYXkudmFsdWUgLyAxMDAwO1xuICAgICAgaWYgKHRoaXMuaXNEZWxheUluU2Vjb25kcykge1xuICAgICAgICB0aGlzLm1heERlbGF5ID0gdGhpcy5tYXhEZWxheSAqIDEwMDA7XG4gICAgICAgIHRoaXMubWluRGVsYXkgPSB0aGlzLm1pbkRlbGF5ICogMTAwMDtcbiAgICAgICAgdGhpcy5pc0RlbGF5SW5TZWNvbmRzID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjb21iaW5lRGF0ZUFuZFRpbWUoZGF0ZTogRGF0ZSwgdGltZTogRGF0ZSkge1xuICAgIHJldHVybiBuZXcgRGF0ZShcbiAgICAgIGRhdGUuZ2V0RnVsbFllYXIoKSxcbiAgICAgIGRhdGUuZ2V0TW9udGgoKSxcbiAgICAgIGRhdGUuZ2V0RGF0ZSgpLFxuICAgICAgdGltZS5nZXRIb3VycygpLFxuICAgICAgdGltZS5nZXRNaW51dGVzKClcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBkYXRlVmFsaWRhdGlvbihmQ29udHJvbDogRm9ybUNvbnRyb2wpIHtcbiAgICBpZiAoZkNvbnRyb2wudmFsdWUpIHtcbiAgICAgIGNvbnN0IGRhdGUgPSBmQ29udHJvbC52YWx1ZSBhcyBEYXRlO1xuICAgICAgZkNvbnRyb2wucGFyZW50LmdldCgndGltZScpLnNldFZhbHVlKGRhdGUpO1xuICAgICAgcmV0dXJuIGRhdGUgPj0gbmV3IERhdGUoKVxuICAgICAgICA/IG51bGxcbiAgICAgICAgOiB7XG4gICAgICAgICAgICBkYXRlVmFsaWRhdGlvbjogdHJ1ZVxuICAgICAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiB7IGRhdGVWYWxpZGF0aW9uOiB0cnVlIH07XG4gIH1cblxuICBwcml2YXRlIHRpbWVWYWxpZGF0aW9uKGZDb250cm9sOiBGb3JtQ29udHJvbCkge1xuICAgIGlmIChmQ29udHJvbC52YWx1ZSkge1xuICAgICAgY29uc3QgZGF0ZSA9IGZDb250cm9sLnZhbHVlIGFzIERhdGU7XG4gICAgICBjb25zdCByZXN1bHQgPVxuICAgICAgICBkYXRlID49IG5ldyBEYXRlKClcbiAgICAgICAgICA/IG51bGxcbiAgICAgICAgICA6IHtcbiAgICAgICAgICAgICAgZGF0ZVZhbGlkYXRpb246IHRydWVcbiAgICAgICAgICAgIH07XG5cbiAgICAgIGNvbnN0IHBpY2tlciA9IGZDb250cm9sLnBhcmVudC5nZXQoJ3BpY2tlcicpO1xuXG4gICAgICBpZiAocmVzdWx0KSB7XG4gICAgICAgIHBpY2tlci5zZXRFcnJvcnMocmVzdWx0KTtcbiAgICAgICAgcGlja2VyLm1hcmtBc1RvdWNoZWQoKTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgIH1cblxuICAgICAgaWYgKHBpY2tlciAmJiBwaWNrZXIuZXJyb3JzICYmIHBpY2tlci5lcnJvcnMuZGF0ZVZhbGlkYXRpb24pIHtcbiAgICAgICAgZGVsZXRlIHBpY2tlci5lcnJvcnMuZGF0ZVZhbGlkYXRpb247XG5cbiAgICAgICAgaWYgKGlzRW1wdHkocGlja2VyLmVycm9ycykpIHtcbiAgICAgICAgICBwaWNrZXIuc2V0RXJyb3JzKG51bGwpO1xuICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cblxuICAgICAgICBwaWNrZXIuc2V0RXJyb3JzKHBpY2tlci5lcnJvcnMpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgcmV0dXJuIHsgZGF0ZVZhbGlkYXRpb246IHRydWUgfTtcbiAgfVxufVxuIiwiPGRpdiBbZm9ybUdyb3VwXT1cImZnT3BlcmF0aW9uU2NoZWR1bGVyXCI+XG4gIDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwXCI+XG4gICAgPGxhYmVsIHRyYW5zbGF0ZT5TdGFydCBkYXRlPC9sYWJlbD5cbiAgICA8ZGl2IGNsYXNzPVwiZGF0ZXRpbWUtcGlja2VyXCI+XG4gICAgICA8Yzh5LWZvcm0tZ3JvdXAgY2xhc3M9XCJkYXRlcGlja2VyXCI+XG4gICAgICAgIDxpbnB1dFxuICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgICAgICBwbGFjZWhvbGRlcj1cInt7IHBsYWNlaG9sZGVyIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICByZXF1aXJlZFxuICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cInBpY2tlclwiXG4gICAgICAgICAgW2JzQ29uZmlnXT1cInsgY3VzdG9tVG9kYXlDbGFzczogJ3RvZGF5JywgZGF0ZUlucHV0Rm9ybWF0OiBkYXRlSW5wdXRGb3JtYXQgfVwiXG4gICAgICAgICAgW21pbkRhdGVdPVwibWluRGF0ZVwiXG4gICAgICAgICAgYnNEYXRlcGlja2VyXG4gICAgICAgICAgKGJsdXIpPVwibWFya0FzVG91Y2hlZCgpXCJcbiAgICAgICAgLz5cbiAgICAgICAgPGM4eS1tZXNzYWdlcz5cbiAgICAgICAgICA8Yzh5LW1lc3NhZ2VcbiAgICAgICAgICAgIFtuYW1lXT1cIidkYXRlVmFsaWRhdGlvbidcIlxuICAgICAgICAgICAgW3RleHRdPVwiJ1NlbGVjdCB0aW1lIGluIHRoZSBmdXR1cmUuJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgPjwvYzh5LW1lc3NhZ2U+XG4gICAgICAgIDwvYzh5LW1lc3NhZ2VzPlxuICAgICAgPC9jOHktZm9ybS1ncm91cD5cbiAgICAgIDx0aW1lcGlja2VyXG4gICAgICAgIGNsYXNzPVwiZm9ybS1ncm91cFwiXG4gICAgICAgIFtzaG93U3Bpbm5lcnNdPVwiZmFsc2VcIlxuICAgICAgICBbc2hvd01lcmlkaWFuXT1cImZhbHNlXCJcbiAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwidGltZVwiXG4gICAgICAgIChibHVyKT1cIm1hcmtBc1RvdWNoZWQoKVwiXG4gICAgICA+PC90aW1lcGlja2VyPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbiAgPGRpdiBjbGFzcz1cImZvcm0tZ3JvdXBcIj5cbiAgICA8Yzh5LWZvcm0tZ3JvdXAgW2hhc0Vycm9yXT1cImRlbGF5RXJyb3JzXCI+XG4gICAgICA8bGFiZWwgdHJhbnNsYXRlPkRlbGF5PC9sYWJlbD5cbiAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cFwiPlxuICAgICAgICA8aW5wdXRcbiAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnZS5nLicgfCB0cmFuc2xhdGUgfX0gMTVcIlxuICAgICAgICAgIHR5cGU9XCJudW1iZXJcIlxuICAgICAgICAgIHJlcXVpcmVkXG4gICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiZGVsYXlcIlxuICAgICAgICAgIChibHVyKT1cIm1hcmtBc1RvdWNoZWQoKVwiXG4gICAgICAgIC8+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cC1idG5cIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYzh5LXNlbGVjdC13cmFwcGVyXCI+XG4gICAgICAgICAgICA8c2VsZWN0XG4gICAgICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sIG0tci1zbS0zMiBtLXIteHMtNTZcIlxuICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidEZWxheSB1bml0cycgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJ1bml0XCJcbiAgICAgICAgICAgICAgKGJsdXIpPVwibWFya0FzVG91Y2hlZCgpXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPG9wdGlvblxuICAgICAgICAgICAgICAgIHZhbHVlPVwic2Vjb25kc1wiXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICBTZWNvbmRzXG4gICAgICAgICAgICAgIDwvb3B0aW9uPlxuICAgICAgICAgICAgICA8b3B0aW9uXG4gICAgICAgICAgICAgICAgdmFsdWU9XCJtaWxsaXNlY29uZHNcIlxuICAgICAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgTWlsbGlzZWNvbmRzXG4gICAgICAgICAgICAgIDwvb3B0aW9uPlxuICAgICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgICAgICA8c3Bhbj48L3NwYW4+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9jOHktZm9ybS1ncm91cD5cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==