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.
- package/esm2022/lib/components/molecules/refresher/refresher.component.mjs +254 -0
- package/esm2022/lib/components/molecules/refresher/types.mjs +15 -0
- package/esm2022/lib/components/organisms/infinite-list/infinite-list.component.mjs +618 -0
- package/esm2022/lib/components/organisms/infinite-list/types.mjs +15 -0
- package/esm2022/lib/components/templates/page-template/page-template.component.mjs +5 -5
- package/esm2022/lib/services/pagination/index.mjs +5 -0
- package/esm2022/lib/services/pagination/pagination.service.mjs +218 -0
- package/esm2022/lib/services/pagination/types.mjs +14 -0
- package/esm2022/lib/services/skeleton/config.mjs +79 -0
- package/esm2022/lib/services/skeleton/directives/loading.directive.mjs +215 -0
- package/esm2022/lib/services/skeleton/index.mjs +16 -0
- package/esm2022/lib/services/skeleton/skeleton.service.mjs +198 -0
- package/esm2022/lib/services/skeleton/templates/detail-skeleton.component.mjs +223 -0
- package/esm2022/lib/services/skeleton/templates/form-skeleton.component.mjs +127 -0
- package/esm2022/lib/services/skeleton/templates/grid-skeleton.component.mjs +154 -0
- package/esm2022/lib/services/skeleton/templates/list-skeleton.component.mjs +110 -0
- package/esm2022/lib/services/skeleton/templates/profile-skeleton.component.mjs +207 -0
- package/esm2022/lib/services/skeleton/templates/table-skeleton.component.mjs +116 -0
- package/esm2022/lib/services/skeleton/types.mjs +11 -0
- package/esm2022/public-api.mjs +12 -1
- package/fesm2022/valtech-components.mjs +3887 -1370
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/molecules/refresher/refresher.component.d.ts +79 -0
- package/lib/components/molecules/refresher/types.d.ts +86 -0
- package/lib/components/organisms/infinite-list/infinite-list.component.d.ts +111 -0
- package/lib/components/organisms/infinite-list/types.d.ts +197 -0
- package/lib/services/pagination/index.d.ts +2 -0
- package/lib/services/pagination/pagination.service.d.ts +43 -0
- package/lib/services/pagination/types.d.ts +113 -0
- package/lib/services/skeleton/config.d.ts +30 -0
- package/lib/services/skeleton/directives/loading.directive.d.ts +71 -0
- package/lib/services/skeleton/index.d.ts +10 -0
- package/lib/services/skeleton/skeleton.service.d.ts +127 -0
- package/lib/services/skeleton/templates/detail-skeleton.component.d.ts +18 -0
- package/lib/services/skeleton/templates/form-skeleton.component.d.ts +22 -0
- package/lib/services/skeleton/templates/grid-skeleton.component.d.ts +18 -0
- package/lib/services/skeleton/templates/list-skeleton.component.d.ts +17 -0
- package/lib/services/skeleton/templates/profile-skeleton.component.d.ts +20 -0
- package/lib/services/skeleton/templates/table-skeleton.component.d.ts +17 -0
- package/lib/services/skeleton/types.d.ts +111 -0
- package/package.json +1 -1
- 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
|