sliftutils 1.7.10 → 1.7.11

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 (83) hide show
  1. package/examplestorage/exampleserver.ts +0 -2
  2. package/index.d.ts +290 -54
  3. package/misc/dist/environment.ts.cache +3 -3
  4. package/misc/dist/getSecret.ts.cache +139 -0
  5. package/misc/dist/strings.ts.cache +13 -0
  6. package/misc/dist/zip.ts.cache +9 -0
  7. package/misc/getSecret.ts +38 -16
  8. package/misc/https/cloudflareHelpers.d.ts +19 -0
  9. package/misc/https/cloudflareHelpers.ts +69 -0
  10. package/misc/https/dist/certs.ts.cache +115 -179
  11. package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
  12. package/misc/https/dist/dns.ts.cache +112 -100
  13. package/misc/https/dist/hostServer.ts.cache +130 -0
  14. package/misc/https/dist/httpsCerts.ts.cache +24 -5
  15. package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
  16. package/misc/https/dns.d.ts +41 -12
  17. package/misc/https/dns.ts +104 -101
  18. package/misc/https/hostServer.d.ts +0 -6
  19. package/misc/https/hostServer.ts +9 -5
  20. package/package.json +2 -2
  21. package/render-utils/dist/observer.tsx.cache +3 -2
  22. package/spec.txt +0 -90
  23. package/storage/ArchivesDisk.d.ts +2 -0
  24. package/storage/ArchivesDisk.ts +7 -3
  25. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
  26. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
  27. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
  28. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
  29. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
  30. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
  31. package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
  32. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
  33. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
  34. package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
  35. package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
  36. package/storage/IArchives.d.ts +47 -15
  37. package/storage/IArchives.ts +86 -31
  38. package/storage/backblaze.d.ts +15 -0
  39. package/storage/backblaze.ts +199 -79
  40. package/storage/dist/ArchivesDisk.ts.cache +373 -0
  41. package/storage/dist/FileFolderAPI.tsx.cache +508 -65
  42. package/storage/dist/IArchives.ts.cache +44 -0
  43. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
  44. package/storage/dist/JSONStorage.ts.cache +6 -2
  45. package/storage/dist/PendingManager.tsx.cache +1 -1
  46. package/storage/dist/TransactionStorage.ts.cache +231 -92
  47. package/storage/dist/backblaze.ts.cache +797 -0
  48. package/storage/dist/fileSystemPointer.ts.cache +36 -3
  49. package/storage/dist/remoteFileStorage.ts.cache +495 -0
  50. package/storage/remoteStorage/ArchivesRemote.d.ts +5 -1
  51. package/storage/remoteStorage/ArchivesRemote.ts +28 -8
  52. package/storage/remoteStorage/ArchivesUrl.d.ts +2 -0
  53. package/storage/remoteStorage/ArchivesUrl.ts +16 -4
  54. package/storage/remoteStorage/blobStore.d.ts +52 -3
  55. package/storage/remoteStorage/blobStore.ts +414 -101
  56. package/storage/remoteStorage/createArchives.d.ts +31 -10
  57. package/storage/remoteStorage/createArchives.ts +470 -253
  58. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
  59. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
  60. package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
  61. package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
  62. package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
  63. package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
  64. package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
  65. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
  66. package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
  67. package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
  68. package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
  69. package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
  70. package/storage/remoteStorage/remoteConfig.d.ts +8 -0
  71. package/storage/remoteStorage/remoteConfig.ts +105 -5
  72. package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
  73. package/storage/remoteStorage/sourceWrapper.ts +223 -0
  74. package/storage/remoteStorage/spec.md +31 -0
  75. package/storage/remoteStorage/storageController.d.ts +11 -0
  76. package/storage/remoteStorage/storageController.ts +109 -40
  77. package/storage/remoteStorage/storageServer.d.ts +0 -5
  78. package/storage/remoteStorage/storageServer.ts +17 -10
  79. package/storage/remoteStorage/storageServerCli.ts +0 -3
  80. package/storage/remoteStorage/storageServerState.d.ts +7 -1
  81. package/storage/remoteStorage/storageServerState.ts +230 -48
  82. package/testsite/server.ts +0 -2
  83. package/yarn.lock +11 -6
@@ -0,0 +1,1242 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
3
+ //exports.BulkDatabaseBase = exports.noopReactiveDeps = exports.bulkDatabase2Timing = exports.BULK_ROOT_FOLDER = void 0;
4
+ const misc_1 = require("socket-function/src/misc");
5
+ const batching_1 = require("socket-function/src/batching");
6
+ const bits_1 = require("socket-function/src/bits");
7
+ const caching_1 = require("socket-function/src/caching");
8
+ const typesafecss_1 = require("typesafecss");
9
+ const BulkDatabaseFormat_1 = require("./BulkDatabaseFormat");
10
+ const BulkDatabaseMerge_1 = require("./BulkDatabaseMerge");
11
+ const blockCache_1 = require("./blockCache");
12
+ const format_1 = require("socket-function/src/formatting/format");
13
+ const logColors_1 = require("socket-function/src/formatting/logColors");
14
+ const streamLog_1 = require("./streamLog");
15
+ const syncClient_1 = require("./syncClient");
16
+ const WriteOverlay_1 = require("./WriteOverlay");
17
+ const mergeLock_1 = require("./mergeLock");
18
+ const mergeMarkers_1 = require("./mergeMarkers");
19
+ const LoadedIndex_1 = require("./LoadedIndex");
20
+ const BulkDatabaseReader_1 = require("./BulkDatabaseReader");
21
+ exports.BULK_ROOT_FOLDER = "bulkDatabases2";
22
+ const FILE_EXTENSION = ".bulk";
23
+ const ROLLOVER_ROWS = 5000;
24
+ const ROLLOVER_BYTES = 5 * 1024 * 1024;
25
+ const MEMORY_WATCHDOG_INTERVAL_MS = 60 * 1000;
26
+ const STALE_DELETE_MS = 24 * 60 * 60 * 1000;
27
+ const MAX_INDEX_RELOAD_ATTEMPTS = 3;
28
+ const FIRST_MERGE_BYTES = BulkDatabaseFormat_1.TARGET_FILE_BYTES / 2;
29
+ const KEY_GROUP_BYTES = 800 * 1024 * 1024;
30
+ const DUP_THRESHOLD = 0.4;
31
+ // Whole-tier dedup short-circuit (after Pass 1): when the bulk tier is over this size AND the overall
32
+ // key duplication fraction is over this threshold, fold every bulk file in one merge instead of the
33
+ // per-key-group walk (which spaces merges 5 min apart — 16 h for 200 groups).
34
+ const DEDUP_TRIGGER_BYTES = 512 * 1024 * 1024;
35
+ const DEDUP_TRIGGER_FRACTION = 0.5;
36
+ const WRITE_FLUSH_FIRST_STEP_MS = 250;
37
+ // Skip logs are throttled per collection: the background write path retries merges about once a second,
38
+ // so an unthrottled log would repeat for the whole duration of another tab's merge.
39
+ const MERGE_SKIP_LOG_INTERVAL_MS = 30 * 1000;
40
+ exports.bulkDatabase2Timing = {
41
+ streamSealAgeMs: 10 * 60 * 60 * 1000,
42
+ // Wait this long after the tab becomes visible before the first merge check, then check this often
43
+ // afterwards. Tab being hidden cancels the timers (no merges while in background). Browser-only;
44
+ // Node compactors (e.g. remoteFileServer) drive their own polling.
45
+ visibleMergeIntervalMs: 5 * 60 * 1000,
46
+ mergeSpacingMs: 5 * 60 * 1000,
47
+ firstMergeTriggerFiles: 20,
48
+ firstMergeTriggerRangeMs: 3 * 24 * 60 * 60 * 1000,
49
+ streamFoldTriggerRows: 100,
50
+ streamFoldTriggerBytes: 64 * 1024 * 1024,
51
+ streamFileMaxBytes: 50 * 1024 * 1024,
52
+ streamFoldHardLimitBytes: 768 * 1024 * 1024,
53
+ // 0 = flush every write (Node — append is real and cheap); browser ramps to 15s to avoid rewriting
54
+ // the whole stream file per write.
55
+ writeFlushMaxDelayMs: (0, typesafecss_1.isNode)() ? 0 : 15 * 1000,
56
+ fileSetPollIntervalMs: 30 * 60 * 1000,
57
+ memoryFlushHeapBytes: 5 * 1024 * 1024 * 1024,
58
+ memoryFlushMinCollectionBytes: 100 * 1024 * 1024,
59
+ memoryFlushThrottleMs: 15 * 60 * 1000,
60
+ };
61
+ function fmtBytes(n) {
62
+ if (n < 1024)
63
+ return n + "B";
64
+ if (n < 1024 * 1024)
65
+ return (n / 1024).toFixed(1) + "KB";
66
+ if (n < 1024 * 1024 * 1024)
67
+ return (n / 1024 / 1024).toFixed(1) + "MB";
68
+ return (n / 1024 / 1024 / 1024).toFixed(2) + "GB";
69
+ }
70
+ exports.noopReactiveDeps = {
71
+ observe() { },
72
+ invalidate() { },
73
+ batch(fn) { fn(); },
74
+ isObserved() { return false; },
75
+ };
76
+ let networkCompactionEnabled = false;
77
+ let fileNameCounter = 0;
78
+ // Per-process ID so two writers picking the same timestamp + counter never collide on a name.
79
+ const writerId = Math.random().toString(36).slice(2, 10);
80
+ function nextCounter() { return ++fileNameCounter; }
81
+ let lastFileTime = 0;
82
+ // Strictly-increasing integer so newest-first ordering is unambiguous within a millisecond.
83
+ function nextFileTime() {
84
+ lastFileTime = Math.max(Date.now(), lastFileTime + 1);
85
+ return lastFileTime;
86
+ }
87
+ function newFileName(timestamp) {
88
+ return `0_${timestamp}_${writerId}_${nextCounter()}${FILE_EXTENSION}`;
89
+ }
90
+ function parseStreamFileName(fileName) {
91
+ if (!fileName.endsWith(streamLog_1.STREAM_EXTENSION))
92
+ return undefined;
93
+ const parts = fileName.slice(0, -streamLog_1.STREAM_EXTENSION.length).split("_");
94
+ if (parts.length !== 3 || parts[0] !== "stream")
95
+ return undefined;
96
+ const timestamp = parseInt(parts[1], 10);
97
+ if (!Number.isFinite(timestamp))
98
+ return undefined;
99
+ return { fileName, timestamp };
100
+ }
101
+ // Accept old 3-part (level_timestamp_counter) and new 4-part (level_timestamp_writerId_counter) shapes.
102
+ function parseFileName(fileName) {
103
+ if (!fileName.endsWith(FILE_EXTENSION))
104
+ return undefined;
105
+ const parts = fileName.slice(0, -FILE_EXTENSION.length).split("_");
106
+ if (parts.length < 3)
107
+ return undefined;
108
+ const level = parseInt(parts[0], 10);
109
+ const timestamp = parseInt(parts[1], 10);
110
+ if (!Number.isFinite(level) || !Number.isFinite(timestamp))
111
+ return undefined;
112
+ return { fileName, level, timestamp };
113
+ }
114
+ class BulkDatabaseBase {
115
+ constructor(name, deps, storageFactory, config = {}) {
116
+ this.name = name;
117
+ this.deps = deps;
118
+ this.storageFactory = storageFactory;
119
+ this.config = config;
120
+ this.activated = false;
121
+ this.subCaches = { bulk: new Map(), stream: new Map() };
122
+ this.pendingAppends = [];
123
+ this.flushChain = Promise.resolve();
124
+ this.currentFlushDelay = 0;
125
+ this.lastWriteTime = 0;
126
+ this.currentStreamFileBytes = 0;
127
+ // In-process re-entry guard: if a merge is running, additional triggers (visibility timer, writes,
128
+ // tryMergeNow calls) return immediately instead of queueing. Keeps the visibility-timer firings
129
+ // from stacking behind a long merge.
130
+ this.mergeInFlight = false;
131
+ this.lastMergeSkipLogMs = 0;
132
+ // Running counters of stream-tier rows + bytes on disk. Seeded from each LoadedIndex build, then
133
+ // incremented per flush so the fold-trigger checks current data without an extra directory listing.
134
+ this.streamRowsOnDisk = 0;
135
+ this.streamBytesOnDisk = 0;
136
+ this.rebuildDirty = false;
137
+ this.rebuildOptions = { dropStaleFallback: false };
138
+ this.storage = (0, caching_1.lazy)(async () => this.storageFactory(`${exports.BULK_ROOT_FOLDER}/${this.name}`));
139
+ // ── cross-tab sync ───────────────────────────────────────────────────────────────────────────────
140
+ this.syncSetup = (0, caching_1.lazy)(async () => {
141
+ if (!(0, syncClient_1.isSyncSupported)())
142
+ return;
143
+ await this.ensureIndex();
144
+ const recent = await (0, syncClient_1.connect)(this.name, w => this.applyRemote(w), () => { this.streamFileName = undefined; });
145
+ for (const w of recent)
146
+ this.applyRemote(w);
147
+ });
148
+ // Throttled marker housekeeping: delete inputs whose replacement outputs have landed (or whose
149
+ // marker has aged out) and retire fulfilled markers. Triggered from listFiles, so it's gated to
150
+ // avoid a delete storm under heavy reads.
151
+ this.processMarkers = (0, misc_1.throttleFunction)(30 * 1000, async () => {
152
+ const storage = await this.storage();
153
+ const names = await storage.getKeys();
154
+ const markers = await (0, mergeMarkers_1.readDeleteMarkers)(storage, names);
155
+ if (markers.length)
156
+ await (0, mergeMarkers_1.processDeleteMarkers)(this.name, storage, markers, names);
157
+ });
158
+ // The background path (maybeMerge) goes through this so write bursts coalesce; explicit callers use
159
+ // tryMergeNow directly and get the per-call result.
160
+ this.tryMergeThrottled = (0, misc_1.throttleFunction)(1000, async () => {
161
+ await this.tryMergeNow();
162
+ });
163
+ // The one merge primitive. Reads + plans + writes outputs before deleting any input, so a crash
164
+ // leaves duplicates (next merge dedupes) rather than a gap. After the file set changes on disk,
165
+ // we trigger an index rebuild + atomic swap; once swap completes, the consumed files' block-cache
166
+ // entries are evicted (no consumer can ask for them now).
167
+ //
168
+ // Serialized: foldOwnStream + merge(timeLo, timeHi) + testMerge's runMerge all hit this; the lock
169
+ // covers tryMergeNow/compact but those two paths bypass it. runInSerial queues so they never
170
+ // collide on the file set.
171
+ this.mergeFileSet = (0, batching_1.runInSerial)(async (bulkFiles, streamFiles, includesOldest = false, forceDeleteStreams = false) => {
172
+ this.reader.beginCompaction();
173
+ try {
174
+ return await this.mergeFileSetInner(bulkFiles, streamFiles, includesOldest, forceDeleteStreams);
175
+ }
176
+ finally {
177
+ this.reader.endCompaction();
178
+ }
179
+ });
180
+ }
181
+ get reader() {
182
+ if (this._reader)
183
+ return this._reader;
184
+ const reader = new BulkDatabaseReader_1.BulkDatabaseReader({
185
+ name: this.name,
186
+ deps: this.deps,
187
+ maxTriggerThrottleMs: this.config.maxTriggerThrottleMs,
188
+ });
189
+ reader.setEnsureIndex(() => this.ensureIndex());
190
+ this._reader = reader;
191
+ this.activate();
192
+ return reader;
193
+ }
194
+ activate() {
195
+ var _a, _b;
196
+ if (this.activated)
197
+ return;
198
+ this.activated = true;
199
+ if (typeof window !== "undefined") {
200
+ try {
201
+ window.addEventListener("pagehide", () => void this.flushPending());
202
+ if (typeof document !== "undefined") {
203
+ document.addEventListener("visibilitychange", () => {
204
+ if (document.visibilityState === "hidden")
205
+ void this.flushPending();
206
+ });
207
+ }
208
+ }
209
+ catch ( /* not in a DOM context */_c) { /* not in a DOM context */ }
210
+ }
211
+ this.fileSetPollTimer = setInterval(() => void this.pollFileSet(), exports.bulkDatabase2Timing.fileSetPollIntervalMs);
212
+ (_b = (_a = this.fileSetPollTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
213
+ this.setupVisibilityMergeCheck();
214
+ BulkDatabaseBase.liveInstances.add(this);
215
+ BulkDatabaseBase.startMemoryWatchdog();
216
+ }
217
+ // Every `visibleMergeIntervalMs` of being-visible time, run a merge check. First check fires
218
+ // `visibleMergeIntervalMs` after the tab becomes visible (not on initial load — gives the user a
219
+ // moment of session commitment before we start churning the FS), then every interval after. Tab
220
+ // hiding cancels the timers; visible-again restarts. Node has no document — there we consider
221
+ // ourselves always-visible and just install the interval directly.
222
+ setupVisibilityMergeCheck() {
223
+ let firstTimer;
224
+ let intervalTimer;
225
+ const stop = () => {
226
+ if (firstTimer) {
227
+ clearTimeout(firstTimer);
228
+ firstTimer = undefined;
229
+ }
230
+ if (intervalTimer) {
231
+ clearInterval(intervalTimer);
232
+ intervalTimer = undefined;
233
+ }
234
+ };
235
+ const start = () => {
236
+ var _a, _b;
237
+ if (firstTimer || intervalTimer)
238
+ return;
239
+ firstTimer = setTimeout(() => {
240
+ var _a, _b;
241
+ firstTimer = undefined;
242
+ void this.maybeMerge();
243
+ intervalTimer = setInterval(() => void this.maybeMerge(), exports.bulkDatabase2Timing.visibleMergeIntervalMs);
244
+ (_b = (_a = intervalTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
245
+ }, exports.bulkDatabase2Timing.visibleMergeIntervalMs);
246
+ (_b = (_a = firstTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
247
+ };
248
+ if (typeof document === "undefined") {
249
+ start();
250
+ return;
251
+ }
252
+ try {
253
+ document.addEventListener("visibilitychange", () => {
254
+ if (document.visibilityState === "visible")
255
+ start();
256
+ else
257
+ stop();
258
+ });
259
+ if (document.visibilityState === "visible")
260
+ start();
261
+ }
262
+ catch ( /* not in a DOM context */_a) { /* not in a DOM context */ }
263
+ }
264
+ static startMemoryWatchdog() {
265
+ var _a, _b;
266
+ if (BulkDatabaseBase.memoryWatchdogStarted)
267
+ return;
268
+ BulkDatabaseBase.memoryWatchdogStarted = true;
269
+ const usedHeap = () => {
270
+ var _a;
271
+ try {
272
+ return (_a = performance === null || performance === void 0 ? void 0 : performance.memory) === null || _a === void 0 ? void 0 : _a.usedJSHeapSize;
273
+ }
274
+ catch (_b) {
275
+ return undefined;
276
+ }
277
+ };
278
+ if (typeof performance === "undefined" || usedHeap() === undefined)
279
+ return;
280
+ const timer = setInterval(() => {
281
+ const used = usedHeap();
282
+ if (used !== undefined)
283
+ BulkDatabaseBase.checkMemoryPressure(used);
284
+ }, MEMORY_WATCHDOG_INTERVAL_MS);
285
+ (_b = (_a = timer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
286
+ }
287
+ static checkMemoryPressure(usedHeapBytes) {
288
+ var _a, _b;
289
+ if (usedHeapBytes < exports.bulkDatabase2Timing.memoryFlushHeapBytes)
290
+ return;
291
+ const now = Date.now();
292
+ if (now - BulkDatabaseBase.lastMemoryFlushMs < exports.bulkDatabase2Timing.memoryFlushThrottleMs)
293
+ return;
294
+ BulkDatabaseBase.lastMemoryFlushMs = now;
295
+ const flushed = [];
296
+ for (const db of BulkDatabaseBase.liveInstances) {
297
+ const bytes = (_b = (_a = db.reader.index) === null || _a === void 0 ? void 0 : _a.totalBytes) !== null && _b !== void 0 ? _b : 0;
298
+ if (bytes > exports.bulkDatabase2Timing.memoryFlushMinCollectionBytes) {
299
+ flushed.push(`${db.name} (${fmtBytes(bytes)})`);
300
+ db.reloadFromDisk();
301
+ }
302
+ }
303
+ if (flushed.length)
304
+ console.log(`[bulk2] heap ${fmtBytes(usedHeapBytes)} over ${fmtBytes(exports.bulkDatabase2Timing.memoryFlushHeapBytes)} - flushed ${flushed.length} large collection(s): ${flushed.join(", ")}`);
305
+ }
306
+ static clearCache() {
307
+ blockCache_1.blockCache.clear();
308
+ }
309
+ static enableNetworkCompaction() {
310
+ networkCompactionEnabled = true;
311
+ }
312
+ async isRemote() {
313
+ return !!(await this.storage()).isRemote;
314
+ }
315
+ streamNeedsFold() {
316
+ return this.streamRowsOnDisk >= exports.bulkDatabase2Timing.streamFoldTriggerRows
317
+ && this.streamBytesOnDisk > exports.bulkDatabase2Timing.streamFoldTriggerBytes;
318
+ }
319
+ async automaticCompactionAllowed() {
320
+ if (networkCompactionEnabled)
321
+ return true;
322
+ if ((0, typesafecss_1.isNode)())
323
+ return true;
324
+ return !(await this.storage()).isRemote;
325
+ }
326
+ isKeyWatched(key) {
327
+ return this.reader.isKeyWatched(key);
328
+ }
329
+ // ── index lifecycle ──────────────────────────────────────────────────────────────────────────────
330
+ async ensureIndex() {
331
+ if (this.reader.index)
332
+ return this.reader.index;
333
+ await this.triggerRebuild();
334
+ const idx = this.reader.index;
335
+ if (!idx)
336
+ throw new Error(`${this.name}: index failed to build`);
337
+ return idx;
338
+ }
339
+ // Coalescing rebuild loop: triggers during a build set rebuildDirty so the loop iterates once more
340
+ // when it finishes — N rapid triggers cause at most ONE extra rebuild after the current one ends.
341
+ triggerRebuild(opts = {}) {
342
+ if (opts.dropStaleFallback)
343
+ this.rebuildOptions.dropStaleFallback = true;
344
+ if (this.rebuildPromise) {
345
+ this.rebuildDirty = true;
346
+ return this.rebuildPromise;
347
+ }
348
+ this.rebuildPromise = (async () => {
349
+ try {
350
+ do {
351
+ this.rebuildDirty = false;
352
+ await this.doOneRebuild();
353
+ } while (this.rebuildDirty);
354
+ }
355
+ finally {
356
+ this.rebuildPromise = undefined;
357
+ this.rebuildOptions.dropStaleFallback = false;
358
+ }
359
+ })();
360
+ return this.rebuildPromise;
361
+ }
362
+ async doOneRebuild() {
363
+ const { bulkFiles, streamFiles } = await this.listFiles();
364
+ const storage = await this.storage();
365
+ const newIndex = await LoadedIndex_1.LoadedIndex.build({
366
+ name: this.name,
367
+ storage,
368
+ bulkFiles,
369
+ streamFiles,
370
+ subCaches: this.subCaches,
371
+ onUnreadableFile: (f, msg) => this.handleUnreadableFile(f, msg),
372
+ });
373
+ const oldIndex = this.reader.index;
374
+ this.reader.setIndex(newIndex, { dropStaleFallback: this.rebuildOptions.dropStaleFallback });
375
+ this.streamRowsOnDisk = newIndex.streamRowsOnDisk;
376
+ this.streamBytesOnDisk = newIndex.streamBytesOnDisk;
377
+ if (oldIndex) {
378
+ for (const f of oldIndex.fileSet) {
379
+ if (!newIndex.fileSet.has(f))
380
+ blockCache_1.blockCache.evict((0, BulkDatabaseReader_1.nullJoin)(this.name, f));
381
+ }
382
+ }
383
+ }
384
+ // Drop everything in-memory, hard reset. Pending un-flushed writes survive (still in overlay).
385
+ reloadFromDisk() {
386
+ var _a;
387
+ this.subCaches.bulk.clear();
388
+ this.subCaches.stream.clear();
389
+ (_a = this.reader.index) === null || _a === void 0 ? void 0 : _a.dropLoadedValues();
390
+ void this.triggerRebuild({ dropStaleFallback: true });
391
+ }
392
+ // External-merge detection: if some other tab/process changed the file set under us, rebuild.
393
+ async pollFileSet() {
394
+ var _a;
395
+ if (!this.reader.index)
396
+ return;
397
+ let current;
398
+ try {
399
+ const { bulkFiles, streamFiles } = await this.listFiles();
400
+ current = new Set([...bulkFiles.map(f => f.fileName), ...streamFiles.map(f => f.fileName)]);
401
+ }
402
+ catch (_b) {
403
+ return;
404
+ }
405
+ const prev = (_a = this.reader.index) === null || _a === void 0 ? void 0 : _a.fileSet;
406
+ if (!prev)
407
+ return;
408
+ const changed = current.size !== prev.size || [...current].some(n => !prev.has(n));
409
+ if (changed)
410
+ void this.triggerRebuild();
411
+ }
412
+ async readWithRetry(fn) {
413
+ await this.ensureIndex();
414
+ for (let attempt = 0;; attempt++) {
415
+ const before = this.reader.index;
416
+ try {
417
+ return await fn();
418
+ }
419
+ catch (e) {
420
+ if (!(e instanceof LoadedIndex_1.MissingFileError) || attempt >= MAX_INDEX_RELOAD_ATTEMPTS)
421
+ throw e;
422
+ if (this.reader.index === before)
423
+ await this.triggerRebuild();
424
+ }
425
+ }
426
+ }
427
+ applyRemote(write) {
428
+ if (write.time <= this.reader.localTime(write.key))
429
+ return;
430
+ this.deps.batch(() => {
431
+ if (write.deleted)
432
+ this.reader.applyDelete(write.key, write.time);
433
+ else
434
+ this.reader.applyWrite(write.key, write.value, write.time);
435
+ });
436
+ }
437
+ // ── writes ───────────────────────────────────────────────────────────────────────────────────────
438
+ async write(entry) {
439
+ return this.writeBatch([entry]);
440
+ }
441
+ async writeBatch(entries) {
442
+ if (!entries.length)
443
+ return;
444
+ void this.syncSetup();
445
+ const rows = entries;
446
+ const stamped = rows.map(row => ({ time: (0, bits_1.getTimeUnique)(), row }));
447
+ const framed = (0, streamLog_1.frameRows)(stamped);
448
+ // Big batches skip the stream and become a bulk file directly — streaming thousands of rows
449
+ // one frame at a time would just churn.
450
+ if (entries.length >= ROLLOVER_ROWS || framed.length >= ROLLOVER_BYTES) {
451
+ await this.writeBulkFile(rows);
452
+ return;
453
+ }
454
+ this.deps.batch(() => {
455
+ for (const { time, row } of stamped)
456
+ this.reader.applyWrite(row.key, row, time);
457
+ });
458
+ for (const { time, row } of stamped)
459
+ (0, syncClient_1.broadcast)(this.name, { key: row.key, time, value: row });
460
+ await this.streamAppend(framed, stamped.length);
461
+ void this.maybeMerge({ onlyIfStreamHeavy: true });
462
+ }
463
+ async delete(key) {
464
+ return this.deleteBatch([key]);
465
+ }
466
+ async deleteBatch(keys) {
467
+ if (!keys.length)
468
+ return;
469
+ void this.syncSetup();
470
+ const stamped = keys.map(key => ({ time: (0, bits_1.getTimeUnique)(), key }));
471
+ this.deps.batch(() => {
472
+ for (const { time, key } of stamped)
473
+ this.reader.applyDelete(key, time);
474
+ });
475
+ for (const { time, key } of stamped)
476
+ (0, syncClient_1.broadcast)(this.name, { key, time, deleted: true });
477
+ await this.streamAppend((0, streamLog_1.frameDeletes)(stamped), stamped.length);
478
+ void this.maybeMerge({ onlyIfStreamHeavy: true });
479
+ }
480
+ // Coalesce stream appends on a ramping per-collection schedule (the browser rewrites the whole
481
+ // file per append). The first write after a lull flushes immediately so a single edit-then-close
482
+ // is saved at once; sustained writes ramp toward writeFlushMaxDelayMs.
483
+ async streamAppend(framed, rows) {
484
+ this.pendingAppends.push({ framed, rows });
485
+ const max = exports.bulkDatabase2Timing.writeFlushMaxDelayMs;
486
+ const now = Date.now();
487
+ if (max <= 0 || this.currentFlushDelay <= 0 || now - this.lastWriteTime > max) {
488
+ this.lastWriteTime = now;
489
+ this.currentFlushDelay = max > 0 ? Math.min(max, WRITE_FLUSH_FIRST_STEP_MS) : 0;
490
+ await this.flushPending();
491
+ return;
492
+ }
493
+ this.lastWriteTime = now;
494
+ if (this.flushTimer === undefined) {
495
+ this.flushTimer = setTimeout(() => { this.flushTimer = undefined; void this.flushPending(); }, this.currentFlushDelay);
496
+ }
497
+ this.currentFlushDelay = Math.min(max, this.currentFlushDelay * 2);
498
+ }
499
+ async flush() {
500
+ await this.flushPending();
501
+ }
502
+ async flushPending() {
503
+ if (this.flushTimer !== undefined) {
504
+ clearTimeout(this.flushTimer);
505
+ this.flushTimer = undefined;
506
+ }
507
+ this.flushChain = this.flushChain.then(() => this.doFlush()).catch(e => {
508
+ console.warn(`${this.name}: stream flush failed, will retry: ${e.message}`);
509
+ });
510
+ return this.flushChain;
511
+ }
512
+ async doFlush() {
513
+ if (!this.pendingAppends.length)
514
+ return;
515
+ const batch = this.pendingAppends.slice();
516
+ const combined = Buffer.concat(batch.map(p => p.framed));
517
+ const storage = await this.storage();
518
+ const fileName = this.getStreamFileName();
519
+ if (fileName !== this.currentStreamFileName) {
520
+ this.currentStreamFileName = fileName;
521
+ this.currentStreamFileBytes = 0;
522
+ }
523
+ // On failure the throw leaves pendingAppends intact so a later flush retries.
524
+ await storage.append(fileName, combined);
525
+ // New entries appended during the await are after `batch` — removing the front is exactly the
526
+ // flushed set.
527
+ this.pendingAppends.splice(0, batch.length);
528
+ this.streamBytesOnDisk += combined.length;
529
+ for (const p of batch)
530
+ this.streamRowsOnDisk += p.rows;
531
+ this.currentStreamFileBytes += combined.length;
532
+ if (this.currentStreamFileBytes >= exports.bulkDatabase2Timing.streamFileMaxBytes) {
533
+ this.streamFileName = undefined;
534
+ this.currentStreamFileName = undefined;
535
+ this.currentStreamFileBytes = 0;
536
+ void this.foldOwnStream(fileName);
537
+ }
538
+ }
539
+ getStreamFileName() {
540
+ // Seal our current file once it ages past the seal threshold — no file is ever appended to past
541
+ // its seal age, which lets a consolidation safely fold it once aged.
542
+ if (this.streamFileName) {
543
+ const info = parseStreamFileName(this.streamFileName);
544
+ if (info && Date.now() - info.timestamp >= exports.bulkDatabase2Timing.streamSealAgeMs)
545
+ this.streamFileName = undefined;
546
+ }
547
+ if (!this.streamFileName) {
548
+ this.streamFileName = `stream_${Date.now()}_${Math.random().toString(36).slice(2, 10)}${streamLog_1.STREAM_EXTENSION}`;
549
+ }
550
+ return this.streamFileName;
551
+ }
552
+ async foldOwnStream(fileName) {
553
+ const info = parseStreamFileName(fileName);
554
+ if (!info)
555
+ return;
556
+ try {
557
+ await this.mergeFileSet([], [info], false, true);
558
+ }
559
+ catch (e) {
560
+ console.warn(`${this.name}: folding own stream ${fileName} failed: ${e.message}`);
561
+ }
562
+ }
563
+ async update(entry) {
564
+ return this.updateBatch([entry]);
565
+ }
566
+ async updateBatch(entries) {
567
+ if (!entries.length)
568
+ return;
569
+ void this.syncSetup();
570
+ const index = await this.ensureIndex();
571
+ const present = [];
572
+ for (const entry of entries) {
573
+ const overlayEntry = this.reader.overlay.get(entry.key);
574
+ const exists = overlayEntry ? overlayEntry.value !== WriteOverlay_1.DELETED : index.keys.has(entry.key);
575
+ if (!exists) {
576
+ console.warn(`${this.name}.update: key ${JSON.stringify(entry.key)} is not in the collection, ignoring`);
577
+ continue;
578
+ }
579
+ present.push(entry);
580
+ }
581
+ if (present.length)
582
+ await this.writeBatch(present);
583
+ }
584
+ // ── file listings ────────────────────────────────────────────────────────────────────────────────
585
+ async listFiles() {
586
+ const storage = await this.storage();
587
+ const names = await storage.getKeys();
588
+ // A consumed-merge input is hidden from reads the instant its deletion marker exists — that's
589
+ // what stops it from being re-read and re-merged. Physical deletion + marker cleanup runs on a
590
+ // throttle (not inline) so a read isn't slowed by it.
591
+ const markers = await (0, mergeMarkers_1.readDeleteMarkers)(storage, names);
592
+ const excluded = (0, mergeMarkers_1.markerExclusions)(markers);
593
+ if (markers.length)
594
+ void this.processMarkers();
595
+ const bulkFiles = [];
596
+ const streamFiles = [];
597
+ for (const n of names) {
598
+ if (excluded.has(n))
599
+ continue;
600
+ if (n.endsWith(FILE_EXTENSION)) {
601
+ const p = parseFileName(n);
602
+ if (p)
603
+ bulkFiles.push(p);
604
+ }
605
+ else if (n.endsWith(streamLog_1.STREAM_EXTENSION)) {
606
+ const p = parseStreamFileName(n);
607
+ if (p)
608
+ streamFiles.push(p);
609
+ }
610
+ }
611
+ bulkFiles.sort((a, b) => {
612
+ if (a.timestamp !== b.timestamp)
613
+ return b.timestamp - a.timestamp;
614
+ return a.fileName < b.fileName && 1 || a.fileName > b.fileName && -1 || 0;
615
+ });
616
+ (0, misc_1.sort)(streamFiles, f => f.timestamp);
617
+ return { bulkFiles, streamFiles };
618
+ }
619
+ async writeBulkFile(rows) {
620
+ const storage = await this.storage();
621
+ const timestamp = nextFileTime();
622
+ const now = Date.now();
623
+ const times = rows.map(() => now);
624
+ for (const built of (0, BulkDatabaseFormat_1.buildFileBuffer)(rows, times)) {
625
+ const name = newFileName(timestamp);
626
+ await storage.set(name, (0, blockCache_1.encodeCompressedBlocks)(built.buffer));
627
+ }
628
+ await this.triggerRebuild();
629
+ void this.maybeMerge();
630
+ }
631
+ // ── merge policy ─────────────────────────────────────────────────────────────────────────────────
632
+ // Called both periodically (visibility timer) and on writes (with the streamNeedsFold gate so a
633
+ // small write doesn't drag the merge through). The mergeInFlight check in tryMergeNow skips any
634
+ // call that arrives while a previous one is still running — so 5-min timer ticks don't pile up.
635
+ async maybeMerge(opts = {}) {
636
+ if (!await this.automaticCompactionAllowed())
637
+ return;
638
+ if (opts.onlyIfStreamHeavy && !this.streamNeedsFold())
639
+ return;
640
+ try {
641
+ await this.tryMergeThrottled();
642
+ }
643
+ catch (e) {
644
+ console.warn(`${this.name}: background merge failed: ${e.message}`);
645
+ }
646
+ }
647
+ // Build the "we didn't merge" result and log it (throttled — see MERGE_SKIP_LOG_INTERVAL_MS). For
648
+ // lock reasons the log and result include the holder and time until the lock goes stale.
649
+ async mergeSkip(reason) {
650
+ let lock;
651
+ if (reason === "tabLockHeld") {
652
+ lock = (0, mergeLock_1.peekMergeLock)(this.name);
653
+ }
654
+ else if (reason === "fileLockHeld") {
655
+ lock = await (0, mergeLock_1.peekMergeFileLock)(await this.storage());
656
+ }
657
+ if (Date.now() - this.lastMergeSkipLogMs >= MERGE_SKIP_LOG_INTERVAL_MS) {
658
+ this.lastMergeSkipLogMs = Date.now();
659
+ const detail = lock && ` (held by ${lock.holderId}, expires in ${(0, format_1.formatTime)(Math.max(0, lock.expiresInMs))})` || "";
660
+ console.log(`${(0, logColors_1.blue)(this.name)} ${(0, logColors_1.magenta)("merge")} skipped: ${reason}${detail}`);
661
+ }
662
+ return { merged: false, skipReason: reason, lockHolderId: lock === null || lock === void 0 ? void 0 : lock.holderId, lockExpiresInMs: lock === null || lock === void 0 ? void 0 : lock.expiresInMs };
663
+ }
664
+ // Acquire both merge locks (same-tab mergeInFlight, cross-tab localStorage, cross-process file),
665
+ // run the pass, release. Skips (with the reason) instead of waiting when any of them is held.
666
+ async runLockedMerge(run) {
667
+ if (this.mergeInFlight)
668
+ return await this.mergeSkip("mergeInFlight");
669
+ if (!(0, mergeLock_1.tryAcquireMergeLock)(this.name, writerId))
670
+ return await this.mergeSkip("tabLockHeld");
671
+ const storage = await this.storage();
672
+ const haveFileLock = await (0, mergeLock_1.tryAcquireMergeFileLock)(storage, writerId);
673
+ if (!haveFileLock) {
674
+ (0, mergeLock_1.releaseMergeLock)(this.name, writerId);
675
+ return await this.mergeSkip("fileLockHeld");
676
+ }
677
+ this.mergeInFlight = true;
678
+ const stopHeartbeat = (0, mergeLock_1.startMergeFileLockHeartbeat)(storage, writerId);
679
+ try {
680
+ return await run();
681
+ }
682
+ finally {
683
+ stopHeartbeat();
684
+ await (0, mergeLock_1.releaseMergeFileLock)(storage, writerId);
685
+ (0, mergeLock_1.releaseMergeLock)(this.name, writerId);
686
+ this.mergeInFlight = false;
687
+ }
688
+ }
689
+ async tryMergeNow() {
690
+ return await this.runLockedMerge(async () => {
691
+ const merged = await this.testMergeINTERNAL_DO_NOT_CALL();
692
+ return { merged };
693
+ });
694
+ }
695
+ async compact() {
696
+ return await this.runLockedMerge(async () => {
697
+ await this.flushPending();
698
+ (0, syncClient_1.broadcastSeal)(this.name);
699
+ this.streamFileName = undefined;
700
+ const { bulkFiles, streamFiles } = await this.listFiles();
701
+ if (bulkFiles.length + streamFiles.length < 1)
702
+ return await this.mergeSkip("nothingToMerge");
703
+ // compact() folds every file → no older data survives outside it → surviving tombstones
704
+ // can be dropped (nothing left to suppress).
705
+ const merged = await this.mergeFileSet(bulkFiles, streamFiles, true);
706
+ return { merged };
707
+ });
708
+ }
709
+ async merge(timeLo, timeHi) {
710
+ if (timeHi >= Date.now()) {
711
+ (0, syncClient_1.broadcastSeal)(this.name);
712
+ this.streamFileName = undefined;
713
+ }
714
+ const { bulkFiles, streamFiles } = await this.listFiles();
715
+ const headers = await Promise.all(bulkFiles.map(f => this.readBulkHeader(f.fileName)));
716
+ const selBulk = bulkFiles.filter((f, i) => {
717
+ const h = headers[i];
718
+ if (!h)
719
+ return false;
720
+ if (!h.maxTime && !h.minTime)
721
+ return timeLo <= 0;
722
+ return h.minTime <= timeHi && h.maxTime >= timeLo;
723
+ });
724
+ const selStream = streamFiles.filter(f => f.timestamp <= timeHi && f.timestamp + exports.bulkDatabase2Timing.streamSealAgeMs >= timeLo);
725
+ if (selBulk.length + selStream.length < 2)
726
+ return;
727
+ await this.mergeFileSet(selBulk, selStream, timeLo <= 0);
728
+ }
729
+ async readBulkHeader(fileName) {
730
+ try {
731
+ const storage = await this.storage();
732
+ const raw = await (0, LoadedIndex_1.makeRawGetRange)(storage, fileName);
733
+ const fileId = (0, BulkDatabaseReader_1.nullJoin)(this.name, fileName);
734
+ const opened = await blockCache_1.blockCache.open(fileId, raw.size, raw.rawGetRange);
735
+ return await (0, BulkDatabaseFormat_1.loadBulkHeader)(opened.getRange, opened.uncompressedSize);
736
+ }
737
+ catch (_a) {
738
+ return undefined;
739
+ }
740
+ }
741
+ async fileLogicalSize(fileName) {
742
+ try {
743
+ const storage = await this.storage();
744
+ const raw = await (0, LoadedIndex_1.makeRawGetRange)(storage, fileName);
745
+ const fileId = (0, BulkDatabaseReader_1.nullJoin)(this.name, fileName);
746
+ const opened = await blockCache_1.blockCache.open(fileId, raw.size, raw.rawGetRange);
747
+ return opened.uncompressedSize;
748
+ }
749
+ catch (_a) {
750
+ return undefined;
751
+ }
752
+ }
753
+ // A bulk file that won't load is either an in-progress write (recent) or a crashed partial write
754
+ // (stale). Warn while recent, delete once clearly abandoned — deleting is safe because the write
755
+ // protocol always lands the replacement before removing the file it supersedes.
756
+ async handleUnreadableFile(file, message) {
757
+ const ageMs = Date.now() - file.timestamp;
758
+ if (ageMs > STALE_DELETE_MS) {
759
+ console.warn(`${this.name}: deleting stale unreadable bulk file ${file.fileName} (${Math.round(ageMs / 86400000)}d old): ${message}`);
760
+ try {
761
+ const storage = await this.storage();
762
+ await storage.remove(file.fileName);
763
+ }
764
+ catch (removeError) {
765
+ console.warn(`${this.name}: failed to delete ${file.fileName}: ${removeError.message}`);
766
+ }
767
+ return;
768
+ }
769
+ console.warn(`${this.name}: skipping unreadable bulk file ${file.fileName} (recent - may be in-progress): ${message}`);
770
+ }
771
+ async mergeFileSetInner(bulkFiles, streamFiles, includesOldest, forceDeleteStreams) {
772
+ const storage = await this.storage();
773
+ const timestamp = nextFileTime();
774
+ // The caller's bulkFiles came from a `listFiles()` snapshot. Between then and now any file
775
+ // could be gone (another tab's deferred delete, manual cleanup). The subCaches reader for a
776
+ // deleted file is silently stale — its in-memory metadata still resolves, but the very next
777
+ // getRange against disk throws. Re-verify existence up-front and drop the cache entry for
778
+ // anything that vanished, so we don't even try to plan around a ghost file.
779
+ const verifiedBulkFiles = (await Promise.all(bulkFiles.map(async (f) => {
780
+ try {
781
+ const info = await storage.getInfo(f.fileName);
782
+ if (!info) {
783
+ this.subCaches.bulk.delete(f.fileName);
784
+ return undefined;
785
+ }
786
+ return f;
787
+ }
788
+ catch (_a) {
789
+ this.subCaches.bulk.delete(f.fileName);
790
+ return undefined;
791
+ }
792
+ }))).filter((f) => f !== undefined);
793
+ bulkFiles = verifiedBulkFiles;
794
+ const consumedBulk = [];
795
+ const bulkReaders = [];
796
+ await Promise.all(bulkFiles.map(async (f) => {
797
+ try {
798
+ const r = await (0, LoadedIndex_1.loadFileReader)(this.name, storage, f, this.subCaches.bulk);
799
+ bulkReaders.push(r);
800
+ consumedBulk.push(f);
801
+ }
802
+ catch ( /* missing or corrupt — skip; its data lives in another file */_a) { /* missing or corrupt — skip; its data lives in another file */ }
803
+ }));
804
+ const streamData = await (0, LoadedIndex_1.loadStreamEntries)(this.name, storage, streamFiles, this.subCaches.stream);
805
+ const ordered = (0, LoadedIndex_1.orderStreamEntries)(streamData.entries);
806
+ const streamReader = ordered.length ? (0, streamLog_1.streamReaderFromEntries)(ordered, 0).reader : undefined;
807
+ const readers = streamReader ? [streamReader, ...bulkReaders] : bulkReaders;
808
+ const readerNames = streamReader ? ["(streams)", ...consumedBulk.map(f => f.fileName)] : consumedBulk.map(f => f.fileName);
809
+ if (!readers.length)
810
+ return false;
811
+ const inputs = [
812
+ ...await Promise.all(consumedBulk.map(async (f) => { var _a, _b; return ({ name: f.fileName, size: (_b = (_a = (await storage.getInfo(f.fileName).catch(() => undefined))) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0 }); })),
813
+ ...streamFiles.map(f => { var _a; return ({ name: f.fileName, size: (_a = streamData.sizes.get(f.fileName)) !== null && _a !== void 0 ? _a : 0 }); }),
814
+ ];
815
+ const inTotal = inputs.reduce((a, f) => a + f.size, 0);
816
+ const mergeStartMs = Date.now();
817
+ // Collect each step instead of logging it live; emitted at the end as one
818
+ // expanded console.group so a merge takes one collapsible block, not a
819
+ // screenful (and never the per-file name dump it used to spew).
820
+ const steps = [];
821
+ // Each step records the time spent since the previous step in blue at the front, so callers can
822
+ // just describe what they did and not bother measuring/formatting elapsed times themselves.
823
+ let lastStepMs = mergeStartMs;
824
+ const log = (line) => {
825
+ const now = Date.now();
826
+ let lineFormatted = `${(0, logColors_1.blue)((0, format_1.formatTime)(now - lastStepMs))} ${line}`;
827
+ // DO NOT REMOVE THIS LOG! Obviously, we should be logging as we run, or else we don't get progress. Why would we stop getting progress? Progress is almost more important than showing a summary at the end...
828
+ console.log(lineFormatted);
829
+ steps.push(lineFormatted);
830
+ lastStepMs = now;
831
+ };
832
+ log(`${(0, logColors_1.magenta)("read")}: ${inputs.length} input file(s), ${fmtBytes(inTotal)}`);
833
+ const newNames = [];
834
+ const mergeResult = await (0, BulkDatabaseMerge_1.runPlannedMerge)({
835
+ sources: readers,
836
+ sourceNames: readerNames,
837
+ collectionName: this.name,
838
+ log,
839
+ writeFile: async (data) => {
840
+ var _a, _b;
841
+ const fname = newFileName(timestamp);
842
+ await storage.set(fname, (0, blockCache_1.encodeCompressedBlocks)(data));
843
+ newNames.push(fname);
844
+ const size = (_b = (_a = (await storage.getInfo(fname).catch(() => undefined))) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0;
845
+ return { name: fname, size };
846
+ },
847
+ });
848
+ const carriedDeletes = includesOldest ? 0 : mergeResult.carriedDeletes.size;
849
+ const outNames = [...newNames];
850
+ if (carriedDeletes) {
851
+ const carryName = `stream_${Date.now()}_${Math.random().toString(36).slice(2, 10)}${streamLog_1.STREAM_EXTENSION}`;
852
+ await storage.set(carryName, (0, streamLog_1.frameDeletes)([...mergeResult.carriedDeletes].map(([key, time]) => ({ time, key }))));
853
+ outNames.push(carryName);
854
+ }
855
+ const outputs = await Promise.all(outNames.map(async (n) => { var _a, _b; return ({ name: n, size: (_b = (_a = (await storage.getInfo(n).catch(() => undefined))) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0 }); }));
856
+ const outTotal = outputs.reduce((a, f) => a + f.size, 0);
857
+ log(`${(0, logColors_1.magenta)("wrote")}: ${outputs.length} output file(s), ${fmtBytes(outTotal)}${carriedDeletes ? `, ${carriedDeletes} tombstones carried` : ""}`);
858
+ console.group(`${(0, logColors_1.blue)(this.name)} ${(0, logColors_1.magenta)("merge")}: ${fmtBytes(inTotal)} -> ${fmtBytes(outTotal)} (${inputs.length}->${outputs.length} files) in ${(0, format_1.formatTime)(Date.now() - mergeStartMs)}`);
859
+ for (const line of steps)
860
+ console.log(line);
861
+ console.groupEnd();
862
+ // Only the sources runPlannedMerge actually used can be retired — a source it dropped mid-plan
863
+ // (file gone, corruption) still holds data we couldn't merge in, so leave it on disk and let a
864
+ // future merge re-attempt it.
865
+ const usedConsumedBulk = consumedBulk.filter(f => mergeResult.usedSourceNames.has(f.fileName));
866
+ const usedStreamFiles = streamFiles.filter(f => mergeResult.usedSourceNames.has(f.fileName) || mergeResult.usedSourceNames.has("(streams)"));
867
+ // A stream may still be appended to after we read it (the writer hasn't sealed/moved on); only
868
+ // retire streams canDeleteStream clears — the rest stay live and a later merge re-folds them
869
+ // once sealed. Bulk files are immutable, so a used one is always safe to retire.
870
+ const deletableStreams = [];
871
+ for (const f of usedStreamFiles) {
872
+ if (await this.canDeleteStream(f, Date.now(), streamData.sizes, forceDeleteStreams))
873
+ deletableStreams.push(f.fileName);
874
+ }
875
+ const deleteFiles = [...usedConsumedBulk.map(f => f.fileName), ...deletableStreams];
876
+ // Write a deletion marker instead of deleting inline. From the next read on, listFiles hides
877
+ // these inputs (so they're never re-merged — the loop fix), and processMarkers removes them
878
+ // physically once the outputs have landed or the marker ages out. Marker BEFORE the rebuild so
879
+ // the freshly-swapped index already excludes the retired inputs.
880
+ if (deleteFiles.length)
881
+ await (0, mergeMarkers_1.writeDeleteMarker)(storage, { deleteFiles, replacedBy: outNames });
882
+ // Rebuild + swap so the index sees the new outputs and drops the retired inputs. Block-cache
883
+ // eviction for the dropped inputs happens here (they're no longer in the new index's fileSet).
884
+ await this.triggerRebuild();
885
+ return newNames.length > 0 || carriedDeletes > 0;
886
+ }
887
+ // A stream is safe to delete iff no writer will append to it again: it's aged past the seal age
888
+ // (writer has provably switched files) OR cross-tab sync is on AND its size didn't change while
889
+ // we read it. Else leave it — the data is also in the new bulk file; a later merge deletes it
890
+ // once aged.
891
+ async canDeleteStream(f, now, sizes, force = false) {
892
+ if (now - f.timestamp >= exports.bulkDatabase2Timing.streamSealAgeMs)
893
+ return true;
894
+ if (!(0, syncClient_1.isSyncSupported)() && !force)
895
+ return false;
896
+ const readSize = sizes.get(f.fileName);
897
+ if (readSize === undefined)
898
+ return false;
899
+ let info;
900
+ try {
901
+ info = await (await this.storage()).getInfo(f.fileName);
902
+ }
903
+ catch (_a) {
904
+ return false;
905
+ }
906
+ return !!info && info.size === readSize;
907
+ }
908
+ async mergeSpacingDelay() {
909
+ const total = exports.bulkDatabase2Timing.mergeSpacingMs;
910
+ if (total <= 0)
911
+ return (0, mergeLock_1.tryAcquireMergeLock)(this.name, writerId);
912
+ const step = 15 * 1000;
913
+ let waited = 0;
914
+ while (waited < total) {
915
+ await new Promise(r => setTimeout(r, Math.min(step, total - waited)));
916
+ waited += step;
917
+ if (!(0, mergeLock_1.tryAcquireMergeLock)(this.name, writerId))
918
+ return false;
919
+ }
920
+ return true;
921
+ }
922
+ // The merge policy (two passes, spaced by mergeSpacingMs):
923
+ // 1) Consolidate recent fragmentation: take newest files up to ~FIRST_MERGE_BYTES; merge them
924
+ // into one when they fragment or span too wide a time range.
925
+ // 2) Key-stratify: walk all keys in ~KEY_GROUP_BYTES groups; rewrite groups whose duplicate-key
926
+ // fraction passes DUP_THRESHOLD, highest first.
927
+ // Use tryMerge instead
928
+ async testMergeINTERNAL_DO_NOT_CALL() {
929
+ var _a;
930
+ let merged = false;
931
+ await this.flushPending();
932
+ const runMerge = async (bulk, stream) => {
933
+ if (merged && !await this.mergeSpacingDelay())
934
+ return false;
935
+ if (await this.mergeFileSet(bulk, stream))
936
+ merged = true;
937
+ return true;
938
+ };
939
+ // Hard stream limit: a stream this big makes every read pull a huge file → fold ALL of it now,
940
+ // force-delete (canDeleteStream still requires size-stable, so an active writer never loses data).
941
+ {
942
+ const { streamFiles } = await this.listFiles();
943
+ if (streamFiles.length) {
944
+ const storage = await this.storage();
945
+ const sizes = await Promise.all(streamFiles.map(async (f) => { var _a, _b; try {
946
+ return (_b = (_a = (await storage.getInfo(f.fileName))) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0;
947
+ }
948
+ catch (_c) {
949
+ return 0;
950
+ } }));
951
+ const totalStreamBytes = sizes.reduce((a, b) => a + b, 0);
952
+ if (totalStreamBytes > exports.bulkDatabase2Timing.streamFoldHardLimitBytes) {
953
+ console.log(`${(0, logColors_1.blue)(this.name)} ${(0, logColors_1.magenta)("fold")} stream tier ${fmtBytes(totalStreamBytes)} over hard limit ${fmtBytes(exports.bulkDatabase2Timing.streamFoldHardLimitBytes)} - folding all streams now`);
954
+ if (await this.mergeFileSet([], streamFiles, false, true))
955
+ merged = true;
956
+ }
957
+ }
958
+ }
959
+ // Pass 1: consolidate recent. Only seal when cross-tab sync can fold recent streams — in Node
960
+ // canDeleteStream needs them aged anyway, so sealing would just fragment streams every pass.
961
+ const foldRecentStreams = (0, syncClient_1.isSyncSupported)();
962
+ if (foldRecentStreams) {
963
+ (0, syncClient_1.broadcastSeal)(this.name);
964
+ this.streamFileName = undefined;
965
+ }
966
+ {
967
+ const { bulkFiles, streamFiles } = await this.listFiles();
968
+ const bulkMeta = await Promise.all(bulkFiles.map(async (f) => {
969
+ const [size, header] = await Promise.all([this.fileLogicalSize(f.fileName), this.readBulkHeader(f.fileName)]);
970
+ return { kind: "bulk", file: f, bytes: size !== null && size !== void 0 ? size : 0, time: (header === null || header === void 0 ? void 0 : header.maxTime) || f.timestamp };
971
+ }));
972
+ const streamMeta = [];
973
+ for (const f of streamFiles) {
974
+ const aged = Date.now() - f.timestamp >= exports.bulkDatabase2Timing.streamSealAgeMs;
975
+ if (!foldRecentStreams && !aged)
976
+ continue;
977
+ let bytes = 0;
978
+ try {
979
+ const info = await (await this.storage()).getInfo(f.fileName);
980
+ bytes = (_a = info === null || info === void 0 ? void 0 : info.size) !== null && _a !== void 0 ? _a : 0;
981
+ }
982
+ catch (_b) {
983
+ bytes = 0;
984
+ }
985
+ streamMeta.push({ kind: "stream", file: f, bytes, time: f.timestamp });
986
+ }
987
+ const items = [...bulkMeta, ...streamMeta].sort((a, b) => b.time - a.time);
988
+ const recent = [];
989
+ let recentBytes = 0;
990
+ for (const it of items) {
991
+ recent.push(it);
992
+ recentBytes += it.bytes;
993
+ if (recentBytes >= FIRST_MERGE_BYTES)
994
+ break;
995
+ }
996
+ const span = recent.length ? recent[0].time - recent[recent.length - 1].time : 0;
997
+ const recentStreamBytes = recent.reduce((a, it) => a + (it.kind === "stream" ? it.bytes : 0), 0);
998
+ const heavyStream = recentStreamBytes > exports.bulkDatabase2Timing.streamFoldTriggerBytes;
999
+ const triggered = recent.length >= 2 && (recent.length > exports.bulkDatabase2Timing.firstMergeTriggerFiles || span > exports.bulkDatabase2Timing.firstMergeTriggerRangeMs)
1000
+ || heavyStream;
1001
+ if (triggered) {
1002
+ const rb = recent.filter(i => i.kind === "bulk").map(i => i.file);
1003
+ const rs = recent.filter(i => i.kind === "stream").map(i => i.file);
1004
+ if (!await runMerge(rb, rs))
1005
+ return merged;
1006
+ }
1007
+ }
1008
+ // Whole-tier dedup short-circuit (between Pass 1 and the per-group Pass 2): when the bulk tier
1009
+ // is big enough AND mostly duplicates, fold every bulk file in one merge. Avoids the per-group
1010
+ // walk's 5-min spacing × N-groups latency.
1011
+ {
1012
+ const { bulkFiles } = await this.listFiles();
1013
+ if (bulkFiles.length >= 2) {
1014
+ const storage = await this.storage();
1015
+ let totalBytes = 0;
1016
+ let totalSlots = 0;
1017
+ const uniqueKeys = new Set();
1018
+ for (const f of bulkFiles) {
1019
+ try {
1020
+ const reader = await (0, LoadedIndex_1.loadFileReader)(this.name, storage, f, this.subCaches.bulk);
1021
+ totalBytes += reader.totalBytes;
1022
+ totalSlots += reader.keys.length;
1023
+ for (const k of reader.keys)
1024
+ uniqueKeys.add(k);
1025
+ }
1026
+ catch ( /* skip unreadable */_c) { /* skip unreadable */ }
1027
+ }
1028
+ const dupFraction = totalSlots ? (totalSlots - uniqueKeys.size) / totalSlots : 0;
1029
+ if (totalBytes > DEDUP_TRIGGER_BYTES && dupFraction > DEDUP_TRIGGER_FRACTION) {
1030
+ console.log(`${(0, logColors_1.blue)(this.name)} ${(0, logColors_1.magenta)("dedup")}: ${fmtBytes(totalBytes)} across ${bulkFiles.length} bulk file(s), ${Math.round(dupFraction * 100)}% duplicate key-slots - folding all at once`);
1031
+ if (!await runMerge(bulkFiles, []))
1032
+ return merged;
1033
+ return merged;
1034
+ }
1035
+ }
1036
+ }
1037
+ // Pass 2: key-stratified deduplication. Disjoint key ranges → one group's merge doesn't
1038
+ // change another's duplication; re-select each group's files at merge time (set shifts).
1039
+ const groups = await this.findDuplicateGroups();
1040
+ for (const g of groups) {
1041
+ const { bulkFiles } = await this.listFiles();
1042
+ const headers = await Promise.all(bulkFiles.map(f => this.readBulkHeader(f.fileName)));
1043
+ const groupFiles = bulkFiles.filter((f, i) => {
1044
+ const h = headers[i];
1045
+ if (!h)
1046
+ return false;
1047
+ if (h.minKey === undefined || h.maxKey === undefined)
1048
+ return true;
1049
+ return h.minKey <= g.hi && h.maxKey >= g.lo;
1050
+ });
1051
+ if (groupFiles.length >= 2) {
1052
+ if (!await runMerge(groupFiles, []))
1053
+ return merged;
1054
+ }
1055
+ }
1056
+ return merged;
1057
+ }
1058
+ async findDuplicateGroups() {
1059
+ var _a;
1060
+ const { bulkFiles } = await this.listFiles();
1061
+ if (bulkFiles.length < 2)
1062
+ return [];
1063
+ const storage = await this.storage();
1064
+ const infos = await Promise.all(bulkFiles.map(async (f) => {
1065
+ try {
1066
+ const reader = await (0, LoadedIndex_1.loadFileReader)(this.name, storage, f, this.subCaches.bulk);
1067
+ return { keys: reader.keys, bytes: reader.totalBytes };
1068
+ }
1069
+ catch (_a) {
1070
+ return { keys: [], bytes: 0 };
1071
+ }
1072
+ }));
1073
+ const keyCount = new Map();
1074
+ let totalSlots = 0, totalBytes = 0;
1075
+ for (const i of infos) {
1076
+ totalBytes += i.bytes;
1077
+ for (const k of i.keys) {
1078
+ keyCount.set(k, (keyCount.get(k) || 0) + 1);
1079
+ totalSlots++;
1080
+ }
1081
+ }
1082
+ if (totalSlots === 0)
1083
+ return [];
1084
+ const bytesPerSlot = totalBytes / totalSlots;
1085
+ const sortedKeys = [...keyCount.keys()].sort();
1086
+ const groups = [];
1087
+ let gStart = 0, gBytes = 0, gSlots = 0, gUnique = 0;
1088
+ for (let i = 0; i < sortedKeys.length; i++) {
1089
+ const c = (_a = keyCount.get(sortedKeys[i])) !== null && _a !== void 0 ? _a : 0;
1090
+ gBytes += c * bytesPerSlot;
1091
+ gSlots += c;
1092
+ gUnique += 1;
1093
+ if (gBytes >= KEY_GROUP_BYTES || i === sortedKeys.length - 1) {
1094
+ const dup = (gSlots - gUnique) / gSlots;
1095
+ if (dup > DUP_THRESHOLD)
1096
+ groups.push({ lo: sortedKeys[gStart], hi: sortedKeys[i], dup });
1097
+ gStart = i + 1;
1098
+ gBytes = 0;
1099
+ gSlots = 0;
1100
+ gUnique = 0;
1101
+ }
1102
+ }
1103
+ groups.sort((a, b) => b.dup - a.dup);
1104
+ return groups;
1105
+ }
1106
+ // ── reads — forwarded to BulkDatabaseReader, with rebuild-on-missing retry ───────────────────────
1107
+ async getSingleField(key, column) {
1108
+ void this.syncSetup();
1109
+ return this.readWithRetry(() => this.reader.getSingleField(key, column));
1110
+ }
1111
+ async getSingleFieldObj(key, column) {
1112
+ void this.syncSetup();
1113
+ return this.readWithRetry(() => this.reader.getSingleFieldObj(key, column));
1114
+ }
1115
+ async getColumn(column) {
1116
+ void this.syncSetup();
1117
+ return this.readWithRetry(() => this.reader.getColumn(column));
1118
+ }
1119
+ async getKeys() {
1120
+ void this.syncSetup();
1121
+ return this.readWithRetry(() => this.reader.getKeys());
1122
+ }
1123
+ getSingleFieldSync(key, column) {
1124
+ void this.syncSetup();
1125
+ return this.reader.getSingleFieldSync(key, column);
1126
+ }
1127
+ getSingleFieldObjSync(key, column) {
1128
+ void this.syncSetup();
1129
+ return this.reader.getSingleFieldObjSync(key, column);
1130
+ }
1131
+ getColumnSync(column) {
1132
+ void this.syncSetup();
1133
+ return this.reader.getColumnSync(column);
1134
+ }
1135
+ isFieldLoadedSync(key, column) {
1136
+ void this.syncSetup();
1137
+ return this.reader.isFieldLoadedSync(key, column);
1138
+ }
1139
+ isColumnLoadedSync(column) {
1140
+ void this.syncSetup();
1141
+ return this.reader.isColumnLoadedSync(column);
1142
+ }
1143
+ // Reactive: true while a merge is rewriting this collection's files. Use this in UI to show a
1144
+ // "compacting…" indicator. Counts both background merges (maybeMerge) and explicit compact/merge
1145
+ // calls. Becomes false once the new index is swapped in (the deferred-delete window is NOT counted).
1146
+ isCompactingSync() {
1147
+ return this.reader.isCompactingSync();
1148
+ }
1149
+ async getColumnInfo() {
1150
+ const index = await this.ensureIndex();
1151
+ return index.reader.columns;
1152
+ }
1153
+ async getKeyStats() {
1154
+ const index = await this.ensureIndex();
1155
+ const rawKeys = index.reader.rawKeyCount;
1156
+ const finalKeys = index.reader.keys.length;
1157
+ return {
1158
+ rawKeys,
1159
+ finalKeys,
1160
+ wastedKeys: rawKeys - finalKeys,
1161
+ duplication: finalKeys ? rawKeys / finalKeys : 0,
1162
+ readers: index.reader.readerCount,
1163
+ };
1164
+ }
1165
+ async getReaderInfo() {
1166
+ const index = await this.ensureIndex();
1167
+ return {
1168
+ rowCount: index.reader.rowCount,
1169
+ totalBytes: index.reader.totalBytes,
1170
+ keyCount: index.reader.keys.length,
1171
+ sampleKey: index.reader.keys[0],
1172
+ columns: index.reader.columns,
1173
+ };
1174
+ }
1175
+ async getFileInfo() {
1176
+ const { bulkFiles, streamFiles } = await this.listFiles();
1177
+ const storage = await this.storage();
1178
+ const statOf = async (name) => {
1179
+ var _a, _b;
1180
+ try {
1181
+ const info = await storage.getInfo(name);
1182
+ return { bytes: (_a = info === null || info === void 0 ? void 0 : info.size) !== null && _a !== void 0 ? _a : 0, lastModified: (_b = info === null || info === void 0 ? void 0 : info.lastModified) !== null && _b !== void 0 ? _b : 0 };
1183
+ }
1184
+ catch (_c) {
1185
+ return { bytes: 0, lastModified: 0 };
1186
+ }
1187
+ };
1188
+ const bulkInfos = await Promise.all(bulkFiles.map(async (f) => {
1189
+ const stat = await statOf(f.fileName);
1190
+ return {
1191
+ name: f.fileName,
1192
+ type: "bulk",
1193
+ bytes: stat.bytes,
1194
+ lastModified: stat.lastModified,
1195
+ getDetails: async () => {
1196
+ // Bulk: reader has keys + per-row keyTimes + header minTime/maxTime. Cached, so cheap.
1197
+ const reader = await (0, LoadedIndex_1.loadFileReader)(this.name, storage, f, this.subCaches.bulk);
1198
+ return { keys: reader.keys, minTime: reader.minTime, maxTime: reader.maxTime };
1199
+ },
1200
+ };
1201
+ }));
1202
+ const streamInfos = await Promise.all(streamFiles.map(async (f) => {
1203
+ const stat = await statOf(f.fileName);
1204
+ return {
1205
+ name: f.fileName,
1206
+ type: "stream",
1207
+ bytes: stat.bytes,
1208
+ lastModified: stat.lastModified,
1209
+ getDetails: async () => {
1210
+ // Stream: must parse the file to walk every entry — header has no key/time bounds. Cached.
1211
+ const data = await (0, LoadedIndex_1.loadStreamEntries)(this.name, storage, [f], this.subCaches.stream);
1212
+ const keys = new Set();
1213
+ let minTime = Infinity, maxTime = -Infinity;
1214
+ for (const e of data.entries) {
1215
+ if (e.time < minTime)
1216
+ minTime = e.time;
1217
+ if (e.time > maxTime)
1218
+ maxTime = e.time;
1219
+ if (e.entry.row)
1220
+ keys.add(e.entry.row.key);
1221
+ else if (e.entry.deletedKey !== undefined)
1222
+ keys.add(e.entry.deletedKey);
1223
+ }
1224
+ return {
1225
+ keys: [...keys],
1226
+ minTime: minTime === Infinity ? 0 : minTime,
1227
+ maxTime: maxTime === -Infinity ? 0 : maxTime,
1228
+ };
1229
+ },
1230
+ };
1231
+ }));
1232
+ const files = [...bulkInfos, ...streamInfos];
1233
+ return { files, count: files.length, totalBytes: files.reduce((a, f) => a + f.bytes, 0) };
1234
+ }
1235
+ }
1236
+ exports.BulkDatabaseBase = BulkDatabaseBase;
1237
+ // ── memory-pressure watchdog (global, browser-only) ──
1238
+ BulkDatabaseBase.liveInstances = new Set();
1239
+ BulkDatabaseBase.memoryWatchdogStarted = false;
1240
+ BulkDatabaseBase.lastMemoryFlushMs = 0;
1241
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnVsa0RhdGFiYXNlQmFzZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIkJ1bGtEYXRhYmFzZUJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbURBQWtFO0FBQ2xFLDJEQUEyRDtBQUMzRCxtREFBeUQ7QUFDekQseURBQW1EO0FBQ25ELDZDQUFxQztBQUVyQyw2REFNOEI7QUFDOUIsMkRBQXNEO0FBQ3RELDZDQUFrRTtBQUNsRSxrRUFBaUY7QUFDakYsd0VBQXlFO0FBQ3pFLDJDQUFpRztBQUNqRyw2Q0FBb0o7QUFDcEosaURBQXlDO0FBQ3pDLDJDQUFpTTtBQUNqTSxpREFBOEc7QUFDOUcsK0NBVXVCO0FBQ3ZCLDZEQUFvRTtBQUV2RCxRQUFBLGdCQUFnQixHQUFHLGdCQUFnQixDQUFDO0FBQ2pELE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQztBQUMvQixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUM7QUFDM0IsTUFBTSxjQUFjLEdBQUcsQ0FBQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDdkMsTUFBTSwyQkFBMkIsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQzlDLE1BQU0sZUFBZSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUM1QyxNQUFNLHlCQUF5QixHQUFHLENBQUMsQ0FBQztBQUNwQyxNQUFNLGlCQUFpQixHQUFHLHNDQUFpQixHQUFHLENBQUMsQ0FBQztBQUNoRCxNQUFNLGVBQWUsR0FBRyxHQUFHLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUMxQyxNQUFNLGFBQWEsR0FBRyxHQUFHLENBQUM7QUFDMUIsc0dBQXNHO0FBQ3RHLG9HQUFvRztBQUNwRyw4RUFBOEU7QUFDOUUsTUFBTSxtQkFBbUIsR0FBRyxHQUFHLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUM5QyxNQUFNLHNCQUFzQixHQUFHLEdBQUcsQ0FBQztBQUNuQyxNQUFNLHlCQUF5QixHQUFHLEdB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bXBvcnQgeyBzb3J0LCB0aHJvdHRsZUZ1bmN0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgcnVuSW5TZXJpYWwgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9iYXRjaGluZ1wiO1xuaW1wb3J0IHsgZ2V0VGltZVVuaXF1ZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2JpdHNcIjtcbmltcG9ydCB7IGxhenkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9jYWNoaW5nXCI7XG5pbXBvcnQgeyBpc05vZGUgfSBmcm9tIFwidHlwZXNhZmVjc3NcIjtcbmltcG9ydCB0eXBlIHsgRmlsZVN0b3JhZ2UgfSBmcm9tIFwiLi4vRmlsZUZvbGRlckFQSVwiO1xuaW1wb3J0IHtcbiAgICBCYXNlQnVsa0RhdGFiYXNlUmVhZGVyLFxuICAgIEJ1bGtIZWFkZXJJbmZvLFxuICAgIGJ1aWxkRmlsZUJ1ZmZlcixcbiAgICBsb2FkQnVsa0hlYWRlcixcbiAgICBUQVJHRVRfRklMRV9CWVRFUyxcbn0gZnJvbSBcIi4vQnVsa0RhdGFiYXNlRm9ybWF0XCI7XG5pbXBvcnQgeyBydW5QbGFubmVkTWVyZ2UgfSBmcm9tIFwiLi9CdWxrRGF0YWJhc2VNZXJnZVwiO1xuaW1wb3J0IHsgYmxvY2tDYWNoZSwgZW5jb2RlQ29tcHJlc3NlZEJsb2NrcyB9IGZyb20gXCIuL2Jsb2NrQ2FjaGVcIjtcbmltcG9ydCB7IGZvcm1hdE51bWJlciwgZm9ybWF0VGltZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2Zvcm1hdHRpbmcvZm9ybWF0XCI7XG5pbXBvcnQgeyBibHVlLCBtYWdlbnRhIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvZm9ybWF0dGluZy9sb2dDb2xvcnNcIjtcbmltcG9ydCB7IFNUUkVBTV9FWFRFTlNJT04sIGZyYW1lRGVsZXRlcywgZnJhbWVSb3dzLCBzdHJlYW1SZWFkZXJGcm9tRW50cmllcyB9IGZyb20gXCIuL3N0cmVhbUxvZ1wiO1xuaW1wb3J0IHsgYnJvYWRjYXN0IGFzIHN5bmNCcm9hZGNhc3QsIGJyb2FkY2FzdFNlYWwgYXMgc3luY0Jyb2FkY2FzdFNlYWwsIGNvbm5lY3QgYXMgc3luY0Nvbm5lY3QsIGlzU3luY1N1cHBvcnRlZCwgUmVtb3RlV3JpdGUgfSBmcm9tIFwiLi9zeW5jQ2xpZW50XCI7XG5pbXBvcnQgeyBERUxFVEVEIH0gZnJvbSBcIi4vV3JpdGVPdmVybGF5XCI7XG5pbXBvcnQgeyBNZXJnZUxvY2tJbmZvLCBwZWVrTWVyZ2VGaWxlTG9jaywgcGVla01lcmdlTG9jaywgcmVsZWFzZU1lcmdlRmlsZUxvY2ssIHJlbGVhc2VNZXJnZUxvY2ssIHN0YXJ0TWVyZ2VGaWxlTG9ja0hlYXJ0YmVhdCwgdHJ5QWNxdWlyZU1lcmdlRmlsZUxvY2ssIHRyeUFjcXVpcmVNZXJnZUxvY2sgfSBmcm9tIFwiLi9tZXJnZUxvY2tcIjtcbmltcG9ydCB7IG1hcmtlckV4Y2x1c2lvbnMsIHByb2Nlc3NEZWxldGVNYXJrZXJzLCByZWFkRGVsZXRlTWFya2Vycywgd3JpdGVEZWxldGVNYXJrZXIgfSBmcm9tIFwiLi9tZXJnZU1hcmtlcnNcIjtcbmltcG9ydCB7XG4gICAgQnVsa0ZpbGVJbmZvLFxuICAgIExvYWRlZEluZGV4LFxuICAgIGxvYWRGaWxlUmVhZGVyLFxuICAgIGxvYWRTdHJlYW1FbnRyaWVzLFxuICAgIG1ha2VSYXdHZXRSYW5nZSxcbiAgICBNaXNzaW5nRmlsZUVycm9yLFxuICAgIG9yZGVyU3RyZWFtRW50cmllcyxcbiAgICBTdHJlYW1GaWxlSW5mbyxcbiAgICBTdWJSZWFkZXJDYWNoZXMsXG59IGZyb20gXCIuL0xvYWRlZEluZGV4XCI7XG5pbXBvcnQgeyBCdWxrRGF0YWJhc2VSZWFkZXIsIG51bGxKb2luIH0gZnJvbSBcIi4vQnVsa0RhdGFiYXNlUmVhZGVyXCI7XG5cbmV4cG9ydCBjb25zdCBCVUxLX1JPT1RfRk9MREVSID0gXCJidWxrRGF0YWJhc2VzMlwiO1xuY29uc3QgRklMRV9FWFRFTlNJT04gPSBcIi5idWxrXCI7XG5jb25zdCBST0xMT1ZFUl9ST1dTID0gNTAwMDtcbmNvbnN0IFJPTExPVkVSX0JZVEVTID0gNSAqIDEwMjQgKiAxMDI0O1xuY29uc3QgTUVNT1JZX1dBVENIRE9HX0lOVEVSVkFMX01TID0gNjAgKiAxMDAwO1xuY29uc3QgU1RBTEVfREVMRVRFX01TID0gMjQgKiA2MCAqIDYwICogMTAwMDtcbmNvbnN0IE1BWF9JTkRFWF9SRUxPQURfQVRURU1QVFMgPSAzO1xuY29uc3QgRklSU1RfTUVSR0VfQllURVMgPSBUQVJHRVRfRklMRV9CWVRFUyAvIDI7XG5jb25zdCBLRVlfR1JPVVBfQllURVMgPSA4MDAgKiAxMDI0ICogMTAyNDtcbmNvbnN0IERVUF9USFJFU0hPTEQgPSAwLjQ7XG4vLyBXaG9sZS10aWVyIGRlZHVwIHNob3J0LWNpcmN1aXQgKGFmdGVyIFBhc3MgMSk6IHdoZW4gdGhlIGJ1bGsgdGllciBpcyBvdmVyIHRoaXMgc2l6ZSBBTkQgdGhlIG92ZXJhbGxcbi8vIGtleSBkdXBsaWNhdGlvbiBmcmFjdGlvbiBpcyBvdmVyIHRoaXMgdGhyZXNob2xkLCBmb2xkIGV2ZXJ5IGJ1bGsgZmlsZSBpbiBvbmUgbWVyZ2UgaW5zdGVhZCBvZiB0aGVcbi8vIHBlci1rZXktZ3JvdXAgd2FsayAod2hpY2ggc3BhY2VzIG1lcmdlcyA1IG1pbiBhcGFydCDigJQgMTYgaCBmb3IgMjAwIGdyb3VwcykuXG5jb25zdCBERURVUF9UUklHR0VSX0JZVEVTID0gNTEyICogMTAyNCAqIDEwMjQ7XG5jb25zdCBERURVUF9UUklHR0VSX0ZSQUNUSU9OID0gMC41O1xuY29uc3QgV1JJVEVfRkxVU0hfRklSU1RfU1RFUF9NUyA9IDI1MDtcbi8vIFNraXAgbG9ncyBhcmUgdGhyb3R0bGVkIHBlciBjb2xsZWN0aW9uOiB0aGUgYmFja2dyb3VuZCB3cml0ZSBwYXRoIHJldHJpZXMgbWVyZ2VzIGFib3V0IG9uY2UgYSBzZWNvbmQsXG4vLyBzbyBhbiB1bnRocm90dGxlZCBsb2cgd291bGQgcmVwZWF0IGZvciB0aGUgd2hvbGUgZHVyYXRpb24gb2YgYW5vdGhlciB0YWIncyBtZXJnZS5cbmNvbnN0IE1FUkdFX1NLSVBfTE9HX0lOVEVSVkFMX01TID0gMzAgKiAxMDAwO1xuXG5leHBvcnQgY29uc3QgYnVsa0RhdGFiYXNlMlRpbWluZyA9IHtcbiAgICBzdHJlYW1TZWFsQWdlTXM6IDEwICogNjAgKiA2MCAqIDEwMDAsXG4gICAgLy8gV2FpdCB0aGlzIGxvbmcgYWZ0ZXIgdGhlIHRhYiBiZWNvbWVzIHZpc2libGUgYmVmb3JlIHRoZSBmaXJzdCBtZXJnZSBjaGVjaywgdGhlbiBjaGVjayB0aGlzIG9mdGVuXG4gICAgLy8gYWZ0ZXJ3YXJkcy4gVGFiIGJlaW5nIGhpZGRlbiBjYW5jZWxzIHRoZSB0aW1lcnMgKG5vIG1lcmdlcyB3aGlsZSBpbiBiYWNrZ3JvdW5kKS4gQnJvd3Nlci1vbmx5O1xuICAgIC8vIE5vZGUgY29tcGFjdG9ycyAoZS5nLiByZW1vdGVGaWxlU2VydmVyKSBkcml2ZSB0aGVpciBvd24gcG9sbGluZy5cbiAgICB2aXNpYmxlTWVyZ2VJbnRlcnZhbE1zOiA1ICogNjAgKiAxMDAwLFxuICAgIG1lcmdlU3BhY2luZ01zOiA1ICogNjAgKiAxMDAwLFxuICAgIGZpcnN0TWVyZ2VUcmlnZ2VyRmlsZXM6IDIwLFxuICAgIGZpcnN0TWVyZ2VUcmlnZ2VyUmFuZ2VNczogMyAqIDI0ICogNjAgKiA2MCAqIDEwMDAsXG4gICAgc3RyZWFtRm9sZFRyaWdnZXJSb3dzOiAxMDAsXG4gICAgc3RyZWFtRm9sZFRyaWdnZXJCeXRlczogNjQgKiAxMDI0ICogMTAyNCxcbiAgICBzdHJlYW1GaWxlTWF4Qnl0ZXM6IDUwICogMTAyNCAqIDEwMjQsXG4gICAgc3RyZWFtRm9sZEhhcmRMaW1pdEJ5dGVzOiA3NjggKiAxMDI0ICogMTAyNCxcbiAgICAvLyAwID0gZmx1c2ggZXZlcnkgd3JpdGUgKE5vZGUg4oCUIGFwcGVuZCBpcyByZWFsIGFuZCBjaGVhcCk7IGJyb3dzZXIgcmFtcHMgdG8gMTVzIHRvIGF2b2lkIHJld3JpdGluZ1xuICAgIC8vIHRoZSB3aG9sZSBzdHJlYW0gZmlsZSBwZXIgd3JpdGUuXG4gICAgd3JpdGVGbHVzaE1heERlbGF5TXM6IGlzTm9kZSgpID8gMCA6IDE1ICogMTAwMCxcbiAgICBmaWxlU2V0UG9sbEludGVydmFsTXM6IDMwICogNjAgKiAxMDAwLFxuICAgIG1lbW9yeUZsdXNoSGVhcEJ5dGVzOiA1ICogMTAyNCAqIDEwMjQgKiAxMDI0LFxuICAgIG1lbW9yeUZsdXNoTWluQ29sbGVjdGlvbkJ5dGVzOiAxMDAgKiAxMDI0ICogMTAyNCxcbiAgICBtZW1vcnlGbHVzaFRocm90dGxlTXM6IDE1ICogNjAgKiAxMDAwLFxufTtcblxuZnVuY3Rpb24gZm10Qnl0ZXMobjogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBpZiAobiA8IDEwMjQpIHJldHVybiBuICsgXCJCXCI7XG4gICAgaWYgKG4gPCAxMDI0ICogMTAyNCkgcmV0dXJuIChuIC8gMTAyNCkudG9GaXhlZCgxKSArIFwiS0JcIjtcbiAgICBpZiAobiA8IDEwMjQgKiAxMDI0ICogMTAyNCkgcmV0dXJuIChuIC8gMTAyNCAvIDEwMjQpLnRvRml4ZWQoMSkgKyBcIk1CXCI7XG4gICAgcmV0dXJuIChuIC8gMTAyNCAvIDEwMjQgLyAxMDI0KS50b0ZpeGVkKDIpICsgXCJHQlwiO1xufVxuXG4vLyBSZWFjdGl2aXR5IHNlYW0gKG5vIG1vYnggZGVwZW5kZW5jeSBpbiB0aGlzIGZpbGUpLiBUaGUgbW9ieCBzdWJjbGFzcyBzdXBwbGllcyBhIFJlYWN0aXZlRGVwcyB0aGF0XG4vLyBtYXBzIHNpZ25hbCBzdHJpbmdzIHRvIGl0cyBvd24gZGVwZW5kZW5jeSB0cmFja2luZzsgbm9uLXJlYWN0aXZlIGNhbGxlcnMgcGFzcyBub29wUmVhY3RpdmVEZXBzLlxuZXhwb3J0IGludGVyZmFjZSBSZWFjdGl2ZURlcHMge1xuICAgIG9ic2VydmUoc2lnbmFsOiBzdHJpbmcpOiB2b2lkO1xuICAgIGludmFsaWRhdGUoc2lnbmFsOiBzdHJpbmcpOiB2b2lkO1xuICAgIGJhdGNoKGZuOiAoKSA9PiB2b2lkKTogdm9pZDtcbiAgICAvLyBPcHRpb25hbCDigJQgbGV0cyB3cml0ZXMgc2tpcCBwZXIta2V5IGludmFsaWRhdGlvbiBmb3Igcm93cyBub3RoaW5nIGlzIHdhdGNoaW5nLiBVbmRlZmluZWQgPVxuICAgIC8vIFwiYXNzdW1lIHdhdGNoZWRcIi5cbiAgICBpc09ic2VydmVkPyhzaWduYWw6IHN0cmluZyk6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjb25zdCBub29wUmVhY3RpdmVEZXBzOiBSZWFjdGl2ZURlcHMgPSB7XG4gICAgb2JzZXJ2ZSgpIHsgfSxcbiAgICBpbnZhbGlkYXRlKCkgeyB9LFxuICAgIGJhdGNoKGZuKSB7IGZuKCk7IH0sXG4gICAgaXNPYnNlcnZlZCgpIHsgcmV0dXJuIGZhbHNlOyB9LFxufTtcblxuZXhwb3J0IHR5cGUgU3RvcmFnZUZhY3RvcnkgPSAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPEZpbGVTdG9yYWdlPjtcblxuZXhwb3J0IHR5cGUgQnVsa0RhdGFiYXNlMkNvbmZpZyA9IHtcbiAgICAvLyBTZWUgQnVsa0RhdGFiYXNlUmVhZGVyLmNmZy5tYXhUcmlnZ2VyVGhyb3R0bGVNcy5cbiAgICBtYXhUcmlnZ2VyVGhyb3R0bGVNcz86IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIE1lcmdlU2tpcFJlYXNvbiA9XG4gICAgLy8gVGhpcyBpbnN0YW5jZSBpcyBhbHJlYWR5IG1pZC1tZXJnZS5cbiAgICB8IFwibWVyZ2VJbkZsaWdodFwiXG4gICAgLy8gQW5vdGhlciBzYW1lLW9yaWdpbiB0YWIgaG9sZHMgdGhlIGxvY2FsU3RvcmFnZSBtZXJnZSBsb2NrLlxuICAgIHwgXCJ0YWJMb2NrSGVsZFwiXG4gICAgLy8gQW5vdGhlciBwcm9jZXNzIGhvbGRzIHRoZSBjcm9zcy1wcm9jZXNzIC5tZXJnZS1sb2NrIGZpbGUgKG9yIHdvbiB0aGUgc2V0dGxlIHJhY2UgZm9yIGl0KS5cbiAgICB8IFwiZmlsZUxvY2tIZWxkXCJcbiAgICAvLyBjb21wYWN0KCkgb25seTogdGhlIGNvbGxlY3Rpb24gaGFzIG5vIGZpbGVzIG9uIGRpc2suXG4gICAgfCBcIm5vdGhpbmdUb01lcmdlXCI7XG5cbi8vIFdoYXQgYSBjb21wYWN0KCkvdHJ5TWVyZ2VOb3coKSBjYWxsIGRpZC4gc2tpcFJlYXNvbiBpcyBzZXQgd2hlbiB0aGUgcGFzcyBuZXZlciByYW47IGZvciB0aGUgbG9ja1xuLy8gcmVhc29ucywgbG9ja0hvbGRlcklkL2xvY2tFeHBpcmVzSW5NcyByZXBvcnQgd2hvIGhvbGRzIHRoZSBsb2NrIGFuZCBob3cgbG9uZyB1bnRpbCBpdCBnb2VzIHN0YWxlXG4vLyAoc28gYSBzY2hlZHVsZXIga25vd3Mgd2hlbiByZXRyeWluZyBjb3VsZCBzdWNjZWVkKS5cbmV4cG9ydCB0eXBlIE1lcmdlQXR0ZW1wdFJlc3VsdCA9IHtcbiAgICBtZXJnZWQ6IGJvb2xlYW47XG4gICAgc2tpcFJlYXNvbj86IE1lcmdlU2tpcFJlYXNvbjtcbiAgICBsb2NrSG9sZGVySWQ/OiBzdHJpbmc7XG4gICAgbG9ja0V4cGlyZXNJbk1zPzogbnVtYmVyO1xufTtcblxubGV0IG5ldHdvcmtDb21wYWN0aW9uRW5hYmxlZCA9IGZhbHNlO1xuXG5sZXQgZmlsZU5hbWVDb3VudGVyID0gMDtcbi8vIFBlci1wcm9jZXNzIElEIHNvIHR3byB3cml0ZXJzIHBpY2tpbmcgdGhlIHNhbWUgdGltZXN0YW1wICsgY291bnRlciBuZXZlciBjb2xsaWRlIG9uIGEgbmFtZS5cbmNvbnN0IHdyaXRlcklkID0gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMiwgMTApO1xuZnVuY3Rpb24gbmV4dENvdW50ZXIoKTogbnVtYmVyIHsgcmV0dXJuICsrZmlsZU5hbWVDb3VudGVyOyB9XG5cbmxldCBsYXN0RmlsZVRpbWUgPSAwO1xuLy8gU3RyaWN0bHktaW5jcmVhc2luZyBpbnRlZ2VyIHNvIG5ld2VzdC1maXJzdCBvcmRlcmluZyBpcyB1bmFtYmlndW91cyB3aXRoaW4gYSBtaWxsaXNlY29uZC5cbmZ1bmN0aW9uIG5leHRGaWxlVGltZSgpOiBudW1iZXIge1xuICAgIGxhc3RGaWxlVGltZSA9IE1hdGgubWF4KERhdGUubm93KCksIGxhc3RGaWxlVGltZSArIDEpO1xuICAgIHJldHVybiBsYXN0RmlsZVRpbWU7XG59XG5cbmZ1bmN0aW9uIG5ld0ZpbGVOYW1lKHRpbWVzdGFtcDogbnVtYmVyKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYDBfJHt0aW1lc3RhbXB9XyR7d3JpdGVySWR9XyR7bmV4dENvdW50ZXIoKX0ke0ZJTEVfRVhURU5TSU9OfWA7XG59XG5cbmZ1bmN0aW9uIHBhcnNlU3RyZWFtRmlsZU5hbWUoZmlsZU5hbWU6IHN0cmluZyk6IFN0cmVhbUZpbGVJbmZvIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIWZpbGVOYW1lLmVuZHNXaXRoKFNUUkVBTV9FWFRFTlNJT04pKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGNvbnN0IHBhcnRzID0gZmlsZU5hbWUuc2xpY2UoMCwgLVNUUkVBTV9FWFRFTlNJT04ubGVuZ3RoKS5zcGxpdChcIl9cIik7XG4gICAgaWYgKHBhcnRzLmxlbmd0aCAhPT0gMyB8fCBwYXJ0c1swXSAhPT0gXCJzdHJlYW1cIikgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCB0aW1lc3RhbXAgPSBwYXJzZUludChwYXJ0c1sxXSwgMTApO1xuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKHRpbWVzdGFtcCkpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHsgZmlsZU5hbWUsIHRpbWVzdGFtcCB9O1xufVxuXG4vLyBBY2NlcHQgb2xkIDMtcGFydCAobGV2ZWxfdGltZXN0YW1wX2NvdW50ZXIpIGFuZCBuZXcgNC1wYXJ0IChsZXZlbF90aW1lc3RhbXBfd3JpdGVySWRfY291bnRlcikgc2hhcGVzLlxuZnVuY3Rpb24gcGFyc2VGaWxlTmFtZShmaWxlTmFtZTogc3RyaW5nKTogQnVsa0ZpbGVJbmZvIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIWZpbGVOYW1lLmVuZHNXaXRoKEZJTEVfRVhURU5TSU9OKSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCBwYXJ0cyA9IGZpbGVOYW1lLnNsaWNlKDAsIC1GSUxFX0VYVEVOU0lPTi5sZW5ndGgpLnNwbGl0KFwiX1wiKTtcbiAgICBpZiAocGFydHMubGVuZ3RoIDwgMykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCBsZXZlbCA9IHBhcnNlSW50KHBhcnRzWzBdLCAxMCk7XG4gICAgY29uc3QgdGltZXN0YW1wID0gcGFyc2VJbnQocGFydHNbMV0sIDEwKTtcbiAgICBpZiAoIU51bWJlci5pc0Zpbml0ZShsZXZlbCkgfHwgIU51bWJlci5pc0Zpbml0ZSh0aW1lc3RhbXApKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiB7IGZpbGVOYW1lLCBsZXZlbCwgdGltZXN0YW1wIH07XG59XG5cbmV4cG9ydCBjbGFzcyBCdWxrRGF0YWJhc2VCYXNlPFQgZXh0ZW5kcyB7IGtleTogc3RyaW5nIH0+IHtcbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IG5hbWU6IHN0cmluZyxcbiAgICAgICAgcHJvdGVjdGVkIGRlcHM6IFJlYWN0aXZlRGVwcyxcbiAgICAgICAgcHJpdmF0ZSBzdG9yYWdlRmFjdG9yeTogU3RvcmFnZUZhY3RvcnksXG4gICAgICAgIHByaXZhdGUgY29uZmlnOiBCdWxrRGF0YWJhc2UyQ29uZmlnID0ge30sXG4gICAgKSB7IH1cblxuICAgIC8vIFRoZSByZWFkZXIgKGFuZCB0aGUgYmFja2dyb3VuZCBtYWNoaW5lcnkgdGhhdCByaWRlcyBhbG9uZyB3aXRoIGl0KSBtdXN0IE5PVCBiZSBzZXQgdXAganVzdFxuICAgIC8vIGJlY2F1c2UgdGhlIGNvbGxlY3Rpb24gd2FzIGNvbnN0cnVjdGVkLiBNYW55IGNvbGxlY3Rpb25zIGFyZSBjb25zdHJ1Y3RlZCBhbmQgbmV2ZXIgdG91Y2hlZCwgYW5kXG4gICAgLy8gaW4gTm9kZSBhIG1lcmdlIHRpY2sgd291bGQgcG9rZSB0aGUgc3RvcmFnZSBmYWN0b3J5IChlLmcuIGluZGV4ZWREQikgYW5kIHRocm93LiBXZSBidWlsZCBpdFxuICAgIC8vIGxhemlseSBvbiBmaXJzdCBhY2Nlc3MgdG8gYHRoaXMucmVhZGVyYDogZXZlcnkgcmVhZCwgd3JpdGUsIGFuZCBtZXJnZSBnb2VzIHRocm91Z2ggdGhlIHJlYWRlcixcbiAgICAvLyB3aGlsZSBwdXJlIGNvbnN0cnVjdGlvbiBuZXZlciB0b3VjaGVzIGl0LlxuICAgIHByaXZhdGUgX3JlYWRlcjogQnVsa0RhdGFiYXNlUmVhZGVyPFQ+IHwgdW5kZWZpbmVkO1xuICAgIHByaXZhdGUgZ2V0IHJlYWRlcigpOiBCdWxrRGF0YWJhc2VSZWFkZXI8VD4ge1xuICAgICAgICBpZiAodGhpcy5fcmVhZGVyKSByZXR1cm4gdGhpcy5fcmVhZGVyO1xuICAgICAgICBjb25zdCByZWFkZXIgPSBuZXcgQnVsa0RhdGFiYXNlUmVhZGVyPFQ+KHtcbiAgICAgICAgICAgIG5hbWU6IHRoaXMubmFtZSxcbiAgICAgICAgICAgIGRlcHM6IHRoaXMuZGVwcyxcbiAgICAgICAgICAgIG1heFRyaWdnZXJUaHJvdHRsZU1zOiB0aGlzLmNvbmZpZy5tYXhUcmlnZ2VyVGhyb3R0bGVNcyxcbiAgICAgICAgfSk7XG4gICAgICAgIHJlYWRlci5zZXRFbnN1cmVJbmRleCgoKSA9PiB0aGlzLmVuc3VyZUluZGV4KCkpO1xuICAgICAgICB0aGlzLl9yZWFkZXIgPSByZWFkZXI7XG4gICAgICAgIHRoaXMuYWN0aXZhdGUoKTtcbiAgICAgICAgcmV0dXJuIHJlYWRlcjtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFjdGl2YXRlZCA9IGZhbHNlO1xuICAgIHByaXZhdGUgYWN0aXZhdGUoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmFjdGl2YXRlZCkgcmV0dXJuO1xuICAgICAgICB0aGlzLmFjdGl2YXRlZCA9IHRydWU7XG4gICAgICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicGFnZWhpZGVcIiwgKCkgPT4gdm9pZCB0aGlzLmZsdXNoUGVuZGluZygpKTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGRvY3VtZW50ICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJ2aXNpYmlsaXR5Y2hhbmdlXCIsICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkb2N1bWVudC52aXNpYmlsaXR5U3RhdGUgPT09IFwiaGlkZGVuXCIpIHZvaWQgdGhpcy5mbHVzaFBlbmRpbmcoKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCB7IC8qIG5vdCBpbiBhIERPTSBjb250ZXh0ICovIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmZpbGVTZXRQb2xsVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB2b2lkIHRoaXMucG9sbEZpbGVTZXQoKSwgYnVsa0RhdGFiYXNlMlRpbWluZy5maWxlU2V0UG9sbEludGVydmFsTXMpO1xuICAgICAgICAodGhpcy5maWxlU2V0UG9sbFRpbWVyIGFzIHsgdW5yZWY/OiAoKSA9PiB2b2lkIH0pLnVucmVmPy4oKTtcbiAgICAgICAgdGhpcy5zZXR1cFZpc2liaWxpdHlNZXJnZUNoZWNrKCk7XG4gICAgICAgIEJ1bGtEYXRhYmFzZUJhc2UubGl2ZUluc3RhbmNlcy5hZGQodGhpcyk7XG4gICAgICAgIEJ1bGtEYXRhYmFzZUJhc2Uuc3RhcnRNZW1vcnlXYXRjaGRvZygpO1xuICAgIH1cblxuICAgIC8vIEV2ZXJ5IGB2aXNpYmxlTWVyZ2VJbnRlcnZhbE1zYCBvZiBiZWluZy12aXNpYmxlIHRpbWUsIHJ1biBhIG1lcmdlIGNoZWNrLiBGaXJzdCBjaGVjayBmaXJlc1xuICAgIC8vIGB2aXNpYmxlTWVyZ2VJbnRlcnZhbE1zYCBhZnRlciB0aGUgdGFiIGJlY29tZXMgdmlzaWJsZSAobm90IG9uIGluaXRpYWwgbG9hZCDigJQgZ2l2ZXMgdGhlIHVzZXIgYVxuICAgIC8vIG1vbWVudCBvZiBzZXNzaW9uIGNvbW1pdG1lbnQgYmVmb3JlIHdlIHN0YXJ0IGNodXJuaW5nIHRoZSBGUyksIHRoZW4gZXZlcnkgaW50ZXJ2YWwgYWZ0ZXIuIFRhYlxuICAgIC8vIGhpZGluZyBjYW5jZWxzIHRoZSB0aW1lcnM7IHZpc2libGUtYWdhaW4gcmVzdGFydHMuIE5vZGUgaGFzIG5vIGRvY3VtZW50IOKAlCB0aGVyZSB3ZSBjb25zaWRlclxuICAgIC8vIG91cnNlbHZlcyBhbHdheXMtdmlzaWJsZSBhbmQganVzdCBpbnN0YWxsIHRoZSBpbnRlcnZhbCBkaXJlY3RseS5cbiAgICBwcml2YXRlIHNldHVwVmlzaWJpbGl0eU1lcmdlQ2hlY2soKTogdm9pZCB7XG4gICAgICAgIGxldCBmaXJzdFRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IGludGVydmFsVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPiB8IHVuZGVmaW5lZDtcbiAgICAgICAgY29uc3Qgc3RvcCA9ICgpID0+IHtcbiAgICAgICAgICAgIGlmIChmaXJzdFRpbWVyKSB7IGNsZWFyVGltZW91dChmaXJzdFRpbWVyKTsgZmlyc3RUaW1lciA9IHVuZGVmaW5lZDsgfVxuICAgICAgICAgICAgaWYgKGludGVydmFsVGltZXIpIHsgY2xlYXJJbnRlcnZhbChpbnRlcnZhbFRpbWVyKTsgaW50ZXJ2YWxUaW1lciA9IHVuZGVmaW5lZDsgfVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBzdGFydCA9ICgpID0+IHtcbiAgICAgICAgICAgIGlmIChmaXJzdFRpbWVyIHx8IGludGVydmFsVGltZXIpIHJldHVybjtcbiAgICAgICAgICAgIGZpcnN0VGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICBmaXJzdFRpbWVyID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHZvaWQgdGhpcy5tYXliZU1lcmdlKCk7XG4gICAgICAgICAgICAgICAgaW50ZXJ2YWxUaW1lciA9IHNldEludGVydmFsKCgpID0+IHZvaWQgdGhpcy5tYXliZU1lcmdlKCksIGJ1bGtEYXRhYmFzZTJUaW1pbmcudmlzaWJsZU1lcmdlSW50ZXJ2YWxNcyk7XG4gICAgICAgICAgICAgICAgKGludGVydmFsVGltZXIgYXMgeyB1bnJlZj86ICgpID0+IHZvaWQgfSkudW5yZWY/LigpO1xuICAgICAgICAgICAgfSwgYnVsa0RhdGFiYXNlMlRpbWluZy52aXNpYmxlTWVyZ2VJbnRlcnZhbE1zKTtcbiAgICAgICAgICAgIChmaXJzdFRpbWVyIGFzIHsgdW5yZWY/OiAoKSA9PiB2b2lkIH0pLnVucmVmPy4oKTtcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKHR5cGVvZiBkb2N1bWVudCA9PT0gXCJ1bmRlZmluZWRcIikgeyBzdGFydCgpOyByZXR1cm47IH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJ2aXNpYmlsaXR5Y2hhbmdlXCIsICgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZG9jdW1lbnQudmlzaWJpbGl0eVN0YXRlID09PSBcInZpc2libGVcIikgc3RhcnQoKTtcbiAgICAgICAgICAgICAgICBlbHNlIHN0b3AoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGRvY3VtZW50LnZpc2liaWxpdHlTdGF0ZSA9PT0gXCJ2aXNpYmxlXCIpIHN0YXJ0KCk7XG4gICAgICAgIH0gY2F0Y2ggeyAvKiBub3QgaW4gYSBET00gY29udGV4dCAqLyB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdWJDYWNoZXM6IFN1YlJlYWRlckNhY2hlcyA9IHsgYnVsazogbmV3IE1hcCgpLCBzdHJlYW06IG5ldyBNYXAoKSB9O1xuXG4gICAgcHJpdmF0ZSBwZW5kaW5nQXBwZW5kczogeyBmcmFtZWQ6IEJ1ZmZlcjsgcm93czogbnVtYmVyIH1bXSA9IFtdO1xuICAgIHByaXZhdGUgZmx1c2hUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gICAgcHJpdmF0ZSBmbHVzaENoYWluOiBQcm9taXNlPHZvaWQ+ID0gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgcHJpdmF0ZSBjdXJyZW50Rmx1c2hEZWxheSA9IDA7XG4gICAgcHJpdmF0ZSBsYXN0V3JpdGVUaW1lID0gMDtcblxuICAgIHByaXZhdGUgc3RyZWFtRmlsZU5hbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIGN1cnJlbnRTdHJlYW1GaWxlTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIHByaXZhdGUgY3VycmVudFN0cmVhbUZpbGVCeXRlcyA9IDA7XG4gICAgLy8gSW4tcHJvY2VzcyByZS1lbnRyeSBndWFyZDogaWYgYSBtZXJnZSBpcyBydW5uaW5nLCBhZGRpdGlvbmFsIHRyaWdnZXJzICh2aXNpYmlsaXR5IHRpbWVyLCB3cml0ZXMsXG4gICAgLy8gdHJ5TWVyZ2VOb3cgY2FsbHMpIHJldHVybiBpbW1lZGlhdGVseSBpbnN0ZWFkIG9mIHF1ZXVlaW5nLiBLZWVwcyB0aGUgdmlzaWJpbGl0eS10aW1lciBmaXJpbmdzXG4gICAgLy8gZnJvbSBzdGFja2luZyBiZWhpbmQgYSBsb25nIG1lcmdlLlxuICAgIHByaXZhdGUgbWVyZ2VJbkZsaWdodCA9IGZhbHNlO1xuICAgIHByaXZhdGUgbGFzdE1lcmdlU2tpcExvZ01zID0gMDtcbiAgICAvLyBSdW5uaW5nIGNvdW50ZXJzIG9mIHN0cmVhbS10aWVyIHJvd3MgKyBieXRlcyBvbiBkaXNrLiBTZWVkZWQgZnJvbSBlYWNoIExvYWRlZEluZGV4IGJ1aWxkLCB0aGVuXG4gICAgLy8gaW5jcmVtZW50ZWQgcGVyIGZsdXNoIHNvIHRoZSBmb2xkLXRyaWdnZXIgY2hlY2tzIGN1cnJlbnQgZGF0YSB3aXRob3V0IGFuIGV4dHJhIGRpcmVjdG9yeSBsaXN0aW5nLlxuICAgIHByaXZhdGUgc3RyZWFtUm93c09uRGlzayA9IDA7XG4gICAgcHJpdmF0ZSBzdHJlYW1CeXRlc09uRGlzayA9IDA7XG5cbiAgICBwcml2YXRlIGZpbGVTZXRQb2xsVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPiB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIHJlYnVpbGRQcm9taXNlOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkO1xuICAgIHByaXZhdGUgcmVidWlsZERpcnR5ID0gZmFsc2U7XG4gICAgcHJpdmF0ZSByZWJ1aWxkT3B0aW9uczogeyBkcm9wU3RhbGVGYWxsYmFjazogYm9vbGVhbiB9ID0geyBkcm9wU3RhbGVGYWxsYmFjazogZmFsc2UgfTtcblxuICAgIC8vIOKUgOKUgCBtZW1vcnktcHJlc3N1cmUgd2F0Y2hkb2cgKGdsb2JhbCwgYnJvd3Nlci1vbmx5KSDilIDilIBcbiAgICBwcml2YXRlIHN0YXRpYyBsaXZlSW5zdGFuY2VzID0gbmV3IFNldDxCdWxrRGF0YWJhc2VCYXNlPHsga2V5OiBzdHJpbmcgfT4+KCk7XG4gICAgcHJpdmF0ZSBzdGF0aWMgbWVtb3J5V2F0Y2hkb2dTdGFydGVkID0gZmFsc2U7XG4gICAgcHJpdmF0ZSBzdGF0aWMgbGFzdE1lbW9yeUZsdXNoTXMgPSAwO1xuICAgIHByaXZhdGUgc3RhdGljIHN0YXJ0TWVtb3J5V2F0Y2hkb2coKSB7XG4gICAgICAgIGlmIChCdWxrRGF0YWJhc2VCYXNlLm1lbW9yeVdhdGNoZG9nU3RhcnRlZCkgcmV0dXJuO1xuICAgICAgICBCdWxrRGF0YWJhc2VCYXNlLm1lbW9yeVdhdGNoZG9nU3RhcnRlZCA9IHRydWU7XG4gICAgICAgIGNvbnN0IHVzZWRIZWFwID0gKCk6IG51bWJlciB8IHVuZGVmaW5lZCA9PiB7XG4gICAgICAgICAgICB0cnkgeyByZXR1cm4gKHBlcmZvcm1hbmNlIGFzIHVua25vd24gYXMgeyBtZW1vcnk/OiB7IHVzZWRKU0hlYXBTaXplPzogbnVtYmVyIH0gfSk/Lm1lbW9yeT8udXNlZEpTSGVhcFNpemU7IH1cbiAgICAgICAgICAgIGNhdGNoIHsgcmV0dXJuIHVuZGVmaW5lZDsgfVxuICAgICAgICB9O1xuICAgICAgICBpZiAodHlwZW9mIHBlcmZvcm1hbmNlID09PSBcInVuZGVmaW5lZFwiIHx8IHVzZWRIZWFwKCkgPT09IHVuZGVmaW5lZCkgcmV0dXJuO1xuICAgICAgICBjb25zdCB0aW1lciA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHVzZWQgPSB1c2VkSGVhcCgpO1xuICAgICAgICAgICAgaWYgKHVzZWQgIT09IHVuZGVmaW5lZCkgQnVsa0RhdGFiYXNlQmFzZS5jaGVja01lbW9yeVByZXNzdXJlKHVzZWQpO1xuICAgICAgICB9LCBNRU1PUllfV0FUQ0hET0dfSU5URVJWQUxfTVMpO1xuICAgICAgICAodGltZXIgYXMgeyB1bnJlZj86ICgpID0+IHZvaWQgfSkudW5yZWY/LigpO1xuICAgIH1cbiAgICBwdWJsaWMgc3RhdGljIGNoZWNrTWVtb3J5UHJlc3N1cmUodXNlZEhlYXBCeXRlczogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGlmICh1c2VkSGVhcEJ5dGVzIDwgYnVsa0RhdGFiYXNlMlRpbWluZy5tZW1vcnlGbHVzaEhlYXBCeXRlcykgcmV0dXJuO1xuICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgICAgICBpZiAobm93IC0gQnVsa0RhdGFiYXNlQmFzZS5sYXN0TWVtb3J5Rmx1c2hNcyA8IGJ1bGtEYXRhYmFzZTJUaW1pbmcubWVtb3J5Rmx1c2hUaHJvdHRsZU1zKSByZXR1cm47XG4gICAgICAgIEJ1bGtEYXRhYmFzZUJhc2UubGFzdE1lbW9yeUZsdXNoTXMgPSBub3c7XG4gICAgICAgIGNvbnN0IGZsdXNoZWQ6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGZvciAoY29uc3QgZGIgb2YgQnVsa0RhdGFiYXNlQmFzZS5saXZlSW5zdGFuY2VzKSB7XG4gICAgICAgICAgICBjb25zdCBieXRlcyA9IGRiLnJlYWRlci5pbmRleD8udG90YWxCeXRlcyA/PyAwO1xuICAgICAgICAgICAgaWYgKGJ5dGVzID4gYnVsa0RhdGFiYXNlMlRpbWluZy5tZW1vcnlGbHVzaE1pbkNvbGxlY3Rpb25CeXRlcykge1xuICAgICAgICAgICAgICAgIGZsdXNoZWQucHVzaChgJHtkYi5uYW1lfSAoJHtmbXRCeXRlcyhieXRlcyl9KWApO1xuICAgICAgICAgICAgICAgIGRiLnJlbG9hZEZyb21EaXNrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZsdXNoZWQubGVuZ3RoKSBjb25zb2xlLmxvZyhgW2J1bGsyXSBoZWFwICR7Zm10Qnl0ZXModXNlZEhlYXBCeXRlcyl9IG92ZXIgJHtmbXRCeXRlcyhidWxrRGF0YWJhc2UyVGltaW5nLm1lbW9yeUZsdXNoSGVhcEJ5dGVzKX0gLSBmbHVzaGVkICR7Zmx1c2hlZC5sZW5ndGh9IGxhcmdlIGNvbGxlY3Rpb24ocyk6ICR7Zmx1c2hlZC5qb2luKFwiLCBcIil9YCk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBjbGVhckNhY2hlKCkge1xuICAgICAgICBibG9ja0NhY2hlLmNsZWFyKCk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBlbmFibGVOZXR3b3JrQ29tcGFjdGlvbigpIHtcbiAgICAgICAgbmV0d29ya0NvbXBhY3Rpb25FbmFibGVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RvcmFnZSA9IGxhenkoYXN5bmMgKCkgPT4gdGhpcy5zdG9yYWdlRmFjdG9yeShgJHtCVUxLX1JPT1RfRk9MREVSfS8ke3RoaXMubmFtZX1gKSk7XG5cbiAgICBwdWJsaWMgYXN5bmMgaXNSZW1vdGUoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIHJldHVybiAhIShhd2FpdCB0aGlzLnN0b3JhZ2UoKSkuaXNSZW1vdGU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdHJlYW1OZWVkc0ZvbGQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0cmVhbVJvd3NPbkRpc2sgPj0gYnVsa0RhdGFiYXNlMlRpbWluZy5zdHJlYW1Gb2xkVHJpZ2dlclJvd3NcbiAgICAgICAgICAgICYmIHRoaXMuc3RyZWFtQnl0ZXNPbkRpc2sgPiBidWxrRGF0YWJhc2UyVGltaW5nLnN0cmVhbUZvbGRUcmlnZ2VyQnl0ZXM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBhdXRvbWF0aWNDb21wYWN0aW9uQWxsb3dlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgaWYgKG5ldHdvcmtDb21wYWN0aW9uRW5hYmxlZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIGlmIChpc05vZGUoKSkgcmV0dXJuIHRydWU7XG4gICAgICAgIHJldHVybiAhKGF3YWl0IHRoaXMuc3RvcmFnZSgpKS5pc1JlbW90ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNLZXlXYXRjaGVkKGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWRlci5pc0tleVdhdGNoZWQoa2V5KTtcbiAgICB9XG5cbiAgICAvLyDilIDilIAgaW5kZXggbGlmZWN5Y2xlIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAgIHByaXZhdGUgYXN5bmMgZW5zdXJlSW5kZXgoKTogUHJvbWlzZTxMb2FkZWRJbmRleDxUPj4ge1xuICAgICAgICBpZiAodGhpcy5yZWFkZXIuaW5kZXgpIHJldHVybiB0aGlzLnJlYWRlci5pbmRleDtcbiAgICAgICAgYXdhaXQgdGhpcy50cmlnZ2VyUmVidWlsZCgpO1xuICAgICAgICBjb25zdCBpZHggPSB0aGlzLnJlYWRlci5pbmRleDtcbiAgICAgICAgaWYgKCFpZHgpIHRocm93IG5ldyBFcnJvcihgJHt0aGlzLm5hbWV9OiBpbmRleCBmYWlsZWQgdG8gYnVpbGRgKTtcbiAgICAgICAgcmV0dXJuIGlkeDtcbiAgICB9XG5cbiAgICAvLyBDb2FsZXNjaW5nIHJlYnVpbGQgbG9vcDogdHJpZ2dlcnMgZHVyaW5nIGEgYnVpbGQgc2V0IHJlYnVpbGREaXJ0eSBzbyB0aGUgbG9vcCBpdGVyYXRlcyBvbmNlIG1vcmVcbiAgICAvLyB3aGVuIGl0IGZpbmlzaGVzIOKAlCBOIHJhcGlkIHRyaWdnZXJzIGNhdXNlIGF0IG1vc3QgT05FIGV4dHJhIHJlYnVpbGQgYWZ0ZXIgdGhlIGN1cnJlbnQgb25lIGVuZHMuXG4gICAgcHJpdmF0ZSB0cmlnZ2VyUmVidWlsZChvcHRzOiB7IGRyb3BTdGFsZUZhbGxiYWNrPzogYm9vbGVhbiB9ID0ge30pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKG9wdHMuZHJvcFN0YWxlRmFsbGJhY2spIHRoaXMucmVidWlsZE9wdGlvbnMuZHJvcFN0YWxlRmFsbGJhY2sgPSB0cnVlO1xuICAgICAgICBpZiAodGhpcy5yZWJ1aWxkUHJvbWlzZSkge1xuICAgICAgICAgICAgdGhpcy5yZWJ1aWxkRGlydHkgPSB0cnVlO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVidWlsZFByb21pc2U7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZWJ1aWxkUHJvbWlzZSA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWJ1aWxkRGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5kb09uZVJlYnVpbGQoKTtcbiAgICAgICAgICAgICAgICB9IHdoaWxlICh0aGlzLnJlYnVpbGREaXJ0eSk7XG4gICAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVidWlsZFByb21pc2UgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5yZWJ1aWxkT3B0aW9ucy5kcm9wU3RhbGVGYWxsYmFjayA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KSgpO1xuICAgICAgICByZXR1cm4gdGhpcy5yZWJ1aWxkUHJvbWlzZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGRvT25lUmVidWlsZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3QgeyBidWxrRmlsZXMsIHN0cmVhbUZpbGVzIH0gPSBhd2FpdCB0aGlzLmxpc3RGaWxlcygpO1xuICAgICAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5zdG9yYWdlKCk7XG4gICAgICAgIGNvbnN0IG5ld0luZGV4ID0gYXdhaXQgTG9hZGVkSW5kZXguYnVpbGQ8VD4oe1xuICAgICAgICAgICAgbmFtZTogdGhpcy5uYW1lLFxuICAgICAgICAgICAgc3RvcmFnZSxcbiAgICAgICAgICAgIGJ1bGtGaWxlcyxcbiAgICAgICAgICAgIHN0cmVhbUZpbGVzLFxuICAgICAgICAgICAgc3ViQ2FjaGVzOiB0aGlzLnN1YkNhY2hlcyxcbiAgICAgICAgICAgIG9uVW5yZWFkYWJsZUZpbGU6IChmLCBtc2cpID0+IHRoaXMuaGFuZGxlVW5yZWFkYWJsZUZpbGUoZiwgbXNnKSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IG9sZEluZGV4ID0gdGhpcy5yZWFkZXIuaW5kZXg7XG4gICAgICAgIHRoaXMucmVhZGVyLnNldEluZGV4KG5ld0luZGV4LCB7IGRyb3BTdGFsZUZhbGxiYWNrOiB0aGlzLnJlYnVpbGRPcHRpb25zLmRyb3BTdGFsZUZhbGxiYWNrIH0pO1xuICAgICAgICB0aGlzLnN0cmVhbVJvd3NPbkRpc2sgPSBuZXdJbmRleC5zdHJlYW1Sb3dzT25EaXNrO1xuICAgICAgICB0aGlzLnN0cmVhbUJ5dGVzT25EaXNrID0gbmV3SW5kZXguc3RyZWFtQnl0ZXNPbkRpc2s7XG4gICAgICAgIGlmIChvbGRJbmRleCkge1xuICAgICAgICAgICAgZm9yIChjb25zdCBmIG9mIG9sZEluZGV4LmZpbGVTZXQpIHtcbiAgICAgICAgICAgICAgICBpZiAoIW5ld0luZGV4LmZpbGVTZXQuaGFzKGYpKSBibG9ja0NhY2hlLmV2aWN0KG51bGxKb2luKHRoaXMubmFtZSwgZikpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gRHJvcCBldmVyeXRoaW5nIGluLW1lbW9yeSwgaGFyZCByZXNldC4gUGVuZGluZyB1bi1mbHVzaGVkIHdyaXRlcyBzdXJ2aXZlIChzdGlsbCBpbiBvdmVybGF5KS5cbiAgICBwdWJsaWMgcmVsb2FkRnJvbURpc2soKTogdm9pZCB7XG4gICAgICAgIHRoaXMuc3ViQ2FjaGVzLmJ1bGsuY2xlYXIoKTtcbiAgICAgICAgdGhpcy5zdWJDYWNoZXMuc3RyZWFtLmNsZWFyKCk7XG4gICAgICAgIHRoaXMucmVhZGVyLmluZGV4Py5kcm9wTG9hZGVkVmFsdWVzKCk7XG4gICAgICAgIHZvaWQgdGhpcy50cmlnZ2VyUmVidWlsZCh7IGRyb3BTdGFsZUZhbGxiYWNrOiB0cnVlIH0pO1xuICAgIH1cblxuICAgIC8vIEV4dGVybmFsLW1lcmdlIGRldGVjdGlvbjogaWYgc29tZSBvdGhlciB0YWIvcHJvY2VzcyBjaGFuZ2VkIHRoZSBmaWxlIHNldCB1bmRlciB1cywgcmVidWlsZC5cbiAgICBwcml2YXRlIGFzeW5jIHBvbGxGaWxlU2V0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMucmVhZGVyLmluZGV4KSByZXR1cm47XG4gICAgICAgIGxldCBjdXJyZW50OiBTZXQ8c3RyaW5nPjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHsgYnVsa0ZpbGVzLCBzdHJlYW1GaWxlcyB9ID0gYXdhaXQgdGhpcy5saXN0RmlsZXMoKTtcbiAgICAgICAgICAgIGN1cnJlbnQgPSBuZXcgU2V0KFsuLi5idWxrRmlsZXMubWFwKGYgPT4gZi5maWxlTmFtZSksIC4uLnN0cmVhbUZpbGVzLm1hcChmID0+IGYuZmlsZU5hbWUpXSk7XG4gICAgICAgIH0gY2F0Y2ggeyByZXR1cm47IH1cbiAgICAgICAgY29uc3QgcHJldiA9IHRoaXMucmVhZGVyLmluZGV4Py5maWxlU2V0O1xuICAgICAgICBpZiAoIXByZXYpIHJldHVybjtcbiAgICAgICAgY29uc3QgY2hhbmdlZCA9IGN1cnJlbnQuc2l6ZSAhPT0gcHJldi5zaXplIHx8IFsuLi5jdXJyZW50XS5zb21lKG4gPT4gIXByZXYuaGFzKG4pKTtcbiAgICAgICAgaWYgKGNoYW5nZWQpIHZvaWQgdGhpcy50cmlnZ2VyUmVidWlsZCgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgcmVhZFdpdGhSZXRyeTxSPihmbjogKCkgPT4gUHJvbWlzZTxSPik6IFByb21pc2U8Uj4ge1xuICAgICAgICBhd2FpdCB0aGlzLmVuc3VyZUluZGV4KCk7XG4gICAgICAgIGZvciAobGV0IGF0dGVtcHQgPSAwOyA7IGF0dGVtcHQrKykge1xuICAgICAgICAgICAgY29uc3QgYmVmb3JlID0gdGhpcy5yZWFkZXIuaW5kZXg7XG4gICAgICAgICAgICB0cnkgeyByZXR1cm4gYXdhaXQgZm4oKTsgfVxuICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBpZiAoIShlIGluc3RhbmNlb2YgTWlzc2luZ0ZpbGVFcnJvcikgfHwgYXR0ZW1wdCA+PSBNQVhfSU5ERVhfUkVMT0FEX0FUVEVNUFRTKSB0aHJvdyBlO1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLnJlYWRlci5pbmRleCA9PT0gYmVmb3JlKSBhd2FpdCB0aGlzLnRyaWdnZXJSZWJ1aWxkKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyDilIDilIAgY3Jvc3MtdGFiIHN5bmMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gICAgcHJpdmF0ZSBzeW5jU2V0dXAgPSBsYXp5KGFzeW5jICgpID0+IHtcbiAgICAgICAgaWYgKCFpc1N5bmNTdXBwb3J0ZWQoKSkgcmV0dXJuO1xuICAgICAgICBhd2FpdCB0aGlzLmVuc3VyZUluZGV4KCk7XG4gICAgICAgIGNvbnN0IHJlY2VudCA9IGF3YWl0IHN5bmNDb25uZWN0KHRoaXMubmFtZSwgdyA9PiB0aGlzLmFwcGx5UmVtb3RlKHcpLCAoKSA9PiB7IHRoaXMuc3RyZWFtRmlsZU5hbWUgPSB1bmRlZmluZWQ7IH0pO1xuICAgICAgICBmb3IgKGNvbnN0IHcgb2YgcmVjZW50KSB0aGlzLmFwcGx5UmVtb3RlKHcpO1xuICAgIH0pO1xuXG4gICAgcHJpdmF0ZSBhcHBseVJlbW90ZSh3cml0ZTogUmVtb3RlV3JpdGUpIHtcbiAgICAgICAgaWYgKHdyaXRlLnRpbWUgPD0gdGhpcy5yZWFkZXIubG9jYWxUaW1lKHdyaXRlLmtleSkpIHJldHVybjtcbiAgICAgICAgdGhpcy5kZXBzLmJhdGNoKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh3cml0ZS5kZWxldGVkKSB0aGlzLnJlYWRlci5hcHBseURlbGV0ZSh3cml0ZS5rZXksIHdyaXRlLnRpbWUpO1xuICAgICAgICAgICAgZWxzZSB0aGlzLnJlYWRlci5hcHBseVdyaXRlKHdyaXRlLmtleSwgd3JpdGUudmFsdWUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4sIHdyaXRlLnRpbWUpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyDilIDilIAgd3JpdGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICAgIHB1YmxpYyBhc3luYyB3cml0ZShlbnRyeTogVCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gdGhpcy53cml0ZUJhdGNoKFtlbnRyeV0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyB3cml0ZUJhdGNoKGVudHJpZXM6IFRbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIWVudHJpZXMubGVuZ3RoKSByZXR1cm47XG4gICAgICAgIHZvaWQgdGhpcy5zeW5jU2V0dXAoKTtcbiAgICAgICAgY29uc3Qgcm93cyA9IGVudHJpZXMgYXMgdW5rbm93biBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdO1xuICAgICAgICBjb25zdCBzdGFtcGVkID0gcm93cy5tYXAocm93ID0+ICh7IHRpbWU6IGdldFRpbWVVbmlxdWUoKSwgcm93IH0pKTtcbiAgICAgICAgY29uc3QgZnJhbWVkID0gZnJhbWVSb3dzKHN0YW1wZWQpO1xuXG4gICAgICAgIC8vIEJpZyBiYXRjaGVzIHNraXAgdGhlIHN0cmVhbSBhbmQgYmVjb21lIGEgYnVsayBmaWxlIGRpcmVjdGx5IOKAlCBzdHJlYW1pbmcgdGhvdXNhbmRzIG9mIHJvd3NcbiAgICAgICAgLy8gb25lIGZyYW1lIGF0IGEgdGltZSB3b3VsZCBqdXN0IGNodXJuLlxuICAgICAgICBpZiAoZW50cmllcy5sZW5ndGggPj0gUk9MTE9WRVJfUk9XUyB8fCBmcmFtZWQubGVuZ3RoID49IFJPTExPVkVSX0JZVEVTKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLndyaXRlQnVsa0ZpbGUocm93cyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmRlcHMuYmF0Y2goKCkgPT4ge1xuICAgICAgICAgICAgZm9yIChjb25zdCB7IHRpbWUsIHJvdyB9IG9mIHN0YW1wZWQpIHRoaXMucmVhZGVyLmFwcGx5V3JpdGUocm93LmtleSBhcyBzdHJpbmcsIHJvdywgdGltZSk7XG4gICAgICAgIH0pO1xuICAgICAgICBmb3IgKGNvbnN0IHsgdGltZSwgcm93IH0gb2Ygc3RhbXBlZCkgc3luY0Jyb2FkY2FzdCh0aGlzLm5hbWUsIHsga2V5OiByb3cua2V5IGFzIHN0cmluZywgdGltZSwgdmFsdWU6IHJvdyB9KTtcbiAgICAgICAgYXdhaXQgdGhpcy5zdHJlYW1BcHBlbmQoZnJhbWVkLCBzdGFtcGVkLmxlbmd0aCk7XG4gICAgICAgIHZvaWQgdGhpcy5tYXliZU1lcmdlKHsgb25seUlmU3RyZWFtSGVhdnk6IHRydWUgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGRlbGV0ZShrZXk6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gdGhpcy5kZWxldGVCYXRjaChba2V5XSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGRlbGV0ZUJhdGNoKGtleXM6IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICgha2V5cy5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgdm9pZCB0aGlzLnN5bmNTZXR1cCgpO1xuICAgICAgICBjb25zdCBzdGFtcGVkID0ga2V5cy5tYXAoa2V5ID0+ICh7IHRpbWU6IGdldFRpbWVVbmlxdWUoKSwga2V5IH0pKTtcbiAgICAgICAgdGhpcy5kZXBzLmJhdGNoKCgpID0+IHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgeyB0aW1lLCBrZXkgfSBvZiBzdGFtcGVkKSB0aGlzLnJlYWRlci5hcHBseURlbGV0ZShrZXksIHRpbWUpO1xuICAgICAgICB9KTtcbiAgICAgICAgZm9yIChjb25zdCB7IHRpbWUsIGtleSB9IG9mIHN0YW1wZWQpIHN5bmNCcm9hZGNhc3QodGhpcy5uYW1lLCB7IGtleSwgdGltZSwgZGVsZXRlZDogdHJ1ZSB9KTtcbiAgICAgICAgYXdhaXQgdGhpcy5zdHJlYW1BcHBlbmQoZnJhbWVEZWxldGVzKHN0YW1wZWQpLCBzdGFtcGVkLmxlbmd0aCk7XG4gICAgICAgIHZvaWQgdGhpcy5tYXliZU1lcmdlKHsgb25seUlmU3RyZWFtSGVhdnk6IHRydWUgfSk7XG4gICAgfVxuXG4gICAgLy8gQ29hbGVzY2Ugc3RyZWFtIGFwcGVuZHMgb24gYSByYW1waW5nIHBlci1jb2xsZWN0aW9uIHNjaGVkdWxlICh0aGUgYnJvd3NlciByZXdyaXRlcyB0aGUgd2hvbGVcbiAgICAvLyBmaWxlIHBlciBhcHBlbmQpLiBUaGUgZmlyc3Qgd3JpdGUgYWZ0ZXIgYSBsdWxsIGZsdXNoZXMgaW1tZWRpYXRlbHkgc28gYSBzaW5nbGUgZWRpdC10aGVuLWNsb3NlXG4gICAgLy8gaXMgc2F2ZWQgYXQgb25jZTsgc3VzdGFpbmVkIHdyaXRlcyByYW1wIHRvd2FyZCB3cml0ZUZsdXNoTWF4RGVsYXlNcy5cbiAgICBwcml2YXRlIGFzeW5jIHN0cmVhbUFwcGVuZChmcmFtZWQ6IEJ1ZmZlciwgcm93czogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMucGVuZGluZ0FwcGVuZHMucHVzaCh7IGZyYW1lZCwgcm93cyB9KTtcbiAgICAgICAgY29uc3QgbWF4ID0gYnVsa0RhdGFiYXNlMlRpbWluZy53cml0ZUZsdXNoTWF4RGVsYXlNcztcbiAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgaWYgKG1heCA8PSAwIHx8IHRoaXMuY3VycmVudEZsdXNoRGVsYXkgPD0gMCB8fCBub3cgLSB0aGlzLmxhc3RXcml0ZVRpbWUgPiBtYXgpIHtcbiAgICAgICAgICAgIHRoaXMubGFzdFdyaXRlVGltZSA9IG5vdztcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEZsdXNoRGVsYXkgPSBtYXggPiAwID8gTWF0aC5taW4obWF4LCBXUklURV9GTFVTSF9GSVJTVF9TVEVQX01TKSA6IDA7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmZsdXNoUGVuZGluZygpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubGFzdFdyaXRlVGltZSA9IG5vdztcbiAgICAgICAgaWYgKHRoaXMuZmx1c2hUaW1lciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLmZsdXNoVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHsgdGhpcy5mbHVzaFRpbWVyID0gdW5kZWZpbmVkOyB2b2lkIHRoaXMuZmx1c2hQZW5kaW5nKCk7IH0sIHRoaXMuY3VycmVudEZsdXNoRGVsYXkpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY3VycmVudEZsdXNoRGVsYXkgPSBNYXRoLm1pbihtYXgsIHRoaXMuY3VycmVudEZsdXNoRGVsYXkgKiAyKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZmx1c2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuZmx1c2hQZW5kaW5nKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBmbHVzaFBlbmRpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLmZsdXNoVGltZXIgIT09IHVuZGVmaW5lZCkgeyBjbGVhclRpbWVvdXQodGhpcy5mbHVzaFRpbWVyKTsgdGhpcy5mbHVzaFRpbWVyID0gdW5kZWZpbmVkOyB9XG4gICAgICAgIHRoaXMuZmx1c2hDaGFpbiA9IHRoaXMuZmx1c2hDaGFpbi50aGVuKCgpID0+IHRoaXMuZG9GbHVzaCgpKS5jYXRjaChlID0+IHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihgJHt0aGlzLm5hbWV9OiBzdHJlYW0gZmx1c2ggZmFpbGVkLCB3aWxsIHJldHJ5OiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmx1c2hDaGFpbjtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGRvRmx1c2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5wZW5kaW5nQXBwZW5kcy5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgY29uc3QgYmF0Y2ggPSB0aGlzLnBlbmRpbmdBcHBlbmRzLnNsaWNlKCk7XG4gICAgICAgIGNvbnN0IGNvbWJpbmVkID0gQnVmZmVyLmNvbmNhdChiYXRjaC5tYXAocCA9PiBwLmZyYW1lZCkpO1xuICAgICAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5zdG9yYWdlKCk7XG4gICAgICAgIGNvbnN0IGZpbGVOYW1lID0gdGhpcy5nZXRTdHJlYW1GaWxlTmFtZSgpO1xuICAgICAgICBpZiAoZmlsZU5hbWUgIT09IHRoaXMuY3VycmVudFN0cmVhbUZpbGVOYW1lKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRTdHJlYW1GaWxlTmFtZSA9IGZpbGVOYW1lO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3RyZWFtRmlsZUJ5dGVzID0gMDtcbiAgICAgICAgfVxuICAgICAgICAvLyBPbiBmYWlsdXJlIHRoZSB0aHJvdyBsZWF2ZXMgcGVuZGluZ0FwcGVuZHMgaW50YWN0IHNvIGEgbGF0ZXIgZmx1c2ggcmV0cmllcy5cbiAgICAgICAgYXdhaXQgc3RvcmFnZS5hcHBlbmQoZmlsZU5hbWUsIGNvbWJpbmVkKTtcbiAgICAgICAgLy8gTmV3IGVudHJpZXMgYXBwZW5kZWQgZHVyaW5nIHRoZSBhd2FpdCBhcmUgYWZ0ZXIgYGJhdGNoYCDigJQgcmVtb3ZpbmcgdGhlIGZyb250IGlzIGV4YWN0bHkgdGhlXG4gICAgICAgIC8vIGZsdXNoZWQgc2V0LlxuICAgICAgICB0aGlzLnBlbmRpbmdBcHBlbmRzLnNwbGljZSgwLCBiYXRjaC5sZW5ndGgpO1xuICAgICAgICB0aGlzLnN0cmVhbUJ5dGVzT25EaXNrICs9IGNvbWJpbmVkLmxlbmd0aDtcbiAgICAgICAgZm9yIChjb25zdCBwIG9mIGJhdGNoKSB0aGlzLnN0cmVhbVJvd3NPbkRpc2sgKz0gcC5yb3dzO1xuICAgICAgICB0aGlzLmN1cnJlbnRTdHJlYW1GaWxlQnl0ZXMgKz0gY29tYmluZWQubGVuZ3RoO1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50U3RyZWFtRmlsZUJ5dGVzID49IGJ1bGtEYXRhYmFzZTJUaW1pbmcuc3RyZWFtRmlsZU1heEJ5dGVzKSB7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbUZpbGVOYW1lID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50U3RyZWFtRmlsZU5hbWUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRTdHJlYW1GaWxlQnl0ZXMgPSAwO1xuICAgICAgICAgICAgdm9pZCB0aGlzLmZvbGRPd25TdHJlYW0oZmlsZU5hbWUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRTdHJlYW1GaWxlTmFtZSgpOiBzdHJpbmcge1xuICAgICAgICAvLyBTZWFsIG91ciBjdXJyZW50IGZpbGUgb25jZSBpdCBhZ2VzIHBhc3QgdGhlIHNlYWwgdGhyZXNob2xkIOKAlCBubyBmaWxlIGlzIGV2ZXIgYXBwZW5kZWQgdG8gcGFzdFxuICAgICAgICAvLyBpdHMgc2VhbCBhZ2UsIHdoaWNoIGxldHMgYSBjb25zb2xpZGF0aW9uIHNhZmVseSBmb2xkIGl0IG9uY2UgYWdlZC5cbiAgICAgICAgaWYgKHRoaXMuc3RyZWFtRmlsZU5hbWUpIHtcbiAgICAgICAgICAgIGNvbnN0IGluZm8gPSBwYXJzZVN0cmVhbUZpbGVOYW1lKHRoaXMuc3RyZWFtRmlsZU5hbWUpO1xuICAgICAgICAgICAgaWYgKGluZm8gJiYgRGF0ZS5ub3coKSAtIGluZm8udGltZXN0YW1wID49IGJ1bGtEYXRhYmFzZTJUaW1pbmcuc3RyZWFtU2VhbEFnZU1zKSB0aGlzLnN0cmVhbUZpbGVOYW1lID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5zdHJlYW1GaWxlTmFtZSkge1xuICAgICAgICAgICAgdGhpcy5zdHJlYW1GaWxlTmFtZSA9IGBzdHJlYW1fJHtEYXRlLm5vdygpfV8ke01hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnNsaWNlKDIsIDEwKX0ke1NUUkVBTV9FWFRFTlNJT059YDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zdHJlYW1GaWxlTmFtZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGZvbGRPd25TdHJlYW0oZmlsZU5hbWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBpbmZvID0gcGFyc2VTdHJlYW1GaWxlTmFtZShmaWxlTmFtZSk7XG4gICAgICAgIGlmICghaW5mbykgcmV0dXJuO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5tZXJnZUZpbGVTZXQoW10sIFtpbmZvXSwgZmFsc2UsIHRydWUpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYCR7dGhpcy5uYW1lfTogZm9sZGluZyBvd24gc3RyZWFtICR7ZmlsZU5hbWV9IGZhaWxlZDogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyB1cGRhdGUoZW50cnk6IFBhcnRpYWw8VD4gJiB7IGtleTogc3RyaW5nIH0pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMudXBkYXRlQmF0Y2goW2VudHJ5XSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHVwZGF0ZUJhdGNoKGVudHJpZXM6IChQYXJ0aWFsPFQ+ICYgeyBrZXk6IHN0cmluZyB9KVtdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghZW50cmllcy5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgdm9pZCB0aGlzLnN5bmNTZXR1cCgpO1xuICAgICAgICBjb25zdCBpbmRleCA9IGF3YWl0IHRoaXMuZW5zdXJlSW5kZXgoKTtcbiAgICAgICAgY29uc3QgcHJlc2VudDogVFtdID0gW107XG4gICAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgICAgICAgICAgY29uc3Qgb3ZlcmxheUVudHJ5ID0gdGhpcy5yZWFkZXIub3ZlcmxheS5nZXQoZW50cnkua2V5KTtcbiAgICAgICAgICAgIGNvbnN0IGV4aXN0cyA9IG92ZXJsYXlFbnRyeSA/IG92ZXJsYXlFbnRyeS52YWx1ZSAhPT0gREVMRVRFRCA6IGluZGV4LmtleXMuaGFzKGVudHJ5LmtleSk7XG4gICAgICAgICAgICBpZiAoIWV4aXN0cykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgJHt0aGlzLm5hbWV9LnVwZGF0ZToga2V5ICR7SlNPTi5zdHJpbmdpZnkoZW50cnkua2V5KX0gaXMgbm90IGluIHRoZSBjb2xsZWN0aW9uLCBpZ25vcmluZ2ApO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcHJlc2VudC5wdXNoKGVudHJ5IGFzIHVua25vd24gYXMgVCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHByZXNlbnQubGVuZ3RoKSBhd2FpdCB0aGlzLndyaXRlQmF0Y2gocHJlc2VudCk7XG4gICAgfVxuXG4gICAgLy8g4pSA4pSAIGZpbGUgbGlzdGluZ3Mg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gICAgcHJpdmF0ZSBhc3luYyBsaXN0RmlsZXMoKTogUHJvbWlzZTx7IGJ1bGtGaWxlczogQnVsa0ZpbGVJbmZvW107IHN0cmVhbUZpbGVzOiBTdHJlYW1GaWxlSW5mb1tdIH0+IHtcbiAgICAgICAgY29uc3Qgc3RvcmFnZSA9IGF3YWl0IHRoaXMuc3RvcmFnZSgpO1xuICAgICAgICBjb25zdCBuYW1lcyA9IGF3YWl0IHN0b3JhZ2UuZ2V0S2V5cygpO1xuICAgICAgICAvLyBBIGNvbnN1bWVkLW1lcmdlIGlucHV0IGlzIGhpZGRlbiBmcm9tIHJlYWRzIHRoZSBpbnN0YW50IGl0cyBkZWxldGlvbiBtYXJrZXIgZXhpc3RzIOKAlCB0aGF0J3NcbiAgICAgICAgLy8gd2hhdCBzdG9wcyBpdCBmcm9tIGJlaW5nIHJlLXJlYWQgYW5kIHJlLW1lcmdlZC4gUGh5c2ljYWwgZGVsZXRpb24gKyBtYXJrZXIgY2xlYW51cCBydW5zIG9uIGFcbiAgICAgICAgLy8gdGhyb3R0bGUgKG5vdCBpbmxpbmUpIHNvIGEgcmVhZCBpc24ndCBzbG93ZWQgYnkgaXQuXG4gICAgICAgIGNvbnN0IG1hcmtlcnMgPSBhd2FpdCByZWFkRGVsZXRlTWFya2VycyhzdG9yYWdlLCBuYW1lcyk7XG4gICAgICAgIGNvbnN0IGV4Y2x1ZGVkID0gbWFya2VyRXhjbHVzaW9ucyhtYXJrZXJzKTtcbiAgICAgICAgaWYgKG1hcmtlcnMubGVuZ3RoKSB2b2lkIHRoaXMucHJvY2Vzc01hcmtlcnMoKTtcbiAgICAgICAgY29uc3QgYnVsa0ZpbGVzOiBCdWxrRmlsZUluZm9bXSA9IFtdO1xuICAgICAgICBjb25zdCBzdHJlYW1GaWxlczogU3RyZWFtRmlsZUluZm9bXSA9IFtdO1xuICAgICAgICBmb3IgKGNvbnN0IG4gb2YgbmFtZXMpIHtcbiAgICAgICAgICAgIGlmIChleGNsdWRlZC5oYXMobikpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKG4uZW5kc1dpdGgoRklMRV9FWFRFTlNJT04pKSB7IGNvbnN0IHAgPSBwYXJzZUZpbGVOYW1lKG4pOyBpZiAocCkgYnVsa0ZpbGVzLnB1c2gocCk7IH1cbiAgICAgICAgICAgIGVsc2UgaWYgKG4uZW5kc1dpdGgoU1RSRUFNX0VYVEVOU0lPTikpIHsgY29uc3QgcCA9IHBhcnNlU3RyZWFtRmlsZU5hbWUobik7IGlmIChwKSBzdHJlYW1GaWxlcy5wdXNoKHApOyB9XG4gICAgICAgIH1cbiAgICAgICAgYnVsa0ZpbGVzLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgICAgICAgIGlmIChhLnRpbWVzdGFtcCAhPT0gYi50aW1lc3RhbXApIHJldHVybiBiLnRpbWVzdGFtcCAtIGEudGltZXN0YW1wO1xuICAgICAgICAgICAgcmV0dXJuIGEuZmlsZU5hbWUgPCBiLmZpbGVOYW1lICYmIDEgfHwgYS5maWxlTmFtZSA+IGIuZmlsZU5hbWUgJiYgLTEgfHwgMDtcbiAgICAgICAgfSk7XG4gICAgICAgIHNvcnQoc3RyZWFtRmlsZXMsIGYgPT4gZi50aW1lc3RhbXApO1xuICAgICAgICByZXR1cm4geyBidWxrRmlsZXMsIHN0cmVhbUZpbGVzIH07XG4gICAgfVxuXG4gICAgLy8gVGhyb3R0bGVkIG1hcmtlciBob3VzZWtlZXBpbmc6IGRlbGV0ZSBpbnB1dHMgd2hvc2UgcmVwbGFjZW1lbnQgb3V0cHV0cyBoYXZlIGxhbmRlZCAob3Igd2hvc2VcbiAgICAvLyBtYXJrZXIgaGFzIGFnZWQgb3V0KSBhbmQgcmV0aXJlIGZ1bGZpbGxlZCBtYXJrZXJzLiBUcmlnZ2VyZWQgZnJvbSBsaXN0RmlsZXMsIHNvIGl0J3MgZ2F0ZWQgdG9cbiAgICAvLyBhdm9pZCBhIGRlbGV0ZSBzdG9ybSB1bmRlciBoZWF2eSByZWFkcy5cbiAgICBwcml2YXRlIHByb2Nlc3NNYXJrZXJzID0gdGhyb3R0bGVGdW5jdGlvbigzMCAqIDEwMDAsIGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3Qgc3RvcmFnZSA9IGF3YWl0IHRoaXMuc3RvcmFnZSgpO1xuICAgICAgICBjb25zdCBuYW1lcyA9IGF3YWl0IHN0b3JhZ2UuZ2V0S2V5cygpO1xuICAgICAgICBjb25zdCBtYXJrZXJzID0gYXdhaXQgcmVhZERlbGV0ZU1hcmtlcnMoc3RvcmFnZSwgbmFtZXMpO1xuICAgICAgICBpZiAobWFya2Vycy5sZW5ndGgpIGF3YWl0IHByb2Nlc3NEZWxldGVNYXJrZXJzKHRoaXMubmFtZSwgc3RvcmFnZSwgbWFya2VycywgbmFtZXMpO1xuICAgIH0pO1xuXG4gICAgcHJpdmF0ZSBhc3luYyB3cml0ZUJ1bGtGaWxlKHJvd3M6IFJlY29yZDxzdHJpbmcsIHVua25vd24+W10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgY29uc3Qgc3RvcmFnZSA9IGF3YWl0IHRoaXMuc3RvcmFnZSgpO1xuICAgICAgICBjb25zdCB0aW1lc3RhbXAgPSBuZXh0RmlsZVRpbWUoKTtcbiAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgY29uc3QgdGltZXMgPSByb3dzLm1hcCgoKSA9PiBub3cpO1xuICAgICAgICBmb3IgKGNvbnN0IGJ1aWx0IG9mIGJ1aWxkRmlsZUJ1ZmZlcihyb3dzLCB0aW1lcykpIHtcbiAgICAgICAgICAgIGNvbnN0IG5hbWUgPSBuZXdGaWxlTmFtZSh0aW1lc3RhbXApO1xuICAgICAgICAgICAgYXdhaXQgc3RvcmFnZS5zZXQobmFtZSwgZW5jb2RlQ29tcHJlc3NlZEJsb2NrcyhidWlsdC5idWZmZXIpKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnRyaWdnZXJSZWJ1aWxkKCk7XG4gICAgICAgIHZvaWQgdGhpcy5tYXliZU1lcmdlKCk7XG4gICAgfVxuXG4gICAgLy8g4pSA4pSAIG1lcmdlIHBvbGljeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgICAvLyBDYWxsZWQgYm90aCBwZXJpb2RpY2FsbHkgKHZpc2liaWxpdHkgdGltZXIpIGFuZCBvbiB3cml0ZXMgKHdpdGggdGhlIHN0cmVhbU5lZWRzRm9sZCBnYXRlIHNvIGFcbiAgICAvLyBzbWFsbCB3cml0ZSBkb2Vzbid0IGRyYWcgdGhlIG1lcmdlIHRocm91Z2gpLiBUaGUgbWVyZ2VJbkZsaWdodCBjaGVjayBpbiB0cnlNZXJnZU5vdyBza2lwcyBhbnlcbiAgICAvLyBjYWxsIHRoYXQgYXJyaXZlcyB3aGlsZSBhIHByZXZpb3VzIG9uZSBpcyBzdGlsbCBydW5uaW5nIOKAlCBzbyA1LW1pbiB0aW1lciB0aWNrcyBkb24ndCBwaWxlIHVwLlxuICAgIHByaXZhdGUgYXN5bmMgbWF5YmVNZXJnZShvcHRzOiB7IG9ubHlJZlN0cmVhbUhlYXZ5PzogYm9vbGVhbiB9ID0ge30pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCFhd2FpdCB0aGlzLmF1dG9tYXRpY0NvbXBhY3Rpb25BbGxvd2VkKCkpIHJldHVybjtcbiAgICAgICAgaWYgKG9wdHMub25seUlmU3RyZWFtSGVhdnkgJiYgIXRoaXMuc3RyZWFtTmVlZHNGb2xkKCkpIHJldHVybjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudHJ5TWVyZ2VUaHJvdHRsZWQoKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGAke3RoaXMubmFtZX06IGJhY2tncm91bmQgbWVyZ2UgZmFpbGVkOiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgdGhlIFwid2UgZGlkbid0IG1lcmdlXCIgcmVzdWx0IGFuZCBsb2cgaXQgKHRocm90dGxlZCDigJQgc2VlIE1FUkdFX1NLSVBfTE9HX0lOVEVSVkFMX01TKS4gRm9yXG4gICAgLy8gbG9jayByZWFzb25zIHRoZSBsb2cgYW5kIHJlc3VsdCBpbmNsdWRlIHRoZSBob2xkZXIgYW5kIHRpbWUgdW50aWwgdGhlIGxvY2sgZ29lcyBzdGFsZS5cbiAgICBwcml2YXRlIGFzeW5jIG1lcmdlU2tpcChyZWFzb246IE1lcmdlU2tpcFJlYXNvbik6IFByb21pc2U8TWVyZ2VBdHRlbXB0UmVzdWx0PiB7XG4gICAgICAgIGxldCBsb2NrOiBNZXJnZUxvY2tJbmZvIHwgdW5kZWZpbmVkO1xuICAgICAgICBpZiAocmVhc29uID09PSBcInRhYkxvY2tIZWxkXCIpIHtcbiAgICAgICAgICAgIGxvY2sgPSBwZWVrTWVyZ2VMb2NrKHRoaXMubmFtZSk7XG4gICAgICAgIH0gZWxzZSBpZiAocmVhc29uID09PSBcImZpbGVMb2NrSGVsZFwiKSB7XG4gICAgICAgICAgICBsb2NrID0gYXdhaXQgcGVla01lcmdlRmlsZUxvY2soYXdhaXQgdGhpcy5zdG9yYWdlKCkpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChEYXRlLm5vdygpIC0gdGhpcy5sYXN0TWVyZ2VTa2lwTG9nTXMgPj0gTUVSR0VfU0tJUF9MT0dfSU5URVJWQUxfTVMpIHtcbiAgICAgICAgICAgIHRoaXMubGFzdE1lcmdlU2tpcExvZ01zID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgIGNvbnN0IGRldGFpbCA9IGxvY2sgJiYgYCAoaGVsZCBieSAke2xvY2suaG9sZGVySWR9LCBleHBpcmVzIGluICR7Zm9ybWF0VGltZShNYXRoLm1heCgwLCBsb2NrLmV4cGlyZXNJbk1zKSl9KWAgfHwgXCJcIjtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGAke2JsdWUodGhpcy5uYW1lKX0gJHttYWdlbnRhKFwibWVyZ2VcIil9IHNraXBwZWQ6ICR7cmVhc29ufSR7ZGV0YWlsfWApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IG1lcmdlZDogZmFsc2UsIHNraXBSZWFzb246IHJlYXNvbiwgbG9ja0hvbGRlcklkOiBsb2NrPy5ob2xkZXJJZCwgbG9ja0V4cGlyZXNJbk1zOiBsb2NrPy5leHBpcmVzSW5NcyB9O1xuICAgIH1cblxuICAgIC8vIEFjcXVpcmUgYm90aCBtZXJnZSBsb2NrcyAoc2FtZS10YWIgbWVyZ2VJbkZsaWdodCwgY3Jvc3MtdGFiIGxvY2FsU3RvcmFnZSwgY3Jvc3MtcHJvY2VzcyBmaWxlKSxcbiAgICAvLyBydW4gdGhlIHBhc3MsIHJlbGVhc2UuIFNraXBzICh3aXRoIHRoZSByZWFzb24pIGluc3RlYWQgb2Ygd2FpdGluZyB3aGVuIGFueSBvZiB0aGVtIGlzIGhlbGQuXG4gICAgcHJpdmF0ZSBhc3luYyBydW5Mb2NrZWRNZXJnZShydW46ICgpID0+IFByb21pc2U8TWVyZ2VBdHRlbXB0UmVzdWx0Pik6IFByb21pc2U8TWVyZ2VBdHRlbXB0UmVzdWx0PiB7XG4gICAgICAgIGlmICh0aGlzLm1lcmdlSW5GbGlnaHQpIHJldHVybiBhd2FpdCB0aGlzLm1lcmdlU2tpcChcIm1lcmdlSW5GbGlnaHRcIik7XG4gICAgICAgIGlmICghdHJ5QWNxdWlyZU1lcmdlTG9jayh0aGlzLm5hbWUsIHdyaXRlcklkKSkgcmV0dXJuIGF3YWl0IHRoaXMubWVyZ2VTa2lwKFwidGFiTG9ja0hlbGRcIik7XG4gICAgICAgIGNvbnN0IHN0b3JhZ2UgPSBhd2FpdCB0aGlzLnN0b3JhZ2UoKTtcbiAgICAgICAgY29uc3QgaGF2ZUZpbGVMb2NrID0gYXdhaXQgdHJ5QWNxdWlyZU1lcmdlRmlsZUxvY2soc3RvcmFnZSwgd3JpdGVySWQpO1xuICAgICAgICBpZiAoIWhhdmVGaWxlTG9jaykge1xuICAgICAgICAgICAgcmVsZWFzZU1lcmdlTG9jayh0aGlzLm5hbWUsIHdyaXRlcklkKTtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLm1lcmdlU2tpcChcImZpbGVMb2NrSGVsZFwiKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1lcmdlSW5GbGlnaHQgPSB0cnVlO1xuICAgICAgICBjb25zdCBzdG9wSGVhcnRiZWF0ID0gc3RhcnRNZXJnZUZpbGVMb2NrSGVhcnRiZWF0KHN0b3JhZ2UsIHdyaXRlcklkKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBydW4oKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIHN0b3BIZWFydGJlYXQoKTtcbiAgICAgICAgICAgIGF3YWl0IHJlbGVhc2VNZXJnZUZpbGVMb2NrKHN0b3JhZ2UsIHdyaXRlcklkKTtcbiAgICAgICAgICAgIHJlbGVhc2VNZXJnZUxvY2sodGhpcy5uYW1lLCB3cml0ZXJJZCk7XG4gICAgICAgICAgICB0aGlzLm1lcmdlSW5GbGlnaHQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRoZSBiYWNrZ3JvdW5kIHBhdGggKG1heWJlTWVyZ2UpIGdvZXMgdGhyb3VnaCB0aGlzIHNvIHdyaXRlIGJ1cnN0cyBjb2FsZXNjZTsgZXhwbGljaXQgY2FsbGVycyB1c2VcbiAgICAvLyB0cnlNZXJnZU5vdyBkaXJlY3RseSBhbmQgZ2V0IHRoZSBwZXItY2FsbCByZXN1bHQuXG4gICAgcHJpdmF0ZSB0cnlNZXJnZVRocm90dGxlZCA9IHRocm90dGxlRnVuY3Rpb24oMTAwMCwgYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCB0aGlzLnRyeU1lcmdlTm93KCk7XG4gICAgfSk7XG5cbiAgICBwdWJsaWMgYXN5bmMgdHJ5TWVyZ2VOb3coKTogUHJvbWlzZTxNZXJnZUF0dGVtcHRSZXN1bHQ+IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucnVuTG9ja2VkTWVyZ2UoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgbWVyZ2VkID0gYXdhaXQgdGhpcy50ZXN0TWVyZ2VJTlRFUk5BTF9ET19OT1RfQ0FMTCgpO1xuICAgICAgICAgICAgcmV0dXJuIHsgbWVyZ2VkIH07XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBjb21wYWN0KCk6IFByb21pc2U8TWVyZ2VBdHRlbXB0UmVzdWx0PiB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnJ1bkxvY2tlZE1lcmdlKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZmx1c2hQZW5kaW5nKCk7XG4gICAgICAgICAgICBzeW5jQnJvYWRjYXN0U2VhbCh0aGlzLm5hbWUpO1xuICAgICAgICAgICAgdGhpcy5zdHJlYW1GaWxlTmFtZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGNvbnN0IHsgYnVsa0ZpbGVzLCBzdHJlYW1GaWxlcyB9ID0gYXdhaXQgdGhpcy5saXN0RmlsZXMoKTtcbiAgICAgICAgICAgIGlmIChidWxrRmlsZXMubGVuZ3RoICsgc3RyZWFtRmlsZXMubGVuZ3RoIDwgMSkgcmV0dXJuIGF3YWl0IHRoaXMubWVyZ2VTa2lwKFwibm90aGluZ1RvTWVyZ2VcIik7XG4gICAgICAgICAgICAvLyBjb21wYWN0KCkgZm9sZHMgZXZlcnkgZmlsZSDihpIgbm8gb2xkZXIgZGF0YSBzdXJ2aXZlcyBvdXRzaWRlIGl0IOKGkiBzdXJ2aXZpbmcgdG9tYnN0b25lc1xuICAgICAgICAgICAgLy8gY2FuIGJlIGRyb3BwZWQgKG5vdGhpbmcgbGVmdCB0byBzdXBwcmVzcykuXG4gICAgICAgICAgICBjb25zdCBtZXJnZWQgPSBhd2FpdCB0aGlzLm1lcmdlRmlsZVNldChidWxrRmlsZXMsIHN0cmVhbUZpbGVzLCB0cnVlKTtcbiAgICAgICAgICAgIHJldHVybiB7IG1lcmdlZCB9O1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgbWVyZ2UodGltZUxvOiBudW1iZXIsIHRpbWVIaTogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aW1lSGkgPj0gRGF0ZS5ub3coKSkgeyBzeW5jQnJvYWRjYXN0U2VhbCh0aGlzLm5hbWUpOyB0aGlzLnN0cmVhbUZpbGVOYW1lID0gdW5kZWZpbmVkOyB9XG4gICAgICAgIGNvbnN0IHsgYnVsa0ZpbGVzLCBzdHJlYW1GaWxlcyB9ID0gYXdhaXQgdGhpcy5saXN0RmlsZXMoKTtcbiAgICAgICAgY29uc3QgaGVhZGVycyA9IGF3YWl0IFByb21pc2UuYWxsKGJ1bGtGaWxlcy5tYXAoZiA9PiB0aGlzLnJlYWRCdWxrSGVhZGVyKGYuZmlsZU5hbWUpKSk7XG4gICAgICAgIGNvbnN0IHNlbEJ1bGsgPSBidWxrRmlsZXMuZmlsdGVyKChmLCBpKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBoID0gaGVhZGVyc1tpXTtcbiAgICAgICAgICAgIGlmICghaCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgaWYgKCFoLm1heFRpbWUgJiYgIWgubWluVGltZSkgcmV0dXJuIHRpbWVMbyA8PSAwO1xuICAgICAgICAgICAgcmV0dXJuIGgubWluVGltZSA8PSB0aW1lSGkgJiYgaC5tYXhUaW1lID49IHRpbWVMbztcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHNlbFN0cmVhbSA9IHN0cmVhbUZpbGVzLmZpbHRlcihmID0+XG4gICAgICAgICAgICBmLnRpbWVzdGFtcCA8PSB0aW1lSGkgJiYgZi50aW1lc3RhbXAgKyBidWxrRGF0YWJhc2UyVGltaW5nLnN0cmVhbVNlYWxBZ2VNcyA+PSB0aW1lTG8pO1xuICAgICAgICBpZiAoc2VsQnVsay5sZW5ndGggKyBzZWxTdHJlYW0ubGVuZ3RoIDwgMikgcmV0dXJuO1xuICAgICAgICBhd2FpdCB0aGlzLm1lcmdlRmlsZVNldChzZWxCdWxrLCBzZWxTdHJlYW0sIHRpbWVMbyA8PSAwKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHJlYWRCdWxrSGVhZGVyKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPEJ1bGtIZWFkZXJJbmZvIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5zdG9yYWdlKCk7XG4gICAgICAgICAgICBjb25zdCByYXcgPSBhd2FpdCBtYWtlUmF3R2V0UmFuZ2Uoc3RvcmFnZSwgZmlsZU5hbWUpO1xuICAgICAgICAgICAgY29uc3QgZmlsZUlkID0gbnVsbEpvaW4odGhpcy5uYW1lLCBmaWxlTmFtZSk7XG4gICAgICAgICAgICBjb25zdCBvcGVuZWQgPSBhd2FpdCBibG9ja0NhY2hlLm9wZW4oZmlsZUlkLCByYXcuc2l6ZSwgcmF3LnJhd0dldFJhbmdlKTtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBsb2FkQnVsa0hlYWRlcihvcGVuZWQuZ2V0UmFuZ2UsIG9wZW5lZC51bmNvbXByZXNzZWRTaXplKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBmaWxlTG9naWNhbFNpemUoZmlsZU5hbWU6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5zdG9yYWdlKCk7XG4gICAgICAgICAgICBjb25zdCByYXcgPSBhd2FpdCBtYWtlUmF3R2V0UmFuZ2Uoc3RvcmFnZSwgZmlsZU5hbWUpO1xuICAgICAgICAgICAgY29uc3QgZmlsZUlkID0gbnVsbEpvaW4odGhpcy5uYW1lLCBmaWxlTmFtZSk7XG4gICAgICAgICAgICBjb25zdCBvcGVuZWQgPSBhd2FpdCBibG9ja0NhY2hlLm9wZW4oZmlsZUlkLCByYXcuc2l6ZSwgcmF3LnJhd0dldFJhbmdlKTtcbiAgICAgICAgICAgIHJldHVybiBvcGVuZWQudW5jb21wcmVzc2VkU2l6ZTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gQSBidWxrIGZpbGUgdGhhdCB3b24ndCBsb2FkIGlzIGVpdGhlciBhbiBpbi1wcm9ncmVzcyB3cml0ZSAocmVjZW50KSBvciBhIGNyYXNoZWQgcGFydGlhbCB3cml0ZVxuICAgIC8vIChzdGFsZSkuIFdhcm4gd2hpbGUgcmVjZW50LCBkZWxldGUgb25jZSBjbGVhcmx5IGFiYW5kb25lZCDigJQgZGVsZXRpbmcgaXMgc2FmZSBiZWNhdXNlIHRoZSB3cml0ZVxuICAgIC8vIHByb3RvY29sIGFsd2F5cyBsYW5kcyB0aGUgcmVwbGFjZW1lbnQgYmVmb3JlIHJlbW92aW5nIHRoZSBmaWxlIGl0IHN1cGVyc2VkZXMuXG4gICAgcHJpdmF0ZSBhc3luYyBoYW5kbGVVbnJlYWRhYmxlRmlsZShmaWxlOiBCdWxrRmlsZUluZm8sIG1lc3NhZ2U6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBhZ2VNcyA9IERhdGUubm93KCkgLSBmaWxlLnRpbWVzdGFtcDtcbiAgICAgICAgaWYgKGFnZU1zID4gU1RBTEVfREVMRVRFX01TKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYCR7dGhpcy5uYW1lfTogZGVsZXRpbmcgc3RhbGUgdW5yZWFkYWJsZSBidWxrIGZpbGUgJHtmaWxlLmZpbGVOYW1lfSAoJHtNYXRoLnJvdW5kKGFnZU1zIC8gODY0MDAwMDApfWQgb2xkKTogJHttZXNzYWdlfWApO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdG9yYWdlID0gYXdhaXQgdGhpcy5zdG9yYWdlKCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgc3RvcmFnZS5yZW1vdmUoZmlsZS5maWxlTmFtZSk7XG4gICAgICAgICAgICB9IGNhdGNoIChyZW1vdmVFcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgJHt0aGlzLm5hbWV9OiBmYWlsZWQgdG8gZGVsZXRlICR7ZmlsZS5maWxlTmFtZX06ICR7KHJlbW92ZUVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUud2FybihgJHt0aGlzLm5hbWV9OiBza2lwcGluZyB1bnJlYWRhYmxlIGJ1bGsgZmlsZSAke2ZpbGUuZmlsZU5hbWV9IChyZWNlbnQgLSBtYXkgYmUgaW4tcHJvZ3Jlc3MpOiAke21lc3NhZ2V9YCk7XG4gICAgfVxuXG4gICAgLy8gVGhlIG9uZSBtZXJnZSBwcmltaXRpdmUuIFJlYWRzICsgcGxhbnMgKyB3cml0ZXMgb3V0cHV0cyBiZWZvcmUgZGVsZXRpbmcgYW55IGlucHV0LCBzbyBhIGNyYXNoXG4gICAgLy8gbGVhdmVzIGR1cGxpY2F0ZXMgKG5leHQgbWVyZ2UgZGVkdXBlcykgcmF0aGVyIHRoYW4gYSBnYXAuIEFmdGVyIHRoZSBmaWxlIHNldCBjaGFuZ2VzIG9uIGRpc2ssXG4gICAgLy8gd2UgdHJpZ2dlciBhbiBpbmRleCByZWJ1aWxkICsgYXRvbWljIHN3YXA7IG9uY2Ugc3dhcCBjb21wbGV0ZXMsIHRoZSBjb25zdW1lZCBmaWxlcycgYmxvY2stY2FjaGVcbiAgICAvLyBlbnRyaWVzIGFyZSBldmljdGVkIChubyBjb25zdW1lciBjYW4gYXNrIGZvciB0aGVtIG5vdykuXG4gICAgLy9cbiAgICAvLyBTZXJpYWxpemVkOiBmb2xkT3duU3RyZWFtICsgbWVyZ2UodGltZUxvLCB0aW1lSGkpICsgdGVzdE1lcmdlJ3MgcnVuTWVyZ2UgYWxsIGhpdCB0aGlzOyB0aGUgbG9ja1xuICAgIC8vIGNvdmVycyB0cnlNZXJnZU5vdy9jb21wYWN0IGJ1dCB0aG9zZSB0d28gcGF0aHMgYnlwYXNzIGl0LiBydW5JblNlcmlhbCBxdWV1ZXMgc28gdGhleSBuZXZlclxuICAgIC8vIGNvbGxpZGUgb24gdGhlIGZpbGUgc2V0LlxuICAgIHByaXZhdGUgbWVyZ2VGaWxlU2V0ID0gcnVuSW5TZXJpYWwoYXN5bmMgKGJ1bGtGaWxlczogQnVsa0ZpbGVJbmZvW10sIHN0cmVhbUZpbGVzOiBTdHJlYW1GaWxlSW5mb1tdLCBpbmNsdWRlc09sZGVzdCA9IGZhbHNlLCBmb3JjZURlbGV0ZVN0cmVhbXMgPSBmYWxzZSk6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICAgICAgICB0aGlzLnJlYWRlci5iZWdpbkNvbXBhY3Rpb24oKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLm1lcmdlRmlsZVNldElubmVyKGJ1bGtGaWxlcywgc3RyZWFtRmlsZXMsIGluY2x1ZGVzT2xkZXN0LCBmb3JjZURlbGV0ZVN0cmVhbXMpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgdGhpcy5yZWFkZXIuZW5kQ29tcGFjdGlvbigpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBwcml2YXRlIGFzeW5jIG1lcmdlRmlsZVNldElubmVyKGJ1bGtGaWxlczogQnVsa0ZpbGVJbmZvW10sIHN0cmVhbUZpbGVzOiBTdHJlYW1GaWxlSW5mb1tdLCBpbmNsdWRlc09sZGVzdDogYm9vbGVhbiwgZm9yY2VEZWxldGVTdHJlYW1zOiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGNvbnN0IHN0b3JhZ2UgPSBhd2FpdCB0aGlzLnN0b3JhZ2UoKTtcbiAgICAgICAgY29uc3QgdGltZXN0YW1wID0gbmV4dEZpbGVUaW1lKCk7XG5cbiAgICAgICAgLy8gVGhlIGNhbGxlcidzIGJ1bGtGaWxlcyBjYW1lIGZyb20gYSBgbGlzdEZpbGVzKClgIHNuYXBzaG90LiBCZXR3ZWVuIHRoZW4gYW5kIG5vdyBhbnkgZmlsZVxuICAgICAgICAvLyBjb3VsZCBiZSBnb25lIChhbm90aGVyIHRhYidzIGRlZmVycmVkIGRlbGV0ZSwgbWFudWFsIGNsZWFudXApLiBUaGUgc3ViQ2FjaGVzIHJlYWRlciBmb3IgYVxuICAgICAgICAvLyBkZWxldGVkIGZpbGUgaXMgc2lsZW50bHkgc3RhbGUg4oCUIGl0cyBpbi1tZW1vcnkgbWV0YWRhdGEgc3RpbGwgcmVzb2x2ZXMsIGJ1dCB0aGUgdmVyeSBuZXh0XG4gICAgICAgIC8vIGdldFJhbmdlIGFnYWluc3QgZGlzayB0aHJvd3MuIFJlLXZlcmlmeSBleGlzdGVuY2UgdXAtZnJvbnQgYW5kIGRyb3AgdGhlIGNhY2hlIGVudHJ5IGZvclxuICAgICAgICAvLyBhbnl0aGluZyB0aGF0IHZhbmlzaGVkLCBzbyB3ZSBkb24ndCBldmVuIHRyeSB0byBwbGFuIGFyb3VuZCBhIGdob3N0IGZpbGUuXG4gICAgICAgIGNvbnN0IHZlcmlmaWVkQnVsa0ZpbGVzID0gKGF3YWl0IFByb21pc2UuYWxsKGJ1bGtGaWxlcy5tYXAoYXN5bmMgZiA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGluZm8gPSBhd2FpdCBzdG9yYWdlLmdldEluZm8oZi5maWxlTmFtZSk7XG4gICAgICAgICAgICAgICAgaWYgKCFpbmZvKSB7IHRoaXMuc3ViQ2FjaGVzLmJ1bGsuZGVsZXRlKGYuZmlsZU5hbWUpOyByZXR1cm4gdW5kZWZpbmVkOyB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGY7XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICB0aGlzLnN1YkNhY2hlcy5idWxrLmRlbGV0ZShmLmZpbGVOYW1lKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KSkpLmZpbHRlcigoZik6IGYgaXMgQnVsa0ZpbGVJbmZvID0+IGYgIT09IHVuZGVmaW5lZCk7XG4gICAgICAgIGJ1bGtGaWxlcyA9IHZlcmlmaWVkQnVsa0ZpbGVzO1xuXG4gICAgICAgIGNvbnN0IGNvbnN1bWVkQnVsazogQnVsa0ZpbGVJbmZvW10gPSBbXTtcbiAgICAgICAgY29uc3QgYnVsa1JlYWRlcnM6IEJhc2VCdWxrRGF0YWJhc2VSZWFkZXJbXSA9IFtdO1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChidWxrRmlsZXMubWFwKGFzeW5jIGYgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCByID0gYXdhaXQgbG9hZEZpbGVSZWFkZXIodGhpcy5uYW1lLCBzdG9yYWdlLCBmLCB0aGlzLnN1YkNhY2hlcy5idWxrKTtcbiAgICAgICAgICAgICAgICBidWxrUmVhZGVycy5wdXNoKHIpO1xuICAgICAgICAgICAgICAgIGNvbnN1bWVkQnVsay5wdXNoKGYpO1xuICAgICAgICAgICAgfSBjYXRjaCB7IC8qIG1pc3Npbmcgb3IgY29ycnVwdCDigJQgc2tpcDsgaXRzIGRhdGEgbGl2ZXMgaW4gYW5vdGhlciBmaWxlICovIH1cbiAgICAgICAgfSkpO1xuXG4gICAgICAgIGNvbnN0IHN0cmVhbURhdGEgPSBhd2FpdCBsb2FkU3RyZWFtRW50cmllcyh0aGlzLm5hbWUsIHN0b3JhZ2UsIHN0cmVhbUZpbGVzLCB0aGlzLnN1YkNhY2hlcy5zdHJlYW0pO1xuICAgICAgICBjb25zdCBvcmRlcmVkID0gb3JkZXJTdHJlYW1FbnRyaWVzKHN0cmVhbURhdGEuZW50cmllcyk7XG4gICAgICAgIGNvbnN0IHN0cmVhbVJlYWRlciA9IG9yZGVyZWQubGVuZ3RoID8gc3RyZWFtUmVhZGVyRnJvbUVudHJpZXMob3JkZXJlZCwgMCkucmVhZGVyIDogdW5kZWZpbmVkO1xuXG4gICAgICAgIGNvbnN0IHJlYWRlcnMgPSBzdHJlYW1SZWFkZXIgPyBbc3RyZWFtUmVhZGVyLCAuLi5idWxrUmVhZGVyc10gOiBidWxrUmVhZGVycztcbiAgICAgICAgY29uc3QgcmVhZGVyTmFtZXMgPSBzdHJlYW1SZWFkZXIgPyBbXCIoc3RyZWFtcylcIiwgLi4uY29uc3VtZWRCdWxrLm1hcChmID0+IGYuZmlsZU5hbWUpXSA6IGNvbnN1bWVkQnVsay5tYXAoZiA9PiBmLmZpbGVOYW1lKTtcbiAgICAgICAgaWYgKCFyZWFkZXJzLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIGNvbnN0IGlucHV0cyA9IFtcbiAgICAgICAgICAgIC4uLmF3YWl0IFByb21pc2UuYWxsKGNvbnN1bWVkQnVsay5tYXAoYXN5bmMgZiA9PiAoeyBuYW1lOiBmLmZpbGVOYW1lLCBzaXplOiAoYXdhaXQgc3RvcmFnZS5nZXRJbmZvKGYuZmlsZU5hbWUpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCkpPy5zaXplID8/IDAgfSkpKSxcbiAgICAgICAgICAgIC4uLnN0cmVhbUZpbGVzLm1hcChmID0+ICh7IG5hbWU6IGYuZmlsZU5hbWUsIHNpemU6IHN0cmVhbURhdGEuc2l6ZXMuZ2V0KGYuZmlsZU5hbWUpID8/IDAgfSkpLFxuICAgICAgICBdO1xuICAgICAgICBjb25zdCBpblRvdGFsID0gaW5wdXRzLnJlZHVjZSgoYSwgZikgPT4gYSArIGYuc2l6ZSwgMCk7XG4gICAgICAgIGNvbnN0IG1lcmdlU3RhcnRNcyA9IERhdGUubm93KCk7XG4gICAgICAgIC8vIENvbGxlY3QgZWFjaCBzdGVwIGluc3RlYWQgb2YgbG9nZ2luZyBpdCBsaXZlOyBlbWl0dGVkIGF0IHRoZSBlbmQgYXMgb25lXG4gICAgICAgIC8vIGV4cGFuZGVkIGNvbnNvbGUuZ3JvdXAgc28gYSBtZXJnZSB0YWtlcyBvbmUgY29sbGFwc2libGUgYmxvY2ssIG5vdCBhXG4gICAgICAgIC8vIHNjcmVlbmZ1bCAoYW5kIG5ldmVyIHRoZSBwZXItZmlsZSBuYW1lIGR1bXAgaXQgdXNlZCB0byBzcGV3KS5cbiAgICAgICAgY29uc3Qgc3RlcHM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIC8vIEVhY2ggc3RlcCByZWNvcmRzIHRoZSB0aW1lIHNwZW50IHNpbmNlIHRoZSBwcmV2aW91cyBzdGVwIGluIGJsdWUgYXQgdGhlIGZyb250LCBzbyBjYWxsZXJzIGNhblxuICAgICAgICAvLyBqdXN0IGRlc2NyaWJlIHdoYXQgdGhleSBkaWQgYW5kIG5vdCBib3RoZXIgbWVhc3VyaW5nL2Zvcm1hdHRpbmcgZWxhcHNlZCB0aW1lcyB0aGVtc2VsdmVzLlxuICAgICAgICBsZXQgbGFzdFN0ZXBNcyA9IG1lcmdlU3RhcnRNcztcbiAgICAgICAgY29uc3QgbG9nID0gKGxpbmU6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgIGxldCBsaW5lRm9ybWF0dGVkID0gYCR7Ymx1ZShmb3JtYXRUaW1lKG5vdyAtIGxhc3RTdGVwTXMpKX0gJHtsaW5lfWA7XG4gICAgICAgICAgICAvLyBETyBOT1QgUkVNT1ZFIFRISVMgTE9HISBPYnZpb3VzbHksIHdlIHNob3VsZCBiZSBsb2dnaW5nIGFzIHdlIHJ1biwgb3IgZWxzZSB3ZSBkb24ndCBnZXQgcHJvZ3Jlc3MuIFdoeSB3b3VsZCB3ZSBzdG9wIGdldHRpbmcgcHJvZ3Jlc3M/IFByb2dyZXNzIGlzIGFsbW9zdCBtb3JlIGltcG9ydGFudCB0aGFuIHNob3dpbmcgYSBzdW1tYXJ5IGF0IHRoZSBlbmQuLi5cbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGxpbmVGb3JtYXR0ZWQpO1xuICAgICAgICAgICAgc3RlcHMucHVzaChsaW5lRm9ybWF0dGVkKTtcbiAgICAgICAgICAgIGxhc3RTdGVwTXMgPSBub3c7XG4gICAgICAgIH07XG4gICAgICAgIGxvZyhgJHttYWdlbnRhKFwicmVhZFwiKX06ICR7aW5wdXRzLmxlbmd0aH0gaW5wdXQgZmlsZShzKSwgJHtmbXRCeXRlcyhpblRvdGFsKX1gKTtcblxuICAgICAgICBjb25zdCBuZXdOYW1lczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgY29uc3QgbWVyZ2VSZXN1bHQgPSBhd2FpdCBydW5QbGFubmVkTWVyZ2Uoe1xuICAgICAgICAgICAgc291cmNlczogcmVhZGVycyxcbiAgICAgICAgICAgIHNvdXJjZU5hbWVzOiByZWFkZXJOYW1lcyxcbiAgICAgICAgICAgIGNvbGxlY3Rpb25OYW1lOiB0aGlzLm5hbWUsXG4gICAgICAgICAgICBsb2csXG4gICAgICAgICAgICB3cml0ZUZpbGU6IGFzeW5jIChkYXRhKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZm5hbWUgPSBuZXdGaWxlTmFtZSh0aW1lc3RhbXApO1xuICAgICAgICAgICAgICAgIGF3YWl0IHN0b3JhZ2Uuc2V0KGZuYW1lLCBlbmNvZGVDb21wcmVzc2VkQmxvY2tzKGRhdGEpKTtcbiAgICAgICAgICAgICAgICBuZXdOYW1lcy5wdXNoKGZuYW1lKTtcbiAgICAgICAgICAgICAgICBjb25zdCBzaXplID0gKGF3YWl0IHN0b3JhZ2UuZ2V0SW5mbyhmbmFtZSkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKSk/LnNpemUgPz8gMDtcbiAgICAgICAgICAgICAgICByZXR1cm4geyBuYW1lOiBmbmFtZSwgc2l6ZSB9O1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgY2FycmllZERlbGV0ZXMgPSBpbmNsdWRlc09sZGVzdCA/IDAgOiBtZXJnZVJlc3VsdC5jYXJyaWVkRGVsZXRlcy5zaXplO1xuICAgICAgICBjb25zdCBvdXROYW1lcyA9IFsuLi5uZXdOYW1lc107XG4gICAgICAgIGlmIChjYXJyaWVkRGVsZXRlcykge1xuICAgICAgICAgICAgY29uc3QgY2FycnlOYW1lID0gYHN0cmVhbV8ke0RhdGUubm93KCl9XyR7TWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMiwgMTApfSR7U1RSRUFNX0VYVEVOU0lPTn1gO1xuICAgICAgICAgICAgYXdhaXQgc3RvcmFnZS5zZXQoY2FycnlOYW1lLCBmcmFtZURlbGV0ZXMoWy4uLm1lcmdlUmVzdWx0LmNhcnJpZWREZWxldGVzXS5tYXAoKFtrZXksIHRpbWVdKSA9PiAoeyB0aW1lLCBrZXkgfSkpKSk7XG4gICAgICAgICAgICBvdXROYW1lcy5wdXNoKGNhcnJ5TmFtZSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBvdXRwdXRzID0gYXdhaXQgUHJvbWlzZS5hbGwob3V0TmFtZXMubWFwKGFzeW5jIG4gPT4gKHsgbmFtZTogbiwgc2l6ZTogKGF3YWl0IHN0b3JhZ2UuZ2V0SW5mbyhuKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpKT8uc2l6ZSA/PyAwIH0pKSk7XG4gICAgICAgIGNvbnN0IG91dFRvdGFsID0gb3V0cHV0cy5yZWR1Y2UoKGEsIGYpID0+IGEgKyBmLnNpemUsIDApO1xuICAgICAgICBsb2coYCR7bWFnZW50YShcIndyb3RlXCIpfTogJHtvdXRwdXRzLmxlbmd0aH0gb3V0cHV0IGZpbGUocyksICR7Zm10Qnl0ZXMob3V0VG90YWwpfSR7Y2FycmllZERlbGV0ZXMgPyBgLCAke2NhcnJpZWREZWxldGVzfSB0b21ic3RvbmVzIGNhcnJpZWRgIDogXCJcIn1gKTtcblxuICAgICAgICBjb25zb2xlLmdyb3VwKGAke2JsdWUodGhpcy5uYW1lKX0gJHttYWdlbnRhKFwibWVyZ2VcIil9OiAke2ZtdEJ5dGVzKGluVG90YWwpfSAtPiAke2ZtdEJ5dGVzKG91dFRvdGFsKX0gKCR7aW5wdXRzLmxlbmd0aH0tPiR7b3V0cHV0cy5sZW5ndGh9IGZpbGVzKSBpbiAke2Zvcm1hdFRpbWUoRGF0ZS5ub3coKSAtIG1lcmdlU3RhcnRNcyl9YCk7XG4gICAgICAgIGZvciAoY29uc3QgbGluZSBvZiBzdGVwcykgY29uc29sZS5sb2cobGluZSk7XG4gICAgICAgIGNvbnNvbGUuZ3JvdXBFbmQoKTtcblxuICAgICAgICAvLyBPbmx5IHRoZSBzb3VyY2VzIHJ1blBsYW5uZWRNZXJnZSBhY3R1YWxseSB1c2VkIGNhbiBiZSByZXRpcmVkIOKAlCBhIHNvdXJjZSBpdCBkcm9wcGVkIG1pZC1wbGFuXG4gICAgICAgIC8vIChmaWxlIGdvbmUsIGNvcnJ1cHRpb24pIHN0aWxsIGhvbGRzIGRhdGEgd2UgY291bGRuJ3QgbWVyZ2UgaW4sIHNvIGxlYXZlIGl0IG9uIGRpc2sgYW5kIGxldCBhXG4gICAgICAgIC8vIGZ1dHVyZSBtZXJnZSByZS1hdHRlbXB0IGl0LlxuICAgICAgICBjb25zdCB1c2VkQ29uc3VtZWRCdWxrID0gY29uc3VtZWRCdWxrLmZpbHRlcihmID0+IG1lcmdlUmVzdWx0LnVzZWRTb3VyY2VOYW1lcy5oYXMoZi5maWxlTmFtZSkpO1xuICAgICAgICBjb25zdCB1c2VkU3RyZWFtRmlsZXMgPSBzdHJlYW1GaWxlcy5maWx0ZXIoZiA9PiBtZXJnZVJlc3VsdC51c2VkU291cmNlTmFtZXMuaGFzKGYuZmlsZU5hbWUpIHx8IG1lcmdlUmVzdWx0LnVzZWRTb3VyY2VOYW1lcy5oYXMoXCIoc3RyZWFtcylcIikpO1xuICAgICAgICAvLyBBIHN0cmVhbSBtYXkgc3RpbGwgYmUgYXBwZW5kZWQgdG8gYWZ0ZXIgd2UgcmVhZCBpdCAodGhlIHdyaXRlciBoYXNuJ3Qgc2VhbGVkL21vdmVkIG9uKTsgb25seVxuICAgICAgICAvLyByZXRpcmUgc3RyZWFtcyBjYW5EZWxldGVTdHJlYW0gY2xlYXJzIOKAlCB0aGUgcmVzdCBzdGF5IGxpdmUgYW5kIGEgbGF0ZXIgbWVyZ2UgcmUtZm9sZHMgdGhlbVxuICAgICAgICAvLyBvbmNlIHNlYWxlZC4gQnVsayBmaWxlcyBhcmUgaW1tdXRhYmxlLCBzbyBhIHVzZWQgb25lIGlzIGFsd2F5cyBzYWZlIHRvIHJldGlyZS5cbiAgICAgICAgY29uc3QgZGVsZXRhYmxlU3RyZWFtczogc3RyaW5nW10gPSBbXTtcbiAgICAgICAgZm9yIChjb25zdCBmIG9mIHVzZWRTdHJlYW1GaWxlcykge1xuICAgICAgICAgICAgaWYgKGF3YWl0IHRoaXMuY2FuRGVsZXRlU3RyZWFtKGYsIERhdGUubm93KCksIHN0cmVhbURhdGEuc2l6ZXMsIGZvcmNlRGVsZXRlU3RyZWFtcykpIGRlbGV0YWJsZVN0cmVhbXMucHVzaChmLmZpbGVOYW1lKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBkZWxldGVGaWxlcyA9IFsuLi51c2VkQ29uc3VtZWRCdWxrLm1hcChmID0+IGYuZmlsZU5hbWUpLCAuLi5kZWxldGFibGVTdHJlYW1zXTtcblxuICAgICAgICAvLyBXcml0ZSBhIGRlbGV0aW9uIG1hcmtlciBpbnN0ZWFkIG9mIGRlbGV0aW5nIGlubGluZS4gRnJvbSB0aGUgbmV4dCByZWFkIG9uLCBsaXN0RmlsZXMgaGlkZXNcbiAgICAgICAgLy8gdGhlc2UgaW5wdXRzIChzbyB0aGV5J3JlIG5ldmVyIHJlLW1lcmdlZCDigJQgdGhlIGxvb3AgZml4KSwgYW5kIHByb2Nlc3NNYXJrZXJzIHJlbW92ZXMgdGhlbVxuICAgICAgICAvLyBwaHlzaWNhbGx5IG9uY2UgdGhlIG91dHB1dHMgaGF2ZSBsYW5kZWQgb3IgdGhlIG1hcmtlciBhZ2VzIG91dC4gTWFya2VyIEJFRk9SRSB0aGUgcmVidWlsZCBzb1xuICAgICAgICAvLyB0aGUgZnJlc2hseS1zd2FwcGVkIGluZGV4IGFscmVhZHkgZXhjbHVkZXMgdGhlIHJldGlyZWQgaW5wdXRzLlxuICAgICAgICBpZiAoZGVsZXRlRmlsZXMubGVuZ3RoKSBhd2FpdCB3cml0ZURlbGV0ZU1hcmtlcihzdG9yYWdlLCB7IGRlbGV0ZUZpbGVzLCByZXBsYWNlZEJ5OiBvdXROYW1lcyB9KTtcblxuICAgICAgICAvLyBSZWJ1aWxkICsgc3dhcCBzbyB0aGUgaW5kZXggc2VlcyB0aGUgbmV3IG91dHB1dHMgYW5kIGRyb3BzIHRoZSByZXRpcmVkIGlucHV0cy4gQmxvY2stY2FjaGVcbiAgICAgICAgLy8gZXZpY3Rpb24gZm9yIHRoZSBkcm9wcGVkIGlucHV0cyBoYXBwZW5zIGhlcmUgKHRoZXkncmUgbm8gbG9uZ2VyIGluIHRoZSBuZXcgaW5kZXgncyBmaWxlU2V0KS5cbiAgICAgICAgYXdhaXQgdGhpcy50cmlnZ2VyUmVidWlsZCgpO1xuICAgICAgICByZXR1cm4gbmV3TmFtZXMubGVuZ3RoID4gMCB8fCBjYXJyaWVkRGVsZXRlcyA+IDA7XG4gICAgfVxuXG4gICAgLy8gQSBzdHJlYW0gaXMgc2FmZSB0byBkZWxldGUgaWZmIG5vIHdyaXRlciB3aWxsIGFwcGVuZCB0byBpdCBhZ2FpbjogaXQncyBhZ2VkIHBhc3QgdGhlIHNlYWwgYWdlXG4gICAgLy8gKHdyaXRlciBoYXMgcHJvdmFibHkgc3dpdGNoZWQgZmlsZXMpIE9SIGNyb3NzLXRhYiBzeW5jIGlzIG9uIEFORCBpdHMgc2l6ZSBkaWRuJ3QgY2hhbmdlIHdoaWxlXG4gICAgLy8gd2UgcmVhZCBpdC4gRWxzZSBsZWF2ZSBpdCDigJQgdGhlIGRhdGEgaXMgYWxzbyBpbiB0aGUgbmV3IGJ1bGsgZmlsZTsgYSBsYXRlciBtZXJnZSBkZWxldGVzIGl0XG4gICAgLy8gb25jZSBhZ2VkLlxuICAgIHByaXZhdGUgYXN5bmMgY2FuRGVsZXRlU3RyZWFtKGY6IFN0cmVhbUZpbGVJbmZvLCBub3c6IG51bWJlciwgc2l6ZXM6IE1hcDxzdHJpbmcsIG51bWJlcj4sIGZvcmNlID0gZmFsc2UpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgaWYgKG5vdyAtIGYudGltZXN0YW1wID49IGJ1bGtEYXRhYmFzZTJUaW1pbmcuc3RyZWFtU2VhbEFnZU1zKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgaWYgKCFpc1N5bmNTdXBwb3J0ZWQoKSAmJiAhZm9yY2UpIHJldHVybiBmYWxzZTtcbiAgICAgICAgY29uc3QgcmVhZFNpemUgPSBzaXplcy5nZXQoZi5maWxlTmFtZSk7XG4gICAgICAgIGlmIChyZWFkU2l6ZSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIGxldCBpbmZvO1xuICAgICAgICB0cnkgeyBpbmZvID0gYXdhaXQgKGF3YWl0IHRoaXMuc3RvcmFnZSgpKS5nZXRJbmZvKGYuZmlsZU5hbWUpOyB9IGNhdGNoIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgICAgIHJldHVybiAhIWluZm8gJiYgaW5mby5zaXplID09PSByZWFkU2l6ZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIG1lcmdlU3BhY2luZ0RlbGF5KCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBjb25zdCB0b3RhbCA9IGJ1bGtEYXRhYmFzZTJUaW1pbmcubWVyZ2VTcGFjaW5nTXM7XG4gICAgICAgIGlmICh0b3RhbCA8PSAwKSByZXR1cm4gdHJ5QWNxdWlyZU1lcmdlTG9jayh0aGlzLm5hbWUsIHdyaXRlcklkKTtcbiAgICAgICAgY29uc3Qgc3RlcCA9IDE1ICogMTAwMDtcbiAgICAgICAgbGV0IHdhaXRlZCA9IDA7XG4gICAgICAgIHdoaWxlICh3YWl0ZWQgPCB0b3RhbCkge1xuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4ociA9PiBzZXRUaW1lb3V0KHIsIE1hdGgubWluKHN0ZXAsIHRvdGFsIC0gd2FpdGVkKSkpO1xuICAgICAgICAgICAgd2FpdGVkICs9IHN0ZXA7XG4gICAgICAgICAgICBpZiAoIXRyeUFjcXVpcmVNZXJnZUxvY2sodGhpcy5uYW1lLCB3cml0ZXJJZCkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBUaGUgbWVyZ2UgcG9saWN5ICh0d28gcGFzc2VzLCBzcGFjZWQgYnkgbWVyZ2VTcGFjaW5nTXMpOlxuICAgIC8vICAgMSkgQ29uc29saWRhdGUgcmVjZW50IGZyYWdtZW50YXRpb246IHRha2UgbmV3ZXN0IGZpbGVzIHVwIHRvIH5GSVJTVF9NRVJHRV9CWVRFUzsgbWVyZ2UgdGhlbVxuICAgIC8vICAgICAgaW50byBvbmUgd2hlbiB0aGV5IGZyYWdtZW50IG9yIHNwYW4gdG9vIHdpZGUgYSB0aW1lIHJhbmdlLlxuICAgIC8vICAgMikgS2V5LXN0cmF0aWZ5OiB3YWxrIGFsbCBrZXlzIGluIH5LRVlfR1JPVVBfQllURVMgZ3JvdXBzOyByZXdyaXRlIGdyb3VwcyB3aG9zZSBkdXBsaWNhdGUta2V5XG4gICAgLy8gICAgICBmcmFjdGlvbiBwYXNzZXMgRFVQX1RIUkVTSE9MRCwgaGlnaGVzdCBmaXJzdC5cbiAgICAvLyBVc2UgdHJ5TWVyZ2UgaW5zdGVhZFxuICAgIHByaXZhdGUgYXN5bmMgdGVzdE1lcmdlSU5URVJOQUxfRE9fTk9UX0NBTEwoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGxldCBtZXJnZWQgPSBmYWxzZTtcbiAgICAgICAgYXdhaXQgdGhpcy5mbHVzaFBlbmRpbmcoKTtcbiAgICAgICAgY29uc3QgcnVuTWVyZ2UgPSBhc3luYyAoYnVsazogQnVsa0ZpbGVJbmZvW10sIHN0cmVhbTogU3RyZWFtRmlsZUluZm9bXSk6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICAgICAgICAgICAgaWYgKG1lcmdlZCAmJiAhYXdhaXQgdGhpcy5tZXJnZVNwYWNpbmdEZWxheSgpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICBpZiAoYXdhaXQgdGhpcy5tZXJnZUZpbGVTZXQoYnVsaywgc3RyZWFtKSkgbWVyZ2VkID0gdHJ1ZTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEhhcmQgc3RyZWFtIGxpbWl0OiBhIHN0cmVhbSB0aGlzIGJpZyBtYWtlcyBldmVyeSByZWFkIHB1bGwgYSBodWdlIGZpbGUg4oaSIGZvbGQgQUxMIG9mIGl0IG5vdyxcbiAgICAgICAgLy8gZm9yY2UtZGVsZXRlIChjYW5EZWxldGVTdHJlYW0gc3RpbGwgcmVxdWlyZXMgc2l6ZS1zdGFibGUsIHNvIGFuIGFjdGl2ZSB3cml0ZXIgbmV2ZXIgbG9zZXMgZGF0YSkuXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnN0IHsgc3RyZWFtRmlsZXMgfSA9IGF3YWl0IHRoaXMubGlzdEZpbGVzKCk7XG4gICAgICAgICAgICBpZiAoc3RyZWFtRmlsZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3RvcmFnZSA9IGF3YWl0IHRoaXMuc3RvcmFnZSgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNpemVzID0gYXdhaXQgUHJvbWlzZS5hbGwoc3RyZWFtRmlsZXMubWFwKGFzeW5jIGYgPT4geyB0cnkgeyByZXR1cm4gKGF3YWl0IHN0b3JhZ2UuZ2V0SW5mbyhmLmZpbGVOYW1lKSk/LnNpemUgPz8gMDsgfSBjYXRjaCB7IHJldHVybiAwOyB9IH0pKTtcbiAgICAgICAgICAgICAgICBjb25zdCB0b3RhbFN0cmVhbUJ5dGVzID0gc2l6ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XG4gICAgICAgICAgICAgICAgaWYgKHRvdGFsU3RyZWFtQnl0ZXMgPiBidWxrRGF0YWJhc2UyVGltaW5nLnN0cmVhbUZvbGRIYXJkTGltaXRCeXRlcykge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgJHtibHVlKHRoaXMubmFtZSl9ICR7bWFnZW50YShcImZvbGRcIil9IHN0cmVhbSB0aWVyICR7Zm10Qnl0ZXModG90YWxTdHJlYW1CeXRlcyl9IG92ZXIgaGFyZCBsaW1pdCAke2ZtdEJ5dGVzKGJ1bGtEYXRhYmFzZTJUaW1pbmcuc3RyZWFtRm9sZEhhcmRMaW1pdEJ5dGVzKX0gLSBmb2xkaW5nIGFsbCBzdHJlYW1zIG5vd2ApO1xuICAgICAgICAgICAgICAgICAgICBpZiAoYXdhaXQgdGhpcy5tZXJnZUZpbGVTZXQoW10sIHN0cmVhbUZpbGVzLCBmYWxzZSwgdHJ1ZSkpIG1lcmdlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUGFzcyAxOiBjb25zb2xpZGF0ZSByZWNlbnQuIE9ubHkgc2VhbCB3aGVuIGNyb3NzLXRhYiBzeW5jIGNhbiBmb2xkIHJlY2VudCBzdHJlYW1zIOKAlCBpbiBOb2RlXG4gICAgICAgIC8vIGNhbkRlbGV0ZVN0cmVhbSBuZWVkcyB0aGVtIGFnZWQgYW55d2F5LCBzbyBzZWFsaW5nIHdvdWxkIGp1c3QgZnJhZ21lbnQgc3RyZWFtcyBldmVyeSBwYXNzLlxuICAgICAgICBjb25zdCBmb2xkUmVjZW50U3RyZWFtcyA9IGlzU3luY1N1cHBvcnRlZCgpO1xuICAgICAgICBpZiAoZm9sZFJlY2VudFN0cmVhbXMpIHtcbiAgICAgICAgICAgIHN5bmNCcm9hZGNhc3RTZWFsKHRoaXMubmFtZSk7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbUZpbGVOYW1lID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnN0IHsgYnVsa0ZpbGVzLCBzdHJlYW1GaWxlcyB9ID0gYXdhaXQgdGhpcy5saXN0RmlsZXMoKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1bGtNZXRhID0gYXdhaXQgUHJvbWlzZS5hbGwoYnVsa0ZpbGVzLm1hcChhc3luYyBmID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBbc2l6ZSwgaGVhZGVyXSA9IGF3YWl0IFByb21pc2UuYWxsKFt0aGlzLmZpbGVMb2dpY2FsU2l6ZShmLmZpbGVOYW1lKSwgdGhpcy5yZWFkQnVsa0hlYWRlcihmLmZpbGVOYW1lKV0pO1xuICAgICAgICAgICAgICAgIHJldHVybiB7IGtpbmQ6IFwiYnVsa1wiIGFzIGNvbnN0LCBmaWxlOiBmLCBieXRlczogc2l6ZSA/PyAwLCB0aW1lOiBoZWFkZXI/Lm1heFRpbWUgfHwgZi50aW1lc3RhbXAgfTtcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIGNvbnN0IHN0cmVhbU1ldGE6IHsga2luZDogXCJzdHJlYW1cIjsgZmlsZTogU3RyZWFtRmlsZUluZm87IGJ5dGVzOiBudW1iZXI7IHRpbWU6IG51bWJlciB9W10gPSBbXTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgZiBvZiBzdHJlYW1GaWxlcykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGFnZWQgPSBEYXRlLm5vdygpIC0gZi50aW1lc3RhbXAgPj0gYnVsa0RhdGFiYXNlMlRpbWluZy5zdHJlYW1TZWFsQWdlTXM7XG4gICAgICAgICAgICAgICAgaWYgKCFmb2xkUmVjZW50U3RyZWFtcyAmJiAhYWdlZCkgY29udGludWU7XG4gICAgICAgICAgICAgICAgbGV0IGJ5dGVzID0gMDtcbiAgICAgICAgICAgICAgICB0cnkgeyBjb25zdCBpbmZvID0gYXdhaXQgKGF3YWl0IHRoaXMuc3RvcmFnZSgpKS5nZXRJbmZvKGYuZmlsZU5hbWUpOyBieXRlcyA9IGluZm8/LnNpemUgPz8gMDsgfSBjYXRjaCB7IGJ5dGVzID0gMDsgfVxuICAgICAgICAgICAgICAgIHN0cmVhbU1ldGEucHVzaCh7IGtpbmQ6IFwic3RyZWFtXCIsIGZpbGU6IGYsIGJ5dGVzLCB0aW1lOiBmLnRpbWVzdGFtcCB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGl0ZW1zID0gWy4uLmJ1bGtNZXRhLCAuLi5zdHJlYW1NZXRhXS5zb3J0KChhLCBiKSA9PiBiLnRpbWUgLSBhLnRpbWUpO1xuICAgICAgICAgICAgY29uc3QgcmVjZW50OiB0eXBlb2YgaXRlbXMgPSBbXTtcbiAgICAgICAgICAgIGxldCByZWNlbnRCeXRlcyA9IDA7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGl0IG9mIGl0ZW1zKSB7XG4gICAgICAgICAgICAgICAgcmVjZW50LnB1c2goaXQpO1xuICAgICAgICAgICAgICAgIHJlY2VudEJ5dGVzICs9IGl0LmJ5dGVzO1xuICAgICAgICAgICAgICAgIGlmIChyZWNlbnRCeXRlcyA+PSBGSVJTVF9NRVJHRV9CWVRFUykgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzcGFuID0gcmVjZW50Lmxlbmd0aCA/IHJlY2VudFswXS50aW1lIC0gcmVjZW50W3JlY2VudC5sZW5ndGggLSAxXS50aW1lIDogMDtcbiAgICAgICAgICAgIGNvbnN0IHJlY2VudFN0cmVhbUJ5dGVzID0gcmVjZW50LnJlZHVjZSgoYSwgaXQpID0+IGEgKyAoaXQua2luZCA9PT0gXCJzdHJlYW1cIiA/IGl0LmJ5dGVzIDogMCksIDApO1xuICAgICAgICAgICAgY29uc3QgaGVhdnlTdHJlYW0gPSByZWNlbnRTdHJlYW1CeXRlcyA+IGJ1bGtEYXRhYmFzZTJUaW1pbmcuc3RyZWFtRm9sZFRyaWdnZXJCeXRlcztcbiAgICAgICAgICAgIGNvbnN0IHRyaWdnZXJlZCA9XG4gICAgICAgICAgICAgICAgcmVjZW50Lmxlbmd0aCA+PSAyICYmIChyZWNlbnQubGVuZ3RoID4gYnVsa0RhdGFiYXNlMlRpbWluZy5maXJzdE1lcmdlVHJpZ2dlckZpbGVzIHx8IHNwYW4gPiBidWxrRGF0YWJhc2UyVGltaW5nLmZpcnN0TWVyZ2VUcmlnZ2VyUmFuZ2VNcylcbiAgICAgICAgICAgICAgICB8fCBoZWF2eVN0cmVhbTtcbiAgICAgICAgICAgIGlmICh0cmlnZ2VyZWQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCByYiA9IHJlY2VudC5maWx0ZXIoaSA9PiBpLmtpbmQgPT09IFwiYnVsa1wiKS5tYXAoaSA9PiAoaS5maWxlIGFzIEJ1bGtGaWxlSW5mbykpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJzID0gcmVjZW50LmZpbHRlcihpID0+IGkua2luZCA9PT0gXCJzdHJlYW1cIikubWFwKGkgPT4gKGkuZmlsZSBhcyBTdHJlYW1GaWxlSW5mbykpO1xuICAgICAgICAgICAgICAgIGlmICghYXdhaXQgcnVuTWVyZ2UocmIsIHJzKSkgcmV0dXJuIG1lcmdlZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdob2xlLXRpZXIgZGVkdXAgc2hvcnQtY2lyY3VpdCAoYmV0d2VlbiBQYXNzIDEgYW5kIHRoZSBwZXItZ3JvdXAgUGFzcyAyKTogd2hlbiB0aGUgYnVsayB0aWVyXG4gICAgICAgIC8vIGlzIGJpZyBlbm91Z2ggQU5EIG1vc3RseSBkdXBsaWNhdGVzLCBmb2xkIGV2ZXJ5IGJ1bGsgZmlsZSBpbiBvbmUgbWVyZ2UuIEF2b2lkcyB0aGUgcGVyLWdyb3VwXG4gICAgICAgIC8vIHdhbGsncyA1LW1pbiBzcGFjaW5nIMOXIE4tZ3JvdXBzIGxhdGVuY3kuXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnN0IHsgYnVsa0ZpbGVzIH0gPSBhd2FpdCB0aGlzLmxpc3RGaWxlcygpO1xuICAgICAgICAgICAgaWYgKGJ1bGtGaWxlcy5sZW5ndGggPj0gMikge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0b3JhZ2UgPSBhd2FpdCB0aGlzLnN0b3JhZ2UoKTtcbiAgICAgICAgICAgICAgICBsZXQgdG90YWxCeXRlcyA9IDA7XG4gICAgICAgICAgICAgICAgbGV0IHRvdGFsU2xvdHMgPSAwO1xuICAgICAgICAgICAgICAgIGNvbnN0IHVuaXF1ZUtleXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGYgb2YgYnVsa0ZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByZWFkZXIgPSBhd2FpdCBsb2FkRmlsZVJlYWRlcih0aGlzLm5hbWUsIHN0b3JhZ2UsIGYsIHRoaXMuc3ViQ2FjaGVzLmJ1bGspO1xuICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxCeXRlcyArPSByZWFkZXIudG90YWxCeXRlcztcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsU2xvdHMgKz0gcmVhZGVyLmtleXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBrIG9mIHJlYWRlci5rZXlzKSB1bmlxdWVLZXlzLmFkZChrKTtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCB7IC8qIHNraXAgdW5yZWFkYWJsZSAqLyB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IGR1cEZyYWN0aW9uID0gdG90YWxTbG90cyA/ICh0b3RhbFNsb3RzIC0gdW5pcXVlS2V5cy5zaXplKSAvIHRvdGFsU2xvdHMgOiAwO1xuICAgICAgICAgICAgICAgIGlmICh0b3RhbEJ5dGVzID4gREVEVVBfVFJJR0dFUl9CWVRFUyAmJiBkdXBGcmFjdGlvbiA+IERFRFVQX1RSSUdHRVJfRlJBQ1RJT04pIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coYCR7Ymx1ZSh0aGlzLm5hbWUpfSAke21hZ2VudGEoXCJkZWR1cFwiKX06ICR7Zm10Qnl0ZXModG90YWxCeXRlcyl9IGFjcm9zcyAke2J1bGtGaWxlcy5sZW5ndGh9IGJ1bGsgZmlsZShzKSwgJHtNYXRoLnJvdW5kKGR1cEZyYWN0aW9uICogMTAwKX0lIGR1cGxpY2F0ZSBrZXktc2xvdHMgLSBmb2xkaW5nIGFsbCBhdCBvbmNlYCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICghYXdhaXQgcnVuTWVyZ2UoYnVsa0ZpbGVzLCBbXSkpIHJldHVybiBtZXJnZWQ7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBtZXJnZWQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUGFzcyAyOiBrZXktc3RyYXRpZmllZCBkZWR1cGxpY2F0aW9uLiBEaXNqb2ludCBrZXkgcmFuZ2VzIOKGkiBvbmUgZ3JvdXAncyBtZXJnZSBkb2Vzbid0XG4gICAgICAgIC8vIGNoYW5nZSBhbm90aGVyJ3MgZHVwbGljYXRpb247IHJlLXNlbGVjdCBlYWNoIGdyb3VwJ3MgZmlsZXMgYXQgbWVyZ2UgdGltZSAoc2V0IHNoaWZ0cykuXG4gICAgICAgIGNvbnN0IGdyb3VwcyA9IGF3YWl0IHRoaXMuZmluZER1cGxpY2F0ZUdyb3VwcygpO1xuICAgICAgICBmb3IgKGNvbnN0IGcgb2YgZ3JvdXBzKSB7XG4gICAgICAgICAgICBjb25zdCB7IGJ1bGtGaWxlcyB9ID0gYXdhaXQgdGhpcy5saXN0RmlsZXMoKTtcbiAgICAgICAgICAgIGNvbnN0IGhlYWRlcnMgPSBhd2FpdCBQcm9taXNlLmFsbChidWxrRmlsZXMubWFwKGYgPT4gdGhpcy5yZWFkQnVsa0hlYWRlcihmLmZpbGVOYW1lKSkpO1xuICAgICAgICAgICAgY29uc3QgZ3JvdXBGaWxlcyA9IGJ1bGtGaWxlcy5maWx0ZXIoKGYsIGkpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBoID0gaGVhZGVyc1tpXTtcbiAgICAgICAgICAgICAgICBpZiAoIWgpIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICBpZiAoaC5taW5LZXkgPT09IHVuZGVmaW5lZCB8fCBoLm1heEtleSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gaC5taW5LZXkgPD0gZy5oaSAmJiBoLm1heEtleSA+PSBnLmxvO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAoZ3JvdXBGaWxlcy5sZW5ndGggPj0gMikgeyBpZiAoIWF3YWl0IHJ1bk1lcmdlKGdyb3VwRmlsZXMsIFtdKSkgcmV0dXJuIG1lcmdlZDsgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG1lcmdlZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGZpbmREdXBsaWNhdGVHcm91cHMoKTogUHJvbWlzZTx7IGxvOiBzdHJpbmc7IGhpOiBzdHJpbmc7IGR1cDogbnVtYmVyIH1bXT4ge1xuICAgICAgICBjb25zdCB7IGJ1bGtGaWxlcyB9ID0gYXdhaXQgdGhpcy5saXN0RmlsZXMoKTtcbiAgICAgICAgaWYgKGJ1bGtGaWxlcy5sZW5ndGggPCAyKSByZXR1cm4gW107XG4gICAgICAgIGNvbnN0IHN0b3JhZ2UgPSBhd2FpdCB0aGlzLnN0b3JhZ2UoKTtcbiAgICAgICAgY29uc3QgaW5mb3MgPSBhd2FpdCBQcm9taXNlLmFsbChidWxrRmlsZXMubWFwKGFzeW5jIGYgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCByZWFkZXIgPSBhd2FpdCBsb2FkRmlsZVJlYWRlcih0aGlzLm5hbWUsIHN0b3JhZ2UsIGYsIHRoaXMuc3ViQ2FjaGVzLmJ1bGspO1xuICAgICAgICAgICAgICAgIHJldHVybiB7IGtleXM6IHJlYWRlci5rZXlzLCBieXRlczogcmVhZGVyLnRvdGFsQnl0ZXMgfTtcbiAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICAgIHJldHVybiB7IGtleXM6IFtdIGFzIHN0cmluZ1tdLCBieXRlczogMCB9O1xuICAgICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIGNvbnN0IGtleUNvdW50ID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgICAgICAgbGV0IHRvdGFsU2xvdHMgPSAwLCB0b3RhbEJ5dGVzID0gMDtcbiAgICAgICAgZm9yIChjb25zdCBpIG9mIGluZm9zKSB7XG4gICAgICAgICAgICB0b3RhbEJ5dGVzICs9IGkuYnl0ZXM7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGsgb2YgaS5rZXlzKSB7IGtleUNvdW50LnNldChrLCAoa2V5Q291bnQuZ2V0KGspIHx8IDApICsgMSk7IHRvdGFsU2xvdHMrKzsgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh0b3RhbFNsb3RzID09PSAwKSByZXR1cm4gW107XG4gICAgICAgIGNvbnN0IGJ5dGVzUGVyU2xvdCA9IHRvdGFsQnl0ZXMgLyB0b3RhbFNsb3RzO1xuICAgICAgICBjb25zdCBzb3J0ZWRLZXlzID0gWy4uLmtleUNvdW50LmtleXMoKV0uc29ydCgpO1xuICAgICAgICBjb25zdCBncm91cHM6IHsgbG86IHN0cmluZzsgaGk6IHN0cmluZzsgZHVwOiBudW1iZXIgfVtdID0gW107XG4gICAgICAgIGxldCBnU3RhcnQgPSAwLCBnQnl0ZXMgPSAwLCBnU2xvdHMgPSAwLCBnVW5pcXVlID0gMDtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzb3J0ZWRLZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBjID0ga2V5Q291bnQuZ2V0KHNvcnRlZEtleXNbaV0pID8/IDA7XG4gICAgICAgICAgICBnQnl0ZXMgKz0gYyAqIGJ5dGVzUGVyU2xvdDsgZ1Nsb3RzICs9IGM7IGdVbmlxdWUgKz0gMTtcbiAgICAgICAgICAgIGlmIChnQnl0ZXMgPj0gS0VZX0dST1VQX0JZVEVTIHx8IGkgPT09IHNvcnRlZEtleXMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGR1cCA9IChnU2xvdHMgLSBnVW5pcXVlKSAvIGdTbG90cztcbiAgICAgICAgICAgICAgICBpZiAoZHVwID4gRFVQX1RIUkVTSE9MRCkgZ3JvdXBzLnB1c2goeyBsbzogc29ydGVkS2V5c1tnU3RhcnRdLCBoaTogc29ydGVkS2V5c1tpXSwgZHVwIH0pO1xuICAgICAgICAgICAgICAgIGdTdGFydCA9IGkgKyAxOyBnQnl0ZXMgPSAwOyBnU2xvdHMgPSAwOyBnVW5pcXVlID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBncm91cHMuc29ydCgoYSwgYikgPT4gYi5kdXAgLSBhLmR1cCk7XG4gICAgICAgIHJldHVybiBncm91cHM7XG4gICAgfVxuXG4gICAgLy8g4pSA4pSAIHJlYWRzIOKAlCBmb3J3YXJkZWQgdG8gQnVsa0RhdGFiYXNlUmVhZGVyLCB3aXRoIHJlYnVpbGQtb24tbWlzc2luZyByZXRyeSDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgICBwdWJsaWMgYXN5bmMgZ2V0U2luZ2xlRmllbGQ8QyBleHRlbmRzIGtleW9mIFQ+KGtleTogc3RyaW5nLCBjb2x1bW46IEMpOiBQcm9taXNlPFRbQ10gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgdm9pZCB0aGlzLnN5bmNTZXR1cCgpO1xuICAgICAgICByZXR1cm4gdGhpcy5yZWFkV2l0aFJldHJ5KCgpID0+IHRoaXMucmVhZGVyLmdldFNpbmdsZUZpZWxkKGtleSwgY29sdW1uKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldFNpbmdsZUZpZWxkT2JqPEMgZXh0ZW5kcyBrZXlvZiBUPihrZXk6IHN0cmluZywgY29sdW1uOiBDKTogUHJvbWlzZTx7IGtleTogc3RyaW5nOyB2YWx1ZTogVFtDXTsgdGltZTogbnVtYmVyIH0gfCB1bmRlZmluZWQ+IHtcbiAgICAgICAgdm9pZCB0aGlzLnN5bmNTZXR1cCgpO1xuICAgICAgICByZXR1cm4gdGhpcy5yZWFkV2l0aFJldHJ5KCgpID0+IHRoaXMucmVhZGVyLmdldFNpbmdsZUZpZWxkT2JqKGtleSwgY29sdW1uKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldENvbHVtbjxDIGV4dGVuZHMga2V5b2YgVD4oY29sdW1uOiBDKTogUHJvbWlzZTx7IGtleTogc3RyaW5nOyB2YWx1ZTogVFtDXTsgdGltZTogbnVtYmVyIH1bXT4ge1xuICAgICAgICB2b2lkIHRoaXMuc3luY1NldHVwKCk7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWRXaXRoUmV0cnkoKCkgPT4gdGhpcy5yZWFkZXIuZ2V0Q29sdW1uKGNvbHVtbikpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRLZXlzKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICAgICAgdm9pZCB0aGlzLnN5bmNTZXR1cCgpO1xuICAgICAgICByZXR1cm4gdGhpcy5yZWFkV2l0aFJldHJ5KCgpID0+IHRoaXMucmVhZGVyLmdldEtleXMoKSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFNpbmdsZUZpZWxkU3luYzxDIGV4dGVuZHMga2V5b2YgVD4oa2V5OiBzdHJpbmcsIGNvbHVtbjogQyk6IFRbQ10gfCB1bmRlZmluZWQge1xuICAgICAgICB2b2lkIHRoaXMuc3luY1NldHVwKCk7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWRlci5nZXRTaW5nbGVGaWVsZFN5bmMoa2V5LCBjb2x1bW4pO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTaW5nbGVGaWVsZE9ialN5bmM8QyBleHRlbmRzIGtleW9mIFQ+KGtleTogc3RyaW5nLCBjb2x1bW46IEMpOiB7IGtleTogc3RyaW5nOyB2YWx1ZTogVFtDXTsgdGltZTogbnVtYmVyIH0gfCB1bmRlZmluZWQge1xuICAgICAgICB2b2lkIHRoaXMuc3luY1NldHVwKCk7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWRlci5nZXRTaW5nbGVGaWVsZE9ialN5bmMoa2V5LCBjb2x1bW4pO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRDb2x1bW5TeW5jPEMgZXh0ZW5kcyBrZXlvZiBUPihjb2x1bW46IEMpOiB7IGtleTogc3RyaW5nOyB2YWx1ZTogVFtDXTsgdGltZTogbnVtYmVyIH1bXSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHZvaWQgdGhpcy5zeW5jU2V0dXAoKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVhZGVyLmdldENvbHVtblN5bmMoY29sdW1uKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNGaWVsZExvYWRlZFN5bmM8QyBleHRlbmRzIGtleW9mIFQ+KGtleTogc3RyaW5nLCBjb2x1bW46IEMpOiBib29sZWFuIHtcbiAgICAgICAgdm9pZCB0aGlzLnN5bmNTZXR1cCgpO1xuICAgICAgICByZXR1cm4gdGhpcy5yZWFkZXIuaXNGaWVsZExvYWRlZFN5bmMoa2V5LCBjb2x1bW4pO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc0NvbHVtbkxvYWRlZFN5bmM8QyBleHRlbmRzIGtleW9mIFQ+KGNvbHVtbjogQyk6IGJvb2xlYW4ge1xuICAgICAgICB2b2lkIHRoaXMuc3luY1NldHVwKCk7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWRlci5pc0NvbHVtbkxvYWRlZFN5bmMoY29sdW1uKTtcbiAgICB9XG5cbiAgICAvLyBSZWFjdGl2ZTogdHJ1ZSB3aGlsZSBhIG1lcmdlIGlzIHJld3JpdGluZyB0aGlzIGNvbGxlY3Rpb24ncyBmaWxlcy4gVXNlIHRoaXMgaW4gVUkgdG8gc2hvdyBhXG4gICAgLy8gXCJjb21wYWN0aW5n4oCmXCIgaW5kaWNhdG9yLiBDb3VudHMgYm90aCBiYWNrZ3JvdW5kIG1lcmdlcyAobWF5YmVNZXJnZSkgYW5kIGV4cGxpY2l0IGNvbXBhY3QvbWVyZ2VcbiAgICAvLyBjYWxscy4gQmVjb21lcyBmYWxzZSBvbmNlIHRoZSBuZXcgaW5kZXggaXMgc3dhcHBlZCBpbiAodGhlIGRlZmVycmVkLWRlbGV0ZSB3aW5kb3cgaXMgTk9UIGNvdW50ZWQpLlxuICAgIHB1YmxpYyBpc0NvbXBhY3RpbmdTeW5jKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5yZWFkZXIuaXNDb21wYWN0aW5nU3luYygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRDb2x1bW5JbmZvKCkge1xuICAgICAgICBjb25zdCBpbmRleCA9IGF3YWl0IHRoaXMuZW5zdXJlSW5kZXgoKTtcbiAgICAgICAgcmV0dXJuIGluZGV4LnJlYWRlci5jb2x1bW5zO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRLZXlTdGF0cygpOiBQcm9taXNlPHsgcmF3S2V5czogbnVtYmVyOyBmaW5hbEtleXM6IG51bWJlcjsgd2FzdGVkS2V5czogbnVtYmVyOyBkdXBsaWNhdGlvbjogbnVtYmVyOyByZWFkZXJzOiBudW1iZXIgfT4ge1xuICAgICAgICBjb25zdCBpbmRleCA9IGF3YWl0IHRoaXMuZW5zdXJlSW5kZXgoKTtcbiAgICAgICAgY29uc3QgcmF3S2V5cyA9IGluZGV4LnJlYWRlci5yYXdLZXlDb3VudDtcbiAgICAgICAgY29uc3QgZmluYWxLZXlzID0gaW5kZXgucmVhZGVyLmtleXMubGVuZ3RoO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcmF3S2V5cyxcbiAgICAgICAgICAgIGZpbmFsS2V5cyxcbiAgICAgICAgICAgIHdhc3RlZEtleXM6IHJhd0tleXMgLSBmaW5hbEtleXMsXG4gICAgICAgICAgICBkdXBsaWNhdGlvbjogZmluYWxLZXlzID8gcmF3S2V5cyAvIGZpbmFsS2V5cyA6IDAsXG4gICAgICAgICAgICByZWFkZXJzOiBpbmRleC5yZWFkZXIucmVhZGVyQ291bnQsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldFJlYWRlckluZm8oKSB7XG4gICAgICAgIGNvbnN0IGluZGV4ID0gYXdhaXQgdGhpcy5lbnN1cmVJbmRleCgpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcm93Q291bnQ6IGluZGV4LnJlYWRlci5yb3dDb3VudCxcbiAgICAgICAgICAgIHRvdGFsQnl0ZXM6IGluZGV4LnJlYWRlci50b3RhbEJ5dGVzLFxuICAgICAgICAgICAga2V5Q291bnQ6IGluZGV4LnJlYWRlci5rZXlzLmxlbmd0aCxcbiAgICAgICAgICAgIHNhbXBsZUtleTogaW5kZXgucmVhZGVyLmtleXNbMF0gYXMgc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgY29sdW1uczogaW5kZXgucmVhZGVyLmNvbHVtbnMsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGdldEZpbGVJbmZvKCk6IFByb21pc2U8QnVsa0ZpbGVJbmZvTGlzdGluZz4ge1xuICAgICAgICBjb25zdCB7IGJ1bGtGaWxlcywgc3RyZWFtRmlsZXMgfSA9IGF3YWl0IHRoaXMubGlzdEZpbGVzKCk7XG4gICAgICAgIGNvbnN0IHN0b3JhZ2UgPSBhd2FpdCB0aGlzLnN0b3JhZ2UoKTtcbiAgICAgICAgY29uc3Qgc3RhdE9mID0gYXN5bmMgKG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCBpbmZvID0gYXdhaXQgc3RvcmFnZS5nZXRJbmZvKG5hbWUpO1xuICAgICAgICAgICAgICAgIHJldHVybiB7IGJ5dGVzOiBpbmZvPy5zaXplID8/IDAsIGxhc3RNb2RpZmllZDogaW5mbz8ubGFzdE1vZGlmaWVkID8/IDAgfTtcbiAgICAgICAgICAgIH0gY2F0Y2ggeyByZXR1cm4geyBieXRlczogMCwgbGFzdE1vZGlmaWVkOiAwIH07IH1cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgYnVsa0luZm9zID0gYXdhaXQgUHJvbWlzZS5hbGwoYnVsa0ZpbGVzLm1hcChhc3luYyBmID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHN0YXQgPSBhd2FpdCBzdGF0T2YoZi5maWxlTmFtZSk7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG5hbWU6IGYuZmlsZU5hbWUsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJidWxrXCIgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgYnl0ZXM6IHN0YXQuYnl0ZXMsXG4gICAgICAgICAgICAgICAgbGFzdE1vZGlmaWVkOiBzdGF0Lmxhc3RNb2RpZmllZCxcbiAgICAgICAgICAgICAgICBnZXREZXRhaWxzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEJ1bGs6IHJlYWRlciBoYXMga2V5cyArIHBlci1yb3cga2V5VGltZXMgKyBoZWFkZXIgbWluVGltZS9tYXhUaW1lLiBDYWNoZWQsIHNvIGNoZWFwLlxuICAgICAgICAgICAgICAgICAgICBjb25zdCByZWFkZXIgPSBhd2FpdCBsb2FkRmlsZVJlYWRlcih0aGlzLm5hbWUsIHN0b3JhZ2UsIGYsIHRoaXMuc3ViQ2FjaGVzLmJ1bGspO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4geyBrZXlzOiByZWFkZXIua2V5cywgbWluVGltZTogcmVhZGVyLm1pblRpbWUsIG1heFRpbWU6IHJlYWRlci5tYXhUaW1lIH07XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0pKTtcbiAgICAgICAgY29uc3Qgc3RyZWFtSW5mb3MgPSBhd2FpdCBQcm9taXNlLmFsbChzdHJlYW1GaWxlcy5tYXAoYXN5bmMgZiA9PiB7XG4gICAgICAgICAgICBjb25zdCBzdGF0ID0gYXdhaXQgc3RhdE9mKGYuZmlsZU5hbWUpO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBmLmZpbGVOYW1lLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwic3RyZWFtXCIgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgYnl0ZXM6IHN0YXQuYnl0ZXMsXG4gICAgICAgICAgICAgICAgbGFzdE1vZGlmaWVkOiBzdGF0Lmxhc3RNb2RpZmllZCxcbiAgICAgICAgICAgICAgICBnZXREZXRhaWxzOiBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFN0cmVhbTogbXVzdCBwYXJzZSB0aGUgZmlsZSB0byB3YWxrIGV2ZXJ5IGVudHJ5IOKAlCBoZWFkZXIgaGFzIG5vIGtleS90aW1lIGJvdW5kcy4gQ2FjaGVkLlxuICAgICAgICAgICAgICAgICAgICBjb25zdCBkYXRhID0gYXdhaXQgbG9hZFN0cmVhbUVudHJpZXModGhpcy5uYW1lLCBzdG9yYWdlLCBbZl0sIHRoaXMuc3ViQ2FjaGVzLnN0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGtleXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IG1pblRpbWUgPSBJbmZpbml0eSwgbWF4VGltZSA9IC1JbmZpbml0eTtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBlIG9mIGRhdGEuZW50cmllcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUudGltZSA8IG1pblRpbWUpIG1pblRpbWUgPSBlLnRpbWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZS50aW1lID4gbWF4VGltZSkgbWF4VGltZSA9IGUudGltZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlLmVudHJ5LnJvdykga2V5cy5hZGQoZS5lbnRyeS5yb3cua2V5IGFzIHN0cmluZyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChlLmVudHJ5LmRlbGV0ZWRLZXkgIT09IHVuZGVmaW5lZCkga2V5cy5hZGQoZS5lbnRyeS5kZWxldGVkS2V5KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICAgICAga2V5czogWy4uLmtleXNdLFxuICAgICAgICAgICAgICAgICAgICAgICAgbWluVGltZTogbWluVGltZSA9PT0gSW5maW5pdHkgPyAwIDogbWluVGltZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heFRpbWU6IG1heFRpbWUgPT09IC1JbmZpbml0eSA/IDAgOiBtYXhUaW1lLFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9O1xuICAgICAgICB9KSk7XG4gICAgICAgIGNvbnN0IGZpbGVzID0gWy4uLmJ1bGtJbmZvcywgLi4uc3RyZWFtSW5mb3NdO1xuICAgICAgICByZXR1cm4geyBmaWxlcywgY291bnQ6IGZpbGVzLmxlbmd0aCwgdG90YWxCeXRlczogZmlsZXMucmVkdWNlKChhLCBmKSA9PiBhICsgZi5ieXRlcywgMCkgfTtcbiAgICB9XG59XG5cbmV4cG9ydCB0eXBlIEJ1bGtGaWxlRGV0YWlscyA9IHsga2V5czogc3RyaW5nW107IG1pblRpbWU6IG51bWJlcjsgbWF4VGltZTogbnVtYmVyIH07XG5leHBvcnQgdHlwZSBCdWxrRmlsZUVudHJ5ID0ge1xuICAgIG5hbWU6IHN0cmluZztcbiAgICB0eXBlOiBcImJ1bGtcIiB8IFwic3RyZWFtXCI7XG4gICAgYnl0ZXM6IG51bWJlcjtcbiAgICAvLyBGaWxlc3lzdGVtIG10aW1lIChtcyBzaW5jZSBlcG9jaCkg4oCUIDAgaWYgdGhlIHN0b3JhZ2UgbGF5ZXIgZGlkbid0IHJldHVybiBvbmUuXG4gICAgbGFzdE1vZGlmaWVkOiBudW1iZXI7XG4gICAgLy8gTGF6eTogcHVsbGVkIGZyb20gdGhlIGNhY2hlZCBzdWItcmVhZGVyIGZvciBidWxrIChmcmVlIGlmIGxvYWRlZCksIG9yIGZyb20gYSBwYXJzZSBvZiB0aGUgc3RyZWFtXG4gICAgLy8gZmlsZSAoc21hbGwg4oCUIHRpZXItMCBzaXplLWNhcHBlZCwgYWxzbyBjYWNoZWQpLiBDYWxsIG9ubHkgd2hlbiB5b3UgbmVlZCB0aGUgcGVyLWZpbGUgZGV0YWlsLlxuICAgIGdldERldGFpbHM6ICgpID0+IFByb21pc2U8QnVsa0ZpbGVEZXRhaWxzPjtcbn07XG5leHBvcnQgdHlwZSBCdWxrRmlsZUluZm9MaXN0aW5nID0geyBmaWxlczogQnVsa0ZpbGVFbnRyeVtdOyBjb3VudDogbnVtYmVyOyB0b3RhbEJ5dGVzOiBudW1iZXIgfTtcblxuIl19
1242
+ /* _JS_SOURCE_HASH = "3b6d62958a073ea311c58075d9cba03308b546ab7e3884788c293653d91d8c95"; */