"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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