sliftutils 1.7.9 → 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.
- package/bin/storageserver.js +4 -0
- package/{teststorage → examplestorage}/browser.tsx +18 -22
- package/{teststorage/server.ts → examplestorage/exampleserver.ts} +4 -6
- package/index.d.ts +770 -84
- package/misc/dist/environment.ts.cache +3 -3
- package/misc/dist/getSecret.ts.cache +139 -0
- package/misc/dist/strings.ts.cache +13 -0
- package/misc/dist/zip.ts.cache +9 -0
- package/misc/getSecret.ts +38 -16
- package/misc/https/cloudflareHelpers.d.ts +19 -0
- package/misc/https/cloudflareHelpers.ts +69 -0
- package/misc/https/dist/certs.ts.cache +115 -179
- package/misc/https/dist/cloudflareHelpers.ts.cache +68 -0
- package/misc/https/dist/dns.ts.cache +112 -100
- package/misc/https/dist/hostServer.ts.cache +130 -0
- package/misc/https/dist/httpsCerts.ts.cache +24 -5
- package/misc/https/dist/persistentLocalStorage.ts.cache +3 -2
- package/misc/https/dns.d.ts +41 -8
- package/misc/https/dns.ts +104 -106
- package/misc/https/hostServer.d.ts +0 -3
- package/misc/https/hostServer.ts +12 -8
- package/package.json +3 -2
- package/render-utils/dist/observer.tsx.cache +3 -2
- package/spec.txt +0 -55
- package/storage/ArchivesDisk.d.ts +67 -0
- package/storage/ArchivesDisk.ts +369 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +1242 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +513 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +352 -0
- package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +306 -0
- package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +435 -0
- package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +58 -0
- package/storage/BulkDatabase2/dist/blockCache.ts.cache +179 -0
- package/storage/BulkDatabase2/dist/mergeLock.ts.cache +149 -0
- package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +101 -0
- package/storage/BulkDatabase2/dist/streamLog.ts.cache +227 -0
- package/storage/BulkDatabase2/dist/syncClient.ts.cache +104 -0
- package/storage/IArchives.d.ts +127 -1
- package/storage/IArchives.ts +201 -1
- package/storage/backblaze.d.ts +29 -2
- package/storage/backblaze.ts +214 -78
- package/storage/dist/ArchivesDisk.ts.cache +373 -0
- package/storage/dist/FileFolderAPI.tsx.cache +508 -65
- package/storage/dist/IArchives.ts.cache +44 -0
- package/storage/dist/IndexedDBFileFolderAPI.ts.cache +8 -2
- package/storage/dist/JSONStorage.ts.cache +6 -2
- package/storage/dist/PendingManager.tsx.cache +1 -1
- package/storage/dist/TransactionStorage.ts.cache +231 -92
- package/storage/dist/backblaze.ts.cache +797 -0
- package/storage/dist/fileSystemPointer.ts.cache +36 -3
- package/storage/dist/remoteFileStorage.ts.cache +495 -0
- package/storage/remoteStorage/ArchivesRemote.d.ts +34 -18
- package/storage/remoteStorage/ArchivesRemote.ts +85 -65
- package/storage/remoteStorage/ArchivesUrl.d.ts +48 -0
- package/storage/remoteStorage/ArchivesUrl.ts +86 -0
- package/storage/remoteStorage/accessPage.tsx +111 -28
- package/storage/remoteStorage/blobStore.d.ts +128 -25
- package/storage/remoteStorage/blobStore.ts +757 -290
- package/storage/remoteStorage/cliArgs.d.ts +1 -0
- package/storage/remoteStorage/cliArgs.ts +9 -0
- package/storage/remoteStorage/createArchives.d.ts +85 -0
- package/storage/remoteStorage/createArchives.ts +612 -0
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +197 -0
- package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +85 -0
- package/storage/remoteStorage/dist/accessPage.tsx.cache +222 -0
- package/storage/remoteStorage/dist/blobStore.ts.cache +837 -0
- package/storage/remoteStorage/dist/cliArgs.ts.cache +16 -0
- package/storage/remoteStorage/dist/createArchives.ts.cache +610 -0
- package/storage/remoteStorage/dist/remoteConfig.ts.cache +206 -0
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +223 -0
- package/storage/remoteStorage/dist/storageController.ts.cache +500 -0
- package/storage/remoteStorage/dist/storageServer.ts.cache +106 -0
- package/storage/remoteStorage/dist/storageServerCli.ts.cache +39 -0
- package/storage/remoteStorage/dist/storageServerState.ts.cache +518 -0
- package/storage/remoteStorage/grantAccess.js +4 -0
- package/storage/remoteStorage/grantAccessCli.d.ts +1 -0
- package/storage/remoteStorage/grantAccessCli.ts +27 -0
- package/storage/remoteStorage/remoteConfig.d.ts +29 -0
- package/storage/remoteStorage/remoteConfig.ts +194 -0
- package/storage/remoteStorage/sourceWrapper.d.ts +41 -0
- package/storage/remoteStorage/sourceWrapper.ts +223 -0
- package/storage/remoteStorage/spec.md +31 -0
- package/storage/remoteStorage/storageController.d.ts +30 -27
- package/storage/remoteStorage/storageController.ts +297 -159
- package/storage/remoteStorage/storageServer.d.ts +6 -0
- package/storage/remoteStorage/storageServer.ts +88 -94
- package/storage/remoteStorage/storageServerCli.d.ts +1 -0
- package/storage/remoteStorage/storageServerCli.ts +38 -0
- package/storage/remoteStorage/storageServerState.d.ts +43 -0
- package/storage/remoteStorage/storageServerState.ts +540 -0
- package/testsite/server.ts +0 -2
- 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"; */
|