sliftutils 1.7.99 → 1.7.100

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.
@@ -0,0 +1,212 @@
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.TransactionFile = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const caching_1 = require("socket-function/src/caching");
10
+ // A persistent Map that knows about time and about deletions. Every value carries the time it was written, so a write that arrives out of order is simply not applied - the map cannot be made to go backwards. A deleted key keeps its time too, as a tombstone in a second map, so "was this deleted, and when" is as cheap to ask as "does this exist", and expiring old tombstones is a walk of the tombstones alone rather than of everything.
11
+ //
12
+ // On disk it is one append-only log of the sets, deletes and purges that produced both maps, rewritten from them whenever it has grown to several times their size.
13
+ // The log is rewritten once it holds this many times more records than there are keys (a log of 3 records per surviving key is mostly history)
14
+ const COMPACT_RATIO = 3;
15
+ // ...but never for a small log, where the rewrite would cost more than the history it removes
16
+ const MIN_COMPACT_RECORDS = 1000;
17
+ // Appends are coalesced for this long. A crash loses at most this much - the callers of this class treat their data as reconstructible - and the alternative is a file write per set.
18
+ const FLUSH_DELAY = 500;
19
+ class TransactionFile {
20
+ constructor(filePath) {
21
+ this.filePath = filePath;
22
+ this.values = new Map();
23
+ this.deleted = new Map();
24
+ // Records the log holds (written plus pending) - what compaction is decided against, NOT the number of keys
25
+ this.logRecords = 0;
26
+ this.pending = [];
27
+ // Serializes everything that touches the file, so an append can never interleave with a rewrite
28
+ this.writeChain = Promise.resolve();
29
+ /** Reads the log and replays it into memory. Every other method assumes this has finished. */
30
+ this.load = (0, caching_1.lazy)(async () => {
31
+ let data;
32
+ try {
33
+ data = await fs_1.default.promises.readFile(this.filePath, "utf8");
34
+ }
35
+ catch (e) {
36
+ if (e.code === "ENOENT")
37
+ return;
38
+ throw e;
39
+ }
40
+ let applied = 0;
41
+ let damaged = 0;
42
+ for (let line of data.split("\n")) {
43
+ if (!line)
44
+ continue;
45
+ let record;
46
+ try {
47
+ record = JSON.parse(line);
48
+ }
49
+ catch (_a) {
50
+ // A crash mid-append leaves a torn final line; anything earlier means real damage. Either way the rest of the log is still worth having - this is an index, and scanning rebuilds whatever we lose.
51
+ damaged++;
52
+ continue;
53
+ }
54
+ applied++;
55
+ // Replayed through the same ordering rules that produced it, so a log written out of order still lands on the same state
56
+ if (record.p) {
57
+ this.values.delete(record.k);
58
+ this.deleted.delete(record.k);
59
+ }
60
+ else if (record.d) {
61
+ this.applyDelete(record.k, record.t, record.t);
62
+ }
63
+ else if (record.v !== undefined) {
64
+ this.applySet(record.k, record.v, record.t, record.t);
65
+ }
66
+ }
67
+ this.logRecords = applied;
68
+ if (damaged) {
69
+ console.error(`${damaged} damaged record(s) in ${this.filePath} were skipped; ${applied} applied, leaving ${this.values.size} values and ${this.deleted.size} tombstones`);
70
+ }
71
+ });
72
+ this.directory = (0, caching_1.lazy)(async () => {
73
+ await fs_1.default.promises.mkdir(path_1.default.dirname(this.filePath), { recursive: true });
74
+ });
75
+ }
76
+ /** The live value, or undefined when the key does not exist here (deleted included - a deletion is an absence, see getDeleted for its time). */
77
+ get(key) {
78
+ return this.values.get(key);
79
+ }
80
+ /** When the key was deleted, if it was. Absent both here and in get means we have never heard of it. */
81
+ getDeleted(key) {
82
+ return this.deleted.get(key);
83
+ }
84
+ /** The time the key last changed either way, or 0 if we have never heard of it - what a new write has to beat. */
85
+ timeOf(key) {
86
+ var _a;
87
+ let live = this.values.get(key);
88
+ if (live)
89
+ return live.time;
90
+ return ((_a = this.deleted.get(key)) === null || _a === void 0 ? void 0 : _a.time) || 0;
91
+ }
92
+ /** O(1), and counts only what exists. */
93
+ get size() {
94
+ return this.values.size;
95
+ }
96
+ get deletedSize() {
97
+ return this.deleted.size;
98
+ }
99
+ /** Live values only. Live, in insertion order - deleting during iteration is safe (JS skips entries removed before they are reached), which is what the passes that walk everything and prune as they go rely on. */
100
+ entries() {
101
+ return this.values.entries();
102
+ }
103
+ /** The tombstones, which is a much smaller walk than the values - so expiring them, or listing what was deleted since some time, costs what it should. */
104
+ deletedEntries() {
105
+ return this.deleted.entries();
106
+ }
107
+ /** Stores a value as of `time`. Returns false when something at least as new is already here, in which case nothing changed - an out-of-order write is not an error, it is just late. */
108
+ set(key, value, time) {
109
+ if (!this.applySet(key, value, time, Date.now()))
110
+ return false;
111
+ this.append({ k: key, t: time, v: value });
112
+ return true;
113
+ }
114
+ /** Deletes as of `time`, keeping the tombstone. Returns false when something at least as new is already here. */
115
+ delete(key, time) {
116
+ if (!this.applyDelete(key, time, Date.now()))
117
+ return false;
118
+ this.append({ k: key, t: time, d: 1 });
119
+ return true;
120
+ }
121
+ /** Forgets the key entirely, tombstone included - for a tombstone old enough that nobody needs to hear about the deletion any more, and for an entry that turned out never to have existed. Not a deletion: it leaves nothing behind to propagate. */
122
+ purge(key) {
123
+ let had = this.values.delete(key);
124
+ had = this.deleted.delete(key) || had;
125
+ if (!had)
126
+ return;
127
+ this.append({ k: key, t: Date.now(), p: 1 });
128
+ }
129
+ applySet(key, value, time, changedAt) {
130
+ if (time < this.timeOf(key))
131
+ return false;
132
+ this.deleted.delete(key);
133
+ this.values.set(key, { value, time, changedAt });
134
+ return true;
135
+ }
136
+ applyDelete(key, time, changedAt) {
137
+ if (time < this.timeOf(key))
138
+ return false;
139
+ this.values.delete(key);
140
+ this.deleted.set(key, { time, changedAt });
141
+ return true;
142
+ }
143
+ append(record) {
144
+ this.pending.push(JSON.stringify(record));
145
+ this.logRecords++;
146
+ this.scheduleFlush();
147
+ }
148
+ scheduleFlush() {
149
+ var _a, _b;
150
+ if (this.flushTimer !== undefined)
151
+ return;
152
+ this.flushTimer = setTimeout(() => {
153
+ this.flushTimer = undefined;
154
+ void this.flush().catch((e) => { var _a; return console.error(`Flushing ${this.filePath} failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); });
155
+ }, FLUSH_DELAY);
156
+ (_b = (_a = this.flushTimer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
157
+ }
158
+ /** Writes everything pending (rewriting the log first if it has grown too far past what it describes). */
159
+ async flush() {
160
+ let result = this.writeChain.then(() => this.write());
161
+ // The chain only exists to serialize writes, so it must not stay rejected: a failure belongs to the caller that asked for this flush, not to every flush after it
162
+ this.writeChain = result.catch(() => { });
163
+ await result;
164
+ }
165
+ async write() {
166
+ if (this.logRecords > Math.max(MIN_COMPACT_RECORDS, (this.values.size + this.deleted.size) * COMPACT_RATIO)) {
167
+ await this.compact();
168
+ return;
169
+ }
170
+ await this.appendPending();
171
+ }
172
+ async appendPending() {
173
+ if (!this.pending.length)
174
+ return;
175
+ let records = this.pending;
176
+ this.pending = [];
177
+ await this.directory();
178
+ try {
179
+ await fs_1.default.promises.appendFile(this.filePath, records.join("\n") + "\n");
180
+ }
181
+ catch (e) {
182
+ // Put them back rather than lose them: the values are still in memory, so all that is at risk is having to rebuild them by scanning
183
+ this.pending = records.concat(this.pending);
184
+ this.scheduleFlush();
185
+ throw e;
186
+ }
187
+ }
188
+ // Rewrites the log as the current contents of both maps. They are the truth - the log only exists to rebuild them - so the snapshot IS the new log.
189
+ async compact() {
190
+ let records = [];
191
+ for (let [key, entry] of this.values) {
192
+ records.push(JSON.stringify({ k: key, t: entry.time, v: entry.value }));
193
+ }
194
+ for (let [key, tombstone] of this.deleted) {
195
+ records.push(JSON.stringify({ k: key, t: tombstone.time, d: 1 }));
196
+ }
197
+ // Cleared with the snapshot: every pending record is already reflected in the maps, so the snapshot contains it. Anything appended from here on is NOT in the snapshot, and lands in the new log after the rename.
198
+ this.pending = [];
199
+ let startedWith = this.logRecords;
200
+ let tempPath = `${this.filePath}.compacting`;
201
+ await this.directory();
202
+ await fs_1.default.promises.writeFile(tempPath, records.length && `${records.join("\n")}\n` || "");
203
+ // Replaces the old log in one step, so a crash leaves either the whole old log or the whole new one
204
+ await fs_1.default.promises.rename(tempPath, this.filePath);
205
+ this.logRecords = records.length + this.pending.length;
206
+ console.log(`Rewrote ${this.filePath}: ${startedWith} log records for ${this.values.size} values and ${this.deleted.size} tombstones`);
207
+ await this.appendPending();
208
+ }
209
+ }
210
+ exports.TransactionFile = TransactionFile;
211
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVHJhbnNhY3Rpb25GaWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiVHJhbnNhY3Rpb25GaWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDRDQUFvQjtBQUNwQixnREFBd0I7QUFDeEIseURBQW1EO0FBRW5ELG9iQUFvYjtBQUNwYixFQUFFO0FBQ0Ysb0tBQW9LO0FBRXBLLCtJQUErSTtBQUMvSSxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQUM7QUFDeEIsOEZBQThGO0FBQzlGLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0FBQ2pDLHNMQUFzTDtBQUN0TCxNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUM7QUFxQnhCLE1BQWEsZUFBZTtJQUN4QixZQUFvQixRQUFnQjtRQUFoQixhQUFRLEdBQVIsUUFBUSxDQUFRO1FBRTVCLFdBQU0sR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztRQUN4QyxZQUFPLEdBQUcsSUFBSSxHQUFHLEVBQXdCLENBQUM7UUFDbEQsNEdBQTRHO1FBQ3BHLGVBQVUsR0FBRyxDQUFDLENBQUM7UUFDZixZQUFPLEdBQWEsRUFBRSxDQUFDO1FBRS9CLGdHQUFnRztRQUN4RixlQUFVLEdBQWtCLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUV0RCw4RkFBOEY7UUFDdkYsU0FBSSxHQUFHLElBQUEsY0FBSSxFQUFDLEtBQUssSUFBSSxFQUFFO1lBQzFCLElBQUksSUFBWSxDQUFDO1lBQ2pCLElBQUksQ0FBQztnQkFDRCxJQUFJLEdBQUcsTUFBTSxZQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzdELENBQUM7WUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNULElBQUssQ0FBdUIsQ0FBQyxJQUFJLEtBQUssUUFBUTtvQkFBRSxPQUFPO2dCQUN2RCxNQUFNLENBQUMsQ0FBQztZQUNaLENBQUM7WUFDRCxJQUFJLE9BQU8sR0FBRyxD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c291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gXCJmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGxhenkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9jYWNoaW5nXCI7XG5cbi8vIEEgcGVyc2lzdGVudCBNYXAgdGhhdCBrbm93cyBhYm91dCB0aW1lIGFuZCBhYm91dCBkZWxldGlvbnMuIEV2ZXJ5IHZhbHVlIGNhcnJpZXMgdGhlIHRpbWUgaXQgd2FzIHdyaXR0ZW4sIHNvIGEgd3JpdGUgdGhhdCBhcnJpdmVzIG91dCBvZiBvcmRlciBpcyBzaW1wbHkgbm90IGFwcGxpZWQgLSB0aGUgbWFwIGNhbm5vdCBiZSBtYWRlIHRvIGdvIGJhY2t3YXJkcy4gQSBkZWxldGVkIGtleSBrZWVwcyBpdHMgdGltZSB0b28sIGFzIGEgdG9tYnN0b25lIGluIGEgc2Vjb25kIG1hcCwgc28gXCJ3YXMgdGhpcyBkZWxldGVkLCBhbmQgd2hlblwiIGlzIGFzIGNoZWFwIHRvIGFzayBhcyBcImRvZXMgdGhpcyBleGlzdFwiLCBhbmQgZXhwaXJpbmcgb2xkIHRvbWJzdG9uZXMgaXMgYSB3YWxrIG9mIHRoZSB0b21ic3RvbmVzIGFsb25lIHJhdGhlciB0aGFuIG9mIGV2ZXJ5dGhpbmcuXG4vL1xuLy8gT24gZGlzayBpdCBpcyBvbmUgYXBwZW5kLW9ubHkgbG9nIG9mIHRoZSBzZXRzLCBkZWxldGVzIGFuZCBwdXJnZXMgdGhhdCBwcm9kdWNlZCBib3RoIG1hcHMsIHJld3JpdHRlbiBmcm9tIHRoZW0gd2hlbmV2ZXIgaXQgaGFzIGdyb3duIHRvIHNldmVyYWwgdGltZXMgdGhlaXIgc2l6ZS5cblxuLy8gVGhlIGxvZyBpcyByZXdyaXR0ZW4gb25jZSBpdCBob2xkcyB0aGlzIG1hbnkgdGltZXMgbW9yZSByZWNvcmRzIHRoYW4gdGhlcmUgYXJlIGtleXMgKGEgbG9nIG9mIDMgcmVjb3JkcyBwZXIgc3Vydml2aW5nIGtleSBpcyBtb3N0bHkgaGlzdG9yeSlcbmNvbnN0IENPTVBBQ1RfUkFUSU8gPSAzO1xuLy8gLi4uYnV0IG5ldmVyIGZvciBhIHNtYWxsIGxvZywgd2hlcmUgdGhlIHJld3JpdGUgd291bGQgY29zdCBtb3JlIHRoYW4gdGhlIGhpc3RvcnkgaXQgcmVtb3Zlc1xuY29uc3QgTUlOX0NPTVBBQ1RfUkVDT1JEUyA9IDEwMDA7XG4vLyBBcHBlbmRzIGFyZSBjb2FsZXNjZWQgZm9yIHRoaXMgbG9uZy4gQSBjcmFzaCBsb3NlcyBhdCBtb3N0IHRoaXMgbXVjaCAtIHRoZSBjYWxsZXJzIG9mIHRoaXMgY2xhc3MgdHJlYXQgdGhlaXIgZGF0YSBhcyByZWNvbnN0cnVjdGlibGUgLSBhbmQgdGhlIGFsdGVybmF0aXZlIGlzIGEgZmlsZSB3cml0ZSBwZXIgc2V0LlxuY29uc3QgRkxVU0hfREVMQVkgPSA1MDA7XG5cbi8qKiBBIGxpdmUgdmFsdWU6IHdoYXQgd2FzIHN0b3JlZCwgd2hlbiBpdCB3YXMgd3JpdHRlbiAodGhlIGNhbGxlcidzIG9yZGVyaW5nKSwgYW5kIHdoZW4gd2UgbGFzdCBjaGFuZ2VkIGl0IChvdXJzKS4gKi9cbmV4cG9ydCB0eXBlIExvZ0VudHJ5PFQ+ID0geyB2YWx1ZTogVDsgdGltZTogbnVtYmVyOyBjaGFuZ2VkQXQ6IG51bWJlciB9O1xuLyoqIEEgZGVsZXRlZCBrZXk6IHdoZW4gaXQgd2FzIGRlbGV0ZWQsIGFuZCB3aGVuIHdlIGxlYXJuZWQuIFRoZSB2YWx1ZSBpcyBnb25lOyB0aGUgdGltZSBpcyB0aGUgcG9pbnQgb2YgYSB0b21ic3RvbmUuICovXG5leHBvcnQgdHlwZSBMb2dUb21ic3RvbmUgPSB7IHRpbWU6IG51bWJlcjsgY2hhbmdlZEF0OiBudW1iZXIgfTtcblxuLy8gT25lIGxpbmUgb2YgdGhlIGxvZywgd2l0aCBzaW5nbGUtbGV0dGVyIGZpZWxkIG5hbWVzIGJlY2F1c2UgdGhlcmUgaXMgb25lIHJlY29yZCBwZXIgc2V0L2RlbGV0ZS9wdXJnZSBldmVyIG1hZGUgYW5kIHRoZSBmaWVsZCBuYW1lcyBhcmUgbW9zdCBvZiBhIHJlY29yZCdzIG92ZXJoZWFkLiBKU09OLnN0cmluZ2lmeSBlc2NhcGVzIG5ld2xpbmVzIGluc2lkZSBrZXlzIGFuZCB2YWx1ZXMsIHNvIGEgcmVjb3JkIGNhbiBuZXZlciBjb250YWluIHRoZSBzZXBhcmF0b3IuXG50eXBlIExvZ1JlY29yZDxUPiA9IHtcbiAgICAvLyBrZXlcbiAgICBrOiBzdHJpbmc7XG4gICAgLy8gdGltZSwgbGFzdE1vZGlmaWVkIHRpbWUgb2YgdGhlIGZpbGUsIG9yIHRoZSBkZWxldGUgdGltZSwgb3IgdGhlIHB1cmdlIHRpbWVcbiAgICB0OiBudW1iZXI7XG4gICAgLy8gdmFsdWVcbiAgICB2PzogVDtcbiAgICAvLyBkZWxldGVkLCB0aGUgZmlsZSBvbiBkaXNrIGlzIGRlbGV0ZWQsIHByZXNlcnZlZCB3aGVuIHdlIGNvbXBhY3RcbiAgICBkPzogMTtcbiAgICAvLyBwdXJnZWQsIHRoZSBmaWxlIG9uIGRpc2sgaXMgZGVsZXRlZCwgbm90IHByZXNlcnZlZCB3aGVuIHdlIGNvbXBhY3RcbiAgICBwPzogMTtcbn07XG5cbmV4cG9ydCBjbGFzcyBUcmFuc2FjdGlvbkZpbGU8VD4ge1xuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgZmlsZVBhdGg6IHN0cmluZykgeyB9XG5cbiAgICBwcml2YXRlIHZhbHVlcyA9IG5ldyBNYXA8c3RyaW5nLCBMb2dFbnRyeTxUPj4oKTtcbiAgICBwcml2YXRlIGRlbGV0ZWQgPSBuZXcgTWFwPHN0cmluZywgTG9nVG9tYnN0b25lPigpO1xuICAgIC8vIFJlY29yZHMgdGhlIGxvZyBob2xkcyAod3JpdHRlbiBwbHVzIHBlbmRpbmcpIC0gd2hhdCBjb21wYWN0aW9uIGlzIGRlY2lkZWQgYWdhaW5zdCwgTk9UIHRoZSBudW1iZXIgb2Yga2V5c1xuICAgIHByaXZhdGUgbG9nUmVjb3JkcyA9IDA7XG4gICAgcHJpdmF0ZSBwZW5kaW5nOiBzdHJpbmdbXSA9IFtdO1xuICAgIHByaXZhdGUgZmx1c2hUaW1lcjogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCB1bmRlZmluZWQ7XG4gICAgLy8gU2VyaWFsaXplcyBldmVyeXRoaW5nIHRoYXQgdG91Y2hlcyB0aGUgZmlsZSwgc28gYW4gYXBwZW5kIGNhbiBuZXZlciBpbnRlcmxlYXZlIHdpdGggYSByZXdyaXRlXG4gICAgcHJpdmF0ZSB3cml0ZUNoYWluOiBQcm9taXNlPHZvaWQ+ID0gUHJvbWlzZS5yZXNvbHZlKCk7XG5cbiAgICAvKiogUmVhZHMgdGhlIGxvZyBhbmQgcmVwbGF5cyBpdCBpbnRvIG1lbW9yeS4gRXZlcnkgb3RoZXIgbWV0aG9kIGFzc3VtZXMgdGhpcyBoYXMgZmluaXNoZWQuICovXG4gICAgcHVibGljIGxvYWQgPSBsYXp5KGFzeW5jICgpID0+IHtcbiAgICAgICAgbGV0IGRhdGE6IHN0cmluZztcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGRhdGEgPSBhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZSh0aGlzLmZpbGVQYXRoLCBcInV0ZjhcIik7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGlmICgoZSBhcyB7IGNvZGU/OiBzdHJpbmcgfSkuY29kZSA9PT0gXCJFTk9FTlRcIikgcmV0dXJuO1xuICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgYXBwbGllZCA9IDA7XG4gICAgICAgIGxldCBkYW1hZ2VkID0gMDtcbiAgICAgICAgZm9yIChsZXQgbGluZSBvZiBkYXRhLnNwbGl0KFwiXFxuXCIpKSB7XG4gICAgICAgICAgICBpZiAoIWxpbmUpIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IHJlY29yZDogTG9nUmVjb3JkPFQ+IHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZWNvcmQgPSBKU09OLnBhcnNlKGxpbmUpIGFzIExvZ1JlY29yZDxUPjtcbiAgICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgICAgIC8vIEEgY3Jhc2ggbWlkLWFwcGVuZCBsZWF2ZXMgYSB0b3JuIGZpbmFsIGxpbmU7IGFueXRoaW5nIGVhcmxpZXIgbWVhbnMgcmVhbCBkYW1hZ2UuIEVpdGhlciB3YXkgdGhlIHJlc3Qgb2YgdGhlIGxvZyBpcyBzdGlsbCB3b3J0aCBoYXZpbmcgLSB0aGlzIGlzIGFuIGluZGV4LCBhbmQgc2Nhbm5pbmcgcmVidWlsZHMgd2hhdGV2ZXIgd2UgbG9zZS5cbiAgICAgICAgICAgICAgICBkYW1hZ2VkKys7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhcHBsaWVkKys7XG4gICAgICAgICAgICAvLyBSZXBsYXllZCB0aHJvdWdoIHRoZSBzYW1lIG9yZGVyaW5nIHJ1bGVzIHRoYXQgcHJvZHVjZWQgaXQsIHNvIGEgbG9nIHdyaXR0ZW4gb3V0IG9mIG9yZGVyIHN0aWxsIGxhbmRzIG9uIHRoZSBzYW1lIHN0YXRlXG4gICAgICAgICAgICBpZiAocmVjb3JkLnApIHtcbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlcy5kZWxldGUocmVjb3JkLmspO1xuICAgICAgICAgICAgICAgIHRoaXMuZGVsZXRlZC5kZWxldGUocmVjb3JkLmspO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChyZWNvcmQuZCkge1xuICAgICAgICAgICAgICAgIHRoaXMuYXBwbHlEZWxldGUocmVjb3JkLmssIHJlY29yZC50LCByZWNvcmQudCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHJlY29yZC52ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmFwcGx5U2V0KHJlY29yZC5rLCByZWNvcmQudiwgcmVjb3JkLnQsIHJlY29yZC50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmxvZ1JlY29yZHMgPSBhcHBsaWVkO1xuICAgICAgICBpZiAoZGFtYWdlZCkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgJHtkYW1hZ2VkfSBkYW1hZ2VkIHJlY29yZChzKSBpbiAke3RoaXMuZmlsZVBhdGh9IHdlcmUgc2tpcHBlZDsgJHthcHBsaWVkfSBhcHBsaWVkLCBsZWF2aW5nICR7dGhpcy52YWx1ZXMuc2l6ZX0gdmFsdWVzIGFuZCAke3RoaXMuZGVsZXRlZC5zaXplfSB0b21ic3RvbmVzYCk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qKiBUaGUgbGl2ZSB2YWx1ZSwgb3IgdW5kZWZpbmVkIHdoZW4gdGhlIGtleSBkb2VzIG5vdCBleGlzdCBoZXJlIChkZWxldGVkIGluY2x1ZGVkIC0gYSBkZWxldGlvbiBpcyBhbiBhYnNlbmNlLCBzZWUgZ2V0RGVsZXRlZCBmb3IgaXRzIHRpbWUpLiAqL1xuICAgIHB1YmxpYyBnZXQoa2V5OiBzdHJpbmcpOiBMb2dFbnRyeTxUPiB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5nZXQoa2V5KTtcbiAgICB9XG4gICAgLyoqIFdoZW4gdGhlIGtleSB3YXMgZGVsZXRlZCwgaWYgaXQgd2FzLiBBYnNlbnQgYm90aCBoZXJlIGFuZCBpbiBnZXQgbWVhbnMgd2UgaGF2ZSBuZXZlciBoZWFyZCBvZiBpdC4gKi9cbiAgICBwdWJsaWMgZ2V0RGVsZXRlZChrZXk6IHN0cmluZyk6IExvZ1RvbWJzdG9uZSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLmRlbGV0ZWQuZ2V0KGtleSk7XG4gICAgfVxuICAgIC8qKiBUaGUgdGltZSB0aGUga2V5IGxhc3QgY2hhbmdlZCBlaXRoZXIgd2F5LCBvciAwIGlmIHdlIGhhdmUgbmV2ZXIgaGVhcmQgb2YgaXQgLSB3aGF0IGEgbmV3IHdyaXRlIGhhcyB0byBiZWF0LiAqL1xuICAgIHB1YmxpYyB0aW1lT2Yoa2V5OiBzdHJpbmcpOiBudW1iZXIge1xuICAgICAgICBsZXQgbGl2ZSA9IHRoaXMudmFsdWVzLmdldChrZXkpO1xuICAgICAgICBpZiAobGl2ZSkgcmV0dXJuIGxpdmUudGltZTtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVsZXRlZC5nZXQoa2V5KT8udGltZSB8fCAwO1xuICAgIH1cblxuICAgIC8qKiBPKDEpLCBhbmQgY291bnRzIG9ubHkgd2hhdCBleGlzdHMuICovXG4gICAgcHVibGljIGdldCBzaXplKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5zaXplO1xuICAgIH1cbiAgICBwdWJsaWMgZ2V0IGRlbGV0ZWRTaXplKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLmRlbGV0ZWQuc2l6ZTtcbiAgICB9XG4gICAgLyoqIExpdmUgdmFsdWVzIG9ubHkuIExpdmUsIGluIGluc2VydGlvbiBvcmRlciAtIGRlbGV0aW5nIGR1cmluZyBpdGVyYXRpb24gaXMgc2FmZSAoSlMgc2tpcHMgZW50cmllcyByZW1vdmVkIGJlZm9yZSB0aGV5IGFyZSByZWFjaGVkKSwgd2hpY2ggaXMgd2hhdCB0aGUgcGFzc2VzIHRoYXQgd2FsayBldmVyeXRoaW5nIGFuZCBwcnVuZSBhcyB0aGV5IGdvIHJlbHkgb24uICovXG4gICAgcHVibGljIGVudHJpZXMoKTogSXRlcmFibGVJdGVyYXRvcjxbc3RyaW5nLCBMb2dFbnRyeTxUPl0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzLmVudHJpZXMoKTtcbiAgICB9XG4gICAgLyoqIFRoZSB0b21ic3RvbmVzLCB3aGljaCBpcyBhIG11Y2ggc21hbGxlciB3YWxrIHRoYW4gdGhlIHZhbHVlcyAtIHNvIGV4cGlyaW5nIHRoZW0sIG9yIGxpc3Rpbmcgd2hhdCB3YXMgZGVsZXRlZCBzaW5jZSBzb21lIHRpbWUsIGNvc3RzIHdoYXQgaXQgc2hvdWxkLiAqL1xuICAgIHB1YmxpYyBkZWxldGVkRW50cmllcygpOiBJdGVyYWJsZUl0ZXJhdG9yPFtzdHJpbmcsIExvZ1RvbWJzdG9uZV0+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVsZXRlZC5lbnRyaWVzKCk7XG4gICAgfVxuXG4gICAgLyoqIFN0b3JlcyBhIHZhbHVlIGFzIG9mIGB0aW1lYC4gUmV0dXJucyBmYWxzZSB3aGVuIHNvbWV0aGluZyBhdCBsZWFzdCBhcyBuZXcgaXMgYWxyZWFkeSBoZXJlLCBpbiB3aGljaCBjYXNlIG5vdGhpbmcgY2hhbmdlZCAtIGFuIG91dC1vZi1vcmRlciB3cml0ZSBpcyBub3QgYW4gZXJyb3IsIGl0IGlzIGp1c3QgbGF0ZS4gKi9cbiAgICBwdWJsaWMgc2V0KGtleTogc3RyaW5nLCB2YWx1ZTogVCwgdGltZTogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghdGhpcy5hcHBseVNldChrZXksIHZhbHVlLCB0aW1lLCBEYXRlLm5vdygpKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgICB0aGlzLmFwcGVuZCh7IGs6IGtleSwgdDogdGltZSwgdjogdmFsdWUgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8qKiBEZWxldGVzIGFzIG9mIGB0aW1lYCwga2VlcGluZyB0aGUgdG9tYnN0b25lLiBSZXR1cm5zIGZhbHNlIHdoZW4gc29tZXRoaW5nIGF0IGxlYXN0IGFzIG5ldyBpcyBhbHJlYWR5IGhlcmUuICovXG4gICAgcHVibGljIGRlbGV0ZShrZXk6IHN0cmluZywgdGltZTogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghdGhpcy5hcHBseURlbGV0ZShrZXksIHRpbWUsIERhdGUubm93KCkpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHRoaXMuYXBwZW5kKHsgazoga2V5LCB0OiB0aW1lLCBkOiAxIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKiogRm9yZ2V0cyB0aGUga2V5IGVudGlyZWx5LCB0b21ic3RvbmUgaW5jbHVkZWQgLSBmb3IgYSB0b21ic3RvbmUgb2xkIGVub3VnaCB0aGF0IG5vYm9keSBuZWVkcyB0byBoZWFyIGFib3V0IHRoZSBkZWxldGlvbiBhbnkgbW9yZSwgYW5kIGZvciBhbiBlbnRyeSB0aGF0IHR1cm5lZCBvdXQgbmV2ZXIgdG8gaGF2ZSBleGlzdGVkLiBOb3QgYSBkZWxldGlvbjogaXQgbGVhdmVzIG5vdGhpbmcgYmVoaW5kIHRvIHByb3BhZ2F0ZS4gKi9cbiAgICBwdWJsaWMgcHVyZ2Uoa2V5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgbGV0IGhhZCA9IHRoaXMudmFsdWVzLmRlbGV0ZShrZXkpO1xuICAgICAgICBoYWQgPSB0aGlzLmRlbGV0ZWQuZGVsZXRlKGtleSkgfHwgaGFkO1xuICAgICAgICBpZiAoIWhhZCkgcmV0dXJuO1xuICAgICAgICB0aGlzLmFwcGVuZCh7IGs6IGtleSwgdDogRGF0ZS5ub3coKSwgcDogMSB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFwcGx5U2V0KGtleTogc3RyaW5nLCB2YWx1ZTogVCwgdGltZTogbnVtYmVyLCBjaGFuZ2VkQXQ6IG51bWJlcik6IGJvb2xlYW4ge1xuICAgICAgICBpZiAodGltZSA8IHRoaXMudGltZU9mKGtleSkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgdGhpcy5kZWxldGVkLmRlbGV0ZShrZXkpO1xuICAgICAgICB0aGlzLnZhbHVlcy5zZXQoa2V5LCB7IHZhbHVlLCB0aW1lLCBjaGFuZ2VkQXQgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXBwbHlEZWxldGUoa2V5OiBzdHJpbmcsIHRpbWU6IG51bWJlciwgY2hhbmdlZEF0OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgaWYgKHRpbWUgPCB0aGlzLnRpbWVPZihrZXkpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHRoaXMudmFsdWVzLmRlbGV0ZShrZXkpO1xuICAgICAgICB0aGlzLmRlbGV0ZWQuc2V0KGtleSwgeyB0aW1lLCBjaGFuZ2VkQXQgfSk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXBwZW5kKHJlY29yZDogTG9nUmVjb3JkPFQ+KTogdm9pZCB7XG4gICAgICAgIHRoaXMucGVuZGluZy5wdXNoKEpTT04uc3RyaW5naWZ5KHJlY29yZCkpO1xuICAgICAgICB0aGlzLmxvZ1JlY29yZHMrKztcbiAgICAgICAgdGhpcy5zY2hlZHVsZUZsdXNoKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzY2hlZHVsZUZsdXNoKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5mbHVzaFRpbWVyICE9PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICAgICAgdGhpcy5mbHVzaFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmZsdXNoVGltZXIgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICB2b2lkIHRoaXMuZmx1c2goKS5jYXRjaCgoZTogRXJyb3IpID0+IGNvbnNvbGUuZXJyb3IoYEZsdXNoaW5nICR7dGhpcy5maWxlUGF0aH0gZmFpbGVkOiAke2Uuc3RhY2sgPz8gZX1gKSk7XG4gICAgICAgIH0sIEZMVVNIX0RFTEFZKTtcbiAgICAgICAgKHRoaXMuZmx1c2hUaW1lciBhcyB7IHVucmVmPzogKCkgPT4gdm9pZCB9KS51bnJlZj8uKCk7XG4gICAgfVxuXG4gICAgLyoqIFdyaXRlcyBldmVyeXRoaW5nIHBlbmRpbmcgKHJld3JpdGluZyB0aGUgbG9nIGZpcnN0IGlmIGl0IGhhcyBncm93biB0b28gZmFyIHBhc3Qgd2hhdCBpdCBkZXNjcmliZXMpLiAqL1xuICAgIHB1YmxpYyBhc3luYyBmbHVzaCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IHJlc3VsdCA9IHRoaXMud3JpdGVDaGFpbi50aGVuKCgpID0+IHRoaXMud3JpdGUoKSk7XG4gICAgICAgIC8vIFRoZSBjaGFpbiBvbmx5IGV4aXN0cyB0byBzZXJpYWxpemUgd3JpdGVzLCBzbyBpdCBtdXN0IG5vdCBzdGF5IHJlamVjdGVkOiBhIGZhaWx1cmUgYmVsb25ncyB0byB0aGUgY2FsbGVyIHRoYXQgYXNrZWQgZm9yIHRoaXMgZmx1c2gsIG5vdCB0byBldmVyeSBmbHVzaCBhZnRlciBpdFxuICAgICAgICB0aGlzLndyaXRlQ2hhaW4gPSByZXN1bHQuY2F0Y2goKCkgPT4geyB9KTtcbiAgICAgICAgYXdhaXQgcmVzdWx0O1xuICAgIH1cblxuICAgIHByaXZhdGUgZGlyZWN0b3J5ID0gbGF6eShhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IGZzLnByb21pc2VzLm1rZGlyKHBhdGguZGlybmFtZSh0aGlzLmZpbGVQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgfSk7XG5cbiAgICBwcml2YXRlIGFzeW5jIHdyaXRlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5sb2dSZWNvcmRzID4gTWF0aC5tYXgoTUlOX0NPTVBBQ1RfUkVDT1JEUywgKHRoaXMudmFsdWVzLnNpemUgKyB0aGlzLmRlbGV0ZWQuc2l6ZSkgKiBDT01QQUNUX1JBVElPKSkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5jb21wYWN0KCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy5hcHBlbmRQZW5kaW5nKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBhcHBlbmRQZW5kaW5nKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAoIXRoaXMucGVuZGluZy5sZW5ndGgpIHJldHVybjtcbiAgICAgICAgbGV0IHJlY29yZHMgPSB0aGlzLnBlbmRpbmc7XG4gICAgICAgIHRoaXMucGVuZGluZyA9IFtdO1xuICAgICAgICBhd2FpdCB0aGlzLmRpcmVjdG9yeSgpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMuYXBwZW5kRmlsZSh0aGlzLmZpbGVQYXRoLCByZWNvcmRzLmpvaW4oXCJcXG5cIikgKyBcIlxcblwiKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gUHV0IHRoZW0gYmFjayByYXRoZXIgdGhhbiBsb3NlIHRoZW06IHRoZSB2YWx1ZXMgYXJlIHN0aWxsIGluIG1lbW9yeSwgc28gYWxsIHRoYXQgaXMgYXQgcmlzayBpcyBoYXZpbmcgdG8gcmVidWlsZCB0aGVtIGJ5IHNjYW5uaW5nXG4gICAgICAgICAgICB0aGlzLnBlbmRpbmcgPSByZWNvcmRzLmNvbmNhdCh0aGlzLnBlbmRpbmcpO1xuICAgICAgICAgICAgdGhpcy5zY2hlZHVsZUZsdXNoKCk7XG4gICAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmV3cml0ZXMgdGhlIGxvZyBhcyB0aGUgY3VycmVudCBjb250ZW50cyBvZiBib3RoIG1hcHMuIFRoZXkgYXJlIHRoZSB0cnV0aCAtIHRoZSBsb2cgb25seSBleGlzdHMgdG8gcmVidWlsZCB0aGVtIC0gc28gdGhlIHNuYXBzaG90IElTIHRoZSBuZXcgbG9nLlxuICAgIHByaXZhdGUgYXN5bmMgY29tcGFjdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgbGV0IHJlY29yZHM6IHN0cmluZ1tdID0gW107XG4gICAgICAgIGZvciAobGV0IFtrZXksIGVudHJ5XSBvZiB0aGlzLnZhbHVlcykge1xuICAgICAgICAgICAgcmVjb3Jkcy5wdXNoKEpTT04uc3RyaW5naWZ5KHsgazoga2V5LCB0OiBlbnRyeS50aW1lLCB2OiBlbnRyeS52YWx1ZSB9IHNhdGlzZmllcyBMb2dSZWNvcmQ8VD4pKTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCBba2V5LCB0b21ic3RvbmVdIG9mIHRoaXMuZGVsZXRlZCkge1xuICAgICAgICAgICAgcmVjb3Jkcy5wdXNoKEpTT04uc3RyaW5naWZ5KHsgazoga2V5LCB0OiB0b21ic3RvbmUudGltZSwgZDogMSB9IHNhdGlzZmllcyBMb2dSZWNvcmQ8VD4pKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBDbGVhcmVkIHdpdGggdGhlIHNuYXBzaG90OiBldmVyeSBwZW5kaW5nIHJlY29yZCBpcyBhbHJlYWR5IHJlZmxlY3RlZCBpbiB0aGUgbWFwcywgc28gdGhlIHNuYXBzaG90IGNvbnRhaW5zIGl0LiBBbnl0aGluZyBhcHBlbmRlZCBmcm9tIGhlcmUgb24gaXMgTk9UIGluIHRoZSBzbmFwc2hvdCwgYW5kIGxhbmRzIGluIHRoZSBuZXcgbG9nIGFmdGVyIHRoZSByZW5hbWUuXG4gICAgICAgIHRoaXMucGVuZGluZyA9IFtdO1xuICAgICAgICBsZXQgc3RhcnRlZFdpdGggPSB0aGlzLmxvZ1JlY29yZHM7XG4gICAgICAgIGxldCB0ZW1wUGF0aCA9IGAke3RoaXMuZmlsZVBhdGh9LmNvbXBhY3RpbmdgO1xuICAgICAgICBhd2FpdCB0aGlzLmRpcmVjdG9yeSgpO1xuICAgICAgICBhd2FpdCBmcy5wcm9taXNlcy53cml0ZUZpbGUodGVtcFBhdGgsIHJlY29yZHMubGVuZ3RoICYmIGAke3JlY29yZHMuam9pbihcIlxcblwiKX1cXG5gIHx8IFwiXCIpO1xuICAgICAgICAvLyBSZXBsYWNlcyB0aGUgb2xkIGxvZyBpbiBvbmUgc3RlcCwgc28gYSBjcmFzaCBsZWF2ZXMgZWl0aGVyIHRoZSB3aG9sZSBvbGQgbG9nIG9yIHRoZSB3aG9sZSBuZXcgb25lXG4gICAgICAgIGF3YWl0IGZzLnByb21pc2VzLnJlbmFtZSh0ZW1wUGF0aCwgdGhpcy5maWxlUGF0aCk7XG4gICAgICAgIHRoaXMubG9nUmVjb3JkcyA9IHJlY29yZHMubGVuZ3RoICsgdGhpcy5wZW5kaW5nLmxlbmd0aDtcbiAgICAgICAgY29uc29sZS5sb2coYFJld3JvdGUgJHt0aGlzLmZpbGVQYXRofTogJHtzdGFydGVkV2l0aH0gbG9nIHJlY29yZHMgZm9yICR7dGhpcy52YWx1ZXMuc2l6ZX0gdmFsdWVzIGFuZCAke3RoaXMuZGVsZXRlZC5zaXplfSB0b21ic3RvbmVzYCk7XG4gICAgICAgIGF3YWl0IHRoaXMuYXBwZW5kUGVuZGluZygpO1xuICAgIH1cbn1cbiJdfQ==
212
+ /* _JS_SOURCE_HASH = "721f22728293dfd0510cfdad96ff16d96bdc9ba934a1513eb2222ffe41ec1642"; */