sliftutils 1.7.32 → 1.7.34

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.
Files changed (116) hide show
  1. package/builders/extensionBuild.ts +1 -1
  2. package/bundler/bundleEntry.ts +1 -3
  3. package/bundler/bundler.ts +2 -4
  4. package/bundler/sourceMaps.ts +1 -2
  5. package/examplestorage/browser.tsx +1 -2
  6. package/examplestorage/exampleserver.ts +1 -2
  7. package/index.d.ts +134 -102
  8. package/misc/dist/environment.ts.cache +2 -2
  9. package/misc/dist/getSecret.ts.cache +2 -2
  10. package/misc/dist/strings.ts.cache +2 -2
  11. package/misc/dist/zip.ts.cache +2 -2
  12. package/misc/https/dist/certs.ts.cache +2 -2
  13. package/misc/https/dist/dns.ts.cache +7 -16
  14. package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
  15. package/misc/https/dns.d.ts +1 -4
  16. package/misc/https/dns.ts +5 -14
  17. package/misc/https/hostServer.d.ts +2 -0
  18. package/misc/https/hostServer.ts +6 -7
  19. package/misc/https/httpsCerts.ts +4 -10
  20. package/misc/openrouter.ts +1 -2
  21. package/package.json +1 -1
  22. package/render-utils/FullscreenModal.tsx +1 -4
  23. package/render-utils/GenericFormat.tsx +2 -8
  24. package/render-utils/Input.tsx +5 -13
  25. package/render-utils/InputLabel.tsx +4 -6
  26. package/render-utils/InputPicker.tsx +1 -2
  27. package/render-utils/URLParam.ts +2 -3
  28. package/render-utils/dist/observer.tsx.cache +2 -2
  29. package/render-utils/mobxTyped.ts +2 -3
  30. package/render-utils/niceStringify.ts +2 -4
  31. package/storage/ArchivesDisk.ts +4 -14
  32. package/storage/BulkDatabase2/BulkDatabase2.d.ts +1 -2
  33. package/storage/BulkDatabase2/BulkDatabase2.ts +4 -11
  34. package/storage/BulkDatabase2/BulkDatabaseBase.ts +42 -114
  35. package/storage/BulkDatabase2/BulkDatabaseFormat.ts +31 -91
  36. package/storage/BulkDatabase2/BulkDatabaseMerge.ts +19 -57
  37. package/storage/BulkDatabase2/BulkDatabaseReader.ts +4 -12
  38. package/storage/BulkDatabase2/LoadedIndex.ts +6 -18
  39. package/storage/BulkDatabase2/WriteOverlay.ts +3 -8
  40. package/storage/BulkDatabase2/blockCache.ts +12 -28
  41. package/storage/BulkDatabase2/dist/BulkDatabaseBase.ts.cache +40 -103
  42. package/storage/BulkDatabase2/dist/BulkDatabaseFormat.ts.cache +19 -50
  43. package/storage/BulkDatabase2/dist/BulkDatabaseMerge.ts.cache +18 -50
  44. package/storage/BulkDatabase2/dist/BulkDatabaseReader.ts.cache +7 -15
  45. package/storage/BulkDatabase2/dist/LoadedIndex.ts.cache +9 -21
  46. package/storage/BulkDatabase2/dist/WriteOverlay.ts.cache +6 -11
  47. package/storage/BulkDatabase2/dist/blockCache.ts.cache +15 -31
  48. package/storage/BulkDatabase2/dist/mergeLock.ts.cache +10 -29
  49. package/storage/BulkDatabase2/dist/mergeMarkers.ts.cache +10 -18
  50. package/storage/BulkDatabase2/dist/streamLog.ts.cache +17 -43
  51. package/storage/BulkDatabase2/dist/syncClient.ts.cache +11 -27
  52. package/storage/BulkDatabase2/mergeLock.ts +7 -26
  53. package/storage/BulkDatabase2/mergeMarkers.ts +7 -15
  54. package/storage/BulkDatabase2/streamLog.ts +14 -40
  55. package/storage/BulkDatabase2/syncClient.ts +8 -24
  56. package/storage/FileFolderAPI.tsx +28 -75
  57. package/storage/IArchives.d.ts +3 -3
  58. package/storage/IArchives.ts +21 -50
  59. package/storage/IStorage.ts +2 -4
  60. package/storage/PendingManager.tsx +2 -3
  61. package/storage/TransactionStorage.ts +11 -24
  62. package/storage/backblaze.ts +12 -43
  63. package/storage/dist/ArchivesDisk.ts.cache +7 -17
  64. package/storage/dist/FileFolderAPI.tsx.cache +25 -63
  65. package/storage/dist/IArchives.ts.cache +10 -20
  66. package/storage/dist/IndexedDBFileFolderAPI.ts.cache +2 -2
  67. package/storage/dist/JSONStorage.ts.cache +2 -2
  68. package/storage/dist/PendingManager.tsx.cache +5 -6
  69. package/storage/dist/TransactionStorage.ts.cache +14 -27
  70. package/storage/dist/backblaze.ts.cache +15 -46
  71. package/storage/dist/embeddingFormats.ts.cache +11 -24
  72. package/storage/dist/fileSystemPointer.ts.cache +4 -7
  73. package/storage/dist/remoteFileStorage.ts.cache +17 -36
  74. package/storage/embeddingFormats.ts +11 -27
  75. package/storage/fileSystemPointer.ts +2 -7
  76. package/storage/proxydatabase/dist/ivfEmbeddingDatabase.ts.cache +8 -18
  77. package/storage/proxydatabase/dist/transactionSet.ts.cache +4 -7
  78. package/storage/proxydatabase/inMemoryDatabase.ts +1 -3
  79. package/storage/proxydatabase/ivfEmbeddingDatabase.ts +8 -23
  80. package/storage/proxydatabase/transactionSet.ts +2 -5
  81. package/storage/remoteFileServer.ts +20 -48
  82. package/storage/remoteFileStorage.ts +14 -33
  83. package/storage/remoteStorage/ArchivesRemote.d.ts +1 -4
  84. package/storage/remoteStorage/ArchivesRemote.ts +11 -26
  85. package/storage/remoteStorage/ArchivesUrl.ts +2 -4
  86. package/storage/remoteStorage/accessPage.tsx +1 -5
  87. package/storage/remoteStorage/blobStore.d.ts +5 -13
  88. package/storage/remoteStorage/blobStore.ts +52 -130
  89. package/storage/remoteStorage/createArchives.d.ts +22 -14
  90. package/storage/remoteStorage/createArchives.ts +54 -188
  91. package/storage/remoteStorage/deployTakeover.d.ts +18 -32
  92. package/storage/remoteStorage/deployTakeover.ts +70 -384
  93. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +12 -24
  94. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +5 -7
  95. package/storage/remoteStorage/dist/blobStore.ts.cache +47 -117
  96. package/storage/remoteStorage/dist/cliArgs.ts.cache +2 -2
  97. package/storage/remoteStorage/dist/createArchives.ts.cache +58 -189
  98. package/storage/remoteStorage/dist/deployTakeover.ts.cache +81 -387
  99. package/storage/remoteStorage/dist/intermediateSources.ts.cache +119 -0
  100. package/storage/remoteStorage/dist/remoteConfig.ts.cache +36 -24
  101. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +20 -40
  102. package/storage/remoteStorage/dist/storageClientController.ts.cache +4 -6
  103. package/storage/remoteStorage/dist/storageController.ts.cache +37 -74
  104. package/storage/remoteStorage/dist/storageServerState.ts.cache +345 -188
  105. package/storage/remoteStorage/grantAccessCli.ts +1 -3
  106. package/storage/remoteStorage/intermediateSources.d.ts +21 -0
  107. package/storage/remoteStorage/intermediateSources.ts +117 -0
  108. package/storage/remoteStorage/remoteConfig.ts +33 -20
  109. package/storage/remoteStorage/sourceWrapper.d.ts +8 -19
  110. package/storage/remoteStorage/sourceWrapper.ts +19 -41
  111. package/storage/remoteStorage/storageClientController.ts +1 -3
  112. package/storage/remoteStorage/storageController.d.ts +7 -6
  113. package/storage/remoteStorage/storageController.ts +36 -82
  114. package/storage/remoteStorage/storageServer.ts +20 -34
  115. package/storage/remoteStorage/storageServerState.d.ts +41 -5
  116. package/storage/remoteStorage/storageServerState.ts +355 -216
@@ -1,433 +1,127 @@
1
- "use strict";
1
+ "use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
2
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
- //exports.getMainPortAcquireDelay = exports.getOwnWindowEndClip = exports.getTakeoverAltPort = exports.getTakeoverStamp = exports.applyDeployRemap = exports.onTakeoverEvent = exports.registerAltPort = exports.initDeployTakeover = void 0;
6
+ //exports.getMainPortAcquireDelay = exports.getAltPortListenEnd = exports.getTakeoverIntermediate = exports.setAltPort = exports.detectDeployTakeover = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
- const child_process_1 = require("child_process");
10
- const remoteConfig_1 = require("./remoteConfig");
11
- // Deploy takeover: the deploy manager (querysub's parametersTimeline) writes <n>-parameters.json
12
- // files into our instance folder describing when each version runs and when it is shut down. Old
13
- // and new version overlap for the overlap time (O = oldEnd - newStart). We turn that overlap into
14
- // an atomic write handoff by REINTERPRETING every routing source that points at us: its valid
15
- // window is split so that the middle of the overlap ([S + 0.5*O, S + 1.5*O]) points at the new
16
- // process's temporary alternate port. The existing valid-window machinery then does everything -
17
- // the old process starts rejecting fresh writes at the first boundary, clients re-resolve, and the
18
- // new process (which recognizes the alternate port as itself) takes over. The remap is an
19
- // INTERPRETATION OVERLAY, applied where routing configs are used (see applyDeployRemap callers) -
20
- // it is never written to disk, never synchronized, and never part of any stored configuration.
21
- //
22
- // Everything here is recomputed idempotently from its inputs (timeline files, the port registry,
23
- // our ancestor pids, the clock) - files can appear or change at any moment, and we can start at
24
- // any point during a switchover.
9
+ const storageServerState_1 = require("./storageServerState");
25
10
  const PARAMETERS_TIMELINE_FILE_REGEX = /^(\d+)-parameters\.json$/;
26
- const TIMELINE_POLL_INTERVAL = 60 * 1000;
27
- // Processes listening on an alternate port register it here (sibling of the storage folder), keyed
28
- // by their actual pid; content includes their ancestor pids so the timeline entry pid (a shell
29
- // ancestor of the process) can be matched to a registry entry
30
- const PORT_REGISTRY_FOLDER_NAME = "storagePortRegistry";
31
- // Main-port acquisition attempts run this often, tightening near the predecessor's scheduled death
11
+ const DEPLOY_DETECT_RETRY_DELAY = 5 * 1000;
12
+ const DEPLOY_DETECT_ATTEMPTS = 6;
13
+ const DEPLOY_RELEASE_MATCH_WINDOW = 5 * 60 * 1000;
14
+ const ALT_PORT_LINGER = 30 * 60 * 1000;
32
15
  const ACQUIRE_SLOW_DELAY = 30 * 1000;
33
- const ACQUIRE_FAST_DELAY = 5 * 1000;
16
+ const ACQUIRE_FAST_DELAY = 1000;
34
17
  const ACQUIRE_FAST_WINDOW = 60 * 1000;
35
- const BOUNDARY_A_FRACTION = 0.5;
36
- const BOUNDARY_B_FRACTION = 1.5;
37
- const REMAP_EXPIRE_FRACTION = 2;
38
- let initialized;
39
- let ancestorPids = new Set();
40
- let timelineFolder;
41
- let ourAltPort;
42
- let current = {};
43
- let currentKey = JSON.stringify(current);
44
- let eventListeners = [];
45
- let eventTimers = [];
46
- let loggedNoMatch = false;
47
- let loggedIdentity = false;
48
- function execText(command) {
49
- return new Promise((resolve, reject) => {
50
- (0, child_process_1.exec)(command, (error, stdout) => {
51
- if (error) {
52
- reject(error);
53
- return;
54
- }
55
- resolve(stdout);
56
- });
57
- });
18
+ let takeover;
19
+ function iso(time) {
20
+ return new Date(time).toISOString();
58
21
  }
59
- // The timeline entry pid is the screen shell that spawned us - an ancestor - so we walk our whole
60
- // ancestor chain to find which entry is us
61
- async function getAncestorPids() {
62
- let pids = new Set([process.pid]);
63
- let currentPid = process.pid;
64
- while (true) {
65
- let ppid;
66
- if (currentPid === process.pid && process.ppid) {
67
- ppid = process.ppid;
68
- }
69
- else {
70
- try {
71
- ppid = parseInt((await execText(`ps -o ppid= -p ${currentPid}`)).trim());
72
- }
73
- catch (_a) {
74
- break;
75
- }
76
- }
77
- if (!ppid || Number.isNaN(ppid) || ppid <= 1 || pids.has(ppid))
78
- break;
79
- pids.add(ppid);
80
- currentPid = ppid;
81
- }
82
- return pids;
22
+ function logPrefix() {
23
+ return `[pid ${process.pid}]`;
83
24
  }
84
- // The instance folder is ALWAYS the parent of our cwd (services run in <instance>/git/) - never
85
- // search for it, a walk could latch onto the wrong folder
86
25
  function getTimelineFolder() {
87
26
  return path_1.default.dirname(process.cwd()).replaceAll("\\", "/") + "/";
88
27
  }
89
- function pidAlive(pid) {
90
- try {
91
- process.kill(pid, 0);
92
- return true;
93
- }
94
- catch (e) {
95
- return e.code === "EPERM";
96
- }
97
- }
98
- function getRegistryFolder() {
99
- if (!initialized) {
100
- throw new Error(`Deploy takeover is not initialized`);
101
- }
102
- return path_1.default.join(path_1.default.dirname(path_1.default.resolve(initialized.storageFolder)), PORT_REGISTRY_FOLDER_NAME);
103
- }
104
- async function readPortRegistry() {
105
- let folder = getRegistryFolder();
106
- let files = [];
28
+ async function readTimelineEntries() {
29
+ var _a, _b;
30
+ let folder = getTimelineFolder();
31
+ let files;
107
32
  try {
108
33
  files = await fs_1.default.promises.readdir(folder);
109
34
  }
110
- catch (_a) {
35
+ catch (e) {
36
+ console.warn(`${logPrefix()} Could not read the deploy timeline folder ${folder}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
111
37
  return [];
112
38
  }
113
39
  let entries = [];
114
40
  for (let file of files) {
115
- let match = /^(\d+)\.json$/.exec(file);
116
- if (!match)
117
- continue;
118
- let pid = parseInt(match[1]);
119
- if (!pidAlive(pid)) {
120
- try {
121
- await fs_1.default.promises.unlink(path_1.default.join(folder, file));
122
- }
123
- catch (_b) { }
124
- continue;
125
- }
126
- try {
127
- let entry = JSON.parse(await fs_1.default.promises.readFile(path_1.default.join(folder, file), "utf8"));
128
- entries.push({ ...entry, pid });
129
- }
130
- catch (_c) { }
131
- }
132
- return entries;
133
- }
134
- async function readTimelineEntries() {
135
- var _a;
136
- if (!timelineFolder)
137
- return [];
138
- let entries = [];
139
- for (let file of await fs_1.default.promises.readdir(timelineFolder)) {
140
41
  if (!PARAMETERS_TIMELINE_FILE_REGEX.test(file))
141
42
  continue;
142
43
  try {
143
- entries.push(JSON.parse(await fs_1.default.promises.readFile(timelineFolder + file, "utf8")));
44
+ entries.push(JSON.parse(await fs_1.default.promises.readFile(folder + file, "utf8")));
144
45
  }
145
46
  catch (e) {
146
- console.warn(`Could not read deploy timeline file ${timelineFolder + file}: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
47
+ console.warn(`${logPrefix()} Could not read deploy timeline file ${folder + file}: ${(_b = e.stack) !== null && _b !== void 0 ? _b : e}`);
147
48
  }
148
49
  }
149
50
  return entries;
150
51
  }
151
- function makeRemap(successorStart, overlap, altPort) {
152
- return {
153
- boundaryA: successorStart + overlap * BOUNDARY_A_FRACTION,
154
- boundaryB: successorStart + overlap * BOUNDARY_B_FRACTION,
155
- expire: successorStart + overlap * REMAP_EXPIRE_FRACTION,
156
- altPort,
157
- };
158
- }
159
- function emit(event) {
160
- var _a;
161
- for (let listener of eventListeners) {
162
- try {
163
- listener(event);
164
- }
165
- catch (e) {
166
- console.error(`Deploy takeover listener failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`);
167
- }
168
- }
169
- }
170
- function scheduleEvents() {
171
- for (let timer of eventTimers) {
172
- clearTimeout(timer);
173
- }
174
- eventTimers = [];
175
- let now = Date.now();
176
- let schedule = (time, fnc) => {
177
- var _a, _b;
178
- if (time <= now)
179
- return;
180
- let timer = setTimeout(fnc, time - now);
181
- (_b = (_a = timer).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
182
- eventTimers.push(timer);
183
- };
184
- const remap = current.remap;
185
- if (remap) {
186
- let altPort = remap.altPort;
187
- schedule(remap.boundaryA, () => console.log(`${logPrefix()} Deploy switchover write handoff boundary ${iso(remap.boundaryA)} passed: fresh writes now belong to the alternate-port side (port ${altPort})`));
188
- schedule(remap.boundaryB, () => console.log(`${logPrefix()} Deploy switchover second boundary ${iso(remap.boundaryB)} passed: fresh writes return to the main port`));
189
- schedule(remap.expire, () => void recompute().catch((e) => { var _a; return console.error(`Deploy takeover recompute failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); }));
190
- }
191
- }
192
- // Multiple processes (predecessor + successor) often share one journal during a switchover, so
193
- // every lifecycle line identifies its process
194
- function logPrefix() {
195
- return `[pid ${process.pid}]`;
196
- }
197
- // Recompute is invoked from init, registerAltPort, the poll, and the expiry timer - possibly
198
- // concurrently. Runs are serialized, or two in-flight runs would both pass the changed-state check
199
- // and double-fire every transition (logs, rebuild events, timers).
200
- let recomputeChain = Promise.resolve();
201
- function recompute() {
202
- let next = recomputeChain.then(() => recomputeNow());
203
- recomputeChain = next.then(() => { }, () => { });
204
- return next;
205
- }
206
- async function recomputeNow() {
207
- if (!initialized || !timelineFolder)
208
- return;
209
- let now = Date.now();
210
- let entries = await readTimelineEntries();
211
- let registry = await readPortRegistry();
212
- let us;
52
+ function findOurRelease(entries, now) {
53
+ let best;
213
54
  for (let entry of entries) {
214
- if (entry.pid && ancestorPids.has(entry.pid)) {
215
- us = entry;
216
- }
217
- }
218
- // Matching failures must be loud, or takeover detection fails silently forever
219
- if (!us && entries.length && !loggedNoMatch) {
220
- loggedNoMatch = true;
221
- console.warn(`${logPrefix()} No deploy timeline entry matches our pid chain (${[...ancestorPids].join(", ")}) - takeover detection cannot work. Entries: ${entries.map(x => { var _a; return `pid=${(_a = x.pid) !== null && _a !== void 0 ? _a : "none"} releaseTime=${x.parameters.releaseTime}`; }).join(" | ")}`);
222
- }
223
- if (us && !loggedIdentity) {
224
- loggedIdentity = true;
225
- console.log(`${logPrefix()} Deploy timeline entry matched: we are pid=${us.pid}, releaseTime=${us.parameters.releaseTime !== undefined && iso(us.parameters.releaseTime) || "unknown"}, ${entries.length} entries total`);
226
- }
227
- let computed = {};
228
- let usRelease = us === null || us === void 0 ? void 0 : us.parameters.releaseTime;
229
- if (us && usRelease !== undefined) {
230
- // The newer entry's releaseTime is when it starts; releaseTime + overlapTime is when the
231
- // older one is killed. That's the whole timeline.
232
- let next;
233
- let prev;
234
- for (let entry of entries) {
235
- if (entry === us)
236
- continue;
237
- let release = entry.parameters.releaseTime;
238
- if (release === undefined)
239
- continue;
240
- if (release > usRelease && (!next || release < next.release)) {
241
- next = { entry, release };
242
- }
243
- if (release < usRelease && (!prev || release > prev.release)) {
244
- prev = { entry, release };
245
- }
246
- }
247
- if (next) {
248
- let successorStart = next.release;
249
- let overlap = next.entry.parameters.overlapTime || us.parameters.overlapTime || 0;
250
- // Tracked even for a ZERO-overlap deploy (the scheduled-switchover log must still
251
- // fire); only the remap (the alternate-port middle window) needs an actual overlap.
252
- // Flushing before the handoff needs nothing special here: the remap ends our valid
253
- // window, and fast writes always flush ahead of their window's end.
254
- computed.dying = { successorStart, overlap };
255
- if (overlap > 0 && now < successorStart + overlap * REMAP_EXPIRE_FRACTION) {
256
- const successorPid = next.entry.pid;
257
- if (successorPid) {
258
- let successorEntry = registry.find(x => x.ancestorPids.includes(successorPid));
259
- if (successorEntry) {
260
- computed.remap = makeRemap(successorStart, overlap, successorEntry.port);
261
- }
262
- }
263
- }
264
- }
265
- if (prev) {
266
- let overlap = us.parameters.overlapTime || prev.entry.parameters.overlapTime || 0;
267
- // The predecessor holds the main port until OUR release + the overlap
268
- computed.predecessorEnd = usRelease + overlap;
269
- if (overlap > 0 && ourAltPort && now < usRelease + overlap * REMAP_EXPIRE_FRACTION && !computed.remap) {
270
- computed.remap = makeRemap(usRelease, overlap, ourAltPort);
271
- }
272
- }
273
- }
274
- let key = JSON.stringify(computed);
275
- if (key === currentKey)
276
- return;
277
- logTransitions(current, computed);
278
- current = computed;
279
- currentKey = key;
280
- scheduleEvents();
281
- emit("remapChanged");
282
- }
283
- function iso(time) {
284
- return new Date(time).toISOString();
285
- }
286
- // The switchover lifecycle is rare and important, so every stage gets a clear line
287
- function logTransitions(prev, next) {
288
- if (!prev.dying && next.dying) {
289
- let { successorStart, overlap } = next.dying;
290
- console.log(`${logPrefix()} Deploy switchover scheduled: our successor starts at ${iso(successorStart)}; fresh writes hand off at ${iso(successorStart + overlap * BOUNDARY_A_FRACTION)}, and we are killed at ${iso(successorStart + overlap)}`);
291
- }
292
- if (!prev.predecessorEnd && next.predecessorEnd) {
293
- console.log(`${logPrefix()} We are a deploy successor: our predecessor holds the main port until ${iso(next.predecessorEnd)}`);
294
- }
295
- if (!prev.remap && next.remap) {
296
- console.log(`${logPrefix()} Deploy switchover remap active: sources pointing at us are split so [${iso(next.remap.boundaryA)} .. ${iso(next.remap.boundaryB)}] routes to alternate port ${next.remap.altPort} (remap expires at ${iso(next.remap.expire)})`);
297
- }
298
- if (prev.remap && !next.remap) {
299
- console.log(`${logPrefix()} Deploy switchover remap ended; running on the plain stored routing config`);
300
- }
301
- }
302
- /** Starts the takeover machinery. Port fallback (alternate port + registry + acquisition polling)
303
- * works regardless; without a deploy timeline folder the switchover-specific parts (the remap,
304
- * the tighter acquisition pacing) simply stay inert. */
305
- async function initDeployTakeover(config) {
306
- var _a, _b;
307
- initialized = config;
308
- ancestorPids = await getAncestorPids();
309
- timelineFolder = getTimelineFolder();
310
- let entries = await readTimelineEntries();
311
- if (!entries.length) {
312
- console.log(`${logPrefix()} No deploy timeline entries in ${timelineFolder}; deploy takeover inactive until they appear (port fallback still works)`);
313
- }
314
- else {
315
- console.log(`${logPrefix()} Deploy timeline found at ${timelineFolder} (${entries.length} entries); our pid chain: ${[...ancestorPids].join(" -> ")}`);
316
- }
317
- await recompute();
318
- let poll = setInterval(() => {
319
- void recompute().catch((e) => { var _a; return console.error(`Deploy takeover recompute failed: ${(_a = e.stack) !== null && _a !== void 0 ? _a : e}`); });
320
- }, TIMELINE_POLL_INTERVAL);
321
- (_b = (_a = poll).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
322
- }
323
- exports.initDeployTakeover = initDeployTakeover;
324
- /** Called when we had to listen on an alternate port (the main port was still held by our
325
- * predecessor): registers it so the predecessor can route the middle overlap window to us. */
326
- async function registerAltPort(port) {
327
- ourAltPort = port;
328
- let folder = getRegistryFolder();
329
- await fs_1.default.promises.mkdir(folder, { recursive: true });
330
- let entry = { pid: process.pid, port, ancestorPids: [...ancestorPids] };
331
- await fs_1.default.promises.writeFile(path_1.default.join(folder, `${process.pid}.json`), JSON.stringify(entry));
332
- await recompute();
333
- }
334
- exports.registerAltPort = registerAltPort;
335
- function onTakeoverEvent(listener) {
336
- eventListeners.push(listener);
337
- }
338
- exports.onTakeoverEvent = onTakeoverEvent;
339
- /** The interpretation overlay: splits every source pointing at our domain+main port so the middle
340
- * of the deploy overlap points at the alternate port. Pure, in-memory only - the stored routing
341
- * config is never modified, and this must never be applied to data that gets persisted. */
342
- function applyDeployRemap(routing) {
343
- let remap = current.remap;
344
- let init = initialized;
345
- if (!remap || !init)
346
- return routing;
347
- let sources = [];
348
- let slice = (source, start, end, url) => {
349
- return { ...source, url: url || source.url, validWindow: [start, end] };
350
- };
351
- for (let source of routing.sources) {
352
- if (typeof source === "string" || source.type !== "remote") {
353
- sources.push(source);
55
+ let releaseTime = entry.parameters.releaseTime;
56
+ if (releaseTime === undefined)
354
57
  continue;
355
- }
356
- let parsed;
357
- try {
358
- parsed = (0, remoteConfig_1.parseHostedUrl)(source.url);
359
- }
360
- catch (_a) {
361
- sources.push(source);
58
+ let overlapTime = entry.parameters.overlapTime || 0;
59
+ if (releaseTime > now + DEPLOY_RELEASE_MATCH_WINDOW)
362
60
  continue;
363
- }
364
- if (parsed.address !== init.domain || parsed.port !== init.mainPort) {
365
- sources.push(source);
61
+ if (now > releaseTime + overlapTime + DEPLOY_RELEASE_MATCH_WINDOW)
366
62
  continue;
63
+ if (best && best.releaseTime >= releaseTime)
64
+ continue;
65
+ best = { releaseTime, overlapTime };
66
+ }
67
+ return best;
68
+ }
69
+ /** Called when the main port is already in use, which on a healthy machine only happens while our predecessor is still running a deploy overlap. Confirms that against the deploy timeline; if no deploy is in progress we are in a bad state (someone else holds our port) and the process must not keep running. */
70
+ async function detectDeployTakeover() {
71
+ for (let attempt = 1; attempt <= DEPLOY_DETECT_ATTEMPTS; attempt++) {
72
+ let entries = await readTimelineEntries();
73
+ let found = findOurRelease(entries, Date.now());
74
+ if (found) {
75
+ takeover = found;
76
+ console.log(`${logPrefix()} Our main port is in use and the deploy timeline confirms a release at ${iso(found.releaseTime)} with an overlap of ${found.overlapTime}ms: we are the successor. Our predecessor is killed at ${iso(found.releaseTime + found.overlapTime)}.`);
77
+ return found;
367
78
  }
368
- let [start, end] = source.validWindow;
369
- let a = Math.max(start, Math.min(remap.boundaryA, end));
370
- let b = Math.max(start, Math.min(remap.boundaryB, end));
371
- let added = false;
372
- if (a > start) {
373
- sources.push(slice(source, start, a));
374
- added = true;
375
- }
376
- if (b > a) {
377
- sources.push(slice(source, a, b, (0, remoteConfig_1.replaceHostedUrlPort)(source.url, remap.altPort)));
378
- added = true;
379
- }
380
- if (end > b) {
381
- sources.push(slice(source, b, end));
382
- added = true;
383
- }
384
- if (!added) {
385
- sources.push(source);
79
+ console.log(`${logPrefix()} Our main port is in use but the deploy timeline in ${getTimelineFolder()} shows no release in progress (attempt ${attempt} of ${DEPLOY_DETECT_ATTEMPTS}); retrying in ${DEPLOY_DETECT_RETRY_DELAY}ms`);
80
+ if (attempt < DEPLOY_DETECT_ATTEMPTS) {
81
+ await new Promise(resolve => setTimeout(resolve, DEPLOY_DETECT_RETRY_DELAY));
386
82
  }
387
83
  }
388
- return { version: routing.version, sources };
84
+ throw new Error(`Our main port is in use, but no deploy is in progress after ${DEPLOY_DETECT_ATTEMPTS * DEPLOY_DETECT_RETRY_DELAY}ms of checking the deploy timeline in ${getTimelineFolder()}. Something else is holding our port, so this process is in a bad state and is exiting.`);
389
85
  }
390
- exports.applyDeployRemap = applyDeployRemap;
391
- /** A stamp of the current remap interpretation, advertised in ping responses - so every connected
392
- * client learns of a takeover within one ping interval, instead of waiting for its config poll
393
- * or a write rejection. */
394
- function getTakeoverStamp() {
395
- let remap = current.remap;
396
- if (!remap)
397
- return undefined;
398
- return JSON.stringify(remap);
399
- }
400
- exports.getTakeoverStamp = getTakeoverStamp;
401
- /** The middle-window alternate port of an active remap. The OTHER process of the takeover lives on
402
- * this port on OUR machine (same disk!), so sources pointing at it are self, never sync targets. */
403
- function getTakeoverAltPort() {
404
- var _a;
405
- return (_a = current.remap) === null || _a === void 0 ? void 0 : _a.altPort;
86
+ exports.detectDeployTakeover = detectDeployTakeover;
87
+ function setAltPort(port) {
88
+ if (!takeover) {
89
+ throw new Error(`An alternate port (${port}) was taken without a detected deploy takeover - detectDeployTakeover must run first`);
90
+ }
91
+ takeover.altPort = port;
92
+ console.log(`${logPrefix()} Listening on alternate port ${port}: writes route here until ${iso(getIntermediateEnd())}, and we keep listening until ${iso(getAltPortListenEnd())}`);
93
+ (0, storageServerState_1.startIntermediateMaintenance)();
406
94
  }
407
- exports.getTakeoverAltPort = getTakeoverAltPort;
408
- /** For the dying process of a takeover: our own process's data ends at the write handoff - fast
409
- * writes must be on disk by then. Undefined for the successor and in normal operation. Both
410
- * processes share the config identity (all self windows look like "ours" to both), so this is
411
- * the only way the dying side knows the post-handoff windows belong to the other process. */
412
- function getOwnWindowEndClip() {
413
- let dying = current.dying;
414
- if (!dying)
95
+ exports.setAltPort = setAltPort;
96
+ /** The window in which writes belong to our alternate port: from the release until our predecessor is killed and we take the main port. */
97
+ function getTakeoverIntermediate() {
98
+ if (!(takeover === null || takeover === void 0 ? void 0 : takeover.altPort))
415
99
  return undefined;
416
- let remap = current.remap;
417
- if (remap)
418
- return remap.boundaryA;
419
- return dying.successorStart;
420
- }
421
- exports.getOwnWindowEndClip = getOwnWindowEndClip;
422
- /** How long to wait between main-port acquisition attempts: tight around the predecessor's
423
- * scheduled death (when the port actually frees), relaxed otherwise. */
100
+ return { start: takeover.releaseTime, end: getIntermediateEnd(), altPort: takeover.altPort };
101
+ }
102
+ exports.getTakeoverIntermediate = getTakeoverIntermediate;
103
+ function getIntermediateEnd() {
104
+ if (!takeover)
105
+ return 0;
106
+ return takeover.releaseTime + takeover.overlapTime;
107
+ }
108
+ /** We never stop listening on the alternate port while its window is still valid, and hold it well past that for clients that have not caught up yet. */
109
+ function getAltPortListenEnd() {
110
+ if (!takeover)
111
+ return 0;
112
+ return Math.max(takeover.releaseTime + takeover.overlapTime * 2, getIntermediateEnd() + ALT_PORT_LINGER);
113
+ }
114
+ exports.getAltPortListenEnd = getAltPortListenEnd;
115
+ /** How long to wait between main-port acquisition attempts: tight around our predecessor's scheduled death (when the port actually frees), relaxed otherwise. */
424
116
  function getMainPortAcquireDelay() {
425
- let end = current.predecessorEnd;
426
- if (end !== undefined && Math.abs(Date.now() - end) <= ACQUIRE_FAST_WINDOW) {
117
+ if (!takeover)
118
+ return ACQUIRE_SLOW_DELAY;
119
+ let predecessorEnd = takeover.releaseTime + takeover.overlapTime;
120
+ if (Date.now() >= predecessorEnd - ACQUIRE_FAST_WINDOW) {
427
121
  return ACQUIRE_FAST_DELAY;
428
122
  }
429
123
  return ACQUIRE_SLOW_DELAY;
430
124
  }
431
125
  exports.getMainPortAcquireDelay = getMainPortAcquireDelay;
432
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95VGFrZW92ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJkZXBsb3lUYWtlb3Zlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSw0Q0FBb0I7QUFDcEIsZ0RBQXdCO0FBQ3hCLGlEQUFxQztBQUVyQyxpREFBc0U7QUFFdEUsaUdBQWlHO0FBQ2pHLGlHQUFpRztBQUNqRyxrR0FBa0c7QUFDbEcsOEZBQThGO0FBQzlGLCtGQUErRjtBQUMvRixpR0FBaUc7QUFDakcsbUdBQW1HO0FBQ25HLDBGQUEwRjtBQUMxRixrR0FBa0c7QUFDbEcsK0ZBQStGO0FBQy9GLEVBQUU7QUFDRixpR0FBaUc7QUFDakcsZ0dBQWdHO0FBQ2hHLGlDQUFpQztBQUVqQyxNQUFNLDhCQUE4QixHQUFHLDBCQUEwQixDQUFDO0FBQ2xFLE1BQU0sc0JBQXNCLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUN6QyxtR0FBbUc7QUFDbkcsK0ZBQStGO0FBQy9GLDhEQUE4RDtBQUM5RCxNQUFNLHlCQUF5QixHQUFHLHFCQUFxQixDQUFDO0FBQ3hELG1HQUFtRztBQUNuRyxNQUFNLGtCQUFrQixHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDckMsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDO0FBQ3BDLE1BQU0sbUJBQW1CLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUN0QyxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLHFCQUFxQixHQUFHLENBQUMsQ0FBQztBQXVCaEMsSUFBSSxXQUFvRixDQUFDO0FBQ3pGLElBQUksWUFBWSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7QUFDckMsSUFBSSxjQUFrQyxDQUFDO0FBQ3ZDLElBQUksVUFBOEIsQ0FBQztBQUNuQyxJQUFJLE9BQU8sR0FBcUIsRUFBRSxDQUFDO0FBQ25DLElBQUksVUFBVSxHQUFH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bSBcInBhdGhcIjtcbmltcG9ydCB7IGV4ZWMgfSBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgUmVtb3RlQ29uZmlnLCBSZW1vdGVDb25maWdCYXNlLCBIb3N0ZWRDb25maWcgfSBmcm9tIFwiLi4vSUFyY2hpdmVzXCI7XG5pbXBvcnQgeyBwYXJzZUhvc3RlZFVybCwgcmVwbGFjZUhvc3RlZFVybFBvcnQgfSBmcm9tIFwiLi9yZW1vdGVDb25maWdcIjtcblxuLy8gRGVwbG95IHRha2VvdmVyOiB0aGUgZGVwbG95IG1hbmFnZXIgKHF1ZXJ5c3ViJ3MgcGFyYW1ldGVyc1RpbWVsaW5lKSB3cml0ZXMgPG4+LXBhcmFtZXRlcnMuanNvblxuLy8gZmlsZXMgaW50byBvdXIgaW5zdGFuY2UgZm9sZGVyIGRlc2NyaWJpbmcgd2hlbiBlYWNoIHZlcnNpb24gcnVucyBhbmQgd2hlbiBpdCBpcyBzaHV0IGRvd24uIE9sZFxuLy8gYW5kIG5ldyB2ZXJzaW9uIG92ZXJsYXAgZm9yIHRoZSBvdmVybGFwIHRpbWUgKE8gPSBvbGRFbmQgLSBuZXdTdGFydCkuIFdlIHR1cm4gdGhhdCBvdmVybGFwIGludG9cbi8vIGFuIGF0b21pYyB3cml0ZSBoYW5kb2ZmIGJ5IFJFSU5URVJQUkVUSU5HIGV2ZXJ5IHJvdXRpbmcgc291cmNlIHRoYXQgcG9pbnRzIGF0IHVzOiBpdHMgdmFsaWRcbi8vIHdpbmRvdyBpcyBzcGxpdCBzbyB0aGF0IHRoZSBtaWRkbGUgb2YgdGhlIG92ZXJsYXAgKFtTICsgMC41Kk8sIFMgKyAxLjUqT10pIHBvaW50cyBhdCB0aGUgbmV3XG4vLyBwcm9jZXNzJ3MgdGVtcG9yYXJ5IGFsdGVybmF0ZSBwb3J0LiBUaGUgZXhpc3RpbmcgdmFsaWQtd2luZG93IG1hY2hpbmVyeSB0aGVuIGRvZXMgZXZlcnl0aGluZyAtXG4vLyB0aGUgb2xkIHByb2Nlc3Mgc3RhcnRzIHJlamVjdGluZyBmcmVzaCB3cml0ZXMgYXQgdGhlIGZpcnN0IGJvdW5kYXJ5LCBjbGllbnRzIHJlLXJlc29sdmUsIGFuZCB0aGVcbi8vIG5ldyBwcm9jZXNzICh3aGljaCByZWNvZ25pemVzIHRoZSBhbHRlcm5hdGUgcG9ydCBhcyBpdHNlbGYpIHRha2VzIG92ZXIuIFRoZSByZW1hcCBpcyBhblxuLy8gSU5URVJQUkVUQVRJT04gT1ZFUkxBWSwgYXBwbGllZCB3aGVyZSByb3V0aW5nIGNvbmZpZ3MgYXJlIHVzZWQgKHNlZSBhcHBseURlcGxveVJlbWFwIGNhbGxlcnMpIC1cbi8vIGl0IGlzIG5ldmVyIHdyaXR0ZW4gdG8gZGlzaywgbmV2ZXIgc3luY2hyb25pemVkLCBhbmQgbmV2ZXIgcGFydCBvZiBhbnkgc3RvcmVkIGNvbmZpZ3VyYXRpb24uXG4vL1xuLy8gRXZlcnl0aGluZyBoZXJlIGlzIHJlY29tcHV0ZWQgaWRlbXBvdGVudGx5IGZyb20gaXRzIGlucHV0cyAodGltZWxpbmUgZmlsZXMsIHRoZSBwb3J0IHJlZ2lzdHJ5LFxuLy8gb3VyIGFuY2VzdG9yIHBpZHMsIHRoZSBjbG9jaykgLSBmaWxlcyBjYW4gYXBwZWFyIG9yIGNoYW5nZSBhdCBhbnkgbW9tZW50LCBhbmQgd2UgY2FuIHN0YXJ0IGF0XG4vLyBhbnkgcG9pbnQgZHVyaW5nIGEgc3dpdGNob3Zlci5cblxuY29uc3QgUEFSQU1FVEVSU19USU1FTElORV9GSUxFX1JFR0VYID0gL14oXFxkKyktcGFyYW1ldGVyc1xcLmpzb24kLztcbmNvbnN0IFRJTUVMSU5FX1BPTExfSU5URVJWQUwgPSA2MCAqIDEwMDA7XG4vLyBQcm9jZXNzZXMgbGlzdGVuaW5nIG9uIGFuIGFsdGVybmF0ZSBwb3J0IHJlZ2lzdGVyIGl0IGhlcmUgKHNpYmxpbmcgb2YgdGhlIHN0b3JhZ2UgZm9sZGVyKSwga2V5ZWRcbi8vIGJ5IHRoZWlyIGFjdHVhbCBwaWQ7IGNvbnRlbnQgaW5jbHVkZXMgdGhlaXIgYW5jZXN0b3IgcGlkcyBzbyB0aGUgdGltZWxpbmUgZW50cnkgcGlkIChhIHNoZWxsXG4vLyBhbmNlc3RvciBvZiB0aGUgcHJvY2VzcykgY2FuIGJlIG1hdGNoZWQgdG8gYSByZWdpc3RyeSBlbnRyeVxuY29uc3QgUE9SVF9SRUdJU1RSWV9GT0xERVJfTkFNRSA9IFwic3RvcmFnZVBvcnRSZWdpc3RyeVwiO1xuLy8gTWFpbi1wb3J0IGFjcXVpc2l0aW9uIGF0dGVtcHRzIHJ1biB0aGlzIG9mdGVuLCB0aWdodGVuaW5nIG5lYXIgdGhlIHByZWRlY2Vzc29yJ3Mgc2NoZWR1bGVkIGRlYXRoXG5jb25zdCBBQ1FVSVJFX1NMT1dfREVMQVkgPSAzMCAqIDEwMDA7XG5jb25zdCBBQ1FVSVJFX0ZBU1RfREVMQVkgPSA1ICogMTAwMDtcbmNvbnN0IEFDUVVJUkVfRkFTVF9XSU5ET1cgPSA2MCAqIDEwMDA7XG5jb25zdCBCT1VOREFSWV9BX0ZSQUNUSU9OID0gMC41O1xuY29uc3QgQk9VTkRBUllfQl9GUkFDVElPTiA9IDEuNTtcbmNvbnN0IFJFTUFQX0VYUElSRV9GUkFDVElPTiA9IDI7XG5cbnR5cGUgVGltZWxpbmVFbnRyeSA9IHtcbiAgICBwaWQ/OiBudW1iZXI7XG4gICAgLy8gcmVsZWFzZVRpbWUgKyBvdmVybGFwVGltZSBkZWZpbmUgZXZlcnl0aGluZzogdGhlIG5ld2VyIGVudHJ5J3MgcmVsZWFzZVRpbWUgaXMgd2hlbiBpdFxuICAgIC8vIHN0YXJ0cywgYW5kIHJlbGVhc2VUaW1lICsgb3ZlcmxhcFRpbWUgaXMgd2hlbiB0aGUgb2xkZXIgb25lIGlzIGtpbGxlZCAoZnJlZWluZyB0aGUgcG9ydCkuXG4gICAgLy8gVGhlIGZpbGVzIGFsc28gY2FycnkgYW4gYWxpdmVXaW5kb3csIHdoaWNoIGlzIGRlbGliZXJhdGVseSBpZ25vcmVkLlxuICAgIHBhcmFtZXRlcnM6IHsgcmVsZWFzZVRpbWU/OiBudW1iZXI7IG92ZXJsYXBUaW1lPzogbnVtYmVyIH07XG59O1xuXG50eXBlIFRha2VvdmVyQ29tcHV0ZWQgPSB7XG4gICAgLy8gV2UgYXJlIHNjaGVkdWxlZCB0byBkaWUgd2l0aCBhIHN1Y2Nlc3NvciBvdmVybGFwcGluZyB1cyAoa25vd24gZnJvbSB0aGUgZmlsZXMgYWxvbmUsIGJlZm9yZVxuICAgIC8vIHRoZSBzdWNjZXNzb3IncyBwb3J0IGlzIGRpc2NvdmVyZWQgLSB0aGUgZmx1c2ggZGVhZGxpbmUgYXBwbGllcyBpbW1lZGlhdGVseSlcbiAgICBkeWluZz86IHsgc3VjY2Vzc29yU3RhcnQ6IG51bWJlcjsgb3ZlcmxhcDogbnVtYmVyIH07XG4gICAgLy8gVGhlIHdpbmRvdyByZWludGVycHJldGF0aW9uLCBvbmNlIHRoZSBtaWRkbGUgd2luZG93J3MgcG9ydCBpcyBrbm93biAodGhlIHN1Y2Nlc3NvcidzXG4gICAgLy8gcmVnaXN0ZXJlZCBhbHRlcm5hdGUgcG9ydCAtIG9yIG91ciBvd24sIHdoZW4gd2UgQVJFIHRoZSBzdWNjZXNzb3IpXG4gICAgcmVtYXA/OiB7IGJvdW5kYXJ5QTogbnVtYmVyOyBib3VuZGFyeUI6IG51bWJlcjsgZXhwaXJlOiBudW1iZXI7IGFsdFBvcnQ6IG51bWJlciB9O1xuICAgIC8vIFdoZW4gb3VyIHByZWRlY2Vzc29yIGRpZXMgYW5kIGZyZWVzIHRoZSBtYWluIHBvcnQgKGZvciBhY3F1aXNpdGlvbiBwYWNpbmcpXG4gICAgcHJlZGVjZXNzb3JFbmQ/OiBudW1iZXI7XG59O1xuXG5leHBvcnQgdHlwZSBUYWtlb3ZlckV2ZW50ID0gXCJyZW1hcENoYW5nZWRcIjtcblxubGV0IGluaXRpYWxpemVkOiB7IGRvbWFpbjogc3RyaW5nOyBtYWluUG9ydDogbnVtYmVyOyBzdG9yYWdlRm9sZGVyOiBzdHJpbmcgfSB8IHVuZGVmaW5lZDtcbmxldCBhbmNlc3RvclBpZHMgPSBuZXcgU2V0PG51bWJlcj4oKTtcbmxldCB0aW1lbGluZUZvbGRlcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xubGV0IG91ckFsdFBvcnQ6IG51bWJlciB8IHVuZGVmaW5lZDtcbmxldCBjdXJyZW50OiBUYWtlb3ZlckNvbXB1dGVkID0ge307XG5sZXQgY3VycmVudEtleSA9IEpTT04uc3RyaW5naWZ5KGN1cnJlbnQpO1xubGV0IGV2ZW50TGlzdGVuZXJzOiAoKGV2ZW50OiBUYWtlb3ZlckV2ZW50KSA9PiB2b2lkKVtdID0gW107XG5sZXQgZXZlbnRUaW1lcnM6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+W10gPSBbXTtcbmxldCBsb2dnZWROb01hdGNoID0gZmFsc2U7XG5sZXQgbG9nZ2VkSWRlbnRpdHkgPSBmYWxzZTtcblxuZnVuY3Rpb24gZXhlY1RleHQoY29tbWFuZDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBleGVjKGNvbW1hbmQsIChlcnJvciwgc3Rkb3V0KSA9PiB7XG4gICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc29sdmUoc3Rkb3V0KTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59XG5cbi8vIFRoZSB0aW1lbGluZSBlbnRyeSBwaWQgaXMgdGhlIHNjcmVlbiBzaGVsbCB0aGF0IHNwYXduZWQgdXMgLSBhbiBhbmNlc3RvciAtIHNvIHdlIHdhbGsgb3VyIHdob2xlXG4vLyBhbmNlc3RvciBjaGFpbiB0byBmaW5kIHdoaWNoIGVudHJ5IGlzIHVzXG5hc3luYyBmdW5jdGlvbiBnZXRBbmNlc3RvclBpZHMoKTogUHJvbWlzZTxTZXQ8bnVtYmVyPj4ge1xuICAgIGxldCBwaWRzID0gbmV3IFNldDxudW1iZXI+KFtwcm9jZXNzLnBpZF0pO1xuICAgIGxldCBjdXJyZW50UGlkID0gcHJvY2Vzcy5waWQ7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgbGV0IHBwaWQ6IG51bWJlcjtcbiAgICAgICAgaWYgKGN1cnJlbnRQaWQgPT09IHByb2Nlc3MucGlkICYmIHByb2Nlc3MucHBpZCkge1xuICAgICAgICAgICAgcHBpZCA9IHByb2Nlc3MucHBpZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgcHBpZCA9IHBhcnNlSW50KChhd2FpdCBleGVjVGV4dChgcHMgLW8gcHBpZD0gLXAgJHtjdXJyZW50UGlkfWApKS50cmltKCkpO1xuICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFwcGlkIHx8IE51bWJlci5pc05hTihwcGlkKSB8fCBwcGlkIDw9IDEgfHwgcGlkcy5oYXMocHBpZCkpIGJyZWFrO1xuICAgICAgICBwaWRzLmFkZChwcGlkKTtcbiAgICAgICAgY3VycmVudFBpZCA9IHBwaWQ7XG4gICAgfVxuICAgIHJldHVybiBwaWRzO1xufVxuXG4vLyBUaGUgaW5zdGFuY2UgZm9sZGVyIGlzIEFMV0FZUyB0aGUgcGFyZW50IG9mIG91ciBjd2QgKHNlcnZpY2VzIHJ1biBpbiA8aW5zdGFuY2U+L2dpdC8pIC0gbmV2ZXJcbi8vIHNlYXJjaCBmb3IgaXQsIGEgd2FsayBjb3VsZCBsYXRjaCBvbnRvIHRoZSB3cm9uZyBmb2xkZXJcbmZ1bmN0aW9uIGdldFRpbWVsaW5lRm9sZGVyKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHBhdGguZGlybmFtZShwcm9jZXNzLmN3ZCgpKS5yZXBsYWNlQWxsKFwiXFxcXFwiLCBcIi9cIikgKyBcIi9cIjtcbn1cblxuZnVuY3Rpb24gcGlkQWxpdmUocGlkOiBudW1iZXIpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgICBwcm9jZXNzLmtpbGwocGlkLCAwKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gKGUgYXMgeyBjb2RlPzogc3RyaW5nIH0pLmNvZGUgPT09IFwiRVBFUk1cIjtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGdldFJlZ2lzdHJ5Rm9sZGVyKCk6IHN0cmluZyB7XG4gICAgaWYgKCFpbml0aWFsaXplZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYERlcGxveSB0YWtlb3ZlciBpcyBub3QgaW5pdGlhbGl6ZWRgKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhdGguam9pbihwYXRoLmRpcm5hbWUocGF0aC5yZXNvbHZlKGluaXRpYWxpemVkLnN0b3JhZ2VGb2xkZXIpKSwgUE9SVF9SRUdJU1RSWV9GT0xERVJfTkFNRSk7XG59XG5cbnR5cGUgUmVnaXN0cnlFbnRyeSA9IHsgcGlkOiBudW1iZXI7IHBvcnQ6IG51bWJlcjsgYW5jZXN0b3JQaWRzOiBudW1iZXJbXSB9O1xuXG5hc3luYyBmdW5jdGlvbiByZWFkUG9ydFJlZ2lzdHJ5KCk6IFByb21pc2U8UmVnaXN0cnlFbnRyeVtdPiB7XG4gICAgbGV0IGZvbGRlciA9IGdldFJlZ2lzdHJ5Rm9sZGVyKCk7XG4gICAgbGV0IGZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIHRyeSB7XG4gICAgICAgIGZpbGVzID0gYXdhaXQgZnMucHJvbWlzZXMucmVhZGRpcihmb2xkZXIpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIGxldCBlbnRyaWVzOiBSZWdpc3RyeUVudHJ5W10gPSBbXTtcbiAgICBmb3IgKGxldCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgIGxldCBtYXRjaCA9IC9eKFxcZCspXFwuanNvbiQvLmV4ZWMoZmlsZSk7XG4gICAgICAgIGlmICghbWF0Y2gpIGNvbnRpbnVlO1xuICAgICAgICBsZXQgcGlkID0gcGFyc2VJbnQobWF0Y2hbMV0pO1xuICAgICAgICBpZiAoIXBpZEFsaXZlKHBpZCkpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMudW5saW5rKHBhdGguam9pbihmb2xkZXIsIGZpbGUpKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggeyB9XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbGV0IGVudHJ5ID0gSlNPTi5wYXJzZShhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZShwYXRoLmpvaW4oZm9sZGVyLCBmaWxlKSwgXCJ1dGY4XCIpKSBhcyBSZWdpc3RyeUVudHJ5O1xuICAgICAgICAgICAgZW50cmllcy5wdXNoKHsgLi4uZW50cnksIHBpZCB9KTtcbiAgICAgICAgfSBjYXRjaCB7IH1cbiAgICB9XG4gICAgcmV0dXJuIGVudHJpZXM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRUaW1lbGluZUVudHJpZXMoKTogUHJvbWlzZTxUaW1lbGluZUVudHJ5W10+IHtcbiAgICBpZiAoIXRpbWVsaW5lRm9sZGVyKSByZXR1cm4gW107XG4gICAgbGV0IGVudHJpZXM6IFRpbWVsaW5lRW50cnlbXSA9IFtdO1xuICAgIGZvciAobGV0IGZpbGUgb2YgYXdhaXQgZnMucHJvbWlzZXMucmVhZGRpcih0aW1lbGluZUZvbGRlcikpIHtcbiAgICAgICAgaWYgKCFQQVJBTUVURVJTX1RJTUVMSU5FX0ZJTEVfUkVHRVgudGVzdChmaWxlKSkgY29udGludWU7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBlbnRyaWVzLnB1c2goSlNPTi5wYXJzZShhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZSh0aW1lbGluZUZvbGRlciArIGZpbGUsIFwidXRmOFwiKSkgYXMgVGltZWxpbmVFbnRyeSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihgQ291bGQgbm90IHJlYWQgZGVwbG95IHRpbWVsaW5lIGZpbGUgJHt0aW1lbGluZUZvbGRlciArIGZpbGV9OiAkeyhlIGFzIEVycm9yKS5zdGFjayA/PyBlfWApO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBlbnRyaWVzO1xufVxuXG5mdW5jdGlvbiBtYWtlUmVtYXAoc3VjY2Vzc29yU3RhcnQ6IG51bWJlciwgb3ZlcmxhcDogbnVtYmVyLCBhbHRQb3J0OiBudW1iZXIpOiBUYWtlb3ZlckNvbXB1dGVkW1wicmVtYXBcIl0ge1xuICAgIHJldHVybiB7XG4gICAgICAgIGJvdW5kYXJ5QTogc3VjY2Vzc29yU3RhcnQgKyBvdmVybGFwICogQk9VTkRBUllfQV9GUkFDVElPTixcbiAgICAgICAgYm91bmRhcnlCOiBzdWNjZXNzb3JTdGFydCArIG92ZXJsYXAgKiBCT1VOREFSWV9CX0ZSQUNUSU9OLFxuICAgICAgICBleHBpcmU6IHN1Y2Nlc3NvclN0YXJ0ICsgb3ZlcmxhcCAqIFJFTUFQX0VYUElSRV9GUkFDVElPTixcbiAgICAgICAgYWx0UG9ydCxcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBlbWl0KGV2ZW50OiBUYWtlb3ZlckV2ZW50KTogdm9pZCB7XG4gICAgZm9yIChsZXQgbGlzdGVuZXIgb2YgZXZlbnRMaXN0ZW5lcnMpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxpc3RlbmVyKGV2ZW50KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRGVwbG95IHRha2VvdmVyIGxpc3RlbmVyIGZhaWxlZDogJHsoZSBhcyBFcnJvcikuc3RhY2sgPz8gZX1gKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZnVuY3Rpb24gc2NoZWR1bGVFdmVudHMoKTogdm9pZCB7XG4gICAgZm9yIChsZXQgdGltZXIgb2YgZXZlbnRUaW1lcnMpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICB9XG4gICAgZXZlbnRUaW1lcnMgPSBbXTtcbiAgICBsZXQgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBsZXQgc2NoZWR1bGUgPSAodGltZTogbnVtYmVyLCBmbmM6ICgpID0+IHZvaWQpID0+IHtcbiAgICAgICAgaWYgKHRpbWUgPD0gbm93KSByZXR1cm47XG4gICAgICAgIGxldCB0aW1lciA9IHNldFRpbWVvdXQoZm5jLCB0aW1lIC0gbm93KTtcbiAgICAgICAgKHRpbWVyIGFzIHsgdW5yZWY/OiAoKSA9PiB2b2lkIH0pLnVucmVmPy4oKTtcbiAgICAgICAgZXZlbnRUaW1lcnMucHVzaCh0aW1lcik7XG4gICAgfTtcbiAgICBjb25zdCByZW1hcCA9IGN1cnJlbnQucmVtYXA7XG4gICAgaWYgKHJlbWFwKSB7XG4gICAgICAgIGxldCBhbHRQb3J0ID0gcmVtYXAuYWx0UG9ydDtcbiAgICAgICAgc2NoZWR1bGUocmVtYXAuYm91bmRhcnlBLCAoKSA9PiBjb25zb2xlLmxvZyhgJHtsb2dQcmVmaXgoKX0gRGVwbG95IHN3aXRjaG92ZXIgd3JpdGUgaGFuZG9mZiBib3VuZGFyeSAke2lzbyhyZW1hcC5ib3VuZGFyeUEpfSBwYXNzZWQ6IGZyZXNoIHdyaXRlcyBub3cgYmVsb25nIHRvIHRoZSBhbHRlcm5hdGUtcG9ydCBzaWRlIChwb3J0ICR7YWx0UG9ydH0pYCkpO1xuICAgICAgICBzY2hlZHVsZShyZW1hcC5ib3VuZGFyeUIsICgpID0+IGNvbnNvbGUubG9nKGAke2xvZ1ByZWZpeCgpfSBEZXBsb3kgc3dpdGNob3ZlciBzZWNvbmQgYm91bmRhcnkgJHtpc28ocmVtYXAuYm91bmRhcnlCKX0gcGFzc2VkOiBmcmVzaCB3cml0ZXMgcmV0dXJuIHRvIHRoZSBtYWluIHBvcnRgKSk7XG4gICAgICAgIHNjaGVkdWxlKHJlbWFwLmV4cGlyZSwgKCkgPT4gdm9pZCByZWNvbXB1dGUoKS5jYXRjaCgoZTogRXJyb3IpID0+IGNvbnNvbGUuZXJyb3IoYERlcGxveSB0YWtlb3ZlciByZWNvbXB1dGUgZmFpbGVkOiAke2Uuc3RhY2sgPz8gZX1gKSkpO1xuICAgIH1cbn1cblxuLy8gTXVsdGlwbGUgcHJvY2Vzc2VzIChwcmVkZWNlc3NvciArIHN1Y2Nlc3Nvcikgb2Z0ZW4gc2hhcmUgb25lIGpvdXJuYWwgZHVyaW5nIGEgc3dpdGNob3Zlciwgc29cbi8vIGV2ZXJ5IGxpZmVjeWNsZSBsaW5lIGlkZW50aWZpZXMgaXRzIHByb2Nlc3NcbmZ1bmN0aW9uIGxvZ1ByZWZpeCgpOiBzdHJpbmcge1xuICAgIHJldHVybiBgW3BpZCAke3Byb2Nlc3MucGlkfV1gO1xufVxuXG4vLyBSZWNvbXB1dGUgaXMgaW52b2tlZCBmcm9tIGluaXQsIHJlZ2lzdGVyQWx0UG9ydCwgdGhlIHBvbGwsIGFuZCB0aGUgZXhwaXJ5IHRpbWVyIC0gcG9zc2libHlcbi8vIGNvbmN1cnJlbnRseS4gUnVucyBhcmUgc2VyaWFsaXplZCwgb3IgdHdvIGluLWZsaWdodCBydW5zIHdvdWxkIGJvdGggcGFzcyB0aGUgY2hhbmdlZC1zdGF0ZSBjaGVja1xuLy8gYW5kIGRvdWJsZS1maXJlIGV2ZXJ5IHRyYW5zaXRpb24gKGxvZ3MsIHJlYnVpbGQgZXZlbnRzLCB0aW1lcnMpLlxubGV0IHJlY29tcHV0ZUNoYWluID0gUHJvbWlzZS5yZXNvbHZlKCk7XG5mdW5jdGlvbiByZWNvbXB1dGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IG5leHQgPSByZWNvbXB1dGVDaGFpbi50aGVuKCgpID0+IHJlY29tcHV0ZU5vdygpKTtcbiAgICByZWNvbXB1dGVDaGFpbiA9IG5leHQudGhlbigoKSA9PiB7IH0sICgpID0+IHsgfSk7XG4gICAgcmV0dXJuIG5leHQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlY29tcHV0ZU5vdygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIWluaXRpYWxpemVkIHx8ICF0aW1lbGluZUZvbGRlcikgcmV0dXJuO1xuICAgIGxldCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGxldCBlbnRyaWVzID0gYXdhaXQgcmVhZFRpbWVsaW5lRW50cmllcygpO1xuICAgIGxldCByZWdpc3RyeSA9IGF3YWl0IHJlYWRQb3J0UmVnaXN0cnkoKTtcbiAgICBsZXQgdXM6IFRpbWVsaW5lRW50cnkgfCB1bmRlZmluZWQ7XG4gICAgZm9yIChsZXQgZW50cnkgb2YgZW50cmllcykge1xuICAgICAgICBpZiAoZW50cnkucGlkICYmIGFuY2VzdG9yUGlkcy5oYXMoZW50cnkucGlkKSkge1xuICAgICAgICAgICAgdXMgPSBlbnRyeTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBNYXRjaGluZyBmYWlsdXJlcyBtdXN0IGJlIGxvdWQsIG9yIHRha2VvdmVyIGRldGVjdGlvbiBmYWlscyBzaWxlbnRseSBmb3JldmVyXG4gICAgaWYgKCF1cyAmJiBlbnRyaWVzLmxlbmd0aCAmJiAhbG9nZ2VkTm9NYXRjaCkge1xuICAgICAgICBsb2dnZWROb01hdGNoID0gdHJ1ZTtcbiAgICAgICAgY29uc29sZS53YXJuKGAke2xvZ1ByZWZpeCgpfSBObyBkZXBsb3kgdGltZWxpbmUgZW50cnkgbWF0Y2hlcyBvdXIgcGlkIGNoYWluICgke1suLi5hbmNlc3RvclBpZHNdLmpvaW4oXCIsIFwiKX0pIC0gdGFrZW92ZXIgZGV0ZWN0aW9uIGNhbm5vdCB3b3JrLiBFbnRyaWVzOiAke2VudHJpZXMubWFwKHggPT4gYHBpZD0ke3gucGlkID8/IFwibm9uZVwifSByZWxlYXNlVGltZT0ke3gucGFyYW1ldGVycy5yZWxlYXNlVGltZX1gKS5qb2luKFwiIHwgXCIpfWApO1xuICAgIH1cbiAgICBpZiAodXMgJiYgIWxvZ2dlZElkZW50aXR5KSB7XG4gICAgICAgIGxvZ2dlZElkZW50aXR5ID0gdHJ1ZTtcbiAgICAgICAgY29uc29sZS5sb2coYCR7bG9nUHJlZml4KCl9IERlcGxveSB0aW1lbGluZSBlbnRyeSBtYXRjaGVkOiB3ZSBhcmUgcGlkPSR7dXMucGlkfSwgcmVsZWFzZVRpbWU9JHt1cy5wYXJhbWV0ZXJzLnJlbGVhc2VUaW1lICE9PSB1bmRlZmluZWQgJiYgaXNvKHVzLnBhcmFtZXRlcnMucmVsZWFzZVRpbWUpIHx8IFwidW5rbm93blwifSwgJHtlbnRyaWVzLmxlbmd0aH0gZW50cmllcyB0b3RhbGApO1xuICAgIH1cbiAgICBsZXQgY29tcHV0ZWQ6IFRha2VvdmVyQ29tcHV0ZWQgPSB7fTtcbiAgICBsZXQgdXNSZWxlYXNlID0gdXM/LnBhcmFtZXRlcnMucmVsZWFzZVRpbWU7XG4gICAgaWYgKHVzICYmIHVzUmVsZWFzZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vIFRoZSBuZXdlciBlbnRyeSdzIHJlbGVhc2VUaW1lIGlzIHdoZW4gaXQgc3RhcnRzOyByZWxlYXNlVGltZSArIG92ZXJsYXBUaW1lIGlzIHdoZW4gdGhlXG4gICAgICAgIC8vIG9sZGVyIG9uZSBpcyBraWxsZWQuIFRoYXQncyB0aGUgd2hvbGUgdGltZWxpbmUuXG4gICAgICAgIGxldCBuZXh0OiB7IGVudHJ5OiBUaW1lbGluZUVudHJ5OyByZWxlYXNlOiBudW1iZXIgfSB8IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IHByZXY6IHsgZW50cnk6IFRpbWVsaW5lRW50cnk7IHJlbGVhc2U6IG51bWJlciB9IHwgdW5kZWZpbmVkO1xuICAgICAgICBmb3IgKGxldCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgICAgICAgICBpZiAoZW50cnkgPT09IHVzKSBjb250aW51ZTtcbiAgICAgICAgICAgIGxldCByZWxlYXNlID0gZW50cnkucGFyYW1ldGVycy5yZWxlYXNlVGltZTtcbiAgICAgICAgICAgIGlmIChyZWxlYXNlID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKHJlbGVhc2UgPiB1c1JlbGVhc2UgJiYgKCFuZXh0IHx8IHJlbGVhc2UgPCBuZXh0LnJlbGVhc2UpKSB7XG4gICAgICAgICAgICAgICAgbmV4dCA9IHsgZW50cnksIHJlbGVhc2UgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChyZWxlYXNlIDwgdXNSZWxlYXNlICYmICghcHJldiB8fCByZWxlYXNlID4gcHJldi5yZWxlYXNlKSkge1xuICAgICAgICAgICAgICAgIHByZXYgPSB7IGVudHJ5LCByZWxlYXNlIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG5leHQpIHtcbiAgICAgICAgICAgIGxldCBzdWNjZXNzb3JTdGFydCA9IG5leHQucmVsZWFzZTtcbiAgICAgICAgICAgIGxldCBvdmVybGFwID0gbmV4dC5lbnRyeS5wYXJhbWV0ZXJzLm92ZXJsYXBUaW1lIHx8IHVzLnBhcmFtZXRlcnMub3ZlcmxhcFRpbWUgfHwgMDtcbiAgICAgICAgICAgIC8vIFRyYWNrZWQgZXZlbiBmb3IgYSBaRVJPLW92ZXJsYXAgZGVwbG95ICh0aGUgc2NoZWR1bGVkLXN3aXRjaG92ZXIgbG9nIG11c3Qgc3RpbGxcbiAgICAgICAgICAgIC8vIGZpcmUpOyBvbmx5IHRoZSByZW1hcCAodGhlIGFsdGVybmF0ZS1wb3J0IG1pZGRsZSB3aW5kb3cpIG5lZWRzIGFuIGFjdHVhbCBvdmVybGFwLlxuICAgICAgICAgICAgLy8gRmx1c2hpbmcgYmVmb3JlIHRoZSBoYW5kb2ZmIG5lZWRzIG5vdGhpbmcgc3BlY2lhbCBoZXJlOiB0aGUgcmVtYXAgZW5kcyBvdXIgdmFsaWRcbiAgICAgICAgICAgIC8vIHdpbmRvdywgYW5kIGZhc3Qgd3JpdGVzIGFsd2F5cyBmbHVzaCBhaGVhZCBvZiB0aGVpciB3aW5kb3cncyBlbmQuXG4gICAgICAgICAgICBjb21wdXRlZC5keWluZyA9IHsgc3VjY2Vzc29yU3RhcnQsIG92ZXJsYXAgfTtcbiAgICAgICAgICAgIGlmIChvdmVybGFwID4gMCAmJiBub3cgPCBzdWNjZXNzb3JTdGFydCArIG92ZXJsYXAgKiBSRU1BUF9FWFBJUkVfRlJBQ1RJT04pIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzdWNjZXNzb3JQaWQgPSBuZXh0LmVudHJ5LnBpZDtcbiAgICAgICAgICAgICAgICBpZiAoc3VjY2Vzc29yUGlkKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCBzdWNjZXNzb3JFbnRyeSA9IHJlZ2lzdHJ5LmZpbmQoeCA9PiB4LmFuY2VzdG9yUGlkcy5pbmNsdWRlcyhzdWNjZXNzb3JQaWQpKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHN1Y2Nlc3NvckVudHJ5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb21wdXRlZC5yZW1hcCA9IG1ha2VSZW1hcChzdWNjZXNzb3JTdGFydCwgb3ZlcmxhcCwgc3VjY2Vzc29yRW50cnkucG9ydCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHByZXYpIHtcbiAgICAgICAgICAgIGxldCBvdmVybGFwID0gdXMucGFyYW1ldGVycy5vdmVybGFwVGltZSB8fCBwcmV2LmVudHJ5LnBhcmFtZXRlcnMub3ZlcmxhcFRpbWUgfHwgMDtcbiAgICAgICAgICAgIC8vIFRoZSBwcmVkZWNlc3NvciBob2xkcyB0aGUgbWFpbiBwb3J0IHVudGlsIE9VUiByZWxlYXNlICsgdGhlIG92ZXJsYXBcbiAgICAgICAgICAgIGNvbXB1dGVkLnByZWRlY2Vzc29yRW5kID0gdXNSZWxlYXNlICsgb3ZlcmxhcDtcbiAgICAgICAgICAgIGlmIChvdmVybGFwID4gMCAmJiBvdXJBbHRQb3J0ICYmIG5vdyA8IHVzUmVsZWFzZSArIG92ZXJsYXAgKiBSRU1BUF9FWFBJUkVfRlJBQ1RJT04gJiYgIWNvbXB1dGVkLnJlbWFwKSB7XG4gICAgICAgICAgICAgICAgY29tcHV0ZWQucmVtYXAgPSBtYWtlUmVtYXAodXNSZWxlYXNlLCBvdmVybGFwLCBvdXJBbHRQb3J0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBsZXQga2V5ID0gSlNPTi5zdHJpbmdpZnkoY29tcHV0ZWQpO1xuICAgIGlmIChrZXkgPT09IGN1cnJlbnRLZXkpIHJldHVybjtcbiAgICBsb2dUcmFuc2l0aW9ucyhjdXJyZW50LCBjb21wdXRlZCk7XG4gICAgY3VycmVudCA9IGNvbXB1dGVkO1xuICAgIGN1cnJlbnRLZXkgPSBrZXk7XG4gICAgc2NoZWR1bGVFdmVudHMoKTtcbiAgICBlbWl0KFwicmVtYXBDaGFuZ2VkXCIpO1xufVxuXG5mdW5jdGlvbiBpc28odGltZTogbnVtYmVyKTogc3RyaW5nIHtcbiAgICByZXR1cm4gbmV3IERhdGUodGltZSkudG9JU09TdHJpbmcoKTtcbn1cblxuLy8gVGhlIHN3aXRjaG92ZXIgbGlmZWN5Y2xlIGlzIHJhcmUgYW5kIGltcG9ydGFudCwgc28gZXZlcnkgc3RhZ2UgZ2V0cyBhIGNsZWFyIGxpbmVcbmZ1bmN0aW9uIGxvZ1RyYW5zaXRpb25zKHByZXY6IFRha2VvdmVyQ29tcHV0ZWQsIG5leHQ6IFRha2VvdmVyQ29tcHV0ZWQpOiB2b2lkIHtcbiAgICBpZiAoIXByZXYuZHlpbmcgJiYgbmV4dC5keWluZykge1xuICAgICAgICBsZXQgeyBzdWNjZXNzb3JTdGFydCwgb3ZlcmxhcCB9ID0gbmV4dC5keWluZztcbiAgICAgICAgY29uc29sZS5sb2coYCR7bG9nUHJlZml4KCl9IERlcGxveSBzd2l0Y2hvdmVyIHNjaGVkdWxlZDogb3VyIHN1Y2Nlc3NvciBzdGFydHMgYXQgJHtpc28oc3VjY2Vzc29yU3RhcnQpfTsgZnJlc2ggd3JpdGVzIGhhbmQgb2ZmIGF0ICR7aXNvKHN1Y2Nlc3NvclN0YXJ0ICsgb3ZlcmxhcCAqIEJPVU5EQVJZX0FfRlJBQ1RJT04pfSwgYW5kIHdlIGFyZSBraWxsZWQgYXQgJHtpc28oc3VjY2Vzc29yU3RhcnQgKyBvdmVybGFwKX1gKTtcbiAgICB9XG4gICAgaWYgKCFwcmV2LnByZWRlY2Vzc29yRW5kICYmIG5leHQucHJlZGVjZXNzb3JFbmQpIHtcbiAgICAgICAgY29uc29sZS5sb2coYCR7bG9nUHJlZml4KCl9IFdlIGFyZSBhIGRlcGxveSBzdWNjZXNzb3I6IG91ciBwcmVkZWNlc3NvciBob2xkcyB0aGUgbWFpbiBwb3J0IHVudGlsICR7aXNvKG5leHQucHJlZGVjZXNzb3JFbmQpfWApO1xuICAgIH1cbiAgICBpZiAoIXByZXYucmVtYXAgJiYgbmV4dC5yZW1hcCkge1xuICAgICAgICBjb25zb2xlLmxvZyhgJHtsb2dQcmVmaXgoKX0gRGVwbG95IHN3aXRjaG92ZXIgcmVtYXAgYWN0aXZlOiBzb3VyY2VzIHBvaW50aW5nIGF0IHVzIGFyZSBzcGxpdCBzbyBbJHtpc28obmV4dC5yZW1hcC5ib3VuZGFyeUEpfSAuLiAke2lzbyhuZXh0LnJlbWFwLmJvdW5kYXJ5Qil9XSByb3V0ZXMgdG8gYWx0ZXJuYXRlIHBvcnQgJHtuZXh0LnJlbWFwLmFsdFBvcnR9IChyZW1hcCBleHBpcmVzIGF0ICR7aXNvKG5leHQucmVtYXAuZXhwaXJlKX0pYCk7XG4gICAgfVxuICAgIGlmIChwcmV2LnJlbWFwICYmICFuZXh0LnJlbWFwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke2xvZ1ByZWZpeCgpfSBEZXBsb3kgc3dpdGNob3ZlciByZW1hcCBlbmRlZDsgcnVubmluZyBvbiB0aGUgcGxhaW4gc3RvcmVkIHJvdXRpbmcgY29uZmlnYCk7XG4gICAgfVxufVxuXG4vKiogU3RhcnRzIHRoZSB0YWtlb3ZlciBtYWNoaW5lcnkuIFBvcnQgZmFsbGJhY2sgKGFsdGVybmF0ZSBwb3J0ICsgcmVnaXN0cnkgKyBhY3F1aXNpdGlvbiBwb2xsaW5nKVxuICogIHdvcmtzIHJlZ2FyZGxlc3M7IHdpdGhvdXQgYSBkZXBsb3kgdGltZWxpbmUgZm9sZGVyIHRoZSBzd2l0Y2hvdmVyLXNwZWNpZmljIHBhcnRzICh0aGUgcmVtYXAsXG4gKiAgdGhlIHRpZ2h0ZXIgYWNxdWlzaXRpb24gcGFjaW5nKSBzaW1wbHkgc3RheSBpbmVydC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbml0RGVwbG95VGFrZW92ZXIoY29uZmlnOiB7IGRvbWFpbjogc3RyaW5nOyBtYWluUG9ydDogbnVtYmVyOyBzdG9yYWdlRm9sZGVyOiBzdHJpbmcgfSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGluaXRpYWxpemVkID0gY29uZmlnO1xuICAgIGFuY2VzdG9yUGlkcyA9IGF3YWl0IGdldEFuY2VzdG9yUGlkcygpO1xuICAgIHRpbWVsaW5lRm9sZGVyID0gZ2V0VGltZWxpbmVGb2xkZXIoKTtcbiAgICBsZXQgZW50cmllcyA9IGF3YWl0IHJlYWRUaW1lbGluZUVudHJpZXMoKTtcbiAgICBpZiAoIWVudHJpZXMubGVuZ3RoKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke2xvZ1ByZWZpeCgpfSBObyBkZXBsb3kgdGltZWxpbmUgZW50cmllcyBpbiAke3RpbWVsaW5lRm9sZGVyfTsgZGVwbG95IHRha2VvdmVyIGluYWN0aXZlIHVudGlsIHRoZXkgYXBwZWFyIChwb3J0IGZhbGxiYWNrIHN0aWxsIHdvcmtzKWApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke2xvZ1ByZWZpeCgpfSBEZXBsb3kgdGltZWxpbmUgZm91bmQgYXQgJHt0aW1lbGluZUZvbGRlcn0gKCR7ZW50cmllcy5sZW5ndGh9IGVudHJpZXMpOyBvdXIgcGlkIGNoYWluOiAke1suLi5hbmNlc3RvclBpZHNdLmpvaW4oXCIgLT4gXCIpfWApO1xuICAgIH1cbiAgICBhd2FpdCByZWNvbXB1dGUoKTtcbiAgICBsZXQgcG9sbCA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgdm9pZCByZWNvbXB1dGUoKS5jYXRjaCgoZTogRXJyb3IpID0+IGNvbnNvbGUuZXJyb3IoYERlcGxveSB0YWtlb3ZlciByZWNvbXB1dGUgZmFpbGVkOiAke2Uuc3RhY2sgPz8gZX1gKSk7XG4gICAgfSwgVElNRUxJTkVfUE9MTF9JTlRFUlZBTCk7XG4gICAgKHBvbGwgYXMgeyB1bnJlZj86ICgpID0+IHZvaWQgfSkudW5yZWY/LigpO1xufVxuXG4vKiogQ2FsbGVkIHdoZW4gd2UgaGFkIHRvIGxpc3RlbiBvbiBhbiBhbHRlcm5hdGUgcG9ydCAodGhlIG1haW4gcG9ydCB3YXMgc3RpbGwgaGVsZCBieSBvdXJcbiAqICBwcmVkZWNlc3Nvcik6IHJlZ2lzdGVycyBpdCBzbyB0aGUgcHJlZGVjZXNzb3IgY2FuIHJvdXRlIHRoZSBtaWRkbGUgb3ZlcmxhcCB3aW5kb3cgdG8gdXMuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVnaXN0ZXJBbHRQb3J0KHBvcnQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIG91ckFsdFBvcnQgPSBwb3J0O1xuICAgIGxldCBmb2xkZXIgPSBnZXRSZWdpc3RyeUZvbGRlcigpO1xuICAgIGF3YWl0IGZzLnByb21pc2VzLm1rZGlyKGZvbGRlciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgbGV0IGVudHJ5OiBSZWdpc3RyeUVudHJ5ID0geyBwaWQ6IHByb2Nlc3MucGlkLCBwb3J0LCBhbmNlc3RvclBpZHM6IFsuLi5hbmNlc3RvclBpZHNdIH07XG4gICAgYXdhaXQgZnMucHJvbWlzZXMud3JpdGVGaWxlKHBhdGguam9pbihmb2xkZXIsIGAke3Byb2Nlc3MucGlkfS5qc29uYCksIEpTT04uc3RyaW5naWZ5KGVudHJ5KSk7XG4gICAgYXdhaXQgcmVjb21wdXRlKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBvblRha2VvdmVyRXZlbnQobGlzdGVuZXI6IChldmVudDogVGFrZW92ZXJFdmVudCkgPT4gdm9pZCk6IHZvaWQge1xuICAgIGV2ZW50TGlzdGVuZXJzLnB1c2gobGlzdGVuZXIpO1xufVxuXG4vKiogVGhlIGludGVycHJldGF0aW9uIG92ZXJsYXk6IHNwbGl0cyBldmVyeSBzb3VyY2UgcG9pbnRpbmcgYXQgb3VyIGRvbWFpbittYWluIHBvcnQgc28gdGhlIG1pZGRsZVxuICogIG9mIHRoZSBkZXBsb3kgb3ZlcmxhcCBwb2ludHMgYXQgdGhlIGFsdGVybmF0ZSBwb3J0LiBQdXJlLCBpbi1tZW1vcnkgb25seSAtIHRoZSBzdG9yZWQgcm91dGluZ1xuICogIGNvbmZpZyBpcyBuZXZlciBtb2RpZmllZCwgYW5kIHRoaXMgbXVzdCBuZXZlciBiZSBhcHBsaWVkIHRvIGRhdGEgdGhhdCBnZXRzIHBlcnNpc3RlZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBseURlcGxveVJlbWFwKHJvdXRpbmc6IFJlbW90ZUNvbmZpZyk6IFJlbW90ZUNvbmZpZyB7XG4gICAgbGV0IHJlbWFwID0gY3VycmVudC5yZW1hcDtcbiAgICBsZXQgaW5pdCA9IGluaXRpYWxpemVkO1xuICAgIGlmICghcmVtYXAgfHwgIWluaXQpIHJldHVybiByb3V0aW5nO1xuICAgIGxldCBzb3VyY2VzOiBSZW1vdGVDb25maWdCYXNlW10gPSBbXTtcbiAgICBsZXQgc2xpY2UgPSAoc291cmNlOiBIb3N0ZWRDb25maWcsIHN0YXJ0OiBudW1iZXIsIGVuZDogbnVtYmVyLCB1cmw/OiBzdHJpbmcpOiBIb3N0ZWRDb25maWcgPT4ge1xuICAgICAgICByZXR1cm4geyAuLi5zb3VyY2UsIHVybDogdXJsIHx8IHNvdXJjZS51cmwsIHZhbGlkV2luZG93OiBbc3RhcnQsIGVuZF0gfTtcbiAgICB9O1xuICAgIGZvciAobGV0IHNvdXJjZSBvZiByb3V0aW5nLnNvdXJjZXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBzb3VyY2UgPT09IFwic3RyaW5nXCIgfHwgc291cmNlLnR5cGUgIT09IFwicmVtb3RlXCIpIHtcbiAgICAgICAgICAgIHNvdXJjZXMucHVzaChzb3VyY2UpO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHBhcnNlZDogeyBhZGRyZXNzOiBzdHJpbmc7IHBvcnQ6IG51bWJlciB9O1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcGFyc2VkID0gcGFyc2VIb3N0ZWRVcmwoc291cmNlLnVybCk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgc291cmNlcy5wdXNoKHNvdXJjZSk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocGFyc2VkLmFkZHJlc3MgIT09IGluaXQuZG9tYWluIHx8IHBhcnNlZC5wb3J0ICE9PSBpbml0Lm1haW5Qb3J0KSB7XG4gICAgICAgICAgICBzb3VyY2VzLnB1c2goc291cmNlKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGxldCBbc3RhcnQsIGVuZF0gPSBzb3VyY2UudmFsaWRXaW5kb3c7XG4gICAgICAgIGxldCBhID0gTWF0aC5tYXgoc3RhcnQsIE1hdGgubWluKHJlbWFwLmJvdW5kYXJ5QSwgZW5kKSk7XG4gICAgICAgIGxldCBiID0gTWF0aC5tYXgoc3RhcnQsIE1hdGgubWluKHJlbWFwLmJvdW5kYXJ5QiwgZW5kKSk7XG4gICAgICAgIGxldCBhZGRlZCA9IGZhbHNlO1xuICAgICAgICBpZiAoYSA+IHN0YXJ0KSB7XG4gICAgICAgICAgICBzb3VyY2VzLnB1c2goc2xpY2Uoc291cmNlLCBzdGFydCwgYSkpO1xuICAgICAgICAgICAgYWRkZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChiID4gYSkge1xuICAgICAgICAgICAgc291cmNlcy5wdXNoKHNsaWNlKHNvdXJjZSwgYSwgYiwgcmVwbGFjZUhvc3RlZFVybFBvcnQoc291cmNlLnVybCwgcmVtYXAuYWx0UG9ydCkpKTtcbiAgICAgICAgICAgIGFkZGVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZW5kID4gYikge1xuICAgICAgICAgICAgc291cmNlcy5wdXNoKHNsaWNlKHNvdXJjZSwgYiwgZW5kKSk7XG4gICAgICAgICAgICBhZGRlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFhZGRlZCkge1xuICAgICAgICAgICAgc291cmNlcy5wdXNoKHNvdXJjZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgdmVyc2lvbjogcm91dGluZy52ZXJzaW9uLCBzb3VyY2VzIH07XG59XG5cbi8qKiBBIHN0YW1wIG9mIHRoZSBjdXJyZW50IHJlbWFwIGludGVycHJldGF0aW9uLCBhZHZlcnRpc2VkIGluIHBpbmcgcmVzcG9uc2VzIC0gc28gZXZlcnkgY29ubmVjdGVkXG4gKiAgY2xpZW50IGxlYXJucyBvZiBhIHRha2VvdmVyIHdpdGhpbiBvbmUgcGluZyBpbnRlcnZhbCwgaW5zdGVhZCBvZiB3YWl0aW5nIGZvciBpdHMgY29uZmlnIHBvbGxcbiAqICBvciBhIHdyaXRlIHJlamVjdGlvbi4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUYWtlb3ZlclN0YW1wKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IHJlbWFwID0gY3VycmVudC5yZW1hcDtcbiAgICBpZiAoIXJlbWFwKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShyZW1hcCk7XG59XG5cbi8qKiBUaGUgbWlkZGxlLXdpbmRvdyBhbHRlcm5hdGUgcG9ydCBvZiBhbiBhY3RpdmUgcmVtYXAuIFRoZSBPVEhFUiBwcm9jZXNzIG9mIHRoZSB0YWtlb3ZlciBsaXZlcyBvblxuICogIHRoaXMgcG9ydCBvbiBPVVIgbWFjaGluZSAoc2FtZSBkaXNrISksIHNvIHNvdXJjZXMgcG9pbnRpbmcgYXQgaXQgYXJlIHNlbGYsIG5ldmVyIHN5bmMgdGFyZ2V0cy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUYWtlb3ZlckFsdFBvcnQoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gY3VycmVudC5yZW1hcD8uYWx0UG9ydDtcbn1cblxuLyoqIEZvciB0aGUgZHlpbmcgcHJvY2VzcyBvZiBhIHRha2VvdmVyOiBvdXIgb3duIHByb2Nlc3MncyBkYXRhIGVuZHMgYXQgdGhlIHdyaXRlIGhhbmRvZmYgLSBmYXN0XG4gKiAgd3JpdGVzIG11c3QgYmUgb24gZGlzayBieSB0aGVuLiBVbmRlZmluZWQgZm9yIHRoZSBzdWNjZXNzb3IgYW5kIGluIG5vcm1hbCBvcGVyYXRpb24uIEJvdGhcbiAqICBwcm9jZXNzZXMgc2hhcmUgdGhlIGNvbmZpZyBpZGVudGl0eSAoYWxsIHNlbGYgd2luZG93cyBsb29rIGxpa2UgXCJvdXJzXCIgdG8gYm90aCksIHNvIHRoaXMgaXNcbiAqICB0aGUgb25seSB3YXkgdGhlIGR5aW5nIHNpZGUga25vd3MgdGhlIHBvc3QtaGFuZG9mZiB3aW5kb3dzIGJlbG9uZyB0byB0aGUgb3RoZXIgcHJvY2Vzcy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPd25XaW5kb3dFbmRDbGlwKCk6IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IGR5aW5nID0gY3VycmVudC5keWluZztcbiAgICBpZiAoIWR5aW5nKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGxldCByZW1hcCA9IGN1cnJlbnQucmVtYXA7XG4gICAgaWYgKHJlbWFwKSByZXR1cm4gcmVtYXAuYm91bmRhcnlBO1xuICAgIHJldHVybiBkeWluZy5zdWNjZXNzb3JTdGFydDtcbn1cblxuLyoqIEhvdyBsb25nIHRvIHdhaXQgYmV0d2VlbiBtYWluLXBvcnQgYWNxdWlzaXRpb24gYXR0ZW1wdHM6IHRpZ2h0IGFyb3VuZCB0aGUgcHJlZGVjZXNzb3Inc1xuICogIHNjaGVkdWxlZCBkZWF0aCAod2hlbiB0aGUgcG9ydCBhY3R1YWxseSBmcmVlcyksIHJlbGF4ZWQgb3RoZXJ3aXNlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1haW5Qb3J0QWNxdWlyZURlbGF5KCk6IG51bWJlciB7XG4gICAgbGV0IGVuZCA9IGN1cnJlbnQucHJlZGVjZXNzb3JFbmQ7XG4gICAgaWYgKGVuZCAhPT0gdW5kZWZpbmVkICYmIE1hdGguYWJzKERhdGUubm93KCkgLSBlbmQpIDw9IEFDUVVJUkVfRkFTVF9XSU5ET1cpIHtcbiAgICAgICAgcmV0dXJuIEFDUVVJUkVfRkFTVF9ERUxBWTtcbiAgICB9XG4gICAgcmV0dXJuIEFDUVVJUkVfU0xPV19ERUxBWTtcbn1cbiJdfQ==
433
- /* _JS_SOURCE_HASH = "50da2af5b8e618f08c78a64cd181647132f2a796cf70437bc15d4f12db01efde"; */
126
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95VGFrZW92ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJkZXBsb3lUYWtlb3Zlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSw0Q0FBb0I7QUFDcEIsZ0RBQXdCO0FBQ3hCLDZEQUFvRTtBQUVwRSxNQUFNLDhCQUE4QixHQUFHLDBCQUEwQixDQUFDO0FBQ2xFLE1BQU0seUJBQXlCLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztBQUMzQyxNQUFNLHNCQUFzQixHQUFHLENBQUMsQ0FBQztBQUNqQyxNQUFNLDJCQUEyQixHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQ2xELE1BQU0sZUFBZSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBQ3ZDLE1BQU0sa0JBQWtCLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUNyQyxNQUFNLGtCQUFrQixHQUFHLElBQUksQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFZdEMsSUFBSSxRQUFvQyxDQUFDO0FBRXpDLFNBQVMsR0FBRyxDQUFDLElBQVk7SUFDckIsT0FBTyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztBQUN4QyxDQUFDO0FBRUQsU0FBUyxTQUFTO0lBQ2QsT0FBTyxRQUFRLE9BQU8sQ0FBQyxHQUFHLEdBQUcsQ0FBQztBQUNsQyxDQUFDO0FBRUQsU0FBUyxpQkFBaUI7SUFDdEIsT0FBTyxjQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLEdBQUcsR0FBRyxDQUFDO0FBQ25FLENBQUM7QUFFRCxLQUFLLFVBQVUsbUJBQW1COztJQUM5QixJQUFJLE1BQU0sR0FBRyxpQkFBaUIsRUFBRSxDQUFDO0lBQ2pDLElBQUksS0FBZSxDQUFDO0lBQ3BCLElBQUksQ0FBQztRQUNELEtBQUssR0FBRyxNQUFNLFlBQUUsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzlDLENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1QsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLFNBQVMsRUFBRSw4Q0FBOEMsTUFBTSxLQUFLLE1BQUMsQ0FBVyxDQUFDLEtBQUssbUNBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMvRyxPQUFPLEVBQUUsQ0FBQztJQUNkLENBQUM7SUFDRCxJQUFJLE9BQU8sR0FBb0IsRUFBRSxDQUFDO0lBQ2xDLEtBQUssSUFBSSxJQUFJLElBQUksS0FBSyxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLDhCQUE4QixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFBRSxTQUFTO1FBQ3pELElBQUksQ0FBQztZQUNELE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLFlBQUUsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQWtCLENBQUMsQ0FBQztRQUNqRyxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNULE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxTQUFTLEVBQUUsd0NBQXdDLE1BQU0sR0FBRyxJQUFJLEtBQUssTUFBQyxDQUFXLENBQUMsS0FBSyxtQ0FBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3BILENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDbkIsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLE9BQXdCLEVBQUUsR0FBVztJQUN6RCxJQUFJLElBQWdDLENBQUM7SUFDckMsS0FBSyxJQUFJLEtBQUssSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUN4QixJQUFJLFdBQVcsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQztRQUMvQyxJQUFJLFdBQVcsS0FBSyxTQUFTO1lBQUUsU0FBUztRQUN4QyxJQUFJLFdBQVcsR0FBRyxLQUFLLENBQUMsVUFBVSxDQUFDLFdBQVcsSUFBSSxDQUFDLENBQUM7UUFDcEQsSUFBSSxXQUFXLEdBQUcsR0FBRyxHQUFHLDJCQUEyQjtZQUFFLFNBQVM7UUFDOUQsSUFBSSxHQUFHLEdBQUcsV0FBVyxHQUFHLFdBQVcsR0FBRywyQkFBMkI7WUFBRSxTQUFTO1FBQzVFLElBQUksSUFBSSxJQUFJLElBQUksQ0FBQyxXQUFXLElBQUksV0FBVztZQUFFLFNBQVM7UUFDdEQsSUFBSSxHQUFHLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxDQUFDO0lBQ3hDLENBQUM7SUFDRCxPQUFPLElBQUksQ0FBQztBQUNoQixDQUFDO0FBRUQsc1RBQXNUO0FBQy9TLEtBQUssVUFBVSxvQkFBb0I7SUFDdEMsS0FBSyxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsT0FBTyxJQUFJLHNCQUFzQixFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUM7UUFDakUsSUFBSSxPQUFPLEdBQUcsTUFBTSxtQkFBbUIsRUFBRSxDQUFDO1FBQzFDLElBQUksS0FBSyxHQUFHLGNBQWMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDaEQsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUNSLFFBQVEsR0FBRyxLQUFLLENBQUM7WUFDakIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsRUFBRSwwRUFBMEUsR0FBRyxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsdUJBQXVCLEtBQUssQ0FBQyxXQUFXLDBEQUEwRCxHQUFHLENBQUMsS0FBSyxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzNRLE9BQU8sS0FBSyxDQUFDO1FBQ2pCLENBQUM7UUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsU0FBUyxFQUFFLHVEQUF1RCxpQkFBaUIsRUFBRSwwQ0FBMEMsT0FBTyxPQUFPLHNCQUFzQixrQkFBa0IseUJBQXlCLElBQUksQ0FBQyxDQUFDO1FBQ25PLElBQUksT0FBTyxHQUFHLHNCQUFzQixFQUFFLENBQUM7WUFDbkMsTUFBTSxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUseUJBQXlCLENBQUMsQ0FBQyxDQUFDO1FBQ2pGLENBQUM7SUFDTCxDQUFDO0lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQywrREFBK0Qsc0JBQXNCLEdBQUcseUJBQXlCLHlDQUF5QyxpQkFBaUIsRUFBRSx5RkFBeUYsQ0FBQyxDQUFDO0FBQzVSLENBQUM7QUFmRCxvREFlQztBQUVELFNBQWdCLFVBQVUsQ0FBQyxJQUFZO0lBQ25DLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNaLE1BQU0sSUFBSSxLQUFLLENBQUMsc0JBQXNCLElBQUksc0ZBQXNGLENBQUMsQ0FBQztJQUN0SSxDQUFDO0lBQ0QsUUFBUSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUM7SUFDeEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsRUFBRSxnQ0FBZ0MsSUFBSSw2QkFBNkIsR0FBRyxDQUFDLGtCQUFrQixFQUFFLENBQUMsaUNBQWlDLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ25MLElBQUEsaURBQTRCLEdBQUUsQ0FBQztBQUNuQyxDQUFDO0FBUEQsZ0NBT0M7QUFFRCwySUFBMkk7QUFDM0ksU0FBZ0IsdUJBQXVCO0lBQ25DLElBQUksQ0FBQyxDQUFBLFFBQVEsYUFBUixRQUFRLHVCQUFSLFFBQVEsQ0FBRSxPQUFPLENBQUE7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUN6QyxPQUFPLEVBQUUsS0FBSyxFQUFFLFFBQVEsQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFLGtCQUFrQixFQUFFLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUNqRyxDQUFDO0FBSEQsMERBR0M7QUFFRCxTQUFTLGtCQUFrQjtJQUN2QixJQUFJLENBQUMsUUFBUTtRQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3hCLE9BQU8sUUFBUSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxDQUFDO0FBQ3ZELENBQUM7QUFFRCx5SkFBeUo7QUFDekosU0FBZ0IsbUJBQW1CO0lBQy9CLElBQUksQ0FBQyxRQUFRO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDeEIsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxXQUFXLEdBQUcsUUFBUSxDQUFDLFdBQVcsR0FBRyxDQUFDLEVBQUUsa0JBQWtCLEVBQUUsR0FBRyxlQUFlLENBQUMsQ0FBQztBQUM3RyxDQUFDO0FBSEQsa0RBR0M7QUFFRCxpS0FBaUs7QUFDakssU0FBZ0IsdUJBQXVCO0lBQ25DLElBQUksQ0FBQyxRQUFRO1FBQUUsT0FBTyxrQkFBa0IsQ0FBQztJQUN6QyxJQUFJLGNBQWMsR0FBRyxRQUFRLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQyxXQUFXLENBQUM7SUFDakUsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksY0FBYyxHQUFHLG1CQUFtQixFQUFFLENBQUM7UUFDckQsT0FBTyxrQkFBa0IsQ0FBQztJQUM5QixDQUFDO0lBQ0QsT0FBTyxrQkFBa0IsQ0FBQztBQUM5QixDQUFDO0FBUEQsMERBT0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSBcImZzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgc3RhcnRJbnRlcm1lZGlhdGVNYWludGVuYW5jZSB9IGZyb20gXCIuL3N0b3JhZ2VTZXJ2ZXJTdGF0ZVwiO1xuXG5jb25zdCBQQVJBTUVURVJTX1RJTUVMSU5FX0ZJTEVfUkVHRVggPSAvXihcXGQrKS1wYXJhbWV0ZXJzXFwuanNvbiQvO1xuY29uc3QgREVQTE9ZX0RFVEVDVF9SRVRSWV9ERUxBWSA9IDUgKiAxMDAwO1xuY29uc3QgREVQTE9ZX0RFVEVDVF9BVFRFTVBUUyA9IDY7XG5jb25zdCBERVBMT1lfUkVMRUFTRV9NQVRDSF9XSU5ET1cgPSA1ICogNjAgKiAxMDAwO1xuY29uc3QgQUxUX1BPUlRfTElOR0VSID0gMzAgKiA2MCAqIDEwMDA7XG5jb25zdCBBQ1FVSVJFX1NMT1dfREVMQVkgPSAzMCAqIDEwMDA7XG5jb25zdCBBQ1FVSVJFX0ZBU1RfREVMQVkgPSAxMDAwO1xuY29uc3QgQUNRVUlSRV9GQVNUX1dJTkRPVyA9IDYwICogMTAwMDtcblxudHlwZSBUaW1lbGluZUVudHJ5ID0ge1xuICAgIHBhcmFtZXRlcnM6IHsgcmVsZWFzZVRpbWU/OiBudW1iZXI7IG92ZXJsYXBUaW1lPzogbnVtYmVyIH07XG59O1xuXG50eXBlIERlcGxveVRha2VvdmVyID0ge1xuICAgIHJlbGVhc2VUaW1lOiBudW1iZXI7XG4gICAgb3ZlcmxhcFRpbWU6IG51bWJlcjtcbiAgICBhbHRQb3J0PzogbnVtYmVyO1xufTtcblxubGV0IHRha2VvdmVyOiBEZXBsb3lUYWtlb3ZlciB8IHVuZGVmaW5lZDtcblxuZnVuY3Rpb24gaXNvKHRpbWU6IG51bWJlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIG5ldyBEYXRlKHRpbWUpLnRvSVNPU3RyaW5nKCk7XG59XG5cbmZ1bmN0aW9uIGxvZ1ByZWZpeCgpOiBzdHJpbmcge1xuICAgIHJldHVybiBgW3BpZCAke3Byb2Nlc3MucGlkfV1gO1xufVxuXG5mdW5jdGlvbiBnZXRUaW1lbGluZUZvbGRlcigpOiBzdHJpbmcge1xuICAgIHJldHVybiBwYXRoLmRpcm5hbWUocHJvY2Vzcy5jd2QoKSkucmVwbGFjZUFsbChcIlxcXFxcIiwgXCIvXCIpICsgXCIvXCI7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRUaW1lbGluZUVudHJpZXMoKTogUHJvbWlzZTxUaW1lbGluZUVudHJ5W10+IHtcbiAgICBsZXQgZm9sZGVyID0gZ2V0VGltZWxpbmVGb2xkZXIoKTtcbiAgICBsZXQgZmlsZXM6IHN0cmluZ1tdO1xuICAgIHRyeSB7XG4gICAgICAgIGZpbGVzID0gYXdhaXQgZnMucHJvbWlzZXMucmVhZGRpcihmb2xkZXIpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGAke2xvZ1ByZWZpeCgpfSBDb3VsZCBub3QgcmVhZCB0aGUgZGVwbG95IHRpbWVsaW5lIGZvbGRlciAke2ZvbGRlcn06ICR7KGUgYXMgRXJyb3IpLnN0YWNrID8/IGV9YCk7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgbGV0IGVudHJpZXM6IFRpbWVsaW5lRW50cnlbXSA9IFtdO1xuICAgIGZvciAobGV0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgICAgaWYgKCFQQVJBTUVURVJTX1RJTUVMSU5FX0ZJTEVfUkVHRVgudGVzdChmaWxlKSkgY29udGludWU7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBlbnRyaWVzLnB1c2goSlNPTi5wYXJzZShhd2FpdCBmcy5wcm9taXNlcy5yZWFkRmlsZShmb2xkZXIgKyBmaWxlLCBcInV0ZjhcIikpIGFzIFRpbWVsaW5lRW50cnkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oYCR7bG9nUHJlZml4KCl9IENvdWxkIG5vdCByZWFkIGRlcGxveSB0aW1lbGluZSBmaWxlICR7Zm9sZGVyICsgZmlsZX06ICR7KGUgYXMgRXJyb3IpLnN0YWNrID8/IGV9YCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGVudHJpZXM7XG59XG5cbmZ1bmN0aW9uIGZpbmRPdXJSZWxlYXNlKGVudHJpZXM6IFRpbWVsaW5lRW50cnlbXSwgbm93OiBudW1iZXIpOiBEZXBsb3lUYWtlb3ZlciB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IGJlc3Q6IERlcGxveVRha2VvdmVyIHwgdW5kZWZpbmVkO1xuICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgbGV0IHJlbGVhc2VUaW1lID0gZW50cnkucGFyYW1ldGVycy5yZWxlYXNlVGltZTtcbiAgICAgICAgaWYgKHJlbGVhc2VUaW1lID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgICBsZXQgb3ZlcmxhcFRpbWUgPSBlbnRyeS5wYXJhbWV0ZXJzLm92ZXJsYXBUaW1lIHx8IDA7XG4gICAgICAgIGlmIChyZWxlYXNlVGltZSA+IG5vdyArIERFUExPWV9SRUxFQVNFX01BVENIX1dJTkRPVykgY29udGludWU7XG4gICAgICAgIGlmIChub3cgPiByZWxlYXNlVGltZSArIG92ZXJsYXBUaW1lICsgREVQTE9ZX1JFTEVBU0VfTUFUQ0hfV0lORE9XKSBjb250aW51ZTtcbiAgICAgICAgaWYgKGJlc3QgJiYgYmVzdC5yZWxlYXNlVGltZSA+PSByZWxlYXNlVGltZSkgY29udGludWU7XG4gICAgICAgIGJlc3QgPSB7IHJlbGVhc2VUaW1lLCBvdmVybGFwVGltZSB9O1xuICAgIH1cbiAgICByZXR1cm4gYmVzdDtcbn1cblxuLyoqIENhbGxlZCB3aGVuIHRoZSBtYWluIHBvcnQgaXMgYWxyZWFkeSBpbiB1c2UsIHdoaWNoIG9uIGEgaGVhbHRoeSBtYWNoaW5lIG9ubHkgaGFwcGVucyB3aGlsZSBvdXIgcHJlZGVjZXNzb3IgaXMgc3RpbGwgcnVubmluZyBhIGRlcGxveSBvdmVybGFwLiBDb25maXJtcyB0aGF0IGFnYWluc3QgdGhlIGRlcGxveSB0aW1lbGluZTsgaWYgbm8gZGVwbG95IGlzIGluIHByb2dyZXNzIHdlIGFyZSBpbiBhIGJhZCBzdGF0ZSAoc29tZW9uZSBlbHNlIGhvbGRzIG91ciBwb3J0KSBhbmQgdGhlIHByb2Nlc3MgbXVzdCBub3Qga2VlcCBydW5uaW5nLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRldGVjdERlcGxveVRha2VvdmVyKCk6IFByb21pc2U8RGVwbG95VGFrZW92ZXI+IHtcbiAgICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBERVBMT1lfREVURUNUX0FUVEVNUFRTOyBhdHRlbXB0KyspIHtcbiAgICAgICAgbGV0IGVudHJpZXMgPSBhd2FpdCByZWFkVGltZWxpbmVFbnRyaWVzKCk7XG4gICAgICAgIGxldCBmb3VuZCA9IGZpbmRPdXJSZWxlYXNlKGVudHJpZXMsIERhdGUubm93KCkpO1xuICAgICAgICBpZiAoZm91bmQpIHtcbiAgICAgICAgICAgIHRha2VvdmVyID0gZm91bmQ7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgJHtsb2dQcmVmaXgoKX0gT3VyIG1haW4gcG9ydCBpcyBpbiB1c2UgYW5kIHRoZSBkZXBsb3kgdGltZWxpbmUgY29uZmlybXMgYSByZWxlYXNlIGF0ICR7aXNvKGZvdW5kLnJlbGVhc2VUaW1lKX0gd2l0aCBhbiBvdmVybGFwIG9mICR7Zm91bmQub3ZlcmxhcFRpbWV9bXM6IHdlIGFyZSB0aGUgc3VjY2Vzc29yLiBPdXIgcHJlZGVjZXNzb3IgaXMga2lsbGVkIGF0ICR7aXNvKGZvdW5kLnJlbGVhc2VUaW1lICsgZm91bmQub3ZlcmxhcFRpbWUpfS5gKTtcbiAgICAgICAgICAgIHJldHVybiBmb3VuZDtcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhgJHtsb2dQcmVmaXgoKX0gT3VyIG1haW4gcG9ydCBpcyBpbiB1c2UgYnV0IHRoZSBkZXBsb3kgdGltZWxpbmUgaW4gJHtnZXRUaW1lbGluZUZvbGRlcigpfSBzaG93cyBubyByZWxlYXNlIGluIHByb2dyZXNzIChhdHRlbXB0ICR7YXR0ZW1wdH0gb2YgJHtERVBMT1lfREVURUNUX0FUVEVNUFRTfSk7IHJldHJ5aW5nIGluICR7REVQTE9ZX0RFVEVDVF9SRVRSWV9ERUxBWX1tc2ApO1xuICAgICAgICBpZiAoYXR0ZW1wdCA8IERFUExPWV9ERVRFQ1RfQVRURU1QVFMpIHtcbiAgICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBERVBMT1lfREVURUNUX1JFVFJZX0RFTEFZKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGBPdXIgbWFpbiBwb3J0IGlzIGluIHVzZSwgYnV0IG5vIGRlcGxveSBpcyBpbiBwcm9ncmVzcyBhZnRlciAke0RFUExPWV9ERVRFQ1RfQVRURU1QVFMgKiBERVBMT1lfREVURUNUX1JFVFJZX0RFTEFZfW1zIG9mIGNoZWNraW5nIHRoZSBkZXBsb3kgdGltZWxpbmUgaW4gJHtnZXRUaW1lbGluZUZvbGRlcigpfS4gU29tZXRoaW5nIGVsc2UgaXMgaG9sZGluZyBvdXIgcG9ydCwgc28gdGhpcyBwcm9jZXNzIGlzIGluIGEgYmFkIHN0YXRlIGFuZCBpcyBleGl0aW5nLmApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc2V0QWx0UG9ydChwb3J0OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAoIXRha2VvdmVyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQW4gYWx0ZXJuYXRlIHBvcnQgKCR7cG9ydH0pIHdhcyB0YWtlbiB3aXRob3V0IGEgZGV0ZWN0ZWQgZGVwbG95IHRha2VvdmVyIC0gZGV0ZWN0RGVwbG95VGFrZW92ZXIgbXVzdCBydW4gZmlyc3RgKTtcbiAgICB9XG4gICAgdGFrZW92ZXIuYWx0UG9ydCA9IHBvcnQ7XG4gICAgY29uc29sZS5sb2coYCR7bG9nUHJlZml4KCl9IExpc3RlbmluZyBvbiBhbHRlcm5hdGUgcG9ydCAke3BvcnR9OiB3cml0ZXMgcm91dGUgaGVyZSB1bnRpbCAke2lzbyhnZXRJbnRlcm1lZGlhdGVFbmQoKSl9LCBhbmQgd2Uga2VlcCBsaXN0ZW5pbmcgdW50aWwgJHtpc28oZ2V0QWx0UG9ydExpc3RlbkVuZCgpKX1gKTtcbiAgICBzdGFydEludGVybWVkaWF0ZU1haW50ZW5hbmNlKCk7XG59XG5cbi8qKiBUaGUgd2luZG93IGluIHdoaWNoIHdyaXRlcyBiZWxvbmcgdG8gb3VyIGFsdGVybmF0ZSBwb3J0OiBmcm9tIHRoZSByZWxlYXNlIHVudGlsIG91ciBwcmVkZWNlc3NvciBpcyBraWxsZWQgYW5kIHdlIHRha2UgdGhlIG1haW4gcG9ydC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUYWtlb3ZlckludGVybWVkaWF0ZSgpOiB7IHN0YXJ0OiBudW1iZXI7IGVuZDogbnVtYmVyOyBhbHRQb3J0OiBudW1iZXIgfSB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCF0YWtlb3Zlcj8uYWx0UG9ydCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICByZXR1cm4geyBzdGFydDogdGFrZW92ZXIucmVsZWFzZVRpbWUsIGVuZDogZ2V0SW50ZXJtZWRpYXRlRW5kKCksIGFsdFBvcnQ6IHRha2VvdmVyLmFsdFBvcnQgfTtcbn1cblxuZnVuY3Rpb24gZ2V0SW50ZXJtZWRpYXRlRW5kKCk6IG51bWJlciB7XG4gICAgaWYgKCF0YWtlb3ZlcikgcmV0dXJuIDA7XG4gICAgcmV0dXJuIHRha2VvdmVyLnJlbGVhc2VUaW1lICsgdGFrZW92ZXIub3ZlcmxhcFRpbWU7XG59XG5cbi8qKiBXZSBuZXZlciBzdG9wIGxpc3RlbmluZyBvbiB0aGUgYWx0ZXJuYXRlIHBvcnQgd2hpbGUgaXRzIHdpbmRvdyBpcyBzdGlsbCB2YWxpZCwgYW5kIGhvbGQgaXQgd2VsbCBwYXN0IHRoYXQgZm9yIGNsaWVudHMgdGhhdCBoYXZlIG5vdCBjYXVnaHQgdXAgeWV0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEFsdFBvcnRMaXN0ZW5FbmQoKTogbnVtYmVyIHtcbiAgICBpZiAoIXRha2VvdmVyKSByZXR1cm4gMDtcbiAgICByZXR1cm4gTWF0aC5tYXgodGFrZW92ZXIucmVsZWFzZVRpbWUgKyB0YWtlb3Zlci5vdmVybGFwVGltZSAqIDIsIGdldEludGVybWVkaWF0ZUVuZCgpICsgQUxUX1BPUlRfTElOR0VSKTtcbn1cblxuLyoqIEhvdyBsb25nIHRvIHdhaXQgYmV0d2VlbiBtYWluLXBvcnQgYWNxdWlzaXRpb24gYXR0ZW1wdHM6IHRpZ2h0IGFyb3VuZCBvdXIgcHJlZGVjZXNzb3IncyBzY2hlZHVsZWQgZGVhdGggKHdoZW4gdGhlIHBvcnQgYWN0dWFsbHkgZnJlZXMpLCByZWxheGVkIG90aGVyd2lzZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRNYWluUG9ydEFjcXVpcmVEZWxheSgpOiBudW1iZXIge1xuICAgIGlmICghdGFrZW92ZXIpIHJldHVybiBBQ1FVSVJFX1NMT1dfREVMQVk7XG4gICAgbGV0IHByZWRlY2Vzc29yRW5kID0gdGFrZW92ZXIucmVsZWFzZVRpbWUgKyB0YWtlb3Zlci5vdmVybGFwVGltZTtcbiAgICBpZiAoRGF0ZS5ub3coKSA+PSBwcmVkZWNlc3NvckVuZCAtIEFDUVVJUkVfRkFTVF9XSU5ET1cpIHtcbiAgICAgICAgcmV0dXJuIEFDUVVJUkVfRkFTVF9ERUxBWTtcbiAgICB9XG4gICAgcmV0dXJuIEFDUVVJUkVfU0xPV19ERUxBWTtcbn1cbiJdfQ==
127
+ /* _JS_SOURCE_HASH = "fcfb2e0742a63c40c3c42d422e2047ade99ef700563ad8c3e97915a2ee9eff92"; */