@seniorsistemas/angular-components 17.27.1-feature-sds-110-1bb20c20 → 17.27.1-feature-sds-110-57186492

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.
Files changed (72) hide show
  1. package/autocomplete/index.d.ts +5 -0
  2. package/autocomplete/lib/autocomplete/autocomplete.component.d.ts +250 -0
  3. package/autocomplete/lib/autocomplete/components/autocomplete-chip/autocomplete-chip.component.d.ts +9 -0
  4. package/autocomplete/public-api.d.ts +1 -0
  5. package/button/lib/button/button.component.d.ts +1 -1
  6. package/dynamic-form/lib/dynamic-form/components/lookup/lookup.component.d.ts +1 -2
  7. package/dynamic-form/lib/dynamic-form/dynamic-form.module.d.ts +3 -2
  8. package/dynamic-form/lib/dynamic-form/form-field/fields/currency/currency-field.component.d.ts +3 -2
  9. package/esm2022/autocomplete/lib/autocomplete/autocomplete.component.mjs +554 -0
  10. package/esm2022/autocomplete/lib/autocomplete/components/autocomplete-chip/autocomplete-chip.component.mjs +17 -0
  11. package/esm2022/autocomplete/public-api.mjs +2 -0
  12. package/esm2022/autocomplete/seniorsistemas-angular-components-autocomplete.mjs +5 -0
  13. package/esm2022/button/lib/button/button.component.mjs +4 -10
  14. package/esm2022/chips/lib/chips/chips/chips.component.mjs +2 -2
  15. package/esm2022/control-errors/lib/control-errors/control-errors.component.mjs +2 -2
  16. package/esm2022/country-phone-picker/lib/country-phone-picker/country-phone-picker.component.mjs +2 -2
  17. package/esm2022/dynamic-form/lib/dynamic-form/components/lookup/lookup.component.mjs +16 -10
  18. package/esm2022/dynamic-form/lib/dynamic-form/dynamic-form.module.mjs +5 -1
  19. package/esm2022/dynamic-form/lib/dynamic-form/form-field/fields/autocomplete/autocomplete-field.component.mjs +7 -6
  20. package/esm2022/dynamic-form/lib/dynamic-form/form-field/fields/currency/currency-field.component.mjs +18 -8
  21. package/esm2022/dynamic-form/lib/dynamic-form/form-field/fields/lookup/lookup-field.component.mjs +1 -1
  22. package/esm2022/dynamic-form/lib/dynamic-form/form-field/fields/password/password-field.component.mjs +2 -2
  23. package/esm2022/dynamic-form/lib/dynamic-form/form-field/fields/select/select-field.component.mjs +1 -1
  24. package/esm2022/inline-edit/lib/inline-edit/components/fields/inline-edit-lookup/inline-edit-lookup.component.mjs +1 -1
  25. package/esm2022/lib/locale/fallback.mjs +2 -1
  26. package/esm2022/object-card/lib/object-card/object-card.component.mjs +3 -3
  27. package/esm2022/paginator/lib/paginator/paginator.component.mjs +2 -2
  28. package/esm2022/panel/lib/panel/panel.component.mjs +3 -3
  29. package/esm2022/select/lib/select/select.component.mjs +234 -336
  30. package/esm2022/text-area/lib/text-area/text-area.component.mjs +4 -4
  31. package/esm2022/text-area-ia/lib/text-area-ia/text-area-ia.component.mjs +4 -4
  32. package/esm2022/toast/lib/toast/toast.component.mjs +13 -13
  33. package/esm2022/token-list/lib/token-list/token-list.component.mjs +3 -3
  34. package/fesm2022/seniorsistemas-angular-components-autocomplete.mjs +575 -0
  35. package/fesm2022/seniorsistemas-angular-components-autocomplete.mjs.map +1 -0
  36. package/fesm2022/seniorsistemas-angular-components-button.mjs +3 -9
  37. package/fesm2022/seniorsistemas-angular-components-button.mjs.map +1 -1
  38. package/fesm2022/seniorsistemas-angular-components-chips.mjs +2 -2
  39. package/fesm2022/seniorsistemas-angular-components-chips.mjs.map +1 -1
  40. package/fesm2022/seniorsistemas-angular-components-control-errors.mjs +1 -1
  41. package/fesm2022/seniorsistemas-angular-components-control-errors.mjs.map +1 -1
  42. package/fesm2022/seniorsistemas-angular-components-country-phone-picker.mjs +2 -2
  43. package/fesm2022/seniorsistemas-angular-components-country-phone-picker.mjs.map +1 -1
  44. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +38 -19
  45. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
  46. package/fesm2022/seniorsistemas-angular-components-inline-edit.mjs +1 -1
  47. package/fesm2022/seniorsistemas-angular-components-inline-edit.mjs.map +1 -1
  48. package/fesm2022/seniorsistemas-angular-components-object-card.mjs +2 -2
  49. package/fesm2022/seniorsistemas-angular-components-object-card.mjs.map +1 -1
  50. package/fesm2022/seniorsistemas-angular-components-paginator.mjs +1 -1
  51. package/fesm2022/seniorsistemas-angular-components-paginator.mjs.map +1 -1
  52. package/fesm2022/seniorsistemas-angular-components-panel.mjs +2 -2
  53. package/fesm2022/seniorsistemas-angular-components-panel.mjs.map +1 -1
  54. package/fesm2022/seniorsistemas-angular-components-select.mjs +232 -334
  55. package/fesm2022/seniorsistemas-angular-components-select.mjs.map +1 -1
  56. package/fesm2022/seniorsistemas-angular-components-text-area-ia.mjs +3 -3
  57. package/fesm2022/seniorsistemas-angular-components-text-area-ia.mjs.map +1 -1
  58. package/fesm2022/seniorsistemas-angular-components-text-area.mjs +3 -3
  59. package/fesm2022/seniorsistemas-angular-components-text-area.mjs.map +1 -1
  60. package/fesm2022/seniorsistemas-angular-components-toast.mjs +12 -12
  61. package/fesm2022/seniorsistemas-angular-components-toast.mjs.map +1 -1
  62. package/fesm2022/seniorsistemas-angular-components-token-list.mjs +2 -2
  63. package/fesm2022/seniorsistemas-angular-components-token-list.mjs.map +1 -1
  64. package/fesm2022/seniorsistemas-angular-components.mjs +1 -0
  65. package/fesm2022/seniorsistemas-angular-components.mjs.map +1 -1
  66. package/package.json +19 -13
  67. package/select/lib/select/select.component.d.ts +148 -157
  68. package/styles.css +1 -0
  69. package/text-area-ia/lib/text-area-ia/text-area-ia.component.d.ts +1 -1
  70. package/toast/lib/toast/toast.component.d.ts +4 -4
  71. package/src/lib/styles/tailwind.scss +0 -3
  72. package/tailwind.css +0 -1167
@@ -0,0 +1,554 @@
1
+ import { OverlayModule } from '@angular/cdk/overlay';
2
+ import { ScrollingModule } from '@angular/cdk/scrolling';
3
+ import { CommonModule } from '@angular/common';
4
+ import { Component, computed, DestroyRef, forwardRef, inject, input, model, output, signal, viewChild } from '@angular/core';
5
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+ import { FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
7
+ import { TranslateModule } from '@ngx-translate/core';
8
+ import { Observable, Subject } from 'rxjs';
9
+ import { debounceTime, distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
10
+ import { AutocompleteChipComponent } from './components/autocomplete-chip/autocomplete-chip.component';
11
+ import * as i0 from "@angular/core";
12
+ import * as i1 from "@angular/common";
13
+ import * as i2 from "@angular/forms";
14
+ import * as i3 from "@angular/cdk/overlay";
15
+ import * as i4 from "@angular/cdk/scrolling";
16
+ import * as i5 from "@ngx-translate/core";
17
+ export class AutocompleteComponent {
18
+ static nextId = 0;
19
+ suggestions = input([]);
20
+ placeholder = input();
21
+ suggestionValue = input();
22
+ suggestionLabel = input();
23
+ readonly = input(false);
24
+ emptyMessage = input();
25
+ delay = input(300);
26
+ invalid = input(false);
27
+ virtualScroll = input(false);
28
+ virtualScrollItemSize = input(37);
29
+ lazy = input(false);
30
+ dropdown = input(false);
31
+ forceSelection = input(false);
32
+ checkmark = input(false);
33
+ multiple = input(false);
34
+ minLengthToSearch = input(1);
35
+ inputClass = input('');
36
+ value = model();
37
+ values = model([]);
38
+ disabled = model(false);
39
+ lazyLoad = output();
40
+ selected = output();
41
+ unselected = output();
42
+ blurred = output();
43
+ cleared = output();
44
+ keyUp = output();
45
+ focused = output();
46
+ completeMethod = output();
47
+ focusedIndex = signal(-1);
48
+ isOpen = signal(false);
49
+ filteredSuggestions = signal([]);
50
+ showEmptyMessage = signal(false);
51
+ filterText = signal('');
52
+ inputValue = signal('');
53
+ loading = signal(false);
54
+ componentId = `autocomplete_${AutocompleteComponent.nextId++}`;
55
+ inputEl = viewChild('inputEl');
56
+ _inputSubject$ = new Subject();
57
+ _lazyLoadSubject$ = new Subject();
58
+ _destroyRef = inject(DestroyRef);
59
+ _onChange;
60
+ _onTouched;
61
+ /**
62
+ * Computed que retorna uma lista de sugestões do tipo `SuggestionWrapper<T>`,
63
+ * adicionando um identificador único a cada sugestão.
64
+ * @returns Uma lista de sugestões processadas com identificadores únicos.
65
+ */
66
+ internalSuggestion = computed(() => {
67
+ const opts = this.suggestions();
68
+ return this._addIdToSuggestions(opts);
69
+ });
70
+ /**
71
+ * Retorna um conjunto (`Set`) com os IDs das sugestões selecionadas.
72
+ */
73
+ selectedSuggestionIds = computed(() => {
74
+ if (!this.multiple()) {
75
+ return new Set();
76
+ }
77
+ const currentValues = this.values();
78
+ return new Set(currentValues.map((value) => {
79
+ return this.internalSuggestion().find((s) => JSON.stringify(s.data) === JSON.stringify(value))?.id;
80
+ }));
81
+ });
82
+ /**
83
+ * Retorna uma lista de sugestões filtradas, enriquecidas com a propriedade `isSelected`.
84
+ * Cada sugestão recebe um campo booleano `isSelected` indicando se ela está selecionada,
85
+ * com base nos IDs das sugestões selecionadas e no valor da sugestão.
86
+ * @returns Uma lista de sugestões filtradas, cada uma com a propriedade adicional `isSelected`.
87
+ */
88
+ enrichedFilteredSuggestions = computed(() => {
89
+ const filtered = this.filteredSuggestions();
90
+ const selectedIds = this.selectedSuggestionIds();
91
+ return filtered.map((suggestion) => ({
92
+ ...suggestion,
93
+ isSelected: selectedIds.has(suggestion.id),
94
+ }));
95
+ });
96
+ constructor() {
97
+ this._validateInputs();
98
+ this._setupInputDebounce();
99
+ this._setupLazyLoadDebounce();
100
+ }
101
+ /**
102
+ * Define o valor do autocomplete.
103
+ * @param value Valor a ser definido, único ou array, conforme seleção múltipla.
104
+ * @throws Se múltiplo for falso e value for array.
105
+ */
106
+ writeValue(value) {
107
+ const suggestionLabel = this.suggestionLabel();
108
+ if (value && this.multiple()) {
109
+ if (Array.isArray(value)) {
110
+ this.values.set(value);
111
+ }
112
+ else {
113
+ this.values.set([value]);
114
+ }
115
+ }
116
+ else {
117
+ if (Array.isArray(value)) {
118
+ throw new Error('The value must not be an array when multiple is false.');
119
+ }
120
+ else {
121
+ this.value.set(value);
122
+ }
123
+ this.inputValue.set(!value ? '' : suggestionLabel ? String(value[suggestionLabel]) : String(value));
124
+ }
125
+ }
126
+ /**
127
+ * Registra uma função de callback que será chamada sempre que o valor do componente mudar.
128
+ * @param onChange Função a ser chamada quando o valor mudar. Recebe o novo valor como argumento, que pode ser um único valor ou um array de valores.
129
+ */
130
+ registerOnChange(onChange) {
131
+ this._onChange = onChange;
132
+ }
133
+ /**
134
+ * Registra uma função de callback que será chamada quando o componente for tocado (perder o foco).
135
+ * @param onTouched Função de callback a ser chamada quando o componente for tocado.
136
+ */
137
+ registerOnTouched(onTouched) {
138
+ this._onTouched = onTouched;
139
+ }
140
+ /**
141
+ * Define o estado de desabilitado do componente.
142
+ * @param disabled Indica se o componente deve ser desabilitado (`true`) ou habilitado (`false`).
143
+ */
144
+ setDisabledState(disabled) {
145
+ this.disabled.set(disabled);
146
+ }
147
+ /**
148
+ * Manipula o evento de entrada do usuário no campo de texto do autocomplete.
149
+ * Este método é chamado sempre que o usuário digita algo no campo de entrada.
150
+ * Ele executa as seguintes ações:
151
+ * - Dispara o callback de "touched" para controle de formulários.
152
+ * - Obtém o valor atual do campo de entrada.
153
+ * - Se o modo lazy estiver ativado, emite o evento de lazyLoad com a consulta e abre o painel de sugestões.
154
+ * - Caso contrário, atualiza o texto de filtro, notifica os observadores e abre o painel de sugestões se houver sugestões disponíveis.
155
+ * @param event Evento de entrada do tipo `Event` proveniente do campo de texto.
156
+ */
157
+ onInput(event) {
158
+ this._onTouched?.();
159
+ const value = event.target.value;
160
+ if (this.lazy()) {
161
+ this._lazyLoadSubject$.next(value);
162
+ this.isOpen.set(true);
163
+ return;
164
+ }
165
+ this.filterText.set(value);
166
+ this.completeMethod.emit({ query: value });
167
+ this._inputSubject$.next(value);
168
+ if (this.suggestions()) {
169
+ this.isOpen.set(true);
170
+ }
171
+ }
172
+ /**
173
+ * Manipula o evento de perda de foco (blur) do campo de entrada do autocomplete.
174
+ * Este método verifica se o valor digitado pelo usuário corresponde exatamente a algum dos itens sugeridos.
175
+ * - Se houver correspondência:
176
+ * - No modo múltiplo (`multiple`), adiciona o item selecionado à lista de valores, caso ainda não esteja presente.
177
+ * - No modo simples, seleciona o item correspondente se ainda não estiver selecionado.
178
+ * - Se não houver correspondência, limpa o campo de entrada.
179
+ */
180
+ onInputBlur(event) {
181
+ const inputValue = String(this.inputValue()).toLowerCase();
182
+ const suggestions = this.internalSuggestion();
183
+ const match = suggestions.find(({ data }) => {
184
+ const label = this.suggestionLabel() ? data[this.suggestionLabel()] : data;
185
+ return String(label).toLowerCase() === inputValue;
186
+ });
187
+ if (match) {
188
+ if (this.multiple()) {
189
+ const currentValues = this.values();
190
+ const exists = currentValues.some((value) => (this.suggestionValue() ? value[this.suggestionValue()] : value) ===
191
+ (this.suggestionValue() ? match.data[this.suggestionValue()] : match.data));
192
+ if (!exists) {
193
+ this.values.set([...currentValues, match.data]);
194
+ this._onChange?.(this.values());
195
+ }
196
+ this.inputValue.set('');
197
+ }
198
+ else {
199
+ if (this.value() !== match.data) {
200
+ this.selectSuggestion(match.data);
201
+ }
202
+ }
203
+ }
204
+ else {
205
+ this.inputValue.set('');
206
+ }
207
+ }
208
+ /**
209
+ * Dispara o evento de foco quando o campo de entrada recebe foco.
210
+ * @param event O evento de foco disparado pelo elemento de entrada.
211
+ */
212
+ onInputFocus(event) {
213
+ this.focused.emit(event);
214
+ }
215
+ /**
216
+ * Manipula eventos de teclado no componente de autocomplete.
217
+ * Este método gerencia a navegação e seleção de sugestões usando as teclas do teclado.
218
+ * - 'ArrowDown': Move o foco para a próxima sugestão.
219
+ * - 'ArrowUp': Move o foco para a sugestão anterior.
220
+ * - 'Enter' ou 'Tab': Seleciona a sugestão atualmente focada e fecha a lista de sugestões.
221
+ * - 'Escape': Fecha a lista de sugestões sem selecionar nenhum item.
222
+ * @param event O evento de teclado disparado pelo usuário.
223
+ */
224
+ onKeyDown(event) {
225
+ const suggestions = this.filteredSuggestions();
226
+ this._onTouched?.();
227
+ const _selectSuggestion = () => {
228
+ if (this.focusedIndex() >= 0 && this.focusedIndex() < suggestions.length) {
229
+ event.preventDefault();
230
+ this.selectSuggestion(suggestions[this.focusedIndex()].data);
231
+ }
232
+ };
233
+ switch (event.key) {
234
+ case 'ArrowDown':
235
+ event.preventDefault();
236
+ this._focusNextSuggestion(suggestions);
237
+ break;
238
+ case 'ArrowUp':
239
+ event.preventDefault();
240
+ this._focusPreviousSuggestion();
241
+ break;
242
+ case 'Enter':
243
+ case 'Tab':
244
+ _selectSuggestion();
245
+ this.isOpen.set(false);
246
+ break;
247
+ case 'Escape':
248
+ this.isOpen.set(false);
249
+ break;
250
+ }
251
+ }
252
+ /**
253
+ * Emite um evento quando uma tecla é liberada no componente. *
254
+ * @param event O evento de teclado associado à tecla liberada.
255
+ */
256
+ onKeyUp(event) {
257
+ this.keyUp.emit(event);
258
+ }
259
+ /**
260
+ * Fecha o dropdown em eventos de redimensionamento de janela.
261
+ */
262
+ onWindowResize() {
263
+ if (this.isOpen()) {
264
+ this.isOpen.set(false);
265
+ }
266
+ }
267
+ /**
268
+ * Seleciona uma sugestão da lista de sugestões.
269
+ * Se o modo múltiplo estiver ativado (`multiple()` retorna true), adiciona a sugestão à lista de suggestões selecionadas,
270
+ * caso ela ainda não esteja presente. Em seguida, limpa o valor do campo de entrada.
271
+ * Se o modo múltiplo não estiver ativado, define a sugestão como valor selecionado e atualiza o campo de entrada
272
+ * com o rótulo correspondente.
273
+ * Em ambos os casos, dispara o callback `_onChange` com o novo valor e fecha o painel de sugestões.
274
+ * @param suggestion - A sugestão a ser selecionada.
275
+ */
276
+ selectSuggestion(suggestion) {
277
+ if (this.multiple()) {
278
+ const currentValues = this.values();
279
+ const exists = currentValues.some((value) => (this.suggestionValue() ? value[this.suggestionValue()] : value) ===
280
+ (this.suggestionValue() ? suggestion[this.suggestionValue()] : suggestion));
281
+ if (!exists) {
282
+ this.values.set([...currentValues, suggestion]);
283
+ this._onChange?.(this.values());
284
+ }
285
+ this.inputValue.set('');
286
+ }
287
+ else {
288
+ this.value.set(suggestion);
289
+ const _value = this.suggestionValue() ? suggestion[this.suggestionValue()] : suggestion;
290
+ const _inputValue = String(this.suggestionLabel() ? suggestion[this.suggestionLabel()] : suggestion);
291
+ this.inputValue.set(_inputValue);
292
+ this._onChange?.(_value);
293
+ }
294
+ this.selected.emit(suggestion);
295
+ this.isOpen.set(false);
296
+ }
297
+ /**
298
+ * Limpa o valor selecionado no componente de autocomplete.
299
+ * Se o modo múltiplo estiver ativado, remove todos os valores selecionados.
300
+ * Caso contrário, define o valor como nulo.
301
+ * Também limpa as sugestões filtradas, fecha o painel de sugestões
302
+ * e limpa o valor do campo de entrada.
303
+ */
304
+ clear() {
305
+ if (this.multiple()) {
306
+ this.values.set([]);
307
+ this._onChange?.(this.values());
308
+ }
309
+ else {
310
+ this.value.set(null);
311
+ this._onChange?.(this.value());
312
+ }
313
+ this.filteredSuggestions.set([]);
314
+ this.isOpen.set(false);
315
+ this.inputValue.set('');
316
+ this.cleared.emit();
317
+ }
318
+ /**
319
+ * Alterna a exibição do dropdown de sugestões do autocomplete.
320
+ * Este método configura o debounce do input, verifica se há sugestões filtradas
321
+ * e, caso não haja sugestões e o texto do filtro esteja vazio, redefine as sugestões filtradas.
322
+ * Por fim, alterna o estado de abertura do dropdown.
323
+ */
324
+ toggleDropdown() {
325
+ this._setupInputDebounce();
326
+ if (this.filterText() === '') {
327
+ if (this.lazy()) {
328
+ this._lazyLoadSubject$.next('');
329
+ }
330
+ else {
331
+ this.resetFilteredSuggestions();
332
+ }
333
+ }
334
+ this.isOpen.set(!this.isOpen());
335
+ }
336
+ /**
337
+ * Função utilizada para otimizar a renderização de listas no Angular, permitindo que o framework
338
+ * identifique cada item de forma única pelo seu `id`. Deve ser utilizada como função de `trackBy`
339
+ * em diretivas como `*ngFor`.
340
+ * @param _ - Índice do item na lista (não utilizado).
341
+ * @param item - Objeto do tipo `SuggestionWrapper<T>` que representa o item atual.
342
+ * @returns O identificador único (`id`) do item.
343
+ */
344
+ trackById(_, item) {
345
+ return item.id;
346
+ }
347
+ /**
348
+ * Remove uma sugestão da lista de valores selecionados.
349
+ * @param suggestion O item a ser removido da lista de sugestões.
350
+ */
351
+ removeSuggestion(suggestion) {
352
+ const suggestionValue = this.suggestionValue();
353
+ this.values.set(this.values().filter((value) => {
354
+ if (suggestionValue) {
355
+ return value[suggestionValue] !== suggestion[suggestionValue];
356
+ }
357
+ return value !== suggestion;
358
+ }));
359
+ this._onChange?.(this.values());
360
+ this.unselected.emit(suggestion);
361
+ }
362
+ /**
363
+ * Reinicia a lista de sugestões filtradas.
364
+ * Se o modo lazy estiver ativado, emite um evento para carregar sugestões com uma consulta vazia.
365
+ * Em seguida, redefine as sugestões filtradas para o valor retornado por `internalSuggestion()`.
366
+ * @private
367
+ */
368
+ resetFilteredSuggestions() {
369
+ if (this.lazy()) {
370
+ this._lazyLoadSubject$.next('');
371
+ }
372
+ else {
373
+ this.filteredSuggestions.set(this.internalSuggestion());
374
+ }
375
+ }
376
+ /**
377
+ * Move o foco para a próxima sugestão na lista de sugestões, se houver.
378
+ * @private
379
+ * @param suggestions Lista de sugestões disponíveis.
380
+ */
381
+ _focusNextSuggestion(suggestions) {
382
+ let nextIndex = this.focusedIndex() + 1;
383
+ if (nextIndex < suggestions.length) {
384
+ this.focusedIndex.set(nextIndex);
385
+ this._scrollToFocusedSuggestion();
386
+ }
387
+ }
388
+ /**
389
+ * Move o foco para a sugestão anterior na lista de sugestões, se houver.
390
+ * @private
391
+ */
392
+ _focusPreviousSuggestion() {
393
+ let prevIndex = this.focusedIndex() - 1;
394
+ if (prevIndex >= 0) {
395
+ this.focusedIndex.set(prevIndex);
396
+ this._scrollToFocusedSuggestion();
397
+ }
398
+ }
399
+ /**
400
+ * Rola a lista de sugestões para garantir que a sugestão atualmente focada esteja visível.
401
+ * @private
402
+ */
403
+ _scrollToFocusedSuggestion() {
404
+ const id = this.filteredSuggestions()[this.focusedIndex()]?.id;
405
+ if (!id) {
406
+ return;
407
+ }
408
+ const el = document.getElementById(id);
409
+ el?.scrollIntoView({ block: 'nearest' });
410
+ }
411
+ /**
412
+ * Adiciona um identificador único a cada sugestão fornecida.
413
+ * @private
414
+ * @param suggestions - Um array de sugestões do tipo T.
415
+ * @returns Um array de objetos `SuggestionWrapper<T>`, cada um contendo a sugestão original e um identificador único.
416
+ */
417
+ _addIdToSuggestions(suggestions) {
418
+ const baseId = `${this.componentId}_suggestion`;
419
+ return suggestions?.map((suggestion, index) => {
420
+ return {
421
+ data: suggestion,
422
+ id: `${baseId}_${index++}`,
423
+ };
424
+ }) ?? [];
425
+ }
426
+ /**
427
+ * Configura o debounce e switchMap para lazy loading, resolvendo race conditions.
428
+ * Este método utiliza switchMap para cancelar requisições anteriores automaticamente
429
+ * quando uma nova busca é iniciada, evitando que resultados antigos sobrescrevam
430
+ * resultados mais recentes.
431
+ * @private
432
+ */
433
+ _setupLazyLoadDebounce() {
434
+ this._lazyLoadSubject$
435
+ .pipe(debounceTime(this.delay()), distinctUntilChanged(), switchMap((query) => {
436
+ this.loading.set(true);
437
+ // TODO: Manter fechado o dropdownd até a busca estiver concluída
438
+ return new Observable((subscriber) => {
439
+ const timeoutId = setTimeout(() => {
440
+ if (!subscriber.closed) {
441
+ subscriber.error(new Error('Lazy load timeout'));
442
+ }
443
+ }, 30000);
444
+ const responseCallback = (data) => {
445
+ clearTimeout(timeoutId);
446
+ if (!subscriber.closed) {
447
+ subscriber.next(data);
448
+ subscriber.complete();
449
+ }
450
+ };
451
+ this.lazyLoad.emit({ query, response: responseCallback });
452
+ });
453
+ }), takeUntilDestroyed(this._destroyRef))
454
+ .subscribe({
455
+ next: (data) => {
456
+ this.loading.set(false);
457
+ // TODO: Abrir o dropdown somente aqui
458
+ const wrappedSuggestions = this._addIdToSuggestions(data);
459
+ this.filteredSuggestions.set(wrappedSuggestions);
460
+ this.showEmptyMessage.set(wrappedSuggestions.length === 0);
461
+ },
462
+ error: (error) => {
463
+ this.loading.set(false);
464
+ // TODO: Abrir o dropdown somente aqui
465
+ console.error('Lazy load error:', error);
466
+ this.filteredSuggestions.set([]);
467
+ this.showEmptyMessage.set(true);
468
+ },
469
+ });
470
+ }
471
+ /**
472
+ * Configura o debounce para o input do autocomplete.
473
+ * Este método utiliza um Subject para escutar as mudanças no valor do input,
474
+ * aplicando um debounce com o tempo definido por `this.delay()`. Quando um novo valor é emitido:
475
+ * - Se houver valor, filtra as sugestões com base no texto digitado e atualiza a lista de sugestões filtradas.
476
+ * - Se não houver valor e o dropdown estiver ativo, reseta as sugestões filtradas.
477
+ * - Caso contrário, limpa a lista de sugestões filtradas.
478
+ * Também atualiza o estado da mensagem de lista vazia e, se a seleção for livre (`forceSelection` for falso),
479
+ * propaga a mudança de valor para o formulário.
480
+ * @private
481
+ */
482
+ _setupInputDebounce() {
483
+ this._inputSubject$
484
+ .pipe(debounceTime(this.delay()), distinctUntilChanged(), filter((value) => value.length >= this.minLengthToSearch() || value.length === 0), takeUntilDestroyed(this._destroyRef))
485
+ .subscribe((value) => {
486
+ if (value) {
487
+ this.filteredSuggestions.set(this.internalSuggestion().filter(({ data }) => {
488
+ const label = String(this.suggestionLabel() ? data[this.suggestionLabel()] : data);
489
+ return label.toLowerCase().includes(value.toLowerCase());
490
+ }));
491
+ this.showEmptyMessage.set(this.filteredSuggestions().length === 0);
492
+ }
493
+ else if (this.dropdown()) {
494
+ this.resetFilteredSuggestions();
495
+ }
496
+ else {
497
+ this.filteredSuggestions.set([]);
498
+ }
499
+ if (!this.forceSelection()) {
500
+ this._onChange?.(value);
501
+ }
502
+ });
503
+ }
504
+ /**
505
+ * Valida as entradas do componente de autocomplete.
506
+ * @private
507
+ * @throws {Error} Se as sugestões forem objetos e `suggestionLabel` não for fornecido.
508
+ */
509
+ _validateInputs() {
510
+ const suggestions = this.suggestions();
511
+ if (!suggestions.length) {
512
+ return;
513
+ }
514
+ const hasObjectSuggestions = suggestions.some((suggestion) => typeof suggestion === 'object' && suggestion !== null);
515
+ if (hasObjectSuggestions) {
516
+ if (!this.suggestionLabel()) {
517
+ throw new Error('The suggestionLabel input must be provided when suggestions are objects.');
518
+ }
519
+ }
520
+ }
521
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
522
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: AutocompleteComponent, isStandalone: true, selector: "s-autocomplete", inputs: { suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, suggestionValue: { classPropertyName: "suggestionValue", publicName: "suggestionValue", isSignal: true, isRequired: false, transformFunction: null }, suggestionLabel: { classPropertyName: "suggestionLabel", publicName: "suggestionLabel", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, virtualScroll: { classPropertyName: "virtualScroll", publicName: "virtualScroll", isSignal: true, isRequired: false, transformFunction: null }, virtualScrollItemSize: { classPropertyName: "virtualScrollItemSize", publicName: "virtualScrollItemSize", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, dropdown: { classPropertyName: "dropdown", publicName: "dropdown", isSignal: true, isRequired: false, transformFunction: null }, forceSelection: { classPropertyName: "forceSelection", publicName: "forceSelection", isSignal: true, isRequired: false, transformFunction: null }, checkmark: { classPropertyName: "checkmark", publicName: "checkmark", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, minLengthToSearch: { classPropertyName: "minLengthToSearch", publicName: "minLengthToSearch", isSignal: true, isRequired: false, transformFunction: null }, inputClass: { classPropertyName: "inputClass", publicName: "inputClass", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, values: { classPropertyName: "values", publicName: "values", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", values: "valuesChange", disabled: "disabledChange", lazyLoad: "lazyLoad", selected: "selected", unselected: "unselected", blurred: "blurred", cleared: "cleared", keyUp: "keyUp", focused: "focused", completeMethod: "completeMethod" }, host: { attributes: { "role": "combobox" }, listeners: { "window:resize": "onWindowResize()" }, properties: { "attr.aria-expanded": "isOpen()", "attr.aria-haspopup": "\"listbox\"", "attr.aria-owns": "isOpen() ? \"dropdown-container-\" + componentId : null" } }, providers: [
523
+ {
524
+ provide: NG_VALUE_ACCESSOR,
525
+ useExisting: forwardRef(() => AutocompleteComponent),
526
+ multi: true,
527
+ },
528
+ ], viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #containerDiv\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"flex h-[35px] w-full items-center overflow-hidden rounded-[4px] border focus-within:border-2 focus-within:border-primary hover:bg-grayscale-10\"\n [class]=\"inputClass()\"\n [ngClass]=\"{\n 'pointer-events-none border-grayscale-20 bg-grayscale-5 text-grayscale-30': disabled(),\n 'pointer-events-auto border-grayscale-30 bg-grayscale-0 text-grayscale-90': !disabled(),\n 'border-criticality-red': invalid(),\n }\"\n>\n <div\n class=\"flex flex-grow gap-2 px-2\"\n [ngClass]=\"{\n 'border-r': dropdown(),\n 'border-grayscale-20': dropdown() && disabled(),\n 'border-grayscale-30 focus-within:border-r-2 focus-within:border-r-primary': dropdown() && !disabled(),\n 'bg-grayscale-5': disabled(),\n 'bg-grayscale-0': !disabled(),\n }\"\n >\n @if (multiple() && values().length > 0) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (suggestion of values(); track suggestion) {\n <s-autocomplete-chip\n [suggestion]=\"suggestion\"\n [suggestionLabel]=\"suggestionLabel()\"\n (suggestionRemoved)=\"removeSuggestion($event)\"\n ></s-autocomplete-chip>\n }\n </div>\n }\n <input\n #inputEl\n class=\"min-h-[35px] grow outline-none\"\n type=\"text\"\n [placeholder]=\"placeholder() ?? 'platform.angular_components.type_to_search' | translate\"\n [readOnly]=\"readonly()\"\n [(ngModel)]=\"inputValue\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.aria-autocomplete]=\"multiple() ? 'list' : 'both'\"\n [attr.aria-activedescendant]=\"focusedIndex() >= 0 ? filteredSuggestions()[focusedIndex()].id : null\"\n role=\"searchbox\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (keyUp)=\"onKeyUp($event)\"\n (blur)=\"onInputBlur($event)\"\n (focus)=\"onInputFocus($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center justify-center\">\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"animate-spin\"\n >\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"9\"\n stroke=\"#428bca\"\n stroke-width=\"2\"\n fill=\"none\"\n stroke-dasharray=\"56.5\"\n stroke-dashoffset=\"10\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n } @else {\n @if (value() && !this.disabled()) {\n <button\n class=\"px-2\"\n (click)=\"clear()\"\n tabindex=\"-1\"\n >\n <i class=\"far fa-times text-grayscale-60\"></i>\n </button>\n }\n }\n </div>\n\n @if (dropdown()) {\n <button\n class=\"flex h-full w-[35px] flex-shrink-0 flex-grow-0 items-center justify-center hover:bg-grayscale-10\"\n (click)=\"toggleDropdown()\"\n >\n <i\n class=\"fas text-grayscale-90\"\n [class.fa-caret-down]=\"!isOpen()\"\n [class.fa-caret-up]=\"isOpen()\"\n ></i>\n </button>\n }\n</div>\n\n@if (showEmptyMessage() || (filteredSuggestions().length > 0 && !readonly())) {\n <ng-template\n #dropdownTemplate\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n (backdropClick)=\"isOpen.set(false)\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (detach)=\"isOpen.set(false)\"\n >\n <div\n [id]=\"'dropdown-container-' + componentId\"\n class=\"mt-0.5 rounded-[4px] bg-grayscale-0 py-1 shadow\"\n [style.width.px]=\"containerDiv.offsetWidth\"\n >\n <ul\n class=\"max-h-52 overflow-auto\"\n role=\"listbox\"\n >\n <!-- Virtual scroll -->\n @if (virtualScroll() && filteredSuggestions().length > 10) {\n <cdk-virtual-scroll-viewport\n [itemSize]=\"virtualScrollItemSize()\"\n class=\"h-52 overflow-auto\"\n >\n <ng-container\n *cdkVirtualFor=\"\n let suggestion of enrichedFilteredSuggestions();\n let i = $index;\n trackBy: trackById\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"suggestionItemTemplate\"\n [ngTemplateOutletContext]=\"{ suggestion, i }\"\n ></ng-container>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Normal list -->\n @if (!virtualScroll() || filteredSuggestions().length <= 10) {\n @for (suggestion of enrichedFilteredSuggestions(); track suggestion.id; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"suggestionItemTemplate\"\n [ngTemplateOutletContext]=\"{ suggestion, i }\"\n ></ng-container>\n }\n }\n\n @if (showEmptyMessage()) {\n <span class=\"p-3 text-grayscale-60\">{{\n emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n }}</span>\n }\n </ul>\n </div>\n </ng-template>\n}\n\n<ng-template\n #suggestionItemTemplate\n let-suggestion=\"suggestion\"\n let-i=\"i\"\n>\n <li\n [id]=\"suggestion.id\"\n class=\"rounded-sm flex cursor-pointer items-center gap-2 px-3 py-2 text-grayscale-70\"\n [class.bg-grayscale-10]=\"i === focusedIndex()\"\n [class.bg-grayscale-20]=\"suggestion.isSelected\"\n [attr.aria-selected]=\"suggestion.isSelected\"\n role=\"option\"\n (click)=\"selectSuggestion(suggestion.data)\"\n >\n @if (checkmark() && multiple() && suggestion.isSelected) {\n <i class=\"far fa-check\"></i>\n }\n {{ suggestionLabel() ? suggestion.data[suggestionLabel()!] : suggestion.data }}\n </li>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i3.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "directive", type: i4.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i4.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i4.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "component", type: AutocompleteChipComponent, selector: "s-autocomplete-chip", inputs: ["suggestion", "suggestionLabel"], outputs: ["suggestionRemoved"] }] });
529
+ }
530
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AutocompleteComponent, decorators: [{
531
+ type: Component,
532
+ args: [{ selector: 's-autocomplete', standalone: true, imports: [
533
+ CommonModule,
534
+ FormsModule,
535
+ ReactiveFormsModule,
536
+ OverlayModule,
537
+ ScrollingModule,
538
+ TranslateModule,
539
+ AutocompleteChipComponent,
540
+ ], providers: [
541
+ {
542
+ provide: NG_VALUE_ACCESSOR,
543
+ useExisting: forwardRef(() => AutocompleteComponent),
544
+ multi: true,
545
+ },
546
+ ], host: {
547
+ role: 'combobox',
548
+ '[attr.aria-expanded]': 'isOpen()',
549
+ '[attr.aria-haspopup]': '"listbox"',
550
+ '[attr.aria-owns]': 'isOpen() ? "dropdown-container-" + componentId : null',
551
+ '(window:resize)': 'onWindowResize()',
552
+ }, template: "<div\n #containerDiv\n cdkOverlayOrigin\n #trigger=\"cdkOverlayOrigin\"\n class=\"flex h-[35px] w-full items-center overflow-hidden rounded-[4px] border focus-within:border-2 focus-within:border-primary hover:bg-grayscale-10\"\n [class]=\"inputClass()\"\n [ngClass]=\"{\n 'pointer-events-none border-grayscale-20 bg-grayscale-5 text-grayscale-30': disabled(),\n 'pointer-events-auto border-grayscale-30 bg-grayscale-0 text-grayscale-90': !disabled(),\n 'border-criticality-red': invalid(),\n }\"\n>\n <div\n class=\"flex flex-grow gap-2 px-2\"\n [ngClass]=\"{\n 'border-r': dropdown(),\n 'border-grayscale-20': dropdown() && disabled(),\n 'border-grayscale-30 focus-within:border-r-2 focus-within:border-r-primary': dropdown() && !disabled(),\n 'bg-grayscale-5': disabled(),\n 'bg-grayscale-0': !disabled(),\n }\"\n >\n @if (multiple() && values().length > 0) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (suggestion of values(); track suggestion) {\n <s-autocomplete-chip\n [suggestion]=\"suggestion\"\n [suggestionLabel]=\"suggestionLabel()\"\n (suggestionRemoved)=\"removeSuggestion($event)\"\n ></s-autocomplete-chip>\n }\n </div>\n }\n <input\n #inputEl\n class=\"min-h-[35px] grow outline-none\"\n type=\"text\"\n [placeholder]=\"placeholder() ?? 'platform.angular_components.type_to_search' | translate\"\n [readOnly]=\"readonly()\"\n [(ngModel)]=\"inputValue\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.aria-autocomplete]=\"multiple() ? 'list' : 'both'\"\n [attr.aria-activedescendant]=\"focusedIndex() >= 0 ? filteredSuggestions()[focusedIndex()].id : null\"\n role=\"searchbox\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeyDown($event)\"\n (keyUp)=\"onKeyUp($event)\"\n (blur)=\"onInputBlur($event)\"\n (focus)=\"onInputFocus($event)\"\n />\n\n @if (loading()) {\n <div class=\"flex items-center justify-center\">\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n xmlns=\"http://www.w3.org/2000/svg\"\n class=\"animate-spin\"\n >\n <circle\n cx=\"10\"\n cy=\"10\"\n r=\"9\"\n stroke=\"#428bca\"\n stroke-width=\"2\"\n fill=\"none\"\n stroke-dasharray=\"56.5\"\n stroke-dashoffset=\"10\"\n stroke-linecap=\"round\"\n />\n </svg>\n </div>\n } @else {\n @if (value() && !this.disabled()) {\n <button\n class=\"px-2\"\n (click)=\"clear()\"\n tabindex=\"-1\"\n >\n <i class=\"far fa-times text-grayscale-60\"></i>\n </button>\n }\n }\n </div>\n\n @if (dropdown()) {\n <button\n class=\"flex h-full w-[35px] flex-shrink-0 flex-grow-0 items-center justify-center hover:bg-grayscale-10\"\n (click)=\"toggleDropdown()\"\n >\n <i\n class=\"fas text-grayscale-90\"\n [class.fa-caret-down]=\"!isOpen()\"\n [class.fa-caret-up]=\"isOpen()\"\n ></i>\n </button>\n }\n</div>\n\n@if (showEmptyMessage() || (filteredSuggestions().length > 0 && !readonly())) {\n <ng-template\n #dropdownTemplate\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n (backdropClick)=\"isOpen.set(false)\"\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n (detach)=\"isOpen.set(false)\"\n >\n <div\n [id]=\"'dropdown-container-' + componentId\"\n class=\"mt-0.5 rounded-[4px] bg-grayscale-0 py-1 shadow\"\n [style.width.px]=\"containerDiv.offsetWidth\"\n >\n <ul\n class=\"max-h-52 overflow-auto\"\n role=\"listbox\"\n >\n <!-- Virtual scroll -->\n @if (virtualScroll() && filteredSuggestions().length > 10) {\n <cdk-virtual-scroll-viewport\n [itemSize]=\"virtualScrollItemSize()\"\n class=\"h-52 overflow-auto\"\n >\n <ng-container\n *cdkVirtualFor=\"\n let suggestion of enrichedFilteredSuggestions();\n let i = $index;\n trackBy: trackById\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"suggestionItemTemplate\"\n [ngTemplateOutletContext]=\"{ suggestion, i }\"\n ></ng-container>\n </ng-container>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Normal list -->\n @if (!virtualScroll() || filteredSuggestions().length <= 10) {\n @for (suggestion of enrichedFilteredSuggestions(); track suggestion.id; let i = $index) {\n <ng-container\n [ngTemplateOutlet]=\"suggestionItemTemplate\"\n [ngTemplateOutletContext]=\"{ suggestion, i }\"\n ></ng-container>\n }\n }\n\n @if (showEmptyMessage()) {\n <span class=\"p-3 text-grayscale-60\">{{\n emptyMessage() ?? 'platform.angular_components.no_records_found' | translate\n }}</span>\n }\n </ul>\n </div>\n </ng-template>\n}\n\n<ng-template\n #suggestionItemTemplate\n let-suggestion=\"suggestion\"\n let-i=\"i\"\n>\n <li\n [id]=\"suggestion.id\"\n class=\"rounded-sm flex cursor-pointer items-center gap-2 px-3 py-2 text-grayscale-70\"\n [class.bg-grayscale-10]=\"i === focusedIndex()\"\n [class.bg-grayscale-20]=\"suggestion.isSelected\"\n [attr.aria-selected]=\"suggestion.isSelected\"\n role=\"option\"\n (click)=\"selectSuggestion(suggestion.data)\"\n >\n @if (checkmark() && multiple() && suggestion.isSelected) {\n <i class=\"far fa-check\"></i>\n }\n {{ suggestionLabel() ? suggestion.data[suggestionLabel()!] : suggestion.data }}\n </li>\n</ng-template>\n" }]
553
+ }], ctorParameters: () => [] });
554
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0b2NvbXBsZXRlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItY29tcG9uZW50cy9hdXRvY29tcGxldGUvc3JjL2xpYi9hdXRvY29tcGxldGUvYXV0b2NvbXBsZXRlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItY29tcG9uZW50cy9hdXRvY29tcGxldGUvc3JjL2xpYi9hdXRvY29tcGxldGUvYXV0b2NvbXBsZXRlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDekQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBYyxVQUFVLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDekksT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDaEUsT0FBTyxFQUF3QixXQUFXLEVBQUUsaUJBQWlCLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUzRyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFdkYsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sNERBQTRELENBQUM7Ozs7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QUMsMEVBQTBFLENBQUMsQ0FBQztZQUNoRyxDQUFDO1FBQ0wsQ0FBQztJQUNMLENBQUM7d0dBeGtCUSxxQkFBcUI7NEZBQXJCLHFCQUFxQiwydkdBZm5CO1lBQ1A7Z0JBQ0ksT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxxQkFBcUIsQ0FBQztnQkFDcEQsS0FBSyxFQUFFLElBQUk7YUFDZDtTQUNKLDhJQzdDTCw0a09BcUxBLDJDRHRKUSxZQUFZLG1TQUNaLFdBQVcsOG1CQUNYLG1CQUFtQiw4QkFDbkIsYUFBYSx1dERBQ2IsZUFBZSw4QkFDZixlQUFlLDRGQUNmLHlCQUF5Qjs7NEZBaUJwQixxQkFBcUI7a0JBNUJqQyxTQUFTOytCQUNJLGdCQUFnQixjQUNkLElBQUksV0FFUDt3QkFDTCxZQUFZO3dCQUNaLFdBQVc7d0JBQ1gsbUJBQW1CO3dCQUNuQixhQUFhO3dCQUNiLGVBQWU7d0JBQ2YsZUFBZTt3QkFDZix5QkFBeUI7cUJBQzVCLGFBQ1U7d0JBQ1A7NEJBQ0ksT0FBTyxFQUFFLGlCQUFpQjs0QkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsc0JBQXNCLENBQUM7NEJBQ3BELEtBQUssRUFBRSxJQUFJO3lCQUNkO3FCQUNKLFFBQ0s7d0JBQ0YsSUFBSSxFQUFFLFVBQVU7d0JBQ2hCLHNCQUFzQixFQUFFLFVBQVU7d0JBQ2xDLHNCQUFzQixFQUFFLFdBQVc7d0JBQ25DLGtCQUFrQixFQUFFLHVEQUF1RDt3QkFDM0UsaUJBQWlCLEVBQUUsa0JBQWtCO3FCQUN4QyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE92ZXJsYXlNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jZGsvb3ZlcmxheSc7XG5pbXBvcnQgeyBTY3JvbGxpbmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jZGsvc2Nyb2xsaW5nJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBDb21wb25lbnQsIGNvbXB1dGVkLCBEZXN0cm95UmVmLCBFbGVtZW50UmVmLCBmb3J3YXJkUmVmLCBpbmplY3QsIGlucHV0LCBtb2RlbCwgb3V0cHV0LCBzaWduYWwsIHZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgQ29udHJvbFZhbHVlQWNjZXNzb3IsIEZvcm1zTW9kdWxlLCBOR19WQUxVRV9BQ0NFU1NPUiwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuaW1wb3J0IHsgVHJhbnNsYXRlTW9kdWxlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIGRpc3RpbmN0VW50aWxDaGFuZ2VkLCBmaWx0ZXIsIHN3aXRjaE1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgQXV0b2NvbXBsZXRlQ2hpcENvbXBvbmVudCB9IGZyb20gJy4vY29tcG9uZW50cy9hdXRvY29tcGxldGUtY2hpcC9hdXRvY29tcGxldGUtY2hpcC5jb21wb25lbnQnO1xuXG4vKipcbiAqIFJlcHJlc2VudGEgdW0gaXRlbSBkZSBzdWdlc3TDo28gZW5jYXBzdWxhZG8sIHV0aWxpemFkbyBlbSBjb21wb25lbnRlcyBkZSBhdXRvY29tcGxldGUuXG4gKiBAdGVtcGxhdGUgVCBUaXBvIGRvcyBkYWRvcyBhc3NvY2lhZG9zIMOgIHN1Z2VzdMOjby5cbiAqIEBwcm9wZXJ0eSBkYXRhIE9zIGRhZG9zIGRhIHN1Z2VzdMOjby5cbiAqIEBwcm9wZXJ0eSBpZCBJZGVudGlmaWNhZG9yIMO6bmljbyBkYSBzdWdlc3TDo28uXG4gKiBAcHJvcGVydHkgW2lzU2VsZWN0ZWRdIEluZGljYSBzZSBhIHN1Z2VzdMOjbyBlc3TDoSBzZWxlY2lvbmFkYS5cbiAqL1xuaW50ZXJmYWNlIFN1Z2dlc3Rpb25XcmFwcGVyPFQ+IHtcbiAgICBkYXRhOiBUO1xuICAgIGlkOiBzdHJpbmc7XG4gICAgaXNTZWxlY3RlZD86IGJvb2xlYW47XG59XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAncy1hdXRvY29tcGxldGUnLFxuICAgIHN0YW5kYWxvbmU6IHRydWUsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2F1dG9jb21wbGV0ZS5jb21wb25lbnQuaHRtbCcsXG4gICAgaW1wb3J0czogW1xuICAgICAgICBDb21tb25Nb2R1bGUsXG4gICAgICAgIEZvcm1zTW9kdWxlLFxuICAgICAgICBSZWFjdGl2ZUZvcm1zTW9kdWxlLFxuICAgICAgICBPdmVybGF5TW9kdWxlLFxuICAgICAgICBTY3JvbGxpbmdNb2R1bGUsXG4gICAgICAgIFRyYW5zbGF0ZU1vZHVsZSxcbiAgICAgICAgQXV0b2NvbXBsZXRlQ2hpcENvbXBvbmVudCxcbiAgICBdLFxuICAgIHByb3ZpZGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICAgICAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IEF1dG9jb21wbGV0ZUNvbXBvbmVudCksXG4gICAgICAgICAgICBtdWx0aTogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICBdLFxuICAgIGhvc3Q6IHtcbiAgICAgICAgcm9sZTogJ2NvbWJvYm94JyxcbiAgICAgICAgJ1thdHRyLmFyaWEtZXhwYW5kZWRdJzogJ2lzT3BlbigpJyxcbiAgICAgICAgJ1thdHRyLmFyaWEtaGFzcG9wdXBdJzogJ1wibGlzdGJveFwiJyxcbiAgICAgICAgJ1thdHRyLmFyaWEtb3duc10nOiAnaXNPcGVuKCkgPyBcImRyb3Bkb3duLWNvbnRhaW5lci1cIiArIGNvbXBvbmVudElkIDogbnVsbCcsXG4gICAgICAgICcod2luZG93OnJlc2l6ZSknOiAnb25XaW5kb3dSZXNpemUoKScsXG4gICAgfSxcbn0pXG5leHBvcnQgY2xhc3MgQXV0b2NvbXBsZXRlQ29tcG9uZW50PFQ+IGltcGxlbWVudHMgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xuICAgIHByaXZhdGUgc3RhdGljIG5leHRJZCA9IDA7XG5cbiAgICBwdWJsaWMgc3VnZ2VzdGlvbnMgPSBpbnB1dDxUW10+KFtdKTtcbiAgICBwdWJsaWMgcGxhY2Vob2xkZXIgPSBpbnB1dDxzdHJpbmc+KCk7XG4gICAgcHVibGljIHN1Z2dlc3Rpb25WYWx1ZSA9IGlucHV0PGtleW9mIFQ+KCk7XG4gICAgcHVibGljIHN1Z2dlc3Rpb25MYWJlbCA9IGlucHV0PGtleW9mIFQ+KCk7XG4gICAgcHVibGljIHJlYWRvbmx5ID0gaW5wdXQoZmFsc2UpO1xuICAgIHB1YmxpYyBlbXB0eU1lc3NhZ2UgPSBpbnB1dDxzdHJpbmc+KCk7XG4gICAgcHVibGljIGRlbGF5ID0gaW5wdXQoMzAwKTtcbiAgICBwdWJsaWMgaW52YWxpZCA9IGlucHV0KGZhbHNlKTtcbiAgICBwdWJsaWMgdmlydHVhbFNjcm9sbCA9IGlucHV0KGZhbHNlKTtcbiAgICBwdWJsaWMgdmlydHVhbFNjcm9sbEl0ZW1TaXplID0gaW5wdXQoMzcpO1xuICAgIHB1YmxpYyBsYXp5ID0gaW5wdXQoZmFsc2UpO1xuICAgIHB1YmxpYyBkcm9wZG93biA9IGlucHV0KGZhbHNlKTtcbiAgICBwdWJsaWMgZm9yY2VTZWxlY3Rpb24gPSBpbnB1dChmYWxzZSk7XG4gICAgcHVibGljIGNoZWNrbWFyayA9IGlucHV0KGZhbHNlKTtcbiAgICBwdWJsaWMgbXVsdGlwbGUgPSBpbnB1dChmYWxzZSk7XG4gICAgcHVibGljIG1pbkxlbmd0aFRvU2VhcmNoID0gaW5wdXQoMSk7XG4gICAgcHVibGljIGlucHV0Q2xhc3MgPSBpbnB1dDxzdHJpbmc+KCcnKTtcblxuICAgIHB1YmxpYyB2YWx1ZSA9IG1vZGVsPFQgfCBudWxsPigpO1xuICAgIHB1YmxpYyB2YWx1ZXMgPSBtb2RlbDxUW10+KFtdKTtcbiAgICBwdWJsaWMgZGlzYWJsZWQgPSBtb2RlbChmYWxzZSk7XG5cbiAgICBwdWJsaWMgbGF6eUxvYWQgPSBvdXRwdXQ8eyBxdWVyeTogc3RyaW5nOyByZXNwb25zZTogKGRhdGE6IFRbXSkgPT4gdm9pZCB9PigpO1xuICAgIHB1YmxpYyBzZWxlY3RlZCA9IG91dHB1dDxUPigpO1xuICAgIHB1YmxpYyB1bnNlbGVjdGVkID0gb3V0cHV0PFQ+KCk7XG4gICAgcHVibGljIGJsdXJyZWQgPSBvdXRwdXQ8RXZlbnQ+KCk7XG4gICAgcHVibGljIGNsZWFyZWQgPSBvdXRwdXQoKTtcbiAgICBwdWJsaWMga2V5VXAgPSBvdXRwdXQ8RXZlbnQ+KCk7XG4gICAgcHVibGljIGZvY3VzZWQgPSBvdXRwdXQ8YW55PigpO1xuICAgIHB1YmxpYyBjb21wbGV0ZU1ldGhvZCA9IG91dHB1dDx7IHF1ZXJ5OiBzdHJpbmcgfT4oKTtcblxuICAgIHB1YmxpYyBmb2N1c2VkSW5kZXggPSBzaWduYWwoLTEpO1xuICAgIHB1YmxpYyBpc09wZW4gPSBzaWduYWwoZmFsc2UpO1xuICAgIHB1YmxpYyBmaWx0ZXJlZFN1Z2dlc3Rpb25zID0gc2lnbmFsPFN1Z2dlc3Rpb25XcmFwcGVyPFQ+W10+KFtdKTtcbiAgICBwdWJsaWMgc2hvd0VtcHR5TWVzc2FnZSA9IHNpZ25hbChmYWxzZSk7XG4gICAgcHVibGljIGZpbHRlclRleHQgPSBzaWduYWwoJycpO1xuICAgIHB1YmxpYyBpbnB1dFZhbHVlID0gc2lnbmFsKCcnKTtcbiAgICBwdWJsaWMgbG9hZGluZyA9IHNpZ25hbChmYWxzZSk7XG5cbiAgICBwdWJsaWMgY29tcG9uZW50SWQgPSBgYXV0b2NvbXBsZXRlXyR7QXV0b2NvbXBsZXRlQ29tcG9uZW50Lm5leHRJZCsrfWA7XG4gICAgcHVibGljIGlucHV0RWwgPSB2aWV3Q2hpbGQ8RWxlbWVudFJlZj4oJ2lucHV0RWwnKTtcblxuICAgIHByaXZhdGUgX2lucHV0U3ViamVjdCQgPSBuZXcgU3ViamVjdDxzdHJpbmc+KCk7XG4gICAgcHJpdmF0ZSBfbGF6eUxvYWRTdWJqZWN0JCA9IG5ldyBTdWJqZWN0PHN0cmluZz4oKTtcbiAgICBwcml2YXRlIF9kZXN0cm95UmVmID0gaW5qZWN0KERlc3Ryb3lSZWYpO1xuICAgIHByaXZhdGUgX29uQ2hhbmdlPzogKHZhbHVlOiBhbnkgfCBhbnlbXSkgPT4gdm9pZDtcbiAgICBwcml2YXRlIF9vblRvdWNoZWQ/OiAoKSA9PiB2b2lkO1xuXG4gICAgLyoqXG4gICAgICogQ29tcHV0ZWQgcXVlIHJldG9ybmEgdW1hIGxpc3RhIGRlIHN1Z2VzdMO1ZXMgZG8gdGlwbyBgU3VnZ2VzdGlvbldyYXBwZXI8VD5gLFxuICAgICAqIGFkaWNpb25hbmRvIHVtIGlkZW50aWZpY2Fkb3Igw7puaWNvIGEgY2FkYSBzdWdlc3TDo28uXG4gICAgICogQHJldHVybnMgVW1hIGxpc3RhIGRlIHN1Z2VzdMO1ZXMgcHJvY2Vzc2FkYXMgY29tIGlkZW50aWZpY2Fkb3JlcyDDum5pY29zLlxuICAgICAqL1xuICAgIHB1YmxpYyBpbnRlcm5hbFN1Z2dlc3Rpb24gPSBjb21wdXRlZDxTdWdnZXN0aW9uV3JhcHBlcjxUPltdPigoKSA9PiB7XG4gICAgICAgIGNvbnN0IG9wdHMgPSB0aGlzLnN1Z2dlc3Rpb25zKCk7XG4gICAgICAgIHJldHVybiB0aGlzLl9hZGRJZFRvU3VnZ2VzdGlvbnMob3B0cyk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBSZXRvcm5hIHVtIGNvbmp1bnRvIChgU2V0YCkgY29tIG9zIElEcyBkYXMgc3VnZXN0w7VlcyBzZWxlY2lvbmFkYXMuXG4gICAgICovXG4gICAgcHVibGljIHNlbGVjdGVkU3VnZ2VzdGlvbklkcyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICAgICAgaWYgKCF0aGlzLm11bHRpcGxlKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZXMgPSB0aGlzLnZhbHVlcygpO1xuXG4gICAgICAgIHJldHVybiBuZXcgU2V0KFxuICAgICAgICAgICAgY3VycmVudFZhbHVlcy5tYXAoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW50ZXJuYWxTdWdnZXN0aW9uKCkuZmluZCgocykgPT4gSlNPTi5zdHJpbmdpZnkocy5kYXRhKSA9PT0gSlNPTi5zdHJpbmdpZnkodmFsdWUpKT8uaWQ7XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIFJldG9ybmEgdW1hIGxpc3RhIGRlIHN1Z2VzdMO1ZXMgZmlsdHJhZGFzLCBlbnJpcXVlY2lkYXMgY29tIGEgcHJvcHJpZWRhZGUgYGlzU2VsZWN0ZWRgLlxuICAgICAqIENhZGEgc3VnZXN0w6NvIHJlY2ViZSB1bSBjYW1wbyBib29sZWFubyBgaXNTZWxlY3RlZGAgaW5kaWNhbmRvIHNlIGVsYSBlc3TDoSBzZWxlY2lvbmFkYSxcbiAgICAgKiBjb20gYmFzZSBub3MgSURzIGRhcyBzdWdlc3TDtWVzIHNlbGVjaW9uYWRhcyBlIG5vIHZhbG9yIGRhIHN1Z2VzdMOjby5cbiAgICAgKiBAcmV0dXJucyBVbWEgbGlzdGEgZGUgc3VnZXN0w7VlcyBmaWx0cmFkYXMsIGNhZGEgdW1hIGNvbSBhIHByb3ByaWVkYWRlIGFkaWNpb25hbCBgaXNTZWxlY3RlZGAuXG4gICAgICovXG4gICAgcHVibGljIGVucmljaGVkRmlsdGVyZWRTdWdnZXN0aW9ucyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICAgICAgY29uc3QgZmlsdGVyZWQgPSB0aGlzLmZpbHRlcmVkU3VnZ2VzdGlvbnMoKTtcbiAgICAgICAgY29uc3Qgc2VsZWN0ZWRJZHMgPSB0aGlzLnNlbGVjdGVkU3VnZ2VzdGlvbklkcygpO1xuXG4gICAgICAgIHJldHVybiBmaWx0ZXJlZC5tYXAoKHN1Z2dlc3Rpb24pID0+ICh7XG4gICAgICAgICAgICAuLi5zdWdnZXN0aW9uLFxuICAgICAgICAgICAgaXNTZWxlY3RlZDogc2VsZWN0ZWRJZHMuaGFzKHN1Z2dlc3Rpb24uaWQpLFxuICAgICAgICB9KSk7XG4gICAgfSk7XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5fdmFsaWRhdGVJbnB1dHMoKTtcbiAgICAgICAgdGhpcy5fc2V0dXBJbnB1dERlYm91bmNlKCk7XG4gICAgICAgIHRoaXMuX3NldHVwTGF6eUxvYWREZWJvdW5jZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlZmluZSBvIHZhbG9yIGRvIGF1dG9jb21wbGV0ZS5cbiAgICAgKiBAcGFyYW0gdmFsdWUgVmFsb3IgYSBzZXIgZGVmaW5pZG8sIMO6bmljbyBvdSBhcnJheSwgY29uZm9ybWUgc2VsZcOnw6NvIG3Dumx0aXBsYS5cbiAgICAgKiBAdGhyb3dzIFNlIG3Dumx0aXBsbyBmb3IgZmFsc28gZSB2YWx1ZSBmb3IgYXJyYXkuXG4gICAgICovXG4gICAgcHVibGljIHdyaXRlVmFsdWUodmFsdWU6IFQgfCBUW10pOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgc3VnZ2VzdGlvbkxhYmVsID0gdGhpcy5zdWdnZXN0aW9uTGFiZWwoKTtcblxuICAgICAgICBpZiAodmFsdWUgJiYgdGhpcy5tdWx0aXBsZSgpKSB7XG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlcy5zZXQodmFsdWUpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlcy5zZXQoW3ZhbHVlXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RoZSB2YWx1ZSBtdXN0IG5vdCBiZSBhbiBhcnJheSB3aGVuIG11bHRpcGxlIGlzIGZhbHNlLicpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlLnNldCh2YWx1ZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuaW5wdXRWYWx1ZS5zZXQoIXZhbHVlID8gJycgOiBzdWdnZXN0aW9uTGFiZWwgPyBTdHJpbmcodmFsdWVbc3VnZ2VzdGlvbkxhYmVsXSkgOiBTdHJpbmcodmFsdWUpKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdHJhIHVtYSBmdW7Dp8OjbyBkZSBjYWxsYmFjayBxdWUgc2Vyw6EgY2hhbWFkYSBzZW1wcmUgcXVlIG8gdmFsb3IgZG8gY29tcG9uZW50ZSBtdWRhci5cbiAgICAgKiBAcGFyYW0gb25DaGFuZ2UgRnVuw6fDo28gYSBzZXIgY2hhbWFkYSBxdWFuZG8gbyB2YWxvciBtdWRhci4gUmVjZWJlIG8gbm92byB2YWxvciBjb21vIGFyZ3VtZW50bywgcXVlIHBvZGUgc2VyIHVtIMO6bmljbyB2YWxvciBvdSB1bSBhcnJheSBkZSB2YWxvcmVzLlxuICAgICAqL1xuICAgIHB1YmxpYyByZWdpc3Rlck9uQ2hhbmdlKG9uQ2hhbmdlOiAodmFsdWU6IGFueSB8IGFueVtdKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX29uQ2hhbmdlID0gb25DaGFuZ2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVnaXN0cmEgdW1hIGZ1bsOnw6NvIGRlIGNhbGxiYWNrIHF1ZSBzZXLDoSBjaGFtYWRhIHF1YW5kbyBvIGNvbXBvbmVudGUgZm9yIHRvY2FkbyAocGVyZGVyIG8gZm9jbykuXG4gICAgICogQHBhcmFtIG9uVG91Y2hlZCBGdW7Dp8OjbyBkZSBjYWxsYmFjayBhIHNlciBjaGFtYWRhIHF1YW5kbyBvIGNvbXBvbmVudGUgZm9yIHRvY2Fkby5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVnaXN0ZXJPblRvdWNoZWQob25Ub3VjaGVkOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX29uVG91Y2hlZCA9IG9uVG91Y2hlZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEZWZpbmUgbyBlc3RhZG8gZGUgZGVzYWJpbGl0YWRvIGRvIGNvbXBvbmVudGUuXG4gICAgICogQHBhcmFtIGRpc2FibGVkIEluZGljYSBzZSBvIGNvbXBvbmVudGUgZGV2ZSBzZXIgZGVzYWJpbGl0YWRvIChgdHJ1ZWApIG91IGhhYmlsaXRhZG8gKGBmYWxzZWApLlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXREaXNhYmxlZFN0YXRlPyhkaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICB0aGlzLmRpc2FibGVkLnNldChkaXNhYmxlZCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFuaXB1bGEgbyBldmVudG8gZGUgZW50cmFkYSBkbyB1c3XDoXJpbyBubyBjYW1wbyBkZSB0ZXh0byBkbyBhdXRvY29tcGxldGUuXG4gICAgICogRXN0ZSBtw6l0b2RvIMOpIGNoYW1hZG8gc2VtcHJlIHF1ZSBvIHVzdcOhcmlvIGRpZ2l0YSBhbGdvIG5vIGNhbXBvIGRlIGVudHJhZGEuXG4gICAgICogRWxlIGV4ZWN1dGEgYXMgc2VndWludGVzIGHDp8O1ZXM6XG4gICAgICogLSBEaXNwYXJhIG8gY2FsbGJhY2sgZGUgXCJ0b3VjaGVkXCIgcGFyYSBjb250cm9sZSBkZSBmb3JtdWzDoXJpb3MuXG4gICAgICogLSBPYnTDqW0gbyB2YWxvciBhdHVhbCBkbyBjYW1wbyBkZSBlbnRyYWRhLlxuICAgICAqIC0gU2UgbyBtb2RvIGxhenkgZXN0aXZlciBhdGl2YWRvLCBlbWl0ZSBvIGV2ZW50byBkZSBsYXp5TG9hZCBjb20gYSBjb25zdWx0YSBlIGFicmUgbyBwYWluZWwgZGUgc3VnZXN0w7Vlcy5cbiAgICAgKiAtIENhc28gY29udHLDoXJpbywgYXR1YWxpemEgbyB0ZXh0byBkZSBmaWx0cm8sIG5vdGlmaWNhIG9zIG9ic2VydmFkb3JlcyBlIGFicmUgbyBwYWluZWwgZGUgc3VnZXN0w7VlcyBzZSBob3V2ZXIgc3VnZXN0w7VlcyBkaXNwb27DrXZlaXMuXG4gICAgICogQHBhcmFtIGV2ZW50IEV2ZW50byBkZSBlbnRyYWRhIGRvIHRpcG8gYEV2ZW50YCBwcm92ZW5pZW50ZSBkbyBjYW1wbyBkZSB0ZXh0by5cbiAgICAgKi9cbiAgICBwdWJsaWMgb25JbnB1dChldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fb25Ub3VjaGVkPy4oKTtcblxuICAgICAgICBjb25zdCB2YWx1ZSA9IChldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkudmFsdWU7XG5cbiAgICAgICAgaWYgKHRoaXMubGF6eSgpKSB7XG4gICAgICAgICAgICB0aGlzLl9sYXp5TG9hZFN1YmplY3QkLm5leHQodmFsdWUpO1xuICAgICAgICAgICAgdGhpcy5pc09wZW4uc2V0KHRydWUpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5maWx0ZXJUZXh0LnNldCh2YWx1ZSk7XG5cbiAgICAgICAgdGhpcy5jb21wbGV0ZU1ldGhvZC5lbWl0KHsgcXVlcnk6IHZhbHVlIH0pO1xuXG4gICAgICAgIHRoaXMuX2lucHV0U3ViamVjdCQubmV4dCh2YWx1ZSk7XG5cbiAgICAgICAgaWYgKHRoaXMuc3VnZ2VzdGlvbnMoKSkge1xuICAgICAgICAgICAgdGhpcy5pc09wZW4uc2V0KHRydWUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFuaXB1bGEgbyBldmVudG8gZGUgcGVyZGEgZGUgZm9jbyAoYmx1cikgZG8gY2FtcG8gZGUgZW50cmFkYSBkbyBhdXRvY29tcGxldGUuXG4gICAgICogRXN0ZSBtw6l0b2RvIHZlcmlmaWNhIHNlIG8gdmFsb3IgZGlnaXRhZG8gcGVsbyB1c3XDoXJpbyBjb3JyZXNwb25kZSBleGF0YW1lbnRlIGEgYWxndW0gZG9zIGl0ZW5zIHN1Z2VyaWRvcy5cbiAgICAgKiAtIFNlIGhvdXZlciBjb3JyZXNwb25kw6puY2lhOlxuICAgICAqICAgLSBObyBtb2RvIG3Dumx0aXBsbyAoYG11bHRpcGxlYCksIGFkaWNpb25hIG8gaXRlbSBzZWxlY2lvbmFkbyDDoCBsaXN0YSBkZSB2YWxvcmVzLCBjYXNvIGFpbmRhIG7Do28gZXN0ZWphIHByZXNlbnRlLlxuICAgICAqICAgLSBObyBtb2RvIHNpbXBsZXMsIHNlbGVjaW9uYSBvIGl0ZW0gY29ycmVzcG9uZGVudGUgc2UgYWluZGEgbsOjbyBlc3RpdmVyIHNlbGVjaW9uYWRvLlxuICAgICAqIC0gU2UgbsOjbyBob3V2ZXIgY29ycmVzcG9uZMOqbmNpYSwgbGltcGEgbyBjYW1wbyBkZSBlbnRyYWRhLlxuICAgICAqL1xuICAgIHB1YmxpYyBvbklucHV0Qmx1cihldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgaW5wdXRWYWx1ZSA9IFN0cmluZyh0aGlzLmlucHV0VmFsdWUoKSkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgY29uc3Qgc3VnZ2VzdGlvbnMgPSB0aGlzLmludGVybmFsU3VnZ2VzdGlvbigpO1xuXG4gICAgICAgIGNvbnN0IG1hdGNoID0gc3VnZ2VzdGlvbnMuZmluZCgoeyBkYXRhIH0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGxhYmVsID0gdGhpcy5zdWdnZXN0aW9uTGFiZWwoKSA/IGRhdGFbdGhpcy5zdWdnZXN0aW9uTGFiZWwoKSFdIDogZGF0YTtcbiAgICAgICAgICAgIHJldHVybiBTdHJpbmcobGFiZWwpLnRvTG93ZXJDYXNlKCkgPT09IGlucHV0VmFsdWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICAgICAgaWYgKHRoaXMubXVsdGlwbGUoKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZXMgPSB0aGlzLnZhbHVlcygpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGV4aXN0cyA9IGN1cnJlbnRWYWx1ZXMuc29tZShcbiAgICAgICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgKHRoaXMuc3VnZ2VzdGlvblZhbHVlKCkgPyB2YWx1ZVt0aGlzLnN1Z2dlc3Rpb25WYWx1ZSgpIV0gOiB2YWx1ZSkgPT09XG4gICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5zdWdnZXN0aW9uVmFsdWUoKSA/IG1hdGNoLmRhdGFbdGhpcy5zdWdnZXN0aW9uVmFsdWUoKSFdIDogbWF0Y2guZGF0YSksXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBpZiAoIWV4aXN0cykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnZhbHVlcy5zZXQoWy4uLmN1cnJlbnRWYWx1ZXMsIG1hdGNoLmRhdGFdKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fb25DaGFuZ2U/Lih0aGlzLnZhbHVlcygpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5pbnB1dFZhbHVlLnNldCgnJyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnZhbHVlKCkgIT09IG1hdGNoLmRhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZWxlY3RTdWdnZXN0aW9uKG1hdGNoLmRhdGEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaW5wdXRWYWx1ZS5zZXQoJycpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGlzcGFyYSBvIGV2ZW50byBkZSBmb2NvIHF1YW5kbyBvIGNhbXBvIGRlIGVudHJhZGEgcmVjZWJlIGZvY28uXG4gICAgICogQHBhcmFtIGV2ZW50IE8gZXZlbnRvIGRlIGZvY28gZGlzcGFyYWRvIHBlbG8gZWxlbWVudG8gZGUgZW50cmFkYS5cbiAgICAgKi9cbiAgICBwdWJsaWMgb25JbnB1dEZvY3VzKGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgICAgICB0aGlzLmZvY3VzZWQuZW1pdChldmVudCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFuaXB1bGEgZXZlbnRvcyBkZSB0ZWNsYWRvIG5vIGNvbXBvbmVudGUgZGUgYXV0b2NvbXBsZXRlLlxuICAgICAqIEVzdGUgbcOpdG9kbyBnZXJlbmNpYSBhIG5hdmVnYcOnw6NvIGUgc2VsZcOnw6NvIGRlIHN1Z2VzdMO1ZXMgdXNhbmRvIGFzIHRlY2xhcyBkbyB0ZWNsYWRvLlxuICAgICAqIC0gJ0Fycm93RG93bic6IE1vdmUgbyBmb2NvIHBhcmEgYSBwcsOzeGltYSBzdWdlc3TDo28uXG4gICAgICogLSAnQXJyb3dVcCc6IE1vdmUgbyBmb2NvIHBhcmEgYSBzdWdlc3TDo28gYW50ZXJpb3IuXG4gICAgICogLSAnRW50ZXInIG91ICdUYWInOiBTZWxlY2lvbmEgYSBzdWdlc3TDo28gYXR1YWxtZW50ZSBmb2NhZGEgZSBmZWNoYSBhIGxpc3RhIGRlIHN1Z2VzdMO1ZXMuXG4gICAgICogLSAnRXNjYXBlJzogRmVjaGEgYSBsaXN0YSBkZSBzdWdlc3TDtWVzIHNlbSBzZWxlY2lvbmFyIG5lbmh1bSBpdGVtLlxuICAgICAqIEBwYXJhbSBldmVudCBPIGV2ZW50byBkZSB0ZWNsYWRvIGRpc3BhcmFkbyBwZWxvIHVzdcOhcmlvLlxuICAgICAqL1xuICAgIHB1YmxpYyBvbktleURvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcbiAgICAgICAgY29uc3Qgc3VnZ2VzdGlvbnMgPSB0aGlzLmZpbHRlcmVkU3VnZ2VzdGlvbnMoKTtcblxuICAgICAgICB0aGlzLl9vblRvdWNoZWQ/LigpO1xuXG4gICAgICAgIGNvbnN0IF9zZWxlY3RTdWdnZXN0aW9uID0gKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuZm9jdXNlZEluZGV4KCkgPj0gMCAmJiB0aGlzLmZvY3VzZWRJbmRleCgpIDwgc3VnZ2VzdGlvbnMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbGVjdFN1Z2dlc3Rpb24oc3VnZ2VzdGlvbnNbdGhpcy5mb2N1c2VkSW5kZXgoKV0uZGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgc3dpdGNoIChldmVudC5rZXkpIHtcbiAgICAgICAgICAgIGNhc2UgJ0Fycm93RG93bic6XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9mb2N1c05leHRTdWdnZXN0aW9uKHN1Z2dlc3Rpb25zKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ0Fycm93VXAnOlxuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdGhpcy5fZm9jdXNQcmV2aW91c1N1Z2dlc3Rpb24oKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ0VudGVyJzpcbiAgICAgICAgICAgIGNhc2UgJ1RhYic6XG4gICAgICAgICAgICAgICAgX3NlbGVjdFN1Z2dlc3Rpb24oKTtcbiAgICAgICAgICAgICAgICB0aGlzLmlzT3Blbi5zZXQoZmFsc2UpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnRXNjYXBlJzpcbiAgICAgICAgICAgICAgICB0aGlzLmlzT3Blbi5zZXQoZmFsc2UpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRW1pdGUgdW0gZXZlbnRvIHF1YW5kbyB1bWEgdGVjbGEgw6kgbGliZXJhZGEgbm8gY29tcG9uZW50ZS4gICAgICpcbiAgICAgKiBAcGFyYW0gZXZlbnQgTyBldmVudG8gZGUgdGVjbGFkbyBhc3NvY2lhZG8gw6AgdGVjbGEgbGliZXJhZGEuXG4gICAgICovXG4gICAgcHVibGljIG9uS2V5VXAoZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgICAgIHRoaXMua2V5VXAuZW1pdChldmVudCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmVjaGEgbyBkcm9wZG93biBlbSBldmVudG9zIGRlIHJlZGltZW5zaW9uYW1lbnRvIGRlIGphbmVsYS5cbiAgICAgKi9cbiAgICBwdWJsaWMgb25XaW5kb3dSZXNpemUoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmlzT3BlbigpKSB7XG4gICAgICAgICAgICB0aGlzLmlzT3Blbi5zZXQoZmFsc2UpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VsZWNpb25hIHVtYSBzdWdlc3TDo28gZGEgbGlzdGEgZGUgc3VnZXN0w7Vlcy5cbiAgICAgKiBTZSBvIG1vZG8gbcO6bHRpcGxvIGVzdGl2ZXIgYXRpdmFkbyAoYG11bHRpcGxlKClgIHJldG9ybmEgdHJ1ZSksIGFkaWNpb25hIGEgc3VnZXN0w6NvIMOgIGxpc3RhIGRlIHN1Z2dlc3TDtWVzIHNlbGVjaW9uYWRhcyxcbiAgICAgKiBjYXNvIGVsYSBhaW5kYSBuw6NvIGVzdGVqYSBwcmVzZW50ZS4gRW0gc2VndWlkYSwgbGltcGEgbyB2YWxvciBkbyBjYW1wbyBkZSBlbnRyYWRhLlxuICAgICAqIFNlIG8gbW9kbyBtw7psdGlwbG8gbsOjbyBlc3RpdmVyIGF0aXZhZG8sIGRlZmluZSBhIHN1Z2VzdMOjbyBjb21vIHZhbG9yIHNlbGVjaW9uYWRvIGUgYXR1YWxpemEgbyBjYW1wbyBkZSBlbnRyYWRhXG4gICAgICogY29tIG8gcsOzdHVsbyBjb3JyZXNwb25kZW50ZS5cbiAgICAgKiBFbSBhbWJvcyBvcyBjYXNvcywgZGlzcGFyYSBvIGNhbGxiYWNrIGBfb25DaGFuZ2VgIGNvbSBvIG5vdm8gdmFsb3IgZSBmZWNoYSBvIHBhaW5lbCBkZSBzdWdlc3TDtWVzLlxuICAgICAqIEBwYXJhbSBzdWdnZXN0aW9uIC0gQSBzdWdlc3TDo28gYSBzZXIgc2VsZWNpb25hZGEuXG4gICAgICovXG4gICAgcHVibGljIHNlbGVjdFN1Z2dlc3Rpb24oc3VnZ2VzdGlvbjogVCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5tdWx0aXBsZSgpKSB7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50VmFsdWVzID0gdGhpcy52YWx1ZXMoKTtcbiAgICAgICAgICAgIGNvbnN0IGV4aXN0cyA9IGN1cnJlbnRWYWx1ZXMuc29tZShcbiAgICAgICAgICAgICAgICAodmFsdWUpID0+XG4gICAgICAgICAgICAgICAgICAgICh0aGlzLnN1Z2dlc3Rpb25WYWx1ZSgpID8gdmFsdWVbdGhpcy5zdWdnZXN0aW9uVmFsdWUoKSFdIDogdmFsdWUpID09PVxuICAgICAgICAgICAgICAgICAgICAodGhpcy5zdWdnZXN0aW9uVmFsdWUoKSA/IHN1Z2dlc3Rpb25bdGhpcy5zdWdnZXN0aW9uVmFsdWUoKSFdIDogc3VnZ2VzdGlvbiksXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBpZiAoIWV4aXN0cykge1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWVzLnNldChbLi4uY3VycmVudFZhbHVlcywgc3VnZ2VzdGlvbl0pO1xuICAgICAgICAgICAgICAgIHRoaXMuX29uQ2hhbmdlPy4odGhpcy52YWx1ZXMoKSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuaW5wdXRWYWx1ZS5zZXQoJycpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy52YWx1ZS5zZXQoc3VnZ2VzdGlvbik7XG4gICAgICAgICAgICBjb25zdCBfdmFsdWUgPSB0aGlzLnN1Z2dlc3Rpb25WYWx1ZSgpID8gc3VnZ2VzdGlvblt0aGlzLnN1Z2dlc3Rpb25WYWx1ZSgpIV0gOiBzdWdnZXN0aW9uO1xuICAgICAgICAgICAgY29uc3QgX2lucHV0VmFsdWUgPSBTdHJpbmcodGhpcy5zdWdnZXN0aW9uTGFiZWwoKSA/IHN1Z2dlc3Rpb25bdGhpcy5zdWdnZXN0aW9uTGFiZWwoKSFdIDogc3VnZ2VzdGlvbik7XG5cbiAgICAgICAgICAgIHRoaXMuaW5wdXRWYWx1ZS5zZXQoX2lucHV0VmFsdWUpO1xuICAgICAgICAgICAgdGhpcy5fb25DaGFuZ2U/LihfdmFsdWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZWxlY3RlZC5lbWl0KHN1Z2dlc3Rpb24pO1xuICAgICAgICB0aGlzLmlzT3Blbi5zZXQoZmFsc2UpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExpbXBhIG8gdmFsb3Igc2VsZWNpb25hZG8gbm8gY29tcG9uZW50ZSBkZSBhdXRvY29tcGxldGUuXG4gICAgICogU2UgbyBtb2RvIG3Dumx0aXBsbyBlc3RpdmVyIGF0aXZhZG8sIHJlbW92ZSB0b2RvcyBvcyB2YWxvcmVzIHNlbGVjaW9uYWRvcy5cbiAgICAgKiBDYXNvIGNvbnRyw6FyaW8sIGRlZmluZSBvIHZhbG9yIGNvbW8gbnVsby5cbiAgICAgKiBUYW1iw6ltIGxpbXBhIGFzIHN1Z2VzdMO1ZXMgZmlsdHJhZGFzLCBmZWNoYSBvIHBhaW5lbCBkZSBzdWdlc3TDtWVzXG4gICAgICogZSBsaW1wYSBvIHZhbG9yIGRvIGNhbXBvIGRlIGVudHJhZGEuXG4gICAgICovXG4gICAgcHVibGljIGNsZWFyKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5tdWx0aXBsZSgpKSB7XG4gICAgICAgICAgICB0aGlzLnZhbHVlcy5zZXQoW10pO1xuICAgICAgICAgICAgdGhpcy5fb25DaGFuZ2U/Lih0aGlzLnZhbHVlcygpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMudmFsdWUuc2V0KG51bGwpO1xuICAgICAgICAgICAgdGhpcy5fb25DaGFuZ2U/Lih0aGlzLnZhbHVlKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5maWx0ZXJlZFN1Z2dlc3Rpb25zLnNldChbXSk7XG4gICAgICAgIHRoaXMuaXNPcGVuLnNldChmYWxzZSk7XG4gICAgICAgIHRoaXMuaW5wdXRWYWx1ZS5zZXQoJycpO1xuICAgICAgICB0aGlzLmNsZWFyZWQuZW1pdCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFsdGVybmEgYSBleGliacOnw6NvIGRvIGRyb3Bkb3duIGRlIHN1Z2VzdMO1ZXMgZG8gYXV0b2NvbXBsZXRlLlxuICAgICAqIEVzdGUgbcOpdG9kbyBjb25maWd1cmEgbyBkZWJvdW5jZSBkbyBpbnB1dCwgdmVyaWZpY2Egc2UgaMOhIHN1Z2VzdMO1ZXMgZmlsdHJhZGFzXG4gICAgICogZSwgY2FzbyBuw6NvIGhhamEgc3VnZXN0w7VlcyBlIG8gdGV4dG8gZG8gZmlsdHJvIGVzdGVqYSB2YXppbywgcmVkZWZpbmUgYXMgc3VnZXN0w7VlcyBmaWx0cmFkYXMuXG4gICAgICogUG9yIGZpbSwgYWx0ZXJuYSBvIGVzdGFkbyBkZSBhYmVydHVyYSBkbyBkcm9wZG93bi5cbiAgICAgKi9cbiAgICBwdWJsaWMgdG9nZ2xlRHJvcGRvd24oKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX3NldHVwSW5wdXREZWJvdW5jZSgpO1xuXG4gICAgICAgIGlmICh0aGlzLmZpbHRlclRleHQoKSA9PT0gJycpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmxhenkoKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2xhenlMb2FkU3ViamVjdCQubmV4dCgnJyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMucmVzZXRGaWx0ZXJlZFN1Z2dlc3Rpb25zKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmlzT3Blbi5zZXQoIXRoaXMuaXNPcGVuKCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZ1bsOnw6NvIHV0aWxpemFkYSBwYXJhIG90aW1pemFyIGEgcmVuZGVyaXphw6fDo28gZGUgbGlzdGFzIG5vIEFuZ3VsYXIsIHBlcm1pdGluZG8gcXVlIG8gZnJhbWV3b3JrXG4gICAgICogaWRlbnRpZmlxdWUgY2FkYSBpdGVtIGRlIGZvcm1hIMO6bmljYSBwZWxvIHNldSBgaWRgLiBEZXZlIHNlciB1dGlsaXphZGEgY29tbyBmdW7Dp8OjbyBkZSBgdHJhY2tCeWBcbiAgICAgKiBlbSBkaXJldGl2YXMgY29tbyBgKm5nRm9yYC5cbiAgICAgKiBAcGFyYW0gXyAtIMONbmRpY2UgZG8gaXRlbSBuYSBsaXN0YSAobsOjbyB1dGlsaXphZG8pLlxuICAgICAqIEBwYXJhbSBpdGVtIC0gT2JqZXRvIGRvIHRpcG8gYFN1Z2dlc3Rpb25XcmFwcGVyPFQ+YCBxdWUgcmVwcmVzZW50YSBvIGl0ZW0gYXR1YWwuXG4gICAgICogQHJldHVybnMgTyBpZGVudGlmaWNhZG9yIMO6bmljbyAoYGlkYCkgZG8gaXRlbS5cbiAgICAgKi9cbiAgICBwdWJsaWMgdHJhY2tCeUlkKF86IG51bWJlciwgaXRlbTogU3VnZ2VzdGlvbldyYXBwZXI8VD4pOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gaXRlbS5pZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmUgdW1hIHN1Z2VzdMOjbyBkYSBsaXN0YSBkZSB2YWxvcmVzIHNlbGVjaW9uYWRvcy5cbiAgICAgKiBAcGFyYW0gc3VnZ2VzdGlvbiBPIGl0ZW0gYSBzZXIgcmVtb3ZpZG8gZGEgbGlzdGEgZGUgc3VnZXN0w7Vlcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlU3VnZ2VzdGlvbihzdWdnZXN0aW9uOiBUKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHN1Z2dlc3Rpb25WYWx1ZSA9IHRoaXMuc3VnZ2VzdGlvblZhbHVlKCk7XG5cbiAgICAgICAgdGhpcy52YWx1ZXMuc2V0KFxuICAgICAgICAgICAgdGhpcy52YWx1ZXMoKS5maWx0ZXIoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHN1Z2dlc3Rpb25WYWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWVbc3VnZ2VzdGlvblZhbHVlXSAhPT0gc3VnZ2VzdGlvbltzdWdnZXN0aW9uVmFsdWVdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdmFsdWUgIT09IHN1Z2dlc3Rpb247XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5fb25DaGFuZ2U/Lih0aGlzLnZhbHVlcygpKTtcbiAgICAgICAgdGhpcy51bnNlbGVjdGVkLmVtaXQoc3VnZ2VzdGlvbik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVpbmljaWEgYSBsaXN0YSBkZSBzdWdlc3TDtWVzIGZpbHRyYWRhcy5cbiAgICAgKiBTZSBvIG1vZG8gbGF6eSBlc3RpdmVyIGF0aXZhZG8sIGVtaXRlIHVtIGV2ZW50byBwYXJhIGNhcnJlZ2FyIHN1Z2VzdMO1ZXMgY29tIHVtYSBjb25zdWx0YSB2YXppYS5cbiAgICAgKiBFbSBzZWd1aWRhLCByZWRlZmluZSBhcyBzdWdlc3TDtWVzIGZpbHRyYWRhcyBwYXJhIG8gdmFsb3IgcmV0b3JuYWRvIHBvciBgaW50ZXJuYWxTdWdnZXN0aW9uKClgLlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSByZXNldEZpbHRlcmVkU3VnZ2VzdGlvbnMoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmxhenkoKSkge1xuICAgICAgICAgICAgdGhpcy5fbGF6eUxvYWRTdWJqZWN0JC5uZXh0KCcnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZmlsdGVyZWRTdWdnZXN0aW9ucy5zZXQodGhpcy5pbnRlcm5hbFN1Z2dlc3Rpb24oKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNb3ZlIG8gZm9jbyBwYXJhIGEgcHLDs3hpbWEgc3VnZXN0w6NvIG5hIGxpc3RhIGRlIHN1Z2VzdMO1ZXMsIHNlIGhvdXZlci5cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSBzdWdnZXN0aW9ucyBMaXN0YSBkZSBzdWdlc3TDtWVzIGRpc3BvbsOtdmVpcy5cbiAgICAgKi9cbiAgICBwcml2YXRlIF9mb2N1c05leHRTdWdnZXN0aW9uKHN1Z2dlc3Rpb25zOiBTdWdnZXN0aW9uV3JhcHBlcjxUPltdKTogdm9pZCB7XG4gICAgICAgIGxldCBuZXh0SW5kZXggPSB0aGlzLmZvY3VzZWRJbmRleCgpICsgMTtcblxuICAgICAgICBpZiAobmV4dEluZGV4IDwgc3VnZ2VzdGlvbnMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLmZvY3VzZWRJbmRleC5zZXQobmV4dEluZGV4KTtcbiAgICAgICAgICAgIHRoaXMuX3Njcm9sbFRvRm9jdXNlZFN1Z2dlc3Rpb24oKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1vdmUgbyBmb2NvIHBhcmEgYSBzdWdlc3TDo28gYW50ZXJpb3IgbmEgbGlzdGEgZGUgc3VnZXN0w7Vlcywgc2UgaG91dmVyLlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSBfZm9jdXNQcmV2aW91c1N1Z2dlc3Rpb24oKTogdm9pZCB7XG4gICAgICAgIGxldCBwcmV2SW5kZXggPSB0aGlzLmZvY3VzZWRJbmRleCgpIC0gMTtcblxuICAgICAgICBpZiAocHJldkluZGV4ID49IDApIHtcbiAgICAgICAgICAgIHRoaXMuZm9jdXNlZEluZGV4LnNldChwcmV2SW5kZXgpO1xuICAgICAgICAgICAgdGhpcy5fc2Nyb2xsVG9Gb2N1c2VkU3VnZ2VzdGlvbigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUm9sYSBhIGxpc3RhIGRlIHN1Z2VzdMO1ZXMgcGFyYSBnYXJhbnRpciBxdWUgYSBzdWdlc3TDo28gYXR1YWxtZW50ZSBmb2NhZGEgZXN0ZWphIHZpc8OtdmVsLlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSBfc2Nyb2xsVG9Gb2N1c2VkU3VnZ2VzdGlvbigpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgaWQgPSB0aGlzLmZpbHRlcmVkU3VnZ2VzdGlvbnMoKVt0aGlzLmZvY3VzZWRJbmRleCgpXT8uaWQ7XG5cbiAgICAgICAgaWYgKCFpZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZWwgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7XG4gICAgICAgIGVsPy5zY3JvbGxJbnRvVmlldyh7IGJsb2NrOiAnbmVhcmVzdCcgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRpY2lvbmEgdW0gaWRlbnRpZmljYWRvciDDum5pY28gYSBjYWRhIHN1Z2VzdMOjbyBmb3JuZWNpZGEuXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0gc3VnZ2VzdGlvbnMgLSBVbSBhcnJheSBkZSBzdWdlc3TDtWVzIGRvIHRpcG8gVC5cbiAgICAgKiBAcmV0dXJucyBVbSBhcnJheSBkZSBvYmpldG9zIGBTdWdnZXN0aW9uV3JhcHBlcjxUPmAsIGNhZGEgdW0gY29udGVuZG8gYSBzdWdlc3TDo28gb3JpZ2luYWwgZSB1bSBpZGVudGlmaWNhZG9yIMO6bmljby5cbiAgICAgKi9cbiAgICBwcml2YXRlIF9hZGRJZFRvU3VnZ2VzdGlvbnMoc3VnZ2VzdGlvbnM6IFRbXSk6IFN1Z2dlc3Rpb25XcmFwcGVyPFQ+W10ge1xuICAgICAgICBjb25zdCBiYXNlSWQgPSBgJHt0aGlzLmNvbXBvbmVudElkfV9zdWdnZXN0aW9uYDtcblxuICAgICAgICByZXR1cm4gc3VnZ2VzdGlvbnM/Lm1hcCgoc3VnZ2VzdGlvbiwgaW5kZXgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgZGF0YTogc3VnZ2VzdGlvbixcbiAgICAgICAgICAgICAgICBpZDogYCR7YmFzZUlkfV8ke2luZGV4Kyt9YCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0pID8/IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbmZpZ3VyYSBvIGRlYm91bmNlIGUgc3dpdGNoTWFwIHBhcmEgbGF6eSBsb2FkaW5nLCByZXNvbHZlbmRvIHJhY2UgY29uZGl0aW9ucy5cbiAgICAgKiBFc3RlIG3DqXRvZG8gdXRpbGl6YSBzd2l0Y2hNYXAgcGFyYSBjYW5jZWxhciByZXF1aXNpw6fDtWVzIGFudGVyaW9yZXMgYXV0b21hdGljYW1lbnRlXG4gICAgICogcXVhbmRvIHVtYSBub3ZhIGJ1c2NhIMOpIGluaWNpYWRhLCBldml0YW5kbyBxdWUgcmVzdWx0YWRvcyBhbnRpZ29zIHNvYnJlc2NyZXZhbVxuICAgICAqIHJlc3VsdGFkb3MgbWFpcyByZWNlbnRlcy5cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgX3NldHVwTGF6eUxvYWREZWJvdW5jZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5fbGF6eUxvYWRTdWJqZWN0JFxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgZGVib3VuY2VUaW1lKHRoaXMuZGVsYXkoKSksXG4gICAgICAgICAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgICAgICAgICAgICAgICBzd2l0Y2hNYXAoKHF1ZXJ5KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9hZGluZy5zZXQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRPRE86IE1hbnRlciBmZWNoYWRvIG8gZHJvcGRvd25kIGF0w6kgYSBidXNjYSBlc3RpdmVyIGNvbmNsdcOtZGFcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlPFRbXT4oKHN1YnNjcmliZXIpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHRpbWVvdXRJZCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghc3Vic2NyaWJlci5jbG9zZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2NyaWJlci5lcnJvcihuZXcgRXJyb3IoJ0xhenkgbG9hZCB0aW1lb3V0JykpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0sIDMwMDAwKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVzcG9uc2VDYWxsYmFjayA9IChkYXRhOiBUW10pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXN1YnNjcmliZXIuY2xvc2VkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNjcmliZXIubmV4dChkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2NyaWJlci5jb21wbGV0ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGF6eUxvYWQuZW1pdCh7IHF1ZXJ5LCByZXNwb25zZTogcmVzcG9uc2VDYWxsYmFjayB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuX2Rlc3Ryb3lSZWYpLFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLnN1YnNjcmliZSh7XG4gICAgICAgICAgICAgICAgbmV4dDogKGRhdGE6IFRbXSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxvYWRpbmcuc2V0KGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gVE9ETzogQWJyaXIgbyBkcm9wZG93biBzb21lbnRlIGFxdWlcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgd3JhcHBlZFN1Z2dlc3Rpb25zID0gdGhpcy5fYWRkSWRUb1N1Z2dlc3Rpb25zKGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbHRlcmVkU3VnZ2VzdGlvbnMuc2V0KHdyYXBwZWRTdWdnZXN0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2hvd0VtcHR5TWVzc2FnZS5zZXQod3JhcHBlZFN1Z2dlc3Rpb25zLmxlbmd0aCA9PT0gMCk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBlcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubG9hZGluZy5zZXQoZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICAvLyBUT0RPOiBBYnJpciBvIGRyb3Bkb3duIHNvbWVudGUgYXF1aVxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdMYXp5IGxvYWQgZXJyb3I6JywgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbHRlcmVkU3VnZ2VzdGlvbnMuc2V0KFtdKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zaG93RW1wdHlNZXNzYWdlLnNldCh0cnVlKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29uZmlndXJhIG8gZGVib3VuY2UgcGFyYSBvIGlucHV0IGRvIGF1dG9jb21wbGV0ZS5cbiAgICAgKiBFc3RlIG3DqXRvZG8gdXRpbGl6YSB1bSBTdWJqZWN0IHBhcmEgZXNjdXRhciBhcyBtdWRhbsOnYXMgbm8gdmFsb3IgZG8gaW5wdXQsXG4gICAgICogYXBsaWNhbmRvIHVtIGRlYm91bmNlIGNvbSBvIHRlbXBvIGRlZmluaWRvIHBvciBgdGhpcy5kZWxheSgpYC4gUXVhbmRvIHVtIG5vdm8gdmFsb3Igw6kgZW1pdGlkbzpcbiAgICAgKiAtIFNlIGhvdXZlciB2YWxvciwgZmlsdHJhIGFzIHN1Z2VzdMO1ZXMgY29tIGJhc2Ugbm8gdGV4dG8gZGlnaXRhZG8gZSBhdHVhbGl6YSBhIGxpc3RhIGRlIHN1Z2VzdMO1ZXMgZmlsdHJhZGFzLlxuICAgICAqIC0gU2UgbsOjbyBob3V2ZXIgdmFsb3IgZSBvIGRyb3Bkb3duIGVzdGl2ZXIgYXRpdm8sIHJlc2V0YSBhcyBzdWdlc3TDtWVzIGZpbHRyYWRhcy5cbiAgICAgKiAtIENhc28gY29udHLDoXJpbywgbGltcGEgYSBsaXN0YSBkZSBzdWdlc3TDtWVzIGZpbHRyYWRhcy5cbiAgICAgKiBUYW1iw6ltIGF0dWFsaXphIG8gZXN0YWRvIGRhIG1lbnNhZ2VtIGRlIGxpc3RhIHZhemlhIGUsIHNlIGEgc2VsZcOnw6NvIGZvciBsaXZyZSAoYGZvcmNlU2VsZWN0aW9uYCBmb3IgZmFsc28pLFxuICAgICAqIHByb3BhZ2EgYSBtdWRhbsOnYSBkZSB2YWxvciBwYXJhIG8gZm9ybXVsw6FyaW8uXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIF9zZXR1cElucHV0RGVib3VuY2UoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuX2lucHV0U3ViamVjdCRcbiAgICAgICAgICAgIC5waXBlKFxuICAgICAgICAgICAgICAgIGRlYm91bmNlVGltZSh0aGlzLmRlbGF5KCkpLFxuICAgICAgICAgICAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCksXG4gICAgICAgICAgICAgICAgZmlsdGVyKCh2YWx1ZSkgPT4gdmFsdWUubGVuZ3RoID49IHRoaXMubWluTGVuZ3RoVG9TZWFyY2goKSB8fCB2YWx1ZS5sZW5ndGggPT09IDApLFxuICAgICAgICAgICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLl9kZXN0cm95UmVmKSxcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmlsdGVyZWRTdWdnZXN0aW9ucy5zZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmludGVybmFsU3VnZ2VzdGlvbigpLmZpbHRlcigoeyBkYXRhIH0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsYWJlbCA9IFN0cmluZyh0aGlzLnN1Z2dlc3Rpb25MYWJlbCgpID8gZGF0YVt0aGlzLnN1Z2dlc3Rpb25MYWJlbCgpIV0gOiBkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gbGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyh2YWx1ZS50b0xvd2VyQ2FzZSgpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNob3dFbXB0eU1lc3NhZ2Uuc2V0KHRoaXMuZmlsdGVyZWRTdWdnZXN0aW9ucygpLmxlbmd0aCA9PT0gMCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmRyb3Bkb3duKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNldEZpbHRlcmVkU3VnZ2VzdGlvbnMoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbHRlcmVkU3VnZ2VzdGlvbnMuc2V0KFtdKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuZm9yY2VTZWxlY3Rpb24oKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9vbkNoYW5nZT8uKHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWYWxpZGEgYXMgZW50cmFkYXMgZG8gY29tcG9uZW50ZSBkZSBhdXRvY29tcGxldGUuXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAdGhyb3dzIHtFcnJvcn0gU2UgYXMgc3VnZXN0w7VlcyBmb3JlbSBvYmpldG9zIGUgYHN1Z2dlc3Rpb25MYWJlbGAgbsOjbyBmb3IgZm9ybmVjaWRvLlxuICAgICAqL1xuICAgIHByaXZhdGUgX3ZhbGlkYXRlSW5wdXRzKCk6IHZvaWQge1xuICAgICAgICBjb25zdCBzdWdnZXN0aW9ucyA9IHRoaXMuc3VnZ2VzdGlvbnMoKTtcblxuICAgICAgICBpZiAoIXN1Z2dlc3Rpb25zLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaGFzT2JqZWN0U3VnZ2VzdGlvbnMgPSBzdWdnZXN0aW9ucy5zb21lKFxuICAgICAgICAgICAgKHN1Z2dlc3Rpb24pID0+IHR5cGVvZiBzdWdnZXN0aW9uID09PSAnb2JqZWN0JyAmJiBzdWdnZXN0aW9uICE9PSBudWxsLFxuICAgICAgICApO1xuXG4gICAgICAgIGlmIChoYXNPYmplY3RTdWdnZXN0aW9ucykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnN1Z2dlc3Rpb25MYWJlbCgpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgc3VnZ2VzdGlvbkxhYmVsIGlucHV0IG11c3QgYmUgcHJvdmlkZWQgd2hlbiBzdWdnZXN0aW9ucyBhcmUgb2JqZWN0cy4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIjxkaXZcbiAgICAjY29udGFpbmVyRGl2XG4gICAgY2RrT3ZlcmxheU9yaWdpblxuICAgICN0cmlnZ2VyPVwiY2RrT3ZlcmxheU9yaWdpblwiXG4gICAgY2xhc3M9XCJmbGV4IGgtWzM1cHhdIHctZnVsbCBpdGVtcy1jZW50ZXIgb3ZlcmZsb3ctaGlkZGVuIHJvdW5kZWQtWzRweF0gYm9yZGVyIGZvY3VzLXdpdGhpbjpib3JkZXItMiBmb2N1cy13aXRoaW46Ym9yZGVyLXByaW1hcnkgaG92ZXI6YmctZ3JheXNjYWxlLTEwXCJcbiAgICBbY2xhc3NdPVwiaW5wdXRDbGFzcygpXCJcbiAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgICdwb2ludGVyLWV2ZW50cy1ub25lIGJvcmRlci1ncmF5c2NhbGUtMjAgYmctZ3JheXNjYWxlLTUgdGV4dC1ncmF5c2NhbGUtMzAnOiBkaXNhYmxlZCgpLFxuICAgICAgICAncG9pbnRlci1ldmVudHMtYXV0byBib3JkZXItZ3JheXNjYWxlLTMwIGJnLWdyYXlzY2FsZS0wIHRleHQtZ3JheXNjYWxlLTkwJzogIWRpc2FibGVkKCksXG4gICAgICAgICdib3JkZXItY3JpdGljYWxpdHktcmVkJzogaW52YWxpZCgpLFxuICAgIH1cIlxuPlxuICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJmbGV4IGZsZXgtZ3JvdyBnYXAtMiBweC0yXCJcbiAgICAgICAgW25nQ2xhc3NdPVwie1xuICAgICAgICAgICAgJ2JvcmRlci1yJzogZHJvcGRvd24oKSxcbiAgICAgICAgICAgICdib3JkZXItZ3JheXNjYWxlLTIwJzogZHJvcGRvd24oKSAmJiBkaXNhYmxlZCgpLFxuICAgICAgICAgICAgJ2JvcmRlci1ncmF5c2NhbGUtMzAgZm9jdXMtd2l0aGluOmJvcmRlci1yLTIgZm9jdXMtd2l0aGluOmJvcmRlci1yLXByaW1hcnknOiBkcm9wZG93bigpICYmICFkaXNhYmxlZCgpLFxuICAgICAgICAgICAgJ2JnLWdyYXlzY2FsZS01JzogZGlzYWJsZWQoKSxcbiAgICAgICAgICAgICdiZy1ncmF5c2NhbGUtMCc6ICFkaXNhYmxlZCgpLFxuICAgICAgICB9XCJcbiAgICA+XG4gICAgICAgIEBpZiAobXVsdGlwbGUoKSAmJiB2YWx1ZXMoKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZmxleCBmbGV4LXdyYXAgaXRlbXMtY2VudGVyIGdhcC0yXCI+XG4gICAgICAgICAgICAgICAgQGZvciAoc3VnZ2VzdGlvbiBvZiB2YWx1ZXMoKTsgdHJhY2sgc3VnZ2VzdGlvbikge1xuICAgICAgICAgICAgICAgICAgICA8cy1hdXRvY29tcGxldGUtY2hpcFxuICAgICAgICAgICAgICAgICAgICAgICAgW3N1Z2dlc3Rpb25dPVwic3VnZ2VzdGlvblwiXG4gICAgICAgICAgICAgICAgICAgICAgICBbc3VnZ2VzdGlvbkxhYmVsXT1cInN1Z2dlc3Rpb25MYWJlbCgpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIChzdWdnZXN0aW9uUmVtb3ZlZCk9XCJyZW1vdmVTdWdnZXN0aW9uKCRldmVudClcIlxuICAgICAgICAgICAgICAgICAgICA+PC9zLWF1dG9jb21wbGV0ZS1jaGlwPlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgI2lucHV0RWxcbiAgICAgICAgICAgIGNsYXNzPVwibWluLWgtWzM1cHhdIGdyb3cgb3V0bGluZS1ub25lXCJcbiAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgIFtwbGFjZWhvbGRlcl09XCJwbGFjZWhvbGRlcigpID8/ICdwbGF0Zm9ybS5hbmd1bGFyX2NvbXBvbmVudHMudHlwZV90b19zZWFyY2gnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgIFtyZWFkT25seV09XCJyZWFkb25seSgpXCJcbiAgICAgICAgICAgIFsobmdNb2RlbCldPVwiaW5wdXRWYWx1ZVwiXG4gICAgICAgICAgICBbYXR0ci5hcmlhLWRpc2FibGVkXT1cImRpc2FibGVkKClcIlxuICAgICAgICAgICAgW2F0dHIuYXJpYS1hdXRvY29tcGxldGVdPVwibXVsdGlwbGUoKSA/ICdsaXN0JyA6ICdib3RoJ1wiXG4gICAgICAgICAgICBbYXR0ci5hcmlhLWFjdGl2ZWRlc2NlbmRhbnRdPVwiZm9jdXNlZEluZGV4KCkgPj0gMCA/IGZpbHRlcmVkU3VnZ2VzdGlvbnMoKVtmb2N1c2VkSW5kZXgoKV0uaWQgOiBudWxsXCJcbiAgICAgICAgICAgIHJvbGU9XCJzZWFyY2hib3hcIlxuICAgICAgICAgICAgKGlucHV0KT1cIm9uSW5wdXQoJGV2ZW50KVwiXG4gICAgICAgICAgICAoa2V5ZG93bik9XCJvbktleURvd24oJGV2ZW50KVwiXG4gICAgICAgICAgICAoa2V5VXApPVwib25LZXlVcCgkZXZlbnQpXCJcbiAgICAgICAgICAgIChibHVyKT1cIm9uSW5wdXRCbHVyKCRldmVudClcIlxuICAgICAgICAgICAgKGZvY3VzKT1cIm9uSW5wdXRGb2N1cygkZXZlbnQpXCJcbiAgICAgICAgLz5cblxuICAgICAgICBAaWYgKGxvYWRpbmcoKSkge1xuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImZsZXggaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyXCI+XG4gICAgICAgICAgICAgICAgPHN2Z1xuICAgICAgICAgICAgICAgICAgICB3aWR0aD1cIjIwXCJcbiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0PVwiMjBcIlxuICAgICAgICAgICAgICAgICAgICB2aWV3Qm94PVwiMCAwIDIwIDIwXCJcbiAgICAgICAgICAgICAgICAgICAgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiYW5pbWF0ZS1zcGluXCJcbiAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgIDxjaXJjbGVcbiAgICAgICAgICAgICAgICAgICAgICAgIGN4PVwiMTBcIlxuICAgICAgICAgICAgICAgICAgICAgICAgY3k9XCIxMFwiXG4gICAgICAgICAgICAgICAgICAgICAgICByPVwiOVwiXG4gICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9XCIjNDI4YmNhXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjJcIlxuICAgICAgICAgICAgICAgICAgICAgICAgZmlsbD1cIm5vbmVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgc3Ryb2tlLWRhc2hhcnJheT1cIjU2LjVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgc3Ryb2tlLWRhc2hvZmZzZXQ9XCIxMFwiXG4gICAgICAgICAgICAgICAgICAgICAgICBzdHJva2UtbGluZWNhcD1cInJvdW5kXCJcbiAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICA8L3N2Zz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgIEBpZiAodmFsdWUoKSAmJiAhdGhpcy5kaXNhYmxlZCgpKSB7XG4gICAgICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cInB4LTJcIlxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwiY2xlYXIoKVwiXG4gICAgICAgICAgICAgICAgICAgIHRhYmluZGV4PVwiLTFcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJmYXIgZmEtdGltZXMgdGV4dC1ncmF5c2NhbGUtNjBcIj48L2k+XG4gICAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICA8L2Rpdj5cblxuICAgIEBpZiAoZHJvcGRvd24oKSkge1xuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBjbGFzcz1cImZsZXggaC1mdWxsIHctWzM1cHhdIGZsZXgtc2hyaW5rLTAgZmxleC1ncm93LTAgaXRlbXMtY2VudGVyIGp1c3RpZnktY2VudGVyIGhvdmVyOmJnLWdyYXlzY2FsZS0xMFwiXG4gICAgICAgICAgICAoY2xpY2spPVwidG9nZ2xlRHJvcGRvd24oKVwiXG4gICAgICAgID5cbiAgICAgICAgICAgIDxpXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJmYXMgdGV4dC1ncmF5c2NhbGUtOTBcIlxuICAgICAgICAgICAgICAgIFtjbGFzcy5mYS1jYXJldC1kb3duXT1cIiFpc09wZW4oKVwiXG4gICAgICAgICAgICAgICAgW2NsYXNzLmZhLWNhcmV0LXVwXT1cImlzT3BlbigpXCJcbiAgICAgICAgICAgID48L2k+XG4gICAgICAgIDwvYnV0dG9uPlxuICAgIH1cbjwvZGl2PlxuXG5AaWYgKHNob3dFbXB0eU1lc3NhZ2UoKSB8fCAoZmlsdGVyZWRTdWdnZXN0aW9ucygpLmxlbmd0aCA+IDAgJiYgIXJlYWRvbmx5KCkpKSB7XG4gICAgPG5nLXRlbXBsYXRlXG4gICAgICAgICNkcm9wZG93blRlbXBsYXRlXG4gICAgICAgIGNka0Nvbm5lY3RlZE92ZXJsYXlcbiAgICAgICAgW2Nka0Nvbm5lY3RlZE92ZXJsYXlPcmlnaW5dPVwidHJpZ2dlclwiXG4gICAgICAgIFtjZGtDb25uZWN0ZWRPdmVybGF5T3Blbl09XCJpc09wZW4oKVwiXG4gICAgICAgIFtjZGtDb25uZWN0ZWRPdmVybGF5SGFzQmFja2Ryb3BdPVwidHJ1ZVwiXG4gICAgICAgIChiYWNrZHJvcENsaWNrKT1cImlzT3Blbi5zZXQoZmFsc2UpXCJcbiAgICAgICAgY2RrQ29ubmVjdGVkT3ZlcmxheUJhY2tkcm9wQ2xhc3M9XCJjZGstb3ZlcmxheS10cmFuc3BhcmVudC1iYWNrZHJvcFwiXG4gICAgICAgIChkZXRhY2gpPVwiaXNPcGVuLnNldChmYWxzZSlcIlxuICAgID5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICAgW2lkXT1cIidkcm9wZG93bi1jb250YWluZXItJyArIGNvbXBvbmVudElkXCJcbiAgICAgICAgICAgIGNsYXNzPVwibXQtMC41IHJvdW5kZWQtWzRweF0gYmctZ3JheXNjYWxlLTAgcHktMSBzaGFkb3dcIlxuICAgICAgICAgICAgW3N0eWxlLndpZHRoLnB4XT1cImNvbnRhaW5lckRpdi5vZmZzZXRXaWR0aFwiXG4gICAgICAgID5cbiAgICAgICAgICAgIDx1bFxuICAgICAgICAgICAgICAgIGNsYXNzPVwibWF4LWgtNTIgb3ZlcmZsb3ctYXV0b1wiXG4gICAgICAgICAgICAgICAgcm9sZT1cImxpc3Rib3hcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDwhLS0gVmlydHVhbCBzY3JvbGwgLS0+XG4gICAgICAgICAgICAgICAgQGlmICh2aXJ0dWFsU2Nyb2xsKCkgJiYgZmlsdGVyZWRTdWdnZXN0aW9ucygpLmxlbmd0aCA+IDEwKSB7XG4gICAgICAgICAgICAgICAgICAgIDxjZGstdmlydHVhbC1zY3JvbGwtdmlld3BvcnRcbiAgICAgICAgICAgICAgICAgICAgICAgIFtpdGVtU2l6ZV09XCJ2aXJ0dWFsU2Nyb2xsSXRlbVNpemUoKVwiXG4gICAgICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImgtNTIgb3ZlcmZsb3ctYXV0b1wiXG4gICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAqY2RrVmlydHVhbEZvcj1cIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXQgc3VnZ2VzdGlvbiBvZiBlbnJpY2hlZEZpbHRlcmVkU3VnZ2VzdGlvbnMoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0IGkgPSAkaW5kZXg7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNrQnk6IHRyYWNrQnlJZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJzdWdnZXN0aW9uSXRlbVRlbXBsYXRlXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgc3VnZ2VzdGlvbiwgaSB9XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgICAgICAgPC9jZGstdmlydHVhbC1zY3JvbGwtdmlld3BvcnQ+XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgPCEtLSBOb3JtYWwgbGlzdCAtLT5cbiAgICAgICAgICAgICAgICBAaWYgKCF2aXJ0dWFsU2Nyb2xsKCkgfHwgZmlsdGVyZWRTdWdnZXN0aW9ucygpLmxlbmd0aCA8PSAxMCkge1xuICAgICAgICAgICAgICAgICAgICBAZm9yIChzdWdnZXN0aW9uIG9mIGVucmljaGVkRmlsdGVyZWRTdWdnZXN0aW9ucygpOyB0cmFjayBzdWdnZXN0aW9uLmlkOyBsZXQgaSA9ICRpbmRleCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cInN1Z2dlc3Rpb25JdGVtVGVtcGxhdGVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7IHN1Z2dlc3Rpb24sIGkgfVwiXG4gICAgICAgICAgICAgICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBAaWYgKHNob3dFbXB0eU1lc3NhZ2UoKSkge1xuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cInAtMyB0ZXh0LWdyYXlzY2FsZS02MFwiPnt7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbXB0eU1lc3NhZ2UoKSA/PyAncGxhdGZvcm0uYW5ndWxhcl9jb21wb25lbnRzLm5vX3JlY29yZHNfZm91bmQnIHwgdHJhbnNsYXRlXG4gICAgICAgICAgICAgICAgICAgIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvdWw+XG4gICAgICAgIDwvZGl2PlxuICAgIDwvbmctdGVtcGxhdGU+XG59XG5cbjxuZy10ZW1wbGF0ZVxuICAgICNzdWdnZXN0aW9uSXRlbVRlbXBsYXRlXG4gICAgbGV0LXN1Z2dlc3Rpb249XCJzdWdnZXN0aW9uXCJcbiAgICBsZXQtaT1cImlcIlxuPlxuICAgIDxsaVxuICAgICAgICBbaWRdPVwic3VnZ2VzdGlvbi5pZFwiXG4gICAgICAgIGNsYXNzPVwicm91bmRlZC1zbSBmbGV4IGN1cnNvci1wb2ludGVyIGl0ZW1zLWNlbnRlciBnYXAtMiBweC0zIHB5LTIgdGV4dC1ncmF5c2NhbGUtNzBcIlxuICAgICAgICBbY2xhc3MuYmctZ3JheXNjYWxlLTEwXT1cImkgPT09IGZvY3VzZWRJbmRleCgpXCJcbiAgICAgICAgW2NsYXNzLmJnLWdyYXlzY2FsZS0yMF09XCJzdWdnZXN0aW9uLmlzU2VsZWN0ZWRcIlxuICAgICAgICBbYXR0ci5hcmlhLXNlbGVjdGVkXT1cInN1Z2dlc3Rpb24uaXNTZWxlY3RlZFwiXG4gICAgICAgIHJvbGU9XCJvcHRpb25cIlxuICAgICAgICAoY2xpY2spPVwic2VsZWN0U3VnZ2VzdGlvbihzdWdnZXN0aW9uLmRhdGEpXCJcbiAgICA+XG4gICAgICAgIEBpZiAoY2hlY2ttYXJrKCkgJiYgbXVsdGlwbGUoKSAmJiBzdWdnZXN0aW9uLmlzU2VsZWN0ZWQpIHtcbiAgICAgICAgICAgIDxpIGNsYXNzPVwiZmFyIGZhLWNoZWNrXCI+PC9pPlxuICAgICAgICB9XG4gICAgICAgIHt7IHN1Z2dlc3Rpb25MYWJlbCgpID8gc3VnZ2VzdGlvbi5kYXRhW3N1Z2dlc3Rpb25MYWJlbCgpIV0gOiBzdWdnZXN0aW9uLmRhdGEgfX1cbiAgICA8L2xpPlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==