@oneluiz/dual-datepicker 3.5.0 → 3.6.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.
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Range Preset Plugin System
3
+ *
4
+ * Version: 3.6.0
5
+ *
6
+ * Plugin-based architecture for date range presets following Open/Closed Principle.
7
+ *
8
+ * WHY THIS EXISTS:
9
+ * - Enterprise apps need industry-specific presets (fiscal, hotel, logistics)
10
+ * - Presets should be distributable as external packages
11
+ * - Core should NOT know about all possible presets
12
+ * - Users should extend presets without modifying library code
13
+ *
14
+ * ARCHITECTURE:
15
+ * ```
16
+ * RangePresetPlugin (interface) - Contract for all presets
17
+ * ↓
18
+ * PresetRegistry (service) - Manages plugin registration
19
+ * ↓
20
+ * PresetEngine (refactored) - Resolves presets via registry
21
+ * ↓
22
+ * DualDateRangeStore - No changes, backward compatible
23
+ * ```
24
+ *
25
+ * USAGE:
26
+ * ```typescript
27
+ * // Built-in presets work automatically
28
+ * store.applyPreset('LAST_7_DAYS'); // ✅ Works
29
+ *
30
+ * // Register custom preset
31
+ * const registry = inject(PresetRegistry);
32
+ * registry.register({
33
+ * key: 'THIS_FISCAL_QUARTER',
34
+ * resolve: (clock, adapter) => {
35
+ * const now = clock.now();
36
+ * const fiscalStart = adapter.startOfMonth(now);
37
+ * const fiscalEnd = adapter.endOfMonth(now);
38
+ * return { start: fiscalStart, end: fiscalEnd };
39
+ * }
40
+ * });
41
+ *
42
+ * // Use custom preset
43
+ * store.applyPreset('THIS_FISCAL_QUARTER'); // ✅ Works
44
+ * ```
45
+ *
46
+ * EXTERNAL PACKAGES:
47
+ * ```typescript
48
+ * // @acme/fiscal-presets package
49
+ * export const FISCAL_PRESETS: RangePresetPlugin[] = [
50
+ * { key: 'FISCAL_Q1', resolve: ... },
51
+ * { key: 'FISCAL_Q2', resolve: ... }
52
+ * ];
53
+ *
54
+ * // In app
55
+ * FISCAL_PRESETS.forEach(p => registry.register(p));
56
+ * ```
57
+ */
58
+ import { DateClock } from './date-clock';
59
+ import { DateAdapter } from './date-adapter';
60
+ /**
61
+ * Date range returned by preset plugins
62
+ */
63
+ export interface DateRange {
64
+ /**
65
+ * Start date of the range (inclusive)
66
+ */
67
+ start: Date;
68
+ /**
69
+ * End date of the range (inclusive)
70
+ */
71
+ end: Date;
72
+ }
73
+ /**
74
+ * Range Preset Plugin Interface
75
+ *
76
+ * All date range presets (built-in or external) implement this interface.
77
+ *
78
+ * DESIGN PRINCIPLES:
79
+ * - **Deterministic**: Given the same clock.now(), always returns same range
80
+ * - **Timezone-safe**: Uses DateAdapter for all date operations
81
+ * - **SSR-compatible**: Uses DateClock injection, no global Date()
82
+ * - **Testable**: Pure function, no side effects
83
+ *
84
+ * EXAMPLE - Built-in preset:
85
+ * ```typescript
86
+ * const todayPreset: RangePresetPlugin = {
87
+ * key: 'TODAY',
88
+ * resolve: (clock, adapter) => {
89
+ * const now = clock.now();
90
+ * const normalized = adapter.normalize(now);
91
+ * return { start: normalized, end: normalized };
92
+ * }
93
+ * };
94
+ * ```
95
+ *
96
+ * EXAMPLE - Custom fiscal preset:
97
+ * ```typescript
98
+ * const fiscalQuarterPreset: RangePresetPlugin = {
99
+ * key: 'THIS_FISCAL_QUARTER',
100
+ * resolve: (clock, adapter) => {
101
+ * const now = clock.now();
102
+ * const month = adapter.getMonth(now); // 0-11
103
+ *
104
+ * // Fiscal year starts in April (month 3)
105
+ * const fiscalMonth = (month + 9) % 12; // Offset to fiscal calendar
106
+ * const quarterStartMonth = Math.floor(fiscalMonth / 3) * 3;
107
+ * const adjustedMonth = (quarterStartMonth - 9 + 12) % 12;
108
+ *
109
+ * const yearOffset = month < 3 ? -1 : 0;
110
+ * const year = adapter.getYear(now) + yearOffset;
111
+ *
112
+ * const start = new Date(year, adjustedMonth, 1);
113
+ * const end = new Date(year, adjustedMonth + 3, 0);
114
+ *
115
+ * return {
116
+ * start: adapter.normalize(start),
117
+ * end: adapter.normalize(end)
118
+ * };
119
+ * }
120
+ * };
121
+ * ```
122
+ *
123
+ * EXAMPLE - Hotel industry preset:
124
+ * ```typescript
125
+ * const checkInWeekPreset: RangePresetPlugin = {
126
+ * key: 'CHECK_IN_WEEK',
127
+ * resolve: (clock, adapter) => {
128
+ * const now = clock.now();
129
+ * // Hotel check-ins are Friday to Friday
130
+ * const dayOfWeek = adapter.getDayOfWeek(now);
131
+ * const daysToFriday = dayOfWeek <= 5 ? 5 - dayOfWeek : 7 - dayOfWeek + 5;
132
+ *
133
+ * const nextFriday = adapter.addDays(now, daysToFriday);
134
+ * const followingFriday = adapter.addDays(nextFriday, 7);
135
+ *
136
+ * return { start: nextFriday, end: followingFriday };
137
+ * }
138
+ * };
139
+ * ```
140
+ */
141
+ export interface RangePresetPlugin {
142
+ /**
143
+ * Unique identifier for the preset
144
+ *
145
+ * Convention: SCREAMING_SNAKE_CASE
146
+ *
147
+ * Examples:
148
+ * - Built-in: 'TODAY', 'LAST_7_DAYS', 'THIS_MONTH'
149
+ * - Fiscal: 'FISCAL_Q1', 'FISCAL_YEAR_TO_DATE'
150
+ * - Hotel: 'CHECK_IN_WEEK', 'NEXT_30_NIGHTS'
151
+ * - Logistics: 'SHIPPING_WEEK', 'DELIVERY_WINDOW'
152
+ */
153
+ key: string;
154
+ /**
155
+ * Resolve the date range for this preset
156
+ *
157
+ * MUST use:
158
+ * - `clock.now()` for current time (SSR-safe, deterministic)
159
+ * - `adapter.*` for all date operations (timezone-safe)
160
+ *
161
+ * MUST NOT use:
162
+ * - `new Date()` directly (breaks SSR determinism)
163
+ * - `date.toISOString()` (timezone bugs)
164
+ * - `date.setDate()` (mutates, use adapter.addDays() instead)
165
+ *
166
+ * @param clock - Injected DateClock for SSR-safe time access
167
+ * @param adapter - Injected DateAdapter for timezone-safe operations
168
+ * @returns Date range with start and end dates (both inclusive)
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * resolve: (clock, adapter) => {
173
+ * const now = clock.now();
174
+ * const start = adapter.addDays(now, -7);
175
+ * const end = adapter.normalize(now);
176
+ * return { start, end };
177
+ * }
178
+ * ```
179
+ */
180
+ resolve(clock: DateClock, adapter: DateAdapter): DateRange;
181
+ }
182
+ /**
183
+ * Type guard to check if object is a valid RangePresetPlugin
184
+ *
185
+ * @param obj - Object to check
186
+ * @returns true if object implements RangePresetPlugin interface
187
+ */
188
+ export declare function isRangePresetPlugin(obj: any): obj is RangePresetPlugin;
@@ -0,0 +1,13 @@
1
+ import { DateClock } from './date-clock';
2
+ import * as i0 from "@angular/core";
3
+ export declare class SystemClock implements DateClock {
4
+ /**
5
+ * Returns current system time
6
+ *
7
+ * This is the standard behavior for client-side applications.
8
+ * For SSR, override DATE_CLOCK token with a fixed Date.
9
+ */
10
+ now(): Date;
11
+ static ɵfac: i0.ɵɵFactoryDeclaration<SystemClock, never>;
12
+ static ɵprov: i0.ɵɵInjectableDeclaration<SystemClock>;
13
+ }
@@ -1,5 +1,6 @@
1
1
  import { EventEmitter, OnInit, OnChanges, SimpleChanges, ElementRef } from '@angular/core';
2
2
  import { ControlValueAccessor } from '@angular/forms';
3
+ import { DualDateRangeStore } from './core/dual-date-range.store';
3
4
  import * as i0 from "@angular/core";
4
5
  export interface DateRange {
5
6
  startDate: string;
@@ -30,8 +31,10 @@ export type ThemeType = 'default' | 'bootstrap' | 'bulma' | 'foundation' | 'tail
30
31
  export declare class DualDatepickerComponent implements OnInit, OnChanges, ControlValueAccessor {
31
32
  private elementRef;
32
33
  placeholder: string;
33
- startDate: string;
34
- endDate: string;
34
+ set startDate(value: string);
35
+ get startDate(): string;
36
+ set endDate(value: string);
37
+ get endDate(): string;
35
38
  showPresets: boolean;
36
39
  showClearButton: boolean;
37
40
  multiRange: boolean;
@@ -61,24 +64,22 @@ export declare class DualDatepickerComponent implements OnInit, OnChanges, Contr
61
64
  multiDateRangeChange: EventEmitter<MultiDateRange>;
62
65
  multiDateRangeSelected: EventEmitter<MultiDateRange>;
63
66
  private dateAdapter;
67
+ protected readonly rangeStore: DualDateRangeStore;
64
68
  showDatePicker: import("@angular/core").WritableSignal<boolean>;
65
- dateRangeText: import("@angular/core").WritableSignal<string>;
66
- selectingStartDate: import("@angular/core").WritableSignal<boolean>;
67
69
  currentMonth: import("@angular/core").WritableSignal<any>;
68
70
  previousMonth: import("@angular/core").WritableSignal<any>;
69
71
  currentMonthDays: import("@angular/core").WritableSignal<any[]>;
70
72
  previousMonthDays: import("@angular/core").WritableSignal<any[]>;
71
73
  isDisabled: import("@angular/core").WritableSignal<boolean>;
72
- pendingStartDate: string;
73
- pendingEndDate: string;
74
- hasPendingChanges: import("@angular/core").WritableSignal<boolean>;
75
- startHour: number;
76
- startMinute: number;
77
- endHour: number;
78
- endMinute: number;
79
74
  showStartTimePicker: import("@angular/core").WritableSignal<boolean>;
80
75
  showEndTimePicker: import("@angular/core").WritableSignal<boolean>;
81
76
  hoverDate: import("@angular/core").WritableSignal<string>;
77
+ get startHour(): number;
78
+ get startMinute(): number;
79
+ get endHour(): number;
80
+ get endMinute(): number;
81
+ private setStartHourMinute;
82
+ private setEndHourMinute;
82
83
  selectedRanges: import("@angular/core").WritableSignal<DateRange[]>;
83
84
  currentRangeIndex: import("@angular/core").WritableSignal<number>;
84
85
  focusedDay: import("@angular/core").WritableSignal<{
@@ -88,6 +89,11 @@ export declare class DualDatepickerComponent implements OnInit, OnChanges, Contr
88
89
  currentMonthName: import("@angular/core").Signal<string>;
89
90
  previousMonthName: import("@angular/core").Signal<string>;
90
91
  weekDayNames: import("@angular/core").Signal<string[]>;
92
+ dateRangeText: import("@angular/core").Signal<string>;
93
+ selectingStartDate: import("@angular/core").Signal<boolean>;
94
+ hasPendingChanges: import("@angular/core").Signal<boolean>;
95
+ get pendingStartDate(): string;
96
+ get pendingEndDate(): string;
91
97
  private readonly defaultMonthNames;
92
98
  private readonly defaultMonthNamesShort;
93
99
  private readonly defaultDayNames;
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Built-in Date Range Preset Plugins
3
+ *
4
+ * Version: 3.6.0
5
+ *
6
+ * Standard presets provided by the library.
7
+ * All presets use DateClock and DateAdapter for SSR-safety and timezone-safety.
8
+ *
9
+ * PRESETS INCLUDED:
10
+ * - TODAY, YESTERDAY
11
+ * - LAST_7_DAYS, LAST_14_DAYS, LAST_30_DAYS, LAST_60_DAYS, LAST_90_DAYS
12
+ * - THIS_WEEK, LAST_WEEK
13
+ * - THIS_MONTH, LAST_MONTH, MONTH_TO_DATE
14
+ * - THIS_QUARTER, LAST_QUARTER, QUARTER_TO_DATE
15
+ * - THIS_YEAR, LAST_YEAR, YEAR_TO_DATE
16
+ */
17
+ /**
18
+ * TODAY - Current day
19
+ */
20
+ export const TODAY_PRESET = {
21
+ key: 'TODAY',
22
+ resolve: (clock, adapter) => {
23
+ const now = clock.now();
24
+ const normalized = adapter.normalize(now);
25
+ return { start: normalized, end: normalized };
26
+ }
27
+ };
28
+ /**
29
+ * YESTERDAY - Previous day
30
+ */
31
+ export const YESTERDAY_PRESET = {
32
+ key: 'YESTERDAY',
33
+ resolve: (clock, adapter) => {
34
+ const now = clock.now();
35
+ const date = adapter.addDays(now, -1);
36
+ return { start: date, end: date };
37
+ }
38
+ };
39
+ /**
40
+ * LAST_7_DAYS - Last 7 days including today
41
+ */
42
+ export const LAST_7_DAYS_PRESET = {
43
+ key: 'LAST_7_DAYS',
44
+ resolve: (clock, adapter) => {
45
+ const now = clock.now();
46
+ const end = adapter.normalize(now);
47
+ const start = adapter.addDays(now, -6);
48
+ return { start, end };
49
+ }
50
+ };
51
+ /**
52
+ * LAST_14_DAYS - Last 14 days including today
53
+ */
54
+ export const LAST_14_DAYS_PRESET = {
55
+ key: 'LAST_14_DAYS',
56
+ resolve: (clock, adapter) => {
57
+ const now = clock.now();
58
+ const end = adapter.normalize(now);
59
+ const start = adapter.addDays(now, -13);
60
+ return { start, end };
61
+ }
62
+ };
63
+ /**
64
+ * LAST_30_DAYS - Last 30 days including today
65
+ */
66
+ export const LAST_30_DAYS_PRESET = {
67
+ key: 'LAST_30_DAYS',
68
+ resolve: (clock, adapter) => {
69
+ const now = clock.now();
70
+ const end = adapter.normalize(now);
71
+ const start = adapter.addDays(now, -29);
72
+ return { start, end };
73
+ }
74
+ };
75
+ /**
76
+ * LAST_60_DAYS - Last 60 days including today
77
+ */
78
+ export const LAST_60_DAYS_PRESET = {
79
+ key: 'LAST_60_DAYS',
80
+ resolve: (clock, adapter) => {
81
+ const now = clock.now();
82
+ const end = adapter.normalize(now);
83
+ const start = adapter.addDays(now, -59);
84
+ return { start, end };
85
+ }
86
+ };
87
+ /**
88
+ * LAST_90_DAYS - Last 90 days including today
89
+ */
90
+ export const LAST_90_DAYS_PRESET = {
91
+ key: 'LAST_90_DAYS',
92
+ resolve: (clock, adapter) => {
93
+ const now = clock.now();
94
+ const end = adapter.normalize(now);
95
+ const start = adapter.addDays(now, -89);
96
+ return { start, end };
97
+ }
98
+ };
99
+ /**
100
+ * THIS_WEEK - Current week (Monday to Sunday)
101
+ */
102
+ export const THIS_WEEK_PRESET = {
103
+ key: 'THIS_WEEK',
104
+ resolve: (clock, adapter) => {
105
+ const now = clock.now();
106
+ const dayOfWeek = adapter.getDay(now);
107
+ const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
108
+ const start = adapter.addDays(now, -daysToMonday);
109
+ const end = adapter.addDays(start, 6);
110
+ return { start, end };
111
+ }
112
+ };
113
+ /**
114
+ * LAST_WEEK - Previous week (Monday to Sunday)
115
+ */
116
+ export const LAST_WEEK_PRESET = {
117
+ key: 'LAST_WEEK',
118
+ resolve: (clock, adapter) => {
119
+ const now = clock.now();
120
+ const dayOfWeek = adapter.getDay(now);
121
+ const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
122
+ const lastMonday = adapter.addDays(now, -daysToMonday - 7);
123
+ const lastSunday = adapter.addDays(lastMonday, 6);
124
+ return { start: lastMonday, end: lastSunday };
125
+ }
126
+ };
127
+ /**
128
+ * THIS_MONTH - Current calendar month (1st to last day)
129
+ */
130
+ export const THIS_MONTH_PRESET = {
131
+ key: 'THIS_MONTH',
132
+ resolve: (clock, adapter) => {
133
+ const now = clock.now();
134
+ const start = adapter.startOfMonth(now);
135
+ const end = adapter.endOfMonth(now);
136
+ return { start, end };
137
+ }
138
+ };
139
+ /**
140
+ * LAST_MONTH - Previous calendar month
141
+ */
142
+ export const LAST_MONTH_PRESET = {
143
+ key: 'LAST_MONTH',
144
+ resolve: (clock, adapter) => {
145
+ const now = clock.now();
146
+ const lastMonth = adapter.addMonths(now, -1);
147
+ const start = adapter.startOfMonth(lastMonth);
148
+ const end = adapter.endOfMonth(lastMonth);
149
+ return { start, end };
150
+ }
151
+ };
152
+ /**
153
+ * MONTH_TO_DATE - From start of current month to today
154
+ */
155
+ export const MONTH_TO_DATE_PRESET = {
156
+ key: 'MONTH_TO_DATE',
157
+ resolve: (clock, adapter) => {
158
+ const now = clock.now();
159
+ const start = adapter.startOfMonth(now);
160
+ const end = adapter.normalize(now);
161
+ return { start, end };
162
+ }
163
+ };
164
+ /**
165
+ * THIS_QUARTER - Current quarter (Q1: Jan-Mar, Q2: Apr-Jun, Q3: Jul-Sep, Q4: Oct-Dec)
166
+ */
167
+ export const THIS_QUARTER_PRESET = {
168
+ key: 'THIS_QUARTER',
169
+ resolve: (clock, adapter) => {
170
+ const now = clock.now();
171
+ const currentMonth = adapter.getMonth(now);
172
+ const quarterStartMonth = Math.floor(currentMonth / 3) * 3;
173
+ const year = adapter.getYear(now);
174
+ const start = new Date(year, quarterStartMonth, 1);
175
+ const normalizedStart = adapter.normalize(start);
176
+ const end = new Date(year, quarterStartMonth + 3, 0);
177
+ const normalizedEnd = adapter.normalize(end);
178
+ return { start: normalizedStart, end: normalizedEnd };
179
+ }
180
+ };
181
+ /**
182
+ * LAST_QUARTER - Previous quarter
183
+ */
184
+ export const LAST_QUARTER_PRESET = {
185
+ key: 'LAST_QUARTER',
186
+ resolve: (clock, adapter) => {
187
+ const now = clock.now();
188
+ const currentMonth = adapter.getMonth(now);
189
+ const lastQuarterStartMonth = Math.floor(currentMonth / 3) * 3 - 3;
190
+ const year = adapter.getYear(now);
191
+ const adjustedYear = lastQuarterStartMonth < 0 ? year - 1 : year;
192
+ const adjustedMonth = lastQuarterStartMonth < 0 ? 9 : lastQuarterStartMonth;
193
+ const start = new Date(adjustedYear, adjustedMonth, 1);
194
+ const normalizedStart = adapter.normalize(start);
195
+ const end = new Date(adjustedYear, adjustedMonth + 3, 0);
196
+ const normalizedEnd = adapter.normalize(end);
197
+ return { start: normalizedStart, end: normalizedEnd };
198
+ }
199
+ };
200
+ /**
201
+ * QUARTER_TO_DATE - From start of current quarter to today
202
+ */
203
+ export const QUARTER_TO_DATE_PRESET = {
204
+ key: 'QUARTER_TO_DATE',
205
+ resolve: (clock, adapter) => {
206
+ const now = clock.now();
207
+ const currentMonth = adapter.getMonth(now);
208
+ const quarterStartMonth = Math.floor(currentMonth / 3) * 3;
209
+ const year = adapter.getYear(now);
210
+ const start = new Date(year, quarterStartMonth, 1);
211
+ const normalizedStart = adapter.normalize(start);
212
+ const end = adapter.normalize(now);
213
+ return { start: normalizedStart, end };
214
+ }
215
+ };
216
+ /**
217
+ * THIS_YEAR - Current calendar year (Jan 1 to Dec 31)
218
+ */
219
+ export const THIS_YEAR_PRESET = {
220
+ key: 'THIS_YEAR',
221
+ resolve: (clock, adapter) => {
222
+ const now = clock.now();
223
+ const year = adapter.getYear(now);
224
+ const start = new Date(year, 0, 1);
225
+ const end = new Date(year, 11, 31);
226
+ return {
227
+ start: adapter.normalize(start),
228
+ end: adapter.normalize(end)
229
+ };
230
+ }
231
+ };
232
+ /**
233
+ * LAST_YEAR - Previous calendar year
234
+ */
235
+ export const LAST_YEAR_PRESET = {
236
+ key: 'LAST_YEAR',
237
+ resolve: (clock, adapter) => {
238
+ const now = clock.now();
239
+ const year = adapter.getYear(now);
240
+ const start = new Date(year - 1, 0, 1);
241
+ const end = new Date(year - 1, 11, 31);
242
+ return {
243
+ start: adapter.normalize(start),
244
+ end: adapter.normalize(end)
245
+ };
246
+ }
247
+ };
248
+ /**
249
+ * YEAR_TO_DATE - From start of current year to today
250
+ */
251
+ export const YEAR_TO_DATE_PRESET = {
252
+ key: 'YEAR_TO_DATE',
253
+ resolve: (clock, adapter) => {
254
+ const now = clock.now();
255
+ const year = adapter.getYear(now);
256
+ const start = new Date(year, 0, 1);
257
+ const end = adapter.normalize(now);
258
+ return { start: adapter.normalize(start), end };
259
+ }
260
+ };
261
+ /**
262
+ * All built-in presets as an array
263
+ *
264
+ * Use this to register all built-in presets at once:
265
+ * ```typescript
266
+ * BUILT_IN_PRESETS.forEach(preset => registry.register(preset));
267
+ * ```
268
+ */
269
+ export const BUILT_IN_PRESETS = [
270
+ TODAY_PRESET,
271
+ YESTERDAY_PRESET,
272
+ LAST_7_DAYS_PRESET,
273
+ LAST_14_DAYS_PRESET,
274
+ LAST_30_DAYS_PRESET,
275
+ LAST_60_DAYS_PRESET,
276
+ LAST_90_DAYS_PRESET,
277
+ THIS_WEEK_PRESET,
278
+ LAST_WEEK_PRESET,
279
+ THIS_MONTH_PRESET,
280
+ LAST_MONTH_PRESET,
281
+ MONTH_TO_DATE_PRESET,
282
+ THIS_QUARTER_PRESET,
283
+ LAST_QUARTER_PRESET,
284
+ QUARTER_TO_DATE_PRESET,
285
+ THIS_YEAR_PRESET,
286
+ LAST_YEAR_PRESET,
287
+ YEAR_TO_DATE_PRESET
288
+ ];
289
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbHQtaW4tcHJlc2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL2J1aWx0LWluLXByZXNldHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBSUg7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQXNCO0lBQzdDLEdBQUcsRUFBRSxPQUFPO0lBQ1osT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLE9BQU8sRUFBRSxFQUFFO1FBQzFCLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN4QixNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUNoRCxDQUFDO0NBQ0YsQ0FBQztBQUVGOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQXNCO0lBQ2pELEdBQUcsRUFBRSxXQUFXO0lBQ2hCLE9BQU8sRUFBRSxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtRQUMxQixNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDeEIsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN0QyxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDcEMsQ0FBQztDQUNGLENBQUM7QUFFRjs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFzQjtJQUNuRCxHQUFHLEVBQUUsYUFBYTtJQUNsQixPQUFPLEVBQUUsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEVBQUU7UUFDMUIsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFD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QUFDLENBQUM7UUFDbkMsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBQ2xELENBQUM7Q0FDRixDQUFDO0FBRUY7Ozs7Ozs7R0FPRztBQUNILE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUF3QjtJQUNuRCxZQUFZO0lBQ1osZ0JBQWdCO0lBQ2hCLGtCQUFrQjtJQUNsQixtQkFBbUI7SUFDbkIsbUJBQW1CO0lBQ25CLG1CQUFtQjtJQUNuQixtQkFBbUI7SUFDbkIsZ0JBQWdCO0lBQ2hCLGdCQUFnQjtJQUNoQixpQkFBaUI7SUFDakIsaUJBQWlCO0lBQ2pCLG9CQUFvQjtJQUNwQixtQkFBbUI7SUFDbkIsbUJBQW1CO0lBQ25CLHNCQUFzQjtJQUN0QixnQkFBZ0I7SUFDaEIsZ0JBQWdCO0lBQ2hCLG1CQUFtQjtDQUNwQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCdWlsdC1pbiBEYXRlIFJhbmdlIFByZXNldCBQbHVnaW5zXG4gKiBcbiAqIFZlcnNpb246IDMuNi4wXG4gKiBcbiAqIFN0YW5kYXJkIHByZXNldHMgcHJvdmlkZWQgYnkgdGhlIGxpYnJhcnkuXG4gKiBBbGwgcHJlc2V0cyB1c2UgRGF0ZUNsb2NrIGFuZCBEYXRlQWRhcHRlciBmb3IgU1NSLXNhZmV0eSBhbmQgdGltZXpvbmUtc2FmZXR5LlxuICogXG4gKiBQUkVTRVRTIElOQ0xVREVEOlxuICogLSBUT0RBWSwgWUVTVEVSREFZXG4gKiAtIExBU1RfN19EQVlTLCBMQVNUXzE0X0RBWVMsIExBU1RfMzBfREFZUywgTEFTVF82MF9EQVlTLCBMQVNUXzkwX0RBWVNcbiAqIC0gVEhJU19XRUVLLCBMQVNUX1dFRUtcbiAqIC0gVEhJU19NT05USCwgTEFTVF9NT05USCwgTU9OVEhfVE9fREFURVxuICogLSBUSElTX1FVQVJURVIsIExBU1RfUVVBUlRFUiwgUVVBUlRFUl9UT19EQVRFXG4gKiAtIFRISVNfWUVBUiwgTEFTVF9ZRUFSLCBZRUFSX1RPX0RBVEVcbiAqL1xuXG5pbXBvcnQgeyBSYW5nZVByZXNldFBsdWdpbiB9IGZyb20gJy4vcmFuZ2UtcHJlc2V0LnBsdWdpbic7XG5cbi8qKlxuICogVE9EQVkgLSBDdXJyZW50IGRheVxuICovXG5leHBvcnQgY29uc3QgVE9EQVlfUFJFU0VUOiBSYW5nZVByZXNldFBsdWdpbiA9IHtcbiAga2V5OiAnVE9EQVknLFxuICByZXNvbHZlOiAoY2xvY2ssIGFkYXB0ZXIpID0+IHtcbiAgICBjb25zdCBub3cgPSBjbG9jay5ub3coKTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gYWRhcHRlci5ub3JtYWxpemUobm93KTtcbiAgICByZXR1cm4geyBzdGFydDogbm9ybWFsaXplZCwgZW5kOiBub3JtYWxpemVkIH07XG4gIH1cbn07XG5cbi8qKlxuICogWUVTVEVSREFZIC0gUHJldmlvdXMgZGF5XG4gKi9cbmV4cG9ydCBjb25zdCBZRVNURVJEQVlfUFJFU0VUOiBSYW5nZVByZXNldFBsdWdpbiA9IHtcbiAga2V5OiAnWUVTVEVSREFZJyxcbiAgcmVzb2x2ZTogKGNsb2NrLCBhZGFwdGVyKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gY2xvY2subm93KCk7XG4gICAgY29uc3QgZGF0ZSA9IGFkYXB0ZXIuYWRkRGF5cyhub3csIC0xKTtcbiAgICByZXR1cm4geyBzdGFydDogZGF0ZSwgZW5kOiBkYXRlIH07XG4gIH1cbn07XG5cbi8qKlxuICogTEFTVF83X0RBWVMgLSBMYXN0IDcgZGF5cyBpbmNsdWRpbmcgdG9kYXlcbiAqL1xuZXhwb3J0IGNvbnN0IExBU1RfN19EQVlTX1BSRVNFVDogUmFuZ2VQcmVzZXRQbHVnaW4gPSB7XG4gIGtleTogJ0xBU1RfN19EQVlTJyxcbiAgcmVzb2x2ZTogKGNsb2NrLCBhZGFwdGVyKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gY2xvY2subm93KCk7XG4gICAgY29uc3QgZW5kID0gYWRhcHRlci5ub3JtYWxpemUobm93KTtcbiAgICBjb25zdCBzdGFydCA9IGFkYXB0ZXIuYWRkRGF5cyhub3csIC02KTtcbiAgICByZXR1cm4geyBzdGFydCwgZW5kIH07XG4gIH1cbn07XG5cbi8qKlxuICogTEFTVF8xNF9EQVlTIC0gTGFzdCAxNCBkYXlzIGluY2x1ZGluZyB0b2RheVxuICovXG5leHBvcnQgY29uc3QgTEFTVF8xNF9EQVlTX1BSRVNFVDogUmFuZ2VQcmVzZXRQbHVnaW4gPSB7XG4gIGtleTogJ0xBU1RfMTRfREFZUycsXG4gIHJlc29sdmU6IChjbG9jaywgYWRhcHRlcikgPT4ge1xuICAgIGNvbnN0IG5vdyA9IGNsb2NrLm5vdygpO1xuICAgIGNvbnN0IGVuZCA9IGFkYXB0ZXIubm9ybWFsaXplKG5vdyk7XG4gICAgY29uc3Qgc3RhcnQgPSBhZGFwdGVyLmFkZERheXMobm93LCAtMTMpO1xuICAgIHJldHVybiB7IHN0YXJ0LCBlbmQgfTtcbiAgfVxufTtcblxuLyoqXG4gKiBMQVNUXzMwX0RBWVMgLSBMYXN0IDMwIGRheXMgaW5jbHVkaW5nIHRvZGF5XG4gKi9cbmV4cG9ydCBjb25zdCBMQVNUXzMwX0RBWVNfUFJFU0VUOiBSYW5nZVByZXNldFBsdWdpbiA9IHtcbiAga2V5OiAnTEFTVF8zMF9EQVlTJyxcbiAgcmVzb2x2ZTogKGNsb2NrLCBhZGFwdGVyKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gY2xvY2subm93KCk7XG4gICAgY29uc3QgZW5kID0gYWRhcHRlci5ub3JtYWxpemUobm93KTtcbiAgICBjb25zdCBzdGFydCA9IGFkYXB0ZXIuYWRkRGF5cyhub3csIC0yOSk7XG4gICAgcmV0dXJuIHsgc3RhcnQsIGVuZCB9O1xuICB9XG59O1xuXG4vKipcbiAqIExBU1RfNjBfREFZUyAtIExhc3QgNjAgZGF5cyBpbmNsdWRpbmcgdG9kYXlcbiAqL1xuZXhwb3J0IGNvbnN0IExBU1RfNjBfREFZU19QUkVTRVQ6IFJhbmdlUHJlc2V0UGx1Z2luID0ge1xuICBrZXk6ICdMQVNUXzYwX0RBWVMnLFxuICByZXNvbHZlOiAoY2xvY2ssIGFkYXB0ZXIpID0+IHtcbiAgICBjb25zdCBub3cgPSBjbG9jay5ub3coKTtcbiAgICBjb25zdCBlbmQgPSBhZGFwdGVyLm5vcm1hbGl6ZShub3cpO1xuICAgIGNvbnN0IHN0YXJ0ID0gYWRhcHRlci5hZGREYXlzKG5vdywgLTU5KTtcbiAgICByZXR1cm4geyBzdGFydCwgZW5kIH07XG4gIH1cbn07XG5cbi8qKlxuICogTEFTVF85MF9EQVlTIC0gTGFzdCA5MCBkYXlzIGluY2x1ZGluZyB0b2RheVxuICovXG5leHBvcnQgY29uc3QgTEFTVF85MF9EQVlTX1BSRVNFVDogUmFuZ2VQcmVzZXRQbHVnaW4gPSB7XG4gIGtleTogJ0xBU1RfOTBfREFZUycsXG4gIHJlc29sdmU6IChjbG9jaywgYWRhcHRlcikgPT4ge1xuICAgIGNvbnN0IG5vdyA9IGNsb2NrLm5vdygpO1xuICAgIGNvbnN0IGVuZCA9IGFkYXB0ZXIubm9ybWFsaXplKG5vdyk7XG4gICAgY29uc3Qgc3RhcnQgPSBhZGFwdGVyLmFkZERheXMobm93LCAtODkpO1xuICAgIHJldHVybiB7IHN0YXJ0LCBlbmQgfTtcbiAgfVxufTtcblxuLyoqXG4gKiBUSElTX1dFRUsgLSBDdXJyZW50IHdlZWsgKE1vbmRheSB0byBTdW5kYXkpXG4gKi9cbmV4cG9ydCBjb25zdCBUSElTX1dFRUtfUFJFU0VUOiBSYW5nZVByZXNldFBsdWdpbiA9IHtcbiAga2V5OiAnVEhJU19XRUVLJyxcbiAgcmVzb2x2ZTogKGNsb2NrLCBhZGFwdGVyKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gY2xvY2subm93KCk7XG4gICAgY29uc3QgZGF5T2ZXZWVrID0gYWRhcHRlci5nZXREYXkobm93KTtcbiAgICBjb25zdCBkYXlzVG9Nb25kYXkgPSBkYXlPZldlZWsgPT09IDAgPyA2IDogZGF5T2ZXZWVrIC0gMTtcbiAgICBjb25zdCBzdGFydCA9IGFkYXB0ZXIuYWRkRGF5cyhub3csIC1kYXlzVG9Nb25kYXkpO1xuICAgIGNvbnN0IGVuZCA9IGFkYXB0ZXIuYWRkRGF5cyhzdGFydCwgNik7XG4gICAgcmV0dXJuIHsgc3RhcnQsIGVuZCB9O1xuICB9XG59O1xuXG4vKipcbiAqIExBU1RfV0VFSyAtIFByZXZpb3VzIHdlZWsgKE1vbmRheSB0byBTdW5kYXkpXG4gKi9cbmV4cG9ydCBjb25zdCBMQVNUX1dFRUtfUFJFU0VUOiBSYW5nZVByZXNldFBsdWdpbiA9IHtcbiAga2V5OiAnTEFTVF9XRUVLJyxcbiAgcmVzb2x2ZTogKGNsb2NrLCBhZGFwdGVyKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gY2xvY2subm93KCk7XG4gICAgY29uc3QgZGF5T2ZXZWVrID0gYWRhcHRlci5nZXREYXkobm93KTtcbiAgICBjb25zdCBkYXlzVG9Nb25kYXkgPSBkYXlPZldlZWsgPT09IDAgPyA2IDogZGF5T2ZXZWVrIC0gMTtcbiAgICBjb25zdCBsYXN0TW9uZGF5ID0gYWRhcHRlci5hZGREYXlzKG5vdywgLWRheXNUb01vbmRheSAtIDcpO1xuICAgIGNvbnN0IGxhc3RTdW5kYXkgPSBhZGFwdGVyLmFkZERheXMobGFzdE1vbmRheSwgNik7XG4gICAgcmV0dXJuIHsgc3RhcnQ6IGxhc3RNb25kYXksIGVuZDogbGFzdFN1bmRheSB9O1xuICB9XG59O1xuXG4vKipcbiAqIFRISVNfTU9OVEggLSBDdXJyZW50IGNhbGVuZGFyIG1vbnRoICgxc3QgdG8gbGFzdCBkYXkpXG4gKi9cbmV4cG9ydCBjb25zdCBUSElTX01PTlRIX1BSRVNFVDogUmFuZ2VQcmVzZXRQbHVnaW4gPSB7XG4gIGtleTogJ1RISVNfTU9OVEgnLFxuICByZXNvbHZlOiAoY2xvY2ssIGFkYXB0ZXIpID0+IHtcbiAgICBjb25zdCBub3cgPSBjbG9jay5ub3coKTtcbiAgICBjb25zdCBzdGFydCA9IGFkYXB0ZXIuc3RhcnRPZk1vbnRoKG5vdyk7XG4gICAgY29uc3QgZW5kID0gYWRhcHRlci5lbmRPZk1vbnRoKG5vdyk7XG4gICAgcmV0dXJuIHsgc3RhcnQsIGVuZCB9O1xuICB9XG59O1xuXG4vKipcbiAqIExBU1RfTU9OVEggLSBQcmV2aW91cyBjYWxlbmRhciBtb250aFxuICovXG5leHBvcnQgY29uc3QgTEFTVF9NT05USF9QUkVTRVQ6IFJhbmdlUHJlc2V0UGx1Z2luID0ge1xuICBrZXk6ICdMQVNUX01PTlRIJyxcbiAgcmVzb2x2ZTogKGNsb2NrLCBhZGFwdGVyKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gY2xvY2subm93KCk7XG4gICAgY29uc3QgbGFzdE1vbnRoID0gYWRhcHRlci5hZGRNb250aHMobm93LCAtMSk7XG4gICAgY29uc3Qgc3RhcnQgPSBhZGFwdGVyLnN0YXJ0T2ZNb250aChsYXN0TW9udGgpO1xuICAgIGNvbnN0IGVuZCA9IGFkYXB0ZXIuZW5kT2ZNb250aChsYXN0TW9udGgpO1xuICAgIHJldHVybiB7IHN0YXJ0LCBlbmQgfTtcbiAgfVxufTtcblxuLyoqXG4gKiBNT05USF9UT19EQVRFIC0gRnJvbSBzdGFydCBvZiBjdXJyZW50IG1vbnRoIHRvIHRvZGF5XG4gKi9cbmV4cG9ydCBjb25zdCBNT05USF9UT19EQVRFX1BSRVNFVDogUmFuZ2VQcmVzZXRQbHVnaW4gPSB7XG4gIGtleTogJ01PTlRIX1RPX0RBVEUnLFxuICByZXNvbHZlOiAoY2xvY2ssIGFkYXB0ZXIpID0+IHtcbiAgICBjb25zdCBub3cgPSBjbG9jay5ub3coKTtcbiAgICBjb25zdCBzdGFydCA9IGFkYXB0ZXIuc3RhcnRPZk1vbnRoKG5vdyk7XG4gICAgY29uc3QgZW5kID0gYWRhcHRlci5ub3JtYWxpemUobm93KTtcbiAgICByZXR1cm4geyBzdGFydCwgZW5kIH07XG4gIH1cbn07XG5cbi8qKlxuICogVEhJU19RVUFSVEVSIC0gQ3VycmVudCBxdWFydGVyIChRMTogSmFuLU1hciwgUTI6IEFwci1KdW4sIFEzOiBKdWwtU2VwLCBRNDogT2N0LURlYylcbiAqL1xuZXhwb3J0IGNvbnN0IFRISVNfUVVBUlRFUl9QUkVTRVQ6IFJhbmdlUHJlc2V0UGx1Z2luID0ge1xuICBrZXk6ICdUSElTX1FVQVJURVInLFxuICByZXNvbHZlOiAoY2xvY2ssIGFkYXB0ZXIpID0+IHtcbiAgICBjb25zdCBub3cgPSBjbG9jay5ub3coKTtcbiAgICBjb25zdCBjdXJyZW50TW9udGggPSBhZGFwdGVyLmdldE1vbnRoKG5vdyk7XG4gICAgY29uc3QgcXVhcnRlclN0YXJ0TW9udGggPSBNYXRoLmZsb29yKGN1cnJlbnRNb250aCAvIDMpICogMztcbiAgICBjb25zdCB5ZWFyID0gYWRhcHRlci5nZXRZZWFyKG5vdyk7XG4gICAgXG4gICAgY29uc3Qgc3RhcnQgPSBuZXcgRGF0ZSh5ZWFyLCBxdWFydGVyU3RhcnRNb250aCwgMSk7XG4gICAgY29uc3Qgbm9ybWFsaXplZFN0YXJ0ID0gYWRhcHRlci5ub3JtYWxpemUoc3RhcnQpO1xuICAgIFxuICAgIGNvbnN0IGVuZCA9IG5ldyBEYXRlKHllYXIsIHF1YXJ0ZXJTdGFydE1vbnRoICsgMywgMCk7XG4gICAgY29uc3Qgbm9ybWFsaXplZEVuZCA9IGFkYXB0ZXIubm9ybWFsaXplKGVuZCk7XG4gICAgXG4gICAgcmV0dXJuIHsgc3RhcnQ6IG5vcm1hbGl6ZWRTdGFydCwgZW5kOiBub3JtYWxpemVkRW5kIH07XG4gIH1cbn07XG5cbi8qKlxuICogTEFTVF9RVUFSVEVSIC0gUHJldmlvdXMgcXVhcnRlclxuICovXG5leHBvcnQgY29uc3QgTEFTVF9RVUFSVEVSX1BSRVNFVDogUmFuZ2VQcmVzZXRQbHVnaW4gPSB7XG4gIGtleTogJ0xBU1RfUVVBUlRFUicsXG4gIHJlc29sdmU6IChjbG9jaywgYWRhcHRlcikgPT4ge1xuICAgIGNvbnN0IG5vdyA9IGNsb2NrLm5vdygpO1xuICAgIGNvbnN0IGN1cnJlbnRNb250aCA9IGFkYXB0ZXIuZ2V0TW9udGgobm93KTtcbiAgICBjb25zdCBsYXN0UXVhcnRlclN0YXJ0TW9udGggPSBNYXRoLmZsb29yKGN1cnJlbnRNb250aCAvIDMpICogMyAtIDM7XG4gICAgY29uc3QgeWVhciA9IGFkYXB0ZXIuZ2V0WWVhcihub3cpO1xuICAgIFxuICAgIGNvbnN0IGFkanVzdGVkWWVhciA9IGxhc3RRdWFydGVyU3RhcnRNb250aCA8IDAgPyB5ZWFyIC0gMSA6IHllYXI7XG4gICAgY29uc3QgYWRqdXN0ZWRNb250aCA9IGxhc3RRdWFydGVyU3RhcnRNb250aCA8IDAgPyA5IDogbGFzdFF1YXJ0ZXJTdGFydE1vbnRoO1xuICAgIFxuICAgIGNvbnN0IHN0YXJ0ID0gbmV3IERhdGUoYWRqdXN0ZWRZZWFyLCBhZGp1c3RlZE1vbnRoLCAxKTtcbiAgICBjb25zdCBub3JtYWxpemVkU3RhcnQgPSBhZGFwdGVyLm5vcm1hbGl6ZShzdGFydCk7XG4gICAgXG4gICAgY29uc3QgZW5kID0gbmV3IERhdGUoYWRqdXN0ZWRZZWFyLCBhZGp1c3RlZE1vbnRoICsgMywgMCk7XG4gICAgY29uc3Qgbm9ybWFsaXplZEVuZCA9IGFkYXB0ZXIubm9ybWFsaXplKGVuZCk7XG4gICAgXG4gICAgcmV0dXJuIHsgc3RhcnQ6IG5vcm1hbGl6ZWRTdGFydCwgZW5kOiBub3JtYWxpemVkRW5kIH07XG4gIH1cbn07XG5cbi8qKlxuICogUVVBUlRFUl9UT19EQVRFIC0gRnJvbSBzdGFydCBvZiBjdXJyZW50IHF1YXJ0ZXIgdG8gdG9kYXlcbiAqL1xuZXhwb3J0IGNvbnN0IFFVQVJURVJfVE9fREFURV9QUkVTRVQ6IFJhbmdlUHJlc2V0UGx1Z2luID0ge1xuICBrZXk6ICdRVUFSVEVSX1RPX0RBVEUnLFxuICByZXNvbHZlOiAoY2xvY2ssIGFkYXB0ZXIpID0+IHtcbiAgICBjb25zdCBub3cgPSBjbG9jay5ub3coKTtcbiAgICBjb25zdCBjdXJyZW50TW9udGggPSBhZGFwdGVyLmdldE1vbnRoKG5vdyk7XG4gICAgY29uc3QgcXVhcnRlclN0YXJ0TW9udGggPSBNYXRoLmZsb29yKGN1cnJlbnRNb250aCAvIDMpICogMztcbiAgICBjb25zdCB5ZWFyID0gYWRhcHRlci5nZXRZZWFyKG5vdyk7XG4gICAgXG4gICAgY29uc3Qgc3RhcnQgPSBuZXcgRGF0ZSh5ZWFyLCBxdWFydGVyU3RhcnRNb250aCwgMSk7XG4gICAgY29uc3Qgbm9ybWFsaXplZFN0YXJ0ID0gYWRhcHRlci5ub3JtYWxpemUoc3RhcnQpO1xuICAgIGNvbnN0IGVuZCA9IGFkYXB0ZXIubm9ybWFsaXplKG5vdyk7XG4gICAgXG4gICAgcmV0dXJuIHsgc3RhcnQ6IG5vcm1hbGl6ZWRTdGFydCwgZW5kIH07XG4gIH1cbn07XG5cbi8qKlxuICogVEhJU19ZRUFSIC0gQ3VycmVudCBjYWxlbmRhciB5ZWFyIChKYW4gMSB0byBEZWMgMzEpXG4gKi9cbmV4cG9ydCBjb25zdCBUSElTX1lFQVJfUFJFU0VUOiBSYW5nZVByZXNldFBsdWdpbiA9IHtcbiAga2V5OiAnVEhJU19ZRUFSJyxcbiAgcmVzb2x2ZTogKGNsb2NrLCBhZGFwdGVyKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gY2xvY2subm93KCk7XG4gICAgY29uc3QgeWVhciA9IGFkYXB0ZXIuZ2V0WWVhcihub3cpO1xuICAgIGNvbnN0IHN0YXJ0ID0gbmV3IERhdGUoeWVhciwgMCwgMSk7XG4gICAgY29uc3QgZW5kID0gbmV3IERhdGUoeWVhciwgMTEsIDMxKTtcbiAgICByZXR1cm4geyBcbiAgICAgIHN0YXJ0OiBhZGFwdGVyLm5vcm1hbGl6ZShzdGFydCksIFxuICAgICAgZW5kOiBhZGFwdGVyLm5vcm1hbGl6ZShlbmQpIFxuICAgIH07XG4gIH1cbn07XG5cbi8qKlxuICogTEFTVF9ZRUFSIC0gUHJldmlvdXMgY2FsZW5kYXIgeWVhclxuICovXG5leHBvcnQgY29uc3QgTEFTVF9ZRUFSX1BSRVNFVDogUmFuZ2VQcmVzZXRQbHVnaW4gPSB7XG4gIGtleTogJ0xBU1RfWUVBUicsXG4gIHJlc29sdmU6IChjbG9jaywgYWRhcHRlcikgPT4ge1xuICAgIGNvbnN0IG5vdyA9IGNsb2NrLm5vdygpO1xuICAgIGNvbnN0IHllYXIgPSBhZGFwdGVyLmdldFllYXIobm93KTtcbiAgICBjb25zdCBzdGFydCA9IG5ldyBEYXRlKHllYXIgLSAxLCAwLCAxKTtcbiAgICBjb25zdCBlbmQgPSBuZXcgRGF0ZSh5ZWFyIC0gMSwgMTEsIDMxKTtcbiAgICByZXR1cm4geyBcbiAgICAgIHN0YXJ0OiBhZGFwdGVyLm5vcm1hbGl6ZShzdGFydCksIFxuICAgICAgZW5kOiBhZGFwdGVyLm5vcm1hbGl6ZShlbmQpIFxuICAgIH07XG4gIH1cbn07XG5cbi8qKlxuICogWUVBUl9UT19EQVRFIC0gRnJvbSBzdGFydCBvZiBjdXJyZW50IHllYXIgdG8gdG9kYXlcbiAqL1xuZXhwb3J0IGNvbnN0IFlFQVJfVE9fREFURV9QUkVTRVQ6IFJhbmdlUHJlc2V0UGx1Z2luID0ge1xuICBrZXk6ICdZRUFSX1RPX0RBVEUnLFxuICByZXNvbHZlOiAoY2xvY2ssIGFkYXB0ZXIpID0+IHtcbiAgICBjb25zdCBub3cgPSBjbG9jay5ub3coKTtcbiAgICBjb25zdCB5ZWFyID0gYWRhcHRlci5nZXRZZWFyKG5vdyk7XG4gICAgY29uc3Qgc3RhcnQgPSBuZXcgRGF0ZSh5ZWFyLCAwLCAxKTtcbiAgICBjb25zdCBlbmQgPSBhZGFwdGVyLm5vcm1hbGl6ZShub3cpO1xuICAgIHJldHVybiB7IHN0YXJ0OiBhZGFwdGVyLm5vcm1hbGl6ZShzdGFydCksIGVuZCB9O1xuICB9XG59O1xuXG4vKipcbiAqIEFsbCBidWlsdC1pbiBwcmVzZXRzIGFzIGFuIGFycmF5XG4gKiBcbiAqIFVzZSB0aGlzIHRvIHJlZ2lzdGVyIGFsbCBidWlsdC1pbiBwcmVzZXRzIGF0IG9uY2U6XG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBCVUlMVF9JTl9QUkVTRVRTLmZvckVhY2gocHJlc2V0ID0+IHJlZ2lzdHJ5LnJlZ2lzdGVyKHByZXNldCkpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjb25zdCBCVUlMVF9JTl9QUkVTRVRTOiBSYW5nZVByZXNldFBsdWdpbltdID0gW1xuICBUT0RBWV9QUkVTRVQsXG4gIFlFU1RFUkRBWV9QUkVTRVQsXG4gIExBU1RfN19EQVlTX1BSRVNFVCxcbiAgTEFTVF8xNF9EQVlTX1BSRVNFVCxcbiAgTEFTVF8zMF9EQVlTX1BSRVNFVCxcbiAgTEFTVF82MF9EQVlTX1BSRVNFVCxcbiAgTEFTVF85MF9EQVlTX1BSRVNFVCxcbiAgVEhJU19XRUVLX1BSRVNFVCxcbiAgTEFTVF9XRUVLX1BSRVNFVCxcbiAgVEhJU19NT05USF9QUkVTRVQsXG4gIExBU1RfTU9OVEhfUFJFU0VULFxuICBNT05USF9UT19EQVRFX1BSRVNFVCxcbiAgVEhJU19RVUFSVEVSX1BSRVNFVCxcbiAgTEFTVF9RVUFSVEVSX1BSRVNFVCxcbiAgUVVBUlRFUl9UT19EQVRFX1BSRVNFVCxcbiAgVEhJU19ZRUFSX1BSRVNFVCxcbiAgTEFTVF9ZRUFSX1BSRVNFVCxcbiAgWUVBUl9UT19EQVRFX1BSRVNFVFxuXTtcbiJdfQ==