sliftutils 1.7.103 → 1.7.105
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/package.json +2 -2
- package/storage/StreamingLogs.ts +5 -3
- package/storage/dist/IArchives.ts.cache +2 -2
- package/storage/dist/StreamingLogs.ts.cache +399 -0
- package/storage/remoteStorage/dist/createArchives.ts.cache +37 -2
- package/storage/remoteStorage/dist/storageLogs.ts.cache +109 -0
- package/yarn.lock +4 -4
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
6
|
+
//exports.StreamingLogs = exports.decodeLogFile = exports.createLogSearcher = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const misc_1 = require("socket-function/src/misc");
|
|
10
|
+
const LZ4_1 = require("socket-function/src/lz4/LZ4");
|
|
11
|
+
// Generic append-only JSON-lines logging over a folder. Every process streams to its OWN file (named by pid + process start time + thread id, which together identify a process incarnation), rotating to a new file at a size limit and LZ4-compressing the finished one. Every process using the folder also MAINTAINS it on a randomized interval: dead processes' files are compressed for them, duplicate compressions are resolved, and the oldest files are deleted once the folder outgrows its byte budget. Instantiate one per folder and call log().
|
|
12
|
+
// Appends are coalesced for this long; a crash loses at most this much
|
|
13
|
+
const FLUSH_DELAY = 5000;
|
|
14
|
+
// A file reaching this size is rotated out and compressed
|
|
15
|
+
const MAX_FILE_BYTES = 100 * 1024 * 1024;
|
|
16
|
+
// The folder's total budget; once exceeded, the oldest files are deleted
|
|
17
|
+
const TOTAL_LIMIT_BYTES = 30 * 1024 * 1024 * 1024;
|
|
18
|
+
// Maintenance runs at a random point in this range, so the processes sharing the folder drift apart instead of stepping on each other every pass
|
|
19
|
+
const MAINTENANCE_MIN_INTERVAL = 30 * 60 * 1000;
|
|
20
|
+
const MAINTENANCE_MAX_INTERVAL = 60 * 60 * 1000;
|
|
21
|
+
// A pid is only the same PROCESS if its start time matches the file name's - within this much, because our own start time is derived from process.uptime and the OS's is read off /proc
|
|
22
|
+
const PROCESS_START_TOLERANCE = 60 * 1000;
|
|
23
|
+
// If flushing fails persistently (disk gone), pending entries are capped rather than growing forever
|
|
24
|
+
const MAX_PENDING_ENTRIES = 10000;
|
|
25
|
+
const UNCOMPRESSED_EXT = ".jsonl";
|
|
26
|
+
const COMPRESSED_EXT = ".jsonl.lz4";
|
|
27
|
+
function parseLogFileName(name) {
|
|
28
|
+
// The time fields accept a fractional part: hosts that shim Date.now to a true-time clock return fractional milliseconds, and files written before the writer rounded them are already on disk everywhere - they must stay listable (and maintainable, or they would never be compressed or cleaned).
|
|
29
|
+
let match = /^pid(\d+)_born(\d+)_thread([\w-]+?)_from(\d+(?:\.\d+)?)(?:_to(\d+(?:\.\d+)?)_count(\d+)_id([a-z0-9]+))?\.jsonl(\.lz4)?$/.exec(name);
|
|
30
|
+
if (!match)
|
|
31
|
+
return undefined;
|
|
32
|
+
let compressed = !!match[8];
|
|
33
|
+
// A compressed file without its compression fields (or the reverse) is not one of ours
|
|
34
|
+
if (compressed !== (match[5] !== undefined))
|
|
35
|
+
return undefined;
|
|
36
|
+
return {
|
|
37
|
+
pid: +match[1],
|
|
38
|
+
processStartTime: +match[2],
|
|
39
|
+
threadId: match[3],
|
|
40
|
+
startTime: +match[4],
|
|
41
|
+
endTime: match[5] !== undefined && +match[5] || undefined,
|
|
42
|
+
entryCount: match[6] !== undefined && +match[6] || undefined,
|
|
43
|
+
compressed,
|
|
44
|
+
originKey: `pid${match[1]}_born${match[2]}_thread${match[3]}_from${match[4]}`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Whether the pid is alive AND is the same process incarnation the file name described. On Linux /proc gives the real start time; elsewhere a live pid is conservatively treated as the same process (never compress under a running process). */
|
|
48
|
+
async function isProcessAlive(pid, processStartTime) {
|
|
49
|
+
try {
|
|
50
|
+
process.kill(pid, 0);
|
|
51
|
+
}
|
|
52
|
+
catch (_a) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
let stat = await fs_1.default.promises.stat(`/proc/${pid}`);
|
|
57
|
+
return Math.abs(stat.ctimeMs - processStartTime) < PROCESS_START_TOLERANCE;
|
|
58
|
+
}
|
|
59
|
+
catch (_b) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A searcher over one log file (as readFileCompressed returns it - always LZ4) that never decodes
|
|
65
|
+
* the whole thing: JSON escapes line breaks inside strings, so the only ACTUAL line breaks in the
|
|
66
|
+
* file are the separators between log statements - a plain substring search over the raw text,
|
|
67
|
+
* bounded out to the surrounding line breaks, finds exactly the matching statements, and only THOSE
|
|
68
|
+
* are decoded and returned as objects. Every search string must appear in a statement's raw JSON for
|
|
69
|
+
* it to match (so search for values as they are encoded - e.g. quoted).
|
|
70
|
+
*/
|
|
71
|
+
function createLogSearcher(data) {
|
|
72
|
+
let text = LZ4_1.LZ4.decompress(data).toString("utf8");
|
|
73
|
+
return searches => {
|
|
74
|
+
if (!searches.length) {
|
|
75
|
+
throw new Error(`Provide at least one search string (an empty search would just be decodeLogFile)`);
|
|
76
|
+
}
|
|
77
|
+
let entries = [];
|
|
78
|
+
let index = 0;
|
|
79
|
+
while (true) {
|
|
80
|
+
let found = text.indexOf(searches[0], index);
|
|
81
|
+
if (found === -1)
|
|
82
|
+
break;
|
|
83
|
+
let lineStart = text.lastIndexOf("\n", found) + 1;
|
|
84
|
+
let lineEnd = text.indexOf("\n", found);
|
|
85
|
+
if (lineEnd === -1) {
|
|
86
|
+
lineEnd = text.length;
|
|
87
|
+
}
|
|
88
|
+
// Past this line either way, so several matches inside one statement return it once
|
|
89
|
+
index = lineEnd + 1;
|
|
90
|
+
let line = text.slice(lineStart, lineEnd);
|
|
91
|
+
let matchesAll = true;
|
|
92
|
+
for (let other of searches.slice(1)) {
|
|
93
|
+
if (!line.includes(other)) {
|
|
94
|
+
matchesAll = false;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (!matchesAll)
|
|
99
|
+
continue;
|
|
100
|
+
try {
|
|
101
|
+
entries.push(JSON.parse(line));
|
|
102
|
+
}
|
|
103
|
+
catch (_a) {
|
|
104
|
+
// A torn final line (the writer crashed mid-append)
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return entries;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
exports.createLogSearcher = createLogSearcher;
|
|
112
|
+
/** Decodes a log file's bytes (as readFileCompressed returns them - always LZ4) back into the logged objects. A torn final line (the writer crashed mid-append) is skipped. */
|
|
113
|
+
function decodeLogFile(data) {
|
|
114
|
+
let text = LZ4_1.LZ4.decompress(data).toString("utf8");
|
|
115
|
+
let entries = [];
|
|
116
|
+
for (let line of text.split("\n")) {
|
|
117
|
+
if (!line)
|
|
118
|
+
continue;
|
|
119
|
+
try {
|
|
120
|
+
entries.push(JSON.parse(line));
|
|
121
|
+
}
|
|
122
|
+
catch (_a) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return entries;
|
|
127
|
+
}
|
|
128
|
+
exports.decodeLogFile = decodeLogFile;
|
|
129
|
+
class StreamingLogs {
|
|
130
|
+
constructor(config) {
|
|
131
|
+
this.config = config;
|
|
132
|
+
this.processStartTime = Math.round(Date.now() - process.uptime() * 1000);
|
|
133
|
+
this.threadId = (this.config.threadId || "none").replace(/[^\w-]/g, "_");
|
|
134
|
+
this.pending = [];
|
|
135
|
+
// Serializes everything that touches the current file, so appends, rotation, and in-memory compression of the live file never interleave
|
|
136
|
+
this.writeChain = Promise.resolve();
|
|
137
|
+
this.currentBytes = 0;
|
|
138
|
+
this.disposed = false;
|
|
139
|
+
this.scheduleMaintenance();
|
|
140
|
+
}
|
|
141
|
+
/** Queues one entry (anything JSON-serializable). Never throws - logging must not take down the caller. */
|
|
142
|
+
log(entry) {
|
|
143
|
+
try {
|
|
144
|
+
if (this.pending.length >= MAX_PENDING_ENTRIES) {
|
|
145
|
+
// The disk is broken (flushes are failing) - dropping the oldest beats growing forever
|
|
146
|
+
this.pending.shift();
|
|
147
|
+
}
|
|
148
|
+
this.pending.push(JSON.stringify(entry));
|
|
149
|
+
this.scheduleFlush();
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
console.warn(`Could not queue a log entry (${e.message})`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
scheduleFlush() {
|
|
156
|
+
var _a, _b;
|
|
157
|
+
if (this.flushTimer !== undefined || this.disposed)
|
|
158
|
+
return;
|
|
159
|
+
this.flushTimer = setTimeout(() => {
|
|
160
|
+
this.flushTimer = undefined;
|
|
161
|
+
void this.flush().catch((e) => { var _a; return console.warn(`Flushing logs in ${this.config.folder} failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); });
|
|
162
|
+
}, FLUSH_DELAY);
|
|
163
|
+
(_b = (_a = this.flushTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
164
|
+
}
|
|
165
|
+
async flush() {
|
|
166
|
+
let result = this.writeChain.then(() => this.writePending());
|
|
167
|
+
// The chain only serializes; a failure belongs to the caller that asked for this flush, not every one after it
|
|
168
|
+
this.writeChain = result.catch(() => { });
|
|
169
|
+
await result;
|
|
170
|
+
}
|
|
171
|
+
async writePending() {
|
|
172
|
+
if (!this.pending.length)
|
|
173
|
+
return;
|
|
174
|
+
let lines = this.pending;
|
|
175
|
+
this.pending = [];
|
|
176
|
+
let data = lines.join("\n") + "\n";
|
|
177
|
+
try {
|
|
178
|
+
if (!this.currentPath) {
|
|
179
|
+
await fs_1.default.promises.mkdir(this.config.folder, { recursive: true });
|
|
180
|
+
// Rounded, as a shimmed Date.now can return fractional milliseconds, and a "." in the name breaks name parsing for any reader without the fractional-tolerant regex
|
|
181
|
+
this.currentPath = path_1.default.join(this.config.folder, `pid${process.pid}_born${this.processStartTime}_thread${this.threadId}_from${Math.round(Date.now())}${UNCOMPRESSED_EXT}`);
|
|
182
|
+
this.currentBytes = 0;
|
|
183
|
+
}
|
|
184
|
+
await fs_1.default.promises.appendFile(this.currentPath, data);
|
|
185
|
+
this.currentBytes += Buffer.byteLength(data);
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
this.pending = lines.concat(this.pending);
|
|
189
|
+
this.scheduleFlush();
|
|
190
|
+
throw e;
|
|
191
|
+
}
|
|
192
|
+
if (this.currentBytes >= (this.config.maxFileBytes || MAX_FILE_BYTES)) {
|
|
193
|
+
let finished = this.currentPath;
|
|
194
|
+
this.currentPath = undefined;
|
|
195
|
+
this.currentBytes = 0;
|
|
196
|
+
void this.compressFile(finished).catch((e) => {
|
|
197
|
+
var _a;
|
|
198
|
+
// Left uncompressed: maintenance (ours after death, or any peer's) compresses it later
|
|
199
|
+
console.warn(`Compressing rotated log ${finished} failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Compresses one finished log file: LZ4 into a temp SUBFOLDER (never a temp name in the log
|
|
205
|
+
* folder itself - a crashed write must not leave a corrupt file where the maintenance scans are),
|
|
206
|
+
* renamed into place (same drive, so the rename is atomic), verified, and only THEN is the
|
|
207
|
+
* original deleted - at no point is the data in fewer than one complete file.
|
|
208
|
+
*/
|
|
209
|
+
async compressFile(filePath) {
|
|
210
|
+
let name = path_1.default.basename(filePath);
|
|
211
|
+
let parsed = parseLogFileName(name);
|
|
212
|
+
if (!parsed || parsed.compressed)
|
|
213
|
+
return;
|
|
214
|
+
let raw = await fs_1.default.promises.readFile(filePath);
|
|
215
|
+
let entryCount = 0;
|
|
216
|
+
for (let i = 0; i < raw.length; i++) {
|
|
217
|
+
if (raw[i] === 10)
|
|
218
|
+
entryCount++;
|
|
219
|
+
}
|
|
220
|
+
let compressed = LZ4_1.LZ4.compress(raw);
|
|
221
|
+
let id = Math.random().toString(36).slice(2, 10);
|
|
222
|
+
let finalName = `${parsed.originKey}_to${Math.round(Date.now())}_count${entryCount}_id${id}${COMPRESSED_EXT}`;
|
|
223
|
+
let tempDir = path_1.default.join(this.config.folder, ".tmp");
|
|
224
|
+
await fs_1.default.promises.mkdir(tempDir, { recursive: true });
|
|
225
|
+
let tempPath = path_1.default.join(tempDir, finalName);
|
|
226
|
+
let finalPath = path_1.default.join(this.config.folder, finalName);
|
|
227
|
+
await fs_1.default.promises.writeFile(tempPath, compressed);
|
|
228
|
+
await fs_1.default.promises.rename(tempPath, finalPath);
|
|
229
|
+
// Paranoia before deleting the only other copy
|
|
230
|
+
await fs_1.default.promises.stat(finalPath);
|
|
231
|
+
await fs_1.default.promises.unlink(filePath);
|
|
232
|
+
console.log(`Compressed log ${name} -> ${finalName} (${raw.length} -> ${compressed.length} bytes, ${entryCount} entries)`);
|
|
233
|
+
}
|
|
234
|
+
// ── listing / reading ──
|
|
235
|
+
async listFiles() {
|
|
236
|
+
let names;
|
|
237
|
+
try {
|
|
238
|
+
names = await fs_1.default.promises.readdir(this.config.folder);
|
|
239
|
+
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
if (e.code === "ENOENT")
|
|
242
|
+
return [];
|
|
243
|
+
throw e;
|
|
244
|
+
}
|
|
245
|
+
let files = [];
|
|
246
|
+
for (let name of names) {
|
|
247
|
+
let parsed = parseLogFileName(name);
|
|
248
|
+
if (!parsed)
|
|
249
|
+
continue;
|
|
250
|
+
let stat = await fs_1.default.promises.stat(path_1.default.join(this.config.folder, name)).catch(() => undefined);
|
|
251
|
+
if (!stat)
|
|
252
|
+
continue;
|
|
253
|
+
let active = !parsed.compressed && await isProcessAlive(parsed.pid, parsed.processStartTime);
|
|
254
|
+
files.push({
|
|
255
|
+
name,
|
|
256
|
+
size: stat.size,
|
|
257
|
+
pid: parsed.pid,
|
|
258
|
+
processStartTime: parsed.processStartTime,
|
|
259
|
+
threadId: parsed.threadId,
|
|
260
|
+
startTime: parsed.startTime,
|
|
261
|
+
endTime: parsed.endTime,
|
|
262
|
+
entryCount: parsed.entryCount,
|
|
263
|
+
compressed: parsed.compressed,
|
|
264
|
+
active,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
(0, misc_1.sort)(files, x => x.startTime);
|
|
268
|
+
return files;
|
|
269
|
+
}
|
|
270
|
+
/** One file's bytes, ALWAYS LZ4-compressed: compressed files are sent as-is, a still-streaming file is flushed and compressed in memory (smaller over the network; decodeLogFile handles both identically). */
|
|
271
|
+
async readFileCompressed(name) {
|
|
272
|
+
let parsed = parseLogFileName(name);
|
|
273
|
+
if (!parsed || name.includes("/") || name.includes("\\")) {
|
|
274
|
+
throw new Error(`Not a log file name: ${JSON.stringify(name.slice(0, 200))}`);
|
|
275
|
+
}
|
|
276
|
+
let filePath = path_1.default.join(this.config.folder, name);
|
|
277
|
+
if (parsed.compressed) {
|
|
278
|
+
return await fs_1.default.promises.readFile(filePath);
|
|
279
|
+
}
|
|
280
|
+
// Flush so our own live file includes everything logged up to now
|
|
281
|
+
await this.flush();
|
|
282
|
+
return LZ4_1.LZ4.compress(await fs_1.default.promises.readFile(filePath));
|
|
283
|
+
}
|
|
284
|
+
// ── maintenance ──
|
|
285
|
+
scheduleMaintenance() {
|
|
286
|
+
var _a, _b;
|
|
287
|
+
if (this.disposed)
|
|
288
|
+
return;
|
|
289
|
+
let wait = MAINTENANCE_MIN_INTERVAL + Math.random() * (MAINTENANCE_MAX_INTERVAL - MAINTENANCE_MIN_INTERVAL);
|
|
290
|
+
this.maintenanceTimer = setTimeout(() => {
|
|
291
|
+
void this.runMaintenance().catch((e) => { var _a; return console.warn(`Log maintenance of ${this.config.folder} failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); }).finally(() => this.scheduleMaintenance());
|
|
292
|
+
}, wait);
|
|
293
|
+
(_b = (_a = this.maintenanceTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Shared upkeep of the folder - every process using it runs this, so nothing depends on any one
|
|
297
|
+
* process surviving: dead processes' uncompressed files are compressed for them; duplicate
|
|
298
|
+
* compressions of one stream (two maintainers racing) are resolved by keeping the OLDEST copy;
|
|
299
|
+
* an uncompressed original whose compression already exists is deleted (its compressor died
|
|
300
|
+
* between rename and unlink); and the folder's total size is brought under its budget by
|
|
301
|
+
* deleting the oldest files.
|
|
302
|
+
*/
|
|
303
|
+
async runMaintenance() {
|
|
304
|
+
var _a;
|
|
305
|
+
let names;
|
|
306
|
+
try {
|
|
307
|
+
names = await fs_1.default.promises.readdir(this.config.folder);
|
|
308
|
+
}
|
|
309
|
+
catch (e) {
|
|
310
|
+
if (e.code === "ENOENT")
|
|
311
|
+
return;
|
|
312
|
+
throw e;
|
|
313
|
+
}
|
|
314
|
+
let parsedByName = new Map();
|
|
315
|
+
for (let name of names) {
|
|
316
|
+
let parsed = parseLogFileName(name);
|
|
317
|
+
if (parsed)
|
|
318
|
+
parsedByName.set(name, parsed);
|
|
319
|
+
}
|
|
320
|
+
let compressedOrigins = new Map();
|
|
321
|
+
for (let [name, parsed] of parsedByName) {
|
|
322
|
+
if (!parsed.compressed)
|
|
323
|
+
continue;
|
|
324
|
+
let list = compressedOrigins.get(parsed.originKey);
|
|
325
|
+
if (!list) {
|
|
326
|
+
list = [];
|
|
327
|
+
compressedOrigins.set(parsed.originKey, list);
|
|
328
|
+
}
|
|
329
|
+
list.push(name);
|
|
330
|
+
}
|
|
331
|
+
// Duplicate compressions: keep the oldest (first written), delete the rest
|
|
332
|
+
for (let [origin, list] of compressedOrigins) {
|
|
333
|
+
if (list.length < 2)
|
|
334
|
+
continue;
|
|
335
|
+
(0, misc_1.sort)(list, name => { var _a; return ((_a = parsedByName.get(name)) === null || _a === void 0 ? void 0 : _a.endTime) || 0; });
|
|
336
|
+
for (let duplicate of list.slice(1)) {
|
|
337
|
+
console.log(`Deleting duplicate compressed log ${duplicate} (another maintainer compressed ${origin} first, keeping ${list[0]})`);
|
|
338
|
+
await fs_1.default.promises.unlink(path_1.default.join(this.config.folder, duplicate)).catch(() => { });
|
|
339
|
+
parsedByName.delete(duplicate);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
for (let [name, parsed] of parsedByName) {
|
|
343
|
+
if (parsed.compressed)
|
|
344
|
+
continue;
|
|
345
|
+
let filePath = path_1.default.join(this.config.folder, name);
|
|
346
|
+
if (filePath === this.currentPath)
|
|
347
|
+
continue;
|
|
348
|
+
if (compressedOrigins.has(parsed.originKey)) {
|
|
349
|
+
// Already compressed by someone whose cleanup died between rename and unlink
|
|
350
|
+
console.log(`Deleting uncompressed log ${name}: its compressed version already exists`);
|
|
351
|
+
await fs_1.default.promises.unlink(filePath).catch(() => { });
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
// A live process owns its uncompressed file; only a DEAD process's files are compressed for it (our own pid always reads as alive, which correctly protects our current file - our rotated leftovers were excluded above only if current, so compress those too)
|
|
355
|
+
if (parsed.pid !== process.pid && await isProcessAlive(parsed.pid, parsed.processStartTime))
|
|
356
|
+
continue;
|
|
357
|
+
try {
|
|
358
|
+
await this.compressFile(filePath);
|
|
359
|
+
}
|
|
360
|
+
catch (e) {
|
|
361
|
+
console.warn(`Compressing dead process's log ${name} failed (the next maintenance pass retries): ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
await this.enforceTotalLimit();
|
|
365
|
+
}
|
|
366
|
+
async enforceTotalLimit() {
|
|
367
|
+
let limit = this.config.totalLimitBytes || TOTAL_LIMIT_BYTES;
|
|
368
|
+
let files = await this.listFiles();
|
|
369
|
+
let total = files.reduce((sum, x) => sum + x.size, 0);
|
|
370
|
+
if (total <= limit)
|
|
371
|
+
return;
|
|
372
|
+
// Oldest first, by the end of what they cover; live files last (they are the newest data by definition)
|
|
373
|
+
let deletable = files.filter(x => !x.active);
|
|
374
|
+
(0, misc_1.sort)(deletable, x => x.endTime || x.startTime);
|
|
375
|
+
let deleted = 0;
|
|
376
|
+
let deletedBytes = 0;
|
|
377
|
+
for (let file of deletable) {
|
|
378
|
+
if (total <= limit)
|
|
379
|
+
break;
|
|
380
|
+
await fs_1.default.promises.unlink(path_1.default.join(this.config.folder, file.name)).catch(() => { });
|
|
381
|
+
total -= file.size;
|
|
382
|
+
deleted++;
|
|
383
|
+
deletedBytes += file.size;
|
|
384
|
+
}
|
|
385
|
+
console.log(`Logs in ${this.config.folder} outgrew their ${limit} byte budget: deleted the ${deleted} oldest files (${deletedBytes} bytes), ${total} bytes remain`);
|
|
386
|
+
}
|
|
387
|
+
dispose() {
|
|
388
|
+
this.disposed = true;
|
|
389
|
+
if (this.flushTimer) {
|
|
390
|
+
clearTimeout(this.flushTimer);
|
|
391
|
+
}
|
|
392
|
+
if (this.maintenanceTimer) {
|
|
393
|
+
clearTimeout(this.maintenanceTimer);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
exports.StreamingLogs = StreamingLogs;
|
|
398
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3RyZWFtaW5nTG9ncy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIlN0cmVhbWluZ0xvZ3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLGdEQUF3QjtBQUN4QixtREFBZ0Q7QUFDaEQscURBQWtEO0FBRWxELGdpQkFBZ2lCO0FBRWhpQix1RUFBdUU7QUFDdkUsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDO0FBQ3pCLDBEQUEwRDtBQUMxRCxNQUFNLGNBQWMsR0FBRyxHQUFHLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUN6Qyx5RUFBeUU7QUFDekUsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDbEQsaUpBQWlKO0FBQ2pKLE1BQU0sd0JBQXdCLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDaEQsTUFBTSx3QkFBd0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUNoRCx3TEFBd0w7QUFDeEwsTUFBTSx1QkFBdUIsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQzFDLHFHQUFxRztBQUNyRyxNQUFNLG1CQUFtQixHQUFHLEtBQUssQ0FBQztBQUVsQyxNQUFNLGdCQUFnQixHQUFHLFFBQVEsQ0FBQztBQUNsQyxNQUFNLGNBQWMsR0FBRyxZQUFZLENBQUM7QUFpQ3BDLFNBQVMsZ0JBQWdCLENBQUMsSUFBWTtJQUNsQyxzU0FBc1M7SUFDdFMsSUFBSSxLQUFLLEdBQUcseUhBQXlILENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pKLElBQUksQ0FBQyxLQUFLO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDN0IsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1Qix1RkFBdUY7SUFDdkYsSUFBSSxVQUFVLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FB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QUUsQ0FBQztZQUNWLFlBQVksSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQzlCLENBQUM7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixLQUFLLDZCQUE2QixPQUFPLGtCQUFrQixZQUFZLFlBQVksS0FBSyxlQUFlLENBQUMsQ0FBQztJQUN4SyxDQUFDO0lBRU0sT0FBTztRQUNWLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1FBQ3JCLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2xCLFlBQVksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDbEMsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDeEIsWUFBWSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7SUFDTCxDQUFDO0NBQ0o7QUF2UUQsc0NBdVFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IHNvcnQgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9taXNjXCI7XG5pbXBvcnQgeyBMWjQgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9sejQvTFo0XCI7XG5cbi8vIEdlbmVyaWMgYXBwZW5kLW9ubHkgSlNPTi1saW5lcyBsb2dnaW5nIG92ZXIgYSBmb2xkZXIuIEV2ZXJ5IHByb2Nlc3Mgc3RyZWFtcyB0byBpdHMgT1dOIGZpbGUgKG5hbWVkIGJ5IHBpZCArIHByb2Nlc3Mgc3RhcnQgdGltZSArIHRocmVhZCBpZCwgd2hpY2ggdG9nZXRoZXIgaWRlbnRpZnkgYSBwcm9jZXNzIGluY2FybmF0aW9uKSwgcm90YXRpbmcgdG8gYSBuZXcgZmlsZSBhdCBhIHNpemUgbGltaXQgYW5kIExaNC1jb21wcmVzc2luZyB0aGUgZmluaXNoZWQgb25lLiBFdmVyeSBwcm9jZXNzIHVzaW5nIHRoZSBmb2xkZXIgYWxzbyBNQUlOVEFJTlMgaXQgb24gYSByYW5kb21pemVkIGludGVydmFsOiBkZWFkIHByb2Nlc3NlcycgZmlsZXMgYXJlIGNvbXByZXNzZWQgZm9yIHRoZW0sIGR1cGxpY2F0ZSBjb21wcmVzc2lvbnMgYXJlIHJlc29sdmVkLCBhbmQgdGhlIG9sZGVzdCBmaWxlcyBhcmUgZGVsZXRlZCBvbmNlIHRoZSBmb2xkZXIgb3V0Z3Jvd3MgaXRzIGJ5dGUgYnVkZ2V0LiBJbnN0YW50aWF0ZSBvbmUgcGVyIGZvbGRlciBhbmQgY2FsbCBsb2coKS5cblxuLy8gQXBwZW5kcyBhcmUgY29hbGVzY2VkIGZvciB0aGlzIGxvbmc7IGEgY3Jhc2ggbG9zZXMgYXQgbW9zdCB0aGlzIG11Y2hcbmNvbnN0IEZMVVNIX0RFTEFZID0gNTAwMDtcbi8vIEEgZmlsZSByZWFjaGluZyB0aGlzIHNpemUgaXMgcm90YXRlZCBvdXQgYW5kIGNvbXByZXNzZWRcbmNvbnN0IE1BWF9GSUxFX0JZVEVTID0gMTAwICogMTAyNCAqIDEwMjQ7XG4vLyBUaGUgZm9sZGVyJ3MgdG90YWwgYnVkZ2V0OyBvbmNlIGV4Y2VlZGVkLCB0aGUgb2xkZXN0IGZpbGVzIGFyZSBkZWxldGVkXG5jb25zdCBUT1RBTF9MSU1JVF9CWVRFUyA9IDMwICogMTAyNCAqIDEwMjQgKiAxMDI0O1xuLy8gTWFpbnRlbmFuY2UgcnVucyBhdCBhIHJhbmRvbSBwb2ludCBpbiB0aGlzIHJhbmdlLCBzbyB0aGUgcHJvY2Vzc2VzIHNoYXJpbmcgdGhlIGZvbGRlciBkcmlmdCBhcGFydCBpbnN0ZWFkIG9mIHN0ZXBwaW5nIG9uIGVhY2ggb3RoZXIgZXZlcnkgcGFzc1xuY29uc3QgTUFJTlRFTkFOQ0VfTUlOX0lOVEVSVkFMID0gMzAgKiA2MCAqIDEwMDA7XG5jb25zdCBNQUlOVEVOQU5DRV9NQVhfSU5URVJWQUwgPSA2MCAqIDYwICogMTAwMDtcbi8vIEEgcGlkIGlzIG9ubHkgdGhlIHNhbWUgUFJPQ0VTUyBpZiBpdHMgc3RhcnQgdGltZSBtYXRjaGVzIHRoZSBmaWxlIG5hbWUncyAtIHdpdGhpbiB0aGlzIG11Y2gsIGJlY2F1c2Ugb3VyIG93biBzdGFydCB0aW1lIGlzIGRlcml2ZWQgZnJvbSBwcm9jZXNzLnVwdGltZSBhbmQgdGhlIE9TJ3MgaXMgcmVhZCBvZmYgL3Byb2NcbmNvbnN0IFBST0NFU1NfU1RBUlRfVE9MRVJBTkNFID0gNjAgKiAxMDAwO1xuLy8gSWYgZmx1c2hpbmcgZmFpbHMgcGVyc2lzdGVudGx5IChkaXNrIGdvbmUpLCBwZW5kaW5nIGVudHJpZXMgYXJlIGNhcHBlZCByYXRoZXIgdGhhbiBncm93aW5nIGZvcmV2ZXJcbmNvbnN0IE1BWF9QRU5ESU5HX0VOVFJJRVMgPSAxMDAwMDtcblxuY29uc3QgVU5DT01QUkVTU0VEX0VYVCA9IFwiLmpzb25sXCI7XG5jb25zdCBDT01QUkVTU0VEX0VYVCA9IFwiLmpzb25sLmx6NFwiO1xuXG4vKiogRXZlcnl0aGluZyBhIGxvZyBmaWxlJ3MgTkFNRSBzYXlzIGFib3V0IGl0IChwbHVzIGl0cyBvbi1kaXNrIHNpemUpLiBUaW1lcyBib3VuZCB0aGUgZW50cmllcyByb3VnaGx5OiBmcm9tIGlzIHdoZW4gaXRzIHByb2Nlc3Mgc3RhcnRlZCB3cml0aW5nIGl0LCB0byBpcyB3aGVuIGl0IHdhcyBjb21wcmVzc2VkLiAqL1xuZXhwb3J0IHR5cGUgTG9nRmlsZUluZm8gPSB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIC8qKiBCeXRlcyBvbiBkaXNrIChjb21wcmVzc2VkIGJ5dGVzIGZvciBjb21wcmVzc2VkIGZpbGVzKSAqL1xuICAgIHNpemU6IG51bWJlcjtcbiAgICBwaWQ6IG51bWJlcjtcbiAgICBwcm9jZXNzU3RhcnRUaW1lOiBudW1iZXI7XG4gICAgdGhyZWFkSWQ6IHN0cmluZztcbiAgICAvKiogV2hlbiB0aGUgcHJvY2VzcyBzdGFydGVkIHdyaXRpbmcgdGhpcyBmaWxlICovXG4gICAgc3RhcnRUaW1lOiBudW1iZXI7XG4gICAgLyoqIFdoZW4gdGhlIGZpbGUgd2FzIGNvbXByZXNzZWQgLSBhYnNlbnQgd2hpbGUgaXQgaXMgc3RpbGwgYmVpbmcgc3RyZWFtZWQgdG8gKi9cbiAgICBlbmRUaW1lPzogbnVtYmVyO1xuICAgIC8qKiBIb3cgbWFueSBlbnRyaWVzIGl0IGhvbGRzIC0gb25seSBjb3VudGVkIGF0IGNvbXByZXNzaW9uLCBzbyBhYnNlbnQgb24gbGl2ZSBmaWxlcyAqL1xuICAgIGVudHJ5Q291bnQ/OiBudW1iZXI7XG4gICAgY29tcHJlc3NlZDogYm9vbGVhbjtcbiAgICAvKiogV2hldGhlciB0aGUgd3JpdGluZyBwcm9jZXNzIGlzIHN0aWxsIGFsaXZlIChhbHdheXMgZmFsc2UgZm9yIGNvbXByZXNzZWQgZmlsZXMpICovXG4gICAgYWN0aXZlOiBib29sZWFuO1xufTtcblxudHlwZSBQYXJzZWROYW1lID0ge1xuICAgIHBpZDogbnVtYmVyO1xuICAgIHByb2Nlc3NTdGFydFRpbWU6IG51bWJlcjtcbiAgICB0aHJlYWRJZDogc3RyaW5nO1xuICAgIHN0YXJ0VGltZTogbnVtYmVyO1xuICAgIGVuZFRpbWU/OiBudW1iZXI7XG4gICAgZW50cnlDb3VudD86IG51bWJlcjtcbiAgICBjb21wcmVzc2VkOiBib29sZWFuO1xuICAgIC8qKiBUaGUgcGFydCBpZGVudGlmeWluZyB0aGUgT1JJR0lOQUwgc3RyZWFtIChwaWQrYm9ybit0aHJlYWQrZnJvbSkgLSB3aGF0IGR1cGxpY2F0ZSBjb21wcmVzc2lvbnMgc2hhcmUgKi9cbiAgICBvcmlnaW5LZXk6IHN0cmluZztcbn07XG5cbmZ1bmN0aW9uIHBhcnNlTG9nRmlsZU5hbWUobmFtZTogc3RyaW5nKTogUGFyc2VkTmFtZSB8IHVuZGVmaW5lZCB7XG4gICAgLy8gVGhlIHRpbWUgZmllbGRzIGFjY2VwdCBhIGZyYWN0aW9uYWwgcGFydDogaG9zdHMgdGhhdCBzaGltIERhdGUubm93IHRvIGEgdHJ1ZS10aW1lIGNsb2NrIHJldHVybiBmcmFjdGlvbmFsIG1pbGxpc2Vjb25kcywgYW5kIGZpbGVzIHdyaXR0ZW4gYmVmb3JlIHRoZSB3cml0ZXIgcm91bmRlZCB0aGVtIGFyZSBhbHJlYWR5IG9uIGRpc2sgZXZlcnl3aGVyZSAtIHRoZXkgbXVzdCBzdGF5IGxpc3RhYmxlIChhbmQgbWFpbnRhaW5hYmxlLCBvciB0aGV5IHdvdWxkIG5ldmVyIGJlIGNvbXByZXNzZWQgb3IgY2xlYW5lZCkuXG4gICAgbGV0IG1hdGNoID0gL15waWQoXFxkKylfYm9ybihcXGQrKV90aHJlYWQoW1xcdy1dKz8pX2Zyb20oXFxkKyg/OlxcLlxcZCspPykoPzpfdG8oXFxkKyg/OlxcLlxcZCspPylfY291bnQoXFxkKylfaWQoW2EtejAtOV0rKSk/XFwuanNvbmwoXFwubHo0KT8kLy5leGVjKG5hbWUpO1xuICAgIGlmICghbWF0Y2gpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgbGV0IGNvbXByZXNzZWQgPSAhIW1hdGNoWzhdO1xuICAgIC8vIEEgY29tcHJlc3NlZCBmaWxlIHdpdGhvdXQgaXRzIGNvbXByZXNzaW9uIGZpZWxkcyAob3IgdGhlIHJldmVyc2UpIGlzIG5vdCBvbmUgb2Ygb3Vyc1xuICAgIGlmIChjb21wcmVzc2VkICE9PSAobWF0Y2hbNV0gIT09IHVuZGVmaW5lZCkpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgcGlkOiArbWF0Y2hbMV0sXG4gICAgICAgIHByb2Nlc3NTdGFydFRpbWU6ICttYXRjaFsyXSxcbiAgICAgICAgdGhyZWFkSWQ6IG1hdGNoWzNdLFxuICAgICAgICBzdGFydFRpbWU6ICttYXRjaFs0XSxcbiAgICAgICAgZW5kVGltZTogbWF0Y2hbNV0gIT09IHVuZGVmaW5lZCAmJiArbWF0Y2hbNV0gfHwgdW5kZWZpbmVkLFxuICAgICAgICBlbnRyeUNvdW50OiBtYXRjaFs2XSAhPT0gdW5kZWZpbmVkICYmICttYXRjaFs2XSB8fCB1bmRlZmluZWQsXG4gICAgICAgIGNvbXByZXNzZWQsXG4gICAgICAgIG9yaWdpbktleTogYHBpZCR7bWF0Y2hbMV19X2Jvcm4ke21hdGNoWzJdfV90aHJlYWQke21hdGNoWzNdfV9mcm9tJHttYXRjaFs0XX1gLFxuICAgIH07XG59XG5cbi8qKiBXaGV0aGVyIHRoZSBwaWQgaXMgYWxpdmUgQU5EIGlzIHRoZSBzYW1lIHByb2Nlc3MgaW5jYXJuYXRpb24gdGhlIGZpbGUgbmFtZSBkZXNjcmliZWQuIE9uIExpbnV4IC9wcm9jIGdpdmVzIHRoZSByZWFsIHN0YXJ0IHRpbWU7IGVsc2V3aGVyZSBhIGxpdmUgcGlkIGlzIGNvbnNlcnZhdGl2ZWx5IHRyZWF0ZWQgYXMgdGhlIHNhbWUgcHJvY2VzcyAobmV2ZXIgY29tcHJlc3MgdW5kZXIgYSBydW5uaW5nIHByb2Nlc3MpLiAqL1xuYXN5bmMgZnVuY3Rpb24gaXNQcm9jZXNzQWxpdmUocGlkOiBudW1iZXIsIHByb2Nlc3NTdGFydFRpbWU6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRyeSB7XG4gICAgICAgIHByb2Nlc3Mua2lsbChwaWQsIDApO1xuICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIGxldCBzdGF0ID0gYXdhaXQgZnMucHJvbWlzZXMuc3RhdChgL3Byb2MvJHtwaWR9YCk7XG4gICAgICAgIHJldHVybiBNYXRoLmFicyhzdGF0LmN0aW1lTXMgLSBwcm9jZXNzU3RhcnRUaW1lKSA8IFBST0NFU1NfU1RBUlRfVE9MRVJBTkNFO1xuICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG59XG5cbi8qKlxuICogQSBzZWFyY2hlciBvdmVyIG9uZSBsb2cgZmlsZSAoYXMgcmVhZEZpbGVDb21wcmVzc2VkIHJldHVybnMgaXQgLSBhbHdheXMgTFo0KSB0aGF0IG5ldmVyIGRlY29kZXNcbiAqIHRoZSB3aG9sZSB0aGluZzogSlNPTiBlc2NhcGVzIGxpbmUgYnJlYWtzIGluc2lkZSBzdHJpbmdzLCBzbyB0aGUgb25seSBBQ1RVQUwgbGluZSBicmVha3MgaW4gdGhlXG4gKiBmaWxlIGFyZSB0aGUgc2VwYXJhdG9ycyBiZXR3ZWVuIGxvZyBzdGF0ZW1lbnRzIC0gYSBwbGFpbiBzdWJzdHJpbmcgc2VhcmNoIG92ZXIgdGhlIHJhdyB0ZXh0LFxuICogYm91bmRlZCBvdXQgdG8gdGhlIHN1cnJvdW5kaW5nIGxpbmUgYnJlYWtzLCBmaW5kcyBleGFjdGx5IHRoZSBtYXRjaGluZyBzdGF0ZW1lbnRzLCBhbmQgb25seSBUSE9TRVxuICogYXJlIGRlY29kZWQgYW5kIHJldHVybmVkIGFzIG9iamVjdHMuIEV2ZXJ5IHNlYXJjaCBzdHJpbmcgbXVzdCBhcHBlYXIgaW4gYSBzdGF0ZW1lbnQncyByYXcgSlNPTiBmb3JcbiAqIGl0IHRvIG1hdGNoIChzbyBzZWFyY2ggZm9yIHZhbHVlcyBhcyB0aGV5IGFyZSBlbmNvZGVkIC0gZS5nLiBxdW90ZWQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTG9nU2VhcmNoZXIoZGF0YTogQnVmZmVyKTogKHNlYXJjaGVzOiBzdHJpbmdbXSkgPT4gdW5rbm93bltdIHtcbiAgICBsZXQgdGV4dCA9IExaNC5kZWNvbXByZXNzKGRhdGEpLnRvU3RyaW5nKFwidXRmOFwiKTtcbiAgICByZXR1cm4gc2VhcmNoZXMgPT4ge1xuICAgICAgICBpZiAoIXNlYXJjaGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBQcm92aWRlIGF0IGxlYXN0IG9uZSBzZWFyY2ggc3RyaW5nIChhbiBlbXB0eSBzZWFyY2ggd291bGQganVzdCBiZSBkZWNvZGVMb2dGaWxlKWApO1xuICAgICAgICB9XG4gICAgICAgIGxldCBlbnRyaWVzOiB1bmtub3duW10gPSBbXTtcbiAgICAgICAgbGV0IGluZGV4ID0gMDtcbiAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICAgIGxldCBmb3VuZCA9IHRleHQuaW5kZXhPZihzZWFyY2hlc1swXSwgaW5kZXgpO1xuICAgICAgICAgICAgaWYgKGZvdW5kID09PSAtMSkgYnJlYWs7XG4gICAgICAgICAgICBsZXQgbGluZVN0YXJ0ID0gdGV4dC5sYXN0SW5kZXhPZihcIlxcblwiLCBmb3VuZCkgKyAxO1xuICAgICAgICAgICAgbGV0IGxpbmVFbmQgPSB0ZXh0LmluZGV4T2YoXCJcXG5cIiwgZm91bmQpO1xuICAgICAgICAgICAgaWYgKGxpbmVFbmQgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgbGluZUVuZCA9IHRleHQubGVuZ3RoO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gUGFzdCB0aGlzIGxpbmUgZWl0aGVyIHdheSwgc28gc2V2ZXJhbCBtYXRjaGVzIGluc2lkZSBvbmUgc3RhdGVtZW50IHJldHVybiBpdCBvbmNlXG4gICAgICAgICAgICBpbmRleCA9IGxpbmVFbmQgKyAxO1xuICAgICAgICAgICAgbGV0IGxpbmUgPSB0ZXh0LnNsaWNlKGxpbmVTdGFydCwgbGluZUVuZCk7XG4gICAgICAgICAgICBsZXQgbWF0Y2hlc0FsbCA9IHRydWU7XG4gICAgICAgICAgICBmb3IgKGxldCBvdGhlciBvZiBzZWFyY2hlcy5zbGljZSgxKSkge1xuICAgICAgICAgICAgICAgIGlmICghbGluZS5pbmNsdWRlcyhvdGhlcikpIHtcbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hlc0FsbCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIW1hdGNoZXNBbGwpIGNvbnRpbnVlO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBlbnRyaWVzLnB1c2goSlNPTi5wYXJzZShsaW5lKSk7XG4gICAgICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAgICAgICAvLyBBIHRvcm4gZmluYWwgbGluZSAodGhlIHdyaXRlciBjcmFzaGVkIG1pZC1hcHBlbmQpXG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVudHJpZXM7XG4gICAgfTtcbn1cblxuLyoqIERlY29kZXMgYSBsb2cgZmlsZSdzIGJ5dGVzIChhcyByZWFkRmlsZUNvbXByZXNzZWQgcmV0dXJucyB0aGVtIC0gYWx3YXlzIExaNCkgYmFjayBpbnRvIHRoZSBsb2dnZWQgb2JqZWN0cy4gQSB0b3JuIGZpbmFsIGxpbmUgKHRoZSB3cml0ZXIgY3Jhc2hlZCBtaWQtYXBwZW5kKSBpcyBza2lwcGVkLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZUxvZ0ZpbGUoZGF0YTogQnVmZmVyKTogdW5rbm93bltdIHtcbiAgICBsZXQgdGV4dCA9IExaNC5kZWNvbXByZXNzKGRhdGEpLnRvU3RyaW5nKFwidXRmOFwiKTtcbiAgICBsZXQgZW50cmllczogdW5rbm93bltdID0gW107XG4gICAgZm9yIChsZXQgbGluZSBvZiB0ZXh0LnNwbGl0KFwiXFxuXCIpKSB7XG4gICAgICAgIGlmICghbGluZSkgY29udGludWU7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBlbnRyaWVzLnB1c2goSlNPTi5wYXJzZShsaW5lKSk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGVudHJpZXM7XG59XG5cbmV4cG9ydCBjbGFzcyBTdHJlYW1pbmdMb2dzIHtcbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIGNvbmZpZzoge1xuICAgICAgICBmb2xkZXI6IHN0cmluZztcbiAgICAgICAgLyoqIEluY2x1ZGVkIGluIGV2ZXJ5IGZpbGUgbmFtZSAtIHNlZSBtaXNjL2h0dHBzL2NlcnRzLnRzIGdldE93blRocmVhZElkLiBQcm9jZXNzZXMgd2l0aG91dCBvbmUgd3JpdGUgXCJub25lXCIuICovXG4gICAgICAgIHRocmVhZElkPzogc3RyaW5nO1xuICAgICAgICBtYXhGaWxlQnl0ZXM/OiBudW1iZXI7XG4gICAgICAgIHRvdGFsTGltaXRCeXRlcz86IG51bWJlcjtcbiAgICB9KSB7XG4gICAgICAgIHRoaXMuc2NoZWR1bGVNYWludGVuYW5jZSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgcHJvY2Vzc1N0YXJ0VGltZSA9IE1hdGgucm91bmQoRGF0ZS5ub3coKSAtIHByb2Nlc3MudXB0aW1lKCkgKiAxMDAwKTtcbiAgICBwcml2YXRlIHRocmVhZElkID0gKHRoaXMuY29uZmlnLnRocmVhZElkIHx8IFwibm9uZVwiKS5yZXBsYWNlKC9bXlxcdy1dL2csIFwiX1wiKTtcbiAgICBwcml2YXRlIHBlbmRpbmc6IHN0cmluZ1tdID0gW107XG4gICAgcHJpdmF0ZSBmbHVzaFRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IHVuZGVmaW5lZDtcbiAgICBwcml2YXRlIG1haW50ZW5hbmNlVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuICAgIC8vIFNlcmlhbGl6ZXMgZXZlcnl0aGluZyB0aGF0IHRvdWNoZXMgdGhlIGN1cnJlbnQgZmlsZSwgc28gYXBwZW5kcywgcm90YXRpb24sIGFuZCBpbi1tZW1vcnkgY29tcHJlc3Npb24gb2YgdGhlIGxpdmUgZmlsZSBuZXZlciBpbnRlcmxlYXZlXG4gICAgcHJpdmF0ZSB3cml0ZUNoYWluOiBQcm9taXNlPHZvaWQ+ID0gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgcHJpdmF0ZSBjdXJyZW50UGF0aDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIHByaXZhdGUgY3VycmVudEJ5dGVzID0gMDtcbiAgICBwcml2YXRlIGRpc3Bvc2VkID0gZmFsc2U7XG5cbiAgICAvKiogUXVldWVzIG9uZSBlbnRyeSAoYW55dGhpbmcgSlNPTi1zZXJpYWxpemFibGUpLiBOZXZlciB0aHJvd3MgLSBsb2dnaW5nIG11c3Qgbm90IHRha2UgZG93biB0aGUgY2FsbGVyLiAqL1xuICAgIHB1YmxpYyBsb2coZW50cnk6IHVua25vd24pOiB2b2lkIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICh0aGlzLnBlbmRpbmcubGVuZ3RoID49IE1BWF9QRU5ESU5HX0VOVFJJRVMpIHtcbiAgICAgICAgICAgICAgICAvLyBUaGUgZGlzayBpcyBicm9rZW4gKGZsdXNoZXMgYXJlIGZhaWxpbmcpIC0gZHJvcHBpbmcgdGhlIG9sZGVzdCBiZWF0cyBncm93aW5nIGZvcmV2ZXJcbiAgICAgICAgICAgICAgICB0aGlzLnBlbmRpbmcuc2hpZnQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMucGVuZGluZy5wdXNoKEpTT04uc3RyaW5naWZ5KGVudHJ5KSk7XG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlRmx1c2goKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGBDb3VsZCBub3QgcXVldWUgYSBsb2cgZW50cnkgKCR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9KWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzY2hlZHVsZUZsdXNoKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5mbHVzaFRpbWVyICE9PSB1bmRlZmluZWQgfHwgdGhpcy5kaXNwb3NlZCkgcmV0dXJuO1xuICAgICAgICB0aGlzLmZsdXNoVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZmx1c2hUaW1lciA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHZvaWQgdGhpcy5mbHVzaCgpLmNhdGNoKChlOiBFcnJvcikgPT4gY29uc29sZS53YXJuKGBGbHVzaGluZyBsb2dzIGluICR7dGhpcy5jb25maWcuZm9sZGVyfSBmYWlsZWQ6ICR7ZS5zdGFjayA/PyBlfWApKTtcbiAgICAgICAgfSwgRkxVU0hfREVMQVkpO1xuICAgICAgICAodGhpcy5mbHVzaFRpbWVyIGFzIHsgdW5yZWY/OiAoKSA9PiB2b2lkIH0pLnVucmVmPy4oKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZmx1c2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxldCByZXN1bHQgPSB0aGlzLndyaXRlQ2hhaW4udGhlbigoKSA9PiB0aGlzLndyaXRlUGVuZGluZygpKTtcbiAgICAgICAgLy8gVGhlIGNoYWluIG9ubHkgc2VyaWFsaXplczsgYSBmYWlsdXJlIGJlbG9uZ3MgdG8gdGhlIGNhbGxlciB0aGF0IGFza2VkIGZvciB0aGlzIGZsdXNoLCBub3QgZXZlcnkgb25lIGFmdGVyIGl0XG4gICAgICAgIHRoaXMud3JpdGVDaGFpbiA9IHJlc3VsdC5jYXRjaCgoKSA9PiB7IH0pO1xuICAgICAgICBhd2FpdCByZXN1bHQ7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyB3cml0ZVBlbmRpbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghdGhpcy5wZW5kaW5nLmxlbmd0aCkgcmV0dXJuO1xuICAgICAgICBsZXQgbGluZXMgPSB0aGlzLnBlbmRpbmc7XG4gICAgICAgIHRoaXMucGVuZGluZyA9IFtdO1xuICAgICAgICBsZXQgZGF0YSA9IGxpbmVzLmpvaW4oXCJcXG5cIikgKyBcIlxcblwiO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmN1cnJlbnRQYXRoKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMubWtkaXIodGhpcy5jb25maWcuZm9sZGVyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgICAvLyBSb3VuZGVkLCBhcyBhIHNoaW1tZWQgRGF0ZS5ub3cgY2FuIHJldHVybiBmcmFjdGlvbmFsIG1pbGxpc2Vjb25kcywgYW5kIGEgXCIuXCIgaW4gdGhlIG5hbWUgYnJlYWtzIG5hbWUgcGFyc2luZyBmb3IgYW55IHJlYWRlciB3aXRob3V0IHRoZSBmcmFjdGlvbmFsLXRvbGVyYW50IHJlZ2V4XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aCA9IHBhdGguam9pbih0aGlzLmNvbmZpZy5mb2xkZXIsIGBwaWQke3Byb2Nlc3MucGlkfV9ib3JuJHt0aGlzLnByb2Nlc3NTdGFydFRpbWV9X3RocmVhZCR7dGhpcy50aHJlYWRJZH1fZnJvbSR7TWF0aC5yb3VuZChEYXRlLm5vdygpKX0ke1VOQ09NUFJFU1NFRF9FWFR9YCk7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50Qnl0ZXMgPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMuYXBwZW5kRmlsZSh0aGlzLmN1cnJlbnRQYXRoLCBkYXRhKTtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEJ5dGVzICs9IEJ1ZmZlci5ieXRlTGVuZ3RoKGRhdGEpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICB0aGlzLnBlbmRpbmcgPSBsaW5lcy5jb25jYXQodGhpcy5wZW5kaW5nKTtcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGVGbHVzaCgpO1xuICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5jdXJyZW50Qnl0ZXMgPj0gKHRoaXMuY29uZmlnLm1heEZpbGVCeXRlcyB8fCBNQVhfRklMRV9CWVRFUykpIHtcbiAgICAgICAgICAgIGxldCBmaW5pc2hlZCA9IHRoaXMuY3VycmVudFBhdGg7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQYXRoID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50Qnl0ZXMgPSAwO1xuICAgICAgICAgICAgdm9pZCB0aGlzLmNvbXByZXNzRmlsZShmaW5pc2hlZCkuY2F0Y2goKGU6IEVycm9yKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gTGVmdCB1bmNvbXByZXNzZWQ6IG1haW50ZW5hbmNlIChvdXJzIGFmdGVyIGRlYXRoLCBvciBhbnkgcGVlcidzKSBjb21wcmVzc2VzIGl0IGxhdGVyXG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKGBDb21wcmVzc2luZyByb3RhdGVkIGxvZyAke2ZpbmlzaGVkfSBmYWlsZWQ6ICR7ZS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb21wcmVzc2VzIG9uZSBmaW5pc2hlZCBsb2cgZmlsZTogTFo0IGludG8gYSB0ZW1wIFNVQkZPTERFUiAobmV2ZXIgYSB0ZW1wIG5hbWUgaW4gdGhlIGxvZ1xuICAgICAqIGZvbGRlciBpdHNlbGYgLSBhIGNyYXNoZWQgd3JpdGUgbXVzdCBub3QgbGVhdmUgYSBjb3JydXB0IGZpbGUgd2hlcmUgdGhlIG1haW50ZW5hbmNlIHNjYW5zIGFyZSksXG4gICAgICogcmVuYW1lZCBpbnRvIHBsYWNlIChzYW1lIGRyaXZlLCBzbyB0aGUgcmVuYW1lIGlzIGF0b21pYyksIHZlcmlmaWVkLCBhbmQgb25seSBUSEVOIGlzIHRoZVxuICAgICAqIG9yaWdpbmFsIGRlbGV0ZWQgLSBhdCBubyBwb2ludCBpcyB0aGUgZGF0YSBpbiBmZXdlciB0aGFuIG9uZSBjb21wbGV0ZSBmaWxlLlxuICAgICAqL1xuICAgIHByaXZhdGUgYXN5bmMgY29tcHJlc3NGaWxlKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IG5hbWUgPSBwYXRoLmJhc2VuYW1lKGZpbGVQYXRoKTtcbiAgICAgICAgbGV0IHBhcnNlZCA9IHBhcnNlTG9nRmlsZU5hbWUobmFtZSk7XG4gICAgICAgIGlmICghcGFyc2VkIHx8IHBhcnNlZC5jb21wcmVzc2VkKSByZXR1cm47XG4gICAgICAgIGxldCByYXcgPSBhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZShmaWxlUGF0aCk7XG4gICAgICAgIGxldCBlbnRyeUNvdW50ID0gMDtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByYXcubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChyYXdbaV0gPT09IDEwKSBlbnRyeUNvdW50Kys7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGNvbXByZXNzZWQgPSBMWjQuY29tcHJlc3MocmF3KTtcbiAgICAgICAgbGV0IGlkID0gTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMiwgMTApO1xuICAgICAgICBsZXQgZmluYWxOYW1lID0gYCR7cGFyc2VkLm9yaWdpbktleX1fdG8ke01hdGgucm91bmQoRGF0ZS5ub3coKSl9X2NvdW50JHtlbnRyeUNvdW50fV9pZCR7aWR9JHtDT01QUkVTU0VEX0VYVH1gO1xuICAgICAgICBsZXQgdGVtcERpciA9IHBhdGguam9pbih0aGlzLmNvbmZpZy5mb2xkZXIsIFwiLnRtcFwiKTtcbiAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMubWtkaXIodGVtcERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIGxldCB0ZW1wUGF0aCA9IHBhdGguam9pbih0ZW1wRGlyLCBmaW5hbE5hbWUpO1xuICAgICAgICBsZXQgZmluYWxQYXRoID0gcGF0aC5qb2luKHRoaXMuY29uZmlnLmZvbGRlciwgZmluYWxOYW1lKTtcbiAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMud3JpdGVGaWxlKHRlbXBQYXRoLCBjb21wcmVzc2VkKTtcbiAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMucmVuYW1lKHRlbXBQYXRoLCBmaW5hbFBhdGgpO1xuICAgICAgICAvLyBQYXJhbm9pYSBiZWZvcmUgZGVsZXRpbmcgdGhlIG9ubHkgb3RoZXIgY29weVxuICAgICAgICBhd2FpdCBmcy5wcm9taXNlcy5zdGF0KGZpbmFsUGF0aCk7XG4gICAgICAgIGF3YWl0IGZzLnByb21pc2VzLnVubGluayhmaWxlUGF0aCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBDb21wcmVzc2VkIGxvZyAke25hbWV9IC0+ICR7ZmluYWxOYW1lfSAoJHtyYXcubGVuZ3RofSAtPiAke2NvbXByZXNzZWQubGVuZ3RofSBieXRlcywgJHtlbnRyeUNvdW50fSBlbnRyaWVzKWApO1xuICAgIH1cblxuICAgIC8vIOKUgOKUgCBsaXN0aW5nIC8gcmVhZGluZyDilIDilIBcblxuICAgIHB1YmxpYyBhc3luYyBsaXN0RmlsZXMoKTogUHJvbWlzZTxMb2dGaWxlSW5mb1tdPiB7XG4gICAgICAgIGxldCBuYW1lczogc3RyaW5nW107XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBuYW1lcyA9IGF3YWl0IGZzLnByb21pc2VzLnJlYWRkaXIodGhpcy5jb25maWcuZm9sZGVyKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKChlIGFzIHsgY29kZT86IHN0cmluZyB9KS5jb2RlID09PSBcIkVOT0VOVFwiKSByZXR1cm4gW107XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICAgIGxldCBmaWxlczogTG9nRmlsZUluZm9bXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBuYW1lIG9mIG5hbWVzKSB7XG4gICAgICAgICAgICBsZXQgcGFyc2VkID0gcGFyc2VMb2dGaWxlTmFtZShuYW1lKTtcbiAgICAgICAgICAgIGlmICghcGFyc2VkKSBjb250aW51ZTtcbiAgICAgICAgICAgIGxldCBzdGF0ID0gYXdhaXQgZnMucHJvbWlzZXMuc3RhdChwYXRoLmpvaW4odGhpcy5jb25maWcuZm9sZGVyLCBuYW1lKSkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICAgICAgICAgIGlmICghc3RhdCkgY29udGludWU7XG4gICAgICAgICAgICBsZXQgYWN0aXZlID0gIXBhcnNlZC5jb21wcmVzc2VkICYmIGF3YWl0IGlzUHJvY2Vzc0FsaXZlKHBhcnNlZC5waWQsIHBhcnNlZC5wcm9jZXNzU3RhcnRUaW1lKTtcbiAgICAgICAgICAgIGZpbGVzLnB1c2goe1xuICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgc2l6ZTogc3RhdC5zaXplLFxuICAgICAgICAgICAgICAgIHBpZDogcGFyc2VkLnBpZCxcbiAgICAgICAgICAgICAgICBwcm9jZXNzU3RhcnRUaW1lOiBwYXJzZWQucHJvY2Vzc1N0YXJ0VGltZSxcbiAgICAgICAgICAgICAgICB0aHJlYWRJZDogcGFyc2VkLnRocmVhZElkLFxuICAgICAgICAgICAgICAgIHN0YXJ0VGltZTogcGFyc2VkLnN0YXJ0VGltZSxcbiAgICAgICAgICAgICAgICBlbmRUaW1lOiBwYXJzZWQuZW5kVGltZSxcbiAgICAgICAgICAgICAgICBlbnRyeUNvdW50OiBwYXJzZWQuZW50cnlDb3VudCxcbiAgICAgICAgICAgICAgICBjb21wcmVzc2VkOiBwYXJzZWQuY29tcHJlc3NlZCxcbiAgICAgICAgICAgICAgICBhY3RpdmUsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBzb3J0KGZpbGVzLCB4ID0+IHguc3RhcnRUaW1lKTtcbiAgICAgICAgcmV0dXJuIGZpbGVzO1xuICAgIH1cblxuICAgIC8qKiBPbmUgZmlsZSdzIGJ5dGVzLCBBTFdBWVMgTFo0LWNvbXByZXNzZWQ6IGNvbXByZXNzZWQgZmlsZXMgYXJlIHNlbnQgYXMtaXMsIGEgc3RpbGwtc3RyZWFtaW5nIGZpbGUgaXMgZmx1c2hlZCBhbmQgY29tcHJlc3NlZCBpbiBtZW1vcnkgKHNtYWxsZXIgb3ZlciB0aGUgbmV0d29yazsgZGVjb2RlTG9nRmlsZSBoYW5kbGVzIGJvdGggaWRlbnRpY2FsbHkpLiAqL1xuICAgIHB1YmxpYyBhc3luYyByZWFkRmlsZUNvbXByZXNzZWQobmFtZTogc3RyaW5nKTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgICAgICAgbGV0IHBhcnNlZCA9IHBhcnNlTG9nRmlsZU5hbWUobmFtZSk7XG4gICAgICAgIGlmICghcGFyc2VkIHx8IG5hbWUuaW5jbHVkZXMoXCIvXCIpIHx8IG5hbWUuaW5jbHVkZXMoXCJcXFxcXCIpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vdCBhIGxvZyBmaWxlIG5hbWU6ICR7SlNPTi5zdHJpbmdpZnkobmFtZS5zbGljZSgwLCAyMDApKX1gKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZmlsZVBhdGggPSBwYXRoLmpvaW4odGhpcy5jb25maWcuZm9sZGVyLCBuYW1lKTtcbiAgICAgICAgaWYgKHBhcnNlZC5jb21wcmVzc2VkKSB7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZnMucHJvbWlzZXMucmVhZEZpbGUoZmlsZVBhdGgpO1xuICAgICAgICB9XG4gICAgICAgIC8vIEZsdXNoIHNvIG91ciBvd24gbGl2ZSBmaWxlIGluY2x1ZGVzIGV2ZXJ5dGhpbmcgbG9nZ2VkIHVwIHRvIG5vd1xuICAgICAgICBhd2FpdCB0aGlzLmZsdXNoKCk7XG4gICAgICAgIHJldHVybiBMWjQuY29tcHJlc3MoYXdhaXQgZnMucHJvbWlzZXMucmVhZEZpbGUoZmlsZVBhdGgpKTtcbiAgICB9XG5cbiAgICAvLyDilIDilIAgbWFpbnRlbmFuY2Ug4pSA4pSAXG5cbiAgICBwcml2YXRlIHNjaGVkdWxlTWFpbnRlbmFuY2UoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRpc3Bvc2VkKSByZXR1cm47XG4gICAgICAgIGxldCB3YWl0ID0gTUFJTlRFTkFOQ0VfTUlOX0lOVEVSVkFMICsgTWF0aC5yYW5kb20oKSAqIChNQUlOVEVOQU5DRV9NQVhfSU5URVJWQUwgLSBNQUlOVEVOQU5DRV9NSU5fSU5URVJWQUwpO1xuICAgICAgICB0aGlzLm1haW50ZW5hbmNlVGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHZvaWQgdGhpcy5ydW5NYWludGVuYW5jZSgpLmNhdGNoKChlOiBFcnJvcikgPT4gY29uc29sZS53YXJuKGBMb2cgbWFpbnRlbmFuY2Ugb2YgJHt0aGlzLmNvbmZpZy5mb2xkZXJ9IGZhaWxlZDogJHtlLnN0YWNrID8/IGV9YCkpLmZpbmFsbHkoKCkgPT4gdGhpcy5zY2hlZHVsZU1haW50ZW5hbmNlKCkpO1xuICAgICAgICB9LCB3YWl0KTtcbiAgICAgICAgKHRoaXMubWFpbnRlbmFuY2VUaW1lciBhcyB7IHVucmVmPzogKCkgPT4gdm9pZCB9KS51bnJlZj8uKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2hhcmVkIHVwa2VlcCBvZiB0aGUgZm9sZGVyIC0gZXZlcnkgcHJvY2VzcyB1c2luZyBpdCBydW5zIHRoaXMsIHNvIG5vdGhpbmcgZGVwZW5kcyBvbiBhbnkgb25lXG4gICAgICogcHJvY2VzcyBzdXJ2aXZpbmc6IGRlYWQgcHJvY2Vzc2VzJyB1bmNvbXByZXNzZWQgZmlsZXMgYXJlIGNvbXByZXNzZWQgZm9yIHRoZW07IGR1cGxpY2F0ZVxuICAgICAqIGNvbXByZXNzaW9ucyBvZiBvbmUgc3RyZWFtICh0d28gbWFpbnRhaW5lcnMgcmFjaW5nKSBhcmUgcmVzb2x2ZWQgYnkga2VlcGluZyB0aGUgT0xERVNUIGNvcHk7XG4gICAgICogYW4gdW5jb21wcmVzc2VkIG9yaWdpbmFsIHdob3NlIGNvbXByZXNzaW9uIGFscmVhZHkgZXhpc3RzIGlzIGRlbGV0ZWQgKGl0cyBjb21wcmVzc29yIGRpZWRcbiAgICAgKiBiZXR3ZWVuIHJlbmFtZSBhbmQgdW5saW5rKTsgYW5kIHRoZSBmb2xkZXIncyB0b3RhbCBzaXplIGlzIGJyb3VnaHQgdW5kZXIgaXRzIGJ1ZGdldCBieVxuICAgICAqIGRlbGV0aW5nIHRoZSBvbGRlc3QgZmlsZXMuXG4gICAgICovXG4gICAgcHVibGljIGFzeW5jIHJ1bk1haW50ZW5hbmNlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgbmFtZXM6IHN0cmluZ1tdO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbmFtZXMgPSBhd2FpdCBmcy5wcm9taXNlcy5yZWFkZGlyKHRoaXMuY29uZmlnLmZvbGRlcik7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGlmICgoZSBhcyB7IGNvZGU/OiBzdHJpbmcgfSkuY29kZSA9PT0gXCJFTk9FTlRcIikgcmV0dXJuO1xuICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcGFyc2VkQnlOYW1lID0gbmV3IE1hcDxzdHJpbmcsIFBhcnNlZE5hbWU+KCk7XG4gICAgICAgIGZvciAobGV0IG5hbWUgb2YgbmFtZXMpIHtcbiAgICAgICAgICAgIGxldCBwYXJzZWQgPSBwYXJzZUxvZ0ZpbGVOYW1lKG5hbWUpO1xuICAgICAgICAgICAgaWYgKHBhcnNlZCkgcGFyc2VkQnlOYW1lLnNldChuYW1lLCBwYXJzZWQpO1xuICAgICAgICB9XG4gICAgICAgIGxldCBjb21wcmVzc2VkT3JpZ2lucyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgICAgICAgZm9yIChsZXQgW25hbWUsIHBhcnNlZF0gb2YgcGFyc2VkQnlOYW1lKSB7XG4gICAgICAgICAgICBpZiAoIXBhcnNlZC5jb21wcmVzc2VkKSBjb250aW51ZTtcbiAgICAgICAgICAgIGxldCBsaXN0ID0gY29tcHJlc3NlZE9yaWdpbnMuZ2V0KHBhcnNlZC5vcmlnaW5LZXkpO1xuICAgICAgICAgICAgaWYgKCFsaXN0KSB7XG4gICAgICAgICAgICAgICAgbGlzdCA9IFtdO1xuICAgICAgICAgICAgICAgIGNvbXByZXNzZWRPcmlnaW5zLnNldChwYXJzZWQub3JpZ2luS2V5LCBsaXN0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxpc3QucHVzaChuYW1lKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBEdXBsaWNhdGUgY29tcHJlc3Npb25zOiBrZWVwIHRoZSBvbGRlc3QgKGZpcnN0IHdyaXR0ZW4pLCBkZWxldGUgdGhlIHJlc3RcbiAgICAgICAgZm9yIChsZXQgW29yaWdpbiwgbGlzdF0gb2YgY29tcHJlc3NlZE9yaWdpbnMpIHtcbiAgICAgICAgICAgIGlmIChsaXN0Lmxlbmd0aCA8IDIpIGNvbnRpbnVlO1xuICAgICAgICAgICAgc29ydChsaXN0LCBuYW1lID0+IHBhcnNlZEJ5TmFtZS5nZXQobmFtZSk/LmVuZFRpbWUgfHwgMCk7XG4gICAgICAgICAgICBmb3IgKGxldCBkdXBsaWNhdGUgb2YgbGlzdC5zbGljZSgxKSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBEZWxldGluZyBkdXBsaWNhdGUgY29tcHJlc3NlZCBsb2cgJHtkdXBsaWNhdGV9IChhbm90aGVyIG1haW50YWluZXIgY29tcHJlc3NlZCAke29yaWdpbn0gZmlyc3QsIGtlZXBpbmcgJHtsaXN0WzBdfSlgKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBmcy5wcm9taXNlcy51bmxpbmsocGF0aC5qb2luKHRoaXMuY29uZmlnLmZvbGRlciwgZHVwbGljYXRlKSkuY2F0Y2goKCkgPT4geyB9KTtcbiAgICAgICAgICAgICAgICBwYXJzZWRCeU5hbWUuZGVsZXRlKGR1cGxpY2F0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgW25hbWUsIHBhcnNlZF0gb2YgcGFyc2VkQnlOYW1lKSB7XG4gICAgICAgICAgICBpZiAocGFyc2VkLmNvbXByZXNzZWQpIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IGZpbGVQYXRoID0gcGF0aC5qb2luKHRoaXMuY29uZmlnLmZvbGRlciwgbmFtZSk7XG4gICAgICAgICAgICBpZiAoZmlsZVBhdGggPT09IHRoaXMuY3VycmVudFBhdGgpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKGNvbXByZXNzZWRPcmlnaW5zLmhhcyhwYXJzZWQub3JpZ2luS2V5KSkge1xuICAgICAgICAgICAgICAgIC8vIEFscmVhZHkgY29tcHJlc3NlZCBieSBzb21lb25lIHdob3NlIGNsZWFudXAgZGllZCBiZXR3ZWVuIHJlbmFtZSBhbmQgdW5saW5rXG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coYERlbGV0aW5nIHVuY29tcHJlc3NlZCBsb2cgJHtuYW1lfTogaXRzIGNvbXByZXNzZWQgdmVyc2lvbiBhbHJlYWR5IGV4aXN0c2ApO1xuICAgICAgICAgICAgICAgIGF3YWl0IGZzLnByb21pc2VzLnVubGluayhmaWxlUGF0aCkuY2F0Y2goKCkgPT4geyB9KTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEEgbGl2ZSBwcm9jZXNzIG93bnMgaXRzIHVuY29tcHJlc3NlZCBmaWxlOyBvbmx5IGEgREVBRCBwcm9jZXNzJ3MgZmlsZXMgYXJlIGNvbXByZXNzZWQgZm9yIGl0IChvdXIgb3duIHBpZCBhbHdheXMgcmVhZHMgYXMgYWxpdmUsIHdoaWNoIGNvcnJlY3RseSBwcm90ZWN0cyBvdXIgY3VycmVudCBmaWxlIC0gb3VyIHJvdGF0ZWQgbGVmdG92ZXJzIHdlcmUgZXhjbHVkZWQgYWJvdmUgb25seSBpZiBjdXJyZW50LCBzbyBjb21wcmVzcyB0aG9zZSB0b28pXG4gICAgICAgICAgICBpZiAocGFyc2VkLnBpZCAhPT0gcHJvY2Vzcy5waWQgJiYgYXdhaXQgaXNQcm9jZXNzQWxpdmUocGFyc2VkLnBpZCwgcGFyc2VkLnByb2Nlc3NTdGFydFRpbWUpKSBjb250aW51ZTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5jb21wcmVzc0ZpbGUoZmlsZVBhdGgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgQ29tcHJlc3NpbmcgZGVhZCBwcm9jZXNzJ3MgbG9nICR7bmFtZX0gZmFpbGVkICh0aGUgbmV4dCBtYWludGVuYW5jZSBwYXNzIHJldHJpZXMpOiAkeyhlIGFzIEVycm9yKS5zdGFjayA/PyBlfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMuZW5mb3JjZVRvdGFsTGltaXQoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIGVuZm9yY2VUb3RhbExpbWl0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBsZXQgbGltaXQgPSB0aGlzLmNvbmZpZy50b3RhbExpbWl0Qnl0ZXMgfHwgVE9UQUxfTElNSVRfQllURVM7XG4gICAgICAgIGxldCBmaWxlcyA9IGF3YWl0IHRoaXMubGlzdEZpbGVzKCk7XG4gICAgICAgIGxldCB0b3RhbCA9IGZpbGVzLnJlZHVjZSgoc3VtLCB4KSA9PiBzdW0gKyB4LnNpemUsIDApO1xuICAgICAgICBpZiAodG90YWwgPD0gbGltaXQpIHJldHVybjtcbiAgICAgICAgLy8gT2xkZXN0IGZpcnN0LCBieSB0aGUgZW5kIG9mIHdoYXQgdGhleSBjb3ZlcjsgbGl2ZSBmaWxlcyBsYXN0ICh0aGV5IGFyZSB0aGUgbmV3ZXN0IGRhdGEgYnkgZGVmaW5pdGlvbilcbiAgICAgICAgbGV0IGRlbGV0YWJsZSA9IGZpbGVzLmZpbHRlcih4ID0+ICF4LmFjdGl2ZSk7XG4gICAgICAgIHNvcnQoZGVsZXRhYmxlLCB4ID0+IHguZW5kVGltZSB8fCB4LnN0YXJ0VGltZSk7XG4gICAgICAgIGxldCBkZWxldGVkID0gMDtcbiAgICAgICAgbGV0IGRlbGV0ZWRCeXRlcyA9IDA7XG4gICAgICAgIGZvciAobGV0IGZpbGUgb2YgZGVsZXRhYmxlKSB7XG4gICAgICAgICAgICBpZiAodG90YWwgPD0gbGltaXQpIGJyZWFrO1xuICAgICAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMudW5saW5rKHBhdGguam9pbih0aGlzLmNvbmZpZy5mb2xkZXIsIGZpbGUubmFtZSkpLmNhdGNoKCgpID0+IHsgfSk7XG4gICAgICAgICAgICB0b3RhbCAtPSBmaWxlLnNpemU7XG4gICAgICAgICAgICBkZWxldGVkKys7XG4gICAgICAgICAgICBkZWxldGVkQnl0ZXMgKz0gZmlsZS5zaXplO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKGBMb2dzIGluICR7dGhpcy5jb25maWcuZm9sZGVyfSBvdXRncmV3IHRoZWlyICR7bGltaXR9IGJ5dGUgYnVkZ2V0OiBkZWxldGVkIHRoZSAke2RlbGV0ZWR9IG9sZGVzdCBmaWxlcyAoJHtkZWxldGVkQnl0ZXN9IGJ5dGVzKSwgJHt0b3RhbH0gYnl0ZXMgcmVtYWluYCk7XG4gICAgfVxuXG4gICAgcHVibGljIGRpc3Bvc2UoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGlzcG9zZWQgPSB0cnVlO1xuICAgICAgICBpZiAodGhpcy5mbHVzaFRpbWVyKSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5mbHVzaFRpbWVyKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5tYWludGVuYW5jZVRpbWVyKSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5tYWludGVuYW5jZVRpbWVyKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdfQ==
|
|
399
|
+
/* _JS_SOURCE_HASH = "e469b5a680d38d12efd2071191e27c81bcbebfb6ac34330bdf9686d27e2b89da"; */
|