@fireflysemantics/slice 14.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,599 @@
1
+ import { AbstractStore } from './AbstractStore';
2
+ import { GUID } from './utilities';
3
+ import { ReplaySubject, of } from 'rxjs';
4
+ import { takeWhile, filter, switchMap } from 'rxjs/operators';
5
+ import { Slice } from './Slice';
6
+ /**
7
+ * This `todoFactory` code will be used to illustrate the API examples. The following
8
+ * utilities are used in the tests and the API Typedoc examples contained here.
9
+ * @example Utilities for API Examples
10
+ ```
11
+ export const enum TodoSliceEnum {
12
+ COMPLETE = "Complete",
13
+ INCOMPLETE = "Incomplete"
14
+ }
15
+
16
+ export class Todo {
17
+ constructor(public complete: boolean, public title: string,public gid?:string, public id?:string) {}
18
+ }
19
+
20
+ export let todos = [new Todo(false, "You complete me!"), new Todo(true, "You completed me!")];
21
+
22
+ export function todosFactory():Todo[] {
23
+ return [new Todo(false, "You complete me!"), new Todo(true, "You completed me!")];
24
+ }
25
+ ```
26
+ */
27
+ export class EStore extends AbstractStore {
28
+ /**
29
+ * Store constructor (Initialization with element is optional)
30
+ *
31
+ * perform initial notification to all observers,
32
+ * such that function like {@link combineLatest}{}
33
+ * will execute at least once.
34
+ * @param entities
35
+ * @example Dynamic `EStore<Todo>` Creation
36
+ ```
37
+ // Initialize the Store
38
+ let store: EStore<Todo> = new EStore<Todo>(todosFactory());
39
+ ```*/
40
+ constructor(entities = [], config) {
41
+ super(config);
42
+ /**
43
+ * An Observable<E[]> reference so that
44
+ *
45
+ */
46
+ this.observable = this.observe();
47
+ /**
48
+ * Notifies observers when the store is empty.
49
+ */
50
+ this.notifyActive = new ReplaySubject(1);
51
+ /**
52
+ * `Map` of active entties. The instance is public and can be used
53
+ * directly to add and remove active entities, however we recommend
54
+ * using the {@link addActive} and {@link deleteActive} methods.
55
+ */
56
+ this.active = new Map();
57
+ /**
58
+ * Notifies observers when the store is loading.
59
+ *
60
+ * This is a common pattern found when implementing
61
+ * `Observable` data sources.
62
+ */
63
+ this.notifyLoading = new ReplaySubject(1);
64
+ /**
65
+ * The current loading state. Use loading when fetching new
66
+ * data for the store. The default loading state is `true`.
67
+ *
68
+ * This is such that if data is fetched asynchronously
69
+ * in a service, components can wait on loading notification
70
+ * before attempting to retrieve data from the service.
71
+ *
72
+ * Loading could be based on a composite response. For example
73
+ * when the stock and mutual funds have loaded, set loading to `false`.
74
+ */
75
+ this._loading = true;
76
+ /**
77
+ * Notifies observers that a search is in progress.
78
+ *
79
+ * This is a common pattern found when implementing
80
+ * `Observable` data sources.
81
+ */
82
+ this.notifySearching = new ReplaySubject(1);
83
+ /**
84
+ * The current `searching` state. Use `searching`
85
+ * for example to display a spinnner
86
+ * when performing a search.
87
+ * The default `searching` state is `false`.
88
+ */
89
+ this._searching = false;
90
+ /**
91
+ * Store slices
92
+ */
93
+ this.slices = new Map();
94
+ const delta = { type: "Initialize" /* INTIALIZE */, entries: entities };
95
+ this.post(entities);
96
+ this.notifyDelta.next(delta);
97
+ }
98
+ /**
99
+ * Calls complete on all {@link BehaviorSubject} instances.
100
+ *
101
+ * Call destroy when disposing of the store.
102
+ */
103
+ destroy() {
104
+ super.destroy();
105
+ this.notifyLoading.complete();
106
+ this.notifyActive.complete();
107
+ this.slices.forEach(slice => slice.destroy());
108
+ }
109
+ /**
110
+ * Toggles the entity:
111
+ *
112
+ * If the store contains the entity
113
+ * it will be deleted. If the store
114
+ * does not contains the entity,
115
+ * it is added.
116
+ * @param e
117
+ * @example Toggle the `Todo` instance
118
+ ```
119
+ estore.post(todo);
120
+ // Remove todo
121
+ estore.toggle(todo);
122
+ // Add it back
123
+ estore.toggle(todo);
124
+
125
+ ```
126
+ */
127
+ toggle(e) {
128
+ if (this.contains(e)) {
129
+ this.delete(e);
130
+ }
131
+ else {
132
+ this.post(e);
133
+ }
134
+ }
135
+ /**
136
+ * Add multiple entity entities to active.
137
+ *
138
+ * If the entity is not contained in the store it is added
139
+ * to the store before it is added to `active`.
140
+ *
141
+ * Also we clone the map prior to broadcasting it with
142
+ * `notifyActive` to make sure we will trigger Angular
143
+ * change detection in the event that it maintains
144
+ * a reference to the `active` state `Map` instance.
145
+ *
146
+ * @example Add a `todo1` and `todo2` as active
147
+ ```
148
+ addActive(todo1);
149
+ addActive(todo2);
150
+ ```
151
+ */
152
+ addActive(e) {
153
+ if (this.contains(e)) {
154
+ this.active.set(e.gid, e);
155
+ this.notifyActive.next(new Map(this.active));
156
+ }
157
+ else {
158
+ this.post(e);
159
+ this.active.set(e.gid, e);
160
+ this.notifyActive.next(new Map(this.active));
161
+ }
162
+ }
163
+ /**
164
+ * Delete an entity as active.
165
+ *
166
+ * Also we clone the map prior to broadcasting it with
167
+ * `notifyActive` to make sure we will trigger Angular
168
+ * change detection in the event that it maintains
169
+ * a reference to the `active` state `Map` instance.
170
+ *
171
+ * @example Mark a `todo` instance as active
172
+ ```
173
+ deleteActive(todo1);
174
+ deleteActive(todo2);
175
+ ```
176
+ */
177
+ deleteActive(e) {
178
+ this.active.delete(e.gid);
179
+ this.notifyActive.next(new Map(this.active));
180
+ }
181
+ /**
182
+ * Clear / reset the active entity map.
183
+ *
184
+ * Also we clone the map prior to broadcasting it with
185
+ * `notifyActive` to make sure we will trigger Angular
186
+ * change detection in the event that it maintains
187
+ * a reference to the `active` state `Map` instance.
188
+ *
189
+ * @example Mark a `todo` instance as active
190
+ ```
191
+ deleteActive(todo1);
192
+ deleteActive(todo2);
193
+ ```
194
+ */
195
+ clearActive() {
196
+ this.active.clear();
197
+ this.notifyActive.next(new Map(this.active));
198
+ }
199
+ /**
200
+ * Observe the active entity.
201
+ * @example
202
+ <pre>
203
+ let active$ = source.observeActive();
204
+ </pre>
205
+ */
206
+ observeActive() {
207
+ return this.notifyActive.asObservable();
208
+ }
209
+ /**
210
+ * Sets the current loading state and notifies observers.
211
+ */
212
+ set loading(loading) {
213
+ this._loading = loading;
214
+ this.notifyLoading.next(this._loading);
215
+ }
216
+ /**
217
+ * @return A snapshot of the loading state.
218
+ */
219
+ get loading() {
220
+ return this._loading;
221
+ }
222
+ /**
223
+ * Observe loading.
224
+ * @example
225
+ <pre>
226
+ let loading$ = source.observeLoading();
227
+ </pre>
228
+
229
+ Note that this obverable piped through
230
+ `takeWhile(v->v, true), such that it will
231
+ complete after each emission.
232
+
233
+ See:
234
+ https://medium.com/@ole.ersoy/waiting-on-estore-to-load-8dcbe161613c
235
+
236
+ For more details.
237
+ */
238
+ observeLoading() {
239
+ return this.notifyLoading.asObservable().
240
+ pipe(takeWhile(v => v, true));
241
+ }
242
+ /**
243
+ * Notfiies when loading has completed.
244
+ */
245
+ observeLoadingComplete() {
246
+ return this.observeLoading().pipe(filter(loading => loading == false), switchMap(() => of(true)));
247
+ }
248
+ /**
249
+ * Sets the current searching state and notifies observers.
250
+ */
251
+ set searching(searching) {
252
+ this._searching = searching;
253
+ this.notifySearching.next(this._searching);
254
+ }
255
+ /**
256
+ * @return A snapshot of the searching state.
257
+ */
258
+ get searching() {
259
+ return this._searching;
260
+ }
261
+ /**
262
+ * Observe searching.
263
+ * @example
264
+ <pre>
265
+ let searching$ = source.observeSearching();
266
+ </pre>
267
+
268
+ Note that this obverable piped through
269
+ `takeWhile(v->v, true), such that it will
270
+ complete after each emission.
271
+
272
+ See:
273
+ https://medium.com/@ole.ersoy/waiting-on-estore-to-load-8dcbe161613c
274
+
275
+ For more details.
276
+ */
277
+ observeSearching() {
278
+ return this.notifySearching.asObservable().
279
+ pipe(takeWhile(v => v, true));
280
+ }
281
+ /**
282
+ * Notfiies when searching has completed.
283
+ */
284
+ observeSearchingComplete() {
285
+ return this.observeSearching().pipe(filter(searching => searching == false), switchMap(() => of(true)));
286
+ }
287
+ /**
288
+ * Adds a slice to the store and keys it by the slices label.
289
+ *
290
+ * @param p
291
+ * @param label
292
+ *
293
+ * @example Setup a Todo Slice for COMPLETE Todos
294
+ ```
295
+ source.addSlice(todo => todo.complete, TodoSlices.COMPLETE);
296
+ ```
297
+ */
298
+ addSlice(p, label) {
299
+ const slice = new Slice(label, p, this);
300
+ this.slices.set(slice.label, slice);
301
+ }
302
+ /**
303
+ * Remove a slice
304
+ * @param label The label identifying the slice
305
+ *
306
+ * @example Remove the TodoSlices.COMPLETE Slice
307
+ ```
308
+ source.removeSlice(TodoSlices.COMPLETE);
309
+ ```
310
+ */
311
+ removeSlice(label) {
312
+ this.slices.delete(label);
313
+ }
314
+ /**
315
+ * Get a slice
316
+ * @param label The label identifying the slice
317
+ * @return The Slice instance or undefined
318
+ *
319
+ * @example Get the TodoSlices.COMPLETE slice
320
+ ```
321
+ source.getSlice(TodoSlices.COMPLETE);
322
+ ```
323
+ */
324
+ getSlice(label) {
325
+ return this.slices.get(label);
326
+ }
327
+ /**
328
+ * Post (Add a new) element(s) to the store.
329
+ * @param e An indiidual entity or an array of entities
330
+ * @example Post a `todo`.
331
+ ```
332
+ store.post(todo);
333
+ ```
334
+ */
335
+ post(e) {
336
+ if (!Array.isArray(e)) {
337
+ const guid = e[this.GUID_KEY]
338
+ ? e[this.GUID_KEY]
339
+ : GUID();
340
+ e[this.GUID_KEY] = guid;
341
+ this.entries.set(guid, e);
342
+ this.updateIDEntry(e);
343
+ Array.from(this.slices.values()).forEach(s => {
344
+ s.post(e);
345
+ });
346
+ //Create a new array reference to trigger Angular change detection.
347
+ let v = [...Array.from(this.entries.values())];
348
+ const delta = { type: "Post" /* POST */, entries: [e] };
349
+ this.notifyAll(v, delta);
350
+ }
351
+ else {
352
+ this.postA(e);
353
+ }
354
+ }
355
+ /**
356
+ * Post elements to the store.
357
+ * @param ...e
358
+ * @example Post two `Todo` instances.
359
+ ```
360
+ store.post(todo1, todo2);
361
+ ```
362
+ */
363
+ postN(...e) {
364
+ e.forEach(e => {
365
+ const guid = e[this.GUID_KEY]
366
+ ? e[this.GUID_KEY]
367
+ : GUID();
368
+ e[this.GUID_KEY] = guid;
369
+ this.entries.set(guid, e);
370
+ this.updateIDEntry(e);
371
+ });
372
+ Array.from(this.slices.values()).forEach(s => {
373
+ s.postA(e);
374
+ });
375
+ //Create a new array reference to trigger Angular change detection.
376
+ let v = [...Array.from(this.entries.values())];
377
+ const delta = { type: "Post" /* POST */, entries: e };
378
+ this.notifyAll(v, delta);
379
+ }
380
+ /**
381
+ * Post (Add) an array of elements to the store.
382
+ * @param e
383
+ * @example Post a `Todo` array.
384
+ ```
385
+ store.post([todo1, todo2]);
386
+ ```
387
+ */
388
+ postA(e) {
389
+ this.postN(...e);
390
+ }
391
+ /**
392
+ * Put (Update) an element.
393
+ * @param e
394
+ * @example Put a Todo instance.
395
+ ```
396
+ store.put(todo1);
397
+ ```
398
+ */
399
+ put(e) {
400
+ if (!Array.isArray(e)) {
401
+ let id = e[this.GUID_KEY];
402
+ this.entries.set(id, e);
403
+ this.updateIDEntry(e);
404
+ let v = [...Array.from(this.entries.values())];
405
+ this.notify.next(v);
406
+ const delta = { type: "Put" /* PUT */, entries: [e] };
407
+ this.notifyDelta.next(delta);
408
+ Array.from(this.slices.values()).forEach(s => {
409
+ s.put(e);
410
+ });
411
+ }
412
+ else {
413
+ this.putA(e);
414
+ }
415
+ }
416
+ /**
417
+ * Put (Update) an element or add an element that was read from a persistence source
418
+ * and thus already has an assigned global id`.
419
+ * @param e
420
+ * @example Put Todo instances.
421
+ ```
422
+ store.put(todo1, todo2);
423
+ ```
424
+ */
425
+ putN(...e) {
426
+ this.putA(e);
427
+ }
428
+ /**
429
+ * Put (Update) the array of elements.
430
+ * @param e
431
+ * @example Put Todo instances.
432
+ ```
433
+ store.put([todo1, todo2]);
434
+ ```
435
+ */
436
+ putA(e) {
437
+ e.forEach(e => {
438
+ let guid = e[this.GUID_KEY];
439
+ this.entries.set(guid, e);
440
+ this.updateIDEntry(e);
441
+ });
442
+ //Create a new array reference to trigger Angular change detection.
443
+ let v = [...Array.from(this.entries.values())];
444
+ this.notify.next(v);
445
+ const delta = { type: "Put" /* PUT */, entries: e };
446
+ this.notifyDelta.next(delta);
447
+ Array.from(this.slices.values()).forEach(s => {
448
+ s.putA(e);
449
+ });
450
+ }
451
+ /**
452
+ * Delete (Update) the array of elements.
453
+ * @param e
454
+ * @example Delete todo1.
455
+ ```
456
+ store.delete(todo1]);
457
+ ```
458
+ */
459
+ delete(e) {
460
+ if (!Array.isArray(e)) {
461
+ this.deleteActive(e);
462
+ const guid = e[this.GUID_KEY];
463
+ this.entries.delete(guid);
464
+ this.deleteIDEntry(e);
465
+ Array.from(this.slices.values()).forEach(s => {
466
+ s.entries.delete(guid);
467
+ });
468
+ //Create a new array reference to trigger Angular change detection.
469
+ let v = [...Array.from(this.entries.values())];
470
+ const delta = { type: "Delete" /* DELETE */, entries: [e] };
471
+ this.notifyAll(v, delta);
472
+ Array.from(this.slices.values()).forEach(s => {
473
+ s.delete(e);
474
+ });
475
+ }
476
+ else {
477
+ this.deleteA(e);
478
+ }
479
+ }
480
+ /**
481
+ * Delete N elements.
482
+ * @param ...e
483
+ * @example Put Todo instances.
484
+ ```
485
+ store.delete(todo1, todo2);
486
+ ```
487
+ */
488
+ deleteN(...e) {
489
+ this.deleteA(e);
490
+ }
491
+ /**
492
+ * Delete N elements.
493
+ * @param ...e
494
+ * @example Put Todo instances.
495
+ ```
496
+ store.delete(todo1, todo2);
497
+ ```
498
+ */
499
+ deleteA(e) {
500
+ e.forEach(e => {
501
+ this.deleteActive(e);
502
+ const guid = e[this.GUID_KEY];
503
+ this.entries.delete(guid);
504
+ this.deleteIDEntry(e);
505
+ Array.from(this.slices.values()).forEach(s => {
506
+ s.entries.delete(guid);
507
+ });
508
+ });
509
+ //Create a new array reference to trigger Angular change detection.
510
+ let v = [...Array.from(this.entries.values())];
511
+ const delta = { type: "Delete" /* DELETE */, entries: e };
512
+ this.notifyAll(v, delta);
513
+ Array.from(this.slices.values()).forEach(s => {
514
+ s.deleteA(e);
515
+ });
516
+ }
517
+ /**
518
+ * Delete elements by {@link Predicate}.
519
+ * @param p The predicate.
520
+ * @example Put Todo instances.
521
+ ```
522
+ store.delete(todo1, todo2);
523
+ ```
524
+ */
525
+ deleteP(p) {
526
+ const d = [];
527
+ Array.from(this.entries.values()).forEach(e => {
528
+ if (p(e)) {
529
+ d.push(e);
530
+ const id = e[this.GUID_KEY];
531
+ this.entries.delete(id);
532
+ this.deleteActive(e);
533
+ this.deleteIDEntry(e);
534
+ }
535
+ });
536
+ //Create a new array reference to trigger Angular change detection.
537
+ let v = [...Array.from(this.entries.values())];
538
+ const delta = { type: "Delete" /* DELETE */, entries: d };
539
+ this.notifyAll(v, delta);
540
+ Array.from(this.slices.values()).forEach(s => {
541
+ s.deleteA(d);
542
+ });
543
+ }
544
+ /**
545
+ * If the entity has the `id` key initialized with a value,
546
+ * then also add the entity to the `idEntries`.
547
+ *
548
+ * @param e The element to be added to the `idEntries`.
549
+ */
550
+ updateIDEntry(e) {
551
+ if (e[this.ID_KEY]) {
552
+ this.idEntries.set(e[this.ID_KEY], e);
553
+ }
554
+ }
555
+ /**
556
+ * If the entity has the `id` key initialized with a value,
557
+ * then also delete the entity to the `idEntries`.
558
+ *
559
+ * @param e The element to be added to the `idEntries`.
560
+ */
561
+ deleteIDEntry(e) {
562
+ if (e[this.ID_KEY]) {
563
+ this.idEntries.delete(e[this.ID_KEY]);
564
+ }
565
+ }
566
+ /**
567
+ * Resets the store and all contained slice instances to empty.
568
+ * Also perform delta notification that sends all current store entries.
569
+ * The ActionType.RESET code is sent with the delta notification. Slices
570
+ * send their own delta notification.
571
+ *
572
+ * @example Reset the store.
573
+ ```
574
+ store.reset();
575
+ ```
576
+ */
577
+ reset() {
578
+ const delta = {
579
+ type: "Reset" /* RESET */,
580
+ entries: Array.from(this.entries.values())
581
+ };
582
+ this.notifyAll([], delta);
583
+ this.entries = new Map();
584
+ Array.from(this.slices.values()).forEach(s => {
585
+ s.reset();
586
+ });
587
+ }
588
+ /**
589
+ * Call all the notifiers at once.
590
+ *
591
+ * @param v
592
+ * @param delta
593
+ */
594
+ notifyAll(v, delta) {
595
+ super.notifyAll(v, delta);
596
+ this.notifyLoading.next(this.loading);
597
+ }
598
+ }
599
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRVN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvc2xpY2Uvc3JjL2xpYi9FU3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWhELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHbkMsT0FBTyxFQUFFLGFBQWEsRUFBRSxFQUFFLEVBQWMsTUFBTSxNQUFNLENBQUM7QUFDckQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUVoQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFFSCxNQUFNLE9BQU8sTUFBVSxTQUFRLGFBQWdCO0lBQzdDOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsWUFBWSxXQUFnQixFQUFFLEVBQUUsTUFBb0I7UUFDbEQsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBNENoQjs7O1dBR0c7UUFDSSxlQUFVLEdBQW9CLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQTtRQUVuRDs7V0FFRztRQUNLLGlCQUFZLEdBQUcsSUFBSSxhQUFhLENBQWlCLENBQUMsQ0FBQyxDQUFDO1FBRzVEOzs7O1dBSUc7UUFDSSxXQUFNLEdBQW1CLElBQUksR0FBRyxFQUFFLENBQUM7UUE2RjFDOzs7OztXQUtHO1FBQ0ssa0JBQWEsR0FBRyxJQUFJLGFBQWEsQ0FBVSxDQUFDLENBQUMsQ0FBQztRQUV0RDs7Ozs7Ozs7OztXQVVHO1FBQ0ssYUFBUSxHQUFZLElBQUksQ0FBQztRQStEakM7Ozs7O1dBS0c7UUFDSyxvQkFBZSxHQUFHLElBQUksYUFBYSxDQUFVLENBQUMsQ0FBQyxDQUFDO1FBRXhEOzs7OztXQUtHO1FBQ0ssZUFBVSxHQUFZLEtBQUssQ0FBQztRQXFEcEM7O1dBRUc7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RiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFic3RyYWN0U3RvcmUgfSBmcm9tICcuL0Fic3RyYWN0U3RvcmUnO1xuaW1wb3J0IHsgU3RvcmVDb25maWcgfSBmcm9tICcuL21vZGVscy9TdG9yZUNvbmZpZyc7XG5pbXBvcnQgeyBHVUlEIH0gZnJvbSAnLi91dGlsaXRpZXMnO1xuXG5pbXBvcnQgeyBBY3Rpb25UeXBlcywgUHJlZGljYXRlLCBEZWx0YSB9IGZyb20gJy4vbW9kZWxzLyc7XG5pbXBvcnQgeyBSZXBsYXlTdWJqZWN0LCBvZiwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgdGFrZVdoaWxlLCBmaWx0ZXIsIHN3aXRjaE1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IFNsaWNlIH0gZnJvbSAnLi9TbGljZSc7XG5cbi8qKlxuICogVGhpcyBgdG9kb0ZhY3RvcnlgIGNvZGUgd2lsbCBiZSB1c2VkIHRvIGlsbHVzdHJhdGUgdGhlIEFQSSBleGFtcGxlcy4gIFRoZSBmb2xsb3dpbmdcbiAqIHV0aWxpdGllcyBhcmUgdXNlZCBpbiB0aGUgdGVzdHMgYW5kIHRoZSBBUEkgVHlwZWRvYyBleGFtcGxlcyBjb250YWluZWQgaGVyZS5cbiAqIEBleGFtcGxlIFV0aWxpdGllcyBmb3IgQVBJIEV4YW1wbGVzXG5gYGBcbmV4cG9ydCBjb25zdCBlbnVtIFRvZG9TbGljZUVudW0ge1xuICBDT01QTEVURSA9IFwiQ29tcGxldGVcIixcbiAgSU5DT01QTEVURSA9IFwiSW5jb21wbGV0ZVwiXG59XG5cbmV4cG9ydCBjbGFzcyBUb2RvIHtcbiAgY29uc3RydWN0b3IocHVibGljIGNvbXBsZXRlOiBib29sZWFuLCBwdWJsaWMgdGl0bGU6IHN0cmluZyxwdWJsaWMgZ2lkPzpzdHJpbmcsIHB1YmxpYyBpZD86c3RyaW5nKSB7fVxufVxuXG5leHBvcnQgbGV0IHRvZG9zID0gW25ldyBUb2RvKGZhbHNlLCBcIllvdSBjb21wbGV0ZSBtZSFcIiksIG5ldyBUb2RvKHRydWUsIFwiWW91IGNvbXBsZXRlZCBtZSFcIildO1xuXG5leHBvcnQgZnVuY3Rpb24gdG9kb3NGYWN0b3J5KCk6VG9kb1tdIHtcbiAgcmV0dXJuIFtuZXcgVG9kbyhmYWxzZSwgXCJZb3UgY29tcGxldGUgbWUhXCIpLCBuZXcgVG9kbyh0cnVlLCBcIllvdSBjb21wbGV0ZWQgbWUhXCIpXTtcbn1cbiBgYGAgXG4gKi9cblxuZXhwb3J0IGNsYXNzIEVTdG9yZTxFPiBleHRlbmRzIEFic3RyYWN0U3RvcmU8RT4ge1xuICAvKipcbiAgICogU3RvcmUgY29uc3RydWN0b3IgKEluaXRpYWxpemF0aW9uIHdpdGggZWxlbWVudCBpcyBvcHRpb25hbClcbiAgICpcbiAgICogcGVyZm9ybSBpbml0aWFsIG5vdGlmaWNhdGlvbiB0byBhbGwgb2JzZXJ2ZXJzLFxuICAgKiBzdWNoIHRoYXQgZnVuY3Rpb24gbGlrZSB7QGxpbmsgY29tYmluZUxhdGVzdH17fVxuICAgKiB3aWxsIGV4ZWN1dGUgYXQgbGVhc3Qgb25jZS5cbiAgICogQHBhcmFtIGVudGl0aWVzXG4gICAqIEBleGFtcGxlIER5bmFtaWMgYEVTdG9yZTxUb2RvPmAgQ3JlYXRpb24gXG5gYGBcbi8vIEluaXRpYWxpemUgdGhlIFN0b3JlXG5sZXQgc3RvcmU6IEVTdG9yZTxUb2RvPiA9IG5ldyBFU3RvcmU8VG9kbz4odG9kb3NGYWN0b3J5KCkpO1xuYGBgKi9cbiAgY29uc3RydWN0b3IoZW50aXRpZXM6IEVbXSA9IFtdLCBjb25maWc/OiBTdG9yZUNvbmZpZykge1xuICAgIHN1cGVyKGNvbmZpZyk7XG4gICAgY29uc3QgZGVsdGE6IERlbHRhPEU+ID0geyB0eXBlOiBBY3Rpb25UeXBlcy5JTlRJQUxJWkUsIGVudHJpZXM6IGVudGl0aWVzIH07XG4gICAgdGhpcy5wb3N0KGVudGl0aWVzKVxuICAgIHRoaXMubm90aWZ5RGVsdGEubmV4dChkZWx0YSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbHMgY29tcGxldGUgb24gYWxsIHtAbGluayBCZWhhdmlvclN1YmplY3R9IGluc3RhbmNlcy5cbiAgICogXG4gICAqIENhbGwgZGVzdHJveSB3aGVuIGRpc3Bvc2luZyBvZiB0aGUgc3RvcmUuXG4gICAqL1xuICBkZXN0cm95KCkge1xuICAgIHN1cGVyLmRlc3Ryb3koKVxuICAgIHRoaXMubm90aWZ5TG9hZGluZy5jb21wbGV0ZSgpXG4gICAgdGhpcy5ub3RpZnlBY3RpdmUuY29tcGxldGUoKVxuICAgIHRoaXMuc2xpY2VzLmZvckVhY2goc2xpY2UgPT4gc2xpY2UuZGVzdHJveSgpKVxuICB9XG5cbiAgLyoqXG4gICAqIFRvZ2dsZXMgdGhlIGVudGl0eTpcbiAgICogXG4gICAqIElmIHRoZSBzdG9yZSBjb250YWlucyB0aGUgZW50aXR5XG4gICAqIGl0IHdpbGwgYmUgZGVsZXRlZC4gIElmIHRoZSBzdG9yZSBcbiAgICogZG9lcyBub3QgY29udGFpbnMgdGhlIGVudGl0eSxcbiAgICogaXQgaXMgYWRkZWQuXG4gICAqIEBwYXJhbSBlIFxuICAgKiBAZXhhbXBsZSBUb2dnbGUgdGhlIGBUb2RvYCBpbnN0YW5jZVxuYGBgXG5lc3RvcmUucG9zdCh0b2RvKTtcbi8vIFJlbW92ZSB0b2RvXG5lc3RvcmUudG9nZ2xlKHRvZG8pO1xuLy8gQWRkIGl0IGJhY2tcbmVzdG9yZS50b2dnbGUodG9kbyk7XG5cbmBgYFxuICAgKi9cbiAgcHVibGljIHRvZ2dsZShlOiBFKSB7XG4gICAgaWYgKHRoaXMuY29udGFpbnMoZSkpIHtcbiAgICAgIHRoaXMuZGVsZXRlKGUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnBvc3QoZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFuIE9ic2VydmFibGU8RVtdPiByZWZlcmVuY2Ugc28gdGhhdCBcbiAgICogXG4gICAqL1xuICBwdWJsaWMgb2JzZXJ2YWJsZTogT2JzZXJ2YWJsZTxFW10+ID0gdGhpcy5vYnNlcnZlKClcblxuICAvKipcbiAgICogTm90aWZpZXMgb2JzZXJ2ZXJzIHdoZW4gdGhlIHN0b3JlIGlzIGVtcHR5LlxuICAgKi9cbiAgcHJpdmF0ZSBub3RpZnlBY3RpdmUgPSBuZXcgUmVwbGF5U3ViamVjdDxNYXA8c3RyaW5nLCBFPj4oMSk7XG5cblxuICAvKipcbiAgICogYE1hcGAgb2YgYWN0aXZlIGVudHRpZXMuIFRoZSBpbnN0YW5jZSBpcyBwdWJsaWMgYW5kIGNhbiBiZSB1c2VkXG4gICAqIGRpcmVjdGx5IHRvIGFkZCBhbmQgcmVtb3ZlIGFjdGl2ZSBlbnRpdGllcywgaG93ZXZlciB3ZSByZWNvbW1lbmRcbiAgICogdXNpbmcgdGhlIHtAbGluayBhZGRBY3RpdmV9IGFuZCB7QGxpbmsgZGVsZXRlQWN0aXZlfSBtZXRob2RzLlxuICAgKi9cbiAgcHVibGljIGFjdGl2ZTogTWFwPHN0cmluZywgRT4gPSBuZXcgTWFwKCk7XG5cbiAgLyoqXG4gICAqIEFkZCBtdWx0aXBsZSBlbnRpdHkgZW50aXRpZXMgdG8gYWN0aXZlLlxuICAgKiBcbiAgICogSWYgdGhlIGVudGl0eSBpcyBub3QgY29udGFpbmVkIGluIHRoZSBzdG9yZSBpdCBpcyBhZGRlZFxuICAgKiB0byB0aGUgc3RvcmUgYmVmb3JlIGl0IGlzIGFkZGVkIHRvIGBhY3RpdmVgLlxuICAgKiBcbiAgICogQWxzbyB3ZSBjbG9uZSB0aGUgbWFwIHByaW9yIHRvIGJyb2FkY2FzdGluZyBpdCB3aXRoXG4gICAqIGBub3RpZnlBY3RpdmVgIHRvIG1ha2Ugc3VyZSB3ZSB3aWxsIHRyaWdnZXIgQW5ndWxhciBcbiAgICogY2hhbmdlIGRldGVjdGlvbiBpbiB0aGUgZXZlbnQgdGhhdCBpdCBtYWludGFpbnMgXG4gICAqIGEgcmVmZXJlbmNlIHRvIHRoZSBgYWN0aXZlYCBzdGF0ZSBgTWFwYCBpbnN0YW5jZS5cbiAgICogXG4gICAqIEBleGFtcGxlIEFkZCBhIGB0b2RvMWAgYW5kIGB0b2RvMmAgYXMgYWN0aXZlXG5gYGBcbmFkZEFjdGl2ZSh0b2RvMSk7XG5hZGRBY3RpdmUodG9kbzIpO1xuYGBgXG4gICAqL1xuICBwdWJsaWMgYWRkQWN0aXZlKGU6IEUpIHtcbiAgICBpZiAodGhpcy5jb250YWlucyhlKSkge1xuICAgICAgdGhpcy5hY3RpdmUuc2V0KCg8YW55PmUpLmdpZCwgZSk7XG4gICAgICB0aGlzLm5vdGlmeUFjdGl2ZS5uZXh0KG5ldyBNYXAodGhpcy5hY3RpdmUpKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICB0aGlzLnBvc3QoZSk7XG4gICAgICB0aGlzLmFjdGl2ZS5zZXQoKDxhbnk+ZSkuZ2lkLCBlKTtcbiAgICAgIHRoaXMubm90aWZ5QWN0aXZlLm5leHQobmV3IE1hcCh0aGlzLmFjdGl2ZSkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgYW4gZW50aXR5IGFzIGFjdGl2ZS5cbiAgICogXG4gICAqIEFsc28gd2UgY2xvbmUgdGhlIG1hcCBwcmlvciB0byBicm9hZGNhc3RpbmcgaXQgd2l0aFxuICAgKiBgbm90aWZ5QWN0aXZlYCB0byBtYWtlIHN1cmUgd2Ugd2lsbCB0cmlnZ2VyIEFuZ3VsYXIgXG4gICAqIGNoYW5nZSBkZXRlY3Rpb24gaW4gdGhlIGV2ZW50IHRoYXQgaXQgbWFpbnRhaW5zIFxuICAgKiBhIHJlZmVyZW5jZSB0byB0aGUgYGFjdGl2ZWAgc3RhdGUgYE1hcGAgaW5zdGFuY2UuXG4gICAqIFxuICAgKiBAZXhhbXBsZSBNYXJrIGEgYHRvZG9gIGluc3RhbmNlIGFzIGFjdGl2ZVxuICBgYGBcbmRlbGV0ZUFjdGl2ZSh0b2RvMSk7XG5kZWxldGVBY3RpdmUodG9kbzIpO1xuICBgYGBcbiAgICovXG4gIHB1YmxpYyBkZWxldGVBY3RpdmUoZTogRSkge1xuICAgIHRoaXMuYWN0aXZlLmRlbGV0ZSgoPGFueT5lKS5naWQpO1xuICAgIHRoaXMubm90aWZ5QWN0aXZlLm5leHQobmV3IE1hcCh0aGlzLmFjdGl2ZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFyIC8gcmVzZXQgdGhlIGFjdGl2ZSBlbnRpdHkgbWFwLlxuICAgKiBcbiAgICogQWxzbyB3ZSBjbG9uZSB0aGUgbWFwIHByaW9yIHRvIGJyb2FkY2FzdGluZyBpdCB3aXRoXG4gICAqIGBub3RpZnlBY3RpdmVgIHRvIG1ha2Ugc3VyZSB3ZSB3aWxsIHRyaWdnZXIgQW5ndWxhciBcbiAgICogY2hhbmdlIGRldGVjdGlvbiBpbiB0aGUgZXZlbnQgdGhhdCBpdCBtYWludGFpbnMgXG4gICAqIGEgcmVmZXJlbmNlIHRvIHRoZSBgYWN0aXZlYCBzdGF0ZSBgTWFwYCBpbnN0YW5jZS5cbiAgICogXG4gICAqIEBleGFtcGxlIE1hcmsgYSBgdG9kb2AgaW5zdGFuY2UgYXMgYWN0aXZlXG4gIGBgYFxuZGVsZXRlQWN0aXZlKHRvZG8xKTtcbmRlbGV0ZUFjdGl2ZSh0b2RvMik7XG4gIGBgYFxuICAgKi9cbiAgY2xlYXJBY3RpdmUoKSB7XG4gICAgdGhpcy5hY3RpdmUuY2xlYXIoKTtcbiAgICB0aGlzLm5vdGlmeUFjdGl2ZS5uZXh0KG5ldyBNYXAodGhpcy5hY3RpdmUpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnNlcnZlIHRoZSBhY3RpdmUgZW50aXR5LlxuICAgKiBAZXhhbXBsZVxuICAgICA8cHJlPlxuICAgIGxldCBhY3RpdmUkID0gc291cmNlLm9ic2VydmVBY3RpdmUoKTtcbiAgICA8L3ByZT5cbiAgKi9cbiAgcHVibGljIG9ic2VydmVBY3RpdmUoKSB7XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5QWN0aXZlLmFzT2JzZXJ2YWJsZSgpXG4gIH1cblxuXG4gIC8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIExPQURJTkdcbiAgLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogT2JzZXJ2YWJsZSBvZiBlcnJvcnMgb2NjdXJyZWQgZHVyaW5nIGEgbG9hZCByZXF1ZXN0LlxuICAgKiBcbiAgICogVGhlIGVycm9yIE9ic2VydmFibGUgc2hvdWxkIGJlIGNyZWF0ZWQgYnkgdGhlIFxuICAgKiBjbGllbnQuXG4gICAqL1xuICBwdWJsaWMgbG9hZGluZ0Vycm9yITogT2JzZXJ2YWJsZTxhbnk+O1xuXG4gIC8qKlxuICAgKiBOb3RpZmllcyBvYnNlcnZlcnMgd2hlbiB0aGUgc3RvcmUgaXMgbG9hZGluZy5cbiAgICogXG4gICAqIFRoaXMgaXMgYSBjb21tb24gcGF0dGVybiBmb3VuZCB3aGVuIGltcGxlbWVudGluZ1xuICAgKiBgT2JzZXJ2YWJsZWAgZGF0YSBzb3VyY2VzLlxuICAgKi9cbiAgcHJpdmF0ZSBub3RpZnlMb2FkaW5nID0gbmV3IFJlcGxheVN1YmplY3Q8Ym9vbGVhbj4oMSk7XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGxvYWRpbmcgc3RhdGUuICBVc2UgbG9hZGluZyB3aGVuIGZldGNoaW5nIG5ld1xuICAgKiBkYXRhIGZvciB0aGUgc3RvcmUuICBUaGUgZGVmYXVsdCBsb2FkaW5nIHN0YXRlIGlzIGB0cnVlYC5cbiAgICogXG4gICAqIFRoaXMgaXMgc3VjaCB0aGF0IGlmIGRhdGEgaXMgZmV0Y2hlZCBhc3luY2hyb25vdXNseSBcbiAgICogaW4gYSBzZXJ2aWNlLCBjb21wb25lbnRzIGNhbiB3YWl0IG9uIGxvYWRpbmcgbm90aWZpY2F0aW9uXG4gICAqIGJlZm9yZSBhdHRlbXB0aW5nIHRvIHJldHJpZXZlIGRhdGEgZnJvbSB0aGUgc2VydmljZS5cbiAgICpcbiAgICogTG9hZGluZyBjb3VsZCBiZSBiYXNlZCBvbiBhIGNvbXBvc2l0ZSByZXNwb25zZS4gIEZvciBleGFtcGxlXG4gICAqIHdoZW4gdGhlIHN0b2NrIGFuZCBtdXR1YWwgZnVuZHMgaGF2ZSBsb2FkZWQsIHNldCBsb2FkaW5nIHRvIGBmYWxzZWAuXG4gICAqL1xuICBwcml2YXRlIF9sb2FkaW5nOiBib29sZWFuID0gdHJ1ZTtcblxuICAvKipcbiAgICogU2V0cyB0aGUgY3VycmVudCBsb2FkaW5nIHN0YXRlIGFuZCBub3RpZmllcyBvYnNlcnZlcnMuXG4gICAqL1xuICBzZXQgbG9hZGluZyhsb2FkaW5nOiBib29sZWFuKSB7XG4gICAgdGhpcy5fbG9hZGluZyA9IGxvYWRpbmc7XG4gICAgdGhpcy5ub3RpZnlMb2FkaW5nLm5leHQodGhpcy5fbG9hZGluZyk7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiBBIHNuYXBzaG90IG9mIHRoZSBsb2FkaW5nIHN0YXRlLlxuICAgKi9cbiAgZ2V0IGxvYWRpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2xvYWRpbmc7XG4gIH1cblxuICAvKipcbiAgICogT2JzZXJ2ZSBsb2FkaW5nLlxuICAgKiBAZXhhbXBsZVxuICAgICA8cHJlPlxuICAgIGxldCBsb2FkaW5nJCA9IHNvdXJjZS5vYnNlcnZlTG9hZGluZygpO1xuICAgIDwvcHJlPlxuXG4gICAgTm90ZSB0aGF0IHRoaXMgb2J2ZXJhYmxlIHBpcGVkIHRocm91Z2hcbiAgICBgdGFrZVdoaWxlKHYtPnYsIHRydWUpLCBzdWNoIHRoYXQgaXQgd2lsbCBcbiAgICBjb21wbGV0ZSBhZnRlciBlYWNoIGVtaXNzaW9uLlxuXG4gICAgU2VlOlxuICAgIGh0dHBzOi8vbWVkaXVtLmNvbS9Ab2xlLmVyc295L3dhaXRpbmctb24tZXN0b3JlLXRvLWxvYWQtOGRjYmUxNjE2MTNjXG5cbiAgICBGb3IgbW9yZSBkZXRhaWxzLlxuICAqL1xuICBwdWJsaWMgb2JzZXJ2ZUxvYWRpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5TG9hZGluZy5hc09ic2VydmFibGUoKS5cbiAgICAgIHBpcGUodGFrZVdoaWxlKHYgPT4gdiwgdHJ1ZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vdGZpaWVzIHdoZW4gbG9hZGluZyBoYXMgY29tcGxldGVkLlxuICAgKi9cbiAgcHVibGljIG9ic2VydmVMb2FkaW5nQ29tcGxldGUoKSB7XG4gICAgcmV0dXJuIHRoaXMub2JzZXJ2ZUxvYWRpbmcoKS5waXBlKFxuICAgICAgZmlsdGVyKGxvYWRpbmcgPT4gbG9hZGluZyA9PSBmYWxzZSksXG4gICAgICBzd2l0Y2hNYXAoKCkgPT4gb2YodHJ1ZSkpKVxuICB9XG5cblxuXG5cblxuXG4gIC8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFNFQVJDSElOR1xuICAvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvKipcbiAgICogT2JzZXJ2YWJsZSBvZiBlcnJvcnMgb2NjdXJyZWQgZHVyaW5nIGEgc2VhcmNoIHJlcXVlc3QuXG4gICAqIFxuICAgKiBUaGUgZXJyb3IgT2JzZXJ2YWJsZSBzaG91bGQgYmUgY3JlYXRlZCBieSB0aGUgXG4gICAqIGNsaWVudC5cbiAgICovXG4gIHB1YmxpYyBzZWFyY2hFcnJvciE6IE9ic2VydmFibGU8YW55PjtcblxuICAvKipcbiAgICogTm90aWZpZXMgb2JzZXJ2ZXJzIHRoYXQgYSBzZWFyY2ggaXMgaW4gcHJvZ3Jlc3MuXG4gICAqIFxuICAgKiBUaGlzIGlzIGEgY29tbW9uIHBhdHRlcm4gZm91bmQgd2hlbiBpbXBsZW1lbnRpbmdcbiAgICogYE9ic2VydmFibGVgIGRhdGEgc291cmNlcy5cbiAgICovXG4gIHByaXZhdGUgbm90aWZ5U2VhcmNoaW5nID0gbmV3IFJlcGxheVN1YmplY3Q8Ym9vbGVhbj4oMSk7XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGBzZWFyY2hpbmdgIHN0YXRlLiAgVXNlIGBzZWFyY2hpbmdgXG4gICAqIGZvciBleGFtcGxlIHRvIGRpc3BsYXkgYSBzcGlubm5lciBcbiAgICogd2hlbiBwZXJmb3JtaW5nIGEgc2VhcmNoLiAgXG4gICAqIFRoZSBkZWZhdWx0IGBzZWFyY2hpbmdgIHN0YXRlIGlzIGBmYWxzZWAuXG4gICAqL1xuICBwcml2YXRlIF9zZWFyY2hpbmc6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvKipcbiAgICogU2V0cyB0aGUgY3VycmVudCBzZWFyY2hpbmcgc3RhdGUgYW5kIG5vdGlmaWVzIG9ic2VydmVycy5cbiAgICovXG4gIHNldCBzZWFyY2hpbmcoc2VhcmNoaW5nOiBib29sZWFuKSB7XG4gICAgdGhpcy5fc2VhcmNoaW5nID0gc2VhcmNoaW5nO1xuICAgIHRoaXMubm90aWZ5U2VhcmNoaW5nLm5leHQodGhpcy5fc2VhcmNoaW5nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIEEgc25hcHNob3Qgb2YgdGhlIHNlYXJjaGluZyBzdGF0ZS5cbiAgICovXG4gIGdldCBzZWFyY2hpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3NlYXJjaGluZztcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnNlcnZlIHNlYXJjaGluZy5cbiAgICogQGV4YW1wbGVcbiAgICAgPHByZT5cbiAgICBsZXQgc2VhcmNoaW5nJCA9IHNvdXJjZS5vYnNlcnZlU2VhcmNoaW5nKCk7XG4gICAgPC9wcmU+XG4gIFxuICAgIE5vdGUgdGhhdCB0aGlzIG9idmVyYWJsZSBwaXBlZCB0aHJvdWdoXG4gICAgYHRha2VXaGlsZSh2LT52LCB0cnVlKSwgc3VjaCB0aGF0IGl0IHdpbGwgXG4gICAgY29tcGxldGUgYWZ0ZXIgZWFjaCBlbWlzc2lvbi5cbiAgXG4gICAgU2VlOlxuICAgIGh0dHBzOi8vbWVkaXVtLmNvbS9Ab2xlLmVyc295L3dhaXRpbmctb24tZXN0b3JlLXRvLWxvYWQtOGRjYmUxNjE2MTNjXG4gIFxuICAgIEZvciBtb3JlIGRldGFpbHMuXG4gICovXG4gIHB1YmxpYyBvYnNlcnZlU2VhcmNoaW5nKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLm5vdGlmeVNlYXJjaGluZy5hc09ic2VydmFibGUoKS5cbiAgICAgIHBpcGUodGFrZVdoaWxlKHYgPT4gdiwgdHJ1ZSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vdGZpaWVzIHdoZW4gc2VhcmNoaW5nIGhhcyBjb21wbGV0ZWQuXG4gICAqL1xuICBwdWJsaWMgb2JzZXJ2ZVNlYXJjaGluZ0NvbXBsZXRlKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLm9ic2VydmVTZWFyY2hpbmcoKS5waXBlKFxuICAgICAgZmlsdGVyKHNlYXJjaGluZyA9PiBzZWFyY2hpbmcgPT0gZmFsc2UpLFxuICAgICAgc3dpdGNoTWFwKCgpID0+IG9mKHRydWUpKSlcbiAgfVxuXG5cblxuXG5cblxuXG4gIC8qKlxuICAgKiBTdG9yZSBzbGljZXNcbiAgICovXG4gIHByaXZhdGUgc2xpY2VzOiBNYXA8c3RyaW5nLCBTbGljZTxFPj4gPSBuZXcgTWFwKCk7XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBzbGljZSB0byB0aGUgc3RvcmUgYW5kIGtleXMgaXQgYnkgdGhlIHNsaWNlcyBsYWJlbC5cbiAgICpcbiAgICogQHBhcmFtIHBcbiAgICogQHBhcmFtIGxhYmVsXG4gICAqIFxuICAgKiBAZXhhbXBsZSBTZXR1cCBhIFRvZG8gU2xpY2UgZm9yIENPTVBMRVRFIFRvZG9zXG5gYGBcbnNvdXJjZS5hZGRTbGljZSh0b2RvID0+IHRvZG8uY29tcGxldGUsIFRvZG9TbGljZXMuQ09NUExFVEUpO1xuYGBgXG4gICAqL1xuICBhZGRTbGljZShwOiBQcmVkaWNhdGU8RT4sIGxhYmVsOiBzdHJpbmcpIHtcbiAgICBjb25zdCBzbGljZTogU2xpY2U8RT4gPSBuZXcgU2xpY2UoXG4gICAgICBsYWJlbCxcbiAgICAgIHAsXG4gICAgICB0aGlzKVxuICAgIHRoaXMuc2xpY2VzLnNldChzbGljZS5sYWJlbCwgc2xpY2UpXG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGEgc2xpY2VcbiAgICogQHBhcmFtIGxhYmVsIFRoZSBsYWJlbCBpZGVudGlmeWluZyB0aGUgc2xpY2VcbiAgICogXG4gICAqIEBleGFtcGxlIFJlbW92ZSB0aGUgVG9kb1NsaWNlcy5DT01QTEVURSBTbGljZVxuYGBgXG5zb3VyY2UucmVtb3ZlU2xpY2UoVG9kb1NsaWNlcy5DT01QTEVURSk7XG5gYGBcbiAgICovXG4gIHJlbW92ZVNsaWNlKGxhYmVsOiBzdHJpbmcpIHtcbiAgICB0aGlzLnNsaWNlcy5kZWxldGUobGFiZWwpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIHNsaWNlXG4gICAqIEBwYXJhbSBsYWJlbCBUaGUgbGFiZWwgaWRlbnRpZnlpbmcgdGhlIHNsaWNlXG4gICAqIEByZXR1cm4gVGhlIFNsaWNlIGluc3RhbmNlIG9yIHVuZGVmaW5lZCBcbiAgICogXG4gICAqIEBleGFtcGxlIEdldCB0aGUgVG9kb1NsaWNlcy5DT01QTEVURSBzbGljZVxuYGBgXG5zb3VyY2UuZ2V0U2xpY2UoVG9kb1NsaWNlcy5DT01QTEVURSk7XG5gYGBcbiAgICovXG4gIGdldFNsaWNlKGxhYmVsOiBzdHJpbmcpOiBTbGljZTxFPiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc2xpY2VzLmdldChsYWJlbCk7XG4gIH1cblxuICAvKipcbiAgICogUG9zdCAoQWRkIGEgbmV3KSBlbGVtZW50KHMpIHRvIHRoZSBzdG9yZS5cbiAgICogQHBhcmFtIGUgQW4gaW5kaWlkdWFsIGVudGl0eSBvciBhbiBhcnJheSBvZiBlbnRpdGllc1xuICAgKiBAZXhhbXBsZSBQb3N0IGEgYHRvZG9gLlxuYGBgXG5zdG9yZS5wb3N0KHRvZG8pO1xuYGBgXG4gICAqL1xuICBwb3N0KGU6IEUgfCBFW10pIHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoZSkpIHtcbiAgICAgIGNvbnN0IGd1aWQ6IHN0cmluZyA9ICg8YW55PmUpW3RoaXMuR1VJRF9LRVldXG4gICAgICAgID8gKDxhbnk+ZSlbdGhpcy5HVUlEX0tFWV1cbiAgICAgICAgOiBHVUlEKCk7XG4gICAgICAoPGFueT5lKVt0aGlzLkdVSURfS0VZXSA9IGd1aWQ7XG4gICAgICB0aGlzLmVudHJpZXMuc2V0KGd1aWQsIGUpO1xuICAgICAgdGhpcy51cGRhdGVJREVudHJ5KGUpO1xuICAgICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgICAgcy5wb3N0KGUpO1xuICAgICAgfSk7XG4gICAgICAvL0NyZWF0ZSBhIG5ldyBhcnJheSByZWZlcmVuY2UgdG8gdHJpZ2dlciBBbmd1bGFyIGNoYW5nZSBkZXRlY3Rpb24uXG4gICAgICBsZXQgdjogRVtdID0gWy4uLkFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKV07XG4gICAgICBjb25zdCBkZWx0YTogRGVsdGE8RT4gPSB7IHR5cGU6IEFjdGlvblR5cGVzLlBPU1QsIGVudHJpZXM6IFtlXSB9O1xuICAgICAgdGhpcy5ub3RpZnlBbGwodiwgZGVsdGEpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHRoaXMucG9zdEEoZSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUG9zdCBlbGVtZW50cyB0byB0aGUgc3RvcmUuXG4gICAqIEBwYXJhbSAuLi5lXG4gICAqIEBleGFtcGxlIFBvc3QgdHdvIGBUb2RvYCBpbnN0YW5jZXMuXG5gYGBcbnN0b3JlLnBvc3QodG9kbzEsIHRvZG8yKTtcbmBgYFxuICAgKi9cbiAgcG9zdE4oLi4uZTogRVtdKSB7XG4gICAgZS5mb3JFYWNoKGUgPT4ge1xuICAgICAgY29uc3QgZ3VpZDogc3RyaW5nID0gKDxhbnk+ZSlbdGhpcy5HVUlEX0tFWV1cbiAgICAgICAgPyAoPGFueT5lKVt0aGlzLkdVSURfS0VZXVxuICAgICAgICA6IEdVSUQoKTtcbiAgICAgICg8YW55PmUpW3RoaXMuR1VJRF9LRVldID0gZ3VpZDtcbiAgICAgIHRoaXMuZW50cmllcy5zZXQoZ3VpZCwgZSk7XG4gICAgICB0aGlzLnVwZGF0ZUlERW50cnkoZSk7XG4gICAgfSk7XG4gICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgIHMucG9zdEEoZSk7XG4gICAgfSk7XG4gICAgLy9DcmVhdGUgYSBuZXcgYXJyYXkgcmVmZXJlbmNlIHRvIHRyaWdnZXIgQW5ndWxhciBjaGFuZ2UgZGV0ZWN0aW9uLlxuICAgIGxldCB2OiBFW10gPSBbLi4uQXJyYXkuZnJvbSh0aGlzLmVudHJpZXMudmFsdWVzKCkpXTtcbiAgICBjb25zdCBkZWx0YTogRGVsdGE8RT4gPSB7IHR5cGU6IEFjdGlvblR5cGVzLlBPU1QsIGVudHJpZXM6IGUgfTtcbiAgICB0aGlzLm5vdGlmeUFsbCh2LCBkZWx0YSk7XG4gIH1cblxuICAvKipcbiAgICogUG9zdCAoQWRkKSBhbiBhcnJheSBvZiBlbGVtZW50cyB0byB0aGUgc3RvcmUuXG4gICAqIEBwYXJhbSBlXG4gICAqIEBleGFtcGxlIFBvc3QgYSBgVG9kb2AgYXJyYXkuXG5gYGBcbnN0b3JlLnBvc3QoW3RvZG8xLCB0b2RvMl0pO1xuYGBgXG4gICAqL1xuICBwb3N0QShlOiBFW10pIHtcbiAgICB0aGlzLnBvc3ROKC4uLmUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFB1dCAoVXBkYXRlKSBhbiBlbGVtZW50LlxuICAgKiBAcGFyYW0gZVxuICAgKiBAZXhhbXBsZSBQdXQgYSBUb2RvIGluc3RhbmNlLlxuYGBgXG5zdG9yZS5wdXQodG9kbzEpO1xuYGBgXG4gICAqL1xuICBwdXQoZTogRSB8IEVbXSkge1xuICAgIGlmICghQXJyYXkuaXNBcnJheShlKSkge1xuICAgICAgbGV0IGlkOiBzdHJpbmcgPSAoPGFueT5lKVt0aGlzLkdVSURfS0VZXTtcbiAgICAgIHRoaXMuZW50cmllcy5zZXQoaWQsIGUpO1xuICAgICAgdGhpcy51cGRhdGVJREVudHJ5KGUpO1xuICAgICAgbGV0IHY6IEVbXSA9IFsuLi5BcnJheS5mcm9tKHRoaXMuZW50cmllcy52YWx1ZXMoKSldO1xuICAgICAgdGhpcy5ub3RpZnkubmV4dCh2KTtcbiAgICAgIGNvbnN0IGRlbHRhOiBEZWx0YTxFPiA9IHsgdHlwZTogQWN0aW9uVHlwZXMuUFVULCBlbnRyaWVzOiBbZV0gfTtcbiAgICAgIHRoaXMubm90aWZ5RGVsdGEubmV4dChkZWx0YSk7XG4gICAgICBBcnJheS5mcm9tKHRoaXMuc2xpY2VzLnZhbHVlcygpKS5mb3JFYWNoKHMgPT4ge1xuICAgICAgICBzLnB1dChlKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHRoaXMucHV0QShlKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQdXQgKFVwZGF0ZSkgYW4gZWxlbWVudCBvciBhZGQgYW4gZWxlbWVudCB0aGF0IHdhcyByZWFkIGZyb20gYSBwZXJzaXN0ZW5jZSBzb3VyY2VcbiAgICogYW5kIHRodXMgYWxyZWFkeSBoYXMgYW4gYXNzaWduZWQgZ2xvYmFsIGlkYC5cbiAgICogQHBhcmFtIGVcbiAgICogQGV4YW1wbGUgUHV0IFRvZG8gaW5zdGFuY2VzLlxuYGBgXG5zdG9yZS5wdXQodG9kbzEsIHRvZG8yKTtcbmBgYFxuICAgKi9cbiAgcHV0TiguLi5lOiBFW10pIHtcbiAgICB0aGlzLnB1dEEoZSk7XG4gIH1cblxuICAvKipcbiAgICogUHV0IChVcGRhdGUpIHRoZSBhcnJheSBvZiBlbGVtZW50cy5cbiAgICogQHBhcmFtIGVcbiAgICogQGV4YW1wbGUgUHV0IFRvZG8gaW5zdGFuY2VzLlxuYGBgXG5zdG9yZS5wdXQoW3RvZG8xLCB0b2RvMl0pO1xuYGBgXG4gICAqL1xuICBwdXRBKGU6IEVbXSkge1xuICAgIGUuZm9yRWFjaChlID0+IHtcbiAgICAgIGxldCBndWlkOiBzdHJpbmcgPSAoPGFueT5lKVt0aGlzLkdVSURfS0VZXVxuICAgICAgdGhpcy5lbnRyaWVzLnNldChndWlkLCBlKVxuICAgICAgdGhpcy51cGRhdGVJREVudHJ5KGUpO1xuICAgIH0pO1xuICAgIC8vQ3JlYXRlIGEgbmV3IGFycmF5IHJlZmVyZW5jZSB0byB0cmlnZ2VyIEFuZ3VsYXIgY2hhbmdlIGRldGVjdGlvbi5cbiAgICBsZXQgdjogRVtdID0gWy4uLkFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKV07XG4gICAgdGhpcy5ub3RpZnkubmV4dCh2KTtcbiAgICBjb25zdCBkZWx0YTogRGVsdGE8RT4gPSB7IHR5cGU6IEFjdGlvblR5cGVzLlBVVCwgZW50cmllczogZSB9O1xuICAgIHRoaXMubm90aWZ5RGVsdGEubmV4dChkZWx0YSk7XG4gICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgIHMucHV0QShlKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgKFVwZGF0ZSkgdGhlIGFycmF5IG9mIGVsZW1lbnRzLlxuICAgKiBAcGFyYW0gZVxuICAgKiBAZXhhbXBsZSBEZWxldGUgdG9kbzEuXG5gYGBcbnN0b3JlLmRlbGV0ZSh0b2RvMV0pO1xuYGBgXG4gICAqL1xuICBkZWxldGUoZTogRSB8IEVbXSkge1xuICAgIGlmICghQXJyYXkuaXNBcnJheShlKSkge1xuICAgICAgdGhpcy5kZWxldGVBY3RpdmUoZSk7XG4gICAgICBjb25zdCBndWlkID0gKDxhbnk+ZSlbdGhpcy5HVUlEX0tFWV07XG4gICAgICB0aGlzLmVudHJpZXMuZGVsZXRlKGd1aWQpO1xuICAgICAgdGhpcy5kZWxldGVJREVudHJ5KGUpO1xuICAgICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgICAgcy5lbnRyaWVzLmRlbGV0ZShndWlkKTtcbiAgICAgIH0pO1xuICAgICAgLy9DcmVhdGUgYSBuZXcgYXJyYXkgcmVmZXJlbmNlIHRvIHRyaWdnZXIgQW5ndWxhciBjaGFuZ2UgZGV0ZWN0aW9uLlxuICAgICAgbGV0IHY6IEVbXSA9IFsuLi5BcnJheS5mcm9tKHRoaXMuZW50cmllcy52YWx1ZXMoKSldO1xuICAgICAgY29uc3QgZGVsdGE6IERlbHRhPEU+ID0geyB0eXBlOiBBY3Rpb25UeXBlcy5ERUxFVEUsIGVudHJpZXM6IFtlXSB9O1xuICAgICAgdGhpcy5ub3RpZnlBbGwodiwgZGVsdGEpO1xuICAgICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgICAgcy5kZWxldGUoZSk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICB0aGlzLmRlbGV0ZUEoZSlcbiAgICB9XG5cbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgTiBlbGVtZW50cy5cbiAgICogQHBhcmFtIC4uLmVcbiAgICogQGV4YW1wbGUgUHV0IFRvZG8gaW5zdGFuY2VzLlxuYGBgXG5zdG9yZS5kZWxldGUodG9kbzEsIHRvZG8yKTtcbmBgYFxuICAgKi9cbiAgZGVsZXRlTiguLi5lOiBFW10pIHtcbiAgICB0aGlzLmRlbGV0ZUEoZSk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlIE4gZWxlbWVudHMuXG4gICAqIEBwYXJhbSAuLi5lXG4gICAqIEBleGFtcGxlIFB1dCBUb2RvIGluc3RhbmNlcy5cbmBgYFxuc3RvcmUuZGVsZXRlKHRvZG8xLCB0b2RvMik7XG5gYGBcbiAgICovXG4gIGRlbGV0ZUEoZTogRVtdKSB7XG4gICAgZS5mb3JFYWNoKGUgPT4ge1xuICAgICAgdGhpcy5kZWxldGVBY3RpdmUoZSk7XG4gICAgICBjb25zdCBndWlkID0gKDxhbnk+ZSlbdGhpcy5HVUlEX0tFWV07XG4gICAgICB0aGlzLmVudHJpZXMuZGVsZXRlKGd1aWQpO1xuICAgICAgdGhpcy5kZWxldGVJREVudHJ5KGUpO1xuICAgICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgICAgcy5lbnRyaWVzLmRlbGV0ZShndWlkKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIC8vQ3JlYXRlIGEgbmV3IGFycmF5IHJlZmVyZW5jZSB0byB0cmlnZ2VyIEFuZ3VsYXIgY2hhbmdlIGRldGVjdGlvbi5cbiAgICBsZXQgdjogRVtdID0gWy4uLkFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKV07XG4gICAgY29uc3QgZGVsdGE6IERlbHRhPEU+ID0geyB0eXBlOiBBY3Rpb25UeXBlcy5ERUxFVEUsIGVudHJpZXM6IGUgfTtcbiAgICB0aGlzLm5vdGlmeUFsbCh2LCBkZWx0YSk7XG4gICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgIHMuZGVsZXRlQShlKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgZWxlbWVudHMgYnkge0BsaW5rIFByZWRpY2F0ZX0uXG4gICAqIEBwYXJhbSBwIFRoZSBwcmVkaWNhdGUuXG4gICAqIEBleGFtcGxlIFB1dCBUb2RvIGluc3RhbmNlcy5cbmBgYFxuc3RvcmUuZGVsZXRlKHRvZG8xLCB0b2RvMik7XG5gYGBcbiAgICovXG4gIGRlbGV0ZVAocDogUHJlZGljYXRlPEU+KSB7XG4gICAgY29uc3QgZDogRVtdID0gW107XG4gICAgQXJyYXkuZnJvbSh0aGlzLmVudHJpZXMudmFsdWVzKCkpLmZvckVhY2goZSA9PiB7XG4gICAgICBpZiAocChlKSkge1xuICAgICAgICBkLnB1c2goZSk7XG4gICAgICAgIGNvbnN0IGlkID0gKDxhbnk+ZSlbdGhpcy5HVUlEX0tFWV07XG4gICAgICAgIHRoaXMuZW50cmllcy5kZWxldGUoaWQpO1xuICAgICAgICB0aGlzLmRlbGV0ZUFjdGl2ZShlKTtcbiAgICAgICAgdGhpcy5kZWxldGVJREVudHJ5KGUpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIC8vQ3JlYXRlIGEgbmV3IGFycmF5IHJlZmVyZW5jZSB0byB0cmlnZ2VyIEFuZ3VsYXIgY2hhbmdlIGRldGVjdGlvbi5cbiAgICBsZXQgdjogRVtdID0gWy4uLkFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKV07XG4gICAgY29uc3QgZGVsdGE6IERlbHRhPEU+ID0geyB0eXBlOiBBY3Rpb25UeXBlcy5ERUxFVEUsIGVudHJpZXM6IGQgfTtcbiAgICB0aGlzLm5vdGlmeUFsbCh2LCBkZWx0YSk7XG4gICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgIHMuZGVsZXRlQShkKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJZiB0aGUgZW50aXR5IGhhcyB0aGUgYGlkYCBrZXkgaW5pdGlhbGl6ZWQgd2l0aCBhIHZhbHVlLFxuICAgKiB0aGVuIGFsc28gYWRkIHRoZSBlbnRpdHkgdG8gdGhlIGBpZEVudHJpZXNgLlxuICAgKlxuICAgKiBAcGFyYW0gZSBUaGUgZWxlbWVudCB0byBiZSBhZGRlZCB0byB0aGUgYGlkRW50cmllc2AuXG4gICAqL1xuICBwcml2YXRlIHVwZGF0ZUlERW50cnkoZTogRSkge1xuICAgIGlmICgoPGFueT5lKVt0aGlzLklEX0tFWV0pIHtcbiAgICAgIHRoaXMuaWRFbnRyaWVzLnNldCgoPGFueT5lKVt0aGlzLklEX0tFWV0sIGUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJZiB0aGUgZW50aXR5IGhhcyB0aGUgYGlkYCBrZXkgaW5pdGlhbGl6ZWQgd2l0aCBhIHZhbHVlLFxuICAgKiB0aGVuIGFsc28gZGVsZXRlIHRoZSBlbnRpdHkgdG8gdGhlIGBpZEVudHJpZXNgLlxuICAgKlxuICAgKiBAcGFyYW0gZSBUaGUgZWxlbWVudCB0byBiZSBhZGRlZCB0byB0aGUgYGlkRW50cmllc2AuXG4gICAqL1xuICBwcml2YXRlIGRlbGV0ZUlERW50cnkoZTogRSkge1xuICAgIGlmICgoPGFueT5lKVt0aGlzLklEX0tFWV0pIHtcbiAgICAgIHRoaXMuaWRFbnRyaWVzLmRlbGV0ZSgoPGFueT5lKVt0aGlzLklEX0tFWV0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldHMgdGhlIHN0b3JlIGFuZCBhbGwgY29udGFpbmVkIHNsaWNlIGluc3RhbmNlcyB0byBlbXB0eS5cbiAgICogQWxzbyBwZXJmb3JtIGRlbHRhIG5vdGlmaWNhdGlvbiB0aGF0IHNlbmRzIGFsbCBjdXJyZW50IHN0b3JlIGVudHJpZXMuXG4gICAqIFRoZSBBY3Rpb25UeXBlLlJFU0VUIGNvZGUgaXMgc2VudCB3aXRoIHRoZSBkZWx0YSBub3RpZmljYXRpb24uICBTbGljZXNcbiAgICogc2VuZCB0aGVpciBvd24gZGVsdGEgbm90aWZpY2F0aW9uLlxuICAgKiBcbiAgICogQGV4YW1wbGUgUmVzZXQgdGhlIHN0b3JlLlxuYGBgXG5zdG9yZS5yZXNldCgpO1xuYGBgXG4gICAqL1xuICByZXNldCgpIHtcbiAgICBjb25zdCBkZWx0YTogRGVsdGE8RT4gPSB7XG4gICAgICB0eXBlOiBBY3Rpb25UeXBlcy5SRVNFVCxcbiAgICAgIGVudHJpZXM6IEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKVxuICAgIH07XG4gICAgdGhpcy5ub3RpZnlBbGwoW10sIGRlbHRhKTtcbiAgICB0aGlzLmVudHJpZXMgPSBuZXcgTWFwKCk7XG4gICAgQXJyYXkuZnJvbSh0aGlzLnNsaWNlcy52YWx1ZXMoKSkuZm9yRWFjaChzID0+IHtcbiAgICAgIHMucmVzZXQoKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsIGFsbCB0aGUgbm90aWZpZXJzIGF0IG9uY2UuXG4gICAqXG4gICAqIEBwYXJhbSB2XG4gICAqIEBwYXJhbSBkZWx0YVxuICAgKi9cbiAgcHJvdGVjdGVkIG5vdGlmeUFsbCh2OiBFW10sIGRlbHRhOiBEZWx0YTxFPikge1xuICAgIHN1cGVyLm5vdGlmeUFsbCh2LCBkZWx0YSk7XG4gICAgdGhpcy5ub3RpZnlMb2FkaW5nLm5leHQodGhpcy5sb2FkaW5nKTtcbiAgfVxufSJdfQ==