@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
237 lines • 42.5 kB
JavaScript
import { Component, forwardRef, Input } from '@angular/core';
import { FormBuilder, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { 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) {
this.formBuilder = formBuilder;
this.options = options;
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();
}
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 }], 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' }\"\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' }\"\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 }], propDecorators: { _minutesAhead: [{
type: Input,
args: ['minutesAhead']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlcmF0aW9uLXNjaGVkdWxlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9vcGVyYXRpb25zL2J1bGstb3BlcmF0aW9uLXNjaGVkdWxlci9vcGVyYXRpb24tc2NoZWR1bGVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL29wZXJhdGlvbnMvYnVsay1vcGVyYXRpb24tc2NoZWR1bGVyL29wZXJhdGlvbi1zY2hlZHVsZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFxQixNQUFNLGVBQWUsQ0FBQztBQUNoRixPQUFPLEVBRUwsV0FBVyxFQUdYLGFBQWEsRUFDYixpQkFBaUIsRUFHakIsVUFBVSxFQUNYLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRXBDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7Ozs7O0FBbUI5QyxNQUFNLE9BQU8sMkJBQTJCO0lBR3RDLElBQTJCLGFBQWEsQ0FBQyxPQUFlO1FBQ3RELElBQUksT0FBTyxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUNwRCxJQUFJLENBQUMsWUFBWSxHQUFHLE9BQU8sQ0FBQztRQUM5QixDQUFDO0lBQ0gsQ0FBQztJQTRCRCxZQUNVLFdBQXdCLEVBQ3hCLE9BQXVCO1FBRHZCLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLFlBQU8sR0FBUCxPQUFPLENBQWdCO1FBNUJqQyxnQkFBVyxHQUFXLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUs1QyxnQkFBVyxHQUFxQixJQUFJLENBQUM7UUFDckMsaUJBQVksR0FBcUIsSUFBSSxDQUFD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QixPQUFPLE1BQU0sQ0FBQztnQkFDaEIsQ0FBQztnQkFFRCxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNsQyxDQUFDO1lBQ0QsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUNELE9BQU8sRUFBRSxjQUFjLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDbEMsQ0FBQzsrR0FuUVUsMkJBQTJCO21HQUEzQiwyQkFBMkIsZ0hBYjNCO1lBQ1Q7Z0JBQ0UsT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsS0FBSyxFQUFFLElBQUk7Z0JBQ1gsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQywyQkFBMkIsQ0FBQzthQUMzRDtZQUNEO2dCQUNFLE9BQU8sRUFBRSxhQUFhO2dCQUN0QixLQUFLLEVBQUUsSUFBSTtnQkFDWCxXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLDJCQUEyQixDQUFDO2FBQzNEO1NBQ0YsMEJDaENILCttRUF1RUE7OzRGRHJDYSwyQkFBMkI7a0JBaEJ2QyxTQUFTOytCQUNFLHlCQUF5QixhQUV4Qjt3QkFDVDs0QkFDRSxPQUFPLEVBQUUsaUJBQWlCOzRCQUMxQixLQUFLLEVBQUUsSUFBSTs0QkFDWCxXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSw0QkFBNEIsQ0FBQzt5QkFDM0Q7d0JBQ0Q7NEJBQ0UsT0FBTyxFQUFFLGFBQWE7NEJBQ3RCLEtBQUssRUFBRSxJQUFJOzRCQUNYLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLDRCQUE0QixDQUFDO3lCQUMzRDtxQkFDRjs2R0FLMEIsYUFBYTtzQkFBdkMsS0FBSzt1QkFBQyxjQUFjIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBmb3J3YXJkUmVmLCBJbnB1dCwgT25EZXN0cm95LCBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIENvbnRyb2xWYWx1ZUFjY2Vzc29yLFxuICBGb3JtQnVpbGRlcixcbiAgRm9ybUNvbnRyb2wsXG4gIEZvcm1Hcm91cCxcbiAgTkdfVkFMSURBVE9SUyxcbiAgTkdfVkFMVUVfQUNDRVNTT1IsXG4gIFZhbGlkYXRpb25FcnJvcnMsXG4gIFZhbGlkYXRvcixcbiAgVmFsaWRhdG9yc1xufSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBnZXR0ZXh0LCBPcHRpb25zU2VydmljZSB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgaXNFbXB0eSB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRocm90dGxlVGltZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IE9wZXJhdGlvblNjaGVkdWxlIH0gZnJvbSAnLi9vcGVyYXRpb24tc2NoZWR1bGUuaW50ZXJmYWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LW9wZXJhdGlvbi1zY2hlZHVsZXInLFxuICB0ZW1wbGF0ZVVybDogJ29wZXJhdGlvbi1zY2hlZHVsZXIuY29tcG9uZW50Lmh0bWwnLFxuICBwcm92aWRlcnM6IFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICAgIG11bHRpOiB0cnVlLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gT3BlcmF0aW9uU2NoZWR1bGVyQ29tcG9uZW50KVxuICAgIH0sXG4gICAge1xuICAgICAgcHJvdmlkZTogTkdfVkFMSURBVE9SUyxcbiAgICAgIG11bHRpOiB0cnVlLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gT3BlcmF0aW9uU2NoZWR1bGVyQ29tcG9uZW50KVxuICAgIH1cbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBPcGVyYXRpb25TY2hlZHVsZXJDb21wb25lbnRcbiAgaW1wbGVtZW50cyBDb250cm9sVmFsdWVBY2Nlc3NvciwgVmFsaWRhdG9yLCBPbkluaXQsIE9uRGVzdHJveVxue1xuICBASW5wdXQoJ21pbnV0ZXNBaGVhZCcpIHNldCBfbWludXRlc0FoZWFkKG1pbnV0ZXM6IG51bWJlcikge1xuICAgIGlmIChtaW51dGVzICYmIG1pbnV0ZXMgPiB0aGlzLk1JTlVURVNfQUhFQURfREVGQVVMVCkge1xuICAgICAgdGhpcy5taW51dGVzQWhlYWQgPSBtaW51dGVzO1xuICAgIH1cbiAgfVxuXG4gIHBsYWNlaG9sZGVyOiBzdHJpbmcgPSBnZXR0ZXh0KCdTdGFydCBkYXRlJyk7XG4gIGZnT3BlcmF0aW9uU2NoZWR1bGVyOiBGb3JtR3JvdXA7XG4gIG1pbkRhdGU6IERhdGU7XG4gIG1pbkRlbGF5OiBudW1iZXI7XG4gIG1heERlbGF5OiBudW1iZXI7XG4gIGRlbGF5RXJyb3JzOiBWYWxpZGF0aW9uRXJyb3JzID0gbnVsbDtcbiAgcGlja2VyRXJyb3JzOiBWYWxpZGF0aW9uRXJyb3JzID0gbnVsbDtcblxuICBwcml2YXRlIHJlYWRvbmx5IERFTEFZX1NFQ09ORFNfREVGQVVMVDogbnVtYmVyID0gMTtcbiAgcHJpdmF0ZSByZWFkb25seSBNSU5fREVMQVlfU0VDT05EU19ERUZBVUxUOiBudW1iZXIgPSAwLjAwMTtcbiAgcHJpdmF0ZSByZWFkb25seSBNQVhfREVMQVlfU0VDT05EU19ERUZBVUxUOiBudW1iZXIgPSAzNjAwO1xuICBwcml2YXRlIHJlYWRvbmx5IE1JTlVURVNfQUhFQURfREVGQVVMVDogbnVtYmVyID0gNTtcbiAgcHJpdmF0ZSBpc0RlbGF5SW5TZWNvbmRzID0gdHJ1ZTtcbiAgcHJpdmF0ZSBtaW51dGVzQWhlYWQ6IG51bWJlciA9IHRoaXMuTUlOVVRFU19BSEVBRF9ERUZBVUxUO1xuICBwcml2YXRlIHJlYWRvbmx5IERFTEFZX0tFWV9DQVRFR09SWSA9ICdkZXZpY2UtY29udHJvbCc7XG4gIHByaXZhdGUgcmVhZG9ubHkgTUFYX0RFTEFZX0tFWV9OQU1FID0gJ2J1bGtvcGVyYXRpb24ubWF4Y3JlYXRpb25yYW1wJztcbiAgcHJpdmF0ZSByZWFkb25seSBNSU5fREVMQVlfS0VZX05BTUUgPSAnYnVsa29wZXJhdGlvbi5jcmVhdGlvbnJhbXAnO1xuICBwcml2YXRlIGN1cnJlbnRVbml0ID0gJ3NlY29uZHMnO1xuICBwcml2YXRlIGRlbGF5SW5TZWNvbmRzOiBudW1iZXI7XG4gIHByaXZhdGUgaW5pdGlhbERhdGU6IERhdGU7XG4gIHByaXZhdGUgc3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG5cbiAgcHJpdmF0ZSBvbkNoYW5nZTogKG5hbWUpID0+IHZvaWQ7XG4gIHByaXZhdGUgb25Ub3VjaGVkOiAoKSA9PiB2b2lkO1xuICBwcml2YXRlIG9uVmFsaWRhdG9yQ2hhbmdlZDogKCkgPT4gdm9pZDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlcixcbiAgICBwcml2YXRlIG9wdGlvbnM6IE9wdGlvbnNTZXJ2aWNlXG4gICkge31cblxuICBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLm1pbkRhdGUgPSBuZXcgRGF0ZSgpO1xuICAgIHRoaXMuaW5pdGlhbERhdGUgPSBuZXcgRGF0ZShcbiAgICAgIHRoaXMubWluRGF0ZS5zZXRNaW51dGVzKHRoaXMubWluRGF0ZS5nZXRNaW51dGVzKCkgKyB0aGlzLm1pbnV0ZXNBaGVhZClcbiAgICApO1xuXG4gICAgdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlciA9IHRoaXMuZm9ybUJ1aWxkZXIuZ3JvdXAoe1xuICAgICAgcGlja2VyOiBbJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCB0aGlzLmRhdGVWYWxpZGF0aW9uXV0sXG4gICAgICB0aW1lOiBbJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCB0aGlzLnRpbWVWYWxpZGF0aW9uXV0sXG4gICAgICBkZWxheTogWycnLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF1dLFxuICAgICAgdW5pdDogWydzZWNvbmRzJ11cbiAgICB9KTtcblxuICAgIHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIucGF0Y2hWYWx1ZSh7XG4gICAgICBwaWNrZXI6IHRoaXMuaW5pdGlhbERhdGUsXG4gICAgICB0aW1lOiB0aGlzLmluaXRpYWxEYXRlLFxuICAgICAgZGVsYXk6IHRoaXMuREVMQVlfU0VDT05EU19ERUZBVUxUXG4gICAgfSk7XG5cbiAgICAvLyBEdWUgdG8gdGhlIHZhbGlkYXRpb24gb2YgcGlja2VyIGFuZCB0aW1lIGl0IGNvdWxkIGJlIHBvc3NpYmxlIHRoYXQgdmFsdWUgY2hhbmdlc1xuICAgIC8vIGFyZSBlbWl0dGVkIG1vcmUgdGhhbiBvbmNlLiBUaGVyZWZvcmUgd2UgdGhyb3R0bGUgdGhlIGVtaXRzLlxuICAgIGNvbnN0IHZhbHVlQ2hhbmdlcyQgPSB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLnZhbHVlQ2hhbmdlcy5waXBlKHRocm90dGxlVGltZSgxMDApKTtcbiAgICB0aGlzLnN1YnNjcmlwdGlvbiA9IHZhbHVlQ2hhbmdlcyQuc3Vic2NyaWJlKGRhdGEgPT4ge1xuICAgICAgdGhpcy5kZWxheUVycm9ycyA9IHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuY29udHJvbHMuZGVsYXkuZXJyb3JzO1xuICAgICAgdGhpcy5waWNrZXJFcnJvcnMgPSB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmNvbnRyb2xzLnBpY2tlci5lcnJvcnM7XG4gICAgICB0aGlzLmNvbnZlcnREZWxheUhhbmRsZXIoZGF0YS51bml0KTtcbiAgICAgIHRoaXMuZW1pdERhdGEoZGF0YSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLnVwZGF0ZURlbGF5VmFsaWRhdGlvbigpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMuc3Vic2NyaXB0aW9uICYmICF0aGlzLnN1YnNjcmlwdGlvbi5jbG9zZWQpIHtcbiAgICAgIHRoaXMuc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICB9XG5cbiAgd3JpdGVWYWx1ZSh2YWx1ZTogT3BlcmF0aW9uU2NoZWR1bGUpOiB2b2lkIHtcbiAgICBpZiAodmFsdWUpIHtcbiAgICAgIHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIucGF0Y2hWYWx1ZSh7XG4gICAgICAgIHBpY2tlcjogdmFsdWUuc2NoZWR1bGVkRGF0ZSxcbiAgICAgICAgdGltZTogdmFsdWUuc2NoZWR1bGVkRGF0ZSxcbiAgICAgICAgZGVsYXk6IHZhbHVlLmRlbGF5SW5TZWNvbmRzID4gMSA/IHZhbHVlLmRlbGF5SW5TZWNvbmRzIDogdmFsdWUuZGVsYXlJblNlY29uZHMgKiAxMDAwLFxuICAgICAgICB1bml0OiB2YWx1ZS5kZWxheUluU2Vjb25kcyA+IDEgPyAnc2Vjb25kcycgOiAnbWlsbGlzZWNvbmRzJ1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcmVnaXN0ZXJPbkNoYW5nZShmbjogYW55KTogdm9pZCB7XG4gICAgdGhpcy5vbkNoYW5nZSA9IGZuO1xuICB9XG5cbiAgcmVnaXN0ZXJPblRvdWNoZWQoZm46IGFueSk6IHZvaWQge1xuICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gIH1cblxuICBzZXREaXNhYmxlZFN0YXRlPyhpc0Rpc2FibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXI/LmRpc2FibGVkID09PSBpc0Rpc2FibGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlzRGlzYWJsZWQgPyB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmRpc2FibGUoKSA6IHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuZW5hYmxlKCk7XG4gIH1cblxuICB2YWxpZGF0ZSgpOiBWYWxpZGF0aW9uRXJyb3JzIHtcbiAgICBpZiAodGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5pbnZhbGlkKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi50aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmNvbnRyb2xzLnBpY2tlci5lcnJvcnMsXG4gICAgICAgIC4uLnRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuY29udHJvbHMudGltZS5lcnJvcnMsXG4gICAgICAgIC4uLnRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuY29udHJvbHMuZGVsYXkuZXJyb3JzXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHJlZ2lzdGVyT25WYWxpZGF0b3JDaGFuZ2UoZm46IGFueSkge1xuICAgIHRoaXMub25WYWxpZGF0b3JDaGFuZ2VkID0gZm47XG4gIH1cblxuICBtYXJrQXNUb3VjaGVkKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLm9uVG91Y2hlZCkge1xuICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICB9XG4gIH1cblxuICBjb252ZXJ0RGVsYXlIYW5kbGVyKHVuaXQ6IHN0cmluZykge1xuICAgIGlmICh0aGlzLmN1cnJlbnRVbml0ID09PSB1bml0KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5jdXJyZW50VW5pdCA9IHVuaXQ7XG5cbiAgICB0aGlzLmNvbnZlcnREZWxheSh0aGlzLmN1cnJlbnRVbml0KTtcblxuICAgIC8vIHVwZGF0ZSB2YWxpZGF0b3Igb24gZGVsYXkgY29udHJvbCB0byBtYWtlIHN1cmUgdGhhdFxuICAgIC8vIHN3aXRjaGluZyBmcm9tIG1pbnV0ZXMgdG8gc2Vjb25kcyBvciB2aWNlIHZlcnNhIGRvZXMgbm90IGhhcm0gdmFsaWRhdGlvbi5cbiAgICB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmNvbnRyb2xzLmRlbGF5LnNldFZhbGlkYXRvcnMoW1xuICAgICAgVmFsaWRhdG9ycy5yZXF1aXJlZCxcbiAgICAgIFZhbGlkYXRvcnMubWluKHRoaXMubWluRGVsYXkpLFxuICAgICAgVmFsaWRhdG9ycy5tYXgodGhpcy5tYXhEZWxheSlcbiAgICBdKTtcbiAgICB0aGlzLmZnT3BlcmF0aW9uU2NoZWR1bGVyLmNvbnRyb2xzLmRlbGF5LnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoKTtcbiAgfVxuXG4gIGVtaXREYXRhKGRhdGE6IHsgZGVsYXlJblNlY29uZHM6IG51bWJlcjsgcGlja2VyOiBEYXRlOyB0aW1lPzogRGF0ZTsgZGVsYXk/OiBudW1iZXIgfSkge1xuICAgIGlmICh0aGlzLm9uVmFsaWRhdG9yQ2hhbmdlZCkge1xuICAgICAgdGhpcy5vblZhbGlkYXRvckNoYW5nZWQoKTtcbiAgICB9XG5cbiAgICBpZiAoZGF0YS5waWNrZXIgJiYgZGF0YS50aW1lKSB7XG4gICAgICBkYXRhLnBpY2tlciA9IHRoaXMuY29tYmluZURhdGVBbmRUaW1lKGRhdGEucGlja2VyLCBkYXRhLnRpbWUpO1xuICAgIH1cblxuICAgIHRoaXMuY29udmVydERlbGF5KHRoaXMuY3VycmVudFVuaXQpO1xuICAgIGRhdGEuZGVsYXlJblNlY29uZHMgPSB0aGlzLmRlbGF5SW5TZWNvbmRzO1xuXG4gICAgaWYgKHRoaXMub25DaGFuZ2UpIHtcbiAgICAgIHRoaXMub25DaGFuZ2Uoe1xuICAgICAgICBkZWxheUluU2Vjb25kczogZGF0YS5kZWxheUluU2Vjb25kcyxcbiAgICAgICAgc2NoZWR1bGVkRGF0ZTogZGF0YS5waWNrZXJcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgdXBkYXRlRGVsYXlWYWxpZGF0aW9uKCkge1xuICAgIGNvbnN0IG1pblN5c3RlbSA9IGF3YWl0IHRoaXMub3B0aW9ucy5nZXRTeXN0ZW1PcHRpb24oXG4gICAgICB0aGlzLkRFTEFZX0tFWV9DQVRFR09SWSxcbiAgICAgIHRoaXMuTUlOX0RFTEFZX0tFWV9OQU1FXG4gICAgKTtcbiAgICBjb25zdCBtYXhTeXN0ZW0gPSBhd2FpdCB0aGlzLm9wdGlvbnMuZ2V0U3lzdGVtT3B0aW9uKFxuICAgICAgdGhpcy5ERUxBWV9LRVlfQ0FURUdPUlksXG4gICAgICB0aGlzLk1BWF9ERUxBWV9LRVlfTkFNRVxuICAgICk7XG5cbiAgICB0aGlzLm1heERlbGF5ID0gbWF4U3lzdGVtID8gTnVtYmVyKG1heFN5c3RlbSkgOiB0aGlzLk1BWF9ERUxBWV9TRUNPTkRTX0RFRkFVTFQ7XG4gICAgdGhpcy5taW5EZWxheSA9IG1pblN5c3RlbSA/IE51bWJlcihtaW5TeXN0ZW0pIDogdGhpcy5NSU5fREVMQVlfU0VDT05EU19ERUZBVUxUO1xuXG4gICAgdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlclxuICAgICAgLmdldCgnZGVsYXknKVxuICAgICAgLnNldFZhbGlkYXRvcnMoW1xuICAgICAgICBWYWxpZGF0b3JzLnJlcXVpcmVkLFxuICAgICAgICBWYWxpZGF0b3JzLm1pbih0aGlzLm1pbkRlbGF5KSxcbiAgICAgICAgVmFsaWRhdG9ycy5tYXgodGhpcy5tYXhEZWxheSlcbiAgICAgIF0pO1xuICAgIHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBjb252ZXJ0RGVsYXkodW5pdDogc3RyaW5nKSB7XG4gICAgdGhpcy5kZWxheUluU2Vjb25kcyA9IHRoaXMuZmdPcGVyYXRpb25TY2hlZHVsZXIuY29udHJvbHMuZGVsYXkudmFsdWU7XG5cbiAgICBpZiAodW5pdCA9PT0gJ3NlY29uZHMnICYmICF0aGlzLmlzRGVsYXlJblNlY29uZHMpIHtcbiAgICAgIHRoaXMubWF4RGVsYXkgPSB0aGlzLm1heERlbGF5IC8gMTAwMDtcbiAgICAgIHRoaXMubWluRGVsYXkgPSB0aGlzLm1pbkRlbGF5IC8gMTAwMDtcbiAgICAgIHRoaXMuaXNEZWxheUluU2Vjb25kcyA9IHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHVuaXQgPT09ICdtaWxsaXNlY29uZHMnKSB7XG4gICAgICB0aGlzLmRlbGF5SW5TZWNvbmRzID0gdGhpcy5mZ09wZXJhdGlvblNjaGVkdWxlci5jb250cm9scy5kZWxheS52YWx1ZSAvIDEwMDA7XG4gICAgICBpZiAodGhpcy5pc0RlbGF5SW5TZWNvbmRzKSB7XG4gICAgICAgIHRoaXMubWF4RGVsYXkgPSB0aGlzLm1heERlbGF5ICogMTAwMDtcbiAgICAgICAgdGhpcy5taW5EZWxheSA9IHRoaXMubWluRGVsYXkgKiAxMDAwO1xuICAgICAgICB0aGlzLmlzRGVsYXlJblNlY29uZHMgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGNvbWJpbmVEYXRlQW5kVGltZShkYXRlOiBEYXRlLCB0aW1lOiBEYXRlKSB7XG4gICAgcmV0dXJuIG5ldyBEYXRlKFxuICAgICAgZGF0ZS5nZXRGdWxsWWVhcigpLFxuICAgICAgZGF0ZS5nZXRNb250aCgpLFxuICAgICAgZGF0ZS5nZXREYXRlKCksXG4gICAgICB0aW1lLmdldEhvdXJzKCksXG4gICAgICB0aW1lLmdldE1pbnV0ZXMoKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGRhdGVWYWxpZGF0aW9uKGZDb250cm9sOiBGb3JtQ29udHJvbCkge1xuICAgIGlmIChmQ29udHJvbC52YWx1ZSkge1xuICAgICAgY29uc3QgZGF0ZSA9IGZDb250cm9sLnZhbHVlIGFzIERhdGU7XG4gICAgICBmQ29udHJvbC5wYXJlbnQuZ2V0KCd0aW1lJykuc2V0VmFsdWUoZGF0ZSk7XG4gICAgICByZXR1cm4gZGF0ZSA+PSBuZXcgRGF0ZSgpXG4gICAgICAgID8gbnVsbFxuICAgICAgICA6IHtcbiAgICAgICAgICAgIGRhdGVWYWxpZGF0aW9uOiB0cnVlXG4gICAgICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIHsgZGF0ZVZhbGlkYXRpb246IHRydWUgfTtcbiAgfVxuXG4gIHByaXZhdGUgdGltZVZhbGlkYXRpb24oZkNvbnRyb2w6IEZvcm1Db250cm9sKSB7XG4gICAgaWYgKGZDb250cm9sLnZhbHVlKSB7XG4gICAgICBjb25zdCBkYXRlID0gZkNvbnRyb2wudmFsdWUgYXMgRGF0ZTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9XG4gICAgICAgIGRhdGUgPj0gbmV3IERhdGUoKVxuICAgICAgICAgID8gbnVsbFxuICAgICAgICAgIDoge1xuICAgICAgICAgICAgICBkYXRlVmFsaWRhdGlvbjogdHJ1ZVxuICAgICAgICAgICAgfTtcblxuICAgICAgY29uc3QgcGlja2VyID0gZkNvbnRyb2wucGFyZW50LmdldCgncGlja2VyJyk7XG5cbiAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgcGlja2VyLnNldEVycm9ycyhyZXN1bHQpO1xuICAgICAgICBwaWNrZXIubWFya0FzVG91Y2hlZCgpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuXG4gICAgICBpZiAocGlja2VyICYmIHBpY2tlci5lcnJvcnMgJiYgcGlja2VyLmVycm9ycy5kYXRlVmFsaWRhdGlvbikge1xuICAgICAgICBkZWxldGUgcGlja2VyLmVycm9ycy5kYXRlVmFsaWRhdGlvbjtcblxuICAgICAgICBpZiAoaXNFbXB0eShwaWNrZXIuZXJyb3JzKSkge1xuICAgICAgICAgIHBpY2tlci5zZXRFcnJvcnMobnVsbCk7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIHBpY2tlci5zZXRFcnJvcnMocGlja2VyLmVycm9ycyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgICByZXR1cm4geyBkYXRlVmFsaWRhdGlvbjogdHJ1ZSB9O1xuICB9XG59XG4iLCI8ZGl2IFtmb3JtR3JvdXBdPVwiZmdPcGVyYXRpb25TY2hlZHVsZXJcIj5cbiAgPGRpdiBjbGFzcz1cImZvcm0tZ3JvdXBcIj5cbiAgICA8bGFiZWwgdHJhbnNsYXRlPlN0YXJ0IGRhdGU8L2xhYmVsPlxuICAgIDxkaXYgY2xhc3M9XCJkYXRldGltZS1waWNrZXJcIj5cbiAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cImRhdGVwaWNrZXJcIj5cbiAgICAgICAgPGlucHV0XG4gICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgIHBsYWNlaG9sZGVyPVwie3sgcGxhY2Vob2xkZXIgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgIHJlcXVpcmVkXG4gICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwicGlja2VyXCJcbiAgICAgICAgICBbYnNDb25maWddPVwieyBjdXN0b21Ub2RheUNsYXNzOiAndG9kYXknIH1cIlxuICAgICAgICAgIFttaW5EYXRlXT1cIm1pbkRhdGVcIlxuICAgICAgICAgIGJzRGF0ZXBpY2tlclxuICAgICAgICAgIChibHVyKT1cIm1hcmtBc1RvdWNoZWQoKVwiXG4gICAgICAgIC8+XG4gICAgICAgIDxjOHktbWVzc2FnZXM+XG4gICAgICAgICAgPGM4eS1tZXNzYWdlXG4gICAgICAgICAgICBbbmFtZV09XCInZGF0ZVZhbGlkYXRpb24nXCJcbiAgICAgICAgICAgIFt0ZXh0XT1cIidTZWxlY3QgdGltZSBpbiB0aGUgZnV0dXJlLicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgID48L2M4eS1tZXNzYWdlPlxuICAgICAgICA8L2M4eS1tZXNzYWdlcz5cbiAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICA8dGltZXBpY2tlclxuICAgICAgICBjbGFzcz1cImZvcm0tZ3JvdXBcIlxuICAgICAgICBbc2hvd1NwaW5uZXJzXT1cImZhbHNlXCJcbiAgICAgICAgW3Nob3dNZXJpZGlhbl09XCJmYWxzZVwiXG4gICAgICAgIGZvcm1Db250cm9sTmFtZT1cInRpbWVcIlxuICAgICAgICAoYmx1cik9XCJtYXJrQXNUb3VjaGVkKClcIlxuICAgICAgPjwvdGltZXBpY2tlcj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwXCI+XG4gICAgPGM4eS1mb3JtLWdyb3VwIFtoYXNFcnJvcl09XCJkZWxheUVycm9yc1wiPlxuICAgICAgPGxhYmVsIHRyYW5zbGF0ZT5EZWxheTwvbGFiZWw+XG4gICAgICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXBcIj5cbiAgICAgICAgPGlucHV0XG4gICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgIHBsYWNlaG9sZGVyPVwie3sgJ2UuZy4nIHwgdHJhbnNsYXRlIH19IDE1XCJcbiAgICAgICAgICB0eXBlPVwibnVtYmVyXCJcbiAgICAgICAgICByZXF1aXJlZFxuICAgICAgICAgIGZvcm1Db250cm9sTmFtZT1cImRlbGF5XCJcbiAgICAgICAgICAoYmx1cik9XCJtYXJrQXNUb3VjaGVkKClcIlxuICAgICAgICAvPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXAtYnRuXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImM4eS1zZWxlY3Qtd3JhcHBlclwiPlxuICAgICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbCBtLXItc20tMzIgbS1yLXhzLTU2XCJcbiAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInRGVsYXkgdW5pdHMnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwidW5pdFwiXG4gICAgICAgICAgICAgIChibHVyKT1cIm1hcmtBc1RvdWNoZWQoKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxvcHRpb25cbiAgICAgICAgICAgICAgICB2YWx1ZT1cInNlY29uZHNcIlxuICAgICAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgU2Vjb25kc1xuICAgICAgICAgICAgICA8L29wdGlvbj5cbiAgICAgICAgICAgICAgPG9wdGlvblxuICAgICAgICAgICAgICAgIHZhbHVlPVwibWlsbGlzZWNvbmRzXCJcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIE1pbGxpc2Vjb25kc1xuICAgICAgICAgICAgICA8L29wdGlvbj5cbiAgICAgICAgICAgIDwvc2VsZWN0PlxuICAgICAgICAgICAgPHNwYW4+PC9zcGFuPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=