valtech-components 2.0.991 → 2.0.993

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,736 @@
1
+ import { Component, computed, effect, inject, Input, signal } from '@angular/core';
2
+ import { ActivatedRoute } from '@angular/router';
3
+ import { IonIcon } from '@ionic/angular/standalone';
4
+ import { addIcons } from 'ionicons';
5
+ import { alarmOutline, chatboxEllipsesOutline, chatbubbleOutline, checkmarkCircleOutline, checkmarkDoneOutline, cloudOfflineOutline, cogOutline, documentTextOutline, notificationsOffOutline, notificationsOutline, openOutline, personOutline, } from 'ionicons/icons';
6
+ import { ButtonComponent } from '../../atoms/button/button.component';
7
+ import { DisplayComponent } from '../../atoms/display/display.component';
8
+ import { TextComponent } from '../../atoms/text/text.component';
9
+ import { TitleComponent } from '../../atoms/title/title.component';
10
+ import { EmptyStateComponent } from '../../molecules/empty-state/empty-state.component';
11
+ import { createErrorStateProps } from '../../molecules/empty-state/factory';
12
+ import { SkeletonLayoutComponent } from '../skeleton-layout/skeleton-layout.component';
13
+ import { ComponentStates } from '../../types';
14
+ import { AuthService } from '../../../services/auth/auth.service';
15
+ import { NotificationActionService } from '../../../services/auth/notification-action.service';
16
+ import { I18nService } from '../../../services/i18n';
17
+ import { interpretError } from '../../../services/errors/interpret-error';
18
+ import { NavigationService } from '../../../services/navigation/navigation.service';
19
+ import { NotificationsService } from '../../../services/firebase/notifications.service';
20
+ import { PageRefreshService } from '../../../services/page-refresh/page-refresh.service';
21
+ import { createRefreshableStream } from '../../../services/refreshable-stream/refreshable-stream';
22
+ import { ToastService } from '../../../services/toast.service';
23
+ import { ValtechErrorService } from '../../../services/errors/valtech-error.service';
24
+ import { NOTIFICATIONS_VIEW_I18N } from './notifications-view.i18n';
25
+ import * as i0 from "@angular/core";
26
+ addIcons({
27
+ alarmOutline,
28
+ chatboxEllipsesOutline,
29
+ chatbubbleOutline,
30
+ checkmarkCircleOutline,
31
+ checkmarkDoneOutline,
32
+ cloudOfflineOutline,
33
+ cogOutline,
34
+ documentTextOutline,
35
+ notificationsOffOutline,
36
+ notificationsOutline,
37
+ openOutline,
38
+ personOutline,
39
+ });
40
+ const DEFAULT_NAMESPACE = 'Notifications';
41
+ const DEFAULT_SETTINGS_PATH = '/app/settings/notifications';
42
+ const DEFAULT_PAGE_SIZE = 10;
43
+ const DEFAULT_MAX_LOAD = 50;
44
+ /**
45
+ * `val-notifications-view` — inbox de notificaciones full-feature autocontenido
46
+ * (organism). Promovido desde `showcase` bajo el proceso de ADR-021.
47
+ *
48
+ * Separado de `/app/settings/notifications` (que controla permiso FCM + master
49
+ * toggle). Aquí el user lee/abre/marca-leídas sus mensajes.
50
+ *
51
+ * - **Stream real-time** vía `NotificationsService.getAll(maxLoad)` envuelto en
52
+ * `createRefreshableStream` (gateado por `firebaseAuthReady`, retry corto,
53
+ * `firstEmitTimeoutMs: 15000`). Estados: loading (skeleton), error
54
+ * (`val-empty-state` + reintentar), empty (`val-empty-state` + CTA), data
55
+ * (lista agrupada Hoy / Este mes / Anteriores).
56
+ * - **Abrir** una notif → `NotificationActionService.open()` (markRead +
57
+ * switch-org + navegar/handoff cross-app). Hook `onNotificationOpen` opcional.
58
+ * - **Marcar todas como leídas** (gateado por `enableMarkAll`).
59
+ * - **CTA push-off** cuando el permiso del navegador no está concedido (gateado
60
+ * por `showPushOffCta`); navega a `settingsNotificationsPath`.
61
+ * - **Paginación soft** — slice local (`pageSize`, +`pageSize` por click) sobre el
62
+ * cache del stream; el tope de fetch es `maxLoad`.
63
+ * - **i18n auto-registrado** es/en bajo `i18nNamespace` (default `Notifications`).
64
+ *
65
+ * NO renderiza ion-content — vive dentro de val-page-wrapper. `Router` y
66
+ * `ActivatedRoute` se inyectan `{ optional: true }` → funciona sin router
67
+ * (embebida / Storybook). El forward-compat icon resolver lee `notif.payload.icon`
68
+ * si existe (`{ type, value, color? }`), cae a un mapa por `notif.type`, luego a
69
+ * `notifications-outline`.
70
+ */
71
+ export class NotificationsViewComponent {
72
+ /** Namespace i18n resuelto (capturado para llamadas no-reactivas). */
73
+ get ns() {
74
+ return this.resolvedConfig().i18nNamespace;
75
+ }
76
+ /** Paso de paginación soft (revela +N por "cargar más"). */
77
+ get pageStep() {
78
+ return this.resolvedConfig().pageSize;
79
+ }
80
+ constructor() {
81
+ this.nav = inject(NavigationService);
82
+ this.i18n = inject(I18nService);
83
+ this.notifs = inject(NotificationsService);
84
+ this.action = inject(NotificationActionService);
85
+ this.toast = inject(ToastService);
86
+ this.errors = inject(ValtechErrorService);
87
+ this.auth = inject(AuthService);
88
+ this.pageRefresh = inject(PageRefreshService);
89
+ // `ActivatedRoute` opcional → la vista funciona embebida / en Storybook sin
90
+ // router (solo lo usa para leer el route data de config como fallback). La
91
+ // navegación va por `NavigationService` (wrapper opcional sobre `Router`).
92
+ this.route = inject(ActivatedRoute, { optional: true });
93
+ this.resolvedConfig = computed(() => {
94
+ const fromRoute = (this.route?.snapshot.data['notificationsConfig'] ?? {});
95
+ const merged = { ...fromRoute, ...(this.config ?? {}) };
96
+ return {
97
+ showPushOffCta: merged.showPushOffCta ?? true,
98
+ enableMarkAll: merged.enableMarkAll ?? true,
99
+ settingsNotificationsPath: merged.settingsNotificationsPath ?? DEFAULT_SETTINGS_PATH,
100
+ i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE,
101
+ pageSize: merged.pageSize ?? DEFAULT_PAGE_SIZE,
102
+ maxLoad: merged.maxLoad ?? DEFAULT_MAX_LOAD,
103
+ onNotificationOpen: merged.onNotificationOpen,
104
+ };
105
+ });
106
+ this._expanded = signal(new Set());
107
+ this._pageSize = signal(this.resolvedConfig().pageSize);
108
+ this._bulkBusy = signal(false);
109
+ this._loadingMore = signal(false);
110
+ /**
111
+ * Push activado = permiso del navegador en `granted`. Si NO está activado,
112
+ * el user puede leer el inbox (Firestore) pero NO recibirá push en su
113
+ * dispositivo → mostramos una card que lo invita a ir a configuración.
114
+ * Se evalúa en cada montaje de la vista.
115
+ */
116
+ this.pushEnabled = signal(this.auth.getNotificationPermissionState() === 'granted');
117
+ /**
118
+ * Stream firestore real-time vía el helper estándar `createRefreshableStream`
119
+ * (modo real-time: factory devuelve un listener vivo `notifs.getAll(maxLoad)`).
120
+ *
121
+ * El helper gatea la primera suscripción por `firebaseAuthReady`, aplica un
122
+ * `retry` corto con backoff y, tras agotar reintentos, emite el fallback (`[]`)
123
+ * y marca `error` — estado de error en UI, no skeleton infinito. `reload()`
124
+ * re-suscribe el stream completo (lo usa el pull-to-refresh).
125
+ */
126
+ this._stream = createRefreshableStream(() => this.notifs.getAll(this.resolvedConfig().maxLoad), {
127
+ fallback: [],
128
+ // `notifs.getAll()` YA gatea internamente por `firebaseAuthReady`. Si el
129
+ // stream también gateara, serían DOS esperas de auth apiladas.
130
+ gateOnFirebaseAuth: false,
131
+ // Cold start de PWA en iOS puede pasar de 8s en redes lentas; con 15s
132
+ // evitamos el falso estado de error.
133
+ firstEmitTimeoutMs: 15000,
134
+ });
135
+ /** True si el stream falló tras agotar reintentos → muestra estado de error. */
136
+ this.streamError = this._stream.error;
137
+ this.loading = computed(() => this._stream.data() === null);
138
+ /**
139
+ * Notifs reales mostradas. Filtramos docs sin título Y sin body — son ruido
140
+ * (típicamente sentinel/system writes pre-schema con title/body opcionales).
141
+ */
142
+ this.allNotifs = computed(() => (this._stream.data() ?? []).filter(n => !!(n.title && n.title.trim()) || !!(n.body && n.body.trim())));
143
+ this.hasMore = computed(() => this.allNotifs().length > this._pageSize());
144
+ this.showMarkAll = computed(() => this.resolvedConfig().enableMarkAll && !this.loading() && this.allNotifs().some(n => !n.isRead));
145
+ /** Sub-conjunto paginado, agrupado por período. */
146
+ this.groups = computed(() => {
147
+ const items = this.allNotifs().slice(0, this._pageSize());
148
+ const now = new Date();
149
+ const buckets = {
150
+ today: [],
151
+ thisMonth: [],
152
+ earlier: [],
153
+ };
154
+ for (const n of items) {
155
+ buckets[this.bucketOf(n, now)].push(n);
156
+ }
157
+ const out = [];
158
+ if (buckets.today.length) {
159
+ out.push({ key: 'today', label: this.tt('groupToday'), items: buckets.today });
160
+ }
161
+ if (buckets.thisMonth.length) {
162
+ out.push({
163
+ key: 'thisMonth',
164
+ label: this.tt('groupThisMonth'),
165
+ items: buckets.thisMonth,
166
+ });
167
+ }
168
+ if (buckets.earlier.length) {
169
+ out.push({ key: 'earlier', label: this.tt('groupEarlier'), items: buckets.earlier });
170
+ }
171
+ return out;
172
+ });
173
+ this.pageTitle = computed(() => this.tt('pageTitle'));
174
+ this.pageDescription = computed(() => this.tt('pageDescription'));
175
+ // CTA "activa las notificaciones push" — visible cuando pushEnabled() es false.
176
+ this.ctaTitle = computed(() => this.tt('pushOffTitle'));
177
+ this.ctaHint = computed(() => this.tt('pushOffHint'));
178
+ this.ctaButtonProps = computed(() => ({
179
+ text: this.tt('pushOffCta'),
180
+ color: 'dark',
181
+ fill: 'outline',
182
+ size: 'small',
183
+ shape: 'round',
184
+ type: 'button',
185
+ }));
186
+ /**
187
+ * Estado de error de carga: convierte el error del stream en
188
+ * `EmptyStateMetadata` via el helper canónico `createErrorStateProps`.
189
+ * El helper decide variante (`offline` vs `error`) por `isNetwork`.
190
+ * Null cuando el stream no ha fallado.
191
+ */
192
+ this.errorState = computed(() => {
193
+ this.i18n.lang();
194
+ const err = this.streamError();
195
+ if (!err)
196
+ return null;
197
+ return createErrorStateProps(err, {
198
+ title: {
199
+ offline: this.tt('offlineTitle'),
200
+ error: this.tt('loadErrorTitle'),
201
+ },
202
+ description: {
203
+ offline: this.tt('offlineHint'),
204
+ error: interpretError(err).message || this.tt('loadErrorHint'),
205
+ },
206
+ retryLabel: this.tt('retryCta'),
207
+ onRetry: () => this._stream.reload(),
208
+ retrying: this.loading(),
209
+ });
210
+ });
211
+ /**
212
+ * Estado vacío (lista real = 0 notificaciones, sin error de carga).
213
+ * Se construye manualmente con `variant: 'empty'` — sin helper de error.
214
+ */
215
+ this.emptyStateProps = computed(() => {
216
+ this.i18n.lang();
217
+ return {
218
+ variant: 'empty',
219
+ icon: 'notifications-off-outline',
220
+ title: this.tt('empty'),
221
+ description: this.tt('emptyHint'),
222
+ action: {
223
+ label: this.tt('emptyCta'),
224
+ handler: () => this.onGoToSettings(),
225
+ },
226
+ };
227
+ });
228
+ this.seeMore = computed(() => this.tt('seeMore'));
229
+ this.seeLess = computed(() => this.tt('seeLess'));
230
+ this.markAllButtonProps = computed(() => ({
231
+ text: this.tt('markAll'),
232
+ color: 'dark',
233
+ fill: 'outline',
234
+ size: 'small',
235
+ shape: 'round',
236
+ type: 'button',
237
+ icon: { name: 'checkmark-done-outline', slot: 'start' },
238
+ state: this._bulkBusy() ? ComponentStates.WORKING : ComponentStates.ENABLED,
239
+ }));
240
+ this.loadMoreButtonProps = computed(() => ({
241
+ text: this.tt('loadMore'),
242
+ color: 'dark',
243
+ fill: 'clear',
244
+ size: 'default',
245
+ shape: 'round',
246
+ type: 'button',
247
+ state: this._loadingMore() ? ComponentStates.WORKING : ComponentStates.ENABLED,
248
+ }));
249
+ const ns = this.ns;
250
+ if (!this.i18n.hasNamespace(ns)) {
251
+ this.i18n.registerContent(ns, NOTIFICATIONS_VIEW_I18N);
252
+ }
253
+ this.nav.setBackHeader('pageTitle', ns, { withMenu: true });
254
+ // Re-aplicar header en cambio de idioma.
255
+ effect(() => {
256
+ this.i18n.lang();
257
+ this.nav.setBackHeader('pageTitle', this.ns, { withMenu: true });
258
+ }, { allowSignalWrites: true });
259
+ }
260
+ /**
261
+ * Registra el pull-to-refresh estándar. Usamos `ngOnInit`/`ngOnDestroy`
262
+ * (NO `ionViewWillEnter`) porque `val-page-wrapper` usa `<router-outlet>`
263
+ * plano — los hooks `ionView*` solo disparan dentro de `<ion-router-outlet>`.
264
+ */
265
+ ngOnInit() {
266
+ this.pageRefresh.register(() => this.reload());
267
+ }
268
+ /** Quita el handler al destruir la vista — el refresher desaparece. */
269
+ ngOnDestroy() {
270
+ this.pageRefresh.unregister();
271
+ }
272
+ /**
273
+ * Refresh manual: re-suscribe el stream Firestore (listener nuevo) vía el
274
+ * helper. Resuelve tras un margen breve — el stream es real-time y re-emite
275
+ * en milisegundos; el delay sólo mantiene el spinner visible lo justo.
276
+ */
277
+ async reload() {
278
+ this._stream.reload();
279
+ await new Promise(r => setTimeout(r, 700));
280
+ }
281
+ // ---------------------------------------------------------------------------
282
+ // Per-item helpers (puros — usables desde template).
283
+ // ---------------------------------------------------------------------------
284
+ openButtonProps() {
285
+ return {
286
+ text: this.tt('open'),
287
+ color: 'dark',
288
+ fill: 'clear',
289
+ size: 'small',
290
+ shape: 'round',
291
+ type: 'button',
292
+ icon: { name: 'open-outline', slot: 'end' },
293
+ };
294
+ }
295
+ isExpanded(id) {
296
+ return this._expanded().has(id);
297
+ }
298
+ toggleExpand(id) {
299
+ const next = new Set(this._expanded());
300
+ if (next.has(id))
301
+ next.delete(id);
302
+ else
303
+ next.add(id);
304
+ this._expanded.set(next);
305
+ }
306
+ isLong(body) {
307
+ if (!body)
308
+ return false;
309
+ return body.length > 110 || body.includes('\n');
310
+ }
311
+ /**
312
+ * Icon resolver con orden de fallback:
313
+ * 1. notif.payload.icon (forward-compat, sin breaking change en schema)
314
+ * 2. mapa por notif.type
315
+ * 3. default notifications-outline
316
+ */
317
+ resolveIcon(n) {
318
+ const hint = n.payload?.['icon'];
319
+ if (hint?.value) {
320
+ if (hint.type === 'image' || hint.type === 'avatar') {
321
+ return { kind: hint.type, src: hint.value };
322
+ }
323
+ // Ignoramos hint.color — todos los iconos van en dark por convención UX.
324
+ return { kind: 'ionicon', name: hint.value, color: 'dark' };
325
+ }
326
+ const t = n.type;
327
+ const name = (() => {
328
+ switch (t) {
329
+ case 'approval':
330
+ return 'checkmark-circle-outline';
331
+ case 'chat':
332
+ case 'chatbot':
333
+ return 'chatbubble-outline';
334
+ case 'comment':
335
+ return 'chatbox-ellipses-outline';
336
+ case 'reminder':
337
+ return 'alarm-outline';
338
+ case 'system':
339
+ return 'cog-outline';
340
+ case 'user':
341
+ case 'mention':
342
+ return 'person-outline';
343
+ case 'document':
344
+ return 'document-text-outline';
345
+ default:
346
+ return 'notifications-outline';
347
+ }
348
+ })();
349
+ return { kind: 'ionicon', name, color: 'dark' };
350
+ }
351
+ ioniconName(n) {
352
+ const r = this.resolveIcon(n);
353
+ return r.kind === 'ionicon' ? r.name : '';
354
+ }
355
+ ioniconColor(n) {
356
+ const r = this.resolveIcon(n);
357
+ return r.kind === 'ionicon' ? r.color : undefined;
358
+ }
359
+ imageSrc(n) {
360
+ const r = this.resolveIcon(n);
361
+ return r.kind === 'image' || r.kind === 'avatar' ? r.src : '';
362
+ }
363
+ ionColor(token) {
364
+ if (!token)
365
+ return 'var(--ion-color-primary)';
366
+ return `var(--ion-color-${token})`;
367
+ }
368
+ relativeTime(n) {
369
+ const d = n.createdAt instanceof Date ? n.createdAt : null;
370
+ if (!d)
371
+ return '';
372
+ const diffMs = Date.now() - d.getTime();
373
+ const min = Math.floor(diffMs / 60000);
374
+ if (min < 1)
375
+ return this.tt('timeNow');
376
+ if (min < 60)
377
+ return this.tt('timeMinutes').replace('{n}', String(min));
378
+ const h = Math.floor(min / 60);
379
+ if (h < 24)
380
+ return this.tt('timeHours').replace('{n}', String(h));
381
+ const days = Math.floor(h / 24);
382
+ return this.tt('timeDays').replace('{n}', String(days));
383
+ }
384
+ /** Devuelve label "Desde {appName}" si la notif viene de otra app, sino null. */
385
+ showCrossAppBadge(n) {
386
+ const currentApp = 'showcase';
387
+ if (!n.appId || n.appId === currentApp)
388
+ return null;
389
+ return this.tt('crossApp').replace('{app}', n.appId);
390
+ }
391
+ // ---------------------------------------------------------------------------
392
+ // Actions
393
+ // ---------------------------------------------------------------------------
394
+ async onOpen(n) {
395
+ try {
396
+ const result = await this.action.open(n);
397
+ this.resolvedConfig().onNotificationOpen?.(n, result);
398
+ }
399
+ catch (err) {
400
+ this.errors.handle(err, {
401
+ context: 'notifications.open',
402
+ fallbackKey: 'openError',
403
+ i18nNamespace: this.ns,
404
+ });
405
+ }
406
+ }
407
+ async onMarkAll() {
408
+ if (this._bulkBusy())
409
+ return;
410
+ this._bulkBusy.set(true);
411
+ try {
412
+ await this.notifs.markAllAsRead();
413
+ this.toast.show({
414
+ message: this.tt('markedAllSuccess'),
415
+ color: 'dark',
416
+ duration: 2500,
417
+ position: 'top',
418
+ });
419
+ }
420
+ catch (err) {
421
+ this.errors.handle(err, {
422
+ context: 'notifications.markAll',
423
+ fallbackKey: 'markedAllError',
424
+ i18nNamespace: this.ns,
425
+ });
426
+ }
427
+ finally {
428
+ this._bulkBusy.set(false);
429
+ }
430
+ }
431
+ onLoadMore() {
432
+ if (this._loadingMore())
433
+ return;
434
+ this._loadingMore.set(true);
435
+ // Slice viene del cache local — no hay fetch real, pero un breve spinner
436
+ // confirma al user que el click registró y suaviza la aparición de items.
437
+ setTimeout(() => {
438
+ this._pageSize.update(n => n + this.pageStep);
439
+ this._loadingMore.set(false);
440
+ }, 250);
441
+ }
442
+ onGoToSettings() {
443
+ this.nav.navigateByUrl(this.resolvedConfig().settingsNotificationsPath);
444
+ }
445
+ // ---------------------------------------------------------------------------
446
+ // Grouping helpers
447
+ // ---------------------------------------------------------------------------
448
+ bucketOf(n, now) {
449
+ const d = n.createdAt instanceof Date ? n.createdAt : null;
450
+ if (!d)
451
+ return 'earlier';
452
+ if (d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth() && d.getDate() === now.getDate()) {
453
+ return 'today';
454
+ }
455
+ if (d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth()) {
456
+ return 'thisMonth';
457
+ }
458
+ return 'earlier';
459
+ }
460
+ tt(key) {
461
+ return this.i18n.t(key, this.ns);
462
+ }
463
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationsViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
464
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: NotificationsViewComponent, isStandalone: true, selector: "val-notifications-view", inputs: { config: "config" }, ngImport: i0, template: `
465
+ <div class="page">
466
+ <header class="page-header">
467
+ <val-display [props]="{ size: 'small', color: 'dark', content: pageTitle() }" />
468
+ <val-title
469
+ [props]="{
470
+ size: 'large',
471
+ color: 'dark',
472
+ bold: false,
473
+ content: pageDescription(),
474
+ }"
475
+ />
476
+ @if (showMarkAll()) {
477
+ <div class="row-actions">
478
+ <val-button [props]="markAllButtonProps()" (click)="onMarkAll()" />
479
+ </div>
480
+ }
481
+ </header>
482
+
483
+ @if (resolvedConfig().showPushOffCta && !pushEnabled()) {
484
+ <section class="notif-cta">
485
+ <ion-icon class="notif-cta__icon" name="notifications-off-outline" aria-hidden="true" />
486
+ <div class="notif-cta__body">
487
+ <val-text
488
+ [props]="{
489
+ content: ctaTitle(),
490
+ size: 'medium',
491
+ color: 'dark',
492
+ bold: true,
493
+ }"
494
+ />
495
+ <val-text
496
+ [props]="{
497
+ content: ctaHint(),
498
+ size: 'small',
499
+ color: 'medium',
500
+ bold: false,
501
+ }"
502
+ />
503
+ <div class="row-actions">
504
+ <val-button [props]="ctaButtonProps()" (click)="onGoToSettings()" />
505
+ </div>
506
+ </div>
507
+ </section>
508
+ }
509
+
510
+ @if (loading()) {
511
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 6 }" />
512
+ } @else if (errorState()) {
513
+ <val-empty-state [props]="errorState()!" />
514
+ } @else if (allNotifs().length === 0) {
515
+ <val-empty-state [props]="emptyStateProps()" />
516
+ } @else {
517
+ @for (group of groups(); track group.key) {
518
+ <section class="group">
519
+ <val-title
520
+ [props]="{
521
+ size: 'medium',
522
+ color: 'dark',
523
+ bold: true,
524
+ content: group.label,
525
+ }"
526
+ />
527
+ <ul class="notif-list">
528
+ @for (n of group.items; track n.id) {
529
+ <li class="notif" [class.notif--unread]="!n.isRead">
530
+ <div class="notif__icon">
531
+ @switch (resolveIcon(n).kind) {
532
+ @case ('ionicon') {
533
+ <ion-icon
534
+ [name]="ioniconName(n)"
535
+ [style.color]="ionColor(ioniconColor(n))"
536
+ aria-hidden="true"
537
+ />
538
+ }
539
+ @case ('image') {
540
+ <img [src]="imageSrc(n)" alt="" loading="lazy" />
541
+ }
542
+ @case ('avatar') {
543
+ <img class="notif__avatar" [src]="imageSrc(n)" alt="" loading="lazy" />
544
+ }
545
+ }
546
+ </div>
547
+
548
+ <div class="notif__body">
549
+ <div class="notif__head">
550
+ <val-text
551
+ [props]="{
552
+ content: n.title || '—',
553
+ size: 'medium',
554
+ color: 'dark',
555
+ bold: true,
556
+ }"
557
+ />
558
+ <span class="notif__time">{{ relativeTime(n) }}</span>
559
+ </div>
560
+ @if (n.body) {
561
+ <p class="notif__text" [class.notif__text--clamped]="!isExpanded(n.id) && isLong(n.body)">
562
+ {{ n.body }}
563
+ </p>
564
+ @if (isLong(n.body)) {
565
+ <button class="notif__expand" type="button" (click)="toggleExpand(n.id)">
566
+ {{ isExpanded(n.id) ? seeLess() : seeMore() }}
567
+ </button>
568
+ }
569
+ }
570
+ @if (showCrossAppBadge(n); as appName) {
571
+ <span class="notif__app">{{ appName }}</span>
572
+ }
573
+ @if (n.actionRoute) {
574
+ <div class="row-actions row-actions--end">
575
+ <val-button [props]="openButtonProps()" (click)="onOpen(n)" />
576
+ </div>
577
+ }
578
+ </div>
579
+ </li>
580
+ }
581
+ </ul>
582
+ </section>
583
+ }
584
+
585
+ @if (hasMore()) {
586
+ <div class="row-actions row-actions--center">
587
+ <val-button [props]="loadMoreButtonProps()" (click)="onLoadMore()" />
588
+ </div>
589
+ }
590
+ }
591
+ </div>
592
+ `, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:16px}.row-actions{margin-top:12px}.row-actions--center{display:flex;justify-content:center;margin-top:20px}.row-actions--end{display:flex;justify-content:flex-end;margin-top:8px}.notif-cta{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;margin-bottom:16px;border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .08));border-radius:14px;background:var(--ion-color-light)}.notif-cta__icon{font-size:24px;color:var(--ion-color-dark, #1a1a1a);flex-shrink:0;margin-top:2px}.notif-cta__body{display:flex;flex-direction:column;gap:2px}.group{padding:12px 0}.group+.group{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.notif-list{list-style:none;padding:0;margin:12px 0 0;display:flex;flex-direction:column;gap:10px}.notif{display:grid;grid-template-columns:44px 1fr;gap:12px;padding:12px;border-radius:12px;background:transparent;transition:background .12s ease}.notif--unread{background:var(--ion-color-light, rgba(0, 0, 0, .04))}.notif__icon{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--ion-color-light, rgba(0, 0, 0, .06));overflow:hidden}.notif__icon ion-icon{font-size:22px}.notif__icon img{width:100%;height:100%;object-fit:cover}.notif__avatar{border-radius:50%}.notif__body{display:flex;flex-direction:column;gap:4px;min-width:0}.notif__head{display:flex;justify-content:space-between;align-items:baseline;gap:8px}.notif__time{font-size:12px;color:var(--ion-color-medium, #92949c);flex-shrink:0}.notif__text{margin:0;font-size:14px;line-height:1.4;color:var(--ion-color-dark, #1a1a1a);white-space:pre-wrap}.notif__text--clamped{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.notif__expand{background:none;border:0;padding:0;font-size:13px;color:var(--ion-color-dark, #1a1a1a);cursor:pointer;align-self:flex-start;text-decoration:underline}.notif__app{font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--ion-color-medium, #92949c);margin-top:2px}\n"], dependencies: [{ kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: DisplayComponent, selector: "val-display", inputs: ["props"] }, { kind: "component", type: TitleComponent, selector: "val-title", inputs: ["props"] }, { kind: "component", type: TextComponent, selector: "val-text", inputs: ["props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { kind: "component", type: SkeletonLayoutComponent, selector: "val-skeleton-layout", inputs: ["props"] }, { kind: "component", type: EmptyStateComponent, selector: "val-empty-state", inputs: ["props"] }] }); }
593
+ }
594
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationsViewComponent, decorators: [{
595
+ type: Component,
596
+ args: [{ selector: 'val-notifications-view', standalone: true, imports: [
597
+ IonIcon,
598
+ DisplayComponent,
599
+ TitleComponent,
600
+ TextComponent,
601
+ ButtonComponent,
602
+ SkeletonLayoutComponent,
603
+ EmptyStateComponent,
604
+ ], template: `
605
+ <div class="page">
606
+ <header class="page-header">
607
+ <val-display [props]="{ size: 'small', color: 'dark', content: pageTitle() }" />
608
+ <val-title
609
+ [props]="{
610
+ size: 'large',
611
+ color: 'dark',
612
+ bold: false,
613
+ content: pageDescription(),
614
+ }"
615
+ />
616
+ @if (showMarkAll()) {
617
+ <div class="row-actions">
618
+ <val-button [props]="markAllButtonProps()" (click)="onMarkAll()" />
619
+ </div>
620
+ }
621
+ </header>
622
+
623
+ @if (resolvedConfig().showPushOffCta && !pushEnabled()) {
624
+ <section class="notif-cta">
625
+ <ion-icon class="notif-cta__icon" name="notifications-off-outline" aria-hidden="true" />
626
+ <div class="notif-cta__body">
627
+ <val-text
628
+ [props]="{
629
+ content: ctaTitle(),
630
+ size: 'medium',
631
+ color: 'dark',
632
+ bold: true,
633
+ }"
634
+ />
635
+ <val-text
636
+ [props]="{
637
+ content: ctaHint(),
638
+ size: 'small',
639
+ color: 'medium',
640
+ bold: false,
641
+ }"
642
+ />
643
+ <div class="row-actions">
644
+ <val-button [props]="ctaButtonProps()" (click)="onGoToSettings()" />
645
+ </div>
646
+ </div>
647
+ </section>
648
+ }
649
+
650
+ @if (loading()) {
651
+ <val-skeleton-layout [props]="{ preset: 'list', rows: 6 }" />
652
+ } @else if (errorState()) {
653
+ <val-empty-state [props]="errorState()!" />
654
+ } @else if (allNotifs().length === 0) {
655
+ <val-empty-state [props]="emptyStateProps()" />
656
+ } @else {
657
+ @for (group of groups(); track group.key) {
658
+ <section class="group">
659
+ <val-title
660
+ [props]="{
661
+ size: 'medium',
662
+ color: 'dark',
663
+ bold: true,
664
+ content: group.label,
665
+ }"
666
+ />
667
+ <ul class="notif-list">
668
+ @for (n of group.items; track n.id) {
669
+ <li class="notif" [class.notif--unread]="!n.isRead">
670
+ <div class="notif__icon">
671
+ @switch (resolveIcon(n).kind) {
672
+ @case ('ionicon') {
673
+ <ion-icon
674
+ [name]="ioniconName(n)"
675
+ [style.color]="ionColor(ioniconColor(n))"
676
+ aria-hidden="true"
677
+ />
678
+ }
679
+ @case ('image') {
680
+ <img [src]="imageSrc(n)" alt="" loading="lazy" />
681
+ }
682
+ @case ('avatar') {
683
+ <img class="notif__avatar" [src]="imageSrc(n)" alt="" loading="lazy" />
684
+ }
685
+ }
686
+ </div>
687
+
688
+ <div class="notif__body">
689
+ <div class="notif__head">
690
+ <val-text
691
+ [props]="{
692
+ content: n.title || '—',
693
+ size: 'medium',
694
+ color: 'dark',
695
+ bold: true,
696
+ }"
697
+ />
698
+ <span class="notif__time">{{ relativeTime(n) }}</span>
699
+ </div>
700
+ @if (n.body) {
701
+ <p class="notif__text" [class.notif__text--clamped]="!isExpanded(n.id) && isLong(n.body)">
702
+ {{ n.body }}
703
+ </p>
704
+ @if (isLong(n.body)) {
705
+ <button class="notif__expand" type="button" (click)="toggleExpand(n.id)">
706
+ {{ isExpanded(n.id) ? seeLess() : seeMore() }}
707
+ </button>
708
+ }
709
+ }
710
+ @if (showCrossAppBadge(n); as appName) {
711
+ <span class="notif__app">{{ appName }}</span>
712
+ }
713
+ @if (n.actionRoute) {
714
+ <div class="row-actions row-actions--end">
715
+ <val-button [props]="openButtonProps()" (click)="onOpen(n)" />
716
+ </div>
717
+ }
718
+ </div>
719
+ </li>
720
+ }
721
+ </ul>
722
+ </section>
723
+ }
724
+
725
+ @if (hasMore()) {
726
+ <div class="row-actions row-actions--center">
727
+ <val-button [props]="loadMoreButtonProps()" (click)="onLoadMore()" />
728
+ </div>
729
+ }
730
+ }
731
+ </div>
732
+ `, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:16px}.row-actions{margin-top:12px}.row-actions--center{display:flex;justify-content:center;margin-top:20px}.row-actions--end{display:flex;justify-content:flex-end;margin-top:8px}.notif-cta{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;margin-bottom:16px;border:1px solid var(--ion-color-light-shade, rgba(0, 0, 0, .08));border-radius:14px;background:var(--ion-color-light)}.notif-cta__icon{font-size:24px;color:var(--ion-color-dark, #1a1a1a);flex-shrink:0;margin-top:2px}.notif-cta__body{display:flex;flex-direction:column;gap:2px}.group{padding:12px 0}.group+.group{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.notif-list{list-style:none;padding:0;margin:12px 0 0;display:flex;flex-direction:column;gap:10px}.notif{display:grid;grid-template-columns:44px 1fr;gap:12px;padding:12px;border-radius:12px;background:transparent;transition:background .12s ease}.notif--unread{background:var(--ion-color-light, rgba(0, 0, 0, .04))}.notif__icon{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--ion-color-light, rgba(0, 0, 0, .06));overflow:hidden}.notif__icon ion-icon{font-size:22px}.notif__icon img{width:100%;height:100%;object-fit:cover}.notif__avatar{border-radius:50%}.notif__body{display:flex;flex-direction:column;gap:4px;min-width:0}.notif__head{display:flex;justify-content:space-between;align-items:baseline;gap:8px}.notif__time{font-size:12px;color:var(--ion-color-medium, #92949c);flex-shrink:0}.notif__text{margin:0;font-size:14px;line-height:1.4;color:var(--ion-color-dark, #1a1a1a);white-space:pre-wrap}.notif__text--clamped{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.notif__expand{background:none;border:0;padding:0;font-size:13px;color:var(--ion-color-dark, #1a1a1a);cursor:pointer;align-self:flex-start;text-decoration:underline}.notif__app{font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--ion-color-medium, #92949c);margin-top:2px}\n"] }]
733
+ }], ctorParameters: () => [], propDecorators: { config: [{
734
+ type: Input
735
+ }] } });
736
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpY2F0aW9ucy12aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9vcmdhbmlzbXMvbm90aWZpY2F0aW9ucy12aWV3L25vdGlmaWNhdGlvbnMtdmlldy5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQXFCLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN0RyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDcEMsT0FBTyxFQUNMLFlBQVksRUFDWixzQkFBc0IsRUFDdEIsaUJBQWlCLEVBQ2pCLHNCQUFzQixFQUN0QixvQkFBb0IsRUFDcEIsbUJBQW1CLEVBQ25CLFVBQVUsRUFDVixtQkFBbUIsRUFDbkIsdUJBQXVCLEVBQ3ZCLG9CQUFvQixFQUNwQixXQUFXLEVBQ1gsYUFBYSxHQUNkLE1BQU0sZ0JBQWdCLENBQUM7QUFFeEIsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNoRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDbkUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbURBQW1ELENBQUM7QUFFeEYsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDNUUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0s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LEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ25DLENBQUM7K0dBcGJVLDBCQUEwQjttR0FBMUIsMEJBQTBCLGdIQXBSM0I7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBZ0lULHNuRUF4SUMsT0FBTywySkFDUCxnQkFBZ0IsMkVBQ2hCLGNBQWMseUVBQ2QsYUFBYSx3RUFDYixlQUFlLDBHQUNmLHVCQUF1QixtRkFDdkIsbUJBQW1COzs0RkFzUlYsMEJBQTBCO2tCQWhTdEMsU0FBUzsrQkFDRSx3QkFBd0IsY0FDdEIsSUFBSSxXQUNQO3dCQUNQLE9BQU87d0JBQ1AsZ0JBQWdCO3dCQUNoQixjQUFjO3dCQUNkLGFBQWE7d0JBQ2IsZUFBZTt3QkFDZix1QkFBdUI7d0JBQ3ZCLG1CQUFtQjtxQkFDcEIsWUFDUzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnSVQ7d0RBdUtRLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgY29tcHV0ZWQsIGVmZmVjdCwgaW5qZWN0LCBJbnB1dCwgT25EZXN0cm95LCBPbkluaXQsIHNpZ25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgSW9uSWNvbiB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyL3N0YW5kYWxvbmUnO1xuaW1wb3J0IHsgYWRkSWNvbnMgfSBmcm9tICdpb25pY29ucyc7XG5pbXBvcnQge1xuICBhbGFybU91dGxpbmUsXG4gIGNoYXRib3hFbGxpcHNlc091dGxpbmUsXG4gIGNoYXRidWJibGVPdXRsaW5lLFxuICBjaGVja21hcmtDaXJjbGVPdXRsaW5lLFxuICBjaGVja21hcmtEb25lT3V0bGluZSxcbiAgY2xvdWRPZmZsaW5lT3V0bGluZSxcbiAgY29nT3V0bGluZSxcbiAgZG9jdW1lbnRUZXh0T3V0bGluZSxcbiAgbm90aWZpY2F0aW9uc09mZk91dGxpbmUsXG4gIG5vdGlmaWNhdGlvbnNPdXRsaW5lLFxuICBvcGVuT3V0bGluZSxcbiAgcGVyc29uT3V0bGluZSxcbn0gZnJvbSAnaW9uaWNvbnMvaWNvbnMnO1xuXG5pbXBvcnQgeyBCdXR0b25Db21wb25lbnQgfSBmcm9tICcuLi8uLi9hdG9tcy9idXR0b24vYnV0dG9uLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBEaXNwbGF5Q29tcG9uZW50IH0gZnJvbSAnLi4vLi4vYXRvbXMvZGlzcGxheS9kaXNwbGF5LmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUZXh0Q29tcG9uZW50IH0gZnJvbSAnLi4vLi4vYXRvbXMvdGV4dC90ZXh0LmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUaXRsZUNvbXBvbmVudCB9IGZyb20gJy4uLy4uL2F0b21zL3RpdGxlL3RpdGxlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBFbXB0eVN0YXRlQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vbW9sZWN1bGVzL2VtcHR5LXN0YXRlL2VtcHR5LXN0YXRlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBFbXB0eVN0YXRlTWV0YWRhdGEgfSBmcm9tICcuLi8uLi9tb2xlY3VsZXMvZW1wdHktc3RhdGUvdHlwZXMnO1xuaW1wb3J0IHsgY3JlYXRlRXJyb3JTdGF0ZVByb3BzIH0gZnJvbSAnLi4vLi4vbW9sZWN1bGVzL2VtcHR5LXN0YXRlL2ZhY3RvcnknO1xuaW1wb3J0IHsgU2tlbGV0b25MYXlvdXRDb21wb25lbnQgfSBmcm9tICcuLi9za2VsZXRvbi1sYXlvdXQvc2tlbGV0b24tbGF5b3V0LmNvbXBvbmVudCc7XG5pbXBvcnQgeyBCdXR0b25NZXRhZGF0YSwgQ29tcG9uZW50U3RhdGVzIH0gZnJvbSAnLi4vLi4vdHlwZXMnO1xuXG5pbXBvcnQgeyBBdXRoU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2F1dGgvYXV0aC5zZXJ2aWNlJztcbmltcG9ydCB7IE5vdGlmaWNhdGlvbkFjdGlvblNlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9hdXRoL25vdGlmaWNhdGlvbi1hY3Rpb24uc2VydmljZSc7XG5pbXBvcnQgeyBJMThuU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2kxOG4nO1xuaW1wb3J0IHsgaW50ZXJwcmV0RXJyb3IgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9lcnJvcnMvaW50ZXJwcmV0LWVycm9yJztcbmltcG9ydCB7IE5hdmlnYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvbmF2aWdhdGlvbi9uYXZpZ2F0aW9uLnNlcnZpY2UnO1xuaW1wb3J0IHsgTm90aWZpY2F0aW9uRG9jdW1lbnQsIE5vdGlmaWNhdGlvbnNTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvZmlyZWJhc2Uvbm90aWZpY2F0aW9ucy5zZXJ2aWNlJztcbmltcG9ydCB7IFBhZ2VSZWZyZXNoU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL3BhZ2UtcmVmcmVzaC9wYWdlLXJlZnJlc2guc2VydmljZSc7XG5pbXBvcnQgeyBjcmVhdGVSZWZyZXNoYWJsZVN0cmVhbSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL3JlZnJlc2hhYmxlLXN0cmVhbS9yZWZyZXNoYWJsZS1zdHJlYW0nO1xuaW1wb3J0IHsgVG9hc3RTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvdG9hc3Quc2VydmljZSc7XG5pbXBvcnQgeyBWYWx0ZWNoRXJyb3JTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvZXJyb3JzL3ZhbHRlY2gtZXJyb3Iuc2VydmljZSc7XG5cbmltcG9ydCB7IE5vdGlmaWNhdGlvbnNWaWV3Q29uZmlnIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBOT1RJRklDQVRJT05TX1ZJRVdfSTE4TiB9IGZyb20gJy4vbm90aWZpY2F0aW9ucy12aWV3LmkxOG4nO1xuXG5hZGRJY29ucyh7XG4gIGFsYXJtT3V0bGluZSxcbiAgY2hhdGJveEVsbGlwc2VzT3V0bGluZSxcbiAgY2hhdGJ1YmJsZU91dGxpbmUsXG4gIGNoZWNrbWFya0NpcmNsZU91dGxpbmUsXG4gIGNoZWNrbWFya0RvbmVPdXRsaW5lLFxuICBjbG91ZE9mZmxpbmVPdXRsaW5lLFxuICBjb2dPdXRsaW5lLFxuICBkb2N1bWVudFRleHRPdXRsaW5lLFxuICBub3RpZmljYXRpb25zT2ZmT3V0bGluZSxcbiAgbm90aWZpY2F0aW9uc091dGxpbmUsXG4gIG9wZW5PdXRsaW5lLFxuICBwZXJzb25PdXRsaW5lLFxufSk7XG5cbmNvbnN0IERFRkFVTFRfTkFNRVNQQUNFID0gJ05vdGlmaWNhdGlvbnMnO1xuY29uc3QgREVGQVVMVF9TRVRUSU5HU19QQVRIID0gJy9hcHAvc2V0dGluZ3Mvbm90aWZpY2F0aW9ucyc7XG5jb25zdCBERUZBVUxUX1BBR0VfU0laRSA9IDEwO1xuY29uc3QgREVGQVVMVF9NQVhfTE9BRCA9IDUwO1xuXG50eXBlIEdyb3VwS2V5ID0gJ3RvZGF5JyB8ICd0aGlzTW9udGgnIHwgJ2VhcmxpZXInO1xuXG5pbnRlcmZhY2UgTm90aWZpY2F0aW9uR3JvdXAge1xuICBrZXk6IEdyb3VwS2V5O1xuICBsYWJlbDogc3RyaW5nO1xuICBpdGVtczogTm90aWZpY2F0aW9uRG9jdW1lbnRbXTtcbn1cblxudHlwZSBSZXNvbHZlZEljb24gPVxuICB8IHsga2luZDogJ2lvbmljb24nOyBuYW1lOiBzdHJpbmc7IGNvbG9yPzogc3RyaW5nIH1cbiAgfCB7IGtpbmQ6ICdpbWFnZSc7IHNyYzogc3RyaW5nIH1cbiAgfCB7IGtpbmQ6ICdhdmF0YXInOyBzcmM6IHN0cmluZyB9O1xuXG5pbnRlcmZhY2UgSWNvbkhpbnQge1xuICB0eXBlPzogJ2lvbmljb24nIHwgJ2ltYWdlJyB8ICdhdmF0YXInO1xuICB2YWx1ZT86IHN0cmluZztcbiAgY29sb3I/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogYHZhbC1ub3RpZmljYXRpb25zLXZpZXdgIOKAlCBpbmJveCBkZSBub3RpZmljYWNpb25lcyBmdWxsLWZlYXR1cmUgYXV0b2NvbnRlbmlkb1xuICogKG9yZ2FuaXNtKS4gUHJvbW92aWRvIGRlc2RlIGBzaG93Y2FzZWAgYmFqbyBlbCBwcm9jZXNvIGRlIEFEUi0wMjEuXG4gKlxuICogU2VwYXJhZG8gZGUgYC9hcHAvc2V0dGluZ3Mvbm90aWZpY2F0aW9uc2AgKHF1ZSBjb250cm9sYSBwZXJtaXNvIEZDTSArIG1hc3RlclxuICogdG9nZ2xlKS4gQXF1w60gZWwgdXNlciBsZWUvYWJyZS9tYXJjYS1sZcOtZGFzIHN1cyBtZW5zYWplcy5cbiAqXG4gKiAtICoqU3RyZWFtIHJlYWwtdGltZSoqIHbDrWEgYE5vdGlmaWNhdGlvbnNTZXJ2aWNlLmdldEFsbChtYXhMb2FkKWAgZW52dWVsdG8gZW5cbiAqICAgYGNyZWF0ZVJlZnJlc2hhYmxlU3RyZWFtYCAoZ2F0ZWFkbyBwb3IgYGZpcmViYXNlQXV0aFJlYWR5YCwgcmV0cnkgY29ydG8sXG4gKiAgIGBmaXJzdEVtaXRUaW1lb3V0TXM6IDE1MDAwYCkuIEVzdGFkb3M6IGxvYWRpbmcgKHNrZWxldG9uKSwgZXJyb3JcbiAqICAgKGB2YWwtZW1wdHktc3RhdGVgICsgcmVpbnRlbnRhciksIGVtcHR5IChgdmFsLWVtcHR5LXN0YXRlYCArIENUQSksIGRhdGFcbiAqICAgKGxpc3RhIGFncnVwYWRhIEhveSAvIEVzdGUgbWVzIC8gQW50ZXJpb3JlcykuXG4gKiAtICoqQWJyaXIqKiB1bmEgbm90aWYg4oaSIGBOb3RpZmljYXRpb25BY3Rpb25TZXJ2aWNlLm9wZW4oKWAgKG1hcmtSZWFkICtcbiAqICAgc3dpdGNoLW9yZyArIG5hdmVnYXIvaGFuZG9mZiBjcm9zcy1hcHApLiBIb29rIGBvbk5vdGlmaWNhdGlvbk9wZW5gIG9wY2lvbmFsLlxuICogLSAqKk1hcmNhciB0b2RhcyBjb21vIGxlw61kYXMqKiAoZ2F0ZWFkbyBwb3IgYGVuYWJsZU1hcmtBbGxgKS5cbiAqIC0gKipDVEEgcHVzaC1vZmYqKiBjdWFuZG8gZWwgcGVybWlzbyBkZWwgbmF2ZWdhZG9yIG5vIGVzdMOhIGNvbmNlZGlkbyAoZ2F0ZWFkb1xuICogICBwb3IgYHNob3dQdXNoT2ZmQ3RhYCk7IG5hdmVnYSBhIGBzZXR0aW5nc05vdGlmaWNhdGlvbnNQYXRoYC5cbiAqIC0gKipQYWdpbmFjacOzbiBzb2Z0Kiog4oCUIHNsaWNlIGxvY2FsIChgcGFnZVNpemVgLCArYHBhZ2VTaXplYCBwb3IgY2xpY2spIHNvYnJlIGVsXG4gKiAgIGNhY2hlIGRlbCBzdHJlYW07IGVsIHRvcGUgZGUgZmV0Y2ggZXMgYG1heExvYWRgLlxuICogLSAqKmkxOG4gYXV0by1yZWdpc3RyYWRvKiogZXMvZW4gYmFqbyBgaTE4bk5hbWVzcGFjZWAgKGRlZmF1bHQgYE5vdGlmaWNhdGlvbnNgKS5cbiAqXG4gKiBOTyByZW5kZXJpemEgaW9uLWNvbnRlbnQg4oCUIHZpdmUgZGVudHJvIGRlIHZhbC1wYWdlLXdyYXBwZXIuIGBSb3V0ZXJgIHlcbiAqIGBBY3RpdmF0ZWRSb3V0ZWAgc2UgaW55ZWN0YW4gYHsgb3B0aW9uYWw6IHRydWUgfWAg4oaSIGZ1bmNpb25hIHNpbiByb3V0ZXJcbiAqIChlbWJlYmlkYSAvIFN0b3J5Ym9vaykuIEVsIGZvcndhcmQtY29tcGF0IGljb24gcmVzb2x2ZXIgbGVlIGBub3RpZi5wYXlsb2FkLmljb25gXG4gKiBzaSBleGlzdGUgKGB7IHR5cGUsIHZhbHVlLCBjb2xvcj8gfWApLCBjYWUgYSB1biBtYXBhIHBvciBgbm90aWYudHlwZWAsIGx1ZWdvIGFcbiAqIGBub3RpZmljYXRpb25zLW91dGxpbmVgLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd2YWwtbm90aWZpY2F0aW9ucy12aWV3JyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIElvbkljb24sXG4gICAgRGlzcGxheUNvbXBvbmVudCxcbiAgICBUaXRsZUNvbXBvbmVudCxcbiAgICBUZXh0Q29tcG9uZW50LFxuICAgIEJ1dHRvbkNvbXBvbmVudCxcbiAgICBTa2VsZXRvbkxheW91dENvbXBvbmVudCxcbiAgICBFbXB0eVN0YXRlQ29tcG9uZW50LFxuICBdLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJwYWdlXCI+XG4gICAgICA8aGVhZGVyIGNsYXNzPVwicGFnZS1oZWFkZXJcIj5cbiAgICAgICAgPHZhbC1kaXNwbGF5IFtwcm9wc109XCJ7IHNpemU6ICdzbWFsbCcsIGNvbG9yOiAnZGFyaycsIGNvbnRlbnQ6IHBhZ2VUaXRsZSgpIH1cIiAvPlxuICAgICAgICA8dmFsLXRpdGxlXG4gICAgICAgICAgW3Byb3BzXT1cIntcbiAgICAgICAgICAgIHNpemU6ICdsYXJnZScsXG4gICAgICAgICAgICBjb2xvcjogJ2RhcmsnLFxuICAgICAgICAgICAgYm9sZDogZmFsc2UsXG4gICAgICAgICAgICBjb250ZW50OiBwYWdlRGVzY3JpcHRpb24oKSxcbiAgICAgICAgICB9XCJcbiAgICAgICAgLz5cbiAgICAgICAgQGlmIChzaG93TWFya0FsbCgpKSB7XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInJvdy1hY3Rpb25zXCI+XG4gICAgICAgICAgICA8dmFsLWJ1dHRvbiBbcHJvcHNdPVwibWFya0FsbEJ1dHRvblByb3BzKClcIiAoY2xpY2spPVwib25NYXJrQWxsKClcIiAvPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L2hlYWRlcj5cblxuICAgICAgQGlmIChyZXNvbHZlZENvbmZpZygpLnNob3dQdXNoT2ZmQ3RhICYmICFwdXNoRW5hYmxlZCgpKSB7XG4gICAgICAgIDxzZWN0aW9uIGNsYXNzPVwibm90aWYtY3RhXCI+XG4gICAgICAgICAgPGlvbi1pY29uIGNsYXNzPVwibm90aWYtY3RhX19pY29uXCIgbmFtZT1cIm5vdGlmaWNhdGlvbnMtb2ZmLW91dGxpbmVcIiBhcmlhLWhpZGRlbj1cInRydWVcIiAvPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJub3RpZi1jdGFfX2JvZHlcIj5cbiAgICAgICAgICAgIDx2YWwtdGV4dFxuICAgICAgICAgICAgICBbcHJvcHNdPVwie1xuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IGN0YVRpdGxlKCksXG4gICAgICAgICAgICAgICAgc2l6ZTogJ21lZGl1bScsXG4gICAgICAgICAgICAgICAgY29sb3I6ICdkYXJrJyxcbiAgICAgICAgICAgICAgICBib2xkOiB0cnVlLFxuICAgICAgICAgICAgICB9XCJcbiAgICAgICAgICAgIC8+XG4gICAgICAgICAgICA8dmFsLXRleHRcbiAgICAgICAgICAgICAgW3Byb3BzXT1cIntcbiAgICAgICAgICAgICAgICBjb250ZW50OiBjdGFIaW50KCksXG4gICAgICAgICAgICAgICAgc2l6ZTogJ3NtYWxsJyxcbiAgICAgICAgICAgICAgICBjb2xvcjogJ21lZGl1bScsXG4gICAgICAgICAgICAgICAgYm9sZDogZmFsc2UsXG4gICAgICAgICAgICAgIH1cIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJyb3ctYWN0aW9uc1wiPlxuICAgICAgICAgICAgICA8dmFsLWJ1dHRvbiBbcHJvcHNdPVwiY3RhQnV0dG9uUHJvcHMoKVwiIChjbGljayk9XCJvbkdvVG9TZXR0aW5ncygpXCIgLz5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L3NlY3Rpb24+XG4gICAgICB9XG5cbiAgICAgIEBpZiAobG9hZGluZygpKSB7XG4gICAgICAgIDx2YWwtc2tlbGV0b24tbGF5b3V0IFtwcm9wc109XCJ7IHByZXNldDogJ2xpc3QnLCByb3dzOiA2IH1cIiAvPlxuICAgICAgfSBAZWxzZSBpZiAoZXJyb3JTdGF0ZSgpKSB7XG4gICAgICAgIDx2YWwtZW1wdHktc3RhdGUgW3Byb3BzXT1cImVycm9yU3RhdGUoKSFcIiAvPlxuICAgICAgfSBAZWxzZSBpZiAoYWxsTm90aWZzKCkubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIDx2YWwtZW1wdHktc3RhdGUgW3Byb3BzXT1cImVtcHR5U3RhdGVQcm9wcygpXCIgLz5cbiAgICAgIH0gQGVsc2Uge1xuICAgICAgICBAZm9yIChncm91cCBvZiBncm91cHMoKTsgdHJhY2sgZ3JvdXAua2V5KSB7XG4gICAgICAgICAgPHNlY3Rpb24gY2xhc3M9XCJncm91cFwiPlxuICAgICAgICAgICAgPHZhbC10aXRsZVxuICAgICAgICAgICAgICBbcHJvcHNdPVwie1xuICAgICAgICAgICAgICAgIHNpemU6ICdtZWRpdW0nLFxuICAgICAgICAgICAgICAgIGNvbG9yOiAnZGFyaycsXG4gICAgICAgICAgICAgICAgYm9sZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjb250ZW50OiBncm91cC5sYWJlbCxcbiAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHVsIGNsYXNzPVwibm90aWYtbGlzdFwiPlxuICAgICAgICAgICAgICBAZm9yIChuIG9mIGdyb3VwLml0ZW1zOyB0cmFjayBuLmlkKSB7XG4gICAgICAgICAgICAgICAgPGxpIGNsYXNzPVwibm90aWZcIiBbY2xhc3Mubm90aWYtLXVucmVhZF09XCIhbi5pc1JlYWRcIj5cbiAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJub3RpZl9faWNvblwiPlxuICAgICAgICAgICAgICAgICAgICBAc3dpdGNoIChyZXNvbHZlSWNvbihuKS5raW5kKSB7XG4gICAgICAgICAgICAgICAgICAgICAgQGNhc2UgKCdpb25pY29uJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgPGlvbi1pY29uXG4gICAgICAgICAgICAgICAgICAgICAgICAgIFtuYW1lXT1cImlvbmljb25OYW1lKG4pXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgW3N0eWxlLmNvbG9yXT1cImlvbkNvbG9yKGlvbmljb25Db2xvcihuKSlcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICBhcmlhLWhpZGRlbj1cInRydWVcIlxuICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgQGNhc2UgKCdpbWFnZScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIDxpbWcgW3NyY109XCJpbWFnZVNyYyhuKVwiIGFsdD1cIlwiIGxvYWRpbmc9XCJsYXp5XCIgLz5cbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgQGNhc2UgKCdhdmF0YXInKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8aW1nIGNsYXNzPVwibm90aWZfX2F2YXRhclwiIFtzcmNdPVwiaW1hZ2VTcmMobilcIiBhbHQ9XCJcIiBsb2FkaW5nPVwibGF6eVwiIC8+XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5vdGlmX19ib2R5XCI+XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJub3RpZl9faGVhZFwiPlxuICAgICAgICAgICAgICAgICAgICAgIDx2YWwtdGV4dFxuICAgICAgICAgICAgICAgICAgICAgICAgW3Byb3BzXT1cIntcbiAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGVudDogbi50aXRsZSB8fCAn4oCUJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZTogJ21lZGl1bScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yOiAnZGFyaycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGJvbGQ6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICB9XCJcbiAgICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibm90aWZfX3RpbWVcIj57eyByZWxhdGl2ZVRpbWUobikgfX08L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICAgICBAaWYgKG4uYm9keSkge1xuICAgICAgICAgICAgICAgICAgICAgIDxwIGNsYXNzPVwibm90aWZfX3RleHRcIiBbY2xhc3Mubm90aWZfX3RleHQtLWNsYW1wZWRdPVwiIWlzRXhwYW5kZWQobi5pZCkgJiYgaXNMb25nKG4uYm9keSlcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt7IG4uYm9keSB9fVxuICAgICAgICAgICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgICAgICAgICBAaWYgKGlzTG9uZyhuLmJvZHkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwibm90aWZfX2V4cGFuZFwiIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwidG9nZ2xlRXhwYW5kKG4uaWQpXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHt7IGlzRXhwYW5kZWQobi5pZCkgPyBzZWVMZXNzKCkgOiBzZWVNb3JlKCkgfX1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBAaWYgKHNob3dDcm9zc0FwcEJhZGdlKG4pOyBhcyBhcHBOYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJub3RpZl9fYXBwXCI+e3sgYXBwTmFtZSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBAaWYgKG4uYWN0aW9uUm91dGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwicm93LWFjdGlvbnMgcm93LWFjdGlvbnMtLWVuZFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPHZhbC1idXR0b24gW3Byb3BzXT1cIm9wZW5CdXR0b25Qcm9wcygpXCIgKGNsaWNrKT1cIm9uT3BlbihuKVwiIC8+XG4gICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvbGk+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvdWw+XG4gICAgICAgICAgPC9zZWN0aW9uPlxuICAgICAgICB9XG5cbiAgICAgICAgQGlmIChoYXNNb3JlKCkpIHtcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwicm93LWFjdGlvbnMgcm93LWFjdGlvbnMtLWNlbnRlclwiPlxuICAgICAgICAgICAgPHZhbC1idXR0b24gW3Byb3BzXT1cImxvYWRNb3JlQnV0dG9uUHJvcHMoKVwiIChjbGljayk9XCJvbkxvYWRNb3JlKClcIiAvPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICB9XG4gICAgPC9kaXY+XG4gIGAsXG4gIHN0eWxlczogW1xuICAgIGBcbiAgICAgIC5wYWdlIHtcbiAgICAgICAgcGFkZGluZzogMTZweCAwO1xuICAgICAgICBtYXgtd2lkdGg6IDcyMHB4O1xuICAgICAgICBtYXJnaW46IDAgYXV0bztcbiAgICAgIH1cbiAgICAgIC5wYWdlLWhlYWRlciB7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDE2cHg7XG4gICAgICB9XG4gICAgICAucm93LWFjdGlvbnMge1xuICAgICAgICBtYXJnaW4tdG9wOiAxMnB4O1xuICAgICAgfVxuICAgICAgLnJvdy1hY3Rpb25zLS1jZW50ZXIge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgICAgICAgbWFyZ2luLXRvcDogMjBweDtcbiAgICAgIH1cbiAgICAgIC5yb3ctYWN0aW9ucy0tZW5kIHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBmbGV4LWVuZDtcbiAgICAgICAgbWFyZ2luLXRvcDogOHB4O1xuICAgICAgfVxuXG4gICAgICAubm90aWYtY3RhIHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZ2FwOiAxMnB4O1xuICAgICAgICBhbGlnbi1pdGVtczogZmxleC1zdGFydDtcbiAgICAgICAgcGFkZGluZzogMTRweCAxNnB4O1xuICAgICAgICBtYXJnaW4tYm90dG9tOiAxNnB4O1xuICAgICAgICAvKiBTdGVwLSogbm8gaW52aWVydGUgZW4gZGFyaywgdGV4dG8gbGlnaHQgKyBiZyBsaWdodCA9IGludmlzaWJsZS5cbiAgICAgICAgICAgbGlnaHQvbGlnaHQtc2hhZGUgc2kgZmxpcHBhbiBjb24gZWwgcGFsZXR0ZSBkYXJrIGRlIElvbmljLiAqL1xuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1pb24tY29sb3ItbGlnaHQtc2hhZGUsIHJnYmEoMCwgMCwgMCwgMC4wOCkpO1xuICAgICAgICBib3JkZXItcmFkaXVzOiAxNHB4O1xuICAgICAgICBiYWNrZ3JvdW5kOiB2YXIoLS1pb24tY29sb3ItbGlnaHQpO1xuICAgICAgfVxuICAgICAgLm5vdGlmLWN0YV9faWNvbiB7XG4gICAgICAgIGZvbnQtc2l6ZTogMjRweDtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1kYXJrLCAjMWExYTFhKTtcbiAgICAgICAgZmxleC1zaHJpbms6IDA7XG4gICAgICAgIG1hcmdpbi10b3A6IDJweDtcbiAgICAgIH1cbiAgICAgIC5ub3RpZi1jdGFfX2JvZHkge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICAgICAgICBnYXA6IDJweDtcbiAgICAgIH1cblxuICAgICAgLmdyb3VwIHtcbiAgICAgICAgcGFkZGluZzogMTJweCAwO1xuICAgICAgfVxuICAgICAgLmdyb3VwICsgLmdyb3VwIHtcbiAgICAgICAgYm9yZGVyLXRvcDogMXB4IHNvbGlkIHZhcigtLXZhbC1ib3JkZXItY29sb3IsIHJnYmEoMCwgMCwgMCwgMC4wOCkpO1xuICAgICAgfVxuXG4gICAgICAubm90aWYtbGlzdCB7XG4gICAgICAgIGxpc3Qtc3R5bGU6IG5vbmU7XG4gICAgICAgIHBhZGRpbmc6IDA7XG4gICAgICAgIG1hcmdpbjogMTJweCAwIDA7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICAgIGdhcDogMTBweDtcbiAgICAgIH1cbiAgICAgIC5ub3RpZiB7XG4gICAgICAgIGRpc3BsYXk6IGdyaWQ7XG4gICAgICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogNDRweCAxZnI7XG4gICAgICAgIGdhcDogMTJweDtcbiAgICAgICAgcGFkZGluZzogMTJweDtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogMTJweDtcbiAgICAgICAgYmFja2dyb3VuZDogdHJhbnNwYXJlbnQ7XG4gICAgICAgIHRyYW5zaXRpb246IGJhY2tncm91bmQgMTIwbXMgZWFzZTtcbiAgICAgIH1cbiAgICAgIC5ub3RpZi0tdW5yZWFkIHtcbiAgICAgICAgYmFja2dyb3VuZDogdmFyKC0taW9uLWNvbG9yLWxpZ2h0LCByZ2JhKDAsIDAsIDAsIDAuMDQpKTtcbiAgICAgIH1cbiAgICAgIC5ub3RpZl9faWNvbiB7XG4gICAgICAgIHdpZHRoOiA0NHB4O1xuICAgICAgICBoZWlnaHQ6IDQ0cHg7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWlvbi1jb2xvci1saWdodCwgcmdiYSgwLCAwLCAwLCAwLjA2KSk7XG4gICAgICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgICB9XG4gICAgICAubm90aWZfX2ljb24gaW9uLWljb24ge1xuICAgICAgICBmb250LXNpemU6IDIycHg7XG4gICAgICB9XG4gICAgICAubm90aWZfX2ljb24gaW1nIHtcbiAgICAgICAgd2lkdGg6IDEwMCU7XG4gICAgICAgIGhlaWdodDogMTAwJTtcbiAgICAgICAgb2JqZWN0LWZpdDogY292ZXI7XG4gICAgICB9XG4gICAgICAubm90aWZfX2F2YXRhciB7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICAgIH1cblxuICAgICAgLm5vdGlmX19ib2R5IHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgICAgICAgZ2FwOiA0cHg7XG4gICAgICAgIG1pbi13aWR0aDogMDtcbiAgICAgIH1cbiAgICAgIC5ub3RpZl9faGVhZCB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcbiAgICAgICAgYWxpZ24taXRlbXM6IGJhc2VsaW5lO1xuICAgICAgICBnYXA6IDhweDtcbiAgICAgIH1cbiAgICAgIC5ub3RpZl9fdGltZSB7XG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1tZWRpdW0sICM5Mjk0OWMpO1xuICAgICAgICBmbGV4LXNocmluazogMDtcbiAgICAgIH1cbiAgICAgIC5ub3RpZl9fdGV4dCB7XG4gICAgICAgIG1hcmdpbjogMDtcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICBsaW5lLWhlaWdodDogMS40O1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLWRhcmssICMxYTFhMWEpO1xuICAgICAgICB3aGl0ZS1zcGFjZTogcHJlLXdyYXA7XG4gICAgICB9XG4gICAgICAubm90aWZfX3RleHQtLWNsYW1wZWQge1xuICAgICAgICBkaXNwbGF5OiAtd2Via2l0LWJveDtcbiAgICAgICAgLXdlYmtpdC1saW5lLWNsYW1wOiAyO1xuICAgICAgICAtd2Via2l0LWJveC1vcmllbnQ6IHZlcnRpY2FsO1xuICAgICAgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgICAgfVxuICAgICAgLm5vdGlmX19leHBhbmQge1xuICAgICAgICBiYWNrZ3JvdW5kOiBub25lO1xuICAgICAgICBib3JkZXI6IDA7XG4gICAgICAgIHBhZGRpbmc6IDA7XG4gICAgICAgIGZvbnQtc2l6ZTogMTNweDtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1kYXJrLCAjMWExYTFhKTtcbiAgICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgICBhbGlnbi1zZWxmOiBmbGV4LXN0YXJ0O1xuICAgICAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTtcbiAgICAgIH1cbiAgICAgIC5ub3RpZl9fYXBwIHtcbiAgICAgICAgZm9udC1zaXplOiAxMXB4O1xuICAgICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgICAgICBsZXR0ZXItc3BhY2luZzogMC40cHg7XG4gICAgICAgIGNvbG9yOiB2YXIoLS1pb24tY29sb3ItbWVkaXVtLCAjOTI5NDljKTtcbiAgICAgICAgbWFyZ2luLXRvcDogMnB4O1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIE5vdGlmaWNhdGlvbnNWaWV3Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBwcml2YXRlIG5hdiA9IGluamVjdChOYXZpZ2F0aW9uU2VydmljZSk7XG4gIHByaXZhdGUgaTE4biA9IGluamVjdChJMThuU2VydmljZSk7XG4gIHByaXZhdGUgbm90aWZzID0gaW5qZWN0KE5vdGlmaWNhdGlvbnNTZXJ2aWNlKTtcbiAgcHJpdmF0ZSBhY3Rpb24gPSBpbmplY3QoTm90aWZpY2F0aW9uQWN0aW9uU2VydmljZSk7XG4gIHByaXZhdGUgdG9hc3QgPSBpbmplY3QoVG9hc3RTZXJ2aWNlKTtcbiAgcHJpdmF0ZSBlcnJvcnMgPSBpbmplY3QoVmFsdGVjaEVycm9yU2VydmljZSk7XG4gIHByaXZhdGUgYXV0aCA9IGluamVjdChBdXRoU2VydmljZSk7XG4gIHByaXZhdGUgcGFnZVJlZnJlc2ggPSBpbmplY3QoUGFnZVJlZnJlc2hTZXJ2aWNlKTtcbiAgLy8gYEFjdGl2YXRlZFJvdXRlYCBvcGNpb25hbCDihpIgbGEgdmlzdGEgZnVuY2lvbmEgZW1iZWJpZGEgLyBlbiBTdG9yeWJvb2sgc2luXG4gIC8vIHJvdXRlciAoc29sbyBsbyB1c2EgcGFyYSBsZWVyIGVsIHJvdXRlIGRhdGEgZGUgY29uZmlnIGNvbW8gZmFsbGJhY2spLiBMYVxuICAvLyBuYXZlZ2FjacOzbiB2YSBwb3IgYE5hdmlnYXRpb25TZXJ2aWNlYCAod3JhcHBlciBvcGNpb25hbCBzb2JyZSBgUm91dGVyYCkuXG4gIHByaXZhdGUgcm91dGUgPSBpbmplY3QoQWN0aXZhdGVkUm91dGUsIHsgb3B0aW9uYWw6IHRydWUgfSk7XG5cbiAgLyoqXG4gICAqIENvbmZpZyB2w61hIEBJbnB1dCAob2JqZWN0LWZpcnN0KS4gU2kgbm8gc2UgcGFzYSwgc2UgY2FlIGFsIHJvdXRlIGRhdGFcbiAgICogYG5vdGlmaWNhdGlvbnNDb25maWdgIChwb2JsYWRvIHBvciBgcHJvdmlkZVZhbHRlY2hOb3RpZmljYXRpb25zUm91dGVzYCkuXG4gICAqIGByZXNvbHZlZENvbmZpZ2AgbWVyZ2VhIGNvbiBsb3MgZGVmYXVsdHMg4oCUIGBASW5wdXRgIGdhbmEgc29icmUgcm91dGUgZGF0YS5cbiAgICovXG4gIEBJbnB1dCgpIGNvbmZpZz86IE5vdGlmaWNhdGlvbnNWaWV3Q29uZmlnO1xuXG4gIHJlYWRvbmx5IHJlc29sdmVkQ29uZmlnID0gY29tcHV0ZWQ8XG4gICAgUmVxdWlyZWQ8T21pdDxOb3RpZmljYXRpb25zVmlld0NvbmZpZywgJ29uTm90aWZpY2F0aW9uT3Blbic+PiAmIFBpY2s8Tm90aWZpY2F0aW9uc1ZpZXdDb25maWcsICdvbk5vdGlmaWNhdGlvbk9wZW4nPlxuICA+KCgpID0+IHtcbiAgICBjb25zdCBmcm9tUm91dGUgPSAodGhpcy5yb3V0ZT8uc25hcHNob3QuZGF0YVsnbm90aWZpY2F0aW9uc0NvbmZpZyddID8/IHt9KSBhcyBOb3RpZmljYXRpb25zVmlld0NvbmZpZztcbiAgICBjb25zdCBtZXJnZWQ6IE5vdGlmaWNhdGlvbnNWaWV3Q29uZmlnID0geyAuLi5mcm9tUm91dGUsIC4uLih0aGlzLmNvbmZpZyA/PyB7fSkgfTtcbiAgICByZXR1cm4ge1xuICAgICAgc2hvd1B1c2hPZmZDdGE6IG1lcmdlZC5zaG93UHVzaE9mZkN0YSA/PyB0cnVlLFxuICAgICAgZW5hYmxlTWFya0FsbDogbWVyZ2VkLmVuYWJsZU1hcmtBbGwgPz8gdHJ1ZSxcbiAgICAgIHNldHRpbmdzTm90aWZpY2F0aW9uc1BhdGg6IG1lcmdlZC5zZXR0aW5nc05vdGlmaWNhdGlvbnNQYXRoID8/IERFRkFVTFRfU0VUVElOR1NfUEFUSCxcbiAgICAgIGkxOG5OYW1lc3BhY2U6IG1lcmdlZC5pMThuTmFtZXNwYWNlID8/IERFRkFVTFRfTkFNRVNQQUNFLFxuICAgICAgcGFnZVNpemU6IG1lcmdlZC5wYWdlU2l6ZSA/PyBERUZBVUxUX1BBR0VfU0laRSxcbiAgICAgIG1heExvYWQ6IG1lcmdlZC5tYXhMb2FkID8/IERFRkFVTFRfTUFYX0xPQUQsXG4gICAgICBvbk5vdGlmaWNhdGlvbk9wZW46IG1lcmdlZC5vbk5vdGlmaWNhdGlvbk9wZW4sXG4gICAgfTtcbiAgfSk7XG5cbiAgLyoqIE5hbWVzcGFjZSBpMThuIHJlc3VlbHRvIChjYXB0dXJhZG8gcGFyYSBsbGFtYWRhcyBuby1yZWFjdGl2YXMpLiAqL1xuICBwcml2YXRlIGdldCBucygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnJlc29sdmVkQ29uZmlnKCkuaTE4bk5hbWVzcGFjZTtcbiAgfVxuXG4gIC8qKiBQYXNvIGRlIHBhZ2luYWNpw7NuIHNvZnQgKHJldmVsYSArTiBwb3IgXCJjYXJnYXIgbcOhc1wiKS4gKi9cbiAgcHJpdmF0ZSBnZXQgcGFnZVN0ZXAoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5yZXNvbHZlZENvbmZpZygpLnBhZ2VTaXplO1xuICB9XG5cbiAgcHJpdmF0ZSByZWFkb25seSBfZXhwYW5kZWQgPSBzaWduYWw8U2V0PHN0cmluZz4+KG5ldyBTZXQoKSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3BhZ2VTaXplID0gc2lnbmFsKHRoaXMucmVzb2x2ZWRDb25maWcoKS5wYWdlU2l6ZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2J1bGtCdXN5ID0gc2lnbmFsKGZhbHNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbG9hZGluZ01vcmUgPSBzaWduYWwoZmFsc2UpO1xuXG4gIC8qKlxuICAgKiBQdXNoIGFjdGl2YWRvID0gcGVybWlzbyBkZWwgbmF2ZWdhZG9yIGVuIGBncmFudGVkYC4gU2kgTk8gZXN0w6EgYWN0aXZhZG8sXG4gICAqIGVsIHVzZXIgcHVlZGUgbGVlciBlbCBpbmJveCAoRmlyZXN0b3JlKSBwZXJvIE5PIHJlY2liaXLDoSBwdXNoIGVuIHN1XG4gICAqIGRpc3Bvc2l0aXZvIOKGkiBtb3N0cmFtb3MgdW5hIGNhcmQgcXVlIGxvIGludml0YSBhIGlyIGEgY29uZmlndXJhY2nDs24uXG4gICAqIFNlIGV2YWzDumEgZW4gY2FkYSBtb250YWplIGRlIGxhIHZpc3RhLlxuICAgKi9cbiAgcmVhZG9ubHkgcHVzaEVuYWJsZWQgPSBzaWduYWwodGhpcy5hdXRoLmdldE5vdGlmaWNhdGlvblBlcm1pc3Npb25TdGF0ZSgpID09PSAnZ3JhbnRlZCcpO1xuXG4gIC8qKlxuICAgKiBTdHJlYW0gZmlyZXN0b3JlIHJlYWwtdGltZSB2w61hIGVsIGhlbHBlciBlc3TDoW5kYXIgYGNyZWF0ZVJlZnJlc2hhYmxlU3RyZWFtYFxuICAgKiAobW9kbyByZWFsLXRpbWU6IGZhY3RvcnkgZGV2dWVsdmUgdW4gbGlzdGVuZXIgdml2byBgbm90aWZzLmdldEFsbChtYXhMb2FkKWApLlxuICAgKlxuICAgKiBFbCBoZWxwZXIgZ2F0ZWEgbGEgcHJpbWVyYSBzdXNjcmlwY2nDs24gcG9yIGBmaXJlYmFzZUF1dGhSZWFkeWAsIGFwbGljYSB1blxuICAgKiBgcmV0cnlgIGNvcnRvIGNvbiBiYWNrb2ZmIHksIHRyYXMgYWdvdGFyIHJlaW50ZW50b3MsIGVtaXRlIGVsIGZhbGxiYWNrIChgW11gKVxuICAgKiB5IG1hcmNhIGBlcnJvcmAg4oCUIGVzdGFkbyBkZSBlcnJvciBlbiBVSSwgbm8gc2tlbGV0b24gaW5maW5pdG8uIGByZWxvYWQoKWBcbiAgICogcmUtc3VzY3JpYmUgZWwgc3RyZWFtIGNvbXBsZXRvIChsbyB1c2EgZWwgcHVsbC10by1yZWZyZXNoKS5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgX3N0cmVhbSA9IGNyZWF0ZVJlZnJlc2hhYmxlU3RyZWFtPE5vdGlmaWNhdGlvbkRvY3VtZW50W10+KFxuICAgICgpID0+IHRoaXMubm90aWZzLmdldEFsbCh0aGlzLnJlc29sdmVkQ29uZmlnKCkubWF4TG9hZCksXG4gICAge1xuICAgICAgZmFsbGJhY2s6IFtdLFxuICAgICAgLy8gYG5vdGlmcy5nZXRBbGwoKWAgWUEgZ2F0ZWEgaW50ZXJuYW1lbnRlIHBvciBgZmlyZWJhc2VBdXRoUmVhZHlgLiBTaSBlbFxuICAgICAgLy8gc3RyZWFtIHRhbWJpw6luIGdhdGVhcmEsIHNlcsOtYW4gRE9TIGVzcGVyYXMgZGUgYXV0aCBhcGlsYWRhcy5cbiAgICAgIGdhdGVPbkZpcmViYXNlQXV0aDogZmFsc2UsXG4gICAgICAvLyBDb2xkIHN0YXJ0IGRlIFBXQSBlbiBpT1MgcHVlZGUgcGFzYXIgZGUgOHMgZW4gcmVkZXMgbGVudGFzOyBjb24gMTVzXG4gICAgICAvLyBldml0YW1vcyBlbCBmYWxzbyBlc3RhZG8gZGUgZXJyb3IuXG4gICAgICBmaXJzdEVtaXRUaW1lb3V0TXM6IDE1MDAwLFxuICAgIH1cbiAgKTtcblxuICAvKiogVHJ1ZSBzaSBlbCBzdHJlYW0gZmFsbMOzIHRyYXMgYWdvdGFyIHJlaW50ZW50b3Mg4oaSIG11ZXN0cmEgZXN0YWRvIGRlIGVycm9yLiAqL1xuICByZWFkb25seSBzdHJlYW1FcnJvciA9IHRoaXMuX3N0cmVhbS5lcnJvcjtcblxuICByZWFkb25seSBsb2FkaW5nID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5fc3RyZWFtLmRhdGEoKSA9PT0gbnVsbCk7XG5cbiAgLyoqXG4gICAqIE5vdGlmcyByZWFsZXMgbW9zdHJhZGFzLiBGaWx0cmFtb3MgZG9jcyBzaW4gdMOtdHVsbyBZIHNpbiBib2R5IOKAlCBzb24gcnVpZG9cbiAgICogKHTDrXBpY2FtZW50ZSBzZW50aW5lbC9zeXN0ZW0gd3JpdGVzIHByZS1zY2hlbWEgY29uIHRpdGxlL2JvZHkgb3BjaW9uYWxlcykuXG4gICAqL1xuICByZWFkb25seSBhbGxOb3RpZnMgPSBjb21wdXRlZDxOb3RpZmljYXRpb25Eb2N1bWVudFtdPigoKSA9PlxuICAgICh0aGlzLl9zdHJlYW0uZGF0YSgpID8/IFtdKS5maWx0ZXIobiA9PiAhIShuLnRpdGxlICYmIG4udGl0bGUudHJpbSgpKSB8fCAhIShuLmJvZHkgJiYgbi5ib2R5LnRyaW0oKSkpXG4gICk7XG4gIHJlYWRvbmx5IGhhc01vcmUgPSBjb21wdXRlZCgoKSA9PiB0aGlzLmFsbE5vdGlmcygpLmxlbmd0aCA+IHRoaXMuX3BhZ2VTaXplKCkpO1xuICByZWFkb25seSBzaG93TWFya0FsbCA9IGNvbXB1dGVkKFxuICAgICgpID0+IHRoaXMucmVzb2x2ZWRDb25maWcoKS5lbmFibGVNYXJrQWxsICYmICF0aGlzLmxvYWRpbmcoKSAmJiB0aGlzLmFsbE5vdGlmcygpLnNvbWUobiA9PiAhbi5pc1JlYWQpXG4gICk7XG5cbiAgLyoqIFN1Yi1jb25qdW50byBwYWdpbmFkbywgYWdydXBhZG8gcG9yIHBlcsOtb2RvLiAqL1xuICByZWFkb25seSBncm91cHMgPSBjb21wdXRlZDxOb3RpZmljYXRpb25Hcm91cFtdPigoKSA9PiB7XG4gICAgY29uc3QgaXRlbXMgPSB0aGlzLmFsbE5vdGlmcygpLnNsaWNlKDAsIHRoaXMuX3BhZ2VTaXplKCkpO1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgY29uc3QgYnVja2V0czogUmVjb3JkPEdyb3VwS2V5LCBOb3RpZmljYXRpb25Eb2N1bWVudFtdPiA9IHtcbiAgICAgIHRvZGF5OiBbXSxcbiAgICAgIHRoaXNNb250aDogW10sXG4gICAgICBlYXJsaWVyOiBbXSxcbiAgICB9O1xuICAgIGZvciAoY29uc3QgbiBvZiBpdGVtcykge1xuICAgICAgYnVja2V0c1t0aGlzLmJ1Y2tldE9mKG4sIG5vdyldLnB1c2gobik7XG4gICAgfVxuICAgIGNvbnN0IG91dDogTm90aWZpY2F0aW9uR3JvdXBbXSA9IFtdO1xuICAgIGlmIChidWNrZXRzLnRvZGF5Lmxlbmd0aCkge1xuICAgICAgb3V0LnB1c2goeyBrZXk6ICd0b2RheScsIGxhYmVsOiB0aGlzLnR0KCdncm91cFRvZGF5JyksIGl0ZW1zOiBidWNrZXRzLnRvZGF5IH0pO1xuICAgIH1cbiAgICBpZiAoYnVja2V0cy50aGlzTW9udGgubGVuZ3RoKSB7XG4gICAgICBvdXQucHVzaCh7XG4gICAgICAgIGtleTogJ3RoaXNNb250aCcsXG4gICAgICAgIGxhYmVsOiB0aGlzLnR0KCdncm91cFRoaXNNb250aCcpLFxuICAgICAgICBpdGVtczogYnVja2V0cy50aGlzTW9udGgsXG4gICAgICB9KTtcbiAgICB9XG4gICAgaWYgKGJ1Y2tldHMuZWFybGllci5sZW5ndGgpIHtcbiAgICAgIG91dC5wdXNoKHsga2V5OiAnZWFybGllcicsIGxhYmVsOiB0aGlzLnR0KCdncm91cEVhcmxpZXInKSwgaXRlbXM6IGJ1Y2tldHMuZWFybGllciB9KTtcbiAgICB9XG4gICAgcmV0dXJuIG91dDtcbiAgfSk7XG5cbiAgcmVhZG9ubHkgcGFnZVRpdGxlID0gY29tcHV0ZWQoKCkgPT4gdGhpcy50dCgncGFnZVRpdGxlJykpO1xuICByZWFkb25seSBwYWdlRGVzY3JpcHRpb24gPSBjb21wdXRlZCgoKSA9PiB0aGlzLnR0KCdwYWdlRGVzY3JpcHRpb24nKSk7XG5cbiAgLy8gQ1RBIFwiYWN0aXZhIGxhcyBub3RpZmljYWNpb25lcyBwdXNoXCIg4oCUIHZpc2libGUgY3VhbmRvIHB1c2hFbmFibGVkKCkgZXMgZmFsc2UuXG4gIHJlYWRvbmx5IGN0YVRpdGxlID0gY29tcHV0ZWQoKCkgPT4gdGhpcy50dCgncHVzaE9mZlRpdGxlJykpO1xuICByZWFkb25seSBjdGFIaW50ID0gY29tcHV0ZWQoKCkgPT4gdGhpcy50dCgncHVzaE9mZkhpbnQnKSk7XG4gIHJlYWRvbmx5IGN0YUJ1dHRvblByb3BzID0gY29tcHV0ZWQ8UGFydGlhbDxCdXR0b25NZXRhZGF0YT4+KCgpID0+ICh7XG4gICAgdGV4dDogdGhpcy50dCgncHVzaE9mZkN0YScpLFxuICAgIGNvbG9yOiAnZGFyaycsXG4gICAgZmlsbDogJ291dGxpbmUnLFxuICAgIHNpemU6ICdzbWFsbCcsXG4gICAgc2hhcGU6ICdyb3VuZCcsXG4gICAgdHlwZTogJ2J1dHRvbicsXG4gIH0pKTtcblxuICAvKipcbiAgICogRXN0YWRvIGRlIGVycm9yIGRlIGNhcmdhOiBjb252aWVydGUgZWwgZXJyb3IgZGVsIHN0cmVhbSBlblxuICAgKiBgRW1wdHlTdGF0ZU1ldGFkYXRhYCB2aWEgZWwgaGVscGVyIGNhbsOzbmljbyBgY3JlYXRlRXJyb3JTdGF0ZVByb3BzYC5cbiAgICogRWwgaGVscGVyIGRlY2lkZSB2YXJpYW50ZSAoYG9mZmxpbmVgIHZzIGBlcnJvcmApIHBvciBgaXNOZXR3b3JrYC5cbiAgICogTnVsbCBjdWFuZG8gZWwgc3RyZWFtIG5vIGhhIGZhbGxhZG8uXG4gICAqL1xuICByZWFkb25seSBlcnJvclN0YXRlID0gY29tcHV0ZWQ8RW1wdHlTdGF0ZU1ldGFkYXRhIHwgbnVsbD4oKCkgPT4ge1xuICAgIHRoaXMuaTE4bi5sYW5nKCk7XG4gICAgY29uc3QgZXJyID0gdGhpcy5zdHJlYW1FcnJvcigpO1xuICAgIGlmICghZXJyKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gY3JlYXRlRXJyb3JTdGF0ZVByb3BzKGVyciwge1xuICAgICAgdGl0bGU6IHtcbiAgICAgICAgb2ZmbGluZTogdGhpcy50dCgnb2ZmbGluZVRpdGxlJyksXG4gICAgICAgIGVycm9yOiB0aGlzLnR0KCdsb2FkRXJyb3JUaXRsZScpLFxuICAgICAgfSxcbiAgICAgIGRlc2NyaXB0aW9uOiB7XG4gICAgICAgIG9mZmxpbmU6IHRoaXMudHQoJ29mZmxpbmVIaW50JyksXG4gICAgICAgIGVycm9yOiBpbnRlcnByZXRFcnJvcihlcnIpLm1lc3NhZ2UgfHwgdGhpcy50dCgnbG9hZEVycm9ySGludCcpLFxuICAgICAgfSxcbiAgICAgIHJldHJ5TGFiZWw6IHRoaXMudHQoJ3JldHJ5Q3RhJyksXG4gICAgICBvblJldHJ5OiAoKSA9PiB0aGlzLl9zdHJlYW0ucmVsb2FkKCksXG4gICAgICByZXRyeWluZzogdGhpcy5sb2FkaW5nKCksXG4gICAgfSk7XG4gIH0pO1xuXG4gIC8qKlxuICAgKiBFc3RhZG8gdmFjw61vIChsaXN0YSByZWFsID0gMCBub3RpZmljYWNpb25lcywgc2luIGVycm9yIGRlIGNhcmdhKS5cbiAgICogU2UgY29uc3RydXllIG1hbnVhbG1lbnRlIGNvbiBgdmFyaWFudDogJ2VtcHR5J2Ag4oCUIHNpbiBoZWxwZXIgZGUgZXJyb3IuXG4gICAqL1xuICByZWFkb25seSBlbXB0eVN0YXRlUHJvcHMgPSBjb21wdXRlZDxFbXB0eVN0YXRlTWV0YWRhdGE+KCgpID0+IHtcbiAgICB0aGlzLmkxOG4ubGFuZygpO1xuICAgIHJldHVybiB7XG4gICAgICB2YXJpYW50OiAnZW1wdHknLFxuICAgICAgaWNvbjogJ25vdGlmaWNhdGlvbnMtb2ZmLW91dGxpbmUnLFxuICAgICAgdGl0bGU6IHRoaXMudHQoJ2VtcHR5JyksXG4gICAgICBkZXNjcmlwdGlvbjogdGhpcy50dCgnZW1wdHlIaW50JyksXG4gICAgICBhY3Rpb246IHtcbiAgICAgICAgbGFiZWw6IHRoaXMudHQoJ2VtcHR5Q3RhJyksXG4gICAgICAgIGhhbmRsZXI6ICgpID0+IHRoaXMub25Hb1RvU2V0dGluZ3MoKSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfSk7XG5cbiAgcmVhZG9ubHkgc2VlTW9yZSA9IGNvbXB1dGVkKCgpID0+IHRoaXMudHQoJ3NlZU1vcmUnKSk7XG4gIHJlYWRvbmx5IHNlZUxlc3MgPSBjb21wdXRlZCgoKSA9PiB0aGlzLnR0KCdzZWVMZXNzJykpO1xuXG4gIHJlYWRvbmx5IG1hcmtBbGxCdXR0b25Qcm9wcyA9IGNvbXB1dGVkPFBhcnRpYWw8QnV0dG9uTWV0YWRhdGE+PigoKSA9PiAoe1xuICAgIHRleHQ6IHRoaXMudHQoJ21hcmtBbGwnKSxcbiAgICBjb2xvcjogJ2RhcmsnLFxuICAgIGZpbGw6ICdvdXRsaW5lJyxcbiAgICBzaXplOiAnc21hbGwnLFxuICAgIHNoYXBlOiAncm91bmQnLFxuICAgIHR5cGU6ICdidXR0b24nLFxuICAgIGljb246IHsgbmFtZTogJ2NoZWNrbWFyay1kb25lLW91dGxpbmUnLCBzbG90OiAnc3RhcnQnIH0sXG4gICAgc3RhdGU6IHRoaXMuX2J1bGtCdXN5KCkgPyBDb21wb25lbnRTdGF0ZXMuV09SS0lORyA6IENvbXBvbmVudFN0YXRlcy5FTkFCTEVELFxuICB9KSk7XG5cbiAgcmVhZG9ubHkgbG9hZE1vcmVCdXR0b25Qcm9wcyA9IGNvbXB1dGVkPFBhcnRpYWw8QnV0dG9uTWV0YWRhdGE+PigoKSA9PiAoe1xuICAgIHRleHQ6IHRoaXMudHQoJ2xvYWRNb3JlJyksXG4gICAgY29sb3I6ICdkYXJrJyxcbiAgICBmaWxsOiAnY2xlYXInLFxuICAgIHNpemU6ICdkZWZhdWx0JyxcbiAgICBzaGFwZTogJ3JvdW5kJyxcbiAgICB0eXBlOiAnYnV0dG9uJyxcbiAgICBzdGF0ZTogdGhpcy5fbG9hZGluZ01vcmUoKSA/IENvbXBvbmVudFN0YXRlcy5XT1JLSU5HIDogQ29tcG9uZW50U3RhdGVzLkVOQUJMRUQsXG4gIH0pKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICBjb25zdCBucyA9IHRoaXMubnM7XG4gICAgaWYgKCF0aGlzLmkxOG4uaGFzTmFtZXNwYWNlKG5zKSkge1xuICAgICAgdGhpcy5pMThuLnJlZ2lzdGVyQ29udGVudChucywgTk9USUZJQ0FUSU9OU19WSUVXX0kxOE4pO1xuICAgIH1cbiAgICB0aGlzLm5hdi5zZXRCYWNrSGVhZGVyKCdwYWdlVGl0bGUnLCBucywgeyB3aXRoTWVudTogdHJ1ZSB9KTtcblxuICAgIC8vIFJlLWFwbGljYXIgaGVhZGVyIGVuIGNhbWJpbyBkZSBpZGlvbWEuXG4gICAgZWZmZWN0KFxuICAgICAgKCkgPT4ge1xuICAgICAgICB0aGlzLmkxOG4ubGFuZygpO1xuICAgICAgICB0aGlzLm5hdi5zZXRCYWNrSGVhZGVyKCdwYWdlVGl0bGUnLCB0aGlzLm5zLCB7IHdpdGhNZW51OiB0cnVlIH0pO1xuICAgICAgfSxcbiAgICAgIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0cmEgZWwgcHVsbC10by1yZWZyZXNoIGVzdMOhbmRhci4gVXNhbW9zIGBuZ09uSW5pdGAvYG5nT25EZXN0cm95YFxuICAgKiAoTk8gYGlvblZpZXdXaWxsRW50ZXJgKSBwb3JxdWUgYHZhbC1wYWdlLXdyYXBwZXJgIHVzYSBgPHJvdXRlci1vdXRsZXQ+YFxuICAgKiBwbGFubyDigJQgbG9zIGhvb2tzIGBpb25WaWV3KmAgc29sbyBkaXNwYXJhbiBkZW50cm8gZGUgYDxpb24tcm91dGVyLW91dGxldD5gLlxuICAgKi9cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5wYWdlUmVmcmVzaC5yZWdpc3RlcigoKSA9PiB0aGlzLnJlbG9hZCgpKTtcbiAgfVxuXG4gIC8qKiBRdWl0YSBlbCBoYW5kbGVyIGFsIGRlc3RydWlyIGxhIHZpc3RhIOKAlCBlbCByZWZyZXNoZXIgZGVzYXBhcmVjZS4gKi9cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5wYWdlUmVmcmVzaC51bnJlZ2lzdGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVmcmVzaCBtYW51YWw6IHJlLXN1c2NyaWJlIGVsIHN0cmVhbSBGaXJlc3RvcmUgKGxpc3RlbmVyIG51ZXZvKSB2w61hIGVsXG4gICAqIGhlbHBlci4gUmVzdWVsdmUgdHJhcyB1biBtYXJnZW4gYnJldmUg4oCUIGVsIHN0cmVhbSBlcyByZWFsLXRpbWUgeSByZS1lbWl0ZVxuICAgKiBlbiBtaWxpc2VndW5kb3M7IGVsIGRlbGF5IHPDs2xvIG1hbnRpZW5lIGVsIHNwaW5uZXIgdmlzaWJsZSBsbyBqdXN0by5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVsb2FkKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuX3N0cmVhbS5yZWxvYWQoKTtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZShyID0+IHNldFRpbWVvdXQociwgNzAwKSk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gUGVyLWl0ZW0gaGVscGVycyAocHVyb3Mg4oCUIHVzYWJsZXMgZGVzZGUgdGVtcGxhdGUpLlxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBvcGVuQnV0dG9uUHJvcHMoKTogUGFydGlhbDxCdXR0b25NZXRhZGF0YT4ge1xuICAgIHJldHVybiB7XG4gICAgICB0ZXh0OiB0aGlzLnR0KCdvcGVuJyksXG4gICAgICBjb2xvcjogJ2RhcmsnLFxuICAgICAgZmlsbDogJ2NsZWFyJyxcbiAgICAgIHNpemU6ICdzbWFsbCcsXG4gICAgICBzaGFwZTogJ3JvdW5kJyxcbiAgICAgIHR5cGU6ICdidXR0b24nLFxuICAgICAgaWNvbjogeyBuYW1lOiAnb3Blbi1vdXRsaW5lJywgc2xvdDogJ2VuZCcgfSxcbiAgICB9O1xuICB9XG5cbiAgaXNFeHBhbmRlZChpZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2V4cGFuZGVkKCkuaGFzKGlkKTtcbiAgfVxuXG4gIHRvZ2dsZUV4cGFuZChpZDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgbmV4dCA9IG5ldyBTZXQodGhpcy5fZXhwYW5kZWQoKSk7XG4gICAgaWYgKG5leHQuaGFzKGlkKSkgbmV4dC5kZWxldGUoaWQpO1xuICAgIGVsc2UgbmV4dC5hZGQoaWQpO1xuICAgIHRoaXMuX2V4cGFuZGVkLnNldChuZXh0KTtcbiAgfVxuXG4gIGlzTG9uZyhib2R5OiBzdHJpbmcgfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBpZiAoIWJvZHkpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gYm9keS5sZW5ndGggPiAxMTAgfHwgYm9keS5pbmNsdWRlcygnXFxuJyk7XG4gIH1cblxuICAvKipcbiAgICogSWNvbiByZXNvbHZlciBjb24gb3JkZW4gZGUgZmFsbGJhY2s6XG4gICAqIDEuIG5vdGlmLnBheWxvYWQuaWNvbiAoZm9yd2FyZC1jb21wYXQsIHNpbiBicmVha2luZyBjaGFuZ2UgZW4gc2NoZW1hKVxuICAgKiAyLiBtYXBhIHBvciBub3RpZi50eXBlXG4gICAqIDMuIGRlZmF1bHQgbm90aWZpY2F0aW9ucy1vdXRsaW5lXG4gICAqL1xuICByZXNvbHZlSWNvbihuOiBOb3RpZmljYXRpb25Eb2N1bWVudCk6IFJlc29sdmVkSWNvbiB7XG4gICAgY29uc3QgaGludCA9IG4ucGF5bG9hZD8uWydpY29uJ10gYXMgSWNvbkhpbnQgfCB1bmRlZmluZWQ7XG4gICAgaWYgKGhpbnQ/LnZhbHVlKSB7XG4gICAgICBpZiAoaGludC50eXBlID09PSAnaW1hZ2UnIHx8IGhpbnQudHlwZSA9PT0gJ2F2YXRhcicpIHtcbiAgICAgICAgcmV0dXJuIHsga2luZDogaGludC50eXBlLCBzcmM6IGhpbnQudmFsdWUgfTtcbiAgICAgIH1cbiAgICAgIC8vIElnbm9yYW1vcyBoaW50LmNvbG9yIOKAlCB0b2RvcyBsb3MgaWNvbm9zIHZhbiBlbiBkYXJrIHBvciBjb252ZW5jacOzbiBVWC5cbiAgICAgIHJldHVybiB7IGtpbmQ6ICdpb25pY29uJywgbmFtZTogaGludC52YWx1ZSwgY29sb3I6ICdkYXJrJyB9O1xuICAgIH1cbiAgICBjb25zdCB0ID0gbi50eXBlO1xuICAgIGNvbnN0IG5hbWUgPSAoKCkgPT4ge1xuICAgICAgc3dpdGNoICh0KSB7XG4gICAgICAgIGNhc2UgJ2FwcHJvdmFsJzpcbiAgICAgICAgICByZXR1cm4gJ2NoZWNrbWFyay1jaXJjbGUtb3V0bGluZSc7XG4gICAgICAgIGNhc2UgJ2NoYXQnOlxuICAgICAgICBjYXNlICdjaGF0Ym90JzpcbiAgICAgICAgICByZXR1cm4gJ2NoYXRidWJibGUtb3V0bGluZSc7XG4gICAgICAgIGNhc2UgJ2NvbW1lbnQnOlxuICAgICAgICAgIHJldHVybiAnY2hhdGJveC1lbGxpcHNlcy1vdXRsaW5lJztcbiAgICAgICAgY2FzZSAncmVtaW5kZXInOlxuICAgICAgICAgIHJldHVybiAnYWxhcm0tb3V0bGluZSc7XG4gICAgICAgIGNhc2UgJ3N5c3RlbSc6XG4gICAgICAgICAgcmV0dXJuICdjb2ctb3V0bGluZSc7XG4gICAgICAgIGNhc2UgJ3VzZXInOlxuICAgICAgICBjYXNlICdtZW50aW9uJzpcbiAgICAgICAgICByZXR1cm4gJ3BlcnNvbi1vdXRsaW5lJztcbiAgICAgICAgY2FzZSAnZG9jdW1lbnQnOlxuICAgICAgICAgIHJldHVybiAnZG9jdW1lbnQtdGV4dC1vdXRsaW5lJztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gJ25vdGlmaWNhdGlvbnMtb3V0bGluZSc7XG4gICAgICB9XG4gICAgfSkoKTtcbiAgICByZXR1cm4geyBraW5kOiAnaW9uaWNvbicsIG5hbWUsIGNvbG9yOiAnZGFyaycgfTtcbiAgfVxuXG4gIGlvbmljb25OYW1lKG46IE5vdGlmaWNhdGlvbkRvY3VtZW50KTogc3RyaW5nIHtcbiAgICBjb25zdCByID0gdGhpcy5yZXNvbHZlSWNvbihuKTtcbiAgICByZXR1cm4gci5raW5kID09PSAnaW9uaWNvbicgPyByLm5hbWUgOiAnJztcbiAgfVxuXG4gIGlvbmljb25Db2xvcihuOiBOb3RpZmljYXRpb25Eb2N1bWVudCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgciA9IHRoaXMucmVzb2x2ZUljb24obik7XG4gICAgcmV0dXJuIHIua2luZCA9PT0gJ2lvbmljb24nID8gci5jb2xvciA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGltYWdlU3JjKG46IE5vdGlmaWNhdGlvbkRvY3VtZW50KTogc3RyaW5nIHtcbiAgICBjb25zdCByID0gdGhpcy5yZXNvbHZlSWNvbihuKTtcbiAgICByZXR1cm4gci5raW5kID09PSAnaW1hZ2UnIHx8IHIua2luZCA9PT0gJ2F2YXRhcicgPyByLnNyYyA6ICcnO1xuICB9XG5cbiAgaW9uQ29sb3IodG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gICAgaWYgKCF0b2tlbikgcmV0dXJuICd2YXIoLS1pb24tY29sb3ItcHJpbWFyeSknO1xuICAgIHJldHVybiBgdmFyKC0taW9uLWNvbG9yLSR7dG9rZW59KWA7XG4gIH1cblxuICByZWxhdGl2ZVRpbWUobjogTm90aWZpY2F0aW9uRG9jdW1lbnQpOiBzdHJpbmcge1xuICAgIGNvbnN0IGQgPSBuLmNyZWF0ZWRBdCBpbnN0YW5jZW9mIERhdGUgPyBuLmNyZWF0ZWRBdCA6IG51bGw7XG4gICAgaWYgKCFkKSByZXR1cm4gJyc7XG4gICAgY29uc3QgZGlmZk1zID0gRGF0ZS5ub3coKSAtIGQuZ2V0VGltZSgpO1xuICAgIGNvbnN0IG1pbiA9IE1hdGguZmxvb3IoZGlmZk1zIC8gNjAwMDApO1xuICAgIGlmIChtaW4gPCAxKSByZXR1cm4gdGhpcy50dCgndGltZU5vdycpO1xuICAgIGlmIChtaW4gPCA2MCkgcmV0dXJuIHRoaXMudHQoJ3RpbWVNaW51dGVzJykucmVwbGFjZSgne259JywgU3RyaW5nKG1pbikpO1xuICAgIGNvbnN0IGggPSBNYXRoLmZsb29yKG1pbiAvIDYwKTtcbiAgICBpZiAoaCA8IDI0KSByZXR1cm4gdGhpcy50dCgndGltZUhvdXJzJykucmVwbGFjZSgne259JywgU3RyaW5nKGgpKTtcbiAgICBjb25zdCBkYXlzID0gTWF0aC5mbG9vcihoIC8gMjQpO1xuICAgIHJldHVybiB0aGlzLnR0KCd0aW1lRGF5cycpLnJlcGxhY2UoJ3tufScsIFN0cmluZyhkYXlzKSk7XG4gIH1cblxuICAvKiogRGV2dWVsdmUgbGFiZWwgXCJEZXNkZSB7YXBwTmFtZX1cIiBzaSBsYSBub3RpZiB2aWVuZSBkZSBvdHJhIGFwcCwgc2lubyBudWxsLiAqL1xuICBzaG93Q3Jvc3NBcHBCYWRnZShuOiBOb3RpZmljYXRpb25Eb2N1bWVudCk6IHN0cmluZyB8IG51bGwge1xuICAgIGNvbnN0IGN1cnJlbnRBcHAgPSAnc2hvd2Nhc2UnO1xuICAgIGlmICghbi5hcHBJZCB8fCBuLmFwcElkID09PSBjdXJyZW50QXBwKSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gdGhpcy50dCgnY3Jvc3NBcHAnKS5yZXBsYWNlKCd7YXBwfScsIG4uYXBwSWQpO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIEFjdGlvbnNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgYXN5bmMgb25PcGVuKG46IE5vdGlmaWNhdGlvbkRvY3VtZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuYWN0aW9uLm9wZW4obik7XG4gICAgICB0aGlzLnJlc29sdmVkQ29uZmlnKCkub25Ob3RpZmljYXRpb25PcGVuPy4obiwgcmVzdWx0KTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMuZXJyb3JzLmhhbmRsZShlcnIsIHtcbiAgICAgICAgY29udGV4dDogJ25vdGlmaWNhdGlvbnMub3BlbicsXG4gICAgICAgIGZhbGxiYWNrS2V5OiAnb3BlbkVycm9yJyxcbiAgICAgICAgaTE4bk5hbWVzcGFjZTogdGhpcy5ucyxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIG9uTWFya0FsbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5fYnVsa0J1c3koKSkgcmV0dXJuO1xuICAgIHRoaXMuX2J1bGtCdXN5LnNldCh0cnVlKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5ub3RpZnMubWFya0FsbEFzUmVhZCgpO1xuICAgICAgdGhpcy50b2FzdC5zaG93KHtcbiAgICAgICAgbWVzc2FnZTogdGhpcy50dCgnbWFya2VkQWxsU3VjY2VzcycpLFxuICAgICAgICBjb2xvcjogJ2RhcmsnLFxuICAgICAgICBkdXJhdGlvbjogMjUwMCxcbiAgICAgICAgcG9zaXRpb246ICd0b3AnLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmVycm9ycy5oYW5kbGUoZXJyLCB7XG4gICAgICAgIGNvbnRleHQ6ICdub3RpZmljYXRpb25zLm1hcmtBbGwnLFxuICAgICAgICBmYWxsYmFja0tleTogJ21hcmtlZEFsbEVycm9yJyxcbiAgICAgICAgaTE4bk5hbWVzcGFjZTogdGhpcy5ucyxcbiAgICAgIH0pO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLl9idWxrQnVzeS5zZXQoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIG9uTG9hZE1vcmUoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuX2xvYWRpbmdNb3JlKCkpIHJldHVybjtcbiAgICB0aGlzLl9sb2FkaW5nTW9yZS5zZXQodHJ1ZSk7XG4gICAgLy8gU2xpY2UgdmllbmUgZGVsIGNhY2hlIGxvY2FsIOKAlCBubyBoYXkgZmV0Y2ggcmVhbCwgcGVybyB1biBicmV2ZSBzcGlubmVyXG4gICAgLy8gY29uZmlybWEgYWwgdXNlciBxdWUgZWwgY2xpY2sgcmVnaXN0csOzIHkgc3Vhdml6YSBsYSBhcGFyaWNpw7NuIGRlIGl0ZW1zLlxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5fcGFnZVNpemUudXBkYXRlKG4gPT4gbiArIHRoaXMucGFnZVN0ZXApO1xuICAgICAgdGhpcy5fbG9hZGluZ01vcmUuc2V0KGZhbHNlKTtcbiAgICB9LCAyNTApO1xuICB9XG5cbiAgb25Hb1RvU2V0dGluZ3MoKTogdm9pZCB7XG4gICAgdGhpcy5uYXYubmF2aWdhdGVCeVVybCh0aGlzLnJlc29sdmVkQ29uZmlnKCkuc2V0dGluZ3NOb3RpZmljYXRpb25zUGF0aCk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gR3JvdXBpbmcgaGVscGVyc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBwcml2YXRlIGJ1Y2tldE9mKG46IE5vdGlmaWNhdGlvbkRvY3VtZW50LCBub3c6IERhdGUpOiBHcm91cEtleSB7XG4gICAgY29uc3QgZCA9IG4uY3JlYXRlZEF0IGluc3RhbmNlb2YgRGF0ZSA/IG4uY3JlYXRlZEF0IDogbnVsbDtcbiAgICBpZiAoIWQpIHJldHVybiAnZWFybGllcic7XG4gICAgaWYgKGQuZ2V0RnVsbFllYXIoKSA9PT0gbm93LmdldEZ1bGxZZWFyKCkgJiYgZC5nZXRNb250aCgpID09PSBub3cuZ2V0TW9udGgoKSAmJiBkLmdldERhdGUoKSA9PT0gbm93LmdldERhdGUoKSkge1xuICAgICAgcmV0dXJuICd0b2RheSc7XG4gICAgfVxuICAgIGlmIChkLmdldEZ1bGxZZWFyKCkgPT09IG5vdy5nZXRGdWxsWWVhcigpICYmIGQuZ2V0TW9udGgoKSA9PT0gbm93LmdldE1vbnRoKCkpIHtcbiAgICAgIHJldHVybiAndGhpc01vbnRoJztcbiAgICB9XG4gICAgcmV0dXJuICdlYXJsaWVyJztcbiAgfVxuXG4gIHByaXZhdGUgdHQoa2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmkxOG4udChrZXksIHRoaXMubnMpO1xuICB9XG59XG4iXX0=