UNPKG

@nova-ui/bits

Version:

SolarWinds Nova Framework

222 lines 35.1 kB
// © 2022 SolarWinds Worldwide, LLC. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, Input, Output, Renderer2, ViewChild, ViewEncapsulation, } from "@angular/core"; import { NG_VALUE_ACCESSOR } from "@angular/forms"; import moment from "moment/moment"; import { NuiFormFieldControl } from "../form-field/public-api"; import * as i0 from "@angular/core"; import * as i1 from "../date-picker/date-picker.component"; import * as i2 from "../time-picker/time-picker.component"; // <example-url>./../examples/index.html#/date-time-picker</example-url><br /> export class DateTimePickerComponent { /** * Input to set aria label text */ get ariaLabel() { return this._ariaLabel; } // changing the value with regular @Input doesn't trigger change detection // so we need to do that manually in the setter set ariaLabel(value) { if (value !== this._ariaLabel) { this._ariaLabel = value; this.cd.markForCheck(); } } /** model of picker */ get model() { return this._model; } set model(value) { if (moment(value).isValid()) { this._model = value; } this.updateChildrenModels(); } constructor(renderer, cd) { this.renderer = renderer; this.cd = cd; /** Callback to invoke on model change */ this.modelChanged = new EventEmitter(); this.isInErrorStateDate = false; this.isInErrorStateTime = false; this._ariaLabel = ""; this.onTouched = () => { }; this.onChange = (value) => { }; } ngOnInit() { if (!this.initEmpty && !this.model) { this.model = moment(); this.onChange(this.model); this.cd.markForCheck(); } } ngAfterViewInit() { if (this.displayMode === "inline") { this.renderer.addClass(this.codeElement.nativeElement, "nui-datetime-picker--inline"); this.renderer.addClass(this.codeElement.nativeElement.querySelector(".nui-timepicker"), "nui-dropdown--inline"); } } writeValue(value) { this.model = value; this.updateChildrenModels(); } registerOnTouched(fn) { this.onTouched = fn; } registerOnChange(fn) { this.onChange = fn; } setDisabledState(isDisabled) { this.isDisabled = isDisabled; this.cd.markForCheck(); // This is needed to update "disabled" state for child date and time pickers } onTimeChanged(event) { this.updateTime(event); this.modelChanged.emit(moment(this.model)); this.onChange(this.model); this.onTouched(); } onDateChanged(event) { const isDateTheSame = moment.isMoment(this.date) && this.date.isSame(event); if (isDateTheSame) { return; } this.updateDate(event); this.modelChanged.emit(moment(this.model)); this.onChange(this.model); this.onTouched(); } onInputBlurred() { this.onTouched(); if (!this.model) { this.isInErrorStateDate = !this.date || (this.date && !moment(this.date).isValid()); this.isInErrorStateTime = !this.time || (this.time && !moment(this.time).isValid()); } } updateChildrenModels() { if (this.model) { this.date = this.model.clone(); this.time = this.model.clone(); } else if (!this.model && this.initEmpty) { // TODO: Replace with undefined // @ts-ignore this.date = null; // @ts-ignore this.time = null; } } updateDate(newValue) { if (!moment.isMoment(newValue) || !moment(newValue).isValid()) { // TODO: Replace with undefined // @ts-ignore this._model = null; // @ts-ignore this.date = null; return; } // In case 'date' is not set, this._model is set from 'time' model if 'time' model exists this._model = this._model || (this.time && this.time.clone()); if (this._model) { this._model.set({ year: newValue.year(), month: newValue.month(), date: newValue.date(), }); } this.date = newValue.clone(); } updateTime(newValue) { if (!moment.isMoment(newValue)) { // TODO: Replace with undefined // @ts-ignore this._model = null; // @ts-ignore this.time = null; return; } // In case 'time' is not set, this._model is set from 'date' model if 'date' model exists this._model = this._model || (this.date && this.date.clone()); if (this._model) { this._model.set({ hours: newValue.hours(), minutes: newValue.minutes(), seconds: newValue.seconds(), milliseconds: newValue.millisecond(), }); } this.time = newValue.clone(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateTimePickerComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DateTimePickerComponent, selector: "nui-date-time-picker", inputs: { maxDate: "maxDate", minDate: "minDate", displayMode: "displayMode", isDisabled: "isDisabled", initEmpty: "initEmpty", handleTimezone: "handleTimezone", appendToBody: "appendToBody", ariaLabel: "ariaLabel", model: "model" }, outputs: { modelChanged: "modelChanged" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DateTimePickerComponent), multi: true, }, { provide: NuiFormFieldControl, useExisting: forwardRef(() => DateTimePickerComponent), multi: true, }, ], viewQueries: [{ propertyName: "codeElement", first: true, predicate: ["nuiDatetimePicker"], descendants: true, static: true }], ngImport: i0, template: "<div\n #nuiDatetimePicker\n class=\"nui-datetime-picker\"\n [attr.aria-label]=\"ariaLabel\"\n>\n <div class=\"nui-datetime-picker__group\">\n <nui-date-picker\n class=\"nui-datepicker--justified\"\n [value]=\"date\"\n (valueChange)=\"onDateChanged($event)\"\n (inputBlurred)=\"onInputBlurred()\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [isDisabled]=\"isDisabled\"\n [isInErrorState]=\"isInErrorStateDate\"\n [handleTimezone]=\"handleTimezone\"\n [appendToBody]=\"appendToBody\"\n [ariaLabel]=\"ariaLabel + ' date'\"\n ></nui-date-picker>\n </div>\n <div class=\"nui-datetime-picker__group nui-datetime-picker__group--last\">\n <nui-time-picker\n class=\"nui-dropdown--justified\"\n [initEmpty]=\"initEmpty\"\n [model]=\"time\"\n (timeChanged)=\"onTimeChanged($event)\"\n (inputBlurred)=\"onInputBlurred()\"\n [isDisabled]=\"isDisabled\"\n [isInErrorState]=\"isInErrorStateTime\"\n [appendToBody]=\"appendToBody\"\n [ariaLabel]=\"ariaLabel + ' time'\"\n ></nui-time-picker>\n </div>\n</div>\n", styles: [".nui .nui-datetime-picker{display:flex;flex-direction:column}.nui .nui-datetime-picker .nui-timepicker,.nui .nui-datetime-picker .nui-timepicker__input-group,.nui .nui-datetime-picker .nui-datepicker{width:100%}.nui .nui-datetime-picker__group{width:135px;margin-bottom:10px}.nui .nui-datetime-picker__group--last{margin-bottom:0}.nui .nui-datetime-picker--inline{width:auto;flex-direction:row;max-width:none}.nui .nui-datetime-picker--inline .nui-datetime-picker__label{display:inline-block;line-height:30px}.nui .nui-datetime-picker--inline .nui-datetime-picker__group,.nui .nui-datetime-picker--inline .nui-datetime-picker__label{margin-bottom:0}.nui .nui-datetime-picker--inline .nui-datetime-picker__group:not(:last-child),.nui .nui-datetime-picker--inline .nui-datetime-picker__label:not(:last-child){margin-right:10px}\n"], dependencies: [{ kind: "component", type: i1.DatePickerComponent, selector: "nui-date-picker", inputs: ["inline", "isRequired", "isDisabled", "isInErrorState", "ariaLabel", "locale", "datepickerMode", "minDate", "maxDate", "minMode", "maxMode", "showWeeks", "dateFormat", "formatDay", "formatMonth", "formatYear", "formatDayHeader", "formatDayTitle", "formatMonthTitle", "startingDay", "yearRange", "onlyCurrentMonth", "preserveInsignificant", "disabledDates", "handleTimezone", "appendToBody", "value"], outputs: ["selectionDone", "valueChange", "calendarNavigated", "inputBlurred"] }, { kind: "component", type: i2.TimePickerComponent, selector: "nui-time-picker", inputs: ["timeStep", "isDisabled", "timeFormat", "preserveInsignificant", "isInErrorState", "ariaLabel", "initEmpty", "appendToBody", "model"], outputs: ["timeChanged", "inputBlurred"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DateTimePickerComponent, decorators: [{ type: Component, args: [{ selector: "nui-date-time-picker", providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DateTimePickerComponent), multi: true, }, { provide: NuiFormFieldControl, useExisting: forwardRef(() => DateTimePickerComponent), multi: true, }, ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #nuiDatetimePicker\n class=\"nui-datetime-picker\"\n [attr.aria-label]=\"ariaLabel\"\n>\n <div class=\"nui-datetime-picker__group\">\n <nui-date-picker\n class=\"nui-datepicker--justified\"\n [value]=\"date\"\n (valueChange)=\"onDateChanged($event)\"\n (inputBlurred)=\"onInputBlurred()\"\n [maxDate]=\"maxDate\"\n [minDate]=\"minDate\"\n [isDisabled]=\"isDisabled\"\n [isInErrorState]=\"isInErrorStateDate\"\n [handleTimezone]=\"handleTimezone\"\n [appendToBody]=\"appendToBody\"\n [ariaLabel]=\"ariaLabel + ' date'\"\n ></nui-date-picker>\n </div>\n <div class=\"nui-datetime-picker__group nui-datetime-picker__group--last\">\n <nui-time-picker\n class=\"nui-dropdown--justified\"\n [initEmpty]=\"initEmpty\"\n [model]=\"time\"\n (timeChanged)=\"onTimeChanged($event)\"\n (inputBlurred)=\"onInputBlurred()\"\n [isDisabled]=\"isDisabled\"\n [isInErrorState]=\"isInErrorStateTime\"\n [appendToBody]=\"appendToBody\"\n [ariaLabel]=\"ariaLabel + ' time'\"\n ></nui-time-picker>\n </div>\n</div>\n", styles: [".nui .nui-datetime-picker{display:flex;flex-direction:column}.nui .nui-datetime-picker .nui-timepicker,.nui .nui-datetime-picker .nui-timepicker__input-group,.nui .nui-datetime-picker .nui-datepicker{width:100%}.nui .nui-datetime-picker__group{width:135px;margin-bottom:10px}.nui .nui-datetime-picker__group--last{margin-bottom:0}.nui .nui-datetime-picker--inline{width:auto;flex-direction:row;max-width:none}.nui .nui-datetime-picker--inline .nui-datetime-picker__label{display:inline-block;line-height:30px}.nui .nui-datetime-picker--inline .nui-datetime-picker__group,.nui .nui-datetime-picker--inline .nui-datetime-picker__label{margin-bottom:0}.nui .nui-datetime-picker--inline .nui-datetime-picker__group:not(:last-child),.nui .nui-datetime-picker--inline .nui-datetime-picker__label:not(:last-child){margin-right:10px}\n"] }] }], ctorParameters: () => [{ type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }], propDecorators: { maxDate: [{ type: Input }], minDate: [{ type: Input }], displayMode: [{ type: Input }], isDisabled: [{ type: Input }], initEmpty: [{ type: Input }], handleTimezone: [{ type: Input }], appendToBody: [{ type: Input }], ariaLabel: [{ type: Input }], codeElement: [{ type: ViewChild, args: ["nuiDatetimePicker", { static: true }] }], modelChanged: [{ type: Output }], model: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS10aW1lLXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2RhdGUtdGltZS1waWNrZXIvZGF0ZS10aW1lLXBpY2tlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL2RhdGUtdGltZS1waWNrZXIvZGF0ZS10aW1lLXBpY2tlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUVILHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osVUFBVSxFQUNWLEtBQUssRUFFTCxNQUFNLEVBQ04sU0FBUyxFQUNULFNBQVMsRUFDVCxpQkFBaUIsR0FDcEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sTUFBTSxNQUFNLGVBQWUsQ0FBQztBQUduQyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7OztBQUUvRCw4RUFBOEU7QUFxQjlFLE1BQU0sT0FBTyx1QkFBdUI7SUFrQmhDOztPQUVHO0lBQ0gsSUFBb0IsU0FBUztRQUN6QixPQUFPLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDM0IsQ0FBQztJQUVELDBFQUEwRTtJQUMxRSwrQ0FBK0M7SUFDL0MsSUFBVyxT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LEtBQUssRUFBRSxJQUFJO3lCQUNkO3dCQUNEOzRCQUNJLE9BQU8sRUFBRSxtQkFBbUI7NEJBQzVCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLHdCQUF3QixDQUFDOzRCQUN0RCxLQUFLLEVBQUUsSUFBSTt5QkFDZDtxQkFDSixpQkFFYyxpQkFBaUIsQ0FBQyxJQUFJLG1CQUNwQix1QkFBdUIsQ0FBQyxNQUFNOzhHQU10QyxPQUFPO3NCQUFmLEtBQUs7Z0JBRUcsT0FBTztzQkFBZixLQUFLO2dCQUVHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRUcsVUFBVTtzQkFBbEIsS0FBSztnQkFFRyxTQUFTO3NCQUFqQixLQUFLO2dCQUVHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBRUcsWUFBWTtzQkFBcEIsS0FBSztnQkFLYyxTQUFTO3NCQUE1QixLQUFLO2dCQWNDLFdBQVc7c0JBRGpCLFNBQVM7dUJBQUMsbUJBQW1CLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUloRCxZQUFZO3NCQURYLE1BQU07Z0JBS0gsS0FBSztzQkFEUixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7XG4gICAgQWZ0ZXJWaWV3SW5pdCxcbiAgICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBDb21wb25lbnQsXG4gICAgRWxlbWVudFJlZixcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgZm9yd2FyZFJlZixcbiAgICBJbnB1dCxcbiAgICBPbkluaXQsXG4gICAgT3V0cHV0LFxuICAgIFJlbmRlcmVyMixcbiAgICBWaWV3Q2hpbGQsXG4gICAgVmlld0VuY2Fwc3VsYXRpb24sXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tIFwiQGFuZ3VsYXIvZm9ybXNcIjtcbmltcG9ydCBtb21lbnQgZnJvbSBcIm1vbWVudC9tb21lbnRcIjtcbmltcG9ydCB7IE1vbWVudCB9IGZyb20gXCJtb21lbnQvbW9tZW50XCI7XG5cbmltcG9ydCB7IE51aUZvcm1GaWVsZENvbnRyb2wgfSBmcm9tIFwiLi4vZm9ybS1maWVsZC9wdWJsaWMtYXBpXCI7XG5cbi8vIDxleGFtcGxlLXVybD4uLy4uL2V4YW1wbGVzL2luZGV4Lmh0bWwjL2RhdGUtdGltZS1waWNrZXI8L2V4YW1wbGUtdXJsPjxiciAvPlxuXG5AQ29tcG9uZW50KHtcbiAgICBzZWxlY3RvcjogXCJudWktZGF0ZS10aW1lLXBpY2tlclwiLFxuICAgIHRlbXBsYXRlVXJsOiBcIi4vZGF0ZS10aW1lLXBpY2tlci5jb21wb25lbnQuaHRtbFwiLFxuICAgIHByb3ZpZGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICAgICAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IERhdGVUaW1lUGlja2VyQ29tcG9uZW50KSxcbiAgICAgICAgICAgIG11bHRpOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgICBwcm92aWRlOiBOdWlGb3JtRmllbGRDb250cm9sLCAvLyB0aGlzIGFsbG93cyBvdXIgZm9ybSBjb250cm9sIHRvIHVzZSBydW4tdGltZSB0eXBlIGNoZWNraW5nXG4gICAgICAgICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBEYXRlVGltZVBpY2tlckNvbXBvbmVudCksXG4gICAgICAgICAgICBtdWx0aTogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICBdLFxuICAgIHN0eWxlVXJsczogW1wiLi9kYXRlLXRpbWUtcGlja2VyLmNvbXBvbmVudC5sZXNzXCJdLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIERhdGVUaW1lUGlja2VyQ29tcG9uZW50XG4gICAgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkluaXQsIENvbnRyb2xWYWx1ZUFjY2Vzc29yXG57XG4gICAgLyoqIGxhdGVzdCBhdmFpbGFibGUgZGF0ZSAqL1xuICAgIEBJbnB1dCgpIG1heERhdGU6IE1vbWVudDtcbiAgICAvKiogZWFybGllc3QgYXZhaWxhYmxlIGRhdGUgKi9cbiAgICBASW5wdXQoKSBtaW5EYXRlOiBNb21lbnQ7XG4gICAgLyoqIHNldHMgbW9kZSBvZiBzaG93aW5nIGRhdGUtdGltZS1waWNrZXIgKi9cbiAgICBASW5wdXQoKSBkaXNwbGF5TW9kZTogc3RyaW5nO1xuXG4gICAgQElucHV0KCkgaXNEaXNhYmxlZDogYm9vbGVhbjtcblxuICAgIEBJbnB1dCgpIGluaXRFbXB0eTogYm9vbGVhbjtcbiAgICAvKiogSXMgdXNlZCB0byBoYW5kbGUgdGltZXpvbmUgb2YgZGF0ZSB2YWx1ZSwgcGFzc2VkIHRvIERhdGVQaWNrZXJDb21wb25lbnQgKi9cbiAgICBASW5wdXQoKSBoYW5kbGVUaW1lem9uZTogYm9vbGVhbjtcbiAgICAvKiogQWxsb3dzIHBvcHVwIGJveCB0byBiZSBhdHRhY2hlZCB0byBkb2N1bWVudC5ib2R5ICovXG4gICAgQElucHV0KCkgYXBwZW5kVG9Cb2R5OiBib29sZWFuO1xuXG4gICAgLyoqXG4gICAgICogSW5wdXQgdG8gc2V0IGFyaWEgbGFiZWwgdGV4dFxuICAgICAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBnZXQgYXJpYUxhYmVsKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLl9hcmlhTGFiZWw7XG4gICAgfVxuXG4gICAgLy8gY2hhbmdpbmcgdGhlIHZhbHVlIHdpdGggcmVndWxhciBASW5wdXQgZG9lc24ndCB0cmlnZ2VyIGNoYW5nZSBkZXRlY3Rpb25cbiAgICAvLyBzbyB3ZSBuZWVkIHRvIGRvIHRoYXQgbWFudWFsbHkgaW4gdGhlIHNldHRlclxuICAgIHB1YmxpYyBzZXQgYXJpYUxhYmVsKHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKHZhbHVlICE9PSB0aGlzLl9hcmlhTGFiZWwpIHtcbiAgICAgICAgICAgIHRoaXMuX2FyaWFMYWJlbCA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIEBWaWV3Q2hpbGQoXCJudWlEYXRldGltZVBpY2tlclwiLCB7IHN0YXRpYzogdHJ1ZSB9KVxuICAgIHB1YmxpYyBjb2RlRWxlbWVudDogRWxlbWVudFJlZjtcbiAgICAvKiogQ2FsbGJhY2sgdG8gaW52b2tlIG9uIG1vZGVsIGNoYW5nZSAqL1xuICAgIEBPdXRwdXQoKVxuICAgIG1vZGVsQ2hhbmdlZDogRXZlbnRFbWl0dGVyPE1vbWVudD4gPSBuZXcgRXZlbnRFbWl0dGVyPE1vbWVudD4oKTtcblxuICAgIC8qKiBtb2RlbCBvZiBwaWNrZXIgKi9cbiAgICBASW5wdXQoKVxuICAgIGdldCBtb2RlbCgpOiBNb21lbnQgfCB1bmRlZmluZWQge1xuICAgICAgICByZXR1cm4gdGhpcy5fbW9kZWw7XG4gICAgfVxuXG4gICAgc2V0IG1vZGVsKHZhbHVlOiBNb21lbnQgfCB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKG1vbWVudCh2YWx1ZSkuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICB0aGlzLl9tb2RlbCA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudXBkYXRlQ2hpbGRyZW5Nb2RlbHMoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZGF0ZT86IE1vbWVudDtcbiAgICBwdWJsaWMgdGltZT86IE1vbWVudDtcbiAgICBwcml2YXRlIF9tb2RlbD86IE1vbWVudDtcbiAgICBwdWJsaWMgaXNJbkVycm9yU3RhdGVEYXRlID0gZmFsc2U7XG4gICAgcHVibGljIGlzSW5FcnJvclN0YXRlVGltZSA9IGZhbHNlO1xuXG4gICAgcHJpdmF0ZSBfYXJpYUxhYmVsOiBzdHJpbmcgPSBcIlwiO1xuXG4gICAgb25Ub3VjaGVkID0gKCk6IHZvaWQgPT4ge307XG4gICAgb25DaGFuZ2UgPSAodmFsdWU6IGFueSk6IHZvaWQgPT4ge307XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsIHByaXZhdGUgY2Q6IENoYW5nZURldGVjdG9yUmVmKSB7fVxuXG4gICAgcHVibGljIG5nT25Jbml0KCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuaW5pdEVtcHR5ICYmICF0aGlzLm1vZGVsKSB7XG4gICAgICAgICAgICB0aGlzLm1vZGVsID0gbW9tZW50KCk7XG4gICAgICAgICAgICB0aGlzLm9uQ2hhbmdlKHRoaXMubW9kZWwpO1xuICAgICAgICAgICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRpc3BsYXlNb2RlID09PSBcImlubGluZVwiKSB7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcmVyLmFkZENsYXNzKFxuICAgICAgICAgICAgICAgIHRoaXMuY29kZUVsZW1lbnQubmF0aXZlRWxlbWVudCxcbiAgICAgICAgICAgICAgICBcIm51aS1kYXRldGltZS1waWNrZXItLWlubGluZVwiXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5hZGRDbGFzcyhcbiAgICAgICAgICAgICAgICB0aGlzLmNvZGVFbGVtZW50Lm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvcihcIi5udWktdGltZXBpY2tlclwiKSxcbiAgICAgICAgICAgICAgICBcIm51aS1kcm9wZG93bi0taW5saW5lXCJcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB3cml0ZVZhbHVlKHZhbHVlOiBNb21lbnQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5tb2RlbCA9IHZhbHVlO1xuICAgICAgICB0aGlzLnVwZGF0ZUNoaWxkcmVuTW9kZWxzKCk7XG4gICAgfVxuXG4gICAgcmVnaXN0ZXJPblRvdWNoZWQoZm46ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcbiAgICB9XG5cbiAgICByZWdpc3Rlck9uQ2hhbmdlKGZuOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgICAgIHRoaXMub25DaGFuZ2UgPSBmbjtcbiAgICB9XG5cbiAgICBzZXREaXNhYmxlZFN0YXRlKGlzRGlzYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pc0Rpc2FibGVkID0gaXNEaXNhYmxlZDtcbiAgICAgICAgdGhpcy5jZC5tYXJrRm9yQ2hlY2soKTsgLy8gVGhpcyBpcyBuZWVkZWQgdG8gdXBkYXRlIFwiZGlzYWJsZWRcIiBzdGF0ZSBmb3IgY2hpbGQgZGF0ZSBhbmQgdGltZSBwaWNrZXJzXG4gICAgfVxuXG4gICAgb25UaW1lQ2hhbmdlZChldmVudDogTW9tZW50KTogdm9pZCB7XG4gICAgICAgIHRoaXMudXBkYXRlVGltZShldmVudCk7XG4gICAgICAgIHRoaXMubW9kZWxDaGFuZ2VkLmVtaXQobW9tZW50KHRoaXMubW9kZWwpKTtcbiAgICAgICAgdGhpcy5vbkNoYW5nZSh0aGlzLm1vZGVsKTtcbiAgICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICB9XG5cbiAgICBvbkRhdGVDaGFuZ2VkKGV2ZW50OiBNb21lbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgaXNEYXRlVGhlU2FtZSA9XG4gICAgICAgICAgICBtb21lbnQuaXNNb21lbnQodGhpcy5kYXRlKSAmJiB0aGlzLmRhdGUuaXNTYW1lKGV2ZW50KTtcblxuICAgICAgICBpZiAoaXNEYXRlVGhlU2FtZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVEYXRlKGV2ZW50KTtcbiAgICAgICAgdGhpcy5tb2RlbENoYW5nZWQuZW1pdChtb21lbnQodGhpcy5tb2RlbCkpO1xuICAgICAgICB0aGlzLm9uQ2hhbmdlKHRoaXMubW9kZWwpO1xuICAgICAgICB0aGlzLm9uVG91Y2hlZCgpO1xuICAgIH1cblxuICAgIG9uSW5wdXRCbHVycmVkKCk6IHZvaWQge1xuICAgICAgICB0aGlzLm9uVG91Y2hlZCgpO1xuICAgICAgICBpZiAoIXRoaXMubW9kZWwpIHtcbiAgICAgICAgICAgIHRoaXMuaXNJbkVycm9yU3RhdGVEYXRlID1cbiAgICAgICAgICAgICAgICAhdGhpcy5kYXRlIHx8ICh0aGlzLmRhdGUgJiYgIW1vbWVudCh0aGlzLmRhdGUpLmlzVmFsaWQoKSk7XG4gICAgICAgICAgICB0aGlzLmlzSW5FcnJvclN0YXRlVGltZSA9XG4gICAgICAgICAgICAgICAgIXRoaXMudGltZSB8fCAodGhpcy50aW1lICYmICFtb21lbnQodGhpcy50aW1lKS5pc1ZhbGlkKCkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB1cGRhdGVDaGlsZHJlbk1vZGVscygpIHtcbiAgICAgICAgaWYgKHRoaXMubW9kZWwpIHtcbiAgICAgICAgICAgIHRoaXMuZGF0ZSA9IHRoaXMubW9kZWwuY2xvbmUoKTtcbiAgICAgICAgICAgIHRoaXMudGltZSA9IHRoaXMubW9kZWwuY2xvbmUoKTtcbiAgICAgICAgfSBlbHNlIGlmICghdGhpcy5tb2RlbCAmJiB0aGlzLmluaXRFbXB0eSkge1xuICAgICAgICAgICAgLy8gVE9ETzogUmVwbGFjZSB3aXRoIHVuZGVmaW5lZFxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgdGhpcy5kYXRlID0gbnVsbDtcbiAgICAgICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgICAgIHRoaXMudGltZSA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHVwZGF0ZURhdGUobmV3VmFsdWU6IE1vbWVudCB8IG51bGwpIHtcbiAgICAgICAgaWYgKCFtb21lbnQuaXNNb21lbnQobmV3VmFsdWUpIHx8ICFtb21lbnQobmV3VmFsdWUpLmlzVmFsaWQoKSkge1xuICAgICAgICAgICAgLy8gVE9ETzogUmVwbGFjZSB3aXRoIHVuZGVmaW5lZFxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgdGhpcy5fbW9kZWwgPSBudWxsO1xuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgdGhpcy5kYXRlID0gbnVsbDtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEluIGNhc2UgJ2RhdGUnIGlzIG5vdCBzZXQsIHRoaXMuX21vZGVsIGlzIHNldCBmcm9tICd0aW1lJyBtb2RlbCBpZiAndGltZScgbW9kZWwgZXhpc3RzXG4gICAgICAgIHRoaXMuX21vZGVsID0gdGhpcy5fbW9kZWwgfHwgKHRoaXMudGltZSAmJiB0aGlzLnRpbWUuY2xvbmUoKSk7XG4gICAgICAgIGlmICh0aGlzLl9tb2RlbCkge1xuICAgICAgICAgICAgdGhpcy5fbW9kZWwuc2V0KHtcbiAgICAgICAgICAgICAgICB5ZWFyOiBuZXdWYWx1ZS55ZWFyKCksXG4gICAgICAgICAgICAgICAgbW9udGg6IG5ld1ZhbHVlLm1vbnRoKCksXG4gICAgICAgICAgICAgICAgZGF0ZTogbmV3VmFsdWUuZGF0ZSgpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmRhdGUgPSBuZXdWYWx1ZS5jbG9uZSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlVGltZShuZXdWYWx1ZTogTW9tZW50KSB7XG4gICAgICAgIGlmICghbW9tZW50LmlzTW9tZW50KG5ld1ZhbHVlKSkge1xuICAgICAgICAgICAgLy8gVE9ETzogUmVwbGFjZSB3aXRoIHVuZGVmaW5lZFxuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgdGhpcy5fbW9kZWwgPSBudWxsO1xuICAgICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgICAgdGhpcy50aW1lID0gbnVsbDtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEluIGNhc2UgJ3RpbWUnIGlzIG5vdCBzZXQsIHRoaXMuX21vZGVsIGlzIHNldCBmcm9tICdkYXRlJyBtb2RlbCBpZiAnZGF0ZScgbW9kZWwgZXhpc3RzXG4gICAgICAgIHRoaXMuX21vZGVsID0gdGhpcy5fbW9kZWwgfHwgKHRoaXMuZGF0ZSAmJiB0aGlzLmRhdGUuY2xvbmUoKSk7XG4gICAgICAgIGlmICh0aGlzLl9tb2RlbCkge1xuICAgICAgICAgICAgdGhpcy5fbW9kZWwuc2V0KHtcbiAgICAgICAgICAgICAgICBob3VyczogbmV3VmFsdWUuaG91cnMoKSxcbiAgICAgICAgICAgICAgICBtaW51dGVzOiBuZXdWYWx1ZS5taW51dGVzKCksXG4gICAgICAgICAgICAgICAgc2Vjb25kczogbmV3VmFsdWUuc2Vjb25kcygpLFxuICAgICAgICAgICAgICAgIG1pbGxpc2Vjb25kczogbmV3VmFsdWUubWlsbGlzZWNvbmQoKSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50aW1lID0gbmV3VmFsdWUuY2xvbmUoKTtcbiAgICB9XG59XG4iLCI8ZGl2XG4gICAgI251aURhdGV0aW1lUGlja2VyXG4gICAgY2xhc3M9XCJudWktZGF0ZXRpbWUtcGlja2VyXCJcbiAgICBbYXR0ci5hcmlhLWxhYmVsXT1cImFyaWFMYWJlbFwiXG4+XG4gICAgPGRpdiBjbGFzcz1cIm51aS1kYXRldGltZS1waWNrZXJfX2dyb3VwXCI+XG4gICAgICAgIDxudWktZGF0ZS1waWNrZXJcbiAgICAgICAgICAgIGNsYXNzPVwibnVpLWRhdGVwaWNrZXItLWp1c3RpZmllZFwiXG4gICAgICAgICAgICBbdmFsdWVdPVwiZGF0ZVwiXG4gICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwib25EYXRlQ2hhbmdlZCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChpbnB1dEJsdXJyZWQpPVwib25JbnB1dEJsdXJyZWQoKVwiXG4gICAgICAgICAgICBbbWF4RGF0ZV09XCJtYXhEYXRlXCJcbiAgICAgICAgICAgIFttaW5EYXRlXT1cIm1pbkRhdGVcIlxuICAgICAgICAgICAgW2lzRGlzYWJsZWRdPVwiaXNEaXNhYmxlZFwiXG4gICAgICAgICAgICBbaXNJbkVycm9yU3RhdGVdPVwiaXNJbkVycm9yU3RhdGVEYXRlXCJcbiAgICAgICAgICAgIFtoYW5kbGVUaW1lem9uZV09XCJoYW5kbGVUaW1lem9uZVwiXG4gICAgICAgICAgICBbYXBwZW5kVG9Cb2R5XT1cImFwcGVuZFRvQm9keVwiXG4gICAgICAgICAgICBbYXJpYUxhYmVsXT1cImFyaWFMYWJlbCArICcgZGF0ZSdcIlxuICAgICAgICA+PC9udWktZGF0ZS1waWNrZXI+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cIm51aS1kYXRldGltZS1waWNrZXJfX2dyb3VwIG51aS1kYXRldGltZS1waWNrZXJfX2dyb3VwLS1sYXN0XCI+XG4gICAgICAgIDxudWktdGltZS1waWNrZXJcbiAgICAgICAgICAgIGNsYXNzPVwibnVpLWRyb3Bkb3duLS1qdXN0aWZpZWRcIlxuICAgICAgICAgICAgW2luaXRFbXB0eV09XCJpbml0RW1wdHlcIlxuICAgICAgICAgICAgW21vZGVsXT1cInRpbWVcIlxuICAgICAgICAgICAgKHRpbWVDaGFuZ2VkKT1cIm9uVGltZUNoYW5nZWQoJGV2ZW50KVwiXG4gICAgICAgICAgICAoaW5wdXRCbHVycmVkKT1cIm9uSW5wdXRCbHVycmVkKClcIlxuICAgICAgICAgICAgW2lzRGlzYWJsZWRdPVwiaXNEaXNhYmxlZFwiXG4gICAgICAgICAgICBbaXNJbkVycm9yU3RhdGVdPVwiaXNJbkVycm9yU3RhdGVUaW1lXCJcbiAgICAgICAgICAgIFthcHBlbmRUb0JvZHldPVwiYXBwZW5kVG9Cb2R5XCJcbiAgICAgICAgICAgIFthcmlhTGFiZWxdPVwiYXJpYUxhYmVsICsgJyB0aW1lJ1wiXG4gICAgICAgID48L251aS10aW1lLXBpY2tlcj5cbiAgICA8L2Rpdj5cbjwvZGl2PlxuIl19