@dbx-tools/core 0.6.70 → 0.6.72

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.
@@ -12,11 +12,14 @@
12
12
  * Kernel releases the lock when the fd closes (including process death).
13
13
  * 2. **file** — atomic lock-directory creation. This is the strategy used by
14
14
  * `proper-lockfile`: `mkdir` is atomic on Windows, Unix, and network file
15
- * systems where `open(..., "wx")` may not be reliable. Optional stale
16
- * detection uses the directory mtime plus a heartbeat.
15
+ * systems where `open(..., "wx")` may not be reliable. Stale detection is
16
+ * always on (fixed {@link STALE_MS} + heartbeat) so a crashed holder on this
17
+ * backend can be reclaimed.
17
18
  *
18
19
  * The first backend that can be *initialized* is used for the whole call. A busy
19
- * lock waits; an unavailable backend falls through to the next.
20
+ * lock waits; an unavailable backend falls through to the next. Callers may only
21
+ * bound how long to wait ({@link FileLockOptions.timeoutMs}); stale timing is
22
+ * not configurable so every holder and waiter agrees.
20
23
  *
21
24
  * @module
22
25
  */
@@ -35,18 +38,9 @@ export interface FileLockOptions {
35
38
  backends?: readonly FileLockBackend[];
36
39
  /**
37
40
  * Stop waiting and throw after this many milliseconds. Omit to poll forever.
41
+ * This is the only wait-loop knob; stale reclaim timing is fixed.
38
42
  */
39
43
  timeoutMs?: number;
40
- /**
41
- * Age after which an unrefreshed lock directory may be removed. Omit to
42
- * disable stale detection. Only used by the `file` backend.
43
- */
44
- staleMs?: number;
45
- /**
46
- * Interval for refreshing the lock directory mtime when `staleMs` is set.
47
- * Defaults to half of `staleMs`.
48
- */
49
- updateMs?: number;
50
44
  /** Invoked once the backend for this call has been chosen. */
51
45
  onAcquire?: (acquisition: FileLockAcquisition) => void;
52
46
  }
@@ -12,11 +12,14 @@
12
12
  * Kernel releases the lock when the fd closes (including process death).
13
13
  * 2. **file** — atomic lock-directory creation. This is the strategy used by
14
14
  * `proper-lockfile`: `mkdir` is atomic on Windows, Unix, and network file
15
- * systems where `open(..., "wx")` may not be reliable. Optional stale
16
- * detection uses the directory mtime plus a heartbeat.
15
+ * systems where `open(..., "wx")` may not be reliable. Stale detection is
16
+ * always on (fixed {@link STALE_MS} + heartbeat) so a crashed holder on this
17
+ * backend can be reclaimed.
17
18
  *
18
19
  * The first backend that can be *initialized* is used for the whole call. A busy
19
- * lock waits; an unavailable backend falls through to the next.
20
+ * lock waits; an unavailable backend falls through to the next. Callers may only
21
+ * bound how long to wait ({@link FileLockOptions.timeoutMs}); stale timing is
22
+ * not configurable so every holder and waiter agrees.
20
23
  *
21
24
  * @module
22
25
  */
@@ -36,6 +39,14 @@ const logger = log.logger("core:file-lock");
36
39
  const DEFAULT_BACKENDS = ["flock", "file"];
37
40
  /** Poll interval while waiting for a contended OS lock. */
38
41
  const POLL_MS = 50;
42
+ /**
43
+ * Age after which an unrefreshed lock directory may be removed.
44
+ * Matches `proper-lockfile`'s default. Not caller-configurable: every process
45
+ * must share the same threshold or a live holder can be mistaken for stale.
46
+ */
47
+ const STALE_MS = object.toNumber(process.env.FILE_LOCK_STALE_MS) ?? 10_000;
48
+ /** Heartbeat interval for refreshing lock-directory mtime (`STALE_MS / 2`). */
49
+ const UPDATE_MS = object.toNumber(process.env.FILE_LOCK_UPDATE_MS) ?? STALE_MS / 2;
39
50
  /** `flock(2)` operation bits (Linux / macOS / BSD). */
40
51
  const LOCK_EX = 2;
41
52
  const LOCK_NB = 4;
@@ -52,7 +63,9 @@ const LOCK_UN = 8;
52
63
  * });
53
64
  */
54
65
  export async function withFileLock(key, fn, options = {}) {
55
- validateOptions(options);
66
+ if (options.timeoutMs !== undefined && options.timeoutMs < 0) {
67
+ throw new TypeError("timeoutMs must be non-negative");
68
+ }
56
69
  const id = lockId(key);
57
70
  const backends = options.backends ?? DEFAULT_BACKENDS;
58
71
  const dir = options.dir ?? join(tmpdir(), "dbx-tools-locks");
@@ -74,7 +87,7 @@ export async function withFileLock(key, fn, options = {}) {
74
87
  const lockPath = join(dir, `${id}.lock`);
75
88
  logger.debug("acquiring lock", { backend, key: id, path: lockPath });
76
89
  options.onAcquire?.({ backend });
77
- return holdLockDirectory(lockPath, deadline, options.staleMs, options.updateMs, fn);
90
+ return holdLockDirectory(lockPath, deadline, fn);
78
91
  }
79
92
  default: {
80
93
  const _exhaustive = backend;
@@ -84,22 +97,6 @@ export async function withFileLock(key, fn, options = {}) {
84
97
  }
85
98
  throw new Error("withFileLock: no lock backend available");
86
99
  }
87
- function validateOptions(options) {
88
- if (options.timeoutMs !== undefined && options.timeoutMs < 0) {
89
- throw new TypeError("timeoutMs must be non-negative");
90
- }
91
- if (options.staleMs !== undefined && options.staleMs <= 0) {
92
- throw new TypeError("staleMs must be positive");
93
- }
94
- if (options.updateMs !== undefined) {
95
- if (options.staleMs === undefined) {
96
- throw new TypeError("updateMs requires staleMs");
97
- }
98
- if (options.updateMs <= 0 || options.updateMs > options.staleMs / 2) {
99
- throw new TypeError("updateMs must be positive and no greater than half of staleMs");
100
- }
101
- }
102
- }
103
100
  /** Canonical filesystem-safe id for a lock key. */
104
101
  function lockId(key) {
105
102
  const stable = object
@@ -168,13 +165,14 @@ async function waitForFlock(fd, flock, lockPath, deadline) {
168
165
  * Atomic lock-directory creation — the portable / Windows path.
169
166
  *
170
167
  * `mkdir` is the same primitive used by `proper-lockfile`: it is atomic across
171
- * supported local and network filesystems. When stale detection is enabled,
172
- * the holder refreshes mtime so a live long-running lock is never reclaimed.
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}.
173
171
  */
174
- async function holdLockDirectory(lockPath, deadline, staleMs, updateMs, fn) {
172
+ async function holdLockDirectory(lockPath, deadline, fn) {
175
173
  await ensureParentDir(lockPath);
176
- await acquireLockDirectory(lockPath, deadline, staleMs);
177
- const stopHeartbeat = startHeartbeat(lockPath, staleMs, updateMs);
174
+ await acquireLockDirectory(lockPath, deadline);
175
+ const stopHeartbeat = startHeartbeat(lockPath);
178
176
  try {
179
177
  return await fn();
180
178
  }
@@ -183,7 +181,7 @@ async function holdLockDirectory(lockPath, deadline, staleMs, updateMs, fn) {
183
181
  await rm(lockPath, { recursive: true, force: true }).catch(() => { });
184
182
  }
185
183
  }
186
- async function acquireLockDirectory(lockPath, deadline, staleMs) {
184
+ async function acquireLockDirectory(lockPath, deadline) {
187
185
  for (;;) {
188
186
  try {
189
187
  await mkdir(lockPath);
@@ -193,18 +191,17 @@ async function acquireLockDirectory(lockPath, deadline, staleMs) {
193
191
  const err = cause;
194
192
  if (err.code !== "EEXIST")
195
193
  throw error.toError(cause);
196
- if (staleMs !== undefined)
197
- await maybeReclaimStale(lockPath, staleMs);
194
+ await maybeReclaimStale(lockPath);
198
195
  assertBeforeDeadline(lockPath, deadline);
199
196
  await async.sleep(POLL_MS);
200
197
  }
201
198
  }
202
199
  }
203
- async function maybeReclaimStale(lockPath, staleMs) {
200
+ async function maybeReclaimStale(lockPath) {
204
201
  try {
205
202
  const { mtimeMs } = await stat(lockPath);
206
203
  const age = Date.now() - mtimeMs;
207
- if (age < staleMs)
204
+ if (age < STALE_MS)
208
205
  return;
209
206
  logger.debug("reclaiming stale lock directory", { path: lockPath, ageMs: age });
210
207
  await rm(lockPath, { recursive: true, force: true });
@@ -215,10 +212,7 @@ async function maybeReclaimStale(lockPath, staleMs) {
215
212
  throw error.toError(cause);
216
213
  }
217
214
  }
218
- function startHeartbeat(lockPath, staleMs, updateMs) {
219
- if (staleMs === undefined)
220
- return () => { };
221
- const intervalMs = updateMs ?? Math.max(1, Math.floor(staleMs / 2));
215
+ function startHeartbeat(lockPath) {
222
216
  const timer = setInterval(() => {
223
217
  const now = new Date();
224
218
  void utimes(lockPath, now, now).catch((cause) => {
@@ -227,7 +221,7 @@ function startHeartbeat(lockPath, staleMs, updateMs) {
227
221
  error: error.errorMessage(cause),
228
222
  });
229
223
  });
230
- }, intervalMs);
224
+ }, UPDATE_MS);
231
225
  timer.unref();
232
226
  return () => clearInterval(timer);
233
227
  }
@@ -239,4 +233,4 @@ function assertBeforeDeadline(lockPath, deadline) {
239
233
  async function ensureParentDir(lockPath) {
240
234
  await mkdir(dirname(lockPath), { recursive: true });
241
235
  }
242
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1sb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpbGUtbG9jay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHOzs7Ozs7Ozs7QUFFSCxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDakMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFMUMsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFekYsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBSzVDLE1BQU0sZ0JBQWdCLEdBQStCLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBRXZFLDJEQUEyRDtBQUMzRCxNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUM7QUFFbkIsdURBQXVEO0FBQ3ZELE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQztBQUNsQixNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUM7QUFDbEIsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0FBMENsQjs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxZQUFZLENBQ2hDLEdBQVksRUFDWixFQUF3QixFQUN4QixVQUEyQixFQUFFO0lBRTdCLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN6QixNQUFNLEVBQUUsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDdkIsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsSUFBSSxnQkFBZ0IsQ0FBQztJ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RSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ3RELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENhc2NhZGluZyBjcm9zcy1wcm9jZXNzIG11dHVhbCBleGNsdXNpb24gdmlhIGEgbG9ja2ZpbGUuXG4gKlxuICogU2VyaWFsaXplcyBjb25jdXJyZW50ICpwcm9jZXNzZXMqICh0d28gYGJ1biBydW4gZGVtb2Agc2hlbGxzLCBhIENMSSBiZXNpZGUgYVxuICogc2VydmVyKSBvbiB0aGUgc2FtZSBrZXkuIEZvciBpbi1wcm9jZXNzIC8gd29ya2VyLXRocmVhZCBleGNsdXNpb24gdXNlXG4gKiB7QGxpbmsgd2l0aFByb2Nlc3NMb2NrfSBmcm9tIGAuL3Byb2Nlc3MtbG9jay50c2AgaW5zdGVhZC5cbiAqXG4gKiBCYWNrZW5kcywgaW4gb3JkZXI6XG4gKlxuICogMS4gKipmbG9jayoqIOKAlCBgZmxvY2soMilgIHZpYSBCdW4gRkZJIG9uIFVuaXggd2hlbiBgYnVuOmZmaWAgY2FuIGxvYWQgbGliYy5cbiAqICAgIE5vdCBhdmFpbGFibGUgb24gV2luZG93cywgYW5kIG5vdCBhdmFpbGFibGUgdW5kZXIgcGxhaW4gTm9kZSAobm8gRkZJKS5cbiAqICAgIEtlcm5lbCByZWxlYXNlcyB0aGUgbG9jayB3aGVuIHRoZSBmZCBjbG9zZXMgKGluY2x1ZGluZyBwcm9jZXNzIGRlYXRoKS5cbiAqIDIuICoqZmlsZSoqIOKAlCBhdG9taWMgbG9jay1kaXJlY3RvcnkgY3JlYXRpb24uIFRoaXMgaXMgdGhlIHN0cmF0ZWd5IHVzZWQgYnlcbiAqICAgIGBwcm9wZXItbG9ja2ZpbGVgOiBgbWtkaXJgIGlzIGF0b21pYyBvbiBXaW5kb3dzLCBVbml4LCBhbmQgbmV0d29yayBmaWxlXG4gKiAgICBzeXN0ZW1zIHdoZXJlIGBvcGVuKC4uLiwgXCJ3eFwiKWAgbWF5IG5vdCBiZSByZWxpYWJsZS4gT3B0aW9uYWwgc3RhbGVcbiAqICAgIGRldGVjdGlvbiB1c2VzIHRoZSBkaXJlY3RvcnkgbXRpbWUgcGx1cyBhIGhlYXJ0YmVhdC5cbiAqXG4gKiBUaGUgZmlyc3QgYmFja2VuZCB0aGF0IGNhbiBiZSAqaW5pdGlhbGl6ZWQqIGlzIHVzZWQgZm9yIHRoZSB3aG9sZSBjYWxsLiBBIGJ1c3lcbiAqIGxvY2sgd2FpdHM7IGFuIHVuYXZhaWxhYmxlIGJhY2tlbmQgZmFsbHMgdGhyb3VnaCB0byB0aGUgbmV4dC5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgbWtkaXIsIG9wZW4sIHJtLCBzdGF0LCB1dGltZXMgfSBmcm9tIFwibm9kZTpmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSBcIm5vZGU6b3NcIjtcbmltcG9ydCB7IGRpcm5hbWUsIGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5cbmltcG9ydCB7IGFzeW5jLCBlcnJvciwgZnVuY3Rpb25Nb2R1bGUsIGhhc2gsIGxvZywgb2JqZWN0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcblxuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcImNvcmU6ZmlsZS1sb2NrXCIpO1xuXG4vKiogQmFja2VuZHMge0BsaW5rIHdpdGhGaWxlTG9ja30gY2FuIGF0dGVtcHQsIGluIGNhc2NhZGUgb3JkZXIuICovXG5leHBvcnQgdHlwZSBGaWxlTG9ja0JhY2tlbmQgPSBcImZsb2NrXCIgfCBcImZpbGVcIjtcblxuY29uc3QgREVGQVVMVF9CQUNLRU5EUzogcmVhZG9ubHkgRmlsZUxvY2tCYWNrZW5kW10gPSBbXCJmbG9ja1wiLCBcImZpbGVcIl07XG5cbi8qKiBQb2xsIGludGVydmFsIHdoaWxlIHdhaXRpbmcgZm9yIGEgY29udGVuZGVkIE9TIGxvY2suICovXG5jb25zdCBQT0xMX01TID0gNTA7XG5cbi8qKiBgZmxvY2soMilgIG9wZXJhdGlvbiBiaXRzIChMaW51eCAvIG1hY09TIC8gQlNEKS4gKi9cbmNvbnN0IExPQ0tfRVggPSAyO1xuY29uc3QgTE9DS19OQiA9IDQ7XG5jb25zdCBMT0NLX1VOID0gODtcblxuLyoqIFJlc3VsdCBtZXRhZGF0YSB3aGVuIGEgY2FsbGVyIHdhbnRzIHRvIGtub3cgd2hpY2ggYmFja2VuZCByYW4uICovXG5leHBvcnQgaW50ZXJmYWNlIEZpbGVMb2NrQWNxdWlzaXRpb24ge1xuICBiYWNrZW5kOiBGaWxlTG9ja0JhY2tlbmQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZUxvY2tPcHRpb25zIHtcbiAgLyoqXG4gICAqIERpcmVjdG9yeSBmb3IgbG9ja2ZpbGVzLiBEZWZhdWx0cyB0byBgJFRNUERJUi9kYngtdG9vbHMtbG9ja3NgLlxuICAgKi9cbiAgZGlyPzogc3RyaW5nO1xuICAvKiogT3ZlcnJpZGUgdGhlIGNhc2NhZGUuIERlZmF1bHRzIHRvIGBmbG9ja2Ag4oaSIGBmaWxlYC4gKi9cbiAgYmFja2VuZHM/OiByZWFkb25seSBGaWxlTG9ja0JhY2tlbmRbXTtcbiAgLyoqXG4gICAqIFN0b3Agd2FpdGluZyBhbmQgdGhyb3cgYWZ0ZXIgdGhpcyBtYW55IG1pbGxpc2Vjb25kcy4gT21pdCB0byBwb2xsIGZvcmV2ZXIuXG4gICAqL1xuICB0aW1lb3V0TXM/OiBudW1iZXI7XG4gIC8qKlxuICAgKiBBZ2UgYWZ0ZXIgd2hpY2ggYW4gdW5yZWZyZXNoZWQgbG9jayBkaXJlY3RvcnkgbWF5IGJlIHJlbW92ZWQuIE9taXQgdG9cbiAgICogZGlzYWJsZSBzdGFsZSBkZXRlY3Rpb24uIE9ubHkgdXNlZCBieSB0aGUgYGZpbGVgIGJhY2tlbmQuXG4gICAqL1xuICBzdGFsZU1zPzogbnVtYmVyO1xuICAvKipcbiAgICogSW50ZXJ2YWwgZm9yIHJlZnJlc2hpbmcgdGhlIGxvY2sgZGlyZWN0b3J5IG10aW1lIHdoZW4gYHN0YWxlTXNgIGlzIHNldC5cbiAgICogRGVmYXVsdHMgdG8gaGFsZiBvZiBgc3RhbGVNc2AuXG4gICAqL1xuICB1cGRhdGVNcz86IG51bWJlcjtcbiAgLyoqIEludm9rZWQgb25jZSB0aGUgYmFja2VuZCBmb3IgdGhpcyBjYWxsIGhhcyBiZWVuIGNob3Nlbi4gKi9cbiAgb25BY3F1aXJlPzogKGFjcXVpc2l0aW9uOiBGaWxlTG9ja0FjcXVpc2l0aW9uKSA9PiB2b2lkO1xufVxuXG50eXBlIEZsb2NrRm4gPSAoZmQ6IG51bWJlciwgb3BlcmF0aW9uOiBudW1iZXIpID0+IG51bWJlcjtcblxuaW50ZXJmYWNlIEJ1bkZmaU1vZHVsZSB7XG4gIGRsb3BlbjogKFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBzeW1ib2xzOiBSZWNvcmQ8c3RyaW5nLCB7IGFyZ3M6IHN0cmluZ1tdOyByZXR1cm5zOiBzdHJpbmcgfT4sXG4gICkgPT4geyBzeW1ib2xzOiB7IGZsb2NrOiBGbG9ja0ZuIH0gfTtcbiAgc3VmZml4OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUnVuIGBmbmAgd2hpbGUgaG9sZGluZyBhIGNyb3NzLXByb2Nlc3MgbG9jayBuYW1lZCBieSBga2V5YC5cbiAqXG4gKiBga2V5YCBpcyBjYW5vbmljYWxpemVkIHdpdGggYG9iamVjdC50b1N0YWJsZUtleWAsIHRoZSBzYW1lIGlkZW50aXR5IHJ1bGUgYXNcbiAqIHByb2Nlc3MgYW5kIFBvc3RncmVzIGFkdmlzb3J5IGxvY2tzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBhd2FpdCB3aXRoRmlsZUxvY2soW1wiY2FjaGVcIiwgXCJhcHBraXRcIl0sIGFzeW5jICgpID0+IHtcbiAqICAgYXdhaXQgbWlncmF0ZSgpO1xuICogfSk7XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3aXRoRmlsZUxvY2s8VD4oXG4gIGtleTogdW5rbm93bixcbiAgZm46ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuICBvcHRpb25zOiBGaWxlTG9ja09wdGlvbnMgPSB7fSxcbik6IFByb21pc2U8VD4ge1xuICB2YWxpZGF0ZU9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IGlkID0gbG9ja0lkKGtleSk7XG4gIGNvbnN0IGJhY2tlbmRzID0gb3B0aW9ucy5iYWNrZW5kcyA/PyBERUZBVUxUX0JBQ0tFTkRTO1xuICBjb25zdCBkaXIgPSBvcHRpb25zLmRpciA/PyBqb2luKHRtcGRpcigpLCBcImRieC10b29scy1sb2Nrc1wiKTtcbiAgY29uc3QgZGVhZGxpbmUgPSBvcHRpb25zLnRpbWVvdXRNcyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogRGF0ZS5ub3coKSArIG9wdGlvbnMudGltZW91dE1zO1xuXG4gIGZvciAoY29uc3QgYmFja2VuZCBvZiBiYWNrZW5kcykge1xuICAgIHN3aXRjaCAoYmFja2VuZCkge1xuICAgICAgY2FzZSBcImZsb2NrXCI6IHtcbiAgICAgICAgY29uc3QgbG9ja1BhdGggPSBqb2luKGRpciwgYCR7aWR9LmZsb2NrYCk7XG4gICAgICAgIGNvbnN0IGZsb2NrID0gYXdhaXQgcmVzb2x2ZUZsb2NrKCk7XG4gICAgICAgIGlmICghZmxvY2spIHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoXCJsb2NrIGJhY2tlbmQgdW5hdmFpbGFibGVcIiwgeyBiYWNrZW5kLCBrZXk6IGlkIH0pO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcImFjcXVpcmluZyBsb2NrXCIsIHsgYmFja2VuZCwga2V5OiBpZCwgcGF0aDogbG9ja1BhdGggfSk7XG4gICAgICAgIG9wdGlvbnMub25BY3F1aXJlPy4oeyBiYWNrZW5kIH0pO1xuICAgICAgICByZXR1cm4gaG9sZEZsb2NrKGxvY2tQYXRoLCBmbG9jaywgZGVhZGxpbmUsIGZuKTtcbiAgICAgIH1cbiAgICAgIGNhc2UgXCJmaWxlXCI6IHtcbiAgICAgICAgY29uc3QgbG9ja1BhdGggPSBqb2luKGRpciwgYCR7aWR9LmxvY2tgKTtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFwiYWNxdWlyaW5nIGxvY2tcIiwgeyBiYWNrZW5kLCBrZXk6IGlkLCBwYXRoOiBsb2NrUGF0aCB9KTtcbiAgICAgICAgb3B0aW9ucy5vbkFjcXVpcmU/Lih7IGJhY2tlbmQgfSk7XG4gICAgICAgIHJldHVybiBob2xkTG9ja0RpcmVjdG9yeShsb2NrUGF0aCwgZGVhZGxpbmUsIG9wdGlvbnMuc3RhbGVNcywgb3B0aW9ucy51cGRhdGVNcywgZm4pO1xuICAgICAgfVxuICAgICAgZGVmYXVsdDoge1xuICAgICAgICBjb25zdCBfZXhoYXVzdGl2ZTogbmV2ZXIgPSBiYWNrZW5kO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVua25vd24gZmlsZS1sb2NrIGJhY2tlbmQ6ICR7U3RyaW5nKF9leGhhdXN0aXZlKX1gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB0aHJvdyBuZXcgRXJyb3IoXCJ3aXRoRmlsZUxvY2s6IG5vIGxvY2sgYmFja2VuZCBhdmFpbGFibGVcIik7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlT3B0aW9ucyhvcHRpb25zOiBGaWxlTG9ja09wdGlvbnMpOiB2b2lkIHtcbiAgaWYgKG9wdGlvbnMudGltZW91dE1zICE9PSB1bmRlZmluZWQgJiYgb3B0aW9ucy50aW1lb3V0TXMgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcInRpbWVvdXRNcyBtdXN0IGJlIG5vbi1uZWdhdGl2ZVwiKTtcbiAgfVxuICBpZiAob3B0aW9ucy5zdGFsZU1zICE9PSB1bmRlZmluZWQgJiYgb3B0aW9ucy5zdGFsZU1zIDw9IDApIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwic3RhbGVNcyBtdXN0IGJlIHBvc2l0aXZlXCIpO1xuICB9XG4gIGlmIChvcHRpb25zLnVwZGF0ZU1zICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAob3B0aW9ucy5zdGFsZU1zID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJ1cGRhdGVNcyByZXF1aXJlcyBzdGFsZU1zXCIpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy51cGRhdGVNcyA8PSAwIHx8IG9wdGlvbnMudXBkYXRlTXMgPiBvcHRpb25zLnN0YWxlTXMgLyAyKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwidXBkYXRlTXMgbXVzdCBiZSBwb3NpdGl2ZSBhbmQgbm8gZ3JlYXRlciB0aGFuIGhhbGYgb2Ygc3RhbGVNc1wiKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqIENhbm9uaWNhbCBmaWxlc3lzdGVtLXNhZmUgaWQgZm9yIGEgbG9jayBrZXkuICovXG5mdW5jdGlvbiBsb2NrSWQoa2V5OiB1bmtub3duKTogc3RyaW5nIHtcbiAgY29uc3Qgc3RhYmxlID0gb2JqZWN0XG4gICAgLnRvT25lT3JNYW55KGtleSlcbiAgICAubWFwKChwYXJ0KSA9PiBvYmplY3QudG9TdGFibGVLZXkocGFydCkpXG4gICAgLmpvaW4oXCJcXHUwMDAwXCIpO1xuICAvLyBTaG9ydCBkaWdlc3Qgc28gcGF0aHMgc3RheSB3ZWxsIHVuZGVyIE9TIGxpbWl0czsgY29sbGlzaW9ucyBhcmUgZmluZSDigJQgdGhleVxuICAvLyBvbmx5IG1lcmdlIGNyaXRpY2FsIHNlY3Rpb25zIHRoYXQgYWxyZWFkeSBzaGFyZWQgYSBrZXkgc3RyaW5nLlxuICByZXR1cm4gaGFzaC5mbnZIYXNoKHN0YWJsZSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBgZmxvY2soMilgIHRocm91Z2ggQnVuIEZGSSB3aGVuIHBvc3NpYmxlLlxuICpcbiAqIE1lbW9pemVkOiB0aGUgRkZJIGltcG9ydCArIGxpYmMgYGRsb3BlbmAgcnVuIG9uY2UgcGVyIHByb2Nlc3MuIFJldHVybnNcbiAqIGB1bmRlZmluZWRgIG9uIFdpbmRvd3MsIHVuZGVyIHBsYWluIE5vZGUsIG9yIHdoZW4gbGliYyBjYW5ub3QgYmUgbG9hZGVkIOKAlFxuICogY2FsbGVycyBmYWxsIHRocm91Z2ggdG8gdGhlIG5leHQgYmFja2VuZC4gQSBtaXNzIGlzIGNhY2hlZCB0b28sIHNvIGEgcHJvY2Vzc1xuICogdGhhdCBjYW5ub3QgZmxvY2sgbmV2ZXIgcmV0cmllcyB0aGUgbG9hZC5cbiAqL1xuY29uc3QgcmVzb2x2ZUZsb2NrID0gZnVuY3Rpb25Nb2R1bGUubWVtb2l6ZShhc3luYyAoKTogUHJvbWlzZTxGbG9ja0ZuIHwgdW5kZWZpbmVkPiA9PiB7XG4gIGlmIChwcm9jZXNzLnBsYXRmb3JtID09PSBcIndpbjMyXCIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmICghcHJvY2Vzcy52ZXJzaW9ucy5idW4pIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgdHJ5IHtcbiAgICAvLyBEeW5hbWljIHNwZWNpZmllciBzbyBgdHNjYCAobm8gYEB0eXBlc2AgZm9yIGBidW46ZmZpYCkgZG9lcyBub3QgcmVzb2x2ZSBpdDtcbiAgICAvLyB0aGUgaW1wb3J0IG9ubHkgc3VjY2VlZHMgdW5kZXIgQnVuIGF0IHJ1bnRpbWUuXG4gICAgY29uc3Qgc3BlY2lmaWVyID0gXCJidW46ZmZpXCI7XG4gICAgY29uc3QgZmZpID0gKGF3YWl0IGltcG9ydChzcGVjaWZpZXIpKSBhcyB1bmtub3duIGFzIEJ1bkZmaU1vZHVsZTtcbiAgICBjb25zdCBsaWJQYXRoID1cbiAgICAgIHByb2Nlc3MucGxhdGZvcm0gPT09IFwiZGFyd2luXCIgPyBcImxpYlN5c3RlbS5CLmR5bGliXCIgOiBgbGliYy4ke2ZmaS5zdWZmaXh9YDtcbiAgICBjb25zdCBsaWIgPSBmZmkuZGxvcGVuKGxpYlBhdGgsIHtcbiAgICAgIGZsb2NrOiB7IGFyZ3M6IFtcImkzMlwiLCBcImkzMlwiXSwgcmV0dXJuczogXCJpMzJcIiB9LFxuICAgIH0pO1xuICAgIHJldHVybiBsaWIuc3ltYm9scy5mbG9jaztcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJmbG9jayBGRkkgdW5hdmFpbGFibGVcIiwgeyBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGNhdXNlKSB9KTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59KTtcblxuYXN5bmMgZnVuY3Rpb24gaG9sZEZsb2NrPFQ+KFxuICBsb2NrUGF0aDogc3RyaW5nLFxuICBmbG9jazogRmxvY2tGbixcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgZm46ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuKTogUHJvbWlzZTxUPiB7XG4gIGF3YWl0IGVuc3VyZVBhcmVudERpcihsb2NrUGF0aCk7XG4gIGNvbnN0IGhhbmRsZSA9IGF3YWl0IG9wZW4obG9ja1BhdGgsIFwiYStcIik7XG4gIHRyeSB7XG4gICAgYXdhaXQgd2FpdEZvckZsb2NrKGhhbmRsZS5mZCwgZmxvY2ssIGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBmbigpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBmbG9jayhoYW5kbGUuZmQsIExPQ0tfVU4pO1xuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBoYW5kbGUuY2xvc2UoKS5jYXRjaCgoKSA9PiB7fSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gd2FpdEZvckZsb2NrKFxuICBmZDogbnVtYmVyLFxuICBmbG9jazogRmxvY2tGbixcbiAgbG9ja1BhdGg6IHN0cmluZyxcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbik6IFByb21pc2U8dm9pZD4ge1xuICBmb3IgKDs7KSB7XG4gICAgY29uc3QgcmMgPSBmbG9jayhmZCwgTE9DS19FWCB8IExPQ0tfTkIpO1xuICAgIGlmIChyYyA9PT0gMCkgcmV0dXJuO1xuICAgIGFzc2VydEJlZm9yZURlYWRsaW5lKGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgYXdhaXQgYXN5bmMuc2xlZXAoUE9MTF9NUyk7XG4gIH1cbn1cblxuLyoqXG4gKiBBdG9taWMgbG9jay1kaXJlY3RvcnkgY3JlYXRpb24g4oCUIHRoZSBwb3J0YWJsZSAvIFdpbmRvd3MgcGF0aC5cbiAqXG4gKiBgbWtkaXJgIGlzIHRoZSBzYW1lIHByaW1pdGl2ZSB1c2VkIGJ5IGBwcm9wZXItbG9ja2ZpbGVgOiBpdCBpcyBhdG9taWMgYWNyb3NzXG4gKiBzdXBwb3J0ZWQgbG9jYWwgYW5kIG5ldHdvcmsgZmlsZXN5c3RlbXMuIFdoZW4gc3RhbGUgZGV0ZWN0aW9uIGlzIGVuYWJsZWQsXG4gKiB0aGUgaG9sZGVyIHJlZnJlc2hlcyBtdGltZSBzbyBhIGxpdmUgbG9uZy1ydW5uaW5nIGxvY2sgaXMgbmV2ZXIgcmVjbGFpbWVkLlxuICovXG5hc3luYyBmdW5jdGlvbiBob2xkTG9ja0RpcmVjdG9yeTxUPihcbiAgbG9ja1BhdGg6IHN0cmluZyxcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgc3RhbGVNczogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICB1cGRhdGVNczogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBmbjogKCkgPT4gVCB8IFByb21pc2U8VD4sXG4pOiBQcm9taXNlPFQ+IHtcbiAgYXdhaXQgZW5zdXJlUGFyZW50RGlyKGxvY2tQYXRoKTtcbiAgYXdhaXQgYWNxdWlyZUxvY2tEaXJlY3RvcnkobG9ja1BhdGgsIGRlYWRsaW5lLCBzdGFsZU1zKTtcbiAgY29uc3Qgc3RvcEhlYXJ0YmVhdCA9IHN0YXJ0SGVhcnRiZWF0KGxvY2tQYXRoLCBzdGFsZU1zLCB1cGRhdGVNcyk7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IGZuKCk7XG4gIH0gZmluYWxseSB7XG4gICAgc3RvcEhlYXJ0YmVhdCgpO1xuICAgIGF3YWl0IHJtKGxvY2tQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSkuY2F0Y2goKCkgPT4ge30pO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGFjcXVpcmVMb2NrRGlyZWN0b3J5KFxuICBsb2NrUGF0aDogc3RyaW5nLFxuICBkZWFkbGluZTogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBzdGFsZU1zOiBudW1iZXIgfCB1bmRlZmluZWQsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgZm9yICg7Oykge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBta2Rpcihsb2NrUGF0aCk7XG4gICAgICByZXR1cm47XG4gICAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICAgIGNvbnN0IGVyciA9IGNhdXNlIGFzIE5vZGVKUy5FcnJub0V4Y2VwdGlvbjtcbiAgICAgIGlmIChlcnIuY29kZSAhPT0gXCJFRVhJU1RcIikgdGhyb3cgZXJyb3IudG9FcnJvcihjYXVzZSk7XG4gICAgICBpZiAoc3RhbGVNcyAhPT0gdW5kZWZpbmVkKSBhd2FpdCBtYXliZVJlY2xhaW1TdGFsZShsb2NrUGF0aCwgc3RhbGVNcyk7XG4gICAgICBhc3NlcnRCZWZvcmVEZWFkbGluZShsb2NrUGF0aCwgZGVhZGxpbmUpO1xuICAgICAgYXdhaXQgYXN5bmMuc2xlZXAoUE9MTF9NUyk7XG4gICAgfVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1heWJlUmVjbGFpbVN0YWxlKGxvY2tQYXRoOiBzdHJpbmcsIHN0YWxlTXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHsgbXRpbWVNcyB9ID0gYXdhaXQgc3RhdChsb2NrUGF0aCk7XG4gICAgY29uc3QgYWdlID0gRGF0ZS5ub3coKSAtIG10aW1lTXM7XG4gICAgaWYgKGFnZSA8IHN0YWxlTXMpIHJldHVybjtcbiAgICBsb2dnZXIuZGVidWcoXCJyZWNsYWltaW5nIHN0YWxlIGxvY2sgZGlyZWN0b3J5XCIsIHsgcGF0aDogbG9ja1BhdGgsIGFnZU1zOiBhZ2UgfSk7XG4gICAgYXdhaXQgcm0obG9ja1BhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICBjb25zdCBlcnIgPSBjYXVzZSBhcyBOb2RlSlMuRXJybm9FeGNlcHRpb247XG4gICAgaWYgKGVyci5jb2RlICE9PSBcIkVOT0VOVFwiKSB0aHJvdyBlcnJvci50b0Vycm9yKGNhdXNlKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBzdGFydEhlYXJ0YmVhdChcbiAgbG9ja1BhdGg6IHN0cmluZyxcbiAgc3RhbGVNczogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICB1cGRhdGVNczogbnVtYmVyIHwgdW5kZWZpbmVkLFxuKTogKCkgPT4gdm9pZCB7XG4gIGlmIChzdGFsZU1zID09PSB1bmRlZmluZWQpIHJldHVybiAoKSA9PiB7fTtcbiAgY29uc3QgaW50ZXJ2YWxNcyA9IHVwZGF0ZU1zID8/IE1hdGgubWF4KDEsIE1hdGguZmxvb3Ioc3RhbGVNcyAvIDIpKTtcbiAgY29uc3QgdGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKTtcbiAgICB2b2lkIHV0aW1lcyhsb2NrUGF0aCwgbm93LCBub3cpLmNhdGNoKChjYXVzZSkgPT4ge1xuICAgICAgbG9nZ2VyLndhcm4oXCJmaWxlIGxvY2sgaGVhcnRiZWF0IGZhaWxlZFwiLCB7XG4gICAgICAgIHBhdGg6IGxvY2tQYXRoLFxuICAgICAgICBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGNhdXNlKSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9LCBpbnRlcnZhbE1zKTtcbiAgdGltZXIudW5yZWYoKTtcbiAgcmV0dXJuICgpID0+IGNsZWFySW50ZXJ2YWwodGltZXIpO1xufVxuXG5mdW5jdGlvbiBhc3NlcnRCZWZvcmVEZWFkbGluZShsb2NrUGF0aDogc3RyaW5nLCBkZWFkbGluZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gIGlmIChkZWFkbGluZSAhPT0gdW5kZWZpbmVkICYmIERhdGUubm93KCkgPj0gZGVhZGxpbmUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRpbWVkIG91dCB3YWl0aW5nIGZvciBmaWxlIGxvY2s6ICR7bG9ja1BhdGh9YCk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZW5zdXJlUGFyZW50RGlyKGxvY2tQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgbWtkaXIoZGlybmFtZShsb2NrUGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xufVxuIl19
236
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1sb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ZpbGUtbG9jay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBd0JHOzs7Ozs7Ozs7QUFFSCxPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDakMsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFMUMsT0FBTyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFekYsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBSzVDLE1BQU0sZ0JBQWdCLEdBQStCLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBRXZFLDJEQUEyRDtBQUMzRCxNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUM7QUFFbkI7Ozs7R0FJRztBQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLE1BQU0sQ0FBQztBQUUzRSwrRUFBK0U7QUFDL0UsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLElBQUksUUFBUSxHQUFHLENBQUMsQ0FBQztBQUVuRix1REFBdUQ7QUFDdkQsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0FBQ2xCLE1BQU0sT0FBTyxHQUFHLENBQUMsQ0FBQztBQUNsQixNQUFNLE9BQU8sR0FBRyxDQUFDLENBQUM7QUFpQ2xC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UyxvQkFBb0IsQ0FBQyxRQUFnQixFQUFFLFFBQTRCO0lBQzFFLElBQUksUUFBUSxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksUUFBUSxFQUFFLENBQUM7UUFDckQsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQ0FBb0MsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUNsRSxDQUFDO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxlQUFlLENBQUMsUUFBZ0I7SUFDN0MsTUFBTSxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7QUFDdEQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ2FzY2FkaW5nIGNyb3NzLXByb2Nlc3MgbXV0dWFsIGV4Y2x1c2lvbiB2aWEgYSBsb2NrZmlsZS5cbiAqXG4gKiBTZXJpYWxpemVzIGNvbmN1cnJlbnQgKnByb2Nlc3NlcyogKHR3byBgYnVuIHJ1biBkZW1vYCBzaGVsbHMsIGEgQ0xJIGJlc2lkZSBhXG4gKiBzZXJ2ZXIpIG9uIHRoZSBzYW1lIGtleS4gRm9yIGluLXByb2Nlc3MgLyB3b3JrZXItdGhyZWFkIGV4Y2x1c2lvbiB1c2VcbiAqIHtAbGluayB3aXRoUHJvY2Vzc0xvY2t9IGZyb20gYC4vcHJvY2Vzcy1sb2NrLnRzYCBpbnN0ZWFkLlxuICpcbiAqIEJhY2tlbmRzLCBpbiBvcmRlcjpcbiAqXG4gKiAxLiAqKmZsb2NrKiog4oCUIGBmbG9jaygyKWAgdmlhIEJ1biBGRkkgb24gVW5peCB3aGVuIGBidW46ZmZpYCBjYW4gbG9hZCBsaWJjLlxuICogICAgTm90IGF2YWlsYWJsZSBvbiBXaW5kb3dzLCBhbmQgbm90IGF2YWlsYWJsZSB1bmRlciBwbGFpbiBOb2RlIChubyBGRkkpLlxuICogICAgS2VybmVsIHJlbGVhc2VzIHRoZSBsb2NrIHdoZW4gdGhlIGZkIGNsb3NlcyAoaW5jbHVkaW5nIHByb2Nlc3MgZGVhdGgpLlxuICogMi4gKipmaWxlKiog4oCUIGF0b21pYyBsb2NrLWRpcmVjdG9yeSBjcmVhdGlvbi4gVGhpcyBpcyB0aGUgc3RyYXRlZ3kgdXNlZCBieVxuICogICAgYHByb3Blci1sb2NrZmlsZWA6IGBta2RpcmAgaXMgYXRvbWljIG9uIFdpbmRvd3MsIFVuaXgsIGFuZCBuZXR3b3JrIGZpbGVcbiAqICAgIHN5c3RlbXMgd2hlcmUgYG9wZW4oLi4uLCBcInd4XCIpYCBtYXkgbm90IGJlIHJlbGlhYmxlLiBTdGFsZSBkZXRlY3Rpb24gaXNcbiAqICAgIGFsd2F5cyBvbiAoZml4ZWQge0BsaW5rIFNUQUxFX01TfSArIGhlYXJ0YmVhdCkgc28gYSBjcmFzaGVkIGhvbGRlciBvbiB0aGlzXG4gKiAgICBiYWNrZW5kIGNhbiBiZSByZWNsYWltZWQuXG4gKlxuICogVGhlIGZpcnN0IGJhY2tlbmQgdGhhdCBjYW4gYmUgKmluaXRpYWxpemVkKiBpcyB1c2VkIGZvciB0aGUgd2hvbGUgY2FsbC4gQSBidXN5XG4gKiBsb2NrIHdhaXRzOyBhbiB1bmF2YWlsYWJsZSBiYWNrZW5kIGZhbGxzIHRocm91Z2ggdG8gdGhlIG5leHQuIENhbGxlcnMgbWF5IG9ubHlcbiAqIGJvdW5kIGhvdyBsb25nIHRvIHdhaXQgKHtAbGluayBGaWxlTG9ja09wdGlvbnMudGltZW91dE1zfSk7IHN0YWxlIHRpbWluZyBpc1xuICogbm90IGNvbmZpZ3VyYWJsZSBzbyBldmVyeSBob2xkZXIgYW5kIHdhaXRlciBhZ3JlZXMuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7IG1rZGlyLCBvcGVuLCBybSwgc3RhdCwgdXRpbWVzIH0gZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IHRtcGRpciB9IGZyb20gXCJub2RlOm9zXCI7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG5pbXBvcnQgeyBhc3luYywgZXJyb3IsIGZ1bmN0aW9uTW9kdWxlLCBoYXNoLCBsb2csIG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJjb3JlOmZpbGUtbG9ja1wiKTtcblxuLyoqIEJhY2tlbmRzIHtAbGluayB3aXRoRmlsZUxvY2t9IGNhbiBhdHRlbXB0LCBpbiBjYXNjYWRlIG9yZGVyLiAqL1xuZXhwb3J0IHR5cGUgRmlsZUxvY2tCYWNrZW5kID0gXCJmbG9ja1wiIHwgXCJmaWxlXCI7XG5cbmNvbnN0IERFRkFVTFRfQkFDS0VORFM6IHJlYWRvbmx5IEZpbGVMb2NrQmFja2VuZFtdID0gW1wiZmxvY2tcIiwgXCJmaWxlXCJdO1xuXG4vKiogUG9sbCBpbnRlcnZhbCB3aGlsZSB3YWl0aW5nIGZvciBhIGNvbnRlbmRlZCBPUyBsb2NrLiAqL1xuY29uc3QgUE9MTF9NUyA9IDUwO1xuXG4vKipcbiAqIEFnZSBhZnRlciB3aGljaCBhbiB1bnJlZnJlc2hlZCBsb2NrIGRpcmVjdG9yeSBtYXkgYmUgcmVtb3ZlZC5cbiAqIE1hdGNoZXMgYHByb3Blci1sb2NrZmlsZWAncyBkZWZhdWx0LiBOb3QgY2FsbGVyLWNvbmZpZ3VyYWJsZTogZXZlcnkgcHJvY2Vzc1xuICogbXVzdCBzaGFyZSB0aGUgc2FtZSB0aHJlc2hvbGQgb3IgYSBsaXZlIGhvbGRlciBjYW4gYmUgbWlzdGFrZW4gZm9yIHN0YWxlLlxuICovXG5jb25zdCBTVEFMRV9NUyA9IG9iamVjdC50b051bWJlcihwcm9jZXNzLmVudi5GSUxFX0xPQ0tfU1RBTEVfTVMpID8/IDEwXzAwMDtcblxuLyoqIEhlYXJ0YmVhdCBpbnRlcnZhbCBmb3IgcmVmcmVzaGluZyBsb2NrLWRpcmVjdG9yeSBtdGltZSAoYFNUQUxFX01TIC8gMmApLiAqL1xuY29uc3QgVVBEQVRFX01TID0gb2JqZWN0LnRvTnVtYmVyKHByb2Nlc3MuZW52LkZJTEVfTE9DS19VUERBVEVfTVMpID8/IFNUQUxFX01TIC8gMjtcblxuLyoqIGBmbG9jaygyKWAgb3BlcmF0aW9uIGJpdHMgKExpbnV4IC8gbWFjT1MgLyBCU0QpLiAqL1xuY29uc3QgTE9DS19FWCA9IDI7XG5jb25zdCBMT0NLX05CID0gNDtcbmNvbnN0IExPQ0tfVU4gPSA4O1xuXG4vKiogUmVzdWx0IG1ldGFkYXRhIHdoZW4gYSBjYWxsZXIgd2FudHMgdG8ga25vdyB3aGljaCBiYWNrZW5kIHJhbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZUxvY2tBY3F1aXNpdGlvbiB7XG4gIGJhY2tlbmQ6IEZpbGVMb2NrQmFja2VuZDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGaWxlTG9ja09wdGlvbnMge1xuICAvKipcbiAgICogRGlyZWN0b3J5IGZvciBsb2NrZmlsZXMuIERlZmF1bHRzIHRvIGAkVE1QRElSL2RieC10b29scy1sb2Nrc2AuXG4gICAqL1xuICBkaXI/OiBzdHJpbmc7XG4gIC8qKiBPdmVycmlkZSB0aGUgY2FzY2FkZS4gRGVmYXVsdHMgdG8gYGZsb2NrYCDihpIgYGZpbGVgLiAqL1xuICBiYWNrZW5kcz86IHJlYWRvbmx5IEZpbGVMb2NrQmFja2VuZFtdO1xuICAvKipcbiAgICogU3RvcCB3YWl0aW5nIGFuZCB0aHJvdyBhZnRlciB0aGlzIG1hbnkgbWlsbGlzZWNvbmRzLiBPbWl0IHRvIHBvbGwgZm9yZXZlci5cbiAgICogVGhpcyBpcyB0aGUgb25seSB3YWl0LWxvb3Aga25vYjsgc3RhbGUgcmVjbGFpbSB0aW1pbmcgaXMgZml4ZWQuXG4gICAqL1xuICB0aW1lb3V0TXM/OiBudW1iZXI7XG4gIC8qKiBJbnZva2VkIG9uY2UgdGhlIGJhY2tlbmQgZm9yIHRoaXMgY2FsbCBoYXMgYmVlbiBjaG9zZW4uICovXG4gIG9uQWNxdWlyZT86IChhY3F1aXNpdGlvbjogRmlsZUxvY2tBY3F1aXNpdGlvbikgPT4gdm9pZDtcbn1cblxudHlwZSBGbG9ja0ZuID0gKGZkOiBudW1iZXIsIG9wZXJhdGlvbjogbnVtYmVyKSA9PiBudW1iZXI7XG5cbmludGVyZmFjZSBCdW5GZmlNb2R1bGUge1xuICBkbG9wZW46IChcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgc3ltYm9sczogUmVjb3JkPHN0cmluZywgeyBhcmdzOiBzdHJpbmdbXTsgcmV0dXJuczogc3RyaW5nIH0+LFxuICApID0+IHsgc3ltYm9sczogeyBmbG9jazogRmxvY2tGbiB9IH07XG4gIHN1ZmZpeDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJ1biBgZm5gIHdoaWxlIGhvbGRpbmcgYSBjcm9zcy1wcm9jZXNzIGxvY2sgbmFtZWQgYnkgYGtleWAuXG4gKlxuICogYGtleWAgaXMgY2Fub25pY2FsaXplZCB3aXRoIGBvYmplY3QudG9TdGFibGVLZXlgLCB0aGUgc2FtZSBpZGVudGl0eSBydWxlIGFzXG4gKiBwcm9jZXNzIGFuZCBQb3N0Z3JlcyBhZHZpc29yeSBsb2Nrcy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYXdhaXQgd2l0aEZpbGVMb2NrKFtcImNhY2hlXCIsIFwiYXBwa2l0XCJdLCBhc3luYyAoKSA9PiB7XG4gKiAgIGF3YWl0IG1pZ3JhdGUoKTtcbiAqIH0pO1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd2l0aEZpbGVMb2NrPFQ+KFxuICBrZXk6IHVua25vd24sXG4gIGZuOiAoKSA9PiBUIHwgUHJvbWlzZTxUPixcbiAgb3B0aW9uczogRmlsZUxvY2tPcHRpb25zID0ge30sXG4pOiBQcm9taXNlPFQ+IHtcbiAgaWYgKG9wdGlvbnMudGltZW91dE1zICE9PSB1bmRlZmluZWQgJiYgb3B0aW9ucy50aW1lb3V0TXMgPCAwKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcInRpbWVvdXRNcyBtdXN0IGJlIG5vbi1uZWdhdGl2ZVwiKTtcbiAgfVxuICBjb25zdCBpZCA9IGxvY2tJZChrZXkpO1xuICBjb25zdCBiYWNrZW5kcyA9IG9wdGlvbnMuYmFja2VuZHMgPz8gREVGQVVMVF9CQUNLRU5EUztcbiAgY29uc3QgZGlyID0gb3B0aW9ucy5kaXIgPz8gam9pbih0bXBkaXIoKSwgXCJkYngtdG9vbHMtbG9ja3NcIik7XG4gIGNvbnN0IGRlYWRsaW5lID0gb3B0aW9ucy50aW1lb3V0TXMgPT09IHVuZGVmaW5lZCA/IHVuZGVmaW5lZCA6IERhdGUubm93KCkgKyBvcHRpb25zLnRpbWVvdXRNcztcblxuICBmb3IgKGNvbnN0IGJhY2tlbmQgb2YgYmFja2VuZHMpIHtcbiAgICBzd2l0Y2ggKGJhY2tlbmQpIHtcbiAgICAgIGNhc2UgXCJmbG9ja1wiOiB7XG4gICAgICAgIGNvbnN0IGxvY2tQYXRoID0gam9pbihkaXIsIGAke2lkfS5mbG9ja2ApO1xuICAgICAgICBjb25zdCBmbG9jayA9IGF3YWl0IHJlc29sdmVGbG9jaygpO1xuICAgICAgICBpZiAoIWZsb2NrKSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKFwibG9jayBiYWNrZW5kIHVuYXZhaWxhYmxlXCIsIHsgYmFja2VuZCwga2V5OiBpZCB9KTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBsb2dnZXIuZGVidWcoXCJhY3F1aXJpbmcgbG9ja1wiLCB7IGJhY2tlbmQsIGtleTogaWQsIHBhdGg6IGxvY2tQYXRoIH0pO1xuICAgICAgICBvcHRpb25zLm9uQWNxdWlyZT8uKHsgYmFja2VuZCB9KTtcbiAgICAgICAgcmV0dXJuIGhvbGRGbG9jayhsb2NrUGF0aCwgZmxvY2ssIGRlYWRsaW5lLCBmbik7XG4gICAgICB9XG4gICAgICBjYXNlIFwiZmlsZVwiOiB7XG4gICAgICAgIGNvbnN0IGxvY2tQYXRoID0gam9pbihkaXIsIGAke2lkfS5sb2NrYCk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcImFjcXVpcmluZyBsb2NrXCIsIHsgYmFja2VuZCwga2V5OiBpZCwgcGF0aDogbG9ja1BhdGggfSk7XG4gICAgICAgIG9wdGlvbnMub25BY3F1aXJlPy4oeyBiYWNrZW5kIH0pO1xuICAgICAgICByZXR1cm4gaG9sZExvY2tEaXJlY3RvcnkobG9ja1BhdGgsIGRlYWRsaW5lLCBmbik7XG4gICAgICB9XG4gICAgICBkZWZhdWx0OiB7XG4gICAgICAgIGNvbnN0IF9leGhhdXN0aXZlOiBuZXZlciA9IGJhY2tlbmQ7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdW5rbm93biBmaWxlLWxvY2sgYmFja2VuZDogJHtTdHJpbmcoX2V4aGF1c3RpdmUpfWApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcIndpdGhGaWxlTG9jazogbm8gbG9jayBiYWNrZW5kIGF2YWlsYWJsZVwiKTtcbn1cblxuLyoqIENhbm9uaWNhbCBmaWxlc3lzdGVtLXNhZmUgaWQgZm9yIGEgbG9jayBrZXkuICovXG5mdW5jdGlvbiBsb2NrSWQoa2V5OiB1bmtub3duKTogc3RyaW5nIHtcbiAgY29uc3Qgc3RhYmxlID0gb2JqZWN0XG4gICAgLnRvT25lT3JNYW55KGtleSlcbiAgICAubWFwKChwYXJ0KSA9PiBvYmplY3QudG9TdGFibGVLZXkocGFydCkpXG4gICAgLmpvaW4oXCJcXHUwMDAwXCIpO1xuICAvLyBTaG9ydCBkaWdlc3Qgc28gcGF0aHMgc3RheSB3ZWxsIHVuZGVyIE9TIGxpbWl0czsgY29sbGlzaW9ucyBhcmUgZmluZSDigJQgdGhleVxuICAvLyBvbmx5IG1lcmdlIGNyaXRpY2FsIHNlY3Rpb25zIHRoYXQgYWxyZWFkeSBzaGFyZWQgYSBrZXkgc3RyaW5nLlxuICByZXR1cm4gaGFzaC5mbnZIYXNoKHN0YWJsZSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBgZmxvY2soMilgIHRocm91Z2ggQnVuIEZGSSB3aGVuIHBvc3NpYmxlLlxuICpcbiAqIE1lbW9pemVkOiB0aGUgRkZJIGltcG9ydCArIGxpYmMgYGRsb3BlbmAgcnVuIG9uY2UgcGVyIHByb2Nlc3MuIFJldHVybnNcbiAqIGB1bmRlZmluZWRgIG9uIFdpbmRvd3MsIHVuZGVyIHBsYWluIE5vZGUsIG9yIHdoZW4gbGliYyBjYW5ub3QgYmUgbG9hZGVkIOKAlFxuICogY2FsbGVycyBmYWxsIHRocm91Z2ggdG8gdGhlIG5leHQgYmFja2VuZC4gQSBtaXNzIGlzIGNhY2hlZCB0b28sIHNvIGEgcHJvY2Vzc1xuICogdGhhdCBjYW5ub3QgZmxvY2sgbmV2ZXIgcmV0cmllcyB0aGUgbG9hZC5cbiAqL1xuY29uc3QgcmVzb2x2ZUZsb2NrID0gZnVuY3Rpb25Nb2R1bGUubWVtb2l6ZShhc3luYyAoKTogUHJvbWlzZTxGbG9ja0ZuIHwgdW5kZWZpbmVkPiA9PiB7XG4gIGlmIChwcm9jZXNzLnBsYXRmb3JtID09PSBcIndpbjMyXCIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGlmICghcHJvY2Vzcy52ZXJzaW9ucy5idW4pIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgdHJ5IHtcbiAgICAvLyBEeW5hbWljIHNwZWNpZmllciBzbyBgdHNjYCAobm8gYEB0eXBlc2AgZm9yIGBidW46ZmZpYCkgZG9lcyBub3QgcmVzb2x2ZSBpdDtcbiAgICAvLyB0aGUgaW1wb3J0IG9ubHkgc3VjY2VlZHMgdW5kZXIgQnVuIGF0IHJ1bnRpbWUuXG4gICAgY29uc3Qgc3BlY2lmaWVyID0gXCJidW46ZmZpXCI7XG4gICAgY29uc3QgZmZpID0gKGF3YWl0IGltcG9ydChzcGVjaWZpZXIpKSBhcyB1bmtub3duIGFzIEJ1bkZmaU1vZHVsZTtcbiAgICBjb25zdCBsaWJQYXRoID1cbiAgICAgIHByb2Nlc3MucGxhdGZvcm0gPT09IFwiZGFyd2luXCIgPyBcImxpYlN5c3RlbS5CLmR5bGliXCIgOiBgbGliYy4ke2ZmaS5zdWZmaXh9YDtcbiAgICBjb25zdCBsaWIgPSBmZmkuZGxvcGVuKGxpYlBhdGgsIHtcbiAgICAgIGZsb2NrOiB7IGFyZ3M6IFtcImkzMlwiLCBcImkzMlwiXSwgcmV0dXJuczogXCJpMzJcIiB9LFxuICAgIH0pO1xuICAgIHJldHVybiBsaWIuc3ltYm9scy5mbG9jaztcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICBsb2dnZXIuZGVidWcoXCJmbG9jayBGRkkgdW5hdmFpbGFibGVcIiwgeyBlcnJvcjogZXJyb3IuZXJyb3JNZXNzYWdlKGNhdXNlKSB9KTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59KTtcblxuYXN5bmMgZnVuY3Rpb24gaG9sZEZsb2NrPFQ+KFxuICBsb2NrUGF0aDogc3RyaW5nLFxuICBmbG9jazogRmxvY2tGbixcbiAgZGVhZGxpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbiAgZm46ICgpID0+IFQgfCBQcm9taXNlPFQ+LFxuKTogUHJvbWlzZTxUPiB7XG4gIGF3YWl0IGVuc3VyZVBhcmVudERpcihsb2NrUGF0aCk7XG4gIGNvbnN0IGhhbmRsZSA9IGF3YWl0IG9wZW4obG9ja1BhdGgsIFwiYStcIik7XG4gIHRyeSB7XG4gICAgYXdhaXQgd2FpdEZvckZsb2NrKGhhbmRsZS5mZCwgZmxvY2ssIGxvY2tQYXRoLCBkZWFkbGluZSk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBmbigpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBmbG9jayhoYW5kbGUuZmQsIExPQ0tfVU4pO1xuICAgIH1cbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBoYW5kbGUuY2xvc2UoKS5jYXRjaCgoKSA9PiB7IH0pO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHdhaXRGb3JGbG9jayhcbiAgZmQ6IG51bWJlcixcbiAgZmxvY2s6IEZsb2NrRm4sXG4gIGxvY2tQYXRoOiBzdHJpbmcsXG4gIGRlYWRsaW5lOiBudW1iZXIgfCB1bmRlZmluZWQsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgZm9yICg7IDspIHtcbiAgICBjb25zdCByYyA9IGZsb2NrKGZkLCBMT0NLX0VYIHwgTE9DS19OQik7XG4gICAgaWYgKHJjID09PSAwKSByZXR1cm47XG4gICAgYXNzZXJ0QmVmb3JlRGVhZGxpbmUobG9ja1BhdGgsIGRlYWRsaW5lKTtcbiAgICBhd2FpdCBhc3luYy5zbGVlcChQT0xMX01TKTtcbiAgfVxufVxuXG4vKipcbiAqIEF0b21pYyBsb2NrLWRpcmVjdG9yeSBjcmVhdGlvbiDigJQgdGhlIHBvcnRhYmxlIC8gV2luZG93cyBwYXRoLlxuICpcbiAqIGBta2RpcmAgaXMgdGhlIHNhbWUgcHJpbWl0aXZlIHVzZWQgYnkgYHByb3Blci1sb2NrZmlsZWA6IGl0IGlzIGF0b21pYyBhY3Jvc3NcbiAqIHN1cHBvcnRlZCBsb2NhbCBhbmQgbmV0d29yayBmaWxlc3lzdGVtcy4gVGhlIGhvbGRlciByZWZyZXNoZXMgbXRpbWUgb24gYSBmaXhlZFxuICogaGVhcnRiZWF0IHNvIGEgbGl2ZSBsb25nLXJ1bm5pbmcgbG9jayBpcyBuZXZlciByZWNsYWltZWQ7IGEgY3Jhc2hlZCBob2xkZXInc1xuICogZGlyZWN0b3J5IGJlY29tZXMgcmVjbGFpbWFibGUgYWZ0ZXIge0BsaW5rIFNUQUxFX01TfS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaG9sZExvY2tEaXJlY3Rvcnk8VD4oXG4gIGxvY2tQYXRoOiBzdHJpbmcsXG4gIGRlYWRsaW5lOiBudW1iZXIgfCB1bmRlZmluZWQsXG4gIGZuOiAoKSA9PiBUIHwgUHJvbWlzZTxUPixcbik6IFByb21pc2U8VD4ge1xuICBhd2FpdCBlbnN1cmVQYXJlbnREaXIobG9ja1BhdGgpO1xuICBhd2FpdCBhY3F1aXJlTG9ja0RpcmVjdG9yeShsb2NrUGF0aCwgZGVhZGxpbmUpO1xuICBjb25zdCBzdG9wSGVhcnRiZWF0ID0gc3RhcnRIZWFydGJlYXQobG9ja1BhdGgpO1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBmbigpO1xuICB9IGZpbmFsbHkge1xuICAgIHN0b3BIZWFydGJlYXQoKTtcbiAgICBhd2FpdCBybShsb2NrUGF0aCwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pLmNhdGNoKCgpID0+IHsgfSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gYWNxdWlyZUxvY2tEaXJlY3RvcnkoXG4gIGxvY2tQYXRoOiBzdHJpbmcsXG4gIGRlYWRsaW5lOiBudW1iZXIgfCB1bmRlZmluZWQsXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgZm9yICg7IDspIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgbWtkaXIobG9ja1BhdGgpO1xuICAgICAgcmV0dXJuO1xuICAgIH0gY2F0Y2ggKGNhdXNlKSB7XG4gICAgICBjb25zdCBlcnIgPSBjYXVzZSBhcyBOb2RlSlMuRXJybm9FeGNlcHRpb247XG4gICAgICBpZiAoZXJyLmNvZGUgIT09IFwiRUVYSVNUXCIpIHRocm93IGVycm9yLnRvRXJyb3IoY2F1c2UpO1xuICAgICAgYXdhaXQgbWF5YmVSZWNsYWltU3RhbGUobG9ja1BhdGgpO1xuICAgICAgYXNzZXJ0QmVmb3JlRGVhZGxpbmUobG9ja1BhdGgsIGRlYWRsaW5lKTtcbiAgICAgIGF3YWl0IGFzeW5jLnNsZWVwKFBPTExfTVMpO1xuICAgIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBtYXliZVJlY2xhaW1TdGFsZShsb2NrUGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgeyBtdGltZU1zIH0gPSBhd2FpdCBzdGF0KGxvY2tQYXRoKTtcbiAgICBjb25zdCBhZ2UgPSBEYXRlLm5vdygpIC0gbXRpbWVNcztcbiAgICBpZiAoYWdlIDwgU1RBTEVfTVMpIHJldHVybjtcbiAgICBsb2dnZXIuZGVidWcoXCJyZWNsYWltaW5nIHN0YWxlIGxvY2sgZGlyZWN0b3J5XCIsIHsgcGF0aDogbG9ja1BhdGgsIGFnZU1zOiBhZ2UgfSk7XG4gICAgYXdhaXQgcm0obG9ja1BhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgfSBjYXRjaCAoY2F1c2UpIHtcbiAgICBjb25zdCBlcnIgPSBjYXVzZSBhcyBOb2RlSlMuRXJybm9FeGNlcHRpb247XG4gICAgaWYgKGVyci5jb2RlICE9PSBcIkVOT0VOVFwiKSB0aHJvdyBlcnJvci50b0Vycm9yKGNhdXNlKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBzdGFydEhlYXJ0YmVhdChsb2NrUGF0aDogc3RyaW5nKTogKCkgPT4gdm9pZCB7XG4gIGNvbnN0IHRpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgdm9pZCB1dGltZXMobG9ja1BhdGgsIG5vdywgbm93KS5jYXRjaCgoY2F1c2UpID0+IHtcbiAgICAgIGxvZ2dlci53YXJuKFwiZmlsZSBsb2NrIGhlYXJ0YmVhdCBmYWlsZWRcIiwge1xuICAgICAgICBwYXRoOiBsb2NrUGF0aCxcbiAgICAgICAgZXJyb3I6IGVycm9yLmVycm9yTWVzc2FnZShjYXVzZSksXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSwgVVBEQVRFX01TKTtcbiAgdGltZXIudW5yZWYoKTtcbiAgcmV0dXJuICgpID0+IGNsZWFySW50ZXJ2YWwodGltZXIpO1xufVxuXG5mdW5jdGlvbiBhc3NlcnRCZWZvcmVEZWFkbGluZShsb2NrUGF0aDogc3RyaW5nLCBkZWFkbGluZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogdm9pZCB7XG4gIGlmIChkZWFkbGluZSAhPT0gdW5kZWZpbmVkICYmIERhdGUubm93KCkgPj0gZGVhZGxpbmUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRpbWVkIG91dCB3YWl0aW5nIGZvciBmaWxlIGxvY2s6ICR7bG9ja1BhdGh9YCk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZW5zdXJlUGFyZW50RGlyKGxvY2tQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgbWtkaXIoZGlybmFtZShsb2NrUGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xufVxuIl19
package/package.json CHANGED
@@ -23,7 +23,7 @@
23
23
  "typescript": "^5.9.3"
24
24
  },
25
25
  "dependencies": {
26
- "@dbx-tools/shared-core": "0.6.70",
26
+ "@dbx-tools/shared-core": "0.6.72",
27
27
  "extract-zip": "^2.0.1",
28
28
  "tar": "^7.5.22",
29
29
  "yaml": "^2.9.0"
@@ -42,7 +42,7 @@
42
42
  "./package.json": "./package.json"
43
43
  }
44
44
  },
45
- "version": "0.6.70",
45
+ "version": "0.6.72",
46
46
  "types": "./lib/index.d.ts",
47
47
  "type": "module",
48
48
  "exports": {
package/src/file-lock.ts CHANGED
@@ -12,11 +12,14 @@
12
12
  * Kernel releases the lock when the fd closes (including process death).
13
13
  * 2. **file** — atomic lock-directory creation. This is the strategy used by
14
14
  * `proper-lockfile`: `mkdir` is atomic on Windows, Unix, and network file
15
- * systems where `open(..., "wx")` may not be reliable. Optional stale
16
- * detection uses the directory mtime plus a heartbeat.
15
+ * systems where `open(..., "wx")` may not be reliable. Stale detection is
16
+ * always on (fixed {@link STALE_MS} + heartbeat) so a crashed holder on this
17
+ * backend can be reclaimed.
17
18
  *
18
19
  * The first backend that can be *initialized* is used for the whole call. A busy
19
- * lock waits; an unavailable backend falls through to the next.
20
+ * lock waits; an unavailable backend falls through to the next. Callers may only
21
+ * bound how long to wait ({@link FileLockOptions.timeoutMs}); stale timing is
22
+ * not configurable so every holder and waiter agrees.
20
23
  *
21
24
  * @module
22
25
  */
@@ -37,6 +40,16 @@ const DEFAULT_BACKENDS: readonly FileLockBackend[] = ["flock", "file"];
37
40
  /** Poll interval while waiting for a contended OS lock. */
38
41
  const POLL_MS = 50;
39
42
 
43
+ /**
44
+ * Age after which an unrefreshed lock directory may be removed.
45
+ * Matches `proper-lockfile`'s default. Not caller-configurable: every process
46
+ * must share the same threshold or a live holder can be mistaken for stale.
47
+ */
48
+ const STALE_MS = object.toNumber(process.env.FILE_LOCK_STALE_MS) ?? 10_000;
49
+
50
+ /** Heartbeat interval for refreshing lock-directory mtime (`STALE_MS / 2`). */
51
+ const UPDATE_MS = object.toNumber(process.env.FILE_LOCK_UPDATE_MS) ?? STALE_MS / 2;
52
+
40
53
  /** `flock(2)` operation bits (Linux / macOS / BSD). */
41
54
  const LOCK_EX = 2;
42
55
  const LOCK_NB = 4;
@@ -56,18 +69,9 @@ export interface FileLockOptions {
56
69
  backends?: readonly FileLockBackend[];
57
70
  /**
58
71
  * Stop waiting and throw after this many milliseconds. Omit to poll forever.
72
+ * This is the only wait-loop knob; stale reclaim timing is fixed.
59
73
  */
60
74
  timeoutMs?: number;
61
- /**
62
- * Age after which an unrefreshed lock directory may be removed. Omit to
63
- * disable stale detection. Only used by the `file` backend.
64
- */
65
- staleMs?: number;
66
- /**
67
- * Interval for refreshing the lock directory mtime when `staleMs` is set.
68
- * Defaults to half of `staleMs`.
69
- */
70
- updateMs?: number;
71
75
  /** Invoked once the backend for this call has been chosen. */
72
76
  onAcquire?: (acquisition: FileLockAcquisition) => void;
73
77
  }
@@ -98,7 +102,9 @@ export async function withFileLock<T>(
98
102
  fn: () => T | Promise<T>,
99
103
  options: FileLockOptions = {},
100
104
  ): Promise<T> {
101
- validateOptions(options);
105
+ if (options.timeoutMs !== undefined && options.timeoutMs < 0) {
106
+ throw new TypeError("timeoutMs must be non-negative");
107
+ }
102
108
  const id = lockId(key);
103
109
  const backends = options.backends ?? DEFAULT_BACKENDS;
104
110
  const dir = options.dir ?? join(tmpdir(), "dbx-tools-locks");
@@ -121,7 +127,7 @@ export async function withFileLock<T>(
121
127
  const lockPath = join(dir, `${id}.lock`);
122
128
  logger.debug("acquiring lock", { backend, key: id, path: lockPath });
123
129
  options.onAcquire?.({ backend });
124
- return holdLockDirectory(lockPath, deadline, options.staleMs, options.updateMs, fn);
130
+ return holdLockDirectory(lockPath, deadline, fn);
125
131
  }
126
132
  default: {
127
133
  const _exhaustive: never = backend;
@@ -133,23 +139,6 @@ export async function withFileLock<T>(
133
139
  throw new Error("withFileLock: no lock backend available");
134
140
  }
135
141
 
136
- function validateOptions(options: FileLockOptions): void {
137
- if (options.timeoutMs !== undefined && options.timeoutMs < 0) {
138
- throw new TypeError("timeoutMs must be non-negative");
139
- }
140
- if (options.staleMs !== undefined && options.staleMs <= 0) {
141
- throw new TypeError("staleMs must be positive");
142
- }
143
- if (options.updateMs !== undefined) {
144
- if (options.staleMs === undefined) {
145
- throw new TypeError("updateMs requires staleMs");
146
- }
147
- if (options.updateMs <= 0 || options.updateMs > options.staleMs / 2) {
148
- throw new TypeError("updateMs must be positive and no greater than half of staleMs");
149
- }
150
- }
151
- }
152
-
153
142
  /** Canonical filesystem-safe id for a lock key. */
154
143
  function lockId(key: unknown): string {
155
144
  const stable = object
@@ -206,7 +195,7 @@ async function holdFlock<T>(
206
195
  flock(handle.fd, LOCK_UN);
207
196
  }
208
197
  } finally {
209
- await handle.close().catch(() => {});
198
+ await handle.close().catch(() => { });
210
199
  }
211
200
  }
212
201
 
@@ -216,7 +205,7 @@ async function waitForFlock(
216
205
  lockPath: string,
217
206
  deadline: number | undefined,
218
207
  ): Promise<void> {
219
- for (;;) {
208
+ for (; ;) {
220
209
  const rc = flock(fd, LOCK_EX | LOCK_NB);
221
210
  if (rc === 0) return;
222
211
  assertBeforeDeadline(lockPath, deadline);
@@ -228,51 +217,49 @@ async function waitForFlock(
228
217
  * Atomic lock-directory creation — the portable / Windows path.
229
218
  *
230
219
  * `mkdir` is the same primitive used by `proper-lockfile`: it is atomic across
231
- * supported local and network filesystems. When stale detection is enabled,
232
- * the holder refreshes mtime so a live long-running lock is never reclaimed.
220
+ * supported local and network filesystems. The holder refreshes mtime on a fixed
221
+ * heartbeat so a live long-running lock is never reclaimed; a crashed holder's
222
+ * directory becomes reclaimable after {@link STALE_MS}.
233
223
  */
234
224
  async function holdLockDirectory<T>(
235
225
  lockPath: string,
236
226
  deadline: number | undefined,
237
- staleMs: number | undefined,
238
- updateMs: number | undefined,
239
227
  fn: () => T | Promise<T>,
240
228
  ): Promise<T> {
241
229
  await ensureParentDir(lockPath);
242
- await acquireLockDirectory(lockPath, deadline, staleMs);
243
- const stopHeartbeat = startHeartbeat(lockPath, staleMs, updateMs);
230
+ await acquireLockDirectory(lockPath, deadline);
231
+ const stopHeartbeat = startHeartbeat(lockPath);
244
232
  try {
245
233
  return await fn();
246
234
  } finally {
247
235
  stopHeartbeat();
248
- await rm(lockPath, { recursive: true, force: true }).catch(() => {});
236
+ await rm(lockPath, { recursive: true, force: true }).catch(() => { });
249
237
  }
250
238
  }
251
239
 
252
240
  async function acquireLockDirectory(
253
241
  lockPath: string,
254
242
  deadline: number | undefined,
255
- staleMs: number | undefined,
256
243
  ): Promise<void> {
257
- for (;;) {
244
+ for (; ;) {
258
245
  try {
259
246
  await mkdir(lockPath);
260
247
  return;
261
248
  } catch (cause) {
262
249
  const err = cause as NodeJS.ErrnoException;
263
250
  if (err.code !== "EEXIST") throw error.toError(cause);
264
- if (staleMs !== undefined) await maybeReclaimStale(lockPath, staleMs);
251
+ await maybeReclaimStale(lockPath);
265
252
  assertBeforeDeadline(lockPath, deadline);
266
253
  await async.sleep(POLL_MS);
267
254
  }
268
255
  }
269
256
  }
270
257
 
271
- async function maybeReclaimStale(lockPath: string, staleMs: number): Promise<void> {
258
+ async function maybeReclaimStale(lockPath: string): Promise<void> {
272
259
  try {
273
260
  const { mtimeMs } = await stat(lockPath);
274
261
  const age = Date.now() - mtimeMs;
275
- if (age < staleMs) return;
262
+ if (age < STALE_MS) return;
276
263
  logger.debug("reclaiming stale lock directory", { path: lockPath, ageMs: age });
277
264
  await rm(lockPath, { recursive: true, force: true });
278
265
  } catch (cause) {
@@ -281,13 +268,7 @@ async function maybeReclaimStale(lockPath: string, staleMs: number): Promise<voi
281
268
  }
282
269
  }
283
270
 
284
- function startHeartbeat(
285
- lockPath: string,
286
- staleMs: number | undefined,
287
- updateMs: number | undefined,
288
- ): () => void {
289
- if (staleMs === undefined) return () => {};
290
- const intervalMs = updateMs ?? Math.max(1, Math.floor(staleMs / 2));
271
+ function startHeartbeat(lockPath: string): () => void {
291
272
  const timer = setInterval(() => {
292
273
  const now = new Date();
293
274
  void utimes(lockPath, now, now).catch((cause) => {
@@ -296,7 +277,7 @@ function startHeartbeat(
296
277
  error: error.errorMessage(cause),
297
278
  });
298
279
  });
299
- }, intervalMs);
280
+ }, UPDATE_MS);
300
281
  timer.unref();
301
282
  return () => clearInterval(timer);
302
283
  }