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

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

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

497 lines
62 KiB
JavaScript
Executable File

"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();
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJBamF4IiwiX29uX2ZyYW1ld29ya19jb3JlX2luaXQiLCJfcGVuZGluZ19jYWxscyIsIl9mbHVzaF90aW1lb3V0IiwiX2NhbGxfY291bnRlciIsIk1BWF9CQVRDSF9TSVpFIiwiREVCT1VOQ0VfTVMiLCJfdHJhY2tlZF9wcm9taXNlcyIsIldlYWtTZXQiLCJ3aW5kb3ciLCJhZGRFdmVudExpc3RlbmVyIiwiZXZlbnQiLCJoYXMiLCJwcm9taXNlIiwicHJldmVudERlZmF1bHQiLCJlcnJvciIsInJlYXNvbiIsImNvbnNvbGUiLCJNb2RhbCIsImNhbGwiLCJ1cmwiLCJwYXJhbXMiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJ1bmRlZmluZWQiLCJwYXRoIiwiRXJyb3IiLCJjb250cm9sbGVyIiwiYWN0aW9uIiwiYWpheF91cmxfdG9fY29udHJvbGxlcl9hY3Rpb24iLCJsb2ciLCJyc3hhcHAiLCJhamF4X2Rpc2FibGVfYmF0Y2hpbmciLCJfY2FsbF9kaXJlY3QiLCJfY2FsbF9iYXRjaCIsImFkZCIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiY2FsbF9rZXkiLCJfZ2VuZXJhdGVfY2FsbF9rZXkiLCJleGlzdGluZ19jYWxsIiwiaXNfY29tcGxldGUiLCJpc19lcnJvciIsInJlc3VsdCIsImNhbGxiYWNrcyIsInB1c2giLCJjYWxsX2lkIiwicGVuZGluZ19jYWxsIiwicGVuZGluZ19jb3VudCIsIk9iamVjdCIsImtleXMiLCJmaWx0ZXIiLCJrZXkiLCJjbGVhclRpbWVvdXQiLCJfZmx1c2hfcGVuZGluZ19jYWxscyIsInNldFRpbWVvdXQiLCJEZWJ1Z2dlciIsImNvbnNvbGVfZGVidWciLCIkIiwiYWpheCIsIm1ldGhvZCIsImRhdGEiLCJkYXRhVHlwZSIsIl9fbG9jYWxfaW50ZWdyYXRpb24iLCJzdWNjZXNzIiwicmVzcG9uc2UiLCJBcnJheSIsImlzQXJyYXkiLCJmb3JFYWNoIiwibXNnIiwiY2hhbm5lbCIsImFyZ3MiLCJfc3VjY2VzcyIsInByb2Nlc3NlZF92YWx1ZSIsIlJzeF9Kc19Nb2RlbCIsIl9pbnN0YW50aWF0ZV9tb2RlbHNfcmVjdXJzaXZlIiwiX2FqYXhfcmV0dXJuX3ZhbHVlIiwiZXJyb3JfdHlwZSIsImRldGFpbHMiLCJmYXRhbF9lcnJvcl9kYXRhIiwiZXJyb3JfbWVzc2FnZSIsImZhdGFsX2Vycm9yIiwidHlwZSIsImxvZ19lcnJvciIsIm1lc3NhZ2UiLCJlbmRwb2ludCIsImF1dGhfZXJyb3IiLCJ1bmF1dGhfZXJyb3IiLCJmb3JtX2Vycm9yIiwiZ2VuZXJpY19lcnJvciIsInhociIsInN0YXR1cyIsIl9leHRyYWN0X2Vycm9yX21lc3NhZ2UiLCJuZXR3b3JrX2Vycm9yIiwic3RhdHVzVGV4dCIsImNhbGxzX3RvX3NlbmQiLCJjYWxsX21hcCIsIm1hcCIsImMiLCJiYXRjaF9jYWxscyIsIkpTT04iLCJzdHJpbmdpZnkiLCJyZXNwb25zZV9rZXkiLCJzdGFydHNXaXRoIiwicGFyc2VJbnQiLCJzdWJzdHJpbmciLCJjYWxsX3Jlc3BvbnNlIiwiX3JlZiIsImVycm9yX2RldGFpbHMiLCJfcmVmMiIsInhocl9lcnJvciIsIl9yZWYzIiwic29ydGVkX3BhcmFtcyIsInNvcnQiLCJyZXNwb25zZUpTT04iLCJyZXNwb25zZVRleHQiLCJwYXJzZSIsImUiLCJwYXJ0cyIsInNwbGl0IiwicGFydCIsIm9uX2NvcmVfZGVmaW5lIl0sInNvdXJjZXMiOlsiYXBwL1JTcGFkZS9Db3JlL0pzL0FqYXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gQEZJTEUtU1VCQ0xBU1MtMDEtRVhDRVBUSU9OXG5cbi8qKlxuICogQ2xpZW50LXNpZGUgQWpheCBjbGFzcyBmb3IgbWFraW5nIEFQSSBjYWxscyB0byBSU1ggY29udHJvbGxlcnNcbiAqXG4gKiBBdXRvbWF0aWNhbGx5IGJhdGNoZXMgbXVsdGlwbGUgY2FsbHMgaW50byBzaW5nbGUgSFRUUCByZXF1ZXN0cyB0byByZWR1Y2UgbmV0d29yayBvdmVyaGVhZC5cbiAqIEJhdGNoZXMgdXAgdG8gMjAgY2FsbHMgb3IgZmx1c2hlcyBhZnRlciBzZXRUaW1lb3V0KDApIGRlYm91bmNlLlxuICovXG5jbGFzcyBBamF4IHtcbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIEFqYXggc3lzdGVtXG4gICAgICogQ2FsbGVkIGF1dG9tYXRpY2FsbHkgd2hlbiBjbGFzcyBpcyBsb2FkZWRcbiAgICAgKi9cbiAgICBzdGF0aWMgX29uX2ZyYW1ld29ya19jb3JlX2luaXQoKSB7XG4gICAgICAgIC8vIFF1ZXVlIG9mIHBlbmRpbmcgY2FsbHMgd2FpdGluZyB0byBiZSBiYXRjaGVkXG4gICAgICAgIEFqYXguX3BlbmRpbmdfY2FsbHMgPSB7fTtcblxuICAgICAgICAvLyBUaW1lciBmb3IgYmF0Y2hpbmcgZmx1c2hcbiAgICAgICAgQWpheC5fZmx1c2hfdGltZW91dCA9IG51bGw7XG5cbiAgICAgICAgLy8gQ2FsbCBjb3VudGVyIGZvciBnZW5lcmF0aW5nIHVuaXF1ZSBjYWxsIElEc1xuICAgICAgICBBamF4Ll9jYWxsX2NvdW50ZXIgPSAwO1xuXG4gICAgICAgIC8vIE1heGltdW0gYmF0Y2ggc2l6ZSBiZWZvcmUgZm9yY2luZyBpbW1lZGlhdGUgZmx1c2hcbiAgICAgICAgQWpheC5NQVhfQkFUQ0hfU0laRSA9IDIwO1xuXG4gICAgICAgIC8vIERlYm91bmNlIHRpbWUgaW4gbWlsbGlzZWNvbmRzXG4gICAgICAgIEFqYXguREVCT1VOQ0VfTVMgPSAwO1xuXG4gICAgICAgIC8vIFRyYWNrIHByb21pc2VzIGZyb20gQWpheCBjYWxscyB0byBkZXRlY3QgdW5jYXVnaHQgcmVqZWN0aW9uc1xuICAgICAgICBBamF4Ll90cmFja2VkX3Byb21pc2VzID0gbmV3IFdlYWtTZXQoKTtcblxuICAgICAgICAvLyBTZXQgdXAgZ2xvYmFsIHVuaGFuZGxlZCByZWplY3Rpb24gaGFuZGxlciBmb3IgQWpheCBlcnJvcnNcbiAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3VuaGFuZGxlZHJlamVjdGlvbicsIGFzeW5jIChldmVudCkgPT4ge1xuICAgICAgICAgICAgLy8gT25seSBoYW5kbGUgcmVqZWN0aW9ucyBmcm9tIEFqYXggcHJvbWlzZXNcbiAgICAgICAgICAgIGlmIChBamF4Ll90cmFja2VkX3Byb21pc2VzLmhhcyhldmVudC5wcm9taXNlKSkge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7IC8vIFByZXZlbnQgYnJvd3NlcidzIGRlZmF1bHQgXCJVbmNhdWdodCAoaW4gcHJvbWlzZSlcIiBlcnJvclxuXG4gICAgICAgICAgICAgICAgY29uc3QgZXJyb3IgPSBldmVudC5yZWFzb247XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignVW5jYXVnaHQgQWpheCBlcnJvcjonLCBlcnJvcik7XG5cbiAgICAgICAgICAgICAgICAvLyBTaG93IE1vZGFsLmVycm9yKCkgZm9yIHVuY2F1Z2h0IEFqYXggZXJyb3JzXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBNb2RhbCAhPT0gJ3VuZGVmaW5lZCcgJiYgTW9kYWwuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgTW9kYWwuZXJyb3IoZXJyb3IsICdVbmNhdWdodCBBamF4IEVycm9yJyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNYWtlIGFuIEFKQVggY2FsbCB0byBhbiBSU1ggY29udHJvbGxlciBhY3Rpb25cbiAgICAgKlxuICAgICAqIEFsbCBjYWxscyBhcmUgYXV0b21hdGljYWxseSBiYXRjaGVkIHVubGVzcyB3aW5kb3cucnN4YXBwLmFqYXhfZGlzYWJsZV9iYXRjaGluZyBpcyB0cnVlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd8b2JqZWN0fGZ1bmN0aW9ufSB1cmwgLSBUaGUgQWpheCBVUkwgKGUuZy4sICcvX2FqYXgvQ29udHJvbGxlcl9OYW1lL2FjdGlvbl9uYW1lJykgb3IgYW4gb2JqZWN0L2Z1bmN0aW9uIHdpdGggYSAucGF0aCBwcm9wZXJ0eVxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMgLSBQYXJhbWV0ZXJzIHRvIHNlbmQgdG8gdGhlIGFjdGlvblxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlfSAtIFJlc29sdmVzIHdpdGggdGhlIHJldHVybiB2YWx1ZSwgcmVqZWN0cyB3aXRoIGVycm9yXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIGNhbGwodXJsLCBwYXJhbXMgPSB7fSkge1xuICAgICAgICAvLyBJZiB1cmwgaXMgYW4gb2JqZWN0IG9yIGZ1bmN0aW9uIHdpdGggYSAucGF0aCBwcm9wZXJ0eSwgdXNlIHRoYXQgYXMgdGhlIFVSTFxuICAgICAgICBpZiAodXJsICYmIHR5cGVvZiB1cmwgPT09ICdvYmplY3QnICYmIHVybC5wYXRoKSB7XG4gICAgICAgICAgICB1cmwgPSB1cmwucGF0aDtcbiAgICAgICAgfSBlbHNlIGlmICh1cmwgJiYgdHlwZW9mIHVybCA9PT0gJ2Z1bmN0aW9uJyAmJiB1cmwucGF0aCkge1xuICAgICAgICAgICAgdXJsID0gdXJsLnBhdGg7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBWYWxpZGF0ZSB1cmwgaXMgYSBub24tZW1wdHkgc3RyaW5nXG4gICAgICAgIGlmICh0eXBlb2YgdXJsICE9PSAnc3RyaW5nJyB8fCB1cmwubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FqYXguY2FsbCgpIHJlcXVpcmVzIGEgbm9uLWVtcHR5IHN0cmluZyBVUkwgb3IgYW4gb2JqZWN0L2Z1bmN0aW9uIHdpdGggYSAucGF0aCBwcm9wZXJ0eScpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRXh0cmFjdCBjb250cm9sbGVyIGFuZCBhY3Rpb24gZnJvbSBVUkxcbiAgICAgICAgY29uc3QgeyBjb250cm9sbGVyLCBhY3Rpb24gfSA9IEFqYXguYWpheF91cmxfdG9fY29udHJvbGxlcl9hY3Rpb24odXJsKTtcblxuICAgICAgICBjb25zb2xlLmxvZygnQWpheDonLCBjb250cm9sbGVyLCBhY3Rpb24sIHBhcmFtcyk7XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgYmF0Y2hpbmcgaXMgZGlzYWJsZWQgZm9yIGRlYnVnZ2luZ1xuICAgICAgICBsZXQgcHJvbWlzZTtcbiAgICAgICAgaWYgKHdpbmRvdy5yc3hhcHAgJiYgd2luZG93LnJzeGFwcC5hamF4X2Rpc2FibGVfYmF0Y2hpbmcpIHtcbiAgICAgICAgICAgIHByb21pc2UgPSBBamF4Ll9jYWxsX2RpcmVjdChjb250cm9sbGVyLCBhY3Rpb24sIHBhcmFtcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwcm9taXNlID0gQWpheC5fY2FsbF9iYXRjaChjb250cm9sbGVyLCBhY3Rpb24sIHBhcmFtcyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUcmFjayB0aGlzIHByb21pc2UgZm9yIHVuaGFuZGxlZCByZWplY3Rpb24gZGV0ZWN0aW9uXG4gICAgICAgIEFqYXguX3RyYWNrZWRfcHJvbWlzZXMuYWRkKHByb21pc2UpO1xuXG4gICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1ha2UgYSBiYXRjaGVkIEFqYXggY2FsbFxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9jYWxsX2JhdGNoKGNvbnRyb2xsZXIsIGFjdGlvbiwgcGFyYW1zID0ge30pIHtcbiAgICAgICAgY29uc29sZS5sb2coJ0FqYXggQmF0Y2g6JywgY29udHJvbGxlciwgYWN0aW9uLCBwYXJhbXMpO1xuXG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICAvLyBHZW5lcmF0ZSBjYWxsIGtleSBmb3IgZGVkdXBsaWNhdGlvblxuICAgICAgICAgICAgY29uc3QgY2FsbF9rZXkgPSBBamF4Ll9nZW5lcmF0ZV9jYWxsX2tleShjb250cm9sbGVyLCBhY3Rpb24sIHBhcmFtcyk7XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoaXMgZXhhY3QgY2FsbCBpcyBhbHJlYWR5IHBlbmRpbmdcbiAgICAgICAgICAgIGlmIChBamF4Ll9wZW5kaW5nX2NhbGxzW2NhbGxfa2V5XSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nX2NhbGwgPSBBamF4Ll9wZW5kaW5nX2NhbGxzW2NhbGxfa2V5XTtcblxuICAgICAgICAgICAgICAgIC8vIElmIGNhbGwgYWxyZWFkeSBjb21wbGV0ZWQgKGNhY2hlZCksIHJldHVybiBpbW1lZGlhdGVseVxuICAgICAgICAgICAgICAgIGlmIChleGlzdGluZ19jYWxsLmlzX2NvbXBsZXRlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChleGlzdGluZ19jYWxsLmlzX2Vycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZXhpc3RpbmdfY2FsbC5lcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHZlKGV4aXN0aW5nX2NhbGwucmVzdWx0KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gQ2FsbCBpcyBwZW5kaW5nLCBhZGQgdGhpcyBwcm9taXNlIHRvIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgIGV4aXN0aW5nX2NhbGwuY2FsbGJhY2tzLnB1c2goeyByZXNvbHZlLCByZWplY3QgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDcmVhdGUgbmV3IHBlbmRpbmcgY2FsbFxuICAgICAgICAgICAgY29uc3QgY2FsbF9pZCA9IEFqYXguX2NhbGxfY291bnRlcisrO1xuICAgICAgICAgICAgY29uc3QgcGVuZGluZ19jYWxsID0ge1xuICAgICAgICAgICAgICAgIGNhbGxfaWQ6IGNhbGxfaWQsXG4gICAgICAgICAgICAgICAgY2FsbF9rZXk6IGNhbGxfa2V5LFxuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXI6IGNvbnRyb2xsZXIsXG4gICAgICAgICAgICAgICAgYWN0aW9uOiBhY3Rpb24sXG4gICAgICAgICAgICAgICAgcGFyYW1zOiBwYXJhbXMsXG4gICAgICAgICAgICAgICAgY2FsbGJhY2tzOiBbeyByZXNvbHZlLCByZWplY3QgfV0sXG4gICAgICAgICAgICAgICAgaXNfY29tcGxldGU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzX2Vycm9yOiBmYWxzZSxcbiAgICAgICAgICAgICAgICByZXN1bHQ6IG51bGwsXG4gICAgICAgICAgICAgICAgZXJyb3I6IG51bGwsXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAvLyBBZGQgdG8gcGVuZGluZyBxdWV1ZVxuICAgICAgICAgICAgQWpheC5fcGVuZGluZ19jYWxsc1tjYWxsX2tleV0gPSBwZW5kaW5nX2NhbGw7XG5cbiAgICAgICAgICAgIC8vIENvdW50IHBlbmRpbmcgY2FsbHNcbiAgICAgICAgICAgIGNvbnN0IHBlbmRpbmdfY291bnQgPSBPYmplY3Qua2V5cyhBamF4Ll9wZW5kaW5nX2NhbGxzKS5maWx0ZXIoKGtleSkgPT4gIUFqYXguX3BlbmRpbmdfY2FsbHNba2V5XS5pc19jb21wbGV0ZSkubGVuZ3RoO1xuXG4gICAgICAgICAgICAvLyBJZiB3ZSd2ZSBoaXQgdGhlIGJhdGNoIHNpemUgbGltaXQsIGZsdXNoIGltbWVkaWF0ZWx5XG4gICAgICAgICAgICBpZiAocGVuZGluZ19jb3VudCA+PSBBamF4Lk1BWF9CQVRDSF9TSVpFKSB7XG4gICAgICAgICAgICAgICAgY2xlYXJUaW1lb3V0KEFqYXguX2ZsdXNoX3RpbWVvdXQpO1xuICAgICAgICAgICAgICAgIEFqYXguX2ZsdXNoX3RpbWVvdXQgPSBudWxsO1xuICAgICAgICAgICAgICAgIEFqYXguX2ZsdXNoX3BlbmRpbmdfY2FsbHMoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gU2NoZWR1bGUgYmF0Y2ggZmx1c2ggd2l0aCBkZWJvdW5jZVxuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dChBamF4Ll9mbHVzaF90aW1lb3V0KTtcbiAgICAgICAgICAgICAgICBBamF4Ll9mbHVzaF90aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIEFqYXguX2ZsdXNoX3BlbmRpbmdfY2FsbHMoKTtcbiAgICAgICAgICAgICAgICB9LCBBamF4LkRFQk9VTkNFX01TKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFrZSBhIGRpcmVjdCAobm9uLWJhdGNoZWQpIEFqYXggY2FsbFxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIF9jYWxsX2RpcmVjdChjb250cm9sbGVyLCBhY3Rpb24sIHBhcmFtcyA9IHt9KSB7XG4gICAgICAgIC8vIENvbnN0cnVjdCBVUkwgZnJvbSBjb250cm9sbGVyIGFuZCBhY3Rpb25cbiAgICAgICAgY29uc3QgdXJsID0gYC9fYWpheC8ke2NvbnRyb2xsZXJ9LyR7YWN0aW9ufWA7XG5cbiAgICAgICAgLy8gTG9nIHRoZSBBSkFYIGNhbGwgdXNpbmcgY29uc29sZV9kZWJ1Z1xuICAgICAgICBpZiAodHlwZW9mIERlYnVnZ2VyICE9PSAndW5kZWZpbmVkJyAmJiBEZWJ1Z2dlci5jb25zb2xlX2RlYnVnKSB7XG4gICAgICAgICAgICBEZWJ1Z2dlci5jb25zb2xlX2RlYnVnKCdBSkFYJywgYENhbGxpbmcgJHtjb250cm9sbGVyfS4ke2FjdGlvbn0gKHVuYmF0Y2hlZClgLCBwYXJhbXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgICQuYWpheCh7XG4gICAgICAgICAgICAgICAgdXJsOiB1cmwsXG4gICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgZGF0YTogcGFyYW1zLFxuICAgICAgICAgICAgICAgIGRhdGFUeXBlOiAnanNvbicsXG4gICAgICAgICAgICAgICAgX19sb2NhbF9pbnRlZ3JhdGlvbjogdHJ1ZSwgLy8gQnlwYXNzICQuYWpheCBvdmVycmlkZVxuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IChyZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgY29uc29sZV9kZWJ1ZyBtZXNzYWdlc1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVzcG9uc2UuY29uc29sZV9kZWJ1ZyAmJiBBcnJheS5pc0FycmF5KHJlc3BvbnNlLmNvbnNvbGVfZGVidWcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNwb25zZS5jb25zb2xlX2RlYnVnLmZvckVhY2goKG1zZykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghQXJyYXkuaXNBcnJheShtc2cpIHx8IG1zZy5sZW5ndGggIT09IDIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvbnNvbGVfZGVidWcgbWVzc2FnZSBmb3JtYXQgLSBleHBlY3RlZCBbY2hhbm5lbCwgW2FyZ3VtZW50c11dJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjaGFubmVsLCBhcmdzXSA9IG1zZztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhjaGFubmVsLCAuLi5hcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHJlc3BvbnNlIHdhcyBzdWNjZXNzZnVsXG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5fc3VjY2VzcyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQEpTLUFKQVgtMDItRVhDRVBUSU9OIC0gVW53cmFwIHNlcnZlciByZXNwb25zZXMgd2l0aCBfYWpheF9yZXR1cm5fdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHByb2Nlc3NlZF92YWx1ZSA9IFJzeF9Kc19Nb2RlbC5faW5zdGFudGlhdGVfbW9kZWxzX3JlY3Vyc2l2ZShyZXNwb25zZS5fYWpheF9yZXR1cm5fdmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZShwcm9jZXNzZWRfdmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSGFuZGxlIGVycm9yIHJlc3BvbnNlc1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JfdHlwZSA9IHJlc3BvbnNlLmVycm9yX3R5cGUgfHwgJ3Vua25vd25fZXJyb3InO1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcmVhc29uID0gcmVzcG9uc2UucmVhc29uIHx8ICdVbmtub3duIGVycm9yIG9jY3VycmVkJztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGRldGFpbHMgPSByZXNwb25zZS5kZXRhaWxzIHx8IHt9O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBIYW5kbGUgc3BlY2lmaWMgZXJyb3IgdHlwZXNcbiAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoZXJyb3JfdHlwZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2ZhdGFsJzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmF0YWwgUEhQIGVycm9yIHdpdGggZnVsbCBlcnJvciBkZXRhaWxzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGZhdGFsX2Vycm9yX2RhdGEgPSByZXNwb25zZS5lcnJvciB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JfbWVzc2FnZSA9IGZhdGFsX2Vycm9yX2RhdGEuZXJyb3IgfHwgJ0ZhdGFsIGVycm9yIG9jY3VycmVkJztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdBamF4IGVycm9yIHJlc3BvbnNlIGZyb20gc2VydmVyOicsIHJlc3BvbnNlLmVycm9yKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmYXRhbF9lcnJvciA9IG5ldyBFcnJvcihlcnJvcl9tZXNzYWdlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmF0YWxfZXJyb3IudHlwZSA9ICdmYXRhbCc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhdGFsX2Vycm9yLmRldGFpbHMgPSByZXNwb25zZS5lcnJvcjtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBMb2cgdG8gc2VydmVyIGlmIGJyb3dzZXIgZXJyb3IgbG9nZ2luZyBpcyBlbmFibGVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlYnVnZ2VyLmxvZ19lcnJvcih7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgQWpheCBGYXRhbCBFcnJvcjogJHtlcnJvcl9tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiAnYWpheF9mYXRhbCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRwb2ludDogdXJsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGV0YWlsczogcmVzcG9uc2UuZXJyb3IsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdChmYXRhbF9lcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAncmVzcG9uc2VfYXV0aF9yZXF1aXJlZCc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVGhlIHVzZXIgaXMgbm8gbG9uZ2VyIGF1dGhlbnRpY2F0ZWQsIHRoaXMgaXMgYSBwbGFjZWhvbGRlciBmb3IgZnV0dXJlIGNvZGUgd2hpY2ggaGFuZGxlcyB0aGlzIHNjZW5hcmlvLidcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgYXV0aF9lcnJvciA9IG5ldyBFcnJvcihyZWFzb24pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdXRoX2Vycm9yLnR5cGUgPSAnYXV0aF9yZXF1aXJlZCc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dGhfZXJyb3IuZGV0YWlscyA9IGRldGFpbHM7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdChhdXRoX2Vycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdyZXNwb25zZV91bmF1dGhvcml6ZWQnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1RoZSB1c2VyIGlzIHVuYXV0aG9yaXplZCB0byBwZXJmb3JtIHRoaXMgYWN0aW9uLCB0aGlzIGlzIGEgcGxhY2Vob2xkZXIgZm9yIGZ1dHVyZSBjb2RlIHdoaWNoIGhhbmRsZXMgdGhpcyBzY2VuYXJpby4nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHVuYXV0aF9lcnJvciA9IG5ldyBFcnJvcihyZWFzb24pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmF1dGhfZXJyb3IudHlwZSA9ICd1bmF1dGhvcml6ZWQnO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmF1dGhfZXJyb3IuZGV0YWlscyA9IGRldGFpbHM7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlamVjdCh1bmF1dGhfZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3Jlc3BvbnNlX2Zvcm1fZXJyb3InOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmb3JtX2Vycm9yID0gbmV3IEVycm9yKHJlYXNvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1fZXJyb3IudHlwZSA9ICdmb3JtX2Vycm9yJztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybV9lcnJvci5kZXRhaWxzID0gZGV0YWlscztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGZvcm1fZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGdlbmVyaWNfZXJyb3IgPSBuZXcgRXJyb3IocmVhc29uKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZXJpY19lcnJvci50eXBlID0gZXJyb3JfdHlwZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZXJpY19lcnJvci5kZXRhaWxzID0gZGV0YWlscztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVqZWN0KGdlbmVyaWNfZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZXJyb3I6ICh4aHIsIHN0YXR1cywgZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZXJyb3JfbWVzc2FnZSA9IEFqYXguX2V4dHJhY3RfZXJyb3JfbWVzc2FnZSh4aHIpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBuZXR3b3JrX2Vycm9yID0gbmV3IEVycm9yKGVycm9yX21lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICBuZXR3b3JrX2Vycm9yLnR5cGUgPSAnbmV0d29ya19lcnJvcic7XG4gICAgICAgICAgICAgICAgICAgIG5ldHdvcmtfZXJyb3Iuc3RhdHVzID0geGhyLnN0YXR1cztcbiAgICAgICAgICAgICAgICAgICAgbmV0d29ya19lcnJvci5zdGF0dXNUZXh0ID0gc3RhdHVzO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIExvZyBzZXJ2ZXIgZXJyb3JzICg1MDArKSB0byB0aGUgc2VydmVyIGlmIGJyb3dzZXIgZXJyb3IgbG9nZ2luZyBpcyBlbmFibGVkXG4gICAgICAgICAgICAgICAgICAgIGlmICh4aHIuc3RhdHVzID49IDUwMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgRGVidWdnZXIubG9nX2Vycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgQWpheCBTZXJ2ZXIgRXJyb3IgJHt4aHIuc3RhdHVzfTogJHtlcnJvcl9tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2FqYXhfc2VydmVyX2Vycm9yJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmRwb2ludDogdXJsLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXR1czogeGhyLnN0YXR1cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0dXNUZXh0OiBzdGF0dXMsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJlamVjdChuZXR3b3JrX2Vycm9yKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZsdXNoIGFsbCBwZW5kaW5nIGNhbGxzIGJ5IHNlbmRpbmcgYmF0Y2ggcmVxdWVzdFxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIF9mbHVzaF9wZW5kaW5nX2NhbGxzKCkge1xuICAgICAgICAvLyBDb2xsZWN0IGFsbCBwZW5kaW5nIGNhbGxzXG4gICAgICAgIGNvbnN0IGNhbGxzX3RvX3NlbmQgPSBbXTtcbiAgICAgICAgY29uc3QgY2FsbF9tYXAgPSB7fTsgLy8gTWFwIGNhbGxfaWQgdG8gcGVuZGluZ19jYWxsIG9iamVjdFxuXG4gICAgICAgIGZvciAoY29uc3QgY2FsbF9rZXkgaW4gQWpheC5fcGVuZGluZ19jYWxscykge1xuICAgICAgICAgICAgY29uc3QgcGVuZGluZ19jYWxsID0gQWpheC5fcGVuZGluZ19jYWxsc1tjYWxsX2tleV07XG5cbiAgICAgICAgICAgIGlmICghcGVuZGluZ19jYWxsLmlzX2NvbXBsZXRlKSB7XG4gICAgICAgICAgICAgICAgY2FsbHNfdG9fc2VuZC5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgY2FsbF9pZDogcGVuZGluZ19jYWxsLmNhbGxfaWQsXG4gICAgICAgICAgICAgICAgICAgIGNvbnRyb2xsZXI6IHBlbmRpbmdfY2FsbC5jb250cm9sbGVyLFxuICAgICAgICAgICAgICAgICAgICBhY3Rpb246IHBlbmRpbmdfY2FsbC5hY3Rpb24sXG4gICAgICAgICAgICAgICAgICAgIHBhcmFtczogcGVuZGluZ19jYWxsLnBhcmFtcyxcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIGNhbGxfbWFwW3BlbmRpbmdfY2FsbC5jYWxsX2lkXSA9IHBlbmRpbmdfY2FsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE5vdGhpbmcgdG8gc2VuZFxuICAgICAgICBpZiAoY2FsbHNfdG9fc2VuZC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIExvZyBiYXRjaCBmb3IgZGVidWdnaW5nXG4gICAgICAgIGlmICh0eXBlb2YgRGVidWdnZXIgIT09ICd1bmRlZmluZWQnICYmIERlYnVnZ2VyLmNvbnNvbGVfZGVidWcpIHtcbiAgICAgICAgICAgIERlYnVnZ2VyLmNvbnNvbGVfZGVidWcoXG4gICAgICAgICAgICAgICAgJ0FKQVhfQkFUQ0gnLFxuICAgICAgICAgICAgICAgIGBTZW5kaW5nIGJhdGNoIG9mICR7Y2FsbHNfdG9fc2VuZC5sZW5ndGh9IGNhbGxzYCxcbiAgICAgICAgICAgICAgICBjYWxsc190b19zZW5kLm1hcCgoYykgPT4gYCR7Yy5jb250cm9sbGVyfS4ke2MuYWN0aW9ufWApXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFNlbmQgYmF0Y2ggcmVxdWVzdFxuICAgICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCAkLmFqYXgoe1xuICAgICAgICAgICAgICAgIHVybDogJy9fYWpheC9fYmF0Y2gnLFxuICAgICAgICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICAgICAgICAgIGRhdGE6IHsgYmF0Y2hfY2FsbHM6IEpTT04uc3RyaW5naWZ5KGNhbGxzX3RvX3NlbmQpIH0sXG4gICAgICAgICAgICAgICAgZGF0YVR5cGU6ICdqc29uJyxcbiAgICAgICAgICAgICAgICBfX2xvY2FsX2ludGVncmF0aW9uOiB0cnVlLCAvLyBCeXBhc3MgJC5hamF4IG92ZXJyaWRlXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gUHJvY2VzcyBiYXRjaCByZXNwb25zZVxuICAgICAgICAgICAgLy8gUmVzcG9uc2UgZm9ybWF0OiB7IENfMDoge3N1Y2Nlc3MsIF9hamF4X3JldHVybl92YWx1ZX0sIENfMTogey4uLn0sIC4uLiB9XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHJlc3BvbnNlX2tleSBpbiByZXNwb25zZSkge1xuICAgICAgICAgICAgICAgIGlmICghcmVzcG9uc2Vfa2V5LnN0YXJ0c1dpdGgoJ0NfJykpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgY29uc3QgY2FsbF9pZCA9IHBhcnNlSW50KHJlc3BvbnNlX2tleS5zdWJzdHJpbmcoMiksIDEwKTtcbiAgICAgICAgICAgICAgICBjb25zdCBjYWxsX3Jlc3BvbnNlID0gcmVzcG9uc2VbcmVzcG9uc2Vfa2V5XTtcbiAgICAgICAgICAgICAgICBjb25zdCBwZW5kaW5nX2NhbGwgPSBjYWxsX21hcFtjYWxsX2lkXTtcblxuICAgICAgICAgICAgICAgIGlmICghcGVuZGluZ19jYWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ1JlY2VpdmVkIHJlc3BvbnNlIGZvciB1bmtub3duIGNhbGxfaWQ6JywgY2FsbF9pZCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIEhhbmRsZSBjb25zb2xlX2RlYnVnIG1lc3NhZ2VzIGlmIHByZXNlbnRcbiAgICAgICAgICAgICAgICBpZiAoY2FsbF9yZXNwb25zZS5jb25zb2xlX2RlYnVnICYmIEFycmF5LmlzQXJyYXkoY2FsbF9yZXNwb25zZS5jb25zb2xlX2RlYnVnKSkge1xuICAgICAgICAgICAgICAgICAgICBjYWxsX3Jlc3BvbnNlLmNvbnNvbGVfZGVidWcuZm9yRWFjaCgobXNnKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkobXNnKSB8fCBtc2cubGVuZ3RoICE9PSAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvbnNvbGVfZGVidWcgbWVzc2FnZSBmb3JtYXQgLSBleHBlY3RlZCBbY2hhbm5lbCwgW2FyZ3VtZW50c11dJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBbY2hhbm5lbCwgYXJnc10gPSBtc2c7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhjaGFubmVsLCAuLi5hcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gTWFyayBjYWxsIGFzIGNvbXBsZXRlXG4gICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmlzX2NvbXBsZXRlID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgIC8vIENoZWNrIGlmIHN1Y2Nlc3NmdWxcbiAgICAgICAgICAgICAgICBpZiAoY2FsbF9yZXNwb25zZS5fc3VjY2VzcyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBASlMtQUpBWC0wMi1FWENFUFRJT04gLSBCYXRjaCBzeXN0ZW0gdW53cmFwcyBzZXJ2ZXIgcmVzcG9uc2VzIHdpdGggX2FqYXhfcmV0dXJuX3ZhbHVlXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByb2Nlc3NlZF92YWx1ZSA9IFJzeF9Kc19Nb2RlbC5faW5zdGFudGlhdGVfbW9kZWxzX3JlY3Vyc2l2ZShjYWxsX3Jlc3BvbnNlLl9hamF4X3JldHVybl92YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIHBlbmRpbmdfY2FsbC5yZXN1bHQgPSBwcm9jZXNzZWRfdmFsdWU7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVzb2x2ZSBhbGwgY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgICAgIHBlbmRpbmdfY2FsbC5jYWxsYmFja3MuZm9yRWFjaCgoeyByZXNvbHZlIH0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUocHJvY2Vzc2VkX3ZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gSGFuZGxlIGVycm9yXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yX3R5cGUgPSBjYWxsX3Jlc3BvbnNlLmVycm9yX3R5cGUgfHwgJ3Vua25vd25fZXJyb3InO1xuICAgICAgICAgICAgICAgICAgICBsZXQgZXJyb3JfbWVzc2FnZTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGVycm9yX2RldGFpbHM7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9yX3R5cGUgPT09ICdmYXRhbCcgJiYgY2FsbF9yZXNwb25zZS5lcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRmF0YWwgUEhQIGVycm9yIHdpdGggZnVsbCBlcnJvciBkZXRhaWxzXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBmYXRhbF9lcnJvcl9kYXRhID0gY2FsbF9yZXNwb25zZS5lcnJvcjtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX21lc3NhZ2UgPSBmYXRhbF9lcnJvcl9kYXRhLmVycm9yIHx8ICdGYXRhbCBlcnJvciBvY2N1cnJlZCc7XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9kZXRhaWxzID0gY2FsbF9yZXNwb25zZS5lcnJvcjtcblxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignQWpheCBlcnJvciByZXNwb25zZSBmcm9tIHNlcnZlcjonLCBjYWxsX3Jlc3BvbnNlLmVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE90aGVyIGVycm9yIHR5cGVzXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlID0gY2FsbF9yZXNwb25zZS5yZWFzb24gfHwgJ1Vua25vd24gZXJyb3Igb2NjdXJyZWQnO1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfZGV0YWlscyA9IGNhbGxfcmVzcG9uc2UuZGV0YWlscyB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKGVycm9yX21lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICBlcnJvci50eXBlID0gZXJyb3JfdHlwZTtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3IuZGV0YWlscyA9IGVycm9yX2RldGFpbHM7XG5cbiAgICAgICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmlzX2Vycm9yID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmVycm9yID0gZXJyb3I7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVqZWN0IGFsbCBjYWxsYmFja3NcbiAgICAgICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmNhbGxiYWNrcy5mb3JFYWNoKCh7IHJlamVjdCB9KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKHhocl9lcnJvcikge1xuICAgICAgICAgICAgLy8gTmV0d29yayBvciBzZXJ2ZXIgZXJyb3IgLSByZWplY3QgYWxsIHBlbmRpbmcgY2FsbHNcbiAgICAgICAgICAgIGNvbnN0IGVycm9yX21lc3NhZ2UgPSBBamF4Ll9leHRyYWN0X2Vycm9yX21lc3NhZ2UoeGhyX2Vycm9yKTtcbiAgICAgICAgICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKGVycm9yX21lc3NhZ2UpO1xuICAgICAgICAgICAgZXJyb3IudHlwZSA9ICduZXR3b3JrX2Vycm9yJztcblxuICAgICAgICAgICAgZm9yIChjb25zdCBjYWxsX2lkIGluIGNhbGxfbWFwKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGVuZGluZ19jYWxsID0gY2FsbF9tYXBbY2FsbF9pZF07XG4gICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmlzX2NvbXBsZXRlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBwZW5kaW5nX2NhbGwuaXNfZXJyb3IgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHBlbmRpbmdfY2FsbC5lcnJvciA9IGVycm9yO1xuXG4gICAgICAgICAgICAgICAgcGVuZGluZ19jYWxsLmNhbGxiYWNrcy5mb3JFYWNoKCh7IHJlamVjdCB9KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0JhdGNoIEFqYXggcmVxdWVzdCBmYWlsZWQ6JywgZXJyb3JfbWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZW5lcmF0ZSBhIHVuaXF1ZSBrZXkgZm9yIGRlZHVwbGljYXRpbmcgY2FsbHNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfZ2VuZXJhdGVfY2FsbF9rZXkoY29udHJvbGxlciwgYWN0aW9uLCBwYXJhbXMpIHtcbiAgICAgICAgLy8gQ3JlYXRlIGEgc3RhYmxlIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2FsbFxuICAgICAgICAvLyBTb3J0IHBhcmFtcyBrZXlzIGZvciBjb25zaXN0ZW50IGhhc2hpbmdcbiAgICAgICAgY29uc3Qgc29ydGVkX3BhcmFtcyA9IHt9O1xuICAgICAgICBPYmplY3Qua2V5cyhwYXJhbXMpXG4gICAgICAgICAgICAuc29ydCgpXG4gICAgICAgICAgICAuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICAgICAgICAgICAgc29ydGVkX3BhcmFtc1trZXldID0gcGFyYW1zW2tleV07XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gYCR7Y29udHJvbGxlcn06OiR7YWN0aW9ufTo6JHtKU09OLnN0cmluZ2lmeShzb3J0ZWRfcGFyYW1zKX1gO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEV4dHJhY3QgZXJyb3IgbWVzc2FnZSBmcm9tIGpRdWVyeSBYSFIgb2JqZWN0XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX2V4dHJhY3RfZXJyb3JfbWVzc2FnZSh4aHIpIHtcbiAgICAgICAgaWYgKHhoci5yZXNwb25zZUpTT04gJiYgeGhyLnJlc3BvbnNlSlNPTi5tZXNzYWdlKSB7XG4gICAgICAgICAgICByZXR1cm4geGhyLnJlc3BvbnNlSlNPTi5tZXNzYWdlO1xuICAgICAgICB9IGVsc2UgaWYgKHhoci5yZXNwb25zZVRleHQpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBKU09OLnBhcnNlKHhoci5yZXNwb25zZVRleHQpO1xuICAgICAgICAgICAgICAgIGlmIChyZXNwb25zZS5tZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5tZXNzYWdlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAvLyBOb3QgSlNPTlxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGAke3hoci5zdGF0dXN9OiAke3hoci5zdGF0dXNUZXh0IHx8ICdVbmtub3duIGVycm9yJ31gO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBhcnNlcyBhbiBBSkFYIFVSTCBpbnRvIGNvbnRyb2xsZXIgYW5kIGFjdGlvblxuICAgICAqIFN1cHBvcnRzIGJvdGggL19hamF4LyBhbmQgL18vIFVSTCBwcmVmaXhlc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdHxmdW5jdGlvbn0gdXJsIC0gVVJMIGluIGZvcm1hdCAnL19hamF4L0NvbnRyb2xsZXJfTmFtZS9hY3Rpb25fbmFtZScgb3IgJy9fL0NvbnRyb2xsZXJfTmFtZS9hY3Rpb25fbmFtZScsIG9yIGFuIG9iamVjdC9mdW5jdGlvbiB3aXRoIGEgLnBhdGggcHJvcGVydHlcbiAgICAgKiBAcmV0dXJucyB7T2JqZWN0fSBPYmplY3Qgd2l0aCB7Y29udHJvbGxlcjogc3RyaW5nLCBhY3Rpb246IHN0cmluZ31cbiAgICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgVVJMIGRvZXNuJ3Qgc3RhcnQgd2l0aCAvX2FqYXggb3IgL18gb3IgaGFzIGludmFsaWQgc3RydWN0dXJlXG4gICAgICovXG4gICAgc3RhdGljIGFqYXhfdXJsX3RvX2NvbnRyb2xsZXJfYWN0aW9uKHVybCkge1xuICAgICAgICAvLyBJZiB1cmwgaXMgYW4gb2JqZWN0IG9yIGZ1bmN0aW9uIHdpdGggYSAucGF0aCBwcm9wZXJ0eSwgdXNlIHRoYXQgYXMgdGhlIFVSTFxuICAgICAgICBpZiAodXJsICYmIHR5cGVvZiB1cmwgPT09ICdvYmplY3QnICYmIHVybC5wYXRoKSB7XG4gICAgICAgICAgICB1cmwgPSB1cmwucGF0aDtcbiAgICAgICAgfSBlbHNlIGlmICh1cmwgJiYgdHlwZW9mIHVybCA9PT0gJ2Z1bmN0aW9uJyAmJiB1cmwucGF0aCkge1xuICAgICAgICAgICAgdXJsID0gdXJsLnBhdGg7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBWYWxpZGF0ZSB1cmwgaXMgYSBzdHJpbmdcbiAgICAgICAgaWYgKHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVSTCBtdXN0IGJlIGEgc3RyaW5nIG9yIGhhdmUgYSAucGF0aCBwcm9wZXJ0eSwgZ290OiAke3R5cGVvZiB1cmx9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXVybC5zdGFydHNXaXRoKCcvX2FqYXgnKSAmJiAhdXJsLnN0YXJ0c1dpdGgoJy9fLycpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVSTCBtdXN0IHN0YXJ0IHdpdGggL19hamF4IG9yIC9fLCBnb3Q6ICR7dXJsfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcGFydHMgPSB1cmwuc3BsaXQoJy8nKS5maWx0ZXIoKHBhcnQpID0+IHBhcnQgIT09ICcnKTtcblxuICAgICAgICBpZiAocGFydHMubGVuZ3RoIDwgMikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIEFKQVggVVJMIHN0cnVjdHVyZTogJHt1cmx9YCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocGFydHMubGVuZ3RoID4gMykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBBSkFYIFVSTCBoYXMgdG9vIG1hbnkgc2VnbWVudHM6ICR7dXJsfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY29udHJvbGxlciA9IHBhcnRzWzFdO1xuICAgICAgICBjb25zdCBhY3Rpb24gPSBwYXJ0c1syXSB8fCAnaW5kZXgnO1xuXG4gICAgICAgIHJldHVybiB7IGNvbnRyb2xsZXIsIGFjdGlvbiB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEF1dG8taW5pdGlhbGl6ZSBzdGF0aWMgcHJvcGVydGllcyB3aGVuIGNsYXNzIGlzIGZpcnN0IGxvYWRlZFxuICAgICAqL1xuICAgIHN0YXRpYyBvbl9jb3JlX2RlZmluZSgpIHtcbiAgICAgICAgQWpheC5fb25fZnJhbWV3b3JrX2NvcmVfaW5pdCgpO1xuICAgIH1cbn1cbiJdLCJtYXBw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