@elderbyte/ngx-starter 18.9.0 → 18.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/common/time/public_api.mjs +3 -1
- package/esm2022/lib/common/time/temporal-plain-date-interval.mjs +34 -0
- package/esm2022/lib/common/time/temporal-util.mjs +187 -0
- package/esm2022/lib/components/errors/error-util.mjs +2 -2
- package/esm2022/lib/components/time/elder-interval-input/elder-interval-input.component.mjs +13 -4
- package/esm2022/lib/components/time/elder-interval-picker/elder-interval-picker-binding.directive.mjs +45 -0
- package/esm2022/lib/components/time/elder-interval-picker/elder-interval-picker-toggle/elder-interval-picker-toggle.component.mjs +203 -0
- package/esm2022/lib/components/time/elder-interval-picker/elder-interval-picker.component.mjs +269 -0
- package/esm2022/lib/components/time/elder-interval-picker/elder-interval-picker.service.mjs +703 -0
- package/esm2022/lib/components/time/elder-time.module.mjs +22 -2
- package/fesm2022/elderbyte-ngx-starter.mjs +1791 -376
- package/fesm2022/elderbyte-ngx-starter.mjs.map +1 -1
- package/lib/common/time/public_api.d.ts +2 -0
- package/lib/common/time/temporal-plain-date-interval.d.ts +15 -0
- package/lib/common/time/temporal-util.d.ts +34 -0
- package/lib/components/time/elder-interval-input/elder-interval-input.component.d.ts +4 -1
- package/lib/components/time/elder-interval-picker/elder-interval-picker-binding.directive.d.ts +30 -0
- package/lib/components/time/elder-interval-picker/elder-interval-picker-toggle/elder-interval-picker-toggle.component.d.ts +48 -0
- package/lib/components/time/elder-interval-picker/elder-interval-picker.component.d.ts +73 -0
- package/lib/components/time/elder-interval-picker/elder-interval-picker.service.d.ts +130 -0
- package/lib/components/time/elder-time.module.d.ts +8 -2
- package/package.json +4 -2
- package/src/assets/i18n/de.json +137 -0
- package/src/assets/i18n/en.json +123 -0
- package/src/lib/components/time/elder-interval-picker/elder-interval-picker.component.scss +36 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { ChangeDetectionStrategy, Component, effect, ElementRef, EventEmitter, input, Input, Output, ViewChild, } from '@angular/core';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
5
|
+
import { DateAdapter } from '@angular/material/core';
|
|
6
|
+
import { MatCalendar, MatDatepickerModule, MatDatepickerToggle, MatDateRangeInput, MatDateRangePicker } from '@angular/material/datepicker';
|
|
7
|
+
import { MatFormFieldModule, MatHint, MatLabel, } from '@angular/material/form-field';
|
|
8
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
9
|
+
import { MatInputModule } from '@angular/material/input';
|
|
10
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
11
|
+
import { MatTooltip } from '@angular/material/tooltip';
|
|
12
|
+
import { LoggerFactory } from '@elderbyte/ts-logger';
|
|
13
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
14
|
+
import { TemporalUtil } from '../../../common/time/temporal-util';
|
|
15
|
+
import { CustomDateAdapter } from '../../../components/time/date-adapters/custom-date-adapter';
|
|
16
|
+
import { ElderLocalDateInputComponent } from '../../../components/time/elder-local-date-input/elder-local-date-input.component';
|
|
17
|
+
import { ElderIntervalPickerService } from './elder-interval-picker.service';
|
|
18
|
+
import * as i0 from "@angular/core";
|
|
19
|
+
import * as i1 from "./elder-interval-picker.service";
|
|
20
|
+
import * as i2 from "@angular/material/datepicker";
|
|
21
|
+
import * as i3 from "@angular/material/form-field";
|
|
22
|
+
import * as i4 from "@angular/material/input";
|
|
23
|
+
import * as i5 from "@angular/common";
|
|
24
|
+
import * as i6 from "@angular/material/icon";
|
|
25
|
+
import * as i7 from "@angular/forms";
|
|
26
|
+
import * as i8 from "@angular/material/button";
|
|
27
|
+
import * as i9 from "@ngx-translate/core";
|
|
28
|
+
import * as i10 from "@angular/material/menu";
|
|
29
|
+
export class ElderIntervalPickerComponent {
|
|
30
|
+
/***************************************************************************
|
|
31
|
+
* *
|
|
32
|
+
* Constructor *
|
|
33
|
+
* *
|
|
34
|
+
**************************************************************************/
|
|
35
|
+
constructor(svc) {
|
|
36
|
+
this.svc = svc;
|
|
37
|
+
/***************************************************************************
|
|
38
|
+
* *
|
|
39
|
+
* Fields *
|
|
40
|
+
* *
|
|
41
|
+
**************************************************************************/
|
|
42
|
+
this.log = LoggerFactory.getLogger(this.constructor.name);
|
|
43
|
+
this.calendarAnchorDateCssClassFn = (cellDate, view) => {
|
|
44
|
+
return this.calendarAnchorDateCssClassFnBody(cellDate, view);
|
|
45
|
+
};
|
|
46
|
+
this.isEmittingOnChange = true;
|
|
47
|
+
this.intervalInputMode = 'date-range';
|
|
48
|
+
this.showAnchor = false;
|
|
49
|
+
this.isAnchorReadOnly = false;
|
|
50
|
+
this.isResultTextVisible = true;
|
|
51
|
+
this.isHelpTextsVisible = false;
|
|
52
|
+
this.dateChange = new EventEmitter();
|
|
53
|
+
this.inputInterval = input(null);
|
|
54
|
+
this.inputAnchorDateTime = input(null);
|
|
55
|
+
/***************************************************************************
|
|
56
|
+
* *
|
|
57
|
+
* Effects *
|
|
58
|
+
* *
|
|
59
|
+
**************************************************************************/
|
|
60
|
+
this._updateMatCalendarElAnchorCssClassEffect = effect(() => {
|
|
61
|
+
const anchorDate = this.svc.anchorDate();
|
|
62
|
+
if (anchorDate) {
|
|
63
|
+
this.calendarStart.updateTodaysDate();
|
|
64
|
+
this.calendarEnd.updateTodaysDate();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
this._updateMatCalendarElSelectionEffect = effect(() => {
|
|
68
|
+
const startDate = this.svc.startDate();
|
|
69
|
+
const endDate = this.svc.endDate();
|
|
70
|
+
if (!this.calendarStart || !this.calendarEnd) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (!startDate && !endDate) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const calendar1 = this.calendarStart;
|
|
77
|
+
const calendar2 = this.calendarEnd;
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
// timeout is needed to run run calendar update last, otherwise there are issues
|
|
80
|
+
if (startDate) {
|
|
81
|
+
const startJsDate = TemporalUtil.getJSDateFromPlainDateTime(startDate);
|
|
82
|
+
calendar1.activeDate = startJsDate;
|
|
83
|
+
}
|
|
84
|
+
if (endDate) {
|
|
85
|
+
const endJsDate = TemporalUtil.getJSDateFromPlainDateTime(endDate);
|
|
86
|
+
calendar2.activeDate = endJsDate;
|
|
87
|
+
}
|
|
88
|
+
}, 0);
|
|
89
|
+
});
|
|
90
|
+
this.svc.setupInputInterval(this.inputInterval);
|
|
91
|
+
this.svc.setupInputAnchorDateTime(this.inputAnchorDateTime);
|
|
92
|
+
this.svc.setupEventEmitter(this.dateChange);
|
|
93
|
+
}
|
|
94
|
+
/***************************************************************************
|
|
95
|
+
* *
|
|
96
|
+
* Life Cycle *
|
|
97
|
+
* *
|
|
98
|
+
**************************************************************************/
|
|
99
|
+
ngOnInit() {
|
|
100
|
+
if (this.inputInterval) {
|
|
101
|
+
this.svc.pullInputInterval();
|
|
102
|
+
}
|
|
103
|
+
if (this.inputAnchorDateTime()) {
|
|
104
|
+
this.svc.pullInputAnchorDateTime();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
ngAfterViewInit() {
|
|
108
|
+
this.svc.isEmittingOnChange.set(this.isEmittingOnChange);
|
|
109
|
+
this.setupDateInputCalendarFocusPrevention();
|
|
110
|
+
}
|
|
111
|
+
ngOnDestroy() {
|
|
112
|
+
this.removeEventListeners();
|
|
113
|
+
}
|
|
114
|
+
/***************************************************************************
|
|
115
|
+
* *
|
|
116
|
+
* Public API *
|
|
117
|
+
* *
|
|
118
|
+
**************************************************************************/
|
|
119
|
+
setupDateInputCalendarFocusPrevention() {
|
|
120
|
+
// Prevents the focus on the calendar when the input field is changed via the keyboard
|
|
121
|
+
this.calendarElFocusEventHandler = (event) => {
|
|
122
|
+
if (!event || !event.relatedTarget) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
const relTarget = event.relatedTarget;
|
|
127
|
+
if (relTarget.name === 'startDateInput') {
|
|
128
|
+
this.startDateInput.nativeElement.focus();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (relTarget.name === 'endDateInput') {
|
|
132
|
+
this.endDateInput.nativeElement.focus();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const nativeElementStart = this.calendarStartElRef.nativeElement;
|
|
137
|
+
const nativeElementEnd = this.calendarEndElRef.nativeElement;
|
|
138
|
+
nativeElementStart.addEventListener('focus', this.calendarElFocusEventHandler, true);
|
|
139
|
+
nativeElementEnd.addEventListener('focus', this.calendarElFocusEventHandler, true);
|
|
140
|
+
}
|
|
141
|
+
clearStartDateTime() {
|
|
142
|
+
this.svc.clearStartDateTime();
|
|
143
|
+
this.svc.resetCalendarMode();
|
|
144
|
+
if (this.isEmittingOnChange) {
|
|
145
|
+
this.svc.emitMainDates();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
clearEndDateTime() {
|
|
149
|
+
this.svc.clearEndDateTime();
|
|
150
|
+
this.svc.resetCalendarMode();
|
|
151
|
+
if (this.isEmittingOnChange) {
|
|
152
|
+
this.svc.emitMainDates();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
clearStartAndEndDateTimes() {
|
|
156
|
+
this.svc.clearStartDateTime();
|
|
157
|
+
this.svc.clearEndDateTime();
|
|
158
|
+
this.svc.resetCalendarMode();
|
|
159
|
+
if (this.isEmittingOnChange) {
|
|
160
|
+
this.svc.emitMainDates();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
handleStartCalendarChange(changedDate) {
|
|
164
|
+
this.svc.calendarMode.set('days');
|
|
165
|
+
const newPlainDate = TemporalUtil.getPlainDateFromJSDate(changedDate);
|
|
166
|
+
this.svc.startDate.set(newPlainDate);
|
|
167
|
+
}
|
|
168
|
+
handleEndCalendarChange(changedDate) {
|
|
169
|
+
this.svc.calendarMode.set('days');
|
|
170
|
+
const newPlainDate = TemporalUtil.getPlainDateFromJSDate(changedDate);
|
|
171
|
+
this.svc.endDate.set(newPlainDate);
|
|
172
|
+
}
|
|
173
|
+
/***************************************************************************
|
|
174
|
+
* *
|
|
175
|
+
* Private methods *
|
|
176
|
+
* *
|
|
177
|
+
**************************************************************************/
|
|
178
|
+
removeEventListeners() {
|
|
179
|
+
if (!this.calendarStartElRef || !this.calendarEndElRef) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (!this.calendarStartElRef.nativeElement || !this.calendarEndElRef.nativeElement) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const nativeElementStart = this.calendarStartElRef.nativeElement;
|
|
186
|
+
const nativeElementEnd = this.calendarEndElRef.nativeElement;
|
|
187
|
+
nativeElementStart.removeEventListener('focus', this.calendarElFocusEventHandler, true);
|
|
188
|
+
nativeElementEnd.removeEventListener('focus', this.calendarElFocusEventHandler, true);
|
|
189
|
+
}
|
|
190
|
+
calendarAnchorDateCssClassFnBody(cellDate, view) {
|
|
191
|
+
const anchorDate = this.svc.fixedAnchorDate();
|
|
192
|
+
if (!anchorDate) {
|
|
193
|
+
return '';
|
|
194
|
+
}
|
|
195
|
+
const date = TemporalUtil.getJSDateFromPlainDateTime(anchorDate);
|
|
196
|
+
if (!date) {
|
|
197
|
+
return '';
|
|
198
|
+
}
|
|
199
|
+
if (cellDate.getDate() === date.getDate() &&
|
|
200
|
+
cellDate.getMonth() === date.getMonth() &&
|
|
201
|
+
cellDate.getFullYear() === date.getFullYear()) {
|
|
202
|
+
return 'elder-custom-anchor-date';
|
|
203
|
+
}
|
|
204
|
+
return '';
|
|
205
|
+
}
|
|
206
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: ElderIntervalPickerComponent, deps: [{ token: i1.ElderIntervalPickerService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
207
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.2", type: ElderIntervalPickerComponent, isStandalone: true, selector: "elder-interval-picker", inputs: { isEmittingOnChange: { classPropertyName: "isEmittingOnChange", publicName: "isEmittingOnChange", isSignal: false, isRequired: false, transformFunction: null }, intervalInputMode: { classPropertyName: "intervalInputMode", publicName: "intervalInputMode", isSignal: false, isRequired: false, transformFunction: null }, showAnchor: { classPropertyName: "showAnchor", publicName: "showAnchor", isSignal: false, isRequired: false, transformFunction: null }, isAnchorReadOnly: { classPropertyName: "isAnchorReadOnly", publicName: "isAnchorReadOnly", isSignal: false, isRequired: false, transformFunction: null }, isResultTextVisible: { classPropertyName: "isResultTextVisible", publicName: "isResultTextVisible", isSignal: false, isRequired: false, transformFunction: null }, isHelpTextsVisible: { classPropertyName: "isHelpTextsVisible", publicName: "isHelpTextsVisible", isSignal: false, isRequired: false, transformFunction: null }, inputInterval: { classPropertyName: "inputInterval", publicName: "inputInterval", isSignal: true, isRequired: false, transformFunction: null }, inputAnchorDateTime: { classPropertyName: "inputAnchorDateTime", publicName: "inputAnchorDateTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateChange: "dateChange" }, providers: [
|
|
208
|
+
ElderIntervalPickerService,
|
|
209
|
+
{ provide: DateAdapter, useClass: CustomDateAdapter },
|
|
210
|
+
], viewQueries: [{ propertyName: "calendarStart", first: true, predicate: ["rangeCalendarStart"], descendants: true }, { propertyName: "calendarEnd", first: true, predicate: ["rangeCalendarEnd"], descendants: true }, { propertyName: "calendarStartElRef", first: true, predicate: ["rangeCalendarStart"], descendants: true, read: ElementRef }, { propertyName: "calendarEndElRef", first: true, predicate: ["rangeCalendarEnd"], descendants: true, read: ElementRef }, { propertyName: "startDateInput", first: true, predicate: ["startDateInput"], descendants: true }, { propertyName: "endDateInput", first: true, predicate: ["endDateInput"], descendants: true }], ngImport: i0, template: "<div class=\"interval-picker-component p-md layout-col gap-xxl\">\n <div class=\"layout-row gap-xxl place-between-start\" style=\"gap: 5%\">\n <div class=\"layout-col gap-md pt-xs\">\n <ng-container *ngTemplateOutlet=\"intervalSelector\"></ng-container>\n </div>\n <div class=\"layout-col\">\n <!-- smart shift -->\n <div class=\"layout-row place-around-center\">\n <button mat-icon-button (click)=\"svc.smartShift(-1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ svc.viewIntervalMessage() }}</span>\n <button mat-icon-button (click)=\"svc.smartShift(1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <!-- calendars and input controls -->\n <ng-container *ngTemplateOutlet=\"calendarsTemplate\"></ng-container>\n </div>\n <div class=\"pt-xs\" style=\"width: 25%\">\n <div class=\"layout-col gap-lg\">\n <div class=\"layout-col gap-xs place-start-start\">\n @if (isHelpTextsVisible) {\n <h5 class=\"mat-h5\">{{ \"intervalPicker.selectSmartInterval\" | translate }}</h5>\n }\n <!-- select current -->\n <button mat-button (click)=\"svc.selectCurrentWeek()\">\n {{ \"intervalPicker.currentPeriod.week\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectCurrentMonth()\">\n {{ \"intervalPicker.currentPeriod.month\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectCurrentQuarter()\">\n {{ \"intervalPicker.currentPeriod.quarter\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectCurrentYear()\">\n {{ \"intervalPicker.currentPeriod.year\" | translate }}\n </button>\n </div>\n <div class=\"fixed-shifts-container\">\n <ng-container *ngTemplateOutlet=\"fixedShifts\"></ng-container>\n </div>\n </div>\n </div>\n </div>\n <div class=\"layout-row place-between-center gap-xxl pt-sm\">\n <div>\n @if (showAnchor) {\n <ng-container *ngTemplateOutlet=\"anchorInputField\"></ng-container>\n }\n </div>\n @if (isResultTextVisible) {\n <!-- result interval -->\n <div class=\"layout-col place-center-center\">\n <div class=\"date-interval mat-caption pt-xs\">\n @if (svc.startDateTimeAsJSDate()) {\n {{ svc.startDateTimeAsJSDate() | date : \"dd.MM. y, HH:mm:ss\" }}\n } @else {\n {{ \"intervalPicker.startDateNotSet\" | translate }}\n }\n <span> - </span>\n @if (svc.endDateTimeAsJSDate()) {\n {{ svc.endDateTimeAsJSDate() | date : \"dd.MM. y, HH:mm:ss\" }}\n } @else {\n {{ \"intervalPicker.endDateNotSet\" | translate }}\n }\n </div>\n <div>\n <span class=\"mat-caption\">{{ svc.deltaHumanReadable() || \" \" }}</span>\n </div>\n </div>\n }\n <div class=\"layout-row gap-lg\">\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"clearStartAndEndDateTimes()\"\n [disabled]=\"svc.isStartAndEndDatesEmpty()\"\n >\n {{ \"intervalPicker.clear\" | translate }}\n </button>\n\n @if(!this.isEmittingOnChange) {\n <button color=\"primary\" mat-raised-button (click)=\"svc.emitMainDates()\">\n {{ \"actions.ok\" | translate }}\n </button>\n }\n </div>\n </div>\n</div>\n\n<ng-template #intervalSelector>\n <div class=\"layout-col\">\n @if (isHelpTextsVisible) {\n <h5 class=\"mat-h5\">{{ \"intervalPicker.selectAbsoluteInterval\" | translate }}</h5>\n }\n <div class=\"layout-row select-buttons-container gap-sm\">\n <div class=\"layout-col gap-xs place-start-stretch\">\n <button mat-button (click)=\"svc.selectCurrentDay()\">\n @if(svc.isFixedAnchorDateSet()) {\n {{ \"intervalPicker.anchorDay\" | translate }}\n } @else {\n {{ \"intervalPicker.today\" | translate }}\n }\n </button>\n <button mat-button (click)=\"svc.selectYesterday()\">\n @if (svc.isFixedAnchorDateSet()) {\n {{ \"intervalPicker.last\" | translate }} 1 {{ \"intervalPicker.day\" | translate }}\n } @else {\n {{ \"intervalPicker.yesterday\" | translate }}\n }\n </button>\n <button mat-button (click)=\"svc.selectLastSevenDays()\">\n {{ \"intervalPicker.last\" | translate }} 7 {{ \"intervalPicker.days\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectLastThirtyDays()\">\n {{ \"intervalPicker.last\" | translate }} 30 {{ \"intervalPicker.days\" | translate }}\n </button>\n @if (intervalInputMode === 'date-time-range') {\n <div class=\"pt-sm\"></div>\n <button mat-button (click)=\"svc.selectLastFiveMinutes()\">\n {{ \"intervalPicker.last\" | translate }} 5 {{ \"intervalPicker.minutes\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectLastHour()\">\n {{ \"intervalPicker.last\" | translate }} {{ \"intervalPicker.hour\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectLast24Hours()\">\n {{ \"intervalPicker.last\" | translate }} 24 {{ \"intervalPicker.hours\" | translate }}\n </button>\n }\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #calendarsTemplate>\n <div class=\"layout-row place-around-center\" style=\"align-items: flex-start; min-height: 280px\">\n <mat-calendar\n #rangeCalendarStart\n style=\"width: 210px; max-width: 100%\"\n [selected]=\"svc.dateRangeForCalendar()\"\n (selectedChange)=\"handleStartCalendarChange($event)\"\n [maxDate]=\"svc.endDateAsJSDate()\"\n [dateClass]=\"calendarAnchorDateCssClassFn\"\n >\n </mat-calendar>\n <mat-calendar\n #rangeCalendarEnd\n style=\"width: 210px; max-width: 100%\"\n [selected]=\"svc.dateRangeForCalendar()\"\n (selectedChange)=\"handleEndCalendarChange($event)\"\n [minDate]=\"svc.startDateAsJSDate()\"\n [dateClass]=\"calendarAnchorDateCssClassFn\"\n >\n </mat-calendar>\n </div>\n <div class=\"layout-row place-around-center gap-xl pt-sm\">\n <div class=\"layout-row place-around-center\">\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.startDate\" | translate }}</mat-label>\n <input\n #startDateInput\n name=\"startDateInput\"\n matInput\n type=\"date\"\n [ngModel]=\"svc.startDateHtmlString()\"\n (ngModelChange)=\"svc.setStartDateFromHtmlString($event)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.clearStartDateTime()\"\n [disabled]=\"!this.svc.startDate()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </div>\n <div class=\"layout-row place-around-center\">\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.endDate\" | translate }}</mat-label>\n <input\n #endDateInput\n name=\"endDateInput\"\n matInput\n type=\"date\"\n [ngModel]=\"svc.endDateHtmlString()\"\n (ngModelChange)=\"svc.setEndDateFromHtmlString($event)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.clearEndDateTime()\"\n [disabled]=\"!this.svc.endDate()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n <br />\n @if (intervalInputMode === 'date-time-range') {\n <div class=\"layout-row place-around-center gap-xl pt-sm\">\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.startTime\" | translate }}</mat-label>\n <input\n name=\"startTimeInput\"\n matInput\n type=\"time\"\n #startTimeControl=\"ngModel\"\n step=\"1\"\n [ngModel]=\"svc.getStartTimeString()\"\n (ngModelChange)=\"svc.setStartTimeFromString($event, startTimeControl)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.svc.clearStartTime()\"\n [disabled]=\"!this.svc.isStartTimeSetAndNotMidnight()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.endTime\" | translate }}</mat-label>\n <input\n name=\"endTimeInput\"\n matInput\n type=\"time\"\n #endTimeControl=\"ngModel\"\n step=\"1\"\n [ngModel]=\"svc.getEndTimeString()\"\n (ngModelChange)=\"svc.setEndTimeFromString($event, endTimeControl)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.svc.clearEndTime()\"\n [disabled]=\"!this.svc.isEndTimeSetAndNotMidnight()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </div>\n }\n</ng-template>\n\n<ng-template #fixedShifts>\n @if (isHelpTextsVisible) {\n <h5 class=\"mat-h5\">{{ \"intervalPicker.shiftInterval\" | translate }}</h5>\n }\n <div class=\"layout-col place-start-stretch\">\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftDay(-1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.day\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftDay(1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftMonth(-1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.month\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftMonth(1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftYear(-1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.year\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftYear(1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n\n @if (intervalInputMode === 'date-time-range') {\n <!-- shift minute -->\n <div class=\"layout-row place-between-center\">\n <button\n mat-icon-button\n (click)=\"svc.shiftTime(-1, 'minutes')\"\n [disabled]=\"svc.isRangeNotSet()\"\n >\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.minute\" | translate }}</span>\n <button\n mat-icon-button\n (click)=\"svc.shiftTime(1, 'minutes')\"\n [disabled]=\"svc.isRangeNotSet()\"\n >\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <!-- shift hour -->\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftTime(-1, 'hours')\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.hour\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftTime(1, 'hours')\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #anchorInputField>\n <div class=\"layout-row flex-none gap-md\">\n <mat-menu #anchorMenu=\"matMenu\">\n @if (svc.startDate()) {\n <button\n mat-menu-item\n (click)=\"svc.setFixedAnchorPointToEndDateTime()\"\n [disabled]=\"!svc.endDate()\"\n >\n <mat-icon class=\"material-symbols-outlined\">login</mat-icon>\n <span>{{ \"intervalPicker.endDate\" | translate }}</span>\n </button>\n } @if (svc.endDate()) {\n <button\n mat-menu-item\n (click)=\"svc.setFixedAnchorPointToStartDateTime()\"\n [disabled]=\"!svc.startDate()\"\n >\n <mat-icon class=\"material-symbols-outlined\">logout</mat-icon>\n <span>{{ \"intervalPicker.startDate\" | translate }}</span>\n </button>\n } @if (svc.fixedAnchorDate()) {\n <button\n mat-menu-item\n (click)=\"this.svc.resetFixedAnchorPoint()\"\n [disabled]=\"!svc.fixedAnchorDate() || isAnchorReadOnly\"\n >\n <mat-icon>close</mat-icon>\n <span>{{ \"intervalPicker.clear\" | translate }}</span>\n </button>\n }\n </mat-menu>\n\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.anchorDate\" | translate }}</mat-label>\n <elder-local-date-input\n name=\"anchorDateInput\"\n (valueUpdated)=\"svc.setAnchorDateFromForm($event)\"\n [value]=\"svc.getAnchorPointAsLocaleDate()\"\n [readonly]=\"isAnchorReadOnly\"\n >\n </elder-local-date-input>\n @if (!isAnchorReadOnly) {\n <button\n mat-icon-button\n matSuffix\n [matMenuTriggerFor]=\"anchorMenu\"\n [disabled]=\"svc.isStartAndEndDatesEmpty() && !svc.fixedAnchorDate()\"\n >\n <mat-icon class=\"material-symbols-outlined\">more_horiz</mat-icon>\n </button>\n }\n </mat-form-field>\n @if (intervalInputMode === 'date-time-range') {\n <mat-form-field class=\"input-control-container-short\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.anchorTime\" | translate }}</mat-label>\n <input\n matInput\n name=\"anchorTimeInput\"\n type=\"time\"\n #anchorTimeControl=\"ngModel\"\n step=\"1\"\n [readonly]=\"isAnchorReadOnly\"\n [ngModel]=\"svc.getAnchorTimeString()\"\n (ngModelChange)=\"svc.setAnchorTimeFromForm($event)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.svc.resetFixedAnchorTime()\"\n [disabled]=\"!svc.isFixedAnchorTimeSetAndNotMidnight() || isAnchorReadOnly\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n }\n </div>\n</ng-template>\n", styles: [".interval-picker-component{min-width:840px;max-width:100%}.fixed-shifts-container{max-width:160px}.input-control-container{width:192px;max-width:100%}.input-control-container-short{width:140px;max-width:100%}.select-buttons-container button{white-space:nowrap;text-align:left;justify-content:flex-start}::ng-deep .interval-picker-component .mat-calendar-body-cell.elder-custom-anchor-date .mat-calendar-body-cell-content{border-radius:50%;background-color:#def;background-color:#b4d2ebbf}\n"], dependencies: [{ kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i2.MatCalendar, selector: "mat-calendar", inputs: ["headerComponent", "startAt", "startView", "selected", "minDate", "maxDate", "dateFilter", "dateClass", "comparisonStart", "comparisonEnd", "startDateAccessibleName", "endDateAccessibleName"], outputs: ["selectedChange", "yearSelected", "monthSelected", "viewChanged", "_userSelection", "_userDragDrop"], exportAs: ["matCalendar"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i5.DatePipe, name: "date" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i7.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: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i8.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i8.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: ElderLocalDateInputComponent, selector: "elder-local-date-input", inputs: ["zone", "autoDatePicker", "arrows", "today", "center", "datePickerTouchUi", "allowNull", "datePickerEnabled", "isoValue", "dateValue", "isoDateValue"], outputs: ["blurred", "valueUpdatedBlur", "isoValueChange", "dateValueChange", "isoDateValueChange"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i9.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i10.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i10.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i10.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
211
|
+
}
|
|
212
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.2", ngImport: i0, type: ElderIntervalPickerComponent, decorators: [{
|
|
213
|
+
type: Component,
|
|
214
|
+
args: [{ selector: 'elder-interval-picker', standalone: true, imports: [
|
|
215
|
+
MatDateRangePicker,
|
|
216
|
+
MatDatepickerModule,
|
|
217
|
+
MatDateRangeInput,
|
|
218
|
+
MatFormFieldModule,
|
|
219
|
+
MatLabel,
|
|
220
|
+
MatHint,
|
|
221
|
+
MatDatepickerToggle,
|
|
222
|
+
MatInputModule,
|
|
223
|
+
CommonModule,
|
|
224
|
+
MatIconModule,
|
|
225
|
+
FormsModule,
|
|
226
|
+
MatButtonModule,
|
|
227
|
+
MatCalendar,
|
|
228
|
+
ElderLocalDateInputComponent,
|
|
229
|
+
MatTooltip,
|
|
230
|
+
TranslateModule,
|
|
231
|
+
MatMenuModule,
|
|
232
|
+
], providers: [
|
|
233
|
+
ElderIntervalPickerService,
|
|
234
|
+
{ provide: DateAdapter, useClass: CustomDateAdapter },
|
|
235
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"interval-picker-component p-md layout-col gap-xxl\">\n <div class=\"layout-row gap-xxl place-between-start\" style=\"gap: 5%\">\n <div class=\"layout-col gap-md pt-xs\">\n <ng-container *ngTemplateOutlet=\"intervalSelector\"></ng-container>\n </div>\n <div class=\"layout-col\">\n <!-- smart shift -->\n <div class=\"layout-row place-around-center\">\n <button mat-icon-button (click)=\"svc.smartShift(-1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ svc.viewIntervalMessage() }}</span>\n <button mat-icon-button (click)=\"svc.smartShift(1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <!-- calendars and input controls -->\n <ng-container *ngTemplateOutlet=\"calendarsTemplate\"></ng-container>\n </div>\n <div class=\"pt-xs\" style=\"width: 25%\">\n <div class=\"layout-col gap-lg\">\n <div class=\"layout-col gap-xs place-start-start\">\n @if (isHelpTextsVisible) {\n <h5 class=\"mat-h5\">{{ \"intervalPicker.selectSmartInterval\" | translate }}</h5>\n }\n <!-- select current -->\n <button mat-button (click)=\"svc.selectCurrentWeek()\">\n {{ \"intervalPicker.currentPeriod.week\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectCurrentMonth()\">\n {{ \"intervalPicker.currentPeriod.month\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectCurrentQuarter()\">\n {{ \"intervalPicker.currentPeriod.quarter\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectCurrentYear()\">\n {{ \"intervalPicker.currentPeriod.year\" | translate }}\n </button>\n </div>\n <div class=\"fixed-shifts-container\">\n <ng-container *ngTemplateOutlet=\"fixedShifts\"></ng-container>\n </div>\n </div>\n </div>\n </div>\n <div class=\"layout-row place-between-center gap-xxl pt-sm\">\n <div>\n @if (showAnchor) {\n <ng-container *ngTemplateOutlet=\"anchorInputField\"></ng-container>\n }\n </div>\n @if (isResultTextVisible) {\n <!-- result interval -->\n <div class=\"layout-col place-center-center\">\n <div class=\"date-interval mat-caption pt-xs\">\n @if (svc.startDateTimeAsJSDate()) {\n {{ svc.startDateTimeAsJSDate() | date : \"dd.MM. y, HH:mm:ss\" }}\n } @else {\n {{ \"intervalPicker.startDateNotSet\" | translate }}\n }\n <span> - </span>\n @if (svc.endDateTimeAsJSDate()) {\n {{ svc.endDateTimeAsJSDate() | date : \"dd.MM. y, HH:mm:ss\" }}\n } @else {\n {{ \"intervalPicker.endDateNotSet\" | translate }}\n }\n </div>\n <div>\n <span class=\"mat-caption\">{{ svc.deltaHumanReadable() || \" \" }}</span>\n </div>\n </div>\n }\n <div class=\"layout-row gap-lg\">\n <button\n mat-raised-button\n color=\"primary\"\n (click)=\"clearStartAndEndDateTimes()\"\n [disabled]=\"svc.isStartAndEndDatesEmpty()\"\n >\n {{ \"intervalPicker.clear\" | translate }}\n </button>\n\n @if(!this.isEmittingOnChange) {\n <button color=\"primary\" mat-raised-button (click)=\"svc.emitMainDates()\">\n {{ \"actions.ok\" | translate }}\n </button>\n }\n </div>\n </div>\n</div>\n\n<ng-template #intervalSelector>\n <div class=\"layout-col\">\n @if (isHelpTextsVisible) {\n <h5 class=\"mat-h5\">{{ \"intervalPicker.selectAbsoluteInterval\" | translate }}</h5>\n }\n <div class=\"layout-row select-buttons-container gap-sm\">\n <div class=\"layout-col gap-xs place-start-stretch\">\n <button mat-button (click)=\"svc.selectCurrentDay()\">\n @if(svc.isFixedAnchorDateSet()) {\n {{ \"intervalPicker.anchorDay\" | translate }}\n } @else {\n {{ \"intervalPicker.today\" | translate }}\n }\n </button>\n <button mat-button (click)=\"svc.selectYesterday()\">\n @if (svc.isFixedAnchorDateSet()) {\n {{ \"intervalPicker.last\" | translate }} 1 {{ \"intervalPicker.day\" | translate }}\n } @else {\n {{ \"intervalPicker.yesterday\" | translate }}\n }\n </button>\n <button mat-button (click)=\"svc.selectLastSevenDays()\">\n {{ \"intervalPicker.last\" | translate }} 7 {{ \"intervalPicker.days\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectLastThirtyDays()\">\n {{ \"intervalPicker.last\" | translate }} 30 {{ \"intervalPicker.days\" | translate }}\n </button>\n @if (intervalInputMode === 'date-time-range') {\n <div class=\"pt-sm\"></div>\n <button mat-button (click)=\"svc.selectLastFiveMinutes()\">\n {{ \"intervalPicker.last\" | translate }} 5 {{ \"intervalPicker.minutes\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectLastHour()\">\n {{ \"intervalPicker.last\" | translate }} {{ \"intervalPicker.hour\" | translate }}\n </button>\n <button mat-button (click)=\"svc.selectLast24Hours()\">\n {{ \"intervalPicker.last\" | translate }} 24 {{ \"intervalPicker.hours\" | translate }}\n </button>\n }\n </div>\n </div>\n </div>\n</ng-template>\n\n<ng-template #calendarsTemplate>\n <div class=\"layout-row place-around-center\" style=\"align-items: flex-start; min-height: 280px\">\n <mat-calendar\n #rangeCalendarStart\n style=\"width: 210px; max-width: 100%\"\n [selected]=\"svc.dateRangeForCalendar()\"\n (selectedChange)=\"handleStartCalendarChange($event)\"\n [maxDate]=\"svc.endDateAsJSDate()\"\n [dateClass]=\"calendarAnchorDateCssClassFn\"\n >\n </mat-calendar>\n <mat-calendar\n #rangeCalendarEnd\n style=\"width: 210px; max-width: 100%\"\n [selected]=\"svc.dateRangeForCalendar()\"\n (selectedChange)=\"handleEndCalendarChange($event)\"\n [minDate]=\"svc.startDateAsJSDate()\"\n [dateClass]=\"calendarAnchorDateCssClassFn\"\n >\n </mat-calendar>\n </div>\n <div class=\"layout-row place-around-center gap-xl pt-sm\">\n <div class=\"layout-row place-around-center\">\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.startDate\" | translate }}</mat-label>\n <input\n #startDateInput\n name=\"startDateInput\"\n matInput\n type=\"date\"\n [ngModel]=\"svc.startDateHtmlString()\"\n (ngModelChange)=\"svc.setStartDateFromHtmlString($event)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.clearStartDateTime()\"\n [disabled]=\"!this.svc.startDate()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </div>\n <div class=\"layout-row place-around-center\">\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.endDate\" | translate }}</mat-label>\n <input\n #endDateInput\n name=\"endDateInput\"\n matInput\n type=\"date\"\n [ngModel]=\"svc.endDateHtmlString()\"\n (ngModelChange)=\"svc.setEndDateFromHtmlString($event)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.clearEndDateTime()\"\n [disabled]=\"!this.svc.endDate()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </div>\n </div>\n <br />\n @if (intervalInputMode === 'date-time-range') {\n <div class=\"layout-row place-around-center gap-xl pt-sm\">\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.startTime\" | translate }}</mat-label>\n <input\n name=\"startTimeInput\"\n matInput\n type=\"time\"\n #startTimeControl=\"ngModel\"\n step=\"1\"\n [ngModel]=\"svc.getStartTimeString()\"\n (ngModelChange)=\"svc.setStartTimeFromString($event, startTimeControl)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.svc.clearStartTime()\"\n [disabled]=\"!this.svc.isStartTimeSetAndNotMidnight()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.endTime\" | translate }}</mat-label>\n <input\n name=\"endTimeInput\"\n matInput\n type=\"time\"\n #endTimeControl=\"ngModel\"\n step=\"1\"\n [ngModel]=\"svc.getEndTimeString()\"\n (ngModelChange)=\"svc.setEndTimeFromString($event, endTimeControl)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.svc.clearEndTime()\"\n [disabled]=\"!this.svc.isEndTimeSetAndNotMidnight()\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n </div>\n }\n</ng-template>\n\n<ng-template #fixedShifts>\n @if (isHelpTextsVisible) {\n <h5 class=\"mat-h5\">{{ \"intervalPicker.shiftInterval\" | translate }}</h5>\n }\n <div class=\"layout-col place-start-stretch\">\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftDay(-1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.day\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftDay(1)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftMonth(-1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.month\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftMonth(1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftYear(-1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.year\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftYear(1, true)\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n\n @if (intervalInputMode === 'date-time-range') {\n <!-- shift minute -->\n <div class=\"layout-row place-between-center\">\n <button\n mat-icon-button\n (click)=\"svc.shiftTime(-1, 'minutes')\"\n [disabled]=\"svc.isRangeNotSet()\"\n >\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.minute\" | translate }}</span>\n <button\n mat-icon-button\n (click)=\"svc.shiftTime(1, 'minutes')\"\n [disabled]=\"svc.isRangeNotSet()\"\n >\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n <!-- shift hour -->\n <div class=\"layout-row place-between-center\">\n <button mat-icon-button (click)=\"svc.shiftTime(-1, 'hours')\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_left</mat-icon>\n </button>\n <span>{{ \"intervalPicker.hour\" | translate }}</span>\n <button mat-icon-button (click)=\"svc.shiftTime(1, 'hours')\" [disabled]=\"svc.isRangeNotSet()\">\n <mat-icon>keyboard_double_arrow_right</mat-icon>\n </button>\n </div>\n }\n </div>\n</ng-template>\n\n<ng-template #anchorInputField>\n <div class=\"layout-row flex-none gap-md\">\n <mat-menu #anchorMenu=\"matMenu\">\n @if (svc.startDate()) {\n <button\n mat-menu-item\n (click)=\"svc.setFixedAnchorPointToEndDateTime()\"\n [disabled]=\"!svc.endDate()\"\n >\n <mat-icon class=\"material-symbols-outlined\">login</mat-icon>\n <span>{{ \"intervalPicker.endDate\" | translate }}</span>\n </button>\n } @if (svc.endDate()) {\n <button\n mat-menu-item\n (click)=\"svc.setFixedAnchorPointToStartDateTime()\"\n [disabled]=\"!svc.startDate()\"\n >\n <mat-icon class=\"material-symbols-outlined\">logout</mat-icon>\n <span>{{ \"intervalPicker.startDate\" | translate }}</span>\n </button>\n } @if (svc.fixedAnchorDate()) {\n <button\n mat-menu-item\n (click)=\"this.svc.resetFixedAnchorPoint()\"\n [disabled]=\"!svc.fixedAnchorDate() || isAnchorReadOnly\"\n >\n <mat-icon>close</mat-icon>\n <span>{{ \"intervalPicker.clear\" | translate }}</span>\n </button>\n }\n </mat-menu>\n\n <mat-form-field class=\"input-control-container\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.anchorDate\" | translate }}</mat-label>\n <elder-local-date-input\n name=\"anchorDateInput\"\n (valueUpdated)=\"svc.setAnchorDateFromForm($event)\"\n [value]=\"svc.getAnchorPointAsLocaleDate()\"\n [readonly]=\"isAnchorReadOnly\"\n >\n </elder-local-date-input>\n @if (!isAnchorReadOnly) {\n <button\n mat-icon-button\n matSuffix\n [matMenuTriggerFor]=\"anchorMenu\"\n [disabled]=\"svc.isStartAndEndDatesEmpty() && !svc.fixedAnchorDate()\"\n >\n <mat-icon class=\"material-symbols-outlined\">more_horiz</mat-icon>\n </button>\n }\n </mat-form-field>\n @if (intervalInputMode === 'date-time-range') {\n <mat-form-field class=\"input-control-container-short\" [subscriptSizing]=\"'dynamic'\">\n <mat-label>{{ \"intervalPicker.anchorTime\" | translate }}</mat-label>\n <input\n matInput\n name=\"anchorTimeInput\"\n type=\"time\"\n #anchorTimeControl=\"ngModel\"\n step=\"1\"\n [readonly]=\"isAnchorReadOnly\"\n [ngModel]=\"svc.getAnchorTimeString()\"\n (ngModelChange)=\"svc.setAnchorTimeFromForm($event)\"\n />\n <button\n mat-icon-button\n matSuffix\n (click)=\"this.svc.resetFixedAnchorTime()\"\n [disabled]=\"!svc.isFixedAnchorTimeSetAndNotMidnight() || isAnchorReadOnly\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </mat-form-field>\n }\n </div>\n</ng-template>\n", styles: [".interval-picker-component{min-width:840px;max-width:100%}.fixed-shifts-container{max-width:160px}.input-control-container{width:192px;max-width:100%}.input-control-container-short{width:140px;max-width:100%}.select-buttons-container button{white-space:nowrap;text-align:left;justify-content:flex-start}::ng-deep .interval-picker-component .mat-calendar-body-cell.elder-custom-anchor-date .mat-calendar-body-cell-content{border-radius:50%;background-color:#def;background-color:#b4d2ebbf}\n"] }]
|
|
236
|
+
}], ctorParameters: () => [{ type: i1.ElderIntervalPickerService }], propDecorators: { calendarStart: [{
|
|
237
|
+
type: ViewChild,
|
|
238
|
+
args: ['rangeCalendarStart']
|
|
239
|
+
}], calendarEnd: [{
|
|
240
|
+
type: ViewChild,
|
|
241
|
+
args: ['rangeCalendarEnd']
|
|
242
|
+
}], calendarStartElRef: [{
|
|
243
|
+
type: ViewChild,
|
|
244
|
+
args: ['rangeCalendarStart', { read: ElementRef }]
|
|
245
|
+
}], calendarEndElRef: [{
|
|
246
|
+
type: ViewChild,
|
|
247
|
+
args: ['rangeCalendarEnd', { read: ElementRef }]
|
|
248
|
+
}], startDateInput: [{
|
|
249
|
+
type: ViewChild,
|
|
250
|
+
args: ['startDateInput']
|
|
251
|
+
}], endDateInput: [{
|
|
252
|
+
type: ViewChild,
|
|
253
|
+
args: ['endDateInput']
|
|
254
|
+
}], isEmittingOnChange: [{
|
|
255
|
+
type: Input
|
|
256
|
+
}], intervalInputMode: [{
|
|
257
|
+
type: Input
|
|
258
|
+
}], showAnchor: [{
|
|
259
|
+
type: Input
|
|
260
|
+
}], isAnchorReadOnly: [{
|
|
261
|
+
type: Input
|
|
262
|
+
}], isResultTextVisible: [{
|
|
263
|
+
type: Input
|
|
264
|
+
}], isHelpTextsVisible: [{
|
|
265
|
+
type: Input
|
|
266
|
+
}], dateChange: [{
|
|
267
|
+
type: Output
|
|
268
|
+
}] } });
|
|
269
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxkZXItaW50ZXJ2YWwtcGlja2VyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2VsZGVyYnl0ZS9uZ3gtc3RhcnRlci9zcmMvbGliL2NvbXBvbmVudHMvdGltZS9lbGRlci1pbnRlcnZhbC1waWNrZXIvZWxkZXItaW50ZXJ2YWwtcGlja2VyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2VsZGVyYnl0ZS9uZ3gtc3RhcnRlci9zcmMvbGliL2NvbXBvbmVudHMvdGltZS9lbGRlci1pbnRlcnZhbC1waWNrZXIvZWxkZXItaW50ZXJ2YWwtcGlja2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxNQUFNLEVBRU4sVUFBVSxFQUNWLFlBQVksRUFDWixLQUFLLEVBQ0wsS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDckQsT0FBTyxFQUNMLFdBQVcsRUFFWCxtQkFBbUIsRUFDbkIsbUJBQW1CLEVBQ25CLGlCQUFpQixFQUNqQixrQkFBa0IsRUFDbkIsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLE9BQU8sRUFDUCxRQUFRLEdBQ1QsTUFBTSw4QkFBOEIsQ0FBQztBQUN0QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFF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QUNBLFlBQVk7c0JBQXRDLFNBQVM7dUJBQUMsY0FBYztnQkFFaEIsa0JBQWtCO3NCQUExQixLQUFLO2dCQUNHLGlCQUFpQjtzQkFBekIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxtQkFBbUI7c0JBQTNCLEtBQUs7Z0JBQ0csa0JBQWtCO3NCQUExQixLQUFLO2dCQUNJLFVBQVU7c0JBQW5CLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENvbXBvbmVudCxcbiAgZWZmZWN0LFxuICBFZmZlY3RSZWYsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgaW5wdXQsXG4gIElucHV0LFxuICBPdXRwdXQsXG4gIFZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE1hdEJ1dHRvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbic7XG5pbXBvcnQgeyBEYXRlQWRhcHRlciB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NvcmUnO1xuaW1wb3J0IHtcbiAgTWF0Q2FsZW5kYXIsXG4gIE1hdENhbGVuZGFyQ2VsbENsYXNzRnVuY3Rpb24sXG4gIE1hdERhdGVwaWNrZXJNb2R1bGUsXG4gIE1hdERhdGVwaWNrZXJUb2dnbGUsXG4gIE1hdERhdGVSYW5nZUlucHV0LFxuICBNYXREYXRlUmFuZ2VQaWNrZXJcbn0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZGF0ZXBpY2tlcic7XG5pbXBvcnQge1xuICBNYXRGb3JtRmllbGRNb2R1bGUsXG4gIE1hdEhpbnQsXG4gIE1hdExhYmVsLFxufSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9mb3JtLWZpZWxkJztcbmltcG9ydCB7IE1hdEljb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pY29uJztcbmltcG9ydCB7IE1hdElucHV0TW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaW5wdXQnO1xuaW1wb3J0IHsgTWF0TWVudU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL21lbnUnO1xuaW1wb3J0IHsgTWF0VG9vbHRpcCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xuaW1wb3J0IHsgTG9nZ2VyRmFjdG9yeSB9IGZyb20gJ0BlbGRlcmJ5dGUvdHMtbG9nZ2VyJztcbmltcG9ydCB7IFRyYW5zbGF0ZU1vZHVsZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi8uLi9jb21tb24vdGltZS9pbnRlcnZhbCc7XG5pbXBvcnQgeyBUZW1wb3JhbFV0aWwgfSBmcm9tICcuLi8uLi8uLi9jb21tb24vdGltZS90ZW1wb3JhbC11dGlsJztcbmltcG9ydCB7IEN1c3RvbURhdGVBZGFwdGVyIH0gZnJvbSAnLi4vLi4vLi4vY29tcG9uZW50cy90aW1lL2RhdGUtYWRhcHRlcnMvY3VzdG9tLWRhdGUtYWRhcHRlcic7XG5pbXBvcnQgeyBJbnRlcnZhbElucHV0TW9kZSB9IGZyb20gJy4uLy4uLy4uL2NvbXBvbmVudHMvdGltZS9lbGRlci1pbnRlcnZhbC1pbnB1dC9lbGRlci1pbnRlcnZhbC1pbnB1dC5jb21wb25lbnQnO1xuaW1wb3J0IHsgRWxkZXJMb2NhbERhdGVJbnB1dENvbXBvbmVudCB9IGZyb20gJy4uLy4uLy4uL2NvbXBvbmVudHMvdGltZS9lbGRlci1sb2NhbC1kYXRlLWlucHV0L2VsZGVyLWxvY2FsLWRhdGUtaW5wdXQuY29tcG9uZW50JztcbmltcG9ydCB7IEVsZGVySW50ZXJ2YWxQaWNrZXJTZXJ2aWNlIH0gZnJvbSAnLi9lbGRlci1pbnRlcnZhbC1waWNrZXIuc2VydmljZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2VsZGVyLWludGVydmFsLXBpY2tlcicsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBNYXREYXRlUmFuZ2VQaWNrZXIsXG4gICAgTWF0RGF0ZXBpY2tlck1vZHVsZSxcbiAgICBNYXREYXRlUmFuZ2VJbnB1dCxcbiAgICBNYXRGb3JtRmllbGRNb2R1bGUsXG4gICAgTWF0TGFiZWwsXG4gICAgTWF0SGludCxcbiAgICBNYXREYXRlcGlja2VyVG9nZ2xlLFxuICAgIE1hdElucHV0TW9kdWxlLFxuICAgIENvbW1vbk1vZHVsZSxcbiAgICBNYXRJY29uTW9kdWxlLFxuICAgIEZvcm1zTW9kdWxlLFxuICAgIE1hdEJ1dHRvbk1vZHVsZSxcbiAgICBNYXRDYWxlbmRhcixcbiAgICBFbGRlckxvY2FsRGF0ZUlucHV0Q29tcG9uZW50LFxuICAgIE1hdFRvb2x0aXAsXG4gICAgVHJhbnNsYXRlTW9kdWxlLFxuICAgIE1hdE1lbnVNb2R1bGUsXG4gIF0sXG4gIHByb3ZpZGVyczogW1xuICAgIEVsZGVySW50ZXJ2YWxQaWNrZXJTZXJ2aWNlLFxuICAgIHsgcHJvdmlkZTogRGF0ZUFkYXB0ZXIsIHVzZUNsYXNzOiBDdXN0b21EYXRlQWRhcHRlciB9LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vZWxkZXItaW50ZXJ2YWwtcGlja2VyLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmw6ICcuL2VsZGVyLWludGVydmFsLXBpY2tlci5jb21wb25lbnQuc2NzcycsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBFbGRlckludGVydmFsUGlja2VyQ29tcG9uZW50IHtcbiAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqXG4gICAqIEZpZWxkcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICpcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKlxuICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgcHJpdmF0ZSByZWFkb25seSBsb2cgPSBMb2dnZXJGYWN0b3J5LmdldExvZ2dlcih0aGlzLmNvbnN0cnVjdG9yLm5hbWUpO1xuICBwdWJsaWMgcmVhZG9ubHkgY2FsZW5kYXJBbmNob3JEYXRlQ3NzQ2xhc3NGbjogTWF0Q2FsZW5kYXJDZWxsQ2xhc3NGdW5jdGlvbjxEYXRlPiA9XG4gICAgKGNlbGxEYXRlOiBEYXRlLCB2aWV3OiBzdHJpbmcpOiBzdHJpbmcgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuY2FsZW5kYXJBbmNob3JEYXRlQ3NzQ2xhc3NGbkJvZHkoY2VsbERhdGUsIHZpZXcpO1xuICAgIH07XG5cbiAgQFZpZXdDaGlsZCgncmFuZ2VDYWxlbmRhclN0YXJ0JykgY2FsZW5kYXJTdGFydCE6IE1hdENhbGVuZGFyPERhdGU+O1xuICBAVmlld0NoaWxkKCdyYW5nZUNhbGVuZGFyRW5kJykgY2FsZW5kYXJFbmQhOiBNYXRDYWxlbmRhcjxEYXRlPjtcblxuICBAVmlld0NoaWxkKCdyYW5nZUNhbGVuZGFyU3RhcnQnLCB7IHJlYWQ6IEVsZW1lbnRSZWYgfSkgY2FsZW5kYXJTdGFydEVsUmVmITogRWxlbWVudFJlZjtcbiAgQFZpZXdDaGlsZCgncmFuZ2VDYWxlbmRhckVuZCcsIHsgcmVhZDogRWxlbWVudFJlZiB9KSBjYWxlbmRhckVuZEVsUmVmITogRWxlbWVudFJlZjtcblxuICBAVmlld0NoaWxkKCdzdGFydERhdGVJbnB1dCcpIHN0YXJ0RGF0ZUlucHV0ITogRWxlbWVudFJlZjtcbiAgQFZpZXdDaGlsZCgnZW5kRGF0ZUlucHV0JykgZW5kRGF0ZUlucHV0ITogRWxlbWVudFJlZjtcblxuICBASW5wdXQoKSBpc0VtaXR0aW5nT25DaGFuZ2UgPSB0cnVlO1xuICBASW5wdXQoKSBpbnRlcnZhbElucHV0TW9kZTogSW50ZXJ2YWxJbnB1dE1vZGUgPSAnZGF0ZS1yYW5nZSc7XG4gIEBJbnB1dCgpIHNob3dBbmNob3IgPSBmYWxzZTtcbiAgQElucHV0KCkgaXNBbmNob3JSZWFkT25seSA9IGZhbHNlO1xuICBASW5wdXQoKSBpc1Jlc3VsdFRleHRWaXNpYmxlID0gdHJ1ZTtcbiAgQElucHV0KCkgaXNIZWxwVGV4dHNWaXNpYmxlID0gZmFsc2U7XG4gIEBPdXRwdXQoKSBkYXRlQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxJbnRlcnZhbD4oKTtcbiAgaW5wdXRJbnRlcnZhbCA9IGlucHV0PEludGVydmFsPihudWxsKTtcbiAgaW5wdXRBbmNob3JEYXRlVGltZSA9IGlucHV0PERhdGU+KG51bGwpO1xuXG4gIHByaXZhdGUgY2FsZW5kYXJFbEZvY3VzRXZlbnRIYW5kbGVyOiAoZXZlbnQ6IEZvY3VzRXZlbnQpID0+IHZvaWQ7XG5cbiAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqXG4gICAqIENvbnN0cnVjdG9yICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICpcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKlxuICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgY29uc3RydWN0b3IocHVibGljIHN2YzogRWxkZXJJbnRlcnZhbFBpY2tlclNlcnZpY2UpIHtcbiAgICB0aGlzLnN2Yy5zZXR1cElucHV0SW50ZXJ2YWwodGhpcy5pbnB1dEludGVydmFsKTtcbiAgICB0aGlzLnN2Yy5zZXR1cElucHV0QW5jaG9yRGF0ZVRpbWUodGhpcy5pbnB1dEFuY2hvckRhdGVUaW1lKTtcbiAgICB0aGlzLnN2Yy5zZXR1cEV2ZW50RW1pdHRlcih0aGlzLmRhdGVDaGFuZ2UpO1xuICB9XG5cbiAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqXG4gICAqIExpZmUgQ3ljbGUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICpcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKlxuICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaW5wdXRJbnRlcnZhbCkge1xuICAgICAgdGhpcy5zdmMucHVsbElucHV0SW50ZXJ2YWwoKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuaW5wdXRBbmNob3JEYXRlVGltZSgpKSB7XG4gICAgICB0aGlzLnN2Yy5wdWxsSW5wdXRBbmNob3JEYXRlVGltZSgpO1xuICAgIH1cbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnN2Yy5pc0VtaXR0aW5nT25DaGFuZ2Uuc2V0KHRoaXMuaXNFbWl0dGluZ09uQ2hhbmdlKTtcbiAgICB0aGlzLnNldHVwRGF0ZUlucHV0Q2FsZW5kYXJGb2N1c1ByZXZlbnRpb24oKTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMucmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTtcbiAgfVxuXG4gIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKlxuICAgKiBQdWJsaWMgQVBJICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICpcbiAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIHNldHVwRGF0ZUlucHV0Q2FsZW5kYXJGb2N1c1ByZXZlbnRpb24oKTogdm9pZCB7XG4gICAgLy8gUHJldmVudHMgdGhlIGZvY3VzIG9uIHRoZSBjYWxlbmRhciB3aGVuIHRoZSBpbnB1dCBmaWVsZCBpcyBjaGFuZ2VkIHZpYSB0aGUga2V5Ym9hcmRcbiAgICB0aGlzLmNhbGVuZGFyRWxGb2N1c0V2ZW50SGFuZGxlciA9IChldmVudDogRm9jdXNFdmVudCk6IHZvaWQgPT4ge1xuICAgICAgaWYgKCFldmVudCB8fCAhZXZlbnQucmVsYXRlZFRhcmdldCkge1xuICAgICAgICByZXR1cm47XG5cbiAgICAgIH1cbiAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICBjb25zdCByZWxUYXJnZXQgPSBldmVudC5yZWxhdGVkVGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgICAgIGlmIChyZWxUYXJnZXQubmFtZSA9PT0gJ3N0YXJ0RGF0ZUlucHV0Jykge1xuICAgICAgICB0aGlzLnN0YXJ0RGF0ZUlucHV0Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBcbiAgICAgIGlmIChyZWxUYXJnZXQubmFtZSA9PT0gJ2VuZERhdGVJbnB1dCcpIHtcbiAgICAgICAgdGhpcy5lbmREYXRlSW5wdXQubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgbmF0aXZlRWxlbWVudFN0YXJ0ID0gdGhpcy5jYWxlbmRhclN0YXJ0RWxSZWYubmF0aXZlRWxlbWVudCBhcyBIVE1MRWxlbWVudDtcbiAgICBjb25zdCBuYXRpdmVFbGVtZW50RW5kID0gdGhpcy5jYWxlbmRhckVuZEVsUmVmLm5hdGl2ZUVsZW1lbnQgYXMgSFRNTEVsZW1lbnQ7XG5cbiAgICBuYXRpdmVFbGVtZW50U3RhcnQuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCB0aGlzLmNhbGVuZGFyRWxGb2N1c0V2ZW50SGFuZGxlciwgdHJ1ZSk7XG4gICAgbmF0aXZlRWxlbWVudEVuZC5hZGRFdmVudExpc3RlbmVyKCdmb2N1cycsIHRoaXMuY2FsZW5kYXJFbEZvY3VzRXZlbnRIYW5kbGVyLCB0cnVlKTtcbiAgfVxuXG4gIGNsZWFyU3RhcnREYXRlVGltZSgpOiB2b2lkIHtcbiAgICB0aGlzLnN2Yy5jbGVhclN0YXJ0RGF0ZVRpbWUoKTtcblxuICAgIHRoaXMuc3ZjLnJlc2V0Q2FsZW5kYXJNb2RlKCk7XG5cbiAgICBpZiAodGhpcy5pc0VtaXR0aW5nT25DaGFuZ2UpIHtcbiAgICAgIHRoaXMuc3ZjLmVtaXRNYWluRGF0ZXMoKTtcbiAgICB9XG4gIH1cblxuICBjbGVhckVuZERhdGVUaW1lKCk6IHZvaWQge1xuICAgIHRoaXMuc3ZjLmNsZWFyRW5kRGF0ZVRpbWUoKTtcblxuICAgIHRoaXMuc3ZjLnJlc2V0Q2FsZW5kYXJNb2RlKCk7XG5cbiAgICBpZiAodGhpcy5pc0VtaXR0aW5nT25DaGFuZ2UpIHtcbiAgICAgIHRoaXMuc3ZjLmVtaXRNYWluRGF0ZXMoKTtcbiAgICB9XG4gIH1cblxuICBjbGVhclN0YXJ0QW5kRW5kRGF0ZVRpbWVzKCk6IHZvaWQge1xuICAgIHRoaXMuc3ZjLmNsZWFyU3RhcnREYXRlVGltZSgpO1xuICAgIHRoaXMuc3ZjLmNsZWFyRW5kRGF0ZVRpbWUoKTtcblxuICAgIHRoaXMuc3ZjLnJlc2V0Q2FsZW5kYXJNb2RlKCk7XG5cbiAgICBpZiAodGhpcy5pc0VtaXR0aW5nT25DaGFuZ2UpIHtcbiAgICAgIHRoaXMuc3ZjLmVtaXRNYWluRGF0ZXMoKTtcbiAgICB9XG4gIH1cblxuICBoYW5kbGVTdGFydENhbGVuZGFyQ2hhbmdlKGNoYW5nZWREYXRlOiBEYXRlKTogdm9pZCB7XG4gICAgdGhpcy5zdmMuY2FsZW5kYXJNb2RlLnNldCgnZGF5cycpO1xuICAgIGNvbnN0IG5ld1BsYWluRGF0ZSA9IFRlbXBvcmFsVXRpbC5nZXRQbGFpbkRhdGVGcm9tSlNEYXRlKGNoYW5nZWREYXRlKTtcbiAgICB0aGlzLnN2Yy5zdGFydERhdGUuc2V0KG5ld1BsYWluRGF0ZSk7XG4gIH1cblxuICBoYW5kbGVFbmRDYWxlbmRhckNoYW5nZShjaGFuZ2VkRGF0ZTogRGF0ZSk6IHZvaWQge1xuICAgIHRoaXMuc3ZjLmNhbGVuZGFyTW9kZS5zZXQoJ2RheXMnKTtcbiAgICBjb25zdCBuZXdQbGFpbkRhdGUgPSBUZW1wb3JhbFV0aWwuZ2V0UGxhaW5EYXRlRnJvbUpTRGF0ZShjaGFuZ2VkRGF0ZSk7XG4gICAgdGhpcy5zdmMuZW5kRGF0ZS5zZXQobmV3UGxhaW5EYXRlKTtcbiAgfVxuXG4gIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKlxuICAgKiBQcml2YXRlIG1ldGhvZHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICpcbiAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIHByaXZhdGUgcmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmNhbGVuZGFyU3RhcnRFbFJlZiB8fCAhdGhpcy5jYWxlbmRhckVuZEVsUmVmKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmNhbGVuZGFyU3RhcnRFbFJlZi5uYXRpdmVFbGVtZW50IHx8ICF0aGlzLmNhbGVuZGFyRW5kRWxSZWYubmF0aXZlRWxlbWVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IG5hdGl2ZUVsZW1lbnRTdGFydCA9IHRoaXMuY2FsZW5kYXJTdGFydEVsUmVmLm5hdGl2ZUVsZW1lbnQgYXMgSFRNTEVsZW1lbnQ7XG4gICAgY29uc3QgbmF0aXZlRWxlbWVudEVuZCA9IHRoaXMuY2FsZW5kYXJFbmRFbFJlZi5uYXRpdmVFbGVtZW50IGFzIEhUTUxFbGVtZW50O1xuXG4gICAgbmF0aXZlRWxlbWVudFN0YXJ0LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2ZvY3VzJywgdGhpcy5jYWxlbmRhckVsRm9jdXNFdmVudEhhbmRsZXIsIHRydWUpO1xuICAgIG5hdGl2ZUVsZW1lbnRFbmQucmVtb3ZlRXZlbnRMaXN0ZW5lcignZm9jdXMnLCB0aGlzLmNhbGVuZGFyRWxGb2N1c0V2ZW50SGFuZGxlciwgdHJ1ZSk7XG4gIH1cblxuICBwcml2YXRlIGNhbGVuZGFyQW5jaG9yRGF0ZUNzc0NsYXNzRm5Cb2R5KFxuICAgIGNlbGxEYXRlOiBEYXRlLFxuICAgIHZpZXc6IHN0cmluZ1xuICApOiBzdHJpbmcge1xuICAgIGNvbnN0IGFuY2hvckRhdGUgPSB0aGlzLnN2Yy5maXhlZEFuY2hvckRhdGUoKTtcblxuICAgIGlmICghYW5jaG9yRGF0ZSkge1xuICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIGNvbnN0IGRhdGUgPSBUZW1wb3JhbFV0aWwuZ2V0SlNEYXRlRnJvbVBsYWluRGF0ZVRpbWUoYW5jaG9yRGF0ZSk7XG5cbiAgICBpZiAoIWRhdGUpIHtcbiAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBjZWxsRGF0ZS5nZXREYXRlKCkgPT09IGRhdGUuZ2V0RGF0ZSgpICYmXG4gICAgICBjZWxsRGF0ZS5nZXRNb250aCgpID09PSBkYXRlLmdldE1vbnRoKCkgJiZcbiAgICAgIGNlbGxEYXRlLmdldEZ1bGxZZWFyKCkgPT09IGRhdGUuZ2V0RnVsbFllYXIoKVxuICAgICkge1xuICAgICAgcmV0dXJuICdlbGRlci1jdXN0b20tYW5jaG9yLWRhdGUnO1xuICAgIH1cblxuICAgIHJldHVybiAnJztcbiAgfVxuXG4gIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKlxuICAgKiBFZmZlY3RzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqXG4gICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICpcbiAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgX3VwZGF0ZU1hdENhbGVuZGFyRWxBbmNob3JDc3NDbGFzc0VmZmVjdDogRWZmZWN0UmVmID0gZWZmZWN0KFxuICAgICgpOiB2b2lkID0+IHtcbiAgICAgIGNvbnN0IGFuY2hvckRhdGUgPSB0aGlzLnN2Yy5hbmNob3JEYXRlKCk7XG5cbiAgICAgIGlmIChhbmNob3JEYXRlKSB7XG4gICAgICAgIHRoaXMuY2FsZW5kYXJTdGFydC51cGRhdGVUb2RheXNEYXRlKCk7XG4gICAgICAgIHRoaXMuY2FsZW5kYXJFbmQudXBkYXRlVG9kYXlzRGF0ZSgpO1xuICAgICAgfVxuICAgIH1cbiAgKTtcblxuICBwcml2YXRlIHJlYWRvbmx5IF91cGRhdGVNYXRDYWxlbmRhckVsU2VsZWN0aW9uRWZmZWN0OiBFZmZlY3RSZWYgPSBlZmZlY3QoXG4gICAgKCk6IHZvaWQgPT4ge1xuICAgICAgY29uc3Qgc3RhcnREYXRlID0gdGhpcy5zdmMuc3RhcnREYXRlKCk7XG4gICAgICBjb25zdCBlbmREYXRlID0gdGhpcy5zdmMuZW5kRGF0ZSgpO1xuXG4gICAgICBpZiAoIXRoaXMuY2FsZW5kYXJTdGFydCB8fCAhdGhpcy5jYWxlbmRhckVuZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICghc3RhcnREYXRlICYmICFlbmREYXRlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY2FsZW5kYXIxID0gdGhpcy5jYWxlbmRhclN0YXJ0O1xuICAgICAgY29uc3QgY2FsZW5kYXIyID0gdGhpcy5jYWxlbmRhckVuZDtcblxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIC8vIHRpbWVvdXQgaXMgbmVlZGVkIHRvIHJ1biBydW4gY2FsZW5kYXIgdXBkYXRlIGxhc3QsIG90aGVyd2lzZSB0aGVyZSBhcmUgaXNzdWVzXG4gICAgICAgIGlmIChzdGFydERhdGUpIHtcbiAgICAgICAgICBjb25zdCBzdGFydEpzRGF0ZSA9XG4gICAgICAgICAgICBUZW1wb3JhbFV0aWwuZ2V0SlNEYXRlRnJvbVBsYWluRGF0ZVRpbWUoc3RhcnREYXRlKTtcbiAgICAgICAgICBjYWxlbmRhcjEuYWN0aXZlRGF0ZSA9IHN0YXJ0SnNEYXRlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGVuZERhdGUpIHtcbiAgICAgICAgICBjb25zdCBlbmRKc0RhdGUgPSBUZW1wb3JhbFV0aWwuZ2V0SlNEYXRlRnJvbVBsYWluRGF0ZVRpbWUoZW5kRGF0ZSk7XG4gICAgICAgICAgY2FsZW5kYXIyLmFjdGl2ZURhdGUgPSBlbmRKc0RhdGU7XG4gICAgICAgIH1cbiAgICAgIH0sIDApO1xuICAgIH1cbiAgKTtcbn1cbiIsIjxkaXYgY2xhc3M9XCJpbnRlcnZhbC1waWNrZXItY29tcG9uZW50IHAtbWQgbGF5b3V0LWNvbCBnYXAteHhsXCI+XG4gIDxkaXYgY2xhc3M9XCJsYXlvdXQtcm93IGdhcC14eGwgcGxhY2UtYmV0d2Vlbi1zdGFydFwiIHN0eWxlPVwiZ2FwOiA1JVwiPlxuICAgIDxkaXYgY2xhc3M9XCJsYXlvdXQtY29sIGdhcC1tZCBwdC14c1wiPlxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImludGVydmFsU2VsZWN0b3JcIj48L25nLWNvbnRhaW5lcj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LWNvbFwiPlxuICAgICAgPCEtLSBzbWFydCBzaGlmdCAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJsYXlvdXQtcm93IHBsYWNlLWFyb3VuZC1jZW50ZXJcIj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKGNsaWNrKT1cInN2Yy5zbWFydFNoaWZ0KC0xKVwiIFtkaXNhYmxlZF09XCJzdmMuaXNSYW5nZU5vdFNldCgpXCI+XG4gICAgICAgICAgPG1hdC1pY29uPmtleWJvYXJkX2RvdWJsZV9hcnJvd19sZWZ0PC9tYXQtaWNvbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxzcGFuPnt7IHN2Yy52aWV3SW50ZXJ2YWxNZXNzYWdlKCkgfX08L3NwYW4+XG4gICAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIChjbGljayk9XCJzdmMuc21hcnRTaGlmdCgxKVwiIFtkaXNhYmxlZF09XCJzdmMuaXNSYW5nZU5vdFNldCgpXCI+XG4gICAgICAgICAgPG1hdC1pY29uPmtleWJvYXJkX2RvdWJsZV9hcnJvd19yaWdodDwvbWF0LWljb24+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgICA8IS0tIGNhbGVuZGFycyBhbmQgaW5wdXQgY29udHJvbHMgLS0+XG4gICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiY2FsZW5kYXJzVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwicHQteHNcIiBzdHlsZT1cIndpZHRoOiAyNSVcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJsYXlvdXQtY29sIGdhcC1sZ1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LWNvbCBnYXAteHMgcGxhY2Utc3RhcnQtc3RhcnRcIj5cbiAgICAgICAgICBAaWYgKGlzSGVscFRleHRzVmlzaWJsZSkge1xuICAgICAgICAgIDxoNSBjbGFzcz1cIm1hdC1oNVwiPnt7IFwiaW50ZXJ2YWxQaWNrZXIuc2VsZWN0U21hcnRJbnRlcnZhbFwiIHwgdHJhbnNsYXRlIH19PC9oNT5cbiAgICAgICAgICB9XG4gICAgICAgICAgPCEtLSBzZWxlY3QgY3VycmVudCAtLT5cbiAgICAgICAgICA8YnV0dG9uIG1hdC1idXR0b24gKGNsaWNrKT1cInN2Yy5zZWxlY3RDdXJyZW50V2VlaygpXCI+XG4gICAgICAgICAgICB7eyBcImludGVydmFsUGlja2VyLmN1cnJlbnRQZXJpb2Qud2Vla1wiIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPGJ1dHRvbiBtYXQtYnV0dG9uIChjbGljayk9XCJzdmMuc2VsZWN0Q3VycmVudE1vbnRoKClcIj5cbiAgICAgICAgICAgIHt7IFwiaW50ZXJ2YWxQaWNrZXIuY3VycmVudFBlcmlvZC5tb250aFwiIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPGJ1dHRvbiBtYXQtYnV0dG9uIChjbGljayk9XCJzdmMuc2VsZWN0Q3VycmVudFF1YXJ0ZXIoKVwiPlxuICAgICAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci5jdXJyZW50UGVyaW9kLnF1YXJ0ZXJcIiB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDxidXR0b24gbWF0LWJ1dHRvbiAoY2xpY2spPVwic3ZjLnNlbGVjdEN1cnJlbnRZZWFyKClcIj5cbiAgICAgICAgICAgIHt7IFwiaW50ZXJ2YWxQaWNrZXIuY3VycmVudFBlcmlvZC55ZWFyXCIgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaXhlZC1zaGlmdHMtY29udGFpbmVyXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImZpeGVkU2hpZnRzXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBwbGFjZS1iZXR3ZWVuLWNlbnRlciBnYXAteHhsIHB0LXNtXCI+XG4gICAgPGRpdj5cbiAgICAgIEBpZiAoc2hvd0FuY2hvcikge1xuICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cImFuY2hvcklucHV0RmllbGRcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgICBAaWYgKGlzUmVzdWx0VGV4dFZpc2libGUpIHtcbiAgICA8IS0tIHJlc3VsdCBpbnRlcnZhbCAtLT5cbiAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LWNvbCBwbGFjZS1jZW50ZXItY2VudGVyXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZGF0ZS1pbnRlcnZhbCBtYXQtY2FwdGlvbiBwdC14c1wiPlxuICAgICAgICBAaWYgKHN2Yy5zdGFydERhdGVUaW1lQXNKU0RhdGUoKSkge1xuICAgICAgICB7eyBzdmMuc3RhcnREYXRlVGltZUFzSlNEYXRlKCkgfCBkYXRlIDogXCJkZC5NTS4geSwgSEg6bW06c3NcIiB9fVxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci5zdGFydERhdGVOb3RTZXRcIiB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICB9XG4gICAgICAgIDxzcGFuPiAtIDwvc3Bhbj5cbiAgICAgICAgQGlmIChzdmMuZW5kRGF0ZVRpbWVBc0pTRGF0ZSgpKSB7XG4gICAgICAgIHt7IHN2Yy5lbmREYXRlVGltZUFzSlNEYXRlKCkgfCBkYXRlIDogXCJkZC5NTS4geSwgSEg6bW06c3NcIiB9fVxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci5lbmREYXRlTm90U2V0XCIgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2PlxuICAgICAgICA8c3BhbiBjbGFzcz1cIm1hdC1jYXB0aW9uXCI+e3sgc3ZjLmRlbHRhSHVtYW5SZWFkYWJsZSgpIHx8IFwiJm5ic3A7XCIgfX08L3NwYW4+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICB9XG4gICAgPGRpdiBjbGFzcz1cImxheW91dC1yb3cgZ2FwLWxnXCI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1yYWlzZWQtYnV0dG9uXG4gICAgICAgIGNvbG9yPVwicHJpbWFyeVwiXG4gICAgICAgIChjbGljayk9XCJjbGVhclN0YXJ0QW5kRW5kRGF0ZVRpbWVzKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwic3ZjLmlzU3RhcnRBbmRFbmREYXRlc0VtcHR5KClcIlxuICAgICAgPlxuICAgICAgICB7eyBcImludGVydmFsUGlja2VyLmNsZWFyXCIgfCB0cmFuc2xhdGUgfX1cbiAgICAgIDwvYnV0dG9uPlxuXG4gICAgICBAaWYoIXRoaXMuaXNFbWl0dGluZ09uQ2hhbmdlKSB7XG4gICAgICA8YnV0dG9uIGNvbG9yPVwicHJpbWFyeVwiIG1hdC1yYWlzZWQtYnV0dG9uIChjbGljayk9XCJzdmMuZW1pdE1haW5EYXRlcygpXCI+XG4gICAgICAgIHt7IFwiYWN0aW9ucy5va1wiIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj5cblxuPG5nLXRlbXBsYXRlICNpbnRlcnZhbFNlbGVjdG9yPlxuICA8ZGl2IGNsYXNzPVwibGF5b3V0LWNvbFwiPlxuICAgIEBpZiAoaXNIZWxwVGV4dHNWaXNpYmxlKSB7XG4gICAgPGg1IGNsYXNzPVwibWF0LWg1XCI+e3sgXCJpbnRlcnZhbFBpY2tlci5zZWxlY3RBYnNvbHV0ZUludGVydmFsXCIgfCB0cmFuc2xhdGUgfX08L2g1PlxuICAgIH1cbiAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBzZWxlY3QtYnV0dG9ucy1jb250YWluZXIgZ2FwLXNtXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LWNvbCBnYXAteHMgcGxhY2Utc3RhcnQtc3RyZXRjaFwiPlxuICAgICAgICA8YnV0dG9uIG1hdC1idXR0b24gKGNsaWNrKT1cInN2Yy5zZWxlY3RDdXJyZW50RGF5KClcIj5cbiAgICAgICAgICBAaWYoc3ZjLmlzRml4ZWRBbmNob3JEYXRlU2V0KCkpIHtcbiAgICAgICAgICB7eyBcImludGVydmFsUGlja2VyLmFuY2hvckRheVwiIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci50b2RheVwiIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgfVxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtYnV0dG9uIChjbGljayk9XCJzdmMuc2VsZWN0WWVzdGVyZGF5KClcIj5cbiAgICAgICAgICBAaWYgKHN2Yy5pc0ZpeGVkQW5jaG9yRGF0ZVNldCgpKSB7XG4gICAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci5sYXN0XCIgfCB0cmFuc2xhdGUgfX0gMSB7eyBcImludGVydmFsUGlja2VyLmRheVwiIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci55ZXN0ZXJkYXlcIiB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgIH1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b24gbWF0LWJ1dHRvbiAoY2xpY2spPVwic3ZjLnNlbGVjdExhc3RTZXZlbkRheXMoKVwiPlxuICAgICAgICAgIHt7IFwiaW50ZXJ2YWxQaWNrZXIubGFzdFwiIHwgdHJhbnNsYXRlIH19IDcge3sgXCJpbnRlcnZhbFBpY2tlci5kYXlzXCIgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDxidXR0b24gbWF0LWJ1dHRvbiAoY2xpY2spPVwic3ZjLnNlbGVjdExhc3RUaGlydHlEYXlzKClcIj5cbiAgICAgICAgICB7eyBcImludGVydmFsUGlja2VyLmxhc3RcIiB8IHRyYW5zbGF0ZSB9fSAzMCB7eyBcImludGVydmFsUGlja2VyLmRheXNcIiB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgQGlmIChpbnRlcnZhbElucHV0TW9kZSA9PT0gJ2RhdGUtdGltZS1yYW5nZScpIHtcbiAgICAgICAgPGRpdiBjbGFzcz1cInB0LXNtXCI+PC9kaXY+XG4gICAgICAgIDxidXR0b24gbWF0LWJ1dHRvbiAoY2xpY2spPVwic3ZjLnNlbGVjdExhc3RGaXZlTWludXRlcygpXCI+XG4gICAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci5sYXN0XCIgfCB0cmFuc2xhdGUgfX0gNSB7eyBcImludGVydmFsUGlja2VyLm1pbnV0ZXNcIiB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtYnV0dG9uIChjbGljayk9XCJzdmMuc2VsZWN0TGFzdEhvdXIoKVwiPlxuICAgICAgICAgIHt7IFwiaW50ZXJ2YWxQaWNrZXIubGFzdFwiIHwgdHJhbnNsYXRlIH19IHt7IFwiaW50ZXJ2YWxQaWNrZXIuaG91clwiIHwgdHJhbnNsYXRlIH19XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8YnV0dG9uIG1hdC1idXR0b24gKGNsaWNrKT1cInN2Yy5zZWxlY3RMYXN0MjRIb3VycygpXCI+XG4gICAgICAgICAge3sgXCJpbnRlcnZhbFBpY2tlci5sYXN0XCIgfCB0cmFuc2xhdGUgfX0gMjQge3sgXCJpbnRlcnZhbFBpY2tlci5ob3Vyc1wiIHwgdHJhbnNsYXRlIH19XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgICB9XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuXG48bmctdGVtcGxhdGUgI2NhbGVuZGFyc1RlbXBsYXRlPlxuICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBwbGFjZS1hcm91bmQtY2VudGVyXCIgc3R5bGU9XCJhbGlnbi1pdGVtczogZmxleC1zdGFydDsgbWluLWhlaWdodDogMjgwcHhcIj5cbiAgICA8bWF0LWNhbGVuZGFyXG4gICAgICAjcmFuZ2VDYWxlbmRhclN0YXJ0XG4gICAgICBzdHlsZT1cIndpZHRoOiAyMTBweDsgbWF4LXdpZHRoOiAxMDAlXCJcbiAgICAgIFtzZWxlY3RlZF09XCJzdmMuZGF0ZVJhbmdlRm9yQ2FsZW5kYXIoKVwiXG4gICAgICAoc2VsZWN0ZWRDaGFuZ2UpPVwiaGFuZGxlU3RhcnRDYWxlbmRhckNoYW5nZSgkZXZlbnQpXCJcbiAgICAgIFttYXhEYXRlXT1cInN2Yy5lbmREYXRlQXNKU0RhdGUoKVwiXG4gICAgICBbZGF0ZUNsYXNzXT1cImNhbGVuZGFyQW5jaG9yRGF0ZUNzc0NsYXNzRm5cIlxuICAgID5cbiAgICA8L21hdC1jYWxlbmRhcj5cbiAgICA8bWF0LWNhbGVuZGFyXG4gICAgICAjcmFuZ2VDYWxlbmRhckVuZFxuICAgICAgc3R5bGU9XCJ3aWR0aDogMjEwcHg7IG1heC13aWR0aDogMTAwJVwiXG4gICAgICBbc2VsZWN0ZWRdPVwic3ZjLmRhdGVSYW5nZUZvckNhbGVuZGFyKClcIlxuICAgICAgKHNlbGVjdGVkQ2hhbmdlKT1cImhhbmRsZUVuZENhbGVuZGFyQ2hhbmdlKCRldmVudClcIlxuICAgICAgW21pbkRhdGVdPVwic3ZjLnN0YXJ0RGF0ZUFzSlNEYXRlKClcIlxuICAgICAgW2RhdGVDbGFzc109XCJjYWxlbmRhckFuY2hvckRhdGVDc3NDbGFzc0ZuXCJcbiAgICA+XG4gICAgPC9tYXQtY2FsZW5kYXI+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBwbGFjZS1hcm91bmQtY2VudGVyIGdhcC14bCBwdC1zbVwiPlxuICAgIDxkaXYgY2xhc3M9XCJsYXlvdXQtcm93IHBsYWNlLWFyb3VuZC1jZW50ZXJcIj5cbiAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LWNvbnRyb2wtY29udGFpbmVyXCIgW3N1YnNjcmlwdFNpemluZ109XCInZHluYW1pYydcIj5cbiAgICAgICAgPG1hdC1sYWJlbD57eyBcImludGVydmFsUGlja2VyLnN0YXJ0RGF0ZVwiIHwgdHJhbnNsYXRlIH19PC9tYXQtbGFiZWw+XG4gICAgICAgIDxpbnB1dFxuICAgICAgICAgICNzdGFydERhdGVJbnB1dFxuICAgICAgICAgIG5hbWU9XCJzdGFydERhdGVJbnB1dFwiXG4gICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICB0eXBlPVwiZGF0ZVwiXG4gICAgICAgICAgW25nTW9kZWxdPVwic3ZjLnN0YXJ0RGF0ZUh0bWxTdHJpbmcoKVwiXG4gICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3ZjLnNldFN0YXJ0RGF0ZUZyb21IdG1sU3RyaW5nKCRldmVudClcIlxuICAgICAgICAvPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgbWF0LWljb24tYnV0dG9uXG4gICAgICAgICAgbWF0U3VmZml4XG4gICAgICAgICAgKGNsaWNrKT1cInRoaXMuY2xlYXJTdGFydERhdGVUaW1lKClcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCIhdGhpcy5zdmMuc3RhcnREYXRlKClcIlxuICAgICAgICA+XG4gICAgICAgICAgPG1hdC1pY29uPmNsb3NlPC9tYXQtaWNvbj5cbiAgICAgICAgPC9idXR0b24+XG4gICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJsYXlvdXQtcm93IHBsYWNlLWFyb3VuZC1jZW50ZXJcIj5cbiAgICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LWNvbnRyb2wtY29udGFpbmVyXCIgW3N1YnNjcmlwdFNpemluZ109XCInZHluYW1pYydcIj5cbiAgICAgICAgPG1hdC1sYWJlbD57eyBcImludGVydmFsUGlja2VyLmVuZERhdGVcIiB8IHRyYW5zbGF0ZSB9fTwvbWF0LWxhYmVsPlxuICAgICAgICA8aW5wdXRcbiAgICAgICAgICAjZW5kRGF0ZUlucHV0XG4gICAgICAgICAgbmFtZT1cImVuZERhdGVJbnB1dFwiXG4gICAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgICB0eXBlPVwiZGF0ZVwiXG4gICAgICAgICAgW25nTW9kZWxdPVwic3ZjLmVuZERhdGVIdG1sU3RyaW5nKClcIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN2Yy5zZXRFbmREYXRlRnJvbUh0bWxTdHJpbmcoJGV2ZW50KVwiXG4gICAgICAgIC8+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgICBtYXRTdWZmaXhcbiAgICAgICAgICAoY2xpY2spPVwidGhpcy5jbGVhckVuZERhdGVUaW1lKClcIlxuICAgICAgICAgIFtkaXNhYmxlZF09XCIhdGhpcy5zdmMuZW5kRGF0ZSgpXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxtYXQtaWNvbj5jbG9zZTwvbWF0LWljb24+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG4gIDxiciAvPlxuICBAaWYgKGludGVydmFsSW5wdXRNb2RlID09PSAnZGF0ZS10aW1lLXJhbmdlJykge1xuICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBwbGFjZS1hcm91bmQtY2VudGVyIGdhcC14bCBwdC1zbVwiPlxuICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LWNvbnRyb2wtY29udGFpbmVyXCIgW3N1YnNjcmlwdFNpemluZ109XCInZHluYW1pYydcIj5cbiAgICAgIDxtYXQtbGFiZWw+e3sgXCJpbnRlcnZhbFBpY2tlci5zdGFydFRpbWVcIiB8IHRyYW5zbGF0ZSB9fTwvbWF0LWxhYmVsPlxuICAgICAgPGlucHV0XG4gICAgICAgIG5hbWU9XCJzdGFydFRpbWVJbnB1dFwiXG4gICAgICAgIG1hdElucHV0XG4gICAgICAgIHR5cGU9XCJ0aW1lXCJcbiAgICAgICAgI3N0YXJ0VGltZUNvbnRyb2w9XCJuZ01vZGVsXCJcbiAgICAgICAgc3RlcD1cIjFcIlxuICAgICAgICBbbmdNb2RlbF09XCJzdmMuZ2V0U3RhcnRUaW1lU3RyaW5nKClcIlxuICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdmMuc2V0U3RhcnRUaW1lRnJvbVN0cmluZygkZXZlbnQsIHN0YXJ0VGltZUNvbnRyb2wpXCJcbiAgICAgIC8+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICBtYXRTdWZmaXhcbiAgICAgICAgKGNsaWNrKT1cInRoaXMuc3ZjLmNsZWFyU3RhcnRUaW1lKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiIXRoaXMuc3ZjLmlzU3RhcnRUaW1lU2V0QW5kTm90TWlkbmlnaHQoKVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbj5jbG9zZTwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgIDxtYXQtZm9ybS1maWVsZCBjbGFzcz1cImlucHV0LWNvbnRyb2wtY29udGFpbmVyXCIgW3N1YnNjcmlwdFNpemluZ109XCInZHluYW1pYydcIj5cbiAgICAgIDxtYXQtbGFiZWw+e3sgXCJpbnRlcnZhbFBpY2tlci5lbmRUaW1lXCIgfCB0cmFuc2xhdGUgfX08L21hdC1sYWJlbD5cbiAgICAgIDxpbnB1dFxuICAgICAgICBuYW1lPVwiZW5kVGltZUlucHV0XCJcbiAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgdHlwZT1cInRpbWVcIlxuICAgICAgICAjZW5kVGltZUNvbnRyb2w9XCJuZ01vZGVsXCJcbiAgICAgICAgc3RlcD1cIjFcIlxuICAgICAgICBbbmdNb2RlbF09XCJzdmMuZ2V0RW5kVGltZVN0cmluZygpXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3ZjLnNldEVuZFRpbWVGcm9tU3RyaW5nKCRldmVudCwgZW5kVGltZUNvbnRyb2wpXCJcbiAgICAgIC8+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICBtYXRTdWZmaXhcbiAgICAgICAgKGNsaWNrKT1cInRoaXMuc3ZjLmNsZWFyRW5kVGltZSgpXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cIiF0aGlzLnN2Yy5pc0VuZFRpbWVTZXRBbmROb3RNaWRuaWdodCgpXCJcbiAgICAgID5cbiAgICAgICAgPG1hdC1pY29uPmNsb3NlPC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gIDwvZGl2PlxuICB9XG48L25nLXRlbXBsYXRlPlxuXG48bmctdGVtcGxhdGUgI2ZpeGVkU2hpZnRzPlxuICBAaWYgKGlzSGVscFRleHRzVmlzaWJsZSkge1xuICA8aDUgY2xhc3M9XCJtYXQtaDVcIj57eyBcImludGVydmFsUGlja2VyLnNoaWZ0SW50ZXJ2YWxcIiB8IHRyYW5zbGF0ZSB9fTwvaDU+XG4gIH1cbiAgPGRpdiBjbGFzcz1cImxheW91dC1jb2wgcGxhY2Utc3RhcnQtc3RyZXRjaFwiPlxuICAgIDxkaXYgY2xhc3M9XCJsYXlvdXQtcm93IHBsYWNlLWJldHdlZW4tY2VudGVyXCI+XG4gICAgICA8YnV0dG9uIG1hdC1pY29uLWJ1dHRvbiAoY2xpY2spPVwic3ZjLnNoaWZ0RGF5KC0xKVwiIFtkaXNhYmxlZF09XCJzdmMuaXNSYW5nZU5vdFNldCgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5rZXlib2FyZF9kb3VibGVfYXJyb3dfbGVmdDwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxzcGFuPnt7IFwiaW50ZXJ2YWxQaWNrZXIuZGF5XCIgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICA8YnV0dG9uIG1hdC1pY29uLWJ1dHRvbiAoY2xpY2spPVwic3ZjLnNoaWZ0RGF5KDEpXCIgW2Rpc2FibGVkXT1cInN2Yy5pc1JhbmdlTm90U2V0KClcIj5cbiAgICAgICAgPG1hdC1pY29uPmtleWJvYXJkX2RvdWJsZV9hcnJvd19yaWdodDwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBwbGFjZS1iZXR3ZWVuLWNlbnRlclwiPlxuICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKGNsaWNrKT1cInN2Yy5zaGlmdE1vbnRoKC0xLCB0cnVlKVwiIFtkaXNhYmxlZF09XCJzdmMuaXNSYW5nZU5vdFNldCgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5rZXlib2FyZF9kb3VibGVfYXJyb3dfbGVmdDwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxzcGFuPnt7IFwiaW50ZXJ2YWxQaWNrZXIubW9udGhcIiB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIChjbGljayk9XCJzdmMuc2hpZnRNb250aCgxLCB0cnVlKVwiIFtkaXNhYmxlZF09XCJzdmMuaXNSYW5nZU5vdFNldCgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5rZXlib2FyZF9kb3VibGVfYXJyb3dfcmlnaHQ8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImxheW91dC1yb3cgcGxhY2UtYmV0d2Vlbi1jZW50ZXJcIj5cbiAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIChjbGljayk9XCJzdmMuc2hpZnRZZWFyKC0xLCB0cnVlKVwiIFtkaXNhYmxlZF09XCJzdmMuaXNSYW5nZU5vdFNldCgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5rZXlib2FyZF9kb3VibGVfYXJyb3dfbGVmdDwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxzcGFuPnt7IFwiaW50ZXJ2YWxQaWNrZXIueWVhclwiIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKGNsaWNrKT1cInN2Yy5zaGlmdFllYXIoMSwgdHJ1ZSlcIiBbZGlzYWJsZWRdPVwic3ZjLmlzUmFuZ2VOb3RTZXQoKVwiPlxuICAgICAgICA8bWF0LWljb24+a2V5Ym9hcmRfZG91YmxlX2Fycm93X3JpZ2h0PC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuXG4gICAgQGlmIChpbnRlcnZhbElucHV0TW9kZSA9PT0gJ2RhdGUtdGltZS1yYW5nZScpIHtcbiAgICA8IS0tIHNoaWZ0IG1pbnV0ZSAtLT5cbiAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBwbGFjZS1iZXR3ZWVuLWNlbnRlclwiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBtYXQtaWNvbi1idXR0b25cbiAgICAgICAgKGNsaWNrKT1cInN2Yy5zaGlmdFRpbWUoLTEsICdtaW51dGVzJylcIlxuICAgICAgICBbZGlzYWJsZWRdPVwic3ZjLmlzUmFuZ2VOb3RTZXQoKVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbj5rZXlib2FyZF9kb3VibGVfYXJyb3dfbGVmdDwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxzcGFuPnt7IFwiaW50ZXJ2YWxQaWNrZXIubWludXRlXCIgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICAoY2xpY2spPVwic3ZjLnNoaWZ0VGltZSgxLCAnbWludXRlcycpXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cInN2Yy5pc1JhbmdlTm90U2V0KClcIlxuICAgICAgPlxuICAgICAgICA8bWF0LWljb24+a2V5Ym9hcmRfZG91YmxlX2Fycm93X3JpZ2h0PC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICAgIDwhLS0gc2hpZnQgaG91ciAtLT5cbiAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LXJvdyBwbGFjZS1iZXR3ZWVuLWNlbnRlclwiPlxuICAgICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKGNsaWNrKT1cInN2Yy5zaGlmdFRpbWUoLTEsICdob3VycycpXCIgW2Rpc2FibGVkXT1cInN2Yy5pc1JhbmdlTm90U2V0KClcIj5cbiAgICAgICAgPG1hdC1pY29uPmtleWJvYXJkX2RvdWJsZV9hcnJvd19sZWZ0PC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgICAgPHNwYW4+e3sgXCJpbnRlcnZhbFBpY2tlci5ob3VyXCIgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICA8YnV0dG9uIG1hdC1pY29uLWJ1dHRvbiAoY2xpY2spPVwic3ZjLnNoaWZ0VGltZSgxLCAnaG91cnMnKVwiIFtkaXNhYmxlZF09XCJzdmMuaXNSYW5nZU5vdFNldCgpXCI+XG4gICAgICAgIDxtYXQtaWNvbj5rZXlib2FyZF9kb3VibGVfYXJyb3dfcmlnaHQ8L21hdC1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gICAgfVxuICA8L2Rpdj5cbjwvbmctdGVtcGxhdGU+XG5cbjxuZy10ZW1wbGF0ZSAjYW5jaG9ySW5wdXRGaWVsZD5cbiAgPGRpdiBjbGFzcz1cImxheW91dC1yb3cgZmxleC1ub25lIGdhcC1tZFwiPlxuICAgIDxtYXQtbWVudSAjYW5jaG9yTWVudT1cIm1hdE1lbnVcIj5cbiAgICAgIEBpZiAoc3ZjLnN0YXJ0RGF0ZSgpKSB7XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1tZW51LWl0ZW1cbiAgICAgICAgKGNsaWNrKT1cInN2Yy5zZXRGaXhlZEFuY2hvclBvaW50VG9FbmREYXRlVGltZSgpXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cIiFzdmMuZW5kRGF0ZSgpXCJcbiAgICAgID5cbiAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwibWF0ZXJpYWwtc3ltYm9scy1vdXRsaW5lZFwiPmxvZ2luPC9tYXQtaWNvbj5cbiAgICAgICAgPHNwYW4+e3sgXCJpbnRlcnZhbFBpY2tlci5lbmREYXRlXCIgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIH0gQGlmIChzdmMuZW5kRGF0ZSgpKSB7XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1tZW51LWl0ZW1cbiAgICAgICAgKGNsaWNrKT1cInN2Yy5zZXRGaXhlZEFuY2hvclBvaW50VG9TdGFydERhdGVUaW1lKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiIXN2Yy5zdGFydERhdGUoKVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cIm1hdGVyaWFsLXN5bWJvbHMtb3V0bGluZWRcIj5sb2dvdXQ8L21hdC1pY29uPlxuICAgICAgICA8c3Bhbj57eyBcImludGVydmFsUGlja2VyLnN0YXJ0RGF0ZVwiIHwgdHJhbnNsYXRlIH19PC9zcGFuPlxuICAgICAgPC9idXR0b24+XG4gICAgICB9IEBpZiAoc3ZjLmZpeGVkQW5jaG9yRGF0ZSgpKSB7XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1tZW51LWl0ZW1cbiAgICAgICAgKGNsaWNrKT1cInRoaXMuc3ZjLnJlc2V0Rml4ZWRBbmNob3JQb2ludCgpXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cIiFzdmMuZml4ZWRBbmNob3JEYXRlKCkgfHwgaXNBbmNob3JSZWFkT25seVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbj5jbG9zZTwvbWF0LWljb24+XG4gICAgICAgIDxzcGFuPnt7IFwiaW50ZXJ2YWxQaWNrZXIuY2xlYXJcIiB8IHRyYW5zbGF0ZSB9fTwvc3Bhbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgICAgfVxuICAgIDwvbWF0LW1lbnU+XG5cbiAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJpbnB1dC1jb250cm9sLWNvbnRhaW5lclwiIFtzdWJzY3JpcHRTaXppbmddPVwiJ2R5bmFtaWMnXCI+XG4gICAgICA8bWF0LWxhYmVsPnt7IFwiaW50ZXJ2YWxQaWNrZXIuYW5jaG9yRGF0ZVwiIHwgdHJhbnNsYXRlIH19PC9tYXQtbGFiZWw+XG4gICAgICA8ZWxkZXItbG9jYWwtZGF0ZS1pbnB1dFxuICAgICAgICBuYW1lPVwiYW5jaG9yRGF0ZUlucHV0XCJcbiAgICAgICAgKHZhbHVlVXBkYXRlZCk9XCJzdmMuc2V0QW5jaG9yRGF0ZUZyb21Gb3JtKCRldmVudClcIlxuICAgICAgICBbdmFsdWVdPVwic3ZjLmdldEFuY2hvclBvaW50QXNMb2NhbGVEYXRlKClcIlxuICAgICAgICBbcmVhZG9ubHldPVwiaXNBbmNob3JSZWFkT25seVwiXG4gICAgICA+XG4gICAgICA8L2VsZGVyLWxvY2FsLWRhdGUtaW5wdXQ+XG4gICAgICBAaWYgKCFpc0FuY2hvclJlYWRPbmx5KSB7XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICBtYXRTdWZmaXhcbiAgICAgICAgW21hdE1lbnVUcmlnZ2VyRm9yXT1cImFuY2hvck1lbnVcIlxuICAgICAgICBbZGlzYWJsZWRdPVwic3ZjLmlzU3RhcnRBbmRFbmREYXRlc0VtcHR5KCkgJiYgIXN2Yy5maXhlZEFuY2hvckRhdGUoKVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cIm1hdGVyaWFsLXN5bWJvbHMtb3V0bGluZWRcIj5tb3JlX2hvcml6PC9tYXQtaWNvbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgICAgfVxuICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgQGlmIChpbnRlcnZhbElucHV0TW9kZSA9PT0gJ2RhdGUtdGltZS1yYW5nZScpIHtcbiAgICA8bWF0LWZvcm0tZmllbGQgY2xhc3M9XCJpbnB1dC1jb250cm9sLWNvbnRhaW5lci1zaG9ydFwiIFtzdWJzY3JpcHRTaXppbmddPVwiJ2R5bmFtaWMnXCI+XG4gICAgICA8bWF0LWxhYmVsPnt7IFwiaW50ZXJ2YWxQaWNrZXIuYW5jaG9yVGltZVwiIHwgdHJhbnNsYXRlIH19PC9tYXQtbGFiZWw+XG4gICAgICA8aW5wdXRcbiAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgbmFtZT1cImFuY2hvclRpbWVJbnB1dFwiXG4gICAgICAgIHR5cGU9XCJ0aW1lXCJcbiAgICAgICAgI2FuY2hvclRpbWVDb250cm9sPVwibmdNb2RlbFwiXG4gICAgICAgIHN0ZXA9XCIxXCJcbiAgICAgICAgW3JlYWRvbmx5XT1cImlzQW5jaG9yUmVhZE9ubHlcIlxuICAgICAgICBbbmdNb2RlbF09XCJzdmMuZ2V0QW5jaG9yVGltZVN0cmluZygpXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3ZjLnNldEFuY2hvclRpbWVGcm9tRm9ybSgkZXZlbnQpXCJcbiAgICAgIC8+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIG1hdC1pY29uLWJ1dHRvblxuICAgICAgICBtYXRTdWZmaXhcbiAgICAgICAgKGNsaWNrKT1cInRoaXMuc3ZjLnJlc2V0Rml4ZWRBbmNob3JUaW1lKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiIXN2Yy5pc0ZpeGVkQW5jaG9yVGltZVNldEFuZE5vdE1pZG5pZ2h0KCkgfHwgaXNBbmNob3JSZWFkT25seVwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtaWNvbj5jbG9zZTwvbWF0LWljb24+XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgIH1cbiAgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuIl19
|