socket-function 1.2.1 → 1.2.4

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 (51) hide show
  1. package/SocketFunction.d.ts +1 -1
  2. package/SocketFunctionTypes.d.ts +1 -1
  3. package/hot/HotReloadController.d.ts +3 -3
  4. package/index.d.ts +25 -10
  5. package/package.json +1 -1
  6. package/require/CSSShim.d.ts +1 -1
  7. package/require/RequireController.d.ts +2 -2
  8. package/require/compileFlags.d.ts +1 -1
  9. package/require/require.d.ts +1 -1
  10. package/src/callManager.d.ts +1 -1
  11. package/test.ts +5 -11
  12. package/time/trueTimeShim.d.ts +16 -1
  13. package/time/trueTimeShim.ts +121 -34
  14. package/dist/SetProcessVariables.ts.cache +0 -9
  15. package/dist/SocketFunction.ts.cache +0 -467
  16. package/hot/dist/HotReloadController.ts.cache +0 -252
  17. package/require/dist/RequireController.ts.cache +0 -386
  18. package/require/dist/compileFlags.ts.cache +0 -41
  19. package/require/dist/extMapper.ts.cache +0 -368
  20. package/require/dist/require.ts.cache +0 -676
  21. package/src/JSONLACKS/dist/JSONLACKS.ts.cache +0 -469
  22. package/src/dist/CallFactory.ts.cache +0 -930
  23. package/src/dist/Zip.ts.cache +0 -156
  24. package/src/dist/batching.ts.cache +0 -377
  25. package/src/dist/bits.ts.cache +0 -121
  26. package/src/dist/buffers.ts.cache +0 -76
  27. package/src/dist/caching.ts.cache +0 -302
  28. package/src/dist/callHTTPHandler.ts.cache +0 -264
  29. package/src/dist/callManager.ts.cache +0 -159
  30. package/src/dist/certStore.ts.cache +0 -59
  31. package/src/dist/createSingleton.ts.cache +0 -62
  32. package/src/dist/fixLargeNetworkCalls.ts.cache +0 -17
  33. package/src/dist/forwardPort.ts.cache +0 -222
  34. package/src/dist/https.ts.cache +0 -141
  35. package/src/dist/misc.ts.cache +0 -499
  36. package/src/dist/nodeCache.ts.cache +0 -136
  37. package/src/dist/nodeProxy.ts.cache +0 -57
  38. package/src/dist/protocolNegotiation.ts.cache +0 -101
  39. package/src/dist/tlsParsing.ts.cache +0 -85
  40. package/src/dist/types.ts.cache +0 -9
  41. package/src/dist/webSocketServer.ts.cache +0 -365
  42. package/src/dist/websocketFactory.ts.cache +0 -53
  43. package/src/formatting/dist/colors.ts.cache +0 -98
  44. package/src/formatting/dist/format.ts.cache +0 -396
  45. package/src/formatting/dist/logColors.ts.cache +0 -28
  46. package/src/lz4/dist/LZ4.ts.cache +0 -53
  47. package/src/profiling/dist/getOwnTime.ts.cache +0 -100
  48. package/src/profiling/dist/measure.ts.cache +0 -338
  49. package/src/profiling/dist/stats.ts.cache +0 -202
  50. package/src/profiling/dist/statsFormat.ts.cache +0 -45
  51. package/time/dist/trueTimeShim.ts.cache +0 -656
@@ -1,656 +0,0 @@
1
- "use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
26
- exports.setGetTimeOffsetBase = exports.getBrowserTime = exports.shimDateNow = exports.waitForFirstTimeSync = exports.getTrueTimeProof = exports.getTrueTimeOffset = exports.getTrueTime = exports.getTimeComponents = exports.getTimeComponentsDetailed = void 0;
27
- const SocketFunction_1 = require("../SocketFunction");
28
- const logColors_1 = require("../src/formatting/logColors");
29
- const misc_1 = require("../src/misc");
30
- // IMPORTANT! We don't ensure that the times of return are unique. We cannot ensure they are unique because the amount of precision is only about ten thousand date times per millisecond, Which would mean if the calling code called date.now frequently enough, which doesn't even have to be that frequent, it could slowly drift farther and farther ahead of the real time, which would be really bad.
31
- module.allowclient = true;
32
- const UPDATE_VERIFY_COUNT = 3;
33
- const UPDATE_TRANSITION_GAP = 1000 * 60 * 20;
34
- const UPDATE_CHECK_INTERVAL = 1000 * 60 * 5;
35
- const DEBUG_TIME_SYNC = false;
36
- const FETCH_RETRY_INITIAL_DELAY = 1000;
37
- const FETCH_RETRY_MAX_DELAY = 1000 * 30;
38
- const FETCH_MAX_FAILURES = 8;
39
- const NTP_TIMEOUT = 1000 * 10;
40
- // Time can never go backwards, but we can run at a slower rate until the output time allows
41
- // the real time to catch up with it.
42
- const MINIMUM_TIME_RATE = 0.5;
43
- const THROW_ON_ERROR = false;
44
- // Hugely important as if we don't synchronize between processes, it means our logs are going to be confusing and out of order.
45
- // - Of course, cross-machine, the logs could be out of order. However, due to the latency between machines, that's less likely. The latency will probably be a few milliseconds, and hopefully, our time isn't more than a few milliseconds off of the real time. However, between processes, the latency could easily be microseconds, and our time will absolutely certainly be microseconds off of the real time.
46
- let USE_LMDB_PROCESS_SYNC = true;
47
- // Browser tabs synchronize via localStorage, for the same reason processes synchronize via LMDB.
48
- const TIME_OFFSET_LOCAL_STORAGE_KEY = "socket-function-time-offset";
49
- function debugLog(...args) {
50
- if (DEBUG_TIME_SYNC) {
51
- console.log("[TimeSync]", ...args);
52
- }
53
- }
54
- let cachedTimeOffsetData = undefined;
55
- let didFirstTimeSync = false;
56
- let onFirstTimeSync;
57
- let firstTimeSyncPromise = new Promise((resolve) => {
58
- onFirstTimeSync = resolve;
59
- });
60
- function markFirstTimeSync() {
61
- if (didFirstTimeSync)
62
- return;
63
- didFirstTimeSync = true;
64
- onFirstTimeSync();
65
- }
66
- const baseGetTime = Date.now;
67
- let lastTime = 0;
68
- let lastBaseTime = 0;
69
- function getTimeComponentsDetailed() {
70
- const systemTime = baseGetTime();
71
- const data = cachedTimeOffsetData;
72
- if (!data) {
73
- return {
74
- systemTime,
75
- fromOffset: 0,
76
- toOffset: 0,
77
- fromTime: systemTime,
78
- toTime: systemTime,
79
- };
80
- }
81
- if (systemTime < data.lastUpdateTime) {
82
- // Before everything (shouldn't happen)
83
- if (THROW_ON_ERROR)
84
- throw new Error(`systemTime ${systemTime} is before lastUpdateTime ${data.lastUpdateTime}`);
85
- return {
86
- systemTime,
87
- fromOffset: data.lastOffset,
88
- toOffset: data.lastOffset,
89
- fromTime: data.lastUpdateTime,
90
- toTime: data.lastUpdateTime,
91
- };
92
- }
93
- else if (systemTime < data.updateTime) {
94
- // Smear between lastOffset and offset
95
- return {
96
- systemTime,
97
- fromOffset: data.lastOffset,
98
- toOffset: data.offset,
99
- fromTime: data.lastUpdateTime,
100
- toTime: data.updateTime,
101
- };
102
- }
103
- else if (systemTime < data.nextUpdateTime) {
104
- // Smear between offset and nextOffset
105
- return {
106
- systemTime,
107
- fromOffset: data.offset,
108
- toOffset: data.nextOffset,
109
- fromTime: data.updateTime,
110
- toTime: data.nextUpdateTime,
111
- };
112
- }
113
- else {
114
- // Past everything (shouldn't happen often)
115
- if (THROW_ON_ERROR)
116
- throw new Error(`systemTime ${systemTime} is past nextUpdateTime ${data.nextUpdateTime}`);
117
- return {
118
- systemTime,
119
- fromOffset: data.nextOffset,
120
- toOffset: data.nextOffset,
121
- fromTime: data.nextUpdateTime,
122
- toTime: data.nextUpdateTime,
123
- };
124
- }
125
- }
126
- exports.getTimeComponentsDetailed = getTimeComponentsDetailed;
127
- function getTimeComponents() {
128
- const detailed = getTimeComponentsDetailed();
129
- const elapsed = detailed.systemTime - detailed.fromTime;
130
- const duration = detailed.toTime - detailed.fromTime;
131
- const fraction = duration > 0 ? Math.min(1, elapsed / duration) : 0;
132
- const offset = detailed.fromOffset + (detailed.toOffset - detailed.fromOffset) * fraction;
133
- return { systemTime: detailed.systemTime, offset };
134
- }
135
- exports.getTimeComponents = getTimeComponents;
136
- function getTrueTime() {
137
- const { systemTime, offset } = getTimeComponents();
138
- let time = systemTime + offset;
139
- // Only adjust time once we have a time offset. Otherwise systems with a really bad clock
140
- // might take days be correct. It is better for the time to jump once at startup, rather
141
- // than be off by days, for days at a time.
142
- if (lastTime && offset) {
143
- if (time < lastTime) {
144
- let diff = systemTime - lastBaseTime;
145
- if (diff >= 0) {
146
- // Some time passed, so we have a baseline for how much to increase the time by.
147
- // This allows the real time to catch up with our time naturally.
148
- time = lastTime + diff * MINIMUM_TIME_RATE;
149
- }
150
- else {
151
- // The issue is the system time going backwards. In this case, allow the time to change
152
- }
153
- }
154
- }
155
- lastTime = time;
156
- lastBaseTime = systemTime;
157
- return time;
158
- }
159
- exports.getTrueTime = getTrueTime;
160
- function getTrueTimeOffset() {
161
- const { offset } = getTimeComponents();
162
- return offset;
163
- }
164
- exports.getTrueTimeOffset = getTrueTimeOffset;
165
- function getTrueTimeProof() {
166
- return cachedTimeOffsetData === null || cachedTimeOffsetData === void 0 ? void 0 : cachedTimeOffsetData.proof;
167
- }
168
- exports.getTrueTimeProof = getTrueTimeProof;
169
- function waitForFirstTimeSync() {
170
- if (didFirstTimeSync)
171
- return undefined;
172
- return firstTimeSyncPromise;
173
- }
174
- exports.waitForFirstTimeSync = waitForFirstTimeSync;
175
- let shimmed = false;
176
- function shimDateNow() {
177
- if (shimmed)
178
- return;
179
- shimmed = true;
180
- if (globalThis.TRUE_TIME_ALREADY_SHIMMED)
181
- return;
182
- globalThis.TRUE_TIME_ALREADY_SHIMMED = true;
183
- Date.now = getTrueTime;
184
- }
185
- exports.shimDateNow = shimDateNow;
186
- function getBrowserTime() {
187
- return baseGetTime();
188
- }
189
- exports.getBrowserTime = getBrowserTime;
190
- function setGetTimeOffsetBase(base) {
191
- getTimeOffsetBase = base;
192
- }
193
- exports.setGetTimeOffsetBase = setGetTimeOffsetBase;
194
- function makeMeasurement(sendTime, receiveTime, serverTime) {
195
- const predictedServerToClientLatency = (receiveTime - sendTime) / 2;
196
- const offset = serverTime + predictedServerToClientLatency - receiveTime;
197
- return { offset, proof: { sendTime, receiveTime, serverTime, offset } };
198
- }
199
- async function defaultGetTimeOffset() {
200
- if (!(0, misc_1.isNode)()) {
201
- let sendTime = baseGetTime();
202
- let serverTrueTime = await TimeController.nodes[SocketFunction_1.SocketFunction.browserNodeId()].getTrueTime();
203
- let receiveTime = baseGetTime();
204
- return makeMeasurement(sendTime, receiveTime, serverTrueTime);
205
- }
206
- const dgram = await Promise.resolve().then(() => __importStar(require("dgram")));
207
- const NTP_SERVER = "time.google.com";
208
- const NTP_PORT = 123;
209
- const NTP_PACKET_SIZE = 48;
210
- const NTP_EPOCH_OFFSET = 2208988800000; // Number of milliseconds between 1900-01-01 and 1970-01-01
211
- return new Promise((resolve, reject) => {
212
- const client = dgram.createSocket("udp4");
213
- const message = Buffer.alloc(NTP_PACKET_SIZE);
214
- // Set the first byte to represent NTP client request (LI = 0, VN = 3, Mode = 3)
215
- message[0] = 0x1B;
216
- const sendTime = baseGetTime();
217
- // NTP is UDP, so a lost packet means the "message" event simply never fires. Without a timeout that leaves updateTimeOffset stuck (updatingOffset stays true forever), permanently stopping all future syncs.
218
- const timeout = setTimeout(() => {
219
- client.close();
220
- reject(new Error(`NTP request to ${NTP_SERVER} timed out`));
221
- }, NTP_TIMEOUT);
222
- client.send(message, 0, message.length, NTP_PORT, NTP_SERVER);
223
- client.on("error", (err) => {
224
- clearTimeout(timeout);
225
- client.close();
226
- reject(err);
227
- });
228
- client.on("message", (msg) => {
229
- const receiveTime = baseGetTime();
230
- // A throw in this handler would be an uncaught exception, not a rejection, so validate before reading fixed offsets.
231
- if (msg.length < NTP_PACKET_SIZE)
232
- return;
233
- clearTimeout(timeout);
234
- // Extract the transmit timestamp from the server response
235
- const transmitTimestampSeconds = msg.readUInt32BE(40);
236
- const transmitTimestampFraction = msg.readUInt32BE(44);
237
- const transmitTimestamp = (transmitTimestampSeconds * 1000) + (transmitTimestampFraction * 1000 / 0x100000000) - NTP_EPOCH_OFFSET;
238
- client.close();
239
- resolve(makeMeasurement(sendTime, receiveTime, transmitTimestamp));
240
- });
241
- });
242
- }
243
- function isValidTimeOffsetData(data) {
244
- const d = data;
245
- return (!!d &&
246
- typeof d.lastOffset === "number" &&
247
- typeof d.lastUpdateTime === "number" &&
248
- typeof d.offset === "number" &&
249
- typeof d.updateTime === "number" &&
250
- typeof d.nextOffset === "number" &&
251
- typeof d.nextUpdateTime === "number");
252
- }
253
- let timeOffsetDb = undefined;
254
- async function getTimeOffsetDb() {
255
- if (!USE_LMDB_PROCESS_SYNC)
256
- return undefined;
257
- if (timeOffsetDb)
258
- return timeOffsetDb;
259
- if (!(0, misc_1.isNode)())
260
- return undefined;
261
- try {
262
- const lmdb = await Promise.resolve().then(() => __importStar(require("lmdb")));
263
- const path = await Promise.resolve().then(() => __importStar(require("path")));
264
- const os = await Promise.resolve().then(() => __importStar(require("os")));
265
- const dbPath = path.join(os.tmpdir(), "socket-function-time-offset-2");
266
- timeOffsetDb = lmdb.open({
267
- path: dbPath,
268
- // Enable versioning for conditional writes
269
- useVersions: true,
270
- });
271
- return timeOffsetDb;
272
- }
273
- catch (e) {
274
- console.error("Error opening LMDB database:", e);
275
- return undefined;
276
- }
277
- }
278
- function getLmdbStore(db) {
279
- return {
280
- async getEntry() {
281
- try {
282
- const entry = await db.getEntry("timeOffset"); // Gets {value, version} atomically
283
- if (!entry)
284
- return undefined;
285
- if (typeof entry.version !== "number" || !isValidTimeOffsetData(entry.value))
286
- return undefined;
287
- return { data: entry.value, version: entry.version };
288
- }
289
- catch (e) {
290
- console.error("Error reading from LMDB database:", e);
291
- return undefined;
292
- }
293
- },
294
- async putIfVersion(data, expectedVersion) {
295
- try {
296
- // Use random version to minimize collision probability on retries
297
- const newVersion = Math.random();
298
- const success = await db.ifVersion("timeOffset", expectedVersion, () => {
299
- return db.put("timeOffset", data, newVersion);
300
- });
301
- return success !== undefined;
302
- }
303
- catch (e) {
304
- console.error("Error writing to LMDB database:", e);
305
- return false;
306
- }
307
- },
308
- async putInitial(data) {
309
- try {
310
- const newVersion = Math.random();
311
- await db.put("timeOffset", data, newVersion);
312
- // Read back to see what actually got written
313
- const actualEntry = await db.getEntry("timeOffset");
314
- return (actualEntry === null || actualEntry === void 0 ? void 0 : actualEntry.version) === newVersion;
315
- }
316
- catch (e) {
317
- console.error("Error writing to LMDB database:", e);
318
- return false;
319
- }
320
- },
321
- };
322
- }
323
- function getLocalStorageStore() {
324
- try {
325
- if (typeof localStorage === "undefined")
326
- return undefined;
327
- }
328
- catch (_a) {
329
- return undefined;
330
- }
331
- function readStored() {
332
- var _a;
333
- try {
334
- const raw = localStorage.getItem(TIME_OFFSET_LOCAL_STORAGE_KEY);
335
- if (!raw)
336
- return undefined;
337
- const parsed = JSON.parse(raw);
338
- if (!parsed || typeof parsed.version !== "number" || !isValidTimeOffsetData(parsed.data))
339
- return undefined;
340
- return parsed;
341
- }
342
- catch (e) {
343
- console.error("Error reading time offset from localStorage:", (_a = e.stack) !== null && _a !== void 0 ? _a : e);
344
- return undefined;
345
- }
346
- }
347
- function writeStored(data) {
348
- var _a;
349
- try {
350
- const version = Math.random();
351
- localStorage.setItem(TIME_OFFSET_LOCAL_STORAGE_KEY, JSON.stringify({ version, data }));
352
- return version;
353
- }
354
- catch (e) {
355
- console.error("Error writing time offset to localStorage:", (_a = e.stack) !== null && _a !== void 0 ? _a : e);
356
- return undefined;
357
- }
358
- }
359
- return {
360
- async getEntry() {
361
- const stored = readStored();
362
- if (!stored)
363
- return undefined;
364
- return { data: stored.data, version: stored.version };
365
- },
366
- // localStorage has no atomic compare-and-swap, but access within a tab is synchronous, so re-reading the version immediately before writing shrinks the race window to effectively nothing. Worst case two tabs both fetch an offset, which is harmless.
367
- async putIfVersion(data, expectedVersion) {
368
- const stored = readStored();
369
- if ((stored === null || stored === void 0 ? void 0 : stored.version) !== expectedVersion)
370
- return false;
371
- return writeStored(data) !== undefined;
372
- },
373
- async putInitial(data) {
374
- var _a;
375
- const version = writeStored(data);
376
- if (version === undefined)
377
- return false;
378
- return ((_a = readStored()) === null || _a === void 0 ? void 0 : _a.version) === version;
379
- },
380
- };
381
- }
382
- let timeOffsetStore = undefined;
383
- let timeOffsetStoreResolved = false;
384
- async function getTimeOffsetStore() {
385
- if (timeOffsetStoreResolved)
386
- return timeOffsetStore;
387
- if ((0, misc_1.isNode)()) {
388
- const db = await getTimeOffsetDb();
389
- if (db) {
390
- timeOffsetStore = getLmdbStore(db);
391
- }
392
- }
393
- else {
394
- timeOffsetStore = getLocalStorageStore();
395
- }
396
- timeOffsetStoreResolved = true;
397
- return timeOffsetStore;
398
- }
399
- let getTimeOffsetBase = defaultGetTimeOffset;
400
- // Returns undefined if we couldn't get any measurements. Callers must NOT treat that as an offset of 0 - a fabricated offset written to the shared store would poison every other process/tab for the full transition window.
401
- async function fetchNewOffset() {
402
- var _a;
403
- let measurements = [];
404
- let failures = 0;
405
- let retryDelay = FETCH_RETRY_INITIAL_DELAY;
406
- while (measurements.length < UPDATE_VERIFY_COUNT) {
407
- // The tab may have been hidden mid-fetch. Measurements from a throttled tab are worse than none, so stop and use whatever we already collected.
408
- if (!canMeasureOffset())
409
- break;
410
- try {
411
- const result = await getTimeOffsetBase();
412
- measurements.push(typeof result === "number" ? { offset: result } : result);
413
- }
414
- catch (e) {
415
- console.error("Error getting time offset:", (_a = e.stack) !== null && _a !== void 0 ? _a : e);
416
- failures++;
417
- if (failures >= FETCH_MAX_FAILURES)
418
- break;
419
- await new Promise(resolve => setTimeout(resolve, retryDelay));
420
- retryDelay = Math.min(retryDelay * 2, FETCH_RETRY_MAX_DELAY);
421
- }
422
- }
423
- if (measurements.length === 0) {
424
- return undefined;
425
- }
426
- // Pick the middle offset
427
- measurements.sort((a, b) => a.offset - b.offset);
428
- let measurement = measurements[Math.floor(measurements.length / 2)];
429
- let offset = measurement.offset;
430
- // Log if offset is significant
431
- let offsetRound = Math.abs(Math.round(offset));
432
- let offsetColored = (Math.abs(offset) > 600 && (0, logColors_1.red)(offsetRound + "ms")
433
- || Math.abs(offset) > 300 && (0, logColors_1.yellow)(offsetRound + "ms")
434
- || (0, logColors_1.green)(offsetRound + "ms"));
435
- if (Math.abs(offset) > 500) {
436
- console.log(`${(0, logColors_1.blue)("Synchronized time")}, local clock was ${offset > 0 ? "behind" : "ahead"} by ${offsetColored} @ ${(0, logColors_1.blue)(Date.now() + "")}`);
437
- }
438
- return measurement;
439
- }
440
- function canMeasureOffset() {
441
- if ((0, misc_1.isNode)())
442
- return true;
443
- if (typeof document === "undefined")
444
- return true;
445
- // Hidden tabs get their timers and message delivery throttled, which corrupts the round-trip latency estimate and therefore the offset. A visible tab will measure and share via localStorage instead.
446
- return document.visibilityState !== "hidden";
447
- }
448
- let updatingOffset = false;
449
- async function updateTimeOffset() {
450
- var _a, _b;
451
- if (updatingOffset)
452
- return;
453
- updatingOffset = true;
454
- try {
455
- const store = await getTimeOffsetStore();
456
- if (!store) {
457
- // IMPORTANT: Always use baseGetTime() for scheduling, never getTrueTime().
458
- // Our update schedule must be based on the stable system clock, not the
459
- // offset-adjusted time which changes as we synchronize.
460
- const currentTime = baseGetTime();
461
- let cachedData = cachedTimeOffsetData;
462
- if (cachedData && currentTime >= cachedData.nextUpdateTime) {
463
- // Past the end - reset and reinitialize
464
- cachedData = undefined;
465
- debugLog("Past nextUpdateTime, resetting");
466
- }
467
- const needsFetch = !cachedData || currentTime >= cachedData.updateTime;
468
- if (needsFetch && !canMeasureOffset()) {
469
- // Keep using whatever offset we have (even a stale one is better than a measurement skewed by background throttling).
470
- }
471
- else if (!cachedData) {
472
- // First time initialization
473
- const measurement = await fetchNewOffset();
474
- if (measurement) {
475
- // Re-read the time, as fetchNewOffset can take minutes when it has to retry.
476
- const initTime = baseGetTime();
477
- const offset = measurement.offset;
478
- cachedTimeOffsetData = {
479
- lastOffset: offset,
480
- lastUpdateTime: initTime,
481
- offset: offset,
482
- updateTime: initTime + UPDATE_TRANSITION_GAP,
483
- nextOffset: offset,
484
- nextUpdateTime: initTime + UPDATE_TRANSITION_GAP * 2,
485
- proof: measurement.proof,
486
- };
487
- debugLog("Initialized - time offset:", offset, "ms, next update in", UPDATE_TRANSITION_GAP, "ms");
488
- }
489
- // On total failure we leave the data unset (getTrueTime then uses the raw system clock) and the next check interval retries. We never fabricate an offset.
490
- }
491
- else if (currentTime >= cachedData.updateTime) {
492
- // Time to rotate
493
- const newMeasurement = await fetchNewOffset();
494
- if (newMeasurement) {
495
- cachedTimeOffsetData = {
496
- lastOffset: cachedData.offset,
497
- lastUpdateTime: cachedData.updateTime,
498
- offset: cachedData.nextOffset,
499
- updateTime: cachedData.nextUpdateTime,
500
- nextOffset: newMeasurement.offset,
501
- nextUpdateTime: cachedData.nextUpdateTime + UPDATE_TRANSITION_GAP,
502
- proof: newMeasurement.proof,
503
- };
504
- const timeUntilNext = cachedTimeOffsetData.nextUpdateTime - baseGetTime();
505
- debugLog("Advancing time offset - current:", cachedTimeOffsetData.offset, "ms, next:", cachedTimeOffsetData.nextOffset, "ms, next update in", timeUntilNext, "ms");
506
- }
507
- }
508
- // Always resolve the first sync, even on failure - SocketFunction.mount awaits this, and hanging forever is worse than temporarily running on the unadjusted system clock.
509
- markFirstTimeSync();
510
- return;
511
- }
512
- // At this point we have a shared store (LMDB for processes, localStorage for tabs) with atomic-ish versioned writes.
513
- while (true) {
514
- const entry = await store.getEntry();
515
- // IMPORTANT: Always use baseGetTime() for scheduling, never getTrueTime().
516
- // Our update schedule must be based on the stable system clock, not the
517
- // offset-adjusted time which changes as we synchronize.
518
- const currentTime = baseGetTime();
519
- let cachedData = entry === null || entry === void 0 ? void 0 : entry.data;
520
- const readVersion = entry === null || entry === void 0 ? void 0 : entry.version;
521
- if (cachedData && currentTime >= cachedData.nextUpdateTime) {
522
- // Past the end - reset and reinitialize
523
- cachedData = undefined;
524
- debugLog("Past nextUpdateTime, resetting");
525
- }
526
- const needsFetch = !cachedData || currentTime >= cachedData.updateTime;
527
- if (needsFetch && !canMeasureOffset()) {
528
- // Keep using whatever offset we have (even a stale one is better than a measurement skewed by background throttling). If we have nothing, run unsynced until we become visible or another tab writes to the store.
529
- cachedTimeOffsetData = (_a = entry === null || entry === void 0 ? void 0 : entry.data) !== null && _a !== void 0 ? _a : cachedTimeOffsetData;
530
- break;
531
- }
532
- if (!cachedData || !readVersion) {
533
- // First time initialization - use conditional write to handle race
534
- const measurement = await fetchNewOffset();
535
- if (!measurement) {
536
- // Total failure - keep any stale data rather than writing a fabricated offset to the shared store. The next check interval retries.
537
- cachedTimeOffsetData = (_b = entry === null || entry === void 0 ? void 0 : entry.data) !== null && _b !== void 0 ? _b : cachedTimeOffsetData;
538
- break;
539
- }
540
- // Re-read the time, as fetchNewOffset can take minutes when it has to retry.
541
- const initTime = baseGetTime();
542
- const offset = measurement.offset;
543
- const initData = {
544
- lastOffset: offset,
545
- lastUpdateTime: initTime,
546
- offset: offset,
547
- updateTime: initTime + UPDATE_TRANSITION_GAP,
548
- nextOffset: offset,
549
- nextUpdateTime: initTime + UPDATE_TRANSITION_GAP * 2,
550
- proof: measurement.proof,
551
- };
552
- if (readVersion) {
553
- const success = await store.putIfVersion(initData, readVersion);
554
- if (!success) {
555
- debugLog("Lost the race, retrying");
556
- // Lost the race, retry
557
- continue;
558
- }
559
- cachedTimeOffsetData = initData;
560
- console.log("Successfully wrote atomic reset");
561
- break;
562
- }
563
- if (!await store.putInitial(initData)) {
564
- // Lost the race, another writer wrote after us
565
- // Retry from the top to read their data
566
- debugLog("Value was changed by another process, retrying");
567
- continue;
568
- }
569
- // We won the race, use our data
570
- cachedTimeOffsetData = initData;
571
- debugLog("Initialized - time offset:", offset, "ms, next update in", UPDATE_TRANSITION_GAP, "ms");
572
- break;
573
- }
574
- if (currentTime >= cachedData.updateTime) {
575
- // Time to rotate
576
- const newMeasurement = await fetchNewOffset();
577
- if (!newMeasurement) {
578
- // Total failure - keep the existing data unrotated (the offset just flattens out at nextOffset). The next check interval retries the rotation.
579
- cachedTimeOffsetData = cachedData;
580
- break;
581
- }
582
- const newData = {
583
- lastOffset: cachedData.offset,
584
- lastUpdateTime: cachedData.updateTime,
585
- offset: cachedData.nextOffset,
586
- updateTime: cachedData.nextUpdateTime,
587
- nextOffset: newMeasurement.offset,
588
- nextUpdateTime: cachedData.nextUpdateTime + UPDATE_TRANSITION_GAP,
589
- proof: newMeasurement.proof,
590
- };
591
- const success = await store.putIfVersion(newData, readVersion);
592
- if (!success) {
593
- // Lost the race, retry
594
- continue;
595
- }
596
- const timeUntilNext = newData.nextUpdateTime - baseGetTime();
597
- debugLog("Advancing time offset - current:", newData.offset, "ms, next:", newData.nextOffset, "ms, next update in", timeUntilNext, "ms");
598
- cachedTimeOffsetData = newData;
599
- break;
600
- }
601
- else {
602
- cachedTimeOffsetData = cachedData;
603
- const timeUntilNext = cachedData.updateTime - baseGetTime();
604
- debugLog("Loaded from store - current:", cachedData.offset, "ms, next:", cachedData.nextOffset, "ms, next update in", timeUntilNext, "ms");
605
- break;
606
- }
607
- }
608
- markFirstTimeSync();
609
- }
610
- finally {
611
- updatingOffset = false;
612
- }
613
- }
614
- function triggerUpdateTimeOffset() {
615
- updateTimeOffset().catch((e) => {
616
- console.warn("Error updating time offset:", e);
617
- });
618
- }
619
- setInterval(triggerUpdateTimeOffset, UPDATE_CHECK_INTERVAL);
620
- setImmediate(() => {
621
- updateTimeOffset().catch((e) => {
622
- console.error("Error updating initial offset:", e);
623
- });
624
- });
625
- if (!(0, misc_1.isNode)() && typeof window !== "undefined" && typeof document !== "undefined") {
626
- // If we loaded in a hidden tab we skip measuring, so re-check as soon as we become visible.
627
- document.addEventListener("visibilitychange", triggerUpdateTimeOffset);
628
- window.addEventListener("focus", triggerUpdateTimeOffset);
629
- // Pick up offsets other tabs write, so only one tab ever has to measure.
630
- window.addEventListener("storage", (e) => {
631
- if (e.key === TIME_OFFSET_LOCAL_STORAGE_KEY) {
632
- triggerUpdateTimeOffset();
633
- }
634
- });
635
- }
636
- class TimeControllerBase {
637
- async getTrueTime() {
638
- await waitForFirstTimeSync();
639
- return getTrueTime();
640
- }
641
- }
642
- const TimeController = SocketFunction_1.SocketFunction.register("TimeController-ddf4753e-fc8a-413f-8cc2-b927dd449976", new TimeControllerBase(), () => ({
643
- getTrueTime: {
644
- // No hooks, as this needs to run very early on. Also, it is basically just a ping,
645
- // so it should be safe for anyone to use (we might even make it just a regular HTTPS endpoint,
646
- // or even just set up a dedicated domain for this).
647
- noDefaultHooks: true,
648
- noClientHooks: true,
649
- },
650
- }), () => ({}), {
651
- // NOTE: Autoexpose, because our exposed endpoints are incredibly lightweight
652
- // (just a ping), and don't expose really expose any data.
653
- // noAutoExpose: true
654
- });
655
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJ1ZVRpbWVTaGltLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidHJ1ZVRpbWVTaGltLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsc0RBQW1EO0FBQ25ELDJEQUF1RTtBQUN2RSxzQ0FBcUM7QUFFckMsNFlBQTRZO0FBRTVZLE1BQU0sQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO0FBRzFCLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBRTlCLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7QUFDN0MsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUM1QyxNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUM7QUFFOUIsTUFBTSx5QkFBeUIsR0FBRyxJQUFJLENBQUM7QUFDdkMsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO0FBQ3hDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxDQUFDO0FBQzdCLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7QUFFOUIsNEZBQTRGO0FBQzVGLDBDQUEwQztBQUMxQyxNQUFNLGlCQUFpQixHQUFHLEdBQUcsQ0FBQztBQUU5QixNQUFNLGNBQWMsR0FBRyxLQUFLLENBQUM7QUFFN0IsK0hBQStIO0FBQy9ILHNaQUFzWjtBQUN0WixJQUFJLHFCQUFxQixHQUFHLElBQUksQ0FBQztBQUVqQyxpR0FBaUc7QUFDakcsTUFBTSw2QkFBNkIsR0FBRyw2QkFBNkIsQ0FBQztBQUVwRSxTQUFTLFFBQVEsQ0FBQyxHQUFHLElBQVc7SUFDNUIsSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUNsQixPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7QUFDTCxDQUFDO0FBMEJELElBQUksb0JBQW9CLEdBQStCLFNBQVMs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QXlFO0lBQ3pFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRTtRQUNyQyxJQUFJLENBQUMsQ0FBQyxHQUFHLEtBQUssNkJBQTZCLEVBQUUsQ0FBQztZQUMxQyx1QkFBdUIsRUFBRSxDQUFDO1FBQzlCLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFHRCxNQUFNLGtCQUFrQjtJQUNiLEtBQUssQ0FBQyxXQUFXO1FBQ3BCLE1BQU0sb0JBQW9CLEVBQUUsQ0FBQztRQUM3QixPQUFPLFdBQVcsRUFBRSxDQUFDO0lBQ3pCLENBQUM7Q0FDSjtBQUVELE1BQU0sY0FBYyxHQUFHLCtCQUFjLENBQUMsUUFBUSxDQUMxQyxxREFBcUQsRUFDckQsSUFBSSxrQkFBa0IsRUFBRSxFQUN4QixHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQ0gsV0FBVyxFQUFFO1FBQ1QsbUZBQW1GO1FBQ25GLGdHQUFnRztRQUNoRyxxREFBcUQ7UUFDckQsY0FBYyxFQUFFLElBQUk7UUFDcEIsYUFBYSxFQUFFLElBQUk7S0FDdEI7Q0FDSixDQUFDLEVBQ0YsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFDVjtBQUNJLDZFQUE2RTtBQUM3RSwyREFBMkQ7QUFDM0QscUJBQXFCO0NBQ3hCLENBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFNvY2tldEZ1bmN0aW9uIH0gZnJvbSBcIi4uL1NvY2tldEZ1bmN0aW9uXCI7XG5pbXBvcnQgeyBibHVlLCBncmVlbiwgcmVkLCB5ZWxsb3cgfSBmcm9tIFwiLi4vc3JjL2Zvcm1hdHRpbmcvbG9nQ29sb3JzXCI7XG5pbXBvcnQgeyBpc05vZGUgfSBmcm9tIFwiLi4vc3JjL21pc2NcIjtcblxuLy8gSU1QT1JUQU5UISBXZSBkb24ndCBlbnN1cmUgdGhhdCB0aGUgdGltZXMgb2YgcmV0dXJuIGFyZSB1bmlxdWUuIFdlIGNhbm5vdCBlbnN1cmUgdGhleSBhcmUgdW5pcXVlIGJlY2F1c2UgdGhlIGFtb3VudCBvZiBwcmVjaXNpb24gaXMgb25seSBhYm91dCB0ZW4gdGhvdXNhbmQgZGF0ZSB0aW1lcyBwZXIgbWlsbGlzZWNvbmQsIFdoaWNoIHdvdWxkIG1lYW4gaWYgdGhlIGNhbGxpbmcgY29kZSBjYWxsZWQgZGF0ZS5ub3cgZnJlcXVlbnRseSBlbm91Z2gsIHdoaWNoIGRvZXNuJ3QgZXZlbiBoYXZlIHRvIGJlIHRoYXQgZnJlcXVlbnQsIGl0IGNvdWxkIHNsb3dseSBkcmlmdCBmYXJ0aGVyIGFuZCBmYXJ0aGVyIGFoZWFkIG9mIHRoZSByZWFsIHRpbWUsIHdoaWNoIHdvdWxkIGJlIHJlYWxseSBiYWQuXG5cbm1vZHVsZS5hbGxvd2NsaWVudCA9IHRydWU7XG5cblxuY29uc3QgVVBEQVRFX1ZFUklGWV9DT1VOVCA9IDM7XG5cbmNvbnN0IFVQREFURV9UUkFOU0lUSU9OX0dBUCA9IDEwMDAgKiA2MCAqIDIwO1xuY29uc3QgVVBEQVRFX0NIRUNLX0lOVEVSVkFMID0gMTAwMCAqIDYwICogNTtcbmNvbnN0IERFQlVHX1RJTUVfU1lOQyA9IGZhbHNlO1xuXG5jb25zdCBGRVRDSF9SRVRSWV9JTklUSUFMX0RFTEFZID0gMTAwMDtcbmNvbnN0IEZFVENIX1JFVFJZX01BWF9ERUxBWSA9IDEwMDAgKiAzMDtcbmNvbnN0IEZFVENIX01BWF9GQUlMVVJFUyA9IDg7XG5jb25zdCBOVFBfVElNRU9VVCA9IDEwMDAgKiAxMDtcblxuLy8gVGltZSBjYW4gbmV2ZXIgZ28gYmFja3dhcmRzLCBidXQgd2UgY2FuIHJ1biBhdCBhIHNsb3dlciByYXRlIHVudGlsIHRoZSBvdXRwdXQgdGltZSBhbGxvd3Ncbi8vICAgICAgdGhlIHJlYWwgdGltZSB0byBjYXRjaCB1cCB3aXRoIGl0LlxuY29uc3QgTUlOSU1VTV9USU1FX1JBVEUgPSAwLjU7XG5cbmNvbnN0IFRIUk9XX09OX0VSUk9SID0gZmFsc2U7XG5cbi8vIEh1Z2VseSBpbXBvcnRhbnQgYXMgaWYgd2UgZG9uJ3Qgc3luY2hyb25pemUgYmV0d2VlbiBwcm9jZXNzZXMsIGl0IG1lYW5zIG91ciBsb2dzIGFyZSBnb2luZyB0byBiZSBjb25mdXNpbmcgYW5kIG91dCBvZiBvcmRlci5cbi8vICAtIE9mIGNvdXJzZSwgY3Jvc3MtbWFjaGluZSwgdGhlIGxvZ3MgY291bGQgYmUgb3V0IG9mIG9yZGVyLiBIb3dldmVyLCBkdWUgdG8gdGhlIGxhdGVuY3kgYmV0d2VlbiBtYWNoaW5lcywgdGhhdCdzIGxlc3MgbGlrZWx5LiBUaGUgbGF0ZW5jeSB3aWxsIHByb2JhYmx5IGJlIGEgZmV3IG1pbGxpc2Vjb25kcywgYW5kIGhvcGVmdWxseSwgb3VyIHRpbWUgaXNuJ3QgbW9yZSB0aGFuIGEgZmV3IG1pbGxpc2Vjb25kcyBvZmYgb2YgdGhlIHJlYWwgdGltZS4gSG93ZXZlciwgYmV0d2VlbiBwcm9jZXNzZXMsIHRoZSBsYXRlbmN5IGNvdWxkIGVhc2lseSBiZSBtaWNyb3NlY29uZHMsIGFuZCBvdXIgdGltZSB3aWxsIGFic29sdXRlbHkgY2VydGFpbmx5IGJlIG1pY3Jvc2Vjb25kcyBvZmYgb2YgdGhlIHJlYWwgdGltZS5cbmxldCBVU0VfTE1EQl9QUk9DRVNTX1NZTkMgPSB0cnVlO1xuXG4vLyBCcm93c2VyIHRhYnMgc3luY2hyb25pemUgdmlhIGxvY2FsU3RvcmFnZSwgZm9yIHRoZSBzYW1lIHJlYXNvbiBwcm9jZXNzZXMgc3luY2hyb25pemUgdmlhIExNREIuXG5jb25zdCBUSU1FX09GRlNFVF9MT0NBTF9TVE9SQUdFX0tFWSA9IFwic29ja2V0LWZ1bmN0aW9uLXRpbWUtb2Zmc2V0XCI7XG5cbmZ1bmN0aW9uIGRlYnVnTG9nKC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgaWYgKERFQlVHX1RJTUVfU1lOQykge1xuICAgICAgICBjb25zb2xlLmxvZyhcIltUaW1lU3luY11cIiwgLi4uYXJncyk7XG4gICAgfVxufVxuXG4vLyBUaGUgcmF3IGV2aWRlbmNlIGJlaGluZCBhbiBvZmZzZXQgbWVhc3VyZW1lbnQuIHNlbmRUaW1lL3JlY2VpdmVUaW1lIGFyZSBvbiB0aGUgbG9jYWwgc3lzdGVtIGNsb2NrLCBzZXJ2ZXJUaW1lIGlzIHRoZSByZW1vdGUgY2xvY2sncyB0aW1lc3RhbXAsIGFuZCBvZmZzZXQgaXMgZGVyaXZlZCBmcm9tIHRoZW0gYnkgYXNzdW1pbmcgdGhlIHNlcnZlciB0aW1lc3RhbXBlZCBhdCB0aGUgbWlkcG9pbnQgb2YgdGhlIHJvdW5kIHRyaXAuXG5leHBvcnQgdHlwZSBUaW1lT2Zmc2V0UHJvb2YgPSB7XG4gICAgc2VuZFRpbWU6IG51bWJlcjtcbiAgICByZWNlaXZlVGltZTogbnVtYmVyO1xuICAgIHNlcnZlclRpbWU6IG51bWJlcjtcbiAgICBvZmZzZXQ6IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIFRpbWVPZmZzZXRNZWFzdXJlbWVudCA9IHtcbiAgICBvZmZzZXQ6IG51bWJlcjtcbiAgICBwcm9vZj86IFRpbWVPZmZzZXRQcm9vZjtcbn07XG5cbnR5cGUgVGltZU9mZnNldERhdGEgPSB7XG4gICAgbGFzdE9mZnNldDogbnVtYmVyO1xuICAgIGxhc3RVcGRhdGVUaW1lOiBudW1iZXI7XG4gICAgb2Zmc2V0OiBudW1iZXI7XG4gICAgdXBkYXRlVGltZTogbnVtYmVyO1xuICAgIG5leHRPZmZzZXQ6IG51bWJlcjtcbiAgICBuZXh0VXBkYXRlVGltZTogbnVtYmVyO1xuICAgIC8vIFByb29mIG9mIHRoZSBtb3N0IHJlY2VudCBtZWFzdXJlbWVudCAodGhlIG9uZSB0aGF0IHByb2R1Y2VkIG5leHRPZmZzZXQpLlxuICAgIHByb29mPzogVGltZU9mZnNldFByb29mO1xufTtcblxubGV0IGNhY2hlZFRpbWVPZmZzZXREYXRhOiBUaW1lT2Zmc2V0RGF0YSB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbmxldCBkaWRGaXJzdFRpbWVTeW5jID0gZmFsc2U7XG5sZXQgb25GaXJzdFRpbWVTeW5jITogKCkgPT4gdm9pZDtcbmxldCBmaXJzdFRpbWVTeW5jUHJvbWlzZSA9IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgb25GaXJzdFRpbWVTeW5jID0gcmVzb2x2ZTtcbn0pO1xuZnVuY3Rpb24gbWFya0ZpcnN0VGltZVN5bmMoKSB7XG4gICAgaWYgKGRpZEZpcnN0VGltZVN5bmMpIHJldHVybjtcbiAgICBkaWRGaXJzdFRpbWVTeW5jID0gdHJ1ZTtcbiAgICBvbkZpcnN0VGltZVN5bmMoKTtcbn1cblxuY29uc3QgYmFzZUdldFRpbWUgPSBEYXRlLm5vdztcbmxldCBsYXN0VGltZSA9IDA7XG5sZXQgbGFzdEJhc2VUaW1lID0gMDtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldFRpbWVDb21wb25lbnRzRGV0YWlsZWQoKToge1xuICAgIHN5c3RlbVRpbWU6IG51bWJlcjtcbiAgICBmcm9tT2Zmc2V0OiBudW1iZXI7XG4gICAgdG9PZmZzZXQ6IG51bWJlcjtcbiAgICBmcm9tVGltZTogbnVtYmVyO1xuICAgIHRvVGltZTogbnVtYmVyO1xufSB7XG4gICAgY29uc3Qgc3lzdGVtVGltZSA9IGJhc2VHZXRUaW1lKCk7XG4gICAgY29uc3QgZGF0YSA9IGNhY2hlZFRpbWVPZmZzZXREYXRhO1xuXG4gICAgaWYgKCFkYXRhKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzeXN0ZW1UaW1lLFxuICAgICAgICAgICAgZnJvbU9mZnNldDogMCxcbiAgICAgICAgICAgIHRvT2Zmc2V0OiAwLFxuICAgICAgICAgICAgZnJvbVRpbWU6IHN5c3RlbVRpbWUsXG4gICAgICAgICAgICB0b1RpbWU6IHN5c3RlbVRpbWUsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKHN5c3RlbVRpbWUgPCBkYXRhLmxhc3RVcGRhdGVUaW1lKSB7XG4gICAgICAgIC8vIEJlZm9yZSBldmVyeXRoaW5nIChzaG91bGRuJ3QgaGFwcGVuKVxuICAgICAgICBpZiAoVEhST1dfT05fRVJST1IpIHRocm93IG5ldyBFcnJvcihgc3lzdGVtVGltZSAke3N5c3RlbVRpbWV9IGlzIGJlZm9yZSBsYXN0VXBkYXRlVGltZSAke2RhdGEubGFzdFVwZGF0ZVRpbWV9YCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzeXN0ZW1UaW1lLFxuICAgICAgICAgICAgZnJvbU9mZnNldDogZGF0YS5sYXN0T2Zmc2V0LFxuICAgICAgICAgICAgdG9PZmZzZXQ6IGRhdGEubGFzdE9mZnNldCxcbiAgICAgICAgICAgIGZyb21UaW1lOiBkYXRhLmxhc3RVcGRhdGVUaW1lLFxuICAgICAgICAgICAgdG9UaW1lOiBkYXRhLmxhc3RVcGRhdGVUaW1lLFxuICAgICAgICB9O1xuICAgIH0gZWxzZSBpZiAoc3lzdGVtVGltZSA8IGRhdGEudXBkYXRlVGltZSkge1xuICAgICAgICAvLyBTbWVhciBiZXR3ZWVuIGxhc3RPZmZzZXQgYW5kIG9mZnNldFxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3lzdGVtVGltZSxcbiAgICAgICAgICAgIGZyb21PZmZzZXQ6IGRhdGEubGFzdE9mZnNldCxcbiAgICAgICAgICAgIHRvT2Zmc2V0OiBkYXRhLm9mZnNldCxcbiAgICAgICAgICAgIGZyb21UaW1lOiBkYXRhLmxhc3RVcGRhdGVUaW1lLFxuICAgICAgICAgICAgdG9UaW1lOiBkYXRhLnVwZGF0ZVRpbWUsXG4gICAgICAgIH07XG4gICAgfSBlbHNlIGlmIChzeXN0ZW1UaW1lIDwgZGF0YS5uZXh0VXBkYXRlVGltZSkge1xuICAgICAgICAvLyBTbWVhciBiZXR3ZWVuIG9mZnNldCBhbmQgbmV4dE9mZnNldFxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3lzdGVtVGltZSxcbiAgICAgICAgICAgIGZyb21PZmZzZXQ6IGRhdGEub2Zmc2V0LFxuICAgICAgICAgICAgdG9PZmZzZXQ6IGRhdGEubmV4dE9mZnNldCxcbiAgICAgICAgICAgIGZyb21UaW1lOiBkYXRhLnVwZGF0ZVRpbWUsXG4gICAgICAgICAgICB0b1RpbWU6IGRhdGEubmV4dFVwZGF0ZVRpbWUsXG4gICAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gUGFzdCBldmVyeXRoaW5nIChzaG91bGRuJ3QgaGFwcGVuIG9mdGVuKVxuICAgICAgICBpZiAoVEhST1dfT05fRVJST1IpIHRocm93IG5ldyBFcnJvcihgc3lzdGVtVGltZSAke3N5c3RlbVRpbWV9IGlzIHBhc3QgbmV4dFVwZGF0ZVRpbWUgJHtkYXRhLm5leHRVcGRhdGVUaW1lfWApO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc3lzdGVtVGltZSxcbiAgICAgICAgICAgIGZyb21PZmZzZXQ6IGRhdGEubmV4dE9mZnNldCxcbiAgICAgICAgICAgIHRvT2Zmc2V0OiBkYXRhLm5leHRPZmZzZXQsXG4gICAgICAgICAgICBmcm9tVGltZTogZGF0YS5uZXh0VXBkYXRlVGltZSxcbiAgICAgICAgICAgIHRvVGltZTogZGF0YS5uZXh0VXBkYXRlVGltZSxcbiAgICAgICAgfTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUaW1lQ29tcG9uZW50cygpOiB7IHN5c3RlbVRpbWU6IG51bWJlcjsgb2Zmc2V0OiBudW1iZXIgfSB7XG4gICAgY29uc3QgZGV0YWlsZWQgPSBnZXRUaW1lQ29tcG9uZW50c0RldGFpbGVkKCk7XG4gICAgY29uc3QgZWxhcHNlZCA9IGRldGFpbGVkLnN5c3RlbVRpbWUgLSBkZXRhaWxlZC5mcm9tVGltZTtcbiAgICBjb25zdCBkdXJhdGlvbiA9IGRldGFpbGVkLnRvVGltZSAtIGRldGFpbGVkLmZyb21UaW1lO1xuICAgIGNvbnN0IGZyYWN0aW9uID0gZHVyYXRpb24gPiAwID8gTWF0aC5taW4oMSwgZWxhcHNlZCAvIGR1cmF0aW9uKSA6IDA7XG4gICAgY29uc3Qgb2Zmc2V0ID0gZGV0YWlsZWQuZnJvbU9mZnNldCArIChkZXRhaWxlZC50b09mZnNldCAtIGRldGFpbGVkLmZyb21PZmZzZXQpICogZnJhY3Rpb247XG4gICAgcmV0dXJuIHsgc3lzdGVtVGltZTogZGV0YWlsZWQuc3lzdGVtVGltZSwgb2Zmc2V0IH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUcnVlVGltZSgpIHtcbiAgICBjb25zdCB7IHN5c3RlbVRpbWUsIG9mZnNldCB9ID0gZ2V0VGltZUNvbXBvbmVudHMoKTtcbiAgICBsZXQgdGltZSA9IHN5c3RlbVRpbWUgKyBvZmZzZXQ7XG5cbiAgICAvLyBPbmx5IGFkanVzdCB0aW1lIG9uY2Ugd2UgaGF2ZSBhIHRpbWUgb2Zmc2V0LiBPdGhlcndpc2Ugc3lzdGVtcyB3aXRoIGEgcmVhbGx5IGJhZCBjbG9ja1xuICAgIC8vICBtaWdodCB0YWtlIGRheXMgYmUgY29ycmVjdC4gSXQgaXMgYmV0dGVyIGZvciB0aGUgdGltZSB0byBqdW1wIG9uY2UgYXQgc3RhcnR1cCwgcmF0aGVyXG4gICAgLy8gIHRoYW4gYmUgb2ZmIGJ5IGRheXMsIGZvciBkYXlzIGF0IGEgdGltZS5cbiAgICBpZiAobGFzdFRpbWUgJiYgb2Zmc2V0KSB7XG4gICAgICAgIGlmICh0aW1lIDwgbGFzdFRpbWUpIHtcbiAgICAgICAgICAgIGxldCBkaWZmID0gc3lzdGVtVGltZSAtIGxhc3RCYXNlVGltZTtcbiAgICAgICAgICAgIGlmIChkaWZmID49IDApIHtcbiAgICAgICAgICAgICAgICAvLyBTb21lIHRpbWUgcGFzc2VkLCBzbyB3ZSBoYXZlIGEgYmFzZWxpbmUgZm9yIGhvdyBtdWNoIHRvIGluY3JlYXNlIHRoZSB0aW1lIGJ5LlxuICAgICAgICAgICAgICAgIC8vICBUaGlzIGFsbG93cyB0aGUgcmVhbCB0aW1lIHRvIGNhdGNoIHVwIHdpdGggb3VyIHRpbWUgbmF0dXJhbGx5LlxuICAgICAgICAgICAgICAgIHRpbWUgPSBsYXN0VGltZSArIGRpZmYgKiBNSU5JTVVNX1RJTUVfUkFURTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gVGhlIGlzc3VlIGlzIHRoZSBzeXN0ZW0gdGltZSBnb2luZyBiYWNrd2FyZHMuIEluIHRoaXMgY2FzZSwgYWxsb3cgdGhlIHRpbWUgdG8gY2hhbmdlXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgbGFzdFRpbWUgPSB0aW1lO1xuICAgIGxhc3RCYXNlVGltZSA9IHN5c3RlbVRpbWU7XG4gICAgcmV0dXJuIHRpbWU7XG59XG5leHBvcnQgZnVuY3Rpb24gZ2V0VHJ1ZVRpbWVPZmZzZXQoKSB7XG4gICAgY29uc3QgeyBvZmZzZXQgfSA9IGdldFRpbWVDb21wb25lbnRzKCk7XG4gICAgcmV0dXJuIG9mZnNldDtcbn1cbmV4cG9ydCBmdW5jdGlvbiBnZXRUcnVlVGltZVByb29mKCk6IFRpbWVPZmZzZXRQcm9vZiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIGNhY2hlZFRpbWVPZmZzZXREYXRhPy5wcm9vZjtcbn1cbmV4cG9ydCBmdW5jdGlvbiB3YWl0Rm9yRmlyc3RUaW1lU3luYygpOiBQcm9taXNlPHZvaWQ+IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoZGlkRmlyc3RUaW1lU3luYykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICByZXR1cm4gZmlyc3RUaW1lU3luY1Byb21pc2U7XG59XG5kZWNsYXJlIGdsb2JhbCB7XG4gICAgdmFyIFRSVUVfVElNRV9BTFJFQURZX1NISU1NRUQ6IGJvb2xlYW47XG59XG5sZXQgc2hpbW1lZCA9IGZhbHNlO1xuZXhwb3J0IGZ1bmN0aW9uIHNoaW1EYXRlTm93KCkge1xuICAgIGlmIChzaGltbWVkKSByZXR1cm47XG4gICAgc2hpbW1lZCA9IHRydWU7XG4gICAgaWYgKGdsb2JhbFRoaXMuVFJVRV9USU1FX0FMUkVBRFlfU0hJTU1FRCkgcmV0dXJuO1xuICAgIGdsb2JhbFRoaXMuVFJVRV9USU1FX0FMUkVBRFlfU0hJTU1FRCA9IHRydWU7XG4gICAgRGF0ZS5ub3cgPSBnZXRUcnVlVGltZTtcbn1cbmV4cG9ydCBmdW5jdGlvbiBnZXRCcm93c2VyVGltZSgpIHtcbiAgICByZXR1cm4gYmFzZUdldFRpbWUoKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNldEdldFRpbWVPZmZzZXRCYXNlKGJhc2U6ICgpID0+IFByb21pc2U8bnVtYmVyIHwgVGltZU9mZnNldE1lYXN1cmVtZW50Pikge1xuICAgIGdldFRpbWVPZmZzZXRCYXNlID0gYmFzZTtcbn1cblxuZnVuY3Rpb24gbWFrZU1lYXN1cmVtZW50KHNlbmRUaW1lOiBudW1iZXIsIHJlY2VpdmVUaW1lOiBudW1iZXIsIHNlcnZlclRpbWU6IG51bWJlcik6IFRpbWVPZmZzZXRNZWFzdXJlbWVudCB7XG4gICAgY29uc3QgcHJlZGljdGVkU2VydmVyVG9DbGllbnRMYXRlbmN5ID0gKHJlY2VpdmVUaW1lIC0gc2VuZFRpbWUpIC8gMjtcbiAgICBjb25zdCBvZmZzZXQgPSBzZXJ2ZXJUaW1lICsgcHJlZGljdGVkU2VydmVyVG9DbGllbnRMYXRlbmN5IC0gcmVjZWl2ZVRpbWU7XG4gICAgcmV0dXJuIHsgb2Zmc2V0LCBwcm9vZjogeyBzZW5kVGltZSwgcmVjZWl2ZVRpbWUsIHNlcnZlclRpbWUsIG9mZnNldCB9IH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlZmF1bHRHZXRUaW1lT2Zmc2V0KCk6IFByb21pc2U8VGltZU9mZnNldE1lYXN1cmVtZW50PiB7XG4gICAgaWYgKCFpc05vZGUoKSkge1xuICAgICAgICBsZXQgc2VuZFRpbWUgPSBiYXNlR2V0VGltZSgpO1xuICAgICAgICBsZXQgc2VydmVyVHJ1ZVRpbWUgPSBhd2FpdCBUaW1lQ29udHJvbGxlci5ub2Rlc1tTb2NrZXRGdW5jdGlvbi5icm93c2VyTm9kZUlkKCldLmdldFRydWVUaW1lKCk7XG4gICAgICAgIGxldCByZWNlaXZlVGltZSA9IGJhc2VHZXRUaW1lKCk7XG4gICAgICAgIHJldHVybiBtYWtlTWVhc3VyZW1lbnQoc2VuZFRpbWUsIHJlY2VpdmVUaW1lLCBzZXJ2ZXJUcnVlVGltZSk7XG4gICAgfVxuXG4gICAgY29uc3QgZGdyYW0gPSBhd2FpdCBpbXBvcnQoXCJkZ3JhbVwiKTtcbiAgICBjb25zdCBOVFBfU0VSVkVSID0gXCJ0aW1lLmdvb2dsZS5jb21cIjtcbiAgICBjb25zdCBOVFBfUE9SVCA9IDEyMztcbiAgICBjb25zdCBOVFBfUEFDS0VUX1NJWkUgPSA0ODtcbiAgICBjb25zdCBOVFBfRVBPQ0hfT0ZGU0VUID0gMjIwODk4ODgwMDAwMDsgLy8gTnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBiZXR3ZWVuIDE5MDAtMDEtMDEgYW5kIDE5NzAtMDEtMDFcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBjb25zdCBjbGllbnQgPSBkZ3JhbS5jcmVhdGVTb2NrZXQoXCJ1ZHA0XCIpO1xuICAgICAgICBjb25zdCBtZXNzYWdlID0gQnVmZmVyLmFsbG9jKE5UUF9QQUNLRVRfU0laRSk7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBmaXJzdCBieXRlIHRvIHJlcHJlc2VudCBOVFAgY2xpZW50IHJlcXVlc3QgKExJID0gMCwgVk4gPSAzLCBNb2RlID0gMylcbiAgICAgICAgbWVzc2FnZVswXSA9IDB4MUI7XG5cbiAgICAgICAgY29uc3Qgc2VuZFRpbWUgPSBiYXNlR2V0VGltZSgpO1xuXG4gICAgICAgIC8vIE5UUCBpcyBVRFAsIHNvIGEgbG9zdCBwYWNrZXQgbWVhbnMgdGhlIFwibWVzc2FnZVwiIGV2ZW50IHNpbXBseSBuZXZlciBmaXJlcy4gV2l0aG91dCBhIHRpbWVvdXQgdGhhdCBsZWF2ZXMgdXBkYXRlVGltZU9mZnNldCBzdHVjayAodXBkYXRpbmdPZmZzZXQgc3RheXMgdHJ1ZSBmb3JldmVyKSwgcGVybWFuZW50bHkgc3RvcHBpbmcgYWxsIGZ1dHVyZSBzeW5jcy5cbiAgICAgICAgY29uc3QgdGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgY2xpZW50LmNsb3NlKCk7XG4gICAgICAgICAgICByZWplY3QobmV3IEVycm9yKGBOVFAgcmVxdWVzdCB0byAke05UUF9TRVJWRVJ9IHRpbWVkIG91dGApKTtcbiAgICAgICAgfSwgTlRQX1RJTUVPVVQpO1xuXG4gICAgICAgIGNsaWVudC5zZW5kKG1lc3NhZ2UsIDAsIG1lc3NhZ2UubGVuZ3RoLCBOVFBfUE9SVCwgTlRQX1NFUlZFUik7XG4gICAgICAgIGNsaWVudC5vbihcImVycm9yXCIsIChlcnIpID0+IHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgICAgIGNsaWVudC5jbG9zZSgpO1xuICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNsaWVudC5vbihcIm1lc3NhZ2VcIiwgKG1zZykgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmVjZWl2ZVRpbWUgPSBiYXNlR2V0VGltZSgpO1xuICAgICAgICAgICAgLy8gQSB0aHJvdyBpbiB0aGlzIGhhbmRsZXIgd291bGQgYmUgYW4gdW5jYXVnaHQgZXhjZXB0aW9uLCBub3QgYSByZWplY3Rpb24sIHNvIHZhbGlkYXRlIGJlZm9yZSByZWFkaW5nIGZpeGVkIG9mZnNldHMuXG4gICAgICAgICAgICBpZiAobXNnLmxlbmd0aCA8IE5UUF9QQUNLRVRfU0laRSkgcmV0dXJuO1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuXG4gICAgICAgICAgICAvLyBFeHRyYWN0IHRoZSB0cmFuc21pdCB0aW1lc3RhbXAgZnJvbSB0aGUgc2VydmVyIHJlc3BvbnNlXG4gICAgICAgICAgICBjb25zdCB0cmFuc21pdFRpbWVzdGFtcFNlY29uZHMgPSBtc2cucmVhZFVJbnQzMkJFKDQwKTtcbiAgICAgICAgICAgIGNvbnN0IHRyYW5zbWl0VGltZXN0YW1wRnJhY3Rpb24gPSBtc2cucmVhZFVJbnQzMkJFKDQ0KTtcbiAgICAgICAgICAgIGNvbnN0IHRyYW5zbWl0VGltZXN0YW1wID0gKHRyYW5zbWl0VGltZXN0YW1wU2Vjb25kcyAqIDEwMDApICsgKHRyYW5zbWl0VGltZXN0YW1wRnJhY3Rpb24gKiAxMDAwIC8gMHgxMDAwMDAwMDApIC0gTlRQX0VQT0NIX09GRlNFVDtcblxuICAgICAgICAgICAgY2xpZW50LmNsb3NlKCk7XG4gICAgICAgICAgICByZXNvbHZlKG1ha2VNZWFzdXJlbWVudChzZW5kVGltZSwgcmVjZWl2ZVRpbWUsIHRyYW5zbWl0VGltZXN0YW1wKSk7XG4gICAgICAgIH0pO1xuICAgIH0pO1xufVxuXG5mdW5jdGlvbiBpc1ZhbGlkVGltZU9mZnNldERhdGEoZGF0YTogdW5rbm93bik6IGRhdGEgaXMgVGltZU9mZnNldERhdGEge1xuICAgIGNvbnN0IGQgPSBkYXRhIGFzIFRpbWVPZmZzZXREYXRhIHwgdW5kZWZpbmVkO1xuICAgIHJldHVybiAoXG4gICAgICAgICEhZCAmJlxuICAgICAgICB0eXBlb2YgZC5sYXN0T2Zmc2V0ID09PSBcIm51bWJlclwiICYmXG4gICAgICAgIHR5cGVvZiBkLmxhc3RVcGRhdGVUaW1lID09PSBcIm51bWJlclwiICYmXG4gICAgICAgIHR5cGVvZiBkLm9mZnNldCA9PT0gXCJudW1iZXJcIiAmJlxuICAgICAgICB0eXBlb2YgZC51cGRhdGVUaW1lID09PSBcIm51bWJlclwiICYmXG4gICAgICAgIHR5cGVvZiBkLm5leHRPZmZzZXQgPT09IFwibnVtYmVyXCIgJiZcbiAgICAgICAgdHlwZW9mIGQubmV4dFVwZGF0ZVRpbWUgPT09IFwibnVtYmVyXCJcbiAgICApO1xufVxuXG50eXBlIFRpbWVPZmZzZXRTdG9yZUVudHJ5ID0ge1xuICAgIGRhdGE6IFRpbWVPZmZzZXREYXRhO1xuICAgIHZlcnNpb246IG51bWJlcjtcbn07XG50eXBlIFRpbWVPZmZzZXRTdG9yZSA9IHtcbiAgICBnZXRFbnRyeSgpOiBQcm9taXNlPFRpbWVPZmZzZXRTdG9yZUVudHJ5IHwgdW5kZWZpbmVkPjtcbiAgICAvLyBBdG9taWMgY29uZGl0aW9uYWwgd3JpdGUsIG9ubHkgc3VjY2VlZHMgaWYgdGhlIHN0b3JlZCB2ZXJzaW9uIG1hdGNoZXMgZXhwZWN0ZWRWZXJzaW9uLlxuICAgIHB1dElmVmVyc2lvbihkYXRhOiBUaW1lT2Zmc2V0RGF0YSwgZXhwZWN0ZWRWZXJzaW9uOiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+O1xuICAgIC8vIFVuY29uZGl0aW9uYWwgd3JpdGUgd2hlbiBubyBlbnRyeSBleGlzdHMgeWV0LiBSZXR1cm5zIGZhbHNlIGlmIGFub3RoZXIgd3JpdGVyIHJhY2VkIHVzLCBpbiB3aGljaCBjYXNlIHRoZSBjYWxsZXIgc2hvdWxkIHJlLXJlYWQgYW5kIHVzZSB0aGVpciBkYXRhLlxuICAgIHB1dEluaXRpYWwoZGF0YTogVGltZU9mZnNldERhdGEpOiBQcm9taXNlPGJvb2xlYW4+O1xufTtcblxubGV0IHRpbWVPZmZzZXREYjogaW1wb3J0KFwibG1kYlwiKS5Sb290RGF0YWJhc2U8VGltZU9mZnNldERhdGEsIHN0cmluZz4gfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5hc3luYyBmdW5jdGlvbiBnZXRUaW1lT2Zmc2V0RGIoKSB7XG4gICAgaWYgKCFVU0VfTE1EQl9QUk9DRVNTX1NZTkMpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgaWYgKHRpbWVPZmZzZXREYikgcmV0dXJuIHRpbWVPZmZzZXREYjtcbiAgICBpZiAoIWlzTm9kZSgpKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgbG1kYiA9IGF3YWl0IGltcG9ydChcImxtZGJcIik7XG4gICAgICAgIGNvbnN0IHBhdGggPSBhd2FpdCBpbXBvcnQoXCJwYXRoXCIpO1xuICAgICAgICBjb25zdCBvcyA9IGF3YWl0IGltcG9ydChcIm9zXCIpO1xuXG4gICAgICAgIGNvbnN0IGRiUGF0aCA9IHBhdGguam9pbihvcy50bXBkaXIoKSwgXCJzb2NrZXQtZnVuY3Rpb24tdGltZS1vZmZzZXQtMlwiKTtcbiAgICAgICAgdGltZU9mZnNldERiID0gbG1kYi5vcGVuPFRpbWVPZmZzZXREYXRhLCBzdHJpbmc+KHtcbiAgICAgICAgICAgIHBhdGg6IGRiUGF0aCxcbiAgICAgICAgICAgIC8vIEVuYWJsZSB2ZXJzaW9uaW5nIGZvciBjb25kaXRpb25hbCB3cml0ZXNcbiAgICAgICAgICAgIHVzZVZlcnNpb25zOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHRpbWVPZmZzZXREYjtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBvcGVuaW5nIExNREIgZGF0YWJhc2U6XCIsIGUpO1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZ2V0TG1kYlN0b3JlKGRiOiBpbXBvcnQoXCJsbWRiXCIpLlJvb3REYXRhYmFzZTxUaW1lT2Zmc2V0RGF0YSwgc3RyaW5nPik6IFRpbWVPZmZzZXRTdG9yZSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgYXN5bmMgZ2V0RW50cnkoKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGVudHJ5ID0gYXdhaXQgZGIuZ2V0RW50cnkoXCJ0aW1lT2Zmc2V0XCIpOyAvLyBHZXRzIHt2YWx1ZSwgdmVyc2lvbn0gYXRvbWljYWxseVxuICAgICAgICAgICAgICAgIGlmICghZW50cnkpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBlbnRyeS52ZXJzaW9uICE9PSBcIm51bWJlclwiIHx8ICFpc1ZhbGlkVGltZU9mZnNldERhdGEoZW50cnkudmFsdWUpKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHJldHVybiB7IGRhdGE6IGVudHJ5LnZhbHVlLCB2ZXJzaW9uOiBlbnRyeS52ZXJzaW9uIH07XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHJlYWRpbmcgZnJvbSBMTURCIGRhdGFiYXNlOlwiLCBlKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBhc3luYyBwdXRJZlZlcnNpb24oZGF0YSwgZXhwZWN0ZWRWZXJzaW9uKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIFVzZSByYW5kb20gdmVyc2lvbiB0byBtaW5pbWl6ZSBjb2xsaXNpb24gcHJvYmFiaWxpdHkgb24gcmV0cmllc1xuICAgICAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSBNYXRoLnJhbmRvbSgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHN1Y2Nlc3MgPSBhd2FpdCBkYi5pZlZlcnNpb24oXCJ0aW1lT2Zmc2V0XCIsIGV4cGVjdGVkVmVyc2lvbiwgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGIucHV0KFwidGltZU9mZnNldFwiLCBkYXRhLCBuZXdWZXJzaW9uKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3VjY2VzcyAhPT0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciB3cml0aW5nIHRvIExNREIgZGF0YWJhc2U6XCIsIGUpO1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgYXN5bmMgcHV0SW5pdGlhbChkYXRhKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSBNYXRoLnJhbmRvbSgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGRiLnB1dChcInRpbWVPZmZzZXRcIiwgZGF0YSwgbmV3VmVyc2lvbik7XG4gICAgICAgICAgICAgICAgLy8gUmVhZCBiYWNrIHRvIHNlZSB3aGF0IGFjdHVhbGx5IGdvdCB3cml0dGVuXG4gICAgICAgICAgICAgICAgY29uc3QgYWN0dWFsRW50cnkgPSBhd2FpdCBkYi5nZXRFbnRyeShcInRpbWVPZmZzZXRcIik7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFjdHVhbEVudHJ5Py52ZXJzaW9uID09PSBuZXdWZXJzaW9uO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciB3cml0aW5nIHRvIExNREIgZGF0YWJhc2U6XCIsIGUpO1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBnZXRMb2NhbFN0b3JhZ2VTdG9yZSgpOiBUaW1lT2Zmc2V0U3RvcmUgfCB1bmRlZmluZWQge1xuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2YgbG9jYWxTdG9yYWdlID09PSBcInVuZGVmaW5lZFwiKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICB0eXBlIFN0b3JlZFZhbHVlID0ge1xuICAgICAgICB2ZXJzaW9uOiBudW1iZXI7XG4gICAgICAgIGRhdGE6IFRpbWVPZmZzZXREYXRhO1xuICAgIH07XG4gICAgZnVuY3Rpb24gcmVhZFN0b3JlZCgpOiBTdG9yZWRWYWx1ZSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByYXcgPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbShUSU1FX09GRlNFVF9MT0NBTF9TVE9SQUdFX0tFWSk7XG4gICAgICAgICAgICBpZiAoIXJhdykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UocmF3KSBhcyBTdG9yZWRWYWx1ZTtcbiAgICAgICAgICAgIGlmICghcGFyc2VkIHx8IHR5cGVvZiBwYXJzZWQudmVyc2lvbiAhPT0gXCJudW1iZXJcIiB8fCAhaXNWYWxpZFRpbWVPZmZzZXREYXRhKHBhcnNlZC5kYXRhKSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIHJldHVybiBwYXJzZWQ7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciByZWFkaW5nIHRpbWUgb2Zmc2V0IGZyb20gbG9jYWxTdG9yYWdlOlwiLCAoZSBhcyBFcnJvcikuc3RhY2sgPz8gZSk7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZ1bmN0aW9uIHdyaXRlU3RvcmVkKGRhdGE6IFRpbWVPZmZzZXREYXRhKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHZlcnNpb24gPSBNYXRoLnJhbmRvbSgpO1xuICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oVElNRV9PRkZTRVRfTE9DQUxfU1RPUkFHRV9LRVksIEpTT04uc3RyaW5naWZ5KHsgdmVyc2lvbiwgZGF0YSB9KSk7XG4gICAgICAgICAgICByZXR1cm4gdmVyc2lvbjtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHdyaXRpbmcgdGltZSBvZmZzZXQgdG8gbG9jYWxTdG9yYWdlOlwiLCAoZSBhcyBFcnJvcikuc3RhY2sgPz8gZSk7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIGFzeW5jIGdldEVudHJ5KCkge1xuICAgICAgICAgICAgY29uc3Qgc3RvcmVkID0gcmVhZFN0b3JlZCgpO1xuICAgICAgICAgICAgaWYgKCFzdG9yZWQpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICByZXR1cm4geyBkYXRhOiBzdG9yZWQuZGF0YSwgdmVyc2lvbjogc3RvcmVkLnZlcnNpb24gfTtcbiAgICAgICAgfSxcbiAgICAgICAgLy8gbG9jYWxTdG9yYWdlIGhhcyBubyBhdG9taWMgY29tcGFyZS1hbmQtc3dhcCwgYnV0IGFjY2VzcyB3aXRoaW4gYSB0YWIgaXMgc3luY2hyb25vdXMsIHNvIHJlLXJlYWRpbmcgdGhlIHZlcnNpb24gaW1tZWRpYXRlbHkgYmVmb3JlIHdyaXRpbmcgc2hyaW5rcyB0aGUgcmFjZSB3aW5kb3cgdG8gZWZmZWN0aXZlbHkgbm90aGluZy4gV29yc3QgY2FzZSB0d28gdGFicyBib3RoIGZldGNoIGFuIG9mZnNldCwgd2hpY2ggaXMgaGFybWxlc3MuXG4gICAgICAgIGFzeW5jIHB1dElmVmVyc2lvbihkYXRhLCBleHBlY3RlZFZlcnNpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IHN0b3JlZCA9IHJlYWRTdG9yZWQoKTtcbiAgICAgICAgICAgIGlmIChzdG9yZWQ/LnZlcnNpb24gIT09IGV4cGVjdGVkVmVyc2lvbikgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgcmV0dXJuIHdyaXRlU3RvcmVkKGRhdGEpICE9PSB1bmRlZmluZWQ7XG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jIHB1dEluaXRpYWwoZGF0YSkge1xuICAgICAgICAgICAgY29uc3QgdmVyc2lvbiA9IHdyaXRlU3RvcmVkKGRhdGEpO1xuICAgICAgICAgICAgaWYgKHZlcnNpb24gPT09IHVuZGVmaW5lZCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgcmV0dXJuIHJlYWRTdG9yZWQoKT8udmVyc2lvbiA9PT0gdmVyc2lvbjtcbiAgICAgICAgfSxcbiAgICB9O1xufVxuXG5sZXQgdGltZU9mZnNldFN0b3JlOiBUaW1lT2Zmc2V0U3RvcmUgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5sZXQgdGltZU9mZnNldFN0b3JlUmVzb2x2ZWQgPSBmYWxzZTtcbmFzeW5jIGZ1bmN0aW9uIGdldFRpbWVPZmZzZXRTdG9yZSgpOiBQcm9taXNlPFRpbWVPZmZzZXRTdG9yZSB8IHVuZGVmaW5lZD4ge1xuICAgIGlmICh0aW1lT2Zmc2V0U3RvcmVSZXNvbHZlZCkgcmV0dXJuIHRpbWVPZmZzZXRTdG9yZTtcbiAgICBpZiAoaXNOb2RlKCkpIHtcbiAgICAgICAgY29uc3QgZGIgPSBhd2FpdCBnZXRUaW1lT2Zmc2V0RGIoKTtcbiAgICAgICAgaWYgKGRiKSB7XG4gICAgICAgICAgICB0aW1lT2Zmc2V0U3RvcmUgPSBnZXRMbWRiU3RvcmUoZGIpO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGltZU9mZnNldFN0b3JlID0gZ2V0TG9jYWxTdG9yYWdlU3RvcmUoKTtcbiAgICB9XG4gICAgdGltZU9mZnNldFN0b3JlUmVzb2x2ZWQgPSB0cnVlO1xuICAgIHJldHVybiB0aW1lT2Zmc2V0U3RvcmU7XG59XG5cbmxldCBnZXRUaW1lT2Zmc2V0QmFzZTogKCkgPT4gUHJvbWlzZTxudW1iZXIgfCBUaW1lT2Zmc2V0TWVhc3VyZW1lbnQ+ID0gZGVmYXVsdEdldFRpbWVPZmZzZXQ7XG5cbi8vIFJldHVybnMgdW5kZWZpbmVkIGlmIHdlIGNvdWxkbid0IGdldCBhbnkgbWVhc3VyZW1lbnRzLiBDYWxsZXJzIG11c3QgTk9UIHRyZWF0IHRoYXQgYXMgYW4gb2Zmc2V0IG9mIDAgLSBhIGZhYnJpY2F0ZWQgb2Zmc2V0IHdyaXR0ZW4gdG8gdGhlIHNoYXJlZCBzdG9yZSB3b3VsZCBwb2lzb24gZXZlcnkgb3RoZXIgcHJvY2Vzcy90YWIgZm9yIHRoZSBmdWxsIHRyYW5zaXRpb24gd2luZG93LlxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hOZXdPZmZzZXQoKTogUHJvbWlzZTxUaW1lT2Zmc2V0TWVhc3VyZW1lbnQgfCB1bmRlZmluZWQ+IHtcbiAgICBsZXQgbWVhc3VyZW1lbnRzOiBUaW1lT2Zmc2V0TWVhc3VyZW1lbnRbXSA9IFtdO1xuICAgIGxldCBmYWlsdXJlcyA9IDA7XG4gICAgbGV0IHJldHJ5RGVsYXkgPSBGRVRDSF9SRVRSWV9JTklUSUFMX0RFTEFZO1xuICAgIHdoaWxlIChtZWFzdXJlbWVudHMubGVuZ3RoIDwgVVBEQVRFX1ZFUklGWV9DT1VOVCkge1xuICAgICAgICAvLyBUaGUgdGFiIG1heSBoYXZlIGJlZW4gaGlkZGVuIG1pZC1mZXRjaC4gTWVhc3VyZW1lbnRzIGZyb20gYSB0aHJvdHRsZWQgdGFiIGFyZSB3b3JzZSB0aGFuIG5vbmUsIHNvIHN0b3AgYW5kIHVzZSB3aGF0ZXZlciB3ZSBhbHJlYWR5IGNvbGxlY3RlZC5cbiAgICAgICAgaWYgKCFjYW5NZWFzdXJlT2Zmc2V0KCkpIGJyZWFrO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZ2V0VGltZU9mZnNldEJhc2UoKTtcbiAgICAgICAgICAgIG1lYXN1cmVtZW50cy5wdXNoKHR5cGVvZiByZXN1bHQgPT09IFwibnVtYmVyXCIgPyB7IG9mZnNldDogcmVzdWx0IH0gOiByZXN1bHQpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgZ2V0dGluZyB0aW1lIG9mZnNldDpcIiwgKGUgYXMgRXJyb3IpLnN0YWNrID8/IGUpO1xuICAgICAgICAgICAgZmFpbHVyZXMrKztcbiAgICAgICAgICAgIGlmIChmYWlsdXJlcyA+PSBGRVRDSF9NQVhfRkFJTFVSRVMpIGJyZWFrO1xuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIHJldHJ5RGVsYXkpKTtcbiAgICAgICAgICAgIHJldHJ5RGVsYXkgPSBNYXRoLm1pbihyZXRyeURlbGF5ICogMiwgRkVUQ0hfUkVUUllfTUFYX0RFTEFZKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmIChtZWFzdXJlbWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gUGljayB0aGUgbWlkZGxlIG9mZnNldFxuICAgIG1lYXN1cmVtZW50cy5zb3J0KChhLCBiKSA9PiBhLm9mZnNldCAtIGIub2Zmc2V0KTtcbiAgICBsZXQgbWVhc3VyZW1lbnQgPSBtZWFzdXJlbWVudHNbTWF0aC5mbG9vcihtZWFzdXJlbWVudHMubGVuZ3RoIC8gMildO1xuICAgIGxldCBvZmZzZXQgPSBtZWFzdXJlbWVudC5vZmZzZXQ7XG5cbiAgICAvLyBMb2cgaWYgb2Zmc2V0IGlzIHNpZ25pZmljYW50XG4gICAgbGV0IG9mZnNldFJvdW5kID0gTWF0aC5hYnMoTWF0aC5yb3VuZChvZmZzZXQpKTtcbiAgICBsZXQgb2Zmc2V0Q29sb3JlZCA9IChcbiAgICAgICAgTWF0aC5hYnMob2Zmc2V0KSA+IDYwMCAmJiByZWQob2Zmc2V0Um91bmQgKyBcIm1zXCIpXG4gICAgICAgIHx8IE1hdGguYWJzKG9mZnNldCkgPiAzMDAgJiYgeWVsbG93KG9mZnNldFJvdW5kICsgXCJtc1wiKVxuICAgICAgICB8fCBncmVlbihvZmZzZXRSb3VuZCArIFwibXNcIilcbiAgICApO1xuICAgIGlmIChNYXRoLmFicyhvZmZzZXQpID4gNTAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke2JsdWUoXCJTeW5jaHJvbml6ZWQgdGltZVwiKX0sIGxvY2FsIGNsb2NrIHdhcyAke29mZnNldCA+IDAgPyBcImJlaGluZFwiIDogXCJhaGVhZFwifSBieSAke29mZnNldENvbG9yZWR9IEAgJHtibHVlKERhdGUubm93KCkgKyBcIlwiKX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbWVhc3VyZW1lbnQ7XG59XG5cbmZ1bmN0aW9uIGNhbk1lYXN1cmVPZmZzZXQoKSB7XG4gICAgaWYgKGlzTm9kZSgpKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAodHlwZW9mIGRvY3VtZW50ID09PSBcInVuZGVmaW5lZFwiKSByZXR1cm4gdHJ1ZTtcbiAgICAvLyBIaWRkZW4gdGFicyBnZXQgdGhlaXIgdGltZXJzIGFuZCBtZXNzYWdlIGRlbGl2ZXJ5IHRocm90dGxlZCwgd2hpY2ggY29ycnVwdHMgdGhlIHJvdW5kLXRyaXAgbGF0ZW5jeSBlc3RpbWF0ZSBhbmQgdGhlcmVmb3JlIHRoZSBvZmZzZXQuIEEgdmlzaWJsZSB0YWIgd2lsbCBtZWFzdXJlIGFuZCBzaGFyZSB2aWEgbG9jYWxTdG9yYWdlIGluc3RlYWQuXG4gICAgcmV0dXJuIGRvY3VtZW50LnZpc2liaWxpdHlTdGF0ZSAhPT0gXCJoaWRkZW5cIjtcbn1cblxubGV0IHVwZGF0aW5nT2Zmc2V0ID0gZmFsc2U7XG5hc3luYyBmdW5jdGlvbiB1cGRhdGVUaW1lT2Zmc2V0KCkge1xuICAgIGlmICh1cGRhdGluZ09mZnNldCkgcmV0dXJuO1xuICAgIHVwZGF0aW5nT2Zmc2V0ID0gdHJ1ZTtcblxuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHN0b3JlID0gYXdhaXQgZ2V0VGltZU9mZnNldFN0b3JlKCk7XG4gICAgICAgIGlmICghc3RvcmUpIHtcbiAgICAgICAgICAgIC8vIElNUE9SVEFOVDogQWx3YXlzIHVzZSBiYXNlR2V0VGltZSgpIGZvciBzY2hlZHVsaW5nLCBuZXZlciBnZXRUcnVlVGltZSgpLlxuICAgICAgICAgICAgLy8gT3VyIHVwZGF0ZSBzY2hlZHVsZSBtdXN0IGJlIGJhc2VkIG9uIHRoZSBzdGFibGUgc3lzdGVtIGNsb2NrLCBub3QgdGhlXG4gICAgICAgICAgICAvLyBvZmZzZXQtYWRqdXN0ZWQgdGltZSB3aGljaCBjaGFuZ2VzIGFzIHdlIHN5bmNocm9uaXplLlxuICAgICAgICAgICAgY29uc3QgY3VycmVudFRpbWUgPSBiYXNlR2V0VGltZSgpO1xuICAgICAgICAgICAgbGV0IGNhY2hlZERhdGEgPSBjYWNoZWRUaW1lT2Zmc2V0RGF0YTtcbiAgICAgICAgICAgIGlmIChjYWNoZWREYXRhICYmIGN1cnJlbnRUaW1lID49IGNhY2hlZERhdGEubmV4dFVwZGF0ZVRpbWUpIHtcbiAgICAgICAgICAgICAgICAvLyBQYXN0IHRoZSBlbmQgLSByZXNldCBhbmQgcmVpbml0aWFsaXplXG4gICAgICAgICAgICAgICAgY2FjaGVkRGF0YSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIlBhc3QgbmV4dFVwZGF0ZVRpbWUsIHJlc2V0dGluZ1wiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgbmVlZHNGZXRjaCA9ICFjYWNoZWREYXRhIHx8IGN1cnJlbnRUaW1lID49IGNhY2hlZERhdGEudXBkYXRlVGltZTtcbiAgICAgICAgICAgIGlmIChuZWVkc0ZldGNoICYmICFjYW5NZWFzdXJlT2Zmc2V0KCkpIHtcbiAgICAgICAgICAgICAgICAvLyBLZWVwIHVzaW5nIHdoYXRldmVyIG9mZnNldCB3ZSBoYXZlIChldmVuIGEgc3RhbGUgb25lIGlzIGJldHRlciB0aGFuIGEgbWVhc3VyZW1lbnQgc2tld2VkIGJ5IGJhY2tncm91bmQgdGhyb3R0bGluZykuXG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFjYWNoZWREYXRhKSB7XG4gICAgICAgICAgICAgICAgLy8gRmlyc3QgdGltZSBpbml0aWFsaXphdGlvblxuICAgICAgICAgICAgICAgIGNvbnN0IG1lYXN1cmVtZW50ID0gYXdhaXQgZmV0Y2hOZXdPZmZzZXQoKTtcbiAgICAgICAgICAgICAgICBpZiAobWVhc3VyZW1lbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gUmUtcmVhZCB0aGUgdGltZSwgYXMgZmV0Y2hOZXdPZmZzZXQgY2FuIHRha2UgbWludXRlcyB3aGVuIGl0IGhhcyB0byByZXRyeS5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5pdFRpbWUgPSBiYXNlR2V0VGltZSgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBtZWFzdXJlbWVudC5vZmZzZXQ7XG4gICAgICAgICAgICAgICAgICAgIGNhY2hlZFRpbWVPZmZzZXREYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdE9mZnNldDogb2Zmc2V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdFVwZGF0ZVRpbWU6IGluaXRUaW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0OiBvZmZzZXQsXG4gICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVUaW1lOiBpbml0VGltZSArIFVQREFURV9UUkFOU0lUSU9OX0dBUCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRPZmZzZXQ6IG9mZnNldCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRVcGRhdGVUaW1lOiBpbml0VGltZSArIFVQREFURV9UUkFOU0lUSU9OX0dBUCAqIDIsXG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9vZjogbWVhc3VyZW1lbnQucHJvb2YsXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiSW5pdGlhbGl6ZWQgLSB0aW1lIG9mZnNldDpcIiwgb2Zmc2V0LCBcIm1zLCBuZXh0IHVwZGF0ZSBpblwiLCBVUERBVEVfVFJBTlNJVElPTl9HQVAsIFwibXNcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIE9uIHRvdGFsIGZhaWx1cmUgd2UgbGVhdmUgdGhlIGRhdGEgdW5zZXQgKGdldFRydWVUaW1lIHRoZW4gdXNlcyB0aGUgcmF3IHN5c3RlbSBjbG9jaykgYW5kIHRoZSBuZXh0IGNoZWNrIGludGVydmFsIHJldHJpZXMuIFdlIG5ldmVyIGZhYnJpY2F0ZSBhbiBvZmZzZXQuXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGN1cnJlbnRUaW1lID49IGNhY2hlZERhdGEudXBkYXRlVGltZSkge1xuICAgICAgICAgICAgICAgIC8vIFRpbWUgdG8gcm90YXRlXG4gICAgICAgICAgICAgICAgY29uc3QgbmV3TWVhc3VyZW1lbnQgPSBhd2FpdCBmZXRjaE5ld09mZnNldCgpO1xuICAgICAgICAgICAgICAgIGlmIChuZXdNZWFzdXJlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBjYWNoZWRUaW1lT2Zmc2V0RGF0YSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RPZmZzZXQ6IGNhY2hlZERhdGEub2Zmc2V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgbGFzdFVwZGF0ZVRpbWU6IGNhY2hlZERhdGEudXBkYXRlVGltZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9mZnNldDogY2FjaGVkRGF0YS5uZXh0T2Zmc2V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlVGltZTogY2FjaGVkRGF0YS5uZXh0VXBkYXRlVGltZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRPZmZzZXQ6IG5ld01lYXN1cmVtZW50Lm9mZnNldCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHRVcGRhdGVUaW1lOiBjYWNoZWREYXRhLm5leHRVcGRhdGVUaW1lICsgVVBEQVRFX1RSQU5TSVRJT05fR0FQLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvb2Y6IG5ld01lYXN1cmVtZW50LnByb29mLFxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0aW1lVW50aWxOZXh0ID0gY2FjaGVkVGltZU9mZnNldERhdGEubmV4dFVwZGF0ZVRpbWUgLSBiYXNlR2V0VGltZSgpO1xuICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkFkdmFuY2luZyB0aW1lIG9mZnNldCAtIGN1cnJlbnQ6XCIsIGNhY2hlZFRpbWVPZmZzZXREYXRhLm9mZnNldCwgXCJtcywgbmV4dDpcIiwgY2FjaGVkVGltZU9mZnNldERhdGEubmV4dE9mZnNldCwgXCJtcywgbmV4dCB1cGRhdGUgaW5cIiwgdGltZVVudGlsTmV4dCwgXCJtc1wiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEFsd2F5cyByZXNvbHZlIHRoZSBmaXJzdCBzeW5jLCBldmVuIG9uIGZhaWx1cmUgLSBTb2NrZXRGdW5jdGlvbi5tb3VudCBhd2FpdHMgdGhpcywgYW5kIGhhbmdpbmcgZm9yZXZlciBpcyB3b3JzZSB0aGFuIHRlbXBvcmFyaWx5IHJ1bm5pbmcgb24gdGhlIHVuYWRqdXN0ZWQgc3lzdGVtIGNsb2NrLlxuICAgICAgICAgICAgbWFya0ZpcnN0VGltZVN5bmMoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEF0IHRoaXMgcG9pbnQgd2UgaGF2ZSBhIHNoYXJlZCBzdG9yZSAoTE1EQiBmb3IgcHJvY2Vzc2VzLCBsb2NhbFN0b3JhZ2UgZm9yIHRhYnMpIHdpdGggYXRvbWljLWlzaCB2ZXJzaW9uZWQgd3JpdGVzLlxuICAgICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICAgICAgY29uc3QgZW50cnkgPSBhd2FpdCBzdG9yZS5nZXRFbnRyeSgpO1xuICAgICAgICAgICAgLy8gSU1QT1JUQU5UOiBBbHdheXMgdXNlIGJhc2VHZXRUaW1lKCkgZm9yIHNjaGVkdWxpbmcsIG5ldmVyIGdldFRydWVUaW1lKCkuXG4gICAgICAgICAgICAvLyBPdXIgdXBkYXRlIHNjaGVkdWxlIG11c3QgYmUgYmFzZWQgb24gdGhlIHN0YWJsZSBzeXN0ZW0gY2xvY2ssIG5vdCB0aGVcbiAgICAgICAgICAgIC8vIG9mZnNldC1hZGp1c3RlZCB0aW1lIHdoaWNoIGNoYW5nZXMgYXMgd2Ugc3luY2hyb25pemUuXG4gICAgICAgICAgICBjb25zdCBjdXJyZW50VGltZSA9IGJhc2VHZXRUaW1lKCk7XG5cbiAgICAgICAgICAgIGxldCBjYWNoZWREYXRhID0gZW50cnk/LmRhdGE7XG4gICAgICAgICAgICBjb25zdCByZWFkVmVyc2lvbiA9IGVudHJ5Py52ZXJzaW9uO1xuXG4gICAgICAgICAgICBpZiAoY2FjaGVkRGF0YSAmJiBjdXJyZW50VGltZSA+PSBjYWNoZWREYXRhLm5leHRVcGRhdGVUaW1lKSB7XG4gICAgICAgICAgICAgICAgLy8gUGFzdCB0aGUgZW5kIC0gcmVzZXQgYW5kIHJlaW5pdGlhbGl6ZVxuICAgICAgICAgICAgICAgIGNhY2hlZERhdGEgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgZGVidWdMb2coXCJQYXN0IG5leHRVcGRhdGVUaW1lLCByZXNldHRpbmdcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IG5lZWRzRmV0Y2ggPSAhY2FjaGVkRGF0YSB8fCBjdXJyZW50VGltZSA+PSBjYWNoZWREYXRhLnVwZGF0ZVRpbWU7XG4gICAgICAgICAgICBpZiAobmVlZHNGZXRjaCAmJiAhY2FuTWVhc3VyZU9mZnNldCgpKSB7XG4gICAgICAgICAgICAgICAgLy8gS2VlcCB1c2luZyB3aGF0ZXZlciBvZmZzZXQgd2UgaGF2ZSAoZXZlbiBhIHN0YWxlIG9uZSBpcyBiZXR0ZXIgdGhhbiBhIG1lYXN1cmVtZW50IHNrZXdlZCBieSBiYWNrZ3JvdW5kIHRocm90dGxpbmcpLiBJZiB3ZSBoYXZlIG5vdGhpbmcsIHJ1biB1bnN5bmNlZCB1bnRpbCB3ZSBiZWNvbWUgdmlzaWJsZSBvciBhbm90aGVyIHRhYiB3cml0ZXMgdG8gdGhlIHN0b3JlLlxuICAgICAgICAgICAgICAgIGNhY2hlZFRpbWVPZmZzZXREYXRhID0gZW50cnk/LmRhdGEgPz8gY2FjaGVkVGltZU9mZnNldERhdGE7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghY2FjaGVkRGF0YSB8fCAhcmVhZFZlcnNpb24pIHtcbiAgICAgICAgICAgICAgICAvLyBGaXJzdCB0aW1lIGluaXRpYWxpemF0aW9uIC0gdXNlIGNvbmRpdGlvbmFsIHdyaXRlIHRvIGhhbmRsZSByYWNlXG4gICAgICAgICAgICAgICAgY29uc3QgbWVhc3VyZW1lbnQgPSBhd2FpdCBmZXRjaE5ld09mZnNldCgpO1xuICAgICAgICAgICAgICAgIGlmICghbWVhc3VyZW1lbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVG90YWwgZmFpbHVyZSAtIGtlZXAgYW55IHN0YWxlIGRhdGEgcmF0aGVyIHRoYW4gd3JpdGluZyBhIGZhYnJpY2F0ZWQgb2Zmc2V0IHRvIHRoZSBzaGFyZWQgc3RvcmUuIFRoZSBuZXh0IGNoZWNrIGludGVydmFsIHJldHJpZXMuXG4gICAgICAgICAgICAgICAgICAgIGNhY2hlZFRpbWVPZmZzZXREYXRhID0gZW50cnk/LmRhdGEgPz8gY2FjaGVkVGltZU9mZnNldERhdGE7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBSZS1yZWFkIHRoZSB0aW1lLCBhcyBmZXRjaE5ld09mZnNldCBjYW4gdGFrZSBtaW51dGVzIHdoZW4gaXQgaGFzIHRvIHJldHJ5LlxuICAgICAgICAgICAgICAgIGNvbnN0IGluaXRUaW1lID0gYmFzZUdldFRpbWUoKTtcbiAgICAgICAgICAgICAgICBjb25zdCBvZmZzZXQgPSBtZWFzdXJlbWVudC5vZmZzZXQ7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdERhdGE6IFRpbWVPZmZzZXREYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBsYXN0T2Zmc2V0OiBvZmZzZXQsXG4gICAgICAgICAgICAgICAgICAgIGxhc3RVcGRhdGVUaW1lOiBpbml0VGltZSxcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0OiBvZmZzZXQsXG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZVRpbWU6IGluaXRUaW1lICsgVVBEQVRFX1RSQU5TSVRJT05fR0FQLFxuICAgICAgICAgICAgICAgICAgICBuZXh0T2Zmc2V0OiBvZmZzZXQsXG4gICAgICAgICAgICAgICAgICAgIG5leHRVcGRhdGVUaW1lOiBpbml0VGltZSArIFVQREFURV9UUkFOU0lUSU9OX0dBUCAqIDIsXG4gICAgICAgICAgICAgICAgICAgIHByb29mOiBtZWFzdXJlbWVudC5wcm9vZixcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgaWYgKHJlYWRWZXJzaW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHN1Y2Nlc3MgPSBhd2FpdCBzdG9yZS5wdXRJZlZlcnNpb24oaW5pdERhdGEsIHJlYWRWZXJzaW9uKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkxvc3QgdGhlIHJhY2UsIHJldHJ5aW5nXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gTG9zdCB0aGUgcmFjZSwgcmV0cnlcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNhY2hlZFRpbWVPZmZzZXREYXRhID0gaW5pdERhdGE7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiU3VjY2Vzc2Z1bGx5IHdyb3RlIGF0b21pYyByZXNldFwiKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCFhd2FpdCBzdG9yZS5wdXRJbml0aWFsKGluaXREYXRhKSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBMb3N0IHRoZSByYWNlLCBhbm90aGVyIHdyaXRlciB3cm90ZSBhZnRlciB1c1xuICAgICAgICAgICAgICAgICAgICAvLyBSZXRyeSBmcm9tIHRoZSB0b3AgdG8gcmVhZCB0aGVpciBkYXRhXG4gICAgICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiVmFsdWUgd2FzIGNoYW5nZWQgYnkgYW5vdGhlciBwcm9jZXNzLCByZXRyeWluZ1wiKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gV2Ugd29uIHRoZSByYWNlLCB1c2Ugb3VyIGRhdGFcbiAgICAgICAgICAgICAgICBjYWNoZWRUaW1lT2Zmc2V0RGF0YSA9IGluaXREYXRhO1xuICAgICAgICAgICAgICAgIGRlYnVnTG9nKFwiSW5pdGlhbGl6ZWQgLSB0aW1lIG9mZnNldDpcIiwgb2Zmc2V0LCBcIm1zLCBuZXh0IHVwZGF0ZSBpblwiLCBVUERBVEVfVFJBTlNJVElPTl9HQVAsIFwibXNcIik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChjdXJyZW50VGltZSA+PSBjYWNoZWREYXRhLnVwZGF0ZVRpbWUpIHtcbiAgICAgICAgICAgICAgICAvLyBUaW1lIHRvIHJvdGF0ZVxuICAgICAgICAgICAgICAgIGNvbnN0IG5ld01lYXN1cmVtZW50ID0gYXdhaXQgZmV0Y2hOZXdPZmZzZXQoKTtcbiAgICAgICAgICAgICAgICBpZiAoIW5ld01lYXN1cmVtZW50KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFRvdGFsIGZhaWx1cmUgLSBrZWVwIHRoZSBleGlzdGluZyBkYXRhIHVucm90YXRlZCAodGhlIG9mZnNldCBqdXN0IGZsYXR0ZW5zIG91dCBhdCBuZXh0T2Zmc2V0KS4gVGhlIG5leHQgY2hlY2sgaW50ZXJ2YWwgcmV0cmllcyB0aGUgcm90YXRpb24uXG4gICAgICAgICAgICAgICAgICAgIGNhY2hlZFRpbWVPZmZzZXREYXRhID0gY2FjaGVkRGF0YTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IG5ld0RhdGE6IFRpbWVPZmZzZXREYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBsYXN0T2Zmc2V0OiBjYWNoZWREYXRhLm9mZnNldCxcbiAgICAgICAgICAgICAgICAgICAgbGFzdFVwZGF0ZVRpbWU6IGNhY2hlZERhdGEudXBkYXRlVGltZSxcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0OiBjYWNoZWREYXRhLm5leHRPZmZzZXQsXG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZVRpbWU6IGNhY2hlZERhdGEubmV4dFVwZGF0ZVRpbWUsXG4gICAgICAgICAgICAgICAgICAgIG5leHRPZmZzZXQ6IG5ld01lYXN1cmVtZW50Lm9mZnNldCxcbiAgICAgICAgICAgICAgICAgICAgbmV4dFVwZGF0ZVRpbWU6IGNhY2hlZERhdGEubmV4dFVwZGF0ZVRpbWUgKyBVUERBVEVfVFJBTlNJVElPTl9HQVAsXG4gICAgICAgICAgICAgICAgICAgIHByb29mOiBuZXdNZWFzdXJlbWVudC5wcm9vZixcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgY29uc3Qgc3VjY2VzcyA9IGF3YWl0IHN0b3JlLnB1dElmVmVyc2lvbihuZXdEYXRhLCByZWFkVmVyc2lvbik7XG4gICAgICAgICAgICAgICAgaWYgKCFzdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIExvc3QgdGhlIHJhY2UsIHJldHJ5XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbnN0IHRpbWVVbnRpbE5leHQgPSBuZXdEYXRhLm5leHRVcGRhdGVUaW1lIC0gYmFzZUdldFRpbWUoKTtcbiAgICAgICAgICAgICAgICBkZWJ1Z0xvZyhcIkFkdmFuY2luZyB0aW1lIG9mZnNldCAtIGN1cnJlbnQ6XCIsIG5ld0RhdGEub2Zmc2V0LCBcIm1zLCBuZXh0OlwiLCBuZXdEYXRhLm5leHRPZmZzZXQsIFwibXMsIG5leHQgdXBkYXRlIGluXCIsIHRpbWVVbnRpbE5leHQsIFwibXNcIik7XG4gICAgICAgICAgICAgICAgY2FjaGVkVGltZU9mZnNldERhdGEgPSBuZXdEYXRhO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjYWNoZWRUaW1lT2Zmc2V0RGF0YSA9IGNhY2hlZERhdGE7XG4gICAgICAgICAgICAgICAgY29uc3QgdGltZVVudGlsTmV4dCA9IGNhY2hlZERhdGEudXBkYXRlVGltZSAtIGJhc2VHZXRUaW1lKCk7XG4gICAgICAgICAgICAgICAgZGVidWdMb2coXCJMb2FkZWQgZnJvbSBzdG9yZSAtIGN1cnJlbnQ6XCIsIGNhY2hlZERhdGEub2Zmc2V0LCBcIm1zLCBuZXh0OlwiLCBjYWNoZWREYXRhLm5leHRPZmZzZXQsIFwibXMsIG5leHQgdXBkYXRlIGluXCIsIHRpbWVVbnRpbE5leHQsIFwibXNcIik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBtYXJrRmlyc3RUaW1lU3luYygpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICAgIHVwZGF0aW5nT2Zmc2V0ID0gZmFsc2U7XG4gICAgfVxufVxuXG5mdW5jdGlvbiB0cmlnZ2VyVXBkYXRlVGltZU9mZnNldCgpIHtcbiAgICB1cGRhdGVUaW1lT2Zmc2V0KCkuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgY29uc29sZS53YXJuKFwiRXJyb3IgdXBkYXRpbmcgdGltZSBvZmZzZXQ6XCIsIGUpO1xuICAgIH0pO1xufVxuXG5zZXRJbnRlcnZhbCh0cmlnZ2VyVXBkYXRlVGltZU9mZnNldCwgVVBEQVRFX0NIRUNLX0lOVEVSVkFMKTtcbnNldEltbWVkaWF0ZSgoKSA9PiB7XG4gICAgdXBkYXRlVGltZU9mZnNldCgpLmNhdGNoKChlKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciB1cGRhdGluZyBpbml0aWFsIG9mZnNldDpcIiwgZSk7XG4gICAgfSk7XG59KTtcblxuaWYgKCFpc05vZGUoKSAmJiB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiICYmIHR5cGVvZiBkb2N1bWVudCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgIC8vIElmIHdlIGxvYWRlZCBpbiBhIGhpZGRlbiB0YWIgd2Ugc2tpcCBtZWFzdXJpbmcsIHNvIHJlLWNoZWNrIGFzIHNvb24gYXMgd2UgYmVjb21lIHZpc2libGUuXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcInZpc2liaWxpdHljaGFuZ2VcIiwgdHJpZ2dlclVwZGF0ZVRpbWVPZmZzZXQpO1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwiZm9jdXNcIiwgdHJpZ2dlclVwZGF0ZVRpbWVPZmZzZXQpO1xuICAgIC8vIFBpY2sgdXAgb2Zmc2V0cyBvdGhlciB0YWJzIHdyaXRlLCBzbyBvbmx5IG9uZSB0YWIgZXZlciBoYXMgdG8gbWVhc3VyZS5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInN0b3JhZ2VcIiwgKGUpID0+IHtcbiAgICAgICAgaWYgKGUua2V5ID09PSBUSU1FX09GRlNFVF9MT0NBTF9TVE9SQUdFX0tFWSkge1xuICAgICAgICAgICAgdHJpZ2dlclVwZGF0ZVRpbWVPZmZzZXQoKTtcbiAgICAgICAgfVxuICAgIH0pO1xufVxuXG5cbmNsYXNzIFRpbWVDb250cm9sbGVyQmFzZSB7XG4gICAgcHVibGljIGFzeW5jIGdldFRydWVUaW1lKCkge1xuICAgICAgICBhd2FpdCB3YWl0Rm9yRmlyc3RUaW1lU3luYygpO1xuICAgICAgICByZXR1cm4gZ2V0VHJ1ZVRpbWUoKTtcbiAgICB9XG59XG5cbmNvbnN0IFRpbWVDb250cm9sbGVyID0gU29ja2V0RnVuY3Rpb24ucmVnaXN0ZXIoXG4gICAgXCJUaW1lQ29udHJvbGxlci1kZGY0NzUzZS1mYzhhLTQxM2YtOGNjMi1iOTI3ZGQ0NDk5NzZcIixcbiAgICBuZXcgVGltZUNvbnRyb2xsZXJCYXNlKCksXG4gICAgKCkgPT4gKHtcbiAgICAgICAgZ2V0VHJ1ZVRpbWU6IHtcbiAgICAgICAgICAgIC8vIE5vIGhvb2tzLCBhcyB0aGlzIG5lZWRzIHRvIHJ1biB2ZXJ5IGVhcmx5IG9uLiBBbHNvLCBpdCBpcyBiYXNpY2FsbHkganVzdCBhIHBpbmcsXG4gICAgICAgICAgICAvLyAgc28gaXQgc2hvdWxkIGJlIHNhZmUgZm9yIGFueW9uZSB0byB1c2UgKHdlIG1pZ2h0IGV2ZW4gbWFrZSBpdCBqdXN0IGEgcmVndWxhciBIVFRQUyBlbmRwb2ludCxcbiAgICAgICAgICAgIC8vICBvciBldmVuIGp1c3Qgc2V0IHVwIGEgZGVkaWNhdGVkIGRvbWFpbiBmb3IgdGhpcykuXG4gICAgICAgICAgICBub0RlZmF1bHRIb29rczogdHJ1ZSxcbiAgICAgICAgICAgIG5vQ2xpZW50SG9va3M6IHRydWUsXG4gICAgICAgIH0sXG4gICAgfSksXG4gICAgKCkgPT4gKHt9KSxcbiAgICB7XG4gICAgICAgIC8vIE5PVEU6IEF1dG9leHBvc2UsIGJlY2F1c2Ugb3VyIGV4cG9zZWQgZW5kcG9pbnRzIGFyZSBpbmNyZWRpYmx5IGxpZ2h0d2VpZ2h0XG4gICAgICAgIC8vICAoanVzdCBhIHBpbmcpLCBhbmQgZG9uJ3QgZXhwb3NlIHJlYWxseSBleHBvc2UgYW55IGRhdGEuXG4gICAgICAgIC8vIG5vQXV0b0V4cG9zZTogdHJ1ZVxuICAgIH1cbik7XG4iXX0=
656
- /* _JS_SOURCE_HASH = "968e3388dca14b6870565a18eff7fadaa009775c1d22b6bdafd68faab5ed5263"; */