state-sync-log 0.9.0

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 (41) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +277 -0
  4. package/dist/state-sync-log.esm.js +1339 -0
  5. package/dist/state-sync-log.esm.mjs +1339 -0
  6. package/dist/state-sync-log.umd.js +1343 -0
  7. package/dist/types/ClientId.d.ts +1 -0
  8. package/dist/types/SortedTxEntry.d.ts +44 -0
  9. package/dist/types/StateCalculator.d.ts +141 -0
  10. package/dist/types/TxRecord.d.ts +14 -0
  11. package/dist/types/checkpointUtils.d.ts +15 -0
  12. package/dist/types/checkpoints.d.ts +62 -0
  13. package/dist/types/clientState.d.ts +19 -0
  14. package/dist/types/createStateSyncLog.d.ts +97 -0
  15. package/dist/types/draft.d.ts +69 -0
  16. package/dist/types/error.d.ts +4 -0
  17. package/dist/types/index.d.ts +4 -0
  18. package/dist/types/json.d.ts +23 -0
  19. package/dist/types/operations.d.ts +64 -0
  20. package/dist/types/reconcile.d.ts +7 -0
  21. package/dist/types/txLog.d.ts +32 -0
  22. package/dist/types/txTimestamp.d.ts +27 -0
  23. package/dist/types/utils.d.ts +23 -0
  24. package/package.json +94 -0
  25. package/src/ClientId.ts +1 -0
  26. package/src/SortedTxEntry.ts +83 -0
  27. package/src/StateCalculator.ts +407 -0
  28. package/src/TxRecord.ts +15 -0
  29. package/src/checkpointUtils.ts +44 -0
  30. package/src/checkpoints.ts +208 -0
  31. package/src/clientState.ts +37 -0
  32. package/src/createStateSyncLog.ts +330 -0
  33. package/src/draft.ts +288 -0
  34. package/src/error.ts +12 -0
  35. package/src/index.ts +8 -0
  36. package/src/json.ts +25 -0
  37. package/src/operations.ts +157 -0
  38. package/src/reconcile.ts +124 -0
  39. package/src/txLog.ts +208 -0
  40. package/src/txTimestamp.ts +56 -0
  41. package/src/utils.ts +55 -0
@@ -0,0 +1,1343 @@
1
+ (function(global, factory) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["state-sync-log"] = {}));
3
+ })(this, (function(exports2) {
4
+ "use strict";var __defProp = Object.defineProperty;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
+
8
+ function getFinalizedEpochAndCheckpoint(yCheckpoint) {
9
+ let maxEpoch = -1;
10
+ let best = null;
11
+ let bestTxCount = -1;
12
+ let bestClientId = "";
13
+ for (const [key, cp] of yCheckpoint.entries()) {
14
+ const { epoch, clientId } = parseCheckpointKey(key);
15
+ if (epoch > maxEpoch) {
16
+ maxEpoch = epoch;
17
+ best = cp;
18
+ bestTxCount = cp.txCount;
19
+ bestClientId = clientId;
20
+ } else if (epoch === maxEpoch) {
21
+ if (cp.txCount > bestTxCount || cp.txCount === bestTxCount && clientId < bestClientId) {
22
+ best = cp;
23
+ bestTxCount = cp.txCount;
24
+ bestClientId = clientId;
25
+ }
26
+ }
27
+ }
28
+ return { finalizedEpoch: maxEpoch, checkpoint: best };
29
+ }
30
+ class StateSyncLogError extends Error {
31
+ constructor(msg) {
32
+ super(msg);
33
+ Object.setPrototypeOf(this, StateSyncLogError.prototype);
34
+ }
35
+ }
36
+ function failure(message) {
37
+ throw new StateSyncLogError(message);
38
+ }
39
+ function checkpointKeyDataToKey(data) {
40
+ return `${data.epoch};${data.txCount};${data.clientId}`;
41
+ }
42
+ function parseCheckpointKey(key) {
43
+ const i1 = key.indexOf(";");
44
+ const i2 = key.indexOf(";", i1 + 1);
45
+ if (i1 === -1 || i2 === -1) {
46
+ failure(`Malformed checkpoint key: ${key}`);
47
+ }
48
+ return {
49
+ epoch: Number.parseInt(key.substring(0, i1), 10),
50
+ txCount: Number.parseInt(key.substring(i1 + 1, i2), 10),
51
+ clientId: key.substring(i2 + 1)
52
+ };
53
+ }
54
+ function createCheckpoint(yTx, yCheckpoint, clientState, activeEpoch, currentState, myClientId) {
55
+ const { checkpoint: prevCP } = getFinalizedEpochAndCheckpoint(yCheckpoint);
56
+ const newWatermarks = prevCP ? { ...prevCP.watermarks } : {};
57
+ const sortedTxs = clientState.stateCalculator.getSortedTxs();
58
+ let endIndex = sortedTxs.length;
59
+ while (endIndex > 0 && sortedTxs[endIndex - 1].txTimestamp.epoch > activeEpoch) {
60
+ endIndex--;
61
+ }
62
+ const activeTxs = sortedTxs.slice(0, endIndex);
63
+ if (activeTxs.length === 0) {
64
+ return;
65
+ }
66
+ let minWallClock = Number.POSITIVE_INFINITY;
67
+ let txCount = 0;
68
+ for (const entry of activeTxs) {
69
+ const ts = entry.txTimestamp;
70
+ if (ts.wallClock < minWallClock) {
71
+ minWallClock = ts.wallClock;
72
+ }
73
+ const newWm = newWatermarks[ts.clientId] ? { ...newWatermarks[ts.clientId] } : { maxClock: -1, maxWallClock: 0 };
74
+ if (ts.clock > newWm.maxClock) {
75
+ newWm.maxClock = ts.clock;
76
+ newWm.maxWallClock = ts.wallClock;
77
+ }
78
+ newWatermarks[ts.clientId] = newWm;
79
+ txCount++;
80
+ }
81
+ for (const clientId in newWatermarks) {
82
+ if (minWallClock - newWatermarks[clientId].maxWallClock > clientState.retentionWindowMs) {
83
+ delete newWatermarks[clientId];
84
+ }
85
+ }
86
+ const cpKey = checkpointKeyDataToKey({
87
+ epoch: activeEpoch,
88
+ txCount,
89
+ clientId: myClientId
90
+ });
91
+ yCheckpoint.set(cpKey, {
92
+ state: currentState,
93
+ // Responsibility for cloning is moved to the caller if needed
94
+ watermarks: newWatermarks,
95
+ txCount,
96
+ minWallClock
97
+ });
98
+ const keysToDelete = [];
99
+ for (const entry of activeTxs) {
100
+ yTx.delete(entry.txTimestampKey);
101
+ keysToDelete.push(entry.txTimestampKey);
102
+ }
103
+ clientState.stateCalculator.removeTxs(keysToDelete);
104
+ }
105
+ function pruneCheckpoints(yCheckpoint, finalizedEpoch) {
106
+ let canonicalKey = null;
107
+ let bestTxCount = -1;
108
+ for (const [key] of yCheckpoint.entries()) {
109
+ const { epoch, txCount } = parseCheckpointKey(key);
110
+ if (epoch === finalizedEpoch && txCount > bestTxCount) {
111
+ canonicalKey = key;
112
+ bestTxCount = txCount;
113
+ }
114
+ }
115
+ for (const key of yCheckpoint.keys()) {
116
+ if (key !== canonicalKey) {
117
+ yCheckpoint.delete(key);
118
+ }
119
+ }
120
+ }
121
+ function getDefaultExportFromCjs(x) {
122
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
123
+ }
124
+ var fastDeepEqual;
125
+ var hasRequiredFastDeepEqual;
126
+ function requireFastDeepEqual() {
127
+ if (hasRequiredFastDeepEqual) return fastDeepEqual;
128
+ hasRequiredFastDeepEqual = 1;
129
+ fastDeepEqual = function equal2(a, b) {
130
+ if (a === b) return true;
131
+ if (a && b && typeof a == "object" && typeof b == "object") {
132
+ if (a.constructor !== b.constructor) return false;
133
+ var length, i, keys;
134
+ if (Array.isArray(a)) {
135
+ length = a.length;
136
+ if (length != b.length) return false;
137
+ for (i = length; i-- !== 0; )
138
+ if (!equal2(a[i], b[i])) return false;
139
+ return true;
140
+ }
141
+ if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
142
+ if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
143
+ if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
144
+ keys = Object.keys(a);
145
+ length = keys.length;
146
+ if (length !== Object.keys(b).length) return false;
147
+ for (i = length; i-- !== 0; )
148
+ if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
149
+ for (i = length; i-- !== 0; ) {
150
+ var key = keys[i];
151
+ if (!equal2(a[key], b[key])) return false;
152
+ }
153
+ return true;
154
+ }
155
+ return a !== a && b !== b;
156
+ };
157
+ return fastDeepEqual;
158
+ }
159
+ var fastDeepEqualExports = requireFastDeepEqual();
160
+ const equal = /* @__PURE__ */ getDefaultExportFromCjs(fastDeepEqualExports);
161
+ const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
162
+ let nanoid = (size = 21) => {
163
+ let id = "";
164
+ let bytes = crypto.getRandomValues(new Uint8Array(size |= 0));
165
+ while (size--) {
166
+ id += urlAlphabet[bytes[size] & 63];
167
+ }
168
+ return id;
169
+ };
170
+ var rfdc_1;
171
+ var hasRequiredRfdc;
172
+ function requireRfdc() {
173
+ if (hasRequiredRfdc) return rfdc_1;
174
+ hasRequiredRfdc = 1;
175
+ rfdc_1 = rfdc2;
176
+ function copyBuffer(cur) {
177
+ if (cur instanceof Buffer) {
178
+ return Buffer.from(cur);
179
+ }
180
+ return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length);
181
+ }
182
+ function rfdc2(opts) {
183
+ opts = opts || {};
184
+ if (opts.circles) return rfdcCircles(opts);
185
+ const constructorHandlers = /* @__PURE__ */ new Map();
186
+ constructorHandlers.set(Date, (o) => new Date(o));
187
+ constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
188
+ constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
189
+ if (opts.constructorHandlers) {
190
+ for (const handler2 of opts.constructorHandlers) {
191
+ constructorHandlers.set(handler2[0], handler2[1]);
192
+ }
193
+ }
194
+ let handler = null;
195
+ return opts.proto ? cloneProto : clone2;
196
+ function cloneArray(a, fn) {
197
+ const keys = Object.keys(a);
198
+ const a2 = new Array(keys.length);
199
+ for (let i = 0; i < keys.length; i++) {
200
+ const k = keys[i];
201
+ const cur = a[k];
202
+ if (typeof cur !== "object" || cur === null) {
203
+ a2[k] = cur;
204
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
205
+ a2[k] = handler(cur, fn);
206
+ } else if (ArrayBuffer.isView(cur)) {
207
+ a2[k] = copyBuffer(cur);
208
+ } else {
209
+ a2[k] = fn(cur);
210
+ }
211
+ }
212
+ return a2;
213
+ }
214
+ function clone2(o) {
215
+ if (typeof o !== "object" || o === null) return o;
216
+ if (Array.isArray(o)) return cloneArray(o, clone2);
217
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
218
+ return handler(o, clone2);
219
+ }
220
+ const o2 = {};
221
+ for (const k in o) {
222
+ if (Object.hasOwnProperty.call(o, k) === false) continue;
223
+ const cur = o[k];
224
+ if (typeof cur !== "object" || cur === null) {
225
+ o2[k] = cur;
226
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
227
+ o2[k] = handler(cur, clone2);
228
+ } else if (ArrayBuffer.isView(cur)) {
229
+ o2[k] = copyBuffer(cur);
230
+ } else {
231
+ o2[k] = clone2(cur);
232
+ }
233
+ }
234
+ return o2;
235
+ }
236
+ function cloneProto(o) {
237
+ if (typeof o !== "object" || o === null) return o;
238
+ if (Array.isArray(o)) return cloneArray(o, cloneProto);
239
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
240
+ return handler(o, cloneProto);
241
+ }
242
+ const o2 = {};
243
+ for (const k in o) {
244
+ const cur = o[k];
245
+ if (typeof cur !== "object" || cur === null) {
246
+ o2[k] = cur;
247
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
248
+ o2[k] = handler(cur, cloneProto);
249
+ } else if (ArrayBuffer.isView(cur)) {
250
+ o2[k] = copyBuffer(cur);
251
+ } else {
252
+ o2[k] = cloneProto(cur);
253
+ }
254
+ }
255
+ return o2;
256
+ }
257
+ }
258
+ function rfdcCircles(opts) {
259
+ const refs = [];
260
+ const refsNew = [];
261
+ const constructorHandlers = /* @__PURE__ */ new Map();
262
+ constructorHandlers.set(Date, (o) => new Date(o));
263
+ constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
264
+ constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
265
+ if (opts.constructorHandlers) {
266
+ for (const handler2 of opts.constructorHandlers) {
267
+ constructorHandlers.set(handler2[0], handler2[1]);
268
+ }
269
+ }
270
+ let handler = null;
271
+ return opts.proto ? cloneProto : clone2;
272
+ function cloneArray(a, fn) {
273
+ const keys = Object.keys(a);
274
+ const a2 = new Array(keys.length);
275
+ for (let i = 0; i < keys.length; i++) {
276
+ const k = keys[i];
277
+ const cur = a[k];
278
+ if (typeof cur !== "object" || cur === null) {
279
+ a2[k] = cur;
280
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
281
+ a2[k] = handler(cur, fn);
282
+ } else if (ArrayBuffer.isView(cur)) {
283
+ a2[k] = copyBuffer(cur);
284
+ } else {
285
+ const index = refs.indexOf(cur);
286
+ if (index !== -1) {
287
+ a2[k] = refsNew[index];
288
+ } else {
289
+ a2[k] = fn(cur);
290
+ }
291
+ }
292
+ }
293
+ return a2;
294
+ }
295
+ function clone2(o) {
296
+ if (typeof o !== "object" || o === null) return o;
297
+ if (Array.isArray(o)) return cloneArray(o, clone2);
298
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
299
+ return handler(o, clone2);
300
+ }
301
+ const o2 = {};
302
+ refs.push(o);
303
+ refsNew.push(o2);
304
+ for (const k in o) {
305
+ if (Object.hasOwnProperty.call(o, k) === false) continue;
306
+ const cur = o[k];
307
+ if (typeof cur !== "object" || cur === null) {
308
+ o2[k] = cur;
309
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
310
+ o2[k] = handler(cur, clone2);
311
+ } else if (ArrayBuffer.isView(cur)) {
312
+ o2[k] = copyBuffer(cur);
313
+ } else {
314
+ const i = refs.indexOf(cur);
315
+ if (i !== -1) {
316
+ o2[k] = refsNew[i];
317
+ } else {
318
+ o2[k] = clone2(cur);
319
+ }
320
+ }
321
+ }
322
+ refs.pop();
323
+ refsNew.pop();
324
+ return o2;
325
+ }
326
+ function cloneProto(o) {
327
+ if (typeof o !== "object" || o === null) return o;
328
+ if (Array.isArray(o)) return cloneArray(o, cloneProto);
329
+ if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
330
+ return handler(o, cloneProto);
331
+ }
332
+ const o2 = {};
333
+ refs.push(o);
334
+ refsNew.push(o2);
335
+ for (const k in o) {
336
+ const cur = o[k];
337
+ if (typeof cur !== "object" || cur === null) {
338
+ o2[k] = cur;
339
+ } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
340
+ o2[k] = handler(cur, cloneProto);
341
+ } else if (ArrayBuffer.isView(cur)) {
342
+ o2[k] = copyBuffer(cur);
343
+ } else {
344
+ const i = refs.indexOf(cur);
345
+ if (i !== -1) {
346
+ o2[k] = refsNew[i];
347
+ } else {
348
+ o2[k] = cloneProto(cur);
349
+ }
350
+ }
351
+ }
352
+ refs.pop();
353
+ refsNew.pop();
354
+ return o2;
355
+ }
356
+ }
357
+ return rfdc_1;
358
+ }
359
+ var rfdcExports = requireRfdc();
360
+ const rfdc = /* @__PURE__ */ getDefaultExportFromCjs(rfdcExports);
361
+ const clone = rfdc({ proto: true });
362
+ function deepEqual(a, b) {
363
+ return equal(a, b);
364
+ }
365
+ function generateID() {
366
+ return nanoid();
367
+ }
368
+ function isObject(value) {
369
+ return value !== null && typeof value === "object";
370
+ }
371
+ function deepClone(value) {
372
+ if (value === null || typeof value !== "object") {
373
+ return value;
374
+ }
375
+ return clone(value);
376
+ }
377
+ function lazy(fn) {
378
+ let computed = false;
379
+ let value;
380
+ return () => {
381
+ if (!computed) {
382
+ value = fn();
383
+ computed = true;
384
+ }
385
+ return value;
386
+ };
387
+ }
388
+ function createDraft(base) {
389
+ return {
390
+ root: base,
391
+ base,
392
+ ownedObjects: /* @__PURE__ */ new Set(),
393
+ isRootOwned: false
394
+ };
395
+ }
396
+ function shallowClone(obj) {
397
+ if (Array.isArray(obj)) {
398
+ return obj.slice();
399
+ }
400
+ const clone2 = {};
401
+ const keys = Object.keys(obj);
402
+ for (let i = 0; i < keys.length; i++) {
403
+ const key = keys[i];
404
+ clone2[key] = obj[key];
405
+ }
406
+ return clone2;
407
+ }
408
+ function ensureOwned(ctx, parent, key, child) {
409
+ if (ctx.ownedObjects.has(child)) {
410
+ return child;
411
+ }
412
+ const cloned = shallowClone(child);
413
+ parent[key] = cloned;
414
+ ctx.ownedObjects.add(cloned);
415
+ return cloned;
416
+ }
417
+ function ensureOwnedPath(ctx, path) {
418
+ if (!ctx.isRootOwned) {
419
+ ctx.root = shallowClone(ctx.root);
420
+ ctx.ownedObjects.add(ctx.root);
421
+ ctx.isRootOwned = true;
422
+ }
423
+ if (path.length === 0) {
424
+ return ctx.root;
425
+ }
426
+ let current = ctx.root;
427
+ for (let i = 0; i < path.length; i++) {
428
+ const segment = path[i];
429
+ const isArrayIndex = typeof segment === "number";
430
+ if (isArrayIndex) {
431
+ if (!Array.isArray(current)) {
432
+ failure(`Expected array at path segment ${segment}`);
433
+ }
434
+ if (segment < 0 || segment >= current.length) {
435
+ failure(`Index ${segment} out of bounds`);
436
+ }
437
+ } else {
438
+ if (!isObject(current) || Array.isArray(current)) {
439
+ failure(`Expected object at path segment "${segment}"`);
440
+ }
441
+ if (!(segment in current)) {
442
+ failure(`Property "${segment}" does not exist`);
443
+ }
444
+ }
445
+ const child = current[segment];
446
+ if (child === null || typeof child !== "object") {
447
+ failure(`Cannot traverse through primitive at path segment ${segment}`);
448
+ }
449
+ current = ensureOwned(ctx, current, segment, child);
450
+ }
451
+ return current;
452
+ }
453
+ function draftSet(ctx, path, key, value) {
454
+ const container = ensureOwnedPath(ctx, path);
455
+ if (Array.isArray(container)) {
456
+ failure("set requires object container");
457
+ }
458
+ container[key] = value;
459
+ }
460
+ function draftDelete(ctx, path, key) {
461
+ const container = ensureOwnedPath(ctx, path);
462
+ if (Array.isArray(container)) {
463
+ failure("delete requires object container");
464
+ }
465
+ delete container[key];
466
+ }
467
+ function draftSplice(ctx, path, index, deleteCount, inserts) {
468
+ const container = ensureOwnedPath(ctx, path);
469
+ if (!Array.isArray(container)) {
470
+ failure("splice requires array container");
471
+ }
472
+ const safeIndex = Math.min(index, container.length);
473
+ if (inserts.length === 0) {
474
+ container.splice(safeIndex, deleteCount);
475
+ } else if (inserts.length === 1) {
476
+ container.splice(safeIndex, deleteCount, inserts[0]);
477
+ } else {
478
+ container.splice(safeIndex, deleteCount, ...inserts);
479
+ }
480
+ }
481
+ function draftAddToSet(ctx, path, value) {
482
+ const container = ensureOwnedPath(ctx, path);
483
+ if (!Array.isArray(container)) {
484
+ failure("addToSet requires array container");
485
+ }
486
+ if (!container.some((item) => deepEqual(item, value))) {
487
+ container.push(value);
488
+ }
489
+ }
490
+ function draftDeleteFromSet(ctx, path, value) {
491
+ const container = ensureOwnedPath(ctx, path);
492
+ if (!Array.isArray(container)) {
493
+ failure("deleteFromSet requires array container");
494
+ }
495
+ for (let i = container.length - 1; i >= 0; i--) {
496
+ if (deepEqual(container[i], value)) {
497
+ container.splice(i, 1);
498
+ }
499
+ }
500
+ }
501
+ function applyOpToDraft(ctx, op) {
502
+ switch (op.kind) {
503
+ case "set":
504
+ draftSet(ctx, op.path, op.key, op.value);
505
+ break;
506
+ case "delete":
507
+ draftDelete(ctx, op.path, op.key);
508
+ break;
509
+ case "splice":
510
+ draftSplice(ctx, op.path, op.index, op.deleteCount, op.inserts);
511
+ break;
512
+ case "addToSet":
513
+ draftAddToSet(ctx, op.path, op.value);
514
+ break;
515
+ case "deleteFromSet":
516
+ draftDeleteFromSet(ctx, op.path, op.value);
517
+ break;
518
+ default:
519
+ throw failure(`Unknown operation kind: ${op.kind}`);
520
+ }
521
+ }
522
+ function applyTxImmutable(base, tx, validateFn) {
523
+ if (tx.ops.length === 0) return base;
524
+ const ctx = createDraft(base);
525
+ try {
526
+ for (const op of tx.ops) {
527
+ applyOpToDraft(ctx, op);
528
+ }
529
+ if (validateFn && !validateFn(ctx.root)) {
530
+ return base;
531
+ }
532
+ return ctx.root;
533
+ } catch {
534
+ return base;
535
+ }
536
+ }
537
+ function computeReconcileOps(currentState, targetState) {
538
+ const ops = [];
539
+ diffValue(currentState, targetState, [], ops);
540
+ return ops;
541
+ }
542
+ function diffValue(current, target, path, ops) {
543
+ if (current === target) return;
544
+ const currentType = typeof current;
545
+ const targetType = typeof target;
546
+ if (current === null || target === null || currentType !== "object" || targetType !== "object") {
547
+ emitReplace(path, target, ops);
548
+ return;
549
+ }
550
+ const currentIsArray = Array.isArray(current);
551
+ const targetIsArray = Array.isArray(target);
552
+ if (currentIsArray !== targetIsArray) {
553
+ emitReplace(path, target, ops);
554
+ return;
555
+ }
556
+ if (currentIsArray) {
557
+ diffArray(current, target, path, ops);
558
+ } else {
559
+ diffObject(current, target, path, ops);
560
+ }
561
+ }
562
+ function diffObject(current, target, path, ops) {
563
+ for (const key in current) {
564
+ if (Object.hasOwn(current, key) && !Object.hasOwn(target, key)) {
565
+ ops.push({ kind: "delete", path, key });
566
+ }
567
+ }
568
+ for (const key in target) {
569
+ if (Object.hasOwn(target, key)) {
570
+ const targetVal = target[key];
571
+ if (!Object.hasOwn(current, key)) {
572
+ ops.push({ kind: "set", path, key, value: targetVal });
573
+ } else if (current[key] !== targetVal) {
574
+ diffValue(current[key], targetVal, [...path, key], ops);
575
+ }
576
+ }
577
+ }
578
+ }
579
+ function diffArray(current, target, path, ops) {
580
+ const currentLen = current.length;
581
+ const targetLen = target.length;
582
+ const minLen = currentLen < targetLen ? currentLen : targetLen;
583
+ for (let i = 0; i < minLen; i++) {
584
+ if (current[i] !== target[i]) {
585
+ diffValue(current[i], target[i], [...path, i], ops);
586
+ }
587
+ }
588
+ if (targetLen > currentLen) {
589
+ ops.push({
590
+ kind: "splice",
591
+ path,
592
+ index: currentLen,
593
+ deleteCount: 0,
594
+ inserts: target.slice(currentLen)
595
+ });
596
+ } else if (currentLen > targetLen) {
597
+ ops.push({
598
+ kind: "splice",
599
+ path,
600
+ index: targetLen,
601
+ deleteCount: currentLen - targetLen,
602
+ inserts: []
603
+ });
604
+ }
605
+ }
606
+ function emitReplace(path, value, ops) {
607
+ if (path.length === 0) {
608
+ failure("StateSyncLog: Cannot replace root state directly via Ops.");
609
+ }
610
+ const parentPath = path.slice(0, -1);
611
+ const keyToCheck = path[path.length - 1];
612
+ if (typeof keyToCheck === "string") {
613
+ ops.push({ kind: "set", path: parentPath, key: keyToCheck, value });
614
+ } else {
615
+ ops.push({
616
+ kind: "splice",
617
+ path: parentPath,
618
+ index: keyToCheck,
619
+ deleteCount: 1,
620
+ inserts: [value]
621
+ });
622
+ }
623
+ }
624
+ function txTimestampToKey(ts) {
625
+ return `${ts.epoch};${ts.clock};${ts.clientId};${ts.wallClock}`;
626
+ }
627
+ function parseTxTimestampKey(key) {
628
+ const i1 = key.indexOf(";");
629
+ const i2 = key.indexOf(";", i1 + 1);
630
+ const i3 = key.indexOf(";", i2 + 1);
631
+ if (i1 === -1 || i2 === -1 || i3 === -1) {
632
+ failure(`Malformed timestamp key: ${key}`);
633
+ }
634
+ return {
635
+ epoch: Number.parseInt(key.substring(0, i1), 10),
636
+ clock: Number.parseInt(key.substring(i1 + 1, i2), 10),
637
+ clientId: key.substring(i2 + 1, i3),
638
+ wallClock: Number.parseInt(key.substring(i3 + 1), 10)
639
+ };
640
+ }
641
+ function compareTxTimestamps(a, b) {
642
+ if (a.epoch !== b.epoch) return a.epoch - b.epoch;
643
+ if (a.clock !== b.clock) return a.clock - b.clock;
644
+ if (a.clientId < b.clientId) return -1;
645
+ if (a.clientId > b.clientId) return 1;
646
+ return 0;
647
+ }
648
+ class SortedTxEntry {
649
+ constructor(txTimestampKey, _yTx) {
650
+ __publicField(this, "_txTimestamp");
651
+ __publicField(this, "_originalTxTimestampKey");
652
+ __publicField(this, "_originalTxTimestamp");
653
+ __publicField(this, "_txRecord");
654
+ this.txTimestampKey = txTimestampKey;
655
+ this._yTx = _yTx;
656
+ }
657
+ /**
658
+ * Gets the parsed timestamp, lazily parsing and caching on first access.
659
+ */
660
+ get txTimestamp() {
661
+ if (!this._txTimestamp) {
662
+ this._txTimestamp = parseTxTimestampKey(this.txTimestampKey);
663
+ }
664
+ return this._txTimestamp;
665
+ }
666
+ /**
667
+ * Gets the original tx timestamp key, lazily and caching on first access.
668
+ */
669
+ get originalTxTimestampKey() {
670
+ var _a;
671
+ if (this._originalTxTimestampKey === void 0) {
672
+ const tx = this.txRecord;
673
+ this._originalTxTimestampKey = (_a = tx.originalTxKey) != null ? _a : null;
674
+ }
675
+ return this._originalTxTimestampKey;
676
+ }
677
+ /**
678
+ * Gets the parsed original tx timestamp, lazily parsing and caching on first access.
679
+ */
680
+ get originalTxTimestamp() {
681
+ if (this._originalTxTimestamp === void 0) {
682
+ const key = this.originalTxTimestampKey;
683
+ this._originalTxTimestamp = key ? parseTxTimestampKey(key) : null;
684
+ }
685
+ return this._originalTxTimestamp;
686
+ }
687
+ /**
688
+ * Gets the logical (deduplicated) tx timestamp key.
689
+ * This is the original tx key if it exists, otherwise the physical key.
690
+ */
691
+ get dedupTxTimestampKey() {
692
+ var _a;
693
+ return (_a = this.originalTxTimestampKey) != null ? _a : this.txTimestampKey;
694
+ }
695
+ /**
696
+ * Gets the logical (deduplicated) parsed tx timestamp.
697
+ * This is the original tx timestamp if it exists, otherwise the physical timestamp.
698
+ */
699
+ get dedupTxTimestamp() {
700
+ var _a;
701
+ return (_a = this.originalTxTimestamp) != null ? _a : this.txTimestamp;
702
+ }
703
+ /**
704
+ * Gets the tx record, lazily fetching and caching on first access.
705
+ * Returns undefined if the tx doesn't exist.
706
+ */
707
+ get txRecord() {
708
+ if (!this._txRecord) {
709
+ this._txRecord = this._yTx.get(this.txTimestampKey);
710
+ if (!this._txRecord) {
711
+ throw failure(`SortedTxEntry: TxRecord not found for key ${this.txTimestampKey}`);
712
+ }
713
+ }
714
+ return this._txRecord;
715
+ }
716
+ }
717
+ function isTransactionInCheckpoint(ts, watermarks) {
718
+ const wm = watermarks[ts.clientId];
719
+ if (!wm) return false;
720
+ return ts.clock <= wm.maxClock;
721
+ }
722
+ class StateCalculator {
723
+ constructor(validateFn) {
724
+ /** Sorted tx cache (ALL active/future txs, kept sorted by timestamp) */
725
+ __publicField(this, "sortedTxs", []);
726
+ /** O(1) existence check and lookup */
727
+ __publicField(this, "sortedTxsMap", /* @__PURE__ */ new Map());
728
+ /**
729
+ * Index of the last transaction applied to cachedState.
730
+ * - null: state needs full recalculation from checkpoint
731
+ * - -1: no transactions have been applied yet (state === checkpoint state)
732
+ * - >= 0: transactions up to and including this index have been applied
733
+ */
734
+ __publicField(this, "lastAppliedIndex", null);
735
+ /** The cached calculated state */
736
+ __publicField(this, "cachedState", null);
737
+ /** The base checkpoint to calculate state from */
738
+ __publicField(this, "baseCheckpoint", null);
739
+ /**
740
+ * Applied dedup keys - tracks which LOGICAL txs have been applied.
741
+ * This is the originalTxKey (or physical key if no original) for each applied tx.
742
+ * Used to properly deduplicate re-emits.
743
+ */
744
+ __publicField(this, "appliedTxKeys", /* @__PURE__ */ new Set());
745
+ /** Max clock seen from any transaction (for Lamport clock updates) */
746
+ __publicField(this, "maxSeenClock", 0);
747
+ /** Validation function (optional) */
748
+ __publicField(this, "validateFn");
749
+ this.validateFn = validateFn;
750
+ }
751
+ /**
752
+ * Sets the base checkpoint. Invalidates cached state if checkpoint changed.
753
+ * @returns true if the checkpoint changed
754
+ */
755
+ setBaseCheckpoint(checkpoint) {
756
+ if (checkpoint === this.baseCheckpoint) {
757
+ return false;
758
+ }
759
+ this.baseCheckpoint = checkpoint;
760
+ this.invalidate();
761
+ return true;
762
+ }
763
+ /**
764
+ * Gets the current base checkpoint.
765
+ */
766
+ getBaseCheckpoint() {
767
+ return this.baseCheckpoint;
768
+ }
769
+ /**
770
+ * Clears all transactions and rebuilds from yTx map.
771
+ * This is used when the checkpoint changes and we need a fresh start.
772
+ */
773
+ rebuildFromYjs(yTx) {
774
+ this.sortedTxs = [];
775
+ this.sortedTxsMap.clear();
776
+ for (const key of yTx.keys()) {
777
+ const entry = new SortedTxEntry(key, yTx);
778
+ this.sortedTxs.push(entry);
779
+ this.sortedTxsMap.set(entry.txTimestampKey, entry);
780
+ if (entry.txTimestamp.clock > this.maxSeenClock) {
781
+ this.maxSeenClock = entry.txTimestamp.clock;
782
+ }
783
+ }
784
+ this.sortedTxs.sort((a, b) => compareTxTimestamps(a.txTimestamp, b.txTimestamp));
785
+ this.invalidate();
786
+ }
787
+ /**
788
+ * Inserts a transaction into the sorted cache.
789
+ * Invalidates cached state if the transaction was inserted before the calculated slice.
790
+ *
791
+ * @returns true if this caused invalidation (out-of-order insert)
792
+ */
793
+ insertTx(key, yTx) {
794
+ if (this.sortedTxsMap.has(key)) {
795
+ return false;
796
+ }
797
+ const entry = new SortedTxEntry(key, yTx);
798
+ const ts = entry.txTimestamp;
799
+ if (ts.clock > this.maxSeenClock) {
800
+ this.maxSeenClock = ts.clock;
801
+ }
802
+ const sortedTxs = this.sortedTxs;
803
+ let insertIndex = sortedTxs.length;
804
+ for (let i = sortedTxs.length - 1; i >= 0; i--) {
805
+ const existingTs = sortedTxs[i].txTimestamp;
806
+ if (compareTxTimestamps(ts, existingTs) >= 0) {
807
+ insertIndex = i + 1;
808
+ break;
809
+ }
810
+ if (i === 0) {
811
+ insertIndex = 0;
812
+ }
813
+ }
814
+ sortedTxs.splice(insertIndex, 0, entry);
815
+ this.sortedTxsMap.set(key, entry);
816
+ if (this.lastAppliedIndex !== null && insertIndex <= this.lastAppliedIndex) {
817
+ this.invalidate();
818
+ return true;
819
+ }
820
+ return false;
821
+ }
822
+ /**
823
+ * Removes multiple transactions from the sorted cache.
824
+ * @returns the number of keys that were actually removed
825
+ */
826
+ removeTxs(keys) {
827
+ if (keys.length === 0) return 0;
828
+ let removedCount = 0;
829
+ let minRemovedIndex = Number.POSITIVE_INFINITY;
830
+ const toDelete = /* @__PURE__ */ new Set();
831
+ for (const key of keys) {
832
+ const entry = this.sortedTxsMap.get(key);
833
+ if (entry) {
834
+ this.sortedTxsMap.delete(key);
835
+ toDelete.add(key);
836
+ const index = this.sortedTxs.indexOf(entry);
837
+ if (index !== -1 && index < minRemovedIndex) {
838
+ minRemovedIndex = index;
839
+ }
840
+ }
841
+ }
842
+ if (toDelete.size === 0) return 0;
843
+ const sortedTxs = this.sortedTxs;
844
+ let i = 0;
845
+ while (i < sortedTxs.length && toDelete.size > 0) {
846
+ if (toDelete.has(sortedTxs[i].txTimestampKey)) {
847
+ toDelete.delete(sortedTxs[i].txTimestampKey);
848
+ sortedTxs.splice(i, 1);
849
+ removedCount++;
850
+ } else {
851
+ i++;
852
+ }
853
+ }
854
+ if (this.lastAppliedIndex !== null && minRemovedIndex <= this.lastAppliedIndex) {
855
+ this.invalidate();
856
+ }
857
+ return removedCount;
858
+ }
859
+ /**
860
+ * Checks if a transaction key exists in the cache.
861
+ */
862
+ hasTx(key) {
863
+ return this.sortedTxsMap.has(key);
864
+ }
865
+ /**
866
+ * Gets a transaction entry by key.
867
+ */
868
+ getTx(key) {
869
+ return this.sortedTxsMap.get(key);
870
+ }
871
+ /**
872
+ * Gets all sorted transaction entries.
873
+ */
874
+ getSortedTxs() {
875
+ return this.sortedTxs;
876
+ }
877
+ /**
878
+ * Gets the number of transactions in the cache.
879
+ */
880
+ get txCount() {
881
+ return this.sortedTxs.length;
882
+ }
883
+ /**
884
+ * Returns true if the state needs full recalculation.
885
+ */
886
+ needsFullRecalculation() {
887
+ return this.lastAppliedIndex === null;
888
+ }
889
+ /**
890
+ * Invalidates the cached state, forcing a full recalculation on next calculateState().
891
+ * Note: cachedState is kept so computeReconcileOps can diff old vs new state.
892
+ */
893
+ invalidate() {
894
+ this.lastAppliedIndex = null;
895
+ }
896
+ /**
897
+ * Calculates and returns the current state, along with a lazy getter for ops that changed from the previous state.
898
+ *
899
+ * - If lastAppliedIndex is null: full recalculation from checkpoint
900
+ * - If lastAppliedIndex >= -1: incremental apply from lastAppliedIndex + 1
901
+ */
902
+ calculateState() {
903
+ var _a, _b, _c, _d;
904
+ const baseState = (_b = (_a = this.baseCheckpoint) == null ? void 0 : _a.state) != null ? _b : {};
905
+ const watermarks = (_d = (_c = this.baseCheckpoint) == null ? void 0 : _c.watermarks) != null ? _d : {};
906
+ const hasWatermarks = Object.keys(watermarks).length > 0;
907
+ if (this.lastAppliedIndex === null) {
908
+ return this.fullRecalculation(baseState, watermarks, hasWatermarks);
909
+ }
910
+ return this.incrementalApply(watermarks, hasWatermarks);
911
+ }
912
+ /**
913
+ * Full recalculation of state from the base checkpoint.
914
+ */
915
+ fullRecalculation(baseState, watermarks, hasWatermarks) {
916
+ var _a;
917
+ const oldState = (_a = this.cachedState) != null ? _a : {};
918
+ this.appliedTxKeys.clear();
919
+ this.lastAppliedIndex = -1;
920
+ this.cachedState = baseState;
921
+ const { state } = this.incrementalApply(watermarks, hasWatermarks, false);
922
+ const getAppliedOps = lazy(() => computeReconcileOps(oldState, state));
923
+ return { state, getAppliedOps };
924
+ }
925
+ /**
926
+ * Incremental apply of transactions from lastAppliedIndex + 1.
927
+ * @param returnOps If true, collects applied transactions (to lazy compute ops). If false, skips collection.
928
+ */
929
+ incrementalApply(watermarks, hasWatermarks, returnOps = true) {
930
+ let state = this.cachedState;
931
+ const appliedTxs = [];
932
+ const sortedTxs = this.sortedTxs;
933
+ const startIndex = this.lastAppliedIndex + 1;
934
+ for (let i = startIndex; i < sortedTxs.length; i++) {
935
+ const entry = sortedTxs[i];
936
+ const dedupKey = entry.dedupTxTimestampKey;
937
+ if (this.appliedTxKeys.has(dedupKey)) {
938
+ continue;
939
+ }
940
+ if (hasWatermarks) {
941
+ const dedupTs = entry.dedupTxTimestamp;
942
+ if (isTransactionInCheckpoint(dedupTs, watermarks)) {
943
+ this.appliedTxKeys.add(dedupKey);
944
+ continue;
945
+ }
946
+ }
947
+ const tx = entry.txRecord;
948
+ const newState = applyTxImmutable(state, tx, this.validateFn);
949
+ if (newState !== state) {
950
+ state = newState;
951
+ if (returnOps) {
952
+ appliedTxs.push(tx);
953
+ }
954
+ }
955
+ this.appliedTxKeys.add(dedupKey);
956
+ this.lastAppliedIndex = i;
957
+ }
958
+ if (sortedTxs.length > 0 && this.lastAppliedIndex < sortedTxs.length - 1) {
959
+ this.lastAppliedIndex = sortedTxs.length - 1;
960
+ }
961
+ this.cachedState = state;
962
+ const getAppliedOps = lazy(() => {
963
+ const ops = [];
964
+ for (const tx of appliedTxs) {
965
+ ops.push(...tx.ops);
966
+ }
967
+ return ops;
968
+ });
969
+ return { state, getAppliedOps };
970
+ }
971
+ /**
972
+ * Gets the max seen clock (for Lamport clock updates).
973
+ */
974
+ getMaxSeenClock() {
975
+ return this.maxSeenClock;
976
+ }
977
+ /**
978
+ * Gets the current cached state without recalculating.
979
+ * Returns null if state has never been calculated.
980
+ */
981
+ getCachedState() {
982
+ return this.cachedState;
983
+ }
984
+ /**
985
+ * Gets the last applied timestamp.
986
+ */
987
+ getLastAppliedTs() {
988
+ var _a, _b;
989
+ if (this.lastAppliedIndex === null || this.lastAppliedIndex < 0) {
990
+ return null;
991
+ }
992
+ return (_b = (_a = this.sortedTxs[this.lastAppliedIndex]) == null ? void 0 : _a.txTimestamp) != null ? _b : null;
993
+ }
994
+ /**
995
+ * Gets the last applied index (for debugging/tracking).
996
+ */
997
+ getLastAppliedIndex() {
998
+ return this.lastAppliedIndex;
999
+ }
1000
+ }
1001
+ function createClientState(validateFn, retentionWindowMs) {
1002
+ return {
1003
+ localClock: 0,
1004
+ cachedFinalizedEpoch: null,
1005
+ // Will be recalculated on first run
1006
+ stateCalculator: new StateCalculator(validateFn),
1007
+ retentionWindowMs
1008
+ };
1009
+ }
1010
+ function appendTx(ops, yTx, activeEpoch, myClientId, clientState, originalKey) {
1011
+ const calc = clientState.stateCalculator;
1012
+ const clock = Math.max(clientState.localClock, calc.getMaxSeenClock()) + 1;
1013
+ clientState.localClock = clock;
1014
+ const ts = {
1015
+ epoch: activeEpoch,
1016
+ clock,
1017
+ clientId: myClientId,
1018
+ wallClock: Date.now()
1019
+ };
1020
+ const key = txTimestampToKey(ts);
1021
+ const record = { ops, originalTxKey: originalKey };
1022
+ yTx.set(key, record);
1023
+ return key;
1024
+ }
1025
+ function syncLog(yTx, myClientId, clientState, finalizedEpoch, baseCP, newKeys) {
1026
+ var _a, _b;
1027
+ const calc = clientState.stateCalculator;
1028
+ const activeEpoch = finalizedEpoch + 1;
1029
+ const watermarks = (_a = baseCP == null ? void 0 : baseCP.watermarks) != null ? _a : {};
1030
+ const referenceTime = (_b = baseCP == null ? void 0 : baseCP.minWallClock) != null ? _b : 0;
1031
+ const shouldPrune = (ts, dedupTs) => {
1032
+ const isAncient = referenceTime - ts.wallClock > clientState.retentionWindowMs;
1033
+ if (isAncient) return true;
1034
+ return isTransactionInCheckpoint(dedupTs, watermarks);
1035
+ };
1036
+ const toDelete = [];
1037
+ const toReEmit = [];
1038
+ const processEntry = (entry) => {
1039
+ if (shouldPrune(entry.txTimestamp, entry.dedupTxTimestamp)) {
1040
+ toDelete.push(entry.txTimestampKey);
1041
+ return false;
1042
+ }
1043
+ if (entry.txTimestamp.epoch <= finalizedEpoch) {
1044
+ toReEmit.push({ originalKey: entry.dedupTxTimestampKey, tx: entry.txRecord });
1045
+ toDelete.push(entry.txTimestampKey);
1046
+ return false;
1047
+ }
1048
+ return true;
1049
+ };
1050
+ for (const entry of calc.getSortedTxs()) {
1051
+ if (processEntry(entry)) {
1052
+ break;
1053
+ }
1054
+ }
1055
+ const processKeyByTimestampKey = (txTimestampKey) => {
1056
+ if (yTx.has(txTimestampKey)) {
1057
+ processEntry(new SortedTxEntry(txTimestampKey, yTx));
1058
+ }
1059
+ };
1060
+ if (newKeys) {
1061
+ for (const key of newKeys) {
1062
+ processKeyByTimestampKey(key);
1063
+ }
1064
+ }
1065
+ for (const { originalKey, tx } of toReEmit) {
1066
+ const newKey = appendTx(tx.ops, yTx, activeEpoch, myClientId, clientState, originalKey);
1067
+ calc.insertTx(newKey, yTx);
1068
+ }
1069
+ for (const key of toDelete) {
1070
+ yTx.delete(key);
1071
+ }
1072
+ calc.removeTxs(toDelete);
1073
+ }
1074
+ function updateState(doc, yTx, yCheckpoint, myClientId, clientState, txChanges) {
1075
+ const calc = clientState.stateCalculator;
1076
+ const { finalizedEpoch, checkpoint: baseCP } = getFinalizedEpochAndCheckpoint(yCheckpoint);
1077
+ clientState.cachedFinalizedEpoch = finalizedEpoch;
1078
+ calc.setBaseCheckpoint(baseCP);
1079
+ const needsRebuildSortedCache = calc.getCachedState() === null || !txChanges;
1080
+ if (needsRebuildSortedCache) {
1081
+ calc.rebuildFromYjs(yTx);
1082
+ } else {
1083
+ calc.removeTxs(txChanges.deleted);
1084
+ }
1085
+ doc.transact(() => {
1086
+ syncLog(yTx, myClientId, clientState, finalizedEpoch, baseCP, txChanges == null ? void 0 : txChanges.added);
1087
+ pruneCheckpoints(yCheckpoint, finalizedEpoch);
1088
+ });
1089
+ if (needsRebuildSortedCache) {
1090
+ return calc.calculateState();
1091
+ }
1092
+ for (const key of txChanges.added) {
1093
+ if (yTx.has(key) && !calc.hasTx(key)) {
1094
+ calc.insertTx(key, yTx);
1095
+ }
1096
+ }
1097
+ return calc.calculateState();
1098
+ }
1099
+ const getSortedTxsSymbol = /* @__PURE__ */ Symbol("getSortedTxs");
1100
+ function createStateSyncLog(options) {
1101
+ const {
1102
+ yDoc,
1103
+ yTxMapName = "state-sync-log-tx",
1104
+ yCheckpointMapName = "state-sync-log-checkpoint",
1105
+ clientId = generateID(),
1106
+ yjsOrigin,
1107
+ validate,
1108
+ retentionWindowMs
1109
+ } = options;
1110
+ if (clientId.includes(";")) {
1111
+ failure(`clientId MUST NOT contain semicolons: ${clientId}`);
1112
+ }
1113
+ const yTx = yDoc.getMap(yTxMapName);
1114
+ const yCheckpoint = yDoc.getMap(yCheckpointMapName);
1115
+ const clientState = createClientState(
1116
+ validate,
1117
+ retentionWindowMs != null ? retentionWindowMs : Number.POSITIVE_INFINITY
1118
+ );
1119
+ const subscribers = /* @__PURE__ */ new Set();
1120
+ const notifySubscribers = (state, getAppliedOps) => {
1121
+ for (const sub of subscribers) {
1122
+ sub(state, getAppliedOps);
1123
+ }
1124
+ };
1125
+ const extractTxChanges = (event) => {
1126
+ const added = [];
1127
+ const deleted = [];
1128
+ for (const [key, change] of event.changes.keys) {
1129
+ if (change.action === "add") {
1130
+ added.push(key);
1131
+ } else if (change.action === "delete") {
1132
+ deleted.push(key);
1133
+ } else if (change.action === "update") {
1134
+ deleted.push(key);
1135
+ added.push(key);
1136
+ }
1137
+ }
1138
+ return { added, deleted };
1139
+ };
1140
+ const emptyTxChanges = { added: [], deleted: [] };
1141
+ const runUpdate = (txChanges) => {
1142
+ const { state, getAppliedOps } = updateState(
1143
+ yDoc,
1144
+ yTx,
1145
+ yCheckpoint,
1146
+ clientId,
1147
+ clientState,
1148
+ txChanges
1149
+ );
1150
+ notifySubscribers(state, getAppliedOps);
1151
+ };
1152
+ const txObserver = (event, _transaction) => {
1153
+ const txChanges = extractTxChanges(event);
1154
+ runUpdate(txChanges);
1155
+ };
1156
+ const checkpointObserver = (_event, _transaction) => {
1157
+ runUpdate(emptyTxChanges);
1158
+ };
1159
+ yCheckpoint.observe(checkpointObserver);
1160
+ yTx.observe(txObserver);
1161
+ runUpdate(void 0);
1162
+ let disposed = false;
1163
+ const assertNotDisposed = () => {
1164
+ if (disposed) {
1165
+ failure("StateSyncLog has been disposed and cannot be used");
1166
+ }
1167
+ };
1168
+ const getActiveEpochInternal = () => {
1169
+ if (clientState.cachedFinalizedEpoch === null) {
1170
+ failure("cachedFinalizedEpoch is null - this should not happen after initialization");
1171
+ }
1172
+ return clientState.cachedFinalizedEpoch + 1;
1173
+ };
1174
+ return {
1175
+ getState() {
1176
+ var _a;
1177
+ assertNotDisposed();
1178
+ return (_a = clientState.stateCalculator.getCachedState()) != null ? _a : {};
1179
+ },
1180
+ subscribe(callback) {
1181
+ assertNotDisposed();
1182
+ subscribers.add(callback);
1183
+ return () => {
1184
+ subscribers.delete(callback);
1185
+ };
1186
+ },
1187
+ emit(ops) {
1188
+ assertNotDisposed();
1189
+ yDoc.transact(() => {
1190
+ const activeEpoch = getActiveEpochInternal();
1191
+ appendTx(ops, yTx, activeEpoch, clientId, clientState);
1192
+ }, yjsOrigin);
1193
+ },
1194
+ reconcileState(targetState) {
1195
+ var _a;
1196
+ assertNotDisposed();
1197
+ const currentState = (_a = clientState.stateCalculator.getCachedState()) != null ? _a : {};
1198
+ const ops = computeReconcileOps(currentState, targetState);
1199
+ if (ops.length > 0) {
1200
+ this.emit(ops);
1201
+ }
1202
+ },
1203
+ compact() {
1204
+ assertNotDisposed();
1205
+ yDoc.transact(() => {
1206
+ var _a;
1207
+ const activeEpoch = getActiveEpochInternal();
1208
+ const currentState = (_a = clientState.stateCalculator.getCachedState()) != null ? _a : {};
1209
+ createCheckpoint(yTx, yCheckpoint, clientState, activeEpoch, currentState, clientId);
1210
+ }, yjsOrigin);
1211
+ },
1212
+ dispose() {
1213
+ if (disposed) return;
1214
+ disposed = true;
1215
+ yTx.unobserve(txObserver);
1216
+ yCheckpoint.unobserve(checkpointObserver);
1217
+ subscribers.clear();
1218
+ },
1219
+ getActiveEpoch() {
1220
+ assertNotDisposed();
1221
+ return getActiveEpochInternal();
1222
+ },
1223
+ getActiveEpochTxCount() {
1224
+ assertNotDisposed();
1225
+ const activeEpoch = getActiveEpochInternal();
1226
+ let count = 0;
1227
+ for (const entry of clientState.stateCalculator.getSortedTxs()) {
1228
+ const ts = entry.txTimestamp;
1229
+ if (ts.epoch === activeEpoch) {
1230
+ count++;
1231
+ } else if (ts.epoch > activeEpoch) {
1232
+ break;
1233
+ }
1234
+ }
1235
+ return count;
1236
+ },
1237
+ getActiveEpochStartTime() {
1238
+ assertNotDisposed();
1239
+ const activeEpoch = getActiveEpochInternal();
1240
+ for (const entry of clientState.stateCalculator.getSortedTxs()) {
1241
+ const ts = entry.txTimestamp;
1242
+ if (ts.epoch === activeEpoch) {
1243
+ return ts.wallClock;
1244
+ } else if (ts.epoch > activeEpoch) {
1245
+ break;
1246
+ }
1247
+ }
1248
+ return void 0;
1249
+ },
1250
+ isLogEmpty() {
1251
+ assertNotDisposed();
1252
+ return yTx.size === 0 && yCheckpoint.size === 0;
1253
+ },
1254
+ [getSortedTxsSymbol]() {
1255
+ assertNotDisposed();
1256
+ return clientState.stateCalculator.getSortedTxs();
1257
+ }
1258
+ };
1259
+ }
1260
+ function resolvePath(state, path) {
1261
+ let current = state;
1262
+ for (const segment of path) {
1263
+ if (typeof segment === "string") {
1264
+ if (!isObject(current) || Array.isArray(current)) {
1265
+ failure(`Expected object at path segment "${segment}"`);
1266
+ }
1267
+ if (!(segment in current)) {
1268
+ failure(`Property "${segment}" does not exist`);
1269
+ }
1270
+ current = current[segment];
1271
+ } else {
1272
+ if (!Array.isArray(current)) {
1273
+ failure(`Expected array at path segment ${segment}`);
1274
+ }
1275
+ if (segment < 0 || segment >= current.length) {
1276
+ failure(`Index ${segment} out of bounds`);
1277
+ }
1278
+ current = current[segment];
1279
+ }
1280
+ }
1281
+ return current;
1282
+ }
1283
+ function applyOp(state, op, cloneValues) {
1284
+ const container = resolvePath(state, op.path);
1285
+ switch (op.kind) {
1286
+ case "set":
1287
+ if (!isObject(container) || Array.isArray(container)) {
1288
+ failure("set requires object container");
1289
+ }
1290
+ container[op.key] = cloneValues ? deepClone(op.value) : op.value;
1291
+ break;
1292
+ case "delete":
1293
+ if (!isObject(container) || Array.isArray(container)) {
1294
+ failure("delete requires object container");
1295
+ }
1296
+ delete container[op.key];
1297
+ break;
1298
+ case "splice": {
1299
+ if (!Array.isArray(container)) {
1300
+ failure("splice requires array container");
1301
+ }
1302
+ const safeIndex = Math.min(op.index, container.length);
1303
+ container.splice(
1304
+ safeIndex,
1305
+ op.deleteCount,
1306
+ ...cloneValues ? op.inserts.map((v) => deepClone(v)) : op.inserts
1307
+ );
1308
+ break;
1309
+ }
1310
+ case "addToSet":
1311
+ if (!Array.isArray(container)) {
1312
+ failure("addToSet requires array container");
1313
+ }
1314
+ if (!container.some((item) => deepEqual(item, op.value))) {
1315
+ container.push(cloneValues ? deepClone(op.value) : op.value);
1316
+ }
1317
+ break;
1318
+ case "deleteFromSet":
1319
+ if (!Array.isArray(container)) {
1320
+ failure("deleteFromSet requires array container");
1321
+ }
1322
+ for (let i = container.length - 1; i >= 0; i--) {
1323
+ if (deepEqual(container[i], op.value)) {
1324
+ container.splice(i, 1);
1325
+ }
1326
+ }
1327
+ break;
1328
+ default:
1329
+ throw failure(`Unknown operation kind: ${op.kind}`);
1330
+ }
1331
+ }
1332
+ function applyOps(ops, target, options) {
1333
+ var _a;
1334
+ const cloneValues = (_a = options == null ? void 0 : options.cloneValues) != null ? _a : true;
1335
+ for (const op of ops) {
1336
+ applyOp(target, op, cloneValues);
1337
+ }
1338
+ }
1339
+ exports2.applyOps = applyOps;
1340
+ exports2.createStateSyncLog = createStateSyncLog;
1341
+ Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
1342
+ }));
1343
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGUtc3luYy1sb2cudW1kLmpzIiwic291cmNlcyI6WyIuLi9zcmMvY2hlY2twb2ludFV0aWxzLnRzIiwiLi4vc3JjL2Vycm9yLnRzIiwiLi4vc3JjL2NoZWNrcG9pbnRzLnRzIiwiLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL2Zhc3QtZGVlcC1lcXVhbEAzLjEuMy9ub2RlX21vZHVsZXMvZmFzdC1kZWVwLWVxdWFsL2luZGV4LmpzIiwiLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL25hbm9pZEA1LjEuNi9ub2RlX21vZHVsZXMvbmFub2lkL3VybC1hbHBoYWJldC9pbmRleC5qcyIsIi4uLy4uLy4uL25vZGVfbW9kdWxlcy8ucG5wbS9uYW5vaWRANS4xLjYvbm9kZV9tb2R1bGVzL25hbm9pZC9pbmRleC5icm93c2VyLmpzIiwiLi4vLi4vLi4vbm9kZV9tb2R1bGVzLy5wbnBtL3JmZGNAMS40LjEvbm9kZV9tb2R1bGVzL3JmZGMvaW5kZXguanMiLCIuLi9zcmMvdXRpbHMudHMiLCIuLi9zcmMvZHJhZnQudHMiLCIuLi9zcmMvcmVjb25jaWxlLnRzIiwiLi4vc3JjL3R4VGltZXN0YW1wLnRzIiwiLi4vc3JjL1NvcnRlZFR4RW50cnkudHMiLCIuLi9zcmMvU3RhdGVDYWxjdWxhdG9yLnRzIiwiLi4vc3JjL2NsaWVudFN0YXRlLnRzIiwiLi4vc3JjL3R4TG9nLnRzIiwiLi4vc3JjL2NyZWF0ZVN0YXRlU3luY0xvZy50cyIsIi4uL3NyYy9vcGVyYXRpb25zLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyB0eXBlIENoZWNrcG9pbnRSZWNvcmQsIHBhcnNlQ2hlY2twb2ludEtleSB9IGZyb20gXCIuL2NoZWNrcG9pbnRzXCJcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBmaW5hbGl6ZWQgZXBvY2ggYW5kIGl0cyBjYW5vbmljYWwgY2hlY2twb2ludCBpbiBhIHNpbmdsZSBwYXNzLlxuICpcbiAqIFBvbGljeSBBOiBUaGUgZmluYWxpemVkIGVwb2NoIGlzIHRoZSBtb3N0IHJlY2VudCBlcG9jaCB3aXRoIGEgY2hlY2twb2ludC5cbiAqIENhbm9uaWNhbCBjaGVja3BvaW50OiBUaGUgY2hlY2twb2ludCB3aXRoIGhpZ2hlc3QgdHhDb3VudCBmb3IgdGhhdCBlcG9jaFxuICogKHRpZS1icmVhazogbG93ZXN0IGNsaWVudElkIGFscGhhYmV0aWNhbGx5KS5cbiAqXG4gKiBSZXR1cm5zIHsgZmluYWxpemVkRXBvY2g6IC0xLCBjaGVja3BvaW50OiBudWxsIH0gaWYgbm8gY2hlY2twb2ludHMgZXhpc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGaW5hbGl6ZWRFcG9jaEFuZENoZWNrcG9pbnQoeUNoZWNrcG9pbnQ6IFkuTWFwPENoZWNrcG9pbnRSZWNvcmQ+KToge1xuICBmaW5hbGl6ZWRFcG9jaDogbnVtYmVyXG4gIGNoZWNrcG9pbnQ6IENoZWNrcG9pbnRSZWNvcmQgfCBudWxsXG59IHtcbiAgbGV0IG1heEVwb2NoID0gLTFcbiAgbGV0IGJlc3Q6IENoZWNrcG9pbnRSZWNvcmQgfCBudWxsID0gbnVsbFxuICBsZXQgYmVzdFR4Q291bnQgPSAtMVxuICBsZXQgYmVzdENsaWVudElkID0gXCJcIlxuXG4gIGZvciAoY29uc3QgW2tleSwgY3BdIG9mIHlDaGVja3BvaW50LmVudHJpZXMoKSkge1xuICAgIGNvbnN0IHsgZXBvY2gsIGNsaWVudElkIH0gPSBwYXJzZUNoZWNrcG9pbnRLZXkoa2V5KVxuXG4gICAgaWYgKGVwb2NoID4gbWF4RXBvY2gpIHtcbiAgICAgIC8vIE5ldyBoaWdoZXN0IGVwb2NoIC0gcmVzZXQgYmVzdCBjaGVja3BvaW50IHRyYWNraW5nXG4gICAgICBtYXhFcG9jaCA9IGVwb2NoXG4gICAgICBiZXN0ID0gY3BcbiAgICAgIGJlc3RUeENvdW50ID0gY3AudHhDb3VudFxuICAgICAgYmVzdENsaWVudElkID0gY2xpZW50SWRcbiAgICB9IGVsc2UgaWYgKGVwb2NoID09PSBtYXhFcG9jaCkge1xuICAgICAgLy8gU2FtZSBlcG9jaCAtIGNoZWNrIGlmIHRoaXMgaXMgYSBiZXR0ZXIgY2Fub25pY2FsIGNoZWNrcG9pbnRcbiAgICAgIC8vIFByaW1hcnk6IGhpZ2hlciB0eENvdW50IHdpbnNcbiAgICAgIC8vIFNlY29uZGFyeSAodGllLWJyZWFrKTogbG93ZXIgY2xpZW50SWQgKGFscGhhYmV0aWNhbGx5KSB3aW5zXG4gICAgICBpZiAoY3AudHhDb3VudCA+IGJlc3RUeENvdW50IHx8IChjcC50eENvdW50ID09PSBiZXN0VHhDb3VudCAmJiBjbGllbnRJZCA8IGJlc3RDbGllbnRJZCkpIHtcbiAgICAgICAgYmVzdCA9IGNwXG4gICAgICAgIGJlc3RUeENvdW50ID0gY3AudHhDb3VudFxuICAgICAgICBiZXN0Q2xpZW50SWQgPSBjbGllbnRJZFxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IGZpbmFsaXplZEVwb2NoOiBtYXhFcG9jaCwgY2hlY2twb2ludDogYmVzdCB9XG59XG4iLCJleHBvcnQgY2xhc3MgU3RhdGVTeW5jTG9nRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1zZzogc3RyaW5nKSB7XG4gICAgc3VwZXIobXNnKVxuXG4gICAgLy8gU2V0IHRoZSBwcm90b3R5cGUgZXhwbGljaXRseSBmb3IgYmV0dGVyIGluc3RhbmNlb2Ygc3VwcG9ydFxuICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBTdGF0ZVN5bmNMb2dFcnJvci5wcm90b3R5cGUpXG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZhaWx1cmUobWVzc2FnZTogc3RyaW5nKTogbmV2ZXIge1xuICB0aHJvdyBuZXcgU3RhdGVTeW5jTG9nRXJyb3IobWVzc2FnZSlcbn1cbiIsImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBDbGllbnRJZCB9IGZyb20gXCIuL0NsaWVudElkXCJcbmltcG9ydCB7IGdldEZpbmFsaXplZEVwb2NoQW5kQ2hlY2twb2ludCB9IGZyb20gXCIuL2NoZWNrcG9pbnRVdGlsc1wiXG5pbXBvcnQgeyBDbGllbnRTdGF0ZSB9IGZyb20gXCIuL2NsaWVudFN0YXRlXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi9lcnJvclwiXG5pbXBvcnQgeyBKU09OT2JqZWN0IH0gZnJvbSBcIi4vanNvblwiXG5pbXBvcnQgeyBUeFJlY29yZCB9IGZyb20gXCIuL1R4UmVjb3JkXCJcbmltcG9ydCB7IFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuXG4vKipcbiAqIFdhdGVybWFya2luZyBmb3IgZGVkdXBsaWNhdGlvbiBhbmQgcHJ1bmluZy5cbiAqIC0gbWF4Q2xvY2s6IEFsbCB0eHMgZnJvbSB0aGlzIGNsaWVudCB3aXRoIGNsb2NrIDw9IG1heENsb2NrIGFyZSBGSU5BTElaRUQuXG4gKiAtIG1heFdhbGxDbG9jazogVGhlIGxhc3QgdGltZSB3ZSBzYXcgdGhpcyBjbGllbnQgYWN0aXZlIChmb3IgcHJ1bmluZykuXG4gKi9cbnR5cGUgQ2xpZW50V2F0ZXJtYXJrID0gUmVhZG9ubHk8e1xuICBtYXhDbG9jazogbnVtYmVyXG4gIG1heFdhbGxDbG9jazogbnVtYmVyXG59PlxuXG4vKipcbiAqIFdhdGVybWFya3MgZm9yIGFsbCBjbGllbnRzLlxuICovXG5leHBvcnQgdHlwZSBDbGllbnRXYXRlcm1hcmtzID0gUmVjb3JkPENsaWVudElkLCBDbGllbnRXYXRlcm1hcms+XG5cbi8qKlxuICogQSBzbmFwc2hvdCBvZiB0aGUgc3RhdGUgYXQgdGhlIGVuZCBvZiBhIHNwZWNpZmljIGVwb2NoLlxuICovXG5leHBvcnQgdHlwZSBDaGVja3BvaW50UmVjb3JkID0ge1xuICBzdGF0ZTogSlNPTk9iamVjdCAvLyBUaGUgZG9jdW1lbnQgc3RhdGVcbiAgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyAvLyBEZWR1cC9QcnVuaW5nIGluZm9cbiAgdHhDb3VudDogbnVtYmVyIC8vIFRpZS1icmVha2VyIGZvciBjYW5vbmljYWwgc2VsZWN0aW9uXG4gIG1pbldhbGxDbG9jazogbnVtYmVyIC8vIFJlZmVyZW5jZSB0aW1lIGZvciB0aGlzIGVwb2NoIChkZXRlcm1pbmlzdGljIHBydW5pbmcpXG59XG5cbi8qKlxuICogVW5pcXVlIElEIGZvciBhIGNoZWNrcG9pbnQuXG4gKiBGb3JtYXQ6IGAke2Vwb2NofTske3R4Q291bnR9OyR7Y2xpZW50SWR9YFxuICovXG5leHBvcnQgdHlwZSBDaGVja3BvaW50S2V5ID0gc3RyaW5nXG5cbi8qKlxuICogRGF0YSBleHRyYWN0ZWQgZnJvbSBhIGNoZWNrcG9pbnQga2V5LlxuICovXG5leHBvcnQgdHlwZSBDaGVja3BvaW50S2V5RGF0YSA9IHtcbiAgZXBvY2g6IG51bWJlclxuICB0eENvdW50OiBudW1iZXJcbiAgY2xpZW50SWQ6IENsaWVudElkXG59XG5cbi8qKlxuICogQ29udmVydHMgY2hlY2twb2ludCBrZXkgZGF0YSBjb21wb25lbnRzIHRvIGEga2V5IHN0cmluZy5cbiAqL1xuZnVuY3Rpb24gY2hlY2twb2ludEtleURhdGFUb0tleShkYXRhOiBDaGVja3BvaW50S2V5RGF0YSk6IENoZWNrcG9pbnRLZXkge1xuICByZXR1cm4gYCR7ZGF0YS5lcG9jaH07JHtkYXRhLnR4Q291bnR9OyR7ZGF0YS5jbGllbnRJZH1gXG59XG5cbi8qKlxuICogSGVscGVyIHRvIHBhcnNlIGNoZWNrcG9pbnQga2V5cy5cbiAqIENoZWNrcG9pbnQga2V5cyBoYXZlIGZvcm1hdDogYCR7ZXBvY2h9OyR7dHhDb3VudH07JHtjbGllbnRJZH1gXG4gKiBUaHJvd3MgaWYga2V5IGlzIG1hbGZvcm1lZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ2hlY2twb2ludEtleShrZXk6IENoZWNrcG9pbnRLZXkpOiBDaGVja3BvaW50S2V5RGF0YSB7XG4gIGNvbnN0IGkxID0ga2V5LmluZGV4T2YoXCI7XCIpXG4gIGNvbnN0IGkyID0ga2V5LmluZGV4T2YoXCI7XCIsIGkxICsgMSlcblxuICBpZiAoaTEgPT09IC0xIHx8IGkyID09PSAtMSkge1xuICAgIGZhaWx1cmUoYE1hbGZvcm1lZCBjaGVja3BvaW50IGtleTogJHtrZXl9YClcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZXBvY2g6IE51bWJlci5wYXJzZUludChrZXkuc3Vic3RyaW5nKDAsIGkxKSwgMTApLFxuICAgIHR4Q291bnQ6IE51bWJlci5wYXJzZUludChrZXkuc3Vic3RyaW5nKGkxICsgMSwgaTIpLCAxMCksXG4gICAgY2xpZW50SWQ6IGtleS5zdWJzdHJpbmcoaTIgKyAxKSxcbiAgfVxufVxuXG4vKipcbiAqIENhbGxlZCBwZXJpb2RpY2FsbHkgKGUuZy4gYnkgYSBzZXJ2ZXIgb3IgbGVhZGVyIGNsaWVudCkgdG8gZmluYWxpemUgdGhlIGVwb2NoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQ2hlY2twb2ludChcbiAgeVR4OiBZLk1hcDxUeFJlY29yZD4sXG4gIHlDaGVja3BvaW50OiBZLk1hcDxDaGVja3BvaW50UmVjb3JkPixcbiAgY2xpZW50U3RhdGU6IENsaWVudFN0YXRlLFxuICBhY3RpdmVFcG9jaDogbnVtYmVyLFxuICBjdXJyZW50U3RhdGU6IEpTT05PYmplY3QsXG4gIG15Q2xpZW50SWQ6IHN0cmluZ1xuKTogdm9pZCB7XG4gIC8vIDEuIFN0YXJ0IHdpdGggcHJldmlvdXMgd2F0ZXJtYXJrcyAoZnJvbSBmaW5hbGl6ZWQgZXBvY2ggPSBhY3RpdmVFcG9jaCAtIDEpXG4gIGNvbnN0IHsgY2hlY2twb2ludDogcHJldkNQIH0gPSBnZXRGaW5hbGl6ZWRFcG9jaEFuZENoZWNrcG9pbnQoeUNoZWNrcG9pbnQpXG4gIGNvbnN0IG5ld1dhdGVybWFya3MgPSBwcmV2Q1AgPyB7IC4uLnByZXZDUC53YXRlcm1hcmtzIH0gOiB7fVxuXG4gIC8vIEdldCBhY3RpdmUgdHhzIHVzaW5nIGNhY2hlZCBzb3J0ZWQgb3JkZXIgKGZpbHRlciBieSBlcG9jaClcbiAgLy8gRklMVEVSIElTIFJFUVVJUkVEOlxuICAvLyBBbHRob3VnaCB3ZSBhcmUgZmluYWxpemluZyAnYWN0aXZlRXBvY2gnLCBvdGhlciBwZWVycyBtYXkgaGF2ZSBhbHJlYWR5XG4gIC8vIGFkdmFuY2VkIHRvIHRoZSBuZXh0IGVwb2NoIGFuZCBzdGFydGVkIHN5bmNpbmcgdGhvc2UgdHhzLlxuICAvLyBXZSBtdXN0IGVuc3VyZSB0aGlzIGNoZWNrcG9pbnQgT05MWSBjb250YWlucyB0eHMgZnJvbSAnYWN0aXZlRXBvY2gnLlxuICAvLyBVc2luZyBzdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzIGF2b2lkcyByZWR1bmRhbnQga2V5IHBhcnNpbmcgKHRpbWVzdGFtcHMgYXJlIGNhY2hlZCkuXG4gIC8vXG4gIC8vIE9QVElNSVpBVElPTjogU2luY2Ugc29ydGVkVHhzIGlzIHNvcnRlZCBieSBlcG9jaCAocHJpbWFyeSBrZXkpIGFuZCBwYXN0IGVwb2Noc1xuICAvLyBhcmUgcHJ1bmVkLCB3ZSBvbmx5IG5lZWQgdG8gZmluZCB0aGUgcmlnaHQgYm91bmRhcnkuIEZ1dHVyZSBlcG9jaHMgYXJlIHJhcmUsXG4gIC8vIHNvIGEgc2ltcGxlIGxpbmVhciBzZWFyY2ggZnJvbSB0aGUgcmlnaHQgaXMgZWZmaWNpZW50ICh0eXBpY2FsbHkgMC0xIGl0ZXJhdGlvbnMpLlxuICBjb25zdCBzb3J0ZWRUeHMgPSBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzKClcblxuICAvLyBGaW5kIGVuZCBib3VuZGFyeSBieSBzZWFyY2hpbmcgZnJvbSByaWdodCAoc2tpcCBhbnkgZnV0dXJlIGVwb2NoIGVudHJpZXMpXG4gIGxldCBlbmRJbmRleCA9IHNvcnRlZFR4cy5sZW5ndGhcbiAgd2hpbGUgKGVuZEluZGV4ID4gMCAmJiBzb3J0ZWRUeHNbZW5kSW5kZXggLSAxXS50eFRpbWVzdGFtcC5lcG9jaCA+IGFjdGl2ZUVwb2NoKSB7XG4gICAgZW5kSW5kZXgtLVxuICB9XG5cbiAgLy8gU2xpY2UgZnJvbSBzdGFydCB0byBlbmRJbmRleCAocGFzdCBlcG9jaHMgYXJlIHBydW5lZCwgc28gdGhlc2UgYXJlIGFsbCBhY3RpdmVFcG9jaClcbiAgY29uc3QgYWN0aXZlVHhzID0gc29ydGVkVHhzLnNsaWNlKDAsIGVuZEluZGV4KVxuXG4gIGlmIChhY3RpdmVUeHMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIC8vIERvIG5vdGhpbmcgaWYgbm8gdHhzIChwcmV2ZW50cyBlbXB0eSBlcG9jaHMpXG4gIH1cblxuICAvLyAyLiBVcGRhdGUgd2F0ZXJtYXJrcyBiYXNlZCBvbiBPQlNFUlZFRCBhY3RpdmUgdHhzIGFuZCBjYWxjdWxhdGUgbWluV2FsbENsb2NrXG4gIC8vIE5PVEU6IFdlIGNhbm5vdCB1c2UgYWN0aXZlVHhzWzBdLnR4VGltZXN0YW1wLndhbGxDbG9jayBmb3IgbWluV2FsbENsb2NrIGJlY2F1c2VcbiAgLy8gdHhzIGFyZSBzb3J0ZWQgYnkgTGFtcG9ydCBjbG9jayAoZXBvY2gg4oaSIGNsb2NrIOKGkiBjbGllbnRJZCksIG5vdCBieSB3YWxsQ2xvY2suXG4gIC8vIEEgY2xpZW50IG1heSBoYXZlIGEgaGlnaCBMYW1wb3J0IGNsb2NrIGJ1dCBlYXJseSB3YWxsQ2xvY2sgZHVlIHRvIGNsb2NrIGRyaWZ0XG4gIC8vIG9yIHJlY2VpdmluZyBtYW55IG1lc3NhZ2VzIGJlZm9yZSBlbWl0dGluZy5cbiAgbGV0IG1pbldhbGxDbG9jayA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWVxuICBsZXQgdHhDb3VudCA9IDBcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBhY3RpdmVUeHMpIHtcbiAgICBjb25zdCB0cyA9IGVudHJ5LnR4VGltZXN0YW1wXG5cbiAgICAvLyBUcmFjayBtaW4gd2FsbENsb2NrIGZvciBkZXRlcm1pbmlzdGljIHBydW5pbmcgcmVmZXJlbmNlXG4gICAgaWYgKHRzLndhbGxDbG9jayA8IG1pbldhbGxDbG9jaykge1xuICAgICAgbWluV2FsbENsb2NrID0gdHMud2FsbENsb2NrXG4gICAgfVxuXG4gICAgY29uc3QgbmV3V20gPSBuZXdXYXRlcm1hcmtzW3RzLmNsaWVudElkXVxuICAgICAgPyB7IC4uLm5ld1dhdGVybWFya3NbdHMuY2xpZW50SWRdIH1cbiAgICAgIDogeyBtYXhDbG9jazogLTEsIG1heFdhbGxDbG9jazogMCB9XG5cbiAgICBpZiAodHMuY2xvY2sgPiBuZXdXbS5tYXhDbG9jaykge1xuICAgICAgbmV3V20ubWF4Q2xvY2sgPSB0cy5jbG9ja1xuICAgICAgbmV3V20ubWF4V2FsbENsb2NrID0gdHMud2FsbENsb2NrXG4gICAgfVxuICAgIG5ld1dhdGVybWFya3NbdHMuY2xpZW50SWRdID0gbmV3V21cbiAgICB0eENvdW50KytcbiAgfVxuXG4gIC8vIDMuIFBydW5lIEluYWN0aXZlIFdhdGVybWFya3MgKERldGVybWluaXN0aWMpXG4gIC8vIFVzZXMgbWluV2FsbENsb2NrIHNvIGFsbCBjbGllbnRzIGFncmVlIG9uIGV4YWN0bHkgd2hvIHRvIHBydW5lLlxuICBmb3IgKGNvbnN0IGNsaWVudElkIGluIG5ld1dhdGVybWFya3MpIHtcbiAgICBpZiAobWluV2FsbENsb2NrIC0gbmV3V2F0ZXJtYXJrc1tjbGllbnRJZF0ubWF4V2FsbENsb2NrID4gY2xpZW50U3RhdGUucmV0ZW50aW9uV2luZG93TXMpIHtcbiAgICAgIGRlbGV0ZSBuZXdXYXRlcm1hcmtzW2NsaWVudElkXVxuICAgIH1cbiAgfVxuXG4gIC8vIDQuIFNhdmUgQ2hlY2twb2ludFxuICBjb25zdCBjcEtleSA9IGNoZWNrcG9pbnRLZXlEYXRhVG9LZXkoe1xuICAgIGVwb2NoOiBhY3RpdmVFcG9jaCxcbiAgICB0eENvdW50LFxuICAgIGNsaWVudElkOiBteUNsaWVudElkLFxuICB9KVxuICB5Q2hlY2twb2ludC5zZXQoY3BLZXksIHtcbiAgICBzdGF0ZTogY3VycmVudFN0YXRlLCAvLyBSZXNwb25zaWJpbGl0eSBmb3IgY2xvbmluZyBpcyBtb3ZlZCB0byB0aGUgY2FsbGVyIGlmIG5lZWRlZFxuICAgIHdhdGVybWFya3M6IG5ld1dhdGVybWFya3MsXG4gICAgdHhDb3VudCxcbiAgICBtaW5XYWxsQ2xvY2ssXG4gIH0pXG5cbiAgLy8gNS4gRWFybHkgdHggcHJ1bmluZyAoT3B0aW1pemF0aW9uKVxuICAvLyBEZWxldGUgYWxsIHR4cyBmcm9tIHRoZSBub3ctZmluYWxpemVkIGVwb2NoXG4gIC8vIFRoaXMgcmVkdWNlcyBtZW1vcnkgcHJlc3N1cmUgaW5zdGVhZCBvZiB3YWl0aW5nIGZvciBjbGVhbnVwTG9nXG4gIGNvbnN0IGtleXNUb0RlbGV0ZTogVHhUaW1lc3RhbXBLZXlbXSA9IFtdXG4gIGZvciAoY29uc3QgZW50cnkgb2YgYWN0aXZlVHhzKSB7XG4gICAgeVR4LmRlbGV0ZShlbnRyeS50eFRpbWVzdGFtcEtleSlcbiAgICBrZXlzVG9EZWxldGUucHVzaChlbnRyeS50eFRpbWVzdGFtcEtleSlcbiAgfVxuICBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IucmVtb3ZlVHhzKGtleXNUb0RlbGV0ZSlcbn1cblxuLyoqXG4gKiBHYXJiYWdlIGNvbGxlY3RzIG9sZCBjaGVja3BvaW50cy5cbiAqIFNob3VsZCBiZSBjYWxsZWQgcGVyaW9kaWNhbGx5IHRvIHByZXZlbnQgdW5ib3VuZGVkIGdyb3d0aCBvZiB5Q2hlY2twb2ludC5cbiAqXG4gKiBLZWVwcyBvbmx5IHRoZSBjYW5vbmljYWwgY2hlY2twb2ludCBmb3IgdGhlIGZpbmFsaXplZCBlcG9jaC5cbiAqIEV2ZXJ5dGhpbmcgZWxzZSBpcyBkZWxldGVkIChvbGQgZXBvY2hzICsgbm9uLWNhbm9uaWNhbCkuXG4gKlxuICogTm90ZTogVGhlIGFjdGl2ZSBlcG9jaCBuZXZlciBoYXMgY2hlY2twb2ludHMgLSBjcmVhdGluZyBhIGNoZWNrcG9pbnRcbiAqIGZvciBhbiBlcG9jaCBpbW1lZGlhdGVseSBtYWtlcyBpdCBmaW5hbGl6ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcnVuZUNoZWNrcG9pbnRzKFxuICB5Q2hlY2twb2ludDogWS5NYXA8Q2hlY2twb2ludFJlY29yZD4sXG4gIGZpbmFsaXplZEVwb2NoOiBudW1iZXJcbik6IHZvaWQge1xuICAvLyBGaW5kIHRoZSBjYW5vbmljYWwgY2hlY2twb2ludCBhbmQgaXRzIGtleSBpbiBvbmUgcGFzc1xuICBsZXQgY2Fub25pY2FsS2V5OiBDaGVja3BvaW50S2V5IHwgbnVsbCA9IG51bGxcbiAgbGV0IGJlc3RUeENvdW50ID0gLTFcblxuICBmb3IgKGNvbnN0IFtrZXldIG9mIHlDaGVja3BvaW50LmVudHJpZXMoKSkge1xuICAgIGNvbnN0IHsgZXBvY2gsIHR4Q291bnQgfSA9IHBhcnNlQ2hlY2twb2ludEtleShrZXkpXG4gICAgaWYgKGVwb2NoID09PSBmaW5hbGl6ZWRFcG9jaCAmJiB0eENvdW50ID4gYmVzdFR4Q291bnQpIHtcbiAgICAgIGNhbm9uaWNhbEtleSA9IGtleVxuICAgICAgYmVzdFR4Q291bnQgPSB0eENvdW50XG4gICAgfVxuICB9XG5cbiAgLy8gRGVsZXRlIGV2ZXJ5dGhpbmcgZXhjZXB0IHRoZSBjYW5vbmljYWwgY2hlY2twb2ludFxuICBmb3IgKGNvbnN0IGtleSBvZiB5Q2hlY2twb2ludC5rZXlzKCkpIHtcbiAgICBpZiAoa2V5ICE9PSBjYW5vbmljYWxLZXkpIHtcbiAgICAgIHlDaGVja3BvaW50LmRlbGV0ZShrZXkpXG4gICAgfVxuICB9XG59XG4iLCIndXNlIHN0cmljdCc7XG5cbi8vIGRvIG5vdCBlZGl0IC5qcyBmaWxlcyBkaXJlY3RseSAtIGVkaXQgc3JjL2luZGV4LmpzdFxuXG5cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBlcXVhbChhLCBiKSB7XG4gIGlmIChhID09PSBiKSByZXR1cm4gdHJ1ZTtcblxuICBpZiAoYSAmJiBiICYmIHR5cGVvZiBhID09ICdvYmplY3QnICYmIHR5cGVvZiBiID09ICdvYmplY3QnKSB7XG4gICAgaWYgKGEuY29uc3RydWN0b3IgIT09IGIuY29uc3RydWN0b3IpIHJldHVybiBmYWxzZTtcblxuICAgIHZhciBsZW5ndGgsIGksIGtleXM7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkoYSkpIHtcbiAgICAgIGxlbmd0aCA9IGEubGVuZ3RoO1xuICAgICAgaWYgKGxlbmd0aCAhPSBiLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gIT09IDA7KVxuICAgICAgICBpZiAoIWVxdWFsKGFbaV0sIGJbaV0pKSByZXR1cm4gZmFsc2U7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cblxuXG4gICAgaWYgKGEuY29uc3RydWN0b3IgPT09IFJlZ0V4cCkgcmV0dXJuIGEuc291cmNlID09PSBiLnNvdXJjZSAmJiBhLmZsYWdzID09PSBiLmZsYWdzO1xuICAgIGlmIChhLnZhbHVlT2YgIT09IE9iamVjdC5wcm90b3R5cGUudmFsdWVPZikgcmV0dXJuIGEudmFsdWVPZigpID09PSBiLnZhbHVlT2YoKTtcbiAgICBpZiAoYS50b1N0cmluZyAhPT0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZykgcmV0dXJuIGEudG9TdHJpbmcoKSA9PT0gYi50b1N0cmluZygpO1xuXG4gICAga2V5cyA9IE9iamVjdC5rZXlzKGEpO1xuICAgIGxlbmd0aCA9IGtleXMubGVuZ3RoO1xuICAgIGlmIChsZW5ndGggIT09IE9iamVjdC5rZXlzKGIpLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gIT09IDA7KVxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoYiwga2V5c1tpXSkpIHJldHVybiBmYWxzZTtcblxuICAgIGZvciAoaSA9IGxlbmd0aDsgaS0tICE9PSAwOykge1xuICAgICAgdmFyIGtleSA9IGtleXNbaV07XG5cbiAgICAgIGlmICghZXF1YWwoYVtrZXldLCBiW2tleV0pKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyB0cnVlIGlmIGJvdGggTmFOLCBmYWxzZSBvdGhlcndpc2VcbiAgcmV0dXJuIGEhPT1hICYmIGIhPT1iO1xufTtcbiIsImV4cG9ydCBjb25zdCB1cmxBbHBoYWJldCA9XG4gICd1c2VhbmRvbS0yNlQxOTgzNDBQWDc1cHhKQUNLVkVSWU1JTkRCVVNIV09MRl9HUVpiZmdoamtscXZ3eXpyaWN0J1xuIiwiLyogQHRzLXNlbGYtdHlwZXM9XCIuL2luZGV4LmQudHNcIiAqL1xuaW1wb3J0IHsgdXJsQWxwaGFiZXQgYXMgc2NvcGVkVXJsQWxwaGFiZXQgfSBmcm9tICcuL3VybC1hbHBoYWJldC9pbmRleC5qcydcbmV4cG9ydCB7IHVybEFscGhhYmV0IH0gZnJvbSAnLi91cmwtYWxwaGFiZXQvaW5kZXguanMnXG5leHBvcnQgbGV0IHJhbmRvbSA9IGJ5dGVzID0+IGNyeXB0by5nZXRSYW5kb21WYWx1ZXMobmV3IFVpbnQ4QXJyYXkoYnl0ZXMpKVxuZXhwb3J0IGxldCBjdXN0b21SYW5kb20gPSAoYWxwaGFiZXQsIGRlZmF1bHRTaXplLCBnZXRSYW5kb20pID0+IHtcbiAgbGV0IG1hc2sgPSAoMiA8PCBNYXRoLmxvZzIoYWxwaGFiZXQubGVuZ3RoIC0gMSkpIC0gMVxuICBsZXQgc3RlcCA9IC1+KCgxLjYgKiBtYXNrICogZGVmYXVsdFNpemUpIC8gYWxwaGFiZXQubGVuZ3RoKVxuICByZXR1cm4gKHNpemUgPSBkZWZhdWx0U2l6ZSkgPT4ge1xuICAgIGxldCBpZCA9ICcnXG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGxldCBieXRlcyA9IGdldFJhbmRvbShzdGVwKVxuICAgICAgbGV0IGogPSBzdGVwIHwgMFxuICAgICAgd2hpbGUgKGotLSkge1xuICAgICAgICBpZCArPSBhbHBoYWJldFtieXRlc1tqXSAmIG1hc2tdIHx8ICcnXG4gICAgICAgIGlmIChpZC5sZW5ndGggPj0gc2l6ZSkgcmV0dXJuIGlkXG4gICAgICB9XG4gICAgfVxuICB9XG59XG5leHBvcnQgbGV0IGN1c3RvbUFscGhhYmV0ID0gKGFscGhhYmV0LCBzaXplID0gMjEpID0+XG4gIGN1c3RvbVJhbmRvbShhbHBoYWJldCwgc2l6ZSB8IDAsIHJhbmRvbSlcbmV4cG9ydCBsZXQgbmFub2lkID0gKHNpemUgPSAyMSkgPT4ge1xuICBsZXQgaWQgPSAnJ1xuICBsZXQgYnl0ZXMgPSBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKG5ldyBVaW50OEFycmF5KChzaXplIHw9IDApKSlcbiAgd2hpbGUgKHNpemUtLSkge1xuICAgIGlkICs9IHNjb3BlZFVybEFscGhhYmV0W2J5dGVzW3NpemVdICYgNjNdXG4gIH1cbiAgcmV0dXJuIGlkXG59XG4iLCIndXNlIHN0cmljdCdcbm1vZHVsZS5leHBvcnRzID0gcmZkY1xuXG5mdW5jdGlvbiBjb3B5QnVmZmVyIChjdXIpIHtcbiAgaWYgKGN1ciBpbnN0YW5jZW9mIEJ1ZmZlcikge1xuICAgIHJldHVybiBCdWZmZXIuZnJvbShjdXIpXG4gIH1cblxuICByZXR1cm4gbmV3IGN1ci5jb25zdHJ1Y3RvcihjdXIuYnVmZmVyLnNsaWNlKCksIGN1ci5ieXRlT2Zmc2V0LCBjdXIubGVuZ3RoKVxufVxuXG5mdW5jdGlvbiByZmRjIChvcHRzKSB7XG4gIG9wdHMgPSBvcHRzIHx8IHt9XG4gIGlmIChvcHRzLmNpcmNsZXMpIHJldHVybiByZmRjQ2lyY2xlcyhvcHRzKVxuXG4gIGNvbnN0IGNvbnN0cnVjdG9ySGFuZGxlcnMgPSBuZXcgTWFwKClcbiAgY29uc3RydWN0b3JIYW5kbGVycy5zZXQoRGF0ZSwgKG8pID0+IG5ldyBEYXRlKG8pKVxuICBjb25zdHJ1Y3RvckhhbmRsZXJzLnNldChNYXAsIChvLCBmbikgPT4gbmV3IE1hcChjbG9uZUFycmF5KEFycmF5LmZyb20obyksIGZuKSkpXG4gIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KFNldCwgKG8sIGZuKSA9PiBuZXcgU2V0KGNsb25lQXJyYXkoQXJyYXkuZnJvbShvKSwgZm4pKSlcbiAgaWYgKG9wdHMuY29uc3RydWN0b3JIYW5kbGVycykge1xuICAgIGZvciAoY29uc3QgaGFuZGxlciBvZiBvcHRzLmNvbnN0cnVjdG9ySGFuZGxlcnMpIHtcbiAgICAgIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KGhhbmRsZXJbMF0sIGhhbmRsZXJbMV0pXG4gICAgfVxuICB9XG5cbiAgbGV0IGhhbmRsZXIgPSBudWxsXG5cbiAgcmV0dXJuIG9wdHMucHJvdG8gPyBjbG9uZVByb3RvIDogY2xvbmVcblxuICBmdW5jdGlvbiBjbG9uZUFycmF5IChhLCBmbikge1xuICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhhKVxuICAgIGNvbnN0IGEyID0gbmV3IEFycmF5KGtleXMubGVuZ3RoKVxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgayA9IGtleXNbaV1cbiAgICAgIGNvbnN0IGN1ciA9IGFba11cbiAgICAgIGlmICh0eXBlb2YgY3VyICE9PSAnb2JqZWN0JyB8fCBjdXIgPT09IG51bGwpIHtcbiAgICAgICAgYTJba10gPSBjdXJcbiAgICAgIH0gZWxzZSBpZiAoY3VyLmNvbnN0cnVjdG9yICE9PSBPYmplY3QgJiYgKGhhbmRsZXIgPSBjb25zdHJ1Y3RvckhhbmRsZXJzLmdldChjdXIuY29uc3RydWN0b3IpKSkge1xuICAgICAgICBhMltrXSA9IGhhbmRsZXIoY3VyLCBmbilcbiAgICAgIH0gZWxzZSBpZiAoQXJyYXlCdWZmZXIuaXNWaWV3KGN1cikpIHtcbiAgICAgICAgYTJba10gPSBjb3B5QnVmZmVyKGN1cilcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGEyW2tdID0gZm4oY3VyKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gYTJcbiAgfVxuXG4gIGZ1bmN0aW9uIGNsb25lIChvKSB7XG4gICAgaWYgKHR5cGVvZiBvICE9PSAnb2JqZWN0JyB8fCBvID09PSBudWxsKSByZXR1cm4gb1xuICAgIGlmIChBcnJheS5pc0FycmF5KG8pKSByZXR1cm4gY2xvbmVBcnJheShvLCBjbG9uZSlcbiAgICBpZiAoby5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoby5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICByZXR1cm4gaGFuZGxlcihvLCBjbG9uZSlcbiAgICB9XG4gICAgY29uc3QgbzIgPSB7fVxuICAgIGZvciAoY29uc3QgayBpbiBvKSB7XG4gICAgICBpZiAoT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwobywgaykgPT09IGZhbHNlKSBjb250aW51ZVxuICAgICAgY29uc3QgY3VyID0gb1trXVxuICAgICAgaWYgKHR5cGVvZiBjdXIgIT09ICdvYmplY3QnIHx8IGN1ciA9PT0gbnVsbCkge1xuICAgICAgICBvMltrXSA9IGN1clxuICAgICAgfSBlbHNlIGlmIChjdXIuY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KGN1ci5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICAgIG8yW2tdID0gaGFuZGxlcihjdXIsIGNsb25lKVxuICAgICAgfSBlbHNlIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoY3VyKSkge1xuICAgICAgICBvMltrXSA9IGNvcHlCdWZmZXIoY3VyKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbzJba10gPSBjbG9uZShjdXIpXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvMlxuICB9XG5cbiAgZnVuY3Rpb24gY2xvbmVQcm90byAobykge1xuICAgIGlmICh0eXBlb2YgbyAhPT0gJ29iamVjdCcgfHwgbyA9PT0gbnVsbCkgcmV0dXJuIG9cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvKSkgcmV0dXJuIGNsb25lQXJyYXkobywgY2xvbmVQcm90bylcbiAgICBpZiAoby5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoby5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICByZXR1cm4gaGFuZGxlcihvLCBjbG9uZVByb3RvKVxuICAgIH1cbiAgICBjb25zdCBvMiA9IHt9XG4gICAgZm9yIChjb25zdCBrIGluIG8pIHtcbiAgICAgIGNvbnN0IGN1ciA9IG9ba11cbiAgICAgIGlmICh0eXBlb2YgY3VyICE9PSAnb2JqZWN0JyB8fCBjdXIgPT09IG51bGwpIHtcbiAgICAgICAgbzJba10gPSBjdXJcbiAgICAgIH0gZWxzZSBpZiAoY3VyLmNvbnN0cnVjdG9yICE9PSBPYmplY3QgJiYgKGhhbmRsZXIgPSBjb25zdHJ1Y3RvckhhbmRsZXJzLmdldChjdXIuY29uc3RydWN0b3IpKSkge1xuICAgICAgICBvMltrXSA9IGhhbmRsZXIoY3VyLCBjbG9uZVByb3RvKVxuICAgICAgfSBlbHNlIGlmIChBcnJheUJ1ZmZlci5pc1ZpZXcoY3VyKSkge1xuICAgICAgICBvMltrXSA9IGNvcHlCdWZmZXIoY3VyKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbzJba10gPSBjbG9uZVByb3RvKGN1cilcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG8yXG4gIH1cbn1cblxuZnVuY3Rpb24gcmZkY0NpcmNsZXMgKG9wdHMpIHtcbiAgY29uc3QgcmVmcyA9IFtdXG4gIGNvbnN0IHJlZnNOZXcgPSBbXVxuXG4gIGNvbnN0IGNvbnN0cnVjdG9ySGFuZGxlcnMgPSBuZXcgTWFwKClcbiAgY29uc3RydWN0b3JIYW5kbGVycy5zZXQoRGF0ZSwgKG8pID0+IG5ldyBEYXRlKG8pKVxuICBjb25zdHJ1Y3RvckhhbmRsZXJzLnNldChNYXAsIChvLCBmbikgPT4gbmV3IE1hcChjbG9uZUFycmF5KEFycmF5LmZyb20obyksIGZuKSkpXG4gIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KFNldCwgKG8sIGZuKSA9PiBuZXcgU2V0KGNsb25lQXJyYXkoQXJyYXkuZnJvbShvKSwgZm4pKSlcbiAgaWYgKG9wdHMuY29uc3RydWN0b3JIYW5kbGVycykge1xuICAgIGZvciAoY29uc3QgaGFuZGxlciBvZiBvcHRzLmNvbnN0cnVjdG9ySGFuZGxlcnMpIHtcbiAgICAgIGNvbnN0cnVjdG9ySGFuZGxlcnMuc2V0KGhhbmRsZXJbMF0sIGhhbmRsZXJbMV0pXG4gICAgfVxuICB9XG5cbiAgbGV0IGhhbmRsZXIgPSBudWxsXG4gIHJldHVybiBvcHRzLnByb3RvID8gY2xvbmVQcm90byA6IGNsb25lXG5cbiAgZnVuY3Rpb24gY2xvbmVBcnJheSAoYSwgZm4pIHtcbiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoYSlcbiAgICBjb25zdCBhMiA9IG5ldyBBcnJheShrZXlzLmxlbmd0aClcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGsgPSBrZXlzW2ldXG4gICAgICBjb25zdCBjdXIgPSBhW2tdXG4gICAgICBpZiAodHlwZW9mIGN1ciAhPT0gJ29iamVjdCcgfHwgY3VyID09PSBudWxsKSB7XG4gICAgICAgIGEyW2tdID0gY3VyXG4gICAgICB9IGVsc2UgaWYgKGN1ci5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoY3VyLmNvbnN0cnVjdG9yKSkpIHtcbiAgICAgICAgYTJba10gPSBoYW5kbGVyKGN1ciwgZm4pXG4gICAgICB9IGVsc2UgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhjdXIpKSB7XG4gICAgICAgIGEyW2tdID0gY29weUJ1ZmZlcihjdXIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBpbmRleCA9IHJlZnMuaW5kZXhPZihjdXIpXG4gICAgICAgIGlmIChpbmRleCAhPT0gLTEpIHtcbiAgICAgICAgICBhMltrXSA9IHJlZnNOZXdbaW5kZXhdXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYTJba10gPSBmbihjdXIpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGEyXG4gIH1cblxuICBmdW5jdGlvbiBjbG9uZSAobykge1xuICAgIGlmICh0eXBlb2YgbyAhPT0gJ29iamVjdCcgfHwgbyA9PT0gbnVsbCkgcmV0dXJuIG9cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvKSkgcmV0dXJuIGNsb25lQXJyYXkobywgY2xvbmUpXG4gICAgaWYgKG8uY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KG8uY29uc3RydWN0b3IpKSkge1xuICAgICAgcmV0dXJuIGhhbmRsZXIobywgY2xvbmUpXG4gICAgfVxuICAgIGNvbnN0IG8yID0ge31cbiAgICByZWZzLnB1c2gobylcbiAgICByZWZzTmV3LnB1c2gobzIpXG4gICAgZm9yIChjb25zdCBrIGluIG8pIHtcbiAgICAgIGlmIChPYmplY3QuaGFzT3duUHJvcGVydHkuY2FsbChvLCBrKSA9PT0gZmFsc2UpIGNvbnRpbnVlXG4gICAgICBjb25zdCBjdXIgPSBvW2tdXG4gICAgICBpZiAodHlwZW9mIGN1ciAhPT0gJ29iamVjdCcgfHwgY3VyID09PSBudWxsKSB7XG4gICAgICAgIG8yW2tdID0gY3VyXG4gICAgICB9IGVsc2UgaWYgKGN1ci5jb25zdHJ1Y3RvciAhPT0gT2JqZWN0ICYmIChoYW5kbGVyID0gY29uc3RydWN0b3JIYW5kbGVycy5nZXQoY3VyLmNvbnN0cnVjdG9yKSkpIHtcbiAgICAgICAgbzJba10gPSBoYW5kbGVyKGN1ciwgY2xvbmUpXG4gICAgICB9IGVsc2UgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhjdXIpKSB7XG4gICAgICAgIG8yW2tdID0gY29weUJ1ZmZlcihjdXIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBpID0gcmVmcy5pbmRleE9mKGN1cilcbiAgICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgICAgbzJba10gPSByZWZzTmV3W2ldXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbzJba10gPSBjbG9uZShjdXIpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmVmcy5wb3AoKVxuICAgIHJlZnNOZXcucG9wKClcbiAgICByZXR1cm4gbzJcbiAgfVxuXG4gIGZ1bmN0aW9uIGNsb25lUHJvdG8gKG8pIHtcbiAgICBpZiAodHlwZW9mIG8gIT09ICdvYmplY3QnIHx8IG8gPT09IG51bGwpIHJldHVybiBvXG4gICAgaWYgKEFycmF5LmlzQXJyYXkobykpIHJldHVybiBjbG9uZUFycmF5KG8sIGNsb25lUHJvdG8pXG4gICAgaWYgKG8uY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KG8uY29uc3RydWN0b3IpKSkge1xuICAgICAgcmV0dXJuIGhhbmRsZXIobywgY2xvbmVQcm90bylcbiAgICB9XG4gICAgY29uc3QgbzIgPSB7fVxuICAgIHJlZnMucHVzaChvKVxuICAgIHJlZnNOZXcucHVzaChvMilcbiAgICBmb3IgKGNvbnN0IGsgaW4gbykge1xuICAgICAgY29uc3QgY3VyID0gb1trXVxuICAgICAgaWYgKHR5cGVvZiBjdXIgIT09ICdvYmplY3QnIHx8IGN1ciA9PT0gbnVsbCkge1xuICAgICAgICBvMltrXSA9IGN1clxuICAgICAgfSBlbHNlIGlmIChjdXIuY29uc3RydWN0b3IgIT09IE9iamVjdCAmJiAoaGFuZGxlciA9IGNvbnN0cnVjdG9ySGFuZGxlcnMuZ2V0KGN1ci5jb25zdHJ1Y3RvcikpKSB7XG4gICAgICAgIG8yW2tdID0gaGFuZGxlcihjdXIsIGNsb25lUHJvdG8pXG4gICAgICB9IGVsc2UgaWYgKEFycmF5QnVmZmVyLmlzVmlldyhjdXIpKSB7XG4gICAgICAgIG8yW2tdID0gY29weUJ1ZmZlcihjdXIpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBpID0gcmVmcy5pbmRleE9mKGN1cilcbiAgICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgICAgbzJba10gPSByZWZzTmV3W2ldXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbzJba10gPSBjbG9uZVByb3RvKGN1cilcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZWZzLnBvcCgpXG4gICAgcmVmc05ldy5wb3AoKVxuICAgIHJldHVybiBvMlxuICB9XG59XG4iLCJpbXBvcnQgZXF1YWwgZnJvbSBcImZhc3QtZGVlcC1lcXVhbFwiXG5pbXBvcnQgeyBuYW5vaWQgfSBmcm9tIFwibmFub2lkXCJcbmltcG9ydCByZmRjIGZyb20gXCJyZmRjXCJcbmltcG9ydCB0eXBlIHsgSlNPTlZhbHVlIH0gZnJvbSBcIi4vanNvblwiXG5cbmNvbnN0IGNsb25lID0gcmZkYyh7IHByb3RvOiB0cnVlIH0pXG5cbi8qKlxuICogRGVlcCBlcXVhbGl0eSBjaGVjayBmb3IgSlNPTlZhbHVlcy5cbiAqIFVzZWQgZm9yIGFkZFRvU2V0IC8gZGVsZXRlRnJvbVNldCBvcGVyYXRpb25zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVlcEVxdWFsKGE6IEpTT05WYWx1ZSwgYjogSlNPTlZhbHVlKTogYm9vbGVhbiB7XG4gIHJldHVybiBlcXVhbChhLCBiKVxufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIHVuaXF1ZSBJRCB1c2luZyBuYW5vaWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZUlEKCk6IHN0cmluZyB7XG4gIHJldHVybiBuYW5vaWQoKVxufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGFuIG9iamVjdCAodHlwZW9mID09PSBcIm9iamVjdFwiICYmICE9PSBudWxsKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0KHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgb2JqZWN0IHtcbiAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIlxufVxuXG4vKipcbiAqIERlZXAgY2xvbmVzIGEgSlNPTi1zZXJpYWxpemFibGUgdmFsdWUuXG4gKiBPcHRpbWl6ZWQ6IHByaW1pdGl2ZXMgYXJlIHJldHVybmVkIGFzLWlzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVlcENsb25lPFQ+KHZhbHVlOiBUKTogVCB7XG4gIC8vIFByaW1pdGl2ZXMgZG9uJ3QgbmVlZCBjbG9uaW5nXG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gdmFsdWVcbiAgfVxuICByZXR1cm4gY2xvbmUodmFsdWUpXG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGxhenkgbWVtb2l6ZWQgZ2V0dGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGF6eTxUPihmbjogKCkgPT4gVCk6ICgpID0+IFQge1xuICBsZXQgY29tcHV0ZWQgPSBmYWxzZVxuICBsZXQgdmFsdWU6IFRcbiAgcmV0dXJuICgpID0+IHtcbiAgICBpZiAoIWNvbXB1dGVkKSB7XG4gICAgICB2YWx1ZSA9IGZuKClcbiAgICAgIGNvbXB1dGVkID0gdHJ1ZVxuICAgIH1cbiAgICByZXR1cm4gdmFsdWVcbiAgfVxufVxuIiwiaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuL2Vycm9yXCJcbmltcG9ydCB0eXBlIHsgSlNPTk9iamVjdCwgSlNPTlJlY29yZCwgSlNPTlZhbHVlLCBQYXRoIH0gZnJvbSBcIi4vanNvblwiXG5pbXBvcnQgdHlwZSB7IE9wLCBWYWxpZGF0ZUZuIH0gZnJvbSBcIi4vb3BlcmF0aW9uc1wiXG5pbXBvcnQgeyBUeFJlY29yZCB9IGZyb20gXCIuL1R4UmVjb3JkXCJcbmltcG9ydCB7IGRlZXBFcXVhbCwgaXNPYmplY3QgfSBmcm9tIFwiLi91dGlsc1wiXG5cbi8qKlxuICogQSBkcmFmdCBjb250ZXh0IGZvciBjb3B5LW9uLXdyaXRlIGltbXV0YWJsZSB1cGRhdGVzLlxuICpcbiAqIFRoaXMgcHJvdmlkZXMgSW1tZXIvTXV0YXRpdmUtbGlrZSBzZW1hbnRpY3Mgd2l0aG91dCB0aGUgcHJveHkgb3ZlcmhlYWQ6XG4gKiAtIFRoZSBvcmlnaW5hbCBiYXNlIHN0YXRlIGlzIG5ldmVyIG11dGF0ZWRcbiAqIC0gT2JqZWN0cyBhcmUgY2xvbmVkIGxhemlseSBvbiBmaXJzdCBtdXRhdGlvbiAoY29weS1vbi13cml0ZSlcbiAqIC0gT25jZSBhbiBvYmplY3QgaXMgY2xvbmVkIChcIm93bmVkXCIpLCBpdCBjYW4gYmUgbXV0YXRlZCBkaXJlY3RseVxuICogLSBJZiBubyBjaGFuZ2VzIGFyZSBtYWRlLCB0aGUgb3JpZ2luYWwgcmVmZXJlbmNlIGlzIHByZXNlcnZlZCAoc3RydWN0dXJhbCBzaGFyaW5nKVxuICovXG5leHBvcnQgaW50ZXJmYWNlIERyYWZ0Q29udGV4dDxUIGV4dGVuZHMgSlNPTk9iamVjdD4ge1xuICAvKiogVGhlIGN1cnJlbnQgcm9vdCAobWF5IGJlIHRoZSBvcmlnaW5hbCBiYXNlIG9yIGEgY2xvbmVkIHZlcnNpb24pICovXG4gIHJvb3Q6IFRcbiAgLyoqIFRoZSBvcmlnaW5hbCBiYXNlIHN0YXRlIChuZXZlciBtdXRhdGVkKSAqL1xuICBiYXNlOiBUXG4gIC8qKiBTZXQgb2Ygb2JqZWN0cyB0aGF0IGhhdmUgYmVlbiBjbG9uZWQgYW5kIGFyZSBzYWZlIHRvIG11dGF0ZSAqL1xuICBvd25lZE9iamVjdHM6IFdlYWtTZXQ8b2JqZWN0PlxuICAvKiogT3B0aW1pemF0aW9uOiBmYXN0IGNoZWNrIGlmIHJvb3QgaXMgYWxyZWFkeSBvd25lZCAqL1xuICBpc1Jvb3RPd25lZDogYm9vbGVhblxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgZHJhZnQgY29udGV4dCBmcm9tIGEgYmFzZSBzdGF0ZS5cbiAqIFRoZSBiYXNlIHN0YXRlIHdpbGwgbmV2ZXIgYmUgbXV0YXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZURyYWZ0PFQgZXh0ZW5kcyBKU09OT2JqZWN0PihiYXNlOiBUKTogRHJhZnRDb250ZXh0PFQ+IHtcbiAgcmV0dXJuIHtcbiAgICByb290OiBiYXNlLFxuICAgIGJhc2UsXG4gICAgb3duZWRPYmplY3RzOiBuZXcgU2V0KCksXG4gICAgaXNSb290T3duZWQ6IGZhbHNlLFxuICB9XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBkcmFmdCB3YXMgbW9kaWZpZWQgKHJvb3QgIT09IGJhc2UpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEcmFmdE1vZGlmaWVkPFQgZXh0ZW5kcyBKU09OT2JqZWN0PihjdHg6IERyYWZ0Q29udGV4dDxUPik6IGJvb2xlYW4ge1xuICByZXR1cm4gY3R4LnJvb3QgIT09IGN0eC5iYXNlXG59XG5cbmZ1bmN0aW9uIHNoYWxsb3dDbG9uZTxUIGV4dGVuZHMgb2JqZWN0PihvYmo6IFQpOiBUIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgIHJldHVybiBvYmouc2xpY2UoKSBhcyB1bmtub3duIGFzIFRcbiAgfVxuICBjb25zdCBjbG9uZSA9IHt9IGFzIFRcbiAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKG9iailcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3Qga2V5ID0ga2V5c1tpXVxuICAgIDsoY2xvbmUgYXMgYW55KVtrZXldID0gKG9iaiBhcyBhbnkpW2tleV1cbiAgfVxuICByZXR1cm4gY2xvbmVcbn1cblxuLyoqXG4gKiBFbnN1cmVzIGFuIG9iamVjdCBpcyBvd25lZCAoY2xvbmVkIGlmIG5lY2Vzc2FyeSkgYW5kIHJldHVybnMgdGhlIG93bmVkIHZlcnNpb24uXG4gKiBBbHNvIHVwZGF0ZXMgdGhlIHBhcmVudCB0byBwb2ludCB0byB0aGUgY2xvbmVkIGNoaWxkLlxuICovXG5mdW5jdGlvbiBlbnN1cmVPd25lZDxUIGV4dGVuZHMgSlNPTk9iamVjdD4oXG4gIGN0eDogRHJhZnRDb250ZXh0PFQ+LFxuICBwYXJlbnQ6IEpTT05PYmplY3QsXG4gIGtleTogc3RyaW5nIHwgbnVtYmVyLFxuICBjaGlsZDogSlNPTlJlY29yZCB8IEpTT05WYWx1ZVtdXG4pOiBKU09OUmVjb3JkIHwgSlNPTlZhbHVlW10ge1xuICBpZiAoY3R4Lm93bmVkT2JqZWN0cy5oYXMoY2hpbGQpKSB7XG4gICAgcmV0dXJuIGNoaWxkXG4gIH1cbiAgY29uc3QgY2xvbmVkID0gc2hhbGxvd0Nsb25lKGNoaWxkKVxuICA7KHBhcmVudCBhcyBhbnkpW2tleV0gPSBjbG9uZWRcbiAgY3R4Lm93bmVkT2JqZWN0cy5hZGQoY2xvbmVkKVxuICByZXR1cm4gY2xvbmVkXG59XG5cbi8qKlxuICogRW5zdXJlcyBhbGwgb2JqZWN0cyBhbG9uZyB0aGUgcGF0aCBhcmUgb3duZWQgKGNsb25lZCBpZiBuZWNlc3NhcnkpLlxuICogUmV0dXJucyB0aGUgY29udGFpbmVyIGF0IHRoZSBlbmQgb2YgdGhlIHBhdGguXG4gKiBUaHJvd3MgaWYgdGhlIHBhdGggaXMgaW52YWxpZC5cbiAqL1xuZnVuY3Rpb24gZW5zdXJlT3duZWRQYXRoPFQgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgY3R4OiBEcmFmdENvbnRleHQ8VD4sXG4gIHBhdGg6IFBhdGhcbik6IEpTT05SZWNvcmQgfCBKU09OVmFsdWVbXSB7XG4gIC8vIEVuc3VyZSByb290IGlzIG93bmVkIGZpcnN0XG4gIGlmICghY3R4LmlzUm9vdE93bmVkKSB7XG4gICAgY3R4LnJvb3QgPSBzaGFsbG93Q2xvbmUoY3R4LnJvb3QgYXMgdW5rbm93biBhcyBvYmplY3QpIGFzIFRcbiAgICBjdHgub3duZWRPYmplY3RzLmFkZChjdHgucm9vdClcbiAgICBjdHguaXNSb290T3duZWQgPSB0cnVlXG4gIH1cblxuICBpZiAocGF0aC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gY3R4LnJvb3RcbiAgfVxuXG4gIGxldCBjdXJyZW50OiBKU09OUmVjb3JkIHwgSlNPTlZhbHVlW10gPSBjdHgucm9vdFxuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcGF0aC5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IHNlZ21lbnQgPSBwYXRoW2ldXG4gICAgY29uc3QgaXNBcnJheUluZGV4ID0gdHlwZW9mIHNlZ21lbnQgPT09IFwibnVtYmVyXCJcblxuICAgIC8vIFZhbGlkYXRlIGNvbnRhaW5lciB0eXBlXG4gICAgaWYgKGlzQXJyYXlJbmRleCkge1xuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGN1cnJlbnQpKSB7XG4gICAgICAgIGZhaWx1cmUoYEV4cGVjdGVkIGFycmF5IGF0IHBhdGggc2VnbWVudCAke3NlZ21lbnR9YClcbiAgICAgIH1cbiAgICAgIGlmIChzZWdtZW50IDwgMCB8fCBzZWdtZW50ID49IGN1cnJlbnQubGVuZ3RoKSB7XG4gICAgICAgIGZhaWx1cmUoYEluZGV4ICR7c2VnbWVudH0gb3V0IG9mIGJvdW5kc2ApXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICghaXNPYmplY3QoY3VycmVudCkgfHwgQXJyYXkuaXNBcnJheShjdXJyZW50KSkge1xuICAgICAgICBmYWlsdXJlKGBFeHBlY3RlZCBvYmplY3QgYXQgcGF0aCBzZWdtZW50IFwiJHtzZWdtZW50fVwiYClcbiAgICAgIH1cbiAgICAgIGlmICghKHNlZ21lbnQgaW4gY3VycmVudCkpIHtcbiAgICAgICAgZmFpbHVyZShgUHJvcGVydHkgXCIke3NlZ21lbnR9XCIgZG9lcyBub3QgZXhpc3RgKVxuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGNoaWxkOiBKU09OVmFsdWUgPSAoY3VycmVudCBhcyBhbnkpW3NlZ21lbnRdXG5cbiAgICAvLyBWYWxpZGF0ZSBjaGlsZCBpcyB0cmF2ZXJzYWJsZVxuICAgIGlmIChjaGlsZCA9PT0gbnVsbCB8fCB0eXBlb2YgY2hpbGQgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGZhaWx1cmUoYENhbm5vdCB0cmF2ZXJzZSB0aHJvdWdoIHByaW1pdGl2ZSBhdCBwYXRoIHNlZ21lbnQgJHtzZWdtZW50fWApXG4gICAgfVxuXG4gICAgLy8gRW5zdXJlIGNoaWxkIGlzIG93bmVkIGFuZCBjb250aW51ZVxuICAgIGN1cnJlbnQgPSBlbnN1cmVPd25lZChjdHgsIGN1cnJlbnQsIHNlZ21lbnQsIGNoaWxkIGFzIEpTT05SZWNvcmQgfCBKU09OVmFsdWVbXSlcbiAgfVxuXG4gIHJldHVybiBjdXJyZW50XG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcInNldFwiIG9wZXJhdGlvbiB0byB0aGUgZHJhZnQgd2l0aCBjb3B5LW9uLXdyaXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZHJhZnRTZXQ8VCBleHRlbmRzIEpTT05PYmplY3Q+KFxuICBjdHg6IERyYWZ0Q29udGV4dDxUPixcbiAgcGF0aDogUGF0aCxcbiAga2V5OiBzdHJpbmcsXG4gIHZhbHVlOiBKU09OVmFsdWVcbik6IHZvaWQge1xuICBjb25zdCBjb250YWluZXIgPSBlbnN1cmVPd25lZFBhdGgoY3R4LCBwYXRoKVxuICBpZiAoQXJyYXkuaXNBcnJheShjb250YWluZXIpKSB7XG4gICAgZmFpbHVyZShcInNldCByZXF1aXJlcyBvYmplY3QgY29udGFpbmVyXCIpXG4gIH1cbiAgOyhjb250YWluZXIgYXMgSlNPTlJlY29yZClba2V5XSA9IHZhbHVlXG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcImRlbGV0ZVwiIG9wZXJhdGlvbiB0byB0aGUgZHJhZnQgd2l0aCBjb3B5LW9uLXdyaXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZHJhZnREZWxldGU8VCBleHRlbmRzIEpTT05PYmplY3Q+KFxuICBjdHg6IERyYWZ0Q29udGV4dDxUPixcbiAgcGF0aDogUGF0aCxcbiAga2V5OiBzdHJpbmdcbik6IHZvaWQge1xuICBjb25zdCBjb250YWluZXIgPSBlbnN1cmVPd25lZFBhdGgoY3R4LCBwYXRoKVxuICBpZiAoQXJyYXkuaXNBcnJheShjb250YWluZXIpKSB7XG4gICAgZmFpbHVyZShcImRlbGV0ZSByZXF1aXJlcyBvYmplY3QgY29udGFpbmVyXCIpXG4gIH1cbiAgZGVsZXRlIChjb250YWluZXIgYXMgSlNPTlJlY29yZClba2V5XVxufVxuXG4vKipcbiAqIEFwcGxpZXMgYSBzaW5nbGUgXCJzcGxpY2VcIiBvcGVyYXRpb24gdG8gdGhlIGRyYWZ0IHdpdGggY29weS1vbi13cml0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRyYWZ0U3BsaWNlPFQgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgY3R4OiBEcmFmdENvbnRleHQ8VD4sXG4gIHBhdGg6IFBhdGgsXG4gIGluZGV4OiBudW1iZXIsXG4gIGRlbGV0ZUNvdW50OiBudW1iZXIsXG4gIGluc2VydHM6IHJlYWRvbmx5IEpTT05WYWx1ZVtdXG4pOiB2b2lkIHtcbiAgY29uc3QgY29udGFpbmVyID0gZW5zdXJlT3duZWRQYXRoKGN0eCwgcGF0aClcbiAgaWYgKCFBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcbiAgICBmYWlsdXJlKFwic3BsaWNlIHJlcXVpcmVzIGFycmF5IGNvbnRhaW5lclwiKVxuICB9XG4gIGNvbnN0IHNhZmVJbmRleCA9IE1hdGgubWluKGluZGV4LCBjb250YWluZXIubGVuZ3RoKVxuICBpZiAoaW5zZXJ0cy5sZW5ndGggPT09IDApIHtcbiAgICBjb250YWluZXIuc3BsaWNlKHNhZmVJbmRleCwgZGVsZXRlQ291bnQpXG4gIH0gZWxzZSBpZiAoaW5zZXJ0cy5sZW5ndGggPT09IDEpIHtcbiAgICBjb250YWluZXIuc3BsaWNlKHNhZmVJbmRleCwgZGVsZXRlQ291bnQsIGluc2VydHNbMF0pXG4gIH0gZWxzZSB7XG4gICAgY29udGFpbmVyLnNwbGljZShzYWZlSW5kZXgsIGRlbGV0ZUNvdW50LCAuLi5pbnNlcnRzKVxuICB9XG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcImFkZFRvU2V0XCIgb3BlcmF0aW9uIHRvIHRoZSBkcmFmdCB3aXRoIGNvcHktb24td3JpdGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkcmFmdEFkZFRvU2V0PFQgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgY3R4OiBEcmFmdENvbnRleHQ8VD4sXG4gIHBhdGg6IFBhdGgsXG4gIHZhbHVlOiBKU09OVmFsdWVcbik6IHZvaWQge1xuICBjb25zdCBjb250YWluZXIgPSBlbnN1cmVPd25lZFBhdGgoY3R4LCBwYXRoKVxuICBpZiAoIUFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xuICAgIGZhaWx1cmUoXCJhZGRUb1NldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcbiAgfVxuICBpZiAoIWNvbnRhaW5lci5zb21lKChpdGVtKSA9PiBkZWVwRXF1YWwoaXRlbSwgdmFsdWUpKSkge1xuICAgIGNvbnRhaW5lci5wdXNoKHZhbHVlKVxuICB9XG59XG5cbi8qKlxuICogQXBwbGllcyBhIHNpbmdsZSBcImRlbGV0ZUZyb21TZXRcIiBvcGVyYXRpb24gdG8gdGhlIGRyYWZ0IHdpdGggY29weS1vbi13cml0ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRyYWZ0RGVsZXRlRnJvbVNldDxUIGV4dGVuZHMgSlNPTk9iamVjdD4oXG4gIGN0eDogRHJhZnRDb250ZXh0PFQ+LFxuICBwYXRoOiBQYXRoLFxuICB2YWx1ZTogSlNPTlZhbHVlXG4pOiB2b2lkIHtcbiAgY29uc3QgY29udGFpbmVyID0gZW5zdXJlT3duZWRQYXRoKGN0eCwgcGF0aClcbiAgaWYgKCFBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcbiAgICBmYWlsdXJlKFwiZGVsZXRlRnJvbVNldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcbiAgfVxuICAvLyBSZW1vdmUgYWxsIG1hdGNoaW5nIGl0ZW1zIChpdGVyYXRlIGJhY2t3YXJkcyB0byBhdm9pZCBpbmRleCBzaGlmdGluZylcbiAgZm9yIChsZXQgaSA9IGNvbnRhaW5lci5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgIGlmIChkZWVwRXF1YWwoY29udGFpbmVyW2ldLCB2YWx1ZSkpIHtcbiAgICAgIGNvbnRhaW5lci5zcGxpY2UoaSwgMSlcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBBcHBsaWVzIGEgc2luZ2xlIG9wZXJhdGlvbiB0byB0aGUgZHJhZnQgd2l0aCBjb3B5LW9uLXdyaXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlPcFRvRHJhZnQ8VCBleHRlbmRzIEpTT05PYmplY3Q+KGN0eDogRHJhZnRDb250ZXh0PFQ+LCBvcDogT3ApOiB2b2lkIHtcbiAgc3dpdGNoIChvcC5raW5kKSB7XG4gICAgY2FzZSBcInNldFwiOlxuICAgICAgZHJhZnRTZXQoY3R4LCBvcC5wYXRoLCBvcC5rZXksIG9wLnZhbHVlKVxuICAgICAgYnJlYWtcbiAgICBjYXNlIFwiZGVsZXRlXCI6XG4gICAgICBkcmFmdERlbGV0ZShjdHgsIG9wLnBhdGgsIG9wLmtleSlcbiAgICAgIGJyZWFrXG4gICAgY2FzZSBcInNwbGljZVwiOlxuICAgICAgZHJhZnRTcGxpY2UoY3R4LCBvcC5wYXRoLCBvcC5pbmRleCwgb3AuZGVsZXRlQ291bnQsIG9wLmluc2VydHMpXG4gICAgICBicmVha1xuICAgIGNhc2UgXCJhZGRUb1NldFwiOlxuICAgICAgZHJhZnRBZGRUb1NldChjdHgsIG9wLnBhdGgsIG9wLnZhbHVlKVxuICAgICAgYnJlYWtcbiAgICBjYXNlIFwiZGVsZXRlRnJvbVNldFwiOlxuICAgICAgZHJhZnREZWxldGVGcm9tU2V0KGN0eCwgb3AucGF0aCwgb3AudmFsdWUpXG4gICAgICBicmVha1xuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBmYWlsdXJlKGBVbmtub3duIG9wZXJhdGlvbiBraW5kOiAkeyhvcCBhcyBhbnkpLmtpbmR9YClcbiAgfVxufVxuXG4vKipcbiAqIEFwcGxpZXMgYSBzaW5nbGUgdHJhbnNhY3Rpb24gdG8gYSBiYXNlIHN0YXRlIGltbXV0YWJseS5cbiAqXG4gKiBLZXkgYmVuZWZpdHMgb3ZlciBNdXRhdGl2ZS9JbW1lcjpcbiAqIC0gTm8gcHJveHkgb3ZlcmhlYWQgLSBkaXJlY3Qgb2JqZWN0IGFjY2VzcyBhbmQgY29weS1vbi13cml0ZSBjbG9uaW5nXG4gKiAtIFN0cnVjdHVyYWwgc2hhcmluZyAtIHVuY2hhbmdlZCBzdWJ0cmVlcyBrZWVwIHRoZWlyIHJlZmVyZW5jZXNcbiAqIC0gWmVyby1jb3B5IG9uIGZhaWx1cmUgLSBpZiB2YWxpZGF0aW9uIGZhaWxzLCByZXR1cm5zIG9yaWdpbmFsIGJhc2UgdW5jaGFuZ2VkXG4gKlxuICogQHBhcmFtIGJhc2UgLSBUaGUgYmFzZSBzdGF0ZSAobmV2ZXIgbXV0YXRlZClcbiAqIEBwYXJhbSB0eCAtIFRoZSB0cmFuc2FjdGlvbiB0byBhcHBseVxuICogQHBhcmFtIHZhbGlkYXRlRm4gLSBPcHRpb25hbCB2YWxpZGF0aW9uIGZ1bmN0aW9uXG4gKiBAcmV0dXJucyBUaGUgZmluYWwgc3RhdGUgKGlmIHZhbGlkKSBvciB0aGUgb3JpZ2luYWwgYmFzZSAoaWYgaW52YWxpZCBvciBlbXB0eSlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFwcGx5VHhJbW11dGFibGU8VCBleHRlbmRzIEpTT05PYmplY3Q+KFxuICBiYXNlOiBULFxuICB0eDogUGljazxUeFJlY29yZCwgXCJvcHNcIj4sXG4gIHZhbGlkYXRlRm4/OiBWYWxpZGF0ZUZuPFQ+XG4pOiBUIHtcbiAgaWYgKHR4Lm9wcy5sZW5ndGggPT09IDApIHJldHVybiBiYXNlXG5cbiAgY29uc3QgY3R4ID0gY3JlYXRlRHJhZnQoYmFzZSlcblxuICB0cnkge1xuICAgIGZvciAoY29uc3Qgb3Agb2YgdHgub3BzKSB7XG4gICAgICBhcHBseU9wVG9EcmFmdChjdHgsIG9wKVxuICAgIH1cblxuICAgIGlmICh2YWxpZGF0ZUZuICYmICF2YWxpZGF0ZUZuKGN0eC5yb290KSkge1xuICAgICAgcmV0dXJuIGJhc2VcbiAgICB9XG5cbiAgICByZXR1cm4gY3R4LnJvb3RcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGJhc2VcbiAgfVxufVxuIiwiaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuL2Vycm9yXCJcbmltcG9ydCB7IEpTT05SZWNvcmQsIEpTT05WYWx1ZSwgUGF0aCB9IGZyb20gXCIuL2pzb25cIlxuaW1wb3J0IHsgT3AgfSBmcm9tIFwiLi9vcGVyYXRpb25zXCJcblxuLyoqXG4gKiBSZWNvbmNpbGVzIHRoZSBjdXJyZW50IHN0YXRlIHdpdGggdGhlIHRhcmdldCBzdGF0ZSBieSBjb21wdXRpbmcgYW5kIGVtaXR0aW5nXG4gKiB0aGUgbWluaW1hbCBzZXQgb2Ygb3BlcmF0aW9ucyBuZWVkZWQgdG8gdHJhbnNmb3JtIGN1cnJlbnRTdGF0ZSBpbnRvIHRhcmdldFN0YXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZVJlY29uY2lsZU9wcyhjdXJyZW50U3RhdGU6IEpTT05WYWx1ZSwgdGFyZ2V0U3RhdGU6IEpTT05WYWx1ZSk6IE9wW10ge1xuICBjb25zdCBvcHM6IE9wW10gPSBbXVxuICBkaWZmVmFsdWUoY3VycmVudFN0YXRlLCB0YXJnZXRTdGF0ZSwgW10sIG9wcylcbiAgcmV0dXJuIG9wc1xufVxuXG5mdW5jdGlvbiBkaWZmVmFsdWUoY3VycmVudDogSlNPTlZhbHVlLCB0YXJnZXQ6IEpTT05WYWx1ZSwgcGF0aDogUGF0aCwgb3BzOiBPcFtdKTogdm9pZCB7XG4gIC8vIDEuIFJlZmVyZW5jZSBlcXVhbGl0eSAoc3RydWN0dXJhbCBzaGFyaW5nKVxuICBpZiAoY3VycmVudCA9PT0gdGFyZ2V0KSByZXR1cm5cblxuICAvLyAyLiBIYW5kbGUgcHJpbWl0aXZlcyBhbmQgbnVsbCBxdWlja2x5XG4gIGNvbnN0IGN1cnJlbnRUeXBlID0gdHlwZW9mIGN1cnJlbnRcbiAgY29uc3QgdGFyZ2V0VHlwZSA9IHR5cGVvZiB0YXJnZXRcblxuICBpZiAoY3VycmVudCA9PT0gbnVsbCB8fCB0YXJnZXQgPT09IG51bGwgfHwgY3VycmVudFR5cGUgIT09IFwib2JqZWN0XCIgfHwgdGFyZ2V0VHlwZSAhPT0gXCJvYmplY3RcIikge1xuICAgIC8vIEF0IGxlYXN0IG9uZSBpcyBwcmltaXRpdmUvbnVsbCwgb3IgdHlwZXMgZG9uJ3QgbWF0Y2hcbiAgICBlbWl0UmVwbGFjZShwYXRoLCB0YXJnZXQsIG9wcylcbiAgICByZXR1cm5cbiAgfVxuXG4gIC8vIEJvdGggYXJlIG9iamVjdHMgKG9iamVjdCBvciBhcnJheSlcbiAgY29uc3QgY3VycmVudElzQXJyYXkgPSBBcnJheS5pc0FycmF5KGN1cnJlbnQpXG4gIGNvbnN0IHRhcmdldElzQXJyYXkgPSBBcnJheS5pc0FycmF5KHRhcmdldClcblxuICBpZiAoY3VycmVudElzQXJyYXkgIT09IHRhcmdldElzQXJyYXkpIHtcbiAgICAvLyBUeXBlIG1pc21hdGNoIChvbmUgYXJyYXksIG9uZSBvYmplY3QpXG4gICAgZW1pdFJlcGxhY2UocGF0aCwgdGFyZ2V0LCBvcHMpXG4gICAgcmV0dXJuXG4gIH1cblxuICBpZiAoY3VycmVudElzQXJyYXkpIHtcbiAgICBkaWZmQXJyYXkoY3VycmVudCwgdGFyZ2V0IGFzIEpTT05WYWx1ZVtdLCBwYXRoLCBvcHMpXG4gIH0gZWxzZSB7XG4gICAgZGlmZk9iamVjdChjdXJyZW50IGFzIEpTT05SZWNvcmQsIHRhcmdldCBhcyBKU09OUmVjb3JkLCBwYXRoLCBvcHMpXG4gIH1cbn1cblxuZnVuY3Rpb24gZGlmZk9iamVjdChjdXJyZW50OiBKU09OUmVjb3JkLCB0YXJnZXQ6IEpTT05SZWNvcmQsIHBhdGg6IFBhdGgsIG9wczogT3BbXSk6IHZvaWQge1xuICAvLyAxLiBEZWxldGUga2V5cyBpbiBjdXJyZW50IGJ1dCBub3QgaW4gdGFyZ2V0XG4gIGZvciAoY29uc3Qga2V5IGluIGN1cnJlbnQpIHtcbiAgICBpZiAoT2JqZWN0Lmhhc093bihjdXJyZW50LCBrZXkpICYmICFPYmplY3QuaGFzT3duKHRhcmdldCwga2V5KSkge1xuICAgICAgb3BzLnB1c2goeyBraW5kOiBcImRlbGV0ZVwiLCBwYXRoLCBrZXkgfSlcbiAgICB9XG4gIH1cblxuICAvLyAyLiBBZGQvVXBkYXRlIGtleXMgaW4gdGFyZ2V0XG4gIGZvciAoY29uc3Qga2V5IGluIHRhcmdldCkge1xuICAgIGlmIChPYmplY3QuaGFzT3duKHRhcmdldCwga2V5KSkge1xuICAgICAgY29uc3QgdGFyZ2V0VmFsID0gdGFyZ2V0W2tleV1cbiAgICAgIGlmICghT2JqZWN0Lmhhc093bihjdXJyZW50LCBrZXkpKSB7XG4gICAgICAgIG9wcy5wdXNoKHsga2luZDogXCJzZXRcIiwgcGF0aCwga2V5LCB2YWx1ZTogdGFyZ2V0VmFsIH0pXG4gICAgICB9IGVsc2UgaWYgKGN1cnJlbnRba2V5XSAhPT0gdGFyZ2V0VmFsKSB7XG4gICAgICAgIC8vIE9ubHkgcmVjdXJzZSBpZiB2YWx1ZXMgZGlmZmVyIChyZWZlcmVuY2UgY2hlY2sgZmlyc3QpXG4gICAgICAgIGRpZmZWYWx1ZShjdXJyZW50W2tleV0sIHRhcmdldFZhbCwgWy4uLnBhdGgsIGtleV0sIG9wcylcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gZGlmZkFycmF5KGN1cnJlbnQ6IEpTT05WYWx1ZVtdLCB0YXJnZXQ6IEpTT05WYWx1ZVtdLCBwYXRoOiBQYXRoLCBvcHM6IE9wW10pOiB2b2lkIHtcbiAgY29uc3QgY3VycmVudExlbiA9IGN1cnJlbnQubGVuZ3RoXG4gIGNvbnN0IHRhcmdldExlbiA9IHRhcmdldC5sZW5ndGhcbiAgY29uc3QgbWluTGVuID0gY3VycmVudExlbiA8IHRhcmdldExlbiA/IGN1cnJlbnRMZW4gOiB0YXJnZXRMZW5cblxuICAvLyBEaWZmIGNvbW1vbiBlbGVtZW50c1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG1pbkxlbjsgaSsrKSB7XG4gICAgaWYgKGN1cnJlbnRbaV0gIT09IHRhcmdldFtpXSkge1xuICAgICAgZGlmZlZhbHVlKGN1cnJlbnRbaV0sIHRhcmdldFtpXSwgWy4uLnBhdGgsIGldLCBvcHMpXG4gICAgfVxuICB9XG5cbiAgLy8gSGFuZGxlIGxlbmd0aCBkaWZmZXJlbmNlXG4gIGlmICh0YXJnZXRMZW4gPiBjdXJyZW50TGVuKSB7XG4gICAgb3BzLnB1c2goe1xuICAgICAga2luZDogXCJzcGxpY2VcIixcbiAgICAgIHBhdGgsXG4gICAgICBpbmRleDogY3VycmVudExlbixcbiAgICAgIGRlbGV0ZUNvdW50OiAwLFxuICAgICAgaW5zZXJ0czogdGFyZ2V0LnNsaWNlKGN1cnJlbnRMZW4pLFxuICAgIH0pXG4gIH0gZWxzZSBpZiAoY3VycmVudExlbiA+IHRhcmdldExlbikge1xuICAgIG9wcy5wdXNoKHtcbiAgICAgIGtpbmQ6IFwic3BsaWNlXCIsXG4gICAgICBwYXRoLFxuICAgICAgaW5kZXg6IHRhcmdldExlbixcbiAgICAgIGRlbGV0ZUNvdW50OiBjdXJyZW50TGVuIC0gdGFyZ2V0TGVuLFxuICAgICAgaW5zZXJ0czogW10sXG4gICAgfSlcbiAgfVxufVxuXG5mdW5jdGlvbiBlbWl0UmVwbGFjZShwYXRoOiBQYXRoLCB2YWx1ZTogSlNPTlZhbHVlLCBvcHM6IE9wW10pOiB2b2lkIHtcbiAgaWYgKHBhdGgubGVuZ3RoID09PSAwKSB7XG4gICAgLy8gQ2Fubm90IHJlcGxhY2Ugcm9vdCBkaXJlY3RseSB2aWEgT3BzICh1bmxlc3Mgd2UgZGVmaW5lIGEgJ3Jvb3QnIG9wLCB3aGljaCB3ZSBkb24ndClcbiAgICAvLyBXZSBleHBlY3Qgcm9vdCB0byBiZSBoYW5kbGVkIGJ5IGRpZmZPYmplY3QgdXN1YWxseS5cbiAgICAvLyBJZiB3ZSBsYW5kIGhlcmUsIGl0IG1lYW5zIHJvb3QgdHlwZXMgbWlzbWF0Y2hlZCAoZS5nLiBPYmogLT4gQXJyYXkpLlxuICAgIGZhaWx1cmUoXCJTdGF0ZVN5bmNMb2c6IENhbm5vdCByZXBsYWNlIHJvb3Qgc3RhdGUgZGlyZWN0bHkgdmlhIE9wcy5cIilcbiAgfVxuXG4gIGNvbnN0IHBhcmVudFBhdGggPSBwYXRoLnNsaWNlKDAsIC0xKVxuICBjb25zdCBrZXlUb0NoZWNrID0gcGF0aFtwYXRoLmxlbmd0aCAtIDFdXG5cbiAgaWYgKHR5cGVvZiBrZXlUb0NoZWNrID09PSBcInN0cmluZ1wiKSB7XG4gICAgLy8gUGFyZW50IGlzIE9iamVjdFxuICAgIG9wcy5wdXNoKHsga2luZDogXCJzZXRcIiwgcGF0aDogcGFyZW50UGF0aCwga2V5OiBrZXlUb0NoZWNrLCB2YWx1ZSB9KVxuICB9IGVsc2Uge1xuICAgIC8vIFBhcmVudCBpcyBBcnJheVxuICAgIG9wcy5wdXNoKHtcbiAgICAgIGtpbmQ6IFwic3BsaWNlXCIsXG4gICAgICBwYXRoOiBwYXJlbnRQYXRoLFxuICAgICAgaW5kZXg6IGtleVRvQ2hlY2ssXG4gICAgICBkZWxldGVDb3VudDogMSxcbiAgICAgIGluc2VydHM6IFt2YWx1ZV0sXG4gICAgfSlcbiAgfVxufVxuIiwiaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuL2Vycm9yXCJcblxuLyoqXG4gKiBQYXJzZWQgdHggdGltZXN0YW1wIGNvbXBvbmVudHMuXG4gKi9cbmV4cG9ydCB0eXBlIFR4VGltZXN0YW1wID0ge1xuICBlcG9jaDogbnVtYmVyXG4gIGNsb2NrOiBudW1iZXJcbiAgY2xpZW50SWQ6IHN0cmluZ1xuICB3YWxsQ2xvY2s6IG51bWJlclxufVxuXG4vKipcbiAqIFVuaXF1ZSB0eCBJRCAoQ29tcG9zaXRlIEtleSkuXG4gKi9cbmV4cG9ydCB0eXBlIFR4VGltZXN0YW1wS2V5ID0gc3RyaW5nXG5cbi8qKlxuICogQ29udmVydHMgYSB0aW1lc3RhbXAgb2JqZWN0IHRvIGEgVHJhbnNhY3Rpb25UaW1lc3RhbXBLZXkgc3RyaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdHhUaW1lc3RhbXBUb0tleSh0czogVHhUaW1lc3RhbXApOiBUeFRpbWVzdGFtcEtleSB7XG4gIHJldHVybiBgJHt0cy5lcG9jaH07JHt0cy5jbG9ja307JHt0cy5jbGllbnRJZH07JHt0cy53YWxsQ2xvY2t9YFxufVxuXG4vKipcbiAqIEhlbHBlciB0byBwYXJzZSB0eCB0aW1lc3RhbXAga2V5cy5cbiAqIFRocm93cyBpZiBrZXkgaXMgbWFsZm9ybWVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VUeFRpbWVzdGFtcEtleShrZXk6IFR4VGltZXN0YW1wS2V5KTogVHhUaW1lc3RhbXAge1xuICBjb25zdCBpMSA9IGtleS5pbmRleE9mKFwiO1wiKVxuICBjb25zdCBpMiA9IGtleS5pbmRleE9mKFwiO1wiLCBpMSArIDEpXG4gIGNvbnN0IGkzID0ga2V5LmluZGV4T2YoXCI7XCIsIGkyICsgMSlcblxuICBpZiAoaTEgPT09IC0xIHx8IGkyID09PSAtMSB8fCBpMyA9PT0gLTEpIHtcbiAgICBmYWlsdXJlKGBNYWxmb3JtZWQgdGltZXN0YW1wIGtleTogJHtrZXl9YClcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZXBvY2g6IE51bWJlci5wYXJzZUludChrZXkuc3Vic3RyaW5nKDAsIGkxKSwgMTApLFxuICAgIGNsb2NrOiBOdW1iZXIucGFyc2VJbnQoa2V5LnN1YnN0cmluZyhpMSArIDEsIGkyKSwgMTApLFxuICAgIGNsaWVudElkOiBrZXkuc3Vic3RyaW5nKGkyICsgMSwgaTMpLFxuICAgIHdhbGxDbG9jazogTnVtYmVyLnBhcnNlSW50KGtleS5zdWJzdHJpbmcoaTMgKyAxKSwgMTApLFxuICB9XG59XG5cbi8qKlxuICogQ29tcGFyZXMgdHdvIHR4IHRpbWVzdGFtcHMgZm9yIGRldGVybWluaXN0aWMgb3JkZXJpbmcuXG4gKiBTb3J0IG9yZGVyOiBlcG9jaCAoYXNjKSDihpIgY2xvY2sgKGFzYykg4oaSIGNsaWVudElkIChhc2MpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb21wYXJlVHhUaW1lc3RhbXBzKGE6IFR4VGltZXN0YW1wLCBiOiBUeFRpbWVzdGFtcCk6IG51bWJlciB7XG4gIGlmIChhLmVwb2NoICE9PSBiLmVwb2NoKSByZXR1cm4gYS5lcG9jaCAtIGIuZXBvY2hcbiAgaWYgKGEuY2xvY2sgIT09IGIuY2xvY2spIHJldHVybiBhLmNsb2NrIC0gYi5jbG9ja1xuICBpZiAoYS5jbGllbnRJZCA8IGIuY2xpZW50SWQpIHJldHVybiAtMVxuICBpZiAoYS5jbGllbnRJZCA+IGIuY2xpZW50SWQpIHJldHVybiAxXG4gIHJldHVybiAwXG59XG4iLCJpbXBvcnQgdHlwZSAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4vZXJyb3JcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyBwYXJzZVR4VGltZXN0YW1wS2V5LCB0eXBlIFR4VGltZXN0YW1wLCB0eXBlIFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuXG4vKipcbiAqIEEgY2FjaGVkIHR4IGVudHJ5IHdpdGggbGF6eSBwYXJzaW5nIGFuZCBvcHRpb25hbCB0eCBjYWNoaW5nLlxuICogVGhlIHRpbWVzdGFtcCBpcyBwYXJzZWQgb24gZmlyc3QgYWNjZXNzIGFuZCBjYWNoZWQuXG4gKiBUaGUgdHggcmVjb3JkIGNhbiBiZSBmZXRjaGVkIGxhemlseSBhbmQgY2FjaGVkLlxuICovXG5leHBvcnQgY2xhc3MgU29ydGVkVHhFbnRyeSB7XG4gIHByaXZhdGUgX3R4VGltZXN0YW1wPzogVHhUaW1lc3RhbXBcbiAgcHJpdmF0ZSBfb3JpZ2luYWxUeFRpbWVzdGFtcEtleT86IFR4VGltZXN0YW1wS2V5IHwgbnVsbFxuICBwcml2YXRlIF9vcmlnaW5hbFR4VGltZXN0YW1wPzogVHhUaW1lc3RhbXAgfCBudWxsXG4gIHByaXZhdGUgX3R4UmVjb3JkPzogVHhSZWNvcmRcblxuICBjb25zdHJ1Y3RvcihcbiAgICByZWFkb25seSB0eFRpbWVzdGFtcEtleTogVHhUaW1lc3RhbXBLZXksXG4gICAgcHJpdmF0ZSByZWFkb25seSBfeVR4OiBZLk1hcDxUeFJlY29yZD5cbiAgKSB7fVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBwYXJzZWQgdGltZXN0YW1wLCBsYXppbHkgcGFyc2luZyBhbmQgY2FjaGluZyBvbiBmaXJzdCBhY2Nlc3MuXG4gICAqL1xuICBnZXQgdHhUaW1lc3RhbXAoKTogVHhUaW1lc3RhbXAge1xuICAgIGlmICghdGhpcy5fdHhUaW1lc3RhbXApIHtcbiAgICAgIHRoaXMuX3R4VGltZXN0YW1wID0gcGFyc2VUeFRpbWVzdGFtcEtleSh0aGlzLnR4VGltZXN0YW1wS2V5KVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fdHhUaW1lc3RhbXBcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBvcmlnaW5hbCB0eCB0aW1lc3RhbXAga2V5LCBsYXppbHkgYW5kIGNhY2hpbmcgb24gZmlyc3QgYWNjZXNzLlxuICAgKi9cbiAgZ2V0IG9yaWdpbmFsVHhUaW1lc3RhbXBLZXkoKTogVHhUaW1lc3RhbXBLZXkgfCBudWxsIHtcbiAgICBpZiAodGhpcy5fb3JpZ2luYWxUeFRpbWVzdGFtcEtleSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCB0eCA9IHRoaXMudHhSZWNvcmRcbiAgICAgIHRoaXMuX29yaWdpbmFsVHhUaW1lc3RhbXBLZXkgPSB0eC5vcmlnaW5hbFR4S2V5ID8/IG51bGxcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX29yaWdpbmFsVHhUaW1lc3RhbXBLZXlcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBwYXJzZWQgb3JpZ2luYWwgdHggdGltZXN0YW1wLCBsYXppbHkgcGFyc2luZyBhbmQgY2FjaGluZyBvbiBmaXJzdCBhY2Nlc3MuXG4gICAqL1xuICBnZXQgb3JpZ2luYWxUeFRpbWVzdGFtcCgpOiBUeFRpbWVzdGFtcCB8IG51bGwge1xuICAgIGlmICh0aGlzLl9vcmlnaW5hbFR4VGltZXN0YW1wID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IGtleSA9IHRoaXMub3JpZ2luYWxUeFRpbWVzdGFtcEtleVxuICAgICAgdGhpcy5fb3JpZ2luYWxUeFRpbWVzdGFtcCA9IGtleSA/IHBhcnNlVHhUaW1lc3RhbXBLZXkoa2V5KSA6IG51bGxcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX29yaWdpbmFsVHhUaW1lc3RhbXBcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBsb2dpY2FsIChkZWR1cGxpY2F0ZWQpIHR4IHRpbWVzdGFtcCBrZXkuXG4gICAqIFRoaXMgaXMgdGhlIG9yaWdpbmFsIHR4IGtleSBpZiBpdCBleGlzdHMsIG90aGVyd2lzZSB0aGUgcGh5c2ljYWwga2V5LlxuICAgKi9cbiAgZ2V0IGRlZHVwVHhUaW1lc3RhbXBLZXkoKTogVHhUaW1lc3RhbXBLZXkge1xuICAgIHJldHVybiB0aGlzLm9yaWdpbmFsVHhUaW1lc3RhbXBLZXkgPz8gdGhpcy50eFRpbWVzdGFtcEtleVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGxvZ2ljYWwgKGRlZHVwbGljYXRlZCkgcGFyc2VkIHR4IHRpbWVzdGFtcC5cbiAgICogVGhpcyBpcyB0aGUgb3JpZ2luYWwgdHggdGltZXN0YW1wIGlmIGl0IGV4aXN0cywgb3RoZXJ3aXNlIHRoZSBwaHlzaWNhbCB0aW1lc3RhbXAuXG4gICAqL1xuICBnZXQgZGVkdXBUeFRpbWVzdGFtcCgpOiBUeFRpbWVzdGFtcCB7XG4gICAgcmV0dXJuIHRoaXMub3JpZ2luYWxUeFRpbWVzdGFtcCA/PyB0aGlzLnR4VGltZXN0YW1wXG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgdHggcmVjb3JkLCBsYXppbHkgZmV0Y2hpbmcgYW5kIGNhY2hpbmcgb24gZmlyc3QgYWNjZXNzLlxuICAgKiBSZXR1cm5zIHVuZGVmaW5lZCBpZiB0aGUgdHggZG9lc24ndCBleGlzdC5cbiAgICovXG4gIGdldCB0eFJlY29yZCgpOiBUeFJlY29yZCB7XG4gICAgaWYgKCF0aGlzLl90eFJlY29yZCkge1xuICAgICAgdGhpcy5fdHhSZWNvcmQgPSB0aGlzLl95VHguZ2V0KHRoaXMudHhUaW1lc3RhbXBLZXkpXG4gICAgICBpZiAoIXRoaXMuX3R4UmVjb3JkKSB7XG4gICAgICAgIHRocm93IGZhaWx1cmUoYFNvcnRlZFR4RW50cnk6IFR4UmVjb3JkIG5vdCBmb3VuZCBmb3Iga2V5ICR7dGhpcy50eFRpbWVzdGFtcEtleX1gKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fdHhSZWNvcmRcbiAgfVxufVxuIiwiaW1wb3J0IHR5cGUgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgdHlwZSBDaGVja3BvaW50UmVjb3JkLCB0eXBlIENsaWVudFdhdGVybWFya3MgfSBmcm9tIFwiLi9jaGVja3BvaW50c1wiXG5pbXBvcnQgeyBhcHBseVR4SW1tdXRhYmxlIH0gZnJvbSBcIi4vZHJhZnRcIlxuaW1wb3J0IHsgSlNPTk9iamVjdCB9IGZyb20gXCIuL2pzb25cIlxuaW1wb3J0IHsgT3AsIFZhbGlkYXRlRm4gfSBmcm9tIFwiLi9vcGVyYXRpb25zXCJcbmltcG9ydCB7IGNvbXB1dGVSZWNvbmNpbGVPcHMgfSBmcm9tIFwiLi9yZWNvbmNpbGVcIlxuaW1wb3J0IHsgU29ydGVkVHhFbnRyeSB9IGZyb20gXCIuL1NvcnRlZFR4RW50cnlcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyBjb21wYXJlVHhUaW1lc3RhbXBzLCB0eXBlIFR4VGltZXN0YW1wLCB0eXBlIFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuaW1wb3J0IHsgbGF6eSB9IGZyb20gXCIuL3V0aWxzXCJcblxuLyoqXG4gKiBDaGVja3MgaWYgYSB0cmFuc2FjdGlvbiBpcyBjb3ZlcmVkIGJ5IHRoZSBjaGVja3BvaW50IHdhdGVybWFya3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1RyYW5zYWN0aW9uSW5DaGVja3BvaW50KHRzOiBUeFRpbWVzdGFtcCwgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyk6IGJvb2xlYW4ge1xuICBjb25zdCB3bSA9IHdhdGVybWFya3NbdHMuY2xpZW50SWRdXG4gIGlmICghd20pIHJldHVybiBmYWxzZVxuICByZXR1cm4gdHMuY2xvY2sgPD0gd20ubWF4Q2xvY2tcbn1cblxuLyoqXG4gKiBTdGF0ZUNhbGN1bGF0b3IgZW5jYXBzdWxhdGVzIHRoZSBzb3J0ZWQgdHJhbnNhY3Rpb24gY2FjaGUgYW5kIHN0YXRlIGNhbGN1bGF0aW9uIGxvZ2ljLlxuICpcbiAqIEl0IG1haW50YWluczpcbiAqIC0gQSBzb3J0ZWQgYXJyYXkgb2YgdHJhbnNhY3Rpb24gZW50cmllc1xuICogLSBBIG1hcCBmb3IgTygxKSBsb29rdXBcbiAqIC0gQSB0cmFja2luZyBpbmRleCBpbmRpY2F0aW5nIHVwIHRvIHdoaWNoIHR4IHRoZSBzdGF0ZSBoYXMgYmVlbiBjYWxjdWxhdGVkXG4gKiAtIFRoZSBjYWNoZWQgY2FsY3VsYXRlZCBzdGF0ZVxuICogLSBUaGUgYmFzZSBjaGVja3BvaW50XG4gKlxuICogVGhlIHRyYWNraW5nIGluZGV4IGlzIGludmFsaWRhdGVkIChzZXQgdG8gbnVsbCkgd2hlbjpcbiAqIC0gQSB0cmFuc2FjdGlvbiBpcyBpbnNlcnRlZCBiZWZvcmUgdGhlIGFscmVhZHktY2FsY3VsYXRlZCBzbGljZVxuICogLSBBIHRyYW5zYWN0aW9uIGlzIGRlbGV0ZWQgZnJvbSB0aGUgYWxyZWFkeS1jYWxjdWxhdGVkIHNsaWNlXG4gKiAtIFRoZSBiYXNlIGNoZWNrcG9pbnQgY2hhbmdlc1xuICovXG5leHBvcnQgY2xhc3MgU3RhdGVDYWxjdWxhdG9yIHtcbiAgLyoqIFNvcnRlZCB0eCBjYWNoZSAoQUxMIGFjdGl2ZS9mdXR1cmUgdHhzLCBrZXB0IHNvcnRlZCBieSB0aW1lc3RhbXApICovXG4gIHByaXZhdGUgc29ydGVkVHhzOiBTb3J0ZWRUeEVudHJ5W10gPSBbXVxuXG4gIC8qKiBPKDEpIGV4aXN0ZW5jZSBjaGVjayBhbmQgbG9va3VwICovXG4gIHByaXZhdGUgc29ydGVkVHhzTWFwOiBNYXA8VHhUaW1lc3RhbXBLZXksIFNvcnRlZFR4RW50cnk+ID0gbmV3IE1hcCgpXG5cbiAgLyoqXG4gICAqIEluZGV4IG9mIHRoZSBsYXN0IHRyYW5zYWN0aW9uIGFwcGxpZWQgdG8gY2FjaGVkU3RhdGUuXG4gICAqIC0gbnVsbDogc3RhdGUgbmVlZHMgZnVsbCByZWNhbGN1bGF0aW9uIGZyb20gY2hlY2twb2ludFxuICAgKiAtIC0xOiBubyB0cmFuc2FjdGlvbnMgaGF2ZSBiZWVuIGFwcGxpZWQgeWV0IChzdGF0ZSA9PT0gY2hlY2twb2ludCBzdGF0ZSlcbiAgICogLSA+PSAwOiB0cmFuc2FjdGlvbnMgdXAgdG8gYW5kIGluY2x1ZGluZyB0aGlzIGluZGV4IGhhdmUgYmVlbiBhcHBsaWVkXG4gICAqL1xuICBwcml2YXRlIGxhc3RBcHBsaWVkSW5kZXg6IG51bWJlciB8IG51bGwgPSBudWxsXG5cbiAgLyoqIFRoZSBjYWNoZWQgY2FsY3VsYXRlZCBzdGF0ZSAqL1xuICBwcml2YXRlIGNhY2hlZFN0YXRlOiBKU09OT2JqZWN0IHwgbnVsbCA9IG51bGxcblxuICAvKiogVGhlIGJhc2UgY2hlY2twb2ludCB0byBjYWxjdWxhdGUgc3RhdGUgZnJvbSAqL1xuICBwcml2YXRlIGJhc2VDaGVja3BvaW50OiBDaGVja3BvaW50UmVjb3JkIHwgbnVsbCA9IG51bGxcblxuICAvKipcbiAgICogQXBwbGllZCBkZWR1cCBrZXlzIC0gdHJhY2tzIHdoaWNoIExPR0lDQUwgdHhzIGhhdmUgYmVlbiBhcHBsaWVkLlxuICAgKiBUaGlzIGlzIHRoZSBvcmlnaW5hbFR4S2V5IChvciBwaHlzaWNhbCBrZXkgaWYgbm8gb3JpZ2luYWwpIGZvciBlYWNoIGFwcGxpZWQgdHguXG4gICAqIFVzZWQgdG8gcHJvcGVybHkgZGVkdXBsaWNhdGUgcmUtZW1pdHMuXG4gICAqL1xuICBwcml2YXRlIGFwcGxpZWRUeEtleXM6IFNldDxUeFRpbWVzdGFtcEtleT4gPSBuZXcgU2V0KClcblxuICAvKiogTWF4IGNsb2NrIHNlZW4gZnJvbSBhbnkgdHJhbnNhY3Rpb24gKGZvciBMYW1wb3J0IGNsb2NrIHVwZGF0ZXMpICovXG4gIHByaXZhdGUgbWF4U2VlbkNsb2NrID0gMFxuXG4gIC8qKiBWYWxpZGF0aW9uIGZ1bmN0aW9uIChvcHRpb25hbCkgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZUZuPzogVmFsaWRhdGVGbjxKU09OT2JqZWN0PlxuXG4gIGNvbnN0cnVjdG9yKHZhbGlkYXRlRm4/OiBWYWxpZGF0ZUZuPEpTT05PYmplY3Q+KSB7XG4gICAgdGhpcy52YWxpZGF0ZUZuID0gdmFsaWRhdGVGblxuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGJhc2UgY2hlY2twb2ludC4gSW52YWxpZGF0ZXMgY2FjaGVkIHN0YXRlIGlmIGNoZWNrcG9pbnQgY2hhbmdlZC5cbiAgICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgY2hlY2twb2ludCBjaGFuZ2VkXG4gICAqL1xuICBzZXRCYXNlQ2hlY2twb2ludChjaGVja3BvaW50OiBDaGVja3BvaW50UmVjb3JkIHwgbnVsbCk6IGJvb2xlYW4ge1xuICAgIGlmIChjaGVja3BvaW50ID09PSB0aGlzLmJhc2VDaGVja3BvaW50KSB7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG5cbiAgICB0aGlzLmJhc2VDaGVja3BvaW50ID0gY2hlY2twb2ludFxuICAgIHRoaXMuaW52YWxpZGF0ZSgpXG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBjdXJyZW50IGJhc2UgY2hlY2twb2ludC5cbiAgICovXG4gIGdldEJhc2VDaGVja3BvaW50KCk6IENoZWNrcG9pbnRSZWNvcmQgfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5iYXNlQ2hlY2twb2ludFxuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyBhbGwgdHJhbnNhY3Rpb25zIGFuZCByZWJ1aWxkcyBmcm9tIHlUeCBtYXAuXG4gICAqIFRoaXMgaXMgdXNlZCB3aGVuIHRoZSBjaGVja3BvaW50IGNoYW5nZXMgYW5kIHdlIG5lZWQgYSBmcmVzaCBzdGFydC5cbiAgICovXG4gIHJlYnVpbGRGcm9tWWpzKHlUeDogWS5NYXA8VHhSZWNvcmQ+KTogdm9pZCB7XG4gICAgdGhpcy5zb3J0ZWRUeHMgPSBbXVxuICAgIHRoaXMuc29ydGVkVHhzTWFwLmNsZWFyKClcblxuICAgIC8vIENvbGxlY3QgYWxsIGVudHJpZXMsIGJ1aWxkIHRoZSBtYXAgYW5kIG1heCBjbG9ja1xuICAgIGZvciAoY29uc3Qga2V5IG9mIHlUeC5rZXlzKCkpIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gbmV3IFNvcnRlZFR4RW50cnkoa2V5LCB5VHgpXG4gICAgICB0aGlzLnNvcnRlZFR4cy5wdXNoKGVudHJ5KVxuXG4gICAgICB0aGlzLnNvcnRlZFR4c01hcC5zZXQoZW50cnkudHhUaW1lc3RhbXBLZXksIGVudHJ5KVxuICAgICAgaWYgKGVudHJ5LnR4VGltZXN0YW1wLmNsb2NrID4gdGhpcy5tYXhTZWVuQ2xvY2spIHtcbiAgICAgICAgdGhpcy5tYXhTZWVuQ2xvY2sgPSBlbnRyeS50eFRpbWVzdGFtcC5jbG9ja1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFNvcnQgb25jZSAtIE8obiBsb2cgbilcbiAgICB0aGlzLnNvcnRlZFR4cy5zb3J0KChhLCBiKSA9PiBjb21wYXJlVHhUaW1lc3RhbXBzKGEudHhUaW1lc3RhbXAsIGIudHhUaW1lc3RhbXApKVxuXG4gICAgLy8gSW52YWxpZGF0ZSBjYWNoZWQgc3RhdGUgc2luY2Ugd2UgcmVidWlsdFxuICAgIHRoaXMuaW52YWxpZGF0ZSgpXG4gIH1cblxuICAvKipcbiAgICogSW5zZXJ0cyBhIHRyYW5zYWN0aW9uIGludG8gdGhlIHNvcnRlZCBjYWNoZS5cbiAgICogSW52YWxpZGF0ZXMgY2FjaGVkIHN0YXRlIGlmIHRoZSB0cmFuc2FjdGlvbiB3YXMgaW5zZXJ0ZWQgYmVmb3JlIHRoZSBjYWxjdWxhdGVkIHNsaWNlLlxuICAgKlxuICAgKiBAcmV0dXJucyB0cnVlIGlmIHRoaXMgY2F1c2VkIGludmFsaWRhdGlvbiAob3V0LW9mLW9yZGVyIGluc2VydClcbiAgICovXG4gIGluc2VydFR4KGtleTogVHhUaW1lc3RhbXBLZXksIHlUeDogWS5NYXA8VHhSZWNvcmQ+KTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuc29ydGVkVHhzTWFwLmhhcyhrZXkpKSB7XG4gICAgICByZXR1cm4gZmFsc2UgLy8gQWxyZWFkeSBleGlzdHNcbiAgICB9XG5cbiAgICBjb25zdCBlbnRyeSA9IG5ldyBTb3J0ZWRUeEVudHJ5KGtleSwgeVR4KVxuICAgIGNvbnN0IHRzID0gZW50cnkudHhUaW1lc3RhbXBcblxuICAgIC8vIFVwZGF0ZSBtYXggc2VlbiBjbG9jayBmb3IgTGFtcG9ydCBjbG9jayBtZWNoYW5pc21cbiAgICBpZiAodHMuY2xvY2sgPiB0aGlzLm1heFNlZW5DbG9jaykge1xuICAgICAgdGhpcy5tYXhTZWVuQ2xvY2sgPSB0cy5jbG9ja1xuICAgIH1cblxuICAgIGNvbnN0IHNvcnRlZFR4cyA9IHRoaXMuc29ydGVkVHhzXG5cbiAgICAvLyBGaW5kIGluc2VydGlvbiBwb3NpdGlvbiAoc2VhcmNoIGZyb20gZW5kIHNpbmNlIG5ldyB0eHMgdHlwaWNhbGx5IGhhdmUgaGlnaGVyIHRpbWVzdGFtcHMpXG4gICAgbGV0IGluc2VydEluZGV4ID0gc29ydGVkVHhzLmxlbmd0aCAvLyBEZWZhdWx0OiBhcHBlbmQgYXQgZW5kXG4gICAgZm9yIChsZXQgaSA9IHNvcnRlZFR4cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgY29uc3QgZXhpc3RpbmdUcyA9IHNvcnRlZFR4c1tpXS50eFRpbWVzdGFtcFxuICAgICAgaWYgKGNvbXBhcmVUeFRpbWVzdGFtcHModHMsIGV4aXN0aW5nVHMpID49IDApIHtcbiAgICAgICAgaW5zZXJ0SW5kZXggPSBpICsgMVxuICAgICAgICBicmVha1xuICAgICAgfVxuICAgICAgaWYgKGkgPT09IDApIHtcbiAgICAgICAgaW5zZXJ0SW5kZXggPSAwIC8vIEluc2VydCBhdCBiZWdpbm5pbmdcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBJbnNlcnQgYXQgdGhlIGZvdW5kIHBvc2l0aW9uXG4gICAgc29ydGVkVHhzLnNwbGljZShpbnNlcnRJbmRleCwgMCwgZW50cnkpXG4gICAgdGhpcy5zb3J0ZWRUeHNNYXAuc2V0KGtleSwgZW50cnkpXG5cbiAgICAvLyBDaGVjayBpZiB0aGlzIGludmFsaWRhdGVzIG91ciBjYWNoZWQgc3RhdGVcbiAgICAvLyBJZiB3ZSBpbnNlcnRlZCBiZWZvcmUgb3IgYXQgdGhlIGxhc3QgYXBwbGllZCBpbmRleCwgd2UgbmVlZCB0byByZWNhbGN1bGF0ZVxuICAgIGlmICh0aGlzLmxhc3RBcHBsaWVkSW5kZXggIT09IG51bGwgJiYgaW5zZXJ0SW5kZXggPD0gdGhpcy5sYXN0QXBwbGllZEluZGV4KSB7XG4gICAgICB0aGlzLmludmFsaWRhdGUoKVxuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIG11bHRpcGxlIHRyYW5zYWN0aW9ucyBmcm9tIHRoZSBzb3J0ZWQgY2FjaGUuXG4gICAqIEByZXR1cm5zIHRoZSBudW1iZXIgb2Yga2V5cyB0aGF0IHdlcmUgYWN0dWFsbHkgcmVtb3ZlZFxuICAgKi9cbiAgcmVtb3ZlVHhzKGtleXM6IHJlYWRvbmx5IFR4VGltZXN0YW1wS2V5W10pOiBudW1iZXIge1xuICAgIGlmIChrZXlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIDBcblxuICAgIGxldCByZW1vdmVkQ291bnQgPSAwXG4gICAgbGV0IG1pblJlbW92ZWRJbmRleCA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWVxuXG4gICAgLy8gQnVpbGQgc2V0IG9mIGtleXMgdG8gZGVsZXRlIGFuZCB0cmFjayB0aGVpciBpbmRpY2VzXG4gICAgY29uc3QgdG9EZWxldGUgPSBuZXcgU2V0PFR4VGltZXN0YW1wS2V5PigpXG4gICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgY29uc3QgZW50cnkgPSB0aGlzLnNvcnRlZFR4c01hcC5nZXQoa2V5KVxuICAgICAgaWYgKGVudHJ5KSB7XG4gICAgICAgIHRoaXMuc29ydGVkVHhzTWFwLmRlbGV0ZShrZXkpXG4gICAgICAgIHRvRGVsZXRlLmFkZChrZXkpXG5cbiAgICAgICAgLy8gRmluZCBpbmRleCBmb3IgaW52YWxpZGF0aW9uIGNoZWNrXG4gICAgICAgIGNvbnN0IGluZGV4ID0gdGhpcy5zb3J0ZWRUeHMuaW5kZXhPZihlbnRyeSlcbiAgICAgICAgaWYgKGluZGV4ICE9PSAtMSAmJiBpbmRleCA8IG1pblJlbW92ZWRJbmRleCkge1xuICAgICAgICAgIG1pblJlbW92ZWRJbmRleCA9IGluZGV4XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodG9EZWxldGUuc2l6ZSA9PT0gMCkgcmV0dXJuIDBcblxuICAgIC8vIFNpbmdsZSBmb3J3YXJkIHBhc3MgdGhyb3VnaCBzb3J0ZWRUeHMsIHJlbW92aW5nIG1hdGNoaW5nIGVudHJpZXNcbiAgICBjb25zdCBzb3J0ZWRUeHMgPSB0aGlzLnNvcnRlZFR4c1xuICAgIGxldCBpID0gMFxuICAgIHdoaWxlIChpIDwgc29ydGVkVHhzLmxlbmd0aCAmJiB0b0RlbGV0ZS5zaXplID4gMCkge1xuICAgICAgaWYgKHRvRGVsZXRlLmhhcyhzb3J0ZWRUeHNbaV0udHhUaW1lc3RhbXBLZXkpKSB7XG4gICAgICAgIHRvRGVsZXRlLmRlbGV0ZShzb3J0ZWRUeHNbaV0udHhUaW1lc3RhbXBLZXkpXG4gICAgICAgIHNvcnRlZFR4cy5zcGxpY2UoaSwgMSlcbiAgICAgICAgcmVtb3ZlZENvdW50KytcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGkrK1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENoZWNrIGlmIHRoaXMgaW52YWxpZGF0ZXMgb3VyIGNhY2hlZCBzdGF0ZVxuICAgIGlmICh0aGlzLmxhc3RBcHBsaWVkSW5kZXggIT09IG51bGwgJiYgbWluUmVtb3ZlZEluZGV4IDw9IHRoaXMubGFzdEFwcGxpZWRJbmRleCkge1xuICAgICAgdGhpcy5pbnZhbGlkYXRlKClcbiAgICB9XG5cbiAgICByZXR1cm4gcmVtb3ZlZENvdW50XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGEgdHJhbnNhY3Rpb24ga2V5IGV4aXN0cyBpbiB0aGUgY2FjaGUuXG4gICAqL1xuICBoYXNUeChrZXk6IFR4VGltZXN0YW1wS2V5KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc29ydGVkVHhzTWFwLmhhcyhrZXkpXG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhIHRyYW5zYWN0aW9uIGVudHJ5IGJ5IGtleS5cbiAgICovXG4gIGdldFR4KGtleTogVHhUaW1lc3RhbXBLZXkpOiBTb3J0ZWRUeEVudHJ5IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zb3J0ZWRUeHNNYXAuZ2V0KGtleSlcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGFsbCBzb3J0ZWQgdHJhbnNhY3Rpb24gZW50cmllcy5cbiAgICovXG4gIGdldFNvcnRlZFR4cygpOiByZWFkb25seSBTb3J0ZWRUeEVudHJ5W10ge1xuICAgIHJldHVybiB0aGlzLnNvcnRlZFR4c1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIG51bWJlciBvZiB0cmFuc2FjdGlvbnMgaW4gdGhlIGNhY2hlLlxuICAgKi9cbiAgZ2V0IHR4Q291bnQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zb3J0ZWRUeHMubGVuZ3RoXG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBzdGF0ZSBuZWVkcyBmdWxsIHJlY2FsY3VsYXRpb24uXG4gICAqL1xuICBuZWVkc0Z1bGxSZWNhbGN1bGF0aW9uKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmxhc3RBcHBsaWVkSW5kZXggPT09IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZhbGlkYXRlcyB0aGUgY2FjaGVkIHN0YXRlLCBmb3JjaW5nIGEgZnVsbCByZWNhbGN1bGF0aW9uIG9uIG5leHQgY2FsY3VsYXRlU3RhdGUoKS5cbiAgICogTm90ZTogY2FjaGVkU3RhdGUgaXMga2VwdCBzbyBjb21wdXRlUmVjb25jaWxlT3BzIGNhbiBkaWZmIG9sZCB2cyBuZXcgc3RhdGUuXG4gICAqL1xuICBpbnZhbGlkYXRlKCk6IHZvaWQge1xuICAgIHRoaXMubGFzdEFwcGxpZWRJbmRleCA9IG51bGxcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXRlLCBhbG9uZyB3aXRoIGEgbGF6eSBnZXR0ZXIgZm9yIG9wcyB0aGF0IGNoYW5nZWQgZnJvbSB0aGUgcHJldmlvdXMgc3RhdGUuXG4gICAqXG4gICAqIC0gSWYgbGFzdEFwcGxpZWRJbmRleCBpcyBudWxsOiBmdWxsIHJlY2FsY3VsYXRpb24gZnJvbSBjaGVja3BvaW50XG4gICAqIC0gSWYgbGFzdEFwcGxpZWRJbmRleCA+PSAtMTogaW5jcmVtZW50YWwgYXBwbHkgZnJvbSBsYXN0QXBwbGllZEluZGV4ICsgMVxuICAgKi9cbiAgY2FsY3VsYXRlU3RhdGUoKTogeyBzdGF0ZTogSlNPTk9iamVjdDsgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSB9IHtcbiAgICBjb25zdCBiYXNlU3RhdGU6IEpTT05PYmplY3QgPSB0aGlzLmJhc2VDaGVja3BvaW50Py5zdGF0ZSA/PyB7fVxuICAgIGNvbnN0IHdhdGVybWFya3MgPSB0aGlzLmJhc2VDaGVja3BvaW50Py53YXRlcm1hcmtzID8/IHt9XG4gICAgY29uc3QgaGFzV2F0ZXJtYXJrcyA9IE9iamVjdC5rZXlzKHdhdGVybWFya3MpLmxlbmd0aCA+IDBcblxuICAgIGlmICh0aGlzLmxhc3RBcHBsaWVkSW5kZXggPT09IG51bGwpIHtcbiAgICAgIC8vIFNMT1cgUEFUSDogRnVsbCByZWNhbGN1bGF0aW9uXG4gICAgICByZXR1cm4gdGhpcy5mdWxsUmVjYWxjdWxhdGlvbihiYXNlU3RhdGUsIHdhdGVybWFya3MsIGhhc1dhdGVybWFya3MpXG4gICAgfVxuXG4gICAgLy8gRkFTVCBQQVRIOiBJbmNyZW1lbnRhbCBhcHBseVxuICAgIHJldHVybiB0aGlzLmluY3JlbWVudGFsQXBwbHkod2F0ZXJtYXJrcywgaGFzV2F0ZXJtYXJrcylcbiAgfVxuXG4gIC8qKlxuICAgKiBGdWxsIHJlY2FsY3VsYXRpb24gb2Ygc3RhdGUgZnJvbSB0aGUgYmFzZSBjaGVja3BvaW50LlxuICAgKi9cbiAgcHJpdmF0ZSBmdWxsUmVjYWxjdWxhdGlvbihcbiAgICBiYXNlU3RhdGU6IEpTT05PYmplY3QsXG4gICAgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyxcbiAgICBoYXNXYXRlcm1hcmtzOiBib29sZWFuXG4gICk6IHsgc3RhdGU6IEpTT05PYmplY3Q7IGdldEFwcGxpZWRPcHM6ICgpID0+IHJlYWRvbmx5IE9wW10gfSB7XG4gICAgY29uc3Qgb2xkU3RhdGUgPSB0aGlzLmNhY2hlZFN0YXRlID8/IHt9XG5cbiAgICAvLyBSZXNldCB0cmFja2luZyBmb3IgZnVsbCByZWNvbXB1dGVcbiAgICB0aGlzLmFwcGxpZWRUeEtleXMuY2xlYXIoKVxuICAgIHRoaXMubGFzdEFwcGxpZWRJbmRleCA9IC0xXG4gICAgdGhpcy5jYWNoZWRTdGF0ZSA9IGJhc2VTdGF0ZVxuXG4gICAgLy8gRGVsZWdhdGUgdG8gaW5jcmVtZW50YWwgYXBwbHkgdG8gcmVwbGF5IGFsbCB0cmFuc2FjdGlvbnNcbiAgICAvLyBXZSBpZ25vcmUgdGhlIHJldHVybmVkIG9wcyBiZWNhdXNlIHRoZXkgcmVwcmVzZW50IHRoZSBvcGVyYXRpb25zIGFwcGxpZWQgZnJvbSB0aGUgYmFzZSBzdGF0ZSxcbiAgICAvLyB3aGVyZWFzIHdlIHdhbnQgdGhlIGRpZmYgZnJvbSB0aGUgKnByZXZpb3VzIGNhY2hlZCBzdGF0ZSouXG4gICAgLy8gV2UgcGFzcyByZXR1cm5PcHM9ZmFsc2UgdG8gYXZvaWQgY29sbGVjdGluZyBvcHMgZHVyaW5nIHJlcGxheS5cbiAgICBjb25zdCB7IHN0YXRlIH0gPSB0aGlzLmluY3JlbWVudGFsQXBwbHkod2F0ZXJtYXJrcywgaGFzV2F0ZXJtYXJrcywgZmFsc2UpXG5cbiAgICAvLyBMYXp5IGxvYWQgdGhlIHJlY29uY2lsaWF0aW9uIG9wcyAoZXhwZW5zaXZlIGRpZmYpXG4gICAgY29uc3QgZ2V0QXBwbGllZE9wcyA9IGxhenkoKCkgPT4gY29tcHV0ZVJlY29uY2lsZU9wcyhvbGRTdGF0ZSwgc3RhdGUpKVxuXG4gICAgcmV0dXJuIHsgc3RhdGUsIGdldEFwcGxpZWRPcHMgfVxuICB9XG5cbiAgLyoqXG4gICAqIEluY3JlbWVudGFsIGFwcGx5IG9mIHRyYW5zYWN0aW9ucyBmcm9tIGxhc3RBcHBsaWVkSW5kZXggKyAxLlxuICAgKiBAcGFyYW0gcmV0dXJuT3BzIElmIHRydWUsIGNvbGxlY3RzIGFwcGxpZWQgdHJhbnNhY3Rpb25zICh0byBsYXp5IGNvbXB1dGUgb3BzKS4gSWYgZmFsc2UsIHNraXBzIGNvbGxlY3Rpb24uXG4gICAqL1xuICBwcml2YXRlIGluY3JlbWVudGFsQXBwbHkoXG4gICAgd2F0ZXJtYXJrczogQ2xpZW50V2F0ZXJtYXJrcyxcbiAgICBoYXNXYXRlcm1hcmtzOiBib29sZWFuLFxuICAgIHJldHVybk9wcyA9IHRydWVcbiAgKTogeyBzdGF0ZTogSlNPTk9iamVjdDsgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSB9IHtcbiAgICBsZXQgc3RhdGUgPSB0aGlzLmNhY2hlZFN0YXRlIGFzIEpTT05PYmplY3RcbiAgICBjb25zdCBhcHBsaWVkVHhzOiBUeFJlY29yZFtdID0gW11cbiAgICBjb25zdCBzb3J0ZWRUeHMgPSB0aGlzLnNvcnRlZFR4c1xuICAgIGNvbnN0IHN0YXJ0SW5kZXggPSB0aGlzLmxhc3RBcHBsaWVkSW5kZXghICsgMVxuXG4gICAgZm9yIChsZXQgaSA9IHN0YXJ0SW5kZXg7IGkgPCBzb3J0ZWRUeHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gc29ydGVkVHhzW2ldXG4gICAgICBjb25zdCBkZWR1cEtleSA9IGVudHJ5LmRlZHVwVHhUaW1lc3RhbXBLZXlcblxuICAgICAgLy8gU2tpcCBpZiBhbHJlYWR5IGFwcGxpZWQgKGRlZHVwbGljYXRpb24pXG4gICAgICBpZiAodGhpcy5hcHBsaWVkVHhLZXlzLmhhcyhkZWR1cEtleSkpIHtcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgLy8gU2tpcCBpZiBpbiBjaGVja3BvaW50XG4gICAgICBpZiAoaGFzV2F0ZXJtYXJrcykge1xuICAgICAgICBjb25zdCBkZWR1cFRzID0gZW50cnkuZGVkdXBUeFRpbWVzdGFtcFxuICAgICAgICBpZiAoaXNUcmFuc2FjdGlvbkluQ2hlY2twb2ludChkZWR1cFRzLCB3YXRlcm1hcmtzKSkge1xuICAgICAgICAgIHRoaXMuYXBwbGllZFR4S2V5cy5hZGQoZGVkdXBLZXkpXG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCB0eCA9IGVudHJ5LnR4UmVjb3JkXG5cbiAgICAgIC8vIEFwcGx5IHRyYW5zYWN0aW9uIDEtYnktMSB0byBhdm9pZCBkcmFmdCBjb250ZXh0IHBvbGx1dGlvbiBvbiB2YWxpZGF0aW9uIGZhaWx1cmVcbiAgICAgIGNvbnN0IG5ld1N0YXRlID0gYXBwbHlUeEltbXV0YWJsZShzdGF0ZSwgdHgsIHRoaXMudmFsaWRhdGVGbilcblxuICAgICAgaWYgKG5ld1N0YXRlICE9PSBzdGF0ZSkge1xuICAgICAgICBzdGF0ZSA9IG5ld1N0YXRlXG4gICAgICAgIGlmIChyZXR1cm5PcHMpIHtcbiAgICAgICAgICBhcHBsaWVkVHhzLnB1c2godHgpXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgdGhpcy5hcHBsaWVkVHhLZXlzLmFkZChkZWR1cEtleSlcbiAgICAgIHRoaXMubGFzdEFwcGxpZWRJbmRleCA9IGlcbiAgICB9XG5cbiAgICAvLyBVcGRhdGUgbGFzdEFwcGxpZWRJbmRleCB0byBlbmQgZXZlbiBpZiBhbGwgdHhzIHdlcmUgc2tpcHBlZFxuICAgIC8vIFRoaXMgZW5zdXJlcyB3ZSBkb24ndCByZS1wcm9jZXNzIHNraXBwZWQgdHhzIG9uIG5leHQgaW5jcmVtZW50YWwgYXBwbHlcbiAgICBpZiAoc29ydGVkVHhzLmxlbmd0aCA+IDAgJiYgdGhpcy5sYXN0QXBwbGllZEluZGV4ISA8IHNvcnRlZFR4cy5sZW5ndGggLSAxKSB7XG4gICAgICB0aGlzLmxhc3RBcHBsaWVkSW5kZXggPSBzb3J0ZWRUeHMubGVuZ3RoIC0gMVxuICAgIH1cblxuICAgIHRoaXMuY2FjaGVkU3RhdGUgPSBzdGF0ZVxuXG4gICAgLy8gTGF6eSBnZXR0ZXIgZm9yIG9wcyAoZmxhdHRlbnMgYXBwbGllZCB0eHMpXG4gICAgY29uc3QgZ2V0QXBwbGllZE9wcyA9IGxhenkoKCkgPT4ge1xuICAgICAgY29uc3Qgb3BzOiBPcFtdID0gW11cbiAgICAgIGZvciAoY29uc3QgdHggb2YgYXBwbGllZFR4cykge1xuICAgICAgICBvcHMucHVzaCguLi50eC5vcHMpXG4gICAgICB9XG4gICAgICByZXR1cm4gb3BzXG4gICAgfSlcblxuICAgIHJldHVybiB7IHN0YXRlLCBnZXRBcHBsaWVkT3BzIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBtYXggc2VlbiBjbG9jayAoZm9yIExhbXBvcnQgY2xvY2sgdXBkYXRlcykuXG4gICAqL1xuICBnZXRNYXhTZWVuQ2xvY2soKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5tYXhTZWVuQ2xvY2tcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBjdXJyZW50IGNhY2hlZCBzdGF0ZSB3aXRob3V0IHJlY2FsY3VsYXRpbmcuXG4gICAqIFJldHVybnMgbnVsbCBpZiBzdGF0ZSBoYXMgbmV2ZXIgYmVlbiBjYWxjdWxhdGVkLlxuICAgKi9cbiAgZ2V0Q2FjaGVkU3RhdGUoKTogSlNPTk9iamVjdCB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNhY2hlZFN0YXRlXG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgbGFzdCBhcHBsaWVkIHRpbWVzdGFtcC5cbiAgICovXG4gIGdldExhc3RBcHBsaWVkVHMoKTogVHhUaW1lc3RhbXAgfCBudWxsIHtcbiAgICBpZiAodGhpcy5sYXN0QXBwbGllZEluZGV4ID09PSBudWxsIHx8IHRoaXMubGFzdEFwcGxpZWRJbmRleCA8IDApIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICAgIHJldHVybiB0aGlzLnNvcnRlZFR4c1t0aGlzLmxhc3RBcHBsaWVkSW5kZXhdPy50eFRpbWVzdGFtcCA/PyBudWxsXG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgbGFzdCBhcHBsaWVkIGluZGV4IChmb3IgZGVidWdnaW5nL3RyYWNraW5nKS5cbiAgICovXG4gIGdldExhc3RBcHBsaWVkSW5kZXgoKTogbnVtYmVyIHwgbnVsbCB7XG4gICAgcmV0dXJuIHRoaXMubGFzdEFwcGxpZWRJbmRleFxuICB9XG59XG4iLCJpbXBvcnQgeyBKU09OT2JqZWN0IH0gZnJvbSBcIi4vanNvblwiXG5pbXBvcnQgeyBWYWxpZGF0ZUZuIH0gZnJvbSBcIi4vb3BlcmF0aW9uc1wiXG5pbXBvcnQgeyBTdGF0ZUNhbGN1bGF0b3IgfSBmcm9tIFwiLi9TdGF0ZUNhbGN1bGF0b3JcIlxuXG4vKipcbiAqIENsaWVudC1zaWRlIHN0YXRlIGluY2x1ZGluZyBjbG9ja3MgYW5kIGNhbGN1bGF0b3IgZm9yIHN0YXRlIG1hbmFnZW1lbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbGllbnRTdGF0ZSB7XG4gIC8vIExhbXBvcnQgY2xvY2tzIChtb25vdG9uaWMsIG5ldmVyIHJlc2V0KVxuICBsb2NhbENsb2NrOiBudW1iZXJcblxuICAvLyBDYWNoZWQgZmluYWxpemVkIGVwb2NoIChudWxsID0gbm90IHlldCBpbml0aWFsaXplZCwgcmVjYWxjdWxhdGVkIG9ubHkgd2hlbiBjaGVja3BvaW50IG1hcCBjaGFuZ2VzKVxuICBjYWNoZWRGaW5hbGl6ZWRFcG9jaDogbnVtYmVyIHwgbnVsbFxuXG4gIC8vIFN0YXRlIGNhbGN1bGF0b3IgKG1hbmFnZXMgc29ydGVkIHR4IGNhY2hlLCBzdGF0ZSBjYWxjdWxhdGlvbiwgYW5kIGludmFsaWRhdGlvbilcbiAgc3RhdGVDYWxjdWxhdG9yOiBTdGF0ZUNhbGN1bGF0b3JcblxuICAvKipcbiAgICogVGltZXN0YW1wIHJldGVudGlvbiB3aW5kb3cgaW4gbWlsbGlzZWNvbmRzLlxuICAgKi9cbiAgcmV0ZW50aW9uV2luZG93TXM6IG51bWJlclxufVxuXG4vKipcbiAqIEZhY3RvcnkgdG8gY3JlYXRlIGFuIGluaXRpYWwgQ2xpZW50U3RhdGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNsaWVudFN0YXRlKFxuICB2YWxpZGF0ZUZuOiBWYWxpZGF0ZUZuPEpTT05PYmplY3Q+IHwgdW5kZWZpbmVkLFxuICByZXRlbnRpb25XaW5kb3dNczogbnVtYmVyXG4pOiBDbGllbnRTdGF0ZSB7XG4gIHJldHVybiB7XG4gICAgbG9jYWxDbG9jazogMCxcbiAgICBjYWNoZWRGaW5hbGl6ZWRFcG9jaDogbnVsbCwgLy8gV2lsbCBiZSByZWNhbGN1bGF0ZWQgb24gZmlyc3QgcnVuXG4gICAgc3RhdGVDYWxjdWxhdG9yOiBuZXcgU3RhdGVDYWxjdWxhdG9yKHZhbGlkYXRlRm4pLFxuICAgIHJldGVudGlvbldpbmRvd01zLFxuICB9XG59XG4iLCJpbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgdHlwZSBDaGVja3BvaW50UmVjb3JkLCBwcnVuZUNoZWNrcG9pbnRzIH0gZnJvbSBcIi4vY2hlY2twb2ludHNcIlxuaW1wb3J0IHsgZ2V0RmluYWxpemVkRXBvY2hBbmRDaGVja3BvaW50IH0gZnJvbSBcIi4vY2hlY2twb2ludFV0aWxzXCJcbmltcG9ydCB7IENsaWVudFN0YXRlIH0gZnJvbSBcIi4vY2xpZW50U3RhdGVcIlxuaW1wb3J0IHsgSlNPTk9iamVjdCB9IGZyb20gXCIuL2pzb25cIlxuaW1wb3J0IHsgT3AgfSBmcm9tIFwiLi9vcGVyYXRpb25zXCJcbmltcG9ydCB7IFNvcnRlZFR4RW50cnkgfSBmcm9tIFwiLi9Tb3J0ZWRUeEVudHJ5XCJcbmltcG9ydCB7IGlzVHJhbnNhY3Rpb25JbkNoZWNrcG9pbnQgfSBmcm9tIFwiLi9TdGF0ZUNhbGN1bGF0b3JcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyB0eXBlIFR4VGltZXN0YW1wLCB0eXBlIFR4VGltZXN0YW1wS2V5LCB0eFRpbWVzdGFtcFRvS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuXG4vKipcbiAqIENoYW5nZXMgdG8gdHJhbnNhY3Rpb24ga2V5cyBmcm9tIGEgWS5ZTWFwRXZlbnQuXG4gKiAtIGFkZGVkOiBrZXlzIHRoYXQgd2VyZSBhZGRlZFxuICogLSBkZWxldGVkOiBrZXlzIHRoYXQgd2VyZSBkZWxldGVkXG4gKi9cbmV4cG9ydCB0eXBlIFR4S2V5Q2hhbmdlcyA9IHtcbiAgYWRkZWQ6IHJlYWRvbmx5IFR4VGltZXN0YW1wS2V5W11cbiAgZGVsZXRlZDogcmVhZG9ubHkgVHhUaW1lc3RhbXBLZXlbXVxufVxuXG4vKipcbiAqIEFwcGVuZHMgYSBuZXcgdHJhbnNhY3Rpb24gdG8gdGhlIGxvZy5cbiAqXG4gKiBAcGFyYW0gb3JpZ2luYWxLZXkgLSBPcHRpb25hbCByZWZlcmVuY2UgdG8gdGhlIG9yaWdpbmFsIHRyYW5zYWN0aW9uIGtleSBmb3IgcmUtZW1pdHMuXG4gKiAgICAgICAgICAgICAgICAgICAgICBVc2VkIGJ5IHN5bmNMb2cgdG8gcHJlc2VydmUgdHJhbnNhY3Rpb25zIG1pc3NlZCBieSBjaGVja3BvaW50cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFwcGVuZFR4KFxuICBvcHM6IHJlYWRvbmx5IE9wW10sXG4gIHlUeDogWS5NYXA8VHhSZWNvcmQ+LFxuICBhY3RpdmVFcG9jaDogbnVtYmVyLFxuICBteUNsaWVudElkOiBzdHJpbmcsXG4gIGNsaWVudFN0YXRlOiBDbGllbnRTdGF0ZSxcbiAgb3JpZ2luYWxLZXk/OiBUeFRpbWVzdGFtcEtleVxuKTogVHhUaW1lc3RhbXBLZXkge1xuICBjb25zdCBjYWxjID0gY2xpZW50U3RhdGUuc3RhdGVDYWxjdWxhdG9yXG5cbiAgLy8gMS4gQWR2YW5jZSBsb2dpY2FsIGNsb2NrIChMYW1wb3J0KSBiYXNlZCBvbiBhbGwgc2VlbiB0cmFmZmljXG4gIGNvbnN0IGNsb2NrID0gTWF0aC5tYXgoY2xpZW50U3RhdGUubG9jYWxDbG9jaywgY2FsYy5nZXRNYXhTZWVuQ2xvY2soKSkgKyAxXG4gIGNsaWVudFN0YXRlLmxvY2FsQ2xvY2sgPSBjbG9ja1xuXG4gIC8vIDIuIEdlbmVyYXRlIEtleSB3aXRoIFdhbGxDbG9jayBmb3IgZnV0dXJlIHBydW5pbmcgc2FmZXR5XG4gIGNvbnN0IHRzOiBUeFRpbWVzdGFtcCA9IHtcbiAgICBlcG9jaDogYWN0aXZlRXBvY2gsXG4gICAgY2xvY2ssXG4gICAgY2xpZW50SWQ6IG15Q2xpZW50SWQsXG4gICAgd2FsbENsb2NrOiBEYXRlLm5vdygpLFxuICB9XG4gIGNvbnN0IGtleSA9IHR4VGltZXN0YW1wVG9LZXkodHMpXG5cbiAgLy8gMy4gV3JpdGUgdG8gWWpzIChBdG9taWMpXG4gIGNvbnN0IHJlY29yZDogVHhSZWNvcmQgPSB7IG9wcywgb3JpZ2luYWxUeEtleTogb3JpZ2luYWxLZXkgfVxuICB5VHguc2V0KGtleSwgcmVjb3JkKVxuXG4gIHJldHVybiBrZXlcbn1cblxuLyoqXG4gKiBTeW5jaHJvbml6ZXMgdGhlIHRyYW5zYWN0aW9uIGxvZyB3aXRoIHRoZSBjdXJyZW50IGNoZWNrcG9pbnQuXG4gKiBSZS1lbWl0cyBtaXNzZWQgdHJhbnNhY3Rpb25zIGFuZCBwcnVuZXMgb2xkIG9uZXMuXG4gKlxuICogU2hvdWxkIGJlIGNhbGxlZCBCRUZPUkUgdXBkYXRlU3RhdGUgdG8gZW5zdXJlIGxvZyBpcyBjbGVhbiBhbmQgY29tcGxldGUuXG4gKlxuICogQHJldHVybnMgdHJ1ZSBpZiBhbnkgdHJhbnNhY3Rpb25zIHdlcmUgcmUtZW1pdHRlZCBvciBkZWxldGVkLCB3aGljaCBtYXkgaW52YWxpZGF0ZSBsYXN0QXBwbGllZEluZGV4XG4gKi9cbmZ1bmN0aW9uIHN5bmNMb2coXG4gIHlUeDogWS5NYXA8VHhSZWNvcmQ+LFxuICBteUNsaWVudElkOiBzdHJpbmcsXG4gIGNsaWVudFN0YXRlOiBDbGllbnRTdGF0ZSxcbiAgZmluYWxpemVkRXBvY2g6IG51bWJlcixcbiAgYmFzZUNQOiBDaGVja3BvaW50UmVjb3JkIHwgbnVsbCxcbiAgbmV3S2V5cz86IHJlYWRvbmx5IFR4VGltZXN0YW1wS2V5W10gLy8ga2V5cyBhZGRlZCBpbiB0aGlzIHVwZGF0ZVxuKTogdm9pZCB7XG4gIGNvbnN0IGNhbGMgPSBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3JcbiAgY29uc3QgYWN0aXZlRXBvY2ggPSBmaW5hbGl6ZWRFcG9jaCArIDFcbiAgY29uc3Qgd2F0ZXJtYXJrcyA9IGJhc2VDUD8ud2F0ZXJtYXJrcyA/PyB7fVxuXG4gIC8vIERldGVybWluaXN0aWMgUmVmZXJlbmNlIFRpbWU6IFVzZSBzdG9yZWQgbWluV2FsbENsb2NrIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIDAgKG5vdGhpbmcgYW5jaWVudCkuXG4gIGNvbnN0IHJlZmVyZW5jZVRpbWUgPSBiYXNlQ1A/Lm1pbldhbGxDbG9jayA/PyAwXG5cbiAgLy8gSGVscGVyIHRvIGNoZWNrIGlmIGEgdHJhbnNhY3Rpb24gc2hvdWxkIGJlIHBydW5lZFxuICBjb25zdCBzaG91bGRQcnVuZSA9ICh0czogVHhUaW1lc3RhbXAsIGRlZHVwVHM6IFR4VGltZXN0YW1wKTogYm9vbGVhbiA9PiB7XG4gICAgY29uc3QgaXNBbmNpZW50ID0gcmVmZXJlbmNlVGltZSAtIHRzLndhbGxDbG9jayA+IGNsaWVudFN0YXRlLnJldGVudGlvbldpbmRvd01zXG4gICAgaWYgKGlzQW5jaWVudCkgcmV0dXJuIHRydWVcbiAgICByZXR1cm4gaXNUcmFuc2FjdGlvbkluQ2hlY2twb2ludChkZWR1cFRzLCB3YXRlcm1hcmtzKVxuICB9XG5cbiAgY29uc3QgdG9EZWxldGU6IFR4VGltZXN0YW1wS2V5W10gPSBbXVxuICBjb25zdCB0b1JlRW1pdDogQXJyYXk8eyBvcmlnaW5hbEtleTogVHhUaW1lc3RhbXBLZXk7IHR4OiBUeFJlY29yZCB9PiA9IFtdXG5cbiAgLy8gMS4gSGVscGVyIHRvIGRlY2lkZSB3aGF0IHRvIGRvIHdpdGggZWFjaCB0cmFuc2FjdGlvblxuICBjb25zdCBwcm9jZXNzRW50cnkgPSAoZW50cnk6IFNvcnRlZFR4RW50cnkpOiBib29sZWFuID0+IHtcbiAgICBpZiAoc2hvdWxkUHJ1bmUoZW50cnkudHhUaW1lc3RhbXAsIGVudHJ5LmRlZHVwVHhUaW1lc3RhbXApKSB7XG4gICAgICB0b0RlbGV0ZS5wdXNoKGVudHJ5LnR4VGltZXN0YW1wS2V5KVxuICAgICAgcmV0dXJuIGZhbHNlIC8vIGRlbGV0ZWRcbiAgICB9XG5cbiAgICBpZiAoZW50cnkudHhUaW1lc3RhbXAuZXBvY2ggPD0gZmluYWxpemVkRXBvY2gpIHtcbiAgICAgIC8vIE5vdCBpbiBjaGVja3BvaW50IGFuZCBzdGlsbCBmcmVzaCAtIHJlLWVtaXQgaXQgdG8gdGhlIGFjdGl2ZSBlcG9jaFxuICAgICAgdG9SZUVtaXQucHVzaCh7IG9yaWdpbmFsS2V5OiBlbnRyeS5kZWR1cFR4VGltZXN0YW1wS2V5LCB0eDogZW50cnkudHhSZWNvcmQgfSlcbiAgICAgIHRvRGVsZXRlLnB1c2goZW50cnkudHhUaW1lc3RhbXBLZXkpXG4gICAgICByZXR1cm4gZmFsc2UgLy8gcmUtZW1pdHRlZFxuICAgIH1cblxuICAgIHJldHVybiB0cnVlIC8vIGFjdGl2ZS9mcmVzaFxuICB9XG5cbiAgLy8gMi4gU2NhbiBsb2NhbCBjYWNoZSAoc29ydGVkVHhzKSB0byBpZGVudGlmeSBtaXNzaW5nL2FuY2llbnQgdHJhbnNhY3Rpb25zXG4gIGZvciAoY29uc3QgZW50cnkgb2YgY2FsYy5nZXRTb3J0ZWRUeHMoKSkge1xuICAgIGlmIChwcm9jZXNzRW50cnkoZW50cnkpKSB7XG4gICAgICAvLyBPcHRpbWl6YXRpb246IFBoeXNpY2FsIGtleXMgYXJlIHNvcnRlZC4gSWYgd2UgaGl0IHRoZSBhY3RpdmUvZnJlc2ggdGVycml0b3J5LCB3ZSBjYW4gc3RvcC5cbiAgICAgIGJyZWFrXG4gICAgfVxuICB9XG5cbiAgY29uc3QgcHJvY2Vzc0tleUJ5VGltZXN0YW1wS2V5ID0gKHR4VGltZXN0YW1wS2V5OiBUeFRpbWVzdGFtcEtleSk6IHZvaWQgPT4ge1xuICAgIC8vIE9ubHkgcHJvY2VzcyBpZiBpdCBhY3R1YWxseSBleGlzdHMgaW4gWWpzIE1hcFxuICAgIGlmICh5VHguaGFzKHR4VGltZXN0YW1wS2V5KSkge1xuICAgICAgcHJvY2Vzc0VudHJ5KG5ldyBTb3J0ZWRUeEVudHJ5KHR4VGltZXN0YW1wS2V5LCB5VHgpKVxuICAgIH1cbiAgfVxuXG4gIC8vIDMuIFNjYW4gTkVXIGtleXMgZnJvbSBZanMgdG8gaGFuZGxlIGluY29taW5nIHRyYW5zYWN0aW9ucyAoc3luYylcbiAgLy8gQW55IGNsaWVudCBjYW4gcmUtZW1pdCAtIGRlZHVwbGljYXRpb24gdmlhIG9yaWdpbmFsVHhLZXkgaGFuZGxlcyBkdXBsaWNhdGVzLlxuICBpZiAobmV3S2V5cykge1xuICAgIGZvciAoY29uc3Qga2V5IG9mIG5ld0tleXMpIHtcbiAgICAgIHByb2Nlc3NLZXlCeVRpbWVzdGFtcEtleShrZXkpXG4gICAgfVxuICB9XG5cbiAgLy8gNC4gUmUtZW1pdCBtaXNzZWQgdHJhbnNhY3Rpb25zIEJFRk9SRSBwcnVuaW5nXG4gIGZvciAoY29uc3QgeyBvcmlnaW5hbEtleSwgdHggfSBvZiB0b1JlRW1pdCkge1xuICAgIGNvbnN0IG5ld0tleSA9IGFwcGVuZFR4KHR4Lm9wcywgeVR4LCBhY3RpdmVFcG9jaCwgbXlDbGllbnRJZCwgY2xpZW50U3RhdGUsIG9yaWdpbmFsS2V5KVxuICAgIGNhbGMuaW5zZXJ0VHgobmV3S2V5LCB5VHgpXG4gIH1cblxuICAvLyA1LiBQcnVuZSBvbGQvZmluYWxpemVkL3JlZHVuZGFudCB0cmFuc2FjdGlvbnMgZnJvbSBZanMgTWFwXG4gIGZvciAoY29uc3Qga2V5IG9mIHRvRGVsZXRlKSB7XG4gICAgeVR4LmRlbGV0ZShrZXkpXG4gIH1cbiAgY2FsYy5yZW1vdmVUeHModG9EZWxldGUpXG59XG5cbi8qKlxuICogVGhlIHByaW1hcnkgdXBkYXRlIGZ1bmN0aW9uIHRoYXQgbWFpbnRhaW5zIGN1cnJlbnQgc3RhdGUuXG4gKlxuICogQHBhcmFtIHR4Q2hhbmdlcyAtIENoYW5nZXMgZnJvbSBZLllNYXBFdmVudC4gSWYgdW5kZWZpbmVkIChmaXJzdCBydW4pLCBwZXJmb3JtcyBhIGZ1bGwgc2Nhbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVwZGF0ZVN0YXRlKFxuICBkb2M6IFkuRG9jLFxuICB5VHg6IFkuTWFwPFR4UmVjb3JkPixcbiAgeUNoZWNrcG9pbnQ6IFkuTWFwPENoZWNrcG9pbnRSZWNvcmQ+LFxuICBteUNsaWVudElkOiBzdHJpbmcsXG4gIGNsaWVudFN0YXRlOiBDbGllbnRTdGF0ZSxcbiAgdHhDaGFuZ2VzOiBUeEtleUNoYW5nZXMgfCB1bmRlZmluZWRcbik6IHsgc3RhdGU6IEpTT05PYmplY3Q7IGdldEFwcGxpZWRPcHM6ICgpID0+IHJlYWRvbmx5IE9wW10gfSB7XG4gIGNvbnN0IGNhbGMgPSBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3JcblxuICAvLyBBbHdheXMgY2FsY3VsYXRlIGZyZXNoIGZpbmFsaXplZCBlcG9jaCBhbmQgY2hlY2twb2ludCB0byBoYW5kbGUgc3luYyByYWNlIGNvbmRpdGlvbnNcbiAgY29uc3QgeyBmaW5hbGl6ZWRFcG9jaCwgY2hlY2twb2ludDogYmFzZUNQIH0gPSBnZXRGaW5hbGl6ZWRFcG9jaEFuZENoZWNrcG9pbnQoeUNoZWNrcG9pbnQpXG5cbiAgLy8gVXBkYXRlIHJlYWQtY2FjaGVcbiAgY2xpZW50U3RhdGUuY2FjaGVkRmluYWxpemVkRXBvY2ggPSBmaW5hbGl6ZWRFcG9jaFxuXG4gIC8vIFNldCBiYXNlIGNoZWNrcG9pbnQgKHRoaXMgaGFuZGxlcyBpbnZhbGlkYXRpb24gaWYgY2hlY2twb2ludCBjaGFuZ2VkKVxuICBjYWxjLnNldEJhc2VDaGVja3BvaW50KGJhc2VDUClcblxuICAvLyBUcmFjayBpZiB3ZSBuZWVkIHRvIHJlYnVpbGQgc29ydGVkIGNhY2hlIChmaXJzdCBydW4gb3IgbWlzc2luZyBkZWx0YSlcbiAgLy8gT3B0aW1pemF0aW9uOiBXZSBkb24ndCBuZWVkIHRvIHJlYnVpbGQganVzdCBiZWNhdXNlIGNoZWNrcG9pbnQgY2hhbmdlZCxcbiAgLy8gYXMgbG9uZyBhcyB3ZSBoYXZlIHR4Q2hhbmdlcyB0byBrZWVwIGNhY2hlIGluIHN5bmMuXG4gIGNvbnN0IG5lZWRzUmVidWlsZFNvcnRlZENhY2hlID0gY2FsYy5nZXRDYWNoZWRTdGF0ZSgpID09PSBudWxsIHx8ICF0eENoYW5nZXNcblxuICAvLyBSZWJ1aWxkIHNvcnRlZCBjYWNoZSBiZWZvcmUgc3luY0xvZyBpZiBuZWVkZWRcbiAgaWYgKG5lZWRzUmVidWlsZFNvcnRlZENhY2hlKSB7XG4gICAgY2FsYy5yZWJ1aWxkRnJvbVlqcyh5VHgpXG4gIH0gZWxzZSB7XG4gICAgLy8gSWYgbm90IHJlYnVpbGRpbmcsIGltbWVkaWF0ZWx5IHByb2Nlc3MgZGVsZXRpb25zIHRvIGF2b2lkIFwiZ2hvc3RcIiB0cmFuc2FjdGlvbnNcbiAgICAvLyBpbiBzeW5jTG9nIChlLmcuIGF0dGVtcHRpbmcgdG8gYWNjZXNzIGEgdHJhbnNhY3Rpb24gdGhhdCB3YXMganVzdCBkZWxldGVkKS5cbiAgICBjYWxjLnJlbW92ZVR4cyh0eENoYW5nZXMuZGVsZXRlZClcbiAgfVxuXG4gIC8vIFN5bmMgYW5kIHBydW5lIHdpdGhpbiB0cmFuc2FjdGlvblxuICBkb2MudHJhbnNhY3QoKCkgPT4ge1xuICAgIHN5bmNMb2coeVR4LCBteUNsaWVudElkLCBjbGllbnRTdGF0ZSwgZmluYWxpemVkRXBvY2gsIGJhc2VDUCwgdHhDaGFuZ2VzPy5hZGRlZClcblxuICAgIC8vIFNhZmUgdG8gdXNlIGxvY2FsIGZpbmFsaXplZEVwb2NoIGhlcmVcbiAgICBwcnVuZUNoZWNrcG9pbnRzKHlDaGVja3BvaW50LCBmaW5hbGl6ZWRFcG9jaClcbiAgfSlcblxuICBpZiAobmVlZHNSZWJ1aWxkU29ydGVkQ2FjaGUpIHtcbiAgICAvLyBGdWxsIHJlY29tcHV0ZSAoY2FsY3VsYXRvciBoYW5kbGVzIHRoaXMpXG4gICAgcmV0dXJuIGNhbGMuY2FsY3VsYXRlU3RhdGUoKVxuICB9XG5cbiAgLy8gSW5jcmVtZW50YWwgdXBkYXRlIHVzaW5nIG9ubHkgY2hhbmdlZCBrZXlzIChjYWxjdWxhdG9yIGhhbmRsZXMgdGhpcylcbiAgLy8gdHhDaGFuZ2VzIGlzIGd1YXJhbnRlZWQgdG8gZXhpc3QgaGVyZSBzaW5jZSAhdHhDaGFuZ2VzIGltcGxpZXMgbmVlZHNSZWJ1aWxkU29ydGVkQ2FjaGVcblxuICAvLyBVcGRhdGUgc29ydGVkIGNhY2hlIHdpdGggbmV3IGtleXMgZnJvbSB0eENoYW5nZXNcbiAgLy8gVGhpcyBtdXN0IGhhcHBlbiBhZnRlciBzeW5jTG9nIHdoaWNoIG1heSBoYXZlIGRlbGV0ZWQgc29tZSBvZiB0aGVzZSBrZXlzXG4gIGZvciAoY29uc3Qga2V5IG9mIHR4Q2hhbmdlcy5hZGRlZCkge1xuICAgIC8vIENSSVRJQ0FMOiBDaGVjayB5VHguaGFzKGtleSkhIHN5bmNMb2cgbWlnaHQgaGF2ZSBqdXN0IHBydW5lZCBpdC5cbiAgICBpZiAoeVR4LmhhcyhrZXkpICYmICFjYWxjLmhhc1R4KGtleSkpIHtcbiAgICAgIGNhbGMuaW5zZXJ0VHgoa2V5LCB5VHgpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGNhbGMuY2FsY3VsYXRlU3RhdGUoKVxufVxuIiwiaW1wb3J0ICogYXMgWSBmcm9tIFwieWpzXCJcbmltcG9ydCB7IENoZWNrcG9pbnRSZWNvcmQsIGNyZWF0ZUNoZWNrcG9pbnQgfSBmcm9tIFwiLi9jaGVja3BvaW50c1wiXG5pbXBvcnQgeyBjcmVhdGVDbGllbnRTdGF0ZSB9IGZyb20gXCIuL2NsaWVudFN0YXRlXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi9lcnJvclwiXG5pbXBvcnQgeyBKU09OT2JqZWN0IH0gZnJvbSBcIi4vanNvblwiXG5cbmltcG9ydCB7IE9wLCBWYWxpZGF0ZUZuIH0gZnJvbSBcIi4vb3BlcmF0aW9uc1wiXG5cbmltcG9ydCB7IGNvbXB1dGVSZWNvbmNpbGVPcHMgfSBmcm9tIFwiLi9yZWNvbmNpbGVcIlxuaW1wb3J0IHsgU29ydGVkVHhFbnRyeSB9IGZyb20gXCIuL1NvcnRlZFR4RW50cnlcIlxuaW1wb3J0IHsgVHhSZWNvcmQgfSBmcm9tIFwiLi9UeFJlY29yZFwiXG5pbXBvcnQgeyBhcHBlbmRUeCwgVHhLZXlDaGFuZ2VzLCB1cGRhdGVTdGF0ZSB9IGZyb20gXCIuL3R4TG9nXCJcbmltcG9ydCB7IFR4VGltZXN0YW1wS2V5IH0gZnJvbSBcIi4vdHhUaW1lc3RhbXBcIlxuaW1wb3J0IHsgZ2VuZXJhdGVJRCB9IGZyb20gXCIuL3V0aWxzXCJcblxuZXhwb3J0IGNvbnN0IGdldFNvcnRlZFR4c1N5bWJvbCA9IFN5bWJvbChcImdldFNvcnRlZFR4c1wiKVxuXG5leHBvcnQgaW50ZXJmYWNlIFN0YXRlU3luY0xvZ09wdGlvbnM8U3RhdGUgZXh0ZW5kcyBKU09OT2JqZWN0PiB7XG4gIC8qKlxuICAgKiBUaGUgWS5qcyBEb2N1bWVudCB0byBiaW5kIHRvLlxuICAgKi9cbiAgeURvYzogWS5Eb2NcblxuICAvKipcbiAgICogTmFtZSBmb3IgdGhlIHR4cyBZLk1hcC5cbiAgICogRGVmYXVsdDogXCJzdGF0ZS1zeW5jLWxvZy10eFwiXG4gICAqL1xuICB5VHhNYXBOYW1lPzogc3RyaW5nXG5cbiAgLyoqXG4gICAqIE5hbWUgZm9yIHRoZSBjaGVja3BvaW50IFkuTWFwLlxuICAgKiBEZWZhdWx0OiBcInN0YXRlLXN5bmMtbG9nLWNoZWNrcG9pbnRcIlxuICAgKi9cbiAgeUNoZWNrcG9pbnRNYXBOYW1lPzogc3RyaW5nXG5cbiAgLyoqXG4gICAqIFVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGlzIGNsaWVudC5cbiAgICogSWYgb21pdHRlZCwgYSByYW5kb20gVVVJRCAobmFub2lkKSB3aWxsIGJlIGdlbmVyYXRlZC5cbiAgICogTk9URTogSWYgeW91IG5lZWQgdG8gcmVzdW1lIGEgc2Vzc2lvbiAoa2VlcCBsb2NhbCBjbG9jay93YXRlcm1hcmspLCB5b3UgTVVTVCBwcm92aWRlIGEgc3RhYmxlIElELlxuICAgKiBNVVNUIE5PVCBjb250YWluIHNlbWljb2xvbnMuXG4gICAqL1xuICBjbGllbnRJZD86IHN0cmluZ1xuXG4gIC8qKlxuICAgKiBPcmlnaW4gdGFnIGZvciBZLmpzIHR4cyBjcmVhdGVkIGJ5IHRoaXMgbGlicmFyeS5cbiAgICovXG4gIHlqc09yaWdpbj86IHVua25vd25cblxuICAvKipcbiAgICogT3B0aW9uYWwgdmFsaWRhdGlvbiBmdW5jdGlvbi5cbiAgICogUnVucyBhZnRlciBlYWNoIHR4J3Mgb3BzIGFyZSBhcHBsaWVkLlxuICAgKiBJZiBpdCByZXR1cm5zIGZhbHNlLCB0aGUgdHggaXMgcmVqZWN0ZWQgKHN0YXRlIHJldmVydHMpLlxuICAgKiBNVVNUIGJlIGRldGVybWluaXN0aWMgYW5kIGNvbnNpc3RlbnQgYWNyb3NzIGFsbCBjbGllbnRzLlxuICAgKi9cbiAgdmFsaWRhdGU/OiAoc3RhdGU6IFN0YXRlKSA9PiBib29sZWFuXG5cbiAgLyoqXG4gICAqIFRpbWVzdGFtcCByZXRlbnRpb24gd2luZG93IGluIG1pbGxpc2Vjb25kcy5cbiAgICogVHhzIG9sZGVyIHRoYW4gdGhpcyB3aW5kb3cgYXJlIGNvbnNpZGVyZWQgXCJBbmNpZW50XCIgYW5kIHBydW5lZC5cbiAgICpcbiAgICogRGVmYXVsdDogSW5maW5pdHkgKE5vIHBydW5pbmcpLlxuICAgKiBSZWNvbW1lbmRlZDogMTQgZGF5cyAoMTIwOTYwMDAwMCBtcykuXG4gICAqL1xuICByZXRlbnRpb25XaW5kb3dNczogbnVtYmVyIHwgdW5kZWZpbmVkXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RhdGVTeW5jTG9nQ29udHJvbGxlcjxTdGF0ZSBleHRlbmRzIEpTT05PYmplY3Q+IHtcbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgc3RhdGUuXG4gICAqL1xuICBnZXRTdGF0ZSgpOiBTdGF0ZVxuXG4gIC8qKlxuICAgKiBTdWJzY3JpYmVzIHRvIHN0YXRlIGNoYW5nZXMuXG4gICAqL1xuICBzdWJzY3JpYmUoY2FsbGJhY2s6IChuZXdTdGF0ZTogU3RhdGUsIGdldEFwcGxpZWRPcHM6ICgpID0+IHJlYWRvbmx5IE9wW10pID0+IHZvaWQpOiAoKSA9PiB2b2lkXG5cbiAgLyoqXG4gICAqIEVtaXRzIGEgbmV3IHR4IChsaXN0IG9mIG9wZXJhdGlvbnMpIHRvIHRoZSBsb2cuXG4gICAqL1xuICBlbWl0KG9wczogT3BbXSk6IHZvaWRcblxuICAvKipcbiAgICogUmVjb25jaWxlcyB0aGUgY3VycmVudCBzdGF0ZSB3aXRoIHRoZSB0YXJnZXQgc3RhdGUuXG4gICAqL1xuICByZWNvbmNpbGVTdGF0ZSh0YXJnZXRTdGF0ZTogU3RhdGUpOiB2b2lkXG5cbiAgLyoqXG4gICAqIE1hbnVhbGx5IHRyaWdnZXJzIGVwb2NoIGNvbXBhY3Rpb24gKENoZWNrcG9pbnRpbmcpLlxuICAgKi9cbiAgY29tcGFjdCgpOiB2b2lkXG5cbiAgLyoqXG4gICAqIENsZWFucyB1cCBvYnNlcnZlcnMgYW5kIHJlbGVhc2VzIG1lbW9yeS5cbiAgICovXG4gIGRpc3Bvc2UoKTogdm9pZFxuXG4gIC8vIC0tLSBPYnNlcnZhYmlsaXR5ICYgU3RhdHMgLS0tXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgYWN0aXZlIGVwb2NoIG51bWJlci5cbiAgICovXG4gIGdldEFjdGl2ZUVwb2NoKCk6IG51bWJlclxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgdHhzIGN1cnJlbnRseSBpbiB0aGUgYWN0aXZlIGVwb2NoLlxuICAgKi9cbiAgZ2V0QWN0aXZlRXBvY2hUeENvdW50KCk6IG51bWJlclxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSB3YWxsQ2xvY2sgdGltZXN0YW1wIG9mIHRoZSBmaXJzdCB0eCBpbiB0aGUgYWN0aXZlIGVwb2NoLlxuICAgKi9cbiAgZ2V0QWN0aXZlRXBvY2hTdGFydFRpbWUoKTogbnVtYmVyIHwgdW5kZWZpbmVkXG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgbG9nIGlzIGNvbXBsZXRlbHkgZW1wdHkuXG4gICAqL1xuICBpc0xvZ0VtcHR5KCk6IGJvb2xlYW5cblxuICAvKipcbiAgICogSW50ZXJuYWwvVGVzdGluZzogUmV0dXJucyBhbGwgdHhzIGN1cnJlbnRseSBpbiB0aGUgbG9nLCBzb3J0ZWQuXG4gICAqL1xuICBbZ2V0U29ydGVkVHhzU3ltYm9sXSgpOiByZWFkb25seSBTb3J0ZWRUeEVudHJ5W11cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgU3RhdGVTeW5jTG9nIGNvbnRyb2xsZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVTdGF0ZVN5bmNMb2c8U3RhdGUgZXh0ZW5kcyBKU09OT2JqZWN0PihcbiAgb3B0aW9uczogU3RhdGVTeW5jTG9nT3B0aW9uczxTdGF0ZT5cbik6IFN0YXRlU3luY0xvZ0NvbnRyb2xsZXI8U3RhdGU+IHtcbiAgY29uc3Qge1xuICAgIHlEb2MsXG4gICAgeVR4TWFwTmFtZSA9IFwic3RhdGUtc3luYy1sb2ctdHhcIixcbiAgICB5Q2hlY2twb2ludE1hcE5hbWUgPSBcInN0YXRlLXN5bmMtbG9nLWNoZWNrcG9pbnRcIixcbiAgICBjbGllbnRJZCA9IGdlbmVyYXRlSUQoKSxcbiAgICB5anNPcmlnaW4sXG4gICAgdmFsaWRhdGUsXG4gICAgcmV0ZW50aW9uV2luZG93TXMsXG4gIH0gPSBvcHRpb25zXG5cbiAgaWYgKGNsaWVudElkLmluY2x1ZGVzKFwiO1wiKSkge1xuICAgIGZhaWx1cmUoYGNsaWVudElkIE1VU1QgTk9UIGNvbnRhaW4gc2VtaWNvbG9uczogJHtjbGllbnRJZH1gKVxuICB9XG5cbiAgY29uc3QgeVR4ID0geURvYy5nZXRNYXA8VHhSZWNvcmQ+KHlUeE1hcE5hbWUpXG4gIGNvbnN0IHlDaGVja3BvaW50ID0geURvYy5nZXRNYXA8Q2hlY2twb2ludFJlY29yZD4oeUNoZWNrcG9pbnRNYXBOYW1lKVxuXG4gIC8vIENhc3QgdmFsaWRhdGUgdG8gYmFzaWMgdHlwZSB0byBtYXRjaCBpbnRlcm5hbCBDbGllbnRTdGF0ZVxuICBjb25zdCBjbGllbnRTdGF0ZSA9IGNyZWF0ZUNsaWVudFN0YXRlKFxuICAgIHZhbGlkYXRlIGFzIHVua25vd24gYXMgVmFsaWRhdGVGbjxKU09OT2JqZWN0PixcbiAgICByZXRlbnRpb25XaW5kb3dNcyA/PyBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFlcbiAgKVxuXG4gIC8vIExpc3RlbmVyc1xuICBjb25zdCBzdWJzY3JpYmVycyA9IG5ldyBTZXQ8KHN0YXRlOiBTdGF0ZSwgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSkgPT4gdm9pZD4oKVxuXG4gIGNvbnN0IG5vdGlmeVN1YnNjcmliZXJzID0gKHN0YXRlOiBTdGF0ZSwgZ2V0QXBwbGllZE9wczogKCkgPT4gcmVhZG9ubHkgT3BbXSkgPT4ge1xuICAgIGZvciAoY29uc3Qgc3ViIG9mIHN1YnNjcmliZXJzKSB7XG4gICAgICBzdWIoc3RhdGUsIGdldEFwcGxpZWRPcHMpXG4gICAgfVxuICB9XG5cbiAgLy8gSGVscGVyIHRvIGV4dHJhY3Qga2V5IGNoYW5nZXMgZnJvbSBZTWFwRXZlbnRcbiAgY29uc3QgZXh0cmFjdFR4Q2hhbmdlcyA9IChldmVudDogWS5ZTWFwRXZlbnQ8VHhSZWNvcmQ+KTogVHhLZXlDaGFuZ2VzID0+IHtcbiAgICBjb25zdCBhZGRlZDogVHhUaW1lc3RhbXBLZXlbXSA9IFtdXG4gICAgY29uc3QgZGVsZXRlZDogVHhUaW1lc3RhbXBLZXlbXSA9IFtdXG5cbiAgICBmb3IgKGNvbnN0IFtrZXksIGNoYW5nZV0gb2YgZXZlbnQuY2hhbmdlcy5rZXlzKSB7XG4gICAgICBpZiAoY2hhbmdlLmFjdGlvbiA9PT0gXCJhZGRcIikge1xuICAgICAgICBhZGRlZC5wdXNoKGtleSlcbiAgICAgIH0gZWxzZSBpZiAoY2hhbmdlLmFjdGlvbiA9PT0gXCJkZWxldGVcIikge1xuICAgICAgICBkZWxldGVkLnB1c2goa2V5KVxuICAgICAgfSBlbHNlIGlmIChjaGFuZ2UuYWN0aW9uID09PSBcInVwZGF0ZVwiKSB7XG4gICAgICAgIGRlbGV0ZWQucHVzaChrZXkpXG4gICAgICAgIGFkZGVkLnB1c2goa2V5KVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IGFkZGVkLCBkZWxldGVkIH1cbiAgfVxuXG4gIC8vIEVtcHR5IHR4Q2hhbmdlcyBvYmplY3QgZm9yIGNoZWNrcG9pbnQgb2JzZXJ2ZXIgKG5vIHR4IGtleXMgY2hhbmdlZClcbiAgY29uc3QgZW1wdHlUeENoYW5nZXM6IFR4S2V5Q2hhbmdlcyA9IHsgYWRkZWQ6IFtdLCBkZWxldGVkOiBbXSB9XG5cbiAgLy8gVXBkYXRlIExvZ2ljIHdpdGggaW5jcmVtZW50YWwgY2hhbmdlc1xuICBjb25zdCBydW5VcGRhdGUgPSAodHhDaGFuZ2VzOiBUeEtleUNoYW5nZXMgfCB1bmRlZmluZWQpID0+IHtcbiAgICBjb25zdCB7IHN0YXRlLCBnZXRBcHBsaWVkT3BzIH0gPSB1cGRhdGVTdGF0ZShcbiAgICAgIHlEb2MsXG4gICAgICB5VHgsXG4gICAgICB5Q2hlY2twb2ludCxcbiAgICAgIGNsaWVudElkLFxuICAgICAgY2xpZW50U3RhdGUsXG4gICAgICB0eENoYW5nZXNcbiAgICApXG4gICAgbm90aWZ5U3Vic2NyaWJlcnMoc3RhdGUgYXMgU3RhdGUsIGdldEFwcGxpZWRPcHMpXG4gIH1cblxuICAvLyBUeCBvYnNlcnZlclxuICBjb25zdCB0eE9ic2VydmVyID0gKGV2ZW50OiBZLllNYXBFdmVudDxUeFJlY29yZD4sIF90cmFuc2FjdGlvbjogWS5UcmFuc2FjdGlvbikgPT4ge1xuICAgIGNvbnN0IHR4Q2hhbmdlcyA9IGV4dHJhY3RUeENoYW5nZXMoZXZlbnQpXG4gICAgcnVuVXBkYXRlKHR4Q2hhbmdlcylcbiAgfVxuXG4gIC8vIENoZWNrcG9pbnQgb2JzZXJ2ZXJcbiAgY29uc3QgY2hlY2twb2ludE9ic2VydmVyID0gKFxuICAgIF9ldmVudDogWS5ZTWFwRXZlbnQ8Q2hlY2twb2ludFJlY29yZD4sXG4gICAgX3RyYW5zYWN0aW9uOiBZLlRyYW5zYWN0aW9uXG4gICkgPT4ge1xuICAgIHJ1blVwZGF0ZShlbXB0eVR4Q2hhbmdlcylcbiAgfVxuXG4gIHlDaGVja3BvaW50Lm9ic2VydmUoY2hlY2twb2ludE9ic2VydmVyKVxuICB5VHgub2JzZXJ2ZSh0eE9ic2VydmVyKVxuXG4gIC8vIEluaXRpYWwgcnVuIChmdWxsIHJlY29tcHV0ZSwgdHJlYXQgYXMgY2hlY2twb2ludCBjaGFuZ2UgdG8gaW5pdGlhbGl6ZSBlcG9jaCBjYWNoZSlcbiAgcnVuVXBkYXRlKHVuZGVmaW5lZClcblxuICAvLyBUcmFjayBkaXNwb3NhbCBzdGF0ZVxuICBsZXQgZGlzcG9zZWQgPSBmYWxzZVxuXG4gIGNvbnN0IGFzc2VydE5vdERpc3Bvc2VkID0gKCkgPT4ge1xuICAgIGlmIChkaXNwb3NlZCkge1xuICAgICAgZmFpbHVyZShcIlN0YXRlU3luY0xvZyBoYXMgYmVlbiBkaXNwb3NlZCBhbmQgY2Fubm90IGJlIHVzZWRcIilcbiAgICB9XG4gIH1cblxuICBjb25zdCBnZXRBY3RpdmVFcG9jaEludGVybmFsID0gKCkgPT4ge1xuICAgIGlmIChjbGllbnRTdGF0ZS5jYWNoZWRGaW5hbGl6ZWRFcG9jaCA9PT0gbnVsbCkge1xuICAgICAgZmFpbHVyZShcImNhY2hlZEZpbmFsaXplZEVwb2NoIGlzIG51bGwgLSB0aGlzIHNob3VsZCBub3QgaGFwcGVuIGFmdGVyIGluaXRpYWxpemF0aW9uXCIpXG4gICAgfVxuICAgIHJldHVybiBjbGllbnRTdGF0ZS5jYWNoZWRGaW5hbGl6ZWRFcG9jaCArIDFcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZ2V0U3RhdGUoKTogU3RhdGUge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgcmV0dXJuIChjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0Q2FjaGVkU3RhdGUoKSA/PyB7fSkgYXMgU3RhdGVcbiAgICB9LFxuXG4gICAgc3Vic2NyaWJlKGNhbGxiYWNrOiAobmV3U3RhdGU6IFN0YXRlLCBnZXRBcHBsaWVkT3BzOiAoKSA9PiByZWFkb25seSBPcFtdKSA9PiB2b2lkKTogKCkgPT4gdm9pZCB7XG4gICAgICBhc3NlcnROb3REaXNwb3NlZCgpXG4gICAgICBzdWJzY3JpYmVycy5hZGQoY2FsbGJhY2spXG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBzdWJzY3JpYmVycy5kZWxldGUoY2FsbGJhY2spXG4gICAgICB9XG4gICAgfSxcblxuICAgIGVtaXQob3BzOiBPcFtdKTogdm9pZCB7XG4gICAgICBhc3NlcnROb3REaXNwb3NlZCgpXG4gICAgICB5RG9jLnRyYW5zYWN0KCgpID0+IHtcbiAgICAgICAgY29uc3QgYWN0aXZlRXBvY2ggPSBnZXRBY3RpdmVFcG9jaEludGVybmFsKClcbiAgICAgICAgYXBwZW5kVHgob3BzLCB5VHgsIGFjdGl2ZUVwb2NoLCBjbGllbnRJZCwgY2xpZW50U3RhdGUpXG4gICAgICB9LCB5anNPcmlnaW4pXG4gICAgfSxcblxuICAgIHJlY29uY2lsZVN0YXRlKHRhcmdldFN0YXRlOiBTdGF0ZSk6IHZvaWQge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgY29uc3QgY3VycmVudFN0YXRlID0gKGNsaWVudFN0YXRlLnN0YXRlQ2FsY3VsYXRvci5nZXRDYWNoZWRTdGF0ZSgpID8/IHt9KSBhcyBTdGF0ZVxuICAgICAgY29uc3Qgb3BzID0gY29tcHV0ZVJlY29uY2lsZU9wcyhjdXJyZW50U3RhdGUsIHRhcmdldFN0YXRlKVxuICAgICAgaWYgKG9wcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuZW1pdChvcHMpXG4gICAgICB9XG4gICAgfSxcblxuICAgIGNvbXBhY3QoKTogdm9pZCB7XG4gICAgICBhc3NlcnROb3REaXNwb3NlZCgpXG4gICAgICB5RG9jLnRyYW5zYWN0KCgpID0+IHtcbiAgICAgICAgY29uc3QgYWN0aXZlRXBvY2ggPSBnZXRBY3RpdmVFcG9jaEludGVybmFsKClcbiAgICAgICAgY29uc3QgY3VycmVudFN0YXRlID0gY2xpZW50U3RhdGUuc3RhdGVDYWxjdWxhdG9yLmdldENhY2hlZFN0YXRlKCkgPz8ge31cbiAgICAgICAgY3JlYXRlQ2hlY2twb2ludCh5VHgsIHlDaGVja3BvaW50LCBjbGllbnRTdGF0ZSwgYWN0aXZlRXBvY2gsIGN1cnJlbnRTdGF0ZSwgY2xpZW50SWQpXG4gICAgICB9LCB5anNPcmlnaW4pXG4gICAgfSxcblxuICAgIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgICBpZiAoZGlzcG9zZWQpIHJldHVybiAvLyBBbHJlYWR5IGRpc3Bvc2VkLCBuby1vcFxuICAgICAgZGlzcG9zZWQgPSB0cnVlXG4gICAgICB5VHgudW5vYnNlcnZlKHR4T2JzZXJ2ZXIpXG4gICAgICB5Q2hlY2twb2ludC51bm9ic2VydmUoY2hlY2twb2ludE9ic2VydmVyKVxuICAgICAgc3Vic2NyaWJlcnMuY2xlYXIoKVxuICAgIH0sXG5cbiAgICBnZXRBY3RpdmVFcG9jaCgpOiBudW1iZXIge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgcmV0dXJuIGdldEFjdGl2ZUVwb2NoSW50ZXJuYWwoKVxuICAgIH0sXG5cbiAgICBnZXRBY3RpdmVFcG9jaFR4Q291bnQoKTogbnVtYmVyIHtcbiAgICAgIGFzc2VydE5vdERpc3Bvc2VkKClcbiAgICAgIGNvbnN0IGFjdGl2ZUVwb2NoID0gZ2V0QWN0aXZlRXBvY2hJbnRlcm5hbCgpXG4gICAgICBsZXQgY291bnQgPSAwXG4gICAgICAvLyBPbmx5IGN1cnJlbnQgb3IgZnV0dXJlIGVwb2NocyBleGlzdCBpbiBzb3J0ZWRUeHMgKHBhc3QgZXBvY2hzIGFyZSBwcnVuZWQgZHVyaW5nIHVwZGF0ZVN0YXRlKS5cbiAgICAgIC8vIEZ1dHVyZSBlcG9jaHMgYXBwZWFyIGlmIHdlIHJlY2VpdmUgdHhzIGJlZm9yZSB0aGUgY29ycmVzcG9uZGluZyBjaGVja3BvaW50LlxuICAgICAgZm9yIChjb25zdCBlbnRyeSBvZiBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzKCkpIHtcbiAgICAgICAgY29uc3QgdHMgPSBlbnRyeS50eFRpbWVzdGFtcFxuICAgICAgICBpZiAodHMuZXBvY2ggPT09IGFjdGl2ZUVwb2NoKSB7XG4gICAgICAgICAgY291bnQrK1xuICAgICAgICB9IGVsc2UgaWYgKHRzLmVwb2NoID4gYWN0aXZlRXBvY2gpIHtcbiAgICAgICAgICBicmVhayAvLyBPcHRpbWl6YXRpb246IHNvcnRlZCBvcmRlciBtZWFucyB3ZSBjYW4gc3RvcCBlYXJseVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gY291bnRcbiAgICB9LFxuXG4gICAgZ2V0QWN0aXZlRXBvY2hTdGFydFRpbWUoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICAgIGFzc2VydE5vdERpc3Bvc2VkKClcbiAgICAgIGNvbnN0IGFjdGl2ZUVwb2NoID0gZ2V0QWN0aXZlRXBvY2hJbnRlcm5hbCgpXG4gICAgICAvLyBPbmx5IGN1cnJlbnQgb3IgZnV0dXJlIGVwb2NocyBleGlzdCBpbiBzb3J0ZWRUeHMgKHBhc3QgZXBvY2hzIGFyZSBwcnVuZWQgZHVyaW5nIHVwZGF0ZVN0YXRlKS5cbiAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgY2xpZW50U3RhdGUuc3RhdGVDYWxjdWxhdG9yLmdldFNvcnRlZFR4cygpKSB7XG4gICAgICAgIGNvbnN0IHRzID0gZW50cnkudHhUaW1lc3RhbXBcbiAgICAgICAgaWYgKHRzLmVwb2NoID09PSBhY3RpdmVFcG9jaCkge1xuICAgICAgICAgIHJldHVybiB0cy53YWxsQ2xvY2tcbiAgICAgICAgfSBlbHNlIGlmICh0cy5lcG9jaCA+IGFjdGl2ZUVwb2NoKSB7XG4gICAgICAgICAgYnJlYWsgLy8gT3B0aW1pemF0aW9uOiBzb3J0ZWQgb3JkZXIgbWVhbnMgd2UgY2FuIHN0b3AgZWFybHlcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgIH0sXG5cbiAgICBpc0xvZ0VtcHR5KCk6IGJvb2xlYW4ge1xuICAgICAgYXNzZXJ0Tm90RGlzcG9zZWQoKVxuICAgICAgcmV0dXJuIHlUeC5zaXplID09PSAwICYmIHlDaGVja3BvaW50LnNpemUgPT09IDBcbiAgICB9LFxuXG4gICAgW2dldFNvcnRlZFR4c1N5bWJvbF0oKTogcmVhZG9ubHkgU29ydGVkVHhFbnRyeVtdIHtcbiAgICAgIGFzc2VydE5vdERpc3Bvc2VkKClcbiAgICAgIHJldHVybiBjbGllbnRTdGF0ZS5zdGF0ZUNhbGN1bGF0b3IuZ2V0U29ydGVkVHhzKClcbiAgICB9LFxuICB9XG59XG4iLCJpbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4vZXJyb3JcIlxyXG5pbXBvcnQgeyBKU09OT2JqZWN0LCBKU09OVmFsdWUsIFBhdGggfSBmcm9tIFwiLi9qc29uXCJcclxuaW1wb3J0IHsgZGVlcENsb25lLCBkZWVwRXF1YWwsIGlzT2JqZWN0IH0gZnJvbSBcIi4vdXRpbHNcIlxyXG5cclxuLyoqXHJcbiAqIFN1cHBvcnRlZCBvcGVyYXRpb25zLlxyXG4gKiBBcHBsaWVkIHNlcXVlbnRpYWxseSB3aXRoaW4gYSB0eC5cclxuICovXHJcbmV4cG9ydCB0eXBlIE9wID1cclxuICB8IHsga2luZDogXCJzZXRcIjsgcGF0aDogUGF0aDsga2V5OiBzdHJpbmc7IHZhbHVlOiBKU09OVmFsdWUgfVxyXG4gIHwgeyBraW5kOiBcImRlbGV0ZVwiOyBwYXRoOiBQYXRoOyBrZXk6IHN0cmluZyB9XHJcbiAgfCB7IGtpbmQ6IFwic3BsaWNlXCI7IHBhdGg6IFBhdGg7IGluZGV4OiBudW1iZXI7IGRlbGV0ZUNvdW50OiBudW1iZXI7IGluc2VydHM6IEpTT05WYWx1ZVtdIH1cclxuICB8IHsga2luZDogXCJhZGRUb1NldFwiOyBwYXRoOiBQYXRoOyB2YWx1ZTogSlNPTlZhbHVlIH1cclxuICB8IHsga2luZDogXCJkZWxldGVGcm9tU2V0XCI7IHBhdGg6IFBhdGg7IHZhbHVlOiBKU09OVmFsdWUgfVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRpb24gZnVuY3Rpb24gdHlwZS5cclxuICpcclxuICogUnVsZXM6XHJcbiAqIC0gVmFsaWRhdGlvbiBNVVNUIGRlcGVuZCBvbmx5IG9uIGNhbmRpZGF0ZVN0YXRlIChhbmQgZGV0ZXJtaW5pc3RpYyBjb2RlKS5cclxuICogLSBWYWxpZGF0aW9uIHJ1bnMgb25jZSBwZXIgdHgsIGFmdGVyIGFsbCBvcHMgYXBwbHkuXHJcbiAqIC0gSWYgdmFsaWRhdGlvbiBmYWlscywgdGhlIHggaXMgcmVqZWN0ZWQgKHN0YXRlIHJldmVydHMgdG8gcHJldmlvdXMpLlxyXG4gKiAtIElmIG5vIHZhbGlkYXRvciBpcyBwcm92aWRlZCwgdmFsaWRhdGlvbiBkZWZhdWx0cyB0byB0cnVlLlxyXG4gKlxyXG4gKiBJTVBPUlRBTlQ6IFZhbGlkYXRpb24gb3V0Y29tZSBpcyAqKmRlcml2ZWQgbG9jYWwgc3RhdGUqKiBhbmQgTVVTVCBOT1QgYmUgcmVwbGljYXRlZC5cclxuICogQWxsIGNsaWVudHMgTVVTVCB1c2UgdGhlIHNhbWUgdmFsaWRhdGlvbiBsb2dpYyB0byBlbnN1cmUgY29uc2lzdGVuY3kuXHJcbiAqL1xyXG5leHBvcnQgdHlwZSBWYWxpZGF0ZUZuPFN0YXRlIGV4dGVuZHMgSlNPTk9iamVjdD4gPSAoY2FuZGlkYXRlU3RhdGU6IFN0YXRlKSA9PiBib29sZWFuXHJcblxyXG4vKipcclxuICogUmVzb2x2ZXMgYSBwYXRoIHdpdGhpbiB0aGUgc3RhdGUuXHJcbiAqIFRocm93cyBpZiBhbnkgc2VnbWVudCBpcyBtaXNzaW5nIG9yIGhhcyB3cm9uZyB0eXBlLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVzb2x2ZVBhdGgoc3RhdGU6IEpTT05PYmplY3QsIHBhdGg6IFBhdGgpOiBKU09OVmFsdWUge1xyXG4gIGxldCBjdXJyZW50OiBKU09OVmFsdWUgPSBzdGF0ZVxyXG4gIGZvciAoY29uc3Qgc2VnbWVudCBvZiBwYXRoKSB7XHJcbiAgICBpZiAodHlwZW9mIHNlZ21lbnQgPT09IFwic3RyaW5nXCIpIHtcclxuICAgICAgaWYgKCFpc09iamVjdChjdXJyZW50KSB8fCBBcnJheS5pc0FycmF5KGN1cnJlbnQpKSB7XHJcbiAgICAgICAgZmFpbHVyZShgRXhwZWN0ZWQgb2JqZWN0IGF0IHBhdGggc2VnbWVudCBcIiR7c2VnbWVudH1cImApXHJcbiAgICAgIH1cclxuICAgICAgaWYgKCEoc2VnbWVudCBpbiBjdXJyZW50KSkge1xyXG4gICAgICAgIGZhaWx1cmUoYFByb3BlcnR5IFwiJHtzZWdtZW50fVwiIGRvZXMgbm90IGV4aXN0YClcclxuICAgICAgfVxyXG4gICAgICBjdXJyZW50ID0gY3VycmVudFtzZWdtZW50XVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGN1cnJlbnQpKSB7XHJcbiAgICAgICAgZmFpbHVyZShgRXhwZWN0ZWQgYXJyYXkgYXQgcGF0aCBzZWdtZW50ICR7c2VnbWVudH1gKVxyXG4gICAgICB9XHJcbiAgICAgIGlmIChzZWdtZW50IDwgMCB8fCBzZWdtZW50ID49IGN1cnJlbnQubGVuZ3RoKSB7XHJcbiAgICAgICAgZmFpbHVyZShgSW5kZXggJHtzZWdtZW50fSBvdXQgb2YgYm91bmRzYClcclxuICAgICAgfVxyXG4gICAgICBjdXJyZW50ID0gY3VycmVudFtzZWdtZW50XVxyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gY3VycmVudFxyXG59XHJcblxyXG4vKipcclxuICogQXBwbGllcyBhIHNpbmdsZSBvcGVyYXRpb24uXHJcbiAqIChSZWZlcmVuY2UgaW1wbGVtZW50YXRpb24gZm9yIHN0YW5kYXJkIEpTT04tcGF0Y2ggYmVoYXZpb3IpXHJcbiAqL1xyXG5mdW5jdGlvbiBhcHBseU9wKHN0YXRlOiBKU09OT2JqZWN0LCBvcDogT3AsIGNsb25lVmFsdWVzOiBib29sZWFuKTogdm9pZCB7XHJcbiAgLy8gU3BlY2lhbCBjYXNlOiBpZiBwYXRoIGlzIGVtcHR5LCB3ZSBjYW4ndCByZXNvbHZlIFwiY29udGFpbmVyXCIuXHJcbiAgLy8gVGhlIGNhbGxlciBtdXN0IGhhbmRsZSByb290LWxldmVsIHJlcGxhY2VtZW50IGlmIG5lY2Vzc2FyeSwgYnV0XHJcbiAgLy8gc3RhbmRhcmQgT3BzIHVzdWFsbHkgYWN0IE9OIGEgY29udGFpbmVyLlxyXG4gIC8vIEV4Y2VwdGlvbjogaWYgd2UgYWN0IG9uIHJvb3QsIGhhbmRsZSBleHBsaWNpdGx5IG9yIGFzc3VtZSBwYXRoIGxlbmd0aCA+IDAuXHJcbiAgLy8gRm9yIHRoaXMgc3BlYywgT3BzIG1vZGlmeSAqZmllbGRzKiBvciAqaW5kaWNlcyouXHJcbiAgLy8gSWYgcGF0aCBpcyBlbXB0eSwgaXQgbWVhbnMgd2UgYXJlIGFjdGluZyBPTiB0aGUgcm9vdCBvYmplY3QgaXRzZWxmP1xyXG4gIC8vIFRoZSBzcGVjJ3MgXCJzZXRcIiBleGFtcGxlOiBjb250YWluZXJbb3Aua2V5XSA9IG9wLnZhbHVlLlxyXG4gIC8vIFRoaXMgaW1wbGllcyB3ZSByZXNvbHZlIHBhdGggdG8gZ2V0IHRoZSBQQVJFTlQgY29udGFpbmVyLlxyXG5cclxuICBjb25zdCBjb250YWluZXIgPSByZXNvbHZlUGF0aChzdGF0ZSwgb3AucGF0aClcclxuXHJcbiAgc3dpdGNoIChvcC5raW5kKSB7XHJcbiAgICBjYXNlIFwic2V0XCI6XHJcbiAgICAgIGlmICghaXNPYmplY3QoY29udGFpbmVyKSB8fCBBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcclxuICAgICAgICBmYWlsdXJlKFwic2V0IHJlcXVpcmVzIG9iamVjdCBjb250YWluZXJcIilcclxuICAgICAgfVxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxyXG4gICAgICA7KGNvbnRhaW5lciBhcyBhbnkpW29wLmtleV0gPSBjbG9uZVZhbHVlcyA/IGRlZXBDbG9uZShvcC52YWx1ZSkgOiBvcC52YWx1ZVxyXG4gICAgICBicmVha1xyXG5cclxuICAgIGNhc2UgXCJkZWxldGVcIjpcclxuICAgICAgaWYgKCFpc09iamVjdChjb250YWluZXIpIHx8IEFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xyXG4gICAgICAgIGZhaWx1cmUoXCJkZWxldGUgcmVxdWlyZXMgb2JqZWN0IGNvbnRhaW5lclwiKVxyXG4gICAgICB9XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XHJcbiAgICAgIGRlbGV0ZSAoY29udGFpbmVyIGFzIGFueSlbb3Aua2V5XVxyXG4gICAgICBicmVha1xyXG5cclxuICAgIGNhc2UgXCJzcGxpY2VcIjoge1xyXG4gICAgICBpZiAoIUFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xyXG4gICAgICAgIGZhaWx1cmUoXCJzcGxpY2UgcmVxdWlyZXMgYXJyYXkgY29udGFpbmVyXCIpXHJcbiAgICAgIH1cclxuICAgICAgY29uc3Qgc2FmZUluZGV4ID0gTWF0aC5taW4ob3AuaW5kZXgsIGNvbnRhaW5lci5sZW5ndGgpXHJcbiAgICAgIGNvbnRhaW5lci5zcGxpY2UoXHJcbiAgICAgICAgc2FmZUluZGV4LFxyXG4gICAgICAgIG9wLmRlbGV0ZUNvdW50LFxyXG4gICAgICAgIC4uLihjbG9uZVZhbHVlcyA/IG9wLmluc2VydHMubWFwKCh2KSA9PiBkZWVwQ2xvbmUodikpIDogb3AuaW5zZXJ0cylcclxuICAgICAgKVxyXG4gICAgICBicmVha1xyXG4gICAgfVxyXG5cclxuICAgIGNhc2UgXCJhZGRUb1NldFwiOlxyXG4gICAgICBpZiAoIUFycmF5LmlzQXJyYXkoY29udGFpbmVyKSkge1xyXG4gICAgICAgIGZhaWx1cmUoXCJhZGRUb1NldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcclxuICAgICAgfVxyXG4gICAgICBpZiAoIWNvbnRhaW5lci5zb21lKChpdGVtKSA9PiBkZWVwRXF1YWwoaXRlbSwgb3AudmFsdWUpKSkge1xyXG4gICAgICAgIGNvbnRhaW5lci5wdXNoKGNsb25lVmFsdWVzID8gZGVlcENsb25lKG9wLnZhbHVlKSA6IG9wLnZhbHVlKVxyXG4gICAgICB9XHJcbiAgICAgIGJyZWFrXHJcblxyXG4gICAgY2FzZSBcImRlbGV0ZUZyb21TZXRcIjpcclxuICAgICAgaWYgKCFBcnJheS5pc0FycmF5KGNvbnRhaW5lcikpIHtcclxuICAgICAgICBmYWlsdXJlKFwiZGVsZXRlRnJvbVNldCByZXF1aXJlcyBhcnJheSBjb250YWluZXJcIilcclxuICAgICAgfVxyXG4gICAgICAvLyBSZW1vdmUgYWxsIG1hdGNoaW5nIGl0ZW1zIHVzaW5nIHNwbGljZSAoZnJvbSBlbmQgdG8gYXZvaWQgaW5kZXggc2hpZnRpbmcpXHJcbiAgICAgIGZvciAobGV0IGkgPSBjb250YWluZXIubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcclxuICAgICAgICBpZiAoZGVlcEVxdWFsKGNvbnRhaW5lcltpXSwgb3AudmFsdWUpKSB7XHJcbiAgICAgICAgICBjb250YWluZXIuc3BsaWNlKGksIDEpXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGJyZWFrXHJcblxyXG4gICAgZGVmYXVsdDpcclxuICAgICAgdGhyb3cgZmFpbHVyZShgVW5rbm93biBvcGVyYXRpb24ga2luZDogJHsob3AgYXMgYW55KS5raW5kfWApXHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogT3B0aW9ucyBmb3IgYXBwbHlPcHMuXHJcbiAqL1xyXG5leHBvcnQgaW50ZXJmYWNlIEFwcGx5T3BzT3B0aW9ucyB7XHJcbiAgLyoqXHJcbiAgICogV2hldGhlciB0byBkZWVwIGNsb25lIHZhbHVlcyBiZWZvcmUgaW5zZXJ0aW5nIHRoZW0gaW50byB0aGUgdGFyZ2V0LlxyXG4gICAqIC0gYHRydWVgIChkZWZhdWx0KTogVmFsdWVzIGFyZSBjbG9uZWQgdG8gcHJldmVudCBhbGlhc2luZyBiZXR3ZWVuIHRoZSBvcHMgYW5kIHRhcmdldC5cclxuICAgKiAtIGBmYWxzZWA6IFZhbHVlcyBhcmUgdXNlZCBkaXJlY3RseSBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlLiBPbmx5IHVzZSB0aGlzIGlmIHlvdVxyXG4gICAqICAgZ3VhcmFudGVlIHRoZSBvcCB2YWx1ZXMgd29uJ3QgYmUgbXV0YXRlZCBhZnRlciBhcHBsaWNhdGlvbi5cclxuICAgKi9cclxuICBjbG9uZVZhbHVlcz86IGJvb2xlYW5cclxufVxyXG5cclxuLyoqXHJcbiAqIEFwcGxpZXMgYSBsaXN0IG9mIG9wZXJhdGlvbnMgdG8gYSBtdXRhYmxlIHRhcmdldCBvYmplY3QuXHJcbiAqIFVzZSB0aGlzIHRvIHN5bmNocm9uaXplIGFuIGV4dGVybmFsIG11dGFibGUgc3RhdGUgKGUuZy4sIE1vYlggc3RvcmUpXHJcbiAqIHdpdGggdGhlIG9wZXJhdGlvbnMgcmVjZWl2ZWQgdmlhIHN1YnNjcmliZSgpLlxyXG4gKlxyXG4gKiBAcGFyYW0gb3BzIC0gVGhlIGxpc3Qgb2Ygb3BlcmF0aW9ucyB0byBhcHBseS5cclxuICogQHBhcmFtIHRhcmdldCAtIFRoZSBtdXRhYmxlIG9iamVjdCB0byBtb2RpZnkuXHJcbiAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgc2V0dGluZ3MgZm9yIGNvbnRyb2xsaW5nIGNsb25pbmcgYmVoYXZpb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gYXBwbHlPcHMob3BzOiByZWFkb25seSBPcFtdLCB0YXJnZXQ6IEpTT05PYmplY3QsIG9wdGlvbnM/OiBBcHBseU9wc09wdGlvbnMpOiB2b2lkIHtcclxuICBjb25zdCBjbG9uZVZhbHVlcyA9IG9wdGlvbnM/LmNsb25lVmFsdWVzID8/IHRydWVcclxuICBmb3IgKGNvbnN0IG9wIG9mIG9wcykge1xyXG4gICAgYXBwbHlPcCh0YXJnZXQsIG9wLCBjbG9uZVZhbHVlcylcclxuICB9XHJcbn1cclxuIl0sIm5hbWVzIjpbImVxdWFsIiwic2NvcGVkVXJsQWxwaGFiZXQiLCJyZmRjIiwiaGFuZGxlciIsImNsb25lIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBWU8sV0FBUywrQkFBK0IsYUFHN0M7QUFDQSxRQUFJLFdBQVc7QUFDZixRQUFJLE9BQWdDO0FBQ3BDLFFBQUksY0FBYztBQUNsQixRQUFJLGVBQWU7QUFFbkIsZUFBVyxDQUFDLEtBQUssRUFBRSxLQUFLLFlBQVksV0FBVztBQUM3QyxZQUFNLEVBQUUsT0FBTyxhQUFhLG1CQUFtQixHQUFHO0FBRWxELFVBQUksUUFBUSxVQUFVO0FBRXBCLG1CQUFXO0FBQ1gsZUFBTztBQUNQLHNCQUFjLEdBQUc7QUFDakIsdUJBQWU7QUFBQSxNQUNqQixXQUFXLFVBQVUsVUFBVTtBQUk3QixZQUFJLEdBQUcsVUFBVSxlQUFnQixHQUFHLFlBQVksZUFBZSxXQUFXLGNBQWU7QUFDdkYsaUJBQU87QUFDUCx3QkFBYyxHQUFHO0FBQ2pCLHlCQUFlO0FBQUEsUUFDakI7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUVBLFdBQU8sRUFBRSxnQkFBZ0IsVUFBVSxZQUFZLEtBQUE7QUFBQSxFQUNqRDtBQUFBLEVDM0NPLE1BQU0sMEJBQTBCLE1BQU07QUFBQSxJQUMzQyxZQUFZLEtBQWE7QUFDdkIsWUFBTSxHQUFHO0FBR1QsYUFBTyxlQUFlLE1BQU0sa0JBQWtCLFNBQVM7QUFBQSxJQUN6RDtBQUFBLEVBQ0Y7QUFFTyxXQUFTLFFBQVEsU0FBd0I7QUFDOUMsVUFBTSxJQUFJLGtCQUFrQixPQUFPO0FBQUEsRUFDckM7QUN5Q0EsV0FBUyx1QkFBdUIsTUFBd0M7QUFDdEUsV0FBTyxHQUFHLEtBQUssS0FBSyxJQUFJ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QztBQUVFLGtCQUFrQixHQUFHLEdBQUcsSUFBSSxjQUFjLFVBQVUsR0FBRyxLQUFLLElBQUksR0FBRztBQUNyRTtBQUFBLE1BRUYsS0FBSztBQUNILFlBQUksQ0FBQyxTQUFTLFNBQVMsS0FBSyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQ3BELGtCQUFRLGtDQUFrQztBQUFBLFFBQzVDO0FBRUEsZUFBUSxVQUFrQixHQUFHLEdBQUc7QUFDaEM7QUFBQSxNQUVGLEtBQUssVUFBVTtBQUNiLFlBQUksQ0FBQyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQzdCLGtCQUFRLGlDQUFpQztBQUFBLFFBQzNDO0FBQ0EsY0FBTSxZQUFZLEtBQUssSUFBSSxHQUFHLE9BQU8sVUFBVSxNQUFNO0FBQ3JELGtCQUFVO0FBQUEsVUFDUjtBQUFBLFVBQ0EsR0FBRztBQUFBLFVBQ0gsR0FBSSxjQUFjLEdBQUcsUUFBUSxJQUFJLENBQUMsTUFBTSxVQUFVLENBQUMsQ0FBQyxJQUFJLEdBQUc7QUFBQSxRQUFBO0FBRTdEO0FBQUEsTUFDRjtBQUFBLE1BRUEsS0FBSztBQUNILFlBQUksQ0FBQyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQzdCLGtCQUFRLG1DQUFtQztBQUFBLFFBQzdDO0FBQ0EsWUFBSSxDQUFDLFVBQVUsS0FBSyxDQUFDLFNBQVMsVUFBVSxNQUFNLEdBQUcsS0FBSyxDQUFDLEdBQUc7QUFDeEQsb0JBQVUsS0FBSyxjQUFjLFVBQVUsR0FBRyxLQUFLLElBQUksR0FBRyxLQUFLO0FBQUEsUUFDN0Q7QUFDQTtBQUFBLE1BRUYsS0FBSztBQUNILFlBQUksQ0FBQyxNQUFNLFFBQVEsU0FBUyxHQUFHO0FBQzdCLGtCQUFRLHdDQUF3QztBQUFBLFFBQ2xEO0FBRUEsaUJBQVMsSUFBSSxVQUFVLFNBQVMsR0FBRyxLQUFLLEdBQUcsS0FBSztBQUM5QyxjQUFJLFVBQVUsVUFBVSxDQUFDLEdBQUcsR0FBRyxLQUFLLEdBQUc7QUFDckMsc0JBQVUsT0FBTyxHQUFHLENBQUM7QUFBQSxVQUN2QjtBQUFBLFFBQ0Y7QUFDQTtBQUFBLE1BRUY7QUFDRSxjQUFNLFFBQVEsMkJBQTRCLEdBQVcsSUFBSSxFQUFFO0FBQUEsSUFBQTtBQUFBLEVBRWpFO0FBd0JPLFdBQVMsU0FBUyxLQUFvQixRQUFvQixTQUFpQzs7QUFDaEcsVUFBTSxlQUFjLHdDQUFTLGdCQUFULFlBQXdCO0FBQzVDLGVBQVcsTUFBTSxLQUFLO0FBQ3BCLGNBQVEsUUFBUSxJQUFJLFdBQVc7QUFBQSxJQUNqQztBQUFBLEVBQ0Y7Ozs7OyIsInhfZ29vZ2xlX2lnbm9yZUxpc3QiOlszLDQsNSw2XX0=