@cqa-lib/cqa-ui 1.1.201 → 1.1.202
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/esm2020/lib/step-builder/step-builder-action/step-builder-action.component.mjs +75 -13
- package/esm2020/lib/step-builder/step-builder-ai-agent/step-builder-ai-agent.component.mjs +3 -3
- package/esm2020/lib/step-builder/step-builder-document/step-builder-document.component.mjs +5 -6
- package/esm2020/lib/step-builder/step-builder-group/step-builder-group.component.mjs +148 -0
- package/esm2020/lib/test-case-details/condition-step/condition-step.component.mjs +7 -5
- package/esm2020/lib/test-case-details/loop-step/loop-step.component.mjs +7 -5
- package/esm2020/lib/test-case-details/step-group/step-group.component.mjs +6 -5
- package/esm2020/lib/ui-kit.module.mjs +6 -6
- package/esm2020/public-api.mjs +2 -2
- package/fesm2015/cqa-lib-cqa-ui.mjs +192 -617
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +195 -612
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/step-builder/step-builder-action/step-builder-action.component.d.ts +10 -2
- package/lib/step-builder/step-builder-group/step-builder-group.component.d.ts +48 -0
- package/lib/ui-kit.module.d.ts +2 -2
- package/package.json +1 -1
- package/public-api.d.ts +1 -1
- package/styles.css +1 -1
- package/esm2020/lib/step-builder/step-builder-api/step-builder-api.component.mjs +0 -636
- package/lib/step-builder/step-builder-api/step-builder-api.component.d.ts +0 -121
|
@@ -1,636 +0,0 @@
|
|
|
1
|
-
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
|
-
import { FormArray, FormGroup, Validators } from '@angular/forms';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
import * as i1 from "@angular/forms";
|
|
5
|
-
import * as i2 from "../../dynamic-select/dynamic-select-field.component";
|
|
6
|
-
import * as i3 from "../../custom-input/custom-input.component";
|
|
7
|
-
import * as i4 from "../../button/button.component";
|
|
8
|
-
import * as i5 from "@angular/material/icon";
|
|
9
|
-
import * as i6 from "../../custom-textarea/custom-textarea.component";
|
|
10
|
-
import * as i7 from "@angular/material/checkbox";
|
|
11
|
-
import * as i8 from "@angular/common";
|
|
12
|
-
export class StepBuilderApiComponent {
|
|
13
|
-
constructor(fb) {
|
|
14
|
-
this.fb = fb;
|
|
15
|
-
/** Options for HTTP method dropdown */
|
|
16
|
-
this.httpMethodOptions = [
|
|
17
|
-
{ id: 'GET', value: 'GET', name: 'GET', label: 'GET' },
|
|
18
|
-
{ id: 'POST', value: 'POST', name: 'POST', label: 'POST' },
|
|
19
|
-
{ id: 'PUT', value: 'PUT', name: 'PUT', label: 'PUT' },
|
|
20
|
-
{ id: 'PATCH', value: 'PATCH', name: 'PATCH', label: 'PATCH' },
|
|
21
|
-
{ id: 'DELETE', value: 'DELETE', name: 'DELETE', label: 'DELETE' },
|
|
22
|
-
{ id: 'HEAD', value: 'HEAD', name: 'HEAD', label: 'HEAD' },
|
|
23
|
-
{ id: 'OPTIONS', value: 'OPTIONS', name: 'OPTIONS', label: 'OPTIONS' }
|
|
24
|
-
];
|
|
25
|
-
/** Options for header name dropdown */
|
|
26
|
-
this.headerNameOptions = [];
|
|
27
|
-
/** Current progress step */
|
|
28
|
-
this.currentStep = 'request-details';
|
|
29
|
-
/** Response preview data */
|
|
30
|
-
this.responsePreview = null;
|
|
31
|
-
/** Loading state */
|
|
32
|
-
this.isLoading = false;
|
|
33
|
-
/** Emit when step is created */
|
|
34
|
-
this.createStep = new EventEmitter();
|
|
35
|
-
/** Emit when cancelled */
|
|
36
|
-
this.cancelled = new EventEmitter();
|
|
37
|
-
/** Emit when request is sent */
|
|
38
|
-
this.sendRequest = new EventEmitter();
|
|
39
|
-
/** Emit when cURL is imported */
|
|
40
|
-
this.importCurl = new EventEmitter();
|
|
41
|
-
this.selectedTab = 'headers';
|
|
42
|
-
this.selectedProgressStep = 'request-details';
|
|
43
|
-
this.formSubmitted = false;
|
|
44
|
-
// progressSteps: ProgressStep[] = ['request-details', 'store-response', 'validation'];
|
|
45
|
-
// Cache config objects to prevent infinite change detection loops
|
|
46
|
-
this.verificationTypeConfigCache = null;
|
|
47
|
-
this.expectedTypeConfigCache = null;
|
|
48
|
-
this.httpMethodConfigCache = null;
|
|
49
|
-
this.headerNameConfigCache = null;
|
|
50
|
-
this.paramNameConfigCache = null;
|
|
51
|
-
this.hasLoadedInitialData = false;
|
|
52
|
-
// Get first HTTP method option (default to 'GET' if options not available yet)
|
|
53
|
-
const firstMethod = this.httpMethodOptions.length > 0
|
|
54
|
-
? this.httpMethodOptions[0].value
|
|
55
|
-
: 'GET';
|
|
56
|
-
this.apiForm = this.fb.group({
|
|
57
|
-
method: [firstMethod, Validators.required],
|
|
58
|
-
url: ['', [Validators.required, this.urlValidator()]],
|
|
59
|
-
headers: this.fb.array([]),
|
|
60
|
-
body: [''],
|
|
61
|
-
params: this.fb.array([]),
|
|
62
|
-
scripts: [''],
|
|
63
|
-
variableName: [''],
|
|
64
|
-
validation: this.fb.array([])
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
urlValidator() {
|
|
68
|
-
return (control) => {
|
|
69
|
-
const url = control.value;
|
|
70
|
-
if (!url) {
|
|
71
|
-
return null; // Let required validator handle empty case
|
|
72
|
-
}
|
|
73
|
-
// Pattern for plain URLs only (no parameters)
|
|
74
|
-
const urlPattern = /^(https?:\/\/)?([\w-]+(\.[\w-]+)+)([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?$/;
|
|
75
|
-
// Pattern to detect any parameter patterns: *|param|, $|param|, @|param|, or ${param}
|
|
76
|
-
const parameterPattern = /(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})/;
|
|
77
|
-
// Pattern for parameter-only values: *|param|, $|param|, @|param|, or ${param}
|
|
78
|
-
const envPattern = /^\*\|[\w-]+\|(\*)?$|^\$\|[\w-]+\|(\*)?$|^@\|[\w-]+\|(\*)?$|^\$\{[^}]+\}$/;
|
|
79
|
-
// Pattern to allow URLs with embedded parameters: *|param|, $|param|, @|param|, or ${param}
|
|
80
|
-
const flexibleUrlPattern = /^[@]?(https?:\/\/)?([\w-]+(\.[\w-]+)+)([\w.,@?^=%&:/~+#-]*(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})[\w.,@?^=%&:/~+#-]*)*$/;
|
|
81
|
-
// Pattern that allows parameters anywhere after http:// or https://
|
|
82
|
-
const protocolWithParamsPattern = /^https?:\/\/(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})[^\s]*$|^https?:\/\/[^\s]*(\*\|[\w-]+\|(\*)?|\$\|[\w-]+\|(\*)?|@\|[\w-]+\|(\*)?|\$\{[^}]+\})[^\s]*$/;
|
|
83
|
-
// Check if URL contains parameters
|
|
84
|
-
if (parameterPattern.test(url)) {
|
|
85
|
-
// If it contains parameters, check if it matches allowed patterns
|
|
86
|
-
const envCombined = new RegExp(`${urlPattern.source}|${flexibleUrlPattern.source}|${envPattern.source}|${protocolWithParamsPattern.source}`);
|
|
87
|
-
if (!envCombined.test(url)) {
|
|
88
|
-
return { hasParameter: true };
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
// If no parameters, check if it's a valid plain URL
|
|
93
|
-
if (!urlPattern.test(url)) {
|
|
94
|
-
return { pattern: true };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return null;
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
ngOnInit() {
|
|
101
|
-
// Sync currentStep input with selectedProgressStep
|
|
102
|
-
if (this.currentStep) {
|
|
103
|
-
this.selectedProgressStep = this.currentStep;
|
|
104
|
-
}
|
|
105
|
-
// Set method to first option if not already set
|
|
106
|
-
if (!this.apiForm.get('method')?.value && this.httpMethodOptions.length > 0) {
|
|
107
|
-
this.apiForm.get('method')?.setValue(this.httpMethodOptions[0].value);
|
|
108
|
-
}
|
|
109
|
-
// Load initial data if provided (edit mode)
|
|
110
|
-
if (this.initialData) {
|
|
111
|
-
this.loadInitialData(this.initialData);
|
|
112
|
-
this.hasLoadedInitialData = true;
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
// Add initial header row for new step
|
|
116
|
-
this.addHeader();
|
|
117
|
-
}
|
|
118
|
-
// Initialize validation form array if starting on validation step
|
|
119
|
-
if (this.selectedProgressStep === 'validation' && this.validationFormArray.length === 0) {
|
|
120
|
-
this.addValidationRule();
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
loadInitialData(data) {
|
|
124
|
-
console.log('loadInitialData: Loading data', data);
|
|
125
|
-
console.log('loadInitialData: Headers count', data.headers?.length || 0);
|
|
126
|
-
console.log('loadInitialData: Headers data', data.headers);
|
|
127
|
-
// Set basic fields
|
|
128
|
-
this.apiForm.patchValue({
|
|
129
|
-
method: data.method || 'GET',
|
|
130
|
-
url: data.url || '',
|
|
131
|
-
body: data.body || '',
|
|
132
|
-
scripts: data.scripts || '',
|
|
133
|
-
variableName: data.variableName || ''
|
|
134
|
-
});
|
|
135
|
-
// Load headers
|
|
136
|
-
// Clear existing headers first
|
|
137
|
-
while (this.headersFormArray.length !== 0) {
|
|
138
|
-
this.headersFormArray.removeAt(0);
|
|
139
|
-
}
|
|
140
|
-
if (data.headers && data.headers.length > 0) {
|
|
141
|
-
// Add headers from initial data (include all headers, even if empty)
|
|
142
|
-
data.headers.forEach(header => {
|
|
143
|
-
const headerGroup = this.fb.group({
|
|
144
|
-
name: [header.name || '', Validators.required],
|
|
145
|
-
value: [header.value || '', Validators.required]
|
|
146
|
-
});
|
|
147
|
-
this.headersFormArray.push(headerGroup);
|
|
148
|
-
});
|
|
149
|
-
console.log('loadInitialData: Loaded headers into form array, count:', this.headersFormArray.length);
|
|
150
|
-
}
|
|
151
|
-
// Ensure at least one header row exists
|
|
152
|
-
if (this.headersFormArray.length === 0) {
|
|
153
|
-
console.log('loadInitialData: No headers found, adding empty header row');
|
|
154
|
-
this.addHeader();
|
|
155
|
-
}
|
|
156
|
-
// Load params
|
|
157
|
-
// Clear existing params first
|
|
158
|
-
while (this.paramsFormArray.length !== 0) {
|
|
159
|
-
this.paramsFormArray.removeAt(0);
|
|
160
|
-
}
|
|
161
|
-
if (data.params && data.params.length > 0) {
|
|
162
|
-
// Add params from initial data (include all params, even if empty)
|
|
163
|
-
data.params.forEach(param => {
|
|
164
|
-
const paramGroup = this.fb.group({
|
|
165
|
-
name: [param.name || '', Validators.required],
|
|
166
|
-
value: [param.value || '', Validators.required]
|
|
167
|
-
});
|
|
168
|
-
this.paramsFormArray.push(paramGroup);
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
// Load validation rules
|
|
172
|
-
if (data.validation && data.validation.length > 0) {
|
|
173
|
-
// Clear existing validation rules
|
|
174
|
-
while (this.validationFormArray.length !== 0) {
|
|
175
|
-
this.validationFormArray.removeAt(0);
|
|
176
|
-
}
|
|
177
|
-
// Add validation rules from initial data
|
|
178
|
-
data.validation.forEach(rule => {
|
|
179
|
-
const validationGroup = this.fb.group({
|
|
180
|
-
jsonPath: [rule.jsonPath || '', Validators.required],
|
|
181
|
-
verificationType: [rule.verificationType || 'equals', Validators.required],
|
|
182
|
-
expectedType: [rule.expectedType || 'string', Validators.required],
|
|
183
|
-
expectedValue: [rule.expectedValue !== undefined ? rule.expectedValue : '', Validators.required],
|
|
184
|
-
result: [rule.result || 'Not run'],
|
|
185
|
-
checked: [rule.checked || false]
|
|
186
|
-
});
|
|
187
|
-
// Ensure all controls are enabled
|
|
188
|
-
validationGroup.enable({ emitEvent: false });
|
|
189
|
-
this.validationFormArray.push(validationGroup);
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
get headersFormArray() {
|
|
194
|
-
return this.apiForm.get('headers');
|
|
195
|
-
}
|
|
196
|
-
get paramsFormArray() {
|
|
197
|
-
return this.apiForm.get('params');
|
|
198
|
-
}
|
|
199
|
-
get validationFormArray() {
|
|
200
|
-
return this.apiForm.get('validation');
|
|
201
|
-
}
|
|
202
|
-
addHeader() {
|
|
203
|
-
// Get first header name option
|
|
204
|
-
const headerOptions = this.headerNameOptions.length > 0
|
|
205
|
-
? this.headerNameOptions
|
|
206
|
-
: [
|
|
207
|
-
{ id: 'string', value: 'string', name: 'string', label: 'string' },
|
|
208
|
-
{ id: 'Content-Type', value: 'Content-Type', name: 'Content-Type', label: 'Content-Type' },
|
|
209
|
-
{ id: 'Authorization', value: 'Authorization', name: 'Authorization', label: 'Authorization' },
|
|
210
|
-
{ id: 'Accept', value: 'Accept', name: 'Accept', label: 'Accept' }
|
|
211
|
-
];
|
|
212
|
-
const firstHeaderName = headerOptions.length > 0 ? headerOptions[0].value : '';
|
|
213
|
-
const headerGroup = this.fb.group({
|
|
214
|
-
name: [firstHeaderName, Validators.required],
|
|
215
|
-
value: ['', Validators.required]
|
|
216
|
-
});
|
|
217
|
-
this.headersFormArray.push(headerGroup);
|
|
218
|
-
}
|
|
219
|
-
removeHeader(index) {
|
|
220
|
-
this.headersFormArray.removeAt(index);
|
|
221
|
-
}
|
|
222
|
-
addParam() {
|
|
223
|
-
const paramGroup = this.fb.group({
|
|
224
|
-
name: ['', Validators.required],
|
|
225
|
-
value: ['', Validators.required]
|
|
226
|
-
});
|
|
227
|
-
this.paramsFormArray.push(paramGroup);
|
|
228
|
-
}
|
|
229
|
-
removeParam(index) {
|
|
230
|
-
this.paramsFormArray.removeAt(index);
|
|
231
|
-
}
|
|
232
|
-
ngOnChanges(changes) {
|
|
233
|
-
// Reset config caches when inputs change
|
|
234
|
-
if (changes['httpMethodOptions']) {
|
|
235
|
-
this.httpMethodConfigCache = null;
|
|
236
|
-
// Set method to first option if not already set or if we're not in edit mode
|
|
237
|
-
if (!this.hasLoadedInitialData && this.httpMethodOptions.length > 0) {
|
|
238
|
-
const methodControl = this.apiForm.get('method');
|
|
239
|
-
if (methodControl && !methodControl.value) {
|
|
240
|
-
methodControl.setValue(this.httpMethodOptions[0].value);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (changes['headerNameOptions']) {
|
|
245
|
-
this.headerNameConfigCache = null;
|
|
246
|
-
// Update header names to first option for empty headers (only if not in edit mode)
|
|
247
|
-
if (!this.hasLoadedInitialData && this.headerNameOptions.length > 0) {
|
|
248
|
-
this.headersFormArray.controls.forEach((headerGroup) => {
|
|
249
|
-
const nameControl = headerGroup.get('name');
|
|
250
|
-
if (nameControl && !nameControl.value) {
|
|
251
|
-
nameControl.setValue(this.headerNameOptions[0].value);
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
// Load initial data if it's set after component initialization
|
|
257
|
-
if (changes['initialData'] && !changes['initialData'].firstChange && this.initialData && !this.hasLoadedInitialData) {
|
|
258
|
-
this.loadInitialData(this.initialData);
|
|
259
|
-
this.hasLoadedInitialData = true;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
getHttpMethodConfig() {
|
|
263
|
-
if (!this.httpMethodConfigCache) {
|
|
264
|
-
this.httpMethodConfigCache = {
|
|
265
|
-
key: 'method',
|
|
266
|
-
placeholder: 'Select method',
|
|
267
|
-
multiple: false,
|
|
268
|
-
searchable: false,
|
|
269
|
-
options: this.httpMethodOptions
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
return this.httpMethodConfigCache;
|
|
273
|
-
}
|
|
274
|
-
getHeaderNameConfig(index) {
|
|
275
|
-
if (!this.headerNameConfigCache) {
|
|
276
|
-
const defaultOptions = [
|
|
277
|
-
{ id: 'string', value: 'string', name: 'string', label: 'string' },
|
|
278
|
-
{ id: 'Content-Type', value: 'Content-Type', name: 'Content-Type', label: 'Content-Type' },
|
|
279
|
-
{ id: 'Authorization', value: 'Authorization', name: 'Authorization', label: 'Authorization' },
|
|
280
|
-
{ id: 'Accept', value: 'Accept', name: 'Accept', label: 'Accept' }
|
|
281
|
-
];
|
|
282
|
-
this.headerNameConfigCache = {
|
|
283
|
-
key: 'name',
|
|
284
|
-
placeholder: 'Select header',
|
|
285
|
-
multiple: false,
|
|
286
|
-
searchable: true,
|
|
287
|
-
options: this.headerNameOptions.length > 0 ? this.headerNameOptions : defaultOptions
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
return this.headerNameConfigCache;
|
|
291
|
-
}
|
|
292
|
-
getParamNameConfig(index) {
|
|
293
|
-
if (!this.paramNameConfigCache) {
|
|
294
|
-
this.paramNameConfigCache = {
|
|
295
|
-
key: 'name',
|
|
296
|
-
placeholder: 'Parameter name',
|
|
297
|
-
multiple: false,
|
|
298
|
-
searchable: false,
|
|
299
|
-
options: []
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
return this.paramNameConfigCache;
|
|
303
|
-
}
|
|
304
|
-
getHeaderFormGroup(index) {
|
|
305
|
-
return this.headersFormArray.at(index);
|
|
306
|
-
}
|
|
307
|
-
getParamFormGroup(index) {
|
|
308
|
-
return this.paramsFormArray.at(index);
|
|
309
|
-
}
|
|
310
|
-
onTabChange(tab) {
|
|
311
|
-
this.selectedTab = tab;
|
|
312
|
-
}
|
|
313
|
-
onSendRequest() {
|
|
314
|
-
this.formSubmitted = true;
|
|
315
|
-
this.markFormGroupTouched(this.apiForm);
|
|
316
|
-
console.log('onSendRequest: apiForm', this.apiForm.value);
|
|
317
|
-
console.log('onSendRequest: apiForm valid', this.apiForm);
|
|
318
|
-
if (this.apiForm.valid) {
|
|
319
|
-
const formValue = this.apiForm.value;
|
|
320
|
-
const headers = formValue.headers.map((h) => ({
|
|
321
|
-
name: h.name,
|
|
322
|
-
value: h.value
|
|
323
|
-
}));
|
|
324
|
-
const params = formValue.params ? formValue.params.map((p) => ({
|
|
325
|
-
name: p.name,
|
|
326
|
-
value: p.value
|
|
327
|
-
})) : [];
|
|
328
|
-
this.sendRequest.emit({
|
|
329
|
-
method: formValue.method,
|
|
330
|
-
url: formValue.url,
|
|
331
|
-
headers,
|
|
332
|
-
body: formValue.body,
|
|
333
|
-
params
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
onImportCurl() {
|
|
338
|
-
this.importCurl.emit();
|
|
339
|
-
}
|
|
340
|
-
onCancel() {
|
|
341
|
-
this.cancelled.emit();
|
|
342
|
-
}
|
|
343
|
-
onCreateStep() {
|
|
344
|
-
this.formSubmitted = true;
|
|
345
|
-
this.markFormGroupTouched(this.apiForm);
|
|
346
|
-
if (this.apiForm.valid) {
|
|
347
|
-
const formValue = this.apiForm.value;
|
|
348
|
-
const stepData = {
|
|
349
|
-
method: formValue.method,
|
|
350
|
-
url: formValue.url,
|
|
351
|
-
headers: formValue.headers.map((h) => ({
|
|
352
|
-
name: h.name,
|
|
353
|
-
value: h.value
|
|
354
|
-
})),
|
|
355
|
-
body: formValue.body,
|
|
356
|
-
params: formValue.params ? formValue.params.map((p) => ({
|
|
357
|
-
name: p.name,
|
|
358
|
-
value: p.value
|
|
359
|
-
})) : [],
|
|
360
|
-
scripts: formValue.scripts,
|
|
361
|
-
variableName: formValue.variableName || '',
|
|
362
|
-
validation: formValue.validation ? formValue.validation.map((v) => ({
|
|
363
|
-
jsonPath: v.jsonPath,
|
|
364
|
-
verificationType: v.verificationType,
|
|
365
|
-
expectedType: v.expectedType,
|
|
366
|
-
expectedValue: v.expectedValue,
|
|
367
|
-
result: v.result || 'Not run'
|
|
368
|
-
})) : []
|
|
369
|
-
};
|
|
370
|
-
console.log('9999999', stepData);
|
|
371
|
-
this.createStep.emit(stepData);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
onNext() {
|
|
375
|
-
// Move to next step or create step if on last step
|
|
376
|
-
const stepOrder = ['request-details', 'store-response', 'validation'];
|
|
377
|
-
const currentIndex = stepOrder.indexOf(this.selectedProgressStep);
|
|
378
|
-
if (currentIndex < stepOrder.length - 1) {
|
|
379
|
-
this.onProgressStepChange(stepOrder[currentIndex + 1]);
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
this.onCreateStep();
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
onBack() {
|
|
386
|
-
// Move to previous step
|
|
387
|
-
const stepOrder = ['request-details', 'store-response', 'validation'];
|
|
388
|
-
const currentIndex = stepOrder.indexOf(this.selectedProgressStep);
|
|
389
|
-
if (currentIndex > 0) {
|
|
390
|
-
this.onProgressStepChange(stepOrder[currentIndex - 1]);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
canGoBack() {
|
|
394
|
-
const stepOrder = ['request-details', 'store-response', 'validation'];
|
|
395
|
-
const currentIndex = stepOrder.indexOf(this.selectedProgressStep);
|
|
396
|
-
return currentIndex > 0;
|
|
397
|
-
}
|
|
398
|
-
isLastStep() {
|
|
399
|
-
const stepOrder = ['request-details', 'store-response', 'validation'];
|
|
400
|
-
const currentIndex = stepOrder.indexOf(this.selectedProgressStep);
|
|
401
|
-
return currentIndex === stepOrder.length - 1;
|
|
402
|
-
}
|
|
403
|
-
getProgressStepClass(step) {
|
|
404
|
-
const stepOrder = ['request-details', 'store-response', 'validation'];
|
|
405
|
-
const currentIndex = stepOrder.indexOf(this.currentStep);
|
|
406
|
-
const stepIndex = stepOrder.indexOf(step);
|
|
407
|
-
if (stepIndex < currentIndex) {
|
|
408
|
-
return 'cqa-text-gray-400'; // Completed
|
|
409
|
-
}
|
|
410
|
-
else if (stepIndex === currentIndex) {
|
|
411
|
-
return 'cqa-text-purple-600 cqa-font-semibold'; // Active
|
|
412
|
-
}
|
|
413
|
-
else {
|
|
414
|
-
return 'cqa-text-gray-400'; // Pending
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
getProgressStepNumber(step) {
|
|
418
|
-
const stepOrder = ['request-details', 'store-response', 'validation'];
|
|
419
|
-
return stepOrder.indexOf(step) + 1;
|
|
420
|
-
}
|
|
421
|
-
getProgressStepLabel(step) {
|
|
422
|
-
const labels = {
|
|
423
|
-
'request-details': 'Request Details',
|
|
424
|
-
'store-response': 'Store Response',
|
|
425
|
-
'validation': 'Validation'
|
|
426
|
-
};
|
|
427
|
-
return labels[step];
|
|
428
|
-
}
|
|
429
|
-
formatJsonResponse(data) {
|
|
430
|
-
if (!data)
|
|
431
|
-
return '';
|
|
432
|
-
try {
|
|
433
|
-
return JSON.stringify(data, null, 2);
|
|
434
|
-
}
|
|
435
|
-
catch {
|
|
436
|
-
return String(data);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
onProgressStepChange(step) {
|
|
440
|
-
this.selectedProgressStep = step;
|
|
441
|
-
// Initialize validation form array if switching to validation step
|
|
442
|
-
if (step === 'validation' && this.validationFormArray.length === 0) {
|
|
443
|
-
this.addValidationRule();
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
addValidationRule() {
|
|
447
|
-
const validationGroup = this.fb.group({
|
|
448
|
-
checked: [false],
|
|
449
|
-
jsonPath: ['', Validators.required],
|
|
450
|
-
verificationType: ['equals'],
|
|
451
|
-
expectedType: ['string'],
|
|
452
|
-
expectedValue: ['', Validators.required],
|
|
453
|
-
result: ['Not run']
|
|
454
|
-
});
|
|
455
|
-
// Ensure all controls are enabled to avoid disabled attribute warnings
|
|
456
|
-
validationGroup.enable({ emitEvent: false });
|
|
457
|
-
this.validationFormArray.push(validationGroup);
|
|
458
|
-
}
|
|
459
|
-
removeValidationRule(index) {
|
|
460
|
-
this.validationFormArray.removeAt(index);
|
|
461
|
-
}
|
|
462
|
-
getValidationFormGroup(index) {
|
|
463
|
-
return this.validationFormArray.at(index);
|
|
464
|
-
}
|
|
465
|
-
trackByValidationRuleIndex(index) {
|
|
466
|
-
return index;
|
|
467
|
-
}
|
|
468
|
-
trackByHeaderIndex(index) {
|
|
469
|
-
return index;
|
|
470
|
-
}
|
|
471
|
-
trackByParamIndex(index) {
|
|
472
|
-
return index;
|
|
473
|
-
}
|
|
474
|
-
getVerificationTypeOptions() {
|
|
475
|
-
return [
|
|
476
|
-
{ id: 'equals', value: 'equals', name: 'Equals', label: 'Equals' },
|
|
477
|
-
{ id: 'not_equals', value: 'not_equals', name: 'Not Equals', label: 'Not Equals' },
|
|
478
|
-
{ id: 'contains', value: 'contains', name: 'Contains', label: 'Contains' },
|
|
479
|
-
{ id: 'not_contains', value: 'not_contains', name: 'Not Contains', label: 'Not Contains' },
|
|
480
|
-
{ id: 'greater_than', value: 'greater_than', name: 'Greater Than', label: 'Greater Than' },
|
|
481
|
-
{ id: 'less_than', value: 'less_than', name: 'Less Than', label: 'Less Than' },
|
|
482
|
-
{ id: 'greater_than_or_equals', value: 'greater_than_or_equals', name: 'Greater Than Or Equals', label: 'Greater Than Or Equals' },
|
|
483
|
-
{ id: 'less_than_or_equals', value: 'less_than_or_equals', name: 'Less Than Or Equals', label: 'Less Than Or Equals' },
|
|
484
|
-
{ id: 'exists', value: 'exists', name: 'Exists', label: 'Exists' },
|
|
485
|
-
{ id: 'not_exists', value: 'not_exists', name: 'Not Exists', label: 'Not Exists' }
|
|
486
|
-
];
|
|
487
|
-
}
|
|
488
|
-
getExpectedTypeOptions() {
|
|
489
|
-
return [
|
|
490
|
-
{ id: 'string', value: 'string', name: 'String', label: 'String' },
|
|
491
|
-
{ id: 'number', value: 'number', name: 'Number', label: 'Number' },
|
|
492
|
-
{ id: 'boolean', value: 'boolean', name: 'Boolean', label: 'Boolean' },
|
|
493
|
-
{ id: 'object', value: 'object', name: 'Object', label: 'Object' },
|
|
494
|
-
{ id: 'array', value: 'array', name: 'Array', label: 'Array' },
|
|
495
|
-
{ id: 'null', value: 'null', name: 'Null', label: 'Null' }
|
|
496
|
-
];
|
|
497
|
-
}
|
|
498
|
-
getVerificationTypeConfig(index) {
|
|
499
|
-
// Cache the config to prevent infinite change detection loops
|
|
500
|
-
if (!this.verificationTypeConfigCache) {
|
|
501
|
-
this.verificationTypeConfigCache = {
|
|
502
|
-
key: 'verificationType',
|
|
503
|
-
placeholder: 'Select verification type',
|
|
504
|
-
multiple: false,
|
|
505
|
-
searchable: false,
|
|
506
|
-
options: this.getVerificationTypeOptions()
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
return this.verificationTypeConfigCache;
|
|
510
|
-
}
|
|
511
|
-
getExpectedTypeConfig(index) {
|
|
512
|
-
// Cache the config to prevent infinite change detection loops
|
|
513
|
-
if (!this.expectedTypeConfigCache) {
|
|
514
|
-
this.expectedTypeConfigCache = {
|
|
515
|
-
key: 'expectedType',
|
|
516
|
-
placeholder: 'Select expected type',
|
|
517
|
-
multiple: false,
|
|
518
|
-
searchable: false,
|
|
519
|
-
options: this.getExpectedTypeOptions()
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
return this.expectedTypeConfigCache;
|
|
523
|
-
}
|
|
524
|
-
getResultClass(result) {
|
|
525
|
-
if (result === 'Pass') {
|
|
526
|
-
return 'cqa-bg-green-500 cqa-text-white';
|
|
527
|
-
}
|
|
528
|
-
else if (result === 'Fail') {
|
|
529
|
-
return 'cqa-bg-red-500 cqa-text-white';
|
|
530
|
-
}
|
|
531
|
-
return 'cqa-bg-gray-300 cqa-text-gray-700';
|
|
532
|
-
}
|
|
533
|
-
get allValidationRulesSelected() {
|
|
534
|
-
return this.validationFormArray.length > 0 &&
|
|
535
|
-
this.validationFormArray.controls.every(control => control.get('checked')?.value);
|
|
536
|
-
}
|
|
537
|
-
get someValidationRulesSelected() {
|
|
538
|
-
return this.validationFormArray.controls.some(control => control.get('checked')?.value) &&
|
|
539
|
-
!this.allValidationRulesSelected;
|
|
540
|
-
}
|
|
541
|
-
onSelectAllValidationRules(checked) {
|
|
542
|
-
this.validationFormArray.controls.forEach(control => {
|
|
543
|
-
control.get('checked')?.setValue(checked);
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
onDeleteSelectedValidationRules() {
|
|
547
|
-
const indicesToRemove = [];
|
|
548
|
-
this.validationFormArray.controls.forEach((control, index) => {
|
|
549
|
-
if (control.get('checked')?.value) {
|
|
550
|
-
indicesToRemove.push(index);
|
|
551
|
-
}
|
|
552
|
-
});
|
|
553
|
-
// Remove in reverse order to maintain correct indices
|
|
554
|
-
indicesToRemove.reverse().forEach(index => {
|
|
555
|
-
this.removeValidationRule(index);
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
markFormGroupTouched(formGroup) {
|
|
559
|
-
Object.keys(formGroup.controls).forEach(key => {
|
|
560
|
-
const control = formGroup.get(key);
|
|
561
|
-
if (control) {
|
|
562
|
-
control.markAsTouched();
|
|
563
|
-
if (control instanceof FormGroup) {
|
|
564
|
-
this.markFormGroupTouched(control);
|
|
565
|
-
}
|
|
566
|
-
else if (control instanceof FormArray) {
|
|
567
|
-
control.controls.forEach((ctrl) => {
|
|
568
|
-
if (ctrl instanceof FormGroup) {
|
|
569
|
-
this.markFormGroupTouched(ctrl);
|
|
570
|
-
}
|
|
571
|
-
else {
|
|
572
|
-
ctrl.markAsTouched();
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
onUrlChange(value) {
|
|
580
|
-
const urlControl = this.apiForm.get('url');
|
|
581
|
-
if (urlControl) {
|
|
582
|
-
urlControl.setValue(value);
|
|
583
|
-
urlControl.updateValueAndValidity();
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
onUrlBlur() {
|
|
587
|
-
const urlControl = this.apiForm.get('url');
|
|
588
|
-
if (urlControl) {
|
|
589
|
-
urlControl.markAsTouched();
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
getUrlErrors() {
|
|
593
|
-
const urlControl = this.apiForm.get('url');
|
|
594
|
-
if (!urlControl || (!this.formSubmitted && !urlControl.touched)) {
|
|
595
|
-
return [];
|
|
596
|
-
}
|
|
597
|
-
const errors = [];
|
|
598
|
-
if (urlControl.errors?.['required']) {
|
|
599
|
-
errors.push('URL is required');
|
|
600
|
-
}
|
|
601
|
-
else if (urlControl.errors?.['pattern']) {
|
|
602
|
-
errors.push('URL is not valid');
|
|
603
|
-
}
|
|
604
|
-
else if (urlControl.errors?.['hasParameter']) {
|
|
605
|
-
errors.push('URL format is invalid. Please check the parameter format.');
|
|
606
|
-
}
|
|
607
|
-
return errors;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
StepBuilderApiComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderApiComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
611
|
-
StepBuilderApiComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: StepBuilderApiComponent, selector: "cqa-step-builder-api", inputs: { httpMethodOptions: "httpMethodOptions", headerNameOptions: "headerNameOptions", currentStep: "currentStep", responsePreview: "responsePreview", isLoading: "isLoading", initialData: "initialData" }, outputs: { createStep: "createStep", cancelled: "cancelled", sendRequest: "sendRequest", importCurl: "importCurl" }, host: { classAttribute: "cqa-ui-root" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create API Test Step\n </h2>\n\n <!-- Progress Tracker -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-4 cqa-mb-6 cqa-pb-4 cqa-border-b cqa-border-gray-200\">\n <!-- <div *ngFor=\"let step of progressSteps\"\n class=\"cqa-flex cqa-items-center cqa-gap-2\"\n [ngClass]=\"getProgressStepClass(step)\">\n <span class=\"cqa-text-sm cqa-font-medium\">{{ getProgressStepNumber(step) }} {{ getProgressStepLabel(step) }}</span>\n <span *ngIf=\"step !== 'validation'\" class=\"cqa-text-gray-300\">\u2022</span>\n </div> -->\n <div class=\"cqa-flex cqa-items-center cqa-w-full cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'request-details'}\" (click)=\"onProgressStepChange('request-details')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">1</div>\n <div>Request Details</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'store-response'}\" (click)=\"onProgressStepChange('store-response')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">2</div>\n <div>Store Response</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'validation'}\" (click)=\"onProgressStepChange('validation')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">3</div>\n <div>Validation</div>\n <div></div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"selectedProgressStep === 'request-details'\">\n <!-- API Request Configuration -->\n <div class=\"cqa-flex cqa-items-start cqa-gap-2 cqa-mb-3\">\n <div class=\"cqa-w-32 cqa-flex-shrink-0\">\n <cqa-dynamic-select\n [form]=\"apiForm\"\n [config]=\"getHttpMethodConfig()\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Enter API endpoint URL'\"\n [value]=\"apiForm.get('url')?.value || ''\"\n [fullWidth]=\"true\"\n [errors]=\"getUrlErrors()\"\n (valueChange)=\"onUrlChange($event)\"\n (blurred)=\"onUrlBlur()\">\n </cqa-custom-input>\n </div>\n <cqa-button\n variant=\"outlined\"\n text=\"Import API cURL\"\n (clicked)=\"onImportCurl()\">\n </cqa-button>\n <cqa-button\n variant=\"filled\"\n text=\"Send Request\"\n (clicked)=\"onSendRequest()\"\n [disabled]=\"!apiForm.get('url')?.value || isLoading\">\n </cqa-button>\n </div>\n\n <!-- Request Details Tabs -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Tab Navigation -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'headers'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'headers'\"\n (click)=\"onTabChange('headers')\">\n Headers\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'body'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'body'\"\n (click)=\"onTabChange('body')\">\n Body\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'params'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'params'\"\n (click)=\"onTabChange('params')\">\n Params\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'scripts'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'scripts'\"\n (click)=\"onTabChange('scripts')\">\n Scripts\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-4 cqa-border cqa-border-gray-200 cqa-border-t-0 cqa-rounded-b-lg\">\n <!-- Headers Tab -->\n <div *ngIf=\"selectedTab === 'headers'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Name*</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Value*</div>\n </div>\n <div *ngFor=\"let header of headersFormArray.controls; let i = index; trackBy: trackByHeaderIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-dynamic-select\n [form]=\"getHeaderFormGroup(i)\"\n [config]=\"getHeaderNameConfig(i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Header value'\"\n [value]=\"getHeaderFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getHeaderFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeHeader(i)\"\n [attr.aria-label]=\"'Remove header'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addHeader()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Header</span>\n </button>\n </div>\n\n <!-- Body Tab -->\n <div *ngIf=\"selectedTab === 'body'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter request body (JSON, XML, etc.)'\"\n [value]=\"apiForm.get('body')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('body')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Params Tab -->\n <div *ngIf=\"selectedTab === 'params'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Value</div>\n </div>\n <div *ngFor=\"let param of paramsFormArray.controls; let i = index; trackBy: trackByParamIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-custom-input\n [placeholder]=\"'Parameter name'\"\n [value]=\"getParamFormGroup(i).get('name')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('name')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Parameter value'\"\n [value]=\"getParamFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeParam(i)\"\n [attr.aria-label]=\"'Remove parameter'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addParam()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Parameter</span>\n </button>\n </div>\n\n <!-- Scripts Tab -->\n <div *ngIf=\"selectedTab === 'scripts'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter scripts (JavaScript, etc.)'\"\n [value]=\"apiForm.get('scripts')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('scripts')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'store-response'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Store Response Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Store Response\n </h3>\n\n <!-- Variable Name Input -->\n <div class=\"cqa-mb-6\">\n <label class=\"cqa-text-[12px] cqa-font-medium cqa-text-gray-700 cqa-mb-1 cqa-block\">\n Variable Name\n </label>\n <cqa-custom-input\n [placeholder]=\"'Variable Name'\"\n [value]=\"apiForm.get('variableName')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('variableName')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </div>\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'validation'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Validation Rules Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Validation Rules\n </h3>\n\n <!-- Validation Rules Table -->\n <div class=\"cqa-bg-white cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-4\">\n <!-- Table Header -->\n <div class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200 cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox\n [checked]=\"allValidationRulesSelected\"\n [indeterminate]=\"someValidationRulesSelected\"\n (change)=\"onSelectAllValidationRules($event.checked)\">\n </mat-checkbox>\n </div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">jsonPath</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">verificationType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedValue</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Result</div>\n </div>\n\n <!-- Table Body -->\n <div class=\"cqa-flex cqa-flex-col\">\n <div *ngFor=\"let validationRule of validationFormArray.controls; let i = index; trackBy: trackByValidationRuleIndex\" \n [formGroup]=\"getValidationFormGroup(i)\"\n class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-border-b cqa-border-gray-200 cqa-items-center cqa-last:border-b-0\">\n <!-- Checkbox -->\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox formControlName=\"checked\">\n </mat-checkbox>\n </div>\n\n <!-- jsonPath -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'jsonPath'\"\n [value]=\"getValidationFormGroup(i).get('jsonPath')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('jsonPath')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- verificationType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getVerificationTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getExpectedTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedValue -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'expectedValue'\"\n [value]=\"getValidationFormGroup(i).get('expectedValue')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('expectedValue')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Result and Delete -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-rounded cqa-text-[10px] cqa-font-medium\"\n [ngClass]=\"getResultClass(getValidationFormGroup(i).get('result')?.value || 'Not run')\">\n {{ getValidationFormGroup(i).get('result')?.value || 'Not run' }}\n </button>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-6 cqa-h-6 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeValidationRule(i)\"\n [attr.aria-label]=\"'Delete validation rule'\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Add Another Rule and Delete Selected -->\n <div class=\"cqa-flex cqa-justify-between cqa-items-center cqa-mb-4\">\n <button\n *ngIf=\"someValidationRulesSelected || allValidationRulesSelected\"\n type=\"button\"\n class=\"cqa-text-red-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-red-700 cqa-transition-colors\"\n (click)=\"onDeleteSelectedValidationRules()\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n <span>Delete Selected</span>\n </button>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addValidationRule()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Another</span>\n </button>\n </div>\n </div>\n</ng-container>\n\n\n <!-- Response Preview Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-6\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Response Preview</h3>\n </div>\n <div class=\"cqa-p-4 cqa-bg-gray-50 cqa-overflow-auto\" style=\"max-height: 300px;\">\n <pre *ngIf=\"responsePreview\" class=\"cqa-text-xs cqa-font-mono cqa-text-gray-800 cqa-whitespace-pre-wrap\">{{ formatJsonResponse(responsePreview) }}</pre>\n <p *ngIf=\"!responsePreview\" class=\"cqa-text-sm cqa-text-gray-400 cqa-text-center cqa-py-8\">\n No response yet. Send a request to see the response preview.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <!-- Cancel button (only on first step) -->\n <cqa-button\n *ngIf=\"selectedProgressStep === 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Cancel\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <!-- Back button (on all steps except first) -->\n <cqa-button\n *ngIf=\"selectedProgressStep !== 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Back\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onBack()\">\n </cqa-button>\n <!-- Next/Create Step button -->\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"filled\"\n [text]=\"isLastStep() ? 'Create Step' : 'Next'\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"isLastStep() ? onCreateStep() : onNext()\">\n </cqa-button>\n </div>\n</div>\n\n", components: [{ type: i2.DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: i3.CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: i4.ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i6.CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused"] }, { type: i7.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], directives: [{ type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
|
|
612
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: StepBuilderApiComponent, decorators: [{
|
|
613
|
-
type: Component,
|
|
614
|
-
args: [{ selector: 'cqa-step-builder-api', host: { class: 'cqa-ui-root' }, template: "<div class=\"cqa-flex cqa-flex-col cqa-h-full cqa-bg-white cqa-px-4 cqa-py-2\">\n <!-- Header -->\n <h2 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Create API Test Step\n </h2>\n\n <!-- Progress Tracker -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-4 cqa-mb-6 cqa-pb-4 cqa-border-b cqa-border-gray-200\">\n <!-- <div *ngFor=\"let step of progressSteps\"\n class=\"cqa-flex cqa-items-center cqa-gap-2\"\n [ngClass]=\"getProgressStepClass(step)\">\n <span class=\"cqa-text-sm cqa-font-medium\">{{ getProgressStepNumber(step) }} {{ getProgressStepLabel(step) }}</span>\n <span *ngIf=\"step !== 'validation'\" class=\"cqa-text-gray-300\">\u2022</span>\n </div> -->\n <div class=\"cqa-flex cqa-items-center cqa-w-full cqa-justify-between\">\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'request-details'}\" (click)=\"onProgressStepChange('request-details')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">1</div>\n <div>Request Details</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'store-response'}\" (click)=\"onProgressStepChange('store-response')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">2</div>\n <div>Store Response</div>\n <div></div>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\" [ngClass]=\"{'cqa-text-purple-600 cqa-font-semibold': selectedProgressStep === 'validation'}\" (click)=\"onProgressStepChange('validation')\">\n <div class=\"cqa-w-8 cqa-h-8 cqa-flex cqa-items-center cqa-justify-center cqa-rounded-full cqa-bg-purple-600 cqa-text-white cqa-text-xs cqa-font-semibold\">3</div>\n <div>Validation</div>\n <div></div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"selectedProgressStep === 'request-details'\">\n <!-- API Request Configuration -->\n <div class=\"cqa-flex cqa-items-start cqa-gap-2 cqa-mb-3\">\n <div class=\"cqa-w-32 cqa-flex-shrink-0\">\n <cqa-dynamic-select\n [form]=\"apiForm\"\n [config]=\"getHttpMethodConfig()\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Enter API endpoint URL'\"\n [value]=\"apiForm.get('url')?.value || ''\"\n [fullWidth]=\"true\"\n [errors]=\"getUrlErrors()\"\n (valueChange)=\"onUrlChange($event)\"\n (blurred)=\"onUrlBlur()\">\n </cqa-custom-input>\n </div>\n <cqa-button\n variant=\"outlined\"\n text=\"Import API cURL\"\n (clicked)=\"onImportCurl()\">\n </cqa-button>\n <cqa-button\n variant=\"filled\"\n text=\"Send Request\"\n (clicked)=\"onSendRequest()\"\n [disabled]=\"!apiForm.get('url')?.value || isLoading\">\n </cqa-button>\n </div>\n\n <!-- Request Details Tabs -->\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-overflow-hidden cqa-mb-6\">\n <!-- Tab Navigation -->\n <div class=\"cqa-flex cqa-items-center cqa-border-b cqa-border-gray-200 cqa-bg-gray-50\">\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'headers'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'headers'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'headers'\"\n (click)=\"onTabChange('headers')\">\n Headers\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'body'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'body'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'body'\"\n (click)=\"onTabChange('body')\">\n Body\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'params'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'params'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'params'\"\n (click)=\"onTabChange('params')\">\n Params\n </button>\n <button\n type=\"button\"\n class=\"cqa-px-4 cqa-py-2 cqa-text-sm cqa-font-medium cqa-transition-colors cqa-border-b-2\"\n [class.cqa-text-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-border-blue-600]=\"selectedTab === 'scripts'\"\n [class.cqa-text-gray-600]=\"selectedTab !== 'scripts'\"\n [class.cqa-border-transparent]=\"selectedTab !== 'scripts'\"\n (click)=\"onTabChange('scripts')\">\n Scripts\n </button>\n </div>\n\n <!-- Tab Content -->\n <div class=\"cqa-flex-1 cqa-overflow-y-auto cqa-p-4 cqa-border cqa-border-gray-200 cqa-border-t-0 cqa-rounded-b-lg\">\n <!-- Headers Tab -->\n <div *ngIf=\"selectedTab === 'headers'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Name*</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Header Value*</div>\n </div>\n <div *ngFor=\"let header of headersFormArray.controls; let i = index; trackBy: trackByHeaderIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-dynamic-select\n [form]=\"getHeaderFormGroup(i)\"\n [config]=\"getHeaderNameConfig(i)\">\n </cqa-dynamic-select>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Header value'\"\n [value]=\"getHeaderFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getHeaderFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeHeader(i)\"\n [attr.aria-label]=\"'Remove header'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addHeader()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Header</span>\n </button>\n </div>\n\n <!-- Body Tab -->\n <div *ngIf=\"selectedTab === 'body'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter request body (JSON, XML, etc.)'\"\n [value]=\"apiForm.get('body')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('body')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n\n <!-- Params Tab -->\n <div *ngIf=\"selectedTab === 'params'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <div class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-start\">\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Name</div>\n <div class=\"cqa-text-xs cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Parameter Value</div>\n </div>\n <div *ngFor=\"let param of paramsFormArray.controls; let i = index; trackBy: trackByParamIndex\" \n class=\"cqa-grid cqa-grid-cols-2 cqa-gap-4 cqa-items-center\">\n <div>\n <cqa-custom-input\n [placeholder]=\"'Parameter name'\"\n [value]=\"getParamFormGroup(i).get('name')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('name')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <div class=\"cqa-flex-1\">\n <cqa-custom-input\n [placeholder]=\"'Parameter value'\"\n [value]=\"getParamFormGroup(i).get('value')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getParamFormGroup(i).get('value')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-8 cqa-h-8 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeParam(i)\"\n [attr.aria-label]=\"'Remove parameter'\">\n <mat-icon class=\"cqa-text-lg\">delete</mat-icon>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-self-start cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addParam()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Parameter</span>\n </button>\n </div>\n\n <!-- Scripts Tab -->\n <div *ngIf=\"selectedTab === 'scripts'\" class=\"cqa-flex cqa-flex-col cqa-gap-3\">\n <cqa-custom-textarea\n [placeholder]=\"'Enter scripts (JavaScript, etc.)'\"\n [value]=\"apiForm.get('scripts')?.value || ''\"\n [fullWidth]=\"true\"\n [rows]=\"10\"\n (valueChange)=\"apiForm.get('scripts')?.setValue($event)\">\n </cqa-custom-textarea>\n </div>\n </div>\n </div>\n\n\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'store-response'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Store Response Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Store Response\n </h3>\n\n <!-- Variable Name Input -->\n <div class=\"cqa-mb-6\">\n <label class=\"cqa-text-[12px] cqa-font-medium cqa-text-gray-700 cqa-mb-1 cqa-block\">\n Variable Name\n </label>\n <cqa-custom-input\n [placeholder]=\"'Variable Name'\"\n [value]=\"apiForm.get('variableName')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"apiForm.get('variableName')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n </div>\n</ng-container>\n<ng-container *ngIf=\"selectedProgressStep === 'validation'\">\n <div class=\"cqa-flex cqa-flex-col cqa-flex-1 cqa-max-h-[500px] cqa-overflow-y-auto\">\n <!-- Validation Rules Title -->\n <h3 class=\"cqa-text-[12px] cqa-font-semibold cqa-text-black-100 cqa-mb-4\">\n Validation Rules\n </h3>\n\n <!-- Validation Rules Table -->\n <div class=\"cqa-bg-white cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-4\">\n <!-- Table Header -->\n <div class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200 cqa-items-center\">\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox\n [checked]=\"allValidationRulesSelected\"\n [indeterminate]=\"someValidationRulesSelected\"\n (change)=\"onSelectAllValidationRules($event.checked)\">\n </mat-checkbox>\n </div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">jsonPath</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">verificationType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedType</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">expectedValue</div>\n <div class=\"cqa-text-[10px] cqa-font-semibold cqa-text-gray-700 cqa-uppercase\">Result</div>\n </div>\n\n <!-- Table Body -->\n <div class=\"cqa-flex cqa-flex-col\">\n <div *ngFor=\"let validationRule of validationFormArray.controls; let i = index; trackBy: trackByValidationRuleIndex\" \n [formGroup]=\"getValidationFormGroup(i)\"\n class=\"cqa-grid cqa-grid-cols-6 cqa-gap-2 cqa-p-3 cqa-border-b cqa-border-gray-200 cqa-items-center cqa-last:border-b-0\">\n <!-- Checkbox -->\n <div class=\"cqa-flex cqa-items-center\">\n <mat-checkbox formControlName=\"checked\">\n </mat-checkbox>\n </div>\n\n <!-- jsonPath -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'jsonPath'\"\n [value]=\"getValidationFormGroup(i).get('jsonPath')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('jsonPath')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- verificationType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getVerificationTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedType -->\n <div>\n <cqa-dynamic-select\n [form]=\"getValidationFormGroup(i)\"\n [config]=\"getExpectedTypeConfig(i)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- expectedValue -->\n <div>\n <cqa-custom-input\n [placeholder]=\"'expectedValue'\"\n [value]=\"getValidationFormGroup(i).get('expectedValue')?.value || ''\"\n [fullWidth]=\"true\"\n (valueChange)=\"getValidationFormGroup(i).get('expectedValue')?.setValue($event)\">\n </cqa-custom-input>\n </div>\n\n <!-- Result and Delete -->\n <div class=\"cqa-flex cqa-items-center cqa-gap-2\">\n <button\n type=\"button\"\n class=\"cqa-px-3 cqa-py-1 cqa-rounded cqa-text-[10px] cqa-font-medium\"\n [ngClass]=\"getResultClass(getValidationFormGroup(i).get('result')?.value || 'Not run')\">\n {{ getValidationFormGroup(i).get('result')?.value || 'Not run' }}\n </button>\n <button\n type=\"button\"\n class=\"cqa-flex cqa-items-center cqa-justify-center cqa-w-6 cqa-h-6 cqa-rounded cqa-text-red-500 hover:cqa-text-red-700 hover:cqa-bg-red-50 cqa-transition-colors\"\n (click)=\"removeValidationRule(i)\"\n [attr.aria-label]=\"'Delete validation rule'\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Add Another Rule and Delete Selected -->\n <div class=\"cqa-flex cqa-justify-between cqa-items-center cqa-mb-4\">\n <button\n *ngIf=\"someValidationRulesSelected || allValidationRulesSelected\"\n type=\"button\"\n class=\"cqa-text-red-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-red-700 cqa-transition-colors\"\n (click)=\"onDeleteSelectedValidationRules()\">\n <mat-icon class=\"cqa-text-base\">delete</mat-icon>\n <span>Delete Selected</span>\n </button>\n <button\n type=\"button\"\n class=\"cqa-text-blue-600 cqa-text-sm cqa-font-medium cqa-flex cqa-items-center cqa-gap-1 hover:cqa-text-blue-700 cqa-transition-colors\"\n (click)=\"addValidationRule()\">\n <mat-icon class=\"cqa-text-base\">add</mat-icon>\n <span>Add Another</span>\n </button>\n </div>\n </div>\n</ng-container>\n\n\n <!-- Response Preview Section -->\n <div class=\"cqa-flex cqa-flex-col cqa-border cqa-border-gray-200 cqa-rounded-lg cqa-overflow-hidden cqa-mb-6\">\n <div class=\"cqa-p-3 cqa-bg-gray-50 cqa-border-b cqa-border-gray-200\">\n <h3 class=\"cqa-text-sm cqa-font-semibold cqa-text-gray-900\">Response Preview</h3>\n </div>\n <div class=\"cqa-p-4 cqa-bg-gray-50 cqa-overflow-auto\" style=\"max-height: 300px;\">\n <pre *ngIf=\"responsePreview\" class=\"cqa-text-xs cqa-font-mono cqa-text-gray-800 cqa-whitespace-pre-wrap\">{{ formatJsonResponse(responsePreview) }}</pre>\n <p *ngIf=\"!responsePreview\" class=\"cqa-text-sm cqa-text-gray-400 cqa-text-center cqa-py-8\">\n No response yet. Send a request to see the response preview.\n </p>\n </div>\n </div>\n <!-- Action Buttons -->\n <div class=\"cqa-flex cqa-w-full cqa-gap-2 cqa-mt-auto cqa-pt-4 cqa-border-t cqa-border-gray-200\">\n <!-- Cancel button (only on first step) -->\n <cqa-button\n *ngIf=\"selectedProgressStep === 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Cancel\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onCancel()\">\n </cqa-button>\n <!-- Back button (on all steps except first) -->\n <cqa-button\n *ngIf=\"selectedProgressStep !== 'request-details'\"\n class=\"cqa-w-1/2\"\n variant=\"outlined\"\n text=\"Back\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"onBack()\">\n </cqa-button>\n <!-- Next/Create Step button -->\n <cqa-button\n class=\"cqa-w-1/2\"\n variant=\"filled\"\n [text]=\"isLastStep() ? 'Create Step' : 'Next'\"\n [customClass]=\"'cqa-flex-1 cqa-w-full'\"\n (clicked)=\"isLastStep() ? onCreateStep() : onNext()\">\n </cqa-button>\n </div>\n</div>\n\n", styles: [] }]
|
|
615
|
-
}], ctorParameters: function () { return [{ type: i1.FormBuilder }]; }, propDecorators: { httpMethodOptions: [{
|
|
616
|
-
type: Input
|
|
617
|
-
}], headerNameOptions: [{
|
|
618
|
-
type: Input
|
|
619
|
-
}], currentStep: [{
|
|
620
|
-
type: Input
|
|
621
|
-
}], responsePreview: [{
|
|
622
|
-
type: Input
|
|
623
|
-
}], isLoading: [{
|
|
624
|
-
type: Input
|
|
625
|
-
}], initialData: [{
|
|
626
|
-
type: Input
|
|
627
|
-
}], createStep: [{
|
|
628
|
-
type: Output
|
|
629
|
-
}], cancelled: [{
|
|
630
|
-
type: Output
|
|
631
|
-
}], sendRequest: [{
|
|
632
|
-
type: Output
|
|
633
|
-
}], importCurl: [{
|
|
634
|
-
type: Output
|
|
635
|
-
}] } });
|
|
636
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1idWlsZGVyLWFwaS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3N0ZXAtYnVpbGRlci9zdGVwLWJ1aWxkZXItYXBpL3N0ZXAtYnVpbGRlci1hcGkuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zdGVwLWJ1aWxkZXIvc3RlcC1idWlsZGVyLWFwaS9zdGVwLWJ1aWxkZXItYXBpLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQW1ELE1BQU0sZUFBZSxDQUFDO0FBQ3hILE9BQU8sRUFBRSxTQUFTLEVBQWUsU0FBUyxFQUFlLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7Ozs7Ozs7O0FBdUM1RixNQUFNLE9BQU8sdUJBQXVCO0lBcURsQyxZQUFvQixFQUFlO1FBQWYsT0FBRSxHQUFGLEVBQUUsQ0FBYTtRQXBEbkMsdUNBQXVDO1FBQzlCLHNCQUFpQixHQUFtQjtZQUMzQyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUU7WUFDdEQsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFO1lBQzFELEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRTtZQUN0RCxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUU7WUFDOUQsRUFBRSxF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QixDQUFDOztvSEFucUJVLHVCQUF1Qjt3R0FBdkIsdUJBQXVCLCtiQ3hDcEMscXprQkFnWkE7MkZEeFdhLHVCQUF1QjtrQkFObkMsU0FBUzsrQkFDRSxzQkFBc0IsUUFHMUIsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFO2tHQUlyQixpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBV0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUdHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBR0csZUFBZTtzQkFBdkIsS0FBSztnQkFHRyxTQUFTO3NCQUFqQixLQUFLO2dCQUdHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBR0ksVUFBVTtzQkFBbkIsTUFBTTtnQkFHRyxTQUFTO3NCQUFsQixNQUFNO2dCQUdHLFdBQVc7c0JBQXBCLE1BQU07Z0JBR0csVUFBVTtzQkFBbkIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBPbkluaXQsIE9uQ2hhbmdlcywgU2ltcGxlQ2hhbmdlcywgQWZ0ZXJWaWV3SW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybUFycmF5LCBGb3JtQnVpbGRlciwgRm9ybUdyb3VwLCBGb3JtQ29udHJvbCwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZywgU2VsZWN0T3B0aW9uIH0gZnJvbSAnLi4vLi4vZHluYW1pYy1zZWxlY3QvZHluYW1pYy1zZWxlY3QtZmllbGQuY29tcG9uZW50JztcblxuZXhwb3J0IHR5cGUgSHR0cE1ldGhvZCA9ICdHRVQnIHwgJ1BPU1QnIHwgJ1BVVCcgfCAnUEFUQ0gnIHwgJ0RFTEVURScgfCAnSEVBRCcgfCAnT1BUSU9OUyc7XG5leHBvcnQgdHlwZSBSZXF1ZXN0VGFiID0gJ2hlYWRlcnMnIHwgJ2JvZHknIHwgJ3BhcmFtcycgfCAnc2NyaXB0cyc7XG5leHBvcnQgdHlwZSBQcm9ncmVzc1N0ZXAgPSAncmVxdWVzdC1kZXRhaWxzJyB8ICdzdG9yZS1yZXNwb25zZScgfCAndmFsaWRhdGlvbic7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSGVhZGVyUm93IHtcbiAgbmFtZTogc3RyaW5nO1xuICB2YWx1ZTogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFZhbGlkYXRpb25SdWxlIHtcbiAganNvblBhdGg6IHN0cmluZztcbiAgdmVyaWZpY2F0aW9uVHlwZTogc3RyaW5nO1xuICBleHBlY3RlZFR5cGU6IHN0cmluZztcbiAgZXhwZWN0ZWRWYWx1ZTogYW55O1xuICByZXN1bHQ/OiAnUGFzcycgfCAnRmFpbCcgfCAnTm90IHJ1bic7XG4gIGNoZWNrZWQ/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFwaUZvcm1EYXRhIHtcbiAgbWV0aG9kOiBIdHRwTWV0aG9kO1xuICB1cmw6IHN0cmluZztcbiAgaGVhZGVyczogSGVhZGVyUm93W107XG4gIGJvZHk/OiBzdHJpbmc7XG4gIHBhcmFtcz86IEhlYWRlclJvd1tdO1xuICBzY3JpcHRzPzogc3RyaW5nO1xuICB2YXJpYWJsZU5hbWU/OiBzdHJpbmc7XG4gIHN0b3JlUmVzcG9uc2U/OiBhbnk7XG4gIHZhbGlkYXRpb24/OiBWYWxpZGF0aW9uUnVsZVtdO1xufVxuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjcWEtc3RlcC1idWlsZGVyLWFwaScsXG4gIHRlbXBsYXRlVXJsOiAnLi9zdGVwLWJ1aWxkZXItYXBpLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbXSxcbiAgaG9zdDogeyBjbGFzczogJ2NxYS11aS1yb290JyB9XG59KVxuZXhwb3J0IGNsYXNzIFN0ZXBCdWlsZGVyQXBpQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMge1xuICAvKiogT3B0aW9ucyBmb3IgSFRUUCBtZXRob2QgZHJvcGRvd24gKi9cbiAgQElucHV0KCkgaHR0cE1ldGhvZE9wdGlvbnM6IFNlbGVjdE9wdGlvbltdID0gW1xuICAgIHsgaWQ6ICdHRVQnLCB2YWx1ZTogJ0dFVCcsIG5hbWU6ICdHRVQnLCBsYWJlbDogJ0dFVCcgfSxcbiAgICB7IGlkOiAnUE9TVCcsIHZhbHVlOiAnUE9TVCcsIG5hbWU6ICdQT1NUJywgbGFiZWw6ICdQT1NUJyB9LFxuICAgIHsgaWQ6ICdQVVQnLCB2YWx1ZTogJ1BVVCcsIG5hbWU6ICdQVVQnLCBsYWJlbDogJ1BVVCcgfSxcbiAgICB7IGlkOiAnUEFUQ0gnLCB2YWx1ZTogJ1BBVENIJywgbmFtZTogJ1BBVENIJywgbGFiZWw6ICdQQVRDSCcgfSxcbiAgICB7IGlkOiAnREVMRVRFJywgdmFsdWU6ICdERUxFVEUnLCBuYW1lOiAnREVMRVRFJywgbGFiZWw6ICdERUxFVEUnIH0sXG4gICAgeyBpZDogJ0hFQUQnLCB2YWx1ZTogJ0hFQUQnLCBuYW1lOiAnSEVBRCcsIGxhYmVsOiAnSEVBRCcgfSxcbiAgICB7IGlkOiAnT1BUSU9OUycsIHZhbHVlOiAnT1BUSU9OUycsIG5hbWU6ICdPUFRJT05TJywgbGFiZWw6ICdPUFRJT05TJyB9XG4gIF07XG5cbiAgLyoqIE9wdGlvbnMgZm9yIGhlYWRlciBuYW1lIGRyb3Bkb3duICovXG4gIEBJbnB1dCgpIGhlYWRlck5hbWVPcHRpb25zOiBTZWxlY3RPcHRpb25bXSA9IFtdO1xuXG4gIC8qKiBDdXJyZW50IHByb2dyZXNzIHN0ZXAgKi9cbiAgQElucHV0KCkgY3VycmVudFN0ZXA6IFByb2dyZXNzU3RlcCA9ICdyZXF1ZXN0LWRldGFpbHMnO1xuXG4gIC8qKiBSZXNwb25zZSBwcmV2aWV3IGRhdGEgKi9cbiAgQElucHV0KCkgcmVzcG9uc2VQcmV2aWV3OiBhbnkgPSBudWxsO1xuXG4gIC8qKiBMb2FkaW5nIHN0YXRlICovXG4gIEBJbnB1dCgpIGlzTG9hZGluZzogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8qKiBJbml0aWFsIGZvcm0gZGF0YSBmb3IgZWRpdCBtb2RlICovXG4gIEBJbnB1dCgpIGluaXRpYWxEYXRhPzogQXBpRm9ybURhdGE7XG5cbiAgLyoqIEVtaXQgd2hlbiBzdGVwIGlzIGNyZWF0ZWQgKi9cbiAgQE91dHB1dCgpIGNyZWF0ZVN0ZXAgPSBuZXcgRXZlbnRFbWl0dGVyPEFwaUZvcm1EYXRhPigpO1xuXG4gIC8qKiBFbWl0IHdoZW4gY2FuY2VsbGVkICovXG4gIEBPdXRwdXQoKSBjYW5jZWxsZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG5cbiAgLyoqIEVtaXQgd2hlbiByZXF1ZXN0IGlzIHNlbnQgKi9cbiAgQE91dHB1dCgpIHNlbmRSZXF1ZXN0ID0gbmV3IEV2ZW50RW1pdHRlcjx7IG1ldGhvZDogSHR0cE1ldGhvZDsgdXJsOiBzdHJpbmc7IGhlYWRlcnM6IEhlYWRlclJvd1tdOyBib2R5Pzogc3RyaW5nOyBwYXJhbXM/OiBIZWFkZXJSb3dbXSB9PigpO1xuXG4gIC8qKiBFbWl0IHdoZW4gY1VSTCBpcyBpbXBvcnRlZCAqL1xuICBAT3V0cHV0KCkgaW1wb3J0Q3VybCA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcblxuICBhcGlGb3JtOiBGb3JtR3JvdXA7XG4gIHNlbGVjdGVkVGFiOiBSZXF1ZXN0VGFiID0gJ2hlYWRlcnMnO1xuICBzZWxlY3RlZFByb2dyZXNzU3RlcDogUHJvZ3Jlc3NTdGVwID0gJ3JlcXVlc3QtZGV0YWlscyc7XG4gIGZvcm1TdWJtaXR0ZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgLy8gcHJvZ3Jlc3NTdGVwczogUHJvZ3Jlc3NTdGVwW10gPSBbJ3JlcXVlc3QtZGV0YWlscycsICdzdG9yZS1yZXNwb25zZScsICd2YWxpZGF0aW9uJ107XG4gIFxuICAvLyBDYWNoZSBjb25maWcgb2JqZWN0cyB0byBwcmV2ZW50IGluZmluaXRlIGNoYW5nZSBkZXRlY3Rpb24gbG9vcHNcbiAgcHJpdmF0ZSB2ZXJpZmljYXRpb25UeXBlQ29uZmlnQ2FjaGU6IER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGV4cGVjdGVkVHlwZUNvbmZpZ0NhY2hlOiBEeW5hbWljU2VsZWN0RmllbGRDb25maWcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBodHRwTWV0aG9kQ29uZmlnQ2FjaGU6IER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGhlYWRlck5hbWVDb25maWdDYWNoZTogRHluYW1pY1NlbGVjdEZpZWxkQ29uZmlnIHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgcGFyYW1OYW1lQ29uZmlnQ2FjaGU6IER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGhhc0xvYWRlZEluaXRpYWxEYXRhOiBib29sZWFuID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBmYjogRm9ybUJ1aWxkZXIpIHtcbiAgICAvLyBHZXQgZmlyc3QgSFRUUCBtZXRob2Qgb3B0aW9uIChkZWZhdWx0IHRvICdHRVQnIGlmIG9wdGlvbnMgbm90IGF2YWlsYWJsZSB5ZXQpXG4gICAgY29uc3QgZmlyc3RNZXRob2QgPSB0aGlzLmh0dHBNZXRob2RPcHRpb25zLmxlbmd0aCA+IDAgXG4gICAgICA/IHRoaXMuaHR0cE1ldGhvZE9wdGlvbnNbMF0udmFsdWUgXG4gICAgICA6ICdHRVQnO1xuICAgIFxuICAgIHRoaXMuYXBpRm9ybSA9IHRoaXMuZmIuZ3JvdXAoe1xuICAgICAgbWV0aG9kOiBbZmlyc3RNZXRob2QsIFZhbGlkYXRvcnMucmVxdWlyZWRdLFxuICAgICAgdXJsOiBbJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCB0aGlzLnVybFZhbGlkYXRvcigpXV0sXG4gICAgICBoZWFkZXJzOiB0aGlzLmZiLmFycmF5KFtdKSxcbiAgICAgIGJvZHk6IFsnJ10sXG4gICAgICBwYXJhbXM6IHRoaXMuZmIuYXJyYXkoW10pLFxuICAgICAgc2NyaXB0czogWycnXSxcbiAgICAgIHZhcmlhYmxlTmFtZTogWycnXSxcbiAgICAgIHZhbGlkYXRpb246IHRoaXMuZmIuYXJyYXkoW10pXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHVybFZhbGlkYXRvcigpIHtcbiAgICByZXR1cm4gKGNvbnRyb2w6IEZvcm1Db250cm9sKTogeyBba2V5OiBzdHJpbmddOiBhbnkgfSB8IG51bGwgPT4ge1xuICAgICAgY29uc3QgdXJsID0gY29udHJvbC52YWx1ZTtcbiAgICAgIGlmICghdXJsKSB7XG4gICAgICAgIHJldHVybiBudWxsOyAvLyBMZXQgcmVxdWlyZWQgdmFsaWRhdG9yIGhhbmRsZSBlbXB0eSBjYXNlXG4gICAgICB9XG5cbiAgICAgIC8vIFBhdHRlcm4gZm9yIHBsYWluIFVSTHMgb25seSAobm8gcGFyYW1ldGVycylcbiAgICAgIGNvbnN0IHVybFBhdHRlcm4gPSAvXihodHRwcz86XFwvXFwvKT8oW1xcdy1dKyhcXC5bXFx3LV0rKSspKFtcXHcuLEA/Xj0lJjovfisjLV0qW1xcd0A/Xj0lJi9+KyMtXSk/JC87XG4gICAgICBcbiAgICAgIC8vIFBhdHRlcm4gdG8gZGV0ZWN0IGFueSBwYXJhbWV0ZXIgcGF0dGVybnM6ICp8cGFyYW18LCAkfHBhcmFtfCwgQHxwYXJhbXwsIG9yICR7cGFyYW19XG4gICAgICBjb25zdCBwYXJhbWV0ZXJQYXR0ZXJuID0gLyhcXCpcXHxbXFx3LV0rXFx8KFxcKik/fFxcJFxcfFtcXHctXStcXHwoXFwqKT98QFxcfFtcXHctXStcXHwoXFwqKT98XFwkXFx7W159XStcXH0pLztcbiAgICAgIFxuICAgICAgLy8gUGF0dGVybiBmb3IgcGFyYW1ldGVyLW9ubHkgdmFsdWVzOiAqfHBhcmFtfCwgJHxwYXJhbXwsIEB8cGFyYW18LCBvciAke3BhcmFtfVxuICAgICAgY29uc3QgZW52UGF0dGVybiA9IC9eXFwqXFx8W1xcdy1dK1xcfChcXCopPyR8XlxcJFxcfFtcXHctXStcXHwoXFwqKT8kfF5AXFx8W1xcdy1dK1xcfChcXCopPyR8XlxcJFxce1tefV0rXFx9JC87XG4gICAgICBcbiAgICAgIC8vIFBhdHRlcm4gdG8gYWxsb3cgVVJMcyB3aXRoIGVtYmVkZGVkIHBhcmFtZXRlcnM6ICp8cGFyYW18LCAkfHBhcmFtfCwgQHxwYXJhbXwsIG9yICR7cGFyYW19XG4gICAgICBjb25zdCBmbGV4aWJsZVVybFBhdHRlcm4gPSAvXltAXT8oaHR0cHM/OlxcL1xcLyk/KFtcXHctXSsoXFwuW1xcdy1dKykrKShbXFx3LixAP149JSY6L34rIy1dKihcXCpcXHxbXFx3LV0rXFx8KFxcKik/fFxcJFxcfFtcXHctXStcXHwoXFwqKT98QFxcfFtcXHctXStcXHwoXFwqKT98XFwkXFx7W159XStcXH0pW1xcdy4sQD9ePSUmOi9+KyMtXSopKiQvO1xuICAgICAgXG4gICAgICAvLyBQYXR0ZXJuIHRoYXQgYWxsb3dzIHBhcmFtZXRlcnMgYW55d2hlcmUgYWZ0ZXIgaHR0cDovLyBvciBodHRwczovL1xuICAgICAgY29uc3QgcHJvdG9jb2xXaXRoUGFyYW1zUGF0dGVybiA9IC9eaHR0cHM/OlxcL1xcLyhcXCpcXHxbXFx3LV0rXFx8KFxcKik/fFxcJFxcfFtcXHctXStcXHwoXFwqKT98QFxcfFtcXHctXStcXHwoXFwqKT98XFwkXFx7W159XStcXH0pW15cXHNdKiR8Xmh0dHBzPzpcXC9cXC9bXlxcc10qKFxcKlxcfFtcXHctXStcXHwoXFwqKT98XFwkXFx8W1xcdy1dK1xcfChcXCopP3xAXFx8W1xcdy1dK1xcfChcXCopP3xcXCRcXHtbXn1dK1xcfSlbXlxcc10qJC87XG4gICAgICBcbiAgICAgIC8vIENoZWNrIGlmIFVSTCBjb250YWlucyBwYXJhbWV0ZXJzXG4gICAgICBpZiAocGFyYW1ldGVyUGF0dGVybi50ZXN0KHVybCkpIHtcbiAgICAgICAgLy8gSWYgaXQgY29udGFpbnMgcGFyYW1ldGVycywgY2hlY2sgaWYgaXQgbWF0Y2hlcyBhbGxvd2VkIHBhdHRlcm5zXG4gICAgICAgIGNvbnN0IGVudkNvbWJpbmVkID0gbmV3IFJlZ0V4cChgJHt1cmxQYXR0ZXJuLnNvdXJjZX18JHtmbGV4aWJsZVVybFBhdHRlcm4uc291cmNlfXwke2VudlBhdHRlcm4uc291cmNlfXwke3Byb3RvY29sV2l0aFBhcmFtc1BhdHRlcm4uc291cmNlfWApO1xuICAgICAgICBpZiAoIWVudkNvbWJpbmVkLnRlc3QodXJsKSkge1xuICAgICAgICAgIHJldHVybiB7IGhhc1BhcmFtZXRlcjogdHJ1ZSB9O1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBJZiBubyBwYXJhbWV0ZXJzLCBjaGVjayBpZiBpdCdzIGEgdmFsaWQgcGxhaW4gVVJMXG4gICAgICAgIGlmICghdXJsUGF0dGVybi50ZXN0KHVybCkpIHtcbiAgICAgICAgICByZXR1cm4geyBwYXR0ZXJuOiB0cnVlIH07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIC8vIFN5bmMgY3VycmVudFN0ZXAgaW5wdXQgd2l0aCBzZWxlY3RlZFByb2dyZXNzU3RlcFxuICAgIGlmICh0aGlzLmN1cnJlbnRTdGVwKSB7XG4gICAgICB0aGlzLnNlbGVjdGVkUHJvZ3Jlc3NTdGVwID0gdGhpcy5jdXJyZW50U3RlcDtcbiAgICB9XG4gICAgXG4gICAgLy8gU2V0IG1ldGhvZCB0byBmaXJzdCBvcHRpb24gaWYgbm90IGFscmVhZHkgc2V0XG4gICAgaWYgKCF0aGlzLmFwaUZvcm0uZ2V0KCdtZXRob2QnKT8udmFsdWUgJiYgdGhpcy5odHRwTWV0aG9kT3B0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLmFwaUZvcm0uZ2V0KCdtZXRob2QnKT8uc2V0VmFsdWUodGhpcy5odHRwTWV0aG9kT3B0aW9uc1swXS52YWx1ZSk7XG4gICAgfVxuICAgIFxuICAgIC8vIExvYWQgaW5pdGlhbCBkYXRhIGlmIHByb3ZpZGVkIChlZGl0IG1vZGUpXG4gICAgaWYgKHRoaXMuaW5pdGlhbERhdGEpIHtcbiAgICAgIHRoaXMubG9hZEluaXRpYWxEYXRhKHRoaXMuaW5pdGlhbERhdGEpO1xuICAgICAgdGhpcy5oYXNMb2FkZWRJbml0aWFsRGF0YSA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEFkZCBpbml0aWFsIGhlYWRlciByb3cgZm9yIG5ldyBzdGVwXG4gICAgICB0aGlzLmFkZEhlYWRlcigpO1xuICAgIH1cbiAgICBcbiAgICAvLyBJbml0aWFsaXplIHZhbGlkYXRpb24gZm9ybSBhcnJheSBpZiBzdGFydGluZyBvbiB2YWxpZGF0aW9uIHN0ZXBcbiAgICBpZiAodGhpcy5zZWxlY3RlZFByb2dyZXNzU3RlcCA9PT0gJ3ZhbGlkYXRpb24nICYmIHRoaXMudmFsaWRhdGlvbkZvcm1BcnJheS5sZW5ndGggPT09IDApIHtcbiAgICAgIHRoaXMuYWRkVmFsaWRhdGlvblJ1bGUoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGxvYWRJbml0aWFsRGF0YShkYXRhOiBBcGlGb3JtRGF0YSk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKCdsb2FkSW5pdGlhbERhdGE6IExvYWRpbmcgZGF0YScsIGRhdGEpO1xuICAgIGNvbnNvbGUubG9nKCdsb2FkSW5pdGlhbERhdGE6IEhlYWRlcnMgY291bnQnLCBkYXRhLmhlYWRlcnM/Lmxlbmd0aCB8fCAwKTtcbiAgICBjb25zb2xlLmxvZygnbG9hZEluaXRpYWxEYXRhOiBIZWFkZXJzIGRhdGEnLCBkYXRhLmhlYWRlcnMpO1xuICAgIFxuICAgIC8vIFNldCBiYXNpYyBmaWVsZHNcbiAgICB0aGlzLmFwaUZvcm0ucGF0Y2hWYWx1ZSh7XG4gICAgICBtZXRob2Q6IGRhdGEubWV0aG9kIHx8ICdHRVQnLFxuICAgICAgdXJsOiBkYXRhLnVybCB8fCAnJyxcbiAgICAgIGJvZHk6IGRhdGEuYm9keSB8fCAnJyxcbiAgICAgIHNjcmlwdHM6IGRhdGEuc2NyaXB0cyB8fCAnJyxcbiAgICAgIHZhcmlhYmxlTmFtZTogZGF0YS52YXJpYWJsZU5hbWUgfHwgJydcbiAgICB9KTtcblxuICAgIC8vIExvYWQgaGVhZGVyc1xuICAgIC8vIENsZWFyIGV4aXN0aW5nIGhlYWRlcnMgZmlyc3RcbiAgICB3aGlsZSAodGhpcy5oZWFkZXJzRm9ybUFycmF5Lmxlbmd0aCAhPT0gMCkge1xuICAgICAgdGhpcy5oZWFkZXJzRm9ybUFycmF5LnJlbW92ZUF0KDApO1xuICAgIH1cbiAgICBcbiAgICBpZiAoZGF0YS5oZWFkZXJzICYmIGRhdGEuaGVhZGVycy5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBBZGQgaGVhZGVycyBmcm9tIGluaXRpYWwgZGF0YSAoaW5jbHVkZSBhbGwgaGVhZGVycywgZXZlbiBpZiBlbXB0eSlcbiAgICAgIGRhdGEuaGVhZGVycy5mb3JFYWNoKGhlYWRlciA9PiB7XG4gICAgICAgIGNvbnN0IGhlYWRlckdyb3VwID0gdGhpcy5mYi5ncm91cCh7XG4gICAgICAgICAgbmFtZTogW2hlYWRlci5uYW1lIHx8ICcnLCBWYWxpZGF0b3JzLnJlcXVpcmVkXSxcbiAgICAgICAgICB2YWx1ZTogW2hlYWRlci52YWx1ZSB8fCAnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuaGVhZGVyc0Zvcm1BcnJheS5wdXNoKGhlYWRlckdyb3VwKTtcbiAgICAgIH0pO1xuICAgICAgY29uc29sZS5sb2coJ2xvYWRJbml0aWFsRGF0YTogTG9hZGVkIGhlYWRlcnMgaW50byBmb3JtIGFycmF5LCBjb3VudDonLCB0aGlzLmhlYWRlcnNGb3JtQXJyYXkubGVuZ3RoKTtcbiAgICB9XG4gICAgXG4gICAgLy8gRW5zdXJlIGF0IGxlYXN0IG9uZSBoZWFkZXIgcm93IGV4aXN0c1xuICAgIGlmICh0aGlzLmhlYWRlcnNGb3JtQXJyYXkubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZygnbG9hZEluaXRpYWxEYXRhOiBObyBoZWFkZXJzIGZvdW5kLCBhZGRpbmcgZW1wdHkgaGVhZGVyIHJvdycpO1xuICAgICAgdGhpcy5hZGRIZWFkZXIoKTtcbiAgICB9XG5cbiAgICAvLyBMb2FkIHBhcmFtc1xuICAgIC8vIENsZWFyIGV4aXN0aW5nIHBhcmFtcyBmaXJzdFxuICAgIHdoaWxlICh0aGlzLnBhcmFtc0Zvcm1BcnJheS5sZW5ndGggIT09IDApIHtcbiAgICAgIHRoaXMucGFyYW1zRm9ybUFycmF5LnJlbW92ZUF0KDApO1xuICAgIH1cbiAgICBcbiAgICBpZiAoZGF0YS5wYXJhbXMgJiYgZGF0YS5wYXJhbXMubGVuZ3RoID4gMCkge1xuICAgICAgLy8gQWRkIHBhcmFtcyBmcm9tIGluaXRpYWwgZGF0YSAoaW5jbHVkZSBhbGwgcGFyYW1zLCBldmVuIGlmIGVtcHR5KVxuICAgICAgZGF0YS5wYXJhbXMuZm9yRWFjaChwYXJhbSA9PiB7XG4gICAgICAgIGNvbnN0IHBhcmFtR3JvdXAgPSB0aGlzLmZiLmdyb3VwKHtcbiAgICAgICAgICBuYW1lOiBbcGFyYW0ubmFtZSB8fCAnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF0sXG4gICAgICAgICAgdmFsdWU6IFtwYXJhbS52YWx1ZSB8fCAnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucGFyYW1zRm9ybUFycmF5LnB1c2gocGFyYW1Hcm91cCk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBMb2FkIHZhbGlkYXRpb24gcnVsZXNcbiAgICBpZiAoZGF0YS52YWxpZGF0aW9uICYmIGRhdGEudmFsaWRhdGlvbi5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBDbGVhciBleGlzdGluZyB2YWxpZGF0aW9uIHJ1bGVzXG4gICAgICB3aGlsZSAodGhpcy52YWxpZGF0aW9uRm9ybUFycmF5Lmxlbmd0aCAhPT0gMCkge1xuICAgICAgICB0aGlzLnZhbGlkYXRpb25Gb3JtQXJyYXkucmVtb3ZlQXQoMCk7XG4gICAgICB9XG4gICAgICAvLyBBZGQgdmFsaWRhdGlvbiBydWxlcyBmcm9tIGluaXRpYWwgZGF0YVxuICAgICAgZGF0YS52YWxpZGF0aW9uLmZvckVhY2gocnVsZSA9PiB7XG4gICAgICAgIGNvbnN0IHZhbGlkYXRpb25Hcm91cCA9IHRoaXMuZmIuZ3JvdXAoe1xuICAgICAgICAgIGpzb25QYXRoOiBbcnVsZS5qc29uUGF0aCB8fCAnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF0sXG4gICAgICAgICAgdmVyaWZpY2F0aW9uVHlwZTogW3J1bGUudmVyaWZpY2F0aW9uVHlwZSB8fCAnZXF1YWxzJywgVmFsaWRhdG9ycy5yZXF1aXJlZF0sXG4gICAgICAgICAgZXhwZWN0ZWRUeXBlOiBbcnVsZS5leHBlY3RlZFR5cGUgfHwgJ3N0cmluZycsIFZhbGlkYXRvcnMucmVxdWlyZWRdLFxuICAgICAgICAgIGV4cGVjdGVkVmFsdWU6IFtydWxlLmV4cGVjdGVkVmFsdWUgIT09IHVuZGVmaW5lZCA/IHJ1bGUuZXhwZWN0ZWRWYWx1ZSA6ICcnLCBWYWxpZGF0b3JzLnJlcXVpcmVkXSxcbiAgICAgICAgICByZXN1bHQ6IFtydWxlLnJlc3VsdCB8fCAnTm90IHJ1biddLFxuICAgICAgICAgIGNoZWNrZWQ6IFtydWxlLmNoZWNrZWQgfHwgZmFsc2VdXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBFbnN1cmUgYWxsIGNvbnRyb2xzIGFyZSBlbmFibGVkXG4gICAgICAgIHZhbGlkYXRpb25Hcm91cC5lbmFibGUoeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xuICAgICAgICB0aGlzLnZhbGlkYXRpb25Gb3JtQXJyYXkucHVzaCh2YWxpZGF0aW9uR3JvdXApO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgZ2V0IGhlYWRlcnNGb3JtQXJyYXkoKTogRm9ybUFycmF5IHtcbiAgICByZXR1cm4gdGhpcy5hcGlGb3JtLmdldCgnaGVhZGVycycpIGFzIEZvcm1BcnJheTtcbiAgfVxuXG4gIGdldCBwYXJhbXNGb3JtQXJyYXkoKTogRm9ybUFycmF5IHtcbiAgICByZXR1cm4gdGhpcy5hcGlGb3JtLmdldCgncGFyYW1zJykgYXMgRm9ybUFycmF5O1xuICB9XG5cbiAgZ2V0IHZhbGlkYXRpb25Gb3JtQXJyYXkoKTogRm9ybUFycmF5IHtcbiAgICByZXR1cm4gdGhpcy5hcGlGb3JtLmdldCgndmFsaWRhdGlvbicpIGFzIEZvcm1BcnJheTtcbiAgfVxuXG4gIGFkZEhlYWRlcigpOiB2b2lkIHtcbiAgICAvLyBHZXQgZmlyc3QgaGVhZGVyIG5hbWUgb3B0aW9uXG4gICAgY29uc3QgaGVhZGVyT3B0aW9ucyA9IHRoaXMuaGVhZGVyTmFtZU9wdGlvbnMubGVuZ3RoID4gMCBcbiAgICAgID8gdGhpcy5oZWFkZXJOYW1lT3B0aW9ucyBcbiAgICAgIDogW1xuICAgICAgICAgIHsgaWQ6ICdzdHJpbmcnLCB2YWx1ZTogJ3N0cmluZycsIG5hbWU6ICdzdHJpbmcnLCBsYWJlbDogJ3N0cmluZycgfSxcbiAgICAgICAgICB7IGlkOiAnQ29udGVudC1UeXBlJywgdmFsdWU6ICdDb250ZW50LVR5cGUnLCBuYW1lOiAnQ29udGVudC1UeXBlJywgbGFiZWw6ICdDb250ZW50LVR5cGUnIH0sXG4gICAgICAgICAgeyBpZDogJ0F1dGhvcml6YXRpb24nLCB2YWx1ZTogJ0F1dGhvcml6YXRpb24nLCBuYW1lOiAnQXV0aG9yaXphdGlvbicsIGxhYmVsOiAnQXV0aG9yaXphdGlvbicgfSxcbiAgICAgICAgICB7IGlkOiAnQWNjZXB0JywgdmFsdWU6ICdBY2NlcHQnLCBuYW1lOiAnQWNjZXB0JywgbGFiZWw6ICdBY2NlcHQnIH1cbiAgICAgICAgXTtcbiAgICBcbiAgICBjb25zdCBmaXJzdEhlYWRlck5hbWUgPSBoZWFkZXJPcHRpb25zLmxlbmd0aCA+IDAgPyBoZWFkZXJPcHRpb25zWzBdLnZhbHVlIDogJyc7XG4gICAgXG4gICAgY29uc3QgaGVhZGVyR3JvdXAgPSB0aGlzLmZiLmdyb3VwKHtcbiAgICAgIG5hbWU6IFtmaXJzdEhlYWRlck5hbWUsIFZhbGlkYXRvcnMucmVxdWlyZWRdLFxuICAgICAgdmFsdWU6IFsnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF1cbiAgICB9KTtcbiAgICB0aGlzLmhlYWRlcnNGb3JtQXJyYXkucHVzaChoZWFkZXJHcm91cCk7XG4gIH1cblxuICByZW1vdmVIZWFkZXIoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMuaGVhZGVyc0Zvcm1BcnJheS5yZW1vdmVBdChpbmRleCk7XG4gIH1cblxuICBhZGRQYXJhbSgpOiB2b2lkIHtcbiAgICBjb25zdCBwYXJhbUdyb3VwID0gdGhpcy5mYi5ncm91cCh7XG4gICAgICBuYW1lOiBbJycsIFZhbGlkYXRvcnMucmVxdWlyZWRdLFxuICAgICAgdmFsdWU6IFsnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF1cbiAgICB9KTtcbiAgICB0aGlzLnBhcmFtc0Zvcm1BcnJheS5wdXNoKHBhcmFtR3JvdXApO1xuICB9XG5cbiAgcmVtb3ZlUGFyYW0oaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMucGFyYW1zRm9ybUFycmF5LnJlbW92ZUF0KGluZGV4KTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAvLyBSZXNldCBjb25maWcgY2FjaGVzIHdoZW4gaW5wdXRzIGNoYW5nZVxuICAgIGlmIChjaGFuZ2VzWydodHRwTWV0aG9kT3B0aW9ucyddKSB7XG4gICAgICB0aGlzLmh0dHBNZXRob2RDb25maWdDYWNoZSA9IG51bGw7XG4gICAgICAvLyBTZXQgbWV0aG9kIHRvIGZpcnN0IG9wdGlvbiBpZiBub3QgYWxyZWFkeSBzZXQgb3IgaWYgd2UncmUgbm90IGluIGVkaXQgbW9kZVxuICAgICAgaWYgKCF0aGlzLmhhc0xvYWRlZEluaXRpYWxEYXRhICYmIHRoaXMuaHR0cE1ldGhvZE9wdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgICBjb25zdCBtZXRob2RDb250cm9sID0gdGhpcy5hcGlGb3JtLmdldCgnbWV0aG9kJyk7XG4gICAgICAgIGlmIChtZXRob2RDb250cm9sICYmICFtZXRob2RDb250cm9sLnZhbHVlKSB7XG4gICAgICAgICAgbWV0aG9kQ29udHJvbC5zZXRWYWx1ZSh0aGlzLmh0dHBNZXRob2RPcHRpb25zWzBdLnZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpZiAoY2hhbmdlc1snaGVhZGVyTmFtZU9wdGlvbnMnXSkge1xuICAgICAgdGhpcy5oZWFkZXJOYW1lQ29uZmlnQ2FjaGUgPSBudWxsO1xuICAgICAgLy8gVXBkYXRlIGhlYWRlciBuYW1lcyB0byBmaXJzdCBvcHRpb24gZm9yIGVtcHR5IGhlYWRlcnMgKG9ubHkgaWYgbm90IGluIGVkaXQgbW9kZSlcbiAgICAgIGlmICghdGhpcy5oYXNMb2FkZWRJbml0aWFsRGF0YSAmJiB0aGlzLmhlYWRlck5hbWVPcHRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5oZWFkZXJzRm9ybUFycmF5LmNvbnRyb2xzLmZvckVhY2goKGhlYWRlckdyb3VwOiBhbnkpID0+IHtcbiAgICAgICAgICBjb25zdCBuYW1lQ29udHJvbCA9IGhlYWRlckdyb3VwLmdldCgnbmFtZScpO1xuICAgICAgICAgIGlmIChuYW1lQ29udHJvbCAmJiAhbmFtZUNvbnRyb2wudmFsdWUpIHtcbiAgICAgICAgICAgIG5hbWVDb250cm9sLnNldFZhbHVlKHRoaXMuaGVhZGVyTmFtZU9wdGlvbnNbMF0udmFsdWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIExvYWQgaW5pdGlhbCBkYXRhIGlmIGl0J3Mgc2V0IGFmdGVyIGNvbXBvbmVudCBpbml0aWFsaXphdGlvblxuICAgIGlmIChjaGFuZ2VzWydpbml0aWFsRGF0YSddICYmICFjaGFuZ2VzWydpbml0aWFsRGF0YSddLmZpcnN0Q2hhbmdlICYmIHRoaXMuaW5pdGlhbERhdGEgJiYgIXRoaXMuaGFzTG9hZGVkSW5pdGlhbERhdGEpIHtcbiAgICAgIHRoaXMubG9hZEluaXRpYWxEYXRhKHRoaXMuaW5pdGlhbERhdGEpO1xuICAgICAgdGhpcy5oYXNMb2FkZWRJbml0aWFsRGF0YSA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgZ2V0SHR0cE1ldGhvZENvbmZpZygpOiBEeW5hbWljU2VsZWN0RmllbGRDb25maWcge1xuICAgIGlmICghdGhpcy5odHRwTWV0aG9kQ29uZmlnQ2FjaGUpIHtcbiAgICAgIHRoaXMuaHR0cE1ldGhvZENvbmZpZ0NhY2hlID0ge1xuICAgICAgICBrZXk6ICdtZXRob2QnLFxuICAgICAgICBwbGFjZWhvbGRlcjogJ1NlbGVjdCBtZXRob2QnLFxuICAgICAgICBtdWx0aXBsZTogZmFsc2UsXG4gICAgICAgIHNlYXJjaGFibGU6IGZhbHNlLFxuICAgICAgICBvcHRpb25zOiB0aGlzLmh0dHBNZXRob2RPcHRpb25zXG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5odHRwTWV0aG9kQ29uZmlnQ2FjaGU7XG4gIH1cblxuICBnZXRIZWFkZXJOYW1lQ29uZmlnKGluZGV4OiBudW1iZXIpOiBEeW5hbWljU2VsZWN0RmllbGRDb25maWcge1xuICAgIGlmICghdGhpcy5oZWFkZXJOYW1lQ29uZmlnQ2FjaGUpIHtcbiAgICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gW1xuICAgICAgICB7IGlkOiAnc3RyaW5nJywgdmFsdWU6ICdzdHJpbmcnLCBuYW1lOiAnc3RyaW5nJywgbGFiZWw6ICdzdHJpbmcnIH0sXG4gICAgICAgIHsgaWQ6ICdDb250ZW50LVR5cGUnLCB2YWx1ZTogJ0NvbnRlbnQtVHlwZScsIG5hbWU6ICdDb250ZW50LVR5cGUnLCBsYWJlbDogJ0NvbnRlbnQtVHlwZScgfSxcbiAgICAgICAgeyBpZDogJ0F1dGhvcml6YXRpb24nLCB2YWx1ZTogJ0F1dGhvcml6YXRpb24nLCBuYW1lOiAnQXV0aG9yaXphdGlvbicsIGxhYmVsOiAnQXV0aG9yaXphdGlvbicgfSxcbiAgICAgICAgeyBpZDogJ0FjY2VwdCcsIHZhbHVlOiAnQWNjZXB0JywgbmFtZTogJ0FjY2VwdCcsIGxhYmVsOiAnQWNjZXB0JyB9XG4gICAgICBdO1xuICAgICAgXG4gICAgICB0aGlzLmhlYWRlck5hbWVDb25maWdDYWNoZSA9IHtcbiAgICAgICAga2V5OiAnbmFtZScsXG4gICAgICAgIHBsYWNlaG9sZGVyOiAnU2VsZWN0IGhlYWRlcicsXG4gICAgICAgIG11bHRpcGxlOiBmYWxzZSxcbiAgICAgICAgc2VhcmNoYWJsZTogdHJ1ZSxcbiAgICAgICAgb3B0aW9uczogdGhpcy5oZWFkZXJOYW1lT3B0aW9ucy5sZW5ndGggPiAwID8gdGhpcy5oZWFkZXJOYW1lT3B0aW9ucyA6IGRlZmF1bHRPcHRpb25zXG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5oZWFkZXJOYW1lQ29uZmlnQ2FjaGU7XG4gIH1cblxuICBnZXRQYXJhbU5hbWVDb25maWcoaW5kZXg6IG51bWJlcik6IER5bmFtaWNTZWxlY3RGaWVsZENvbmZpZyB7XG4gICAgaWYgKCF0aGlzLnBhcmFtTmFtZUNvbmZpZ0NhY2hlKSB7XG4gICAgICB0aGlzLnBhcmFtTmFtZUNvbmZpZ0NhY2hlID0ge1xuICAgICAgICBrZXk6ICduYW1lJyxcbiAgICAgICAgcGxhY2Vob2xkZXI6ICdQYXJhbWV0ZXIgbmFtZScsXG4gICAgICAgIG11bHRpcGxlOiBmYWxzZSxcbiAgICAgICAgc2VhcmNoYWJsZTogZmFsc2UsXG4gICAgICAgIG9wdGlvbnM6IFtdXG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5wYXJhbU5hbWVDb25maWdDYWNoZTtcbiAgfVxuXG4gIGdldEhlYWRlckZvcm1Hcm91cChpbmRleDogbnVtYmVyKTogRm9ybUdyb3VwIHtcbiAgICByZXR1cm4gdGhpcy5oZWFkZXJzRm9ybUFycmF5LmF0KGluZGV4KSBhcyBGb3JtR3JvdXA7XG4gIH1cblxuICBnZXRQYXJhbUZvcm1Hcm91cChpbmRleDogbnVtYmVyKTogRm9ybUdyb3VwIHtcbiAgICByZXR1cm4gdGhpcy5wYXJhbXNGb3JtQXJyYXkuYXQoaW5kZXgpIGFzIEZvcm1Hcm91cDtcbiAgfVxuXG4gIG9uVGFiQ2hhbmdlKHRhYjogUmVxdWVzdFRhYik6IHZvaWQge1xuICAgIHRoaXMuc2VsZWN0ZWRUYWIgPSB0YWI7XG4gIH1cblxuICBvblNlbmRSZXF1ZXN0KCk6IHZvaWQge1xuICAgIHRoaXMuZm9ybVN1Ym1pdHRlZCA9IHRydWU7XG4gICAgdGhpcy5tYXJrRm9ybUdyb3VwVG91Y2hlZCh0aGlzLmFwaUZvcm0pO1xuICAgIGNvbnNvbGUubG9nKCdvblNlbmRSZXF1ZXN0OiBhcGlGb3JtJywgdGhpcy5hcGlGb3JtLnZhbHVlKTtcbiAgICBjb25zb2xlLmxvZygnb25TZW5kUmVxdWVzdDogYXBpRm9ybSB2YWxpZCcsIHRoaXMuYXBpRm9ybSk7XG4gICAgaWYgKHRoaXMuYXBpRm9ybS52YWxpZCkge1xuICAgICAgY29uc3QgZm9ybVZhbHVlID0gdGhpcy5hcGlGb3JtLnZhbHVlO1xuICAgICAgY29uc3QgaGVhZGVycyA9IGZvcm1WYWx1ZS5oZWFkZXJzLm1hcCgoaDogYW55KSA9PiAoe1xuICAgICAgICBuYW1lOiBoLm5hbWUsXG4gICAgICAgIHZhbHVlOiBoLnZhbHVlXG4gICAgICB9KSk7XG4gICAgICBjb25zdCBwYXJhbXMgPSBmb3JtVmFsdWUucGFyYW1zID8gZm9ybVZhbHVlLnBhcmFtcy5tYXAoKHA6IGFueSkgPT4gKHtcbiAgICAgICAgbmFtZTogcC5uYW1lLFxuICAgICAgICB2YWx1ZTogcC52YWx1ZVxuICAgICAgfSkpIDogW107XG5cbiAgICAgIHRoaXMuc2VuZFJlcXVlc3QuZW1pdCh7XG4gICAgICAgIG1ldGhvZDogZm9ybVZhbHVlLm1ldGhvZCxcbiAgICAgICAgdXJsOiBmb3JtVmFsdWUudXJsLFxuICAgICAgICBoZWFkZXJzLFxuICAgICAgICBib2R5OiBmb3JtVmFsdWUuYm9keSxcbiAgICAgICAgcGFyYW1zXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBvbkltcG9ydEN1cmwoKTogdm9pZCB7XG4gICAgdGhpcy5pbXBvcnRDdXJsLmVtaXQoKTtcbiAgfVxuXG4gIG9uQ2FuY2VsKCk6IHZvaWQge1xuICAgIHRoaXMuY2FuY2VsbGVkLmVtaXQoKTtcbiAgfVxuXG4gIG9uQ3JlYXRlU3RlcCgpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1TdWJtaXR0ZWQgPSB0cnVlO1xuICAgIHRoaXMubWFya0Zvcm1Hcm91cFRvdWNoZWQodGhpcy5hcGlGb3JtKTtcbiAgICBcbiAgICBpZiAodGhpcy5hcGlGb3JtLnZhbGlkKSB7XG4gICAgICBjb25zdCBmb3JtVmFsdWUgPSB0aGlzLmFwaUZvcm0udmFsdWU7XG4gICAgICBjb25zdCBzdGVwRGF0YTogQXBpRm9ybURhdGEgPSB7XG4gICAgICAgIG1ldGhvZDogZm9ybVZhbHVlLm1ldGhvZCxcbiAgICAgICAgdXJsOiBmb3JtVmFsdWUudXJsLFxuICAgICAgICBoZWFkZXJzOiBmb3JtVmFsdWUuaGVhZGVycy5tYXAoKGg6IGFueSkgPT4gKHtcbiAgICAgICAgICBuYW1lOiBoLm5hbWUsXG4gICAgICAgICAgdmFsdWU6IGgudmFsdWVcbiAgICAgICAgfSkpLFxuICAgICAgICBib2R5OiBmb3JtVmFsdWUuYm9keSxcbiAgICAgICAgcGFyYW1zOiBmb3JtVmFsdWUucGFyYW1zID8gZm9ybVZhbHVlLnBhcmFtcy5tYXAoKHA6IGFueSkgPT4gKHtcbiAgICAgICAgICBuYW1lOiBwLm5hbWUsXG4gICAgICAgICAgdmFsdWU6IHAudmFsdWVcbiAgICAgICAgfSkpIDogW10sXG4gICAgICAgIHNjcmlwdHM6IGZvcm1WYWx1ZS5zY3JpcHRzLFxuICAgICAgICB2YXJpYWJsZU5hbWU6IGZvcm1WYWx1ZS52YXJpYWJsZU5hbWUgfHwgJycsXG4gICAgICAgIHZhbGlkYXRpb246IGZvcm1WYWx1ZS52YWxpZGF0aW9uID8gZm9ybVZhbHVlLnZhbGlkYXRpb24ubWFwKCh2OiBhbnkpID0+ICh7XG4gICAgICAgICAganNvblBhdGg6IHYuanNvblBhdGgsXG4gICAgICAgICAgdmVyaWZpY2F0aW9uVHlwZTogdi52ZXJpZmljYXRpb25UeXBlLFxuICAgICAgICAgIGV4cGVjdGVkVHlwZTogdi5leHBlY3RlZFR5cGUsXG4gICAgICAgICAgZXhwZWN0ZWRWYWx1ZTogdi5leHBlY3RlZFZhbHVlLFxuICAgICAgICAgIHJlc3VsdDogdi5yZXN1bHQgfHwgJ05vdCBydW4nXG4gICAgICAgIH0pKSA6IFtdXG4gICAgICB9O1xuICAgICAgY29uc29sZS5sb2coJzk5OTk5OTknLCBzdGVwRGF0YSk7XG4gICAgICB0aGlzLmNyZWF0ZVN0ZXAuZW1pdChzdGVwRGF0YSk7XG4gICAgfVxuICB9XG5cbiAgb25OZXh0KCk6IHZvaWQge1xuICAgIC8vIE1vdmUgdG8gbmV4dCBzdGVwIG9yIGNyZWF0ZSBzdGVwIGlmIG9uIGxhc3Qgc3RlcFxuICAgIGNvbnN0IHN0ZXBPcmRlcjogUHJvZ3Jlc3NTdGVwW10gPSBbJ3JlcXVlc3QtZGV0YWlscycsICdzdG9yZS1yZXNwb25zZScsICd2YWxpZGF0aW9uJ107XG4gICAgY29uc3QgY3VycmVudEluZGV4ID0gc3RlcE9yZGVyLmluZGV4T2YodGhpcy5zZWxlY3RlZFByb2dyZXNzU3RlcCk7XG4gICAgaWYgKGN1cnJlbnRJbmRleCA8IHN0ZXBPcmRlci5sZW5ndGggLSAxKSB7XG4gICAgICB0aGlzLm9uUHJvZ3Jlc3NTdGVwQ2hhbmdlKHN0ZXBPcmRlcltjdXJyZW50SW5kZXggKyAxXSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMub25DcmVhdGVTdGVwKCk7XG4gICAgfVxuICB9XG5cbiAgb25CYWNrKCk6IHZvaWQge1xuICAgIC8vIE1vdmUgdG8gcHJldmlvdXMgc3RlcFxuICAgIGNvbnN0IHN0ZXBPcmRlcjogUHJvZ3Jlc3NTdGVwW10gPSBbJ3JlcXVlc3QtZGV0YWlscycsICdzdG9yZS1yZXNwb25zZScsICd2YWxpZGF0aW9uJ107XG4gICAgY29uc3QgY3VycmVudEluZGV4ID0gc3RlcE9yZGVyLmluZGV4T2YodGhpcy5zZWxlY3RlZFByb2dyZXNzU3RlcCk7XG4gICAgaWYgKGN1cnJlbnRJbmRleCA+IDApIHtcbiAgICAgIHRoaXMub25Qcm9ncmVzc1N0ZXBDaGFuZ2Uoc3RlcE9yZGVyW2N1cnJlbnRJbmRleCAtIDFdKTtcbiAgICB9XG4gIH1cblxuICBjYW5Hb0JhY2soKTogYm9vbGVhbiB7XG4gICAgY29uc3Qgc3RlcE9yZGVyOiBQcm9ncmVzc1N0ZXBbXSA9IFsncmVxdWVzdC1kZXRhaWxzJywgJ3N0b3JlLXJlc3BvbnNlJywgJ3ZhbGlkYXRpb24nXTtcbiAgICBjb25zdCBjdXJyZW50SW5kZXggPSBzdGVwT3JkZXIuaW5kZXhPZih0aGlzLnNlbGVjdGVkUHJvZ3Jlc3NTdGVwKTtcbiAgICByZXR1cm4gY3VycmVudEluZGV4ID4gMDtcbiAgfVxuXG4gIGlzTGFzdFN0ZXAoKTogYm9vbGVhbiB7XG4gICAgY29uc3Qgc3RlcE9yZGVyOiBQcm9ncmVzc1N0ZXBbXSA9IFsncmVxdWVzdC1kZXRhaWxzJywgJ3N0b3JlLXJlc3BvbnNlJywgJ3ZhbGlkYXRpb24nXTtcbiAgICBjb25zdCBjdXJyZW50SW5kZXggPSBzdGVwT3JkZXIuaW5kZXhPZih0aGlzLnNlbGVjdGVkUHJvZ3Jlc3NTdGVwKTtcbiAgICByZXR1cm4gY3VycmVudEluZGV4ID09PSBzdGVwT3JkZXIubGVuZ3RoIC0gMTtcbiAgfVxuXG4gIGdldFByb2dyZXNzU3RlcENsYXNzKHN0ZXA6IFByb2dyZXNzU3RlcCk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3RlcE9yZGVyOiBQcm9ncmVzc1N0ZXBbXSA9IFsncmVxdWVzdC1kZXRhaWxzJywgJ3N0b3JlLXJlc3BvbnNlJywgJ3ZhbGlkYXRpb24nXTtcbiAgICBjb25zdCBjdXJyZW50SW5kZXggPSBzdGVwT3JkZXIuaW5kZXhPZih0aGlzLmN1cnJlbnRTdGVwKTtcbiAgICBjb25zdCBzdGVwSW5kZXggPSBzdGVwT3JkZXIuaW5kZXhPZihzdGVwKTtcblxuICAgIGlmIChzdGVwSW5kZXggPCBjdXJyZW50SW5kZXgpIHtcbiAgICAgIHJldHVybiAnY3FhLXRleHQtZ3JheS00MDAnOyAvLyBDb21wbGV0ZWRcbiAgICB9IGVsc2UgaWYgKHN0ZXBJbmRleCA9PT0gY3VycmVudEluZGV4KSB7XG4gICAgICByZXR1cm4gJ2NxYS10ZXh0LXB1cnBsZS02MDAgY3FhLWZvbnQtc2VtaWJvbGQnOyAvLyBBY3RpdmVcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuICdjcWEtdGV4dC1ncmF5LTQwMCc7IC8vIFBlbmRpbmdcbiAgICB9XG4gIH1cblxuICBnZXRQcm9ncmVzc1N0ZXBOdW1iZXIoc3RlcDogUHJvZ3Jlc3NTdGVwKTogbnVtYmVyIHtcbiAgICBjb25zdCBzdGVwT3JkZXI6IFByb2dyZXNzU3RlcFtdID0gWydyZXF1ZXN0LWRldGFpbHMnLCAnc3RvcmUtcmVzcG9uc2UnLCAndmFsaWRhdGlvbiddO1xuICAgIHJldHVybiBzdGVwT3JkZXIuaW5kZXhPZihzdGVwKSArIDE7XG4gIH1cblxuICBnZXRQcm9ncmVzc1N0ZXBMYWJlbChzdGVwOiBQcm9ncmVzc1N0ZXApOiBzdHJpbmcge1xuICAgIGNvbnN0IGxhYmVsczogUmVjb3JkPFByb2dyZXNzU3RlcCwgc3RyaW5nPiA9IHtcbiAgICAgICdyZXF1ZXN0LWRldGFpbHMnOiAnUmVxdWVzdCBEZXRhaWxzJyxcbiAgICAgICdzdG9yZS1yZXNwb25zZSc6ICdTdG9yZSBSZXNwb25zZScsXG4gICAgICAndmFsaWRhdGlvbic6ICdWYWxpZGF0aW9uJ1xuICAgIH07XG4gICAgcmV0dXJuIGxhYmVsc1tzdGVwXTtcbiAgfVxuXG4gIGZvcm1hdEpzb25SZXNwb25zZShkYXRhOiBhbnkpOiBzdHJpbmcge1xuICAgIGlmICghZGF0YSkgcmV0dXJuICcnO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoZGF0YSwgbnVsbCwgMik7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gU3RyaW5nKGRhdGEpO1xuICAgIH1cbiAgfVxuICBcbiAgb25Qcm9ncmVzc1N0ZXBDaGFuZ2Uoc3RlcDogUHJvZ3Jlc3NTdGVwKTogdm9pZCB7XG4gICAgdGhpcy5zZWxlY3RlZFByb2dyZXNzU3RlcCA9IHN0ZXA7XG4gICAgLy8gSW5pdGlhbGl6ZSB2YWxpZGF0aW9uIGZvcm0gYXJyYXkgaWYgc3dpdGNoaW5nIHRvIHZhbGlkYXRpb24gc3RlcFxuICAgIGlmIChzdGVwID09PSAndmFsaWRhdGlvbicgJiYgdGhpcy52YWxpZGF0aW9uRm9ybUFycmF5Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhpcy5hZGRWYWxpZGF0aW9uUnVsZSgpO1xuICAgIH1cbiAgfVxuXG4gIGFkZFZhbGlkYXRpb25SdWxlKCk6IHZvaWQge1xuICAgIGNvbnN0IHZhbGlkYXRpb25Hcm91cCA9IHRoaXMuZmIuZ3JvdXAoe1xuICAgICAgY2hlY2tlZDogW2ZhbHNlXSxcbiAgICAgIGpzb25QYXRoOiBbJycsIFZhbGlkYXRvcnMucmVxdWlyZWRdLFxuICAgICAgdmVyaWZpY2F0aW9uVHlwZTogWydlcXVhbHMnXSxcbiAgICAgIGV4cGVjdGVkVHlwZTogWydzdHJpbmcnXSxcbiAgICAgIGV4cGVjdGVkVmFsdWU6IFsnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF0sXG4gICAgICByZXN1bHQ6IFsnTm90IHJ1biddXG4gICAgfSk7XG4gICAgLy8gRW5zdXJlIGFsbCBjb250cm9scyBhcmUgZW5hYmxlZCB0byBhdm9pZCBkaXNhYmxlZCBhdHRyaWJ1dGUgd2FybmluZ3NcbiAgICB2YWxpZGF0aW9uR3JvdXAuZW5hYmxlKHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcbiAgICB0aGlzLnZhbGlkYXRpb25Gb3JtQXJyYXkucHVzaCh2YWxpZGF0aW9uR3JvdXApO1xuICB9XG5cbiAgcmVtb3ZlVmFsaWRhdGlvblJ1bGUoaW5kZXg6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMudmFsaWRhdGlvbkZvcm1BcnJheS5yZW1vdmVBdChpbmRleCk7XG4gIH1cblxuICBnZXRWYWxpZGF0aW9uRm9ybUdyb3VwKGluZGV4OiBudW1iZXIpOiBGb3JtR3JvdXAge1xuICAgIHJldHVybiB0aGlzLnZhbGlkYXRpb25Gb3JtQXJyYXkuYXQoaW5kZXgpIGFzIEZvcm1Hcm91cDtcbiAgfVxuXG4gIHRyYWNrQnlWYWxpZGF0aW9uUnVsZUluZGV4KGluZGV4OiBudW1iZXIpOiBudW1iZXIge1xuICAgIHJldHVybiBpbmRleDtcbiAgfVxuXG4gIHRyYWNrQnlIZWFkZXJJbmRleChpbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gaW5kZXg7XG4gIH1cblxuICB0cmFja0J5UGFyYW1JbmRleChpbmRleDogbnVtYmVyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gaW5kZXg7XG4gIH1cblxuICBnZXRWZXJpZmljYXRpb25UeXBlT3B0aW9ucygpOiBTZWxlY3RPcHRpb25bXSB7XG4gICAgcmV0dXJuIFtcbiAgICAgIHsgaWQ6ICdlcXVhbHMnLCB2YWx1ZTogJ2VxdWFscycsIG5hbWU6ICdFcXVhbHMnLCBsYWJlbDogJ0VxdWFscycgfSxcbiAgICAgIHsgaWQ6ICdub3RfZXF1YWxzJywgdmFsdWU6ICdub3RfZXF1YWxzJywgbmFtZTogJ05vdCBFcXVhbHMnLCBsYWJlbDogJ05vdCBFcXVhbHMnIH0sXG4gICAgICB7IGlkOiAnY29udGFpbnMnLCB2YWx1ZTogJ2NvbnRhaW5zJywgbmFtZTogJ0NvbnRhaW5zJywgbGFiZWw6ICdDb250YWlucycgfSxcbiAgICAgIHsgaWQ6ICdub3RfY29udGFpbnMnLCB2YWx1ZTogJ25vdF9jb250YWlucycsIG5hbWU6ICdOb3QgQ29udGFpbnMnLCBsYWJlbDogJ05vdCBDb250YWlucycgfSxcbiAgICAgIHsgaWQ6ICdncmVhdGVyX3RoYW4nLCB2YWx1ZTogJ2dyZWF0ZXJfdGhhbicsIG5hbWU6ICdHcmVhdGVyIFRoYW4nLCBsYWJlbDogJ0dyZWF0ZXIgVGhhbicgfSxcbiAgICAgIHsgaWQ6ICdsZXNzX3RoYW4nLCB2YWx1ZTogJ2xlc3NfdGhhbicsIG5hbWU6ICdMZXNzIFRoYW4nLCBsYWJlbDogJ0xlc3MgVGhhbicgfSxcbiAgICAgIHsgaWQ6ICdncmVhdGVyX3RoYW5fb3JfZXF1YWxzJywgdmFsdWU6ICdncmVhdGVyX3RoYW5fb3JfZXF1YWxzJywgbmFtZTogJ0dyZWF0ZXIgVGhhbiBPciBFcXVhbHMnLCBsYWJlbDogJ0dyZWF0ZXIgVGhhbiBPciBFcXVhbHMnIH0sXG4gICAgICB7IGlkOiAnbGVzc190aGFuX29yX2VxdWFscycsIHZhbHVlOiAnbGVzc190aGFuX29yX2VxdWFscycsIG5hbWU6ICdMZXNzIFRoYW4gT3IgRXF1YWxzJywgbGFiZWw6ICdMZXNzIFRoYW4gT3IgRXF1YWxzJyB9LFxuICAgICAgeyBpZDogJ2V4aXN0cycsIHZhbHVlOiAnZXhpc3RzJywgbmFtZTogJ0V4aXN0cycsIGxhYmVsOiAnRXhpc3RzJyB9LFxuICAgICAgeyBpZDogJ25vdF9leGlzdHMnLCB2YWx1ZTogJ25vdF9leGlzdHMnLCBuYW1lOiAnTm90IEV4aXN0cycsIGxhYmVsOiAnTm90IEV4aXN0cycgfVxuICAgIF07XG4gIH1cblxuICBnZXRFeHBlY3RlZFR5cGVPcHRpb25zKCk6IFNlbGVjdE9wdGlvbltdIHtcbiAgICByZXR1cm4gW1xuICAgICAgeyBpZDogJ3N0cmluZycsIHZhbHVlOiAnc3RyaW5nJywgbmFtZTogJ1N0cmluZycsIGxhYmVsOiAnU3RyaW5nJyB9LFxuICAgICAgeyBpZDogJ251bWJlcicsIHZhbHVlOiAnbnVtYmVyJywgbmFtZTogJ051bWJlcicsIGxhYmVsOiAnTnVtYmVyJyB9LFxuICAgICAgeyBpZDogJ2Jvb2xlYW4nLCB2YWx1ZTogJ2Jvb2xlYW4nLCBuYW1lOiAnQm9vbGVhbicsIGxhYmVsOiAnQm9vbGVhbicgfSxcbiAgICAgIHsgaWQ6ICdvYmplY3QnLCB2YWx1ZTogJ29iamVjdCcsIG5hbWU6ICdPYmplY3QnLCBsYWJlbDogJ09iamVjdCcgfSxcbiAgICAgIHsgaWQ6ICdhcnJheScsIHZhbHVlOiAnYXJyYXknLCBuYW1lOiAnQXJyYXknLCBsYWJlbDogJ0FycmF5JyB9LFxuICAgICAgeyBpZDogJ251bGwnLCB2YWx1ZTogJ251bGwnLCBuYW1lOiAnTnVsbCcsIGxhYmVsOiAnTnVsbCcgfVxuICAgIF07XG4gIH1cblxuICBnZXRWZXJpZmljYXRpb25UeXBlQ29uZmlnKGluZGV4OiBudW1iZXIpOiBEeW5hbWljU2VsZWN0RmllbGRDb25maWcge1xuICAgIC8vIENhY2hlIHRoZSBjb25maWcgdG8gcHJldmVudCBpbmZpbml0ZSBjaGFuZ2UgZGV0ZWN0aW9uIGxvb3BzXG4gICAgaWYgKCF0aGlzLnZlcmlmaWNhdGlvblR5cGVDb25maWdDYWNoZSkge1xuICAgICAgdGhpcy52ZXJpZmljYXRpb25UeXBlQ29uZmlnQ2FjaGUgPSB7XG4gICAgICAgIGtleTogJ3ZlcmlmaWNhdGlvblR5cGUnLFxuICAgICAgICBwbGFjZWhvbGRlcjogJ1NlbGVjdCB2ZXJpZmljYXRpb24gdHlwZScsXG4gICAgICAgIG11bHRpcGxlOiBmYWxzZSxcbiAgICAgICAgc2VhcmNoYWJsZTogZmFsc2UsXG4gICAgICAgIG9wdGlvbnM6IHRoaXMuZ2V0VmVyaWZpY2F0aW9uVHlwZU9wdGlvbnMoKVxuICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudmVyaWZpY2F0aW9uVHlwZUNvbmZpZ0NhY2hlO1xuICB9XG5cbiAgZ2V0RXhwZWN0ZWRUeXBlQ29uZmlnKGluZGV4OiBudW1iZXIpOiBEeW5hbWljU2VsZWN0RmllbGRDb25maWcge1xuICAgIC8vIENhY2hlIHRoZSBjb25maWcgdG8gcHJldmVudCBpbmZpbml0ZSBjaGFuZ2UgZGV0ZWN0aW9uIGxvb3BzXG4gICAgaWYgKCF0aGlzLmV4cGVjdGVkVHlwZUNvbmZpZ0NhY2hlKSB7XG4gICAgICB0aGlzLmV4cGVjdGVkVHlwZUNvbmZpZ0NhY2hlID0ge1xuICAgICAgICBrZXk6ICdleHBlY3RlZFR5cGUnLFxuICAgICAgICBwbGFjZWhvbGRlcjogJ1NlbGVjdCBleHBlY3RlZCB0eXBlJyxcbiAgICAgICAgbXVsdGlwbGU6IGZhbHNlLFxuICAgICAgICBzZWFyY2hhYmxlOiBmYWxzZSxcbiAgICAgICAgb3B0aW9uczogdGhpcy5nZXRFeHBlY3RlZFR5cGVPcHRpb25zKClcbiAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmV4cGVjdGVkVHlwZUNvbmZpZ0NhY2hlO1xuICB9XG5cbiAgZ2V0UmVzdWx0Q2xhc3MocmVzdWx0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmIChyZXN1bHQgPT09ICdQYXNzJykge1xuICAgICAgcmV0dXJuICdjcWEtYmctZ3JlZW4tNTAwIGNxYS10ZXh0LXdoaXRlJztcbiAgICB9IGVsc2UgaWYgKHJlc3VsdCA9PT0gJ0ZhaWwnKSB7XG4gICAgICByZXR1cm4gJ2NxYS1iZy1yZWQtNTAwIGNxYS10ZXh0LXdoaXRlJztcbiAgICB9XG4gICAgcmV0dXJuICdjcWEtYmctZ3JheS0zMDAgY3FhLXRleHQtZ3JheS03MDAnO1xuICB9XG5cbiAgZ2V0IGFsbFZhbGlkYXRpb25SdWxlc1NlbGVjdGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnZhbGlkYXRpb25Gb3JtQXJyYXkubGVuZ3RoID4gMCAmJiBcbiAgICAgICAgICAgdGhpcy52YWxpZGF0aW9uRm9ybUFycmF5LmNvbnRyb2xzLmV2ZXJ5KGNvbnRyb2wgPT4gY29udHJvbC5nZXQoJ2NoZWNrZWQnKT8udmFsdWUpO1xuICB9XG5cbiAgZ2V0IHNvbWVWYWxpZGF0aW9uUnVsZXNTZWxlY3RlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy52YWxpZGF0aW9uRm9ybUFycmF5LmNvbnRyb2xzLnNvbWUoY29udHJvbCA9PiBjb250cm9sLmdldCgnY2hlY2tlZCcpPy52YWx1ZSkgJiYgXG4gICAgICAgICAgICF0aGlzLmFsbFZhbGlkYXRpb25SdWxlc1NlbGVjdGVkO1xuICB9XG5cbiAgb25TZWxlY3RBbGxWYWxpZGF0aW9uUnVsZXMoY2hlY2tlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMudmFsaWRhdGlvbkZvcm1BcnJheS5jb250cm9scy5mb3JFYWNoKGNvbnRyb2wgPT4ge1xuICAgICAgY29udHJvbC5nZXQoJ2NoZWNrZWQnKT8uc2V0VmFsdWUoY2hlY2tlZCk7XG4gICAgfSk7XG4gIH1cblxuICBvbkRlbGV0ZVNlbGVjdGVkVmFsaWRhdGlvblJ1bGVzKCk6IHZvaWQge1xuICAgIGNvbnN0IGluZGljZXNUb1JlbW92ZTogbnVtYmVyW10gPSBbXTtcbiAgICB0aGlzLnZhbGlkYXRpb25Gb3JtQXJyYXkuY29udHJvbHMuZm9yRWFjaCgoY29udHJvbCwgaW5kZXgpID0+IHtcbiAgICAgIGlmIChjb250cm9sLmdldCgnY2hlY2tlZCcpPy52YWx1ZSkge1xuICAgICAgICBpbmRpY2VzVG9SZW1vdmUucHVzaChpbmRleCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgLy8gUmVtb3ZlIGluIHJldmVyc2Ugb3JkZXIgdG8gbWFpbnRhaW4gY29ycmVjdCBpbmRpY2VzXG4gICAgaW5kaWNlc1RvUmVtb3ZlLnJldmVyc2UoKS5mb3JFYWNoKGluZGV4ID0+IHtcbiAgICAgIHRoaXMucmVtb3ZlVmFsaWRhdGlvblJ1bGUoaW5kZXgpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBtYXJrRm9ybUdyb3VwVG91Y2hlZChmb3JtR3JvdXA6IEZvcm1Hcm91cCk6IHZvaWQge1xuICAgIE9iamVjdC5rZXlzKGZvcm1Hcm91cC5jb250cm9scykuZm9yRWFjaChrZXkgPT4ge1xuICAgICAgY29uc3QgY29udHJvbCA9IGZvcm1Hcm91cC5nZXQoa2V5KTtcbiAgICAgIGlmIChjb250cm9sKSB7XG4gICAgICAgIGNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xuICAgICAgICBpZiAoY29udHJvbCBpbnN0YW5jZW9mIEZvcm1Hcm91cCkge1xuICAgICAgICAgIHRoaXMubWFya0Zvcm1Hcm91cFRvdWNoZWQoY29udHJvbCk7XG4gICAgICAgIH0gZWxzZSBpZiAoY29udHJvbCBpbnN0YW5jZW9mIEZvcm1BcnJheSkge1xuICAgICAgICAgIGNvbnRyb2wuY29udHJvbHMuZm9yRWFjaCgoY3RybDogYW55KSA9PiB7XG4gICAgICAgICAgICBpZiAoY3RybCBpbnN0YW5jZW9mIEZvcm1Hcm91cCkge1xuICAgICAgICAgICAgICB0aGlzLm1hcmtGb3JtR3JvdXBUb3VjaGVkKGN0cmwpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgY3RybC5tYXJrQXNUb3VjaGVkKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIG9uVXJsQ2hhbmdlKHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCB1cmxDb250cm9sID0gdGhpcy5hcGlGb3JtLmdldCgndXJsJyk7XG4gICAgaWYgKHVybENvbnRyb2wpIHtcbiAgICAgIHVybENvbnRyb2wuc2V0VmFsdWUodmFsdWUpO1xuICAgICAgdXJsQ29udHJvbC51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7XG4gICAgfVxuICB9XG5cbiAgb25VcmxCbHVyKCk6IHZvaWQge1xuICAgIGNvbnN0IHVybENvbnRyb2wgPSB0aGlzLmFwaUZvcm0uZ2V0KCd1cmwnKTtcbiAgICBpZiAodXJsQ29udHJvbCkge1xuICAgICAgdXJsQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0VXJsRXJyb3JzKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCB1cmxDb250cm9sID0gdGhpcy5hcGlGb3JtLmdldCgndXJsJyk7XG4gICAgaWYgKCF1cmxDb250cm9sIHx8ICghdGhpcy5mb3JtU3VibWl0dGVkICYmICF1cmxDb250cm9sLnRvdWNoZWQpKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuXG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xuICAgIFxuICAgIGlmICh1cmxDb250cm9sLmVycm9ycz8uWydyZXF1aXJlZCddKSB7XG4gICAgICBlcnJvcnMucHVzaCgnVVJMIGlzIHJlcXVpcmVkJyk7XG4gICAgfSBlbHNlIGlmICh1cmxDb250cm9sLmVycm9ycz8uWydwYXR0ZXJuJ10pIHtcbiAgICAgIGVycm9ycy5wdXNoKCdVUkwgaXMgbm90IHZhbGlkJyk7XG4gICAgfSBlbHNlIGlmICh1cmxDb250cm9sLmVycm9ycz8uWydoYXNQYXJhbWV0ZXInXSkge1xuICAgICAgZXJyb3JzLnB1c2goJ1VSTCBmb3JtYXQgaXMgaW52YWxpZC4gUGxlYXNlIGNoZWNrIHRoZSBwYXJhbWV0ZXIgZm9ybWF0LicpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gZXJyb3JzO1xuICB9XG59XG5cbiIsIjxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWgtZnVsbCBjcWEtYmctd2hpdGUgY3FhLXB4LTQgY3FhLXB5LTJcIj5cbiAgPCEtLSBIZWFkZXIgLS0+XG4gIDxoMiBjbGFzcz1cImNxYS10ZXh0LVsxMnB4XSBjcWEtZm9udC1zZW1pYm9sZCBjcWEtdGV4dC1ibGFjay0xMDAgY3FhLW1iLTRcIj5cbiAgICBDcmVhdGUgQVBJIFRlc3QgU3RlcFxuICA8L2gyPlxuXG4gIDwhLS0gUHJvZ3Jlc3MgVHJhY2tlciAtLT5cbiAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC00IGNxYS1tYi02IGNxYS1wYi00IGNxYS1ib3JkZXItYiBjcWEtYm9yZGVyLWdyYXktMjAwXCI+XG4gICAgPCEtLSA8ZGl2ICpuZ0Zvcj1cImxldCBzdGVwIG9mIHByb2dyZXNzU3RlcHNcIlxuICAgICAgICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMlwiXG4gICAgICAgICBbbmdDbGFzc109XCJnZXRQcm9ncmVzc1N0ZXBDbGFzcyhzdGVwKVwiPlxuICAgICAgPHNwYW4gY2xhc3M9XCJjcWEtdGV4dC1zbSBjcWEtZm9udC1tZWRpdW1cIj57eyBnZXRQcm9ncmVzc1N0ZXBOdW1iZXIoc3RlcCkgfX0ge3sgZ2V0UHJvZ3Jlc3NTdGVwTGFiZWwoc3RlcCkgfX08L3NwYW4+XG4gICAgICA8c3BhbiAqbmdJZj1cInN0ZXAgIT09ICd2YWxpZGF0aW9uJ1wiIGNsYXNzPVwiY3FhLXRleHQtZ3JheS0zMDBcIj7igKI8L3NwYW4+XG4gICAgPC9kaXY+IC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS13LWZ1bGwgY3FhLWp1c3RpZnktYmV0d2VlblwiPlxuICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0yXCIgW25nQ2xhc3NdPVwieydjcWEtdGV4dC1wdXJwbGUtNjAwIGNxYS1mb250LXNlbWlib2xkJzogc2VsZWN0ZWRQcm9ncmVzc1N0ZXAgPT09ICdyZXF1ZXN0LWRldGFpbHMnfVwiIChjbGljayk9XCJvblByb2dyZXNzU3RlcENoYW5nZSgncmVxdWVzdC1kZXRhaWxzJylcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXctOCBjcWEtaC04IGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1yb3VuZGVkLWZ1bGwgY3FhLWJnLXB1cnBsZS02MDAgY3FhLXRleHQtd2hpdGUgY3FhLXRleHQteHMgY3FhLWZvbnQtc2VtaWJvbGRcIj4xPC9kaXY+XG4gICAgICAgICAgPGRpdj5SZXF1ZXN0IERldGFpbHM8L2Rpdj5cbiAgICAgICAgICA8ZGl2PjwvZGl2PlxuICAgICAgICAgPC9kaXY+XG4gICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTJcIiBbbmdDbGFzc109XCJ7J2NxYS10ZXh0LXB1cnBsZS02MDAgY3FhLWZvbnQtc2VtaWJvbGQnOiBzZWxlY3RlZFByb2dyZXNzU3RlcCA9PT0gJ3N0b3JlLXJlc3BvbnNlJ31cIiAoY2xpY2spPVwib25Qcm9ncmVzc1N0ZXBDaGFuZ2UoJ3N0b3JlLXJlc3BvbnNlJylcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXctOCBjcWEtaC04IGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1yb3VuZGVkLWZ1bGwgY3FhLWJnLXB1cnBsZS02MDAgY3FhLXRleHQtd2hpdGUgY3FhLXRleHQteHMgY3FhLWZvbnQtc2VtaWJvbGRcIj4yPC9kaXY+XG4gICAgICAgICAgPGRpdj5TdG9yZSBSZXNwb25zZTwvZGl2PlxuICAgICAgICAgIDxkaXY+PC9kaXY+XG4gICAgICAgICA8L2Rpdj5cbiAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMlwiIFtuZ0NsYXNzXT1cInsnY3FhLXRleHQtcHVycGxlLTYwMCBjcWEtZm9udC1zZW1pYm9sZCc6IHNlbGVjdGVkUHJvZ3Jlc3NTdGVwID09PSAndmFsaWRhdGlvbid9XCIgKGNsaWNrKT1cIm9uUHJvZ3Jlc3NTdGVwQ2hhbmdlKCd2YWxpZGF0aW9uJylcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXctOCBjcWEtaC04IGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS1yb3VuZGVkLWZ1bGwgY3FhLWJnLXB1cnBsZS02MDAgY3FhLXRleHQtd2hpdGUgY3FhLXRleHQteHMgY3FhLWZvbnQtc2VtaWJvbGRcIj4zPC9kaXY+XG4gICAgICAgICAgPGRpdj5WYWxpZGF0aW9uPC9kaXY+XG4gICAgICAgICAgPGRpdj48L2Rpdj5cbiAgICAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbiAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNlbGVjdGVkUHJvZ3Jlc3NTdGVwID09PSAncmVxdWVzdC1kZXRhaWxzJ1wiPlxuICA8IS0tIEFQSSBSZXF1ZXN0IENvbmZpZ3VyYXRpb24gLS0+XG4gIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtc3RhcnQgY3FhLWdhcC0yIGNxYS1tYi0zXCI+XG4gICAgPGRpdiBjbGFzcz1cImNxYS13LTMyIGNxYS1mbGV4LXNocmluay0wXCI+XG4gICAgICA8Y3FhLWR5bmFtaWMtc2VsZWN0XG4gICAgICAgIFtmb3JtXT1cImFwaUZvcm1cIlxuICAgICAgICBbY29uZmlnXT1cImdldEh0dHBNZXRob2RDb25maWcoKVwiPlxuICAgICAgPC9jcWEtZHluYW1pYy1zZWxlY3Q+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4LTFcIj5cbiAgICAgIDxjcWEtY3VzdG9tLWlucHV0XG4gICAgICAgIFtwbGFjZWhvbGRlcl09XCInRW50ZXIgQVBJIGVuZHBvaW50IFVSTCdcIlxuICAgICAgICBbdmFsdWVdPVwiYXBpRm9ybS5nZXQoJ3VybCcpPy52YWx1ZSB8fCAnJ1wiXG4gICAgICAgIFtmdWxsV2lkdGhdPVwidHJ1ZVwiXG4gICAgICAgIFtlcnJvcnNdPVwiZ2V0VXJsRXJyb3JzKClcIlxuICAgICAgICAodmFsdWVDaGFuZ2UpPVwib25VcmxDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgIChibHVycmVkKT1cIm9uVXJsQmx1cigpXCI+XG4gICAgICA8L2NxYS1jdXN0b20taW5wdXQ+XG4gICAgPC9kaXY+XG4gICAgPGNxYS1idXR0b25cbiAgICAgIHZhcmlhbnQ9XCJvdXRsaW5lZFwiXG4gICAgICB0ZXh0PVwiSW1wb3J0IEFQSSBjVVJMXCJcbiAgICAgIChjbGlja2VkKT1cIm9uSW1wb3J0Q3VybCgpXCI+XG4gICAgPC9jcWEtYnV0dG9uPlxuICAgIDxjcWEtYnV0dG9uXG4gICAgICB2YXJpYW50PVwiZmlsbGVkXCJcbiAgICAgIHRleHQ9XCJTZW5kIFJlcXVlc3RcIlxuICAgICAgKGNsaWNrZWQpPVwib25TZW5kUmVxdWVzdCgpXCJcbiAgICAgIFtkaXNhYmxlZF09XCIhYXBpRm9ybS5nZXQoJ3VybCcpPy52YWx1ZSB8fCBpc0xvYWRpbmdcIj5cbiAgICA8L2NxYS1idXR0b24+XG4gIDwvZGl2PlxuXG4gIDwhLS0gUmVxdWVzdCBEZXRhaWxzIFRhYnMgLS0+XG4gIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWZsZXgtMSBjcWEtb3ZlcmZsb3ctaGlkZGVuIGNxYS1tYi02XCI+XG4gICAgPCEtLSBUYWIgTmF2aWdhdGlvbiAtLT5cbiAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtYm9yZGVyLWIgY3FhLWJvcmRlci1ncmF5LTIwMCBjcWEtYmctZ3JheS01MFwiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgY2xhc3M9XCJjcWEtcHgtNCBjcWEtcHktMiBjcWEtdGV4dC1zbSBjcWEtZm9udC1tZWRpdW0gY3FhLXRyYW5zaXRpb24tY29sb3JzIGNxYS1ib3JkZXItYi0yXCJcbiAgICAgICAgW2NsYXNzLmNxYS10ZXh0LWJsdWUtNjAwXT1cInNlbGVjdGVkVGFiID09PSAnaGVhZGVycydcIlxuICAgICAgICBbY2xhc3MuY3FhLWJvcmRlci1ibHVlLTYwMF09XCJzZWxlY3RlZFRhYiA9PT0gJ2hlYWRlcnMnXCJcbiAgICAgICAgW2NsYXNzLmNxYS10ZXh0LWdyYXktNjAwXT1cInNlbGVjdGVkVGFiICE9PSAnaGVhZGVycydcIlxuICAgICAgICBbY2xhc3MuY3FhLWJvcmRlci10cmFuc3BhcmVudF09XCJzZWxlY3RlZFRhYiAhPT0gJ2hlYWRlcnMnXCJcbiAgICAgICAgKGNsaWNrKT1cIm9uVGFiQ2hhbmdlKCdoZWFkZXJzJylcIj5cbiAgICAgICAgSGVhZGVyc1xuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImNxYS1weC00IGNxYS1weS0yIGNxYS10ZXh0LXNtIGNxYS1mb250LW1lZGl1bSBjcWEtdHJhbnNpdGlvbi1jb2xvcnMgY3FhLWJvcmRlci1iLTJcIlxuICAgICAgICBbY2xhc3MuY3FhLXRleHQtYmx1ZS02MDBdPVwic2VsZWN0ZWRUYWIgPT09ICdib2R5J1wiXG4gICAgICAgIFtjbGFzcy5jcWEtYm9yZGVyLWJsdWUtNjAwXT1cInNlbGVjdGVkVGFiID09PSAnYm9keSdcIlxuICAgICAgICBbY2xhc3MuY3FhLXRleHQtZ3JheS02MDBdPVwic2VsZWN0ZWRUYWIgIT09ICdib2R5J1wiXG4gICAgICAgIFtjbGFzcy5jcWEtYm9yZGVyLXRyYW5zcGFyZW50XT1cInNlbGVjdGVkVGFiICE9PSAnYm9keSdcIlxuICAgICAgICAoY2xpY2spPVwib25UYWJDaGFuZ2UoJ2JvZHknKVwiPlxuICAgICAgICBCb2R5XG4gICAgICA8L2J1dHRvbj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIGNsYXNzPVwiY3FhLXB4LTQgY3FhLXB5LTIgY3FhLXRleHQtc20gY3FhLWZvbnQtbWVkaXVtIGNxYS10cmFuc2l0aW9uLWNvbG9ycyBjcWEtYm9yZGVyLWItMlwiXG4gICAgICAgIFtjbGFzcy5jcWEtdGV4dC1ibHVlLTYwMF09XCJzZWxlY3RlZFRhYiA9PT0gJ3BhcmFtcydcIlxuICAgICAgICBbY2xhc3MuY3FhLWJvcmRlci1ibHVlLTYwMF09XCJzZWxlY3RlZFRhYiA9PT0gJ3BhcmFtcydcIlxuICAgICAgICBbY2xhc3MuY3FhLXRleHQtZ3JheS02MDBdPVwic2VsZWN0ZWRUYWIgIT09ICdwYXJhbXMnXCJcbiAgICAgICAgW2NsYXNzLmNxYS1ib3JkZXItdHJhbnNwYXJlbnRdPVwic2VsZWN0ZWRUYWIgIT09ICdwYXJhbXMnXCJcbiAgICAgICAgKGNsaWNrKT1cIm9uVGFiQ2hhbmdlKCdwYXJhbXMnKVwiPlxuICAgICAgICBQYXJhbXNcbiAgICAgIDwvYnV0dG9uPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgY2xhc3M9XCJjcWEtcHgtNCBjcWEtcHktMiBjcWEtdGV4dC1zbSBjcWEtZm9udC1tZWRpdW0gY3FhLXRyYW5zaXRpb24tY29sb3JzIGNxYS1ib3JkZXItYi0yXCJcbiAgICAgICAgW2NsYXNzLmNxYS10ZXh0LWJsdWUtNjAwXT1cInNlbGVjdGVkVGFiID09PSAnc2NyaXB0cydcIlxuICAgICAgICBbY2xhc3MuY3FhLWJvcmRlci1ibHVlLTYwMF09XCJzZWxlY3RlZFRhYiA9PT0gJ3NjcmlwdHMnXCJcbiAgICAgICAgW2NsYXNzLmNxYS10ZXh0LWdyYXktNjAwXT1cInNlbGVjdGVkVGFiICE9PSAnc2NyaXB0cydcIlxuICAgICAgICBbY2xhc3MuY3FhLWJvcmRlci10cmFuc3BhcmVudF09XCJzZWxlY3RlZFRhYiAhPT0gJ3NjcmlwdHMnXCJcbiAgICAgICAgKGNsaWNrKT1cIm9uVGFiQ2hhbmdlKCdzY3JpcHRzJylcIj5cbiAgICAgICAgU2NyaXB0c1xuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIFRhYiBDb250ZW50IC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleC0xIGNxYS1vdmVyZmxvdy15LWF1dG8gY3FhLXAtNCBjcWEtYm9yZGVyIGNxYS1ib3JkZXItZ3JheS0yMDAgY3FhLWJvcmRlci10LTAgY3FhLXJvdW5kZWQtYi1sZ1wiPlxuICAgICAgPCEtLSBIZWFkZXJzIFRhYiAtLT5cbiAgICAgIDxkaXYgKm5nSWY9XCJzZWxlY3RlZFRhYiA9PT0gJ2hlYWRlcnMnXCIgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWdhcC0zXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZ3JpZCBjcWEtZ3JpZC1jb2xzLTIgY3FhLWdhcC00IGNxYS1pdGVtcy1zdGFydFwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdGV4dC14cyBjcWEtZm9udC1zZW1pYm9sZCBjcWEtdGV4dC1ncmF5LTcwMCBjcWEtdXBwZXJjYXNlXCI+SGVhZGVyIE5hbWUqPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS10ZXh0LXhzIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LWdyYXktNzAwIGNxYS11cHBlcmNhc2VcIj5IZWFkZXIgVmFsdWUqPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBoZWFkZXIgb2YgaGVhZGVyc0Zvcm1BcnJheS5jb250cm9sczsgbGV0IGkgPSBpbmRleDsgdHJhY2tCeTogdHJhY2tCeUhlYWRlckluZGV4XCIgXG4gICAgICAgICAgICAgY2xhc3M9XCJjcWEtZ3JpZCBjcWEtZ3JpZC1jb2xzLTIgY3FhLWdhcC00IGNxYS1pdGVtcy1jZW50ZXJcIj5cbiAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPGNxYS1keW5hbWljLXNlbGVjdFxuICAgICAgICAgICAgICBbZm9ybV09XCJnZXRIZWFkZXJGb3JtR3JvdXAoaSlcIlxuICAgICAgICAgICAgICBbY29uZmlnXT1cImdldEhlYWRlck5hbWVDb25maWcoaSlcIj5cbiAgICAgICAgICAgIDwvY3FhLWR5bmFtaWMtc2VsZWN0PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMlwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4LTFcIj5cbiAgICAgICAgICAgICAgPGNxYS1jdXN0b20taW5wdXRcbiAgICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ0hlYWRlciB2YWx1ZSdcIlxuICAgICAgICAgICAgICAgIFt2YWx1ZV09XCJnZXRIZWFkZXJGb3JtR3JvdXAoaSkuZ2V0KCd2YWx1ZScpPy52YWx1ZSB8fCAnJ1wiXG4gICAgICAgICAgICAgICAgW2Z1bGxXaWR0aF09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwiZ2V0SGVhZGVyRm9ybUdyb3VwKGkpLmdldCgndmFsdWUnKT8uc2V0VmFsdWUoJGV2ZW50KVwiPlxuICAgICAgICAgICAgICA8L2NxYS1jdXN0b20taW5wdXQ+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtanVzdGlmeS1jZW50ZXIgY3FhLXctOCBjcWEtaC04IGNxYS1yb3VuZGVkIGNxYS10ZXh0LXJlZC01MDAgaG92ZXI6Y3FhLXRleHQtcmVkLTcwMCBob3ZlcjpjcWEtYmctcmVkLTUwIGNxYS10cmFuc2l0aW9uLWNvbG9yc1wiXG4gICAgICAgICAgICAgIChjbGljayk9XCJyZW1vdmVIZWFkZXIoaSlcIlxuICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidSZW1vdmUgaGVhZGVyJ1wiPlxuICAgICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjcWEtdGV4dC1sZ1wiPmRlbGV0ZTwvbWF0LWljb24+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICBjbGFzcz1cImNxYS10ZXh0LWJsdWUtNjAwIGNxYS10ZXh0LXNtIGNxYS1mb250LW1lZGl1bSBjcWEtc2VsZi1zdGFydCBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMSBob3ZlcjpjcWEtdGV4dC1ibHVlLTcwMCBjcWEtdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICAgIChjbGljayk9XCJhZGRIZWFkZXIoKVwiPlxuICAgICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImNxYS10ZXh0LWJhc2VcIj5hZGQ8L21hdC1pY29uPlxuICAgICAgICAgIDxzcGFuPkFkZCBIZWFkZXI8L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gQm9keSBUYWIgLS0+XG4gICAgICA8ZGl2ICpuZ0lmPVwic2VsZWN0ZWRUYWIgPT09ICdib2R5J1wiIGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1nYXAtM1wiPlxuICAgICAgICA8Y3FhLWN1c3RvbS10ZXh0YXJlYVxuICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInRW50ZXIgcmVxdWVzdCBib2R5IChKU09OLCBYTUwsIGV0Yy4pJ1wiXG4gICAgICAgICAgW3ZhbHVlXT1cImFwaUZvcm0uZ2V0KCdib2R5Jyk/LnZhbHVlIHx8ICcnXCJcbiAgICAgICAgICBbZnVsbFdpZHRoXT1cInRydWVcIlxuICAgICAgICAgIFtyb3dzXT1cIjEwXCJcbiAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwiYXBpRm9ybS5nZXQoJ2JvZHknKT8uc2V0VmFsdWUoJGV2ZW50KVwiPlxuICAgICAgICA8L2NxYS1jdXN0b20tdGV4dGFyZWE+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBQYXJhbXMgVGFiIC0tPlxuICAgICAgPGRpdiAqbmdJZj1cInNlbGVjdGVkVGFiID09PSAncGFyYW1zJ1wiIGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1nYXAtM1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWdyaWQgY3FhLWdyaWQtY29scy0yIGNxYS1nYXAtNCBjcWEtaXRlbXMtc3RhcnRcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQteHMgY3FhLWZvbnQtc2VtaWJvbGQgY3FhLXRleHQtZ3JheS03MDAgY3FhLXVwcGVyY2FzZVwiPlBhcmFtZXRlciBOYW1lPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS10ZXh0LXhzIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LWdyYXktNzAwIGNxYS11cHBlcmNhc2VcIj5QYXJhbWV0ZXIgVmFsdWU8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgKm5nRm9yPVwibGV0IHBhcmFtIG9mIHBhcmFtc0Zvcm1BcnJheS5jb250cm9sczsgbGV0IGkgPSBpbmRleDsgdHJhY2tCeTogdHJhY2tCeVBhcmFtSW5kZXhcIiBcbiAgICAgICAgICAgICBjbGFzcz1cImNxYS1ncmlkIGNxYS1ncmlkLWNvbHMtMiBjcWEtZ2FwLTQgY3FhLWl0ZW1zLWNlbnRlclwiPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8Y3FhLWN1c3RvbS1pbnB1dFxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1BhcmFtZXRlciBuYW1lJ1wiXG4gICAgICAgICAgICAgIFt2YWx1ZV09XCJnZXRQYXJhbUZvcm1Hcm91cChpKS5nZXQoJ25hbWUnKT8udmFsdWUgfHwgJydcIlxuICAgICAgICAgICAgICBbZnVsbFdpZHRoXT1cInRydWVcIlxuICAgICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwiZ2V0UGFyYW1Gb3JtR3JvdXAoaSkuZ2V0KCduYW1lJyk/LnNldFZhbHVlKCRldmVudClcIj5cbiAgICAgICAgICAgIDwvY3FhLWN1c3RvbS1pbnB1dD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTJcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleC0xXCI+XG4gICAgICAgICAgICAgIDxjcWEtY3VzdG9tLWlucHV0XG4gICAgICAgICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIidQYXJhbWV0ZXIgdmFsdWUnXCJcbiAgICAgICAgICAgICAgICBbdmFsdWVdPVwiZ2V0UGFyYW1Gb3JtR3JvdXAoaSkuZ2V0KCd2YWx1ZScpPy52YWx1ZSB8fCAnJ1wiXG4gICAgICAgICAgICAgICAgW2Z1bGxXaWR0aF09XCJ0cnVlXCJcbiAgICAgICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwiZ2V0UGFyYW1Gb3JtR3JvdXAoaSkuZ2V0KCd2YWx1ZScpPy5zZXRWYWx1ZSgkZXZlbnQpXCI+XG4gICAgICAgICAgICAgIDwvY3FhLWN1c3RvbS1pbnB1dD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1qdXN0aWZ5LWNlbnRlciBjcWEtdy04IGNxYS1oLTggY3FhLXJvdW5kZWQgY3FhLXRleHQtcmVkLTUwMCBob3ZlcjpjcWEtdGV4dC1yZWQtNzAwIGhvdmVyOmNxYS1iZy1yZWQtNTAgY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInJlbW92ZVBhcmFtKGkpXCJcbiAgICAgICAgICAgICAgW2F0dHIuYXJpYS1sYWJlbF09XCInUmVtb3ZlIHBhcmFtZXRlcidcIj5cbiAgICAgICAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwiY3FhLXRleHQtbGdcIj5kZWxldGU8L21hdC1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgY2xhc3M9XCJjcWEtdGV4dC1ibHVlLTYwMCBjcWEtdGV4dC1zbSBjcWEtZm9udC1tZWRpdW0gY3FhLXNlbGYtc3RhcnQgY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTEgaG92ZXI6Y3FhLXRleHQtYmx1ZS03MDAgY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgICAoY2xpY2spPVwiYWRkUGFyYW0oKVwiPlxuICAgICAgICAgIDxtYXQtaWNvbiBjbGFzcz1cImNxYS10ZXh0LWJhc2VcIj5hZGQ8L21hdC1pY29uPlxuICAgICAgICAgIDxzcGFuPkFkZCBQYXJhbWV0ZXI8L3NwYW4+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gU2NyaXB0cyBUYWIgLS0+XG4gICAgICA8ZGl2ICpuZ0lmPVwic2VsZWN0ZWRUYWIgPT09ICdzY3JpcHRzJ1wiIGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1nYXAtM1wiPlxuICAgICAgICA8Y3FhLWN1c3RvbS10ZXh0YXJlYVxuICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInRW50ZXIgc2NyaXB0cyAoSmF2YVNjcmlwdCwgZXRjLiknXCJcbiAgICAgICAgICBbdmFsdWVdPVwiYXBpRm9ybS5nZXQoJ3NjcmlwdHMnKT8udmFsdWUgfHwgJydcIlxuICAgICAgICAgIFtmdWxsV2lkdGhdPVwidHJ1ZVwiXG4gICAgICAgICAgW3Jvd3NdPVwiMTBcIlxuICAgICAgICAgICh2YWx1ZUNoYW5nZSk9XCJhcGlGb3JtLmdldCgnc2NyaXB0cycpPy5zZXRWYWx1ZSgkZXZlbnQpXCI+XG4gICAgICAgIDwvY3FhLWN1c3RvbS10ZXh0YXJlYT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cblxuXG48L25nLWNvbnRhaW5lcj5cbjxuZy1jb250YWluZXIgKm5nSWY9XCJzZWxlY3RlZFByb2dyZXNzU3RlcCA9PT0gJ3N0b3JlLXJlc3BvbnNlJ1wiPlxuICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1mbGV4LTEgY3FhLW1heC1oLVs1MDBweF0gY3FhLW92ZXJmbG93LXktYXV0b1wiPlxuICAgIDwhLS0gU3RvcmUgUmVzcG9uc2UgVGl0bGUgLS0+XG4gICAgPGgzIGNsYXNzPVwiY3FhLXRleHQtWzEycHhdIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LWJsYWNrLTEwMCBjcWEtbWItNFwiPlxuICAgICAgU3RvcmUgUmVzcG9uc2VcbiAgICA8L2gzPlxuXG4gICAgPCEtLSBWYXJpYWJsZSBOYW1lIElucHV0IC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjcWEtbWItNlwiPlxuICAgICAgPGxhYmVsIGNsYXNzPVwiY3FhLXRleHQtWzEycHhdIGNxYS1mb250LW1lZGl1bSBjcWEtdGV4dC1ncmF5LTcwMCBjcWEtbWItMSBjcWEtYmxvY2tcIj5cbiAgICAgICAgVmFyaWFibGUgTmFtZVxuICAgICAgPC9sYWJlbD5cbiAgICAgIDxjcWEtY3VzdG9tLWlucHV0XG4gICAgICAgIFtwbGFjZWhvbGRlcl09XCInVmFyaWFibGUgTmFtZSdcIlxuICAgICAgICBbdmFsdWVdPVwiYXBpRm9ybS5nZXQoJ3ZhcmlhYmxlTmFtZScpPy52YWx1ZSB8fCAnJ1wiXG4gICAgICAgIFtmdWxsV2lkdGhdPVwidHJ1ZVwiXG4gICAgICAgICh2YWx1ZUNoYW5nZSk9XCJhcGlGb3JtLmdldCgndmFyaWFibGVOYW1lJyk/LnNldFZhbHVlKCRldmVudClcIj5cbiAgICAgIDwvY3FhLWN1c3RvbS1pbnB1dD5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L25nLWNvbnRhaW5lcj5cbjxuZy1jb250YWluZXIgKm5nSWY9XCJzZWxlY3RlZFByb2dyZXNzU3RlcCA9PT0gJ3ZhbGlkYXRpb24nXCI+XG4gIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2wgY3FhLWZsZXgtMSBjcWEtbWF4LWgtWzUwMHB4XSBjcWEtb3ZlcmZsb3cteS1hdXRvXCI+XG4gICAgPCEtLSBWYWxpZGF0aW9uIFJ1bGVzIFRpdGxlIC0tPlxuICAgIDxoMyBjbGFzcz1cImNxYS10ZXh0LVsxMnB4XSBjcWEtZm9udC1zZW1pYm9sZCBjcWEtdGV4dC1ibGFjay0xMDAgY3FhLW1iLTRcIj5cbiAgICAgIFZhbGlkYXRpb24gUnVsZXNcbiAgICA8L2gzPlxuXG4gICAgPCEtLSBWYWxpZGF0aW9uIFJ1bGVzIFRhYmxlIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjcWEtYmctd2hpdGUgY3FhLWJvcmRlciBjcWEtYm9yZGVyLWdyYXktMjAwIGNxYS1yb3VuZGVkLWxnIGNxYS1vdmVyZmxvdy1oaWRkZW4gY3FhLW1iLTRcIj5cbiAgICAgIDwhLS0gVGFibGUgSGVhZGVyIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cImNxYS1ncmlkIGNxYS1ncmlkLWNvbHMtNiBjcWEtZ2FwLTIgY3FhLXAtMyBjcWEtYmctZ3JheS01MCBjcWEtYm9yZGVyLWIgY3FhLWJvcmRlci1ncmF5LTIwMCBjcWEtaXRlbXMtY2VudGVyXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyXCI+XG4gICAgICAgICAgPG1hdC1jaGVja2JveFxuICAgICAgICAgICAgW2NoZWNrZWRdPVwiYWxsVmFsaWRhdGlvblJ1bGVzU2VsZWN0ZWRcIlxuICAgICAgICAgICAgW2luZGV0ZXJtaW5hdGVdPVwic29tZVZhbGlkYXRpb25SdWxlc1NlbGVjdGVkXCJcbiAgICAgICAgICAgIChjaGFuZ2UpPVwib25TZWxlY3RBbGxWYWxpZGF0aW9uUnVsZXMoJGV2ZW50LmNoZWNrZWQpXCI+XG4gICAgICAgICAgPC9tYXQtY2hlY2tib3g+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LWdyYXktNzAwIGNxYS11cHBlcmNhc2VcIj5qc29uUGF0aDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LWdyYXktNzAwIGNxYS11cHBlcmNhc2VcIj52ZXJpZmljYXRpb25UeXBlPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtc2VtaWJvbGQgY3FhLXRleHQtZ3JheS03MDAgY3FhLXVwcGVyY2FzZVwiPmV4cGVjdGVkVHlwZTwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LWdyYXktNzAwIGNxYS11cHBlcmNhc2VcIj5leHBlY3RlZFZhbHVlPC9kaXY+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJjcWEtdGV4dC1bMTBweF0gY3FhLWZvbnQtc2VtaWJvbGQgY3FhLXRleHQtZ3JheS03MDAgY3FhLXVwcGVyY2FzZVwiPlJlc3VsdDwvZGl2PlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gVGFibGUgQm9keSAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtZmxleC1jb2xcIj5cbiAgICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgdmFsaWRhdGlvblJ1bGUgb2YgdmFsaWRhdGlvbkZvcm1BcnJheS5jb250cm9sczsgbGV0IGkgPSBpbmRleDsgdHJhY2tCeTogdHJhY2tCeVZhbGlkYXRpb25SdWxlSW5kZXhcIiBcbiAgICAgICAgICAgICBbZm9ybUdyb3VwXT1cImdldFZhbGlkYXRpb25Gb3JtR3JvdXAoaSlcIlxuICAgICAgICAgICAgIGNsYXNzPVwiY3FhLWdyaWQgY3FhLWdyaWQtY29scy02IGNxYS1nYXAtMiBjcWEtcC0zIGNxYS1ib3JkZXItYiBjcWEtYm9yZGVyLWdyYXktMjAwIGNxYS1pdGVtcy1jZW50ZXIgY3FhLWxhc3Q6Ym9yZGVyLWItMFwiPlxuICAgICAgICAgIDwhLS0gQ2hlY2tib3ggLS0+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXJcIj5cbiAgICAgICAgICAgIDxtYXQtY2hlY2tib3ggZm9ybUNvbnRyb2xOYW1lPVwiY2hlY2tlZFwiPlxuICAgICAgICAgICAgPC9tYXQtY2hlY2tib3g+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8IS0tIGpzb25QYXRoIC0tPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8Y3FhLWN1c3RvbS1pbnB1dFxuICAgICAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ2pzb25QYXRoJ1wiXG4gICAgICAgICAgICAgIFt2YWx1ZV09XCJnZXRWYWxpZGF0aW9uRm9ybUdyb3VwKGkpLmdldCgnanNvblBhdGgnKT8udmFsdWUgfHwgJydcIlxuICAgICAgICAgICAgICBbZnVsbFdpZHRoXT1cInRydWVcIlxuICAgICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwiZ2V0VmFsaWRhdGlvbkZvcm1Hcm91cChpKS5nZXQoJ2pzb25QYXRoJyk/LnNldFZhbHVlKCRldmVudClcIj5cbiAgICAgICAgICAgIDwvY3FhLWN1c3RvbS1pbnB1dD5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDwhLS0gdmVyaWZpY2F0aW9uVHlwZSAtLT5cbiAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgPGNxYS1keW5hbWljLXNlbGVjdFxuICAgICAgICAgICAgICBbZm9ybV09XCJnZXRWYWxpZGF0aW9uRm9ybUdyb3VwKGkpXCJcbiAgICAgICAgICAgICAgW2NvbmZpZ109XCJnZXRWZXJpZmljYXRpb25UeXBlQ29uZmlnKGkpXCI+XG4gICAgICAgICAgICA8L2NxYS1keW5hbWljLXNlbGVjdD5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDwhLS0gZXhwZWN0ZWRUeXBlIC0tPlxuICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICA8Y3FhLWR5bmFtaWMtc2VsZWN0XG4gICAgICAgICAgICAgIFtmb3JtXT1cImdldFZhbGlkYXRpb25Gb3JtR3JvdXAoaSlcIlxuICAgICAgICAgICAgICBbY29uZmlnXT1cImdldEV4cGVjdGVkVHlwZUNvbmZpZyhpKVwiPlxuICAgICAgICAgICAgPC9jcWEtZHluYW1pYy1zZWxlY3Q+XG4gICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICA8IS0tIGV4cGVjdGVkVmFsdWUgLS0+XG4gICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgIDxjcWEtY3VzdG9tLWlucHV0XG4gICAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCInZXhwZWN0ZWRWYWx1ZSdcIlxuICAgICAgICAgICAgICBbdmFsdWVdPVwiZ2V0VmFsaWRhdGlvbkZvcm1Hcm91cChpKS5nZXQoJ2V4cGVjdGVkVmFsdWUnKT8udmFsdWUgfHwgJydcIlxuICAgICAgICAgICAgICBbZnVsbFdpZHRoXT1cInRydWVcIlxuICAgICAgICAgICAgICAodmFsdWVDaGFuZ2UpPVwiZ2V0VmFsaWRhdGlvbkZvcm1Hcm91cChpKS5nZXQoJ2V4cGVjdGVkVmFsdWUnKT8uc2V0VmFsdWUoJGV2ZW50KVwiPlxuICAgICAgICAgICAgPC9jcWEtY3VzdG9tLWlucHV0PlxuICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgPCEtLSBSZXN1bHQgYW5kIERlbGV0ZSAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWl0ZW1zLWNlbnRlciBjcWEtZ2FwLTJcIj5cbiAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICAgIGNsYXNzPVwiY3FhLXB4LTMgY3FhLXB5LTEgY3FhLXJvdW5kZWQgY3FhLXRleHQtWzEwcHhdIGNxYS1mb250LW1lZGl1bVwiXG4gICAgICAgICAgICAgIFtuZ0NsYXNzXT1cImdldFJlc3VsdENsYXNzKGdldFZhbGlkYXRpb25Gb3JtR3JvdXAoaSkuZ2V0KCdyZXN1bHQnKT8udmFsdWUgfHwgJ05vdCBydW4nKVwiPlxuICAgICAgICAgICAgICB7eyBnZXRWYWxpZGF0aW9uRm9ybUdyb3VwKGkpLmdldCgncmVzdWx0Jyk/LnZhbHVlIHx8ICdOb3QgcnVuJyB9fVxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICBjbGFzcz1cImNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWp1c3RpZnktY2VudGVyIGNxYS13LTYgY3FhLWgtNiBjcWEtcm91bmRlZCBjcWEtdGV4dC1yZWQtNTAwIGhvdmVyOmNxYS10ZXh0LXJlZC03MDAgaG92ZXI6Y3FhLWJnLXJlZC01MCBjcWEtdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICAgICAgICAoY2xpY2spPVwicmVtb3ZlVmFsaWRhdGlvblJ1bGUoaSlcIlxuICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidEZWxldGUgdmFsaWRhdGlvbiBydWxlJ1wiPlxuICAgICAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjcWEtdGV4dC1iYXNlXCI+ZGVsZXRlPC9tYXQtaWNvbj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBBZGQgQW5vdGhlciBSdWxlIGFuZCBEZWxldGUgU2VsZWN0ZWQgLS0+XG4gICAgPGRpdiBjbGFzcz1cImNxYS1mbGV4IGNxYS1qdXN0aWZ5LWJldHdlZW4gY3FhLWl0ZW1zLWNlbnRlciBjcWEtbWItNFwiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICAqbmdJZj1cInNvbWVWYWxpZGF0aW9uUnVsZXNTZWxlY3RlZCB8fCBhbGxWYWxpZGF0aW9uUnVsZXNTZWxlY3RlZFwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImNxYS10ZXh0LXJlZC02MDAgY3FhLXRleHQtc20gY3FhLWZvbnQtbWVkaXVtIGNxYS1mbGV4IGNxYS1pdGVtcy1jZW50ZXIgY3FhLWdhcC0xIGhvdmVyOmNxYS10ZXh0LXJlZC03MDAgY3FhLXRyYW5zaXRpb24tY29sb3JzXCJcbiAgICAgICAgKGNsaWNrKT1cIm9uRGVsZXRlU2VsZWN0ZWRWYWxpZGF0aW9uUnVsZXMoKVwiPlxuICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjcWEtdGV4dC1iYXNlXCI+ZGVsZXRlPC9tYXQtaWNvbj5cbiAgICAgICAgPHNwYW4+RGVsZXRlIFNlbGVjdGVkPC9zcGFuPlxuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBjbGFzcz1cImNxYS10ZXh0LWJsdWUtNjAwIGNxYS10ZXh0LXNtIGNxYS1mb250LW1lZGl1bSBjcWEtZmxleCBjcWEtaXRlbXMtY2VudGVyIGNxYS1nYXAtMSBob3ZlcjpjcWEtdGV4dC1ibHVlLTcwMCBjcWEtdHJhbnNpdGlvbi1jb2xvcnNcIlxuICAgICAgICAoY2xpY2spPVwiYWRkVmFsaWRhdGlvblJ1bGUoKVwiPlxuICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJjcWEtdGV4dC1iYXNlXCI+YWRkPC9tYXQtaWNvbj5cbiAgICAgICAgPHNwYW4+QWRkIEFub3RoZXI8L3NwYW4+XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L25nLWNvbnRhaW5lcj5cblxuXG4gIDwhLS0gUmVzcG9uc2UgUHJldmlldyBTZWN0aW9uIC0tPlxuICA8ZGl2IGNsYXNzPVwiY3FhLWZsZXggY3FhLWZsZXgtY29sIGNxYS1ib3JkZXIgY3FhLWJvcmRlci1ncmF5LTIwMCBjcWEtcm91bmRlZC1sZyBjcWEtb3ZlcmZsb3ctaGlkZGVuIGNxYS1tYi02XCI+XG4gICAgPGRpdiBjbGFzcz1cImNxYS1wLTMgY3FhLWJnLWdyYXktNTAgY3FhLWJvcmRlci1iIGNxYS1ib3JkZXItZ3JheS0yMDBcIj5cbiAgICAgIDxoMyBjbGFzcz1cImNxYS10ZXh0LXNtIGNxYS1mb250LXNlbWlib2xkIGNxYS10ZXh0LWdyYXktOTAwXCI+UmVzcG9uc2UgUHJldmlldzwvaDM+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImNxYS1wLTQgY3FhLWJnLWdyYXktNTAgY3FhLW92ZXJmbG93LWF1dG9cIiBzdHlsZT1cIm1heC1oZWlnaHQ6IDMwMHB4O1wiPlxuICAgICAgPHByZSAqbmdJZj1cInJlc3BvbnNlUHJldmlld1wiIGNsYXNzPVwiY3FhLXRleHQteHMgY3FhLWZvbnQtbW9ubyBjcWEtdGV4dC1ncmF5LTgwMCBjcWEtd2hpdGVzcGFjZS1wcmUtd3JhcFwiPnt7IGZvcm1hdEpzb25SZXNwb25zZShyZXNwb25zZVByZXZpZXcpIH19PC9wcmU+XG4gICAgICA8cCAqbmdJZj1cIiFyZXNwb25zZVByZXZpZXdcIiBjbGFzcz1cImNxYS10ZXh0LXNtIGNxYS10ZXh0LWdyYXktNDAwIGNxYS10ZXh0LWNlbnRlciBjcWEtcHktOFwiPlxuICAgICAgICBObyByZXNwb25zZSB5ZXQuIFNlbmQgYSByZXF1ZXN0IHRvIHNlZSB0aGUgcmVzcG9uc2UgcHJldmlldy5cbiAgICAgIDwvcD5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG4gIDwhLS0gQWN0aW9uIEJ1dHRvbnMgLS0+XG4gIDxkaXYgY2xhc3M9XCJjcWEtZmxleCBjcWEtdy1mdWxsIGNxYS1nYXAtMiBjcWEtbXQtYXV0byBjcWEtcHQtNCBjcWEtYm9yZGVyLXQgY3FhLWJvcmRlci1ncmF5LTIwMFwiPlxuICAgIDwhLS0gQ2FuY2VsIGJ1dHRvbiAob25seSBvbiBmaXJzdCBzdGVwKSAtLT5cbiAgICA8Y3FhLWJ1dHRvblxuICAgICAgKm5nSWY9XCJzZWxlY3RlZFByb2dyZXNzU3RlcCA9PT0gJ3JlcXVlc3QtZGV0YWlscydcIlxuICAgICAgY2xhc3M9XCJjcWEtdy0xLzJcIlxuICAgICAgdmFyaWFudD1cIm91dGxpbmVkXCJcbiAgICAgIHRleHQ9XCJDYW5jZWxcIlxuICAgICAgW2N1c3RvbUNsYXNzXT1cIidjcWEtZmxleC0xIGNxYS13LWZ1bGwnXCJcbiAgICAgIChjbGlja2VkKT1cIm9uQ2FuY2VsKClcIj5cbiAgICA8L2NxYS1idXR0b24+XG4gICAgPCEtLSBCYWNrIGJ1dHRvbiAob24gYWxsIHN0ZXBzIGV4Y2VwdCBmaXJzdCkgLS0+XG4gICAgPGNxYS1idXR0b25cbiAgICAgICpuZ0lmPVwic2VsZWN0ZWRQcm9ncmVzc1N0ZXAgIT09ICdyZXF1ZXN0LWRldGFpbHMnXCJcbiAgICAgIGNsYXNzPVwiY3FhLXctMS8yXCJcbiAgICAgIHZhcmlhbnQ9XCJvdXRsaW5lZFwiXG4gICAgICB0ZXh0PVwiQmFja1wiXG4gICAgICBbY3VzdG9tQ2xhc3NdPVwiJ2NxYS1mbGV4LTEgY3FhLXctZnVsbCdcIlxuICAgICAgKGNsaWNrZWQpPVwib25CYWNrKClcIj5cbiAgICA8L2NxYS1idXR0b24+XG4gICAgPCEtLSBOZXh0L0NyZWF0ZSBTdGVwIGJ1dHRvbiAtLT5cbiAgICA8Y3FhLWJ1dHRvblxuICAgICAgY2xhc3M9XCJjcWEtdy0xLzJcIlxuICAgICAgdmFyaWFudD1cImZpbGxlZFwiXG4gICAgICBbdGV4dF09XCJpc0xhc3RTdGVwKCkgPyAnQ3JlYXRlIFN0ZXAnIDogJ05leHQnXCJcbiAgICAgIFtjdXN0b21DbGFzc109XCInY3FhLWZsZXgtMSBjcWEtdy1mdWxsJ1wiXG4gICAgICAoY2xpY2tlZCk9XCJpc0xhc3RTdGVwKCkgPyBvbkNyZWF0ZVN0ZXAoKSA6IG9uTmV4dCgpXCI+XG4gICAgPC9jcWEtYnV0dG9uPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG4iXX0=
|