@eqproject/eqp-dynamic-module 2.8.23 → 2.8.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,653 @@
1
+ import { Component, Input, ViewChild, Output, EventEmitter, } from "@angular/core";
2
+ import { TypeColumn, } from "@eqproject/eqp-table";
3
+ import { FieldTypeEnum } from "../../../../models/baseField.model";
4
+ import { Record } from "../../../../models/record.model";
5
+ import { DateTimeTypeEnum, } from "../../../../models/fields/dateField.model";
6
+ import { UtilityHelperService } from "../../../../services/utilityHelper.services";
7
+ import { DynamicModuleListFormRecordActionsDefault } from "../../../../models/dynamicModuleListFormRecordActionsDefault";
8
+ import { ParamTypeEnum, } from "../../../../models/endPointConfiguration.model";
9
+ import { GlobalService } from "../../../../services/global.service";
10
+ import { ModeEnum } from "tmw-picker";
11
+ import * as i0 from "@angular/core";
12
+ import * as i1 from "../../../../services/utilityHelper.services";
13
+ import * as i2 from "@angular/common";
14
+ import * as i3 from "@angular/material/form-field";
15
+ import * as i4 from "@angular/material/core";
16
+ import * as i5 from "@angular/material/select";
17
+ import * as i6 from "@angular/material/card";
18
+ import * as i7 from "@angular/material/table";
19
+ import * as i8 from "tmw-picker";
20
+ export class HListFormRecordComponent {
21
+ //#region Constructor
22
+ constructor(utilityHelperService, changeDetector, datepipe) {
23
+ this.utilityHelperService = utilityHelperService;
24
+ this.changeDetector = changeDetector;
25
+ this.datepipe = datepipe;
26
+ this.form = null; // boh ma c'era prima
27
+ this.externalButtons = new Array();
28
+ this.defaultListActions = new DynamicModuleListFormRecordActionsDefault();
29
+ this.showTitle = true;
30
+ this.columns = new Array();
31
+ this.loadedFilters = false;
32
+ this.loadedTable = false;
33
+ this.onViewRecord = new EventEmitter();
34
+ this.onAddViewEditRecord = new EventEmitter();
35
+ this.onDeleteRecord = new EventEmitter();
36
+ this.onAfterDeleteRecord = new EventEmitter();
37
+ this.modes = ModeEnum;
38
+ this.minDate = new Date();
39
+ this.maxDate = new Date();
40
+ // le proprietà della risposta da stampare nelle righe
41
+ this.properties = [];
42
+ // le label associate alle proprietà da stampare che condividono lo stesso indice
43
+ this.propertiesLabel = [];
44
+ // Colonne da visualizzare (fissa la prima colonna e genera dinamicamente le altre)
45
+ this.displayedColumns = [];
46
+ // this.propertiesLabel["AnswerDate"] = "Data";
47
+ }
48
+ //#endregion Constructor
49
+ //#region ngOnIntit
50
+ ngOnInit() {
51
+ this.defaultListActions = this.configurations.defaultListActions;
52
+ this.showTitle = this.configurations.showTitle;
53
+ GlobalService.debugLog('list-form-record - ngOnInit - configurations', this.configurations);
54
+ this.getFormByID();
55
+ }
56
+ //#endregion ngOnIntit
57
+ //#region ngOnChanges
58
+ ngOnChanges(changes) {
59
+ GlobalService.debugLog('list-form-record - changes', changes);
60
+ // Se viene modificato il valore di "ngModelInput" allora aggiorna l'input
61
+ // if (changes['configurations'] != undefined && changes['configurations'].firstChange == false) {
62
+ // this.configurations.values = changes['configurations'].currentValue;
63
+ // this.reloadTables();
64
+ // }
65
+ }
66
+ //#endregion ngOnChanges
67
+ //#region getFormByID
68
+ async getFormByID(id = this.formID) {
69
+ GlobalService.debugLog('list-form-record - getFormByID', this.form);
70
+ if (this.form == null) {
71
+ const dynamicModuleParams = new Array();
72
+ dynamicModuleParams.push({
73
+ ParamName: "id",
74
+ ParamValue: id,
75
+ ParamType: ParamTypeEnum["Query param"],
76
+ });
77
+ await this.utilityHelperService.RunEndPointCall(this.endPointConfiguration.Forms.GetByIDEndPoint, dynamicModuleParams, (res) => {
78
+ this.form = res;
79
+ this.configureColumns();
80
+ }, (err) => { });
81
+ }
82
+ else {
83
+ this.configureColumns();
84
+ }
85
+ }
86
+ //#endregion getFormByID
87
+ //#region getRecordsByFormID
88
+ /**
89
+ * Metodo per recuperare tutti i record salvati per una particolare Form.
90
+ * La chiamata viene effettuata solo se è stato configurato l'endPoint da usare.
91
+ * La risposta della chiamata deve essere un array di oggetti di tipo "DynRecord"
92
+ * a partire dai quali vengono ricreati i Record usati nel client.
93
+ */
94
+ async getRecordsByFormID() {
95
+ /**
96
+ * prende le risposte e le rende piatte, adatte a diventare una riga da tabella
97
+ * mette tutte le risposte nelle strutture necessarie per il recupero e la visualizzazione
98
+ * @param answers
99
+ */
100
+ const rearrangeAnswersAndPopulateLists = (answers) => {
101
+ this.configurations.values = new Array();
102
+ answers.forEach((answer) => {
103
+ var tmpRec = new Record();
104
+ tmpRec = JSON.parse(answer.SerializedValues);
105
+ tmpRec.ID = answer.ID;
106
+ tmpRec.EntID = answer.EntID;
107
+ tmpRec.Version = answer.Version;
108
+ tmpRec.userID = answer.userID;
109
+ tmpRec.AnswerDate = answer.AnswerDate;
110
+ this.configurations.values.push(tmpRec);
111
+ });
112
+ };
113
+ /**
114
+ * prepara la lista delle colonne da mostrare (una per ogni risposta, più la colonna delle proprietà)
115
+ * imposta la lista delle risposte da visualizzare
116
+ * libera le variabili di caricamento per mostrare i contenuti della vista
117
+ */
118
+ const nameColumnsAndStartView = () => {
119
+ //destruttura l'array risposte e per ogni risposta genera un elemento col[i]
120
+ this.displayedColumns = ["property", ...this.configurations.values.map((_, i) => `col${i}`)];
121
+ this.filteredAnswers = this.configurations.values;
122
+ this.setMinMaxDates();
123
+ this.loadedFilters = true;
124
+ this.loadedTable = true;
125
+ setTimeout((_) => {
126
+ this.changeDetector.detectChanges();
127
+ }, 0); // refresh ui
128
+ };
129
+ if (this.configurations.values) {
130
+ // vengo da un'altra visualizzazione che ha già recuperato le risposte
131
+ console.log("hList - getRecordsByFormID A", this.configurations);
132
+ nameColumnsAndStartView();
133
+ }
134
+ else {
135
+ // sono in una nuova istanza in cui devo recuperare le risposte
136
+ console.log("hList - getRecordsByFormID B", this.configurations);
137
+ try {
138
+ if (this.endPointConfiguration &&
139
+ this.endPointConfiguration.Records &&
140
+ this.endPointConfiguration.Records.GetByFormIDEndPoint) {
141
+ let dynamicModuleParams = [
142
+ {
143
+ ParamName: "EntID",
144
+ ParamValue: this.form.ID,
145
+ ParamType: ParamTypeEnum["Query param"],
146
+ },
147
+ ];
148
+ if (this.configurations.userID == null) {
149
+ // non ho specificato un utente
150
+ // vedo tutte le risposte del modulo
151
+ await this.utilityHelperService.RunEndPointCall(this.endPointConfiguration.Records.GetByFormIDEndPoint, dynamicModuleParams, (res) => {
152
+ rearrangeAnswersAndPopulateLists(res);
153
+ nameColumnsAndStartView();
154
+ });
155
+ }
156
+ else {
157
+ // conosco l'utente
158
+ // voglio solamente le sue risposte
159
+ dynamicModuleParams.push({
160
+ ParamName: "UserID",
161
+ ParamValue: this.configurations.userID,
162
+ ParamType: ParamTypeEnum["Query param"],
163
+ });
164
+ await this.utilityHelperService.RunEndPointCall(this.endPointConfiguration.Records.GetAllByEntAndUserIDEndPoint, dynamicModuleParams, (res) => {
165
+ rearrangeAnswersAndPopulateLists(res);
166
+ nameColumnsAndStartView();
167
+ });
168
+ }
169
+ }
170
+ }
171
+ catch (e) {
172
+ console.error('exception', e);
173
+ }
174
+ }
175
+ }
176
+ //#endregion getRecordsByFormID
177
+ //#region configureColumns
178
+ /**
179
+ * Metodo per configurare le colonne della eqp-table.
180
+ */
181
+ configureColumns() {
182
+ this.columns = [
183
+ {
184
+ key: "action",
185
+ display: "",
186
+ type: TypeColumn.MenuAction,
187
+ buttonMenuIcon: "more_vert",
188
+ styles: { flex: "0 0 6%" },
189
+ actions: [],
190
+ },
191
+ ];
192
+ if (this.defaultListActions.view == true) {
193
+ this.columns
194
+ .find((c) => c.key === "action")
195
+ .actions.push({
196
+ name: "Visualizza",
197
+ icon: "info",
198
+ fn: (element, index, col) => this.viewRecord(element),
199
+ });
200
+ }
201
+ if (this.defaultListActions.edit == true) {
202
+ this.columns
203
+ .find((c) => c.key === "action")
204
+ .actions.push({
205
+ name: "Modifica",
206
+ icon: "edit",
207
+ fn: (element, index, col) => this.viewOrEditRecord(element, false),
208
+ });
209
+ }
210
+ if (this.defaultListActions.duplicate == true) {
211
+ /*this.columns
212
+ .find((c) => c.key === "action")
213
+ .actions.push({
214
+ name: "Duplica",
215
+ icon: "file_copy",
216
+ fn: (element, index, col) => this.duplicateRecord(element),
217
+ });*/
218
+ }
219
+ if (this.defaultListActions.delete == true) {
220
+ this.columns
221
+ .find((c) => c.key === "action")
222
+ .actions.push({
223
+ name: "Elimina",
224
+ icon: "delete",
225
+ fn: (element, index, col) => this.deleteRecord(element),
226
+ });
227
+ }
228
+ this.externalButtons.forEach((button) => {
229
+ this.columns
230
+ .find((c) => c.key === "action")
231
+ .actions.push({
232
+ name: button.text,
233
+ icon: button.icon,
234
+ fn: (element, index, col) => button.fn(),
235
+ });
236
+ });
237
+ this.createAdditionalActions();
238
+ this.createColumnsFromFormFields();
239
+ this.getRecordsByFormID();
240
+ }
241
+ //#endregion configureColumns
242
+ //#region createAdditionalActions
243
+ /**
244
+ * Metodo per aggiungere nella colonna "action" della eqp-table le azioni sui record
245
+ * definite dall'utente all'interno della Form.
246
+ */
247
+ createAdditionalActions() {
248
+ GlobalService.debugLog('list-form-record - createAdditionalActions', this.form);
249
+ if (this.form.ActionsOnRecord && this.form.ActionsOnRecord.length > 0) {
250
+ this.form.ActionsOnRecord.sort((a, b) => a.OrdinalPosition > b.OrdinalPosition
251
+ ? 1
252
+ : b.OrdinalPosition > a.OrdinalPosition
253
+ ? -1
254
+ : 0).forEach((action) => {
255
+ this.columns
256
+ .find((c) => c.key === "action")
257
+ .actions.push({
258
+ name: action.Name,
259
+ icon: action.Icon,
260
+ fn: (element, index, col) => {
261
+ const rec = element;
262
+ const ctx = UtilityHelperService.context;
263
+ eval(action.Action);
264
+ // TODO: salvare le modifiche
265
+ },
266
+ });
267
+ });
268
+ }
269
+ }
270
+ //#endregion createAdditionalActions
271
+ //#region createColumnsFromFormFields
272
+ /**
273
+ * Metodo per creare la configurazione delle colonne per la eqp-table.
274
+ * Individua i BaseField da mostrare e li usa per creare le ConfigColumn.
275
+ * Le colonne vengono create per i BaseField con il flag InListView a TRUE
276
+ * oppure, nel caso non siano stati specificati i campi da visualizzare,
277
+ * seleziona i primi 6.
278
+ */
279
+ createColumnsFromFormFields() {
280
+ GlobalService.debugLog('list-form-record - createColumnsFromFormFields', this.form);
281
+ var fieldsForColumns;
282
+ fieldsForColumns = this.form.Fields.filter((f) => {
283
+ if (f.AnswerStyle) {
284
+ return f.AnswerStyle.InListView;
285
+ }
286
+ else {
287
+ return f.InListView;
288
+ }
289
+ });
290
+ fieldsForColumns
291
+ .sort((a, b) => a.OrdinalPosition > b.OrdinalPosition
292
+ ? 1
293
+ : b.OrdinalPosition > a.OrdinalPosition
294
+ ? -1
295
+ : 0)
296
+ .forEach((field) => {
297
+ // this.columns.push(this.createFieldColumn(field));
298
+ this.properties.push({ label: field.Label, type: field.FieldType, config: field });
299
+ this.propertiesLabel[field.Label] = field.Description;
300
+ });
301
+ this.selectedProperties = this.properties;
302
+ }
303
+ //#endregion createColumnsFromFormFields
304
+ //#region createFieldColumn
305
+ /**
306
+ * Metodo per creare l'oggetto ConfigureColumn che rappresenta il BaseField passato in input.
307
+ * @param field BaseField per cui creare la colonna nella eqp-table
308
+ * @returns Restituisce una ConfigColumn per la eqp-table
309
+ */
310
+ // private createFieldColumn(field: BaseField): ConfigColumn {
311
+ // var column: ConfigColumn = { key: field.Name, display: field.Label };
312
+ // switch (field.FieldType) {
313
+ // case FieldTypeEnum["Booleano"]:
314
+ // column.type = TypeColumn.Boolean;
315
+ // column.booleanValues = {
316
+ // false: '<i class="fa fa-times error-color"></i>',
317
+ // true: '<i class="fa fa-check success-color"></i>',
318
+ // };
319
+ // column.styles = {
320
+ // flex: "0 0 7%",
321
+ // cellAlignment: CellAlignmentEnum.CENTER,
322
+ // };
323
+ // break;
324
+ // case FieldTypeEnum["Data e/o ora"]:
325
+ // if (
326
+ // (field as DateField).IsOnlyDate != DateTimeTypeEnum["Solo orario"]
327
+ // ) {
328
+ // column.type = TypeColumn.Date;
329
+ // if (
330
+ // (field as DateField).IsOnlyDate == DateTimeTypeEnum["Data e ora"]
331
+ // ) {
332
+ // column.format = "dd/MM/yyyy HH:mm";
333
+ // } else if (
334
+ // (field as DateField).IsOnlyDate == DateTimeTypeEnum["Solo data"]
335
+ // ) {
336
+ // column.format = (field as DateField).DateFormat
337
+ // ? (field as DateField).DateFormat.replace("DD", "dd")
338
+ // : "dd/MM/yyyy";
339
+ // }
340
+ // }
341
+ // break;
342
+ // case FieldTypeEnum["Campo numerico"]:
343
+ // if ((field as NumericField).CurrencySymbol) {
344
+ // column.numberPipe = NumberColumnPipe.CURRENCY;
345
+ // column.currencyPipeCode = (field as NumericField).CurrencySymbol;
346
+ // } else if (!(field as NumericField).IsInteger) {
347
+ // column.numberPipe = NumberColumnPipe.DECIMAL;
348
+ // }
349
+ // break;
350
+ // case FieldTypeEnum["Allegato"]:
351
+ // case FieldTypeEnum["Immagine"]:
352
+ // /*
353
+ // column.value = (element: Record) => {
354
+ // if (
355
+ // (field as AttachmentField).IsMultiAttach ||
356
+ // ((field as ImageField).AttachDefinition &&
357
+ // (field as ImageField).AttachDefinition.IsMultiAttach)
358
+ // ) {
359
+ // return element[field.Name] != null && element[field.Name].length > 0
360
+ // ? (element[field.Name] as Array<IAttachmentDTO>)
361
+ // .map((a) => a.FileName)
362
+ // .join(", ")
363
+ // : null;
364
+ // } else {
365
+ // return element[field.Name] != null && element[field.Name].length > 0
366
+ // ? (element[field.Name] as Array<IAttachmentDTO>)[0].FileName
367
+ // : null;
368
+ // }
369
+ // };
370
+ // column.isSortable = false;
371
+ // column.isSearchable = false;
372
+ // */
373
+ // break;
374
+ // case FieldTypeEnum["Elenco generico"]:
375
+ // column.value = (element: Record) => {
376
+ // if ((field as ListValueField).IsMultiChoiche) {
377
+ // if (!element[field.Name] || element[field.Name].length == 0) {
378
+ // return null;
379
+ // } else {
380
+ // return Object.keys((field as ListValueField).ValuePairs)
381
+ // .filter((k) =>
382
+ // element[field.Name].includes(
383
+ // (field as ListValueField).ValuePairs[k]
384
+ // )
385
+ // )
386
+ // .join(", ");
387
+ // }
388
+ // } else {
389
+ // return Object.keys((field as ListValueField).ValuePairs).find(
390
+ // (k) =>
391
+ // (field as ListValueField).ValuePairs[k] == element[field.Name]
392
+ // );
393
+ // }
394
+ // };
395
+ // column.isSortable = false;
396
+ // column.isSearchable = false;
397
+ // break;
398
+ // case FieldTypeEnum["Lookup"]:
399
+ // // TODO
400
+ // break;
401
+ // }
402
+ // return column;
403
+ // }
404
+ //#endregion createFieldColumn
405
+ //#region viewRecord
406
+ viewRecord(record) {
407
+ this.onViewRecord.emit(record);
408
+ }
409
+ //#endregion viewRecord
410
+ /**
411
+ * Metodo che scatena l'evento di Output per mostrare o modificare il record
412
+ * selezionato sulla eqp-table.
413
+ * @param record Record da visualizzare o modificare selezionato sulla eqp-table.
414
+ * @param onlyView Se TRUE viene mostrato il componente add-form-record in sola lettura.
415
+ */
416
+ viewOrEditRecord(record, onlyView) {
417
+ this.onAddViewEditRecord.emit({ record, onlyView });
418
+ }
419
+ /**
420
+ * Metodo per eliminare un record dalla lista.
421
+ * @param record Record da eliminare selezionato sulla eqp-table.
422
+ */
423
+ deleteRecord(record) {
424
+ this.onDeleteRecord.emit(record);
425
+ }
426
+ /**
427
+ * Metodo per ricaricare i dati della eqp-table.
428
+ */
429
+ reloadTables() {
430
+ if (this.tableRecords) {
431
+ this.tableRecords.reloadDatatable();
432
+ }
433
+ }
434
+ //#region onSelectionChange
435
+ /**
436
+ * Funzione che viene chiamata al cambio di selezione dei parametri da mostrare
437
+ * aggiorna la lista delle proprietà selezionate che gestisce le righe mostrate per ogni risposta
438
+ * @param selectedProperties
439
+ */
440
+ onSelectionChange(selectedProperties) {
441
+ console.log(selectedProperties.value);
442
+ if (selectedProperties.value.length > 0) {
443
+ this.selectedProperties = selectedProperties.value;
444
+ }
445
+ else {
446
+ this.selectedProperties = this.properties;
447
+ }
448
+ console.log(this.selectedProperties);
449
+ }
450
+ //#endregion onSelectionChange
451
+ //#region filterDataAnswers
452
+ /**
453
+ * funzione che filtra le risposte in base al range di date basandosi sul campo fisso AnswerDate per il paragone
454
+ */
455
+ filterDataAnswers() {
456
+ setTimeout(() => {
457
+ this.filteredAnswers = [];
458
+ this.maxDate.setHours(23, 59, 59, 59);
459
+ this.configurations.values.forEach((value) => {
460
+ if (new Date(value.AnswerDate) >= this.minDate && new Date(value.AnswerDate) <= this.maxDate) {
461
+ this.filteredAnswers.push(value);
462
+ }
463
+ });
464
+ this.displayedColumns = ["property", ...this.filteredAnswers.map((_, i) => `col${i}`)];
465
+ // this.loadedTable = true;
466
+ }, 100);
467
+ }
468
+ //#endregion filterDataAnswers
469
+ //#region setMinMaxDates
470
+ // Funzione per ottenere la data più recente e quella più vecchia
471
+ setMinMaxDates() {
472
+ // Converto le date di AnswerDate in oggetti Date e ordino
473
+ const dates = this.configurations.values.map(value => new Date(value.AnswerDate));
474
+ // Trovo la data più recente (max) e la più vecchia (min)
475
+ this.minDate = new Date(Math.min(...dates.map(date => date.getTime())));
476
+ this.maxDate = new Date(Math.max(...dates.map(date => date.getTime())));
477
+ }
478
+ //#endregion setMinMaxDates
479
+ //#region printValue
480
+ printValue(fieldType, value, fieldconfig) {
481
+ // return value;
482
+ // PREPARO IL VALUEPAIRS
483
+ switch (fieldType) {
484
+ case FieldTypeEnum["Elenco generico"]:
485
+ {
486
+ return value;
487
+ break;
488
+ }
489
+ ;
490
+ case FieldTypeEnum["Campo numerico"]:
491
+ {
492
+ if (fieldconfig.IsInteger) {
493
+ if (fieldconfig.DecimalSeparator == null) {
494
+ return Math.floor(value);
495
+ }
496
+ else {
497
+ const decimals = fieldconfig.DecimalPrecision * 10;
498
+ return Math.round(value * decimals) / decimals;
499
+ }
500
+ }
501
+ else {
502
+ const decimals = fieldconfig.DecimalPrecision * 10;
503
+ return Math.round(value * decimals) / decimals;
504
+ }
505
+ break;
506
+ }
507
+ ;
508
+ case FieldTypeEnum['Immagine']:
509
+ {
510
+ return "immagine";
511
+ GlobalService.debugLog("immagine " + fieldconfig.Name + " : " + value);
512
+ // // Recupero il BASE64 dell'immagine Resized via promise client
513
+ // var resizedBase64 = await this.resizeBase64Image("data:image/" + value.FileExtension + ";base64," + value.FileDataBase64);
514
+ // // Aggiungo l'HTML con il nuovo BASE64
515
+ // return "<img src='" + resizedBase64 + "' style='height: " + value.ResizedImageHeightPx + "px'>";
516
+ break;
517
+ }
518
+ ;
519
+ case FieldTypeEnum['Allegato']:
520
+ {
521
+ return "Allegato";
522
+ // GlobalService.debugLog("Allegato " + field.Name + " : " + value, record)
523
+ if (value != null) {
524
+ let resizedBase64;
525
+ // if (value[0].IsImage) {
526
+ // // Recupero il BASE64 dell'immagine Resized via promise client
527
+ // resizedBase64 = await this.resizeBase64Image("data:image/" + value[0].FileExtension + ";base64," + value[0].FileDataBase64);
528
+ // // GlobalService.debugLog("Allegato resizedBase64", resizedBase64)
529
+ // // Aggiungo l'HTML con il nuovo BASE64
530
+ // return '<img class="image-preview" src="' + resizedBase64 + '" style="height: ' + value[0].ResizedImageHeightPx + 'px">';
531
+ // } else if (value[0].FileContentType == "application/pdf") {
532
+ // return '<iframe src="data:application/pdf;base64,' + value[0].FileDataBase64 + '"style="min-height: 300px; height: 100%;"></iframe>';
533
+ // } else {
534
+ // return '<iframe src="data:"' + value[0].FileExtension + '";base64,' + value[0].FileDataBase64 + '"style="min-height: 300px; height: 100%;"></iframe>';
535
+ // }
536
+ // Aggiungo l'HTML con il nuovo BASE64
537
+ // return "<img src='" + resizedBase64 + "' style='height: " + value[0].ResizedImageHeightPx + "px'>";
538
+ // GlobalService.debugLog("Allegato outputValuesArray", outputValuesArray[field.Name])
539
+ }
540
+ break;
541
+ }
542
+ ;
543
+ case FieldTypeEnum['Immagine con markers']:
544
+ {
545
+ return "Immagine con markers";
546
+ // Recupero il BASE64 dell'immagine Resized via promise client
547
+ // var resizedBase64 = await this.resizeBase64Image("data:image/" + value.FileExtension + ";base64," + value.FileDataBase64);
548
+ // Aggiungo l'HTML con il nuovo BASE64
549
+ // return "<img src='" + resizedBase64 + "' style='height: " + value.ResizedImageHeightPx + "px'>";
550
+ break;
551
+ }
552
+ ;
553
+ case FieldTypeEnum['Elenco immagini']:
554
+ {
555
+ return "Elenco immagini";
556
+ let outputValuesArray = "";
557
+ if (value != null && fieldconfig.IsMultiChoiche) {
558
+ value.forEach((imageobj) => {
559
+ var attachmentInForm = fieldconfig.AttachmentList.find(x => x.ID == imageobj);
560
+ if (attachmentInForm != null) {
561
+ outputValuesArray += attachmentInForm.ButtonKey + ", ";
562
+ }
563
+ });
564
+ var parts = outputValuesArray.split(", ");
565
+ return parts.slice(0, parts.length - 1).join(", ");
566
+ }
567
+ else {
568
+ var attachmentInForm = fieldconfig.AttachmentList.find(x => x.ID == value);
569
+ if (attachmentInForm != null) {
570
+ return attachmentInForm.ButtonKey;
571
+ }
572
+ }
573
+ break;
574
+ }
575
+ ;
576
+ case FieldTypeEnum['Data e/o ora']: {
577
+ GlobalService.debugLog("Data e/o ora", fieldconfig);
578
+ if (fieldconfig.DateFormat != null) {
579
+ let fixDateFormat = fieldconfig.DateFormat.replace("DD", "dd");
580
+ return this.datepipe.transform(value, fixDateFormat);
581
+ }
582
+ else {
583
+ if (fieldconfig.IsOnlyDate == DateTimeTypeEnum['Solo data']) {
584
+ return this.datepipe.transform(value, "dd/MM/yyyy");
585
+ }
586
+ else if (fieldconfig.IsOnlyDate == DateTimeTypeEnum['Data e ora']) {
587
+ return this.datepipe.transform(value, "dd/MM/yyyy HH:mm");
588
+ }
589
+ else if (fieldconfig.IsOnlyDate == DateTimeTypeEnum['Solo orario']) {
590
+ return this.datepipe.transform(value, "HH:mm");
591
+ }
592
+ }
593
+ break;
594
+ }
595
+ default: {
596
+ return value;
597
+ }
598
+ }
599
+ }
600
+ //#endregion printValue
601
+ //#region resizeBase64Image
602
+ async resizeBase64Image(base64Image) {
603
+ return new Promise((resolve, reject) => {
604
+ const imagetype = /data:image\/([\w]+);/;
605
+ const match = base64Image.match(imagetype);
606
+ const img = new Image();
607
+ img.src = base64Image;
608
+ img.onload = function () {
609
+ const canvas = document.createElement("canvas");
610
+ const ctx = canvas.getContext('2d');
611
+ const width = img.width;
612
+ const height = img.height;
613
+ const aspectRatio = width / height;
614
+ const newHeight = 128;
615
+ const newWidth = newHeight * aspectRatio;
616
+ canvas.width = newWidth;
617
+ canvas.height = newHeight;
618
+ ctx.drawImage(img, 0, 0, newWidth, newHeight);
619
+ let quality = 0.8;
620
+ let dataURL = canvas.toDataURL('image/' + match[1], quality);
621
+ resolve(dataURL);
622
+ };
623
+ });
624
+ }
625
+ }
626
+ HListFormRecordComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: HListFormRecordComponent, deps: [{ token: i1.UtilityHelperService }, { token: i0.ChangeDetectorRef }, { token: i2.DatePipe }], target: i0.ɵɵFactoryTarget.Component });
627
+ HListFormRecordComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: HListFormRecordComponent, selector: "hlist-form-record", inputs: { configurations: "configurations", endPointConfiguration: "endPointConfiguration", formID: "formID", form: "form", externalButtons: "externalButtons" }, outputs: { onViewRecord: "onViewRecord", onAddViewEditRecord: "onAddViewEditRecord", onDeleteRecord: "onDeleteRecord", onAfterDeleteRecord: "onAfterDeleteRecord" }, viewQueries: [{ propertyName: "tableRecords", first: true, predicate: ["tableRecords"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<mat-card class=\"list-form-record\">\r\n <mat-card-header class=\"align-items-center justify-content-between\">\r\n <mat-card-title *ngIf=\"loadedFilters && showTitle\"\r\n >Elenco {{ form.Name }}</mat-card-title\r\n >\r\n <!-- <mat-card-actions>\r\n <button\r\n class=\"btn btn-primary\"\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n (click)=\"onAddViewEditRecord.emit(null)\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n <span style=\"margin-left: 10px\">Aggiungi</span>\r\n </button>\r\n </mat-card-actions> -->\r\n </mat-card-header>\r\n <mat-card-content>\r\n <!--#region FILTERS -->\r\n <div class=\"row\" *ngIf=\"loadedFilters\">\r\n <div class=\"col-sm-12 col-md-3\">\r\n <tmw-datetimepicker\r\n class=\"date\"\r\n [placeholder]=\"'Periodo inizio'\"\r\n [label]=\"'Periodo inizio'\"\r\n [(ngModelInput)]=\"minDate\"\r\n (ngModelInputChange)=\"filterDataAnswers()\"\r\n [pickerMode]=\"modes.DATEPICKER\"\r\n [outputFormat]=\"'DD/MM/YYYY'\"\r\n [showSeconds]=\"false\"\r\n >\r\n </tmw-datetimepicker>\r\n </div>\r\n <div class=\"col-sm-12 col-md-3\">\r\n <tmw-datetimepicker\r\n class=\"date\"\r\n [placeholder]=\"'Periodo fine'\"\r\n [label]=\"'Periodo fine'\"\r\n [(ngModelInput)]=\"maxDate\"\r\n (ngModelInputChange)=\"filterDataAnswers()\"\r\n [pickerMode]=\"modes.DATEPICKER\"\r\n [outputFormat]=\"'DD/MM/YYYY'\"\r\n [showSeconds]=\"false\"\r\n >\r\n </tmw-datetimepicker>\r\n </div>\r\n <div class=\"col-sm-12 col-md-3 mt-2\">\r\n <mat-form-field>\r\n <mat-label>Selezione dei campi</mat-label>\r\n <mat-select (selectionChange)=\"onSelectionChange($event)\" multiple>\r\n <mat-option *ngFor=\"let property of properties\" [value]=\"property\">\r\n {{ propertiesLabel[property.label] }}\r\n </mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n <!-- <div class=\"col-sm-12 col-md-3 mt-2\">\r\n <button\r\n [disabled]=\"\r\n selectedProperties == null || selectedProperties.length == 0\r\n \"\r\n class=\"btn btn-graph-generate button-next me-2\"\r\n mat-raised-button\r\n color=\"primary\"\r\n (click)=\"filterDataAnswers()\"\r\n >\r\n Genera\r\n </button>\r\n </div> -->\r\n </div>\r\n <!--#endregion FILTERS -->\r\n\r\n <!--#region TABLE -->\r\n <div class=\"table-container\">\r\n <table\r\n mat-table\r\n [dataSource]=\"selectedProperties\"\r\n class=\"mat-elevation-z8 mat-table-fixed\"\r\n >\r\n <!-- Colonna fissa per le propriet\u00E0 -->\r\n <ng-container matColumnDef=\"property\" sticky>\r\n <th mat-header-cell *matHeaderCellDef class=\"sticky-column\">\r\n Data Inserimento\r\n </th>\r\n <td\r\n mat-cell\r\n *matCellDef=\"let selectedProperties\"\r\n class=\"sticky-column\"\r\n >\r\n {{ propertiesLabel[selectedProperties.label] }}\r\n </td>\r\n </ng-container>\r\n\r\n <!-- Genera dinamicamente le colonne per ogni risposta -->\r\n <ng-container\r\n *ngFor=\"let value of filteredAnswers; let i = index\"\r\n [matColumnDef]=\"'col' + i\"\r\n >\r\n <th mat-header-cell *matHeaderCellDef>\r\n {{ value.AnswerDate | date : \"dd/MM/yyyy HH:mm\" }}\r\n </th>\r\n <!-- <th mat-header-cell *matHeaderCellDef> {{ value.AnswerDate | date:'dd/MM/yyyy HH:mm' }} </th> -->\r\n <td mat-cell *matCellDef=\"let selectedProperties\">\r\n {{\r\n selectedProperties.label === \"AnswerDate\"\r\n ? (value.AnswerDate | date : \"dd/MM/yyyy HH:mm\")\r\n : printValue(selectedProperties.type, value[selectedProperties.label], selectedProperties.config) ?? \"N/A\"\r\n }}\r\n <!-- - \r\n {{selectedProperties.type}}\r\n {{selectedProperties.label}} -->\r\n </td>\r\n </ng-container>\r\n\r\n <!-- Header della tabella -->\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n\r\n <!-- Righe della tabella -->\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\"></tr>\r\n </table>\r\n </div>\r\n <!--#region TABLE -->\r\n </mat-card-content>\r\n <mat-card-footer>\r\n <!-- <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar> -->\r\n </mat-card-footer>\r\n</mat-card>\r\n\r\n<!-- <div class=\"row eqp-dynamic-module-title list-form-record-header\">\r\n <div class=\"col-md-6\">\r\n <h4 *ngIf=\"showTitle\">\r\n <b>Elenco {{ form.Name }}</b>\r\n </h4>\r\n </div>\r\n <div class=\"col-md-6 text-right\" *ngIf=\"defaultListActions.add\">\r\n <button class=\"btn btn-primary\" mat-raised-button color=\"primary\" type=\"button\"\r\n (click)=\"onAddViewEditRecord.emit(null)\">\r\n <mat-icon>add</mat-icon>\r\n <span style=\"margin-left: 10px\">Aggiungi</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<eqp-table class=\"list-form-record-table\" #tableRecords *ngIf=\"loader && configurations.values\"\r\n [data]=\"configurations.values\" [columns]=\"columns\"></eqp-table> -->\r\n", styles: ["::ng-deep .error-color{color:var(--danger)}::ng-deep .success-color{color:var(--success)}.table-container{max-width:100%;overflow-x:auto;border:1px solid #ddd}.sticky-column{position:sticky;left:0;background:white;z-index:10;box-shadow:2px 0 5px #0000001a}.mat-table-fixed{width:-moz-max-content;width:max-content;min-width:100%;table-layout:fixed}th,td{text-align:center;padding:10px;min-width:100px;max-width:200px}\n"], dependencies: [{ kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "component", type: i4.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i6.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i6.MatCardFooter, selector: "mat-card-footer" }, { kind: "component", type: i6.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i6.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "component", type: i7.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i7.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i7.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i7.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i7.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i7.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i7.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i7.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i7.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i7.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i8.TmwDateTimePickerComponent, selector: "tmw-datetimepicker", inputs: ["debugMode", "ngModelInput", "formGroupInput", "formControlNameInput", "pickerMode", "timeType", "label", "placeholder", "hint", "minDate", "maxDate", "locale", "inputFormat", "outputFormat", "forSaveLocalOnDB", "disabled", "readonly", "currentDateAsDefault", "showSpinners", "touchUi", "enableMeridian", "hideTime", "stepHour", "showHours", "hourLabel", "stepMinute", "showMinutes", "minuteLabel", "stepSecond", "showSeconds", "secondLabel", "disableMinute", "dayLabel", "monthLabel", "yearLabel", "highLightedDates", "highLightedAriaFormat"], outputs: ["ngModelInputChange"] }, { kind: "pipe", type: i2.DatePipe, name: "date" }] });
628
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: HListFormRecordComponent, decorators: [{
629
+ type: Component,
630
+ args: [{ selector: "hlist-form-record", template: "<mat-card class=\"list-form-record\">\r\n <mat-card-header class=\"align-items-center justify-content-between\">\r\n <mat-card-title *ngIf=\"loadedFilters && showTitle\"\r\n >Elenco {{ form.Name }}</mat-card-title\r\n >\r\n <!-- <mat-card-actions>\r\n <button\r\n class=\"btn btn-primary\"\r\n mat-raised-button\r\n color=\"primary\"\r\n type=\"button\"\r\n (click)=\"onAddViewEditRecord.emit(null)\"\r\n >\r\n <mat-icon>add</mat-icon>\r\n <span style=\"margin-left: 10px\">Aggiungi</span>\r\n </button>\r\n </mat-card-actions> -->\r\n </mat-card-header>\r\n <mat-card-content>\r\n <!--#region FILTERS -->\r\n <div class=\"row\" *ngIf=\"loadedFilters\">\r\n <div class=\"col-sm-12 col-md-3\">\r\n <tmw-datetimepicker\r\n class=\"date\"\r\n [placeholder]=\"'Periodo inizio'\"\r\n [label]=\"'Periodo inizio'\"\r\n [(ngModelInput)]=\"minDate\"\r\n (ngModelInputChange)=\"filterDataAnswers()\"\r\n [pickerMode]=\"modes.DATEPICKER\"\r\n [outputFormat]=\"'DD/MM/YYYY'\"\r\n [showSeconds]=\"false\"\r\n >\r\n </tmw-datetimepicker>\r\n </div>\r\n <div class=\"col-sm-12 col-md-3\">\r\n <tmw-datetimepicker\r\n class=\"date\"\r\n [placeholder]=\"'Periodo fine'\"\r\n [label]=\"'Periodo fine'\"\r\n [(ngModelInput)]=\"maxDate\"\r\n (ngModelInputChange)=\"filterDataAnswers()\"\r\n [pickerMode]=\"modes.DATEPICKER\"\r\n [outputFormat]=\"'DD/MM/YYYY'\"\r\n [showSeconds]=\"false\"\r\n >\r\n </tmw-datetimepicker>\r\n </div>\r\n <div class=\"col-sm-12 col-md-3 mt-2\">\r\n <mat-form-field>\r\n <mat-label>Selezione dei campi</mat-label>\r\n <mat-select (selectionChange)=\"onSelectionChange($event)\" multiple>\r\n <mat-option *ngFor=\"let property of properties\" [value]=\"property\">\r\n {{ propertiesLabel[property.label] }}\r\n </mat-option>\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n <!-- <div class=\"col-sm-12 col-md-3 mt-2\">\r\n <button\r\n [disabled]=\"\r\n selectedProperties == null || selectedProperties.length == 0\r\n \"\r\n class=\"btn btn-graph-generate button-next me-2\"\r\n mat-raised-button\r\n color=\"primary\"\r\n (click)=\"filterDataAnswers()\"\r\n >\r\n Genera\r\n </button>\r\n </div> -->\r\n </div>\r\n <!--#endregion FILTERS -->\r\n\r\n <!--#region TABLE -->\r\n <div class=\"table-container\">\r\n <table\r\n mat-table\r\n [dataSource]=\"selectedProperties\"\r\n class=\"mat-elevation-z8 mat-table-fixed\"\r\n >\r\n <!-- Colonna fissa per le propriet\u00E0 -->\r\n <ng-container matColumnDef=\"property\" sticky>\r\n <th mat-header-cell *matHeaderCellDef class=\"sticky-column\">\r\n Data Inserimento\r\n </th>\r\n <td\r\n mat-cell\r\n *matCellDef=\"let selectedProperties\"\r\n class=\"sticky-column\"\r\n >\r\n {{ propertiesLabel[selectedProperties.label] }}\r\n </td>\r\n </ng-container>\r\n\r\n <!-- Genera dinamicamente le colonne per ogni risposta -->\r\n <ng-container\r\n *ngFor=\"let value of filteredAnswers; let i = index\"\r\n [matColumnDef]=\"'col' + i\"\r\n >\r\n <th mat-header-cell *matHeaderCellDef>\r\n {{ value.AnswerDate | date : \"dd/MM/yyyy HH:mm\" }}\r\n </th>\r\n <!-- <th mat-header-cell *matHeaderCellDef> {{ value.AnswerDate | date:'dd/MM/yyyy HH:mm' }} </th> -->\r\n <td mat-cell *matCellDef=\"let selectedProperties\">\r\n {{\r\n selectedProperties.label === \"AnswerDate\"\r\n ? (value.AnswerDate | date : \"dd/MM/yyyy HH:mm\")\r\n : printValue(selectedProperties.type, value[selectedProperties.label], selectedProperties.config) ?? \"N/A\"\r\n }}\r\n <!-- - \r\n {{selectedProperties.type}}\r\n {{selectedProperties.label}} -->\r\n </td>\r\n </ng-container>\r\n\r\n <!-- Header della tabella -->\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n\r\n <!-- Righe della tabella -->\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\"></tr>\r\n </table>\r\n </div>\r\n <!--#region TABLE -->\r\n </mat-card-content>\r\n <mat-card-footer>\r\n <!-- <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar> -->\r\n </mat-card-footer>\r\n</mat-card>\r\n\r\n<!-- <div class=\"row eqp-dynamic-module-title list-form-record-header\">\r\n <div class=\"col-md-6\">\r\n <h4 *ngIf=\"showTitle\">\r\n <b>Elenco {{ form.Name }}</b>\r\n </h4>\r\n </div>\r\n <div class=\"col-md-6 text-right\" *ngIf=\"defaultListActions.add\">\r\n <button class=\"btn btn-primary\" mat-raised-button color=\"primary\" type=\"button\"\r\n (click)=\"onAddViewEditRecord.emit(null)\">\r\n <mat-icon>add</mat-icon>\r\n <span style=\"margin-left: 10px\">Aggiungi</span>\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<eqp-table class=\"list-form-record-table\" #tableRecords *ngIf=\"loader && configurations.values\"\r\n [data]=\"configurations.values\" [columns]=\"columns\"></eqp-table> -->\r\n", styles: ["::ng-deep .error-color{color:var(--danger)}::ng-deep .success-color{color:var(--success)}.table-container{max-width:100%;overflow-x:auto;border:1px solid #ddd}.sticky-column{position:sticky;left:0;background:white;z-index:10;box-shadow:2px 0 5px #0000001a}.mat-table-fixed{width:-moz-max-content;width:max-content;min-width:100%;table-layout:fixed}th,td{text-align:center;padding:10px;min-width:100px;max-width:200px}\n"] }]
631
+ }], ctorParameters: function () { return [{ type: i1.UtilityHelperService }, { type: i0.ChangeDetectorRef }, { type: i2.DatePipe }]; }, propDecorators: { configurations: [{
632
+ type: Input
633
+ }], endPointConfiguration: [{
634
+ type: Input
635
+ }], formID: [{
636
+ type: Input
637
+ }], form: [{
638
+ type: Input
639
+ }], externalButtons: [{
640
+ type: Input
641
+ }], tableRecords: [{
642
+ type: ViewChild,
643
+ args: ["tableRecords", { static: true }]
644
+ }], onViewRecord: [{
645
+ type: Output
646
+ }], onAddViewEditRecord: [{
647
+ type: Output
648
+ }], onDeleteRecord: [{
649
+ type: Output
650
+ }], onAfterDeleteRecord: [{
651
+ type: Output
652
+ }] } });
653
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGxpc3QtZm9ybS1yZWNvcmQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZXFwLWR5bmFtaWMtbW9kdWxlL3NyYy9saWIvY29tcG9uZW50cy9wcml2YXRlL2Zvcm0tcmVjb3Jkcy9obGlzdC1mb3JtLXJlY29yZC9obGlzdC1mb3JtLXJlY29yZC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9lcXAtZHluYW1pYy1tb2R1bGUvc3JjL2xpYi9jb21wb25lbnRzL3ByaXZhdGUvZm9ybS1yZWNvcmRzL2hsaXN0LWZvcm0tcmVjb3JkL2hsaXN0LWZvcm0tcmVjb3JkLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsS0FBSyxFQUNMLFNBQVMsRUFDVCxNQUFNLEVBQ04sWUFBWSxHQUtiLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFLTCxVQUFVLEdBQ1gsTUFBTSxzQkFBc0IsQ0FBQztBQUU5QixPQUFPLEVBQWEsYUFBYSxFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDOUUsT0FBTyxFQUFhLE1BQU0sRUFBZ0IsTUFBTSxpQ0FBaUMsQ0FBQztBQUVsRixPQUFPLEVBRUwsZ0JBQWdCLEdBQ2pCLE1BQU0sMkNBQTJDLENBQUM7QUFJbkQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDbkYsT0FBTyxFQUFFLHlDQUF5QyxFQUFFLE1BQU0sOERBQThELENBQUM7QUFFekgsT0FBTyxFQUdMLGFBQWEsR0FDZCxNQUFNLGdEQUFnRCxDQUFDO0FBRXhELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sWUFBWSxDQUFDOzs7Ozs7Ozs7O0FBV3RDLE1BQU0sT0FBTyx3QkFBd0I7SUF3Q25DLHFCQUFxQjtJQUNyQixZQUNVLG9CQUEwQyxFQUMxQyxjQUFpQyxFQUNqQyxRQUFrQjtRQUZsQix5QkFBb0IsR0FBcEIsb0JBQW9CLENBQXNCO1FBQzFDLG1CQUFjLEdBQWQsY0FBYyxDQUFtQjtRQUNqQyxhQUFRLEdBQVIsUUFBUSxDQUFVO1FBdENuQixTQUFJLEdBQVMsSUFBSSxDQUFDLENBQUMscUJBQXFCO1FBQ3hDLG9CQUFlLEdBQXdCLElBQUksS0FBSyxFQUFnQixDQUFDO1FBRTFFLHVCQUFrQixHQUNoQixJQUFJLHlDQUF5QyxFQUFFLENBQUM7UUFDbEQsY0FBUyxHQUFHLElBQUksQ0FBQztRQUdqQixZQUFPLEdBQUcsSUFBSSxLQUFLLEVBQWdCLENBQUM7UUFDcEMsa0JBQWEsR0FBWSxLQUFLLENBQUM7UUFDL0IsZ0JBQVcsR0FBWSxLQUFLLENBQUM7UUFFbkIsaUJBQVksR0FBeUIsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUNoRSx3QkFBbUIsR0FBeUQsSUFBSSxZQUFZLEVBQXlDLENBQUM7UUFFdEksbUJBQWMsR0FBeUIsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUNsRSx3QkFBbUIsR0FBeUIsSUFBSSxZQUFZLEVBQVUsQ0FBQztRQUVqRixVQUFLLEdBQUcsUUFBUSxDQUFDO1FBQ2pCLFlBQU8sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3JCLFlBQU8sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBRXJCLHNEQUFzRDtRQUN0RCxlQUFVLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLGlGQUFpRjtRQUNqRixvQkFBZSxHQUFHLEVBQUUsQ0FBQztRQU1yQixtRkFBbUY7UUFDbkYscUJBQWdCLEdBQUcsRUFBRSxDQUFDO1FBUXBCLCtDQUErQztJQUNqRCxDQUFDO0lBQ0Qsd0JBQXdCO0lBRXhCLG1CQUFtQjtJQUNuQixRQUFRO1FBQ04sSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsa0JBQWtCLENBQUM7UUFDakUsSUFBSSxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQztRQUMvQyxhQUFhLENBQUMsUUFBUSxDQUFDLDhDQUE4QyxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUU1RixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDckIsQ0FBQztJQUNELHNCQUFzQjtJQUV0QixxQkFBcUI7SUFDckIsV0FBVyxDQUFDLE9BQXNCO1FBQ2hDLGFBQWEsQ0FBQyxRQUFRLENBQUMsNEJBQTRCLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDOUQsMEVBQTBFO1FBQzFFLGtHQUFrRztRQUNsRyx5RUFBeUU7UUFDekUseUJBQXlCO1FBQ3pCLElBQUk7SUFDTixDQUFDO0lBQ0Qsd0JBQXdCO0lBRXhCLHFCQUFxQjtJQUNyQixLQUFLLENBQUMsV0FBVyxDQUFDLEtBQWEsSUFBSSxDQUFDLE1BQU07UUFDeEMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxnQ0FBZ0MsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFcEUsSUFBSSxJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksRUFBRTtZQUNyQixNQUFNLG1CQUFtQixHQUN2QixJQUFJLEtBQUssRUFBc0IsQ0FBQztZQUNsQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUM7Z0JBQ3ZCLFNBQVMsRUFBRSxJQUFJO2dCQUNmLFVBQVUsRUFBRSxFQUFFO2dCQUNkLFNBQVMsRUFBRSxhQUFhLENBQUMsYUFBYSxDQUFDO2FBQ3hDLENBQUMsQ0FBQztZQUNILE1BQU0sSUFBSSxDQUFDLG9CQUFvQixDQUFDLGVBQWUsQ0FDN0MsSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxlQUFlLEVBQ2hELG1CQUFtQixFQUNuQixDQUFDLEdBQVMsRUFBRSxFQUFFO2dCQUNaLElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxDQUFDO2dCQUNoQixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUMxQixDQUFDLEVBQ0QsQ0FBQyxHQUFHLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FDYixDQUFDO1NBQ0g7YUFBTTtZQUNMLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1NBQ3pCO0lBQ0gsQ0FBQztJQUNELHdCQUF3QjtJQUV4Qiw0QkFBNEI7SUFDNUI7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsa0JBQWtCO1FBQ3RCOzs7O1dBSUc7UUFDSCxNQUFNLGdDQUFnQyxHQUFHLENBQUMsT0FBTyxFQUFFLEVBQUU7WUFDbkQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEdBQUcsSUFBSSxLQUFLLEVBQVUsQ0FBQztZQUNqRCxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7Z0JBQ3pCLElBQUksTUFBTSxHQUFXLElBQUksTUFBTSxFQUFFLENBQUM7Z0JBQ2xDLE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO2dCQUM3QyxNQUFNLENBQUMsRUFBRSxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQztnQkFDNUIsTUFBTSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDO2dCQUNoQyxNQUFNLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7Z0JBQzlCLE1BQU0sQ0FBQyxVQUFVLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQztnQkFDdEMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzFDLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFBO1FBRUQ7Ozs7V0FJRztRQUNILE1BQU0sdUJBQXVCLEdBQUcsR0FBRyxFQUFFO1lBQ25DLDRFQUE0RTtZQUM1RSxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUM3RixJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDO1lBQ2xELElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUV0QixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztZQUMxQixJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksQ0FBQztZQUN4QixVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtnQkFDZixJQUFJLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3RDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWE7UUFDdEIsQ0FBQyxDQUFBO1FBRUQsSUFBSSxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRTtZQUM5QixzRUFBc0U7WUFDdEUsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4QkFBOEIsRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUE7WUFDaEUsdUJBQXVCLEVBQUUsQ0FBQztTQUMzQjthQUFNO1lBQ0wsK0RBQStEO1lBQy9ELE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQThCLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFBO1lBQ2hFLElBQUk7Z0JBQ0YsSUFDRSxJQUFJLENBQUMscUJBQXFCO29CQUMxQixJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTztvQkFDbEMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsRUFDdEQ7b0JBQ0EsSUFBSSxtQkFBbUIsR0FBRzt3QkFDeEI7NEJBQ0UsU0FBUyxFQUFFLE9BQU87NEJBQ2xCLFVBQVUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7NEJBQ3hCLFNBQVMsRUFBRSxhQUFhLENBQUMsYUFBYSxDQUFDO3lCQUN4QztxQkFDRixDQUFDO29CQUNGLElBQUksSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLElBQUksSUFBSSxFQUFFO3dCQUN0QywrQkFBK0I7d0JBQy9CLG9DQUFvQzt3QkFDcEMsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsZUFBZSxDQUM3QyxJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTyxDQUFDLG1CQUFtQixFQUN0RCxtQkFBbUIsRUFDbkIsQ0FBQyxHQUFxQixFQUFFLEVBQUU7NEJBQ3hCLGdDQUFnQyxDQUFDLEdBQUcsQ0FBQyxDQUFDOzRCQUN0Qyx1QkFBdUIsRUFBRSxDQUFDO3dCQUM1QixDQUFDLENBQ0YsQ0FBQztxQkFDSDt5QkFBTTt3QkFDTCxtQkFBbUI7d0JBQ25CLG1DQUFtQzt3QkFDbkMsbUJBQW1CLENBQUMsSUFBSSxDQUN0Qjs0QkFDRSxTQUFTLEVBQUUsUUFBUTs0QkFDbkIsVUFBVSxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTTs0QkFDdEMsU0FBUyxFQUFFLGFBQWEsQ0FBQyxhQUFhLENBQUM7eUJBQ3hDLENBQUMsQ0FBQzt3QkFDTCxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxlQUFlLENBQzdDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsNEJBQTRCLEVBQy9ELG1CQUFtQixFQUNuQixDQUFDLEdBQXFCLEVBQUUsRUFBRTs0QkFDeEIsZ0NBQWdDLENBQUMsR0FBRyxDQUFDLENBQUM7NEJBQ3RDLHVCQUF1QixFQUFFLENBQUM7d0JBQzVCLENBQUMsQ0FDRixDQUFDO3FCQUVIO2lCQUNGO2FBQ0Y7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixPQUFPLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQTthQUM5QjtTQUNGO0lBQ0gsQ0FBQztJQUNELCtCQUErQjtJQUcvQiwwQkFBMEI7SUFDMUI7O09BRUc7SUFDSyxnQkFBZ0I7UUFDdEIsSUFBSSxDQUFDLE9BQU8sR0FBRztZQUNiO2dCQUNFLEdBQUcsRUFBRSxRQUFRO2dCQUNiLE9BQU8sRUFBRSxFQUFFO2dCQUNYLElBQUksRUFBRSxVQUFVLENBQUMsVUFBVTtnQkFDM0IsY0FBYyxFQUFFLFdBQVc7Z0JBQzNCLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7Z0JBQzFCLE9BQU8sRUFBRSxFQUFFO2FBQ1o7U0FDRixDQUFDO1FBRUYsSUFBSSxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxJQUFJLElBQUksRUFBRTtZQUN4QyxJQUFJLENBQUMsT0FBTztpQkFDVCxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssUUFBUSxDQUFDO2lCQUMvQixPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUNaLElBQUksRUFBRSxZQUFZO2dCQUNsQixJQUFJLEVBQUUsTUFBTTtnQkFDWixFQUFFLEVBQUUsQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUM7YUFDdEQsQ0FBQyxDQUFDO1NBQ047UUFDRCxJQUFJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLElBQUksSUFBSSxFQUFFO1lBQ3hDLElBQUksQ0FBQyxPQUFPO2lCQUNULElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxRQUFRLENBQUM7aUJBQy9CLE9BQU8sQ0FBQyxJQUFJLENBQUM7Z0JBQ1osSUFBSSxFQUFFLFVBQVU7Z0JBQ2hCLElBQUksRUFBRSxNQUFNO2dCQUNaLEVBQUUsRUFBRSxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQzthQUNuRSxDQUFDLENBQUM7U0FDTjtRQUNELElBQUksSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsSUFBSSxJQUFJLEVBQUU7WUFDN0M7Ozs7OzttQkFNTztTQUNSO1FBQ0QsSUFBSSxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxJQUFJLElBQUksRUFBRTtZQUMxQyxJQUFJLENBQUMsT0FBTztpQkFDVCxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssUUFBUSxDQUFDO2lCQUMvQixPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUNaLElBQUksRUFBRSxTQUFTO2dCQUNmLElBQUksRUFBRSxRQUFRO2dCQUNkLEVBQUUsRUFBRSxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQzthQUN4RCxDQUFDLENBQUM7U0FDTjtRQUVELElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7WUFDdEMsSUFBSSxDQUFDLE9BQU87aUJBQ1QsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLFFBQVEsQ0FBQztpQkFDL0IsT0FBTyxDQUFDLElBQUksQ0FBQztnQkFDWixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7Z0JBQ2pCLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtnQkFDakIsRUFBRSxFQUFFLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUU7YUFDekMsQ0FBQyxDQUFDO1FBQ1AsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBQ0QsNkJBQTZCO0lBRTdCLGlDQUFpQztJQUNqQzs7O09BR0c7SUFDSyx1QkFBdUI7UUFDN0IsYUFBYSxDQUFDLFFBQVEsQ0FBQyw0Q0FBNEMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFaEYsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQ3JFLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUN0QyxDQUFDLENBQUMsZUFBZSxHQUFHLENBQUMsQ0FBQyxlQUFlO2dCQUNuQyxDQUFDLENBQUMsQ0FBQztnQkFDSCxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWUsR0FBRyxDQUFDLENBQUMsZUFBZTtvQkFDckMsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDSixDQUFDLENBQUMsQ0FBQyxDQUNSLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7Z0JBQ25CLElBQUksQ0FBQyxPQUFPO3FCQUNULElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxRQUFRLENBQUM7cUJBQy9CLE9BQU8sQ0FBQyxJQUFJLENBQUM7b0JBQ1osSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJO29CQUNqQixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7b0JBQ2pCLEVBQUUsRUFBRSxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLEVBQUU7d0JBQzFCLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQzt3QkFDcEIsTUFBTSxHQUFHLEdBQUcsb0JBQW9CLENBQUMsT0FBTyxDQUFDO3dCQUN6QyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO3dCQUNwQiw2QkFBNkI7b0JBQy9CLENBQUM7aUJBQ0YsQ0FBQyxDQUFDO1lBQ1AsQ0FBQyxDQUFDLENBQUM7U0FDSjtJQUNILENBQUM7SUFDRCxvQ0FBb0M7SUFHcEMscUNBQXFDO0lBQ3JDOzs7Ozs7T0FNRztJQUNLLDJCQUEyQjtRQUNqQyxhQUFhLENBQUMsUUFBUSxDQUFDLGdEQUFnRCxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVwRixJQUFJLGdCQUFrQyxDQUFDO1FBQ3ZDLGdCQUFnQixHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1lBQy9DLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRTtnQkFDakIsT0FBTyxDQUFDLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQTthQUNoQztpQkFBTTtnQkFDTCxPQUFPLENBQUMsQ0FBQyxVQUFVLENBQUM7YUFDckI7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUNILGdCQUFnQjthQUNiLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUNiLENBQUMsQ0FBQyxlQUFlLEdBQUcsQ0FBQyxDQUFDLGVBQWU7WUFDbkMsQ0FBQyxDQUFDLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWUsR0FBRyxDQUFDLENBQUMsZUFBZTtnQkFDckMsQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDSixDQUFDLENBQUMsQ0FBQyxDQUNSO2FBQ0EsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDakIsb0RBQW9EO1lBQ3BELElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDbkYsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQztRQUN4RCxDQUFDLENBQUMsQ0FBQztRQUNMLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQzVDLENBQUM7SUFDRCx3Q0FBd0M7SUFFeEMsMkJBQTJCO0lBQzNCOzs7O09BSUc7SUFDSCw4REFBOEQ7SUFDOUQsMEVBQTBFO0lBQzFFLCtCQUErQjtJQUMvQixzQ0FBc0M7SUFDdEMsMENBQTBDO0lBQzFDLGlDQUFpQztJQUNqQyw0REFBNEQ7SUFDNUQsNkRBQTZEO0lBQzdELFdBQVc7SUFDWCwwQkFBMEI7SUFDMUIsMEJBQTBCO0lBQzFCLG1EQUFtRDtJQUNuRCxXQUFXO0lBQ1gsZUFBZTtJQUNmLDBDQUEwQztJQUMxQyxhQUFhO0lBQ2IsNkVBQTZFO0lBQzdFLFlBQVk7SUFDWix5Q0FBeUM7SUFDekMsZUFBZTtJQUNmLDhFQUE4RTtJQUM5RSxjQUFjO0lBQ2QsZ0RBQWdEO0lBQ2hELHNCQUFzQjtJQUN0Qiw2RUFBNkU7SUFDN0UsY0FBYztJQUNkLDREQUE0RDtJQUM1RCxvRUFBb0U7SUFDcEUsOEJBQThCO0lBQzlCLFlBQVk7SUFDWixVQUFVO0lBQ1YsZUFBZTtJQUNmLDRDQUE0QztJQUM1QyxzREFBc0Q7SUFDdEQseURBQXlEO0lBQ3pELDRFQUE0RTtJQUM1RSx5REFBeUQ7SUFDekQsd0RBQXdEO0lBQ3hELFVBQVU7SUFDVixlQUFlO0lBQ2Ysc0NBQXNDO0lBQ3RDLHNDQUFzQztJQUV0QyxXQUFXO0lBQ1gsZ0RBQWdEO0lBQ2hELGlCQUFpQjtJQUNqQiwwREFBMEQ7SUFDMUQseURBQXlEO0lBQ3pELHNFQUFzRTtJQUN0RSxnQkFBZ0I7SUFDaEIsbUZBQW1GO0lBQ25GLGlFQUFpRTtJQUNqRSw0Q0FBNEM7SUFDNUMsZ0NBQWdDO0lBQ2hDLHdCQUF3QjtJQUN4QixxQkFBcUI7SUFDckIsbUZBQW1GO0lBQ25GLDZFQUE2RTtJQUM3RSx3QkFBd0I7SUFDeEIsY0FBYztJQUNkLGFBQWE7SUFDYixxQ0FBcUM7SUFDckMsdUNBQXVDO0lBQ3ZDLFdBQVc7SUFFWCxlQUFlO0lBQ2YsNkNBQTZDO0lBQzdDLDhDQUE4QztJQUM5QywwREFBMEQ7SUFDMUQsMkVBQTJFO0lBQzNFLDJCQUEyQjtJQUMzQixxQkFBcUI7SUFDckIsdUVBQXVFO0lBQ3ZFLCtCQUErQjtJQUMvQixnREFBZ0Q7SUFDaEQsNERBQTREO0lBQzVELG9CQUFvQjtJQUNwQixrQkFBa0I7SUFDbEIsNkJBQTZCO0lBQzdCLGNBQWM7SUFDZCxtQkFBbUI7SUFDbkIsMkVBQTJFO0lBQzNFLHFCQUFxQjtJQUNyQiwrRUFBK0U7SUFDL0UsZUFBZTtJQUNmLFlBQVk7SUFDWixXQUFXO0lBQ1gsbUNBQW1DO0lBQ25DLHFDQUFxQztJQUNyQyxlQUFlO0lBQ2Ysb0NBQW9DO0lBQ3BDLGdCQUFnQjtJQUNoQixlQUFlO0lBQ2YsTUFBTTtJQUNOLG1CQUFtQjtJQUNuQixJQUFJO0lBQ0osOEJBQThCO0lBRTlCLG9CQUFvQjtJQUNwQixVQUFVLENBQUMsTUFBYztRQUN2QixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBQ0QsdUJBQXVCO0lBRXZCOzs7OztPQUtHO0lBQ0ssZ0JBQWdCLENBQUMsTUFBYyxFQUFFLFFBQWlCO1FBQ3hELElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsWUFBWSxDQUFDLE1BQWM7UUFDekIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVEOztPQUVHO0lBQ0ssWUFBWTtRQUNsQixJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUU7WUFDckIsSUFBSSxDQUFDLFlBQVksQ0FBQyxlQUFlLEVBQUUsQ0FBQztTQUNyQztJQUNILENBQUM7SUFFRCwyQkFBMkI7SUFDM0I7Ozs7T0FJRztJQUNILGlCQUFpQixDQUFDLGtCQUFrQjtRQUNsQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3RDLElBQUksa0JBQWtCLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDdkMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGtCQUFrQixDQUFDLEtBQUssQ0FBQztTQUNwRDthQUFNO1lBQ0wsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxVQUFVLENBQUM7U0FDM0M7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFDRCw4QkFBOEI7SUFFOUIsMkJBQTJCO0lBQzNCOztPQUVHO0lBQ0gsaUJBQWlCO1FBQ2YsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUNkLElBQUksQ0FBQyxlQUFlLEdBQUcsRUFBRSxDQUFDO1lBRTFCLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBRXRDLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUMzQyxJQUFJLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxJQUFJLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFO29CQUU1RixJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztpQkFDbEM7WUFDSCxDQUFDLENBQUMsQ0FBQztZQUNILElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLFVBQVUsRUFBRSxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFFdkYsMkJBQTJCO1FBRTdCLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNWLENBQUM7SUFDRCw4QkFBOEI7SUFFOUIsd0JBQXdCO0lBQ3hCLGlFQUFpRTtJQUNqRSxjQUFjO1FBQ1osMERBQTBEO1FBQzFELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBRWxGLHlEQUF5RDtRQUN6RCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3hFLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUUsQ0FBQztJQUNELDJCQUEyQjtJQUUzQixvQkFBb0I7SUFDcEIsVUFBVSxDQUFDLFNBQVMsRUFBRSxLQUFLLEVBQUUsV0FBVztRQUN0QyxnQkFBZ0I7UUFDaEIsd0JBQXdCO1FBRXhCLFFBQVEsU0FBUyxFQUFFO1lBQ2pCLEtBQUssYUFBYSxDQUFDLGlCQUFpQixDQUFDO2dCQUFFO29CQUNyQyxPQUFPLEtBQUssQ0FBQztvQkFDYixNQUFNO2lCQUNQO2dCQUFBLENBQUM7WUFDRixLQUFLLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFBRTtvQkFDcEMsSUFBbUIsV0FBWSxDQUFDLFNBQVMsRUFBRTt3QkFDekMsSUFBbUIsV0FBWSxDQUFDLGdCQUFnQixJQUFJLElBQUksRUFBRTs0QkFDeEQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO3lCQUMxQjs2QkFBTTs0QkFDTCxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDOzRCQUNuRCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQyxHQUFHLFFBQVEsQ0FBQzt5QkFDaEQ7cUJBQ0Y7eUJBQU07d0JBQ0wsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLGdCQUFnQixHQUFHLEVBQUUsQ0FBQzt3QkFDbkQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsR0FBRyxRQUFRLENBQUM7cUJBQ2hEO29CQUNELE1BQU07aUJBQ1A7Z0JBQUEsQ0FBQztZQUVGLEtBQUssYUFBYSxDQUFDLFVBQVUsQ0FBQztnQkFBRTtvQkFDOUIsT0FBTyxVQUFVLENBQUM7b0JBQ2xCLGFBQWEsQ0FBQyxRQUFRLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQyxJQUFJLEdBQUcsS0FBSyxHQUFHLEtBQUssQ0FBQyxDQUFBO29CQUN0RSxpRUFBaUU7b0JBQ2pFLDZIQUE2SDtvQkFFN0gseUNBQXlDO29CQUN6QyxtR0FBbUc7b0JBRW5HLE1BQU07aUJBQ1A7Z0JBQUEsQ0FBQztZQUdGLEtBQUssYUFBYSxDQUFDLFVBQVUsQ0FBQztnQkFBRTtvQkFDOUIsT0FBTyxVQUFVLENBQUM7b0JBQ2xCLDJFQUEyRTtvQkFFM0UsSUFBSSxLQUFLLElBQUksSUFBSSxFQUFFO3dCQUNqQixJQUFJLGFBQWEsQ0FBQzt3QkFDbEIsMEJBQTBCO3dCQUMxQixtRUFBbUU7d0JBQ25FLGlJQUFpSTt3QkFDakksdUVBQXVFO3dCQUN2RSwyQ0FBMkM7d0JBQzNDLDhIQUE4SDt3QkFDOUgsOERBQThEO3dCQUM5RCwwSUFBMEk7d0JBQzFJLFdBQVc7d0JBQ1gsMkpBQTJKO3dCQUMzSixJQUFJO3dCQUVKLHNDQUFzQzt3QkFDdEMsdUdBQXVHO3dCQUN2RyxzRkFBc0Y7cUJBQ3ZGO29CQUVELE1BQU07aUJBQ1A7Z0JBQUEsQ0FBQztZQUVGLEtBQUssYUFBYSxDQUFDLHNCQUFzQixDQUFDO2dCQUFFO29CQUMxQyxPQUFPLHNCQUFzQixDQUFDO29CQUU5Qiw4REFBOEQ7b0JBQzlELDZIQUE2SDtvQkFFN0gsc0NBQXNDO29CQUN0QyxtR0FBbUc7b0JBRW5HLE1BQU07aUJBQ1A7Z0JBQUEsQ0FBQztZQUVGLEtBQUssYUFBYSxDQUFDLGlCQUFpQixDQUFDO2dCQUFFO29CQUNyQyxPQUFPLGlCQUFpQixDQUFDO29CQUN6QixJQUFJLGlCQUFpQixHQUFHLEVBQUUsQ0FBQztvQkFDM0IsSUFBSSxLQUFLLElBQUksSUFBSSxJQUF5QixXQUFZLENBQUMsY0FBYyxFQUFFO3dCQUNyRSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsUUFBZ0IsRUFBRSxFQUFFOzRCQUNqQyxJQUFJLGdCQUFnQixHQUF1QyxXQUFZLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksUUFBUSxDQUFDLENBQUM7NEJBQ25ILElBQUksZ0JBQWdCLElBQUksSUFBSSxFQUFFO2dDQUM1QixpQkFBaUIsSUFBSSxnQkFBZ0IsQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDOzZCQUN4RDt3QkFDSCxDQUFDLENBQUMsQ0FBQzt3QkFDSCxJQUFJLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7d0JBQzFDLE9BQU8sS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7cUJBQ3BEO3lCQUNJO3dCQUNILElBQUksZ0JBQWdCLEdBQXVDLFdBQVksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxLQUFLLENBQUMsQ0FBQzt3QkFDaEgsSUFBSSxnQkFBZ0IsSUFBSSxJQUFJLEVBQUU7NEJBQzVCLE9BQU8sZ0JBQWdCLENBQUMsU0FBUyxDQUFDO3lCQUNuQztxQkFDRjtvQkFFRCxNQUFNO2lCQUNQO2dCQUFBLENBQUM7WUFDRixLQUFLLGFBQWEsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDO2dCQUNsQyxhQUFhLENBQUMsUUFBUSxDQUFDLGNBQWMsRUFBRSxXQUFXLENBQUMsQ0FBQztnQkFDcEQsSUFBZ0IsV0FBWSxDQUFDLFVBQVUsSUFBSSxJQUFJLEVBQUU7b0JBQy9DLElBQUksYUFBYSxHQUFlLFdBQVksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztvQkFDNUUsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsYUFBYSxDQUFDLENBQUM7aUJBQ3REO3FCQUNJO29CQUNILElBQWdCLFdBQVksQ0FBQyxVQUFVLElBQUksZ0JBQWdCLENBQUMsV0FBVyxDQUFDLEVBQUU7d0JBQ3hFLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDO3FCQUNyRDt5QkFBTSxJQUFnQixXQUFZLENBQUMsVUFBVSxJQUFJLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxFQUFFO3dCQUNoRixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO3FCQUMzRDt5QkFBTSxJQUFnQixXQUFZLENBQUMsVUFBVSxJQUFJLGdCQUFnQixDQUFDLGFBQWEsQ0FBQyxFQUFFO3dCQUNqRixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztxQkFDaEQ7aUJBQ0Y7Z0JBQ0QsTUFBTTthQUNQO1lBRUQsT0FBTyxDQUFDLENBQUM7Z0JBQ1AsT0FBTyxLQUFLLENBQUM7YUFDZDtTQUNGO0lBRUgsQ0FBQztJQUNELHVCQUF1QjtJQUV2QiwyQkFBMkI7SUFDbkIsS0FBSyxDQUFDLGlCQUFpQixDQUFDLFdBQW1CO1FBQ2pELE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDckMsTUFBTSxTQUFTLEdBQUcsc0JBQXNCLENBQUM7WUFDekMsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMzQyxNQUFNLEdBQUcsR0FBRyxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3hCLEdBQUcsQ0FBQyxHQUFHLEdBQUcsV0FBVyxDQUFDO1lBQ3RCLEdBQUcsQ0FBQyxNQUFNLEdBQUc7Z0JBQ1gsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDaEQsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDcEMsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQztnQkFDeEIsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztnQkFDMUIsTUFBTSxXQUFXLEdBQUcsS0FBSyxHQUFHLE1BQU0sQ0FBQztnQkFFbkMsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDO2dCQUN0QixNQUFNLFFBQVEsR0FBRyxTQUFTLEdBQUcsV0FBVyxDQUFDO2dCQUV6QyxNQUFNLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQztnQkFDeEIsTUFBTSxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUM7Z0JBQzFCLEdBQUcsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDO2dCQUM5QyxJQUFJLE9BQU8sR0FBRyxHQUFHLENBQUM7Z0JBQ2xCLElBQUksT0FBTyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsUUFBUSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDN0QsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ25CLENBQUMsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7c0hBeHFCVSx3QkFBd0I7MEdBQXhCLHdCQUF3QixpaEJDcERyQyxrOUtBa0pBOzRGRDlGYSx3QkFBd0I7a0JBTHBDLFNBQVM7K0JBQ0UsbUJBQW1CO2tLQUtwQixjQUFjO3NCQUF0QixLQUFLO2dCQUNHLHFCQUFxQjtzQkFBN0IsS0FBSztnQkFHRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csSUFBSTtzQkFBWixLQUFLO2dCQUNHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBS3VDLFlBQVk7c0JBQXhELFNBQVM7dUJBQUMsY0FBYyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFNakMsWUFBWTtzQkFBckIsTUFBTTtnQkFDRyxtQkFBbUI7c0JBQTVCLE1BQU07Z0JBRUcsY0FBYztzQkFBdkIsTUFBTTtnQkFDRyxtQkFBbUI7c0JBQTVCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIENvbXBvbmVudCxcclxuICBPbkluaXQsXHJcbiAgSW5wdXQsXHJcbiAgVmlld0NoaWxkLFxyXG4gIE91dHB1dCxcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgT25DaGFuZ2VzLFxyXG4gIFNpbXBsZUNoYW5nZXMsXHJcbiAgybXJtU5nT25DaGFuZ2VzRmVhdHVyZSxcclxuICBDaGFuZ2VEZXRlY3RvclJlZixcclxufSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xyXG5pbXBvcnQgeyBJQXR0YWNobWVudERUTyB9IGZyb20gXCJAZXFwcm9qZWN0L2VxcC1hdHRhY2htZW50c1wiO1xyXG5pbXBvcnQge1xyXG4gIENlbGxBbGlnbm1lbnRFbnVtLFxyXG4gIENvbmZpZ0NvbHVtbixcclxuICBFcXBUYWJsZUNvbXBvbmVudCxcclxuICBOdW1iZXJDb2x1bW5QaXBlLFxyXG4gIFR5cGVDb2x1bW4sXHJcbn0gZnJvbSBcIkBlcXByb2plY3QvZXFwLXRhYmxlXCI7XHJcbmltcG9ydCB7IEZvcm0gfSBmcm9tIFwiLi4vLi4vLi4vLi4vbW9kZWxzL2Zvcm0ubW9kZWxcIjtcclxuaW1wb3J0IHsgQmFzZUZpZWxkLCBGaWVsZFR5cGVFbnVtIH0gZnJvbSBcIi4uLy4uLy4uLy4uL21vZGVscy9iYXNlRmllbGQubW9kZWxcIjtcclxuaW1wb3J0IHsgRHluUmVjb3JkLCBSZWNvcmQsIFJlY29yZEJ1dHRvbiB9IGZyb20gXCIuLi8uLi8uLi8uLi9tb2RlbHMvcmVjb3JkLm1vZGVsXCI7XHJcbmltcG9ydCB7IEF0dGFjaG1lbnRGaWVsZCB9IGZyb20gXCIuLi8uLi8uLi8uLi9tb2RlbHMvZmllbGRzL2F0dGFjaG1lbnRGaWVsZC5tb2RlbFwiO1xyXG5pbXBvcnQge1xyXG4gIERhdGVGaWVsZCxcclxuICBEYXRlVGltZVR5cGVFbnVtLFxyXG59IGZyb20gXCIuLi8uLi8uLi8uLi9tb2RlbHMvZmllbGRzL2RhdGVGaWVsZC5tb2RlbFwiO1xyXG5pbXBvcnQgeyBJbWFnZUZpZWxkIH0gZnJvbSBcIi4uLy4uLy4uLy4uL21vZGVscy9maWVsZHMvaW1hZ2VGaWVsZC5tb2RlbFwiO1xyXG5pbXBvcnQgeyBMaXN0VmFsdWVGaWVsZCB9IGZyb20gXCIuLi8uLi8uLi8uLi9tb2RlbHMvZmllbGRzL2xpc3RWYWx1ZUZpZWxkLm1vZGVsXCI7XHJcbmltcG9ydCB7IE51bWVyaWNGaWVsZCB9IGZyb20gXCIuLi8uLi8uLi8uLi9tb2RlbHMvZmllbGRzL251bWVyaWNGaWVsZC5tb2RlbFwiO1xyXG5pbXBvcnQgeyBVdGlsaXR5SGVscGVyU2VydmljZSB9IGZyb20gXCIuLi8uLi8uLi8uLi9zZXJ2aWNlcy91dGlsaXR5SGVscGVyLnNlcnZpY2VzXCI7XHJcbmltcG9ydCB7IER5bmFtaWNNb2R1bGVMaXN0Rm9ybVJlY29yZEFjdGlvbnNEZWZhdWx0IH0gZnJvbSBcIi4uLy4uLy4uLy4uL21vZGVscy9keW5hbWljTW9kdWxlTGlzdEZvcm1SZWNvcmRBY3Rpb25zRGVmYXVsdFwiO1xyXG5pbXBvcnQgeyBEeW5hbWljTW9kdWxlTGlzdENvbmZpZyB9IGZyb20gXCIuLi8uLi8uLi8uLi9tb2RlbHMvZHluYW1pY01vZHVsZUxpc3RDb25maWcubW9kZWxcIjtcclxuaW1wb3J0IHtcclxuICBFbmRQb2ludENvbmZpZ3VyYXRpb24sXHJcbiAgRW5kUG9pbnREYXRhUGFyYW1zLFxyXG4gIFBhcmFtVHlwZUVudW0sXHJcbn0gZnJvbSBcIi4uLy4uLy4uLy4uL21vZGVscy9lbmRQb2ludENvbmZpZ3VyYXRpb24ubW9kZWxcIjtcclxuaW1wb3J0IHsgRXFwRHluYW1pY01vZHVsZURpYWxvZ1NlcnZpY2UgfSBmcm9tIFwiLi4vLi4vLi4vLi4vc2VydmljZXMvZXFwLWR5bmFtaWMtbW9kdWxlLWRpYWxvZy5zZXJ2aWNlXCI7XHJcbmltcG9ydCB7IEdsb2JhbFNlcnZpY2UgfSBmcm9tIFwiLi4vLi4vLi4vLi4vc2VydmljZXMvZ2xvYmFsLnNlcnZpY2VcIjtcclxuaW1wb3J0IHsgTW9kZUVudW0gfSBmcm9tIFwidG13LXBpY2tlclwiO1xyXG5pbXBvcnQgeyBJbWFnZVNlbGVjdG9yRmllbGQgfSBmcm9tIFwiLi4vLi4vLi4vLi4vbW9kZWxzL2ZpZWxkcy9pbWFnZVNlbGVjdG9yRmllbGQubW9kZWxcIjtcclxuaW1wb3J0IHsgRHluQXR0YWNobWVudCB9IGZyb20gXCIuLi8uLi8uLi8uLi9tb2RlbHMvZHluQXR0YWNobWVudFwiO1xyXG5pbXBvcnQgeyBEYXRlUGlwZSB9IGZyb20gXCJAYW5ndWxhci9jb21tb25cIjtcclxuXHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogXCJobGlzdC1mb3JtLXJlY29yZFwiLFxyXG4gIHRlbXBsYXRlVXJsOiBcImhsaXN0LWZvcm0tcmVjb3JkLmNvbXBvbmVudC5odG1sXCIsXHJcbiAgc3R5bGVVcmxzOiBbXCIuL2hsaXN0LWZvcm0tcmVjb3JkLmNvbXBvbmVudC5zY3NzXCJdLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgSExpc3RGb3JtUmVjb3JkQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMge1xyXG4gIEBJbnB1dCgpIGNvbmZpZ3VyYXRpb25zOiBEeW5hbWljTW9kdWxlTGlzdENvbmZpZztcclxuICBASW5wdXQoKSBlbmRQb2ludENvbmZpZ3VyYXRpb246IEVuZFBvaW50Q29uZmlndXJhdGlvbjtcclxuXHJcbiAgLy8gbCd1bmEgbyBsJ2FsdHJhIHBlciBkdWUgbW9kYWxpdMOgIGQndXNvXHJcbiAgQElucHV0KCkgZm9ybUlEOiBzdHJpbmc7XHJcbiAgQElucHV0KCkgZm9ybTogRm9ybSA9IG51bGw7IC8vIGJvaCBtYSBjJ2VyYSBwcmltYVxyXG4gIEBJbnB1dCgpIGV4dGVybmFsQnV0dG9uczogQXJyYXk8UmVjb3JkQnV0dG9uPiA9IG5ldyBBcnJheTxSZWNvcmRCdXR0b24+KCk7XHJcblxyXG4gIGRlZmF1bHRMaXN0QWN0aW9uczogRHluYW1pY01vZHVsZUxpc3RGb3JtUmVjb3JkQWN0aW9uc0RlZmF1bHQgPVxyXG4gICAgbmV3IER5bmFtaWNNb2R1bGVMaXN0Rm9ybVJlY29yZEFjdGlvbnNEZWZhdWx0KCk7XHJcbiAgc2hvd1RpdGxlID0gdHJ1ZTtcclxuICBAVmlld0NoaWxkKFwidGFibGVSZWNvcmRzXCIsIHsgc3RhdGljOiB0cnVlIH0pIHRhYmxlUmVjb3JkczogRXFwVGFibGVDb21wb25lbnQ7XHJcblxyXG4gIGNvbHVtbnMgPSBuZXcgQXJyYXk8Q29uZmlnQ29sdW1uPigpO1xyXG4gIGxvYWRlZEZpbHRlcnM6IGJvb2xlYW4gPSBmYWxzZTtcclxuICBsb2FkZWRUYWJsZTogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBAT3V0cHV0KCkgb25WaWV3UmVjb3JkOiBFdmVudEVtaXR0ZXI8UmVjb3JkPiA9IG5ldyBFdmVudEVtaXR0ZXI8UmVjb3JkPigpO1xyXG4gIEBPdXRwdXQoKSBvbkFkZFZpZXdFZGl0UmVjb3JkOiBFdmVudEVtaXR0ZXI8eyByZWNvcmQ6IFJlY29yZDsgb25seVZpZXc6IGJvb2xlYW47IH0+ID0gbmV3IEV2ZW50RW1pdHRlcjx7IHJlY29yZDogUmVjb3JkOyBvbmx5VmlldzogYm9vbGVhbiB9PigpO1xyXG5cclxuICBAT3V0cHV0KCkgb25EZWxldGVSZWNvcmQ6IEV2ZW50RW1pdHRlcjxSZWNvcmQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxSZWNvcmQ+KCk7XHJcbiAgQE91dHB1dCgpIG9uQWZ0ZXJEZWxldGVSZWNvcmQ6IEV2ZW50RW1pdHRlcjxSZWNvcmQ+ID0gbmV3IEV2ZW50RW1pdHRlcjxSZWNvcmQ+KCk7XHJcblxyXG4gIG1vZGVzID0gTW9kZUVudW07XHJcbiAgbWluRGF0ZSA9IG5ldyBEYXRlKCk7XHJcbiAgbWF4RGF0ZSA9IG5ldyBEYXRlKCk7XHJcblxyXG4gIC8vIGxlIHByb3ByaWV0w6AgZGVsbGEgcmlzcG9zdGEgZGEgc3RhbXBhcmUgbmVsbGUgcmlnaGVcclxuICBwcm9wZXJ0aWVzID0gW107XHJcbiAgLy8gbGUgbGFiZWwgYXNzb2NpYXRlIGFsbGUgcHJvcHJpZXTDoCBkYSBzdGFtcGFyZSBjaGUgY29uZGl2aWRvbm8gbG8gc3Rlc3NvIGluZGljZVxyXG4gIHByb3BlcnRpZXNMYWJlbCA9IFtdO1xyXG4gIHNlbGVjdGVkUHJvcGVydGllczogc3RyaW5nW107XHJcblxyXG4gIC8vIGkgZGF0aSBkZWxsZSByaXNwb3N0ZSBkYSBzdGFtcGFyZVxyXG4gIGZpbHRlcmVkQW5zd2VycyAvL2xlIHJpc3Bvc3RlIGZpbHRyYXRlIFxyXG5cclxuICAvLyBDb2xvbm5lIGRhIHZpc3VhbGl6emFyZSAoZmlzc2EgbGEgcHJpbWEgY29sb25uYSBlIGdlbmVyYSBkaW5hbWljYW1lbnRlIGxlIGFsdHJlKVxyXG4gIGRpc3BsYXllZENvbHVtbnMgPSBbXTtcclxuXHJcbiAgLy8jcmVnaW9uIENvbnN0cnVjdG9yXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIHV0aWxpdHlIZWxwZXJTZXJ2aWNlOiBVdGlsaXR5SGVscGVyU2VydmljZSxcclxuICAgIHByaXZhdGUgY2hhbmdlRGV0ZWN0b3I6IENoYW5nZURldGVjdG9yUmVmLFxyXG4gICAgcHJpdmF0ZSBkYXRlcGlwZTogRGF0ZVBpcGVcclxuICApIHtcclxuICAgIC8vIHRoaXMucHJvcGVydGllc0xhYmVsW1wiQW5zd2VyRGF0ZVwiXSA9IFwiRGF0YVwiO1xyXG4gIH1cclxuICAvLyNlbmRyZWdpb24gQ29uc3RydWN0b3JcclxuXHJcbiAgLy8jcmVnaW9uIG5nT25JbnRpdFxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5kZWZhdWx0TGlzdEFjdGlvbnMgPSB0aGlzLmNvbmZpZ3VyYXRpb25zLmRlZmF1bHRMaXN0QWN0aW9ucztcclxuICAgIHRoaXMuc2hvd1RpdGxlID0gdGhpcy5jb25maWd1cmF0aW9ucy5zaG93VGl0bGU7XHJcbiAgICBHbG9iYWxTZXJ2aWNlLmRlYnVnTG9nKCdsaXN0LWZvcm0tcmVjb3JkIC0gbmdPbkluaXQgLSBjb25maWd1cmF0aW9ucycsIHRoaXMuY29uZmlndXJhdGlvbnMpO1xyXG5cclxuICAgIHRoaXMuZ2V0Rm9ybUJ5SUQoKTtcclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIG5nT25JbnRpdFxyXG5cclxuICAvLyNyZWdpb24gbmdPbkNoYW5nZXNcclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XHJcbiAgICBHbG9iYWxTZXJ2aWNlLmRlYnVnTG9nKCdsaXN0LWZvcm0tcmVjb3JkIC0gY2hhbmdlcycsIGNoYW5nZXMpO1xyXG4gICAgLy8gU2UgdmllbmUgbW9kaWZpY2F0byBpbCB2YWxvcmUgZGkgXCJuZ01vZGVsSW5wdXRcIiBhbGxvcmEgYWdnaW9ybmEgbCdpbnB1dFxyXG4gICAgLy8gaWYgKGNoYW5nZXNbJ2NvbmZpZ3VyYXRpb25zJ10gIT0gdW5kZWZpbmVkICYmIGNoYW5nZXNbJ2NvbmZpZ3VyYXRpb25zJ10uZmlyc3RDaGFuZ2UgPT0gZmFsc2UpIHtcclxuICAgIC8vICAgdGhpcy5jb25maWd1cmF0aW9ucy52YWx1ZXMgPSBjaGFuZ2VzWydjb25maWd1cmF0aW9ucyddLmN1cnJlbnRWYWx1ZTtcclxuICAgIC8vICAgdGhpcy5yZWxvYWRUYWJsZXMoKTtcclxuICAgIC8vIH1cclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIG5nT25DaGFuZ2VzXHJcblxyXG4gIC8vI3JlZ2lvbiBnZXRGb3JtQnlJRFxyXG4gIGFzeW5jIGdldEZvcm1CeUlEKGlkOiBzdHJpbmcgPSB0aGlzLmZvcm1JRCkge1xyXG4gICAgR2xvYmFsU2VydmljZS5kZWJ1Z0xvZygnbGlzdC1mb3JtLXJlY29yZCAtIGdldEZvcm1CeUlEJywgdGhpcy5mb3JtKTtcclxuXHJcbiAgICBpZiAodGhpcy5mb3JtID09IG51bGwpIHtcclxuICAgICAgY29uc3QgZHluYW1pY01vZHVsZVBhcmFtczogQXJyYXk8RW5kUG9pbnREYXRhUGFyYW1zPiA9XHJcbiAgICAgICAgbmV3IEFycmF5PEVuZFBvaW50RGF0YVBhcmFtcz4oKTtcclxuICAgICAgZHluYW1pY01vZHVsZVBhcmFtcy5wdXNoKHtcclxuICAgICAgICBQYXJhbU5hbWU6IFwiaWRcIixcclxuICAgICAgICBQYXJhbVZhbHVlOiBpZCxcclxuICAgICAgICBQYXJhbVR5cGU6IFBhcmFtVHlwZUVudW1bXCJRdWVyeSBwYXJhbVwiXSxcclxuICAgICAgfSk7XHJcbiAgICAgIGF3YWl0IHRoaXMudXRpbGl0eUhlbHBlclNlcnZpY2UuUnVuRW5kUG9pbnRDYWxsKFxyXG4gICAgICAgIHRoaXMuZW5kUG9pbnRDb25maWd1cmF0aW9uLkZvcm1zLkdldEJ5SURFbmRQb2ludCxcclxuICAgICAgICBkeW5hbWljTW9kdWxlUGFyYW1zLFxyXG4gICAgICAgIChyZXM6IEZvcm0pID0+IHtcclxuICAgICAgICAgIHRoaXMuZm9ybSA9IHJlcztcclxuICAgICAgICAgIHRoaXMuY29uZmlndXJlQ29sdW1ucygpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgKGVycikgPT4geyB9XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLmNvbmZpZ3VyZUNvbHVtbnMoKTtcclxuICAgIH1cclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIGdldEZvcm1CeUlEXHJcblxyXG4gIC8vI3JlZ2lvbiBnZXRSZWNvcmRzQnlGb3JtSURcclxuICAvKipcclxuICAgKiBNZXRvZG8gcGVyIHJlY3VwZXJhcmUgdHV0dGkgaSByZWNvcmQgc2FsdmF0aSBwZXIgdW5hIHBhcnRpY29sYXJlIEZvcm0uXHJcbiAgICogTGEgY2hpYW1hdGEgdmllbmUgZWZmZXR0dWF0YSBzb2xvIHNlIMOoIHN0YXRvIGNvbmZpZ3VyYXRvIGwnZW5kUG9pbnQgZGEgdXNhcmUuXHJcbiAgICogTGEgcmlzcG9zdGEgZGVsbGEgY2hpYW1hdGEgZGV2ZSBlc3NlcmUgdW4gYXJyYXkgZGkgb2dnZXR0aSBkaSB0aXBvIFwiRHluUmVjb3JkXCJcclxuICAgKiBhIHBhcnRpcmUgZGFpIHF1YWxpIHZlbmdvbm8gcmljcmVhdGkgaSBSZWNvcmQgdXNhdGkgbmVsIGNsaWVudC5cclxuICAgKi9cclxuICBhc3luYyBnZXRSZWNvcmRzQnlGb3JtSUQoKSB7XHJcbiAgICAvKipcclxuICAgICAqIHByZW5kZSBsZSByaXNwb3N0ZSBlIGxlIHJlbmRlIHBpYXR0ZSwgYWRhdHRlIGEgZGl2ZW50YXJlIHVuYSByaWdhIGRhIHRhYmVsbGFcclxuICAgICAqIG1ldHRlIHR1dHRlIGxlIHJpc3Bvc3RlIG5lbGxlIHN0cnV0dHVyZSBuZWNlc3NhcmllIHBlciBpbCByZWN1cGVybyBlIGxhIHZpc3VhbGl6emF6aW9uZVxyXG4gICAgICogQHBhcmFtIGFuc3dlcnMgXHJcbiAgICAgKi9cclxuICAgIGNvbnN0IHJlYXJyYW5nZUFuc3dlcnNBbmRQb3B1bGF0ZUxpc3RzID0gKGFuc3dlcnMpID0+IHtcclxuICAgICAgdGhpcy5jb25maWd1cmF0aW9ucy52YWx1ZXMgPSBuZXcgQXJyYXk8UmVjb3JkPigpO1xyXG4gICAgICBhbnN3ZXJzLmZvckVhY2goKGFuc3dlcikgPT4ge1xyXG4gICAgICAgIHZhciB0bXBSZWM6IFJlY29yZCA9IG5ldyBSZWNvcmQoKTtcclxuICAgICAgICB0bXBSZWMgPSBKU09OLnBhcnNlKGFuc3dlci5TZXJpYWxpemVkVmFsdWVzKTtcclxuICAgICAgICB0bXBSZWMuSUQgPSBhbnN3ZXIuSUQ7XHJcbiAgICAgICAgdG1wUmVjLkVudElEID0gYW5zd2VyLkVudElEO1xyXG4gICAgICAgIHRtcFJlYy5WZXJzaW9uID0gYW5zd2VyLlZlcnNpb247XHJcbiAgICAgICAgdG1wUmVjLnVzZXJJRCA9IGFuc3dlci51c2VySUQ7XHJcbiAgICAgICAgdG1wUmVjLkFuc3dlckRhdGUgPSBhbnN3ZXIuQW5zd2VyRGF0ZTtcclxuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb25zLnZhbHVlcy5wdXNoKHRtcFJlYyk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogcHJlcGFyYSBsYSBsaXN0YSBkZWxsZSBjb2xvbm5lIGRhIG1vc3RyYXJlICh1bmEgcGVyIG9nbmkgcmlzcG9zdGEsIHBpw7kgbGEgY29sb25uYSBkZWxsZSBwcm9wcmlldMOgKVxyXG4gICAgICogaW1wb3N0YSBsYSBsaXN0YSBkZWxsZSByaXNwb3N0ZSBkYSB2aXN1YWxpenphcmVcclxuICAgICAqIGxpYmVyYSBsZSB2YXJpYWJpbGkgZGkgY2FyaWNhbWVudG8gcGVyIG1vc3RyYXJlIGkgY29udGVudXRpIGRlbGxhIHZpc3RhXHJcbiAgICAgKi9cclxuICAgIGNvbnN0IG5hbWVDb2x1bW5zQW5kU3RhcnRWaWV3ID0gKCkgPT4ge1xyXG4gICAgICAvL2Rlc3RydXR0dXJhIGwnYXJyYXkgcmlzcG9zdGUgZSBwZXIgb2duaSByaXNwb3N0YSBnZW5lcmEgdW4gZWxlbWVudG8gY29sW2ldXHJcbiAgICAgIHRoaXMuZGlzcGxheWVkQ29sdW1ucyA9IFtcInByb3BlcnR5XCIsIC4uLnRoaXMuY29uZmlndXJhdGlvbnMudmFsdWVzLm1hcCgoXywgaSkgPT4gYGNvbCR7aX1gKV07XHJcbiAgICAgIHRoaXMuZmlsdGVyZWRBbnN3ZXJzID0gdGhpcy5jb25maWd1cmF0aW9ucy52YWx1ZXM7XHJcbiAgICAgIHRoaXMuc2V0TWluTWF4RGF0ZXMoKTtcclxuXHJcbiAgICAgIHRoaXMubG9hZGVkRmlsdGVycyA9IHRydWU7XHJcbiAgICAgIHRoaXMubG9hZGVkVGFibGUgPSB0cnVlO1xyXG4gICAgICBzZXRUaW1lb3V0KChfKSA9PiB7XHJcbiAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3Rvci5kZXRlY3RDaGFuZ2VzKCk7XHJcbiAgICAgIH0sIDApOyAvLyByZWZyZXNoIHVpXHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuY29uZmlndXJhdGlvbnMudmFsdWVzKSB7XHJcbiAgICAgIC8vIHZlbmdvIGRhIHVuJ2FsdHJhIHZpc3VhbGl6emF6aW9uZSBjaGUgaGEgZ2nDoCByZWN1cGVyYXRvIGxlIHJpc3Bvc3RlXHJcbiAgICAgIGNvbnNvbGUubG9nKFwiaExpc3QgLSBnZXRSZWNvcmRzQnlGb3JtSUQgQVwiLCB0aGlzLmNvbmZpZ3VyYXRpb25zKVxyXG4gICAgICBuYW1lQ29sdW1uc0FuZFN0YXJ0VmlldygpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gc29ubyBpbiB1bmEgbnVvdmEgaXN0YW56YSBpbiBjdWkgZGV2byByZWN1cGVyYXJlIGxlIHJpc3Bvc3RlXHJcbiAgICAgIGNvbnNvbGUubG9nKFwiaExpc3QgLSBnZXRSZWNvcmRzQnlGb3JtSUQgQlwiLCB0aGlzLmNvbmZpZ3VyYXRpb25zKVxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHRoaXMuZW5kUG9pbnRDb25maWd1cmF0aW9uICYmXHJcbiAgICAgICAgICB0aGlzLmVuZFBvaW50Q29uZmlndXJhdGlvbi5SZWNvcmRzICYmXHJcbiAgICAgICAgICB0aGlzLmVuZFBvaW50Q29uZmlndXJhdGlvbi5SZWNvcmRzLkdldEJ5Rm9ybUlERW5kUG9pbnRcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGxldCBkeW5hbWljTW9kdWxlUGFyYW1zID0gW1xyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgUGFyYW1OYW1lOiBcIkVudElEXCIsXHJcbiAgICAgICAgICAgICAgUGFyYW1WYWx1ZTogdGhpcy5mb3JtLklELFxyXG4gICAgICAgICAgICAgIFBhcmFtVHlwZTogUGFyYW1UeXBlRW51bVtcIlF1ZXJ5IHBhcmFtXCJdLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgXTtcclxuICAgICAgICAgIGlmICh0aGlzLmNvbmZpZ3VyYXRpb25zLnVzZXJJRCA9PSBudWxsKSB7XHJcbiAgICAgICAgICAgIC8vIG5vbiBobyBzcGVjaWZpY2F0byB1biB1dGVudGVcclxuICAgICAgICAgICAgLy8gdmVkbyB0dXR0ZSBsZSByaXNwb3N0ZSBkZWwgbW9kdWxvXHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudXRpbGl0eUhlbHBlclNlcnZpY2UuUnVuRW5kUG9pbnRDYWxsKFxyXG4gICAgICAgICAgICAgIHRoaXMuZW5kUG9pbnRDb25maWd1cmF0aW9uLlJlY29yZHMuR2V0QnlGb3JtSURFbmRQb2ludCxcclxuICAgICAgICAgICAgICBkeW5hbWljTW9kdWxlUGFyYW1zLFxyXG4gICAgICAgICAgICAgIChyZXM6IEFycmF5PER5blJlY29yZD4pID0+IHtcclxuICAgICAgICAgICAgICAgIHJlYXJyYW5nZUFuc3dlcnNBbmRQb3B1bGF0ZUxpc3RzKHJlcyk7XHJcbiAgICAgICAgICAgICAgICBuYW1lQ29sdW1uc0FuZFN0YXJ0VmlldygpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIGNvbm9zY28gbCd1dGVudGVcclxuICAgICAgICAgICAgLy8gdm9nbGlvIHNvbGFtZW50ZSBsZSBzdWUgcmlzcG9zdGVcclxuICAgICAgICAgICAgZHluYW1pY01vZHVsZVBhcmFtcy5wdXNoKFxyXG4gICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIFBhcmFtTmFtZTogXCJVc2VySURcIixcclxuICAgICAgICAgICAgICAgIFBhcmFtVmFsdWU6IHRoaXMuY29uZmlndXJhdGlvbnMudXNlcklELFxyXG4gICAgICAgICAgICAgICAgUGFyYW1UeXBlOiBQYXJhbVR5cGVFbnVtW1wiUXVlcnkgcGFyYW1cIl0sXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudXRpbGl0eUhlbHBlclNlcnZpY2UuUnVuRW5kUG9pbnRDYWxsKFxyXG4gICAgICAgICAgICAgIHRoaXMuZW5kUG9pbnRDb25maWd1cmF0aW9uLlJlY29yZHMuR2V0QWxsQnlFbnRBbmRVc2VySURFbmRQb2ludCxcclxuICAgICAgICAgICAgICBkeW5hbWljTW9kdWxlUGFyYW1zLFxyXG4gICAgICAgICAgICAgIChyZXM6IEFycmF5PER5blJlY29yZD4pID0+IHtcclxuICAgICAgICAgICAgICAgIHJlYXJyYW5nZUFuc3dlcnNBbmRQb3B1bGF0ZUxpc3RzKHJlcyk7XHJcbiAgICAgICAgICAgICAgICBuYW1lQ29sdW1uc0FuZFN0YXJ0VmlldygpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgY29uc29sZS5lcnJvcignZXhjZXB0aW9uJywgZSlcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuICAvLyNlbmRyZWdpb24gZ2V0UmVjb3Jkc0J5Rm9ybUlEXHJcblxyXG5cclxuICAvLyNyZWdpb24gY29uZmlndXJlQ29sdW1uc1xyXG4gIC8qKlxyXG4gICAqIE1ldG9kbyBwZXIgY29uZmlndXJhcmUgbGUgY29sb25uZSBkZWxsYSBlcXAtdGFibGUuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjb25maWd1cmVDb2x1bW5zKCkge1xyXG4gICAgdGhpcy5jb2x1bW5zID0gW1xyXG4gICAgICB7XHJcbiAgICAgICAga2V5OiBcImFjdGlvblwiLFxyXG4gICAgICAgIGRpc3BsYXk6IFwiXCIsXHJcbiAgICAgICAgdHlwZTogVHlwZUNvbHVtbi5NZW51QWN0aW9uLFxyXG4gICAgICAgIGJ1dHRvbk1lbnVJY29uOiBcIm1vcmVfdmVydFwiLFxyXG4gICAgICAgIHN0eWxlczogeyBmbGV4OiBcIjAgMCA2JVwiIH0sXHJcbiAgICAgICAgYWN0aW9uczogW10sXHJcbiAgICAgIH0sXHJcbiAgICBdO1xyXG5cclxuICAgIGlmICh0aGlzLmRlZmF1bHRMaXN0QWN0aW9ucy52aWV3ID09IHRydWUpIHtcclxuICAgICAgdGhpcy5jb2x1bW5zXHJcbiAgICAgICAgLmZpbmQoKGMpID0+IGMua2V5ID09PSBcImFjdGlvblwiKVxyXG4gICAgICAgIC5hY3Rpb25zLnB1c2goe1xyXG4gICAgICAgICAgbmFtZTogXCJWaXN1YWxpenphXCIsXHJcbiAgICAgICAgICBpY29uOiBcImluZm9cIixcclxuICAgICAgICAgIGZuOiAoZWxlbWVudCwgaW5kZXgsIGNvbCkgPT4gdGhpcy52aWV3UmVjb3JkKGVsZW1lbnQpLFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgaWYgKHRoaXMuZGVmYXVsdExpc3RBY3Rpb25zLmVkaXQgPT0gdHJ1ZSkge1xyXG4gICAgICB0aGlzLmNvbHVtbnNcclxuICAgICAgICAuZmluZCgoYykgPT4gYy5rZXkgPT09IFwiYWN0aW9uXCIpXHJcbiAgICAgICAgLmFjdGlvbnMucHVzaCh7XHJcbiAgICAgICAgICBuYW1lOiBcIk1vZGlmaWNhXCIsXHJcbiAgICAgICAgICBpY29uOiBcImVkaXRcIixcclxuICAgICAgICAgIGZuOiAoZWxlbWVudCwgaW5kZXgsIGNvbCkgPT4gdGhpcy52aWV3T3JFZGl0UmVjb3JkKGVsZW1lbnQsIGZhbHNlKSxcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIGlmICh0aGlzLmRlZmF1bHRMaXN0QWN0aW9ucy5kdXBsaWNhdGUgPT0gdHJ1ZSkge1xyXG4gICAgICAvKnRoaXMuY29sdW1uc1xyXG4gICAgICAgIC5maW5kKChjKSA9PiBjLmtleSA9PT0gXCJhY3Rpb25cIilcclxuICAgICAgICAuYWN0aW9ucy5wdXNoKHtcclxuICAgICAgICAgIG5hbWU6IFwiRHVwbGljYVwiLFxyXG4gICAgICAgICAgaWNvbjogXCJmaWxlX2NvcHlcIixcclxuICAgICAgICAgIGZuOiAoZWxlbWVudCwgaW5kZXgsIGNvbCkgPT4gdGhpcy5kdXBsaWNhdGVSZWNvcmQoZWxlbWVudCksXHJcbiAgICAgICAgfSk7Ki9cclxuICAgIH1cclxuICAgIGlmICh0aGlzLmRlZmF1bHRMaXN0QWN0aW9ucy5kZWxldGUgPT0gdHJ1ZSkge1xyXG4gICAgICB0aGlzLmNvbHVtbnNcclxuICAgICAgICAuZmluZCgoYykgPT4gYy5rZXkgPT09IFwiYWN0aW9uXCIpXHJcbiAgICAgICAgLmFjdGlvbnMucHVzaCh7XHJcbiAgICAgICAgICBuYW1lOiBcIkVsaW1pbmFcIixcclxuICAgICAgICAgIGljb246IFwiZGVsZXRlXCIsXHJcbiAgICAgICAgICBmbjogKGVsZW1lbnQsIGluZGV4LCBjb2wpID0+IHRoaXMuZGVsZXRlUmVjb3JkKGVsZW1lbnQpLFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuZXh0ZXJuYWxCdXR0b25zLmZvckVhY2goKGJ1dHRvbikgPT4ge1xyXG4gICAgICB0aGlzLmNvbHVtbnNcclxuICAgICAgICAuZmluZCgoYykgPT4gYy5rZXkgPT09IFwiYWN0aW9uXCIpXHJcbiAgICAgICAgLmFjdGlvbnMucHVzaCh7XHJcbiAgICAgICAgICBuYW1lOiBidXR0b24udGV4dCxcclxuICAgICAgICAgIGljb246IGJ1dHRvbi5pY29uLFxyXG4gICAgICAgICAgZm46IChlbGVtZW50LCBpbmRleCwgY29sKSA9PiBidXR0b24uZm4oKSxcclxuICAgICAgICB9KTtcclxuICAgIH0pO1xyXG5cclxuICAgIHRoaXMuY3JlYXRlQWRkaXRpb25hbEFjdGlvbnMoKTtcclxuICAgIHRoaXMuY3JlYXRlQ29sdW1uc0Zyb21Gb3JtRmllbGRzKCk7XHJcbiAgICB0aGlzLmdldFJlY29yZHNCeUZvcm1JRCgpO1xyXG4gIH1cclxuICAvLyNlbmRyZWdpb24gY29uZmlndXJlQ29sdW1uc1xyXG5cclxuICAvLyNyZWdpb24gY3JlYXRlQWRkaXRpb25hbEFjdGlvbnNcclxuICAvKipcclxuICAgKiBNZXRvZG8gcGVyIGFnZ2l1bmdlcmUgbmVsbGEgY29sb25uYSBcImFjdGlvblwiIGRlbGxhIGVxcC10YWJsZSBsZSBhemlvbmkgc3VpIHJlY29yZFxyXG4gICAqIGRlZmluaXRlIGRhbGwndXRlbnRlIGFsbCdpbnRlcm5vIGRlbGxhIEZvcm0uXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjcmVhdGVBZGRpdGlvbmFsQWN0aW9ucygpIHtcclxuICAgIEdsb2JhbFNlcnZpY2UuZGVidWdMb2coJ2xpc3QtZm9ybS1yZWNvcmQgLSBjcmVhdGVBZGRpdGlvbmFsQWN0aW9ucycsIHRoaXMuZm9ybSk7XHJcblxyXG4gICAgaWYgKHRoaXMuZm9ybS5BY3Rpb25zT25SZWNvcmQgJiYgdGhpcy5mb3JtLkFjdGlvbnNPblJlY29yZC5sZW5ndGggPiAwKSB7XHJcbiAgICAgIHRoaXMuZm9ybS5BY3Rpb25zT25SZWNvcmQuc29ydCgoYSwgYikgPT5cclxuICAgICAgICBhLk9yZGluYWxQb3NpdGlvbiA+IGIuT3JkaW5hbFBvc2l0aW9uXHJcbiAgICAgICAgICA/IDFcclxuICAgICAgICAgIDogYi5PcmRpbmFsUG9zaXRpb24gPiBhLk9yZGluYWxQb3NpdGlvblxyXG4gICAgICAgICAgICA/IC0xXHJcbiAgICAgICAgICAgIDogMFxyXG4gICAgICApLmZvckVhY2goKGFjdGlvbikgPT4ge1xyXG4gICAgICAgIHRoaXMuY29sdW1uc1xyXG4gICAgICAgICAgLmZpbmQoKGMpID0+IGMua2V5ID09PSBcImFjdGlvblwiKVxyXG4gICAgICAgICAgLmFjdGlvbnMucHVzaCh7XHJcbiAgICAgICAgICAgIG5hbWU6IGFjdGlvbi5OYW1lLFxyXG4gICAgICAgICAgICBpY29uOiBhY3Rpb24uSWNvbixcclxuICAgICAgICAgICAgZm46IChlbGVtZW50LCBpbmRleCwgY29sKSA9PiB7XHJcbiAgICAgICAgICAgICAgY29uc3QgcmVjID0gZWxlbWVudDtcclxuICAgICAgICAgICAgICBjb25zdCBjdHggPSBVdGlsaXR5SGVscGVyU2VydmljZS5jb250ZXh0O1xyXG4gICAgICAgICAgICAgIGV2YWwoYWN0aW9uLkFjdGlvbik7XHJcbiAgICAgICAgICAgICAgLy8gVE9ETzogc2FsdmFyZSBsZSBtb2RpZmljaGVcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgIH0pO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIGNyZWF0ZUFkZGl0aW9uYWxBY3Rpb25zXHJcblxyXG5cclxuICAvLyNyZWdpb24gY3JlYXRlQ29sdW1uc0Zyb21Gb3JtRmllbGRzXHJcbiAgLyoqXHJcbiAgICogTWV0b2RvIHBlciBjcmVhcmUgbGEgY29uZmlndXJhemlvbmUgZGVsbGUgY29sb25uZSBwZXIgbGEgZXFwLXRhYmxlLlxyXG4gICAqIEluZGl2aWR1YSBpIEJhc2VGaWVsZCBkYSBtb3N0cmFyZSBlIGxpIHVzYSBwZXIgY3JlYXJlIGxlIENvbmZpZ0NvbHVtbi5cclxuICAgKiBMZSBjb2xvbm5lIHZlbmdvbm8gY3JlYXRlIHBlciBpIEJhc2VGaWVsZCBjb24gaWwgZmxhZyBJbkxpc3RWaWV3IGEgVFJVRVxyXG4gICAqIG9wcHVyZSwgbmVsIGNhc28gbm9uIHNpYW5vIHN0YXRpIHNwZWNpZmljYXRpIGkgY2FtcGkgZGEgdmlzdWFsaXp6YXJlLFxyXG4gICAqIHNlbGV6aW9uYSBpIHByaW1pIDYuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjcmVhdGVDb2x1bW5zRnJvbUZvcm1GaWVsZHMoKSB7XHJcbiAgICBHbG9iYWxTZXJ2aWNlLmRlYnVnTG9nKCdsaXN0LWZvcm0tcmVjb3JkIC0gY3JlYXRlQ29sdW1uc0Zyb21Gb3JtRmllbGRzJywgdGhpcy5mb3JtKTtcclxuXHJcbiAgICB2YXIgZmllbGRzRm9yQ29sdW1uczogQXJyYXk8QmFzZUZpZWxkPjtcclxuICAgIGZpZWxkc0ZvckNvbHVtbnMgPSB0aGlzLmZvcm0uRmllbGRzLmZpbHRlcigoZikgPT4ge1xyXG4gICAgICBpZiAoZi5BbnN3ZXJTdHlsZSkge1xyXG4gICAgICAgIHJldHVybiBmLkFuc3dlclN0eWxlLkluTGlzdFZpZXdcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gZi5Jbkxpc3RWaWV3O1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICAgIGZpZWxkc0ZvckNvbHVtbnNcclxuICAgICAgLnNvcnQoKGEsIGIpID0+XHJcbiAgICAgICAgYS5PcmRpbmFsUG9zaXRpb24gPiBiLk9yZGluYWxQb3NpdGlvblxyXG4gICAgICAgICAgPyAxXHJcbiAgICAgICAgICA6IGIuT3JkaW5hbFBvc2l0aW9uID4gYS5PcmRpbmFsUG9zaXRpb25cclxuICAgICAgICAgICAgPyAtMVxyXG4gICAgICAgICAgICA6IDBcclxuICAgICAgKVxyXG4gICAgICAuZm9yRWFjaCgoZmllbGQpID0+IHtcclxuICAgICAgICAvLyB0aGlzLmNvbHVtbnMucHVzaCh0aGlzLmNyZWF0ZUZpZWxkQ29sdW1uKGZpZWxkKSk7XHJcbiAgICAgICAgdGhpcy5wcm9wZXJ0aWVzLnB1c2goeyBsYWJlbDogZmllbGQuTGFiZWwsIHR5cGU6IGZpZWxkLkZpZWxkVHlwZSwgY29uZmlnOiBmaWVsZCB9KTtcclxuICAgICAgICB0aGlzLnByb3BlcnRpZXNMYWJlbFtmaWVsZC5MYWJlbF0gPSBmaWVsZC5EZXNjcmlwdGlvbjtcclxuICAgICAgfSk7XHJcbiAgICB0aGlzLnNlbGVjdGVkUHJvcGVydGllcyA9IHRoaXMucHJvcGVydGllcztcclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIGNyZWF0ZUNvbHVtbnNGcm9tRm9ybUZpZWxkc1xyXG5cclxuICAvLyNyZWdpb24gY3JlYXRlRmllbGRDb2x1bW5cclxuICAvKipcclxuICAgKiBNZXRvZG8gcGVyIGNyZWFyZSBsJ29nZ2V0dG8gQ29uZmlndXJlQ29sdW1uIGNoZSByYXBwcmVzZW50YSBpbCBCYXNlRmllbGQgcGFzc2F0byBpbiBpbnB1dC5cclxuICAgKiBAcGFyYW0gZmllbGQgQmFzZUZpZWxkIHBlciBjdWkgY3JlYXJlIGxhIGNvbG9ubmEgbmVsbGEgZXFwLXRhYmxlXHJcbiAgICogQHJldHVybnMgUmVzdGl0dWlzY2UgdW5hIENvbmZpZ0NvbHVtbiBwZXIgbGEgZXFwLXRhYmxlXHJcbiAgICovXHJcbiAgLy8gcHJpdmF0ZSBjcmVhdGVGaWVsZENvbHVtbihmaWVsZDogQmFzZUZpZWxkKTogQ29uZmlnQ29sdW1uIHtcclxuICAvLyAgIHZhciBjb2x1bW46IENvbmZpZ0NvbHVtbiA9IHsga2V5OiBmaWVsZC5OYW1lLCBkaXNwbGF5OiBmaWVsZC5MYWJlbCB9O1xyXG4gIC8vICAgc3dpdGNoIChmaWVsZC5GaWVsZFR5cGUpIHtcclxuICAvLyAgICAgY2FzZSBGaWVsZFR5cGVFbnVtW1wiQm9vbGVhbm9cIl06XHJcbiAgLy8gICAgICAgY29sdW1uLnR5cGUgPSBUeXBlQ29sdW1uLkJvb2xlYW47XHJcbiAgLy8gICAgICAgY29sdW1uLmJvb2xlYW5WYWx1ZXMgPSB7XHJcbiAgLy8gICAgICAgICBmYWxzZTogJzxpIGNsYXNzPVwiZmEgZmEtdGltZXMgZXJyb3ItY29sb3JcIj48L2k+JyxcclxuICAvLyAgICAgICAgIHRydWU6ICc8aSBjbGFzcz1cImZhIGZhLWNoZWNrIHN1Y2Nlc3MtY29sb3JcIj48L2k+JyxcclxuICAvLyAgICAgICB9O1xyXG4gIC8vICAgICAgIGNvbHVtbi5zdHlsZXMgPSB7XHJcbiAgLy8gICAgICAgICBmbGV4OiBcIjAgMCA3JVwiLFxyXG4gIC8vICAgICAgICAgY2VsbEFsaWdubWVudDogQ2VsbEFsaWdubWVudEVudW0uQ0VOVEVSLFxyXG4gIC8vICAgICAgIH07XHJcbiAgLy8gICAgICAgYnJlYWs7XHJcbiAgLy8gICAgIGNhc2UgRmllbGRUeXBlRW51bVtcIkRhdGEgZS9vIG9yYVwiXTpcclxuICAvLyAgICAgICBpZiAoXHJcbiAgLy8gICAgICAgICAoZmllbGQgYXMgRGF0ZUZpZWxkKS5Jc09ubHlEYXRlICE9IERhdGVUaW1lVHlwZUVudW1bXCJTb2xvIG9yYXJpb1wiXVxyXG4gIC8vICAgICAgICkge1xyXG4gIC8vICAgICAgICAgY29sdW1uLnR5cGUgPSBUeXBlQ29sdW1uLkRhdGU7XHJcbiAgLy8gICAgICAgICBpZiAoXHJcbiAgLy8gICAgICAgICAgIChmaWVsZCBhcyBEYXRlRmllbGQpLklzT25seURhdGUgPT0gRGF0ZVRpbWVUeXBlRW51bVtcIkRhdGEgZSBvcmFcIl1cclxuICAvLyAgICAgICAgICkge1xyXG4gIC8vICAgICAgICAgICBjb2x1bW4uZm9ybWF0ID0gXCJkZC9NTS95eXl5IEhIOm1tXCI7XHJcbiAgLy8gICAgICAgICB9IGVsc2UgaWYgKFxyXG4gIC8vICAgICAgICAgICAoZmllbGQgYXMgRGF0ZUZpZWxkKS5Jc09ubHlEYXRlID09IERhdGVUaW1lVHlwZUVudW1bXCJTb2xvIGRhdGFcIl1cclxuICAvLyAgICAgICAgICkge1xyXG4gIC8vICAgICAgICAgICBjb2x1bW4uZm9ybWF0ID0gKGZpZWxkIGFzIERhdGVGaWVsZCkuRGF0ZUZvcm1hdFxyXG4gIC8vICAgICAgICAgICAgID8gKGZpZWxkIGFzIERhdGVGaWVsZCkuRGF0ZUZvcm1hdC5yZXBsYWNlKFwiRERcIiwgXCJkZFwiKVxyXG4gIC8vICAgICAgICAgICAgIDogXCJkZC9NTS95eXl5XCI7XHJcbiAgLy8gICAgICAgICB9XHJcbiAgLy8gICAgICAgfVxyXG4gIC8vICAgICAgIGJyZWFrO1xyXG4gIC8vICAgICBjYXNlIEZpZWxkVHlwZUVudW1bXCJDYW1wbyBudW1lcmljb1wiXTpcclxuICAvLyAgICAgICBpZiAoKGZpZWxkIGFzIE51bWVyaWNGaWVsZCkuQ3VycmVuY3lTeW1ib2wpIHtcclxuICAvLyAgICAgICAgIGNvbHVtbi5udW1iZXJQaXBlID0gTnVtYmVyQ29sdW1uUGlwZS5DVVJSRU5DWTtcclxuICAvLyAgICAgICAgIGNvbHVtbi5jdXJyZW5jeVBpcGVDb2RlID0gKGZpZWxkIGFzIE51bWVyaWNGaWVsZCkuQ3VycmVuY3lTeW1ib2w7XHJcbiAgLy8gICAgICAgfSBlbHNlIGlmICghKGZpZWxkIGFzIE51bWVyaWNGaWVsZCkuSXNJbnRlZ2VyKSB7XHJcbiAgLy8gICAgICAgICBjb2x1bW4ubnVtYmVyUGlwZSA9IE51bWJlckNvbHVtblBpcGUuREVDSU1BTDtcclxuICAvLyAgICAgICB9XHJcbiAgLy8gICAgICAgYnJlYWs7XHJcbiAgLy8gICAgIGNhc2UgRmllbGRUeXBlRW51bVtcIkFsbGVnYXRvXCJdOlxyXG4gIC8vICAgICBjYXNlIEZpZWxkVHlwZUVudW1bXCJJbW1hZ2luZVwiXTpcclxuXHJcbiAgLy8gICAgICAgLypcclxuICAvLyAgICAgICAgIGNvbHVtbi52YWx1ZSA9IChlbGVtZW50OiBSZWNvcmQpID0+IHtcclxuICAvLyAgICAgICAgICAgaWYgKFxyXG4gIC8vICAgICAgICAgICAgIChmaWVsZCBhcyBBdHRhY2htZW50RmllbGQpLklzTXVsdGlBdHRhY2ggfHxcclxuICAvLyAgICAgICAgICAgICAoKGZpZWxkIGFzIEltYWdlRmllbGQpLkF0dGFjaERlZmluaXRpb24gJiZcclxuICAvLyAgICAgICAgICAgICAgIChmaWVsZCBhcyBJbWFnZUZpZWxkKS5BdHRhY2hEZWZpbml0aW9uLklzTXVsdGlBdHRhY2gpXHJcbiAgLy8gICAgICAgICAgICkge1xyXG4gIC8vICAgICAgICAgICAgIHJldHVybiBlbGVtZW50W2ZpZWxkLk5hbWVdICE9IG51bGwgJiYgZWxlbWVudFtmaWVsZC5OYW1lXS5sZW5ndGggPiAwXHJcbiAgLy8gICAgICAgICAgICAgICA/IChlbGVtZW50W2ZpZWxkLk5hbWVdIGFzIEFycmF5PElBdHRhY2htZW50RFRPPilcclxuICAvLyAgICAgICAgICAgICAgICAgICAubWFwKChhKSA9PiBhLkZpbGVOYW1lKVxyXG4gIC8vICAgICAgICAgICAgICAgICAgIC5qb2luKFwiLCBcIilcclxuICAvLyAgICAgICAgICAgICAgIDogbnVsbDtcclxuICAvLyAgICAgICAgICAgfSBlbHNlIHtcclxuICAvLyAgICAgICAgICAgICByZXR1cm4gZWxlbWVudFtmaWVsZC5OYW1lXSAhPSBudWxsICYmIGVsZW1lbnRbZmllbGQuTmFtZV0ubGVuZ3RoID4gMFxyXG4gIC8vICAgICAgICAgICAgICAgPyAoZWxlbWVudFtmaWVsZC5OYW1lXSBhcyBBcnJheTxJQXR0YWNobWVudERUTz4pWzBdLkZpbGVOYW1lXHJcbiAgLy8gICAgICAgICAgICAgICA6IG51bGw7XHJcbiAgLy8gICAgICAgICAgIH1cclxuICAvLyAgICAgICAgIH07XHJcbiAgLy8gICAgICAgICBjb2x1bW4uaXNTb3J0YWJsZSA9IGZhbHNlO1xyXG4gIC8vICAgICAgICAgY29sdW1uLmlzU2VhcmNoYWJsZSA9IGZhbHNlO1xyXG4gIC8vICAgICAgICovXHJcblxyXG4gIC8vICAgICAgIGJyZWFrO1xyXG4gIC8vICAgICBjYXNlIEZpZWxkVHlwZUVudW1bXCJFbGVuY28gZ2VuZXJpY29cIl06XHJcbiAgLy8gICAgICAgY29sdW1uLnZhbHVlID0gKGVsZW1lbnQ6IFJlY29yZCkgPT4ge1xyXG4gIC8vICAgICAgICAgaWYgKChmaWVsZCBhcyBMaXN0VmFsdWVGaWVsZCkuSXNNdWx0aUNob2ljaGUpIHtcclxuICAvLyAgICAgICAgICAgaWYgKCFlbGVtZW50W2ZpZWxkLk5hbWVdIHx8IGVsZW1lbnRbZmllbGQuTmFtZV0ubGVuZ3RoID09IDApIHtcclxuICAvLyAgICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAvLyAgICAgICAgICAgfSBlbHNlIHtcclxuICAvLyAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LmtleXMoKGZpZWxkIGFzIExpc3RWYWx1ZUZpZWxkKS5WYWx1ZVBhaXJzKVxyXG4gIC8vICAgICAgICAgICAgICAgLmZpbHRlcigoaykgPT5cclxuICAvLyAgICAgICAgICAgICAgICAgZWxlbWVudFtmaWVsZC5OYW1lXS5pbmNsdWRlcyhcclxuICAvLyAgICAgICAgICAgICAgICAgICAoZmllbGQgYXMgTGlzdFZhbHVlRmllbGQpLlZhbHVlUGFpcnNba11cclxuICAvLyAgICAgICAgICAgICAgICAgKVxyXG4gIC8vICAgICAgICAgICAgICAgKVxyXG4gIC8vICAgICAgICAgICAgICAgLmpvaW4oXCIsIFwiKTtcclxuICAvLyAgICAgICAgICAgfVxyXG4gIC8vICAgICAgICAgfSBlbHNlIHtcclxuICAvLyAgICAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKChmaWVsZCBhcyBMaXN0VmFsdWVGaWVsZCkuVmFsdWVQYWlycykuZmluZChcclxuICAvLyAgICAgICAgICAgICAoaykgPT5cclxuICAvLyAgICAgICAgICAgICAgIChmaWVsZCBhcyBMaXN0VmFsdWVGaWVsZCkuVmFsdWVQYWlyc1trXSA9PSBlbGVtZW50W2ZpZWxkLk5hbWVdXHJcbiAgLy8gICAgICAgICAgICk7XHJcbiAgLy8gICAgICAgICB9XHJcbiAgLy8gICAgICAgfTtcclxuICAvLyAgICAgICBjb2x1bW4uaXNTb3J0YWJsZSA9IGZhbHNlO1xyXG4gIC8vICAgICAgIGNvbHVtbi5pc1NlYXJjaGFibGUgPSBmYWxzZTtcclxuICAvLyAgICAgICBicmVhaztcclxuICAvLyAgICAgY2FzZSBGaWVsZFR5cGVFbnVtW1wiTG9va3VwXCJdOlxyXG4gIC8vICAgICAgIC8vIFRPRE9cclxuICAvLyAgICAgICBicmVhaztcclxuICAvLyAgIH1cclxuICAvLyAgIHJldHVybiBjb2x1bW47XHJcbiAgLy8gfVxyXG4gIC8vI2VuZHJlZ2lvbiBjcmVhdGVGaWVsZENvbHVtblxyXG5cclxuICAvLyNyZWdpb24gdmlld1JlY29yZFxyXG4gIHZpZXdSZWNvcmQocmVjb3JkOiBSZWNvcmQpIHtcclxuICAgIHRoaXMub25WaWV3UmVjb3JkLmVtaXQocmVjb3JkKTtcclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIHZpZXdSZWNvcmRcclxuXHJcbiAgLyoqXHJcbiAgICogTWV0b2RvIGNoZSBzY2F0ZW5hIGwnZXZlbnRvIGRpIE91dHB1dCBwZXIgbW9zdHJhcmUgbyBtb2RpZmljYXJlIGlsIHJlY29yZFxyXG4gICAqIHNlbGV6aW9uYXRvIHN1bGxhIGVxcC10YWJsZS5cclxuICAgKiBAcGFyYW0gcmVjb3JkIFJlY29yZCBkYSB2aXN1YWxpenphcmUgbyBtb2RpZmljYXJlIHNlbGV6aW9uYXRvIHN1bGxhIGVxcC10YWJsZS5cclxuICAgKiBAcGFyYW0gb25seVZpZXcgU2UgVFJVRSB2aWVuZSBtb3N0cmF0byBpbCBjb21wb25lbnRlIGFkZC1mb3JtLXJlY29yZCBpbiBzb2xhIGxldHR1cmEuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSB2aWV3T3JFZGl0UmVjb3JkKHJlY29yZDogUmVjb3JkLCBvbmx5VmlldzogYm9vbGVhbikge1xyXG4gICAgdGhpcy5vbkFkZFZpZXdFZGl0UmVjb3JkLmVtaXQoeyByZWNvcmQsIG9ubHlWaWV3IH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogTWV0b2RvIHBlciBlbGltaW5hcmUgdW4gcmVjb3JkIGRhbGxhIGxpc3RhLlxyXG4gICAqIEBwYXJhbSByZWNvcmQgUmVjb3JkIGRhIGVsaW1pbmFyZSBzZWxlemlvbmF0byBzdWxsYSBlcXAtdGFibGUuXHJcbiAgICovXHJcbiAgZGVsZXRlUmVjb3JkKHJlY29yZDogUmVjb3JkKSB7XHJcbiAgICB0aGlzLm9uRGVsZXRlUmVjb3JkLmVtaXQocmVjb3JkKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIE1ldG9kbyBwZXIgcmljYXJpY2FyZSBpIGRhdGkgZGVsbGEgZXFwLXRhYmxlLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgcmVsb2FkVGFibGVzKCkge1xyXG4gICAgaWYgKHRoaXMudGFibGVSZWNvcmRzKSB7XHJcbiAgICAgIHRoaXMudGFibGVSZWNvcmRzLnJlbG9hZERhdGF0YWJsZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8jcmVnaW9uIG9uU2VsZWN0aW9uQ2hhbmdlXHJcbiAgLyoqXHJcbiAgICogRnVuemlvbmUgY2hlIHZpZW5lIGNoaWFtYXRhIGFsIGNhbWJpbyBkaSBzZWxlemlvbmUgZGVpIHBhcmFtZXRyaSBkYSBtb3N0cmFyZVxyXG4gICAqIGFnZ2lvcm5hIGxhIGxpc3RhIGRlbGxlIHByb3ByaWV0w6Agc2VsZXppb25hdGUgY2hlIGdlc3Rpc2NlIGxlIHJpZ2hlIG1vc3RyYXRlIHBlciBvZ25pIHJpc3Bvc3RhXHJcbiAgICogQHBhcmFtIHNlbGVjdGVkUHJvcGVydGllcyBcclxuICAgKi9cclxuICBvblNlbGVjdGlvbkNoYW5nZShzZWxlY3RlZFByb3BlcnRpZXMpIHtcclxuICAgIGNvbnNvbGUubG9nKHNlbGVjdGVkUHJvcGVydGllcy52YWx1ZSk7XHJcbiAgICBpZiAoc2VsZWN0ZWRQcm9wZXJ0aWVzLnZhbHVlLmxlbmd0aCA+IDApIHtcclxuICAgICAgdGhpcy5zZWxlY3RlZFByb3BlcnRpZXMgPSBzZWxlY3RlZFByb3BlcnRpZXMudmFsdWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLnNlbGVjdGVkUHJvcGVydGllcyA9IHRoaXMucHJvcGVydGllcztcclxuICAgIH1cclxuICAgIGNvbnNvbGUubG9nKHRoaXMuc2VsZWN0ZWRQcm9wZXJ0aWVzKTtcclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIG9uU2VsZWN0aW9uQ2hhbmdlXHJcblxyXG4gIC8vI3JlZ2lvbiBmaWx0ZXJEYXRhQW5zd2Vyc1xyXG4gIC8qKlxyXG4gICAqIGZ1bnppb25lIGNoZSBmaWx0cmEgbGUgcmlzcG9zdGUgaW4gYmFzZSBhbCByYW5nZSBkaSBkYXRlIGJhc2FuZG9zaSBzdWwgY2FtcG8gZmlzc28gQW5zd2VyRGF0ZSBwZXIgaWwgcGFyYWdvbmVcclxuICAgKi9cclxuICBmaWx0ZXJEYXRhQW5zd2VycygpIHtcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLmZpbHRlcmVkQW5zd2VycyA9IFtdO1xyXG5cclxuICAgICAgdGhpcy5tYXhEYXRlLnNldEhvdXJzKDIzLCA1OSwgNTksIDU5KTtcclxuXHJcbiAgICAgIHRoaXMuY29uZmlndXJhdGlvbnMudmFsdWVzLmZvckVhY2goKHZhbHVlKSA9PiB7XHJcbiAgICAgICAgaWYgKG5ldyBEYXRlKHZhbHVlLkFuc3dlckRhdGUpID49IHRoaXMubWluRGF0ZSAmJiBuZXcgRGF0ZSh2YWx1ZS5BbnN3ZXJEYXRlKSA8PSB0aGlzLm1heERhdGUpIHtcclxuXHJcbiAgICAgICAgICB0aGlzLmZpbHRlcmVkQW5zd2Vycy5wdXNoKHZhbHVlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgICB0aGlzLmRpc3BsYXllZENvbHVtbnMgPSBbXCJwcm9wZXJ0eVwiLCAuLi50aGlzLmZpbHRlcmVkQW5zd2Vycy5tYXAoKF8sIGkpID0+IGBjb2wke2l9YCldO1xyXG5cclxuICAgICAgLy8gdGhpcy5sb2FkZWRUYWJsZSA9IHRydWU7XHJcblxyXG4gICAgfSwgMTAwKTtcclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIGZpbHRlckRhdGFBbnN3ZXJzXHJcblxyXG4gIC8vI3JlZ2lvbiBzZXRNaW5NYXhEYXRlc1xyXG4gIC8vIEZ1bnppb25lIHBlciBvdHRlbmVyZSBsYSBkYXRhIHBpw7kgcmVjZW50ZSBlIHF1ZWxsYSBwacO5IHZlY2NoaWFcclxuICBzZXRNaW5NYXhEYXRlcygpIHtcclxuICAgIC8vIENvbnZlcnRvIGxlIGRhdGUgZGkgQW5zd2VyRGF0ZSBpbiBvZ2dldHRpIERhdGUgZSBvcmRpbm9cclxuICAgIGNvbnN0IGRhdGVzID0gdGhpcy5jb25maWd1cmF0aW9ucy52YWx1ZXMubWFwKHZhbHVlID0+IG5ldyBEYXRlKHZhbHVlLkFuc3dlckRhdGUpKTtcclxuXHJcbiAgICAvLyBUcm92byBsYSBkYXRhIHBpw7kgcmVjZW50ZSAobWF4KSBlIGxhIHBpw7kgdmVjY2hpYSAobWluKVxyXG4gICAgdGhpcy5taW5EYXRlID0gbmV3IERhdGUoTWF0aC5taW4oLi4uZGF0ZXMubWFwKGRhdGUgPT4gZGF0ZS5nZXRUaW1lKCkpKSk7XHJcbiAgICB0aGlzLm1heERhdGUgPSBuZXcgRGF0ZShNYXRoLm1heCguLi5kYXRlcy5tYXAoZGF0ZSA9PiBkYXRlLmdldFRpbWUoKSkpKTtcclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIHNldE1pbk1heERhdGVzXHJcblxyXG4gIC8vI3JlZ2lvbiBwcmludFZhbHVlXHJcbiAgcHJpbnRWYWx1ZShmaWVsZFR5cGUsIHZhbHVlLCBmaWVsZGNvbmZpZykge1xyXG4gICAgLy8gcmV0dXJuIHZhbHVlO1xyXG4gICAgLy8gUFJFUEFSTyBJTCBWQUxVRVBBSVJTXHJcblxyXG4gICAgc3dpdGNoIChmaWVsZFR5cGUpIHtcclxuICAgICAgY2FzZSBGaWVsZFR5cGVFbnVtW1wiRWxlbmNvIGdlbmVyaWNvXCJdOiB7XHJcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9O1xyXG4gICAgICBjYXNlIEZpZWxkVHlwZUVudW1bXCJDYW1wbyBudW1lcmljb1wiXToge1xyXG4gICAgICAgIGlmICgoPE51bWVyaWNGaWVsZD5maWVsZGNvbmZpZykuSXNJbnRlZ2VyKSB7XHJcbiAgICAgICAgICBpZiAoKDxOdW1lcmljRmllbGQ+ZmllbGRjb25maWcpLkRlY2ltYWxTZXBhcmF0b3IgPT0gbnVsbCkge1xyXG4gICAgICAgICAgICByZXR1cm4gTWF0aC5mbG9vcih2YWx1ZSk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBjb25zdCBkZWNpbWFscyA9IGZpZWxkY29uZmlnLkRlY2ltYWxQcmVjaXNpb24gKiAxMDtcclxuICAgICAgICAgICAgcmV0dXJuIE1hdGgucm91bmQodmFsdWUgKiBkZWNpbWFscykgLyBkZWNpbWFscztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uc3QgZGVjaW1hbHMgPSBmaWVsZGNvbmZpZy5EZWNpbWFsUHJlY2lzaW9uICogMTA7XHJcbiAgICAgICAgICByZXR1cm4gTWF0aC5yb3VuZCh2YWx1ZSAqIGRlY2ltYWxzKSAvIGRlY2ltYWxzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBicmVhaztcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGNhc2UgRmllbGRUeXBlRW51bVsnSW1tYWdpbmUnXToge1xyXG4gICAgICAgIHJldHVybiBcImltbWFnaW5lXCI7XHJcbiAgICAgICAgR2xvYmFsU2VydmljZS5kZWJ1Z0xvZyhcImltbWFnaW5lIFwiICsgZmllbGRjb25maWcuTmFtZSArIFwiIDogXCIgKyB2YWx1ZSlcclxuICAgICAgICAvLyAvLyBSZWN1cGVybyBpbCBCQVNFNjQgZGVsbCdpbW1hZ2luZSBSZXNpemVkIHZpYSBwcm9taXNlIGNsaWVudFxyXG4gICAgICAgIC8vIHZhciByZXNpemVkQmFzZTY0ID0gYXdhaXQgdGhpcy5yZXNpemVCYXNlNjRJbWFnZShcImRhdGE6aW1hZ2UvXCIgKyB2YWx1ZS5GaWxlRXh0ZW5zaW9uICsgXCI7YmFzZTY0LFwiICsgdmFsdWUuRmlsZURhdGFCYXNlNjQpO1xyXG5cclxuICAgICAgICAvLyAvLyBBZ2dpdW5nbyBsJ0hUTUwgY29uIGlsIG51b3ZvIEJBU0U2NFxyXG4gICAgICAgIC8vIHJldHVybiBcIjxpbWcgc3JjPSdcIiArIHJlc2l6ZWRCYXNlNjQgKyBcIicgc3R5bGU9J2hlaWdodDogXCIgKyB2YWx1ZS5SZXNpemVkSW1hZ2VIZWlnaHRQeCArIFwicHgnPlwiO1xyXG5cclxuICAgICAgICBicmVhaztcclxuICAgICAgfTtcclxuXHJcblxyXG4gICAgICBjYXNlIEZpZWxkVHlwZUVudW1bJ0FsbGVnYXRvJ106IHtcclxuICAgICAgICByZXR1cm4gXCJBbGxlZ2F0b1wiO1xyXG4gICAgICAgIC8vIEdsb2JhbFNlcnZpY2UuZGVidWdMb2coXCJBbGxlZ2F0byBcIiArIGZpZWxkLk5hbWUgKyBcIiA6IFwiICsgdmFsdWUsIHJlY29yZClcclxuXHJcbiAgICAgICAgaWYgKHZhbHVlICE9IG51bGwpIHtcclxuICAgICAgICAgIGxldCByZXNpemVkQmFzZTY0O1xyXG4gICAgICAgICAgLy8gaWYgKHZhbHVlWzBdLklzSW1hZ2UpIHtcclxuICAgICAgICAgIC8vICAgLy8gUmVjdXBlcm8gaWwgQkFTRTY0IGRlbGwnaW1tYWdpbmUgUmVzaXplZCB2aWEgcHJvbWlzZSBjbGllbnRcclxuICAgICAgICAgIC8vICAgcmVzaXplZEJhc2U2NCA9IGF3YWl0IHRoaXMucmVzaXplQmFzZTY0SW1hZ2UoXCJkYXRhOmltYWdlL1wiICsgdmFsdWVbMF0uRmlsZUV4dGVuc2lvbiArIFwiO2Jhc2U2NCxcIiArIHZhbHVlWzBdLkZpbGVEYXRhQmFzZTY0KTtcclxuICAgICAgICAgIC8vICAgLy8gR2xvYmFsU2VydmljZS5kZWJ1Z0xvZyhcIkFsbGVnYXRvIHJlc2l6ZWRCYXNlNjRcIiwgcmVzaXplZEJhc2U2NClcclxuICAgICAgICAgIC8vICAgLy8gQWdnaXVuZ28gbCdIVE1MIGNvbiBpbCBudW92byBCQVNFNjRcclxuICAgICAgICAgIC8vICAgcmV0dXJuICc8aW1nIGNsYXNzPVwiaW1hZ2UtcHJldmlld1wiIHNyYz1cIicgKyByZXNpemVkQmFzZTY0ICsgJ1wiIHN0eWxlPVwiaGVpZ2h0OiAnICsgdmFsdWVbMF0uUmVzaXplZEltYWdlSGVpZ2h0UHggKyAncHhcIj4nO1xyXG4gICAgICAgICAgLy8gfSBlbHNlIGlmICh2YWx1ZVswXS5GaWxlQ29udGVudFR5cGUgPT0gXCJhcHBsaWNhdGlvbi9wZGZcIikge1xyXG4gICAgICAgICAgLy8gICByZXR1cm4gJzxpZnJhbWUgc3JjPVwiZGF0YTphcHBsaWNhdGlvbi9wZGY7YmFzZTY0LCcgKyB2YWx1ZVswXS5GaWxlRGF0YUJhc2U2NCArICdcInN0eWxlPVwibWluLWhlaWdodDogMzAwcHg7IGhlaWdodDogMTAwJTtcIj48L2lmcmFtZT4nO1xyXG4gICAgICAgICAgLy8gfSBlbHNlIHtcclxuICAgICAgICAgIC8vICAgcmV0dXJuICc8aWZyYW1lIHNyYz1cImRhdGE6XCInICsgdmFsdWVbMF0uRmlsZUV4dGVuc2lvbiArICdcIjtiYXNlNjQsJyArIHZhbHVlWzBdLkZpbGVEYXRhQmFzZTY0ICsgJ1wic3R5bGU9XCJtaW4taGVpZ2h0OiAzMDBweDsgaGVpZ2h0OiAxMDAlO1wiPjwvaWZyYW1lPic7XHJcbiAgICAgICAgICAvLyB9XHJcblxyXG4gICAgICAgICAgLy8gQWdnaXVuZ28gbCdIVE1MIGNvbiBpbCBudW92byBCQVNFNjRcclxuICAgICAgICAgIC8vIHJldHVybiAgXCI8aW1nIHNyYz0nXCIgKyByZXNpemVkQmFzZTY0ICsgXCInIHN0eWxlPSdoZWlnaHQ6IFwiICsgdmFsdWVbMF0uUmVzaXplZEltYWdlSGVpZ2h0UHggKyBcInB4Jz5cIjtcclxuICAgICAgICAgIC8vIEdsb2JhbFNlcnZpY2UuZGVidWdMb2coXCJBbGxlZ2F0byBvdXRwdXRWYWx1ZXNBcnJheVwiLCBvdXRwdXRWYWx1ZXNBcnJheVtmaWVsZC5OYW1lXSlcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9O1xyXG5cclxuICAgICAgY2FzZSBGaWVsZFR5cGVFbnVtWydJbW1hZ2luZSBjb24gbWFya2VycyddOiB7XHJcbiAgICAgICAgcmV0dXJuIFwiSW1tYWdpbmUgY29uIG1hcmtlcnNcIjtcclxuXHJcbiAgICAgICAgLy8gUmVjdXBlcm8gaWwgQkFTRTY0IGRlbGwnaW1tYWdpbmUgUmVzaXplZCB2aWEgcHJvbWlzZSBjbGllbnRcclxuICAgICAgICAvLyB2YXIgcmVzaXplZEJhc2U2NCA9IGF3YWl0IHRoaXMucmVzaXplQmFzZTY0SW1hZ2UoXCJkYXRhOmltYWdlL1wiICsgdmFsdWUuRmlsZUV4dGVuc2lvbiArIFwiO2Jhc2U2NCxcIiArIHZhbHVlLkZpbGVEYXRhQmFzZTY0KTtcclxuXHJcbiAgICAgICAgLy8gQWdnaXVuZ28gbCdIVE1MIGNvbiBpbCBudW92byBCQVNFNjRcclxuICAgICAgICAvLyByZXR1cm4gXCI8aW1nIHNyYz0nXCIgKyByZXNpemVkQmFzZTY0ICsgXCInIHN0eWxlPSdoZWlnaHQ6IFwiICsgdmFsdWUuUmVzaXplZEltYWdlSGVpZ2h0UHggKyBcInB4Jz5cIjtcclxuXHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIH07XHJcblxyXG4gICAgICBjYXNlIEZpZWxkVHlwZUVudW1bJ0VsZW5jbyBpbW1hZ2luaSddOiB7XHJcbiAgICAgICAgcmV0dXJuIFwiRWxlbmNvIGltbWFnaW5pXCI7XHJcbiAgICAgICAgbGV0IG91dHB1dFZhbHVlc0FycmF5ID0gXCJcIjtcclxuICAgICAgICBpZiAodmFsdWUgIT0gbnVsbCAmJiAoPEltYWdlU2VsZWN0b3JGaWVsZD5maWVsZGNvbmZpZykuSXNNdWx0aUNob2ljaGUpIHtcclxuICAgICAgICAgIHZhbHVlLmZvckVhY2goKGltYWdlb2JqOiBudW1iZXIpID0+IHtcclxuICAgICAgICAgICAgdmFyIGF0dGFjaG1lbnRJbkZvcm06IER5bkF0dGFjaG1lbnQgPSAoPEltYWdlU2VsZWN0b3JGaWVsZD5maWVsZGNvbmZpZykuQXR0YWNobWVudExpc3QuZmluZCh4ID0+IHguSUQgPT0gaW1hZ2VvYmopO1xyXG4gICAgICAgICAgICBpZiAoYXR0YWNobWVudEluRm9ybSAhPSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgb3V0cHV0VmFsdWVzQXJyYXkgKz0gYXR0YWNobWVudEluRm9ybS5CdXR0b25LZXkgKyBcIiwgXCI7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgdmFyIHBhcnRzID0gb3V0cHV0VmFsdWVzQXJyYXkuc3BsaXQoXCIsIFwiKTtcclxuICAgICAgICAgIHJldHVybiBwYXJ0cy5zbGljZSgwLCBwYXJ0cy5sZW5ndGggLSAxKS5qb2luKFwiLCBcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgdmFyIGF0dGFjaG1lbnRJbkZvcm06IER5bkF0dGFjaG1lbnQgPSAoPEltYWdlU2VsZWN0b3JGaWVsZD5maWVsZGNvbmZpZykuQXR0YWNobWVudExpc3QuZmluZCh4ID0+IHguSUQgPT0gdmFsdWUpO1xyXG4gICAgICAgICAgaWYgKGF0dGFjaG1lbnRJbkZvcm0gIT0gbnVsbCkge1xyXG4gICAgICAgICAgICByZXR1cm4gYXR0YWNobWVudEluRm9ybS5CdXR0b25LZXk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBicmVhaztcclxuICAgICAgfTtcclxuICAgICAgY2FzZSBGaWVsZFR5cGVFbnVtWydEYXRhIGUvbyBvcmEnXToge1xyXG4gICAgICAgIEdsb2JhbFNlcnZpY2UuZGVidWdMb2coXCJEYXRhIGUvbyBvcmFcIiwgZmllbGRjb25maWcpO1xyXG4gICAgICAgIGlmICgoPERhdGVGaWVsZD5maWVsZGNvbmZpZykuRGF0ZUZvcm1hdCAhPSBudWxsKSB7XHJcbiAgICAgICAgICBsZXQgZml4RGF0ZUZvcm1hdCA9ICg8RGF0ZUZpZWxkPmZpZWxkY29uZmlnKS5EYXRlRm9ybWF0LnJlcGxhY2UoXCJERFwiLCBcImRkXCIpO1xyXG4gICAgICAgICAgcmV0dXJuIHRoaXMuZGF0ZXBpcGUudHJhbnNmb3JtKHZhbHVlLCBmaXhEYXRlRm9ybWF0KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICBpZiAoKDxEYXRlRmllbGQ+ZmllbGRjb25maWcpLklzT25seURhdGUgPT0gRGF0ZVRpbWVUeXBlRW51bVsnU29sbyBkYXRhJ10pIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0ZXBpcGUudHJhbnNmb3JtKHZhbHVlLCBcImRkL01NL3l5eXlcIik7XHJcbiAgICAgICAgICB9IGVsc2UgaWYgKCg8RGF0ZUZpZWxkPmZpZWxkY29uZmlnKS5Jc09ubHlEYXRlID09IERhdGVUaW1lVHlwZUVudW1bJ0RhdGEgZSBvcmEnXSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRlcGlwZS50cmFuc2Zvcm0odmFsdWUsIFwiZGQvTU0veXl5eSBISDptbVwiKTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAoKDxEYXRlRmllbGQ+ZmllbGRjb25maWcpLklzT25seURhdGUgPT0gRGF0ZVRpbWVUeXBlRW51bVsnU29sbyBvcmFyaW8nXSkge1xyXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRlcGlwZS50cmFuc2Zvcm0odmFsdWUsIFwiSEg6bW1cIik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBkZWZhdWx0OiB7XHJcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gIH1cclxuICAvLyNlbmRyZWdpb24gcHJpbnRWYWx1ZVxyXG5cclxuICAvLyNyZWdpb24gcmVzaXplQmFzZTY0SW1hZ2VcclxuICBwcml2YXRlIGFzeW5jIHJlc2l6ZUJhc2U2NEltYWdlKGJhc2U2NEltYWdlOiBzdHJpbmcpIHtcclxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgIGNvbnN0IGltYWdldHlwZSA9IC9kYXRhOmltYWdlXFwvKFtcXHddKyk7LztcclxuICAgICAgY29uc3QgbWF0Y2ggPSBiYXNlNjRJbWFnZS5tYXRjaChpbWFnZXR5cGUpO1xyXG4gICAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcclxuICAgICAgaW1nLnNyYyA9IGJhc2U2NEltYWdlO1xyXG4gICAgICBpbWcub25sb2FkID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XHJcbiAgICAgICAgY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XHJcbiAgICAgICAgY29uc3Qgd2lkdGggPSBpbWcud2lkdGg7XHJcbiAgICAgICAgY29uc3QgaGVpZ2h0ID0gaW1nLmhlaWdodDtcclxuICAgICAgICBjb25zdCBhc3BlY3RSYXRpbyA9IHdpZHRoIC8gaGVpZ2h0O1xyXG5cclxuICAgICAgICBjb25zdCBuZXdIZWlnaHQgPSAxMjg7XHJcbiAgICAgICAgY29uc3QgbmV3V2lkdGggPSBuZXdIZWlnaHQgKiBhc3BlY3RSYXRpbztcclxuXHJcbiAgICAgICAgY2FudmFzLndpZHRoID0gbmV3V2lkdGg7XHJcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IG5ld0hlaWdodDtcclxuICAgICAgICBjdHguZHJhd0ltYWdlKGltZywgMCwgMCwgbmV3V2lkdGgsIG5ld0hlaWdodCk7XHJcbiAgICAgICAgbGV0IHF1YWxpdHkgPSAwLjg7XHJcbiAgICAgICAgbGV0IGRhdGFVUkwgPSBjYW52YXMudG9EYXRhVVJMKCdpbWFnZS8nICsgbWF0Y2hbMV0sIHF1YWxpdHkpO1xyXG4gICAgICAgIHJlc29sdmUoZGF0YVVSTCk7XHJcbiAgICAgIH07XHJcbiAgICB9KTtcclxuICB9XHJcbiAgLy8jZW5kcmVnaW9uIHJlc2l6ZUJhc2U2NEltYWdlXHJcbn1cclxuIiwiPG1hdC1jYXJkIGNsYXNzPVwibGlzdC1mb3JtLXJlY29yZFwiPlxyXG4gIDxtYXQtY2FyZC1oZWFkZXIgY2xhc3M9XCJhbGlnbi1pdGVtcy1jZW50ZXIganVzdGlmeS1jb250ZW50LWJldHdlZW5cIj5cclxuICAgIDxtYXQtY2FyZC10aXRsZSAqbmdJZj1cImxvYWRlZEZpbHRlcnMgJiYgc2hvd1RpdGxlXCJcclxuICAgICAgPkVsZW5jbyB7eyBmb3JtLk5hbWUgfX08L21hdC1jYXJkLXRpdGxlXHJcbiAgICA+XHJcbiAgICA8IS0tIDxtYXQtY2FyZC1hY3Rpb25zPlxyXG4gICAgICA8YnV0dG9uXHJcbiAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxyXG4gICAgICAgIG1hdC1yYWlzZWQtYnV0dG9uXHJcbiAgICAgICAgY29sb3I9XCJwcmltYXJ5XCJcclxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICAoY2xpY2spPVwib25BZGRWaWV3RWRpdFJlY29yZC5lbWl0KG51bGwpXCJcclxuICAgICAgPlxyXG4gICAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPlxyXG4gICAgICAgIDxzcGFuIHN0eWxlPVwibWFyZ2luLWxlZnQ6IDEwcHhcIj5BZ2dpdW5naTwvc3Bhbj5cclxuICAgICAgPC9idXR0b24+XHJcbiAgICA8L21hdC1jYXJkLWFjdGlvbnM+IC0tPlxyXG4gIDwvbWF0LWNhcmQtaGVhZGVyPlxyXG4gIDxtYXQtY2FyZC1jb250ZW50PlxyXG4gICAgPCEtLSNyZWdpb24gRklMVEVSUyAtLT5cclxuICAgIDxkaXYgY2xhc3M9XCJyb3dcIiAqbmdJZj1cImxvYWRlZEZpbHRlcnNcIj5cclxuICAgICAgPGRpdiBjbGFzcz1cImNvbC1zbS0xMiBjb2wtbWQtM1wiPlxyXG4gICAgICAgIDx0bXctZGF0ZXRpbWVwaWNrZXJcclxuICAgICAgICAgIGNsYXNzPVwiZGF0ZVwiXHJcbiAgICAgICAgICBbcGxhY2Vob2xkZXJdPVwiJ1BlcmlvZG8gaW5pemlvJ1wiXHJcbiAgICAgICAgICBbbGFiZWxdPVwiJ1BlcmlvZG8gaW5pemlvJ1wiXHJcbiAgICAgICAgICBbKG5nTW9kZWxJbnB1dCldPVwibWluRGF0ZVwiXHJcbiAgICAgICAgICAobmdNb2RlbElucHV0Q2hhbmdlKT1cImZpbHRlckRhdGFBbnN3ZXJzKClcIlxyXG4gICAgICAgICAgW3BpY2tlck1vZGVdPVwibW9kZXMuREFURVBJQ0tFUlwiXHJcbiAgICAgICAgICBbb3V0cHV0Rm9ybWF0XT1cIidERC9NTS9ZWVlZJ1wiXHJcbiAgICAgICAgICBbc2hvd1NlY29uZHNdPVwiZmFsc2VcIlxyXG4gICAgICAgID5cclxuICAgICAgICA8L3Rtdy1kYXRldGltZXBpY2tlcj5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tMTIgY29sLW1kLTNcIj5cclxuICAgICAgICA8dG13LWRhdGV0aW1lcGlja2VyXHJcbiAgICAgICAgICBjbGFzcz1cImRhdGVcIlxyXG4gICAgICAgICAgW3BsYWNlaG9sZGVyXT1cIidQZXJpb2RvIGZpbmUnXCJcclxuICAgICAgICAgIFtsYWJlbF09XCInUGVyaW9kbyBmaW5lJ1wiXHJcbiAgICAgICAgICBbKG5nTW9kZWxJbnB1dCldPVwibWF4RGF0ZVwiXHJcbiAgICAgICAgICAobmdNb2RlbElucHV0Q2hhbmdlKT1cImZpbHRlckRhdGFBbnN3ZXJzKClcIlxyXG4gICAgICAgICAgW3BpY2tlck1vZGVdPVwibW9kZXMuREFURVBJQ0tFUlwiXHJcbiAgICAgICAgICBbb3V0cHV0Rm9ybWF0XT1cIidERC9NTS9ZWVlZJ1wiXHJcbiAgICAgICAgICBbc2hvd1NlY29uZHNdPVwiZmFsc2VcIlxyXG4gICAgICAgID5cclxuICAgICAgICA8L3Rtdy1kYXRldGltZXBpY2tlcj5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJjb2wtc20tMTIgY29sLW1kLTMgbXQtMlwiPlxyXG4gICAgICAgIDxtYXQtZm9ybS1maWVsZD5cclxuICAgICAgICAgIDxtYXQtbGFiZWw+U2VsZXppb25lIGRlaSBjYW1waTwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgPG1hdC1zZWxlY3QgKHNlbGVjdGlvbkNoYW5nZSk9XCJvblNlbGVjdGlvbkNoYW5nZSgkZXZlbnQpXCIgbXVsdGlwbGU+XHJcbiAgICAgICAgICAgIDxtYXQtb3B0aW9uICpuZ0Zvcj1cImxldCBwcm9wZXJ0eSBvZiBwcm9wZXJ0aWVzXCIgW3ZhbHVlXT1cInByb3BlcnR5XCI+XHJcbiAgICAgICAgICAgICAge3sgcHJvcGVydGllc0xhYmVsW3Byb3BlcnR5LmxhYmVsXSB9fVxyXG4gICAgICAgICAgICA8L21hdC1vcHRpb24+XHJcbiAgICAgICAgICA8L21hdC1zZWxlY3Q+XHJcbiAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIDwhLS0gPGRpdiBjbGFzcz1cImNvbC1zbS0xMiBjb2wtbWQtMyBtdC0yXCI+XHJcbiAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgW2Rpc2FibGVkXT1cIlxyXG4gICAgICAgICAgICBzZWxlY3RlZFByb3BlcnRpZXMgPT0gbnVsbCB8fCBzZWxlY3RlZFByb3BlcnRpZXMubGVuZ3RoID09IDBcclxuICAgICAgICAgIFwiXHJcbiAgICAgICAgICBjbGFzcz1cImJ0biBidG4tZ3JhcGgtZ2VuZXJhdGUgYnV0dG9uLW5leHQgbWUtMlwiXHJcbiAgICAgICAgICBtYXQtcmFpc2VkLWJ1dHRvblxyXG4gICAgICAgICAgY29sb3I9XCJwcmltYXJ5XCJcclxuICAgICAgICAgIChjbGljayk9XCJmaWx0ZXJEYXRhQW5zd2VycygpXCJcclxuICAgICAgICA+XHJcbiAgICAgICAgICBHZW5lcmFcclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgPC9kaXY+IC0tPlxyXG4gICAgPC9kaXY+XHJcbiAgICA8IS0tI2VuZHJlZ2lvbiBGSUxURVJTIC0tPlxyXG5cclxuICAgIDwhLS0jcmVnaW9uIFRBQkxFIC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cInRhYmxlLWNvbnRhaW5lclwiPlxyXG4gICAgICA8dGFibGVcclxuICAgICAgICBtYXQtdGFibGVcclxuICAgICAgICBbZGF0YVNvdXJjZV09XCJzZWxlY3RlZFByb3BlcnRpZXNcIlxyXG4gICAgICAgIGNsYXNzPVwibWF0LWVsZXZhdGlvbi16OCBtYXQtdGFibGUtZml4ZWRcIlxyXG4gICAgICA+XHJcbiAgICAgICAgPCEtLSBDb2xvbm5hIGZpc3NhIHBlciBsZSBwcm9wcmlldMOgIC0tPlxyXG4gICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwicHJvcGVydHlcIiBzdGlja3k+XHJcbiAgICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIGNsYXNzPVwic3RpY2t5LWNvbHVtblwiPlxyXG4gICAgICAgICAgICBEYXRhIEluc2VyaW1lbnRvXHJcbiAgICAgICAgICA8L3RoPlxyXG4gICAgICAgICAgPHRkXHJcbiAgICAgICAgICAgIG1hdC1jZWxsXHJcbiAgICAgICAgICAgICptYXRDZWxsRGVmPVwibGV0IHNlbGVjdGVkUHJvcGVydGllc1wiXHJcbiAgICAgICAgICAgIGNsYXNzPVwic3RpY2t5LWNvbHVtblwiXHJcbiAgICAgICAgICA+XHJcbiAgICAgICAgICAgIHt7IHByb3BlcnRpZXNMYWJlbFtzZWxlY3RlZFByb3BlcnRpZXMubGFiZWxdIH19XHJcbiAgICAgICAgICA8L3RkPlxyXG4gICAgICAgIDwvbmctY29udGFpbmVyPlxyXG5cclxuICAgICAgICA8IS0tIEdlbmVyYSBkaW5hbWljYW1lbnRlIGxlIGNvbG9ubmUgcGVyIG9nbmkgcmlzcG9zdGEgLS0+XHJcbiAgICAgICAgPG5nLWNvbnRhaW5lclxyXG4gICAgICAgICAgKm5nRm9yPVwibGV0IHZhbHVlIG9mIGZpbHRlcmVkQW5zd2VyczsgbGV0IGkgPSBpbmRleFwiXHJcbiAgICAgICAgICBbbWF0Q29sdW1uRGVmXT1cIidjb2wnICsgaVwiXHJcbiAgICAgICAgPlxyXG4gICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj5cclxuICAgICAgICAgICAge3sgdmFsdWUuQW5zd2VyRGF0ZSB8IGRhdGUgOiBcImRkL01NL3l5eXkgSEg6bW1cIiB9fVxyXG4gICAgICAgICAgPC90aD5cclxuICAgICAgICAgIDwhLS0gPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj4ge3sgdmFsdWUuQW5zd2VyRGF0ZSB8IGRhdGU6J2RkL01NL3l5eXkgSEg6bW0nIH19IDwvdGg+IC0tPlxyXG4gICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IHNlbGVjdGVkUHJvcGVydGllc1wiPlxyXG4gICAgICAgICAgICB7e1xyXG4gICAgICAgICAgICAgIHNlbGVjdGVkUHJvcGVydGllcy5sYWJlbCA9PT0gXCJBbnN3ZXJEYXRlXCJcclxuICAgICAgICAgICAgICAgID8gKHZhbHVlLkFuc3dlckRhdGUgfCBkYXRlIDogXCJkZC9NTS95eXl5IEhIOm1tXCIpXHJcbiAgICAgICAgICAgICAgICA6IHByaW50VmFsdWUoc2VsZWN0ZWRQcm9wZXJ0aWVzLnR5cGUsIHZhbHVlW3NlbGVjdGVkUHJvcGVydGllcy5sYWJlbF0sIHNlbGVjdGVkUHJvcGVydGllcy5jb25maWcpID8/IFwiTi9BXCJcclxuICAgICAgICAgICAgfX1cclxuICAgICAgICAgICAgIDwhLS0gLSBcclxuICAgICAgICAgICAge3tzZWxlY3RlZFByb3BlcnRpZXMudHlwZX19XHJcbiAgICAgICAgICAgIHt7c2VsZWN0ZWRQcm9wZXJ0aWVzLmxhYmVsfX0gLS0+XHJcbiAgICAgICAgICA8L3RkPlxyXG4gICAgICAgIDwvbmctY29udGFpbmVyPlxyXG5cclxuICAgICAgICA8IS0tIEhlYWRlciBkZWxsYSB0YWJlbGxhIC0tPlxyXG4gICAgICAgIDx0ciBtYXQtaGVhZGVyLXJvdyAqbWF0SGVhZGVyUm93RGVmPVwiZGlzcGxheWVkQ29sdW1uc1wiPjwvdHI+XHJcblxyXG4gICAgICAgIDwhLS0gUmlnaGUgZGVsbGEgdGFiZWxsYSAtLT5cclxuICAgICAgICA8dHIgbWF0LXJvdyAqbWF0Um93RGVmPVwibGV0IHJvdzsgY29sdW1uczogZGlzcGxheWVkQ29sdW1uc1wiPjwvdHI+XHJcbiAgICAgIDwvdGFibGU+XHJcbiAgICA8L2Rpdj5cclxuICAgIDwhLS0jcmVnaW9uIFRBQkxFIC0tPlxyXG4gIDwvbWF0LWNhcmQtY29udGVudD5cclxuICA8bWF0LWNhcmQtZm9vdGVyPlxyXG4gICAgPCEtLSA8bWF0LXByb2dyZXNzLWJhciBtb2RlPVwiaW5kZXRlcm1pbmF0ZVwiPjwvbWF0LXByb2dyZXNzLWJhcj4gLS0+XHJcbiAgPC9tYXQtY2FyZC1mb290ZXI+XHJcbjwvbWF0LWNhcmQ+XHJcblxyXG48IS0tIDxkaXYgY2xhc3M9XCJyb3cgZXFwLWR5bmFtaWMtbW9kdWxlLXRpdGxlIGxpc3QtZm9ybS1yZWNvcmQtaGVhZGVyXCI+XHJcbiAgPGRpdiBjbGFzcz1cImNvbC1tZC02XCI+XHJcbiAgICA8aDQgKm5nSWY9XCJzaG93VGl0bGVcIj5cclxuICAgICAgPGI+RWxlbmNvIHt7IGZvcm0uTmFtZSB9fTwvYj5cclxuICAgIDwvaDQ+XHJcbiAgPC9kaXY+XHJcbiAgPGRpdiBjbGFzcz1cImNvbC1tZC02IHRleHQtcmlnaHRcIiAqbmdJZj1cImRlZmF1bHRMaXN0QWN0aW9ucy5hZGRcIj5cclxuICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIiBtYXQtcmFpc2VkLWJ1dHRvbiBjb2xvcj1cInByaW1hcnlcIiB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgKGNsaWNrKT1cIm9uQWRkVmlld0VkaXRSZWNvcmQuZW1pdChudWxsKVwiPlxyXG4gICAgICA8bWF0LWljb24+YWRkPC9tYXQtaWNvbj5cclxuICAgICAgPHNwYW4gc3R5bGU9XCJtYXJnaW4tbGVmdDogMTBweFwiPkFnZ2l1bmdpPC9zcGFuPlxyXG4gICAgPC9idXR0b24+XHJcbiAgPC9kaXY+XHJcbjwvZGl2PlxyXG5cclxuPGVxcC10YWJsZSBjbGFzcz1cImxpc3QtZm9ybS1yZWNvcmQtdGFibGVcIiAjdGFibGVSZWNvcmRzICpuZ0lmPVwibG9hZGVyICYmIGNvbmZpZ3VyYXRpb25zLnZhbHVlc1wiXHJcbiAgW2RhdGFdPVwiY29uZmlndXJhdGlvbnMudmFsdWVzXCIgW2NvbHVtbnNdPVwiY29sdW1uc1wiPjwvZXFwLXRhYmxlPiAtLT5cclxuIl19