@hug/ngx-time-picker 1.1.1 → 1.1.3

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 1.1.3 (2024-07-08)
2
+
3
+
4
+ ### 🌱 Dependencies
5
+
6
+ - **@hug/ngx-core:** upgrade to v1.1.7 ([b0f15b9](https://github.com/DSI-HUG/ngx-components/commit/b0f15b9))
7
+
8
+ - **@hug/ngx-numeric-stepper:** upgrade to v1.1.4 ([197b1ad](https://github.com/DSI-HUG/ngx-components/commit/197b1ad))
9
+
10
+
11
+ ### ❤️ Thank You
12
+
13
+ - dsi-hug-bot @dsi-hug-bot
14
+
1
15
  ## 1.1.1 (2024-06-24)
2
16
 
3
17
 
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHVnLW5neC10aW1lLXBpY2tlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL3RpbWUtcGlja2VyL3NyYy9odWctbmd4LXRpbWUtcGlja2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxTQUFTLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vaW5kZXgnO1xuIl19
@@ -0,0 +1,2 @@
1
+ export * from './time-picker.component';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wcm9qZWN0cy90aW1lLXBpY2tlci9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyx5QkFBeUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vdGltZS1waWNrZXIuY29tcG9uZW50JztcbiJdfQ==
@@ -0,0 +1,302 @@
1
+ import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Optional, Output, Self, ViewChild, ViewEncapsulation } from '@angular/core';
4
+ import { FormsModule } from '@angular/forms';
5
+ import { MatFormFieldModule } from '@angular/material/form-field';
6
+ import { MatInputModule } from '@angular/material/input';
7
+ import { Destroy } from '@hug/ngx-core';
8
+ import { NumericStepperComponent } from '@hug/ngx-numeric-stepper';
9
+ import { isSameHour, set } from 'date-fns';
10
+ import { debounce, distinctUntilChanged, map, Subject, takeUntil, timer } from 'rxjs';
11
+ import * as i0 from "@angular/core";
12
+ import * as i1 from "@angular/forms";
13
+ import * as i2 from "@angular/common";
14
+ import * as i3 from "@angular/material/form-field";
15
+ import * as i4 from "@angular/material/input";
16
+ // TODO sdil refactor rxjs flows
17
+ export class TimePickerComponent extends Destroy {
18
+ constructor(changeDetectorRef, control) {
19
+ super();
20
+ this.changeDetectorRef = changeDetectorRef;
21
+ this.control = control;
22
+ this.timeChange = new EventEmitter();
23
+ /** Display mode for the time-picker */
24
+ this.mode = 'fullTime';
25
+ /** Data type to manage (Date or Duration) */
26
+ this.dataType = 'date';
27
+ /**
28
+ * Force the hour or minute to be null (only if the other field is disabled)
29
+ *
30
+ * For instance, if set to true and the hours are disabled, the minutes input value will be null
31
+ * This is useful to force the user to provide a value
32
+ */
33
+ this.forceNullValue = false;
34
+ this.appearance = 'outline';
35
+ this.defaultPlaceholderHours = '_ _';
36
+ this.defaultPlaceholderMinutes = '_ _';
37
+ this.onHoursChange$ = new Subject();
38
+ this.onMinutesChange$ = new Subject();
39
+ this._step = 1;
40
+ this._disabled = false;
41
+ this._autoFocus = true;
42
+ // ************* End of ControlValueAccessor Implementation **************
43
+ this.onChangeCallback = (_a) => undefined;
44
+ this.onTouchedCallback = () => undefined;
45
+ if (this.control) {
46
+ this.control.valueAccessor = this;
47
+ }
48
+ this.onHoursChange$.pipe(debounce(hours => timer(typeof hours === 'object' ? 0 : 10)), distinctUntilChanged(), map(hours => {
49
+ if (typeof hours === 'object') {
50
+ const value = hours.target.value;
51
+ return [value !== undefined ? parseInt(value, 10) : undefined, true];
52
+ }
53
+ return [!isNaN(hours) ? hours : 0, false];
54
+ }), takeUntil(this.destroyed$)).subscribe(([hours, isEvent]) => {
55
+ if (!this.value) {
56
+ this.value = this.dataType === 'date' ? set(new Date(), { hours, minutes: 0, seconds: 0, milliseconds: 0 }) : { hours, minutes: 0 };
57
+ }
58
+ else if (this.value instanceof Date) {
59
+ const value = this.value?.getTime();
60
+ const clone = new Date(value);
61
+ if (hours !== undefined) {
62
+ clone.setHours(hours);
63
+ }
64
+ this.value = clone;
65
+ }
66
+ else {
67
+ this.value = {
68
+ hours: hours && hours < 0 ? 0 : hours,
69
+ minutes: this.value.minutes
70
+ };
71
+ }
72
+ this.changeDetectorRef.markForCheck();
73
+ if (isEvent && this._autoFocus && this.minutes) {
74
+ this.minutes.nativeElement.focus({
75
+ preventScroll: true
76
+ });
77
+ this.minutes.nativeElement.select();
78
+ }
79
+ });
80
+ this.onMinutesChange$.pipe(debounce(minutes => timer(typeof minutes === 'object' ? 0 : 10)), distinctUntilChanged(), map(event => {
81
+ let minutes;
82
+ if (typeof event === 'object') {
83
+ const value = event.target.value;
84
+ minutes = value !== undefined ? parseInt(value, 10) : undefined;
85
+ }
86
+ else {
87
+ minutes = event;
88
+ }
89
+ return minutes && !isNaN(minutes) && minutes || 0;
90
+ }), takeUntil(this.destroyed$)).subscribe(minutes => {
91
+ if (!this.value) {
92
+ this.value = this.dataType === 'date' ? set(new Date(), { hours: 0, minutes, seconds: 0, milliseconds: 0 }) : { hours: 0, minutes };
93
+ }
94
+ else if (this.value instanceof Date) {
95
+ const newValue = new Date(this.value.getTime());
96
+ if (minutes < 0) {
97
+ minutes += 60;
98
+ }
99
+ else if (minutes >= 60) {
100
+ minutes -= 60;
101
+ }
102
+ newValue.setMinutes(minutes);
103
+ if (this.mode !== 'fullTimeWithHoursDisabled' || (this.mode === 'fullTimeWithHoursDisabled' && isSameHour(this.value, newValue))) {
104
+ this.value = newValue;
105
+ }
106
+ }
107
+ else {
108
+ this.value = {
109
+ hours: this.value.hours,
110
+ minutes: minutes < 0 || minutes >= 60 ? 0 : minutes
111
+ };
112
+ }
113
+ this.changeDetectorRef.markForCheck();
114
+ });
115
+ }
116
+ set autoFocus(value) {
117
+ this._autoFocus = coerceBooleanProperty(value);
118
+ }
119
+ set time(value) {
120
+ this.writeValue(value);
121
+ }
122
+ get time() {
123
+ return this.value;
124
+ }
125
+ /** Step of the arrows */
126
+ set step(value) {
127
+ this._step = coerceNumberProperty(value);
128
+ this.changeDetectorRef.markForCheck();
129
+ }
130
+ /** To get the step of the minutes arrows */
131
+ get step() {
132
+ return this._step;
133
+ }
134
+ /** Disabled property setter. Can be string or empty so you can use it like : <time-picker disabled></time-picker> */
135
+ set disabled(value) {
136
+ this._disabled = coerceBooleanProperty(value);
137
+ this.changeDetectorRef.markForCheck();
138
+ }
139
+ /** To get disabled attribute. */
140
+ get disabled() {
141
+ return this._disabled;
142
+ }
143
+ onKeyDown($event, mode) {
144
+ // Get input element
145
+ const inputElement = mode === 'hours' ? this.hours?.nativeElement : this.minutes?.nativeElement;
146
+ if ($event.key?.toLowerCase() === 'd') {
147
+ $event.stopPropagation();
148
+ $event.preventDefault();
149
+ this.value = new Date();
150
+ }
151
+ else if (inputElement) {
152
+ if ($event.key?.toLowerCase() === 'a' && $event.ctrlKey) {
153
+ inputElement.select();
154
+ }
155
+ else if ($event.key && !['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Backspace', 'Delete', 'Tab', 'Enter', 'Control', 'Shift'].includes($event.key)) {
156
+ // Set regex for input format validation (differs if we are dealing with a date or a duration)
157
+ let regex;
158
+ if (mode === 'hours') {
159
+ regex = this.dataType === 'date' ? /^(\d|[01]\d|2[0-3])$/ : /^(\d+)$/;
160
+ }
161
+ else {
162
+ regex = /^(\d|[0-5]\d)$/;
163
+ }
164
+ // Get the selection in input element
165
+ const [selectionStart, selectionEnd] = [inputElement.selectionStart || 0, inputElement.selectionEnd || 0].sort((a, b) => a - b);
166
+ const selectionDiff = selectionEnd - selectionStart;
167
+ // Get the current value in input element and update it with the new touched key
168
+ const inputValue = inputElement.value || '';
169
+ const inputValueArr = Array.from(inputValue);
170
+ inputValueArr.splice(selectionStart, selectionDiff, $event.key);
171
+ const newInputValue = inputValueArr.join('');
172
+ // Prevent event if the time is not valid
173
+ if (!regex.test(newInputValue)) {
174
+ $event.stopPropagation();
175
+ $event.preventDefault();
176
+ }
177
+ else if (this._autoFocus && mode === 'hours' && ((this.dataType === 'date' && parseFloat(newInputValue) >= 3) || newInputValue.length === 2)) {
178
+ this.onHoursChange$.next($event);
179
+ }
180
+ }
181
+ }
182
+ }
183
+ get hoursValue() {
184
+ if (!this.value || (this.forceNullValue && this.mode === 'fullTimeWithMinutesDisabled' && this.control.pristine)) {
185
+ return undefined;
186
+ }
187
+ return this.value instanceof Date ? this.value.getHours() : this.value.hours;
188
+ }
189
+ get minutesValue() {
190
+ if (!this.value || (this.forceNullValue && this.mode === 'fullTimeWithHoursDisabled' && this.control.pristine)) {
191
+ return undefined;
192
+ }
193
+ return this.value instanceof Date ? this.value.getMinutes() : this.value.minutes;
194
+ }
195
+ incrementValue(fieldType) {
196
+ if (fieldType === 'hours') {
197
+ this.onHoursChange$.next((this.hoursValue || 0) + 1);
198
+ }
199
+ else {
200
+ this.onMinutesChange$.next((this.minutesValue || 0) + this._step);
201
+ }
202
+ }
203
+ decrementValue(fieldType) {
204
+ if (fieldType === 'hours') {
205
+ this.onHoursChange$.next((this.hoursValue || 0) - 1);
206
+ }
207
+ else {
208
+ this.onMinutesChange$.next((this.minutesValue || 0) - this._step);
209
+ }
210
+ }
211
+ onClick(mode) {
212
+ if (this._autoFocus) {
213
+ if (mode === 'hours') {
214
+ this.hours?.nativeElement.select();
215
+ }
216
+ else {
217
+ this.minutes?.nativeElement.select();
218
+ }
219
+ }
220
+ }
221
+ // ************* ControlValueAccessor Implementation **************
222
+ /** set accessor including call the onchange callback */
223
+ set value(v) {
224
+ if (v !== this._value) {
225
+ this.writeValue(v);
226
+ this.onChangeCallback(v);
227
+ this.timeChange.emit(v);
228
+ }
229
+ }
230
+ /** get accessor */
231
+ get value() {
232
+ return this._value;
233
+ }
234
+ /** From ControlValueAccessor interface */
235
+ writeValue(value) {
236
+ if ((value ?? null) !== (this._value ?? null)) {
237
+ if (value instanceof Date) {
238
+ this._value = value ? new Date(value.getTime()) : set(new Date(), { hours: 0, minutes: 0, seconds: 0 });
239
+ }
240
+ else {
241
+ this._value = value;
242
+ }
243
+ this.changeDetectorRef.markForCheck();
244
+ }
245
+ }
246
+ /** From ControlValueAccessor interface */
247
+ registerOnChange(fn) {
248
+ this.onChangeCallback = fn;
249
+ }
250
+ /** From ControlValueAccessor interface */
251
+ registerOnTouched(fn) {
252
+ this.onTouchedCallback = fn;
253
+ }
254
+ setDisabledState(isDisabled) {
255
+ this.disabled = isDisabled;
256
+ }
257
+ }
258
+ TimePickerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TimePickerComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
259
+ TimePickerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TimePickerComponent, isStandalone: true, selector: "time-picker", inputs: { mode: "mode", dataType: "dataType", forceNullValue: "forceNullValue", appearance: "appearance", autoFocus: "autoFocus", defaultPlaceholderHours: "defaultPlaceholderHours", defaultPlaceholderMinutes: "defaultPlaceholderMinutes", time: "time", step: "step", disabled: "disabled" }, outputs: { timeChange: "timeChange" }, viewQueries: [{ propertyName: "hours", first: true, predicate: ["hours"], descendants: true }, { propertyName: "minutes", first: true, predicate: ["minutes"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<!-- Hours -->\n<mat-form-field [appearance]=\"appearance\" class=\"hours\" [class.disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [style.display]=\"mode === 'minutesOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n <input #hours matInput type=\"text\" [ngModel]=\"hoursValue | number:'2.'\" (change)=\"onHoursChange$.next($event)\" (keydown)=\"onKeyDown($event, 'hours')\" [disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderHours\" (click)=\"onClick('hours')\" />\n <numeric-stepper (increment)=\"incrementValue('hours')\" (decrement)=\"decrementValue('hours')\"></numeric-stepper>\n</mat-form-field>\n\n<!-- Separator -->\n<span class=\"time-separator\" [style.display]=\"mode === 'minutesOnly' || mode === 'hoursOnly' ? 'none' : 'block'\">:</span>\n\n<!-- Minutes -->\n<mat-form-field [appearance]=\"appearance\" class=\"minutes\" [class.disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [style.display]=\"mode === 'hoursOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n <input #minutes matInput type=\"text\" [ngModel]=\"minutesValue | number:'2.'\" (change)=\"onMinutesChange$.next($event)\" (keydown)=\"onKeyDown($event, 'minutes')\" [disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderMinutes\" (click)=\"onClick('minutes')\" />\n <numeric-stepper (increment)=\"incrementValue('minutes')\" (decrement)=\"decrementValue('minutes')\"></numeric-stepper>\n</mat-form-field>\n", styles: ["time-picker{display:flex;flex-direction:row;align-items:baseline;justify-content:center}time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper{padding-bottom:0}time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper .mat-form-field-infix{border-bottom:.7em solid transparent}time-picker mat-form-field[numeric-stepper-form-field]{width:48px}time-picker .time-separator{width:4px;font-size:14.5px;line-height:17px;margin:0 8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { 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: "component", type: NumericStepperComponent, selector: "numeric-stepper", inputs: ["layout", "input", "arrowIcons", "showOnInit"], outputs: ["increment", "decrement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
260
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TimePickerComponent, decorators: [{
261
+ type: Component,
262
+ args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'time-picker', encapsulation: ViewEncapsulation.None, standalone: true, imports: [
263
+ CommonModule,
264
+ FormsModule,
265
+ MatFormFieldModule,
266
+ MatInputModule,
267
+ NumericStepperComponent
268
+ ], template: "<!-- Hours -->\n<mat-form-field [appearance]=\"appearance\" class=\"hours\" [class.disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [style.display]=\"mode === 'minutesOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n <input #hours matInput type=\"text\" [ngModel]=\"hoursValue | number:'2.'\" (change)=\"onHoursChange$.next($event)\" (keydown)=\"onKeyDown($event, 'hours')\" [disabled]=\"disabled || mode === 'fullTimeWithHoursDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderHours\" (click)=\"onClick('hours')\" />\n <numeric-stepper (increment)=\"incrementValue('hours')\" (decrement)=\"decrementValue('hours')\"></numeric-stepper>\n</mat-form-field>\n\n<!-- Separator -->\n<span class=\"time-separator\" [style.display]=\"mode === 'minutesOnly' || mode === 'hoursOnly' ? 'none' : 'block'\">:</span>\n\n<!-- Minutes -->\n<mat-form-field [appearance]=\"appearance\" class=\"minutes\" [class.disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [style.display]=\"mode === 'hoursOnly' ? 'none' : 'block'\" floatLabel=\"never\">\n <input #minutes matInput type=\"text\" [ngModel]=\"minutesValue | number:'2.'\" (change)=\"onMinutesChange$.next($event)\" (keydown)=\"onKeyDown($event, 'minutes')\" [disabled]=\"disabled || mode === 'fullTimeWithMinutesDisabled'\" [maxLength]=\"2\" autocomplete=\"off\" [placeholder]=\"defaultPlaceholderMinutes\" (click)=\"onClick('minutes')\" />\n <numeric-stepper (increment)=\"incrementValue('minutes')\" (decrement)=\"decrementValue('minutes')\"></numeric-stepper>\n</mat-form-field>\n", styles: ["time-picker{display:flex;flex-direction:row;align-items:baseline;justify-content:center}time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper{padding-bottom:0}time-picker:not([inform]) .mat-form-field-appearance-outline .mat-form-field-wrapper .mat-form-field-infix{border-bottom:.7em solid transparent}time-picker mat-form-field[numeric-stepper-form-field]{width:48px}time-picker .time-separator{width:4px;font-size:14.5px;line-height:17px;margin:0 8px}\n"] }]
269
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i1.NgControl, decorators: [{
270
+ type: Self
271
+ }, {
272
+ type: Optional
273
+ }] }]; }, propDecorators: { hours: [{
274
+ type: ViewChild,
275
+ args: ['hours']
276
+ }], minutes: [{
277
+ type: ViewChild,
278
+ args: ['minutes']
279
+ }], timeChange: [{
280
+ type: Output
281
+ }], mode: [{
282
+ type: Input
283
+ }], dataType: [{
284
+ type: Input
285
+ }], forceNullValue: [{
286
+ type: Input
287
+ }], appearance: [{
288
+ type: Input
289
+ }], autoFocus: [{
290
+ type: Input
291
+ }], defaultPlaceholderHours: [{
292
+ type: Input
293
+ }], defaultPlaceholderMinutes: [{
294
+ type: Input
295
+ }], time: [{
296
+ type: Input
297
+ }], step: [{
298
+ type: Input
299
+ }], disabled: [{
300
+ type: Input
301
+ }] } });
302
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcHJvamVjdHMvdGltZS1waWNrZXIvc3JjL3RpbWUtcGlja2VyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL3Byb2plY3RzL3RpbWUtcGlja2VyL3NyYy90aW1lLXBpY2tlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWdCLHFCQUFxQixFQUFFLG9CQUFvQixFQUFlLE1BQU0sdUJBQXVCLENBQUM7QUFDL0csT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSx1QkFBdUIsRUFBcUIsU0FBUyxFQUFjLFlBQVksRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdLLE9BQU8sRUFBd0IsV0FBVyxFQUFhLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUUsT0FBTyxFQUEwQixrQkFBa0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzFGLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxRQUFRLEVBQUUsb0JBQW9CLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7Ozs7QUFVdEYsZ0NBQWdDO0FBZ0JoQyxNQUFNLE9BQU8sbUJBQW9CLFNBQVEsT0FBTztJQXNFNUMsWUFDWSxpQkFBb0MsRUFDakIsT0FBa0I7UUFFN0MsS0FBSyxFQUFFLENBQUM7UUFIQSxzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ2pCLFlBQU8sR0FBUCxPQUFPLENBQVc7UUFwRXZCLGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBa0IsQ0FBQztRQUUxRSx1Q0FBdUM7UUFDdkIsU0FBSSxHQUEwQixVQUFVLENBQUM7UUFFekQsNkNBQTZDO1FBQzdCLGFBQVEsR0FBYSxNQUFNLENBQUM7UUFFNUM7Ozs7O1dBS0c7UUFDYSxtQkFBYyxHQUFHLEtBQUssQ0FBQztRQUV2QixlQUFVLEdBQTJCLFNBQVMsQ0FBQztRQU8vQyw0QkFBdUIsR0FBRyxLQUFLLENBQUM7UUFDaEMsOEJBQXlCLEdBQUcsS0FBSyxDQUFDO1FBbUMzQyxtQkFBYyxHQUFHLElBQUksT0FBTyxFQUFrQixDQUFDO1FBQy9DLHFCQUFnQixHQUFHLElBQUksT0FBTyxFQUFrQixDQUFDO1FBQ2pELFVBQUssR0FBRyxDQUFDLENBQUM7UUFDVCxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBRWxCLGVBQVUsR0FBRyxJQUFJLENBQUM7UUFpTjFCLDBFQUEwRTtRQUVoRSxxQkFBZ0IsR0FBRyxDQUFDLEVBQVcsRUFBUSxFQUFFLENBQUMsU0FBUyxDQUFDO1FBQ3BELHNCQUFpQixHQUFHLEdBQVMsRUFBRSxDQUFDLFNBQVMsQ0FBQztRQTVNaEQsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ2QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDO1NBQ3JDO1FBRUQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQ3BCLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLEtBQUssS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFDNUQsb0JBQW9CLEVBQUUsRUFDdEIsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ1IsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUU7Z0JBQzNCLE1BQU0sS0FBSyxHQUFJLEtBQUssQ0FBQyxNQUEyQixDQUFDLEtBQUssQ0FBQztnQkFDdkQsT0FBTyxDQUFDLEtBQUssS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQVUsQ0FBQzthQUNqRjtZQUNELE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFVLENBQUM7UUFDdkQsQ0FBQyxDQUFDLEVBQ0YsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FDN0IsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFO1lBQzdCLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFO2dCQUNiLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBYyxDQUFDO2FBQ25KO2lCQUFNLElBQUksSUFBSSxDQUFDLEtBQUssWUFBWSxJQUFJLEVBQUU7Z0JBQ25DLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUM7Z0JBQ3BDLE1BQU0sS0FBSyxHQUFHLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUM5QixJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUU7b0JBQ3JCLEtBQUssQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7aUJBQ3pCO2dCQUNELElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO2FBQ3RCO2lCQUFNO2dCQUNILElBQUksQ0FBQyxLQUFLLEdBQUc7b0JBQ1QsS0FBSyxFQUFFLEtBQUssSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUs7b0JBQ3JDLE9BQU8sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU87aUJBQzlCLENBQUM7YUFDTDtZQUNELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUV0QyxJQUFJLE9BQU8sSUFBSSxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUU7Z0JBQzVDLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQztvQkFDN0IsYUFBYSxFQUFFLElBQUk7aUJBQ3RCLENBQUMsQ0FBQztnQkFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQzthQUN2QztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FDdEIsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sT0FBTyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUNoRSxvQkFBb0IsRUFBRSxFQUN0QixHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDUixJQUFJLE9BQTJCLENBQUM7WUFDaEMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUU7Z0JBQzNCLE1BQU0sS0FBSyxHQUFJLEtBQUssQ0FBQyxNQUEyQixDQUFDLEtBQUssQ0FBQztnQkFDdkQsT0FBTyxHQUFHLEtBQUssS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQzthQUNuRTtpQkFBTTtnQkFDSCxPQUFPLEdBQUcsS0FBSyxDQUFDO2FBQ25CO1lBQ0QsT0FBTyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksT0FBTyxJQUFJLENBQUMsQ0FBQztRQUN0RCxDQUFDLENBQUMsRUFDRixTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUM3QixDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUNsQixJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRTtnQkFDYixJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsWUFBWSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQWMsQ0FBQzthQUNuSjtpQkFBTSxJQUFJLElBQUksQ0FBQyxLQUFLLFlBQVksSUFBSSxFQUFFO2dCQUNuQyxNQUFNLFFBQVEsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7Z0JBQ2hELElBQUksT0FBTyxHQUFHLENBQUMsRUFBRTtvQkFDYixPQUFPLElBQUksRUFBRSxDQUFDO2lCQUNqQjtxQkFBTSxJQUFJLE9BQU8sSUFBSSxFQUFFLEVBQUU7b0JBQ3RCLE9BQU8sSUFBSSxFQUFFLENBQUM7aUJBQ2pCO2dCQUNELFFBQVEsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBRTdCLElBQUksSUFBSSxDQUFDLElBQUksS0FBSywyQkFBMkIsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssMkJBQTJCLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUMsRUFBRTtvQkFDOUgsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUM7aUJBQ3pCO2FBQ0o7aUJBQU07Z0JBQ0gsSUFBSSxDQUFDLEtBQUssR0FBRztvQkFDVCxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLO29CQUN2QixPQUFPLEVBQUUsT0FBTyxHQUFHLENBQUMsSUFBSSxPQUFPLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU87aUJBQ3RELENBQUM7YUFDTDtZQUNELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUMxQyxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFwSUQsSUFDVyxTQUFTLENBQUMsS0FBbUI7UUFDcEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxxQkFBcUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBS0QsSUFDVyxJQUFJLENBQUMsS0FBaUM7UUFDN0MsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMzQixDQUFDO0lBRUQsSUFBVyxJQUFJO1FBQ1gsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ3RCLENBQUM7SUFFRCx5QkFBeUI7SUFDekIsSUFDVyxJQUFJLENBQUMsS0FBa0I7UUFDOUIsSUFBSSxDQUFDLEtBQUssR0FBRyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsaUJBQWlCLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDMUMsQ0FBQztJQUVELDRDQUE0QztJQUM1QyxJQUFXLElBQUk7UUFDWCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDdEIsQ0FBQztJQUVELHFIQUFxSDtJQUNySCxJQUNXLFFBQVEsQ0FBQyxLQUFtQjtRQUNuQyxJQUFJLENBQUMsU0FBUyxHQUFHLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUMxQyxDQUFDO0lBRUQsaUNBQWlDO0lBQ2pDLElBQVcsUUFBUTtRQUNmLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUMxQixDQUFDO0lBK0ZNLFNBQVMsQ0FBQyxNQUFxQixFQUFFLElBQXlCO1FBQzdELG9CQUFvQjtRQUNwQixNQUFNLFlBQVksR0FBRyxJQUFJLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7UUFDaEcsSUFBSSxNQUFNLENBQUMsR0FBRyxFQUFFLFdBQVcsRUFBRSxLQUFLLEdBQUcsRUFBRTtZQUNuQyxNQUFNLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDekIsTUFBTSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztTQUMzQjthQUFNLElBQUksWUFBWSxFQUFFO1lBQ3JCLElBQUksTUFBTSxDQUFDLEdBQUcsRUFBRSxXQUFXLEVBQUUsS0FBSyxHQUFHLElBQUksTUFBTSxDQUFDLE9BQU8sRUFBRTtnQkFDckQsWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQ3pCO2lCQUFNLElBQUksTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDM0osOEZBQThGO2dCQUM5RixJQUFJLEtBQUssQ0FBQztnQkFDVixJQUFJLElBQUksS0FBSyxPQUFPLEVBQUU7b0JBQ2xCLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztpQkFDekU7cUJBQU07b0JBQ0gsS0FBSyxHQUFHLGdCQUFnQixDQUFDO2lCQUM1QjtnQkFFRCxxQ0FBcUM7Z0JBQ3JDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsWUFBWSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsY0FBYyxJQUFJLENBQUMsRUFBRSxZQUFZLENBQUMsWUFBWSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDaEksTUFBTSxhQUFhLEdBQUcsWUFBWSxHQUFHLGNBQWMsQ0FBQztnQkFFcEQsZ0ZBQWdGO2dCQUNoRixNQUFNLFVBQVUsR0FBRyxZQUFZLENBQUMsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDNUMsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDN0MsYUFBYSxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsYUFBYSxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDaEUsTUFBTSxhQUFhLEdBQUcsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFFN0MseUNBQXlDO2dCQUN6QyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRTtvQkFDNUIsTUFBTSxDQUFDLGVBQWUsRUFBRSxDQUFDO29CQUN6QixNQUFNLENBQUMsY0FBYyxFQUFFLENBQUM7aUJBQzNCO3FCQUFNLElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxJQUFJLEtBQUssT0FBTyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxLQUFLLE1BQU0sSUFBSSxVQUFVLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksYUFBYSxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsRUFBRTtvQkFDNUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7aUJBQ3BDO2FBQ0o7U0FDSjtJQUNMLENBQUM7SUFFRCxJQUFXLFVBQVU7UUFDakIsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssNkJBQTZCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRTtZQUM5RyxPQUFPLFNBQVMsQ0FBQztTQUNwQjtRQUNELE9BQU8sSUFBSSxDQUFDLEtBQUssWUFBWSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO0lBQ2pGLENBQUM7SUFFRCxJQUFXLFlBQVk7UUFDbkIsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFJLElBQUksQ0FBQyxJQUFJLEtBQUssMkJBQTJCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRTtZQUM1RyxPQUFPLFNBQVMsQ0FBQztTQUNwQjtRQUNELE9BQU8sSUFBSSxDQUFDLEtBQUssWUFBWSxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDO0lBQ3JGLENBQUM7SUFFTSxjQUFjLENBQUMsU0FBb0I7UUFDdEMsSUFBSSxTQUFTLEtBQUssT0FBTyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztTQUN4RDthQUFNO1lBQ0gsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQ3JFO0lBQ0wsQ0FBQztJQUVNLGNBQWMsQ0FBQyxTQUFvQjtRQUN0QyxJQUFJLFNBQVMsS0FBSyxPQUFPLEVBQUU7WUFDdkIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1NBQ3hEO2FBQU07WUFDSCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLFlBQVksSUFBSSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDckU7SUFDTCxDQUFDO0lBRU0sT0FBTyxDQUFDLElBQXlCO1FBQ3BDLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRTtZQUNqQixJQUFJLElBQUksS0FBSyxPQUFPLEVBQUU7Z0JBQ2xCLElBQUksQ0FBQyxLQUFLLEVBQUUsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQ3RDO2lCQUFNO2dCQUNILElBQUksQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQ3hDO1NBQ0o7SUFDTCxDQUFDO0lBRUQsbUVBQW1FO0lBQ25FLHdEQUF3RDtJQUN4RCxJQUFXLEtBQUssQ0FBQyxDQUE2QjtRQUMxQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ25CLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbkIsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3pCLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQzNCO0lBQ0wsQ0FBQztJQUVELG1CQUFtQjtJQUNuQixJQUFXLEtBQUs7UUFDWixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVELDBDQUEwQztJQUNuQyxVQUFVLENBQUMsS0FBaUM7UUFDL0MsSUFBSSxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLEVBQUU7WUFDM0MsSUFBSSxLQUFLLFlBQVksSUFBSSxFQUFFO2dCQUN2QixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2FBQzNHO2lCQUFNO2dCQUNILElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDO2FBQ3ZCO1lBRUQsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFlBQVksRUFBRSxDQUFDO1NBQ3pDO0lBQ0wsQ0FBQztJQUVELDBDQUEwQztJQUNuQyxnQkFBZ0IsQ0FBQyxFQUF5QjtRQUM3QyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRCwwQ0FBMEM7SUFDbkMsaUJBQWlCLENBQUMsRUFBYztRQUNuQyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFTSxnQkFBZ0IsQ0FBQyxVQUFtQjtRQUN2QyxJQUFJLENBQUMsUUFBUSxHQUFHLFVBQVUsQ0FBQztJQUMvQixDQUFDOztnSEFwUlEsbUJBQW1CO29HQUFuQixtQkFBbUIsNGxCQ25DaEMsNmpEQWNBLGdpQkRjUSxZQUFZLHNGQUNaLFdBQVcsOG1CQUNYLGtCQUFrQixzTkFDbEIsY0FBYywyV0FDZCx1QkFBdUI7MkZBR2xCLG1CQUFtQjtrQkFmL0IsU0FBUztzQ0FDVyx1QkFBdUIsQ0FBQyxNQUFNLFlBQ3JDLGFBQWEsaUJBR1IsaUJBQWlCLENBQUMsSUFBSSxjQUN6QixJQUFJLFdBQ1A7d0JBQ0wsWUFBWTt3QkFDWixXQUFXO3dCQUNYLGtCQUFrQjt3QkFDbEIsY0FBYzt3QkFDZCx1QkFBdUI7cUJBQzFCOzswQkEwRUksSUFBSTs7MEJBQUksUUFBUTs0Q0F2RU0sS0FBSztzQkFBL0IsU0FBUzt1QkFBQyxPQUFPO2dCQUNXLE9BQU87c0JBQW5DLFNBQVM7dUJBQUMsU0FBUztnQkFFTSxVQUFVO3NCQUFuQyxNQUFNO2dCQUdTLElBQUk7c0JBQW5CLEtBQUs7Z0JBR1UsUUFBUTtzQkFBdkIsS0FBSztnQkFRVSxjQUFjO3NCQUE3QixLQUFLO2dCQUVVLFVBQVU7c0JBQXpCLEtBQUs7Z0JBR0ssU0FBUztzQkFEbkIsS0FBSztnQkFLVSx1QkFBdUI7c0JBQXRDLEtBQUs7Z0JBQ1UseUJBQXlCO3NCQUF4QyxLQUFLO2dCQUdLLElBQUk7c0JBRGQsS0FBSztnQkFXSyxJQUFJO3NCQURkLEtBQUs7Z0JBYUssUUFBUTtzQkFEbEIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJvb2xlYW5JbnB1dCwgY29lcmNlQm9vbGVhblByb3BlcnR5LCBjb2VyY2VOdW1iZXJQcm9wZXJ0eSwgTnVtYmVySW5wdXQgfSBmcm9tICdAYW5ndWxhci9jZGsvY29lcmNpb24nO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDaGFuZ2VEZXRlY3RvclJlZiwgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBFdmVudEVtaXR0ZXIsIElucHV0LCBPcHRpb25hbCwgT3V0cHV0LCBTZWxmLCBWaWV3Q2hpbGQsIFZpZXdFbmNhcHN1bGF0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgRm9ybXNNb2R1bGUsIE5nQ29udHJvbCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IE1hdEZvcm1GaWVsZEFwcGVhcmFuY2UsIE1hdEZvcm1GaWVsZE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xuaW1wb3J0IHsgTWF0SW5wdXRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9pbnB1dCc7XG5pbXBvcnQgeyBEZXN0cm95IH0gZnJvbSAnQGh1Zy9uZ3gtY29yZSc7XG5pbXBvcnQgeyBOdW1lcmljU3RlcHBlckNvbXBvbmVudCB9IGZyb20gJ0BodWcvbmd4LW51bWVyaWMtc3RlcHBlcic7XG5pbXBvcnQgeyBpc1NhbWVIb3VyLCBzZXQgfSBmcm9tICdkYXRlLWZucyc7XG5pbXBvcnQgeyBkZWJvdW5jZSwgZGlzdGluY3RVbnRpbENoYW5nZWQsIG1hcCwgU3ViamVjdCwgdGFrZVVudGlsLCB0aW1lciB9IGZyb20gJ3J4anMnO1xuXG5leHBvcnQgdHlwZSBUaW1lUGlja2VyRGlzcGxheU1vZGUgPSAnZnVsbFRpbWUnIHwgJ2Z1bGxUaW1lV2l0aEhvdXJzRGlzYWJsZWQnIHwgJ2Z1bGxUaW1lV2l0aE1pbnV0ZXNEaXNhYmxlZCcgfCAnaG91cnNPbmx5JyB8ICdtaW51dGVzT25seSc7XG5cbmV4cG9ydCB0eXBlIERhdGVPckR1cmF0aW9uID0gRGF0ZSB8IER1cmF0aW9uO1xuXG50eXBlIERhdGFUeXBlID0gJ2RhdGUnIHwgJ2R1cmF0aW9uJztcblxudHlwZSBGaWVsZFR5cGUgPSAnaG91cnMnIHwgJ21pbnV0ZXMnO1xuXG4vLyBUT0RPIHNkaWwgcmVmYWN0b3IgcnhqcyBmbG93c1xuQENvbXBvbmVudCh7XG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gICAgc2VsZWN0b3I6ICd0aW1lLXBpY2tlcicsXG4gICAgc3R5bGVVcmxzOiBbJy4vdGltZS1waWNrZXIuY29tcG9uZW50LnNjc3MnXSxcbiAgICB0ZW1wbGF0ZVVybDogJy4vdGltZS1waWNrZXIuY29tcG9uZW50Lmh0bWwnLFxuICAgIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gICAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgICBpbXBvcnRzOiBbXG4gICAgICAgIENvbW1vbk1vZHVsZSxcbiAgICAgICAgRm9ybXNNb2R1bGUsXG4gICAgICAgIE1hdEZvcm1GaWVsZE1vZHVsZSxcbiAgICAgICAgTWF0SW5wdXRNb2R1bGUsXG4gICAgICAgIE51bWVyaWNTdGVwcGVyQ29tcG9uZW50XG4gICAgXVxufSlcbmV4cG9ydCBjbGFzcyBUaW1lUGlja2VyQ29tcG9uZW50IGV4dGVuZHMgRGVzdHJveSBpbXBsZW1lbnRzIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcbiAgICBAVmlld0NoaWxkKCdob3VycycpIHB1YmxpYyBob3Vycz86IEVsZW1lbnRSZWY8SFRNTElucHV0RWxlbWVudD47XG4gICAgQFZpZXdDaGlsZCgnbWludXRlcycpIHB1YmxpYyBtaW51dGVzPzogRWxlbWVudFJlZjxIVE1MSW5wdXRFbGVtZW50PjtcblxuICAgIEBPdXRwdXQoKSBwdWJsaWMgcmVhZG9ubHkgdGltZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8RGF0ZU9yRHVyYXRpb24+KCk7XG5cbiAgICAvKiogRGlzcGxheSBtb2RlIGZvciB0aGUgdGltZS1waWNrZXIgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgbW9kZTogVGltZVBpY2tlckRpc3BsYXlNb2RlID0gJ2Z1bGxUaW1lJztcblxuICAgIC8qKiBEYXRhIHR5cGUgdG8gbWFuYWdlIChEYXRlIG9yIER1cmF0aW9uKSAqL1xuICAgIEBJbnB1dCgpIHB1YmxpYyBkYXRhVHlwZTogRGF0YVR5cGUgPSAnZGF0ZSc7XG5cbiAgICAvKipcbiAgICAgKiBGb3JjZSB0aGUgaG91ciBvciBtaW51dGUgdG8gYmUgbnVsbCAob25seSBpZiB0aGUgb3RoZXIgZmllbGQgaXMgZGlzYWJsZWQpXG4gICAgICpcbiAgICAgKiBGb3IgaW5zdGFuY2UsIGlmIHNldCB0byB0cnVlIGFuZCB0aGUgaG91cnMgYXJlIGRpc2FibGVkLCB0aGUgbWludXRlcyBpbnB1dCB2YWx1ZSB3aWxsIGJlIG51bGxcbiAgICAgKiBUaGlzIGlzIHVzZWZ1bCB0byBmb3JjZSB0aGUgdXNlciB0byBwcm92aWRlIGEgdmFsdWVcbiAgICAgKi9cbiAgICBASW5wdXQoKSBwdWJsaWMgZm9yY2VOdWxsVmFsdWUgPSBmYWxzZTtcblxuICAgIEBJbnB1dCgpIHB1YmxpYyBhcHBlYXJhbmNlOiBNYXRGb3JtRmllbGRBcHBlYXJhbmNlID0gJ291dGxpbmUnO1xuXG4gICAgQElucHV0KClcbiAgICBwdWJsaWMgc2V0IGF1dG9Gb2N1cyh2YWx1ZTogQm9vbGVhbklucHV0KSB7XG4gICAgICAgIHRoaXMuX2F1dG9Gb2N1cyA9IGNvZXJjZUJvb2xlYW5Qcm9wZXJ0eSh2YWx1ZSk7XG4gICAgfVxuXG4gICAgQElucHV0KCkgcHVibGljIGRlZmF1bHRQbGFjZWhvbGRlckhvdXJzID0gJ18gXyc7XG4gICAgQElucHV0KCkgcHVibGljIGRlZmF1bHRQbGFjZWhvbGRlck1pbnV0ZXMgPSAnXyBfJztcblxuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHNldCB0aW1lKHZhbHVlOiBEYXRlT3JEdXJhdGlvbiB8IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLndyaXRlVmFsdWUodmFsdWUpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgdGltZSgpOiBEYXRlT3JEdXJhdGlvbiB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlO1xuICAgIH1cblxuICAgIC8qKiBTdGVwIG9mIHRoZSBhcnJvd3MgKi9cbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBzZXQgc3RlcCh2YWx1ZTogTnVtYmVySW5wdXQpIHtcbiAgICAgICAgdGhpcy5fc3RlcCA9IGNvZXJjZU51bWJlclByb3BlcnR5KHZhbHVlKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG5cbiAgICAvKiogVG8gZ2V0IHRoZSBzdGVwIG9mIHRoZSBtaW51dGVzIGFycm93cyAqL1xuICAgIHB1YmxpYyBnZXQgc3RlcCgpOiBOdW1iZXJJbnB1dCB7XG4gICAgICAgIHJldHVybiB0aGlzLl9zdGVwO1xuICAgIH1cblxuICAgIC8qKiBEaXNhYmxlZCBwcm9wZXJ0eSBzZXR0ZXIuIENhbiBiZSBzdHJpbmcgb3IgZW1wdHkgc28geW91IGNhbiB1c2UgaXQgbGlrZSA6IDx0aW1lLXBpY2tlciBkaXNhYmxlZD48L3RpbWUtcGlja2VyPiAqL1xuICAgIEBJbnB1dCgpXG4gICAgcHVibGljIHNldCBkaXNhYmxlZCh2YWx1ZTogQm9vbGVhbklucHV0KSB7XG4gICAgICAgIHRoaXMuX2Rpc2FibGVkID0gY29lcmNlQm9vbGVhblByb3BlcnR5KHZhbHVlKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICB9XG5cbiAgICAvKiogVG8gZ2V0IGRpc2FibGVkIGF0dHJpYnV0ZS4gKi9cbiAgICBwdWJsaWMgZ2V0IGRpc2FibGVkKCk6IEJvb2xlYW5JbnB1dCB7XG4gICAgICAgIHJldHVybiB0aGlzLl9kaXNhYmxlZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgb25Ib3Vyc0NoYW5nZSQgPSBuZXcgU3ViamVjdDxFdmVudCB8IG51bWJlcj4oKTtcbiAgICBwdWJsaWMgb25NaW51dGVzQ2hhbmdlJCA9IG5ldyBTdWJqZWN0PEV2ZW50IHwgbnVtYmVyPigpO1xuICAgIHB1YmxpYyBfc3RlcCA9IDE7XG4gICAgcHJpdmF0ZSBfZGlzYWJsZWQgPSBmYWxzZTtcbiAgICBwcml2YXRlIF92YWx1ZT86IERhdGVPckR1cmF0aW9uO1xuICAgIHByaXZhdGUgX2F1dG9Gb2N1cyA9IHRydWU7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgY2hhbmdlRGV0ZWN0b3JSZWY6IENoYW5nZURldGVjdG9yUmVmLFxuICAgICAgICBAU2VsZigpIEBPcHRpb25hbCgpIHB1YmxpYyBjb250cm9sOiBOZ0NvbnRyb2xcbiAgICApIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICBpZiAodGhpcy5jb250cm9sKSB7XG4gICAgICAgICAgICB0aGlzLmNvbnRyb2wudmFsdWVBY2Nlc3NvciA9IHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm9uSG91cnNDaGFuZ2UkLnBpcGUoXG4gICAgICAgICAgICBkZWJvdW5jZShob3VycyA9PiB0aW1lcih0eXBlb2YgaG91cnMgPT09ICdvYmplY3QnID8gMCA6IDEwKSksXG4gICAgICAgICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxuICAgICAgICAgICAgbWFwKGhvdXJzID0+IHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGhvdXJzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZSA9IChob3Vycy50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkudmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBbdmFsdWUgIT09IHVuZGVmaW5lZCA/IHBhcnNlSW50KHZhbHVlLCAxMCkgOiB1bmRlZmluZWQsIHRydWVdIGFzIGNvbnN0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gWyFpc05hTihob3VycykgPyBob3VycyA6IDAsIGZhbHNlXSBhcyBjb25zdDtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveWVkJClcbiAgICAgICAgKS5zdWJzY3JpYmUoKFtob3VycywgaXNFdmVudF0pID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy52YWx1ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUgPSB0aGlzLmRhdGFUeXBlID09PSAnZGF0ZScgPyBzZXQobmV3IERhdGUoKSwgeyBob3VycywgbWludXRlczogMCwgc2Vjb25kczogMCwgbWlsbGlzZWNvbmRzOiAwIH0pIDogeyBob3VycywgbWludXRlczogMCB9IGFzIER1cmF0aW9uO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLnZhbHVlIGluc3RhbmNlb2YgRGF0ZSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy52YWx1ZT8uZ2V0VGltZSgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGNsb25lID0gbmV3IERhdGUodmFsdWUpO1xuICAgICAgICAgICAgICAgIGlmIChob3VycyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGNsb25lLnNldEhvdXJzKGhvdXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy52YWx1ZSA9IGNsb25lO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0ge1xuICAgICAgICAgICAgICAgICAgICBob3VyczogaG91cnMgJiYgaG91cnMgPCAwID8gMCA6IGhvdXJzLFxuICAgICAgICAgICAgICAgICAgICBtaW51dGVzOiB0aGlzLnZhbHVlLm1pbnV0ZXNcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcblxuICAgICAgICAgICAgaWYgKGlzRXZlbnQgJiYgdGhpcy5fYXV0b0ZvY3VzICYmIHRoaXMubWludXRlcykge1xuICAgICAgICAgICAgICAgIHRoaXMubWludXRlcy5uYXRpdmVFbGVtZW50LmZvY3VzKHtcbiAgICAgICAgICAgICAgICAgICAgcHJldmVudFNjcm9sbDogdHJ1ZVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMubWludXRlcy5uYXRpdmVFbGVtZW50LnNlbGVjdCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLm9uTWludXRlc0NoYW5nZSQucGlwZShcbiAgICAgICAgICAgIGRlYm91bmNlKG1pbnV0ZXMgPT4gdGltZXIodHlwZW9mIG1pbnV0ZXMgPT09ICdvYmplY3QnID8gMCA6IDEwKSksXG4gICAgICAgICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxuICAgICAgICAgICAgbWFwKGV2ZW50ID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgbWludXRlczogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZXZlbnQgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gKGV2ZW50LnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS52YWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgbWludXRlcyA9IHZhbHVlICE9PSB1bmRlZmluZWQgPyBwYXJzZUludCh2YWx1ZSwgMTApIDogdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG1pbnV0ZXMgPSBldmVudDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1pbnV0ZXMgJiYgIWlzTmFOKG1pbnV0ZXMpICYmIG1pbnV0ZXMgfHwgMDtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveWVkJClcbiAgICAgICAgKS5zdWJzY3JpYmUobWludXRlcyA9PiB7XG4gICAgICAgICAgICBpZiAoIXRoaXMudmFsdWUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0gdGhpcy5kYXRhVHlwZSA9PT0gJ2RhdGUnID8gc2V0KG5ldyBEYXRlKCksIHsgaG91cnM6IDAsIG1pbnV0ZXMsIHNlY29uZHM6IDAsIG1pbGxpc2Vjb25kczogMCB9KSA6IHsgaG91cnM6IDAsIG1pbnV0ZXMgfSBhcyBEdXJhdGlvbjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy52YWx1ZSBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXdWYWx1ZSA9IG5ldyBEYXRlKHRoaXMudmFsdWUuZ2V0VGltZSgpKTtcbiAgICAgICAgICAgICAgICBpZiAobWludXRlcyA8IDApIHtcbiAgICAgICAgICAgICAgICAgICAgbWludXRlcyArPSA2MDtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1pbnV0ZXMgPj0gNjApIHtcbiAgICAgICAgICAgICAgICAgICAgbWludXRlcyAtPSA2MDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbmV3VmFsdWUuc2V0TWludXRlcyhtaW51dGVzKTtcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLm1vZGUgIT09ICdmdWxsVGltZVdpdGhIb3Vyc0Rpc2FibGVkJyB8fCAodGhpcy5tb2RlID09PSAnZnVsbFRpbWVXaXRoSG91cnNEaXNhYmxlZCcgJiYgaXNTYW1lSG91cih0aGlzLnZhbHVlLCBuZXdWYWx1ZSkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudmFsdWUgPSBuZXdWYWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUgPSB7XG4gICAgICAgICAgICAgICAgICAgIGhvdXJzOiB0aGlzLnZhbHVlLmhvdXJzLFxuICAgICAgICAgICAgICAgICAgICBtaW51dGVzOiBtaW51dGVzIDwgMCB8fCBtaW51dGVzID49IDYwID8gMCA6IG1pbnV0ZXNcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIG9uS2V5RG93bigkZXZlbnQ6IEtleWJvYXJkRXZlbnQsIG1vZGU6ICdob3VycycgfCAnbWludXRlcycpOiB2b2lkIHtcbiAgICAgICAgLy8gR2V0IGlucHV0IGVsZW1lbnRcbiAgICAgICAgY29uc3QgaW5wdXRFbGVtZW50ID0gbW9kZSA9PT0gJ2hvdXJzJyA/IHRoaXMuaG91cnM/Lm5hdGl2ZUVsZW1lbnQgOiB0aGlzLm1pbnV0ZXM/Lm5hdGl2ZUVsZW1lbnQ7XG4gICAgICAgIGlmICgkZXZlbnQua2V5Py50b0xvd2VyQ2FzZSgpID09PSAnZCcpIHtcbiAgICAgICAgICAgICRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgdGhpcy52YWx1ZSA9IG5ldyBEYXRlKCk7XG4gICAgICAgIH0gZWxzZSBpZiAoaW5wdXRFbGVtZW50KSB7XG4gICAgICAgICAgICBpZiAoJGV2ZW50LmtleT8udG9Mb3dlckNhc2UoKSA9PT0gJ2EnICYmICRldmVudC5jdHJsS2V5KSB7XG4gICAgICAgICAgICAgICAgaW5wdXRFbGVtZW50LnNlbGVjdCgpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICgkZXZlbnQua2V5ICYmICFbJ0Fycm93VXAnLCAnQXJyb3dEb3duJywgJ0Fycm93TGVmdCcsICdBcnJvd1JpZ2h0JywgJ0JhY2tzcGFjZScsICdEZWxldGUnLCAnVGFiJywgJ0VudGVyJywgJ0NvbnRyb2wnLCAnU2hpZnQnXS5pbmNsdWRlcygkZXZlbnQua2V5KSkge1xuICAgICAgICAgICAgICAgIC8vIFNldCByZWdleCBmb3IgaW5wdXQgZm9ybWF0IHZhbGlkYXRpb24gKGRpZmZlcnMgaWYgd2UgYXJlIGRlYWxpbmcgd2l0aCBhIGRhdGUgb3IgYSBkdXJhdGlvbilcbiAgICAgICAgICAgICAgICBsZXQgcmVnZXg7XG4gICAgICAgICAgICAgICAgaWYgKG1vZGUgPT09ICdob3VycycpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVnZXggPSB0aGlzLmRhdGFUeXBlID09PSAnZGF0ZScgPyAvXihcXGR8WzAxXVxcZHwyWzAtM10pJC8gOiAvXihcXGQrKSQvO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJlZ2V4ID0gL14oXFxkfFswLTVdXFxkKSQvO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgc2VsZWN0aW9uIGluIGlucHV0IGVsZW1lbnRcbiAgICAgICAgICAgICAgICBjb25zdCBbc2VsZWN0aW9uU3RhcnQsIHNlbGVjdGlvbkVuZF0gPSBbaW5wdXRFbGVtZW50LnNlbGVjdGlvblN0YXJ0IHx8IDAsIGlucHV0RWxlbWVudC5zZWxlY3Rpb25FbmQgfHwgMF0uc29ydCgoYSwgYikgPT4gYSAtIGIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNlbGVjdGlvbkRpZmYgPSBzZWxlY3Rpb25FbmQgLSBzZWxlY3Rpb25TdGFydDtcblxuICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgY3VycmVudCB2YWx1ZSBpbiBpbnB1dCBlbGVtZW50IGFuZCB1cGRhdGUgaXQgd2l0aCB0aGUgbmV3IHRvdWNoZWQga2V5XG4gICAgICAgICAgICAgICAgY29uc3QgaW5wdXRWYWx1ZSA9IGlucHV0RWxlbWVudC52YWx1ZSB8fCAnJztcbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dFZhbHVlQXJyID0gQXJyYXkuZnJvbShpbnB1dFZhbHVlKTtcbiAgICAgICAgICAgICAgICBpbnB1dFZhbHVlQXJyLnNwbGljZShzZWxlY3Rpb25TdGFydCwgc2VsZWN0aW9uRGlmZiwgJGV2ZW50LmtleSk7XG4gICAgICAgICAgICAgICAgY29uc3QgbmV3SW5wdXRWYWx1ZSA9IGlucHV0VmFsdWVBcnIuam9pbignJyk7XG5cbiAgICAgICAgICAgICAgICAvLyBQcmV2ZW50IGV2ZW50IGlmIHRoZSB0aW1lIGlzIG5vdCB2YWxpZFxuICAgICAgICAgICAgICAgIGlmICghcmVnZXgudGVzdChuZXdJbnB1dFZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICAgICAgICAgICRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5fYXV0b0ZvY3VzICYmIG1vZGUgPT09ICdob3VycycgJiYgKCh0aGlzLmRhdGFUeXBlID09PSAnZGF0ZScgJiYgcGFyc2VGbG9hdChuZXdJbnB1dFZhbHVlKSA+PSAzKSB8fCBuZXdJbnB1dFZhbHVlLmxlbmd0aCA9PT0gMikpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vbkhvdXJzQ2hhbmdlJC5uZXh0KCRldmVudCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBob3Vyc1ZhbHVlKCk6IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGlmICghdGhpcy52YWx1ZSB8fCAodGhpcy5mb3JjZU51bGxWYWx1ZSAmJiB0aGlzLm1vZGUgPT09ICdmdWxsVGltZVdpdGhNaW51dGVzRGlzYWJsZWQnICYmIHRoaXMuY29udHJvbC5wcmlzdGluZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWUgaW5zdGFuY2VvZiBEYXRlID8gdGhpcy52YWx1ZS5nZXRIb3VycygpIDogdGhpcy52YWx1ZS5ob3VycztcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IG1pbnV0ZXNWYWx1ZSgpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAoIXRoaXMudmFsdWUgfHwgKHRoaXMuZm9yY2VOdWxsVmFsdWUgJiYgdGhpcy5tb2RlID09PSAnZnVsbFRpbWVXaXRoSG91cnNEaXNhYmxlZCcgJiYgdGhpcy5jb250cm9sLnByaXN0aW5lKSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZSBpbnN0YW5jZW9mIERhdGUgPyB0aGlzLnZhbHVlLmdldE1pbnV0ZXMoKSA6IHRoaXMudmFsdWUubWludXRlcztcbiAgICB9XG5cbiAgICBwdWJsaWMgaW5jcmVtZW50VmFsdWUoZmllbGRUeXBlOiBGaWVsZFR5cGUpOiB2b2lkIHtcbiAgICAgICAgaWYgKGZpZWxkVHlwZSA9PT0gJ2hvdXJzJykge1xuICAgICAgICAgICAgdGhpcy5vbkhvdXJzQ2hhbmdlJC5uZXh0KCh0aGlzLmhvdXJzVmFsdWUgfHwgMCkgKyAxKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMub25NaW51dGVzQ2hhbmdlJC5uZXh0KCh0aGlzLm1pbnV0ZXNWYWx1ZSB8fCAwKSArIHRoaXMuX3N0ZXApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGRlY3JlbWVudFZhbHVlKGZpZWxkVHlwZTogRmllbGRUeXBlKTogdm9pZCB7XG4gICAgICAgIGlmIChmaWVsZFR5cGUgPT09ICdob3VycycpIHtcbiAgICAgICAgICAgIHRoaXMub25Ib3Vyc0NoYW5nZSQubmV4dCgodGhpcy5ob3Vyc1ZhbHVlIHx8IDApIC0gMSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLm9uTWludXRlc0NoYW5nZSQubmV4dCgodGhpcy5taW51dGVzVmFsdWUgfHwgMCkgLSB0aGlzLl9zdGVwKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBvbkNsaWNrKG1vZGU6ICdob3VycycgfCAnbWludXRlcycpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuX2F1dG9Gb2N1cykge1xuICAgICAgICAgICAgaWYgKG1vZGUgPT09ICdob3VycycpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmhvdXJzPy5uYXRpdmVFbGVtZW50LnNlbGVjdCgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLm1pbnV0ZXM/Lm5hdGl2ZUVsZW1lbnQuc2VsZWN0KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyAqKioqKioqKioqKioqIENvbnRyb2xWYWx1ZUFjY2Vzc29yIEltcGxlbWVudGF0aW9uICoqKioqKioqKioqKioqXG4gICAgLyoqIHNldCBhY2Nlc3NvciBpbmNsdWRpbmcgY2FsbCB0aGUgb25jaGFuZ2UgY2FsbGJhY2sgKi9cbiAgICBwdWJsaWMgc2V0IHZhbHVlKHY6IERhdGVPckR1cmF0aW9uIHwgdW5kZWZpbmVkKSB7XG4gICAgICAgIGlmICh2ICE9PSB0aGlzLl92YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy53cml0ZVZhbHVlKHYpO1xuICAgICAgICAgICAgdGhpcy5vbkNoYW5nZUNhbGxiYWNrKHYpO1xuICAgICAgICAgICAgdGhpcy50aW1lQ2hhbmdlLmVtaXQodik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogZ2V0IGFjY2Vzc29yICovXG4gICAgcHVibGljIGdldCB2YWx1ZSgpOiBEYXRlT3JEdXJhdGlvbiB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLl92YWx1ZTtcbiAgICB9XG5cbiAgICAvKiogRnJvbSBDb250cm9sVmFsdWVBY2Nlc3NvciBpbnRlcmZhY2UgKi9cbiAgICBwdWJsaWMgd3JpdGVWYWx1ZSh2YWx1ZTogRGF0ZU9yRHVyYXRpb24gfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICAgICAgaWYgKCh2YWx1ZSA/PyBudWxsKSAhPT0gKHRoaXMuX3ZhbHVlID8/IG51bGwpKSB7XG4gICAgICAgICAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fdmFsdWUgPSB2YWx1ZSA/IG5ldyBEYXRlKHZhbHVlLmdldFRpbWUoKSkgOiBzZXQobmV3IERhdGUoKSwgeyBob3VyczogMCwgbWludXRlczogMCwgc2Vjb25kczogMCB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fdmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBGcm9tIENvbnRyb2xWYWx1ZUFjY2Vzc29yIGludGVyZmFjZSAqL1xuICAgIHB1YmxpYyByZWdpc3Rlck9uQ2hhbmdlKGZuOiAoX2E6IHVua25vd24pID0+IHZvaWQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5vbkNoYW5nZUNhbGxiYWNrID0gZm47XG4gICAgfVxuXG4gICAgLyoqIEZyb20gQ29udHJvbFZhbHVlQWNjZXNzb3IgaW50ZXJmYWNlICovXG4gICAgcHVibGljIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgICAgIHRoaXMub25Ub3VjaGVkQ2FsbGJhY2sgPSBmbjtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0RGlzYWJsZWRTdGF0ZShpc0Rpc2FibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuICAgIH1cbiAgICAvLyAqKioqKioqKioqKioqIEVuZCBvZiBDb250cm9sVmFsdWVBY2Nlc3NvciBJbXBsZW1lbnRhdGlvbiAqKioqKioqKioqKioqKlxuXG4gICAgcHJvdGVjdGVkIG9uQ2hhbmdlQ2FsbGJhY2sgPSAoX2E6IHVua25vd24pOiB2b2lkID0+IHVuZGVmaW5lZDtcbiAgICBwcm90ZWN0ZWQgb25Ub3VjaGVkQ2FsbGJhY2sgPSAoKTogdm9pZCA9PiB1bmRlZmluZWQ7XG59XG4iLCI8IS0tIEhvdXJzIC0tPlxuPG1hdC1mb3JtLWZpZWxkIFthcHBlYXJhbmNlXT1cImFwcGVhcmFuY2VcIiBjbGFzcz1cImhvdXJzXCIgW2NsYXNzLmRpc2FibGVkXT1cImRpc2FibGVkIHx8IG1vZGUgPT09ICdmdWxsVGltZVdpdGhIb3Vyc0Rpc2FibGVkJ1wiIFtzdHlsZS5kaXNwbGF5XT1cIm1vZGUgPT09ICdtaW51dGVzT25seScgPyAnbm9uZScgOiAnYmxvY2snXCIgZmxvYXRMYWJlbD1cIm5ldmVyXCI+XG4gICAgPGlucHV0ICNob3VycyBtYXRJbnB1dCB0eXBlPVwidGV4dFwiIFtuZ01vZGVsXT1cImhvdXJzVmFsdWUgfCBudW1iZXI6JzIuJ1wiIChjaGFuZ2UpPVwib25Ib3Vyc0NoYW5nZSQubmV4dCgkZXZlbnQpXCIgKGtleWRvd24pPVwib25LZXlEb3duKCRldmVudCwgJ2hvdXJzJylcIiBbZGlzYWJsZWRdPVwiZGlzYWJsZWQgfHwgbW9kZSA9PT0gJ2Z1bGxUaW1lV2l0aEhvdXJzRGlzYWJsZWQnXCIgW21heExlbmd0aF09XCIyXCIgYXV0b2NvbXBsZXRlPVwib2ZmXCIgW3BsYWNlaG9sZGVyXT1cImRlZmF1bHRQbGFjZWhvbGRlckhvdXJzXCIgKGNsaWNrKT1cIm9uQ2xpY2soJ2hvdXJzJylcIiAvPlxuICAgIDxudW1lcmljLXN0ZXBwZXIgKGluY3JlbWVudCk9XCJpbmNyZW1lbnRWYWx1ZSgnaG91cnMnKVwiIChkZWNyZW1lbnQpPVwiZGVjcmVtZW50VmFsdWUoJ2hvdXJzJylcIj48L251bWVyaWMtc3RlcHBlcj5cbjwvbWF0LWZvcm0tZmllbGQ+XG5cbjwhLS0gU2VwYXJhdG9yIC0tPlxuPHNwYW4gY2xhc3M9XCJ0aW1lLXNlcGFyYXRvclwiIFtzdHlsZS5kaXNwbGF5XT1cIm1vZGUgPT09ICdtaW51dGVzT25seScgfHwgbW9kZSA9PT0gJ2hvdXJzT25seScgPyAnbm9uZScgOiAnYmxvY2snXCI+Ojwvc3Bhbj5cblxuPCEtLSBNaW51dGVzIC0tPlxuPG1hdC1mb3JtLWZpZWxkIFthcHBlYXJhbmNlXT1cImFwcGVhcmFuY2VcIiBjbGFzcz1cIm1pbnV0ZXNcIiBbY2xhc3MuZGlzYWJsZWRdPVwiZGlzYWJsZWQgfHwgbW9kZSA9PT0gJ2Z1bGxUaW1lV2l0aE1pbnV0ZXNEaXNhYmxlZCdcIiBbc3R5bGUuZGlzcGxheV09XCJtb2RlID09PSAnaG91cnNPbmx5JyA/ICdub25lJyA6ICdibG9jaydcIiBmbG9hdExhYmVsPVwibmV2ZXJcIj5cbiAgICA8aW5wdXQgI21pbnV0ZXMgbWF0SW5wdXQgdHlwZT1cInRleHRcIiBbbmdNb2RlbF09XCJtaW51dGVzVmFsdWUgfCBudW1iZXI6JzIuJ1wiIChjaGFuZ2UpPVwib25NaW51dGVzQ2hhbmdlJC5uZXh0KCRldmVudClcIiAoa2V5ZG93bik9XCJvbktleURvd24oJGV2ZW50LCAnbWludXRlcycpXCIgW2Rpc2FibGVkXT1cImRpc2FibGVkIHx8IG1vZGUgPT09ICdmdWxsVGltZVdpdGhNaW51dGVzRGlzYWJsZWQnXCIgW21heExlbmd0aF09XCIyXCIgYXV0b2NvbXBsZXRlPVwib2ZmXCIgW3BsYWNlaG9sZGVyXT1cImRlZmF1bHRQbGFjZWhvbGRlck1pbnV0ZXNcIiAoY2xpY2spPVwib25DbGljaygnbWludXRlcycpXCIgLz5cbiAgICA8bnVtZXJpYy1zdGVwcGVyIChpbmNyZW1lbnQpPVwiaW5jcmVtZW50VmFsdWUoJ21pbnV0ZXMnKVwiIChkZWNyZW1lbnQpPVwiZGVjcmVtZW50VmFsdWUoJ21pbnV0ZXMnKVwiPjwvbnVtZXJpYy1zdGVwcGVyPlxuPC9tYXQtZm9ybS1maWVsZD5cbiJdfQ==