"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: * *
* * *
* * 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 = $('
').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 = $(''); // Add summary message if provided if (summary_msg) { $('

').text(summary_msg).appendTo($alert); } // Add unmatched errors as bulleted list if (Object.keys(unmatched_errors).length > 0) { const $list = $(''); for (const field_name in unmatched_errors) { const error_msg = unmatched_errors[field_name]; $('
  • ').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 = $('').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 = $(''); const $list = $alert.find('ul'); messages.forEach(msg => { const text = (msg + '').trim() || 'An error has occurred'; $('
  • ').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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