valtech-components 2.0.449 → 2.0.451
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/atoms/fab/fab.component.mjs +4 -5
- package/esm2022/lib/components/templates/page-template/page-template.component.mjs +5 -3
- package/esm2022/lib/services/link-processor.service.mjs +43 -61
- package/esm2022/lib/services/modal/modal.service.mjs +9 -8
- package/esm2022/public-api.mjs +4 -24
- package/fesm2022/valtech-components-simple-modal-content.component-DQhEgUmS.mjs +136 -0
- package/fesm2022/valtech-components-simple-modal-content.component-DQhEgUmS.mjs.map +1 -0
- package/fesm2022/valtech-components.mjs +59 -3093
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/fab/fab.component.d.ts +1 -2
- package/lib/services/modal/modal.service.d.ts +0 -2
- package/package.json +1 -3
- package/public-api.d.ts +0 -8
- package/esm2022/lib/components/organisms/tabbed-content/tabbed-content.component.mjs +0 -170
- package/esm2022/lib/components/organisms/tabbed-content/types.mjs +0 -2
- package/esm2022/lib/services/firebase/config.mjs +0 -108
- package/esm2022/lib/services/firebase/firebase.service.mjs +0 -285
- package/esm2022/lib/services/firebase/firestore-collection.mjs +0 -254
- package/esm2022/lib/services/firebase/firestore.service.mjs +0 -508
- package/esm2022/lib/services/firebase/index.mjs +0 -49
- package/esm2022/lib/services/firebase/messaging.service.mjs +0 -503
- package/esm2022/lib/services/firebase/shared-config.mjs +0 -138
- package/esm2022/lib/services/firebase/storage.service.mjs +0 -421
- package/esm2022/lib/services/firebase/types.mjs +0 -8
- package/esm2022/lib/services/firebase/utils/path-builder.mjs +0 -195
- package/esm2022/lib/services/firebase/utils/query-builder.mjs +0 -302
- package/lib/components/organisms/tabbed-content/tabbed-content.component.d.ts +0 -65
- package/lib/components/organisms/tabbed-content/types.d.ts +0 -53
- package/lib/services/firebase/config.d.ts +0 -49
- package/lib/services/firebase/firebase.service.d.ts +0 -140
- package/lib/services/firebase/firestore-collection.d.ts +0 -174
- package/lib/services/firebase/firestore.service.d.ts +0 -303
- package/lib/services/firebase/index.d.ts +0 -39
- package/lib/services/firebase/messaging.service.d.ts +0 -254
- package/lib/services/firebase/shared-config.d.ts +0 -126
- package/lib/services/firebase/storage.service.d.ts +0 -204
- package/lib/services/firebase/types.d.ts +0 -281
- package/lib/services/firebase/utils/path-builder.d.ts +0 -132
- package/lib/services/firebase/utils/query-builder.d.ts +0 -210
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firebase Service
|
|
3
|
-
*
|
|
4
|
-
* Servicio principal para la autenticación con Firebase usando Custom Tokens.
|
|
5
|
-
* Permite que usuarios autenticados con tu backend (Cognito, etc.) accedan
|
|
6
|
-
* a servicios de Firebase (Firestore, Storage, FCM) de manera segura.
|
|
7
|
-
*/
|
|
8
|
-
import { inject, Injectable } from '@angular/core';
|
|
9
|
-
import { Auth, authState, signInWithCustomToken, signOut } from '@angular/fire/auth';
|
|
10
|
-
import { BehaviorSubject, distinctUntilChanged, map } from 'rxjs';
|
|
11
|
-
import { VALTECH_FIREBASE_CONFIG } from './config';
|
|
12
|
-
import * as i0 from "@angular/core";
|
|
13
|
-
/**
|
|
14
|
-
* Servicio de autenticación de Firebase.
|
|
15
|
-
*
|
|
16
|
-
* Este servicio NO maneja el login de usuarios directamente.
|
|
17
|
-
* En su lugar, trabaja con Custom Tokens generados por tu backend.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* // Después de autenticarte con tu backend (ej: Cognito)
|
|
22
|
-
* @Component({...})
|
|
23
|
-
* export class LoginComponent {
|
|
24
|
-
* private authService = inject(AuthService); // Tu servicio de auth
|
|
25
|
-
* private firebase = inject(FirebaseService); // Este servicio
|
|
26
|
-
*
|
|
27
|
-
* async login(email: string, password: string) {
|
|
28
|
-
* // 1. Autenticar con tu backend
|
|
29
|
-
* const response = await this.authService.login(email, password);
|
|
30
|
-
*
|
|
31
|
-
* // 2. El backend devuelve un Firebase Custom Token
|
|
32
|
-
* if (response.firebaseToken) {
|
|
33
|
-
* await this.firebase.signInWithCustomToken(response.firebaseToken);
|
|
34
|
-
* }
|
|
35
|
-
*
|
|
36
|
-
* // Ahora el usuario puede acceder a Firestore, Storage, etc.
|
|
37
|
-
* }
|
|
38
|
-
*
|
|
39
|
-
* async logout() {
|
|
40
|
-
* await this.authService.logout();
|
|
41
|
-
* await this.firebase.signOut();
|
|
42
|
-
* }
|
|
43
|
-
* }
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
export class FirebaseService {
|
|
47
|
-
constructor() {
|
|
48
|
-
this.auth = inject(Auth);
|
|
49
|
-
this.config = inject(VALTECH_FIREBASE_CONFIG);
|
|
50
|
-
/** Estado interno de la sesión */
|
|
51
|
-
this.sessionState = new BehaviorSubject({
|
|
52
|
-
user: null,
|
|
53
|
-
isAuthenticated: false,
|
|
54
|
-
isLoading: true,
|
|
55
|
-
error: null,
|
|
56
|
-
});
|
|
57
|
-
/** Estado actual de la sesión como Observable */
|
|
58
|
-
this.state$ = this.sessionState.asObservable();
|
|
59
|
-
/** Usuario actual de Firebase como Observable */
|
|
60
|
-
this.user$ = authState(this.auth).pipe(map((user) => (user ? this.mapUser(user) : null)), distinctUntilChanged((a, b) => a?.uid === b?.uid));
|
|
61
|
-
/** Indica si el usuario está autenticado en Firebase */
|
|
62
|
-
this.isAuthenticated$ = this.user$.pipe(map((user) => !!user), distinctUntilChanged());
|
|
63
|
-
// Escuchar cambios en el estado de autenticación
|
|
64
|
-
authState(this.auth).subscribe({
|
|
65
|
-
next: (user) => {
|
|
66
|
-
this.sessionState.next({
|
|
67
|
-
user: user ? this.mapUser(user) : null,
|
|
68
|
-
isAuthenticated: !!user,
|
|
69
|
-
isLoading: false,
|
|
70
|
-
error: null,
|
|
71
|
-
});
|
|
72
|
-
},
|
|
73
|
-
error: (error) => {
|
|
74
|
-
this.sessionState.next({
|
|
75
|
-
user: null,
|
|
76
|
-
isAuthenticated: false,
|
|
77
|
-
isLoading: false,
|
|
78
|
-
error,
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
// ===========================================================================
|
|
84
|
-
// AUTENTICACIÓN
|
|
85
|
-
// ===========================================================================
|
|
86
|
-
/**
|
|
87
|
-
* Autentica al usuario con un Custom Token generado por el backend.
|
|
88
|
-
*
|
|
89
|
-
* @param token - Firebase Custom Token generado por tu backend
|
|
90
|
-
* @returns UserCredential con la información del usuario
|
|
91
|
-
* @throws Error si el token es inválido o expiró
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```typescript
|
|
95
|
-
* // Después de login exitoso con tu backend
|
|
96
|
-
* const { firebaseToken } = await backendAuth.login(email, password);
|
|
97
|
-
* await firebaseService.signInWithCustomToken(firebaseToken);
|
|
98
|
-
* ```
|
|
99
|
-
*/
|
|
100
|
-
async signInWithCustomToken(token) {
|
|
101
|
-
try {
|
|
102
|
-
const credential = await signInWithCustomToken(this.auth, token);
|
|
103
|
-
return credential;
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
const message = this.getErrorMessage(error);
|
|
107
|
-
throw new Error(message);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Cierra la sesión de Firebase.
|
|
112
|
-
* Llamar junto con el logout de tu sistema de autenticación principal.
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```typescript
|
|
116
|
-
* async logout() {
|
|
117
|
-
* await this.backendAuth.logout(); // Tu auth
|
|
118
|
-
* await this.firebase.signOut(); // Firebase
|
|
119
|
-
* }
|
|
120
|
-
* ```
|
|
121
|
-
*/
|
|
122
|
-
async signOut() {
|
|
123
|
-
try {
|
|
124
|
-
await signOut(this.auth);
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
const message = this.getErrorMessage(error);
|
|
128
|
-
throw new Error(message);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
// ===========================================================================
|
|
132
|
-
// GETTERS SÍNCRONOS
|
|
133
|
-
// ===========================================================================
|
|
134
|
-
/**
|
|
135
|
-
* Obtiene el usuario actual de Firebase (síncrono).
|
|
136
|
-
* Retorna null si no hay usuario autenticado.
|
|
137
|
-
*/
|
|
138
|
-
get currentUser() {
|
|
139
|
-
const user = this.auth.currentUser;
|
|
140
|
-
return user ? this.mapUser(user) : null;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Obtiene el UID del usuario actual.
|
|
144
|
-
* Retorna null si no hay usuario autenticado.
|
|
145
|
-
*/
|
|
146
|
-
get uid() {
|
|
147
|
-
return this.auth.currentUser?.uid ?? null;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Indica si hay un usuario autenticado actualmente.
|
|
151
|
-
*/
|
|
152
|
-
get isAuthenticated() {
|
|
153
|
-
return !!this.auth.currentUser;
|
|
154
|
-
}
|
|
155
|
-
// ===========================================================================
|
|
156
|
-
// TOKENS
|
|
157
|
-
// ===========================================================================
|
|
158
|
-
/**
|
|
159
|
-
* Obtiene el ID Token de Firebase para el usuario actual.
|
|
160
|
-
* Útil para validar el usuario en tu backend.
|
|
161
|
-
*
|
|
162
|
-
* @param forceRefresh - Si true, fuerza la renovación del token
|
|
163
|
-
* @returns ID Token o null si no hay usuario
|
|
164
|
-
*/
|
|
165
|
-
async getIdToken(forceRefresh = false) {
|
|
166
|
-
const user = this.auth.currentUser;
|
|
167
|
-
if (!user)
|
|
168
|
-
return null;
|
|
169
|
-
try {
|
|
170
|
-
return await user.getIdToken(forceRefresh);
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
return null;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Obtiene los claims personalizados del token del usuario.
|
|
178
|
-
* Los claims son establecidos por tu backend al crear el Custom Token.
|
|
179
|
-
*
|
|
180
|
-
* @returns Objeto con los claims o vacío si no hay usuario
|
|
181
|
-
*/
|
|
182
|
-
async getClaims() {
|
|
183
|
-
const user = this.auth.currentUser;
|
|
184
|
-
if (!user)
|
|
185
|
-
return {};
|
|
186
|
-
try {
|
|
187
|
-
const result = await user.getIdTokenResult();
|
|
188
|
-
return result.claims;
|
|
189
|
-
}
|
|
190
|
-
catch {
|
|
191
|
-
return {};
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Verifica si el usuario tiene un rol específico.
|
|
196
|
-
* El rol debe estar definido en los claims del Custom Token.
|
|
197
|
-
*
|
|
198
|
-
* @param role - Nombre del rol a verificar
|
|
199
|
-
* @returns true si el usuario tiene el rol
|
|
200
|
-
*/
|
|
201
|
-
async hasRole(role) {
|
|
202
|
-
const claims = await this.getClaims();
|
|
203
|
-
return claims['role'] === role || (Array.isArray(claims['roles']) && claims['roles'].includes(role));
|
|
204
|
-
}
|
|
205
|
-
// ===========================================================================
|
|
206
|
-
// UTILIDADES
|
|
207
|
-
// ===========================================================================
|
|
208
|
-
/**
|
|
209
|
-
* Espera a que el estado de autenticación esté determinado.
|
|
210
|
-
* Útil en guards o al inicializar la app.
|
|
211
|
-
*
|
|
212
|
-
* @returns Usuario actual o null
|
|
213
|
-
*/
|
|
214
|
-
waitForAuth() {
|
|
215
|
-
return new Promise((resolve) => {
|
|
216
|
-
const subscription = this.state$.subscribe((state) => {
|
|
217
|
-
if (!state.isLoading) {
|
|
218
|
-
subscription.unsubscribe();
|
|
219
|
-
resolve(state.user);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Obtiene la configuración actual de Firebase.
|
|
226
|
-
*/
|
|
227
|
-
getConfig() {
|
|
228
|
-
return this.config;
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Indica si los emuladores están habilitados.
|
|
232
|
-
*/
|
|
233
|
-
isUsingEmulators() {
|
|
234
|
-
return !!(this.config.emulator?.firestore || this.config.emulator?.auth || this.config.emulator?.storage);
|
|
235
|
-
}
|
|
236
|
-
// ===========================================================================
|
|
237
|
-
// MÉTODOS PRIVADOS
|
|
238
|
-
// ===========================================================================
|
|
239
|
-
/**
|
|
240
|
-
* Mapea un User de Firebase a nuestra interface FirebaseUser
|
|
241
|
-
*/
|
|
242
|
-
mapUser(user) {
|
|
243
|
-
return {
|
|
244
|
-
uid: user.uid,
|
|
245
|
-
email: user.email,
|
|
246
|
-
displayName: user.displayName,
|
|
247
|
-
photoURL: user.photoURL,
|
|
248
|
-
emailVerified: user.emailVerified,
|
|
249
|
-
isAnonymous: user.isAnonymous,
|
|
250
|
-
providerId: user.providerId,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Convierte errores de Firebase a mensajes en español
|
|
255
|
-
*/
|
|
256
|
-
getErrorMessage(error) {
|
|
257
|
-
if (error instanceof Error) {
|
|
258
|
-
const code = error.code;
|
|
259
|
-
switch (code) {
|
|
260
|
-
case 'auth/invalid-custom-token':
|
|
261
|
-
return 'Token de autenticación inválido';
|
|
262
|
-
case 'auth/custom-token-mismatch':
|
|
263
|
-
return 'El token no corresponde a este proyecto';
|
|
264
|
-
case 'auth/network-request-failed':
|
|
265
|
-
return 'Error de conexión. Verifica tu conexión a internet';
|
|
266
|
-
case 'auth/too-many-requests':
|
|
267
|
-
return 'Demasiados intentos. Intenta de nuevo más tarde';
|
|
268
|
-
case 'auth/user-disabled':
|
|
269
|
-
return 'Esta cuenta ha sido deshabilitada';
|
|
270
|
-
case 'auth/user-not-found':
|
|
271
|
-
return 'Usuario no encontrado';
|
|
272
|
-
default:
|
|
273
|
-
return error.message || 'Error de autenticación desconocido';
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
return 'Error de autenticación desconocido';
|
|
277
|
-
}
|
|
278
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirebaseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
279
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirebaseService, providedIn: 'root' }); }
|
|
280
|
-
}
|
|
281
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirebaseService, decorators: [{
|
|
282
|
-
type: Injectable,
|
|
283
|
-
args: [{ providedIn: 'root' }]
|
|
284
|
-
}], ctorParameters: () => [] });
|
|
285
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlyZWJhc2Uuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvZmlyZWJhc2UvZmlyZWJhc2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRCxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxxQkFBcUIsRUFBRSxPQUFPLEVBQXdCLE1BQU0sb0JBQW9CLENBQUM7QUFDM0csT0FBTyxFQUFFLGVBQWUsRUFBRSxvQkFBb0IsRUFBRSxHQUFHLEVBQWMsTUFBTSxNQUFNLENBQUM7QUFFOUUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sVUFBVSxDQUFDOztBQUduRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQ0c7QUFFSCxNQUFNLE9BQU8sZUFBZTtJQTJCMUI7UUExQlEsU0FBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQixXQUFNLEdBQUcsTUFBTSxDQUFDLHVCQUF1QixDQUFDLENBQUM7UUFFakQsa0NBQWtDO1FBQzFCLGlCQUFZLEdBQUcsSUFBSSxlQUFlLENBQWU7WUFDdkQsSUFBSSxFQUFFLElBQUk7WUFDVixlQUFlLEVBQUUsS0FBSztZQUN0QixTQUFTLEVBQUUsSUFBSTtZQUNmLEtBQUssRUFBRSxJQUFJO1NBQ1osQ0FBQyxDQUFDO1FBRUgsaURBQWlEO1FBQ3hDLFdBQU0sR0FBNkIsSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUU3RSxpREFBaUQ7UUFDeEMsVUFBSyxHQUFvQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FDekUsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENB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QyxVQUFVO1NBQzVCLENBQUM7SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSyxlQUFlLENBQUMsS0FBYztRQUNwQyxJQUFJLEtBQUssWUFBWSxLQUFLLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksR0FBSSxLQUEyQixDQUFDLElBQUksQ0FBQztZQUUvQyxRQUFRLElBQUksRUFBRSxDQUFDO2dCQUNiLEtBQUssMkJBQTJCO29CQUM5QixPQUFPLGlDQUFpQyxDQUFDO2dCQUMzQyxLQUFLLDRCQUE0QjtvQkFDL0IsT0FBTyx5Q0FBeUMsQ0FBQztnQkFDbkQsS0FBSyw2QkFBNkI7b0JBQ2hDLE9BQU8sb0RBQW9ELENBQUM7Z0JBQzlELEtBQUssd0JBQXdCO29CQUMzQixPQUFPLGlEQUFpRCxDQUFDO2dCQUMzRCxLQUFLLG9CQUFvQjtvQkFDdkIsT0FBTyxtQ0FBbUMsQ0FBQztnQkFDN0MsS0FBSyxxQkFBcUI7b0JBQ3hCLE9BQU8sdUJBQXVCLENBQUM7Z0JBQ2pDO29CQUNFLE9BQU8sS0FBSyxDQUFDLE9BQU8sSUFBSSxvQ0FBb0MsQ0FBQztZQUNqRSxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sb0NBQW9DLENBQUM7SUFDOUMsQ0FBQzsrR0FsUVUsZUFBZTttSEFBZixlQUFlLGNBREYsTUFBTTs7NEZBQ25CLGVBQWU7a0JBRDNCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGaXJlYmFzZSBTZXJ2aWNlXG4gKlxuICogU2VydmljaW8gcHJpbmNpcGFsIHBhcmEgbGEgYXV0ZW50aWNhY2nDs24gY29uIEZpcmViYXNlIHVzYW5kbyBDdXN0b20gVG9rZW5zLlxuICogUGVybWl0ZSBxdWUgdXN1YXJpb3MgYXV0ZW50aWNhZG9zIGNvbiB0dSBiYWNrZW5kIChDb2duaXRvLCBldGMuKSBhY2NlZGFuXG4gKiBhIHNlcnZpY2lvcyBkZSBGaXJlYmFzZSAoRmlyZXN0b3JlLCBTdG9yYWdlLCBGQ00pIGRlIG1hbmVyYSBzZWd1cmEuXG4gKi9cblxuaW1wb3J0IHsgaW5qZWN0LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBdXRoLCBhdXRoU3RhdGUsIHNpZ25JbldpdGhDdXN0b21Ub2tlbiwgc2lnbk91dCwgVXNlciwgVXNlckNyZWRlbnRpYWwgfSBmcm9tICdAYW5ndWxhci9maXJlL2F1dGgnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgbWFwLCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IFZBTFRFQ0hfRklSRUJBU0VfQ09ORklHIH0gZnJvbSAnLi9jb25maWcnO1xuaW1wb3J0IHsgRmlyZWJhc2VVc2VyLCBTZXNzaW9uU3RhdGUsIFZhbHRlY2hGaXJlYmFzZUNvbmZpZyB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKipcbiAqIFNlcnZpY2lvIGRlIGF1dGVudGljYWNpw7NuIGRlIEZpcmViYXNlLlxuICpcbiAqIEVzdGUgc2VydmljaW8gTk8gbWFuZWphIGVsIGxvZ2luIGRlIHVzdWFyaW9zIGRpcmVjdGFtZW50ZS5cbiAqIEVuIHN1IGx1Z2FyLCB0cmFiYWphIGNvbiBDdXN0b20gVG9rZW5zIGdlbmVyYWRvcyBwb3IgdHUgYmFja2VuZC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gRGVzcHXDqXMgZGUgYXV0ZW50aWNhcnRlIGNvbiB0dSBiYWNrZW5kIChlajogQ29nbml0bylcbiAqIEBDb21wb25lbnQoey4uLn0pXG4gKiBleHBvcnQgY2xhc3MgTG9naW5Db21wb25lbnQge1xuICogICBwcml2YXRlIGF1dGhTZXJ2aWNlID0gaW5qZWN0KEF1dGhTZXJ2aWNlKTsgICAgIC8vIFR1IHNlcnZpY2lvIGRlIGF1dGhcbiAqICAgcHJpdmF0ZSBmaXJlYmFzZSA9IGluamVjdChGaXJlYmFzZVNlcnZpY2UpOyAgICAvLyBFc3RlIHNlcnZpY2lvXG4gKlxuICogICBhc3luYyBsb2dpbihlbWFpbDogc3RyaW5nLCBwYXNzd29yZDogc3RyaW5nKSB7XG4gKiAgICAgLy8gMS4gQXV0ZW50aWNhciBjb24gdHUgYmFja2VuZFxuICogICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5hdXRoU2VydmljZS5sb2dpbihlbWFpbCwgcGFzc3dvcmQpO1xuICpcbiAqICAgICAvLyAyLiBFbCBiYWNrZW5kIGRldnVlbHZlIHVuIEZpcmViYXNlIEN1c3RvbSBUb2tlblxuICogICAgIGlmIChyZXNwb25zZS5maXJlYmFzZVRva2VuKSB7XG4gKiAgICAgICBhd2FpdCB0aGlzLmZpcmViYXNlLnNpZ25JbldpdGhDdXN0b21Ub2tlbihyZXNwb25zZS5maXJlYmFzZVRva2VuKTtcbiAqICAgICB9XG4gKlxuICogICAgIC8vIEFob3JhIGVsIHVzdWFyaW8gcHVlZGUgYWNjZWRlciBhIEZpcmVzdG9yZSwgU3RvcmFnZSwgZXRjLlxuICogICB9XG4gKlxuICogICBhc3luYyBsb2dvdXQoKSB7XG4gKiAgICAgYXdhaXQgdGhpcy5hdXRoU2VydmljZS5sb2dvdXQoKTtcbiAqICAgICBhd2FpdCB0aGlzLmZpcmViYXNlLnNpZ25PdXQoKTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgRmlyZWJhc2VTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBhdXRoID0gaW5qZWN0KEF1dGgpO1xuICBwcml2YXRlIGNvbmZpZyA9IGluamVjdChWQUxURUNIX0ZJUkVCQVNFX0NPTkZJRyk7XG5cbiAgLyoqIEVzdGFkbyBpbnRlcm5vIGRlIGxhIHNlc2nDs24gKi9cbiAgcHJpdmF0ZSBzZXNzaW9uU3RhdGUgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PFNlc3Npb25TdGF0ZT4oe1xuICAgIHVzZXI6IG51bGwsXG4gICAgaXNBdXRoZW50aWNhdGVkOiBmYWxzZSxcbiAgICBpc0xvYWRpbmc6IHRydWUsXG4gICAgZXJyb3I6IG51bGwsXG4gIH0pO1xuXG4gIC8qKiBFc3RhZG8gYWN0dWFsIGRlIGxhIHNlc2nDs24gY29tbyBPYnNlcnZhYmxlICovXG4gIHJlYWRvbmx5IHN0YXRlJDogT2JzZXJ2YWJsZTxTZXNzaW9uU3RhdGU+ID0gdGhpcy5zZXNzaW9uU3RhdGUuYXNPYnNlcnZhYmxlKCk7XG5cbiAgLyoqIFVzdWFyaW8gYWN0dWFsIGRlIEZpcmViYXNlIGNvbW8gT2JzZXJ2YWJsZSAqL1xuICByZWFkb25seSB1c2VyJDogT2JzZXJ2YWJsZTxGaXJlYmFzZVVzZXIgfCBudWxsPiA9IGF1dGhTdGF0ZSh0aGlzLmF1dGgpLnBpcGUoXG4gICAgbWFwKCh1c2VyKSA9PiAodXNlciA/IHRoaXMubWFwVXNlcih1c2VyKSA6IG51bGwpKSxcbiAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgoYSwgYikgPT4gYT8udWlkID09PSBiPy51aWQpXG4gICk7XG5cbiAgLyoqIEluZGljYSBzaSBlbCB1c3VhcmlvIGVzdMOhIGF1dGVudGljYWRvIGVuIEZpcmViYXNlICovXG4gIHJlYWRvbmx5IGlzQXV0aGVudGljYXRlZCQ6IE9ic2VydmFibGU8Ym9vbGVhbj4gPSB0aGlzLnVzZXIkLnBpcGUoXG4gICAgbWFwKCh1c2VyKSA9PiAhIXVzZXIpLFxuICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgKTtcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICAvLyBFc2N1Y2hhciBjYW1iaW9zIGVuIGVsIGVzdGFkbyBkZSBhdXRlbnRpY2FjacOzblxuICAgIGF1dGhTdGF0ZSh0aGlzLmF1dGgpLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAodXNlcikgPT4ge1xuICAgICAgICB0aGlzLnNlc3Npb25TdGF0ZS5uZXh0KHtcbiAgICAgICAgICB1c2VyOiB1c2VyID8gdGhpcy5tYXBVc2VyKHVzZXIpIDogbnVsbCxcbiAgICAgICAgICBpc0F1dGhlbnRpY2F0ZWQ6ICEhdXNlcixcbiAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgIGVycm9yOiBudWxsLFxuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKGVycm9yKSA9PiB7XG4gICAgICAgIHRoaXMuc2Vzc2lvblN0YXRlLm5leHQoe1xuICAgICAgICAgIHVzZXI6IG51bGwsXG4gICAgICAgICAgaXNBdXRoZW50aWNhdGVkOiBmYWxzZSxcbiAgICAgICAgICBpc0xvYWRpbmc6IGZhbHNlLFxuICAgICAgICAgIGVycm9yLFxuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gQVVURU5USUNBQ0nDk05cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIEF1dGVudGljYSBhbCB1c3VhcmlvIGNvbiB1biBDdXN0b20gVG9rZW4gZ2VuZXJhZG8gcG9yIGVsIGJhY2tlbmQuXG4gICAqXG4gICAqIEBwYXJhbSB0b2tlbiAtIEZpcmViYXNlIEN1c3RvbSBUb2tlbiBnZW5lcmFkbyBwb3IgdHUgYmFja2VuZFxuICAgKiBAcmV0dXJucyBVc2VyQ3JlZGVudGlhbCBjb24gbGEgaW5mb3JtYWNpw7NuIGRlbCB1c3VhcmlvXG4gICAqIEB0aHJvd3MgRXJyb3Igc2kgZWwgdG9rZW4gZXMgaW52w6FsaWRvIG8gZXhwaXLDs1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIERlc3B1w6lzIGRlIGxvZ2luIGV4aXRvc28gY29uIHR1IGJhY2tlbmRcbiAgICogY29uc3QgeyBmaXJlYmFzZVRva2VuIH0gPSBhd2FpdCBiYWNrZW5kQXV0aC5sb2dpbihlbWFpbCwgcGFzc3dvcmQpO1xuICAgKiBhd2FpdCBmaXJlYmFzZVNlcnZpY2Uuc2lnbkluV2l0aEN1c3RvbVRva2VuKGZpcmViYXNlVG9rZW4pO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIHNpZ25JbldpdGhDdXN0b21Ub2tlbih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxVc2VyQ3JlZGVudGlhbD4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjcmVkZW50aWFsID0gYXdhaXQgc2lnbkluV2l0aEN1c3RvbVRva2VuKHRoaXMuYXV0aCwgdG9rZW4pO1xuICAgICAgcmV0dXJuIGNyZWRlbnRpYWw7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSB0aGlzLmdldEVycm9yTWVzc2FnZShlcnJvcik7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENpZXJyYSBsYSBzZXNpw7NuIGRlIEZpcmViYXNlLlxuICAgKiBMbGFtYXIganVudG8gY29uIGVsIGxvZ291dCBkZSB0dSBzaXN0ZW1hIGRlIGF1dGVudGljYWNpw7NuIHByaW5jaXBhbC5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhc3luYyBsb2dvdXQoKSB7XG4gICAqICAgYXdhaXQgdGhpcy5iYWNrZW5kQXV0aC5sb2dvdXQoKTsgICAgLy8gVHUgYXV0aFxuICAgKiAgIGF3YWl0IHRoaXMuZmlyZWJhc2Uuc2lnbk91dCgpOyAgICAgICAvLyBGaXJlYmFzZVxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgc2lnbk91dCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgc2lnbk91dCh0aGlzLmF1dGgpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBtZXNzYWdlID0gdGhpcy5nZXRFcnJvck1lc3NhZ2UoZXJyb3IpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBHRVRURVJTIFPDjU5DUk9OT1NcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE9idGllbmUgZWwgdXN1YXJpbyBhY3R1YWwgZGUgRmlyZWJhc2UgKHPDrW5jcm9ubykuXG4gICAqIFJldG9ybmEgbnVsbCBzaSBubyBoYXkgdXN1YXJpbyBhdXRlbnRpY2Fkby5cbiAgICovXG4gIGdldCBjdXJyZW50VXNlcigpOiBGaXJlYmFzZVVzZXIgfCBudWxsIHtcbiAgICBjb25zdCB1c2VyID0gdGhpcy5hdXRoLmN1cnJlbnRVc2VyO1xuICAgIHJldHVybiB1c2VyID8gdGhpcy5tYXBVc2VyKHVzZXIpIDogbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIGVsIFVJRCBkZWwgdXN1YXJpbyBhY3R1YWwuXG4gICAqIFJldG9ybmEgbnVsbCBzaSBubyBoYXkgdXN1YXJpbyBhdXRlbnRpY2Fkby5cbiAgICovXG4gIGdldCB1aWQoKTogc3RyaW5nIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMuYXV0aC5jdXJyZW50VXNlcj8udWlkID8/IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhIHNpIGhheSB1biB1c3VhcmlvIGF1dGVudGljYWRvIGFjdHVhbG1lbnRlLlxuICAgKi9cbiAgZ2V0IGlzQXV0aGVudGljYXRlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gISF0aGlzLmF1dGguY3VycmVudFVzZXI7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gVE9LRU5TXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIGVsIElEIFRva2VuIGRlIEZpcmViYXNlIHBhcmEgZWwgdXN1YXJpbyBhY3R1YWwuXG4gICAqIMOadGlsIHBhcmEgdmFsaWRhciBlbCB1c3VhcmlvIGVuIHR1IGJhY2tlbmQuXG4gICAqXG4gICAqIEBwYXJhbSBmb3JjZVJlZnJlc2ggLSBTaSB0cnVlLCBmdWVyemEgbGEgcmVub3ZhY2nDs24gZGVsIHRva2VuXG4gICAqIEByZXR1cm5zIElEIFRva2VuIG8gbnVsbCBzaSBubyBoYXkgdXN1YXJpb1xuICAgKi9cbiAgYXN5bmMgZ2V0SWRUb2tlbihmb3JjZVJlZnJlc2ggPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICAgIGNvbnN0IHVzZXIgPSB0aGlzLmF1dGguY3VycmVudFVzZXI7XG4gICAgaWYgKCF1c2VyKSByZXR1cm4gbnVsbDtcblxuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgdXNlci5nZXRJZFRva2VuKGZvcmNlUmVmcmVzaCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogT2J0aWVuZSBsb3MgY2xhaW1zIHBlcnNvbmFsaXphZG9zIGRlbCB0b2tlbiBkZWwgdXN1YXJpby5cbiAgICogTG9zIGNsYWltcyBzb24gZXN0YWJsZWNpZG9zIHBvciB0dSBiYWNrZW5kIGFsIGNyZWFyIGVsIEN1c3RvbSBUb2tlbi5cbiAgICpcbiAgICogQHJldHVybnMgT2JqZXRvIGNvbiBsb3MgY2xhaW1zIG8gdmFjw61vIHNpIG5vIGhheSB1c3VhcmlvXG4gICAqL1xuICBhc3luYyBnZXRDbGFpbXMoKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICAgIGNvbnN0IHVzZXIgPSB0aGlzLmF1dGguY3VycmVudFVzZXI7XG4gICAgaWYgKCF1c2VyKSByZXR1cm4ge307XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdXNlci5nZXRJZFRva2VuUmVzdWx0KCk7XG4gICAgICByZXR1cm4gcmVzdWx0LmNsYWltcztcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpY2Egc2kgZWwgdXN1YXJpbyB0aWVuZSB1biByb2wgZXNwZWPDrWZpY28uXG4gICAqIEVsIHJvbCBkZWJlIGVzdGFyIGRlZmluaWRvIGVuIGxvcyBjbGFpbXMgZGVsIEN1c3RvbSBUb2tlbi5cbiAgICpcbiAgICogQHBhcmFtIHJvbGUgLSBOb21icmUgZGVsIHJvbCBhIHZlcmlmaWNhclxuICAgKiBAcmV0dXJucyB0cnVlIHNpIGVsIHVzdWFyaW8gdGllbmUgZWwgcm9sXG4gICAqL1xuICBhc3luYyBoYXNSb2xlKHJvbGU6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IGNsYWltcyA9IGF3YWl0IHRoaXMuZ2V0Q2xhaW1zKCk7XG4gICAgcmV0dXJuIGNsYWltc1sncm9sZSddID09PSByb2xlIHx8IChBcnJheS5pc0FycmF5KGNsYWltc1sncm9sZXMnXSkgJiYgY2xhaW1zWydyb2xlcyddLmluY2x1ZGVzKHJvbGUpKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBVVElMSURBREVTXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBFc3BlcmEgYSBxdWUgZWwgZXN0YWRvIGRlIGF1dGVudGljYWNpw7NuIGVzdMOpIGRldGVybWluYWRvLlxuICAgKiDDmnRpbCBlbiBndWFyZHMgbyBhbCBpbmljaWFsaXphciBsYSBhcHAuXG4gICAqXG4gICAqIEByZXR1cm5zIFVzdWFyaW8gYWN0dWFsIG8gbnVsbFxuICAgKi9cbiAgd2FpdEZvckF1dGgoKTogUHJvbWlzZTxGaXJlYmFzZVVzZXIgfCBudWxsPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICBjb25zdCBzdWJzY3JpcHRpb24gPSB0aGlzLnN0YXRlJC5zdWJzY3JpYmUoKHN0YXRlKSA9PiB7XG4gICAgICAgIGlmICghc3RhdGUuaXNMb2FkaW5nKSB7XG4gICAgICAgICAgc3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICAgICAgcmVzb2x2ZShzdGF0ZS51c2VyKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogT2J0aWVuZSBsYSBjb25maWd1cmFjacOzbiBhY3R1YWwgZGUgRmlyZWJhc2UuXG4gICAqL1xuICBnZXRDb25maWcoKTogVmFsdGVjaEZpcmViYXNlQ29uZmlnIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWc7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhIHNpIGxvcyBlbXVsYWRvcmVzIGVzdMOhbiBoYWJpbGl0YWRvcy5cbiAgICovXG4gIGlzVXNpbmdFbXVsYXRvcnMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhKHRoaXMuY29uZmlnLmVtdWxhdG9yPy5maXJlc3RvcmUgfHwgdGhpcy5jb25maWcuZW11bGF0b3I/LmF1dGggfHwgdGhpcy5jb25maWcuZW11bGF0b3I/LnN0b3JhZ2UpO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIE3DiVRPRE9TIFBSSVZBRE9TXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBNYXBlYSB1biBVc2VyIGRlIEZpcmViYXNlIGEgbnVlc3RyYSBpbnRlcmZhY2UgRmlyZWJhc2VVc2VyXG4gICAqL1xuICBwcml2YXRlIG1hcFVzZXIodXNlcjogVXNlcik6IEZpcmViYXNlVXNlciB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHVpZDogdXNlci51aWQsXG4gICAgICBlbWFpbDogdXNlci5lbWFpbCxcbiAgICAgIGRpc3BsYXlOYW1lOiB1c2VyLmRpc3BsYXlOYW1lLFxuICAgICAgcGhvdG9VUkw6IHVzZXIucGhvdG9VUkwsXG4gICAgICBlbWFpbFZlcmlmaWVkOiB1c2VyLmVtYWlsVmVyaWZpZWQsXG4gICAgICBpc0Fub255bW91czogdXNlci5pc0Fub255bW91cyxcbiAgICAgIHByb3ZpZGVySWQ6IHVzZXIucHJvdmlkZXJJZCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZpZXJ0ZSBlcnJvcmVzIGRlIEZpcmViYXNlIGEgbWVuc2FqZXMgZW4gZXNwYcOxb2xcbiAgICovXG4gIHByaXZhdGUgZ2V0RXJyb3JNZXNzYWdlKGVycm9yOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgY29uc3QgY29kZSA9IChlcnJvciBhcyB7IGNvZGU/OiBzdHJpbmcgfSkuY29kZTtcblxuICAgICAgc3dpdGNoIChjb2RlKSB7XG4gICAgICAgIGNhc2UgJ2F1dGgvaW52YWxpZC1jdXN0b20tdG9rZW4nOlxuICAgICAgICAgIHJldHVybiAnVG9rZW4gZGUgYXV0ZW50aWNhY2nDs24gaW52w6FsaWRvJztcbiAgICAgICAgY2FzZSAnYXV0aC9jdXN0b20tdG9rZW4tbWlzbWF0Y2gnOlxuICAgICAgICAgIHJldHVybiAnRWwgdG9rZW4gbm8gY29ycmVzcG9uZGUgYSBlc3RlIHByb3llY3RvJztcbiAgICAgICAgY2FzZSAnYXV0aC9uZXR3b3JrLXJlcXVlc3QtZmFpbGVkJzpcbiAgICAgICAgICByZXR1cm4gJ0Vycm9yIGRlIGNvbmV4acOzbi4gVmVyaWZpY2EgdHUgY29uZXhpw7NuIGEgaW50ZXJuZXQnO1xuICAgICAgICBjYXNlICdhdXRoL3Rvby1tYW55LXJlcXVlc3RzJzpcbiAgICAgICAgICByZXR1cm4gJ0RlbWFzaWFkb3MgaW50ZW50b3MuIEludGVudGEgZGUgbnVldm8gbcOhcyB0YXJkZSc7XG4gICAgICAgIGNhc2UgJ2F1dGgvdXNlci1kaXNhYmxlZCc6XG4gICAgICAgICAgcmV0dXJuICdFc3RhIGN1ZW50YSBoYSBzaWRvIGRlc2hhYmlsaXRhZGEnO1xuICAgICAgICBjYXNlICdhdXRoL3VzZXItbm90LWZvdW5kJzpcbiAgICAgICAgICByZXR1cm4gJ1VzdWFyaW8gbm8gZW5jb250cmFkbyc7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIGVycm9yLm1lc3NhZ2UgfHwgJ0Vycm9yIGRlIGF1dGVudGljYWNpw7NuIGRlc2Nvbm9jaWRvJztcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gJ0Vycm9yIGRlIGF1dGVudGljYWNpw7NuIGRlc2Nvbm9jaWRvJztcbiAgfVxufVxuIl19
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Firestore Collection Factory
|
|
3
|
-
*
|
|
4
|
-
* Patrón factory para crear instancias de colección tipadas.
|
|
5
|
-
* Reemplaza la clase abstracta para evitar problemas con inject() en clases no-injectable.
|
|
6
|
-
*/
|
|
7
|
-
import { Injectable, inject } from '@angular/core';
|
|
8
|
-
import { FirestoreService } from './firestore.service';
|
|
9
|
-
import * as i0 from "@angular/core";
|
|
10
|
-
/**
|
|
11
|
-
* Factory para crear instancias de colección tipadas.
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* @Injectable({ providedIn: 'root' })
|
|
16
|
-
* export class UsersService {
|
|
17
|
-
* private users = inject(FirestoreCollectionFactory).create<User>('users');
|
|
18
|
-
*
|
|
19
|
-
* getAll = () => this.users.getAll();
|
|
20
|
-
* getById = (id: string) => this.users.getById(id);
|
|
21
|
-
* create = (data: Omit<User, 'id'>) => this.users.create(data);
|
|
22
|
-
*
|
|
23
|
-
* // Métodos personalizados
|
|
24
|
-
* async getActiveUsers(): Promise<User[]> {
|
|
25
|
-
* return this.users.query({
|
|
26
|
-
* where: [{ field: 'active', operator: '==', value: true }]
|
|
27
|
-
* });
|
|
28
|
-
* }
|
|
29
|
-
* }
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export class FirestoreCollectionFactory {
|
|
33
|
-
constructor() {
|
|
34
|
-
this.firestore = inject(FirestoreService);
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Crea una instancia de colección tipada.
|
|
38
|
-
*
|
|
39
|
-
* @param collectionPath - Ruta de la colección en Firestore
|
|
40
|
-
* @param options - Opciones de configuración
|
|
41
|
-
* @returns Instancia de TypedCollection
|
|
42
|
-
*/
|
|
43
|
-
create(collectionPath, options) {
|
|
44
|
-
return new TypedCollection(this.firestore, collectionPath, options);
|
|
45
|
-
}
|
|
46
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreCollectionFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
47
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreCollectionFactory, providedIn: 'root' }); }
|
|
48
|
-
}
|
|
49
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreCollectionFactory, decorators: [{
|
|
50
|
-
type: Injectable,
|
|
51
|
-
args: [{ providedIn: 'root' }]
|
|
52
|
-
}] });
|
|
53
|
-
/**
|
|
54
|
-
* Colección tipada con métodos CRUD.
|
|
55
|
-
*
|
|
56
|
-
* NO usa inject() - recibe FirestoreService por constructor.
|
|
57
|
-
* Esto evita el error NG0203.
|
|
58
|
-
*/
|
|
59
|
-
export class TypedCollection {
|
|
60
|
-
constructor(firestore, collectionPath, options = {}) {
|
|
61
|
-
this.firestore = firestore;
|
|
62
|
-
this.collectionPath = collectionPath;
|
|
63
|
-
this.options = {
|
|
64
|
-
softDelete: false,
|
|
65
|
-
timestamps: true,
|
|
66
|
-
...options,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
// ===========================================================================
|
|
70
|
-
// LECTURAS ONE-TIME
|
|
71
|
-
// ===========================================================================
|
|
72
|
-
/**
|
|
73
|
-
* Obtiene un documento por ID.
|
|
74
|
-
*/
|
|
75
|
-
async getById(id) {
|
|
76
|
-
return this.firestore.getDoc(this.collectionPath, id);
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Obtiene todos los documentos de la colección.
|
|
80
|
-
*/
|
|
81
|
-
async getAll(options) {
|
|
82
|
-
const queryOptions = this.applyDefaultFilters(options);
|
|
83
|
-
return this.firestore.getDocs(this.collectionPath, queryOptions);
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Ejecuta una query personalizada.
|
|
87
|
-
*/
|
|
88
|
-
async query(options) {
|
|
89
|
-
const queryOptions = this.applyDefaultFilters(options);
|
|
90
|
-
return this.firestore.getDocs(this.collectionPath, queryOptions);
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Obtiene documentos con paginación.
|
|
94
|
-
*/
|
|
95
|
-
async paginate(options) {
|
|
96
|
-
const queryOptions = this.applyDefaultFilters(options);
|
|
97
|
-
return this.firestore.getPaginated(this.collectionPath, queryOptions);
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Obtiene el primer documento que coincida con la query.
|
|
101
|
-
*/
|
|
102
|
-
async getFirst(options) {
|
|
103
|
-
const queryOptions = this.applyDefaultFilters({
|
|
104
|
-
...options,
|
|
105
|
-
limit: 1,
|
|
106
|
-
});
|
|
107
|
-
const results = await this.firestore.getDocs(this.collectionPath, queryOptions);
|
|
108
|
-
return results[0] ?? null;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Cuenta los documentos que coinciden con la query.
|
|
112
|
-
* Nota: Esto carga todos los documentos, usar con cuidado en colecciones grandes.
|
|
113
|
-
*/
|
|
114
|
-
async count(options) {
|
|
115
|
-
const queryOptions = this.applyDefaultFilters(options);
|
|
116
|
-
const results = await this.firestore.getDocs(this.collectionPath, queryOptions);
|
|
117
|
-
return results.length;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Verifica si un documento existe.
|
|
121
|
-
*/
|
|
122
|
-
async exists(id) {
|
|
123
|
-
return this.firestore.exists(this.collectionPath, id);
|
|
124
|
-
}
|
|
125
|
-
// ===========================================================================
|
|
126
|
-
// SUBSCRIPCIONES REAL-TIME
|
|
127
|
-
// ===========================================================================
|
|
128
|
-
/**
|
|
129
|
-
* Suscribe a cambios de un documento.
|
|
130
|
-
*/
|
|
131
|
-
watch(id) {
|
|
132
|
-
return this.firestore.docChanges(this.collectionPath, id);
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Suscribe a cambios de la colección.
|
|
136
|
-
*/
|
|
137
|
-
watchAll(options) {
|
|
138
|
-
const queryOptions = this.applyDefaultFilters(options);
|
|
139
|
-
return this.firestore.collectionChanges(this.collectionPath, queryOptions);
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Suscribe a una query personalizada.
|
|
143
|
-
*/
|
|
144
|
-
watchQuery(options) {
|
|
145
|
-
const queryOptions = this.applyDefaultFilters(options);
|
|
146
|
-
return this.firestore.collectionChanges(this.collectionPath, queryOptions);
|
|
147
|
-
}
|
|
148
|
-
// ===========================================================================
|
|
149
|
-
// ESCRITURA
|
|
150
|
-
// ===========================================================================
|
|
151
|
-
/**
|
|
152
|
-
* Crea un nuevo documento con ID auto-generado.
|
|
153
|
-
*/
|
|
154
|
-
async create(data) {
|
|
155
|
-
return this.firestore.addDoc(this.collectionPath, data);
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Crea un documento con ID específico.
|
|
159
|
-
*/
|
|
160
|
-
async createWithId(id, data) {
|
|
161
|
-
return this.firestore.setDoc(this.collectionPath, id, data);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Actualiza campos de un documento.
|
|
165
|
-
*/
|
|
166
|
-
async update(id, data) {
|
|
167
|
-
return this.firestore.updateDoc(this.collectionPath, id, data);
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Elimina un documento.
|
|
171
|
-
* Si softDelete está habilitado, marca como eliminado en lugar de borrar.
|
|
172
|
-
*/
|
|
173
|
-
async delete(id) {
|
|
174
|
-
if (this.options.softDelete) {
|
|
175
|
-
return this.firestore.updateDoc(this.collectionPath, id, {
|
|
176
|
-
deletedAt: new Date(),
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
return this.firestore.deleteDoc(this.collectionPath, id);
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Restaura un documento soft-deleted.
|
|
183
|
-
*/
|
|
184
|
-
async restore(id) {
|
|
185
|
-
if (!this.options.softDelete) {
|
|
186
|
-
throw new Error('Soft delete no está habilitado para esta colección');
|
|
187
|
-
}
|
|
188
|
-
return this.firestore.updateDoc(this.collectionPath, id, {
|
|
189
|
-
deletedAt: null,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
// ===========================================================================
|
|
193
|
-
// SUB-COLECCIONES
|
|
194
|
-
// ===========================================================================
|
|
195
|
-
/**
|
|
196
|
-
* Obtiene una referencia a una sub-colección.
|
|
197
|
-
*
|
|
198
|
-
* @example
|
|
199
|
-
* ```typescript
|
|
200
|
-
* // En UsersService
|
|
201
|
-
* getUserDocuments(userId: string) {
|
|
202
|
-
* return this.users.subcollection<Document>(userId, 'documents');
|
|
203
|
-
* }
|
|
204
|
-
*
|
|
205
|
-
* // Uso
|
|
206
|
-
* const docs = await users.getUserDocuments('user123').getAll();
|
|
207
|
-
* ```
|
|
208
|
-
*/
|
|
209
|
-
subcollection(parentId, subcollectionName) {
|
|
210
|
-
const subPath = `${this.collectionPath}/${parentId}/${subcollectionName}`;
|
|
211
|
-
return {
|
|
212
|
-
getById: (id) => this.firestore.getDoc(subPath, id),
|
|
213
|
-
getAll: (options) => this.firestore.getDocs(subPath, options),
|
|
214
|
-
watch: (id) => this.firestore.docChanges(subPath, id),
|
|
215
|
-
watchAll: (options) => this.firestore.collectionChanges(subPath, options),
|
|
216
|
-
create: (data) => this.firestore.addDoc(subPath, data),
|
|
217
|
-
update: (id, data) => this.firestore.updateDoc(subPath, id, data),
|
|
218
|
-
delete: (id) => this.firestore.deleteDoc(subPath, id),
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
// ===========================================================================
|
|
222
|
-
// MÉTODOS PRIVADOS
|
|
223
|
-
// ===========================================================================
|
|
224
|
-
/**
|
|
225
|
-
* Aplica filtros por defecto a las queries.
|
|
226
|
-
*/
|
|
227
|
-
applyDefaultFilters(options) {
|
|
228
|
-
if (!this.options.softDelete) {
|
|
229
|
-
return options ?? {};
|
|
230
|
-
}
|
|
231
|
-
// Excluir documentos soft-deleted por defecto
|
|
232
|
-
const whereClause = { field: 'deletedAt', operator: '==', value: null };
|
|
233
|
-
return {
|
|
234
|
-
...options,
|
|
235
|
-
where: [...(options?.where ?? []), whereClause],
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
// ===========================================================================
|
|
239
|
-
// UTILIDADES
|
|
240
|
-
// ===========================================================================
|
|
241
|
-
/**
|
|
242
|
-
* Genera un nuevo ID sin crear el documento.
|
|
243
|
-
*/
|
|
244
|
-
generateId() {
|
|
245
|
-
return this.firestore.generateId(this.collectionPath);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Obtiene la ruta de la colección.
|
|
249
|
-
*/
|
|
250
|
-
getPath() {
|
|
251
|
-
return this.collectionPath;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlyZXN0b3JlLWNvbGxlY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ZpcmViYXNlL2ZpcmVzdG9yZS1jb2xsZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHbkQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7O0FBaUN2RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBRUgsTUFBTSxPQUFPLDBCQUEwQjtJQUR2QztRQUVVLGNBQVMsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztLQWU5QztJQWJDOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FDSixjQUFzQixFQUN0QixPQUEyQjtRQUUzQixPQUFPLElBQUksZUFBZSxDQUFJLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3pFLENBQUM7K0dBZlUsMEJBQTBCO21IQUExQiwwQkFBMEIsY0FEYixNQUFNOzs0RkFDbkIsMEJBQTBCO2tCQUR0QyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRTs7QUFtQmxDOzs7OztHQUtHO0FBQ0gsTUFBTSxPQUFPLGVBQWU7SUFHMUIsWUFDVSxTQUEyQixFQUMzQixjQUFzQixFQUM5QixVQUE2QixFQUFFO1FBRnZCLGNBQVMsR0FBVCxTQUFTLENBQWtCO1FBQzNCLG1CQUFjLEdBQWQsY0FBYyxDQUFRO1FBRzlCLElBQUksQ0FBQyxPQUFPLEdBQUc7WUFDYixVQUFVLEVBQUUsS0FBSztZQUNqQixVQUFVLEVBQUUsSUFBSTtZQUNoQixHQUFHLE9BQU87U0FDWCxDQUFDO0lBQ0osQ0FBQztJQUVELDhFQUE4RTtJQUM5RSxvQkFBb0I7SUFDcEIsOEVBQThFO0lBRTlFOztPQUVH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QUFFLEVBQUUsSUFBSSxDQUFDO1lBQ3hGLE1BQU0sRUFBRSxDQUFDLEVBQVUsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztTQUM5RCxDQUFDO0lBQ0osQ0FBQztJQUVELDhFQUE4RTtJQUM5RSxtQkFBbUI7SUFDbkIsOEVBQThFO0lBRTlFOztPQUVHO0lBQ0ssbUJBQW1CLENBQUMsT0FBc0I7UUFDaEQsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDN0IsT0FBTyxPQUFPLElBQUksRUFBRSxDQUFDO1FBQ3ZCLENBQUM7UUFFRCw4Q0FBOEM7UUFDOUMsTUFBTSxXQUFXLEdBQUcsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxJQUFhLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO1FBRWpGLE9BQU87WUFDTCxHQUFHLE9BQU87WUFDVixLQUFLLEVBQUUsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFLENBQUMsRUFBRSxXQUFXLENBQUM7U0FDaEQsQ0FBQztJQUNKLENBQUM7SUFFRCw4RUFBOEU7SUFDOUUsYUFBYTtJQUNiLDhFQUE4RTtJQUU5RTs7T0FFRztJQUNILFVBQVU7UUFDUixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPO1FBQ0wsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDO0lBQzdCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRmlyZXN0b3JlIENvbGxlY3Rpb24gRmFjdG9yeVxuICpcbiAqIFBhdHLDs24gZmFjdG9yeSBwYXJhIGNyZWFyIGluc3RhbmNpYXMgZGUgY29sZWNjacOzbiB0aXBhZGFzLlxuICogUmVlbXBsYXphIGxhIGNsYXNlIGFic3RyYWN0YSBwYXJhIGV2aXRhciBwcm9ibGVtYXMgY29uIGluamVjdCgpIGVuIGNsYXNlcyBuby1pbmplY3RhYmxlLlxuICovXG5cbmltcG9ydCB7IEluamVjdGFibGUsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBGaXJlc3RvcmVTZXJ2aWNlIH0gZnJvbSAnLi9maXJlc3RvcmUuc2VydmljZSc7XG5pbXBvcnQgeyBGaXJlc3RvcmVEb2N1bWVudCwgUGFnaW5hdGVkUmVzdWx0LCBRdWVyeU9wdGlvbnMgfSBmcm9tICcuL3R5cGVzJztcblxuLyoqXG4gKiBPcGNpb25lcyBkZSBjb25maWd1cmFjacOzbiBwYXJhIHVuYSBjb2xlY2Npw7NuLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbGxlY3Rpb25PcHRpb25zIHtcbiAgLyoqXG4gICAqIFNpIHRydWUsIHVzYSBzb2Z0IGRlbGV0ZSAobWFyY2EgZGVsZXRlZEF0IGVuIGx1Z2FyIGRlIGVsaW1pbmFyKS5cbiAgICogRGVmYXVsdDogZmFsc2VcbiAgICovXG4gIHNvZnREZWxldGU/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBTaSB0cnVlLCBtYW5lamEgYXV0b23DoXRpY2FtZW50ZSBjcmVhdGVkQXQvdXBkYXRlZEF0LlxuICAgKiBEZWZhdWx0OiB0cnVlXG4gICAqL1xuICB0aW1lc3RhbXBzPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBSZWZlcmVuY2lhIGEgdW5hIHN1Yi1jb2xlY2Npw7NuIHRpcGFkYS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdWJDb2xsZWN0aW9uUmVmPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4ge1xuICBnZXRCeUlkKGlkOiBzdHJpbmcpOiBQcm9taXNlPFQgfCBudWxsPjtcbiAgZ2V0QWxsKG9wdGlvbnM/OiBRdWVyeU9wdGlvbnMpOiBQcm9taXNlPFRbXT47XG4gIHdhdGNoKGlkOiBzdHJpbmcpOiBPYnNlcnZhYmxlPFQgfCBudWxsPjtcbiAgd2F0Y2hBbGwob3B0aW9ucz86IFF1ZXJ5T3B0aW9ucyk6IE9ic2VydmFibGU8VFtdPjtcbiAgY3JlYXRlKGRhdGE6IE9taXQ8VCwgJ2lkJyB8ICdjcmVhdGVkQXQnIHwgJ3VwZGF0ZWRBdCc+KTogUHJvbWlzZTxUPjtcbiAgdXBkYXRlKGlkOiBzdHJpbmcsIGRhdGE6IFBhcnRpYWw8VD4pOiBQcm9taXNlPHZvaWQ+O1xuICBkZWxldGUoaWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD47XG59XG5cbi8qKlxuICogRmFjdG9yeSBwYXJhIGNyZWFyIGluc3RhbmNpYXMgZGUgY29sZWNjacOzbiB0aXBhZGFzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuICogZXhwb3J0IGNsYXNzIFVzZXJzU2VydmljZSB7XG4gKiAgIHByaXZhdGUgdXNlcnMgPSBpbmplY3QoRmlyZXN0b3JlQ29sbGVjdGlvbkZhY3RvcnkpLmNyZWF0ZTxVc2VyPigndXNlcnMnKTtcbiAqXG4gKiAgIGdldEFsbCA9ICgpID0+IHRoaXMudXNlcnMuZ2V0QWxsKCk7XG4gKiAgIGdldEJ5SWQgPSAoaWQ6IHN0cmluZykgPT4gdGhpcy51c2Vycy5nZXRCeUlkKGlkKTtcbiAqICAgY3JlYXRlID0gKGRhdGE6IE9taXQ8VXNlciwgJ2lkJz4pID0+IHRoaXMudXNlcnMuY3JlYXRlKGRhdGEpO1xuICpcbiAqICAgLy8gTcOpdG9kb3MgcGVyc29uYWxpemFkb3NcbiAqICAgYXN5bmMgZ2V0QWN0aXZlVXNlcnMoKTogUHJvbWlzZTxVc2VyW10+IHtcbiAqICAgICByZXR1cm4gdGhpcy51c2Vycy5xdWVyeSh7XG4gKiAgICAgICB3aGVyZTogW3sgZmllbGQ6ICdhY3RpdmUnLCBvcGVyYXRvcjogJz09JywgdmFsdWU6IHRydWUgfV1cbiAqICAgICB9KTtcbiAqICAgfVxuICogfVxuICogYGBgXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgRmlyZXN0b3JlQ29sbGVjdGlvbkZhY3Rvcnkge1xuICBwcml2YXRlIGZpcmVzdG9yZSA9IGluamVjdChGaXJlc3RvcmVTZXJ2aWNlKTtcblxuICAvKipcbiAgICogQ3JlYSB1bmEgaW5zdGFuY2lhIGRlIGNvbGVjY2nDs24gdGlwYWRhLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs24gZW4gRmlyZXN0b3JlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3BjaW9uZXMgZGUgY29uZmlndXJhY2nDs25cbiAgICogQHJldHVybnMgSW5zdGFuY2lhIGRlIFR5cGVkQ29sbGVjdGlvblxuICAgKi9cbiAgY3JlYXRlPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgY29sbGVjdGlvblBhdGg6IHN0cmluZyxcbiAgICBvcHRpb25zPzogQ29sbGVjdGlvbk9wdGlvbnNcbiAgKTogVHlwZWRDb2xsZWN0aW9uPFQ+IHtcbiAgICByZXR1cm4gbmV3IFR5cGVkQ29sbGVjdGlvbjxUPih0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgsIG9wdGlvbnMpO1xuICB9XG59XG5cbi8qKlxuICogQ29sZWNjacOzbiB0aXBhZGEgY29uIG3DqXRvZG9zIENSVUQuXG4gKlxuICogTk8gdXNhIGluamVjdCgpIC0gcmVjaWJlIEZpcmVzdG9yZVNlcnZpY2UgcG9yIGNvbnN0cnVjdG9yLlxuICogRXN0byBldml0YSBlbCBlcnJvciBORzAyMDMuXG4gKi9cbmV4cG9ydCBjbGFzcyBUeXBlZENvbGxlY3Rpb248VCBleHRlbmRzIEZpcmVzdG9yZURvY3VtZW50PiB7XG4gIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogQ29sbGVjdGlvbk9wdGlvbnM7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBmaXJlc3RvcmU6IEZpcmVzdG9yZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBjb2xsZWN0aW9uUGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IENvbGxlY3Rpb25PcHRpb25zID0ge31cbiAgKSB7XG4gICAgdGhpcy5vcHRpb25zID0ge1xuICAgICAgc29mdERlbGV0ZTogZmFsc2UsXG4gICAgICB0aW1lc3RhbXBzOiB0cnVlLFxuICAgICAgLi4ub3B0aW9ucyxcbiAgICB9O1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIExFQ1RVUkFTIE9ORS1USU1FXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIHVuIGRvY3VtZW50byBwb3IgSUQuXG4gICAqL1xuICBhc3luYyBnZXRCeUlkKGlkOiBzdHJpbmcpOiBQcm9taXNlPFQgfCBudWxsPiB7XG4gICAgcmV0dXJuIHRoaXMuZmlyZXN0b3JlLmdldERvYzxUPih0aGlzLmNvbGxlY3Rpb25QYXRoLCBpZCk7XG4gIH1cblxuICAvKipcbiAgICogT2J0aWVuZSB0b2RvcyBsb3MgZG9jdW1lbnRvcyBkZSBsYSBjb2xlY2Npw7NuLlxuICAgKi9cbiAgYXN5bmMgZ2V0QWxsKG9wdGlvbnM/OiBRdWVyeU9wdGlvbnMpOiBQcm9taXNlPFRbXT4ge1xuICAgIGNvbnN0IHF1ZXJ5T3B0aW9ucyA9IHRoaXMuYXBwbHlEZWZhdWx0RmlsdGVycyhvcHRpb25zKTtcbiAgICByZXR1cm4gdGhpcy5maXJlc3RvcmUuZ2V0RG9jczxUPih0aGlzLmNvbGxlY3Rpb25QYXRoLCBxdWVyeU9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVqZWN1dGEgdW5hIHF1ZXJ5IHBlcnNvbmFsaXphZGEuXG4gICAqL1xuICBhc3luYyBxdWVyeShvcHRpb25zOiBRdWVyeU9wdGlvbnMpOiBQcm9taXNlPFRbXT4ge1xuICAgIGNvbnN0IHF1ZXJ5T3B0aW9ucyA9IHRoaXMuYXBwbHlEZWZhdWx0RmlsdGVycyhvcHRpb25zKTtcbiAgICByZXR1cm4gdGhpcy5maXJlc3RvcmUuZ2V0RG9jczxUPih0aGlzLmNvbGxlY3Rpb25QYXRoLCBxdWVyeU9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9idGllbmUgZG9jdW1lbnRvcyBjb24gcGFnaW5hY2nDs24uXG4gICAqL1xuICBhc3luYyBwYWdpbmF0ZShvcHRpb25zOiBRdWVyeU9wdGlvbnMgJiB7IGxpbWl0OiBudW1iZXIgfSk6IFByb21pc2U8UGFnaW5hdGVkUmVzdWx0PFQ+PiB7XG4gICAgY29uc3QgcXVlcnlPcHRpb25zID0gdGhpcy5hcHBseURlZmF1bHRGaWx0ZXJzKG9wdGlvbnMpIGFzIFF1ZXJ5T3B0aW9ucyAmIHsgbGltaXQ6IG51bWJlciB9O1xuICAgIHJldHVybiB0aGlzLmZpcmVzdG9yZS5nZXRQYWdpbmF0ZWQ8VD4odGhpcy5jb2xsZWN0aW9uUGF0aCwgcXVlcnlPcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIGVsIHByaW1lciBkb2N1bWVudG8gcXVlIGNvaW5jaWRhIGNvbiBsYSBxdWVyeS5cbiAgICovXG4gIGFzeW5jIGdldEZpcnN0KG9wdGlvbnM/OiBRdWVyeU9wdGlvbnMpOiBQcm9taXNlPFQgfCBudWxsPiB7XG4gICAgY29uc3QgcXVlcnlPcHRpb25zID0gdGhpcy5hcHBseURlZmF1bHRGaWx0ZXJzKHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgICBsaW1pdDogMSxcbiAgICB9KTtcbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgdGhpcy5maXJlc3RvcmUuZ2V0RG9jczxUPih0aGlzLmNvbGxlY3Rpb25QYXRoLCBxdWVyeU9wdGlvbnMpO1xuICAgIHJldHVybiByZXN1bHRzWzBdID8/IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogQ3VlbnRhIGxvcyBkb2N1bWVudG9zIHF1ZSBjb2luY2lkZW4gY29uIGxhIHF1ZXJ5LlxuICAgKiBOb3RhOiBFc3RvIGNhcmdhIHRvZG9zIGxvcyBkb2N1bWVudG9zLCB1c2FyIGNvbiBjdWlkYWRvIGVuIGNvbGVjY2lvbmVzIGdyYW5kZXMuXG4gICAqL1xuICBhc3luYyBjb3VudChvcHRpb25zPzogUXVlcnlPcHRpb25zKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBxdWVyeU9wdGlvbnMgPSB0aGlzLmFwcGx5RGVmYXVsdEZpbHRlcnMob3B0aW9ucyk7XG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMuZmlyZXN0b3JlLmdldERvY3M8VD4odGhpcy5jb2xsZWN0aW9uUGF0aCwgcXVlcnlPcHRpb25zKTtcbiAgICByZXR1cm4gcmVzdWx0cy5sZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpY2Egc2kgdW4gZG9jdW1lbnRvIGV4aXN0ZS5cbiAgICovXG4gIGFzeW5jIGV4aXN0cyhpZDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuZmlyZXN0b3JlLmV4aXN0cyh0aGlzLmNvbGxlY3Rpb25QYXRoLCBpZCk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gU1VCU0NSSVBDSU9ORVMgUkVBTC1USU1FXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBTdXNjcmliZSBhIGNhbWJpb3MgZGUgdW4gZG9jdW1lbnRvLlxuICAgKi9cbiAgd2F0Y2goaWQ6IHN0cmluZyk6IE9ic2VydmFibGU8VCB8IG51bGw+IHtcbiAgICByZXR1cm4gdGhpcy5maXJlc3RvcmUuZG9jQ2hhbmdlczxUPih0aGlzLmNvbGxlY3Rpb25QYXRoLCBpZCk7XG4gIH1cblxuICAvKipcbiAgICogU3VzY3JpYmUgYSBjYW1iaW9zIGRlIGxhIGNvbGVjY2nDs24uXG4gICAqL1xuICB3YXRjaEFsbChvcHRpb25zPzogUXVlcnlPcHRpb25zKTogT2JzZXJ2YWJsZTxUW10+IHtcbiAgICBjb25zdCBxdWVyeU9wdGlvbnMgPSB0aGlzLmFwcGx5RGVmYXVsdEZpbHRlcnMob3B0aW9ucyk7XG4gICAgcmV0dXJuIHRoaXMuZmlyZXN0b3JlLmNvbGxlY3Rpb25DaGFuZ2VzPFQ+KHRoaXMuY29sbGVjdGlvblBhdGgsIHF1ZXJ5T3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogU3VzY3JpYmUgYSB1bmEgcXVlcnkgcGVyc29uYWxpemFkYS5cbiAgICovXG4gIHdhdGNoUXVlcnkob3B0aW9uczogUXVlcnlPcHRpb25zKTogT2JzZXJ2YWJsZTxUW10+IHtcbiAgICBjb25zdCBxdWVyeU9wdGlvbnMgPSB0aGlzLmFwcGx5RGVmYXVsdEZpbHRlcnMob3B0aW9ucyk7XG4gICAgcmV0dXJuIHRoaXMuZmlyZXN0b3JlLmNvbGxlY3Rpb25DaGFuZ2VzPFQ+KHRoaXMuY29sbGVjdGlvblBhdGgsIHF1ZXJ5T3B0aW9ucyk7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gRVNDUklUVVJBXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBDcmVhIHVuIG51ZXZvIGRvY3VtZW50byBjb24gSUQgYXV0by1nZW5lcmFkby5cbiAgICovXG4gIGFzeW5jIGNyZWF0ZShkYXRhOiBPbWl0PFQsICdpZCcgfCAnY3JlYXRlZEF0JyB8ICd1cGRhdGVkQXQnPik6IFByb21pc2U8VD4ge1xuICAgIHJldHVybiB0aGlzLmZpcmVzdG9yZS5hZGREb2M8VD4odGhpcy5jb2xsZWN0aW9uUGF0aCwgZGF0YSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYSB1biBkb2N1bWVudG8gY29uIElEIGVzcGVjw61maWNvLlxuICAgKi9cbiAgYXN5bmMgY3JlYXRlV2l0aElkKGlkOiBzdHJpbmcsIGRhdGE6IE9taXQ8VCwgJ2lkJz4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5maXJlc3RvcmUuc2V0RG9jPFQ+KHRoaXMuY29sbGVjdGlvblBhdGgsIGlkLCBkYXRhKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBY3R1YWxpemEgY2FtcG9zIGRlIHVuIGRvY3VtZW50by5cbiAgICovXG4gIGFzeW5jIHVwZGF0ZShpZDogc3RyaW5nLCBkYXRhOiBQYXJ0aWFsPE9taXQ8VCwgJ2lkJyB8ICdjcmVhdGVkQXQnPj4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5maXJlc3RvcmUudXBkYXRlRG9jPFQ+KHRoaXMuY29sbGVjdGlvblBhdGgsIGlkLCBkYXRhKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbGltaW5hIHVuIGRvY3VtZW50by5cbiAgICogU2kgc29mdERlbGV0ZSBlc3TDoSBoYWJpbGl0YWRvLCBtYXJjYSBjb21vIGVsaW1pbmFkbyBlbiBsdWdhciBkZSBib3JyYXIuXG4gICAqL1xuICBhc3luYyBkZWxldGUoaWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLm9wdGlvbnMuc29mdERlbGV0ZSkge1xuICAgICAgcmV0dXJuIHRoaXMuZmlyZXN0b3JlLnVwZGF0ZURvYzxUPih0aGlzLmNvbGxlY3Rpb25QYXRoLCBpZCwge1xuICAgICAgICBkZWxldGVkQXQ6IG5ldyBEYXRlKCksXG4gICAgICB9IGFzIHVua25vd24gYXMgUGFydGlhbDxUPik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmZpcmVzdG9yZS5kZWxldGVEb2ModGhpcy5jb2xsZWN0aW9uUGF0aCwgaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc3RhdXJhIHVuIGRvY3VtZW50byBzb2Z0LWRlbGV0ZWQuXG4gICAqL1xuICBhc3luYyByZXN0b3JlKGlkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMub3B0aW9ucy5zb2Z0RGVsZXRlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NvZnQgZGVsZXRlIG5vIGVzdMOhIGhhYmlsaXRhZG8gcGFyYSBlc3RhIGNvbGVjY2nDs24nKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZmlyZXN0b3JlLnVwZGF0ZURvYzxUPih0aGlzLmNvbGxlY3Rpb25QYXRoLCBpZCwge1xuICAgICAgZGVsZXRlZEF0OiBudWxsLFxuICAgIH0gYXMgdW5rbm93biBhcyBQYXJ0aWFsPFQ+KTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBTVUItQ09MRUNDSU9ORVNcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE9idGllbmUgdW5hIHJlZmVyZW5jaWEgYSB1bmEgc3ViLWNvbGVjY2nDs24uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gRW4gVXNlcnNTZXJ2aWNlXG4gICAqIGdldFVzZXJEb2N1bWVudHModXNlcklkOiBzdHJpbmcpIHtcbiAgICogICByZXR1cm4gdGhpcy51c2Vycy5zdWJjb2xsZWN0aW9uPERvY3VtZW50Pih1c2VySWQsICdkb2N1bWVudHMnKTtcbiAgICogfVxuICAgKlxuICAgKiAvLyBVc29cbiAgICogY29uc3QgZG9jcyA9IGF3YWl0IHVzZXJzLmdldFVzZXJEb2N1bWVudHMoJ3VzZXIxMjMnKS5nZXRBbGwoKTtcbiAgICogYGBgXG4gICAqL1xuICBzdWJjb2xsZWN0aW9uPFMgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgcGFyZW50SWQ6IHN0cmluZyxcbiAgICBzdWJjb2xsZWN0aW9uTmFtZTogc3RyaW5nXG4gICk6IFN1YkNvbGxlY3Rpb25SZWY8Uz4ge1xuICAgIGNvbnN0IHN1YlBhdGggPSBgJHt0aGlzLmNvbGxlY3Rpb25QYXRofS8ke3BhcmVudElkfS8ke3N1YmNvbGxlY3Rpb25OYW1lfWA7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZ2V0QnlJZDogKGlkOiBzdHJpbmcpID0+IHRoaXMuZmlyZXN0b3JlLmdldERvYzxTPihzdWJQYXRoLCBpZCksXG4gICAgICBnZXRBbGw6IChvcHRpb25zPzogUXVlcnlPcHRpb25zKSA9PiB0aGlzLmZpcmVzdG9yZS5nZXREb2NzPFM+KHN1YlBhdGgsIG9wdGlvbnMpLFxuICAgICAgd2F0Y2g6IChpZDogc3RyaW5nKSA9PiB0aGlzLmZpcmVzdG9yZS5kb2NDaGFuZ2VzPFM+KHN1YlBhdGgsIGlkKSxcbiAgICAgIHdhdGNoQWxsOiAob3B0aW9ucz86IFF1ZXJ5T3B0aW9ucykgPT4gdGhpcy5maXJlc3RvcmUuY29sbGVjdGlvbkNoYW5nZXM8Uz4oc3ViUGF0aCwgb3B0aW9ucyksXG4gICAgICBjcmVhdGU6IChkYXRhOiBPbWl0PFMsICdpZCcgfCAnY3JlYXRlZEF0JyB8ICd1cGRhdGVkQXQnPikgPT5cbiAgICAgICAgdGhpcy5maXJlc3RvcmUuYWRkRG9jPFM+KHN1YlBhdGgsIGRhdGEpLFxuICAgICAgdXBkYXRlOiAoaWQ6IHN0cmluZywgZGF0YTogUGFydGlhbDxTPikgPT4gdGhpcy5maXJlc3RvcmUudXBkYXRlRG9jPFM+KHN1YlBhdGgsIGlkLCBkYXRhKSxcbiAgICAgIGRlbGV0ZTogKGlkOiBzdHJpbmcpID0+IHRoaXMuZmlyZXN0b3JlLmRlbGV0ZURvYyhzdWJQYXRoLCBpZCksXG4gICAgfTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBNw4lUT0RPUyBQUklWQURPU1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogQXBsaWNhIGZpbHRyb3MgcG9yIGRlZmVjdG8gYSBsYXMgcXVlcmllcy5cbiAgICovXG4gIHByaXZhdGUgYXBwbHlEZWZhdWx0RmlsdGVycyhvcHRpb25zPzogUXVlcnlPcHRpb25zKTogUXVlcnlPcHRpb25zIHtcbiAgICBpZiAoIXRoaXMub3B0aW9ucy5zb2Z0RGVsZXRlKSB7XG4gICAgICByZXR1cm4gb3B0aW9ucyA/PyB7fTtcbiAgICB9XG5cbiAgICAvLyBFeGNsdWlyIGRvY3VtZW50b3Mgc29mdC1kZWxldGVkIHBvciBkZWZlY3RvXG4gICAgY29uc3Qgd2hlcmVDbGF1c2UgPSB7IGZpZWxkOiAnZGVsZXRlZEF0Jywgb3BlcmF0b3I6ICc9PScgYXMgY29uc3QsIHZhbHVlOiBudWxsIH07XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4ub3B0aW9ucyxcbiAgICAgIHdoZXJlOiBbLi4uKG9wdGlvbnM/LndoZXJlID8/IFtdKSwgd2hlcmVDbGF1c2VdLFxuICAgIH07XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gVVRJTElEQURFU1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogR2VuZXJhIHVuIG51ZXZvIElEIHNpbiBjcmVhciBlbCBkb2N1bWVudG8uXG4gICAqL1xuICBnZW5lcmF0ZUlkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuZmlyZXN0b3JlLmdlbmVyYXRlSWQodGhpcy5jb2xsZWN0aW9uUGF0aCk7XG4gIH1cblxuICAvKipcbiAgICogT2J0aWVuZSBsYSBydXRhIGRlIGxhIGNvbGVjY2nDs24uXG4gICAqL1xuICBnZXRQYXRoKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuY29sbGVjdGlvblBhdGg7XG4gIH1cbn1cblxuLyoqXG4gKiBAZGVwcmVjYXRlZCBVc2UgRmlyZXN0b3JlQ29sbGVjdGlvbkZhY3RvcnkuY3JlYXRlKCkgaW5zdGVhZC5cbiAqIFR5cGUgYWxpYXMgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LlxuICovXG5leHBvcnQgdHlwZSBGaXJlc3RvcmVDb2xsZWN0aW9uPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4gPSBUeXBlZENvbGxlY3Rpb248VD47XG4iXX0=
|