valtech-components 2.0.996 → 2.0.997

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/esm2022/lib/components/organisms/notification-preferences-view/notification-preferences-view.component.mjs +667 -0
  2. package/esm2022/lib/components/organisms/notification-preferences-view/notification-preferences-view.i18n.mjs +71 -0
  3. package/esm2022/lib/components/organisms/notification-preferences-view/notification-preferences.routes.mjs +31 -0
  4. package/esm2022/lib/components/organisms/notification-preferences-view/types.mjs +2 -0
  5. package/esm2022/lib/components/organisms/organization-view/organization-view.component.mjs +1 -76
  6. package/esm2022/lib/components/organisms/organization-view/organization-view.i18n.mjs +1 -5
  7. package/esm2022/lib/components/organisms/permissions-view/permissions-view.component.mjs +511 -0
  8. package/esm2022/lib/components/organisms/permissions-view/permissions-view.i18n.mjs +116 -0
  9. package/esm2022/lib/components/organisms/permissions-view/permissions.routes.mjs +29 -0
  10. package/esm2022/lib/components/organisms/permissions-view/types.mjs +2 -0
  11. package/esm2022/lib/components/organisms/settings-hub/settings.routes.mjs +12 -1
  12. package/esm2022/lib/services/auth/auth.service.mjs +1 -14
  13. package/esm2022/lib/services/auth/types.mjs +1 -1
  14. package/esm2022/lib/services/org/org.service.mjs +1 -8
  15. package/esm2022/lib/services/org/permission-catalog.service.mjs +33 -0
  16. package/esm2022/lib/services/org/types.mjs +1 -1
  17. package/esm2022/lib/version.mjs +2 -2
  18. package/esm2022/public-api.mjs +8 -4
  19. package/fesm2022/valtech-components.mjs +1484 -1003
  20. package/fesm2022/valtech-components.mjs.map +1 -1
  21. package/lib/components/organisms/notification-preferences-view/notification-preferences-view.component.d.ts +146 -0
  22. package/lib/components/organisms/notification-preferences-view/notification-preferences-view.i18n.d.ts +11 -0
  23. package/lib/components/organisms/notification-preferences-view/notification-preferences.routes.d.ts +26 -0
  24. package/lib/components/organisms/notification-preferences-view/types.d.ts +36 -0
  25. package/lib/components/organisms/organization-view/organization-view.component.d.ts +0 -5
  26. package/lib/components/organisms/permissions-view/permissions-view.component.d.ts +71 -0
  27. package/lib/components/organisms/permissions-view/permissions-view.i18n.d.ts +9 -0
  28. package/lib/components/organisms/permissions-view/permissions.routes.d.ts +24 -0
  29. package/lib/components/organisms/permissions-view/types.d.ts +26 -0
  30. package/lib/components/organisms/settings-hub/settings.routes.d.ts +15 -0
  31. package/lib/services/auth/auth.service.d.ts +1 -7
  32. package/lib/services/auth/types.d.ts +0 -23
  33. package/lib/services/org/org.service.d.ts +1 -6
  34. package/lib/services/org/permission-catalog.service.d.ts +34 -0
  35. package/lib/services/org/types.d.ts +0 -30
  36. package/lib/version.d.ts +1 -1
  37. package/package.json +1 -1
  38. package/public-api.d.ts +8 -5
  39. package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.component.mjs +0 -385
  40. package/esm2022/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.mjs +0 -63
  41. package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.component.mjs +0 -313
  42. package/esm2022/lib/components/organisms/member-import-modal/member-import-modal.i18n.mjs +0 -63
  43. package/esm2022/lib/services/apikeys/api-keys.service.mjs +0 -46
  44. package/esm2022/lib/services/apikeys/types.mjs +0 -7
  45. package/lib/components/organisms/api-keys-modal/api-keys-modal.component.d.ts +0 -44
  46. package/lib/components/organisms/api-keys-modal/api-keys-modal.i18n.d.ts +0 -6
  47. package/lib/components/organisms/member-import-modal/member-import-modal.component.d.ts +0 -47
  48. package/lib/components/organisms/member-import-modal/member-import-modal.i18n.d.ts +0 -6
  49. package/lib/services/apikeys/api-keys.service.d.ts +0 -25
  50. package/lib/services/apikeys/types.d.ts +0 -46
@@ -0,0 +1,667 @@
1
+ import { Component, computed, effect, inject, Input, signal } from '@angular/core';
2
+ import { FormControl } from '@angular/forms';
3
+ import { ActivatedRoute } from '@angular/router';
4
+ import { IonIcon } from '@ionic/angular/standalone';
5
+ import { addIcons } from 'ionicons';
6
+ import { alertCircleOutline, chevronDownOutline, chevronUpOutline, closeCircleOutline, notificationsOffOutline, notificationsOutline, refreshOutline, } from 'ionicons/icons';
7
+ import { ButtonComponent } from '../../atoms/button/button.component';
8
+ import { DisplayComponent } from '../../atoms/display/display.component';
9
+ import { TextComponent } from '../../atoms/text/text.component';
10
+ import { TitleComponent } from '../../atoms/title/title.component';
11
+ import { ToggleInputComponent } from '../../molecules/toggle-input/toggle-input.component';
12
+ import { ComponentStates } from '../../types';
13
+ import { AuthService } from '../../../services/auth/auth.service';
14
+ import { MessagingService } from '../../../services/firebase/messaging.service';
15
+ import { I18nService } from '../../../services/i18n';
16
+ import { NavigationService } from '../../../services/navigation/navigation.service';
17
+ import { PageRefreshService } from '../../../services/page-refresh/page-refresh.service';
18
+ import { PreferencesService } from '../../../services/preferences/preferences.service';
19
+ import { ToastService } from '../../../services/toast.service';
20
+ import { NOTIFICATION_PREFERENCES_VIEW_I18N } from './notification-preferences-view.i18n';
21
+ import * as i0 from "@angular/core";
22
+ addIcons({
23
+ alertCircleOutline,
24
+ chevronDownOutline,
25
+ chevronUpOutline,
26
+ closeCircleOutline,
27
+ notificationsOffOutline,
28
+ notificationsOutline,
29
+ refreshOutline,
30
+ });
31
+ const DEFAULT_NAMESPACE = 'Settings.Notifications';
32
+ /**
33
+ * `val-notification-preferences-view` — **preferencias de notificaciones push**
34
+ * (FCM) full-feature autocontenida (organism). Promovida desde `showcase` bajo el
35
+ * proceso de ADR-021.
36
+ *
37
+ * Separada de `val-notifications-view` (el inbox / feed). Aquí el user **activa o
38
+ * desactiva** las notificaciones push en este dispositivo.
39
+ *
40
+ * UX simplificado: UN solo toggle que ejecuta toda la secuencia (pedir permiso →
41
+ * SW ready → getToken → registrar en backend → set master pref) vía
42
+ * `MessagingService.enable()`. El registro del device en el backend va como
43
+ * callback (la lib no depende de `AuthService` para evitar ciclos). Mensajes
44
+ * contextuales y botón "Reintentar" aparecen solo cuando aplican.
45
+ *
46
+ * NO renderiza ion-content — vive dentro de val-page-wrapper. `ActivatedRoute` se
47
+ * inyecta `{ optional: true }` → funciona sin router (embebida / Storybook).
48
+ */
49
+ export class NotificationPreferencesViewComponent {
50
+ /** Namespace i18n resuelto (capturado para llamadas no-reactivas). */
51
+ get ns() {
52
+ return this.resolvedConfig().i18nNamespace;
53
+ }
54
+ // ---------------------------------------------------------------------------
55
+ // Lifecycle
56
+ // ---------------------------------------------------------------------------
57
+ constructor() {
58
+ this.nav = inject(NavigationService);
59
+ this.i18n = inject(I18nService);
60
+ this.toast = inject(ToastService);
61
+ this.auth = inject(AuthService);
62
+ this.messaging = inject(MessagingService);
63
+ this.pageRefresh = inject(PageRefreshService);
64
+ this.prefs = inject(PreferencesService);
65
+ // `ActivatedRoute` opcional → la vista funciona embebida / en Storybook sin
66
+ // router (solo lo usa para leer el route data de config como fallback).
67
+ this.route = inject(ActivatedRoute, { optional: true });
68
+ this.resolvedConfig = computed(() => {
69
+ const fromRoute = (this.route?.snapshot.data['notificationPreferencesConfig'] ??
70
+ {});
71
+ const merged = { ...fromRoute, ...(this.config ?? {}) };
72
+ return {
73
+ showDetails: merged.showDetails ?? true,
74
+ i18nNamespace: merged.i18nNamespace ?? DEFAULT_NAMESPACE,
75
+ onPushEnabled: merged.onPushEnabled,
76
+ onPushDisabled: merged.onPushDisabled,
77
+ };
78
+ });
79
+ /** Operación en curso (gobierna spinner del toggle + label "Activando…"). */
80
+ this._busy = signal(null);
81
+ /** True si el último intento falló — gobierna estado `error` + retry button. */
82
+ this._lastFailed = signal(false);
83
+ /** True mientras se re-obtiene el token FCM en background (no afecta la UI). */
84
+ this._repairingToken = false;
85
+ /** Toggle del expand de detalles técnicos. */
86
+ this.showDetails = signal(false);
87
+ this.permission = signal('default');
88
+ this.isSupported = signal(false);
89
+ this.currentToken = signal(null);
90
+ this.needsIOSInstall = signal(this.detectNeedsIOSInstall());
91
+ /** FormControl del toggle (sync-eado con `isEnabled` via effect). */
92
+ this.toggleControl = new FormControl(false, {
93
+ nonNullable: true,
94
+ });
95
+ /** Handler del listener `focus` — referencia guardada para poder removerlo. */
96
+ this.onWindowFocus = () => this.scheduleBrowserRefresh();
97
+ /** Timer del debounce del refresh disparado por `focus`. */
98
+ this.focusDebounceTimer = null;
99
+ /** Ventana de debounce (ms) para el refresh disparado por `focus`. */
100
+ this.FOCUS_DEBOUNCE_MS = 500;
101
+ // ---------------------------------------------------------------------------
102
+ // Estado derivado
103
+ // ---------------------------------------------------------------------------
104
+ this.pageTitle = computed(() => this.tt('pageTitle'));
105
+ this.pageDescription = computed(() => this.tt('pageDescription'));
106
+ /**
107
+ * Estado efectivo del toggle: "el usuario tiene push activo".
108
+ *
109
+ * Se deriva SOLO de la decisión del usuario (`master`) y del permiso del SO
110
+ * (`permission`). El token FCM NO forma parte del estado de UI: vive en
111
+ * memoria, se pierde en cada recarga/suspensión de la PWA y produciría flicker.
112
+ * Si falta token con `master && granted`, es un detalle reparable en
113
+ * background (ver `repairTokenIfNeeded`), no un cambio del toggle.
114
+ */
115
+ this.isEnabled = computed(() => this.prefs.notificationsMaster() && this.permission() === 'granted');
116
+ this.state = computed(() => {
117
+ if (this.needsIOSInstall())
118
+ return 'needs-install';
119
+ if (this.permission() === 'unsupported' || !this.isSupported()) {
120
+ // iOS standalone aún puede dar isSupported false temprano antes de init —
121
+ // solo bloqueamos si el browser explícitamente no soporta APIs.
122
+ if (this.permission() === 'unsupported')
123
+ return 'unsupported';
124
+ }
125
+ const busy = this._busy();
126
+ if (busy === 'enabling')
127
+ return 'enabling';
128
+ if (busy === 'disabling')
129
+ return 'disabling';
130
+ if (this.isEnabled())
131
+ return 'enabled';
132
+ if (this.permission() === 'denied')
133
+ return 'blocked';
134
+ if (this._lastFailed())
135
+ return 'error';
136
+ return 'idle';
137
+ });
138
+ this.busyLabel = computed(() => {
139
+ const s = this.state();
140
+ if (s === 'enabling')
141
+ return this.tt('enabling');
142
+ if (s === 'disabling')
143
+ return this.tt('disabling');
144
+ return null;
145
+ });
146
+ this.contextMessage = computed(() => {
147
+ switch (this.state()) {
148
+ case 'unsupported':
149
+ return this.tt('permissionUnsupported');
150
+ case 'blocked':
151
+ return this.tt('permissionDeniedInfo');
152
+ case 'error':
153
+ return this.tt('errorGeneric');
154
+ default:
155
+ return null;
156
+ }
157
+ });
158
+ this.alertVariant = computed(() => {
159
+ const s = this.state();
160
+ if (s === 'error' || s === 'blocked')
161
+ return 'warning';
162
+ if (s === 'unsupported')
163
+ return 'danger';
164
+ return 'info';
165
+ });
166
+ this.alertIcon = computed(() => {
167
+ const s = this.state();
168
+ if (s === 'unsupported')
169
+ return 'close-circle-outline';
170
+ return 'alert-circle-outline';
171
+ });
172
+ this.toggleProps = computed(() => ({
173
+ control: this.toggleControl,
174
+ color: 'primary',
175
+ disabled: this._busy() !== null ||
176
+ this.state() === 'unsupported' ||
177
+ this.state() === 'needs-install' ||
178
+ this.state() === 'blocked',
179
+ }));
180
+ this.retryButtonProps = computed(() => ({
181
+ text: this.tt('retryCta'),
182
+ color: 'dark',
183
+ fill: 'outline',
184
+ size: 'default',
185
+ shape: 'round',
186
+ type: 'button',
187
+ icon: { name: 'refresh-outline', slot: 'start' },
188
+ state: this._busy() !== null ? ComponentStates.WORKING : ComponentStates.ENABLED,
189
+ }));
190
+ this.tokenPreview = computed(() => {
191
+ const t = this.currentToken();
192
+ if (!t)
193
+ return null;
194
+ return `${t.slice(0, 22)}…${t.slice(-6)}`;
195
+ });
196
+ const ns = this.ns;
197
+ if (!this.i18n.hasNamespace(ns)) {
198
+ this.i18n.registerContent(ns, NOTIFICATION_PREFERENCES_VIEW_I18N);
199
+ }
200
+ this.nav.setBackHeader('pageTitle', ns, { withMenu: true });
201
+ void this.refreshBrowserState();
202
+ // Re-aplicar header en cambio de idioma.
203
+ effect(() => {
204
+ this.i18n.lang();
205
+ this.nav.setBackHeader('pageTitle', this.ns, { withMenu: true });
206
+ }, { allowSignalWrites: true });
207
+ // Sync FormControl ←→ estado efectivo. Cuando el estado cambia (cambio de
208
+ // permission por el browser, o snapshot Firestore de `master`), el toggle se
209
+ // re-alinea con la realidad.
210
+ //
211
+ // IMPORTANTE: se ignoran los cambios mientras hay una operación en curso
212
+ // (`_busy() !== null`). Durante `onEnable`/`onDisable` las señales fuente se
213
+ // actualizan en momentos distintos y producirían estados intermedios →
214
+ // flicker visible. El toggle se re-alinea UNA sola vez en el `finally`.
215
+ effect(() => {
216
+ const eff = this.isEnabled();
217
+ if (this._busy() !== null)
218
+ return;
219
+ if (this.toggleControl.value !== eff) {
220
+ this.toggleControl.setValue(eff, { emitEvent: false });
221
+ }
222
+ }, { allowSignalWrites: true });
223
+ // Interceptar click del user: el toggle ya cambió visualmente, ejecutar
224
+ // la acción correspondiente.
225
+ this.toggleControl.valueChanges.subscribe(v => {
226
+ if (this._busy() !== null)
227
+ return;
228
+ if (v && !this.isEnabled()) {
229
+ void this.onEnable();
230
+ }
231
+ else if (!v && this.isEnabled()) {
232
+ void this.onDisable();
233
+ }
234
+ });
235
+ // Detectar regreso a la pestaña — el user pudo haber cambiado permisos
236
+ // desde la config del browser. El refresh va con debounce para no
237
+ // dispararse en ráfagas (en PWA mobile `focus` salta con cada cambio de
238
+ // app / aparición del teclado). El listener se remueve en ngOnDestroy.
239
+ if (typeof window !== 'undefined') {
240
+ window.addEventListener('focus', this.onWindowFocus);
241
+ }
242
+ }
243
+ /**
244
+ * Registra el pull-to-refresh estándar. Aunque esta vista no muestra una
245
+ * lista remota, sí refleja estado mutable del browser (permiso, token,
246
+ * soporte FCM) que puede cambiar fuera de la app — el refresh re-evalúa todo.
247
+ *
248
+ * Se usa `ngOnInit`/`ngOnDestroy` (NO `ionViewWillEnter`) porque
249
+ * `val-page-wrapper` usa `<router-outlet>` plano — los hooks `ionView*` solo
250
+ * disparan dentro de `<ion-router-outlet>`.
251
+ */
252
+ ngOnInit() {
253
+ this.pageRefresh.register(() => this.refreshBrowserState());
254
+ }
255
+ ngOnDestroy() {
256
+ this.pageRefresh.unregister();
257
+ if (typeof window !== 'undefined') {
258
+ window.removeEventListener('focus', this.onWindowFocus);
259
+ }
260
+ if (this.focusDebounceTimer !== null) {
261
+ clearTimeout(this.focusDebounceTimer);
262
+ this.focusDebounceTimer = null;
263
+ }
264
+ }
265
+ /** Refresca el estado del browser con debounce — evita ráfagas de `focus`. */
266
+ scheduleBrowserRefresh() {
267
+ if (this.focusDebounceTimer !== null) {
268
+ clearTimeout(this.focusDebounceTimer);
269
+ }
270
+ this.focusDebounceTimer = setTimeout(() => {
271
+ this.focusDebounceTimer = null;
272
+ void this.refreshBrowserState();
273
+ }, this.FOCUS_DEBOUNCE_MS);
274
+ }
275
+ // ---------------------------------------------------------------------------
276
+ // Actions
277
+ // ---------------------------------------------------------------------------
278
+ /**
279
+ * Secuencia completa de activación.
280
+ *
281
+ * Toda la mecánica (permission → SW ready → getToken con retry → watchdog de
282
+ * auto-reload) vive en `MessagingService.enable()` de la lib. El paso de
283
+ * registro del device en el backend se pasa como callback (`registerDevice`)
284
+ * porque la lib no puede depender de `AuthService` sin crear un ciclo.
285
+ *
286
+ * `enable()` no hace throw: resuelve con un `EnablePushResult` descriptivo.
287
+ */
288
+ async onEnable() {
289
+ this._busy.set('enabling');
290
+ this._lastFailed.set(false);
291
+ try {
292
+ const result = await this.messaging.enable({
293
+ registerDevice: token => this.auth.registerDevice(token).then(r => r.registered),
294
+ });
295
+ if (result.status === 'enabled') {
296
+ // Persistir flag master si aún no estaba activo.
297
+ if (!this.prefs.notificationsMaster()) {
298
+ await this.prefs.setNotificationsMaster(true);
299
+ }
300
+ this.toast.show({
301
+ message: this.tt('enableSuccess'),
302
+ duration: 2000,
303
+ color: 'dark',
304
+ position: 'top',
305
+ });
306
+ this.resolvedConfig().onPushEnabled?.();
307
+ }
308
+ else if (result.status === 'timeout' && result.reloaded) {
309
+ // La lib disparó el auto-reload — la página está por recargarse.
310
+ return;
311
+ }
312
+ else {
313
+ // denied / unsupported / error / timeout sin reload → fallo recuperable.
314
+ this._lastFailed.set(true);
315
+ this.toast.show({
316
+ message: this.tt('errorGeneric'),
317
+ duration: 3000,
318
+ color: 'dark',
319
+ position: 'top',
320
+ });
321
+ }
322
+ }
323
+ catch {
324
+ // `enable()` no hace throw, pero el callback de registro sí puede.
325
+ this._lastFailed.set(true);
326
+ this.toast.show({
327
+ message: this.tt('errorGeneric'),
328
+ duration: 3000,
329
+ color: 'dark',
330
+ position: 'top',
331
+ });
332
+ }
333
+ finally {
334
+ // Único refresh final: re-alinea el toggle UNA sola vez con el estado real.
335
+ await this.refreshBrowserState();
336
+ this._busy.set(null);
337
+ }
338
+ }
339
+ async onDisable() {
340
+ this._busy.set('disabling');
341
+ this._lastFailed.set(false);
342
+ try {
343
+ await this.auth.disableNotifications();
344
+ if (this.prefs.notificationsMaster()) {
345
+ await this.prefs.setNotificationsMaster(false);
346
+ }
347
+ this.toast.show({
348
+ message: this.tt('disableSuccess'),
349
+ duration: 2000,
350
+ color: 'dark',
351
+ position: 'top',
352
+ });
353
+ this.resolvedConfig().onPushDisabled?.();
354
+ }
355
+ catch {
356
+ this._lastFailed.set(true);
357
+ }
358
+ finally {
359
+ await this.refreshBrowserState();
360
+ this._busy.set(null);
361
+ }
362
+ }
363
+ /** Reintentar la secuencia completa de activación, sin importar el estado actual. */
364
+ async onRetry() {
365
+ this._lastFailed.set(false);
366
+ await this.onEnable();
367
+ }
368
+ toggleDetails() {
369
+ this.showDetails.update(v => !v);
370
+ }
371
+ // ---------------------------------------------------------------------------
372
+ // Privados
373
+ // ---------------------------------------------------------------------------
374
+ async refreshBrowserState() {
375
+ this.isSupported.set(await this.messaging.isSupported());
376
+ this.permission.set(this.auth.getNotificationPermissionState());
377
+ this.currentToken.set(this.messaging.currentToken ?? null);
378
+ void this.repairTokenIfNeeded();
379
+ }
380
+ /**
381
+ * Repara el token FCM en background.
382
+ *
383
+ * Si el usuario tiene push activo (`master && granted`) pero no hay token en
384
+ * memoria — caso típico tras un cold start de la PWA — re-obtenemos el token
385
+ * y re-registramos el device sin tocar el toggle ni mostrar un error
386
+ * alarmista. El token es un detalle de implementación reparable, no parte del
387
+ * estado de UI (ver `isEnabled`).
388
+ */
389
+ async repairTokenIfNeeded() {
390
+ if (this._busy() !== null)
391
+ return;
392
+ if (this._repairingToken)
393
+ return;
394
+ if (!this.isEnabled())
395
+ return;
396
+ if (this.currentToken())
397
+ return;
398
+ this._repairingToken = true;
399
+ try {
400
+ const token = await this.messaging.getToken();
401
+ if (token) {
402
+ this.currentToken.set(token);
403
+ await this.auth.registerDevice(token);
404
+ }
405
+ }
406
+ catch {
407
+ // Reparación best-effort: no degradamos el toggle ni mostramos error.
408
+ }
409
+ finally {
410
+ this._repairingToken = false;
411
+ }
412
+ }
413
+ /**
414
+ * iOS browser sin estar instalado como PWA — push web no disponible.
415
+ * Aplica a Safari y a Edge/Chrome/Firefox en iOS (todos WebKit por mandato Apple).
416
+ */
417
+ detectNeedsIOSInstall() {
418
+ if (typeof window === 'undefined' || typeof navigator === 'undefined') {
419
+ return false;
420
+ }
421
+ const ua = navigator.userAgent || '';
422
+ const isIOS = /iPad|iPhone|iPod/.test(ua);
423
+ if (!isIOS)
424
+ return false;
425
+ const isStandalone = window.matchMedia?.('(display-mode: standalone)').matches ||
426
+ navigator.standalone === true;
427
+ return !isStandalone;
428
+ }
429
+ tt(key) {
430
+ return this.i18n.t(key, this.ns);
431
+ }
432
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationPreferencesViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
433
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: NotificationPreferencesViewComponent, isStandalone: true, selector: "val-notification-preferences-view", inputs: { config: "config" }, ngImport: i0, template: `
434
+ <div class="page">
435
+ <header class="page-header">
436
+ <val-display [props]="{ size: 'small', color: 'dark', content: pageTitle() }" />
437
+ <val-title
438
+ [props]="{
439
+ size: 'large',
440
+ color: 'dark',
441
+ bold: false,
442
+ content: pageDescription(),
443
+ }"
444
+ />
445
+ </header>
446
+
447
+ @if (state() === 'needs-install') {
448
+ <section class="settings-section">
449
+ <val-title
450
+ [props]="{
451
+ size: 'medium',
452
+ color: 'dark',
453
+ bold: true,
454
+ content: tt('iosInstallTitle'),
455
+ }"
456
+ />
457
+ <div class="section-body">
458
+ <val-text
459
+ [props]="{
460
+ size: 'small',
461
+ color: 'medium',
462
+ bold: false,
463
+ content: tt('iosInstallHint'),
464
+ }"
465
+ />
466
+ <ol class="install-steps">
467
+ <li>{{ tt('iosInstallStep1') }}</li>
468
+ <li>{{ tt('iosInstallStep2') }}</li>
469
+ <li>{{ tt('iosInstallStep3') }}</li>
470
+ <li>{{ tt('iosInstallStep4') }}</li>
471
+ </ol>
472
+ </div>
473
+ </section>
474
+ }
475
+
476
+ <section class="settings-section">
477
+ <div class="notif-row">
478
+ <div class="notif-row__icon">
479
+ <ion-icon name="notifications-outline" aria-hidden="true" />
480
+ </div>
481
+ <div class="notif-row__body">
482
+ <val-title
483
+ [props]="{
484
+ size: 'medium',
485
+ color: 'dark',
486
+ bold: true,
487
+ content: tt('simpleTitle'),
488
+ }"
489
+ />
490
+ <val-text
491
+ [props]="{
492
+ size: 'small',
493
+ color: 'medium',
494
+ bold: false,
495
+ content: tt('simpleDescription'),
496
+ }"
497
+ />
498
+ @if (busyLabel(); as label) {
499
+ <span class="notif-row__busy">{{ label }}</span>
500
+ }
501
+ </div>
502
+ <div class="notif-row__control">
503
+ <val-toggle-input [props]="toggleProps()" />
504
+ </div>
505
+ </div>
506
+
507
+ @if (contextMessage(); as msg) {
508
+ <div class="alert" [class]="'alert--' + alertVariant()">
509
+ <ion-icon [name]="alertIcon()" aria-hidden="true" />
510
+ <span>{{ msg }}</span>
511
+ </div>
512
+ }
513
+
514
+ @if (state() === 'error') {
515
+ <div class="row-actions">
516
+ <val-button [props]="retryButtonProps()" (click)="onRetry()" />
517
+ </div>
518
+ }
519
+ </section>
520
+
521
+ @if (resolvedConfig().showDetails && state() !== 'needs-install' && state() !== 'unsupported') {
522
+ <section class="settings-section">
523
+ <button class="details-toggle" type="button" (click)="toggleDetails()">
524
+ <span>{{ showDetails() ? tt('detailsHide') : tt('detailsShow') }}</span>
525
+ <ion-icon [name]="showDetails() ? 'chevron-up-outline' : 'chevron-down-outline'" aria-hidden="true" />
526
+ </button>
527
+ @if (showDetails()) {
528
+ <dl class="details">
529
+ <div class="details__row">
530
+ <dt>{{ tt('detailsToken') }}</dt>
531
+ <dd>{{ tokenPreview() ?? tt('detailsNone') }}</dd>
532
+ </div>
533
+ <div class="details__row">
534
+ <dt>{{ tt('diagnosticsPermission') }}</dt>
535
+ <dd>{{ permission() }}</dd>
536
+ </div>
537
+ <div class="details__row">
538
+ <dt>{{ tt('diagnosticsSupported') }}</dt>
539
+ <dd>{{ isSupported() ? '✓' : '✗' }}</dd>
540
+ </div>
541
+ </dl>
542
+ }
543
+ </section>
544
+ }
545
+ </div>
546
+ `, isInline: true, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:8px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-body{margin-top:16px;display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.notif-row{display:grid;grid-template-columns:44px 1fr auto;gap:16px;align-items:center}.notif-row__icon{width:44px;height:44px;border-radius:50%;background:var(--ion-color-light, rgba(0, 0, 0, .06));display:flex;align-items:center;justify-content:center}.notif-row__icon ion-icon{font-size:22px;color:var(--ion-color-dark, #1a1a1a)}.notif-row__body{display:flex;flex-direction:column;gap:4px;min-width:0}.notif-row__busy{font-size:12px;color:var(--ion-color-medium, #92949c);font-style:italic;margin-top:4px}.notif-row__control{flex-shrink:0}.alert{display:flex;gap:10px;align-items:flex-start;margin-top:12px;padding:12px 14px;border-radius:10px;font-size:13px;line-height:1.45;background:var(--ion-color-light, rgba(0, 0, 0, .04));color:var(--ion-color-dark, #1a1a1a)}.alert ion-icon{font-size:18px;flex-shrink:0;margin-top:1px}.alert--warning ion-icon{color:var(--ion-color-warning-shade, #c79e08)}.alert--danger ion-icon{color:var(--ion-color-danger-shade, #cf3c4f)}.alert--info ion-icon{color:var(--ion-color-medium, #6b6b6b)}.install-steps{margin:0;padding-left:20px;font-size:13px;line-height:1.6;color:var(--ion-color-dark, #1a1a1a)}.install-steps li+li{margin-top:4px}.details-toggle{display:flex;align-items:center;gap:6px;background:none;border:0;padding:0;font-size:13px;color:var(--ion-color-medium, #6b6b6b);cursor:pointer}.details-toggle ion-icon{font-size:14px}.details{margin:12px 0 0;display:flex;flex-direction:column;gap:6px}.details__row{display:grid;grid-template-columns:140px 1fr;gap:12px;font-size:12px;align-items:baseline}.details__row dt{margin:0;color:var(--ion-color-medium, #6b6b6b);text-transform:uppercase;letter-spacing:.4px;font-weight:500}.details__row dd{margin:0;color:var(--ion-color-dark, #1a1a1a);font-family:ui-monospace,SFMono-Regular,monospace;font-size:11px;word-break:break-all}\n"], dependencies: [{ kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: ToggleInputComponent, selector: "val-toggle-input", inputs: ["preset", "props"] }, { kind: "component", type: ButtonComponent, selector: "val-button", inputs: ["preset", "props"], outputs: ["onClick"] }, { 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"] }] }); }
547
+ }
548
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationPreferencesViewComponent, decorators: [{
549
+ type: Component,
550
+ args: [{ selector: 'val-notification-preferences-view', standalone: true, imports: [IonIcon, ToggleInputComponent, ButtonComponent, DisplayComponent, TitleComponent, TextComponent], template: `
551
+ <div class="page">
552
+ <header class="page-header">
553
+ <val-display [props]="{ size: 'small', color: 'dark', content: pageTitle() }" />
554
+ <val-title
555
+ [props]="{
556
+ size: 'large',
557
+ color: 'dark',
558
+ bold: false,
559
+ content: pageDescription(),
560
+ }"
561
+ />
562
+ </header>
563
+
564
+ @if (state() === 'needs-install') {
565
+ <section class="settings-section">
566
+ <val-title
567
+ [props]="{
568
+ size: 'medium',
569
+ color: 'dark',
570
+ bold: true,
571
+ content: tt('iosInstallTitle'),
572
+ }"
573
+ />
574
+ <div class="section-body">
575
+ <val-text
576
+ [props]="{
577
+ size: 'small',
578
+ color: 'medium',
579
+ bold: false,
580
+ content: tt('iosInstallHint'),
581
+ }"
582
+ />
583
+ <ol class="install-steps">
584
+ <li>{{ tt('iosInstallStep1') }}</li>
585
+ <li>{{ tt('iosInstallStep2') }}</li>
586
+ <li>{{ tt('iosInstallStep3') }}</li>
587
+ <li>{{ tt('iosInstallStep4') }}</li>
588
+ </ol>
589
+ </div>
590
+ </section>
591
+ }
592
+
593
+ <section class="settings-section">
594
+ <div class="notif-row">
595
+ <div class="notif-row__icon">
596
+ <ion-icon name="notifications-outline" aria-hidden="true" />
597
+ </div>
598
+ <div class="notif-row__body">
599
+ <val-title
600
+ [props]="{
601
+ size: 'medium',
602
+ color: 'dark',
603
+ bold: true,
604
+ content: tt('simpleTitle'),
605
+ }"
606
+ />
607
+ <val-text
608
+ [props]="{
609
+ size: 'small',
610
+ color: 'medium',
611
+ bold: false,
612
+ content: tt('simpleDescription'),
613
+ }"
614
+ />
615
+ @if (busyLabel(); as label) {
616
+ <span class="notif-row__busy">{{ label }}</span>
617
+ }
618
+ </div>
619
+ <div class="notif-row__control">
620
+ <val-toggle-input [props]="toggleProps()" />
621
+ </div>
622
+ </div>
623
+
624
+ @if (contextMessage(); as msg) {
625
+ <div class="alert" [class]="'alert--' + alertVariant()">
626
+ <ion-icon [name]="alertIcon()" aria-hidden="true" />
627
+ <span>{{ msg }}</span>
628
+ </div>
629
+ }
630
+
631
+ @if (state() === 'error') {
632
+ <div class="row-actions">
633
+ <val-button [props]="retryButtonProps()" (click)="onRetry()" />
634
+ </div>
635
+ }
636
+ </section>
637
+
638
+ @if (resolvedConfig().showDetails && state() !== 'needs-install' && state() !== 'unsupported') {
639
+ <section class="settings-section">
640
+ <button class="details-toggle" type="button" (click)="toggleDetails()">
641
+ <span>{{ showDetails() ? tt('detailsHide') : tt('detailsShow') }}</span>
642
+ <ion-icon [name]="showDetails() ? 'chevron-up-outline' : 'chevron-down-outline'" aria-hidden="true" />
643
+ </button>
644
+ @if (showDetails()) {
645
+ <dl class="details">
646
+ <div class="details__row">
647
+ <dt>{{ tt('detailsToken') }}</dt>
648
+ <dd>{{ tokenPreview() ?? tt('detailsNone') }}</dd>
649
+ </div>
650
+ <div class="details__row">
651
+ <dt>{{ tt('diagnosticsPermission') }}</dt>
652
+ <dd>{{ permission() }}</dd>
653
+ </div>
654
+ <div class="details__row">
655
+ <dt>{{ tt('diagnosticsSupported') }}</dt>
656
+ <dd>{{ isSupported() ? '✓' : '✗' }}</dd>
657
+ </div>
658
+ </dl>
659
+ }
660
+ </section>
661
+ }
662
+ </div>
663
+ `, styles: [".page{padding:16px 0;max-width:720px;margin:0 auto}.page-header{margin-bottom:8px}.settings-section{padding:16px 0}.settings-section+.settings-section{border-top:1px solid var(--val-border-color, rgba(0, 0, 0, .08))}.section-body{margin-top:16px;display:flex;flex-direction:column;gap:10px}.row-actions{margin-top:12px}.notif-row{display:grid;grid-template-columns:44px 1fr auto;gap:16px;align-items:center}.notif-row__icon{width:44px;height:44px;border-radius:50%;background:var(--ion-color-light, rgba(0, 0, 0, .06));display:flex;align-items:center;justify-content:center}.notif-row__icon ion-icon{font-size:22px;color:var(--ion-color-dark, #1a1a1a)}.notif-row__body{display:flex;flex-direction:column;gap:4px;min-width:0}.notif-row__busy{font-size:12px;color:var(--ion-color-medium, #92949c);font-style:italic;margin-top:4px}.notif-row__control{flex-shrink:0}.alert{display:flex;gap:10px;align-items:flex-start;margin-top:12px;padding:12px 14px;border-radius:10px;font-size:13px;line-height:1.45;background:var(--ion-color-light, rgba(0, 0, 0, .04));color:var(--ion-color-dark, #1a1a1a)}.alert ion-icon{font-size:18px;flex-shrink:0;margin-top:1px}.alert--warning ion-icon{color:var(--ion-color-warning-shade, #c79e08)}.alert--danger ion-icon{color:var(--ion-color-danger-shade, #cf3c4f)}.alert--info ion-icon{color:var(--ion-color-medium, #6b6b6b)}.install-steps{margin:0;padding-left:20px;font-size:13px;line-height:1.6;color:var(--ion-color-dark, #1a1a1a)}.install-steps li+li{margin-top:4px}.details-toggle{display:flex;align-items:center;gap:6px;background:none;border:0;padding:0;font-size:13px;color:var(--ion-color-medium, #6b6b6b);cursor:pointer}.details-toggle ion-icon{font-size:14px}.details{margin:12px 0 0;display:flex;flex-direction:column;gap:6px}.details__row{display:grid;grid-template-columns:140px 1fr;gap:12px;font-size:12px;align-items:baseline}.details__row dt{margin:0;color:var(--ion-color-medium, #6b6b6b);text-transform:uppercase;letter-spacing:.4px;font-weight:500}.details__row dd{margin:0;color:var(--ion-color-dark, #1a1a1a);font-family:ui-monospace,SFMono-Regular,monospace;font-size:11px;word-break:break-all}\n"] }]
664
+ }], ctorParameters: () => [], propDecorators: { config: [{
665
+ type: Input
666
+ }] } });
667
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpY2F0aW9uLXByZWZlcmVuY2VzLXZpZXcuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL29yZ2FuaXNtcy9ub3RpZmljYXRpb24tcHJlZmVyZW5jZXMtdmlldy9ub3RpZmljYXRpb24tcHJlZmVyZW5jZXMtdmlldy5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQXFCLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN0RyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQ3BDLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsa0JBQWtCLEVBQ2xCLGdCQUFnQixFQUNoQixrQkFBa0IsRUFDbEIsdUJBQXVCLEVBQ3ZCLG9CQUFvQixFQUNwQixjQUFjLEdBQ2YsTUFBTSxnQkFBZ0IsQ0FBQztBQUV4QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDdEUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDekUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNuRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxxREFBcUQsQ0FBQztBQUUzRixPQUFPLEVBQWtCLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUU5RCxPQUFPLEVBQUUs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QUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIGNvbXB1dGVkLCBlZmZlY3QsIGluamVjdCwgSW5wdXQsIE9uRGVzdHJveSwgT25Jbml0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1Db250cm9sIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgSW9uSWNvbiB9IGZyb20gJ0Bpb25pYy9hbmd1bGFyL3N0YW5kYWxvbmUnO1xuaW1wb3J0IHsgYWRkSWNvbnMgfSBmcm9tICdpb25pY29ucyc7XG5pbXBvcnQge1xuICBhbGVydENpcmNsZU91dGxpbmUsXG4gIGNoZXZyb25Eb3duT3V0bGluZSxcbiAgY2hldnJvblVwT3V0bGluZSxcbiAgY2xvc2VDaXJjbGVPdXRsaW5lLFxuICBub3RpZmljYXRpb25zT2ZmT3V0bGluZSxcbiAgbm90aWZpY2F0aW9uc091dGxpbmUsXG4gIHJlZnJlc2hPdXRsaW5lLFxufSBmcm9tICdpb25pY29ucy9pY29ucyc7XG5cbmltcG9ydCB7IEJ1dHRvbkNvbXBvbmVudCB9IGZyb20gJy4uLy4uL2F0b21zL2J1dHRvbi9idXR0b24uY29tcG9uZW50JztcbmltcG9ydCB7IERpc3BsYXlDb21wb25lbnQgfSBmcm9tICcuLi8uLi9hdG9tcy9kaXNwbGF5L2Rpc3BsYXkuY29tcG9uZW50JztcbmltcG9ydCB7IFRleHRDb21wb25lbnQgfSBmcm9tICcuLi8uLi9hdG9tcy90ZXh0L3RleHQuY29tcG9uZW50JztcbmltcG9ydCB7IFRpdGxlQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vYXRvbXMvdGl0bGUvdGl0bGUuY29tcG9uZW50JztcbmltcG9ydCB7IFRvZ2dsZUlucHV0Q29tcG9uZW50IH0gZnJvbSAnLi4vLi4vbW9sZWN1bGVzL3RvZ2dsZS1pbnB1dC90b2dnbGUtaW5wdXQuY29tcG9uZW50JztcbmltcG9ydCB7IFRvZ2dsZUlucHV0TWV0YWRhdGEgfSBmcm9tICcuLi8uLi9tb2xlY3VsZXMvdG9nZ2xlLWlucHV0L3R5cGVzJztcbmltcG9ydCB7IEJ1dHRvbk1ldGFkYXRhLCBDb21wb25lbnRTdGF0ZXMgfSBmcm9tICcuLi8uLi90eXBlcyc7XG5cbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvYXV0aC9hdXRoLnNlcnZpY2UnO1xuaW1wb3J0IHsgTm90aWZpY2F0aW9uUGVybWlzc2lvblN0YXRlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvYXV0aC90eXBlcyc7XG5pbXBvcnQgeyBFbmFibGVQdXNoUmVzdWx0IH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvZmlyZWJhc2UvdHlwZXMnO1xuaW1wb3J0IHsgTWVzc2FnaW5nU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL2ZpcmViYXNlL21lc3NhZ2luZy5zZXJ2aWNlJztcbmltcG9ydCB7IEkxOG5TZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vc2VydmljZXMvaTE4bic7XG5pbXBvcnQgeyBOYXZpZ2F0aW9uU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL25hdmlnYXRpb24vbmF2aWdhdGlvbi5zZXJ2aWNlJztcbmltcG9ydCB7IFBhZ2VSZWZyZXNoU2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL3BhZ2UtcmVmcmVzaC9wYWdlLXJlZnJlc2guc2VydmljZSc7XG5pbXBvcnQgeyBQcmVmZXJlbmNlc1NlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9zZXJ2aWNlcy9wcmVmZXJlbmNlcy9wcmVmZXJlbmNlcy5zZXJ2aWNlJztcbmltcG9ydCB7IFRvYXN0U2VydmljZSB9IGZyb20gJy4uLy4uLy4uL3NlcnZpY2VzL3RvYXN0LnNlcnZpY2UnO1xuXG5pbXBvcnQgeyBOb3RpZmljYXRpb25QcmVmZXJlbmNlc1ZpZXdDb25maWcgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IE5PVElGSUNBVElPTl9QUkVGRVJFTkNFU19WSUVXX0kxOE4gfSBmcm9tICcuL25vdGlmaWNhdGlvbi1wcmVmZXJlbmNlcy12aWV3LmkxOG4nO1xuXG5hZGRJY29ucyh7XG4gIGFsZXJ0Q2lyY2xlT3V0bGluZSxcbiAgY2hldnJvbkRvd25PdXRsaW5lLFxuICBjaGV2cm9uVXBPdXRsaW5lLFxuICBjbG9zZUNpcmNsZU91dGxpbmUsXG4gIG5vdGlmaWNhdGlvbnNPZmZPdXRsaW5lLFxuICBub3RpZmljYXRpb25zT3V0bGluZSxcbiAgcmVmcmVzaE91dGxpbmUsXG59KTtcblxuY29uc3QgREVGQVVMVF9OQU1FU1BBQ0UgPSAnU2V0dGluZ3MuTm90aWZpY2F0aW9ucyc7XG5cbi8qKlxuICogRXN0YWRvcyBkZSBsYSB2aXN0YSBkZSBwcmVmZXJlbmNpYXMgcHVzaDpcbiAqICAtIGBpZGxlYDogICAgICAgICAgdG9nZ2xlIG9mZiwgc2luIG9wZXJhY2nDs24gZW4gY3Vyc28sIHNpbiBlcnJvcmVzXG4gKiAgLSBgZW5hYmxpbmdgOiAgICAgIHNlY3VlbmNpYSBkZSBhY3RpdmFjacOzbiBlbiBjdXJzbyAodG9nZ2xlIHNwaW5uZXIpXG4gKiAgLSBgZW5hYmxlZGA6ICAgICAgIHRvZG8gT0sgKG1hc3Rlcj10cnVlICsgcGVybWlzc2lvbj1ncmFudGVkICsgdG9rZW4gcmVnaXN0cmFkbylcbiAqICAtIGBkaXNhYmxpbmdgOiAgICAgZGVzYWN0aXZhY2nDs24gZW4gY3Vyc29cbiAqICAtIGBlcnJvcmA6ICAgICAgICAgw7psdGltbyBpbnRlbnRvIGZhbGzDsyDihpIgbWVuc2FqZSArIGJvdMOzbiBcIlJlaW50ZW50YXJcIlxuICogIC0gYGJsb2NrZWRgOiAgICAgICBuYXZlZ2Fkb3IgZGVuZWfDsyBwZXJtaXNvcyDihpIgbWVuc2FqZSArIGPDs21vIGFycmVnbGFyXG4gKiAgLSBgdW5zdXBwb3J0ZWRgOiAgIG5hdmVnYWRvciBubyBzb3BvcnRhIEZDTSDihpIgbWVuc2FqZVxuICogIC0gYG5lZWRzLWluc3RhbGxgOiBpT1Mgc2luIHN0YW5kYWxvbmUg4oaSIGluc3RydWNjaW9uZXMgZGUgaW5zdGFsYWNpw7NuIFBXQVxuICovXG50eXBlIFVpU3RhdGUgPSAnaWRsZScgfCAnZW5hYmxpbmcnIHwgJ2VuYWJsZWQnIHwgJ2Rpc2FibGluZycgfCAnZXJyb3InIHwgJ2Jsb2NrZWQnIHwgJ3Vuc3VwcG9ydGVkJyB8ICduZWVkcy1pbnN0YWxsJztcblxuLyoqXG4gKiBgdmFsLW5vdGlmaWNhdGlvbi1wcmVmZXJlbmNlcy12aWV3YCDigJQgKipwcmVmZXJlbmNpYXMgZGUgbm90aWZpY2FjaW9uZXMgcHVzaCoqXG4gKiAoRkNNKSBmdWxsLWZlYXR1cmUgYXV0b2NvbnRlbmlkYSAob3JnYW5pc20pLiBQcm9tb3ZpZGEgZGVzZGUgYHNob3djYXNlYCBiYWpvIGVsXG4gKiBwcm9jZXNvIGRlIEFEUi0wMjEuXG4gKlxuICogU2VwYXJhZGEgZGUgYHZhbC1ub3RpZmljYXRpb25zLXZpZXdgIChlbCBpbmJveCAvIGZlZWQpLiBBcXXDrSBlbCB1c2VyICoqYWN0aXZhIG9cbiAqIGRlc2FjdGl2YSoqIGxhcyBub3RpZmljYWNpb25lcyBwdXNoIGVuIGVzdGUgZGlzcG9zaXRpdm8uXG4gKlxuICogVVggc2ltcGxpZmljYWRvOiBVTiBzb2xvIHRvZ2dsZSBxdWUgZWplY3V0YSB0b2RhIGxhIHNlY3VlbmNpYSAocGVkaXIgcGVybWlzbyDihpJcbiAqIFNXIHJlYWR5IOKGkiBnZXRUb2tlbiDihpIgcmVnaXN0cmFyIGVuIGJhY2tlbmQg4oaSIHNldCBtYXN0ZXIgcHJlZikgdsOtYVxuICogYE1lc3NhZ2luZ1NlcnZpY2UuZW5hYmxlKClgLiBFbCByZWdpc3RybyBkZWwgZGV2aWNlIGVuIGVsIGJhY2tlbmQgdmEgY29tb1xuICogY2FsbGJhY2sgKGxhIGxpYiBubyBkZXBlbmRlIGRlIGBBdXRoU2VydmljZWAgcGFyYSBldml0YXIgY2ljbG9zKS4gTWVuc2FqZXNcbiAqIGNvbnRleHR1YWxlcyB5IGJvdMOzbiBcIlJlaW50ZW50YXJcIiBhcGFyZWNlbiBzb2xvIGN1YW5kbyBhcGxpY2FuLlxuICpcbiAqIE5PIHJlbmRlcml6YSBpb24tY29udGVudCDigJQgdml2ZSBkZW50cm8gZGUgdmFsLXBhZ2Utd3JhcHBlci4gYEFjdGl2YXRlZFJvdXRlYCBzZVxuICogaW55ZWN0YSBgeyBvcHRpb25hbDogdHJ1ZSB9YCDihpIgZnVuY2lvbmEgc2luIHJvdXRlciAoZW1iZWJpZGEgLyBTdG9yeWJvb2spLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd2YWwtbm90aWZpY2F0aW9uLXByZWZlcmVuY2VzLXZpZXcnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbSW9uSWNvbiwgVG9nZ2xlSW5wdXRDb21wb25lbnQsIEJ1dHRvbkNvbXBvbmVudCwgRGlzcGxheUNvbXBvbmVudCwgVGl0bGVDb21wb25lbnQsIFRleHRDb21wb25lbnRdLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJwYWdlXCI+XG4gICAgICA8aGVhZGVyIGNsYXNzPVwicGFnZS1oZWFkZXJcIj5cbiAgICAgICAgPHZhbC1kaXNwbGF5IFtwcm9wc109XCJ7IHNpemU6ICdzbWFsbCcsIGNvbG9yOiAnZGFyaycsIGNvbnRlbnQ6IHBhZ2VUaXRsZSgpIH1cIiAvPlxuICAgICAgICA8dmFsLXRpdGxlXG4gICAgICAgICAgW3Byb3BzXT1cIntcbiAgICAgICAgICAgIHNpemU6ICdsYXJnZScsXG4gICAgICAgICAgICBjb2xvcjogJ2RhcmsnLFxuICAgICAgICAgICAgYm9sZDogZmFsc2UsXG4gICAgICAgICAgICBjb250ZW50OiBwYWdlRGVzY3JpcHRpb24oKSxcbiAgICAgICAgICB9XCJcbiAgICAgICAgLz5cbiAgICAgIDwvaGVhZGVyPlxuXG4gICAgICBAaWYgKHN0YXRlKCkgPT09ICduZWVkcy1pbnN0YWxsJykge1xuICAgICAgICA8c2VjdGlvbiBjbGFzcz1cInNldHRpbmdzLXNlY3Rpb25cIj5cbiAgICAgICAgICA8dmFsLXRpdGxlXG4gICAgICAgICAgICBbcHJvcHNdPVwie1xuICAgICAgICAgICAgICBzaXplOiAnbWVkaXVtJyxcbiAgICAgICAgICAgICAgY29sb3I6ICdkYXJrJyxcbiAgICAgICAgICAgICAgYm9sZDogdHJ1ZSxcbiAgICAgICAgICAgICAgY29udGVudDogdHQoJ2lvc0luc3RhbGxUaXRsZScpLFxuICAgICAgICAgICAgfVwiXG4gICAgICAgICAgLz5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwic2VjdGlvbi1ib2R5XCI+XG4gICAgICAgICAgICA8dmFsLXRleHRcbiAgICAgICAgICAgICAgW3Byb3BzXT1cIntcbiAgICAgICAgICAgICAgICBzaXplOiAnc21hbGwnLFxuICAgICAgICAgICAgICAgIGNvbG9yOiAnbWVkaXVtJyxcbiAgICAgICAgICAgICAgICBib2xkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBjb250ZW50OiB0dCgnaW9zSW5zdGFsbEhpbnQnKSxcbiAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPG9sIGNsYXNzPVwiaW5zdGFsbC1zdGVwc1wiPlxuICAgICAgICAgICAgICA8bGk+e3sgdHQoJ2lvc0luc3RhbGxTdGVwMScpIH19PC9saT5cbiAgICAgICAgICAgICAgPGxpPnt7IHR0KCdpb3NJbnN0YWxsU3RlcDInKSB9fTwvbGk+XG4gICAgICAgICAgICAgIDxsaT57eyB0dCgnaW9zSW5zdGFsbFN0ZXAzJykgfX08L2xpPlxuICAgICAgICAgICAgICA8bGk+e3sgdHQoJ2lvc0luc3RhbGxTdGVwNCcpIH19PC9saT5cbiAgICAgICAgICAgIDwvb2w+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvc2VjdGlvbj5cbiAgICAgIH1cblxuICAgICAgPHNlY3Rpb24gY2xhc3M9XCJzZXR0aW5ncy1zZWN0aW9uXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJub3RpZi1yb3dcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibm90aWYtcm93X19pY29uXCI+XG4gICAgICAgICAgICA8aW9uLWljb24gbmFtZT1cIm5vdGlmaWNhdGlvbnMtb3V0bGluZVwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiIC8+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cIm5vdGlmLXJvd19fYm9keVwiPlxuICAgICAgICAgICAgPHZhbC10aXRsZVxuICAgICAgICAgICAgICBbcHJvcHNdPVwie1xuICAgICAgICAgICAgICAgIHNpemU6ICdtZWRpdW0nLFxuICAgICAgICAgICAgICAgIGNvbG9yOiAnZGFyaycsXG4gICAgICAgICAgICAgICAgYm9sZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjb250ZW50OiB0dCgnc2ltcGxlVGl0bGUnKSxcbiAgICAgICAgICAgICAgfVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAgPHZhbC10ZXh0XG4gICAgICAgICAgICAgIFtwcm9wc109XCJ7XG4gICAgICAgICAgICAgICAgc2l6ZTogJ3NtYWxsJyxcbiAgICAgICAgICAgICAgICBjb2xvcjogJ21lZGl1bScsXG4gICAgICAgICAgICAgICAgYm9sZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgY29udGVudDogdHQoJ3NpbXBsZURlc2NyaXB0aW9uJyksXG4gICAgICAgICAgICAgIH1cIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIEBpZiAoYnVzeUxhYmVsKCk7IGFzIGxhYmVsKSB7XG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibm90aWYtcm93X19idXN5XCI+e3sgbGFiZWwgfX08L3NwYW4+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cIm5vdGlmLXJvd19fY29udHJvbFwiPlxuICAgICAgICAgICAgPHZhbC10b2dnbGUtaW5wdXQgW3Byb3BzXT1cInRvZ2dsZVByb3BzKClcIiAvPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICBAaWYgKGNvbnRleHRNZXNzYWdlKCk7IGFzIG1zZykge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJhbGVydFwiIFtjbGFzc109XCInYWxlcnQtLScgKyBhbGVydFZhcmlhbnQoKVwiPlxuICAgICAgICAgICAgPGlvbi1pY29uIFtuYW1lXT1cImFsZXJ0SWNvbigpXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCIgLz5cbiAgICAgICAgICAgIDxzcGFuPnt7IG1zZyB9fTwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgfVxuXG4gICAgICAgIEBpZiAoc3RhdGUoKSA9PT0gJ2Vycm9yJykge1xuICAgICAgICAgIDxkaXYgY2xhc3M9XCJyb3ctYWN0aW9uc1wiPlxuICAgICAgICAgICAgPHZhbC1idXR0b24gW3Byb3BzXT1cInJldHJ5QnV0dG9uUHJvcHMoKVwiIChjbGljayk9XCJvblJldHJ5KClcIiAvPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICB9XG4gICAgICA8L3NlY3Rpb24+XG5cbiAgICAgIEBpZiAocmVzb2x2ZWRDb25maWcoKS5zaG93RGV0YWlscyAmJiBzdGF0ZSgpICE9PSAnbmVlZHMtaW5zdGFsbCcgJiYgc3RhdGUoKSAhPT0gJ3Vuc3VwcG9ydGVkJykge1xuICAgICAgICA8c2VjdGlvbiBjbGFzcz1cInNldHRpbmdzLXNlY3Rpb25cIj5cbiAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiZGV0YWlscy10b2dnbGVcIiB0eXBlPVwiYnV0dG9uXCIgKGNsaWNrKT1cInRvZ2dsZURldGFpbHMoKVwiPlxuICAgICAgICAgICAgPHNwYW4+e3sgc2hvd0RldGFpbHMoKSA/IHR0KCdkZXRhaWxzSGlkZScpIDogdHQoJ2RldGFpbHNTaG93JykgfX08L3NwYW4+XG4gICAgICAgICAgICA8aW9uLWljb24gW25hbWVdPVwic2hvd0RldGFpbHMoKSA/ICdjaGV2cm9uLXVwLW91dGxpbmUnIDogJ2NoZXZyb24tZG93bi1vdXRsaW5lJ1wiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiIC8+XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgQGlmIChzaG93RGV0YWlscygpKSB7XG4gICAgICAgICAgICA8ZGwgY2xhc3M9XCJkZXRhaWxzXCI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJkZXRhaWxzX19yb3dcIj5cbiAgICAgICAgICAgICAgICA8ZHQ+e3sgdHQoJ2RldGFpbHNUb2tlbicpIH19PC9kdD5cbiAgICAgICAgICAgICAgICA8ZGQ+e3sgdG9rZW5QcmV2aWV3KCkgPz8gdHQoJ2RldGFpbHNOb25lJykgfX08L2RkPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImRldGFpbHNfX3Jvd1wiPlxuICAgICAgICAgICAgICAgIDxkdD57eyB0dCgnZGlhZ25vc3RpY3NQZXJtaXNzaW9uJykgfX08L2R0PlxuICAgICAgICAgICAgICAgIDxkZD57eyBwZXJtaXNzaW9uKCkgfX08L2RkPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImRldGFpbHNfX3Jvd1wiPlxuICAgICAgICAgICAgICAgIDxkdD57eyB0dCgnZGlhZ25vc3RpY3NTdXBwb3J0ZWQnKSB9fTwvZHQ+XG4gICAgICAgICAgICAgICAgPGRkPnt7IGlzU3VwcG9ydGVkKCkgPyAn4pyTJyA6ICfinJcnIH19PC9kZD5cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2RsPlxuICAgICAgICAgIH1cbiAgICAgICAgPC9zZWN0aW9uPlxuICAgICAgfVxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZXM6IFtcbiAgICBgXG4gICAgICAucGFnZSB7XG4gICAgICAgIHBhZGRpbmc6IDE2cHggMDtcbiAgICAgICAgbWF4LXdpZHRoOiA3MjBweDtcbiAgICAgICAgbWFyZ2luOiAwIGF1dG87XG4gICAgICB9XG4gICAgICAucGFnZS1oZWFkZXIge1xuICAgICAgICBtYXJnaW4tYm90dG9tOiA4cHg7XG4gICAgICB9XG4gICAgICAuc2V0dGluZ3Mtc2VjdGlvbiB7XG4gICAgICAgIHBhZGRpbmc6IDE2cHggMDtcbiAgICAgIH1cbiAgICAgIC5zZXR0aW5ncy1zZWN0aW9uICsgLnNldHRpbmdzLXNlY3Rpb24ge1xuICAgICAgICBib3JkZXItdG9wOiAxcHggc29saWQgdmFyKC0tdmFsLWJvcmRlci1jb2xvciwgcmdiYSgwLCAwLCAwLCAwLjA4KSk7XG4gICAgICB9XG4gICAgICAuc2VjdGlvbi1ib2R5IHtcbiAgICAgICAgbWFyZ2luLXRvcDogMTZweDtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgICAgICAgZ2FwOiAxMHB4O1xuICAgICAgfVxuICAgICAgLnJvdy1hY3Rpb25zIHtcbiAgICAgICAgbWFyZ2luLXRvcDogMTJweDtcbiAgICAgIH1cblxuICAgICAgLm5vdGlmLXJvdyB7XG4gICAgICAgIGRpc3BsYXk6IGdyaWQ7XG4gICAgICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogNDRweCAxZnIgYXV0bztcbiAgICAgICAgZ2FwOiAxNnB4O1xuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgICAgfVxuICAgICAgLm5vdGlmLXJvd19faWNvbiB7XG4gICAgICAgIHdpZHRoOiA0NHB4O1xuICAgICAgICBoZWlnaHQ6IDQ0cHg7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDUwJTtcbiAgICAgICAgYmFja2dyb3VuZDogdmFyKC0taW9uLWNvbG9yLWxpZ2h0LCByZ2JhKDAsIDAsIDAsIDAuMDYpKTtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gICAgICB9XG4gICAgICAubm90aWYtcm93X19pY29uIGlvbi1pY29uIHtcbiAgICAgICAgZm9udC1zaXplOiAyMnB4O1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLWRhcmssICMxYTFhMWEpO1xuICAgICAgfVxuICAgICAgLm5vdGlmLXJvd19fYm9keSB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICAgIGdhcDogNHB4O1xuICAgICAgICBtaW4td2lkdGg6IDA7XG4gICAgICB9XG4gICAgICAubm90aWYtcm93X19idXN5IHtcbiAgICAgICAgZm9udC1zaXplOiAxMnB4O1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLW1lZGl1bSwgIzkyOTQ5Yyk7XG4gICAgICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcbiAgICAgICAgbWFyZ2luLXRvcDogNHB4O1xuICAgICAgfVxuICAgICAgLm5vdGlmLXJvd19fY29udHJvbCB7XG4gICAgICAgIGZsZXgtc2hyaW5rOiAwO1xuICAgICAgfVxuXG4gICAgICAuYWxlcnQge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBnYXA6IDEwcHg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBmbGV4LXN0YXJ0O1xuICAgICAgICBtYXJnaW4tdG9wOiAxMnB4O1xuICAgICAgICBwYWRkaW5nOiAxMnB4IDE0cHg7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDEwcHg7XG4gICAgICAgIGZvbnQtc2l6ZTogMTNweDtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuNDU7XG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWlvbi1jb2xvci1saWdodCwgcmdiYSgwLCAwLCAwLCAwLjA0KSk7XG4gICAgICAgIGNvbG9yOiB2YXIoLS1pb24tY29sb3ItZGFyaywgIzFhMWExYSk7XG4gICAgICB9XG4gICAgICAuYWxlcnQgaW9uLWljb24ge1xuICAgICAgICBmb250LXNpemU6IDE4cHg7XG4gICAgICAgIGZsZXgtc2hyaW5rOiAwO1xuICAgICAgICBtYXJnaW4tdG9wOiAxcHg7XG4gICAgICB9XG4gICAgICAuYWxlcnQtLXdhcm5pbmcgaW9uLWljb24ge1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLXdhcm5pbmctc2hhZGUsICNjNzllMDgpO1xuICAgICAgfVxuICAgICAgLmFsZXJ0LS1kYW5nZXIgaW9uLWljb24ge1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLWRhbmdlci1zaGFkZSwgI2NmM2M0Zik7XG4gICAgICB9XG4gICAgICAuYWxlcnQtLWluZm8gaW9uLWljb24ge1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLW1lZGl1bSwgIzZiNmI2Yik7XG4gICAgICB9XG5cbiAgICAgIC5pbnN0YWxsLXN0ZXBzIHtcbiAgICAgICAgbWFyZ2luOiAwO1xuICAgICAgICBwYWRkaW5nLWxlZnQ6IDIwcHg7XG4gICAgICAgIGZvbnQtc2l6ZTogMTNweDtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuNjtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1kYXJrLCAjMWExYTFhKTtcbiAgICAgIH1cbiAgICAgIC5pbnN0YWxsLXN0ZXBzIGxpICsgbGkge1xuICAgICAgICBtYXJnaW4tdG9wOiA0cHg7XG4gICAgICB9XG5cbiAgICAgIC5kZXRhaWxzLXRvZ2dsZSB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgIGdhcDogNnB4O1xuICAgICAgICBiYWNrZ3JvdW5kOiBub25lO1xuICAgICAgICBib3JkZXI6IDA7XG4gICAgICAgIHBhZGRpbmc6IDA7XG4gICAgICAgIGZvbnQtc2l6ZTogMTNweDtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1tZWRpdW0sICM2YjZiNmIpO1xuICAgICAgICBjdXJzb3I6IHBvaW50ZXI7XG4gICAgICB9XG4gICAgICAuZGV0YWlscy10b2dnbGUgaW9uLWljb24ge1xuICAgICAgICBmb250LXNpemU6IDE0cHg7XG4gICAgICB9XG4gICAgICAuZGV0YWlscyB7XG4gICAgICAgIG1hcmdpbjogMTJweCAwIDA7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICAgIGdhcDogNnB4O1xuICAgICAgfVxuICAgICAgLmRldGFpbHNfX3JvdyB7XG4gICAgICAgIGRpc3BsYXk6IGdyaWQ7XG4gICAgICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogMTQwcHggMWZyO1xuICAgICAgICBnYXA6IDEycHg7XG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgICAgYWxpZ24taXRlbXM6IGJhc2VsaW5lO1xuICAgICAgfVxuICAgICAgLmRldGFpbHNfX3JvdyBkdCB7XG4gICAgICAgIG1hcmdpbjogMDtcbiAgICAgICAgY29sb3I6IHZhcigtLWlvbi1jb2xvci1tZWRpdW0sICM2YjZiNmIpO1xuICAgICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgICAgICBsZXR0ZXItc3BhY2luZzogMC40cHg7XG4gICAgICAgIGZvbnQtd2VpZ2h0OiA1MDA7XG4gICAgICB9XG4gICAgICAuZGV0YWlsc19fcm93IGRkIHtcbiAgICAgICAgbWFyZ2luOiAwO1xuICAgICAgICBjb2xvcjogdmFyKC0taW9uLWNvbG9yLWRhcmssICMxYTFhMWEpO1xuICAgICAgICBmb250LWZhbWlseTogdWktbW9ub3NwYWNlLCBTRk1vbm8tUmVndWxhciwgbW9ub3NwYWNlO1xuICAgICAgICBmb250LXNpemU6IDExcHg7XG4gICAgICAgIHdvcmQtYnJlYWs6IGJyZWFrLWFsbDtcbiAgICAgIH1cbiAgICBgLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBOb3RpZmljYXRpb25QcmVmZXJlbmNlc1ZpZXdDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIHByaXZhdGUgbmF2ID0gaW5qZWN0KE5hdmlnYXRpb25TZXJ2aWNlKTtcbiAgcHJpdmF0ZSBpMThuID0gaW5qZWN0KEkxOG5TZXJ2aWNlKTtcbiAgcHJpdmF0ZSB0b2FzdCA9IGluamVjdChUb2FzdFNlcnZpY2UpO1xuICBwcml2YXRlIGF1dGggPSBpbmplY3QoQXV0aFNlcnZpY2UpO1xuICBwcml2YXRlIG1lc3NhZ2luZyA9IGluamVjdChNZXNzYWdpbmdTZXJ2aWNlKTtcbiAgcHJpdmF0ZSBwYWdlUmVmcmVzaCA9IGluamVjdChQYWdlUmVmcmVzaFNlcnZpY2UpO1xuICByZWFkb25seSBwcmVmcyA9IGluamVjdChQcmVmZXJlbmNlc1NlcnZpY2UpO1xuICAvLyBgQWN0aXZhdGVkUm91dGVgIG9wY2lvbmFsIOKGkiBsYSB2aXN0YSBmdW5jaW9uYSBlbWJlYmlkYSAvIGVuIFN0b3J5Ym9vayBzaW5cbiAgLy8gcm91dGVyIChzb2xvIGxvIHVzYSBwYXJhIGxlZXIgZWwgcm91dGUgZGF0YSBkZSBjb25maWcgY29tbyBmYWxsYmFjaykuXG4gIHByaXZhdGUgcm91dGUgPSBpbmplY3QoQWN0aXZhdGVkUm91dGUsIHsgb3B0aW9uYWw6IHRydWUgfSk7XG5cbiAgLyoqXG4gICAqIENvbmZpZyB2w61hIEBJbnB1dCAob2JqZWN0LWZpcnN0KS4gU2kgbm8gc2UgcGFzYSwgc2UgY2FlIGFsIHJvdXRlIGRhdGFcbiAgICogYG5vdGlmaWNhdGlvblByZWZlcmVuY2VzQ29uZmlnYCAocG9ibGFkbyBwb3JcbiAgICogYHByb3ZpZGVWYWx0ZWNoTm90aWZpY2F0aW9uUHJlZmVyZW5jZXNSb3V0ZXNgKS4gYHJlc29sdmVkQ29uZmlnYCBtZXJnZWEgY29uXG4gICAqIGxvcyBkZWZhdWx0cyDigJQgYEBJbnB1dGAgZ2FuYSBzb2JyZSByb3V0ZSBkYXRhLlxuICAgKi9cbiAgQElucHV0KCkgY29uZmlnPzogTm90aWZpY2F0aW9uUHJlZmVyZW5jZXNWaWV3Q29uZmlnO1xuXG4gIHJlYWRvbmx5IHJlc29sdmVkQ29uZmlnID0gY29tcHV0ZWQ8XG4gICAgUmVxdWlyZWQ8T21pdDxOb3RpZmljYXRpb25QcmVmZXJlbmNlc1ZpZXdDb25maWcsICdvblB1c2hFbmFibGVkJyB8ICdvblB1c2hEaXNhYmxlZCc+PiAmXG4gICAgICBQaWNrPE5vdGlmaWNhdGlvblByZWZlcmVuY2VzVmlld0NvbmZpZywgJ29uUHVzaEVuYWJsZWQnIHwgJ29uUHVzaERpc2FibGVkJz5cbiAgPigoKSA9PiB7XG4gICAgY29uc3QgZnJvbVJvdXRlID0gKHRoaXMucm91dGU/LnNuYXBzaG90LmRhdGFbJ25vdGlmaWNhdGlvblByZWZlcmVuY2VzQ29uZmlnJ10gPz9cbiAgICAgIHt9KSBhcyBOb3RpZmljYXRpb25QcmVmZXJlbmNlc1ZpZXdDb25maWc7XG4gICAgY29uc3QgbWVyZ2VkOiBOb3RpZmljYXRpb25QcmVmZXJlbmNlc1ZpZXdDb25maWcgPSB7IC4uLmZyb21Sb3V0ZSwgLi4uKHRoaXMuY29uZmlnID8/IHt9KSB9O1xuICAgIHJldHVybiB7XG4gICAgICBzaG93RGV0YWlsczogbWVyZ2VkLnNob3dEZXRhaWxzID8/IHRydWUsXG4gICAgICBpMThuTmFtZXNwYWNlOiBtZXJnZWQuaTE4bk5hbWVzcGFjZSA/PyBERUZBVUxUX05BTUVTUEFDRSxcbiAgICAgIG9uUHVzaEVuYWJsZWQ6IG1lcmdlZC5vblB1c2hFbmFibGVkLFxuICAgICAgb25QdXNoRGlzYWJsZWQ6IG1lcmdlZC5vblB1c2hEaXNhYmxlZCxcbiAgICB9O1xuICB9KTtcblxuICAvKiogTmFtZXNwYWNlIGkxOG4gcmVzdWVsdG8gKGNhcHR1cmFkbyBwYXJhIGxsYW1hZGFzIG5vLXJlYWN0aXZhcykuICovXG4gIHByaXZhdGUgZ2V0IG5zKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucmVzb2x2ZWRDb25maWcoKS5pMThuTmFtZXNwYWNlO1xuICB9XG5cbiAgLyoqIE9wZXJhY2nDs24gZW4gY3Vyc28gKGdvYmllcm5hIHNwaW5uZXIgZGVsIHRvZ2dsZSArIGxhYmVsIFwiQWN0aXZhbmRv4oCmXCIpLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IF9idXN5ID0gc2lnbmFsPG51bGwgfCAnZW5hYmxpbmcnIHwgJ2Rpc2FibGluZyc+KG51bGwpO1xuICAvKiogVHJ1ZSBzaSBlbCDDumx0aW1vIGludGVudG8gZmFsbMOzIOKAlCBnb2JpZXJuYSBlc3RhZG8gYGVycm9yYCArIHJldHJ5IGJ1dHRvbi4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBfbGFzdEZhaWxlZCA9IHNpZ25hbChmYWxzZSk7XG4gIC8qKiBUcnVlIG1pZW50cmFzIHNlIHJlLW9idGllbmUgZWwgdG9rZW4gRkNNIGVuIGJhY2tncm91bmQgKG5vIGFmZWN0YSBsYSBVSSkuICovXG4gIHByaXZhdGUgX3JlcGFpcmluZ1Rva2VuID0gZmFsc2U7XG4gIC8qKiBUb2dnbGUgZGVsIGV4cGFuZCBkZSBkZXRhbGxlcyB0w6ljbmljb3MuICovXG4gIHJlYWRvbmx5IHNob3dEZXRhaWxzID0gc2lnbmFsKGZhbHNlKTtcblxuICByZWFkb25seSBwZXJtaXNzaW9uID0gc2lnbmFsPE5vdGlmaWNhdGlvblBlcm1pc3Npb25TdGF0ZT4oJ2RlZmF1bHQnKTtcbiAgcmVhZG9ubHkgaXNTdXBwb3J0ZWQgPSBzaWduYWwoZmFsc2UpO1xuICByZWFkb25seSBjdXJyZW50VG9rZW4gPSBzaWduYWw8c3RyaW5nIHwgbnVsbD4obnVsbCk7XG4gIHJlYWRvbmx5IG5lZWRzSU9TSW5zdGFsbCA9IHNpZ25hbCh0aGlzLmRldGVjdE5lZWRzSU9TSW5zdGFsbCgpKTtcblxuICAvKiogRm9ybUNvbnRyb2wgZGVsIHRvZ2dsZSAoc3luYy1lYWRvIGNvbiBgaXNFbmFibGVkYCB2aWEgZWZmZWN0KS4gKi9cbiAgcmVhZG9ubHkgdG9nZ2xlQ29udHJvbCA9IG5ldyBGb3JtQ29udHJvbDxib29sZWFuPihmYWxzZSwge1xuICAgIG5vbk51bGxhYmxlOiB0cnVlLFxuICB9KTtcblxuICAvKiogSGFuZGxlciBkZWwgbGlzdGVuZXIgYGZvY3VzYCDigJQgcmVmZXJlbmNpYSBndWFyZGFkYSBwYXJhIHBvZGVyIHJlbW92ZXJsby4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBvbldpbmRvd0ZvY3VzID0gKCkgPT4gdGhpcy5zY2hlZHVsZUJyb3dzZXJSZWZyZXNoKCk7XG4gIC8qKiBUaW1lciBkZWwgZGVib3VuY2UgZGVsIHJlZnJlc2ggZGlzcGFyYWRvIHBvciBgZm9jdXNgLiAqL1xuICBwcml2YXRlIGZvY3VzRGVib3VuY2VUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsID0gbnVsbDtcbiAgLyoqIFZlbnRhbmEgZGUgZGVib3VuY2UgKG1zKSBwYXJhIGVsIHJlZnJlc2ggZGlzcGFyYWRvIHBvciBgZm9jdXNgLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IEZPQ1VTX0RFQk9VTkNFX01TID0gNTAwO1xuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBFc3RhZG8gZGVyaXZhZG9cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcmVhZG9ubHkgcGFnZVRpdGxlID0gY29tcHV0ZWQoKCkgPT4gdGhpcy50dCgncGFnZVRpdGxlJykpO1xuICByZWFkb25seSBwYWdlRGVzY3JpcHRpb24gPSBjb21wdXRlZCgoKSA9PiB0aGlzLnR0KCdwYWdlRGVzY3JpcHRpb24nKSk7XG5cbiAgLyoqXG4gICAqIEVzdGFkbyBlZmVjdGl2byBkZWwgdG9nZ2xlOiBcImVsIHVzdWFyaW8gdGllbmUgcHVzaCBhY3Rpdm9cIi5cbiAgICpcbiAgICogU2UgZGVyaXZhIFNPTE8gZGUgbGEgZGVjaXNpw7NuIGRlbCB1c3VhcmlvIChgbWFzdGVyYCkgeSBkZWwgcGVybWlzbyBkZWwgU09cbiAgICogKGBwZXJtaXNzaW9uYCkuIEVsIHRva2VuIEZDTSBOTyBmb3JtYSBwYXJ0ZSBkZWwgZXN0YWRvIGRlIFVJOiB2aXZlIGVuXG4gICAqIG1lbW9yaWEsIHNlIHBpZXJkZSBlbiBjYWRhIHJlY2FyZ2Evc3VzcGVuc2nDs24gZGUgbGEgUFdBIHkgcHJvZHVjaXLDrWEgZmxpY2tlci5cbiAgICogU2kgZmFsdGEgdG9rZW4gY29uIGBtYXN0ZXIgJiYgZ3JhbnRlZGAsIGVzIHVuIGRldGFsbGUgcmVwYXJhYmxlIGVuXG4gICAqIGJhY2tncm91bmQgKHZlciBgcmVwYWlyVG9rZW5JZk5lZWRlZGApLCBubyB1biBjYW1iaW8gZGVsIHRvZ2dsZS5cbiAgICovXG4gIHJlYWRvbmx5IGlzRW5hYmxlZCA9IGNvbXB1dGVkKCgpID0+IHRoaXMucHJlZnMubm90aWZpY2F0aW9uc01hc3RlcigpICYmIHRoaXMucGVybWlzc2lvbigpID09PSAnZ3JhbnRlZCcpO1xuXG4gIHJlYWRvbmx5IHN0YXRlID0gY29tcHV0ZWQ8VWlTdGF0ZT4oKCkgPT4ge1xuICAgIGlmICh0aGlzLm5lZWRzSU9TSW5zdGFsbCgpKSByZXR1cm4gJ25lZWRzLWluc3RhbGwnO1xuICAgIGlmICh0aGlzLnBlcm1pc3Npb24oKSA9PT0gJ3Vuc3VwcG9ydGVkJyB8fCAhdGhpcy5pc1N1cHBvcnRlZCgpKSB7XG4gICAgICAvLyBpT1Mgc3RhbmRhbG9uZSBhw7puIHB1ZWRlIGRhciBpc1N1cHBvcnRlZCBmYWxzZSB0ZW1wcmFubyBhbnRlcyBkZSBpbml0IOKAlFxuICAgICAgLy8gc29sbyBibG9xdWVhbW9zIHNpIGVsIGJyb3dzZXIgZXhwbMOtY2l0YW1lbnRlIG5vIHNvcG9ydGEgQVBJcy5cbiAgICAgIGlmICh0aGlzLnBlcm1pc3Npb24oKSA9PT0gJ3Vuc3VwcG9ydGVkJykgcmV0dXJuICd1bnN1cHBvcnRlZCc7XG4gICAgfVxuICAgIGNvbnN0IGJ1c3kgPSB0aGlzLl9idXN5KCk7XG4gICAgaWYgKGJ1c3kgPT09ICdlbmFibGluZycpIHJldHVybiAnZW5hYmxpbmcnO1xuICAgIGlmIChidXN5ID09PSAnZGlzYWJsaW5nJykgcmV0dXJuICdkaXNhYmxpbmcnO1xuICAgIGlmICh0aGlzLmlzRW5hYmxlZCgpKSByZXR1cm4gJ2VuYWJsZWQnO1xuICAgIGlmICh0aGlzLnBlcm1pc3Npb24oKSA9PT0gJ2RlbmllZCcpIHJldHVybiAnYmxvY2tlZCc7XG4gICAgaWYgKHRoaXMuX2xhc3RGYWlsZWQoKSkgcmV0dXJuICdlcnJvcic7XG4gICAgcmV0dXJuICdpZGxlJztcbiAgfSk7XG5cbiAgcmVhZG9ubHkgYnVzeUxhYmVsID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IHMgPSB0aGlzLnN0YXRlKCk7XG4gICAgaWYgKHMgPT09ICdlbmFibGluZycpIHJldHVybiB0aGlzLnR0KCdlbmFibGluZycpO1xuICAgIGlmIChzID09PSAnZGlzYWJsaW5nJykgcmV0dXJuIHRoaXMudHQoJ2Rpc2FibGluZycpO1xuICAgIHJldHVybiBudWxsO1xuICB9KTtcblxuICByZWFkb25seSBjb250ZXh0TWVzc2FnZSA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBzd2l0Y2ggKHRoaXMuc3RhdGUoKSkge1xuICAgICAgY2FzZSAndW5zdXBwb3J0ZWQnOlxuICAgICAgICByZXR1cm4gdGhpcy50dCgncGVybWlzc2lvblVuc3VwcG9ydGVkJyk7XG4gICAgICBjYXNlICdibG9ja2VkJzpcbiAgICAgICAgcmV0dXJuIHRoaXMudHQoJ3Blcm1pc3Npb25EZW5pZWRJbmZvJyk7XG4gICAgICBjYXNlICdlcnJvcic6XG4gICAgICAgIHJldHVybiB0aGlzLnR0KCdlcnJvckdlbmVyaWMnKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfSk7XG5cbiAgcmVhZG9ubHkgYWxlcnRWYXJpYW50ID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IHMgPSB0aGlzLnN0YXRlKCk7XG4gICAgaWYgKHMgPT09ICdlcnJvcicgfHwgcyA9PT0gJ2Jsb2NrZWQnKSByZXR1cm4gJ3dhcm5pbmcnO1xuICAgIGlmIChzID09PSAndW5zdXBwb3J0ZWQnKSByZXR1cm4gJ2Rhbmdlcic7XG4gICAgcmV0dXJuICdpbmZvJztcbiAgfSk7XG5cbiAgcmVhZG9ubHkgYWxlcnRJY29uID0gY29tcHV0ZWQoKCkgPT4ge1xuICAgIGNvbnN0IHMgPSB0aGlzLnN0YXRlKCk7XG4gICAgaWYgKHMgPT09ICd1bnN1cHBvcnRlZCcpIHJldHVybiAnY2xvc2UtY2lyY2xlLW91dGxpbmUnO1xuICAgIHJldHVybiAnYWxlcnQtY2lyY2xlLW91dGxpbmUnO1xuICB9KTtcblxuICByZWFkb25seSB0b2dnbGVQcm9wcyA9IGNvbXB1dGVkPFRvZ2dsZUlucHV0TWV0YWRhdGE+KCgpID0+ICh7XG4gICAgY29udHJvbDogdGhpcy50b2dnbGVDb250cm9sLFxuICAgIGNvbG9yOiAncHJpbWFyeScsXG4gICAgZGlzYWJsZWQ6XG4gICAgICB0aGlzLl9idXN5KCkgIT09IG51bGwgfHxcbiAgICAgIHRoaXMuc3RhdGUoKSA9PT0gJ3Vuc3VwcG9ydGVkJyB8fFxuICAgICAgdGhpcy5zdGF0ZSgpID09PSAnbmVlZHMtaW5zdGFsbCcgfHxcbiAgICAgIHRoaXMuc3RhdGUoKSA9PT0gJ2Jsb2NrZWQnLFxuICB9KSk7XG5cbiAgcmVhZG9ubHkgcmV0cnlCdXR0b25Qcm9wcyA9IGNvbXB1dGVkPFBhcnRpYWw8QnV0dG9uTWV0YWRhdGE+PigoKSA9PiAoe1xuICAgIHRleHQ6IHRoaXMudHQoJ3JldHJ5Q3RhJyksXG4gICAgY29sb3I6ICdkYXJrJyxcbiAgICBmaWxsOiAnb3V0bGluZScsXG4gICAgc2l6ZTogJ2RlZmF1bHQnLFxuICAgIHNoYXBlOiAncm91bmQnLFxuICAgIHR5cGU6ICdidXR0b24nLFxuICAgIGljb246IHsgbmFtZTogJ3JlZnJlc2gtb3V0bGluZScsIHNsb3Q6ICdzdGFydCcgfSxcbiAgICBzdGF0ZTogdGhpcy5fYnVzeSgpICE9PSBudWxsID8gQ29tcG9uZW50U3RhdGVzLldPUktJTkcgOiBDb21wb25lbnRTdGF0ZXMuRU5BQkxFRCxcbiAgfSkpO1xuXG4gIHJlYWRvbmx5IHRva2VuUHJldmlldyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBjb25zdCB0ID0gdGhpcy5jdXJyZW50VG9rZW4oKTtcbiAgICBpZiAoIXQpIHJldHVybiBudWxsO1xuICAgIHJldHVybiBgJHt0LnNsaWNlKDAsIDIyKX3igKYke3Quc2xpY2UoLTYpfWA7XG4gIH0pO1xuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBMaWZlY3ljbGVcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgY29uc3QgbnMgPSB0aGlzLm5zO1xuICAgIGlmICghdGhpcy5pMThuLmhhc05hbWVzcGFjZShucykpIHtcbiAgICAgIHRoaXMuaTE4bi5yZWdpc3RlckNvbnRlbnQobnMsIE5PVElGSUNBVElPTl9QUkVGRVJFTkNFU19WSUVXX0kxOE4pO1xuICAgIH1cbiAgICB0aGlzLm5hdi5zZXRCYWNrSGVhZGVyKCdwYWdlVGl0bGUnLCBucywgeyB3aXRoTWVudTogdHJ1ZSB9KTtcblxuICAgIHZvaWQgdGhpcy5yZWZyZXNoQnJvd3NlclN0YXRlKCk7XG5cbiAgICAvLyBSZS1hcGxpY2FyIGhlYWRlciBlbiBjYW1iaW8gZGUgaWRpb21hLlxuICAgIGVmZmVjdChcbiAgICAgICgpID0+IHtcbiAgICAgICAgdGhpcy5pMThuLmxhbmcoKTtcbiAgICAgICAgdGhpcy5uYXYuc2V0QmFja0hlYWRlcigncGFnZVRpdGxlJywgdGhpcy5ucywgeyB3aXRoTWVudTogdHJ1ZSB9KTtcbiAgICAgIH0sXG4gICAgICB7IGFsbG93U2lnbmFsV3JpdGVzOiB0cnVlIH1cbiAgICApO1xuXG4gICAgLy8gU3luYyBGb3JtQ29udHJvbCDihpDihpIgZXN0YWRvIGVmZWN0aXZvLiBDdWFuZG8gZWwgZXN0YWRvIGNhbWJpYSAoY2FtYmlvIGRlXG4gICAgLy8gcGVybWlzc2lvbiBwb3IgZWwgYnJvd3NlciwgbyBzbmFwc2hvdCBGaXJlc3RvcmUgZGUgYG1hc3RlcmApLCBlbCB0b2dnbGUgc2VcbiAgICAvLyByZS1hbGluZWEgY29uIGxhIHJlYWxpZGFkLlxuICAgIC8vXG4gICAgLy8gSU1QT1JUQU5URTogc2UgaWdub3JhbiBsb3MgY2FtYmlvcyBtaWVudHJhcyBoYXkgdW5hIG9wZXJhY2nDs24gZW4gY3Vyc29cbiAgICAvLyAoYF9idXN5KCkgIT09IG51bGxgKS4gRHVyYW50ZSBgb25FbmFibGVgL2BvbkRpc2FibGVgIGxhcyBzZcOxYWxlcyBmdWVudGUgc2VcbiAgICAvLyBhY3R1YWxpemFuIGVuIG1vbWVudG9zIGRpc3RpbnRvcyB5IHByb2R1Y2lyw61hbiBlc3RhZG9zIGludGVybWVkaW9zIOKGklxuICAgIC8vIGZsaWNrZXIgdmlzaWJsZS4gRWwgdG9nZ2xlIHNlIHJlLWFsaW5lYSBVTkEgc29sYSB2ZXogZW4gZWwgYGZpbmFsbHlgLlxuICAgIGVmZmVjdChcbiAgICAgICgpID0+IHtcbiAgICAgICAgY29uc3QgZWZmID0gdGhpcy5pc0VuYWJsZWQoKTtcbiAgICAgICAgaWYgKHRoaXMuX2J1c3koKSAhPT0gbnVsbCkgcmV0dXJuO1xuICAgICAgICBpZiAodGhpcy50b2dnbGVDb250cm9sLnZhbHVlICE9PSBlZmYpIHtcbiAgICAgICAgICB0aGlzLnRvZ2dsZUNvbnRyb2wuc2V0VmFsdWUoZWZmLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICB7IGFsbG93U2lnbmFsV3JpdGVzOiB0cnVlIH1cbiAgICApO1xuXG4gICAgLy8gSW50ZXJjZXB0YXIgY2xpY2sgZGVsIHVzZXI6IGVsIHRvZ2dsZSB5YSBjYW1iacOzIHZpc3VhbG1lbnRlLCBlamVjdXRhclxuICAgIC8vIGxhIGFjY2nDs24gY29ycmVzcG9uZGllbnRlLlxuICAgIHRoaXMudG9nZ2xlQ29udHJvbC52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKHYgPT4ge1xuICAgICAgaWYgKHRoaXMuX2J1c3koKSAhPT0gbnVsbCkgcmV0dXJuO1xuICAgICAgaWYgKHYgJiYgIXRoaXMuaXNFbmFibGVkKCkpIHtcbiAgICAgICAgdm9pZCB0aGlzLm9uRW5hYmxlKCk7XG4gICAgICB9IGVsc2UgaWYgKCF2ICYmIHRoaXMuaXNFbmFibGVkKCkpIHtcbiAgICAgICAgdm9pZCB0aGlzLm9uRGlzYWJsZSgpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gRGV0ZWN0YXIgcmVncmVzbyBhIGxhIHBlc3Rhw7FhIOKAlCBlbCB1c2VyIHB1ZG8gaGFiZXIgY2FtYmlhZG8gcGVybWlzb3NcbiAgICAvLyBkZXNkZSBsYSBjb25maWcgZGVsIGJyb3dzZXIuIEVsIHJlZnJlc2ggdmEgY29uIGRlYm91bmNlIHBhcmEgbm9cbiAgICAvLyBkaXNwYXJhcnNlIGVuIHLDoWZhZ2FzIChlbiBQV0EgbW9iaWxlIGBmb2N1c2Agc2FsdGEgY29uIGNhZGEgY2FtYmlvIGRlXG4gICAgLy8gYXBwIC8gYXBhcmljacOzbiBkZWwgdGVjbGFkbykuIEVsIGxpc3RlbmVyIHNlIHJlbXVldmUgZW4gbmdPbkRlc3Ryb3kuXG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignZm9jdXMnLCB0aGlzLm9uV2luZG93Rm9jdXMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RyYSBlbCBwdWxsLXRvLXJlZnJlc2ggZXN0w6FuZGFyLiBBdW5xdWUgZXN0YSB2aXN0YSBubyBtdWVzdHJhIHVuYVxuICAgKiBsaXN0YSByZW1vdGEsIHPDrSByZWZsZWphIGVzdGFkbyBtdXRhYmxlIGRlbCBicm93c2VyIChwZXJtaXNvLCB0b2tlbixcbiAgICogc29wb3J0ZSBGQ00pIHF1ZSBwdWVkZSBjYW1iaWFyIGZ1ZXJhIGRlIGxhIGFwcCDigJQgZWwgcmVmcmVzaCByZS1ldmFsw7phIHRvZG8uXG4gICAqXG4gICAqIFNlIHVzYSBgbmdPbkluaXRgL2BuZ09uRGVzdHJveWAgKE5PIGBpb25WaWV3V2lsbEVudGVyYCkgcG9ycXVlXG4gICAqIGB2YWwtcGFnZS13cmFwcGVyYCB1c2EgYDxyb3V0ZXItb3V0bGV0PmAgcGxhbm8g4oCUIGxvcyBob29rcyBgaW9uVmlldypgIHNvbG9cbiAgICogZGlzcGFyYW4gZGVudHJvIGRlIGA8aW9uLXJvdXRlci1vdXRsZXQ+YC5cbiAgICovXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMucGFnZVJlZnJlc2gucmVnaXN0ZXIoKCkgPT4gdGhpcy5yZWZyZXNoQnJvd3NlclN0YXRlKCkpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5wYWdlUmVmcmVzaC51bnJlZ2lzdGVyKCk7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignZm9jdXMnLCB0aGlzLm9uV2luZG93Rm9jdXMpO1xuICAgIH1cbiAgICBpZiAodGhpcy5mb2N1c0RlYm91bmNlVGltZXIgIT09IG51bGwpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmZvY3VzRGVib3VuY2VUaW1lcik7XG4gICAgICB0aGlzLmZvY3VzRGVib3VuY2VUaW1lciA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqIFJlZnJlc2NhIGVsIGVzdGFkbyBkZWwgYnJvd3NlciBjb24gZGVib3VuY2Ug4oCUIGV2aXRhIHLDoWZhZ2FzIGRlIGBmb2N1c2AuICovXG4gIHByaXZhdGUgc2NoZWR1bGVCcm93c2VyUmVmcmVzaCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5mb2N1c0RlYm91bmNlVGltZXIgIT09IG51bGwpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLmZvY3VzRGVib3VuY2VUaW1lcik7XG4gICAgfVxuICAgIHRoaXMuZm9jdXNEZWJvdW5jZVRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmZvY3VzRGVib3VuY2VUaW1lciA9IG51bGw7XG4gICAgICB2b2lkIHRoaXMucmVmcmVzaEJyb3dzZXJTdGF0ZSgpO1xuICAgIH0sIHRoaXMuRk9DVVNfREVCT1VOQ0VfTVMpO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIEFjdGlvbnNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLyoqXG4gICAqIFNlY3VlbmNpYSBjb21wbGV0YSBkZSBhY3RpdmFjacOzbi5cbiAgICpcbiAgICogVG9kYSBsYSBtZWPDoW5pY2EgKHBlcm1pc3Npb24g4oaSIFNXIHJlYWR5IOKGkiBnZXRUb2tlbiBjb24gcmV0cnkg4oaSIHdhdGNoZG9nIGRlXG4gICAqIGF1dG8tcmVsb2FkKSB2aXZlIGVuIGBNZXNzYWdpbmdTZXJ2aWNlLmVuYWJsZSgpYCBkZSBsYSBsaWIuIEVsIHBhc28gZGVcbiAgICogcmVnaXN0cm8gZGVsIGRldmljZSBlbiBlbCBiYWNrZW5kIHNlIHBhc2EgY29tbyBjYWxsYmFjayAoYHJlZ2lzdGVyRGV2aWNlYClcbiAgICogcG9ycXVlIGxhIGxpYiBubyBwdWVkZSBkZXBlbmRlciBkZSBgQXV0aFNlcnZpY2VgIHNpbiBjcmVhciB1biBjaWNsby5cbiAgICpcbiAgICogYGVuYWJsZSgpYCBubyBoYWNlIHRocm93OiByZXN1ZWx2ZSBjb24gdW4gYEVuYWJsZVB1c2hSZXN1bHRgIGRlc2NyaXB0aXZvLlxuICAgKi9cbiAgYXN5bmMgb25FbmFibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fYnVzeS5zZXQoJ2VuYWJsaW5nJyk7XG4gICAgdGhpcy5fbGFzdEZhaWxlZC5zZXQoZmFsc2UpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdDogRW5hYmxlUHVzaFJlc3VsdCA9IGF3YWl0IHRoaXMubWVzc2FnaW5nLmVuYWJsZSh7XG4gICAgICAgIHJlZ2lzdGVyRGV2aWNlOiB0b2tlbiA9PiB0aGlzLmF1dGgucmVnaXN0ZXJEZXZpY2UodG9rZW4pLnRoZW4ociA9PiByLnJlZ2lzdGVyZWQpLFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChyZXN1bHQuc3RhdHVzID09PSAnZW5hYmxlZCcpIHtcbiAgICAgICAgLy8gUGVyc2lzdGlyIGZsYWcgbWFzdGVyIHNpIGHDum4gbm8gZXN0YWJhIGFjdGl2by5cbiAgICAgICAgaWYgKCF0aGlzLnByZWZzLm5vdGlmaWNhdGlvbnNNYXN0ZXIoKSkge1xuICAgICAgICAgIGF3YWl0IHRoaXMucHJlZnMuc2V0Tm90aWZpY2F0aW9uc01hc3Rlcih0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRvYXN0LnNob3coe1xuICAgICAgICAgIG1lc3NhZ2U6IHRoaXMudHQoJ2VuYWJsZVN1Y2Nlc3MnKSxcbiAgICAgICAgICBkdXJhdGlvbjogMjAwMCxcbiAgICAgICAgICBjb2xvcjogJ2RhcmsnLFxuICAgICAgICAgIHBvc2l0aW9uOiAndG9wJyxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMucmVzb2x2ZWRDb25maWcoKS5vblB1c2hFbmFibGVkPy4oKTtcbiAgICAgIH0gZWxzZSBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ3RpbWVvdXQnICYmIHJlc3VsdC5yZWxvYWRlZCkge1xuICAgICAgICAvLyBMYSBsaWIgZGlzcGFyw7MgZWwgYXV0by1yZWxvYWQg4oCUIGxhIHDDoWdpbmEgZXN0w6EgcG9yIHJlY2FyZ2Fyc2UuXG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGRlbmllZCAvIHVuc3VwcG9ydGVkIC8gZXJyb3IgLyB0aW1lb3V0IHNpbiByZWxvYWQg4oaSIGZhbGxvIHJlY3VwZXJhYmxlLlxuICAgICAgICB0aGlzLl9sYXN0RmFpbGVkLnNldCh0cnVlKTtcbiAgICAgICAgdGhpcy50b2FzdC5zaG93KHtcbiAgICAgICAgICBtZXNzYWdlOiB0aGlzLnR0KCdlcnJvckdlbmVyaWMnKSxcbiAgICAgICAgICBkdXJhdGlvbjogMzAwMCxcbiAgICAgICAgICBjb2xvcjogJ2RhcmsnLFxuICAgICAgICAgIHBvc2l0aW9uOiAndG9wJyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBgZW5hYmxlKClgIG5vIGhhY2UgdGhyb3csIHBlcm8gZWwgY2FsbGJhY2sgZGUgcmVnaXN0cm8gc8OtIHB1ZWRlLlxuICAgICAgdGhpcy5fbGFzdEZhaWxlZC5zZXQodHJ1ZSk7XG4gICAgICB0aGlzLnRvYXN0LnNob3coe1xuICAgICAgICBtZXNzYWdlOiB0aGlzLnR0KCdlcnJvckdlbmVyaWMnKSxcbiAgICAgICAgZHVyYXRpb246IDMwMDAsXG4gICAgICAgIGNvbG9yOiAnZGFyaycsXG4gICAgICAgIHBvc2l0aW9uOiAndG9wJyxcbiAgICAgIH0pO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAvLyDDmm5pY28gcmVmcmVzaCBmaW5hbDogcmUtYWxpbmVhIGVsIHRvZ2dsZSBVTkEgc29sYSB2ZXogY29uIGVsIGVzdGFkbyByZWFsLlxuICAgICAgYXdhaXQgdGhpcy5yZWZyZXNoQnJvd3NlclN0YXRlKCk7XG4gICAgICB0aGlzLl9idXN5LnNldChudWxsKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBvbkRpc2FibGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fYnVzeS5zZXQoJ2Rpc2FibGluZycpO1xuICAgIHRoaXMuX2xhc3RGYWlsZWQuc2V0KGZhbHNlKTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmF1dGguZGlzYWJsZU5vdGlmaWNhdGlvbnMoKTtcbiAgICAgIGlmICh0aGlzLnByZWZzLm5vdGlmaWNhdGlvbnNNYXN0ZXIoKSkge1xuICAgICAgICBhd2FpdCB0aGlzLnByZWZzLnNldE5vdGlmaWNhdGlvbnNNYXN0ZXIoZmFsc2UpO1xuICAgICAgfVxuICAgICAgdGhpcy50b2FzdC5zaG93KHtcbiAgICAgICAgbWVzc2FnZTogdGhpcy50dCgnZGlzYWJsZVN1Y2Nlc3MnKSxcbiAgICAgICAgZHVyYXRpb246IDIwMDAsXG4gICAgICAgIGNvbG9yOiAnZGFyaycsXG4gICAgICAgIHBvc2l0aW9uOiAndG9wJyxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5yZXNvbHZlZENvbmZpZygpLm9uUHVzaERpc2FibGVkPy4oKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRoaXMuX2xhc3RGYWlsZWQuc2V0KHRydWUpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCB0aGlzLnJlZnJlc2hCcm93c2VyU3RhdGUoKTtcbiAgICAgIHRoaXMuX2J1c3kuc2V0KG51bGwpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSZWludGVudGFyIGxhIHNlY3VlbmNpYSBjb21wbGV0YSBkZSBhY3RpdmFjacOzbiwgc2luIGltcG9ydGFyIGVsIGVzdGFkbyBhY3R1YWwuICovXG4gIGFzeW5jIG9uUmV0cnkoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5fbGFzdEZhaWxlZC5zZXQoZmFsc2UpO1xuICAgIGF3YWl0IHRoaXMub25FbmFibGUoKTtcbiAgfVxuXG4gIHRvZ2dsZURldGFpbHMoKTogdm9pZCB7XG4gICAgdGhpcy5zaG93RGV0YWlscy51cGRhdGUodiA9PiAhdik7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gUHJpdmFkb3NcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcHJpdmF0ZSBhc3luYyByZWZyZXNoQnJvd3NlclN0YXRlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuaXNTdXBwb3J0ZWQuc2V0KGF3YWl0IHRoaXMubWVzc2FnaW5nLmlzU3VwcG9ydGVkKCkpO1xuICAgIHRoaXMucGVybWlzc2lvbi5zZXQodGhpcy5hdXRoLmdldE5vdGlmaWNhdGlvblBlcm1pc3Npb25TdGF0ZSgpKTtcbiAgICB0aGlzLmN1cnJlbnRUb2tlbi5zZXQodGhpcy5tZXNzYWdpbmcuY3VycmVudFRva2VuID8/IG51bGwpO1xuICAgIHZvaWQgdGhpcy5yZXBhaXJUb2tlbklmTmVlZGVkKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVwYXJhIGVsIHRva2VuIEZDTSBlbiBiYWNrZ3JvdW5kLlxuICAgKlxuICAgKiBTaSBlbCB1c3VhcmlvIHRpZW5lIHB1c2ggYWN0aXZvIChgbWFzdGVyICYmIGdyYW50ZWRgKSBwZXJvIG5vIGhheSB0b2tlbiBlblxuICAgKiBtZW1vcmlhIOKAlCBjYXNvIHTDrXBpY28gdHJhcyB1biBjb2xkIHN0YXJ0IGRlIGxhIFBXQSDigJQgcmUtb2J0ZW5lbW9zIGVsIHRva2VuXG4gICAqIHkgcmUtcmVnaXN0cmFtb3MgZWwgZGV2aWNlIHNpbiB0b2NhciBlbCB0b2dnbGUgbmkgbW9zdHJhciB1biBlcnJvclxuICAgKiBhbGFybWlzdGEuIEVsIHRva2VuIGVzIHVuIGRldGFsbGUgZGUgaW1wbGVtZW50YWNpw7NuIHJlcGFyYWJsZSwgbm8gcGFydGUgZGVsXG4gICAqIGVzdGFkbyBkZSBVSSAodmVyIGBpc0VuYWJsZWRgKS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcmVwYWlyVG9rZW5JZk5lZWRlZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5fYnVzeSgpICE9PSBudWxsKSByZXR1cm47XG4gICAgaWYgKHRoaXMuX3JlcGFpcmluZ1Rva2VuKSByZXR1cm47XG4gICAgaWYgKCF0aGlzLmlzRW5hYmxlZCgpKSByZXR1cm47XG4gICAgaWYgKHRoaXMuY3VycmVudFRva2VuKCkpIHJldHVybjtcblxuICAgIHRoaXMuX3JlcGFpcmluZ1Rva2VuID0gdHJ1ZTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgdG9rZW4gPSBhd2FpdCB0aGlzLm1lc3NhZ2luZy5nZXRUb2tlbigpO1xuICAgICAgaWYgKHRva2VuKSB7XG4gICAgICAgIHRoaXMuY3VycmVudFRva2VuLnNldCh0b2tlbik7XG4gICAgICAgIGF3YWl0IHRoaXMuYXV0aC5yZWdpc3RlckRldmljZSh0b2tlbik7XG4gICAgICB9XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBSZXBhcmFjacOzbiBiZXN0LWVmZm9ydDogbm8gZGVncmFkYW1vcyBlbCB0b2dnbGUgbmkgbW9zdHJhbW9zIGVycm9yLlxuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLl9yZXBhaXJpbmdUb2tlbiA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBpT1MgYnJvd3NlciBzaW4gZXN0YXIgaW5zdGFsYWRvIGNvbW8gUFdBIOKAlCBwdXNoIHdlYiBubyBkaXNwb25pYmxlLlxuICAgKiBBcGxpY2EgYSBTYWZhcmkgeSBhIEVkZ2UvQ2hyb21lL0ZpcmVmb3ggZW4gaU9TICh0b2RvcyBXZWJLaXQgcG9yIG1hbmRhdG8gQXBwbGUpLlxuICAgKi9cbiAgcHJpdmF0ZSBkZXRlY3ROZWVkc0lPU0luc3RhbGwoKTogYm9vbGVhbiB7XG4gICAgaWYgKHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnIHx8IHR5cGVvZiBuYXZpZ2F0b3IgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IHVhID0gbmF2aWdhdG9yLnVzZXJBZ2VudCB8fCAnJztcbiAgICBjb25zdCBpc0lPUyA9IC9pUGFkfGlQaG9uZXxpUG9kLy50ZXN0KHVhKTtcbiAgICBpZiAoIWlzSU9TKSByZXR1cm4gZmFsc2U7XG4gICAgY29uc3QgaXNTdGFuZGFsb25lID1cbiAgICAgIHdpbmRvdy5tYXRjaE1lZGlhPy4oJyhkaXNwbGF5LW1vZGU6IHN0YW5kYWxvbmUpJykubWF0Y2hlcyB8fFxuICAgICAgKG5hdmlnYXRvciBhcyB1bmtub3duIGFzIHsgc3RhbmRhbG9uZT86IGJvb2xlYW4gfSkuc3RhbmRhbG9uZSA9PT0gdHJ1ZTtcbiAgICByZXR1cm4gIWlzU3RhbmRhbG9uZTtcbiAgfVxuXG4gIHByb3RlY3RlZCB0dChrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuaTE4bi50KGtleSwgdGhpcy5ucyk7XG4gIH1cbn1cbiJdfQ==