valtech-components 2.0.452 → 2.0.454

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 (48) hide show
  1. package/esm2022/lib/components/molecules/pin-input/pin-input.component.mjs +10 -2
  2. package/esm2022/lib/services/auth/auth-state.service.mjs +173 -0
  3. package/esm2022/lib/services/auth/auth.service.mjs +454 -0
  4. package/esm2022/lib/services/auth/config.mjs +76 -0
  5. package/esm2022/lib/services/auth/guards.mjs +194 -0
  6. package/esm2022/lib/services/auth/index.mjs +70 -0
  7. package/esm2022/lib/services/auth/interceptor.mjs +98 -0
  8. package/esm2022/lib/services/auth/storage.service.mjs +141 -0
  9. package/esm2022/lib/services/auth/sync.service.mjs +149 -0
  10. package/esm2022/lib/services/auth/token.service.mjs +113 -0
  11. package/esm2022/lib/services/auth/types.mjs +29 -0
  12. package/esm2022/lib/services/firebase/config.mjs +108 -0
  13. package/esm2022/lib/services/firebase/firebase.service.mjs +288 -0
  14. package/esm2022/lib/services/firebase/firestore-collection.mjs +254 -0
  15. package/esm2022/lib/services/firebase/firestore.service.mjs +509 -0
  16. package/esm2022/lib/services/firebase/index.mjs +49 -0
  17. package/esm2022/lib/services/firebase/messaging.service.mjs +512 -0
  18. package/esm2022/lib/services/firebase/shared-config.mjs +138 -0
  19. package/esm2022/lib/services/firebase/storage.service.mjs +422 -0
  20. package/esm2022/lib/services/firebase/types.mjs +8 -0
  21. package/esm2022/lib/services/firebase/utils/path-builder.mjs +195 -0
  22. package/esm2022/lib/services/firebase/utils/query-builder.mjs +302 -0
  23. package/esm2022/public-api.mjs +3 -5
  24. package/fesm2022/valtech-components.mjs +4204 -5
  25. package/fesm2022/valtech-components.mjs.map +1 -1
  26. package/lib/services/auth/auth-state.service.d.ts +85 -0
  27. package/lib/services/auth/auth.service.d.ts +146 -0
  28. package/lib/services/auth/config.d.ts +38 -0
  29. package/lib/services/auth/guards.d.ts +123 -0
  30. package/lib/services/auth/index.d.ts +63 -0
  31. package/lib/services/auth/interceptor.d.ts +22 -0
  32. package/lib/services/auth/storage.service.d.ts +48 -0
  33. package/lib/services/auth/sync.service.d.ts +49 -0
  34. package/lib/services/auth/token.service.d.ts +51 -0
  35. package/lib/services/auth/types.d.ts +315 -0
  36. package/lib/services/firebase/config.d.ts +49 -0
  37. package/lib/services/firebase/firebase.service.d.ts +140 -0
  38. package/lib/services/firebase/firestore-collection.d.ts +175 -0
  39. package/lib/services/firebase/firestore.service.d.ts +304 -0
  40. package/lib/services/firebase/index.d.ts +39 -0
  41. package/lib/services/firebase/messaging.service.d.ts +263 -0
  42. package/lib/services/firebase/shared-config.d.ts +126 -0
  43. package/lib/services/firebase/storage.service.d.ts +206 -0
  44. package/lib/services/firebase/types.d.ts +281 -0
  45. package/lib/services/firebase/utils/path-builder.d.ts +132 -0
  46. package/lib/services/firebase/utils/query-builder.d.ts +210 -0
  47. package/package.json +1 -1
  48. package/public-api.d.ts +2 -0
@@ -0,0 +1,509 @@
1
+ /**
2
+ * Firestore Service
3
+ *
4
+ * Servicio genérico para operaciones CRUD en Firestore.
5
+ * Soporta lecturas one-time, subscripciones real-time, paginación y queries complejas.
6
+ */
7
+ import { Injectable } from '@angular/core';
8
+ import { addDoc, collection, collectionData, deleteDoc, doc, docData, getDoc, getDocs, limit, orderBy, query, serverTimestamp, setDoc, startAfter, startAt, endBefore, endAt, Timestamp, updateDoc, where, writeBatch, increment, arrayUnion, arrayRemove, } from '@angular/fire/firestore';
9
+ import { map } from 'rxjs';
10
+ import { buildPath } from './utils/path-builder';
11
+ import * as i0 from "@angular/core";
12
+ import * as i1 from "@angular/fire/firestore";
13
+ /**
14
+ * Servicio para operaciones CRUD en Firestore.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * interface User extends FirestoreDocument {
19
+ * name: string;
20
+ * email: string;
21
+ * role: 'admin' | 'user';
22
+ * }
23
+ *
24
+ * @Component({...})
25
+ * export class UsersComponent {
26
+ * private firestore = inject(FirestoreService);
27
+ *
28
+ * // Lectura one-time
29
+ * async loadUser(id: string) {
30
+ * const user = await this.firestore.getDoc<User>('users', id);
31
+ * }
32
+ *
33
+ * // Subscripción real-time
34
+ * users$ = this.firestore.collectionChanges<User>('users', {
35
+ * where: [{ field: 'role', operator: '==', value: 'admin' }],
36
+ * orderBy: [{ field: 'name', direction: 'asc' }]
37
+ * });
38
+ *
39
+ * // Crear documento
40
+ * async createUser(data: Omit<User, 'id'>) {
41
+ * const user = await this.firestore.addDoc<User>('users', data);
42
+ * }
43
+ * }
44
+ * ```
45
+ */
46
+ export class FirestoreService {
47
+ constructor(firestore) {
48
+ this.firestore = firestore;
49
+ }
50
+ // ===========================================================================
51
+ // LECTURAS ONE-TIME (Promise)
52
+ // ===========================================================================
53
+ /**
54
+ * Obtiene un documento por ID (lectura única).
55
+ *
56
+ * @param collectionPath - Ruta de la colección
57
+ * @param docId - ID del documento
58
+ * @returns Documento o null si no existe
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const user = await firestoreService.getDoc<User>('users', 'abc123');
63
+ * if (user) {
64
+ * console.log(user.name);
65
+ * }
66
+ * ```
67
+ */
68
+ async getDoc(collectionPath, docId) {
69
+ const docRef = doc(this.firestore, collectionPath, docId);
70
+ const snapshot = await getDoc(docRef);
71
+ if (!snapshot.exists()) {
72
+ return null;
73
+ }
74
+ return this.mapDocument(snapshot);
75
+ }
76
+ /**
77
+ * Obtiene múltiples documentos con opciones de query.
78
+ *
79
+ * @param collectionPath - Ruta de la colección
80
+ * @param options - Opciones de query (where, orderBy, limit)
81
+ * @returns Array de documentos
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * // Todos los usuarios activos ordenados por nombre
86
+ * const users = await firestoreService.getDocs<User>('users', {
87
+ * where: [{ field: 'active', operator: '==', value: true }],
88
+ * orderBy: [{ field: 'name', direction: 'asc' }],
89
+ * limit: 50
90
+ * });
91
+ * ```
92
+ */
93
+ async getDocs(collectionPath, options) {
94
+ const collectionRef = collection(this.firestore, collectionPath);
95
+ const constraints = this.buildQueryConstraints(options);
96
+ const q = query(collectionRef, ...constraints);
97
+ const snapshot = await getDocs(q);
98
+ return snapshot.docs.map((doc) => this.mapDocument(doc));
99
+ }
100
+ /**
101
+ * Obtiene documentos con paginación basada en cursores.
102
+ *
103
+ * @param collectionPath - Ruta de la colección
104
+ * @param options - Opciones de query (debe incluir limit)
105
+ * @returns Resultado paginado con cursor para la siguiente página
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * // Primera página
110
+ * const page1 = await firestoreService.getPaginated<User>('users', {
111
+ * orderBy: [{ field: 'createdAt', direction: 'desc' }],
112
+ * limit: 10
113
+ * });
114
+ *
115
+ * // Siguiente página
116
+ * if (page1.hasMore) {
117
+ * const page2 = await firestoreService.getPaginated<User>('users', {
118
+ * orderBy: [{ field: 'createdAt', direction: 'desc' }],
119
+ * limit: 10,
120
+ * startAfter: page1.lastDoc
121
+ * });
122
+ * }
123
+ * ```
124
+ */
125
+ async getPaginated(collectionPath, options) {
126
+ const collectionRef = collection(this.firestore, collectionPath);
127
+ const constraints = this.buildQueryConstraints(options);
128
+ // Pedir uno más para saber si hay más páginas
129
+ const q = query(collectionRef, ...constraints, limit(options.limit + 1));
130
+ const snapshot = await getDocs(q);
131
+ const docs = snapshot.docs;
132
+ const hasMore = docs.length > options.limit;
133
+ // Si hay más, remover el documento extra
134
+ const resultDocs = hasMore ? docs.slice(0, -1) : docs;
135
+ const lastDoc = resultDocs.length > 0 ? resultDocs[resultDocs.length - 1] : null;
136
+ return {
137
+ data: resultDocs.map((doc) => this.mapDocument(doc)),
138
+ hasMore,
139
+ lastDoc,
140
+ };
141
+ }
142
+ /**
143
+ * Verifica si un documento existe.
144
+ *
145
+ * @param collectionPath - Ruta de la colección
146
+ * @param docId - ID del documento
147
+ * @returns true si el documento existe
148
+ */
149
+ async exists(collectionPath, docId) {
150
+ const docRef = doc(this.firestore, collectionPath, docId);
151
+ const snapshot = await getDoc(docRef);
152
+ return snapshot.exists();
153
+ }
154
+ // ===========================================================================
155
+ // SUBSCRIPCIONES REAL-TIME (Observable)
156
+ // ===========================================================================
157
+ /**
158
+ * Suscribe a cambios de un documento (real-time).
159
+ *
160
+ * @param collectionPath - Ruta de la colección
161
+ * @param docId - ID del documento
162
+ * @returns Observable que emite cuando el documento cambia
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * // En el componente
167
+ * user$ = this.firestoreService.docChanges<User>('users', this.userId);
168
+ *
169
+ * // En el template
170
+ * @if (user$ | async; as user) {
171
+ * <p>{{ user.name }}</p>
172
+ * }
173
+ * ```
174
+ */
175
+ docChanges(collectionPath, docId) {
176
+ const docRef = doc(this.firestore, collectionPath, docId);
177
+ return docData(docRef, { idField: 'id' }).pipe(map((data) => {
178
+ if (!data)
179
+ return null;
180
+ return this.convertTimestamps(data);
181
+ }));
182
+ }
183
+ /**
184
+ * Suscribe a cambios de una colección (real-time).
185
+ *
186
+ * @param collectionPath - Ruta de la colección
187
+ * @param options - Opciones de query
188
+ * @returns Observable que emite cuando la colección cambia
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * // Usuarios activos en tiempo real
193
+ * activeUsers$ = this.firestoreService.collectionChanges<User>('users', {
194
+ * where: [{ field: 'status', operator: '==', value: 'online' }]
195
+ * });
196
+ * ```
197
+ */
198
+ collectionChanges(collectionPath, options) {
199
+ const collectionRef = collection(this.firestore, collectionPath);
200
+ const constraints = this.buildQueryConstraints(options);
201
+ const q = query(collectionRef, ...constraints);
202
+ return collectionData(q, { idField: 'id' }).pipe(map((docs) => docs.map((doc) => this.convertTimestamps(doc))));
203
+ }
204
+ // ===========================================================================
205
+ // ESCRITURA
206
+ // ===========================================================================
207
+ /**
208
+ * Agrega un documento con ID auto-generado.
209
+ *
210
+ * @param collectionPath - Ruta de la colección
211
+ * @param data - Datos del documento (sin id, createdAt, updatedAt)
212
+ * @returns Documento creado con su ID
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * const newUser = await firestoreService.addDoc<User>('users', {
217
+ * name: 'John Doe',
218
+ * email: 'john@example.com',
219
+ * role: 'user'
220
+ * });
221
+ * console.log('Created user with ID:', newUser.id);
222
+ * ```
223
+ */
224
+ async addDoc(collectionPath, data) {
225
+ const collectionRef = collection(this.firestore, collectionPath);
226
+ const timestamp = serverTimestamp();
227
+ const docData = {
228
+ ...data,
229
+ createdAt: timestamp,
230
+ updatedAt: timestamp,
231
+ };
232
+ const docRef = await addDoc(collectionRef, docData);
233
+ // Obtener el documento creado para retornarlo con timestamps resueltos
234
+ const snapshot = await getDoc(docRef);
235
+ return this.mapDocument(snapshot);
236
+ }
237
+ /**
238
+ * Crea o sobrescribe un documento con ID específico.
239
+ *
240
+ * @param collectionPath - Ruta de la colección
241
+ * @param docId - ID del documento
242
+ * @param data - Datos del documento
243
+ * @param options - Opciones (merge: true para merge en lugar de sobrescribir)
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * // Sobrescribir completamente
248
+ * await firestoreService.setDoc<User>('users', 'user123', userData);
249
+ *
250
+ * // Merge con datos existentes
251
+ * await firestoreService.setDoc<User>('users', 'user123', { name: 'New Name' }, { merge: true });
252
+ * ```
253
+ */
254
+ async setDoc(collectionPath, docId, data, options) {
255
+ const docRef = doc(this.firestore, collectionPath, docId);
256
+ const timestamp = serverTimestamp();
257
+ const docData = {
258
+ ...data,
259
+ updatedAt: timestamp,
260
+ ...(options?.merge ? {} : { createdAt: timestamp }),
261
+ };
262
+ await setDoc(docRef, docData, { merge: options?.merge ?? false });
263
+ }
264
+ /**
265
+ * Actualiza campos específicos de un documento.
266
+ *
267
+ * @param collectionPath - Ruta de la colección
268
+ * @param docId - ID del documento
269
+ * @param data - Campos a actualizar
270
+ *
271
+ * @example
272
+ * ```typescript
273
+ * await firestoreService.updateDoc<User>('users', 'user123', {
274
+ * name: 'Updated Name',
275
+ * lastLogin: new Date()
276
+ * });
277
+ * ```
278
+ */
279
+ async updateDoc(collectionPath, docId, data) {
280
+ const docRef = doc(this.firestore, collectionPath, docId);
281
+ await updateDoc(docRef, {
282
+ ...data,
283
+ updatedAt: serverTimestamp(),
284
+ });
285
+ }
286
+ /**
287
+ * Elimina un documento.
288
+ *
289
+ * @param collectionPath - Ruta de la colección
290
+ * @param docId - ID del documento
291
+ *
292
+ * @example
293
+ * ```typescript
294
+ * await firestoreService.deleteDoc('users', 'user123');
295
+ * ```
296
+ */
297
+ async deleteDoc(collectionPath, docId) {
298
+ const docRef = doc(this.firestore, collectionPath, docId);
299
+ await deleteDoc(docRef);
300
+ }
301
+ // ===========================================================================
302
+ // OPERACIONES EN LOTE
303
+ // ===========================================================================
304
+ /**
305
+ * Ejecuta múltiples operaciones de escritura de forma atómica.
306
+ *
307
+ * @param operations - Función que recibe el batch y agrega operaciones
308
+ *
309
+ * @example
310
+ * ```typescript
311
+ * await firestoreService.batch((batch) => {
312
+ * batch.set('users/user1', { name: 'User 1' });
313
+ * batch.update('users/user2', { status: 'inactive' });
314
+ * batch.delete('users/user3');
315
+ * });
316
+ * ```
317
+ */
318
+ async batch(operations) {
319
+ const batch = writeBatch(this.firestore);
320
+ const batchApi = {
321
+ set: (path, data) => {
322
+ const [collectionPath, docId] = this.splitPath(path);
323
+ const docRef = doc(this.firestore, collectionPath, docId);
324
+ batch.set(docRef, {
325
+ ...data,
326
+ createdAt: serverTimestamp(),
327
+ updatedAt: serverTimestamp(),
328
+ });
329
+ },
330
+ update: (path, data) => {
331
+ const [collectionPath, docId] = this.splitPath(path);
332
+ const docRef = doc(this.firestore, collectionPath, docId);
333
+ batch.update(docRef, {
334
+ ...data,
335
+ updatedAt: serverTimestamp(),
336
+ });
337
+ },
338
+ delete: (path) => {
339
+ const [collectionPath, docId] = this.splitPath(path);
340
+ const docRef = doc(this.firestore, collectionPath, docId);
341
+ batch.delete(docRef);
342
+ },
343
+ };
344
+ operations(batchApi);
345
+ await batch.commit();
346
+ }
347
+ // ===========================================================================
348
+ // UTILIDADES
349
+ // ===========================================================================
350
+ /**
351
+ * Construye una ruta a partir de un template.
352
+ *
353
+ * @param template - Template con placeholders {param}
354
+ * @param params - Valores para los placeholders
355
+ * @returns Ruta construida
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * const path = firestoreService.buildPath('users/{userId}/documents/{docId}', {
360
+ * userId: 'user123',
361
+ * docId: 'doc456'
362
+ * });
363
+ * // => 'users/user123/documents/doc456'
364
+ * ```
365
+ */
366
+ buildPath(template, params) {
367
+ return buildPath(template, params);
368
+ }
369
+ /**
370
+ * Genera un ID único para un documento (sin crearlo).
371
+ *
372
+ * @param collectionPath - Ruta de la colección
373
+ * @returns ID único generado por Firestore
374
+ */
375
+ generateId(collectionPath) {
376
+ const collectionRef = collection(this.firestore, collectionPath);
377
+ return doc(collectionRef).id;
378
+ }
379
+ /**
380
+ * Retorna un valor de timestamp del servidor.
381
+ * Usar en campos de fecha para que Firestore asigne el timestamp.
382
+ */
383
+ serverTimestamp() {
384
+ return serverTimestamp();
385
+ }
386
+ /**
387
+ * Retorna un valor para agregar elementos a un array.
388
+ *
389
+ * @example
390
+ * ```typescript
391
+ * await firestoreService.updateDoc('users', 'user123', {
392
+ * tags: firestoreService.arrayUnion('new-tag')
393
+ * });
394
+ * ```
395
+ */
396
+ arrayUnion(...elements) {
397
+ return arrayUnion(...elements);
398
+ }
399
+ /**
400
+ * Retorna un valor para remover elementos de un array.
401
+ */
402
+ arrayRemove(...elements) {
403
+ return arrayRemove(...elements);
404
+ }
405
+ /**
406
+ * Retorna un valor para incrementar un campo numérico.
407
+ *
408
+ * @example
409
+ * ```typescript
410
+ * await firestoreService.updateDoc('users', 'user123', {
411
+ * loginCount: firestoreService.increment(1)
412
+ * });
413
+ * ```
414
+ */
415
+ increment(n) {
416
+ return increment(n);
417
+ }
418
+ // ===========================================================================
419
+ // MÉTODOS PRIVADOS
420
+ // ===========================================================================
421
+ /**
422
+ * Construye los QueryConstraints a partir de QueryOptions
423
+ */
424
+ buildQueryConstraints(options) {
425
+ const constraints = [];
426
+ if (!options)
427
+ return constraints;
428
+ // Where clauses
429
+ if (options.where) {
430
+ for (const clause of options.where) {
431
+ constraints.push(where(clause.field, clause.operator, clause.value));
432
+ }
433
+ }
434
+ // OrderBy clauses
435
+ if (options.orderBy) {
436
+ for (const clause of options.orderBy) {
437
+ constraints.push(orderBy(clause.field, clause.direction));
438
+ }
439
+ }
440
+ // Cursors para paginación
441
+ if (options.startAfter) {
442
+ constraints.push(startAfter(options.startAfter));
443
+ }
444
+ if (options.startAt) {
445
+ constraints.push(startAt(options.startAt));
446
+ }
447
+ if (options.endBefore) {
448
+ constraints.push(endBefore(options.endBefore));
449
+ }
450
+ if (options.endAt) {
451
+ constraints.push(endAt(options.endAt));
452
+ }
453
+ // Limit (se agrega al final)
454
+ if (options.limit) {
455
+ constraints.push(limit(options.limit));
456
+ }
457
+ return constraints;
458
+ }
459
+ /**
460
+ * Mapea un DocumentSnapshot a nuestro tipo
461
+ */
462
+ mapDocument(snapshot) {
463
+ const data = snapshot.data();
464
+ if (!data) {
465
+ throw new Error('Documento no tiene datos');
466
+ }
467
+ return {
468
+ id: snapshot.id,
469
+ ...this.convertTimestamps(data),
470
+ };
471
+ }
472
+ /**
473
+ * Convierte Timestamps de Firestore a Date de JavaScript
474
+ */
475
+ convertTimestamps(data) {
476
+ const result = {};
477
+ for (const [key, value] of Object.entries(data)) {
478
+ if (value instanceof Timestamp) {
479
+ result[key] = value.toDate();
480
+ }
481
+ else if (value && typeof value === 'object' && !Array.isArray(value)) {
482
+ result[key] = this.convertTimestamps(value);
483
+ }
484
+ else {
485
+ result[key] = value;
486
+ }
487
+ }
488
+ return result;
489
+ }
490
+ /**
491
+ * Divide una ruta de documento en colección e ID
492
+ */
493
+ splitPath(path) {
494
+ const segments = path.split('/');
495
+ if (segments.length < 2 || segments.length % 2 !== 0) {
496
+ throw new Error(`Ruta de documento inválida: ${path}`);
497
+ }
498
+ const docId = segments.pop();
499
+ const collectionPath = segments.join('/');
500
+ return [collectionPath, docId];
501
+ }
502
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreService, deps: [{ token: i1.Firestore }], target: i0.ɵɵFactoryTarget.Injectable }); }
503
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreService, providedIn: 'root' }); }
504
+ }
505
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreService, decorators: [{
506
+ type: Injectable,
507
+ args: [{ providedIn: 'root' }]
508
+ }], ctorParameters: () => [{ type: i1.Firestore }] });
509
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlyZXN0b3JlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ZpcmViYXNlL2ZpcmVzdG9yZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQ0wsTUFBTSxFQUNOLFVBQVUsRUFDVixjQUFjLEVBQ2QsU0FBUyxFQUNULEdBQUcsRUFDSCxPQUFPLEVBS1AsTUFBTSxFQUNOLE9BQU8sRUFDUCxLQUFLLEVBQ0wsT0FBTyxFQUNQLEtBQUssRUFFTCxlQUFlLEVBQ2YsTUFBTSxFQUNOLFVBQVUsRUFDVixPQUFPLEVBQ1AsU0FBUyxFQUNULEtBQUssRUFDTCxTQUFTLEVBQ1QsU0FBUyxFQUNULEtBQUssRUFDTCxVQUFVLEVBQ1YsU0FBUyxFQUNULFVBQVUsRUFDVixXQUFXLEdBRVosTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQUUsR0FBRyxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBR3ZDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7O0FBRWpEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdDRztBQUVILE1BQU0sT0FBTyxnQkFBZ0I7SUFDM0IsWUFBb0IsU0FBb0I7UUFBcEIsY0FBUyxHQUFULFNBQVMsQ0FBVztJQUFHLENBQUM7SUFFNUMsOEVBQThFO0lBQzlFLDhCQUE4QjtJQUM5Qiw4RUFBOEU7SUFFOUU7Ozs7Ozs7Ozs7Ozs7O09BY0c7SUFDSCxLQUFLLENBQUMsTUFBTSxDQUNWLGNBQXNCLEVBQ3RCLEtBQWE7UUFFYixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDMUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFdEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQ3ZCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBSSxRQUFRLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUNYLGNBQXNCLEVBQ3RCLE9BQXNCO1FBRXRCLE1BQU0sYUFBYSxHQUFHLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ2pFLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4RCxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsYUFBYSxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7UUFDL0MsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFbEMsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBSSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09Bd0JHO0lBQ0gsS0FBSyxDQUFDLFlBQVksQ0FDaEIsY0FBc0IsRUFDdEIsT0FBeUM7UUFFekMsTUFBTSxhQUFhLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDakUsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXhELDhDQUE4QztRQUM5QyxNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsYUFBYSxFQUFFLEdBQUcsV0FBVyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekUsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFbEMsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQztRQUMzQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUM7UUFFNUMseUNBQXlDO1FBQ3pDLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQ3RELE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBRWpGLE9BQU87WUFDTCxJQUFJLEVBQUUsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBSSxHQUFHLENBQUMsQ0FBQztZQUN2RCxPQUFPO1lBQ1AsT0FBTztTQUNSLENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0gsS0FBSyxDQUFDLE1BQU0sQ0FBQyxjQUFzQixFQUFFLEtBQWE7UUFDaEQsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzFELE1BQU0sUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RDLE9BQU8sUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCw4RUFBOEU7SUFDOUUsd0NBQXdDO0lBQ3hDLDhFQUE4RTtJQUU5RTs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQkc7SUFDSCxVQUFVLENBQ1IsY0FBc0IsRUFDdEIsS0FBYTtRQUViLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGNBQWMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMxRCxPQUFPLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQzVDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFO1lBQ1gsSUFBSSxDQUFDLElBQUk7Z0JBQUUsT0FBTyxJQUFJLENBQUM7WUFDdkIsT0FBTyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBb0IsQ0FBTSxDQUFDO1FBQzNELENBQUMsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7O09BY0c7SUFDSCxpQkFBaUIsQ0FDZixjQUFzQixFQUN0QixPQUFzQjtRQUV0QixNQUFNLGFBQWEsR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUNqRSxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDeEQsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLGFBQWEsRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDO1FBRS9DLE9BQU8sY0FBYyxDQUFDLENBQUMsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FDOUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFNLENBQUMsQ0FBQyxDQUNuRSxDQUFDO0lBQ0osQ0FBQztJQUVELDhFQUE4RTtJQUM5RSxZQUFZO0lBQ1osOEVBQThFO0lBRTlFOzs7Ozs7Ozs7Ozs7Ozs7O09BZ0JHO0lBQ0gsS0FBSyxDQUFDLE1BQU0sQ0FDVixjQUFzQixFQUN0QixJQUErQztRQUUvQyxNQUFNLGFBQWEsR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUNqRSxNQUFNLFNBQVMsR0FBRyxlQUFlLEVBQUUsQ0FBQztRQUVwQyxNQUFNLE9BQU8sR0FBRztZQUNkLEdBQUcsSUFBSTtZQUNQLFNBQVMsRUFBRSxTQUFTO1lBQ3BCLFNBQVMsRUFBRSxTQUFTO1NBQ3JCLENBQUM7UUFFRixNQUFNLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQyxhQUFhLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFcEQsdUVBQXVFO1FBQ3ZFLE1BQU0sUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RDLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBSSxRQUFRLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7T0FnQkc7SUFDSCxLQUFLLENBQUMsTUFBTSxDQUNWLGNBQXNCLEVBQ3RCLEtBQWEsRUFDYixJQUFtQixFQUNuQixPQUE2QjtRQUU3QixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDMUQsTUFBTSxTQUFTLEdBQUcsZUFBZSxFQUFFLENBQUM7UUFFcEMsTUFBTSxPQUFPLEdBQUc7WUFDZCxHQUFHLElBQUk7WUFDUCxTQUFTLEVBQUUsU0FBUztZQUNwQixHQUFHLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsQ0FBQztTQUNwRCxDQUFDO1FBRUYsTUFBTSxNQUFNLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxJQUFJLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ0gsS0FBSyxDQUFDLFNBQVMsQ0FDYixjQUFzQixFQUN0QixLQUFhLEVBQ2IsSUFBMEM7UUFFMUMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRTFELE1BQU0sU0FBUyxDQUFDLE1BQU0sRUFBRTtZQUN0QixHQUFHLElBQUk7WUFDUCxTQUFTLEVBQUUsZUFBZSxFQUFFO1NBQzdCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsS0FBSyxDQUFDLFNBQVMsQ0FBQyxjQUFzQixFQUFFLEtBQWE7UUFDbkQsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzFELE1BQU0sU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFRCw4RUFBOEU7SUFDOUUsc0JBQXNCO0lBQ3RCLDhFQUE4RTtJQUU5RTs7Ozs7Ozs7Ozs7OztPQWFHO0lBQ0gsS0FBSyxDQUFDLEtBQUssQ0FDVCxVQUlVO1FBRVYsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUV6QyxNQUFNLFFBQVEsR0FBRztZQUNmLEdBQUcsRUFBRSxDQUFJLElBQVksRUFBRSxJQUFPLEVBQUUsRUFBRTtnQkFDaEMsTUFBTSxDQUFDLGNBQWMsRUFBRSxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNyRCxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQzFELEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFO29CQUNoQixHQUFHLElBQUk7b0JBQ1AsU0FBUyxFQUFFLGVBQWUsRUFBRTtvQkFDNUIsU0FBUyxFQUFFLGVBQWUsRUFBRTtpQkFDYixDQUFDLENBQUM7WUFDckIsQ0FBQztZQUNELE1BQU0sRUFBRSxDQUFJLElBQVksRUFBRSxJQUFnQixFQUFFLEVBQUU7Z0JBQzVDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDckQsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxFQUFFLEtBQUssQ0FBQyxDQUFDO2dCQUMxRCxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRTtvQkFDbkIsR0FBRyxJQUFJO29CQUNQLFNBQVMsRUFBRSxlQUFlLEVBQUU7aUJBQ2IsQ0FBQyxDQUFDO1lBQ3JCLENBQUM7WUFDRCxNQUFNLEVBQUUsQ0FBQyxJQUFZLEVBQUUsRUFBRTtnQkFDdkIsTUFBTSxDQUFDLGNBQWMsRUFBRSxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNyRCxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQzFELEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdkIsQ0FBQztTQUNGLENBQUM7UUFFRixVQUFVLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDckIsTUFBTSxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVELDhFQUE4RTtJQUM5RSxhQUFhO0lBQ2IsOEVBQThFO0lBRTlFOzs7Ozs7Ozs7Ozs7Ozs7T0FlRztJQUNILFNBQVMsQ0FBQyxRQUFnQixFQUFFLE1BQThCO1FBQ3hELE9BQU8sU0FBUyxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNyQyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxVQUFVLENBQUMsY0FBc0I7UUFDL0IsTUFBTSxhQUFhLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDakUsT0FBTyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQy9CLENBQUM7SUFFRDs7O09BR0c7SUFDSCxlQUFlO1FBQ2IsT0FBTyxlQUFlLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0gsVUFBVSxDQUFDLEdBQUcsUUFBbUI7UUFDL0IsT0FBTyxVQUFVLENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxXQUFXLENBQUMsR0FBRyxRQUFtQjtRQUNoQyxPQUFPLFdBQVcsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSCxTQUFTLENBQUMsQ0FBUztRQUNqQixPQUFPLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0QixDQUFDO0lBRUQsOEVBQThFO0lBQzlFLG1CQUFtQjtJQUNuQiw4RUFBOEU7SUFFOUU7O09BRUc7SUFDSyxxQkFBcUIsQ0FBQyxPQUFzQjtRQUNsRCxNQUFNLFdBQVcsR0FBc0IsRUFBRSxDQUFDO1FBRTFDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTyxXQUFXLENBQUM7UUFFakMsZ0JBQWdCO1FBQ2hCLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2xCLEtBQUssTUFBTSxNQUFNLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNuQyxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDdkUsQ0FBQztRQUNILENBQUM7UUFFRCxrQkFBa0I7UUFDbEIsSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDcEIsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ3JDLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7WUFDNUQsQ0FBQztRQUNILENBQUM7UUFFRCwwQkFBMEI7UUFDMUIsSUFBSSxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDdkIsV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3BCLFdBQVcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCxJQUFJLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN0QixXQUFXLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztRQUNqRCxDQUFDO1FBQ0QsSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDbEIsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDekMsQ0FBQztRQUVELDZCQUE2QjtRQUM3QixJQUFJLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNsQixXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUN6QyxDQUFDO1FBRUQsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssV0FBVyxDQUNqQixRQUF3QztRQUV4QyxNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDN0IsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1FBQzlDLENBQUM7UUFFRCxPQUFPO1lBQ0wsRUFBRSxFQUFFLFFBQVEsQ0FBQyxFQUFFO1lBQ2YsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDO1NBQzNCLENBQUM7SUFDVCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxpQkFBaUIsQ0FBQyxJQUFrQjtRQUMxQyxNQUFNLE1BQU0sR0FBaUIsRUFBRSxDQUFDO1FBRWhDLEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDaEQsSUFBSSxLQUFLLFlBQVksU0FBUyxFQUFFLENBQUM7Z0JBQy9CLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDL0IsQ0FBQztpQkFBTSxJQUFJLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZFLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDOUMsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7WUFDdEIsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxTQUFTLENBQUMsSUFBWTtRQUM1QixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2pDLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDckQsTUFBTSxJQUFJLEtBQUssQ0FBQywrQkFBK0IsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUN6RCxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRyxDQUFDO1FBQzlCLE1BQU0sY0FBYyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUMsT0FBTyxDQUFDLGNBQWMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqQyxDQUFDOytHQTVoQlUsZ0JBQWdCO21IQUFoQixnQkFBZ0IsY0FESCxNQUFNOzs0RkFDbkIsZ0JBQWdCO2tCQUQ1QixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRmlyZXN0b3JlIFNlcnZpY2VcbiAqXG4gKiBTZXJ2aWNpbyBnZW7DqXJpY28gcGFyYSBvcGVyYWNpb25lcyBDUlVEIGVuIEZpcmVzdG9yZS5cbiAqIFNvcG9ydGEgbGVjdHVyYXMgb25lLXRpbWUsIHN1YnNjcmlwY2lvbmVzIHJlYWwtdGltZSwgcGFnaW5hY2nDs24geSBxdWVyaWVzIGNvbXBsZWphcy5cbiAqL1xuXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBhZGREb2MsXG4gIGNvbGxlY3Rpb24sXG4gIGNvbGxlY3Rpb25EYXRhLFxuICBkZWxldGVEb2MsXG4gIGRvYyxcbiAgZG9jRGF0YSxcbiAgRG9jdW1lbnREYXRhLFxuICBEb2N1bWVudFJlZmVyZW5jZSxcbiAgRG9jdW1lbnRTbmFwc2hvdCxcbiAgRmlyZXN0b3JlLFxuICBnZXREb2MsXG4gIGdldERvY3MsXG4gIGxpbWl0LFxuICBvcmRlckJ5LFxuICBxdWVyeSxcbiAgUXVlcnlDb25zdHJhaW50LFxuICBzZXJ2ZXJUaW1lc3RhbXAsXG4gIHNldERvYyxcbiAgc3RhcnRBZnRlcixcbiAgc3RhcnRBdCxcbiAgZW5kQmVmb3JlLFxuICBlbmRBdCxcbiAgVGltZXN0YW1wLFxuICB1cGRhdGVEb2MsXG4gIHdoZXJlLFxuICB3cml0ZUJhdGNoLFxuICBpbmNyZW1lbnQsXG4gIGFycmF5VW5pb24sXG4gIGFycmF5UmVtb3ZlLFxuICBGaWVsZFZhbHVlLFxufSBmcm9tICdAYW5ndWxhci9maXJlL2ZpcmVzdG9yZSc7XG5pbXBvcnQgeyBtYXAsIE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgRmlyZXN0b3JlRG9jdW1lbnQsIFBhZ2luYXRlZFJlc3VsdCwgUXVlcnlPcHRpb25zIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBidWlsZFBhdGggfSBmcm9tICcuL3V0aWxzL3BhdGgtYnVpbGRlcic7XG5cbi8qKlxuICogU2VydmljaW8gcGFyYSBvcGVyYWNpb25lcyBDUlVEIGVuIEZpcmVzdG9yZS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW50ZXJmYWNlIFVzZXIgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudCB7XG4gKiAgIG5hbWU6IHN0cmluZztcbiAqICAgZW1haWw6IHN0cmluZztcbiAqICAgcm9sZTogJ2FkbWluJyB8ICd1c2VyJztcbiAqIH1cbiAqXG4gKiBAQ29tcG9uZW50KHsuLi59KVxuICogZXhwb3J0IGNsYXNzIFVzZXJzQ29tcG9uZW50IHtcbiAqICAgcHJpdmF0ZSBmaXJlc3RvcmUgPSBpbmplY3QoRmlyZXN0b3JlU2VydmljZSk7XG4gKlxuICogICAvLyBMZWN0dXJhIG9uZS10aW1lXG4gKiAgIGFzeW5jIGxvYWRVc2VyKGlkOiBzdHJpbmcpIHtcbiAqICAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5maXJlc3RvcmUuZ2V0RG9jPFVzZXI+KCd1c2VycycsIGlkKTtcbiAqICAgfVxuICpcbiAqICAgLy8gU3Vic2NyaXBjacOzbiByZWFsLXRpbWVcbiAqICAgdXNlcnMkID0gdGhpcy5maXJlc3RvcmUuY29sbGVjdGlvbkNoYW5nZXM8VXNlcj4oJ3VzZXJzJywge1xuICogICAgIHdoZXJlOiBbeyBmaWVsZDogJ3JvbGUnLCBvcGVyYXRvcjogJz09JywgdmFsdWU6ICdhZG1pbicgfV0sXG4gKiAgICAgb3JkZXJCeTogW3sgZmllbGQ6ICduYW1lJywgZGlyZWN0aW9uOiAnYXNjJyB9XVxuICogICB9KTtcbiAqXG4gKiAgIC8vIENyZWFyIGRvY3VtZW50b1xuICogICBhc3luYyBjcmVhdGVVc2VyKGRhdGE6IE9taXQ8VXNlciwgJ2lkJz4pIHtcbiAqICAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5maXJlc3RvcmUuYWRkRG9jPFVzZXI+KCd1c2VycycsIGRhdGEpO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBGaXJlc3RvcmVTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBmaXJlc3RvcmU6IEZpcmVzdG9yZSkge31cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gTEVDVFVSQVMgT05FLVRJTUUgKFByb21pc2UpXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIHVuIGRvY3VtZW50byBwb3IgSUQgKGxlY3R1cmEgw7puaWNhKS5cbiAgICpcbiAgICogQHBhcmFtIGNvbGxlY3Rpb25QYXRoIC0gUnV0YSBkZSBsYSBjb2xlY2Npw7NuXG4gICAqIEBwYXJhbSBkb2NJZCAtIElEIGRlbCBkb2N1bWVudG9cbiAgICogQHJldHVybnMgRG9jdW1lbnRvIG8gbnVsbCBzaSBubyBleGlzdGVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCB1c2VyID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXREb2M8VXNlcj4oJ3VzZXJzJywgJ2FiYzEyMycpO1xuICAgKiBpZiAodXNlcikge1xuICAgKiAgIGNvbnNvbGUubG9nKHVzZXIubmFtZSk7XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBnZXREb2M8VCBleHRlbmRzIEZpcmVzdG9yZURvY3VtZW50PihcbiAgICBjb2xsZWN0aW9uUGF0aDogc3RyaW5nLFxuICAgIGRvY0lkOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxUIHwgbnVsbD4ge1xuICAgIGNvbnN0IGRvY1JlZiA9IGRvYyh0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgsIGRvY0lkKTtcbiAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGdldERvYyhkb2NSZWYpO1xuXG4gICAgaWYgKCFzbmFwc2hvdC5leGlzdHMoKSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMubWFwRG9jdW1lbnQ8VD4oc25hcHNob3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9idGllbmUgbcO6bHRpcGxlcyBkb2N1bWVudG9zIGNvbiBvcGNpb25lcyBkZSBxdWVyeS5cbiAgICpcbiAgICogQHBhcmFtIGNvbGxlY3Rpb25QYXRoIC0gUnV0YSBkZSBsYSBjb2xlY2Npw7NuXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3BjaW9uZXMgZGUgcXVlcnkgKHdoZXJlLCBvcmRlckJ5LCBsaW1pdClcbiAgICogQHJldHVybnMgQXJyYXkgZGUgZG9jdW1lbnRvc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIFRvZG9zIGxvcyB1c3VhcmlvcyBhY3Rpdm9zIG9yZGVuYWRvcyBwb3Igbm9tYnJlXG4gICAqIGNvbnN0IHVzZXJzID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXREb2NzPFVzZXI+KCd1c2VycycsIHtcbiAgICogICB3aGVyZTogW3sgZmllbGQ6ICdhY3RpdmUnLCBvcGVyYXRvcjogJz09JywgdmFsdWU6IHRydWUgfV0sXG4gICAqICAgb3JkZXJCeTogW3sgZmllbGQ6ICduYW1lJywgZGlyZWN0aW9uOiAnYXNjJyB9XSxcbiAgICogICBsaW1pdDogNTBcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZ2V0RG9jczxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFF1ZXJ5T3B0aW9uc1xuICApOiBQcm9taXNlPFRbXT4ge1xuICAgIGNvbnN0IGNvbGxlY3Rpb25SZWYgPSBjb2xsZWN0aW9uKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCk7XG4gICAgY29uc3QgY29uc3RyYWludHMgPSB0aGlzLmJ1aWxkUXVlcnlDb25zdHJhaW50cyhvcHRpb25zKTtcbiAgICBjb25zdCBxID0gcXVlcnkoY29sbGVjdGlvblJlZiwgLi4uY29uc3RyYWludHMpO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jcyhxKTtcblxuICAgIHJldHVybiBzbmFwc2hvdC5kb2NzLm1hcCgoZG9jKSA9PiB0aGlzLm1hcERvY3VtZW50PFQ+KGRvYykpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9idGllbmUgZG9jdW1lbnRvcyBjb24gcGFnaW5hY2nDs24gYmFzYWRhIGVuIGN1cnNvcmVzLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcGNpb25lcyBkZSBxdWVyeSAoZGViZSBpbmNsdWlyIGxpbWl0KVxuICAgKiBAcmV0dXJucyBSZXN1bHRhZG8gcGFnaW5hZG8gY29uIGN1cnNvciBwYXJhIGxhIHNpZ3VpZW50ZSBww6FnaW5hXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gUHJpbWVyYSBww6FnaW5hXG4gICAqIGNvbnN0IHBhZ2UxID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXRQYWdpbmF0ZWQ8VXNlcj4oJ3VzZXJzJywge1xuICAgKiAgIG9yZGVyQnk6IFt7IGZpZWxkOiAnY3JlYXRlZEF0JywgZGlyZWN0aW9uOiAnZGVzYycgfV0sXG4gICAqICAgbGltaXQ6IDEwXG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBTaWd1aWVudGUgcMOhZ2luYVxuICAgKiBpZiAocGFnZTEuaGFzTW9yZSkge1xuICAgKiAgIGNvbnN0IHBhZ2UyID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXRQYWdpbmF0ZWQ8VXNlcj4oJ3VzZXJzJywge1xuICAgKiAgICAgb3JkZXJCeTogW3sgZmllbGQ6ICdjcmVhdGVkQXQnLCBkaXJlY3Rpb246ICdkZXNjJyB9XSxcbiAgICogICAgIGxpbWl0OiAxMCxcbiAgICogICAgIHN0YXJ0QWZ0ZXI6IHBhZ2UxLmxhc3REb2NcbiAgICogICB9KTtcbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGdldFBhZ2luYXRlZDxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9uczogUXVlcnlPcHRpb25zICYgeyBsaW1pdDogbnVtYmVyIH1cbiAgKTogUHJvbWlzZTxQYWdpbmF0ZWRSZXN1bHQ8VD4+IHtcbiAgICBjb25zdCBjb2xsZWN0aW9uUmVmID0gY29sbGVjdGlvbih0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgpO1xuICAgIGNvbnN0IGNvbnN0cmFpbnRzID0gdGhpcy5idWlsZFF1ZXJ5Q29uc3RyYWludHMob3B0aW9ucyk7XG5cbiAgICAvLyBQZWRpciB1bm8gbcOhcyBwYXJhIHNhYmVyIHNpIGhheSBtw6FzIHDDoWdpbmFzXG4gICAgY29uc3QgcSA9IHF1ZXJ5KGNvbGxlY3Rpb25SZWYsIC4uLmNvbnN0cmFpbnRzLCBsaW1pdChvcHRpb25zLmxpbWl0ICsgMSkpO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jcyhxKTtcblxuICAgIGNvbnN0IGRvY3MgPSBzbmFwc2hvdC5kb2NzO1xuICAgIGNvbnN0IGhhc01vcmUgPSBkb2NzLmxlbmd0aCA+IG9wdGlvbnMubGltaXQ7XG5cbiAgICAvLyBTaSBoYXkgbcOhcywgcmVtb3ZlciBlbCBkb2N1bWVudG8gZXh0cmFcbiAgICBjb25zdCByZXN1bHREb2NzID0gaGFzTW9yZSA/IGRvY3Muc2xpY2UoMCwgLTEpIDogZG9jcztcbiAgICBjb25zdCBsYXN0RG9jID0gcmVzdWx0RG9jcy5sZW5ndGggPiAwID8gcmVzdWx0RG9jc1tyZXN1bHREb2NzLmxlbmd0aCAtIDFdIDogbnVsbDtcblxuICAgIHJldHVybiB7XG4gICAgICBkYXRhOiByZXN1bHREb2NzLm1hcCgoZG9jKSA9PiB0aGlzLm1hcERvY3VtZW50PFQ+KGRvYykpLFxuICAgICAgaGFzTW9yZSxcbiAgICAgIGxhc3REb2MsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmljYSBzaSB1biBkb2N1bWVudG8gZXhpc3RlLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIGRvY0lkIC0gSUQgZGVsIGRvY3VtZW50b1xuICAgKiBAcmV0dXJucyB0cnVlIHNpIGVsIGRvY3VtZW50byBleGlzdGVcbiAgICovXG4gIGFzeW5jIGV4aXN0cyhjb2xsZWN0aW9uUGF0aDogc3RyaW5nLCBkb2NJZDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jKGRvY1JlZik7XG4gICAgcmV0dXJuIHNuYXBzaG90LmV4aXN0cygpO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFNVQlNDUklQQ0lPTkVTIFJFQUwtVElNRSAoT2JzZXJ2YWJsZSlcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIFN1c2NyaWJlIGEgY2FtYmlvcyBkZSB1biBkb2N1bWVudG8gKHJlYWwtdGltZSkuXG4gICAqXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uUGF0aCAtIFJ1dGEgZGUgbGEgY29sZWNjacOzblxuICAgKiBAcGFyYW0gZG9jSWQgLSBJRCBkZWwgZG9jdW1lbnRvXG4gICAqIEByZXR1cm5zIE9ic2VydmFibGUgcXVlIGVtaXRlIGN1YW5kbyBlbCBkb2N1bWVudG8gY2FtYmlhXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gRW4gZWwgY29tcG9uZW50ZVxuICAgKiB1c2VyJCA9IHRoaXMuZmlyZXN0b3JlU2VydmljZS5kb2NDaGFuZ2VzPFVzZXI+KCd1c2VycycsIHRoaXMudXNlcklkKTtcbiAgICpcbiAgICogLy8gRW4gZWwgdGVtcGxhdGVcbiAgICogQGlmICh1c2VyJCB8IGFzeW5jOyBhcyB1c2VyKSB7XG4gICAqICAgPHA+e3sgdXNlci5uYW1lIH19PC9wPlxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgZG9jQ2hhbmdlczxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgZG9jSWQ6IHN0cmluZ1xuICApOiBPYnNlcnZhYmxlPFQgfCBudWxsPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIHJldHVybiBkb2NEYXRhKGRvY1JlZiwgeyBpZEZpZWxkOiAnaWQnIH0pLnBpcGUoXG4gICAgICBtYXAoKGRhdGEpID0+IHtcbiAgICAgICAgaWYgKCFkYXRhKSByZXR1cm4gbnVsbDtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udmVydFRpbWVzdGFtcHMoZGF0YSBhcyBEb2N1bWVudERhdGEpIGFzIFQ7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogU3VzY3JpYmUgYSBjYW1iaW9zIGRlIHVuYSBjb2xlY2Npw7NuIChyZWFsLXRpbWUpLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcGNpb25lcyBkZSBxdWVyeVxuICAgKiBAcmV0dXJucyBPYnNlcnZhYmxlIHF1ZSBlbWl0ZSBjdWFuZG8gbGEgY29sZWNjacOzbiBjYW1iaWFcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBVc3VhcmlvcyBhY3Rpdm9zIGVuIHRpZW1wbyByZWFsXG4gICAqIGFjdGl2ZVVzZXJzJCA9IHRoaXMuZmlyZXN0b3JlU2VydmljZS5jb2xsZWN0aW9uQ2hhbmdlczxVc2VyPigndXNlcnMnLCB7XG4gICAqICAgd2hlcmU6IFt7IGZpZWxkOiAnc3RhdHVzJywgb3BlcmF0b3I6ICc9PScsIHZhbHVlOiAnb25saW5lJyB9XVxuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBjb2xsZWN0aW9uQ2hhbmdlczxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFF1ZXJ5T3B0aW9uc1xuICApOiBPYnNlcnZhYmxlPFRbXT4ge1xuICAgIGNvbnN0IGNvbGxlY3Rpb25SZWYgPSBjb2xsZWN0aW9uKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCk7XG4gICAgY29uc3QgY29uc3RyYWludHMgPSB0aGlzLmJ1aWxkUXVlcnlDb25zdHJhaW50cyhvcHRpb25zKTtcbiAgICBjb25zdCBxID0gcXVlcnkoY29sbGVjdGlvblJlZiwgLi4uY29uc3RyYWludHMpO1xuXG4gICAgcmV0dXJuIGNvbGxlY3Rpb25EYXRhKHEsIHsgaWRGaWVsZDogJ2lkJyB9KS5waXBlKFxuICAgICAgbWFwKChkb2NzKSA9PiBkb2NzLm1hcCgoZG9jKSA9PiB0aGlzLmNvbnZlcnRUaW1lc3RhbXBzKGRvYykgYXMgVCkpXG4gICAgKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBFU0NSSVRVUkFcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIEFncmVnYSB1biBkb2N1bWVudG8gY29uIElEIGF1dG8tZ2VuZXJhZG8uXG4gICAqXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uUGF0aCAtIFJ1dGEgZGUgbGEgY29sZWNjacOzblxuICAgKiBAcGFyYW0gZGF0YSAtIERhdG9zIGRlbCBkb2N1bWVudG8gKHNpbiBpZCwgY3JlYXRlZEF0LCB1cGRhdGVkQXQpXG4gICAqIEByZXR1cm5zIERvY3VtZW50byBjcmVhZG8gY29uIHN1IElEXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgbmV3VXNlciA9IGF3YWl0IGZpcmVzdG9yZVNlcnZpY2UuYWRkRG9jPFVzZXI+KCd1c2VycycsIHtcbiAgICogICBuYW1lOiAnSm9obiBEb2UnLFxuICAgKiAgIGVtYWlsOiAnam9obkBleGFtcGxlLmNvbScsXG4gICAqICAgcm9sZTogJ3VzZXInXG4gICAqIH0pO1xuICAgKiBjb25zb2xlLmxvZygnQ3JlYXRlZCB1c2VyIHdpdGggSUQ6JywgbmV3VXNlci5pZCk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYWRkRG9jPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgY29sbGVjdGlvblBhdGg6IHN0cmluZyxcbiAgICBkYXRhOiBPbWl0PFQsICdpZCcgfCAnY3JlYXRlZEF0JyB8ICd1cGRhdGVkQXQnPlxuICApOiBQcm9taXNlPFQ+IHtcbiAgICBjb25zdCBjb2xsZWN0aW9uUmVmID0gY29sbGVjdGlvbih0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgpO1xuICAgIGNvbnN0IHRpbWVzdGFtcCA9IHNlcnZlclRpbWVzdGFtcCgpO1xuXG4gICAgY29uc3QgZG9jRGF0YSA9IHtcbiAgICAgIC4uLmRhdGEsXG4gICAgICBjcmVhdGVkQXQ6IHRpbWVzdGFtcCxcbiAgICAgIHVwZGF0ZWRBdDogdGltZXN0YW1wLFxuICAgIH07XG5cbiAgICBjb25zdCBkb2NSZWYgPSBhd2FpdCBhZGREb2MoY29sbGVjdGlvblJlZiwgZG9jRGF0YSk7XG5cbiAgICAvLyBPYnRlbmVyIGVsIGRvY3VtZW50byBjcmVhZG8gcGFyYSByZXRvcm5hcmxvIGNvbiB0aW1lc3RhbXBzIHJlc3VlbHRvc1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jKGRvY1JlZik7XG4gICAgcmV0dXJuIHRoaXMubWFwRG9jdW1lbnQ8VD4oc25hcHNob3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWEgbyBzb2JyZXNjcmliZSB1biBkb2N1bWVudG8gY29uIElEIGVzcGVjw61maWNvLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIGRvY0lkIC0gSUQgZGVsIGRvY3VtZW50b1xuICAgKiBAcGFyYW0gZGF0YSAtIERhdG9zIGRlbCBkb2N1bWVudG9cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcGNpb25lcyAobWVyZ2U6IHRydWUgcGFyYSBtZXJnZSBlbiBsdWdhciBkZSBzb2JyZXNjcmliaXIpXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gU29icmVzY3JpYmlyIGNvbXBsZXRhbWVudGVcbiAgICogYXdhaXQgZmlyZXN0b3JlU2VydmljZS5zZXREb2M8VXNlcj4oJ3VzZXJzJywgJ3VzZXIxMjMnLCB1c2VyRGF0YSk7XG4gICAqXG4gICAqIC8vIE1lcmdlIGNvbiBkYXRvcyBleGlzdGVudGVzXG4gICAqIGF3YWl0IGZpcmVzdG9yZVNlcnZpY2Uuc2V0RG9jPFVzZXI+KCd1c2VycycsICd1c2VyMTIzJywgeyBuYW1lOiAnTmV3IE5hbWUnIH0sIHsgbWVyZ2U6IHRydWUgfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgc2V0RG9jPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgY29sbGVjdGlvblBhdGg6IHN0cmluZyxcbiAgICBkb2NJZDogc3RyaW5nLFxuICAgIGRhdGE6IE9taXQ8VCwgJ2lkJz4sXG4gICAgb3B0aW9ucz86IHsgbWVyZ2U/OiBib29sZWFuIH1cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIGNvbnN0IHRpbWVzdGFtcCA9IHNlcnZlclRpbWVzdGFtcCgpO1xuXG4gICAgY29uc3QgZG9jRGF0YSA9IHtcbiAgICAgIC4uLmRhdGEsXG4gICAgICB1cGRhdGVkQXQ6IHRpbWVzdGFtcCxcbiAgICAgIC4uLihvcHRpb25zPy5tZXJnZSA/IHt9IDogeyBjcmVhdGVkQXQ6IHRpbWVzdGFtcCB9KSxcbiAgICB9O1xuXG4gICAgYXdhaXQgc2V0RG9jKGRvY1JlZiwgZG9jRGF0YSwgeyBtZXJnZTogb3B0aW9ucz8ubWVyZ2UgPz8gZmFsc2UgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWN0dWFsaXphIGNhbXBvcyBlc3BlY8OtZmljb3MgZGUgdW4gZG9jdW1lbnRvLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIGRvY0lkIC0gSUQgZGVsIGRvY3VtZW50b1xuICAgKiBAcGFyYW0gZGF0YSAtIENhbXBvcyBhIGFjdHVhbGl6YXJcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCBmaXJlc3RvcmVTZXJ2aWNlLnVwZGF0ZURvYzxVc2VyPigndXNlcnMnLCAndXNlcjEyMycsIHtcbiAgICogICBuYW1lOiAnVXBkYXRlZCBOYW1lJyxcbiAgICogICBsYXN0TG9naW46IG5ldyBEYXRlKClcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgdXBkYXRlRG9jPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgY29sbGVjdGlvblBhdGg6IHN0cmluZyxcbiAgICBkb2NJZDogc3RyaW5nLFxuICAgIGRhdGE6IFBhcnRpYWw8T21pdDxULCAnaWQnIHwgJ2NyZWF0ZWRBdCc+PlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBkb2NSZWYgPSBkb2ModGhpcy5maXJlc3RvcmUsIGNvbGxlY3Rpb25QYXRoLCBkb2NJZCk7XG5cbiAgICBhd2FpdCB1cGRhdGVEb2MoZG9jUmVmLCB7XG4gICAgICAuLi5kYXRhLFxuICAgICAgdXBkYXRlZEF0OiBzZXJ2ZXJUaW1lc3RhbXAoKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbGltaW5hIHVuIGRvY3VtZW50by5cbiAgICpcbiAgICogQHBhcmFtIGNvbGxlY3Rpb25QYXRoIC0gUnV0YSBkZSBsYSBjb2xlY2Npw7NuXG4gICAqIEBwYXJhbSBkb2NJZCAtIElEIGRlbCBkb2N1bWVudG9cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCBmaXJlc3RvcmVTZXJ2aWNlLmRlbGV0ZURvYygndXNlcnMnLCAndXNlcjEyMycpO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGRlbGV0ZURvYyhjb2xsZWN0aW9uUGF0aDogc3RyaW5nLCBkb2NJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIGF3YWl0IGRlbGV0ZURvYyhkb2NSZWYpO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIE9QRVJBQ0lPTkVTIEVOIExPVEVcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIEVqZWN1dGEgbcO6bHRpcGxlcyBvcGVyYWNpb25lcyBkZSBlc2NyaXR1cmEgZGUgZm9ybWEgYXTDs21pY2EuXG4gICAqXG4gICAqIEBwYXJhbSBvcGVyYXRpb25zIC0gRnVuY2nDs24gcXVlIHJlY2liZSBlbCBiYXRjaCB5IGFncmVnYSBvcGVyYWNpb25lc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGF3YWl0IGZpcmVzdG9yZVNlcnZpY2UuYmF0Y2goKGJhdGNoKSA9PiB7XG4gICAqICAgYmF0Y2guc2V0KCd1c2Vycy91c2VyMScsIHsgbmFtZTogJ1VzZXIgMScgfSk7XG4gICAqICAgYmF0Y2gudXBkYXRlKCd1c2Vycy91c2VyMicsIHsgc3RhdHVzOiAnaW5hY3RpdmUnIH0pO1xuICAgKiAgIGJhdGNoLmRlbGV0ZSgndXNlcnMvdXNlcjMnKTtcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYmF0Y2goXG4gICAgb3BlcmF0aW9uczogKGJhdGNoOiB7XG4gICAgICBzZXQ6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFQpID0+IHZvaWQ7XG4gICAgICB1cGRhdGU6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFBhcnRpYWw8VD4pID0+IHZvaWQ7XG4gICAgICBkZWxldGU6IChwYXRoOiBzdHJpbmcpID0+IHZvaWQ7XG4gICAgfSkgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBiYXRjaCA9IHdyaXRlQmF0Y2godGhpcy5maXJlc3RvcmUpO1xuXG4gICAgY29uc3QgYmF0Y2hBcGkgPSB7XG4gICAgICBzZXQ6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFQpID0+IHtcbiAgICAgICAgY29uc3QgW2NvbGxlY3Rpb25QYXRoLCBkb2NJZF0gPSB0aGlzLnNwbGl0UGF0aChwYXRoKTtcbiAgICAgICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgICAgICBiYXRjaC5zZXQoZG9jUmVmLCB7XG4gICAgICAgICAgLi4uZGF0YSxcbiAgICAgICAgICBjcmVhdGVkQXQ6IHNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICAgIHVwZGF0ZWRBdDogc2VydmVyVGltZXN0YW1wKCksXG4gICAgICAgIH0gYXMgRG9jdW1lbnREYXRhKTtcbiAgICAgIH0sXG4gICAgICB1cGRhdGU6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFBhcnRpYWw8VD4pID0+IHtcbiAgICAgICAgY29uc3QgW2NvbGxlY3Rpb25QYXRoLCBkb2NJZF0gPSB0aGlzLnNwbGl0UGF0aChwYXRoKTtcbiAgICAgICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgICAgICBiYXRjaC51cGRhdGUoZG9jUmVmLCB7XG4gICAgICAgICAgLi4uZGF0YSxcbiAgICAgICAgICB1cGRhdGVkQXQ6IHNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICB9IGFzIERvY3VtZW50RGF0YSk7XG4gICAgICB9LFxuICAgICAgZGVsZXRlOiAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IFtjb2xsZWN0aW9uUGF0aCwgZG9jSWRdID0gdGhpcy5zcGxpdFBhdGgocGF0aCk7XG4gICAgICAgIGNvbnN0IGRvY1JlZiA9IGRvYyh0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgsIGRvY0lkKTtcbiAgICAgICAgYmF0Y2guZGVsZXRlKGRvY1JlZik7XG4gICAgICB9LFxuICAgIH07XG5cbiAgICBvcGVyYXRpb25zKGJhdGNoQXBpKTtcbiAgICBhd2FpdCBiYXRjaC5jb21taXQoKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBVVElMSURBREVTXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBDb25zdHJ1eWUgdW5hIHJ1dGEgYSBwYXJ0aXIgZGUgdW4gdGVtcGxhdGUuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZSAtIFRlbXBsYXRlIGNvbiBwbGFjZWhvbGRlcnMge3BhcmFtfVxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVmFsb3JlcyBwYXJhIGxvcyBwbGFjZWhvbGRlcnNcbiAgICogQHJldHVybnMgUnV0YSBjb25zdHJ1aWRhXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgcGF0aCA9IGZpcmVzdG9yZVNlcnZpY2UuYnVpbGRQYXRoKCd1c2Vycy97dXNlcklkfS9kb2N1bWVudHMve2RvY0lkfScsIHtcbiAgICogICB1c2VySWQ6ICd1c2VyMTIzJyxcbiAgICogICBkb2NJZDogJ2RvYzQ1NidcbiAgICogfSk7XG4gICAqIC8vID0+ICd1c2Vycy91c2VyMTIzL2RvY3VtZW50cy9kb2M0NTYnXG4gICAqIGBgYFxuICAgKi9cbiAgYnVpbGRQYXRoKHRlbXBsYXRlOiBzdHJpbmcsIHBhcmFtczogUmVjb3JkPHN0cmluZywgc3RyaW5nPik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGJ1aWxkUGF0aCh0ZW1wbGF0ZSwgcGFyYW1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmEgdW4gSUQgw7puaWNvIHBhcmEgdW4gZG9jdW1lbnRvIChzaW4gY3JlYXJsbykuXG4gICAqXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uUGF0aCAtIFJ1dGEgZGUgbGEgY29sZWNjacOzblxuICAgKiBAcmV0dXJucyBJRCDDum5pY28gZ2VuZXJhZG8gcG9yIEZpcmVzdG9yZVxuICAgKi9cbiAgZ2VuZXJhdGVJZChjb2xsZWN0aW9uUGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBjb2xsZWN0aW9uUmVmID0gY29sbGVjdGlvbih0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgpO1xuICAgIHJldHVybiBkb2MoY29sbGVjdGlvblJlZikuaWQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0b3JuYSB1biB2YWxvciBkZSB0aW1lc3RhbXAgZGVsIHNlcnZpZG9yLlxuICAgKiBVc2FyIGVuIGNhbXBvcyBkZSBmZWNoYSBwYXJhIHF1ZSBGaXJlc3RvcmUgYXNpZ25lIGVsIHRpbWVzdGFtcC5cbiAgICovXG4gIHNlcnZlclRpbWVzdGFtcCgpOiBGaWVsZFZhbHVlIHtcbiAgICByZXR1cm4gc2VydmVyVGltZXN0YW1wKCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0b3JuYSB1biB2YWxvciBwYXJhIGFncmVnYXIgZWxlbWVudG9zIGEgdW4gYXJyYXkuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogYXdhaXQgZmlyZXN0b3JlU2VydmljZS51cGRhdGVEb2MoJ3VzZXJzJywgJ3VzZXIxMjMnLCB7XG4gICAqICAgdGFnczogZmlyZXN0b3JlU2VydmljZS5hcnJheVVuaW9uKCduZXctdGFnJylcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXJyYXlVbmlvbiguLi5lbGVtZW50czogdW5rbm93bltdKTogRmllbGRWYWx1ZSB7XG4gICAgcmV0dXJuIGFycmF5VW5pb24oLi4uZWxlbWVudHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldG9ybmEgdW4gdmFsb3IgcGFyYSByZW1vdmVyIGVsZW1lbnRvcyBkZSB1biBhcnJheS5cbiAgICovXG4gIGFycmF5UmVtb3ZlKC4uLmVsZW1lbnRzOiB1bmtub3duW10pOiBGaWVsZFZhbHVlIHtcbiAgICByZXR1cm4gYXJyYXlSZW1vdmUoLi4uZWxlbWVudHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldG9ybmEgdW4gdmFsb3IgcGFyYSBpbmNyZW1lbnRhciB1biBjYW1wbyBudW3DqXJpY28uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogYXdhaXQgZmlyZXN0b3JlU2VydmljZS51cGRhdGVEb2MoJ3VzZXJzJywgJ3VzZXIxMjMnLCB7XG4gICAqICAgbG9naW5Db3VudDogZmlyZXN0b3JlU2VydmljZS5pbmNyZW1lbnQoMSlcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgaW5jcmVtZW50KG46IG51bWJlcik6IEZpZWxkVmFsdWUge1xuICAgIHJldHVybiBpbmNyZW1lbnQobik7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gTcOJVE9ET1MgUFJJVkFET1NcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIENvbnN0cnV5ZSBsb3MgUXVlcnlDb25zdHJhaW50cyBhIHBhcnRpciBkZSBRdWVyeU9wdGlvbnNcbiAgICovXG4gIHByaXZhdGUgYnVpbGRRdWVyeUNvbnN0cmFpbnRzKG9wdGlvbnM/OiBRdWVyeU9wdGlvbnMpOiBRdWVyeUNvbnN0cmFpbnRbXSB7XG4gICAgY29uc3QgY29uc3RyYWludHM6IFF1ZXJ5Q29uc3RyYWludFtdID0gW107XG5cbiAgICBpZiAoIW9wdGlvbnMpIHJldHVybiBjb25zdHJhaW50cztcblxuICAgIC8vIFdoZXJlIGNsYXVzZXNcbiAgICBpZiAob3B0aW9ucy53aGVyZSkge1xuICAgICAgZm9yIChjb25zdCBjbGF1c2Ugb2Ygb3B0aW9ucy53aGVyZSkge1xuICAgICAgICBjb25zdHJhaW50cy5wdXNoKHdoZXJlKGNsYXVzZS5maWVsZCwgY2xhdXNlLm9wZXJhdG9yLCBjbGF1c2UudmFsdWUpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBPcmRlckJ5IGNsYXVzZXNcbiAgICBpZiAob3B0aW9ucy5vcmRlckJ5KSB7XG4gICAgICBmb3IgKGNvbnN0IGNsYXVzZSBvZiBvcHRpb25zLm9yZGVyQnkpIHtcbiAgICAgICAgY29uc3RyYWludHMucHVzaChvcmRlckJ5KGNsYXVzZS5maWVsZCwgY2xhdXNlLmRpcmVjdGlvbikpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEN1cnNvcnMgcGFyYSBwYWdpbmFjacOzblxuICAgIGlmIChvcHRpb25zLnN0YXJ0QWZ0ZXIpIHtcbiAgICAgIGNvbnN0cmFpbnRzLnB1c2goc3RhcnRBZnRlcihvcHRpb25zLnN0YXJ0QWZ0ZXIpKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuc3RhcnRBdCkge1xuICAgICAgY29uc3RyYWludHMucHVzaChzdGFydEF0KG9wdGlvbnMuc3RhcnRBdCkpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5lbmRCZWZvcmUpIHtcbiAgICAgIGNvbnN0cmFpbnRzLnB1c2goZW5kQmVmb3JlKG9wdGlvbnMuZW5kQmVmb3JlKSk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLmVuZEF0KSB7XG4gICAgICBjb25zdHJhaW50cy5wdXNoKGVuZEF0KG9wdGlvbnMuZW5kQXQpKTtcbiAgICB9XG5cbiAgICAvLyBMaW1pdCAoc2UgYWdyZWdhIGFsIGZpbmFsKVxuICAgIGlmIChvcHRpb25zLmxpbWl0KSB7XG4gICAgICBjb25zdHJhaW50cy5wdXNoKGxpbWl0KG9wdGlvbnMubGltaXQpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY29uc3RyYWludHM7XG4gIH1cblxuICAvKipcbiAgICogTWFwZWEgdW4gRG9jdW1lbnRTbmFwc2hvdCBhIG51ZXN0cm8gdGlwb1xuICAgKi9cbiAgcHJpdmF0ZSBtYXBEb2N1bWVudDxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIHNuYXBzaG90OiBEb2N1bWVudFNuYXBzaG90PERvY3VtZW50RGF0YT5cbiAgKTogVCB7XG4gICAgY29uc3QgZGF0YSA9IHNuYXBzaG90LmRhdGEoKTtcbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRG9jdW1lbnRvIG5vIHRpZW5lIGRhdG9zJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBzbmFwc2hvdC5pZCxcbiAgICAgIC4uLnRoaXMuY29udmVydFRpbWVzdGFtcHMoZGF0YSksXG4gICAgfSBhcyBUO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZpZXJ0ZSBUaW1lc3RhbXBzIGRlIEZpcmVzdG9yZSBhIERhdGUgZGUgSmF2YVNjcmlwdFxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0VGltZXN0YW1wcyhkYXRhOiBEb2N1bWVudERhdGEpOiBEb2N1bWVudERhdGEge1xuICAgIGNvbnN0IHJlc3VsdDogRG9jdW1lbnREYXRhID0ge307XG5cbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhkYXRhKSkge1xuICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgVGltZXN0YW1wKSB7XG4gICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWUudG9EYXRlKCk7XG4gICAgICB9IGVsc2UgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgIHJlc3VsdFtrZXldID0gdGhpcy5jb252ZXJ0VGltZXN0YW1wcyh2YWx1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHRba2V5XSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogRGl2aWRlIHVuYSBydXRhIGRlIGRvY3VtZW50byBlbiBjb2xlY2Npw7NuIGUgSURcbiAgICovXG4gIHByaXZhdGUgc3BsaXRQYXRoKHBhdGg6IHN0cmluZyk6IFtzdHJpbmcsIHN0cmluZ10ge1xuICAgIGNvbnN0IHNlZ21lbnRzID0gcGF0aC5zcGxpdCgnLycpO1xuICAgIGlmIChzZWdtZW50cy5sZW5ndGggPCAyIHx8IHNlZ21lbnRzLmxlbmd0aCAlIDIgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUnV0YSBkZSBkb2N1bWVudG8gaW52w6FsaWRhOiAke3BhdGh9YCk7XG4gICAgfVxuICAgIGNvbnN0IGRvY0lkID0gc2VnbWVudHMucG9wKCkhO1xuICAgIGNvbnN0IGNvbGxlY3Rpb25QYXRoID0gc2VnbWVudHMuam9pbignLycpO1xuICAgIHJldHVybiBbY29sbGVjdGlvblBhdGgsIGRvY0lkXTtcbiAgfVxufVxuIl19
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Firebase Services
3
+ *
4
+ * Servicios reutilizables para integración con Firebase.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // En main.ts
9
+ * import { provideValtechFirebase } from 'valtech-components';
10
+ *
11
+ * bootstrapApplication(AppComponent, {
12
+ * providers: [
13
+ * provideValtechFirebase({
14
+ * firebase: environment.firebase,
15
+ * persistence: true,
16
+ * }),
17
+ * ],
18
+ * });
19
+ *
20
+ * // En componentes
21
+ * import { FirebaseService, FirestoreService } from 'valtech-components';
22
+ *
23
+ * @Component({...})
24
+ * export class MyComponent {
25
+ * private firebase = inject(FirebaseService);
26
+ * private firestore = inject(FirestoreService);
27
+ * }
28
+ * ```
29
+ */
30
+ // Tipos
31
+ export * from './types';
32
+ // Configuración
33
+ export { VALTECH_FIREBASE_CONFIG, hasEmulators, provideValtechFirebase } from './config';
34
+ // Configuración compartida del monorepo
35
+ export { APP_IDS, FIREBASE_PROJECTS, SHARED_EMULATOR_CONFIG, collections, createFirebaseConfig, isEmulatorMode, storagePaths, } from './shared-config';
36
+ // Servicios
37
+ export { FirebaseService } from './firebase.service';
38
+ // Firestore
39
+ export { FirestoreService } from './firestore.service';
40
+ // Firestore Collections (Factory Pattern)
41
+ export { FirestoreCollectionFactory, TypedCollection, } from './firestore-collection';
42
+ // Utilidades
43
+ export { QueryBuilder, query } from './utils/query-builder';
44
+ export { buildPath, extractPathParams, getCollectionPath, getDocumentId, isCollectionPath, isDocumentPath, isValidPath, joinPath, } from './utils/path-builder';
45
+ // Storage
46
+ export { StorageService } from './storage.service';
47
+ // Messaging (FCM)
48
+ export { MessagingService } from './messaging.service';
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ZpcmViYXNlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNEJHO0FBRUgsUUFBUTtBQUNSLGNBQWMsU0FBUyxDQUFDO0FBRXhCLGdCQUFnQjtBQUNoQixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsWUFBWSxFQUFFLHNCQUFzQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRXpGLHdDQUF3QztBQUN4QyxPQUFPLEVBQ0wsT0FBTyxFQUNQLGlCQUFpQixFQUNqQixzQkFBc0IsRUFDdEIsV0FBVyxFQUNYLG9CQUFvQixFQUNwQixjQUFjLEVBQ2QsWUFBWSxHQUdiLE1BQU0saUJBQWlCLENBQUM7QUFFekIsWUFBWTtBQUNaLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxZQUFZO0FBQ1osT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdkQsMENBQTBDO0FBQzFDLE9BQU8sRUFHTCwwQkFBMEIsRUFFMUIsZUFBZSxHQUNoQixNQUFNLHdCQUF3QixDQUFDO0FBRWhDLGFBQWE7QUFDYixPQUFPLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzVELE9BQU8sRUFDTCxTQUFTLEVBQ1QsaUJBQWlCLEVBQ2pCLGlCQUFpQixFQUNqQixhQUFhLEVBQ2IsZ0JBQWdCLEVBQ2hCLGNBQWMsRUFDZCxXQUFXLEVBQ1gsUUFBUSxHQUNULE1BQU0sc0JBQXNCLENBQUM7QUFFOUIsVUFBVTtBQUNWLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUVuRCxrQkFBa0I7QUFDbEIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZpcmViYXNlIFNlcnZpY2VzXG4gKlxuICogU2VydmljaW9zIHJldXRpbGl6YWJsZXMgcGFyYSBpbnRlZ3JhY2nDs24gY29uIEZpcmViYXNlLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBFbiBtYWluLnRzXG4gKiBpbXBvcnQgeyBwcm92aWRlVmFsdGVjaEZpcmViYXNlIH0gZnJvbSAndmFsdGVjaC1jb21wb25lbnRzJztcbiAqXG4gKiBib290c3RyYXBBcHBsaWNhdGlvbihBcHBDb21wb25lbnQsIHtcbiAqICAgcHJvdmlkZXJzOiBbXG4gKiAgICAgcHJvdmlkZVZhbHRlY2hGaXJlYmFzZSh7XG4gKiAgICAgICBmaXJlYmFzZTogZW52aXJvbm1lbnQuZmlyZWJhc2UsXG4gKiAgICAgICBwZXJzaXN0ZW5jZTogdHJ1ZSxcbiAqICAgICB9KSxcbiAqICAgXSxcbiAqIH0pO1xuICpcbiAqIC8vIEVuIGNvbXBvbmVudGVzXG4gKiBpbXBvcnQgeyBGaXJlYmFzZVNlcnZpY2UsIEZpcmVzdG9yZVNlcnZpY2UgfSBmcm9tICd2YWx0ZWNoLWNvbXBvbmVudHMnO1xuICpcbiAqIEBDb21wb25lbnQoey4uLn0pXG4gKiBleHBvcnQgY2xhc3MgTXlDb21wb25lbnQge1xuICogICBwcml2YXRlIGZpcmViYXNlID0gaW5qZWN0KEZpcmViYXNlU2VydmljZSk7XG4gKiAgIHByaXZhdGUgZmlyZXN0b3JlID0gaW5qZWN0KEZpcmVzdG9yZVNlcnZpY2UpO1xuICogfVxuICogYGBgXG4gKi9cblxuLy8gVGlwb3NcbmV4cG9ydCAqIGZyb20gJy4vdHlwZXMnO1xuXG4vLyBDb25maWd1cmFjacOzblxuZXhwb3J0IHsgVkFMVEVDSF9GSVJFQkFTRV9DT05GSUcsIGhhc0VtdWxhdG9ycywgcHJvdmlkZVZhbHRlY2hGaXJlYmFzZSB9IGZyb20gJy4vY29uZmlnJztcblxuLy8gQ29uZmlndXJhY2nDs24gY29tcGFydGlkYSBkZWwgbW9ub3JlcG9cbmV4cG9ydCB7XG4gIEFQUF9JRFMsXG4gIEZJUkVCQVNFX1BST0pFQ1RTLFxuICBTSEFSRURfRU1VTEFUT1JfQ09ORklHLFxuICBjb2xsZWN0aW9ucyxcbiAgY3JlYXRlRmlyZWJhc2VDb25maWcsXG4gIGlzRW11bGF0b3JNb2RlLFxuICBzdG9yYWdlUGF0aHMsXG4gIHR5cGUgQXBwSWQsXG4gIHR5cGUgQ3JlYXRlRmlyZWJhc2VDb25maWdPcHRpb25zLFxufSBmcm9tICcuL3NoYXJlZC1jb25maWcnO1xuXG4vLyBTZXJ2aWNpb3NcbmV4cG9ydCB7IEZpcmViYXNlU2VydmljZSB9IGZyb20gJy4vZmlyZWJhc2Uuc2VydmljZSc7XG5cbi8vIEZpcmVzdG9yZVxuZXhwb3J0IHsgRmlyZXN0b3JlU2VydmljZSB9IGZyb20gJy4vZmlyZXN0b3JlLnNlcnZpY2UnO1xuXG4vLyBGaXJlc3RvcmUgQ29sbGVjdGlvbnMgKEZhY3RvcnkgUGF0dGVybilcbmV4cG9ydCB7XG4gIENvbGxlY3Rpb25PcHRpb25zLFxuICBGaXJlc3RvcmVDb2xsZWN0aW9uLFxuICBGaXJlc3RvcmVDb2xsZWN0aW9uRmFjdG9yeSxcbiAgU3ViQ29sbGVjdGlvblJlZixcbiAgVHlwZWRDb2xsZWN0aW9uLFxufSBmcm9tICcuL2ZpcmVzdG9yZS1jb2xsZWN0aW9uJztcblxuLy8gVXRpbGlkYWRlc1xuZXhwb3J0IHsgUXVlcnlCdWlsZGVyLCBxdWVyeSB9IGZyb20gJy4vdXRpbHMvcXVlcnktYnVpbGRlcic7XG5leHBvcnQge1xuICBidWlsZFBhdGgsXG4gIGV4dHJhY3RQYXRoUGFyYW1zLFxuICBnZXRDb2xsZWN0aW9uUGF0aCxcbiAgZ2V0RG9jdW1lbnRJZCxcbiAgaXNDb2xsZWN0aW9uUGF0aCxcbiAgaXNEb2N1bWVudFBhdGgsXG4gIGlzVmFsaWRQYXRoLFxuICBqb2luUGF0aCxcbn0gZnJvbSAnLi91dGlscy9wYXRoLWJ1aWxkZXInO1xuXG4vLyBTdG9yYWdlXG5leHBvcnQgeyBTdG9yYWdlU2VydmljZSB9IGZyb20gJy4vc3RvcmFnZS5zZXJ2aWNlJztcblxuLy8gTWVzc2FnaW5nIChGQ00pXG5leHBvcnQgeyBNZXNzYWdpbmdTZXJ2aWNlIH0gZnJvbSAnLi9tZXNzYWdpbmcuc2VydmljZSc7XG4iXX0=