valtech-components 2.0.510 → 2.0.512

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 (42) hide show
  1. package/esm2022/lib/components/molecules/refresher/refresher.component.mjs +254 -0
  2. package/esm2022/lib/components/molecules/refresher/types.mjs +15 -0
  3. package/esm2022/lib/components/organisms/infinite-list/infinite-list.component.mjs +618 -0
  4. package/esm2022/lib/components/organisms/infinite-list/types.mjs +15 -0
  5. package/esm2022/lib/components/templates/page-template/page-template.component.mjs +5 -5
  6. package/esm2022/lib/services/pagination/index.mjs +5 -0
  7. package/esm2022/lib/services/pagination/pagination.service.mjs +218 -0
  8. package/esm2022/lib/services/pagination/types.mjs +14 -0
  9. package/esm2022/lib/services/skeleton/config.mjs +79 -0
  10. package/esm2022/lib/services/skeleton/directives/loading.directive.mjs +215 -0
  11. package/esm2022/lib/services/skeleton/index.mjs +16 -0
  12. package/esm2022/lib/services/skeleton/skeleton.service.mjs +198 -0
  13. package/esm2022/lib/services/skeleton/templates/detail-skeleton.component.mjs +223 -0
  14. package/esm2022/lib/services/skeleton/templates/form-skeleton.component.mjs +127 -0
  15. package/esm2022/lib/services/skeleton/templates/grid-skeleton.component.mjs +154 -0
  16. package/esm2022/lib/services/skeleton/templates/list-skeleton.component.mjs +110 -0
  17. package/esm2022/lib/services/skeleton/templates/profile-skeleton.component.mjs +207 -0
  18. package/esm2022/lib/services/skeleton/templates/table-skeleton.component.mjs +116 -0
  19. package/esm2022/lib/services/skeleton/types.mjs +11 -0
  20. package/esm2022/public-api.mjs +12 -1
  21. package/fesm2022/valtech-components.mjs +3887 -1370
  22. package/fesm2022/valtech-components.mjs.map +1 -1
  23. package/lib/components/molecules/refresher/refresher.component.d.ts +79 -0
  24. package/lib/components/molecules/refresher/types.d.ts +86 -0
  25. package/lib/components/organisms/infinite-list/infinite-list.component.d.ts +111 -0
  26. package/lib/components/organisms/infinite-list/types.d.ts +197 -0
  27. package/lib/services/pagination/index.d.ts +2 -0
  28. package/lib/services/pagination/pagination.service.d.ts +43 -0
  29. package/lib/services/pagination/types.d.ts +113 -0
  30. package/lib/services/skeleton/config.d.ts +30 -0
  31. package/lib/services/skeleton/directives/loading.directive.d.ts +71 -0
  32. package/lib/services/skeleton/index.d.ts +10 -0
  33. package/lib/services/skeleton/skeleton.service.d.ts +127 -0
  34. package/lib/services/skeleton/templates/detail-skeleton.component.d.ts +18 -0
  35. package/lib/services/skeleton/templates/form-skeleton.component.d.ts +22 -0
  36. package/lib/services/skeleton/templates/grid-skeleton.component.d.ts +18 -0
  37. package/lib/services/skeleton/templates/list-skeleton.component.d.ts +17 -0
  38. package/lib/services/skeleton/templates/profile-skeleton.component.d.ts +20 -0
  39. package/lib/services/skeleton/templates/table-skeleton.component.d.ts +17 -0
  40. package/lib/services/skeleton/types.d.ts +111 -0
  41. package/package.json +1 -1
  42. package/public-api.d.ts +6 -0
@@ -0,0 +1,618 @@
1
+ import { Component, Input, Output, EventEmitter, signal, computed, ViewChild, inject, ChangeDetectorRef, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { IonInfiniteScroll, IonInfiniteScrollContent, IonButton, IonSpinner, IonIcon, IonText, IonList, IonItem, } from '@ionic/angular/standalone';
4
+ import { firstValueFrom, isObservable } from 'rxjs';
5
+ import { DEFAULT_INFINITE_LIST_METADATA, } from './types';
6
+ import { RefresherComponent } from '../../molecules/refresher/refresher.component';
7
+ import { SkeletonService } from '../../../services/skeleton/skeleton.service';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/common";
10
+ /**
11
+ * Componente wrapper para listas con infinite scroll.
12
+ *
13
+ * @example
14
+ * <!-- Uso basico con data source -->
15
+ * <val-infinite-list
16
+ * [props]="{
17
+ * dataSource: { loadFn: loadUsers, trackBy: trackByUserId },
18
+ * itemTemplate: userTemplate,
19
+ * pageSize: 20,
20
+ * threshold: '150px'
21
+ * }"
22
+ * ></val-infinite-list>
23
+ *
24
+ * <ng-template #userTemplate let-user let-index="index">
25
+ * <val-card [props]="{ title: user.name, subtitle: user.email }">
26
+ * <p>{{ user.bio }}</p>
27
+ * </val-card>
28
+ * </ng-template>
29
+ *
30
+ * @example
31
+ * <!-- Con pull-to-refresh y estado vacio personalizado -->
32
+ * <val-infinite-list
33
+ * [props]="{
34
+ * dataSource: { loadFn: loadMessages },
35
+ * itemTemplate: messageTemplate,
36
+ * direction: 'both',
37
+ * enableRefresh: true,
38
+ * emptyState: {
39
+ * icon: 'chatbubbles-outline',
40
+ * title: 'Sin mensajes',
41
+ * message: 'Inicia una conversacion'
42
+ * },
43
+ * skeleton: { template: 'list', count: 5 }
44
+ * }"
45
+ * (refresh)="onRefresh($event)"
46
+ * ></val-infinite-list>
47
+ */
48
+ export class InfiniteListComponent {
49
+ constructor() {
50
+ this.skeletonService = inject(SkeletonService);
51
+ this.cdr = inject(ChangeDetectorRef);
52
+ // === Events ===
53
+ this.loadMore = new EventEmitter();
54
+ this.refresh = new EventEmitter();
55
+ this.stateChange = new EventEmitter();
56
+ this.itemsChange = new EventEmitter();
57
+ this.errorOccurred = new EventEmitter();
58
+ // === Reactive State ===
59
+ this.items = signal([]);
60
+ this.state = signal('idle');
61
+ this.hasMoreBottom = signal(true);
62
+ this.hasMoreTop = signal(false);
63
+ this.error = signal(null);
64
+ this.isInitialLoad = signal(true);
65
+ this.currentPage = 0;
66
+ this.currentCursor = null;
67
+ /** Progreso de carga (0-1 si totalCount conocido) */
68
+ this.loadProgress = computed(() => {
69
+ if (!this.props?.dataSource?.totalCount)
70
+ return null;
71
+ return this.items().length / this.props.dataSource.totalCount;
72
+ });
73
+ /** Anuncio de estado para lectores de pantalla */
74
+ this.statusAnnouncement = computed(() => {
75
+ switch (this.state()) {
76
+ case 'loading':
77
+ return 'Cargando items...';
78
+ case 'error':
79
+ return `Error: ${this.error()?.message || 'Ocurrio un error'}`;
80
+ case 'complete':
81
+ return 'Todos los items han sido cargados';
82
+ default:
83
+ return '';
84
+ }
85
+ });
86
+ }
87
+ /** Props combinados con defaults */
88
+ get mergedProps() {
89
+ return { ...DEFAULT_INFINITE_LIST_METADATA, ...this.props };
90
+ }
91
+ /** Config del refresher */
92
+ get refresherConfig() {
93
+ return this.mergedProps.refreshConfig ?? {};
94
+ }
95
+ /** Componente de skeleton a usar */
96
+ get skeletonComponent() {
97
+ const templateName = this.mergedProps.skeleton?.template || 'list';
98
+ const template = this.skeletonService.getTemplate(templateName);
99
+ return template?.component ?? null;
100
+ }
101
+ /** Inputs para el skeleton */
102
+ get skeletonInputs() {
103
+ return {
104
+ config: {
105
+ count: this.mergedProps.skeleton?.count ?? 3,
106
+ animated: true,
107
+ ...this.mergedProps.skeleton?.config,
108
+ },
109
+ };
110
+ }
111
+ ngOnInit() {
112
+ // Cargar items iniciales del dataSource si existen
113
+ if (this.props.dataSource.items?.length) {
114
+ this.items.set([...this.props.dataSource.items]);
115
+ this.isInitialLoad.set(false);
116
+ }
117
+ // Auto-cargar si esta habilitado
118
+ if (this.mergedProps.autoLoad && !this.items().length) {
119
+ this.loadInitial();
120
+ }
121
+ }
122
+ ngOnDestroy() {
123
+ // Cleanup
124
+ }
125
+ /** Funcion de tracking para ngFor */
126
+ trackByFn(index, item) {
127
+ if (this.props.dataSource.trackBy) {
128
+ return this.props.dataSource.trackBy(index, item);
129
+ }
130
+ return index;
131
+ }
132
+ /** Si debe mostrar el scroll inferior */
133
+ shouldShowBottomScroll() {
134
+ const dir = this.mergedProps.direction;
135
+ return (dir === 'bottom' || dir === 'both') && this.items().length > 0;
136
+ }
137
+ /** Carga inicial de datos */
138
+ async loadInitial() {
139
+ if (!this.props.dataSource.loadFn)
140
+ return;
141
+ this.state.set('loading');
142
+ this.stateChange.emit('loading');
143
+ this.error.set(null);
144
+ try {
145
+ const params = {
146
+ direction: 'bottom',
147
+ page: 0,
148
+ pageSize: this.mergedProps.pageSize ?? 20,
149
+ };
150
+ const result = await this.executeLoad(params);
151
+ this.items.set(result.items);
152
+ this.hasMoreBottom.set(result.hasMore);
153
+ this.currentPage = 1;
154
+ this.currentCursor = result.cursor;
155
+ this.isInitialLoad.set(false);
156
+ this.state.set('idle');
157
+ this.stateChange.emit('idle');
158
+ this.itemsChange.emit(this.items());
159
+ }
160
+ catch (err) {
161
+ this.handleError(err);
162
+ }
163
+ }
164
+ /** Cargar mas items en la parte inferior */
165
+ async loadBottom() {
166
+ if (!this.hasMoreBottom() || this.state() === 'loading')
167
+ return;
168
+ if (!this.props.dataSource.loadFn)
169
+ return;
170
+ this.state.set('loading');
171
+ this.stateChange.emit('loading');
172
+ try {
173
+ const params = {
174
+ direction: 'bottom',
175
+ page: this.currentPage,
176
+ pageSize: this.mergedProps.pageSize ?? 20,
177
+ cursor: this.currentCursor,
178
+ lastItem: this.items()[this.items().length - 1],
179
+ };
180
+ const result = await this.executeLoad(params);
181
+ this.items.update((current) => [...current, ...result.items]);
182
+ this.hasMoreBottom.set(result.hasMore);
183
+ this.currentPage++;
184
+ this.currentCursor = result.cursor;
185
+ this.state.set(result.hasMore ? 'idle' : 'complete');
186
+ this.stateChange.emit(result.hasMore ? 'idle' : 'complete');
187
+ this.itemsChange.emit(this.items());
188
+ }
189
+ catch (err) {
190
+ this.handleError(err);
191
+ }
192
+ }
193
+ /** Cargar mas items en la parte superior */
194
+ async loadTop() {
195
+ if (!this.hasMoreTop() || this.state() === 'loading')
196
+ return;
197
+ if (!this.props.dataSource.loadFn)
198
+ return;
199
+ this.state.set('loading');
200
+ try {
201
+ const params = {
202
+ direction: 'top',
203
+ page: 0,
204
+ pageSize: this.mergedProps.pageSize ?? 20,
205
+ firstItem: this.items()[0],
206
+ };
207
+ const result = await this.executeLoad(params);
208
+ this.items.update((current) => [...result.items, ...current]);
209
+ this.hasMoreTop.set(result.hasMore);
210
+ this.state.set('idle');
211
+ this.itemsChange.emit(this.items());
212
+ }
213
+ catch (err) {
214
+ this.handleError(err);
215
+ }
216
+ }
217
+ /** Refresh - recargar desde cero */
218
+ async refreshList() {
219
+ this.currentPage = 0;
220
+ this.currentCursor = null;
221
+ this.hasMoreBottom.set(true);
222
+ this.items.set([]);
223
+ await this.loadInitial();
224
+ }
225
+ /** Reintentar despues de error */
226
+ async retry() {
227
+ this.error.set(null);
228
+ if (this.items().length === 0) {
229
+ await this.loadInitial();
230
+ }
231
+ else {
232
+ await this.loadBottom();
233
+ }
234
+ }
235
+ /** Reset completo */
236
+ async reset() {
237
+ this.items.set([]);
238
+ this.currentPage = 0;
239
+ this.currentCursor = null;
240
+ this.hasMoreBottom.set(true);
241
+ this.hasMoreTop.set(false);
242
+ this.error.set(null);
243
+ this.isInitialLoad.set(true);
244
+ this.state.set('idle');
245
+ if (this.mergedProps.autoLoad) {
246
+ await this.loadInitial();
247
+ }
248
+ }
249
+ /** Agregar items al inicio */
250
+ prependItems(newItems) {
251
+ this.items.update((current) => [...newItems, ...current]);
252
+ this.itemsChange.emit(this.items());
253
+ }
254
+ /** Agregar items al final */
255
+ appendItems(newItems) {
256
+ this.items.update((current) => [...current, ...newItems]);
257
+ this.itemsChange.emit(this.items());
258
+ }
259
+ /** Actualizar un item por indice */
260
+ updateItem(index, item) {
261
+ this.items.update((current) => {
262
+ const updated = [...current];
263
+ updated[index] = item;
264
+ return updated;
265
+ });
266
+ this.itemsChange.emit(this.items());
267
+ }
268
+ /** Remover un item por indice */
269
+ removeItem(index) {
270
+ this.items.update((current) => current.filter((_, i) => i !== index));
271
+ this.itemsChange.emit(this.items());
272
+ }
273
+ /** Handler para evento de infinite scroll */
274
+ async onInfiniteScroll(event) {
275
+ await this.loadBottom();
276
+ event.target.complete();
277
+ }
278
+ /** Handler para evento de refresh */
279
+ async onRefreshTriggered(event) {
280
+ this.refresh.emit(event);
281
+ await this.refreshList();
282
+ event.complete();
283
+ }
284
+ async executeLoad(params) {
285
+ const loadFn = this.props.dataSource.loadFn;
286
+ const result = loadFn(params);
287
+ if (isObservable(result)) {
288
+ return await firstValueFrom(result);
289
+ }
290
+ return await result;
291
+ }
292
+ handleError(err) {
293
+ this.error.set(err);
294
+ this.state.set('error');
295
+ this.stateChange.emit('error');
296
+ this.errorOccurred.emit(err);
297
+ console.error('[InfiniteList] Error loading items:', err);
298
+ }
299
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: InfiniteListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
300
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: InfiniteListComponent, isStandalone: true, selector: "val-infinite-list", inputs: { props: "props" }, outputs: { loadMore: "loadMore", refresh: "refresh", stateChange: "stateChange", itemsChange: "itemsChange", errorOccurred: "errorOccurred" }, viewQueries: [{ propertyName: "infiniteScroll", first: true, predicate: IonInfiniteScroll, descendants: true }], ngImport: i0, template: `
301
+ <!-- Pull to refresh wrapper -->
302
+ @if (mergedProps.enableRefresh) {
303
+ <val-refresher [props]="refresherConfig" (refresh)="onRefreshTriggered($event)">
304
+ <ng-container *ngTemplateOutlet="listContent"></ng-container>
305
+ </val-refresher>
306
+ } @else {
307
+ <ng-container *ngTemplateOutlet="listContent"></ng-container>
308
+ }
309
+
310
+ <!-- Main list content template -->
311
+ <ng-template #listContent>
312
+ <div
313
+ class="infinite-list-container"
314
+ [class]="mergedProps.cssClass"
315
+ [style.max-height]="mergedProps.maxHeight"
316
+ [style.overflow-y]="mergedProps.maxHeight ? 'auto' : 'visible'"
317
+ role="feed"
318
+ [attr.aria-busy]="state() === 'loading'"
319
+ [attr.aria-label]="mergedProps.ariaLabel"
320
+ [attr.aria-description]="mergedProps.ariaDescription"
321
+ >
322
+ <!-- Loading state (initial) -->
323
+ @if (state() === 'loading' && items().length === 0) {
324
+ <div class="infinite-list-skeleton">
325
+ @if (mergedProps.skeleton?.customTemplate) {
326
+ <ng-container *ngTemplateOutlet="mergedProps.skeleton.customTemplate"></ng-container>
327
+ } @else {
328
+ <ng-container *ngComponentOutlet="skeletonComponent; inputs: skeletonInputs"></ng-container>
329
+ }
330
+ </div>
331
+ }
332
+
333
+ <!-- Empty state -->
334
+ @if (state() === 'idle' && items().length === 0 && !isInitialLoad()) {
335
+ <div class="infinite-list-empty">
336
+ @if (mergedProps.emptyState?.template) {
337
+ <ng-container *ngTemplateOutlet="mergedProps.emptyState.template"></ng-container>
338
+ } @else {
339
+ @if (mergedProps.emptyState?.icon) {
340
+ <ion-icon [name]="mergedProps.emptyState.icon" size="large"></ion-icon>
341
+ }
342
+ @if (mergedProps.emptyState?.title) {
343
+ <h3>{{ mergedProps.emptyState.title }}</h3>
344
+ }
345
+ @if (mergedProps.emptyState?.message) {
346
+ <p>{{ mergedProps.emptyState.message }}</p>
347
+ }
348
+ }
349
+ </div>
350
+ }
351
+
352
+ <!-- Error state -->
353
+ @if (state() === 'error') {
354
+ <div class="infinite-list-error">
355
+ @if (mergedProps.errorState?.template) {
356
+ <ng-container
357
+ *ngTemplateOutlet="mergedProps.errorState.template; context: { error: error(), retry: retry.bind(this) }"
358
+ ></ng-container>
359
+ } @else {
360
+ @if (mergedProps.errorState?.icon) {
361
+ <ion-icon [name]="mergedProps.errorState.icon" color="danger" size="large"></ion-icon>
362
+ } @else {
363
+ <ion-icon name="alert-circle-outline" color="danger" size="large"></ion-icon>
364
+ }
365
+ <h3>{{ mergedProps.errorState?.title || 'Error' }}</h3>
366
+ <p>{{ mergedProps.errorState?.message || error()?.message || 'Ocurrio un error' }}</p>
367
+ @if (mergedProps.errorState?.showRetry !== false) {
368
+ <ion-button fill="outline" (click)="retry()">
369
+ {{ mergedProps.errorState?.retryText || 'Reintentar' }}
370
+ </ion-button>
371
+ }
372
+ }
373
+ </div>
374
+ }
375
+
376
+ <!-- Items list -->
377
+ @if (items().length > 0) {
378
+ <div class="infinite-list-items" [class.with-dividers]="mergedProps.showDividers">
379
+ @for (item of items(); track trackByFn($index, item); let i = $index; let first = $first; let last = $last) {
380
+ <article
381
+ class="infinite-list-item"
382
+ [attr.aria-setsize]="mergedProps.dataSource.totalCount || null"
383
+ [attr.aria-posinset]="i + 1"
384
+ >
385
+ <ng-container
386
+ *ngTemplateOutlet="
387
+ mergedProps.itemTemplate;
388
+ context: { $implicit: item, index: i, first: first, last: last, count: items().length }
389
+ "
390
+ ></ng-container>
391
+ </article>
392
+ }
393
+ </div>
394
+ }
395
+
396
+ <!-- Bottom infinite scroll -->
397
+ @if (shouldShowBottomScroll()) {
398
+ @if (mergedProps.useLoadMoreButton) {
399
+ <div class="infinite-list-load-more">
400
+ @if (hasMoreBottom()) {
401
+ <ion-button
402
+ fill="outline"
403
+ [color]="mergedProps.color"
404
+ [disabled]="state() === 'loading'"
405
+ (click)="loadBottom()"
406
+ >
407
+ @if (state() === 'loading') {
408
+ <ion-spinner [name]="mergedProps.spinnerType" slot="start"></ion-spinner>
409
+ }
410
+ {{ mergedProps.loadMoreText || 'Cargar mas' }}
411
+ </ion-button>
412
+ } @else {
413
+ <ion-text color="medium">{{ mergedProps.noMoreText || 'No hay mas items' }}</ion-text>
414
+ }
415
+ </div>
416
+ } @else {
417
+ <ion-infinite-scroll
418
+ [threshold]="mergedProps.threshold"
419
+ [disabled]="!hasMoreBottom()"
420
+ (ionInfinite)="onInfiniteScroll($event)"
421
+ >
422
+ <ion-infinite-scroll-content
423
+ [loadingSpinner]="mergedProps.spinnerType"
424
+ [loadingText]="state() === 'loading' ? 'Cargando...' : ''"
425
+ ></ion-infinite-scroll-content>
426
+ </ion-infinite-scroll>
427
+ }
428
+ }
429
+
430
+ <!-- No more items indicator -->
431
+ @if (!hasMoreBottom() && items().length > 0 && !mergedProps.useLoadMoreButton) {
432
+ <div class="infinite-list-end">
433
+ <ion-text color="medium">{{ mergedProps.noMoreText || 'No hay mas items' }}</ion-text>
434
+ </div>
435
+ }
436
+ </div>
437
+ </ng-template>
438
+
439
+ <!-- Live region for accessibility announcements -->
440
+ <div class="sr-only" role="status" aria-live="polite" [attr.aria-atomic]="true">
441
+ {{ statusAnnouncement() }}
442
+ </div>
443
+ `, isInline: true, styles: [":host{display:block}.infinite-list-container{width:100%}.infinite-list-skeleton,.infinite-list-empty,.infinite-list-error{padding:24px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px}.infinite-list-empty ion-icon,.infinite-list-error ion-icon{font-size:48px;opacity:.6}.infinite-list-empty h3,.infinite-list-error h3{margin:0;font-size:18px;font-weight:600}.infinite-list-empty p,.infinite-list-error p{margin:0;color:var(--ion-color-medium);font-size:14px}.infinite-list-items{&.with-dividers .infinite-list-item:not(:last-child){border-bottom:1px solid var(--ion-color-light-shade, #d7d8da)}}.infinite-list-load-more{display:flex;justify-content:center;padding:16px}.infinite-list-end{display:flex;justify-content:center;padding:16px;font-size:14px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: IonInfiniteScroll, selector: "ion-infinite-scroll", inputs: ["disabled", "position", "threshold"] }, { kind: "component", type: IonInfiniteScrollContent, selector: "ion-infinite-scroll-content", inputs: ["loadingSpinner", "loadingText"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: RefresherComponent, selector: "val-refresher", inputs: ["props"], outputs: ["refresh", "pullProgressChange", "stateChange"] }] }); }
444
+ }
445
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: InfiniteListComponent, decorators: [{
446
+ type: Component,
447
+ args: [{ selector: 'val-infinite-list', standalone: true, imports: [
448
+ CommonModule,
449
+ IonInfiniteScroll,
450
+ IonInfiniteScrollContent,
451
+ IonButton,
452
+ IonSpinner,
453
+ IonIcon,
454
+ IonText,
455
+ IonList,
456
+ IonItem,
457
+ RefresherComponent,
458
+ ], template: `
459
+ <!-- Pull to refresh wrapper -->
460
+ @if (mergedProps.enableRefresh) {
461
+ <val-refresher [props]="refresherConfig" (refresh)="onRefreshTriggered($event)">
462
+ <ng-container *ngTemplateOutlet="listContent"></ng-container>
463
+ </val-refresher>
464
+ } @else {
465
+ <ng-container *ngTemplateOutlet="listContent"></ng-container>
466
+ }
467
+
468
+ <!-- Main list content template -->
469
+ <ng-template #listContent>
470
+ <div
471
+ class="infinite-list-container"
472
+ [class]="mergedProps.cssClass"
473
+ [style.max-height]="mergedProps.maxHeight"
474
+ [style.overflow-y]="mergedProps.maxHeight ? 'auto' : 'visible'"
475
+ role="feed"
476
+ [attr.aria-busy]="state() === 'loading'"
477
+ [attr.aria-label]="mergedProps.ariaLabel"
478
+ [attr.aria-description]="mergedProps.ariaDescription"
479
+ >
480
+ <!-- Loading state (initial) -->
481
+ @if (state() === 'loading' && items().length === 0) {
482
+ <div class="infinite-list-skeleton">
483
+ @if (mergedProps.skeleton?.customTemplate) {
484
+ <ng-container *ngTemplateOutlet="mergedProps.skeleton.customTemplate"></ng-container>
485
+ } @else {
486
+ <ng-container *ngComponentOutlet="skeletonComponent; inputs: skeletonInputs"></ng-container>
487
+ }
488
+ </div>
489
+ }
490
+
491
+ <!-- Empty state -->
492
+ @if (state() === 'idle' && items().length === 0 && !isInitialLoad()) {
493
+ <div class="infinite-list-empty">
494
+ @if (mergedProps.emptyState?.template) {
495
+ <ng-container *ngTemplateOutlet="mergedProps.emptyState.template"></ng-container>
496
+ } @else {
497
+ @if (mergedProps.emptyState?.icon) {
498
+ <ion-icon [name]="mergedProps.emptyState.icon" size="large"></ion-icon>
499
+ }
500
+ @if (mergedProps.emptyState?.title) {
501
+ <h3>{{ mergedProps.emptyState.title }}</h3>
502
+ }
503
+ @if (mergedProps.emptyState?.message) {
504
+ <p>{{ mergedProps.emptyState.message }}</p>
505
+ }
506
+ }
507
+ </div>
508
+ }
509
+
510
+ <!-- Error state -->
511
+ @if (state() === 'error') {
512
+ <div class="infinite-list-error">
513
+ @if (mergedProps.errorState?.template) {
514
+ <ng-container
515
+ *ngTemplateOutlet="mergedProps.errorState.template; context: { error: error(), retry: retry.bind(this) }"
516
+ ></ng-container>
517
+ } @else {
518
+ @if (mergedProps.errorState?.icon) {
519
+ <ion-icon [name]="mergedProps.errorState.icon" color="danger" size="large"></ion-icon>
520
+ } @else {
521
+ <ion-icon name="alert-circle-outline" color="danger" size="large"></ion-icon>
522
+ }
523
+ <h3>{{ mergedProps.errorState?.title || 'Error' }}</h3>
524
+ <p>{{ mergedProps.errorState?.message || error()?.message || 'Ocurrio un error' }}</p>
525
+ @if (mergedProps.errorState?.showRetry !== false) {
526
+ <ion-button fill="outline" (click)="retry()">
527
+ {{ mergedProps.errorState?.retryText || 'Reintentar' }}
528
+ </ion-button>
529
+ }
530
+ }
531
+ </div>
532
+ }
533
+
534
+ <!-- Items list -->
535
+ @if (items().length > 0) {
536
+ <div class="infinite-list-items" [class.with-dividers]="mergedProps.showDividers">
537
+ @for (item of items(); track trackByFn($index, item); let i = $index; let first = $first; let last = $last) {
538
+ <article
539
+ class="infinite-list-item"
540
+ [attr.aria-setsize]="mergedProps.dataSource.totalCount || null"
541
+ [attr.aria-posinset]="i + 1"
542
+ >
543
+ <ng-container
544
+ *ngTemplateOutlet="
545
+ mergedProps.itemTemplate;
546
+ context: { $implicit: item, index: i, first: first, last: last, count: items().length }
547
+ "
548
+ ></ng-container>
549
+ </article>
550
+ }
551
+ </div>
552
+ }
553
+
554
+ <!-- Bottom infinite scroll -->
555
+ @if (shouldShowBottomScroll()) {
556
+ @if (mergedProps.useLoadMoreButton) {
557
+ <div class="infinite-list-load-more">
558
+ @if (hasMoreBottom()) {
559
+ <ion-button
560
+ fill="outline"
561
+ [color]="mergedProps.color"
562
+ [disabled]="state() === 'loading'"
563
+ (click)="loadBottom()"
564
+ >
565
+ @if (state() === 'loading') {
566
+ <ion-spinner [name]="mergedProps.spinnerType" slot="start"></ion-spinner>
567
+ }
568
+ {{ mergedProps.loadMoreText || 'Cargar mas' }}
569
+ </ion-button>
570
+ } @else {
571
+ <ion-text color="medium">{{ mergedProps.noMoreText || 'No hay mas items' }}</ion-text>
572
+ }
573
+ </div>
574
+ } @else {
575
+ <ion-infinite-scroll
576
+ [threshold]="mergedProps.threshold"
577
+ [disabled]="!hasMoreBottom()"
578
+ (ionInfinite)="onInfiniteScroll($event)"
579
+ >
580
+ <ion-infinite-scroll-content
581
+ [loadingSpinner]="mergedProps.spinnerType"
582
+ [loadingText]="state() === 'loading' ? 'Cargando...' : ''"
583
+ ></ion-infinite-scroll-content>
584
+ </ion-infinite-scroll>
585
+ }
586
+ }
587
+
588
+ <!-- No more items indicator -->
589
+ @if (!hasMoreBottom() && items().length > 0 && !mergedProps.useLoadMoreButton) {
590
+ <div class="infinite-list-end">
591
+ <ion-text color="medium">{{ mergedProps.noMoreText || 'No hay mas items' }}</ion-text>
592
+ </div>
593
+ }
594
+ </div>
595
+ </ng-template>
596
+
597
+ <!-- Live region for accessibility announcements -->
598
+ <div class="sr-only" role="status" aria-live="polite" [attr.aria-atomic]="true">
599
+ {{ statusAnnouncement() }}
600
+ </div>
601
+ `, styles: [":host{display:block}.infinite-list-container{width:100%}.infinite-list-skeleton,.infinite-list-empty,.infinite-list-error{padding:24px 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px}.infinite-list-empty ion-icon,.infinite-list-error ion-icon{font-size:48px;opacity:.6}.infinite-list-empty h3,.infinite-list-error h3{margin:0;font-size:18px;font-weight:600}.infinite-list-empty p,.infinite-list-error p{margin:0;color:var(--ion-color-medium);font-size:14px}.infinite-list-items{&.with-dividers .infinite-list-item:not(:last-child){border-bottom:1px solid var(--ion-color-light-shade, #d7d8da)}}.infinite-list-load-more{display:flex;justify-content:center;padding:16px}.infinite-list-end{display:flex;justify-content:center;padding:16px;font-size:14px}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
602
+ }], propDecorators: { infiniteScroll: [{
603
+ type: ViewChild,
604
+ args: [IonInfiniteScroll]
605
+ }], props: [{
606
+ type: Input
607
+ }], loadMore: [{
608
+ type: Output
609
+ }], refresh: [{
610
+ type: Output
611
+ }], stateChange: [{
612
+ type: Output
613
+ }], itemsChange: [{
614
+ type: Output
615
+ }], errorOccurred: [{
616
+ type: Output
617
+ }] } });
618
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5maW5pdGUtbGlzdC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL2NvbXBvbmVudHMvb3JnYW5pc21zL2luZmluaXRlLWxpc3QvaW5maW5pdGUtbGlzdC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxLQUFLLEVBQ0wsTUFBTSxFQUNOLFlBQVksRUFDWixNQUFNLEVBQ04sUUFBUSxFQUdSLFNBQVMsRUFDVCxNQUFNLEVBQ04saUJBQWlCLEdBQ2xCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLHdCQUF3QixFQUN4QixTQUFTLEVBQ1QsVUFBVSxFQUNWLE9BQU8sRUFDUCxPQUFPLEVBQ1AsT0FBTyxFQUNQLE9BQU8sR0FDUixNQUFNLDJCQUEyQixDQUFDO0FBQ25DLE9BQU8sRUFBRSxjQUFjLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BELE9BQU8sRUFNTCw4QkFBOEIsR0FDL0IsTUFBTSxTQUFTLENBQUM7QUFFakIsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sK0NBQStDLENBQUM7QUFDbkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDZDQUE2QyxDQUFDOzs7QUFHOUU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQ0c7QUEyT0gsTUFBTSxPQUFPLHFCQUFxQjtJQTFPbEM7UUEyT21CLG9CQUFlLEdBQUcsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQzFDLFFBQUcsR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQU9qRCxpQkFBaUI7UUFDUCxhQUFRLEdBQUcsSUFBSSxZQUFZLEVBQWlCLENBQUM7UUFDN0MsWUFBTyxHQUFHLElBQUksWUFB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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErSVQ7OEJBZ0Y2QixjQUFjO3NCQUEzQyxTQUFTO3VCQUFDLGlCQUFpQjtnQkFHbkIsS0FBSztzQkFBYixLQUFLO2dCQUdJLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csT0FBTztzQkFBaEIsTUFBTTtnQkFDRyxXQUFXO3NCQUFwQixNQUFNO2dCQUNHLFdBQVc7c0JBQXBCLE1BQU07Z0JBQ0csYUFBYTtzQkFBdEIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgSW5wdXQsXG4gIE91dHB1dCxcbiAgRXZlbnRFbWl0dGVyLFxuICBzaWduYWwsXG4gIGNvbXB1dGVkLFxuICBPbkluaXQsXG4gIE9uRGVzdHJveSxcbiAgVmlld0NoaWxkLFxuICBpbmplY3QsXG4gIENoYW5nZURldGVjdG9yUmVmLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBJb25JbmZpbml0ZVNjcm9sbCxcbiAgSW9uSW5maW5pdGVTY3JvbGxDb250ZW50LFxuICBJb25CdXR0b24sXG4gIElvblNwaW5uZXIsXG4gIElvbkljb24sXG4gIElvblRleHQsXG4gIElvbkxpc3QsXG4gIElvbkl0ZW0sXG59IGZyb20gJ0Bpb25pYy9hbmd1bGFyL3N0YW5kYWxvbmUnO1xuaW1wb3J0IHsgZmlyc3RWYWx1ZUZyb20sIGlzT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtcbiAgSW5maW5pdGVMaXN0TWV0YWRhdGEsXG4gIEluZmluaXRlTGlzdFN0YXRlLFxuICBMb2FkTW9yZUV2ZW50LFxuICBMb2FkUGFyYW1zLFxuICBMb2FkUmVzdWx0LFxuICBERUZBVUxUX0lORklOSVRFX0xJU1RfTUVUQURBVEEsXG59IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgUmVmcmVzaEV2ZW50LCBSZWZyZXNoZXJNZXRhZGF0YSB9IGZyb20gJy4uLy4uL21vbGVjdWxlcy9yZWZyZXNoZXIvdHlwZXMnO1xuaW1wb3J0IHsgUmVmcmVzaGVyQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vbW9sZWN1bGVzL3JlZnJlc2hlci9yZWZyZXNoZXIuY29tcG9uZW50JztcbmltcG9ydCB7IFNrZWxldG9uU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL3NrZWxldG9uL3NrZWxldG9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgU2tlbGV0b25UZW1wbGF0ZUNvbXBvbmVudCB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL3NrZWxldG9uL3R5cGVzJztcblxuLyoqXG4gKiBDb21wb25lbnRlIHdyYXBwZXIgcGFyYSBsaXN0YXMgY29uIGluZmluaXRlIHNjcm9sbC5cbiAqXG4gKiBAZXhhbXBsZVxuICogPCEtLSBVc28gYmFzaWNvIGNvbiBkYXRhIHNvdXJjZSAtLT5cbiAqIDx2YWwtaW5maW5pdGUtbGlzdFxuICogICBbcHJvcHNdPVwie1xuICogICAgIGRhdGFTb3VyY2U6IHsgbG9hZEZuOiBsb2FkVXNlcnMsIHRyYWNrQnk6IHRyYWNrQnlVc2VySWQgfSxcbiAqICAgICBpdGVtVGVtcGxhdGU6IHVzZXJUZW1wbGF0ZSxcbiAqICAgICBwYWdlU2l6ZTogMjAsXG4gKiAgICAgdGhyZXNob2xkOiAnMTUwcHgnXG4gKiAgIH1cIlxuICogPjwvdmFsLWluZmluaXRlLWxpc3Q+XG4gKlxuICogPG5nLXRlbXBsYXRlICN1c2VyVGVtcGxhdGUgbGV0LXVzZXIgbGV0LWluZGV4PVwiaW5kZXhcIj5cbiAqICAgPHZhbC1jYXJkIFtwcm9wc109XCJ7IHRpdGxlOiB1c2VyLm5hbWUsIHN1YnRpdGxlOiB1c2VyLmVtYWlsIH1cIj5cbiAqICAgICA8cD57eyB1c2VyLmJpbyB9fTwvcD5cbiAqICAgPC92YWwtY2FyZD5cbiAqIDwvbmctdGVtcGxhdGU+XG4gKlxuICogQGV4YW1wbGVcbiAqIDwhLS0gQ29uIHB1bGwtdG8tcmVmcmVzaCB5IGVzdGFkbyB2YWNpbyBwZXJzb25hbGl6YWRvIC0tPlxuICogPHZhbC1pbmZpbml0ZS1saXN0XG4gKiAgIFtwcm9wc109XCJ7XG4gKiAgICAgZGF0YVNvdXJjZTogeyBsb2FkRm46IGxvYWRNZXNzYWdlcyB9LFxuICogICAgIGl0ZW1UZW1wbGF0ZTogbWVzc2FnZVRlbXBsYXRlLFxuICogICAgIGRpcmVjdGlvbjogJ2JvdGgnLFxuICogICAgIGVuYWJsZVJlZnJlc2g6IHRydWUsXG4gKiAgICAgZW1wdHlTdGF0ZToge1xuICogICAgICAgaWNvbjogJ2NoYXRidWJibGVzLW91dGxpbmUnLFxuICogICAgICAgdGl0bGU6ICdTaW4gbWVuc2FqZXMnLFxuICogICAgICAgbWVzc2FnZTogJ0luaWNpYSB1bmEgY29udmVyc2FjaW9uJ1xuICogICAgIH0sXG4gKiAgICAgc2tlbGV0b246IHsgdGVtcGxhdGU6ICdsaXN0JywgY291bnQ6IDUgfVxuICogICB9XCJcbiAqICAgKHJlZnJlc2gpPVwib25SZWZyZXNoKCRldmVudClcIlxuICogPjwvdmFsLWluZmluaXRlLWxpc3Q+XG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3ZhbC1pbmZpbml0ZS1saXN0JyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIENvbW1vbk1vZHVsZSxcbiAgICBJb25JbmZpbml0ZVNjcm9sbCxcbiAgICBJb25JbmZpbml0ZVNjcm9sbENvbnRlbnQsXG4gICAgSW9uQnV0dG9uLFxuICAgIElvblNwaW5uZXIsXG4gICAgSW9uSWNvbixcbiAgICBJb25UZXh0LFxuICAgIElvbkxpc3QsXG4gICAgSW9uSXRlbSxcbiAgICBSZWZyZXNoZXJDb21wb25lbnQsXG4gIF0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPCEtLSBQdWxsIHRvIHJlZnJlc2ggd3JhcHBlciAtLT5cbiAgICBAaWYgKG1lcmdlZFByb3BzLmVuYWJsZVJlZnJlc2gpIHtcbiAgICAgIDx2YWwtcmVmcmVzaGVyIFtwcm9wc109XCJyZWZyZXNoZXJDb25maWdcIiAocmVmcmVzaCk9XCJvblJlZnJlc2hUcmlnZ2VyZWQoJGV2ZW50KVwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwibGlzdENvbnRlbnRcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvdmFsLXJlZnJlc2hlcj5cbiAgICB9IEBlbHNlIHtcbiAgICAgIDxuZy1jb250YWluZXIgKm5nVGVtcGxhdGVPdXRsZXQ9XCJsaXN0Q29udGVudFwiPjwvbmctY29udGFpbmVyPlxuICAgIH1cblxuICAgIDwhLS0gTWFpbiBsaXN0IGNvbnRlbnQgdGVtcGxhdGUgLS0+XG4gICAgPG5nLXRlbXBsYXRlICNsaXN0Q29udGVudD5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJpbmZpbml0ZS1saXN0LWNvbnRhaW5lclwiXG4gICAgICAgIFtjbGFzc109XCJtZXJnZWRQcm9wcy5jc3NDbGFzc1wiXG4gICAgICAgIFtzdHlsZS5tYXgtaGVpZ2h0XT1cIm1lcmdlZFByb3BzLm1heEhlaWdodFwiXG4gICAgICAgIFtzdHlsZS5vdmVyZmxvdy15XT1cIm1lcmdlZFByb3BzLm1heEhlaWdodCA/ICdhdXRvJyA6ICd2aXNpYmxlJ1wiXG4gICAgICAgIHJvbGU9XCJmZWVkXCJcbiAgICAgICAgW2F0dHIuYXJpYS1idXN5XT1cInN0YXRlKCkgPT09ICdsb2FkaW5nJ1wiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwibWVyZ2VkUHJvcHMuYXJpYUxhYmVsXCJcbiAgICAgICAgW2F0dHIuYXJpYS1kZXNjcmlwdGlvbl09XCJtZXJnZWRQcm9wcy5hcmlhRGVzY3JpcHRpb25cIlxuICAgICAgPlxuICAgICAgICA8IS0tIExvYWRpbmcgc3RhdGUgKGluaXRpYWwpIC0tPlxuICAgICAgICBAaWYgKHN0YXRlKCkgPT09ICdsb2FkaW5nJyAmJiBpdGVtcygpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbmZpbml0ZS1saXN0LXNrZWxldG9uXCI+XG4gICAgICAgICAgICBAaWYgKG1lcmdlZFByb3BzLnNrZWxldG9uPy5jdXN0b21UZW1wbGF0ZSkge1xuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwibWVyZ2VkUHJvcHMuc2tlbGV0b24uY3VzdG9tVGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0NvbXBvbmVudE91dGxldD1cInNrZWxldG9uQ29tcG9uZW50OyBpbnB1dHM6IHNrZWxldG9uSW5wdXRzXCI+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIH1cblxuICAgICAgICA8IS0tIEVtcHR5IHN0YXRlIC0tPlxuICAgICAgICBAaWYgKHN0YXRlKCkgPT09ICdpZGxlJyAmJiBpdGVtcygpLmxlbmd0aCA9PT0gMCAmJiAhaXNJbml0aWFsTG9hZCgpKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImluZmluaXRlLWxpc3QtZW1wdHlcIj5cbiAgICAgICAgICAgIEBpZiAobWVyZ2VkUHJvcHMuZW1wdHlTdGF0ZT8udGVtcGxhdGUpIHtcbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdUZW1wbGF0ZU91dGxldD1cIm1lcmdlZFByb3BzLmVtcHR5U3RhdGUudGVtcGxhdGVcIj48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICBAaWYgKG1lcmdlZFByb3BzLmVtcHR5U3RhdGU/Lmljb24pIHtcbiAgICAgICAgICAgICAgICA8aW9uLWljb24gW25hbWVdPVwibWVyZ2VkUHJvcHMuZW1wdHlTdGF0ZS5pY29uXCIgc2l6ZT1cImxhcmdlXCI+PC9pb24taWNvbj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBAaWYgKG1lcmdlZFByb3BzLmVtcHR5U3RhdGU/LnRpdGxlKSB7XG4gICAgICAgICAgICAgICAgPGgzPnt7IG1lcmdlZFByb3BzLmVtcHR5U3RhdGUudGl0bGUgfX08L2gzPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIEBpZiAobWVyZ2VkUHJvcHMuZW1wdHlTdGF0ZT8ubWVzc2FnZSkge1xuICAgICAgICAgICAgICAgIDxwPnt7IG1lcmdlZFByb3BzLmVtcHR5U3RhdGUubWVzc2FnZSB9fTwvcD5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG5cbiAgICAgICAgPCEtLSBFcnJvciBzdGF0ZSAtLT5cbiAgICAgICAgQGlmIChzdGF0ZSgpID09PSAnZXJyb3InKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImluZmluaXRlLWxpc3QtZXJyb3JcIj5cbiAgICAgICAgICAgIEBpZiAobWVyZ2VkUHJvcHMuZXJyb3JTdGF0ZT8udGVtcGxhdGUpIHtcbiAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwibWVyZ2VkUHJvcHMuZXJyb3JTdGF0ZS50ZW1wbGF0ZTsgY29udGV4dDogeyBlcnJvcjogZXJyb3IoKSwgcmV0cnk6IHJldHJ5LmJpbmQodGhpcykgfVwiXG4gICAgICAgICAgICAgID48L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICBAaWYgKG1lcmdlZFByb3BzLmVycm9yU3RhdGU/Lmljb24pIHtcbiAgICAgICAgICAgICAgICA8aW9uLWljb24gW25hbWVdPVwibWVyZ2VkUHJvcHMuZXJyb3JTdGF0ZS5pY29uXCIgY29sb3I9XCJkYW5nZXJcIiBzaXplPVwibGFyZ2VcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cImFsZXJ0LWNpcmNsZS1vdXRsaW5lXCIgY29sb3I9XCJkYW5nZXJcIiBzaXplPVwibGFyZ2VcIj48L2lvbi1pY29uPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDxoMz57eyBtZXJnZWRQcm9wcy5lcnJvclN0YXRlPy50aXRsZSB8fCAnRXJyb3InIH19PC9oMz5cbiAgICAgICAgICAgICAgPHA+e3sgbWVyZ2VkUHJvcHMuZXJyb3JTdGF0ZT8ubWVzc2FnZSB8fCBlcnJvcigpPy5tZXNzYWdlIHx8ICdPY3VycmlvIHVuIGVycm9yJyB9fTwvcD5cbiAgICAgICAgICAgICAgQGlmIChtZXJnZWRQcm9wcy5lcnJvclN0YXRlPy5zaG93UmV0cnkgIT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgPGlvbi1idXR0b24gZmlsbD1cIm91dGxpbmVcIiAoY2xpY2spPVwicmV0cnkoKVwiPlxuICAgICAgICAgICAgICAgICAge3sgbWVyZ2VkUHJvcHMuZXJyb3JTdGF0ZT8ucmV0cnlUZXh0IHx8ICdSZWludGVudGFyJyB9fVxuICAgICAgICAgICAgICAgIDwvaW9uLWJ1dHRvbj5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG5cbiAgICAgICAgPCEtLSBJdGVtcyBsaXN0IC0tPlxuICAgICAgICBAaWYgKGl0ZW1zKCkubGVuZ3RoID4gMCkge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbmZpbml0ZS1saXN0LWl0ZW1zXCIgW2NsYXNzLndpdGgtZGl2aWRlcnNdPVwibWVyZ2VkUHJvcHMuc2hvd0RpdmlkZXJzXCI+XG4gICAgICAgICAgICBAZm9yIChpdGVtIG9mIGl0ZW1zKCk7IHRyYWNrIHRyYWNrQnlGbigkaW5kZXgsIGl0ZW0pOyBsZXQgaSA9ICRpbmRleDsgbGV0IGZpcnN0ID0gJGZpcnN0OyBsZXQgbGFzdCA9ICRsYXN0KSB7XG4gICAgICAgICAgICAgIDxhcnRpY2xlXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJpbmZpbml0ZS1saXN0LWl0ZW1cIlxuICAgICAgICAgICAgICAgIFthdHRyLmFyaWEtc2V0c2l6ZV09XCJtZXJnZWRQcm9wcy5kYXRhU291cmNlLnRvdGFsQ291bnQgfHwgbnVsbFwiXG4gICAgICAgICAgICAgICAgW2F0dHIuYXJpYS1wb3NpbnNldF09XCJpICsgMVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgICAqbmdUZW1wbGF0ZU91dGxldD1cIlxuICAgICAgICAgICAgICAgICAgICBtZXJnZWRQcm9wcy5pdGVtVGVtcGxhdGU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6IHsgJGltcGxpY2l0OiBpdGVtLCBpbmRleDogaSwgZmlyc3Q6IGZpcnN0LCBsYXN0OiBsYXN0LCBjb3VudDogaXRlbXMoKS5sZW5ndGggfVxuICAgICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgIDwvYXJ0aWNsZT5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIDwhLS0gQm90dG9tIGluZmluaXRlIHNjcm9sbCAtLT5cbiAgICAgICAgQGlmIChzaG91bGRTaG93Qm90dG9tU2Nyb2xsKCkpIHtcbiAgICAgICAgICBAaWYgKG1lcmdlZFByb3BzLnVzZUxvYWRNb3JlQnV0dG9uKSB7XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaW5maW5pdGUtbGlzdC1sb2FkLW1vcmVcIj5cbiAgICAgICAgICAgICAgQGlmIChoYXNNb3JlQm90dG9tKCkpIHtcbiAgICAgICAgICAgICAgICA8aW9uLWJ1dHRvblxuICAgICAgICAgICAgICAgICAgZmlsbD1cIm91dGxpbmVcIlxuICAgICAgICAgICAgICAgICAgW2NvbG9yXT1cIm1lcmdlZFByb3BzLmNvbG9yXCJcbiAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJzdGF0ZSgpID09PSAnbG9hZGluZydcIlxuICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cImxvYWRCb3R0b20oKVwiXG4gICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgQGlmIChzdGF0ZSgpID09PSAnbG9hZGluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgPGlvbi1zcGlubmVyIFtuYW1lXT1cIm1lcmdlZFByb3BzLnNwaW5uZXJUeXBlXCIgc2xvdD1cInN0YXJ0XCI+PC9pb24tc3Bpbm5lcj5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIHt7IG1lcmdlZFByb3BzLmxvYWRNb3JlVGV4dCB8fCAnQ2FyZ2FyIG1hcycgfX1cbiAgICAgICAgICAgICAgICA8L2lvbi1idXR0b24+XG4gICAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICAgIDxpb24tdGV4dCBjb2xvcj1cIm1lZGl1bVwiPnt7IG1lcmdlZFByb3BzLm5vTW9yZVRleHQgfHwgJ05vIGhheSBtYXMgaXRlbXMnIH19PC9pb24tdGV4dD5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgICA8aW9uLWluZmluaXRlLXNjcm9sbFxuICAgICAgICAgICAgICBbdGhyZXNob2xkXT1cIm1lcmdlZFByb3BzLnRocmVzaG9sZFwiXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhaGFzTW9yZUJvdHRvbSgpXCJcbiAgICAgICAgICAgICAgKGlvbkluZmluaXRlKT1cIm9uSW5maW5pdGVTY3JvbGwoJGV2ZW50KVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxpb24taW5maW5pdGUtc2Nyb2xsLWNvbnRlbnRcbiAgICAgICAgICAgICAgICBbbG9hZGluZ1NwaW5uZXJdPVwibWVyZ2VkUHJvcHMuc3Bpbm5lclR5cGVcIlxuICAgICAgICAgICAgICAgIFtsb2FkaW5nVGV4dF09XCJzdGF0ZSgpID09PSAnbG9hZGluZycgPyAnQ2FyZ2FuZG8uLi4nIDogJydcIlxuICAgICAgICAgICAgICA+PC9pb24taW5maW5pdGUtc2Nyb2xsLWNvbnRlbnQ+XG4gICAgICAgICAgICA8L2lvbi1pbmZpbml0ZS1zY3JvbGw+XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgPCEtLSBObyBtb3JlIGl0ZW1zIGluZGljYXRvciAtLT5cbiAgICAgICAgQGlmICghaGFzTW9yZUJvdHRvbSgpICYmIGl0ZW1zKCkubGVuZ3RoID4gMCAmJiAhbWVyZ2VkUHJvcHMudXNlTG9hZE1vcmVCdXR0b24pIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiaW5maW5pdGUtbGlzdC1lbmRcIj5cbiAgICAgICAgICAgIDxpb24tdGV4dCBjb2xvcj1cIm1lZGl1bVwiPnt7IG1lcmdlZFByb3BzLm5vTW9yZVRleHQgfHwgJ05vIGhheSBtYXMgaXRlbXMnIH19PC9pb24tdGV4dD5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG4gICAgPC9uZy10ZW1wbGF0ZT5cblxuICAgIDwhLS0gTGl2ZSByZWdpb24gZm9yIGFjY2Vzc2liaWxpdHkgYW5ub3VuY2VtZW50cyAtLT5cbiAgICA8ZGl2IGNsYXNzPVwic3Itb25seVwiIHJvbGU9XCJzdGF0dXNcIiBhcmlhLWxpdmU9XCJwb2xpdGVcIiBbYXR0ci5hcmlhLWF0b21pY109XCJ0cnVlXCI+XG4gICAgICB7eyBzdGF0dXNBbm5vdW5jZW1lbnQoKSB9fVxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZXM6IFtcbiAgICBgXG4gICAgICA6aG9zdCB7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgfVxuXG4gICAgICAuaW5maW5pdGUtbGlzdC1jb250YWluZXIge1xuICAgICAgICB3aWR0aDogMTAwJTtcbiAgICAgIH1cblxuICAgICAgLmluZmluaXRlLWxpc3Qtc2tlbGV0b24sXG4gICAgICAuaW5maW5pdGUtbGlzdC1lbXB0eSxcbiAgICAgIC5pbmZpbml0ZS1saXN0LWVycm9yIHtcbiAgICAgICAgcGFkZGluZzogMjRweCAxNnB4O1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgICBnYXA6IDEycHg7XG4gICAgICB9XG5cbiAgICAgIC5pbmZpbml0ZS1saXN0LWVtcHR5IGlvbi1pY29uLFxuICAgICAgLmluZmluaXRlLWxpc3QtZXJyb3IgaW9uLWljb24ge1xuICAgICAgICBmb250LXNpemU6IDQ4cHg7XG4gICAgICAgIG9wYWNpdHk6IDAuNjtcbiAgICAgIH1cblxuICAgICAgLmluZmluaXRlLWxpc3QtZW1wdHkgaDMsXG4gICAgICAuaW5maW5pdGUtbGlzdC1lcnJvciBoMyB7XG4gICAgICAgIG1hcmdpbjogMDtcbiAgICAgICAgZm9udC1zaXplOiAxOHB4O1xuICAgICAgICBmb250LXdlaWdodDogNjAwO1xuICAgICAgfVxuXG4gICAgICAuaW5maW5pdGUtbGlzdC1lbXB0eSBwLFxuICAgICAgLmluZmluaXRlLWxpc3QtZXJyb3IgcCB7XG4gICAgICAgIG1hcmdpbjogMDtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1tZWRpdW0pO1xuICAgICAgICBmb250LXNpemU6IDE0cHg7XG4gICAgICB9XG5cbiAgICAgIC5pbmZpbml0ZS1saXN0LWl0ZW1zIHtcbiAgICAgICAgJi53aXRoLWRpdmlkZXJzIC5pbmZpbml0ZS1saXN0LWl0ZW06bm90KDpsYXN0LWNoaWxkKSB7XG4gICAgICAgICAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkIHZhcigtLWlvbi1jb2xvci1saWdodC1zaGFkZSwgI2Q3ZDhkYSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLmluZmluaXRlLWxpc3QtbG9hZC1tb3JlIHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gICAgICAgIHBhZGRpbmc6IDE2cHg7XG4gICAgICB9XG5cbiAgICAgIC5pbmZpbml0ZS1saXN0LWVuZCB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgICAgICBwYWRkaW5nOiAxNnB4O1xuICAgICAgICBmb250LXNpemU6IDE0cHg7XG4gICAgICB9XG5cbiAgICAgIC5zci1vbmx5IHtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB3aWR0aDogMXB4O1xuICAgICAgICBoZWlnaHQ6IDFweDtcbiAgICAgICAgcGFkZGluZzogMDtcbiAgICAgICAgbWFyZ2luOiAtMXB4O1xuICAgICAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgICAgICBjbGlwOiByZWN0KDAsIDAsIDAsIDApO1xuICAgICAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICAgICAgICBib3JkZXI6IDA7XG4gICAgICB9XG4gICAgYCxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgSW5maW5pdGVMaXN0Q29tcG9uZW50PFQgPSB1bmtub3duPiBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgcHJpdmF0ZSByZWFkb25seSBza2VsZXRvblNlcnZpY2UgPSBpbmplY3QoU2tlbGV0b25TZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjZHIgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuXG4gIEBWaWV3Q2hpbGQoSW9uSW5maW5pdGVTY3JvbGwpIGluZmluaXRlU2Nyb2xsPzogSW9uSW5maW5pdGVTY3JvbGw7XG5cbiAgLyoqIENvbmZpZ3VyYWNpb24gZGVsIGNvbXBvbmVudGUgKi9cbiAgQElucHV0KCkgcHJvcHMhOiBJbmZpbml0ZUxpc3RNZXRhZGF0YTxUPjtcblxuICAvLyA9PT0gRXZlbnRzID09PVxuICBAT3V0cHV0KCkgbG9hZE1vcmUgPSBuZXcgRXZlbnRFbWl0dGVyPExvYWRNb3JlRXZlbnQ+KCk7XG4gIEBPdXRwdXQoKSByZWZyZXNoID0gbmV3IEV2ZW50RW1pdHRlcjxSZWZyZXNoRXZlbnQ+KCk7XG4gIEBPdXRwdXQoKSBzdGF0ZUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8SW5maW5pdGVMaXN0U3RhdGU+KCk7XG4gIEBPdXRwdXQoKSBpdGVtc0NoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8VFtdPigpO1xuICBAT3V0cHV0KCkgZXJyb3JPY2N1cnJlZCA9IG5ldyBFdmVudEVtaXR0ZXI8RXJyb3I+KCk7XG5cbiAgLy8gPT09IFJlYWN0aXZlIFN0YXRlID09PVxuICByZWFkb25seSBpdGVtcyA9IHNpZ25hbDxUW10+KFtdKTtcbiAgcmVhZG9ubHkgc3RhdGUgPSBzaWduYWw8SW5maW5pdGVMaXN0U3RhdGU+KCdpZGxlJyk7XG4gIHJlYWRvbmx5IGhhc01vcmVCb3R0b20gPSBzaWduYWw8Ym9vbGVhbj4odHJ1ZSk7XG4gIHJlYWRvbmx5IGhhc01vcmVUb3AgPSBzaWduYWw8Ym9vbGVhbj4oZmFsc2UpO1xuICByZWFkb25seSBlcnJvciA9IHNpZ25hbDxFcnJvciB8IG51bGw+KG51bGwpO1xuICByZWFkb25seSBpc0luaXRpYWxMb2FkID0gc2lnbmFsPGJvb2xlYW4+KHRydWUpO1xuXG4gIHByaXZhdGUgY3VycmVudFBhZ2UgPSAwO1xuICBwcml2YXRlIGN1cnJlbnRDdXJzb3I6IHVua25vd24gPSBudWxsO1xuXG4gIC8qKiBQcm9ncmVzbyBkZSBjYXJnYSAoMC0xIHNpIHRvdGFsQ291bnQgY29ub2NpZG8pICovXG4gIHJlYWRvbmx5IGxvYWRQcm9ncmVzcyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBpZiAoIXRoaXMucHJvcHM/LmRhdGFTb3VyY2U/LnRvdGFsQ291bnQpIHJldHVybiBudWxsO1xuICAgIHJldHVybiB0aGlzLml0ZW1zKCkubGVuZ3RoIC8gdGhpcy5wcm9wcy5kYXRhU291cmNlLnRvdGFsQ291bnQ7XG4gIH0pO1xuXG4gIC8qKiBQcm9wcyBjb21iaW5hZG9zIGNvbiBkZWZhdWx0cyAqL1xuICBnZXQgbWVyZ2VkUHJvcHMoKTogSW5maW5pdGVMaXN0TWV0YWRhdGE8VD4ge1xuICAgIHJldHVybiB7IC4uLkRFRkFVTFRfSU5GSU5JVEVfTElTVF9NRVRBREFUQSwgLi4udGhpcy5wcm9wcyB9IGFzIEluZmluaXRlTGlzdE1ldGFkYXRhPFQ+O1xuICB9XG5cbiAgLyoqIENvbmZpZyBkZWwgcmVmcmVzaGVyICovXG4gIGdldCByZWZyZXNoZXJDb25maWcoKTogUmVmcmVzaGVyTWV0YWRhdGEge1xuICAgIHJldHVybiB0aGlzLm1lcmdlZFByb3BzLnJlZnJlc2hDb25maWcgPz8ge307XG4gIH1cblxuICAvKiogQ29tcG9uZW50ZSBkZSBza2VsZXRvbiBhIHVzYXIgKi9cbiAgZ2V0IHNrZWxldG9uQ29tcG9uZW50KCkge1xuICAgIGNvbnN0IHRlbXBsYXRlTmFtZSA9IHRoaXMubWVyZ2VkUHJvcHMuc2tlbGV0b24/LnRlbXBsYXRlIHx8ICdsaXN0JztcbiAgICBjb25zdCB0ZW1wbGF0ZSA9IHRoaXMuc2tlbGV0b25TZXJ2aWNlLmdldFRlbXBsYXRlKHRlbXBsYXRlTmFtZSk7XG4gICAgcmV0dXJuIHRlbXBsYXRlPy5jb21wb25lbnQgPz8gbnVsbDtcbiAgfVxuXG4gIC8qKiBJbnB1dHMgcGFyYSBlbCBza2VsZXRvbiAqL1xuICBnZXQgc2tlbGV0b25JbnB1dHMoKTogeyBjb25maWc6IHVua25vd24gfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbmZpZzoge1xuICAgICAgICBjb3VudDogdGhpcy5tZXJnZWRQcm9wcy5za2VsZXRvbj8uY291bnQgPz8gMyxcbiAgICAgICAgYW5pbWF0ZWQ6IHRydWUsXG4gICAgICAgIC4uLnRoaXMubWVyZ2VkUHJvcHMuc2tlbGV0b24/LmNvbmZpZyxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBBbnVuY2lvIGRlIGVzdGFkbyBwYXJhIGxlY3RvcmVzIGRlIHBhbnRhbGxhICovXG4gIHJlYWRvbmx5IHN0YXR1c0Fubm91bmNlbWVudCA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBzd2l0Y2ggKHRoaXMuc3RhdGUoKSkge1xuICAgICAgY2FzZSAnbG9hZGluZyc6XG4gICAgICAgIHJldHVybiAnQ2FyZ2FuZG8gaXRlbXMuLi4nO1xuICAgICAgY2FzZSAnZXJyb3InOlxuICAgICAgICByZXR1cm4gYEVycm9yOiAke3RoaXMuZXJyb3IoKT8ubWVzc2FnZSB8fCAnT2N1cnJpbyB1biBlcnJvcid9YDtcbiAgICAgIGNhc2UgJ2NvbXBsZXRlJzpcbiAgICAgICAgcmV0dXJuICdUb2RvcyBsb3MgaXRlbXMgaGFuIHNpZG8gY2FyZ2Fkb3MnO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgfSk7XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgLy8gQ2FyZ2FyIGl0ZW1zIGluaWNpYWxlcyBkZWwgZGF0YVNvdXJjZSBzaSBleGlzdGVuXG4gICAgaWYgKHRoaXMucHJvcHMuZGF0YVNvdXJjZS5pdGVtcz8ubGVuZ3RoKSB7XG4gICAgICB0aGlzLml0ZW1zLnNldChbLi4udGhpcy5wcm9wcy5kYXRhU291cmNlLml0ZW1zXSk7XG4gICAgICB0aGlzLmlzSW5pdGlhbExvYWQuc2V0KGZhbHNlKTtcbiAgICB9XG5cbiAgICAvLyBBdXRvLWNhcmdhciBzaSBlc3RhIGhhYmlsaXRhZG9cbiAgICBpZiAodGhpcy5tZXJnZWRQcm9wcy5hdXRvTG9hZCAmJiAhdGhpcy5pdGVtcygpLmxlbmd0aCkge1xuICAgICAgdGhpcy5sb2FkSW5pdGlhbCgpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIC8vIENsZWFudXBcbiAgfVxuXG4gIC8qKiBGdW5jaW9uIGRlIHRyYWNraW5nIHBhcmEgbmdGb3IgKi9cbiAgdHJhY2tCeUZuKGluZGV4OiBudW1iZXIsIGl0ZW06IFQpOiB1bmtub3duIHtcbiAgICBpZiAodGhpcy5wcm9wcy5kYXRhU291cmNlLnRyYWNrQnkpIHtcbiAgICAgIHJldHVybiB0aGlzLnByb3BzLmRhdGFTb3VyY2UudHJhY2tCeShpbmRleCwgaXRlbSk7XG4gICAgfVxuICAgIHJldHVybiBpbmRleDtcbiAgfVxuXG4gIC8qKiBTaSBkZWJlIG1vc3RyYXIgZWwgc2Nyb2xsIGluZmVyaW9yICovXG4gIHNob3VsZFNob3dCb3R0b21TY3JvbGwoKTogYm9vbGVhbiB7XG4gICAgY29uc3QgZGlyID0gdGhpcy5tZXJnZWRQcm9wcy5kaXJlY3Rpb247XG4gICAgcmV0dXJuIChkaXIgPT09ICdib3R0b20nIHx8IGRpciA9PT0gJ2JvdGgnKSAmJiB0aGlzLml0ZW1zKCkubGVuZ3RoID4gMDtcbiAgfVxuXG4gIC8qKiBDYXJnYSBpbmljaWFsIGRlIGRhdG9zICovXG4gIGFzeW5jIGxvYWRJbml0aWFsKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICghdGhpcy5wcm9wcy5kYXRhU291cmNlLmxvYWRGbikgcmV0dXJuO1xuXG4gICAgdGhpcy5zdGF0ZS5zZXQoJ2xvYWRpbmcnKTtcbiAgICB0aGlzLnN0YXRlQ2hhbmdlLmVtaXQoJ2xvYWRpbmcnKTtcbiAgICB0aGlzLmVycm9yLnNldChudWxsKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJhbXM6IExvYWRQYXJhbXMgPSB7XG4gICAgICAgIGRpcmVjdGlvbjogJ2JvdHRvbScsXG4gICAgICAgIHBhZ2U6IDAsXG4gICAgICAgIHBhZ2VTaXplOiB0aGlzLm1lcmdlZFByb3BzLnBhZ2VTaXplID8/IDIwLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5leGVjdXRlTG9hZChwYXJhbXMpO1xuXG4gICAgICB0aGlzLml0ZW1zLnNldChyZXN1bHQuaXRlbXMgYXMgVFtdKTtcbiAgICAgIHRoaXMuaGFzTW9yZUJvdHRvbS5zZXQocmVzdWx0Lmhhc01vcmUpO1xuICAgICAgdGhpcy5jdXJyZW50UGFnZSA9IDE7XG4gICAgICB0aGlzLmN1cnJlbnRDdXJzb3IgPSByZXN1bHQuY3Vyc29yO1xuICAgICAgdGhpcy5pc0luaXRpYWxMb2FkLnNldChmYWxzZSk7XG5cbiAgICAgIHRoaXMuc3RhdGUuc2V0KCdpZGxlJyk7XG4gICAgICB0aGlzLnN0YXRlQ2hhbmdlLmVtaXQoJ2lkbGUnKTtcbiAgICAgIHRoaXMuaXRlbXNDaGFuZ2UuZW1pdCh0aGlzLml0ZW1zKCkpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5oYW5kbGVFcnJvcihlcnIgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDYXJnYXIgbWFzIGl0ZW1zIGVuIGxhIHBhcnRlIGluZmVyaW9yICovXG4gIGFzeW5jIGxvYWRCb3R0b20oKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmhhc01vcmVCb3R0b20oKSB8fCB0aGlzLnN0YXRlKCkgPT09ICdsb2FkaW5nJykgcmV0dXJuO1xuICAgIGlmICghdGhpcy5wcm9wcy5kYXRhU291cmNlLmxvYWRGbikgcmV0dXJuO1xuXG4gICAgdGhpcy5zdGF0ZS5zZXQoJ2xvYWRpbmcnKTtcbiAgICB0aGlzLnN0YXRlQ2hhbmdlLmVtaXQoJ2xvYWRpbmcnKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJhbXM6IExvYWRQYXJhbXMgPSB7XG4gICAgICAgIGRpcmVjdGlvbjogJ2JvdHRvbScsXG4gICAgICAgIHBhZ2U6IHRoaXMuY3VycmVudFBhZ2UsXG4gICAgICAgIHBhZ2VTaXplOiB0aGlzLm1lcmdlZFByb3BzLnBhZ2VTaXplID8/IDIwLFxuICAgICAgICBjdXJzb3I6IHRoaXMuY3VycmVudEN1cnNvcixcbiAgICAgICAgbGFzdEl0ZW06IHRoaXMuaXRlbXMoKVt0aGlzLml0ZW1zKCkubGVuZ3RoIC0gMV0sXG4gICAgICB9O1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmV4ZWN1dGVMb2FkKHBhcmFtcyk7XG5cbiAgICAgIHRoaXMuaXRlbXMudXBkYXRlKChjdXJyZW50KSA9PiBbLi4uY3VycmVudCwgLi4uKHJlc3VsdC5pdGVtcyBhcyBUW10pXSk7XG4gICAgICB0aGlzLmhhc01vcmVCb3R0b20uc2V0KHJlc3VsdC5oYXNNb3JlKTtcbiAgICAgIHRoaXMuY3VycmVudFBhZ2UrKztcbiAgICAgIHRoaXMuY3VycmVudEN1cnNvciA9IHJlc3VsdC5jdXJzb3I7XG5cbiAgICAgIHRoaXMuc3RhdGUuc2V0KHJlc3VsdC5oYXNNb3JlID8gJ2lkbGUnIDogJ2NvbXBsZXRlJyk7XG4gICAgICB0aGlzLnN0YXRlQ2hhbmdlLmVtaXQocmVzdWx0Lmhhc01vcmUgPyAnaWRsZScgOiAnY29tcGxldGUnKTtcbiAgICAgIHRoaXMuaXRlbXNDaGFuZ2UuZW1pdCh0aGlzLml0ZW1zKCkpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5oYW5kbGVFcnJvcihlcnIgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDYXJnYXIgbWFzIGl0ZW1zIGVuIGxhIHBhcnRlIHN1cGVyaW9yICovXG4gIGFzeW5jIGxvYWRUb3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKCF0aGlzLmhhc01vcmVUb3AoKSB8fCB0aGlzLnN0YXRlKCkgPT09ICdsb2FkaW5nJykgcmV0dXJuO1xuICAgIGlmICghdGhpcy5wcm9wcy5kYXRhU291cmNlLmxvYWRGbikgcmV0dXJuO1xuXG4gICAgdGhpcy5zdGF0ZS5zZXQoJ2xvYWRpbmcnKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJhbXM6IExvYWRQYXJhbXMgPSB7XG4gICAgICAgIGRpcmVjdGlvbjogJ3RvcCcsXG4gICAgICAgIHBhZ2U6IDAsXG4gICAgICAgIHBhZ2VTaXplOiB0aGlzLm1lcmdlZFByb3BzLnBhZ2VTaXplID8/IDIwLFxuICAgICAgICBmaXJzdEl0ZW06IHRoaXMuaXRlbXMoKVswXSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuZXhlY3V0ZUxvYWQocGFyYW1zKTtcblxuICAgICAgdGhpcy5pdGVtcy51cGRhdGUoKGN1cnJlbnQpID0+IFsuLi4ocmVzdWx0Lml0ZW1zIGFzIFRbXSksIC4uLmN1cnJlbnRdKTtcbiAgICAgIHRoaXMuaGFzTW9yZVRvcC5zZXQocmVzdWx0Lmhhc01vcmUpO1xuXG4gICAgICB0aGlzLnN0YXRlLnNldCgnaWRsZScpO1xuICAgICAgdGhpcy5pdGVtc0NoYW5nZS5lbWl0KHRoaXMuaXRlbXMoKSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmhhbmRsZUVycm9yKGVyciBhcyBFcnJvcik7XG4gICAgfVxuICB9XG5cbiAgLyoqIFJlZnJlc2ggLSByZWNhcmdhciBkZXNkZSBjZXJvICovXG4gIGFzeW5jIHJlZnJlc2hMaXN0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuY3VycmVudFBhZ2UgPSAwO1xuICAgIHRoaXMuY3VycmVudEN1cnNvciA9IG51bGw7XG4gICAgdGhpcy5oYXNNb3JlQm90dG9tLnNldCh0cnVlKTtcbiAgICB0aGlzLml0ZW1zLnNldChbXSk7XG4gICAgYXdhaXQgdGhpcy5sb2FkSW5pdGlhbCgpO1xuICB9XG5cbiAgLyoqIFJlaW50ZW50YXIgZGVzcHVlcyBkZSBlcnJvciAqL1xuICBhc3luYyByZXRyeSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmVycm9yLnNldChudWxsKTtcbiAgICBpZiAodGhpcy5pdGVtcygpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYXdhaXQgdGhpcy5sb2FkSW5pdGlhbCgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCB0aGlzLmxvYWRCb3R0b20oKTtcbiAgICB9XG4gIH1cblxuICAvKiogUmVzZXQgY29tcGxldG8gKi9cbiAgYXN5bmMgcmVzZXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5pdGVtcy5zZXQoW10pO1xuICAgIHRoaXMuY3VycmVudFBhZ2UgPSAwO1xuICAgIHRoaXMuY3VycmVudEN1cnNvciA9IG51bGw7XG4gICAgdGhpcy5oYXNNb3JlQm90dG9tLnNldCh0cnVlKTtcbiAgICB0aGlzLmhhc01vcmVUb3Auc2V0KGZhbHNlKTtcbiAgICB0aGlzLmVycm9yLnNldChudWxsKTtcbiAgICB0aGlzLmlzSW5pdGlhbExvYWQuc2V0KHRydWUpO1xuICAgIHRoaXMuc3RhdGUuc2V0KCdpZGxlJyk7XG5cbiAgICBpZiAodGhpcy5tZXJnZWRQcm9wcy5hdXRvTG9hZCkge1xuICAgICAgYXdhaXQgdGhpcy5sb2FkSW5pdGlhbCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBBZ3JlZ2FyIGl0ZW1zIGFsIGluaWNpbyAqL1xuICBwcmVwZW5kSXRlbXMobmV3SXRlbXM6IFRbXSk6IHZvaWQge1xuICAgIHRoaXMuaXRlbXMudXBkYXRlKChjdXJyZW50KSA9PiBbLi4ubmV3SXRlbXMsIC4uLmN1cnJlbnRdKTtcbiAgICB0aGlzLml0ZW1zQ2hhbmdlLmVtaXQodGhpcy5pdGVtcygpKTtcbiAgfVxuXG4gIC8qKiBBZ3JlZ2FyIGl0ZW1zIGFsIGZpbmFsICovXG4gIGFwcGVuZEl0ZW1zKG5ld0l0ZW1zOiBUW10pOiB2b2lkIHtcbiAgICB0aGlzLml0ZW1zLnVwZGF0ZSgoY3VycmVudCkgPT4gWy4uLmN1cnJlbnQsIC4uLm5ld0l0ZW1zXSk7XG4gICAgdGhpcy5pdGVtc0NoYW5nZS5lbWl0KHRoaXMuaXRlbXMoKSk7XG4gIH1cblxuICAvKiogQWN0dWFsaXphciB1biBpdGVtIHBvciBpbmRpY2UgKi9cbiAgdXBkYXRlSXRlbShpbmRleDogbnVtYmVyLCBpdGVtOiBUKTogdm9pZCB7XG4gICAgdGhpcy5pdGVtcy51cGRhdGUoKGN1cnJlbnQpID0+IHtcbiAgICAgIGNvbnN0IHVwZGF0ZWQgPSBbLi4uY3VycmVudF07XG4gICAgICB1cGRhdGVkW2luZGV4XSA9IGl0ZW07XG4gICAgICByZXR1cm4gdXBkYXRlZDtcbiAgICB9KTtcbiAgICB0aGlzLml0ZW1zQ2hhbmdlLmVtaXQodGhpcy5pdGVtcygpKTtcbiAgfVxuXG4gIC8qKiBSZW1vdmVyIHVuIGl0ZW0gcG9yIGluZGljZSAqL1xuICByZW1vdmVJdGVtKGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLml0ZW1zLnVwZGF0ZSgoY3VycmVudCkgPT4gY3VycmVudC5maWx0ZXIoKF8sIGkpID0+IGkgIT09IGluZGV4KSk7XG4gICAgdGhpcy5pdGVtc0NoYW5nZS5lbWl0KHRoaXMuaXRlbXMoKSk7XG4gIH1cblxuICAvKiogSGFuZGxlciBwYXJhIGV2ZW50byBkZSBpbmZpbml0ZSBzY3JvbGwgKi9cbiAgYXN5bmMgb25JbmZpbml0ZVNjcm9sbChldmVudDogQ3VzdG9tRXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmxvYWRCb3R0b20oKTtcbiAgICAoZXZlbnQudGFyZ2V0IGFzIEhUTUxJb25JbmZpbml0ZVNjcm9sbEVsZW1lbnQpLmNvbXBsZXRlKCk7XG4gIH1cblxuICAvKiogSGFuZGxlciBwYXJhIGV2ZW50byBkZSByZWZyZXNoICovXG4gIGFzeW5jIG9uUmVmcmVzaFRyaWdnZXJlZChldmVudDogUmVmcmVzaEV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5yZWZyZXNoLmVtaXQoZXZlbnQpO1xuICAgIGF3YWl0IHRoaXMucmVmcmVzaExpc3QoKTtcbiAgICBldmVudC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBleGVjdXRlTG9hZChwYXJhbXM6IExvYWRQYXJhbXMpOiBQcm9taXNlPExvYWRSZXN1bHQ8dW5rbm93bj4+IHtcbiAgICBjb25zdCBsb2FkRm4gPSB0aGlzLnByb3BzLmRhdGFTb3VyY2UubG9hZEZuITtcbiAgICBjb25zdCByZXN1bHQgPSBsb2FkRm4ocGFyYW1zKTtcblxuICAgIGlmIChpc09ic2VydmFibGUocmVzdWx0KSkge1xuICAgICAgcmV0dXJuIGF3YWl0IGZpcnN0VmFsdWVGcm9tKHJlc3VsdCk7XG4gICAgfVxuICAgIHJldHVybiBhd2FpdCByZXN1bHQ7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUVycm9yKGVycjogRXJyb3IpOiB2b2lkIHtcbiAgICB0aGlzLmVycm9yLnNldChlcnIpO1xuICAgIHRoaXMuc3RhdGUuc2V0KCdlcnJvcicpO1xuICAgIHRoaXMuc3RhdGVDaGFuZ2UuZW1pdCgnZXJyb3InKTtcbiAgICB0aGlzLmVycm9yT2NjdXJyZWQuZW1pdChlcnIpO1xuICAgIGNvbnNvbGUuZXJyb3IoJ1tJbmZpbml0ZUxpc3RdIEVycm9yIGxvYWRpbmcgaXRlbXM6JywgZXJyKTtcbiAgfVxufVxuIl19