@idea-ionic/uncommon 8.5.12 → 8.6.0-beta.1

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 (57) hide show
  1. package/fesm2022/idea-ionic-uncommon.mjs +85 -85
  2. package/fesm2022/idea-ionic-uncommon.mjs.map +1 -1
  3. package/index.d.ts +1405 -3
  4. package/package.json +12 -13
  5. package/esm2022/idea-ionic-uncommon.mjs +0 -5
  6. package/esm2022/public-api.mjs +0 -26
  7. package/esm2022/src/AWSAPI.service.mjs +0 -431
  8. package/esm2022/src/AWSAPISocket.service.mjs +0 -188
  9. package/esm2022/src/address/address.component.mjs +0 -409
  10. package/esm2022/src/announcement/announcement.component.mjs +0 -72
  11. package/esm2022/src/cachedResources.service.mjs +0 -55
  12. package/esm2022/src/colors/colorPicker.component.mjs +0 -191
  13. package/esm2022/src/contacts/contacts.component.mjs +0 -188
  14. package/esm2022/src/dateTime/calendarPicker.component.mjs +0 -213
  15. package/esm2022/src/dateTime/dateTime.component.mjs +0 -217
  16. package/esm2022/src/duration/duration.component.mjs +0 -195
  17. package/esm2022/src/echo/echo.page.mjs +0 -233
  18. package/esm2022/src/echo/echo.routes.mjs +0 -6
  19. package/esm2022/src/errorReporting.service.mjs +0 -69
  20. package/esm2022/src/mde/mde.component.mjs +0 -143
  21. package/esm2022/src/mde/mdeToolbar.component.mjs +0 -25
  22. package/esm2022/src/offline/cacheableResource.component.mjs +0 -56
  23. package/esm2022/src/offline/offline.service.mjs +0 -63
  24. package/esm2022/src/offline/offlineData.service.mjs +0 -480
  25. package/esm2022/src/offline/offlineIndicator.component.mjs +0 -105
  26. package/esm2022/src/offline/offlineManager.component.mjs +0 -101
  27. package/esm2022/src/pushNotifications.service.mjs +0 -57
  28. package/esm2022/src/sentiment/sentiment.component.mjs +0 -112
  29. package/esm2022/src/timeInterval/fromTimeToTime.component.mjs +0 -171
  30. package/esm2022/src/timeInterval/timeInterval.component.mjs +0 -206
  31. package/esm2022/src/tinCan.service.mjs +0 -49
  32. package/public-api.d.ts +0 -25
  33. package/src/AWSAPI.service.d.ts +0 -178
  34. package/src/AWSAPISocket.service.d.ts +0 -129
  35. package/src/address/address.component.d.ts +0 -64
  36. package/src/announcement/announcement.component.d.ts +0 -23
  37. package/src/cachedResources.service.d.ts +0 -34
  38. package/src/colors/colorPicker.component.d.ts +0 -78
  39. package/src/contacts/contacts.component.d.ts +0 -31
  40. package/src/dateTime/calendarPicker.component.d.ts +0 -45
  41. package/src/dateTime/dateTime.component.d.ts +0 -81
  42. package/src/duration/duration.component.d.ts +0 -68
  43. package/src/echo/echo.page.d.ts +0 -34
  44. package/src/echo/echo.routes.d.ts +0 -2
  45. package/src/errorReporting.service.d.ts +0 -26
  46. package/src/mde/mde.component.d.ts +0 -39
  47. package/src/mde/mdeToolbar.component.d.ts +0 -5
  48. package/src/offline/cacheableResource.component.d.ts +0 -11
  49. package/src/offline/offline.service.d.ts +0 -39
  50. package/src/offline/offlineData.service.d.ts +0 -281
  51. package/src/offline/offlineIndicator.component.d.ts +0 -25
  52. package/src/offline/offlineManager.component.d.ts +0 -17
  53. package/src/pushNotifications.service.d.ts +0 -26
  54. package/src/sentiment/sentiment.component.d.ts +0 -35
  55. package/src/timeInterval/fromTimeToTime.component.d.ts +0 -61
  56. package/src/timeInterval/timeInterval.component.d.ts +0 -84
  57. package/src/tinCan.service.d.ts +0 -31
@@ -1,480 +0,0 @@
1
- import { Injectable, inject } from '@angular/core';
2
- import { IDEAStorageService, IDEATranslationsService } from '@idea-ionic/common';
3
- import { IDEAAWSAPIService } from '../AWSAPI.service';
4
- import { IDEAOfflineService } from './offline.service';
5
- import * as i0 from "@angular/core";
6
- /**
7
- * After how much time we need to request a synchronisation to keep the contents up-to-date.
8
- */
9
- export const SYNC_EXPIRATION_INTERVAL = 1000 * 60 * 60 * 24; // a day
10
- /**
11
- * Prefix for the key of the API requests queue info in the local storage.
12
- */
13
- export const QUEUE_API_REQUESTS_KEY = 'IDEAOfflineService.queueAPIrequests';
14
- /**
15
- * Prefix for the key of the last sync time info in the local storage.
16
- */
17
- export const LAST_SYNC_KEY = 'IDEAOfflineService.lastSyncAt';
18
- /**
19
- * The max number of elements per resource to synchronize during the first analysis of a synchronisation.
20
- * If the number of elements exceeds (there is more data after the 1st page), the operation require manual confirmation.
21
- */
22
- export const NUM_ELEMENTS_WITHOUT_MANUAL_SYNC = 100;
23
- /**
24
- * The max number of elements per resource to request at the same time during a normal synchronisation.
25
- */
26
- export const NUM_ELEMENTS_WITH_MANUAL_SYNC = 300;
27
- /**
28
- * Manage the offline functioning of the app's data (upload/download/synchronization).
29
- * Note: it includes all the methods of IDEAOfflineService.
30
- *
31
- * Download: it works through the **Delta** mechanism on back-end resources.
32
- * Practically, the service prepares each possible API GET requests for each of the involved resources.
33
- * In this way, if offline, the API service can hit an element by URL in the cache (storage offline).
34
- *
35
- * **How to use it**. Configure the sync mechanism in the main app.component as it follows:
36
- *
37
- * 1. Implement a CacheableResource class for each DeltaResource you want to cache offline.
38
- * 2. Set up the service (`setUpOfflineData`).
39
- * 3. Run a synchronization.
40
- * 4. Add the navigation to the Offline Manager (UI).
41
- * 5. Optionally, push offline API requests to the queue when offline.
42
- *
43
- * e.g. of CacheableResource classes:
44
- * ```
45
- * class CustomerCR extends CacheableResource {
46
- * constructor(description: string) {
47
- * super(DeltaResources.CUSTOMERS, description);
48
- * }
49
- * public listURL(element: any): string {
50
- * return `teams/${element.teamId}/customers`;
51
- * }
52
- * public elementURL(element: any): string {
53
- * return `teams/${element.teamId}/customers/${element.customerId}`;
54
- * }
55
- * public findIndexInList(list: Array<any>, element: any): number {
56
- * return list.findIndex(x => x.customerId === element.customerId);
57
- * }
58
- * public sort(a: any, b: any): number {
59
- * return a.name.localeCompare(b.name);
60
- * }
61
- * }
62
- */
63
- export class IDEAOfflineDataService {
64
- constructor() {
65
- this._storage = inject(IDEAStorageService);
66
- this._translate = inject(IDEATranslationsService);
67
- this._offline = inject(IDEAOfflineService);
68
- this._API = inject(IDEAAWSAPIService);
69
- this.queueAPIRequests = new Array();
70
- this.resources = new Array();
71
- this.cacheableResources = {};
72
- // subscribe to network changes
73
- this._offline.subscribe(isOnline => {
74
- if (isOnline) {
75
- // try a synchronization if needed or if the last one failed
76
- if (this.errorInLastSync)
77
- this.synchronize();
78
- else
79
- this.synchronizeIfNeeded();
80
- }
81
- });
82
- }
83
- //
84
- // NETWORK STATUS from IDEAOfflineService
85
- //
86
- /**
87
- * Quickly check the connection status.
88
- */
89
- isOnline() {
90
- return this._offline.isOnline();
91
- }
92
- /**
93
- * Quickly check the connection status.
94
- */
95
- isOffline() {
96
- return this._offline.isOffline();
97
- }
98
- /**
99
- * Subscribe to the service to be notified when the connection status changes.
100
- */
101
- subscribe(callback) {
102
- return this._offline.subscribe(callback);
103
- }
104
- /**
105
- * Quickly check for online connection.
106
- */
107
- check() {
108
- return this._offline.check();
109
- }
110
- //
111
- // CONFIGURATION
112
- //
113
- /**
114
- * Whether the offline mode is allowed. You can customize this function, if needed.
115
- */
116
- isAllowed() {
117
- return !!this.resources.length;
118
- }
119
- /**
120
- * Set up the service to use and sync offline data.
121
- */
122
- setUpOfflineData(teamId, useQueueAPIRequests, cacheableResources) {
123
- // set the team
124
- this.teamId = teamId;
125
- // decide if to allow certain API request while offline
126
- this.useQueueAPIRequests = useQueueAPIRequests;
127
- // load the API request pending queue, if any
128
- this.queueAPIRequestKey = this.teamId ? `${QUEUE_API_REQUESTS_KEY}_${this.teamId}` : QUEUE_API_REQUESTS_KEY;
129
- this.loadQueueAPIRequest();
130
- // load the lastSyncAt information for the team
131
- this.lastSyncKey = this.teamId ? `${LAST_SYNC_KEY}_${this.teamId}` : LAST_SYNC_KEY;
132
- this.loadLastSyncAt();
133
- // load the cacheable resources
134
- this.resources = new Array();
135
- this.cacheableResources = {};
136
- cacheableResources.forEach(r => this.addCacheableResource(r));
137
- }
138
- /**
139
- * Load from the local storage the last sync at information.
140
- */
141
- loadLastSyncAt() {
142
- return new Promise(resolve => {
143
- this._storage.get(this.lastSyncKey).then((lastSyncAt) => {
144
- this.lastSyncAt = lastSyncAt ? Number(lastSyncAt) : null;
145
- resolve(this.lastSyncAt);
146
- });
147
- });
148
- }
149
- /**
150
- * Update last sync at info in the local storage.
151
- */
152
- saveLastSyncAt(lastSyncAt) {
153
- this.lastSyncAt = lastSyncAt;
154
- return this._storage.set(this.lastSyncKey, lastSyncAt);
155
- }
156
- /**
157
- * Add a CacheableResource.
158
- */
159
- addCacheableResource(cacheableResource) {
160
- if (this.teamId)
161
- cacheableResource.teamId = this.teamId;
162
- this.cacheableResources[cacheableResource.resource] = cacheableResource;
163
- this.resources.push(cacheableResource.resource);
164
- }
165
- /**
166
- * Remove a CacheableResource by its DeltaResource.
167
- */
168
- removeCacheableResource(resource) {
169
- delete this.cacheableResources[resource];
170
- this.resources.splice(this.resources.indexOf(resource), 1);
171
- }
172
- /**
173
- * Get the the DeltaResourced configured.
174
- */
175
- getResources() {
176
- return this.resources;
177
- }
178
- /**
179
- * Get a CacheableResource by its DeltaResource.
180
- */
181
- getCacheableResource(resource) {
182
- return this.cacheableResources[resource];
183
- }
184
- //
185
- // UPLOAD
186
- //
187
- /**
188
- * Execute all the API requests in the queue; the requests terminated with an error will remain in the queue.
189
- */
190
- runQueueAPIRequests() {
191
- return new Promise((resolve, reject) => {
192
- if (!this.useQueueAPIRequests || this.isOffline() || !this.queueAPIRequests.length)
193
- return resolve();
194
- this.queueAPIRequests.forEach(async (request) => {
195
- const options = {};
196
- if (request.resourceId)
197
- options.resourceId = request.resourceId;
198
- if (request.body)
199
- options.body = request.body;
200
- let promise;
201
- try {
202
- switch (request.method.toUpperCase()) {
203
- case 'POST':
204
- promise = await this._API.postResource(request.resource, options);
205
- break;
206
- case 'PUT':
207
- promise = await this._API.putResource(request.resource, options);
208
- break;
209
- case 'PATCH':
210
- promise = await this._API.patchResource(request.resource, options);
211
- break;
212
- }
213
- if (!promise)
214
- request.error = 'INVALID_METHOD';
215
- else
216
- request.error = null;
217
- }
218
- catch (err) {
219
- request.error = err.message || 'UNKNOWN_ERROR';
220
- }
221
- });
222
- // keep the requests NOT successfully executed
223
- this.saveQueueAPIRequest(this.queueAPIRequests.filter(x => x.error)).then(() => {
224
- // if the queue is empty, the entire operation was successful
225
- if (this.queueAPIRequests.length)
226
- reject();
227
- else
228
- resolve();
229
- });
230
- });
231
- }
232
- /**
233
- * Load from the local storage the API requests queue.
234
- */
235
- loadQueueAPIRequest() {
236
- return new Promise(resolve => {
237
- if (!this.useQueueAPIRequests)
238
- return resolve([]);
239
- this._storage.get(this.queueAPIRequestKey).then((queue) => {
240
- this.queueAPIRequests = queue || [];
241
- resolve(this.queueAPIRequests);
242
- });
243
- });
244
- }
245
- /**
246
- * Update the queue in memory and also save the copy in the local storage.
247
- */
248
- saveQueueAPIRequest(queue) {
249
- if (!this.isAllowed())
250
- return Promise.reject();
251
- this.queueAPIRequests = queue || this.queueAPIRequests;
252
- return this._storage.set(this.queueAPIRequestKey, this.queueAPIRequests);
253
- }
254
- /**
255
- * Delete a request stuck in an error.
256
- */
257
- deleteRequest(request) {
258
- if (!this.isAllowed())
259
- return Promise.reject();
260
- if (request) {
261
- this.queueAPIRequests.splice(this.queueAPIRequests.indexOf(request), 1);
262
- this.saveQueueAPIRequest();
263
- }
264
- }
265
- //
266
- // DOWNLOAD
267
- //
268
- /**
269
- * Save the records of a delta and, if the latter has more pages, go recursive.
270
- */
271
- async syncDeltaRecords(delta, done) {
272
- // for each resource, we reset the status; if a resource still need to be synchronized, it will be flagged below
273
- this.resources.forEach(resource => {
274
- this.cacheableResources[resource].error = false;
275
- this.cacheableResources[resource].synchronizing = false;
276
- });
277
- try {
278
- // synchronze each of the resources included in the delta; this execution can go in parallel
279
- await Promise.all(delta.resources.map(async (resource) => {
280
- const cr = this.cacheableResources[resource];
281
- if (cr) {
282
- // synchronize the delta records; note: the executuion inside a resource must go in series
283
- cr.synchronizing = true;
284
- const success = await this.syncResourceDeltaRecords(resource, delta.records[resource]);
285
- if (!success)
286
- this.errorInLastSync = true;
287
- }
288
- }));
289
- // if there were error of if there is nothing left to sync, we are done
290
- if (this.errorInLastSync || !delta.next)
291
- return done();
292
- // otherwise, get the next page of the delta and go recursive until we are done
293
- const params = { next: delta.next, limit: NUM_ELEMENTS_WITH_MANUAL_SYNC };
294
- if (this.lastSyncAt)
295
- params.since = this.lastSyncAt;
296
- const newDelta = await this._API.getResource(this.teamId ? `teams/${this.teamId}/delta` : 'delta', { params });
297
- this.syncDeltaRecords(newDelta, done);
298
- }
299
- catch (err) {
300
- // if something went wrong, stops the operation, since we need to make sure the entire flow is consistent
301
- this.errorInLastSync = true;
302
- return done();
303
- }
304
- }
305
- /**
306
- * Save offline a list of DeltaRecords for this resource, creating a map of all the corresponding API GET requests.
307
- */
308
- async syncResourceDeltaRecords(resource, records) {
309
- // acquire the info an a cacheable resource
310
- const cr = this.cacheableResources[resource];
311
- if (!cr)
312
- return Promise.resolve(true);
313
- try {
314
- // prepare helpers to group executions of elements of the same list
315
- let list = null, oldListURL = null;
316
- for (const r of records) {
317
- // calculate the URL to access the API request key for this element
318
- const elementURL = cr.elementURL(r.element);
319
- // if the element was deleted (based on delta), delete its corresponding API GET request
320
- if (r.deleted)
321
- await this._API.deleteFromCache(elementURL);
322
- // otherwise, update it
323
- else
324
- await this._API.putInCache(elementURL, r.element);
325
- // calculate the URLs to access the API request key for this element's list
326
- const listURL = cr.listURL(r.element);
327
- // to improve the performance, get/sort/save the list only when it changes from the previous element's one.
328
- if (listURL !== oldListURL) {
329
- // skip first cycle (oldListURL === null)
330
- if (oldListURL) {
331
- // re-sort the list; note: it should be sorted from the last time, so we only manage the new element
332
- list = list.sort(cr.sort);
333
- // save the updated list
334
- await this._API.putInCache(oldListURL, list);
335
- }
336
- // get the list of elements from the local storage by the calculated URL
337
- list = await this._API.getFromCache(listURL);
338
- // save the reference to the list for the next cycle
339
- oldListURL = listURL;
340
- }
341
- // find in the list the element we want to manage
342
- const index = cr.findIndexInList(list, r.element);
343
- // delete the element from the list
344
- if (index !== -1)
345
- list.splice(index, 1);
346
- // if the element wasn't deleted (following the delta record information), insert the new version
347
- if (!r.deleted)
348
- list.push(r.element);
349
- }
350
- // in case there were elements, save the last element's list
351
- if (oldListURL) {
352
- // re-sort the list; note: it should be sorted from the last time, so we only manage the new element
353
- list = list.sort(cr.sort);
354
- // save the updated list
355
- await this._API.putInCache(oldListURL, list);
356
- }
357
- return Promise.resolve(true);
358
- }
359
- catch (err) {
360
- // if something went wrong, stops the operation, since we need to make sure the entire flow is consistent
361
- cr.error = true;
362
- return Promise.resolve(false);
363
- }
364
- }
365
- //
366
- // SYNCHRONISATION (UPLOAD+DOWNLOAD)
367
- //
368
- /**
369
- * Run a sync, but only if needed, i.e. the cached content expired or we have pending API requests in the queue.
370
- */
371
- synchronizeIfNeeded() {
372
- return new Promise((resolve, reject) => {
373
- if (!this.isAllowed())
374
- return;
375
- this.loadLastSyncAt().then(() => this.loadQueueAPIRequest()
376
- .then(() => {
377
- if (this.queueAPIRequests.length || Date.now() > this.lastSyncAt + SYNC_EXPIRATION_INTERVAL)
378
- this.synchronize();
379
- resolve();
380
- })
381
- .catch(err => reject(err)));
382
- });
383
- }
384
- /**
385
- * Synchronization of the whole set of resources (upload+download).
386
- * @param manualConfirmation if true, the request comes directly from a user action (not automatic procedures).
387
- */
388
- synchronize(manualConfirmation) {
389
- return new Promise((resolve, reject) => {
390
- if (!this.isAllowed() || this.synchronizing)
391
- return resolve();
392
- this.synchronizing = true;
393
- this.errorInLastSync = false;
394
- this.requiresManualConfirmation = false;
395
- // load the lastSyncAt information
396
- this.loadLastSyncAt().then(() =>
397
- // try to run all the pending API requests in the queue, i.e. uploading the offline resources changed
398
- this.runQueueAPIRequests()
399
- .then(() => {
400
- // set this moment in time: if anything happened before the end of the sync, we don't lose fresh data
401
- const now = Date.now();
402
- // prepare a first "short" Delta request, to see if there is a lot of data to process
403
- const params = { limit: NUM_ELEMENTS_WITHOUT_MANUAL_SYNC };
404
- if (this.lastSyncAt)
405
- params.since = this.lastSyncAt;
406
- this._API
407
- .getResource(this.teamId ? `teams/${this.teamId}/delta` : 'delta', { params })
408
- .then((delta) => {
409
- // decide if to proceed with the sync: in case there is another page, it requires a manual confirmation
410
- if (delta.next && !manualConfirmation) {
411
- this.requiresManualConfirmation = true;
412
- this.synchronizing = false;
413
- return resolve();
414
- }
415
- // save the records in the delta and request possible new pages
416
- this.syncDeltaRecords(delta, () => {
417
- if (this.errorInLastSync) {
418
- this.synchronizing = false;
419
- resolve();
420
- }
421
- else {
422
- // all the resources are succesfully in sync
423
- this.resources.forEach(resource => (this.cacheableResources[resource].synchronizing = false));
424
- // update the timestamp of last sync
425
- this.saveLastSyncAt(now)
426
- .then(() => {
427
- this.synchronizing = false;
428
- resolve();
429
- })
430
- .catch(() => {
431
- // we couldn't save the last sync info
432
- this.errorInLastSync = true;
433
- this.synchronizing = false;
434
- reject();
435
- });
436
- }
437
- });
438
- })
439
- .catch(() => {
440
- // we couldn't acquire new information (Delta)
441
- this.errorInLastSync = true;
442
- this.synchronizing = false;
443
- reject();
444
- });
445
- })
446
- .catch(() => {
447
- // we stop, since we don't want backend data to override local info not yet uploaded
448
- this.errorInLastSync = true;
449
- this.synchronizing = false;
450
- reject();
451
- }));
452
- });
453
- }
454
- /**
455
- * Force a full synchronisation.
456
- */
457
- forceFullSync() {
458
- this._storage.clear().then(() => this.synchronize(true));
459
- }
460
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: IDEAOfflineDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
461
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: IDEAOfflineDataService, providedIn: 'root' }); }
462
- }
463
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: IDEAOfflineDataService, decorators: [{
464
- type: Injectable,
465
- args: [{ providedIn: 'root' }]
466
- }], ctorParameters: () => [] });
467
- /**
468
- * The abstract class to implement for each resource to cache offline from the back-end (DOWNLOAD).
469
- */
470
- export class CacheableResource {
471
- constructor(resource, description) {
472
- this.resource = resource;
473
- this.description = description;
474
- this.synchronizing = false;
475
- this.error = false;
476
- // loaded at runtime
477
- this.teamId = null;
478
- }
479
- }
480
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib2ZmbGluZURhdGEuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL21vZHVsZXMvdW5jb21tb24vc3JjL29mZmxpbmUvb2ZmbGluZURhdGEuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUduRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVqRixPQUFPLEVBQUUsaUJBQWlCLEVBQW9CLE1BQU0sbUJBQW1CLENBQUM7QUFDeEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7O0FBRXZEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsUUFBUTtBQUNyRTs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLHFDQUFxQyxDQUFDO0FBQzVFOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLCtCQUErQixDQUFDO0FBQzdEOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLGdDQUFnQyxHQUFHLEdBQUcsQ0FBQztBQUNwRDs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLDZCQUE2QixHQUFHLEdBQUcsQ0FBQztBQUVqRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQ0c7QUFFSCxNQUFNLE9BQU8sc0JBQXNCO0lBcURqQztRQXBEVSxhQUFRLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDdEMsZUFBVSxHQUFHLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1FBQzdDLGFBQVEsR0FBRyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztRQUN0QyxTQUFJLEdBQUcsTUFB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QURULE1BQU07OzJGQUNuQixzQkFBc0I7a0JBRGxDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFOztBQXFkbEM7O0dBRUc7QUFDSCxNQUFNLE9BQWdCLGlCQUFpQjtJQXVCckMsWUFBWSxRQUFnQixFQUFFLFdBQW1CO1FBQy9DLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQy9CLElBQUksQ0FBQyxhQUFhLEdBQUcsS0FBSyxDQUFDO1FBQzNCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLG9CQUFvQjtRQUNwQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztJQUNyQixDQUFDO0NBc0JGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IERlbHRhLCBEZWx0YVJlY29yZCwgRGVsdGFSZXNvdXJjZXMsIGVwb2NoRGF0ZVRpbWUgfSBmcm9tICdpZGVhLXRvb2xib3gnO1xuaW1wb3J0IHsgSURFQVN0b3JhZ2VTZXJ2aWNlLCBJREVBVHJhbnNsYXRpb25zU2VydmljZSB9IGZyb20gJ0BpZGVhLWlvbmljL2NvbW1vbic7XG5cbmltcG9ydCB7IElERUFBV1NBUElTZXJ2aWNlLCBBUElSZXF1ZXN0T3B0aW9uIH0gZnJvbSAnLi4vQVdTQVBJLnNlcnZpY2UnO1xuaW1wb3J0IHsgSURFQU9mZmxpbmVTZXJ2aWNlIH0gZnJvbSAnLi9vZmZsaW5lLnNlcnZpY2UnO1xuXG4vKipcbiAqIEFmdGVyIGhvdyBtdWNoIHRpbWUgd2UgbmVlZCB0byByZXF1ZXN0IGEgc3luY2hyb25pc2F0aW9uIHRvIGtlZXAgdGhlIGNvbnRlbnRzIHVwLXRvLWRhdGUuXG4gKi9cbmV4cG9ydCBjb25zdCBTWU5DX0VYUElSQVRJT05fSU5URVJWQUwgPSAxMDAwICogNjAgKiA2MCAqIDI0OyAvLyBhIGRheVxuLyoqXG4gKiBQcmVmaXggZm9yIHRoZSBrZXkgb2YgdGhlIEFQSSByZXF1ZXN0cyBxdWV1ZSBpbmZvIGluIHRoZSBsb2NhbCBzdG9yYWdlLlxuICovXG5leHBvcnQgY29uc3QgUVVFVUVfQVBJX1JFUVVFU1RTX0tFWSA9ICdJREVBT2ZmbGluZVNlcnZpY2UucXVldWVBUElyZXF1ZXN0cyc7XG4vKipcbiAqIFByZWZpeCBmb3IgdGhlIGtleSBvZiB0aGUgbGFzdCBzeW5jIHRpbWUgaW5mbyBpbiB0aGUgbG9jYWwgc3RvcmFnZS5cbiAqL1xuZXhwb3J0IGNvbnN0IExBU1RfU1lOQ19LRVkgPSAnSURFQU9mZmxpbmVTZXJ2aWNlLmxhc3RTeW5jQXQnO1xuLyoqXG4gKiBUaGUgbWF4IG51bWJlciBvZiBlbGVtZW50cyBwZXIgcmVzb3VyY2UgdG8gc3luY2hyb25pemUgZHVyaW5nIHRoZSBmaXJzdCBhbmFseXNpcyBvZiBhIHN5bmNocm9uaXNhdGlvbi5cbiAqIElmIHRoZSBudW1iZXIgb2YgZWxlbWVudHMgZXhjZWVkcyAodGhlcmUgaXMgbW9yZSBkYXRhIGFmdGVyIHRoZSAxc3QgcGFnZSksIHRoZSBvcGVyYXRpb24gcmVxdWlyZSBtYW51YWwgY29uZmlybWF0aW9uLlxuICovXG5leHBvcnQgY29uc3QgTlVNX0VMRU1FTlRTX1dJVEhPVVRfTUFOVUFMX1NZTkMgPSAxMDA7XG4vKipcbiAqIFRoZSBtYXggbnVtYmVyIG9mIGVsZW1lbnRzIHBlciByZXNvdXJjZSB0byByZXF1ZXN0IGF0IHRoZSBzYW1lIHRpbWUgZHVyaW5nIGEgbm9ybWFsIHN5bmNocm9uaXNhdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IE5VTV9FTEVNRU5UU19XSVRIX01BTlVBTF9TWU5DID0gMzAwO1xuXG4vKipcbiAqIE1hbmFnZSB0aGUgb2ZmbGluZSBmdW5jdGlvbmluZyBvZiB0aGUgYXBwJ3MgZGF0YSAodXBsb2FkL2Rvd25sb2FkL3N5bmNocm9uaXphdGlvbikuXG4gKiBOb3RlOiBpdCBpbmNsdWRlcyBhbGwgdGhlIG1ldGhvZHMgb2YgSURFQU9mZmxpbmVTZXJ2aWNlLlxuICpcbiAqIERvd25sb2FkOiBpdCB3b3JrcyB0aHJvdWdoIHRoZSAqKkRlbHRhKiogbWVjaGFuaXNtIG9uIGJhY2stZW5kIHJlc291cmNlcy5cbiAqIFByYWN0aWNhbGx5LCB0aGUgc2VydmljZSBwcmVwYXJlcyBlYWNoIHBvc3NpYmxlIEFQSSBHRVQgcmVxdWVzdHMgZm9yIGVhY2ggb2YgdGhlIGludm9sdmVkIHJlc291cmNlcy5cbiAqIEluIHRoaXMgd2F5LCBpZiBvZmZsaW5lLCB0aGUgQVBJIHNlcnZpY2UgY2FuIGhpdCBhbiBlbGVtZW50IGJ5IFVSTCBpbiB0aGUgY2FjaGUgKHN0b3JhZ2Ugb2ZmbGluZSkuXG4gKlxuICogKipIb3cgdG8gdXNlIGl0KiouIENvbmZpZ3VyZSB0aGUgc3luYyBtZWNoYW5pc20gaW4gdGhlIG1haW4gYXBwLmNvbXBvbmVudCBhcyBpdCBmb2xsb3dzOlxuICpcbiAqICAgIDEuIEltcGxlbWVudCBhIENhY2hlYWJsZVJlc291cmNlIGNsYXNzIGZvciBlYWNoIERlbHRhUmVzb3VyY2UgeW91IHdhbnQgdG8gY2FjaGUgb2ZmbGluZS5cbiAqICAgIDIuIFNldCB1cCB0aGUgc2VydmljZSAoYHNldFVwT2ZmbGluZURhdGFgKS5cbiAqICAgIDMuIFJ1biBhIHN5bmNocm9uaXphdGlvbi5cbiAqICAgIDQuIEFkZCB0aGUgbmF2aWdhdGlvbiB0byB0aGUgT2ZmbGluZSBNYW5hZ2VyIChVSSkuXG4gKiAgICA1LiBPcHRpb25hbGx5LCBwdXNoIG9mZmxpbmUgQVBJIHJlcXVlc3RzIHRvIHRoZSBxdWV1ZSB3aGVuIG9mZmxpbmUuXG4gKlxuICogZS5nLiBvZiBDYWNoZWFibGVSZXNvdXJjZSBjbGFzc2VzOlxuICogYGBgXG4gKiBjbGFzcyBDdXN0b21lckNSIGV4dGVuZHMgQ2FjaGVhYmxlUmVzb3VyY2Uge1xuICogICBjb25zdHJ1Y3RvcihkZXNjcmlwdGlvbjogc3RyaW5nKSB7XG4gKiAgICAgc3VwZXIoRGVsdGFSZXNvdXJjZXMuQ1VTVE9NRVJTLCBkZXNjcmlwdGlvbik7XG4gKiAgIH1cbiAqICAgcHVibGljIGxpc3RVUkwoZWxlbWVudDogYW55KTogc3RyaW5nIHtcbiAqICAgICByZXR1cm4gYHRlYW1zLyR7ZWxlbWVudC50ZWFtSWR9L2N1c3RvbWVyc2A7XG4gKiAgIH1cbiAqICAgcHVibGljIGVsZW1lbnRVUkwoZWxlbWVudDogYW55KTogc3RyaW5nIHtcbiAqICAgICByZXR1cm4gYHRlYW1zLyR7ZWxlbWVudC50ZWFtSWR9L2N1c3RvbWVycy8ke2VsZW1lbnQuY3VzdG9tZXJJZH1gO1xuICogICB9XG4gKiAgIHB1YmxpYyBmaW5kSW5kZXhJbkxpc3QobGlzdDogQXJyYXk8YW55PiwgZWxlbWVudDogYW55KTogbnVtYmVyIHtcbiAqICAgICByZXR1cm4gbGlzdC5maW5kSW5kZXgoeCA9PiB4LmN1c3RvbWVySWQgPT09IGVsZW1lbnQuY3VzdG9tZXJJZCk7XG4gKiAgIH1cbiAqICAgcHVibGljIHNvcnQoYTogYW55LCBiOiBhbnkpOiBudW1iZXIge1xuICogICAgIHJldHVybiBhLm5hbWUubG9jYWxlQ29tcGFyZShiLm5hbWUpO1xuICogICB9XG4gKiB9XG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgSURFQU9mZmxpbmVEYXRhU2VydmljZSB7XG4gIHByb3RlY3RlZCBfc3RvcmFnZSA9IGluamVjdChJREVBU3RvcmFnZVNlcnZpY2UpO1xuICBwcm90ZWN0ZWQgX3RyYW5zbGF0ZSA9IGluamVjdChJREVBVHJhbnNsYXRpb25zU2VydmljZSk7XG4gIHByb3RlY3RlZCBfb2ZmbGluZSA9IGluamVjdChJREVBT2ZmbGluZVNlcnZpY2UpO1xuICBwcm90ZWN0ZWQgX0FQSSA9IGluamVjdChJREVBQVdTQVBJU2VydmljZSk7XG5cbiAgLyoqXG4gICAqIFRydWUgd2hlbiBydW5uaW5nIGEgc3luY2hyb25pemF0aW9uLlxuICAgKi9cbiAgc3luY2hyb25pemluZzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFRoZSB0aW1lc3RhbXAgb2YgdGhlIGxhc3Qgc3luY2hyb25pemF0aW9uLlxuICAgKi9cbiAgbGFzdFN5bmNBdDogZXBvY2hEYXRlVGltZTtcbiAgLyoqXG4gICAqIFRydWUgaWYgYW4gZXJyb3IgaGFwcGVuZWQgaW4gdGhlIGxhc3Qgc3luY2hyb25pemF0aW9uLlxuICAgKi9cbiAgZXJyb3JJbkxhc3RTeW5jOiBib29sZWFuO1xuICAvKipcbiAgICogVHJ1ZSBpZiB0aGUgc3luY2hyb25pc2F0aW9uIGlzIHRvbyB2YXN0IGFuZCBzbyByZXF1aXJlIGEgbWFudWFsIGFjdGlvbiBvZiB0aGUgdXNlci5cbiAgICovXG4gIHJlcXVpcmVzTWFudWFsQ29uZmlybWF0aW9uOiBib29sZWFuO1xuICAvKipcbiAgICogSWYgZmFsc2UsIGlnbm9yZSB0aGUgZW50aXJlIHVwbG9hZCBzY2VuYXJpby5cbiAgICovXG4gIHVzZVF1ZXVlQVBJUmVxdWVzdHM6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBUaGUgYXJyYXkgb2YgdGhlIHJlcXVlc3RzIG5vdCBleGVjdXRlZCBiZWNhdXNlIHdlIGFyZS93ZXJlIG9mZmxpbmU7IHRoZXkgbmVlZCB0byBydW4gb25jZSBvbmxpbmUuXG4gICAqL1xuICBxdWV1ZUFQSVJlcXVlc3RzOiBBUElSZXF1ZXN0W107XG5cbiAgLyoqXG4gICAqIFRoZSBpZCBvZiB0aGUgdGVhbSBvZiB3aGljaCB0byBtYW5hZ2UgZGF0YSBvZmZsaW5lLlxuICAgKiBJZiBudWxsLCB0aGUgcHJvamVjdCBpc24ndCB0ZWFtcy1iYXNlZC5cbiAgICovXG4gIHByb3RlY3RlZCB0ZWFtSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBhcnJheSBvZiBEZWx0YVJlc291cmNlcyB0byBjYWNoZSBvZmZsaW5lLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJlc291cmNlczogKERlbHRhUmVzb3VyY2VzIHwgc3RyaW5nKVtdO1xuICAvKipcbiAgICogSGVscGVyIHN0cnVjdHVyZSB0byBtYW5hZ2UgdGhlIENhY2hlYWJsZVJlc291cmNlIGZvciBlYWNoIERlbHRhUmVzb3VyY2UuXG4gICAqL1xuICBwcm90ZWN0ZWQgY2FjaGVhYmxlUmVzb3VyY2VzOiB7IFtyZXNvdXJjZTogc3RyaW5nXTogQ2FjaGVhYmxlUmVzb3VyY2UgfTtcbiAgLyoqXG4gICAqIEtleSB0byBhY3F1aXJlIGZyb20gdGhlIHN0b3JhZ2UgdGhlIGxhc3RTeW5jQXQgaW5mb3JtYXRpb24gb2YgdGhlIHRlYW0uXG4gICAqL1xuICBwcm90ZWN0ZWQgbGFzdFN5bmNLZXk6IHN0cmluZztcbiAgLyoqXG4gICAqIEtleSB0byBhY3F1aXJlIGZyb20gdGhlIHN0b3JhZ2UgdGhlIGxhc3RTeW5jQXQgaW5mb3JtYXRpb24gb2YgdGhlIHRlYW0uXG4gICAqL1xuICBwcm90ZWN0ZWQgcXVldWVBUElSZXF1ZXN0S2V5OiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5xdWV1ZUFQSVJlcXVlc3RzID0gbmV3IEFycmF5PEFQSVJlcXVlc3Q+KCk7XG4gICAgdGhpcy5yZXNvdXJjZXMgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuICAgIHRoaXMuY2FjaGVhYmxlUmVzb3VyY2VzID0ge307XG4gICAgLy8gc3Vic2NyaWJlIHRvIG5ldHdvcmsgY2hhbmdlc1xuICAgIHRoaXMuX29mZmxpbmUuc3Vic2NyaWJlKGlzT25saW5lID0+IHtcbiAgICAgIGlmIChpc09ubGluZSkge1xuICAgICAgICAvLyB0cnkgYSBzeW5jaHJvbml6YXRpb24gaWYgbmVlZGVkIG9yIGlmIHRoZSBsYXN0IG9uZSBmYWlsZWRcbiAgICAgICAgaWYgKHRoaXMuZXJyb3JJbkxhc3RTeW5jKSB0aGlzLnN5bmNocm9uaXplKCk7XG4gICAgICAgIGVsc2UgdGhpcy5zeW5jaHJvbml6ZUlmTmVlZGVkKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvL1xuICAvLyBORVRXT1JLIFNUQVRVUyBmcm9tIElERUFPZmZsaW5lU2VydmljZVxuICAvL1xuXG4gIC8qKlxuICAgKiBRdWlja2x5IGNoZWNrIHRoZSBjb25uZWN0aW9uIHN0YXR1cy5cbiAgICovXG4gIGlzT25saW5lKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9vZmZsaW5lLmlzT25saW5lKCk7XG4gIH1cbiAgLyoqXG4gICAqIFF1aWNrbHkgY2hlY2sgdGhlIGNvbm5lY3Rpb24gc3RhdHVzLlxuICAgKi9cbiAgaXNPZmZsaW5lKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9vZmZsaW5lLmlzT2ZmbGluZSgpO1xuICB9XG4gIC8qKlxuICAgKiBTdWJzY3JpYmUgdG8gdGhlIHNlcnZpY2UgdG8gYmUgbm90aWZpZWQgd2hlbiB0aGUgY29ubmVjdGlvbiBzdGF0dXMgY2hhbmdlcy5cbiAgICovXG4gIHN1YnNjcmliZShjYWxsYmFjazogKGlzT25saW5lOiBib29sZWFuKSA9PiB2b2lkKTogU3Vic2NyaXB0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5fb2ZmbGluZS5zdWJzY3JpYmUoY2FsbGJhY2spO1xuICB9XG4gIC8qKlxuICAgKiBRdWlja2x5IGNoZWNrIGZvciBvbmxpbmUgY29ubmVjdGlvbi5cbiAgICovXG4gIHB1YmxpYyBjaGVjaygpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5fb2ZmbGluZS5jaGVjaygpO1xuICB9XG5cbiAgLy9cbiAgLy8gQ09ORklHVVJBVElPTlxuICAvL1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBvZmZsaW5lIG1vZGUgaXMgYWxsb3dlZC4gWW91IGNhbiBjdXN0b21pemUgdGhpcyBmdW5jdGlvbiwgaWYgbmVlZGVkLlxuICAgKi9cbiAgaXNBbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXRoaXMucmVzb3VyY2VzLmxlbmd0aDtcbiAgfVxuICAvKipcbiAgICogU2V0IHVwIHRoZSBzZXJ2aWNlIHRvIHVzZSBhbmQgc3luYyBvZmZsaW5lIGRhdGEuXG4gICAqL1xuICBzZXRVcE9mZmxpbmVEYXRhKHRlYW1JZDogc3RyaW5nLCB1c2VRdWV1ZUFQSVJlcXVlc3RzOiBib29sZWFuLCBjYWNoZWFibGVSZXNvdXJjZXM6IENhY2hlYWJsZVJlc291cmNlW10pOiB2b2lkIHtcbiAgICAvLyBzZXQgdGhlIHRlYW1cbiAgICB0aGlzLnRlYW1JZCA9IHRlYW1JZDtcbiAgICAvLyBkZWNpZGUgaWYgdG8gYWxsb3cgY2VydGFpbiBBUEkgcmVxdWVzdCB3aGlsZSBvZmZsaW5lXG4gICAgdGhpcy51c2VRdWV1ZUFQSVJlcXVlc3RzID0gdXNlUXVldWVBUElSZXF1ZXN0cztcbiAgICAvLyBsb2FkIHRoZSBBUEkgcmVxdWVzdCBwZW5kaW5nIHF1ZXVlLCBpZiBhbnlcbiAgICB0aGlzLnF1ZXVlQVBJUmVxdWVzdEtleSA9IHRoaXMudGVhbUlkID8gYCR7UVVFVUVfQVBJX1JFUVVFU1RTX0tFWX1fJHt0aGlzLnRlYW1JZH1gIDogUVVFVUVfQVBJX1JFUVVFU1RTX0tFWTtcbiAgICB0aGlzLmxvYWRRdWV1ZUFQSVJlcXVlc3QoKTtcbiAgICAvLyBsb2FkIHRoZSBsYXN0U3luY0F0IGluZm9ybWF0aW9uIGZvciB0aGUgdGVhbVxuICAgIHRoaXMubGFzdFN5bmNLZXkgPSB0aGlzLnRlYW1JZCA/IGAke0xBU1RfU1lOQ19LRVl9XyR7dGhpcy50ZWFtSWR9YCA6IExBU1RfU1lOQ19LRVk7XG4gICAgdGhpcy5sb2FkTGFzdFN5bmNBdCgpO1xuICAgIC8vIGxvYWQgdGhlIGNhY2hlYWJsZSByZXNvdXJjZXNcbiAgICB0aGlzLnJlc291cmNlcyA9IG5ldyBBcnJheTxEZWx0YVJlc291cmNlcyB8IHN0cmluZz4oKTtcbiAgICB0aGlzLmNhY2hlYWJsZVJlc291cmNlcyA9IHt9O1xuICAgIGNhY2hlYWJsZVJlc291cmNlcy5mb3JFYWNoKHIgPT4gdGhpcy5hZGRDYWNoZWFibGVSZXNvdXJjZShyKSk7XG4gIH1cbiAgLyoqXG4gICAqIExvYWQgZnJvbSB0aGUgbG9jYWwgc3RvcmFnZSB0aGUgbGFzdCBzeW5jIGF0IGluZm9ybWF0aW9uLlxuICAgKi9cbiAgcHJvdGVjdGVkIGxvYWRMYXN0U3luY0F0KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgdGhpcy5fc3RvcmFnZS5nZXQodGhpcy5sYXN0U3luY0tleSkudGhlbigobGFzdFN5bmNBdDogbnVtYmVyKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMubGFzdFN5bmNBdCA9IGxhc3RTeW5jQXQgPyBOdW1iZXIobGFzdFN5bmNBdCkgOiBudWxsO1xuICAgICAgICByZXNvbHZlKHRoaXMubGFzdFN5bmNBdCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICAvKipcbiAgICogVXBkYXRlIGxhc3Qgc3luYyBhdCBpbmZvIGluIHRoZSBsb2NhbCBzdG9yYWdlLlxuICAgKi9cbiAgcHJvdGVjdGVkIHNhdmVMYXN0U3luY0F0KGxhc3RTeW5jQXQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMubGFzdFN5bmNBdCA9IGxhc3RTeW5jQXQ7XG4gICAgcmV0dXJuIHRoaXMuX3N0b3JhZ2Uuc2V0KHRoaXMubGFzdFN5bmNLZXksIGxhc3RTeW5jQXQpO1xuICB9XG4gIC8qKlxuICAgKiBBZGQgYSBDYWNoZWFibGVSZXNvdXJjZS5cbiAgICovXG4gIHByb3RlY3RlZCBhZGRDYWNoZWFibGVSZXNvdXJjZShjYWNoZWFibGVSZXNvdXJjZTogQ2FjaGVhYmxlUmVzb3VyY2UpOiB2b2lkIHtcbiAgICBpZiAodGhpcy50ZWFtSWQpIGNhY2hlYWJsZVJlc291cmNlLnRlYW1JZCA9IHRoaXMudGVhbUlkO1xuICAgIHRoaXMuY2FjaGVhYmxlUmVzb3VyY2VzW2NhY2hlYWJsZVJlc291cmNlLnJlc291cmNlXSA9IGNhY2hlYWJsZVJlc291cmNlO1xuICAgIHRoaXMucmVzb3VyY2VzLnB1c2goY2FjaGVhYmxlUmVzb3VyY2UucmVzb3VyY2UpO1xuICB9XG4gIC8qKlxuICAgKiBSZW1vdmUgYSBDYWNoZWFibGVSZXNvdXJjZSBieSBpdHMgRGVsdGFSZXNvdXJjZS5cbiAgICovXG4gIHByb3RlY3RlZCByZW1vdmVDYWNoZWFibGVSZXNvdXJjZShyZXNvdXJjZTogRGVsdGFSZXNvdXJjZXMgfCBzdHJpbmcpOiB2b2lkIHtcbiAgICBkZWxldGUgdGhpcy5jYWNoZWFibGVSZXNvdXJjZXNbcmVzb3VyY2VdO1xuICAgIHRoaXMucmVzb3VyY2VzLnNwbGljZSh0aGlzLnJlc291cmNlcy5pbmRleE9mKHJlc291cmNlKSwgMSk7XG4gIH1cbiAgLyoqXG4gICAqIEdldCB0aGUgdGhlIERlbHRhUmVzb3VyY2VkIGNvbmZpZ3VyZWQuXG4gICAqL1xuICBnZXRSZXNvdXJjZXMoKTogKERlbHRhUmVzb3VyY2VzIHwgc3RyaW5nKVtdIHtcbiAgICByZXR1cm4gdGhpcy5yZXNvdXJjZXM7XG4gIH1cbiAgLyoqXG4gICAqIEdldCBhIENhY2hlYWJsZVJlc291cmNlIGJ5IGl0cyBEZWx0YVJlc291cmNlLlxuICAgKi9cbiAgZ2V0Q2FjaGVhYmxlUmVzb3VyY2UocmVzb3VyY2U6IERlbHRhUmVzb3VyY2VzIHwgc3RyaW5nKTogQ2FjaGVhYmxlUmVzb3VyY2Uge1xuICAgIHJldHVybiB0aGlzLmNhY2hlYWJsZVJlc291cmNlc1tyZXNvdXJjZV07XG4gIH1cblxuICAvL1xuICAvLyBVUExPQURcbiAgLy9cblxuICAvKipcbiAgICogRXhlY3V0ZSBhbGwgdGhlIEFQSSByZXF1ZXN0cyBpbiB0aGUgcXVldWU7IHRoZSByZXF1ZXN0cyB0ZXJtaW5hdGVkIHdpdGggYW4gZXJyb3Igd2lsbCByZW1haW4gaW4gdGhlIHF1ZXVlLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJ1blF1ZXVlQVBJUmVxdWVzdHMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpOiB2b2lkID0+IHtcbiAgICAgIGlmICghdGhpcy51c2VRdWV1ZUFQSVJlcXVlc3RzIHx8IHRoaXMuaXNPZmZsaW5lKCkgfHwgIXRoaXMucXVldWVBUElSZXF1ZXN0cy5sZW5ndGgpIHJldHVybiByZXNvbHZlKCk7XG4gICAgICB0aGlzLnF1ZXVlQVBJUmVxdWVzdHMuZm9yRWFjaChhc3luYyByZXF1ZXN0ID0+IHtcbiAgICAgICAgY29uc3Qgb3B0aW9uczogQVBJUmVxdWVzdE9wdGlvbiA9IHt9O1xuICAgICAgICBpZiAocmVxdWVzdC5yZXNvdXJjZUlkKSBvcHRpb25zLnJlc291cmNlSWQgPSByZXF1ZXN0LnJlc291cmNlSWQ7XG4gICAgICAgIGlmIChyZXF1ZXN0LmJvZHkpIG9wdGlvbnMuYm9keSA9IHJlcXVlc3QuYm9keTtcbiAgICAgICAgbGV0IHByb21pc2U6IFByb21pc2U8YW55PjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBzd2l0Y2ggKHJlcXVlc3QubWV0aG9kLnRvVXBwZXJDYXNlKCkpIHtcbiAgICAgICAgICAgIGNhc2UgJ1BPU1QnOlxuICAgICAgICAgICAgICBwcm9taXNlID0gYXdhaXQgdGhpcy5fQVBJLnBvc3RSZXNvdXJjZShyZXF1ZXN0LnJlc291cmNlLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdQVVQnOlxuICAgICAgICAgICAgICBwcm9taXNlID0gYXdhaXQgdGhpcy5fQVBJLnB1dFJlc291cmNlKHJlcXVlc3QucmVzb3VyY2UsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ1BBVENIJzpcbiAgICAgICAgICAgICAgcHJvbWlzZSA9IGF3YWl0IHRoaXMuX0FQSS5wYXRjaFJlc291cmNlKHJlcXVlc3QucmVzb3VyY2UsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKCFwcm9taXNlKSByZXF1ZXN0LmVycm9yID0gJ0lOVkFMSURfTUVUSE9EJztcbiAgICAgICAgICBlbHNlIHJlcXVlc3QuZXJyb3IgPSBudWxsO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICByZXF1ZXN0LmVycm9yID0gKGVyciBhcyBFcnJvcikubWVzc2FnZSB8fCAnVU5LTk9XTl9FUlJPUic7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgLy8ga2VlcCB0aGUgcmVxdWVzdHMgTk9UIHN1Y2Nlc3NmdWxseSBleGVjdXRlZFxuICAgICAgdGhpcy5zYXZlUXVldWVBUElSZXF1ZXN0KHRoaXMucXVldWVBUElSZXF1ZXN0cy5maWx0ZXIoeCA9PiB4LmVycm9yKSkudGhlbigoKTogdm9pZCA9PiB7XG4gICAgICAgIC8vIGlmIHRoZSBxdWV1ZSBpcyBlbXB0eSwgdGhlIGVudGlyZSBvcGVyYXRpb24gd2FzIHN1Y2Nlc3NmdWxcbiAgICAgICAgaWYgKHRoaXMucXVldWVBUElSZXF1ZXN0cy5sZW5ndGgpIHJlamVjdCgpO1xuICAgICAgICBlbHNlIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBMb2FkIGZyb20gdGhlIGxvY2FsIHN0b3JhZ2UgdGhlIEFQSSByZXF1ZXN0cyBxdWV1ZS5cbiAgICovXG4gIHByb3RlY3RlZCBsb2FkUXVldWVBUElSZXF1ZXN0KCk6IFByb21pc2U8QVBJUmVxdWVzdFtdPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgaWYgKCF0aGlzLnVzZVF1ZXVlQVBJUmVxdWVzdHMpIHJldHVybiByZXNvbHZlKFtdKTtcbiAgICAgIHRoaXMuX3N0b3JhZ2UuZ2V0KHRoaXMucXVldWVBUElSZXF1ZXN0S2V5KS50aGVuKChxdWV1ZTogQVBJUmVxdWVzdFtdKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMucXVldWVBUElSZXF1ZXN0cyA9IHF1ZXVlIHx8IFtdO1xuICAgICAgICByZXNvbHZlKHRoaXMucXVldWVBUElSZXF1ZXN0cyk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICAvKipcbiAgICogVXBkYXRlIHRoZSBxdWV1ZSBpbiBtZW1vcnkgYW5kIGFsc28gc2F2ZSB0aGUgY29weSBpbiB0aGUgbG9jYWwgc3RvcmFnZS5cbiAgICovXG4gIHNhdmVRdWV1ZUFQSVJlcXVlc3QocXVldWU/OiBBUElSZXF1ZXN0W10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuaXNBbGxvd2VkKCkpIHJldHVybiBQcm9taXNlLnJlamVjdCgpO1xuICAgIHRoaXMucXVldWVBUElSZXF1ZXN0cyA9IHF1ZXVlIHx8IHRoaXMucXVldWVBUElSZXF1ZXN0cztcbiAgICByZXR1cm4gdGhpcy5fc3RvcmFnZS5zZXQodGhpcy5xdWV1ZUFQSVJlcXVlc3RLZXksIHRoaXMucXVldWVBUElSZXF1ZXN0cyk7XG4gIH1cbiAgLyoqXG4gICAqIERlbGV0ZSBhIHJlcXVlc3Qgc3R1Y2sgaW4gYW4gZXJyb3IuXG4gICAqL1xuICBkZWxldGVSZXF1ZXN0KHJlcXVlc3Q6IEFQSVJlcXVlc3QpIHtcbiAgICBpZiAoIXRoaXMuaXNBbGxvd2VkKCkpIHJldHVybiBQcm9taXNlLnJlamVjdCgpO1xuICAgIGlmIChyZXF1ZXN0KSB7XG4gICAgICB0aGlzLnF1ZXVlQVBJUmVxdWVzdHMuc3BsaWNlKHRoaXMucXVldWVBUElSZXF1ZXN0cy5pbmRleE9mKHJlcXVlc3QpLCAxKTtcbiAgICAgIHRoaXMuc2F2ZVF1ZXVlQVBJUmVxdWVzdCgpO1xuICAgIH1cbiAgfVxuXG4gIC8vXG4gIC8vIERPV05MT0FEXG4gIC8vXG5cbiAgLyoqXG4gICAqIFNhdmUgdGhlIHJlY29yZHMgb2YgYSBkZWx0YSBhbmQsIGlmIHRoZSBsYXR0ZXIgaGFzIG1vcmUgcGFnZXMsIGdvIHJlY3Vyc2l2ZS5cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBzeW5jRGVsdGFSZWNvcmRzKGRlbHRhOiBEZWx0YSwgZG9uZT86IGFueSk6IFByb21pc2U8YW55PiB7XG4gICAgLy8gZm9yIGVhY2ggcmVzb3VyY2UsIHdlIHJlc2V0IHRoZSBzdGF0dXM7IGlmIGEgcmVzb3VyY2Ugc3RpbGwgbmVlZCB0byBiZSBzeW5jaHJvbml6ZWQsIGl0IHdpbGwgYmUgZmxhZ2dlZCBiZWxvd1xuICAgIHRoaXMucmVzb3VyY2VzLmZvckVhY2gocmVzb3VyY2UgPT4ge1xuICAgICAgdGhpcy5jYWNoZWFibGVSZXNvdXJjZXNbcmVzb3VyY2VdLmVycm9yID0gZmFsc2U7XG4gICAgICB0aGlzLmNhY2hlYWJsZVJlc291cmNlc1tyZXNvdXJjZV0uc3luY2hyb25pemluZyA9IGZhbHNlO1xuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICAvLyBzeW5jaHJvbnplIGVhY2ggb2YgdGhlIHJlc291cmNlcyBpbmNsdWRlZCBpbiB0aGUgZGVsdGE7IHRoaXMgZXhlY3V0aW9uIGNhbiBnbyBpbiBwYXJhbGxlbFxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGRlbHRhLnJlc291cmNlcy5tYXAoYXN5bmMgcmVzb3VyY2UgPT4ge1xuICAgICAgICAgIGNvbnN0IGNyID0gdGhpcy5jYWNoZWFibGVSZXNvdXJjZXNbcmVzb3VyY2VdO1xuICAgICAgICAgIGlmIChjcikge1xuICAgICAgICAgICAgLy8gc3luY2hyb25pemUgdGhlIGRlbHRhIHJlY29yZHM7IG5vdGU6IHRoZSBleGVjdXR1aW9uIGluc2lkZSBhIHJlc291cmNlIG11c3QgZ28gaW4gc2VyaWVzXG4gICAgICAgICAgICBjci5zeW5jaHJvbml6aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIGNvbnN0IHN1Y2Nlc3MgPSBhd2FpdCB0aGlzLnN5bmNSZXNvdXJjZURlbHRhUmVjb3JkcyhyZXNvdXJjZSwgZGVsdGEucmVjb3Jkc1tyZXNvdXJjZV0pO1xuICAgICAgICAgICAgaWYgKCFzdWNjZXNzKSB0aGlzLmVycm9ySW5MYXN0U3luYyA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICAgIC8vIGlmIHRoZXJlIHdlcmUgZXJyb3Igb2YgaWYgdGhlcmUgaXMgbm90aGluZyBsZWZ0IHRvIHN5bmMsIHdlIGFyZSBkb25lXG4gICAgICBpZiAodGhpcy5lcnJvckluTGFzdFN5bmMgfHwgIWRlbHRhLm5leHQpIHJldHVybiBkb25lKCk7XG4gICAgICAvLyBvdGhlcndpc2UsIGdldCB0aGUgbmV4dCBwYWdlIG9mIHRoZSBkZWx0YSBhbmQgZ28gcmVjdXJzaXZlIHVudGlsIHdlIGFyZSBkb25lXG4gICAgICBjb25zdCBwYXJhbXM6IGFueSA9IHsgbmV4dDogZGVsdGEubmV4dCwgbGltaXQ6IE5VTV9FTEVNRU5UU19XSVRIX01BTlVBTF9TWU5DIH07XG4gICAgICBpZiAodGhpcy5sYXN0U3luY0F0KSBwYXJhbXMuc2luY2UgPSB0aGlzLmxhc3RTeW5jQXQ7XG4gICAgICBjb25zdCBuZXdEZWx0YSA9IGF3YWl0IHRoaXMuX0FQSS5nZXRSZXNvdXJjZSh0aGlzLnRlYW1JZCA/IGB0ZWFtcy8ke3RoaXMudGVhbUlkfS9kZWx0YWAgOiAnZGVsdGEnLCB7IHBhcmFtcyB9KTtcbiAgICAgIHRoaXMuc3luY0RlbHRhUmVjb3JkcyhuZXdEZWx0YSwgZG9uZSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBpZiBzb21ldGhpbmcgd2VudCB3cm9uZywgc3RvcHMgdGhlIG9wZXJhdGlvbiwgc2luY2Ugd2UgbmVlZCB0byBtYWtlIHN1cmUgdGhlIGVudGlyZSBmbG93IGlzIGNvbnNpc3RlbnRcbiAgICAgIHRoaXMuZXJyb3JJbkxhc3RTeW5jID0gdHJ1ZTtcbiAgICAgIHJldHVybiBkb25lKCk7XG4gICAgfVxuICB9XG4gIC8qKlxuICAgKiBTYXZlIG9mZmxpbmUgYSBsaXN0IG9mIERlbHRhUmVjb3JkcyBmb3IgdGhpcyByZXNvdXJjZSwgY3JlYXRpbmcgYSBtYXAgb2YgYWxsIHRoZSBjb3JyZXNwb25kaW5nIEFQSSBHRVQgcmVxdWVzdHMuXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgc3luY1Jlc291cmNlRGVsdGFSZWNvcmRzKHJlc291cmNlOiBzdHJpbmcsIHJlY29yZHM6IERlbHRhUmVjb3JkW10pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAvLyBhY3F1aXJlIHRoZSBpbmZvIGFuIGEgY2FjaGVhYmxlIHJlc291cmNlXG4gICAgY29uc3QgY3IgPSB0aGlzLmNhY2hlYWJsZVJlc291cmNlc1tyZXNvdXJjZV07XG4gICAgaWYgKCFjcikgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0cnVlKTtcbiAgICB0cnkge1xuICAgICAgLy8gcHJlcGFyZSBoZWxwZXJzIHRvIGdyb3VwIGV4ZWN1dGlvbnMgb2YgZWxlbWVudHMgb2YgdGhlIHNhbWUgbGlzdFxuICAgICAgbGV0IGxpc3Q6IGFueVtdID0gbnVsbCxcbiAgICAgICAgb2xkTGlzdFVSTDogc3RyaW5nID0gbnVsbDtcbiAgICAgIGZvciAoY29uc3QgciBvZiByZWNvcmRzKSB7XG4gICAgICAgIC8vIGNhbGN1bGF0ZSB0aGUgVVJMIHRvIGFjY2VzcyB0aGUgQVBJIHJlcXVlc3Qga2V5IGZvciB0aGlzIGVsZW1lbnRcbiAgICAgICAgY29uc3QgZWxlbWVudFVSTCA9IGNyLmVsZW1lbnRVUkwoci5lbGVtZW50KTtcbiAgICAgICAgLy8gaWYgdGhlIGVsZW1lbnQgd2FzIGRlbGV0ZWQgKGJhc2VkIG9uIGRlbHRhKSwgZGVsZXRlIGl0cyBjb3JyZXNwb25kaW5nIEFQSSBHRVQgcmVxdWVzdFxuICAgICAgICBpZiAoci5kZWxldGVkKSBhd2FpdCB0aGlzLl9BUEkuZGVsZXRlRnJvbUNhY2hlKGVsZW1lbnRVUkwpO1xuICAgICAgICAvLyBvdGhlcndpc2UsIHVwZGF0ZSBpdFxuICAgICAgICBlbHNlIGF3YWl0IHRoaXMuX0FQSS5wdXRJbkNhY2hlKGVsZW1lbnRVUkwsIHIuZWxlbWVudCk7XG4gICAgICAgIC8vIGNhbGN1bGF0ZSB0aGUgVVJMcyB0byBhY2Nlc3MgdGhlIEFQSSByZXF1ZXN0IGtleSBmb3IgdGhpcyBlbGVtZW50J3MgbGlzdFxuICAgICAgICBjb25zdCBsaXN0VVJMID0gY3IubGlzdFVSTChyLmVsZW1lbnQpO1xuICAgICAgICAvLyB0byBpbXByb3ZlIHRoZSBwZXJmb3JtYW5jZSwgZ2V0L3NvcnQvc2F2ZSB0aGUgbGlzdCBvbmx5IHdoZW4gaXQgY2hhbmdlcyBmcm9tIHRoZSBwcmV2aW91cyBlbGVtZW50J3Mgb25lLlxuICAgICAgICBpZiAobGlzdFVSTCAhPT0gb2xkTGlzdFVSTCkge1xuICAgICAgICAgIC8vIHNraXAgZmlyc3QgY3ljbGUgKG9sZExpc3RVUkwgPT09IG51bGwpXG4gICAgICAgICAgaWYgKG9sZExpc3RVUkwpIHtcbiAgICAgICAgICAgIC8vIHJlLXNvcnQgdGhlIGxpc3Q7IG5vdGU6IGl0IHNob3VsZCBiZSBzb3J0ZWQgZnJvbSB0aGUgbGFzdCB0aW1lLCBzbyB3ZSBvbmx5IG1hbmFnZSB0aGUgbmV3IGVsZW1lbnRcbiAgICAgICAgICAgIGxpc3QgPSBsaXN0LnNvcnQoY3Iuc29ydCk7XG4gICAgICAgICAgICAvLyBzYXZlIHRoZSB1cGRhdGVkIGxpc3RcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX0FQSS5wdXRJbkNhY2hlKG9sZExpc3RVUkwsIGxpc3QpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBnZXQgdGhlIGxpc3Qgb2YgZWxlbWVudHMgZnJvbSB0aGUgbG9jYWwgc3RvcmFnZSBieSB0aGUgY2FsY3VsYXRlZCBVUkxcbiAgICAgICAgICBsaXN0ID0gYXdhaXQgdGhpcy5fQVBJLmdldEZyb21DYWNoZShsaXN0VVJMKTtcbiAgICAgICAgICAvLyBzYXZlIHRoZSByZWZlcmVuY2UgdG8gdGhlIGxpc3QgZm9yIHRoZSBuZXh0IGN5Y2xlXG4gICAgICAgICAgb2xkTGlzdFVSTCA9IGxpc3RVUkw7XG4gICAgICAgIH1cbiAgICAgICAgLy8gZmluZCBpbiB0aGUgbGlzdCB0aGUgZWxlbWVudCB3ZSB3YW50IHRvIG1hbmFnZVxuICAgICAgICBjb25zdCBpbmRleCA9IGNyLmZpbmRJbmRleEluTGlzdChsaXN0LCByLmVsZW1lbnQpO1xuICAgICAgICAvLyBkZWxldGUgdGhlIGVsZW1lbnQgZnJvbSB0aGUgbGlzdFxuICAgICAgICBpZiAoaW5kZXggIT09IC0xKSBsaXN0LnNwbGljZShpbmRleCwgMSk7XG4gICAgICAgIC8vIGlmIHRoZSBlbGVtZW50IHdhc24ndCBkZWxldGVkIChmb2xsb3dpbmcgdGhlIGRlbHRhIHJlY29yZCBpbmZvcm1hdGlvbiksIGluc2VydCB0aGUgbmV3IHZlcnNpb25cbiAgICAgICAgaWYgKCFyLmRlbGV0ZWQpIGxpc3QucHVzaChyLmVsZW1lbnQpO1xuICAgICAgfVxuICAgICAgLy8gaW4gY2FzZSB0aGVyZSB3ZXJlIGVsZW1lbnRzLCBzYXZlIHRoZSBsYXN0IGVsZW1lbnQncyBsaXN0XG4gICAgICBpZiAob2xkTGlzdFVSTCkge1xuICAgICAgICAvLyByZS1zb3J0IHRoZSBsaXN0OyBub3RlOiBpdCBzaG91bGQgYmUgc29ydGVkIGZyb20gdGhlIGxhc3QgdGltZSwgc28gd2Ugb25seSBtYW5hZ2UgdGhlIG5ldyBlbGVtZW50XG4gICAgICAgIGxpc3QgPSBsaXN0LnNvcnQoY3Iuc29ydCk7XG4gICAgICAgIC8vIHNhdmUgdGhlIHVwZGF0ZWQgbGlzdFxuICAgICAgICBhd2FpdCB0aGlzLl9BUEkucHV0SW5DYWNoZShvbGRMaXN0VVJMLCBsaXN0KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUodHJ1ZSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBpZiBzb21ldGhpbmcgd2VudCB3cm9uZywgc3RvcHMgdGhlIG9wZXJhdGlvbiwgc2luY2Ugd2UgbmVlZCB0byBtYWtlIHN1cmUgdGhlIGVudGlyZSBmbG93IGlzIGNvbnNpc3RlbnRcbiAgICAgIGNyLmVycm9yID0gdHJ1ZTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIC8vXG4gIC8vIFNZTkNIUk9OSVNBVElPTiAoVVBMT0FEK0RPV05MT0FEKVxuICAvL1xuXG4gIC8qKlxuICAgKiBSdW4gYSBzeW5jLCBidXQgb25seSBpZiBuZWVkZWQsIGkuZS4gdGhlIGNhY2hlZCBjb250ZW50IGV4cGlyZWQgb3Igd2UgaGF2ZSBwZW5kaW5nIEFQSSByZXF1ZXN0cyBpbiB0aGUgcXVldWUuXG4gICAqL1xuICBzeW5jaHJvbml6ZUlmTmVlZGVkKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICBpZiAoIXRoaXMuaXNBbGxvd2VkKCkpIHJldHVybjtcbiAgICAgIHRoaXMubG9hZExhc3RTeW5jQXQoKS50aGVuKFxuICAgICAgICAoKTogUHJvbWlzZTx2b2lkPiA9PlxuICAgICAgICAgIHRoaXMubG9hZFF1ZXVlQVBJUmVxdWVzdCgpXG4gICAgICAgICAgICAudGhlbigoKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLnF1ZXVlQVBJUmVxdWVzdHMubGVuZ3RoIHx8IERhdGUubm93KCkgPiB0aGlzLmxhc3RTeW5jQXQgKyBTWU5DX0VYUElSQVRJT05fSU5URVJWQUwpXG4gICAgICAgICAgICAgICAgdGhpcy5zeW5jaHJvbml6ZSgpO1xuICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKGVyciA9PiByZWplY3QoZXJyKSlcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cbiAgLyoqXG4gICAqIFN5bmNocm9uaXphdGlvbiBvZiB0aGUgd2hvbGUgc2V0IG9mIHJlc291cmNlcyAodXBsb2FkK2Rvd25sb2FkKS5cbiAgICogQHBhcmFtIG1hbnVhbENvbmZpcm1hdGlvbiBpZiB0cnVlLCB0aGUgcmVxdWVzdCBjb21lcyBkaXJlY3RseSBmcm9tIGEgdXNlciBhY3Rpb24gKG5vdCBhdXRvbWF0aWMgcHJvY2VkdXJlcykuXG4gICAqL1xuICBzeW5jaHJvbml6ZShtYW51YWxDb25maXJtYXRpb24/OiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpOiB2b2lkID0+IHtcbiAgICAgIGlmICghdGhpcy5pc0FsbG93ZWQoKSB8fCB0aGlzLnN5bmNocm9uaXppbmcpIHJldHVybiByZXNvbHZlKCk7XG4gICAgICB0aGlzLnN5bmNocm9uaXppbmcgPSB0cnVlO1xuICAgICAgdGhpcy5lcnJvckluTGFzdFN5bmMgPSBmYWxzZTtcbiAgICAgIHRoaXMucmVxdWlyZXNNYW51YWxDb25maXJtYXRpb24gPSBmYWxzZTtcbiAgICAgIC8vIGxvYWQgdGhlIGxhc3RTeW5jQXQgaW5mb3JtYXRpb25cbiAgICAgIHRoaXMubG9hZExhc3RTeW5jQXQoKS50aGVuKFxuICAgICAgICAoKTogUHJvbWlzZTx2b2lkPiA9PlxuICAgICAgICAgIC8vIHRyeSB0byBydW4gYWxsIHRoZSBwZW5kaW5nIEFQSSByZXF1ZXN0cyBpbiB0aGUgcXVldWUsIGkuZS4gdXBsb2FkaW5nIHRoZSBvZmZsaW5lIHJlc291cmNlcyBjaGFuZ2VkXG4gICAgICAgICAgdGhpcy5ydW5RdWV1ZUFQSVJlcXVlc3RzKClcbiAgICAgICAgICAgIC50aGVuKCgpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgLy8gc2V0IHRoaXMgbW9tZW50IGluIHRpbWU6IGlmIGFueXRoaW5nIGhhcHBlbmVkIGJlZm9yZSB0aGUgZW5kIG9mIHRoZSBzeW5jLCB3ZSBkb24ndCBsb3NlIGZyZXNoIGRhdGFcbiAgICAgICAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgLy8gcHJlcGFyZSBhIGZpcnN0IFwic2hvcnRcIiBEZWx0YSByZXF1ZXN0LCB0byBzZWUgaWYgdGhlcmUgaXMgYSBsb3Qgb2YgZGF0YSB0byBwcm9jZXNzXG4gICAgICAgICAgICAgIGNvbnN0IHBhcmFtczogYW55ID0geyBsaW1pdDogTlVNX0VMRU1FTlRTX1dJVEhPVVRfTUFOVUFMX1NZTkMgfTtcbiAgICAgICAgICAgICAgaWYgKHRoaXMubGFzdFN5bmNBdCkgcGFyYW1zLnNpbmNlID0gdGhpcy5sYXN0U3luY0F0O1xuICAgICAgICAgICAgICB0aGlzLl9BUElcbiAgICAgICAgICAgICAgICAuZ2V0UmVzb3VyY2UodGhpcy50ZWFtSWQgPyBgdGVhbXMvJHt0aGlzLnRlYW1JZH0vZGVsdGFgIDogJ2RlbHRhJywgeyBwYXJhbXMgfSlcbiAgICAgICAgICAgICAgICAudGhlbigoZGVsdGE6IERlbHRhKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgICAgICAvLyBkZWNpZGUgaWYgdG8gcHJvY2VlZCB3aXRoIHRoZSBzeW5jOiBpbiBjYXNlIHRoZXJlIGlzIGFub3RoZXIgcGFnZSwgaXQgcmVxdWlyZXMgYSBtYW51YWwgY29uZmlybWF0aW9uXG4gICAgICAgICAgICAgICAgICBpZiAoZGVsdGEubmV4dCAmJiAhbWFudWFsQ29uZmlybWF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVxdWlyZXNNYW51YWxDb25maXJtYXRpb24gPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnN5bmNocm9uaXppbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIC8vIHNhdmUgdGhlIHJlY29yZHMgaW4gdGhlIGRlbHRhIGFuZCByZXF1ZXN0IHBvc3NpYmxlIG5ldyBwYWdlc1xuICAgICAgICAgICAgICAgICAgdGhpcy5zeW5jRGVsdGFSZWNvcmRzKGRlbHRhLCAoKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmVycm9ySW5MYXN0U3luYykge1xuICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3luY2hyb25pemluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAvLyBhbGwgdGhlIHJlc291cmNlcyBhcmUgc3VjY2VzZnVsbHkgaW4gc3luY1xuICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVzb3VyY2VzLmZvckVhY2gocmVzb3VyY2UgPT4gKHRoaXMuY2FjaGVhYmxlUmVzb3VyY2VzW3Jlc291cmNlXS5zeW5jaHJvbml6aW5nID0gZmFsc2UpKTtcbiAgICAgICAgICAgICAgICAgICAgICAvLyB1cGRhdGUgdGhlIHRpbWVzdGFtcCBvZiBsYXN0IHN5bmNcbiAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNhdmVMYXN0U3luY0F0KG5vdylcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKCgpOiB2b2lkID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zeW5jaHJvbml6aW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAuY2F0Y2goKCk6IHZvaWQgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB3ZSBjb3VsZG4ndCBzYXZlIHRoZSBsYXN0IHN5bmMgaW5mb1xuICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmVycm9ySW5MYXN0U3luYyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3luY2hyb25pemluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5jYXRjaCgoKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgICAgICAvLyB3ZSBjb3VsZG4ndCBhY3F1aXJlIG5ldyBpbmZvcm1hdGlvbiAoRGVsdGEpXG4gICAgICAgICAgICAgICAgICB0aGlzLmVycm9ySW5MYXN0U3luYyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICB0aGlzLnN5bmNocm9uaXppbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgIHJlamVjdCgpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5jYXRjaCgoKTogdm9pZCA9PiB7XG4gICAgICAgICAgICAgIC8vIHdlIHN0b3AsIHNpbmNlIHdlIGRvbid0IHdhbnQgYmFja2VuZCBkYXRhIHRvIG92ZXJyaWRlIGxvY2FsIGluZm8gbm90IHlldCB1cGxvYWRlZFxuICAgICAgICAgICAgICB0aGlzLmVycm9ySW5MYXN0U3luYyA9IHRydWU7XG4gICAgICAgICAgICAgIHRoaXMuc3luY2hyb25pemluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICByZWplY3QoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICApO1xuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBGb3JjZSBhIGZ1bGwgc3luY2hyb25pc2F0aW9uLlxuICAgKi9cbiAgZm9yY2VGdWxsU3luYygpOiB2b2lkIHtcbiAgICB0aGlzLl9zdG9yYWdlLmNsZWFyKCkudGhlbigoKTogUHJvbWlzZTx2b2lkPiA9PiB0aGlzLnN5bmNocm9uaXplKHRydWUpKTtcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBkZXNjcmlwdGlvbiBvZiBhbiBBUEkgcmVxdWVzdCB0byBhIHJlc291cmNlLCB0byB1c2Ugd2l0aCBgSURFQUFXU0FQSWAuXG4gKiBVc2VkIGZvciBxdWV1ZXMgb2YgcmVxdWVzdHMgKFVQTE9BRCkuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQVBJUmVxdWVzdCB7XG4gIC8qKlxuICAgKiBSZXNvdXJjZSBwYXRoIChlLmcuIGB1c2Vyc2Agb3IgYHRlYW1zLyR7dGVhbUlkfS91c2Vyc2ApLlxuICAgKi9cbiAgcmVzb3VyY2U6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBpZCB0byBpZGVudGlmeSBhIHNwZWNpZmljIGVsZW1lbnQgb2YgdGhlIHJlc291cmNlLlxuICAgKi9cbiAgcmVzb3VyY2VJZDogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIEFQSSByZXF1ZXN0IG1ldGhvZCAoZS5nLiBQT1NULCBQVVQsIFBBVENIKS5cbiAgICovXG4gIG1ldGhvZDogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGJvZHkgb2YgdGhlIHJlcXVlc3QuXG4gICAqL1xuICBib2R5OiBhbnk7XG4gIC8qKlxuICAgKiBBIGRlc2NyaXB0aW9uIHRvIHNob3cgZm9yIHRoZSByZXF1ZXN0LlxuICAgKi9cbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBJZiBub3QgbnVsbCwgdGhlIHJlcXVlc3QgdHJpZWQgdG8gcnVuIGJ1dCBpdCBlbmNvdW50ZXJlZCB0aGUgZXJyb3IuXG4gICAqL1xuICBlcnJvcj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgYWJzdHJhY3QgY2xhc3MgdG8gaW1wbGVtZW50IGZvciBlYWNoIHJlc291cmNlIHRvIGNhY2hlIG9mZmxpbmUgZnJvbSB0aGUgYmFjay1lbmQgKERPV05MT0FEKS5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIENhY2hlYWJsZVJlc291cmNlIHtcbiAgLyoqXG4gICAqIFRoZSB0ZWFtIG93bmluZyB0aGUgcmVzb3VyY2UuXG4gICAqIElmIG51bGwsIHRoZSBwcm9qZWN0IGlzbid0IHRlYW1zLWJhc2VkLlxuICAgKi9cbiAgdGVhbUlkOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgaWRlbnRpZmllciBvZiB0aGUgcmVzb3VyY2UuXG4gICAqL1xuICByZXNvdXJjZTogRGVsdGFSZXNvdXJjZXMgfCBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgcmVzb3VyY2UgZGVzY3JpcHRpb24gKHRyYW5zbGF0ZWQpIGZvciB0aGUgVUkuXG4gICAqL1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAvKipcbiAgICogUnVudGltZSBhdHRyaWJ1dGUgdG8ga25vdyBpZiB0aGUgcmVzb3VyY2UgaXMgc3luY2hyb25pemluZy5cbiAgICovXG4gIHN5bmNocm9uaXppbmc6IGJvb2xlYW47XG4gIC8qKlxuICAgKiBUcnVlIGlmIG9uZSBvZiB0aGUgZWxlbWVudHMgZmFpbGVkIHRoZSBleGVjdXRpb24uXG4gICAqL1xuICBlcnJvcjogYm9vbGVhbjtcblxuICBjb25zdHJ1Y3RvcihyZXNvdXJjZTogc3RyaW5nLCBkZXNjcmlwdGlvbjogc3RyaW5nKSB7XG4gICAgdGhpcy5yZXNvdXJjZSA9IHJlc291cmNlO1xuICAgIHRoaXMuZGVzY3JpcHRpb24gPSBkZXNjcmlwdGlvbjtcbiAgICB0aGlzLnN5bmNocm9uaXppbmcgPSBmYWxzZTtcbiAgICB0aGlzLmVycm9yID0gZmFsc2U7XG4gICAgLy8gbG9hZGVkIGF0IHJ1bnRpbWVcbiAgICB0aGlzLnRlYW1JZCA9IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogSG93IHRvIGJ1aWxkIHRoZSByZWxhdGl2ZSBVUkwgdG8gdGhlIHJlc291cmNlIChsaXN0KS5cbiAgICogRS5nLiBgdGVhbXMvJHtlbGVtZW50LnRlYW1JZH0vY3VzdG9tZXJzYCBvciBgY3VzdG9tZXJzYC5cbiAgICovXG4gIGFic3RyYWN0IGxpc3RVUkwoZWxlbWVudDogYW55KTogc3RyaW5nO1xuICAvKipcbiAgICogSG93IHRvIGJ1aWxkIHRoZSByZWxhdGl2ZSBVUkwgdG8gdGhlIHJlc291cmNlIGVsZW1lbnQgKGRldGFpbCkuXG4gICAqIEUuZy4gYHRlYW1zLyR7ZWxlbWVudC50ZWFtSWR9L2N1c3RvbWVycy8ke2VsZW1lbnQuY3VzdG9tZXJJZH1gIG9yIGBjdXN0b21lcnMvJHtlbGVtZW50LmN1c3RvbWVySWR9YC5cbiAgICovXG4gIGFic3RyYWN0IGVsZW1lbnRVUkwoZWxlbWVudDogYW55KTogc3RyaW5nO1xuICAvKipcbiAgICogSG93IHRvIHVuaXF1ZWx5IGlkZW50aWZ5IGFuIGVsZW1lbnQgaW4gdGhlIGxpc3QgKGJ5IGl0cyBpZHMpLlxuICAgKiBFLmcuIGByZXR1cm4gbGlzdC5maW5kSW5kZXgoeCA9PiB4LmN1c3RvbWVySWQgPT09IGVsZW1lbnQuY3VzdG9tZXJJZCk7YFxuICAgKi9cbiAgYWJzdHJhY3QgZmluZEluZGV4SW5MaXN0KGxpc3Q6IGFueVtdLCBlbGVtZW50OiBhbnkpOiBudW1iZXI7XG4gIC8qKlxuICAgKiBIb3cgdG8ga2VlcCB0aGUgbGlzdCBzb3J0ZWQuXG4gICAqIEUuZy4gYHJldHVybiBhLm5hbWUubG9jYWxlQ29tcGFyZShiLm5hbWUpO2BcbiAgICovXG4gIGFic3RyYWN0IHNvcnQoYTogYW55LCBiOiBhbnkpOiBudW1iZXI7XG59XG4iXX0=