@decaf-ts/transactional-decorators 0.0.22 → 0.1.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 (52) hide show
  1. package/README.md +7 -0
  2. package/dist/transactional-decorators.cjs +544 -0
  3. package/dist/transactional-decorators.esm.cjs +533 -0
  4. package/lib/Transaction.cjs +1 -2
  5. package/lib/constants.cjs +1 -2
  6. package/lib/decorators.cjs +1 -2
  7. package/lib/esm/Transaction.d.ts +86 -0
  8. package/lib/esm/Transaction.js +1 -2
  9. package/lib/esm/constants.d.ts +1 -0
  10. package/lib/esm/constants.js +1 -2
  11. package/lib/esm/decorators.d.ts +19 -0
  12. package/lib/esm/decorators.js +1 -2
  13. package/{dist/types → lib/esm}/index.d.ts +1 -1
  14. package/lib/esm/index.js +2 -3
  15. package/lib/esm/interfaces/TransactionLock.js +1 -2
  16. package/lib/esm/interfaces/index.js +1 -2
  17. package/lib/esm/locks/Lock.js +1 -2
  18. package/lib/esm/locks/SyncronousLock.js +1 -2
  19. package/lib/esm/locks/index.js +1 -2
  20. package/lib/esm/types.js +1 -2
  21. package/lib/esm/utils.js +1 -2
  22. package/lib/index.cjs +2 -3
  23. package/lib/index.d.ts +24 -0
  24. package/lib/interfaces/TransactionLock.cjs +1 -2
  25. package/lib/interfaces/TransactionLock.d.ts +26 -0
  26. package/lib/interfaces/index.cjs +1 -2
  27. package/lib/interfaces/index.d.ts +1 -0
  28. package/lib/locks/Lock.cjs +1 -2
  29. package/lib/locks/Lock.d.ts +24 -0
  30. package/lib/locks/SyncronousLock.cjs +1 -2
  31. package/lib/locks/SyncronousLock.d.ts +40 -0
  32. package/lib/locks/index.cjs +1 -2
  33. package/lib/locks/index.d.ts +2 -0
  34. package/lib/types.cjs +1 -2
  35. package/lib/types.d.ts +7 -0
  36. package/lib/utils.cjs +1 -2
  37. package/lib/utils.d.ts +1 -0
  38. package/package.json +22 -34
  39. package/dist/esm/transactional-decorators.js +0 -2
  40. package/dist/esm/transactional-decorators.js.LICENSE.txt +0 -14
  41. package/dist/transactional-decorators.js +0 -2
  42. package/dist/transactional-decorators.js.LICENSE.txt +0 -14
  43. /package/{dist/types → lib}/Transaction.d.ts +0 -0
  44. /package/{dist/types → lib}/constants.d.ts +0 -0
  45. /package/{dist/types → lib}/decorators.d.ts +0 -0
  46. /package/{dist/types → lib/esm}/interfaces/TransactionLock.d.ts +0 -0
  47. /package/{dist/types → lib/esm}/interfaces/index.d.ts +0 -0
  48. /package/{dist/types → lib/esm}/locks/Lock.d.ts +0 -0
  49. /package/{dist/types → lib/esm}/locks/SyncronousLock.d.ts +0 -0
  50. /package/{dist/types → lib/esm}/locks/index.d.ts +0 -0
  51. /package/{dist/types → lib/esm}/types.d.ts +0 -0
  52. /package/{dist/types → lib/esm}/utils.d.ts +0 -0
package/README.md CHANGED
@@ -37,6 +37,13 @@ Documentation available [here](https://decaf-ts.github.io/transactional-decorato
37
37
 
38
38
  ### Description
39
39
 
40
+ Standalone module, exposes a simple implementation to handle concurrency:
41
+ - Simple yet powerful locking;
42
+ - decorate methods as `@transactional()` for control;
43
+ - decorate classes as `@Transactional()`, enabling Instance proxying and keeping transactions across different classes/method calls (grouping several calls in a sing transaction)l
44
+ - Customizable Transaction Lock;
45
+ - Seamless integration with `db-decorators`;
46
+
40
47
  ### How to Use
41
48
 
42
49
  - [Initial Setup](./tutorials/For%20Developers.md#_initial-setup_)
@@ -0,0 +1,544 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@decaf-ts/reflection'), require('@decaf-ts/db-decorators')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@decaf-ts/reflection', '@decaf-ts/db-decorators'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["transactional-decorators"] = {}, global.reflection, global.dbDecorators));
5
+ })(this, (function (exports, reflection, dbDecorators) { 'use strict';
6
+
7
+ /**
8
+ * @summary Simple Promise based Lock class
9
+ *
10
+ * @class Lock
11
+ * @category Transactions
12
+ */
13
+ class Lock {
14
+ constructor() {
15
+ this.queue = [];
16
+ this.locked = false;
17
+ }
18
+ /**
19
+ * @summary executes when lock is available
20
+ * @param {Function} func
21
+ */
22
+ async execute(func) {
23
+ await this.acquire();
24
+ let result;
25
+ try {
26
+ result = await Promise.resolve(func());
27
+ }
28
+ catch (e) {
29
+ this.release();
30
+ throw e;
31
+ }
32
+ this.release();
33
+ return result;
34
+ }
35
+ /**
36
+ * @summary waits to acquire the lock
37
+ * @param {string} [issuer]
38
+ */
39
+ async acquire() {
40
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
41
+ const self = this;
42
+ if (self.locked) {
43
+ return new Promise((resolve) => self.queue.push(resolve));
44
+ }
45
+ else {
46
+ self.locked = true;
47
+ return Promise.resolve();
48
+ }
49
+ }
50
+ /**
51
+ * @summary releases the lock
52
+ */
53
+ release() {
54
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
55
+ const self = this;
56
+ const next = self.queue.shift();
57
+ if (next) {
58
+ if (typeof globalThis.window === "undefined")
59
+ globalThis.process.nextTick(next); // if you are on node
60
+ else
61
+ setTimeout(next, 0); // if you are in the browser
62
+ }
63
+ else {
64
+ self.locked = false;
65
+ }
66
+ }
67
+ }
68
+
69
+ class SyncronousLock {
70
+ constructor(counter = 1, onBegin, onEnd) {
71
+ this.currentTransaction = undefined;
72
+ this.lock = new Lock();
73
+ this.counter = counter;
74
+ this.pendingTransactions = [];
75
+ this.onBegin = onBegin;
76
+ this.onEnd = onEnd;
77
+ }
78
+ /**
79
+ * @summary Submits a transaction to be processed
80
+ * @param {Transaction} transaction
81
+ */
82
+ submit(transaction) {
83
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
84
+ const self = this;
85
+ self.lock.acquire().then(() => {
86
+ if (self.currentTransaction &&
87
+ self.currentTransaction.id === transaction.id) {
88
+ self.lock.release();
89
+ return transaction.fire();
90
+ }
91
+ if (self.counter > 0) {
92
+ self.counter--;
93
+ self.lock.release();
94
+ return self.fireTransaction(transaction);
95
+ }
96
+ else {
97
+ self.pendingTransactions.push(transaction);
98
+ self.lock.release();
99
+ }
100
+ });
101
+ }
102
+ /**
103
+ * @summary Executes a transaction
104
+ *
105
+ * @param {Transaction} transaction
106
+ * @private
107
+ */
108
+ fireTransaction(transaction) {
109
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
110
+ const self = this;
111
+ self.lock.acquire().then(() => {
112
+ self.currentTransaction = transaction;
113
+ self.lock.release();
114
+ if (self.onBegin)
115
+ self.onBegin().then(() => {
116
+ // all.call(
117
+ // self,
118
+ // `Firing transaction {0}. {1} remaining...`,
119
+ // transaction.id,
120
+ // this.pendingTransactions.length,
121
+ // );
122
+ transaction.fire();
123
+ });
124
+ else {
125
+ // all.call(
126
+ // self,
127
+ // `Firing transaction {0}. {1} remaining...`,
128
+ // transaction.id,
129
+ // this.pendingTransactions.length,
130
+ // );
131
+ transaction.fire();
132
+ }
133
+ });
134
+ }
135
+ /**
136
+ * @summary Releases The lock after the conclusion of a transaction
137
+ */
138
+ async release(err) {
139
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
140
+ const self = this;
141
+ return new Promise((resolve) => {
142
+ self.lock.acquire().then(() => {
143
+ if (!self.currentTransaction)
144
+ console.warn("Trying to release an unexisting transaction. should never happen...");
145
+ // debug.call(
146
+ // self,
147
+ // "Releasing transaction: {0}",
148
+ // self.currentTransaction?.toString(true, true),
149
+ // );
150
+ self.currentTransaction = undefined;
151
+ self.lock.release();
152
+ const afterConclusionCB = () => {
153
+ self.lock.acquire().then(() => {
154
+ if (self.pendingTransactions.length > 0) {
155
+ const transaction = self.pendingTransactions.shift();
156
+ const cb = () => self.fireTransaction(transaction);
157
+ //
158
+ // all(
159
+ // `Releasing Transaction Lock on transaction {0}`,
160
+ // transaction.id,
161
+ // );
162
+ if (typeof globalThis.window ===
163
+ "undefined")
164
+ globalThis.process.nextTick(cb); // if you are on node
165
+ else
166
+ setTimeout(cb, 0); // if you are in the browser
167
+ }
168
+ else {
169
+ self.counter++;
170
+ }
171
+ self.lock.release();
172
+ resolve();
173
+ });
174
+ };
175
+ if (self.onEnd)
176
+ self.onEnd(err).then(() => afterConclusionCB());
177
+ else
178
+ afterConclusionCB();
179
+ });
180
+ });
181
+ }
182
+ }
183
+
184
+ const TransactionalKeys = {
185
+ REFLECT: "model.transactional.",
186
+ TRANSACTIONAL: "transactional",
187
+ };
188
+
189
+ function getObjectName(obj) {
190
+ if (!obj)
191
+ return;
192
+ if (typeof obj === "string")
193
+ return obj;
194
+ if (obj.constructor &&
195
+ obj.constructor.name &&
196
+ ["Function", "Object"].indexOf(obj.constructor.name) === -1)
197
+ return obj.constructor.name;
198
+ if (typeof obj === "function" && obj.name)
199
+ return obj.name;
200
+ return obj.toString();
201
+ }
202
+
203
+ /**
204
+ * @summary Transaction Class
205
+ *
206
+ * @param {string} source
207
+ * @param {string} [method]
208
+ * @param {function(): void} [action]
209
+ * @param {any[]} [metadata]
210
+ *
211
+ * @class Transaction
212
+ *
213
+ * @category Transactions
214
+ */
215
+ class Transaction {
216
+ constructor(source, method, action, metadata) {
217
+ this.id = Date.now();
218
+ this.action = action;
219
+ this.method = method;
220
+ this.log = [[this.id, source, method].join(" | ")];
221
+ this.source = source;
222
+ this.metadata = metadata;
223
+ }
224
+ /**
225
+ * @summary Pushes a transaction to que queue and waits its resolution
226
+ *
227
+ * @param {any} issuer any class. will be used as this when calling the callbackMethod
228
+ * @param {Function} callbackMethod callback function containing the transaction. will be called with the issuear as this
229
+ * @param {any[]} args arguments to pass to the method. Last one must be the callback
230
+ */
231
+ static push(issuer, callbackMethod, ...args) {
232
+ const callback = args.pop();
233
+ if (!callback || typeof callback !== "function")
234
+ throw new Error("Missing callback");
235
+ const cb = (err, ...args) => {
236
+ Transaction.getLock()
237
+ .release(err)
238
+ .then(() => callback(err, ...args));
239
+ };
240
+ const transaction = new Transaction(issuer.constructor.name, callbackMethod.name ? getObjectName(callbackMethod) : "Anonymous", () => {
241
+ return callbackMethod.call(transaction.bindToTransaction(issuer), ...args, cb);
242
+ });
243
+ Transaction.getLock().submit(transaction);
244
+ }
245
+ /**
246
+ * @summary Sets the lock to be used
247
+ * @param lock
248
+ */
249
+ static setLock(lock) {
250
+ this.lock = lock;
251
+ }
252
+ /**
253
+ * @summary gets the lock
254
+ */
255
+ static getLock() {
256
+ if (!this.lock)
257
+ this.lock = new SyncronousLock();
258
+ return this.lock;
259
+ }
260
+ /**
261
+ * @summary submits a transaction
262
+ * @param {Transaction} transaction
263
+ */
264
+ static submit(transaction) {
265
+ Transaction.getLock().submit(transaction);
266
+ }
267
+ /**
268
+ * @summary releases the lock
269
+ * @param {Err} err
270
+ */
271
+ static async release(err) {
272
+ return Transaction.getLock().release(err);
273
+ }
274
+ /**
275
+ * @summary retrieves the metadata for the transaction
276
+ */
277
+ getMetadata() {
278
+ return this.metadata ? [...this.metadata] : undefined;
279
+ }
280
+ /**
281
+ * @summary Binds a new operation to the current transaction
282
+ * @param {Transaction} nextTransaction
283
+ */
284
+ bindTransaction(nextTransaction) {
285
+ // all(`Binding the {0} to {1}`, nextTransaction, this);
286
+ this.log.push(...nextTransaction.log);
287
+ nextTransaction.bindTransaction = this.bindToTransaction.bind(this);
288
+ nextTransaction.bindToTransaction = this.bindToTransaction.bind(this);
289
+ this.action = nextTransaction.action;
290
+ }
291
+ /**
292
+ * @summary Binds the Transactional Decorated Object to the transaction
293
+ * @description by having all {@link transactional} decorated
294
+ * methods always pass the current Transaction as an argument
295
+ *
296
+ * @param {any} obj
297
+ * @return {any} the bound {@param obj}
298
+ */
299
+ bindToTransaction(obj) {
300
+ const transactionalMethods = dbDecorators.getAllPropertyDecoratorsRecursive(obj, undefined, TransactionalKeys.REFLECT);
301
+ if (!transactionalMethods)
302
+ return obj;
303
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
304
+ const self = this;
305
+ const boundObj = reflection.Reflection.getAllProperties(obj).reduce((accum, k) => {
306
+ if (Object.keys(transactionalMethods).indexOf(k) !== -1 &&
307
+ transactionalMethods[k].find((o) => o.key === TransactionalKeys.TRANSACTIONAL))
308
+ accum[k] = (...args) => obj[k].call(obj.__originalObj || obj, self, ...args);
309
+ else if (k === "clazz" || k === "constructor")
310
+ accum[k] = obj[k];
311
+ else if (typeof obj[k] === "function")
312
+ accum[k] = obj[k].bind(obj.__originalObj || obj);
313
+ else if (typeof obj[k] === "object" && obj[k].constructor) {
314
+ const decs = reflection.Reflection.getClassDecorators(TransactionalKeys.REFLECT, obj[k]);
315
+ if (decs.find((e) => e.key === TransactionalKeys.TRANSACTIONAL))
316
+ accum[k] = self.bindToTransaction(obj[k]);
317
+ else
318
+ accum[k] = obj[k];
319
+ }
320
+ else
321
+ accum[k] = obj[k];
322
+ return accum;
323
+ }, {});
324
+ boundObj[dbDecorators.DBKeys.ORIGINAL] = obj[dbDecorators.DBKeys.ORIGINAL] || obj;
325
+ boundObj.toString = () => getObjectName(boundObj[dbDecorators.DBKeys.ORIGINAL]) +
326
+ " proxy for transaction " +
327
+ this.id;
328
+ return boundObj;
329
+ }
330
+ /**
331
+ * @summary Fires the Transaction
332
+ */
333
+ fire() {
334
+ if (!this.action)
335
+ throw new Error(`Missing the method`);
336
+ return this.action();
337
+ }
338
+ /**
339
+ * @summary toString override
340
+ * @param {boolean} [withId] defaults to true
341
+ * @param {boolean} [withLog] defaults to true
342
+ */
343
+ toString(withId = true, withLog = false) {
344
+ return `${withId ? `[${this.id}]` : ""}[Transaction][${this.source}.${this.method}${withLog ? `]\nTransaction Log:\n${this.log.join("\n")}` : "]"}`;
345
+ }
346
+ /**
347
+ * @summary gets the transactions reflections key
348
+ * @function getRepoKey
349
+ * @param {string} key
350
+ * @memberOf module:db-decorators.Transactions
351
+ * */
352
+ static key(key) {
353
+ return TransactionalKeys.REFLECT + key;
354
+ }
355
+ }
356
+
357
+ /**
358
+ * @summary Sets a class Async method as transactional
359
+ *
360
+ * @param {any[]} [data] option metadata available to the {@link TransactionLock}
361
+ *
362
+ * @function transactional
363
+ *
364
+ * @memberOf module:db-decorators.Decorators.transactions
365
+ */
366
+ function transactional(...data) {
367
+ return function (target, propertyKey, descriptor) {
368
+ if (!descriptor)
369
+ throw new dbDecorators.InternalError("Missing descriptor. Should be impossible");
370
+ reflection.metadata(Transaction.key(TransactionalKeys.TRANSACTIONAL), data)(target, propertyKey);
371
+ const originalMethod = descriptor.value;
372
+ const methodWrapper = function (...args) {
373
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
374
+ const self = this;
375
+ return new Promise((resolve, reject) => {
376
+ const cb = (err, result) => {
377
+ Transaction.release(err).then(() => {
378
+ if (err)
379
+ return reject(err);
380
+ resolve(result);
381
+ });
382
+ };
383
+ let transaction = args.shift();
384
+ if (transaction instanceof Transaction) {
385
+ const updatedTransaction = new Transaction(this.constructor.name, propertyKey, async () => {
386
+ originalMethod
387
+ .call(updatedTransaction.bindToTransaction(self), ...args)
388
+ .then(resolve)
389
+ .catch(reject);
390
+ }, data.length ? data : undefined);
391
+ transaction.bindTransaction(updatedTransaction);
392
+ transaction.fire();
393
+ }
394
+ else {
395
+ args.unshift(transaction);
396
+ transaction = new Transaction(this.constructor.name, propertyKey, () => {
397
+ originalMethod
398
+ .call(transaction.bindToTransaction(self), ...args)
399
+ .then((result) => cb(undefined, result))
400
+ .catch(cb);
401
+ }, data.length ? data : undefined);
402
+ Transaction.submit(transaction);
403
+ }
404
+ });
405
+ };
406
+ Object.defineProperty(methodWrapper, "name", {
407
+ value: propertyKey,
408
+ });
409
+ descriptor.value = methodWrapper;
410
+ };
411
+ }
412
+ //
413
+ // /**
414
+ // * @summary Sets a class Async method as transactional
415
+ // *
416
+ // * @param {any[]} [metadata] option metadata available to the {@link TransactionLock}
417
+ // *
418
+ // * @function transactionalAsync
419
+ // *
420
+ // * @memberOf module:db-decorators.Decorators.transactions
421
+ // */
422
+ // export function transactionalAsync(...metadata: any[]) {
423
+ // return function (
424
+ // target: any,
425
+ // propertyKey: string,
426
+ // descriptor: PropertyDescriptor,
427
+ // ) {
428
+ // metadasta(getTransactionalKey(TransactionalKeys.TRANSACTIONAL))
429
+ // Reflect.defineMetadata(
430
+ // ,
431
+ // {
432
+ // type: "async",
433
+ // metadata: metadata.length ? metadata : undefined,
434
+ // } as TransactionalMetadata,
435
+ // target,
436
+ // propertyKey,
437
+ // );
438
+ //
439
+ // const originalMethod = descriptor.value;
440
+ //
441
+ // const methodWrapper = function (this: any, ...args: any[]) {
442
+ // const callback: Callback = args.pop();
443
+ // if (!callback || typeof callback !== "function")
444
+ // throw new CriticalError(`Missing Callback`);
445
+ //
446
+ // const cb = (err?: Err, ...args: any[]) => {
447
+ // Transaction.release(err).then((_) => callback(err, ...args));
448
+ // };
449
+ //
450
+ // const self = this;
451
+ //
452
+ // let transaction = args.shift();
453
+ // if (transaction instanceof Transaction) {
454
+ // const updatedTransaction: Transaction = new Transaction(
455
+ // this.constructor.name,
456
+ // propertyKey,
457
+ // () => {
458
+ // try {
459
+ // return originalMethod.call(
460
+ // updatedTransaction.bindToTransaction(self),
461
+ // ...args,
462
+ // callback,
463
+ // );
464
+ // } catch (e: any) {
465
+ // return callback(e);
466
+ // }
467
+ // },
468
+ // metadata.length ? metadata : undefined,
469
+ // );
470
+ //
471
+ // transaction.bindTransaction(updatedTransaction);
472
+ // transaction.fire();
473
+ // } else {
474
+ // args.unshift(transaction);
475
+ // transaction = undefined;
476
+ // transaction = new Transaction(
477
+ // this.constructor.name,
478
+ // propertyKey,
479
+ // () => {
480
+ // try {
481
+ // return originalMethod.call(
482
+ // transaction.bindToTransaction(self),
483
+ // ...args,
484
+ // cb,
485
+ // );
486
+ // } catch (e: any) {
487
+ // return cb(e);
488
+ // }
489
+ // },
490
+ // metadata.length ? metadata : undefined,
491
+ // );
492
+ // Transaction.submit(transaction);
493
+ // }
494
+ // };
495
+ //
496
+ // Object.defineProperty(methodWrapper, "name", {
497
+ // value: propertyKey,
498
+ // });
499
+ // descriptor.value = methodWrapper;
500
+ // };
501
+ // }
502
+ /**
503
+ * @summary Util function to wrap super calls with the transaction when the super's method is also transactional
504
+ *
505
+ * @param {Function} method the super method (must be bound to the proper this), eg: super.create.bind(this)
506
+ * @param {any[]} args the arguments to call the method with
507
+ *
508
+ * @memberOf module:db-decorators.Transaction
509
+ */
510
+ function transactionalSuperCall(method, ...args) {
511
+ const lock = Transaction.getLock();
512
+ const currentTransaction = lock.currentTransaction;
513
+ return method(currentTransaction, ...args);
514
+ }
515
+
516
+ /**
517
+ * @summary Module summary
518
+ * @description Module description
519
+ * @module ts-workspace
520
+ */
521
+ /**
522
+ * @summary Namespace summary
523
+ * @description Namespace description
524
+ * @namespace Namespace
525
+ * @memberOf module:ts-workspace
526
+ */
527
+ /**
528
+ * @summary stores the current package version
529
+ * @description this is how you should document a constant
530
+ * @const VERSION
531
+ * @memberOf module:ts-workspace
532
+ */
533
+ const VERSION = "0.1.1";
534
+
535
+ exports.Lock = Lock;
536
+ exports.SyncronousLock = SyncronousLock;
537
+ exports.Transaction = Transaction;
538
+ exports.TransactionalKeys = TransactionalKeys;
539
+ exports.VERSION = VERSION;
540
+ exports.transactional = transactional;
541
+ exports.transactionalSuperCall = transactionalSuperCall;
542
+
543
+ }));
544
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNhY3Rpb25hbC1kZWNvcmF0b3JzLmNqcyIsInNvdXJjZXMiOlsiLi4vc3JjL2xvY2tzL0xvY2sudHMiLCIuLi9zcmMvbG9ja3MvU3luY3Jvbm91c0xvY2sudHMiLCIuLi9zcmMvY29uc3RhbnRzLnRzIiwiLi4vc3JjL3V0aWxzLnRzIiwiLi4vc3JjL1RyYW5zYWN0aW9uLnRzIiwiLi4vc3JjL2RlY29yYXRvcnMudHMiLCIuLi9zcmMvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTG9ja0NhbGxhYmxlIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5cbi8qKlxuICogQHN1bW1hcnkgU2ltcGxlIFByb21pc2UgYmFzZWQgTG9jayBjbGFzc1xuICpcbiAqIEBjbGFzcyBMb2NrXG4gKiBAY2F0ZWdvcnkgVHJhbnNhY3Rpb25zXG4gKi9cbmV4cG9ydCBjbGFzcyBMb2NrIHtcbiAgcHJpdmF0ZSBxdWV1ZTogTG9ja0NhbGxhYmxlW10gPSBbXTtcbiAgcHJpdmF0ZSBsb2NrZWQgPSBmYWxzZTtcblxuICAvKipcbiAgICogQHN1bW1hcnkgZXhlY3V0ZXMgd2hlbiBsb2NrIGlzIGF2YWlsYWJsZVxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBmdW5jXG4gICAqL1xuICBhc3luYyBleGVjdXRlKGZ1bmM6ICgpID0+IGFueSkge1xuICAgIGF3YWl0IHRoaXMuYWNxdWlyZSgpO1xuICAgIGxldCByZXN1bHQ6IGFueTtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5yZXNvbHZlKGZ1bmMoKSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aGlzLnJlbGVhc2UoKTtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICAgIHRoaXMucmVsZWFzZSgpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgd2FpdHMgdG8gYWNxdWlyZSB0aGUgbG9ja1xuICAgKiBAcGFyYW0ge3N0cmluZ30gW2lzc3Vlcl1cbiAgICovXG4gIGFzeW5jIGFjcXVpcmUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby10aGlzLWFsaWFzXG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgaWYgKHNlbGYubG9ja2VkKSB7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHNlbGYucXVldWUucHVzaChyZXNvbHZlKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNlbGYubG9ja2VkID0gdHJ1ZTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgcmVsZWFzZXMgdGhlIGxvY2tcbiAgICovXG4gIHJlbGVhc2UoKSB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby10aGlzLWFsaWFzXG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgY29uc3QgbmV4dDogTG9ja0NhbGxhYmxlIHwgdW5kZWZpbmVkID0gc2VsZi5xdWV1ZS5zaGlmdCgpO1xuICAgIGlmIChuZXh0KSB7XG4gICAgICBpZiAoXG4gICAgICAgIHR5cGVvZiAoZ2xvYmFsVGhpcyBhcyB1bmtub3duIGFzIHsgd2luZG93OiBhbnkgfSkud2luZG93ID09PSBcInVuZGVmaW5lZFwiXG4gICAgICApXG4gICAgICAgIGdsb2JhbFRoaXMucHJvY2Vzcy5uZXh0VGljayhuZXh0KTsgLy8gaWYgeW91IGFyZSBvbiBub2RlXG4gICAgICBlbHNlIHNldFRpbWVvdXQobmV4dCwgMCk7IC8vIGlmIHlvdSBhcmUgaW4gdGhlIGJyb3dzZXJcbiAgICB9IGVsc2Uge1xuICAgICAgc2VsZi5sb2NrZWQgPSBmYWxzZTtcbiAgICB9XG4gIH1cbn1cbiIsIi8qKlxuICogQHN1bW1hcnkgU2ltcGxlIFN5bmNocm9ub3VzIExvY2sgaW1wbGVtZW50YXRpb25cbiAqIEBkZXNjcmlwdGlvbiBmb3IgdHJhbnNhY3Rpb24gbWFuYWdlbWVudFxuICogYWRhcHRlZCBmcm9tIHtAbGluayBodHRwczovL3d3dy50YWxraW5naGlnaHRlY2guY29tL2VuL2NyZWF0aW5nLWEtanMtbG9jay1mb3ItYS1yZXNvdXJjZS99XG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IFtjb3VudGVyXSB0aGUgbnVtYmVyIG9mIHNpbXVsdGFuZW91cyB0cmFuc2FjdGlvbnMgYWxsb3dlZC4gZGVmYXVsdHMgdG8gMVxuICogQHBhcmFtIHtGdW5jdGlvbn0gW29uQmVnaW5dIHRvIGJlIGNhbGxlZCBhdCB0aGUgc3RhcnQgb2YgdGhlIHRyYW5zYWN0aW9uXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBbb25FbmRdIHRvIGJlIGNhbGxlZCBhdCB0aGUgY29uY2x1c2lvbiBvZiB0aGUgdHJhbnNhY3Rpb25cbiAqXG4gKiBAY2xhc3MgU3luY3Jvbm91c0xvY2tcbiAqIEBpbXBsZW1lbnRzIFRyYW5zYWN0aW9uTG9ja1xuICpcbiAqIEBjYXRlZ29yeSBUcmFuc2FjdGlvbnNcbiAqLyBpbXBvcnQgeyBUcmFuc2FjdGlvbiB9IGZyb20gXCIuLi9UcmFuc2FjdGlvblwiO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb25Mb2NrIH0gZnJvbSBcIi4uL2ludGVyZmFjZXMvVHJhbnNhY3Rpb25Mb2NrXCI7XG5pbXBvcnQgeyBMb2NrIH0gZnJvbSBcIi4vTG9ja1wiO1xuXG5leHBvcnQgY2xhc3MgU3luY3Jvbm91c0xvY2sgaW1wbGVtZW50cyBUcmFuc2FjdGlvbkxvY2sge1xuICBwcml2YXRlIGNvdW50ZXI6IG51bWJlcjtcbiAgcHJpdmF0ZSBwZW5kaW5nVHJhbnNhY3Rpb25zOiBUcmFuc2FjdGlvbltdO1xuICBjdXJyZW50VHJhbnNhY3Rpb24/OiBUcmFuc2FjdGlvbiA9IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWFkb25seSBvbkJlZ2luPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgcHJpdmF0ZSByZWFkb25seSBvbkVuZD86IChlcnI/OiBFcnJvcikgPT4gUHJvbWlzZTx2b2lkPjtcblxuICBwcml2YXRlIHJlYWRvbmx5IGxvY2sgPSBuZXcgTG9jaygpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGNvdW50ZXI6IG51bWJlciA9IDEsXG4gICAgb25CZWdpbj86ICgpID0+IFByb21pc2U8dm9pZD4sXG4gICAgb25FbmQ/OiAoZXJyPzogRXJyb3IpID0+IFByb21pc2U8dm9pZD4sXG4gICkge1xuICAgIHRoaXMuY291bnRlciA9IGNvdW50ZXI7XG4gICAgdGhpcy5wZW5kaW5nVHJhbnNhY3Rpb25zID0gW107XG4gICAgdGhpcy5vbkJlZ2luID0gb25CZWdpbjtcbiAgICB0aGlzLm9uRW5kID0gb25FbmQ7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgU3VibWl0cyBhIHRyYW5zYWN0aW9uIHRvIGJlIHByb2Nlc3NlZFxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKi9cbiAgc3VibWl0KHRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbik6IHZvaWQge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdGhpcy1hbGlhc1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgIHNlbGYubG9jay5hY3F1aXJlKCkudGhlbigoKSA9PiB7XG4gICAgICBpZiAoXG4gICAgICAgIHNlbGYuY3VycmVudFRyYW5zYWN0aW9uICYmXG4gICAgICAgIHNlbGYuY3VycmVudFRyYW5zYWN0aW9uLmlkID09PSB0cmFuc2FjdGlvbi5pZFxuICAgICAgKSB7XG4gICAgICAgIHNlbGYubG9jay5yZWxlYXNlKCk7XG4gICAgICAgIHJldHVybiB0cmFuc2FjdGlvbi5maXJlKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzZWxmLmNvdW50ZXIgPiAwKSB7XG4gICAgICAgIHNlbGYuY291bnRlci0tO1xuICAgICAgICBzZWxmLmxvY2sucmVsZWFzZSgpO1xuICAgICAgICByZXR1cm4gc2VsZi5maXJlVHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2VsZi5wZW5kaW5nVHJhbnNhY3Rpb25zLnB1c2godHJhbnNhY3Rpb24pO1xuICAgICAgICBzZWxmLmxvY2sucmVsZWFzZSgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IEV4ZWN1dGVzIGEgdHJhbnNhY3Rpb25cbiAgICpcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgZmlyZVRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbikge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdGhpcy1hbGlhc1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgIHNlbGYubG9jay5hY3F1aXJlKCkudGhlbigoKSA9PiB7XG4gICAgICBzZWxmLmN1cnJlbnRUcmFuc2FjdGlvbiA9IHRyYW5zYWN0aW9uO1xuICAgICAgc2VsZi5sb2NrLnJlbGVhc2UoKTtcbiAgICAgIGlmIChzZWxmLm9uQmVnaW4pXG4gICAgICAgIHNlbGYub25CZWdpbigpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgIC8vIGFsbC5jYWxsKFxuICAgICAgICAgIC8vICAgc2VsZixcbiAgICAgICAgICAvLyAgIGBGaXJpbmcgdHJhbnNhY3Rpb24gezB9LiB7MX0gcmVtYWluaW5nLi4uYCxcbiAgICAgICAgICAvLyAgIHRyYW5zYWN0aW9uLmlkLFxuICAgICAgICAgIC8vICAgdGhpcy5wZW5kaW5nVHJhbnNhY3Rpb25zLmxlbmd0aCxcbiAgICAgICAgICAvLyApO1xuICAgICAgICAgIHRyYW5zYWN0aW9uLmZpcmUoKTtcbiAgICAgICAgfSk7XG4gICAgICBlbHNlIHtcbiAgICAgICAgLy8gYWxsLmNhbGwoXG4gICAgICAgIC8vICAgc2VsZixcbiAgICAgICAgLy8gICBgRmlyaW5nIHRyYW5zYWN0aW9uIHswfS4gezF9IHJlbWFpbmluZy4uLmAsXG4gICAgICAgIC8vICAgdHJhbnNhY3Rpb24uaWQsXG4gICAgICAgIC8vICAgdGhpcy5wZW5kaW5nVHJhbnNhY3Rpb25zLmxlbmd0aCxcbiAgICAgICAgLy8gKTtcbiAgICAgICAgdHJhbnNhY3Rpb24uZmlyZSgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIC8qKlxuICAgKiBAc3VtbWFyeSBSZWxlYXNlcyBUaGUgbG9jayBhZnRlciB0aGUgY29uY2x1c2lvbiBvZiBhIHRyYW5zYWN0aW9uXG4gICAqL1xuICBhc3luYyByZWxlYXNlKGVycj86IEVycm9yKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby10aGlzLWFsaWFzXG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICBzZWxmLmxvY2suYWNxdWlyZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICBpZiAoIXNlbGYuY3VycmVudFRyYW5zYWN0aW9uKVxuICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgIFwiVHJ5aW5nIHRvIHJlbGVhc2UgYW4gdW5leGlzdGluZyB0cmFuc2FjdGlvbi4gc2hvdWxkIG5ldmVyIGhhcHBlbi4uLlwiLFxuICAgICAgICAgICk7XG4gICAgICAgIC8vIGRlYnVnLmNhbGwoXG4gICAgICAgIC8vICAgc2VsZixcbiAgICAgICAgLy8gICBcIlJlbGVhc2luZyB0cmFuc2FjdGlvbjogezB9XCIsXG4gICAgICAgIC8vICAgc2VsZi5jdXJyZW50VHJhbnNhY3Rpb24/LnRvU3RyaW5nKHRydWUsIHRydWUpLFxuICAgICAgICAvLyApO1xuICAgICAgICBzZWxmLmN1cnJlbnRUcmFuc2FjdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgc2VsZi5sb2NrLnJlbGVhc2UoKTtcblxuICAgICAgICBjb25zdCBhZnRlckNvbmNsdXNpb25DQiA9ICgpID0+IHtcbiAgICAgICAgICBzZWxmLmxvY2suYWNxdWlyZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHNlbGYucGVuZGluZ1RyYW5zYWN0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID1cbiAgICAgICAgICAgICAgICBzZWxmLnBlbmRpbmdUcmFuc2FjdGlvbnMuc2hpZnQoKSBhcyBUcmFuc2FjdGlvbjtcblxuICAgICAgICAgICAgICBjb25zdCBjYiA9ICgpID0+IHNlbGYuZmlyZVRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uKTtcbiAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgLy8gYWxsKFxuICAgICAgICAgICAgICAvLyAgIGBSZWxlYXNpbmcgVHJhbnNhY3Rpb24gTG9jayBvbiB0cmFuc2FjdGlvbiB7MH1gLFxuICAgICAgICAgICAgICAvLyAgIHRyYW5zYWN0aW9uLmlkLFxuICAgICAgICAgICAgICAvLyApO1xuXG4gICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICB0eXBlb2YgKGdsb2JhbFRoaXMgYXMgdW5rbm93biBhcyB7IHdpbmRvdzogYW55IH0pLndpbmRvdyA9PT1cbiAgICAgICAgICAgICAgICBcInVuZGVmaW5lZFwiXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICBnbG9iYWxUaGlzLnByb2Nlc3MubmV4dFRpY2soY2IpOyAvLyBpZiB5b3UgYXJlIG9uIG5vZGVcbiAgICAgICAgICAgICAgZWxzZSBzZXRUaW1lb3V0KGNiLCAwKTsgLy8gaWYgeW91IGFyZSBpbiB0aGUgYnJvd3NlclxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc2VsZi5jb3VudGVyKys7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZWxmLmxvY2sucmVsZWFzZSgpO1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChzZWxmLm9uRW5kKSBzZWxmLm9uRW5kKGVycikudGhlbigoKSA9PiBhZnRlckNvbmNsdXNpb25DQigpKTtcbiAgICAgICAgZWxzZSBhZnRlckNvbmNsdXNpb25DQigpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbn1cbiIsImV4cG9ydCBjb25zdCBUcmFuc2FjdGlvbmFsS2V5czogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgUkVGTEVDVDogXCJtb2RlbC50cmFuc2FjdGlvbmFsLlwiLFxuICBUUkFOU0FDVElPTkFMOiBcInRyYW5zYWN0aW9uYWxcIixcbn07XG4iLCJleHBvcnQgZnVuY3Rpb24gZ2V0T2JqZWN0TmFtZShvYmo6IGFueSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghb2JqKSByZXR1cm47XG4gIGlmICh0eXBlb2Ygb2JqID09PSBcInN0cmluZ1wiKSByZXR1cm4gb2JqO1xuICBpZiAoXG4gICAgb2JqLmNvbnN0cnVjdG9yICYmXG4gICAgb2JqLmNvbnN0cnVjdG9yLm5hbWUgJiZcbiAgICBbXCJGdW5jdGlvblwiLCBcIk9iamVjdFwiXS5pbmRleE9mKG9iai5jb25zdHJ1Y3Rvci5uYW1lKSA9PT0gLTFcbiAgKVxuICAgIHJldHVybiBvYmouY29uc3RydWN0b3IubmFtZTtcbiAgaWYgKHR5cGVvZiBvYmogPT09IFwiZnVuY3Rpb25cIiAmJiBvYmoubmFtZSkgcmV0dXJuIG9iai5uYW1lO1xuICByZXR1cm4gb2JqLnRvU3RyaW5nKCk7XG59XG4iLCJpbXBvcnQgeyBUcmFuc2FjdGlvbkxvY2sgfSBmcm9tIFwiLi9pbnRlcmZhY2VzL1RyYW5zYWN0aW9uTG9ja1wiO1xuaW1wb3J0IHsgUmVmbGVjdGlvbiB9IGZyb20gXCJAZGVjYWYtdHMvcmVmbGVjdGlvblwiO1xuaW1wb3J0IHsgQ2FsbGJhY2sgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHsgU3luY3Jvbm91c0xvY2sgfSBmcm9tIFwiLi9sb2Nrcy9TeW5jcm9ub3VzTG9ja1wiO1xuaW1wb3J0IHtcbiAgREJLZXlzLFxuICBnZXRBbGxQcm9wZXJ0eURlY29yYXRvcnNSZWN1cnNpdmUsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgZ2V0T2JqZWN0TmFtZSB9IGZyb20gXCIuL3V0aWxzXCI7XG5pbXBvcnQgeyBUcmFuc2FjdGlvbmFsS2V5cyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuXG4vKipcbiAqIEBzdW1tYXJ5IFRyYW5zYWN0aW9uIENsYXNzXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVxuICogQHBhcmFtIHtzdHJpbmd9IFttZXRob2RdXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKCk6IHZvaWR9IFthY3Rpb25dXG4gKiBAcGFyYW0ge2FueVtdfSBbbWV0YWRhdGFdXG4gKlxuICogQGNsYXNzIFRyYW5zYWN0aW9uXG4gKlxuICogQGNhdGVnb3J5IFRyYW5zYWN0aW9uc1xuICovXG5leHBvcnQgY2xhc3MgVHJhbnNhY3Rpb24ge1xuICByZWFkb25seSBpZDogbnVtYmVyO1xuICBwcm90ZWN0ZWQgYWN0aW9uPzogKCkgPT4gYW55O1xuICByZWFkb25seSBtZXRob2Q/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHNvdXJjZT86IHN0cmluZztcbiAgcmVhZG9ubHkgbG9nOiBzdHJpbmdbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBtZXRhZGF0YT86IGFueVtdO1xuXG4gIHByaXZhdGUgc3RhdGljIGxvY2s6IFRyYW5zYWN0aW9uTG9jaztcblxuICBjb25zdHJ1Y3RvcihcbiAgICBzb3VyY2U6IHN0cmluZyxcbiAgICBtZXRob2Q/OiBzdHJpbmcsXG4gICAgYWN0aW9uPzogKCkgPT4gYW55LFxuICAgIG1ldGFkYXRhPzogYW55W11cbiAgKSB7XG4gICAgdGhpcy5pZCA9IERhdGUubm93KCk7XG4gICAgdGhpcy5hY3Rpb24gPSBhY3Rpb247XG4gICAgdGhpcy5tZXRob2QgPSBtZXRob2Q7XG4gICAgdGhpcy5sb2cgPSBbW3RoaXMuaWQsIHNvdXJjZSwgbWV0aG9kXS5qb2luKFwiIHwgXCIpXTtcbiAgICB0aGlzLnNvdXJjZSA9IHNvdXJjZTtcbiAgICB0aGlzLm1ldGFkYXRhID0gbWV0YWRhdGE7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgUHVzaGVzIGEgdHJhbnNhY3Rpb24gdG8gcXVlIHF1ZXVlIGFuZCB3YWl0cyBpdHMgcmVzb2x1dGlvblxuICAgKlxuICAgKiBAcGFyYW0ge2FueX0gaXNzdWVyIGFueSBjbGFzcy4gd2lsbCBiZSB1c2VkIGFzIHRoaXMgd2hlbiBjYWxsaW5nIHRoZSBjYWxsYmFja01ldGhvZFxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja01ldGhvZCBjYWxsYmFjayBmdW5jdGlvbiBjb250YWluaW5nIHRoZSB0cmFuc2FjdGlvbi4gd2lsbCBiZSBjYWxsZWQgd2l0aCB0aGUgaXNzdWVhciBhcyB0aGlzXG4gICAqIEBwYXJhbSB7YW55W119IGFyZ3MgYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIG1ldGhvZC4gTGFzdCBvbmUgbXVzdCBiZSB0aGUgY2FsbGJhY2tcbiAgICovXG4gIHN0YXRpYyBwdXNoKFxuICAgIGlzc3VlcjogYW55LFxuICAgIGNhbGxiYWNrTWV0aG9kOiAoLi4uYXJneno6IChhbnkgfCBDYWxsYmFjaylbXSkgPT4gdm9pZCxcbiAgICAuLi5hcmdzOiAoYW55IHwgQ2FsbGJhY2spW11cbiAgKSB7XG4gICAgY29uc3QgY2FsbGJhY2s6IENhbGxiYWNrID0gYXJncy5wb3AoKTtcbiAgICBpZiAoIWNhbGxiYWNrIHx8IHR5cGVvZiBjYWxsYmFjayAhPT0gXCJmdW5jdGlvblwiKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTWlzc2luZyBjYWxsYmFja1wiKTtcbiAgICBjb25zdCBjYiA9IChlcnI/OiBFcnJvciwgLi4uYXJnczogYW55W10pID0+IHtcbiAgICAgIFRyYW5zYWN0aW9uLmdldExvY2soKVxuICAgICAgICAucmVsZWFzZShlcnIpXG4gICAgICAgIC50aGVuKCgpID0+IGNhbGxiYWNrKGVyciwgLi4uYXJncykpO1xuICAgIH07XG4gICAgY29uc3QgdHJhbnNhY3Rpb246IFRyYW5zYWN0aW9uID0gbmV3IFRyYW5zYWN0aW9uKFxuICAgICAgaXNzdWVyLmNvbnN0cnVjdG9yLm5hbWUsXG4gICAgICBjYWxsYmFja01ldGhvZC5uYW1lID8gZ2V0T2JqZWN0TmFtZShjYWxsYmFja01ldGhvZCkgOiBcIkFub255bW91c1wiLFxuICAgICAgKCkgPT4ge1xuICAgICAgICByZXR1cm4gY2FsbGJhY2tNZXRob2QuY2FsbChcbiAgICAgICAgICB0cmFuc2FjdGlvbi5iaW5kVG9UcmFuc2FjdGlvbihpc3N1ZXIpLFxuICAgICAgICAgIC4uLmFyZ3MsXG4gICAgICAgICAgY2JcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICApO1xuICAgIFRyYW5zYWN0aW9uLmdldExvY2soKS5zdWJtaXQodHJhbnNhY3Rpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IFNldHMgdGhlIGxvY2sgdG8gYmUgdXNlZFxuICAgKiBAcGFyYW0gbG9ja1xuICAgKi9cbiAgc3RhdGljIHNldExvY2sobG9jazogVHJhbnNhY3Rpb25Mb2NrKSB7XG4gICAgdGhpcy5sb2NrID0gbG9jaztcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSBnZXRzIHRoZSBsb2NrXG4gICAqL1xuICBzdGF0aWMgZ2V0TG9jaygpOiBUcmFuc2FjdGlvbkxvY2sge1xuICAgIGlmICghdGhpcy5sb2NrKSB0aGlzLmxvY2sgPSBuZXcgU3luY3Jvbm91c0xvY2soKTtcbiAgICByZXR1cm4gdGhpcy5sb2NrO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IHN1Ym1pdHMgYSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKi9cbiAgc3RhdGljIHN1Ym1pdCh0cmFuc2FjdGlvbjogVHJhbnNhY3Rpb24pIHtcbiAgICBUcmFuc2FjdGlvbi5nZXRMb2NrKCkuc3VibWl0KHRyYW5zYWN0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSByZWxlYXNlcyB0aGUgbG9ja1xuICAgKiBAcGFyYW0ge0Vycn0gZXJyXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgcmVsZWFzZShlcnI/OiBFcnJvcikge1xuICAgIHJldHVybiBUcmFuc2FjdGlvbi5nZXRMb2NrKCkucmVsZWFzZShlcnIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IHJldHJpZXZlcyB0aGUgbWV0YWRhdGEgZm9yIHRoZSB0cmFuc2FjdGlvblxuICAgKi9cbiAgZ2V0TWV0YWRhdGEoKSB7XG4gICAgcmV0dXJuIHRoaXMubWV0YWRhdGEgPyBbLi4udGhpcy5tZXRhZGF0YV0gOiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgQmluZHMgYSBuZXcgb3BlcmF0aW9uIHRvIHRoZSBjdXJyZW50IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb259IG5leHRUcmFuc2FjdGlvblxuICAgKi9cbiAgYmluZFRyYW5zYWN0aW9uKG5leHRUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb24pIHtcbiAgICAvLyBhbGwoYEJpbmRpbmcgdGhlIHswfSB0byB7MX1gLCBuZXh0VHJhbnNhY3Rpb24sIHRoaXMpO1xuICAgIHRoaXMubG9nLnB1c2goLi4ubmV4dFRyYW5zYWN0aW9uLmxvZyk7XG4gICAgbmV4dFRyYW5zYWN0aW9uLmJpbmRUcmFuc2FjdGlvbiA9IHRoaXMuYmluZFRvVHJhbnNhY3Rpb24uYmluZCh0aGlzKTtcbiAgICBuZXh0VHJhbnNhY3Rpb24uYmluZFRvVHJhbnNhY3Rpb24gPSB0aGlzLmJpbmRUb1RyYW5zYWN0aW9uLmJpbmQodGhpcyk7XG4gICAgdGhpcy5hY3Rpb24gPSBuZXh0VHJhbnNhY3Rpb24uYWN0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIEBzdW1tYXJ5IEJpbmRzIHRoZSBUcmFuc2FjdGlvbmFsIERlY29yYXRlZCBPYmplY3QgdG8gdGhlIHRyYW5zYWN0aW9uXG4gICAqIEBkZXNjcmlwdGlvbiBieSBoYXZpbmcgYWxsIHtAbGluayB0cmFuc2FjdGlvbmFsfSBkZWNvcmF0ZWRcbiAgICogbWV0aG9kcyBhbHdheXMgcGFzcyB0aGUgY3VycmVudCBUcmFuc2FjdGlvbiBhcyBhbiBhcmd1bWVudFxuICAgKlxuICAgKiBAcGFyYW0ge2FueX0gb2JqXG4gICAqIEByZXR1cm4ge2FueX0gdGhlIGJvdW5kIHtAcGFyYW0gb2JqfVxuICAgKi9cbiAgYmluZFRvVHJhbnNhY3Rpb24ob2JqOiBhbnkpOiBhbnkge1xuICAgIGNvbnN0IHRyYW5zYWN0aW9uYWxNZXRob2RzID0gZ2V0QWxsUHJvcGVydHlEZWNvcmF0b3JzUmVjdXJzaXZlKFxuICAgICAgb2JqLFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgVHJhbnNhY3Rpb25hbEtleXMuUkVGTEVDVFxuICAgICk7XG4gICAgaWYgKCF0cmFuc2FjdGlvbmFsTWV0aG9kcykgcmV0dXJuIG9iajtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXRoaXMtYWxpYXNcbiAgICBjb25zdCBzZWxmID0gdGhpcztcblxuICAgIGNvbnN0IGJvdW5kT2JqID0gUmVmbGVjdGlvbi5nZXRBbGxQcm9wZXJ0aWVzKG9iaikucmVkdWNlKFxuICAgICAgKGFjY3VtOiBhbnksIGs6IHN0cmluZykgPT4ge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgT2JqZWN0LmtleXModHJhbnNhY3Rpb25hbE1ldGhvZHMpLmluZGV4T2YoaykgIT09IC0xICYmXG4gICAgICAgICAgdHJhbnNhY3Rpb25hbE1ldGhvZHNba10uZmluZChcbiAgICAgICAgICAgIChvKSA9PiBvLmtleSA9PT0gVHJhbnNhY3Rpb25hbEtleXMuVFJBTlNBQ1RJT05BTFxuICAgICAgICAgIClcbiAgICAgICAgKVxuICAgICAgICAgIGFjY3VtW2tdID0gKC4uLmFyZ3M6IGFueVtdKSA9PlxuICAgICAgICAgICAgb2JqW2tdLmNhbGwob2JqLl9fb3JpZ2luYWxPYmogfHwgb2JqLCBzZWxmLCAuLi5hcmdzKTtcbiAgICAgICAgZWxzZSBpZiAoayA9PT0gXCJjbGF6elwiIHx8IGsgPT09IFwiY29uc3RydWN0b3JcIikgYWNjdW1ba10gPSBvYmpba107XG4gICAgICAgIGVsc2UgaWYgKHR5cGVvZiBvYmpba10gPT09IFwiZnVuY3Rpb25cIilcbiAgICAgICAgICBhY2N1bVtrXSA9IG9ialtrXS5iaW5kKG9iai5fX29yaWdpbmFsT2JqIHx8IG9iaik7XG4gICAgICAgIGVsc2UgaWYgKHR5cGVvZiBvYmpba10gPT09IFwib2JqZWN0XCIgJiYgb2JqW2tdLmNvbnN0cnVjdG9yKSB7XG4gICAgICAgICAgY29uc3QgZGVjcyA9IFJlZmxlY3Rpb24uZ2V0Q2xhc3NEZWNvcmF0b3JzKFxuICAgICAgICAgICAgVHJhbnNhY3Rpb25hbEtleXMuUkVGTEVDVCxcbiAgICAgICAgICAgIG9ialtrXVxuICAgICAgICAgICk7XG4gICAgICAgICAgaWYgKGRlY3MuZmluZCgoZTogYW55KSA9PiBlLmtleSA9PT0gVHJhbnNhY3Rpb25hbEtleXMuVFJBTlNBQ1RJT05BTCkpXG4gICAgICAgICAgICBhY2N1bVtrXSA9IHNlbGYuYmluZFRvVHJhbnNhY3Rpb24ob2JqW2tdKTtcbiAgICAgICAgICBlbHNlIGFjY3VtW2tdID0gb2JqW2tdO1xuICAgICAgICB9IGVsc2UgYWNjdW1ba10gPSBvYmpba107XG5cbiAgICAgICAgcmV0dXJuIGFjY3VtO1xuICAgICAgfSxcbiAgICAgIHt9XG4gICAgKTtcblxuICAgIGJvdW5kT2JqW0RCS2V5cy5PUklHSU5BTF0gPSBvYmpbREJLZXlzLk9SSUdJTkFMXSB8fCBvYmo7XG4gICAgYm91bmRPYmoudG9TdHJpbmcgPSAoKSA9PlxuICAgICAgZ2V0T2JqZWN0TmFtZShib3VuZE9ialtEQktleXMuT1JJR0lOQUxdKSArXG4gICAgICBcIiBwcm94eSBmb3IgdHJhbnNhY3Rpb24gXCIgK1xuICAgICAgdGhpcy5pZDtcblxuICAgIHJldHVybiBib3VuZE9iajtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSBGaXJlcyB0aGUgVHJhbnNhY3Rpb25cbiAgICovXG4gIGZpcmUoKSB7XG4gICAgaWYgKCF0aGlzLmFjdGlvbikgdGhyb3cgbmV3IEVycm9yKGBNaXNzaW5nIHRoZSBtZXRob2RgKTtcbiAgICByZXR1cm4gdGhpcy5hY3Rpb24oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAc3VtbWFyeSB0b1N0cmluZyBvdmVycmlkZVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFt3aXRoSWRdIGRlZmF1bHRzIHRvIHRydWVcbiAgICogQHBhcmFtIHtib29sZWFufSBbd2l0aExvZ10gZGVmYXVsdHMgdG8gdHJ1ZVxuICAgKi9cbiAgdG9TdHJpbmcod2l0aElkID0gdHJ1ZSwgd2l0aExvZyA9IGZhbHNlKSB7XG4gICAgcmV0dXJuIGAke3dpdGhJZCA/IGBbJHt0aGlzLmlkfV1gIDogXCJcIn1bVHJhbnNhY3Rpb25dWyR7dGhpcy5zb3VyY2V9LiR7dGhpcy5tZXRob2R9JHtcbiAgICAgIHdpdGhMb2cgPyBgXVxcblRyYW5zYWN0aW9uIExvZzpcXG4ke3RoaXMubG9nLmpvaW4oXCJcXG5cIil9YCA6IFwiXVwiXG4gICAgfWA7XG4gIH1cblxuICAvKipcbiAgICogQHN1bW1hcnkgZ2V0cyB0aGUgdHJhbnNhY3Rpb25zIHJlZmxlY3Rpb25zIGtleVxuICAgKiBAZnVuY3Rpb24gZ2V0UmVwb0tleVxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5XG4gICAqIEBtZW1iZXJPZiBtb2R1bGU6ZGItZGVjb3JhdG9ycy5UcmFuc2FjdGlvbnNcbiAgICogKi9cbiAgc3RhdGljIGtleShrZXk6IHN0cmluZykge1xuICAgIHJldHVybiBUcmFuc2FjdGlvbmFsS2V5cy5SRUZMRUNUICsga2V5O1xuICB9XG59XG4iLCJpbXBvcnQgeyBUcmFuc2FjdGlvbmFsS2V5cyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgbWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL3JlZmxlY3Rpb25cIjtcbmltcG9ydCB7IFRyYW5zYWN0aW9uIH0gZnJvbSBcIi4vVHJhbnNhY3Rpb25cIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuLyoqXG4gKiBAc3VtbWFyeSBTZXRzIGEgY2xhc3MgQXN5bmMgbWV0aG9kIGFzIHRyYW5zYWN0aW9uYWxcbiAqXG4gKiBAcGFyYW0ge2FueVtdfSAgW2RhdGFdIG9wdGlvbiBtZXRhZGF0YSBhdmFpbGFibGUgdG8gdGhlIHtAbGluayBUcmFuc2FjdGlvbkxvY2t9XG4gKlxuICogQGZ1bmN0aW9uIHRyYW5zYWN0aW9uYWxcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnMuRGVjb3JhdG9ycy50cmFuc2FjdGlvbnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zYWN0aW9uYWwoLi4uZGF0YTogYW55W10pIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBwcm9wZXJ0eUtleT86IGFueSxcbiAgICBkZXNjcmlwdG9yPzogUHJvcGVydHlEZXNjcmlwdG9yXG4gICkge1xuICAgIGlmICghZGVzY3JpcHRvcilcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTWlzc2luZyBkZXNjcmlwdG9yLiBTaG91bGQgYmUgaW1wb3NzaWJsZVwiKTtcbiAgICBtZXRhZGF0YShUcmFuc2FjdGlvbi5rZXkoVHJhbnNhY3Rpb25hbEtleXMuVFJBTlNBQ1RJT05BTCksIGRhdGEpKFxuICAgICAgdGFyZ2V0LFxuICAgICAgcHJvcGVydHlLZXlcbiAgICApO1xuXG4gICAgY29uc3Qgb3JpZ2luYWxNZXRob2QgPSBkZXNjcmlwdG9yLnZhbHVlO1xuXG4gICAgY29uc3QgbWV0aG9kV3JhcHBlciA9IGZ1bmN0aW9uICh0aGlzOiBhbnksIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdGhpcy1hbGlhc1xuICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8YW55PigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGNvbnN0IGNiID0gKGVycj86IEVycm9yLCByZXN1bHQ/OiBhbnkpID0+IHtcbiAgICAgICAgICBUcmFuc2FjdGlvbi5yZWxlYXNlKGVycikudGhlbigoKSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyKSByZXR1cm4gcmVqZWN0KGVycik7XG4gICAgICAgICAgICByZXNvbHZlKHJlc3VsdCk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgbGV0IHRyYW5zYWN0aW9uID0gYXJncy5zaGlmdCgpO1xuICAgICAgICBpZiAodHJhbnNhY3Rpb24gaW5zdGFuY2VvZiBUcmFuc2FjdGlvbikge1xuICAgICAgICAgIGNvbnN0IHVwZGF0ZWRUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb24gPSBuZXcgVHJhbnNhY3Rpb24oXG4gICAgICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLm5hbWUsXG4gICAgICAgICAgICBwcm9wZXJ0eUtleSxcbiAgICAgICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgICAgb3JpZ2luYWxNZXRob2RcbiAgICAgICAgICAgICAgICAuY2FsbCh1cGRhdGVkVHJhbnNhY3Rpb24uYmluZFRvVHJhbnNhY3Rpb24oc2VsZiksIC4uLmFyZ3MpXG4gICAgICAgICAgICAgICAgLnRoZW4ocmVzb2x2ZSlcbiAgICAgICAgICAgICAgICAuY2F0Y2gocmVqZWN0KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkYXRhLmxlbmd0aCA/IGRhdGEgOiB1bmRlZmluZWRcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgdHJhbnNhY3Rpb24uYmluZFRyYW5zYWN0aW9uKHVwZGF0ZWRUcmFuc2FjdGlvbik7XG4gICAgICAgICAgdHJhbnNhY3Rpb24uZmlyZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGFyZ3MudW5zaGlmdCh0cmFuc2FjdGlvbik7XG4gICAgICAgICAgdHJhbnNhY3Rpb24gPSBuZXcgVHJhbnNhY3Rpb24oXG4gICAgICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLm5hbWUsXG4gICAgICAgICAgICBwcm9wZXJ0eUtleSxcbiAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgb3JpZ2luYWxNZXRob2RcbiAgICAgICAgICAgICAgICAuY2FsbCh0cmFuc2FjdGlvbi5iaW5kVG9UcmFuc2FjdGlvbihzZWxmKSwgLi4uYXJncylcbiAgICAgICAgICAgICAgICAudGhlbigocmVzdWx0OiBhbnkpID0+IGNiKHVuZGVmaW5lZCwgcmVzdWx0KSlcbiAgICAgICAgICAgICAgICAuY2F0Y2goY2IpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGRhdGEubGVuZ3RoID8gZGF0YSA6IHVuZGVmaW5lZFxuICAgICAgICAgICk7XG4gICAgICAgICAgVHJhbnNhY3Rpb24uc3VibWl0KHRyYW5zYWN0aW9uKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShtZXRob2RXcmFwcGVyLCBcIm5hbWVcIiwge1xuICAgICAgdmFsdWU6IHByb3BlcnR5S2V5LFxuICAgIH0pO1xuICAgIGRlc2NyaXB0b3IudmFsdWUgPSBtZXRob2RXcmFwcGVyO1xuICB9O1xufVxuLy9cbi8vIC8qKlxuLy8gICogQHN1bW1hcnkgU2V0cyBhIGNsYXNzIEFzeW5jIG1ldGhvZCBhcyB0cmFuc2FjdGlvbmFsXG4vLyAgKlxuLy8gICogQHBhcmFtIHthbnlbXX0gIFttZXRhZGF0YV0gb3B0aW9uIG1ldGFkYXRhIGF2YWlsYWJsZSB0byB0aGUge0BsaW5rIFRyYW5zYWN0aW9uTG9ja31cbi8vICAqXG4vLyAgKiBAZnVuY3Rpb24gdHJhbnNhY3Rpb25hbEFzeW5jXG4vLyAgKlxuLy8gICogQG1lbWJlck9mIG1vZHVsZTpkYi1kZWNvcmF0b3JzLkRlY29yYXRvcnMudHJhbnNhY3Rpb25zXG4vLyAgKi9cbi8vIGV4cG9ydCBmdW5jdGlvbiB0cmFuc2FjdGlvbmFsQXN5bmMoLi4ubWV0YWRhdGE6IGFueVtdKSB7XG4vLyAgIHJldHVybiBmdW5jdGlvbiAoXG4vLyAgICAgdGFyZ2V0OiBhbnksXG4vLyAgICAgcHJvcGVydHlLZXk6IHN0cmluZyxcbi8vICAgICBkZXNjcmlwdG9yOiBQcm9wZXJ0eURlc2NyaXB0b3IsXG4vLyAgICkge1xuLy8gICAgIG1ldGFkYXN0YShnZXRUcmFuc2FjdGlvbmFsS2V5KFRyYW5zYWN0aW9uYWxLZXlzLlRSQU5TQUNUSU9OQUwpKVxuLy8gICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4vLyAgICAgICAsXG4vLyAgICAgICB7XG4vLyAgICAgICAgIHR5cGU6IFwiYXN5bmNcIixcbi8vICAgICAgICAgbWV0YWRhdGE6IG1ldGFkYXRhLmxlbmd0aCA/IG1ldGFkYXRhIDogdW5kZWZpbmVkLFxuLy8gICAgICAgfSBhcyBUcmFuc2FjdGlvbmFsTWV0YWRhdGEsXG4vLyAgICAgICB0YXJnZXQsXG4vLyAgICAgICBwcm9wZXJ0eUtleSxcbi8vICAgICApO1xuLy9cbi8vICAgICBjb25zdCBvcmlnaW5hbE1ldGhvZCA9IGRlc2NyaXB0b3IudmFsdWU7XG4vL1xuLy8gICAgIGNvbnN0IG1ldGhvZFdyYXBwZXIgPSBmdW5jdGlvbiAodGhpczogYW55LCAuLi5hcmdzOiBhbnlbXSkge1xuLy8gICAgICAgY29uc3QgY2FsbGJhY2s6IENhbGxiYWNrID0gYXJncy5wb3AoKTtcbi8vICAgICAgIGlmICghY2FsbGJhY2sgfHwgdHlwZW9mIGNhbGxiYWNrICE9PSBcImZ1bmN0aW9uXCIpXG4vLyAgICAgICAgIHRocm93IG5ldyBDcml0aWNhbEVycm9yKGBNaXNzaW5nIENhbGxiYWNrYCk7XG4vL1xuLy8gICAgICAgY29uc3QgY2IgPSAoZXJyPzogRXJyLCAuLi5hcmdzOiBhbnlbXSkgPT4ge1xuLy8gICAgICAgICBUcmFuc2FjdGlvbi5yZWxlYXNlKGVycikudGhlbigoXykgPT4gY2FsbGJhY2soZXJyLCAuLi5hcmdzKSk7XG4vLyAgICAgICB9O1xuLy9cbi8vICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuLy9cbi8vICAgICAgIGxldCB0cmFuc2FjdGlvbiA9IGFyZ3Muc2hpZnQoKTtcbi8vICAgICAgIGlmICh0cmFuc2FjdGlvbiBpbnN0YW5jZW9mIFRyYW5zYWN0aW9uKSB7XG4vLyAgICAgICAgIGNvbnN0IHVwZGF0ZWRUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb24gPSBuZXcgVHJhbnNhY3Rpb24oXG4vLyAgICAgICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5uYW1lLFxuLy8gICAgICAgICAgIHByb3BlcnR5S2V5LFxuLy8gICAgICAgICAgICgpID0+IHtcbi8vICAgICAgICAgICAgIHRyeSB7XG4vLyAgICAgICAgICAgICAgIHJldHVybiBvcmlnaW5hbE1ldGhvZC5jYWxsKFxuLy8gICAgICAgICAgICAgICAgIHVwZGF0ZWRUcmFuc2FjdGlvbi5iaW5kVG9UcmFuc2FjdGlvbihzZWxmKSxcbi8vICAgICAgICAgICAgICAgICAuLi5hcmdzLFxuLy8gICAgICAgICAgICAgICAgIGNhbGxiYWNrLFxuLy8gICAgICAgICAgICAgICApO1xuLy8gICAgICAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4vLyAgICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlKTtcbi8vICAgICAgICAgICAgIH1cbi8vICAgICAgICAgICB9LFxuLy8gICAgICAgICAgIG1ldGFkYXRhLmxlbmd0aCA/IG1ldGFkYXRhIDogdW5kZWZpbmVkLFxuLy8gICAgICAgICApO1xuLy9cbi8vICAgICAgICAgdHJhbnNhY3Rpb24uYmluZFRyYW5zYWN0aW9uKHVwZGF0ZWRUcmFuc2FjdGlvbik7XG4vLyAgICAgICAgIHRyYW5zYWN0aW9uLmZpcmUoKTtcbi8vICAgICAgIH0gZWxzZSB7XG4vLyAgICAgICAgIGFyZ3MudW5zaGlmdCh0cmFuc2FjdGlvbik7XG4vLyAgICAgICAgIHRyYW5zYWN0aW9uID0gdW5kZWZpbmVkO1xuLy8gICAgICAgICB0cmFuc2FjdGlvbiA9IG5ldyBUcmFuc2FjdGlvbihcbi8vICAgICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLm5hbWUsXG4vLyAgICAgICAgICAgcHJvcGVydHlLZXksXG4vLyAgICAgICAgICAgKCkgPT4ge1xuLy8gICAgICAgICAgICAgdHJ5IHtcbi8vICAgICAgICAgICAgICAgcmV0dXJuIG9yaWdpbmFsTWV0aG9kLmNhbGwoXG4vLyAgICAgICAgICAgICAgICAgdHJhbnNhY3Rpb24uYmluZFRvVHJhbnNhY3Rpb24oc2VsZiksXG4vLyAgICAgICAgICAgICAgICAgLi4uYXJncyxcbi8vICAgICAgICAgICAgICAgICBjYixcbi8vICAgICAgICAgICAgICAgKTtcbi8vICAgICAgICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuLy8gICAgICAgICAgICAgICByZXR1cm4gY2IoZSk7XG4vLyAgICAgICAgICAgICB9XG4vLyAgICAgICAgICAgfSxcbi8vICAgICAgICAgICBtZXRhZGF0YS5sZW5ndGggPyBtZXRhZGF0YSA6IHVuZGVmaW5lZCxcbi8vICAgICAgICAgKTtcbi8vICAgICAgICAgVHJhbnNhY3Rpb24uc3VibWl0KHRyYW5zYWN0aW9uKTtcbi8vICAgICAgIH1cbi8vICAgICB9O1xuLy9cbi8vICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkobWV0aG9kV3JhcHBlciwgXCJuYW1lXCIsIHtcbi8vICAgICAgIHZhbHVlOiBwcm9wZXJ0eUtleSxcbi8vICAgICB9KTtcbi8vICAgICBkZXNjcmlwdG9yLnZhbHVlID0gbWV0aG9kV3JhcHBlcjtcbi8vICAgfTtcbi8vIH1cblxuLyoqXG4gKiBAc3VtbWFyeSBVdGlsIGZ1bmN0aW9uIHRvIHdyYXAgc3VwZXIgY2FsbHMgd2l0aCB0aGUgdHJhbnNhY3Rpb24gd2hlbiB0aGUgc3VwZXIncyBtZXRob2QgaXMgYWxzbyB0cmFuc2FjdGlvbmFsXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gbWV0aG9kIHRoZSBzdXBlciBtZXRob2QgKG11c3QgYmUgYm91bmQgdG8gdGhlIHByb3BlciB0aGlzKSwgZWc6IHN1cGVyLmNyZWF0ZS5iaW5kKHRoaXMpXG4gKiBAcGFyYW0ge2FueVtdfSBhcmdzIHRoZSBhcmd1bWVudHMgdG8gY2FsbCB0aGUgbWV0aG9kIHdpdGhcbiAqXG4gKiBAbWVtYmVyT2YgbW9kdWxlOmRiLWRlY29yYXRvcnMuVHJhbnNhY3Rpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zYWN0aW9uYWxTdXBlckNhbGwobWV0aG9kOiBhbnksIC4uLmFyZ3M6IGFueSkge1xuICBjb25zdCBsb2NrID0gVHJhbnNhY3Rpb24uZ2V0TG9jaygpO1xuICBjb25zdCBjdXJyZW50VHJhbnNhY3Rpb24gPSBsb2NrLmN1cnJlbnRUcmFuc2FjdGlvbjtcbiAgcmV0dXJuIG1ldGhvZChjdXJyZW50VHJhbnNhY3Rpb24sIC4uLmFyZ3MpO1xufVxuIiwiZXhwb3J0ICogZnJvbSBcIi4vaW50ZXJmYWNlc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vbG9ja3NcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2NvbnN0YW50c1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vZGVjb3JhdG9yc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vVHJhbnNhY3Rpb25cIjtcbmV4cG9ydCAqIGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQHN1bW1hcnkgTW9kdWxlIHN1bW1hcnlcbiAqIEBkZXNjcmlwdGlvbiBNb2R1bGUgZGVzY3JpcHRpb25cbiAqIEBtb2R1bGUgdHMtd29ya3NwYWNlXG4gKi9cblxuLyoqXG4gKiBAc3VtbWFyeSBOYW1lc3BhY2Ugc3VtbWFyeVxuICogQGRlc2NyaXB0aW9uIE5hbWVzcGFjZSBkZXNjcmlwdGlvblxuICogQG5hbWVzcGFjZSBOYW1lc3BhY2VcbiAqIEBtZW1iZXJPZiBtb2R1bGU6dHMtd29ya3NwYWNlXG4gKi9cblxuLyoqXG4gKiBAc3VtbWFyeSBzdG9yZXMgdGhlIGN1cnJlbnQgcGFja2FnZSB2ZXJzaW9uXG4gKiBAZGVzY3JpcHRpb24gdGhpcyBpcyBob3cgeW91IHNob3VsZCBkb2N1bWVudCBhIGNvbnN0YW50XG4gKiBAY29uc3QgVkVSU0lPTlxuICogQG1lbWJlck9mIG1vZHVsZTp0cy13b3Jrc3BhY2VcbiAqL1xuZXhwb3J0IGNvbnN0IFZFUlNJT04gPSBcIiMjVkVSU0lPTiMjXCI7XG4iXSwibmFtZXMiOlsiZ2V0QWxsUHJvcGVydHlEZWNvcmF0b3JzUmVjdXJzaXZlIiwiUmVmbGVjdGlvbiIsIkRCS2V5cyIsIkludGVybmFsRXJyb3IiLCJtZXRhZGF0YSJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0lBRUE7Ozs7O0lBS0c7VUFDVSxJQUFJLENBQUE7SUFBakIsSUFBQSxXQUFBLEdBQUE7WUFDVSxJQUFLLENBQUEsS0FBQSxHQUFtQixFQUFFO1lBQzFCLElBQU0sQ0FBQSxNQUFBLEdBQUcsS0FBSzs7SUFFdEI7OztJQUdHO1FBQ0gsTUFBTSxPQUFPLENBQUMsSUFBZSxFQUFBO0lBQzNCLFFBQUEsTUFBTSxJQUFJLENBQUMsT0FBTyxFQUFFO0lBQ3BCLFFBQUEsSUFBSSxNQUFXO0lBQ2YsUUFBQSxJQUFJO2dCQUNGLE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7O1lBQ3RDLE9BQU8sQ0FBTSxFQUFFO2dCQUNmLElBQUksQ0FBQyxPQUFPLEVBQUU7SUFDZCxZQUFBLE1BQU0sQ0FBQzs7WUFFVCxJQUFJLENBQUMsT0FBTyxFQUFFO0lBQ2QsUUFBQSxPQUFPLE1BQU07O0lBR2Y7OztJQUdHO0lBQ0gsSUFBQSxNQUFNLE9BQU8sR0FBQTs7WUFFWCxNQUFNLElBQUksR0FBRyxJQUFJO0lBQ2pCLFFBQUEsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO0lBQ2YsWUFBQSxPQUFPLElBQUksT0FBTyxDQUFPLENBQUMsT0FBTyxLQUFL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O0lBQ2xDLEtBQUM7SUFDSDtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUNBO0lBQ0E7SUFDQTtJQUVBOzs7Ozs7O0lBT0c7YUFDYSxzQkFBc0IsQ0FBQyxNQUFXLEVBQUUsR0FBRyxJQUFTLEVBQUE7SUFDOUQsSUFBQSxNQUFNLElBQUksR0FBRyxXQUFXLENBQUMsT0FBTyxFQUFFO0lBQ2xDLElBQUEsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsa0JBQWtCO0lBQ2xELElBQUEsT0FBTyxNQUFNLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFDNUM7O0lDaExBOzs7O0lBSUc7SUFFSDs7Ozs7SUFLRztJQUVIOzs7OztJQUtHO0FBQ0ksVUFBTSxPQUFPLEdBQUc7Ozs7Ozs7Ozs7Ozs7OyJ9