Files
rspade_system/storage-working/rsx-tmp/babel_b9c658aa7f2a17c11b96ec6cb5be5dd2.js
root 77b4d10af8 Refactor filename naming system and apply convention-based renames
Standardize settings file naming and relocate documentation files
Fix code quality violations from rsx:check
Reorganize user_management directory into logical subdirectories
Move Quill Bundle to core and align with Tom Select pattern
Simplify Site Settings page to focus on core site information
Complete Phase 5: Multi-tenant authentication with login flow and site selection
Add route query parameter rule and synchronize filename validation logic
Fix critical bug in UpdateNpmCommand causing missing JavaScript stubs
Implement filename convention rule and resolve VS Code auto-rename conflict
Implement js-sanitizer RPC server to eliminate 900+ Node.js process spawns
Implement RPC server architecture for JavaScript parsing
WIP: Add RPC server infrastructure for JS parsing (partial implementation)
Update jqhtml terminology from destroy to stop, fix datagrid DOM preservation
Add JQHTML-CLASS-01 rule and fix redundant class names
Improve code quality rules and resolve violations
Remove legacy fatal error format in favor of unified 'fatal' error type
Filter internal keys from window.rsxapp output
Update button styling and comprehensive form/modal documentation
Add conditional fly-in animation for modals
Fix non-deterministic bundle compilation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 19:10:02 +00:00

461 lines
41 KiB
JavaScript
Executable File

"use strict";
/*
* Core utility functions for the RSpade framework.
* These functions handle type checking, type conversion, string manipulation,
* and object/array utilities. They mirror functionality from PHP functions.
*
* Other utility functions are organized in:
* - async.js: Async utilities (sleep, debounce, mutex)
* - browser.js: Browser/DOM utilities (is_mobile, scroll functions)
* - datetime.js: Date/time utilities
* - hash.js: Hashing and comparison
* - error.js: Error handling
*/
// Todo: test that prod build identifies and removes uncalled functions from the final bundle.
// ============================================================================
// CONSTANTS AND HELPERS
// ============================================================================
// Define commonly used constants
const undef = 'undefined';
/**
* Iterates over arrays or objects with promise support
*
* Works with both synchronous and asynchronous callbacks. If the callback
* returns promises, they are executed in parallel and this function returns
* a promise that resolves when all parallel tasks complete.
*
* @param {Array|Object} obj - Collection to iterate
* @param {Function} callback - Function to call for each item (value, key) - can be async
* @returns {Promise|undefined} Promise if any callbacks return promises, undefined otherwise
*
* @example
* // Synchronous usage
* foreach([1,2,3], (val) => console.log(val));
*
* @example
* // Asynchronous usage - waits for all to complete
* await foreach([1,2,3], async (val) => {
* await fetch('/api/process/' + val);
* });
*/
function foreach(obj, callback) {
const results = [];
if (Array.isArray(obj)) {
obj.forEach((value, index) => {
results.push(callback(value, index));
});
} else if (obj && typeof obj === 'object') {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
results.push(callback(obj[key], key));
}
}
}
// Filter for promises
const promises = results.filter(result => result && typeof result.then === 'function');
// If there are any promises, return Promise.all to wait for all to complete
if (promises.length > 0) {
return Promise.all(promises);
}
// No promises returned, so we're done
return undefined;
}
// ============================================================================
// TYPE CHECKING FUNCTIONS
// ============================================================================
/**
* Checks if a value is numeric
* @param {*} n - Value to check
* @returns {boolean} True if the value is a finite number
*/
function is_numeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
/**
* Checks if a value is a string
* @param {*} s - Value to check
* @returns {boolean} True if the value is a string
*/
function is_string(s) {
return typeof s == 'string';
}
/**
* Checks if a value is an integer
* @param {*} n - Value to check
* @returns {boolean} True if the value is an integer
*/
function is_integer(n) {
return Number.isInteger(n);
}
/**
* Checks if a value is a promise-like object
* @param {*} obj - Value to check
* @returns {boolean} True if the value has a then method
*/
function is_promise(obj) {
return typeof obj == 'object' && typeof obj.then == 'function';
}
/**
* Checks if a value is an array
* @param {*} obj - Value to check
* @returns {boolean} True if the value is an array
*/
function is_array(obj) {
return Array.isArray(obj);
}
/**
* Checks if a value is an object (excludes null)
* @param {*} obj - Value to check
* @returns {boolean} True if the value is an object and not null
*/
function is_object(obj) {
return typeof obj === 'object' && obj !== null;
}
/**
* Checks if a value is a function
* @param {*} function_to_check - Value to check
* @returns {boolean} True if the value is a function
*/
function is_function(function_to_check) {
return function_to_check && {}.toString.call(function_to_check) === '[object Function]';
}
/**
* Checks if a string is a valid email address
* Uses a practical RFC 5322 compliant regex that matches 99.99% of real-world email addresses
* @param {string} email - Email address to validate
* @returns {boolean} True if the string is a valid email address
*/
function is_email(email) {
if (!is_string(email)) {
return false;
}
const regex = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;
return regex.test(email);
}
/**
* Checks if a value is defined (not undefined)
* @param {*} value - Value to check
* @returns {boolean} True if value is not undefined
*/
function isset(value) {
return typeof value != undef;
}
/**
* Checks if a value is empty (null, undefined, 0, "", empty array/object)
* @param {*} object - Value to check
* @returns {boolean} True if the value is considered empty
*/
function empty(object) {
if (typeof object == undef) {
return true;
}
if (object === null) {
return true;
}
if (typeof object == 'string' && object == '') {
return true;
}
if (typeof object == 'number') {
return object == 0;
}
if (Array.isArray(object)) {
return !object.length;
}
if (typeof object == 'function') {
return false;
}
for (let key in object) {
if (object.hasOwnProperty(key)) {
return false;
}
}
return true;
}
// ============================================================================
// TYPE CONVERSION FUNCTIONS
// ============================================================================
/**
* Converts a value to a floating point number
* Returns 0 for null, undefined, NaN, or non-numeric values
* @param {*} val - Value to convert
* @returns {number} Floating point number
*/
function float(val) {
// Handle null, undefined, empty string
if (val === null || val === undefined || val === '') {
return 0.0;
}
// Try to parse the value
const parsed = parseFloat(val);
// Check for NaN and return 0 if parsing failed
return isNaN(parsed) ? 0.0 : parsed;
}
/**
* Converts a value to an integer
* Returns 0 for null, undefined, NaN, or non-numeric values
* @param {*} val - Value to convert
* @returns {number} Integer value
*/
function int(val) {
// Handle null, undefined, empty string
if (val === null || val === undefined || val === '') {
return 0;
}
// Try to parse the value
const parsed = parseInt(val, 10);
// Check for NaN and return 0 if parsing failed
return isNaN(parsed) ? 0 : parsed;
}
/**
* Converts a value to a string
* Returns empty string for null or undefined
* @param {*} val - Value to convert
* @returns {string} String representation
*/
function str(val) {
// Handle null and undefined specially
if (val === null || val === undefined) {
return '';
}
// Convert to string
return String(val);
}
/**
* Converts numeric strings to numbers, returns all other values unchanged
* Used when you need to ensure numeric types but don't want to force
* conversion of non-numeric values (which would become 0)
* @param {*} val - Value to convert
* @returns {*} Number if input was numeric string, otherwise unchanged
*/
function value_unless_numeric_string_then_numeric_value(val) {
// If it's already a number, return it
if (typeof val === 'number') {
return val;
}
// If it's a string and numeric, convert it
if (is_string(val) && is_numeric(val)) {
// Use parseFloat to handle both integers and floats
return parseFloat(val);
}
// Return everything else unchanged (null, objects, non-numeric strings, etc.)
return val;
}
// ============================================================================
// STRING MANIPULATION FUNCTIONS
// ============================================================================
/**
* Escapes HTML special characters (uses Lodash escape)
* @param {string} str - String to escape
* @returns {string} HTML-escaped string
*/
function html(str) {
return _.escape(str);
}
/**
* Converts newlines to HTML line breaks
* @param {string} str - String to convert
* @returns {string} String with newlines replaced by <br />
*/
function nl2br(str) {
if (typeof str === undef || str === null) {
return '';
}
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1<br />$2');
}
/**
* Escapes HTML and converts newlines to <br />
* @param {string} str - String to process
* @returns {string} HTML-escaped string with line breaks
*/
function htmlbr(str) {
return nl2br(html(str));
}
/**
* URL-encodes a string
* @param {string} str - String to encode
* @returns {string} URL-encoded string
*/
function urlencode(str) {
return encodeURIComponent(str);
}
/**
* URL-decodes a string
* @param {string} str - String to decode
* @returns {string} URL-decoded string
*/
function urldecode(str) {
return decodeURIComponent(str);
}
/**
* JSON-encodes a value
* @param {*} value - Value to encode
* @returns {string} JSON string
*/
function json_encode(value) {
return JSON.stringify(value);
}
/**
* JSON-decodes a string
* @param {string} str - JSON string to decode
* @returns {*} Decoded value
*/
function json_decode(str) {
return JSON.parse(str);
}
/**
* Console debug output with channel filtering
* Alias for Debugger.console_debug
* @param {string} channel - Debug channel name
* @param {...*} values - Values to log
*/
function console_debug(channel) {
for (var _len = arguments.length, values = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
values[_key - 1] = arguments[_key];
}
Debugger.console_debug(channel, ...values);
}
/**
* Replaces all occurrences of a substring in a string
* @param {string} string - String to search in
* @param {string} search - Substring to find
* @param {string} replace - Replacement substring
* @returns {string} String with all occurrences replaced
*/
function replace_all(string, search, replace) {
if (!is_string(string)) {
string = string + '';
}
return string.split(search).join(replace);
}
/**
* Capitalizes the first letter of each word
* @param {string} input - String to capitalize
* @returns {string} String with first letter of each word capitalized
*/
function ucwords(input) {
return input.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
}
// ============================================================================
// OBJECT AND ARRAY UTILITIES
// ============================================================================
/**
* Counts the number of properties in an object or elements in an array
* @param {Object|Array} o - Object or array to count
* @returns {number} Number of own properties/elements
*/
function count(o) {
let c = 0;
for (const k in o) {
if (o.hasOwnProperty(k)) {
++c;
}
}
return c;
}
/**
* Creates a shallow clone of an object, array, or function
* @param {*} obj - Value to clone
* @returns {*} Cloned value
*/
function clone(obj) {
if (typeof Function.prototype.__clone == undef) {
Function.prototype.__clone = function () {
//https://stackoverflow.com/questions/1833588/javascript-clone-a-function
const that = this;
let temp = function cloned() {
return that.apply(this, arguments);
};
for (let key in this) {
if (this.hasOwnProperty(key)) {
temp[key] = this[key];
}
}
return temp;
};
}
if (typeof obj == 'function') {
return obj.__clone();
} else if (obj.constructor && obj.constructor == Array) {
return obj.slice(0);
} else {
// https://stackoverflow.com/questions/728360/how-do-i-correctly-clone-a-javascript-object/30042948#30042948
return Object.assign({}, obj);
}
}
/**
* Returns the first non-null/undefined value from arguments
* @param {...*} arguments - Values to check
* @returns {*} First non-null/undefined value, or null if none found
*/
function coalesce() {
let args = Array.from(arguments);
let return_val = null;
args.forEach(function (arg) {
if (return_val === null && typeof arg != undef && arg !== null) {
return_val = arg;
}
});
return return_val;
}
/**
* Converts CSV string to array, trimming each element
* @param {string} str_csv - CSV string to convert
* @returns {Array<string>} Array of trimmed values
* @todo Handle quoted/escaped characters
*/
function csv_to_array_trim(str_csv) {
const parts = str_csv.split(',');
const ret = [];
foreach(parts, part => {
ret.push(part.trim());
});
return ret;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJ1bmRlZiIsImZvcmVhY2giLCJvYmoiLCJjYWxsYmFjayIsInJlc3VsdHMiLCJBcnJheSIsImlzQXJyYXkiLCJmb3JFYWNoIiwidmFsdWUiLCJpbmRleCIsInB1c2giLCJrZXkiLCJoYXNPd25Qcm9wZXJ0eSIsInByb21pc2VzIiwiZmlsdGVyIiwicmVzdWx0IiwidGhlbiIsImxlbmd0aCIsIlByb21pc2UiLCJhbGwiLCJ1bmRlZmluZWQiLCJpc19udW1lcmljIiwibiIsImlzTmFOIiwicGFyc2VGbG9hdCIsImlzRmluaXRlIiwiaXNfc3RyaW5nIiwicyIsImlzX2ludGVnZXIiLCJOdW1iZXIiLCJpc0ludGVnZXIiLCJpc19wcm9taXNlIiwiaXNfYXJyYXkiLCJpc19vYmplY3QiLCJpc19mdW5jdGlvbiIsImZ1bmN0aW9uX3RvX2NoZWNrIiwidG9TdHJpbmciLCJjYWxsIiwiaXNfZW1haWwiLCJlbWFpbCIsInJlZ2V4IiwidGVzdCIsImlzc2V0IiwiZW1wdHkiLCJvYmplY3QiLCJmbG9hdCIsInZhbCIsInBhcnNlZCIsImludCIsInBhcnNlSW50Iiwic3RyIiwiU3RyaW5nIiwidmFsdWVfdW5sZXNzX251bWVyaWNfc3RyaW5nX3RoZW5fbnVtZXJpY192YWx1ZSIsImh0bWwiLCJfIiwiZXNjYXBlIiwibmwyYnIiLCJyZXBsYWNlIiwiaHRtbGJyIiwidXJsZW5jb2RlIiwiZW5jb2RlVVJJQ29tcG9uZW50IiwidXJsZGVjb2RlIiwiZGVjb2RlVVJJQ29tcG9uZW50IiwianNvbl9lbmNvZGUiLCJKU09OIiwic3RyaW5naWZ5IiwianNvbl9kZWNvZGUiLCJwYXJzZSIsImNvbnNvbGVfZGVidWciLCJjaGFubmVsIiwiX2xlbiIsImFyZ3VtZW50cyIsInZhbHVlcyIsIl9rZXkiLCJEZWJ1Z2dlciIsInJlcGxhY2VfYWxsIiwic3RyaW5nIiwic2VhcmNoIiwic3BsaXQiLCJqb2luIiwidWN3b3JkcyIsImlucHV0IiwibWFwIiwid29yZCIsImNoYXJBdCIsInRvVXBwZXJDYXNlIiwic2xpY2UiLCJjb3VudCIsIm8iLCJjIiwiayIsImNsb25lIiwiRnVuY3Rpb24iLCJwcm90b3R5cGUiLCJfX2Nsb25lIiwidGhhdCIsInRlbXAiLCJjbG9uZWQiLCJhcHBseSIsImNvbnN0cnVjdG9yIiwiT2JqZWN0IiwiYXNzaWduIiwiY29hbGVzY2UiLCJhcmdzIiwiZnJvbSIsInJldHVybl92YWwiLCJhcmciLCJjc3ZfdG9fYXJyYXlfdHJpbSIsInN0cl9jc3YiLCJwYXJ0cyIsInJldCIsInBhcnQiLCJ0cmltIl0sInNvdXJjZXMiOlsiYXBwL1JTcGFkZS9Db3JlL0pzL2Z1bmN0aW9ucy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29yZSB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgdGhlIFJTcGFkZSBmcmFtZXdvcmsuXG4gKiBUaGVzZSBmdW5jdGlvbnMgaGFuZGxlIHR5cGUgY2hlY2tpbmcsIHR5cGUgY29udmVyc2lvbiwgc3RyaW5nIG1hbmlwdWxhdGlvbixcbiAqIGFuZCBvYmplY3QvYXJyYXkgdXRpbGl0aWVzLiBUaGV5IG1pcnJvciBmdW5jdGlvbmFsaXR5IGZyb20gUEhQIGZ1bmN0aW9ucy5cbiAqXG4gKiBPdGhlciB1dGlsaXR5IGZ1bmN0aW9ucyBhcmUgb3JnYW5pemVkIGluOlxuICogLSBhc3luYy5qczogQXN5bmMgdXRpbGl0aWVzIChzbGVlcCwgZGVib3VuY2UsIG11dGV4KVxuICogLSBicm93c2VyLmpzOiBCcm93c2VyL0RPTSB1dGlsaXRpZXMgKGlzX21vYmlsZSwgc2Nyb2xsIGZ1bmN0aW9ucylcbiAqIC0gZGF0ZXRpbWUuanM6IERhdGUvdGltZSB1dGlsaXRpZXNcbiAqIC0gaGFzaC5qczogSGFzaGluZyBhbmQgY29tcGFyaXNvblxuICogLSBlcnJvci5qczogRXJyb3IgaGFuZGxpbmdcbiAqL1xuXG4vLyBUb2RvOiB0ZXN0IHRoYXQgcHJvZCBidWlsZCBpZGVudGlmaWVzIGFuZCByZW1vdmVzIHVuY2FsbGVkIGZ1bmN0aW9ucyBmcm9tIHRoZSBmaW5hbCBidW5kbGUuXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIENPTlNUQU5UUyBBTkQgSEVMUEVSU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vLyBEZWZpbmUgY29tbW9ubHkgdXNlZCBjb25zdGFudHNcbmNvbnN0IHVuZGVmID0gJ3VuZGVmaW5lZCc7XG5cbi8qKlxuICogSXRlcmF0ZXMgb3ZlciBhcnJheXMgb3Igb2JqZWN0cyB3aXRoIHByb21pc2Ugc3VwcG9ydFxuICpcbiAqIFdvcmtzIHdpdGggYm90aCBzeW5jaHJvbm91cyBhbmQgYXN5bmNocm9ub3VzIGNhbGxiYWNrcy4gSWYgdGhlIGNhbGxiYWNrXG4gKiByZXR1cm5zIHByb21pc2VzLCB0aGV5IGFyZSBleGVjdXRlZCBpbiBwYXJhbGxlbCBhbmQgdGhpcyBmdW5jdGlvbiByZXR1cm5zXG4gKiBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBwYXJhbGxlbCB0YXNrcyBjb21wbGV0ZS5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gb2JqIC0gQ29sbGVjdGlvbiB0byBpdGVyYXRlXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayAtIEZ1bmN0aW9uIHRvIGNhbGwgZm9yIGVhY2ggaXRlbSAodmFsdWUsIGtleSkgLSBjYW4gYmUgYXN5bmNcbiAqIEByZXR1cm5zIHtQcm9taXNlfHVuZGVmaW5lZH0gUHJvbWlzZSBpZiBhbnkgY2FsbGJhY2tzIHJldHVybiBwcm9taXNlcywgdW5kZWZpbmVkIG90aGVyd2lzZVxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBTeW5jaHJvbm91cyB1c2FnZVxuICogZm9yZWFjaChbMSwyLDNdLCAodmFsKSA9PiBjb25zb2xlLmxvZyh2YWwpKTtcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gQXN5bmNocm9ub3VzIHVzYWdlIC0gd2FpdHMgZm9yIGFsbCB0byBjb21wbGV0ZVxuICogYXdhaXQgZm9yZWFjaChbMSwyLDNdLCBhc3luYyAodmFsKSA9PiB7XG4gKiAgICAgYXdhaXQgZmV0Y2goJy9hcGkvcHJvY2Vzcy8nICsgdmFsKTtcbiAqIH0pO1xuICovXG5mdW5jdGlvbiBmb3JlYWNoKG9iaiwgY2FsbGJhY2spIHtcbiAgICBjb25zdCByZXN1bHRzID0gW107XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgICAgIG9iai5mb3JFYWNoKCh2YWx1ZSwgaW5kZXgpID0+IHtcbiAgICAgICAgICAgIHJlc3VsdHMucHVzaChjYWxsYmFjayh2YWx1ZSwgaW5kZXgpKTtcbiAgICAgICAgfSk7XG4gICAgfSBlbHNlIGlmIChvYmogJiYgdHlwZW9mIG9iaiA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgZm9yIChsZXQga2V5IGluIG9iaikge1xuICAgICAgICAgICAgaWYgKG9iai5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0cy5wdXNoKGNhbGxiYWNrKG9ialtrZXldLCBrZXkpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZpbHRlciBmb3IgcHJvbWlzZXNcbiAgICBjb25zdCBwcm9taXNlcyA9IHJlc3VsdHMuZmlsdGVyKChyZXN1bHQpID0+IHJlc3VsdCAmJiB0eXBlb2YgcmVzdWx0LnRoZW4gPT09ICdmdW5jdGlvbicpO1xuXG4gICAgLy8gSWYgdGhlcmUgYXJlIGFueSBwcm9taXNlcywgcmV0dXJuIFByb21pc2UuYWxsIHRvIHdhaXQgZm9yIGFsbCB0byBjb21wbGV0ZVxuICAgIGlmIChwcm9taXNlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHJldHVybiBQcm9taXNlLmFsbChwcm9taXNlcyk7XG4gICAgfVxuXG4gICAgLy8gTm8gcHJvbWlzZXMgcmV0dXJuZWQsIHNvIHdlJ3JlIGRvbmVcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFRZUEUgQ0hFQ0tJTkcgRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgbnVtZXJpY1xuICogQHBhcmFtIHsqfSBuIC0gVmFsdWUgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB2YWx1ZSBpcyBhIGZpbml0ZSBudW1iZXJcbiAqL1xuZnVuY3Rpb24gaXNfbnVtZXJpYyhuKSB7XG4gICAgcmV0dXJuICFpc05hTihwYXJzZUZsb2F0KG4pKSAmJiBpc0Zpbml0ZShuKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSB2YWx1ZSBpcyBhIHN0cmluZ1xuICogQHBhcmFtIHsqfSBzIC0gVmFsdWUgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB2YWx1ZSBpcyBhIHN0cmluZ1xuICovXG5mdW5jdGlvbiBpc19zdHJpbmcocykge1xuICAgIHJldHVybiB0eXBlb2YgcyA9PSAnc3RyaW5nJztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSB2YWx1ZSBpcyBhbiBpbnRlZ2VyXG4gKiBAcGFyYW0geyp9IG4gLSBWYWx1ZSB0byBjaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIHZhbHVlIGlzIGFuIGludGVnZXJcbiAqL1xuZnVuY3Rpb24gaXNfaW50ZWdlcihuKSB7XG4gICAgcmV0dXJuIE51bWJlci5pc0ludGVnZXIobik7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYSBwcm9taXNlLWxpa2Ugb2JqZWN0XG4gKiBAcGFyYW0geyp9IG9iaiAtIFZhbHVlIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgdmFsdWUgaGFzIGEgdGhlbiBtZXRob2RcbiAqL1xuZnVuY3Rpb24gaXNfcHJvbWlzZShvYmopIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iaiA9PSAnb2JqZWN0JyAmJiB0eXBlb2Ygb2JqLnRoZW4gPT0gJ2Z1bmN0aW9uJztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSB2YWx1ZSBpcyBhbiBhcnJheVxuICogQHBhcmFtIHsqfSBvYmogLSBWYWx1ZSB0byBjaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIHZhbHVlIGlzIGFuIGFycmF5XG4gKi9cbmZ1bmN0aW9uIGlzX2FycmF5KG9iaikge1xuICAgIHJldHVybiBBcnJheS5pc0FycmF5KG9iaik7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYW4gb2JqZWN0IChleGNsdWRlcyBudWxsKVxuICogQHBhcmFtIHsqfSBvYmogLSBWYWx1ZSB0byBjaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIHZhbHVlIGlzIGFuIG9iamVjdCBhbmQgbm90IG51bGxcbiAqL1xuZnVuY3Rpb24gaXNfb2JqZWN0KG9iaikge1xuICAgIHJldHVybiB0eXBlb2Ygb2JqID09PSAnb2JqZWN0JyAmJiBvYmogIT09IG51bGw7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYSBmdW5jdGlvblxuICogQHBhcmFtIHsqfSBmdW5jdGlvbl90b19jaGVjayAtIFZhbHVlIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgdmFsdWUgaXMgYSBmdW5jdGlvblxuICovXG5mdW5jdGlvbiBpc19mdW5jdGlvbihmdW5jdGlvbl90b19jaGVjaykge1xuICAgIHJldHVybiBmdW5jdGlvbl90b19jaGVjayAmJiB7fS50b1N0cmluZy5jYWxsKGZ1bmN0aW9uX3RvX2NoZWNrKSA9PT0gJ1tvYmplY3QgRnVuY3Rpb25dJztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSBzdHJpbmcgaXMgYSB2YWxpZCBlbWFpbCBhZGRyZXNzXG4gKiBVc2VzIGEgcHJhY3RpY2FsIFJGQyA1MzIyIGNvbXBsaWFudCByZWdleCB0aGF0IG1hdGNoZXMgOTkuOTklIG9mIHJlYWwtd29ybGQgZW1haWwgYWRkcmVzc2VzXG4gKiBAcGFyYW0ge3N0cmluZ30gZW1haWwgLSBFbWFpbCBhZGRyZXNzIHRvIHZhbGlkYXRlXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgc3RyaW5nIGlzIGEgdmFsaWQgZW1haWwgYWRkcmVzc1xuICovXG5mdW5jdGlvbiBpc19lbWFpbChlbWFpbCkge1xuICAgIGlmICghaXNfc3RyaW5nKGVtYWlsKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IHJlZ2V4ID0gL15bYS16MC05ISMkJSYnKisvPT9eX2B7fH1+LV0rKD86XFwuW2EtejAtOSEjJCUmJyorLz0/Xl9ge3x9fi1dKykqQCg/OlthLXowLTldKD86W2EtejAtOS1dKlthLXowLTldKT9cXC4pK1thLXowLTldKD86W2EtejAtOS1dKlthLXowLTldKT8kL2k7XG4gICAgcmV0dXJuIHJlZ2V4LnRlc3QoZW1haWwpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGRlZmluZWQgKG5vdCB1bmRlZmluZWQpXG4gKiBAcGFyYW0geyp9IHZhbHVlIC0gVmFsdWUgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHZhbHVlIGlzIG5vdCB1bmRlZmluZWRcbiAqL1xuZnVuY3Rpb24gaXNzZXQodmFsdWUpIHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlICE9IHVuZGVmO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGVtcHR5IChudWxsLCB1bmRlZmluZWQsIDAsIFwiXCIsIGVtcHR5IGFycmF5L29iamVjdClcbiAqIEBwYXJhbSB7Kn0gb2JqZWN0IC0gVmFsdWUgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB2YWx1ZSBpcyBjb25zaWRlcmVkIGVtcHR5XG4gKi9cbmZ1bmN0aW9uIGVtcHR5KG9iamVjdCkge1xuICAgIGlmICh0eXBlb2Ygb2JqZWN0ID09IHVuZGVmKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBpZiAob2JqZWN0ID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIG9iamVjdCA9PSAnc3RyaW5nJyAmJiBvYmplY3QgPT0gJycpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmICh0eXBlb2Ygb2JqZWN0ID09ICdudW1iZXInKSB7XG4gICAgICAgIHJldHVybiBvYmplY3QgPT0gMDtcbiAgICB9XG4gICAgaWYgKEFycmF5LmlzQXJyYXkob2JqZWN0KSkge1xuICAgICAgICByZXR1cm4gIW9iamVjdC5sZW5ndGg7XG4gICAgfVxuICAgIGlmICh0eXBlb2Ygb2JqZWN0ID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBmb3IgKGxldCBrZXkgaW4gb2JqZWN0KSB7XG4gICAgICAgIGlmIChvYmplY3QuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUWVBFIENPTlZFUlNJT04gRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGZsb2F0aW5nIHBvaW50IG51bWJlclxuICogUmV0dXJucyAwIGZvciBudWxsLCB1bmRlZmluZWQsIE5hTiwgb3Igbm9uLW51bWVyaWMgdmFsdWVzXG4gKiBAcGFyYW0geyp9IHZhbCAtIFZhbHVlIHRvIGNvbnZlcnRcbiAqIEByZXR1cm5zIHtudW1iZXJ9IEZsb2F0aW5nIHBvaW50IG51bWJlclxuICovXG5mdW5jdGlvbiBmbG9hdCh2YWwpIHtcbiAgICAvLyBIYW5kbGUgbnVsbCwgdW5kZWZpbmVkLCBlbXB0eSBzdHJpbmdcbiAgICBpZiAodmFsID09PSBudWxsIHx8IHZhbCA9PT0gdW5kZWZpbmVkIHx8IHZhbCA9PT0gJycpIHtcbiAgICAgICAgcmV0dXJuIDAuMDtcbiAgICB9XG5cbiAgICAvLyBUcnkgdG8gcGFyc2UgdGhlIHZhbHVlXG4gICAgY29uc3QgcGFyc2VkID0gcGFyc2VGbG9hdCh2YWwpO1xuXG4gICAgLy8gQ2hlY2sgZm9yIE5hTiBhbmQgcmV0dXJuIDAgaWYgcGFyc2luZyBmYWlsZWRcbiAgICByZXR1cm4gaXNOYU4ocGFyc2VkKSA/IDAuMCA6IHBhcnNlZDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGFuIGludGVnZXJcbiAqIFJldHVybnMgMCBmb3IgbnVsbCwgdW5kZWZpbmVkLCBOYU4sIG9yIG5vbi1udW1lcmljIHZhbHVlc1xuICogQHBhcmFtIHsqfSB2YWwgLSBWYWx1ZSB0byBjb252ZXJ0XG4gKiBAcmV0dXJucyB7bnVtYmVyfSBJbnRlZ2VyIHZhbHVlXG4gKi9cbmZ1bmN0aW9uIGludCh2YWwpIHtcbiAgICAvLyBIYW5kbGUgbnVsbCwgdW5kZWZpbmVkLCBlbXB0eSBzdHJpbmdcbiAgICBpZiAodmFsID09PSBudWxsIHx8IHZhbCA9PT0gdW5kZWZpbmVkIHx8IHZhbCA9PT0gJycpIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRoZSB2YWx1ZVxuICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlSW50KHZhbCwgMTApO1xuXG4gICAgLy8gQ2hlY2sgZm9yIE5hTiBhbmQgcmV0dXJuIDAgaWYgcGFyc2luZyBmYWlsZWRcbiAgICByZXR1cm4gaXNOYU4ocGFyc2VkKSA/IDAgOiBwYXJzZWQ7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIHN0cmluZ1xuICogUmV0dXJucyBlbXB0eSBzdHJpbmcgZm9yIG51bGwgb3IgdW5kZWZpbmVkXG4gKiBAcGFyYW0geyp9IHZhbCAtIFZhbHVlIHRvIGNvbnZlcnRcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFN0cmluZyByZXByZXNlbnRhdGlvblxuICovXG5mdW5jdGlvbiBzdHIodmFsKSB7XG4gICAgLy8gSGFuZGxlIG51bGwgYW5kIHVuZGVmaW5lZCBzcGVjaWFsbHlcbiAgICBpZiAodmFsID09PSBudWxsIHx8IHZhbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0IHRvIHN0cmluZ1xuICAgIHJldHVybiBTdHJpbmcodmFsKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBudW1lcmljIHN0cmluZ3MgdG8gbnVtYmVycywgcmV0dXJucyBhbGwgb3RoZXIgdmFsdWVzIHVuY2hhbmdlZFxuICogVXNlZCB3aGVuIHlvdSBuZWVkIHRvIGVuc3VyZSBudW1lcmljIHR5cGVzIGJ1dCBkb24ndCB3YW50IHRvIGZvcmNlXG4gKiBjb252ZXJzaW9uIG9mIG5vbi1udW1lcmljIHZhbHVlcyAod2hpY2ggd291bGQgYmVjb21lIDApXG4gKiBAcGFyYW0geyp9IHZhbCAtIFZhbHVlIHRvIGNvbnZlcnRcbiAqIEByZXR1cm5zIHsqfSBOdW1iZXIgaWYgaW5wdXQgd2FzIG51bWVyaWMgc3RyaW5nLCBvdGhlcndpc2UgdW5jaGFuZ2VkXG4gKi9cbmZ1bmN0aW9uIHZhbHVlX3VubGVzc19udW1lcmljX3N0cmluZ190aGVuX251bWVyaWNfdmFsdWUodmFsKSB7XG4gICAgLy8gSWYgaXQncyBhbHJlYWR5IGEgbnVtYmVyLCByZXR1cm4gaXRcbiAgICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgcmV0dXJuIHZhbDtcbiAgICB9XG5cbiAgICAvLyBJZiBpdCdzIGEgc3RyaW5nIGFuZCBudW1lcmljLCBjb252ZXJ0IGl0XG4gICAgaWYgKGlzX3N0cmluZyh2YWwpICYmIGlzX251bWVyaWModmFsKSkge1xuICAgICAgICAvLyBVc2UgcGFyc2VGbG9hdCB0byBoYW5kbGUgYm90aCBpbnRlZ2VycyBhbmQgZmxvYXRzXG4gICAgICAgIHJldHVybiBwYXJzZUZsb2F0KHZhbCk7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJuIGV2ZXJ5dGhpbmcgZWxzZSB1bmNoYW5nZWQgKG51bGwsIG9iamVjdHMsIG5vbi1udW1lcmljIHN0cmluZ3MsIGV0Yy4pXG4gICAgcmV0dXJuIHZhbDtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gU1RSSU5HIE1BTklQVUxBVElPTiBGVU5DVElPTlNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBFc2NhcGVzIEhUTUwgc3BlY2lhbCBjaGFyYWN0ZXJzICh1c2VzIExvZGFzaCBlc2NhcGUpXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyIC0gU3RyaW5nIHRvIGVzY2FwZVxuICogQHJldHVybnMge3N0cmluZ30gSFRNTC1lc2NhcGVkIHN0cmluZ1xuICovXG5mdW5jdGlvbiBodG1sKHN0cikge1xuICAgIHJldHVybiBfLmVzY2FwZShzdHIpO1xufVxuXG4vKipcbiAqIENvbnZlcnRzIG5ld2xpbmVzIHRvIEhUTUwgbGluZSBicmVha3NcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHIgLSBTdHJpbmcgdG8gY29udmVydFxuICogQHJldHVybnMge3N0cmluZ30gU3RyaW5nIHdpdGggbmV3bGluZXMgcmVwbGFjZWQgYnkgPGJyIC8+XG4gKi9cbmZ1bmN0aW9uIG5sMmJyKHN0cikge1xuICAgIGlmICh0eXBlb2Ygc3RyID09PSB1bmRlZiB8fCBzdHIgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cbiAgICByZXR1cm4gKHN0ciArICcnKS5yZXBsYWNlKC8oW14+XFxyXFxuXT8pKFxcclxcbnxcXG5cXHJ8XFxyfFxcbikvZywgJyQxPGJyIC8+JDInKTtcbn1cblxuLyoqXG4gKiBFc2NhcGVzIEhUTUwgYW5kIGNvbnZlcnRzIG5ld2xpbmVzIHRvIDxiciAvPlxuICogQHBhcmFtIHtzdHJpbmd9IHN0ciAtIFN0cmluZyB0byBwcm9jZXNzXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBIVE1MLWVzY2FwZWQgc3RyaW5nIHdpdGggbGluZSBicmVha3NcbiAqL1xuZnVuY3Rpb24gaHRtbGJyKHN0cikge1xuICAgIHJldHVybiBubDJicihodG1sKHN0cikpO1xufVxuXG4vKipcbiAqIFVSTC1lbmNvZGVzIGEgc3RyaW5nXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyIC0gU3RyaW5nIHRvIGVuY29kZVxuICogQHJldHVybnMge3N0cmluZ30gVVJMLWVuY29kZWQgc3RyaW5nXG4gKi9cbmZ1bmN0aW9uIHVybGVuY29kZShzdHIpIHtcbiAgICByZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KHN0cik7XG59XG5cbi8qKlxuICogVVJMLWRlY29kZXMgYSBzdHJpbmdcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHIgLSBTdHJpbmcgdG8gZGVjb2RlXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBVUkwtZGVjb2RlZCBzdHJpbmdcbiAqL1xuZnVuY3Rpb24gdXJsZGVjb2RlKHN0cikge1xuICAgIHJldHVybiBkZWNvZGVVUklDb21wb25lbnQoc3RyKTtcbn1cblxuLyoqXG4gKiBKU09OLWVuY29kZXMgYSB2YWx1ZVxuICogQHBhcmFtIHsqfSB2YWx1ZSAtIFZhbHVlIHRvIGVuY29kZVxuICogQHJldHVybnMge3N0cmluZ30gSlNPTiBzdHJpbmdcbiAqL1xuZnVuY3Rpb24ganNvbl9lbmNvZGUodmFsdWUpIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xufVxuXG4vKipcbiAqIEpTT04tZGVjb2RlcyBhIHN0cmluZ1xuICogQHBhcmFtIHtzdHJpbmd9IHN0ciAtIEpTT04gc3RyaW5nIHRvIGRlY29kZVxuICogQHJldHVybnMgeyp9IERlY29kZWQgdmFsdWVcbiAqL1xuZnVuY3Rpb24ganNvbl9kZWNvZGUoc3RyKSB7XG4gICAgcmV0dXJuIEpTT04ucGFyc2Uoc3RyKTtcbn1cblxuLyoqXG4gKiBDb25zb2xlIGRlYnVnIG91dHB1dCB3aXRoIGNoYW5uZWwgZmlsdGVyaW5nXG4gKiBBbGlhcyBmb3IgRGVidWdnZXIuY29uc29sZV9kZWJ1Z1xuICogQHBhcmFtIHtzdHJpbmd9IGNoYW5uZWwgLSBEZWJ1ZyBjaGFubmVsIG5hbWVcbiAqIEBwYXJhbSB7Li4uKn0gdmFsdWVzIC0gVmFsdWVzIHRvIGxvZ1xuICovXG5mdW5jdGlvbiBjb25zb2xlX2RlYnVnKGNoYW5uZWwsIC4uLnZhbHVlcykge1xuICAgIERlYnVnZ2VyLmNvbnNvbGVfZGVidWcoY2hhbm5lbCwgLi4udmFsdWVzKTtcbn1cblxuLyoqXG4gKiBSZXBsYWNlcyBhbGwgb2NjdXJyZW5jZXMgb2YgYSBzdWJzdHJpbmcgaW4gYSBzdHJpbmdcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmcgLSBTdHJpbmcgdG8gc2VhcmNoIGluXG4gKiBAcGFyYW0ge3N0cmluZ30gc2VhcmNoIC0gU3Vic3RyaW5nIHRvIGZpbmRcbiAqIEBwYXJhbSB7c3RyaW5nfSByZXBsYWNlIC0gUmVwbGFjZW1lbnQgc3Vic3RyaW5nXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBTdHJpbmcgd2l0aCBhbGwgb2NjdXJyZW5jZXMgcmVwbGFjZWRcbiAqL1xuZnVuY3Rpb24gcmVwbGFjZV9hbGwoc3RyaW5nLCBzZWFyY2gsIHJlcGxhY2UpIHtcbiAgICBpZiAoIWlzX3N0cmluZyhzdHJpbmcpKSB7XG4gICAgICAgIHN0cmluZyA9IHN0cmluZyArICcnO1xuICAgIH1cbiAgICByZXR1cm4gc3RyaW5nLnNwbGl0KHNlYXJjaCkuam9pbihyZXBsYWNlKTtcbn1cblxuLyoqXG4gKiBDYXBpdGFsaXplcyB0aGUgZmlyc3QgbGV0dGVyIG9mIGVhY2ggd29yZFxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gU3RyaW5nIHRvIGNhcGl0YWxpemVcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFN0cmluZyB3aXRoIGZpcnN0IGxldHRlciBvZiBlYWNoIHdvcmQgY2FwaXRhbGl6ZWRcbiAqL1xuZnVuY3Rpb24gdWN3b3JkcyhpbnB1dCkge1xuICAgIHJldHVybiBpbnB1dFxuICAgICAgICAuc3BsaXQoJyAnKVxuICAgICAgICAubWFwKCh3b3JkKSA9PiB3b3JkLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgd29yZC5zbGljZSgxKSlcbiAgICAgICAgLmpvaW4oJyAnKTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gT0JKRUNUIEFORCBBUlJBWSBVVElMSVRJRVNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBDb3VudHMgdGhlIG51bWJlciBvZiBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBvciBlbGVtZW50cyBpbiBhbiBhcnJheVxuICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IG8gLSBPYmplY3Qgb3IgYXJyYXkgdG8gY291bnRcbiAqIEByZXR1cm5zIHtudW1iZXJ9IE51bWJlciBvZiBvd24gcHJvcGVydGllcy9lbGVtZW50c1xuICovXG5mdW5jdGlvbiBjb3VudChvKSB7XG4gICAgbGV0IGMgPSAwO1xuICAgIGZvciAoY29uc3QgayBpbiBvKSB7XG4gICAgICAgIGlmIChvLmhhc093blByb3BlcnR5KGspKSB7XG4gICAgICAgICAgICArK2M7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGM7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHNoYWxsb3cgY2xvbmUgb2YgYW4gb2JqZWN0LCBhcnJheSwgb3IgZnVuY3Rpb25cbiAqIEBwYXJhbSB7Kn0gb2JqIC0gVmFsdWUgdG8gY2xvbmVcbiAqIEByZXR1cm5zIHsqfSBDbG9uZWQgdmFsdWVcbiAqL1xuZnVuY3Rpb24gY2xvbmUob2JqKSB7XG4gICAgaWYgKHR5cGVvZiBGdW5jdGlvbi5wcm90b3R5cGUuX19jbG9uZSA9PSB1bmRlZikge1xuICAgICAgICBGdW5jdGlvbi5wcm90b3R5cGUuX19jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTgzMzU4OC9qYXZhc2NyaXB0LWNsb25lLWEtZnVuY3Rpb25cbiAgICAgICAgICAgIGNvbnN0IHRoYXQgPSB0aGlzO1xuICAgICAgICAgICAgbGV0IHRlbXAgPSBmdW5jdGlvbiBjbG9uZWQoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoYXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBmb3IgKGxldCBrZXkgaW4gdGhpcykge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgdGVtcFtrZXldID0gdGhpc1trZXldO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0ZW1wO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIGlmICh0eXBlb2Ygb2JqID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmV0dXJuIG9iai5fX2Nsb25lKCk7XG4gICAgfSBlbHNlIGlmIChvYmouY29uc3RydWN0b3IgJiYgb2JqLmNvbnN0cnVjdG9yID09IEFycmF5KSB7XG4gICAgICAgIHJldHVybiBvYmouc2xpY2UoMCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNzI4MzYwL2hvdy1kby1pLWNvcnJlY3RseS1jbG9uZS1hLWphdmFzY3JpcHQtb2JqZWN0LzMwMDQyOTQ4IzMwMDQyOTQ4XG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCBvYmopO1xuICAgIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBmaXJzdCBub24tbnVsbC91bmRlZmluZWQgdmFsdWUgZnJvbSBhcmd1bWVudHNcbiAqIEBwYXJhbSB7Li4uKn0gYXJndW1lbnRzIC0gVmFsdWVzIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Kn0gRmlyc3Qgbm9uLW51bGwvdW5kZWZpbmVkIHZhbHVlLCBvciBudWxsIGlmIG5vbmUgZm91bmRcbiAqL1xuZnVuY3Rpb24gY29hbGVzY2UoKSB7XG4gICAgbGV0IGFyZ3MgPSBBcnJheS5mcm9tKGFyZ3VtZW50cyk7XG4gICAgbGV0IHJldHVybl92YWwgPSBudWxsO1xuICAgIGFyZ3MuZm9yRWFjaChmdW5jdGlvbiAoYXJnKSB7XG4gICAgICAgIGlmIChyZXR1cm5fdmFsID09PSBudWxsICYmIHR5cGVvZiBhcmcgIT0gdW5kZWYgJiYgYXJnICE9PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm5fdmFsID0gYXJnO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHJldHVybl92YWw7XG59XG5cbi8qKlxuICogQ29udmVydHMgQ1NWIHN0cmluZyB0byBhcnJheSwgdHJpbW1pbmcgZWFjaCBlbGVtZW50XG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyX2NzdiAtIENTViBzdHJpbmcgdG8gY29udmVydFxuICogQHJldHVybnMge0FycmF5PHN0cmluZz59IEFycmF5IG9mIHRyaW1tZWQgdmFsdWVzXG4gKiBAdG9kbyBIYW5kbGUgcXVvdGVkL2VzY2FwZWQgY2hhcmFjdGVyc1xuICovXG5mdW5jdGlvbiBjc3ZfdG9fYXJyYXlfdHJpbShzdHJfY3N2KSB7XG4gICAgY29uc3QgcGFydHMgPSBzdHJfY3N2LnNwbGl0KCcsJyk7XG4gICAgY29uc3QgcmV0ID0gW107XG4gICAgZm9yZWFjaChwYXJ0cywgKHBhcnQpID0+IHtcbiAgICAgICAgcmV0LnB1c2gocGFydC50cmltKCkpO1xuICAgIH0pO1xuICAgIHJldHVybiByZXQ7XG59XG4iXSwibWFwcGluZ3MiOiI7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE1BQU1BLEtBQUssR0FBRyxXQUFXOztBQUV6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTQyxPQUFPQSxDQUFDQyxHQUFHLEVBQUVDLFFBQVEsRUFBRTtFQUM1QixNQUFNQyxPQUFPLEdBQUcsRUFBRTtFQUVsQixJQUFJQyxLQUFLLENBQUNDLE9BQU8sQ0FBQ0osR0FBRyxDQUFDLEVBQUU7SUFDcEJBLEdBQUcsQ0FBQ0ssT0FBTyxDQUFDLENBQUNDLEtBQUssRUFBRUMsS0FBSyxLQUFLO01BQzFCTCxPQUFPLENBQUNNLElBQUksQ0FBQ1AsUUFBUSxDQUFDSyxLQUFLLEVBQUVDLEtBQUssQ0FBQyxDQUFDO0lBQ3hDLENBQUMsQ0FBQztFQUNOLENBQUMsTUFBTSxJQUFJUCxHQUFHLElBQUksT0FBT0EsR0FBRyxLQUFLLFFBQVEsRUFBRTtJQUN2QyxLQUFLLElBQUlTLEdBQUcsSUFBSVQsR0FBRyxFQUFFO01BQ2pCLElBQUlBLEdBQUcsQ0FBQ1UsY0FBYyxDQUFDRCxHQUFHLENBQUMsRUFBRTtRQUN6QlAsT0FBTyxDQUFDTSxJQUFJLENBQUNQ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QUN0QyxDQUFDO01BQ0QsS0FBSyxJQUFJNUQsR0FBRyxJQUFJLElBQUksRUFBRTtRQUNsQixJQUFJLElBQUksQ0FBQ0MsY0FBYyxDQUFDRCxHQUFHLENBQUMsRUFBRTtVQUMxQnFGLElBQUksQ0FBQ3JGLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQ0EsR0FBRyxDQUFDO1FBQ3pCO01BQ0o7TUFDQSxPQUFPcUYsSUFBSTtJQUNmLENBQUM7RUFDTDtFQUVBLElBQUksT0FBTzlGLEdBQUcsSUFBSSxVQUFVLEVBQUU7SUFDMUIsT0FBT0EsR0FBRyxDQUFDNEYsT0FBTyxDQUFDLENBQUM7RUFDeEIsQ0FBQyxNQUFNLElBQUk1RixHQUFHLENBQUNpRyxXQUFXLElBQUlqRyxHQUFHLENBQUNpRyxXQUFXLElBQUk5RixLQUFLLEVBQUU7SUFDcEQsT0FBT0gsR0FBRyxDQUFDb0YsS0FBSyxDQUFDLENBQUMsQ0FBQztFQUN2QixDQUFDLE1BQU07SUFDSDtJQUNBLE9BQU9jLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFbkcsR0FBRyxDQUFDO0VBQ2pDO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVNvRyxRQUFRQSxDQUFBLEVBQUc7RUFDaEIsSUFBSUMsSUFBSSxHQUFHbEcsS0FBSyxDQUFDbUcsSUFBSSxDQUFDakMsU0FBUyxDQUFDO0VBQ2hDLElBQUlrQyxVQUFVLEdBQUcsSUFBSTtFQUNyQkYsSUFBSSxDQUFDaEcsT0FBTyxDQUFDLFVBQVVtRyxHQUFHLEVBQUU7SUFDeEIsSUFBSUQsVUFBVSxLQUFLLElBQUksSUFBSSxPQUFPQyxHQUFHLElBQUkxRyxLQUFLLElBQUkwRyxHQUFHLEtBQUssSUFBSSxFQUFFO01BQzVERCxVQUFVLEdBQUdDLEdBQUc7SUFDcEI7RUFDSixDQUFDLENBQUM7RUFDRixPQUFPRCxVQUFVO0FBQ3JCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVNFLGlCQUFpQkEsQ0FBQ0MsT0FBTyxFQUFFO0VBQ2hDLE1BQU1DLEtBQUssR0FBR0QsT0FBTyxDQUFDOUIsS0FBSyxDQUFDLEdBQUcsQ0FBQztFQUNoQyxNQUFNZ0MsR0FBRyxHQUFHLEVBQUU7RUFDZDdHLE9BQU8sQ0FBQzRHLEtBQUssRUFBR0UsSUFBSSxJQUFLO0lBQ3JCRCxHQUFHLENBQUNwRyxJQUFJLENBQUNxRyxJQUFJLENBQUNDLElBQUksQ0FBQyxDQUFDLENBQUM7RUFDekIsQ0FBQyxDQUFDO0VBQ0YsT0FBT0YsR0FBRztBQUNkIiwiaWdub3JlTGlzdCI6W119