fn-input 0.0.11 → 0.0.12
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/fesm2022/fn-input.mjs +14 -158
- package/fesm2022/fn-input.mjs.map +1 -1
- package/lib/fn-input.component.d.ts +2 -8
- package/lib/fn-input.component.d.ts.map +1 -1
- package/package.json +2 -4
- package/esm2022/fn-input.mjs +0 -5
- package/esm2022/lib/fn-input.component.mjs +0 -1192
- package/esm2022/lib/fn-input.types.mjs +0 -12
- package/esm2022/public-api.mjs +0 -3
|
@@ -1,1192 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, EventEmitter, inject, Input, Output, signal, ViewChild, ViewChildren, } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
// Removed HttpClient import
|
|
4
|
-
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
5
|
-
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
|
6
|
-
import { Subscription, merge } from 'rxjs';
|
|
7
|
-
import { startWith } from 'rxjs/operators';
|
|
8
|
-
import { FNLabel } from 'fn-label';
|
|
9
|
-
import { DEFAULT_CURRENCY_META, FN_TOAST_SERVICE, } from './fn-input.types';
|
|
10
|
-
import * as i0 from "@angular/core";
|
|
11
|
-
import * as i1 from "@angular/forms";
|
|
12
|
-
import * as i2 from "@angular/common";
|
|
13
|
-
import * as i3 from "@ngx-translate/core";
|
|
14
|
-
const CORE_ICONS = {
|
|
15
|
-
'eye-open': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 12s4-8 10-8 10 8 10 8-4 8-10 8-10-8-10-8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><circle cx="12" cy="12" r="3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
16
|
-
'eye-close': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 10a11 11 0 0 0 20 0" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M5 13l-1 2M12 14v2M19 13l1 2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
17
|
-
'two-square': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="8" y="4" width="12" height="12" rx="2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 8v10a2 2 0 0 0 2 2h10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
18
|
-
'round-arrow-top-left': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M23 4v6h-6M1 20v-6h6M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
19
|
-
'check-circle': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/><path d="M8 12l3 3 5-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
20
|
-
'info-circle': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="16" x2="12" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="8" x2="12.01" y2="8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
21
|
-
'alert-circle': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="8" x2="12" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="16" x2="12.01" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
22
|
-
'exclamation-circle': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="8" x2="12" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="16" x2="12.01" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
23
|
-
cross: `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 6L6 18M6 6l12 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`,
|
|
24
|
-
};
|
|
25
|
-
export class FNInput {
|
|
26
|
-
cdr;
|
|
27
|
-
field = {};
|
|
28
|
-
helperHandle;
|
|
29
|
-
toastService;
|
|
30
|
-
injectedToastService = inject(FN_TOAST_SERVICE, { optional: true });
|
|
31
|
-
get effectiveToastService() {
|
|
32
|
-
return this.toastService || this.injectedToastService || undefined;
|
|
33
|
-
}
|
|
34
|
-
currencyMeta = DEFAULT_CURRENCY_META;
|
|
35
|
-
defaultLocale = 'en-US';
|
|
36
|
-
form;
|
|
37
|
-
valueChange = new EventEmitter();
|
|
38
|
-
fieldBlur = new EventEmitter();
|
|
39
|
-
translateService = inject(TranslateService);
|
|
40
|
-
hasFocus = signal(false);
|
|
41
|
-
textareaElement;
|
|
42
|
-
iconContainers;
|
|
43
|
-
// Internal Toast State
|
|
44
|
-
toasts = signal([]);
|
|
45
|
-
// Removed HttpClient injection
|
|
46
|
-
subs = new Subscription();
|
|
47
|
-
sizeMap = {
|
|
48
|
-
extrasmall: 10,
|
|
49
|
-
small: 16,
|
|
50
|
-
medium: 20,
|
|
51
|
-
large: 24,
|
|
52
|
-
'x-large': 32,
|
|
53
|
-
xxlarge: 48,
|
|
54
|
-
};
|
|
55
|
-
getIconSizeName(size) {
|
|
56
|
-
switch (size) {
|
|
57
|
-
case 16:
|
|
58
|
-
return 'small';
|
|
59
|
-
case 20:
|
|
60
|
-
return 'medium';
|
|
61
|
-
case 24:
|
|
62
|
-
return 'large';
|
|
63
|
-
case 32:
|
|
64
|
-
return 'x-large';
|
|
65
|
-
default:
|
|
66
|
-
return 'medium';
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
get isAlphanumeric() {
|
|
70
|
-
return this.field.isAlphanumeric !== false;
|
|
71
|
-
}
|
|
72
|
-
get isEmailField() {
|
|
73
|
-
return this.field.type === 'email' || this.field.name?.toLowerCase().includes('email');
|
|
74
|
-
}
|
|
75
|
-
get alphanumericPattern() {
|
|
76
|
-
if (this.field.isAddressLine) {
|
|
77
|
-
return /[^A-Za-z0-9 \-_&(),/]/g;
|
|
78
|
-
}
|
|
79
|
-
return /[^A-Za-z0-9 \-_&()]/g;
|
|
80
|
-
}
|
|
81
|
-
isDisabled = false;
|
|
82
|
-
control;
|
|
83
|
-
isVisible = signal(true); // Track visibility state
|
|
84
|
-
helperText = '';
|
|
85
|
-
// Use a counter-based approach for unique IDs (safer than Math.random())
|
|
86
|
-
static idCounter = 0;
|
|
87
|
-
uniqueId = `fn-input-${++FNInput.idCounter}`;
|
|
88
|
-
constructor(cdr) {
|
|
89
|
-
this.cdr = cdr;
|
|
90
|
-
}
|
|
91
|
-
ngOnInit() {
|
|
92
|
-
if (this.field.hidden)
|
|
93
|
-
return;
|
|
94
|
-
this.helperText = this.field.helperText ?? '';
|
|
95
|
-
this.initFormControl();
|
|
96
|
-
if (this.field.value)
|
|
97
|
-
this.control.setValue(this.field.value);
|
|
98
|
-
this.setupVisibilityCondition();
|
|
99
|
-
this.setupFieldMessageListener();
|
|
100
|
-
this.setupToastSubscription();
|
|
101
|
-
}
|
|
102
|
-
ngOnDestroy() {
|
|
103
|
-
this.subs.unsubscribe();
|
|
104
|
-
}
|
|
105
|
-
ngOnChanges(changes) {
|
|
106
|
-
if (changes['field'] || changes['form']) {
|
|
107
|
-
this.updateAllIcons();
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
setupFieldMessageListener() {
|
|
111
|
-
if (!this.control)
|
|
112
|
-
return;
|
|
113
|
-
const val$ = this.control.valueChanges.pipe(startWith(this.control.value));
|
|
114
|
-
const status$ = this.control.statusChanges.pipe(startWith(this.control.status));
|
|
115
|
-
this.subs.add(merge(val$, status$).subscribe(() => {
|
|
116
|
-
try {
|
|
117
|
-
this.cdr.detectChanges();
|
|
118
|
-
}
|
|
119
|
-
catch (e) {
|
|
120
|
-
console.warn('CDR detectChanges failed during field message update:', e);
|
|
121
|
-
this.cdr.markForCheck();
|
|
122
|
-
}
|
|
123
|
-
}));
|
|
124
|
-
}
|
|
125
|
-
ngAfterViewInit() {
|
|
126
|
-
// Access the textarea element by ViewChild or native element reference
|
|
127
|
-
this.autoResizeInitial();
|
|
128
|
-
if (this.field.type === 'textarea' && this.control?.value) {
|
|
129
|
-
setTimeout(() => this.autoResizeInitial(), 30);
|
|
130
|
-
}
|
|
131
|
-
// Apply initial formatting after view is initialized
|
|
132
|
-
if (this.field.type === 'number' && this.field.isCurrency && this.control?.value) {
|
|
133
|
-
this.formatInitialCurrencyValue();
|
|
134
|
-
}
|
|
135
|
-
this.setupIconContainersListener();
|
|
136
|
-
}
|
|
137
|
-
setupIconContainersListener() {
|
|
138
|
-
this.subs.add(this.iconContainers.changes.subscribe(() => {
|
|
139
|
-
this.updateAllIcons();
|
|
140
|
-
}));
|
|
141
|
-
}
|
|
142
|
-
enforceLowercase(event) {
|
|
143
|
-
const input = event.target;
|
|
144
|
-
const start = input.selectionStart;
|
|
145
|
-
const end = input.selectionEnd;
|
|
146
|
-
input.value = input.value.toLowerCase();
|
|
147
|
-
if (this.control) {
|
|
148
|
-
this.control.setValue(input.value, { emitEvent: false });
|
|
149
|
-
}
|
|
150
|
-
this.valueChange.emit({ name: this.field.name, value: input.value });
|
|
151
|
-
// restore cursor position so typing is smooth
|
|
152
|
-
input.setSelectionRange(start, end);
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Handle email input - allows only valid email characters and enforces lowercase.
|
|
156
|
-
* Allowed: a-z, 0-9, . _ + - @
|
|
157
|
-
* Rules:
|
|
158
|
-
* - Only one @ allowed
|
|
159
|
-
* - No consecutive dots (..)
|
|
160
|
-
* - Automatic lowercase
|
|
161
|
-
*/
|
|
162
|
-
handleEmailInput(event) {
|
|
163
|
-
const input = event.target;
|
|
164
|
-
const cursorPosition = input.selectionStart || 0;
|
|
165
|
-
const originalValue = input.value;
|
|
166
|
-
// 1. Convert to lowercase
|
|
167
|
-
const lowerValue = originalValue.toLowerCase();
|
|
168
|
-
// 2. Split at the first @ to handle local and domain parts separately
|
|
169
|
-
const parts = lowerValue.split('@');
|
|
170
|
-
let localPart = parts[0];
|
|
171
|
-
let domainPart = parts.length > 1 ? parts.slice(1).join('') : null;
|
|
172
|
-
// 3. Filter local part: a-z, 0-9, ., _, +, -
|
|
173
|
-
// Rule: Cannot start with a dot (.)
|
|
174
|
-
localPart = localPart.replaceAll(/[^a-z0-9._+-]/g, '');
|
|
175
|
-
while (localPart.startsWith('.')) {
|
|
176
|
-
localPart = localPart.substring(1);
|
|
177
|
-
}
|
|
178
|
-
while (localPart.includes('..')) {
|
|
179
|
-
localPart = localPart.replaceAll('..', '.');
|
|
180
|
-
}
|
|
181
|
-
// 4. Filter domain part: a-z, 0-9, ., -
|
|
182
|
-
// Rule: No underscores (_), no plus signs (+), cannot start with a hyphen (-)
|
|
183
|
-
let filteredValue = localPart;
|
|
184
|
-
if (domainPart !== null) {
|
|
185
|
-
domainPart = domainPart.replaceAll(/[^a-z0-9.-]/g, '');
|
|
186
|
-
while (domainPart.startsWith('-')) {
|
|
187
|
-
domainPart = domainPart.substring(1);
|
|
188
|
-
}
|
|
189
|
-
while (domainPart.includes('..')) {
|
|
190
|
-
domainPart = domainPart.replaceAll('..', '.');
|
|
191
|
-
}
|
|
192
|
-
filteredValue += '@' + domainPart;
|
|
193
|
-
}
|
|
194
|
-
if (originalValue !== filteredValue) {
|
|
195
|
-
const charsRemovedBeforeCursor = this.countRemovedCharsBeforeCursor(originalValue.toLowerCase(), filteredValue, cursorPosition);
|
|
196
|
-
input.value = filteredValue;
|
|
197
|
-
this.control.setValue(filteredValue, { emitEvent: false });
|
|
198
|
-
const newCursorPos = Math.max(0, cursorPosition - charsRemovedBeforeCursor);
|
|
199
|
-
input.setSelectionRange(newCursorPos, newCursorPos);
|
|
200
|
-
}
|
|
201
|
-
else if (originalValue !== lowerValue) {
|
|
202
|
-
// If only case changed (e.g., typed Uppercase)
|
|
203
|
-
input.value = filteredValue;
|
|
204
|
-
this.control.setValue(filteredValue, { emitEvent: false });
|
|
205
|
-
input.setSelectionRange(cursorPosition, cursorPosition);
|
|
206
|
-
}
|
|
207
|
-
if (this.field.type === 'password' && this.field.feedback) {
|
|
208
|
-
this.checkPasswordStrength(filteredValue);
|
|
209
|
-
}
|
|
210
|
-
this.valueChange.emit({ name: this.field.name, value: filteredValue });
|
|
211
|
-
this.control.markAsTouched();
|
|
212
|
-
}
|
|
213
|
-
onFocus() {
|
|
214
|
-
this.hasFocus.set(true);
|
|
215
|
-
}
|
|
216
|
-
formatInitialCurrencyValue() {
|
|
217
|
-
const numericValue = Number(this.control.value);
|
|
218
|
-
if (!Number.isNaN(numericValue)) {
|
|
219
|
-
setTimeout(() => {
|
|
220
|
-
const inputElement = document.getElementById(this.uniqueId);
|
|
221
|
-
if (inputElement) {
|
|
222
|
-
inputElement.value = this.formatCurrencyWithCommas(numericValue);
|
|
223
|
-
}
|
|
224
|
-
}, 50);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
initFormControl() {
|
|
228
|
-
const controller = this.form.controls?.[this.field.name];
|
|
229
|
-
this.control = controller;
|
|
230
|
-
if (this.field.value)
|
|
231
|
-
this.control.setValue(this.field.value);
|
|
232
|
-
if (this.control) {
|
|
233
|
-
// Handle disabled state
|
|
234
|
-
if (this.field.disabled ?? false) {
|
|
235
|
-
this.control?.disable();
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
this.control?.enable();
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
autoResizeInitial() {
|
|
243
|
-
const textarea = this.textareaElement?.nativeElement;
|
|
244
|
-
if (textarea) {
|
|
245
|
-
// Get the number of rows (default to 2 if not specified)
|
|
246
|
-
const rows = this.field.rows || 1;
|
|
247
|
-
// Calculate line height from computed styles
|
|
248
|
-
const computedStyle = globalThis.getComputedStyle(textarea);
|
|
249
|
-
const lineHeight = Number.parseFloat(computedStyle.lineHeight) || 32; // Default to 24px if not set
|
|
250
|
-
// Calculate minimum height based on rows
|
|
251
|
-
const minHeight = rows * lineHeight;
|
|
252
|
-
// Reset height to auto to get accurate scrollHeight
|
|
253
|
-
textarea.style.height = 'auto';
|
|
254
|
-
// Use the larger of scrollHeight or minHeight
|
|
255
|
-
const newHeight = Math.max(textarea.scrollHeight, minHeight);
|
|
256
|
-
textarea.style.height = newHeight + 'px';
|
|
257
|
-
textarea.style.overflow = 'hidden';
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
handleTextArea(event) {
|
|
261
|
-
const element = event.target;
|
|
262
|
-
const cursorPosition = element.selectionStart;
|
|
263
|
-
const originalValue = element.value;
|
|
264
|
-
// Apply alphanumeric filtering if enabled
|
|
265
|
-
if (this.field.type === 'textarea' && this.isAlphanumeric) {
|
|
266
|
-
// Only allow characters based on the selected pattern
|
|
267
|
-
const alphanumericPattern = this.alphanumericPattern;
|
|
268
|
-
let filteredValue = originalValue.replaceAll(alphanumericPattern, '');
|
|
269
|
-
// Prevent leading spaces
|
|
270
|
-
if (filteredValue.startsWith(' ')) {
|
|
271
|
-
filteredValue = filteredValue.trimStart();
|
|
272
|
-
}
|
|
273
|
-
// Replace multiple consecutive spaces with single space
|
|
274
|
-
filteredValue = filteredValue.replaceAll(/\s{2,}/g, ' ');
|
|
275
|
-
if (originalValue !== filteredValue) {
|
|
276
|
-
// Calculate the number of characters removed before the cursor position
|
|
277
|
-
const charsRemovedBeforeCursor = originalValue.length - filteredValue.length;
|
|
278
|
-
element.value = filteredValue;
|
|
279
|
-
this.control.setValue(filteredValue, { emitEvent: false });
|
|
280
|
-
// Restore cursor position - account for removed characters
|
|
281
|
-
const newCursorPos = Math.max(0, (cursorPosition || 0) - charsRemovedBeforeCursor);
|
|
282
|
-
element.setSelectionRange(newCursorPos, newCursorPos);
|
|
283
|
-
}
|
|
284
|
-
// increase height
|
|
285
|
-
this.autoResizeInitial();
|
|
286
|
-
this.valueChange.emit({ name: this.field.name, value: filteredValue });
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
let filteredValue = originalValue;
|
|
290
|
-
// Strict filtering if !isAlphanumeric
|
|
291
|
-
if (!this.isAlphanumeric) {
|
|
292
|
-
console.log('isAlphanumeric', this.isAlphanumeric);
|
|
293
|
-
const allowedPattern = /[^a-zA-Z0-9\s(){}[\];,."='+\-*/<>!&|%_@$?:]/g;
|
|
294
|
-
filteredValue = filteredValue.replaceAll(allowedPattern, '');
|
|
295
|
-
}
|
|
296
|
-
// Prevent leading spaces
|
|
297
|
-
if (filteredValue.startsWith(' ')) {
|
|
298
|
-
filteredValue = filteredValue.trimStart();
|
|
299
|
-
}
|
|
300
|
-
// Replace multiple consecutive spaces with single space
|
|
301
|
-
filteredValue = filteredValue.replaceAll(/\s{2,}/g, ' ');
|
|
302
|
-
if (originalValue !== filteredValue) {
|
|
303
|
-
// Calculate the number of characters removed before the cursor position
|
|
304
|
-
const charsRemovedBeforeCursor = originalValue.length - filteredValue.length;
|
|
305
|
-
element.value = filteredValue;
|
|
306
|
-
this.control.setValue(filteredValue, { emitEvent: false });
|
|
307
|
-
// Restore cursor position - account for removed characters
|
|
308
|
-
const newCursorPos = Math.max(0, (cursorPosition || 0) - charsRemovedBeforeCursor);
|
|
309
|
-
element.setSelectionRange(newCursorPos, newCursorPos);
|
|
310
|
-
}
|
|
311
|
-
// increase height
|
|
312
|
-
this.autoResizeInitial();
|
|
313
|
-
this.valueChange.emit({ name: this.field.name, value: filteredValue });
|
|
314
|
-
}
|
|
315
|
-
this.control.markAsTouched();
|
|
316
|
-
}
|
|
317
|
-
togglePasswordVisibility() {
|
|
318
|
-
this.showPassword = !this.showPassword;
|
|
319
|
-
this.updateAllIcons();
|
|
320
|
-
}
|
|
321
|
-
handleInput(event) {
|
|
322
|
-
const target = event.target;
|
|
323
|
-
const cursorPosition = target.selectionStart;
|
|
324
|
-
const originalValue = target.value;
|
|
325
|
-
let filteredValue = originalValue;
|
|
326
|
-
// IF NOT alphanumeric, user wants strict filtering:
|
|
327
|
-
// "only accept tihs.) {} [] ; , . " ' = + - * / < > ! & | % &_( )-/.;@!, $% : dont allow emoji"
|
|
328
|
-
// Interpretation: Allow alphanumeric + specified special chars. Ban emojis.
|
|
329
|
-
// Actually, the user said: "if isAlphanumeric false only accept..."
|
|
330
|
-
// So if isAlphanumeric is TRUE, we use the existing handleAlphanumericInput logic (or similar).
|
|
331
|
-
// The current logic in handleInput is generic.
|
|
332
|
-
// The existing code has a separate `handleAlphanumericInput` method but it's not called here?
|
|
333
|
-
// Wait, the template likely calls `handleAlphanumericInput` if `isAlphanumeric` is true, or `handleInput` otherwise?
|
|
334
|
-
// Let's check the template.
|
|
335
|
-
// BUT assuming `handleInput` is the generic handler:
|
|
336
|
-
if (!this.isAlphanumeric) {
|
|
337
|
-
// Regex to allow: a-z, A-Z, 0-9, and: ) {} [] ; , . " ' = + - * / < > ! & | % _ ( - @ $ ? :
|
|
338
|
-
// Note: User list: ) {} [] ; , . " ' = + - * / < > ! & | % &_( )-/.;@!, $%
|
|
339
|
-
// Combined unique special chars: ) { } [ ] ; , . " ' = + - * / < > ! & | % _ ( @ $ ? :
|
|
340
|
-
// Also space is implied? usually yes.
|
|
341
|
-
// And NO EMOJIS.
|
|
342
|
-
// easier to just replace anything NOT in the allowed set.
|
|
343
|
-
// Allowed chars regex pattern:
|
|
344
|
-
// A-Za-z0-9
|
|
345
|
-
// Space: \s
|
|
346
|
-
// Special: (){}[\];,."='+\-*/<>!&|%_@$?:
|
|
347
|
-
// Note: - inside [] needs to be escaped or at end. ] needs escape. \ needs escape? (not in list).
|
|
348
|
-
// User list has: `.` `"` `'` `?` (wait, ? not in list?)
|
|
349
|
-
// User list: `) {} [] ; , . " ' = + - * / < > ! & | % &_( )-/.;@!, $%`
|
|
350
|
-
// Uniques: ) { } [ ] ; , . " ' = + - * / < > ! & | % _ ( @ $
|
|
351
|
-
// (The `&` is repeated, `.` repeated, `,` repeated etc.)
|
|
352
|
-
// I will create a regex that matches anything NOT in this list and replace with empty string.
|
|
353
|
-
// [^a-zA-Z0-9\s(){}[\];,."='+\-*/<>!&|%_@$]
|
|
354
|
-
// Note: `*`, `+`, `?` etc need escaping in regex if outside [], but inside [] they are literals mostly.
|
|
355
|
-
// `-` needs to be last or escaped. `]` needs escape. `^` needs escape if first? No, invalid here.
|
|
356
|
-
// Let's verify valid chars:
|
|
357
|
-
// a-z A-Z 0-9
|
|
358
|
-
// space
|
|
359
|
-
// ) { } [ ] ; , . " ' = + - * / < > ! & | % _ ( @ $ :
|
|
360
|
-
const allowedPattern = /[^a-zA-Z0-9\s(){}[\];,."='+\-*/<>!&|%_@$?:]/g;
|
|
361
|
-
filteredValue = filteredValue.replaceAll(allowedPattern, '');
|
|
362
|
-
}
|
|
363
|
-
// Prevent leading spaces
|
|
364
|
-
if (filteredValue.startsWith(' ')) {
|
|
365
|
-
filteredValue = filteredValue.trimStart();
|
|
366
|
-
}
|
|
367
|
-
// replaceAll multiple consecutive spaces with single space
|
|
368
|
-
filteredValue = filteredValue.replaceAll(/\s{2,}/g, ' ');
|
|
369
|
-
if (originalValue !== filteredValue) {
|
|
370
|
-
// Calculate the number of characters removed before the cursor position
|
|
371
|
-
const charsRemovedBeforeCursor = originalValue.length - filteredValue.length;
|
|
372
|
-
target.value = filteredValue;
|
|
373
|
-
this.control.setValue(filteredValue, { emitEvent: false });
|
|
374
|
-
// Restore cursor position - account for removed characters
|
|
375
|
-
const newCursorPos = Math.max(0, (cursorPosition || 0) - charsRemovedBeforeCursor);
|
|
376
|
-
target.setSelectionRange(newCursorPos, newCursorPos);
|
|
377
|
-
}
|
|
378
|
-
// Trailing spaces will be trimmed on blur, not during input
|
|
379
|
-
if (this.field.type === 'password' && this.field.feedback) {
|
|
380
|
-
this.checkPasswordStrength(filteredValue);
|
|
381
|
-
}
|
|
382
|
-
this.valueChange.emit({ name: this.field.name, value: filteredValue });
|
|
383
|
-
this.control.markAsTouched();
|
|
384
|
-
}
|
|
385
|
-
/**
|
|
386
|
-
* Handle alphanumeric input - allows only letters, numbers, and specific special characters
|
|
387
|
-
* Allowed: A-Z, a-z, 0-9, space, hyphen, underscore, ampersand, and parentheses
|
|
388
|
-
* Also prevents leading spaces and multiple consecutive spaces
|
|
389
|
-
*/
|
|
390
|
-
handleAlphanumericInput(event) {
|
|
391
|
-
const target = event.target;
|
|
392
|
-
const cursorPosition = target.selectionStart;
|
|
393
|
-
const originalValue = target.value;
|
|
394
|
-
// Only allow characters based on the selected pattern
|
|
395
|
-
const alphanumericPattern = this.alphanumericPattern;
|
|
396
|
-
let filteredValue = originalValue.replaceAll(alphanumericPattern, '');
|
|
397
|
-
// Prevent leading spaces
|
|
398
|
-
if (filteredValue.startsWith(' ')) {
|
|
399
|
-
filteredValue = filteredValue.trimStart();
|
|
400
|
-
}
|
|
401
|
-
// Replace multiple consecutive spaces with single space
|
|
402
|
-
filteredValue = filteredValue.replaceAll(/\s{2,}/g, ' ');
|
|
403
|
-
if (originalValue !== filteredValue) {
|
|
404
|
-
// Calculate the number of characters removed before the cursor position
|
|
405
|
-
const charsRemovedBeforeCursor = originalValue.length - filteredValue.length;
|
|
406
|
-
target.value = filteredValue;
|
|
407
|
-
this.control.setValue(filteredValue, { emitEvent: false });
|
|
408
|
-
// Restore cursor position - account for removed characters
|
|
409
|
-
const newCursorPos = Math.max(0, (cursorPosition || 0) - charsRemovedBeforeCursor);
|
|
410
|
-
target.setSelectionRange(newCursorPos, newCursorPos);
|
|
411
|
-
}
|
|
412
|
-
if (this.field.type === 'password' && this.field.feedback) {
|
|
413
|
-
this.checkPasswordStrength(filteredValue);
|
|
414
|
-
}
|
|
415
|
-
this.valueChange.emit({ name: this.field.name, value: filteredValue });
|
|
416
|
-
this.control.markAsTouched();
|
|
417
|
-
}
|
|
418
|
-
handleBlur(e, maxDecimals = 2) {
|
|
419
|
-
this.hasFocus.set(false);
|
|
420
|
-
const target = e.target;
|
|
421
|
-
const cleanValueString = target.value;
|
|
422
|
-
if (!cleanValueString) {
|
|
423
|
-
this.fieldBlur.emit({ name: this.field.name, value: '' });
|
|
424
|
-
this.cdr.detectChanges();
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
// Delegate to type-specific handlers
|
|
428
|
-
if (this.field.type === 'text' || this.field.type === 'textarea') {
|
|
429
|
-
this.handleTextFieldBlur(target, cleanValueString);
|
|
430
|
-
}
|
|
431
|
-
else if (this.field.type === 'number') {
|
|
432
|
-
this.handleNumberFieldBlur(target, cleanValueString, maxDecimals);
|
|
433
|
-
}
|
|
434
|
-
// Emit final value
|
|
435
|
-
this.fieldBlur.emit({
|
|
436
|
-
name: this.field.name,
|
|
437
|
-
value: target.value,
|
|
438
|
-
});
|
|
439
|
-
this.cdr.detectChanges();
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Handle blur for text and textarea fields - trim trailing spaces
|
|
443
|
-
*/
|
|
444
|
-
handleTextFieldBlur(target, cleanValueString) {
|
|
445
|
-
const trimmed = cleanValueString.trim();
|
|
446
|
-
if (cleanValueString !== trimmed) {
|
|
447
|
-
target.value = trimmed;
|
|
448
|
-
this.control.setValue(trimmed, { emitEvent: false });
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Handle blur for number fields - validate and format
|
|
453
|
-
*/
|
|
454
|
-
handleNumberFieldBlur(target, cleanValueString, maxDecimals) {
|
|
455
|
-
// Remove commas for parsing/validation
|
|
456
|
-
const numString = cleanValueString.replaceAll(',', '');
|
|
457
|
-
// Check if the string is a valid number format
|
|
458
|
-
const isValidNumberFormat = /^-?\d+(\.\d+)?$/.test(numString);
|
|
459
|
-
// If not a valid number format, clear the field
|
|
460
|
-
if (!isValidNumberFormat) {
|
|
461
|
-
target.value = '';
|
|
462
|
-
this.control.setValue('');
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
// Format currency fields or set raw value for non-currency
|
|
466
|
-
if (this.field.type === 'number' && this.field.isCurrency) {
|
|
467
|
-
this.processCurrencyValue(target, numString, maxDecimals);
|
|
468
|
-
}
|
|
469
|
-
else {
|
|
470
|
-
// Non-currency: preserve the raw string value
|
|
471
|
-
target.value = numString;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Process currency value - handle formatting and decimal places
|
|
476
|
-
*/
|
|
477
|
-
processCurrencyValue(target, numString, maxDecimals) {
|
|
478
|
-
// Handle negative values - convert to positive
|
|
479
|
-
let processedValue = numString.startsWith('-') ? numString.substring(1) : numString;
|
|
480
|
-
// Handle edge case of "-0" or just "-"
|
|
481
|
-
if (processedValue === '' || processedValue === '0') {
|
|
482
|
-
processedValue = '0';
|
|
483
|
-
}
|
|
484
|
-
// Format the value with proper decimal places
|
|
485
|
-
const cleanValueString = this.formatDecimalPlaces(processedValue, maxDecimals);
|
|
486
|
-
const formattedValue = this.formatCurrencyWithCommas(cleanValueString, maxDecimals);
|
|
487
|
-
// Update the control value with the numeric string (not formatted)
|
|
488
|
-
this.control.setValue(cleanValueString, { emitEvent: false });
|
|
489
|
-
// Trigger validators and mark as touched
|
|
490
|
-
this.control.updateValueAndValidity();
|
|
491
|
-
this.control.markAsTouched();
|
|
492
|
-
// Set display value with commas after Angular's form control update
|
|
493
|
-
setTimeout(() => {
|
|
494
|
-
target.value = formattedValue;
|
|
495
|
-
}, 0);
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* Format decimal places - pad or truncate to maxDecimals
|
|
499
|
-
*/
|
|
500
|
-
formatDecimalPlaces(value, maxDecimals) {
|
|
501
|
-
let [intPart, decPart] = value.includes('.') ? value.split('.') : [value, ''];
|
|
502
|
-
// Pad or truncate decimal part to maxDecimals
|
|
503
|
-
if (decPart.length < maxDecimals) {
|
|
504
|
-
decPart = decPart.padEnd(maxDecimals, '0');
|
|
505
|
-
}
|
|
506
|
-
else if (decPart.length > maxDecimals) {
|
|
507
|
-
decPart = decPart.slice(0, maxDecimals);
|
|
508
|
-
}
|
|
509
|
-
// Build the clean value string (without commas)
|
|
510
|
-
return maxDecimals > 0 ? `${intPart}.${decPart}` : intPart;
|
|
511
|
-
}
|
|
512
|
-
handleNumberInput(event, maxDecimals = 2) {
|
|
513
|
-
const target = event.target;
|
|
514
|
-
const originalValue = target.value;
|
|
515
|
-
const cursorPosition = target.selectionStart ?? 0;
|
|
516
|
-
// Step 1: Filter and format the input value
|
|
517
|
-
let value = this.filterNumericInput(target.value, maxDecimals);
|
|
518
|
-
// Step 2: Update cursor position if value changed
|
|
519
|
-
this.updateCursorPositionAfterFilter(target, originalValue, value, cursorPosition);
|
|
520
|
-
// Step 3: Update form control and validate
|
|
521
|
-
this.updateFormControlValue(value, maxDecimals);
|
|
522
|
-
// Step 4: Emit changes
|
|
523
|
-
this.valueChange.emit({ name: this.field.name, value: target.value });
|
|
524
|
-
this.control.markAsTouched();
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Filter numeric input to only allow digits and decimal point
|
|
528
|
-
* Ensures only one decimal point and enforces max decimal places
|
|
529
|
-
*/
|
|
530
|
-
filterNumericInput(value, maxDecimals) {
|
|
531
|
-
// Remove ALL non-numeric characters except decimal point
|
|
532
|
-
let filtered = value.replaceAll(/[^0-9.]/g, '');
|
|
533
|
-
// Ensure only one decimal point
|
|
534
|
-
filtered = this.filterDecimalPoints(filtered);
|
|
535
|
-
// Restrict to maxDecimals decimal places if decimal exists
|
|
536
|
-
filtered = this.enforceDecimalLimit(filtered, maxDecimals);
|
|
537
|
-
return filtered;
|
|
538
|
-
}
|
|
539
|
-
/**
|
|
540
|
-
* Ensure only one decimal point exists in the value
|
|
541
|
-
*/
|
|
542
|
-
filterDecimalPoints(value) {
|
|
543
|
-
const parts = value.split('.');
|
|
544
|
-
if (parts.length > 2) {
|
|
545
|
-
return parts[0] + '.' + parts.slice(1).join('');
|
|
546
|
-
}
|
|
547
|
-
return value;
|
|
548
|
-
}
|
|
549
|
-
/**
|
|
550
|
-
* Enforce maximum decimal places limit
|
|
551
|
-
*/
|
|
552
|
-
enforceDecimalLimit(value, maxDecimals) {
|
|
553
|
-
if (!value.includes('.')) {
|
|
554
|
-
return value;
|
|
555
|
-
}
|
|
556
|
-
const [integerPart, decimalPart] = value.split('.');
|
|
557
|
-
if (decimalPart && decimalPart.length > maxDecimals) {
|
|
558
|
-
return integerPart + '.' + decimalPart.slice(0, maxDecimals);
|
|
559
|
-
}
|
|
560
|
-
return value;
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Update cursor position after filtering input
|
|
564
|
-
*/
|
|
565
|
-
updateCursorPositionAfterFilter(target, originalValue, newValue, cursorPosition) {
|
|
566
|
-
if (target.value === newValue) {
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
const charsRemovedBeforeCursor = this.countRemovedCharsBeforeCursor(originalValue, newValue, cursorPosition);
|
|
570
|
-
target.value = newValue;
|
|
571
|
-
const newPosition = Math.max(0, cursorPosition - charsRemovedBeforeCursor);
|
|
572
|
-
target.setSelectionRange(newPosition, newPosition);
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Update form control value and perform validation
|
|
576
|
-
*/
|
|
577
|
-
updateFormControlValue(value, maxDecimals) {
|
|
578
|
-
this.control.setValue(value, { emitEvent: false });
|
|
579
|
-
this.validateIntegerDigits(value, maxDecimals);
|
|
580
|
-
this.clearNumericError();
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* Count how many characters were removed before the cursor position
|
|
584
|
-
* This helps maintain correct cursor position after filtering input
|
|
585
|
-
*/
|
|
586
|
-
countRemovedCharsBeforeCursor(original, filtered, cursorPos) {
|
|
587
|
-
let removedCount = 0;
|
|
588
|
-
let filteredIndex = 0;
|
|
589
|
-
for (let i = 0; i < cursorPos && i < original.length; i++) {
|
|
590
|
-
if (filteredIndex < filtered.length && original[i] === filtered[filteredIndex]) {
|
|
591
|
-
filteredIndex++;
|
|
592
|
-
}
|
|
593
|
-
else {
|
|
594
|
-
removedCount++;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return removedCount;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Handle paste event for number inputs
|
|
601
|
-
* Prevents pasting of non-numeric characters and enforces digit limits
|
|
602
|
-
*/
|
|
603
|
-
handleNumberPaste(event, maxDecimals = 2) {
|
|
604
|
-
event.preventDefault();
|
|
605
|
-
const target = event.target;
|
|
606
|
-
const pastedText = event.clipboardData?.getData('text') || '';
|
|
607
|
-
const isCurrency = this.field.type === 'number' && !!this.field.isCurrency;
|
|
608
|
-
const filteredText = isCurrency
|
|
609
|
-
? this.getFilteredCurrencyPastedText(pastedText)
|
|
610
|
-
: this.getFilteredIntegerPastedText(pastedText);
|
|
611
|
-
const finalValue = this.buildFinalPasteValue(target, filteredText, isCurrency, maxDecimals);
|
|
612
|
-
// Update the input
|
|
613
|
-
target.value = finalValue;
|
|
614
|
-
this.control.setValue(finalValue, { emitEvent: false });
|
|
615
|
-
this.validateIntegerDigits(finalValue, maxDecimals);
|
|
616
|
-
this.clearNumericError();
|
|
617
|
-
this.valueChange.emit({ name: this.field.name, value: finalValue });
|
|
618
|
-
this.control.markAsTouched();
|
|
619
|
-
this.setCursorAfterPaste(target, filteredText, finalValue);
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Filter pasted text for currency input (allows digits and decimal point)
|
|
623
|
-
*/
|
|
624
|
-
getFilteredCurrencyPastedText(pastedText) {
|
|
625
|
-
return pastedText.replaceAll(/[^0-9.]/g, '');
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* Filter pasted text for integer-only input (allows digits only)
|
|
629
|
-
*/
|
|
630
|
-
getFilteredIntegerPastedText(pastedText) {
|
|
631
|
-
return pastedText.replaceAll(/\D/g, '');
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Build final value after paste operation
|
|
635
|
-
*/
|
|
636
|
-
buildFinalPasteValue(target, filteredText, isCurrency, maxDecimals) {
|
|
637
|
-
const currentValue = target.value;
|
|
638
|
-
const start = target.selectionStart;
|
|
639
|
-
const end = target.selectionEnd;
|
|
640
|
-
let finalValue;
|
|
641
|
-
// If selection API is not supported or no selection, replace entire content
|
|
642
|
-
if (start === null || end === null || (start === 0 && end === 0)) {
|
|
643
|
-
finalValue = filteredText;
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
finalValue = currentValue.substring(0, start) + filteredText + currentValue.substring(end);
|
|
647
|
-
}
|
|
648
|
-
return isCurrency ? this.applyDecimalRestrictions(finalValue, maxDecimals) : finalValue;
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* Apply decimal restrictions for currency fields
|
|
652
|
-
*/
|
|
653
|
-
applyDecimalRestrictions(value, maxDecimals) {
|
|
654
|
-
let result = value;
|
|
655
|
-
// Ensure only one decimal point
|
|
656
|
-
const parts = result.split('.');
|
|
657
|
-
if (parts.length > 2) {
|
|
658
|
-
result = parts[0] + '.' + parts.slice(1).join('');
|
|
659
|
-
}
|
|
660
|
-
// Restrict to maxDecimals decimal places
|
|
661
|
-
if (result.includes('.')) {
|
|
662
|
-
const [intPart, decPart] = result.split('.');
|
|
663
|
-
if (decPart.length > maxDecimals) {
|
|
664
|
-
result = intPart + '.' + decPart.slice(0, maxDecimals);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return result;
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Validate integer digit limit and set/clear errors
|
|
671
|
-
*/
|
|
672
|
-
validateIntegerDigits(value, maxDecimals) {
|
|
673
|
-
if (this.field.type !== 'number' || !this.field.maxIntegerDigits) {
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
const maxIntDigits = this.field.maxIntegerDigits ?? 15;
|
|
677
|
-
const [intPart] = value.includes('.') ? value.split('.') : [value];
|
|
678
|
-
if (intPart.length > maxIntDigits) {
|
|
679
|
-
this.setMaxIntegerDigitsError(intPart.length, maxIntDigits, maxDecimals);
|
|
680
|
-
}
|
|
681
|
-
else {
|
|
682
|
-
this.clearMaxIntegerDigitsError();
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
/**
|
|
686
|
-
* Set max integer digits error
|
|
687
|
-
*/
|
|
688
|
-
setMaxIntegerDigitsError(actual, max, maxDecimals) {
|
|
689
|
-
const currentErrors = this.control.errors || {};
|
|
690
|
-
this.control.setErrors({
|
|
691
|
-
...currentErrors,
|
|
692
|
-
maxIntegerDigits: {
|
|
693
|
-
actual,
|
|
694
|
-
max,
|
|
695
|
-
maxDecimals,
|
|
696
|
-
message: `Please shorten your input to ${max} whole digits and ${maxDecimals} decimal or fewer.`,
|
|
697
|
-
},
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
/**
|
|
701
|
-
* Clear max integer digits error if present
|
|
702
|
-
*/
|
|
703
|
-
clearMaxIntegerDigitsError() {
|
|
704
|
-
if (!this.control.hasError('maxIntegerDigits')) {
|
|
705
|
-
return;
|
|
706
|
-
}
|
|
707
|
-
const errors = { ...this.control.errors };
|
|
708
|
-
delete errors['maxIntegerDigits'];
|
|
709
|
-
this.control.setErrors(Object.keys(errors).length ? errors : null);
|
|
710
|
-
}
|
|
711
|
-
/**
|
|
712
|
-
* Clear numeric error if present
|
|
713
|
-
*/
|
|
714
|
-
clearNumericError() {
|
|
715
|
-
if (!this.control.hasError('numeric')) {
|
|
716
|
-
return;
|
|
717
|
-
}
|
|
718
|
-
const errors = { ...this.control.errors };
|
|
719
|
-
delete errors['numeric'];
|
|
720
|
-
this.control.setErrors(Object.keys(errors).length ? errors : null);
|
|
721
|
-
}
|
|
722
|
-
/**
|
|
723
|
-
* Set cursor position after paste operation
|
|
724
|
-
*/
|
|
725
|
-
setCursorAfterPaste(target, filteredText, finalValue) {
|
|
726
|
-
// Input type="number" does not support selection APIs
|
|
727
|
-
if (target.type === 'number') {
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
const start = target.selectionStart || 0;
|
|
731
|
-
const newCursorPos = start + filteredText.length;
|
|
732
|
-
const actualPos = Math.min(newCursorPos, finalValue.length);
|
|
733
|
-
target.setSelectionRange(actualPos, actualPos);
|
|
734
|
-
}
|
|
735
|
-
// Format number with comma separators
|
|
736
|
-
// Uses string-based formatting for large numbers to preserve precision
|
|
737
|
-
formatCurrencyWithCommas(value, maxDecimals = 2) {
|
|
738
|
-
if (this.field.type !== 'number' || !this.field.isCurrency)
|
|
739
|
-
return value.toString();
|
|
740
|
-
const strValue = value.toString();
|
|
741
|
-
// Return original value for empty or invalid inputs
|
|
742
|
-
if (!strValue || strValue === 'NaN')
|
|
743
|
-
return '';
|
|
744
|
-
// Use string-based formatting to preserve precision for large numbers
|
|
745
|
-
const [integerPart, decimalPart] = strValue.includes('.')
|
|
746
|
-
? strValue.split('.')
|
|
747
|
-
: [strValue, ''];
|
|
748
|
-
// Format integer part with comma separators (every 3 digits from right)
|
|
749
|
-
// Using iterative approach instead of regex to avoid ReDoS concerns
|
|
750
|
-
let formattedInteger = '';
|
|
751
|
-
const len = integerPart.length;
|
|
752
|
-
for (let i = 0; i < len; i++) {
|
|
753
|
-
if (i > 0 && (len - i) % 3 === 0) {
|
|
754
|
-
formattedInteger += ',';
|
|
755
|
-
}
|
|
756
|
-
formattedInteger += integerPart[i];
|
|
757
|
-
}
|
|
758
|
-
// Format decimal part (pad or truncate to maxDecimals)
|
|
759
|
-
let formattedDecimal = decimalPart || '';
|
|
760
|
-
if (formattedDecimal.length < maxDecimals) {
|
|
761
|
-
formattedDecimal = formattedDecimal.padEnd(maxDecimals, '0');
|
|
762
|
-
}
|
|
763
|
-
else if (formattedDecimal.length > maxDecimals) {
|
|
764
|
-
formattedDecimal = formattedDecimal.slice(0, maxDecimals);
|
|
765
|
-
}
|
|
766
|
-
return maxDecimals > 0 ? `${formattedInteger}.${formattedDecimal}` : formattedInteger;
|
|
767
|
-
}
|
|
768
|
-
handleNumberKeydown(event, isCurrency) {
|
|
769
|
-
if (isCurrency)
|
|
770
|
-
return;
|
|
771
|
-
// Allow: Backspace, Delete, Tab, Arrow keys
|
|
772
|
-
if (['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
|
|
773
|
-
return;
|
|
774
|
-
}
|
|
775
|
-
// Allow clipboard operations (Ctrl+V, Ctrl+C, Ctrl+X, Cmd+V, Cmd+C, Cmd+X)
|
|
776
|
-
// and selection (Ctrl+A, Cmd+A)
|
|
777
|
-
if (event.ctrlKey || event.metaKey) {
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
// Block everything that is not 0-9
|
|
781
|
-
if (!/^\d$/.test(event.key)) {
|
|
782
|
-
event.preventDefault();
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
// Get locale from currency code using currencyMeta
|
|
786
|
-
getLocaleFromCurrency(currencyCode) {
|
|
787
|
-
const currencyObj = this.currencyMeta.find((c) => c.code === currencyCode);
|
|
788
|
-
return currencyObj?.locale || this.defaultLocale;
|
|
789
|
-
}
|
|
790
|
-
showPassword = false;
|
|
791
|
-
passwordStrengthLabel = '';
|
|
792
|
-
strengthClass = '';
|
|
793
|
-
passwordStrengthPercent = 0;
|
|
794
|
-
isPasswordFocused = false;
|
|
795
|
-
onPasswordFocus() {
|
|
796
|
-
this.hasFocus.set(true);
|
|
797
|
-
this.isPasswordFocused = true;
|
|
798
|
-
this.cdr.detectChanges();
|
|
799
|
-
}
|
|
800
|
-
onPasswordBlur() {
|
|
801
|
-
this.isPasswordFocused = false;
|
|
802
|
-
this.cdr.detectChanges();
|
|
803
|
-
}
|
|
804
|
-
handlePasswordBlur(e) {
|
|
805
|
-
this.handleBlur(e); // Original blur functionality (sets hasFocus to false)
|
|
806
|
-
this.onPasswordBlur(); // Hide password feedback
|
|
807
|
-
}
|
|
808
|
-
checkPasswordStrength(value) {
|
|
809
|
-
if (!value || this.field.type !== 'password') {
|
|
810
|
-
this.passwordStrengthLabel = '';
|
|
811
|
-
this.strengthClass = '';
|
|
812
|
-
this.passwordStrengthPercent = 0;
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
let score = 0;
|
|
816
|
-
if (value.length >= 8)
|
|
817
|
-
score++;
|
|
818
|
-
if (/[A-Z]/.test(value))
|
|
819
|
-
score++;
|
|
820
|
-
if (/\d/.test(value))
|
|
821
|
-
score++;
|
|
822
|
-
if (/[\W_]/.test(value))
|
|
823
|
-
score++;
|
|
824
|
-
if (score <= 1) {
|
|
825
|
-
this.passwordStrengthLabel = this.field.weakLabel || 'Weak';
|
|
826
|
-
this.strengthClass = 'text-[var(--RHB-Red-100)]';
|
|
827
|
-
this.passwordStrengthPercent = 25;
|
|
828
|
-
}
|
|
829
|
-
else if (score === 2 || score === 3) {
|
|
830
|
-
this.passwordStrengthLabel = this.field.mediumLabel || 'Medium';
|
|
831
|
-
this.strengthClass = 'text-[var(--Orange-100)]';
|
|
832
|
-
this.passwordStrengthPercent = score === 2 ? 50 : 75;
|
|
833
|
-
}
|
|
834
|
-
else {
|
|
835
|
-
this.passwordStrengthLabel = this.field.strongLabel || 'Strong';
|
|
836
|
-
this.strengthClass = 'text-[var(--Green-100)]';
|
|
837
|
-
this.passwordStrengthPercent = 100;
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
increment() {
|
|
841
|
-
if (this.field.type !== 'number')
|
|
842
|
-
return;
|
|
843
|
-
const step = this.field.step || 1;
|
|
844
|
-
const current = Number(this.control.value) || 0;
|
|
845
|
-
let nextValue = current + step;
|
|
846
|
-
if (typeof this.field.max === 'number') {
|
|
847
|
-
nextValue = Math.min(nextValue, this.field.max);
|
|
848
|
-
}
|
|
849
|
-
this.control.setValue(nextValue);
|
|
850
|
-
this.control.markAsTouched();
|
|
851
|
-
this.valueChange.emit({ name: this.field.name, value: nextValue });
|
|
852
|
-
// Update display value for currency inputs
|
|
853
|
-
if (this.field.isCurrency) {
|
|
854
|
-
setTimeout(() => {
|
|
855
|
-
const inputElement = document.getElementById(this.uniqueId);
|
|
856
|
-
if (inputElement) {
|
|
857
|
-
inputElement.value = this.formatCurrencyWithCommas(nextValue);
|
|
858
|
-
}
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
decrement() {
|
|
863
|
-
if (this.field.type !== 'number')
|
|
864
|
-
return;
|
|
865
|
-
const step = this.field.step || 1;
|
|
866
|
-
const current = Number(this.control.value) || 0;
|
|
867
|
-
let nextValue = current - step;
|
|
868
|
-
// Ensure minimum value is 0 (no negative values)
|
|
869
|
-
const minValue = Math.max(this.field.min || 0, 0);
|
|
870
|
-
nextValue = Math.max(nextValue, minValue);
|
|
871
|
-
this.control.setValue(nextValue);
|
|
872
|
-
this.control.markAsTouched();
|
|
873
|
-
this.valueChange.emit({ name: this.field.name, value: nextValue });
|
|
874
|
-
// Update display value for currency inputs
|
|
875
|
-
if (this.field.isCurrency) {
|
|
876
|
-
setTimeout(() => {
|
|
877
|
-
const inputElement = document.getElementById(this.uniqueId);
|
|
878
|
-
if (inputElement) {
|
|
879
|
-
inputElement.value = this.formatCurrencyWithCommas(nextValue);
|
|
880
|
-
}
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
copyText(e) {
|
|
885
|
-
e.stopPropagation();
|
|
886
|
-
if (!this.control.value)
|
|
887
|
-
return;
|
|
888
|
-
navigator.clipboard.writeText(this.control.value).then(() => {
|
|
889
|
-
const service = this.effectiveToastService;
|
|
890
|
-
if (service) {
|
|
891
|
-
// Position set to top as requested
|
|
892
|
-
service.success('Copied to clipboard', 'Success', 2000);
|
|
893
|
-
}
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
prefixClick(e) {
|
|
897
|
-
if (this.field.prefix?.onClick) {
|
|
898
|
-
this.field.prefix.onClick(e);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
suffixClick(e) {
|
|
902
|
-
if (this.field.suffix?.onClick) {
|
|
903
|
-
this.field.suffix.onClick(e);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* Set up visibility condition listener
|
|
908
|
-
* Watches the dependent field and shows/hides this field based on conditions
|
|
909
|
-
*/
|
|
910
|
-
setupVisibilityCondition() {
|
|
911
|
-
if (!this.field.visibilityCondition || !this.form)
|
|
912
|
-
return;
|
|
913
|
-
const { dependsOn } = this.field.visibilityCondition;
|
|
914
|
-
const dependentControl = this.form.get(dependsOn);
|
|
915
|
-
if (!dependentControl) {
|
|
916
|
-
return;
|
|
917
|
-
}
|
|
918
|
-
// Initial visibility check
|
|
919
|
-
this.updateVisibility(dependentControl.value);
|
|
920
|
-
// Subscribe to value changes
|
|
921
|
-
dependentControl.valueChanges.subscribe((value) => {
|
|
922
|
-
this.updateVisibility(value);
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Update field visibility based on dependent field value
|
|
927
|
-
*/
|
|
928
|
-
updateVisibility(dependentValue) {
|
|
929
|
-
if (!this.field.visibilityCondition)
|
|
930
|
-
return;
|
|
931
|
-
const { showWhen, hideWhen } = this.field.visibilityCondition;
|
|
932
|
-
let shouldBeVisible = false;
|
|
933
|
-
// Check showWhen condition
|
|
934
|
-
if (showWhen !== undefined) {
|
|
935
|
-
if (Array.isArray(showWhen)) {
|
|
936
|
-
shouldBeVisible = showWhen.includes(dependentValue);
|
|
937
|
-
}
|
|
938
|
-
else {
|
|
939
|
-
shouldBeVisible = dependentValue === showWhen;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
// Check hideWhen condition (overrides showWhen)
|
|
943
|
-
if (hideWhen !== undefined) {
|
|
944
|
-
const shouldHide = Array.isArray(hideWhen)
|
|
945
|
-
? hideWhen.includes(dependentValue)
|
|
946
|
-
: dependentValue === hideWhen;
|
|
947
|
-
if (shouldHide) {
|
|
948
|
-
shouldBeVisible = false;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
// Update visibility
|
|
952
|
-
this.isVisible.set(shouldBeVisible);
|
|
953
|
-
// Only clear value when hiding if there's no initial value
|
|
954
|
-
// This preserves data when editing existing records
|
|
955
|
-
if (!shouldBeVisible && this.control && !this.control.value) {
|
|
956
|
-
this.control.setValue(null);
|
|
957
|
-
this.control.markAsUntouched();
|
|
958
|
-
this.control.updateValueAndValidity();
|
|
959
|
-
}
|
|
960
|
-
this.cdr.detectChanges();
|
|
961
|
-
}
|
|
962
|
-
setupToastSubscription() {
|
|
963
|
-
const service = this.effectiveToastService;
|
|
964
|
-
if (service) {
|
|
965
|
-
this.subs.add(service.toasts$.subscribe((toasts) => {
|
|
966
|
-
this.toasts.set(toasts);
|
|
967
|
-
// Wait for DOM to update then render toast icons
|
|
968
|
-
this.updateAllIcons();
|
|
969
|
-
}));
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
removeToast(id) {
|
|
973
|
-
this.effectiveToastService?.remove(id);
|
|
974
|
-
}
|
|
975
|
-
getTranslatedMessage(message) {
|
|
976
|
-
if (this.helperHandle && typeof this.helperHandle.translate === 'function') {
|
|
977
|
-
return this.helperHandle.translate(message);
|
|
978
|
-
}
|
|
979
|
-
return message;
|
|
980
|
-
}
|
|
981
|
-
getToastIconName(toast) {
|
|
982
|
-
switch (toast.type) {
|
|
983
|
-
case 'success':
|
|
984
|
-
return 'check-circle';
|
|
985
|
-
case 'warn':
|
|
986
|
-
case 'info':
|
|
987
|
-
return 'info-circle';
|
|
988
|
-
case 'error':
|
|
989
|
-
return 'exclamation-circle';
|
|
990
|
-
default:
|
|
991
|
-
return 'info-circle';
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
showFormFieldMessage(control, helperText) {
|
|
995
|
-
if (this.helperHandle) {
|
|
996
|
-
return this.helperHandle.showFormFieldMessage(control, helperText);
|
|
997
|
-
}
|
|
998
|
-
const isError = control?.touched && !!control?.errors;
|
|
999
|
-
const isHelper = !isError && Boolean(helperText ?? '');
|
|
1000
|
-
return isError || isHelper;
|
|
1001
|
-
}
|
|
1002
|
-
getTranslatedLabel(label) {
|
|
1003
|
-
if (!label)
|
|
1004
|
-
return '';
|
|
1005
|
-
try {
|
|
1006
|
-
const labelStr = label.toString();
|
|
1007
|
-
return (labelStr
|
|
1008
|
-
.split('::')
|
|
1009
|
-
.map((part) => part.trim())
|
|
1010
|
-
.filter((part) => !!part)
|
|
1011
|
-
.map((part) => this.translateService.instant(part))
|
|
1012
|
-
.join(' ') + this.getEndSymbol(labelStr));
|
|
1013
|
-
}
|
|
1014
|
-
catch (e) {
|
|
1015
|
-
console.warn('Translation failed in getTranslatedLabel:', label, e);
|
|
1016
|
-
return label;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
getEndSymbol(label) {
|
|
1020
|
-
return label.toString().includes('required') && label.toString().includes('FNFieldMessage')
|
|
1021
|
-
? '.'
|
|
1022
|
-
: '';
|
|
1023
|
-
}
|
|
1024
|
-
// --- ICON LOGIC ---
|
|
1025
|
-
updateAllIcons() {
|
|
1026
|
-
// We'll call this after ViewInit or when inputs change
|
|
1027
|
-
setTimeout(() => {
|
|
1028
|
-
this.iconContainers?.forEach((container) => {
|
|
1029
|
-
const ds = container.nativeElement.dataset;
|
|
1030
|
-
const name = ds['iconName'];
|
|
1031
|
-
const variant = ds['iconVariant'] || 'Line';
|
|
1032
|
-
const size = (ds['iconSize'] || 'medium');
|
|
1033
|
-
const color = ds['iconColor'];
|
|
1034
|
-
const disabled = ds['iconDisabled'] === 'true';
|
|
1035
|
-
if (name) {
|
|
1036
|
-
this.loadIconToContainer(container.nativeElement, name, variant, size, color, disabled);
|
|
1037
|
-
}
|
|
1038
|
-
});
|
|
1039
|
-
}, 0);
|
|
1040
|
-
}
|
|
1041
|
-
loadIconToContainer(container, name, variant, sizeName, color, disabled) {
|
|
1042
|
-
const size = this.sizeMap[sizeName];
|
|
1043
|
-
// 1. Check if raw SVG string is provided
|
|
1044
|
-
const trimmedName = name.trim();
|
|
1045
|
-
if (trimmedName.startsWith('<svg')) {
|
|
1046
|
-
this.renderSvgToContainer(container, trimmedName, color, size, 'custom', disabled);
|
|
1047
|
-
return;
|
|
1048
|
-
}
|
|
1049
|
-
// 1b. Check if it's just raw SVG inner content (like `<path ...>`)
|
|
1050
|
-
if (trimmedName.startsWith('<path') ||
|
|
1051
|
-
trimmedName.startsWith('<g') ||
|
|
1052
|
-
trimmedName.startsWith('<circle') ||
|
|
1053
|
-
trimmedName.startsWith('<rect') ||
|
|
1054
|
-
trimmedName.startsWith('<polygon')) {
|
|
1055
|
-
const wrappedSvg = `<svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">${trimmedName}</svg>`;
|
|
1056
|
-
this.renderSvgToContainer(container, wrappedSvg, color, size, 'custom', disabled);
|
|
1057
|
-
return;
|
|
1058
|
-
}
|
|
1059
|
-
// 2. Check built-in icons registry
|
|
1060
|
-
// Strip possible --size suffix if it was passed by mistake from old logic
|
|
1061
|
-
const baseName = trimmedName.split('--')[0].trim();
|
|
1062
|
-
if (CORE_ICONS[baseName]) {
|
|
1063
|
-
this.renderSvgToContainer(container, CORE_ICONS[baseName], color, size, baseName, disabled);
|
|
1064
|
-
return;
|
|
1065
|
-
}
|
|
1066
|
-
// No fallback to HTTP
|
|
1067
|
-
console.warn(`[fn-input] Icon "${name}" not found in core registry and no raw SVG provided.`);
|
|
1068
|
-
container.innerHTML = '';
|
|
1069
|
-
this.cdr.detectChanges();
|
|
1070
|
-
}
|
|
1071
|
-
renderSvgToContainer(container, raw, color, size, name, disabled) {
|
|
1072
|
-
try {
|
|
1073
|
-
const parser = new DOMParser();
|
|
1074
|
-
const doc = parser.parseFromString(raw, 'image/svg+xml');
|
|
1075
|
-
const svg = doc.querySelector('svg');
|
|
1076
|
-
if (!svg) {
|
|
1077
|
-
container.innerHTML = '';
|
|
1078
|
-
return;
|
|
1079
|
-
}
|
|
1080
|
-
// SVG Normalization logic
|
|
1081
|
-
for (const s of svg.querySelectorAll('style'))
|
|
1082
|
-
s.remove();
|
|
1083
|
-
if (color) {
|
|
1084
|
-
for (const el of svg.querySelectorAll('*')) {
|
|
1085
|
-
const style = el.getAttribute('style');
|
|
1086
|
-
if (style) {
|
|
1087
|
-
const cleaned = style
|
|
1088
|
-
.replaceAll(/fill\s*:\s*[^;]+;?/gi, '')
|
|
1089
|
-
.replaceAll(/stroke\s*:\s*[^;]+;?/gi, '');
|
|
1090
|
-
if (cleaned)
|
|
1091
|
-
el.setAttribute('style', cleaned);
|
|
1092
|
-
else
|
|
1093
|
-
el.removeAttribute('style');
|
|
1094
|
-
}
|
|
1095
|
-
const fill = el.getAttribute('fill');
|
|
1096
|
-
if (fill && fill !== 'none' && !fill.startsWith('url(')) {
|
|
1097
|
-
el.setAttribute('fill', 'currentColor');
|
|
1098
|
-
}
|
|
1099
|
-
const stroke = el.getAttribute('stroke');
|
|
1100
|
-
if (stroke && stroke !== 'none' && !stroke.startsWith('url(')) {
|
|
1101
|
-
el.setAttribute('stroke', 'currentColor');
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
svg.removeAttribute('width');
|
|
1106
|
-
svg.removeAttribute('height');
|
|
1107
|
-
if (!svg.getAttribute('viewBox')) {
|
|
1108
|
-
svg.setAttribute('viewBox', `0 0 ${size} ${size}`);
|
|
1109
|
-
}
|
|
1110
|
-
svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
|
1111
|
-
svg.setAttribute('focusable', 'false');
|
|
1112
|
-
svg.setAttribute('aria-hidden', 'true');
|
|
1113
|
-
svg.setAttribute('width', '100%');
|
|
1114
|
-
svg.setAttribute('height', '100%');
|
|
1115
|
-
const style = `;display:block;max-width:100%;max-height:100%;`;
|
|
1116
|
-
svg.setAttribute('style', (svg.getAttribute('style') || '') + style);
|
|
1117
|
-
container.innerHTML = '';
|
|
1118
|
-
if (color) {
|
|
1119
|
-
container.style.color = color;
|
|
1120
|
-
}
|
|
1121
|
-
if (disabled) {
|
|
1122
|
-
container.style.opacity = '0.5';
|
|
1123
|
-
container.style.cursor = 'not-allowed';
|
|
1124
|
-
}
|
|
1125
|
-
else {
|
|
1126
|
-
container.style.opacity = '1';
|
|
1127
|
-
container.style.cursor = '';
|
|
1128
|
-
}
|
|
1129
|
-
container.appendChild(svg);
|
|
1130
|
-
this.cdr.detectChanges();
|
|
1131
|
-
}
|
|
1132
|
-
catch (error) {
|
|
1133
|
-
console.error(`[fn-input] Error parsing SVG for icon "${name}":`, error);
|
|
1134
|
-
container.innerHTML = '';
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
// Removed getIconPath as HTTP loading is disabled
|
|
1138
|
-
// --- MESSAGE LOGIC ---
|
|
1139
|
-
getFieldMessage() {
|
|
1140
|
-
if (!this.control)
|
|
1141
|
-
return this.field?.helperText || '';
|
|
1142
|
-
if (this.control.touched && this.control.errors) {
|
|
1143
|
-
for (const key of Object.keys(this.control.errors)) {
|
|
1144
|
-
const errorValue = this.control.errors[key];
|
|
1145
|
-
if (errorValue && typeof errorValue === 'object' && errorValue.message) {
|
|
1146
|
-
return errorValue.message;
|
|
1147
|
-
}
|
|
1148
|
-
if (this.field?.errors?.[key]) {
|
|
1149
|
-
return this.field.errors[key];
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
return (this.field?.errors?.['default'] ||
|
|
1153
|
-
'Please enter ' + this.translateService.instant(this.field?.label));
|
|
1154
|
-
}
|
|
1155
|
-
return this.field?.helperText || '';
|
|
1156
|
-
}
|
|
1157
|
-
get isError() {
|
|
1158
|
-
return !!(this.control?.touched && this.control?.errors);
|
|
1159
|
-
}
|
|
1160
|
-
get isSuccess() {
|
|
1161
|
-
return !!(this.control?.valid && this.control?.touched);
|
|
1162
|
-
}
|
|
1163
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FNInput, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1164
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FNInput, isStandalone: true, selector: "fn-input", inputs: { field: "field", helperHandle: "helperHandle", toastService: "toastService", currencyMeta: "currencyMeta", defaultLocale: "defaultLocale", form: "form" }, outputs: { valueChange: "valueChange", fieldBlur: "fieldBlur" }, viewQueries: [{ propertyName: "textareaElement", first: true, predicate: ["fnTextarea"], descendants: true }, { propertyName: "iconContainers", predicate: ["iconContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (field.name && isVisible() && !field.hidden) {\r\n <div class=\"fn-input-container\">\r\n @if (field.type! !== 'hidden') {\r\n <fn-label\r\n [for]=\"uniqueId\"\r\n [label]=\"field.label\"\r\n [required]=\"field.required || false\"\r\n [hideOptional]=\"field.hideOptional || false\"\r\n [color]=\"field.color || '#03182b'\"\r\n [variant]=\"field.labelVariant || 'p1'\"\r\n [statusLabel]=\"field.statusLabel\"\r\n ></fn-label>\r\n }\r\n\r\n <ng-container>\r\n @switch (field.type) {\r\n <!-- Textarea Field -->\r\n @case ('textarea') {\r\n <textarea\r\n #fnTextarea\r\n style=\"resize: none\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [rows]=\"field.rows || 1\"\r\n [readonly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"handleTextArea($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n ></textarea>\r\n }\r\n\r\n <!-- Password Field -->\r\n @case ('password') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"showPassword ? 'text' : 'password'\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [disabled]=\"field.disabled || false\"\r\n [formControl]=\"control\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [readonly]=\"field.readOnly || false\"\r\n (input)=\"isAlphanumeric ? handleAlphanumericInput($event) : handleInput($event)\"\r\n (focus)=\"onPasswordFocus()\"\r\n (blur)=\"handlePasswordBlur($event)\"\r\n class=\"fn-input-field overflow-hidden text-ellipsis\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-12':\r\n (field.toggleMask && !field.isCopyText) ||\r\n (!field.toggleMask && field.isCopyText),\r\n 'pr-24': field.toggleMask && field.isCopyText && !field.hasGenerateKey,\r\n 'pr-32': field.toggleMask && field.isCopyText && field.hasGenerateKey,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.toggleMask && !field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n } @else if (field.isCopyText && !field.toggleMask) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n } @else if (field.toggleMask && field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n [ngClass]=\"{ 'opacity-50 cursor-not-allowed': !control.value }\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (field.feedback && isPasswordFocused) {\r\n <div class=\"mt-2 space-y-1\">\r\n <div class=\"flex items-center justify-between text-xs\">\r\n <span class=\"font-medium\" [ngClass]=\"strengthClass\">\r\n {{ passwordStrengthLabel | translate }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"\r\n passwordStrengthPercent > 50 ? 'check-circle' : 'info-circle'\r\n \"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"extrasmall\"\r\n [attr.data-icon-color]=\"\r\n passwordStrengthPercent <= 25\r\n ? '#ef3e42'\r\n : passwordStrengthPercent <= 75\r\n ? '#ff9f00'\r\n : '#6cc24a'\r\n \"\r\n ></div>\r\n </div>\r\n </div>\r\n <div class=\"h-1.5 w-full bg-[#eef0f2] rounded-full overflow-hidden\">\r\n <div\r\n class=\"h-full transition-all duration-300 rounded-full\"\r\n [ngClass]=\"{\r\n 'bg-[#ef3e42]': passwordStrengthPercent <= 25,\r\n 'bg-[#ff9f00]': passwordStrengthPercent > 25 && passwordStrengthPercent <= 75,\r\n 'bg-[#6cc24a]': passwordStrengthPercent > 75,\r\n }\"\r\n [style.width.%]=\"passwordStrengthPercent\"\r\n ></div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Number Field -->\r\n @case ('number') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type === 'number' && field.isCurrency ? 'text' : 'number'\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"isDisabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n [min]=\"field.type === 'number' && !field.isCurrency ? 0 : null\"\r\n [max]=\"field.type === 'number' && !field.isCurrency ? field.max : null\"\r\n [step]=\"field.type === 'number' && !field.isCurrency ? field.step || 1 : null\"\r\n (input)=\"handleNumberInput($event, field.minFractionDigits || 2)\"\r\n (paste)=\"handleNumberPaste($event, field.minFractionDigits || 2)\"\r\n (blur)=\"handleBlur($event, field.minFractionDigits || 2)\"\r\n (keydown)=\"handleNumberKeydown($event, field.isCurrency || false)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10': field.suffix?.icon && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'text-[24px] font-bold': field.isCurrency,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Default Input Field (text, email, etc.) -->\r\n @default {\r\n <div class=\"relative z-0\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"\r\n isEmailField\r\n ? handleEmailInput($event)\r\n : field.type === 'text' && isAlphanumeric\r\n ? handleAlphanumericInput($event)\r\n : handleInput($event)\r\n \"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10':\r\n (field.icon || field.suffix?.icon) && !field.isCopyText && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'pr-20':\r\n field.isCopyText && !field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-30':\r\n field.isCopyText && field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-32':\r\n field.isCopyText && field.hasGenerateKey && (field.icon || field.suffix?.icon),\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n\r\n @if (field.icon || field.suffix?.icon || field.suffix?.text) {\r\n @if (field.suffix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"suffixClick($event)\"\r\n (keydown.enter)=\"suffixClick($event)\"\r\n [attr.tabindex]=\"field.suffix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.suffix?.onClick\"\r\n >{{ field.suffix!.text }}</span\r\n >\r\n }\r\n @if (field.icon || field.suffix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.suffix?.icon || field.icon!.name\"\r\n [attr.data-icon-variant]=\"field.icon?.variant || 'Line'\"\r\n [attr.data-icon-size]=\"field.icon ? getIconSizeName(field.icon.size) : 'medium'\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-container>\r\n\r\n @if (showFormFieldMessage(control, helperText)) {\r\n <div class=\"fn-field-message-container\">\r\n <span\r\n class=\"fn-field-message-text\"\r\n [ngClass]=\"{\r\n error: isError,\r\n success: isSuccess,\r\n }\"\r\n >\r\n {{ getFieldMessage() | translate }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Integrated Toast Notifications -->\r\n <div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\" [class.toast-enter]=\"toast.isVisible\">\r\n <span class=\"toast-icon\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"getToastIconName(toast)\"\r\n data-icon-variant=\"Colour\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"\r\n toast.type === 'success'\r\n ? '#6cc24a'\r\n : toast.type === 'warn'\r\n ? '#ff9f00'\r\n : toast.type === 'error'\r\n ? '#ef3e42'\r\n : '#03182b'\r\n \"\r\n ></div>\r\n </span>\r\n <div class=\"toast-content\">\r\n <span class=\"toast-message\">\r\n {{ getTranslatedMessage(toast.message) | translate }}\r\n </span>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"removeToast(toast.id)\" aria-label=\"Close\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"cross\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n data-icon-color=\"#ffffff\"\r\n ></div>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".fn-input-container{display:flex;flex-direction:column;width:100%}.fn-label{font-family:Outfit,sans-serif;font-weight:500;margin-bottom:8px;display:flex;align-items:center}.fn-label span{color:#c4cdd2;font-size:14px;font-weight:400}.fn-input-field{width:100%;height:48px;padding:0 16px;background-color:#f7f8f9;border-bottom:1.5px solid #c4cdd2;font-family:Outfit,sans-serif;font-size:16px;color:#03182b;transition:all .2s ease;border-radius:4px 4px 0 0}.fn-input-field::placeholder{color:#c4cdd2}.fn-input-field:focus{outline:none;background-color:#fff;border-bottom-color:#03182b}.fn-input-field.error{border-bottom-color:#ef3e42}.fn-input-field.success{border-bottom-color:#6cc24a}.fn-input-field.disabled{background-color:#eef0f2;color:#c4cdd2;cursor:not-allowed}.fn-input-field.pl-10{padding-left:40px!important}.fn-input-field.has-prefix-text{padding-left:100px!important}.fn-input-field.pr-10{padding-right:40px!important}.fn-input-field.has-suffix-text{padding-right:120px!important}.fn-input-field.pr-12{padding-right:44px!important}.fn-input-field.pr-20{padding-right:72px!important}.fn-input-field.pr-24{padding-right:88px!important}.fn-input-field.pr-30{padding-right:104px!important}.fn-input-field.pr-32{padding-right:120px!important}.fn-field-message-container{margin-top:4px}.fn-field-message-text{font-family:Outfit,sans-serif;font-size:12px;color:#c4cdd2}.fn-field-message-text.error{color:#ef3e42}.fn-field-message-text.success{color:#6cc24a}.icon-container{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}.relative{position:relative}.absolute{position:absolute}.right-0{right:0}.left-0{left:0}.top-1\\/2{top:50%}.-translate-y-1\\/2{transform:translateY(-50%)}.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.mt-2{margin-top:.5rem}.space-y-1>:not([hidden])~:not([hidden]){margin-top:.25rem}.text-xs{font-size:.75rem}.font-medium{font-weight:500}.h-1\\.5{height:.375rem}.w-full{width:100%}.bg-\\[\\#eef0f2\\]{background-color:#eef0f2}.rounded-full{border-radius:9999px}.overflow-hidden{overflow:hidden}.transition-all{transition-property:all}.duration-300{transition-duration:.3s}.cursor-pointer{cursor:pointer}.opacity-50{opacity:.5}.cursor-not-allowed{cursor:not-allowed}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.toast-container{position:fixed;top:24px;left:50%;transform:translate(-50%);z-index:9999;width:100%;max-width:336px;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast{display:flex;align-items:center;background:#25333f;border-radius:8px;padding:12px;width:336px;max-width:100%;opacity:0;transform:translateY(-20px);transition:all .3s cubic-bezier(.4,0,.2,1);pointer-events:auto}.toast.toast-enter{opacity:1;transform:translateY(0)}.toast.toast-success{border-left:4px solid #6cc24a}.toast.toast-warn{border-left:4px solid #ff9f00}.toast.toast-error{border-left:4px solid #ef3e42}.toast.toast-info{border-left:4px solid #3b82f6}.toast .toast-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;margin-right:8px;flex-shrink:0}.toast .toast-content{flex:1;min-width:0}.toast .toast-message{font-size:14px;line-height:20px;color:#fff;display:block}.toast .toast-close{background:none;border:none;font-size:20px;color:#fff;opacity:.7;cursor:pointer;padding:0;margin-left:8px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:opacity .2s;pointer-events:auto}.toast .toast-close:hover{opacity:1}\n"], dependencies: [{ 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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3.TranslatePipe, name: "translate" }, { kind: "component", type: FNLabel, selector: "fn-label", inputs: ["field", "label", "required", "className", "class", "for", "color", "variant", "statusLabel", "ngClass", "hideOptional"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1165
|
-
}
|
|
1166
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FNInput, decorators: [{
|
|
1167
|
-
type: Component,
|
|
1168
|
-
args: [{ selector: 'fn-input', standalone: true, imports: [FormsModule, CommonModule, ReactiveFormsModule, TranslateModule, FNLabel], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (field.name && isVisible() && !field.hidden) {\r\n <div class=\"fn-input-container\">\r\n @if (field.type! !== 'hidden') {\r\n <fn-label\r\n [for]=\"uniqueId\"\r\n [label]=\"field.label\"\r\n [required]=\"field.required || false\"\r\n [hideOptional]=\"field.hideOptional || false\"\r\n [color]=\"field.color || '#03182b'\"\r\n [variant]=\"field.labelVariant || 'p1'\"\r\n [statusLabel]=\"field.statusLabel\"\r\n ></fn-label>\r\n }\r\n\r\n <ng-container>\r\n @switch (field.type) {\r\n <!-- Textarea Field -->\r\n @case ('textarea') {\r\n <textarea\r\n #fnTextarea\r\n style=\"resize: none\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [rows]=\"field.rows || 1\"\r\n [readonly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"handleTextArea($event)\"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n ></textarea>\r\n }\r\n\r\n <!-- Password Field -->\r\n @case ('password') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"showPassword ? 'text' : 'password'\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [disabled]=\"field.disabled || false\"\r\n [formControl]=\"control\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [readonly]=\"field.readOnly || false\"\r\n (input)=\"isAlphanumeric ? handleAlphanumericInput($event) : handleInput($event)\"\r\n (focus)=\"onPasswordFocus()\"\r\n (blur)=\"handlePasswordBlur($event)\"\r\n class=\"fn-input-field overflow-hidden text-ellipsis\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-12':\r\n (field.toggleMask && !field.isCopyText) ||\r\n (!field.toggleMask && field.isCopyText),\r\n 'pr-24': field.toggleMask && field.isCopyText && !field.hasGenerateKey,\r\n 'pr-32': field.toggleMask && field.isCopyText && field.hasGenerateKey,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.toggleMask && !field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n } @else if (field.isCopyText && !field.toggleMask) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n } @else if (field.toggleMask && field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"togglePasswordVisibility()\"\r\n (keydown)=\"togglePasswordVisibility()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"showPassword ? 'eye-open' : 'eye-close'\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"large\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n [ngClass]=\"{ 'opacity-50 cursor-not-allowed': !control.value }\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (field.feedback && isPasswordFocused) {\r\n <div class=\"mt-2 space-y-1\">\r\n <div class=\"flex items-center justify-between text-xs\">\r\n <span class=\"font-medium\" [ngClass]=\"strengthClass\">\r\n {{ passwordStrengthLabel | translate }}\r\n </span>\r\n <div class=\"flex items-center gap-1\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"\r\n passwordStrengthPercent > 50 ? 'check-circle' : 'info-circle'\r\n \"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"extrasmall\"\r\n [attr.data-icon-color]=\"\r\n passwordStrengthPercent <= 25\r\n ? '#ef3e42'\r\n : passwordStrengthPercent <= 75\r\n ? '#ff9f00'\r\n : '#6cc24a'\r\n \"\r\n ></div>\r\n </div>\r\n </div>\r\n <div class=\"h-1.5 w-full bg-[#eef0f2] rounded-full overflow-hidden\">\r\n <div\r\n class=\"h-full transition-all duration-300 rounded-full\"\r\n [ngClass]=\"{\r\n 'bg-[#ef3e42]': passwordStrengthPercent <= 25,\r\n 'bg-[#ff9f00]': passwordStrengthPercent > 25 && passwordStrengthPercent <= 75,\r\n 'bg-[#6cc24a]': passwordStrengthPercent > 75,\r\n }\"\r\n [style.width.%]=\"passwordStrengthPercent\"\r\n ></div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Number Field -->\r\n @case ('number') {\r\n <div class=\"relative w-full\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type === 'number' && field.isCurrency ? 'text' : 'number'\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"isDisabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n [min]=\"field.type === 'number' && !field.isCurrency ? 0 : null\"\r\n [max]=\"field.type === 'number' && !field.isCurrency ? field.max : null\"\r\n [step]=\"field.type === 'number' && !field.isCurrency ? field.step || 1 : null\"\r\n (input)=\"handleNumberInput($event, field.minFractionDigits || 2)\"\r\n (paste)=\"handleNumberPaste($event, field.minFractionDigits || 2)\"\r\n (blur)=\"handleBlur($event, field.minFractionDigits || 2)\"\r\n (keydown)=\"handleNumberKeydown($event, field.isCurrency || false)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10': field.suffix?.icon && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'text-[24px] font-bold': field.isCurrency,\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n </div>\r\n }\r\n\r\n <!-- Default Input Field (text, email, etc.) -->\r\n @default {\r\n <div class=\"relative z-0\">\r\n @if (field.prefix?.icon || field.prefix?.text) {\r\n <div\r\n class=\"absolute left-0 top-1/2 -translate-y-1/2 pl-3 flex items-center gap-2\"\r\n style=\"z-index: 1\"\r\n >\r\n @if (field.prefix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.prefix!.icon\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n @if (field.prefix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"prefixClick($event)\"\r\n (keydown.enter)=\"prefixClick($event)\"\r\n [attr.tabindex]=\"field.prefix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.prefix?.onClick\"\r\n >{{ field.prefix!.text }}</span\r\n >\r\n }\r\n </div>\r\n }\r\n <input\r\n [type]=\"field.type\"\r\n [name]=\"field.name\"\r\n [id]=\"uniqueId\"\r\n [required]=\"field.required || false\"\r\n [placeholder]=\"field.placeholder || '' | translate\"\r\n [disabled]=\"field.disabled || false\"\r\n [readOnly]=\"field.readOnly || false\"\r\n [formControl]=\"control\"\r\n (input)=\"\r\n isEmailField\r\n ? handleEmailInput($event)\r\n : field.type === 'text' && isAlphanumeric\r\n ? handleAlphanumericInput($event)\r\n : handleInput($event)\r\n \"\r\n (blur)=\"handleBlur($event)\"\r\n class=\"fn-input-field\"\r\n [ngClass]=\"{\r\n disabled: control.disabled || field.readOnly,\r\n error: control.touched && control.errors,\r\n success: field['hasSuccessBorder'] && control.valid && !control.errors,\r\n 'pl-10': field.prefix?.icon && !field.prefix?.text,\r\n 'has-prefix-text': !!field.prefix?.text,\r\n 'pr-10':\r\n (field.icon || field.suffix?.icon) && !field.isCopyText && !field.suffix?.text,\r\n 'has-suffix-text': !!field.suffix?.text,\r\n 'pr-20':\r\n field.isCopyText && !field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-30':\r\n field.isCopyText && field.hasGenerateKey && !(field.icon || field.suffix?.icon),\r\n 'pr-32':\r\n field.isCopyText && field.hasGenerateKey && (field.icon || field.suffix?.icon),\r\n }\"\r\n [ngStyle]=\"{\r\n color: field.valueColor || 'inherit',\r\n 'font-size': field.valueSize || '',\r\n }\"\r\n (focus)=\"onFocus()\"\r\n />\r\n\r\n <div class=\"absolute right-0 top-1/2 -translate-y-1/2 flex items-center pr-3 gap-2\">\r\n @if (field.isCopyText) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"copyText($event)\"\r\n (keydown)=\"copyText($event)\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"two-square\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n @if (field.hasGenerateKey) {\r\n <span\r\n class=\"cursor-pointer\"\r\n (click)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n (keydown)=\"field.onGenerateKey && field.onGenerateKey()\"\r\n >\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"round-arrow-top-left\"\r\n data-icon-color=\"#03182b\"\r\n ></div>\r\n </span>\r\n }\r\n }\r\n\r\n @if (field.icon || field.suffix?.icon || field.suffix?.text) {\r\n @if (field.suffix?.text) {\r\n <span\r\n class=\"text-sm font-medium whitespace-nowrap\"\r\n [ngStyle]=\"{ color: control.disabled ? '#c4cdd2' : '#03182b' }\"\r\n (click)=\"suffixClick($event)\"\r\n (keydown.enter)=\"suffixClick($event)\"\r\n [attr.tabindex]=\"field.suffix?.onClick ? 0 : null\"\r\n [class.cursor-pointer]=\"!!field.suffix?.onClick\"\r\n >{{ field.suffix!.text }}</span\r\n >\r\n }\r\n @if (field.icon || field.suffix?.icon) {\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"field.suffix?.icon || field.icon!.name\"\r\n [attr.data-icon-variant]=\"field.icon?.variant || 'Line'\"\r\n [attr.data-icon-size]=\"field.icon ? getIconSizeName(field.icon.size) : 'medium'\"\r\n [attr.data-icon-color]=\"control.disabled ? '#c4cdd2' : '#03182b'\"\r\n ></div>\r\n }\r\n }\r\n </div>\r\n </div>\r\n }\r\n }\r\n </ng-container>\r\n\r\n @if (showFormFieldMessage(control, helperText)) {\r\n <div class=\"fn-field-message-container\">\r\n <span\r\n class=\"fn-field-message-text\"\r\n [ngClass]=\"{\r\n error: isError,\r\n success: isSuccess,\r\n }\"\r\n >\r\n {{ getFieldMessage() | translate }}\r\n </span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Integrated Toast Notifications -->\r\n <div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\" [class.toast-enter]=\"toast.isVisible\">\r\n <span class=\"toast-icon\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n [attr.data-icon-name]=\"getToastIconName(toast)\"\r\n data-icon-variant=\"Colour\"\r\n data-icon-size=\"medium\"\r\n [attr.data-icon-color]=\"\r\n toast.type === 'success'\r\n ? '#6cc24a'\r\n : toast.type === 'warn'\r\n ? '#ff9f00'\r\n : toast.type === 'error'\r\n ? '#ef3e42'\r\n : '#03182b'\r\n \"\r\n ></div>\r\n </span>\r\n <div class=\"toast-content\">\r\n <span class=\"toast-message\">\r\n {{ getTranslatedMessage(toast.message) | translate }}\r\n </span>\r\n </div>\r\n <button class=\"toast-close\" (click)=\"removeToast(toast.id)\" aria-label=\"Close\">\r\n <div\r\n #iconContainer\r\n class=\"icon-container\"\r\n data-icon-name=\"cross\"\r\n data-icon-variant=\"Line\"\r\n data-icon-size=\"medium\"\r\n data-icon-color=\"#ffffff\"\r\n ></div>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".fn-input-container{display:flex;flex-direction:column;width:100%}.fn-label{font-family:Outfit,sans-serif;font-weight:500;margin-bottom:8px;display:flex;align-items:center}.fn-label span{color:#c4cdd2;font-size:14px;font-weight:400}.fn-input-field{width:100%;height:48px;padding:0 16px;background-color:#f7f8f9;border-bottom:1.5px solid #c4cdd2;font-family:Outfit,sans-serif;font-size:16px;color:#03182b;transition:all .2s ease;border-radius:4px 4px 0 0}.fn-input-field::placeholder{color:#c4cdd2}.fn-input-field:focus{outline:none;background-color:#fff;border-bottom-color:#03182b}.fn-input-field.error{border-bottom-color:#ef3e42}.fn-input-field.success{border-bottom-color:#6cc24a}.fn-input-field.disabled{background-color:#eef0f2;color:#c4cdd2;cursor:not-allowed}.fn-input-field.pl-10{padding-left:40px!important}.fn-input-field.has-prefix-text{padding-left:100px!important}.fn-input-field.pr-10{padding-right:40px!important}.fn-input-field.has-suffix-text{padding-right:120px!important}.fn-input-field.pr-12{padding-right:44px!important}.fn-input-field.pr-20{padding-right:72px!important}.fn-input-field.pr-24{padding-right:88px!important}.fn-input-field.pr-30{padding-right:104px!important}.fn-input-field.pr-32{padding-right:120px!important}.fn-field-message-container{margin-top:4px}.fn-field-message-text{font-family:Outfit,sans-serif;font-size:12px;color:#c4cdd2}.fn-field-message-text.error{color:#ef3e42}.fn-field-message-text.success{color:#6cc24a}.icon-container{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}.relative{position:relative}.absolute{position:absolute}.right-0{right:0}.left-0{left:0}.top-1\\/2{top:50%}.-translate-y-1\\/2{transform:translateY(-50%)}.flex{display:flex}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.mt-2{margin-top:.5rem}.space-y-1>:not([hidden])~:not([hidden]){margin-top:.25rem}.text-xs{font-size:.75rem}.font-medium{font-weight:500}.h-1\\.5{height:.375rem}.w-full{width:100%}.bg-\\[\\#eef0f2\\]{background-color:#eef0f2}.rounded-full{border-radius:9999px}.overflow-hidden{overflow:hidden}.transition-all{transition-property:all}.duration-300{transition-duration:.3s}.cursor-pointer{cursor:pointer}.opacity-50{opacity:.5}.cursor-not-allowed{cursor:not-allowed}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.toast-container{position:fixed;top:24px;left:50%;transform:translate(-50%);z-index:9999;width:100%;max-width:336px;display:flex;flex-direction:column;gap:8px;pointer-events:none}.toast{display:flex;align-items:center;background:#25333f;border-radius:8px;padding:12px;width:336px;max-width:100%;opacity:0;transform:translateY(-20px);transition:all .3s cubic-bezier(.4,0,.2,1);pointer-events:auto}.toast.toast-enter{opacity:1;transform:translateY(0)}.toast.toast-success{border-left:4px solid #6cc24a}.toast.toast-warn{border-left:4px solid #ff9f00}.toast.toast-error{border-left:4px solid #ef3e42}.toast.toast-info{border-left:4px solid #3b82f6}.toast .toast-icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;margin-right:8px;flex-shrink:0}.toast .toast-content{flex:1;min-width:0}.toast .toast-message{font-size:14px;line-height:20px;color:#fff;display:block}.toast .toast-close{background:none;border:none;font-size:20px;color:#fff;opacity:.7;cursor:pointer;padding:0;margin-left:8px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:opacity .2s;pointer-events:auto}.toast .toast-close:hover{opacity:1}\n"] }]
|
|
1169
|
-
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { field: [{
|
|
1170
|
-
type: Input
|
|
1171
|
-
}], helperHandle: [{
|
|
1172
|
-
type: Input
|
|
1173
|
-
}], toastService: [{
|
|
1174
|
-
type: Input
|
|
1175
|
-
}], currencyMeta: [{
|
|
1176
|
-
type: Input
|
|
1177
|
-
}], defaultLocale: [{
|
|
1178
|
-
type: Input
|
|
1179
|
-
}], form: [{
|
|
1180
|
-
type: Input
|
|
1181
|
-
}], valueChange: [{
|
|
1182
|
-
type: Output
|
|
1183
|
-
}], fieldBlur: [{
|
|
1184
|
-
type: Output
|
|
1185
|
-
}], textareaElement: [{
|
|
1186
|
-
type: ViewChild,
|
|
1187
|
-
args: ['fnTextarea']
|
|
1188
|
-
}], iconContainers: [{
|
|
1189
|
-
type: ViewChildren,
|
|
1190
|
-
args: ['iconContainer']
|
|
1191
|
-
}] } });
|
|
1192
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm4taW5wdXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvZm4taW5wdXQvc3JjL2xpYi9mbi1pbnB1dC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9mbi1pbnB1dC9zcmMvbGliL2ZuLWlucHV0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFFTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUVULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUVMLE1BQU0sRUFDTixNQUFNLEVBQ04sU0FBUyxFQUlULFlBQVksR0FFYixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsNEJBQTRCO0FBQzVCLE9BQU8sRUFBMEIsV0FBVyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUYsT0FBTyxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ25DLE9BQU8sRUFJTCxxQkFBcUIsRUFHckIsZ0JBQWdCLEdBQ2pCLE1BQU0sa0JBQWtCLENBQUM7Ozs7O0FBSTFCLE1BQU0sVUFBVSxHQUEyQjtJQUN6QyxVQUFVLEVBQUUsbVZBQW1WO0lBQy9WLFdBQVcsRUFBRSxzVUFBc1U7SUFDblYsWUFBWSxFQUFFLGlWQUFpVjtJQUMvVixzQkFBc0IsRUFBRSwwUUFBMFE7SUFDbFMsY0FBYyxFQUFFLHNRQUFzUTtJQUN0UixhQUFhLEVBQUUsaWNBQWljO0lBQ2hkLGNBQWMsRUFBRSxrY0FBa2M7SUFDbGQsb0JBQW9CLEVBQUUsa2NBQWtjO0lBQ3hkLEtBQUssRUFBRSxzTUFBc007Q0FDOU0sQ0FBQztBQVVGLE1BQU0sT0FBTyxPQUFPO0lBMkVXO0lBMUVwQixLQUFLLEdBQUcsRUFBaUIsQ0FBQztJQUMxQixZQUFZLENBQWlCO0lBQzdCLFlBQVksQ0FBZ0I7SUFDcEIsb0JBQW9CLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFFckYsSUFBSSxxQkFBcUI7UUFDdkIsT0FBTyxJQUFJLENBQUMsWUFBWSxJQUFJLElBQUksQ0FBQyxvQkFBb0IsSUFBSSxTQUFTLENBQUM7SUFDckUsQ0FBQztJQUNRLFlBQVksR0FBRyxxQkFBcUIsQ0FBQztJQUNyQyxhQUFhLEdBQUcsT0FBTyxDQUFDO0lBQ3hCLElBQUksQ0FBYTtJQUNoQixXQUFXLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztJQUNqQyxTQUFTLEdBQUcsSUFBSSxZQUFZLEVBQUUsQ0FBQztJQUV6QyxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUM1QyxRQUFRLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ0EsZUFBZSxDQUFtQztJQUM1QyxjQUFjLENBQXNDO0lBRW5GLHVCQUF1QjtJQUN2QixNQUFNLEdBQUcsTUFBTSxDQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRTNCLCtCQUErQjtJQUNkLElBQUksR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0lBRTFCLE9BQU8sR0FBMkM7UUFDakUsVUFBVSxFQUFFLEVBQUU7UUFDZCxLQUFLLEVBQUUsRUFBRTtRQUNULE1BQU0sRUFBRSxFQUFFO1FBQ1YsS0FBSyxFQUFFLEVBQUU7UUFDVCxTQUFTLEVBQUUsRUFBRTtRQUNiLE9BQU8sRUFBRSxFQUFFO0tBQ1osQ0FBQztJQUVGLGVBQWUsQ0FBQyxJQUFZO1FBQzFCLFFBQVEsSUFBSSxFQUFFLENBQUM7WUFDYixLQUFLLEVBQUU7Z0JBQ0wsT0FBTyxPQUFPLENBQUM7WUFDakIsS0FBSyxFQUFFO2dCQUNMLE9BQU8sUUFBUSxDQUFDO1lBQ2xCLEtBQUssRUFBRTtnQkFDTCxPQUFPLE9BQU8sQ0FBQztZQUNqQixLQUFLLEVBQUU7Z0JBQ0wsT0FBTyxTQUFTLENBQUM7WUFDbkI7Z0JBQ0UsT0FBTyxRQUFRLENBQUM7UUFDcEIsQ0FBQztJQUNILENBQUM7SUFFRCxJQUFJLGNBQWM7UUFDaEIsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLGNBQWMsS0FBSyxLQUFLLENBQUM7SUFDN0MsQ0FBQztJQUVELElBQUksWUFBWTtRQUNkLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssT0FBTyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN6RixDQUFDO0lBRUQsSUFBWSxtQkFBbUI7UUFDN0IsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQzdCLE9BQU8sd0JBQXdCLENBQUM7UUFDbEMsQ0FBQztRQUVELE9BQU8sc0JBQXNCLENBQUM7SUFDaEMsQ0FBQztJQUVELFVBQVUsR0FBRyxLQUFLLENBQUM7SUFDbkIsT0FBTyxDQUFlO0lBQ3RCLFNBQVMsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyx5QkFBeUI7SUFDbkQsVUFBVSxHQUFHLEVBQUUsQ0FBQztJQUVoQix5RUFBeUU7SUFDakUsTUFBTSxDQUFDLFNBQVMsR0FBRyxDQUFDLENBQUM7SUFDN0IsUUFBUSxHQUFHLFlBQVksRUFBRSxPQUFPLENBQUMsU0FBUyxFQUFFLENBQUM7SUFFN0MsWUFBNkIsR0FBc0I7UUFBdEIsUUFBRyxHQUFILEdBQUcsQ0FBbUI7SUFBRyxDQUFDO0lBRXZELFFBQVE7UUFDTixJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTTtZQUFFLE9BQU87UUFDOUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUM7UUFDOUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBRXZCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLO1lBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5RCxJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUNqQyxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztJQUNoQyxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUN4QyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDeEIsQ0FBQztJQUNILENBQUM7SUFFTyx5QkFBeUI7UUFDL0IsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTztRQUUxQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUMzRSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUVoRixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FDWCxLQUFLLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDbEMsSUFBSSxDQUFDO2dCQUNILElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDM0IsQ0FBQztZQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ1gsT0FBTyxDQUFDLElBQUksQ0FBQyx1REFBdUQsRUFBRSxDQUFDLENBQUMsQ0FBQztnQkFDekUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUMxQixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRCxlQUFlO1FBQ2IsdUVBQXVFO1FBQ3ZFLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3pCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssVUFBVSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7WUFDMUQsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2pELENBQUM7UUFDRCxxREFBcUQ7UUFDckQsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsQ0FBQztZQUNqRixJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztRQUNwQyxDQUFDO1FBQ0QsSUFBSSxDQUFDLDJCQUEyQixFQUFFLENBQUM7SUFDckMsQ0FBQztJQUVPLDJCQUEyQjtRQUNqQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FDWCxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQ3pDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN4QixDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQztJQUVELGdCQUFnQixDQUFDLEtBQVk7UUFDM0IsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQTBCLENBQUM7UUFDL0MsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQztRQUNuQyxNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsWUFBWSxDQUFDO1FBRS9CLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN4QyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDM0QsQ0FBQztRQUNELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVyRSw4Q0FBOEM7UUFDOUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILGdCQUFnQixDQUFDLEtBQVk7UUFDM0IsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQTBCLENBQUM7UUFDL0MsTUFBTSxjQUFjLEdBQUcsS0FBSyxDQUFDLGNBQWMsSUFBSSxDQUFDLENBQUM7UUFDakQsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQztRQUVsQywwQkFBMEI7UUFDMUIsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRS9DLHNFQUFzRTtRQUN0RSxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BDLElBQUksU0FBUyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6QixJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUVuRSw2Q0FBNkM7UUFDN0Msb0NBQW9DO1FBQ3BDLFNBQVMsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZELE9BQU8sU0FBUyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2pDLFNBQVMsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JDLENBQUM7UUFDRCxPQUFPLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNoQyxTQUFTLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDOUMsQ0FBQztRQUVELHdDQUF3QztRQUN4Qyw4RUFBOEU7UUFDOUUsSUFBSSxhQUFhLEdBQUcsU0FBUyxDQUFDO1FBQzlCLElBQUksVUFBVSxLQUFLLElBQUksRUFBRSxDQUFDO1lBQ3hCLFVBQVUsR0FBRyxVQUFVLENBQUMsVUFBVSxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN2RCxPQUFPLFVBQVUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDbEMsVUFBVSxHQUFHLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdkMsQ0FBQztZQUNELE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNqQyxVQUFVLEdBQUcsVUFBVSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDaEQsQ0FBQztZQUNELGFBQWEsSUFBSSxHQUFHLEdBQUcsVUFBVSxDQUFDO1FBQ3BDLENBQUM7UUFFRCxJQUFJLGFBQWEsS0FBSyxhQUFhLEVBQUUsQ0FBQztZQUNwQyxNQUFNLHdCQUF3QixHQUFHLElBQUksQ0FBQyw2QkFBNkIsQ0FDakUsYUFBYSxDQUFDLFdBQVcsRUFBRSxFQUMzQixhQUFhLEVBQ2IsY0FBYyxDQUNmLENBQUM7WUFDRixLQUFLLENBQUMsS0FBSyxHQUFHLGFBQWEsQ0FBQztZQUM1QixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxhQUFhLEVBQUUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUMzRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxjQUFjLEdBQUcsd0JBQXdCLENBQUMsQ0FBQztZQUM1RSxLQUFLLENBQUMsaUJBQWlCLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQ3RELENBQUM7YUFBTSxJQUFJLGFBQWEsS0FBSyxVQUFVLEVBQUUsQ0FBQztZQUN4QywrQ0FBK0M7WUFDL0MsS0FBSyxDQUFDLEtBQUssR0FBRyxhQUFhLENBQUM7WUFDNUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYSxFQUFFLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDM0QsS0FBSyxDQUFDLGlCQUFpQixDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUMxRCxDQUFDO1FBRUQsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxVQUFVLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMxRCxJQUFJLENBQUMscUJBQXFCLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDNUMsQ0FBQztRQUVELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZFLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVELE9BQU87UUFDTCxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBRU8sMEJBQTBCO1FBQ2hDLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDaEMsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDZCxNQUFNLFlBQVksR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQXFCLENBQUM7Z0JBQ2hGLElBQUksWUFBWSxFQUFFLENBQUM7b0JBQ2pCLFlBQVksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUNuRSxDQUFDO1lBQ0gsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ1QsQ0FBQztJQUNILENBQUM7SUFFRCxlQUFlO1FBQ2IsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3pELElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBeUIsQ0FBQztRQUN6QyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSztZQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFOUQsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDakIsd0JBQXdCO1lBQ3hCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLElBQUksS0FBSyxFQUFFLENBQUM7Z0JBQ2pDLElBQUksQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFDMUIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUM7WUFDekIsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQsaUJBQWlCO1FBQ2YsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGVBQWUsRUFBRSxhQUFhLENBQUM7UUFDckQsSUFBSSxRQUFRLEVBQUUsQ0FBQztZQUNiLHlEQUF5RDtZQUN6RCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUM7WUFFbEMsNkNBQTZDO1lBQzdDLE1BQU0sYUFBYSxHQUFHLFVBQVUsQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM1RCxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyw2QkFBNkI7WUFFbkcseUNBQXlDO1lBQ3pDLE1BQU0sU0FBUyxHQUFHLElBQUksR0FBRyxVQUFVLENBQUM7WUFFcEMsb0RBQW9EO1lBQ3BELFFBQVEsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztZQUUvQiw4Q0FBOEM7WUFDOUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQzdELFFBQVEsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLFNBQVMsR0FBRyxJQUFJLENBQUM7WUFDekMsUUFBUSxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3JDLENBQUM7SUFDSCxDQUFDO0lBRUQsY0FBYyxDQUFDLEtBQVk7UUFDekIsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE1BQTZCLENBQUM7UUFDcEQsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLGNBQWMsQ0FBQztRQUM5QyxNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO1FBRXBDLDBDQUEwQztRQUMxQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLFVBQVUsSUFBSSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDMUQsc0RBQXNEO1lBQ3RELE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDO1lBQ3JELElBQUksYUFBYSxHQUFHLGFBQWEsQ0FBQyxVQUFVLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFFdEUseUJBQXlCO1lBQ3pCLElBQUksYUFBYSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNsQyxhQUFhLEdBQUcsYUFBYSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQzVDLENBQUM7WUFFRCx3REFBd0Q7WUFDeEQsYUFBYSxHQUFHLGFBQWEsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBRXpELElBQUksYUFBYSxLQUFLLGFBQWEsRUFBRSxDQUFDO2dCQUNwQyx3RUFBd0U7Z0JBQ3hFLE1BQU0sd0JBQXdCLEdBQUcsYUFBYSxDQUFDLE1BQU0sR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDO2dCQUM3RSxPQUFPLENBQUMsS0FBSyxHQUFHLGFBQWEsQ0FBQztnQkFDOUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYSxFQUFFLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7Z0JBQzNELDJEQUEyRDtnQkFDM0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxjQUFjLElBQUksQ0FBQyxDQUFDLEdBQUcsd0JBQXdCLENBQUMsQ0FBQztnQkFDbkYsT0FBTyxDQUFDLGlCQUFpQixDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQztZQUN4RCxDQUFDO1lBRUQsa0JBQWtCO1lBQ2xCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxhQUFhLEdBQUcsYUFBYSxDQUFDO1lBRWxDLHNDQUFzQztZQUN0QyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN6QixPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztnQkFFbkQsTUFBTSxjQUFjLEdBQUcsOENBQThDLENBQUM7Z0JBQ3RFLGFBQWEsR0FBRyxhQUFhLENBQUMsVUFBVSxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUMvRCxDQUFDO1lBRUQseUJBQXlCO1lBQ3pCLElBQUksYUFBYSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNsQyxhQUFhLEdBQUcsYUFBYSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQzVDLENBQUM7WUFFRCx3REFBd0Q7WUFDeEQsYUFBYSxHQUFHLGFBQWEsQ0FBQyxVQUFVLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBRXpELElBQUksYUFBYSxLQUFLLGFBQWEsRUFBRSxDQUFDO2dCQUNwQyx3RUFBd0U7Z0JBQ3hFLE1BQU0sd0JBQXdCLEdBQUcsYUFBYSxDQUFDLE1BQU0sR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDO2dCQUM3RSxPQUFPLENBQUMsS0FBSyxHQUFHLGFBQWEsQ0FBQztnQkFDOUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYSxFQUFFLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7Z0JBQzNELDJEQUEyRDtnQkFDM0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxjQUFjLElBQUksQ0FBQyxDQUFDLEdBQUcsd0JBQXdCLENBQUMsQ0FBQztnQkFDbkYsT0FBTyxDQUFDLGlCQUFpQixDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQztZQUN4RCxDQUFDO1lBRUQsa0JBQWtCO1lBQ2xCLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRCx3QkFBd0I7UUFDdEIsSUFBSSxDQUFDLFlBQVksR0FBRyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUM7UUFDdkMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ3hCLENBQUM7SUFFRCxXQUFXLENBQUMsS0FBWTtRQUN0QixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBMEIsQ0FBQztRQUNoRCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDO1FBQzdDLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUM7UUFFbkMsSUFBSSxhQUFhLEdBQUcsYUFBYSxDQUFDO1FBRWxDLG9EQUFvRDtRQUNwRCxnR0FBZ0c7UUFDaEcsNEVBQTRFO1FBQzVFLG9FQUFvRTtRQUNwRSxnR0FBZ0c7UUFDaEcsK0NBQStDO1FBQy9DLDhGQUE4RjtRQUM5RixxSEFBcUg7UUFDckgsNEJBQTRCO1FBQzVCLHFEQUFxRDtRQUVyRCxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3pCLDRGQUE0RjtZQUM1RiwyRUFBMkU7WUFDM0UsdUZBQXVGO1lBQ3ZGLHNDQUFzQztZQUN0QyxpQkFBaUI7WUFDakIsMERBQTBEO1lBRTFELCtCQUErQjtZQUMvQixZQUFZO1lBQ1osWUFBWTtZQUNaLHlDQUF5QztZQUN6QyxrR0FBa0c7WUFDbEcsd0RBQXdEO1lBQ3hELHVFQUF1RTtZQUN2RSw2REFBNkQ7WUFDN0QseURBQXlEO1lBQ3pELDhGQUE4RjtZQUU5Riw0Q0FBNEM7WUFDNUMsd0dBQXdHO1lBQ3hHLGtHQUFrRztZQUNsRyw0QkFBNEI7WUFDNUIsY0FBYztZQUNkLFFBQVE7WUFDUixzREFBc0Q7WUFFdEQsTUFBTSxjQUFjLEdBQUcsOENBQThDLENBQUM7WUFDdEUsYUFBYSxHQUFHLGFBQWEsQ0FBQyxVQUFVLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFFRCx5QkFBeUI7UUFDekIsSUFBSSxhQUFhLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDbEMsYUFBYSxHQUFHLGFBQWEsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUM1QyxDQUFDO1FBRUQsMkRBQTJEO1FBQzNELGFBQWEsR0FBRyxhQUFhLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUV6RCxJQUFJLGFBQWEsS0FBSyxhQUFhLEVBQUUsQ0FBQztZQUNwQyx3RUFBd0U7WUFDeEUsTUFBTSx3QkFBd0IsR0FBRyxhQUFhLENBQUMsTUFBTSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUM7WUFDN0UsTUFBTSxDQUFDLEtBQUssR0FBRyxhQUFhLENBQUM7WUFDN0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsYUFBYSxFQUFFLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDM0QsMkRBQTJEO1lBQzNELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsY0FBYyxJQUFJLENBQUMsQ0FBQyxHQUFHLHdCQUF3QixDQUFDLENBQUM7WUFDbkYsTUFBTSxDQUFDLGlCQUFpQixDQUFDLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQztRQUN2RCxDQUFDO1FBRUQsNERBQTREO1FBQzVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssVUFBVSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDMUQsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFFRCxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUN2RSxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsdUJBQXVCLENBQUMsS0FBWTtRQUNsQyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBMEIsQ0FBQztRQUNoRCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDO1FBQzdDLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUM7UUFFbkMsc0RBQXNEO1FBQ3RELE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDO1FBQ3JELElBQUksYUFBYSxHQUFHLGFBQWEsQ0FBQyxVQUFVLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFdEUseUJBQXlCO1FBQ3pCLElBQUksYUFBYSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2xDLGFBQWEsR0FBRyxhQUFhLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDNUMsQ0FBQztRQUVELHdEQUF3RDtRQUN4RCxhQUFhLEdBQUcsYUFBYSxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFFekQsSUFBSSxhQUFhLEtBQUssYUFBYSxFQUFFLENBQUM7WUFDcEMsd0VBQXdFO1lBQ3hFLE1BQU0sd0JBQXdCLEdBQUcsYUFBYSxDQUFDLE1BQU0sR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDO1lBQzdFLE1BQU0sQ0FBQyxLQUFLLEdBQUcsYUFBYSxDQUFDO1lBQzdCLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLGFBQWEsRUFBRSxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQzNELDJEQUEyRDtZQUMzRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLGNBQWMsSUFBSSxDQUFDLENBQUMsR0FBRyx3QkFBd0IsQ0FBQyxDQUFDO1lBQ25GLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDdkQsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssVUFBVSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDMUQsSUFBSSxDQUFDLHFCQUFxQixDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFFRCxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUN2RSxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRCxVQUFVLENBQUMsQ0FBUSxFQUFFLGNBQXNCLENBQUM7UUFDMUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDekIsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLE1BQWdELENBQUM7UUFDbEUsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDO1FBRXRDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQzFELElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDekIsT0FBTztRQUNULENBQUM7UUFFRCxxQ0FBcUM7UUFDckMsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxNQUFNLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDakUsSUFBSSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3JELENBQUM7YUFBTSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3hDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUVELG1CQUFtQjtRQUNuQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQztZQUNsQixJQUFJLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJO1lBQ3JCLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSztTQUNwQixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRDs7T0FFRztJQUNLLG1CQUFtQixDQUN6QixNQUE4QyxFQUM5QyxnQkFBd0I7UUFFeEIsTUFBTSxPQUFPLEdBQUcsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDeEMsSUFBSSxnQkFBZ0IsS0FBSyxPQUFPLEVBQUUsQ0FBQztZQUNqQyxNQUFNLENBQUMsS0FBSyxHQUFHLE9BQU8sQ0FBQztZQUN2QixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUN2RCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0sscUJBQXFCLENBQzNCLE1BQThDLEVBQzlDLGdCQUF3QixFQUN4QixXQUFtQjtRQUVuQix1Q0FBdUM7UUFDdkMsTUFBTSxTQUFTLEdBQUcsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUV2RCwrQ0FBK0M7UUFDL0MsTUFBTSxtQkFBbUIsR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFOUQsZ0RBQWdEO1FBQ2hELElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ2xCLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzFCLE9BQU87UUFDVCxDQUFDO1FBRUQsMkRBQTJEO1FBQzNELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDMUQsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxTQUFTLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDNUQsQ0FBQzthQUFNLENBQUM7WUFDTiw4Q0FBOEM7WUFDOUMsTUFBTSxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUM7UUFDM0IsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLG9CQUFvQixDQUMxQixNQUE4QyxFQUM5QyxTQUFpQixFQUNqQixXQUFtQjtRQUVuQiwrQ0FBK0M7UUFDL0MsSUFBSSxjQUFjLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBRXBGLHVDQUF1QztRQUN2QyxJQUFJLGNBQWMsS0FBSyxFQUFFLElBQUksY0FBYyxLQUFLLEdBQUcsRUFBRSxDQUFDO1lBQ3BELGNBQWMsR0FBRyxHQUFHLENBQUM7UUFDdkIsQ0FBQztRQUVELDhDQUE4QztRQUM5QyxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxjQUFjLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFFL0UsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLGdCQUFnQixFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBRXBGLG1FQUFtRTtRQUNuRSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBRTlELHlDQUF5QztRQUN6QyxJQUFJLENBQUMsT0FBTyxDQUFDLHNCQUFzQixFQUFFLENBQUM7UUFDdEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUU3QixvRUFBb0U7UUFDcEUsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNkLE1BQU0sQ0FBQyxLQUFLLEdBQUcsY0FBYyxDQUFDO1FBQ2hDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNSLENBQUM7SUFFRDs7T0FFRztJQUNLLG1CQUFtQixDQUFDLEtBQWEsRUFBRSxXQUFtQjtRQUM1RCxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRTlFLDhDQUE4QztRQUM5QyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsV0FBVyxFQUFFLENBQUM7WUFDakMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzdDLENBQUM7YUFBTSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsV0FBVyxFQUFFLENBQUM7WUFDeEMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQzFDLENBQUM7UUFFRCxnREFBZ0Q7UUFDaEQsT0FBTyxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLE9BQU8sSUFBSSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO0lBQzdELENBQUM7SUFFRCxpQkFBaUIsQ0FBQyxLQUFZLEVBQUUsY0FBc0IsQ0FBQztRQUNyRCxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBMEIsQ0FBQztRQUNoRCxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDO1FBQ25DLE1BQU0sY0FBYyxHQUFHLE1BQU0sQ0FBQyxjQUFjLElBQUksQ0FBQyxDQUFDO1FBRWxELDRDQUE0QztRQUM1QyxJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQztRQUUvRCxrREFBa0Q7UUFDbEQsSUFBSSxDQUFDLCtCQUErQixDQUFDLE1BQU0sRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBRW5GLDJDQUEyQztRQUMzQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsS0FBSyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBRWhELHVCQUF1QjtRQUN2QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDdEUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUMvQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssa0JBQWtCLENBQUMsS0FBYSxFQUFFLFdBQW1CO1FBQzNELHlEQUF5RDtRQUN6RCxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVoRCxnQ0FBZ0M7UUFDaEMsUUFBUSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUU5QywyREFBMkQ7UUFDM0QsUUFBUSxHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFFM0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CLENBQUMsS0FBYTtRQUN2QyxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQy9CLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNyQixPQUFPLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbEQsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CLENBQUMsS0FBYSxFQUFFLFdBQW1CO1FBQzVELElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDekIsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBRUQsTUFBTSxDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BELElBQUksV0FBVyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsV0FBVyxFQUFFLENBQUM7WUFDcEQsT0FBTyxXQUFXLEdBQUcsR0FBRyxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7T0FFRztJQUNLLCtCQUErQixDQUNyQyxNQUF3QixFQUN4QixhQUFxQixFQUNyQixRQUFnQixFQUNoQixjQUFzQjtRQUV0QixJQUFJLE1BQU0sQ0FBQyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDOUIsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLHdCQUF3QixHQUFHLElBQUksQ0FBQyw2QkFBNkIsQ0FDakUsYUFBYSxFQUNiLFFBQVEsRUFDUixjQUFjLENBQ2YsQ0FBQztRQUNGLE1BQU0sQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDO1FBQ3hCLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLGNBQWMsR0FBRyx3QkFBd0IsQ0FBQyxDQUFDO1FBQzNFLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVEOztPQUVHO0lBQ0ssc0JBQXNCLENBQUMsS0FBYSxFQUFFLFdBQW1CO1FBQy9ELElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDL0MsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7T0FHRztJQUNLLDZCQUE2QixDQUNuQyxRQUFnQixFQUNoQixRQUFnQixFQUNoQixTQUFpQjtRQUVqQixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7UUFDckIsSUFBSSxhQUFhLEdBQUcsQ0FBQyxDQUFDO1FBRXRCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLElBQUksQ0FBQyxHQUFHLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUMxRCxJQUFJLGFBQWEsR0FBRyxRQUFRLENBQUMsTUFBTSxJQUFJLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztnQkFDL0UsYUFBYSxFQUFFLENBQUM7WUFDbEIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFlBQVksRUFBRSxDQUFDO1lBQ2pCLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxZQUFZLENBQUM7SUFDdEIsQ0FBQztJQUVEOzs7T0FHRztJQUNILGlCQUFpQixDQUFDLEtBQXFCLEVBQUUsY0FBc0IsQ0FBQztRQUM5RCxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDdkIsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQTBCLENBQUM7UUFDaEQsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLGFBQWEsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzlELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLFFBQVEsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUM7UUFFM0UsTUFBTSxZQUFZLEdBQUcsVUFBVTtZQUM3QixDQUFDLENBQUMsSUFBSSxDQUFDLDZCQUE2QixDQUFDLFVBQVUsQ0FBQztZQUNoRCxDQUFDLENBQUMsSUFBSSxDQUFDLDRCQUE0QixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUU1RixtQkFBbUI7UUFDbkIsTUFBTSxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUM7UUFDMUIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsVUFBVSxFQUFFLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFFeEQsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFVBQVUsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUNwRCxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUV6QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUNwRSxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRTdCLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsWUFBWSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRDs7T0FFRztJQUNLLDZCQUE2QixDQUFDLFVBQWtCO1FBQ3RELE9BQU8sVUFBVSxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOztPQUVHO0lBQ0ssNEJBQTRCLENBQUMsVUFBa0I7UUFDckQsT0FBTyxVQUFVLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQ7O09BRUc7SUFDSyxvQkFBb0IsQ0FDMUIsTUFBd0IsRUFDeEIsWUFBb0IsRUFDcEIsVUFBbUIsRUFDbkIsV0FBbUI7UUFFbkIsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUNsQyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDO1FBQ3BDLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUM7UUFFaEMsSUFBSSxVQUFrQixDQUFDO1FBRXZCLDRFQUE0RTtRQUM1RSxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksR0FBRyxLQUFLLElBQUksSUFBSSxDQUFDLEtBQUssS0FBSyxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDakUsVUFBVSxHQUFHLFlBQVksQ0FBQztRQUM1QixDQUFDO2FBQU0sQ0FBQztZQUNOLFVBQVUsR0FBRyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsR0FBRyxZQUFZLEdBQUcsWUFBWSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM3RixDQUFDO1FBRUQsT0FBTyxVQUFVLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQztJQUMxRixDQUFDO0lBRUQ7O09BRUc7SUFDSyx3QkFBd0IsQ0FBQyxLQUFhLEVBQUUsV0FBbUI7UUFDakUsSUFBSSxNQUFNLEdBQUcsS0FBSyxDQUFDO1FBRW5CLGdDQUFnQztRQUNoQyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2hDLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNyQixNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwRCxDQUFDO1FBRUQseUNBQXlDO1FBQ3pDLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3QyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsV0FBVyxFQUFFLENBQUM7Z0JBQ2pDLE1BQU0sR0FBRyxPQUFPLEdBQUcsR0FBRyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBQ3pELENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVEOztPQUVHO0lBQ0sscUJBQXFCLENBQUMsS0FBYSxFQUFFLFdBQW1CO1FBQzlELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2pFLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsSUFBSSxFQUFFLENBQUM7UUFDdkQsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFbkUsSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLFlBQVksRUFBRSxDQUFDO1lBQ2xDLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLFlBQVksRUFBRSxXQUFXLENBQUMsQ0FBQztRQUMzRSxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1FBQ3BDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyx3QkFBd0IsQ0FBQyxNQUFjLEVBQUUsR0FBVyxFQUFFLFdBQW1CO1FBQy9FLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUNoRCxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztZQUNyQixHQUFHLGFBQWE7WUFDaEIsZ0JBQWdCLEVBQUU7Z0JBQ2hCLE1BQU07Z0JBQ04sR0FBRztnQkFDSCxXQUFXO2dCQUNYLE9BQU8sRUFBRSxnQ0FBZ0MsR0FBRyxxQkFBcUIsV0FBVyxvQkFBb0I7YUFDakc7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSywwQkFBMEI7UUFDaEMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLGtCQUFrQixDQUFDLEVBQUUsQ0FBQztZQUMvQyxPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sTUFBTSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQzFDLE9BQU8sTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDbEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVEOztPQUVHO0lBQ0ssaUJBQWlCO1FBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1lBQ3RDLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxNQUFNLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDMUMsT0FBTyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDekIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CLENBQ3pCLE1BQXdCLEVBQ3hCLFlBQW9CLEVBQ3BCLFVBQWtCO1FBRWxCLHNEQUFzRDtRQUN0RCxJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDN0IsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsY0FBYyxJQUFJLENBQUMsQ0FBQztRQUN6QyxNQUFNLFlBQVksR0FBRyxLQUFLLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQztRQUNqRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUQsTUFBTSxDQUFDLGlCQUFpQixDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQsc0NBQXNDO0lBQ3RDLHVFQUF1RTtJQUN2RSx3QkFBd0IsQ0FBQyxLQUFzQixFQUFFLGNBQXNCLENBQUM7UUFDdEUsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFVBQVU7WUFBRSxPQUFPLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUVwRixNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFbEMsb0RBQW9EO1FBQ3BELElBQUksQ0FBQyxRQUFRLElBQUksUUFBUSxLQUFLLEtBQUs7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUUvQyxzRUFBc0U7UUFDdEUsTUFBTSxDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQztZQUN2RCxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7WUFDckIsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRW5CLHdFQUF3RTtRQUN4RSxvRUFBb0U7UUFDcEUsSUFBSSxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7UUFDMUIsTUFBTSxHQUFHLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQztRQUMvQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDN0IsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztnQkFDakMsZ0JBQWdCLElBQUksR0FBRyxDQUFDO1lBQzFCLENBQUM7WUFDRCxnQkFBZ0IsSUFBSSxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDckMsQ0FBQztRQUNELHVEQUF1RDtRQUN2RCxJQUFJLGdCQUFnQixHQUFHLFdBQVcsSUFBSSxFQUFFLENBQUM7UUFDekMsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsV0FBVyxFQUFFLENBQUM7WUFDMUMsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUMvRCxDQUFDO2FBQU0sSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsV0FBVyxFQUFFLENBQUM7WUFDakQsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUM1RCxDQUFDO1FBRUQsT0FBTyxXQUFXLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLGdCQUFnQixJQUFJLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDO0lBQ3hGLENBQUM7SUFFRCxtQkFBbUIsQ0FBQyxLQUFvQixFQUFFLFVBQW1CO1FBQzNELElBQUksVUFBVTtZQUFFLE9BQU87UUFFdkIsNENBQTRDO1FBQzVDLElBQUksQ0FBQyxXQUFXLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsWUFBWSxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2xGLE9BQU87UUFDVCxDQUFDO1FBRUQsMkVBQTJFO1FBQzNFLGdDQUFnQztRQUNoQyxJQUFJLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ25DLE9BQU87UUFDVCxDQUFDO1FBRUQsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzVCLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN6QixDQUFDO0lBQ0gsQ0FBQztJQUVELG1EQUFtRDtJQUNuRCxxQkFBcUIsQ0FBQyxZQUFxQjtRQUN6QyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FDeEMsQ0FBQyxDQUFtQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLFlBQVksQ0FDakUsQ0FBQztRQUVGLE9BQU8sV0FBVyxFQUFFLE1BQU0sSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDO0lBQ25ELENBQUM7SUFFRCxZQUFZLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLHFCQUFxQixHQUFHLEVBQUUsQ0FBQztJQUMzQixhQUFhLEdBQUcsRUFBRSxDQUFDO0lBQ25CLHVCQUF1QixHQUFHLENBQUMsQ0FBQztJQUM1QixpQkFBaUIsR0FBRyxLQUFLLENBQUM7SUFDMUIsZUFBZTtRQUNiLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3hCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7UUFDOUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsY0FBYztRQUNaLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxLQUFLLENBQUM7UUFDL0IsSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQsa0JBQWtCLENBQUMsQ0FBUTtRQUN6QixJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsdURBQXVEO1FBQzNFLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLHlCQUF5QjtJQUNsRCxDQUFDO0lBRUQscUJBQXFCLENBQUMsS0FBYTtRQUNqQyxJQUFJLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQzdDLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxFQUFFLENBQUM7WUFDaEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxFQUFFLENBQUM7WUFDeEIsSUFBSSxDQUFDLHVCQUF1QixHQUFHLENBQUMsQ0FBQztZQUVqQyxPQUFPO1FBQ1QsQ0FBQztRQUNELElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUNkLElBQUksS0FBSyxDQUFDLE1BQU0sSUFBSSxDQUFDO1lBQUUsS0FBSyxFQUFFLENBQUM7UUFDL0IsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztZQUFFLEtBQUssRUFBRSxDQUFDO1FBQ2pDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7WUFBRSxLQUFLLEVBQUUsQ0FBQztRQUM5QixJQUFJLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO1lBQUUsS0FBSyxFQUFFLENBQUM7UUFFakMsSUFBSSxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksTUFBTSxDQUFDO1lBQzVELElBQUksQ0FBQyxhQUFhLEdBQUcsMkJBQTJCLENBQUM7WUFDakQsSUFBSSxDQUFDLHVCQUF1QixHQUFHLEVBQUUsQ0FBQztRQUNwQyxDQUFDO2FBQU0sSUFBSSxLQUFLLEtBQUssQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN0QyxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLElBQUksUUFBUSxDQUFDO1lBQ2hFLElBQUksQ0FBQyxhQUFhLEdBQUcsMEJBQTBCLENBQUM7WUFDaEQsSUFBSSxDQUFDLHVCQUF1QixHQUFHLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3ZELENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLHFCQUFxQixHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxJQUFJLFFBQVEsQ0FBQztZQUNoRSxJQUFJLENBQUMsYUFBYSxHQUFHLHlCQUF5QixDQUFDO1lBQy9DLElBQUksQ0FBQyx1QkFBdUIsR0FBRyxHQUFHLENBQUM7UUFDckMsQ0FBQztJQUNILENBQUM7SUFFRCxTQUFTO1FBQ1AsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRO1lBQUUsT0FBTztRQUN6QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUM7UUFDbEMsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hELElBQUksU0FBUyxHQUFHLE9BQU8sR0FBRyxJQUFJLENBQUM7UUFFL0IsSUFBSSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3ZDLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2xELENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQzdCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBRW5FLDJDQUEyQztRQUMzQyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDMUIsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDZCxNQUFNLFlBQVksR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQXFCLENBQUM7Z0JBQ2hGLElBQUksWUFBWSxFQUFFLENBQUM7b0JBQ2pCLFlBQVksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUNoRSxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQztJQUVELFNBQVM7UUFDUCxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLFFBQVE7WUFBRSxPQUFPO1FBQ3pDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsQ0FBQztRQUNsQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsSUFBSSxTQUFTLEdBQUcsT0FBTyxHQUFHLElBQUksQ0FBQztRQUUvQixpREFBaUQ7UUFDakQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDbEQsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRTFDLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDN0IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFFbkUsMkNBQTJDO1FBQzNDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUMxQixVQUFVLENBQUMsR0FBRyxFQUFFO2dCQUNkLE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBcUIsQ0FBQztnQkFDaEYsSUFBSSxZQUFZLEVBQUUsQ0FBQztvQkFDakIsWUFBWSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ2hFLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDO0lBRUQsUUFBUSxDQUFDLENBQVE7UUFDZixDQUFDLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDcEIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSztZQUFFLE9BQU87UUFDaEMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO1lBQzFELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQztZQUMzQyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNaLG1DQUFtQztnQkFDbkMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDMUQsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELFdBQVcsQ0FBQyxDQUFRO1FBQ2xCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLENBQUM7WUFDL0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQy9CLENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVyxDQUFDLENBQVE7UUFDbEIsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsQ0FBQztZQUMvQixJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDL0IsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCx3QkFBd0I7UUFDdEIsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsbUJBQW1CLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSTtZQUFFLE9BQU87UUFFMUQsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsbUJBQW1CLENBQUM7UUFDckQsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUVsRCxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUN0QixPQUFPO1FBQ1QsQ0FBQztRQUVELDJCQUEyQjtRQUMzQixJQUFJLENBQUMsZ0JBQWdCLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFOUMsNkJBQTZCO1FBQzdCLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNoRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDL0IsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxnQkFBZ0IsQ0FBQyxjQUFtQjtRQUMxQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUI7WUFBRSxPQUFPO1FBRTVDLE1BQU0sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQztRQUM5RCxJQUFJLGVBQWUsR0FBRyxLQUFLLENBQUM7UUFFNUIsMkJBQTJCO1FBQzNCLElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzNCLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUM1QixlQUFlLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN0RCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sZUFBZSxHQUFHLGNBQWMsS0FBSyxRQUFRLENBQUM7WUFDaEQsQ0FBQztRQUNILENBQUM7UUFFRCxnREFBZ0Q7UUFDaEQsSUFBSSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDM0IsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7Z0JBQ3hDLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQztnQkFDbkMsQ0FBQyxDQUFDLGNBQWMsS0FBSyxRQUFRLENBQUM7WUFFaEMsSUFBSSxVQUFVLEVBQUUsQ0FBQztnQkFDZixlQUFlLEdBQUcsS0FBSyxDQUFDO1lBQzFCLENBQUM7UUFDSCxDQUFDO1FBRUQsb0JBQW9CO1FBQ3BCLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBRXBDLDJEQUEyRDtRQUMzRCxvREFBb0Q7UUFDcEQsSUFBSSxDQUFDLGVBQWUsSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUM1RCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQyxPQUFPLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztRQUN4QyxDQUFDO1FBRUQsSUFBSSxDQUFDLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRU8sc0JBQXNCO1FBQzVCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQztRQUMzQyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ1osSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQ1gsT0FBTyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFhLEVBQUUsRUFBRTtnQkFDMUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQ3hCLGlEQUFpRDtnQkFDakQsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3hCLENBQUMsQ0FBQyxDQUNILENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVELFdBQVcsQ0FBQyxFQUFVO1FBQ3BCLElBQUksQ0FBQyxxQkFBcUIsRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVELG9CQUFvQixDQUFDLE9BQWU7UUFDbEMsSUFBSSxJQUFJLENBQUMsWUFBWSxJQUFJLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDM0UsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM5QyxDQUFDO1FBQ0QsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVELGdCQUFnQixDQUFDLEtBQVU7UUFDekIsUUFBUSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbkIsS0FBSyxTQUFTO2dCQUNaLE9BQU8sY0FBYyxDQUFDO1lBQ3hCLEtBQUssTUFBTSxDQUFDO1lBQ1osS0FBSyxNQUFNO2dCQUNULE9BQU8sYUFBYSxDQUFDO1lBQ3ZCLEtBQUssT0FBTztnQkFDVixPQUFPLG9CQUFvQixDQUFDO1lBQzlCO2dCQUNFLE9BQU8sYUFBYSxDQUFDO1FBQ3pCLENBQUM7SUFDSCxDQUFDO0lBRUQsb0JBQW9CLENBQUMsT0FBWSxFQUFFLFVBQWtCO1FBQ25ELElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3RCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDckUsQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLE9BQU8sRUFBRSxPQUFPLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUM7UUFDdEQsTUFBTSxRQUFRLEdBQUcsQ0FBQyxPQUFPLElBQUksT0FBTyxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUN2RCxPQUFPLE9BQU8sSUFBSSxRQUFRLENBQUM7SUFDN0IsQ0FBQztJQUVELGtCQUFrQixDQUFDLEtBQWE7UUFDOUIsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUN0QixJQUFJLENBQUM7WUFDSCxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEMsT0FBTyxDQUNMLFFBQVE7aUJBQ0wsS0FBSyxDQUFDLElBQUksQ0FBQztpQkFDWCxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztpQkFDMUIsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO2lCQUN4QixHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQ2xELElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUMzQyxDQUFDO1FBQ0osQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDWCxPQUFPLENBQUMsSUFBSSxDQUFDLDJDQUEyQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNwRSxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7SUFDSCxDQUFDO0lBRUQsWUFBWSxDQUFDLEtBQWE7UUFDeEIsT0FBTyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQUM7WUFDekYsQ0FBQyxDQUFDLEdBQUc7WUFDTCxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ1QsQ0FBQztJQUVELHFCQUFxQjtJQUNiLGNBQWM7UUFDcEIsdURBQXVEO1FBQ3ZELFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDZCxJQUFJLENBQUMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFO2dCQUN6QyxNQUFNLEVBQUUsR0FBRyxTQUFTLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQztnQkFDM0MsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUM1QixNQUFNLE9BQU8sR0FBSSxFQUFFLENBQUMsYUFBYSxDQUFxQixJQUFJLE1BQU0sQ0FBQztnQkFDakUsTUFBTSxJQUFJLEdBQUcsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksUUFBUSxDQUFxQixDQUFDO2dCQUM5RCxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQzlCLE1BQU0sUUFBUSxHQUFHLEVBQUUsQ0FBQyxjQUFjLENBQUMsS0FBSyxNQUFNLENBQUM7Z0JBRS9DLElBQUksSUFBSSxFQUFFLENBQUM7b0JBQ1QsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxhQUFhLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUMxRixDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTCxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDUixDQUFDO0lBRU8sbUJBQW1CLENBQ3pCLFNBQXNCLEVBQ3RCLElBQVksRUFDWixPQUF3QixFQUN4QixRQUEwQixFQUMxQixLQUFxQixFQUNyQixRQUFrQjtRQUVsQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRXBDLHlDQUF5QztRQUN6QyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDaEMsSUFBSSxXQUFXLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7WUFDbkMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDbkYsT0FBTztRQUNULENBQUM7UUFFRCxtRUFBbUU7UUFDbkUsSUFDRSxXQUFXLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQztZQUMvQixXQUFXLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQztZQUM1QixXQUFXLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQztZQUNqQyxXQUFXLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQztZQUMvQixXQUFXLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxFQUNsQyxDQUFDO1lBQ0QsTUFBTSxVQUFVLEdBQUcsbUZBQW1GLFdBQVcsUUFBUSxDQUFDO1lBQzFILElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ2xGLE9BQU87UUFDVCxDQUFDO1FBRUQsbUNBQW1DO1FBQ25DLDBFQUEwRTtRQUMxRSxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ25ELElBQUksVUFBVSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsRUFBRSxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDNUYsT0FBTztRQUNULENBQUM7UUFFRCxzQkFBc0I7UUFDdEIsT0FBTyxDQUFDLElBQUksQ0FBQyxvQkFBb0IsSUFBSSx1REFBdUQsQ0FBQyxDQUFDO1FBQzlGLFNBQVMsQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVPLG9CQUFvQixDQUMxQixTQUFzQixFQUN0QixHQUFXLEVBQ1gsS0FBZ0MsRUFDaEMsSUFBWSxFQUNaLElBQVksRUFDWixRQUFrQjtRQUVsQixJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUMsR0FBRyxFQUFFLGVBQWUsQ0FBQyxDQUFDO1lBQ3pELE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUE2QixDQUFDO1lBRWpFLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDVCxTQUFTLENBQUMsU0FBUyxHQUFHLEVBQUUsQ0FBQztnQkFDekIsT0FBTztZQUNULENBQUM7WUFFRCwwQkFBMEI7WUFDMUIsS0FBSyxNQUFNLENBQUMsSUFBSSxHQUFHLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDO2dCQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUUxRCxJQUFJLEtBQUssRUFBRSxDQUFDO2dCQUNWLEtBQUssTUFBTSxFQUFFLElBQUksR0FBRyxDQUFDLGdCQUFnQixDQUFhLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ3ZELE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQ3ZDLElBQUksS0FBSyxFQUFFLENBQUM7d0JBQ1YsTUFBTSxPQUFPLEdBQUcsS0FBSzs2QkFDbEIsVUFBVSxDQUFDLHNCQUFzQixFQUFFLEVBQUUsQ0FBQzs2QkFDdEMsVUFBVSxDQUFDLHdCQUF3QixFQUFFLEVBQUUsQ0FBQyxDQUFDO3dCQUM1QyxJQUFJLE9BQU87NEJBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7OzRCQUMxQyxFQUFFLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO29CQUNuQyxDQUFDO29CQUVELE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7b0JBQ3JDLElBQUksSUFBSSxJQUFJLElBQUksS0FBSyxNQUFNLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7d0JBQ3hELEVBQUUsQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLGNBQWMsQ0FBQyxDQUFDO29CQUMxQyxDQUFDO29CQUVELE1BQU0sTUFBTSxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQ3pDLElBQUksTUFBTSxJQUFJLE1BQU0sS0FBSyxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7d0JBQzlELEVBQUUsQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLGNBQWMsQ0FBQyxDQUFDO29CQUM1QyxDQUFDO2dCQUNILENBQUM7WUFDSCxDQUFDO1lBRUQsR0FBRyxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM3QixHQUFHLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQzlCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7Z0JBQ2pDLEdBQUcsQ0FBQyxZQUFZLENBQUMsU0FBUyxFQUFFLE9BQU8sSUFBSSxJQUFJLElBQUksRUFBRSxDQUFDLENBQUM7WUFDckQsQ0FBQztZQUNELEdBQUcsQ0FBQyxZQUFZLENBQUMscUJBQXFCLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFDekQsR0FBRyxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDdkMsR0FBRyxDQUFDLFlBQVksQ0FBQyxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDeEMsR0FBRyxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDbEMsR0FBRyxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFFbkMsTUFBTSxLQUFLLEdBQUcsZ0RBQWdELENBQUM7WUFDL0QsR0FBRyxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDO1lBRXJFLFNBQVMsQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDO1lBQ3pCLElBQUksS0FBSyxFQUFFLENBQUM7Z0JBQ1YsU0FBUyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1lBQ2hDLENBQUM7WUFDRCxJQUFJLFFBQVEsRUFBRSxDQUFDO2dCQUNiLFNBQVMsQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQztnQkFDaEMsU0FBUyxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsYUFBYSxDQUFDO1lBQ3pDLENBQUM7aUJBQU0sQ0FBQztnQkFDTixTQUFTLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUM7Z0JBQzlCLFNBQVMsQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLEVBQUUsQ0FBQztZQUM5QixDQUFDO1lBQ0QsU0FBUyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMzQixJQUFJLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQzNCLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQywwQ0FBMEMsSUFBSSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDekUsU0FBUyxDQUFDLFNBQVMsR0FBRyxFQUFFLENBQUM7UUFDM0IsQ0FBQztJQUNILENBQUM7SUFFRCxrREFBa0Q7SUFFbEQsd0JBQXdCO0lBQ3hCLGVBQWU7UUFDYixJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU87WUFBRSxPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsVUFBVSxJQUFJLEVBQUUsQ0FBQztRQUV2RCxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEQsS0FBSyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDbkQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzVDLElBQUksVUFBVSxJQUFJLE9BQU8sVUFBVSxLQUFLLFFBQVEsSUFBSSxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUM7b0JBQ3ZFLE9BQU8sVUFBVSxDQUFDLE9BQU8sQ0FBQztnQkFDNUIsQ0FBQztnQkFDRCxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDOUIsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDaEMsQ0FBQztZQUNILENBQUM7WUFDRCxPQUFPLENBQ0wsSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUM7Z0JBQy9CLGVBQWUsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQ25FLENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLFVBQVUsSUFBSSxFQUFFLENBQUM7SUFDdEMsQ0FBQztJQUVELElBQUksT0FBTztRQUNULE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxPQUFPLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEtBQUssSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQzFELENBQUM7d0dBMTFDVSxPQUFPOzRGQUFQLE9BQU8sa2dCQzFEcEIsc2dyQkEyZUEsNG1IRHRiWSxXQUFXLG1uQkFBRSxZQUFZLGlOQUFFLG1CQUFtQixpTkFBRSxlQUFlLDRGQUFFLE9BQU87OzRGQUt2RSxPQUFPO2tCQVJuQixTQUFTOytCQUNFLFVBQVUsY0FDUixJQUFJLFdBQ1AsQ0FBQyxXQUFXLEVBQUUsWUFBWSxFQUFFLG1CQUFtQixFQUFFLGVBQWUsRUFBRSxPQUFPLENBQUMsbUJBR2xFLHVCQUF1QixDQUFDLE1BQU07c0ZBR3RDLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxZQUFZO3NCQUFwQixLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBTUcsWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxhQUFhO3NCQUFyQixLQUFLO2dCQUNHLElBQUk7c0JBQVosS0FBSztnQkFDSSxXQUFXO3NCQUFwQixNQUFNO2dCQUNHLFNBQVM7c0JBQWxCLE1BQU07Z0JBSWtCLGVBQWU7c0JBQXZDLFNBQVM7dUJBQUMsWUFBWTtnQkFDUSxjQUFjO3NCQUE1QyxZQUFZO3VCQUFDLGVBQWUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIEFmdGVyVmlld0luaXQsXHJcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXHJcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXHJcbiAgQ29tcG9uZW50LFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgRXZlbnRFbWl0dGVyLFxyXG4gIGluamVjdCxcclxuICBJbnB1dCxcclxuICBPbkluaXQsXHJcbiAgT3V0cHV0LFxyXG4gIHNpZ25hbCxcclxuICBWaWV3Q2hpbGQsXHJcbiAgT25EZXN0cm95LFxyXG4gIE9uQ2hhbmdlcyxcclxuICBTaW1wbGVDaGFuZ2VzLFxyXG4gIFZpZXdDaGlsZHJlbixcclxuICBRdWVyeUxpc3QsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbi8vIFJlbW92ZWQgSHR0cENsaWVudCBpbXBvcnRcclxuaW1wb3J0IHsgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCwgRm9ybXNNb2R1bGUsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IFRyYW5zbGF0ZU1vZHVsZSwgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xyXG5pbXBvcnQgeyBTdWJzY3JpcHRpb24sIG1lcmdlIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IHN0YXJ0V2l0aCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgRk5MYWJlbCB9IGZyb20gJ2ZuLWxhYmVsJztcclxuaW1wb3J0IHtcclxuICBGTklucHV0QmFzZSxcclxuICBGTklucHV0SGVscGVyLFxyXG4gIEZOSW5wdXRUb2FzdCxcclxuICBERUZBVUxUX0NVUlJFTkNZX01FVEEsXHJcbiAgVHlwZUljb25WYXJpYW50LFxyXG4gIFR5cGVJY29uU2l6ZSxcclxuICBGTl9UT0FTVF9TRVJWSUNFLFxyXG59IGZyb20gJy4vZm4taW5wdXQudHlwZXMnO1xyXG5cclxuZXhwb3J0IHR5cGUgVHlwZUljb25TaXplTmFtZSA9ICdleHRyYXNtYWxsJyB8ICdzbWFsbCcgfCAnbWVkaXVtJyB8ICdsYXJnZScgfCAneC1sYXJnZScgfCAneHhsYXJnZSc7XHJcblxyXG5jb25zdCBDT1JFX0lDT05TOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xyXG4gICdleWUtb3Blbic6IGA8c3ZnIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj48cGF0aCBkPVwiTTIgMTJzNC04IDEwLTggMTAgOCAxMCA4LTQgOC0xMCA4LTEwLTgtMTAtOHpcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPjxjaXJjbGUgY3g9XCIxMlwiIGN5PVwiMTJcIiByPVwiM1wiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PC9zdmc+YCxcclxuICAnZXllLWNsb3NlJzogYDxzdmcgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPjxwYXRoIGQ9XCJNMiAxMGExMSAxMSAwIDAgMCAyMCAwXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz48cGF0aCBkPVwiTTUgMTNsLTEgMk0xMiAxNHYyTTE5IDEzbDEgMlwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PC9zdmc+YCxcclxuICAndHdvLXNxdWFyZSc6IGA8c3ZnIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj48cmVjdCB4PVwiOFwiIHk9XCI0XCIgd2lkdGg9XCIxMlwiIGhlaWdodD1cIjEyXCIgcng9XCIyXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz48cGF0aCBkPVwiTTQgOHYxMGEyIDIgMCAwIDAgMiAyaDEwXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz48L3N2Zz5gLFxyXG4gICdyb3VuZC1hcnJvdy10b3AtbGVmdCc6IGA8c3ZnIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj48cGF0aCBkPVwiTTIzIDR2NmgtNk0xIDIwdi02aDZNMy41MSA5YTkgOSAwIDAgMSAxNC44NS0zLjM2TDIzIDEwTTEgMTRsNC42NCA0LjM2QTkgOSAwIDAgMCAyMC40OSAxNVwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PC9zdmc+YCxcclxuICAnY2hlY2stY2lyY2xlJzogYDxzdmcgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPjxjaXJjbGUgY3g9XCIxMlwiIGN5PVwiMTJcIiByPVwiMTBcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCIvPjxwYXRoIGQ9XCJNOCAxMmwzIDMgNS01XCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz48L3N2Zz5gLFxyXG4gICdpbmZvLWNpcmNsZSc6IGA8c3ZnIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj48Y2lyY2xlIGN4PVwiMTJcIiBjeT1cIjEyXCIgcj1cIjEwXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz48bGluZSB4MT1cIjEyXCIgeTE9XCIxNlwiIHgyPVwiMTJcIiB5Mj1cIjEyXCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz48bGluZSB4MT1cIjEyXCIgeTE9XCI4XCIgeDI9XCIxMi4wMVwiIHkyPVwiOFwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PC9zdmc+YCxcclxuICAnYWxlcnQtY2lyY2xlJzogYDxzdmcgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPjxjaXJjbGUgY3g9XCIxMlwiIGN5PVwiMTJcIiByPVwiMTBcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPjxsaW5lIHgxPVwiMTJcIiB5MT1cIjhcIiB4Mj1cIjEyXCIgeTI9XCIxMlwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PGxpbmUgeDE9XCIxMlwiIHkxPVwiMTZcIiB4Mj1cIjEyLjAxXCIgeTI9XCIxNlwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PC9zdmc+YCxcclxuICAnZXhjbGFtYXRpb24tY2lyY2xlJzogYDxzdmcgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPjxjaXJjbGUgY3g9XCIxMlwiIGN5PVwiMTJcIiByPVwiMTBcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIvPjxsaW5lIHgxPVwiMTJcIiB5MT1cIjhcIiB4Mj1cIjEyXCIgeTI9XCIxMlwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PGxpbmUgeDE9XCIxMlwiIHkxPVwiMTZcIiB4Mj1cIjEyLjAxXCIgeTI9XCIxNlwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PC9zdmc+YCxcclxuICBjcm9zczogYDxzdmcgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPjxwYXRoIGQ9XCJNMTggNkw2IDE4TTYgNmwxMiAxMlwiIHN0cm9rZT1cImN1cnJlbnRDb2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIi8+PC9zdmc+YCxcclxufTtcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnZm4taW5wdXQnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW0Zvcm1zTW9kdWxlLCBDb21tb25Nb2R1bGUsIFJlYWN0aXZlRm9ybXNNb2R1bGUsIFRyYW5zbGF0ZU1vZHVsZSwgRk5MYWJlbF0sXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2ZuLWlucHV0LmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9mbi1pbnB1dC5jb21wb25lbnQuc2NzcyddLFxyXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgRk5JbnB1dCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95LCBPbkNoYW5nZXMge1xyXG4gIEBJbnB1dCgpIGZpZWxkID0ge30gYXMgRk5JbnB1dEJhc2U7XHJcbiAgQElucHV0KCkgaGVscGVySGFuZGxlPzogRk5JbnB1dEhlbHBlcjtcclxuICBASW5wdXQoKSB0b2FzdFNlcnZpY2U/OiBGTklucHV0VG9hc3Q7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBpbmplY3RlZFRvYXN0U2VydmljZSA9IGluamVjdChGTl9UT0FTVF9TRVJWSUNFLCB7IG9wdGlvbmFsOiB0cnVlIH0pO1xyXG5cclxuICBnZXQgZWZmZWN0aXZlVG9hc3RTZXJ2aWNlKCk6IEZOSW5wdXRUb2FzdCB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gdGhpcy50b2FzdFNlcnZpY2UgfHwgdGhpcy5pbmplY3RlZFRvYXN0U2VydmljZSB8fCB1bmRlZmluZWQ7XHJcbiAgfVxyXG4gIEBJbnB1dCgpIGN1cnJlbmN5TWV0YSA9IERFRkFVTFRfQ1VSUkVOQ1lfTUVUQTtcclxuICBASW5wdXQoKSBkZWZhdWx0TG9jYWxlID0gJ2VuLVVTJztcclxuICBASW5wdXQoKSBmb3JtITogRm9ybUdyb3VwO1xyXG4gIEBPdXRwdXQoKSB2YWx1ZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuICBAT3V0cHV0KCkgZmllbGRCbHVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xyXG5cclxuICB0cmFuc2xhdGVTZXJ2aWNlID0gaW5qZWN0KFRyYW5zbGF0ZVNlcnZpY2UpO1xyXG4gIGhhc0ZvY3VzID0gc2lnbmFsKGZhbHNlKTtcclxuICBAVmlld0NoaWxkKCdmblRleHRhcmVhJykgdGV4dGFyZWFFbGVtZW50ITogRWxlbWVudFJlZjxIVE1MVGV4dEFyZWFFbGVtZW50PjtcclxuICBAVmlld0NoaWxkcmVuKCdpY29uQ29udGFpbmVyJykgaWNvbkNvbnRhaW5lcnMhOiBRdWVyeUxpc3Q8RWxlbWVudFJlZjxIVE1MRWxlbWVudD4+O1xyXG5cclxuICAvLyBJbnRlcm5hbCBUb2FzdCBTdGF0ZVxyXG4gIHRvYXN0cyA9IHNpZ25hbDxhbnlbXT4oW10pO1xyXG5cclxuICAvLyBSZW1vdmVkIEh0dHBDbGllbnQgaW5qZWN0aW9uXHJcbiAgcHJpdmF0ZSByZWFkb25seSBzdWJzID0gbmV3IFN1YnNjcmlwdGlvbigpO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IHNpemVNYXA6IFJlY29yZDxUeXBlSWNvblNpemVOYW1lLCBUeXBlSWNvblNpemU+ID0ge1xyXG4gICAgZXh0cmFzbWFsbDogMTAsXHJcbiAgICBzbWFsbDogMTYsXHJcbiAgICBtZWRpdW06IDIwLFxyXG4gICAgbGFyZ2U6IDI0LFxyXG4gICAgJ3gtbGFyZ2UnOiAzMixcclxuICAgIHh4bGFyZ2U6IDQ4LFxyXG4gIH07XHJcblxyXG4gIGdldEljb25TaXplTmFtZShzaXplOiBudW1iZXIpOiAnc21hbGwnIHwgJ21lZGl1bScgfCAnbGFyZ2UnIHwgJ3gtbGFyZ2UnIHtcclxuICAgIHN3aXRjaCAoc2l6ZSkge1xyXG4gICAgICBjYXNlIDE2OlxyXG4gICAgICAgIHJldHVybiAnc21hbGwnO1xyXG4gICAgICBjYXNlIDIwOlxyXG4gICAgICAgIHJldHVybiAnbWVkaXVtJztcclxuICAgICAgY2FzZSAyNDpcclxuICAgICAgICByZXR1cm4gJ2xhcmdlJztcclxuICAgICAgY2FzZSAzMjpcclxuICAgICAgICByZXR1cm4gJ3gtbGFyZ2UnO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHJldHVybiAnbWVkaXVtJztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGdldCBpc0FscGhhbnVtZXJpYygpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLmZpZWxkLmlzQWxwaGFudW1lcmljICE9PSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGdldCBpc0VtYWlsRmllbGQoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5maWVsZC50eXBlID09PSAnZW1haWwnIHx8IHRoaXMuZmllbGQubmFtZT8udG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnZW1haWwnKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0IGFscGhhbnVtZXJpY1BhdHRlcm4oKTogUmVnRXhwIHtcclxuICAgIGlmICh0aGlzLmZpZWxkLmlzQWRkcmVzc0xpbmUpIHtcclxuICAgICAgcmV0dXJuIC9bXkEtWmEtejAtOSBcXC1fJigpLC9dL2c7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIC9bXkEtWmEtejAtOSBcXC1fJigpXS9nO1xyXG4gIH1cclxuXHJcbiAgaXNEaXNhYmxlZCA9IGZhbHNlO1xyXG4gIGNvbnRyb2whOiBGb3JtQ29udHJvbDtcclxuICBpc1Zpc2libGUgPSBzaWduYWwodHJ1ZSk7IC8vIFRyYWNrIHZpc2liaWxpdHkgc3RhdGVcclxuICBoZWxwZXJUZXh0ID0gJyc7XHJcblxyXG4gIC8vIFVzZSBhIGNvdW50ZXItYmFzZWQgYXBwcm9hY2ggZm9yIHVuaXF1ZSBJRHMgKHNhZmVyIHRoYW4gTWF0aC5yYW5kb20oKSlcclxuICBwcml2YXRlIHN0YXRpYyBpZENvdW50ZXIgPSAwO1xyXG4gIHVuaXF1ZUlkID0gYGZuLWlucHV0LSR7KytGTklucHV0LmlkQ291bnRlcn1gO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYpIHt9XHJcblxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMuZmllbGQuaGlkZGVuKSByZXR1cm47XHJcbiAgICB0aGlzLmhlbHBlclRleHQgPSB0aGlzLmZpZWxkLmhlbHBlclRleHQgPz8gJyc7XHJcbiAgICB0aGlzLmluaXRGb3JtQ29udHJvbCgpO1xyXG5cclxuICAgIGlmICh0aGlzLmZpZWxkLnZhbHVlKSB0aGlzLmNvbnRyb2wuc2V0VmFsdWUodGhpcy5maWVsZC52YWx1ZSk7XHJcbiAgICB0aGlzLnNldHVwVmlzaWJpbGl0eUNvbmRpdGlvbigpO1xyXG4gICAgdGhpcy5zZXR1cEZpZWxkTWVzc2FnZUxpc3RlbmVyKCk7XHJcbiAgICB0aGlzLnNldHVwVG9hc3RTdWJzY3JpcHRpb24oKTtcclxuICB9XHJcblxyXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgdGhpcy5zdWJzLnVuc3Vic2NyaWJlKCk7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcbiAgICBpZiAoY2hhbmdlc1snZmllbGQnXSB8fCBjaGFuZ2VzWydmb3JtJ10pIHtcclxuICAgICAgdGhpcy51cGRhdGVBbGxJY29ucygpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXR1cEZpZWxkTWVzc2FnZUxpc3RlbmVyKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLmNvbnRyb2wpIHJldHVybjtcclxuXHJcbiAgICBjb25zdCB2YWwkID0gdGhpcy5jb250cm9sLnZhbHVlQ2hhbmdlcy5waXBlKHN0YXJ0V2l0aCh0aGlzLmNvbnRyb2wudmFsdWUpKTtcclxuICAgIGNvbnN0IHN0YXR1cyQgPSB0aGlzLmNvbnRyb2wuc3RhdHVzQ2hhbmdlcy5waXBlKHN0YXJ0V2l0aCh0aGlzLmNvbnRyb2wuc3RhdHVzKSk7XHJcblxyXG4gICAgdGhpcy5zdWJzLmFkZChcclxuICAgICAgbWVyZ2UodmFsJCwgc3RhdHVzJCkuc3Vic2NyaWJlKCgpID0+IHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgIGNvbnNvbGUud2FybignQ0RSIGRldGVjdENoYW5nZXMgZmFpbGVkIGR1cmluZyBmaWVsZCBtZXNzYWdlIHVwZGF0ZTonLCBlKTtcclxuICAgICAgICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSksXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xyXG4gICAgLy8gQWNjZXNzIHRoZSB0ZXh0YXJlYSBlbGVtZW50IGJ5IFZpZXdDaGlsZCBvciBuYXRpdmUgZWxlbWVudCByZWZlcmVuY2VcclxuICAgIHRoaXMuYXV0b1Jlc2l6ZUluaXRpYWwoKTtcclxuICAgIGlmICh0aGlzLmZpZWxkLnR5cGUgPT09ICd0ZXh0YXJlYScgJiYgdGhpcy5jb250cm9sPy52YWx1ZSkge1xyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMuYXV0b1Jlc2l6ZUluaXRpYWwoKSwgMzApO1xyXG4gICAgfVxyXG4gICAgLy8gQXBwbHkgaW5pdGlhbCBmb3JtYXR0aW5nIGFmdGVyIHZpZXcgaXMgaW5pdGlhbGl6ZWRcclxuICAgIGlmICh0aGlzLmZpZWxkLnR5cGUgPT09ICdudW1iZXInICYmIHRoaXMuZmllbGQuaXNDdXJyZW5jeSAmJiB0aGlzLmNvbnRyb2w/LnZhbHVlKSB7XHJcbiAgICAgIHRoaXMuZm9ybWF0SW5pdGlhbEN1cnJlbmN5VmFsdWUoKTtcclxuICAgIH1cclxuICAgIHRoaXMuc2V0dXBJY29uQ29udGFpbmVyc0xpc3RlbmVyKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldHVwSWNvbkNvbnRhaW5lcnNMaXN0ZW5lcigpOiB2b2lkIHtcclxuICAgIHRoaXMuc3Vicy5hZGQoXHJcbiAgICAgIHRoaXMuaWNvbkNvbnRhaW5lcnMuY2hhbmdlcy5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICAgIHRoaXMudXBkYXRlQWxsSWNvbnMoKTtcclxuICAgICAgfSksXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgZW5mb3JjZUxvd2VyY2FzZShldmVudDogRXZlbnQpIHtcclxuICAgIGNvbnN0IGlucHV0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgICBjb25zdCBzdGFydCA9IGlucHV0LnNlbGVjdGlvblN0YXJ0O1xyXG4gICAgY29uc3QgZW5kID0gaW5wdXQuc2VsZWN0aW9uRW5kO1xyXG5cclxuICAgIGlucHV0LnZhbHVlID0gaW5wdXQudmFsdWUudG9Mb3dlckNhc2UoKTtcclxuICAgIGlmICh0aGlzLmNvbnRyb2wpIHtcclxuICAgICAgdGhpcy5jb250cm9sLnNldFZhbHVlKGlucHV0LnZhbHVlLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnZhbHVlQ2hhbmdlLmVtaXQoeyBuYW1lOiB0aGlzLmZpZWxkLm5hbWUsIHZhbHVlOiBpbnB1dC52YWx1ZSB9KTtcclxuXHJcbiAgICAvLyByZXN0b3JlIGN1cnNvciBwb3NpdGlvbiBzbyB0eXBpbmcgaXMgc21vb3RoXHJcbiAgICBpbnB1dC5zZXRTZWxlY3Rpb25SYW5nZShzdGFydCwgZW5kKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZSBlbWFpbCBpbnB1dCAtIGFsbG93cyBvbmx5IHZhbGlkIGVtYWlsIGNoYXJhY3RlcnMgYW5kIGVuZm9yY2VzIGxvd2VyY2FzZS5cclxuICAgKiBBbGxvd2VkOiBhLXosIDAtOSwgLiBfICsgLSBAXHJcbiAgICogUnVsZXM6XHJcbiAgICogLSBPbmx5IG9uZSBAIGFsbG93ZWRcclxuICAgKiAtIE5vIGNvbnNlY3V0aXZlIGRvdHMgKC4uKVxyXG4gICAqIC0gQXV0b21hdGljIGxvd2VyY2FzZVxyXG4gICAqL1xyXG4gIGhhbmRsZUVtYWlsSW5wdXQoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XHJcbiAgICBjb25zdCBpbnB1dCA9IGV2ZW50LnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgY29uc3QgY3Vyc29yUG9zaXRpb24gPSBpbnB1dC5zZWxlY3Rpb25TdGFydCB8fCAwO1xyXG4gICAgY29uc3Qgb3JpZ2luYWxWYWx1ZSA9IGlucHV0LnZhbHVlO1xyXG5cclxuICAgIC8vIDEuIENvbnZlcnQgdG8gbG93ZXJjYXNlXHJcbiAgICBjb25zdCBsb3dlclZhbHVlID0gb3JpZ2luYWxWYWx1ZS50b0xvd2VyQ2FzZSgpO1xyXG5cclxuICAgIC8vIDIuIFNwbGl0IGF0IHRoZSBmaXJzdCBAIHRvIGhhbmRsZSBsb2NhbCBhbmQgZG9tYWluIHBhcnRzIHNlcGFyYXRlbHlcclxuICAgIGNvbnN0IHBhcnRzID0gbG93ZXJWYWx1ZS5zcGxpdCgnQCcpO1xyXG4gICAgbGV0IGxvY2FsUGFydCA9IHBhcnRzWzBdO1xyXG4gICAgbGV0IGRvbWFpblBhcnQgPSBwYXJ0cy5sZW5ndGggPiAxID8gcGFydHMuc2xpY2UoMSkuam9pbignJykgOiBudWxsO1xyXG5cclxuICAgIC8vIDMuIEZpbHRlciBsb2NhbCBwYXJ0OiBhLXosIDAtOSwgLiwgXywgKywgLVxyXG4gICAgLy8gUnVsZTogQ2Fubm90IHN0YXJ0IHdpdGggYSBkb3QgKC4pXHJcbiAgICBsb2NhbFBhcnQgPSBsb2NhbFBhcnQucmVwbGFjZUFsbCgvW15hLXowLTkuXystXS9nLCAnJyk7XHJcbiAgICB3aGlsZSAobG9jYWxQYXJ0LnN0YXJ0c1dpdGgoJy4nKSkge1xyXG4gICAgICBsb2NhbFBhcnQgPSBsb2NhbFBhcnQuc3Vic3RyaW5nKDEpO1xyXG4gICAgfVxyXG4gICAgd2hpbGUgKGxvY2FsUGFydC5pbmNsdWRlcygnLi4nKSkge1xyXG4gICAgICBsb2NhbFBhcnQgPSBsb2NhbFBhcnQucmVwbGFjZUFsbCgnLi4nLCAnLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIDQuIEZpbHRlciBkb21haW4gcGFydDogYS16LCAwLTksIC4sIC1cclxuICAgIC8vIFJ1bGU6IE5vIHVuZGVyc2NvcmVzIChfKSwgbm8gcGx1cyBzaWducyAoKyksIGNhbm5vdCBzdGFydCB3aXRoIGEgaHlwaGVuICgtKVxyXG4gICAgbGV0IGZpbHRlcmVkVmFsdWUgPSBsb2NhbFBhcnQ7XHJcbiAgICBpZiAoZG9tYWluUGFydCAhPT0gbnVsbCkge1xyXG4gICAgICBkb21haW5QYXJ0ID0gZG9tYWluUGFydC5yZXBsYWNlQWxsKC9bXmEtejAtOS4tXS9nLCAnJyk7XHJcbiAgICAgIHdoaWxlIChkb21haW5QYXJ0LnN0YXJ0c1dpdGgoJy0nKSkge1xyXG4gICAgICAgIGRvbWFpblBhcnQgPSBkb21haW5QYXJ0LnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgICB3aGlsZSAoZG9tYWluUGFydC5pbmNsdWRlcygnLi4nKSkge1xyXG4gICAgICAgIGRvbWFpblBhcnQgPSBkb21haW5QYXJ0LnJlcGxhY2VBbGwoJy4uJywgJy4nKTtcclxuICAgICAgfVxyXG4gICAgICBmaWx0ZXJlZFZhbHVlICs9ICdAJyArIGRvbWFpblBhcnQ7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKG9yaWdpbmFsVmFsdWUgIT09IGZpbHRlcmVkVmFsdWUpIHtcclxuICAgICAgY29uc3QgY2hhcnNSZW1vdmVkQmVmb3JlQ3Vyc29yID0gdGhpcy5jb3VudFJlbW92ZWRDaGFyc0JlZm9yZUN1cnNvcihcclxuICAgICAgICBvcmlnaW5hbFZhbHVlLnRvTG93ZXJDYXNlKCksXHJcbiAgICAgICAgZmlsdGVyZWRWYWx1ZSxcclxuICAgICAgICBjdXJzb3JQb3NpdGlvbixcclxuICAgICAgKTtcclxuICAgICAgaW5wdXQudmFsdWUgPSBmaWx0ZXJlZFZhbHVlO1xyXG4gICAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUoZmlsdGVyZWRWYWx1ZSwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG4gICAgICBjb25zdCBuZXdDdXJzb3JQb3MgPSBNYXRoLm1heCgwLCBjdXJzb3JQb3NpdGlvbiAtIGNoYXJzUmVtb3ZlZEJlZm9yZUN1cnNvcik7XHJcbiAgICAgIGlucHV0LnNldFNlbGVjdGlvblJhbmdlKG5ld0N1cnNvclBvcywgbmV3Q3Vyc29yUG9zKTtcclxuICAgIH0gZWxzZSBpZiAob3JpZ2luYWxWYWx1ZSAhPT0gbG93ZXJWYWx1ZSkge1xyXG4gICAgICAvLyBJZiBvbmx5IGNhc2UgY2hhbmdlZCAoZS5nLiwgdHlwZWQgVXBwZXJjYXNlKVxyXG4gICAgICBpbnB1dC52YWx1ZSA9IGZpbHRlcmVkVmFsdWU7XHJcbiAgICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZShmaWx0ZXJlZFZhbHVlLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICAgIGlucHV0LnNldFNlbGVjdGlvblJhbmdlKGN1cnNvclBvc2l0aW9uLCBjdXJzb3JQb3NpdGlvbik7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuZmllbGQudHlwZSA9PT0gJ3Bhc3N3b3JkJyAmJiB0aGlzLmZpZWxkLmZlZWRiYWNrKSB7XHJcbiAgICAgIHRoaXMuY2hlY2tQYXNzd29yZFN0cmVuZ3RoKGZpbHRlcmVkVmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMudmFsdWVDaGFuZ2UuZW1pdCh7IG5hbWU6IHRoaXMuZmllbGQubmFtZSwgdmFsdWU6IGZpbHRlcmVkVmFsdWUgfSk7XHJcbiAgICB0aGlzLmNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gIH1cclxuXHJcbiAgb25Gb2N1cygpOiB2b2lkIHtcclxuICAgIHRoaXMuaGFzRm9jdXMuc2V0KHRydWUpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBmb3JtYXRJbml0aWFsQ3VycmVuY3lWYWx1ZSgpOiB2b2lkIHtcclxuICAgIGNvbnN0IG51bWVyaWNWYWx1ZSA9IE51bWJlcih0aGlzLmNvbnRyb2wudmFsdWUpO1xyXG4gICAgaWYgKCFOdW1iZXIuaXNOYU4obnVtZXJpY1ZhbHVlKSkge1xyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICBjb25zdCBpbnB1dEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnVuaXF1ZUlkKSBhcyBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgICAgIGlmIChpbnB1dEVsZW1lbnQpIHtcclxuICAgICAgICAgIGlucHV0RWxlbWVudC52YWx1ZSA9IHRoaXMuZm9ybWF0Q3VycmVuY3lXaXRoQ29tbWFzKG51bWVyaWNWYWx1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9LCA1MCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBpbml0Rm9ybUNvbnRyb2woKSB7XHJcbiAgICBjb25zdCBjb250cm9sbGVyID0gdGhpcy5mb3JtLmNvbnRyb2xzPy5bdGhpcy5maWVsZC5uYW1lXTtcclxuICAgIHRoaXMuY29udHJvbCA9IGNvbnRyb2xsZXIgYXMgRm9ybUNvbnRyb2w7XHJcbiAgICBpZiAodGhpcy5maWVsZC52YWx1ZSkgdGhpcy5jb250cm9sLnNldFZhbHVlKHRoaXMuZmllbGQudmFsdWUpO1xyXG5cclxuICAgIGlmICh0aGlzLmNvbnRyb2wpIHtcclxuICAgICAgLy8gSGFuZGxlIGRpc2FibGVkIHN0YXRlXHJcbiAgICAgIGlmICh0aGlzLmZpZWxkLmRpc2FibGVkID8/IGZhbHNlKSB7XHJcbiAgICAgICAgdGhpcy5jb250cm9sPy5kaXNhYmxlKCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5jb250cm9sPy5lbmFibGUoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgYXV0b1Jlc2l6ZUluaXRpYWwoKSB7XHJcbiAgICBjb25zdCB0ZXh0YXJlYSA9IHRoaXMudGV4dGFyZWFFbGVtZW50Py5uYXRpdmVFbGVtZW50O1xyXG4gICAgaWYgKHRleHRhcmVhKSB7XHJcbiAgICAgIC8vIEdldCB0aGUgbnVtYmVyIG9mIHJvd3MgKGRlZmF1bHQgdG8gMiBpZiBub3Qgc3BlY2lmaWVkKVxyXG4gICAgICBjb25zdCByb3dzID0gdGhpcy5maWVsZC5yb3dzIHx8IDE7XHJcblxyXG4gICAgICAvLyBDYWxjdWxhdGUgbGluZSBoZWlnaHQgZnJvbSBjb21wdXRlZCBzdHlsZXNcclxuICAgICAgY29uc3QgY29tcHV0ZWRTdHlsZSA9IGdsb2JhbFRoaXMuZ2V0Q29tcHV0ZWRTdHlsZSh0ZXh0YXJlYSk7XHJcbiAgICAgIGNvbnN0IGxpbmVIZWlnaHQgPSBOdW1iZXIucGFyc2VGbG9hdChjb21wdXRlZFN0eWxlLmxpbmVIZWlnaHQpIHx8IDMyOyAvLyBEZWZhdWx0IHRvIDI0cHggaWYgbm90IHNldFxyXG5cclxuICAgICAgLy8gQ2FsY3VsYXRlIG1pbmltdW0gaGVpZ2h0IGJhc2VkIG9uIHJvd3NcclxuICAgICAgY29uc3QgbWluSGVpZ2h0ID0gcm93cyAqIGxpbmVIZWlnaHQ7XHJcblxyXG4gICAgICAvLyBSZXNldCBoZWlnaHQgdG8gYXV0byB0byBnZXQgYWNjdXJhdGUgc2Nyb2xsSGVpZ2h0XHJcbiAgICAgIHRleHRhcmVhLnN0eWxlLmhlaWdodCA9ICdhdXRvJztcclxuXHJcbiAgICAgIC8vIFVzZSB0aGUgbGFyZ2VyIG9mIHNjcm9sbEhlaWdodCBvciBtaW5IZWlnaHRcclxuICAgICAgY29uc3QgbmV3SGVpZ2h0ID0gTWF0aC5tYXgodGV4dGFyZWEuc2Nyb2xsSGVpZ2h0LCBtaW5IZWlnaHQpO1xyXG4gICAgICB0ZXh0YXJlYS5zdHlsZS5oZWlnaHQgPSBuZXdIZWlnaHQgKyAncHgnO1xyXG4gICAgICB0ZXh0YXJlYS5zdHlsZS5vdmVyZmxvdyA9ICdoaWRkZW4nO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgaGFuZGxlVGV4dEFyZWEoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XHJcbiAgICBjb25zdCBlbGVtZW50ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxUZXh0QXJlYUVsZW1lbnQ7XHJcbiAgICBjb25zdCBjdXJzb3JQb3NpdGlvbiA9IGVsZW1lbnQuc2VsZWN0aW9uU3RhcnQ7XHJcbiAgICBjb25zdCBvcmlnaW5hbFZhbHVlID0gZWxlbWVudC52YWx1ZTtcclxuXHJcbiAgICAvLyBBcHBseSBhbHBoYW51bWVyaWMgZmlsdGVyaW5nIGlmIGVuYWJsZWRcclxuICAgIGlmICh0aGlzLmZpZWxkLnR5cGUgPT09ICd0ZXh0YXJlYScgJiYgdGhpcy5pc0FscGhhbnVtZXJpYykge1xyXG4gICAgICAvLyBPbmx5IGFsbG93IGNoYXJhY3RlcnMgYmFzZWQgb24gdGhlIHNlbGVjdGVkIHBhdHRlcm5cclxuICAgICAgY29uc3QgYWxwaGFudW1lcmljUGF0dGVybiA9IHRoaXMuYWxwaGFudW1lcmljUGF0dGVybjtcclxuICAgICAgbGV0IGZpbHRlcmVkVmFsdWUgPSBvcmlnaW5hbFZhbHVlLnJlcGxhY2VBbGwoYWxwaGFudW1lcmljUGF0dGVybiwgJycpO1xyXG5cclxuICAgICAgLy8gUHJldmVudCBsZWFkaW5nIHNwYWNlc1xyXG4gICAgICBpZiAoZmlsdGVyZWRWYWx1ZS5zdGFydHNXaXRoKCcgJykpIHtcclxuICAgICAgICBmaWx0ZXJlZFZhbHVlID0gZmlsdGVyZWRWYWx1ZS50cmltU3RhcnQoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUmVwbGFjZSBtdWx0aXBsZSBjb25zZWN1dGl2ZSBzcGFjZXMgd2l0aCBzaW5nbGUgc3BhY2VcclxuICAgICAgZmlsdGVyZWRWYWx1ZSA9IGZpbHRlcmVkVmFsdWUucmVwbGFjZUFsbCgvXFxzezIsfS9nLCAnICcpO1xyXG5cclxuICAgICAgaWYgKG9yaWdpbmFsVmFsdWUgIT09IGZpbHRlcmVkVmFsdWUpIHtcclxuICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiBjaGFyYWN0ZXJzIHJlbW92ZWQgYmVmb3JlIHRoZSBjdXJzb3IgcG9zaXRpb25cclxuICAgICAgICBjb25zdCBjaGFyc1JlbW92ZWRCZWZvcmVDdXJzb3IgPSBvcmlnaW5hbFZhbHVlLmxlbmd0aCAtIGZpbHRlcmVkVmFsdWUubGVuZ3RoO1xyXG4gICAgICAgIGVsZW1lbnQudmFsdWUgPSBmaWx0ZXJlZFZhbHVlO1xyXG4gICAgICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZShmaWx0ZXJlZFZhbHVlLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICAgICAgLy8gUmVzdG9yZSBjdXJzb3IgcG9zaXRpb24gLSBhY2NvdW50IGZvciByZW1vdmVkIGNoYXJhY3RlcnNcclxuICAgICAgICBjb25zdCBuZXdDdXJzb3JQb3MgPSBNYXRoLm1heCgwLCAoY3Vyc29yUG9zaXRpb24gfHwgMCkgLSBjaGFyc1JlbW92ZWRCZWZvcmVDdXJzb3IpO1xyXG4gICAgICAgIGVsZW1lbnQuc2V0U2VsZWN0aW9uUmFuZ2UobmV3Q3Vyc29yUG9zLCBuZXdDdXJzb3JQb3MpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBpbmNyZWFzZSBoZWlnaHRcclxuICAgICAgdGhpcy5hdXRvUmVzaXplSW5pdGlhbCgpO1xyXG4gICAgICB0aGlzLnZhbHVlQ2hhbmdlLmVtaXQoeyBuYW1lOiB0aGlzLmZpZWxkLm5hbWUsIHZhbHVlOiBmaWx0ZXJlZFZhbHVlIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGV0IGZpbHRlcmVkVmFsdWUgPSBvcmlnaW5hbFZhbHVlO1xyXG5cclxuICAgICAgLy8gU3RyaWN0IGZpbHRlcmluZyBpZiAhaXNBbHBoYW51bWVyaWNcclxuICAgICAgaWYgKCF0aGlzLmlzQWxwaGFudW1lcmljKSB7XHJcbiAgICAgICAgY29uc29sZS5sb2coJ2lzQWxwaGFudW1lcmljJywgdGhpcy5pc0FscGhhbnVtZXJpYyk7XHJcblxyXG4gICAgICAgIGNvbnN0IGFsbG93ZWRQYXR0ZXJuID0gL1teYS16QS1aMC05XFxzKCl7fVtcXF07LC5cIj0nK1xcLSovPD4hJnwlX0AkPzpdL2c7XHJcbiAgICAgICAgZmlsdGVyZWRWYWx1ZSA9IGZpbHRlcmVkVmFsdWUucmVwbGFjZUFsbChhbGxvd2VkUGF0dGVybiwgJycpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBQcmV2ZW50IGxlYWRpbmcgc3BhY2VzXHJcbiAgICAgIGlmIChmaWx0ZXJlZFZhbHVlLnN0YXJ0c1dpdGgoJyAnKSkge1xyXG4gICAgICAgIGZpbHRlcmVkVmFsdWUgPSBmaWx0ZXJlZFZhbHVlLnRyaW1TdGFydCgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBSZXBsYWNlIG11bHRpcGxlIGNvbnNlY3V0aXZlIHNwYWNlcyB3aXRoIHNpbmdsZSBzcGFjZVxyXG4gICAgICBmaWx0ZXJlZFZhbHVlID0gZmlsdGVyZWRWYWx1ZS5yZXBsYWNlQWxsKC9cXHN7Mix9L2csICcgJyk7XHJcblxyXG4gICAgICBpZiAob3JpZ2luYWxWYWx1ZSAhPT0gZmlsdGVyZWRWYWx1ZSkge1xyXG4gICAgICAgIC8vIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIGNoYXJhY3RlcnMgcmVtb3ZlZCBiZWZvcmUgdGhlIGN1cnNvciBwb3NpdGlvblxyXG4gICAgICAgIGNvbnN0IGNoYXJzUmVtb3ZlZEJlZm9yZUN1cnNvciA9IG9yaWdpbmFsVmFsdWUubGVuZ3RoIC0gZmlsdGVyZWRWYWx1ZS5sZW5ndGg7XHJcbiAgICAgICAgZWxlbWVudC52YWx1ZSA9IGZpbHRlcmVkVmFsdWU7XHJcbiAgICAgICAgdGhpcy5jb250cm9sLnNldFZhbHVlKGZpbHRlcmVkVmFsdWUsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcclxuICAgICAgICAvLyBSZXN0b3JlIGN1cnNvciBwb3NpdGlvbiAtIGFjY291bnQgZm9yIHJlbW92ZWQgY2hhcmFjdGVyc1xyXG4gICAgICAgIGNvbnN0IG5ld0N1cnNvclBvcyA9IE1hdGgubWF4KDAsIChjdXJzb3JQb3NpdGlvbiB8fCAwKSAtIGNoYXJzUmVtb3ZlZEJlZm9yZUN1cnNvcik7XHJcbiAgICAgICAgZWxlbWVudC5zZXRTZWxlY3Rpb25SYW5nZShuZXdDdXJzb3JQb3MsIG5ld0N1cnNvclBvcyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGluY3JlYXNlIGhlaWdodFxyXG4gICAgICB0aGlzLmF1dG9SZXNpemVJbml0aWFsKCk7XHJcbiAgICAgIHRoaXMudmFsdWVDaGFuZ2UuZW1pdCh7IG5hbWU6IHRoaXMuZmllbGQubmFtZSwgdmFsdWU6IGZpbHRlcmVkVmFsdWUgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5jb250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuICB9XHJcblxyXG4gIHRvZ2dsZVBhc3N3b3JkVmlzaWJpbGl0eSgpOiB2b2lkIHtcclxuICAgIHRoaXMuc2hvd1Bhc3N3b3JkID0gIXRoaXMuc2hvd1Bhc3N3b3JkO1xyXG4gICAgdGhpcy51cGRhdGVBbGxJY29ucygpO1xyXG4gIH1cclxuXHJcbiAgaGFuZGxlSW5wdXQoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XHJcbiAgICBjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudDtcclxuICAgIGNvbnN0IGN1cnNvclBvc2l0aW9uID0gdGFyZ2V0LnNlbGVjdGlvblN0YXJ0O1xyXG4gICAgY29uc3Qgb3JpZ2luYWxWYWx1ZSA9IHRhcmdldC52YWx1ZTtcclxuXHJcbiAgICBsZXQgZmlsdGVyZWRWYWx1ZSA9IG9yaWdpbmFsVmFsdWU7XHJcblxyXG4gICAgLy8gSUYgTk9UIGFscGhhbnVtZXJpYywgdXNlciB3YW50cyBzdHJpY3QgZmlsdGVyaW5nOlxyXG4gICAgLy8gXCJvbmx5IGFjY2VwdCB0aWhzLikge30gW10gOyAsIC4gXCIgJyA9ICsgLSAqIC8gPCA+ICEgJiB8ICUgJl8oICktLy47QCEsICQlIDogZG9udCBhbGxvdyBlbW9qaVwiXHJcbiAgICAvLyBJbnRlcnByZXRhdGlvbjogQWxsb3cgYWxwaGFudW1lcmljICsgc3BlY2lmaWVkIHNwZWNpYWwgY2hhcnMuIEJhbiBlbW9qaXMuXHJcbiAgICAvLyBBY3R1YWxseSwgdGhlIHVzZXIgc2FpZDogXCJpZiBpc0FscGhhbnVtZXJpYyBmYWxzZSBvbmx5IGFjY2VwdC4uLlwiXHJcbiAgICAvLyBTbyBpZiBpc0FscGhhbnVtZXJpYyBpcyBUUlVFLCB3ZSB1c2UgdGhlIGV4aXN0aW5nIGhhbmRsZUFscGhhbnVtZXJpY0lucHV0IGxvZ2ljIChvciBzaW1pbGFyKS5cclxuICAgIC8vIFRoZSBjdXJyZW50IGxvZ2ljIGluIGhhbmRsZUlucHV0IGlzIGdlbmVyaWMuXHJcbiAgICAvLyBUaGUgZXhpc3RpbmcgY29kZSBoYXMgYSBzZXBhcmF0ZSBgaGFuZGxlQWxwaGFudW1lcmljSW5wdXRgIG1ldGhvZCBidXQgaXQncyBub3QgY2FsbGVkIGhlcmU/XHJcbiAgICAvLyBXYWl0LCB0aGUgdGVtcGxhdGUgbGlrZWx5IGNhbGxzIGBoYW5kbGVBbHBoYW51bWVyaWNJbnB1dGAgaWYgYGlzQWxwaGFudW1lcmljYCBpcyB0cnVlLCBvciBgaGFuZGxlSW5wdXRgIG90aGVyd2lzZT9cclxuICAgIC8vIExldCdzIGNoZWNrIHRoZSB0ZW1wbGF0ZS5cclxuICAgIC8vIEJVVCBhc3N1bWluZyBgaGFuZGxlSW5wdXRgIGlzIHRoZSBnZW5lcmljIGhhbmRsZXI6XHJcblxyXG4gICAgaWYgKCF0aGlzLmlzQWxwaGFudW1lcmljKSB7XHJcbiAgICAgIC8vIFJlZ2V4IHRvIGFsbG93OiBhLXosIEEtWiwgMC05LCBhbmQ6ICkge30gW10gOyAsIC4gXCIgJyA9ICsgLSAqIC8gPCA+ICEgJiB8ICUgXyAoIC0gQCAkID8gOlxyXG4gICAgICAvLyBOb3RlOiBVc2VyIGxpc3Q6ICkge30gW10gOyAsIC4gXCIgJyA9ICsgLSAqIC8gPCA+ICEgJiB8ICUgJl8oICktLy47QCEsICQlXHJcbiAgICAgIC8vIENvbWJpbmVkIHVuaXF1ZSBzcGVjaWFsIGNoYXJzOiApIHsgfSBbIF0gOyAsIC4gXCIgJyA9ICsgLSAqIC8gPCA+ICEgJiB8ICUgXyAoIEAgJCA/IDpcclxuICAgICAgLy8gQWxzbyBzcGFjZSBpcyBpbXBsaWVkPyB1c3VhbGx5IHllcy5cclxuICAgICAgLy8gQW5kIE5PIEVNT0pJUy5cclxuICAgICAgLy8gZWFzaWVyIHRvIGp1c3QgcmVwbGFjZSBhbnl0aGluZyBOT1QgaW4gdGhlIGFsbG93ZWQgc2V0LlxyXG5cclxuICAgICAgLy8gQWxsb3dlZCBjaGFycyByZWdleCBwYXR0ZXJuOlxyXG4gICAgICAvLyBBLVphLXowLTlcclxuICAgICAgLy8gU3BhY2U6IFxcc1xyXG4gICAgICAvLyBTcGVjaWFsOiAoKXt9W1xcXTssLlwiPScrXFwtKi88PiEmfCVfQCQ/OlxyXG4gICAgICAvLyBOb3RlOiAtIGluc2lkZSBbXSBuZWVkcyB0byBiZSBlc2NhcGVkIG9yIGF0IGVuZC4gXSBuZWVkcyBlc2NhcGUuIFxcIG5lZWRzIGVzY2FwZT8gKG5vdCBpbiBsaXN0KS5cclxuICAgICAgLy8gVXNlciBsaXN0IGhhczogYC5gIGBcImAgYCdgIGA/YCAod2FpdCwgPyBub3QgaW4gbGlzdD8pXHJcbiAgICAgIC8vIFVzZXIgbGlzdDogYCkge30gW10gOyAsIC4gXCIgJyA9ICsgLSAqIC8gPCA+ICEgJiB8ICUgJl8oICktLy47QCEsICQlYFxyXG4gICAgICAvLyBVbmlxdWVzOiApIHsgfSBbIF0gOyAsIC4gXCIgJyA9ICsgLSAqIC8gPCA+ICEgJiB8ICUgXyAoIEAgJFxyXG4gICAgICAvLyAoVGhlIGAmYCBpcyByZXBlYXRlZCwgYC5gIHJlcGVhdGVkLCBgLGAgcmVwZWF0ZWQgZXRjLilcclxuICAgICAgLy8gSSB3aWxsIGNyZWF0ZSBhIHJlZ2V4IHRoYXQgbWF0Y2hlcyBhbnl0aGluZyBOT1QgaW4gdGhpcyBsaXN0IGFuZCByZXBsYWNlIHdpdGggZW1wdHkgc3RyaW5nLlxyXG5cclxuICAgICAgLy8gW15hLXpBLVowLTlcXHMoKXt9W1xcXTssLlwiPScrXFwtKi88PiEmfCVfQCRdXHJcbiAgICAgIC8vIE5vdGU6IGAqYCwgYCtgLCBgP2AgZXRjIG5lZWQgZXNjYXBpbmcgaW4gcmVnZXggaWYgb3V0c2lkZSBbXSwgYnV0IGluc2lkZSBbXSB0aGV5IGFyZSBsaXRlcmFscyBtb3N0bHkuXHJcbiAgICAgIC8vIGAtYCBuZWVkcyB0byBiZSBsYXN0IG9yIGVzY2FwZWQuIGBdYCBuZWVkcyBlc2NhcGUuIGBeYCBuZWVkcyBlc2NhcGUgaWYgZmlyc3Q/IE5vLCBpbnZhbGlkIGhlcmUuXHJcbiAgICAgIC8vIExldCdzIHZlcmlmeSB2YWxpZCBjaGFyczpcclxuICAgICAgLy8gYS16IEEtWiAwLTlcclxuICAgICAgLy8gc3BhY2VcclxuICAgICAgLy8gKSB7IH0gWyBdIDsgLCAuIFwiICcgPSArIC0gKiAvIDwgPiAhICYgfCAlIF8gKCBAICQgOlxyXG5cclxuICAgICAgY29uc3QgYWxsb3dlZFBhdHRlcm4gPSAvW15hLXpBLVowLTlcXHMoKXt9W1xcXTssLlwiPScrXFwtKi88PiEmfCVfQCQ/Ol0vZztcclxuICAgICAgZmlsdGVyZWRWYWx1ZSA9IGZpbHRlcmVkVmFsdWUucmVwbGFjZUFsbChhbGxvd2VkUGF0dGVybiwgJycpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFByZXZlbnQgbGVhZGluZyBzcGFjZXNcclxuICAgIGlmIChmaWx0ZXJlZFZhbHVlLnN0YXJ0c1dpdGgoJyAnKSkge1xyXG4gICAgICBmaWx0ZXJlZFZhbHVlID0gZmlsdGVyZWRWYWx1ZS50cmltU3RhcnQoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyByZXBsYWNlQWxsIG11bHRpcGxlIGNvbnNlY3V0aXZlIHNwYWNlcyB3aXRoIHNpbmdsZSBzcGFjZVxyXG4gICAgZmlsdGVyZWRWYWx1ZSA9IGZpbHRlcmVkVmFsdWUucmVwbGFjZUFsbCgvXFxzezIsfS9nLCAnICcpO1xyXG5cclxuICAgIGlmIChvcmlnaW5hbFZhbHVlICE9PSBmaWx0ZXJlZFZhbHVlKSB7XHJcbiAgICAgIC8vIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIGNoYXJhY3RlcnMgcmVtb3ZlZCBiZWZvcmUgdGhlIGN1cnNvciBwb3NpdGlvblxyXG4gICAgICBjb25zdCBjaGFyc1JlbW92ZWRCZWZvcmVDdXJzb3IgPSBvcmlnaW5hbFZhbHVlLmxlbmd0aCAtIGZpbHRlcmVkVmFsdWUubGVuZ3RoO1xyXG4gICAgICB0YXJnZXQudmFsdWUgPSBmaWx0ZXJlZFZhbHVlO1xyXG4gICAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUoZmlsdGVyZWRWYWx1ZSwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG4gICAgICAvLyBSZXN0b3JlIGN1cnNvciBwb3NpdGlvbiAtIGFjY291bnQgZm9yIHJlbW92ZWQgY2hhcmFjdGVyc1xyXG4gICAgICBjb25zdCBuZXdDdXJzb3JQb3MgPSBNYXRoLm1heCgwLCAoY3Vyc29yUG9zaXRpb24gfHwgMCkgLSBjaGFyc1JlbW92ZWRCZWZvcmVDdXJzb3IpO1xyXG4gICAgICB0YXJnZXQuc2V0U2VsZWN0aW9uUmFuZ2UobmV3Q3Vyc29yUG9zLCBuZXdDdXJzb3JQb3MpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRyYWlsaW5nIHNwYWNlcyB3aWxsIGJlIHRyaW1tZWQgb24gYmx1ciwgbm90IGR1cmluZyBpbnB1dFxyXG4gICAgaWYgKHRoaXMuZmllbGQudHlwZSA9PT0gJ3Bhc3N3b3JkJyAmJiB0aGlzLmZpZWxkLmZlZWRiYWNrKSB7XHJcbiAgICAgIHRoaXMuY2hlY2tQYXNzd29yZFN0cmVuZ3RoKGZpbHRlcmVkVmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMudmFsdWVDaGFuZ2UuZW1pdCh7IG5hbWU6IHRoaXMuZmllbGQubmFtZSwgdmFsdWU6IGZpbHRlcmVkVmFsdWUgfSk7XHJcbiAgICB0aGlzLmNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIGFscGhhbnVtZXJpYyBpbnB1dCAtIGFsbG93cyBvbmx5IGxldHRlcnMsIG51bWJlcnMsIGFuZCBzcGVjaWZpYyBzcGVjaWFsIGNoYXJhY3RlcnNcclxuICAgKiBBbGxvd2VkOiBBLVosIGEteiwgMC05LCBzcGFjZSwgaHlwaGVuLCB1bmRlcnNjb3JlLCBhbXBlcnNhbmQsIGFuZCBwYXJlbnRoZXNlc1xyXG4gICAqIEFsc28gcHJldmVudHMgbGVhZGluZyBzcGFjZXMgYW5kIG11bHRpcGxlIGNvbnNlY3V0aXZlIHNwYWNlc1xyXG4gICAqL1xyXG4gIGhhbmRsZUFscGhhbnVtZXJpY0lucHV0KGV2ZW50OiBFdmVudCk6IHZvaWQge1xyXG4gICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgICBjb25zdCBjdXJzb3JQb3NpdGlvbiA9IHRhcmdldC5zZWxlY3Rpb25TdGFydDtcclxuICAgIGNvbnN0IG9yaWdpbmFsVmFsdWUgPSB0YXJnZXQudmFsdWU7XHJcblxyXG4gICAgLy8gT25seSBhbGxvdyBjaGFyYWN0ZXJzIGJhc2VkIG9uIHRoZSBzZWxlY3RlZCBwYXR0ZXJuXHJcbiAgICBjb25zdCBhbHBoYW51bWVyaWNQYXR0ZXJuID0gdGhpcy5hbHBoYW51bWVyaWNQYXR0ZXJuO1xyXG4gICAgbGV0IGZpbHRlcmVkVmFsdWUgPSBvcmlnaW5hbFZhbHVlLnJlcGxhY2VBbGwoYWxwaGFudW1lcmljUGF0dGVybiwgJycpO1xyXG5cclxuICAgIC8vIFByZXZlbnQgbGVhZGluZyBzcGFjZXNcclxuICAgIGlmIChmaWx0ZXJlZFZhbHVlLnN0YXJ0c1dpdGgoJyAnKSkge1xyXG4gICAgICBmaWx0ZXJlZFZhbHVlID0gZmlsdGVyZWRWYWx1ZS50cmltU3RhcnQoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXBsYWNlIG11bHRpcGxlIGNvbnNlY3V0aXZlIHNwYWNlcyB3aXRoIHNpbmdsZSBzcGFjZVxyXG4gICAgZmlsdGVyZWRWYWx1ZSA9IGZpbHRlcmVkVmFsdWUucmVwbGFjZUFsbCgvXFxzezIsfS9nLCAnICcpO1xyXG5cclxuICAgIGlmIChvcmlnaW5hbFZhbHVlICE9PSBmaWx0ZXJlZFZhbHVlKSB7XHJcbiAgICAgIC8vIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIGNoYXJhY3RlcnMgcmVtb3ZlZCBiZWZvcmUgdGhlIGN1cnNvciBwb3NpdGlvblxyXG4gICAgICBjb25zdCBjaGFyc1JlbW92ZWRCZWZvcmVDdXJzb3IgPSBvcmlnaW5hbFZhbHVlLmxlbmd0aCAtIGZpbHRlcmVkVmFsdWUubGVuZ3RoO1xyXG4gICAgICB0YXJnZXQudmFsdWUgPSBmaWx0ZXJlZFZhbHVlO1xyXG4gICAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUoZmlsdGVyZWRWYWx1ZSwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG4gICAgICAvLyBSZXN0b3JlIGN1cnNvciBwb3NpdGlvbiAtIGFjY291bnQgZm9yIHJlbW92ZWQgY2hhcmFjdGVyc1xyXG4gICAgICBjb25zdCBuZXdDdXJzb3JQb3MgPSBNYXRoLm1heCgwLCAoY3Vyc29yUG9zaXRpb24gfHwgMCkgLSBjaGFyc1JlbW92ZWRCZWZvcmVDdXJzb3IpO1xyXG4gICAgICB0YXJnZXQuc2V0U2VsZWN0aW9uUmFuZ2UobmV3Q3Vyc29yUG9zLCBuZXdDdXJzb3JQb3MpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLmZpZWxkLnR5cGUgPT09ICdwYXNzd29yZCcgJiYgdGhpcy5maWVsZC5mZWVkYmFjaykge1xyXG4gICAgICB0aGlzLmNoZWNrUGFzc3dvcmRTdHJlbmd0aChmaWx0ZXJlZFZhbHVlKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnZhbHVlQ2hhbmdlLmVtaXQoeyBuYW1lOiB0aGlzLmZpZWxkLm5hbWUsIHZhbHVlOiBmaWx0ZXJlZFZhbHVlIH0pO1xyXG4gICAgdGhpcy5jb250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuICB9XHJcblxyXG4gIGhhbmRsZUJsdXIoZTogRXZlbnQsIG1heERlY2ltYWxzOiBudW1iZXIgPSAyKTogdm9pZCB7XHJcbiAgICB0aGlzLmhhc0ZvY3VzLnNldChmYWxzZSk7XHJcbiAgICBjb25zdCB0YXJnZXQgPSBlLnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50IHwgSFRNTFRleHRBcmVhRWxlbWVudDtcclxuICAgIGNvbnN0IGNsZWFuVmFsdWVTdHJpbmcgPSB0YXJnZXQudmFsdWU7XHJcblxyXG4gICAgaWYgKCFjbGVhblZhbHVlU3RyaW5nKSB7XHJcbiAgICAgIHRoaXMuZmllbGRCbHVyLmVtaXQoeyBuYW1lOiB0aGlzLmZpZWxkLm5hbWUsIHZhbHVlOiAnJyB9KTtcclxuICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVsZWdhdGUgdG8gdHlwZS1zcGVjaWZpYyBoYW5kbGVyc1xyXG4gICAgaWYgKHRoaXMuZmllbGQudHlwZSA9PT0gJ3RleHQnIHx8IHRoaXMuZmllbGQudHlwZSA9PT0gJ3RleHRhcmVhJykge1xyXG4gICAgICB0aGlzLmhhbmRsZVRleHRGaWVsZEJsdXIodGFyZ2V0LCBjbGVhblZhbHVlU3RyaW5nKTtcclxuICAgIH0gZWxzZSBpZiAodGhpcy5maWVsZC50eXBlID09PSAnbnVtYmVyJykge1xyXG4gICAgICB0aGlzLmhhbmRsZU51bWJlckZpZWxkQmx1cih0YXJnZXQsIGNsZWFuVmFsdWVTdHJpbmcsIG1heERlY2ltYWxzKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBFbWl0IGZpbmFsIHZhbHVlXHJcbiAgICB0aGlzLmZpZWxkQmx1ci5lbWl0KHtcclxuICAgICAgbmFtZTogdGhpcy5maWVsZC5uYW1lLFxyXG4gICAgICB2YWx1ZTogdGFyZ2V0LnZhbHVlLFxyXG4gICAgfSk7XHJcbiAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIYW5kbGUgYmx1ciBmb3IgdGV4dCBhbmQgdGV4dGFyZWEgZmllbGRzIC0gdHJpbSB0cmFpbGluZyBzcGFjZXNcclxuICAgKi9cclxuICBwcml2YXRlIGhhbmRsZVRleHRGaWVsZEJsdXIoXHJcbiAgICB0YXJnZXQ6IEhUTUxJbnB1dEVsZW1lbnQgfCBIVE1MVGV4dEFyZWFFbGVtZW50LFxyXG4gICAgY2xlYW5WYWx1ZVN0cmluZzogc3RyaW5nLFxyXG4gICk6IHZvaWQge1xyXG4gICAgY29uc3QgdHJpbW1lZCA9IGNsZWFuVmFsdWVTdHJpbmcudHJpbSgpO1xyXG4gICAgaWYgKGNsZWFuVmFsdWVTdHJpbmcgIT09IHRyaW1tZWQpIHtcclxuICAgICAgdGFyZ2V0LnZhbHVlID0gdHJpbW1lZDtcclxuICAgICAgdGhpcy5jb250cm9sLnNldFZhbHVlKHRyaW1tZWQsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZSBibHVyIGZvciBudW1iZXIgZmllbGRzIC0gdmFsaWRhdGUgYW5kIGZvcm1hdFxyXG4gICAqL1xyXG4gIHByaXZhdGUgaGFuZGxlTnVtYmVyRmllbGRCbHVyKFxyXG4gICAgdGFyZ2V0OiBIVE1MSW5wdXRFbGVtZW50IHwgSFRNTFRleHRBcmVhRWxlbWVudCxcclxuICAgIGNsZWFuVmFsdWVTdHJpbmc6IHN0cmluZyxcclxuICAgIG1heERlY2ltYWxzOiBudW1iZXIsXHJcbiAgKTogdm9pZCB7XHJcbiAgICAvLyBSZW1vdmUgY29tbWFzIGZvciBwYXJzaW5nL3ZhbGlkYXRpb25cclxuICAgIGNvbnN0IG51bVN0cmluZyA9IGNsZWFuVmFsdWVTdHJpbmcucmVwbGFjZUFsbCgnLCcsICcnKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgc3RyaW5nIGlzIGEgdmFsaWQgbnVtYmVyIGZvcm1hdFxyXG4gICAgY29uc3QgaXNWYWxpZE51bWJlckZvcm1hdCA9IC9eLT9cXGQrKFxcLlxcZCspPyQvLnRlc3QobnVtU3RyaW5nKTtcclxuXHJcbiAgICAvLyBJZiBub3QgYSB2YWxpZCBudW1iZXIgZm9ybWF0LCBjbGVhciB0aGUgZmllbGRcclxuICAgIGlmICghaXNWYWxpZE51bWJlckZvcm1hdCkge1xyXG4gICAgICB0YXJnZXQudmFsdWUgPSAnJztcclxuICAgICAgdGhpcy5jb250cm9sLnNldFZhbHVlKCcnKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEZvcm1hdCBjdXJyZW5jeSBmaWVsZHMgb3Igc2V0IHJhdyB2YWx1ZSBmb3Igbm9uLWN1cnJlbmN5XHJcbiAgICBpZiAodGhpcy5maWVsZC50eXBlID09PSAnbnVtYmVyJyAmJiB0aGlzLmZpZWxkLmlzQ3VycmVuY3kpIHtcclxuICAgICAgdGhpcy5wcm9jZXNzQ3VycmVuY3lWYWx1ZSh0YXJnZXQsIG51bVN0cmluZywgbWF4RGVjaW1hbHMpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gTm9uLWN1cnJlbmN5OiBwcmVzZXJ2ZSB0aGUgcmF3IHN0cmluZyB2YWx1ZVxyXG4gICAgICB0YXJnZXQudmFsdWUgPSBudW1TdHJpbmc7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBQcm9jZXNzIGN1cnJlbmN5IHZhbHVlIC0gaGFuZGxlIGZvcm1hdHRpbmcgYW5kIGRlY2ltYWwgcGxhY2VzXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBwcm9jZXNzQ3VycmVuY3lWYWx1ZShcclxuICAgIHRhcmdldDogSFRNTElucHV0RWxlbWVudCB8IEhUTUxUZXh0QXJlYUVsZW1lbnQsXHJcbiAgICBudW1TdHJpbmc6IHN0cmluZyxcclxuICAgIG1heERlY2ltYWxzOiBudW1iZXIsXHJcbiAgKTogdm9pZCB7XHJcbiAgICAvLyBIYW5kbGUgbmVnYXRpdmUgdmFsdWVzIC0gY29udmVydCB0byBwb3NpdGl2ZVxyXG4gICAgbGV0IHByb2Nlc3NlZFZhbHVlID0gbnVtU3RyaW5nLnN0YXJ0c1dpdGgoJy0nKSA/IG51bVN0cmluZy5zdWJzdHJpbmcoMSkgOiBudW1TdHJpbmc7XHJcblxyXG4gICAgLy8gSGFuZGxlIGVkZ2UgY2FzZSBvZiBcIi0wXCIgb3IganVzdCBcIi1cIlxyXG4gICAgaWYgKHByb2Nlc3NlZFZhbHVlID09PSAnJyB8fCBwcm9jZXNzZWRWYWx1ZSA9PT0gJzAnKSB7XHJcbiAgICAgIHByb2Nlc3NlZFZhbHVlID0gJzAnO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEZvcm1hdCB0aGUgdmFsdWUgd2l0aCBwcm9wZXIgZGVjaW1hbCBwbGFjZXNcclxuICAgIGNvbnN0IGNsZWFuVmFsdWVTdHJpbmcgPSB0aGlzLmZvcm1hdERlY2ltYWxQbGFjZXMocHJvY2Vzc2VkVmFsdWUsIG1heERlY2ltYWxzKTtcclxuXHJcbiAgICBjb25zdCBmb3JtYXR0ZWRWYWx1ZSA9IHRoaXMuZm9ybWF0Q3VycmVuY3lXaXRoQ29tbWFzKGNsZWFuVmFsdWVTdHJpbmcsIG1heERlY2ltYWxzKTtcclxuXHJcbiAgICAvLyBVcGRhdGUgdGhlIGNvbnRyb2wgdmFsdWUgd2l0aCB0aGUgbnVtZXJpYyBzdHJpbmcgKG5vdCBmb3JtYXR0ZWQpXHJcbiAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUoY2xlYW5WYWx1ZVN0cmluZywgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG5cclxuICAgIC8vIFRyaWdnZXIgdmFsaWRhdG9ycyBhbmQgbWFyayBhcyB0b3VjaGVkXHJcbiAgICB0aGlzLmNvbnRyb2wudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpO1xyXG4gICAgdGhpcy5jb250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuXHJcbiAgICAvLyBTZXQgZGlzcGxheSB2YWx1ZSB3aXRoIGNvbW1hcyBhZnRlciBBbmd1bGFyJ3MgZm9ybSBjb250cm9sIHVwZGF0ZVxyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIHRhcmdldC52YWx1ZSA9IGZvcm1hdHRlZFZhbHVlO1xyXG4gICAgfSwgMCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGb3JtYXQgZGVjaW1hbCBwbGFjZXMgLSBwYWQgb3IgdHJ1bmNhdGUgdG8gbWF4RGVjaW1hbHNcclxuICAgKi9cclxuICBwcml2YXRlIGZvcm1hdERlY2ltYWxQbGFjZXModmFsdWU6IHN0cmluZywgbWF4RGVjaW1hbHM6IG51bWJlcik6IHN0cmluZyB7XHJcbiAgICBsZXQgW2ludFBhcnQsIGRlY1BhcnRdID0gdmFsdWUuaW5jbHVkZXMoJy4nKSA/IHZhbHVlLnNwbGl0KCcuJykgOiBbdmFsdWUsICcnXTtcclxuXHJcbiAgICAvLyBQYWQgb3IgdHJ1bmNhdGUgZGVjaW1hbCBwYXJ0IHRvIG1heERlY2ltYWxzXHJcbiAgICBpZiAoZGVjUGFydC5sZW5ndGggPCBtYXhEZWNpbWFscykge1xyXG4gICAgICBkZWNQYXJ0ID0gZGVjUGFydC5wYWRFbmQobWF4RGVjaW1hbHMsICcwJyk7XHJcbiAgICB9IGVsc2UgaWYgKGRlY1BhcnQubGVuZ3RoID4gbWF4RGVjaW1hbHMpIHtcclxuICAgICAgZGVjUGFydCA9IGRlY1BhcnQuc2xpY2UoMCwgbWF4RGVjaW1hbHMpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEJ1aWxkIHRoZSBjbGVhbiB2YWx1ZSBzdHJpbmcgKHdpdGhvdXQgY29tbWFzKVxyXG4gICAgcmV0dXJuIG1heERlY2ltYWxzID4gMCA/IGAke2ludFBhcnR9LiR7ZGVjUGFydH1gIDogaW50UGFydDtcclxuICB9XHJcblxyXG4gIGhhbmRsZU51bWJlcklucHV0KGV2ZW50OiBFdmVudCwgbWF4RGVjaW1hbHM6IG51bWJlciA9IDIpOiB2b2lkIHtcclxuICAgIGNvbnN0IHRhcmdldCA9IGV2ZW50LnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgY29uc3Qgb3JpZ2luYWxWYWx1ZSA9IHRhcmdldC52YWx1ZTtcclxuICAgIGNvbnN0IGN1cnNvclBvc2l0aW9uID0gdGFyZ2V0LnNlbGVjdGlvblN0YXJ0ID8/IDA7XHJcblxyXG4gICAgLy8gU3RlcCAxOiBGaWx0ZXIgYW5kIGZvcm1hdCB0aGUgaW5wdXQgdmFsdWVcclxuICAgIGxldCB2YWx1ZSA9IHRoaXMuZmlsdGVyTnVtZXJpY0lucHV0KHRhcmdldC52YWx1ZSwgbWF4RGVjaW1hbHMpO1xyXG5cclxuICAgIC8vIFN0ZXAgMjogVXBkYXRlIGN1cnNvciBwb3NpdGlvbiBpZiB2YWx1ZSBjaGFuZ2VkXHJcbiAgICB0aGlzLnVwZGF0ZUN1cnNvclBvc2l0aW9uQWZ0ZXJGaWx0ZXIodGFyZ2V0LCBvcmlnaW5hbFZhbHVlLCB2YWx1ZSwgY3Vyc29yUG9zaXRpb24pO1xyXG5cclxuICAgIC8vIFN0ZXAgMzogVXBkYXRlIGZvcm0gY29udHJvbCBhbmQgdmFsaWRhdGVcclxuICAgIHRoaXMudXBkYXRlRm9ybUNvbnRyb2xWYWx1ZSh2YWx1ZSwgbWF4RGVjaW1hbHMpO1xyXG5cclxuICAgIC8vIFN0ZXAgNDogRW1pdCBjaGFuZ2VzXHJcbiAgICB0aGlzLnZhbHVlQ2hhbmdlLmVtaXQoeyBuYW1lOiB0aGlzLmZpZWxkLm5hbWUsIHZhbHVlOiB0YXJnZXQudmFsdWUgfSk7XHJcbiAgICB0aGlzLmNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRmlsdGVyIG51bWVyaWMgaW5wdXQgdG8gb25seSBhbGxvdyBkaWdpdHMgYW5kIGRlY2ltYWwgcG9pbnRcclxuICAgKiBFbnN1cmVzIG9ubHkgb25lIGRlY2ltYWwgcG9pbnQgYW5kIGVuZm9yY2VzIG1heCBkZWNpbWFsIHBsYWNlc1xyXG4gICAqL1xyXG4gIHByaXZhdGUgZmlsdGVyTnVtZXJpY0lucHV0KHZhbHVlOiBzdHJpbmcsIG1heERlY2ltYWxzOiBudW1iZXIpOiBzdHJpbmcge1xyXG4gICAgLy8gUmVtb3ZlIEFMTCBub24tbnVtZXJpYyBjaGFyYWN0ZXJzIGV4Y2VwdCBkZWNpbWFsIHBvaW50XHJcbiAgICBsZXQgZmlsdGVyZWQgPSB2YWx1ZS5yZXBsYWNlQWxsKC9bXjAtOS5dL2csICcnKTtcclxuXHJcbiAgICAvLyBFbnN1cmUgb25seSBvbmUgZGVjaW1hbCBwb2ludFxyXG4gICAgZmlsdGVyZWQgPSB0aGlzLmZpbHRlckRlY2ltYWxQb2ludHMoZmlsdGVyZWQpO1xyXG5cclxuICAgIC8vIFJlc3RyaWN0IHRvIG1heERlY2ltYWxzIGRlY2ltYWwgcGxhY2VzIGlmIGRlY2ltYWwgZXhpc3RzXHJcbiAgICBmaWx0ZXJlZCA9IHRoaXMuZW5mb3JjZURlY2ltYWxMaW1pdChmaWx0ZXJlZCwgbWF4RGVjaW1hbHMpO1xyXG5cclxuICAgIHJldHVybiBmaWx0ZXJlZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVuc3VyZSBvbmx5IG9uZSBkZWNpbWFsIHBvaW50IGV4aXN0cyBpbiB0aGUgdmFsdWVcclxuICAgKi9cclxuICBwcml2YXRlIGZpbHRlckRlY2ltYWxQb2ludHModmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBwYXJ0cyA9IHZhbHVlLnNwbGl0KCcuJyk7XHJcbiAgICBpZiAocGFydHMubGVuZ3RoID4gMikge1xyXG4gICAgICByZXR1cm4gcGFydHNbMF0gKyAnLicgKyBwYXJ0cy5zbGljZSgxKS5qb2luKCcnKTtcclxuICAgIH1cclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVuZm9yY2UgbWF4aW11bSBkZWNpbWFsIHBsYWNlcyBsaW1pdFxyXG4gICAqL1xyXG4gIHByaXZhdGUgZW5mb3JjZURlY2ltYWxMaW1pdCh2YWx1ZTogc3RyaW5nLCBtYXhEZWNpbWFsczogbnVtYmVyKTogc3RyaW5nIHtcclxuICAgIGlmICghdmFsdWUuaW5jbHVkZXMoJy4nKSkge1xyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgW2ludGVnZXJQYXJ0LCBkZWNpbWFsUGFydF0gPSB2YWx1ZS5zcGxpdCgnLicpO1xyXG4gICAgaWYgKGRlY2ltYWxQYXJ0ICYmIGRlY2ltYWxQYXJ0Lmxlbmd0aCA+IG1heERlY2ltYWxzKSB7XHJcbiAgICAgIHJldHVybiBpbnRlZ2VyUGFydCArICcuJyArIGRlY2ltYWxQYXJ0LnNsaWNlKDAsIG1heERlY2ltYWxzKTtcclxuICAgIH1cclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFVwZGF0ZSBjdXJzb3IgcG9zaXRpb24gYWZ0ZXIgZmlsdGVyaW5nIGlucHV0XHJcbiAgICovXHJcbiAgcHJpdmF0ZSB1cGRhdGVDdXJzb3JQb3NpdGlvbkFmdGVyRmlsdGVyKFxyXG4gICAgdGFyZ2V0OiBIVE1MSW5wdXRFbGVtZW50LFxyXG4gICAgb3JpZ2luYWxWYWx1ZTogc3RyaW5nLFxyXG4gICAgbmV3VmFsdWU6IHN0cmluZyxcclxuICAgIGN1cnNvclBvc2l0aW9uOiBudW1iZXIsXHJcbiAgKTogdm9pZCB7XHJcbiAgICBpZiAodGFyZ2V0LnZhbHVlID09PSBuZXdWYWx1ZSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgY2hhcnNSZW1vdmVkQmVmb3JlQ3Vyc29yID0gdGhpcy5jb3VudFJlbW92ZWRDaGFyc0JlZm9yZUN1cnNvcihcclxuICAgICAgb3JpZ2luYWxWYWx1ZSxcclxuICAgICAgbmV3VmFsdWUsXHJcbiAgICAgIGN1cnNvclBvc2l0aW9uLFxyXG4gICAgKTtcclxuICAgIHRhcmdldC52YWx1ZSA9IG5ld1ZhbHVlO1xyXG4gICAgY29uc3QgbmV3UG9zaXRpb24gPSBNYXRoLm1heCgwLCBjdXJzb3JQb3NpdGlvbiAtIGNoYXJzUmVtb3ZlZEJlZm9yZUN1cnNvcik7XHJcbiAgICB0YXJnZXQuc2V0U2VsZWN0aW9uUmFuZ2UobmV3UG9zaXRpb24sIG5ld1Bvc2l0aW9uKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFVwZGF0ZSBmb3JtIGNvbnRyb2wgdmFsdWUgYW5kIHBlcmZvcm0gdmFsaWRhdGlvblxyXG4gICAqL1xyXG4gIHByaXZhdGUgdXBkYXRlRm9ybUNvbnRyb2xWYWx1ZSh2YWx1ZTogc3RyaW5nLCBtYXhEZWNpbWFsczogbnVtYmVyKTogdm9pZCB7XHJcbiAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUodmFsdWUsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcclxuICAgIHRoaXMudmFsaWRhdGVJbnRlZ2VyRGlnaXRzKHZhbHVlLCBtYXhEZWNpbWFscyk7XHJcbiAgICB0aGlzLmNsZWFyTnVtZXJpY0Vycm9yKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDb3VudCBob3cgbWFueSBjaGFyYWN0ZXJzIHdlcmUgcmVtb3ZlZCBiZWZvcmUgdGhlIGN1cnNvciBwb3NpdGlvblxyXG4gICAqIFRoaXMgaGVscHMgbWFpbnRhaW4gY29ycmVjdCBjdXJzb3IgcG9zaXRpb24gYWZ0ZXIgZmlsdGVyaW5nIGlucHV0XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjb3VudFJlbW92ZWRDaGFyc0JlZm9yZUN1cnNvcihcclxuICAgIG9yaWdpbmFsOiBzdHJpbmcsXHJcbiAgICBmaWx0ZXJlZDogc3RyaW5nLFxyXG4gICAgY3Vyc29yUG9zOiBudW1iZXIsXHJcbiAgKTogbnVtYmVyIHtcclxuICAgIGxldCByZW1vdmVkQ291bnQgPSAwO1xyXG4gICAgbGV0IGZpbHRlcmVkSW5kZXggPSAwO1xyXG5cclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY3Vyc29yUG9zICYmIGkgPCBvcmlnaW5hbC5sZW5ndGg7IGkrKykge1xyXG4gICAgICBpZiAoZmlsdGVyZWRJbmRleCA8IGZpbHRlcmVkLmxlbmd0aCAmJiBvcmlnaW5hbFtpXSA9PT0gZmlsdGVyZWRbZmlsdGVyZWRJbmRleF0pIHtcclxuICAgICAgICBmaWx0ZXJlZEluZGV4Kys7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmVtb3ZlZENvdW50Kys7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVtb3ZlZENvdW50O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIHBhc3RlIGV2ZW50IGZvciBudW1iZXIgaW5wdXRzXHJcbiAgICogUHJldmVudHMgcGFzdGluZyBvZiBub24tbnVtZXJpYyBjaGFyYWN0ZXJzIGFuZCBlbmZvcmNlcyBkaWdpdCBsaW1pdHNcclxuICAgKi9cclxuICBoYW5kbGVOdW1iZXJQYXN0ZShldmVudDogQ2xpcGJvYXJkRXZlbnQsIG1heERlY2ltYWxzOiBudW1iZXIgPSAyKTogdm9pZCB7XHJcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgY29uc3QgdGFyZ2V0ID0gZXZlbnQudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQ7XHJcbiAgICBjb25zdCBwYXN0ZWRUZXh0ID0gZXZlbnQuY2xpcGJvYXJkRGF0YT8uZ2V0RGF0YSgndGV4dCcpIHx8ICcnO1xyXG4gICAgY29uc3QgaXNDdXJyZW5jeSA9IHRoaXMuZmllbGQudHlwZSA9PT0gJ251bWJlcicgJiYgISF0aGlzLmZpZWxkLmlzQ3VycmVuY3k7XHJcblxyXG4gICAgY29uc3QgZmlsdGVyZWRUZXh0ID0gaXNDdXJyZW5jeVxyXG4gICAgICA/IHRoaXMuZ2V0RmlsdGVyZWRDdXJyZW5jeVBhc3RlZFRleHQocGFzdGVkVGV4dClcclxuICAgICAgOiB0aGlzLmdldEZpbHRlcmVkSW50ZWdlclBhc3RlZFRleHQocGFzdGVkVGV4dCk7XHJcbiAgICBjb25zdCBmaW5hbFZhbHVlID0gdGhpcy5idWlsZEZpbmFsUGFzdGVWYWx1ZSh0YXJnZXQsIGZpbHRlcmVkVGV4dCwgaXNDdXJyZW5jeSwgbWF4RGVjaW1hbHMpO1xyXG5cclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5wdXRcclxuICAgIHRhcmdldC52YWx1ZSA9IGZpbmFsVmFsdWU7XHJcbiAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUoZmluYWxWYWx1ZSwgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG5cclxuICAgIHRoaXMudmFsaWRhdGVJbnRlZ2VyRGlnaXRzKGZpbmFsVmFsdWUsIG1heERlY2ltYWxzKTtcclxuICAgIHRoaXMuY2xlYXJOdW1lcmljRXJyb3IoKTtcclxuXHJcbiAgICB0aGlzLnZhbHVlQ2hhbmdlLmVtaXQoeyBuYW1lOiB0aGlzLmZpZWxkLm5hbWUsIHZhbHVlOiBmaW5hbFZhbHVlIH0pO1xyXG4gICAgdGhpcy5jb250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuXHJcbiAgICB0aGlzLnNldEN1cnNvckFmdGVyUGFzdGUodGFyZ2V0LCBmaWx0ZXJlZFRleHQsIGZpbmFsVmFsdWUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRmlsdGVyIHBhc3RlZCB0ZXh0IGZvciBjdXJyZW5jeSBpbnB1dCAoYWxsb3dzIGRpZ2l0cyBhbmQgZGVjaW1hbCBwb2ludClcclxuICAgKi9cclxuICBwcml2YXRlIGdldEZpbHRlcmVkQ3VycmVuY3lQYXN0ZWRUZXh0KHBhc3RlZFRleHQ6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gcGFzdGVkVGV4dC5yZXBsYWNlQWxsKC9bXjAtOS5dL2csICcnKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEZpbHRlciBwYXN0ZWQgdGV4dCBmb3IgaW50ZWdlci1vbmx5IGlucHV0IChhbGxvd3MgZGlnaXRzIG9ubHkpXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRGaWx0ZXJlZEludGVnZXJQYXN0ZWRUZXh0KHBhc3RlZFRleHQ6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gcGFzdGVkVGV4dC5yZXBsYWNlQWxsKC9cXEQvZywgJycpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQnVpbGQgZmluYWwgdmFsdWUgYWZ0ZXIgcGFzdGUgb3BlcmF0aW9uXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBidWlsZEZpbmFsUGFzdGVWYWx1ZShcclxuICAgIHRhcmdldDogSFRNTElucHV0RWxlbWVudCxcclxuICAgIGZpbHRlcmVkVGV4dDogc3RyaW5nLFxyXG4gICAgaXNDdXJyZW5jeTogYm9vbGVhbixcclxuICAgIG1heERlY2ltYWxzOiBudW1iZXIsXHJcbiAgKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGN1cnJlbnRWYWx1ZSA9IHRhcmdldC52YWx1ZTtcclxuICAgIGNvbnN0IHN0YXJ0ID0gdGFyZ2V0LnNlbGVjdGlvblN0YXJ0O1xyXG4gICAgY29uc3QgZW5kID0gdGFyZ2V0LnNlbGVjdGlvbkVuZDtcclxuXHJcbiAgICBsZXQgZmluYWxWYWx1ZTogc3RyaW5nO1xyXG5cclxuICAgIC8vIElmIHNlbGVjdGlvbiBBUEkgaXMgbm90IHN1cHBvcnRlZCBvciBubyBzZWxlY3Rpb24sIHJlcGxhY2UgZW50aXJlIGNvbnRlbnRcclxuICAgIGlmIChzdGFydCA9PT0gbnVsbCB8fCBlbmQgPT09IG51bGwgfHwgKHN0YXJ0ID09PSAwICYmIGVuZCA9PT0gMCkpIHtcclxuICAgICAgZmluYWxWYWx1ZSA9IGZpbHRlcmVkVGV4dDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGZpbmFsVmFsdWUgPSBjdXJyZW50VmFsdWUuc3Vic3RyaW5nKDAsIHN0YXJ0KSArIGZpbHRlcmVkVGV4dCArIGN1cnJlbnRWYWx1ZS5zdWJzdHJpbmcoZW5kKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gaXNDdXJyZW5jeSA/IHRoaXMuYXBwbHlEZWNpbWFsUmVzdHJpY3Rpb25zKGZpbmFsVmFsdWUsIG1heERlY2ltYWxzKSA6IGZpbmFsVmFsdWU7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBBcHBseSBkZWNpbWFsIHJlc3RyaWN0aW9ucyBmb3IgY3VycmVuY3kgZmllbGRzXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBhcHBseURlY2ltYWxSZXN0cmljdGlvbnModmFsdWU6IHN0cmluZywgbWF4RGVjaW1hbHM6IG51bWJlcik6IHN0cmluZyB7XHJcbiAgICBsZXQgcmVzdWx0ID0gdmFsdWU7XHJcblxyXG4gICAgLy8gRW5zdXJlIG9ubHkgb25lIGRlY2ltYWwgcG9pbnRcclxuICAgIGNvbnN0IHBhcnRzID0gcmVzdWx0LnNwbGl0KCcuJyk7XHJcbiAgICBpZiAocGFydHMubGVuZ3RoID4gMikge1xyXG4gICAgICByZXN1bHQgPSBwYXJ0c1swXSArICcuJyArIHBhcnRzLnNsaWNlKDEpLmpvaW4oJycpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc3RyaWN0IHRvIG1heERlY2ltYWxzIGRlY2ltYWwgcGxhY2VzXHJcbiAgICBpZiAocmVzdWx0LmluY2x1ZGVzKCcuJykpIHtcclxuICAgICAgY29uc3QgW2ludFBhcnQsIGRlY1BhcnRdID0gcmVzdWx0LnNwbGl0KCcuJyk7XHJcbiAgICAgIGlmIChkZWNQYXJ0Lmxlbmd0aCA+IG1heERlY2ltYWxzKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gaW50UGFydCArICcuJyArIGRlY1BhcnQuc2xpY2UoMCwgbWF4RGVjaW1hbHMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlIGludGVnZXIgZGlnaXQgbGltaXQgYW5kIHNldC9jbGVhciBlcnJvcnNcclxuICAgKi9cclxuICBwcml2YXRlIHZhbGlkYXRlSW50ZWdlckRpZ2l0cyh2YWx1ZTogc3RyaW5nLCBtYXhEZWNpbWFsczogbnVtYmVyKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5maWVsZC50eXBlICE9PSAnbnVtYmVyJyB8fCAhdGhpcy5maWVsZC5tYXhJbnRlZ2VyRGlnaXRzKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBtYXhJbnREaWdpdHMgPSB0aGlzLmZpZWxkLm1heEludGVnZXJEaWdpdHMgPz8gMTU7XHJcbiAgICBjb25zdCBbaW50UGFydF0gPSB2YWx1ZS5pbmNsdWRlcygnLicpID8gdmFsdWUuc3BsaXQoJy4nKSA6IFt2YWx1ZV07XHJcblxyXG4gICAgaWYgKGludFBhcnQubGVuZ3RoID4gbWF4SW50RGlnaXRzKSB7XHJcbiAgICAgIHRoaXMuc2V0TWF4SW50ZWdlckRpZ2l0c0Vycm9yKGludFBhcnQubGVuZ3RoLCBtYXhJbnREaWdpdHMsIG1heERlY2ltYWxzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuY2xlYXJNYXhJbnRlZ2VyRGlnaXRzRXJyb3IoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldCBtYXggaW50ZWdlciBkaWdpdHMgZXJyb3JcclxuICAgKi9cclxuICBwcml2YXRlIHNldE1heEludGVnZXJEaWdpdHNFcnJvcihhY3R1YWw6IG51bWJlciwgbWF4OiBudW1iZXIsIG1heERlY2ltYWxzOiBudW1iZXIpOiB2b2lkIHtcclxuICAgIGNvbnN0IGN1cnJlbnRFcnJvcnMgPSB0aGlzLmNvbnRyb2wuZXJyb3JzIHx8IHt9O1xyXG4gICAgdGhpcy5jb250cm9sLnNldEVycm9ycyh7XHJcbiAgICAgIC4uLmN1cnJlbnRFcnJvcnMsXHJcbiAgICAgIG1heEludGVnZXJEaWdpdHM6IHtcclxuICAgICAgICBhY3R1YWwsXHJcbiAgICAgICAgbWF4LFxyXG4gICAgICAgIG1heERlY2ltYWxzLFxyXG4gICAgICAgIG1lc3NhZ2U6IGBQbGVhc2Ugc2hvcnRlbiB5b3VyIGlucHV0IHRvICR7bWF4fSB3aG9sZSBkaWdpdHMgYW5kICR7bWF4RGVjaW1hbHN9IGRlY2ltYWwgb3IgZmV3ZXIuYCxcclxuICAgICAgfSxcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ2xlYXIgbWF4IGludGVnZXIgZGlnaXRzIGVycm9yIGlmIHByZXNlbnRcclxuICAgKi9cclxuICBwcml2YXRlIGNsZWFyTWF4SW50ZWdlckRpZ2l0c0Vycm9yKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLmNvbnRyb2wuaGFzRXJyb3IoJ21heEludGVnZXJEaWdpdHMnKSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZXJyb3JzID0geyAuLi50aGlzLmNvbnRyb2wuZXJyb3JzIH07XHJcbiAgICBkZWxldGUgZXJyb3JzWydtYXhJbnRlZ2VyRGlnaXRzJ107XHJcbiAgICB0aGlzLmNvbnRyb2wuc2V0RXJyb3JzKE9iamVjdC5rZXlzKGVycm9ycykubGVuZ3RoID8gZXJyb3JzIDogbnVsbCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDbGVhciBudW1lcmljIGVycm9yIGlmIHByZXNlbnRcclxuICAgKi9cclxuICBwcml2YXRlIGNsZWFyTnVtZXJpY0Vycm9yKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLmNvbnRyb2wuaGFzRXJyb3IoJ251bWVyaWMnKSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZXJyb3JzID0geyAuLi50aGlzLmNvbnRyb2wuZXJyb3JzIH07XHJcbiAgICBkZWxldGUgZXJyb3JzWydudW1lcmljJ107XHJcbiAgICB0aGlzLmNvbnRyb2wuc2V0RXJyb3JzKE9iamVjdC5rZXlzKGVycm9ycykubGVuZ3RoID8gZXJyb3JzIDogbnVsbCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXQgY3Vyc29yIHBvc2l0aW9uIGFmdGVyIHBhc3RlIG9wZXJhdGlvblxyXG4gICAqL1xyXG4gIHByaXZhdGUgc2V0Q3Vyc29yQWZ0ZXJQYXN0ZShcclxuICAgIHRhcmdldDogSFRNTElucHV0RWxlbWVudCxcclxuICAgIGZpbHRlcmVkVGV4dDogc3RyaW5nLFxyXG4gICAgZmluYWxWYWx1ZTogc3RyaW5nLFxyXG4gICk6IHZvaWQge1xyXG4gICAgLy8gSW5wdXQgdHlwZT1cIm51bWJlclwiIGRvZXMgbm90IHN1cHBvcnQgc2VsZWN0aW9uIEFQSXNcclxuICAgIGlmICh0YXJnZXQudHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHN0YXJ0ID0gdGFyZ2V0LnNlbGVjdGlvblN0YXJ0IHx8IDA7XHJcbiAgICBjb25zdCBuZXdDdXJzb3JQb3MgPSBzdGFydCArIGZpbHRlcmVkVGV4dC5sZW5ndGg7XHJcbiAgICBjb25zdCBhY3R1YWxQb3MgPSBNYXRoLm1pbihuZXdDdXJzb3JQb3MsIGZpbmFsVmFsdWUubGVuZ3RoKTtcclxuICAgIHRhcmdldC5zZXRTZWxlY3Rpb25SYW5nZShhY3R1YWxQb3MsIGFjdHVhbFBvcyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3JtYXQgbnVtYmVyIHdpdGggY29tbWEgc2VwYXJhdG9yc1xyXG4gIC8vIFVzZXMgc3RyaW5nLWJhc2VkIGZvcm1hdHRpbmcgZm9yIGxhcmdlIG51bWJlcnMgdG8gcHJlc2VydmUgcHJlY2lzaW9uXHJcbiAgZm9ybWF0Q3VycmVuY3lXaXRoQ29tbWFzKHZhbHVlOiBudW1iZXIgfCBzdHJpbmcsIG1heERlY2ltYWxzOiBudW1iZXIgPSAyKTogc3RyaW5nIHtcclxuICAgIGlmICh0aGlzLmZpZWxkLnR5cGUgIT09ICdudW1iZXInIHx8ICF0aGlzLmZpZWxkLmlzQ3VycmVuY3kpIHJldHVybiB2YWx1ZS50b1N0cmluZygpO1xyXG5cclxuICAgIGNvbnN0IHN0clZhbHVlID0gdmFsdWUudG9TdHJpbmcoKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gb3JpZ2luYWwgdmFsdWUgZm9yIGVtcHR5IG9yIGludmFsaWQgaW5wdXRzXHJcbiAgICBpZiAoIXN0clZhbHVlIHx8IHN0clZhbHVlID09PSAnTmFOJykgcmV0dXJuICcnO1xyXG5cclxuICAgIC8vIFVzZSBzdHJpbmctYmFzZWQgZm9ybWF0dGluZyB0byBwcmVzZXJ2ZSBwcmVjaXNpb24gZm9yIGxhcmdlIG51bWJlcnNcclxuICAgIGNvbnN0IFtpbnRlZ2VyUGFydCwgZGVjaW1hbFBhcnRdID0gc3RyVmFsdWUuaW5jbHVkZXMoJy4nKVxyXG4gICAgICA/IHN0clZhbHVlLnNwbGl0KCcuJylcclxuICAgICAgOiBbc3RyVmFsdWUsICcnXTtcclxuXHJcbiAgICAvLyBGb3JtYXQgaW50ZWdlciBwYXJ0IHdpdGggY29tbWEgc2VwYXJhdG9ycyAoZXZlcnkgMyBkaWdpdHMgZnJvbSByaWdodClcclxuICAgIC8vIFVzaW5nIGl0ZXJhdGl2ZSBhcHByb2FjaCBpbnN0ZWFkIG9mIHJlZ2V4IHRvIGF2b2lkIFJlRG9TIGNvbmNlcm5zXHJcbiAgICBsZXQgZm9ybWF0dGVkSW50ZWdlciA9ICcnO1xyXG4gICAgY29uc3QgbGVuID0gaW50ZWdlclBhcnQubGVuZ3RoO1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICBpZiAoaSA+IDAgJiYgKGxlbiAtIGkpICUgMyA9PT0gMCkge1xyXG4gICAgICAgIGZvcm1hdHRlZEludGVnZXIgKz0gJywnO1xyXG4gICAgICB9XHJcbiAgICAgIGZvcm1hdHRlZEludGVnZXIgKz0gaW50ZWdlclBhcnRbaV07XHJcbiAgICB9XHJcbiAgICAvLyBGb3JtYXQgZGVjaW1hbCBwYXJ0IChwYWQgb3IgdHJ1bmNhdGUgdG8gbWF4RGVjaW1hbHMpXHJcbiAgICBsZXQgZm9ybWF0dGVkRGVjaW1hbCA9IGRlY2ltYWxQYXJ0IHx8ICcnO1xyXG4gICAgaWYgKGZvcm1hdHRlZERlY2ltYWwubGVuZ3RoIDwgbWF4RGVjaW1hbHMpIHtcclxuICAgICAgZm9ybWF0dGVkRGVjaW1hbCA9IGZvcm1hdHRlZERlY2ltYWwucGFkRW5kKG1heERlY2ltYWxzLCAnMCcpO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXR0ZWREZWNpbWFsLmxlbmd0aCA+IG1heERlY2ltYWxzKSB7XHJcbiAgICAgIGZvcm1hdHRlZERlY2ltYWwgPSBmb3JtYXR0ZWREZWNpbWFsLnNsaWNlKDAsIG1heERlY2ltYWxzKTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gbWF4RGVjaW1hbHMgPiAwID8gYCR7Zm9ybWF0dGVkSW50ZWdlcn0uJHtmb3JtYXR0ZWREZWNpbWFsfWAgOiBmb3JtYXR0ZWRJbnRlZ2VyO1xyXG4gIH1cclxuXHJcbiAgaGFuZGxlTnVtYmVyS2V5ZG93bihldmVudDogS2V5Ym9hcmRFdmVudCwgaXNDdXJyZW5jeTogYm9vbGVhbikge1xyXG4gICAgaWYgKGlzQ3VycmVuY3kpIHJldHVybjtcclxuXHJcbiAgICAvLyBBbGxvdzogQmFja3NwYWNlLCBEZWxldGUsIFRhYiwgQXJyb3cga2V5c1xyXG4gICAgaWYgKFsnQmFja3NwYWNlJywgJ0RlbGV0ZScsICdUYWInLCAnQXJyb3dMZWZ0JywgJ0Fycm93UmlnaHQnXS5pbmNsdWRlcyhldmVudC5rZXkpKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGxvdyBjbGlwYm9hcmQgb3BlcmF0aW9ucyAoQ3RybCtWLCBDdHJsK0MsIEN0cmwrWCwgQ21kK1YsIENtZCtDLCBDbWQrWClcclxuICAgIC8vIGFuZCBzZWxlY3Rpb24gKEN0cmwrQSwgQ21kK0EpXHJcbiAgICBpZiAoZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5KSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBCbG9jayBldmVyeXRoaW5nIHRoYXQgaXMgbm90IDAtOVxyXG4gICAgaWYgKCEvXlxcZCQvLnRlc3QoZXZlbnQua2V5KSkge1xyXG4gICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gR2V0IGxvY2FsZSBmcm9tIGN1cnJlbmN5IGNvZGUgdXNpbmcgY3VycmVuY3lNZXRhXHJcbiAgZ2V0TG9jYWxlRnJvbUN1cnJlbmN5KGN1cnJlbmN5Q29kZT86IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBjdXJyZW5jeU9iaiA9IHRoaXMuY3VycmVuY3lNZXRhLmZpbmQoXHJcbiAgICAgIChjOiB7IGNvZGU6IHN0cmluZzsgbG9jYWxlOiBzdHJpbmcgfSkgPT4gYy5jb2RlID09PSBjdXJyZW5jeUNvZGUsXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBjdXJyZW5jeU9iaj8ubG9jYWxlIHx8IHRoaXMuZGVmYXVsdExvY2FsZTtcclxuICB9XHJcblxyXG4gIHNob3dQYXNzd29yZCA9IGZhbHNlO1xyXG4gIHBhc3N3b3JkU3RyZW5ndGhMYWJlbCA9ICcnO1xyXG4gIHN0cmVuZ3RoQ2xhc3MgPSAnJztcclxuICBwYXNzd29yZFN0cmVuZ3RoUGVyY2VudCA9IDA7XHJcbiAgaXNQYXNzd29yZEZvY3VzZWQgPSBmYWxzZTtcclxuICBvblBhc3N3b3JkRm9jdXMoKTogdm9pZCB7XHJcbiAgICB0aGlzLmhhc0ZvY3VzLnNldCh0cnVlKTtcclxuICAgIHRoaXMuaXNQYXNzd29yZEZvY3VzZWQgPSB0cnVlO1xyXG4gICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gIH1cclxuXHJcbiAgb25QYXNzd29yZEJsdXIoKTogdm9pZCB7XHJcbiAgICB0aGlzLmlzUGFzc3dvcmRGb2N1c2VkID0gZmFsc2U7XHJcbiAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG5cclxuICBoYW5kbGVQYXNzd29yZEJsdXIoZTogRXZlbnQpOiB2b2lkIHtcclxuICAgIHRoaXMuaGFuZGxlQmx1cihlKTsgLy8gT3JpZ2luYWwgYmx1ciBmdW5jdGlvbmFsaXR5IChzZXRzIGhhc0ZvY3VzIHRvIGZhbHNlKVxyXG4gICAgdGhpcy5vblBhc3N3b3JkQmx1cigpOyAvLyBIaWRlIHBhc3N3b3JkIGZlZWRiYWNrXHJcbiAgfVxyXG5cclxuICBjaGVja1Bhc3N3b3JkU3RyZW5ndGgodmFsdWU6IHN0cmluZykge1xyXG4gICAgaWYgKCF2YWx1ZSB8fCB0aGlzLmZpZWxkLnR5cGUgIT09ICdwYXNzd29yZCcpIHtcclxuICAgICAgdGhpcy5wYXNzd29yZFN0cmVuZ3RoTGFiZWwgPSAnJztcclxuICAgICAgdGhpcy5zdHJlbmd0aENsYXNzID0gJyc7XHJcbiAgICAgIHRoaXMucGFzc3dvcmRTdHJlbmd0aFBlcmNlbnQgPSAwO1xyXG5cclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgbGV0IHNjb3JlID0gMDtcclxuICAgIGlmICh2YWx1ZS5sZW5ndGggPj0gOCkgc2NvcmUrKztcclxuICAgIGlmICgvW0EtWl0vLnRlc3QodmFsdWUpKSBzY29yZSsrO1xyXG4gICAgaWYgKC9cXGQvLnRlc3QodmFsdWUpKSBzY29yZSsrO1xyXG4gICAgaWYgKC9bXFxXX10vLnRlc3QodmFsdWUpKSBzY29yZSsrO1xyXG5cclxuICAgIGlmIChzY29yZSA8PSAxKSB7XHJcbiAgICAgIHRoaXMucGFzc3dvcmRTdHJlbmd0aExhYmVsID0gdGhpcy5maWVsZC53ZWFrTGFiZWwgfHwgJ1dlYWsnO1xyXG4gICAgICB0aGlzLnN0cmVuZ3RoQ2xhc3MgPSAndGV4dC1bdmFyKC0tUkhCLVJlZC0xMDApXSc7XHJcbiAgICAgIHRoaXMucGFzc3dvcmRTdHJlbmd0aFBlcmNlbnQgPSAyNTtcclxuICAgIH0gZWxzZSBpZiAoc2NvcmUgPT09IDIgfHwgc2NvcmUgPT09IDMpIHtcclxuICAgICAgdGhpcy5wYXNzd29yZFN0cmVuZ3RoTGFiZWwgPSB0aGlzLmZpZWxkLm1lZGl1bUxhYmVsIHx8ICdNZWRpdW0nO1xyXG4gICAgICB0aGlzLnN0cmVuZ3RoQ2xhc3MgPSAndGV4dC1bdmFyKC0tT3JhbmdlLTEwMCldJztcclxuICAgICAgdGhpcy5wYXNzd29yZFN0cmVuZ3RoUGVyY2VudCA9IHNjb3JlID09PSAyID8gNTAgOiA3NTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMucGFzc3dvcmRTdHJlbmd0aExhYmVsID0gdGhpcy5maWVsZC5zdHJvbmdMYWJlbCB8fCAnU3Ryb25nJztcclxuICAgICAgdGhpcy5zdHJlbmd0aENsYXNzID0gJ3RleHQtW3ZhcigtLUdyZWVuLTEwMCldJztcclxuICAgICAgdGhpcy5wYXNzd29yZFN0cmVuZ3RoUGVyY2VudCA9IDEwMDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGluY3JlbWVudCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmZpZWxkLnR5cGUgIT09ICdudW1iZXInKSByZXR1cm47XHJcbiAgICBjb25zdCBzdGVwID0gdGhpcy5maWVsZC5zdGVwIHx8IDE7XHJcbiAgICBjb25zdCBjdXJyZW50ID0gTnVtYmVyKHRoaXMuY29udHJvbC52YWx1ZSkgfHwgMDtcclxuICAgIGxldCBuZXh0VmFsdWUgPSBjdXJyZW50ICsgc3RlcDtcclxuXHJcbiAgICBpZiAodHlwZW9mIHRoaXMuZmllbGQubWF4ID09PSAnbnVtYmVyJykge1xyXG4gICAgICBuZXh0VmFsdWUgPSBNYXRoLm1pbihuZXh0VmFsdWUsIHRoaXMuZmllbGQubWF4KTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUobmV4dFZhbHVlKTtcclxuICAgIHRoaXMuY29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XHJcbiAgICB0aGlzLnZhbHVlQ2hhbmdlLmVtaXQoeyBuYW1lOiB0aGlzLmZpZWxkLm5hbWUsIHZhbHVlOiBuZXh0VmFsdWUgfSk7XHJcblxyXG4gICAgLy8gVXBkYXRlIGRpc3BsYXkgdmFsdWUgZm9yIGN1cnJlbmN5IGlucHV0c1xyXG4gICAgaWYgKHRoaXMuZmllbGQuaXNDdXJyZW5jeSkge1xyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICBjb25zdCBpbnB1dEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLnVuaXF1ZUlkKSBhcyBIVE1MSW5wdXRFbGVtZW50O1xyXG4gICAgICAgIGlmIChpbnB1dEVsZW1lbnQpIHtcclxuICAgICAgICAgIGlucHV0RWxlbWVudC52YWx1ZSA9IHRoaXMuZm9ybWF0Q3VycmVuY3lXaXRoQ29tbWFzKG5leHRWYWx1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGRlY3JlbWVudCgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmZpZWxkLnR5cGUgIT09ICdudW1iZXInKSByZXR1cm47XHJcbiAgICBjb25zdCBzdGVwID0gdGhpcy5maWVsZC5zdGVwIHx8IDE7XHJcbiAgICBjb25zdCBjdXJyZW50ID0gTnVtYmVyKHRoaXMuY29udHJvbC52YWx1ZSkgfHwgMDtcclxuICAgIGxldCBuZXh0VmFsdWUgPSBjdXJyZW50IC0gc3RlcDtcclxuXHJcbiAgICAvLyBFbnN1cmUgbWluaW11bSB2YWx1ZSBpcyAwIChubyBuZWdhdGl2ZSB2YWx1ZXMpXHJcbiAgICBjb25zdCBtaW5WYWx1ZSA9IE1hdGgubWF4KHRoaXMuZmllbGQubWluIHx8IDAsIDApO1xyXG4gICAgbmV4dFZhbHVlID0gTWF0aC5tYXgobmV4dFZhbHVlLCBtaW5WYWx1ZSk7XHJcblxyXG4gICAgdGhpcy5jb250cm9sLnNldFZhbHVlKG5leHRWYWx1ZSk7XHJcbiAgICB0aGlzLmNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gICAgdGhpcy52YWx1ZUNoYW5nZS5lbWl0KHsgbmFtZTogdGhpcy5maWVsZC5uYW1lLCB2YWx1ZTogbmV4dFZhbHVlIH0pO1xyXG5cclxuICAgIC8vIFVwZGF0ZSBkaXNwbGF5IHZhbHVlIGZvciBjdXJyZW5jeSBpbnB1dHNcclxuICAgIGlmICh0aGlzLmZpZWxkLmlzQ3VycmVuY3kpIHtcclxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgY29uc3QgaW5wdXRFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy51bmlxdWVJZCkgYXMgSFRNTElucHV0RWxlbWVudDtcclxuICAgICAgICBpZiAoaW5wdXRFbGVtZW50KSB7XHJcbiAgICAgICAgICBpbnB1dEVsZW1lbnQudmFsdWUgPSB0aGlzLmZvcm1hdEN1cnJlbmN5V2l0aENvbW1hcyhuZXh0VmFsdWUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjb3B5VGV4dChlOiBFdmVudCk6IHZvaWQge1xyXG4gICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIGlmICghdGhpcy5jb250cm9sLnZhbHVlKSByZXR1cm47XHJcbiAgICBuYXZpZ2F0b3IuY2xpcGJvYXJkLndyaXRlVGV4dCh0aGlzLmNvbnRyb2wudmFsdWUpLnRoZW4oKCkgPT4ge1xyXG4gICAgICBjb25zdCBzZXJ2aWNlID0gdGhpcy5lZmZlY3RpdmVUb2FzdFNlcnZpY2U7XHJcbiAgICAgIGlmIChzZXJ2aWNlKSB7XHJcbiAgICAgICAgLy8gUG9zaXRpb24gc2V0IHRvIHRvcCBhcyByZXF1ZXN0ZWRcclxuICAgICAgICBzZXJ2aWNlLnN1Y2Nlc3MoJ0NvcGllZCB0byBjbGlwYm9hcmQnLCAnU3VjY2VzcycsIDIwMDApO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByZWZpeENsaWNrKGU6IEV2ZW50KTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5maWVsZC5wcmVmaXg/Lm9uQ2xpY2spIHtcclxuICAgICAgdGhpcy5maWVsZC5wcmVmaXgub25DbGljayhlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHN1ZmZpeENsaWNrKGU6IEV2ZW50KTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5maWVsZC5zdWZmaXg/Lm9uQ2xpY2spIHtcclxuICAgICAgdGhpcy5maWVsZC5zdWZmaXgub25DbGljayhlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldCB1cCB2aXNpYmlsaXR5IGNvbmRpdGlvbiBsaXN0ZW5lclxyXG4gICAqIFdhdGNoZXMgdGhlIGRlcGVuZGVudCBmaWVsZCBhbmQgc2hvd3MvaGlkZXMgdGhpcyBmaWVsZCBiYXNlZCBvbiBjb25kaXRpb25zXHJcbiAgICovXHJcbiAgc2V0dXBWaXNpYmlsaXR5Q29uZGl0aW9uKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLmZpZWxkLnZpc2liaWxpdHlDb25kaXRpb24gfHwgIXRoaXMuZm9ybSkgcmV0dXJuO1xyXG5cclxuICAgIGNvbnN0IHsgZGVwZW5kc09uIH0gPSB0aGlzLmZpZWxkLnZpc2liaWxpdHlDb25kaXRpb247XHJcbiAgICBjb25zdCBkZXBlbmRlbnRDb250cm9sID0gdGhpcy5mb3JtLmdldChkZXBlbmRzT24pO1xyXG5cclxuICAgIGlmICghZGVwZW5kZW50Q29udHJvbCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW5pdGlhbCB2aXNpYmlsaXR5IGNoZWNrXHJcbiAgICB0aGlzLnVwZGF0ZVZpc2liaWxpdHkoZGVwZW5kZW50Q29udHJvbC52YWx1ZSk7XHJcblxyXG4gICAgLy8gU3Vic2NyaWJlIHRvIHZhbHVlIGNoYW5nZXNcclxuICAgIGRlcGVuZGVudENvbnRyb2wudmFsdWVDaGFuZ2VzLnN1YnNjcmliZSgodmFsdWUpID0+IHtcclxuICAgICAgdGhpcy51cGRhdGVWaXNpYmlsaXR5KHZhbHVlKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVXBkYXRlIGZpZWxkIHZpc2liaWxpdHkgYmFzZWQgb24gZGVwZW5kZW50IGZpZWxkIHZhbHVlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSB1cGRhdGVWaXNpYmlsaXR5KGRlcGVuZGVudFZhbHVlOiBhbnkpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5maWVsZC52aXNpYmlsaXR5Q29uZGl0aW9uKSByZXR1cm47XHJcblxyXG4gICAgY29uc3QgeyBzaG93V2hlbiwgaGlkZVdoZW4gfSA9IHRoaXMuZmllbGQudmlzaWJpbGl0eUNvbmRpdGlvbjtcclxuICAgIGxldCBzaG91bGRCZVZpc2libGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDaGVjayBzaG93V2hlbiBjb25kaXRpb25cclxuICAgIGlmIChzaG93V2hlbiAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHNob3dXaGVuKSkge1xyXG4gICAgICAgIHNob3VsZEJlVmlzaWJsZSA9IHNob3dXaGVuLmluY2x1ZGVzKGRlcGVuZGVudFZhbHVlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzaG91bGRCZVZpc2libGUgPSBkZXBlbmRlbnRWYWx1ZSA9PT0gc2hvd1doZW47XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBoaWRlV2hlbiBjb25kaXRpb24gKG92ZXJyaWRlcyBzaG93V2hlbilcclxuICAgIGlmIChoaWRlV2hlbiAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIGNvbnN0IHNob3VsZEhpZGUgPSBBcnJheS5pc0FycmF5KGhpZGVXaGVuKVxyXG4gICAgICAgID8gaGlkZVdoZW4uaW5jbHVkZXMoZGVwZW5kZW50VmFsdWUpXHJcbiAgICAgICAgOiBkZXBlbmRlbnRWYWx1ZSA9PT0gaGlkZVdoZW47XHJcblxyXG4gICAgICBpZiAoc2hvdWxkSGlkZSkge1xyXG4gICAgICAgIHNob3VsZEJlVmlzaWJsZSA9IGZhbHNlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXBkYXRlIHZpc2liaWxpdHlcclxuICAgIHRoaXMuaXNWaXNpYmxlLnNldChzaG91bGRCZVZpc2libGUpO1xyXG5cclxuICAgIC8vIE9ubHkgY2xlYXIgdmFsdWUgd2hlbiBoaWRpbmcgaWYgdGhlcmUncyBubyBpbml0aWFsIHZhbHVlXHJcbiAgICAvLyBUaGlzIHByZXNlcnZlcyBkYXRhIHdoZW4gZWRpdGluZyBleGlzdGluZyByZWNvcmRzXHJcbiAgICBpZiAoIXNob3VsZEJlVmlzaWJsZSAmJiB0aGlzLmNvbnRyb2wgJiYgIXRoaXMuY29udHJvbC52YWx1ZSkge1xyXG4gICAgICB0aGlzLmNvbnRyb2wuc2V0VmFsdWUobnVsbCk7XHJcbiAgICAgIHRoaXMuY29udHJvbC5tYXJrQXNVbnRvdWNoZWQoKTtcclxuICAgICAgdGhpcy5jb250cm9sLnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldHVwVG9hc3RTdWJzY3JpcHRpb24oKTogdm9pZCB7XHJcbiAgICBjb25zdCBzZXJ2aWNlID0gdGhpcy5lZmZlY3RpdmVUb2FzdFNlcnZpY2U7XHJcbiAgICBpZiAoc2VydmljZSkge1xyXG4gICAgICB0aGlzLnN1YnMuYWRkKFxyXG4gICAgICAgIHNlcnZpY2UudG9hc3RzJC5zdWJzY3JpYmUoKHRvYXN0czogYW55W10pID0+IHtcclxuICAgICAgICAgIHRoaXMudG9hc3RzLnNldCh0b2FzdHMpO1xyXG4gICAgICAgICAgLy8gV2FpdCBmb3IgRE9NIHRvIHVwZGF0ZSB0aGVuIHJlbmRlciB0b2FzdCBpY29uc1xyXG4gICAgICAgICAgdGhpcy51cGRhdGVBbGxJY29ucygpO1xyXG4gICAgICAgIH0pLFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmVtb3ZlVG9hc3QoaWQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgdGhpcy5lZmZlY3RpdmVUb2FzdFNlcnZpY2U/LnJlbW92ZShpZCk7XHJcbiAgfVxyXG5cclxuICBnZXRUcmFuc2xhdGVkTWVzc2FnZShtZXNzYWdlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgaWYgKHRoaXMuaGVscGVySGFuZGxlICYmIHR5cGVvZiB0aGlzLmhlbHBlckhhbmRsZS50cmFuc2xhdGUgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuaGVscGVySGFuZGxlLnRyYW5zbGF0ZShtZXNzYWdlKTtcclxuICAgIH1cclxuICAgIHJldHVybiBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgZ2V0VG9hc3RJY29uTmFtZSh0b2FzdDogYW55KTogc3RyaW5nIHtcclxuICAgIHN3aXRjaCAodG9hc3QudHlwZSkge1xyXG4gICAgICBjYXNlICdzdWNjZXNzJzpcclxuICAgICAgICByZXR1cm4gJ2NoZWNrLWNpcmNsZSc7XHJcbiAgICAgIGNhc2UgJ3dhcm4nOlxyXG4gICAgICBjYXNlICdpbmZvJzpcclxuICAgICAgICByZXR1cm4gJ2luZm8tY2lyY2xlJztcclxuICAgICAgY2FzZSAnZXJyb3InOlxyXG4gICAgICAgIHJldHVybiAnZXhjbGFtYXRpb24tY2lyY2xlJztcclxuICAgICAgZGVmYXVsdDpcclxuICAgICAgICByZXR1cm4gJ2luZm8tY2lyY2xlJztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHNob3dGb3JtRmllbGRNZXNzYWdlKGNvbnRyb2w6IGFueSwgaGVscGVyVGV4dDogc3RyaW5nKTogYm9vbGVhbiB7XHJcbiAgICBpZiAodGhpcy5oZWxwZXJIYW5kbGUpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuaGVscGVySGFuZGxlLnNob3dGb3JtRmllbGRNZXNzYWdlKGNvbnRyb2wsIGhlbHBlclRleHQpO1xyXG4gICAgfVxyXG4gICAgY29uc3QgaXNFcnJvciA9IGNvbnRyb2w/LnRvdWNoZWQgJiYgISFjb250cm9sPy5lcnJvcnM7XHJcbiAgICBjb25zdCBpc0hlbHBlciA9ICFpc0Vycm9yICYmIEJvb2xlYW4oaGVscGVyVGV4dCA/PyAnJyk7XHJcbiAgICByZXR1cm4gaXNFcnJvciB8fCBpc0hlbHBlcjtcclxuICB9XHJcblxyXG4gIGdldFRyYW5zbGF0ZWRMYWJlbChsYWJlbDogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIGlmICghbGFiZWwpIHJldHVybiAnJztcclxuICAgIHRyeSB7XHJcbiAgICAgIGNvbnN0IGxhYmVsU3RyID0gbGFiZWwudG9TdHJpbmcoKTtcclxuICAgICAgcmV0dXJuIChcclxuICAgICAgICBsYWJlbFN0clxyXG4gICAgICAgICAgLnNwbGl0KCc6OicpXHJcbiAgICAgICAgICAubWFwKChwYXJ0KSA9PiBwYXJ0LnRyaW0oKSlcclxuICAgICAgICAgIC5maWx0ZXIoKHBhcnQpID0+ICEhcGFydClcclxuICAgICAgICAgIC5tYXAoKHBhcnQpID0+IHRoaXMudHJhbnNsYXRlU2VydmljZS5pbnN0YW50KHBhcnQpKVxyXG4gICAgICAgICAgLmpvaW4oJyAnKSArIHRoaXMuZ2V0RW5kU3ltYm9sKGxhYmVsU3RyKVxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZSkge1xyXG4gICAgICBjb25zb2xlLndhcm4oJ1RyYW5zbGF0aW9uIGZhaWxlZCBpbiBnZXRUcmFuc2xhdGVkTGFiZWw6JywgbGFiZWwsIGUpO1xyXG4gICAgICByZXR1cm4gbGFiZWw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXRFbmRTeW1ib2wobGFiZWw6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gbGFiZWwudG9TdHJpbmcoKS5pbmNsdWRlcygncmVxdWlyZWQnKSAmJiBsYWJlbC50b1N0cmluZygpLmluY2x1ZGVzKCdGTkZpZWxkTWVzc2FnZScpXHJcbiAgICAgID8gJy4nXHJcbiAgICAgIDogJyc7XHJcbiAgfVxyXG5cclxuICAvLyAtLS0gSUNPTiBMT0dJQyAtLS1cclxuICBwcml2YXRlIHVwZGF0ZUFsbEljb25zKCk6IHZvaWQge1xyXG4gICAgLy8gV2UnbGwgY2FsbCB0aGlzIGFmdGVyIFZpZXdJbml0IG9yIHdoZW4gaW5wdXRzIGNoYW5nZVxyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIHRoaXMuaWNvbkNvbnRhaW5lcnM/LmZvckVhY2goKGNvbnRhaW5lcikgPT4ge1xyXG4gICAgICAgIGNvbnN0IGRzID0gY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuZGF0YXNldDtcclxuICAgICAgICBjb25zdCBuYW1lID0gZHNbJ2ljb25OYW1lJ107XHJcbiAgICAgICAgY29uc3QgdmFyaWFudCA9IChkc1snaWNvblZhcmlhbnQnXSBhcyBUeXBlSWNvblZhcmlhbnQpIHx8ICdMaW5lJztcclxuICAgICAgICBjb25zdCBzaXplID0gKGRzWydpY29uU2l6ZSddIHx8ICdtZWRpdW0nKSBhcyBUeXBlSWNvblNpemVOYW1lO1xyXG4gICAgICAgIGNvbnN0IGNvbG9yID0gZHNbJ2ljb25Db2xvciddO1xyXG4gICAgICAgIGNvbnN0IGRpc2FibGVkID0gZHNbJ2ljb25EaXNhYmxlZCddID09PSAndHJ1ZSc7XHJcblxyXG4gICAgICAgIGlmIChuYW1lKSB7XHJcbiAgICAgICAgICB0aGlzLmxvYWRJY29uVG9Db250YWluZXIoY29udGFpbmVyLm5hdGl2ZUVsZW1lbnQsIG5hbWUsIHZhcmlhbnQsIHNpemUsIGNvbG9yLCBkaXNhYmxlZCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sIDApO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBsb2FkSWNvblRvQ29udGFpbmVyKFxyXG4gICAgY29udGFpbmVyOiBIVE1MRWxlbWVudCxcclxuICAgIG5hbWU6IHN0cmluZyxcclxuICAgIHZhcmlhbnQ6IFR5cGVJY29uVmFyaWFudCxcclxuICAgIHNpemVOYW1lOiBUeXBlSWNvblNpemVOYW1lLFxyXG4gICAgY29sb3I/OiBzdHJpbmcgfCBudWxsLFxyXG4gICAgZGlzYWJsZWQ/OiBib29sZWFuLFxyXG4gICk6IHZvaWQge1xyXG4gICAgY29uc3Qgc2l6ZSA9IHRoaXMuc2l6ZU1hcFtzaXplTmFtZV07XHJcblxyXG4gICAgLy8gMS4gQ2hlY2sgaWYgcmF3IFNWRyBzdHJpbmcgaXMgcHJvdmlkZWRcclxuICAgIGNvbnN0IHRyaW1tZWROYW1lID0gbmFtZS50cmltKCk7XHJcbiAgICBpZiAodHJpbW1lZE5hbWUuc3RhcnRzV2l0aCgnPHN2ZycpKSB7XHJcbiAgICAgIHRoaXMucmVuZGVyU3ZnVG9Db250YWluZXIoY29udGFpbmVyLCB0cmltbWVkTmFtZSwgY29sb3IsIHNpemUsICdjdXN0b20nLCBkaXNhYmxlZCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyAxYi4gQ2hlY2sgaWYgaXQncyBqdXN0IHJhdyBTVkcgaW5uZXIgY29udGVudCAobGlrZSBgPHBhdGggLi4uPmApXHJcbiAgICBpZiAoXHJcbiAgICAgIHRyaW1tZWROYW1lLnN0YXJ0c1dpdGgoJzxwYXRoJykgfHxcclxuICAgICAgdHJpbW1lZE5hbWUuc3RhcnRzV2l0aCgnPGcnKSB8fFxyXG4gICAgICB0cmltbWVkTmFtZS5zdGFydHNXaXRoKCc8Y2lyY2xlJykgfHxcclxuICAgICAgdHJpbW1lZE5hbWUuc3RhcnRzV2l0aCgnPHJlY3QnKSB8fFxyXG4gICAgICB0cmltbWVkTmFtZS5zdGFydHNXaXRoKCc8cG9seWdvbicpXHJcbiAgICApIHtcclxuICAgICAgY29uc3Qgd3JhcHBlZFN2ZyA9IGA8c3ZnIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwiY3VycmVudENvbG9yXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPiR7dHJpbW1lZE5hbWV9PC9zdmc+YDtcclxuICAgICAgdGhpcy5yZW5kZXJTdmdUb0NvbnRhaW5lcihjb250YWluZXIsIHdyYXBwZWRTdmcsIGNvbG9yLCBzaXplLCAnY3VzdG9tJywgZGlzYWJsZWQpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gMi4gQ2hlY2sgYnVpbHQtaW4gaWNvbnMgcmVnaXN0cnlcclxuICAgIC8vIFN0cmlwIHBvc3NpYmxlIC0tc2l6ZSBzdWZmaXggaWYgaXQgd2FzIHBhc3NlZCBieSBtaXN0YWtlIGZyb20gb2xkIGxvZ2ljXHJcbiAgICBjb25zdCBiYXNlTmFtZSA9IHRyaW1tZWROYW1lLnNwbGl0KCctLScpWzBdLnRyaW0oKTtcclxuICAgIGlmIChDT1JFX0lDT05TW2Jhc2VOYW1lXSkge1xyXG4gICAgICB0aGlzLnJlbmRlclN2Z1RvQ29udGFpbmVyKGNvbnRhaW5lciwgQ09SRV9JQ09OU1tiYXNlTmFtZV0sIGNvbG9yLCBzaXplLCBiYXNlTmFtZSwgZGlzYWJsZWQpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTm8gZmFsbGJhY2sgdG8gSFRUUFxyXG4gICAgY29uc29sZS53YXJuKGBbZm4taW5wdXRdIEljb24gXCIke25hbWV9XCIgbm90IGZvdW5kIGluIGNvcmUgcmVnaXN0cnkgYW5kIG5vIHJhdyBTVkcgcHJvdmlkZWQuYCk7XHJcbiAgICBjb250YWluZXIuaW5uZXJIVE1MID0gJyc7XHJcbiAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlbmRlclN2Z1RvQ29udGFpbmVyKFxyXG4gICAgY29udGFpbmVyOiBIVE1MRWxlbWVudCxcclxuICAgIHJhdzogc3RyaW5nLFxyXG4gICAgY29sb3I6IHN0cmluZyB8IG51bGwgfCB1bmRlZmluZWQsXHJcbiAgICBzaXplOiBudW1iZXIsXHJcbiAgICBuYW1lOiBzdHJpbmcsXHJcbiAgICBkaXNhYmxlZD86IGJvb2xlYW4sXHJcbiAgKTogdm9pZCB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjb25zdCBwYXJzZXIgPSBuZXcgRE9NUGFyc2VyKCk7XHJcbiAgICAgIGNvbnN0IGRvYyA9IHBhcnNlci5wYXJzZUZyb21TdHJpbmcocmF3LCAnaW1hZ2Uvc3ZnK3htbCcpO1xyXG4gICAgICBjb25zdCBzdmcgPSBkb2MucXVlcnlTZWxlY3Rvcignc3ZnJykgYXMgdW5rbm93biBhcyBTVkdTVkdFbGVtZW50O1xyXG5cclxuICAgICAgaWYgKCFzdmcpIHtcclxuICAgICAgICBjb250YWluZXIuaW5uZXJIVE1MID0gJyc7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBTVkcgTm9ybWFsaXphdGlvbiBsb2dpY1xyXG4gICAgICBmb3IgKGNvbnN0IHMgb2Ygc3ZnLnF1ZXJ5U2VsZWN0b3JBbGwoJ3N0eWxlJykpIHMucmVtb3ZlKCk7XHJcblxyXG4gICAgICBpZiAoY29sb3IpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IGVsIG9mIHN2Zy5xdWVyeVNlbGVjdG9yQWxsPFNWR0VsZW1lbnQ+KCcqJykpIHtcclxuICAgICAgICAgIGNvbnN0IHN0eWxlID0gZWwuZ2V0QXR0cmlidXRlKCdzdHlsZScpO1xyXG4gICAgICAgICAgaWYgKHN0eWxlKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGNsZWFuZWQgPSBzdHlsZVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlQWxsKC9maWxsXFxzKjpcXHMqW147XSs7Py9naSwgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2VBbGwoL3N0cm9rZVxccyo6XFxzKlteO10rOz8vZ2ksICcnKTtcclxuICAgICAgICAgICAgaWYgKGNsZWFuZWQpIGVsLnNldEF0dHJpYnV0ZSgnc3R5bGUnLCBjbGVhbmVkKTtcclxuICAgICAgICAgICAgZWxzZSBlbC5yZW1vdmVBdHRyaWJ1dGUoJ3N0eWxlJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgY29uc3QgZmlsbCA9IGVsLmdldEF0dHJpYnV0ZSgnZmlsbCcpO1xyXG4gICAgICAgICAgaWYgKGZpbGwgJiYgZmlsbCAhPT0gJ25vbmUnICYmICFmaWxsLnN0YXJ0c1dpdGgoJ3VybCgnKSkge1xyXG4gICAgICAgICAgICBlbC5zZXRBdHRyaWJ1dGUoJ2ZpbGwnLCAnY3VycmVudENvbG9yJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgY29uc3Qgc3Ryb2tlID0gZWwuZ2V0QXR0cmlidXRlKCdzdHJva2UnKTtcclxuICAgICAgICAgIGlmIChzdHJva2UgJiYgc3Ryb2tlICE9PSAnbm9uZScgJiYgIXN0cm9rZS5zdGFydHNXaXRoKCd1cmwoJykpIHtcclxuICAgICAgICAgICAgZWwuc2V0QXR0cmlidXRlKCdzdHJva2UnLCAnY3VycmVudENvbG9yJyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBzdmcucmVtb3ZlQXR0cmlidXRlKCd3aWR0aCcpO1xyXG4gICAgICBzdmcucmVtb3ZlQXR0cmlidXRlKCdoZWlnaHQnKTtcclxuICAgICAgaWYgKCFzdmcuZ2V0QXR0cmlidXRlKCd2aWV3Qm94JykpIHtcclxuICAgICAgICBzdmcuc2V0QXR0cmlidXRlKCd2aWV3Qm94JywgYDAgMCAke3NpemV9ICR7c2l6ZX1gKTtcclxuICAgICAgfVxyXG4gICAgICBzdmcuc2V0QXR0cmlidXRlKCdwcmVzZXJ2ZUFzcGVjdFJhdGlvJywgJ3hNaWRZTWlkIG1lZXQnKTtcclxuICAgICAgc3ZnLnNldEF0dHJpYnV0ZSgnZm9jdXNhYmxlJywgJ2ZhbHNlJyk7XHJcbiAgICAgIHN2Zy5zZXRBdHRyaWJ1dGUoJ2FyaWEtaGlkZGVuJywgJ3RydWUnKTtcclxuICAgICAgc3ZnLnNldEF0dHJpYnV0ZSgnd2lkdGgnLCAnMTAwJScpO1xyXG4gICAgICBzdmcuc2V0QXR0cmlidXRlKCdoZWlnaHQnLCAnMTAwJScpO1xyXG5cclxuICAgICAgY29uc3Qgc3R5bGUgPSBgO2Rpc3BsYXk6YmxvY2s7bWF4LXdpZHRoOjEwMCU7bWF4LWhlaWdodDoxMDAlO2A7XHJcbiAgICAgIHN2Zy5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgKHN2Zy5nZXRBdHRyaWJ1dGUoJ3N0eWxlJykgfHwgJycpICsgc3R5bGUpO1xyXG5cclxuICAgICAgY29udGFpbmVyLmlubmVySFRNTCA9ICcnO1xyXG4gICAgICBpZiAoY29sb3IpIHtcclxuICAgICAgICBjb250YWluZXIuc3R5bGUuY29sb3IgPSBjb2xvcjtcclxuICAgICAgfVxyXG4gICAgICBpZiAoZGlzYWJsZWQpIHtcclxuICAgICAgICBjb250YWluZXIuc3R5bGUub3BhY2l0eSA9ICcwLjUnO1xyXG4gICAgICAgIGNvbnRhaW5lci5zdHlsZS5jdXJzb3IgPSAnbm90LWFsbG93ZWQnO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnRhaW5lci5zdHlsZS5vcGFjaXR5ID0gJzEnO1xyXG4gICAgICAgIGNvbnRhaW5lci5zdHlsZS5jdXJzb3IgPSAnJztcclxuICAgICAgfVxyXG4gICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoc3ZnKTtcclxuICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgY29uc29sZS5lcnJvcihgW2ZuLWlucHV0XSBFcnJvciBwYXJzaW5nIFNWRyBmb3IgaWNvbiBcIiR7bmFtZX1cIjpgLCBlcnJvcik7XHJcbiAgICAgIGNvbnRhaW5lci5pbm5lckhUTUwgPSAnJztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJlbW92ZWQgZ2V0SWNvblBhdGggYXMgSFRUUCBsb2FkaW5nIGlzIGRpc2FibGVkXHJcblxyXG4gIC8vIC0tLSBNRVNTQUdFIExPR0lDIC0tLVxyXG4gIGdldEZpZWxkTWVzc2FnZSgpOiBzdHJpbmcge1xyXG4gICAgaWYgKCF0aGlzLmNvbnRyb2wpIHJldHVybiB0aGlzLmZpZWxkPy5oZWxwZXJUZXh0IHx8ICcnO1xyXG5cclxuICAgIGlmICh0aGlzLmNvbnRyb2wudG91Y2hlZCAmJiB0aGlzLmNvbnRyb2wuZXJyb3JzKSB7XHJcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHRoaXMuY29udHJvbC5lcnJvcnMpKSB7XHJcbiAgICAgICAgY29uc3QgZXJyb3JWYWx1ZSA9IHRoaXMuY29udHJvbC5lcnJvcnNba2V5XTtcclxuICAgICAgICBpZiAoZXJyb3JWYWx1ZSAmJiB0eXBlb2YgZXJyb3JWYWx1ZSA9PT0gJ29iamVjdCcgJiYgZXJyb3JWYWx1ZS5tZXNzYWdlKSB7XHJcbiAgICAgICAgICByZXR1cm4gZXJyb3JWYWx1ZS5tZXNzYWdlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodGhpcy5maWVsZD8uZXJyb3JzPy5ba2V5XSkge1xyXG4gICAgICAgICAgcmV0dXJuIHRoaXMuZmllbGQuZXJyb3JzW2tleV07XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiAoXHJcbiAgICAgICAgdGhpcy5maWVsZD8uZXJyb3JzPy5bJ2RlZmF1bHQnXSB8fFxyXG4gICAgICAgICdQbGVhc2UgZW50ZXIgJyArIHRoaXMudHJhbnNsYXRlU2VydmljZS5pbnN0YW50KHRoaXMuZmllbGQ/LmxhYmVsKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzLmZpZWxkPy5oZWxwZXJUZXh0IHx8ICcnO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGlzRXJyb3IoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gISEodGhpcy5jb250cm9sPy50b3VjaGVkICYmIHRoaXMuY29udHJvbD8uZXJyb3JzKTtcclxuICB9XHJcblxyXG4gIGdldCBpc1N1Y2Nlc3MoKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gISEodGhpcy5jb250cm9sPy52YWxpZCAmJiB0aGlzLmNvbnRyb2w/LnRvdWNoZWQpO1xyXG4gIH1cclxufVxyXG4iLCJAaWYgKGZpZWxkLm5hbWUgJiYgaXNWaXNpYmxlKCkgJiYgIWZpZWxkLmhpZGRlbikge1xyXG4gIDxkaXYgY2xhc3M9XCJmbi1pbnB1dC1jb250YWluZXJcIj5cclxuICAgIEBpZiAoZmllbGQudHlwZSEgIT09ICdoaWRkZW4nKSB7XHJcbiAgICAgIDxmbi1sYWJlbFxyXG4gICAgICAgIFtmb3JdPVwidW5pcXVlSWRcIlxyXG4gICAgICAgIFtsYWJlbF09XCJmaWVsZC5sYWJlbFwiXHJcbiAgICAgICAgW3JlcXVpcmVkXT1cImZpZWxkLnJlcXVpcmVkIHx8IGZhbHNlXCJcclxuICAgICAgICBbaGlkZU9wdGlvbmFsXT1cImZpZWxkLmhpZGVPcHRpb25hbCB8fCBmYWxzZVwiXHJcbiAgICAgICAgW2NvbG9yXT1cImZpZWxkLmNvbG9yIHx8ICcjMDMxODJiJ1wiXHJcbiAgICAgICAgW3ZhcmlhbnRdPVwiZmllbGQubGFiZWxWYXJpYW50IHx8ICdwMSdcIlxyXG4gICAgICAgIFtzdGF0dXNMYWJlbF09XCJmaWVsZC5zdGF0dXNMYWJlbFwiXHJcbiAgICAgID48L2ZuLWxhYmVsPlxyXG4gICAgfVxyXG5cclxuICAgIDxuZy1jb250YWluZXI+XHJcbiAgICAgIEBzd2l0Y2ggKGZpZWxkLnR5cGUpIHtcclxuICAgICAgICA8IS0tIFRleHRhcmVhIEZpZWxkIC0tPlxyXG4gICAgICAgIEBjYXNlICgndGV4dGFyZWEnKSB7XHJcbiAgICAgICAgICA8dGV4dGFyZWFcclxuICAgICAgICAgICAgI2ZuVGV4dGFyZWFcclxuICAgICAgICAgICAgc3R5bGU9XCJyZXNpemU6IG5vbmVcIlxyXG4gICAgICAgICAgICBbbmFtZV09XCJmaWVsZC5uYW1lXCJcclxuICAgICAgICAgICAgW2lkXT1cInVuaXF1ZUlkXCJcclxuICAgICAgICAgICAgW3JlcXVpcmVkXT1cImZpZWxkLnJlcXVpcmVkIHx8IGZhbHNlXCJcclxuICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cImZpZWxkLnBsYWNlaG9sZGVyIHx8ICcnIHwgdHJhbnNsYXRlXCJcclxuICAgICAgICAgICAgW2Rpc2FibGVkXT1cImZpZWxkLmRpc2FibGVkIHx8IGZhbHNlXCJcclxuICAgICAgICAgICAgW3Jvd3NdPVwiZmllbGQucm93cyB8fCAxXCJcclxuICAgICAgICAgICAgW3JlYWRvbmx5XT1cImZpZWxkLnJlYWRPbmx5IHx8IGZhbHNlXCJcclxuICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImNvbnRyb2xcIlxyXG4gICAgICAgICAgICAoaW5wdXQpPVwiaGFuZGxlVGV4dEFyZWEoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgIChibHVyKT1cImhhbmRsZUJsdXIoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgIGNsYXNzPVwiZm4taW5wdXQtZmllbGRcIlxyXG4gICAgICAgICAgICBbbmdDbGFzc109XCJ7XHJcbiAgICAgICAgICAgICAgZGlzYWJsZWQ6IGNvbnRyb2wuZGlzYWJsZWQgfHwgZmllbGQucmVhZE9ubHksXHJcbiAgICAgICAgICAgICAgZXJyb3I6IGNvbnRyb2wudG91Y2hlZCAmJiBjb250cm9sLmVycm9ycyxcclxuICAgICAgICAgICAgICBzdWNjZXNzOiBmaWVsZFsnaGFzU3VjY2Vzc0JvcmRlciddICYmIGNvbnRyb2wudmFsaWQgJiYgIWNvbnRyb2wuZXJyb3JzLFxyXG4gICAgICAgICAgICB9XCJcclxuICAgICAgICAgICAgW25nU3R5bGVdPVwie1xyXG4gICAgICAgICAgICAgIGNvbG9yOiBmaWVsZC52YWx1ZUNvbG9yIHx8ICdpbmhlcml0JyxcclxuICAgICAgICAgICAgICAnZm9udC1zaXplJzogZmllbGQudmFsdWVTaXplIHx8ICcnLFxyXG4gICAgICAgICAgICB9XCJcclxuICAgICAgICAgICAgKGZvY3VzKT1cIm9uRm9jdXMoKVwiXHJcbiAgICAgICAgICA+PC90ZXh0YXJlYT5cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIDwhLS0gUGFzc3dvcmQgRmllbGQgLS0+XHJcbiAgICAgICAgQGNhc2UgKCdwYXNzd29yZCcpIHtcclxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJyZWxhdGl2ZSB3LWZ1bGxcIj5cclxuICAgICAgICAgICAgQGlmIChmaWVsZC5wcmVmaXg/Lmljb24gfHwgZmllbGQucHJlZml4Py50ZXh0KSB7XHJcbiAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJhYnNvbHV0ZSBsZWZ0LTAgdG9wLTEvMiAtdHJhbnNsYXRlLXktMS8yIHBsLTMgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTJcIlxyXG4gICAgICAgICAgICAgICAgc3R5bGU9XCJ6LWluZGV4OiAxXCJcclxuICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICBAaWYgKGZpZWxkLnByZWZpeD8uaWNvbikge1xyXG4gICAgICAgICAgICAgICAgICA8ZGl2XHJcbiAgICAgICAgICAgICAgICAgICAgI2ljb25Db250YWluZXJcclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImljb24tY29udGFpbmVyXCJcclxuICAgICAgICAgICAgICAgICAgICBbYXR0ci5kYXRhLWljb24tbmFtZV09XCJmaWVsZC5wcmVmaXghLmljb25cIlxyXG4gICAgICAgICAgICAgICAgICAgIGRhdGEtaWNvbi12YXJpYW50PVwiTGluZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLXNpemU9XCJtZWRpdW1cIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtaWNvbi1jb2xvcl09XCJjb250cm9sLmRpc2FibGVkID8gJyNjNGNkZDInIDogJyMwMzE4MmInXCJcclxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgQGlmIChmaWVsZC5wcmVmaXg/LnRleHQpIHtcclxuICAgICAgICAgICAgICAgICAgPHNwYW5cclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cInRleHQtc20gZm9udC1tZWRpdW0gd2hpdGVzcGFjZS1ub3dyYXBcIlxyXG4gICAgICAgICAgICAgICAgICAgIFtuZ1N0eWxlXT1cInsgY29sb3I6IGNvbnRyb2wuZGlzYWJsZWQgPyAnI2M0Y2RkMicgOiAnIzAzMTgyYicgfVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInByZWZpeENsaWNrKCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAgIChrZXlkb3duLmVudGVyKT1cInByZWZpeENsaWNrKCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLnRhYmluZGV4XT1cImZpZWxkLnByZWZpeD8ub25DbGljayA/IDAgOiBudWxsXCJcclxuICAgICAgICAgICAgICAgICAgICBbY2xhc3MuY3Vyc29yLXBvaW50ZXJdPVwiISFmaWVsZC5wcmVmaXg/Lm9uQ2xpY2tcIlxyXG4gICAgICAgICAgICAgICAgICAgID57eyBmaWVsZC5wcmVmaXghLnRleHQgfX08L3NwYW5cclxuICAgICAgICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgIFt0eXBlXT1cInNob3dQYXNzd29yZCA/ICd0ZXh0JyA6ICdwYXNzd29yZCdcIlxyXG4gICAgICAgICAgICAgIFtpZF09XCJ1bmlxdWVJZFwiXHJcbiAgICAgICAgICAgICAgW3JlcXVpcmVkXT1cImZpZWxkLnJlcXVpcmVkIHx8IGZhbHNlXCJcclxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiZmllbGQuZGlzYWJsZWQgfHwgZmFsc2VcIlxyXG4gICAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJjb250cm9sXCJcclxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiZmllbGQucGxhY2Vob2xkZXIgfHwgJycgfCB0cmFuc2xhdGVcIlxyXG4gICAgICAgICAgICAgIFtyZWFkb25seV09XCJmaWVsZC5yZWFkT25seSB8fCBmYWxzZVwiXHJcbiAgICAgICAgICAgICAgKGlucHV0KT1cImlzQWxwaGFudW1lcmljID8gaGFuZGxlQWxwaGFudW1lcmljSW5wdXQoJGV2ZW50KSA6IGhhbmRsZUlucHV0KCRldmVudClcIlxyXG4gICAgICAgICAgICAgIChmb2N1cyk9XCJvblBhc3N3b3JkRm9jdXMoKVwiXHJcbiAgICAgICAgICAgICAgKGJsdXIpPVwiaGFuZGxlUGFzc3dvcmRCbHVyKCRldmVudClcIlxyXG4gICAgICAgICAgICAgIGNsYXNzPVwiZm4taW5wdXQtZmllbGQgb3ZlcmZsb3ctaGlkZGVuIHRleHQtZWxsaXBzaXNcIlxyXG4gICAgICAgICAgICAgIFtuZ0NsYXNzXT1cIntcclxuICAgICAgICAgICAgICAgIGRpc2FibGVkOiBjb250cm9sLmRpc2FibGVkIHx8IGZpZWxkLnJlYWRPbmx5LFxyXG4gICAgICAgICAgICAgICAgZXJyb3I6IGNvbnRyb2wudG91Y2hlZCAmJiBjb250cm9sLmVycm9ycyxcclxuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IGZpZWxkWydoYXNTdWNjZXNzQm9yZGVyJ10gJiYgY29udHJvbC52YWxpZCxcclxuICAgICAgICAgICAgICAgICdwbC0xMCc6IGZpZWxkLnByZWZpeD8uaWNvbiAmJiAhZmllbGQucHJlZml4Py50ZXh0LFxyXG4gICAgICAgICAgICAgICAgJ2hhcy1wcmVmaXgtdGV4dCc6ICEhZmllbGQucHJlZml4Py50ZXh0LFxyXG4gICAgICAgICAgICAgICAgJ3ByLTEyJzpcclxuICAgICAgICAgICAgICAgICAgKGZpZWxkLnRvZ2dsZU1hc2sgJiYgIWZpZWxkLmlzQ29weVRleHQpIHx8XHJcbiAgICAgICAgICAgICAgICAgICghZmllbGQudG9nZ2xlTWFzayAmJiBmaWVsZC5pc0NvcHlUZXh0KSxcclxuICAgICAgICAgICAgICAgICdwci0yNCc6IGZpZWxkLnRvZ2dsZU1hc2sgJiYgZmllbGQuaXNDb3B5VGV4dCAmJiAhZmllbGQuaGFzR2VuZXJhdGVLZXksXHJcbiAgICAgICAgICAgICAgICAncHItMzInOiBmaWVsZC50b2dnbGVNYXNrICYmIGZpZWxkLmlzQ29weVRleHQgJiYgZmllbGQuaGFzR2VuZXJhdGVLZXksXHJcbiAgICAgICAgICAgICAgfVwiXHJcbiAgICAgICAgICAgICAgW25nU3R5bGVdPVwie1xyXG4gICAgICAgICAgICAgICAgY29sb3I6IGZpZWxkLnZhbHVlQ29sb3IgfHwgJ2luaGVyaXQnLFxyXG4gICAgICAgICAgICAgICAgJ2ZvbnQtc2l6ZSc6IGZpZWxkLnZhbHVlU2l6ZSB8fCAnJyxcclxuICAgICAgICAgICAgICB9XCJcclxuICAgICAgICAgICAgLz5cclxuXHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJhYnNvbHV0ZSByaWdodC0wIHRvcC0xLzIgLXRyYW5zbGF0ZS15LTEvMiBmbGV4IGl0ZW1zLWNlbnRlciBwci0zIGdhcC0yXCI+XHJcbiAgICAgICAgICAgICAgQGlmIChmaWVsZC50b2dnbGVNYXNrICYmICFmaWVsZC5pc0NvcHlUZXh0KSB7XHJcbiAgICAgICAgICAgICAgICA8c3BhblxyXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImN1cnNvci1wb2ludGVyXCJcclxuICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZVBhc3N3b3JkVmlzaWJpbGl0eSgpXCJcclxuICAgICAgICAgICAgICAgICAgKGtleWRvd24pPVwidG9nZ2xlUGFzc3dvcmRWaXNpYmlsaXR5KClcIlxyXG4gICAgICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgICAgICA8ZGl2XHJcbiAgICAgICAgICAgICAgICAgICAgI2ljb25Db250YWluZXJcclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImljb24tY29udGFpbmVyXCJcclxuICAgICAgICAgICAgICAgICAgICBbYXR0ci5kYXRhLWljb24tbmFtZV09XCJzaG93UGFzc3dvcmQgPyAnZXllLW9wZW4nIDogJ2V5ZS1jbG9zZSdcIlxyXG4gICAgICAgICAgICAgICAgICAgIGRhdGEtaWNvbi12YXJpYW50PVwiTGluZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLXNpemU9XCJsYXJnZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLWNvbG9yPVwiIzAzMTgyYlwiXHJcbiAgICAgICAgICAgICAgICAgID48L2Rpdj5cclxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cclxuICAgICAgICAgICAgICB9IEBlbHNlIGlmIChmaWVsZC5pc0NvcHlUZXh0ICYmICFmaWVsZC50b2dnbGVNYXNrKSB7XHJcbiAgICAgICAgICAgICAgICA8c3BhblxyXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImN1cnNvci1wb2ludGVyXCJcclxuICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cImNvcHlUZXh0KCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAoa2V5ZG93bik9XCJjb3B5VGV4dCgkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgICAgICNpY29uQ29udGFpbmVyXHJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJpY29uLWNvbnRhaW5lclwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLW5hbWU9XCJ0d28tc3F1YXJlXCJcclxuICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tY29sb3I9XCIjMDMxODJiXCJcclxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgQGlmIChmaWVsZC5oYXNHZW5lcmF0ZUtleSkge1xyXG4gICAgICAgICAgICAgICAgICA8c3BhblxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY3Vyc29yLXBvaW50ZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJmaWVsZC5vbkdlbmVyYXRlS2V5ICYmIGZpZWxkLm9uR2VuZXJhdGVLZXkoKVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKGtleWRvd24pPVwiZmllbGQub25HZW5lcmF0ZUtleSAmJiBmaWVsZC5vbkdlbmVyYXRlS2V5KClcIlxyXG4gICAgICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgICAgICAgI2ljb25Db250YWluZXJcclxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaWNvbi1jb250YWluZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLW5hbWU9XCJyb3VuZC1hcnJvdy10b3AtbGVmdFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tdmFyaWFudD1cIkxpbmVcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLXNpemU9XCJsYXJnZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tY29sb3I9XCIjMDMxODJiXCJcclxuICAgICAgICAgICAgICAgICAgICA+PC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9IEBlbHNlIGlmIChmaWVsZC50b2dnbGVNYXNrICYmIGZpZWxkLmlzQ29weVRleHQpIHtcclxuICAgICAgICAgICAgICAgIDxzcGFuXHJcbiAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY3Vyc29yLXBvaW50ZXJcIlxyXG4gICAgICAgICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlUGFzc3dvcmRWaXNpYmlsaXR5KClcIlxyXG4gICAgICAgICAgICAgICAgICAoa2V5ZG93bik9XCJ0b2dnbGVQYXNzd29yZFZpc2liaWxpdHkoKVwiXHJcbiAgICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgICAgICAgICAjaWNvbkNvbnRhaW5lclxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaWNvbi1jb250YWluZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtaWNvbi1uYW1lXT1cInNob3dQYXNzd29yZCA/ICdleWUtb3BlbicgOiAnZXllLWNsb3NlJ1wiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLXZhcmlhbnQ9XCJMaW5lXCJcclxuICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tc2l6ZT1cImxhcmdlXCJcclxuICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tY29sb3I9XCIjMDMxODJiXCJcclxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgPHNwYW5cclxuICAgICAgICAgICAgICAgICAgY2xhc3M9XCJjdXJzb3ItcG9pbnRlclwiXHJcbiAgICAgICAgICAgICAgICAgIChjbGljayk9XCJjb3B5VGV4dCgkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgICAgKGtleWRvd24pPVwiY29weVRleHQoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgICAgICAgICAjaWNvbkNvbnRhaW5lclxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaWNvbi1jb250YWluZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgIGRhdGEtaWNvbi1uYW1lPVwidHdvLXNxdWFyZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLWNvbG9yPVwiIzAzMTgyYlwiXHJcbiAgICAgICAgICAgICAgICAgID48L2Rpdj5cclxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIEBpZiAoZmllbGQuaGFzR2VuZXJhdGVLZXkpIHtcclxuICAgICAgICAgICAgICAgICAgPHNwYW5cclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImN1cnNvci1wb2ludGVyXCJcclxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiZmllbGQub25HZW5lcmF0ZUtleSAmJiBmaWVsZC5vbkdlbmVyYXRlS2V5KClcIlxyXG4gICAgICAgICAgICAgICAgICAgIChrZXlkb3duKT1cImZpZWxkLm9uR2VuZXJhdGVLZXkgJiYgZmllbGQub25HZW5lcmF0ZUtleSgpXCJcclxuICAgICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7ICdvcGFjaXR5LTUwIGN1cnNvci1ub3QtYWxsb3dlZCc6ICFjb250cm9sLnZhbHVlIH1cIlxyXG4gICAgICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgICAgICAgI2ljb25Db250YWluZXJcclxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaWNvbi1jb250YWluZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLW5hbWU9XCJyb3VuZC1hcnJvdy10b3AtbGVmdFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tY29sb3I9XCIjMDMxODJiXCJcclxuICAgICAgICAgICAgICAgICAgICA+PC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgQGlmIChmaWVsZC5mZWVkYmFjayAmJiBpc1Bhc3N3b3JkRm9jdXNlZCkge1xyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibXQtMiBzcGFjZS15LTFcIj5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIHRleHQteHNcIj5cclxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZm9udC1tZWRpdW1cIiBbbmdDbGFzc109XCJzdHJlbmd0aENsYXNzXCI+XHJcbiAgICAgICAgICAgICAgICAgIHt7IHBhc3N3b3JkU3RyZW5ndGhMYWJlbCB8IHRyYW5zbGF0ZSB9fVxyXG4gICAgICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZsZXggaXRlbXMtY2VudGVyIGdhcC0xXCI+XHJcbiAgICAgICAgICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgICAgICAgICAjaWNvbkNvbnRhaW5lclxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaWNvbi1jb250YWluZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtaWNvbi1uYW1lXT1cIlxyXG4gICAgICAgICAgICAgICAgICAgICAgcGFzc3dvcmRTdHJlbmd0aFBlcmNlbnQgPiA1MCA/ICdjaGVjay1jaXJjbGUnIDogJ2luZm8tY2lyY2xlJ1xyXG4gICAgICAgICAgICAgICAgICAgIFwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLXZhcmlhbnQ9XCJMaW5lXCJcclxuICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tc2l6ZT1cImV4dHJhc21hbGxcIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtaWNvbi1jb2xvcl09XCJcclxuICAgICAgICAgICAgICAgICAgICAgIHBhc3N3b3JkU3RyZW5ndGhQZXJjZW50IDw9IDI1XHJcbiAgICAgICAgICAgICAgICAgICAgICAgID8gJyNlZjNlNDInXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDogcGFzc3dvcmRTdHJlbmd0aFBlcmNlbnQgPD0gNzVcclxuICAgICAgICAgICAgICAgICAgICAgICAgICA/ICcjZmY5ZjAwJ1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgIDogJyM2Y2MyNGEnXHJcbiAgICAgICAgICAgICAgICAgICAgXCJcclxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImgtMS41IHctZnVsbCBiZy1bI2VlZjBmMl0gcm91bmRlZC1mdWxsIG92ZXJmbG93LWhpZGRlblwiPlxyXG4gICAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImgtZnVsbCB0cmFuc2l0aW9uLWFsbCBkdXJhdGlvbi0zMDAgcm91bmRlZC1mdWxsXCJcclxuICAgICAgICAgICAgICAgICAgW25nQ2xhc3NdPVwie1xyXG4gICAgICAgICAgICAgICAgICAgICdiZy1bI2VmM2U0Ml0nOiBwYXNzd29yZFN0cmVuZ3RoUGVyY2VudCA8PSAyNSxcclxuICAgICAgICAgICAgICAgICAgICAnYmctWyNmZjlmMDBdJzogcGFzc3dvcmRTdHJlbmd0aFBlcmNlbnQgPiAyNSAmJiBwYXNzd29yZFN0cmVuZ3RoUGVyY2VudCA8PSA3NSxcclxuICAgICAgICAgICAgICAgICAgICAnYmctWyM2Y2MyNGFdJzogcGFzc3dvcmRTdHJlbmd0aFBlcmNlbnQgPiA3NSxcclxuICAgICAgICAgICAgICAgICAgfVwiXHJcbiAgICAgICAgICAgICAgICAgIFtzdHlsZS53aWR0aC4lXT1cInBhc3N3b3JkU3RyZW5ndGhQZXJjZW50XCJcclxuICAgICAgICAgICAgICAgID48L2Rpdj5cclxuICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICA8IS0tIE51bWJlciBGaWVsZCAtLT5cclxuICAgICAgICBAY2FzZSAoJ251bWJlcicpIHtcclxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJyZWxhdGl2ZSB3LWZ1bGxcIj5cclxuICAgICAgICAgICAgQGlmIChmaWVsZC5wcmVmaXg/Lmljb24gfHwgZmllbGQucHJlZml4Py50ZXh0KSB7XHJcbiAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJhYnNvbHV0ZSBsZWZ0LTAgdG9wLTEvMiAtdHJhbnNsYXRlLXktMS8yIHBsLTMgZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTJcIlxyXG4gICAgICAgICAgICAgICAgc3R5bGU9XCJ6LWluZGV4OiAxXCJcclxuICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICBAaWYgKGZpZWxkLnByZWZpeD8uaWNvbikge1xyXG4gICAgICAgICAgICAgICAgICA8ZGl2XHJcbiAgICAgICAgICAgICAgICAgICAgI2ljb25Db250YWluZXJcclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImljb24tY29udGFpbmVyXCJcclxuICAgICAgICAgICAgICAgICAgICBbYXR0ci5kYXRhLWljb24tbmFtZV09XCJmaWVsZC5wcmVmaXghLmljb25cIlxyXG4gICAgICAgICAgICAgICAgICAgIGRhdGEtaWNvbi12YXJpYW50PVwiTGluZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLXNpemU9XCJtZWRpdW1cIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtaWNvbi1jb2xvcl09XCJjb250cm9sLmRpc2FibGVkID8gJyNjNGNkZDInIDogJyMwMzE4MmInXCJcclxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgQGlmIChmaWVsZC5wcmVmaXg/LnRleHQpIHtcclxuICAgICAgICAgICAgICAgICAgPHNwYW5cclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cInRleHQtc20gZm9udC1tZWRpdW0gd2hpdGVzcGFjZS1ub3dyYXBcIlxyXG4gICAgICAgICAgICAgICAgICAgIFtuZ1N0eWxlXT1cInsgY29sb3I6IGNvbnRyb2wuZGlzYWJsZWQgPyAnI2M0Y2RkMicgOiAnIzAzMTgyYicgfVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInByZWZpeENsaWNrKCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAgIChrZXlkb3duLmVudGVyKT1cInByZWZpeENsaWNrKCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLnRhYmluZGV4XT1cImZpZWxkLnByZWZpeD8ub25DbGljayA/IDAgOiBudWxsXCJcclxuICAgICAgICAgICAgICAgICAgICBbY2xhc3MuY3Vyc29yLXBvaW50ZXJdPVwiISFmaWVsZC5wcmVmaXg/Lm9uQ2xpY2tcIlxyXG4gICAgICAgICAgICAgICAgICAgID57eyBmaWVsZC5wcmVmaXghLnRleHQgfX08L3NwYW5cclxuICAgICAgICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgIFt0eXBlXT1cImZpZWxkLnR5cGUgPT09ICdudW1iZXInICYmIGZpZWxkLmlzQ3VycmVuY3kgPyAndGV4dCcgOiAnbnVtYmVyJ1wiXHJcbiAgICAgICAgICAgICAgW25hbWVdPVwiZmllbGQubmFtZVwiXHJcbiAgICAgICAgICAgICAgW2lkXT1cInVuaXF1ZUlkXCJcclxuICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwiZmllbGQucmVxdWlyZWQgfHwgZmFsc2VcIlxyXG4gICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJmaWVsZC5wbGFjZWhvbGRlciB8fCAnJyB8IHRyYW5zbGF0ZVwiXHJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImlzRGlzYWJsZWQgfHwgZmFsc2VcIlxyXG4gICAgICAgICAgICAgIFtyZWFkT25seV09XCJmaWVsZC5yZWFkT25seSB8fCBmYWxzZVwiXHJcbiAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImNvbnRyb2xcIlxyXG4gICAgICAgICAgICAgIFttaW5dPVwiZmllbGQudHlwZSA9PT0gJ251bWJlcicgJiYgIWZpZWxkLmlzQ3VycmVuY3kgPyAwIDogbnVsbFwiXHJcbiAgICAgICAgICAgICAgW21heF09XCJmaWVsZC50eXBlID09PSAnbnVtYmVyJyAmJiAhZmllbGQuaXNDdXJyZW5jeSA/IGZpZWxkLm1heCA6IG51bGxcIlxyXG4gICAgICAgICAgICAgIFtzdGVwXT1cImZpZWxkLnR5cGUgPT09ICdudW1iZXInICYmICFmaWVsZC5pc0N1cnJlbmN5ID8gZmllbGQuc3RlcCB8fCAxIDogbnVsbFwiXHJcbiAgICAgICAgICAgICAgKGlucHV0KT1cImhhbmRsZU51bWJlcklucHV0KCRldmVudCwgZmllbGQubWluRnJhY3Rpb25EaWdpdHMgfHwgMilcIlxyXG4gICAgICAgICAgICAgIChwYXN0ZSk9XCJoYW5kbGVOdW1iZXJQYXN0ZSgkZXZlbnQsIGZpZWxkLm1pbkZyYWN0aW9uRGlnaXRzIHx8IDIpXCJcclxuICAgICAgICAgICAgICAoYmx1cik9XCJoYW5kbGVCbHVyKCRldmVudCwgZmllbGQubWluRnJhY3Rpb25EaWdpdHMgfHwgMilcIlxyXG4gICAgICAgICAgICAgIChrZXlkb3duKT1cImhhbmRsZU51bWJlcktleWRvd24oJGV2ZW50LCBmaWVsZC5pc0N1cnJlbmN5IHx8IGZhbHNlKVwiXHJcbiAgICAgICAgICAgICAgY2xhc3M9XCJmbi1pbnB1dC1maWVsZFwiXHJcbiAgICAgICAgICAgICAgW25nQ2xhc3NdPVwie1xyXG4gICAgICAgICAgICAgICAgZGlzYWJsZWQ6IGNvbnRyb2wuZGlzYWJsZWQgfHwgZmllbGQucmVhZE9ubHksXHJcbiAgICAgICAgICAgICAgICBlcnJvcjogY29udHJvbC50b3VjaGVkICYmIGNvbnRyb2wuZXJyb3JzLFxyXG4gICAgICAgICAgICAgICAgc3VjY2VzczogZmllbGRbJ2hhc1N1Y2Nlc3NCb3JkZXInXSAmJiBjb250cm9sLnZhbGlkICYmICFjb250cm9sLmVycm9ycyxcclxuICAgICAgICAgICAgICAgICdwbC0xMCc6IGZpZWxkLnByZWZpeD8uaWNvbiAmJiAhZmllbGQucHJlZml4Py50ZXh0LFxyXG4gICAgICAgICAgICAgICAgJ2hhcy1wcmVmaXgtdGV4dCc6ICEhZmllbGQucHJlZml4Py50ZXh0LFxyXG4gICAgICAgICAgICAgICAgJ3ByLTEwJzogZmllbGQuc3VmZml4Py5pY29uICYmICFmaWVsZC5zdWZmaXg/LnRleHQsXHJcbiAgICAgICAgICAgICAgICAnaGFzLXN1ZmZpeC10ZXh0JzogISFmaWVsZC5zdWZmaXg/LnRleHQsXHJcbiAgICAgICAgICAgICAgICAndGV4dC1bMjRweF0gZm9udC1ib2xkJzogZmllbGQuaXNDdXJyZW5jeSxcclxuICAgICAgICAgICAgICB9XCJcclxuICAgICAgICAgICAgICBbbmdTdHlsZV09XCJ7XHJcbiAgICAgICAgICAgICAgICBjb2xvcjogZmllbGQudmFsdWVDb2xvciB8fCAnaW5oZXJpdCcsXHJcbiAgICAgICAgICAgICAgICAnZm9udC1zaXplJzogZmllbGQudmFsdWVTaXplIHx8ICcnLFxyXG4gICAgICAgICAgICAgIH1cIlxyXG4gICAgICAgICAgICAgIChmb2N1cyk9XCJvbkZvY3VzKClcIlxyXG4gICAgICAgICAgICAvPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICA8IS0tIERlZmF1bHQgSW5wdXQgRmllbGQgKHRleHQsIGVtYWlsLCBldGMuKSAtLT5cclxuICAgICAgICBAZGVmYXVsdCB7XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwicmVsYXRpdmUgei0wXCI+XHJcbiAgICAgICAgICAgIEBpZiAoZmllbGQucHJlZml4Py5pY29uIHx8IGZpZWxkLnByZWZpeD8udGV4dCkge1xyXG4gICAgICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYWJzb2x1dGUgbGVmdC0wIHRvcC0xLzIgLXRyYW5zbGF0ZS15LTEvMiBwbC0zIGZsZXggaXRlbXMtY2VudGVyIGdhcC0yXCJcclxuICAgICAgICAgICAgICAgIHN0eWxlPVwiei1pbmRleDogMVwiXHJcbiAgICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgICAgQGlmIChmaWVsZC5wcmVmaXg/Lmljb24pIHtcclxuICAgICAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgICAgICNpY29uQ29udGFpbmVyXHJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJpY29uLWNvbnRhaW5lclwiXHJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuZGF0YS1pY29uLW5hbWVdPVwiZmllbGQucHJlZml4IS5pY29uXCJcclxuICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tdmFyaWFudD1cIkxpbmVcIlxyXG4gICAgICAgICAgICAgICAgICAgIGRhdGEtaWNvbi1zaXplPVwibWVkaXVtXCJcclxuICAgICAgICAgICAgICAgICAgICBbYXR0ci5kYXRhLWljb24tY29sb3JdPVwiY29udHJvbC5kaXNhYmxlZCA/ICcjYzRjZGQyJyA6ICcjMDMxODJiJ1wiXHJcbiAgICAgICAgICAgICAgICAgID48L2Rpdj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIEBpZiAoZmllbGQucHJlZml4Py50ZXh0KSB7XHJcbiAgICAgICAgICAgICAgICAgIDxzcGFuXHJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJ0ZXh0LXNtIGZvbnQtbWVkaXVtIHdoaXRlc3BhY2Utbm93cmFwXCJcclxuICAgICAgICAgICAgICAgICAgICBbbmdTdHlsZV09XCJ7IGNvbG9yOiBjb250cm9sLmRpc2FibGVkID8gJyNjNGNkZDInIDogJyMwMzE4MmInIH1cIlxyXG4gICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJwcmVmaXhDbGljaygkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgICAgICAoa2V5ZG93bi5lbnRlcik9XCJwcmVmaXhDbGljaygkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgICAgICBbYXR0ci50YWJpbmRleF09XCJmaWVsZC5wcmVmaXg/Lm9uQ2xpY2sgPyAwIDogbnVsbFwiXHJcbiAgICAgICAgICAgICAgICAgICAgW2NsYXNzLmN1cnNvci1wb2ludGVyXT1cIiEhZmllbGQucHJlZml4Py5vbkNsaWNrXCJcclxuICAgICAgICAgICAgICAgICAgICA+e3sgZmllbGQucHJlZml4IS50ZXh0IH19PC9zcGFuXHJcbiAgICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICBbdHlwZV09XCJmaWVsZC50eXBlXCJcclxuICAgICAgICAgICAgICBbbmFtZV09XCJmaWVsZC5uYW1lXCJcclxuICAgICAgICAgICAgICBbaWRdPVwidW5pcXVlSWRcIlxyXG4gICAgICAgICAgICAgIFtyZXF1aXJlZF09XCJmaWVsZC5yZXF1aXJlZCB8fCBmYWxzZVwiXHJcbiAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cImZpZWxkLnBsYWNlaG9sZGVyIHx8ICcnIHwgdHJhbnNsYXRlXCJcclxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiZmllbGQuZGlzYWJsZWQgfHwgZmFsc2VcIlxyXG4gICAgICAgICAgICAgIFtyZWFkT25seV09XCJmaWVsZC5yZWFkT25seSB8fCBmYWxzZVwiXHJcbiAgICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImNvbnRyb2xcIlxyXG4gICAgICAgICAgICAgIChpbnB1dCk9XCJcclxuICAgICAgICAgICAgICAgIGlzRW1haWxGaWVsZFxyXG4gICAgICAgICAgICAgICAgICA/IGhhbmRsZUVtYWlsSW5wdXQoJGV2ZW50KVxyXG4gICAgICAgICAgICAgICAgICA6IGZpZWxkLnR5cGUgPT09ICd0ZXh0JyAmJiBpc0FscGhhbnVtZXJpY1xyXG4gICAgICAgICAgICAgICAgICAgID8gaGFuZGxlQWxwaGFudW1lcmljSW5wdXQoJGV2ZW50KVxyXG4gICAgICAgICAgICAgICAgICAgIDogaGFuZGxlSW5wdXQoJGV2ZW50KVxyXG4gICAgICAgICAgICAgIFwiXHJcbiAgICAgICAgICAgICAgKGJsdXIpPVwiaGFuZGxlQmx1cigkZXZlbnQpXCJcclxuICAgICAgICAgICAgICBjbGFzcz1cImZuLWlucHV0LWZpZWxkXCJcclxuICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7XHJcbiAgICAgICAgICAgICAgICBkaXNhYmxlZDogY29udHJvbC5kaXNhYmxlZCB8fCBmaWVsZC5yZWFkT25seSxcclxuICAgICAgICAgICAgICAgIGVycm9yOiBjb250cm9sLnRvdWNoZWQgJiYgY29udHJvbC5lcnJvcnMsXHJcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiBmaWVsZFsnaGFzU3VjY2Vzc0JvcmRlciddICYmIGNvbnRyb2wudmFsaWQgJiYgIWNvbnRyb2wuZXJyb3JzLFxyXG4gICAgICAgICAgICAgICAgJ3BsLTEwJzogZmllbGQucHJlZml4Py5pY29uICYmICFmaWVsZC5wcmVmaXg/LnRleHQsXHJcbiAgICAgICAgICAgICAgICAnaGFzLXByZWZpeC10ZXh0JzogISFmaWVsZC5wcmVmaXg/LnRleHQsXHJcbiAgICAgICAgICAgICAgICAncHItMTAnOlxyXG4gICAgICAgICAgICAgICAgICAoZmllbGQuaWNvbiB8fCBmaWVsZC5zdWZmaXg/Lmljb24pICYmICFmaWVsZC5pc0NvcHlUZXh0ICYmICFmaWVsZC5zdWZmaXg/LnRleHQsXHJcbiAgICAgICAgICAgICAgICAnaGFzLXN1ZmZpeC10ZXh0JzogISFmaWVsZC5zdWZmaXg/LnRleHQsXHJcbiAgICAgICAgICAgICAgICAncHItMjAnOlxyXG4gICAgICAgICAgICAgICAgICBmaWVsZC5pc0NvcHlUZXh0ICYmICFmaWVsZC5oYXNHZW5lcmF0ZUtleSAmJiAhKGZpZWxkLmljb24gfHwgZmllbGQuc3VmZml4Py5pY29uKSxcclxuICAgICAgICAgICAgICAgICdwci0zMCc6XHJcbiAgICAgICAgICAgICAgICAgIGZpZWxkLmlzQ29weVRleHQgJiYgZmllbGQuaGFzR2VuZXJhdGVLZXkgJiYgIShmaWVsZC5pY29uIHx8IGZpZWxkLnN1ZmZpeD8uaWNvbiksXHJcbiAgICAgICAgICAgICAgICAncHItMzInOlxyXG4gICAgICAgICAgICAgICAgICBmaWVsZC5pc0NvcHlUZXh0ICYmIGZpZWxkLmhhc0dlbmVyYXRlS2V5ICYmIChmaWVsZC5pY29uIHx8IGZpZWxkLnN1ZmZpeD8uaWNvbiksXHJcbiAgICAgICAgICAgICAgfVwiXHJcbiAgICAgICAgICAgICAgW25nU3R5bGVdPVwie1xyXG4gICAgICAgICAgICAgICAgY29sb3I6IGZpZWxkLnZhbHVlQ29sb3IgfHwgJ2luaGVyaXQnLFxyXG4gICAgICAgICAgICAgICAgJ2ZvbnQtc2l6ZSc6IGZpZWxkLnZhbHVlU2l6ZSB8fCAnJyxcclxuICAgICAgICAgICAgICB9XCJcclxuICAgICAgICAgICAgICAoZm9jdXMpPVwib25Gb2N1cygpXCJcclxuICAgICAgICAgICAgLz5cclxuXHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJhYnNvbHV0ZSByaWdodC0wIHRvcC0xLzIgLXRyYW5zbGF0ZS15LTEvMiBmbGV4IGl0ZW1zLWNlbnRlciBwci0zIGdhcC0yXCI+XHJcbiAgICAgICAgICAgICAgQGlmIChmaWVsZC5pc0NvcHlUZXh0KSB7XHJcbiAgICAgICAgICAgICAgICA8c3BhblxyXG4gICAgICAgICAgICAgICAgICBjbGFzcz1cImN1cnNvci1wb2ludGVyXCJcclxuICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cImNvcHlUZXh0KCRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAoa2V5ZG93bik9XCJjb3B5VGV4dCgkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgICAgICNpY29uQ29udGFpbmVyXHJcbiAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJpY29uLWNvbnRhaW5lclwiXHJcbiAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLW5hbWU9XCJ0d28tc3F1YXJlXCJcclxuICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tY29sb3I9XCIjMDMxODJiXCJcclxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgQGlmIChmaWVsZC5oYXNHZW5lcmF0ZUtleSkge1xyXG4gICAgICAgICAgICAgICAgICA8c3BhblxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiY3Vyc29yLXBvaW50ZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgIChjbGljayk9XCJmaWVsZC5vbkdlbmVyYXRlS2V5ICYmIGZpZWxkLm9uR2VuZXJhdGVLZXkoKVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKGtleWRvd24pPVwiZmllbGQub25HZW5lcmF0ZUtleSAmJiBmaWVsZC5vbkdlbmVyYXRlS2V5KClcIlxyXG4gICAgICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAgICAgICAgICAgI2ljb25Db250YWluZXJcclxuICAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaWNvbi1jb250YWluZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgZGF0YS1pY29uLW5hbWU9XCJyb3VuZC1hcnJvdy10b3AtbGVmdFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBkYXRhLWljb24tY29sb3I9XCIjMDMxODJiXCJcclxuICAgICAgICAgICAgICAgICAgICA+PC9kaXY+XHJcbiAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIEBpZiAoZmllbGQuaWNvbiB8fCBmaWVsZC5zdWZmaXg/Lmljb24gfHwgZmllbGQuc3VmZml4Py50ZXh0KSB7XHJcbiAgICAgICAgICAgICAgICBAaWYgKGZpZWxkLnN1ZmZpeD8udGV4dCkge1xyXG4gICAgICAgICAgICAgICAgICA8c3BhblxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwidGV4dC1zbSBmb250LW1lZGl1bSB3aGl0ZXNwYWNlLW5vd3JhcFwiXHJcbiAgICAgICAgICAgICAgICAgICAgW25nU3R5bGVdPVwieyBjb2xvcjogY29udHJvbC5kaXNhYmxlZCA/ICcjYzRjZGQyJyA6ICcjMDMxODJiJyB9XCJcclxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwic3VmZml4Q2xpY2soJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICAgICAgKGtleWRvd24uZW50ZXIpPVwic3VmZml4Q2xpY2soJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIudGFiaW5kZXhdPVwiZmllbGQuc3VmZml4Py5vbkNsaWNrID8gMCA6IG51bGxcIlxyXG4gICAgICAgICAgICAgICAgICAgIFtjbGFzcy5jdXJzb3ItcG9pbnRlcl09XCIhIWZpZWxkLnN1ZmZpeD8ub25DbGlja1wiXHJcbiAgICAgICAgICAgICAgICAgICAgPnt7IGZpZWxkLnN1ZmZpeCEudGV4dCB9fTwvc3BhblxyXG4gICAgICAgICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBAaWYgKGZpZWxkLmljb24gfHwgZmllbGQuc3VmZml4Py5pY29uKSB7XHJcbiAgICAgICAgICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgICAgICAgICAjaWNvbkNvbnRhaW5lclxyXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaWNvbi1jb250YWluZXJcIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtaWNvbi1uYW1lXT1cImZpZWxkLnN1ZmZpeD8uaWNvbiB8fCBmaWVsZC5pY29uIS5uYW1lXCJcclxuICAgICAgICAgICAgICAgICAgICBbYXR0ci5kYXRhLWljb24tdmFyaWFudF09XCJmaWVsZC5pY29uPy52YXJpYW50IHx8ICdMaW5lJ1wiXHJcbiAgICAgICAgICAgICAgICAgICAgW2F0dHIuZGF0YS1pY29uLXNpemVdPVwiZmllbGQuaWNvbiA/IGdldEljb25TaXplTmFtZShmaWVsZC5pY29uLnNpemUpIDogJ21lZGl1bSdcIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtaWNvbi1jb2xvcl09XCJjb250cm9sLmRpc2FibGVkID8gJyNjNGNkZDInIDogJyMwMzE4MmInXCJcclxuICAgICAgICAgICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIDwvbmctY29udGFpbmVyPlxyXG5cclxuICAgIEBpZiAoc2hvd0Zvcm1GaWVsZE1lc3NhZ2UoY29udHJvbCwgaGVscGVyVGV4dCkpIHtcclxuICAgICAgPGRpdiBjbGFzcz1cImZuLWZpZWxkLW1lc3NhZ2UtY29udGFpbmVyXCI+XHJcbiAgICAgICAgPHNwYW5cclxuICAgICAgICAgIGNsYXNzPVwiZm4tZmllbGQtbWVzc2FnZS10ZXh0XCJcclxuICAgICAgICAgIFtuZ0NsYXNzXT1cIntcclxuICAgICAgICAgICAgZXJyb3I6IGlzRXJyb3IsXHJcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGlzU3VjY2VzcyxcclxuICAgICAgICAgIH1cIlxyXG4gICAgICAgID5cclxuICAgICAgICAgIHt7IGdldEZpZWxkTWVzc2FnZSgpIHwgdHJhbnNsYXRlIH19XHJcbiAgICAgICAgPC9zcGFuPlxyXG4gICAgICA8L2Rpdj5cclxuICAgIH1cclxuICA8L2Rpdj5cclxuXHJcbiAgPCEtLSBJbnRlZ3JhdGVkIFRvYXN0IE5vdGlmaWNhdGlvbnMgLS0+XHJcbiAgPGRpdiBjbGFzcz1cInRvYXN0LWNvbnRhaW5lclwiPlxyXG4gICAgQGZvciAodG9hc3Qgb2YgdG9hc3RzKCk7IHRyYWNrIHRvYXN0LmlkKSB7XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJ0b2FzdCB0b2FzdC17eyB0b2FzdC50eXBlIH19XCIgW2NsYXNzLnRvYXN0LWVudGVyXT1cInRvYXN0LmlzVmlzaWJsZVwiPlxyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwidG9hc3QtaWNvblwiPlxyXG4gICAgICAgICAgPGRpdlxyXG4gICAgICAgICAgICAjaWNvbkNvbnRhaW5lclxyXG4gICAgICAgICAgICBjbGFzcz1cImljb24tY29udGFpbmVyXCJcclxuICAgICAgICAgICAgW2F0dHIuZGF0YS1pY29uLW5hbWVdPVwiZ2V0VG9hc3RJY29uTmFtZSh0b2FzdClcIlxyXG4gICAgICAgICAgICBkYXRhLWljb24tdmFyaWFudD1cIkNvbG91clwiXHJcbiAgICAgICAgICAgIGRhdGEtaWNvbi1zaXplPVwibWVkaXVtXCJcclxuICAgICAgICAgICAgW2F0dHIuZGF0YS1pY29uLWNvbG9yXT1cIlxyXG4gICAgICAgICAgICAgIHRvYXN0LnR5cGUgPT09ICdzdWNjZXNzJ1xyXG4gICAgICAgICAgICAgICAgPyAnIzZjYzI0YSdcclxuICAgICAgICAgICAgICAgIDogdG9hc3QudHlwZSA9PT0gJ3dhcm4nXHJcbiAgICAgICAgICAgICAgICAgID8gJyNmZjlmMDAnXHJcbiAgICAgICAgICAgICAgICAgIDogdG9hc3QudHlwZSA9PT0gJ2Vycm9yJ1xyXG4gICAgICAgICAgICAgICAgICAgID8gJyNlZjNlNDInXHJcbiAgICAgICAgICAgICAgICAgICAgOiAnIzAzMTgyYidcclxuICAgICAgICAgICAgXCJcclxuICAgICAgICAgID48L2Rpdj5cclxuICAgICAgICA8L3NwYW4+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInRvYXN0LWNvbnRlbnRcIj5cclxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwidG9hc3QtbWVzc2FnZVwiPlxyXG4gICAgICAgICAgICB7eyBnZXRUcmFuc2xhdGVkTWVzc2FnZSh0b2FzdC5tZXNzYWdlKSB8IHRyYW5zbGF0ZSB9fVxyXG4gICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDxidXR0b24gY2xhc3M9XCJ0b2FzdC1jbG9zZVwiIChjbGljayk9XCJyZW1vdmVUb2FzdCh0b2FzdC5pZClcIiBhcmlhLWxhYmVsPVwiQ2xvc2VcIj5cclxuICAgICAgICAgIDxkaXZcclxuICAgICAgICAgICAgI2ljb25Db250YWluZXJcclxuICAgICAgICAgICAgY2xhc3M9XCJpY29uLWNvbnRhaW5lclwiXHJcbiAgICAgICAgICAgIGRhdGEtaWNvbi1uYW1lPVwiY3Jvc3NcIlxyXG4gICAgICAgICAgICBkYXRhLWljb24tdmFyaWFudD1cIkxpbmVcIlxyXG4gICAgICAgICAgICBkYXRhLWljb24tc2l6ZT1cIm1lZGl1bVwiXHJcbiAgICAgICAgICAgIGRhdGEtaWNvbi1jb2xvcj1cIiNmZmZmZmZcIlxyXG4gICAgICAgICAgPjwvZGl2PlxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICA8L2Rpdj5cclxuICAgIH1cclxuICA8L2Rpdj5cclxufVxyXG4iXX0=
|