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>
4739 lines
521 KiB
JavaScript
Executable File
4739 lines
521 KiB
JavaScript
Executable File
/* === storage/rsx-tmp/npm_import_declarations_95a6f602c98037611b640b0b5342830b.js === */
|
|
// NPM Import Declarations for App Bundle
|
|
// Auto-generated to provide NPM modules to app bundle scope
|
|
// Cache key: 95a6f602c98037611b640b0b5342830b
|
|
|
|
const jqhtml = window._rsx_npm.jqhtml;
|
|
if (!jqhtml) {
|
|
throw new Error(
|
|
'RSX Framework Error: NPM module "jqhtml" not found.\n' +
|
|
'Expected window._rsx_npm.jqhtml to be defined by the vendor bundle.'
|
|
);
|
|
}
|
|
|
|
const _Base_Jqhtml_Component = window._rsx_npm._Base_Jqhtml_Component;
|
|
if (!_Base_Jqhtml_Component) {
|
|
throw new Error(
|
|
'RSX Framework Error: NPM module "_Base_Jqhtml_Component" not found.\n' +
|
|
'Expected window._rsx_npm._Base_Jqhtml_Component to be defined by the vendor bundle.'
|
|
);
|
|
}
|
|
|
|
// Clean up NPM container to prevent console access
|
|
delete window._rsx_npm;
|
|
|
|
|
|
/* === app/RSpade/Core/Js/decorator.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* Decorator function that marks a function as a decorator implementation.
|
|
*
|
|
* When a function has @decorator in its JSDoc comment, it whitelists that function
|
|
* to be used as a decorator on other methods throughout the codebase.
|
|
*
|
|
* The function itself performs no operation - it simply returns its input unchanged.
|
|
* Its purpose is purely as a marker for the manifest validation system.
|
|
*
|
|
* Usage:
|
|
* // /**
|
|
* // * My custom decorator implementation
|
|
* // * @decorator
|
|
* // *\/
|
|
* function my_custom_decorator(target, key, descriptor) {
|
|
* // Decorator implementation
|
|
* }
|
|
*
|
|
* This allows my_custom_decorator to be used as @my_custom_decorator on static methods.
|
|
*
|
|
* TODO: This is probably no longer necessary? maybe?
|
|
*/
|
|
function decorator(value) {
|
|
return value;
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/browser.js (babel) === */
|
|
"use strict";
|
|
|
|
/*
|
|
* Browser and DOM utility functions for the RSpade framework.
|
|
* These functions handle browser detection, viewport utilities, and DOM manipulation.
|
|
*/
|
|
|
|
// ============================================================================
|
|
// BROWSER DETECTION
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Detects if user is on a mobile device or using mobile viewport
|
|
* @returns {boolean} True if mobile device or viewport < 992px
|
|
* @todo Improve user agent detection for all mobile devices
|
|
*/
|
|
function is_mobile() {
|
|
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
|
return true;
|
|
} else if ($(window).width() < 992) {
|
|
// 992px = bootstrap 4 col-md-
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Detects if user is on desktop (not mobile)
|
|
* @returns {boolean} True if not mobile device/viewport
|
|
*/
|
|
function is_desktop() {
|
|
return !is_mobile();
|
|
}
|
|
|
|
/**
|
|
* Detects the user's operating system
|
|
* @returns {string} OS name: 'Mac OS', 'iPhone', 'iPad', 'Windows', 'Android-Phone', 'Android-Tablet', 'Linux', or 'Unknown'
|
|
*/
|
|
function get_os() {
|
|
let user_agent = window.navigator.userAgent,
|
|
platform = window.navigator.platform,
|
|
macos_platforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
|
|
windows_platforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
|
|
ios_platforms = ['iPhone', 'iPad', 'iPod'],
|
|
os = null;
|
|
let is_mobile_device = is_mobile();
|
|
if (macos_platforms.indexOf(platform) !== -1) {
|
|
os = 'Mac OS';
|
|
} else if (ios_platforms.indexOf(platform) !== -1 && is_mobile_device) {
|
|
os = 'iPhone';
|
|
} else if (ios_platforms.indexOf(platform) !== -1 && !is_mobile_device) {
|
|
os = 'iPad';
|
|
} else if (windows_platforms.indexOf(platform) !== -1) {
|
|
os = 'Windows';
|
|
} else if (/Android/.test(user_agent) && is_mobile_device) {
|
|
os = 'Android-Phone';
|
|
} else if (/Android/.test(user_agent) && !is_mobile_device) {
|
|
os = 'Android-Tablet';
|
|
} else if (!os && /Linux/.test(platform)) {
|
|
os = 'Linux';
|
|
} else {
|
|
os = 'Unknown';
|
|
}
|
|
return os;
|
|
}
|
|
|
|
/**
|
|
* Detects if the user agent is a web crawler/bot
|
|
* @returns {boolean} True if user agent appears to be a bot/crawler
|
|
*/
|
|
function is_crawler() {
|
|
let user_agent = navigator.userAgent;
|
|
let bot_pattern = /bot|spider|crawl|slurp|archiver|ping|search|dig|tracker|monitor|snoopy|yahoo|baidu|msn|ask|teoma|axios/i;
|
|
return bot_pattern.test(user_agent);
|
|
}
|
|
|
|
// ============================================================================
|
|
// DOM SCROLLING UTILITIES
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Scrolls parent container to make target element visible if needed
|
|
* @param {string|HTMLElement|jQuery} target - Target element to scroll into view
|
|
*/
|
|
function scroll_into_view_if_needed(target) {
|
|
const $target = $(target);
|
|
|
|
// Find the closest parent with overflow-y: auto
|
|
const $parent = $target.parent();
|
|
|
|
// Calculate the absolute top position of the target
|
|
const target_top = $target.position().top + $parent.scrollTop();
|
|
const target_height = $target.outerHeight();
|
|
const parent_height = $parent.height();
|
|
const scroll_position = $parent.scrollTop();
|
|
|
|
// Check if the target is out of view
|
|
if (target_top < scroll_position || target_top + target_height > scroll_position + parent_height) {
|
|
Debugger.console_debug('UI', 'Scrolling!', target_top);
|
|
|
|
// Calculate the new scroll position to center the target
|
|
let new_scroll_position = target_top + target_height / 2 - parent_height / 2;
|
|
|
|
// Limit the scroll position between 0 and the maximum scrollable height
|
|
new_scroll_position = Math.max(0, Math.min(new_scroll_position, $parent[0].scrollHeight - parent_height));
|
|
|
|
// Scroll the parent to the new scroll position
|
|
$parent.scrollTop(new_scroll_position);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Scrolls page to make target element visible if needed (with animation)
|
|
* @param {string|HTMLElement|jQuery} target - Target element to scroll into view
|
|
*/
|
|
function scroll_page_into_view_if_needed(target) {
|
|
const $target = $(target);
|
|
|
|
// Calculate the absolute top position of the target relative to the document
|
|
const target_top = $target.offset().top;
|
|
const target_height = $target.outerHeight();
|
|
const window_height = $(window).height();
|
|
const window_scroll_position = $(window).scrollTop();
|
|
|
|
// Check if the target is out of view
|
|
if (target_top < window_scroll_position || target_top + target_height > window_scroll_position + window_height) {
|
|
Debugger.console_debug('UI', 'Scrolling!', target_top);
|
|
|
|
// Calculate the new scroll position to center the target
|
|
const new_scroll_position = target_top + target_height / 2 - window_height / 2;
|
|
|
|
// Animate the scroll to the new position
|
|
$('html, body').animate({
|
|
scrollTop: new_scroll_position
|
|
}, 1000); // duration of the scroll animation in milliseconds
|
|
}
|
|
}
|
|
|
|
// ============================================================================
|
|
// DOM UTILITIES
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Waits for all images on the page to load
|
|
* @param {Function} callback - Function to call when all images are loaded
|
|
*/
|
|
function wait_for_images(callback) {
|
|
const $images = $('img'); // Get all img tags
|
|
const total_images = $images.length;
|
|
let images_loaded = 0;
|
|
if (total_images === 0) {
|
|
callback(); // if there are no images, immediately call the callback
|
|
}
|
|
$images.each(function () {
|
|
const img = new Image();
|
|
img.onload = function () {
|
|
images_loaded++;
|
|
if (images_loaded === total_images) {
|
|
callback(); // call the callback when all images are loaded
|
|
}
|
|
};
|
|
img.onerror = function () {
|
|
images_loaded++;
|
|
if (images_loaded === total_images) {
|
|
callback(); // also call the callback if an image fails to load
|
|
}
|
|
};
|
|
img.src = this.src; // this triggers the loading
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates a jQuery element containing a non-breaking space
|
|
* @returns {jQuery} jQuery span element with
|
|
*/
|
|
function $nbsp() {
|
|
return $('<span> </span>');
|
|
}
|
|
|
|
/**
|
|
* Escapes special characters in a jQuery selector
|
|
* @param {string} id - Element ID to escape
|
|
* @returns {string} jQuery selector string with escaped special characters
|
|
* @warning Not safe for security-critical operations
|
|
*/
|
|
function escape_jq_selector(id) {
|
|
return '#' + id.replace(/(:|\.|\[|\]|,|=|@)/g, '\\$1');
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/datetime.js (babel) === */
|
|
"use strict";
|
|
|
|
/*
|
|
* Date and time utility functions for the RSpade framework.
|
|
* These functions handle date/time conversions and Unix timestamps.
|
|
*/
|
|
|
|
// ============================================================================
|
|
// DATE/TIME UTILITIES
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Gets the current Unix timestamp (seconds since epoch)
|
|
* @returns {number} Current Unix timestamp in seconds
|
|
* @todo Calculate based on server time at page render
|
|
* @todo Move to a date library
|
|
*/
|
|
function unix_time() {
|
|
return Math.round(new Date().getTime() / 1000);
|
|
}
|
|
|
|
/**
|
|
* Converts a date string to Unix timestamp
|
|
* @param {string} str_date - Date string (Y-m-d H:i:s format)
|
|
* @returns {number} Unix timestamp in seconds
|
|
*/
|
|
function ymdhis_to_unix(str_date) {
|
|
const date = new Date(str_date);
|
|
return date.getTime() / 1000;
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/error.js (babel) === */
|
|
"use strict";
|
|
|
|
/*
|
|
* Error handling utility functions for the RSpade framework.
|
|
* These functions handle error creation and debugging utilities.
|
|
*/
|
|
|
|
// ============================================================================
|
|
// ERROR HANDLING
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Creates an error object from a string
|
|
* @param {string|Object} str - Error message or existing error object
|
|
* @param {number} [error_code] - Optional error status code
|
|
* @returns {Object} Error object with error and status properties
|
|
*/
|
|
function error(str, error_code) {
|
|
if (typeof str.error != undef) {
|
|
return str;
|
|
} else {
|
|
if (typeof error_code == undef) {
|
|
return {
|
|
error: str,
|
|
status: null
|
|
};
|
|
} else {
|
|
return {
|
|
error: str,
|
|
status: error_code
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sanity check failure handler for JavaScript
|
|
*
|
|
* This function should be called when a sanity check fails - i.e., when the code
|
|
* encounters a condition that "shouldn't happen" if everything is working correctly.
|
|
*
|
|
* Unlike PHP, we can't stop JavaScript execution, but we can:
|
|
* 1. Throw an error that will be caught by error handlers
|
|
* 2. Log a clear error to the console
|
|
* 3. Provide stack trace for debugging
|
|
*
|
|
* Use this instead of silently returning or continuing when encountering unexpected conditions.
|
|
*
|
|
* @param {string} message Optional specific message about what shouldn't have happened
|
|
* @throws {Error} Always throws with location and context information
|
|
*/
|
|
function shouldnt_happen() {
|
|
let message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
const error = new Error();
|
|
const stack = error.stack || '';
|
|
const stackLines = stack.split('\n');
|
|
|
|
// Get the caller location (skip the Error line and this function)
|
|
let callerInfo = 'unknown location';
|
|
if (stackLines.length > 2) {
|
|
const callerLine = stackLines[2] || stackLines[1] || '';
|
|
// Extract file and line number from stack trace
|
|
const match = callerLine.match(/at\s+.*?\s+\((.*?):(\d+):(\d+)\)/) || callerLine.match(/at\s+(.*?):(\d+):(\d+)/);
|
|
if (match) {
|
|
callerInfo = `${match[1]}:${match[2]}`;
|
|
}
|
|
}
|
|
let errorMessage = `Fatal: shouldnt_happen() was called at ${callerInfo}\n`;
|
|
errorMessage += 'This indicates a sanity check failed - the code is not behaving as expected.\n';
|
|
if (message) {
|
|
errorMessage += `Details: ${message}\n`;
|
|
}
|
|
errorMessage += 'Please thoroughly review the related code to determine why this error occurred.';
|
|
|
|
// Log to console with full visibility
|
|
console.error('='.repeat(80));
|
|
console.error('SANITY CHECK FAILURE');
|
|
console.error('='.repeat(80));
|
|
console.error(errorMessage);
|
|
console.error('Stack trace:', stack);
|
|
console.error('='.repeat(80));
|
|
|
|
// Throw error to stop execution flow
|
|
const fatalError = new Error(errorMessage);
|
|
fatalError.name = 'SanityCheckFailure';
|
|
throw fatalError;
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/hash.js (babel) === */
|
|
"use strict";
|
|
|
|
/*
|
|
* Hashing and comparison utility functions for the RSpade framework.
|
|
* These functions handle object hashing and deep comparison.
|
|
*/
|
|
|
|
// ============================================================================
|
|
// HASHING AND COMPARISON
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Generates a unique hash for any value (handles objects, arrays, circular references)
|
|
* @param {*} the_var - Value to hash
|
|
* @param {boolean} [calc_sha1=true] - If true, returns SHA1 hash; if false, returns JSON
|
|
* @param {Array<string>} [ignored_keys=null] - Keys to ignore when hashing objects
|
|
* @returns {string} SHA1 hash or JSON string of the value
|
|
*/
|
|
function hash(the_var) {
|
|
let calc_sha1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
let ignored_keys = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
if (typeof the_var == undef) {
|
|
the_var = '__undefined__';
|
|
}
|
|
if (ignored_keys === null) {
|
|
ignored_keys = ['$'];
|
|
}
|
|
|
|
// Converts value to json, discarding circular references
|
|
let json_stringify_nocirc = function (value) {
|
|
const cache = [];
|
|
return JSON.stringify(value, function (key, v) {
|
|
if (typeof v === 'object' && typeof the_var._cache_key == 'function') {
|
|
return the_var._hash_key();
|
|
} else if (typeof v === 'object' && v !== null) {
|
|
if (cache.indexOf(v) !== -1) {
|
|
// Duplicate reference found, discard key
|
|
return;
|
|
}
|
|
cache.push(v);
|
|
}
|
|
return v;
|
|
});
|
|
};
|
|
|
|
// Turn every property and all its children into a single depth array of values that we can then
|
|
// sort and hash as a whole
|
|
let flat_var = {};
|
|
let _flatten = function (the_var, prefix) {
|
|
let depth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
// If a class object is provided, circular references can make the call stack recursive.
|
|
// For the purposes of how the hash function is called, this should be sufficient.
|
|
if (depth > 10) {
|
|
return;
|
|
}
|
|
|
|
// Does not account for dates i think...
|
|
|
|
if (is_object(the_var) && typeof the_var._cache_key == 'function') {
|
|
// Use _cache_key to hash components
|
|
flat_var[prefix] = the_var._hash_key();
|
|
} else if (is_object(the_var) && typeof Abstract !== 'undefined' && the_var instanceof Abstract) {
|
|
// Stringify all class objects
|
|
flat_var[prefix] = json_stringify_nocirc(the_var);
|
|
} else if (is_object(the_var)) {
|
|
// Iterate other objects
|
|
flat_var[prefix] = {};
|
|
for (let k in the_var) {
|
|
if (the_var.hasOwnProperty(k) && ignored_keys.indexOf(k) == -1) {
|
|
_flatten(the_var[k], prefix + '..' + k, depth + 1);
|
|
}
|
|
}
|
|
} else if (is_array(the_var)) {
|
|
// Iterate arrays
|
|
flat_var[prefix] = [];
|
|
let i = 0;
|
|
foreach(the_var, v => {
|
|
_flatten(v, prefix + '..' + i, depth + 1);
|
|
i++;
|
|
});
|
|
} else if (is_function(the_var)) {
|
|
// nothing
|
|
} else if (!is_numeric(the_var)) {
|
|
flat_var[prefix] = String(the_var);
|
|
} else {
|
|
flat_var[prefix] = the_var;
|
|
}
|
|
};
|
|
_flatten(the_var, '_');
|
|
let sorter = [];
|
|
foreach(flat_var, function (v, k) {
|
|
sorter.push([k, v]);
|
|
});
|
|
sorter.sort(function (a, b) {
|
|
return a[0] > b[0];
|
|
});
|
|
let json = JSON.stringify(sorter);
|
|
if (calc_sha1) {
|
|
let hashed = sha1.sha1(json);
|
|
return hashed;
|
|
} else {
|
|
return json;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deep comparison of two values (ignores property order and functions)
|
|
* @param {*} a - First value to compare
|
|
* @param {*} b - Second value to compare
|
|
* @returns {boolean} True if values are deeply equal
|
|
*/
|
|
function deep_equal(a, b) {
|
|
return hash(a, false) == hash(b, false);
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Mutex.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* Mutex decorator for exclusive method execution
|
|
*
|
|
* Without arguments: Per-instance locking (each object has its own lock per method)
|
|
* @mutex
|
|
* async my_method() { ... }
|
|
*
|
|
* With ID argument: Global locking by ID (all instances share the lock)
|
|
* @mutex('operation_name')
|
|
* async my_method() { ... }
|
|
*
|
|
* @decorator
|
|
* @param {string} [global_id] - Optional global mutex ID for cross-instance locking
|
|
*/
|
|
function mutex(global_id) {
|
|
// Storage (using IIFEs to keep WeakMap/Map in closure scope)
|
|
const instance_mutexes = function () {
|
|
if (!mutex._instance_storage) {
|
|
mutex._instance_storage = new WeakMap();
|
|
}
|
|
return mutex._instance_storage;
|
|
}();
|
|
const global_mutexes = function () {
|
|
if (!mutex._global_storage) {
|
|
mutex._global_storage = new Map();
|
|
}
|
|
return mutex._global_storage;
|
|
}();
|
|
|
|
/**
|
|
* Get or create a mutex for a specific instance and method
|
|
*/
|
|
function get_instance_mutex(instance, method_name) {
|
|
let instance_locks = instance_mutexes.get(instance);
|
|
if (!instance_locks) {
|
|
instance_locks = new Map();
|
|
instance_mutexes.set(instance, instance_locks);
|
|
}
|
|
let lock_state = instance_locks.get(method_name);
|
|
if (!lock_state) {
|
|
lock_state = {
|
|
active: false,
|
|
queue: []
|
|
};
|
|
instance_locks.set(method_name, lock_state);
|
|
}
|
|
return lock_state;
|
|
}
|
|
|
|
/**
|
|
* Get or create a global mutex by ID
|
|
*/
|
|
function get_global_mutex(id) {
|
|
let lock_state = global_mutexes.get(id);
|
|
if (!lock_state) {
|
|
lock_state = {
|
|
active: false,
|
|
queue: []
|
|
};
|
|
global_mutexes.set(id, lock_state);
|
|
}
|
|
return lock_state;
|
|
}
|
|
|
|
/**
|
|
* Execute the next queued operation for a mutex
|
|
*/
|
|
function schedule_next(lock_state) {
|
|
if (lock_state.active || lock_state.queue.length === 0) {
|
|
return;
|
|
}
|
|
const {
|
|
fn,
|
|
resolve,
|
|
reject
|
|
} = lock_state.queue.shift();
|
|
lock_state.active = true;
|
|
Promise.resolve().then(fn).then(resolve, reject).finally(() => {
|
|
lock_state.active = false;
|
|
schedule_next(lock_state);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Acquire a mutex lock and execute callback
|
|
*/
|
|
function acquire_lock(lock_state, fn) {
|
|
return new Promise((resolve, reject) => {
|
|
lock_state.queue.push({
|
|
fn,
|
|
resolve,
|
|
reject
|
|
});
|
|
schedule_next(lock_state);
|
|
});
|
|
}
|
|
|
|
// If called with an ID argument: @mutex('id')
|
|
if (typeof global_id === 'string') {
|
|
return function (target, key, descriptor) {
|
|
const original_method = descriptor.value;
|
|
if (typeof original_method !== 'function') {
|
|
throw new Error(`@mutex can only be applied to methods (tried to apply to ${key})`);
|
|
}
|
|
descriptor.value = function () {
|
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
args[_key] = arguments[_key];
|
|
}
|
|
const lock_state = get_global_mutex(global_id);
|
|
return acquire_lock(lock_state, () => original_method.apply(this, args));
|
|
};
|
|
return descriptor;
|
|
};
|
|
}
|
|
|
|
// If called without arguments: @mutex (target is the first argument)
|
|
const target = global_id; // In this case, first arg is target
|
|
const key = arguments[1];
|
|
const descriptor = arguments[2];
|
|
const original_method = descriptor.value;
|
|
if (typeof original_method !== 'function') {
|
|
throw new Error(`@mutex can only be applied to methods (tried to apply to ${key})`);
|
|
}
|
|
descriptor.value = function () {
|
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
args[_key2] = arguments[_key2];
|
|
}
|
|
const lock_state = get_instance_mutex(this, key);
|
|
return acquire_lock(lock_state, () => original_method.apply(this, args));
|
|
};
|
|
return descriptor;
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/async.js (babel) === */
|
|
"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);
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/functions.js (babel) === */
|
|
"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;
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Manifest.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* Manifest - JavaScript class registry and metadata system
|
|
*
|
|
* This class maintains a registry of all JavaScript classes in the bundle,
|
|
* tracking their names and inheritance relationships. It provides utilities
|
|
* for working with class hierarchies and calling initialization methods.
|
|
*/
|
|
class Manifest {
|
|
/**
|
|
* Define classes in the manifest (framework internal)
|
|
* @param {Array} items - Array of class definitions [[Class, "ClassName", ParentClass, decorators], ...]
|
|
*/
|
|
static _define(items) {
|
|
// Initialize the classes object if not already defined
|
|
if (typeof Manifest._classes === 'undefined') {
|
|
Manifest._classes = {};
|
|
}
|
|
|
|
// Process each class definition
|
|
items.forEach(item => {
|
|
let class_object = item[0];
|
|
let class_name = item[1];
|
|
let class_extends = item[2] || null;
|
|
let decorators = item[3] || null;
|
|
|
|
// Store the class information (using object to avoid duplicates)
|
|
Manifest._classes[class_name] = {
|
|
class: class_object,
|
|
name: class_name,
|
|
extends: class_extends,
|
|
decorators: decorators // Store compact decorator data
|
|
};
|
|
|
|
// Add metadata to the class object itself
|
|
class_object._name = class_name;
|
|
class_object._extends = class_extends;
|
|
class_object._decorators = decorators;
|
|
});
|
|
|
|
// Build the subclass index after all classes are defined
|
|
Manifest._build_subclass_index();
|
|
}
|
|
|
|
/**
|
|
* Build an index of subclasses for efficient lookups
|
|
* This creates a mapping where each class name points to an array of all its subclasses
|
|
* @private
|
|
*/
|
|
static _build_subclass_index() {
|
|
// Initialize the subclass index
|
|
Manifest._subclass_index = {};
|
|
|
|
// Step through each class and walk up its parent chain
|
|
for (let class_name in Manifest._classes) {
|
|
const classdata = Manifest._classes[class_name];
|
|
let current_class_name = class_name;
|
|
let current_classdata = classdata;
|
|
|
|
// Walk up the parent chain until we reach the root
|
|
while (current_classdata) {
|
|
const extends_name = current_classdata.extends;
|
|
if (extends_name) {
|
|
// Initialize the parent's subclass array if needed
|
|
if (!Manifest._subclass_index[extends_name]) {
|
|
Manifest._subclass_index[extends_name] = [];
|
|
}
|
|
|
|
// Add this class to its parent's subclass list
|
|
if (!Manifest._subclass_index[extends_name].includes(class_name)) {
|
|
Manifest._subclass_index[extends_name].push(class_name);
|
|
}
|
|
|
|
// Move up to the parent's metadata (if it exists in manifest)
|
|
if (Manifest._classes[extends_name]) {
|
|
current_classdata = Manifest._classes[extends_name];
|
|
} else {
|
|
// Parent not in manifest (e.g., native JavaScript class), stop here
|
|
current_classdata = null;
|
|
}
|
|
} else {
|
|
// No parent, we've reached the root
|
|
current_classdata = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all classes that extend a given base class
|
|
* @param {Class|string} base_class - The base class (object or name string) to check for
|
|
* @returns {Array} Array of objects with {class_name, class_object} for classes that extend the base class
|
|
*/
|
|
static get_extending(base_class) {
|
|
if (!Manifest._classes) {
|
|
return [];
|
|
}
|
|
|
|
// Convert string to class object if needed
|
|
let base_class_object = base_class;
|
|
if (typeof base_class === 'string') {
|
|
base_class_object = Manifest.get_class_by_name(base_class);
|
|
if (!base_class_object) {
|
|
throw new Error(`Base class not found: ${base_class}`);
|
|
}
|
|
}
|
|
const classes = [];
|
|
for (let class_name in Manifest._classes) {
|
|
const classdata = Manifest._classes[class_name];
|
|
if (Manifest.js_is_subclass_of(classdata.class, base_class_object)) {
|
|
classes.push({
|
|
class_name: class_name,
|
|
class_object: classdata.class
|
|
});
|
|
}
|
|
}
|
|
|
|
// Sort alphabetically by class name to ensure deterministic behavior and prevent race condition bugs
|
|
classes.sort((a, b) => a.class_name.localeCompare(b.class_name));
|
|
return classes;
|
|
}
|
|
|
|
/**
|
|
* Check if a class is a subclass of another class
|
|
* Matches PHP Manifest::js_is_subclass_of() signature and behavior
|
|
* @param {Class|string} subclass - The child class (object or name) to check
|
|
* @param {Class|string} superclass - The parent class (object or name) to check against
|
|
* @returns {boolean} True if subclass extends superclass (directly or indirectly)
|
|
*/
|
|
static js_is_subclass_of(subclass, superclass) {
|
|
// Convert string names to class objects
|
|
let subclass_object = subclass;
|
|
if (typeof subclass === 'string') {
|
|
subclass_object = Manifest.get_class_by_name(subclass);
|
|
if (!subclass_object) {
|
|
// Can't resolve subclass - return false per spec
|
|
return false;
|
|
}
|
|
}
|
|
let superclass_object = superclass;
|
|
if (typeof superclass === 'string') {
|
|
superclass_object = Manifest.get_class_by_name(superclass);
|
|
if (!superclass_object) {
|
|
// Can't resolve superclass - fail loud per spec
|
|
throw new Error(`Superclass not found in manifest: ${superclass}`);
|
|
}
|
|
}
|
|
|
|
// Classes are not subclasses of themselves
|
|
if (subclass_object === superclass_object) {
|
|
return false;
|
|
}
|
|
|
|
// Walk up the inheritance chain
|
|
let current_class = subclass_object;
|
|
while (current_class) {
|
|
if (current_class === superclass_object) {
|
|
return true;
|
|
}
|
|
// Move up to parent class
|
|
if (current_class._extends) {
|
|
// _extends may be a string or class reference
|
|
if (typeof current_class._extends === 'string') {
|
|
current_class = Manifest.get_class_by_name(current_class._extends);
|
|
} else {
|
|
current_class = current_class._extends;
|
|
}
|
|
} else {
|
|
current_class = null;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get a class by its name
|
|
* @param {string} class_name - The name of the class
|
|
* @returns {Class|null} The class object or null if not found
|
|
*/
|
|
static get_class_by_name(class_name) {
|
|
if (!Manifest._classes || !Manifest._classes[class_name]) {
|
|
return null;
|
|
}
|
|
return Manifest._classes[class_name].class;
|
|
}
|
|
|
|
/**
|
|
* Get all registered classes
|
|
* @returns {Array} Array of objects with {class_name, class_object, extends}
|
|
*/
|
|
static get_all_classes() {
|
|
if (!Manifest._classes) {
|
|
return [];
|
|
}
|
|
const results = [];
|
|
for (let class_name in Manifest._classes) {
|
|
const classdata = Manifest._classes[class_name];
|
|
results.push({
|
|
class_name: classdata.name,
|
|
class_object: classdata.class,
|
|
extends: classdata.extends
|
|
});
|
|
}
|
|
|
|
// Sort alphabetically by class name to ensure deterministic behavior and prevent race condition bugs
|
|
results.sort((a, b) => a.class_name.localeCompare(b.class_name));
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Get the build key from the application configuration
|
|
* @returns {string} The build key or "NOBUILD" if not available
|
|
*/
|
|
static build_key() {
|
|
if (window.rsxapp && window.rsxapp.build_key) {
|
|
return window.rsxapp.build_key;
|
|
}
|
|
return 'NOBUILD';
|
|
}
|
|
|
|
/**
|
|
* Get decorators for a specific class and method
|
|
* @param {string|Class} class_name - The class name or class object
|
|
* @param {string} method_name - The method name
|
|
* @returns {Array|null} Array of decorator objects or null if none found
|
|
*/
|
|
static get_decorators(class_name, method_name) {
|
|
// Convert class object to name if needed
|
|
if (typeof class_name !== 'string') {
|
|
class_name = class_name._name || class_name.name;
|
|
}
|
|
const class_info = Manifest._classes[class_name];
|
|
if (!class_info || !class_info.decorators || !class_info.decorators[method_name]) {
|
|
return null;
|
|
}
|
|
|
|
// Transform compact format to object format
|
|
return Manifest._transform_decorators(class_info.decorators[method_name]);
|
|
}
|
|
|
|
/**
|
|
* Get all methods with decorators for a class
|
|
* @param {string|Class} class_name - The class name or class object
|
|
* @returns {Object} Object with method names as keys and decorator arrays as values
|
|
*/
|
|
static get_all_decorators(class_name) {
|
|
// Convert class object to name if needed
|
|
if (typeof class_name !== 'string') {
|
|
class_name = class_name._name || class_name.name;
|
|
}
|
|
const class_info = Manifest._classes[class_name];
|
|
if (!class_info || !class_info.decorators) {
|
|
return {};
|
|
}
|
|
|
|
// Transform all decorators from compact to object format
|
|
const result = {};
|
|
for (let method_name in class_info.decorators) {
|
|
result[method_name] = Manifest._transform_decorators(class_info.decorators[method_name]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Transform compact decorator format to object format
|
|
* @param {Array} compact_decorators - Array of [name, [args]] tuples
|
|
* @returns {Array} Array of decorator objects with name and arguments properties
|
|
* @private
|
|
*/
|
|
static _transform_decorators(compact_decorators) {
|
|
if (!Array.isArray(compact_decorators)) {
|
|
return [];
|
|
}
|
|
return compact_decorators.map(decorator => {
|
|
if (Array.isArray(decorator) && decorator.length >= 2) {
|
|
return {
|
|
name: decorator[0],
|
|
arguments: decorator[1] || []
|
|
};
|
|
}
|
|
// Handle malformed decorator data
|
|
return {
|
|
name: 'unknown',
|
|
arguments: []
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check if a method has a specific decorator
|
|
* @param {string|Class} class_name - The class name or class object
|
|
* @param {string} method_name - The method name
|
|
* @param {string} decorator_name - The decorator name to check for
|
|
* @returns {boolean} True if the method has the decorator
|
|
*/
|
|
static has_decorator(class_name, method_name, decorator_name) {
|
|
const decorators = Manifest.get_decorators(class_name, method_name);
|
|
if (!decorators) {
|
|
return false;
|
|
}
|
|
return decorators.some(d => d.name === decorator_name);
|
|
}
|
|
|
|
/**
|
|
* Get all subclasses of a given class using the pre-built index
|
|
* This is the JavaScript equivalent of PHP's Manifest::js_get_subclasses_of()
|
|
* @param {Class|string} base_class - The base class (object or name string) to get subclasses of
|
|
* @returns {Array<Class>} Array of actual class objects that are subclasses of the base class
|
|
*/
|
|
static js_get_subclasses_of(base_class) {
|
|
// Initialize index if needed
|
|
if (!Manifest._subclass_index) {
|
|
Manifest._build_subclass_index();
|
|
}
|
|
|
|
// Convert class object to name if needed
|
|
let base_class_name = base_class;
|
|
if (typeof base_class !== 'string') {
|
|
base_class_name = base_class._name || base_class.name;
|
|
}
|
|
|
|
// Check if the base class exists
|
|
if (!Manifest._classes[base_class_name]) {
|
|
// Base class not in manifest - return empty array
|
|
return [];
|
|
}
|
|
|
|
// Get subclass names from the index
|
|
const subclass_names = Manifest._subclass_index[base_class_name] || [];
|
|
|
|
// Convert names to actual class objects
|
|
const subclass_objects = [];
|
|
for (let subclass_name of subclass_names) {
|
|
const classdata = Manifest._classes[subclass_name];
|
|
subclass_objects.push(classdata.class);
|
|
}
|
|
|
|
// Sort by class name for deterministic behavior
|
|
subclass_objects.sort((a, b) => {
|
|
const name_a = a._name || a.name;
|
|
const name_b = b._name || b.name;
|
|
return name_a.localeCompare(name_b);
|
|
});
|
|
return subclass_objects;
|
|
}
|
|
}
|
|
|
|
// RSX manifest automatically makes classes global - no manual assignment needed
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Rsx_Behaviors.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* Rsx_Behaviors - Core Framework User Experience Enhancements
|
|
*
|
|
* This class provides automatic quality-of-life behaviors that improve the default
|
|
* browser experience for RSX applications. These behaviors are transparent to
|
|
* application developers and run automatically on framework initialization.
|
|
*
|
|
* These behaviors use jQuery event delegation to handle both existing and dynamically
|
|
* added content. They are implemented with low priority to allow application code to
|
|
* override default behaviors when needed.
|
|
*
|
|
* @internal Framework use only - not part of public API
|
|
*/
|
|
class Rsx_Behaviors {
|
|
static _on_framework_core_init() {
|
|
Rsx_Behaviors._init_ignore_invalid_anchor_links();
|
|
Rsx_Behaviors._trim_copied_text();
|
|
}
|
|
|
|
/**
|
|
* - Anchor link handling: Prevents broken "#" links from causing page jumps or URL changes
|
|
* - Ignores "#" (empty hash) to prevent scroll-to-top behavior
|
|
* - Ignores "#placeholder*" links used as route placeholders during development
|
|
* - Validates anchor targets exist before allowing navigation
|
|
* - Preserves normal anchor behavior when targets exist
|
|
*/
|
|
static _init_ignore_invalid_anchor_links() {
|
|
return; // disabled for now - make this into a configurable option
|
|
|
|
// Use event delegation on document to handle all current and future anchor clicks
|
|
// Use mousedown instead of click to run before most application handlers
|
|
$(document).on('mousedown', 'a[href^="#"]', function (e) {
|
|
const $link = $(this);
|
|
const href = $link.attr('href');
|
|
|
|
// Check if another handler has already prevented default
|
|
if (e.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
// Allow data-rsx-allow-hash attribute to bypass this behavior
|
|
if ($link.data('rsx-allow-hash')) {
|
|
return;
|
|
}
|
|
|
|
// Handle empty hash - prevent scroll to top
|
|
if (href === '#') {
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
return false;
|
|
}
|
|
|
|
// Handle placeholder links used during development
|
|
if (href.startsWith('#placeholder')) {
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
return false;
|
|
}
|
|
|
|
// For other hash links, check if target exists
|
|
const targetId = href.substring(1);
|
|
if (targetId) {
|
|
// Check for element with matching ID or name attribute
|
|
const targetExists = document.getElementById(targetId) !== null || document.querySelector(`[name="${targetId}"]`) !== null;
|
|
if (!targetExists) {
|
|
// Target doesn't exist - prevent navigation
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
return false;
|
|
}
|
|
// Target exists - allow normal anchor behavior
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* - Copy text trimming: Automatically removes leading/trailing whitespace from copied text
|
|
* - Hold Shift to preserve whitespace
|
|
* - Skips trimming in code blocks, textareas, and contenteditable elements
|
|
*/
|
|
static _trim_copied_text() {
|
|
document.addEventListener('copy', function (event) {
|
|
// Don't trim if user is holding Shift (allows copying with whitespace if needed)
|
|
if (event.shiftKey) return;
|
|
let selection = window.getSelection();
|
|
let selected_text = selection.toString();
|
|
|
|
// Don't trim if selection is empty
|
|
if (!selected_text) return;
|
|
|
|
// Don't trim if copying from code blocks, textareas, or content-editable (preserve formatting)
|
|
let container = selection.getRangeAt(0).commonAncestorContainer;
|
|
if (container.nodeType === 3) container = container.parentNode; // Text node to element
|
|
if (container.closest('pre, code, .code-block, textarea, [contenteditable="true"]')) return;
|
|
let trimmed_text = selected_text.trim();
|
|
|
|
// Only modify if there's actually whitespace to trim
|
|
if (trimmed_text !== selected_text && trimmed_text.length > 0) {
|
|
event.preventDefault();
|
|
event.clipboardData.setData('text/plain', trimmed_text);
|
|
console.log('Copy: trimmed whitespace from selection');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Rsx_Cache.js (babel) === */
|
|
"use strict";
|
|
|
|
// Simple key value cache. Can only store 5000 entries, will reset after 5000 entries.
|
|
|
|
// Todo: keep local cache concept the same, replace global cache concept with the nov 2019 version of
|
|
// session cache. Use a session key & build key to track cache keys so cached values only last until user logs out.
|
|
// review session code to ensure that session key *always* rotates on logout. Make session id a protected value.
|
|
class Rsx_Cache {
|
|
static on_core_define() {
|
|
Core_Cache._caches = {
|
|
global: {},
|
|
instance: {}
|
|
};
|
|
Core_Cache._caches_set = 0;
|
|
}
|
|
|
|
// Alias for get_instance
|
|
static get(key) {
|
|
return Rsx_Cache.get_instance(key);
|
|
}
|
|
|
|
// Returns from the pool of cached data for this 'instance'. An instance
|
|
// in this case is a virtual page load / navigation in the SPA. Call Main.lib.reset() to reset.
|
|
// Returns null on failure
|
|
static get_instance(key) {
|
|
if (Main.debug('no_api_cache')) {
|
|
return null;
|
|
}
|
|
let key_encoded = Rsx_Cache._encodekey(key);
|
|
if (typeof Core_Cache._caches.instance[key_encoded] != undef) {
|
|
return JSON.parse(Core_Cache._caches.instance[key_encoded]);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Returns null on failure
|
|
// Returns a cached value from global cache (unique to page load, survives reset())
|
|
static get_global(key) {
|
|
if (Main.debug('no_api_cache')) {
|
|
return null;
|
|
}
|
|
let key_encoded = Rsx_Cache._encodekey(key);
|
|
if (typeof Core_Cache._caches.global[key_encoded] != undef) {
|
|
return JSON.parse(Core_Cache._caches.global[key_encoded]);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Sets a value in instance and global cache (not shared between browser tabs)
|
|
static set(key, value) {
|
|
if (Main.debug('no_api_cache')) {
|
|
return;
|
|
}
|
|
if (value === null) {
|
|
return;
|
|
}
|
|
if (value.length > 64 * 1024) {
|
|
Debugger.console_debug('CACHE', 'Warning - not caching large cache entry', key);
|
|
return;
|
|
}
|
|
let key_encoded = Rsx_Cache._encodekey(key);
|
|
Core_Cache._caches.global[key_encoded] = JSON.stringify(value);
|
|
Core_Cache._caches.instance[key_encoded] = JSON.stringify(value);
|
|
|
|
// Debugger.console_debug("CACHE", "Set", key, value);
|
|
|
|
Core_Cache._caches_set++;
|
|
|
|
// Reset cache after 5000 items set
|
|
if (Core_Cache._caches_set > 5000) {
|
|
// Get an accurate count
|
|
Core_Cache._caches_set = count(Core_Cache._caches.global);
|
|
if (Core_Cache._caches_set > 5000) {
|
|
Core_Cache._caches = {
|
|
global: {},
|
|
instance: {}
|
|
};
|
|
Core_Cache._caches_set = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Returns null on failure
|
|
// Returns a cached value from session cache (shared between browser tabs)
|
|
static get_session(key) {
|
|
if (Main.debug('no_api_cache')) {
|
|
return null;
|
|
}
|
|
if (!Rsx_Cache._supportsStorage()) {
|
|
return null;
|
|
}
|
|
let key_encoded = Rsx_Cache._encodekey(key);
|
|
let rs = sessionStorage.getItem(key_encoded);
|
|
if (!empty(rs)) {
|
|
return JSON.parse(rs);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Sets a value in session cache (shared between browser tabs)
|
|
static set_session(key, value) {
|
|
let _tryagain = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
if (Main.debug('no_api_cache')) {
|
|
return;
|
|
}
|
|
if (value.length > 64 * 1024) {
|
|
Debugger.console_debug('CACHE', 'Warning - not caching large cache entry', key);
|
|
return;
|
|
}
|
|
if (!Rsx_Cache._supportsStorage()) {
|
|
return null;
|
|
}
|
|
let key_encoded = Rsx_Cache._encodekey(key);
|
|
try {
|
|
sessionStorage.removeItem(key_encoded);
|
|
sessionStorage.setItem(key_encoded, JSON.stringify(value));
|
|
} catch (e) {
|
|
if (Rsx_Cache._isOutOfSpace(e) && sessionStorage.length) {
|
|
sessionStorage.clear();
|
|
if (_tryagain) {
|
|
Core_Cache.set_session(key, value, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static _reset() {
|
|
Core_Cache._caches.instance = {};
|
|
}
|
|
|
|
/**
|
|
* For given key of any type including an object, return a string representing
|
|
* the key that the cached value should be stored as in sessionstorage
|
|
*/
|
|
static _encodekey(key) {
|
|
const prefix = 'cache_';
|
|
|
|
// Session reimplement
|
|
// var prefix = "cache_" + Spa.session().user_id() + "_";
|
|
|
|
if (is_string(key) && key.length < 150 && key.indexOf(' ') == -1) {
|
|
return prefix + Manifest.build_key() + '_' + key;
|
|
} else {
|
|
return prefix + hash([Manifest.build_key(), key]);
|
|
}
|
|
}
|
|
|
|
// Determines if sessionStorage is supported in the browser;
|
|
// result is cached for better performance instead of being run each time.
|
|
// Feature detection is based on how Modernizr does it;
|
|
// it's not straightforward due to FF4 issues.
|
|
// It's not run at parse-time as it takes 200ms in Android.
|
|
// Code from https://github.com/pamelafox/lscache/blob/master/lscache.js, Apache License Pamelafox
|
|
static _supportsStorage() {
|
|
let key = '__cachetest__';
|
|
let value = key;
|
|
if (Rsx_Cache.__supportsStorage !== undefined) {
|
|
return Rsx_Cache.__supportsStorage;
|
|
}
|
|
|
|
// some browsers will throw an error if you try to access local storage (e.g. brave browser)
|
|
// hence check is inside a try/catch
|
|
try {
|
|
if (!sessionStorage) {
|
|
return false;
|
|
}
|
|
} catch (ex) {
|
|
return false;
|
|
}
|
|
try {
|
|
sessionStorage.setItem(key, value);
|
|
sessionStorage.removeItem(key);
|
|
Rsx_Cache.__supportsStorage = true;
|
|
} catch (e) {
|
|
// If we hit the limit, and we don't have an empty sessionStorage then it means we have support
|
|
if (Rsx_Cache._isOutOfSpace(e) && sessionStorage.length) {
|
|
Rsx_Cache.__supportsStorage = true; // just maxed it out and even the set test failed.
|
|
} else {
|
|
Rsx_Cache.__supportsStorage = false;
|
|
}
|
|
}
|
|
return Rsx_Cache.__supportsStorage;
|
|
}
|
|
|
|
// Check to set if the error is us dealing with being out of space
|
|
static _isOutOfSpace(e) {
|
|
return e && (e.name === 'QUOTA_EXCEEDED_ERR' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED' || e.name === 'QuotaExceededError');
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Rsx_Init.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* Rsx_Init - Core framework initialization and environment validation
|
|
*/
|
|
class Rsx_Init {
|
|
/**
|
|
* Called via Rsx._rsx_core_boot
|
|
* Initializes the core environment and runs basic sanity checks
|
|
*/
|
|
static _on_framework_core_init() {
|
|
if (!Rsx.is_prod()) {
|
|
Rsx_Init.__environment_checks();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Development environment checks to ensure proper configuration
|
|
*/
|
|
static __environment_checks() {
|
|
// Find all script tags in the DOM
|
|
const scripts = document.getElementsByTagName('script');
|
|
for (let i = 0; i < scripts.length; i++) {
|
|
const script = scripts[i];
|
|
|
|
// Skip inline scripts (no src attribute)
|
|
if (!script.src) {
|
|
continue;
|
|
}
|
|
|
|
// Check if script has defer attribute
|
|
if (!script.defer) {
|
|
const src = script.src || '(inline script)';
|
|
const reason = `All script tags used in an RSpade project must have defer attribute. Found script without defer: ${src}`;
|
|
|
|
// Stop framework boot with reason
|
|
Rsx._rsx_core_boot_stop(reason);
|
|
|
|
// Also log to console for visibility
|
|
console.error(`[RSX BOOT STOPPED] ${reason}`);
|
|
|
|
// Stop checking after first violation
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Rsx_Js_Model.js (babel) === */
|
|
"use strict";
|
|
|
|
// @FILE-SUBCLASS-01-EXCEPTION
|
|
|
|
/**
|
|
* Base class for JavaScript ORM models
|
|
*
|
|
* Provides core functionality for fetching records from backend PHP models.
|
|
* All model stubs generated by the manifest extend this base class.
|
|
*
|
|
* Example usage:
|
|
* // Fetch single record
|
|
* const user = await User_Model.fetch(123);
|
|
*
|
|
* // Fetch multiple records
|
|
* const users = await User_Model.fetch([1, 2, 3]);
|
|
*
|
|
* // Create instance with data
|
|
* const user = new User_Model({id: 1, name: 'John'});
|
|
*
|
|
* @Instantiatable
|
|
*/
|
|
class Rsx_Js_Model {
|
|
/**
|
|
* Constructor - Initialize model instance with data
|
|
*
|
|
* @param {Object} data - Key-value pairs to populate the model
|
|
*/
|
|
constructor() {
|
|
let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
// __MODEL SYSTEM: Enables automatic ORM instantiation when fetching from PHP models.
|
|
// PHP models add "__MODEL": "ClassName" to JSON, JavaScript uses it to create proper instances.
|
|
// This provides typed model objects instead of plain JSON, with methods and type checking.
|
|
|
|
// This constructor filters out the __MODEL marker that was used to identify which class
|
|
// to instantiate, keeping only the actual data properties on the instance.
|
|
const {
|
|
__MODEL,
|
|
...modelData
|
|
} = data;
|
|
Object.assign(this, modelData);
|
|
}
|
|
|
|
/**
|
|
* Fetch record(s) from the backend model
|
|
*
|
|
* This method mirrors the PHP Model::fetch() functionality.
|
|
* The backend model must have a fetch() method with the
|
|
* #[Ajax_Endpoint_Model_Fetch] annotation to be callable.
|
|
*
|
|
* @param {number|Array} id - Single ID or array of IDs to fetch
|
|
* @returns {Promise} - Single model instance, array of instances, or false
|
|
*/
|
|
static async fetch(id) {
|
|
const CurrentClass = this;
|
|
// Get the model class name from the current class
|
|
const modelName = CurrentClass.name;
|
|
const response = await $.ajax({
|
|
url: `/_fetch/${modelName}`,
|
|
method: 'POST',
|
|
data: {
|
|
id: id
|
|
},
|
|
dataType: 'json'
|
|
});
|
|
|
|
// Handle response based on type
|
|
if (response === false) {
|
|
return false;
|
|
}
|
|
|
|
// Use _instantiate_models_recursive to handle ORM instantiation
|
|
// This will automatically detect __MODEL properties and create appropriate instances
|
|
return Rsx_Js_Model._instantiate_models_recursive(response);
|
|
}
|
|
|
|
/**
|
|
* Get the model class name
|
|
* Used internally for API calls
|
|
*
|
|
* @returns {string} The class name
|
|
*/
|
|
static getModelName() {
|
|
const CurrentClass = this;
|
|
return CurrentClass.name;
|
|
}
|
|
|
|
/**
|
|
* Refresh this instance with latest data from server
|
|
*
|
|
* @returns {Promise} Updated instance or false if not found
|
|
*/
|
|
async refresh() {
|
|
const that = this;
|
|
if (!that.id) {
|
|
shouldnt_happen('Cannot refresh model without id property');
|
|
}
|
|
const fresh = await that.constructor.fetch(that.id);
|
|
if (fresh === false) {
|
|
return false;
|
|
}
|
|
|
|
// Update this instance with fresh data
|
|
Object.assign(that, fresh);
|
|
return that;
|
|
}
|
|
|
|
/**
|
|
* Convert model instance to plain object
|
|
* Useful for serialization or sending to APIs
|
|
*
|
|
* @returns {Object} Plain object representation
|
|
*/
|
|
toObject() {
|
|
const that = this;
|
|
const obj = {};
|
|
for (const key in that) {
|
|
if (that.hasOwnProperty(key) && typeof that[key] !== 'function') {
|
|
obj[key] = that[key];
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
/**
|
|
* Convert model instance to JSON string
|
|
*
|
|
* @returns {string} JSON representation
|
|
*/
|
|
toJSON() {
|
|
const that = this;
|
|
return JSON.stringify(that.toObject());
|
|
}
|
|
|
|
/**
|
|
* Recursively instantiate ORM models in response data
|
|
*
|
|
* Looks for objects with __MODEL property and instantiates the appropriate
|
|
* JavaScript model class if it exists in the global scope.
|
|
*
|
|
* @param {*} data - The data to process (can be any type)
|
|
* @returns {*} The data with ORM objects instantiated
|
|
*/
|
|
static _instantiate_models_recursive(data) {
|
|
// __MODEL SYSTEM: Enables automatic ORM instantiation when fetching from PHP models.
|
|
// PHP models add "__MODEL": "ClassName" to JSON, JavaScript uses it to create proper instances.
|
|
// This provides typed model objects instead of plain JSON, with methods and type checking.
|
|
|
|
// This recursive processor scans all API response data looking for __MODEL markers.
|
|
// When found, it attempts to instantiate the appropriate JavaScript model class,
|
|
// converting {__MODEL: "User_Model", id: 1, name: "John"} into new User_Model({...}).
|
|
// Works recursively through arrays and nested objects to handle complex data structures.
|
|
// Handle null/undefined
|
|
if (data === null || data === undefined) {
|
|
return data;
|
|
}
|
|
|
|
// Handle arrays - recursively process each element
|
|
if (Array.isArray(data)) {
|
|
return data.map(item => Rsx_Js_Model._instantiate_models_recursive(item));
|
|
}
|
|
|
|
// Handle objects
|
|
if (typeof data === 'object') {
|
|
// Check if this object has a __MODEL property
|
|
if (data.__MODEL && typeof data.__MODEL === 'string') {
|
|
// Try to find the model class in the global scope
|
|
const ModelClass = window[data.__MODEL];
|
|
|
|
// If the model class exists and extends Rsx_Js_Model, instantiate it
|
|
// Dynamic model resolution requires checking class existence - @JS-DEFENSIVE-01-EXCEPTION
|
|
if (ModelClass && ModelClass.prototype instanceof Rsx_Js_Model) {
|
|
return new ModelClass(data);
|
|
}
|
|
}
|
|
|
|
// Recursively process all object properties
|
|
const result = {};
|
|
for (const key in data) {
|
|
if (data.hasOwnProperty(key)) {
|
|
result[key] = Rsx_Js_Model._instantiate_models_recursive(data[key]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Return primitive values as-is
|
|
return data;
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Rsx_View_Transitions.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* View_Transitions - Smooth page-to-page transitions using View Transitions API
|
|
*
|
|
* Enables cross-document view transitions so the browser doesn't paint the new page
|
|
* until it's ready, creating smooth animations between pages.
|
|
*
|
|
* Falls back gracefully if View Transitions API is not available.
|
|
*/
|
|
class Rsx_View_Transitions {
|
|
/**
|
|
* Called during framework core init phase
|
|
* Checks for View Transitions API support and enables if available
|
|
*/
|
|
static _on_framework_core_init() {
|
|
// Check if View Transitions API is supported
|
|
if (!document.startViewTransition) {
|
|
console_debug('VIEW_TRANSITIONS', 'View Transitions API not supported, skipping');
|
|
return;
|
|
}
|
|
|
|
// Enable cross-document view transitions via CSS
|
|
Rsx_View_Transitions._inject_transition_css();
|
|
}
|
|
|
|
/**
|
|
* Inject CSS to enable cross-document view transitions
|
|
*
|
|
* The @view-transition { navigation: auto; } rule tells the browser to:
|
|
* 1. Capture a snapshot of the current page before navigation
|
|
* 2. Fetch the new page
|
|
* 3. Wait until the new page is fully loaded and painted (document.ready)
|
|
* 4. Animate smoothly between the two states
|
|
*
|
|
* This prevents the white flash during navigation and creates app-like transitions.
|
|
*/
|
|
static _inject_transition_css() {
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
@view-transition {
|
|
navigation: auto;
|
|
}
|
|
|
|
/* Disable animation - instant transition */
|
|
::view-transition-group(*),
|
|
::view-transition-old(*),
|
|
::view-transition-new(*) {
|
|
animation-duration: 0s;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/ReadWriteLock.js (babel) === */
|
|
"use strict";
|
|
|
|
var _50ae609e_ReadWriteLock;
|
|
function _50ae609e_assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
|
|
/**
|
|
* ReadWriteLock implementation for RSpade framework
|
|
* Provides exclusive (write) and shared (read) locking mechanisms for asynchronous operations
|
|
*/
|
|
class ReadWriteLock {
|
|
/**
|
|
* Acquire an exclusive mutex 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>}
|
|
*/
|
|
static acquire(name, cb) {
|
|
return new Promise((resolve, reject) => {
|
|
const s = _50ae609e_assertClassBrand(ReadWriteLock, this, _50ae609e_get_lock).call(this, name);
|
|
s.writer_q.push({
|
|
cb,
|
|
resolve,
|
|
reject
|
|
});
|
|
_50ae609e_assertClassBrand(ReadWriteLock, this, _50ae609e_schedule).call(this, name);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Acquire a shared read lock by name.
|
|
* Multiple readers can run in parallel; blocks when writer is active.
|
|
* @param {string} name
|
|
* @param {() => any|Promise<any>} cb
|
|
* @returns {Promise<any>}
|
|
*/
|
|
static acquire_read(name, cb) {
|
|
return new Promise((resolve, reject) => {
|
|
const s = _50ae609e_assertClassBrand(ReadWriteLock, this, _50ae609e_get_lock).call(this, name);
|
|
if (s.writer_active || s.writer_q.length > 0) {
|
|
s.reader_q.push({
|
|
cb,
|
|
resolve,
|
|
reject
|
|
});
|
|
return _50ae609e_assertClassBrand(ReadWriteLock, this, _50ae609e_schedule).call(this, name);
|
|
}
|
|
s.readers += 1;
|
|
Promise.resolve().then(cb).then(resolve, reject).finally(() => {
|
|
s.readers -= 1;
|
|
if (s.readers === 0) _50ae609e_assertClassBrand(ReadWriteLock, this, _50ae609e_schedule).call(this, name);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Force-unlock a mutex (use with caution).
|
|
* Completely removes the lock state, potentially breaking waiting operations.
|
|
* @param {string} name
|
|
*/
|
|
static force_unlock(name) {
|
|
_50ae609e_assertClassBrand(ReadWriteLock, this, _locks)._.delete(name);
|
|
}
|
|
|
|
/**
|
|
* Get information about pending operations on a mutex.
|
|
* @param {string} name
|
|
* @returns {{readers: number, writer_active: boolean, reader_q: number, writer_q: number}}
|
|
*/
|
|
static pending(name) {
|
|
const s = _50ae609e_assertClassBrand(ReadWriteLock, this, _locks)._.get(name);
|
|
if (!s) return {
|
|
readers: 0,
|
|
writer_active: false,
|
|
reader_q: 0,
|
|
writer_q: 0
|
|
};
|
|
return {
|
|
readers: s.readers,
|
|
writer_active: s.writer_active,
|
|
reader_q: s.reader_q.length,
|
|
writer_q: s.writer_q.length
|
|
};
|
|
}
|
|
}
|
|
_50ae609e_ReadWriteLock = ReadWriteLock;
|
|
/**
|
|
* Get or create a lock object for a given name
|
|
* @private
|
|
*/
|
|
function _50ae609e_get_lock(name) {
|
|
let s = _50ae609e_assertClassBrand(_50ae609e_ReadWriteLock, this, _locks)._.get(name);
|
|
if (!s) {
|
|
s = {
|
|
readers: 0,
|
|
writer_active: false,
|
|
reader_q: [],
|
|
writer_q: []
|
|
};
|
|
_50ae609e_assertClassBrand(_50ae609e_ReadWriteLock, this, _locks)._.set(name, s);
|
|
}
|
|
return s;
|
|
}
|
|
/**
|
|
* Schedule the next operation for a lock
|
|
* @private
|
|
*/
|
|
function _50ae609e_schedule(name) {
|
|
const s = _50ae609e_assertClassBrand(_50ae609e_ReadWriteLock, this, _50ae609e_get_lock).call(this, name);
|
|
if (s.writer_active || s.readers > 0) return;
|
|
|
|
// run one writer if queued
|
|
if (s.writer_q.length > 0) {
|
|
const {
|
|
cb,
|
|
resolve,
|
|
reject
|
|
} = s.writer_q.shift();
|
|
s.writer_active = true;
|
|
Promise.resolve().then(cb).then(resolve, reject).finally(() => {
|
|
s.writer_active = false;
|
|
_50ae609e_assertClassBrand(_50ae609e_ReadWriteLock, this, _50ae609e_schedule).call(this, name);
|
|
});
|
|
return;
|
|
}
|
|
|
|
// otherwise run all queued readers in parallel
|
|
if (s.reader_q.length > 0) {
|
|
const batch = s.reader_q.splice(0);
|
|
s.readers += batch.length;
|
|
for (const {
|
|
cb,
|
|
resolve,
|
|
reject
|
|
} of batch) {
|
|
Promise.resolve().then(cb).then(resolve, reject).finally(() => {
|
|
s.readers -= 1;
|
|
if (s.readers === 0) _50ae609e_assertClassBrand(_50ae609e_ReadWriteLock, this, _50ae609e_schedule).call(this, name);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
var _locks = {
|
|
_: new Map()
|
|
};
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Form_Utils.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* Form utilities for validation and error handling
|
|
*/
|
|
class Form_Utils {
|
|
/**
|
|
* Framework initialization hook to register jQuery plugin
|
|
* Creates $.fn.ajax_submit() for form elements
|
|
* @private
|
|
*/
|
|
static _on_framework_core_define() {
|
|
let params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
$.fn.ajax_submit = function () {
|
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
const $element = $(this);
|
|
if (!$element.is('form')) {
|
|
throw new Error('ajax_submit() can only be called on form elements');
|
|
}
|
|
const url = $element.attr('action');
|
|
if (!url) {
|
|
throw new Error('Form must have an action attribute');
|
|
}
|
|
const {
|
|
controller,
|
|
action
|
|
} = Ajax.ajax_url_to_controller_action(url);
|
|
return Form_Utils.ajax_submit($element, controller, action, options);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Shows form validation errors
|
|
*
|
|
* REQUIRED HTML STRUCTURE:
|
|
* For inline field errors to display properly, form fields must follow this structure:
|
|
*
|
|
* <div class="form-group">
|
|
* <label class="form-label" for="field-name">Field Label</label>
|
|
* <input class="form-control" id="field-name" name="field-name" type="text">
|
|
* </div>
|
|
*
|
|
* Key requirements:
|
|
* - Wrap each field in a container with class "form-group" (or "form-check" / "input-group")
|
|
* - Input must have a "name" attribute matching the error key
|
|
* - Use "form-control" class on inputs for Bootstrap 5 styling
|
|
*
|
|
* Accepts three formats:
|
|
* - String: Single error shown as alert
|
|
* - Array of strings: Multiple errors shown as bulleted alert
|
|
* - Object: Field names mapped to errors, shown inline (unmatched shown as alert)
|
|
*
|
|
* @param {string} parent_selector - jQuery selector for parent element
|
|
* @param {string|Object|Array} errors - Error messages to display
|
|
* @returns {Promise} Promise that resolves when all animations complete
|
|
*/
|
|
static apply_form_errors(parent_selector, errors) {
|
|
console.error(errors);
|
|
const $parent = $(parent_selector);
|
|
|
|
// Reset the form errors before applying new ones
|
|
Form_Utils.reset_form_errors(parent_selector);
|
|
|
|
// Normalize input to standard format
|
|
const normalized = Form_Utils._normalize_errors(errors);
|
|
return new Promise(resolve => {
|
|
let animations = [];
|
|
if (normalized.type === 'string') {
|
|
// Single error message
|
|
animations = Form_Utils._apply_general_errors($parent, normalized.data);
|
|
} else if (normalized.type === 'array') {
|
|
// Array of error messages
|
|
const deduplicated = Form_Utils._deduplicate_errors(normalized.data);
|
|
animations = Form_Utils._apply_general_errors($parent, deduplicated);
|
|
} else if (normalized.type === 'fields') {
|
|
// Field-specific errors
|
|
const result = Form_Utils._apply_field_errors($parent, normalized.data);
|
|
animations = result.animations;
|
|
|
|
// Count matched fields
|
|
const matched_count = Object.keys(normalized.data).length - Object.keys(result.unmatched).length;
|
|
const unmatched_deduplicated = Form_Utils._deduplicate_errors(result.unmatched);
|
|
const unmatched_count = Object.keys(unmatched_deduplicated).length;
|
|
|
|
// Show summary alert if there are any field errors (matched or unmatched)
|
|
if (matched_count > 0 || unmatched_count > 0) {
|
|
// Build summary message
|
|
let summary_msg = '';
|
|
if (matched_count > 0) {
|
|
summary_msg = matched_count === 1 ? 'Please correct the error highlighted below.' : 'Please correct the errors highlighted below.';
|
|
}
|
|
|
|
// If there are unmatched errors, add them as a bulleted list
|
|
if (unmatched_count > 0) {
|
|
const summary_animations = Form_Utils._apply_combined_error($parent, summary_msg, unmatched_deduplicated);
|
|
animations.push(...summary_animations);
|
|
} else {
|
|
// Just the summary message, no unmatched errors
|
|
const summary_animations = Form_Utils._apply_general_errors($parent, summary_msg);
|
|
animations.push(...summary_animations);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Resolve the promise once all animations are complete
|
|
Promise.all(animations).then(() => {
|
|
// Scroll to error container if it exists
|
|
const $error_container = $parent.find('[data-id="error_container"]').first();
|
|
if ($error_container.length > 0) {
|
|
const container_top = $error_container.offset().top;
|
|
|
|
// Calculate fixed header offset
|
|
const fixed_header_height = Form_Utils._get_fixed_header_height();
|
|
|
|
// Scroll to position error container 20px below any fixed headers
|
|
const target_scroll = container_top - fixed_header_height - 20;
|
|
$('html, body').animate({
|
|
scrollTop: target_scroll
|
|
}, 500);
|
|
}
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Clears form validation errors and resets all form values to defaults
|
|
* @param {string|jQuery} form_selector - jQuery selector or jQuery object for form element
|
|
*/
|
|
static reset(form_selector) {
|
|
const $form = typeof form_selector === 'string' ? $(form_selector) : form_selector;
|
|
Form_Utils.reset_form_errors(form_selector);
|
|
$form.trigger('reset');
|
|
}
|
|
|
|
/**
|
|
* Serializes form data into key-value object
|
|
* Returns all input elements with name attributes as object properties
|
|
* @param {string|jQuery} form_selector - jQuery selector or jQuery object for form element
|
|
* @returns {Object} Form data as key-value pairs
|
|
*/
|
|
static serialize(form_selector) {
|
|
const $form = typeof form_selector === 'string' ? $(form_selector) : form_selector;
|
|
const data = {};
|
|
$form.serializeArray().forEach(item => {
|
|
data[item.name] = item.value;
|
|
});
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Submits form to RSX controller action via AJAX
|
|
* @param {string|jQuery} form_selector - jQuery selector or jQuery object for form element
|
|
* @param {string} controller - Controller class name (e.g., 'User_Controller')
|
|
* @param {string} action - Action method name (e.g., 'save_profile')
|
|
* @param {Object} options - Optional configuration {on_success: fn, on_error: fn}
|
|
* @returns {Promise} Promise that resolves with response data
|
|
*/
|
|
static async ajax_submit(form_selector, controller, action) {
|
|
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
const $form = typeof form_selector === 'string' ? $(form_selector) : form_selector;
|
|
const form_data = Form_Utils.serialize($form);
|
|
Form_Utils.reset_form_errors(form_selector);
|
|
try {
|
|
const response = await Ajax.call(controller, action, form_data);
|
|
if (options.on_success) {
|
|
options.on_success(response);
|
|
}
|
|
return response;
|
|
} catch (error) {
|
|
if (error.type === 'form_error' && error.details) {
|
|
await Form_Utils.apply_form_errors(form_selector, error.details);
|
|
} else {
|
|
await Form_Utils.apply_form_errors(form_selector, error.message || 'An error occurred');
|
|
}
|
|
if (options.on_error) {
|
|
options.on_error(error);
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes form validation errors
|
|
* @param {string} parent_selector - jQuery selector for parent element
|
|
*/
|
|
static reset_form_errors(parent_selector) {
|
|
const $parent = $(parent_selector);
|
|
|
|
// Remove flash messages
|
|
$('.flash-messages').remove();
|
|
|
|
// Remove alert-danger messages
|
|
$parent.find('.alert-danger').remove();
|
|
|
|
// Remove validation error classes and text from form elements
|
|
$parent.find('.is-invalid').removeClass('is-invalid');
|
|
$parent.find('.invalid-feedback').remove();
|
|
}
|
|
|
|
// ------------------------
|
|
|
|
/**
|
|
* Normalizes error input into standard formats
|
|
* @param {string|Object|Array} errors - Raw error input
|
|
* @returns {Object} Normalized errors as {type: 'string'|'array'|'fields', data: ...}
|
|
* @private
|
|
*/
|
|
static _normalize_errors(errors) {
|
|
// Handle null/undefined
|
|
if (!errors) {
|
|
return {
|
|
type: 'string',
|
|
data: 'An error has occurred'
|
|
};
|
|
}
|
|
|
|
// Handle string
|
|
if (typeof errors === 'string') {
|
|
return {
|
|
type: 'string',
|
|
data: errors
|
|
};
|
|
}
|
|
|
|
// Handle array
|
|
if (Array.isArray(errors)) {
|
|
// Array of strings - general errors
|
|
if (errors.every(e => typeof e === 'string')) {
|
|
return {
|
|
type: 'array',
|
|
data: errors
|
|
};
|
|
}
|
|
// Array with object as first element - extract it
|
|
if (errors.length > 0 && typeof errors[0] === 'object') {
|
|
return Form_Utils._normalize_errors(errors[0]);
|
|
}
|
|
// Empty or mixed array
|
|
return {
|
|
type: 'array',
|
|
data: []
|
|
};
|
|
}
|
|
|
|
// Handle object - check for Laravel response wrapper
|
|
if (typeof errors === 'object') {
|
|
// Unwrap {errors: {...}} or {error: {...}}
|
|
const unwrapped = errors.errors || errors.error;
|
|
if (unwrapped) {
|
|
return Form_Utils._normalize_errors(unwrapped);
|
|
}
|
|
|
|
// Convert Laravel validator format {field: [msg1, msg2]} to {field: msg1}
|
|
const normalized = {};
|
|
for (const field in errors) {
|
|
if (errors.hasOwnProperty(field)) {
|
|
const value = errors[field];
|
|
if (Array.isArray(value) && value.length > 0) {
|
|
normalized[field] = value[0];
|
|
} else if (typeof value === 'string') {
|
|
normalized[field] = value;
|
|
} else {
|
|
normalized[field] = String(value);
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
type: 'fields',
|
|
data: normalized
|
|
};
|
|
}
|
|
|
|
// Final catch-all*
|
|
return {
|
|
type: 'string',
|
|
data: String(errors)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Removes duplicate error messages from array or object values
|
|
* @param {Array|Object} errors - Errors to deduplicate
|
|
* @returns {Array|Object} Deduplicated errors
|
|
* @private
|
|
*/
|
|
static _deduplicate_errors(errors) {
|
|
if (Array.isArray(errors)) {
|
|
return [...new Set(errors)];
|
|
}
|
|
if (typeof errors === 'object') {
|
|
const seen = new Set();
|
|
const result = {};
|
|
for (const key in errors) {
|
|
const value = errors[key];
|
|
if (!seen.has(value)) {
|
|
seen.add(value);
|
|
result[key] = value;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
/**
|
|
* Applies field-specific validation errors to form inputs
|
|
* @param {jQuery} $parent - Parent element containing form
|
|
* @param {Object} field_errors - Object mapping field names to error messages
|
|
* @returns {Object} Object containing {animations: Array, unmatched: Object}
|
|
* @private
|
|
*/
|
|
static _apply_field_errors($parent, field_errors) {
|
|
const animations = [];
|
|
const unmatched = {};
|
|
for (const field_name in field_errors) {
|
|
const error_message = field_errors[field_name];
|
|
const $input = $parent.find(`[name="${field_name}"]`);
|
|
if (!$input.length) {
|
|
unmatched[field_name] = error_message;
|
|
continue;
|
|
}
|
|
const $error = $('<div class="invalid-feedback"></div>').html(error_message);
|
|
const $target = $input.closest('.form-group, .form-check, .input-group');
|
|
if (!$target.length) {
|
|
unmatched[field_name] = error_message;
|
|
continue;
|
|
}
|
|
$input.addClass('is-invalid');
|
|
$error.appendTo($target);
|
|
animations.push($error.hide().fadeIn(300).promise());
|
|
}
|
|
return {
|
|
animations,
|
|
unmatched
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Applies combined error message with summary and unmatched field errors
|
|
* @param {jQuery} $parent - Parent element containing form
|
|
* @param {string} summary_msg - Summary message (e.g., "Please correct the errors below")
|
|
* @param {Object} unmatched_errors - Object of field errors that couldn't be matched to fields
|
|
* @returns {Array} Array of animation promises
|
|
* @private
|
|
*/
|
|
static _apply_combined_error($parent, summary_msg, unmatched_errors) {
|
|
const animations = [];
|
|
const $error_container = $parent.find('[data-id="error_container"]').first();
|
|
const $target = $error_container.length > 0 ? $error_container : $parent;
|
|
|
|
// Create alert with summary message and bulleted list of unmatched errors
|
|
const $alert = $('<div class="alert alert-danger" role="alert"></div>');
|
|
|
|
// Add summary message if provided
|
|
if (summary_msg) {
|
|
$('<p class="mb-2"></p>').text(summary_msg).appendTo($alert);
|
|
}
|
|
|
|
// Add unmatched errors as bulleted list
|
|
if (Object.keys(unmatched_errors).length > 0) {
|
|
const $list = $('<ul class="mb-0"></ul>');
|
|
for (const field_name in unmatched_errors) {
|
|
const error_msg = unmatched_errors[field_name];
|
|
$('<li></li>').html(error_msg).appendTo($list);
|
|
}
|
|
$list.appendTo($alert);
|
|
}
|
|
if ($error_container.length > 0) {
|
|
animations.push($alert.hide().appendTo($target).fadeIn(300).promise());
|
|
} else {
|
|
animations.push($alert.hide().prependTo($target).fadeIn(300).promise());
|
|
}
|
|
return animations;
|
|
}
|
|
|
|
/**
|
|
* Applies general error messages as alert box
|
|
* @param {jQuery} $parent - Parent element to prepend alert to
|
|
* @param {string|Array} messages - Error message(s) to display
|
|
* @returns {Array} Array of animation promises
|
|
* @private
|
|
*/
|
|
static _apply_general_errors($parent, messages) {
|
|
const animations = [];
|
|
|
|
// Look for a specific error container div (e.g., in Rsx_Form component)
|
|
const $error_container = $parent.find('[data-id="error_container"]').first();
|
|
const $target = $error_container.length > 0 ? $error_container : $parent;
|
|
if (typeof messages === 'string') {
|
|
// Single error - simple alert without list
|
|
const $alert = $('<div class="alert alert-danger" role="alert"></div>').text(messages);
|
|
if ($error_container.length > 0) {
|
|
animations.push($alert.hide().appendTo($target).fadeIn(300).promise());
|
|
} else {
|
|
animations.push($alert.hide().prependTo($target).fadeIn(300).promise());
|
|
}
|
|
} else if (Array.isArray(messages) && messages.length > 0) {
|
|
// Multiple errors - bulleted list
|
|
const $alert = $('<div class="alert alert-danger" role="alert"><ul class="mb-0"></ul></div>');
|
|
const $list = $alert.find('ul');
|
|
messages.forEach(msg => {
|
|
const text = (msg + '').trim() || 'An error has occurred';
|
|
$('<li></li>').html(text).appendTo($list);
|
|
});
|
|
if ($error_container.length > 0) {
|
|
animations.push($alert.hide().appendTo($target).fadeIn(300).promise());
|
|
} else {
|
|
animations.push($alert.hide().prependTo($target).fadeIn(300).promise());
|
|
}
|
|
} else if (typeof messages === 'object' && !Array.isArray(messages)) {
|
|
// Object of unmatched field errors - convert to array
|
|
const error_list = Object.values(messages).map(v => String(v).trim()).filter(v => v);
|
|
if (error_list.length > 0) {
|
|
return Form_Utils._apply_general_errors($parent, error_list);
|
|
}
|
|
}
|
|
return animations;
|
|
}
|
|
|
|
/**
|
|
* Calculates the total height of fixed/sticky headers at the top of the page
|
|
* @returns {number} Total height in pixels of fixed top elements
|
|
* @private
|
|
*/
|
|
static _get_fixed_header_height() {
|
|
let total_height = 0;
|
|
|
|
// Find all fixed or sticky positioned elements
|
|
$('*').each(function () {
|
|
const $el = $(this);
|
|
const position = $el.css('position');
|
|
|
|
// Only check fixed or sticky elements
|
|
if (position !== 'fixed' && position !== 'sticky') {
|
|
return;
|
|
}
|
|
|
|
// Check if element is positioned at or near the top
|
|
const top = parseInt($el.css('top')) || 0;
|
|
if (top > 50) {
|
|
return; // Not a top header
|
|
}
|
|
|
|
// Check if element is visible
|
|
if (!$el.is(':visible')) {
|
|
return;
|
|
}
|
|
|
|
// Check if element spans significant width (likely a header/navbar)
|
|
const width = $el.outerWidth();
|
|
const viewport_width = $(window).width();
|
|
if (width < viewport_width * 0.5) {
|
|
return; // Too narrow to be a header
|
|
}
|
|
|
|
// Add this element's height
|
|
total_height += $el.outerHeight();
|
|
});
|
|
return total_height;
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Debugger.js (babel) === */
|
|
"use strict";
|
|
|
|
function _27e0e986_defineProperty(e, r, t) { return (r = _27e0e986_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
function _27e0e986_toPropertyKey(t) { var i = _27e0e986_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
function _27e0e986_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
/**
|
|
* Debugger class for console_debug and browser error logging
|
|
* Handles batched submission to server when configured
|
|
*/
|
|
class Debugger {
|
|
/**
|
|
* Initialize framework error handling
|
|
* Called during framework initialization
|
|
*/
|
|
static _on_framework_core_init() {
|
|
// Check if browser error logging is enabled
|
|
if (window.rsxapp && window.rsxapp.log_browser_errors) {
|
|
// Register global error handler
|
|
window.addEventListener('error', function (event) {
|
|
Debugger._handle_browser_error({
|
|
message: event.message,
|
|
filename: event.filename,
|
|
lineno: event.lineno,
|
|
colno: event.colno,
|
|
stack: event.error ? event.error.stack : null,
|
|
type: 'error'
|
|
});
|
|
});
|
|
|
|
// Register unhandled promise rejection handler
|
|
window.addEventListener('unhandledrejection', function (event) {
|
|
Debugger._handle_browser_error({
|
|
message: event.reason ? event.reason.message || String(event.reason) : 'Unhandled promise rejection',
|
|
stack: event.reason && event.reason.stack ? event.reason.stack : null,
|
|
type: 'unhandledrejection'
|
|
});
|
|
});
|
|
}
|
|
|
|
// Register ui refresh handler
|
|
Rsx.on('refresh', Debugger.on_refresh);
|
|
}
|
|
|
|
// In dev mode, some ui elements can be automatically applied to assist with development
|
|
static on_refresh() {
|
|
if (!Rsx.is_prod()) {
|
|
// Add an underline 2 px blue to all a tags with href === "#" using jquery
|
|
// Todo: maybe this should be a configurable debug option?
|
|
// $('a[href="#"]').css({
|
|
// 'border-bottom': '2px solid blue',
|
|
// 'text-decoration': 'none'
|
|
// });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* JavaScript implementation of console_debug
|
|
* Mirrors PHP functionality with batching for Laravel log
|
|
*/
|
|
static console_debug(channel) {
|
|
// Check if console_debug is enabled
|
|
if (!window.rsxapp || !window.rsxapp.console_debug || !window.rsxapp.console_debug.enabled) {
|
|
return;
|
|
}
|
|
const config = window.rsxapp.console_debug;
|
|
|
|
// Normalize channel name
|
|
channel = String(channel).toUpperCase().replace(/[\[\]]/g, '');
|
|
|
|
// Apply filtering
|
|
if (config.filter_mode === 'specific') {
|
|
const specific = config.specific_channel;
|
|
if (specific) {
|
|
// Split comma-separated values and normalize
|
|
const channels = specific.split(',').map(c => c.trim().toUpperCase());
|
|
if (!channels.includes(channel)) {
|
|
return;
|
|
}
|
|
}
|
|
} else if (config.filter_mode === 'whitelist') {
|
|
const whitelist = (config.filter_channels || []).map(c => c.toUpperCase());
|
|
if (!whitelist.includes(channel)) {
|
|
return;
|
|
}
|
|
} else if (config.filter_mode === 'blacklist') {
|
|
const blacklist = (config.filter_channels || []).map(c => c.toUpperCase());
|
|
if (blacklist.includes(channel)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Prepare the message
|
|
for (var _len = arguments.length, values = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
values[_key - 1] = arguments[_key];
|
|
}
|
|
let message = {
|
|
channel: channel,
|
|
values: values,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
|
|
// Add location if configured
|
|
if (config.include_location || config.include_backtrace) {
|
|
const error = new Error();
|
|
const stack = error.stack || '';
|
|
const stackLines = stack.split('\n');
|
|
if (config.include_location && stackLines.length > 2) {
|
|
// Skip Error line and this function
|
|
const callerLine = stackLines[2] || '';
|
|
const match = callerLine.match(/at\s+.*?\s+\((.*?):(\d+):(\d+)\)/) || callerLine.match(/at\s+(.*?):(\d+):(\d+)/);
|
|
if (match) {
|
|
message.location = `${match[1]}:${match[2]}`;
|
|
}
|
|
}
|
|
if (config.include_backtrace) {
|
|
// Include first 5 stack frames, skipping this function
|
|
message.backtrace = stackLines.slice(2, 7).map(line => line.trim()).filter(line => line);
|
|
}
|
|
}
|
|
|
|
// Output to browser console if enabled
|
|
if (config.outputs && config.outputs.browser) {
|
|
const prefix = config.include_benchmark ? `[${Debugger._get_time_prefix()}] ` : '';
|
|
const channelPrefix = `[${channel}]`;
|
|
|
|
// Use appropriate console method based on channel
|
|
let consoleMethod = 'log';
|
|
if (channel.includes('ERROR')) consoleMethod = 'error';else if (channel.includes('WARN')) consoleMethod = 'warn';else if (channel.includes('INFO')) consoleMethod = 'info';
|
|
console[consoleMethod](prefix + channelPrefix, ...values);
|
|
}
|
|
|
|
// Batch for Laravel log if enabled
|
|
if (config.outputs && config.outputs.laravel_log) {
|
|
Debugger._batch_console_message(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log an error to the server
|
|
* Used manually or by Ajax error handling
|
|
*/
|
|
static log_error(error) {
|
|
// Check if browser error logging is enabled
|
|
if (!window.rsxapp || !window.rsxapp.log_browser_errors) {
|
|
return;
|
|
}
|
|
|
|
// Normalize error format
|
|
let errorData = {};
|
|
if (typeof error === 'string') {
|
|
errorData.message = error;
|
|
errorData.type = 'manual';
|
|
} else if (error instanceof Error) {
|
|
errorData.message = error.message;
|
|
errorData.stack = error.stack;
|
|
errorData.type = 'exception';
|
|
} else if (error && typeof error === 'object') {
|
|
errorData = error;
|
|
if (!errorData.type) {
|
|
errorData.type = 'manual';
|
|
}
|
|
}
|
|
Debugger._handle_browser_error(errorData);
|
|
}
|
|
|
|
/**
|
|
* Internal: Handle browser errors with batching
|
|
*/
|
|
static _handle_browser_error(errorData) {
|
|
// Check limits
|
|
if (Debugger._error_count >= Debugger.MAX_ERRORS_PER_PAGE) {
|
|
return;
|
|
}
|
|
if (Debugger._error_batch_count >= Debugger.MAX_ERROR_BATCHES) {
|
|
return;
|
|
}
|
|
Debugger._error_count++;
|
|
|
|
// Add metadata
|
|
errorData.url = window.location.href;
|
|
errorData.userAgent = navigator.userAgent;
|
|
errorData.timestamp = new Date().toISOString();
|
|
|
|
// Add to batch
|
|
Debugger._error_batch.push(errorData);
|
|
|
|
// Clear existing timer
|
|
if (Debugger._error_timer) {
|
|
clearTimeout(Debugger._error_timer);
|
|
}
|
|
|
|
// Set debounce timer
|
|
Debugger._error_timer = setTimeout(() => {
|
|
Debugger._flush_error_batch();
|
|
}, Debugger.DEBOUNCE_MS);
|
|
}
|
|
|
|
/**
|
|
* Internal: Batch console_debug messages for Laravel log
|
|
*/
|
|
static _batch_console_message(message) {
|
|
Debugger._console_batch.push(message);
|
|
|
|
// Clear existing timer
|
|
if (Debugger._console_timer) {
|
|
clearTimeout(Debugger._console_timer);
|
|
}
|
|
|
|
// Set debounce timer
|
|
Debugger._console_timer = setTimeout(() => {
|
|
Debugger._flush_console_batch();
|
|
}, Debugger.DEBOUNCE_MS);
|
|
}
|
|
|
|
/**
|
|
* Internal: Flush console_debug batch to server
|
|
*/
|
|
static async _flush_console_batch() {
|
|
if (Debugger._console_batch.length === 0) {
|
|
return;
|
|
}
|
|
const messages = Debugger._console_batch;
|
|
Debugger._console_batch = [];
|
|
Debugger._console_timer = null;
|
|
try {
|
|
return Ajax.call(Rsx.Route('Debugger_Controller', 'log_console_messages'), {
|
|
messages: messages
|
|
});
|
|
} catch (error) {
|
|
// Silently fail - don't create error loop
|
|
console.error('Failed to send console_debug messages to server:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal: Flush error batch to server
|
|
*/
|
|
static async _flush_error_batch() {
|
|
if (Debugger._error_batch.length === 0) {
|
|
return;
|
|
}
|
|
const errors = Debugger._error_batch;
|
|
Debugger._error_batch = [];
|
|
Debugger._error_timer = null;
|
|
Debugger._error_batch_count++;
|
|
try {
|
|
return Ajax.call(Rsx.Route('Debugger_Controller', 'log_browser_errors'), {
|
|
errors: errors
|
|
});
|
|
} catch (error) {
|
|
// Silently fail - don't create error loop
|
|
console.error('Failed to send browser errors to server:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal: Get time prefix for benchmarking
|
|
*/
|
|
static _get_time_prefix() {
|
|
const now = Date.now();
|
|
if (!Debugger._start_time) {
|
|
Debugger._start_time = now;
|
|
}
|
|
const elapsed = now - Debugger._start_time;
|
|
return (elapsed / 1000).toFixed(3) + 's';
|
|
}
|
|
}
|
|
// Batching state for console_debug messages
|
|
_27e0e986_defineProperty(Debugger, "_console_batch", []);
|
|
_27e0e986_defineProperty(Debugger, "_console_timer", null);
|
|
_27e0e986_defineProperty(Debugger, "_console_batch_count", 0);
|
|
// Batching state for error messages
|
|
_27e0e986_defineProperty(Debugger, "_error_batch", []);
|
|
_27e0e986_defineProperty(Debugger, "_error_timer", null);
|
|
_27e0e986_defineProperty(Debugger, "_error_count", 0);
|
|
_27e0e986_defineProperty(Debugger, "_error_batch_count", 0);
|
|
// Constants
|
|
_27e0e986_defineProperty(Debugger, "DEBOUNCE_MS", 2000);
|
|
_27e0e986_defineProperty(Debugger, "MAX_ERRORS_PER_PAGE", 20);
|
|
_27e0e986_defineProperty(Debugger, "MAX_ERROR_BATCHES", 5);
|
|
// Store start time for benchmarking
|
|
_27e0e986_defineProperty(Debugger, "_start_time", null);
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Rsx_Jq_Helpers.js (babel) === */
|
|
"use strict";
|
|
|
|
// @JS-THIS-01-EXCEPTION
|
|
/**
|
|
* jQuery helper extensions for the RSX framework
|
|
* These extensions add utility methods to jQuery's prototype
|
|
* Note: 'this' references in jQuery extensions refer to jQuery objects by design
|
|
*/
|
|
class Rsx_Jq_Helpers {
|
|
/**
|
|
* Initialize jQuery extensions when the framework core is defined
|
|
* This method is called during framework initialization
|
|
*/
|
|
static _on_framework_core_define() {
|
|
// Returns true if jquery selector matched an element
|
|
$.fn.exists = function () {
|
|
return this.length > 0;
|
|
};
|
|
|
|
// Returns true if jquery element is visible
|
|
$.fn.is_visible = function () {
|
|
return this.is(':visible');
|
|
};
|
|
|
|
// Scrolls to the target element, only scrolls up. Todo: Create a version
|
|
// of this that also scrolls only down, or both
|
|
$.fn.scroll_up_to = function () {
|
|
let speed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
if (!this.exists()) {
|
|
// console.warn("Could not find target element to scroll to");
|
|
return;
|
|
}
|
|
if (!this.is_in_dom()) {
|
|
// console.warn("Target element for scroll is not on dom");
|
|
return;
|
|
}
|
|
let e_top = Math.round(this.offset().top);
|
|
let s_top = $('body').scrollTop();
|
|
if (e_top < 0) {
|
|
let target = s_top + e_top;
|
|
$('html, body').animate({
|
|
scrollTop: target
|
|
}, speed);
|
|
}
|
|
};
|
|
|
|
// $().is(":focus") - check if element has focus
|
|
$.expr[':'].focus = function (elem) {
|
|
return elem === document.activeElement && (elem.type || elem.href);
|
|
};
|
|
|
|
// Save native click behavior before override
|
|
$.fn._click_native = $.fn.click;
|
|
|
|
// Override .click() to call preventDefault by default
|
|
// This prevents accidental page navigation/form submission - the correct behavior 95% of the time
|
|
$.fn.click = function (handler) {
|
|
// If no handler provided, trigger click event (jQuery .click() with no args)
|
|
if (typeof handler === 'undefined') {
|
|
return this._click_native();
|
|
}
|
|
|
|
// Attach click handler with automatic preventDefault
|
|
return this.on('click', function (e) {
|
|
// Save original preventDefault
|
|
const original_preventDefault = e.preventDefault.bind(e);
|
|
|
|
// Override preventDefault to show warning when called explicitly
|
|
e.preventDefault = function () {
|
|
console.warn('event.preventDefault() is called automatically by RSpade .click() handlers and can be removed.');
|
|
return original_preventDefault();
|
|
};
|
|
|
|
// Call preventDefault before handler
|
|
original_preventDefault();
|
|
return handler.call(this, e);
|
|
});
|
|
};
|
|
|
|
// Escape hatch: click handler without preventDefault for the 5% case
|
|
$.fn.click_allow_default = function (handler) {
|
|
if (typeof handler === 'undefined') {
|
|
return this._click_native();
|
|
}
|
|
return this._click_native(handler);
|
|
};
|
|
|
|
// Returns true if the jquery element exists in and is attached to the DOM
|
|
$.fn.is_in_dom = function () {
|
|
let $element = this;
|
|
let _ancestor = function (HTMLobj) {
|
|
while (HTMLobj.parentElement) {
|
|
HTMLobj = HTMLobj.parentElement;
|
|
}
|
|
return HTMLobj;
|
|
};
|
|
return _ancestor($element[0]) === document.documentElement;
|
|
};
|
|
|
|
// Returns true if the element is visible in the viewport
|
|
$.fn.is_in_viewport = function () {
|
|
let scrolltop = $(window).scrollTop() > 0 ? $(window).scrollTop() : $('body').scrollTop();
|
|
let $element = this;
|
|
const top_of_element = $element.offset().top;
|
|
const bottom_of_element = $element.offset().top + $element.outerHeight();
|
|
const bottom_of_screen = scrolltop + $(window).innerHeight();
|
|
const top_of_screen = scrolltop;
|
|
if (bottom_of_screen > top_of_element && top_of_screen < bottom_of_element) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// Gets the tagname of a jquery element
|
|
$.fn.tagname = function () {
|
|
return this.prop('tagName').toLowerCase();
|
|
};
|
|
|
|
// Returns true if a href is not same domain
|
|
$.fn.is_external = function () {
|
|
const host = window.location.host;
|
|
const link = $('<a>', {
|
|
href: this.attr('href')
|
|
})[0].hostname;
|
|
return link !== host;
|
|
};
|
|
|
|
// HTML5 form validation wrappers
|
|
$.fn.checkValidity = function () {
|
|
if (this.length === 0) return false;
|
|
return this[0].checkValidity();
|
|
};
|
|
$.fn.reportValidity = function () {
|
|
if (this.length === 0) return false;
|
|
return this[0].reportValidity();
|
|
};
|
|
$.fn.requestSubmit = function () {
|
|
if (this.length === 0) return this;
|
|
this[0].requestSubmit();
|
|
return this;
|
|
};
|
|
|
|
// Find related components by searching up the ancestor tree
|
|
// Like .closest() but searches within ancestors instead of matching them
|
|
$.fn.closest_sibling = function (selector) {
|
|
let $current = this;
|
|
let $parent = $current.parent();
|
|
|
|
// Keep going up the tree until we hit body
|
|
while ($parent.length > 0 && !$parent.is('body')) {
|
|
// Search within this parent for the selector
|
|
let $found = $parent.find(selector);
|
|
if ($found.length > 0) {
|
|
return $found;
|
|
}
|
|
|
|
// Move up one level
|
|
$parent = $parent.parent();
|
|
}
|
|
|
|
// If we reached body, search within body as well
|
|
if ($parent.is('body')) {
|
|
let $found = $parent.find(selector);
|
|
if ($found.length > 0) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
// Return empty jQuery object if nothing found
|
|
return $();
|
|
};
|
|
|
|
// Override $.ajax to prevent direct AJAX calls to local server
|
|
// Developers must use the Ajax endpoint pattern: await Controller.method(params)
|
|
const native_ajax = $.ajax;
|
|
$.ajax = function (url, options) {
|
|
// Handle both $.ajax(url, options) and $.ajax(options) signatures
|
|
let settings;
|
|
if (typeof url === 'string') {
|
|
settings = options || {};
|
|
settings.url = url;
|
|
} else {
|
|
settings = url || {};
|
|
}
|
|
|
|
// Check if this is a local request (relative URL or same domain)
|
|
const request_url = settings.url || '';
|
|
const is_relative = !request_url.match(/^https?:\/\//);
|
|
const is_same_domain = request_url.startsWith(window.location.origin);
|
|
const is_local_request = is_relative || is_same_domain;
|
|
|
|
// Allow framework Ajax.call() to function
|
|
if (settings.__local_integration === true) {
|
|
return native_ajax.call(this, settings);
|
|
}
|
|
|
|
// Allow file upload endpoint - requires native $.ajax for FormData support
|
|
const is_file_upload = request_url === '/_upload' || request_url.endsWith('/_upload');
|
|
if (is_file_upload) {
|
|
return native_ajax.call(this, settings);
|
|
}
|
|
|
|
// Block local AJAX requests that don't use the Ajax endpoint pattern
|
|
if (is_local_request) {
|
|
// Try to parse controller and action from URL
|
|
let controller_name = null;
|
|
let action_name = null;
|
|
const url_match = request_url.match(/\/_rsx_api\/([^\/]+)\/([^\/\?]+)/);
|
|
if (url_match) {
|
|
controller_name = url_match[1];
|
|
action_name = url_match[2];
|
|
}
|
|
let error_message = 'AJAX requests to localhost via $.ajax() are prohibited.\n\n';
|
|
if (controller_name && action_name) {
|
|
error_message += `Instead of:\n`;
|
|
error_message += ` $.ajax({url: '${request_url}', ...})\n\n`;
|
|
error_message += `Use:\n`;
|
|
error_message += ` await ${controller_name}.${action_name}(parameters)\n\n`;
|
|
} else {
|
|
error_message += `Use the Ajax endpoint pattern:\n`;
|
|
error_message += ` await Controller_Name.action_name(parameters)\n\n`;
|
|
}
|
|
error_message += `The controller method must have the #[Ajax_Endpoint] attribute.`;
|
|
shouldnt_happen(error_message);
|
|
}
|
|
|
|
// Allow external requests (different domain)
|
|
return native_ajax.call(this, settings);
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Rsx.js (babel) === */
|
|
"use strict";
|
|
|
|
function _e8211f5b_defineProperty(e, r, t) { return (r = _e8211f5b_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
function _e8211f5b_toPropertyKey(t) { var i = _e8211f5b_toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
function _e8211f5b_toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
// @ROUTE-EXISTS-01-EXCEPTION - This file contains documentation examples with fictional route names
|
|
|
|
/**
|
|
* Rsx - Core JavaScript Runtime System
|
|
*
|
|
* The Rsx class is the central hub for the RSX JavaScript runtime, providing essential
|
|
* system-level utilities that all other framework components depend on. It serves as the
|
|
* foundation for the client-side framework, handling core operations that must be globally
|
|
* accessible and consistently available.
|
|
*
|
|
* Core Responsibilities:
|
|
* - Event System: Application-wide event bus for framework lifecycle and custom events
|
|
* - Environment Detection: Runtime environment identification (dev/production)
|
|
* - Route Management: Type-safe route generation and URL building
|
|
* - Unique ID Generation: Client-side unique identifier generation
|
|
* - Framework Bootstrap: Multi-phase initialization orchestration
|
|
* - Logging: Centralized logging interface (delegates to console_debug)
|
|
*
|
|
* The Rsx class deliberately keeps its scope limited to core utilities. Advanced features
|
|
* are delegated to specialized classes:
|
|
* - Manifest operations → Manifest class
|
|
* - Caching → Rsx_Cache class
|
|
* - AJAX/API calls → Ajax_* classes
|
|
* - Route proxies → Rsx_Route_Proxy class
|
|
* - Behaviors → Rsx_Behaviors class
|
|
*
|
|
* All methods are static - Rsx is never instantiated. It's available globally from the
|
|
* moment bundles load and remains constant throughout the application lifecycle.
|
|
*
|
|
* Usage Examples:
|
|
* ```javascript
|
|
* // Event system
|
|
* Rsx.on('app_ready', () => console.log('App initialized'));
|
|
* Rsx.trigger('custom_event', {data: 'value'});
|
|
*
|
|
* // Environment detection
|
|
* if (Rsx.is_dev()) { console.log('Development mode'); }
|
|
*
|
|
* // Route generation
|
|
* const url = Rsx.Route('Controller', 'action').url();
|
|
*
|
|
* // Unique IDs
|
|
* const uniqueId = Rsx.uid(); // e.g., "rsx_1234567890_1"
|
|
* ```
|
|
*
|
|
* @static
|
|
* @global
|
|
*/
|
|
class Rsx {
|
|
// Initialize event handlers storage
|
|
static _init_events() {
|
|
if (typeof Rsx._event_handlers === 'undefined') {
|
|
Rsx._event_handlers = {};
|
|
}
|
|
if (typeof Rsx._triggered_events === 'undefined') {
|
|
Rsx._triggered_events = {};
|
|
}
|
|
}
|
|
|
|
// Register an event handler
|
|
static on(event, callback) {
|
|
Rsx._init_events();
|
|
if (typeof callback !== 'function') {
|
|
throw new Error('Callback must be a function');
|
|
}
|
|
if (!Rsx._event_handlers[event]) {
|
|
Rsx._event_handlers[event] = [];
|
|
}
|
|
Rsx._event_handlers[event].push(callback);
|
|
|
|
// If this event was already triggered, call the callback immediately
|
|
if (Rsx._triggered_events[event]) {
|
|
console_debug('RSX_INIT', 'Triggering ' + event + ' for late registered callback');
|
|
callback(Rsx._triggered_events[event]);
|
|
}
|
|
}
|
|
|
|
// Trigger an event with optional data
|
|
static trigger(event) {
|
|
let data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
Rsx._init_events();
|
|
|
|
// Record that this event was triggered
|
|
Rsx._triggered_events[event] = data;
|
|
if (!Rsx._event_handlers[event]) {
|
|
return;
|
|
}
|
|
console_debug('RSX_INIT', 'Triggering ' + event + ' for ' + Rsx._event_handlers[event].length + ' callbacks');
|
|
|
|
// Call all registered handlers for this event in order
|
|
for (const callback of Rsx._event_handlers[event]) {
|
|
callback(data);
|
|
}
|
|
}
|
|
|
|
// Alias for trigger.refresh(''), should be called after major UI updates to apply such effects as
|
|
// underlining links to unimplemented # routes
|
|
static trigger_refresh() {
|
|
// Use Rsx.on('refresh', callback); to register a callback for refresh
|
|
this.trigger('refresh');
|
|
}
|
|
|
|
// Log to server that an event happened
|
|
static log(type) {
|
|
let message = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'notice';
|
|
Core_Log.log(type, message);
|
|
}
|
|
|
|
// Returns true if the app is being run in dev mode
|
|
// This should affect caching and some debug checks
|
|
static is_dev() {
|
|
return window.rsxapp.debug;
|
|
}
|
|
static is_prod() {
|
|
return !window.rsxapp.debug;
|
|
}
|
|
|
|
// Generates a unique number for the application instance
|
|
static uid() {
|
|
if (typeof Rsx._uid == undef) {
|
|
Rsx._uid = 0;
|
|
}
|
|
return Rsx._uid++;
|
|
}
|
|
|
|
// Storage for route definitions loaded from bundles
|
|
|
|
/**
|
|
* Define routes from bundled data
|
|
* Called by generated JavaScript in bundles
|
|
*/
|
|
static _define_routes(routes) {
|
|
// Merge routes into the global route storage
|
|
for (const class_name in routes) {
|
|
if (!Rsx._routes[class_name]) {
|
|
Rsx._routes[class_name] = {};
|
|
}
|
|
for (const method_name in routes[class_name]) {
|
|
Rsx._routes[class_name][method_name] = routes[class_name][method_name];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate URL for a controller route
|
|
*
|
|
* This method generates URLs for controller actions by looking up route patterns
|
|
* and replacing parameters. It handles both regular routes and Ajax endpoints.
|
|
*
|
|
* If the route is not found in the route definitions, a default pattern is used:
|
|
* `/_/{controller}/{action}` with all parameters appended as query strings.
|
|
*
|
|
* Usage examples:
|
|
* ```javascript
|
|
* // Simple route without parameters (defaults to 'index' action)
|
|
* const url = Rsx.Route('Frontend_Index_Controller');
|
|
* // Returns: /dashboard
|
|
*
|
|
* // Route with explicit action
|
|
* const url = Rsx.Route('Frontend_Index_Controller', 'index');
|
|
* // Returns: /dashboard
|
|
*
|
|
* // Route with integer parameter (sets 'id')
|
|
* const url = Rsx.Route('Frontend_Client_View_Controller', 'view', 123);
|
|
* // Returns: /clients/view/123
|
|
*
|
|
* // Route with named parameters (object)
|
|
* const url = Rsx.Route('Frontend_Client_View_Controller', 'view', {id: 'C001'});
|
|
* // Returns: /clients/view/C001
|
|
*
|
|
* // Route with required and query parameters
|
|
* const url = Rsx.Route('Frontend_Client_View_Controller', 'view', {
|
|
* id: 'C001',
|
|
* tab: 'history'
|
|
* });
|
|
* // Returns: /clients/view/C001?tab=history
|
|
*
|
|
* // Route not found - uses default pattern
|
|
* const url = Rsx.Route('Unimplemented_Controller', 'some_action', {foo: 'bar'});
|
|
* // Returns: /_/Unimplemented_Controller/some_action?foo=bar
|
|
*
|
|
* // Placeholder route
|
|
* const url = Rsx.Route('Future_Controller', '#index');
|
|
* // Returns: #
|
|
* ```
|
|
*
|
|
* @param {string} class_name The controller class name (e.g., 'User_Controller')
|
|
* @param {string} [action_name='index'] The action/method name (defaults to 'index'). Use '#action' for placeholders.
|
|
* @param {number|Object} [params=null] Route parameters. Integer sets 'id', object provides named params.
|
|
* @returns {string} The generated URL
|
|
*/
|
|
static Route(class_name) {
|
|
let action_name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'index';
|
|
let params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
// Normalize params to object
|
|
let params_obj = {};
|
|
if (typeof params === 'number') {
|
|
params_obj = {
|
|
id: params
|
|
};
|
|
} else if (params && typeof params === 'object') {
|
|
params_obj = params;
|
|
} else if (params !== null && params !== undefined) {
|
|
throw new Error('Params must be number, object, or null');
|
|
}
|
|
|
|
// Placeholder route: action starts with # means unimplemented/scaffolding
|
|
if (action_name.startsWith('#')) {
|
|
return '#';
|
|
}
|
|
|
|
// Check if route exists in definitions
|
|
let pattern;
|
|
if (Rsx._routes[class_name] && Rsx._routes[class_name][action_name]) {
|
|
pattern = Rsx._routes[class_name][action_name];
|
|
} else {
|
|
// Route not found - use default pattern /_/{controller}/{action}
|
|
pattern = `/_/${class_name}/${action_name}`;
|
|
}
|
|
|
|
// Generate URL from pattern
|
|
return Rsx._generate_url_from_pattern(pattern, params_obj);
|
|
}
|
|
|
|
/**
|
|
* Generate URL from route pattern by replacing parameters
|
|
*
|
|
* @param {string} pattern The route pattern (e.g., '/users/:id/view')
|
|
* @param {Object} params Parameters to fill into the route
|
|
* @returns {string} The generated URL
|
|
*/
|
|
static _generate_url_from_pattern(pattern, params) {
|
|
// Extract required parameters from the pattern
|
|
const required_params = [];
|
|
const matches = pattern.match(/:([a-zA-Z_][a-zA-Z0-9_]*)/g);
|
|
if (matches) {
|
|
// Remove the : prefix from each match
|
|
for (const match of matches) {
|
|
required_params.push(match.substring(1));
|
|
}
|
|
}
|
|
|
|
// Check for required parameters
|
|
const missing = [];
|
|
for (const required of required_params) {
|
|
if (!(required in params)) {
|
|
missing.push(required);
|
|
}
|
|
}
|
|
if (missing.length > 0) {
|
|
throw new Error(`Required parameters [${missing.join(', ')}] are missing for route ${pattern}`);
|
|
}
|
|
|
|
// Build the URL by replacing parameters
|
|
let url = pattern;
|
|
const used_params = {};
|
|
for (const param_name of required_params) {
|
|
const value = params[param_name];
|
|
// URL encode the value
|
|
const encoded_value = encodeURIComponent(value);
|
|
url = url.replace(':' + param_name, encoded_value);
|
|
used_params[param_name] = true;
|
|
}
|
|
|
|
// Collect any extra parameters for query string
|
|
const query_params = {};
|
|
for (const key in params) {
|
|
if (!used_params[key]) {
|
|
query_params[key] = params[key];
|
|
}
|
|
}
|
|
|
|
// Append query string if there are extra parameters
|
|
if (Object.keys(query_params).length > 0) {
|
|
const query_string = Object.entries(query_params).map(_ref => {
|
|
let [key, value] = _ref;
|
|
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
}).join('&');
|
|
url += '?' + query_string;
|
|
}
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* Internal: Call a specific method on all classes that have it
|
|
* Collects promises from return values and waits for all to resolve
|
|
* @param {string} method_name The method name to call on all classes
|
|
* @returns {Promise} Promise that resolves when all method calls complete
|
|
*/
|
|
static async _rsx_call_all_classes(method_name) {
|
|
const all_classes = Manifest.get_all_classes();
|
|
const classes_with_method = [];
|
|
const promise_pile = [];
|
|
for (const class_info of all_classes) {
|
|
const class_object = class_info.class_object;
|
|
const class_name = class_info.class_name;
|
|
|
|
// Check if this class has the method (static methods are on the class itself)
|
|
if (typeof class_object[method_name] === 'function') {
|
|
classes_with_method.push(class_name);
|
|
const return_value = await class_object[method_name]();
|
|
|
|
// Collect promises from return value
|
|
if (return_value instanceof Promise) {
|
|
promise_pile.push(return_value);
|
|
} else if (Array.isArray(return_value)) {
|
|
for (const item of return_value) {
|
|
if (item instanceof Promise) {
|
|
promise_pile.push(item);
|
|
}
|
|
}
|
|
}
|
|
if (Rsx.__stopped) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (classes_with_method.length > 0) {
|
|
console_debug('RSX_INIT', `${method_name}: ${classes_with_method.length} classes`);
|
|
}
|
|
|
|
// Await all promises before returning
|
|
if (promise_pile.length > 0) {
|
|
console_debug('RSX_INIT', `${method_name}: Awaiting ${promise_pile.length} promises`);
|
|
await Promise.all(promise_pile);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal: Execute multi-phase initialization for all registered classes
|
|
* This runs various initialization phases in order to properly set up the application
|
|
* @returns {Promise} Promise that resolves when all initialization phases complete
|
|
*/
|
|
static async _rsx_core_boot() {
|
|
if (Rsx.__booted) {
|
|
console.error('Rsx._rsx_core_boot called more than once');
|
|
return;
|
|
}
|
|
Rsx.__booted = true;
|
|
|
|
// Get all registered classes from the manifest
|
|
const all_classes = Manifest.get_all_classes();
|
|
console_debug('RSX_INIT', `Starting _rsx_core_boot with ${all_classes.length} classes`);
|
|
if (!all_classes || all_classes.length === 0) {
|
|
// No classes to initialize
|
|
shouldnt_happen('No classes registered in js - there should be at least the core framework classes');
|
|
return;
|
|
}
|
|
|
|
// Define initialization phases in order
|
|
const phases = [{
|
|
event: 'framework_core_define',
|
|
method: '_on_framework_core_define'
|
|
}, {
|
|
event: 'framework_modules_define',
|
|
method: '_on_framework_modules_define'
|
|
}, {
|
|
event: 'framework_core_init',
|
|
method: '_on_framework_core_init'
|
|
}, {
|
|
event: 'app_modules_define',
|
|
method: 'on_app_modules_define'
|
|
}, {
|
|
event: 'app_define',
|
|
method: 'on_app_define'
|
|
}, {
|
|
event: 'framework_modules_init',
|
|
method: '_on_framework_modules_init'
|
|
}, {
|
|
event: 'app_modules_init',
|
|
method: 'on_app_modules_init'
|
|
}, {
|
|
event: 'app_init',
|
|
method: 'on_app_init'
|
|
}, {
|
|
event: 'app_ready',
|
|
method: 'on_app_ready'
|
|
}];
|
|
|
|
// Execute each phase in order
|
|
for (const phase of phases) {
|
|
await Rsx._rsx_call_all_classes(phase.method);
|
|
if (Rsx.__stopped) {
|
|
return;
|
|
}
|
|
Rsx.trigger(phase.event);
|
|
}
|
|
|
|
// Ui refresh callbacks
|
|
Rsx.trigger_refresh();
|
|
|
|
// All phases complete
|
|
console_debug('RSX_INIT', 'Initialization complete');
|
|
|
|
// TODO: Find a good wait to wait for all jqhtml components to load, then trigger on_ready and on('ready') emulating the top level last syntax that jqhtml components operateas, but as a standard js class (such as a page class). The biggest question is, how do we efficiently choose only the top level jqhtml components. do we only consider components cretaed directly on blade templates? that seams reasonable...
|
|
|
|
// Trigger _debug_ready event - this is ONLY for tooling like rsx:debug
|
|
// DO NOT use this in application code - use on_app_ready() phase instead
|
|
// This event exists solely for debugging tools that need to run after full initialization
|
|
Rsx.trigger('_debug_ready');
|
|
}
|
|
|
|
/* Calling this stops the boot process. */
|
|
static async _rsx_core_boot_stop(reason) {
|
|
console.error(reason);
|
|
Rsx.__stopped = true;
|
|
}
|
|
|
|
/**
|
|
* Parse URL hash into key-value object
|
|
* Handles format: #key=value&key2=value2
|
|
*
|
|
* @returns {Object} Parsed hash parameters
|
|
*/
|
|
static _parse_hash() {
|
|
const hash = window.location.hash;
|
|
if (!hash || hash === '#') {
|
|
return {};
|
|
}
|
|
|
|
// Remove leading # and parse as query string
|
|
const hash_string = hash.substring(1);
|
|
const params = {};
|
|
const pairs = hash_string.split('&');
|
|
for (const pair of pairs) {
|
|
const [key, value] = pair.split('=');
|
|
if (key) {
|
|
params[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';
|
|
}
|
|
}
|
|
return params;
|
|
}
|
|
|
|
/**
|
|
* Serialize object into URL hash format
|
|
* Produces format: #key=value&key2=value2
|
|
*
|
|
* @param {Object} params Key-value pairs to encode
|
|
* @returns {string} Encoded hash string (with leading #, or empty string)
|
|
*/
|
|
static _serialize_hash(params) {
|
|
const pairs = [];
|
|
for (const key in params) {
|
|
const value = params[key];
|
|
if (value !== null && value !== undefined && value !== '') {
|
|
pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
|
|
}
|
|
}
|
|
return pairs.length > 0 ? '#' + pairs.join('&') : '';
|
|
}
|
|
|
|
/**
|
|
* Get all page state from URL hash
|
|
*
|
|
* Usage:
|
|
* ```javascript
|
|
* const state = Rsx.get_all_page_state();
|
|
* // Returns: {dg_page: '2', dg_sort: 'name'}
|
|
* ```
|
|
*
|
|
* @returns {Object} All hash parameters as key-value pairs
|
|
*/
|
|
static get_all_page_state() {
|
|
return Rsx._parse_hash();
|
|
}
|
|
|
|
/**
|
|
* Get single value from URL hash state
|
|
*
|
|
* Usage:
|
|
* ```javascript
|
|
* const page = Rsx.get_page_state('dg_page');
|
|
* // Returns: '2' or null if not set
|
|
* ```
|
|
*
|
|
* @param {string} key The key to retrieve
|
|
* @returns {string|null} The value or null if not found
|
|
*/
|
|
static get_page_state(key) {
|
|
var _state$key;
|
|
const state = Rsx._parse_hash();
|
|
return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
|
|
}
|
|
|
|
/**
|
|
* Set single value in URL hash state (replaces history, doesn't add)
|
|
*
|
|
* Usage:
|
|
* ```javascript
|
|
* Rsx.set_page_state('dg_page', 2);
|
|
* // URL becomes: http://example.com/page#dg_page=2
|
|
*
|
|
* Rsx.set_page_state('dg_page', null); // Remove key
|
|
* ```
|
|
*
|
|
* @param {string} key The key to set
|
|
* @param {string|number|null} value The value (null/empty removes the key)
|
|
*/
|
|
static set_page_state(key, value) {
|
|
const state = Rsx._parse_hash();
|
|
|
|
// Update or remove the key
|
|
if (value === null || value === undefined || value === '') {
|
|
delete state[key];
|
|
} else {
|
|
state[key] = String(value);
|
|
}
|
|
|
|
// Update URL without adding history
|
|
const new_hash = Rsx._serialize_hash(state);
|
|
const url = window.location.pathname + window.location.search + new_hash;
|
|
history.replaceState(null, '', url);
|
|
}
|
|
|
|
/**
|
|
* Set multiple values in URL hash state at once
|
|
*
|
|
* Usage:
|
|
* ```javascript
|
|
* Rsx.set_all_page_state({dg_page: 2, dg_sort: 'name'});
|
|
* // URL becomes: http://example.com/page#dg_page=2&dg_sort=name
|
|
* ```
|
|
*
|
|
* @param {Object} new_state Object with key-value pairs to set
|
|
*/
|
|
static set_all_page_state(new_state) {
|
|
const state = Rsx._parse_hash();
|
|
|
|
// Merge new state
|
|
for (const key in new_state) {
|
|
const value = new_state[key];
|
|
if (value === null || value === undefined || value === '') {
|
|
delete state[key];
|
|
} else {
|
|
state[key] = String(value);
|
|
}
|
|
}
|
|
|
|
// Update URL without adding history
|
|
const new_hash = Rsx._serialize_hash(state);
|
|
const url = window.location.pathname + window.location.search + new_hash;
|
|
history.replaceState(null, '', url);
|
|
}
|
|
|
|
/**
|
|
* Render an error in a DOM element
|
|
*
|
|
* Displays errors from Ajax calls in a standardized format. Handles different
|
|
* error types (fatal, validation, auth, generic) with appropriate formatting.
|
|
*
|
|
* Usage:
|
|
* ```javascript
|
|
* try {
|
|
* const result = await Controller.method();
|
|
* } catch (error) {
|
|
* Rsx.render_error(error, '#error_container');
|
|
* }
|
|
* ```
|
|
*
|
|
* @param {Error|Object} error - Error object from Ajax call
|
|
* @param {jQuery|string} container - jQuery element or selector for error display
|
|
*/
|
|
static render_error(error, container) {
|
|
const $container = $(container);
|
|
if (!$container.exists()) {
|
|
console.error('Rsx.render_error: Container not found', container);
|
|
return;
|
|
}
|
|
|
|
// Clear existing content
|
|
$container.empty();
|
|
let html = '';
|
|
|
|
// Handle different error types
|
|
if (error.type === 'fatal' && error.details) {
|
|
// Fatal PHP error with file/line/error
|
|
const details = error.details;
|
|
const file = details.file || 'Unknown file';
|
|
const line = details.line || '?';
|
|
const message = details.error || error.message || 'Fatal error occurred';
|
|
html = `
|
|
<div class="alert alert-danger" role="alert">
|
|
<h5>Uncaught Fatal Error in ${file}:${line}:</h5>
|
|
<p class="mb-0">${Rsx._escape_html(message)}</p>
|
|
</div>
|
|
`;
|
|
} else if (error.type === 'form_error' && error.details) {
|
|
// Validation errors - show unmatched errors only
|
|
// (matched errors should be handled by Form_Utils.apply_form_errors)
|
|
const errors = error.details;
|
|
const error_list = [];
|
|
for (const field in errors) {
|
|
error_list.push(errors[field]);
|
|
}
|
|
if (error_list.length > 0) {
|
|
html = `
|
|
<div class="alert alert-warning" role="alert">
|
|
<h5>Validation Errors:</h5>
|
|
<ul class="mb-0">
|
|
${error_list.map(err => `<li>${Rsx._escape_html(err)}</li>`).join('')}
|
|
</ul>
|
|
</div>
|
|
`;
|
|
}
|
|
} else if (error.type === 'auth_required' || error.type === 'unauthorized') {
|
|
// Authentication/authorization errors
|
|
const message = error.message || 'Authentication required';
|
|
html = `
|
|
<div class="alert alert-warning" role="alert">
|
|
<p class="mb-0">${Rsx._escape_html(message)}</p>
|
|
</div>
|
|
`;
|
|
} else if (error.type === 'network') {
|
|
// Network errors
|
|
const message = error.message || 'Unable to reach server. Please check your connection.';
|
|
html = `
|
|
<div class="alert alert-danger" role="alert">
|
|
<p class="mb-0">${Rsx._escape_html(message)}</p>
|
|
</div>
|
|
`;
|
|
} else {
|
|
// Generic/unknown error
|
|
const message = error.message || error.toString() || 'An unknown error occurred';
|
|
html = `
|
|
<div class="alert alert-danger" role="alert">
|
|
<p class="mb-0">${Rsx._escape_html(message)}</p>
|
|
</div>
|
|
`;
|
|
}
|
|
$container.html(html);
|
|
}
|
|
|
|
/**
|
|
* Escape HTML to prevent XSS in error messages
|
|
* @private
|
|
*/
|
|
static _escape_html(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
}
|
|
// Gets set to true to interupt startup sequence
|
|
_e8211f5b_defineProperty(Rsx, "__stopped", false);
|
|
_e8211f5b_defineProperty(Rsx, "_routes", {});
|
|
|
|
|
|
/* === app/RSpade/Core/Js/Ajax.js (babel) === */
|
|
"use strict";
|
|
|
|
// @FILE-SUBCLASS-01-EXCEPTION
|
|
|
|
/**
|
|
* Client-side Ajax class for making API calls to RSX controllers
|
|
*
|
|
* Automatically batches multiple calls into single HTTP requests to reduce network overhead.
|
|
* Batches up to 20 calls or flushes after setTimeout(0) debounce.
|
|
*/
|
|
class Ajax {
|
|
/**
|
|
* Initialize Ajax system
|
|
* Called automatically when class is loaded
|
|
*/
|
|
static _on_framework_core_init() {
|
|
// Queue of pending calls waiting to be batched
|
|
Ajax._pending_calls = {};
|
|
|
|
// Timer for batching flush
|
|
Ajax._flush_timeout = null;
|
|
|
|
// Call counter for generating unique call IDs
|
|
Ajax._call_counter = 0;
|
|
|
|
// Maximum batch size before forcing immediate flush
|
|
Ajax.MAX_BATCH_SIZE = 20;
|
|
|
|
// Debounce time in milliseconds
|
|
Ajax.DEBOUNCE_MS = 0;
|
|
|
|
// Track promises from Ajax calls to detect uncaught rejections
|
|
Ajax._tracked_promises = new WeakSet();
|
|
|
|
// Set up global unhandled rejection handler for Ajax errors
|
|
window.addEventListener('unhandledrejection', async event => {
|
|
// Only handle rejections from Ajax promises
|
|
if (Ajax._tracked_promises.has(event.promise)) {
|
|
event.preventDefault(); // Prevent browser's default "Uncaught (in promise)" error
|
|
|
|
const error = event.reason;
|
|
console.error('Uncaught Ajax error:', error);
|
|
|
|
// Show Modal.error() for uncaught Ajax errors
|
|
if (typeof Modal !== 'undefined' && Modal.error) {
|
|
await Modal.error(error, 'Uncaught Ajax Error');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Make an AJAX call to an RSX controller action
|
|
*
|
|
* All calls are automatically batched unless window.rsxapp.ajax_disable_batching is true.
|
|
*
|
|
* @param {string|object|function} url - The Ajax URL (e.g., '/_ajax/Controller_Name/action_name') or an object/function with a .path property
|
|
* @param {object} params - Parameters to send to the action
|
|
* @returns {Promise} - Resolves with the return value, rejects with error
|
|
*/
|
|
static async call(url) {
|
|
let params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
// If url is an object or function with a .path property, use that as the URL
|
|
if (url && typeof url === 'object' && url.path) {
|
|
url = url.path;
|
|
} else if (url && typeof url === 'function' && url.path) {
|
|
url = url.path;
|
|
}
|
|
|
|
// Validate url is a non-empty string
|
|
if (typeof url !== 'string' || url.length === 0) {
|
|
throw new Error('Ajax.call() requires a non-empty string URL or an object/function with a .path property');
|
|
}
|
|
|
|
// Extract controller and action from URL
|
|
const {
|
|
controller,
|
|
action
|
|
} = Ajax.ajax_url_to_controller_action(url);
|
|
console.log('Ajax:', controller, action, params);
|
|
|
|
// Check if batching is disabled for debugging
|
|
let promise;
|
|
if (window.rsxapp && window.rsxapp.ajax_disable_batching) {
|
|
promise = Ajax._call_direct(controller, action, params);
|
|
} else {
|
|
promise = Ajax._call_batch(controller, action, params);
|
|
}
|
|
|
|
// Track this promise for unhandled rejection detection
|
|
Ajax._tracked_promises.add(promise);
|
|
return promise;
|
|
}
|
|
|
|
/**
|
|
* Make a batched Ajax call
|
|
* @private
|
|
*/
|
|
static _call_batch(controller, action) {
|
|
let params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
console.log('Ajax Batch:', controller, action, params);
|
|
return new Promise((resolve, reject) => {
|
|
// Generate call key for deduplication
|
|
const call_key = Ajax._generate_call_key(controller, action, params);
|
|
|
|
// Check if this exact call is already pending
|
|
if (Ajax._pending_calls[call_key]) {
|
|
const existing_call = Ajax._pending_calls[call_key];
|
|
|
|
// If call already completed (cached), return immediately
|
|
if (existing_call.is_complete) {
|
|
if (existing_call.is_error) {
|
|
reject(existing_call.error);
|
|
} else {
|
|
resolve(existing_call.result);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Call is pending, add this promise to callbacks
|
|
existing_call.callbacks.push({
|
|
resolve,
|
|
reject
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Create new pending call
|
|
const call_id = Ajax._call_counter++;
|
|
const pending_call = {
|
|
call_id: call_id,
|
|
call_key: call_key,
|
|
controller: controller,
|
|
action: action,
|
|
params: params,
|
|
callbacks: [{
|
|
resolve,
|
|
reject
|
|
}],
|
|
is_complete: false,
|
|
is_error: false,
|
|
result: null,
|
|
error: null
|
|
};
|
|
|
|
// Add to pending queue
|
|
Ajax._pending_calls[call_key] = pending_call;
|
|
|
|
// Count pending calls
|
|
const pending_count = Object.keys(Ajax._pending_calls).filter(key => !Ajax._pending_calls[key].is_complete).length;
|
|
|
|
// If we've hit the batch size limit, flush immediately
|
|
if (pending_count >= Ajax.MAX_BATCH_SIZE) {
|
|
clearTimeout(Ajax._flush_timeout);
|
|
Ajax._flush_timeout = null;
|
|
Ajax._flush_pending_calls();
|
|
} else {
|
|
// Schedule batch flush with debounce
|
|
clearTimeout(Ajax._flush_timeout);
|
|
Ajax._flush_timeout = setTimeout(() => {
|
|
Ajax._flush_pending_calls();
|
|
}, Ajax.DEBOUNCE_MS);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Make a direct (non-batched) Ajax call
|
|
* @private
|
|
*/
|
|
static async _call_direct(controller, action) {
|
|
let params = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
// Construct URL from controller and action
|
|
const url = `/_ajax/${controller}/${action}`;
|
|
|
|
// Log the AJAX call using console_debug
|
|
if (typeof Debugger !== 'undefined' && Debugger.console_debug) {
|
|
Debugger.console_debug('AJAX', `Calling ${controller}.${action} (unbatched)`, params);
|
|
}
|
|
return new Promise((resolve, reject) => {
|
|
$.ajax({
|
|
url: url,
|
|
method: 'POST',
|
|
data: params,
|
|
dataType: 'json',
|
|
__local_integration: true,
|
|
// Bypass $.ajax override
|
|
success: response => {
|
|
// Handle console_debug messages
|
|
if (response.console_debug && Array.isArray(response.console_debug)) {
|
|
response.console_debug.forEach(msg => {
|
|
if (!Array.isArray(msg) || msg.length !== 2) {
|
|
throw new Error('Invalid console_debug message format - expected [channel, [arguments]]');
|
|
}
|
|
const [channel, args] = msg;
|
|
console.log(channel, ...args);
|
|
});
|
|
}
|
|
|
|
// Check if the response was successful
|
|
if (response._success === true) {
|
|
// @JS-AJAX-02-EXCEPTION - Unwrap server responses with _ajax_return_value
|
|
const processed_value = Rsx_Js_Model._instantiate_models_recursive(response._ajax_return_value);
|
|
resolve(processed_value);
|
|
} else {
|
|
// Handle error responses
|
|
const error_type = response.error_type || 'unknown_error';
|
|
const reason = response.reason || 'Unknown error occurred';
|
|
const details = response.details || {};
|
|
|
|
// Handle specific error types
|
|
switch (error_type) {
|
|
case 'fatal':
|
|
// Fatal PHP error with full error details
|
|
const fatal_error_data = response.error || {};
|
|
const error_message = fatal_error_data.error || 'Fatal error occurred';
|
|
console.error('Ajax error response from server:', response.error);
|
|
const fatal_error = new Error(error_message);
|
|
fatal_error.type = 'fatal';
|
|
fatal_error.details = response.error;
|
|
|
|
// Log to server if browser error logging is enabled
|
|
Debugger.log_error({
|
|
message: `Ajax Fatal Error: ${error_message}`,
|
|
type: 'ajax_fatal',
|
|
endpoint: url,
|
|
details: response.error
|
|
});
|
|
reject(fatal_error);
|
|
break;
|
|
case 'response_auth_required':
|
|
console.error('The user is no longer authenticated, this is a placeholder for future code which handles this scenario.');
|
|
const auth_error = new Error(reason);
|
|
auth_error.type = 'auth_required';
|
|
auth_error.details = details;
|
|
reject(auth_error);
|
|
break;
|
|
case 'response_unauthorized':
|
|
console.error('The user is unauthorized to perform this action, this is a placeholder for future code which handles this scenario.');
|
|
const unauth_error = new Error(reason);
|
|
unauth_error.type = 'unauthorized';
|
|
unauth_error.details = details;
|
|
reject(unauth_error);
|
|
break;
|
|
case 'response_form_error':
|
|
const form_error = new Error(reason);
|
|
form_error.type = 'form_error';
|
|
form_error.details = details;
|
|
reject(form_error);
|
|
break;
|
|
default:
|
|
const generic_error = new Error(reason);
|
|
generic_error.type = error_type;
|
|
generic_error.details = details;
|
|
reject(generic_error);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
error: (xhr, status, error) => {
|
|
const error_message = Ajax._extract_error_message(xhr);
|
|
const network_error = new Error(error_message);
|
|
network_error.type = 'network_error';
|
|
network_error.status = xhr.status;
|
|
network_error.statusText = status;
|
|
|
|
// Log server errors (500+) to the server if browser error logging is enabled
|
|
if (xhr.status >= 500) {
|
|
Debugger.log_error({
|
|
message: `Ajax Server Error ${xhr.status}: ${error_message}`,
|
|
type: 'ajax_server_error',
|
|
endpoint: url,
|
|
status: xhr.status,
|
|
statusText: status
|
|
});
|
|
}
|
|
reject(network_error);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Flush all pending calls by sending batch request
|
|
* @private
|
|
*/
|
|
static async _flush_pending_calls() {
|
|
// Collect all pending calls
|
|
const calls_to_send = [];
|
|
const call_map = {}; // Map call_id to pending_call object
|
|
|
|
for (const call_key in Ajax._pending_calls) {
|
|
const pending_call = Ajax._pending_calls[call_key];
|
|
if (!pending_call.is_complete) {
|
|
calls_to_send.push({
|
|
call_id: pending_call.call_id,
|
|
controller: pending_call.controller,
|
|
action: pending_call.action,
|
|
params: pending_call.params
|
|
});
|
|
call_map[pending_call.call_id] = pending_call;
|
|
}
|
|
}
|
|
|
|
// Nothing to send
|
|
if (calls_to_send.length === 0) {
|
|
return;
|
|
}
|
|
|
|
// Log batch for debugging
|
|
if (typeof Debugger !== 'undefined' && Debugger.console_debug) {
|
|
Debugger.console_debug('AJAX_BATCH', `Sending batch of ${calls_to_send.length} calls`, calls_to_send.map(c => `${c.controller}.${c.action}`));
|
|
}
|
|
try {
|
|
// Send batch request
|
|
const response = await $.ajax({
|
|
url: '/_ajax/_batch',
|
|
method: 'POST',
|
|
data: {
|
|
batch_calls: JSON.stringify(calls_to_send)
|
|
},
|
|
dataType: 'json',
|
|
__local_integration: true // Bypass $.ajax override
|
|
});
|
|
|
|
// Process batch response
|
|
// Response format: { C_0: {success, _ajax_return_value}, C_1: {...}, ... }
|
|
for (const response_key in response) {
|
|
if (!response_key.startsWith('C_')) {
|
|
continue;
|
|
}
|
|
const call_id = parseInt(response_key.substring(2), 10);
|
|
const call_response = response[response_key];
|
|
const pending_call = call_map[call_id];
|
|
if (!pending_call) {
|
|
console.error('Received response for unknown call_id:', call_id);
|
|
continue;
|
|
}
|
|
|
|
// Handle console_debug messages if present
|
|
if (call_response.console_debug && Array.isArray(call_response.console_debug)) {
|
|
call_response.console_debug.forEach(msg => {
|
|
if (!Array.isArray(msg) || msg.length !== 2) {
|
|
throw new Error('Invalid console_debug message format - expected [channel, [arguments]]');
|
|
}
|
|
const [channel, args] = msg;
|
|
console.log(channel, ...args);
|
|
});
|
|
}
|
|
|
|
// Mark call as complete
|
|
pending_call.is_complete = true;
|
|
|
|
// Check if successful
|
|
if (call_response._success === true) {
|
|
// @JS-AJAX-02-EXCEPTION - Batch system unwraps server responses with _ajax_return_value
|
|
const processed_value = Rsx_Js_Model._instantiate_models_recursive(call_response._ajax_return_value);
|
|
pending_call.result = processed_value;
|
|
|
|
// Resolve all callbacks
|
|
pending_call.callbacks.forEach(_ref => {
|
|
let {
|
|
resolve
|
|
} = _ref;
|
|
resolve(processed_value);
|
|
});
|
|
} else {
|
|
// Handle error
|
|
const error_type = call_response.error_type || 'unknown_error';
|
|
let error_message;
|
|
let error_details;
|
|
if (error_type === 'fatal' && call_response.error) {
|
|
// Fatal PHP error with full error details
|
|
const fatal_error_data = call_response.error;
|
|
error_message = fatal_error_data.error || 'Fatal error occurred';
|
|
error_details = call_response.error;
|
|
console.error('Ajax error response from server:', call_response.error);
|
|
} else {
|
|
// Other error types
|
|
error_message = call_response.reason || 'Unknown error occurred';
|
|
error_details = call_response.details || {};
|
|
}
|
|
const error = new Error(error_message);
|
|
error.type = error_type;
|
|
error.details = error_details;
|
|
pending_call.is_error = true;
|
|
pending_call.error = error;
|
|
|
|
// Reject all callbacks
|
|
pending_call.callbacks.forEach(_ref2 => {
|
|
let {
|
|
reject
|
|
} = _ref2;
|
|
reject(error);
|
|
});
|
|
}
|
|
}
|
|
} catch (xhr_error) {
|
|
// Network or server error - reject all pending calls
|
|
const error_message = Ajax._extract_error_message(xhr_error);
|
|
const error = new Error(error_message);
|
|
error.type = 'network_error';
|
|
for (const call_id in call_map) {
|
|
const pending_call = call_map[call_id];
|
|
pending_call.is_complete = true;
|
|
pending_call.is_error = true;
|
|
pending_call.error = error;
|
|
pending_call.callbacks.forEach(_ref3 => {
|
|
let {
|
|
reject
|
|
} = _ref3;
|
|
reject(error);
|
|
});
|
|
}
|
|
console.error('Batch Ajax request failed:', error_message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate a unique key for deduplicating calls
|
|
* @private
|
|
*/
|
|
static _generate_call_key(controller, action, params) {
|
|
// Create a stable string representation of the call
|
|
// Sort params keys for consistent hashing
|
|
const sorted_params = {};
|
|
Object.keys(params).sort().forEach(key => {
|
|
sorted_params[key] = params[key];
|
|
});
|
|
return `${controller}::${action}::${JSON.stringify(sorted_params)}`;
|
|
}
|
|
|
|
/**
|
|
* Extract error message from jQuery XHR object
|
|
* @private
|
|
*/
|
|
static _extract_error_message(xhr) {
|
|
if (xhr.responseJSON && xhr.responseJSON.message) {
|
|
return xhr.responseJSON.message;
|
|
} else if (xhr.responseText) {
|
|
try {
|
|
const response = JSON.parse(xhr.responseText);
|
|
if (response.message) {
|
|
return response.message;
|
|
}
|
|
} catch (e) {
|
|
// Not JSON
|
|
}
|
|
}
|
|
return `${xhr.status}: ${xhr.statusText || 'Unknown error'}`;
|
|
}
|
|
|
|
/**
|
|
* Parses an AJAX URL into controller and action
|
|
* Supports both /_ajax/ and /_/ URL prefixes
|
|
* @param {string|object|function} url - URL in format '/_ajax/Controller_Name/action_name' or '/_/Controller_Name/action_name', or an object/function with a .path property
|
|
* @returns {Object} Object with {controller: string, action: string}
|
|
* @throws {Error} If URL doesn't start with /_ajax or /_ or has invalid structure
|
|
*/
|
|
static ajax_url_to_controller_action(url) {
|
|
// If url is an object or function with a .path property, use that as the URL
|
|
if (url && typeof url === 'object' && url.path) {
|
|
url = url.path;
|
|
} else if (url && typeof url === 'function' && url.path) {
|
|
url = url.path;
|
|
}
|
|
|
|
// Validate url is a string
|
|
if (typeof url !== 'string') {
|
|
throw new Error(`URL must be a string or have a .path property, got: ${typeof url}`);
|
|
}
|
|
if (!url.startsWith('/_ajax') && !url.startsWith('/_/')) {
|
|
throw new Error(`URL must start with /_ajax or /_, got: ${url}`);
|
|
}
|
|
const parts = url.split('/').filter(part => part !== '');
|
|
if (parts.length < 2) {
|
|
throw new Error(`Invalid AJAX URL structure: ${url}`);
|
|
}
|
|
if (parts.length > 3) {
|
|
throw new Error(`AJAX URL has too many segments: ${url}`);
|
|
}
|
|
const controller = parts[1];
|
|
const action = parts[2] || 'index';
|
|
return {
|
|
controller,
|
|
action
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Auto-initialize static properties when class is first loaded
|
|
*/
|
|
static on_core_define() {
|
|
Ajax._on_framework_core_init();
|
|
}
|
|
}
|
|
|
|
|
|
/* === app/RSpade/Integrations/Jqhtml/Component.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* Component - Base class for JQHTML components in RSX framework
|
|
*
|
|
* This class wraps the jqhtml.Component from the npm package and provides
|
|
* the standard interface for RSX components following the Upper_Case naming convention.
|
|
*
|
|
* _Base_Jqhtml_Component is imported from npm via Jqhtml_Bundle.
|
|
*
|
|
* @Instantiatable
|
|
*/
|
|
class Component extends _Base_Jqhtml_Component {}
|
|
|
|
// RSX manifest automatically makes classes global - no manual assignment needed
|
|
|
|
|
|
/* === app/RSpade/Integrations/Jqhtml/Jqhtml_Integration.js (babel) === */
|
|
"use strict";
|
|
|
|
/**
|
|
* JQHTML Integration - Automatic component registration and binding
|
|
*
|
|
* This module automatically:
|
|
* 1. Registers component classes that extend Component
|
|
* 2. Binds templates to component classes when names match
|
|
* 3. Enables $(selector).component("Component_Name") syntax
|
|
*/
|
|
class Jqhtml_Integration {
|
|
/**
|
|
* Compiled Jqhtml templates self-register. The developer (the framework in this case) is still
|
|
* responsible for registering es6 component classes with jqhtml. This does so at an early stage
|
|
* of framework init.
|
|
*/
|
|
static _on_framework_modules_define() {
|
|
let jqhtml_components = Manifest.get_extending('Component');
|
|
console_debug('JQHTML_INIT', 'Registering ' + jqhtml_components.length + ' Jqhtml Components');
|
|
for (let component of jqhtml_components) {
|
|
jqhtml.register_component(component.class_name, component.class_object);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Framework modules init phase - Bind components and initialize DOM
|
|
* This runs after templates are registered to bind component classes
|
|
* @param {jQuery} [$scope] Optional scope to search within (defaults to body)
|
|
* @returns {Array<Promise>|undefined} Array of promises for recursive calls, undefined for top-level
|
|
*/
|
|
static _on_framework_modules_init($scope) {
|
|
const is_top_level = !$scope;
|
|
const promises = [];
|
|
const components_needing_init = ($scope || $('body')).find('.Component_Init');
|
|
if (components_needing_init.length > 0) {
|
|
console_debug('JQHTML_INIT', `Initializing ${components_needing_init.length} DOM components`);
|
|
}
|
|
components_needing_init.each(function () {
|
|
const $element = $(this);
|
|
|
|
// Skip if element is no longer attached to the document
|
|
// (may have been removed by a parent component's .empty() call)
|
|
if (!document.contains($element[0])) {
|
|
return;
|
|
}
|
|
|
|
// Check if any parent has Component_Init class - skip nested components
|
|
let parent = $element[0].parentElement;
|
|
while (parent) {
|
|
if (parent.classList.contains('Component_Init')) {
|
|
return; // Skip this element, it's nested
|
|
}
|
|
parent = parent.parentElement;
|
|
}
|
|
const component_name = $element.attr('data-component-init-name');
|
|
|
|
// jQuery's .data() doesn't auto-parse JSON - we need to parse it manually
|
|
let component_args = {};
|
|
const args_string = $element.attr('data-component-args');
|
|
|
|
// Unset component- php side initialization args, it is no longer needed as a compionent attribute
|
|
// Unsetting also prevents undesired access to this code in other parts of the program, prevening an
|
|
// unwanted future dependency on this paradigm
|
|
$element.removeAttr('data-component-init-name');
|
|
$element.removeAttr('data-component-args');
|
|
$element.removeData('component-init-name');
|
|
$element.removeData('component-args');
|
|
if (args_string) {
|
|
try {
|
|
component_args = JSON.parse(args_string);
|
|
} catch (e) {
|
|
console.error(`[JQHTML Integration] Failed to parse component args for ${component_name}:`, e);
|
|
component_args = {};
|
|
}
|
|
}
|
|
if (component_name) {
|
|
// Transform $ prefixed keys to data- attributes
|
|
let component_args_filtered = {};
|
|
for (const [key, value] of Object.entries(component_args)) {
|
|
// if (key.startsWith('$')) {
|
|
// component_args_filtered[key.substring(1)] = value;
|
|
// } else
|
|
if (key.startsWith('data-')) {
|
|
component_args_filtered[key.substring(5)] = value;
|
|
} else {
|
|
component_args_filtered[key] = value;
|
|
}
|
|
}
|
|
try {
|
|
// Store inner HTML as string for nested component processing
|
|
component_args_filtered._inner_html = $element.html();
|
|
$element.empty();
|
|
|
|
// Remove the init class before instantiation to prevent re-initialization
|
|
$element.removeClass('Component_Init');
|
|
|
|
// Create promise for this component's initialization
|
|
const component_promise = new Promise(resolve => {
|
|
// Use jQuery component plugin to create the component
|
|
// Plugin handles element internally, just pass args
|
|
// Get the updated $element from
|
|
let component = $element.component(component_name, component_args_filtered);
|
|
component.on('render', function () {
|
|
// Recursively collect promises from nested components
|
|
|
|
// Getting the updated component here - if the tag name was not div, the element would have been recreated, so we need to get the element set on the component, not from our earlier selector
|
|
|
|
const nested_promises = Jqhtml_Integration._on_framework_modules_init(component.$);
|
|
promises.push(...nested_promises);
|
|
|
|
// Resolve this component's promise
|
|
resolve();
|
|
}).$;
|
|
});
|
|
promises.push(component_promise);
|
|
} catch (error) {
|
|
console.error(`[JQHTML Integration] Failed to initialize component ${component_name}:`, error);
|
|
console.error('Error details:', error.stack || error);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Top-level call: spawn async handler to wait for all promises, then trigger event
|
|
if (is_top_level) {
|
|
(async () => {
|
|
await Promise.all(promises);
|
|
await Rsx._rsx_call_all_classes('on_jqhtml_ready');
|
|
Rsx.trigger('jqhtml_ready');
|
|
})();
|
|
return;
|
|
}
|
|
|
|
// Recursive call: return promises for parent to collect
|
|
return promises;
|
|
}
|
|
|
|
/**
|
|
* Get all registered component names
|
|
* @returns {Array<string>} Array of component names
|
|
*/
|
|
static get_component_names() {
|
|
return jqhtml.get_component_names();
|
|
}
|
|
|
|
/**
|
|
* Check if a component is registered
|
|
* @param {string} name Component name
|
|
* @returns {boolean} True if component is registered
|
|
*/
|
|
static has_component(name) {
|
|
return jqhtml.has_component(name);
|
|
}
|
|
}
|
|
|
|
// RSX manifest automatically makes classes global - no manual assignment needed
|
|
|
|
|
|
/* === storage/rsx-tmp/bundle_Bootstrap5_Bundle_57b2a356.js === */
|
|
// JavaScript Manifest - Generated by BundleCompiler
|
|
// Registers all classes in this bundle for runtime introspection
|
|
Manifest._define([
|
|
[Manifest, "Manifest", null],
|
|
[Rsx_Behaviors, "Rsx_Behaviors", null],
|
|
[Rsx_Cache, "Rsx_Cache", null],
|
|
[Rsx_Init, "Rsx_Init", null],
|
|
[Rsx_Js_Model, "Rsx_Js_Model", null],
|
|
[Rsx_View_Transitions, "Rsx_View_Transitions", null],
|
|
[ReadWriteLock, "ReadWriteLock", null],
|
|
[Form_Utils, "Form_Utils", null],
|
|
[Debugger, "Debugger", null],
|
|
[Rsx_Jq_Helpers, "Rsx_Jq_Helpers", null],
|
|
[Rsx, "Rsx", null],
|
|
[Ajax, "Ajax", null],
|
|
[Component, "Component", _Base_Jqhtml_Component],
|
|
[Jqhtml_Integration, "Jqhtml_Integration", null]
|
|
]);
|
|
|
|
|
|
|
|
/* === storage/rsx-tmp/bundle_Bootstrap5_Bundle_e83e43d3.js === */
|
|
$(document).ready(async function() {
|
|
try {
|
|
console_debug('RSX_INIT', 'Document ready, starting Rsx._rsx_core_boot');
|
|
await Rsx._rsx_core_boot();
|
|
console_debug('RSX_INIT', 'Initialization complete');
|
|
} catch (error) {
|
|
console.error('[RSX_INIT] Initialization failed:', error);
|
|
console.error('[RSX_INIT] Stack:', error.stack);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0b3JhZ2UvcnN4LXRtcC9ucG1faW1wb3J0X2RlY2xhcmF0aW9uc185NWE2ZjYwMmM5ODAzNzYxMWI2NDBiMGI1MzQyODMwYi5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9kZWNvcmF0b3IuanMiLCJhcHAvUlNwYWRlL0NvcmUvSnMvYnJvd3Nlci5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9kYXRldGltZS5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9lcnJvci5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9oYXNoLmpzIiwiYXBwL1JTcGFkZS9Db3JlL0pzL011dGV4LmpzIiwiYXBwL1JTcGFkZS9Db3JlL0pzL2FzeW5jLmpzIiwiYXBwL1JTcGFkZS9Db3JlL0pzL2Z1bmN0aW9ucy5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9NYW5pZmVzdC5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9Sc3hfQmVoYXZpb3JzLmpzIiwiYXBwL1JTcGFkZS9Db3JlL0pzL1JzeF9DYWNoZS5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9Sc3hfSW5pdC5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9Sc3hfSnNfTW9kZWwuanMiLCJhcHAvUlNwYWRlL0NvcmUvSnMvUnN4X1ZpZXdfVHJhbnNpdGlvbnMuanMiLCJhcHAvUlNwYWRlL0NvcmUvSnMvUmVhZFdyaXRlTG9jay5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9Gb3JtX1V0aWxzLmpzIiwiYXBwL1JTcGFkZS9Db3JlL0pzL0RlYnVnZ2VyLmpzIiwiYXBwL1JTcGFkZS9Db3JlL0pzL1JzeF9KcV9IZWxwZXJzLmpzIiwiYXBwL1JTcGFkZS9Db3JlL0pzL1JzeC5qcyIsImFwcC9SU3BhZGUvQ29yZS9Kcy9BamF4LmpzIiwiYXBwL1JTcGFkZS9JbnRlZ3JhdGlvbnMvSnFodG1sL0pxaHRtbF9Db21wb25lbnQuanMiLCJhcHAvUlNwYWRlL0ludGVncmF0aW9ucy9KcWh0bWwvSnFodG1sX0ludGVncmF0aW9uLmpzIiwic3RvcmFnZS9yc3gtdG1wL2J1bmRsZV9Cb290c3RyYXA1X0J1bmRsZV81N2IyYTM1Ni5qcyIsInN0b3JhZ2UvcnN4LXRtcC9idW5kbGVfQm9vdHN0cmFwNV9CdW5kbGVfZTgzZTQzZDMuanMiXSwibmFtZXMiOlsiZGVjb3JhdG9yIiwidmFsdWUiLCJpc19tb2JpbGUiLCJ0ZXN0IiwibmF2aWdhdG9yIiwidXNlckFnZW50IiwiJCIsIndpbmRvdyIsIndpZHRoIiwiaXNfZGVza3RvcCIsImdldF9vcyIsInVzZXJfYWdlbnQiLCJwbGF0Zm9ybSIsIm1hY29zX3BsYXRmb3JtcyIsIndpbmRvd3NfcGxhdGZvcm1zIiwiaW9zX3BsYXRmb3JtcyIsIm9zIiwiaXNfbW9iaWxlX2RldmljZSIsImluZGV4T2YiLCJpc19jcmF3bGVyIiwiYm90X3BhdHRlcm4iLCJzY3JvbGxfaW50b192aWV3X2lmX25lZWRlZCIsInRhcmdldCIsIiR0YXJnZXQiLCIkcGFyZW50IiwicGFyZW50IiwidGFyZ2V0X3RvcCIsInBvc2l0aW9uIiwidG9wIiwic2Nyb2xsVG9wIiwidGFyZ2V0X2hlaWdodCIsIm91dGVySGVpZ2h0IiwicGFyZW50X2hlaWdodCIsImhlaWdodCIsInNjcm9sbF9wb3NpdGlvbiIsIkRlYnVnZ2VyIiwiY29uc29sZV9kZWJ1ZyIsIm5ld19zY3JvbGxfcG9zaXRpb24iLCJNYXRoIiwibWF4IiwibWluIiwic2Nyb2xsSGVpZ2h0Iiwic2Nyb2xsX3BhZ2VfaW50b192aWV3X2lmX25lZWRlZCIsIm9mZnNldCIsIndpbmRvd19oZWlnaHQiLCJ3aW5kb3dfc2Nyb2xsX3Bvc2l0aW9uIiwiYW5pbWF0ZSIsIndhaXRfZm9yX2ltYWdlcyIsImNhbGxiYWNrIiwiJGltYWdlcyIsInRvdGFsX2ltYWdlcyIsImxlbmd0aCIsImltYWdlc19sb2FkZWQiLCJlYWNoIiwiaW1nIiwiSW1hZ2UiLCJvbmxvYWQiLCJvbmVycm9yIiwic3JjIiwiJG5ic3AiLCJlc2NhcGVfanFfc2VsZWN0b3IiLCJpZCIsInJlcGxhY2UiLCJ1bml4X3RpbWUiLCJyb3VuZCIsIkRhdGUiLCJnZXRUaW1lIiwieW1kaGlzX3RvX3VuaXgiLCJzdHJfZGF0ZSIsImRhdGUiLCJlcnJvciIsInN0ciIsImVycm9yX2NvZGUiLCJ1bmRlZiIsInN0YXR1cyIsInNob3VsZG50X2hhcHBlbiIsIm1lc3NhZ2UiLCJhcmd1bWVudHMiLCJ1bmRlZmluZWQiLCJFcnJvciIsInN0YWNrIiwic3RhY2tMaW5lcyIsInNwbGl0IiwiY2FsbGVySW5mbyIsImNhbGxlckxpbmUiLCJtYXRjaCIsImVycm9yTWVzc2FnZSIsImNvbnNvbGUiLCJyZXBlYXQiLCJmYXRhbEVycm9yIiwibmFtZSIsImhhc2giLCJ0aGVfdmFyIiwiY2FsY19zaGExIiwiaWdub3JlZF9rZXlzIiwianNvbl9zdHJpbmdpZnlfbm9jaXJjIiwiY2FjaGUiLCJKU09OIiwic3RyaW5naWZ5Iiwia2V5IiwidiIsIl9jYWNoZV9rZXkiLCJfaGFzaF9rZXkiLCJwdXNoIiwiZmxhdF92YXIiLCJfZmxhdHRlbiIsInByZWZpeCIsImRlcHRoIiwiaXNfb2JqZWN0IiwiQWJzdHJhY3QiLCJrIiwiaGFzT3duUHJvcGVydHkiLCJpc19hcnJheSIsImkiLCJmb3JlYWNoIiwiaXNfZnVuY3Rpb24iLCJpc19udW1lcmljIiwiU3RyaW5nIiwic29ydGVyIiwic29ydCIsImEiLCJiIiwianNvbiIsImhhc2hlZCIsInNoYTEiLCJkZWVwX2VxdWFsIiwibXV0ZXgiLCJnbG9iYWxfaWQiLCJpbnN0YW5jZV9tdXRleGVzIiwiX2luc3RhbmNlX3N0b3JhZ2UiLCJXZWFrTWFwIiwiZ2xvYmFsX211dGV4ZXMiLCJfZ2xvYmFsX3N0b3JhZ2UiLCJNYXAiLCJnZXRfaW5zdGFuY2VfbXV0ZXgiLCJpbnN0YW5jZSIsIm1ldGhvZF9uYW1lIiwiaW5zdGFuY2VfbG9ja3MiLCJnZXQiLCJzZXQiLCJsb2NrX3N0YXRlIiwiYWN0aXZlIiwicXVldWUiLCJnZXRfZ2xvYmFsX211dGV4Iiwic2NoZWR1bGVfbmV4dCIsImZuIiwicmVzb2x2ZSIsInJlamVjdCIsInNoaWZ0IiwiUHJvbWlzZSIsInRoZW4iLCJmaW5hbGx5IiwiYWNxdWlyZV9sb2NrIiwiZGVzY3JpcHRvciIsIm9yaWdpbmFsX21ldGhvZCIsIl9sZW4iLCJhcmdzIiwiQXJyYXkiLCJfa2V5IiwiYXBwbHkiLCJfbGVuMiIsIl9rZXkyIiwic2xlZXAiLCJtaWxsaXNlY29uZHMiLCJyZXF1ZXN0QW5pbWF0aW9uRnJhbWUiLCJzZXRUaW1lb3V0IiwiZGVib3VuY2UiLCJjYWxsYmFja19vcl9kZWxheSIsImRlbGF5IiwiaW1tZWRpYXRlIiwiZGVjb3JhdG9yX2RlbGF5IiwiZGVjb3JhdG9yX2ltbWVkaWF0ZSIsImNvbnRleHQiLCJraW5kIiwiZGVib3VuY2VfaW1wbCIsInJ1bm5pbmciLCJxdWV1ZWQiLCJsYXN0X2VuZF90aW1lIiwidGltZXIiLCJuZXh0X2FyZ3MiLCJuZXh0X2NvbnRleHQiLCJyZXNvbHZlX3F1ZXVlIiwicmVqZWN0X3F1ZXVlIiwicnVuX2Z1bmN0aW9uIiwidGhlc2VfcmVzb2x2ZXMiLCJ0aGVzZV9yZWplY3RzIiwicmVzdWx0IiwiZXJyIiwibm93IiwiY2xlYXJUaW1lb3V0IiwiZmlyc3RfY2FsbCIsInNpbmNlIiwiSW5maW5pdHkiLCJ3YWl0Iiwicndsb2NrIiwiY2IiLCJSZWFkV3JpdGVMb2NrIiwiYWNxdWlyZSIsInJ3bG9ja19yZWFkIiwiYWNxdWlyZV9yZWFkIiwicndsb2NrX2ZvcmNlX3VubG9jayIsImZvcmNlX3VubG9jayIsInJ3bG9ja19wZW5kaW5nIiwicGVuZGluZyIsIm9iaiIsInJlc3VsdHMiLCJpc0FycmF5IiwiZm9yRWFjaCIsImluZGV4IiwicHJvbWlzZXMiLCJmaWx0ZXIiLCJhbGwiLCJuIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiaXNGaW5pdGUiLCJpc19zdHJpbmciLCJzIiwiaXNfaW50ZWdlciIsIk51bWJlciIsImlzSW50ZWdlciIsImlzX3Byb21pc2UiLCJmdW5jdGlvbl90b19jaGVjayIsInRvU3RyaW5nIiwiY2FsbCIsImlzX2VtYWlsIiwiZW1haWwiLCJyZWdleCIsImlzc2V0IiwiZW1wdHkiLCJvYmplY3QiLCJmbG9hdCIsInZhbCIsInBhcnNlZCIsImludCIsInBhcnNlSW50IiwidmFsdWVfdW5sZXNzX251bWVyaWNfc3RyaW5nX3RoZW5fbnVtZXJpY192YWx1ZSIsImh0bWwiLCJfIiwiZXNjYXBlIiwibmwyYnIiLCJodG1sYnIiLCJ1cmxlbmNvZGUiLCJlbmNvZGVVUklDb21wb25lbnQiLCJ1cmxkZWNvZGUiLCJkZWNvZGVVUklDb21wb25lbnQiLCJqc29uX2VuY29kZSIsImpzb25fZGVjb2RlIiwicGFyc2UiLCJjaGFubmVsIiwidmFsdWVzIiwicmVwbGFjZV9hbGwiLCJzdHJpbmciLCJzZWFyY2giLCJqb2luIiwidWN3b3JkcyIsImlucHV0IiwibWFwIiwid29yZCIsImNoYXJBdCIsInRvVXBwZXJDYXNlIiwic2xpY2UiLCJjb3VudCIsIm8iLCJjIiwiY2xvbmUiLCJGdW5jdGlvbiIsInByb3RvdHlwZSIsIl9fY2xvbmUiLCJ0aGF0IiwidGVtcCIsImNsb25lZCIsImNvbnN0cnVjdG9yIiwiT2JqZWN0IiwiYXNzaWduIiwiY29hbGVzY2UiLCJmcm9tIiwicmV0dXJuX3ZhbCIsImFyZyIsImNzdl90b19hcnJheV90cmltIiwic3RyX2NzdiIsInBhcnRzIiwicmV0IiwicGFydCIsInRyaW0iLCJNYW5pZmVzdCIsIl9kZWZpbmUiLCJpdGVtcyIsIl9jbGFzc2VzIiwiaXRlbSIsImNsYXNzX29iamVjdCIsImNsYXNzX25hbWUiLCJjbGFzc19leHRlbmRzIiwiZGVjb3JhdG9ycyIsImNsYXNzIiwiZXh0ZW5kcyIsIl9uYW1lIiwiX2V4dGVuZHMiLCJfZGVjb3JhdG9ycyIsIl9idWlsZF9zdWJjbGFzc19pbmRleCIsIl9zdWJjbGFzc19pbmRleCIsImNsYXNzZGF0YSIsImN1cnJlbnRfY2xhc3NfbmFtZSIsImN1cnJlbnRfY2xhc3NkYXRhIiwiZXh0ZW5kc19uYW1lIiwiaW5jbHVkZXMiLCJnZXRfZXh0ZW5kaW5nIiwiYmFzZV9jbGFzcyIsImJhc2VfY2xhc3Nfb2JqZWN0IiwiZ2V0X2NsYXNzX2J5X25hbWUiLCJjbGFzc2VzIiwianNfaXNfc3ViY2xhc3Nfb2YiLCJsb2NhbGVDb21wYXJlIiwic3ViY2xhc3MiLCJzdXBlcmNsYXNzIiwic3ViY2xhc3Nfb2JqZWN0Iiwic3VwZXJjbGFzc19vYmplY3QiLCJjdXJyZW50X2NsYXNzIiwiZ2V0X2FsbF9jbGFzc2VzIiwiYnVpbGRfa2V5IiwicnN4YXBwIiwiZ2V0X2RlY29yYXRvcnMiLCJjbGFzc19pbmZvIiwiX3RyYW5zZm9ybV9kZWNvcmF0b3JzIiwiZ2V0X2FsbF9kZWNvcmF0b3JzIiwiY29tcGFjdF9kZWNvcmF0b3JzIiwiaGFzX2RlY29yYXRvciIsImRlY29yYXRvcl9uYW1lIiwic29tZSIsImQiLCJqc19nZXRfc3ViY2xhc3Nlc19vZiIsImJhc2VfY2xhc3NfbmFtZSIsInN1YmNsYXNzX25hbWVzIiwic3ViY2xhc3Nfb2JqZWN0cyIsInN1YmNsYXNzX25hbWUiLCJuYW1lX2EiLCJuYW1lX2IiLCJSc3hfQmVoYXZpb3JzIiwiX29uX2ZyYW1ld29ya19jb3JlX2luaXQiLCJfaW5pdF9pZ25vcmVfaW52YWxpZF9hbmNob3JfbGlua3MiLCJfdHJpbV9jb3BpZWRfdGV4dCIsImRvY3VtZW50Iiwib24iLCJlIiwiJGxpbmsiLCJocmVmIiwiYXR0ciIsImlzRGVmYXVsdFByZXZlbnRlZCIsImRhdGEiLCJwcmV2ZW50RGVmYXVsdCIsInN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbiIsInN0YXJ0c1dpdGgiLCJ0YXJnZXRJZCIsInN1YnN0cmluZyIsInRhcmdldEV4aXN0cyIsImdldEVsZW1lbnRCeUlkIiwicXVlcnlTZWxlY3RvciIsImFkZEV2ZW50TGlzdGVuZXIiLCJldmVudCIsInNoaWZ0S2V5Iiwic2VsZWN0aW9uIiwiZ2V0U2VsZWN0aW9uIiwic2VsZWN0ZWRfdGV4dCIsImNvbnRhaW5lciIsImdldFJhbmdlQXQiLCJjb21tb25BbmNlc3RvckNvbnRhaW5lciIsIm5vZGVUeXBlIiwicGFyZW50Tm9kZSIsImNsb3Nlc3QiLCJ0cmltbWVkX3RleHQiLCJjbGlwYm9hcmREYXRhIiwic2V0RGF0YSIsImxvZyIsIlJzeF9DYWNoZSIsIm9uX2NvcmVfZGVmaW5lIiwiQ29yZV9DYWNoZSIsIl9jYWNoZXMiLCJnbG9iYWwiLCJfY2FjaGVzX3NldCIsImdldF9pbnN0YW5jZSIsIk1haW4iLCJkZWJ1ZyIsImtleV9lbmNvZGVkIiwiX2VuY29kZWtleSIsImdldF9nbG9iYWwiLCJnZXRfc2Vzc2lvbiIsIl9zdXBwb3J0c1N0b3JhZ2UiLCJycyIsInNlc3Npb25TdG9yYWdlIiwiZ2V0SXRlbSIsInNldF9zZXNzaW9uIiwiX3RyeWFnYWluIiwicmVtb3ZlSXRlbSIsInNldEl0ZW0iLCJfaXNPdXRPZlNwYWNlIiwiY2xlYXIiLCJfcmVzZXQiLCJfX3N1cHBvcnRzU3RvcmFnZSIsImV4IiwiUnN4X0luaXQiLCJSc3giLCJpc19wcm9kIiwiX19lbnZpcm9ubWVudF9jaGVja3MiLCJzY3JpcHRzIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzY3JpcHQiLCJkZWZlciIsInJlYXNvbiIsIl9yc3hfY29yZV9ib290X3N0b3AiLCJSc3hfSnNfTW9kZWwiLCJfX01PREVMIiwibW9kZWxEYXRhIiwiZmV0Y2giLCJDdXJyZW50Q2xhc3MiLCJtb2RlbE5hbWUiLCJyZXNwb25zZSIsImFqYXgiLCJ1cmwiLCJtZXRob2QiLCJkYXRhVHlwZSIsIl9pbnN0YW50aWF0ZV9tb2RlbHNfcmVjdXJzaXZlIiwiZ2V0TW9kZWxOYW1lIiwicmVmcmVzaCIsImZyZXNoIiwidG9PYmplY3QiLCJ0b0pTT04iLCJNb2RlbENsYXNzIiwiUnN4X1ZpZXdfVHJhbnNpdGlvbnMiLCJzdGFydFZpZXdUcmFuc2l0aW9uIiwiX2luamVjdF90cmFuc2l0aW9uX2NzcyIsInN0eWxlIiwiY3JlYXRlRWxlbWVudCIsInRleHRDb250ZW50IiwiaGVhZCIsImFwcGVuZENoaWxkIiwiXzUwYWU2MDllX2Fzc2VydENsYXNzQnJhbmQiLCJfNTBhZTYwOWVfZ2V0X2xvY2siLCJ3cml0ZXJfcSIsIl81MGFlNjA5ZV9zY2hlZHVsZSIsIndyaXRlcl9hY3RpdmUiLCJyZWFkZXJfcSIsInJlYWRlcnMiLCJfbG9ja3MiLCJkZWxldGUiLCJfNTBhZTYwOWVfUmVhZFdyaXRlTG9jayIsImJhdGNoIiwic3BsaWNlIiwiRm9ybV9VdGlscyIsIl9vbl9mcmFtZXdvcmtfY29yZV9kZWZpbmUiLCJwYXJhbXMiLCJhamF4X3N1Ym1pdCIsIm9wdGlvbnMiLCIkZWxlbWVudCIsImlzIiwiY29udHJvbGxlciIsImFjdGlvbiIsIkFqYXgiLCJhamF4X3VybF90b19jb250cm9sbGVyX2FjdGlvbiIsImFwcGx5X2Zvcm1fZXJyb3JzIiwicGFyZW50X3NlbGVjdG9yIiwiZXJyb3JzIiwicmVzZXRfZm9ybV9lcnJvcnMiLCJub3JtYWxpemVkIiwiX25vcm1hbGl6ZV9lcnJvcnMiLCJhbmltYXRpb25zIiwidHlwZSIsIl9hcHBseV9nZW5lcmFsX2Vycm9ycyIsImRlZHVwbGljYXRlZCIsIl9kZWR1cGxpY2F0ZV9lcnJvcnMiLCJfYXBwbHlfZmllbGRfZXJyb3JzIiwibWF0Y2hlZF9jb3VudCIsImtleXMiLCJ1bm1hdGNoZWQiLCJ1bm1hdGNoZWRfZGVkdXBsaWNhdGVkIiwidW5tYXRjaGVkX2NvdW50Iiwic3VtbWFyeV9tc2ciLCJzdW1tYXJ5X2FuaW1hdGlvbnMiLCJfYXBwbHlfY29tYmluZWRfZXJyb3IiLCIkZXJyb3JfY29udGFpbmVyIiwiZmluZCIsImZpcnN0IiwiY29udGFpbmVyX3RvcCIsImZpeGVkX2hlYWRlcl9oZWlnaHQiLCJfZ2V0X2ZpeGVkX2hlYWRlcl9oZWlnaHQiLCJ0YXJnZXRfc2Nyb2xsIiwicmVzZXQiLCJmb3JtX3NlbGVjdG9yIiwiJGZvcm0iLCJ0cmlnZ2VyIiwic2VyaWFsaXplIiwic2VyaWFsaXplQXJyYXkiLCJmb3JtX2RhdGEiLCJvbl9zdWNjZXNzIiwiZGV0YWlscyIsIm9uX2Vycm9yIiwicmVtb3ZlIiwicmVtb3ZlQ2xhc3MiLCJldmVyeSIsInVud3JhcHBlZCIsImZpZWxkIiwiU2V0Iiwic2VlbiIsImhhcyIsImFkZCIsImZpZWxkX2Vycm9ycyIsImZpZWxkX25hbWUiLCJlcnJvcl9tZXNzYWdlIiwiJGlucHV0IiwiJGVycm9yIiwiYWRkQ2xhc3MiLCJhcHBlbmRUbyIsImhpZGUiLCJmYWRlSW4iLCJwcm9taXNlIiwidW5tYXRjaGVkX2Vycm9ycyIsIiRhbGVydCIsInRleHQiLCIkbGlzdCIsImVycm9yX21zZyIsInByZXBlbmRUbyIsIm1lc3NhZ2VzIiwibXNnIiwiZXJyb3JfbGlzdCIsInRvdGFsX2hlaWdodCIsIiRlbCIsImNzcyIsIm91dGVyV2lkdGgiLCJ2aWV3cG9ydF93aWR0aCIsImxvZ19icm93c2VyX2Vycm9ycyIsIl9oYW5kbGVfYnJvd3Nlcl9lcnJvciIsImZpbGVuYW1lIiwibGluZW5vIiwiY29sbm8iLCJvbl9yZWZyZXNoIiwiZW5hYmxlZCIsImNvbmZpZyIsImZpbHRlcl9tb2RlIiwic3BlY2lmaWMiLCJzcGVjaWZpY19jaGFubmVsIiwiY2hhbm5lbHMiLCJ3aGl0ZWxpc3QiLCJmaWx0ZXJfY2hhbm5lbHMiLCJibGFja2xpc3QiLCJ0aW1lc3RhbXAiLCJ0b0lTT1N0cmluZyIsImluY2x1ZGVfbG9jYXRpb24iLCJpbmNsdWRlX2JhY2t0cmFjZSIsImxvY2F0aW9uIiwiYmFja3RyYWNlIiwibGluZSIsIm91dHB1dHMiLCJicm93c2VyIiwiaW5jbHVkZV9iZW5jaG1hcmsiLCJfZ2V0X3RpbWVfcHJlZml4IiwiY2hhbm5lbFByZWZpeCIsImNvbnNvbGVNZXRob2QiLCJsYXJhdmVsX2xvZyIsIl9iYXRjaF9jb25zb2xlX21lc3NhZ2UiLCJsb2dfZXJyb3IiLCJlcnJvckRhdGEiLCJfZXJyb3JfY291bnQiLCJNQVhfRVJST1JTX1BFUl9QQUdFIiwiX2Vycm9yX2JhdGNoX2NvdW50IiwiTUFYX0VSUk9SX0JBVENIRVMiLCJfZXJyb3JfYmF0Y2giLCJfZXJyb3JfdGltZXIiLCJfZmx1c2hfZXJyb3JfYmF0Y2giLCJERUJPVU5DRV9NUyIsIl9jb25zb2xlX2JhdGNoIiwiX2NvbnNvbGVfdGltZXIiLCJfZmx1c2hfY29uc29sZV9iYXRjaCIsIlJvdXRlIiwiX3N0YXJ0X3RpbWUiLCJlbGFwc2VkIiwidG9GaXhlZCIsIl8yN2UwZTk4Nl9kZWZpbmVQcm9wZXJ0eSIsIlJzeF9KcV9IZWxwZXJzIiwiZXhpc3RzIiwiaXNfdmlzaWJsZSIsInNjcm9sbF91cF90byIsInNwZWVkIiwiaXNfaW5fZG9tIiwiZV90b3AiLCJzX3RvcCIsImV4cHIiLCJmb2N1cyIsImVsZW0iLCJhY3RpdmVFbGVtZW50IiwiX2NsaWNrX25hdGl2ZSIsImNsaWNrIiwiaGFuZGxlciIsIm9yaWdpbmFsX3ByZXZlbnREZWZhdWx0IiwiYmluZCIsIndhcm4iLCJjbGlja19hbGxvd19kZWZhdWx0IiwiX2FuY2VzdG9yIiwiSFRNTG9iaiIsInBhcmVudEVsZW1lbnQiLCJkb2N1bWVudEVsZW1lbnQiLCJpc19pbl92aWV3cG9ydCIsInNjcm9sbHRvcCIsInRvcF9vZl9lbGVtZW50IiwiYm90dG9tX29mX2VsZW1lbnQiLCJib3R0b21fb2Zfc2NyZWVuIiwiaW5uZXJIZWlnaHQiLCJ0b3Bfb2Zfc2NyZWVuIiwidGFnbmFtZSIsInByb3AiLCJ0b0xvd2VyQ2FzZSIsImlzX2V4dGVybmFsIiwiaG9zdCIsImxpbmsiLCJob3N0bmFtZSIsImNoZWNrVmFsaWRpdHkiLCJyZXBvcnRWYWxpZGl0eSIsInJlcXVlc3RTdWJtaXQiLCJjbG9zZXN0X3NpYmxpbmciLCJzZWxlY3RvciIsIiRjdXJyZW50IiwiJGZvdW5kIiwibmF0aXZlX2FqYXgiLCJzZXR0aW5ncyIsInJlcXVlc3RfdXJsIiwiaXNfcmVsYXRpdmUiLCJpc19zYW1lX2RvbWFpbiIsIm9yaWdpbiIsImlzX2xvY2FsX3JlcXVlc3QiLCJfX2xvY2FsX2ludGVncmF0aW9uIiwiaXNfZmlsZV91cGxvYWQiLCJlbmRzV2l0aCIsImNvbnRyb2xsZXJfbmFtZSIsImFjdGlvbl9uYW1lIiwidXJsX21hdGNoIiwiX2luaXRfZXZlbnRzIiwiX2V2ZW50X2hhbmRsZXJzIiwiX3RyaWdnZXJlZF9ldmVudHMiLCJ0cmlnZ2VyX3JlZnJlc2giLCJDb3JlX0xvZyIsImlzX2RldiIsInVpZCIsIl91aWQiLCJfZGVmaW5lX3JvdXRlcyIsInJvdXRlcyIsIl9yb3V0ZXMiLCJwYXJhbXNfb2JqIiwicGF0dGVybiIsIl9nZW5lcmF0ZV91cmxfZnJvbV9wYXR0ZXJuIiwicmVxdWlyZWRfcGFyYW1zIiwibWF0Y2hlcyIsIm1pc3NpbmciLCJyZXF1aXJlZCIsInVzZWRfcGFyYW1zIiwicGFyYW1fbmFtZSIsImVuY29kZWRfdmFsdWUiLCJxdWVyeV9wYXJhbXMiLCJxdWVyeV9zdHJpbmciLCJlbnRyaWVzIiwiX3JlZiIsIl9yc3hfY2FsbF9hbGxfY2xhc3NlcyIsImFsbF9jbGFzc2VzIiwiY2xhc3Nlc193aXRoX21ldGhvZCIsInByb21pc2VfcGlsZSIsInJldHVybl92YWx1ZSIsIl9fc3RvcHBlZCIsIl9yc3hfY29yZV9ib290IiwiX19ib290ZWQiLCJwaGFzZXMiLCJwaGFzZSIsIl9wYXJzZV9oYXNoIiwiaGFzaF9zdHJpbmciLCJwYWlycyIsInBhaXIiLCJfc2VyaWFsaXplX2hhc2giLCJnZXRfYWxsX3BhZ2Vfc3RhdGUiLCJnZXRfcGFnZV9zdGF0ZSIsIl9zdGF0ZSRrZXkiLCJzdGF0ZSIsInNldF9wYWdlX3N0YXRlIiwibmV3X2hhc2giLCJwYXRobmFtZSIsImhpc3RvcnkiLCJyZXBsYWNlU3RhdGUiLCJzZXRfYWxsX3BhZ2Vfc3RhdGUiLCJuZXdfc3RhdGUiLCJyZW5kZXJfZXJyb3IiLCIkY29udGFpbmVyIiwiZmlsZSIsIl9lc2NhcGVfaHRtbCIsImRpdiIsImlubmVySFRNTCIsIl9lODIxMWY1Yl9kZWZpbmVQcm9wZXJ0eSIsIl9wZW5kaW5nX2NhbGxzIiwiX2ZsdXNoX3RpbWVvdXQiLCJfY2FsbF9jb3VudGVyIiwiTUFYX0JBVENIX1NJWkUiLCJfdHJhY2tlZF9wcm9taXNlcyIsIldlYWtTZXQiLCJNb2RhbCIsInBhdGgiLCJhamF4X2Rpc2FibGVfYmF0Y2hpbmciLCJfY2FsbF9kaXJlY3QiLCJfY2FsbF9iYXRjaCIsImNhbGxfa2V5IiwiX2dlbmVyYXRlX2NhbGxfa2V5IiwiZXhpc3RpbmdfY2FsbCIsImlzX2NvbXBsZXRlIiwiaXNfZXJyb3IiLCJjYWxsYmFja3MiLCJjYWxsX2lkIiwicGVuZGluZ19jYWxsIiwicGVuZGluZ19jb3VudCIsIl9mbHVzaF9wZW5kaW5nX2NhbGxzIiwic3VjY2VzcyIsIl9zdWNjZXNzIiwicHJvY2Vzc2VkX3ZhbHVlIiwiX2FqYXhfcmV0dXJuX3ZhbHVlIiwiZXJyb3JfdHlwZSIsImZhdGFsX2Vycm9yX2RhdGEiLCJmYXRhbF9lcnJvciIsImVuZHBvaW50IiwiYXV0aF9lcnJvciIsInVuYXV0aF9lcnJvciIsImZvcm1fZXJyb3IiLCJnZW5lcmljX2Vycm9yIiwieGhyIiwiX2V4dHJhY3RfZXJyb3JfbWVzc2FnZSIsIm5ldHdvcmtfZXJyb3IiLCJzdGF0dXNUZXh0IiwiY2FsbHNfdG9fc2VuZCIsImNhbGxfbWFwIiwiYmF0Y2hfY2FsbHMiLCJyZXNwb25zZV9rZXkiLCJjYWxsX3Jlc3BvbnNlIiwiZXJyb3JfZGV0YWlscyIsIl9yZWYyIiwieGhyX2Vycm9yIiwiX3JlZjMiLCJzb3J0ZWRfcGFyYW1zIiwicmVzcG9uc2VKU09OIiwicmVzcG9uc2VUZXh0IiwiSnFodG1sX0NvbXBvbmVudCIsIl9CYXNlX0pxaHRtbF9Db21wb25lbnQiLCJKcWh0bWxfSW50ZWdyYXRpb24iLCJfb25fZnJhbWV3b3JrX21vZHVsZXNfZGVmaW5lIiwianFodG1sX2NvbXBvbmVudHMiLCJjb21wb25lbnQiLCJqcWh0bWwiLCJyZWdpc3Rlcl9jb21wb25lbnQiLCJfb25fZnJhbWV3b3JrX21vZHVsZXNfaW5pdCIsIiRzY29wZSIsImlzX3RvcF9sZXZlbCIsImNvbXBvbmVudHNfbmVlZGluZ19pbml0IiwiY29udGFpbnMiLCJjbGFzc0xpc3QiLCJjb21wb25lbnRfbmFtZSIsImNvbXBvbmVudF9hcmdzIiwiYXJnc19zdHJpbmciLCJyZW1vdmVBdHRyIiwicmVtb3ZlRGF0YSIsImNvbXBvbmVudF9hcmdzX2ZpbHRlcmVkIiwiX2lubmVyX2h0bWwiLCJjb21wb25lbnRfcHJvbWlzZSIsIm5lc3RlZF9wcm9taXNlcyIsImdldF9jb21wb25lbnRfbmFtZXMiLCJoYXNfY29tcG9uZW50Il0sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7OztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVNBLFNBQVNBLENBQUNDLEtBQUssRUFBRTtFQUN0QixPQUFPQSxLQUFLO0FBQ2hCOzs7Ozs7QUN4QkE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTQyxTQUFTQSxDQUFBLEVBQUc7RUFDakIsSUFBSSxnRUFBZ0UsQ0FBQ0MsSUFBSSxDQUFDQyxTQUFTLENBQUNDLFNBQVMsQ0FBQyxFQUFFO0lBQzVGLE9BQU8sSUFBSTtFQUNmLENBQUMsTUFBTSxJQUFJQyxDQUFDLENBQUNDLE1BQU0sQ0FBQyxDQUFDQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEdBQUcsRUFBRTtJQUNoQztJQUNBLE9BQU8sSUFBSTtFQUNmLENBQUMsTUFBTTtJQUNILE9BQU8sS0FBSztFQUNoQjtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBU0MsVUFBVUEsQ0FBQSxFQUFHO0VBQ2xCLE9BQU8sQ0FBQ1AsU0FBUyxDQUFDLENBQUM7QUFDdkI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTUSxNQUFNQSxDQUFBLEVBQUc7RUFDZCxJQUFJQyxVQUFVLEdBQUdKLE1BQU0sQ0FBQ0gsU0FBUyxDQUFDQyxTQUFTO0lBQ3ZDTyxR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T0FBTyxDQUFDakIsS0FBSyxDQUFDLGdCQUFnQixFQUFFQSxLQUFLLENBQUNVLEtBQUssSUFBSVYsS0FBSyxDQUFDO1FBQ3pEO01BQ0o7SUFDSixDQUFDLENBQUM7O0lBRUY7SUFDQSxJQUFJd3FCLFlBQVksRUFBRTtNQUNkLENBQUMsWUFBWTtRQUNULE1BQU16bEIsT0FBTyxDQUFDOEQsR0FBRyxDQUFDRixRQUFRLENBQUM7UUFDM0IsTUFBTStMLEdBQUcsQ0FBQ2tRLHFCQUFxQixDQUFDLGlCQUFpQixDQUFDO1FBQ2xEbFEsR0FBRyxDQUFDd0YsT0FBTyxDQUFDLGNBQWMsQ0FBQztNQUMvQixDQUFDLEVBQUUsQ0FBQztNQUNKO0lBQ0o7O0lBRUE7SUFDQSxPQUFPdlIsUUFBUTtFQUNuQjs7RUFFQTtBQUNKO0FBQ0E7QUFDQTtFQUNJLE9BQU8waUIsbUJBQW1CQSxDQUFBLEVBQUc7SUFDekIsT0FBT2pCLE1BQU0sQ0FBQ2lCLG1CQUFtQixDQUFDLENBQUM7RUFDdkM7O0VBRUE7QUFDSjtBQUNBO0FBQ0E7QUFDQTtFQUNJLE9BQU9DLGFBQWFBLENBQUNscUIsSUFBSSxFQUFFO0lBQ3ZCLE9BQU9ncEIsTUFBTSxDQUFDa0IsYUFBYSxDQUFDbHFCLElBQUksQ0FBQztFQUNyQztBQUNKOztBQUVBOzs7O0FDaktBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRyIsImZpbGUiOiJidW5kbGVfb3V0cHV0X0Jvb3RzdHJhcDVfQnVuZGxlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gTlBNIEltcG9ydCBEZWNsYXJhdGlvbnMgZm9yIEFwcCBCdW5kbGVcbi8vIEF1dG8tZ2VuZXJhdGVkIHRvIHByb3ZpZGUgTlBNIG1vZHVsZXMgdG8gYXBwIGJ1bmRsZSBzY29wZVxuLy8gQ2FjaGUga2V5OiA5NWE2ZjYwMmM5ODAzNzYxMWI2NDBiMGI1MzQyODMwYlxuXG5jb25zdCBqcWh0bWwgPSB3aW5kb3cuX3JzeF9ucG0uanFodG1sO1xuaWYgKCFqcWh0bWwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdSU1ggRnJhbWV3b3JrIEVycm9yOiBOUE0gbW9kdWxlIFwianFodG1sXCIgbm90IGZvdW5kLlxcbicgK1xuICAgICAgICAnRXhwZWN0ZWQgd2luZG93Ll9yc3hfbnBtLmpxaHRtbCB0byBiZSBkZWZpbmVkIGJ5IHRoZSB2ZW5kb3IgYnVuZGxlLidcbiAgICApO1xufVxuXG5jb25zdCBfQmFzZV9KcWh0bWxfQ29tcG9uZW50ID0gd2luZG93Ll9yc3hfbnBtLl9CYXNlX0pxaHRtbF9Db21wb25lbnQ7XG5pZiAoIV9CYXNlX0pxaHRtbF9Db21wb25lbnQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdSU1ggRnJhbWV3b3JrIEVycm9yOiBOUE0gbW9kdWxlIFwiX0Jhc2VfSnFodG1sX0NvbXBvbmVudFwiIG5vdCBmb3VuZC5cXG4nICtcbiAgICAgICAgJ0V4cGVjdGVkIHdpbmRvdy5fcnN4X25wbS5fQmFzZV9KcWh0bWxfQ29tcG9uZW50IHRvIGJlIGRlZmluZWQgYnkgdGhlIHZlbmRvciBidW5kbGUuJ1xuICAgICk7XG59XG5cbi8vIENsZWFuIHVwIE5QTSBjb250YWluZXIgdG8gcHJldmVudCBjb25zb2xlIGFjY2Vzc1xuZGVsZXRlIHdpbmRvdy5fcnN4X25wbTtcbiIsIi8qKlxuICogRGVjb3JhdG9yIGZ1bmN0aW9uIHRoYXQgbWFya3MgYSBmdW5jdGlvbiBhcyBhIGRlY29yYXRvciBpbXBsZW1lbnRhdGlvbi5cbiAqXG4gKiBXaGVuIGEgZnVuY3Rpb24gaGFzIEBkZWNvcmF0b3IgaW4gaXRzIEpTRG9jIGNvbW1lbnQsIGl0IHdoaXRlbGlzdHMgdGhhdCBmdW5jdGlvblxuICogdG8gYmUgdXNlZCBhcyBhIGRlY29yYXRvciBvbiBvdGhlciBtZXRob2RzIHRocm91Z2hvdXQgdGhlIGNvZGViYXNlLlxuICpcbiAqIFRoZSBmdW5jdGlvbiBpdHNlbGYgcGVyZm9ybXMgbm8gb3BlcmF0aW9uIC0gaXQgc2ltcGx5IHJldHVybnMgaXRzIGlucHV0IHVuY2hhbmdlZC5cbiAqIEl0cyBwdXJwb3NlIGlzIHB1cmVseSBhcyBhIG1hcmtlciBmb3IgdGhlIG1hbmlmZXN0IHZhbGlkYXRpb24gc3lzdGVtLlxuICpcbiAqIFVzYWdlOlxuICogICAvLyAvKipcbiAqICAgLy8gICogTXkgY3VzdG9tIGRlY29yYXRvciBpbXBsZW1lbnRhdGlvblxuICogICAvLyAgKiBAZGVjb3JhdG9yXG4gKiAgIC8vICAqXFwvXG4gKiAgIGZ1bmN0aW9uIG15X2N1c3RvbV9kZWNvcmF0b3IodGFyZ2V0LCBrZXksIGRlc2NyaXB0b3IpIHtcbiAqICAgICAgIC8vIERlY29yYXRvciBpbXBsZW1lbnRhdGlvblxuICogICB9XG4gKlxuICogVGhpcyBhbGxvd3MgbXlfY3VzdG9tX2RlY29yYXRvciB0byBiZSB1c2VkIGFzIEBteV9jdXN0b21fZGVjb3JhdG9yIG9uIHN0YXRpYyBtZXRob2RzLlxuICpcbiAqIFRPRE86IFRoaXMgaXMgcHJvYmFibHkgbm8gbG9uZ2VyIG5lY2Vzc2FyeT8gbWF5YmU/XG4gKi9cbmZ1bmN0aW9uIGRlY29yYXRvcih2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZTtcbn1cbiIsIi8qXG4gKiBCcm93c2VyIGFuZCBET00gdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHRoZSBSU3BhZGUgZnJhbWV3b3JrLlxuICogVGhlc2UgZnVuY3Rpb25zIGhhbmRsZSBicm93c2VyIGRldGVjdGlvbiwgdmlld3BvcnQgdXRpbGl0aWVzLCBhbmQgRE9NIG1hbmlwdWxhdGlvbi5cbiAqL1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBCUk9XU0VSIERFVEVDVElPTlxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIERldGVjdHMgaWYgdXNlciBpcyBvbiBhIG1vYmlsZSBkZXZpY2Ugb3IgdXNpbmcgbW9iaWxlIHZpZXdwb3J0XG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiBtb2JpbGUgZGV2aWNlIG9yIHZpZXdwb3J0IDwgOTkycHhcbiAqIEB0b2RvIEltcHJvdmUgdXNlciBhZ2VudCBkZXRlY3Rpb24gZm9yIGFsbCBtb2JpbGUgZGV2aWNlc1xuICovXG5mdW5jdGlvbiBpc19tb2JpbGUoKSB7XG4gICAgaWYgKC9BbmRyb2lkfHdlYk9TfGlQaG9uZXxpUGFkfGlQb2R8QmxhY2tCZXJyeXxJRU1vYmlsZXxPcGVyYSBNaW5pL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKCQod2luZG93KS53aWR0aCgpIDwgOTkyKSB7XG4gICAgICAgIC8vIDk5MnB4ID0gYm9vdHN0cmFwIDQgY29sLW1kLVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG4vKipcbiAqIERldGVjdHMgaWYgdXNlciBpcyBvbiBkZXNrdG9wIChub3QgbW9iaWxlKVxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgbm90IG1vYmlsZSBkZXZpY2Uvdmlld3BvcnRcbiAqL1xuZnVuY3Rpb24gaXNfZGVza3RvcCgpIHtcbiAgICByZXR1cm4gIWlzX21vYmlsZSgpO1xufVxuXG4vKipcbiAqIERldGVjdHMgdGhlIHVzZXIncyBvcGVyYXRpbmcgc3lzdGVtXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBPUyBuYW1lOiAnTWFjIE9TJywgJ2lQaG9uZScsICdpUGFkJywgJ1dpbmRvd3MnLCAnQW5kcm9pZC1QaG9uZScsICdBbmRyb2lkLVRhYmxldCcsICdMaW51eCcsIG9yICdVbmtub3duJ1xuICovXG5mdW5jdGlvbiBnZXRfb3MoKSB7XG4gICAgbGV0IHVzZXJfYWdlbnQgPSB3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudCxcbiAgICAgICAgcGxhdGZvcm0gPSB3aW5kb3cubmF2aWdhdG9yLnBsYXRmb3JtLFxuICAgICAgICBtYWNvc19wbGF0Zm9ybXMgPSBbJ01hY2ludG9zaCcsICdNYWNJbnRlbCcsICdNYWNQUEMnLCAnTWFjNjhLJ10sXG4gICAgICAgIHdpbmRvd3NfcGxhdGZvcm1zID0gWydXaW4zMicsICdXaW42NCcsICdXaW5kb3dzJywgJ1dpbkNFJ10sXG4gICAgICAgIGlvc19wbGF0Zm9ybXMgPSBbJ2lQaG9uZScsICdpUGFkJywgJ2lQb2QnXSxcbiAgICAgICAgb3MgPSBudWxsO1xuXG4gICAgbGV0IGlzX21vYmlsZV9kZXZpY2UgPSBpc19tb2JpbGUoKTtcblxuICAgIGlmIChtYWNvc19wbGF0Zm9ybXMuaW5kZXhPZihwbGF0Zm9ybSkgIT09IC0xKSB7XG4gICAgICAgIG9zID0gJ01hYyBPUyc7XG4gICAgfSBlbHNlIGlmIChpb3NfcGxhdGZvcm1zLmluZGV4T2YocGxhdGZvcm0pICE9PSAtMSAmJiBpc19tb2JpbGVfZGV2aWNlKSB7XG4gICAgICAgIG9zID0gJ2lQaG9uZSc7XG4gICAgfSBlbHNlIGlmIChpb3NfcGxhdGZvcm1zLmluZGV4T2YocGxhdGZvcm0pICE9PSAtMSAmJiAhaXNfbW9iaWxlX2RldmljZSkge1xuICAgICAgICBvcyA9ICdpUGFkJztcbiAgICB9IGVsc2UgaWYgKHdpbmRvd3NfcGxhdGZvcm1zLmluZGV4T2YocGxhdGZvcm0pICE9PSAtMSkge1xuICAgICAgICBvcyA9ICdXaW5kb3dzJztcbiAgICB9IGVsc2UgaWYgKC9BbmRyb2lkLy50ZXN0KHVzZXJfYWdlbnQpICYmIGlzX21vYmlsZV9kZXZpY2UpIHtcbiAgICAgICAgb3MgPSAnQW5kcm9pZC1QaG9uZSc7XG4gICAgfSBlbHNlIGlmICgvQW5kcm9pZC8udGVzdCh1c2VyX2FnZW50KSAmJiAhaXNfbW9iaWxlX2RldmljZSkge1xuICAgICAgICBvcyA9ICdBbmRyb2lkLVRhYmxldCc7XG4gICAgfSBlbHNlIGlmICghb3MgJiYgL0xpbnV4Ly50ZXN0KHBsYXRmb3JtKSkge1xuICAgICAgICBvcyA9ICdMaW51eCc7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgb3MgPSAnVW5rbm93bic7XG4gICAgfVxuXG4gICAgcmV0dXJuIG9zO1xufVxuXG4vKipcbiAqIERldGVjdHMgaWYgdGhlIHVzZXIgYWdlbnQgaXMgYSB3ZWIgY3Jhd2xlci9ib3RcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHVzZXIgYWdlbnQgYXBwZWFycyB0byBiZSBhIGJvdC9jcmF3bGVyXG4gKi9cbmZ1bmN0aW9uIGlzX2NyYXdsZXIoKSB7XG4gICAgbGV0IHVzZXJfYWdlbnQgPSBuYXZpZ2F0b3IudXNlckFnZW50O1xuICAgIGxldCBib3RfcGF0dGVybiA9IC9ib3R8c3BpZGVyfGNyYXdsfHNsdXJwfGFyY2hpdmVyfHBpbmd8c2VhcmNofGRpZ3x0cmFja2VyfG1vbml0b3J8c25vb3B5fHlhaG9vfGJhaWR1fG1zbnxhc2t8dGVvbWF8YXhpb3MvaTtcblxuICAgIHJldHVybiBib3RfcGF0dGVybi50ZXN0KHVzZXJfYWdlbnQpO1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBET00gU0NST0xMSU5HIFVUSUxJVElFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIFNjcm9sbHMgcGFyZW50IGNvbnRhaW5lciB0byBtYWtlIHRhcmdldCBlbGVtZW50IHZpc2libGUgaWYgbmVlZGVkXG4gKiBAcGFyYW0ge3N0cmluZ3xIVE1MRWxlbWVudHxqUXVlcnl9IHRhcmdldCAtIFRhcmdldCBlbGVtZW50IHRvIHNjcm9sbCBpbnRvIHZpZXdcbiAqL1xuZnVuY3Rpb24gc2Nyb2xsX2ludG9fdmlld19pZl9uZWVkZWQodGFyZ2V0KSB7XG4gICAgY29uc3QgJHRhcmdldCA9ICQodGFyZ2V0KTtcblxuICAgIC8vIEZpbmQgdGhlIGNsb3Nlc3QgcGFyZW50IHdpdGggb3ZlcmZsb3cteTogYXV0b1xuICAgIGNvbnN0ICRwYXJlbnQgPSAkdGFyZ2V0LnBhcmVudCgpO1xuXG4gICAgLy8gQ2FsY3VsYXRlIHRoZSBhYnNvbHV0ZSB0b3AgcG9zaXRpb24gb2YgdGhlIHRhcmdldFxuICAgIGNvbnN0IHRhcmdldF90b3AgPSAkdGFyZ2V0LnBvc2l0aW9uKCkudG9wICsgJHBhcmVudC5zY3JvbGxUb3AoKTtcblxuICAgIGNvbnN0IHRhcmdldF9oZWlnaHQgPSAkdGFyZ2V0Lm91dGVySGVpZ2h0KCk7XG4gICAgY29uc3QgcGFyZW50X2hlaWdodCA9ICRwYXJlbnQuaGVpZ2h0KCk7XG4gICAgY29uc3Qgc2Nyb2xsX3Bvc2l0aW9uID0gJHBhcmVudC5zY3JvbGxUb3AoKTtcblxuICAgIC8vIENoZWNrIGlmIHRoZSB0YXJnZXQgaXMgb3V0IG9mIHZpZXdcbiAgICBpZiAodGFyZ2V0X3RvcCA8IHNjcm9sbF9wb3NpdGlvbiB8fCB0YXJnZXRfdG9wICsgdGFyZ2V0X2hlaWdodCA+IHNjcm9sbF9wb3NpdGlvbiArIHBhcmVudF9oZWlnaHQpIHtcbiAgICAgICAgRGVidWdnZXIuY29uc29sZV9kZWJ1ZygnVUknLCAnU2Nyb2xsaW5nIScsIHRhcmdldF90b3ApO1xuXG4gICAgICAgIC8vIENhbGN1bGF0ZSB0aGUgbmV3IHNjcm9sbCBwb3NpdGlvbiB0byBjZW50ZXIgdGhlIHRhcmdldFxuICAgICAgICBsZXQgbmV3X3Njcm9sbF9wb3NpdGlvbiA9IHRhcmdldF90b3AgKyB0YXJnZXRfaGVpZ2h0IC8gMiAtIHBhcmVudF9oZWlnaHQgLyAyO1xuXG4gICAgICAgIC8vIExpbWl0IHRoZSBzY3JvbGwgcG9zaXRpb24gYmV0d2VlbiAwIGFuZCB0aGUgbWF4aW11bSBzY3JvbGxhYmxlIGhlaWdodFxuICAgICAgICBuZXdfc2Nyb2xsX3Bvc2l0aW9uID0gTWF0aC5tYXgoMCwgTWF0aC5taW4obmV3X3Njcm9sbF9wb3NpdGlvbiwgJHBhcmVudFswXS5zY3JvbGxIZWlnaHQgLSBwYXJlbnRfaGVpZ2h0KSk7XG5cbiAgICAgICAgLy8gU2Nyb2xsIHRoZSBwYXJlbnQgdG8gdGhlIG5ldyBzY3JvbGwgcG9zaXRpb25cbiAgICAgICAgJHBhcmVudC5zY3JvbGxUb3AobmV3X3Njcm9sbF9wb3NpdGlvbik7XG4gICAgfVxufVxuXG4vKipcbiAqIFNjcm9sbHMgcGFnZSB0byBtYWtlIHRhcmdldCBlbGVtZW50IHZpc2libGUgaWYgbmVlZGVkICh3aXRoIGFuaW1hdGlvbilcbiAqIEBwYXJhbSB7c3RyaW5nfEhUTUxFbGVtZW50fGpRdWVyeX0gdGFyZ2V0IC0gVGFyZ2V0IGVsZW1lbnQgdG8gc2Nyb2xsIGludG8gdmlld1xuICovXG5mdW5jdGlvbiBzY3JvbGxfcGFnZV9pbnRvX3ZpZXdfaWZfbmVlZGVkKHRhcmdldCkge1xuICAgIGNvbnN0ICR0YXJnZXQgPSAkKHRhcmdldCk7XG5cbiAgICAvLyBDYWxjdWxhdGUgdGhlIGFic29sdXRlIHRvcCBwb3NpdGlvbiBvZiB0aGUgdGFyZ2V0IHJlbGF0aXZlIHRvIHRoZSBkb2N1bWVudFxuICAgIGNvbnN0IHRhcmdldF90b3AgPSAkdGFyZ2V0Lm9mZnNldCgpLnRvcDtcblxuICAgIGNvbnN0IHRhcmdldF9oZWlnaHQgPSAkdGFyZ2V0Lm91dGVySGVpZ2h0KCk7XG4gICAgY29uc3Qgd2luZG93X2hlaWdodCA9ICQod2luZG93KS5oZWlnaHQoKTtcbiAgICBjb25zdCB3aW5kb3dfc2Nyb2xsX3Bvc2l0aW9uID0gJCh3aW5kb3cpLnNjcm9sbFRvcCgpO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHRhcmdldCBpcyBvdXQgb2Ygdmlld1xuICAgIGlmICh0YXJnZXRfdG9wIDwgd2luZG93X3Njcm9sbF9wb3NpdGlvbiB8fCB0YXJnZXRfdG9wICsgdGFyZ2V0X2hlaWdodCA+IHdpbmRvd19zY3JvbGxfcG9zaXRpb24gKyB3aW5kb3dfaGVpZ2h0KSB7XG4gICAgICAgIERlYnVnZ2VyLmNvbnNvbGVfZGVidWcoJ1VJJywgJ1Njcm9sbGluZyEnLCB0YXJnZXRfdG9wKTtcblxuICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIG5ldyBzY3JvbGwgcG9zaXRpb24gdG8gY2VudGVyIHRoZSB0YXJnZXRcbiAgICAgICAgY29uc3QgbmV3X3Njcm9sbF9wb3NpdGlvbiA9IHRhcmdldF90b3AgKyB0YXJnZXRfaGVpZ2h0IC8gMiAtIHdpbmRvd19oZWlnaHQgLyAyO1xuXG4gICAgICAgIC8vIEFuaW1hdGUgdGhlIHNjcm9sbCB0byB0aGUgbmV3IHBvc2l0aW9uXG4gICAgICAgICQoJ2h0bWwsIGJvZHknKS5hbmltYXRlKFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHNjcm9sbFRvcDogbmV3X3Njcm9sbF9wb3NpdGlvbixcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAxMDAwXG4gICAgICAgICk7IC8vIGR1cmF0aW9uIG9mIHRoZSBzY3JvbGwgYW5pbWF0aW9uIGluIG1pbGxpc2Vjb25kc1xuICAgIH1cbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gRE9NIFVUSUxJVElFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIFdhaXRzIGZvciBhbGwgaW1hZ2VzIG9uIHRoZSBwYWdlIHRvIGxvYWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIC0gRnVuY3Rpb24gdG8gY2FsbCB3aGVuIGFsbCBpbWFnZXMgYXJlIGxvYWRlZFxuICovXG5mdW5jdGlvbiB3YWl0X2Zvcl9pbWFnZXMoY2FsbGJhY2spIHtcbiAgICBjb25zdCAkaW1hZ2VzID0gJCgnaW1nJyk7IC8vIEdldCBhbGwgaW1nIHRhZ3NcbiAgICBjb25zdCB0b3RhbF9pbWFnZXMgPSAkaW1hZ2VzLmxlbmd0aDtcbiAgICBsZXQgaW1hZ2VzX2xvYWRlZCA9IDA7XG5cbiAgICBpZiAodG90YWxfaW1hZ2VzID09PSAwKSB7XG4gICAgICAgIGNhbGxiYWNrKCk7IC8vIGlmIHRoZXJlIGFyZSBubyBpbWFnZXMsIGltbWVkaWF0ZWx5IGNhbGwgdGhlIGNhbGxiYWNrXG4gICAgfVxuXG4gICAgJGltYWdlcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgaW1nID0gbmV3IEltYWdlKCk7XG4gICAgICAgIGltZy5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpbWFnZXNfbG9hZGVkKys7XG4gICAgICAgICAgICBpZiAoaW1hZ2VzX2xvYWRlZCA9PT0gdG90YWxfaW1hZ2VzKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soKTsgLy8gY2FsbCB0aGUgY2FsbGJhY2sgd2hlbiBhbGwgaW1hZ2VzIGFyZSBsb2FkZWRcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgaW1nLm9uZXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpbWFnZXNfbG9hZGVkKys7XG4gICAgICAgICAgICBpZiAoaW1hZ2VzX2xvYWRlZCA9PT0gdG90YWxfaW1hZ2VzKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soKTsgLy8gYWxzbyBjYWxsIHRoZSBjYWxsYmFjayBpZiBhbiBpbWFnZSBmYWlscyB0byBsb2FkXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGltZy5zcmMgPSB0aGlzLnNyYzsgLy8gdGhpcyB0cmlnZ2VycyB0aGUgbG9hZGluZ1xuICAgIH0pO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBqUXVlcnkgZWxlbWVudCBjb250YWluaW5nIGEgbm9uLWJyZWFraW5nIHNwYWNlXG4gKiBAcmV0dXJucyB7alF1ZXJ5fSBqUXVlcnkgc3BhbiBlbGVtZW50IHdpdGggJm5ic3A7XG4gKi9cbmZ1bmN0aW9uICRuYnNwKCkge1xuICAgIHJldHVybiAkKCc8c3Bhbj4mbmJzcDs8L3NwYW4+Jyk7XG59XG5cbi8qKlxuICogRXNjYXBlcyBzcGVjaWFsIGNoYXJhY3RlcnMgaW4gYSBqUXVlcnkgc2VsZWN0b3JcbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCAtIEVsZW1lbnQgSUQgdG8gZXNjYXBlXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBqUXVlcnkgc2VsZWN0b3Igc3RyaW5nIHdpdGggZXNjYXBlZCBzcGVjaWFsIGNoYXJhY3RlcnNcbiAqIEB3YXJuaW5nIE5vdCBzYWZlIGZvciBzZWN1cml0eS1jcml0aWNhbCBvcGVyYXRpb25zXG4gKi9cbmZ1bmN0aW9uIGVzY2FwZV9qcV9zZWxlY3RvcihpZCkge1xuICAgIHJldHVybiAnIycgKyBpZC5yZXBsYWNlKC8oOnxcXC58XFxbfFxcXXwsfD18QCkvZywgJ1xcXFwkMScpO1xufSIsIi8qXG4gKiBEYXRlIGFuZCB0aW1lIHV0aWxpdHkgZnVuY3Rpb25zIGZvciB0aGUgUlNwYWRlIGZyYW1ld29yay5cbiAqIFRoZXNlIGZ1bmN0aW9ucyBoYW5kbGUgZGF0ZS90aW1lIGNvbnZlcnNpb25zIGFuZCBVbml4IHRpbWVzdGFtcHMuXG4gKi9cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gREFURS9USU1FIFVUSUxJVElFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEdldHMgdGhlIGN1cnJlbnQgVW5peCB0aW1lc3RhbXAgKHNlY29uZHMgc2luY2UgZXBvY2gpXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBDdXJyZW50IFVuaXggdGltZXN0YW1wIGluIHNlY29uZHNcbiAqIEB0b2RvIENhbGN1bGF0ZSBiYXNlZCBvbiBzZXJ2ZXIgdGltZSBhdCBwYWdlIHJlbmRlclxuICogQHRvZG8gTW92ZSB0byBhIGRhdGUgbGlicmFyeVxuICovXG5mdW5jdGlvbiB1bml4X3RpbWUoKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBhIGRhdGUgc3RyaW5nIHRvIFVuaXggdGltZXN0YW1wXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyX2RhdGUgLSBEYXRlIHN0cmluZyAoWS1tLWQgSDppOnMgZm9ybWF0KVxuICogQHJldHVybnMge251bWJlcn0gVW5peCB0aW1lc3RhbXAgaW4gc2Vjb25kc1xuICovXG5mdW5jdGlvbiB5bWRoaXNfdG9fdW5peChzdHJfZGF0ZSkge1xuICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZShzdHJfZGF0ZSk7XG4gICAgcmV0dXJuIGRhdGUuZ2V0VGltZSgpIC8gMTAwMDtcbn0iLCIvKlxuICogRXJyb3IgaGFuZGxpbmcgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHRoZSBSU3BhZGUgZnJhbWV3b3JrLlxuICogVGhlc2UgZnVuY3Rpb25zIGhhbmRsZSBlcnJvciBjcmVhdGlvbiBhbmQgZGVidWdnaW5nIHV0aWxpdGllcy5cbiAqL1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBFUlJPUiBIQU5ETElOR1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIENyZWF0ZXMgYW4gZXJyb3Igb2JqZWN0IGZyb20gYSBzdHJpbmdcbiAqIEBwYXJhbSB7c3RyaW5nfE9iamVjdH0gc3RyIC0gRXJyb3IgbWVzc2FnZSBvciBleGlzdGluZyBlcnJvciBvYmplY3RcbiAqIEBwYXJhbSB7bnVtYmVyfSBbZXJyb3JfY29kZV0gLSBPcHRpb25hbCBlcnJvciBzdGF0dXMgY29kZVxuICogQHJldHVybnMge09iamVjdH0gRXJyb3Igb2JqZWN0IHdpdGggZXJyb3IgYW5kIHN0YXR1cyBwcm9wZXJ0aWVzXG4gKi9cbmZ1bmN0aW9uIGVycm9yKHN0ciwgZXJyb3JfY29kZSkge1xuICAgIGlmICh0eXBlb2Ygc3RyLmVycm9yICE9IHVuZGVmKSB7XG4gICAgICAgIHJldHVybiBzdHI7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHR5cGVvZiBlcnJvcl9jb2RlID09IHVuZGVmKSB7XG4gICAgICAgICAgICByZXR1cm4geyBlcnJvcjogc3RyLCBzdGF0dXM6IG51bGwgfTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiB7IGVycm9yOiBzdHIsIHN0YXR1czogZXJyb3JfY29kZSB9O1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIFNhbml0eSBjaGVjayBmYWlsdXJlIGhhbmRsZXIgZm9yIEphdmFTY3JpcHRcbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIHNob3VsZCBiZSBjYWxsZWQgd2hlbiBhIHNhbml0eSBjaGVjayBmYWlscyAtIGkuZS4sIHdoZW4gdGhlIGNvZGVcbiAqIGVuY291bnRlcnMgYSBjb25kaXRpb24gdGhhdCBcInNob3VsZG4ndCBoYXBwZW5cIiBpZiBldmVyeXRoaW5nIGlzIHdvcmtpbmcgY29ycmVjdGx5LlxuICpcbiAqIFVubGlrZSBQSFAsIHdlIGNhbid0IHN0b3AgSmF2YVNjcmlwdCBleGVjdXRpb24sIGJ1dCB3ZSBjYW46XG4gKiAxLiBUaHJvdyBhbiBlcnJvciB0aGF0IHdpbGwgYmUgY2F1Z2h0IGJ5IGVycm9yIGhhbmRsZXJzXG4gKiAyLiBMb2cgYSBjbGVhciBlcnJvciB0byB0aGUgY29uc29sZVxuICogMy4gUHJvdmlkZSBzdGFjayB0cmFjZSBmb3IgZGVidWdnaW5nXG4gKlxuICogVXNlIHRoaXMgaW5zdGVhZCBvZiBzaWxlbnRseSByZXR1cm5pbmcgb3IgY29udGludWluZyB3aGVuIGVuY291bnRlcmluZyB1bmV4cGVjdGVkIGNvbmRpdGlvbnMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgT3B0aW9uYWwgc3BlY2lmaWMgbWVzc2FnZSBhYm91dCB3aGF0IHNob3VsZG4ndCBoYXZlIGhhcHBlbmVkXG4gKiBAdGhyb3dzIHtFcnJvcn0gQWx3YXlzIHRocm93cyB3aXRoIGxvY2F0aW9uIGFuZCBjb250ZXh0IGluZm9ybWF0aW9uXG4gKi9cbmZ1bmN0aW9uIHNob3VsZG50X2hhcHBlbihtZXNzYWdlID0gbnVsbCkge1xuICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKCk7XG4gICAgY29uc3Qgc3RhY2sgPSBlcnJvci5zdGFjayB8fCAnJztcbiAgICBjb25zdCBzdGFja0xpbmVzID0gc3RhY2suc3BsaXQoJ1xcbicpO1xuXG4gICAgLy8gR2V0IHRoZSBjYWxsZXIgbG9jYXRpb24gKHNraXAgdGhlIEVycm9yIGxpbmUgYW5kIHRoaXMgZnVuY3Rpb24pXG4gICAgbGV0IGNhbGxlckluZm8gPSAndW5rbm93biBsb2NhdGlvbic7XG4gICAgaWYgKHN0YWNrTGluZXMubGVuZ3RoID4gMikge1xuICAgICAgICBjb25zdCBjYWxsZXJMaW5lID0gc3RhY2tMaW5lc1syXSB8fCBzdGFja0xpbmVzWzFdIHx8ICcnO1xuICAgICAgICAvLyBFeHRyYWN0IGZpbGUgYW5kIGxpbmUgbnVtYmVyIGZyb20gc3RhY2sgdHJhY2VcbiAgICAgICAgY29uc3QgbWF0Y2ggPSBjYWxsZXJMaW5lLm1hdGNoKC9hdFxccysuKj9cXHMrXFwoKC4qPyk6KFxcZCspOihcXGQrKVxcKS8pIHx8IGNhbGxlckxpbmUubWF0Y2goL2F0XFxzKyguKj8pOihcXGQrKTooXFxkKykvKTtcbiAgICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgICAgICBjYWxsZXJJbmZvID0gYCR7bWF0Y2hbMV19OiR7bWF0Y2hbMl19YDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGxldCBlcnJvck1lc3NhZ2UgPSBgRmF0YWw6IHNob3VsZG50X2hhcHBlbigpIHdhcyBjYWxsZWQgYXQgJHtjYWxsZXJJbmZvfVxcbmA7XG4gICAgZXJyb3JNZXNzYWdlICs9ICdUaGlzIGluZGljYXRlcyBhIHNhbml0eSBjaGVjayBmYWlsZWQgLSB0aGUgY29kZSBpcyBub3QgYmVoYXZpbmcgYXMgZXhwZWN0ZWQuXFxuJztcblxuICAgIGlmIChtZXNzYWdlKSB7XG4gICAgICAgIGVycm9yTWVzc2FnZSArPSBgRGV0YWlsczogJHttZXNzYWdlfVxcbmA7XG4gICAgfVxuXG4gICAgZXJyb3JNZXNzYWdlICs9ICdQbGVhc2UgdGhvcm91Z2hseSByZXZpZXcgdGhlIHJlbGF0ZWQgY29kZSB0byBkZXRlcm1pbmUgd2h5IHRoaXMgZXJyb3Igb2NjdXJyZWQuJztcblxuICAgIC8vIExvZyB0byBjb25zb2xlIHdpdGggZnVsbCB2aXNpYmlsaXR5XG4gICAgY29uc29sZS5lcnJvcignPScucmVwZWF0KDgwKSk7XG4gICAgY29uc29sZS5lcnJvcignU0FOSVRZIENIRUNLIEZBSUxVUkUnKTtcbiAgICBjb25zb2xlLmVycm9yKCc9Jy5yZXBlYXQoODApKTtcbiAgICBjb25zb2xlLmVycm9yKGVycm9yTWVzc2FnZSk7XG4gICAgY29uc29sZS5lcnJvcignU3RhY2sgdHJhY2U6Jywgc3RhY2spO1xuICAgIGNvbnNvbGUuZXJyb3IoJz0nLnJlcGVhdCg4MCkpO1xuXG4gICAgLy8gVGhyb3cgZXJyb3IgdG8gc3RvcCBleGVjdXRpb24gZmxvd1xuICAgIGNvbnN0IGZhdGFsRXJyb3IgPSBuZXcgRXJyb3IoZXJyb3JNZXNzYWdlKTtcbiAgICBmYXRhbEVycm9yLm5hbWUgPSAnU2FuaXR5Q2hlY2tGYWlsdXJlJztcbiAgICB0aHJvdyBmYXRhbEVycm9yO1xufSIsIi8qXG4gKiBIYXNoaW5nIGFuZCBjb21wYXJpc29uIHV0aWxpdHkgZnVuY3Rpb25zIGZvciB0aGUgUlNwYWRlIGZyYW1ld29yay5cbiAqIFRoZXNlIGZ1bmN0aW9ucyBoYW5kbGUgb2JqZWN0IGhhc2hpbmcgYW5kIGRlZXAgY29tcGFyaXNvbi5cbiAqL1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBIQVNISU5HIEFORCBDT01QQVJJU09OXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogR2VuZXJhdGVzIGEgdW5pcXVlIGhhc2ggZm9yIGFueSB2YWx1ZSAoaGFuZGxlcyBvYmplY3RzLCBhcnJheXMsIGNpcmN1bGFyIHJlZmVyZW5jZXMpXG4gKiBAcGFyYW0geyp9IHRoZV92YXIgLSBWYWx1ZSB0byBoYXNoXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtjYWxjX3NoYTE9dHJ1ZV0gLSBJZiB0cnVlLCByZXR1cm5zIFNIQTEgaGFzaDsgaWYgZmFsc2UsIHJldHVybnMgSlNPTlxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBbaWdub3JlZF9rZXlzPW51bGxdIC0gS2V5cyB0byBpZ25vcmUgd2hlbiBoYXNoaW5nIG9iamVjdHNcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFNIQTEgaGFzaCBvciBKU09OIHN0cmluZyBvZiB0aGUgdmFsdWVcbiAqL1xuZnVuY3Rpb24gaGFzaCh0aGVfdmFyLCBjYWxjX3NoYTEgPSB0cnVlLCBpZ25vcmVkX2tleXMgPSBudWxsKSB7XG4gICAgaWYgKHR5cGVvZiB0aGVfdmFyID09IHVuZGVmKSB7XG4gICAgICAgIHRoZV92YXIgPSAnX191bmRlZmluZWRfXyc7XG4gICAgfVxuXG4gICAgaWYgKGlnbm9yZWRfa2V5cyA9PT0gbnVsbCkge1xuICAgICAgICBpZ25vcmVkX2tleXMgPSBbJyQnXTtcbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0cyB2YWx1ZSB0byBqc29uLCBkaXNjYXJkaW5nIGNpcmN1bGFyIHJlZmVyZW5jZXNcbiAgICBsZXQganNvbl9zdHJpbmdpZnlfbm9jaXJjID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgIGNvbnN0IGNhY2hlID0gW107XG4gICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZSwgZnVuY3Rpb24gKGtleSwgdikge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiB2ID09PSAnb2JqZWN0JyAmJiB0eXBlb2YgdGhlX3Zhci5fY2FjaGVfa2V5ID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhlX3Zhci5faGFzaF9rZXkoKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHYgPT09ICdvYmplY3QnICYmIHYgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBpZiAoY2FjaGUuaW5kZXhPZih2KSAhPT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRHVwbGljYXRlIHJlZmVyZW5jZSBmb3VuZCwgZGlzY2FyZCBrZXlcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYWNoZS5wdXNoKHYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHY7XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvLyBUdXJuIGV2ZXJ5IHByb3BlcnR5IGFuZCBhbGwgaXRzIGNoaWxkcmVuIGludG8gYSBzaW5nbGUgZGVwdGggYXJyYXkgb2YgdmFsdWVzIHRoYXQgd2UgY2FuIHRoZW5cbiAgICAvLyBzb3J0IGFuZCBoYXNoIGFzIGEgd2hvbGVcbiAgICBsZXQgZmxhdF92YXIgPSB7fTtcbiAgICBsZXQgX2ZsYXR0ZW4gPSBmdW5jdGlvbiAodGhlX3ZhciwgcHJlZml4LCBkZXB0aCA9IDApIHtcbiAgICAgICAgLy8gSWYgYSBjbGFzcyBvYmplY3QgaXMgcHJvdmlkZWQsIGNpcmN1bGFyIHJlZmVyZW5jZXMgY2FuIG1ha2UgdGhlIGNhbGwgc3RhY2sgcmVjdXJzaXZlLlxuICAgICAgICAvLyBGb3IgdGhlIHB1cnBvc2VzIG9mIGhvdyB0aGUgaGFzaCBmdW5jdGlvbiBpcyBjYWxsZWQsIHRoaXMgc2hvdWxkIGJlIHN1ZmZpY2llbnQuXG4gICAgICAgIGlmIChkZXB0aCA+IDEwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBEb2VzIG5vdCBhY2NvdW50IGZvciBkYXRlcyBpIHRoaW5rLi4uXG5cbiAgICAgICAgaWYgKGlzX29iamVjdCh0aGVfdmFyKSAmJiB0eXBlb2YgdGhlX3Zhci5fY2FjaGVfa2V5ID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIC8vIFVzZSBfY2FjaGVfa2V5IHRvIGhhc2ggY29tcG9uZW50c1xuICAgICAgICAgICAgZmxhdF92YXJbcHJlZml4XSA9IHRoZV92YXIuX2hhc2hfa2V5KCk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNfb2JqZWN0KHRoZV92YXIpICYmIHR5cGVvZiBBYnN0cmFjdCAhPT0gJ3VuZGVmaW5lZCcgJiYgdGhlX3ZhciBpbnN0YW5jZW9mIEFic3RyYWN0KSB7XG4gICAgICAgICAgICAvLyBTdHJpbmdpZnkgYWxsIGNsYXNzIG9iamVjdHNcbiAgICAgICAgICAgIGZsYXRfdmFyW3ByZWZpeF0gPSBqc29uX3N0cmluZ2lmeV9ub2NpcmModGhlX3Zhcik7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNfb2JqZWN0KHRoZV92YXIpKSB7XG4gICAgICAgICAgICAvLyBJdGVyYXRlIG90aGVyIG9iamVjdHNcbiAgICAgICAgICAgIGZsYXRfdmFyW3ByZWZpeF0gPSB7fTtcbiAgICAgICAgICAgIGZvciAobGV0IGsgaW4gdGhlX3Zhcikge1xuICAgICAgICAgICAgICAgIGlmICh0aGVfdmFyLmhhc093blByb3BlcnR5KGspICYmIGlnbm9yZWRfa2V5cy5pbmRleE9mKGspID09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIF9mbGF0dGVuKHRoZV92YXJba10sIHByZWZpeCArICcuLicgKyBrLCBkZXB0aCArIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChpc19hcnJheSh0aGVfdmFyKSkge1xuICAgICAgICAgICAgLy8gSXRlcmF0ZSBhcnJheXNcbiAgICAgICAgICAgIGZsYXRfdmFyW3ByZWZpeF0gPSBbXTtcbiAgICAgICAgICAgIGxldCBpID0gMDtcbiAgICAgICAgICAgIGZvcmVhY2godGhlX3ZhciwgKHYpID0+IHtcbiAgICAgICAgICAgICAgICBfZmxhdHRlbih2LCBwcmVmaXggKyAnLi4nICsgaSwgZGVwdGggKyAxKTtcbiAgICAgICAgICAgICAgICBpKys7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChpc19mdW5jdGlvbih0aGVfdmFyKSkge1xuICAgICAgICAgICAgLy8gbm90aGluZ1xuICAgICAgICB9IGVsc2UgaWYgKCFpc19udW1lcmljKHRoZV92YXIpKSB7XG4gICAgICAgICAgICBmbGF0X3ZhcltwcmVmaXhdID0gU3RyaW5nKHRoZV92YXIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZmxhdF92YXJbcHJlZml4XSA9IHRoZV92YXI7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgX2ZsYXR0ZW4odGhlX3ZhciwgJ18nKTtcblxuICAgIGxldCBzb3J0ZXIgPSBbXTtcblxuICAgIGZvcmVhY2goZmxhdF92YXIsIGZ1bmN0aW9uICh2LCBrKSB7XG4gICAgICAgIHNvcnRlci5wdXNoKFtrLCB2XSk7XG4gICAgfSk7XG5cbiAgICBzb3J0ZXIuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgICByZXR1cm4gYVswXSA+IGJbMF07XG4gICAgfSk7XG5cbiAgICBsZXQganNvbiA9IEpTT04uc3RyaW5naWZ5KHNvcnRlcik7XG5cbiAgICBpZiAoY2FsY19zaGExKSB7XG4gICAgICAgIGxldCBoYXNoZWQgPSBzaGExLnNoYTEoanNvbik7XG4gICAgICAgIHJldHVybiBoYXNoZWQ7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGpzb247XG4gICAgfVxufVxuXG4vKipcbiAqIERlZXAgY29tcGFyaXNvbiBvZiB0d28gdmFsdWVzIChpZ25vcmVzIHByb3BlcnR5IG9yZGVyIGFuZCBmdW5jdGlvbnMpXG4gKiBAcGFyYW0geyp9IGEgLSBGaXJzdCB2YWx1ZSB0byBjb21wYXJlXG4gKiBAcGFyYW0geyp9IGIgLSBTZWNvbmQgdmFsdWUgdG8gY29tcGFyZVxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdmFsdWVzIGFyZSBkZWVwbHkgZXF1YWxcbiAqL1xuZnVuY3Rpb24gZGVlcF9lcXVhbChhLCBiKSB7XG4gICAgcmV0dXJuIGhhc2goYSwgZmFsc2UpID09IGhhc2goYiwgZmFsc2UpO1xufSIsIi8qKlxuICogTXV0ZXggZGVjb3JhdG9yIGZvciBleGNsdXNpdmUgbWV0aG9kIGV4ZWN1dGlvblxuICpcbiAqIFdpdGhvdXQgYXJndW1lbnRzOiBQZXItaW5zdGFuY2UgbG9ja2luZyAoZWFjaCBvYmplY3QgaGFzIGl0cyBvd24gbG9jayBwZXIgbWV0aG9kKVxuICogICBAbXV0ZXhcbiAqICAgYXN5bmMgbXlfbWV0aG9kKCkgeyAuLi4gfVxuICpcbiAqIFdpdGggSUQgYXJndW1lbnQ6IEdsb2JhbCBsb2NraW5nIGJ5IElEIChhbGwgaW5zdGFuY2VzIHNoYXJlIHRoZSBsb2NrKVxuICogICBAbXV0ZXgoJ29wZXJhdGlvbl9uYW1lJylcbiAqICAgYXN5bmMgbXlfbWV0aG9kKCkgeyAuLi4gfVxuICpcbiAqIEBkZWNvcmF0b3JcbiAqIEBwYXJhbSB7c3RyaW5nfSBbZ2xvYmFsX2lkXSAtIE9wdGlvbmFsIGdsb2JhbCBtdXRleCBJRCBmb3IgY3Jvc3MtaW5zdGFuY2UgbG9ja2luZ1xuICovXG5mdW5jdGlvbiBtdXRleChnbG9iYWxfaWQpIHtcbiAgICAvLyBTdG9yYWdlICh1c2luZyBJSUZFcyB0byBrZWVwIFdlYWtNYXAvTWFwIGluIGNsb3N1cmUgc2NvcGUpXG4gICAgY29uc3QgaW5zdGFuY2VfbXV0ZXhlcyA9IChmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKCFtdXRleC5faW5zdGFuY2Vfc3RvcmFnZSkge1xuICAgICAgICAgICAgbXV0ZXguX2luc3RhbmNlX3N0b3JhZ2UgPSBuZXcgV2Vha01hcCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtdXRleC5faW5zdGFuY2Vfc3RvcmFnZTtcbiAgICB9KSgpO1xuXG4gICAgY29uc3QgZ2xvYmFsX211dGV4ZXMgPSAoZnVuY3Rpb24oKSB7XG4gICAgICAgIGlmICghbXV0ZXguX2dsb2JhbF9zdG9yYWdlKSB7XG4gICAgICAgICAgICBtdXRleC5fZ2xvYmFsX3N0b3JhZ2UgPSBuZXcgTWFwKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG11dGV4Ll9nbG9iYWxfc3RvcmFnZTtcbiAgICB9KSgpO1xuXG4gICAgLyoqXG4gICAgICogR2V0IG9yIGNyZWF0ZSBhIG11dGV4IGZvciBhIHNwZWNpZmljIGluc3RhbmNlIGFuZCBtZXRob2RcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRfaW5zdGFuY2VfbXV0ZXgoaW5zdGFuY2UsIG1ldGhvZF9uYW1lKSB7XG4gICAgICAgIGxldCBpbnN0YW5jZV9sb2NrcyA9IGluc3RhbmNlX211dGV4ZXMuZ2V0KGluc3RhbmNlKTtcbiAgICAgICAgaWYgKCFpbnN0YW5jZV9sb2Nrcykge1xuICAgICAgICAgICAgaW5zdGFuY2VfbG9ja3MgPSBuZXcgTWFwKCk7XG4gICAgICAgICAgICBpbnN0YW5jZV9tdXRleGVzLnNldChpbnN0YW5jZSwgaW5zdGFuY2VfbG9ja3MpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGxvY2tfc3RhdGUgPSBpbnN0YW5jZV9sb2Nrcy5nZXQobWV0aG9kX25hbWUpO1xuICAgICAgICBpZiAoIWxvY2tfc3RhdGUpIHtcbiAgICAgICAgICAgIGxvY2tfc3RhdGUgPSB7IGFjdGl2ZTogZmFsc2UsIHF1ZXVlOiBbXSB9O1xuICAgICAgICAgICAgaW5zdGFuY2VfbG9ja3Muc2V0KG1ldGhvZF9uYW1lLCBsb2NrX3N0YXRlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBsb2NrX3N0YXRlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBvciBjcmVhdGUgYSBnbG9iYWwgbXV0ZXggYnkgSURcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRfZ2xvYmFsX211dGV4KGlkKSB7XG4gICAgICAgIGxldCBsb2NrX3N0YXRlID0gZ2xvYmFsX211dGV4ZXMuZ2V0KGlkKTtcbiAgICAgICAgaWYgKCFsb2NrX3N0YXRlKSB7XG4gICAgICAgICAgICBsb2NrX3N0YXRlID0geyBhY3RpdmU6IGZhbHNlLCBxdWV1ZTogW10gfTtcbiAgICAgICAgICAgIGdsb2JhbF9tdXRleGVzLnNldChpZCwgbG9ja19zdGF0ZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGxvY2tfc3RhdGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXhlY3V0ZSB0aGUgbmV4dCBxdWV1ZWQgb3BlcmF0aW9uIGZvciBhIG11dGV4XG4gICAgICovXG4gICAgZnVuY3Rpb24gc2NoZWR1bGVfbmV4dChsb2NrX3N0YXRlKSB7XG4gICAgICAgIGlmIChsb2NrX3N0YXRlLmFjdGl2ZSB8fCBsb2NrX3N0YXRlLnF1ZXVlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgeyBmbiwgcmVzb2x2ZSwgcmVqZWN0IH0gPSBsb2NrX3N0YXRlLnF1ZXVlLnNoaWZ0KCk7XG4gICAgICAgIGxvY2tfc3RhdGUuYWN0aXZlID0gdHJ1ZTtcblxuICAgICAgICBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgICAgICAgLnRoZW4oZm4pXG4gICAgICAgICAgICAudGhlbihyZXNvbHZlLCByZWplY3QpXG4gICAgICAgICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgbG9ja19zdGF0ZS5hY3RpdmUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBzY2hlZHVsZV9uZXh0KGxvY2tfc3RhdGUpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWNxdWlyZSBhIG11dGV4IGxvY2sgYW5kIGV4ZWN1dGUgY2FsbGJhY2tcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBhY3F1aXJlX2xvY2sobG9ja19zdGF0ZSwgZm4pIHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIGxvY2tfc3RhdGUucXVldWUucHVzaCh7IGZuLCByZXNvbHZlLCByZWplY3QgfSk7XG4gICAgICAgICAgICBzY2hlZHVsZV9uZXh0KGxvY2tfc3RhdGUpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBJZiBjYWxsZWQgd2l0aCBhbiBJRCBhcmd1bWVudDogQG11dGV4KCdpZCcpXG4gICAgaWYgKHR5cGVvZiBnbG9iYWxfaWQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbih0YXJnZXQsIGtleSwgZGVzY3JpcHRvcikge1xuICAgICAgICAgICAgY29uc3Qgb3JpZ2luYWxfbWV0aG9kID0gZGVzY3JpcHRvci52YWx1ZTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiBvcmlnaW5hbF9tZXRob2QgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEBtdXRleCBjYW4gb25seSBiZSBhcHBsaWVkIHRvIG1ldGhvZHMgKHRyaWVkIHRvIGFwcGx5IHRvICR7a2V5fSlgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZGVzY3JpcHRvci52YWx1ZSA9IGZ1bmN0aW9uKC4uLmFyZ3MpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBsb2NrX3N0YXRlID0gZ2V0X2dsb2JhbF9tdXRleChnbG9iYWxfaWQpO1xuICAgICAgICAgICAgICAgIHJldHVybiBhY3F1aXJlX2xvY2sobG9ja19zdGF0ZSwgKCkgPT4gb3JpZ2luYWxfbWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3MpKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8vIElmIGNhbGxlZCB3aXRob3V0IGFyZ3VtZW50czogQG11dGV4ICh0YXJnZXQgaXMgdGhlIGZpcnN0IGFyZ3VtZW50KVxuICAgIGNvbnN0IHRhcmdldCA9IGdsb2JhbF9pZDsgIC8vIEluIHRoaXMgY2FzZSwgZmlyc3QgYXJnIGlzIHRhcmdldFxuICAgIGNvbnN0IGtleSA9IGFyZ3VtZW50c1sxXTtcbiAgICBjb25zdCBkZXNjcmlwdG9yID0gYXJndW1lbnRzWzJdO1xuXG4gICAgY29uc3Qgb3JpZ2luYWxfbWV0aG9kID0gZGVzY3JpcHRvci52YWx1ZTtcblxuICAgIGlmICh0eXBlb2Ygb3JpZ2luYWxfbWV0aG9kICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQG11dGV4IGNhbiBvbmx5IGJlIGFwcGxpZWQgdG8gbWV0aG9kcyAodHJpZWQgdG8gYXBwbHkgdG8gJHtrZXl9KWApO1xuICAgIH1cblxuICAgIGRlc2NyaXB0b3IudmFsdWUgPSBmdW5jdGlvbiguLi5hcmdzKSB7XG4gICAgICAgIGNvbnN0IGxvY2tfc3RhdGUgPSBnZXRfaW5zdGFuY2VfbXV0ZXgodGhpcywga2V5KTtcbiAgICAgICAgcmV0dXJuIGFjcXVpcmVfbG9jayhsb2NrX3N0YXRlLCAoKSA9PiBvcmlnaW5hbF9tZXRob2QuYXBwbHkodGhpcywgYXJncykpO1xuICAgIH07XG5cbiAgICByZXR1cm4gZGVzY3JpcHRvcjtcbn1cbiIsIi8qXG4gKiBBc3luYyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgdGhlIFJTcGFkZSBmcmFtZXdvcmsuXG4gKiBUaGVzZSBmdW5jdGlvbnMgaGFuZGxlIGFzeW5jaHJvbm91cyBvcGVyYXRpb25zLCBkZWxheXMsIGRlYm91bmNpbmcsIGFuZCBtdXRleGVzLlxuICovXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEFTWU5DIFVUSUxJVElFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIFBhdXNlcyBleGVjdXRpb24gZm9yIHNwZWNpZmllZCBtaWxsaXNlY29uZHNcbiAqIEBwYXJhbSB7bnVtYmVyfSBbbWlsbGlzZWNvbmRzPTBdIC0gRGVsYXkgaW4gbWlsbGlzZWNvbmRzICgwIHVzZXMgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKVxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciBkZWxheVxuICogQGV4YW1wbGUgYXdhaXQgc2xlZXAoMTAwMCk7IC8vIFdhaXQgMSBzZWNvbmRcbiAqL1xuZnVuY3Rpb24gc2xlZXAobWlsbGlzZWNvbmRzID0gMCkge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICBpZiAobWlsbGlzZWNvbmRzID09IDAgJiYgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKSB7XG4gICAgICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUocmVzb2x2ZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzZXRUaW1lb3V0KHJlc29sdmUsIG1pbGxpc2Vjb25kcyk7XG4gICAgICAgIH1cbiAgICB9KTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVib3VuY2VkIGZ1bmN0aW9uIHdpdGggZXhjbHVzaXZpdHkgYW5kIHByb21pc2UgZmFuLWluXG4gKlxuICogVGhpcyBmdW5jdGlvbiwgd2hlbiBpbnZva2VkLCBpbW1lZGlhdGVseSBydW5zIHRoZSBjYWxsYmFjayBleGNsdXNpdmVseS5cbiAqIEZvciBzdWJzZXF1ZW50IGludm9jYXRpb25zLCBpdCBhcHBsaWVzIGEgZGVsYXkgYmVmb3JlIHJ1bm5pbmcgdGhlIGNhbGxiYWNrIGV4Y2x1c2l2ZWx5IGFnYWluLlxuICogVGhlIGRlbGF5IHN0YXJ0cyBhZnRlciB0aGUgY3VycmVudCBhc3luY2hyb25vdXMgb3BlcmF0aW9uIHJlc29sdmVzLlxuICpcbiAqIElmICdkZWxheScgaXMgc2V0IHRvIDAsIHRoZSBmdW5jdGlvbiB3aWxsIG9ubHkgcHJldmVudCBlbnF1ZXVlaW5nIG11bHRpcGxlIGV4ZWN1dGlvbnMgb2YgdGhlXG4gKiBzYW1lIG1ldGhvZCBtb3JlIHRoYW4gb25jZSwgYnV0IHdpbGwgc3RpbGwgcnVuIHRoZW0gaW1tZWRpYXRlbHkgaW4gYW4gZXhjbHVzaXZlIHNlcXVlbnRpYWwgbWFubmVyLlxuICpcbiAqIFRoZSBtb3N0IHJlY2VudCBpbnZvY2F0aW9uIG9mIHRoZSBmdW5jdGlvbiB3aWxsIGJlIHRoZSBwYXJhbWV0ZXJzIHRoYXQgZ2V0IHBhc3NlZCB0byB0aGUgZnVuY3Rpb25cbiAqIHdoZW4gaXQgaW52b2tlcy5cbiAqXG4gKiBUaGUgZnVuY3Rpb24gcmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBuZXh0IGV4Y2x1c2l2ZSBleGVjdXRpb24gY29tcGxldGVzLlxuICpcbiAqIFVzYWdlIGFzIGZ1bmN0aW9uOlxuICogICBjb25zdCBkZWJvdW5jZWRGbiA9IGRlYm91bmNlKG15RnVuY3Rpb24sIDI1MCk7XG4gKlxuICogVXNhZ2UgYXMgZGVjb3JhdG9yOlxuICogICBAZGVib3VuY2UoMjUwKVxuICogICBteU1ldGhvZCgpIHsgLi4uIH1cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufG51bWJlcn0gY2FsbGJhY2tfb3JfZGVsYXkgVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIE9SIGRlbGF5IHdoZW4gdXNlZCBhcyBkZWNvcmF0b3JcbiAqIEBwYXJhbSB7bnVtYmVyfSBkZWxheSBUaGUgZGVsYXkgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSBzdWJzZXF1ZW50IGludm9jYXRpb25zXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGltbWVkaWF0ZSBpZiB0cnVlLCB0aGUgZmlyc3QgdGltZSB0aGUgYWN0aW9uIGlzIGNhbGxlZCwgdGhlIGNhbGxiYWNrIGV4ZWN1dGVzIGltbWVkaWF0ZWx5XG4gKiBAcmV0dXJucyB7ZnVuY3Rpb259IEEgZnVuY3Rpb24gdGhhdCB3aGVuIGludm9rZWQsIHJ1bnMgdGhlIGNhbGxiYWNrIGltbWVkaWF0ZWx5IGFuZCBleGNsdXNpdmVseSxcbiAqXG4gKiBAZGVjb3JhdG9yXG4gKi9cbmZ1bmN0aW9uIGRlYm91bmNlKGNhbGxiYWNrX29yX2RlbGF5LCBkZWxheSwgaW1tZWRpYXRlID0gZmFsc2UpIHtcbiAgICAvLyBEZWNvcmF0b3IgdXNhZ2U6IEBkZWJvdW5jZSgyNTApIG9yIEBkZWJvdW5jZSgyNTAsIHRydWUpXG4gICAgLy8gRmlyc3QgYXJndW1lbnQgaXMgYSBudW1iZXIgKHRoZSBkZWxheSksIHJldHVybnMgZGVjb3JhdG9yIGZ1bmN0aW9uXG4gICAgaWYgKHR5cGVvZiBjYWxsYmFja19vcl9kZWxheSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgY29uc3QgZGVjb3JhdG9yX2RlbGF5ID0gY2FsbGJhY2tfb3JfZGVsYXk7XG4gICAgICAgIGNvbnN0IGRlY29yYXRvcl9pbW1lZGlhdGUgPSBkZWxheSB8fCBmYWxzZTtcblxuICAgICAgICAvLyBUQzM5IGRlY29yYXRvciBmb3JtOiByZWNlaXZlcyAodmFsdWUsIGNvbnRleHQpXG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAodmFsdWUsIGNvbnRleHQpIHtcbiAgICAgICAgICAgIGlmIChjb250ZXh0LmtpbmQgPT09ICdtZXRob2QnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRlYm91bmNlX2ltcGwodmFsdWUsIGRlY29yYXRvcl9kZWxheSwgZGVjb3JhdG9yX2ltbWVkaWF0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gRnVuY3Rpb24gdXNhZ2U6IGRlYm91bmNlKGZuLCAyNTApXG4gICAgLy8gRmlyc3QgYXJndW1lbnQgaXMgYSBmdW5jdGlvbiAodGhlIGNhbGxiYWNrKVxuICAgIGNvbnN0IGNhbGxiYWNrID0gY2FsbGJhY2tfb3JfZGVsYXk7XG4gICAgcmV0dXJuIGRlYm91bmNlX2ltcGwoY2FsbGJhY2ssIGRlbGF5LCBpbW1lZGlhdGUpO1xufVxuXG4vKipcbiAqIEludGVybmFsIGltcGxlbWVudGF0aW9uIG9mIGRlYm91bmNlIGxvZ2ljXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBkZWJvdW5jZV9pbXBsKGNhbGxiYWNrLCBkZWxheSwgaW1tZWRpYXRlID0gZmFsc2UpIHtcbiAgICBsZXQgcnVubmluZyA9IGZhbHNlO1xuICAgIGxldCBxdWV1ZWQgPSBmYWxzZTtcbiAgICBsZXQgbGFzdF9lbmRfdGltZSA9IDA7IC8vIHRpbWVzdGFtcCBvZiBsYXN0IGNvbXBsZXRlZCBydW5cbiAgICBsZXQgdGltZXIgPSBudWxsO1xuXG4gICAgbGV0IG5leHRfYXJncyA9IFtdO1xuICAgIGxldCBuZXh0X2NvbnRleHQgPSBudWxsO1xuICAgIGxldCByZXNvbHZlX3F1ZXVlID0gW107XG4gICAgbGV0IHJlamVjdF9xdWV1ZSA9IFtdO1xuXG4gICAgY29uc3QgcnVuX2Z1bmN0aW9uID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCB0aGVzZV9yZXNvbHZlcyA9IHJlc29sdmVfcXVldWU7XG4gICAgICAgIGNvbnN0IHRoZXNlX3JlamVjdHMgPSByZWplY3RfcXVldWU7XG4gICAgICAgIGNvbnN0IGFyZ3MgPSBuZXh0X2FyZ3M7XG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSBuZXh0X2NvbnRleHQ7XG5cbiAgICAgICAgcmVzb2x2ZV9xdWV1ZSA9IFtdO1xuICAgICAgICByZWplY3RfcXVldWUgPSBbXTtcbiAgICAgICAgbmV4dF9hcmdzID0gW107XG4gICAgICAgIG5leHRfY29udGV4dCA9IG51bGw7XG4gICAgICAgIHF1ZXVlZCA9IGZhbHNlO1xuICAgICAgICBydW5uaW5nID0gdHJ1ZTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY2FsbGJhY2suYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHJlc29sdmUgb2YgdGhlc2VfcmVzb2x2ZXMpIHJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHJlamVjdCBvZiB0aGVzZV9yZWplY3RzKSByZWplY3QoZXJyKTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIHJ1bm5pbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIGxhc3RfZW5kX3RpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgaWYgKHF1ZXVlZCkge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gICAgICAgICAgICAgICAgdGltZXIgPSBzZXRUaW1lb3V0KHJ1bl9mdW5jdGlvbiwgTWF0aC5tYXgoZGVsYXksIDApKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGltZXIgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiBmdW5jdGlvbiAoLi4uYXJncykge1xuICAgICAgICBuZXh0X2FyZ3MgPSBhcmdzO1xuICAgICAgICBuZXh0X2NvbnRleHQgPSB0aGlzO1xuXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICByZXNvbHZlX3F1ZXVlLnB1c2gocmVzb2x2ZSk7XG4gICAgICAgICAgICByZWplY3RfcXVldWUucHVzaChyZWplY3QpO1xuXG4gICAgICAgICAgICAvLyBOb3RoaW5nIHJ1bm5pbmcgYW5kIG5vdGhpbmcgc2NoZWR1bGVkXG4gICAgICAgICAgICBpZiAoIXJ1bm5pbmcgJiYgIXRpbWVyKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZmlyc3RfY2FsbCA9IGxhc3RfZW5kX3RpbWUgPT09IDA7XG5cbiAgICAgICAgICAgICAgICBpZiAoaW1tZWRpYXRlICYmIGZpcnN0X2NhbGwpIHtcbiAgICAgICAgICAgICAgICAgICAgcnVuX2Z1bmN0aW9uKCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjb25zdCBzaW5jZSA9IGZpcnN0X2NhbGwgPyBJbmZpbml0eSA6IERhdGUubm93KCkgLSBsYXN0X2VuZF90aW1lO1xuICAgICAgICAgICAgICAgIGlmIChzaW5jZSA+PSBkZWxheSkge1xuICAgICAgICAgICAgICAgICAgICBydW5fZnVuY3Rpb24oKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB3YWl0ID0gTWF0aC5tYXgoZGVsYXkgLSBzaW5jZSwgMCk7XG4gICAgICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gICAgICAgICAgICAgICAgICAgIHRpbWVyID0gc2V0VGltZW91dChydW5fZnVuY3Rpb24sIHdhaXQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIElmIHdlJ3JlIGFscmVhZHkgcnVubmluZyBvciBhIHRpbWVyIGV4aXN0cywganVzdCBtYXJrIHF1ZXVlZC5cbiAgICAgICAgICAgIC8vIFRoZSBmaW5hbGx5e30gb2YgcnVuX2Z1bmN0aW9uIGhhbmRsZXMgc2NoZWR1bGluZyBhZnRlciBmdWxsIGRlbGF5LlxuICAgICAgICAgICAgcXVldWVkID0gdHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgfTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUkVBRC1XUklURSBMT0NLIEZVTkNUSU9OUyAtIERlbGVnYXRlZCB0byBSZWFkV3JpdGVMb2NrIGNsYXNzXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQWNxdWlyZSBhbiBleGNsdXNpdmUgd3JpdGUgbG9jayBieSBuYW1lLlxuICogT25seSBvbmUgd3JpdGVyIHJ1bnMgYXQgYSB0aW1lOyBibG9ja3MgcmVhZGVycyB1bnRpbCBmaW5pc2hlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gKiBAcGFyYW0geygpID0+IGFueXxQcm9taXNlPGFueT59IGNiXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxhbnk+fVxuICovXG5mdW5jdGlvbiByd2xvY2sobmFtZSwgY2IpIHtcbiAgICByZXR1cm4gUmVhZFdyaXRlTG9jay5hY3F1aXJlKG5hbWUsIGNiKTtcbn1cblxuLyoqXG4gKiBBY3F1aXJlIGEgc2hhcmVkIHJlYWQgbG9jayBieSBuYW1lLlxuICogTXVsdGlwbGUgcmVhZGVycyBydW4gaW4gcGFyYWxsZWwsIGJ1dCByZWFkZXJzIGFyZSBibG9ja2VkIGJ5IHF1ZXVlZC9hY3RpdmUgd3JpdGVycy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gKiBAcGFyYW0geygpID0+IGFueXxQcm9taXNlPGFueT59IGNiXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxhbnk+fVxuICovXG5mdW5jdGlvbiByd2xvY2tfcmVhZChuYW1lLCBjYikge1xuICAgIHJldHVybiBSZWFkV3JpdGVMb2NrLmFjcXVpcmVfcmVhZChuYW1lLCBjYik7XG59XG5cbi8qKlxuICogRm9yY2VmdWxseSBjbGVhciBhbGwgbG9ja3MgYW5kIHF1ZXVlcyBmb3IgYSBnaXZlbiBuYW1lLlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAqL1xuZnVuY3Rpb24gcndsb2NrX2ZvcmNlX3VubG9jayhuYW1lKSB7XG4gICAgUmVhZFdyaXRlTG9jay5mb3JjZV91bmxvY2sobmFtZSk7XG59XG5cbi8qKlxuICogSW5zcGVjdCBsb2NrIHN0YXRlIGZvciBkZWJ1Z2dpbmcuXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZVxuICogQHJldHVybnMge3tyZWFkZXJzOm51bWJlciwgd3JpdGVyX2FjdGl2ZTpib29sZWFuLCByZWFkZXJfcTpudW1iZXIsIHdyaXRlcl9xOm51bWJlcn19XG4gKi9cbmZ1bmN0aW9uIHJ3bG9ja19wZW5kaW5nKG5hbWUpIHtcbiAgICByZXR1cm4gUmVhZFdyaXRlTG9jay5wZW5kaW5nKG5hbWUpO1xufVxuIiwiLypcbiAqIENvcmUgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHRoZSBSU3BhZGUgZnJhbWV3b3JrLlxuICogVGhlc2UgZnVuY3Rpb25zIGhhbmRsZSB0eXBlIGNoZWNraW5nLCB0eXBlIGNvbnZlcnNpb24sIHN0cmluZyBtYW5pcHVsYXRpb24sXG4gKiBhbmQgb2JqZWN0L2FycmF5IHV0aWxpdGllcy4gVGhleSBtaXJyb3IgZnVuY3Rpb25hbGl0eSBmcm9tIFBIUCBmdW5jdGlvbnMuXG4gKlxuICogT3RoZXIgdXRpbGl0eSBmdW5jdGlvbnMgYXJlIG9yZ2FuaXplZCBpbjpcbiAqIC0gYXN5bmMuanM6IEFzeW5jIHV0aWxpdGllcyAoc2xlZXAsIGRlYm91bmNlLCBtdXRleClcbiAqIC0gYnJvd3Nlci5qczogQnJvd3Nlci9ET00gdXRpbGl0aWVzIChpc19tb2JpbGUsIHNjcm9sbCBmdW5jdGlvbnMpXG4gKiAtIGRhdGV0aW1lLmpzOiBEYXRlL3RpbWUgdXRpbGl0aWVzXG4gKiAtIGhhc2guanM6IEhhc2hpbmcgYW5kIGNvbXBhcmlzb25cbiAqIC0gZXJyb3IuanM6IEVycm9yIGhhbmRsaW5nXG4gKi9cblxuLy8gVG9kbzogdGVzdCB0aGF0IHByb2QgYnVpbGQgaWRlbnRpZmllcyBhbmQgcmVtb3ZlcyB1bmNhbGxlZCBmdW5jdGlvbnMgZnJvbSB0aGUgZmluYWwgYnVuZGxlLlxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBDT05TVEFOVFMgQU5EIEhFTFBFUlNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLy8gRGVmaW5lIGNvbW1vbmx5IHVzZWQgY29uc3RhbnRzXG5jb25zdCB1bmRlZiA9ICd1bmRlZmluZWQnO1xuXG4vKipcbiAqIEl0ZXJhdGVzIG92ZXIgYXJyYXlzIG9yIG9iamVjdHMgd2l0aCBwcm9taXNlIHN1cHBvcnRcbiAqXG4gKiBXb3JrcyB3aXRoIGJvdGggc3luY2hyb25vdXMgYW5kIGFzeW5jaHJvbm91cyBjYWxsYmFja3MuIElmIHRoZSBjYWxsYmFja1xuICogcmV0dXJucyBwcm9taXNlcywgdGhleSBhcmUgZXhlY3V0ZWQgaW4gcGFyYWxsZWwgYW5kIHRoaXMgZnVuY3Rpb24gcmV0dXJuc1xuICogYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBhbGwgcGFyYWxsZWwgdGFza3MgY29tcGxldGUuXG4gKlxuICogQHBhcmFtIHtBcnJheXxPYmplY3R9IG9iaiAtIENvbGxlY3Rpb24gdG8gaXRlcmF0ZVxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgLSBGdW5jdGlvbiB0byBjYWxsIGZvciBlYWNoIGl0ZW0gKHZhbHVlLCBrZXkpIC0gY2FuIGJlIGFzeW5jXG4gKiBAcmV0dXJucyB7UHJvbWlzZXx1bmRlZmluZWR9IFByb21pc2UgaWYgYW55IGNhbGxiYWNrcyByZXR1cm4gcHJvbWlzZXMsIHVuZGVmaW5lZCBvdGhlcndpc2VcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gU3luY2hyb25vdXMgdXNhZ2VcbiAqIGZvcmVhY2goWzEsMiwzXSwgKHZhbCkgPT4gY29uc29sZS5sb2codmFsKSk7XG4gKlxuICogQGV4YW1wbGVcbiAqIC8vIEFzeW5jaHJvbm91cyB1c2FnZSAtIHdhaXRzIGZvciBhbGwgdG8gY29tcGxldGVcbiAqIGF3YWl0IGZvcmVhY2goWzEsMiwzXSwgYXN5bmMgKHZhbCkgPT4ge1xuICogICAgIGF3YWl0IGZldGNoKCcvYXBpL3Byb2Nlc3MvJyArIHZhbCk7XG4gKiB9KTtcbiAqL1xuZnVuY3Rpb24gZm9yZWFjaChvYmosIGNhbGxiYWNrKSB7XG4gICAgY29uc3QgcmVzdWx0cyA9IFtdO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgICAgICBvYmouZm9yRWFjaCgodmFsdWUsIGluZGV4KSA9PiB7XG4gICAgICAgICAgICByZXN1bHRzLnB1c2goY2FsbGJhY2sodmFsdWUsIGluZGV4KSk7XG4gICAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAob2JqICYmIHR5cGVvZiBvYmogPT09ICdvYmplY3QnKSB7XG4gICAgICAgIGZvciAobGV0IGtleSBpbiBvYmopIHtcbiAgICAgICAgICAgIGlmIChvYmouaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgICAgIHJlc3VsdHMucHVzaChjYWxsYmFjayhvYmpba2V5XSwga2V5KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBGaWx0ZXIgZm9yIHByb21pc2VzXG4gICAgY29uc3QgcHJvbWlzZXMgPSByZXN1bHRzLmZpbHRlcigocmVzdWx0KSA9PiByZXN1bHQgJiYgdHlwZW9mIHJlc3VsdC50aGVuID09PSAnZnVuY3Rpb24nKTtcblxuICAgIC8vIElmIHRoZXJlIGFyZSBhbnkgcHJvbWlzZXMsIHJldHVybiBQcm9taXNlLmFsbCB0byB3YWl0IGZvciBhbGwgdG8gY29tcGxldGVcbiAgICBpZiAocHJvbWlzZXMubGVuZ3RoID4gMCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuICAgIH1cblxuICAgIC8vIE5vIHByb21pc2VzIHJldHVybmVkLCBzbyB3ZSdyZSBkb25lXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUWVBFIENIRUNLSU5HIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIG51bWVyaWNcbiAqIEBwYXJhbSB7Kn0gbiAtIFZhbHVlIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgdmFsdWUgaXMgYSBmaW5pdGUgbnVtYmVyXG4gKi9cbmZ1bmN0aW9uIGlzX251bWVyaWMobikge1xuICAgIHJldHVybiAhaXNOYU4ocGFyc2VGbG9hdChuKSkgJiYgaXNGaW5pdGUobik7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYSBzdHJpbmdcbiAqIEBwYXJhbSB7Kn0gcyAtIFZhbHVlIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgdmFsdWUgaXMgYSBzdHJpbmdcbiAqL1xuZnVuY3Rpb24gaXNfc3RyaW5nKHMpIHtcbiAgICByZXR1cm4gdHlwZW9mIHMgPT0gJ3N0cmluZyc7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYW4gaW50ZWdlclxuICogQHBhcmFtIHsqfSBuIC0gVmFsdWUgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB2YWx1ZSBpcyBhbiBpbnRlZ2VyXG4gKi9cbmZ1bmN0aW9uIGlzX2ludGVnZXIobikge1xuICAgIHJldHVybiBOdW1iZXIuaXNJbnRlZ2VyKG4pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGEgcHJvbWlzZS1saWtlIG9iamVjdFxuICogQHBhcmFtIHsqfSBvYmogLSBWYWx1ZSB0byBjaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIHZhbHVlIGhhcyBhIHRoZW4gbWV0aG9kXG4gKi9cbmZ1bmN0aW9uIGlzX3Byb21pc2Uob2JqKSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmogPT0gJ29iamVjdCcgJiYgdHlwZW9mIG9iai50aGVuID09ICdmdW5jdGlvbic7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYW4gYXJyYXlcbiAqIEBwYXJhbSB7Kn0gb2JqIC0gVmFsdWUgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB2YWx1ZSBpcyBhbiBhcnJheVxuICovXG5mdW5jdGlvbiBpc19hcnJheShvYmopIHtcbiAgICByZXR1cm4gQXJyYXkuaXNBcnJheShvYmopO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGFuIG9iamVjdCAoZXhjbHVkZXMgbnVsbClcbiAqIEBwYXJhbSB7Kn0gb2JqIC0gVmFsdWUgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB2YWx1ZSBpcyBhbiBvYmplY3QgYW5kIG5vdCBudWxsXG4gKi9cbmZ1bmN0aW9uIGlzX29iamVjdChvYmopIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iaiA9PT0gJ29iamVjdCcgJiYgb2JqICE9PSBudWxsO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHZhbHVlIGlzIGEgZnVuY3Rpb25cbiAqIEBwYXJhbSB7Kn0gZnVuY3Rpb25fdG9fY2hlY2sgLSBWYWx1ZSB0byBjaGVja1xuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIHZhbHVlIGlzIGEgZnVuY3Rpb25cbiAqL1xuZnVuY3Rpb24gaXNfZnVuY3Rpb24oZnVuY3Rpb25fdG9fY2hlY2spIHtcbiAgICByZXR1cm4gZnVuY3Rpb25fdG9fY2hlY2sgJiYge30udG9TdHJpbmcuY2FsbChmdW5jdGlvbl90b19jaGVjaykgPT09ICdbb2JqZWN0IEZ1bmN0aW9uXSc7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgc3RyaW5nIGlzIGEgdmFsaWQgZW1haWwgYWRkcmVzc1xuICogVXNlcyBhIHByYWN0aWNhbCBSRkMgNTMyMiBjb21wbGlhbnQgcmVnZXggdGhhdCBtYXRjaGVzIDk5Ljk5JSBvZiByZWFsLXdvcmxkIGVtYWlsIGFkZHJlc3Nlc1xuICogQHBhcmFtIHtzdHJpbmd9IGVtYWlsIC0gRW1haWwgYWRkcmVzcyB0byB2YWxpZGF0ZVxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIHN0cmluZyBpcyBhIHZhbGlkIGVtYWlsIGFkZHJlc3NcbiAqL1xuZnVuY3Rpb24gaXNfZW1haWwoZW1haWwpIHtcbiAgICBpZiAoIWlzX3N0cmluZyhlbWFpbCkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCByZWdleCA9IC9eW2EtejAtOSEjJCUmJyorLz0/Xl9ge3x9fi1dKyg/OlxcLlthLXowLTkhIyQlJicqKy89P15fYHt8fX4tXSspKkAoPzpbYS16MC05XSg/OlthLXowLTktXSpbYS16MC05XSk/XFwuKStbYS16MC05XSg/OlthLXowLTktXSpbYS16MC05XSk/JC9pO1xuICAgIHJldHVybiByZWdleC50ZXN0KGVtYWlsKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSB2YWx1ZSBpcyBkZWZpbmVkIChub3QgdW5kZWZpbmVkKVxuICogQHBhcmFtIHsqfSB2YWx1ZSAtIFZhbHVlIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB2YWx1ZSBpcyBub3QgdW5kZWZpbmVkXG4gKi9cbmZ1bmN0aW9uIGlzc2V0KHZhbHVlKSB7XG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSAhPSB1bmRlZjtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSB2YWx1ZSBpcyBlbXB0eSAobnVsbCwgdW5kZWZpbmVkLCAwLCBcIlwiLCBlbXB0eSBhcnJheS9vYmplY3QpXG4gKiBAcGFyYW0geyp9IG9iamVjdCAtIFZhbHVlIHRvIGNoZWNrXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgdmFsdWUgaXMgY29uc2lkZXJlZCBlbXB0eVxuICovXG5mdW5jdGlvbiBlbXB0eShvYmplY3QpIHtcbiAgICBpZiAodHlwZW9mIG9iamVjdCA9PSB1bmRlZikge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKG9iamVjdCA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBvYmplY3QgPT0gJ3N0cmluZycgJiYgb2JqZWN0ID09ICcnKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIG9iamVjdCA9PSAnbnVtYmVyJykge1xuICAgICAgICByZXR1cm4gb2JqZWN0ID09IDA7XG4gICAgfVxuICAgIGlmIChBcnJheS5pc0FycmF5KG9iamVjdCkpIHtcbiAgICAgICAgcmV0dXJuICFvYmplY3QubGVuZ3RoO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIG9iamVjdCA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZm9yIChsZXQga2V5IGluIG9iamVjdCkge1xuICAgICAgICBpZiAob2JqZWN0Lmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gVFlQRSBDT05WRVJTSU9OIEZVTkNUSU9OU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBmbG9hdGluZyBwb2ludCBudW1iZXJcbiAqIFJldHVybnMgMCBmb3IgbnVsbCwgdW5kZWZpbmVkLCBOYU4sIG9yIG5vbi1udW1lcmljIHZhbHVlc1xuICogQHBhcmFtIHsqfSB2YWwgLSBWYWx1ZSB0byBjb252ZXJ0XG4gKiBAcmV0dXJucyB7bnVtYmVyfSBGbG9hdGluZyBwb2ludCBudW1iZXJcbiAqL1xuZnVuY3Rpb24gZmxvYXQodmFsKSB7XG4gICAgLy8gSGFuZGxlIG51bGwsIHVuZGVmaW5lZCwgZW1wdHkgc3RyaW5nXG4gICAgaWYgKHZhbCA9PT0gbnVsbCB8fCB2YWwgPT09IHVuZGVmaW5lZCB8fCB2YWwgPT09ICcnKSB7XG4gICAgICAgIHJldHVybiAwLjA7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRoZSB2YWx1ZVxuICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlRmxvYXQodmFsKTtcblxuICAgIC8vIENoZWNrIGZvciBOYU4gYW5kIHJldHVybiAwIGlmIHBhcnNpbmcgZmFpbGVkXG4gICAgcmV0dXJuIGlzTmFOKHBhcnNlZCkgPyAwLjAgOiBwYXJzZWQ7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhbiBpbnRlZ2VyXG4gKiBSZXR1cm5zIDAgZm9yIG51bGwsIHVuZGVmaW5lZCwgTmFOLCBvciBub24tbnVtZXJpYyB2YWx1ZXNcbiAqIEBwYXJhbSB7Kn0gdmFsIC0gVmFsdWUgdG8gY29udmVydFxuICogQHJldHVybnMge251bWJlcn0gSW50ZWdlciB2YWx1ZVxuICovXG5mdW5jdGlvbiBpbnQodmFsKSB7XG4gICAgLy8gSGFuZGxlIG51bGwsIHVuZGVmaW5lZCwgZW1wdHkgc3RyaW5nXG4gICAgaWYgKHZhbCA9PT0gbnVsbCB8fCB2YWwgPT09IHVuZGVmaW5lZCB8fCB2YWwgPT09ICcnKSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cblxuICAgIC8vIFRyeSB0byBwYXJzZSB0aGUgdmFsdWVcbiAgICBjb25zdCBwYXJzZWQgPSBwYXJzZUludCh2YWwsIDEwKTtcblxuICAgIC8vIENoZWNrIGZvciBOYU4gYW5kIHJldHVybiAwIGlmIHBhcnNpbmcgZmFpbGVkXG4gICAgcmV0dXJuIGlzTmFOKHBhcnNlZCkgPyAwIDogcGFyc2VkO1xufVxuXG4vKipcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBzdHJpbmdcbiAqIFJldHVybnMgZW1wdHkgc3RyaW5nIGZvciBudWxsIG9yIHVuZGVmaW5lZFxuICogQHBhcmFtIHsqfSB2YWwgLSBWYWx1ZSB0byBjb252ZXJ0XG4gKiBAcmV0dXJucyB7c3RyaW5nfSBTdHJpbmcgcmVwcmVzZW50YXRpb25cbiAqL1xuZnVuY3Rpb24gc3RyKHZhbCkge1xuICAgIC8vIEhhbmRsZSBudWxsIGFuZCB1bmRlZmluZWQgc3BlY2lhbGx5XG4gICAgaWYgKHZhbCA9PT0gbnVsbCB8fCB2YWwgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgLy8gQ29udmVydCB0byBzdHJpbmdcbiAgICByZXR1cm4gU3RyaW5nKHZhbCk7XG59XG5cbi8qKlxuICogQ29udmVydHMgbnVtZXJpYyBzdHJpbmdzIHRvIG51bWJlcnMsIHJldHVybnMgYWxsIG90aGVyIHZhbHVlcyB1bmNoYW5nZWRcbiAqIFVzZWQgd2hlbiB5b3UgbmVlZCB0byBlbnN1cmUgbnVtZXJpYyB0eXBlcyBidXQgZG9uJ3Qgd2FudCB0byBmb3JjZVxuICogY29udmVyc2lvbiBvZiBub24tbnVtZXJpYyB2YWx1ZXMgKHdoaWNoIHdvdWxkIGJlY29tZSAwKVxuICogQHBhcmFtIHsqfSB2YWwgLSBWYWx1ZSB0byBjb252ZXJ0XG4gKiBAcmV0dXJucyB7Kn0gTnVtYmVyIGlmIGlucHV0IHdhcyBudW1lcmljIHN0cmluZywgb3RoZXJ3aXNlIHVuY2hhbmdlZFxuICovXG5mdW5jdGlvbiB2YWx1ZV91bmxlc3NfbnVtZXJpY19zdHJpbmdfdGhlbl9udW1lcmljX3ZhbHVlKHZhbCkge1xuICAgIC8vIElmIGl0J3MgYWxyZWFkeSBhIG51bWJlciwgcmV0dXJuIGl0XG4gICAgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKSB7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfVxuXG4gICAgLy8gSWYgaXQncyBhIHN0cmluZyBhbmQgbnVtZXJpYywgY29udmVydCBpdFxuICAgIGlmIChpc19zdHJpbmcodmFsKSAmJiBpc19udW1lcmljKHZhbCkpIHtcbiAgICAgICAgLy8gVXNlIHBhcnNlRmxvYXQgdG8gaGFuZGxlIGJvdGggaW50ZWdlcnMgYW5kIGZsb2F0c1xuICAgICAgICByZXR1cm4gcGFyc2VGbG9hdCh2YWwpO1xuICAgIH1cblxuICAgIC8vIFJldHVybiBldmVyeXRoaW5nIGVsc2UgdW5jaGFuZ2VkIChudWxsLCBvYmplY3RzLCBub24tbnVtZXJpYyBzdHJpbmdzLCBldGMuKVxuICAgIHJldHVybiB2YWw7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFNUUklORyBNQU5JUFVMQVRJT04gRlVOQ1RJT05TXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogRXNjYXBlcyBIVE1MIHNwZWNpYWwgY2hhcmFjdGVycyAodXNlcyBMb2Rhc2ggZXNjYXBlKVxuICogQHBhcmFtIHtzdHJpbmd9IHN0ciAtIFN0cmluZyB0byBlc2NhcGVcbiAqIEByZXR1cm5zIHtzdHJpbmd9IEhUTUwtZXNjYXBlZCBzdHJpbmdcbiAqL1xuZnVuY3Rpb24gaHRtbChzdHIpIHtcbiAgICByZXR1cm4gXy5lc2NhcGUoc3RyKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0cyBuZXdsaW5lcyB0byBIVE1MIGxpbmUgYnJlYWtzXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyIC0gU3RyaW5nIHRvIGNvbnZlcnRcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFN0cmluZyB3aXRoIG5ld2xpbmVzIHJlcGxhY2VkIGJ5IDxiciAvPlxuICovXG5mdW5jdGlvbiBubDJicihzdHIpIHtcbiAgICBpZiAodHlwZW9mIHN0ciA9PT0gdW5kZWYgfHwgc3RyID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG4gICAgcmV0dXJuIChzdHIgKyAnJykucmVwbGFjZSgvKFtePlxcclxcbl0/KShcXHJcXG58XFxuXFxyfFxccnxcXG4pL2csICckMTxiciAvPiQyJyk7XG59XG5cbi8qKlxuICogRXNjYXBlcyBIVE1MIGFuZCBjb252ZXJ0cyBuZXdsaW5lcyB0byA8YnIgLz5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHIgLSBTdHJpbmcgdG8gcHJvY2Vzc1xuICogQHJldHVybnMge3N0cmluZ30gSFRNTC1lc2NhcGVkIHN0cmluZyB3aXRoIGxpbmUgYnJlYWtzXG4gKi9cbmZ1bmN0aW9uIGh0bWxicihzdHIpIHtcbiAgICByZXR1cm4gbmwyYnIoaHRtbChzdHIpKTtcbn1cblxuLyoqXG4gKiBVUkwtZW5jb2RlcyBhIHN0cmluZ1xuICogQHBhcmFtIHtzdHJpbmd9IHN0ciAtIFN0cmluZyB0byBlbmNvZGVcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFVSTC1lbmNvZGVkIHN0cmluZ1xuICovXG5mdW5jdGlvbiB1cmxlbmNvZGUoc3RyKSB7XG4gICAgcmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChzdHIpO1xufVxuXG4vKipcbiAqIFVSTC1kZWNvZGVzIGEgc3RyaW5nXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyIC0gU3RyaW5nIHRvIGRlY29kZVxuICogQHJldHVybnMge3N0cmluZ30gVVJMLWRlY29kZWQgc3RyaW5nXG4gKi9cbmZ1bmN0aW9uIHVybGRlY29kZShzdHIpIHtcbiAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KHN0cik7XG59XG5cbi8qKlxuICogSlNPTi1lbmNvZGVzIGEgdmFsdWVcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgLSBWYWx1ZSB0byBlbmNvZGVcbiAqIEByZXR1cm5zIHtzdHJpbmd9IEpTT04gc3RyaW5nXG4gKi9cbmZ1bmN0aW9uIGpzb25fZW5jb2RlKHZhbHVlKSB7XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbn1cblxuLyoqXG4gKiBKU09OLWRlY29kZXMgYSBzdHJpbmdcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHIgLSBKU09OIHN0cmluZyB0byBkZWNvZGVcbiAqIEByZXR1cm5zIHsqfSBEZWNvZGVkIHZhbHVlXG4gKi9cbmZ1bmN0aW9uIGpzb25fZGVjb2RlKHN0cikge1xuICAgIHJldHVybiBKU09OLnBhcnNlKHN0cik7XG59XG5cbi8qKlxuICogQ29uc29sZSBkZWJ1ZyBvdXRwdXQgd2l0aCBjaGFubmVsIGZpbHRlcmluZ1xuICogQWxpYXMgZm9yIERlYnVnZ2VyLmNvbnNvbGVfZGVidWdcbiAqIEBwYXJhbSB7c3RyaW5nfSBjaGFubmVsIC0gRGVidWcgY2hhbm5lbCBuYW1lXG4gKiBAcGFyYW0gey4uLip9IHZhbHVlcyAtIFZhbHVlcyB0byBsb2dcbiAqL1xuZnVuY3Rpb24gY29uc29sZV9kZWJ1ZyhjaGFubmVsLCAuLi52YWx1ZXMpIHtcbiAgICBEZWJ1Z2dlci5jb25zb2xlX2RlYnVnKGNoYW5uZWwsIC4uLnZhbHVlcyk7XG59XG5cbi8qKlxuICogUmVwbGFjZXMgYWxsIG9jY3VycmVuY2VzIG9mIGEgc3Vic3RyaW5nIGluIGEgc3RyaW5nXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nIC0gU3RyaW5nIHRvIHNlYXJjaCBpblxuICogQHBhcmFtIHtzdHJpbmd9IHNlYXJjaCAtIFN1YnN0cmluZyB0byBmaW5kXG4gKiBAcGFyYW0ge3N0cmluZ30gcmVwbGFjZSAtIFJlcGxhY2VtZW50IHN1YnN0cmluZ1xuICogQHJldHVybnMge3N0cmluZ30gU3RyaW5nIHdpdGggYWxsIG9jY3VycmVuY2VzIHJlcGxhY2VkXG4gKi9cbmZ1bmN0aW9uIHJlcGxhY2VfYWxsKHN0cmluZywgc2VhcmNoLCByZXBsYWNlKSB7XG4gICAgaWYgKCFpc19zdHJpbmcoc3RyaW5nKSkge1xuICAgICAgICBzdHJpbmcgPSBzdHJpbmcgKyAnJztcbiAgICB9XG4gICAgcmV0dXJuIHN0cmluZy5zcGxpdChzZWFyY2gpLmpvaW4ocmVwbGFjZSk7XG59XG5cbi8qKlxuICogQ2FwaXRhbGl6ZXMgdGhlIGZpcnN0IGxldHRlciBvZiBlYWNoIHdvcmRcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFN0cmluZyB0byBjYXBpdGFsaXplXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBTdHJpbmcgd2l0aCBmaXJzdCBsZXR0ZXIgb2YgZWFjaCB3b3JkIGNhcGl0YWxpemVkXG4gKi9cbmZ1bmN0aW9uIHVjd29yZHMoaW5wdXQpIHtcbiAgICByZXR1cm4gaW5wdXRcbiAgICAgICAgLnNwbGl0KCcgJylcbiAgICAgICAgLm1hcCgod29yZCkgPT4gd29yZC5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIHdvcmQuc2xpY2UoMSkpXG4gICAgICAgIC5qb2luKCcgJyk7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIE9CSkVDVCBBTkQgQVJSQVkgVVRJTElUSUVTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQ291bnRzIHRoZSBudW1iZXIgb2YgcHJvcGVydGllcyBpbiBhbiBvYmplY3Qgb3IgZWxlbWVudHMgaW4gYW4gYXJyYXlcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvIC0gT2JqZWN0IG9yIGFycmF5IHRvIGNvdW50XG4gKiBAcmV0dXJucyB7bnVtYmVyfSBOdW1iZXIgb2Ygb3duIHByb3BlcnRpZXMvZWxlbWVudHNcbiAqL1xuZnVuY3Rpb24gY291bnQobykge1xuICAgIGxldCBjID0gMDtcbiAgICBmb3IgKGNvbnN0IGsgaW4gbykge1xuICAgICAgICBpZiAoby5oYXNPd25Qcm9wZXJ0eShrKSkge1xuICAgICAgICAgICAgKytjO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBzaGFsbG93IGNsb25lIG9mIGFuIG9iamVjdCwgYXJyYXksIG9yIGZ1bmN0aW9uXG4gKiBAcGFyYW0geyp9IG9iaiAtIFZhbHVlIHRvIGNsb25lXG4gKiBAcmV0dXJucyB7Kn0gQ2xvbmVkIHZhbHVlXG4gKi9cbmZ1bmN0aW9uIGNsb25lKG9iaikge1xuICAgIGlmICh0eXBlb2YgRnVuY3Rpb24ucHJvdG90eXBlLl9fY2xvbmUgPT0gdW5kZWYpIHtcbiAgICAgICAgRnVuY3Rpb24ucHJvdG90eXBlLl9fY2xvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAvL2h0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzE4MzM1ODgvamF2YXNjcmlwdC1jbG9uZS1hLWZ1bmN0aW9uXG4gICAgICAgICAgICBjb25zdCB0aGF0ID0gdGhpcztcbiAgICAgICAgICAgIGxldCB0ZW1wID0gZnVuY3Rpb24gY2xvbmVkKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGF0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgZm9yIChsZXQga2V5IGluIHRoaXMpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRlbXBba2V5XSA9IHRoaXNba2V5XTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGVtcDtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIG9iaiA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJldHVybiBvYmouX19jbG9uZSgpO1xuICAgIH0gZWxzZSBpZiAob2JqLmNvbnN0cnVjdG9yICYmIG9iai5jb25zdHJ1Y3RvciA9PSBBcnJheSkge1xuICAgICAgICByZXR1cm4gb2JqLnNsaWNlKDApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzcyODM2MC9ob3ctZG8taS1jb3JyZWN0bHktY2xvbmUtYS1qYXZhc2NyaXB0LW9iamVjdC8zMDA0Mjk0OCMzMDA0Mjk0OFxuICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgb2JqKTtcbiAgICB9XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgZmlyc3Qgbm9uLW51bGwvdW5kZWZpbmVkIHZhbHVlIGZyb20gYXJndW1lbnRzXG4gKiBAcGFyYW0gey4uLip9IGFyZ3VtZW50cyAtIFZhbHVlcyB0byBjaGVja1xuICogQHJldHVybnMgeyp9IEZpcnN0IG5vbi1udWxsL3VuZGVmaW5lZCB2YWx1ZSwgb3IgbnVsbCBpZiBub25lIGZvdW5kXG4gKi9cbmZ1bmN0aW9uIGNvYWxlc2NlKCkge1xuICAgIGxldCBhcmdzID0gQXJyYXkuZnJvbShhcmd1bWVudHMpO1xuICAgIGxldCByZXR1cm5fdmFsID0gbnVsbDtcbiAgICBhcmdzLmZvckVhY2goZnVuY3Rpb24gKGFyZykge1xuICAgICAgICBpZiAocmV0dXJuX3ZhbCA9PT0gbnVsbCAmJiB0eXBlb2YgYXJnICE9IHVuZGVmICYmIGFyZyAhPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuX3ZhbCA9IGFyZztcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiByZXR1cm5fdmFsO1xufVxuXG4vKipcbiAqIENvbnZlcnRzIENTViBzdHJpbmcgdG8gYXJyYXksIHRyaW1taW5nIGVhY2ggZWxlbWVudFxuICogQHBhcmFtIHtzdHJpbmd9IHN0cl9jc3YgLSBDU1Ygc3RyaW5nIHRvIGNvbnZlcnRcbiAqIEByZXR1cm5zIHtBcnJheTxzdHJpbmc+fSBBcnJheSBvZiB0cmltbWVkIHZhbHVlc1xuICogQHRvZG8gSGFuZGxlIHF1b3RlZC9lc2NhcGVkIGNoYXJhY3RlcnNcbiAqL1xuZnVuY3Rpb24gY3N2X3RvX2FycmF5X3RyaW0oc3RyX2Nzdikge1xuICAgIGNvbnN0IHBhcnRzID0gc3RyX2Nzdi5zcGxpdCgnLCcpO1xuICAgIGNvbnN0IHJldCA9IFtdO1xuICAgIGZvcmVhY2gocGFydHMsIChwYXJ0KSA9PiB7XG4gICAgICAgIHJldC5wdXNoKHBhcnQudHJpbSgpKTtcbiAgICB9KTtcbiAgICByZXR1cm4gcmV0O1xufVxuIiwiLyoqXG4gKiBNYW5pZmVzdCAtIEphdmFTY3JpcHQgY2xhc3MgcmVnaXN0cnkgYW5kIG1ldGFkYXRhIHN5c3RlbVxuICpcbiAqIFRoaXMgY2xhc3MgbWFpbnRhaW5zIGEgcmVnaXN0cnkgb2YgYWxsIEphdmFTY3JpcHQgY2xhc3NlcyBpbiB0aGUgYnVuZGxlLFxuICogdHJhY2tpbmcgdGhlaXIgbmFtZXMgYW5kIGluaGVyaXRhbmNlIHJlbGF0aW9uc2hpcHMuIEl0IHByb3ZpZGVzIHV0aWxpdGllc1xuICogZm9yIHdvcmtpbmcgd2l0aCBjbGFzcyBoaWVyYXJjaGllcyBhbmQgY2FsbGluZyBpbml0aWFsaXphdGlvbiBtZXRob2RzLlxuICovXG5jbGFzcyBNYW5pZmVzdCB7XG4gICAgLyoqXG4gICAgICogRGVmaW5lIGNsYXNzZXMgaW4gdGhlIG1hbmlmZXN0IChmcmFtZXdvcmsgaW50ZXJuYWwpXG4gICAgICogQHBhcmFtIHtBcnJheX0gaXRlbXMgLSBBcnJheSBvZiBjbGFzcyBkZWZpbml0aW9ucyBbW0NsYXNzLCBcIkNsYXNzTmFtZVwiLCBQYXJlbnRDbGFzcywgZGVjb3JhdG9yc10sIC4uLl1cbiAgICAgKi9cbiAgICBzdGF0aWMgX2RlZmluZShpdGVtcykge1xuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBjbGFzc2VzIG9iamVjdCBpZiBub3QgYWxyZWFkeSBkZWZpbmVkXG4gICAgICAgIGlmICh0eXBlb2YgTWFuaWZlc3QuX2NsYXNzZXMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBNYW5pZmVzdC5fY2xhc3NlcyA9IHt9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUHJvY2VzcyBlYWNoIGNsYXNzIGRlZmluaXRpb25cbiAgICAgICAgaXRlbXMuZm9yRWFjaCgoaXRlbSkgPT4ge1xuICAgICAgICAgICAgbGV0IGNsYXNzX29iamVjdCA9IGl0ZW1bMF07XG4gICAgICAgICAgICBsZXQgY2xhc3NfbmFtZSA9IGl0ZW1bMV07XG4gICAgICAgICAgICBsZXQgY2xhc3NfZXh0ZW5kcyA9IGl0ZW1bMl0gfHwgbnVsbDtcbiAgICAgICAgICAgIGxldCBkZWNvcmF0b3JzID0gaXRlbVszXSB8fCBudWxsO1xuXG4gICAgICAgICAgICAvLyBTdG9yZSB0aGUgY2xhc3MgaW5mb3JtYXRpb24gKHVzaW5nIG9iamVjdCB0byBhdm9pZCBkdXBsaWNhdGVzKVxuICAgICAgICAgICAgTWFuaWZlc3QuX2NsYXNzZXNbY2xhc3NfbmFtZV0gPSB7XG4gICAgICAgICAgICAgICAgY2xhc3M6IGNsYXNzX29iamVjdCxcbiAgICAgICAgICAgICAgICBuYW1lOiBjbGFzc19uYW1lLFxuICAgICAgICAgICAgICAgIGV4dGVuZHM6IGNsYXNzX2V4dGVuZHMsXG4gICAgICAgICAgICAgICAgZGVjb3JhdG9yczogZGVjb3JhdG9ycywgIC8vIFN0b3JlIGNvbXBhY3QgZGVjb3JhdG9yIGRhdGFcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8vIEFkZCBtZXRhZGF0YSB0byB0aGUgY2xhc3Mgb2JqZWN0IGl0c2VsZlxuICAgICAgICAgICAgY2xhc3Nfb2JqZWN0Ll9uYW1lID0gY2xhc3NfbmFtZTtcbiAgICAgICAgICAgIGNsYXNzX29iamVjdC5fZXh0ZW5kcyA9IGNsYXNzX2V4dGVuZHM7XG4gICAgICAgICAgICBjbGFzc19vYmplY3QuX2RlY29yYXRvcnMgPSBkZWNvcmF0b3JzO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBCdWlsZCB0aGUgc3ViY2xhc3MgaW5kZXggYWZ0ZXIgYWxsIGNsYXNzZXMgYXJlIGRlZmluZWRcbiAgICAgICAgTWFuaWZlc3QuX2J1aWxkX3N1YmNsYXNzX2luZGV4KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQnVpbGQgYW4gaW5kZXggb2Ygc3ViY2xhc3NlcyBmb3IgZWZmaWNpZW50IGxvb2t1cHNcbiAgICAgKiBUaGlzIGNyZWF0ZXMgYSBtYXBwaW5nIHdoZXJlIGVhY2ggY2xhc3MgbmFtZSBwb2ludHMgdG8gYW4gYXJyYXkgb2YgYWxsIGl0cyBzdWJjbGFzc2VzXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX2J1aWxkX3N1YmNsYXNzX2luZGV4KCkge1xuICAgICAgICAvLyBJbml0aWFsaXplIHRoZSBzdWJjbGFzcyBpbmRleFxuICAgICAgICBNYW5pZmVzdC5fc3ViY2xhc3NfaW5kZXggPSB7fTtcblxuICAgICAgICAvLyBTdGVwIHRocm91Z2ggZWFjaCBjbGFzcyBhbmQgd2FsayB1cCBpdHMgcGFyZW50IGNoYWluXG4gICAgICAgIGZvciAobGV0IGNsYXNzX25hbWUgaW4gTWFuaWZlc3QuX2NsYXNzZXMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNsYXNzZGF0YSA9IE1hbmlmZXN0Ll9jbGFzc2VzW2NsYXNzX25hbWVdO1xuICAgICAgICAgICAgbGV0IGN1cnJlbnRfY2xhc3NfbmFtZSA9IGNsYXNzX25hbWU7XG4gICAgICAgICAgICBsZXQgY3VycmVudF9jbGFzc2RhdGEgPSBjbGFzc2RhdGE7XG5cbiAgICAgICAgICAgIC8vIFdhbGsgdXAgdGhlIHBhcmVudCBjaGFpbiB1bnRpbCB3ZSByZWFjaCB0aGUgcm9vdFxuICAgICAgICAgICAgd2hpbGUgKGN1cnJlbnRfY2xhc3NkYXRhKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXh0ZW5kc19uYW1lID0gY3VycmVudF9jbGFzc2RhdGEuZXh0ZW5kcztcblxuICAgICAgICAgICAgICAgIGlmIChleHRlbmRzX25hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSW5pdGlhbGl6ZSB0aGUgcGFyZW50J3Mgc3ViY2xhc3MgYXJyYXkgaWYgbmVlZGVkXG4gICAgICAgICAgICAgICAgICAgIGlmICghTWFuaWZlc3QuX3N1YmNsYXNzX2luZGV4W2V4dGVuZHNfbmFtZV0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIE1hbmlmZXN0Ll9zdWJjbGFzc19pbmRleFtleHRlbmRzX25hbWVdID0gW107XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBBZGQgdGhpcyBjbGFzcyB0byBpdHMgcGFyZW50J3Mgc3ViY2xhc3MgbGlzdFxuICAgICAgICAgICAgICAgICAgICBpZiAoIU1hbmlmZXN0Ll9zdWJjbGFzc19pbmRleFtleHRlbmRzX25hbWVdLmluY2x1ZGVzKGNsYXNzX25hbWUpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBNYW5pZmVzdC5fc3ViY2xhc3NfaW5kZXhbZXh0ZW5kc19uYW1lXS5wdXNoKGNsYXNzX25hbWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gTW92ZSB1cCB0byB0aGUgcGFyZW50J3MgbWV0YWRhdGEgKGlmIGl0IGV4aXN0cyBpbiBtYW5pZmVzdClcbiAgICAgICAgICAgICAgICAgICAgaWYgKE1hbmlmZXN0Ll9jbGFzc2VzW2V4dGVuZHNfbmFtZV0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRfY2xhc3NkYXRhID0gTWFuaWZlc3QuX2NsYXNzZXNbZXh0ZW5kc19uYW1lXTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBhcmVudCBub3QgaW4gbWFuaWZlc3QgKGUuZy4sIG5hdGl2ZSBKYXZhU2NyaXB0IGNsYXNzKSwgc3RvcCBoZXJlXG4gICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50X2NsYXNzZGF0YSA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBObyBwYXJlbnQsIHdlJ3ZlIHJlYWNoZWQgdGhlIHJvb3RcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudF9jbGFzc2RhdGEgPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhbGwgY2xhc3NlcyB0aGF0IGV4dGVuZCBhIGdpdmVuIGJhc2UgY2xhc3NcbiAgICAgKiBAcGFyYW0ge0NsYXNzfHN0cmluZ30gYmFzZV9jbGFzcyAtIFRoZSBiYXNlIGNsYXNzIChvYmplY3Qgb3IgbmFtZSBzdHJpbmcpIHRvIGNoZWNrIGZvclxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gQXJyYXkgb2Ygb2JqZWN0cyB3aXRoIHtjbGFzc19uYW1lLCBjbGFzc19vYmplY3R9IGZvciBjbGFzc2VzIHRoYXQgZXh0ZW5kIHRoZSBiYXNlIGNsYXNzXG4gICAgICovXG4gICAgc3RhdGljIGdldF9leHRlbmRpbmcoYmFzZV9jbGFzcykge1xuICAgICAgICBpZiAoIU1hbmlmZXN0Ll9jbGFzc2VzKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDb252ZXJ0IHN0cmluZyB0byBjbGFzcyBvYmplY3QgaWYgbmVlZGVkXG4gICAgICAgIGxldCBiYXNlX2NsYXNzX29iamVjdCA9IGJhc2VfY2xhc3M7XG4gICAgICAgIGlmICh0eXBlb2YgYmFzZV9jbGFzcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGJhc2VfY2xhc3Nfb2JqZWN0ID0gTWFuaWZlc3QuZ2V0X2NsYXNzX2J5X25hbWUoYmFzZV9jbGFzcyk7XG4gICAgICAgICAgICBpZiAoIWJhc2VfY2xhc3Nfb2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBCYXNlIGNsYXNzIG5vdCBmb3VuZDogJHtiYXNlX2NsYXNzfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2xhc3NlcyA9IFtdO1xuXG4gICAgICAgIGZvciAobGV0IGNsYXNzX25hbWUgaW4gTWFuaWZlc3QuX2NsYXNzZXMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNsYXNzZGF0YSA9IE1hbmlmZXN0Ll9jbGFzc2VzW2NsYXNzX25hbWVdO1xuICAgICAgICAgICAgaWYgKE1hbmlmZXN0LmpzX2lzX3N1YmNsYXNzX29mKGNsYXNzZGF0YS5jbGFzcywgYmFzZV9jbGFzc19vYmplY3QpKSB7XG4gICAgICAgICAgICAgICAgY2xhc3Nlcy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgY2xhc3NfbmFtZTogY2xhc3NfbmFtZSxcbiAgICAgICAgICAgICAgICAgICAgY2xhc3Nfb2JqZWN0OiBjbGFzc2RhdGEuY2xhc3MsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTb3J0IGFscGhhYmV0aWNhbGx5IGJ5IGNsYXNzIG5hbWUgdG8gZW5zdXJlIGRldGVybWluaXN0aWMgYmVoYXZpb3IgYW5kIHByZXZlbnQgcmFjZSBjb25kaXRpb24gYnVnc1xuICAgICAgICBjbGFzc2VzLnNvcnQoKGEsIGIpID0+IGEuY2xhc3NfbmFtZS5sb2NhbGVDb21wYXJlKGIuY2xhc3NfbmFtZSkpO1xuXG4gICAgICAgIHJldHVybiBjbGFzc2VzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIGEgY2xhc3MgaXMgYSBzdWJjbGFzcyBvZiBhbm90aGVyIGNsYXNzXG4gICAgICogTWF0Y2hlcyBQSFAgTWFuaWZlc3Q6OmpzX2lzX3N1YmNsYXNzX29mKCkgc2lnbmF0dXJlIGFuZCBiZWhhdmlvclxuICAgICAqIEBwYXJhbSB7Q2xhc3N8c3RyaW5nfSBzdWJjbGFzcyAtIFRoZSBjaGlsZCBjbGFzcyAob2JqZWN0IG9yIG5hbWUpIHRvIGNoZWNrXG4gICAgICogQHBhcmFtIHtDbGFzc3xzdHJpbmd9IHN1cGVyY2xhc3MgLSBUaGUgcGFyZW50IGNsYXNzIChvYmplY3Qgb3IgbmFtZSkgdG8gY2hlY2sgYWdhaW5zdFxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHN1YmNsYXNzIGV4dGVuZHMgc3VwZXJjbGFzcyAoZGlyZWN0bHkgb3IgaW5kaXJlY3RseSlcbiAgICAgKi9cbiAgICBzdGF0aWMganNfaXNfc3ViY2xhc3Nfb2Yoc3ViY2xhc3MsIHN1cGVyY2xhc3MpIHtcbiAgICAgICAgLy8gQ29udmVydCBzdHJpbmcgbmFtZXMgdG8gY2xhc3Mgb2JqZWN0c1xuICAgICAgICBsZXQgc3ViY2xhc3Nfb2JqZWN0ID0gc3ViY2xhc3M7XG4gICAgICAgIGlmICh0eXBlb2Ygc3ViY2xhc3MgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBzdWJjbGFzc19vYmplY3QgPSBNYW5pZmVzdC5nZXRfY2xhc3NfYnlfbmFtZShzdWJjbGFzcyk7XG4gICAgICAgICAgICBpZiAoIXN1YmNsYXNzX29iamVjdCkge1xuICAgICAgICAgICAgICAgIC8vIENhbid0IHJlc29sdmUgc3ViY2xhc3MgLSByZXR1cm4gZmFsc2UgcGVyIHNwZWNcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgc3VwZXJjbGFzc19vYmplY3QgPSBzdXBlcmNsYXNzO1xuICAgICAgICBpZiAodHlwZW9mIHN1cGVyY2xhc3MgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBzdXBlcmNsYXNzX29iamVjdCA9IE1hbmlmZXN0LmdldF9jbGFzc19ieV9uYW1lKHN1cGVyY2xhc3MpO1xuICAgICAgICAgICAgaWYgKCFzdXBlcmNsYXNzX29iamVjdCkge1xuICAgICAgICAgICAgICAgIC8vIENhbid0IHJlc29sdmUgc3VwZXJjbGFzcyAtIGZhaWwgbG91ZCBwZXIgc3BlY1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU3VwZXJjbGFzcyBub3QgZm91bmQgaW4gbWFuaWZlc3Q6ICR7c3VwZXJjbGFzc31gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENsYXNzZXMgYXJlIG5vdCBzdWJjbGFzc2VzIG9mIHRoZW1zZWx2ZXNcbiAgICAgICAgaWYgKHN1YmNsYXNzX29iamVjdCA9PT0gc3VwZXJjbGFzc19vYmplY3QpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdhbGsgdXAgdGhlIGluaGVyaXRhbmNlIGNoYWluXG4gICAgICAgIGxldCBjdXJyZW50X2NsYXNzID0gc3ViY2xhc3Nfb2JqZWN0O1xuICAgICAgICB3aGlsZSAoY3VycmVudF9jbGFzcykge1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRfY2xhc3MgPT09IHN1cGVyY2xhc3Nfb2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBNb3ZlIHVwIHRvIHBhcmVudCBjbGFzc1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRfY2xhc3MuX2V4dGVuZHMpIHtcbiAgICAgICAgICAgICAgICAvLyBfZXh0ZW5kcyBtYXkgYmUgYSBzdHJpbmcgb3IgY2xhc3MgcmVmZXJlbmNlXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBjdXJyZW50X2NsYXNzLl9leHRlbmRzID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgICAgICBjdXJyZW50X2NsYXNzID0gTWFuaWZlc3QuZ2V0X2NsYXNzX2J5X25hbWUoY3VycmVudF9jbGFzcy5fZXh0ZW5kcyk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudF9jbGFzcyA9IGN1cnJlbnRfY2xhc3MuX2V4dGVuZHM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50X2NsYXNzID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYSBjbGFzcyBieSBpdHMgbmFtZVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjbGFzc19uYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNsYXNzXG4gICAgICogQHJldHVybnMge0NsYXNzfG51bGx9IFRoZSBjbGFzcyBvYmplY3Qgb3IgbnVsbCBpZiBub3QgZm91bmRcbiAgICAgKi9cbiAgICBzdGF0aWMgZ2V0X2NsYXNzX2J5X25hbWUoY2xhc3NfbmFtZSkge1xuICAgICAgICBpZiAoIU1hbmlmZXN0Ll9jbGFzc2VzIHx8ICFNYW5pZmVzdC5fY2xhc3Nlc1tjbGFzc19uYW1lXSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gTWFuaWZlc3QuX2NsYXNzZXNbY2xhc3NfbmFtZV0uY2xhc3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCByZWdpc3RlcmVkIGNsYXNzZXNcbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IEFycmF5IG9mIG9iamVjdHMgd2l0aCB7Y2xhc3NfbmFtZSwgY2xhc3Nfb2JqZWN0LCBleHRlbmRzfVxuICAgICAqL1xuICAgIHN0YXRpYyBnZXRfYWxsX2NsYXNzZXMoKSB7XG4gICAgICAgIGlmICghTWFuaWZlc3QuX2NsYXNzZXMpIHtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc3VsdHMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgY2xhc3NfbmFtZSBpbiBNYW5pZmVzdC5fY2xhc3Nlcykge1xuICAgICAgICAgICAgY29uc3QgY2xhc3NkYXRhID0gTWFuaWZlc3QuX2NsYXNzZXNbY2xhc3NfbmFtZV07XG4gICAgICAgICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICAgICAgICAgIGNsYXNzX25hbWU6IGNsYXNzZGF0YS5uYW1lLFxuICAgICAgICAgICAgICAgIGNsYXNzX29iamVjdDogY2xhc3NkYXRhLmNsYXNzLFxuICAgICAgICAgICAgICAgIGV4dGVuZHM6IGNsYXNzZGF0YS5leHRlbmRzLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTb3J0IGFscGhhYmV0aWNhbGx5IGJ5IGNsYXNzIG5hbWUgdG8gZW5zdXJlIGRldGVybWluaXN0aWMgYmVoYXZpb3IgYW5kIHByZXZlbnQgcmFjZSBjb25kaXRpb24gYnVnc1xuICAgICAgICByZXN1bHRzLnNvcnQoKGEsIGIpID0+IGEuY2xhc3NfbmFtZS5sb2NhbGVDb21wYXJlKGIuY2xhc3NfbmFtZSkpO1xuXG4gICAgICAgIHJldHVybiByZXN1bHRzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgYnVpbGQga2V5IGZyb20gdGhlIGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb25cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYnVpbGQga2V5IG9yIFwiTk9CVUlMRFwiIGlmIG5vdCBhdmFpbGFibGVcbiAgICAgKi9cbiAgICBzdGF0aWMgYnVpbGRfa2V5KCkge1xuICAgICAgICBpZiAod2luZG93LnJzeGFwcCAmJiB3aW5kb3cucnN4YXBwLmJ1aWxkX2tleSkge1xuICAgICAgICAgICAgcmV0dXJuIHdpbmRvdy5yc3hhcHAuYnVpbGRfa2V5O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAnTk9CVUlMRCc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGRlY29yYXRvcnMgZm9yIGEgc3BlY2lmaWMgY2xhc3MgYW5kIG1ldGhvZFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfENsYXNzfSBjbGFzc19uYW1lIC0gVGhlIGNsYXNzIG5hbWUgb3IgY2xhc3Mgb2JqZWN0XG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGhvZF9uYW1lIC0gVGhlIG1ldGhvZCBuYW1lXG4gICAgICogQHJldHVybnMge0FycmF5fG51bGx9IEFycmF5IG9mIGRlY29yYXRvciBvYmplY3RzIG9yIG51bGwgaWYgbm9uZSBmb3VuZFxuICAgICAqL1xuICAgIHN0YXRpYyBnZXRfZGVjb3JhdG9ycyhjbGFzc19uYW1lLCBtZXRob2RfbmFtZSkge1xuICAgICAgICAvLyBDb252ZXJ0IGNsYXNzIG9iamVjdCB0byBuYW1lIGlmIG5lZWRlZFxuICAgICAgICBpZiAodHlwZW9mIGNsYXNzX25hbWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBjbGFzc19uYW1lID0gY2xhc3NfbmFtZS5fbmFtZSB8fCBjbGFzc19uYW1lLm5hbWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjbGFzc19pbmZvID0gTWFuaWZlc3QuX2NsYXNzZXNbY2xhc3NfbmFtZV07XG4gICAgICAgIGlmICghY2xhc3NfaW5mbyB8fCAhY2xhc3NfaW5mby5kZWNvcmF0b3JzIHx8ICFjbGFzc19pbmZvLmRlY29yYXRvcnNbbWV0aG9kX25hbWVdKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRyYW5zZm9ybSBjb21wYWN0IGZvcm1hdCB0byBvYmplY3QgZm9ybWF0XG4gICAgICAgIHJldHVybiBNYW5pZmVzdC5fdHJhbnNmb3JtX2RlY29yYXRvcnMoY2xhc3NfaW5mby5kZWNvcmF0b3JzW21ldGhvZF9uYW1lXSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBtZXRob2RzIHdpdGggZGVjb3JhdG9ycyBmb3IgYSBjbGFzc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfENsYXNzfSBjbGFzc19uYW1lIC0gVGhlIGNsYXNzIG5hbWUgb3IgY2xhc3Mgb2JqZWN0XG4gICAgICogQHJldHVybnMge09iamVjdH0gT2JqZWN0IHdpdGggbWV0aG9kIG5hbWVzIGFzIGtleXMgYW5kIGRlY29yYXRvciBhcnJheXMgYXMgdmFsdWVzXG4gICAgICovXG4gICAgc3RhdGljIGdldF9hbGxfZGVjb3JhdG9ycyhjbGFzc19uYW1lKSB7XG4gICAgICAgIC8vIENvbnZlcnQgY2xhc3Mgb2JqZWN0IHRvIG5hbWUgaWYgbmVlZGVkXG4gICAgICAgIGlmICh0eXBlb2YgY2xhc3NfbmFtZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGNsYXNzX25hbWUgPSBjbGFzc19uYW1lLl9uYW1lIHx8IGNsYXNzX25hbWUubmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNsYXNzX2luZm8gPSBNYW5pZmVzdC5fY2xhc3Nlc1tjbGFzc19uYW1lXTtcbiAgICAgICAgaWYgKCFjbGFzc19pbmZvIHx8ICFjbGFzc19pbmZvLmRlY29yYXRvcnMpIHtcbiAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRyYW5zZm9ybSBhbGwgZGVjb3JhdG9ycyBmcm9tIGNvbXBhY3QgdG8gb2JqZWN0IGZvcm1hdFxuICAgICAgICBjb25zdCByZXN1bHQgPSB7fTtcbiAgICAgICAgZm9yIChsZXQgbWV0aG9kX25hbWUgaW4gY2xhc3NfaW5mby5kZWNvcmF0b3JzKSB7XG4gICAgICAgICAgICByZXN1bHRbbWV0aG9kX25hbWVdID0gTWFuaWZlc3QuX3RyYW5zZm9ybV9kZWNvcmF0b3JzKGNsYXNzX2luZm8uZGVjb3JhdG9yc1ttZXRob2RfbmFtZV0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJhbnNmb3JtIGNvbXBhY3QgZGVjb3JhdG9yIGZvcm1hdCB0byBvYmplY3QgZm9ybWF0XG4gICAgICogQHBhcmFtIHtBcnJheX0gY29tcGFjdF9kZWNvcmF0b3JzIC0gQXJyYXkgb2YgW25hbWUsIFthcmdzXV0gdHVwbGVzXG4gICAgICogQHJldHVybnMge0FycmF5fSBBcnJheSBvZiBkZWNvcmF0b3Igb2JqZWN0cyB3aXRoIG5hbWUgYW5kIGFyZ3VtZW50cyBwcm9wZXJ0aWVzXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX3RyYW5zZm9ybV9kZWNvcmF0b3JzKGNvbXBhY3RfZGVjb3JhdG9ycykge1xuICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkoY29tcGFjdF9kZWNvcmF0b3JzKSkge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNvbXBhY3RfZGVjb3JhdG9ycy5tYXAoZGVjb3JhdG9yID0+IHtcbiAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KGRlY29yYXRvcikgJiYgZGVjb3JhdG9yLmxlbmd0aCA+PSAyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogZGVjb3JhdG9yWzBdLFxuICAgICAgICAgICAgICAgICAgICBhcmd1bWVudHM6IGRlY29yYXRvclsxXSB8fCBbXVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBIYW5kbGUgbWFsZm9ybWVkIGRlY29yYXRvciBkYXRhXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG5hbWU6ICd1bmtub3duJyxcbiAgICAgICAgICAgICAgICBhcmd1bWVudHM6IFtdXG4gICAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiBhIG1ldGhvZCBoYXMgYSBzcGVjaWZpYyBkZWNvcmF0b3JcbiAgICAgKiBAcGFyYW0ge3N0cmluZ3xDbGFzc30gY2xhc3NfbmFtZSAtIFRoZSBjbGFzcyBuYW1lIG9yIGNsYXNzIG9iamVjdFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtZXRob2RfbmFtZSAtIFRoZSBtZXRob2QgbmFtZVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBkZWNvcmF0b3JfbmFtZSAtIFRoZSBkZWNvcmF0b3IgbmFtZSB0byBjaGVjayBmb3JcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgbWV0aG9kIGhhcyB0aGUgZGVjb3JhdG9yXG4gICAgICovXG4gICAgc3RhdGljIGhhc19kZWNvcmF0b3IoY2xhc3NfbmFtZSwgbWV0aG9kX25hbWUsIGRlY29yYXRvcl9uYW1lKSB7XG4gICAgICAgIGNvbnN0IGRlY29yYXRvcnMgPSBNYW5pZmVzdC5nZXRfZGVjb3JhdG9ycyhjbGFzc19uYW1lLCBtZXRob2RfbmFtZSk7XG4gICAgICAgIGlmICghZGVjb3JhdG9ycykge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGRlY29yYXRvcnMuc29tZShkID0+IGQubmFtZSA9PT0gZGVjb3JhdG9yX25hbWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhbGwgc3ViY2xhc3NlcyBvZiBhIGdpdmVuIGNsYXNzIHVzaW5nIHRoZSBwcmUtYnVpbHQgaW5kZXhcbiAgICAgKiBUaGlzIGlzIHRoZSBKYXZhU2NyaXB0IGVxdWl2YWxlbnQgb2YgUEhQJ3MgTWFuaWZlc3Q6OmpzX2dldF9zdWJjbGFzc2VzX29mKClcbiAgICAgKiBAcGFyYW0ge0NsYXNzfHN0cmluZ30gYmFzZV9jbGFzcyAtIFRoZSBiYXNlIGNsYXNzIChvYmplY3Qgb3IgbmFtZSBzdHJpbmcpIHRvIGdldCBzdWJjbGFzc2VzIG9mXG4gICAgICogQHJldHVybnMge0FycmF5PENsYXNzPn0gQXJyYXkgb2YgYWN0dWFsIGNsYXNzIG9iamVjdHMgdGhhdCBhcmUgc3ViY2xhc3NlcyBvZiB0aGUgYmFzZSBjbGFzc1xuICAgICAqL1xuICAgIHN0YXRpYyBqc19nZXRfc3ViY2xhc3Nlc19vZihiYXNlX2NsYXNzKSB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgaW5kZXggaWYgbmVlZGVkXG4gICAgICAgIGlmICghTWFuaWZlc3QuX3N1YmNsYXNzX2luZGV4KSB7XG4gICAgICAgICAgICBNYW5pZmVzdC5fYnVpbGRfc3ViY2xhc3NfaW5kZXgoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENvbnZlcnQgY2xhc3Mgb2JqZWN0IHRvIG5hbWUgaWYgbmVlZGVkXG4gICAgICAgIGxldCBiYXNlX2NsYXNzX25hbWUgPSBiYXNlX2NsYXNzO1xuICAgICAgICBpZiAodHlwZW9mIGJhc2VfY2xhc3MgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBiYXNlX2NsYXNzX25hbWUgPSBiYXNlX2NsYXNzLl9uYW1lIHx8IGJhc2VfY2xhc3MubmFtZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENoZWNrIGlmIHRoZSBiYXNlIGNsYXNzIGV4aXN0c1xuICAgICAgICBpZiAoIU1hbmlmZXN0Ll9jbGFzc2VzW2Jhc2VfY2xhc3NfbmFtZV0pIHtcbiAgICAgICAgICAgIC8vIEJhc2UgY2xhc3Mgbm90IGluIG1hbmlmZXN0IC0gcmV0dXJuIGVtcHR5IGFycmF5XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cblxuICAgICAgICAvLyBHZXQgc3ViY2xhc3MgbmFtZXMgZnJvbSB0aGUgaW5kZXhcbiAgICAgICAgY29uc3Qgc3ViY2xhc3NfbmFtZXMgPSBNYW5pZmVzdC5fc3ViY2xhc3NfaW5kZXhbYmFzZV9jbGFzc19uYW1lXSB8fCBbXTtcblxuICAgICAgICAvLyBDb252ZXJ0IG5hbWVzIHRvIGFjdHVhbCBjbGFzcyBvYmplY3RzXG4gICAgICAgIGNvbnN0IHN1YmNsYXNzX29iamVjdHMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgc3ViY2xhc3NfbmFtZSBvZiBzdWJjbGFzc19uYW1lcykge1xuICAgICAgICAgICAgY29uc3QgY2xhc3NkYXRhID0gTWFuaWZlc3QuX2NsYXNzZXNbc3ViY2xhc3NfbmFtZV07XG4gICAgICAgICAgICBzdWJjbGFzc19vYmplY3RzLnB1c2goY2xhc3NkYXRhLmNsYXNzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNvcnQgYnkgY2xhc3MgbmFtZSBmb3IgZGV0ZXJtaW5pc3RpYyBiZWhhdmlvclxuICAgICAgICBzdWJjbGFzc19vYmplY3RzLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5hbWVfYSA9IGEuX25hbWUgfHwgYS5uYW1lO1xuICAgICAgICAgICAgY29uc3QgbmFtZV9iID0gYi5fbmFtZSB8fCBiLm5hbWU7XG4gICAgICAgICAgICByZXR1cm4gbmFtZV9hLmxvY2FsZUNvbXBhcmUobmFtZV9iKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHN1YmNsYXNzX29iamVjdHM7XG4gICAgfVxufVxuXG4vLyBSU1ggbWFuaWZlc3QgYXV0b21hdGljYWxseSBtYWtlcyBjbGFzc2VzIGdsb2JhbCAtIG5vIG1hbnVhbCBhc3NpZ25tZW50IG5lZWRlZFxuIiwiLyoqXG4gKiBSc3hfQmVoYXZpb3JzIC0gQ29yZSBGcmFtZXdvcmsgVXNlciBFeHBlcmllbmNlIEVuaGFuY2VtZW50c1xuICpcbiAqIFRoaXMgY2xhc3MgcHJvdmlkZXMgYXV0b21hdGljIHF1YWxpdHktb2YtbGlmZSBiZWhhdmlvcnMgdGhhdCBpbXByb3ZlIHRoZSBkZWZhdWx0XG4gKiBicm93c2VyIGV4cGVyaWVuY2UgZm9yIFJTWCBhcHBsaWNhdGlvbnMuIFRoZXNlIGJlaGF2aW9ycyBhcmUgdHJhbnNwYXJlbnQgdG9cbiAqIGFwcGxpY2F0aW9uIGRldmVsb3BlcnMgYW5kIHJ1biBhdXRvbWF0aWNhbGx5IG9uIGZyYW1ld29yayBpbml0aWFsaXphdGlvbi5cbiAqXG4gKiBUaGVzZSBiZWhhdmlvcnMgdXNlIGpRdWVyeSBldmVudCBkZWxlZ2F0aW9uIHRvIGhhbmRsZSBib3RoIGV4aXN0aW5nIGFuZCBkeW5hbWljYWxseVxuICogYWRkZWQgY29udGVudC4gVGhleSBhcmUgaW1wbGVtZW50ZWQgd2l0aCBsb3cgcHJpb3JpdHkgdG8gYWxsb3cgYXBwbGljYXRpb24gY29kZSB0b1xuICogb3ZlcnJpZGUgZGVmYXVsdCBiZWhhdmlvcnMgd2hlbiBuZWVkZWQuXG4gKlxuICogQGludGVybmFsIEZyYW1ld29yayB1c2Ugb25seSAtIG5vdCBwYXJ0IG9mIHB1YmxpYyBBUElcbiAqL1xuY2xhc3MgUnN4X0JlaGF2aW9ycyB7XG4gICAgc3RhdGljIF9vbl9mcmFtZXdvcmtfY29yZV9pbml0KCkge1xuICAgICAgICBSc3hfQmVoYXZpb3JzLl9pbml0X2lnbm9yZV9pbnZhbGlkX2FuY2hvcl9saW5rcygpO1xuICAgICAgICBSc3hfQmVoYXZpb3JzLl90cmltX2NvcGllZF90ZXh0KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogLSBBbmNob3IgbGluayBoYW5kbGluZzogUHJldmVudHMgYnJva2VuIFwiI1wiIGxpbmtzIGZyb20gY2F1c2luZyBwYWdlIGp1bXBzIG9yIFVSTCBjaGFuZ2VzXG4gICAgICogLSBJZ25vcmVzIFwiI1wiIChlbXB0eSBoYXNoKSB0byBwcmV2ZW50IHNjcm9sbC10by10b3AgYmVoYXZpb3JcbiAgICAgKiAtIElnbm9yZXMgXCIjcGxhY2Vob2xkZXIqXCIgbGlua3MgdXNlZCBhcyByb3V0ZSBwbGFjZWhvbGRlcnMgZHVyaW5nIGRldmVsb3BtZW50XG4gICAgICogLSBWYWxpZGF0ZXMgYW5jaG9yIHRhcmdldHMgZXhpc3QgYmVmb3JlIGFsbG93aW5nIG5hdmlnYXRpb25cbiAgICAgKiAtIFByZXNlcnZlcyBub3JtYWwgYW5jaG9yIGJlaGF2aW9yIHdoZW4gdGFyZ2V0cyBleGlzdFxuICAgICAqL1xuICAgIHN0YXRpYyBfaW5pdF9pZ25vcmVfaW52YWxpZF9hbmNob3JfbGlua3MoKSB7XG4gICAgICAgIHJldHVybjsgLy8gZGlzYWJsZWQgZm9yIG5vdyAtIG1ha2UgdGhpcyBpbnRvIGEgY29uZmlndXJhYmxlIG9wdGlvblxuXG4gICAgICAgIC8vIFVzZSBldmVudCBkZWxlZ2F0aW9uIG9uIGRvY3VtZW50IHRvIGhhbmRsZSBhbGwgY3VycmVudCBhbmQgZnV0dXJlIGFuY2hvciBjbGlja3NcbiAgICAgICAgLy8gVXNlIG1vdXNlZG93biBpbnN0ZWFkIG9mIGNsaWNrIHRvIHJ1biBiZWZvcmUgbW9zdCBhcHBsaWNhdGlvbiBoYW5kbGVyc1xuICAgICAgICAkKGRvY3VtZW50KS5vbignbW91c2Vkb3duJywgJ2FbaHJlZl49XCIjXCJdJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGNvbnN0ICRsaW5rID0gJCh0aGlzKTtcbiAgICAgICAgICAgIGNvbnN0IGhyZWYgPSAkbGluay5hdHRyKCdocmVmJyk7XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIGFub3RoZXIgaGFuZGxlciBoYXMgYWxyZWFkeSBwcmV2ZW50ZWQgZGVmYXVsdFxuICAgICAgICAgICAgaWYgKGUuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEFsbG93IGRhdGEtcnN4LWFsbG93LWhhc2ggYXR0cmlidXRlIHRvIGJ5cGFzcyB0aGlzIGJlaGF2aW9yXG4gICAgICAgICAgICBpZiAoJGxpbmsuZGF0YSgncnN4LWFsbG93LWhhc2gnKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSGFuZGxlIGVtcHR5IGhhc2ggLSBwcmV2ZW50IHNjcm9sbCB0byB0b3BcbiAgICAgICAgICAgIGlmIChocmVmID09PSAnIycpIHtcbiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEhhbmRsZSBwbGFjZWhvbGRlciBsaW5rcyB1c2VkIGR1cmluZyBkZXZlbG9wbWVudFxuICAgICAgICAgICAgaWYgKGhyZWYuc3RhcnRzV2l0aCgnI3BsYWNlaG9sZGVyJykpIHtcbiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEZvciBvdGhlciBoYXNoIGxpbmtzLCBjaGVjayBpZiB0YXJnZXQgZXhpc3RzXG4gICAgICAgICAgICBjb25zdCB0YXJnZXRJZCA9IGhyZWYuc3Vic3RyaW5nKDEpO1xuICAgICAgICAgICAgaWYgKHRhcmdldElkKSB7XG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgZm9yIGVsZW1lbnQgd2l0aCBtYXRjaGluZyBJRCBvciBuYW1lIGF0dHJpYnV0ZVxuICAgICAgICAgICAgICAgIGNvbnN0IHRhcmdldEV4aXN0cyA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHRhcmdldElkKSAhPT0gbnVsbCB8fCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBbbmFtZT1cIiR7dGFyZ2V0SWR9XCJdYCkgIT09IG51bGw7XG5cbiAgICAgICAgICAgICAgICBpZiAoIXRhcmdldEV4aXN0cykge1xuICAgICAgICAgICAgICAgICAgICAvLyBUYXJnZXQgZG9lc24ndCBleGlzdCAtIHByZXZlbnQgbmF2aWdhdGlvblxuICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgIGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gVGFyZ2V0IGV4aXN0cyAtIGFsbG93IG5vcm1hbCBhbmNob3IgYmVoYXZpb3JcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogLSBDb3B5IHRleHQgdHJpbW1pbmc6IEF1dG9tYXRpY2FsbHkgcmVtb3ZlcyBsZWFkaW5nL3RyYWlsaW5nIHdoaXRlc3BhY2UgZnJvbSBjb3BpZWQgdGV4dFxuICAgICAqIC0gSG9sZCBTaGlmdCB0byBwcmVzZXJ2ZSB3aGl0ZXNwYWNlXG4gICAgICogLSBTa2lwcyB0cmltbWluZyBpbiBjb2RlIGJsb2NrcywgdGV4dGFyZWFzLCBhbmQgY29udGVudGVkaXRhYmxlIGVsZW1lbnRzXG4gICAgICovXG4gICAgc3RhdGljIF90cmltX2NvcGllZF90ZXh0KCkge1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdjb3B5JywgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICAvLyBEb24ndCB0cmltIGlmIHVzZXIgaXMgaG9sZGluZyBTaGlmdCAoYWxsb3dzIGNvcHlpbmcgd2l0aCB3aGl0ZXNwYWNlIGlmIG5lZWRlZClcbiAgICAgICAgICAgIGlmIChldmVudC5zaGlmdEtleSkgcmV0dXJuO1xuXG4gICAgICAgICAgICBsZXQgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuICAgICAgICAgICAgbGV0IHNlbGVjdGVkX3RleHQgPSBzZWxlY3Rpb24udG9TdHJpbmcoKTtcblxuICAgICAgICAgICAgLy8gRG9uJ3QgdHJpbSBpZiBzZWxlY3Rpb24gaXMgZW1wdHlcbiAgICAgICAgICAgIGlmICghc2VsZWN0ZWRfdGV4dCkgcmV0dXJuO1xuXG4gICAgICAgICAgICAvLyBEb24ndCB0cmltIGlmIGNvcHlpbmcgZnJvbSBjb2RlIGJsb2NrcywgdGV4dGFyZWFzLCBvciBjb250ZW50LWVkaXRhYmxlIChwcmVzZXJ2ZSBmb3JtYXR0aW5nKVxuICAgICAgICAgICAgbGV0IGNvbnRhaW5lciA9IHNlbGVjdGlvbi5nZXRSYW5nZUF0KDApLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyO1xuICAgICAgICAgICAgaWYgKGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gMykgY29udGFpbmVyID0gY29udGFpbmVyLnBhcmVudE5vZGU7IC8vIFRleHQgbm9kZSB0byBlbGVtZW50XG4gICAgICAgICAgICBpZiAoY29udGFpbmVyLmNsb3Nlc3QoJ3ByZSwgY29kZSwgLmNvZGUtYmxvY2ssIHRleHRhcmVhLCBbY29udGVudGVkaXRhYmxlPVwidHJ1ZVwiXScpKSByZXR1cm47XG5cbiAgICAgICAgICAgIGxldCB0cmltbWVkX3RleHQgPSBzZWxlY3RlZF90ZXh0LnRyaW0oKTtcblxuICAgICAgICAgICAgLy8gT25seSBtb2RpZnkgaWYgdGhlcmUncyBhY3R1YWxseSB3aGl0ZXNwYWNlIHRvIHRyaW1cbiAgICAgICAgICAgIGlmICh0cmltbWVkX3RleHQgIT09IHNlbGVjdGVkX3RleHQgJiYgdHJpbW1lZF90ZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGV2ZW50LmNsaXBib2FyZERhdGEuc2V0RGF0YSgndGV4dC9wbGFpbicsIHRyaW1tZWRfdGV4dCk7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ0NvcHk6IHRyaW1tZWQgd2hpdGVzcGFjZSBmcm9tIHNlbGVjdGlvbicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG59XG4iLCIvLyBTaW1wbGUga2V5IHZhbHVlIGNhY2hlLiAgQ2FuIG9ubHkgc3RvcmUgNTAwMCBlbnRyaWVzLCB3aWxsIHJlc2V0IGFmdGVyIDUwMDAgZW50cmllcy5cblxuLy8gVG9kbzoga2VlcCBsb2NhbCBjYWNoZSBjb25jZXB0IHRoZSBzYW1lLCByZXBsYWNlIGdsb2JhbCBjYWNoZSBjb25jZXB0IHdpdGggdGhlIG5vdiAyMDE5IHZlcnNpb24gb2Zcbi8vIHNlc3Npb24gY2FjaGUuICBVc2UgYSBzZXNzaW9uIGtleSAmIGJ1aWxkIGtleSB0byB0cmFjayBjYWNoZSBrZXlzIHNvIGNhY2hlZCB2YWx1ZXMgb25seSBsYXN0IHVudGlsIHVzZXIgbG9ncyBvdXQuXG4vLyByZXZpZXcgc2Vzc2lvbiBjb2RlIHRvIGVuc3VyZSB0aGF0IHNlc3Npb24ga2V5ICphbHdheXMqIHJvdGF0ZXMgb24gbG9nb3V0LiAgTWFrZSBzZXNzaW9uIGlkIGEgcHJvdGVjdGVkIHZhbHVlLlxuY2xhc3MgUnN4X0NhY2hlIHtcbiAgICBzdGF0aWMgb25fY29yZV9kZWZpbmUoKSB7XG4gICAgICAgIENvcmVfQ2FjaGUuX2NhY2hlcyA9IHtcbiAgICAgICAgICAgIGdsb2JhbDoge30sXG4gICAgICAgICAgICBpbnN0YW5jZToge30sXG4gICAgICAgIH07XG5cbiAgICAgICAgQ29yZV9DYWNoZS5fY2FjaGVzX3NldCA9IDA7XG4gICAgfVxuXG4gICAgLy8gQWxpYXMgZm9yIGdldF9pbnN0YW5jZVxuICAgIHN0YXRpYyBnZXQoa2V5KSB7XG4gICAgICAgIHJldHVybiBSc3hfQ2FjaGUuZ2V0X2luc3RhbmNlKGtleSk7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJucyBmcm9tIHRoZSBwb29sIG9mIGNhY2hlZCBkYXRhIGZvciB0aGlzICdpbnN0YW5jZScuICBBbiBpbnN0YW5jZVxuICAgIC8vIGluIHRoaXMgY2FzZSBpcyBhIHZpcnR1YWwgcGFnZSBsb2FkIC8gbmF2aWdhdGlvbiBpbiB0aGUgU1BBLiAgQ2FsbCBNYWluLmxpYi5yZXNldCgpIHRvIHJlc2V0LlxuICAgIC8vIFJldHVybnMgbnVsbCBvbiBmYWlsdXJlXG4gICAgc3RhdGljIGdldF9pbnN0YW5jZShrZXkpIHtcbiAgICAgICAgaWYgKE1haW4uZGVidWcoJ25vX2FwaV9jYWNoZScpKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBrZXlfZW5jb2RlZCA9IFJzeF9DYWNoZS5fZW5jb2Rla2V5KGtleSk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBDb3JlX0NhY2hlLl9jYWNoZXMuaW5zdGFuY2Vba2V5X2VuY29kZWRdICE9IHVuZGVmKSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShDb3JlX0NhY2hlLl9jYWNoZXMuaW5zdGFuY2Vba2V5X2VuY29kZWRdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8vIFJldHVybnMgbnVsbCBvbiBmYWlsdXJlXG4gICAgLy8gUmV0dXJucyBhIGNhY2hlZCB2YWx1ZSBmcm9tIGdsb2JhbCBjYWNoZSAodW5pcXVlIHRvIHBhZ2UgbG9hZCwgc3Vydml2ZXMgcmVzZXQoKSlcbiAgICBzdGF0aWMgZ2V0X2dsb2JhbChrZXkpIHtcbiAgICAgICAgaWYgKE1haW4uZGVidWcoJ25vX2FwaV9jYWNoZScpKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBrZXlfZW5jb2RlZCA9IFJzeF9DYWNoZS5fZW5jb2Rla2V5KGtleSk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBDb3JlX0NhY2hlLl9jYWNoZXMuZ2xvYmFsW2tleV9lbmNvZGVkXSAhPSB1bmRlZikge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoQ29yZV9DYWNoZS5fY2FjaGVzLmdsb2JhbFtrZXlfZW5jb2RlZF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gU2V0cyBhIHZhbHVlIGluIGluc3RhbmNlIGFuZCBnbG9iYWwgY2FjaGUgKG5vdCBzaGFyZWQgYmV0d2VlbiBicm93c2VyIHRhYnMpXG4gICAgc3RhdGljIHNldChrZXksIHZhbHVlKSB7XG4gICAgICAgIGlmIChNYWluLmRlYnVnKCdub19hcGlfY2FjaGUnKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodmFsdWUubGVuZ3RoID4gNjQgKiAxMDI0KSB7XG4gICAgICAgICAgICBEZWJ1Z2dlci5jb25zb2xlX2RlYnVnKCdDQUNIRScsICdXYXJuaW5nIC0gbm90IGNhY2hpbmcgbGFyZ2UgY2FjaGUgZW50cnknLCBrZXkpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGtleV9lbmNvZGVkID0gUnN4X0NhY2hlLl9lbmNvZGVrZXkoa2V5KTtcblxuICAgICAgICBDb3JlX0NhY2hlLl9jYWNoZXMuZ2xvYmFsW2tleV9lbmNvZGVkXSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcbiAgICAgICAgQ29yZV9DYWNoZS5fY2FjaGVzLmluc3RhbmNlW2tleV9lbmNvZGVkXSA9IEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcblxuICAgICAgICAvLyBEZWJ1Z2dlci5jb25zb2xlX2RlYnVnKFwiQ0FDSEVcIiwgXCJTZXRcIiwga2V5LCB2YWx1ZSk7XG5cbiAgICAgICAgQ29yZV9DYWNoZS5fY2FjaGVzX3NldCsrO1xuXG4gICAgICAgIC8vIFJlc2V0IGNhY2hlIGFmdGVyIDUwMDAgaXRlbXMgc2V0XG4gICAgICAgIGlmIChDb3JlX0NhY2hlLl9jYWNoZXNfc2V0ID4gNTAwMCkge1xuICAgICAgICAgICAgLy8gR2V0IGFuIGFjY3VyYXRlIGNvdW50XG4gICAgICAgICAgICBDb3JlX0NhY2hlLl9jYWNoZXNfc2V0ID0gY291bnQoQ29yZV9DYWNoZS5fY2FjaGVzLmdsb2JhbCk7XG5cbiAgICAgICAgICAgIGlmIChDb3JlX0NhY2hlLl9jYWNoZXNfc2V0ID4gNTAwMCkge1xuICAgICAgICAgICAgICAgIENvcmVfQ2FjaGUuX2NhY2hlcyA9IHtcbiAgICAgICAgICAgICAgICAgICAgZ2xvYmFsOiB7fSxcbiAgICAgICAgICAgICAgICAgICAgaW5zdGFuY2U6IHt9LFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgQ29yZV9DYWNoZS5fY2FjaGVzX3NldCA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZXR1cm5zIG51bGwgb24gZmFpbHVyZVxuICAgIC8vIFJldHVybnMgYSBjYWNoZWQgdmFsdWUgZnJvbSBzZXNzaW9uIGNhY2hlIChzaGFyZWQgYmV0d2VlbiBicm93c2VyIHRhYnMpXG4gICAgc3RhdGljIGdldF9zZXNzaW9uKGtleSkge1xuICAgICAgICBpZiAoTWFpbi5kZWJ1Zygnbm9fYXBpX2NhY2hlJykpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFSc3hfQ2FjaGUuX3N1cHBvcnRzU3RvcmFnZSgpKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBrZXlfZW5jb2RlZCA9IFJzeF9DYWNoZS5fZW5jb2Rla2V5KGtleSk7XG5cbiAgICAgICAgbGV0IHJzID0gc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShrZXlfZW5jb2RlZCk7XG5cbiAgICAgICAgaWYgKCFlbXB0eShycykpIHtcbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gU2V0cyBhIHZhbHVlIGluIHNlc3Npb24gY2FjaGUgKHNoYXJlZCBiZXR3ZWVuIGJyb3dzZXIgdGFicylcbiAgICBzdGF0aWMgc2V0X3Nlc3Npb24oa2V5LCB2YWx1ZSwgX3RyeWFnYWluID0gdHJ1ZSkge1xuICAgICAgICBpZiAoTWFpbi5kZWJ1Zygnbm9fYXBpX2NhY2hlJykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh2YWx1ZS5sZW5ndGggPiA2NCAqIDEwMjQpIHtcbiAgICAgICAgICAgIERlYnVnZ2VyLmNvbnNvbGVfZGVidWcoJ0NBQ0hFJywgJ1dhcm5pbmcgLSBub3QgY2FjaGluZyBsYXJnZSBjYWNoZSBlbnRyeScsIGtleSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIVJzeF9DYWNoZS5fc3VwcG9ydHNTdG9yYWdlKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGtleV9lbmNvZGVkID0gUnN4X0NhY2hlLl9lbmNvZGVrZXkoa2V5KTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgc2Vzc2lvblN0b3JhZ2UucmVtb3ZlSXRlbShrZXlfZW5jb2RlZCk7XG4gICAgICAgICAgICBzZXNzaW9uU3RvcmFnZS5zZXRJdGVtKGtleV9lbmNvZGVkLCBKU09OLnN0cmluZ2lmeSh2YWx1ZSkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAoUnN4X0NhY2hlLl9pc091dE9mU3BhY2UoZSkgJiYgc2Vzc2lvblN0b3JhZ2UubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgc2Vzc2lvblN0b3JhZ2UuY2xlYXIoKTtcbiAgICAgICAgICAgICAgICBpZiAoX3RyeWFnYWluKSB7XG4gICAgICAgICAgICAgICAgICAgIENvcmVfQ2FjaGUuc2V0X3Nlc3Npb24oa2V5LCB2YWx1ZSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHN0YXRpYyBfcmVzZXQoKSB7XG4gICAgICAgIENvcmVfQ2FjaGUuX2NhY2hlcy5pbnN0YW5jZSA9IHt9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZvciBnaXZlbiBrZXkgb2YgYW55IHR5cGUgaW5jbHVkaW5nIGFuIG9iamVjdCwgcmV0dXJuIGEgc3RyaW5nIHJlcHJlc2VudGluZ1xuICAgICAqIHRoZSBrZXkgdGhhdCB0aGUgY2FjaGVkIHZhbHVlIHNob3VsZCBiZSBzdG9yZWQgYXMgaW4gc2Vzc2lvbnN0b3JhZ2VcbiAgICAgKi9cbiAgICBzdGF0aWMgX2VuY29kZWtleShrZXkpIHtcbiAgICAgICAgY29uc3QgcHJlZml4ID0gJ2NhY2hlXyc7XG5cbiAgICAgICAgLy8gU2Vzc2lvbiByZWltcGxlbWVudFxuICAgICAgICAvLyB2YXIgcHJlZml4ID0gXCJjYWNoZV9cIiArIFNwYS5zZXNzaW9uKCkudXNlcl9pZCgpICsgXCJfXCI7XG5cbiAgICAgICAgaWYgKGlzX3N0cmluZyhrZXkpICYmIGtleS5sZW5ndGggPCAxNTAgJiYga2V5LmluZGV4T2YoJyAnKSA9PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIHByZWZpeCArIE1hbmlmZXN0LmJ1aWxkX2tleSgpICsgJ18nICsga2V5O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHByZWZpeCArIGhhc2goW01hbmlmZXN0LmJ1aWxkX2tleSgpLCBrZXldKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIERldGVybWluZXMgaWYgc2Vzc2lvblN0b3JhZ2UgaXMgc3VwcG9ydGVkIGluIHRoZSBicm93c2VyO1xuICAgIC8vIHJlc3VsdCBpcyBjYWNoZWQgZm9yIGJldHRlciBwZXJmb3JtYW5jZSBpbnN0ZWFkIG9mIGJlaW5nIHJ1biBlYWNoIHRpbWUuXG4gICAgLy8gRmVhdHVyZSBkZXRlY3Rpb24gaXMgYmFzZWQgb24gaG93IE1vZGVybml6ciBkb2VzIGl0O1xuICAgIC8vIGl0J3Mgbm90IHN0cmFpZ2h0Zm9yd2FyZCBkdWUgdG8gRkY0IGlzc3Vlcy5cbiAgICAvLyBJdCdzIG5vdCBydW4gYXQgcGFyc2UtdGltZSBhcyBpdCB0YWtlcyAyMDBtcyBpbiBBbmRyb2lkLlxuICAgIC8vIENvZGUgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vcGFtZWxhZm94L2xzY2FjaGUvYmxvYi9tYXN0ZXIvbHNjYWNoZS5qcywgQXBhY2hlIExpY2Vuc2UgUGFtZWxhZm94XG4gICAgc3RhdGljIF9zdXBwb3J0c1N0b3JhZ2UoKSB7XG4gICAgICAgIGxldCBrZXkgPSAnX19jYWNoZXRlc3RfXyc7XG4gICAgICAgIGxldCB2YWx1ZSA9IGtleTtcblxuICAgICAgICBpZiAoUnN4X0NhY2hlLl9fc3VwcG9ydHNTdG9yYWdlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBSc3hfQ2FjaGUuX19zdXBwb3J0c1N0b3JhZ2U7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzb21lIGJyb3dzZXJzIHdpbGwgdGhyb3cgYW4gZXJyb3IgaWYgeW91IHRyeSB0byBhY2Nlc3MgbG9jYWwgc3RvcmFnZSAoZS5nLiBicmF2ZSBicm93c2VyKVxuICAgICAgICAvLyBoZW5jZSBjaGVjayBpcyBpbnNpZGUgYSB0cnkvY2F0Y2hcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICghc2Vzc2lvblN0b3JhZ2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGV4KSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShrZXksIHZhbHVlKTtcbiAgICAgICAgICAgIHNlc3Npb25TdG9yYWdlLnJlbW92ZUl0ZW0oa2V5KTtcbiAgICAgICAgICAgIFJzeF9DYWNoZS5fX3N1cHBvcnRzU3RvcmFnZSA9IHRydWU7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIC8vIElmIHdlIGhpdCB0aGUgbGltaXQsIGFuZCB3ZSBkb24ndCBoYXZlIGFuIGVtcHR5IHNlc3Npb25TdG9yYWdlIHRoZW4gaXQgbWVhbnMgd2UgaGF2ZSBzdXBwb3J0XG4gICAgICAgICAgICBpZiAoUnN4X0NhY2hlLl9pc091dE9mU3BhY2UoZSkgJiYgc2Vzc2lvblN0b3JhZ2UubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgUnN4X0NhY2hlLl9fc3VwcG9ydHNTdG9yYWdlID0gdHJ1ZTsgLy8ganVzdCBtYXhlZCBpdCBvdXQgYW5kIGV2ZW4gdGhlIHNldCB0ZXN0IGZhaWxlZC5cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgUnN4X0NhY2hlLl9fc3VwcG9ydHNTdG9yYWdlID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gUnN4X0NhY2hlLl9fc3VwcG9ydHNTdG9yYWdlO1xuICAgIH1cblxuICAgIC8vIENoZWNrIHRvIHNldCBpZiB0aGUgZXJyb3IgaXMgdXMgZGVhbGluZyB3aXRoIGJlaW5nIG91dCBvZiBzcGFjZVxuICAgIHN0YXRpYyBfaXNPdXRPZlNwYWNlKGUpIHtcbiAgICAgICAgcmV0dXJuIGUgJiYgKGUubmFtZSA9PT0gJ1FVT1RBX0VYQ0VFREVEX0VSUicgfHwgZS5uYW1lID09PSAnTlNfRVJST1JfRE9NX1FVT1RBX1JFQUNIRUQnIHx8IGUubmFtZSA9PT0gJ1F1b3RhRXhjZWVkZWRFcnJvcicpO1xuICAgIH1cbn1cbiIsIi8qKlxuICogUnN4X0luaXQgLSBDb3JlIGZyYW1ld29yayBpbml0aWFsaXphdGlvbiBhbmQgZW52aXJvbm1lbnQgdmFsaWRhdGlvblxuICovXG5jbGFzcyBSc3hfSW5pdCB7XG4gICAgLyoqXG4gICAgICogQ2FsbGVkIHZpYSBSc3guX3JzeF9jb3JlX2Jvb3RcbiAgICAgKiBJbml0aWFsaXplcyB0aGUgY29yZSBlbnZpcm9ubWVudCBhbmQgcnVucyBiYXNpYyBzYW5pdHkgY2hlY2tzXG4gICAgICovXG4gICAgc3RhdGljIF9vbl9mcmFtZXdvcmtfY29yZV9pbml0KCkge1xuICAgICAgICBpZiAoIVJzeC5pc19wcm9kKCkpIHtcbiAgICAgICAgICAgIFJzeF9Jbml0Ll9fZW52aXJvbm1lbnRfY2hlY2tzKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEZXZlbG9wbWVudCBlbnZpcm9ubWVudCBjaGVja3MgdG8gZW5zdXJlIHByb3BlciBjb25maWd1cmF0aW9uXG4gICAgICovXG4gICAgc3RhdGljIF9fZW52aXJvbm1lbnRfY2hlY2tzKCkge1xuICAgICAgICAvLyBGaW5kIGFsbCBzY3JpcHQgdGFncyBpbiB0aGUgRE9NXG4gICAgICAgIGNvbnN0IHNjcmlwdHMgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzY3JpcHRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBzY3JpcHQgPSBzY3JpcHRzW2ldO1xuXG4gICAgICAgICAgICAvLyBTa2lwIGlubGluZSBzY3JpcHRzIChubyBzcmMgYXR0cmlidXRlKVxuICAgICAgICAgICAgaWYgKCFzY3JpcHQuc3JjKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHNjcmlwdCBoYXMgZGVmZXIgYXR0cmlidXRlXG4gICAgICAgICAgICBpZiAoIXNjcmlwdC5kZWZlcikge1xuICAgICAgICAgICAgICAgIGNvbnN0IHNyYyA9IHNjcmlwdC5zcmMgfHwgJyhpbmxpbmUgc2NyaXB0KSc7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVhc29uID0gYEFsbCBzY3JpcHQgdGFncyB1c2VkIGluIGFuIFJTcGFkZSBwcm9qZWN0IG11c3QgaGF2ZSBkZWZlciBhdHRyaWJ1dGUuIEZvdW5kIHNjcmlwdCB3aXRob3V0IGRlZmVyOiAke3NyY31gO1xuXG4gICAgICAgICAgICAgICAgLy8gU3RvcCBmcmFtZXdvcmsgYm9vdCB3aXRoIHJlYXNvblxuICAgICAgICAgICAgICAgIFJzeC5fcnN4X2NvcmVfYm9vdF9zdG9wKHJlYXNvbik7XG5cbiAgICAgICAgICAgICAgICAvLyBBbHNvIGxvZyB0byBjb25zb2xlIGZvciB2aXNpYmlsaXR5XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgW1JTWCBCT09UIFNUT1BQRURdICR7cmVhc29ufWApO1xuXG4gICAgICAgICAgICAgICAgLy8gU3RvcCBjaGVja2luZyBhZnRlciBmaXJzdCB2aW9sYXRpb25cbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59IiwiLy8gQEZJTEUtU1VCQ0xBU1MtMDEtRVhDRVBUSU9OXG5cbi8qKlxuICogQmFzZSBjbGFzcyBmb3IgSmF2YVNjcmlwdCBPUk0gbW9kZWxzXG4gKlxuICogUHJvdmlkZXMgY29yZSBmdW5jdGlvbmFsaXR5IGZvciBmZXRjaGluZyByZWNvcmRzIGZyb20gYmFja2VuZCBQSFAgbW9kZWxzLlxuICogQWxsIG1vZGVsIHN0dWJzIGdlbmVyYXRlZCBieSB0aGUgbWFuaWZlc3QgZXh0ZW5kIHRoaXMgYmFzZSBjbGFzcy5cbiAqXG4gKiBFeGFtcGxlIHVzYWdlOlxuICogICAvLyBGZXRjaCBzaW5nbGUgcmVjb3JkXG4gKiAgIGNvbnN0IHVzZXIgPSBhd2FpdCBVc2VyX01vZGVsLmZldGNoKDEyMyk7XG4gKlxuICogICAvLyBGZXRjaCBtdWx0aXBsZSByZWNvcmRzXG4gKiAgIGNvbnN0IHVzZXJzID0gYXdhaXQgVXNlcl9Nb2RlbC5mZXRjaChbMSwgMiwgM10pO1xuICpcbiAqICAgLy8gQ3JlYXRlIGluc3RhbmNlIHdpdGggZGF0YVxuICogICBjb25zdCB1c2VyID0gbmV3IFVzZXJfTW9kZWwoe2lkOiAxLCBuYW1lOiAnSm9obid9KTtcbiAqXG4gKiAgQEluc3RhbnRpYXRhYmxlXG4gKi9cbmNsYXNzIFJzeF9Kc19Nb2RlbCB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0b3IgLSBJbml0aWFsaXplIG1vZGVsIGluc3RhbmNlIHdpdGggZGF0YVxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBLZXktdmFsdWUgcGFpcnMgdG8gcG9wdWxhdGUgdGhlIG1vZGVsXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoZGF0YSA9IHt9KSB7XG4gICAgICAgIC8vIF9fTU9ERUwgU1lTVEVNOiBFbmFibGVzIGF1dG9tYXRpYyBPUk0gaW5zdGFudGlhdGlvbiB3aGVuIGZldGNoaW5nIGZyb20gUEhQIG1vZGVscy5cbiAgICAgICAgLy8gUEhQIG1vZGVscyBhZGQgXCJfX01PREVMXCI6IFwiQ2xhc3NOYW1lXCIgdG8gSlNPTiwgSmF2YVNjcmlwdCB1c2VzIGl0IHRvIGNyZWF0ZSBwcm9wZXIgaW5zdGFuY2VzLlxuICAgICAgICAvLyBUaGlzIHByb3ZpZGVzIHR5cGVkIG1vZGVsIG9iamVjdHMgaW5zdGVhZCBvZiBwbGFpbiBKU09OLCB3aXRoIG1ldGhvZHMgYW5kIHR5cGUgY2hlY2tpbmcuXG5cbiAgICAgICAgLy8gVGhpcyBjb25zdHJ1Y3RvciBmaWx0ZXJzIG91dCB0aGUgX19NT0RFTCBtYXJrZXIgdGhhdCB3YXMgdXNlZCB0byBpZGVudGlmeSB3aGljaCBjbGFzc1xuICAgICAgICAvLyB0byBpbnN0YW50aWF0ZSwga2VlcGluZyBvbmx5IHRoZSBhY3R1YWwgZGF0YSBwcm9wZXJ0aWVzIG9uIHRoZSBpbnN0YW5jZS5cbiAgICAgICAgY29uc3QgeyBfX01PREVMLCAuLi5tb2RlbERhdGEgfSA9IGRhdGE7XG4gICAgICAgIE9iamVjdC5hc3NpZ24odGhpcywgbW9kZWxEYXRhKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGZXRjaCByZWNvcmQocykgZnJvbSB0aGUgYmFja2VuZCBtb2RlbFxuICAgICAqXG4gICAgICogVGhpcyBtZXRob2QgbWlycm9ycyB0aGUgUEhQIE1vZGVsOjpmZXRjaCgpIGZ1bmN0aW9uYWxpdHkuXG4gICAgICogVGhlIGJhY2tlbmQgbW9kZWwgbXVzdCBoYXZlIGEgZmV0Y2goKSBtZXRob2Qgd2l0aCB0aGVcbiAgICAgKiAjW0FqYXhfRW5kcG9pbnRfTW9kZWxfRmV0Y2hdIGFubm90YXRpb24gdG8gYmUgY2FsbGFibGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge251bWJlcnxBcnJheX0gaWQgLSBTaW5nbGUgSUQgb3IgYXJyYXkgb2YgSURzIHRvIGZldGNoXG4gICAgICogQHJldHVybnMge1Byb21pc2V9IC0gU2luZ2xlIG1vZGVsIGluc3RhbmNlLCBhcnJheSBvZiBpbnN0YW5jZXMsIG9yIGZhbHNlXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIGZldGNoKGlkKSB7XG4gICAgICAgIGNvbnN0IEN1cnJlbnRDbGFzcyA9IHRoaXM7XG4gICAgICAgIC8vIEdldCB0aGUgbW9kZWwgY2xhc3MgbmFtZSBmcm9tIHRoZSBjdXJyZW50IGNsYXNzXG4gICAgICAgIGNvbnN0IG1vZGVsTmFtZSA9IEN1cnJlbnRDbGFzcy5uYW1lO1xuXG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgJC5hamF4KHtcbiAgICAgICAgICAgIHVybDogYC9fZmV0Y2gvJHttb2RlbE5hbWV9YCxcbiAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgZGF0YTogeyBpZDogaWQgfSxcbiAgICAgICAgICAgIGRhdGFUeXBlOiAnanNvbicsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEhhbmRsZSByZXNwb25zZSBiYXNlZCBvbiB0eXBlXG4gICAgICAgIGlmIChyZXNwb25zZSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFVzZSBfaW5zdGFudGlhdGVfbW9kZWxzX3JlY3Vyc2l2ZSB0byBoYW5kbGUgT1JNIGluc3RhbnRpYXRpb25cbiAgICAgICAgLy8gVGhpcyB3aWxsIGF1dG9tYXRpY2FsbHkgZGV0ZWN0IF9fTU9ERUwgcHJvcGVydGllcyBhbmQgY3JlYXRlIGFwcHJvcHJpYXRlIGluc3RhbmNlc1xuICAgICAgICByZXR1cm4gUnN4X0pzX01vZGVsLl9pbnN0YW50aWF0ZV9tb2RlbHNfcmVjdXJzaXZlKHJlc3BvbnNlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIG1vZGVsIGNsYXNzIG5hbWVcbiAgICAgKiBVc2VkIGludGVybmFsbHkgZm9yIEFQSSBjYWxsc1xuICAgICAqXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsYXNzIG5hbWVcbiAgICAgKi9cbiAgICBzdGF0aWMgZ2V0TW9kZWxOYW1lKCkge1xuICAgICAgICBjb25zdCBDdXJyZW50Q2xhc3MgPSB0aGlzO1xuICAgICAgICByZXR1cm4gQ3VycmVudENsYXNzLm5hbWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVmcmVzaCB0aGlzIGluc3RhbmNlIHdpdGggbGF0ZXN0IGRhdGEgZnJvbSBzZXJ2ZXJcbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlfSBVcGRhdGVkIGluc3RhbmNlIG9yIGZhbHNlIGlmIG5vdCBmb3VuZFxuICAgICAqL1xuICAgIGFzeW5jIHJlZnJlc2goKSB7XG4gICAgICAgIGNvbnN0IHRoYXQgPSB0aGlzO1xuICAgICAgICBpZiAoIXRoYXQuaWQpIHtcbiAgICAgICAgICAgIHNob3VsZG50X2hhcHBlbignQ2Fubm90IHJlZnJlc2ggbW9kZWwgd2l0aG91dCBpZCBwcm9wZXJ0eScpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZnJlc2ggPSBhd2FpdCB0aGF0LmNvbnN0cnVjdG9yLmZldGNoKHRoYXQuaWQpO1xuXG4gICAgICAgIGlmIChmcmVzaCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFVwZGF0ZSB0aGlzIGluc3RhbmNlIHdpdGggZnJlc2ggZGF0YVxuICAgICAgICBPYmplY3QuYXNzaWduKHRoYXQsIGZyZXNoKTtcbiAgICAgICAgcmV0dXJuIHRoYXQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29udmVydCBtb2RlbCBpbnN0YW5jZSB0byBwbGFpbiBvYmplY3RcbiAgICAgKiBVc2VmdWwgZm9yIHNlcmlhbGl6YXRpb24gb3Igc2VuZGluZyB0byBBUElzXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBQbGFpbiBvYmplY3QgcmVwcmVzZW50YXRpb25cbiAgICAgKi9cbiAgICB0b09iamVjdCgpIHtcbiAgICAgICAgY29uc3QgdGhhdCA9IHRoaXM7XG4gICAgICAgIGNvbnN0IG9iaiA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiB0aGF0KSB7XG4gICAgICAgICAgICBpZiAodGhhdC5oYXNPd25Qcm9wZXJ0eShrZXkpICYmIHR5cGVvZiB0aGF0W2tleV0gIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICBvYmpba2V5XSA9IHRoYXRba2V5XTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb2JqO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbnZlcnQgbW9kZWwgaW5zdGFuY2UgdG8gSlNPTiBzdHJpbmdcbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IEpTT04gcmVwcmVzZW50YXRpb25cbiAgICAgKi9cbiAgICB0b0pTT04oKSB7XG4gICAgICAgIGNvbnN0IHRoYXQgPSB0aGlzO1xuICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodGhhdC50b09iamVjdCgpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWN1cnNpdmVseSBpbnN0YW50aWF0ZSBPUk0gbW9kZWxzIGluIHJlc3BvbnNlIGRhdGFcbiAgICAgKlxuICAgICAqIExvb2tzIGZvciBvYmplY3RzIHdpdGggX19NT0RFTCBwcm9wZXJ0eSBhbmQgaW5zdGFudGlhdGVzIHRoZSBhcHByb3ByaWF0ZVxuICAgICAqIEphdmFTY3JpcHQgbW9kZWwgY2xhc3MgaWYgaXQgZXhpc3RzIGluIHRoZSBnbG9iYWwgc2NvcGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0geyp9IGRhdGEgLSBUaGUgZGF0YSB0byBwcm9jZXNzIChjYW4gYmUgYW55IHR5cGUpXG4gICAgICogQHJldHVybnMgeyp9IFRoZSBkYXRhIHdpdGggT1JNIG9iamVjdHMgaW5zdGFudGlhdGVkXG4gICAgICovXG4gICAgc3RhdGljIF9pbnN0YW50aWF0ZV9tb2RlbHNfcmVjdXJzaXZlKGRhdGEpIHtcbiAgICAgICAgLy8gX19NT0RFTCBTWVNURU06IEVuYWJsZXMgYXV0b21hdGljIE9STSBpbnN0YW50aWF0aW9uIHdoZW4gZmV0Y2hpbmcgZnJvbSBQSFAgbW9kZWxzLlxuICAgICAgICAvLyBQSFAgbW9kZWxzIGFkZCBcIl9fTU9ERUxcIjogXCJDbGFzc05hbWVcIiB0byBKU09OLCBKYXZhU2NyaXB0IHVzZXMgaXQgdG8gY3JlYXRlIHByb3BlciBpbnN0YW5jZXMuXG4gICAgICAgIC8vIFRoaXMgcHJvdmlkZXMgdHlwZWQgbW9kZWwgb2JqZWN0cyBpbnN0ZWFkIG9mIHBsYWluIEpTT04sIHdpdGggbWV0aG9kcyBhbmQgdHlwZSBjaGVja2luZy5cblxuICAgICAgICAvLyBUaGlzIHJlY3Vyc2l2ZSBwcm9jZXNzb3Igc2NhbnMgYWxsIEFQSSByZXNwb25zZSBkYXRhIGxvb2tpbmcgZm9yIF9fTU9ERUwgbWFya2Vycy5cbiAgICAgICAgLy8gV2hlbiBmb3VuZCwgaXQgYXR0ZW1wdHMgdG8gaW5zdGFudGlhdGUgdGhlIGFwcHJvcHJpYXRlIEphdmFTY3JpcHQgbW9kZWwgY2xhc3MsXG4gICAgICAgIC8vIGNvbnZlcnRpbmcge19fTU9ERUw6IFwiVXNlcl9Nb2RlbFwiLCBpZDogMSwgbmFtZTogXCJKb2huXCJ9IGludG8gbmV3IFVzZXJfTW9kZWwoey4uLn0pLlxuICAgICAgICAvLyBXb3JrcyByZWN1cnNpdmVseSB0aHJvdWdoIGFycmF5cyBhbmQgbmVzdGVkIG9iamVjdHMgdG8gaGFuZGxlIGNvbXBsZXggZGF0YSBzdHJ1Y3R1cmVzLlxuICAgICAgICAvLyBIYW5kbGUgbnVsbC91bmRlZmluZWRcbiAgICAgICAgaWYgKGRhdGEgPT09IG51bGwgfHwgZGF0YSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICByZXR1cm4gZGF0YTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEhhbmRsZSBhcnJheXMgLSByZWN1cnNpdmVseSBwcm9jZXNzIGVhY2ggZWxlbWVudFxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkge1xuICAgICAgICAgICAgcmV0dXJuIGRhdGEubWFwKChpdGVtKSA9PiBSc3hfSnNfTW9kZWwuX2luc3RhbnRpYXRlX21vZGVsc19yZWN1cnNpdmUoaXRlbSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIG9iamVjdHNcbiAgICAgICAgaWYgKHR5cGVvZiBkYXRhID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBvYmplY3QgaGFzIGEgX19NT0RFTCBwcm9wZXJ0eVxuICAgICAgICAgICAgaWYgKGRhdGEuX19NT0RFTCAmJiB0eXBlb2YgZGF0YS5fX01PREVMID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIC8vIFRyeSB0byBmaW5kIHRoZSBtb2RlbCBjbGFzcyBpbiB0aGUgZ2xvYmFsIHNjb3BlXG4gICAgICAgICAgICAgICAgY29uc3QgTW9kZWxDbGFzcyA9IHdpbmRvd1tkYXRhLl9fTU9ERUxdO1xuXG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIG1vZGVsIGNsYXNzIGV4aXN0cyBhbmQgZXh0ZW5kcyBSc3hfSnNfTW9kZWwsIGluc3RhbnRpYXRlIGl0XG4gICAgICAgICAgICAgICAgLy8gRHluYW1pYyBtb2RlbCByZXNvbHV0aW9uIHJlcXVpcmVzIGNoZWNraW5nIGNsYXNzIGV4aXN0ZW5jZSAtIEBKUy1ERUZFTlNJVkUtMDEtRVhDRVBUSU9OXG4gICAgICAgICAgICAgICAgaWYgKE1vZGVsQ2xhc3MgJiYgTW9kZWxDbGFzcy5wcm90b3R5cGUgaW5zdGFuY2VvZiBSc3hfSnNfTW9kZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBNb2RlbENsYXNzKGRhdGEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUmVjdXJzaXZlbHkgcHJvY2VzcyBhbGwgb2JqZWN0IHByb3BlcnRpZXNcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHt9O1xuICAgICAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gZGF0YSkge1xuICAgICAgICAgICAgICAgIGlmIChkYXRhLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0W2tleV0gPSBSc3hfSnNfTW9kZWwuX2luc3RhbnRpYXRlX21vZGVsc19yZWN1cnNpdmUoZGF0YVtrZXldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmV0dXJuIHByaW1pdGl2ZSB2YWx1ZXMgYXMtaXNcbiAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfVxufVxuIiwiLyoqXG4gKiBWaWV3X1RyYW5zaXRpb25zIC0gU21vb3RoIHBhZ2UtdG8tcGFnZSB0cmFuc2l0aW9ucyB1c2luZyBWaWV3IFRyYW5zaXRpb25zIEFQSVxuICpcbiAqIEVuYWJsZXMgY3Jvc3MtZG9jdW1lbnQgdmlldyB0cmFuc2l0aW9ucyBzbyB0aGUgYnJvd3NlciBkb2Vzbid0IHBhaW50IHRoZSBuZXcgcGFnZVxuICogdW50aWwgaXQncyByZWFkeSwgY3JlYXRpbmcgc21vb3RoIGFuaW1hdGlvbnMgYmV0d2VlbiBwYWdlcy5cbiAqXG4gKiBGYWxscyBiYWNrIGdyYWNlZnVsbHkgaWYgVmlldyBUcmFuc2l0aW9ucyBBUEkgaXMgbm90IGF2YWlsYWJsZS5cbiAqL1xuY2xhc3MgUnN4X1ZpZXdfVHJhbnNpdGlvbnMge1xuICAgIC8qKlxuICAgICAqIENhbGxlZCBkdXJpbmcgZnJhbWV3b3JrIGNvcmUgaW5pdCBwaGFzZVxuICAgICAqIENoZWNrcyBmb3IgVmlldyBUcmFuc2l0aW9ucyBBUEkgc3VwcG9ydCBhbmQgZW5hYmxlcyBpZiBhdmFpbGFibGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX29uX2ZyYW1ld29ya19jb3JlX2luaXQoKSB7XG4gICAgICAgIC8vIENoZWNrIGlmIFZpZXcgVHJhbnNpdGlvbnMgQVBJIGlzIHN1cHBvcnRlZFxuICAgICAgICBpZiAoIWRvY3VtZW50LnN0YXJ0Vmlld1RyYW5zaXRpb24pIHtcbiAgICAgICAgICAgIGNvbnNvbGVfZGVidWcoJ1ZJRVdfVFJBTlNJVElPTlMnLCAnVmlldyBUcmFuc2l0aW9ucyBBUEkgbm90IHN1cHBvcnRlZCwgc2tpcHBpbmcnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVuYWJsZSBjcm9zcy1kb2N1bWVudCB2aWV3IHRyYW5zaXRpb25zIHZpYSBDU1NcbiAgICAgICAgUnN4X1ZpZXdfVHJhbnNpdGlvbnMuX2luamVjdF90cmFuc2l0aW9uX2NzcygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEluamVjdCBDU1MgdG8gZW5hYmxlIGNyb3NzLWRvY3VtZW50IHZpZXcgdHJhbnNpdGlvbnNcbiAgICAgKlxuICAgICAqIFRoZSBAdmlldy10cmFuc2l0aW9uIHsgbmF2aWdhdGlvbjogYXV0bzsgfSBydWxlIHRlbGxzIHRoZSBicm93c2VyIHRvOlxuICAgICAqIDEuIENhcHR1cmUgYSBzbmFwc2hvdCBvZiB0aGUgY3VycmVudCBwYWdlIGJlZm9yZSBuYXZpZ2F0aW9uXG4gICAgICogMi4gRmV0Y2ggdGhlIG5ldyBwYWdlXG4gICAgICogMy4gV2FpdCB1bnRpbCB0aGUgbmV3IHBhZ2UgaXMgZnVsbHkgbG9hZGVkIGFuZCBwYWludGVkIChkb2N1bWVudC5yZWFkeSlcbiAgICAgKiA0LiBBbmltYXRlIHNtb290aGx5IGJldHdlZW4gdGhlIHR3byBzdGF0ZXNcbiAgICAgKlxuICAgICAqIFRoaXMgcHJldmVudHMgdGhlIHdoaXRlIGZsYXNoIGR1cmluZyBuYXZpZ2F0aW9uIGFuZCBjcmVhdGVzIGFwcC1saWtlIHRyYW5zaXRpb25zLlxuICAgICAqL1xuICAgIHN0YXRpYyBfaW5qZWN0X3RyYW5zaXRpb25fY3NzKCkge1xuICAgICAgICBjb25zdCBzdHlsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG5cbiAgICAgICAgc3R5bGUudGV4dENvbnRlbnQgPSBgXG4gICAgICAgICAgICBAdmlldy10cmFuc2l0aW9uIHtcbiAgICAgICAgICAgICAgICBuYXZpZ2F0aW9uOiBhdXRvO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvKiBEaXNhYmxlIGFuaW1hdGlvbiAtIGluc3RhbnQgdHJhbnNpdGlvbiAqL1xuICAgICAgICAgICAgOjp2aWV3LXRyYW5zaXRpb24tZ3JvdXAoKiksXG4gICAgICAgICAgICA6OnZpZXctdHJhbnNpdGlvbi1vbGQoKiksXG4gICAgICAgICAgICA6OnZpZXctdHJhbnNpdGlvbi1uZXcoKikge1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvbi1kdXJhdGlvbjogMHM7XG4gICAgICAgICAgICB9XG4gICAgICAgIGA7XG5cbiAgICAgICAgZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChzdHlsZSk7XG4gICAgfVxufVxuIiwiLyoqXG4gKiBSZWFkV3JpdGVMb2NrIGltcGxlbWVudGF0aW9uIGZvciBSU3BhZGUgZnJhbWV3b3JrXG4gKiBQcm92aWRlcyBleGNsdXNpdmUgKHdyaXRlKSBhbmQgc2hhcmVkIChyZWFkKSBsb2NraW5nIG1lY2hhbmlzbXMgZm9yIGFzeW5jaHJvbm91cyBvcGVyYXRpb25zXG4gKi9cbmNsYXNzIFJlYWRXcml0ZUxvY2sge1xuICAgIHN0YXRpYyAjbG9ja3MgPSBuZXcgTWFwKCk7XG5cbiAgICAvKipcbiAgICAgKiBHZXQgb3IgY3JlYXRlIGEgbG9jayBvYmplY3QgZm9yIGEgZ2l2ZW4gbmFtZVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljICNnZXRfbG9jayhuYW1lKSB7XG4gICAgICAgIGxldCBzID0gdGhpcy4jbG9ja3MuZ2V0KG5hbWUpO1xuICAgICAgICBpZiAoIXMpIHtcbiAgICAgICAgICAgIHMgPSB7IHJlYWRlcnM6IDAsIHdyaXRlcl9hY3RpdmU6IGZhbHNlLCByZWFkZXJfcTogW10sIHdyaXRlcl9xOiBbXSB9O1xuICAgICAgICAgICAgdGhpcy4jbG9ja3Muc2V0KG5hbWUsIHMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNjaGVkdWxlIHRoZSBuZXh0IG9wZXJhdGlvbiBmb3IgYSBsb2NrXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgI3NjaGVkdWxlKG5hbWUpIHtcbiAgICAgICAgY29uc3QgcyA9IHRoaXMuI2dldF9sb2NrKG5hbWUpO1xuICAgICAgICBpZiAocy53cml0ZXJfYWN0aXZlIHx8IHMucmVhZGVycyA+IDApIHJldHVybjtcblxuICAgICAgICAvLyBydW4gb25lIHdyaXRlciBpZiBxdWV1ZWRcbiAgICAgICAgaWYgKHMud3JpdGVyX3EubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc3QgeyBjYiwgcmVzb2x2ZSwgcmVqZWN0IH0gPSBzLndyaXRlcl9xLnNoaWZ0KCk7XG4gICAgICAgICAgICBzLndyaXRlcl9hY3RpdmUgPSB0cnVlO1xuICAgICAgICAgICAgUHJvbWlzZS5yZXNvbHZlKClcbiAgICAgICAgICAgICAgICAudGhlbihjYilcbiAgICAgICAgICAgICAgICAudGhlbihyZXNvbHZlLCByZWplY3QpXG4gICAgICAgICAgICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBzLndyaXRlcl9hY3RpdmUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy4jc2NoZWR1bGUobmFtZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBvdGhlcndpc2UgcnVuIGFsbCBxdWV1ZWQgcmVhZGVycyBpbiBwYXJhbGxlbFxuICAgICAgICBpZiAocy5yZWFkZXJfcS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBiYXRjaCA9IHMucmVhZGVyX3Euc3BsaWNlKDApO1xuICAgICAgICAgICAgcy5yZWFkZXJzICs9IGJhdGNoLmxlbmd0aDtcbiAgICAgICAgICAgIGZvciAoY29uc3QgeyBjYiwgcmVzb2x2ZSwgcmVqZWN0IH0gb2YgYmF0Y2gpIHtcbiAgICAgICAgICAgICAgICBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgICAgICAgICAgICAgICAudGhlbihjYilcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4ocmVzb2x2ZSwgcmVqZWN0KVxuICAgICAgICAgICAgICAgICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzLnJlYWRlcnMgLT0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzLnJlYWRlcnMgPT09IDApIHRoaXMuI3NjaGVkdWxlKG5hbWUpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFjcXVpcmUgYW4gZXhjbHVzaXZlIG11dGV4IGxvY2sgYnkgbmFtZS5cbiAgICAgKiBPbmx5IG9uZSB3cml0ZXIgcnVucyBhdCBhIHRpbWU7IGJsb2NrcyByZWFkZXJzIHVudGlsIGZpbmlzaGVkLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gICAgICogQHBhcmFtIHsoKSA9PiBhbnl8UHJvbWlzZTxhbnk+fSBjYlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPGFueT59XG4gICAgICovXG4gICAgc3RhdGljIGFjcXVpcmUobmFtZSwgY2IpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHMgPSB0aGlzLiNnZXRfbG9jayhuYW1lKTtcbiAgICAgICAgICAgIHMud3JpdGVyX3EucHVzaCh7IGNiLCByZXNvbHZlLCByZWplY3QgfSk7XG4gICAgICAgICAgICB0aGlzLiNzY2hlZHVsZShuYW1lKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWNxdWlyZSBhIHNoYXJlZCByZWFkIGxvY2sgYnkgbmFtZS5cbiAgICAgKiBNdWx0aXBsZSByZWFkZXJzIGNhbiBydW4gaW4gcGFyYWxsZWw7IGJsb2NrcyB3aGVuIHdyaXRlciBpcyBhY3RpdmUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAgICAgKiBAcGFyYW0geygpID0+IGFueXxQcm9taXNlPGFueT59IGNiXG4gICAgICogQHJldHVybnMge1Byb21pc2U8YW55Pn1cbiAgICAgKi9cbiAgICBzdGF0aWMgYWNxdWlyZV9yZWFkKG5hbWUsIGNiKSB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBzID0gdGhpcy4jZ2V0X2xvY2sobmFtZSk7XG4gICAgICAgICAgICBpZiAocy53cml0ZXJfYWN0aXZlIHx8IHMud3JpdGVyX3EubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHMucmVhZGVyX3EucHVzaCh7IGNiLCByZXNvbHZlLCByZWplY3QgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuI3NjaGVkdWxlKG5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcy5yZWFkZXJzICs9IDE7XG4gICAgICAgICAgICBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgICAgICAgICAgIC50aGVuKGNiKVxuICAgICAgICAgICAgICAgIC50aGVuKHJlc29sdmUsIHJlamVjdClcbiAgICAgICAgICAgICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHMucmVhZGVycyAtPSAxO1xuICAgICAgICAgICAgICAgICAgICBpZiAocy5yZWFkZXJzID09PSAwKSB0aGlzLiNzY2hlZHVsZShuYW1lKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRm9yY2UtdW5sb2NrIGEgbXV0ZXggKHVzZSB3aXRoIGNhdXRpb24pLlxuICAgICAqIENvbXBsZXRlbHkgcmVtb3ZlcyB0aGUgbG9jayBzdGF0ZSwgcG90ZW50aWFsbHkgYnJlYWtpbmcgd2FpdGluZyBvcGVyYXRpb25zLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gICAgICovXG4gICAgc3RhdGljIGZvcmNlX3VubG9jayhuYW1lKSB7XG4gICAgICAgIHRoaXMuI2xvY2tzLmRlbGV0ZShuYW1lKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgaW5mb3JtYXRpb24gYWJvdXQgcGVuZGluZyBvcGVyYXRpb25zIG9uIGEgbXV0ZXguXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAgICAgKiBAcmV0dXJucyB7e3JlYWRlcnM6IG51bWJlciwgd3JpdGVyX2FjdGl2ZTogYm9vbGVhbiwgcmVhZGVyX3E6IG51bWJlciwgd3JpdGVyX3E6IG51bWJlcn19XG4gICAgICovXG4gICAgc3RhdGljIHBlbmRpbmcobmFtZSkge1xuICAgICAgICBjb25zdCBzID0gdGhpcy4jbG9ja3MuZ2V0KG5hbWUpO1xuICAgICAgICBpZiAoIXMpIHJldHVybiB7IHJlYWRlcnM6IDAsIHdyaXRlcl9hY3RpdmU6IGZhbHNlLCByZWFkZXJfcTogMCwgd3JpdGVyX3E6IDAgfTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHJlYWRlcnM6IHMucmVhZGVycyxcbiAgICAgICAgICAgIHdyaXRlcl9hY3RpdmU6IHMud3JpdGVyX2FjdGl2ZSxcbiAgICAgICAgICAgIHJlYWRlcl9xOiBzLnJlYWRlcl9xLmxlbmd0aCxcbiAgICAgICAgICAgIHdyaXRlcl9xOiBzLndyaXRlcl9xLmxlbmd0aFxuICAgICAgICB9O1xuICAgIH1cbn0iLCIvKipcbiAqIEZvcm0gdXRpbGl0aWVzIGZvciB2YWxpZGF0aW9uIGFuZCBlcnJvciBoYW5kbGluZ1xuICovXG5jbGFzcyBGb3JtX1V0aWxzIHtcbiAgICAvKipcbiAgICAgKiBGcmFtZXdvcmsgaW5pdGlhbGl6YXRpb24gaG9vayB0byByZWdpc3RlciBqUXVlcnkgcGx1Z2luXG4gICAgICogQ3JlYXRlcyAkLmZuLmFqYXhfc3VibWl0KCkgZm9yIGZvcm0gZWxlbWVudHNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfb25fZnJhbWV3b3JrX2NvcmVfZGVmaW5lKHBhcmFtcyA9IHt9KSB7XG4gICAgICAgICQuZm4uYWpheF9zdWJtaXQgPSBmdW5jdGlvbihvcHRpb25zID0ge30pIHtcbiAgICAgICAgICAgIGNvbnN0ICRlbGVtZW50ID0gJCh0aGlzKTtcblxuICAgICAgICAgICAgaWYgKCEkZWxlbWVudC5pcygnZm9ybScpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdhamF4X3N1Ym1pdCgpIGNhbiBvbmx5IGJlIGNhbGxlZCBvbiBmb3JtIGVsZW1lbnRzJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHVybCA9ICRlbGVtZW50LmF0dHIoJ2FjdGlvbicpO1xuICAgICAgICAgICAgaWYgKCF1cmwpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Zvcm0gbXVzdCBoYXZlIGFuIGFjdGlvbiBhdHRyaWJ1dGUnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgeyBjb250cm9sbGVyLCBhY3Rpb24gfSA9IEFqYXguYWpheF91cmxfdG9fY29udHJvbGxlcl9hY3Rpb24odXJsKTtcblxuICAgICAgICAgICAgcmV0dXJuIEZvcm1fVXRpbHMuYWpheF9zdWJtaXQoJGVsZW1lbnQsIGNvbnRyb2xsZXIsIGFjdGlvbiwgb3B0aW9ucyk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2hvd3MgZm9ybSB2YWxpZGF0aW9uIGVycm9yc1xuICAgICAqXG4gICAgICogUkVRVUlSRUQgSFRNTCBTVFJVQ1RVUkU6XG4gICAgICogRm9yIGlubGluZSBmaWVsZCBlcnJvcnMgdG8gZGlzcGxheSBwcm9wZXJseSwgZm9ybSBmaWVsZHMgbXVzdCBmb2xsb3cgdGhpcyBzdHJ1Y3R1cmU6XG4gICAgICpcbiAgICAgKiA8ZGl2IGNsYXNzPVwiZm9ybS1ncm91cFwiPlxuICAgICAqICAgPGxhYmVsIGNsYXNzPVwiZm9ybS1sYWJlbFwiIGZvcj1cImZpZWxkLW5hbWVcIj5GaWVsZCBMYWJlbDwvbGFiZWw+XG4gICAgICogICA8aW5wdXQgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIiBpZD1cImZpZWxkLW5hbWVcIiBuYW1lPVwiZmllbGQtbmFtZVwiIHR5cGU9XCJ0ZXh0XCI+XG4gICAgICogPC9kaXY+XG4gICAgICpcbiAgICAgKiBLZXkgcmVxdWlyZW1lbnRzOlxuICAgICAqIC0gV3JhcCBlYWNoIGZpZWxkIGluIGEgY29udGFpbmVyIHdpdGggY2xhc3MgXCJmb3JtLWdyb3VwXCIgKG9yIFwiZm9ybS1jaGVja1wiIC8gXCJpbnB1dC1ncm91cFwiKVxuICAgICAqIC0gSW5wdXQgbXVzdCBoYXZlIGEgXCJuYW1lXCIgYXR0cmlidXRlIG1hdGNoaW5nIHRoZSBlcnJvciBrZXlcbiAgICAgKiAtIFVzZSBcImZvcm0tY29udHJvbFwiIGNsYXNzIG9uIGlucHV0cyBmb3IgQm9vdHN0cmFwIDUgc3R5bGluZ1xuICAgICAqXG4gICAgICogQWNjZXB0cyB0aHJlZSBmb3JtYXRzOlxuICAgICAqIC0gU3RyaW5nOiBTaW5nbGUgZXJyb3Igc2hvd24gYXMgYWxlcnRcbiAgICAgKiAtIEFycmF5IG9mIHN0cmluZ3M6IE11bHRpcGxlIGVycm9ycyBzaG93biBhcyBidWxsZXRlZCBhbGVydFxuICAgICAqIC0gT2JqZWN0OiBGaWVsZCBuYW1lcyBtYXBwZWQgdG8gZXJyb3JzLCBzaG93biBpbmxpbmUgKHVubWF0Y2hlZCBzaG93biBhcyBhbGVydClcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRfc2VsZWN0b3IgLSBqUXVlcnkgc2VsZWN0b3IgZm9yIHBhcmVudCBlbGVtZW50XG4gICAgICogQHBhcmFtIHtzdHJpbmd8T2JqZWN0fEFycmF5fSBlcnJvcnMgLSBFcnJvciBtZXNzYWdlcyB0byBkaXNwbGF5XG4gICAgICogQHJldHVybnMge1Byb21pc2V9IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBhbmltYXRpb25zIGNvbXBsZXRlXG4gICAgICovXG4gICAgc3RhdGljIGFwcGx5X2Zvcm1fZXJyb3JzKHBhcmVudF9zZWxlY3RvciwgZXJyb3JzKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JzKTtcblxuICAgICAgICBjb25zdCAkcGFyZW50ID0gJChwYXJlbnRfc2VsZWN0b3IpO1xuXG4gICAgICAgIC8vIFJlc2V0IHRoZSBmb3JtIGVycm9ycyBiZWZvcmUgYXBwbHlpbmcgbmV3IG9uZXNcbiAgICAgICAgRm9ybV9VdGlscy5yZXNldF9mb3JtX2Vycm9ycyhwYXJlbnRfc2VsZWN0b3IpO1xuXG4gICAgICAgIC8vIE5vcm1hbGl6ZSBpbnB1dCB0byBzdGFuZGFyZCBmb3JtYXRcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IEZvcm1fVXRpbHMuX25vcm1hbGl6ZV9lcnJvcnMoZXJyb3JzKTtcblxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgICAgIGxldCBhbmltYXRpb25zID0gW107XG5cbiAgICAgICAgICAgIGlmIChub3JtYWxpemVkLnR5cGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgLy8gU2luZ2xlIGVycm9yIG1lc3NhZ2VcbiAgICAgICAgICAgICAgICBhbmltYXRpb25zID0gRm9ybV9VdGlscy5fYXBwbHlfZ2VuZXJhbF9lcnJvcnMoJHBhcmVudCwgbm9ybWFsaXplZC5kYXRhKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAobm9ybWFsaXplZC50eXBlID09PSAnYXJyYXknKSB7XG4gICAgICAgICAgICAgICAgLy8gQXJyYXkgb2YgZXJyb3IgbWVzc2FnZXNcbiAgICAgICAgICAgICAgICBjb25zdCBkZWR1cGxpY2F0ZWQgPSBGb3JtX1V0aWxzLl9kZWR1cGxpY2F0ZV9lcnJvcnMobm9ybWFsaXplZC5kYXRhKTtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25zID0gRm9ybV9VdGlscy5fYXBwbHlfZ2VuZXJhbF9lcnJvcnMoJHBhcmVudCwgZGVkdXBsaWNhdGVkKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAobm9ybWFsaXplZC50eXBlID09PSAnZmllbGRzJykge1xuICAgICAgICAgICAgICAgIC8vIEZpZWxkLXNwZWNpZmljIGVycm9yc1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IEZvcm1fVXRpbHMuX2FwcGx5X2ZpZWxkX2Vycm9ycygkcGFyZW50LCBub3JtYWxpemVkLmRhdGEpO1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvbnMgPSByZXN1bHQuYW5pbWF0aW9ucztcblxuICAgICAgICAgICAgICAgIC8vIENvdW50IG1hdGNoZWQgZmllbGRzXG4gICAgICAgICAgICAgICAgY29uc3QgbWF0Y2hlZF9jb3VudCA9IE9iamVjdC5rZXlzKG5vcm1hbGl6ZWQuZGF0YSkubGVuZ3RoIC0gT2JqZWN0LmtleXMocmVzdWx0LnVubWF0Y2hlZCkubGVuZ3RoO1xuICAgICAgICAgICAgICAgIGNvbnN0IHVubWF0Y2hlZF9kZWR1cGxpY2F0ZWQgPSBGb3JtX1V0aWxzLl9kZWR1cGxpY2F0ZV9lcnJvcnMocmVzdWx0LnVubWF0Y2hlZCk7XG4gICAgICAgICAgICAgICAgY29uc3QgdW5tYXRjaGVkX2NvdW50ID0gT2JqZWN0LmtleXModW5tYXRjaGVkX2RlZHVwbGljYXRlZCkubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgLy8gU2hvdyBzdW1tYXJ5IGFsZXJ0IGlmIHRoZXJlIGFyZSBhbnkgZmllbGQgZXJyb3JzIChtYXRjaGVkIG9yIHVubWF0Y2hlZClcbiAgICAgICAgICAgICAgICBpZiAobWF0Y2hlZF9jb3VudCA+IDAgfHwgdW5tYXRjaGVkX2NvdW50ID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBCdWlsZCBzdW1tYXJ5IG1lc3NhZ2VcbiAgICAgICAgICAgICAgICAgICAgbGV0IHN1bW1hcnlfbXNnID0gJyc7XG4gICAgICAgICAgICAgICAgICAgIGlmIChtYXRjaGVkX2NvdW50ID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyeV9tc2cgPSBtYXRjaGVkX2NvdW50ID09PSAxXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyAnUGxlYXNlIGNvcnJlY3QgdGhlIGVycm9yIGhpZ2hsaWdodGVkIGJlbG93LidcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6ICdQbGVhc2UgY29ycmVjdCB0aGUgZXJyb3JzIGhpZ2hsaWdodGVkIGJlbG93Lic7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGVyZSBhcmUgdW5tYXRjaGVkIGVycm9ycywgYWRkIHRoZW0gYXMgYSBidWxsZXRlZCBsaXN0XG4gICAgICAgICAgICAgICAgICAgIGlmICh1bm1hdGNoZWRfY291bnQgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBzdW1tYXJ5X2FuaW1hdGlvbnMgPSBGb3JtX1V0aWxzLl9hcHBseV9jb21iaW5lZF9lcnJvcigkcGFyZW50LCBzdW1tYXJ5X21zZywgdW5tYXRjaGVkX2RlZHVwbGljYXRlZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBhbmltYXRpb25zLnB1c2goLi4uc3VtbWFyeV9hbmltYXRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEp1c3QgdGhlIHN1bW1hcnkgbWVzc2FnZSwgbm8gdW5tYXRjaGVkIGVycm9yc1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3VtbWFyeV9hbmltYXRpb25zID0gRm9ybV9VdGlscy5fYXBwbHlfZ2VuZXJhbF9lcnJvcnMoJHBhcmVudCwgc3VtbWFyeV9tc2cpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYW5pbWF0aW9ucy5wdXNoKC4uLnN1bW1hcnlfYW5pbWF0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFJlc29sdmUgdGhlIHByb21pc2Ugb25jZSBhbGwgYW5pbWF0aW9ucyBhcmUgY29tcGxldGVcbiAgICAgICAgICAgIFByb21pc2UuYWxsKGFuaW1hdGlvbnMpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIFNjcm9sbCB0byBlcnJvciBjb250YWluZXIgaWYgaXQgZXhpc3RzXG4gICAgICAgICAgICAgICAgY29uc3QgJGVycm9yX2NvbnRhaW5lciA9ICRwYXJlbnQuZmluZCgnW2RhdGEtaWQ9XCJlcnJvcl9jb250YWluZXJcIl0nKS5maXJzdCgpO1xuICAgICAgICAgICAgICAgIGlmICgkZXJyb3JfY29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udGFpbmVyX3RvcCA9ICRlcnJvcl9jb250YWluZXIub2Zmc2V0KCkudG9wO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIENhbGN1bGF0ZSBmaXhlZCBoZWFkZXIgb2Zmc2V0XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGZpeGVkX2hlYWRlcl9oZWlnaHQgPSBGb3JtX1V0aWxzLl9nZXRfZml4ZWRfaGVhZGVyX2hlaWdodCgpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFNjcm9sbCB0byBwb3NpdGlvbiBlcnJvciBjb250YWluZXIgMjBweCBiZWxvdyBhbnkgZml4ZWQgaGVhZGVyc1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0YXJnZXRfc2Nyb2xsID0gY29udGFpbmVyX3RvcCAtIGZpeGVkX2hlYWRlcl9oZWlnaHQgLSAyMDtcbiAgICAgICAgICAgICAgICAgICAgJCgnaHRtbCwgYm9keScpLmFuaW1hdGUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgc2Nyb2xsVG9wOiB0YXJnZXRfc2Nyb2xsXG4gICAgICAgICAgICAgICAgICAgIH0sIDUwMCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENsZWFycyBmb3JtIHZhbGlkYXRpb24gZXJyb3JzIGFuZCByZXNldHMgYWxsIGZvcm0gdmFsdWVzIHRvIGRlZmF1bHRzXG4gICAgICogQHBhcmFtIHtzdHJpbmd8alF1ZXJ5fSBmb3JtX3NlbGVjdG9yIC0galF1ZXJ5IHNlbGVjdG9yIG9yIGpRdWVyeSBvYmplY3QgZm9yIGZvcm0gZWxlbWVudFxuICAgICAqL1xuICAgIHN0YXRpYyByZXNldChmb3JtX3NlbGVjdG9yKSB7XG4gICAgICAgIGNvbnN0ICRmb3JtID0gdHlwZW9mIGZvcm1fc2VsZWN0b3IgPT09ICdzdHJpbmcnID8gJChmb3JtX3NlbGVjdG9yKSA6IGZvcm1fc2VsZWN0b3I7XG5cbiAgICAgICAgRm9ybV9VdGlscy5yZXNldF9mb3JtX2Vycm9ycyhmb3JtX3NlbGVjdG9yKTtcbiAgICAgICAgJGZvcm0udHJpZ2dlcigncmVzZXQnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXJpYWxpemVzIGZvcm0gZGF0YSBpbnRvIGtleS12YWx1ZSBvYmplY3RcbiAgICAgKiBSZXR1cm5zIGFsbCBpbnB1dCBlbGVtZW50cyB3aXRoIG5hbWUgYXR0cmlidXRlcyBhcyBvYmplY3QgcHJvcGVydGllc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfGpRdWVyeX0gZm9ybV9zZWxlY3RvciAtIGpRdWVyeSBzZWxlY3RvciBvciBqUXVlcnkgb2JqZWN0IGZvciBmb3JtIGVsZW1lbnRcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBGb3JtIGRhdGEgYXMga2V5LXZhbHVlIHBhaXJzXG4gICAgICovXG4gICAgc3RhdGljIHNlcmlhbGl6ZShmb3JtX3NlbGVjdG9yKSB7XG4gICAgICAgIGNvbnN0ICRmb3JtID0gdHlwZW9mIGZvcm1fc2VsZWN0b3IgPT09ICdzdHJpbmcnID8gJChmb3JtX3NlbGVjdG9yKSA6IGZvcm1fc2VsZWN0b3I7XG4gICAgICAgIGNvbnN0IGRhdGEgPSB7fTtcblxuICAgICAgICAkZm9ybS5zZXJpYWxpemVBcnJheSgpLmZvckVhY2goKGl0ZW0pID0+IHtcbiAgICAgICAgICAgIGRhdGFbaXRlbS5uYW1lXSA9IGl0ZW0udmFsdWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN1Ym1pdHMgZm9ybSB0byBSU1ggY29udHJvbGxlciBhY3Rpb24gdmlhIEFKQVhcbiAgICAgKiBAcGFyYW0ge3N0cmluZ3xqUXVlcnl9IGZvcm1fc2VsZWN0b3IgLSBqUXVlcnkgc2VsZWN0b3Igb3IgalF1ZXJ5IG9iamVjdCBmb3IgZm9ybSBlbGVtZW50XG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGNvbnRyb2xsZXIgLSBDb250cm9sbGVyIGNsYXNzIG5hbWUgKGUuZy4sICdVc2VyX0NvbnRyb2xsZXInKVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBhY3Rpb24gLSBBY3Rpb24gbWV0aG9kIG5hbWUgKGUuZy4sICdzYXZlX3Byb2ZpbGUnKVxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3B0aW9uYWwgY29uZmlndXJhdGlvbiB7b25fc3VjY2VzczogZm4sIG9uX2Vycm9yOiBmbn1cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggcmVzcG9uc2UgZGF0YVxuICAgICAqL1xuICAgIHN0YXRpYyBhc3luYyBhamF4X3N1Ym1pdChmb3JtX3NlbGVjdG9yLCBjb250cm9sbGVyLCBhY3Rpb24sIG9wdGlvbnMgPSB7fSkge1xuICAgICAgICBjb25zdCAkZm9ybSA9IHR5cGVvZiBmb3JtX3NlbGVjdG9yID09PSAnc3RyaW5nJyA/ICQoZm9ybV9zZWxlY3RvcikgOiBmb3JtX3NlbGVjdG9yO1xuICAgICAgICBjb25zdCBmb3JtX2RhdGEgPSBGb3JtX1V0aWxzLnNlcmlhbGl6ZSgkZm9ybSk7XG5cbiAgICAgICAgRm9ybV9VdGlscy5yZXNldF9mb3JtX2Vycm9ycyhmb3JtX3NlbGVjdG9yKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBBamF4LmNhbGwoY29udHJvbGxlciwgYWN0aW9uLCBmb3JtX2RhdGEpO1xuXG4gICAgICAgICAgICBpZiAob3B0aW9ucy5vbl9zdWNjZXNzKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5vbl9zdWNjZXNzKHJlc3BvbnNlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgaWYgKGVycm9yLnR5cGUgPT09ICdmb3JtX2Vycm9yJyAmJiBlcnJvci5kZXRhaWxzKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgRm9ybV9VdGlscy5hcHBseV9mb3JtX2Vycm9ycyhmb3JtX3NlbGVjdG9yLCBlcnJvci5kZXRhaWxzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgRm9ybV9VdGlscy5hcHBseV9mb3JtX2Vycm9ycyhmb3JtX3NlbGVjdG9yLCBlcnJvci5tZXNzYWdlIHx8ICdBbiBlcnJvciBvY2N1cnJlZCcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAob3B0aW9ucy5vbl9lcnJvcikge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMub25fZXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgZm9ybSB2YWxpZGF0aW9uIGVycm9yc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRfc2VsZWN0b3IgLSBqUXVlcnkgc2VsZWN0b3IgZm9yIHBhcmVudCBlbGVtZW50XG4gICAgICovXG4gICAgc3RhdGljIHJlc2V0X2Zvcm1fZXJyb3JzKHBhcmVudF9zZWxlY3Rvcikge1xuICAgICAgICBjb25zdCAkcGFyZW50ID0gJChwYXJlbnRfc2VsZWN0b3IpO1xuXG4gICAgICAgIC8vIFJlbW92ZSBmbGFzaCBtZXNzYWdlc1xuICAgICAgICAkKCcuZmxhc2gtbWVzc2FnZXMnKS5yZW1vdmUoKTtcblxuICAgICAgICAvLyBSZW1vdmUgYWxlcnQtZGFuZ2VyIG1lc3NhZ2VzXG4gICAgICAgICRwYXJlbnQuZmluZCgnLmFsZXJ0LWRhbmdlcicpLnJlbW92ZSgpO1xuXG4gICAgICAgIC8vIFJlbW92ZSB2YWxpZGF0aW9uIGVycm9yIGNsYXNzZXMgYW5kIHRleHQgZnJvbSBmb3JtIGVsZW1lbnRzXG4gICAgICAgICRwYXJlbnQuZmluZCgnLmlzLWludmFsaWQnKS5yZW1vdmVDbGFzcygnaXMtaW52YWxpZCcpO1xuICAgICAgICAkcGFyZW50LmZpbmQoJy5pbnZhbGlkLWZlZWRiYWNrJykucmVtb3ZlKCk7XG4gICAgfVxuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICAvKipcbiAgICAgKiBOb3JtYWxpemVzIGVycm9yIGlucHV0IGludG8gc3RhbmRhcmQgZm9ybWF0c1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfE9iamVjdHxBcnJheX0gZXJyb3JzIC0gUmF3IGVycm9yIGlucHV0XG4gICAgICogQHJldHVybnMge09iamVjdH0gTm9ybWFsaXplZCBlcnJvcnMgYXMge3R5cGU6ICdzdHJpbmcnfCdhcnJheSd8J2ZpZWxkcycsIGRhdGE6IC4uLn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfbm9ybWFsaXplX2Vycm9ycyhlcnJvcnMpIHtcbiAgICAgICAgLy8gSGFuZGxlIG51bGwvdW5kZWZpbmVkXG4gICAgICAgIGlmICghZXJyb3JzKSB7XG4gICAgICAgICAgICByZXR1cm4geyB0eXBlOiAnc3RyaW5nJywgZGF0YTogJ0FuIGVycm9yIGhhcyBvY2N1cnJlZCcgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEhhbmRsZSBzdHJpbmdcbiAgICAgICAgaWYgKHR5cGVvZiBlcnJvcnMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXR1cm4geyB0eXBlOiAnc3RyaW5nJywgZGF0YTogZXJyb3JzIH07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBIYW5kbGUgYXJyYXlcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZXJyb3JzKSkge1xuICAgICAgICAgICAgLy8gQXJyYXkgb2Ygc3RyaW5ncyAtIGdlbmVyYWwgZXJyb3JzXG4gICAgICAgICAgICBpZiAoZXJyb3JzLmV2ZXJ5KChlKSA9PiB0eXBlb2YgZSA9PT0gJ3N0cmluZycpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ2FycmF5JywgZGF0YTogZXJyb3JzIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBBcnJheSB3aXRoIG9iamVjdCBhcyBmaXJzdCBlbGVtZW50IC0gZXh0cmFjdCBpdFxuICAgICAgICAgICAgaWYgKGVycm9ycy5sZW5ndGggPiAwICYmIHR5cGVvZiBlcnJvcnNbMF0gPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIEZvcm1fVXRpbHMuX25vcm1hbGl6ZV9lcnJvcnMoZXJyb3JzWzBdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEVtcHR5IG9yIG1peGVkIGFycmF5XG4gICAgICAgICAgICByZXR1cm4geyB0eXBlOiAnYXJyYXknLCBkYXRhOiBbXSB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIG9iamVjdCAtIGNoZWNrIGZvciBMYXJhdmVsIHJlc3BvbnNlIHdyYXBwZXJcbiAgICAgICAgaWYgKHR5cGVvZiBlcnJvcnMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAvLyBVbndyYXAge2Vycm9yczogey4uLn19IG9yIHtlcnJvcjogey4uLn19XG4gICAgICAgICAgICBjb25zdCB1bndyYXBwZWQgPSBlcnJvcnMuZXJyb3JzIHx8IGVycm9ycy5lcnJvcjtcbiAgICAgICAgICAgIGlmICh1bndyYXBwZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gRm9ybV9VdGlscy5fbm9ybWFsaXplX2Vycm9ycyh1bndyYXBwZWQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDb252ZXJ0IExhcmF2ZWwgdmFsaWRhdG9yIGZvcm1hdCB7ZmllbGQ6IFttc2cxLCBtc2cyXX0gdG8ge2ZpZWxkOiBtc2cxfVxuICAgICAgICAgICAgY29uc3Qgbm9ybWFsaXplZCA9IHt9O1xuICAgICAgICAgICAgZm9yIChjb25zdCBmaWVsZCBpbiBlcnJvcnMpIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyb3JzLmhhc093blByb3BlcnR5KGZpZWxkKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGVycm9yc1tmaWVsZF07XG4gICAgICAgICAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSAmJiB2YWx1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkW2ZpZWxkXSA9IHZhbHVlWzBdO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGl6ZWRbZmllbGRdID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkW2ZpZWxkXSA9IFN0cmluZyh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB7IHR5cGU6ICdmaWVsZHMnLCBkYXRhOiBub3JtYWxpemVkIH07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBGaW5hbCBjYXRjaC1hbGwqXG4gICAgICAgIHJldHVybiB7IHR5cGU6ICdzdHJpbmcnLCBkYXRhOiBTdHJpbmcoZXJyb3JzKSB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgZHVwbGljYXRlIGVycm9yIG1lc3NhZ2VzIGZyb20gYXJyYXkgb3Igb2JqZWN0IHZhbHVlc1xuICAgICAqIEBwYXJhbSB7QXJyYXl8T2JqZWN0fSBlcnJvcnMgLSBFcnJvcnMgdG8gZGVkdXBsaWNhdGVcbiAgICAgKiBAcmV0dXJucyB7QXJyYXl8T2JqZWN0fSBEZWR1cGxpY2F0ZWQgZXJyb3JzXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX2RlZHVwbGljYXRlX2Vycm9ycyhlcnJvcnMpIHtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoZXJyb3JzKSkge1xuICAgICAgICAgICAgcmV0dXJuIFsuLi5uZXcgU2V0KGVycm9ycyldO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBlcnJvcnMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBjb25zdCBzZWVuID0gbmV3IFNldCgpO1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0ge307XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBlcnJvcnMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZSA9IGVycm9yc1trZXldO1xuICAgICAgICAgICAgICAgIGlmICghc2Vlbi5oYXModmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlZW4uYWRkKHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGVycm9ycztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBcHBsaWVzIGZpZWxkLXNwZWNpZmljIHZhbGlkYXRpb24gZXJyb3JzIHRvIGZvcm0gaW5wdXRzXG4gICAgICogQHBhcmFtIHtqUXVlcnl9ICRwYXJlbnQgLSBQYXJlbnQgZWxlbWVudCBjb250YWluaW5nIGZvcm1cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gZmllbGRfZXJyb3JzIC0gT2JqZWN0IG1hcHBpbmcgZmllbGQgbmFtZXMgdG8gZXJyb3IgbWVzc2FnZXNcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBPYmplY3QgY29udGFpbmluZyB7YW5pbWF0aW9uczogQXJyYXksIHVubWF0Y2hlZDogT2JqZWN0fVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9hcHBseV9maWVsZF9lcnJvcnMoJHBhcmVudCwgZmllbGRfZXJyb3JzKSB7XG4gICAgICAgIGNvbnN0IGFuaW1hdGlvbnMgPSBbXTtcbiAgICAgICAgY29uc3QgdW5tYXRjaGVkID0ge307XG5cbiAgICAgICAgZm9yIChjb25zdCBmaWVsZF9uYW1lIGluIGZpZWxkX2Vycm9ycykge1xuICAgICAgICAgICAgY29uc3QgZXJyb3JfbWVzc2FnZSA9IGZpZWxkX2Vycm9yc1tmaWVsZF9uYW1lXTtcbiAgICAgICAgICAgIGNvbnN0ICRpbnB1dCA9ICRwYXJlbnQuZmluZChgW25hbWU9XCIke2ZpZWxkX25hbWV9XCJdYCk7XG5cbiAgICAgICAgICAgIGlmICghJGlucHV0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHVubWF0Y2hlZFtmaWVsZF9uYW1lXSA9IGVycm9yX21lc3NhZ2U7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0ICRlcnJvciA9ICQoJzxkaXYgY2xhc3M9XCJpbnZhbGlkLWZlZWRiYWNrXCI+PC9kaXY+JykuaHRtbChlcnJvcl9tZXNzYWdlKTtcbiAgICAgICAgICAgIGNvbnN0ICR0YXJnZXQgPSAkaW5wdXQuY2xvc2VzdCgnLmZvcm0tZ3JvdXAsIC5mb3JtLWNoZWNrLCAuaW5wdXQtZ3JvdXAnKTtcblxuICAgICAgICAgICAgaWYgKCEkdGFyZ2V0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHVubWF0Y2hlZFtmaWVsZF9uYW1lXSA9IGVycm9yX21lc3NhZ2U7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICRpbnB1dC5hZGRDbGFzcygnaXMtaW52YWxpZCcpO1xuICAgICAgICAgICAgJGVycm9yLmFwcGVuZFRvKCR0YXJnZXQpO1xuICAgICAgICAgICAgYW5pbWF0aW9ucy5wdXNoKCRlcnJvci5oaWRlKCkuZmFkZUluKDMwMCkucHJvbWlzZSgpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7IGFuaW1hdGlvbnMsIHVubWF0Y2hlZCB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFwcGxpZXMgY29tYmluZWQgZXJyb3IgbWVzc2FnZSB3aXRoIHN1bW1hcnkgYW5kIHVubWF0Y2hlZCBmaWVsZCBlcnJvcnNcbiAgICAgKiBAcGFyYW0ge2pRdWVyeX0gJHBhcmVudCAtIFBhcmVudCBlbGVtZW50IGNvbnRhaW5pbmcgZm9ybVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzdW1tYXJ5X21zZyAtIFN1bW1hcnkgbWVzc2FnZSAoZS5nLiwgXCJQbGVhc2UgY29ycmVjdCB0aGUgZXJyb3JzIGJlbG93XCIpXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHVubWF0Y2hlZF9lcnJvcnMgLSBPYmplY3Qgb2YgZmllbGQgZXJyb3JzIHRoYXQgY291bGRuJ3QgYmUgbWF0Y2hlZCB0byBmaWVsZHNcbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IEFycmF5IG9mIGFuaW1hdGlvbiBwcm9taXNlc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9hcHBseV9jb21iaW5lZF9lcnJvcigkcGFyZW50LCBzdW1tYXJ5X21zZywgdW5tYXRjaGVkX2Vycm9ycykge1xuICAgICAgICBjb25zdCBhbmltYXRpb25zID0gW107XG4gICAgICAgIGNvbnN0ICRlcnJvcl9jb250YWluZXIgPSAkcGFyZW50LmZpbmQoJ1tkYXRhLWlkPVwiZXJyb3JfY29udGFpbmVyXCJdJykuZmlyc3QoKTtcbiAgICAgICAgY29uc3QgJHRhcmdldCA9ICRlcnJvcl9jb250YWluZXIubGVuZ3RoID4gMCA/ICRlcnJvcl9jb250YWluZXIgOiAkcGFyZW50O1xuXG4gICAgICAgIC8vIENyZWF0ZSBhbGVydCB3aXRoIHN1bW1hcnkgbWVzc2FnZSBhbmQgYnVsbGV0ZWQgbGlzdCBvZiB1bm1hdGNoZWQgZXJyb3JzXG4gICAgICAgIGNvbnN0ICRhbGVydCA9ICQoJzxkaXYgY2xhc3M9XCJhbGVydCBhbGVydC1kYW5nZXJcIiByb2xlPVwiYWxlcnRcIj48L2Rpdj4nKTtcblxuICAgICAgICAvLyBBZGQgc3VtbWFyeSBtZXNzYWdlIGlmIHByb3ZpZGVkXG4gICAgICAgIGlmIChzdW1tYXJ5X21zZykge1xuICAgICAgICAgICAgJCgnPHAgY2xhc3M9XCJtYi0yXCI+PC9wPicpLnRleHQoc3VtbWFyeV9tc2cpLmFwcGVuZFRvKCRhbGVydCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBZGQgdW5tYXRjaGVkIGVycm9ycyBhcyBidWxsZXRlZCBsaXN0XG4gICAgICAgIGlmIChPYmplY3Qua2V5cyh1bm1hdGNoZWRfZXJyb3JzKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCAkbGlzdCA9ICQoJzx1bCBjbGFzcz1cIm1iLTBcIj48L3VsPicpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBmaWVsZF9uYW1lIGluIHVubWF0Y2hlZF9lcnJvcnMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlcnJvcl9tc2cgPSB1bm1hdGNoZWRfZXJyb3JzW2ZpZWxkX25hbWVdO1xuICAgICAgICAgICAgICAgICQoJzxsaT48L2xpPicpLmh0bWwoZXJyb3JfbXNnKS5hcHBlbmRUbygkbGlzdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkbGlzdC5hcHBlbmRUbygkYWxlcnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCRlcnJvcl9jb250YWluZXIubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgYW5pbWF0aW9ucy5wdXNoKCRhbGVydC5oaWRlKCkuYXBwZW5kVG8oJHRhcmdldCkuZmFkZUluKDMwMCkucHJvbWlzZSgpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGFuaW1hdGlvbnMucHVzaCgkYWxlcnQuaGlkZSgpLnByZXBlbmRUbygkdGFyZ2V0KS5mYWRlSW4oMzAwKS5wcm9taXNlKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFuaW1hdGlvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQXBwbGllcyBnZW5lcmFsIGVycm9yIG1lc3NhZ2VzIGFzIGFsZXJ0IGJveFxuICAgICAqIEBwYXJhbSB7alF1ZXJ5fSAkcGFyZW50IC0gUGFyZW50IGVsZW1lbnQgdG8gcHJlcGVuZCBhbGVydCB0b1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfEFycmF5fSBtZXNzYWdlcyAtIEVycm9yIG1lc3NhZ2UocykgdG8gZGlzcGxheVxuICAgICAqIEByZXR1cm5zIHtBcnJheX0gQXJyYXkgb2YgYW5pbWF0aW9uIHByb21pc2VzXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX2FwcGx5X2dlbmVyYWxfZXJyb3JzKCRwYXJlbnQsIG1lc3NhZ2VzKSB7XG4gICAgICAgIGNvbnN0IGFuaW1hdGlvbnMgPSBbXTtcblxuICAgICAgICAvLyBMb29rIGZvciBhIHNwZWNpZmljIGVycm9yIGNvbnRhaW5lciBkaXYgKGUuZy4sIGluIFJzeF9Gb3JtIGNvbXBvbmVudClcbiAgICAgICAgY29uc3QgJGVycm9yX2NvbnRhaW5lciA9ICRwYXJlbnQuZmluZCgnW2RhdGEtaWQ9XCJlcnJvcl9jb250YWluZXJcIl0nKS5maXJzdCgpO1xuICAgICAgICBjb25zdCAkdGFyZ2V0ID0gJGVycm9yX2NvbnRhaW5lci5sZW5ndGggPiAwID8gJGVycm9yX2NvbnRhaW5lciA6ICRwYXJlbnQ7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBtZXNzYWdlcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIC8vIFNpbmdsZSBlcnJvciAtIHNpbXBsZSBhbGVydCB3aXRob3V0IGxpc3RcbiAgICAgICAgICAgIGNvbnN0ICRhbGVydCA9ICQoJzxkaXYgY2xhc3M9XCJhbGVydCBhbGVydC1kYW5nZXJcIiByb2xlPVwiYWxlcnRcIj48L2Rpdj4nKS50ZXh0KG1lc3NhZ2VzKTtcbiAgICAgICAgICAgIGlmICgkZXJyb3JfY29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25zLnB1c2goJGFsZXJ0LmhpZGUoKS5hcHBlbmRUbygkdGFyZ2V0KS5mYWRlSW4oMzAwKS5wcm9taXNlKCkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25zLnB1c2goJGFsZXJ0LmhpZGUoKS5wcmVwZW5kVG8oJHRhcmdldCkuZmFkZUluKDMwMCkucHJvbWlzZSgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KG1lc3NhZ2VzKSAmJiBtZXNzYWdlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAvLyBNdWx0aXBsZSBlcnJvcnMgLSBidWxsZXRlZCBsaXN0XG4gICAgICAgICAgICBjb25zdCAkYWxlcnQgPSAkKCc8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtZGFuZ2VyXCIgcm9sZT1cImFsZXJ0XCI+PHVsIGNsYXNzPVwibWItMFwiPjwvdWw+PC9kaXY+Jyk7XG4gICAgICAgICAgICBjb25zdCAkbGlzdCA9ICRhbGVydC5maW5kKCd1bCcpO1xuXG4gICAgICAgICAgICBtZXNzYWdlcy5mb3JFYWNoKChtc2cpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCB0ZXh0ID0gKG1zZyArICcnKS50cmltKCkgfHwgJ0FuIGVycm9yIGhhcyBvY2N1cnJlZCc7XG4gICAgICAgICAgICAgICAgJCgnPGxpPjwvbGk+JykuaHRtbCh0ZXh0KS5hcHBlbmRUbygkbGlzdCk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKCRlcnJvcl9jb250YWluZXIubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvbnMucHVzaCgkYWxlcnQuaGlkZSgpLmFwcGVuZFRvKCR0YXJnZXQpLmZhZGVJbigzMDApLnByb21pc2UoKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGFuaW1hdGlvbnMucHVzaCgkYWxlcnQuaGlkZSgpLnByZXBlbmRUbygkdGFyZ2V0KS5mYWRlSW4oMzAwKS5wcm9taXNlKCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiBtZXNzYWdlcyA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkobWVzc2FnZXMpKSB7XG4gICAgICAgICAgICAvLyBPYmplY3Qgb2YgdW5tYXRjaGVkIGZpZWxkIGVycm9ycyAtIGNvbnZlcnQgdG8gYXJyYXlcbiAgICAgICAgICAgIGNvbnN0IGVycm9yX2xpc3QgPSBPYmplY3QudmFsdWVzKG1lc3NhZ2VzKVxuICAgICAgICAgICAgICAgIC5tYXAoKHYpID0+IFN0cmluZyh2KS50cmltKCkpXG4gICAgICAgICAgICAgICAgLmZpbHRlcigodikgPT4gdik7XG4gICAgICAgICAgICBpZiAoZXJyb3JfbGlzdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIEZvcm1fVXRpbHMuX2FwcGx5X2dlbmVyYWxfZXJyb3JzKCRwYXJlbnQsIGVycm9yX2xpc3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFuaW1hdGlvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2FsY3VsYXRlcyB0aGUgdG90YWwgaGVpZ2h0IG9mIGZpeGVkL3N0aWNreSBoZWFkZXJzIGF0IHRoZSB0b3Agb2YgdGhlIHBhZ2VcbiAgICAgKiBAcmV0dXJucyB7bnVtYmVyfSBUb3RhbCBoZWlnaHQgaW4gcGl4ZWxzIG9mIGZpeGVkIHRvcCBlbGVtZW50c1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9nZXRfZml4ZWRfaGVhZGVyX2hlaWdodCgpIHtcbiAgICAgICAgbGV0IHRvdGFsX2hlaWdodCA9IDA7XG5cbiAgICAgICAgLy8gRmluZCBhbGwgZml4ZWQgb3Igc3RpY2t5IHBvc2l0aW9uZWQgZWxlbWVudHNcbiAgICAgICAgJCgnKicpLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBjb25zdCAkZWwgPSAkKHRoaXMpO1xuICAgICAgICAgICAgY29uc3QgcG9zaXRpb24gPSAkZWwuY3NzKCdwb3NpdGlvbicpO1xuXG4gICAgICAgICAgICAvLyBPbmx5IGNoZWNrIGZpeGVkIG9yIHN0aWNreSBlbGVtZW50c1xuICAgICAgICAgICAgaWYgKHBvc2l0aW9uICE9PSAnZml4ZWQnICYmIHBvc2l0aW9uICE9PSAnc3RpY2t5Jykge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgZWxlbWVudCBpcyBwb3NpdGlvbmVkIGF0IG9yIG5lYXIgdGhlIHRvcFxuICAgICAgICAgICAgY29uc3QgdG9wID0gcGFyc2VJbnQoJGVsLmNzcygndG9wJykpIHx8IDA7XG4gICAgICAgICAgICBpZiAodG9wID4gNTApIHtcbiAgICAgICAgICAgICAgICByZXR1cm47IC8vIE5vdCBhIHRvcCBoZWFkZXJcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgZWxlbWVudCBpcyB2aXNpYmxlXG4gICAgICAgICAgICBpZiAoISRlbC5pcygnOnZpc2libGUnKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgZWxlbWVudCBzcGFucyBzaWduaWZpY2FudCB3aWR0aCAobGlrZWx5IGEgaGVhZGVyL25hdmJhcilcbiAgICAgICAgICAgIGNvbnN0IHdpZHRoID0gJGVsLm91dGVyV2lkdGgoKTtcbiAgICAgICAgICAgIGNvbnN0IHZpZXdwb3J0X3dpZHRoID0gJCh3aW5kb3cpLndpZHRoKCk7XG4gICAgICAgICAgICBpZiAod2lkdGggPCB2aWV3cG9ydF93aWR0aCAqIDAuNSkge1xuICAgICAgICAgICAgICAgIHJldHVybjsgLy8gVG9vIG5hcnJvdyB0byBiZSBhIGhlYWRlclxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBBZGQgdGhpcyBlbGVtZW50J3MgaGVpZ2h0XG4gICAgICAgICAgICB0b3RhbF9oZWlnaHQgKz0gJGVsLm91dGVySGVpZ2h0KCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0b3RhbF9oZWlnaHQ7XG4gICAgfVxufVxuIiwiLyoqXG4gKiBEZWJ1Z2dlciBjbGFzcyBmb3IgY29uc29sZV9kZWJ1ZyBhbmQgYnJvd3NlciBlcnJvciBsb2dnaW5nXG4gKiBIYW5kbGVzIGJhdGNoZWQgc3VibWlzc2lvbiB0byBzZXJ2ZXIgd2hlbiBjb25maWd1cmVkXG4gKi9cbmNsYXNzIERlYnVnZ2VyIHtcbiAgICAvLyBCYXRjaGluZyBzdGF0ZSBmb3IgY29uc29sZV9kZWJ1ZyBtZXNzYWdlc1xuICAgIHN0YXRpYyBfY29uc29sZV9iYXRjaCA9IFtdO1xuICAgIHN0YXRpYyBfY29uc29sZV90aW1lciA9IG51bGw7XG4gICAgc3RhdGljIF9jb25zb2xlX2JhdGNoX2NvdW50ID0gMDtcblxuICAgIC8vIEJhdGNoaW5nIHN0YXRlIGZvciBlcnJvciBtZXNzYWdlc1xuICAgIHN0YXRpYyBfZXJyb3JfYmF0Y2ggPSBbXTtcbiAgICBzdGF0aWMgX2Vycm9yX3RpbWVyID0gbnVsbDtcbiAgICBzdGF0aWMgX2Vycm9yX2NvdW50ID0gMDtcbiAgICBzdGF0aWMgX2Vycm9yX2JhdGNoX2NvdW50ID0gMDtcblxuICAgIC8vIENvbnN0YW50c1xuICAgIHN0YXRpYyBERUJPVU5DRV9NUyA9IDIwMDA7XG4gICAgc3RhdGljIE1BWF9FUlJPUlNfUEVSX1BBR0UgPSAyMDtcbiAgICBzdGF0aWMgTUFYX0VSUk9SX0JBVENIRVMgPSA1O1xuXG4gICAgLy8gU3RvcmUgc3RhcnQgdGltZSBmb3IgYmVuY2htYXJraW5nXG4gICAgc3RhdGljIF9zdGFydF90aW1lID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgZnJhbWV3b3JrIGVycm9yIGhhbmRsaW5nXG4gICAgICogQ2FsbGVkIGR1cmluZyBmcmFtZXdvcmsgaW5pdGlhbGl6YXRpb25cbiAgICAgKi9cbiAgICBzdGF0aWMgX29uX2ZyYW1ld29ya19jb3JlX2luaXQoKSB7XG4gICAgICAgIC8vIENoZWNrIGlmIGJyb3dzZXIgZXJyb3IgbG9nZ2luZyBpcyBlbmFibGVkXG4gICAgICAgIGlmICh3aW5kb3cucnN4YXBwICYmIHdpbmRvdy5yc3hhcHAubG9nX2Jyb3dzZXJfZXJyb3JzKSB7XG4gICAgICAgICAgICAvLyBSZWdpc3RlciBnbG9iYWwgZXJyb3IgaGFuZGxlclxuICAgICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ2Vycm9yJywgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgRGVidWdnZXIuX2hhbmRsZV9icm93c2VyX2Vycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTogZXZlbnQubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgZmlsZW5hbWU6IGV2ZW50LmZpbGVuYW1lLFxuICAgICAgICAgICAgICAgICAgICBsaW5lbm86IGV2ZW50LmxpbmVubyxcbiAgICAgICAgICAgICAgICAgICAgY29sbm86IGV2ZW50LmNvbG5vLFxuICAgICAgICAgICAgICAgICAgICBzdGFjazogZXZlbnQuZXJyb3IgPyBldmVudC5lcnJvci5zdGFjayA6IG51bGwsXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICdlcnJvcicsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gUmVnaXN0ZXIgdW5oYW5kbGVkIHByb21pc2UgcmVqZWN0aW9uIGhhbmRsZXJcbiAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCd1bmhhbmRsZWRyZWplY3Rpb24nLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgICAgICBEZWJ1Z2dlci5faGFuZGxlX2Jyb3dzZXJfZXJyb3Ioe1xuICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBldmVudC5yZWFzb24gPyBldmVudC5yZWFzb24ubWVzc2FnZSB8fCBTdHJpbmcoZXZlbnQucmVhc29uKSA6ICdVbmhhbmRsZWQgcHJvbWlzZSByZWplY3Rpb24nLFxuICAgICAgICAgICAgICAgICAgICBzdGFjazogZXZlbnQucmVhc29uICYmIGV2ZW50LnJlYXNvbi5zdGFjayA/IGV2ZW50LnJlYXNvbi5zdGFjayA6IG51bGwsXG4gICAgICAgICAgICAgICAgICAgIHR5cGU6ICd1bmhhbmRsZWRyZWplY3Rpb24nLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZWdpc3RlciB1aSByZWZyZXNoIGhhbmRsZXJcbiAgICAgICAgUnN4Lm9uKCdyZWZyZXNoJywgRGVidWdnZXIub25fcmVmcmVzaCk7XG4gICAgfVxuXG4gICAgLy8gSW4gZGV2IG1vZGUsIHNvbWUgdWkgZWxlbWVudHMgY2FuIGJlIGF1dG9tYXRpY2FsbHkgYXBwbGllZCB0byBhc3Npc3Qgd2l0aCBkZXZlbG9wbWVudFxuICAgIHN0YXRpYyBvbl9yZWZyZXNoKCkge1xuICAgICAgICBpZiAoIVJzeC5pc19wcm9kKCkpIHtcbiAgICAgICAgICAgIC8vIEFkZCBhbiB1bmRlcmxpbmUgMiBweCBibHVlIHRvIGFsbCBhIHRhZ3Mgd2l0aCBocmVmID09PSBcIiNcIiB1c2luZyBqcXVlcnlcbiAgICAgICAgICAgIC8vIFRvZG86IG1heWJlIHRoaXMgc2hvdWxkIGJlIGEgY29uZmlndXJhYmxlIGRlYnVnIG9wdGlvbj9cbiAgICAgICAgICAgIC8vICQoJ2FbaHJlZj1cIiNcIl0nKS5jc3Moe1xuICAgICAgICAgICAgLy8gICAgICdib3JkZXItYm90dG9tJzogJzJweCBzb2xpZCBibHVlJyxcbiAgICAgICAgICAgIC8vICAgICAndGV4dC1kZWNvcmF0aW9uJzogJ25vbmUnXG4gICAgICAgICAgICAvLyB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEphdmFTY3JpcHQgaW1wbGVtZW50YXRpb24gb2YgY29uc29sZV9kZWJ1Z1xuICAgICAqIE1pcnJvcnMgUEhQIGZ1bmN0aW9uYWxpdHkgd2l0aCBiYXRjaGluZyBmb3IgTGFyYXZlbCBsb2dcbiAgICAgKi9cbiAgICBzdGF0aWMgY29uc29sZV9kZWJ1ZyhjaGFubmVsLCAuLi52YWx1ZXMpIHtcbiAgICAgICAgLy8gQ2hlY2sgaWYgY29uc29sZV9kZWJ1ZyBpcyBlbmFibGVkXG4gICAgICAgIGlmICghd2luZG93LnJzeGFwcCB8fCAhd2luZG93LnJzeGFwcC5jb25zb2xlX2RlYnVnIHx8ICF3aW5kb3cucnN4YXBwLmNvbnNvbGVfZGVidWcuZW5hYmxlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY29uZmlnID0gd2luZG93LnJzeGFwcC5jb25zb2xlX2RlYnVnO1xuXG4gICAgICAgIC8vIE5vcm1hbGl6ZSBjaGFubmVsIG5hbWVcbiAgICAgICAgY2hhbm5lbCA9IFN0cmluZyhjaGFubmVsKVxuICAgICAgICAgICAgLnRvVXBwZXJDYXNlKClcbiAgICAgICAgICAgIC5yZXBsYWNlKC9bXFxbXFxdXS9nLCAnJyk7XG5cbiAgICAgICAgLy8gQXBwbHkgZmlsdGVyaW5nXG4gICAgICAgIGlmIChjb25maWcuZmlsdGVyX21vZGUgPT09ICdzcGVjaWZpYycpIHtcbiAgICAgICAgICAgIGNvbnN0IHNwZWNpZmljID0gY29uZmlnLnNwZWNpZmljX2NoYW5uZWw7XG4gICAgICAgICAgICBpZiAoc3BlY2lmaWMpIHtcbiAgICAgICAgICAgICAgICAvLyBTcGxpdCBjb21tYS1zZXBhcmF0ZWQgdmFsdWVzIGFuZCBub3JtYWxpemVcbiAgICAgICAgICAgICAgICBjb25zdCBjaGFubmVscyA9IHNwZWNpZmljLnNwbGl0KCcsJykubWFwKChjKSA9PiBjLnRyaW0oKS50b1VwcGVyQ2FzZSgpKTtcbiAgICAgICAgICAgICAgICBpZiAoIWNoYW5uZWxzLmluY2x1ZGVzKGNoYW5uZWwpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoY29uZmlnLmZpbHRlcl9tb2RlID09PSAnd2hpdGVsaXN0Jykge1xuICAgICAgICAgICAgY29uc3Qgd2hpdGVsaXN0ID0gKGNvbmZpZy5maWx0ZXJfY2hhbm5lbHMgfHwgW10pLm1hcCgoYykgPT4gYy50b1VwcGVyQ2FzZSgpKTtcbiAgICAgICAgICAgIGlmICghd2hpdGVsaXN0LmluY2x1ZGVzKGNoYW5uZWwpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGNvbmZpZy5maWx0ZXJfbW9kZSA9PT0gJ2JsYWNrbGlzdCcpIHtcbiAgICAgICAgICAgIGNvbnN0IGJsYWNrbGlzdCA9IChjb25maWcuZmlsdGVyX2NoYW5uZWxzIHx8IFtdKS5tYXAoKGMpID0+IGMudG9VcHBlckNhc2UoKSk7XG4gICAgICAgICAgICBpZiAoYmxhY2tsaXN0LmluY2x1ZGVzKGNoYW5uZWwpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUHJlcGFyZSB0aGUgbWVzc2FnZVxuICAgICAgICBsZXQgbWVzc2FnZSA9IHtcbiAgICAgICAgICAgIGNoYW5uZWw6IGNoYW5uZWwsXG4gICAgICAgICAgICB2YWx1ZXM6IHZhbHVlcyxcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEFkZCBsb2NhdGlvbiBpZiBjb25maWd1cmVkXG4gICAgICAgIGlmIChjb25maWcuaW5jbHVkZV9sb2NhdGlvbiB8fCBjb25maWcuaW5jbHVkZV9iYWNrdHJhY2UpIHtcbiAgICAgICAgICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKCk7XG4gICAgICAgICAgICBjb25zdCBzdGFjayA9IGVycm9yLnN0YWNrIHx8ICcnO1xuICAgICAgICAgICAgY29uc3Qgc3RhY2tMaW5lcyA9IHN0YWNrLnNwbGl0KCdcXG4nKTtcblxuICAgICAgICAgICAgaWYgKGNvbmZpZy5pbmNsdWRlX2xvY2F0aW9uICYmIHN0YWNrTGluZXMubGVuZ3RoID4gMikge1xuICAgICAgICAgICAgICAgIC8vIFNraXAgRXJyb3IgbGluZSBhbmQgdGhpcyBmdW5jdGlvblxuICAgICAgICAgICAgICAgIGNvbnN0IGNhbGxlckxpbmUgPSBzdGFja0xpbmVzWzJdIHx8ICcnO1xuICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoID0gY2FsbGVyTGluZS5tYXRjaCgvYXRcXHMrLio/XFxzK1xcKCguKj8pOihcXGQrKTooXFxkKylcXCkvKSB8fCBjYWxsZXJMaW5lLm1hdGNoKC9hdFxccysoLio/KTooXFxkKyk6KFxcZCspLyk7XG4gICAgICAgICAgICAgICAgaWYgKG1hdGNoKSB7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UubG9jYXRpb24gPSBgJHttYXRjaFsxXX06JHttYXRjaFsyXX1gO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGNvbmZpZy5pbmNsdWRlX2JhY2t0cmFjZSkge1xuICAgICAgICAgICAgICAgIC8vIEluY2x1ZGUgZmlyc3QgNSBzdGFjayBmcmFtZXMsIHNraXBwaW5nIHRoaXMgZnVuY3Rpb25cbiAgICAgICAgICAgICAgICBtZXNzYWdlLmJhY2t0cmFjZSA9IHN0YWNrTGluZXNcbiAgICAgICAgICAgICAgICAgICAgLnNsaWNlKDIsIDcpXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoKGxpbmUpID0+IGxpbmUudHJpbSgpKVxuICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChsaW5lKSA9PiBsaW5lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE91dHB1dCB0byBicm93c2VyIGNvbnNvbGUgaWYgZW5hYmxlZFxuICAgICAgICBpZiAoY29uZmlnLm91dHB1dHMgJiYgY29uZmlnLm91dHB1dHMuYnJvd3Nlcikge1xuICAgICAgICAgICAgY29uc3QgcHJlZml4ID0gY29uZmlnLmluY2x1ZGVfYmVuY2htYXJrID8gYFske0RlYnVnZ2VyLl9nZXRfdGltZV9wcmVmaXgoKX1dIGAgOiAnJztcbiAgICAgICAgICAgIGNvbnN0IGNoYW5uZWxQcmVmaXggPSBgWyR7Y2hhbm5lbH1dYDtcblxuICAgICAgICAgICAgLy8gVXNlIGFwcHJvcHJpYXRlIGNvbnNvbGUgbWV0aG9kIGJhc2VkIG9uIGNoYW5uZWxcbiAgICAgICAgICAgIGxldCBjb25zb2xlTWV0aG9kID0gJ2xvZyc7XG4gICAgICAgICAgICBpZiAoY2hhbm5lbC5pbmNsdWRlcygnRVJST1InKSkgY29uc29sZU1ldGhvZCA9ICdlcnJvcic7XG4gICAgICAgICAgICBlbHNlIGlmIChjaGFubmVsLmluY2x1ZGVzKCdXQVJOJykpIGNvbnNvbGVNZXRob2QgPSAnd2Fybic7XG4gICAgICAgICAgICBlbHNlIGlmIChjaGFubmVsLmluY2x1ZGVzKCdJTkZPJykpIGNvbnNvbGVNZXRob2QgPSAnaW5mbyc7XG5cbiAgICAgICAgICAgIGNvbnNvbGVbY29uc29sZU1ldGhvZF0ocHJlZml4ICsgY2hhbm5lbFByZWZpeCwgLi4udmFsdWVzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEJhdGNoIGZvciBMYXJhdmVsIGxvZyBpZiBlbmFibGVkXG4gICAgICAgIGlmIChjb25maWcub3V0cHV0cyAmJiBjb25maWcub3V0cHV0cy5sYXJhdmVsX2xvZykge1xuICAgICAgICAgICAgRGVidWdnZXIuX2JhdGNoX2NvbnNvbGVfbWVzc2FnZShtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExvZyBhbiBlcnJvciB0byB0aGUgc2VydmVyXG4gICAgICogVXNlZCBtYW51YWxseSBvciBieSBBamF4IGVycm9yIGhhbmRsaW5nXG4gICAgICovXG4gICAgc3RhdGljIGxvZ19lcnJvcihlcnJvcikge1xuICAgICAgICAvLyBDaGVjayBpZiBicm93c2VyIGVycm9yIGxvZ2dpbmcgaXMgZW5hYmxlZFxuICAgICAgICBpZiAoIXdpbmRvdy5yc3hhcHAgfHwgIXdpbmRvdy5yc3hhcHAubG9nX2Jyb3dzZXJfZXJyb3JzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBOb3JtYWxpemUgZXJyb3IgZm9ybWF0XG4gICAgICAgIGxldCBlcnJvckRhdGEgPSB7fTtcbiAgICAgICAgaWYgKHR5cGVvZiBlcnJvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGVycm9yRGF0YS5tZXNzYWdlID0gZXJyb3I7XG4gICAgICAgICAgICBlcnJvckRhdGEudHlwZSA9ICdtYW51YWwnO1xuICAgICAgICB9IGVsc2UgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICAgIGVycm9yRGF0YS5tZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcbiAgICAgICAgICAgIGVycm9yRGF0YS5zdGFjayA9IGVycm9yLnN0YWNrO1xuICAgICAgICAgICAgZXJyb3JEYXRhLnR5cGUgPSAnZXhjZXB0aW9uJztcbiAgICAgICAgfSBlbHNlIGlmIChlcnJvciAmJiB0eXBlb2YgZXJyb3IgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICBlcnJvckRhdGEgPSBlcnJvcjtcbiAgICAgICAgICAgIGlmICghZXJyb3JEYXRhLnR5cGUpIHtcbiAgICAgICAgICAgICAgICBlcnJvckRhdGEudHlwZSA9ICdtYW51YWwnO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgRGVidWdnZXIuX2hhbmRsZV9icm93c2VyX2Vycm9yKGVycm9yRGF0YSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWw6IEhhbmRsZSBicm93c2VyIGVycm9ycyB3aXRoIGJhdGNoaW5nXG4gICAgICovXG4gICAgc3RhdGljIF9oYW5kbGVfYnJvd3Nlcl9lcnJvcihlcnJvckRhdGEpIHtcbiAgICAgICAgLy8gQ2hlY2sgbGltaXRzXG4gICAgICAgIGlmIChEZWJ1Z2dlci5fZXJyb3JfY291bnQgPj0gRGVidWdnZXIuTUFYX0VSUk9SU19QRVJfUEFHRSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChEZWJ1Z2dlci5fZXJyb3JfYmF0Y2hfY291bnQgPj0gRGVidWdnZXIuTUFYX0VSUk9SX0JBVENIRVMpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIERlYnVnZ2VyLl9lcnJvcl9jb3VudCsrO1xuXG4gICAgICAgIC8vIEFkZCBtZXRhZGF0YVxuICAgICAgICBlcnJvckRhdGEudXJsID0gd2luZG93LmxvY2F0aW9uLmhyZWY7XG4gICAgICAgIGVycm9yRGF0YS51c2VyQWdlbnQgPSBuYXZpZ2F0b3IudXNlckFnZW50O1xuICAgICAgICBlcnJvckRhdGEudGltZXN0YW1wID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpO1xuXG4gICAgICAgIC8vIEFkZCB0byBiYXRjaFxuICAgICAgICBEZWJ1Z2dlci5fZXJyb3JfYmF0Y2gucHVzaChlcnJvckRhdGEpO1xuXG4gICAgICAgIC8vIENsZWFyIGV4aXN0aW5nIHRpbWVyXG4gICAgICAgIGlmIChEZWJ1Z2dlci5fZXJyb3JfdGltZXIpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChEZWJ1Z2dlci5fZXJyb3JfdGltZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU2V0IGRlYm91bmNlIHRpbWVyXG4gICAgICAgIERlYnVnZ2VyLl9lcnJvcl90aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgRGVidWdnZXIuX2ZsdXNoX2Vycm9yX2JhdGNoKCk7XG4gICAgICAgIH0sIERlYnVnZ2VyLkRFQk9VTkNFX01TKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnRlcm5hbDogQmF0Y2ggY29uc29sZV9kZWJ1ZyBtZXNzYWdlcyBmb3IgTGFyYXZlbCBsb2dcbiAgICAgKi9cbiAgICBzdGF0aWMgX2JhdGNoX2NvbnNvbGVfbWVzc2FnZShtZXNzYWdlKSB7XG4gICAgICAgIERlYnVnZ2VyLl9jb25zb2xlX2JhdGNoLnB1c2gobWVzc2FnZSk7XG5cbiAgICAgICAgLy8gQ2xlYXIgZXhpc3RpbmcgdGltZXJcbiAgICAgICAgaWYgKERlYnVnZ2VyLl9jb25zb2xlX3RpbWVyKSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQoRGVidWdnZXIuX2NvbnNvbGVfdGltZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU2V0IGRlYm91bmNlIHRpbWVyXG4gICAgICAgIERlYnVnZ2VyLl9jb25zb2xlX3RpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICBEZWJ1Z2dlci5fZmx1c2hfY29uc29sZV9iYXRjaCgpO1xuICAgICAgICB9LCBEZWJ1Z2dlci5ERUJPVU5DRV9NUyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWw6IEZsdXNoIGNvbnNvbGVfZGVidWcgYmF0Y2ggdG8gc2VydmVyXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIF9mbHVzaF9jb25zb2xlX2JhdGNoKCkge1xuICAgICAgICBpZiAoRGVidWdnZXIuX2NvbnNvbGVfYmF0Y2gubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBtZXNzYWdlcyA9IERlYnVnZ2VyLl9jb25zb2xlX2JhdGNoO1xuICAgICAgICBEZWJ1Z2dlci5fY29uc29sZV9iYXRjaCA9IFtdO1xuICAgICAgICBEZWJ1Z2dlci5fY29uc29sZV90aW1lciA9IG51bGw7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiBBamF4LmNhbGwoUnN4LlJvdXRlKCdEZWJ1Z2dlcl9Db250cm9sbGVyJywgJ2xvZ19jb25zb2xlX21lc3NhZ2VzJyksIHsgbWVzc2FnZXM6IG1lc3NhZ2VzIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgLy8gU2lsZW50bHkgZmFpbCAtIGRvbid0IGNyZWF0ZSBlcnJvciBsb29wXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdGYWlsZWQgdG8gc2VuZCBjb25zb2xlX2RlYnVnIG1lc3NhZ2VzIHRvIHNlcnZlcjonLCBlcnJvcik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnRlcm5hbDogRmx1c2ggZXJyb3IgYmF0Y2ggdG8gc2VydmVyXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIF9mbHVzaF9lcnJvcl9iYXRjaCgpIHtcbiAgICAgICAgaWYgKERlYnVnZ2VyLl9lcnJvcl9iYXRjaC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGVycm9ycyA9IERlYnVnZ2VyLl9lcnJvcl9iYXRjaDtcbiAgICAgICAgRGVidWdnZXIuX2Vycm9yX2JhdGNoID0gW107XG4gICAgICAgIERlYnVnZ2VyLl9lcnJvcl90aW1lciA9IG51bGw7XG4gICAgICAgIERlYnVnZ2VyLl9lcnJvcl9iYXRjaF9jb3VudCsrO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gQWpheC5jYWxsKFJzeC5Sb3V0ZSgnRGVidWdnZXJfQ29udHJvbGxlcicsICdsb2dfYnJvd3Nlcl9lcnJvcnMnKSwgeyBlcnJvcnM6IGVycm9ycyB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIC8vIFNpbGVudGx5IGZhaWwgLSBkb24ndCBjcmVhdGUgZXJyb3IgbG9vcFxuICAgICAgICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHNlbmQgYnJvd3NlciBlcnJvcnMgdG8gc2VydmVyOicsIGVycm9yKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEludGVybmFsOiBHZXQgdGltZSBwcmVmaXggZm9yIGJlbmNobWFya2luZ1xuICAgICAqL1xuICAgIHN0YXRpYyBfZ2V0X3RpbWVfcHJlZml4KCkge1xuICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgICAgICBpZiAoIURlYnVnZ2VyLl9zdGFydF90aW1lKSB7XG4gICAgICAgICAgICBEZWJ1Z2dlci5fc3RhcnRfdGltZSA9IG5vdztcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlbGFwc2VkID0gbm93IC0gRGVidWdnZXIuX3N0YXJ0X3RpbWU7XG4gICAgICAgIHJldHVybiAoZWxhcHNlZCAvIDEwMDApLnRvRml4ZWQoMykgKyAncyc7XG4gICAgfVxufVxuIiwiLy8gQEpTLVRISVMtMDEtRVhDRVBUSU9OXG4vKipcbiAqIGpRdWVyeSBoZWxwZXIgZXh0ZW5zaW9ucyBmb3IgdGhlIFJTWCBmcmFtZXdvcmtcbiAqIFRoZXNlIGV4dGVuc2lvbnMgYWRkIHV0aWxpdHkgbWV0aG9kcyB0byBqUXVlcnkncyBwcm90b3R5cGVcbiAqIE5vdGU6ICd0aGlzJyByZWZlcmVuY2VzIGluIGpRdWVyeSBleHRlbnNpb25zIHJlZmVyIHRvIGpRdWVyeSBvYmplY3RzIGJ5IGRlc2lnblxuICovXG5jbGFzcyBSc3hfSnFfSGVscGVycyB7XG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZSBqUXVlcnkgZXh0ZW5zaW9ucyB3aGVuIHRoZSBmcmFtZXdvcmsgY29yZSBpcyBkZWZpbmVkXG4gICAgICogVGhpcyBtZXRob2QgaXMgY2FsbGVkIGR1cmluZyBmcmFtZXdvcmsgaW5pdGlhbGl6YXRpb25cbiAgICAgKi9cbiAgICBzdGF0aWMgX29uX2ZyYW1ld29ya19jb3JlX2RlZmluZSgpIHtcbiAgICAgICAgLy8gUmV0dXJucyB0cnVlIGlmIGpxdWVyeSBzZWxlY3RvciBtYXRjaGVkIGFuIGVsZW1lbnRcbiAgICAgICAgJC5mbi5leGlzdHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sZW5ndGggPiAwO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFJldHVybnMgdHJ1ZSBpZiBqcXVlcnkgZWxlbWVudCBpcyB2aXNpYmxlXG4gICAgICAgICQuZm4uaXNfdmlzaWJsZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmlzKCc6dmlzaWJsZScpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFNjcm9sbHMgdG8gdGhlIHRhcmdldCBlbGVtZW50LCBvbmx5IHNjcm9sbHMgdXAuICBUb2RvOiBDcmVhdGUgYSB2ZXJzaW9uXG4gICAgICAgIC8vIG9mIHRoaXMgdGhhdCBhbHNvIHNjcm9sbHMgb25seSBkb3duLCBvciBib3RoXG4gICAgICAgICQuZm4uc2Nyb2xsX3VwX3RvID0gZnVuY3Rpb24gKHNwZWVkID0gMCkge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmV4aXN0cygpKSB7XG4gICAgICAgICAgICAgICAgLy8gY29uc29sZS53YXJuKFwiQ291bGQgbm90IGZpbmQgdGFyZ2V0IGVsZW1lbnQgdG8gc2Nyb2xsIHRvXCIpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCF0aGlzLmlzX2luX2RvbSgpKSB7XG4gICAgICAgICAgICAgICAgLy8gY29uc29sZS53YXJuKFwiVGFyZ2V0IGVsZW1lbnQgZm9yIHNjcm9sbCBpcyBub3Qgb24gZG9tXCIpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGV0IGVfdG9wID0gTWF0aC5yb3VuZCh0aGlzLm9mZnNldCgpLnRvcCk7XG4gICAgICAgICAgICBsZXQgc190b3AgPSAkKCdib2R5Jykuc2Nyb2xsVG9wKCk7XG4gICAgICAgICAgICBpZiAoZV90b3AgPCAwKSB7XG4gICAgICAgICAgICAgICAgbGV0IHRhcmdldCA9IHNfdG9wICsgZV90b3A7XG4gICAgICAgICAgICAgICAgJCgnaHRtbCwgYm9keScpLmFuaW1hdGUoXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFRvcDogdGFyZ2V0LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBzcGVlZFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gJCgpLmlzKFwiOmZvY3VzXCIpIC0gY2hlY2sgaWYgZWxlbWVudCBoYXMgZm9jdXNcbiAgICAgICAgJC5leHByWyc6J10uZm9jdXMgPSBmdW5jdGlvbiAoZWxlbSkge1xuICAgICAgICAgICAgcmV0dXJuIGVsZW0gPT09IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgJiYgKGVsZW0udHlwZSB8fCBlbGVtLmhyZWYpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFNhdmUgbmF0aXZlIGNsaWNrIGJlaGF2aW9yIGJlZm9yZSBvdmVycmlkZVxuICAgICAgICAkLmZuLl9jbGlja19uYXRpdmUgPSAkLmZuLmNsaWNrO1xuXG4gICAgICAgIC8vIE92ZXJyaWRlIC5jbGljaygpIHRvIGNhbGwgcHJldmVudERlZmF1bHQgYnkgZGVmYXVsdFxuICAgICAgICAvLyBUaGlzIHByZXZlbnRzIGFjY2lkZW50YWwgcGFnZSBuYXZpZ2F0aW9uL2Zvcm0gc3VibWlzc2lvbiAtIHRoZSBjb3JyZWN0IGJlaGF2aW9yIDk1JSBvZiB0aGUgdGltZVxuICAgICAgICAkLmZuLmNsaWNrID0gZnVuY3Rpb24gKGhhbmRsZXIpIHtcbiAgICAgICAgICAgIC8vIElmIG5vIGhhbmRsZXIgcHJvdmlkZWQsIHRyaWdnZXIgY2xpY2sgZXZlbnQgKGpRdWVyeSAuY2xpY2soKSB3aXRoIG5vIGFyZ3MpXG4gICAgICAgICAgICBpZiAodHlwZW9mIGhhbmRsZXIgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NsaWNrX25hdGl2ZSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBBdHRhY2ggY2xpY2sgaGFuZGxlciB3aXRoIGF1dG9tYXRpYyBwcmV2ZW50RGVmYXVsdFxuICAgICAgICAgICAgcmV0dXJuIHRoaXMub24oJ2NsaWNrJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICAvLyBTYXZlIG9yaWdpbmFsIHByZXZlbnREZWZhdWx0XG4gICAgICAgICAgICAgICAgY29uc3Qgb3JpZ2luYWxfcHJldmVudERlZmF1bHQgPSBlLnByZXZlbnREZWZhdWx0LmJpbmQoZSk7XG5cbiAgICAgICAgICAgICAgICAvLyBPdmVycmlkZSBwcmV2ZW50RGVmYXVsdCB0byBzaG93IHdhcm5pbmcgd2hlbiBjYWxsZWQgZXhwbGljaXRseVxuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdldmVudC5wcmV2ZW50RGVmYXVsdCgpIGlzIGNhbGxlZCBhdXRvbWF0aWNhbGx5IGJ5IFJTcGFkZSAuY2xpY2soKSBoYW5kbGVycyBhbmQgY2FuIGJlIHJlbW92ZWQuJyk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBvcmlnaW5hbF9wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAvLyBDYWxsIHByZXZlbnREZWZhdWx0IGJlZm9yZSBoYW5kbGVyXG4gICAgICAgICAgICAgICAgb3JpZ2luYWxfcHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBoYW5kbGVyLmNhbGwodGhpcywgZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBFc2NhcGUgaGF0Y2g6IGNsaWNrIGhhbmRsZXIgd2l0aG91dCBwcmV2ZW50RGVmYXVsdCBmb3IgdGhlIDUlIGNhc2VcbiAgICAgICAgJC5mbi5jbGlja19hbGxvd19kZWZhdWx0ID0gZnVuY3Rpb24gKGhhbmRsZXIpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgaGFuZGxlciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fY2xpY2tfbmF0aXZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fY2xpY2tfbmF0aXZlKGhhbmRsZXIpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFJldHVybnMgdHJ1ZSBpZiB0aGUganF1ZXJ5IGVsZW1lbnQgZXhpc3RzIGluIGFuZCBpcyBhdHRhY2hlZCB0byB0aGUgRE9NXG4gICAgICAgICQuZm4uaXNfaW5fZG9tID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgbGV0ICRlbGVtZW50ID0gdGhpcztcbiAgICAgICAgICAgIGxldCBfYW5jZXN0b3IgPSBmdW5jdGlvbiAoSFRNTG9iaikge1xuICAgICAgICAgICAgICAgIHdoaWxlIChIVE1Mb2JqLnBhcmVudEVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgSFRNTG9iaiA9IEhUTUxvYmoucGFyZW50RWxlbWVudDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIEhUTUxvYmo7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgcmV0dXJuIF9hbmNlc3RvcigkZWxlbWVudFswXSkgPT09IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgdGhlIGVsZW1lbnQgaXMgdmlzaWJsZSBpbiB0aGUgdmlld3BvcnRcbiAgICAgICAgJC5mbi5pc19pbl92aWV3cG9ydCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGxldCBzY3JvbGx0b3AgPSAkKHdpbmRvdykuc2Nyb2xsVG9wKCkgPiAwID8gJCh3aW5kb3cpLnNjcm9sbFRvcCgpIDogJCgnYm9keScpLnNjcm9sbFRvcCgpO1xuXG4gICAgICAgICAgICBsZXQgJGVsZW1lbnQgPSB0aGlzO1xuXG4gICAgICAgICAgICBjb25zdCB0b3Bfb2ZfZWxlbWVudCA9ICRlbGVtZW50Lm9mZnNldCgpLnRvcDtcbiAgICAgICAgICAgIGNvbnN0IGJvdHRvbV9vZl9lbGVtZW50ID0gJGVsZW1lbnQub2Zmc2V0KCkudG9wICsgJGVsZW1lbnQub3V0ZXJIZWlnaHQoKTtcbiAgICAgICAgICAgIGNvbnN0IGJvdHRvbV9vZl9zY3JlZW4gPSBzY3JvbGx0b3AgKyAkKHdpbmRvdykuaW5uZXJIZWlnaHQoKTtcbiAgICAgICAgICAgIGNvbnN0IHRvcF9vZl9zY3JlZW4gPSBzY3JvbGx0b3A7XG5cbiAgICAgICAgICAgIGlmIChib3R0b21fb2Zfc2NyZWVuID4gdG9wX29mX2VsZW1lbnQgJiYgdG9wX29mX3NjcmVlbiA8IGJvdHRvbV9vZl9lbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICAvLyBHZXRzIHRoZSB0YWduYW1lIG9mIGEganF1ZXJ5IGVsZW1lbnRcbiAgICAgICAgJC5mbi50YWduYW1lID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucHJvcCgndGFnTmFtZScpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gUmV0dXJucyB0cnVlIGlmIGEgaHJlZiBpcyBub3Qgc2FtZSBkb21haW5cbiAgICAgICAgJC5mbi5pc19leHRlcm5hbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNvbnN0IGhvc3QgPSB3aW5kb3cubG9jYXRpb24uaG9zdDtcbiAgICAgICAgICAgIGNvbnN0IGxpbmsgPSAkKCc8YT4nLCB7XG4gICAgICAgICAgICAgICAgaHJlZjogdGhpcy5hdHRyKCdocmVmJyksXG4gICAgICAgICAgICB9KVswXS5ob3N0bmFtZTtcbiAgICAgICAgICAgIHJldHVybiBsaW5rICE9PSBob3N0O1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEhUTUw1IGZvcm0gdmFsaWRhdGlvbiB3cmFwcGVyc1xuICAgICAgICAkLmZuLmNoZWNrVmFsaWRpdHkgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5sZW5ndGggPT09IDApIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzWzBdLmNoZWNrVmFsaWRpdHkoKTtcbiAgICAgICAgfTtcblxuICAgICAgICAkLmZuLnJlcG9ydFZhbGlkaXR5ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKHRoaXMubGVuZ3RoID09PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICByZXR1cm4gdGhpc1swXS5yZXBvcnRWYWxpZGl0eSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgICQuZm4ucmVxdWVzdFN1Ym1pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB0aGlzWzBdLnJlcXVlc3RTdWJtaXQoKTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEZpbmQgcmVsYXRlZCBjb21wb25lbnRzIGJ5IHNlYXJjaGluZyB1cCB0aGUgYW5jZXN0b3IgdHJlZVxuICAgICAgICAvLyBMaWtlIC5jbG9zZXN0KCkgYnV0IHNlYXJjaGVzIHdpdGhpbiBhbmNlc3RvcnMgaW5zdGVhZCBvZiBtYXRjaGluZyB0aGVtXG4gICAgICAgICQuZm4uY2xvc2VzdF9zaWJsaW5nID0gZnVuY3Rpb24gKHNlbGVjdG9yKSB7XG4gICAgICAgICAgICBsZXQgJGN1cnJlbnQgPSB0aGlzO1xuICAgICAgICAgICAgbGV0ICRwYXJlbnQgPSAkY3VycmVudC5wYXJlbnQoKTtcblxuICAgICAgICAgICAgLy8gS2VlcCBnb2luZyB1cCB0aGUgdHJlZSB1bnRpbCB3ZSBoaXQgYm9keVxuICAgICAgICAgICAgd2hpbGUgKCRwYXJlbnQubGVuZ3RoID4gMCAmJiAhJHBhcmVudC5pcygnYm9keScpKSB7XG4gICAgICAgICAgICAgICAgLy8gU2VhcmNoIHdpdGhpbiB0aGlzIHBhcmVudCBmb3IgdGhlIHNlbGVjdG9yXG4gICAgICAgICAgICAgICAgbGV0ICRmb3VuZCA9ICRwYXJlbnQuZmluZChzZWxlY3Rvcik7XG4gICAgICAgICAgICAgICAgaWYgKCRmb3VuZC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAkZm91bmQ7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gTW92ZSB1cCBvbmUgbGV2ZWxcbiAgICAgICAgICAgICAgICAkcGFyZW50ID0gJHBhcmVudC5wYXJlbnQoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSWYgd2UgcmVhY2hlZCBib2R5LCBzZWFyY2ggd2l0aGluIGJvZHkgYXMgd2VsbFxuICAgICAgICAgICAgaWYgKCRwYXJlbnQuaXMoJ2JvZHknKSkge1xuICAgICAgICAgICAgICAgIGxldCAkZm91bmQgPSAkcGFyZW50LmZpbmQoc2VsZWN0b3IpO1xuICAgICAgICAgICAgICAgIGlmICgkZm91bmQubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gJGZvdW5kO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUmV0dXJuIGVtcHR5IGpRdWVyeSBvYmplY3QgaWYgbm90aGluZyBmb3VuZFxuICAgICAgICAgICAgcmV0dXJuICQoKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBPdmVycmlkZSAkLmFqYXggdG8gcHJldmVudCBkaXJlY3QgQUpBWCBjYWxscyB0byBsb2NhbCBzZXJ2ZXJcbiAgICAgICAgLy8gRGV2ZWxvcGVycyBtdXN0IHVzZSB0aGUgQWpheCBlbmRwb2ludCBwYXR0ZXJuOiBhd2FpdCBDb250cm9sbGVyLm1ldGhvZChwYXJhbXMpXG4gICAgICAgIGNvbnN0IG5hdGl2ZV9hamF4ID0gJC5hamF4O1xuICAgICAgICAkLmFqYXggPSBmdW5jdGlvbiAodXJsLCBvcHRpb25zKSB7XG4gICAgICAgICAgICAvLyBIYW5kbGUgYm90aCAkLmFqYXgodXJsLCBvcHRpb25zKSBhbmQgJC5hamF4KG9wdGlvbnMpIHNpZ25hdHVyZXNcbiAgICAgICAgICAgIGxldCBzZXR0aW5ncztcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdXJsID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIHNldHRpbmdzID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgICAgICBzZXR0aW5ncy51cmwgPSB1cmw7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNldHRpbmdzID0gdXJsIHx8IHt9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGlzIGlzIGEgbG9jYWwgcmVxdWVzdCAocmVsYXRpdmUgVVJMIG9yIHNhbWUgZG9tYWluKVxuICAgICAgICAgICAgY29uc3QgcmVxdWVzdF91cmwgPSBzZXR0aW5ncy51cmwgfHwgJyc7XG4gICAgICAgICAgICBjb25zdCBpc19yZWxhdGl2ZSA9ICFyZXF1ZXN0X3VybC5tYXRjaCgvXmh0dHBzPzpcXC9cXC8vKTtcbiAgICAgICAgICAgIGNvbnN0IGlzX3NhbWVfZG9tYWluID0gcmVxdWVzdF91cmwuc3RhcnRzV2l0aCh3aW5kb3cubG9jYXRpb24ub3JpZ2luKTtcbiAgICAgICAgICAgIGNvbnN0IGlzX2xvY2FsX3JlcXVlc3QgPSBpc19yZWxhdGl2ZSB8fCBpc19zYW1lX2RvbWFpbjtcblxuICAgICAgICAgICAgLy8gQWxsb3cgZnJhbWV3b3JrIEFqYXguY2FsbCgpIHRvIGZ1bmN0aW9uXG4gICAgICAgICAgICBpZiAoc2V0dGluZ3MuX19sb2NhbF9pbnRlZ3JhdGlvbiA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuYXRpdmVfYWpheC5jYWxsKHRoaXMsIHNldHRpbmdzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQWxsb3cgZmlsZSB1cGxvYWQgZW5kcG9pbnQgLSByZXF1aXJlcyBuYXRpdmUgJC5hamF4IGZvciBGb3JtRGF0YSBzdXBwb3J0XG4gICAgICAgICAgICBjb25zdCBpc19maWxlX3VwbG9hZCA9IHJlcXVlc3RfdXJsID09PSAnL191cGxvYWQnIHx8IHJlcXVlc3RfdXJsLmVuZHNXaXRoKCcvX3VwbG9hZCcpO1xuICAgICAgICAgICAgaWYgKGlzX2ZpbGVfdXBsb2FkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5hdGl2ZV9hamF4LmNhbGwodGhpcywgc2V0dGluZ3MpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBCbG9jayBsb2NhbCBBSkFYIHJlcXVlc3RzIHRoYXQgZG9uJ3QgdXNlIHRoZSBBamF4IGVuZHBvaW50IHBhdHRlcm5cbiAgICAgICAgICAgIGlmIChpc19sb2NhbF9yZXF1ZXN0KSB7XG4gICAgICAgICAgICAgICAgLy8gVHJ5IHRvIHBhcnNlIGNvbnRyb2xsZXIgYW5kIGFjdGlvbiBmcm9tIFVSTFxuICAgICAgICAgICAgICAgIGxldCBjb250cm9sbGVyX25hbWUgPSBudWxsO1xuICAgICAgICAgICAgICAgIGxldCBhY3Rpb25fbmFtZSA9IG51bGw7XG4gICAgICAgICAgICAgICAgY29uc3QgdXJsX21hdGNoID0gcmVxdWVzdF91cmwubWF0Y2goL1xcL19yc3hfYXBpXFwvKFteXFwvXSspXFwvKFteXFwvXFw/XSspLyk7XG4gICAgICAgICAgICAgICAgaWYgKHVybF9tYXRjaCkge1xuICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVyX25hbWUgPSB1cmxfbWF0Y2hbMV07XG4gICAgICAgICAgICAgICAgICAgIGFjdGlvbl9uYW1lID0gdXJsX21hdGNoWzJdO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGxldCBlcnJvcl9tZXNzYWdlID0gJ0FKQVggcmVxdWVzdHMgdG8gbG9jYWxob3N0IHZpYSAkLmFqYXgoKSBhcmUgcHJvaGliaXRlZC5cXG5cXG4nO1xuXG4gICAgICAgICAgICAgICAgaWYgKGNvbnRyb2xsZXJfbmFtZSAmJiBhY3Rpb25fbmFtZSkge1xuICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlICs9IGBJbnN0ZWFkIG9mOlxcbmA7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2UgKz0gYCAgJC5hamF4KHt1cmw6ICcke3JlcXVlc3RfdXJsfScsIC4uLn0pXFxuXFxuYDtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JfbWVzc2FnZSArPSBgVXNlOlxcbmA7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2UgKz0gYCAgYXdhaXQgJHtjb250cm9sbGVyX25hbWV9LiR7YWN0aW9uX25hbWV9KHBhcmFtZXRlcnMpXFxuXFxuYDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlICs9IGBVc2UgdGhlIEFqYXggZW5kcG9pbnQgcGF0dGVybjpcXG5gO1xuICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlICs9IGAgIGF3YWl0IENvbnRyb2xsZXJfTmFtZS5hY3Rpb25fbmFtZShwYXJhbWV0ZXJzKVxcblxcbmA7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZXJyb3JfbWVzc2FnZSArPSBgVGhlIGNvbnRyb2xsZXIgbWV0aG9kIG11c3QgaGF2ZSB0aGUgI1tBamF4X0VuZHBvaW50XSBhdHRyaWJ1dGUuYDtcblxuICAgICAgICAgICAgICAgIHNob3VsZG50X2hhcHBlbihlcnJvcl9tZXNzYWdlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQWxsb3cgZXh0ZXJuYWwgcmVxdWVzdHMgKGRpZmZlcmVudCBkb21haW4pXG4gICAgICAgICAgICByZXR1cm4gbmF0aXZlX2FqYXguY2FsbCh0aGlzLCBzZXR0aW5ncyk7XG4gICAgICAgIH07XG4gICAgfVxufSIsIi8vIEBST1VURS1FWElTVFMtMDEtRVhDRVBUSU9OIC0gVGhpcyBmaWxlIGNvbnRhaW5zIGRvY3VtZW50YXRpb24gZXhhbXBsZXMgd2l0aCBmaWN0aW9uYWwgcm91dGUgbmFtZXNcblxuLyoqXG4gKiBSc3ggLSBDb3JlIEphdmFTY3JpcHQgUnVudGltZSBTeXN0ZW1cbiAqXG4gKiBUaGUgUnN4IGNsYXNzIGlzIHRoZSBjZW50cmFsIGh1YiBmb3IgdGhlIFJTWCBKYXZhU2NyaXB0IHJ1bnRpbWUsIHByb3ZpZGluZyBlc3NlbnRpYWxcbiAqIHN5c3RlbS1sZXZlbCB1dGlsaXRpZXMgdGhhdCBhbGwgb3RoZXIgZnJhbWV3b3JrIGNvbXBvbmVudHMgZGVwZW5kIG9uLiBJdCBzZXJ2ZXMgYXMgdGhlXG4gKiBmb3VuZGF0aW9uIGZvciB0aGUgY2xpZW50LXNpZGUgZnJhbWV3b3JrLCBoYW5kbGluZyBjb3JlIG9wZXJhdGlvbnMgdGhhdCBtdXN0IGJlIGdsb2JhbGx5XG4gKiBhY2Nlc3NpYmxlIGFuZCBjb25zaXN0ZW50bHkgYXZhaWxhYmxlLlxuICpcbiAqIENvcmUgUmVzcG9uc2liaWxpdGllczpcbiAqIC0gRXZlbnQgU3lzdGVtOiBBcHBsaWNhdGlvbi13aWRlIGV2ZW50IGJ1cyBmb3IgZnJhbWV3b3JrIGxpZmVjeWNsZSBhbmQgY3VzdG9tIGV2ZW50c1xuICogLSBFbnZpcm9ubWVudCBEZXRlY3Rpb246IFJ1bnRpbWUgZW52aXJvbm1lbnQgaWRlbnRpZmljYXRpb24gKGRldi9wcm9kdWN0aW9uKVxuICogLSBSb3V0ZSBNYW5hZ2VtZW50OiBUeXBlLXNhZmUgcm91dGUgZ2VuZXJhdGlvbiBhbmQgVVJMIGJ1aWxkaW5nXG4gKiAtIFVuaXF1ZSBJRCBHZW5lcmF0aW9uOiBDbGllbnQtc2lkZSB1bmlxdWUgaWRlbnRpZmllciBnZW5lcmF0aW9uXG4gKiAtIEZyYW1ld29yayBCb290c3RyYXA6IE11bHRpLXBoYXNlIGluaXRpYWxpemF0aW9uIG9yY2hlc3RyYXRpb25cbiAqIC0gTG9nZ2luZzogQ2VudHJhbGl6ZWQgbG9nZ2luZyBpbnRlcmZhY2UgKGRlbGVnYXRlcyB0byBjb25zb2xlX2RlYnVnKVxuICpcbiAqIFRoZSBSc3ggY2xhc3MgZGVsaWJlcmF0ZWx5IGtlZXBzIGl0cyBzY29wZSBsaW1pdGVkIHRvIGNvcmUgdXRpbGl0aWVzLiBBZHZhbmNlZCBmZWF0dXJlc1xuICogYXJlIGRlbGVnYXRlZCB0byBzcGVjaWFsaXplZCBjbGFzc2VzOlxuICogLSBNYW5pZmVzdCBvcGVyYXRpb25zIOKGkiBNYW5pZmVzdCBjbGFzc1xuICogLSBDYWNoaW5nIOKGkiBSc3hfQ2FjaGUgY2xhc3NcbiAqIC0gQUpBWC9BUEkgY2FsbHMg4oaSIEFqYXhfKiBjbGFzc2VzXG4gKiAtIFJvdXRlIHByb3hpZXMg4oaSIFJzeF9Sb3V0ZV9Qcm94eSBjbGFzc1xuICogLSBCZWhhdmlvcnMg4oaSIFJzeF9CZWhhdmlvcnMgY2xhc3NcbiAqXG4gKiBBbGwgbWV0aG9kcyBhcmUgc3RhdGljIC0gUnN4IGlzIG5ldmVyIGluc3RhbnRpYXRlZC4gSXQncyBhdmFpbGFibGUgZ2xvYmFsbHkgZnJvbSB0aGVcbiAqIG1vbWVudCBidW5kbGVzIGxvYWQgYW5kIHJlbWFpbnMgY29uc3RhbnQgdGhyb3VnaG91dCB0aGUgYXBwbGljYXRpb24gbGlmZWN5Y2xlLlxuICpcbiAqIFVzYWdlIEV4YW1wbGVzOlxuICogYGBgamF2YXNjcmlwdFxuICogLy8gRXZlbnQgc3lzdGVtXG4gKiBSc3gub24oJ2FwcF9yZWFkeScsICgpID0+IGNvbnNvbGUubG9nKCdBcHAgaW5pdGlhbGl6ZWQnKSk7XG4gKiBSc3gudHJpZ2dlcignY3VzdG9tX2V2ZW50Jywge2RhdGE6ICd2YWx1ZSd9KTtcbiAqXG4gKiAvLyBFbnZpcm9ubWVudCBkZXRlY3Rpb25cbiAqIGlmIChSc3guaXNfZGV2KCkpIHsgY29uc29sZS5sb2coJ0RldmVsb3BtZW50IG1vZGUnKTsgfVxuICpcbiAqIC8vIFJvdXRlIGdlbmVyYXRpb25cbiAqIGNvbnN0IHVybCA9IFJzeC5Sb3V0ZSgnQ29udHJvbGxlcicsICdhY3Rpb24nKS51cmwoKTtcbiAqXG4gKiAvLyBVbmlxdWUgSURzXG4gKiBjb25zdCB1bmlxdWVJZCA9IFJzeC51aWQoKTsgLy8gZS5nLiwgXCJyc3hfMTIzNDU2Nzg5MF8xXCJcbiAqIGBgYFxuICpcbiAqIEBzdGF0aWNcbiAqIEBnbG9iYWxcbiAqL1xuY2xhc3MgUnN4IHtcbiAgICAvLyBHZXRzIHNldCB0byB0cnVlIHRvIGludGVydXB0IHN0YXJ0dXAgc2VxdWVuY2VcbiAgICBzdGF0aWMgX19zdG9wcGVkID0gZmFsc2U7XG5cbiAgICAvLyBJbml0aWFsaXplIGV2ZW50IGhhbmRsZXJzIHN0b3JhZ2VcbiAgICBzdGF0aWMgX2luaXRfZXZlbnRzKCkge1xuICAgICAgICBpZiAodHlwZW9mIFJzeC5fZXZlbnRfaGFuZGxlcnMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBSc3guX2V2ZW50X2hhbmRsZXJzID0ge307XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBSc3guX3RyaWdnZXJlZF9ldmVudHMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBSc3guX3RyaWdnZXJlZF9ldmVudHMgPSB7fTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlZ2lzdGVyIGFuIGV2ZW50IGhhbmRsZXJcbiAgICBzdGF0aWMgb24oZXZlbnQsIGNhbGxiYWNrKSB7XG4gICAgICAgIFJzeC5faW5pdF9ldmVudHMoKTtcblxuICAgICAgICBpZiAodHlwZW9mIGNhbGxiYWNrICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhbGxiYWNrIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFSc3guX2V2ZW50X2hhbmRsZXJzW2V2ZW50XSkge1xuICAgICAgICAgICAgUnN4Ll9ldmVudF9oYW5kbGVyc1tldmVudF0gPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIFJzeC5fZXZlbnRfaGFuZGxlcnNbZXZlbnRdLnB1c2goY2FsbGJhY2spO1xuXG4gICAgICAgIC8vIElmIHRoaXMgZXZlbnQgd2FzIGFscmVhZHkgdHJpZ2dlcmVkLCBjYWxsIHRoZSBjYWxsYmFjayBpbW1lZGlhdGVseVxuICAgICAgICBpZiAoUnN4Ll90cmlnZ2VyZWRfZXZlbnRzW2V2ZW50XSkge1xuICAgICAgICAgICAgY29uc29sZV9kZWJ1ZygnUlNYX0lOSVQnLCAnVHJpZ2dlcmluZyAnICsgZXZlbnQgKyAnIGZvciBsYXRlIHJlZ2lzdGVyZWQgY2FsbGJhY2snKTtcbiAgICAgICAgICAgIGNhbGxiYWNrKFJzeC5fdHJpZ2dlcmVkX2V2ZW50c1tldmVudF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gVHJpZ2dlciBhbiBldmVudCB3aXRoIG9wdGlvbmFsIGRhdGFcbiAgICBzdGF0aWMgdHJpZ2dlcihldmVudCwgZGF0YSA9IHt9KSB7XG4gICAgICAgIFJzeC5faW5pdF9ldmVudHMoKTtcblxuICAgICAgICAvLyBSZWNvcmQgdGhhdCB0aGlzIGV2ZW50IHdhcyB0cmlnZ2VyZWRcbiAgICAgICAgUnN4Ll90cmlnZ2VyZWRfZXZlbnRzW2V2ZW50XSA9IGRhdGE7XG5cbiAgICAgICAgaWYgKCFSc3guX2V2ZW50X2hhbmRsZXJzW2V2ZW50XSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc29sZV9kZWJ1ZygnUlNYX0lOSVQnLCAnVHJpZ2dlcmluZyAnICsgZXZlbnQgKyAnIGZvciAnICsgUnN4Ll9ldmVudF9oYW5kbGVyc1tldmVudF0ubGVuZ3RoICsgJyBjYWxsYmFja3MnKTtcblxuICAgICAgICAvLyBDYWxsIGFsbCByZWdpc3RlcmVkIGhhbmRsZXJzIGZvciB0aGlzIGV2ZW50IGluIG9yZGVyXG4gICAgICAgIGZvciAoY29uc3QgY2FsbGJhY2sgb2YgUnN4Ll9ldmVudF9oYW5kbGVyc1tldmVudF0pIHtcbiAgICAgICAgICAgIGNhbGxiYWNrKGRhdGEpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gQWxpYXMgZm9yIHRyaWdnZXIucmVmcmVzaCgnJyksIHNob3VsZCBiZSBjYWxsZWQgYWZ0ZXIgbWFqb3IgVUkgdXBkYXRlcyB0byBhcHBseSBzdWNoIGVmZmVjdHMgYXNcbiAgICAvLyB1bmRlcmxpbmluZyBsaW5rcyB0byB1bmltcGxlbWVudGVkICMgcm91dGVzXG4gICAgc3RhdGljIHRyaWdnZXJfcmVmcmVzaCgpIHtcbiAgICAgICAgLy8gVXNlIFJzeC5vbigncmVmcmVzaCcsIGNhbGxiYWNrKTsgdG8gcmVnaXN0ZXIgYSBjYWxsYmFjayBmb3IgcmVmcmVzaFxuICAgICAgICB0aGlzLnRyaWdnZXIoJ3JlZnJlc2gnKTtcbiAgICB9XG5cbiAgICAvLyBMb2cgdG8gc2VydmVyIHRoYXQgYW4gZXZlbnQgaGFwcGVuZWRcbiAgICBzdGF0aWMgbG9nKHR5cGUsIG1lc3NhZ2UgPSAnbm90aWNlJykge1xuICAgICAgICBDb3JlX0xvZy5sb2codHlwZSwgbWVzc2FnZSk7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJucyB0cnVlIGlmIHRoZSBhcHAgaXMgYmVpbmcgcnVuIGluIGRldiBtb2RlXG4gICAgLy8gVGhpcyBzaG91bGQgYWZmZWN0IGNhY2hpbmcgYW5kIHNvbWUgZGVidWcgY2hlY2tzXG4gICAgc3RhdGljIGlzX2RldigpIHtcbiAgICAgICAgcmV0dXJuIHdpbmRvdy5yc3hhcHAuZGVidWc7XG4gICAgfVxuXG4gICAgc3RhdGljIGlzX3Byb2QoKSB7XG4gICAgICAgIHJldHVybiAhd2luZG93LnJzeGFwcC5kZWJ1ZztcbiAgICB9XG5cbiAgICAvLyBHZW5lcmF0ZXMgYSB1bmlxdWUgbnVtYmVyIGZvciB0aGUgYXBwbGljYXRpb24gaW5zdGFuY2VcbiAgICBzdGF0aWMgdWlkKCkge1xuICAgICAgICBpZiAodHlwZW9mIFJzeC5fdWlkID09IHVuZGVmKSB7XG4gICAgICAgICAgICBSc3guX3VpZCA9IDA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFJzeC5fdWlkKys7XG4gICAgfVxuXG4gICAgLy8gU3RvcmFnZSBmb3Igcm91dGUgZGVmaW5pdGlvbnMgbG9hZGVkIGZyb20gYnVuZGxlc1xuICAgIHN0YXRpYyBfcm91dGVzID0ge307XG5cbiAgICAvKipcbiAgICAgKiBEZWZpbmUgcm91dGVzIGZyb20gYnVuZGxlZCBkYXRhXG4gICAgICogQ2FsbGVkIGJ5IGdlbmVyYXRlZCBKYXZhU2NyaXB0IGluIGJ1bmRsZXNcbiAgICAgKi9cbiAgICBzdGF0aWMgX2RlZmluZV9yb3V0ZXMocm91dGVzKSB7XG4gICAgICAgIC8vIE1lcmdlIHJvdXRlcyBpbnRvIHRoZSBnbG9iYWwgcm91dGUgc3RvcmFnZVxuICAgICAgICBmb3IgKGNvbnN0IGNsYXNzX25hbWUgaW4gcm91dGVzKSB7XG4gICAgICAgICAgICBpZiAoIVJzeC5fcm91dGVzW2NsYXNzX25hbWVdKSB7XG4gICAgICAgICAgICAgICAgUnN4Ll9yb3V0ZXNbY2xhc3NfbmFtZV0gPSB7fTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAoY29uc3QgbWV0aG9kX25hbWUgaW4gcm91dGVzW2NsYXNzX25hbWVdKSB7XG4gICAgICAgICAgICAgICAgUnN4Ll9yb3V0ZXNbY2xhc3NfbmFtZV1bbWV0aG9kX25hbWVdID0gcm91dGVzW2NsYXNzX25hbWVdW21ldGhvZF9uYW1lXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdlbmVyYXRlIFVSTCBmb3IgYSBjb250cm9sbGVyIHJvdXRlXG4gICAgICpcbiAgICAgKiBUaGlzIG1ldGhvZCBnZW5lcmF0ZXMgVVJMcyBmb3IgY29udHJvbGxlciBhY3Rpb25zIGJ5IGxvb2tpbmcgdXAgcm91dGUgcGF0dGVybnNcbiAgICAgKiBhbmQgcmVwbGFjaW5nIHBhcmFtZXRlcnMuIEl0IGhhbmRsZXMgYm90aCByZWd1bGFyIHJvdXRlcyBhbmQgQWpheCBlbmRwb2ludHMuXG4gICAgICpcbiAgICAgKiBJZiB0aGUgcm91dGUgaXMgbm90IGZvdW5kIGluIHRoZSByb3V0ZSBkZWZpbml0aW9ucywgYSBkZWZhdWx0IHBhdHRlcm4gaXMgdXNlZDpcbiAgICAgKiBgL18ve2NvbnRyb2xsZXJ9L3thY3Rpb259YCB3aXRoIGFsbCBwYXJhbWV0ZXJzIGFwcGVuZGVkIGFzIHF1ZXJ5IHN0cmluZ3MuXG4gICAgICpcbiAgICAgKiBVc2FnZSBleGFtcGxlczpcbiAgICAgKiBgYGBqYXZhc2NyaXB0XG4gICAgICogLy8gU2ltcGxlIHJvdXRlIHdpdGhvdXQgcGFyYW1ldGVycyAoZGVmYXVsdHMgdG8gJ2luZGV4JyBhY3Rpb24pXG4gICAgICogY29uc3QgdXJsID0gUnN4LlJvdXRlKCdGcm9udGVuZF9JbmRleF9Db250cm9sbGVyJyk7XG4gICAgICogLy8gUmV0dXJuczogL2Rhc2hib2FyZFxuICAgICAqXG4gICAgICogLy8gUm91dGUgd2l0aCBleHBsaWNpdCBhY3Rpb25cbiAgICAgKiBjb25zdCB1cmwgPSBSc3guUm91dGUoJ0Zyb250ZW5kX0luZGV4X0NvbnRyb2xsZXInLCAnaW5kZXgnKTtcbiAgICAgKiAvLyBSZXR1cm5zOiAvZGFzaGJvYXJkXG4gICAgICpcbiAgICAgKiAvLyBSb3V0ZSB3aXRoIGludGVnZXIgcGFyYW1ldGVyIChzZXRzICdpZCcpXG4gICAgICogY29uc3QgdXJsID0gUnN4LlJvdXRlKCdGcm9udGVuZF9DbGllbnRfVmlld19Db250cm9sbGVyJywgJ3ZpZXcnLCAxMjMpO1xuICAgICAqIC8vIFJldHVybnM6IC9jbGllbnRzL3ZpZXcvMTIzXG4gICAgICpcbiAgICAgKiAvLyBSb3V0ZSB3aXRoIG5hbWVkIHBhcmFtZXRlcnMgKG9iamVjdClcbiAgICAgKiBjb25zdCB1cmwgPSBSc3guUm91dGUoJ0Zyb250ZW5kX0NsaWVudF9WaWV3X0NvbnRyb2xsZXInLCAndmlldycsIHtpZDogJ0MwMDEnfSk7XG4gICAgICogLy8gUmV0dXJuczogL2NsaWVudHMvdmlldy9DMDAxXG4gICAgICpcbiAgICAgKiAvLyBSb3V0ZSB3aXRoIHJlcXVpcmVkIGFuZCBxdWVyeSBwYXJhbWV0ZXJzXG4gICAgICogY29uc3QgdXJsID0gUnN4LlJvdXRlKCdGcm9udGVuZF9DbGllbnRfVmlld19Db250cm9sbGVyJywgJ3ZpZXcnLCB7XG4gICAgICogICAgIGlkOiAnQzAwMScsXG4gICAgICogICAgIHRhYjogJ2hpc3RvcnknXG4gICAgICogfSk7XG4gICAgICogLy8gUmV0dXJuczogL2NsaWVudHMvdmlldy9DMDAxP3RhYj1oaXN0b3J5XG4gICAgICpcbiAgICAgKiAvLyBSb3V0ZSBub3QgZm91bmQgLSB1c2VzIGRlZmF1bHQgcGF0dGVyblxuICAgICAqIGNvbnN0IHVybCA9IFJzeC5Sb3V0ZSgnVW5pbXBsZW1lbnRlZF9Db250cm9sbGVyJywgJ3NvbWVfYWN0aW9uJywge2ZvbzogJ2Jhcid9KTtcbiAgICAgKiAvLyBSZXR1cm5zOiAvXy9VbmltcGxlbWVudGVkX0NvbnRyb2xsZXIvc29tZV9hY3Rpb24/Zm9vPWJhclxuICAgICAqXG4gICAgICogLy8gUGxhY2Vob2xkZXIgcm91dGVcbiAgICAgKiBjb25zdCB1cmwgPSBSc3guUm91dGUoJ0Z1dHVyZV9Db250cm9sbGVyJywgJyNpbmRleCcpO1xuICAgICAqIC8vIFJldHVybnM6ICNcbiAgICAgKiBgYGBcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjbGFzc19uYW1lIFRoZSBjb250cm9sbGVyIGNsYXNzIG5hbWUgKGUuZy4sICdVc2VyX0NvbnRyb2xsZXInKVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbYWN0aW9uX25hbWU9J2luZGV4J10gVGhlIGFjdGlvbi9tZXRob2QgbmFtZSAoZGVmYXVsdHMgdG8gJ2luZGV4JykuIFVzZSAnI2FjdGlvbicgZm9yIHBsYWNlaG9sZGVycy5cbiAgICAgKiBAcGFyYW0ge251bWJlcnxPYmplY3R9IFtwYXJhbXM9bnVsbF0gUm91dGUgcGFyYW1ldGVycy4gSW50ZWdlciBzZXRzICdpZCcsIG9iamVjdCBwcm92aWRlcyBuYW1lZCBwYXJhbXMuXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGdlbmVyYXRlZCBVUkxcbiAgICAgKi9cbiAgICBzdGF0aWMgUm91dGUoY2xhc3NfbmFtZSwgYWN0aW9uX25hbWUgPSAnaW5kZXgnLCBwYXJhbXMgPSBudWxsKSB7XG4gICAgICAgIC8vIE5vcm1hbGl6ZSBwYXJhbXMgdG8gb2JqZWN0XG4gICAgICAgIGxldCBwYXJhbXNfb2JqID0ge307XG4gICAgICAgIGlmICh0eXBlb2YgcGFyYW1zID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgcGFyYW1zX29iaiA9IHsgaWQ6IHBhcmFtcyB9O1xuICAgICAgICB9IGVsc2UgaWYgKHBhcmFtcyAmJiB0eXBlb2YgcGFyYW1zID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcGFyYW1zX29iaiA9IHBhcmFtcztcbiAgICAgICAgfSBlbHNlIGlmIChwYXJhbXMgIT09IG51bGwgJiYgcGFyYW1zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUGFyYW1zIG11c3QgYmUgbnVtYmVyLCBvYmplY3QsIG9yIG51bGwnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFBsYWNlaG9sZGVyIHJvdXRlOiBhY3Rpb24gc3RhcnRzIHdpdGggIyBtZWFucyB1bmltcGxlbWVudGVkL3NjYWZmb2xkaW5nXG4gICAgICAgIGlmIChhY3Rpb25fbmFtZS5zdGFydHNXaXRoKCcjJykpIHtcbiAgICAgICAgICAgIHJldHVybiAnIyc7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDaGVjayBpZiByb3V0ZSBleGlzdHMgaW4gZGVmaW5pdGlvbnNcbiAgICAgICAgbGV0IHBhdHRlcm47XG4gICAgICAgIGlmIChSc3guX3JvdXRlc1tjbGFzc19uYW1lXSAmJiBSc3guX3JvdXRlc1tjbGFzc19uYW1lXVthY3Rpb25fbmFtZV0pIHtcbiAgICAgICAgICAgIHBhdHRlcm4gPSBSc3guX3JvdXRlc1tjbGFzc19uYW1lXVthY3Rpb25fbmFtZV07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBSb3V0ZSBub3QgZm91bmQgLSB1c2UgZGVmYXVsdCBwYXR0ZXJuIC9fL3tjb250cm9sbGVyfS97YWN0aW9ufVxuICAgICAgICAgICAgcGF0dGVybiA9IGAvXy8ke2NsYXNzX25hbWV9LyR7YWN0aW9uX25hbWV9YDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEdlbmVyYXRlIFVSTCBmcm9tIHBhdHRlcm5cbiAgICAgICAgcmV0dXJuIFJzeC5fZ2VuZXJhdGVfdXJsX2Zyb21fcGF0dGVybihwYXR0ZXJuLCBwYXJhbXNfb2JqKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZW5lcmF0ZSBVUkwgZnJvbSByb3V0ZSBwYXR0ZXJuIGJ5IHJlcGxhY2luZyBwYXJhbWV0ZXJzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0dGVybiBUaGUgcm91dGUgcGF0dGVybiAoZS5nLiwgJy91c2Vycy86aWQvdmlldycpXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcyBQYXJhbWV0ZXJzIHRvIGZpbGwgaW50byB0aGUgcm91dGVcbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZ2VuZXJhdGVkIFVSTFxuICAgICAqL1xuICAgIHN0YXRpYyBfZ2VuZXJhdGVfdXJsX2Zyb21fcGF0dGVybihwYXR0ZXJuLCBwYXJhbXMpIHtcbiAgICAgICAgLy8gRXh0cmFjdCByZXF1aXJlZCBwYXJhbWV0ZXJzIGZyb20gdGhlIHBhdHRlcm5cbiAgICAgICAgY29uc3QgcmVxdWlyZWRfcGFyYW1zID0gW107XG4gICAgICAgIGNvbnN0IG1hdGNoZXMgPSBwYXR0ZXJuLm1hdGNoKC86KFthLXpBLVpfXVthLXpBLVowLTlfXSopL2cpO1xuICAgICAgICBpZiAobWF0Y2hlcykge1xuICAgICAgICAgICAgLy8gUmVtb3ZlIHRoZSA6IHByZWZpeCBmcm9tIGVhY2ggbWF0Y2hcbiAgICAgICAgICAgIGZvciAoY29uc3QgbWF0Y2ggb2YgbWF0Y2hlcykge1xuICAgICAgICAgICAgICAgIHJlcXVpcmVkX3BhcmFtcy5wdXNoKG1hdGNoLnN1YnN0cmluZygxKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDaGVjayBmb3IgcmVxdWlyZWQgcGFyYW1ldGVyc1xuICAgICAgICBjb25zdCBtaXNzaW5nID0gW107XG4gICAgICAgIGZvciAoY29uc3QgcmVxdWlyZWQgb2YgcmVxdWlyZWRfcGFyYW1zKSB7XG4gICAgICAgICAgICBpZiAoIShyZXF1aXJlZCBpbiBwYXJhbXMpKSB7XG4gICAgICAgICAgICAgICAgbWlzc2luZy5wdXNoKHJlcXVpcmVkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtaXNzaW5nLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUmVxdWlyZWQgcGFyYW1ldGVycyBbJHttaXNzaW5nLmpvaW4oJywgJyl9XSBhcmUgbWlzc2luZyBmb3Igcm91dGUgJHtwYXR0ZXJufWApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQnVpbGQgdGhlIFVSTCBieSByZXBsYWNpbmcgcGFyYW1ldGVyc1xuICAgICAgICBsZXQgdXJsID0gcGF0dGVybjtcbiAgICAgICAgY29uc3QgdXNlZF9wYXJhbXMgPSB7fTtcblxuICAgICAgICBmb3IgKGNvbnN0IHBhcmFtX25hbWUgb2YgcmVxdWlyZWRfcGFyYW1zKSB7XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSA9IHBhcmFtc1twYXJhbV9uYW1lXTtcbiAgICAgICAgICAgIC8vIFVSTCBlbmNvZGUgdGhlIHZhbHVlXG4gICAgICAgICAgICBjb25zdCBlbmNvZGVkX3ZhbHVlID0gZW5jb2RlVVJJQ29tcG9uZW50KHZhbHVlKTtcbiAgICAgICAgICAgIHVybCA9IHVybC5yZXBsYWNlKCc6JyArIHBhcmFtX25hbWUsIGVuY29kZWRfdmFsdWUpO1xuICAgICAgICAgICAgdXNlZF9wYXJhbXNbcGFyYW1fbmFtZV0gPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29sbGVjdCBhbnkgZXh0cmEgcGFyYW1ldGVycyBmb3IgcXVlcnkgc3RyaW5nXG4gICAgICAgIGNvbnN0IHF1ZXJ5X3BhcmFtcyA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBwYXJhbXMpIHtcbiAgICAgICAgICAgIGlmICghdXNlZF9wYXJhbXNba2V5XSkge1xuICAgICAgICAgICAgICAgIHF1ZXJ5X3BhcmFtc1trZXldID0gcGFyYW1zW2tleV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBBcHBlbmQgcXVlcnkgc3RyaW5nIGlmIHRoZXJlIGFyZSBleHRyYSBwYXJhbWV0ZXJzXG4gICAgICAgIGlmIChPYmplY3Qua2V5cyhxdWVyeV9wYXJhbXMpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IHF1ZXJ5X3N0cmluZyA9IE9iamVjdC5lbnRyaWVzKHF1ZXJ5X3BhcmFtcylcbiAgICAgICAgICAgICAgICAubWFwKChba2V5LCB2YWx1ZV0pID0+IGAke2VuY29kZVVSSUNvbXBvbmVudChrZXkpfT0ke2VuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSl9YClcbiAgICAgICAgICAgICAgICAuam9pbignJicpO1xuICAgICAgICAgICAgdXJsICs9ICc/JyArIHF1ZXJ5X3N0cmluZztcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB1cmw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWw6IENhbGwgYSBzcGVjaWZpYyBtZXRob2Qgb24gYWxsIGNsYXNzZXMgdGhhdCBoYXZlIGl0XG4gICAgICogQ29sbGVjdHMgcHJvbWlzZXMgZnJvbSByZXR1cm4gdmFsdWVzIGFuZCB3YWl0cyBmb3IgYWxsIHRvIHJlc29sdmVcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbWV0aG9kX25hbWUgVGhlIG1ldGhvZCBuYW1lIHRvIGNhbGwgb24gYWxsIGNsYXNzZXNcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gYWxsIG1ldGhvZCBjYWxscyBjb21wbGV0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBhc3luYyBfcnN4X2NhbGxfYWxsX2NsYXNzZXMobWV0aG9kX25hbWUpIHtcbiAgICAgICAgY29uc3QgYWxsX2NsYXNzZXMgPSBNYW5pZmVzdC5nZXRfYWxsX2NsYXNzZXMoKTtcbiAgICAgICAgY29uc3QgY2xhc3Nlc193aXRoX21ldGhvZCA9IFtdO1xuICAgICAgICBjb25zdCBwcm9taXNlX3BpbGUgPSBbXTtcblxuICAgICAgICBmb3IgKGNvbnN0IGNsYXNzX2luZm8gb2YgYWxsX2NsYXNzZXMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNsYXNzX29iamVjdCA9IGNsYXNzX2luZm8uY2xhc3Nfb2JqZWN0O1xuICAgICAgICAgICAgY29uc3QgY2xhc3NfbmFtZSA9IGNsYXNzX2luZm8uY2xhc3NfbmFtZTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBjbGFzcyBoYXMgdGhlIG1ldGhvZCAoc3RhdGljIG1ldGhvZHMgYXJlIG9uIHRoZSBjbGFzcyBpdHNlbGYpXG4gICAgICAgICAgICBpZiAodHlwZW9mIGNsYXNzX29iamVjdFttZXRob2RfbmFtZV0gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICBjbGFzc2VzX3dpdGhfbWV0aG9kLnB1c2goY2xhc3NfbmFtZSk7XG4gICAgICAgICAgICAgICAgY29uc3QgcmV0dXJuX3ZhbHVlID0gYXdhaXQgY2xhc3Nfb2JqZWN0W21ldGhvZF9uYW1lXSgpO1xuXG4gICAgICAgICAgICAgICAgLy8gQ29sbGVjdCBwcm9taXNlcyBmcm9tIHJldHVybiB2YWx1ZVxuICAgICAgICAgICAgICAgIGlmIChyZXR1cm5fdmFsdWUgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHByb21pc2VfcGlsZS5wdXNoKHJldHVybl92YWx1ZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KHJldHVybl92YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBpdGVtIG9mIHJldHVybl92YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvbWlzZV9waWxlLnB1c2goaXRlbSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoUnN4Ll9fc3RvcHBlZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNsYXNzZXNfd2l0aF9tZXRob2QubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc29sZV9kZWJ1ZygnUlNYX0lOSVQnLCBgJHttZXRob2RfbmFtZX06ICR7Y2xhc3Nlc193aXRoX21ldGhvZC5sZW5ndGh9IGNsYXNzZXNgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEF3YWl0IGFsbCBwcm9taXNlcyBiZWZvcmUgcmV0dXJuaW5nXG4gICAgICAgIGlmIChwcm9taXNlX3BpbGUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc29sZV9kZWJ1ZygnUlNYX0lOSVQnLCBgJHttZXRob2RfbmFtZX06IEF3YWl0aW5nICR7cHJvbWlzZV9waWxlLmxlbmd0aH0gcHJvbWlzZXNgKTtcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VfcGlsZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnRlcm5hbDogRXhlY3V0ZSBtdWx0aS1waGFzZSBpbml0aWFsaXphdGlvbiBmb3IgYWxsIHJlZ2lzdGVyZWQgY2xhc3Nlc1xuICAgICAqIFRoaXMgcnVucyB2YXJpb3VzIGluaXRpYWxpemF0aW9uIHBoYXNlcyBpbiBvcmRlciB0byBwcm9wZXJseSBzZXQgdXAgdGhlIGFwcGxpY2F0aW9uXG4gICAgICogQHJldHVybnMge1Byb21pc2V9IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBpbml0aWFsaXphdGlvbiBwaGFzZXMgY29tcGxldGVcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgX3JzeF9jb3JlX2Jvb3QoKSB7XG4gICAgICAgIGlmIChSc3guX19ib290ZWQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1JzeC5fcnN4X2NvcmVfYm9vdCBjYWxsZWQgbW9yZSB0aGFuIG9uY2UnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIFJzeC5fX2Jvb3RlZCA9IHRydWU7XG5cbiAgICAgICAgLy8gR2V0IGFsbCByZWdpc3RlcmVkIGNsYXNzZXMgZnJvbSB0aGUgbWFuaWZlc3RcbiAgICAgICAgY29uc3QgYWxsX2NsYXNzZXMgPSBNYW5pZmVzdC5nZXRfYWxsX2NsYXNzZXMoKTtcblxuICAgICAgICBjb25zb2xlX2RlYnVnKCdSU1hfSU5JVCcsIGBTdGFydGluZyBfcnN4X2NvcmVfYm9vdCB3aXRoICR7YWxsX2NsYXNzZXMubGVuZ3RofSBjbGFzc2VzYCk7XG5cbiAgICAgICAgaWYgKCFhbGxfY2xhc3NlcyB8fCBhbGxfY2xhc3Nlcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIC8vIE5vIGNsYXNzZXMgdG8gaW5pdGlhbGl6ZVxuICAgICAgICAgICAgc2hvdWxkbnRfaGFwcGVuKCdObyBjbGFzc2VzIHJlZ2lzdGVyZWQgaW4ganMgLSB0aGVyZSBzaG91bGQgYmUgYXQgbGVhc3QgdGhlIGNvcmUgZnJhbWV3b3JrIGNsYXNzZXMnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERlZmluZSBpbml0aWFsaXphdGlvbiBwaGFzZXMgaW4gb3JkZXJcbiAgICAgICAgY29uc3QgcGhhc2VzID0gW1xuICAgICAgICAgICAgeyBldmVudDogJ2ZyYW1ld29ya19jb3JlX2RlZmluZScsIG1ldGhvZDogJ19vbl9mcmFtZXdvcmtfY29yZV9kZWZpbmUnIH0sXG4gICAgICAgICAgICB7IGV2ZW50OiAnZnJhbWV3b3JrX21vZHVsZXNfZGVmaW5lJywgbWV0aG9kOiAnX29uX2ZyYW1ld29ya19tb2R1bGVzX2RlZmluZScgfSxcbiAgICAgICAgICAgIHsgZXZlbnQ6ICdmcmFtZXdvcmtfY29yZV9pbml0JywgbWV0aG9kOiAnX29uX2ZyYW1ld29ya19jb3JlX2luaXQnIH0sXG4gICAgICAgICAgICB7IGV2ZW50OiAnYXBwX21vZHVsZXNfZGVmaW5lJywgbWV0aG9kOiAnb25fYXBwX21vZHVsZXNfZGVmaW5lJyB9LFxuICAgICAgICAgICAgeyBldmVudDogJ2FwcF9kZWZpbmUnLCBtZXRob2Q6ICdvbl9hcHBfZGVmaW5lJyB9LFxuICAgICAgICAgICAgeyBldmVudDogJ2ZyYW1ld29ya19tb2R1bGVzX2luaXQnLCBtZXRob2Q6ICdfb25fZnJhbWV3b3JrX21vZHVsZXNfaW5pdCcgfSxcbiAgICAgICAgICAgIHsgZXZlbnQ6ICdhcHBfbW9kdWxlc19pbml0JywgbWV0aG9kOiAnb25fYXBwX21vZHVsZXNfaW5pdCcgfSxcbiAgICAgICAgICAgIHsgZXZlbnQ6ICdhcHBfaW5pdCcsIG1ldGhvZDogJ29uX2FwcF9pbml0JyB9LFxuICAgICAgICAgICAgeyBldmVudDogJ2FwcF9yZWFkeScsIG1ldGhvZDogJ29uX2FwcF9yZWFkeScgfSxcbiAgICAgICAgXTtcblxuICAgICAgICAvLyBFeGVjdXRlIGVhY2ggcGhhc2UgaW4gb3JkZXJcbiAgICAgICAgZm9yIChjb25zdCBwaGFzZSBvZiBwaGFzZXMpIHtcbiAgICAgICAgICAgIGF3YWl0IFJzeC5fcnN4X2NhbGxfYWxsX2NsYXNzZXMocGhhc2UubWV0aG9kKTtcblxuICAgICAgICAgICAgaWYgKFJzeC5fX3N0b3BwZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIFJzeC50cmlnZ2VyKHBoYXNlLmV2ZW50KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFVpIHJlZnJlc2ggY2FsbGJhY2tzXG4gICAgICAgIFJzeC50cmlnZ2VyX3JlZnJlc2goKTtcblxuICAgICAgICAvLyBBbGwgcGhhc2VzIGNvbXBsZXRlXG4gICAgICAgIGNvbnNvbGVfZGVidWcoJ1JTWF9JTklUJywgJ0luaXRpYWxpemF0aW9uIGNvbXBsZXRlJyk7XG5cbiAgICAgICAgLy8gVE9ETzogRmluZCBhIGdvb2Qgd2FpdCB0byB3YWl0IGZvciBhbGwganFodG1sIGNvbXBvbmVudHMgdG8gbG9hZCwgdGhlbiB0cmlnZ2VyIG9uX3JlYWR5IGFuZCBvbigncmVhZHknKSBlbXVsYXRpbmcgdGhlIHRvcCBsZXZlbCBsYXN0IHN5bnRheCB0aGF0IGpxaHRtbCBjb21wb25lbnRzIG9wZXJhdGVhcywgYnV0IGFzIGEgc3RhbmRhcmQganMgY2xhc3MgKHN1Y2ggYXMgYSBwYWdlIGNsYXNzKS4gIFRoZSBiaWdnZXN0IHF1ZXN0aW9uIGlzLCBob3cgZG8gd2UgZWZmaWNpZW50bHkgY2hvb3NlIG9ubHkgdGhlIHRvcCBsZXZlbCBqcWh0bWwgY29tcG9uZW50cy4gIGRvIHdlIG9ubHkgY29uc2lkZXIgY29tcG9uZW50cyBjcmV0YWVkIGRpcmVjdGx5IG9uIGJsYWRlIHRlbXBsYXRlcz8gdGhhdCBzZWFtcyByZWFzb25hYmxlLi4uXG5cbiAgICAgICAgLy8gVHJpZ2dlciBfZGVidWdfcmVhZHkgZXZlbnQgLSB0aGlzIGlzIE9OTFkgZm9yIHRvb2xpbmcgbGlrZSByc3g6ZGVidWdcbiAgICAgICAgLy8gRE8gTk9UIHVzZSB0aGlzIGluIGFwcGxpY2F0aW9uIGNvZGUgLSB1c2Ugb25fYXBwX3JlYWR5KCkgcGhhc2UgaW5zdGVhZFxuICAgICAgICAvLyBUaGlzIGV2ZW50IGV4aXN0cyBzb2xlbHkgZm9yIGRlYnVnZ2luZyB0b29scyB0aGF0IG5lZWQgdG8gcnVuIGFmdGVyIGZ1bGwgaW5pdGlhbGl6YXRpb25cbiAgICAgICAgUnN4LnRyaWdnZXIoJ19kZWJ1Z19yZWFkeScpO1xuICAgIH1cblxuICAgIC8qIENhbGxpbmcgdGhpcyBzdG9wcyB0aGUgYm9vdCBwcm9jZXNzLiAqL1xuICAgIHN0YXRpYyBhc3luYyBfcnN4X2NvcmVfYm9vdF9zdG9wKHJlYXNvbikge1xuICAgICAgICBjb25zb2xlLmVycm9yKHJlYXNvbik7XG4gICAgICAgIFJzeC5fX3N0b3BwZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBhcnNlIFVSTCBoYXNoIGludG8ga2V5LXZhbHVlIG9iamVjdFxuICAgICAqIEhhbmRsZXMgZm9ybWF0OiAja2V5PXZhbHVlJmtleTI9dmFsdWUyXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBQYXJzZWQgaGFzaCBwYXJhbWV0ZXJzXG4gICAgICovXG4gICAgc3RhdGljIF9wYXJzZV9oYXNoKCkge1xuICAgICAgICBjb25zdCBoYXNoID0gd2luZG93LmxvY2F0aW9uLmhhc2g7XG4gICAgICAgIGlmICghaGFzaCB8fCBoYXNoID09PSAnIycpIHtcbiAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlbW92ZSBsZWFkaW5nICMgYW5kIHBhcnNlIGFzIHF1ZXJ5IHN0cmluZ1xuICAgICAgICBjb25zdCBoYXNoX3N0cmluZyA9IGhhc2guc3Vic3RyaW5nKDEpO1xuICAgICAgICBjb25zdCBwYXJhbXMgPSB7fTtcblxuICAgICAgICBjb25zdCBwYWlycyA9IGhhc2hfc3RyaW5nLnNwbGl0KCcmJyk7XG4gICAgICAgIGZvciAoY29uc3QgcGFpciBvZiBwYWlycykge1xuICAgICAgICAgICAgY29uc3QgW2tleSwgdmFsdWVdID0gcGFpci5zcGxpdCgnPScpO1xuICAgICAgICAgICAgaWYgKGtleSkge1xuICAgICAgICAgICAgICAgIHBhcmFtc1tkZWNvZGVVUklDb21wb25lbnQoa2V5KV0gPSB2YWx1ZSA/IGRlY29kZVVSSUNvbXBvbmVudCh2YWx1ZSkgOiAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBwYXJhbXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VyaWFsaXplIG9iamVjdCBpbnRvIFVSTCBoYXNoIGZvcm1hdFxuICAgICAqIFByb2R1Y2VzIGZvcm1hdDogI2tleT12YWx1ZSZrZXkyPXZhbHVlMlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBhcmFtcyBLZXktdmFsdWUgcGFpcnMgdG8gZW5jb2RlXG4gICAgICogQHJldHVybnMge3N0cmluZ30gRW5jb2RlZCBoYXNoIHN0cmluZyAod2l0aCBsZWFkaW5nICMsIG9yIGVtcHR5IHN0cmluZylcbiAgICAgKi9cbiAgICBzdGF0aWMgX3NlcmlhbGl6ZV9oYXNoKHBhcmFtcykge1xuICAgICAgICBjb25zdCBwYWlycyA9IFtdO1xuICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBwYXJhbXMpIHtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gcGFyYW1zW2tleV07XG4gICAgICAgICAgICBpZiAodmFsdWUgIT09IG51bGwgJiYgdmFsdWUgIT09IHVuZGVmaW5lZCAmJiB2YWx1ZSAhPT0gJycpIHtcbiAgICAgICAgICAgICAgICBwYWlycy5wdXNoKGAke2VuY29kZVVSSUNvbXBvbmVudChrZXkpfT0ke2VuY29kZVVSSUNvbXBvbmVudCh2YWx1ZSl9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcGFpcnMubGVuZ3RoID4gMCA/ICcjJyArIHBhaXJzLmpvaW4oJyYnKSA6ICcnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhbGwgcGFnZSBzdGF0ZSBmcm9tIFVSTCBoYXNoXG4gICAgICpcbiAgICAgKiBVc2FnZTpcbiAgICAgKiBgYGBqYXZhc2NyaXB0XG4gICAgICogY29uc3Qgc3RhdGUgPSBSc3guZ2V0X2FsbF9wYWdlX3N0YXRlKCk7XG4gICAgICogLy8gUmV0dXJuczoge2RnX3BhZ2U6ICcyJywgZGdfc29ydDogJ25hbWUnfVxuICAgICAqIGBgYFxuICAgICAqXG4gICAgICogQHJldHVybnMge09iamVjdH0gQWxsIGhhc2ggcGFyYW1ldGVycyBhcyBrZXktdmFsdWUgcGFpcnNcbiAgICAgKi9cbiAgICBzdGF0aWMgZ2V0X2FsbF9wYWdlX3N0YXRlKCkge1xuICAgICAgICByZXR1cm4gUnN4Ll9wYXJzZV9oYXNoKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHNpbmdsZSB2YWx1ZSBmcm9tIFVSTCBoYXNoIHN0YXRlXG4gICAgICpcbiAgICAgKiBVc2FnZTpcbiAgICAgKiBgYGBqYXZhc2NyaXB0XG4gICAgICogY29uc3QgcGFnZSA9IFJzeC5nZXRfcGFnZV9zdGF0ZSgnZGdfcGFnZScpO1xuICAgICAqIC8vIFJldHVybnM6ICcyJyBvciBudWxsIGlmIG5vdCBzZXRcbiAgICAgKiBgYGBcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSB0byByZXRyaWV2ZVxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd8bnVsbH0gVGhlIHZhbHVlIG9yIG51bGwgaWYgbm90IGZvdW5kXG4gICAgICovXG4gICAgc3RhdGljIGdldF9wYWdlX3N0YXRlKGtleSkge1xuICAgICAgICBjb25zdCBzdGF0ZSA9IFJzeC5fcGFyc2VfaGFzaCgpO1xuICAgICAgICByZXR1cm4gc3RhdGVba2V5XSA/PyBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBzaW5nbGUgdmFsdWUgaW4gVVJMIGhhc2ggc3RhdGUgKHJlcGxhY2VzIGhpc3RvcnksIGRvZXNuJ3QgYWRkKVxuICAgICAqXG4gICAgICogVXNhZ2U6XG4gICAgICogYGBgamF2YXNjcmlwdFxuICAgICAqIFJzeC5zZXRfcGFnZV9zdGF0ZSgnZGdfcGFnZScsIDIpO1xuICAgICAqIC8vIFVSTCBiZWNvbWVzOiBodHRwOi8vZXhhbXBsZS5jb20vcGFnZSNkZ19wYWdlPTJcbiAgICAgKlxuICAgICAqIFJzeC5zZXRfcGFnZV9zdGF0ZSgnZGdfcGFnZScsIG51bGwpOyAvLyBSZW1vdmUga2V5XG4gICAgICogYGBgXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IFRoZSBrZXkgdG8gc2V0XG4gICAgICogQHBhcmFtIHtzdHJpbmd8bnVtYmVyfG51bGx9IHZhbHVlIFRoZSB2YWx1ZSAobnVsbC9lbXB0eSByZW1vdmVzIHRoZSBrZXkpXG4gICAgICovXG4gICAgc3RhdGljIHNldF9wYWdlX3N0YXRlKGtleSwgdmFsdWUpIHtcbiAgICAgICAgY29uc3Qgc3RhdGUgPSBSc3guX3BhcnNlX2hhc2goKTtcblxuICAgICAgICAvLyBVcGRhdGUgb3IgcmVtb3ZlIHRoZSBrZXlcbiAgICAgICAgaWYgKHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09ICcnKSB7XG4gICAgICAgICAgICBkZWxldGUgc3RhdGVba2V5XTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHN0YXRlW2tleV0gPSBTdHJpbmcodmFsdWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVXBkYXRlIFVSTCB3aXRob3V0IGFkZGluZyBoaXN0b3J5XG4gICAgICAgIGNvbnN0IG5ld19oYXNoID0gUnN4Ll9zZXJpYWxpemVfaGFzaChzdGF0ZSk7XG4gICAgICAgIGNvbnN0IHVybCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZSArIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2ggKyBuZXdfaGFzaDtcbiAgICAgICAgaGlzdG9yeS5yZXBsYWNlU3RhdGUobnVsbCwgJycsIHVybCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IG11bHRpcGxlIHZhbHVlcyBpbiBVUkwgaGFzaCBzdGF0ZSBhdCBvbmNlXG4gICAgICpcbiAgICAgKiBVc2FnZTpcbiAgICAgKiBgYGBqYXZhc2NyaXB0XG4gICAgICogUnN4LnNldF9hbGxfcGFnZV9zdGF0ZSh7ZGdfcGFnZTogMiwgZGdfc29ydDogJ25hbWUnfSk7XG4gICAgICogLy8gVVJMIGJlY29tZXM6IGh0dHA6Ly9leGFtcGxlLmNvbS9wYWdlI2RnX3BhZ2U9MiZkZ19zb3J0PW5hbWVcbiAgICAgKiBgYGBcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBuZXdfc3RhdGUgT2JqZWN0IHdpdGgga2V5LXZhbHVlIHBhaXJzIHRvIHNldFxuICAgICAqL1xuICAgIHN0YXRpYyBzZXRfYWxsX3BhZ2Vfc3RhdGUobmV3X3N0YXRlKSB7XG4gICAgICAgIGNvbnN0IHN0YXRlID0gUnN4Ll9wYXJzZV9oYXNoKCk7XG5cbiAgICAgICAgLy8gTWVyZ2UgbmV3IHN0YXRlXG4gICAgICAgIGZvciAoY29uc3Qga2V5IGluIG5ld19zdGF0ZSkge1xuICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBuZXdfc3RhdGVba2V5XTtcbiAgICAgICAgICAgIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSAnJykge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBzdGF0ZVtrZXldO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzdGF0ZVtrZXldID0gU3RyaW5nKHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFVwZGF0ZSBVUkwgd2l0aG91dCBhZGRpbmcgaGlzdG9yeVxuICAgICAgICBjb25zdCBuZXdfaGFzaCA9IFJzeC5fc2VyaWFsaXplX2hhc2goc3RhdGUpO1xuICAgICAgICBjb25zdCB1cmwgPSB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUgKyB3aW5kb3cubG9jYXRpb24uc2VhcmNoICsgbmV3X2hhc2g7XG4gICAgICAgIGhpc3RvcnkucmVwbGFjZVN0YXRlKG51bGwsICcnLCB1cmwpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbmRlciBhbiBlcnJvciBpbiBhIERPTSBlbGVtZW50XG4gICAgICpcbiAgICAgKiBEaXNwbGF5cyBlcnJvcnMgZnJvbSBBamF4IGNhbGxzIGluIGEgc3RhbmRhcmRpemVkIGZvcm1hdC4gSGFuZGxlcyBkaWZmZXJlbnRcbiAgICAgKiBlcnJvciB0eXBlcyAoZmF0YWwsIHZhbGlkYXRpb24sIGF1dGgsIGdlbmVyaWMpIHdpdGggYXBwcm9wcmlhdGUgZm9ybWF0dGluZy5cbiAgICAgKlxuICAgICAqIFVzYWdlOlxuICAgICAqIGBgYGphdmFzY3JpcHRcbiAgICAgKiB0cnkge1xuICAgICAqICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBDb250cm9sbGVyLm1ldGhvZCgpO1xuICAgICAqIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICogICAgIFJzeC5yZW5kZXJfZXJyb3IoZXJyb3IsICcjZXJyb3JfY29udGFpbmVyJyk7XG4gICAgICogfVxuICAgICAqIGBgYFxuICAgICAqXG4gICAgICogQHBhcmFtIHtFcnJvcnxPYmplY3R9IGVycm9yIC0gRXJyb3Igb2JqZWN0IGZyb20gQWpheCBjYWxsXG4gICAgICogQHBhcmFtIHtqUXVlcnl8c3RyaW5nfSBjb250YWluZXIgLSBqUXVlcnkgZWxlbWVudCBvciBzZWxlY3RvciBmb3IgZXJyb3IgZGlzcGxheVxuICAgICAqL1xuICAgIHN0YXRpYyByZW5kZXJfZXJyb3IoZXJyb3IsIGNvbnRhaW5lcikge1xuICAgICAgICBjb25zdCAkY29udGFpbmVyID0gJChjb250YWluZXIpO1xuXG4gICAgICAgIGlmICghJGNvbnRhaW5lci5leGlzdHMoKSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignUnN4LnJlbmRlcl9lcnJvcjogQ29udGFpbmVyIG5vdCBmb3VuZCcsIGNvbnRhaW5lcik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDbGVhciBleGlzdGluZyBjb250ZW50XG4gICAgICAgICRjb250YWluZXIuZW1wdHkoKTtcblxuICAgICAgICBsZXQgaHRtbCA9ICcnO1xuXG4gICAgICAgIC8vIEhhbmRsZSBkaWZmZXJlbnQgZXJyb3IgdHlwZXNcbiAgICAgICAgaWYgKGVycm9yLnR5cGUgPT09ICdmYXRhbCcgJiYgZXJyb3IuZGV0YWlscykge1xuICAgICAgICAgICAgLy8gRmF0YWwgUEhQIGVycm9yIHdpdGggZmlsZS9saW5lL2Vycm9yXG4gICAgICAgICAgICBjb25zdCBkZXRhaWxzID0gZXJyb3IuZGV0YWlscztcbiAgICAgICAgICAgIGNvbnN0IGZpbGUgPSBkZXRhaWxzLmZpbGUgfHwgJ1Vua25vd24gZmlsZSc7XG4gICAgICAgICAgICBjb25zdCBsaW5lID0gZGV0YWlscy5saW5lIHx8ICc/JztcbiAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBkZXRhaWxzLmVycm9yIHx8IGVycm9yLm1lc3NhZ2UgfHwgJ0ZhdGFsIGVycm9yIG9jY3VycmVkJztcblxuICAgICAgICAgICAgaHRtbCA9IGBcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtZGFuZ2VyXCIgcm9sZT1cImFsZXJ0XCI+XG4gICAgICAgICAgICAgICAgICAgIDxoNT5VbmNhdWdodCBGYXRhbCBFcnJvciBpbiAke2ZpbGV9OiR7bGluZX06PC9oNT5cbiAgICAgICAgICAgICAgICAgICAgPHAgY2xhc3M9XCJtYi0wXCI+JHtSc3guX2VzY2FwZV9odG1sKG1lc3NhZ2UpfTwvcD5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIGA7XG4gICAgICAgIH0gZWxzZSBpZiAoZXJyb3IudHlwZSA9PT0gJ2Zvcm1fZXJyb3InICYmIGVycm9yLmRldGFpbHMpIHtcbiAgICAgICAgICAgIC8vIFZhbGlkYXRpb24gZXJyb3JzIC0gc2hvdyB1bm1hdGNoZWQgZXJyb3JzIG9ubHlcbiAgICAgICAgICAgIC8vIChtYXRjaGVkIGVycm9ycyBzaG91bGQgYmUgaGFuZGxlZCBieSBGb3JtX1V0aWxzLmFwcGx5X2Zvcm1fZXJyb3JzKVxuICAgICAgICAgICAgY29uc3QgZXJyb3JzID0gZXJyb3IuZGV0YWlscztcbiAgICAgICAgICAgIGNvbnN0IGVycm9yX2xpc3QgPSBbXTtcblxuICAgICAgICAgICAgZm9yIChjb25zdCBmaWVsZCBpbiBlcnJvcnMpIHtcbiAgICAgICAgICAgICAgICBlcnJvcl9saXN0LnB1c2goZXJyb3JzW2ZpZWxkXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChlcnJvcl9saXN0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBodG1sID0gYFxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtd2FybmluZ1wiIHJvbGU9XCJhbGVydFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGg1PlZhbGlkYXRpb24gRXJyb3JzOjwvaDU+XG4gICAgICAgICAgICAgICAgICAgICAgICA8dWwgY2xhc3M9XCJtYi0wXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJHtlcnJvcl9saXN0Lm1hcChlcnIgPT4gYDxsaT4ke1JzeC5fZXNjYXBlX2h0bWwoZXJyKX08L2xpPmApLmpvaW4oJycpfVxuICAgICAgICAgICAgICAgICAgICAgICAgPC91bD5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgYDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChlcnJvci50eXBlID09PSAnYXV0aF9yZXF1aXJlZCcgfHwgZXJyb3IudHlwZSA9PT0gJ3VuYXV0aG9yaXplZCcpIHtcbiAgICAgICAgICAgIC8vIEF1dGhlbnRpY2F0aW9uL2F1dGhvcml6YXRpb24gZXJyb3JzXG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IubWVzc2FnZSB8fCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnO1xuICAgICAgICAgICAgaHRtbCA9IGBcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtd2FybmluZ1wiIHJvbGU9XCJhbGVydFwiPlxuICAgICAgICAgICAgICAgICAgICA8cCBjbGFzcz1cIm1iLTBcIj4ke1JzeC5fZXNjYXBlX2h0bWwobWVzc2FnZSl9PC9wPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgYDtcbiAgICAgICAgfSBlbHNlIGlmIChlcnJvci50eXBlID09PSAnbmV0d29yaycpIHtcbiAgICAgICAgICAgIC8vIE5ldHdvcmsgZXJyb3JzXG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IubWVzc2FnZSB8fCAnVW5hYmxlIHRvIHJlYWNoIHNlcnZlci4gUGxlYXNlIGNoZWNrIHlvdXIgY29ubmVjdGlvbi4nO1xuICAgICAgICAgICAgaHRtbCA9IGBcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtZGFuZ2VyXCIgcm9sZT1cImFsZXJ0XCI+XG4gICAgICAgICAgICAgICAgICAgIDxwIGNsYXNzPVwibWItMFwiPiR7UnN4Ll9lc2NhcGVfaHRtbChtZXNzYWdlKX08L3A+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICBgO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gR2VuZXJpYy91bmtub3duIGVycm9yXG4gICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gZXJyb3IubWVzc2FnZSB8fCBlcnJvci50b1N0cmluZygpIHx8ICdBbiB1bmtub3duIGVycm9yIG9jY3VycmVkJztcbiAgICAgICAgICAgIGh0bWwgPSBgXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LWRhbmdlclwiIHJvbGU9XCJhbGVydFwiPlxuICAgICAgICAgICAgICAgICAgICA8cCBjbGFzcz1cIm1iLTBcIj4ke1JzeC5fZXNjYXBlX2h0bWwobWVzc2FnZSl9PC9wPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgYDtcbiAgICAgICAgfVxuXG4gICAgICAgICRjb250YWluZXIuaHRtbChodG1sKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFc2NhcGUgSFRNTCB0byBwcmV2ZW50IFhTUyBpbiBlcnJvciBtZXNzYWdlc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9lc2NhcGVfaHRtbCh0ZXh0KSB7XG4gICAgICAgIGNvbnN0IGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICBkaXYudGV4dENvbnRlbnQgPSB0ZXh0O1xuICAgICAgICByZXR1cm4gZGl2LmlubmVySFRNTDtcbiAgICB9XG59XG4iLCIvLyBARklMRS1TVUJDTEFTUy0wMS1FWENFUFRJT05cblxuLyoqXG4gKiBDbGllbnQtc2lkZSBBamF4IGNsYXNzIGZvciBtYWtpbmcgQVBJIGNhbGxzIHRvIFJTWCBjb250cm9sbGVyc1xuICpcbiAqIEF1dG9tYXRpY2FsbHkgYmF0Y2hlcyBtdWx0aXBsZSBjYWxscyBpbnRvIHNpbmdsZSBIVFRQIHJlcXVlc3RzIHRvIHJlZHVjZSBuZXR3b3JrIG92ZXJoZWFkLlxuICogQmF0Y2hlcyB1cCB0byAyMCBjYWxscyBvciBmbHVzaGVzIGFmdGVyIHNldFRpbWVvdXQoMCkgZGVib3VuY2UuXG4gKi9cbmNsYXNzIEFqYXgge1xuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemUgQWpheCBzeXN0ZW1cbiAgICAgKiBDYWxsZWQgYXV0b21hdGljYWxseSB3aGVuIGNsYXNzIGlzIGxvYWRlZFxuICAgICAqL1xuICAgIHN0YXRpYyBfb25fZnJhbWV3b3JrX2NvcmVfaW5pdCgpIHtcbiAgICAgICAgLy8gUXVldWUgb2YgcGVuZGluZyBjYWxscyB3YWl0aW5nIHRvIGJlIGJhdGNoZWRcbiAgICAgICAgQWpheC5fcGVuZGluZ19jYWxscyA9IHt9O1xuXG4gICAgICAgIC8vIFRpbWVyIGZvciBiYXRjaGluZyBmbHVzaFxuICAgICAgICBBamF4Ll9mbHVzaF90aW1lb3V0ID0gbnVsbDtcblxuICAgICAgICAvLyBDYWxsIGNvdW50ZXIgZm9yIGdlbmVyYXRpbmcgdW5pcXVlIGNhbGwgSURzXG4gICAgICAgIEFqYXguX2NhbGxfY291bnRlciA9IDA7XG5cbiAgICAgICAgLy8gTWF4aW11bSBiYXRjaCBzaXplIGJlZm9yZSBmb3JjaW5nIGltbWVkaWF0ZSBmbHVzaFxuICAgICAgICBBamF4Lk1BWF9CQVRDSF9TSVpFID0gMjA7XG5cbiAgICAgICAgLy8gRGVib3VuY2UgdGltZSBpbiBtaWxsaXNlY29uZHNcbiAgICAgICAgQWpheC5ERUJPVU5DRV9NUyA9IDA7XG5cbiAgICAgICAgLy8gVHJhY2sgcHJvbWlzZXMgZnJvbSBBamF4IGNhbGxzIHRvIGRldGVjdCB1bmNhdWdodCByZWplY3Rpb25zXG4gICAgICAgIEFqYXguX3RyYWNrZWRfcHJvbWlzZXMgPSBuZXcgV2Vha1NldCgpO1xuXG4gICAgICAgIC8vIFNldCB1cCBnbG9iYWwgdW5oYW5kbGVkIHJlamVjdGlvbiBoYW5kbGVyIGZvciBBamF4IGVycm9yc1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigndW5oYW5kbGVkcmVqZWN0aW9uJywgYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAvLyBPbmx5IGhhbmRsZSByZWplY3Rpb25zIGZyb20gQWpheCBwcm9taXNlc1xuICAgICAgICAgICAgaWYgKEFqYXguX3RyYWNrZWRfcHJvbWlzZXMuaGFzKGV2ZW50LnByb21pc2UpKSB7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTsgLy8gUHJldmVudCBicm93c2VyJ3MgZGVmYXVsdCBcIlVuY2F1Z2h0IChpbiBwcm9taXNlKVwiIGVycm9yXG5cbiAgICAgICAgICAgICAgICBjb25zdCBlcnJvciA9IGV2ZW50LnJlYXNvbjtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdVbmNhdWdodCBBamF4IGVycm9yOicsIGVycm9yKTtcblxuICAgICAgICAgICAgICAgIC8vIFNob3cgTW9kYWwuZXJyb3IoKSBmb3IgdW5jYXVnaHQgQWpheCBlcnJvcnNcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIE1vZGFsICE9PSAndW5kZWZpbmVkJyAmJiBNb2RhbC5lcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBhd2FpdCBNb2RhbC5lcnJvcihlcnJvciwgJ1VuY2F1Z2h0IEFqYXggRXJyb3InKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1ha2UgYW4gQUpBWCBjYWxsIHRvIGFuIFJTWCBjb250cm9sbGVyIGFjdGlvblxuICAgICAqXG4gICAgICogQWxsIGNhbGxzIGFyZSBhdXRvbWF0aWNhbGx5IGJhdGNoZWQgdW5sZXNzIHdpbmRvdy5yc3hhcHAuYWpheF9kaXNhYmxlX2JhdGNoaW5nIGlzIHRydWUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ3xvYmplY3R8ZnVuY3Rpb259IHVybCAtIFRoZSBBamF4IFVSTCAoZS5nLiwgJy9fYWpheC9Db250cm9sbGVyX05hbWUvYWN0aW9uX25hbWUnKSBvciBhbiBvYmplY3QvZnVuY3Rpb24gd2l0aCBhIC5wYXRoIHByb3BlcnR5XG4gICAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtcyAtIFBhcmFtZXRlcnMgdG8gc2VuZCB0byB0aGUgYWN0aW9uXG4gICAgICogQHJldHVybnMge1Byb21pc2V9IC0gUmVzb2x2ZXMgd2l0aCB0aGUgcmV0dXJuIHZhbHVlLCByZWplY3RzIHdpdGggZXJyb3JcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgY2FsbCh1cmwsIHBhcmFtcyA9IHt9KSB7XG4gICAgICAgIC8vIElmIHVybCBpcyBhbiBvYmplY3Qgb3IgZnVuY3Rpb24gd2l0aCBhIC5wYXRoIHByb3BlcnR5LCB1c2UgdGhhdCBhcyB0aGUgVVJMXG4gICAgICAgIGlmICh1cmwgJiYgdHlwZW9mIHVybCA9PT0gJ29iamVjdCcgJiYgdXJsLnBhdGgpIHtcbiAgICAgICAgICAgIHVybCA9IHVybC5wYXRoO1xuICAgICAgICB9IGVsc2UgaWYgKHVybCAmJiB0eXBlb2YgdXJsID09PSAnZnVuY3Rpb24nICYmIHVybC5wYXRoKSB7XG4gICAgICAgICAgICB1cmwgPSB1cmwucGF0aDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFZhbGlkYXRlIHVybCBpcyBhIG5vbi1lbXB0eSBzdHJpbmdcbiAgICAgICAgaWYgKHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnIHx8IHVybC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQWpheC5jYWxsKCkgcmVxdWlyZXMgYSBub24tZW1wdHkgc3RyaW5nIFVSTCBvciBhbiBvYmplY3QvZnVuY3Rpb24gd2l0aCBhIC5wYXRoIHByb3BlcnR5Jyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFeHRyYWN0IGNvbnRyb2xsZXIgYW5kIGFjdGlvbiBmcm9tIFVSTFxuICAgICAgICBjb25zdCB7IGNvbnRyb2xsZXIsIGFjdGlvbiB9ID0gQWpheC5hamF4X3VybF90b19jb250cm9sbGVyX2FjdGlvbih1cmwpO1xuXG4gICAgICAgIGNvbnNvbGUubG9nKCdBamF4OicsIGNvbnRyb2xsZXIsIGFjdGlvbiwgcGFyYW1zKTtcblxuICAgICAgICAvLyBDaGVjayBpZiBiYXRjaGluZyBpcyBkaXNhYmxlZCBmb3IgZGVidWdnaW5nXG4gICAgICAgIGxldCBwcm9taXNlO1xuICAgICAgICBpZiAod2luZG93LnJzeGFwcCAmJiB3aW5kb3cucnN4YXBwLmFqYXhfZGlzYWJsZV9iYXRjaGluZykge1xuICAgICAgICAgICAgcHJvbWlzZSA9IEFqYXguX2NhbGxfZGlyZWN0KGNvbnRyb2xsZXIsIGFjdGlvbiwgcGFyYW1zKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHByb21pc2UgPSBBamF4Ll9jYWxsX2JhdGNoKGNvbnRyb2xsZXIsIGFjdGlvbiwgcGFyYW1zKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRyYWNrIHRoaXMgcHJvbWlzZSBmb3IgdW5oYW5kbGVkIHJlamVjdGlvbiBkZXRlY3Rpb25cbiAgICAgICAgQWpheC5fdHJhY2tlZF9wcm9taXNlcy5hZGQocHJvbWlzZSk7XG5cbiAgICAgICAgcmV0dXJuIHByb21pc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFrZSBhIGJhdGNoZWQgQWpheCBjYWxsXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX2NhbGxfYmF0Y2goY29udHJvbGxlciwgYWN0aW9uLCBwYXJhbXMgPSB7fSkge1xuICAgICAgICBjb25zb2xlLmxvZygnQWpheCBCYXRjaDonLCBjb250cm9sbGVyLCBhY3Rpb24sIHBhcmFtcyk7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIC8vIEdlbmVyYXRlIGNhbGwga2V5IGZvciBkZWR1cGxpY2F0aW9uXG4gICAgICAgICAgICBjb25zdCBjYWxsX2tleSA9IEFqYXguX2dlbmVyYXRlX2NhbGxfa2V5KGNvbnRyb2xsZXIsIGFjdGlvbiwgcGFyYW1zKTtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhpcyBleGFjdCBjYWxsIGlzIGFscmVhZHkgcGVuZGluZ1xuICAgICAgICAgICAgaWYgKEFqYXguX3BlbmRpbmdfY2FsbHNbY2FsbF9rZXldKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXhpc3RpbmdfY2FsbCA9IEFqYXguX3BlbmRpbmdfY2FsbHNbY2FsbF9rZXldO1xuXG4gICAgICAgICAgICAgICAgLy8gSWYgY2FsbCBhbHJlYWR5IGNvbXBsZXRlZCAoY2FjaGVkKSwgcmV0dXJuIGltbWVkaWF0ZWx5XG4gICAgICAgICAgICAgICAgaWYgKGV4aXN0aW5nX2NhbGwuaXNfY29tcGxldGUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGV4aXN0aW5nX2NhbGwuaXNfZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdChleGlzdGluZ19jYWxsLmVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoZXhpc3RpbmdfY2FsbC5yZXN1bHQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBDYWxsIGlzIHBlbmRpbmcsIGFkZCB0aGlzIHByb21pc2UgdG8gY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgZXhpc3RpbmdfY2FsbC5jYWxsYmFja3MucHVzaCh7IHJlc29sdmUsIHJlamVjdCB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENyZWF0ZSBuZXcgcGVuZGluZyBjYWxsXG4gICAgICAgICAgICBjb25zdCBjYWxsX2lkID0gQWpheC5fY2FsbF9jb3VudGVyKys7XG4gICAgICAgICAgICBjb25zdCBwZW5kaW5nX2NhbGwgPSB7XG4gICAgICAgICAgICAgICAgY2FsbF9pZDogY2FsbF9pZCxcbiAgICAgICAgICAgICAgICBjYWxsX2tleTogY2FsbF9rZXksXG4gICAgICAgICAgICAgICAgY29udHJvbGxlcjogY29udHJvbGxlcixcbiAgICAgICAgICAgICAgICBhY3Rpb246IGFjdGlvbixcbiAgICAgICAgICAgICAgICBwYXJhbXM6IHBhcmFtcyxcbiAgICAgICAgICAgICAgICBjYWxsYmFja3M6IFt7IHJlc29sdmUsIHJlamVjdCB9XSxcbiAgICAgICAgICAgICAgICBpc19jb21wbGV0ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgaXNfZXJyb3I6IGZhbHNlLFxuICAgICAgICAgICAgICAgIHJlc3VsdDogbnVsbCxcbiAgICAgICAgICAgICAgICBlcnJvcjogbnVsbCxcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8vIEFkZCB0byBwZW5kaW5nIHF1ZXVlXG4gICAgICAgICAgICBBamF4Ll9wZW5kaW5nX2NhbGxzW2NhbGxfa2V5XSA9IHBlbmRpbmdfY2FsbDtcblxuICAgICAgICAgICAgLy8gQ291bnQgcGVuZGluZyBjYWxsc1xuICAgICAgICAgICAgY29uc3QgcGVuZGluZ19jb3VudCA9IE9iamVjdC5rZXlzKEFqYXguX3BlbmRpbmdfY2FsbHMpLmZpbHRlcigoa2V5KSA9PiAhQWpheC5fcGVuZGluZ19jYWxsc1trZXldLmlzX2NvbXBsZXRlKS5sZW5ndGg7XG5cbiAgICAgICAgICAgIC8vIElmIHdlJ3ZlIGhpdCB0aGUgYmF0Y2ggc2l6ZSBsaW1pdCwgZmx1c2ggaW1tZWRpYXRlbHlcbiAgICAgICAgICAgIGlmIChwZW5kaW5nX2NvdW50ID49IEFqYXguTUFYX0JBVENIX1NJWkUpIHtcbiAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQoQWpheC5fZmx1c2hfdGltZW91dCk7XG4gICAgICAgICAgICAgICAgQWpheC5fZmx1c2hfdGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICAgICAgQWpheC5fZmx1c2hfcGVuZGluZ19jYWxscygpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBTY2hlZHVsZSBiYXRjaCBmbHVzaCB3aXRoIGRlYm91bmNlXG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KEFqYXguX2ZsdXNoX3RpbWVvdXQpO1xuICAgICAgICAgICAgICAgIEFqYXguX2ZsdXNoX3RpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgQWpheC5fZmx1c2hfcGVuZGluZ19jYWxscygpO1xuICAgICAgICAgICAgICAgIH0sIEFqYXguREVCT1VOQ0VfTVMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNYWtlIGEgZGlyZWN0IChub24tYmF0Y2hlZCkgQWpheCBjYWxsXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgX2NhbGxfZGlyZWN0KGNvbnRyb2xsZXIsIGFjdGlvbiwgcGFyYW1zID0ge30pIHtcbiAgICAgICAgLy8gQ29uc3RydWN0IFVSTCBmcm9tIGNvbnRyb2xsZXIgYW5kIGFjdGlvblxuICAgICAgICBjb25zdCB1cmwgPSBgL19hamF4LyR7Y29udHJvbGxlcn0vJHthY3Rpb259YDtcblxuICAgICAgICAvLyBMb2cgdGhlIEFKQVggY2FsbCB1c2luZyBjb25zb2xlX2RlYnVnXG4gICAgICAgIGlmICh0eXBlb2YgRGVidWdnZXIgIT09ICd1bmRlZmluZWQnICYmIERlYnVnZ2VyLmNvbnNvbGVfZGVidWcpIHtcbiAgICAgICAgICAgIERlYnVnZ2VyLmNvbnNvbGVfZGVidWcoJ0FKQVgnLCBgQ2FsbGluZyAke2NvbnRyb2xsZXJ9LiR7YWN0aW9ufSAodW5iYXRjaGVkKWAsIHBhcmFtcyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgJC5hamF4KHtcbiAgICAgICAgICAgICAgICB1cmw6IHVybCxcbiAgICAgICAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICAgICAgICBkYXRhOiBwYXJhbXMsXG4gICAgICAgICAgICAgICAgZGF0YVR5cGU6ICdqc29uJyxcbiAgICAgICAgICAgICAgICBfX2xvY2FsX2ludGVncmF0aW9uOiB0cnVlLCAvLyBCeXBhc3MgJC5hamF4IG92ZXJyaWRlXG4gICAgICAgICAgICAgICAgc3VjY2VzczogKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEhhbmRsZSBjb25zb2xlX2RlYnVnIG1lc3NhZ2VzXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5jb25zb2xlX2RlYnVnICYmIEFycmF5LmlzQXJyYXkocmVzcG9uc2UuY29uc29sZV9kZWJ1ZykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlLmNvbnNvbGVfZGVidWcuZm9yRWFjaCgobXNnKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KG1zZykgfHwgbXNnLmxlbmd0aCAhPT0gMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29uc29sZV9kZWJ1ZyBtZXNzYWdlIGZvcm1hdCAtIGV4cGVjdGVkIFtjaGFubmVsLCBbYXJndW1lbnRzXV0nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgW2NoYW5uZWwsIGFyZ3NdID0gbXNnO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGNoYW5uZWwsIC4uLmFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgcmVzcG9uc2Ugd2FzIHN1Y2Nlc3NmdWxcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlLl9zdWNjZXNzID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBASlMtQUpBWC0wMi1FWENFUFRJT04gLSBVbndyYXAgc2VydmVyIHJlc3BvbnNlcyB3aXRoIF9hamF4X3JldHVybl92YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcHJvY2Vzc2VkX3ZhbHVlID0gUnN4X0pzX01vZGVsLl9pbnN0YW50aWF0ZV9tb2RlbHNfcmVjdXJzaXZlKHJlc3BvbnNlLl9hamF4X3JldHVybl92YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKHByb2Nlc3NlZF92YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgZXJyb3IgcmVzcG9uc2VzXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBlcnJvcl90eXBlID0gcmVzcG9uc2UuZXJyb3JfdHlwZSB8fCAndW5rbm93bl9lcnJvcic7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByZWFzb24gPSByZXNwb25zZS5yZWFzb24gfHwgJ1Vua25vd24gZXJyb3Igb2NjdXJyZWQnO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZGV0YWlscyA9IHJlc3BvbnNlLmRldGFpbHMgfHwge307XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEhhbmRsZSBzcGVjaWZpYyBlcnJvciB0eXBlc1xuICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChlcnJvcl90eXBlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnZmF0YWwnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGYXRhbCBQSFAgZXJyb3Igd2l0aCBmdWxsIGVycm9yIGRldGFpbHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZmF0YWxfZXJyb3JfZGF0YSA9IHJlc3BvbnNlLmVycm9yIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBlcnJvcl9tZXNzYWdlID0gZmF0YWxfZXJyb3JfZGF0YS5lcnJvciB8fCAnRmF0YWwgZXJyb3Igb2NjdXJyZWQnO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0FqYXggZXJyb3IgcmVzcG9uc2UgZnJvbSBzZXJ2ZXI6JywgcmVzcG9uc2UuZXJyb3IpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZhdGFsX2Vycm9yID0gbmV3IEVycm9yKGVycm9yX21lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYXRhbF9lcnJvci50eXBlID0gJ2ZhdGFsJztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmF0YWxfZXJyb3IuZGV0YWlscyA9IHJlc3BvbnNlLmVycm9yO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvZyB0byBzZXJ2ZXIgaWYgYnJvd3NlciBlcnJvciBsb2dnaW5nIGlzIGVuYWJsZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVidWdnZXIubG9nX2Vycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBBamF4IEZhdGFsIEVycm9yOiAke2Vycm9yX21lc3NhZ2V9YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdhamF4X2ZhdGFsJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZHBvaW50OiB1cmwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXRhaWxzOiByZXNwb25zZS5lcnJvcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGZhdGFsX2Vycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdyZXNwb25zZV9hdXRoX3JlcXVpcmVkJzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUaGUgdXNlciBpcyBubyBsb25nZXIgYXV0aGVudGljYXRlZCwgdGhpcyBpcyBhIHBsYWNlaG9sZGVyIGZvciBmdXR1cmUgY29kZSB3aGljaCBoYW5kbGVzIHRoaXMgc2NlbmFyaW8uJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBhdXRoX2Vycm9yID0gbmV3IEVycm9yKHJlYXNvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dGhfZXJyb3IudHlwZSA9ICdhdXRoX3JlcXVpcmVkJztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0aF9lcnJvci5kZXRhaWxzID0gZGV0YWlscztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGF1dGhfZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3Jlc3BvbnNlX3VuYXV0aG9yaXplZCc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVGhlIHVzZXIgaXMgdW5hdXRob3JpemVkIHRvIHBlcmZvcm0gdGhpcyBhY3Rpb24sIHRoaXMgaXMgYSBwbGFjZWhvbGRlciBmb3IgZnV0dXJlIGNvZGUgd2hpY2ggaGFuZGxlcyB0aGlzIHNjZW5hcmlvLidcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdW5hdXRoX2Vycm9yID0gbmV3IEVycm9yKHJlYXNvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuYXV0aF9lcnJvci50eXBlID0gJ3VuYXV0aG9yaXplZCc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuYXV0aF9lcnJvci5kZXRhaWxzID0gZGV0YWlscztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KHVuYXV0aF9lcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAncmVzcG9uc2VfZm9ybV9lcnJvcic6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZvcm1fZXJyb3IgPSBuZXcgRXJyb3IocmVhc29uKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybV9lcnJvci50eXBlID0gJ2Zvcm1fZXJyb3InO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtX2Vycm9yLmRldGFpbHMgPSBkZXRhaWxzO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZm9ybV9lcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZ2VuZXJpY19lcnJvciA9IG5ldyBFcnJvcihyZWFzb24pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lcmljX2Vycm9yLnR5cGUgPSBlcnJvcl90eXBlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lcmljX2Vycm9yLmRldGFpbHMgPSBkZXRhaWxzO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZ2VuZXJpY19lcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBlcnJvcjogKHhociwgc3RhdHVzLCBlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlcnJvcl9tZXNzYWdlID0gQWpheC5fZXh0cmFjdF9lcnJvcl9tZXNzYWdlKHhocik7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG5ldHdvcmtfZXJyb3IgPSBuZXcgRXJyb3IoZXJyb3JfbWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAgIG5ldHdvcmtfZXJyb3IudHlwZSA9ICduZXR3b3JrX2Vycm9yJztcbiAgICAgICAgICAgICAgICAgICAgbmV0d29ya19lcnJvci5zdGF0dXMgPSB4aHIuc3RhdHVzO1xuICAgICAgICAgICAgICAgICAgICBuZXR3b3JrX2Vycm9yLnN0YXR1c1RleHQgPSBzdGF0dXM7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gTG9nIHNlcnZlciBlcnJvcnMgKDUwMCspIHRvIHRoZSBzZXJ2ZXIgaWYgYnJvd3NlciBlcnJvciBsb2dnaW5nIGlzIGVuYWJsZWRcbiAgICAgICAgICAgICAgICAgICAgaWYgKHhoci5zdGF0dXMgPj0gNTAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBEZWJ1Z2dlci5sb2dfZXJyb3Ioe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBBamF4IFNlcnZlciBFcnJvciAke3hoci5zdGF0dXN9OiAke2Vycm9yX21lc3NhZ2V9YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnYWpheF9zZXJ2ZXJfZXJyb3InLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZHBvaW50OiB1cmwsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzOiB4aHIuc3RhdHVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1c1RleHQ6IHN0YXR1cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KG5ldHdvcmtfZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmx1c2ggYWxsIHBlbmRpbmcgY2FsbHMgYnkgc2VuZGluZyBiYXRjaCByZXF1ZXN0XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgX2ZsdXNoX3BlbmRpbmdfY2FsbHMoKSB7XG4gICAgICAgIC8vIENvbGxlY3QgYWxsIHBlbmRpbmcgY2FsbHNcbiAgICAgICAgY29uc3QgY2FsbHNfdG9fc2VuZCA9IFtdO1xuICAgICAgICBjb25zdCBjYWxsX21hcCA9IHt9OyAvLyBNYXAgY2FsbF9pZCB0byBwZW5kaW5nX2NhbGwgb2JqZWN0XG5cbiAgICAgICAgZm9yIChjb25zdCBjYWxsX2tleSBpbiBBamF4Ll9wZW5kaW5nX2NhbGxzKSB7XG4gICAgICAgICAgICBjb25zdCBwZW5kaW5nX2NhbGwgPSBBamF4Ll9wZW5kaW5nX2NhbGxzW2NhbGxfa2V5XTtcblxuICAgICAgICAgICAgaWYgKCFwZW5kaW5nX2NhbGwuaXNfY29tcGxldGUpIHtcbiAgICAgICAgICAgICAgICBjYWxsc190b19zZW5kLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBjYWxsX2lkOiBwZW5kaW5nX2NhbGwuY2FsbF9pZCxcbiAgICAgICAgICAgICAgICAgICAgY29udHJvbGxlcjogcGVuZGluZ19jYWxsLmNvbnRyb2xsZXIsXG4gICAgICAgICAgICAgICAgICAgIGFjdGlvbjogcGVuZGluZ19jYWxsLmFjdGlvbixcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1zOiBwZW5kaW5nX2NhbGwucGFyYW1zLFxuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgY2FsbF9tYXBbcGVuZGluZ19jYWxsLmNhbGxfaWRdID0gcGVuZGluZ19jYWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gTm90aGluZyB0byBzZW5kXG4gICAgICAgIGlmIChjYWxsc190b19zZW5kLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTG9nIGJhdGNoIGZvciBkZWJ1Z2dpbmdcbiAgICAgICAgaWYgKHR5cGVvZiBEZWJ1Z2dlciAhPT0gJ3VuZGVmaW5lZCcgJiYgRGVidWdnZXIuY29uc29sZV9kZWJ1Zykge1xuICAgICAgICAgICAgRGVidWdnZXIuY29uc29sZV9kZWJ1ZyhcbiAgICAgICAgICAgICAgICAnQUpBWF9CQVRDSCcsXG4gICAgICAgICAgICAgICAgYFNlbmRpbmcgYmF0Y2ggb2YgJHtjYWxsc190b19zZW5kLmxlbmd0aH0gY2FsbHNgLFxuICAgICAgICAgICAgICAgIGNhbGxzX3RvX3NlbmQubWFwKChjKSA9PiBgJHtjLmNvbnRyb2xsZXJ9LiR7Yy5hY3Rpb259YClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gU2VuZCBiYXRjaCByZXF1ZXN0XG4gICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0ICQuYWpheCh7XG4gICAgICAgICAgICAgICAgdXJsOiAnL19hamF4L19iYXRjaCcsXG4gICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgZGF0YTogeyBiYXRjaF9jYWxsczogSlNPTi5zdHJpbmdpZnkoY2FsbHNfdG9fc2VuZCkgfSxcbiAgICAgICAgICAgICAgICBkYXRhVHlwZTogJ2pzb24nLFxuICAgICAgICAgICAgICAgIF9fbG9jYWxfaW50ZWdyYXRpb246IHRydWUsIC8vIEJ5cGFzcyAkLmFqYXggb3ZlcnJpZGVcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBQcm9jZXNzIGJhdGNoIHJlc3BvbnNlXG4gICAgICAgICAgICAvLyBSZXNwb25zZSBmb3JtYXQ6IHsgQ18wOiB7c3VjY2VzcywgX2FqYXhfcmV0dXJuX3ZhbHVlfSwgQ18xOiB7Li4ufSwgLi4uIH1cbiAgICAgICAgICAgIGZvciAoY29uc3QgcmVzcG9uc2Vfa2V5IGluIHJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFyZXNwb25zZV9rZXkuc3RhcnRzV2l0aCgnQ18nKSkge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjb25zdCBjYWxsX2lkID0gcGFyc2VJbnQocmVzcG9uc2Vfa2V5LnN1YnN0cmluZygyKSwgMTApO1xuICAgICAgICAgICAgICAgIGNvbnN0IGNhbGxfcmVzcG9uc2UgPSByZXNwb25zZVtyZXNwb25zZV9rZXldO1xuICAgICAgICAgICAgICAgIGNvbnN0IHBlbmRpbmdfY2FsbCA9IGNhbGxfbWFwW2NhbGxfaWRdO1xuXG4gICAgICAgICAgICAgICAgaWYgKCFwZW5kaW5nX2NhbGwpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignUmVjZWl2ZWQgcmVzcG9uc2UgZm9yIHVua25vd24gY2FsbF9pZDonLCBjYWxsX2lkKTtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gSGFuZGxlIGNvbnNvbGVfZGVidWcgbWVzc2FnZXMgaWYgcHJlc2VudFxuICAgICAgICAgICAgICAgIGlmIChjYWxsX3Jlc3BvbnNlLmNvbnNvbGVfZGVidWcgJiYgQXJyYXkuaXNBcnJheShjYWxsX3Jlc3BvbnNlLmNvbnNvbGVfZGVidWcpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxfcmVzcG9uc2UuY29uc29sZV9kZWJ1Zy5mb3JFYWNoKChtc2cpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheShtc2cpIHx8IG1zZy5sZW5ndGggIT09IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29uc29sZV9kZWJ1ZyBtZXNzYWdlIGZvcm1hdCAtIGV4cGVjdGVkIFtjaGFubmVsLCBbYXJndW1lbnRzXV0nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjaGFubmVsLCBhcmdzXSA9IG1zZztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGNoYW5uZWwsIC4uLmFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBNYXJrIGNhbGwgYXMgY29tcGxldGVcbiAgICAgICAgICAgICAgICBwZW5kaW5nX2NhbGwuaXNfY29tcGxldGUgPSB0cnVlO1xuXG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgc3VjY2Vzc2Z1bFxuICAgICAgICAgICAgICAgIGlmIChjYWxsX3Jlc3BvbnNlLl9zdWNjZXNzID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEBKUy1BSkFYLTAyLUVYQ0VQVElPTiAtIEJhdGNoIHN5c3RlbSB1bndyYXBzIHNlcnZlciByZXNwb25zZXMgd2l0aCBfYWpheF9yZXR1cm5fdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcHJvY2Vzc2VkX3ZhbHVlID0gUnN4X0pzX01vZGVsLl9pbnN0YW50aWF0ZV9tb2RlbHNfcmVjdXJzaXZlKGNhbGxfcmVzcG9uc2UuX2FqYXhfcmV0dXJuX3ZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLnJlc3VsdCA9IHByb2Nlc3NlZF92YWx1ZTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBSZXNvbHZlIGFsbCBjYWxsYmFja3NcbiAgICAgICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmNhbGxiYWNrcy5mb3JFYWNoKCh7IHJlc29sdmUgfSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShwcm9jZXNzZWRfdmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgZXJyb3JcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JfdHlwZSA9IGNhbGxfcmVzcG9uc2UuZXJyb3JfdHlwZSB8fCAndW5rbm93bl9lcnJvcic7XG4gICAgICAgICAgICAgICAgICAgIGxldCBlcnJvcl9tZXNzYWdlO1xuICAgICAgICAgICAgICAgICAgICBsZXQgZXJyb3JfZGV0YWlscztcblxuICAgICAgICAgICAgICAgICAgICBpZiAoZXJyb3JfdHlwZSA9PT0gJ2ZhdGFsJyAmJiBjYWxsX3Jlc3BvbnNlLmVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBGYXRhbCBQSFAgZXJyb3Igd2l0aCBmdWxsIGVycm9yIGRldGFpbHNcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZhdGFsX2Vycm9yX2RhdGEgPSBjYWxsX3Jlc3BvbnNlLmVycm9yO1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfbWVzc2FnZSA9IGZhdGFsX2Vycm9yX2RhdGEuZXJyb3IgfHwgJ0ZhdGFsIGVycm9yIG9jY3VycmVkJztcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX2RldGFpbHMgPSBjYWxsX3Jlc3BvbnNlLmVycm9yO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdBamF4IGVycm9yIHJlc3BvbnNlIGZyb20gc2VydmVyOicsIGNhbGxfcmVzcG9uc2UuZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gT3RoZXIgZXJyb3IgdHlwZXNcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2UgPSBjYWxsX3Jlc3BvbnNlLnJlYXNvbiB8fCAnVW5rbm93biBlcnJvciBvY2N1cnJlZCc7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9kZXRhaWxzID0gY2FsbF9yZXNwb25zZS5kZXRhaWxzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3IoZXJyb3JfbWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yLnR5cGUgPSBlcnJvcl90eXBlO1xuICAgICAgICAgICAgICAgICAgICBlcnJvci5kZXRhaWxzID0gZXJyb3JfZGV0YWlscztcblxuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nX2NhbGwuaXNfZXJyb3IgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nX2NhbGwuZXJyb3IgPSBlcnJvcjtcblxuICAgICAgICAgICAgICAgICAgICAvLyBSZWplY3QgYWxsIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgICAgICBwZW5kaW5nX2NhbGwuY2FsbGJhY2tzLmZvckVhY2goKHsgcmVqZWN0IH0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoeGhyX2Vycm9yKSB7XG4gICAgICAgICAgICAvLyBOZXR3b3JrIG9yIHNlcnZlciBlcnJvciAtIHJlamVjdCBhbGwgcGVuZGluZyBjYWxsc1xuICAgICAgICAgICAgY29uc3QgZXJyb3JfbWVzc2FnZSA9IEFqYXguX2V4dHJhY3RfZXJyb3JfbWVzc2FnZSh4aHJfZXJyb3IpO1xuICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3IoZXJyb3JfbWVzc2FnZSk7XG4gICAgICAgICAgICBlcnJvci50eXBlID0gJ25ldHdvcmtfZXJyb3InO1xuXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGNhbGxfaWQgaW4gY2FsbF9tYXApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBwZW5kaW5nX2NhbGwgPSBjYWxsX21hcFtjYWxsX2lkXTtcbiAgICAgICAgICAgICAgICBwZW5kaW5nX2NhbGwuaXNfY29tcGxldGUgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHBlbmRpbmdfY2FsbC5pc19lcnJvciA9IHRydWU7XG4gICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmVycm9yID0gZXJyb3I7XG5cbiAgICAgICAgICAgICAgICBwZW5kaW5nX2NhbGwuY2FsbGJhY2tzLmZvckVhY2goKHsgcmVqZWN0IH0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc29sZS5lcnJvcignQmF0Y2ggQWpheCByZXF1ZXN0IGZhaWxlZDonLCBlcnJvcl9tZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdlbmVyYXRlIGEgdW5pcXVlIGtleSBmb3IgZGVkdXBsaWNhdGluZyBjYWxsc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9nZW5lcmF0ZV9jYWxsX2tleShjb250cm9sbGVyLCBhY3Rpb24sIHBhcmFtcykge1xuICAgICAgICAvLyBDcmVhdGUgYSBzdGFibGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjYWxsXG4gICAgICAgIC8vIFNvcnQgcGFyYW1zIGtleXMgZm9yIGNvbnNpc3RlbnQgaGFzaGluZ1xuICAgICAgICBjb25zdCBzb3J0ZWRfcGFyYW1zID0ge307XG4gICAgICAgIE9iamVjdC5rZXlzKHBhcmFtcylcbiAgICAgICAgICAgIC5zb3J0KClcbiAgICAgICAgICAgIC5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgICAgICAgICAgICBzb3J0ZWRfcGFyYW1zW2tleV0gPSBwYXJhbXNba2V5XTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBgJHtjb250cm9sbGVyfTo6JHthY3Rpb259Ojoke0pTT04uc3RyaW5naWZ5KHNvcnRlZF9wYXJhbXMpfWA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXh0cmFjdCBlcnJvciBtZXNzYWdlIGZyb20galF1ZXJ5IFhIUiBvYmplY3RcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfZXh0cmFjdF9lcnJvcl9tZXNzYWdlKHhocikge1xuICAgICAgICBpZiAoeGhyLnJlc3BvbnNlSlNPTiAmJiB4aHIucmVzcG9uc2VKU09OLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgIHJldHVybiB4aHIucmVzcG9uc2VKU09OLm1lc3NhZ2U7XG4gICAgICAgIH0gZWxzZSBpZiAoeGhyLnJlc3BvbnNlVGV4dCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IEpTT04ucGFyc2UoeGhyLnJlc3BvbnNlVGV4dCk7XG4gICAgICAgICAgICAgICAgaWYgKHJlc3BvbnNlLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLm1lc3NhZ2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIC8vIE5vdCBKU09OXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYCR7eGhyLnN0YXR1c306ICR7eGhyLnN0YXR1c1RleHQgfHwgJ1Vua25vd24gZXJyb3InfWA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGFyc2VzIGFuIEFKQVggVVJMIGludG8gY29udHJvbGxlciBhbmQgYWN0aW9uXG4gICAgICogU3VwcG9ydHMgYm90aCAvX2FqYXgvIGFuZCAvXy8gVVJMIHByZWZpeGVzXG4gICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fGZ1bmN0aW9ufSB1cmwgLSBVUkwgaW4gZm9ybWF0ICcvX2FqYXgvQ29udHJvbGxlcl9OYW1lL2FjdGlvbl9uYW1lJyBvciAnL18vQ29udHJvbGxlcl9OYW1lL2FjdGlvbl9uYW1lJywgb3IgYW4gb2JqZWN0L2Z1bmN0aW9uIHdpdGggYSAucGF0aCBwcm9wZXJ0eVxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IE9iamVjdCB3aXRoIHtjb250cm9sbGVyOiBzdHJpbmcsIGFjdGlvbjogc3RyaW5nfVxuICAgICAqIEB0aHJvd3Mge0Vycm9yfSBJZiBVUkwgZG9lc24ndCBzdGFydCB3aXRoIC9fYWpheCBvciAvXyBvciBoYXMgaW52YWxpZCBzdHJ1Y3R1cmVcbiAgICAgKi9cbiAgICBzdGF0aWMgYWpheF91cmxfdG9fY29udHJvbGxlcl9hY3Rpb24odXJsKSB7XG4gICAgICAgIC8vIElmIHVybCBpcyBhbiBvYmplY3Qgb3IgZnVuY3Rpb24gd2l0aCBhIC5wYXRoIHByb3BlcnR5LCB1c2UgdGhhdCBhcyB0aGUgVVJMXG4gICAgICAgIGlmICh1cmwgJiYgdHlwZW9mIHVybCA9PT0gJ29iamVjdCcgJiYgdXJsLnBhdGgpIHtcbiAgICAgICAgICAgIHVybCA9IHVybC5wYXRoO1xuICAgICAgICB9IGVsc2UgaWYgKHVybCAmJiB0eXBlb2YgdXJsID09PSAnZnVuY3Rpb24nICYmIHVybC5wYXRoKSB7XG4gICAgICAgICAgICB1cmwgPSB1cmwucGF0aDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFZhbGlkYXRlIHVybCBpcyBhIHN0cmluZ1xuICAgICAgICBpZiAodHlwZW9mIHVybCAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVVJMIG11c3QgYmUgYSBzdHJpbmcgb3IgaGF2ZSBhIC5wYXRoIHByb3BlcnR5LCBnb3Q6ICR7dHlwZW9mIHVybH1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdXJsLnN0YXJ0c1dpdGgoJy9fYWpheCcpICYmICF1cmwuc3RhcnRzV2l0aCgnL18vJykpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVVJMIG11c3Qgc3RhcnQgd2l0aCAvX2FqYXggb3IgL18sIGdvdDogJHt1cmx9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwYXJ0cyA9IHVybC5zcGxpdCgnLycpLmZpbHRlcigocGFydCkgPT4gcGFydCAhPT0gJycpO1xuXG4gICAgICAgIGlmIChwYXJ0cy5sZW5ndGggPCAyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgQUpBWCBVUkwgc3RydWN0dXJlOiAke3VybH1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwYXJ0cy5sZW5ndGggPiAzKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEFKQVggVVJMIGhhcyB0b28gbWFueSBzZWdtZW50czogJHt1cmx9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjb250cm9sbGVyID0gcGFydHNbMV07XG4gICAgICAgIGNvbnN0IGFjdGlvbiA9IHBhcnRzWzJdIHx8ICdpbmRleCc7XG5cbiAgICAgICAgcmV0dXJuIHsgY29udHJvbGxlciwgYWN0aW9uIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQXV0by1pbml0aWFsaXplIHN0YXRpYyBwcm9wZXJ0aWVzIHdoZW4gY2xhc3MgaXMgZmlyc3QgbG9hZGVkXG4gICAgICovXG4gICAgc3RhdGljIG9uX2NvcmVfZGVmaW5lKCkge1xuICAgICAgICBBamF4Ll9vbl9mcmFtZXdvcmtfY29yZV9pbml0KCk7XG4gICAgfVxufVxuIiwiLyoqXG4gKiBKcWh0bWxfQ29tcG9uZW50IC0gQmFzZSBjbGFzcyBmb3IgSlFIVE1MIGNvbXBvbmVudHMgaW4gUlNYIGZyYW1ld29ya1xuICpcbiAqIFRoaXMgY2xhc3Mgd3JhcHMgdGhlIGpxaHRtbC5Db21wb25lbnQgZnJvbSB0aGUgbnBtIHBhY2thZ2UgYW5kIHByb3ZpZGVzXG4gKiB0aGUgc3RhbmRhcmQgaW50ZXJmYWNlIGZvciBSU1ggY29tcG9uZW50cyBmb2xsb3dpbmcgdGhlIFVwcGVyX0Nhc2UgbmFtaW5nIGNvbnZlbnRpb24uXG4gKlxuICogX0Jhc2VfSnFodG1sX0NvbXBvbmVudCBpcyBpbXBvcnRlZCBmcm9tIG5wbSB2aWEgSnFodG1sX0J1bmRsZS5cbiAqXG4gKiBASW5zdGFudGlhdGFibGVcbiAqL1xuY2xhc3MgSnFodG1sX0NvbXBvbmVudCBleHRlbmRzIF9CYXNlX0pxaHRtbF9Db21wb25lbnQge31cblxuLy8gUlNYIG1hbmlmZXN0IGF1dG9tYXRpY2FsbHkgbWFrZXMgY2xhc3NlcyBnbG9iYWwgLSBubyBtYW51YWwgYXNzaWdubWVudCBuZWVkZWRcbiIsIi8qKlxuICogSlFIVE1MIEludGVncmF0aW9uIC0gQXV0b21hdGljIGNvbXBvbmVudCByZWdpc3RyYXRpb24gYW5kIGJpbmRpbmdcbiAqXG4gKiBUaGlzIG1vZHVsZSBhdXRvbWF0aWNhbGx5OlxuICogMS4gUmVnaXN0ZXJzIGNvbXBvbmVudCBjbGFzc2VzIHRoYXQgZXh0ZW5kIEpxaHRtbF9Db21wb25lbnRcbiAqIDIuIEJpbmRzIHRlbXBsYXRlcyB0byBjb21wb25lbnQgY2xhc3NlcyB3aGVuIG5hbWVzIG1hdGNoXG4gKiAzLiBFbmFibGVzICQoc2VsZWN0b3IpLmNvbXBvbmVudChcIkNvbXBvbmVudF9OYW1lXCIpIHN5bnRheFxuICovXG5jbGFzcyBKcWh0bWxfSW50ZWdyYXRpb24ge1xuICAgIC8qKlxuICAgICAqIENvbXBpbGVkIEpxaHRtbCB0ZW1wbGF0ZXMgc2VsZi1yZWdpc3Rlci4gIFRoZSBkZXZlbG9wZXIgKHRoZSBmcmFtZXdvcmsgaW4gdGhpcyBjYXNlKSBpcyBzdGlsbFxuICAgICAqIHJlc3BvbnNpYmxlIGZvciByZWdpc3RlcmluZyBlczYgY29tcG9uZW50IGNsYXNzZXMgd2l0aCBqcWh0bWwuICBUaGlzIGRvZXMgc28gYXQgYW4gZWFybHkgc3RhZ2VcbiAgICAgKiBvZiBmcmFtZXdvcmsgaW5pdC5cbiAgICAgKi9cbiAgICBzdGF0aWMgX29uX2ZyYW1ld29ya19tb2R1bGVzX2RlZmluZSgpIHtcbiAgICAgICAgbGV0IGpxaHRtbF9jb21wb25lbnRzID0gTWFuaWZlc3QuZ2V0X2V4dGVuZGluZygnSnFodG1sX0NvbXBvbmVudCcpO1xuXG4gICAgICAgIGNvbnNvbGVfZGVidWcoJ0pRSFRNTF9JTklUJywgJ1JlZ2lzdGVyaW5nICcgKyBqcWh0bWxfY29tcG9uZW50cy5sZW5ndGggKyAnIEpxaHRtbCBDb21wb25lbnRzJyk7XG5cbiAgICAgICAgZm9yIChsZXQgY29tcG9uZW50IG9mIGpxaHRtbF9jb21wb25lbnRzKSB7XG4gICAgICAgICAgICBqcWh0bWwucmVnaXN0ZXJfY29tcG9uZW50KGNvbXBvbmVudC5jbGFzc19uYW1lLCBjb21wb25lbnQuY2xhc3Nfb2JqZWN0KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZyYW1ld29yayBtb2R1bGVzIGluaXQgcGhhc2UgLSBCaW5kIGNvbXBvbmVudHMgYW5kIGluaXRpYWxpemUgRE9NXG4gICAgICogVGhpcyBydW5zIGFmdGVyIHRlbXBsYXRlcyBhcmUgcmVnaXN0ZXJlZCB0byBiaW5kIGNvbXBvbmVudCBjbGFzc2VzXG4gICAgICogQHBhcmFtIHtqUXVlcnl9IFskc2NvcGVdIE9wdGlvbmFsIHNjb3BlIHRvIHNlYXJjaCB3aXRoaW4gKGRlZmF1bHRzIHRvIGJvZHkpXG4gICAgICogQHJldHVybnMge0FycmF5PFByb21pc2U+fHVuZGVmaW5lZH0gQXJyYXkgb2YgcHJvbWlzZXMgZm9yIHJlY3Vyc2l2ZSBjYWxscywgdW5kZWZpbmVkIGZvciB0b3AtbGV2ZWxcbiAgICAgKi9cbiAgICBzdGF0aWMgX29uX2ZyYW1ld29ya19tb2R1bGVzX2luaXQoJHNjb3BlKSB7XG4gICAgICAgIGNvbnN0IGlzX3RvcF9sZXZlbCA9ICEkc2NvcGU7XG4gICAgICAgIGNvbnN0IHByb21pc2VzID0gW107XG4gICAgICAgIGNvbnN0IGNvbXBvbmVudHNfbmVlZGluZ19pbml0ID0gKCRzY29wZSB8fCAkKCdib2R5JykpLmZpbmQoJy5KcWh0bWxfQ29tcG9uZW50X0luaXQnKTtcbiAgICAgICAgaWYgKGNvbXBvbmVudHNfbmVlZGluZ19pbml0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnNvbGVfZGVidWcoJ0pRSFRNTF9JTklUJywgYEluaXRpYWxpemluZyAke2NvbXBvbmVudHNfbmVlZGluZ19pbml0Lmxlbmd0aH0gRE9NIGNvbXBvbmVudHNgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbXBvbmVudHNfbmVlZGluZ19pbml0LmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgY29uc3QgJGVsZW1lbnQgPSAkKHRoaXMpO1xuXG4gICAgICAgICAgICAvLyBTa2lwIGlmIGVsZW1lbnQgaXMgbm8gbG9uZ2VyIGF0dGFjaGVkIHRvIHRoZSBkb2N1bWVudFxuICAgICAgICAgICAgLy8gKG1heSBoYXZlIGJlZW4gcmVtb3ZlZCBieSBhIHBhcmVudCBjb21wb25lbnQncyAuZW1wdHkoKSBjYWxsKVxuICAgICAgICAgICAgaWYgKCFkb2N1bWVudC5jb250YWlucygkZWxlbWVudFswXSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIGFueSBwYXJlbnQgaGFzIEpxaHRtbF9Db21wb25lbnRfSW5pdCBjbGFzcyAtIHNraXAgbmVzdGVkIGNvbXBvbmVudHNcbiAgICAgICAgICAgIGxldCBwYXJlbnQgPSAkZWxlbWVudFswXS5wYXJlbnRFbGVtZW50O1xuICAgICAgICAgICAgd2hpbGUgKHBhcmVudCkge1xuICAgICAgICAgICAgICAgIGlmIChwYXJlbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdKcWh0bWxfQ29tcG9uZW50X0luaXQnKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47IC8vIFNraXAgdGhpcyBlbGVtZW50LCBpdCdzIG5lc3RlZFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBwYXJlbnQgPSBwYXJlbnQucGFyZW50RWxlbWVudDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgY29tcG9uZW50X25hbWUgPSAkZWxlbWVudC5hdHRyKCdkYXRhLWNvbXBvbmVudC1pbml0LW5hbWUnKTtcblxuICAgICAgICAgICAgLy8galF1ZXJ5J3MgLmRhdGEoKSBkb2Vzbid0IGF1dG8tcGFyc2UgSlNPTiAtIHdlIG5lZWQgdG8gcGFyc2UgaXQgbWFudWFsbHlcbiAgICAgICAgICAgIGxldCBjb21wb25lbnRfYXJncyA9IHt9O1xuICAgICAgICAgICAgY29uc3QgYXJnc19zdHJpbmcgPSAkZWxlbWVudC5hdHRyKCdkYXRhLWNvbXBvbmVudC1hcmdzJyk7XG5cbiAgICAgICAgICAgIC8vIFVuc2V0IGNvbXBvbmVudC0gcGhwIHNpZGUgaW5pdGlhbGl6YXRpb24gYXJncywgaXQgaXMgbm8gbG9uZ2VyIG5lZWRlZCBhcyBhIGNvbXBpb25lbnQgYXR0cmlidXRlXG4gICAgICAgICAgICAvLyBVbnNldHRpbmcgYWxzbyBwcmV2ZW50cyB1bmRlc2lyZWQgYWNjZXNzIHRvIHRoaXMgY29kZSBpbiBvdGhlciBwYXJ0cyBvZiB0aGUgcHJvZ3JhbSwgcHJldmVuaW5nIGFuXG4gICAgICAgICAgICAvLyB1bndhbnRlZCBmdXR1cmUgZGVwZW5kZW5jeSBvbiB0aGlzIHBhcmFkaWdtXG4gICAgICAgICAgICAkZWxlbWVudC5yZW1vdmVBdHRyKCdkYXRhLWNvbXBvbmVudC1pbml0LW5hbWUnKTtcbiAgICAgICAgICAgICRlbGVtZW50LnJlbW92ZUF0dHIoJ2RhdGEtY29tcG9uZW50LWFyZ3MnKTtcbiAgICAgICAgICAgICRlbGVtZW50LnJlbW92ZURhdGEoJ2NvbXBvbmVudC1pbml0LW5hbWUnKTtcbiAgICAgICAgICAgICRlbGVtZW50LnJlbW92ZURhdGEoJ2NvbXBvbmVudC1hcmdzJyk7XG5cbiAgICAgICAgICAgIGlmIChhcmdzX3N0cmluZykge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbXBvbmVudF9hcmdzID0gSlNPTi5wYXJzZShhcmdzX3N0cmluZyk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKGBbSlFIVE1MIEludGVncmF0aW9uXSBGYWlsZWQgdG8gcGFyc2UgY29tcG9uZW50IGFyZ3MgZm9yICR7Y29tcG9uZW50X25hbWV9OmAsIGUpO1xuICAgICAgICAgICAgICAgICAgICBjb21wb25lbnRfYXJncyA9IHt9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGNvbXBvbmVudF9uYW1lKSB7XG4gICAgICAgICAgICAgICAgLy8gVHJhbnNmb3JtICQgcHJlZml4ZWQga2V5cyB0byBkYXRhLSBhdHRyaWJ1dGVzXG4gICAgICAgICAgICAgICAgbGV0IGNvbXBvbmVudF9hcmdzX2ZpbHRlcmVkID0ge307XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoY29tcG9uZW50X2FyZ3MpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGlmIChrZXkuc3RhcnRzV2l0aCgnJCcpKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbXBvbmVudF9hcmdzX2ZpbHRlcmVkW2tleS5zdWJzdHJpbmcoMSldID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIC8vIH0gZWxzZVxuICAgICAgICAgICAgICAgICAgICBpZiAoa2V5LnN0YXJ0c1dpdGgoJ2RhdGEtJykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBvbmVudF9hcmdzX2ZpbHRlcmVkW2tleS5zdWJzdHJpbmcoNSldID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb21wb25lbnRfYXJnc19maWx0ZXJlZFtrZXldID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAvLyBTdG9yZSBpbm5lciBIVE1MIGFzIHN0cmluZyBmb3IgbmVzdGVkIGNvbXBvbmVudCBwcm9jZXNzaW5nXG4gICAgICAgICAgICAgICAgICAgIGNvbXBvbmVudF9hcmdzX2ZpbHRlcmVkLl9pbm5lcl9odG1sID0gJGVsZW1lbnQuaHRtbCgpO1xuICAgICAgICAgICAgICAgICAgICAkZWxlbWVudC5lbXB0eSgpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0aGUgaW5pdCBjbGFzcyBiZWZvcmUgaW5zdGFudGlhdGlvbiB0byBwcmV2ZW50IHJlLWluaXRpYWxpemF0aW9uXG4gICAgICAgICAgICAgICAgICAgICRlbGVtZW50LnJlbW92ZUNsYXNzKCdKcWh0bWxfQ29tcG9uZW50X0luaXQnKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBDcmVhdGUgcHJvbWlzZSBmb3IgdGhpcyBjb21wb25lbnQncyBpbml0aWFsaXphdGlvblxuICAgICAgICAgICAgICAgICAgICBjb25zdCBjb21wb25lbnRfcHJvbWlzZSA9IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVc2UgalF1ZXJ5IGNvbXBvbmVudCBwbHVnaW4gdG8gY3JlYXRlIHRoZSBjb21wb25lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFBsdWdpbiBoYW5kbGVzIGVsZW1lbnQgaW50ZXJuYWxseSwganVzdCBwYXNzIGFyZ3NcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgdXBkYXRlZCAkZWxlbWVudCBmcm9tXG4gICAgICAgICAgICAgICAgICAgICAgICBsZXQgY29tcG9uZW50ID0gJGVsZW1lbnQuY29tcG9uZW50KGNvbXBvbmVudF9uYW1lLCBjb21wb25lbnRfYXJnc19maWx0ZXJlZCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBvbmVudC5vbigncmVuZGVyJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlY3Vyc2l2ZWx5IGNvbGxlY3QgcHJvbWlzZXMgZnJvbSBuZXN0ZWQgY29tcG9uZW50c1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0dGluZyB0aGUgdXBkYXRlZCBjb21wb25lbnQgaGVyZSAtIGlmIHRoZSB0YWcgbmFtZSB3YXMgbm90IGRpdiwgdGhlIGVsZW1lbnQgd291bGQgaGF2ZSBiZWVuIHJlY3JlYXRlZCwgc28gd2UgbmVlZCB0byBnZXQgdGhlIGVsZW1lbnQgc2V0IG9uIHRoZSBjb21wb25lbnQsIG5vdCBmcm9tIG91ciBlYXJsaWVyIHNlbGVjdG9yXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBuZXN0ZWRfcHJvbWlzZXMgPSBKcWh0bWxfSW50ZWdyYXRpb24uX29uX2ZyYW1ld29ya19tb2R1bGVzX2luaXQoY29tcG9uZW50LiQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2goLi4ubmVzdGVkX3Byb21pc2VzKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlc29sdmUgdGhpcyBjb21wb25lbnQncyBwcm9taXNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSkuJDtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgcHJvbWlzZXMucHVzaChjb21wb25lbnRfcHJvbWlzZSk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihgW0pRSFRNTCBJbnRlZ3JhdGlvbl0gRmFpbGVkIHRvIGluaXRpYWxpemUgY29tcG9uZW50ICR7Y29tcG9uZW50X25hbWV9OmAsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZGV0YWlsczonLCBlcnJvci5zdGFjayB8fCBlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBUb3AtbGV2ZWwgY2FsbDogc3Bhd24gYXN5bmMgaGFuZGxlciB0byB3YWl0IGZvciBhbGwgcHJvbWlzZXMsIHRoZW4gdHJpZ2dlciBldmVudFxuICAgICAgICBpZiAoaXNfdG9wX2xldmVsKSB7XG4gICAgICAgICAgICAoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VzKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBSc3guX3JzeF9jYWxsX2FsbF9jbGFzc2VzKCdvbl9qcWh0bWxfcmVhZHknKTtcbiAgICAgICAgICAgICAgICBSc3gudHJpZ2dlcignanFodG1sX3JlYWR5Jyk7XG4gICAgICAgICAgICB9KSgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVjdXJzaXZlIGNhbGw6IHJldHVybiBwcm9taXNlcyBmb3IgcGFyZW50IHRvIGNvbGxlY3RcbiAgICAgICAgcmV0dXJuIHByb21pc2VzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhbGwgcmVnaXN0ZXJlZCBjb21wb25lbnQgbmFtZXNcbiAgICAgKiBAcmV0dXJucyB7QXJyYXk8c3RyaW5nPn0gQXJyYXkgb2YgY29tcG9uZW50IG5hbWVzXG4gICAgICovXG4gICAgc3RhdGljIGdldF9jb21wb25lbnRfbmFtZXMoKSB7XG4gICAgICAgIHJldHVybiBqcWh0bWwuZ2V0X2NvbXBvbmVudF9uYW1lcygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIGEgY29tcG9uZW50IGlzIHJlZ2lzdGVyZWRcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBDb21wb25lbnQgbmFtZVxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGNvbXBvbmVudCBpcyByZWdpc3RlcmVkXG4gICAgICovXG4gICAgc3RhdGljIGhhc19jb21wb25lbnQobmFtZSkge1xuICAgICAgICByZXR1cm4ganFodG1sLmhhc19jb21wb25lbnQobmFtZSk7XG4gICAgfVxufVxuXG4vLyBSU1ggbWFuaWZlc3QgYXV0b21hdGljYWxseSBtYWtlcyBjbGFzc2VzIGdsb2JhbCAtIG5vIG1hbnVhbCBhc3NpZ25tZW50IG5lZWRlZFxuIiwiLy8gSmF2YVNjcmlwdCBNYW5pZmVzdCAtIEdlbmVyYXRlZCBieSBCdW5kbGVDb21waWxlclxuLy8gUmVnaXN0ZXJzIGFsbCBjbGFzc2VzIGluIHRoaXMgYnVuZGxlIGZvciBydW50aW1lIGludHJvc3BlY3Rpb25cbk1hbmlmZXN0Ll9kZWZpbmUoW1xuICAgIFtNYW5pZmVzdCwgXCJNYW5pZmVzdFwiLCBudWxsXSxcbiAgICBbUnN4X0JlaGF2aW9ycywgXCJSc3hfQmVoYXZpb3JzXCIsIG51bGxdLFxuICAgIFtSc3hfQ2FjaGUsIFwiUnN4X0NhY2hlXCIsIG51bGxdLFxuICAgIFtSc3hfSW5pdCwgXCJSc3hfSW5pdFwiLCBudWxsXSxcbiAgICBbUnN4X0pzX01vZGVsLCBcIlJzeF9Kc19Nb2RlbFwiLCBudWxsXSxcbiAgICBbUnN4X1ZpZXdfVHJhbnNpdGlvbnMsIFwiUnN4X1ZpZXdfVHJhbnNpdGlvbnNcIiwgbnVsbF0sXG4gICAgW1JlYWRXcml0ZUxvY2ssIFwiUmVhZFdyaXRlTG9ja1wiLCBudWxsXSxcbiAgICBbRm9ybV9VdGlscywgXCJGb3JtX1V0aWxzXCIsIG51bGxdLFxuICAgIFtEZWJ1Z2dlciwgXCJEZWJ1Z2dlclwiLCBudWxsXSxcbiAgICBbUnN4X0pxX0hlbHBlcnMsIFwiUnN4X0pxX0hlbHBlcnNcIiwgbnVsbF0sXG4gICAgW1JzeCwgXCJSc3hcIiwgbnVsbF0sXG4gICAgW0FqYXgsIFwiQWpheFwiLCBudWxsXSxcbiAgICBbSnFodG1sX0NvbXBvbmVudCwgXCJKcWh0bWxfQ29tcG9uZW50XCIsIF9CYXNlX0pxaHRtbF9Db21wb25lbnRdLFxuICAgIFtKcWh0bWxfSW50ZWdyYXRpb24sIFwiSnFodG1sX0ludGVncmF0aW9uXCIsIG51bGxdXG5dKTtcblxuIiwiJChkb2N1bWVudCkucmVhZHkoYXN5bmMgZnVuY3Rpb24oKSB7XG50cnkge1xuY29uc29sZV9kZWJ1ZygnUlNYX0lOSVQnLCAnRG9jdW1lbnQgcmVhZHksIHN0YXJ0aW5nIFJzeC5fcnN4X2NvcmVfYm9vdCcpO1xuYXdhaXQgUnN4Ll9yc3hfY29yZV9ib290KCk7XG5jb25zb2xlX2RlYnVnKCdSU1hfSU5JVCcsICdJbml0aWFsaXphdGlvbiBjb21wbGV0ZScpO1xufSBjYXRjaCAoZXJyb3IpIHtcbmNvbnNvbGUuZXJyb3IoJ1tSU1hfSU5JVF0gSW5pdGlhbGl6YXRpb24gZmFpbGVkOicsIGVycm9yKTtcbmNvbnNvbGUuZXJyb3IoJ1tSU1hfSU5JVF0gU3RhY2s6JywgZXJyb3Iuc3RhY2spO1xudGhyb3cgZXJyb3I7XG59XG59KTsiXSwic291cmNlUm9vdCI6IiJ9
|