Implement JQHTML function cache ID system and fix bundle compilation Implement underscore prefix for system tables Fix JS syntax linter to support decorators and grant exception to Task system SPA: Update planning docs and wishlists with remaining features SPA: Document Navigation API abandonment and future enhancements Implement SPA browser integration with History API (Phase 1) Convert contacts view page to SPA action Convert clients pages to SPA actions and document conversion procedure SPA: Merge GET parameters and update documentation Implement SPA route URL generation in JavaScript and PHP Implement SPA bootstrap controller architecture Add SPA routing manual page (rsx:man spa) Add SPA routing documentation to CLAUDE.md Phase 4 Complete: Client-side SPA routing implementation Update get_routes() consumers for unified route structure Complete SPA Phase 3: PHP-side route type detection and is_spa flag Restore unified routes structure and Manifest_Query class Refactor route indexing and add SPA infrastructure Phase 3 Complete: SPA route registration in manifest Implement SPA Phase 2: Extract router code and test decorators Rename Jqhtml_Component to Component and complete SPA foundation setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
198 lines
21 KiB
JavaScript
Executable File
198 lines
21 KiB
JavaScript
Executable File
"use strict";
|
|
|
|
/*
|
|
* Async utility functions for the RSpade framework.
|
|
* These functions handle asynchronous operations, delays, debouncing, and mutexes.
|
|
*/
|
|
|
|
// ============================================================================
|
|
// ASYNC UTILITIES
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Pauses execution for specified milliseconds
|
|
* @param {number} [milliseconds=0] - Delay in milliseconds (0 uses requestAnimationFrame)
|
|
* @returns {Promise<void>} Promise that resolves after delay
|
|
* @example await sleep(1000); // Wait 1 second
|
|
*/
|
|
function sleep() {
|
|
let milliseconds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
return new Promise(resolve => {
|
|
if (milliseconds == 0 && requestAnimationFrame) {
|
|
requestAnimationFrame(resolve);
|
|
} else {
|
|
setTimeout(resolve, milliseconds);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates a debounced function with exclusivity and promise fan-in
|
|
*
|
|
* This function, when invoked, immediately runs the callback exclusively.
|
|
* For subsequent invocations, it applies a delay before running the callback exclusively again.
|
|
* The delay starts after the current asynchronous operation resolves.
|
|
*
|
|
* If 'delay' is set to 0, the function will only prevent enqueueing multiple executions of the
|
|
* same method more than once, but will still run them immediately in an exclusive sequential manner.
|
|
*
|
|
* The most recent invocation of the function will be the parameters that get passed to the function
|
|
* when it invokes.
|
|
*
|
|
* The function returns a promise that resolves when the next exclusive execution completes.
|
|
*
|
|
* Usage as function:
|
|
* const debouncedFn = debounce(myFunction, 250);
|
|
*
|
|
* Usage as decorator:
|
|
* @debounce(250)
|
|
* myMethod() { ... }
|
|
*
|
|
* @param {function|number} callback_or_delay The callback function OR delay when used as decorator
|
|
* @param {number} delay The delay in milliseconds before subsequent invocations
|
|
* @param {boolean} immediate if true, the first time the action is called, the callback executes immediately
|
|
* @returns {function} A function that when invoked, runs the callback immediately and exclusively,
|
|
*
|
|
* @decorator
|
|
*/
|
|
function debounce(callback_or_delay, delay) {
|
|
let immediate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
// Decorator usage: @debounce(250) or @debounce(250, true)
|
|
// First argument is a number (the delay), returns decorator function
|
|
if (typeof callback_or_delay === 'number') {
|
|
const decorator_delay = callback_or_delay;
|
|
const decorator_immediate = delay || false;
|
|
|
|
// TC39 decorator form: receives (value, context)
|
|
return function (value, context) {
|
|
if (context.kind === 'method') {
|
|
return debounce_impl(value, decorator_delay, decorator_immediate);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Function usage: debounce(fn, 250)
|
|
// First argument is a function (the callback)
|
|
const callback = callback_or_delay;
|
|
return debounce_impl(callback, delay, immediate);
|
|
}
|
|
|
|
/**
|
|
* Internal implementation of debounce logic
|
|
* @private
|
|
*/
|
|
function debounce_impl(callback, delay) {
|
|
let immediate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
let running = false;
|
|
let queued = false;
|
|
let last_end_time = 0; // timestamp of last completed run
|
|
let timer = null;
|
|
let next_args = [];
|
|
let next_context = null;
|
|
let resolve_queue = [];
|
|
let reject_queue = [];
|
|
const run_function = async () => {
|
|
const these_resolves = resolve_queue;
|
|
const these_rejects = reject_queue;
|
|
const args = next_args;
|
|
const context = next_context;
|
|
resolve_queue = [];
|
|
reject_queue = [];
|
|
next_args = [];
|
|
next_context = null;
|
|
queued = false;
|
|
running = true;
|
|
try {
|
|
const result = await callback.apply(context, args);
|
|
for (const resolve of these_resolves) resolve(result);
|
|
} catch (err) {
|
|
for (const reject of these_rejects) reject(err);
|
|
} finally {
|
|
running = false;
|
|
last_end_time = Date.now();
|
|
if (queued) {
|
|
clearTimeout(timer);
|
|
timer = setTimeout(run_function, Math.max(delay, 0));
|
|
} else {
|
|
timer = null;
|
|
}
|
|
}
|
|
};
|
|
return function () {
|
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
next_args = args;
|
|
next_context = this;
|
|
return new Promise((resolve, reject) => {
|
|
resolve_queue.push(resolve);
|
|
reject_queue.push(reject);
|
|
|
|
// Nothing running and nothing scheduled
|
|
if (!running && !timer) {
|
|
const first_call = last_end_time === 0;
|
|
if (immediate && first_call) {
|
|
run_function();
|
|
return;
|
|
}
|
|
const since = first_call ? Infinity : Date.now() - last_end_time;
|
|
if (since >= delay) {
|
|
run_function();
|
|
} else {
|
|
const wait = Math.max(delay - since, 0);
|
|
clearTimeout(timer);
|
|
timer = setTimeout(run_function, wait);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// If we're already running or a timer exists, just mark queued.
|
|
// The finally{} of run_function handles scheduling after full delay.
|
|
queued = true;
|
|
});
|
|
};
|
|
}
|
|
|
|
// ============================================================================
|
|
// READ-WRITE LOCK FUNCTIONS - Delegated to ReadWriteLock class
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Acquire an exclusive write lock by name.
|
|
* Only one writer runs at a time; blocks readers until finished.
|
|
* @param {string} name
|
|
* @param {() => any|Promise<any>} cb
|
|
* @returns {Promise<any>}
|
|
*/
|
|
function rwlock(name, cb) {
|
|
return ReadWriteLock.acquire(name, cb);
|
|
}
|
|
|
|
/**
|
|
* Acquire a shared read lock by name.
|
|
* Multiple readers run in parallel, but readers are blocked by queued/active writers.
|
|
* @param {string} name
|
|
* @param {() => any|Promise<any>} cb
|
|
* @returns {Promise<any>}
|
|
*/
|
|
function rwlock_read(name, cb) {
|
|
return ReadWriteLock.acquire_read(name, cb);
|
|
}
|
|
|
|
/**
|
|
* Forcefully clear all locks and queues for a given name.
|
|
* @param {string} name
|
|
*/
|
|
function rwlock_force_unlock(name) {
|
|
ReadWriteLock.force_unlock(name);
|
|
}
|
|
|
|
/**
|
|
* Inspect lock state for debugging.
|
|
* @param {string} name
|
|
* @returns {{readers:number, writer_active:boolean, reader_q:number, writer_q:number}}
|
|
*/
|
|
function rwlock_pending(name) {
|
|
return ReadWriteLock.pending(name);
|
|
}
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJzbGVlcCIsIm1pbGxpc2Vjb25kcyIsImFyZ3VtZW50cyIsImxlbmd0aCIsInVuZGVmaW5lZCIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwic2V0VGltZW91dCIsImRlYm91bmNlIiwiY2FsbGJhY2tfb3JfZGVsYXkiLCJkZWxheSIsImltbWVkaWF0ZSIsImRlY29yYXRvcl9kZWxheSIsImRlY29yYXRvcl9pbW1lZGlhdGUiLCJ2YWx1ZSIsImNvbnRleHQiLCJraW5kIiwiZGVib3VuY2VfaW1wbCIsImNhbGxiYWNrIiwicnVubmluZyIsInF1ZXVlZCIsImxhc3RfZW5kX3RpbWUiLCJ0aW1lciIsIm5leHRfYXJncyIsIm5leHRfY29udGV4dCIsInJlc29sdmVfcXVldWUiLCJyZWplY3RfcXVldWUiLCJydW5fZnVuY3Rpb24iLCJ0aGVzZV9yZXNvbHZlcyIsInRoZXNlX3JlamVjdHMiLCJhcmdzIiwicmVzdWx0IiwiYXBwbHkiLCJlcnIiLCJyZWplY3QiLCJEYXRlIiwibm93IiwiY2xlYXJUaW1lb3V0IiwiTWF0aCIsIm1heCIsIl9sZW4iLCJBcnJheSIsIl9rZXkiLCJwdXNoIiwiZmlyc3RfY2FsbCIsInNpbmNlIiwiSW5maW5pdHkiLCJ3YWl0Iiwicndsb2NrIiwibmFtZSIsImNiIiwiUmVhZFdyaXRlTG9jayIsImFjcXVpcmUiLCJyd2xvY2tfcmVhZCIsImFjcXVpcmVfcmVhZCIsInJ3bG9ja19mb3JjZV91bmxvY2siLCJmb3JjZV91bmxvY2siLCJyd2xvY2tfcGVuZGluZyIsInBlbmRpbmciXSwic291cmNlcyI6WyJhcHAvUlNwYWRlL0NvcmUvSnMvYXN5bmMuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIEFzeW5jIHV0aWxpdHkgZnVuY3Rpb25zIGZvciB0aGUgUlNwYWRlIGZyYW1ld29yay5cbiAqIFRoZXNlIGZ1bmN0aW9ucyBoYW5kbGUgYXN5bmNocm9ub3VzIG9wZXJhdGlvbnMsIGRlbGF5cywgZGVib3VuY2luZywgYW5kIG11dGV4ZXMuXG4gKi9cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQVNZTkMgVVRJTElUSUVTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogUGF1c2VzIGV4ZWN1dGlvbiBmb3Igc3BlY2lmaWVkIG1pbGxpc2Vjb25kc1xuICogQHBhcmFtIHtudW1iZXJ9IFttaWxsaXNlY29uZHM9MF0gLSBEZWxheSBpbiBtaWxsaXNlY29uZHMgKDAgdXNlcyByZXF1ZXN0QW5pbWF0aW9uRnJhbWUpXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIGRlbGF5XG4gKiBAZXhhbXBsZSBhd2FpdCBzbGVlcCgxMDAwKTsgLy8gV2FpdCAxIHNlY29uZFxuICovXG5mdW5jdGlvbiBzbGVlcChtaWxsaXNlY29uZHMgPSAwKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgIGlmIChtaWxsaXNlY29uZHMgPT0gMCAmJiByZXF1ZXN0QW5pbWF0aW9uRnJhbWUpIHtcbiAgICAgICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShyZXNvbHZlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgbWlsbGlzZWNvbmRzKTtcbiAgICAgICAgfVxuICAgIH0pO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBkZWJvdW5jZWQgZnVuY3Rpb24gd2l0aCBleGNsdXNpdml0eSBhbmQgcHJvbWlzZSBmYW4taW5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uLCB3aGVuIGludm9rZWQsIGltbWVkaWF0ZWx5IHJ1bnMgdGhlIGNhbGxiYWNrIGV4Y2x1c2l2ZWx5LlxuICogRm9yIHN1YnNlcXVlbnQgaW52b2NhdGlvbnMsIGl0IGFwcGxpZXMgYSBkZWxheSBiZWZvcmUgcnVubmluZyB0aGUgY2FsbGJhY2sgZXhjbHVzaXZlbHkgYWdhaW4uXG4gKiBUaGUgZGVsYXkgc3RhcnRzIGFmdGVyIHRoZSBjdXJyZW50IGFzeW5jaHJvbm91cyBvcGVyYXRpb24gcmVzb2x2ZXMuXG4gKlxuICogSWYgJ2RlbGF5JyBpcyBzZXQgdG8gMCwgdGhlIGZ1bmN0aW9uIHdpbGwgb25seSBwcmV2ZW50IGVucXVldWVpbmcgbXVsdGlwbGUgZXhlY3V0aW9ucyBvZiB0aGVcbiAqIHNhbWUgbWV0aG9kIG1vcmUgdGhhbiBvbmNlLCBidXQgd2lsbCBzdGlsbCBydW4gdGhlbSBpbW1lZGlhdGVseSBpbiBhbiBleGNsdXNpdmUgc2VxdWVudGlhbCBtYW5uZXIuXG4gKlxuICogVGhlIG1vc3QgcmVjZW50IGludm9jYXRpb24gb2YgdGhlIGZ1bmN0aW9uIHdpbGwgYmUgdGhlIHBhcmFtZXRlcnMgdGhhdCBnZXQgcGFzc2VkIHRvIHRoZSBmdW5jdGlvblxuICogd2hlbiBpdCBpbnZva2VzLlxuICpcbiAqIFRoZSBmdW5jdGlvbiByZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIG5leHQgZXhjbHVzaXZlIGV4ZWN1dGlvbiBjb21wbGV0ZXMuXG4gKlxuICogVXNhZ2UgYXMgZnVuY3Rpb246XG4gKiAgIGNvbnN0IGRlYm91bmNlZEZuID0gZGVib3VuY2UobXlGdW5jdGlvbiwgMjUwKTtcbiAqXG4gKiBVc2FnZSBhcyBkZWNvcmF0b3I6XG4gKiAgIEBkZWJvdW5jZSgyNTApXG4gKiAgIG15TWV0aG9kKCkgeyAuLi4gfVxuICpcbiAqIEBwYXJhbSB7ZnVuY3Rpb258bnVtYmVyfSBjYWxsYmFja19vcl9kZWxheSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gT1IgZGVsYXkgd2hlbiB1c2VkIGFzIGRlY29yYXRvclxuICogQHBhcmFtIHtudW1iZXJ9IGRlbGF5IFRoZSBkZWxheSBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHN1YnNlcXVlbnQgaW52b2NhdGlvbnNcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaW1tZWRpYXRlIGlmIHRydWUsIHRoZSBmaXJzdCB0aW1lIHRoZSBhY3Rpb24gaXMgY2FsbGVkLCB0aGUgY2FsbGJhY2sgZXhlY3V0ZXMgaW1tZWRpYXRlbHlcbiAqIEByZXR1cm5zIHtmdW5jdGlvbn0gQSBmdW5jdGlvbiB0aGF0IHdoZW4gaW52b2tlZCwgcnVucyB0aGUgY2FsbGJhY2sgaW1tZWRpYXRlbHkgYW5kIGV4Y2x1c2l2ZWx5LFxuICpcbiAqIEBkZWNvcmF0b3JcbiAqL1xuZnVuY3Rpb24gZGVib3VuY2UoY2FsbGJhY2tfb3JfZGVsYXksIGRlbGF5LCBpbW1lZGlhdGUgPSBmYWxzZSkge1xuICAgIC8vIERlY29yYXRvciB1c2FnZTogQGRlYm91bmNlKDI1MCkgb3IgQGRlYm91bmNlKDI1MCwgdHJ1ZSlcbiAgICAvLyBGaXJzdCBhcmd1bWVudCBpcyBhIG51bWJlciAodGhlIGRlbGF5KSwgcmV0dXJucyBkZWNvcmF0b3IgZnVuY3Rpb25cbiAgICBpZiAodHlwZW9mIGNhbGxiYWNrX29yX2RlbGF5ID09PSAnbnVtYmVyJykge1xuICAgICAgICBjb25zdCBkZWNvcmF0b3JfZGVsYXkgPSBjYWxsYmFja19vcl9kZWxheTtcbiAgICAgICAgY29uc3QgZGVjb3JhdG9yX2ltbWVkaWF0ZSA9IGRlbGF5IHx8IGZhbHNlO1xuXG4gICAgICAgIC8vIFRDMzkgZGVjb3JhdG9yIGZvcm06IHJlY2VpdmVzICh2YWx1ZSwgY29udGV4dClcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICh2YWx1ZSwgY29udGV4dCkge1xuICAgICAgICAgICAgaWYgKGNvbnRleHQua2luZCA9PT0gJ21ldGhvZCcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGVib3VuY2VfaW1wbCh2YWx1ZSwgZGVjb3JhdG9yX2RlbGF5LCBkZWNvcmF0b3JfaW1tZWRpYXRlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBGdW5jdGlvbiB1c2FnZTogZGVib3VuY2UoZm4sIDI1MClcbiAgICAvLyBGaXJzdCBhcmd1bWVudCBpcyBhIGZ1bmN0aW9uICh0aGUgY2FsbGJhY2spXG4gICAgY29uc3QgY2FsbGJhY2sgPSBjYWxsYmFja19vcl9kZWxheTtcbiAgICByZXR1cm4gZGVib3VuY2VfaW1wbChjYWxsYmFjaywgZGVsYXksIGltbWVkaWF0ZSk7XG59XG5cbi8qKlxuICogSW50ZXJuYWwgaW1wbGVtZW50YXRpb24gb2YgZGVib3VuY2UgbG9naWNcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGRlYm91bmNlX2ltcGwoY2FsbGJhY2ssIGRlbGF5LCBpbW1lZGlhdGUgPSBmYWxzZSkge1xuICAgIGxldCBydW5uaW5nID0gZmFsc2U7XG4gICAgbGV0IHF1ZXVlZCA9IGZhbHNlO1xuICAgIGxldCBsYXN0X2VuZF90aW1lID0gMDsgLy8gdGltZXN0YW1wIG9mIGxhc3QgY29tcGxldGVkIHJ1blxuICAgIGxldCB0aW1lciA9IG51bGw7XG5cbiAgICBsZXQgbmV4dF9hcmdzID0gW107XG4gICAgbGV0IG5leHRfY29udGV4dCA9IG51bGw7XG4gICAgbGV0IHJlc29sdmVfcXVldWUgPSBbXTtcbiAgICBsZXQgcmVqZWN0X3F1ZXVlID0gW107XG5cbiAgICBjb25zdCBydW5fZnVuY3Rpb24gPSBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHRoZXNlX3Jlc29sdmVzID0gcmVzb2x2ZV9xdWV1ZTtcbiAgICAgICAgY29uc3QgdGhlc2VfcmVqZWN0cyA9IHJlamVjdF9xdWV1ZTtcbiAgICAgICAgY29uc3QgYXJncyA9IG5leHRfYXJncztcbiAgICAgICAgY29uc3QgY29udGV4dCA9IG5leHRfY29udGV4dDtcblxuICAgICAgICByZXNvbHZlX3F1ZXVlID0gW107XG4gICAgICAgIHJlamVjdF9xdWV1ZSA9IFtdO1xuICAgICAgICBuZXh0X2FyZ3MgPSBbXTtcbiAgICAgICAgbmV4dF9jb250ZXh0ID0gbnVsbDtcbiAgICAgICAgcXVldWVkID0gZmFsc2U7XG4gICAgICAgIHJ1bm5pbmcgPSB0cnVlO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBjYWxsYmFjay5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcmVzb2x2ZSBvZiB0aGVzZV9yZXNvbHZlcykgcmVzb2x2ZShyZXN1bHQpO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcmVqZWN0IG9mIHRoZXNlX3JlamVjdHMpIHJlamVjdChlcnIpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgcnVubmluZyA9IGZhbHNlO1xuICAgICAgICAgICAgbGFzdF9lbmRfdGltZSA9IERhdGUubm93KCk7XG4gICAgICAgICAgICBpZiAocXVldWVkKSB7XG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQocnVuX2Z1bmN0aW9uLCBNYXRoLm1heChkZWxheSwgMCkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aW1lciA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uICguLi5hcmdzKSB7XG4gICAgICAgIG5leHRfYXJncyA9IGFyZ3M7XG4gICAgICAgIG5leHRfY29udGV4dCA9IHRoaXM7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHJlc29sdmVfcXVldWUucHVzaChyZXNvbHZlKTtcbiAgICAgICAgICAgIHJlamVjdF9xdWV1ZS5wdXNoKHJlamVjdCk7XG5cbiAgICAgICAgICAgIC8vIE5vdGhpbmcgcnVubmluZyBhbmQgbm90aGluZyBzY2hlZHVsZWRcbiAgICAgICAgICAgIGlmICghcnVubmluZyAmJiAhdGltZXIpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBmaXJzdF9jYWxsID0gbGFzdF9lbmRfdGltZSA9PT0gMDtcblxuICAgICAgICAgICAgICAgIGlmIChpbW1lZGlhdGUgJiYgZmlyc3RfY2FsbCkge1xuICAgICAgICAgICAgICAgICAgICBydW5fZnVuY3Rpb24oKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbnN0IHNpbmNlID0gZmlyc3RfY2FsbCA/IEluZmluaXR5IDogRGF0ZS5ub3coKSAtIGxhc3RfZW5kX3RpbWU7XG4gICAgICAgICAgICAgICAgaWYgKHNpbmNlID49IGRlbGF5KSB7XG4gICAgICAgICAgICAgICAgICAgIHJ1bl9mdW5jdGlvbigpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHdhaXQgPSBNYXRoLm1heChkZWxheSAtIHNpbmNlLCAwKTtcbiAgICAgICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVyKTtcbiAgICAgICAgICAgICAgICAgICAgdGltZXIgPSBzZXRUaW1lb3V0KHJ1bl9mdW5jdGlvbiwgd2FpdCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSWYgd2UncmUgYWxyZWFkeSBydW5uaW5nIG9yIGEgdGltZXIgZXhpc3RzLCBqdXN0IG1hcmsgcXVldWVkLlxuICAgICAgICAgICAgLy8gVGhlIGZpbmFsbHl7fSBvZiBydW5fZnVuY3Rpb24gaGFuZGxlcyBzY2hlZHVsaW5nIGFmdGVyIGZ1bGwgZGVsYXkuXG4gICAgICAgICAgICBxdWV1ZWQgPSB0cnVlO1xuICAgICAgICB9KTtcbiAgICB9O1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBSRUFELVdSSVRFIExPQ0sgRlVOQ1RJT05TIC0gRGVsZWdhdGVkIHRvIFJlYWRXcml0ZUxvY2sgY2xhc3Ncbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBBY3F1aXJlIGFuIGV4Y2x1c2l2ZSB3cml0ZSBsb2NrIGJ5IG5hbWUuXG4gKiBPbmx5IG9uZSB3cml0ZXIgcnVucyBhdCBhIHRpbWU7IGJsb2NrcyByZWFkZXJzIHVudGlsIGZpbmlzaGVkLlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAqIEBwYXJhbSB7KCkgPT4gYW55fFByb21pc2U8YW55Pn0gY2JcbiAqIEByZXR1cm5zIHtQcm9taXNlPGFueT59XG4gKi9cbmZ1bmN0aW9uIHJ3bG9jayhuYW1lLCBjYikge1xuICAgIHJldHVybiBSZWFkV3JpdGVMb2NrLmFjcXVpcmUobmFtZSwgY2IpO1xufVxuXG4vKipcbiAqIEFjcXVpcmUgYSBzaGFyZWQgcmVhZCBsb2NrIGJ5IG5hbWUuXG4gKiBNdWx0aXBsZSByZWFkZXJzIHJ1biBpbiBwYXJhbGxlbCwgYnV0IHJlYWRlcnMgYXJlIGJsb2NrZWQgYnkgcXVldWVkL2FjdGl2ZSB3cml0ZXJzLlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAqIEBwYXJhbSB7KCkgPT4gYW55fFByb21pc2U8YW55Pn0gY2JcbiAqIEByZXR1cm5zIHtQcm9taXNlPGFueT59XG4gKi9cbmZ1bmN0aW9uIHJ3bG9ja19yZWFkKG5hbWUsIGNiKSB7XG4gICAgcmV0dXJuIFJlYWRXcml0ZUxvY2suYWNxdWlyZV9yZWFkKG5hbWUsIGNiKTtcbn1cblxuLyoqXG4gKiBGb3JjZWZ1bGx5IGNsZWFyIGFsbCBsb2NrcyBhbmQgcXVldWVzIGZvciBhIGdpdmVuIG5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZVxuICovXG5mdW5jdGlvbiByd2xvY2tfZm9yY2VfdW5sb2NrKG5hbWUpIHtcbiAgICBSZWFkV3JpdGVMb2NrLmZvcmNlX3VubG9jayhuYW1lKTtcbn1cblxuLyoqXG4gKiBJbnNwZWN0IGxvY2sgc3RhdGUgZm9yIGRlYnVnZ2luZy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gKiBAcmV0dXJucyB7e3JlYWRlcnM6bnVtYmVyLCB3cml0ZXJfYWN0aXZlOmJvb2xlYW4sIHJlYWRlcl9xOm51bWJlciwgd3JpdGVyX3E6bnVtYmVyfX1cbiAqL1xuZnVuY3Rpb24gcndsb2NrX3BlbmRpbmcobmFtZSkge1xuICAgIHJldHVybiBSZWFkV3JpdGVMb2NrLnBlbmRpbmcobmFtZSk7XG59XG4iXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVNBLEtBQUtBLENBQUEsRUFBbUI7RUFBQSxJQUFsQkMsWUFBWSxHQUFBQyxTQUFBLENBQUFDLE1BQUEsUUFBQUQsU0FBQSxRQUFBRSxTQUFBLEdBQUFGLFNBQUEsTUFBRyxDQUFDO0VBQzNCLE9BQU8sSUFBSUcsT0FBTyxDQUFFQyxPQUFPLElBQUs7SUFDNUIsSUFBSUwsWUFBWSxJQUFJLENBQUMsSUFBSU0scUJBQXFCLEVBQUU7TUFDNUNBLHFCQUFxQixDQUFDRCxPQUFPLENBQUM7SUFDbEMsQ0FBQyxNQUFNO01BQ0hFLFVBQVUsQ0FBQ0YsT0FBTyxFQUFFTCxZQUFZLENBQUM7SUFDckM7RUFDSixDQUFDLENBQUM7QUFDTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBU1EsUUFBUUEsQ0FBQ0MsaUJBQWlCLEVBQUVDLEtBQUssRUFBcUI7RUFBQSxJQUFuQkMsU0FBUyxH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
|