Files
rspade_system/storage-broken/rsx-tmp/babel_fe93a9b8e4cc5cffa55f634274fab75d.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

463 lines
58 KiB
JavaScript
Executable File

"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;
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJGb3JtX1V0aWxzIiwiX29uX2ZyYW1ld29ya19jb3JlX2RlZmluZSIsInBhcmFtcyIsImFyZ3VtZW50cyIsImxlbmd0aCIsInVuZGVmaW5lZCIsIiQiLCJmbiIsImFqYXhfc3VibWl0Iiwib3B0aW9ucyIsIiRlbGVtZW50IiwiaXMiLCJFcnJvciIsInVybCIsImF0dHIiLCJjb250cm9sbGVyIiwiYWN0aW9uIiwiQWpheCIsImFqYXhfdXJsX3RvX2NvbnRyb2xsZXJfYWN0aW9uIiwiYXBwbHlfZm9ybV9lcnJvcnMiLCJwYXJlbnRfc2VsZWN0b3IiLCJlcnJvcnMiLCJjb25zb2xlIiwiZXJyb3IiLCIkcGFyZW50IiwicmVzZXRfZm9ybV9lcnJvcnMiLCJub3JtYWxpemVkIiwiX25vcm1hbGl6ZV9lcnJvcnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsImFuaW1hdGlvbnMiLCJ0eXBlIiwiX2FwcGx5X2dlbmVyYWxfZXJyb3JzIiwiZGF0YSIsImRlZHVwbGljYXRlZCIsIl9kZWR1cGxpY2F0ZV9lcnJvcnMiLCJyZXN1bHQiLCJfYXBwbHlfZmllbGRfZXJyb3JzIiwibWF0Y2hlZF9jb3VudCIsIk9iamVjdCIsImtleXMiLCJ1bm1hdGNoZWQiLCJ1bm1hdGNoZWRfZGVkdXBsaWNhdGVkIiwidW5tYXRjaGVkX2NvdW50Iiwic3VtbWFyeV9tc2ciLCJzdW1tYXJ5X2FuaW1hdGlvbnMiLCJfYXBwbHlfY29tYmluZWRfZXJyb3IiLCJwdXNoIiwiYWxsIiwidGhlbiIsIiRlcnJvcl9jb250YWluZXIiLCJmaW5kIiwiZmlyc3QiLCJjb250YWluZXJfdG9wIiwib2Zmc2V0IiwidG9wIiwiZml4ZWRfaGVhZGVyX2hlaWdodCIsIl9nZXRfZml4ZWRfaGVhZGVyX2hlaWdodCIsInRhcmdldF9zY3JvbGwiLCJhbmltYXRlIiwic2Nyb2xsVG9wIiwicmVzZXQiLCJmb3JtX3NlbGVjdG9yIiwiJGZvcm0iLCJ0cmlnZ2VyIiwic2VyaWFsaXplIiwic2VyaWFsaXplQXJyYXkiLCJmb3JFYWNoIiwiaXRlbSIsIm5hbWUiLCJ2YWx1ZSIsImZvcm1fZGF0YSIsInJlc3BvbnNlIiwiY2FsbCIsIm9uX3N1Y2Nlc3MiLCJkZXRhaWxzIiwibWVzc2FnZSIsIm9uX2Vycm9yIiwicmVtb3ZlIiwicmVtb3ZlQ2xhc3MiLCJBcnJheSIsImlzQXJyYXkiLCJldmVyeSIsImUiLCJ1bndyYXBwZWQiLCJmaWVsZCIsImhhc093blByb3BlcnR5IiwiU3RyaW5nIiwiU2V0Iiwic2VlbiIsImtleSIsImhhcyIsImFkZCIsImZpZWxkX2Vycm9ycyIsImZpZWxkX25hbWUiLCJlcnJvcl9tZXNzYWdlIiwiJGlucHV0IiwiJGVycm9yIiwiaHRtbCIsIiR0YXJnZXQiLCJjbG9zZXN0IiwiYWRkQ2xhc3MiLCJhcHBlbmRUbyIsImhpZGUiLCJmYWRlSW4iLCJwcm9taXNlIiwidW5tYXRjaGVkX2Vycm9ycyIsIiRhbGVydCIsInRleHQiLCIkbGlzdCIsImVycm9yX21zZyIsInByZXBlbmRUbyIsIm1lc3NhZ2VzIiwibXNnIiwidHJpbSIsImVycm9yX2xpc3QiLCJ2YWx1ZXMiLCJtYXAiLCJ2IiwiZmlsdGVyIiwidG90YWxfaGVpZ2h0IiwiZWFjaCIsIiRlbCIsInBvc2l0aW9uIiwiY3NzIiwicGFyc2VJbnQiLCJ3aWR0aCIsIm91dGVyV2lkdGgiLCJ2aWV3cG9ydF93aWR0aCIsIndpbmRvdyIsIm91dGVySGVpZ2h0Il0sInNvdXJjZXMiOlsiYXBwL1JTcGFkZS9Db3JlL0pzL0Zvcm1fVXRpbHMuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGb3JtIHV0aWxpdGllcyBmb3IgdmFsaWRhdGlvbiBhbmQgZXJyb3IgaGFuZGxpbmdcbiAqL1xuY2xhc3MgRm9ybV9VdGlscyB7XG4gICAgLyoqXG4gICAgICogRnJhbWV3b3JrIGluaXRpYWxpemF0aW9uIGhvb2sgdG8gcmVnaXN0ZXIgalF1ZXJ5IHBsdWdpblxuICAgICAqIENyZWF0ZXMgJC5mbi5hamF4X3N1Ym1pdCgpIGZvciBmb3JtIGVsZW1lbnRzXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX29uX2ZyYW1ld29ya19jb3JlX2RlZmluZShwYXJhbXMgPSB7fSkge1xuICAgICAgICAkLmZuLmFqYXhfc3VibWl0ID0gZnVuY3Rpb24ob3B0aW9ucyA9IHt9KSB7XG4gICAgICAgICAgICBjb25zdCAkZWxlbWVudCA9ICQodGhpcyk7XG5cbiAgICAgICAgICAgIGlmICghJGVsZW1lbnQuaXMoJ2Zvcm0nKSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignYWpheF9zdWJtaXQoKSBjYW4gb25seSBiZSBjYWxsZWQgb24gZm9ybSBlbGVtZW50cycpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCB1cmwgPSAkZWxlbWVudC5hdHRyKCdhY3Rpb24nKTtcbiAgICAgICAgICAgIGlmICghdXJsKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGb3JtIG11c3QgaGF2ZSBhbiBhY3Rpb24gYXR0cmlidXRlJyk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHsgY29udHJvbGxlciwgYWN0aW9uIH0gPSBBamF4LmFqYXhfdXJsX3RvX2NvbnRyb2xsZXJfYWN0aW9uKHVybCk7XG5cbiAgICAgICAgICAgIHJldHVybiBGb3JtX1V0aWxzLmFqYXhfc3VibWl0KCRlbGVtZW50LCBjb250cm9sbGVyLCBhY3Rpb24sIG9wdGlvbnMpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3dzIGZvcm0gdmFsaWRhdGlvbiBlcnJvcnNcbiAgICAgKlxuICAgICAqIFJFUVVJUkVEIEhUTUwgU1RSVUNUVVJFOlxuICAgICAqIEZvciBpbmxpbmUgZmllbGQgZXJyb3JzIHRvIGRpc3BsYXkgcHJvcGVybHksIGZvcm0gZmllbGRzIG11c3QgZm9sbG93IHRoaXMgc3RydWN0dXJlOlxuICAgICAqXG4gICAgICogPGRpdiBjbGFzcz1cImZvcm0tZ3JvdXBcIj5cbiAgICAgKiAgIDxsYWJlbCBjbGFzcz1cImZvcm0tbGFiZWxcIiBmb3I9XCJmaWVsZC1uYW1lXCI+RmllbGQgTGFiZWw8L2xhYmVsPlxuICAgICAqICAgPGlucHV0IGNsYXNzPVwiZm9ybS1jb250cm9sXCIgaWQ9XCJmaWVsZC1uYW1lXCIgbmFtZT1cImZpZWxkLW5hbWVcIiB0eXBlPVwidGV4dFwiPlxuICAgICAqIDwvZGl2PlxuICAgICAqXG4gICAgICogS2V5IHJlcXVpcmVtZW50czpcbiAgICAgKiAtIFdyYXAgZWFjaCBmaWVsZCBpbiBhIGNvbnRhaW5lciB3aXRoIGNsYXNzIFwiZm9ybS1ncm91cFwiIChvciBcImZvcm0tY2hlY2tcIiAvIFwiaW5wdXQtZ3JvdXBcIilcbiAgICAgKiAtIElucHV0IG11c3QgaGF2ZSBhIFwibmFtZVwiIGF0dHJpYnV0ZSBtYXRjaGluZyB0aGUgZXJyb3Iga2V5XG4gICAgICogLSBVc2UgXCJmb3JtLWNvbnRyb2xcIiBjbGFzcyBvbiBpbnB1dHMgZm9yIEJvb3RzdHJhcCA1IHN0eWxpbmdcbiAgICAgKlxuICAgICAqIEFjY2VwdHMgdGhyZWUgZm9ybWF0czpcbiAgICAgKiAtIFN0cmluZzogU2luZ2xlIGVycm9yIHNob3duIGFzIGFsZXJ0XG4gICAgICogLSBBcnJheSBvZiBzdHJpbmdzOiBNdWx0aXBsZSBlcnJvcnMgc2hvd24gYXMgYnVsbGV0ZWQgYWxlcnRcbiAgICAgKiAtIE9iamVjdDogRmllbGQgbmFtZXMgbWFwcGVkIHRvIGVycm9ycywgc2hvd24gaW5saW5lICh1bm1hdGNoZWQgc2hvd24gYXMgYWxlcnQpXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyZW50X3NlbGVjdG9yIC0galF1ZXJ5IHNlbGVjdG9yIGZvciBwYXJlbnQgZWxlbWVudFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfE9iamVjdHxBcnJheX0gZXJyb3JzIC0gRXJyb3IgbWVzc2FnZXMgdG8gZGlzcGxheVxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlfSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBhbGwgYW5pbWF0aW9ucyBjb21wbGV0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBhcHBseV9mb3JtX2Vycm9ycyhwYXJlbnRfc2VsZWN0b3IsIGVycm9ycykge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9ycyk7XG5cbiAgICAgICAgY29uc3QgJHBhcmVudCA9ICQocGFyZW50X3NlbGVjdG9yKTtcblxuICAgICAgICAvLyBSZXNldCB0aGUgZm9ybSBlcnJvcnMgYmVmb3JlIGFwcGx5aW5nIG5ldyBvbmVzXG4gICAgICAgIEZvcm1fVXRpbHMucmVzZXRfZm9ybV9lcnJvcnMocGFyZW50X3NlbGVjdG9yKTtcblxuICAgICAgICAvLyBOb3JtYWxpemUgaW5wdXQgdG8gc3RhbmRhcmQgZm9ybWF0XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBGb3JtX1V0aWxzLl9ub3JtYWxpemVfZXJyb3JzKGVycm9ycyk7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgICBsZXQgYW5pbWF0aW9ucyA9IFtdO1xuXG4gICAgICAgICAgICBpZiAobm9ybWFsaXplZC50eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgIC8vIFNpbmdsZSBlcnJvciBtZXNzYWdlXG4gICAgICAgICAgICAgICAgYW5pbWF0aW9ucyA9IEZvcm1fVXRpbHMuX2FwcGx5X2dlbmVyYWxfZXJyb3JzKCRwYXJlbnQsIG5vcm1hbGl6ZWQuZGF0YSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG5vcm1hbGl6ZWQudHlwZSA9PT0gJ2FycmF5Jykge1xuICAgICAgICAgICAgICAgIC8vIEFycmF5IG9mIGVycm9yIG1lc3NhZ2VzXG4gICAgICAgICAgICAgICAgY29uc3QgZGVkdXBsaWNhdGVkID0gRm9ybV9VdGlscy5fZGVkdXBsaWNhdGVfZXJyb3JzKG5vcm1hbGl6ZWQuZGF0YSk7XG4gICAgICAgICAgICAgICAgYW5pbWF0aW9ucyA9IEZvcm1fVXRpbHMuX2FwcGx5X2dlbmVyYWxfZXJyb3JzKCRwYXJlbnQsIGRlZHVwbGljYXRlZCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG5vcm1hbGl6ZWQudHlwZSA9PT0gJ2ZpZWxkcycpIHtcbiAgICAgICAgICAgICAgICAvLyBGaWVsZC1zcGVjaWZpYyBlcnJvcnNcbiAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBGb3JtX1V0aWxzLl9hcHBseV9maWVsZF9lcnJvcnMoJHBhcmVudCwgbm9ybWFsaXplZC5kYXRhKTtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25zID0gcmVzdWx0LmFuaW1hdGlvbnM7XG5cbiAgICAgICAgICAgICAgICAvLyBDb3VudCBtYXRjaGVkIGZpZWxkc1xuICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoZWRfY291bnQgPSBPYmplY3Qua2V5cyhub3JtYWxpemVkLmRhdGEpLmxlbmd0aCAtIE9iamVjdC5rZXlzKHJlc3VsdC51bm1hdGNoZWQpLmxlbmd0aDtcbiAgICAgICAgICAgICAgICBjb25zdCB1bm1hdGNoZWRfZGVkdXBsaWNhdGVkID0gRm9ybV9VdGlscy5fZGVkdXBsaWNhdGVfZXJyb3JzKHJlc3VsdC51bm1hdGNoZWQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHVubWF0Y2hlZF9jb3VudCA9IE9iamVjdC5rZXlzKHVubWF0Y2hlZF9kZWR1cGxpY2F0ZWQpLmxlbmd0aDtcblxuICAgICAgICAgICAgICAgIC8vIFNob3cgc3VtbWFyeSBhbGVydCBpZiB0aGVyZSBhcmUgYW55IGZpZWxkIGVycm9ycyAobWF0Y2hlZCBvciB1bm1hdGNoZWQpXG4gICAgICAgICAgICAgICAgaWYgKG1hdGNoZWRfY291bnQgPiAwIHx8IHVubWF0Y2hlZF9jb3VudCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQnVpbGQgc3VtbWFyeSBtZXNzYWdlXG4gICAgICAgICAgICAgICAgICAgIGxldCBzdW1tYXJ5X21zZyA9ICcnO1xuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2hlZF9jb3VudCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcnlfbXNnID0gbWF0Y2hlZF9jb3VudCA9PT0gMVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gJ1BsZWFzZSBjb3JyZWN0IHRoZSBlcnJvciBoaWdobGlnaHRlZCBiZWxvdy4nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgOiAnUGxlYXNlIGNvcnJlY3QgdGhlIGVycm9ycyBoaWdobGlnaHRlZCBiZWxvdy4nO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlcmUgYXJlIHVubWF0Y2hlZCBlcnJvcnMsIGFkZCB0aGVtIGFzIGEgYnVsbGV0ZWQgbGlzdFxuICAgICAgICAgICAgICAgICAgICBpZiAodW5tYXRjaGVkX2NvdW50ID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3VtbWFyeV9hbmltYXRpb25zID0gRm9ybV9VdGlscy5fYXBwbHlfY29tYmluZWRfZXJyb3IoJHBhcmVudCwgc3VtbWFyeV9tc2csIHVubWF0Y2hlZF9kZWR1cGxpY2F0ZWQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYW5pbWF0aW9ucy5wdXNoKC4uLnN1bW1hcnlfYW5pbWF0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBKdXN0IHRoZSBzdW1tYXJ5IG1lc3NhZ2UsIG5vIHVubWF0Y2hlZCBlcnJvcnNcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHN1bW1hcnlfYW5pbWF0aW9ucyA9IEZvcm1fVXRpbHMuX2FwcGx5X2dlbmVyYWxfZXJyb3JzKCRwYXJlbnQsIHN1bW1hcnlfbXNnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFuaW1hdGlvbnMucHVzaCguLi5zdW1tYXJ5X2FuaW1hdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBSZXNvbHZlIHRoZSBwcm9taXNlIG9uY2UgYWxsIGFuaW1hdGlvbnMgYXJlIGNvbXBsZXRlXG4gICAgICAgICAgICBQcm9taXNlLmFsbChhbmltYXRpb25zKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICAvLyBTY3JvbGwgdG8gZXJyb3IgY29udGFpbmVyIGlmIGl0IGV4aXN0c1xuICAgICAgICAgICAgICAgIGNvbnN0ICRlcnJvcl9jb250YWluZXIgPSAkcGFyZW50LmZpbmQoJ1tkYXRhLWlkPVwiZXJyb3JfY29udGFpbmVyXCJdJykuZmlyc3QoKTtcbiAgICAgICAgICAgICAgICBpZiAoJGVycm9yX2NvbnRhaW5lci5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRhaW5lcl90b3AgPSAkZXJyb3JfY29udGFpbmVyLm9mZnNldCgpLnRvcDtcblxuICAgICAgICAgICAgICAgICAgICAvLyBDYWxjdWxhdGUgZml4ZWQgaGVhZGVyIG9mZnNldFxuICAgICAgICAgICAgICAgICAgICBjb25zdCBmaXhlZF9oZWFkZXJfaGVpZ2h0ID0gRm9ybV9VdGlscy5fZ2V0X2ZpeGVkX2hlYWRlcl9oZWlnaHQoKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBTY3JvbGwgdG8gcG9zaXRpb24gZXJyb3IgY29udGFpbmVyIDIwcHggYmVsb3cgYW55IGZpeGVkIGhlYWRlcnNcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0X3Njcm9sbCA9IGNvbnRhaW5lcl90b3AgLSBmaXhlZF9oZWFkZXJfaGVpZ2h0IC0gMjA7XG4gICAgICAgICAgICAgICAgICAgICQoJ2h0bWwsIGJvZHknKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjcm9sbFRvcDogdGFyZ2V0X3Njcm9sbFxuICAgICAgICAgICAgICAgICAgICB9LCA1MDApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGVhcnMgZm9ybSB2YWxpZGF0aW9uIGVycm9ycyBhbmQgcmVzZXRzIGFsbCBmb3JtIHZhbHVlcyB0byBkZWZhdWx0c1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfGpRdWVyeX0gZm9ybV9zZWxlY3RvciAtIGpRdWVyeSBzZWxlY3RvciBvciBqUXVlcnkgb2JqZWN0IGZvciBmb3JtIGVsZW1lbnRcbiAgICAgKi9cbiAgICBzdGF0aWMgcmVzZXQoZm9ybV9zZWxlY3Rvcikge1xuICAgICAgICBjb25zdCAkZm9ybSA9IHR5cGVvZiBmb3JtX3NlbGVjdG9yID09PSAnc3RyaW5nJyA/ICQoZm9ybV9zZWxlY3RvcikgOiBmb3JtX3NlbGVjdG9yO1xuXG4gICAgICAgIEZvcm1fVXRpbHMucmVzZXRfZm9ybV9lcnJvcnMoZm9ybV9zZWxlY3Rvcik7XG4gICAgICAgICRmb3JtLnRyaWdnZXIoJ3Jlc2V0Jyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VyaWFsaXplcyBmb3JtIGRhdGEgaW50byBrZXktdmFsdWUgb2JqZWN0XG4gICAgICogUmV0dXJucyBhbGwgaW5wdXQgZWxlbWVudHMgd2l0aCBuYW1lIGF0dHJpYnV0ZXMgYXMgb2JqZWN0IHByb3BlcnRpZXNcbiAgICAgKiBAcGFyYW0ge3N0cmluZ3xqUXVlcnl9IGZvcm1fc2VsZWN0b3IgLSBqUXVlcnkgc2VsZWN0b3Igb3IgalF1ZXJ5IG9iamVjdCBmb3IgZm9ybSBlbGVtZW50XG4gICAgICogQHJldHVybnMge09iamVjdH0gRm9ybSBkYXRhIGFzIGtleS12YWx1ZSBwYWlyc1xuICAgICAqL1xuICAgIHN0YXRpYyBzZXJpYWxpemUoZm9ybV9zZWxlY3Rvcikge1xuICAgICAgICBjb25zdCAkZm9ybSA9IHR5cGVvZiBmb3JtX3NlbGVjdG9yID09PSAnc3RyaW5nJyA/ICQoZm9ybV9zZWxlY3RvcikgOiBmb3JtX3NlbGVjdG9yO1xuICAgICAgICBjb25zdCBkYXRhID0ge307XG5cbiAgICAgICAgJGZvcm0uc2VyaWFsaXplQXJyYXkoKS5mb3JFYWNoKChpdGVtKSA9PiB7XG4gICAgICAgICAgICBkYXRhW2l0ZW0ubmFtZV0gPSBpdGVtLnZhbHVlO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTdWJtaXRzIGZvcm0gdG8gUlNYIGNvbnRyb2xsZXIgYWN0aW9uIHZpYSBBSkFYXG4gICAgICogQHBhcmFtIHtzdHJpbmd8alF1ZXJ5fSBmb3JtX3NlbGVjdG9yIC0galF1ZXJ5IHNlbGVjdG9yIG9yIGpRdWVyeSBvYmplY3QgZm9yIGZvcm0gZWxlbWVudFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjb250cm9sbGVyIC0gQ29udHJvbGxlciBjbGFzcyBuYW1lIChlLmcuLCAnVXNlcl9Db250cm9sbGVyJylcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYWN0aW9uIC0gQWN0aW9uIG1ldGhvZCBuYW1lIChlLmcuLCAnc2F2ZV9wcm9maWxlJylcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24ge29uX3N1Y2Nlc3M6IGZuLCBvbl9lcnJvcjogZm59XG4gICAgICogQHJldHVybnMge1Byb21pc2V9IFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHJlc3BvbnNlIGRhdGFcbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgYWpheF9zdWJtaXQoZm9ybV9zZWxlY3RvciwgY29udHJvbGxlciwgYWN0aW9uLCBvcHRpb25zID0ge30pIHtcbiAgICAgICAgY29uc3QgJGZvcm0gPSB0eXBlb2YgZm9ybV9zZWxlY3RvciA9PT0gJ3N0cmluZycgPyAkKGZvcm1fc2VsZWN0b3IpIDogZm9ybV9zZWxlY3RvcjtcbiAgICAgICAgY29uc3QgZm9ybV9kYXRhID0gRm9ybV9VdGlscy5zZXJpYWxpemUoJGZvcm0pO1xuXG4gICAgICAgIEZvcm1fVXRpbHMucmVzZXRfZm9ybV9lcnJvcnMoZm9ybV9zZWxlY3Rvcik7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgQWpheC5jYWxsKGNvbnRyb2xsZXIsIGFjdGlvbiwgZm9ybV9kYXRhKTtcblxuICAgICAgICAgICAgaWYgKG9wdGlvbnMub25fc3VjY2Vzcykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMub25fc3VjY2VzcyhyZXNwb25zZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGlmIChlcnJvci50eXBlID09PSAnZm9ybV9lcnJvcicgJiYgZXJyb3IuZGV0YWlscykge1xuICAgICAgICAgICAgICAgIGF3YWl0IEZvcm1fVXRpbHMuYXBwbHlfZm9ybV9lcnJvcnMoZm9ybV9zZWxlY3RvciwgZXJyb3IuZGV0YWlscyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGF3YWl0IEZvcm1fVXRpbHMuYXBwbHlfZm9ybV9lcnJvcnMoZm9ybV9zZWxlY3RvciwgZXJyb3IubWVzc2FnZSB8fCAnQW4gZXJyb3Igb2NjdXJyZWQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG9wdGlvbnMub25fZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLm9uX2Vycm9yKGVycm9yKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGZvcm0gdmFsaWRhdGlvbiBlcnJvcnNcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGFyZW50X3NlbGVjdG9yIC0galF1ZXJ5IHNlbGVjdG9yIGZvciBwYXJlbnQgZWxlbWVudFxuICAgICAqL1xuICAgIHN0YXRpYyByZXNldF9mb3JtX2Vycm9ycyhwYXJlbnRfc2VsZWN0b3IpIHtcbiAgICAgICAgY29uc3QgJHBhcmVudCA9ICQocGFyZW50X3NlbGVjdG9yKTtcblxuICAgICAgICAvLyBSZW1vdmUgZmxhc2ggbWVzc2FnZXNcbiAgICAgICAgJCgnLmZsYXNoLW1lc3NhZ2VzJykucmVtb3ZlKCk7XG5cbiAgICAgICAgLy8gUmVtb3ZlIGFsZXJ0LWRhbmdlciBtZXNzYWdlc1xuICAgICAgICAkcGFyZW50LmZpbmQoJy5hbGVydC1kYW5nZXInKS5yZW1vdmUoKTtcblxuICAgICAgICAvLyBSZW1vdmUgdmFsaWRhdGlvbiBlcnJvciBjbGFzc2VzIGFuZCB0ZXh0IGZyb20gZm9ybSBlbGVtZW50c1xuICAgICAgICAkcGFyZW50LmZpbmQoJy5pcy1pbnZhbGlkJykucmVtb3ZlQ2xhc3MoJ2lzLWludmFsaWQnKTtcbiAgICAgICAgJHBhcmVudC5maW5kKCcuaW52YWxpZC1mZWVkYmFjaycpLnJlbW92ZSgpO1xuICAgIH1cblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgLyoqXG4gICAgICogTm9ybWFsaXplcyBlcnJvciBpbnB1dCBpbnRvIHN0YW5kYXJkIGZvcm1hdHNcbiAgICAgKiBAcGFyYW0ge3N0cmluZ3xPYmplY3R8QXJyYXl9IGVycm9ycyAtIFJhdyBlcnJvciBpbnB1dFxuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IE5vcm1hbGl6ZWQgZXJyb3JzIGFzIHt0eXBlOiAnc3RyaW5nJ3wnYXJyYXknfCdmaWVsZHMnLCBkYXRhOiAuLi59XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgX25vcm1hbGl6ZV9lcnJvcnMoZXJyb3JzKSB7XG4gICAgICAgIC8vIEhhbmRsZSBudWxsL3VuZGVmaW5lZFxuICAgICAgICBpZiAoIWVycm9ycykge1xuICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ3N0cmluZycsIGRhdGE6ICdBbiBlcnJvciBoYXMgb2NjdXJyZWQnIH07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBIYW5kbGUgc3RyaW5nXG4gICAgICAgIGlmICh0eXBlb2YgZXJyb3JzID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ3N0cmluZycsIGRhdGE6IGVycm9ycyB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIGFycmF5XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGVycm9ycykpIHtcbiAgICAgICAgICAgIC8vIEFycmF5IG9mIHN0cmluZ3MgLSBnZW5lcmFsIGVycm9yc1xuICAgICAgICAgICAgaWYgKGVycm9ycy5ldmVyeSgoZSkgPT4gdHlwZW9mIGUgPT09ICdzdHJpbmcnKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB7IHR5cGU6ICdhcnJheScsIGRhdGE6IGVycm9ycyB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gQXJyYXkgd2l0aCBvYmplY3QgYXMgZmlyc3QgZWxlbWVudCAtIGV4dHJhY3QgaXRcbiAgICAgICAgICAgIGlmIChlcnJvcnMubGVuZ3RoID4gMCAmJiB0eXBlb2YgZXJyb3JzWzBdID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIHJldHVybiBGb3JtX1V0aWxzLl9ub3JtYWxpemVfZXJyb3JzKGVycm9yc1swXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBFbXB0eSBvciBtaXhlZCBhcnJheVxuICAgICAgICAgICAgcmV0dXJuIHsgdHlwZTogJ2FycmF5JywgZGF0YTogW10gfTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEhhbmRsZSBvYmplY3QgLSBjaGVjayBmb3IgTGFyYXZlbCByZXNwb25zZSB3cmFwcGVyXG4gICAgICAgIGlmICh0eXBlb2YgZXJyb3JzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgLy8gVW53cmFwIHtlcnJvcnM6IHsuLi59fSBvciB7ZXJyb3I6IHsuLi59fVxuICAgICAgICAgICAgY29uc3QgdW53cmFwcGVkID0gZXJyb3JzLmVycm9ycyB8fCBlcnJvcnMuZXJyb3I7XG4gICAgICAgICAgICBpZiAodW53cmFwcGVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIEZvcm1fVXRpbHMuX25vcm1hbGl6ZV9lcnJvcnModW53cmFwcGVkKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ29udmVydCBMYXJhdmVsIHZhbGlkYXRvciBmb3JtYXQge2ZpZWxkOiBbbXNnMSwgbXNnMl19IHRvIHtmaWVsZDogbXNnMX1cbiAgICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSB7fTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgZmllbGQgaW4gZXJyb3JzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycm9ycy5oYXNPd25Qcm9wZXJ0eShmaWVsZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBlcnJvcnNbZmllbGRdO1xuICAgICAgICAgICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkgJiYgdmFsdWUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZFtmaWVsZF0gPSB2YWx1ZVswXTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemVkW2ZpZWxkXSA9IHZhbHVlO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZFtmaWVsZF0gPSBTdHJpbmcodmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4geyB0eXBlOiAnZmllbGRzJywgZGF0YTogbm9ybWFsaXplZCB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRmluYWwgY2F0Y2gtYWxsKlxuICAgICAgICByZXR1cm4geyB0eXBlOiAnc3RyaW5nJywgZGF0YTogU3RyaW5nKGVycm9ycykgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGR1cGxpY2F0ZSBlcnJvciBtZXNzYWdlcyBmcm9tIGFycmF5IG9yIG9iamVjdCB2YWx1ZXNcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gZXJyb3JzIC0gRXJyb3JzIHRvIGRlZHVwbGljYXRlXG4gICAgICogQHJldHVybnMge0FycmF5fE9iamVjdH0gRGVkdXBsaWNhdGVkIGVycm9yc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9kZWR1cGxpY2F0ZV9lcnJvcnMoZXJyb3JzKSB7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGVycm9ycykpIHtcbiAgICAgICAgICAgIHJldHVybiBbLi4ubmV3IFNldChlcnJvcnMpXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgZXJyb3JzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgY29uc3Qgc2VlbiA9IG5ldyBTZXQoKTtcbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IHt9O1xuICAgICAgICAgICAgZm9yIChjb25zdCBrZXkgaW4gZXJyb3JzKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgdmFsdWUgPSBlcnJvcnNba2V5XTtcbiAgICAgICAgICAgICAgICBpZiAoIXNlZW4uaGFzKHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICBzZWVuLmFkZCh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBlcnJvcnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQXBwbGllcyBmaWVsZC1zcGVjaWZpYyB2YWxpZGF0aW9uIGVycm9ycyB0byBmb3JtIGlucHV0c1xuICAgICAqIEBwYXJhbSB7alF1ZXJ5fSAkcGFyZW50IC0gUGFyZW50IGVsZW1lbnQgY29udGFpbmluZyBmb3JtXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGZpZWxkX2Vycm9ycyAtIE9iamVjdCBtYXBwaW5nIGZpZWxkIG5hbWVzIHRvIGVycm9yIG1lc3NhZ2VzXG4gICAgICogQHJldHVybnMge09iamVjdH0gT2JqZWN0IGNvbnRhaW5pbmcge2FuaW1hdGlvbnM6IEFycmF5LCB1bm1hdGNoZWQ6IE9iamVjdH1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfYXBwbHlfZmllbGRfZXJyb3JzKCRwYXJlbnQsIGZpZWxkX2Vycm9ycykge1xuICAgICAgICBjb25zdCBhbmltYXRpb25zID0gW107XG4gICAgICAgIGNvbnN0IHVubWF0Y2hlZCA9IHt9O1xuXG4gICAgICAgIGZvciAoY29uc3QgZmllbGRfbmFtZSBpbiBmaWVsZF9lcnJvcnMpIHtcbiAgICAgICAgICAgIGNvbnN0IGVycm9yX21lc3NhZ2UgPSBmaWVsZF9lcnJvcnNbZmllbGRfbmFtZV07XG4gICAgICAgICAgICBjb25zdCAkaW5wdXQgPSAkcGFyZW50LmZpbmQoYFtuYW1lPVwiJHtmaWVsZF9uYW1lfVwiXWApO1xuXG4gICAgICAgICAgICBpZiAoISRpbnB1dC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB1bm1hdGNoZWRbZmllbGRfbmFtZV0gPSBlcnJvcl9tZXNzYWdlO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCAkZXJyb3IgPSAkKCc8ZGl2IGNsYXNzPVwiaW52YWxpZC1mZWVkYmFja1wiPjwvZGl2PicpLmh0bWwoZXJyb3JfbWVzc2FnZSk7XG4gICAgICAgICAgICBjb25zdCAkdGFyZ2V0ID0gJGlucHV0LmNsb3Nlc3QoJy5mb3JtLWdyb3VwLCAuZm9ybS1jaGVjaywgLmlucHV0LWdyb3VwJyk7XG5cbiAgICAgICAgICAgIGlmICghJHRhcmdldC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB1bm1hdGNoZWRbZmllbGRfbmFtZV0gPSBlcnJvcl9tZXNzYWdlO1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAkaW5wdXQuYWRkQ2xhc3MoJ2lzLWludmFsaWQnKTtcbiAgICAgICAgICAgICRlcnJvci5hcHBlbmRUbygkdGFyZ2V0KTtcbiAgICAgICAgICAgIGFuaW1hdGlvbnMucHVzaCgkZXJyb3IuaGlkZSgpLmZhZGVJbigzMDApLnByb21pc2UoKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4geyBhbmltYXRpb25zLCB1bm1hdGNoZWQgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBcHBsaWVzIGNvbWJpbmVkIGVycm9yIG1lc3NhZ2Ugd2l0aCBzdW1tYXJ5IGFuZCB1bm1hdGNoZWQgZmllbGQgZXJyb3JzXG4gICAgICogQHBhcmFtIHtqUXVlcnl9ICRwYXJlbnQgLSBQYXJlbnQgZWxlbWVudCBjb250YWluaW5nIGZvcm1cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gc3VtbWFyeV9tc2cgLSBTdW1tYXJ5IG1lc3NhZ2UgKGUuZy4sIFwiUGxlYXNlIGNvcnJlY3QgdGhlIGVycm9ycyBiZWxvd1wiKVxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSB1bm1hdGNoZWRfZXJyb3JzIC0gT2JqZWN0IG9mIGZpZWxkIGVycm9ycyB0aGF0IGNvdWxkbid0IGJlIG1hdGNoZWQgdG8gZmllbGRzXG4gICAgICogQHJldHVybnMge0FycmF5fSBBcnJheSBvZiBhbmltYXRpb24gcHJvbWlzZXNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfYXBwbHlfY29tYmluZWRfZXJyb3IoJHBhcmVudCwgc3VtbWFyeV9tc2csIHVubWF0Y2hlZF9lcnJvcnMpIHtcbiAgICAgICAgY29uc3QgYW5pbWF0aW9ucyA9IFtdO1xuICAgICAgICBjb25zdCAkZXJyb3JfY29udGFpbmVyID0gJHBhcmVudC5maW5kKCdbZGF0YS1pZD1cImVycm9yX2NvbnRhaW5lclwiXScpLmZpcnN0KCk7XG4gICAgICAgIGNvbnN0ICR0YXJnZXQgPSAkZXJyb3JfY29udGFpbmVyLmxlbmd0aCA+IDAgPyAkZXJyb3JfY29udGFpbmVyIDogJHBhcmVudDtcblxuICAgICAgICAvLyBDcmVhdGUgYWxlcnQgd2l0aCBzdW1tYXJ5IG1lc3NhZ2UgYW5kIGJ1bGxldGVkIGxpc3Qgb2YgdW5tYXRjaGVkIGVycm9yc1xuICAgICAgICBjb25zdCAkYWxlcnQgPSAkKCc8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtZGFuZ2VyXCIgcm9sZT1cImFsZXJ0XCI+PC9kaXY+Jyk7XG5cbiAgICAgICAgLy8gQWRkIHN1bW1hcnkgbWVzc2FnZSBpZiBwcm92aWRlZFxuICAgICAgICBpZiAoc3VtbWFyeV9tc2cpIHtcbiAgICAgICAgICAgICQoJzxwIGNsYXNzPVwibWItMlwiPjwvcD4nKS50ZXh0KHN1bW1hcnlfbXNnKS5hcHBlbmRUbygkYWxlcnQpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQWRkIHVubWF0Y2hlZCBlcnJvcnMgYXMgYnVsbGV0ZWQgbGlzdFxuICAgICAgICBpZiAoT2JqZWN0LmtleXModW5tYXRjaGVkX2Vycm9ycykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgY29uc3QgJGxpc3QgPSAkKCc8dWwgY2xhc3M9XCJtYi0wXCI+PC91bD4nKTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgZmllbGRfbmFtZSBpbiB1bm1hdGNoZWRfZXJyb3JzKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXJyb3JfbXNnID0gdW5tYXRjaGVkX2Vycm9yc1tmaWVsZF9uYW1lXTtcbiAgICAgICAgICAgICAgICAkKCc8bGk+PC9saT4nKS5odG1sKGVycm9yX21zZykuYXBwZW5kVG8oJGxpc3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgJGxpc3QuYXBwZW5kVG8oJGFsZXJ0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgkZXJyb3JfY29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGFuaW1hdGlvbnMucHVzaCgkYWxlcnQuaGlkZSgpLmFwcGVuZFRvKCR0YXJnZXQpLmZhZGVJbigzMDApLnByb21pc2UoKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhbmltYXRpb25zLnB1c2goJGFsZXJ0LmhpZGUoKS5wcmVwZW5kVG8oJHRhcmdldCkuZmFkZUluKDMwMCkucHJvbWlzZSgpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhbmltYXRpb25zO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFwcGxpZXMgZ2VuZXJhbCBlcnJvciBtZXNzYWdlcyBhcyBhbGVydCBib3hcbiAgICAgKiBAcGFyYW0ge2pRdWVyeX0gJHBhcmVudCAtIFBhcmVudCBlbGVtZW50IHRvIHByZXBlbmQgYWxlcnQgdG9cbiAgICAgKiBAcGFyYW0ge3N0cmluZ3xBcnJheX0gbWVzc2FnZXMgLSBFcnJvciBtZXNzYWdlKHMpIHRvIGRpc3BsYXlcbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9IEFycmF5IG9mIGFuaW1hdGlvbiBwcm9taXNlc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIF9hcHBseV9nZW5lcmFsX2Vycm9ycygkcGFyZW50LCBtZXNzYWdlcykge1xuICAgICAgICBjb25zdCBhbmltYXRpb25zID0gW107XG5cbiAgICAgICAgLy8gTG9vayBmb3IgYSBzcGVjaWZpYyBlcnJvciBjb250YWluZXIgZGl2IChlLmcuLCBpbiBSc3hfRm9ybSBjb21wb25lbnQpXG4gICAgICAgIGNvbnN0ICRlcnJvcl9jb250YWluZXIgPSAkcGFyZW50LmZpbmQoJ1tkYXRhLWlkPVwiZXJyb3JfY29udGFpbmVyXCJdJykuZmlyc3QoKTtcbiAgICAgICAgY29uc3QgJHRhcmdldCA9ICRlcnJvcl9jb250YWluZXIubGVuZ3RoID4gMCA/ICRlcnJvcl9jb250YWluZXIgOiAkcGFyZW50O1xuXG4gICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZXMgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAvLyBTaW5nbGUgZXJyb3IgLSBzaW1wbGUgYWxlcnQgd2l0aG91dCBsaXN0XG4gICAgICAgICAgICBjb25zdCAkYWxlcnQgPSAkKCc8ZGl2IGNsYXNzPVwiYWxlcnQgYWxlcnQtZGFuZ2VyXCIgcm9sZT1cImFsZXJ0XCI+PC9kaXY+JykudGV4dChtZXNzYWdlcyk7XG4gICAgICAgICAgICBpZiAoJGVycm9yX2NvbnRhaW5lci5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYW5pbWF0aW9ucy5wdXNoKCRhbGVydC5oaWRlKCkuYXBwZW5kVG8oJHRhcmdldCkuZmFkZUluKDMwMCkucHJvbWlzZSgpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYW5pbWF0aW9ucy5wdXNoKCRhbGVydC5oaWRlKCkucHJlcGVuZFRvKCR0YXJnZXQpLmZhZGVJbigzMDApLnByb21pc2UoKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShtZXNzYWdlcykgJiYgbWVzc2FnZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgLy8gTXVsdGlwbGUgZXJyb3JzIC0gYnVsbGV0ZWQgbGlzdFxuICAgICAgICAgICAgY29uc3QgJGFsZXJ0ID0gJCgnPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LWRhbmdlclwiIHJvbGU9XCJhbGVydFwiPjx1bCBjbGFzcz1cIm1iLTBcIj48L3VsPjwvZGl2PicpO1xuICAgICAgICAgICAgY29uc3QgJGxpc3QgPSAkYWxlcnQuZmluZCgndWwnKTtcblxuICAgICAgICAgICAgbWVzc2FnZXMuZm9yRWFjaCgobXNnKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGV4dCA9IChtc2cgKyAnJykudHJpbSgpIHx8ICdBbiBlcnJvciBoYXMgb2NjdXJyZWQnO1xuICAgICAgICAgICAgICAgICQoJzxsaT48L2xpPicpLmh0bWwodGV4dCkuYXBwZW5kVG8oJGxpc3QpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGlmICgkZXJyb3JfY29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25zLnB1c2goJGFsZXJ0LmhpZGUoKS5hcHBlbmRUbygkdGFyZ2V0KS5mYWRlSW4oMzAwKS5wcm9taXNlKCkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25zLnB1c2goJGFsZXJ0LmhpZGUoKS5wcmVwZW5kVG8oJHRhcmdldCkuZmFkZUluKDMwMCkucHJvbWlzZSgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbWVzc2FnZXMgPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KG1lc3NhZ2VzKSkge1xuICAgICAgICAgICAgLy8gT2JqZWN0IG9mIHVubWF0Y2hlZCBmaWVsZCBlcnJvcnMgLSBjb252ZXJ0IHRvIGFycmF5XG4gICAgICAgICAgICBjb25zdCBlcnJvcl9saXN0ID0gT2JqZWN0LnZhbHVlcyhtZXNzYWdlcylcbiAgICAgICAgICAgICAgICAubWFwKCh2KSA9PiBTdHJpbmcodikudHJpbSgpKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKHYpID0+IHYpO1xuICAgICAgICAgICAgaWYgKGVycm9yX2xpc3QubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBGb3JtX1V0aWxzLl9hcHBseV9nZW5lcmFsX2Vycm9ycygkcGFyZW50LCBlcnJvcl9saXN0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhbmltYXRpb25zO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZXMgdGhlIHRvdGFsIGhlaWdodCBvZiBmaXhlZC9zdGlja3kgaGVhZGVycyBhdCB0aGUgdG9wIG9mIHRoZSBwYWdlXG4gICAgICogQHJldHVybnMge251bWJlcn0gVG90YWwgaGVpZ2h0IGluIHBpeGVscyBvZiBmaXhlZCB0b3AgZWxlbWVudHNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHN0YXRpYyBfZ2V0X2ZpeGVkX2hlYWRlcl9oZWlnaHQoKSB7XG4gICAgICAgIGxldCB0b3RhbF9oZWlnaHQgPSAwO1xuXG4gICAgICAgIC8vIEZpbmQgYWxsIGZpeGVkIG9yIHN0aWNreSBwb3NpdGlvbmVkIGVsZW1lbnRzXG4gICAgICAgICQoJyonKS5lYWNoKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgY29uc3QgJGVsID0gJCh0aGlzKTtcbiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uID0gJGVsLmNzcygncG9zaXRpb24nKTtcblxuICAgICAgICAgICAgLy8gT25seSBjaGVjayBmaXhlZCBvciBzdGlja3kgZWxlbWVudHNcbiAgICAgICAgICAgIGlmIChwb3NpdGlvbiAhPT0gJ2ZpeGVkJyAmJiBwb3NpdGlvbiAhPT0gJ3N0aWNreScpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIGVsZW1lbnQgaXMgcG9zaXRpb25lZCBhdCBvciBuZWFyIHRoZSB0b3BcbiAgICAgICAgICAgIGNvbnN0IHRvcCA9IHBhcnNlSW50KCRlbC5jc3MoJ3RvcCcpKSB8fCAwO1xuICAgICAgICAgICAgaWYgKHRvcCA+IDUwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuOyAvLyBOb3QgYSB0b3AgaGVhZGVyXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIGVsZW1lbnQgaXMgdmlzaWJsZVxuICAgICAgICAgICAgaWYgKCEkZWwuaXMoJzp2aXNpYmxlJykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIGVsZW1lbnQgc3BhbnMgc2lnbmlmaWNhbnQgd2lkdGggKGxpa2VseSBhIGhlYWRlci9uYXZiYXIpXG4gICAgICAgICAgICBjb25zdCB3aWR0aCA9ICRlbC5vdXRlcldpZHRoKCk7XG4gICAgICAgICAgICBjb25zdCB2aWV3cG9ydF93aWR0aCA9ICQod2luZG93KS53aWR0aCgpO1xuICAgICAgICAgICAgaWYgKHdpZHRoIDwgdmlld3BvcnRfd2lkdGggKiAwLjUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47IC8vIFRvbyBuYXJyb3cgdG8gYmUgYSBoZWFkZXJcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQWRkIHRoaXMgZWxlbWVudCdzIGhlaWdodFxuICAgICAgICAgICAgdG90YWxfaGVpZ2h0ICs9ICRlbC5vdXRlckhlaWdodCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdG90YWxfaGVpZ2h0O1xuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7QUFBQTtBQUNBO0FBQ0E7QUFDQSxNQUFNQSxVQUFVLENBQUM7RUFDYjtBQUNKO0FBQ0E7QUFDQTtBQUNBO0VBQ0ksT0FBT0MseUJBQXlCQSxDQUFBLEVBQWM7SUFBQSxJQUFiQyxNQUFNLEdBQUFDLFNBQUEsQ0FBQUMsTUFBQSxRQUFBRCxTQUFBLFFBQUFFLFNBQUEsR0FBQUYsU0FBQSxNQUFHLENBQUMsQ0FBQztJQUN4Q0csQ0FBQyxDQUFDQyxFQUFFLENBQUNDLFdBQVcsR0FBRyxZQUF1QjtNQUFBLElBQWRDLE9BQU8sR0FBQU4sU0FBQSxDQUFBQyxNQUFBLFFBQUFELFNBQUEsUUFBQUUsU0FBQSxHQUFBRixTQUFBLE1BQUcsQ0FBQyxDQUFDO01BQ3BDLE1BQU1PLFFBQVEsR0FBR0osQ0FBQyxDQUFDLElBQUksQ0FBQztNQUV4QixJQUFJLENBQUNJLFFBQVEsQ0FBQ0MsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1FBQ3RCLE1BQU0sSUFBSUMsS0FBSyxDQUFDLG1EQUFtRCxDQUFDO01BQ3hFO01BRUEsTUFBTUMsR0FBRyxHQUFHSCxRQUFRLENBQUNJLElBQUksQ0FBQyxRQUFRLENBQUM7TUFDbkMsSUFBSSxDQUFD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