@dbx-tools/core 0.6.222 → 0.6.224
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/README.md +14 -10
- package/index.ts +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +2 -2
- package/lib/src/file-lock.d.ts +8 -10
- package/lib/src/file-lock.js +22 -55
- package/package.json +4 -2
- package/src/file-lock.ts +26 -55
package/README.md
CHANGED
|
@@ -22,8 +22,8 @@ Key features:
|
|
|
22
22
|
Databricks bundle's App `config.env`.
|
|
23
23
|
- YAML/JSON brand-context discovery and loading with shared Zod validation.
|
|
24
24
|
- Idempotent executable downloads with zip/tar extraction and atomic installs.
|
|
25
|
-
- Cross-process file locks with
|
|
26
|
-
|
|
25
|
+
- Cross-process file locks with one portable, stale-reclaiming lock-directory
|
|
26
|
+
protocol shared by Bun and Node.
|
|
27
27
|
- Keyed mutual exclusion across the main thread and its worker threads.
|
|
28
28
|
|
|
29
29
|
## Install A Binary
|
|
@@ -285,12 +285,16 @@ await fileLock.withFileLock(["cache", name], async () => {
|
|
|
285
285
|
```
|
|
286
286
|
|
|
287
287
|
`withFileLock()` serializes processes on the same machine or shared filesystem.
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
288
|
+
Bun and Node both use `proper-lockfile` atomic lock-directory creation,
|
|
289
|
+
heartbeats, stale-lock reclamation, and ownership-safe release. Callers can
|
|
290
|
+
select the lock directory, explicitly request the legacy Bun `flock` backend,
|
|
291
|
+
observe the chosen backend, or set a wait timeout. Lock keys use the same stable
|
|
292
|
+
structured identity as process and Postgres advisory locks.
|
|
293
|
+
|
|
294
|
+
Drain long-running processes that still use the legacy default before starting
|
|
295
|
+
an upgraded process against the same shared state. The explicit `flock` backend
|
|
296
|
+
remains available for compatibility, but it does not coordinate with the
|
|
297
|
+
portable directory protocol.
|
|
294
298
|
|
|
295
299
|
Use `processLock.withProcessLock()` when only threads in one process compete,
|
|
296
300
|
`fileLock.withFileLock()` when local processes compete, and Postgres advisory
|
|
@@ -328,8 +332,8 @@ cached too.
|
|
|
328
332
|
- `config` - scoped environment, dotenv, and validated Databricks bundle lookup,
|
|
329
333
|
including runtime detection and typed coercion helpers.
|
|
330
334
|
- `file` - best-effort filesystem stat.
|
|
331
|
-
- `fileLock` -
|
|
332
|
-
|
|
335
|
+
- `fileLock` - portable cross-process lock directories shared by Bun and Node,
|
|
336
|
+
with an explicit legacy `flock` option.
|
|
333
337
|
- `processLock` - keyed mutual exclusion across the main thread and its workers,
|
|
334
338
|
with worker wiring (`processLockWorkerOptions`, `attachProcessLock`,
|
|
335
339
|
`processLockAttached`).
|
package/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
|
|
5
5
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/core";
|
|
6
|
-
export const PACKAGE_VERSION = "0.6.
|
|
6
|
+
export const PACKAGE_VERSION = "0.6.224";
|
|
7
7
|
export * as bin from "./src/bin.ts";
|
|
8
8
|
export * as brand from "./src/brand.ts";
|
|
9
9
|
export * as bundle from "./src/bundle.ts";
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const PACKAGE_IDENTIFIER = "@dbx-tools/core";
|
|
2
|
-
export declare const PACKAGE_VERSION = "0.6.
|
|
2
|
+
export declare const PACKAGE_VERSION = "0.6.224";
|
|
3
3
|
export * as bin from "./src/bin.ts";
|
|
4
4
|
export * as brand from "./src/brand.ts";
|
|
5
5
|
export * as bundle from "./src/bundle.ts";
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Regenerated from the exporting modules in ./src.
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/core";
|
|
5
|
-
export const PACKAGE_VERSION = "0.6.
|
|
5
|
+
export const PACKAGE_VERSION = "0.6.224";
|
|
6
6
|
export * as bin from "./src/bin.js";
|
|
7
7
|
export * as brand from "./src/brand.js";
|
|
8
8
|
export * as bundle from "./src/bundle.js";
|
|
@@ -15,4 +15,4 @@ export * as project from "./src/project.js";
|
|
|
15
15
|
export { BrandContextSchema, defaultBrandContext, parseBrandContext, brandContextJsonSchema, brandContextPrompt } from "./src/brand.js";
|
|
16
16
|
export { MAX_TCP_PORT, ENV_ONLY, valueSchema, bundleResourceSchema, bundleEnvEntrySchema, bundleAppSchema, appEnvEntrySchema, appSchema } from "./src/config.js";
|
|
17
17
|
export { COMMAND_NOT_FOUND_EXIT_CODE } from "./src/exec.js";
|
|
18
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxpQkFBaUIsQ0FBQztBQUNwRCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsU0FBUyxDQUFDO0FBQ3pDLE9BQU8sS0FBSyxHQUFHLE1BQU0sY0FBYyxDQUFDO0FBQ3BDLE9BQU8sS0FBSyxLQUFLLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxLQUFLLE1BQU0sTUFBTSxpQkFBaUIsQ0FBQztBQUMxQyxPQUFPLEtBQUssTUFBTSxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sS0FBSyxJQUFJLE1BQU0sZUFBZSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxJQUFJLE1BQU0sZUFBZSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxRQUFRLE1BQU0sb0JBQW9CLENBQUM7QUFDL0MsT0FBTyxLQUFLLFdBQVcsTUFBTSx1QkFBdUIsQ0FBQztBQUNyRCxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsRUFBRSxzQkFBc0IsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXhJLE9BQU8sRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxvQkFBb0IsRUFBRSxvQkFBb0IsRUFBRSxlQUFlLEVBQUUsaUJBQWlCLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakssT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sZUFBZSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gR0VORVJBVEVEIGJ5IHByb2plbiB3YXRjaCAtIERPIE5PVCBFRElULlxuLy8gUmVnZW5lcmF0ZWQgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZXMgaW4gLi9zcmMuXG4vLyBIYW5kIGVkaXRzIGFyZSBvdmVyd3JpdHRlbiBvbiB0aGUgbmV4dCB3YXRjaDsgdGhpcyBmaWxlIGlzIHJlYWQtb25seS5cblxuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfSURFTlRJRklFUiA9IFwiQGRieC10b29scy9jb3JlXCI7XG5leHBvcnQgY29uc3QgUEFDS0FHRV9WRVJTSU9OID0gXCIwLjYuMjI0XCI7XG5leHBvcnQgKiBhcyBiaW4gZnJvbSBcIi4vc3JjL2Jpbi50c1wiO1xuZXhwb3J0ICogYXMgYnJhbmQgZnJvbSBcIi4vc3JjL2JyYW5kLnRzXCI7XG5leHBvcnQgKiBhcyBidW5kbGUgZnJvbSBcIi4vc3JjL2J1bmRsZS50c1wiO1xuZXhwb3J0ICogYXMgY29uZmlnIGZyb20gXCIuL3NyYy9jb25maWcudHNcIjtcbmV4cG9ydCAqIGFzIGV4ZWMgZnJvbSBcIi4vc3JjL2V4ZWMudHNcIjtcbmV4cG9ydCAqIGFzIGZpbGUgZnJvbSBcIi4vc3JjL2ZpbGUudHNcIjtcbmV4cG9ydCAqIGFzIGZpbGVMb2NrIGZyb20gXCIuL3NyYy9maWxlLWxvY2sudHNcIjtcbmV4cG9ydCAqIGFzIHByb2Nlc3NMb2NrIGZyb20gXCIuL3NyYy9wcm9jZXNzLWxvY2sudHNcIjtcbmV4cG9ydCAqIGFzIHByb2plY3QgZnJvbSBcIi4vc3JjL3Byb2plY3QudHNcIjtcbmV4cG9ydCB0eXBlIHsgQmluQ29udGV4dCwgQmluU2VsZWN0aW9uQ29udGV4dCwgQmluU2VsZWN0b3IsIEJpblZlcnNpb25PdXRwdXQsIEJpblZlcnNpb25QYXJzZXIsIEJpbk9wdGlvbnMsIEJpblVybCB9IGZyb20gXCIuL3NyYy9iaW4udHNcIjtcbmV4cG9ydCB7IEJyYW5kQ29udGV4dFNjaGVtYSwgZGVmYXVsdEJyYW5kQ29udGV4dCwgcGFyc2VCcmFuZENvbnRleHQsIGJyYW5kQ29udGV4dEpzb25TY2hlbWEsIGJyYW5kQ29udGV4dFByb21wdCB9IGZyb20gXCIuL3NyYy9icmFuZC50c1wiO1xuZXhwb3J0IHR5cGUgeyBCcmFuZENvbnRleHQsIEJyYW5kQ29udGV4dElucHV0IH0gZnJvbSBcIi4vc3JjL2JyYW5kLnRzXCI7XG5leHBvcnQgeyBNQVhfVENQX1BPUlQsIEVOVl9PTkxZLCB2YWx1ZVNjaGVtYSwgYnVuZGxlUmVzb3VyY2VTY2hlbWEsIGJ1bmRsZUVudkVudHJ5U2NoZW1hLCBidW5kbGVBcHBTY2hlbWEsIGFwcEVudkVudHJ5U2NoZW1hLCBhcHBTY2hlbWEgfSBmcm9tIFwiLi9zcmMvY29uZmlnLnRzXCI7XG5leHBvcnQgdHlwZSB7IENvbmZpZ01hcFZhbHVlLCBDb25maWdEYXRhLCBDb25maWdTb3VyY2UsIENvbmZpZ09wdGlvbnMsIENvbmZpZ0ZpbGUgfSBmcm9tIFwiLi9zcmMvY29uZmlnLnRzXCI7XG5leHBvcnQgeyBDT01NQU5EX05PVF9GT1VORF9FWElUX0NPREUgfSBmcm9tIFwiLi9zcmMvZXhlYy50c1wiO1xuZXhwb3J0IHR5cGUgeyBFeGVjU3RkaW8sIExpbmVIYW5kbGVyLCBTdGRpb09wdGlvbiwgRXhlY1Jlc3VsdCwgQ2hpbGRQcm9jZXNzUmVzdWx0LCBFeGVjT3B0aW9ucywgU3luY0V4ZWNTdGRpbywgU3luY0V4ZWNPcHRpb25zLCBTcGF3bkFyZ3MgfSBmcm9tIFwiLi9zcmMvZXhlYy50c1wiO1xuZXhwb3J0IHR5cGUgeyBGaWxlTG9ja0JhY2tlbmQsIEZpbGVMb2NrQWNxdWlzaXRpb24sIEZpbGVMb2NrT3B0aW9ucyB9IGZyb20gXCIuL3NyYy9maWxlLWxvY2sudHNcIjtcbmV4cG9ydCB0eXBlIHsgUHJvamVjdENvbnRleHQgfSBmcm9tIFwiLi9zcmMvcHJvamVjdC50c1wiO1xuIl19
|
package/lib/src/file-lock.d.ts
CHANGED
|
@@ -5,16 +5,14 @@
|
|
|
5
5
|
* server) on the same key. For in-process / worker-thread exclusion use
|
|
6
6
|
* {@link withProcessLock} from `./process-lock.ts` instead.
|
|
7
7
|
*
|
|
8
|
-
* Backends
|
|
8
|
+
* Backends:
|
|
9
9
|
*
|
|
10
|
-
* 1. **
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 2. **
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* always on (fixed {@link STALE_MS} + heartbeat) so a crashed holder on this
|
|
17
|
-
* backend can be reclaimed.
|
|
10
|
+
* 1. **file** (default) — `proper-lockfile` atomic lock-directory creation,
|
|
11
|
+
* heartbeat, stale recovery, and ownership-safe release. Bun and Node use
|
|
12
|
+
* this same protocol.
|
|
13
|
+
* 2. **flock** (explicit compatibility option) — `flock(2)` via Bun FFI on
|
|
14
|
+
* Unix. It remains available to callers that selected it explicitly, but a
|
|
15
|
+
* runtime-dependent cascade cannot coordinate Bun and Node.
|
|
18
16
|
*
|
|
19
17
|
* The first backend that can be *initialized* is used for the whole call. A busy
|
|
20
18
|
* lock waits; an unavailable backend falls through to the next. Callers may only
|
|
@@ -34,7 +32,7 @@ export interface FileLockOptions {
|
|
|
34
32
|
* Directory for lockfiles. Defaults to `$TMPDIR/dbx-tools-locks`.
|
|
35
33
|
*/
|
|
36
34
|
dir?: string;
|
|
37
|
-
/** Override the
|
|
35
|
+
/** Override the backend list. Defaults to the portable `file` protocol. */
|
|
38
36
|
backends?: readonly FileLockBackend[];
|
|
39
37
|
/**
|
|
40
38
|
* Stop waiting and throw after this many milliseconds. Omit to poll forever.
|
package/lib/src/file-lock.js
CHANGED
|
@@ -5,16 +5,14 @@
|
|
|
5
5
|
* server) on the same key. For in-process / worker-thread exclusion use
|
|
6
6
|
* {@link withProcessLock} from `./process-lock.ts` instead.
|
|
7
7
|
*
|
|
8
|
-
* Backends
|
|
8
|
+
* Backends:
|
|
9
9
|
*
|
|
10
|
-
* 1. **
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 2. **
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* always on (fixed {@link STALE_MS} + heartbeat) so a crashed holder on this
|
|
17
|
-
* backend can be reclaimed.
|
|
10
|
+
* 1. **file** (default) — `proper-lockfile` atomic lock-directory creation,
|
|
11
|
+
* heartbeat, stale recovery, and ownership-safe release. Bun and Node use
|
|
12
|
+
* this same protocol.
|
|
13
|
+
* 2. **flock** (explicit compatibility option) — `flock(2)` via Bun FFI on
|
|
14
|
+
* Unix. It remains available to callers that selected it explicitly, but a
|
|
15
|
+
* runtime-dependent cascade cannot coordinate Bun and Node.
|
|
18
16
|
*
|
|
19
17
|
* The first backend that can be *initialized* is used for the whole call. A busy
|
|
20
18
|
* lock waits; an unavailable backend falls through to the next. Callers may only
|
|
@@ -31,12 +29,13 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
31
29
|
}
|
|
32
30
|
return path;
|
|
33
31
|
};
|
|
34
|
-
import { mkdir, open
|
|
32
|
+
import { mkdir, open } from "node:fs/promises";
|
|
35
33
|
import { tmpdir } from "node:os";
|
|
36
34
|
import { dirname, join } from "node:path";
|
|
37
35
|
import { async, error, functionModule, hash, log, object } from "@dbx-tools/shared-core";
|
|
36
|
+
import lockfile from "proper-lockfile";
|
|
38
37
|
const logger = log.logger("core:file-lock");
|
|
39
|
-
const DEFAULT_BACKENDS = ["
|
|
38
|
+
const DEFAULT_BACKENDS = ["file"];
|
|
40
39
|
/** Poll interval while waiting for a contended OS lock. */
|
|
41
40
|
const POLL_MS = 50;
|
|
42
41
|
/**
|
|
@@ -84,7 +83,7 @@ export async function withFileLock(key, fn, options = {}) {
|
|
|
84
83
|
return holdFlock(lockPath, flock, deadline, fn);
|
|
85
84
|
}
|
|
86
85
|
case "file": {
|
|
87
|
-
const lockPath = join(dir,
|
|
86
|
+
const lockPath = join(dir, id);
|
|
88
87
|
logger.debug("acquiring lock", { backend, key: id, path: lockPath });
|
|
89
88
|
options.onAcquire?.({ backend });
|
|
90
89
|
return holdLockDirectory(lockPath, deadline, fn);
|
|
@@ -162,69 +161,37 @@ async function waitForFlock(fd, flock, lockPath, deadline) {
|
|
|
162
161
|
}
|
|
163
162
|
}
|
|
164
163
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* `mkdir` is the same primitive used by `proper-lockfile`: it is atomic across
|
|
168
|
-
* supported local and network filesystems. The holder refreshes mtime on a fixed
|
|
169
|
-
* heartbeat so a live long-running lock is never reclaimed; a crashed holder's
|
|
170
|
-
* directory becomes reclaimable after {@link STALE_MS}.
|
|
164
|
+
* Portable lock-directory ownership through `proper-lockfile`.
|
|
171
165
|
*/
|
|
172
166
|
async function holdLockDirectory(lockPath, deadline, fn) {
|
|
173
167
|
await ensureParentDir(lockPath);
|
|
174
|
-
await acquireLockDirectory(lockPath, deadline);
|
|
175
|
-
const stopHeartbeat = startHeartbeat(lockPath);
|
|
168
|
+
const release = await acquireLockDirectory(lockPath, deadline);
|
|
176
169
|
try {
|
|
177
170
|
return await fn();
|
|
178
171
|
}
|
|
179
172
|
finally {
|
|
180
|
-
|
|
181
|
-
await rm(lockPath, { recursive: true, force: true }).catch(() => { });
|
|
173
|
+
await release();
|
|
182
174
|
}
|
|
183
175
|
}
|
|
184
176
|
async function acquireLockDirectory(lockPath, deadline) {
|
|
185
177
|
for (;;) {
|
|
186
178
|
try {
|
|
187
|
-
await
|
|
188
|
-
|
|
179
|
+
return await lockfile.lock(lockPath, {
|
|
180
|
+
realpath: false,
|
|
181
|
+
stale: STALE_MS,
|
|
182
|
+
update: UPDATE_MS,
|
|
183
|
+
retries: 0,
|
|
184
|
+
});
|
|
189
185
|
}
|
|
190
186
|
catch (cause) {
|
|
191
187
|
const err = cause;
|
|
192
|
-
if (err.code !== "
|
|
188
|
+
if (err.code !== "ELOCKED")
|
|
193
189
|
throw error.toError(cause);
|
|
194
|
-
await maybeReclaimStale(lockPath);
|
|
195
190
|
assertBeforeDeadline(lockPath, deadline);
|
|
196
191
|
await async.sleep(POLL_MS);
|
|
197
192
|
}
|
|
198
193
|
}
|
|
199
194
|
}
|
|
200
|
-
async function maybeReclaimStale(lockPath) {
|
|
201
|
-
try {
|
|
202
|
-
const { mtimeMs } = await stat(lockPath);
|
|
203
|
-
const age = Date.now() - mtimeMs;
|
|
204
|
-
if (age < STALE_MS)
|
|
205
|
-
return;
|
|
206
|
-
logger.debug("reclaiming stale lock directory", { path: lockPath, ageMs: age });
|
|
207
|
-
await rm(lockPath, { recursive: true, force: true });
|
|
208
|
-
}
|
|
209
|
-
catch (cause) {
|
|
210
|
-
const err = cause;
|
|
211
|
-
if (err.code !== "ENOENT")
|
|
212
|
-
throw error.toError(cause);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
function startHeartbeat(lockPath) {
|
|
216
|
-
const timer = setInterval(() => {
|
|
217
|
-
const now = new Date();
|
|
218
|
-
void utimes(lockPath, now, now).catch((cause) => {
|
|
219
|
-
logger.warn("file lock heartbeat failed", {
|
|
220
|
-
path: lockPath,
|
|
221
|
-
error: error.errorMessage(cause),
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
}, UPDATE_MS);
|
|
225
|
-
timer.unref();
|
|
226
|
-
return () => clearInterval(timer);
|
|
227
|
-
}
|
|
228
195
|
function assertBeforeDeadline(lockPath, deadline) {
|
|
229
196
|
if (deadline !== undefined && Date.now() >= deadline) {
|
|
230
197
|
throw new Error(`Timed out waiting for file lock: ${lockPath}`);
|
|
@@ -233,4 +200,4 @@ function assertBeforeDeadline(lockPath, deadline) {
|
|
|
233
200
|
async function ensureParentDir(lockPath) {
|
|
234
201
|
await mkdir(dirname(lockPath), { recursive: true });
|
|
235
202
|
}
|
|
236
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1sb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpbGUtbG9jay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHOzs7Ozs7Ozs7QUFFSCxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDakMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFMUMsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFekYsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBSzVDLE1BQU0sZ0JBQWdCLEdBQStCLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBRXZFLDJEQUEyRDtBQUMzRCxNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUM7QUFFbkI7Ozs7R0FJRztBQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLE1BQU0sQ0FBQztBQUUzRSwrRUFBK0U7QUFDL0UsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztBQUVuRix1REFBdUQ7QUFDdkQsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0FBQ2xCLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQztBQUNsQixNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUM7QUFpQ2xC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b0JBQW9CLENBQUMsUUFBZ0IsRUFBRSxRQUE0QjtJQUMxRSxJQUFJLFFBQVEsS0FBSyxTQUFTLElBQUksSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQ3JELE1BQU0sSUFBSSxLQUFLLENBQUMsb0NBQW9DLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDbEUsQ0FBQztBQUNILENBQUM7QUFFRCxLQUFLLFVBQVUsZUFBZSxDQUFDLFFBQWdCO0lBQzdDLE1BQU0sS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ3RELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENhc2NhZGluZyBjcm9zcy1wcm9jZXNzIG11dHVhbCBleGNsdXNpb24gdmlhIGEgbG9ja2ZpbGUuXG4gKlxuICogU2VyaWFsaXplcyBjb25jdXJyZW50ICpwcm9jZXNzZXMqICh0d28gYGJ1biBydW4gZGVtb2Agc2hlbGxzLCBhIENMSSBiZXNpZGUgYVxuICogc2VydmVyKSBvbiB0aGUgc2FtZSBrZXkuIEZvciBpbi1wcm9jZXNzIC8gd29ya2VyLXRocmVhZCBleGNsdXNpb24gdXNlXG4gKiB7QGxpbmsgd2l0aFByb2Nlc3NMb2NrfSBmcm9tIGAuL3Byb2Nlc3MtbG9jay50c2AgaW5zdGVhZC5cbiAqXG4gKiBCYWNrZW5kcywgaW4gb3JkZXI6XG4gKlxuICogMS4gKipmbG9jayoqIOKAlCBgZmxvY2soMilgIHZpYSBCdW4gRkZJIG9uIFVuaXggd2hlbiBgYnVuOmZmaWAgY2FuIGxvYWQgbGliYy5cbiAqICAgIE5vdCBhdmFpbGFibGUgb24gV2luZG93cywgYW5kIG5vdCBhdmFpbGFibGUgdW5kZXIgcGxhaW4gTm9kZSAobm8gRkZJKS5cbiAqICAgIEtlcm5lbCByZWxlYXNlcyB0aGUgbG9jayB3aGVuIHRoZSBmZCBjbG9zZXMgKGluY2x1ZGluZyBwcm9jZXNzIGRlYXRoKS5cbiAqIDIuICoqZmlsZSoqIOKAlCBhdG9taWMgbG9jay1kaXJlY3RvcnkgY3JlYXRpb24uIFRoaXMgaXMgdGhlIHN0cmF0ZWd5IHVzZWQgYnlcbiAqICAgIGBwcm9wZXItbG9ja2ZpbGVgOiBgbWtkaXJgIGlzIGF0b21pYyBvbiBXaW5kb3dzLCBVbml4LCBhbmQgbmV0d29yayBmaWxlXG4gKiAgICBzeXN0ZW1zIHdoZXJlIGBvcGVuKC4uLiwgXCJ3eFwiKWAgbWF5IG5vdCBiZSByZWxpYWJsZS4gU3RhbGUgZGV0ZWN0aW9uIGlzXG4gKiAgICBhbHdheXMgb24gKGZpeGVkIHtAbGluayBTVEFMRV9NU30gKyBoZWFydGJlYXQpIHNvIGEgY3Jhc2hlZCBob2xkZXIgb24gdGhpc1xuICogICAgYmFja2VuZCBjYW4gYmUgcmVjbGFpbWVkLlxuICpcbiAqIFRoZSBmaXJzdCBiYWNrZW5kIHRoYXQgY2FuIGJlICppbml0aWFsaXplZCogaXMgdXNlZCBmb3IgdGhlIHdob2xlIGNhbGwuIEEgYnVzeVxuICogbG9jayB3YWl0czsgYW4gdW5hdmFpbGFibGUgYmFja2VuZCBmYWxscyB0aHJvdWdoIHRvIHRoZSBuZXh0LiBDYWxsZXJzIG1heSBvbmx5XG4gKiBib3VuZCBob3cgbG9uZyB0byB3YWl0ICh7QGxpbmsgRmlsZUxvY2tPcHRpb25zLnRpbWVvdXRNc30pOyBzdGFsZSB0aW1pbmcgaXNcbiAqIG5vdCBjb25maWd1cmFibGUgc28gZXZlcnkgaG9sZGVyIGFuZCB3YWl0ZXIgYWdyZWVzLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBta2Rpciwgb3Blbiwgcm0sIHN0YXQsIHV0aW1lcyB9IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwibm9kZTpvc1wiO1xuaW1wb3J0IHsgZGlybmFtZSwgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcblxuaW1wb3J0IHsgYXN5bmMsIGVycm9yLCBmdW5jdGlvbk1vZHVsZSwgaGFzaCwgbG9nLCBvYmplY3QgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiY29yZTpmaWxlLWxvY2tcIik7XG5cbi8qKiBCYWNrZW5kcyB7QGxpbmsgd2l0aEZpbGVMb2NrfSBjYW4gYXR0ZW1wdCwgaW4gY2FzY2FkZSBvcmRlci4gKi9cbmV4cG9ydCB0eXBlIEZpbGVMb2NrQmFja2VuZCA9IFwiZmxvY2tcIiB8IFwiZmlsZVwiO1xuXG5jb25zdCBERUZBVUxUX0JBQ0tFTkRTOiByZWFkb25seSBGaWxlTG9ja0JhY2tlbmRbXSA9IFtcImZsb2NrXCIsIFwiZmlsZVwiXTtcblxuLyoqIFBvbGwgaW50ZXJ2YWwgd2hpbGUgd2FpdGluZyBmb3IgYSBjb250ZW5kZWQgT1MgbG9jay4gKi9cbmNvbnN0IFBPTExfTVMgPSA1MDtcblxuLyoqXG4gKiBBZ2UgYWZ0ZXIgd2hpY2ggYW4gdW5yZWZyZXNoZWQgbG9jayBkaXJlY3RvcnkgbWF5IGJlIHJlbW92ZWQuXG4gKiBNYXRjaGVzIGBwcm9wZXItbG9ja2ZpbGVgJ3MgZGVmYXVsdC4gTm90IGNhbGxlci1jb25maWd1cmFibGU6IGV2ZXJ5IHByb2Nlc3NcbiAqIG11c3Qgc2hhcmUgdGhlIHNhbWUgdGhyZXNob2xkIG9yIGEgbGl2ZSBob2xkZXIgY2FuIGJlIG1pc3Rha2VuIGZvciBzdGFsZS5cbiAqL1xuY29uc3QgU1RBTEVfTVMgPSBvYmplY3QudG9OdW1iZXIocHJvY2Vzcy5lbnYuRklMRV9MT0NLX1NUQUxFX01TKSA/PyAxMF8wMDA7XG5cbi8qKiBIZWFydGJlYXQgaW50ZXJ2YWwgZm9yIHJlZnJlc2hpbmcgbG9jay1kaXJlY3RvcnkgbXRpbWUgKGBTVEFMRV9NUyAvIDJgKS4gKi9cbmNvbnN0IFVQREFURV9NUyA9IG9iamVjdC50b051bWJlcihwcm9jZXNzLmVudi5GSUxFX0xPQ0tfVVBEQVRFX01TKSA/PyBTVEFMRV9NUyAvIDI7XG5cbi8qKiBgZmxvY2soMilgIG9wZXJhdGlvbiBiaXRzIChMaW51eCAvIG1hY09TIC8gQlNEKS4gKi9cbmNvbnN0IExPQ0tfRVggPSAyO1xuY29uc3QgTE9DS19OQiA9IDQ7XG5jb25zdCBMT0NLX1VOID0gODtcblxuLyoqIFJlc3VsdCBtZXRhZGF0YSB3aGVuIGEgY2FsbGVyIHdhbnRzIHRvIGtub3cgd2hpY2ggYmFja2VuZCByYW4uICovXG5leHBvcnQgaW50ZXJmYWNlIEZpbGVMb2NrQWNxdWlzaXRpb24ge1xuICBiYWNrZW5kOiBGaWxlTG9ja0JhY2tlbmQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZUxvY2tPcHRpb25zIHtcbiAgLyoqXG4gICAqIERpcmVjdG9yeSBmb3IgbG9ja2ZpbGVzLiBEZWZhdWx0cyB0byBgJFRNUERJUi9kYngtdG9vbHMtbG9ja3NgLlxuICAgKi9cbiAgZGlyPzogc3RyaW5nO1xuICAvKiogT3ZlcnJpZGUgdGhlIGNhc2NhZGUuIERlZmF1bHRzIHRvIGBmbG9ja2Ag4oaSIGBmaWxlYC4gKi9cbiAgYmFja2VuZHM/OiByZWFkb25seSBGaWxlTG9ja0JhY2tlbmRbXTtcbiAgLyoqXG4gICAqIFN0b3Agd2FpdGluZyBhbmQgdGhyb3cgYWZ0ZXIgdGhpcyBtYW55IG1pbGxpc2Vjb25kcy4gT21pdCB0byBwb2xsIGZvcmV2ZXIuXG4gICAqIFRoaXMgaXMgdGhlIG9ubHkgd2FpdC1sb29wIGtub2I7IHN0YWxlIHJlY2xhaW0gdGltaW5nIGlzIGZpeGVkLlxuICAgKi9cbiAgdGltZW91dE1zPzogbnVtYmVyO1xuICAvKiogSW52b2tlZCBvbmNlIHRoZSBiYWNrZW5kIGZvciB0aGlzIGNhbGwgaGFzIGJlZW4gY2hvc2VuLiAqL1xuICBvbkFjcXVpcmU/OiAoYWNxdWlzaXRpb246IEZpbGVMb2NrQWNxdWlzaXRpb24pID0+IHZvaWQ7XG59XG5cbnR5cGUgRmxvY2tGbiA9IChmZDogbnVtYmVyLCBvcGVyYXRpb246IG51bWJlcikgPT4gbnVtYmVyO1xuXG5pbnRlcmZhY2UgQnVuRmZpTW9kdWxlIHtcbiAgZGxvcGVuOiAoXG4gICAgcGF0aDogc3RyaW5nLFxuICAgIHN5bWJvbHM6IFJlY29yZDxzdHJpbmcsIHsgYXJnczogc3RyaW5nW107IHJldHVybnM6IHN0cmluZyB9PixcbiAgKSA9PiB7IHN5bWJvbHM6IHsgZmxvY2s6IEZsb2NrRm4gfSB9O1xuICBzdWZmaXg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBSdW4gYGZuYCB3aGlsZSBob2xkaW5nIGEgY3Jvc3MtcHJvY2VzcyBsb2NrIG5hbWVkIGJ5IGBrZXlgLlxuICpcbiAqIGBrZXlgIGlzIGNhbm9uaWNhbGl6ZWQgd2l0aCBgb2JqZWN0LnRvU3RhYmxlS2V5YCwgdGhlIHNhbWUgaWRlbnRpdHkgcnVsZSBhc1xuICogcHJvY2VzcyBhbmQgUG9zdGdyZXMgYWR2aXNvcnkgbG9ja3MuXG4gKlxuICogQGV4YW1wbGVcbiAqIGF3YWl0IHdpdGhGaWxlTG9jayhbXCJjYWNoZVwiLCBcImFwcGtpdFwiXSwgYXN5bmMgKCkgPT4ge1xuICogICBhd2FpdCBtaWdyYXRlKCk7XG4gKiB9KTtcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdpdGhGaWxlTG9jazxUPihcbiAga2V5OiB1bmtub3duLFxuICBmbjogKCkgPT4gVCB8IFByb21pc2U8VD4sXG4gIG9wdGlvbnM6IEZpbGVMb2NrT3B0aW9ucyA9IHt9LFxuKTogUHJvbWlzZTxUPiB7XG4gIGlmIChvcHRpb25zLnRpbWVvdXRNcyAhPT0gdW5kZWZpbmVkICYmIG9wdGlvbnMudGltZW91dE1zIDwgMCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJ0aW1lb3V0TXMgbXVzdCBiZSBub24tbmVnYXRpdmVcIik7XG4gIH1cbiAgY29uc3QgaWQgPSBsb2NrSWQoa2V5KTtcbiAgY29uc3QgYmFja2VuZHMgPSBvcHRpb25zLmJhY2tlbmRzID8/IERFRkFVTFRfQkFDS0VORFM7XG4gIGNvbnN0IGRpciA9IG9wdGlvbnMuZGlyID8/IGpvaW4odG1wZGlyKCksIFwiZGJ4LXRvb2xzLWxvY2tzXCIpO1xuICBjb25zdCBkZWFkbGluZSA9IG9wdGlvbnMudGltZW91dE1zID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiBEYXRlLm5vdygpICsgb3B0aW9ucy50aW1lb3V0TXM7XG5cbiAgZm9yIChjb25zdCBiYWNrZW5kIG9mIGJhY2tlbmRzKSB7XG4gICAgc3dpdGNoIChiYWNrZW5kKSB7XG4gICAgICBjYXNlIFwiZmxvY2tcIjoge1xuICAgICAgICBjb25zdCBsb2NrUGF0aCA9IGpvaW4oZGlyLCBgJHtpZH0uZmxvY2tgKTtcbiAgICAgICAgY29uc3QgZmxvY2sgPSBhd2FpdCByZXNvbHZlRmxvY2soKTtcbiAgICAgICAgaWYgKCFmbG9jaykge1xuICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcImxvY2sgYmFja2VuZCB1bmF2YWlsYWJsZVwiLCB7IGJhY2tlbmQsIGtleTogaWQgfSk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgbG9nZ2VyLmRlYnVnKFwiYWNxdWlyaW5nIGxvY2tcIiwgeyBiYWNrZW5kLCBrZXk6IGlkLCBwYXRoOiBsb2NrUGF0aCB9KTtcbiAgICAgICAgb3B0aW9ucy5vbkFjcXVpcmU/Lih7IGJhY2tlbmQgfSk7XG4gICAgICAgIHJldHVybiBob2xkRmxvY2sobG9ja1BhdGgsIGZsb2NrLCBkZWFkbGluZSwgZm4pO1xuICAgICAgfVxuICAgICAgY2FzZSBcImZpbGVcIjoge1xuICAgICAgICBjb25zdCBsb2NrUGF0aCA9IGpvaW4oZGlyLCBgJHtpZH0ubG9ja2ApO1xuICAgICAgICBsb2dnZXIuZGVidWcoXCJhY3F1aXJpbmcgbG9ja1wiLCB7IGJhY2tlbmQsIGtleTogaWQsIHBhdGg6IGxvY2tQYXRoIH0pO1xuICAgICAgICBvcHRpb25zLm9uQWNxdWlyZT8uKHsgYmFja2VuZCB9KTtcbiAgICAgICAgcmV0dXJuIGhvbGRMb2NrRGlyZWN0b3J5KGxvY2tQYXRoLCBkZWFkbGluZSwgZm4pO1xuICAgICAgfVxuICAgICAgZGVmYXVsdDoge1xuICAgICAgICBjb25zdCBfZXhoYXVzdGl2ZTogbmV2ZXIgPSBiYWNrZW5kO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVua25vd24gZmlsZS1sb2NrIGJhY2tlbmQ6ICR7U3RyaW5nKF9leGhhdXN0aXZlKX1gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB0aHJvdyBuZXcgRXJyb3IoXCJ3aXRoRmlsZUxvY2s6IG5vIGxvY2sgYmFja2VuZCBhdmFpbGFibGVcIik7XG59XG5cbi8qKiBDYW5vbmljYWwgZmlsZXN5c3RlbS1zYWZlIGlkIGZvciBhIGxvY2sga2V5LiAqL1xuZnVuY3Rpb24gbG9ja0lkKGtleTogdW5rbm93bik6IHN0cmluZyB7XG4gIGNvbnN0IHN0YWJsZSA9IG9iamVjdFxuICAgIC50b09uZU9yTWFueShrZXkpXG4gICAgLm1hcCgocGFydCkgPT4gb2JqZWN0LnRvU3RhYmxlS2V5KHBhcnQpKVxuICAgIC5qb2luKFwiXFx1MDAwMFwiKTtcbiAgLy8gU2hvcnQgZGlnZXN0IHNvIHBhdGhzIHN0YXkgd2VsbCB1bmRlciBPUyBsaW1pdHM7IGNvbGxpc2lvbnMgYXJlIGZpbmUg4oCUIHRoZXlcbiAgLy8gb25seSBtZXJnZSBjcml0aWNhbCBzZWN0aW9ucyB0aGF0IGFscmVhZHkgc2hhcmVkIGEga2V5IHN0cmluZy5cbiAgcmV0dXJuIGhhc2guZm52SGFzaChzdGFibGUpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYGZsb2NrKDIpYCB0aHJvdWdoIEJ1biBGRkkgd2hlbiBwb3NzaWJsZS5cbiAqXG4gKiBNZW1vaXplZDogdGhlIEZGSSBpbXBvcnQgKyBsaWJjIGBkbG9wZW5gIHJ1biBvbmNlIHBlciBwcm9jZXNzLiBSZXR1cm5zXG4gKiBgdW5kZWZpbmVkYCBvbiBXaW5kb3dzLCB1bmRlciBwbGFpbiBOb2RlLCBvciB3aGVuIGxpYmMgY2Fubm90IGJlIGxvYWRlZCDigJRcbiAqIGNhbGxlcnMgZmFsbCB0aHJvdWdoIHRvIHRoZSBuZXh0IGJhY2tlbmQuIEEgbWlzcyBpcyBjYWNoZWQgdG9vLCBzbyBhIHByb2Nlc3NcbiAqIHRoYXQgY2Fubm90IGZsb2NrIG5ldmVyIHJldHJpZXMgdGhlIGxvYWQuXG4gKi9cbmNvbnN0IHJlc29sdmVGbG9jayA9IGZ1bmN0aW9uTW9kdWxlLm1lbW9pemUoYXN5bmMgKCk6IFByb21pc2U8RmxvY2tGbiB8IHVuZGVmaW5lZD4gPT4ge1xuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gXCJ3aW4zMlwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAoIXByb2Nlc3MudmVyc2lvbnMuYnVuKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIHRyeSB7XG4gICAgLy8gRHluYW1pYyBzcGVjaWZpZXIgc28gYHRzY2AgKG5vIGBAdHlwZXNgIGZvciBgYnVuOmZmaWApIGRvZXMgbm90IHJlc29sdmUgaXQ7XG4gICAgLy8gdGhlIGltcG9ydCBvbmx5IHN1Y2NlZWRzIHVuZGVyIEJ1biBhdCBydW50aW1lLlxuICAgIGNvbnN0IHNwZWNpZmllciA9IFwiYnVuOmZmaVwiO1xuICAgIGNvbnN0IGZmaSA9IChhd2FpdCBpbXBvcnQoc3BlY2lmaWVyKSkgYXMgdW5rbm93biBhcyBCdW5GZmlNb2R1bGU7XG4gICAgY29uc3QgbGliUGF0aCA9IHByb2Nlc3MucGxhdGZvcm0gPT09IFwiZGFyd2luXCIgPyBcImxpYlN5c3RlbS5CLmR5bGliXCIgOiBgbGliYy4ke2ZmaS5zdWZmaXh9YDtcbiAgICBjb25zdCBsaWIgPSBmZmkuZGxvcGVuKGxpYlBhdGgsIHtcbiAgICAgIGZsb2NrOiB7IGFyZ3M6IFtcImkzMlwiLCBcImkzMlwiXSwgcmV0dXJuczogXCJpMzJcIiB9LFxuICAgIH0pO1xuICAgIHJldHVybiBsaWIuc3ltYm9scy5mbG9jaztcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJmbG9jayBGRkkgdW5hdmFpbGFibGVcIiwgeyBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGNhdXNlKSB9KTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59KTtcblxuYXN5bmMgZnVuY3Rpb24gaG9sZEZsb2NrPFQ+KFxuICBsb2NrUGF0aDogc3RyaW5nLFxuICBmbG9jazogRmxvY2tGbixcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgZm46ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuKTogUHJvbWlzZTxUPiB7XG4gIGF3YWl0IGVuc3VyZVBhcmVudERpcihsb2NrUGF0aCk7XG4gIGNvbnN0IGhhbmRsZSA9IGF3YWl0IG9wZW4obG9ja1BhdGgsIFwiYStcIik7XG4gIHRyeSB7XG4gICAgYXdhaXQgd2FpdEZvckZsb2NrKGhhbmRsZS5mZCwgZmxvY2ssIGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBmbigpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBmbG9jayhoYW5kbGUuZmQsIExPQ0tfVU4pO1xuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBoYW5kbGUuY2xvc2UoKS5jYXRjaCgoKSA9PiB7fSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gd2FpdEZvckZsb2NrKFxuICBmZDogbnVtYmVyLFxuICBmbG9jazogRmxvY2tGbixcbiAgbG9ja1BhdGg6IHN0cmluZyxcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbik6IFByb21pc2U8dm9pZD4ge1xuICBmb3IgKDs7KSB7XG4gICAgY29uc3QgcmMgPSBmbG9jayhmZCwgTE9DS19FWCB8IExPQ0tfTkIpO1xuICAgIGlmIChyYyA9PT0gMCkgcmV0dXJuO1xuICAgIGFzc2VydEJlZm9yZURlYWRsaW5lKGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgYXdhaXQgYXN5bmMuc2xlZXAoUE9MTF9NUyk7XG4gIH1cbn1cblxuLyoqXG4gKiBBdG9taWMgbG9jay1kaXJlY3RvcnkgY3JlYXRpb24g4oCUIHRoZSBwb3J0YWJsZSAvIFdpbmRvd3MgcGF0aC5cbiAqXG4gKiBgbWtkaXJgIGlzIHRoZSBzYW1lIHByaW1pdGl2ZSB1c2VkIGJ5IGBwcm9wZXItbG9ja2ZpbGVgOiBpdCBpcyBhdG9taWMgYWNyb3NzXG4gKiBzdXBwb3J0ZWQgbG9jYWwgYW5kIG5ldHdvcmsgZmlsZXN5c3RlbXMuIFRoZSBob2xkZXIgcmVmcmVzaGVzIG10aW1lIG9uIGEgZml4ZWRcbiAqIGhlYXJ0YmVhdCBzbyBhIGxpdmUgbG9uZy1ydW5uaW5nIGxvY2sgaXMgbmV2ZXIgcmVjbGFpbWVkOyBhIGNyYXNoZWQgaG9sZGVyJ3NcbiAqIGRpcmVjdG9yeSBiZWNvbWVzIHJlY2xhaW1hYmxlIGFmdGVyIHtAbGluayBTVEFMRV9NU30uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGhvbGRMb2NrRGlyZWN0b3J5PFQ+KFxuICBsb2NrUGF0aDogc3RyaW5nLFxuICBkZWFkbGluZTogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBmbjogKCkgPT4gVCB8IFByb21pc2U8VD4sXG4pOiBQcm9taXNlPFQ+IHtcbiAgYXdhaXQgZW5zdXJlUGFyZW50RGlyKGxvY2tQYXRoKTtcbiAgYXdhaXQgYWNxdWlyZUxvY2tEaXJlY3RvcnkobG9ja1BhdGgsIGRlYWRsaW5lKTtcbiAgY29uc3Qgc3RvcEhlYXJ0YmVhdCA9IHN0YXJ0SGVhcnRiZWF0KGxvY2tQYXRoKTtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgZm4oKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBzdG9wSGVhcnRiZWF0KCk7XG4gICAgYXdhaXQgcm0obG9ja1BhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KS5jYXRjaCgoKSA9PiB7fSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gYWNxdWlyZUxvY2tEaXJlY3RvcnkobG9ja1BhdGg6IHN0cmluZywgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCk6IFByb21pc2U8dm9pZD4ge1xuICBmb3IgKDs7KSB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IG1rZGlyKGxvY2tQYXRoKTtcbiAgICAgIHJldHVybjtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgY29uc3QgZXJyID0gY2F1c2UgYXMgTm9kZUpTLkVycm5vRXhjZXB0aW9uO1xuICAgICAgaWYgKGVyci5jb2RlICE9PSBcIkVFWElTVFwiKSB0aHJvdyBlcnJvci50b0Vycm9yKGNhdXNlKTtcbiAgICAgIGF3YWl0IG1heWJlUmVjbGFpbVN0YWxlKGxvY2tQYXRoKTtcbiAgICAgIGFzc2VydEJlZm9yZURlYWRsaW5lKGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgICBhd2FpdCBhc3luYy5zbGVlcChQT0xMX01TKTtcbiAgICB9XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gbWF5YmVSZWNsYWltU3RhbGUobG9ja1BhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHsgbXRpbWVNcyB9ID0gYXdhaXQgc3RhdChsb2NrUGF0aCk7XG4gICAgY29uc3QgYWdlID0gRGF0ZS5ub3coKSAtIG10aW1lTXM7XG4gICAgaWYgKGFnZSA8IFNUQUxFX01TKSByZXR1cm47XG4gICAgbG9nZ2VyLmRlYnVnKFwicmVjbGFpbWluZyBzdGFsZSBsb2NrIGRpcmVjdG9yeVwiLCB7IHBhdGg6IGxvY2tQYXRoLCBhZ2VNczogYWdlIH0pO1xuICAgIGF3YWl0IHJtKGxvY2tQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgY29uc3QgZXJyID0gY2F1c2UgYXMgTm9kZUpTLkVycm5vRXhjZXB0aW9uO1xuICAgIGlmIChlcnIuY29kZSAhPT0gXCJFTk9FTlRcIikgdGhyb3cgZXJyb3IudG9FcnJvcihjYXVzZSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gc3RhcnRIZWFydGJlYXQobG9ja1BhdGg6IHN0cmluZyk6ICgpID0+IHZvaWQge1xuICBjb25zdCB0aW1lciA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpO1xuICAgIHZvaWQgdXRpbWVzKGxvY2tQYXRoLCBub3csIG5vdykuY2F0Y2goKGNhdXNlKSA9PiB7XG4gICAgICBsb2dnZXIud2FybihcImZpbGUgbG9jayBoZWFydGJlYXQgZmFpbGVkXCIsIHtcbiAgICAgICAgcGF0aDogbG9ja1BhdGgsXG4gICAgICAgIGVycm9yOiBlcnJvci5lcnJvck1lc3NhZ2UoY2F1c2UpLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0sIFVQREFURV9NUyk7XG4gIHRpbWVyLnVucmVmKCk7XG4gIHJldHVybiAoKSA9PiBjbGVhckludGVydmFsKHRpbWVyKTtcbn1cblxuZnVuY3Rpb24gYXNzZXJ0QmVmb3JlRGVhZGxpbmUobG9ja1BhdGg6IHN0cmluZywgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICBpZiAoZGVhZGxpbmUgIT09IHVuZGVmaW5lZCAmJiBEYXRlLm5vdygpID49IGRlYWRsaW5lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUaW1lZCBvdXQgd2FpdGluZyBmb3IgZmlsZSBsb2NrOiAke2xvY2tQYXRofWApO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGVuc3VyZVBhcmVudERpcihsb2NrUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IG1rZGlyKGRpcm5hbWUobG9ja1BhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbn1cbiJdfQ==
|
|
203
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1sb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpbGUtbG9jay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRzs7Ozs7Ozs7O0FBRUgsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMvQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ2pDLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRTFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLGNBQWMsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3pGLE9BQU8sUUFBUSxNQUFNLGlCQUFpQixDQUFDO0FBRXZDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUs1QyxNQUFNLGdCQUFnQixHQUErQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBRTlELDJEQUEyRDtBQUMzRCxNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUM7QUFFbkI7Ozs7R0FJRztBQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLE1BQU0sQ0FBQztBQUUzRSwrRUFBK0U7QUFDL0UsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztBQUVuRix1REFBdUQ7QUFDdkQsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0FBQ2xCLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQztBQUNsQixNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUM7QUFpQ2xCOzs7Ozs7Ozs7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QUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztBQUN0RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDYXNjYWRpbmcgY3Jvc3MtcHJvY2VzcyBtdXR1YWwgZXhjbHVzaW9uIHZpYSBhIGxvY2tmaWxlLlxuICpcbiAqIFNlcmlhbGl6ZXMgY29uY3VycmVudCAqcHJvY2Vzc2VzKiAodHdvIGBidW4gcnVuIGRlbW9gIHNoZWxscywgYSBDTEkgYmVzaWRlIGFcbiAqIHNlcnZlcikgb24gdGhlIHNhbWUga2V5LiBGb3IgaW4tcHJvY2VzcyAvIHdvcmtlci10aHJlYWQgZXhjbHVzaW9uIHVzZVxuICoge0BsaW5rIHdpdGhQcm9jZXNzTG9ja30gZnJvbSBgLi9wcm9jZXNzLWxvY2sudHNgIGluc3RlYWQuXG4gKlxuICogQmFja2VuZHM6XG4gKlxuICogMS4gKipmaWxlKiogKGRlZmF1bHQpIOKAlCBgcHJvcGVyLWxvY2tmaWxlYCBhdG9taWMgbG9jay1kaXJlY3RvcnkgY3JlYXRpb24sXG4gKiAgICBoZWFydGJlYXQsIHN0YWxlIHJlY292ZXJ5LCBhbmQgb3duZXJzaGlwLXNhZmUgcmVsZWFzZS4gQnVuIGFuZCBOb2RlIHVzZVxuICogICAgdGhpcyBzYW1lIHByb3RvY29sLlxuICogMi4gKipmbG9jayoqIChleHBsaWNpdCBjb21wYXRpYmlsaXR5IG9wdGlvbikg4oCUIGBmbG9jaygyKWAgdmlhIEJ1biBGRkkgb25cbiAqICAgIFVuaXguIEl0IHJlbWFpbnMgYXZhaWxhYmxlIHRvIGNhbGxlcnMgdGhhdCBzZWxlY3RlZCBpdCBleHBsaWNpdGx5LCBidXQgYVxuICogICAgcnVudGltZS1kZXBlbmRlbnQgY2FzY2FkZSBjYW5ub3QgY29vcmRpbmF0ZSBCdW4gYW5kIE5vZGUuXG4gKlxuICogVGhlIGZpcnN0IGJhY2tlbmQgdGhhdCBjYW4gYmUgKmluaXRpYWxpemVkKiBpcyB1c2VkIGZvciB0aGUgd2hvbGUgY2FsbC4gQSBidXN5XG4gKiBsb2NrIHdhaXRzOyBhbiB1bmF2YWlsYWJsZSBiYWNrZW5kIGZhbGxzIHRocm91Z2ggdG8gdGhlIG5leHQuIENhbGxlcnMgbWF5IG9ubHlcbiAqIGJvdW5kIGhvdyBsb25nIHRvIHdhaXQgKHtAbGluayBGaWxlTG9ja09wdGlvbnMudGltZW91dE1zfSk7IHN0YWxlIHRpbWluZyBpc1xuICogbm90IGNvbmZpZ3VyYWJsZSBzbyBldmVyeSBob2xkZXIgYW5kIHdhaXRlciBhZ3JlZXMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IG1rZGlyLCBvcGVuIH0gZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG5pbXBvcnQgeyBhc3luYywgZXJyb3IsIGZ1bmN0aW9uTW9kdWxlLCBoYXNoLCBsb2csIG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgbG9ja2ZpbGUgZnJvbSBcInByb3Blci1sb2NrZmlsZVwiO1xuXG5jb25zdCBsb2dnZXIgPSBsb2cubG9nZ2VyKFwiY29yZTpmaWxlLWxvY2tcIik7XG5cbi8qKiBCYWNrZW5kcyB7QGxpbmsgd2l0aEZpbGVMb2NrfSBjYW4gYXR0ZW1wdCwgaW4gY2FzY2FkZSBvcmRlci4gKi9cbmV4cG9ydCB0eXBlIEZpbGVMb2NrQmFja2VuZCA9IFwiZmxvY2tcIiB8IFwiZmlsZVwiO1xuXG5jb25zdCBERUZBVUxUX0JBQ0tFTkRTOiByZWFkb25seSBGaWxlTG9ja0JhY2tlbmRbXSA9IFtcImZpbGVcIl07XG5cbi8qKiBQb2xsIGludGVydmFsIHdoaWxlIHdhaXRpbmcgZm9yIGEgY29udGVuZGVkIE9TIGxvY2suICovXG5jb25zdCBQT0xMX01TID0gNTA7XG5cbi8qKlxuICogQWdlIGFmdGVyIHdoaWNoIGFuIHVucmVmcmVzaGVkIGxvY2sgZGlyZWN0b3J5IG1heSBiZSByZW1vdmVkLlxuICogTWF0Y2hlcyBgcHJvcGVyLWxvY2tmaWxlYCdzIGRlZmF1bHQuIE5vdCBjYWxsZXItY29uZmlndXJhYmxlOiBldmVyeSBwcm9jZXNzXG4gKiBtdXN0IHNoYXJlIHRoZSBzYW1lIHRocmVzaG9sZCBvciBhIGxpdmUgaG9sZGVyIGNhbiBiZSBtaXN0YWtlbiBmb3Igc3RhbGUuXG4gKi9cbmNvbnN0IFNUQUxFX01TID0gb2JqZWN0LnRvTnVtYmVyKHByb2Nlc3MuZW52LkZJTEVfTE9DS19TVEFMRV9NUykgPz8gMTBfMDAwO1xuXG4vKiogSGVhcnRiZWF0IGludGVydmFsIGZvciByZWZyZXNoaW5nIGxvY2stZGlyZWN0b3J5IG10aW1lIChgU1RBTEVfTVMgLyAyYCkuICovXG5jb25zdCBVUERBVEVfTVMgPSBvYmplY3QudG9OdW1iZXIocHJvY2Vzcy5lbnYuRklMRV9MT0NLX1VQREFURV9NUykgPz8gU1RBTEVfTVMgLyAyO1xuXG4vKiogYGZsb2NrKDIpYCBvcGVyYXRpb24gYml0cyAoTGludXggLyBtYWNPUyAvIEJTRCkuICovXG5jb25zdCBMT0NLX0VYID0gMjtcbmNvbnN0IExPQ0tfTkIgPSA0O1xuY29uc3QgTE9DS19VTiA9IDg7XG5cbi8qKiBSZXN1bHQgbWV0YWRhdGEgd2hlbiBhIGNhbGxlciB3YW50cyB0byBrbm93IHdoaWNoIGJhY2tlbmQgcmFuLiAqL1xuZXhwb3J0IGludGVyZmFjZSBGaWxlTG9ja0FjcXVpc2l0aW9uIHtcbiAgYmFja2VuZDogRmlsZUxvY2tCYWNrZW5kO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEZpbGVMb2NrT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBEaXJlY3RvcnkgZm9yIGxvY2tmaWxlcy4gRGVmYXVsdHMgdG8gYCRUTVBESVIvZGJ4LXRvb2xzLWxvY2tzYC5cbiAgICovXG4gIGRpcj86IHN0cmluZztcbiAgLyoqIE92ZXJyaWRlIHRoZSBiYWNrZW5kIGxpc3QuIERlZmF1bHRzIHRvIHRoZSBwb3J0YWJsZSBgZmlsZWAgcHJvdG9jb2wuICovXG4gIGJhY2tlbmRzPzogcmVhZG9ubHkgRmlsZUxvY2tCYWNrZW5kW107XG4gIC8qKlxuICAgKiBTdG9wIHdhaXRpbmcgYW5kIHRocm93IGFmdGVyIHRoaXMgbWFueSBtaWxsaXNlY29uZHMuIE9taXQgdG8gcG9sbCBmb3JldmVyLlxuICAgKiBUaGlzIGlzIHRoZSBvbmx5IHdhaXQtbG9vcCBrbm9iOyBzdGFsZSByZWNsYWltIHRpbWluZyBpcyBmaXhlZC5cbiAgICovXG4gIHRpbWVvdXRNcz86IG51bWJlcjtcbiAgLyoqIEludm9rZWQgb25jZSB0aGUgYmFja2VuZCBmb3IgdGhpcyBjYWxsIGhhcyBiZWVuIGNob3Nlbi4gKi9cbiAgb25BY3F1aXJlPzogKGFjcXVpc2l0aW9uOiBGaWxlTG9ja0FjcXVpc2l0aW9uKSA9PiB2b2lkO1xufVxuXG50eXBlIEZsb2NrRm4gPSAoZmQ6IG51bWJlciwgb3BlcmF0aW9uOiBudW1iZXIpID0+IG51bWJlcjtcblxuaW50ZXJmYWNlIEJ1bkZmaU1vZHVsZSB7XG4gIGRsb3BlbjogKFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBzeW1ib2xzOiBSZWNvcmQ8c3RyaW5nLCB7IGFyZ3M6IHN0cmluZ1tdOyByZXR1cm5zOiBzdHJpbmcgfT4sXG4gICkgPT4geyBzeW1ib2xzOiB7IGZsb2NrOiBGbG9ja0ZuIH0gfTtcbiAgc3VmZml4OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUnVuIGBmbmAgd2hpbGUgaG9sZGluZyBhIGNyb3NzLXByb2Nlc3MgbG9jayBuYW1lZCBieSBga2V5YC5cbiAqXG4gKiBga2V5YCBpcyBjYW5vbmljYWxpemVkIHdpdGggYG9iamVjdC50b1N0YWJsZUtleWAsIHRoZSBzYW1lIGlkZW50aXR5IHJ1bGUgYXNcbiAqIHByb2Nlc3MgYW5kIFBvc3RncmVzIGFkdmlzb3J5IGxvY2tzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBhd2FpdCB3aXRoRmlsZUxvY2soW1wiY2FjaGVcIiwgXCJhcHBraXRcIl0sIGFzeW5jICgpID0+IHtcbiAqICAgYXdhaXQgbWlncmF0ZSgpO1xuICogfSk7XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3aXRoRmlsZUxvY2s8VD4oXG4gIGtleTogdW5rbm93bixcbiAgZm46ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuICBvcHRpb25zOiBGaWxlTG9ja09wdGlvbnMgPSB7fSxcbik6IFByb21pc2U8VD4ge1xuICBpZiAob3B0aW9ucy50aW1lb3V0TXMgIT09IHVuZGVmaW5lZCAmJiBvcHRpb25zLnRpbWVvdXRNcyA8IDApIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwidGltZW91dE1zIG11c3QgYmUgbm9uLW5lZ2F0aXZlXCIpO1xuICB9XG4gIGNvbnN0IGlkID0gbG9ja0lkKGtleSk7XG4gIGNvbnN0IGJhY2tlbmRzID0gb3B0aW9ucy5iYWNrZW5kcyA/PyBERUZBVUxUX0JBQ0tFTkRTO1xuICBjb25zdCBkaXIgPSBvcHRpb25zLmRpciA/PyBqb2luKHRtcGRpcigpLCBcImRieC10b29scy1sb2Nrc1wiKTtcbiAgY29uc3QgZGVhZGxpbmUgPSBvcHRpb25zLnRpbWVvdXRNcyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogRGF0ZS5ub3coKSArIG9wdGlvbnMudGltZW91dE1zO1xuXG4gIGZvciAoY29uc3QgYmFja2VuZCBvZiBiYWNrZW5kcykge1xuICAgIHN3aXRjaCAoYmFja2VuZCkge1xuICAgICAgY2FzZSBcImZsb2NrXCI6IHtcbiAgICAgICAgY29uc3QgbG9ja1BhdGggPSBqb2luKGRpciwgYCR7aWR9LmZsb2NrYCk7XG4gICAgICAgIGNvbnN0IGZsb2NrID0gYXdhaXQgcmVzb2x2ZUZsb2NrKCk7XG4gICAgICAgIGlmICghZmxvY2spIHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoXCJsb2NrIGJhY2tlbmQgdW5hdmFpbGFibGVcIiwgeyBiYWNrZW5kLCBrZXk6IGlkIH0pO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcImFjcXVpcmluZyBsb2NrXCIsIHsgYmFja2VuZCwga2V5OiBpZCwgcGF0aDogbG9ja1BhdGggfSk7XG4gICAgICAgIG9wdGlvbnMub25BY3F1aXJlPy4oeyBiYWNrZW5kIH0pO1xuICAgICAgICByZXR1cm4gaG9sZEZsb2NrKGxvY2tQYXRoLCBmbG9jaywgZGVhZGxpbmUsIGZuKTtcbiAgICAgIH1cbiAgICAgIGNhc2UgXCJmaWxlXCI6IHtcbiAgICAgICAgY29uc3QgbG9ja1BhdGggPSBqb2luKGRpciwgaWQpO1xuICAgICAgICBsb2dnZXIuZGVidWcoXCJhY3F1aXJpbmcgbG9ja1wiLCB7IGJhY2tlbmQsIGtleTogaWQsIHBhdGg6IGxvY2tQYXRoIH0pO1xuICAgICAgICBvcHRpb25zLm9uQWNxdWlyZT8uKHsgYmFja2VuZCB9KTtcbiAgICAgICAgcmV0dXJuIGhvbGRMb2NrRGlyZWN0b3J5KGxvY2tQYXRoLCBkZWFkbGluZSwgZm4pO1xuICAgICAgfVxuICAgICAgZGVmYXVsdDoge1xuICAgICAgICBjb25zdCBfZXhoYXVzdGl2ZTogbmV2ZXIgPSBiYWNrZW5kO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVua25vd24gZmlsZS1sb2NrIGJhY2tlbmQ6ICR7U3RyaW5nKF9leGhhdXN0aXZlKX1gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB0aHJvdyBuZXcgRXJyb3IoXCJ3aXRoRmlsZUxvY2s6IG5vIGxvY2sgYmFja2VuZCBhdmFpbGFibGVcIik7XG59XG5cbi8qKiBDYW5vbmljYWwgZmlsZXN5c3RlbS1zYWZlIGlkIGZvciBhIGxvY2sga2V5LiAqL1xuZnVuY3Rpb24gbG9ja0lkKGtleTogdW5rbm93bik6IHN0cmluZyB7XG4gIGNvbnN0IHN0YWJsZSA9IG9iamVjdFxuICAgIC50b09uZU9yTWFueShrZXkpXG4gICAgLm1hcCgocGFydCkgPT4gb2JqZWN0LnRvU3RhYmxlS2V5KHBhcnQpKVxuICAgIC5qb2luKFwiXFx1MDAwMFwiKTtcbiAgLy8gU2hvcnQgZGlnZXN0IHNvIHBhdGhzIHN0YXkgd2VsbCB1bmRlciBPUyBsaW1pdHM7IGNvbGxpc2lvbnMgYXJlIGZpbmUg4oCUIHRoZXlcbiAgLy8gb25seSBtZXJnZSBjcml0aWNhbCBzZWN0aW9ucyB0aGF0IGFscmVhZHkgc2hhcmVkIGEga2V5IHN0cmluZy5cbiAgcmV0dXJuIGhhc2guZm52SGFzaChzdGFibGUpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYGZsb2NrKDIpYCB0aHJvdWdoIEJ1biBGRkkgd2hlbiBwb3NzaWJsZS5cbiAqXG4gKiBNZW1vaXplZDogdGhlIEZGSSBpbXBvcnQgKyBsaWJjIGBkbG9wZW5gIHJ1biBvbmNlIHBlciBwcm9jZXNzLiBSZXR1cm5zXG4gKiBgdW5kZWZpbmVkYCBvbiBXaW5kb3dzLCB1bmRlciBwbGFpbiBOb2RlLCBvciB3aGVuIGxpYmMgY2Fubm90IGJlIGxvYWRlZCDigJRcbiAqIGNhbGxlcnMgZmFsbCB0aHJvdWdoIHRvIHRoZSBuZXh0IGJhY2tlbmQuIEEgbWlzcyBpcyBjYWNoZWQgdG9vLCBzbyBhIHByb2Nlc3NcbiAqIHRoYXQgY2Fubm90IGZsb2NrIG5ldmVyIHJldHJpZXMgdGhlIGxvYWQuXG4gKi9cbmNvbnN0IHJlc29sdmVGbG9jayA9IGZ1bmN0aW9uTW9kdWxlLm1lbW9pemUoYXN5bmMgKCk6IFByb21pc2U8RmxvY2tGbiB8IHVuZGVmaW5lZD4gPT4ge1xuICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gXCJ3aW4zMlwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICBpZiAoIXByb2Nlc3MudmVyc2lvbnMuYnVuKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIHRyeSB7XG4gICAgLy8gRHluYW1pYyBzcGVjaWZpZXIgc28gYHRzY2AgKG5vIGBAdHlwZXNgIGZvciBgYnVuOmZmaWApIGRvZXMgbm90IHJlc29sdmUgaXQ7XG4gICAgLy8gdGhlIGltcG9ydCBvbmx5IHN1Y2NlZWRzIHVuZGVyIEJ1biBhdCBydW50aW1lLlxuICAgIGNvbnN0IHNwZWNpZmllciA9IFwiYnVuOmZmaVwiO1xuICAgIGNvbnN0IGZmaSA9IChhd2FpdCBpbXBvcnQoc3BlY2lmaWVyKSkgYXMgdW5rbm93biBhcyBCdW5GZmlNb2R1bGU7XG4gICAgY29uc3QgbGliUGF0aCA9IHByb2Nlc3MucGxhdGZvcm0gPT09IFwiZGFyd2luXCIgPyBcImxpYlN5c3RlbS5CLmR5bGliXCIgOiBgbGliYy4ke2ZmaS5zdWZmaXh9YDtcbiAgICBjb25zdCBsaWIgPSBmZmkuZGxvcGVuKGxpYlBhdGgsIHtcbiAgICAgIGZsb2NrOiB7IGFyZ3M6IFtcImkzMlwiLCBcImkzMlwiXSwgcmV0dXJuczogXCJpMzJcIiB9LFxuICAgIH0pO1xuICAgIHJldHVybiBsaWIuc3ltYm9scy5mbG9jaztcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJmbG9jayBGRkkgdW5hdmFpbGFibGVcIiwgeyBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGNhdXNlKSB9KTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59KTtcblxuYXN5bmMgZnVuY3Rpb24gaG9sZEZsb2NrPFQ+KFxuICBsb2NrUGF0aDogc3RyaW5nLFxuICBmbG9jazogRmxvY2tGbixcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgZm46ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuKTogUHJvbWlzZTxUPiB7XG4gIGF3YWl0IGVuc3VyZVBhcmVudERpcihsb2NrUGF0aCk7XG4gIGNvbnN0IGhhbmRsZSA9IGF3YWl0IG9wZW4obG9ja1BhdGgsIFwiYStcIik7XG4gIHRyeSB7XG4gICAgYXdhaXQgd2FpdEZvckZsb2NrKGhhbmRsZS5mZCwgZmxvY2ssIGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBmbigpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBmbG9jayhoYW5kbGUuZmQsIExPQ0tfVU4pO1xuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBoYW5kbGUuY2xvc2UoKS5jYXRjaCgoKSA9PiB7fSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gd2FpdEZvckZsb2NrKFxuICBmZDogbnVtYmVyLFxuICBmbG9jazogRmxvY2tGbixcbiAgbG9ja1BhdGg6IHN0cmluZyxcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbik6IFByb21pc2U8dm9pZD4ge1xuICBmb3IgKDs7KSB7XG4gICAgY29uc3QgcmMgPSBmbG9jayhmZCwgTE9DS19FWCB8IExPQ0tfTkIpO1xuICAgIGlmIChyYyA9PT0gMCkgcmV0dXJuO1xuICAgIGFzc2VydEJlZm9yZURlYWRsaW5lKGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgYXdhaXQgYXN5bmMuc2xlZXAoUE9MTF9NUyk7XG4gIH1cbn1cblxuLyoqXG4gKiBQb3J0YWJsZSBsb2NrLWRpcmVjdG9yeSBvd25lcnNoaXAgdGhyb3VnaCBgcHJvcGVyLWxvY2tmaWxlYC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaG9sZExvY2tEaXJlY3Rvcnk8VD4oXG4gIGxvY2tQYXRoOiBzdHJpbmcsXG4gIGRlYWRsaW5lOiBudW1iZXIgfCB1bmRlZmluZWQsXG4gIGZuOiAoKSA9PiBUIHwgUHJvbWlzZTxUPixcbik6IFByb21pc2U8VD4ge1xuICBhd2FpdCBlbnN1cmVQYXJlbnREaXIobG9ja1BhdGgpO1xuICBjb25zdCByZWxlYXNlID0gYXdhaXQgYWNxdWlyZUxvY2tEaXJlY3RvcnkobG9ja1BhdGgsIGRlYWRsaW5lKTtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgZm4oKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCByZWxlYXNlKCk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gYWNxdWlyZUxvY2tEaXJlY3RvcnkoXG4gIGxvY2tQYXRoOiBzdHJpbmcsXG4gIGRlYWRsaW5lOiBudW1iZXIgfCB1bmRlZmluZWQsXG4pOiBQcm9taXNlPCgpID0+IFByb21pc2U8dm9pZD4+IHtcbiAgZm9yICg7Oykge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgbG9ja2ZpbGUubG9jayhsb2NrUGF0aCwge1xuICAgICAgICByZWFscGF0aDogZmFsc2UsXG4gICAgICAgIHN0YWxlOiBTVEFMRV9NUyxcbiAgICAgICAgdXBkYXRlOiBVUERBVEVfTVMsXG4gICAgICAgIHJldHJpZXM6IDAsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgY29uc3QgZXJyID0gY2F1c2UgYXMgTm9kZUpTLkVycm5vRXhjZXB0aW9uO1xuICAgICAgaWYgKGVyci5jb2RlICE9PSBcIkVMT0NLRURcIikgdGhyb3cgZXJyb3IudG9FcnJvcihjYXVzZSk7XG4gICAgICBhc3NlcnRCZWZvcmVEZWFkbGluZShsb2NrUGF0aCwgZGVhZGxpbmUpO1xuICAgICAgYXdhaXQgYXN5bmMuc2xlZXAoUE9MTF9NUyk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGFzc2VydEJlZm9yZURlYWRsaW5lKGxvY2tQYXRoOiBzdHJpbmcsIGRlYWRsaW5lOiBudW1iZXIgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgaWYgKGRlYWRsaW5lICE9PSB1bmRlZmluZWQgJiYgRGF0ZS5ub3coKSA+PSBkZWFkbGluZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgVGltZWQgb3V0IHdhaXRpbmcgZm9yIGZpbGUgbG9jazogJHtsb2NrUGF0aH1gKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVQYXJlbnREaXIobG9ja1BhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBhd2FpdCBta2RpcihkaXJuYW1lKGxvY2tQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG59XG4iXX0=
|
package/package.json
CHANGED
|
@@ -21,11 +21,13 @@
|
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/bun": "1.3.14",
|
|
23
23
|
"@types/node": "^24.6.0",
|
|
24
|
+
"@types/proper-lockfile": "^4.1.4",
|
|
24
25
|
"typescript": "^5.9.3"
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"@dbx-tools/shared-core": "0.6.
|
|
28
|
+
"@dbx-tools/shared-core": "0.6.224",
|
|
28
29
|
"extract-zip": "^2.0.1",
|
|
30
|
+
"proper-lockfile": "^4.1.2",
|
|
29
31
|
"tar": "^7.5.22",
|
|
30
32
|
"yaml": "^2.9.0",
|
|
31
33
|
"zod": "4.3.6"
|
|
@@ -44,7 +46,7 @@
|
|
|
44
46
|
"./package.json": "./package.json"
|
|
45
47
|
}
|
|
46
48
|
},
|
|
47
|
-
"version": "0.6.
|
|
49
|
+
"version": "0.6.224",
|
|
48
50
|
"types": "./lib/index.d.ts",
|
|
49
51
|
"type": "module",
|
|
50
52
|
"exports": {
|
package/src/file-lock.ts
CHANGED
|
@@ -5,16 +5,14 @@
|
|
|
5
5
|
* server) on the same key. For in-process / worker-thread exclusion use
|
|
6
6
|
* {@link withProcessLock} from `./process-lock.ts` instead.
|
|
7
7
|
*
|
|
8
|
-
* Backends
|
|
8
|
+
* Backends:
|
|
9
9
|
*
|
|
10
|
-
* 1. **
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* 2. **
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* always on (fixed {@link STALE_MS} + heartbeat) so a crashed holder on this
|
|
17
|
-
* backend can be reclaimed.
|
|
10
|
+
* 1. **file** (default) — `proper-lockfile` atomic lock-directory creation,
|
|
11
|
+
* heartbeat, stale recovery, and ownership-safe release. Bun and Node use
|
|
12
|
+
* this same protocol.
|
|
13
|
+
* 2. **flock** (explicit compatibility option) — `flock(2)` via Bun FFI on
|
|
14
|
+
* Unix. It remains available to callers that selected it explicitly, but a
|
|
15
|
+
* runtime-dependent cascade cannot coordinate Bun and Node.
|
|
18
16
|
*
|
|
19
17
|
* The first backend that can be *initialized* is used for the whole call. A busy
|
|
20
18
|
* lock waits; an unavailable backend falls through to the next. Callers may only
|
|
@@ -24,18 +22,19 @@
|
|
|
24
22
|
* @module
|
|
25
23
|
*/
|
|
26
24
|
|
|
27
|
-
import { mkdir, open
|
|
25
|
+
import { mkdir, open } from "node:fs/promises";
|
|
28
26
|
import { tmpdir } from "node:os";
|
|
29
27
|
import { dirname, join } from "node:path";
|
|
30
28
|
|
|
31
29
|
import { async, error, functionModule, hash, log, object } from "@dbx-tools/shared-core";
|
|
30
|
+
import lockfile from "proper-lockfile";
|
|
32
31
|
|
|
33
32
|
const logger = log.logger("core:file-lock");
|
|
34
33
|
|
|
35
34
|
/** Backends {@link withFileLock} can attempt, in cascade order. */
|
|
36
35
|
export type FileLockBackend = "flock" | "file";
|
|
37
36
|
|
|
38
|
-
const DEFAULT_BACKENDS: readonly FileLockBackend[] = ["
|
|
37
|
+
const DEFAULT_BACKENDS: readonly FileLockBackend[] = ["file"];
|
|
39
38
|
|
|
40
39
|
/** Poll interval while waiting for a contended OS lock. */
|
|
41
40
|
const POLL_MS = 50;
|
|
@@ -65,7 +64,7 @@ export interface FileLockOptions {
|
|
|
65
64
|
* Directory for lockfiles. Defaults to `$TMPDIR/dbx-tools-locks`.
|
|
66
65
|
*/
|
|
67
66
|
dir?: string;
|
|
68
|
-
/** Override the
|
|
67
|
+
/** Override the backend list. Defaults to the portable `file` protocol. */
|
|
69
68
|
backends?: readonly FileLockBackend[];
|
|
70
69
|
/**
|
|
71
70
|
* Stop waiting and throw after this many milliseconds. Omit to poll forever.
|
|
@@ -124,7 +123,7 @@ export async function withFileLock<T>(
|
|
|
124
123
|
return holdFlock(lockPath, flock, deadline, fn);
|
|
125
124
|
}
|
|
126
125
|
case "file": {
|
|
127
|
-
const lockPath = join(dir,
|
|
126
|
+
const lockPath = join(dir, id);
|
|
128
127
|
logger.debug("acquiring lock", { backend, key: id, path: lockPath });
|
|
129
128
|
options.onAcquire?.({ backend });
|
|
130
129
|
return holdLockDirectory(lockPath, deadline, fn);
|
|
@@ -213,12 +212,7 @@ async function waitForFlock(
|
|
|
213
212
|
}
|
|
214
213
|
|
|
215
214
|
/**
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* `mkdir` is the same primitive used by `proper-lockfile`: it is atomic across
|
|
219
|
-
* supported local and network filesystems. The holder refreshes mtime on a fixed
|
|
220
|
-
* heartbeat so a live long-running lock is never reclaimed; a crashed holder's
|
|
221
|
-
* directory becomes reclaimable after {@link STALE_MS}.
|
|
215
|
+
* Portable lock-directory ownership through `proper-lockfile`.
|
|
222
216
|
*/
|
|
223
217
|
async function holdLockDirectory<T>(
|
|
224
218
|
lockPath: string,
|
|
@@ -226,58 +220,35 @@ async function holdLockDirectory<T>(
|
|
|
226
220
|
fn: () => T | Promise<T>,
|
|
227
221
|
): Promise<T> {
|
|
228
222
|
await ensureParentDir(lockPath);
|
|
229
|
-
await acquireLockDirectory(lockPath, deadline);
|
|
230
|
-
const stopHeartbeat = startHeartbeat(lockPath);
|
|
223
|
+
const release = await acquireLockDirectory(lockPath, deadline);
|
|
231
224
|
try {
|
|
232
225
|
return await fn();
|
|
233
226
|
} finally {
|
|
234
|
-
|
|
235
|
-
await rm(lockPath, { recursive: true, force: true }).catch(() => {});
|
|
227
|
+
await release();
|
|
236
228
|
}
|
|
237
229
|
}
|
|
238
230
|
|
|
239
|
-
async function acquireLockDirectory(
|
|
231
|
+
async function acquireLockDirectory(
|
|
232
|
+
lockPath: string,
|
|
233
|
+
deadline: number | undefined,
|
|
234
|
+
): Promise<() => Promise<void>> {
|
|
240
235
|
for (;;) {
|
|
241
236
|
try {
|
|
242
|
-
await
|
|
243
|
-
|
|
237
|
+
return await lockfile.lock(lockPath, {
|
|
238
|
+
realpath: false,
|
|
239
|
+
stale: STALE_MS,
|
|
240
|
+
update: UPDATE_MS,
|
|
241
|
+
retries: 0,
|
|
242
|
+
});
|
|
244
243
|
} catch (cause) {
|
|
245
244
|
const err = cause as NodeJS.ErrnoException;
|
|
246
|
-
if (err.code !== "
|
|
247
|
-
await maybeReclaimStale(lockPath);
|
|
245
|
+
if (err.code !== "ELOCKED") throw error.toError(cause);
|
|
248
246
|
assertBeforeDeadline(lockPath, deadline);
|
|
249
247
|
await async.sleep(POLL_MS);
|
|
250
248
|
}
|
|
251
249
|
}
|
|
252
250
|
}
|
|
253
251
|
|
|
254
|
-
async function maybeReclaimStale(lockPath: string): Promise<void> {
|
|
255
|
-
try {
|
|
256
|
-
const { mtimeMs } = await stat(lockPath);
|
|
257
|
-
const age = Date.now() - mtimeMs;
|
|
258
|
-
if (age < STALE_MS) return;
|
|
259
|
-
logger.debug("reclaiming stale lock directory", { path: lockPath, ageMs: age });
|
|
260
|
-
await rm(lockPath, { recursive: true, force: true });
|
|
261
|
-
} catch (cause) {
|
|
262
|
-
const err = cause as NodeJS.ErrnoException;
|
|
263
|
-
if (err.code !== "ENOENT") throw error.toError(cause);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function startHeartbeat(lockPath: string): () => void {
|
|
268
|
-
const timer = setInterval(() => {
|
|
269
|
-
const now = new Date();
|
|
270
|
-
void utimes(lockPath, now, now).catch((cause) => {
|
|
271
|
-
logger.warn("file lock heartbeat failed", {
|
|
272
|
-
path: lockPath,
|
|
273
|
-
error: error.errorMessage(cause),
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
}, UPDATE_MS);
|
|
277
|
-
timer.unref();
|
|
278
|
-
return () => clearInterval(timer);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
252
|
function assertBeforeDeadline(lockPath: string, deadline: number | undefined): void {
|
|
282
253
|
if (deadline !== undefined && Date.now() >= deadline) {
|
|
283
254
|
throw new Error(`Timed out waiting for file lock: ${lockPath}`);
|