Files
rspade_system/storage-broken/rsx-build/bundles/Bootstrap5_Bundle__app.30e5466c.js
root 9ebcc359ae Fix code quality violations and enhance ROUTE-EXISTS-01 rule
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>
2025-11-19 17:48:15 +00:00

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 &nbsp;
*/
function $nbsp() {
return $('<span>&nbsp;</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