sliftutils 1.7.10 → 1.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examplestorage/exampleserver.ts +0 -2
- package/index.d.ts +290 -54
- 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 -12
- package/misc/https/dns.ts +104 -101
- package/misc/https/hostServer.d.ts +0 -6
- package/misc/https/hostServer.ts +9 -5
- package/package.json +2 -2
- package/render-utils/dist/observer.tsx.cache +3 -2
- package/spec.txt +0 -90
- package/storage/ArchivesDisk.d.ts +2 -0
- package/storage/ArchivesDisk.ts +7 -3
- 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 +47 -15
- package/storage/IArchives.ts +86 -31
- package/storage/backblaze.d.ts +15 -0
- package/storage/backblaze.ts +199 -79
- 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 +5 -1
- package/storage/remoteStorage/ArchivesRemote.ts +28 -8
- package/storage/remoteStorage/ArchivesUrl.d.ts +2 -0
- package/storage/remoteStorage/ArchivesUrl.ts +16 -4
- package/storage/remoteStorage/blobStore.d.ts +52 -3
- package/storage/remoteStorage/blobStore.ts +414 -101
- package/storage/remoteStorage/createArchives.d.ts +31 -10
- package/storage/remoteStorage/createArchives.ts +470 -253
- 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/remoteConfig.d.ts +8 -0
- package/storage/remoteStorage/remoteConfig.ts +105 -5
- 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 +11 -0
- package/storage/remoteStorage/storageController.ts +109 -40
- package/storage/remoteStorage/storageServer.d.ts +0 -5
- package/storage/remoteStorage/storageServer.ts +17 -10
- package/storage/remoteStorage/storageServerCli.ts +0 -3
- package/storage/remoteStorage/storageServerState.d.ts +7 -1
- package/storage/remoteStorage/storageServerState.ts +230 -48
- package/testsite/server.ts +0 -2
- package/yarn.lock +11 -6
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
+
//exports.runPlannedMerge = void 0;
|
|
4
|
+
const format_1 = require("socket-function/src/formatting/format");
|
|
5
|
+
const logColors_1 = require("socket-function/src/formatting/logColors");
|
|
6
|
+
const BulkDatabaseFormat_1 = require("./BulkDatabaseFormat");
|
|
7
|
+
// Default total in-flight buffer budget for the executor: how much output value-data we hold in memory at
|
|
8
|
+
// once. Multiple output files (≤ TARGET_FILE_BYTES each) are built together inside this budget so reading
|
|
9
|
+
// inputs once amortizes their I/O across several outputs. Tighter budget → more passes, less memory.
|
|
10
|
+
const DEFAULT_OUTPUT_BATCH_BYTES = 2 * 1024 * 1024 * 1024;
|
|
11
|
+
// Per-value on-disk overhead (4-byte offset entry + 1-byte type tag). Used for the partition-cut size
|
|
12
|
+
// estimate; the executor doesn't use it (offsets/types are sized exactly from the plan).
|
|
13
|
+
const PER_VALUE_OVERHEAD = 5;
|
|
14
|
+
function fmtBytes(n) {
|
|
15
|
+
if (n < 1024)
|
|
16
|
+
return n + "B";
|
|
17
|
+
if (n < 1024 * 1024)
|
|
18
|
+
return (n / 1024).toFixed(1) + "KB";
|
|
19
|
+
if (n < 1024 * 1024 * 1024)
|
|
20
|
+
return (n / 1024 / 1024).toFixed(1) + "MB";
|
|
21
|
+
return (n / 1024 / 1024 / 1024).toFixed(2) + "GB";
|
|
22
|
+
}
|
|
23
|
+
// Plan a merge over `sources` and execute it, writing one or more output files via the caller's
|
|
24
|
+
// `writeFile`. Two phases:
|
|
25
|
+
// • Planning: load only per-column INDEXES (offsets + types — ~5 B/row, small even on 20GB
|
|
26
|
+
// collections), determine the winning cell per (live key, column) by newest write-time + non-ABSENT
|
|
27
|
+
// fall-through, sort keys, partition into ~targetFileBytes output files, and pre-compute each output
|
|
28
|
+
// column's offsets/types arrays plus a run-length-encoded copy plan (no value data touched yet).
|
|
29
|
+
// • Execute: group outputs into ~targetBatchBytes batches; per batch, allocate column blobs with
|
|
30
|
+
// offsets/types already filled in, then iterate input sources copying contiguous byte runs straight
|
|
31
|
+
// into the output buffers. A source with no contribution to this batch is skipped entirely.
|
|
32
|
+
// Returns the new output file descriptors plus any tombstones whose newest event is still a delete
|
|
33
|
+
// (carried forward when older files outside the merge could still hold a now-stale set for that key).
|
|
34
|
+
async function runPlannedMerge(config) {
|
|
35
|
+
var _a, _b, _c, _d, _e;
|
|
36
|
+
const targetFileBytes = (_a = config.targetFileBytes) !== null && _a !== void 0 ? _a : BulkDatabaseFormat_1.TARGET_FILE_BYTES;
|
|
37
|
+
const targetBatchBytes = (_b = config.targetBatchBytes) !== null && _b !== void 0 ? _b : DEFAULT_OUTPUT_BATCH_BYTES;
|
|
38
|
+
const log = (_c = config.log) !== null && _c !== void 0 ? _c : (line => console.log(`${(0, logColors_1.blue)(config.collectionName)} ${line}`));
|
|
39
|
+
// ─────────────────────────────────────────── Phase 1: plan ───────────────────────────────────────────
|
|
40
|
+
// Load per-source column indexes FIRST so a file that's gone (deleted between caller's listFiles and
|
|
41
|
+
// now) gets caught here and excluded from the merge entirely. Each source's load is wrapped in a
|
|
42
|
+
// try/catch; on failure we mark the source bad, log a "skipped" line, and the rest of planning +
|
|
43
|
+
// execute pretends the source doesn't exist. The caller only deletes inputs that were actually used.
|
|
44
|
+
const sourceOk = new Array(config.sources.length).fill(true);
|
|
45
|
+
const indexesPerSource = await Promise.all(config.sources.map(async (src, si) => {
|
|
46
|
+
const map = new Map();
|
|
47
|
+
try {
|
|
48
|
+
await Promise.all(src.columns
|
|
49
|
+
.filter(c => c.column !== BulkDatabaseFormat_1.KEY_COLUMN)
|
|
50
|
+
.map(async (c) => { map.set(c.column, await src.getColumnIndex(c.column)); }));
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
sourceOk[si] = false;
|
|
54
|
+
log(`${(0, logColors_1.magenta)("skipped")} ${config.sourceNames[si]}: ${e.message}`);
|
|
55
|
+
// Stack goes straight to console (not the buffered step log) so the merge summary stays
|
|
56
|
+
// readable but we can still trace where the failure came from.
|
|
57
|
+
console.log(`${config.collectionName} skipped ${config.sourceNames[si]}:`, e.stack || e);
|
|
58
|
+
}
|
|
59
|
+
return map;
|
|
60
|
+
}));
|
|
61
|
+
const usedSourceNames = new Set();
|
|
62
|
+
for (let si = 0; si < config.sources.length; si++) {
|
|
63
|
+
if (sourceOk[si])
|
|
64
|
+
usedSourceNames.add(config.sourceNames[si]);
|
|
65
|
+
}
|
|
66
|
+
// Aggregate keyTimes + deleteTimes across GOOD sources only (max per key). A bad source's cached
|
|
67
|
+
// metadata might claim a key as newest, but we can't actually read its cells — letting it win the
|
|
68
|
+
// time resolution would just drop that key out of the output.
|
|
69
|
+
const deleteTime = new Map();
|
|
70
|
+
const keyTime = new Map();
|
|
71
|
+
for (let si = 0; si < config.sources.length; si++) {
|
|
72
|
+
if (!sourceOk[si])
|
|
73
|
+
continue;
|
|
74
|
+
const src = config.sources[si];
|
|
75
|
+
for (const [k, t] of src.keyTimes) {
|
|
76
|
+
const prev = keyTime.get(k);
|
|
77
|
+
if (prev === undefined || t > prev)
|
|
78
|
+
keyTime.set(k, t);
|
|
79
|
+
}
|
|
80
|
+
if (src.deleteTimes) {
|
|
81
|
+
for (const [k, t] of src.deleteTimes) {
|
|
82
|
+
const prev = deleteTime.get(k);
|
|
83
|
+
if (prev === undefined || t > prev)
|
|
84
|
+
deleteTime.set(k, t);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Live keys (newest set strictly newer than newest delete) + tombstones to carry forward (newest
|
|
89
|
+
// event is a delete and the merge doesn't include the oldest data — that's the caller's call).
|
|
90
|
+
const liveKeys = [];
|
|
91
|
+
for (const [k, t] of keyTime) {
|
|
92
|
+
const dT = (_d = deleteTime.get(k)) !== null && _d !== void 0 ? _d : -Infinity;
|
|
93
|
+
if (t > dT)
|
|
94
|
+
liveKeys.push(k);
|
|
95
|
+
}
|
|
96
|
+
const carriedDeletes = new Map();
|
|
97
|
+
for (const [k, dT] of deleteTime) {
|
|
98
|
+
const sT = (_e = keyTime.get(k)) !== null && _e !== void 0 ? _e : -Infinity;
|
|
99
|
+
if (dT >= sT)
|
|
100
|
+
carriedDeletes.set(k, dT);
|
|
101
|
+
}
|
|
102
|
+
// All distinct value columns from GOOD sources (KEY_COLUMN excluded — it's added at file-assembly
|
|
103
|
+
// time). Order: first-seen, matching the existing builders.
|
|
104
|
+
const allColumns = [];
|
|
105
|
+
const seenCols = new Set();
|
|
106
|
+
for (let si = 0; si < config.sources.length; si++) {
|
|
107
|
+
if (!sourceOk[si])
|
|
108
|
+
continue;
|
|
109
|
+
for (const c of config.sources[si].columns) {
|
|
110
|
+
if (c.column === BulkDatabaseFormat_1.KEY_COLUMN || seenCols.has(c.column))
|
|
111
|
+
continue;
|
|
112
|
+
seenCols.add(c.column);
|
|
113
|
+
allColumns.push(c.column);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const cellsPerKey = new Map();
|
|
117
|
+
for (const key of liveKeys) {
|
|
118
|
+
const cells = new Array(allColumns.length);
|
|
119
|
+
for (let ci = 0; ci < allColumns.length; ci++) {
|
|
120
|
+
const col = allColumns[ci];
|
|
121
|
+
let bestTime = -Infinity;
|
|
122
|
+
let best;
|
|
123
|
+
for (let si = 0; si < config.sources.length; si++) {
|
|
124
|
+
if (!sourceOk[si])
|
|
125
|
+
continue;
|
|
126
|
+
const src = config.sources[si];
|
|
127
|
+
const t = src.keyTimes.get(key);
|
|
128
|
+
if (t === undefined)
|
|
129
|
+
continue;
|
|
130
|
+
const rowIdx = src.rowOfKey(key);
|
|
131
|
+
if (rowIdx === undefined)
|
|
132
|
+
continue;
|
|
133
|
+
const idx = indexesPerSource[si].get(col);
|
|
134
|
+
if (!idx)
|
|
135
|
+
continue;
|
|
136
|
+
const type = idx.types[rowIdx];
|
|
137
|
+
if (type === BulkDatabaseFormat_1.TYPE_ABSENT_TAG)
|
|
138
|
+
continue;
|
|
139
|
+
if (t > bestTime) {
|
|
140
|
+
bestTime = t;
|
|
141
|
+
best = {
|
|
142
|
+
sourceIdx: si,
|
|
143
|
+
sourceRow: rowIdx,
|
|
144
|
+
byteLen: idx.offsets[rowIdx + 1] - idx.offsets[rowIdx],
|
|
145
|
+
type,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
cells[ci] = best;
|
|
150
|
+
}
|
|
151
|
+
cellsPerKey.set(key, cells);
|
|
152
|
+
}
|
|
153
|
+
// Sort live keys lexicographically so each output file is key-contiguous (tight minKey/maxKey + fast
|
|
154
|
+
// single-key reads via header skip).
|
|
155
|
+
liveKeys.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
156
|
+
// Per-key estimated bytes for partition cutting: KEY_COLUMN cell + per value-column cell (bytes + 5B
|
|
157
|
+
// overhead) + TIME_COLUMN cell. Rough — only needs to keep each output near the target.
|
|
158
|
+
function keyTotalBytes(key) {
|
|
159
|
+
const cells = cellsPerKey.get(key);
|
|
160
|
+
let total = key.length * 2 + PER_VALUE_OVERHEAD;
|
|
161
|
+
for (const cell of cells)
|
|
162
|
+
total += (cell ? cell.byteLen : 0) + PER_VALUE_OVERHEAD;
|
|
163
|
+
total += 8 + PER_VALUE_OVERHEAD;
|
|
164
|
+
return total;
|
|
165
|
+
}
|
|
166
|
+
// Walk sorted keys, cut each file when accumulated bytes would exceed targetFileBytes. A single key
|
|
167
|
+
// larger than the target still becomes its own (oversized) file — we never split within a key.
|
|
168
|
+
const fileKeyRanges = [];
|
|
169
|
+
{
|
|
170
|
+
let chunkStart = 0;
|
|
171
|
+
let chunkBytes = 0;
|
|
172
|
+
for (let i = 0; i < liveKeys.length; i++) {
|
|
173
|
+
const kb = keyTotalBytes(liveKeys[i]);
|
|
174
|
+
if (i > chunkStart && chunkBytes + kb > targetFileBytes) {
|
|
175
|
+
fileKeyRanges.push({ start: chunkStart, end: i });
|
|
176
|
+
chunkStart = i;
|
|
177
|
+
chunkBytes = 0;
|
|
178
|
+
}
|
|
179
|
+
chunkBytes += kb;
|
|
180
|
+
}
|
|
181
|
+
if (liveKeys.length > chunkStart)
|
|
182
|
+
fileKeyRanges.push({ start: chunkStart, end: liveKeys.length });
|
|
183
|
+
}
|
|
184
|
+
// Build per-file plans: offsets/types/copy-runs per column.
|
|
185
|
+
const plans = fileKeyRanges.map(range => buildOutputPlan(range, liveKeys, cellsPerKey, allColumns, keyTime));
|
|
186
|
+
log(`${(0, logColors_1.magenta)("plan")}: ${(0, format_1.formatNumber)(liveKeys.length)} live keys, ${plans.length} output file(s), ${(0, format_1.formatNumber)(carriedDeletes.size)} tombstones carried`);
|
|
187
|
+
// ───────────────────────────────────────── Phase 2: execute ──────────────────────────────────────────
|
|
188
|
+
// Group output files into batches that fit within targetBatchBytes so we read inputs once per batch
|
|
189
|
+
// (and skip inputs that contribute nothing to this batch).
|
|
190
|
+
const batches = [];
|
|
191
|
+
{
|
|
192
|
+
let start = 0;
|
|
193
|
+
while (start < plans.length) {
|
|
194
|
+
let end = start + 1;
|
|
195
|
+
let total = plans[start].estimatedFileBytes;
|
|
196
|
+
while (end < plans.length && total + plans[end].estimatedFileBytes <= targetBatchBytes) {
|
|
197
|
+
total += plans[end].estimatedFileBytes;
|
|
198
|
+
end++;
|
|
199
|
+
}
|
|
200
|
+
batches.push(plans.slice(start, end));
|
|
201
|
+
start = end;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const outputs = [];
|
|
205
|
+
for (let bi = 0; bi < batches.length; bi++) {
|
|
206
|
+
const batch = batches[bi];
|
|
207
|
+
const batchBytes = batch.reduce((a, p) => a + p.estimatedFileBytes, 0);
|
|
208
|
+
log(`${(0, logColors_1.magenta)("batch")} ${bi + 1}/${batches.length}: ${batch.length} output file(s), ~${fmtBytes(batchBytes)} budget`);
|
|
209
|
+
const batchOutputs = await executeBatch(batch, indexesPerSource, config.sources, config.sourceNames, config.writeFile, log);
|
|
210
|
+
outputs.push(...batchOutputs);
|
|
211
|
+
}
|
|
212
|
+
const writtenBytes = outputs.reduce((a, o) => a + o.size, 0);
|
|
213
|
+
log(`${(0, logColors_1.magenta)("execute")}: ${outputs.length} file(s), ${fmtBytes(writtenBytes)} written`);
|
|
214
|
+
return { outputs, carriedDeletes, usedSourceNames };
|
|
215
|
+
}
|
|
216
|
+
exports.runPlannedMerge = runPlannedMerge;
|
|
217
|
+
function buildOutputPlan(range, liveKeys, cellsPerKey, allColumns, keyTime) {
|
|
218
|
+
var _a, _b;
|
|
219
|
+
const keys = liveKeys.slice(range.start, range.end);
|
|
220
|
+
const rowCount = keys.length;
|
|
221
|
+
const times = keys.map(k => { var _a; return (_a = keyTime.get(k)) !== null && _a !== void 0 ? _a : 0; });
|
|
222
|
+
const sourceCounts = new Map();
|
|
223
|
+
const columns = allColumns.map((colName, ci) => {
|
|
224
|
+
var _a;
|
|
225
|
+
const offsets = new Uint32Array(rowCount + 1);
|
|
226
|
+
const types = new Uint8Array(rowCount);
|
|
227
|
+
const runs = [];
|
|
228
|
+
let outputByte = 0;
|
|
229
|
+
let currentRun;
|
|
230
|
+
for (let i = 0; i < rowCount; i++) {
|
|
231
|
+
const cell = cellsPerKey.get(keys[i])[ci];
|
|
232
|
+
offsets[i] = outputByte;
|
|
233
|
+
if (!cell) {
|
|
234
|
+
types[i] = BulkDatabaseFormat_1.TYPE_ABSENT_TAG;
|
|
235
|
+
// ABSENT contributes nothing to the data section and breaks any extending run.
|
|
236
|
+
if (currentRun) {
|
|
237
|
+
runs.push(currentRun);
|
|
238
|
+
currentRun = undefined;
|
|
239
|
+
}
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
types[i] = cell.type;
|
|
243
|
+
sourceCounts.set(cell.sourceIdx, ((_a = sourceCounts.get(cell.sourceIdx)) !== null && _a !== void 0 ? _a : 0) + 1);
|
|
244
|
+
// RLE: extend the current run iff the next cell is the next row of the same source (its
|
|
245
|
+
// source-side bytes sit immediately after, so one read suffices) AND non-ABSENT (we never
|
|
246
|
+
// landed in the break-path above).
|
|
247
|
+
if (currentRun && currentRun.sourceIdx === cell.sourceIdx && currentRun.sourceEndRow === cell.sourceRow) {
|
|
248
|
+
currentRun.sourceEndRow = cell.sourceRow + 1;
|
|
249
|
+
currentRun.byteLength += cell.byteLen;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
if (currentRun)
|
|
253
|
+
runs.push(currentRun);
|
|
254
|
+
currentRun = {
|
|
255
|
+
sourceIdx: cell.sourceIdx,
|
|
256
|
+
sourceStartRow: cell.sourceRow,
|
|
257
|
+
sourceEndRow: cell.sourceRow + 1,
|
|
258
|
+
outputByteStart: outputByte,
|
|
259
|
+
byteLength: cell.byteLen,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
outputByte += cell.byteLen;
|
|
263
|
+
}
|
|
264
|
+
if (currentRun)
|
|
265
|
+
runs.push(currentRun);
|
|
266
|
+
offsets[rowCount] = outputByte;
|
|
267
|
+
return { name: colName, offsets, types, dataLength: outputByte, runs };
|
|
268
|
+
});
|
|
269
|
+
// File size estimate: KEY_COLUMN blob + value column blobs + TIME_COLUMN blob + header guess. Used to
|
|
270
|
+
// batch output files; only needs to be close, not exact.
|
|
271
|
+
let estimatedFileBytes = 4 + 2048;
|
|
272
|
+
let keyBytes = 0;
|
|
273
|
+
for (const k of keys)
|
|
274
|
+
keyBytes += k.length * 2;
|
|
275
|
+
estimatedFileBytes += (0, BulkDatabaseFormat_1.columnIndexByteLength)(rowCount) + keyBytes;
|
|
276
|
+
for (const col of columns)
|
|
277
|
+
estimatedFileBytes += (0, BulkDatabaseFormat_1.columnIndexByteLength)(rowCount) + col.dataLength;
|
|
278
|
+
estimatedFileBytes += (0, BulkDatabaseFormat_1.columnIndexByteLength)(rowCount) + rowCount * 8;
|
|
279
|
+
return {
|
|
280
|
+
keys,
|
|
281
|
+
times,
|
|
282
|
+
minKey: (_a = keys[0]) !== null && _a !== void 0 ? _a : "",
|
|
283
|
+
maxKey: (_b = keys[rowCount - 1]) !== null && _b !== void 0 ? _b : "",
|
|
284
|
+
columns,
|
|
285
|
+
estimatedFileBytes,
|
|
286
|
+
sourceCounts,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
async function executeBatch(plans, indexesPerSource, sources, sourceNames, writeFile, log) {
|
|
290
|
+
const blobsPerFile = plans.map(plan => plan.columns.map(col => {
|
|
291
|
+
const indexSize = (0, BulkDatabaseFormat_1.columnIndexByteLength)(col.offsets.length - 1);
|
|
292
|
+
const blob = Buffer.alloc(indexSize + col.dataLength);
|
|
293
|
+
for (let i = 0; i < col.offsets.length; i++)
|
|
294
|
+
blob.writeUInt32LE(col.offsets[i], i * 4);
|
|
295
|
+
blob.set(col.types, 4 * col.offsets.length);
|
|
296
|
+
return { name: col.name, blob, dataStart: indexSize };
|
|
297
|
+
}));
|
|
298
|
+
// For each source, copy its byte runs into every output column whose plan references it. A source
|
|
299
|
+
// that's not referenced by any column in this batch is skipped entirely — that's the point of the
|
|
300
|
+
// batch shape: read 20GB of inputs only once for the whole pass, not once per output.
|
|
301
|
+
for (let si = 0; si < sources.length; si++) {
|
|
302
|
+
let contributes = false;
|
|
303
|
+
for (let fi = 0; fi < plans.length && !contributes; fi++) {
|
|
304
|
+
for (const col of plans[fi].columns) {
|
|
305
|
+
if (col.runs.some(r => r.sourceIdx === si)) {
|
|
306
|
+
contributes = true;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!contributes)
|
|
312
|
+
continue;
|
|
313
|
+
let bytesRead = 0;
|
|
314
|
+
for (let fi = 0; fi < plans.length; fi++) {
|
|
315
|
+
const plan = plans[fi];
|
|
316
|
+
for (let ci = 0; ci < plan.columns.length; ci++) {
|
|
317
|
+
const col = plan.columns[ci];
|
|
318
|
+
const target = blobsPerFile[fi][ci];
|
|
319
|
+
const colIndex = indexesPerSource[si].get(col.name);
|
|
320
|
+
if (!colIndex)
|
|
321
|
+
continue;
|
|
322
|
+
for (const run of col.runs) {
|
|
323
|
+
if (run.sourceIdx !== si)
|
|
324
|
+
continue;
|
|
325
|
+
const bytes = await colIndex.readValueBytes(run.sourceStartRow, run.sourceEndRow);
|
|
326
|
+
if (bytes.length !== run.byteLength) {
|
|
327
|
+
throw new Error(`Expected ${run.byteLength} bytes from source #${si} (${sourceNames[si]}) column ${col.name} rows [${run.sourceStartRow}, ${run.sourceEndRow}), got ${bytes.length}`);
|
|
328
|
+
}
|
|
329
|
+
bytes.copy(target.blob, target.dataStart + run.outputByteStart);
|
|
330
|
+
bytesRead += bytes.length;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
log(`${(0, logColors_1.magenta)("input")} ${si + 1}/${sources.length} ${sourceNames[si]}: ${fmtBytes(bytesRead)} read`);
|
|
335
|
+
}
|
|
336
|
+
// Assemble + write each output file in this batch.
|
|
337
|
+
const outputs = [];
|
|
338
|
+
for (let fi = 0; fi < plans.length; fi++) {
|
|
339
|
+
const plan = plans[fi];
|
|
340
|
+
const valueColumns = blobsPerFile[fi].map(b => ({ name: b.name, blob: b.blob }));
|
|
341
|
+
const fileBuf = (0, BulkDatabaseFormat_1.assemblePlannedFile)({ valueColumns, keys: plan.keys, times: plan.times });
|
|
342
|
+
const { name, size } = await writeFile(fileBuf);
|
|
343
|
+
const sourcesNamed = new Map();
|
|
344
|
+
for (const [si, n] of plan.sourceCounts)
|
|
345
|
+
sourcesNamed.set(sourceNames[si], n);
|
|
346
|
+
log(`${(0, logColors_1.magenta)("output")} ${fi + 1}/${plans.length}: ${(0, format_1.formatNumber)(plan.keys.length)} rows from ${plan.sourceCounts.size} input(s), ${fmtBytes(size)}`);
|
|
347
|
+
outputs.push({ name, minKey: plan.minKey, maxKey: plan.maxKey, rowCount: plan.keys.length, size, sources: sourcesNamed });
|
|
348
|
+
}
|
|
349
|
+
return outputs;
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnVsa0RhdGFiYXNlTWVyZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJCdWxrRGF0YWJhc2VNZXJnZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxrRUFBcUU7QUFDckUsd0VBQXlFO0FBQ3pFLDZEQVE4QjtBQUU5QiwwR0FBMEc7QUFDMUcsMEdBQTBHO0FBQzFHLHFHQUFxRztBQUNyRyxNQUFNLDBCQUEwQixHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUUxRCxzR0FBc0c7QUFDdEcseUZBQXlGO0FBQ3pGLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxDQUFDO0FBRTdCLFNBQVMsUUFBUSxDQUFDLENBQVM7SUFDdkIsSUFBSSxDQUFDLEdBQUcsSUFBSTtRQUFFLE9BQU8sQ0FBQyxHQUFHLEdBQUcsQ0FBQztJQUM3QixJQUFJLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSTtRQUFFLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQztJQUN6RCxJQUFJLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxHQUFHLElBQUk7UUFBRSxPQUFPLENBQUMsQ0FBQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ3ZFLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDO0FBQ3RELENBQUM7QUErQ0QsZ0dBQWdHO0FBQ2hHLDJCQUEyQjtBQUMzQiw2RkFBNkY7QUFDN0Ysd0dBQXdHO0FBQ3hHLHlHQUF5RztBQUN6RyxxR0FBcUc7QUFDckcsbUdBQW1HO0FBQ25HLHdHQUF3RztBQUN4RyxnR0FBZ0c7QUFDaEcsbUdBQW1HO0FBQ25HLHNHQUFzRztBQUMvRixL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Q2hELE1BQU0sWUFBWSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBQy9DLEtBQUssTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsWUFBWTtZQUFFLFlBQVksQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzlFLEdBQUcsQ0FBQyxHQUFHLElBQUEsbUJBQU8sRUFBQyxRQUFRLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssSUFBQSxxQkFBWSxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLGNBQWMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN6SixPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7SUFDOUgsQ0FBQztJQUNELE9BQU8sT0FBTyxDQUFDO0FBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmb3JtYXROdW1iZXIgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9mb3JtYXR0aW5nL2Zvcm1hdFwiO1xuaW1wb3J0IHsgYmx1ZSwgbWFnZW50YSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2Zvcm1hdHRpbmcvbG9nQ29sb3JzXCI7XG5pbXBvcnQge1xuICAgIEJhc2VCdWxrRGF0YWJhc2VSZWFkZXIsXG4gICAgQ29sdW1uSW5kZXgsXG4gICAgYXNzZW1ibGVQbGFubmVkRmlsZSxcbiAgICBjb2x1bW5JbmRleEJ5dGVMZW5ndGgsXG4gICAgS0VZX0NPTFVNTixcbiAgICBUQVJHRVRfRklMRV9CWVRFUyxcbiAgICBUWVBFX0FCU0VOVF9UQUcsXG59IGZyb20gXCIuL0J1bGtEYXRhYmFzZUZvcm1hdFwiO1xuXG4vLyBEZWZhdWx0IHRvdGFsIGluLWZsaWdodCBidWZmZXIgYnVkZ2V0IGZvciB0aGUgZXhlY3V0b3I6IGhvdyBtdWNoIG91dHB1dCB2YWx1ZS1kYXRhIHdlIGhvbGQgaW4gbWVtb3J5IGF0XG4vLyBvbmNlLiBNdWx0aXBsZSBvdXRwdXQgZmlsZXMgKOKJpCBUQVJHRVRfRklMRV9CWVRFUyBlYWNoKSBhcmUgYnVpbHQgdG9nZXRoZXIgaW5zaWRlIHRoaXMgYnVkZ2V0IHNvIHJlYWRpbmdcbi8vIGlucHV0cyBvbmNlIGFtb3J0aXplcyB0aGVpciBJL08gYWNyb3NzIHNldmVyYWwgb3V0cHV0cy4gVGlnaHRlciBidWRnZXQg4oaSIG1vcmUgcGFzc2VzLCBsZXNzIG1lbW9yeS5cbmNvbnN0IERFRkFVTFRfT1VUUFVUX0JBVENIX0JZVEVTID0gMiAqIDEwMjQgKiAxMDI0ICogMTAyNDtcblxuLy8gUGVyLXZhbHVlIG9uLWRpc2sgb3ZlcmhlYWQgKDQtYnl0ZSBvZmZzZXQgZW50cnkgKyAxLWJ5dGUgdHlwZSB0YWcpLiBVc2VkIGZvciB0aGUgcGFydGl0aW9uLWN1dCBzaXplXG4vLyBlc3RpbWF0ZTsgdGhlIGV4ZWN1dG9yIGRvZXNuJ3QgdXNlIGl0IChvZmZzZXRzL3R5cGVzIGFyZSBzaXplZCBleGFjdGx5IGZyb20gdGhlIHBsYW4pLlxuY29uc3QgUEVSX1ZBTFVFX09WRVJIRUFEID0gNTtcblxuZnVuY3Rpb24gZm10Qnl0ZXMobjogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBpZiAobiA8IDEwMjQpIHJldHVybiBuICsgXCJCXCI7XG4gICAgaWYgKG4gPCAxMDI0ICogMTAyNCkgcmV0dXJuIChuIC8gMTAyNCkudG9GaXhlZCgxKSArIFwiS0JcIjtcbiAgICBpZiAobiA8IDEwMjQgKiAxMDI0ICogMTAyNCkgcmV0dXJuIChuIC8gMTAyNCAvIDEwMjQpLnRvRml4ZWQoMSkgKyBcIk1CXCI7XG4gICAgcmV0dXJuIChuIC8gMTAyNCAvIDEwMjQgLyAxMDI0KS50b0ZpeGVkKDIpICsgXCJHQlwiO1xufVxuXG4vLyBBIGNvbnRpZ3VvdXMgY29weSBvcGVyYXRpb246IHRha2UgYHNvdXJjZUVuZFJvdyAtIHNvdXJjZVN0YXJ0Um93YCBjb25zZWN1dGl2ZSByb3dzIG9mIG9uZSBzb3VyY2Vcbi8vIGNvbHVtbiwgc3BsaWNlIHRoZSByZXN1bHRpbmcgYnl0ZXMgaW50byB0aGUgb3V0cHV0IGNvbHVtbidzIGRhdGEgc2VjdGlvbiBhdCBvdXRwdXRCeXRlU3RhcnQuIEFkamFjZW50XG4vLyBwZXItcm93IGRlY2lzaW9ucyBnZXQgUkxFJ2QgaW50byBvbmUgY29weSBvcCDigJQgb25lIHNvdXJjZS1zaWRlIHJlYWQgKyBtZW1jcHkgaW5zdGVhZCBvZiBvbmUgcGVyIHJvdy5cbnR5cGUgQ29weVJ1biA9IHtcbiAgICBzb3VyY2VJZHg6IG51bWJlcjtcbiAgICBzb3VyY2VTdGFydFJvdzogbnVtYmVyO1xuICAgIHNvdXJjZUVuZFJvdzogbnVtYmVyO1xuICAgIG91dHB1dEJ5dGVTdGFydDogbnVtYmVyO1xuICAgIGJ5dGVMZW5ndGg6IG51bWJlcjtcbn07XG5cbnR5cGUgUGxhbm5lZE91dHB1dENvbHVtbiA9IHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgLy8gb2Zmc2V0c1tpXS4ub2Zmc2V0c1tpKzFdID0gcm93IGkncyB2YWx1ZSBieXRlIHJhbmdlIGluIHRoZSBjb2x1bW4ncyBkYXRhIHNlY3Rpb24uIFBvcHVsYXRlZCBieSB0aGVcbiAgICAvLyBwbGFubmVyOyB0aGUgZXhlY3V0b3Igd3JpdGVzIGl0IHZlcmJhdGltIGludG8gdGhlIG91dHB1dCBjb2x1bW4gYmxvYi5cbiAgICBvZmZzZXRzOiBVaW50MzJBcnJheTtcbiAgICAvLyBQZXItcm93IHR5cGUgdGFnIChUWVBFX0FCU0VOVCBmb3IgZmFsbC10aHJvdWdoKS4gUG9wdWxhdGVkIGJ5IHRoZSBwbGFubmVyLlxuICAgIHR5cGVzOiBVaW50OEFycmF5O1xuICAgIC8vIFRvdGFsIGJ5dGVzIHRoZSBkYXRhIHNlY3Rpb24gd2lsbCBvY2N1cHkgPSBvZmZzZXRzW3Jvd0NvdW50XS5cbiAgICBkYXRhTGVuZ3RoOiBudW1iZXI7XG4gICAgLy8gUnVuLWxlbmd0aCBlbmNvZGVkIHBlci1yb3cgY29weSBkZWNpc2lvbnMsIGluIG91dHB1dCByb3cgb3JkZXIuIEFCU0VOVCByb3dzIGNvbnRyaWJ1dGUgbm8gcnVuLlxuICAgIHJ1bnM6IENvcHlSdW5bXTtcbn07XG5cbmV4cG9ydCB0eXBlIFBsYW5uZWRPdXRwdXRGaWxlID0ge1xuICAgIGtleXM6IHN0cmluZ1tdO1xuICAgIHRpbWVzOiBudW1iZXJbXTtcbiAgICBtaW5LZXk6IHN0cmluZztcbiAgICBtYXhLZXk6IHN0cmluZztcbiAgICBjb2x1bW5zOiBQbGFubmVkT3V0cHV0Q29sdW1uW107XG4gICAgLy8gU3VtIG9mIGFsbCBjb2x1bW4gZGF0YSBzaXplcyArIGluZGV4IG92ZXJoZWFkICsgaGVhZGVyIGd1ZXNzOyB1c2VkIHRvIGdyb3VwIG91dHB1dHMgaW50byBiYXRjaGVzLlxuICAgIGVzdGltYXRlZEZpbGVCeXRlczogbnVtYmVyO1xuICAgIC8vIHNvdXJjZUlkeCDihpIgbm9uLUFCU0VOVCBjZWxsIGNvdW50IGNvbnRyaWJ1dGVkIHRvIHRoaXMgb3V0cHV0IGZpbGUgKGZvciBsb2dnaW5nIFwid2hlcmUgaXQgY2FtZSBmcm9tXCIpLlxuICAgIHNvdXJjZUNvdW50czogTWFwPG51bWJlciwgbnVtYmVyPjtcbn07XG5cbmV4cG9ydCB0eXBlIFBsYW5uZWRNZXJnZU91dHB1dCA9IHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgbWluS2V5OiBzdHJpbmc7XG4gICAgbWF4S2V5OiBzdHJpbmc7XG4gICAgcm93Q291bnQ6IG51bWJlcjtcbiAgICBzaXplOiBudW1iZXI7XG4gICAgc291cmNlczogTWFwPHN0cmluZywgbnVtYmVyPjtcbn07XG5cbi8vIFBsYW4gYSBtZXJnZSBvdmVyIGBzb3VyY2VzYCBhbmQgZXhlY3V0ZSBpdCwgd3JpdGluZyBvbmUgb3IgbW9yZSBvdXRwdXQgZmlsZXMgdmlhIHRoZSBjYWxsZXInc1xuLy8gYHdyaXRlRmlsZWAuIFR3byBwaGFzZXM6XG4vLyAgIOKAoiBQbGFubmluZzogbG9hZCBvbmx5IHBlci1jb2x1bW4gSU5ERVhFUyAob2Zmc2V0cyArIHR5cGVzIOKAlCB+NSBCL3Jvdywgc21hbGwgZXZlbiBvbiAyMEdCXG4vLyAgICAgY29sbGVjdGlvbnMpLCBkZXRlcm1pbmUgdGhlIHdpbm5pbmcgY2VsbCBwZXIgKGxpdmUga2V5LCBjb2x1bW4pIGJ5IG5ld2VzdCB3cml0ZS10aW1lICsgbm9uLUFCU0VOVFxuLy8gICAgIGZhbGwtdGhyb3VnaCwgc29ydCBrZXlzLCBwYXJ0aXRpb24gaW50byB+dGFyZ2V0RmlsZUJ5dGVzIG91dHB1dCBmaWxlcywgYW5kIHByZS1jb21wdXRlIGVhY2ggb3V0cHV0XG4vLyAgICAgY29sdW1uJ3Mgb2Zmc2V0cy90eXBlcyBhcnJheXMgcGx1cyBhIHJ1bi1sZW5ndGgtZW5jb2RlZCBjb3B5IHBsYW4gKG5vIHZhbHVlIGRhdGEgdG91Y2hlZCB5ZXQpLlxuLy8gICDigKIgRXhlY3V0ZTogZ3JvdXAgb3V0cHV0cyBpbnRvIH50YXJnZXRCYXRjaEJ5dGVzIGJhdGNoZXM7IHBlciBiYXRjaCwgYWxsb2NhdGUgY29sdW1uIGJsb2JzIHdpdGhcbi8vICAgICBvZmZzZXRzL3R5cGVzIGFscmVhZHkgZmlsbGVkIGluLCB0aGVuIGl0ZXJhdGUgaW5wdXQgc291cmNlcyBjb3B5aW5nIGNvbnRpZ3VvdXMgYnl0ZSBydW5zIHN0cmFpZ2h0XG4vLyAgICAgaW50byB0aGUgb3V0cHV0IGJ1ZmZlcnMuIEEgc291cmNlIHdpdGggbm8gY29udHJpYnV0aW9uIHRvIHRoaXMgYmF0Y2ggaXMgc2tpcHBlZCBlbnRpcmVseS5cbi8vIFJldHVybnMgdGhlIG5ldyBvdXRwdXQgZmlsZSBkZXNjcmlwdG9ycyBwbHVzIGFueSB0b21ic3RvbmVzIHdob3NlIG5ld2VzdCBldmVudCBpcyBzdGlsbCBhIGRlbGV0ZVxuLy8gKGNhcnJpZWQgZm9yd2FyZCB3aGVuIG9sZGVyIGZpbGVzIG91dHNpZGUgdGhlIG1lcmdlIGNvdWxkIHN0aWxsIGhvbGQgYSBub3ctc3RhbGUgc2V0IGZvciB0aGF0IGtleSkuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuUGxhbm5lZE1lcmdlKGNvbmZpZzoge1xuICAgIHNvdXJjZXM6IEJhc2VCdWxrRGF0YWJhc2VSZWFkZXJbXTtcbiAgICBzb3VyY2VOYW1lczogc3RyaW5nW107XG4gICAgY29sbGVjdGlvbk5hbWU6IHN0cmluZztcbiAgICB0YXJnZXRGaWxlQnl0ZXM/OiBudW1iZXI7XG4gICAgdGFyZ2V0QmF0Y2hCeXRlcz86IG51bWJlcjtcbiAgICAvLyBTaW5rIGZvciBzdGVwIGxpbmVzLiBXaGVuIG9taXR0ZWQsIGZhbGxzIGJhY2sgdG8gYSBibHVlLXByZWZpeGVkXG4gICAgLy8gY29uc29sZS5sb2cgc28gc3RhbmRhbG9uZSBjYWxsZXJzIHN0aWxsIGdldCBpZGVudGlmaWFibGUgb3V0cHV0LlxuICAgIGxvZz86IChsaW5lOiBzdHJpbmcpID0+IHZvaWQ7XG4gICAgd3JpdGVGaWxlOiAoZGF0YTogQnVmZmVyKSA9PiBQcm9taXNlPHsgbmFtZTogc3RyaW5nOyBzaXplOiBudW1iZXIgfT47XG59KTogUHJvbWlzZTx7IG91dHB1dHM6IFBsYW5uZWRNZXJnZU91dHB1dFtdOyBjYXJyaWVkRGVsZXRlczogTWFwPHN0cmluZywgbnVtYmVyPjsgdXNlZFNvdXJjZU5hbWVzOiBTZXQ8c3RyaW5nPiB9PiB7XG4gICAgY29uc3QgdGFyZ2V0RmlsZUJ5dGVzID0gY29uZmlnLnRhcmdldEZpbGVCeXRlcyA/PyBUQVJHRVRfRklMRV9CWVRFUztcbiAgICBjb25zdCB0YXJnZXRCYXRjaEJ5dGVzID0gY29uZmlnLnRhcmdldEJhdGNoQnl0ZXMgPz8gREVGQVVMVF9PVVRQVVRfQkFUQ0hfQllURVM7XG4gICAgY29uc3QgbG9nID0gY29uZmlnLmxvZyA/PyAobGluZSA9PiBjb25zb2xlLmxvZyhgJHtibHVlKGNvbmZpZy5jb2xsZWN0aW9uTmFtZSl9ICR7bGluZX1gKSk7XG5cbiAgICAvLyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgUGhhc2UgMTogcGxhbiDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcbiAgICAvLyBMb2FkIHBlci1zb3VyY2UgY29sdW1uIGluZGV4ZXMgRklSU1Qgc28gYSBmaWxlIHRoYXQncyBnb25lIChkZWxldGVkIGJldHdlZW4gY2FsbGVyJ3MgbGlzdEZpbGVzIGFuZFxuICAgIC8vIG5vdykgZ2V0cyBjYXVnaHQgaGVyZSBhbmQgZXhjbHVkZWQgZnJvbSB0aGUgbWVyZ2UgZW50aXJlbHkuIEVhY2ggc291cmNlJ3MgbG9hZCBpcyB3cmFwcGVkIGluIGFcbiAgICAvLyB0cnkvY2F0Y2g7IG9uIGZhaWx1cmUgd2UgbWFyayB0aGUgc291cmNlIGJhZCwgbG9nIGEgXCJza2lwcGVkXCIgbGluZSwgYW5kIHRoZSByZXN0IG9mIHBsYW5uaW5nICtcbiAgICAvLyBleGVjdXRlIHByZXRlbmRzIHRoZSBzb3VyY2UgZG9lc24ndCBleGlzdC4gVGhlIGNhbGxlciBvbmx5IGRlbGV0ZXMgaW5wdXRzIHRoYXQgd2VyZSBhY3R1YWxseSB1c2VkLlxuICAgIGNvbnN0IHNvdXJjZU9rID0gbmV3IEFycmF5PGJvb2xlYW4+KGNvbmZpZy5zb3VyY2VzLmxlbmd0aCkuZmlsbCh0cnVlKTtcbiAgICBjb25zdCBpbmRleGVzUGVyU291cmNlOiBNYXA8c3RyaW5nLCBDb2x1bW5JbmRleD5bXSA9IGF3YWl0IFByb21pc2UuYWxsKGNvbmZpZy5zb3VyY2VzLm1hcChhc3luYyAoc3JjLCBzaSkgPT4ge1xuICAgICAgICBjb25zdCBtYXAgPSBuZXcgTWFwPHN0cmluZywgQ29sdW1uSW5kZXg+KCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChzcmMuY29sdW1uc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoYyA9PiBjLmNvbHVtbiAhPT0gS0VZX0NPTFVNTilcbiAgICAgICAgICAgICAgICAubWFwKGFzeW5jIGMgPT4geyBtYXAuc2V0KGMuY29sdW1uLCBhd2FpdCBzcmMuZ2V0Q29sdW1uSW5kZXgoYy5jb2x1bW4pKTsgfSkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBzb3VyY2VPa1tzaV0gPSBmYWxzZTtcbiAgICAgICAgICAgIGxvZyhgJHttYWdlbnRhKFwic2tpcHBlZFwiKX0gJHtjb25maWcuc291cmNlTmFtZXNbc2ldfTogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICAgICAgICAgIC8vIFN0YWNrIGdvZXMgc3RyYWlnaHQgdG8gY29uc29sZSAobm90IHRoZSBidWZmZXJlZCBzdGVwIGxvZykgc28gdGhlIG1lcmdlIHN1bW1hcnkgc3RheXNcbiAgICAgICAgICAgIC8vIHJlYWRhYmxlIGJ1dCB3ZSBjYW4gc3RpbGwgdHJhY2Ugd2hlcmUgdGhlIGZhaWx1cmUgY2FtZSBmcm9tLlxuICAgICAgICAgICAgY29uc29sZS5sb2coYCR7Y29uZmlnLmNvbGxlY3Rpb25OYW1lfSBza2lwcGVkICR7Y29uZmlnLnNvdXJjZU5hbWVzW3NpXX06YCwgKGUgYXMgRXJyb3IpLnN0YWNrIHx8IGUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtYXA7XG4gICAgfSkpO1xuICAgIGNvbnN0IHVzZWRTb3VyY2VOYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGZvciAobGV0IHNpID0gMDsgc2kgPCBjb25maWcuc291cmNlcy5sZW5ndGg7IHNpKyspIHtcbiAgICAgICAgaWYgKHNvdXJjZU9rW3NpXSkgdXNlZFNvdXJjZU5hbWVzLmFkZChjb25maWcuc291cmNlTmFtZXNbc2ldKTtcbiAgICB9XG5cbiAgICAvLyBBZ2dyZWdhdGUga2V5VGltZXMgKyBkZWxldGVUaW1lcyBhY3Jvc3MgR09PRCBzb3VyY2VzIG9ubHkgKG1heCBwZXIga2V5KS4gQSBiYWQgc291cmNlJ3MgY2FjaGVkXG4gICAgLy8gbWV0YWRhdGEgbWlnaHQgY2xhaW0gYSBrZXkgYXMgbmV3ZXN0LCBidXQgd2UgY2FuJ3QgYWN0dWFsbHkgcmVhZCBpdHMgY2VsbHMg4oCUIGxldHRpbmcgaXQgd2luIHRoZVxuICAgIC8vIHRpbWUgcmVzb2x1dGlvbiB3b3VsZCBqdXN0IGRyb3AgdGhhdCBrZXkgb3V0IG9mIHRoZSBvdXRwdXQuXG4gICAgY29uc3QgZGVsZXRlVGltZSA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gICAgY29uc3Qga2V5VGltZSA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gICAgZm9yIChsZXQgc2kgPSAwOyBzaSA8IGNvbmZpZy5zb3VyY2VzLmxlbmd0aDsgc2krKykge1xuICAgICAgICBpZiAoIXNvdXJjZU9rW3NpXSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IHNyYyA9IGNvbmZpZy5zb3VyY2VzW3NpXTtcbiAgICAgICAgZm9yIChjb25zdCBbaywgdF0gb2Ygc3JjLmtleVRpbWVzKSB7XG4gICAgICAgICAgICBjb25zdCBwcmV2ID0ga2V5VGltZS5nZXQoayk7XG4gICAgICAgICAgICBpZiAocHJldiA9PT0gdW5kZWZpbmVkIHx8IHQgPiBwcmV2KSBrZXlUaW1lLnNldChrLCB0KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3JjLmRlbGV0ZVRpbWVzKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtrLCB0XSBvZiBzcmMuZGVsZXRlVGltZXMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwcmV2ID0gZGVsZXRlVGltZS5nZXQoayk7XG4gICAgICAgICAgICAgICAgaWYgKHByZXYgPT09IHVuZGVmaW5lZCB8fCB0ID4gcHJldikgZGVsZXRlVGltZS5zZXQoaywgdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBMaXZlIGtleXMgKG5ld2VzdCBzZXQgc3RyaWN0bHkgbmV3ZXIgdGhhbiBuZXdlc3QgZGVsZXRlKSArIHRvbWJzdG9uZXMgdG8gY2FycnkgZm9yd2FyZCAobmV3ZXN0XG4gICAgLy8gZXZlbnQgaXMgYSBkZWxldGUgYW5kIHRoZSBtZXJnZSBkb2Vzbid0IGluY2x1ZGUgdGhlIG9sZGVzdCBkYXRhIOKAlCB0aGF0J3MgdGhlIGNhbGxlcidzIGNhbGwpLlxuICAgIGNvbnN0IGxpdmVLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgW2ssIHRdIG9mIGtleVRpbWUpIHtcbiAgICAgICAgY29uc3QgZFQgPSBkZWxldGVUaW1lLmdldChrKSA/PyAtSW5maW5pdHk7XG4gICAgICAgIGlmICh0ID4gZFQpIGxpdmVLZXlzLnB1c2goayk7XG4gICAgfVxuICAgIGNvbnN0IGNhcnJpZWREZWxldGVzID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgICBmb3IgKGNvbnN0IFtrLCBkVF0gb2YgZGVsZXRlVGltZSkge1xuICAgICAgICBjb25zdCBzVCA9IGtleVRpbWUuZ2V0KGspID8/IC1JbmZpbml0eTtcbiAgICAgICAgaWYgKGRUID49IHNUKSBjYXJyaWVkRGVsZXRlcy5zZXQoaywgZFQpO1xuICAgIH1cblxuICAgIC8vIEFsbCBkaXN0aW5jdCB2YWx1ZSBjb2x1bW5zIGZyb20gR09PRCBzb3VyY2VzIChLRVlfQ09MVU1OIGV4Y2x1ZGVkIOKAlCBpdCdzIGFkZGVkIGF0IGZpbGUtYXNzZW1ibHlcbiAgICAvLyB0aW1lKS4gT3JkZXI6IGZpcnN0LXNlZW4sIG1hdGNoaW5nIHRoZSBleGlzdGluZyBidWlsZGVycy5cbiAgICBjb25zdCBhbGxDb2x1bW5zOiBzdHJpbmdbXSA9IFtdO1xuICAgIGNvbnN0IHNlZW5Db2xzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgZm9yIChsZXQgc2kgPSAwOyBzaSA8IGNvbmZpZy5zb3VyY2VzLmxlbmd0aDsgc2krKykge1xuICAgICAgICBpZiAoIXNvdXJjZU9rW3NpXSkgY29udGludWU7XG4gICAgICAgIGZvciAoY29uc3QgYyBvZiBjb25maWcuc291cmNlc1tzaV0uY29sdW1ucykge1xuICAgICAgICAgICAgaWYgKGMuY29sdW1uID09PSBLRVlfQ09MVU1OIHx8IHNlZW5Db2xzLmhhcyhjLmNvbHVtbikpIGNvbnRpbnVlO1xuICAgICAgICAgICAgc2VlbkNvbHMuYWRkKGMuY29sdW1uKTtcbiAgICAgICAgICAgIGFsbENvbHVtbnMucHVzaChjLmNvbHVtbik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBGb3IgZWFjaCBsaXZlIGtleSwgZm9yIGVhY2ggY29sdW1uLCBmaW5kIHRoZSB3aW5uaW5nIHNvdXJjZTogYW1vbmcgc291cmNlcyB0aGF0IGhhdmUgdGhpcyBrZXksIHRoZVxuICAgIC8vIG9uZSB3aG9zZSBrZXlUaW1lIGlzIGxhcmdlc3QgQU5EIHdob3NlIGNvbHVtbi1pbmRleCByZXBvcnRzIG5vbi1BQlNFTlQuIFJlY29yZCBzb3VyY2UgKyBzb3VyY2VSb3cgK1xuICAgIC8vIGJ5dGVMZW4gKyB0eXBlIHNvIHRoZSBwbGFubmVyIGNhbiBzaXplIG9mZnNldHMgYW5kIHRoZSBleGVjdXRvciBjYW4gY29weSB0aGUgYnl0ZXMuXG4gICAgdHlwZSBDZWxsQ2hvaWNlID0geyBzb3VyY2VJZHg6IG51bWJlcjsgc291cmNlUm93OiBudW1iZXI7IGJ5dGVMZW46IG51bWJlcjsgdHlwZTogbnVtYmVyIH07XG4gICAgY29uc3QgY2VsbHNQZXJLZXkgPSBuZXcgTWFwPHN0cmluZywgKENlbGxDaG9pY2UgfCB1bmRlZmluZWQpW10+KCk7XG4gICAgZm9yIChjb25zdCBrZXkgb2YgbGl2ZUtleXMpIHtcbiAgICAgICAgY29uc3QgY2VsbHM6IChDZWxsQ2hvaWNlIHwgdW5kZWZpbmVkKVtdID0gbmV3IEFycmF5KGFsbENvbHVtbnMubGVuZ3RoKTtcbiAgICAgICAgZm9yIChsZXQgY2kgPSAwOyBjaSA8IGFsbENvbHVtbnMubGVuZ3RoOyBjaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBjb2wgPSBhbGxDb2x1bW5zW2NpXTtcbiAgICAgICAgICAgIGxldCBiZXN0VGltZSA9IC1JbmZpbml0eTtcbiAgICAgICAgICAgIGxldCBiZXN0OiBDZWxsQ2hvaWNlIHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgZm9yIChsZXQgc2kgPSAwOyBzaSA8IGNvbmZpZy5zb3VyY2VzLmxlbmd0aDsgc2krKykge1xuICAgICAgICAgICAgICAgIGlmICghc291cmNlT2tbc2ldKSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICBjb25zdCBzcmMgPSBjb25maWcuc291cmNlc1tzaV07XG4gICAgICAgICAgICAgICAgY29uc3QgdCA9IHNyYy5rZXlUaW1lcy5nZXQoa2V5KTtcbiAgICAgICAgICAgICAgICBpZiAodCA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICBjb25zdCByb3dJZHggPSBzcmMucm93T2ZLZXkoa2V5KTtcbiAgICAgICAgICAgICAgICBpZiAocm93SWR4ID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIGNvbnN0IGlkeCA9IGluZGV4ZXNQZXJTb3VyY2Vbc2ldLmdldChjb2wpO1xuICAgICAgICAgICAgICAgIGlmICghaWR4KSBjb250aW51ZTtcbiAgICAgICAgICAgICAgICBjb25zdCB0eXBlID0gaWR4LnR5cGVzW3Jvd0lkeF07XG4gICAgICAgICAgICAgICAgaWYgKHR5cGUgPT09IFRZUEVfQUJTRU5UX1RBRykgY29udGludWU7XG4gICAgICAgICAgICAgICAgaWYgKHQgPiBiZXN0VGltZSkge1xuICAgICAgICAgICAgICAgICAgICBiZXN0VGltZSA9IHQ7XG4gICAgICAgICAgICAgICAgICAgIGJlc3QgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VJZHg6IHNpLFxuICAgICAgICAgICAgICAgICAgICAgICAgc291cmNlUm93OiByb3dJZHgsXG4gICAgICAgICAgICAgICAgICAgICAgICBieXRlTGVuOiBpZHgub2Zmc2V0c1tyb3dJZHggKyAxXSAtIGlkeC5vZmZzZXRzW3Jvd0lkeF0sXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlLFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNlbGxzW2NpXSA9IGJlc3Q7XG4gICAgICAgIH1cbiAgICAgICAgY2VsbHNQZXJLZXkuc2V0KGtleSwgY2VsbHMpO1xuICAgIH1cblxuICAgIC8vIFNvcnQgbGl2ZSBrZXlzIGxleGljb2dyYXBoaWNhbGx5IHNvIGVhY2ggb3V0cHV0IGZpbGUgaXMga2V5LWNvbnRpZ3VvdXMgKHRpZ2h0IG1pbktleS9tYXhLZXkgKyBmYXN0XG4gICAgLy8gc2luZ2xlLWtleSByZWFkcyB2aWEgaGVhZGVyIHNraXApLlxuICAgIGxpdmVLZXlzLnNvcnQoKGEsIGIpID0+IGEgPCBiID8gLTEgOiBhID4gYiA/IDEgOiAwKTtcblxuICAgIC8vIFBlci1rZXkgZXN0aW1hdGVkIGJ5dGVzIGZvciBwYXJ0aXRpb24gY3V0dGluZzogS0VZX0NPTFVNTiBjZWxsICsgcGVyIHZhbHVlLWNvbHVtbiBjZWxsIChieXRlcyArIDVCXG4gICAgLy8gb3ZlcmhlYWQpICsgVElNRV9DT0xVTU4gY2VsbC4gUm91Z2gg4oCUIG9ubHkgbmVlZHMgdG8ga2VlcCBlYWNoIG91dHB1dCBuZWFyIHRoZSB0YXJnZXQuXG4gICAgZnVuY3Rpb24ga2V5VG90YWxCeXRlcyhrZXk6IHN0cmluZyk6IG51bWJlciB7XG4gICAgICAgIGNvbnN0IGNlbGxzID0gY2VsbHNQZXJLZXkuZ2V0KGtleSkhO1xuICAgICAgICBsZXQgdG90YWwgPSBrZXkubGVuZ3RoICogMiArIFBFUl9WQUxVRV9PVkVSSEVBRDtcbiAgICAgICAgZm9yIChjb25zdCBjZWxsIG9mIGNlbGxzKSB0b3RhbCArPSAoY2VsbCA/IGNlbGwuYnl0ZUxlbiA6IDApICsgUEVSX1ZBTFVFX09WRVJIRUFEO1xuICAgICAgICB0b3RhbCArPSA4ICsgUEVSX1ZBTFVFX09WRVJIRUFEO1xuICAgICAgICByZXR1cm4gdG90YWw7XG4gICAgfVxuXG4gICAgLy8gV2FsayBzb3J0ZWQga2V5cywgY3V0IGVhY2ggZmlsZSB3aGVuIGFjY3VtdWxhdGVkIGJ5dGVzIHdvdWxkIGV4Y2VlZCB0YXJnZXRGaWxlQnl0ZXMuIEEgc2luZ2xlIGtleVxuICAgIC8vIGxhcmdlciB0aGFuIHRoZSB0YXJnZXQgc3RpbGwgYmVjb21lcyBpdHMgb3duIChvdmVyc2l6ZWQpIGZpbGUg4oCUIHdlIG5ldmVyIHNwbGl0IHdpdGhpbiBhIGtleS5cbiAgICBjb25zdCBmaWxlS2V5UmFuZ2VzOiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH1bXSA9IFtdO1xuICAgIHtcbiAgICAgICAgbGV0IGNodW5rU3RhcnQgPSAwO1xuICAgICAgICBsZXQgY2h1bmtCeXRlcyA9IDA7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbGl2ZUtleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGtiID0ga2V5VG90YWxCeXRlcyhsaXZlS2V5c1tpXSk7XG4gICAgICAgICAgICBpZiAoaSA+IGNodW5rU3RhcnQgJiYgY2h1bmtCeXRlcyArIGtiID4gdGFyZ2V0RmlsZUJ5dGVzKSB7XG4gICAgICAgICAgICAgICAgZmlsZUtleVJhbmdlcy5wdXNoKHsgc3RhcnQ6IGNodW5rU3RhcnQsIGVuZDogaSB9KTtcbiAgICAgICAgICAgICAgICBjaHVua1N0YXJ0ID0gaTtcbiAgICAgICAgICAgICAgICBjaHVua0J5dGVzID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNodW5rQnl0ZXMgKz0ga2I7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGxpdmVLZXlzLmxlbmd0aCA+IGNodW5rU3RhcnQpIGZpbGVLZXlSYW5nZXMucHVzaCh7IHN0YXJ0OiBjaHVua1N0YXJ0LCBlbmQ6IGxpdmVLZXlzLmxlbmd0aCB9KTtcbiAgICB9XG5cbiAgICAvLyBCdWlsZCBwZXItZmlsZSBwbGFuczogb2Zmc2V0cy90eXBlcy9jb3B5LXJ1bnMgcGVyIGNvbHVtbi5cbiAgICBjb25zdCBwbGFucyA9IGZpbGVLZXlSYW5nZXMubWFwKHJhbmdlID0+IGJ1aWxkT3V0cHV0UGxhbihyYW5nZSwgbGl2ZUtleXMsIGNlbGxzUGVyS2V5LCBhbGxDb2x1bW5zLCBrZXlUaW1lKSk7XG5cbiAgICBsb2coYCR7bWFnZW50YShcInBsYW5cIil9OiAke2Zvcm1hdE51bWJlcihsaXZlS2V5cy5sZW5ndGgpfSBsaXZlIGtleXMsICR7cGxhbnMubGVuZ3RofSBvdXRwdXQgZmlsZShzKSwgJHtmb3JtYXROdW1iZXIoY2FycmllZERlbGV0ZXMuc2l6ZSl9IHRvbWJzdG9uZXMgY2FycmllZGApO1xuXG4gICAgLy8g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAIFBoYXNlIDI6IGV4ZWN1dGUg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gICAgLy8gR3JvdXAgb3V0cHV0IGZpbGVzIGludG8gYmF0Y2hlcyB0aGF0IGZpdCB3aXRoaW4gdGFyZ2V0QmF0Y2hCeXRlcyBzbyB3ZSByZWFkIGlucHV0cyBvbmNlIHBlciBiYXRjaFxuICAgIC8vIChhbmQgc2tpcCBpbnB1dHMgdGhhdCBjb250cmlidXRlIG5vdGhpbmcgdG8gdGhpcyBiYXRjaCkuXG4gICAgY29uc3QgYmF0Y2hlczogUGxhbm5lZE91dHB1dEZpbGVbXVtdID0gW107XG4gICAge1xuICAgICAgICBsZXQgc3RhcnQgPSAwO1xuICAgICAgICB3aGlsZSAoc3RhcnQgPCBwbGFucy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGxldCBlbmQgPSBzdGFydCArIDE7XG4gICAgICAgICAgICBsZXQgdG90YWwgPSBwbGFuc1tzdGFydF0uZXN0aW1hdGVkRmlsZUJ5dGVzO1xuICAgICAgICAgICAgd2hpbGUgKGVuZCA8IHBsYW5zLmxlbmd0aCAmJiB0b3RhbCArIHBsYW5zW2VuZF0uZXN0aW1hdGVkRmlsZUJ5dGVzIDw9IHRhcmdldEJhdGNoQnl0ZXMpIHtcbiAgICAgICAgICAgICAgICB0b3RhbCArPSBwbGFuc1tlbmRdLmVzdGltYXRlZEZpbGVCeXRlcztcbiAgICAgICAgICAgICAgICBlbmQrKztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJhdGNoZXMucHVzaChwbGFucy5zbGljZShzdGFydCwgZW5kKSk7XG4gICAgICAgICAgICBzdGFydCA9IGVuZDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IG91dHB1dHM6IFBsYW5uZWRNZXJnZU91dHB1dFtdID0gW107XG4gICAgZm9yIChsZXQgYmkgPSAwOyBiaSA8IGJhdGNoZXMubGVuZ3RoOyBiaSsrKSB7XG4gICAgICAgIGNvbnN0IGJhdGNoID0gYmF0Y2hlc1tiaV07XG4gICAgICAgIGNvbnN0IGJhdGNoQnl0ZXMgPSBiYXRjaC5yZWR1Y2UoKGEsIHApID0+IGEgKyBwLmVzdGltYXRlZEZpbGVCeXRlcywgMCk7XG4gICAgICAgIGxvZyhgJHttYWdlbnRhKFwiYmF0Y2hcIil9ICR7YmkgKyAxfS8ke2JhdGNoZXMubGVuZ3RofTogJHtiYXRjaC5sZW5ndGh9IG91dHB1dCBmaWxlKHMpLCB+JHtmbXRCeXRlcyhiYXRjaEJ5dGVzKX0gYnVkZ2V0YCk7XG4gICAgICAgIGNvbnN0IGJhdGNoT3V0cHV0cyA9IGF3YWl0IGV4ZWN1dGVCYXRjaChiYXRjaCwgaW5kZXhlc1BlclNvdXJjZSwgY29uZmlnLnNvdXJjZXMsIGNvbmZpZy5zb3VyY2VOYW1lcywgY29uZmlnLndyaXRlRmlsZSwgbG9nKTtcbiAgICAgICAgb3V0cHV0cy5wdXNoKC4uLmJhdGNoT3V0cHV0cyk7XG4gICAgfVxuICAgIGNvbnN0IHdyaXR0ZW5CeXRlcyA9IG91dHB1dHMucmVkdWNlKChhLCBvKSA9PiBhICsgby5zaXplLCAwKTtcbiAgICBsb2coYCR7bWFnZW50YShcImV4ZWN1dGVcIil9OiAke291dHB1dHMubGVuZ3RofSBmaWxlKHMpLCAke2ZtdEJ5dGVzKHdyaXR0ZW5CeXRlcyl9IHdyaXR0ZW5gKTtcblxuICAgIHJldHVybiB7IG91dHB1dHMsIGNhcnJpZWREZWxldGVzLCB1c2VkU291cmNlTmFtZXMgfTtcbn1cblxuZnVuY3Rpb24gYnVpbGRPdXRwdXRQbGFuKFxuICAgIHJhbmdlOiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyIH0sXG4gICAgbGl2ZUtleXM6IHN0cmluZ1tdLFxuICAgIGNlbGxzUGVyS2V5OiBNYXA8c3RyaW5nLCAoeyBzb3VyY2VJZHg6IG51bWJlcjsgc291cmNlUm93OiBudW1iZXI7IGJ5dGVMZW46IG51bWJlcjsgdHlwZTogbnVtYmVyIH0gfCB1bmRlZmluZWQpW10+LFxuICAgIGFsbENvbHVtbnM6IHN0cmluZ1tdLFxuICAgIGtleVRpbWU6IE1hcDxzdHJpbmcsIG51bWJlcj4sXG4pOiBQbGFubmVkT3V0cHV0RmlsZSB7XG4gICAgY29uc3Qga2V5cyA9IGxpdmVLZXlzLnNsaWNlKHJhbmdlLnN0YXJ0LCByYW5nZS5lbmQpO1xuICAgIGNvbnN0IHJvd0NvdW50ID0ga2V5cy5sZW5ndGg7XG4gICAgY29uc3QgdGltZXMgPSBrZXlzLm1hcChrID0+IGtleVRpbWUuZ2V0KGspID8/IDApO1xuICAgIGNvbnN0IHNvdXJjZUNvdW50cyA9IG5ldyBNYXA8bnVtYmVyLCBudW1iZXI+KCk7XG5cbiAgICBjb25zdCBjb2x1bW5zOiBQbGFubmVkT3V0cHV0Q29sdW1uW10gPSBhbGxDb2x1bW5zLm1hcCgoY29sTmFtZSwgY2kpID0+IHtcbiAgICAgICAgY29uc3Qgb2Zmc2V0cyA9IG5ldyBVaW50MzJBcnJheShyb3dDb3VudCArIDEpO1xuICAgICAgICBjb25zdCB0eXBlcyA9IG5ldyBVaW50OEFycmF5KHJvd0NvdW50KTtcbiAgICAgICAgY29uc3QgcnVuczogQ29weVJ1bltdID0gW107XG4gICAgICAgIGxldCBvdXRwdXRCeXRlID0gMDtcbiAgICAgICAgbGV0IGN1cnJlbnRSdW46IENvcHlSdW4gfCB1bmRlZmluZWQ7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByb3dDb3VudDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBjZWxsID0gY2VsbHNQZXJLZXkuZ2V0KGtleXNbaV0pIVtjaV07XG4gICAgICAgICAgICBvZmZzZXRzW2ldID0gb3V0cHV0Qnl0ZTtcbiAgICAgICAgICAgIGlmICghY2VsbCkge1xuICAgICAgICAgICAgICAgIHR5cGVzW2ldID0gVFlQRV9BQlNFTlRfVEFHO1xuICAgICAgICAgICAgICAgIC8vIEFCU0VOVCBjb250cmlidXRlcyBub3RoaW5nIHRvIHRoZSBkYXRhIHNlY3Rpb24gYW5kIGJyZWFrcyBhbnkgZXh0ZW5kaW5nIHJ1bi5cbiAgICAgICAgICAgICAgICBpZiAoY3VycmVudFJ1bikgeyBydW5zLnB1c2goY3VycmVudFJ1bik7IGN1cnJlbnRSdW4gPSB1bmRlZmluZWQ7IH1cbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHR5cGVzW2ldID0gY2VsbC50eXBlO1xuICAgICAgICAgICAgc291cmNlQ291bnRzLnNldChjZWxsLnNvdXJjZUlkeCwgKHNvdXJjZUNvdW50cy5nZXQoY2VsbC5zb3VyY2VJZHgpID8/IDApICsgMSk7XG4gICAgICAgICAgICAvLyBSTEU6IGV4dGVuZCB0aGUgY3VycmVudCBydW4gaWZmIHRoZSBuZXh0IGNlbGwgaXMgdGhlIG5leHQgcm93IG9mIHRoZSBzYW1lIHNvdXJjZSAoaXRzXG4gICAgICAgICAgICAvLyBzb3VyY2Utc2lkZSBieXRlcyBzaXQgaW1tZWRpYXRlbHkgYWZ0ZXIsIHNvIG9uZSByZWFkIHN1ZmZpY2VzKSBBTkQgbm9uLUFCU0VOVCAod2UgbmV2ZXJcbiAgICAgICAgICAgIC8vIGxhbmRlZCBpbiB0aGUgYnJlYWstcGF0aCBhYm92ZSkuXG4gICAgICAgICAgICBpZiAoY3VycmVudFJ1biAmJiBjdXJyZW50UnVuLnNvdXJjZUlkeCA9PT0gY2VsbC5zb3VyY2VJZHggJiYgY3VycmVudFJ1bi5zb3VyY2VFbmRSb3cgPT09IGNlbGwuc291cmNlUm93KSB7XG4gICAgICAgICAgICAgICAgY3VycmVudFJ1bi5zb3VyY2VFbmRSb3cgPSBjZWxsLnNvdXJjZVJvdyArIDE7XG4gICAgICAgICAgICAgICAgY3VycmVudFJ1bi5ieXRlTGVuZ3RoICs9IGNlbGwuYnl0ZUxlbjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRSdW4pIHJ1bnMucHVzaChjdXJyZW50UnVuKTtcbiAgICAgICAgICAgICAgICBjdXJyZW50UnVuID0ge1xuICAgICAgICAgICAgICAgICAgICBzb3VyY2VJZHg6IGNlbGwuc291cmNlSWR4LFxuICAgICAgICAgICAgICAgICAgICBzb3VyY2VTdGFydFJvdzogY2VsbC5zb3VyY2VSb3csXG4gICAgICAgICAgICAgICAgICAgIHNvdXJjZUVuZFJvdzogY2VsbC5zb3VyY2VSb3cgKyAxLFxuICAgICAgICAgICAgICAgICAgICBvdXRwdXRCeXRlU3RhcnQ6IG91dHB1dEJ5dGUsXG4gICAgICAgICAgICAgICAgICAgIGJ5dGVMZW5ndGg6IGNlbGwuYnl0ZUxlbixcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb3V0cHV0Qnl0ZSArPSBjZWxsLmJ5dGVMZW47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGN1cnJlbnRSdW4pIHJ1bnMucHVzaChjdXJyZW50UnVuKTtcbiAgICAgICAgb2Zmc2V0c1tyb3dDb3VudF0gPSBvdXRwdXRCeXRlO1xuXG4gICAgICAgIHJldHVybiB7IG5hbWU6IGNvbE5hbWUsIG9mZnNldHMsIHR5cGVzLCBkYXRhTGVuZ3RoOiBvdXRwdXRCeXRlLCBydW5zIH07XG4gICAgfSk7XG5cbiAgICAvLyBGaWxlIHNpemUgZXN0aW1hdGU6IEtFWV9DT0xVTU4gYmxvYiArIHZhbHVlIGNvbHVtbiBibG9icyArIFRJTUVfQ09MVU1OIGJsb2IgKyBoZWFkZXIgZ3Vlc3MuIFVzZWQgdG9cbiAgICAvLyBiYXRjaCBvdXRwdXQgZmlsZXM7IG9ubHkgbmVlZHMgdG8gYmUgY2xvc2UsIG5vdCBleGFjdC5cbiAgICBsZXQgZXN0aW1hdGVkRmlsZUJ5dGVzID0gNCArIDIwNDg7XG4gICAgbGV0IGtleUJ5dGVzID0gMDtcbiAgICBmb3IgKGNvbnN0IGsgb2Yga2V5cykga2V5Qnl0ZXMgKz0gay5sZW5ndGggKiAyO1xuICAgIGVzdGltYXRlZEZpbGVCeXRlcyArPSBjb2x1bW5JbmRleEJ5dGVMZW5ndGgocm93Q291bnQpICsga2V5Qnl0ZXM7XG4gICAgZm9yIChjb25zdCBjb2wgb2YgY29sdW1ucykgZXN0aW1hdGVkRmlsZUJ5dGVzICs9IGNvbHVtbkluZGV4Qnl0ZUxlbmd0aChyb3dDb3VudCkgKyBjb2wuZGF0YUxlbmd0aDtcbiAgICBlc3RpbWF0ZWRGaWxlQnl0ZXMgKz0gY29sdW1uSW5kZXhCeXRlTGVuZ3RoKHJvd0NvdW50KSArIHJvd0NvdW50ICogODtcblxuICAgIHJldHVybiB7XG4gICAgICAgIGtleXMsXG4gICAgICAgIHRpbWVzLFxuICAgICAgICBtaW5LZXk6IGtleXNbMF0gPz8gXCJcIixcbiAgICAgICAgbWF4S2V5OiBrZXlzW3Jvd0NvdW50IC0gMV0gPz8gXCJcIixcbiAgICAgICAgY29sdW1ucyxcbiAgICAgICAgZXN0aW1hdGVkRmlsZUJ5dGVzLFxuICAgICAgICBzb3VyY2VDb3VudHMsXG4gICAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZXhlY3V0ZUJhdGNoKFxuICAgIHBsYW5zOiBQbGFubmVkT3V0cHV0RmlsZVtdLFxuICAgIGluZGV4ZXNQZXJTb3VyY2U6IE1hcDxzdHJpbmcsIENvbHVtbkluZGV4PltdLFxuICAgIHNvdXJjZXM6IEJhc2VCdWxrRGF0YWJhc2VSZWFkZXJbXSxcbiAgICBzb3VyY2VOYW1lczogc3RyaW5nW10sXG4gICAgd3JpdGVGaWxlOiAoZGF0YTogQnVmZmVyKSA9PiBQcm9taXNlPHsgbmFtZTogc3RyaW5nOyBzaXplOiBudW1iZXIgfT4sXG4gICAgbG9nOiAobGluZTogc3RyaW5nKSA9PiB2b2lkLFxuKTogUHJvbWlzZTxQbGFubmVkTWVyZ2VPdXRwdXRbXT4ge1xuICAgIC8vIEFsbG9jYXRlIG9uZSBiaWcgYnVmZmVyIHBlciAob3V0cHV0IGZpbGUsIGNvbHVtbikg4oCUIG9mZnNldHMgKyB0eXBlcyBhcmUgd3JpdHRlbiBpbW1lZGlhdGVseSBmcm9tXG4gICAgLy8gdGhlIHBsYW4sIHRoZSBkYXRhIHNlY3Rpb24gaXMgZmlsbGVkIGJlbG93IGJ5IHRoZSBwZXItc291cmNlIGNvcHkgbG9vcC5cbiAgICB0eXBlIENvbHVtbkJ1ZmZlciA9IHsgbmFtZTogc3RyaW5nOyBibG9iOiBCdWZmZXI7IGRhdGFTdGFydDogbnVtYmVyIH07XG4gICAgY29uc3QgYmxvYnNQZXJGaWxlOiBDb2x1bW5CdWZmZXJbXVtdID0gcGxhbnMubWFwKHBsYW4gPT4gcGxhbi5jb2x1bW5zLm1hcChjb2wgPT4ge1xuICAgICAgICBjb25zdCBpbmRleFNpemUgPSBjb2x1bW5JbmRleEJ5dGVMZW5ndGgoY29sLm9mZnNldHMubGVuZ3RoIC0gMSk7XG4gICAgICAgIGNvbnN0IGJsb2IgPSBCdWZmZXIuYWxsb2MoaW5kZXhTaXplICsgY29sLmRhdGFMZW5ndGgpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvbC5vZmZzZXRzLmxlbmd0aDsgaSsrKSBibG9iLndyaXRlVUludDMyTEUoY29sLm9mZnNldHNbaV0sIGkgKiA0KTtcbiAgICAgICAgYmxvYi5zZXQoY29sLnR5cGVzLCA0ICogY29sLm9mZnNldHMubGVuZ3RoKTtcbiAgICAgICAgcmV0dXJuIHsgbmFtZTogY29sLm5hbWUsIGJsb2IsIGRhdGFTdGFydDogaW5kZXhTaXplIH07XG4gICAgfSkpO1xuXG4gICAgLy8gRm9yIGVhY2ggc291cmNlLCBjb3B5IGl0cyBieXRlIHJ1bnMgaW50byBldmVyeSBvdXRwdXQgY29sdW1uIHdob3NlIHBsYW4gcmVmZXJlbmNlcyBpdC4gQSBzb3VyY2VcbiAgICAvLyB0aGF0J3Mgbm90IHJlZmVyZW5jZWQgYnkgYW55IGNvbHVtbiBpbiB0aGlzIGJhdGNoIGlzIHNraXBwZWQgZW50aXJlbHkg4oCUIHRoYXQncyB0aGUgcG9pbnQgb2YgdGhlXG4gICAgLy8gYmF0Y2ggc2hhcGU6IHJlYWQgMjBHQiBvZiBpbnB1dHMgb25seSBvbmNlIGZvciB0aGUgd2hvbGUgcGFzcywgbm90IG9uY2UgcGVyIG91dHB1dC5cbiAgICBmb3IgKGxldCBzaSA9IDA7IHNpIDwgc291cmNlcy5sZW5ndGg7IHNpKyspIHtcbiAgICAgICAgbGV0IGNvbnRyaWJ1dGVzID0gZmFsc2U7XG4gICAgICAgIGZvciAobGV0IGZpID0gMDsgZmkgPCBwbGFucy5sZW5ndGggJiYgIWNvbnRyaWJ1dGVzOyBmaSsrKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGNvbCBvZiBwbGFuc1tmaV0uY29sdW1ucykge1xuICAgICAgICAgICAgICAgIGlmIChjb2wucnVucy5zb21lKHIgPT4gci5zb3VyY2VJZHggPT09IHNpKSkgeyBjb250cmlidXRlcyA9IHRydWU7IGJyZWFrOyB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFjb250cmlidXRlcykgY29udGludWU7XG5cbiAgICAgICAgbGV0IGJ5dGVzUmVhZCA9IDA7XG4gICAgICAgIGZvciAobGV0IGZpID0gMDsgZmkgPCBwbGFucy5sZW5ndGg7IGZpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IHBsYW4gPSBwbGFuc1tmaV07XG4gICAgICAgICAgICBmb3IgKGxldCBjaSA9IDA7IGNpIDwgcGxhbi5jb2x1bW5zLmxlbmd0aDsgY2krKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNvbCA9IHBsYW4uY29sdW1uc1tjaV07XG4gICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0ID0gYmxvYnNQZXJGaWxlW2ZpXVtjaV07XG4gICAgICAgICAgICAgICAgY29uc3QgY29sSW5kZXggPSBpbmRleGVzUGVyU291cmNlW3NpXS5nZXQoY29sLm5hbWUpO1xuICAgICAgICAgICAgICAgIGlmICghY29sSW5kZXgpIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIGZvciAoY29uc3QgcnVuIG9mIGNvbC5ydW5zKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChydW4uc291cmNlSWR4ICE9PSBzaSkgY29udGludWU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGJ5dGVzID0gYXdhaXQgY29sSW5kZXgucmVhZFZhbHVlQnl0ZXMocnVuLnNvdXJjZVN0YXJ0Um93LCBydW4uc291cmNlRW5kUm93KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGJ5dGVzLmxlbmd0aCAhPT0gcnVuLmJ5dGVMZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtydW4uYnl0ZUxlbmd0aH0gYnl0ZXMgZnJvbSBzb3VyY2UgIyR7c2l9ICgke3NvdXJjZU5hbWVzW3NpXX0pIGNvbHVtbiAke2NvbC5uYW1lfSByb3dzIFske3J1bi5zb3VyY2VTdGFydFJvd30sICR7cnVuLnNvdXJjZUVuZFJvd30pLCBnb3QgJHtieXRlcy5sZW5ndGh9YCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnl0ZXMuY29weSh0YXJnZXQuYmxvYiwgdGFyZ2V0LmRhdGFTdGFydCArIHJ1bi5vdXRwdXRCeXRlU3RhcnQpO1xuICAgICAgICAgICAgICAgICAgICBieXRlc1JlYWQgKz0gYnl0ZXMubGVuZ3RoO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBsb2coYCR7bWFnZW50YShcImlucHV0XCIpfSAke3NpICsgMX0vJHtzb3VyY2VzLmxlbmd0aH0gJHtzb3VyY2VOYW1lc1tzaV19OiAke2ZtdEJ5dGVzKGJ5dGVzUmVhZCl9IHJlYWRgKTtcbiAgICB9XG5cbiAgICAvLyBBc3NlbWJsZSArIHdyaXRlIGVhY2ggb3V0cHV0IGZpbGUgaW4gdGhpcyBiYXRjaC5cbiAgICBjb25zdCBvdXRwdXRzOiBQbGFubmVkTWVyZ2VPdXRwdXRbXSA9IFtdO1xuICAgIGZvciAobGV0IGZpID0gMDsgZmkgPCBwbGFucy5sZW5ndGg7IGZpKyspIHtcbiAgICAgICAgY29uc3QgcGxhbiA9IHBsYW5zW2ZpXTtcbiAgICAgICAgY29uc3QgdmFsdWVDb2x1bW5zID0gYmxvYnNQZXJGaWxlW2ZpXS5tYXAoYiA9PiAoeyBuYW1lOiBiLm5hbWUsIGJsb2I6IGIuYmxvYiB9KSk7XG4gICAgICAgIGNvbnN0IGZpbGVCdWYgPSBhc3NlbWJsZVBsYW5uZWRGaWxlKHsgdmFsdWVDb2x1bW5zLCBrZXlzOiBwbGFuLmtleXMsIHRpbWVzOiBwbGFuLnRpbWVzIH0pO1xuICAgICAgICBjb25zdCB7IG5hbWUsIHNpemUgfSA9IGF3YWl0IHdyaXRlRmlsZShmaWxlQnVmKTtcbiAgICAgICAgY29uc3Qgc291cmNlc05hbWVkID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTtcbiAgICAgICAgZm9yIChjb25zdCBbc2ksIG5dIG9mIHBsYW4uc291cmNlQ291bnRzKSBzb3VyY2VzTmFtZWQuc2V0KHNvdXJjZU5hbWVzW3NpXSwgbik7XG4gICAgICAgIGxvZyhgJHttYWdlbnRhKFwib3V0cHV0XCIpfSAke2ZpICsgMX0vJHtwbGFucy5sZW5ndGh9OiAke2Zvcm1hdE51bWJlcihwbGFuLmtleXMubGVuZ3RoKX0gcm93cyBmcm9tICR7cGxhbi5zb3VyY2VDb3VudHMuc2l6ZX0gaW5wdXQocyksICR7Zm10Qnl0ZXMoc2l6ZSl9YCk7XG4gICAgICAgIG91dHB1dHMucHVzaCh7IG5hbWUsIG1pbktleTogcGxhbi5taW5LZXksIG1heEtleTogcGxhbi5tYXhLZXksIHJvd0NvdW50OiBwbGFuLmtleXMubGVuZ3RoLCBzaXplLCBzb3VyY2VzOiBzb3VyY2VzTmFtZWQgfSk7XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXRzO1xufVxuIl19
|
|
352
|
+
/* _JS_SOURCE_HASH = "a47b64af2f351fc3f733f7f11152d7e852e7e7ca892b4960d928f6960e7a4740"; */
|