UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

239 lines 43.2 kB
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==