Implement JQHTML function cache ID system and fix bundle compilation Implement underscore prefix for system tables Fix JS syntax linter to support decorators and grant exception to Task system SPA: Update planning docs and wishlists with remaining features SPA: Document Navigation API abandonment and future enhancements Implement SPA browser integration with History API (Phase 1) Convert contacts view page to SPA action Convert clients pages to SPA actions and document conversion procedure SPA: Merge GET parameters and update documentation Implement SPA route URL generation in JavaScript and PHP Implement SPA bootstrap controller architecture Add SPA routing manual page (rsx:man spa) Add SPA routing documentation to CLAUDE.md Phase 4 Complete: Client-side SPA routing implementation Update get_routes() consumers for unified route structure Complete SPA Phase 3: PHP-side route type detection and is_spa flag Restore unified routes structure and Manifest_Query class Refactor route indexing and add SPA infrastructure Phase 3 Complete: SPA route registration in manifest Implement SPA Phase 2: Extract router code and test decorators Rename Jqhtml_Component to Component and complete SPA foundation setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
406 lines
52 KiB
JavaScript
Executable File
406 lines
52 KiB
JavaScript
Executable File
"use strict";
|
|
|
|
/**
|
|
* DataGrid Component (Phase 1)
|
|
*
|
|
* Due to the more dynamic nature of this component, we are handling load / render lifecycles
|
|
* directly in this class rather than using the on_load lifecycle event
|
|
*
|
|
* **Features**:
|
|
* - Ajax data fetching
|
|
* - Sorting (click headers)
|
|
* - Pagination (next/prev/page select)
|
|
* - Row selection (checkboxes)
|
|
* - CSV export (selected rows, current page)
|
|
* - URL state synchronization
|
|
*
|
|
* **Usage**:
|
|
* ```html
|
|
* <Contacts_DataGrid $api="Frontend_Contacts_Controller" />
|
|
* ```
|
|
*
|
|
* **Required Args**:
|
|
* - `api` - Controller class name with datagrid_fetch() Ajax endpoint
|
|
*
|
|
* **Optional Args**:
|
|
* - `per_page` - Default rows per page (default: 25)
|
|
* - `sort` - Default sort column (default: first column)
|
|
* - `order` - Default sort order (default: 'asc')
|
|
*/
|
|
class DataGrid_Abstract extends Component {
|
|
// Initialize data before first render
|
|
on_create() {
|
|
let that = this;
|
|
|
|
// Initialize data state immediately so template can render
|
|
that.data.rows = [];
|
|
that.data.loading = true;
|
|
that.data.is_empty = false;
|
|
that.data.loaded = false;
|
|
that.data.total_pages = 0;
|
|
}
|
|
|
|
// Calls when datagrid first initialized
|
|
async on_ready() {
|
|
var _that$args$per_page, _that$args$sort, _that$args$order;
|
|
let that = this;
|
|
if (!that.args.data_source) {
|
|
console.error('Datagrid ' + that.component_name() + ' requires args.data_source set to a Ajax_Endpoint object');
|
|
return;
|
|
}
|
|
|
|
// Store defaults for later comparison
|
|
that.data.default_page = 1;
|
|
that.data.default_per_page = (_that$args$per_page = that.args.per_page) !== null && _that$args$per_page !== void 0 ? _that$args$per_page : 15;
|
|
that.data.default_sort = (_that$args$sort = that.args.sort) !== null && _that$args$sort !== void 0 ? _that$args$sort : null;
|
|
that.data.default_order = (_that$args$order = that.args.order) !== null && _that$args$order !== void 0 ? _that$args$order : 'asc';
|
|
that.data.default_filter = '';
|
|
|
|
// Set configured values
|
|
that.data.per_page = that.data.default_per_page;
|
|
|
|
// Initialize state from URL hash if present, otherwise use defaults
|
|
const hash_page = Rsx.get_page_state(that._cid + '_page');
|
|
const hash_sort = Rsx.get_page_state(that._cid + '_sort');
|
|
const hash_order = Rsx.get_page_state(that._cid + '_order');
|
|
const hash_filter = Rsx.get_page_state(that._cid + '_filter');
|
|
that.data.page = hash_page ? int(hash_page) : that.data.default_page;
|
|
that.data.sort = hash_sort || that.data.default_sort;
|
|
that.data.order = hash_order || that.data.default_order;
|
|
that.data.filter = hash_filter || that.data.default_filter;
|
|
that.register_render_callbacks();
|
|
that.register_filter_handlers();
|
|
|
|
// If hash had a filter value, populate the filter input
|
|
if (that.data.filter) {
|
|
const $filter = that.$id('filter_input');
|
|
if ($filter && $filter.length > 0) {
|
|
$filter.val(that.data.filter);
|
|
}
|
|
}
|
|
|
|
// Measure row height and set fixed tbody height (all in one frame)
|
|
await that.measure_and_set_fixed_height();
|
|
|
|
// Fetch the initial page (respects hash state)
|
|
that.load_page(that.data.page);
|
|
}
|
|
|
|
// Update header only if sort/order changed
|
|
update_header() {
|
|
let that = this;
|
|
|
|
// Track last rendered state
|
|
if (!that._last_header_state) {
|
|
that._last_header_state = {};
|
|
}
|
|
const current = {
|
|
sort: that.data.sort,
|
|
order: that.data.order
|
|
};
|
|
|
|
// Only render if values changed
|
|
if (that._last_header_state.sort !== current.sort || that._last_header_state.order !== current.order) {
|
|
that._last_header_state = current;
|
|
that.id('datagrid_table_header').render();
|
|
}
|
|
}
|
|
|
|
// Update pagination only if values changed
|
|
update_pagination() {
|
|
let that = this;
|
|
|
|
// Track last rendered state
|
|
if (!that._last_pagination_state) {
|
|
that._last_pagination_state = {};
|
|
}
|
|
const current = {
|
|
page: that.data.page,
|
|
per_page: that.data.per_page,
|
|
total: that.data.total,
|
|
total_pages: that.data.total_pages
|
|
};
|
|
|
|
// Only render if values changed
|
|
if (that._last_pagination_state.page !== current.page || that._last_pagination_state.per_page !== current.per_page || that._last_pagination_state.total !== current.total || that._last_pagination_state.total_pages !== current.total_pages) {
|
|
that._last_pagination_state = current;
|
|
that.id('pagination_info').render();
|
|
that.id('pagination_controls').render();
|
|
}
|
|
}
|
|
|
|
// Load data for specified page and re-render data
|
|
async load_page(page) {
|
|
let that = this;
|
|
|
|
// Set loading state
|
|
that.data.loading = true;
|
|
that.data.page = page;
|
|
|
|
// Update UI with requested values (optimistic update)
|
|
that.update_header();
|
|
that.update_pagination();
|
|
|
|
// Only render loading state if no data yet (initial load)
|
|
if (that.data.rows.length === 0) {
|
|
that.id('datagrid_table_body').render();
|
|
}
|
|
const response = await Ajax.call(that.args.data_source, {
|
|
page: page,
|
|
per_page: that.data.per_page,
|
|
sort: that.data.sort,
|
|
order: that.data.order,
|
|
filter: that.data.filter
|
|
});
|
|
|
|
// Update data
|
|
that.data.loading = false;
|
|
that.data.loaded = true;
|
|
that.data.rows = response.records;
|
|
that.data.page = response.page;
|
|
that.data.per_page = response.per_page;
|
|
that.data.total = response.total;
|
|
that.data.total_pages = response.total_pages;
|
|
that.data.sort = response.sort;
|
|
that.data.order = response.order;
|
|
that.data.is_empty = response.records.length === 0;
|
|
|
|
// Persist state to URL hash for bookmarking/sharing
|
|
// Only set values that differ from defaults (null removes the key)
|
|
const state = {};
|
|
state[that._cid + '_page'] = that.data.page !== that.data.default_page ? that.data.page : null;
|
|
state[that._cid + '_sort'] = that.data.sort !== that.data.default_sort ? that.data.sort : null;
|
|
state[that._cid + '_order'] = that.data.order !== that.data.default_order ? that.data.order : null;
|
|
state[that._cid + '_filter'] = that.data.filter !== that.data.default_filter ? that.data.filter : null;
|
|
Rsx.set_all_page_state(state);
|
|
|
|
// Update UI with server response (only renders if changed)
|
|
that.id('datagrid_table_body').render();
|
|
that.update_header();
|
|
that.update_pagination();
|
|
|
|
// Scroll to top of datagrid if it's not currently visible
|
|
that.scroll_to_top_if_needed();
|
|
}
|
|
|
|
// The callbacks in this function fire after each targeted component re-renders
|
|
register_render_callbacks() {
|
|
let that = this;
|
|
|
|
// Attach row click handler - re-runs every time datagrid_table_body renders
|
|
that.id('datagrid_table_body').on('render', function () {
|
|
console.log('DGTB_R');
|
|
// Step 1: Wrap cells in data-href rows with anchor tags
|
|
$(this).find('tr[data-href]').each(function () {
|
|
let $row = $(this);
|
|
let href = $row.attr('data-href');
|
|
$row.find('td').each(function () {
|
|
// let $col = $(this);
|
|
// // Skip if cell already contains interactive elements
|
|
// if ($col.find('a, button, input, select, textarea').length > 0) {
|
|
// return;
|
|
// }
|
|
// // Wrap entire cell contents in an anchor (preserve DOM nodes for component lifecycle)
|
|
// let $anchor = $('<a>', {
|
|
// href: href,
|
|
// class: 'datagrid-row-link'
|
|
// });
|
|
// // Move existing child nodes into anchor (preserves components and their state)
|
|
// $col.contents().appendTo($anchor);
|
|
// // Add anchor to cell
|
|
// $col.append($anchor);
|
|
});
|
|
});
|
|
|
|
// Step 2: Find all cells with single anchor as only child and apply full-width styling
|
|
$(this).find('td').each(function () {
|
|
let $col = $(this);
|
|
let $children = $col.children();
|
|
|
|
// Check if cell contains exactly one direct child that is an anchor
|
|
if ($children.length === 1 && $children.first().is('a')) {
|
|
// Add class to transfer padding from cell to anchor
|
|
$col.addClass('has-full-link');
|
|
}
|
|
// Check if cell contains only text (no child elements)
|
|
else if ($children.length === 0) {
|
|
// Add class to apply vertical padding to text-only cells
|
|
$col.addClass('has-only-text');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Attach sortable header click handler - re-runs every time datagrid_table_header renders
|
|
that.id('datagrid_table_header').on('render', function () {
|
|
// Transform th[data-sortby] elements by wrapping contents in clickable link
|
|
$(this).find('th[data-sortby]').each(function () {
|
|
let $th = $(this);
|
|
let sortby = $th.attr('data-sortby');
|
|
|
|
// TODO: Find out why this on('render') callback is being called twice/on already-processed HTML
|
|
// This unwrap logic shouldn't be necessary - template should render fresh each time
|
|
// For now, unwrap already-wrapped content to prevent double-wrapping
|
|
let $existing_link = $th.find('a.sortable-header');
|
|
let contents;
|
|
if ($existing_link.length > 0) {
|
|
// Unwrap - get the text content without the wrapper and arrows
|
|
contents = $existing_link.clone().find('i.bi').remove().end().html();
|
|
} else {
|
|
contents = $th.html();
|
|
}
|
|
|
|
// Build the arrow icon HTML if this column is currently sorted
|
|
let arrow = '';
|
|
if (that.data.sort === sortby) {
|
|
arrow = that.data.order === 'desc' ? '<i class="bi bi-chevron-up ms-1"></i>' : '<i class="bi bi-chevron-down ms-1"></i>';
|
|
}
|
|
|
|
// Replace contents with wrapped link (fresh wrapper every time)
|
|
$th.html(`<a href="#" class="sortable-header" data-sortby="${sortby}">${contents}${arrow}</a>`);
|
|
});
|
|
|
|
// Attach click handlers to the sortable links we just created
|
|
$(this).find('a.sortable-header[data-sortby]').on('click', function (e) {
|
|
e.preventDefault();
|
|
const sortby = $(this).attr('data-sortby');
|
|
that.sort_by(sortby);
|
|
});
|
|
});
|
|
|
|
// Attach pagination click handler - re-runs every time pagination_controls renders
|
|
that.id('pagination_controls').on('render', function () {
|
|
$(this).find('.page-link').on('click', function (e) {
|
|
e.preventDefault();
|
|
const $link = $(this);
|
|
const page = int($link.attr('data-page'));
|
|
|
|
// Ignore disabled/ellipsis clicks
|
|
if (!page || isNaN(page) || $link.parent().hasClass('disabled')) {
|
|
return;
|
|
}
|
|
|
|
// Load the requested page
|
|
that.load_page(page);
|
|
});
|
|
});
|
|
|
|
// Attach clear filter button handler - re-runs every time datagrid_table_body renders
|
|
that.id('datagrid_table_body').on('render', function () {
|
|
const $clear_btn = that.$id('clear_filter_btn');
|
|
if ($clear_btn && $clear_btn.length > 0) {
|
|
$clear_btn.on('click', function (e) {
|
|
e.preventDefault();
|
|
that.clear_filter();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Sort by specified column, toggling order if already sorted by that column
|
|
sort_by(column) {
|
|
let that = this;
|
|
|
|
// Toggle order if clicking same column, otherwise default to asc
|
|
if (that.data.sort === column) {
|
|
that.data.order = that.data.order === 'asc' ? 'desc' : 'asc';
|
|
} else {
|
|
that.data.sort = column;
|
|
that.data.order = 'asc';
|
|
}
|
|
|
|
// Reload current page with new sort
|
|
that.id('datagrid_table_header').render();
|
|
that.load_page(that.data.page);
|
|
}
|
|
|
|
// Register filter input handlers
|
|
register_filter_handlers() {
|
|
let that = this;
|
|
|
|
// Find filter input by common identifiers
|
|
let $filter = that.$id('filter_input');
|
|
if (!$filter || $filter.length === 0) {
|
|
$filter = that.$.find('input[type="search"], input[type="text"].filter-input');
|
|
}
|
|
if ($filter && $filter.length > 0) {
|
|
$filter.on('input keyup', function () {
|
|
const filter_value = $(this).val();
|
|
that.filter_changed(filter_value);
|
|
});
|
|
}
|
|
}
|
|
filter_changed(filter) {
|
|
let that = this;
|
|
that.data.filter = filter;
|
|
that.load_page(1);
|
|
}
|
|
|
|
// Scroll to datagrid top if the top edge is not currently visible in viewport
|
|
scroll_to_top_if_needed() {
|
|
let that = this;
|
|
const $datagrid = that.$;
|
|
const datagridTop = $datagrid.offset().top;
|
|
const scrollTop = $(window).scrollTop();
|
|
|
|
// If datagrid top is above the current viewport, scroll to show it
|
|
if (datagridTop < scrollTop) {
|
|
// If datagrid is within 300px of page top, scroll to 0
|
|
if (datagridTop <= 300) {
|
|
window.scrollTo({
|
|
top: 0,
|
|
behavior: 'instant'
|
|
});
|
|
} else {
|
|
// Scroll to 20px above datagrid
|
|
window.scrollTo({
|
|
top: datagridTop - 20,
|
|
behavior: 'instant'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Measure actual row height and set fixed tbody min-height
|
|
// All happens in one animation frame so user doesn't see it
|
|
async measure_and_set_fixed_height() {
|
|
let that = this;
|
|
|
|
// Wait for next animation frame to ensure DOM is ready
|
|
await sleep(0);
|
|
const $tbody = that.id('datagrid_table_body').$;
|
|
|
|
// Temporarily render a single measurement row
|
|
const $measurement_row = $('<tr>').css('visibility', 'hidden').html('<td>Measuring...</td>');
|
|
$tbody.append($measurement_row);
|
|
|
|
// Measure the row height
|
|
const row_height = $measurement_row.outerHeight();
|
|
|
|
// Remove measurement row
|
|
$measurement_row.remove();
|
|
|
|
// Calculate and set min-height based on per_page
|
|
const min_height = row_height * that.data.per_page;
|
|
$tbody.css('min-height', min_height + 'px');
|
|
|
|
// Store for future reference
|
|
that.data.row_height = row_height;
|
|
that.data.tbody_min_height = min_height;
|
|
}
|
|
|
|
// Clear filter and reset to page 1
|
|
clear_filter() {
|
|
let that = this;
|
|
that.data.filter = '';
|
|
|
|
// Clear the filter input
|
|
const $filter = that.$id('filter_input');
|
|
if ($filter && $filter.length > 0) {
|
|
$filter.val('');
|
|
}
|
|
|
|
// Reload from page 1
|
|
that.load_page(1);
|
|
}
|
|
}
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJEYXRhR3JpZF9BYnN0cmFjdCIsIkpxaHRtbF9Db21wb25lbnQiLCJvbl9jcmVhdGUiLCJ0aGF0IiwiZGF0YSIsInJvd3MiLCJsb2FkaW5nIiwiaXNfZW1wdHkiLCJsb2FkZWQiLCJ0b3RhbF9wYWdlcyIsIm9uX3JlYWR5IiwiX3RoYXQkYXJncyRwZXJfcGFnZSIsIl90aGF0JGFyZ3Mkc29ydCIsIl90aGF0JGFyZ3Mkb3JkZXIiLCJhcmdzIiwiZGF0YV9zb3VyY2UiLCJjb25zb2xlIiwiZXJyb3IiLCJjb21wb25lbnRfbmFtZSIsImRlZmF1bHRfcGFnZSIsImRlZmF1bHRfcGVyX3BhZ2UiLCJwZXJfcGFnZSIsImRlZmF1bHRfc29ydCIsInNvcnQiLCJkZWZhdWx0X29yZGVyIiwib3JkZXIiLCJkZWZhdWx0X2ZpbHRlciIsImhhc2hfcGFnZSIsIlJzeCIsImdldF9wYWdlX3N0YXRlIiwiX2NpZCIsImhhc2hfc29ydCIsImhhc2hfb3JkZXIiLCJoYXNoX2ZpbHRlciIsInBhZ2UiLCJpbnQiLCJmaWx0ZXIiLCJyZWdpc3Rlcl9yZW5kZXJfY2FsbGJhY2tzIiwicmVnaXN0ZXJfZmlsdGVyX2hhbmRsZXJzIiwiJGZpbHRlciIsIiRpZCIsImxlbmd0aCIsInZhbCIsIm1lYXN1cmVfYW5kX3NldF9maXhlZF9oZWlnaHQiLCJsb2FkX3BhZ2UiLCJ1cGRhdGVfaGVhZGVyIiwiX2xhc3RfaGVhZGVyX3N0YXRlIiwiY3VycmVudCIsImlkIiwicmVuZGVyIiwidXBkYXRlX3BhZ2luYXRpb24iLCJfbGFzdF9wYWdpbmF0aW9uX3N0YXRlIiwidG90YWwiLCJyZXNwb25zZSIsIkFqYXgiLCJjYWxsIiwicmVjb3JkcyIsInN0YXRlIiwic2V0X2FsbF9wYWdlX3N0YXRlIiwic2Nyb2xsX3RvX3RvcF9pZl9uZWVkZWQiLCJvbiIsImxvZyIsIiQiLCJmaW5kIiwiZWFjaCIsIiRyb3ciLCJocmVmIiwiYXR0ciIsIiRjb2wiLCIkY2hpbGRyZW4iLCJjaGlsZHJlbiIsImZpcnN0IiwiaXMiLCJhZGRDbGFzcyIsIiR0aCIsInNvcnRieSIsIiRleGlzdGluZ19saW5rIiwiY29udGVudHMiLCJjbG9uZSIsInJlbW92ZSIsImVuZCIsImh0bWwiLCJhcnJvdyIsImUiLCJwcmV2ZW50RGVmYXVsdCIsInNvcnRfYnkiLCIkbGluayIsImlzTmFOIiwicGFyZW50IiwiaGFzQ2xhc3MiLCIkY2xlYXJfYnRuIiwiY2xlYXJfZmlsdGVyIiwiY29sdW1uIiwiZmlsdGVyX3ZhbHVlIiwiZmlsdGVyX2NoYW5nZWQiLCIkZGF0YWdyaWQiLCJkYXRhZ3JpZFRvcCIsIm9mZnNldCIsInRvcCIsInNjcm9sbFRvcCIsIndpbmRvdyIsInNjcm9sbFRvIiwiYmVoYXZpb3IiLCJzbGVlcCIsIiR0Ym9keSIsIiRtZWFzdXJlbWVudF9yb3ciLCJjc3MiLCJhcHBlbmQiLCJyb3dfaGVpZ2h0Iiwib3V0ZXJIZWlnaHQiLCJtaW5faGVpZ2h0IiwidGJvZHlfbWluX2hlaWdodCJdLCJzb3VyY2VzIjpbInJzeC90aGVtZS9jb21wb25lbnRzL2RhdGFncmlkL2RhdGFncmlkX2Fic3RyYWN0LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRGF0YUdyaWQgQ29tcG9uZW50IChQaGFzZSAxKVxuICpcbiAqIER1ZSB0byB0aGUgbW9yZSBkeW5hbWljIG5hdHVyZSBvZiB0aGlzIGNvbXBvbmVudCwgd2UgYXJlIGhhbmRsaW5nIGxvYWQgLyByZW5kZXIgbGlmZWN5Y2xlc1xuICogZGlyZWN0bHkgaW4gdGhpcyBjbGFzcyByYXRoZXIgdGhhbiB1c2luZyB0aGUgb25fbG9hZCBsaWZlY3ljbGUgZXZlbnRcbiAqXG4gKiAqKkZlYXR1cmVzKio6XG4gKiAtIEFqYXggZGF0YSBmZXRjaGluZ1xuICogLSBTb3J0aW5nIChjbGljayBoZWFkZXJzKVxuICogLSBQYWdpbmF0aW9uIChuZXh0L3ByZXYvcGFnZSBzZWxlY3QpXG4gKiAtIFJvdyBzZWxlY3Rpb24gKGNoZWNrYm94ZXMpXG4gKiAtIENTViBleHBvcnQgKHNlbGVjdGVkIHJvd3MsIGN1cnJlbnQgcGFnZSlcbiAqIC0gVVJMIHN0YXRlIHN5bmNocm9uaXphdGlvblxuICpcbiAqICoqVXNhZ2UqKjpcbiAqIGBgYGh0bWxcbiAqIDxDb250YWN0c19EYXRhR3JpZCAkYXBpPVwiRnJvbnRlbmRfQ29udGFjdHNfQ29udHJvbGxlclwiIC8+XG4gKiBgYGBcbiAqXG4gKiAqKlJlcXVpcmVkIEFyZ3MqKjpcbiAqIC0gYGFwaWAgLSBDb250cm9sbGVyIGNsYXNzIG5hbWUgd2l0aCBkYXRhZ3JpZF9mZXRjaCgpIEFqYXggZW5kcG9pbnRcbiAqXG4gKiAqKk9wdGlvbmFsIEFyZ3MqKjpcbiAqIC0gYHBlcl9wYWdlYCAtIERlZmF1bHQgcm93cyBwZXIgcGFnZSAoZGVmYXVsdDogMjUpXG4gKiAtIGBzb3J0YCAtIERlZmF1bHQgc29ydCBjb2x1bW4gKGRlZmF1bHQ6IGZpcnN0IGNvbHVtbilcbiAqIC0gYG9yZGVyYCAtIERlZmF1bHQgc29ydCBvcmRlciAoZGVmYXVsdDogJ2FzYycpXG4gKi9cbmNsYXNzIERhdGFHcmlkX0Fic3RyYWN0IGV4dGVuZHMgSnFodG1sX0NvbXBvbmVudCB7XG4gICAgLy8gSW5pdGlhbGl6ZSBkYXRhIGJlZm9yZSBmaXJzdCByZW5kZXJcbiAgICBvbl9jcmVhdGUoKSB7XG4gICAgICAgIGxldCB0aGF0ID0gdGhpcztcblxuICAgICAgICAvLyBJbml0aWFsaXplIGRhdGEgc3RhdGUgaW1tZWRpYXRlbHkgc28gdGVtcGxhdGUgY2FuIHJlbmRlclxuICAgICAgICB0aGF0LmRhdGEucm93cyA9IFtdO1xuICAgICAgICB0aGF0LmRhdGEubG9hZGluZyA9IHRydWU7XG4gICAgICAgIHRoYXQuZGF0YS5pc19lbXB0eSA9IGZhbHNlO1xuICAgICAgICB0aGF0LmRhdGEubG9hZGVkID0gZmFsc2U7XG4gICAgICAgIHRoYXQuZGF0YS50b3RhbF9wYWdlcyA9IDA7XG4gICAgfVxuXG4gICAgLy8gQ2FsbHMgd2hlbiBkYXRhZ3JpZCBmaXJzdCBpbml0aWFsaXplZFxuICAgIGFzeW5jIG9uX3JlYWR5KCkge1xuICAgICAgICBsZXQgdGhhdCA9IHRoaXM7XG5cbiAgICAgICAgaWYgKCF0aGF0LmFyZ3MuZGF0YV9zb3VyY2UpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ0RhdGFncmlkICcgKyB0aGF0LmNvbXBvbmVudF9uYW1lKCkgKyAnIHJlcXVpcmVzIGFyZ3MuZGF0YV9zb3VyY2Ugc2V0IHRvIGEgQWpheF9FbmRwb2ludCBvYmplY3QnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFN0b3JlIGRlZmF1bHRzIGZvciBsYXRlciBjb21wYXJpc29uXG4gICAgICAgIHRoYXQuZGF0YS5kZWZhdWx0X3BhZ2UgPSAxO1xuICAgICAgICB0aGF0LmRhdGEuZGVmYXVsdF9wZXJfcGFnZSA9IHRoYXQuYXJncy5wZXJfcGFnZSA/PyAxNTtcbiAgICAgICAgdGhhdC5kYXRhLmRlZmF1bHRfc29ydCA9IHRoYXQuYXJncy5zb3J0ID8/IG51bGw7XG4gICAgICAgIHRoYXQuZGF0YS5kZWZhdWx0X29yZGVyID0gdGhhdC5hcmdzLm9yZGVyID8/ICdhc2MnO1xuICAgICAgICB0aGF0LmRhdGEuZGVmYXVsdF9maWx0ZXIgPSAnJztcblxuICAgICAgICAvLyBTZXQgY29uZmlndXJlZCB2YWx1ZXNcbiAgICAgICAgdGhhdC5kYXRhLnBlcl9wYWdlID0gdGhhdC5kYXRhLmRlZmF1bHRfcGVyX3BhZ2U7XG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBzdGF0ZSBmcm9tIFVSTCBoYXNoIGlmIHByZXNlbnQsIG90aGVyd2lzZSB1c2UgZGVmYXVsdHNcbiAgICAgICAgY29uc3QgaGFzaF9wYWdlID0gUnN4LmdldF9wYWdlX3N0YXRlKHRoYXQuX2NpZCArICdfcGFnZScpO1xuICAgICAgICBjb25zdCBoYXNoX3NvcnQgPSBSc3guZ2V0X3BhZ2Vfc3RhdGUodGhhdC5fY2lkICsgJ19zb3J0Jyk7XG4gICAgICAgIGNvbnN0IGhhc2hfb3JkZXIgPSBSc3guZ2V0X3BhZ2Vfc3RhdGUodGhhdC5fY2lkICsgJ19vcmRlcicpO1xuICAgICAgICBjb25zdCBoYXNoX2ZpbHRlciA9IFJzeC5nZXRfcGFnZV9zdGF0ZSh0aGF0Ll9jaWQgKyAnX2ZpbHRlcicpO1xuXG4gICAgICAgIHRoYXQuZGF0YS5wYWdlID0gaGFzaF9wYWdlID8gaW50KGhhc2hfcGFnZSkgOiB0aGF0LmRhdGEuZGVmYXVsdF9wYWdlO1xuICAgICAgICB0aGF0LmRhdGEuc29ydCA9IGhhc2hfc29ydCB8fCB0aGF0LmRhdGEuZGVmYXVsdF9zb3J0O1xuICAgICAgICB0aGF0LmRhdGEub3JkZXIgPSBoYXNoX29yZGVyIHx8IHRoYXQuZGF0YS5kZWZhdWx0X29yZGVyO1xuICAgICAgICB0aGF0LmRhdGEuZmlsdGVyID0gaGFzaF9maWx0ZXIgfHwgdGhhdC5kYXRhLmRlZmF1bHRfZmlsdGVyO1xuXG4gICAgICAgIHRoYXQucmVnaXN0ZXJfcmVuZGVyX2NhbGxiYWNrcygpO1xuICAgICAgICB0aGF0LnJlZ2lzdGVyX2ZpbHRlcl9oYW5kbGVycygpO1xuXG4gICAgICAgIC8vIElmIGhhc2ggaGFkIGEgZmlsdGVyIHZhbHVlLCBwb3B1bGF0ZSB0aGUgZmlsdGVyIGlucHV0XG4gICAgICAgIGlmICh0aGF0LmRhdGEuZmlsdGVyKSB7XG4gICAgICAgICAgICBjb25zdCAkZmlsdGVyID0gdGhhdC4kaWQoJ2ZpbHRlcl9pbnB1dCcpO1xuICAgICAgICAgICAgaWYgKCRmaWx0ZXIgJiYgJGZpbHRlci5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgJGZpbHRlci52YWwodGhhdC5kYXRhLmZpbHRlcik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBNZWFzdXJlIHJvdyBoZWlnaHQgYW5kIHNldCBmaXhlZCB0Ym9keSBoZWlnaHQgKGFsbCBpbiBvbmUgZnJhbWUpXG4gICAgICAgIGF3YWl0IHRoYXQubWVhc3VyZV9hbmRfc2V0X2ZpeGVkX2hlaWdodCgpO1xuXG4gICAgICAgIC8vIEZldGNoIHRoZSBpbml0aWFsIHBhZ2UgKHJlc3BlY3RzIGhhc2ggc3RhdGUpXG4gICAgICAgIHRoYXQubG9hZF9wYWdlKHRoYXQuZGF0YS5wYWdlKTtcbiAgICB9XG5cbiAgICAvLyBVcGRhdGUgaGVhZGVyIG9ubHkgaWYgc29ydC9vcmRlciBjaGFuZ2VkXG4gICAgdXBkYXRlX2hlYWRlcigpIHtcbiAgICAgICAgbGV0IHRoYXQgPSB0aGlzO1xuXG4gICAgICAgIC8vIFRyYWNrIGxhc3QgcmVuZGVyZWQgc3RhdGVcbiAgICAgICAgaWYgKCF0aGF0Ll9sYXN0X2hlYWRlcl9zdGF0ZSkge1xuICAgICAgICAgICAgdGhhdC5fbGFzdF9oZWFkZXJfc3RhdGUgPSB7fTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGN1cnJlbnQgPSB7XG4gICAgICAgICAgICBzb3J0OiB0aGF0LmRhdGEuc29ydCxcbiAgICAgICAgICAgIG9yZGVyOiB0aGF0LmRhdGEub3JkZXIsXG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gT25seSByZW5kZXIgaWYgdmFsdWVzIGNoYW5nZWRcbiAgICAgICAgaWYgKHRoYXQuX2xhc3RfaGVhZGVyX3N0YXRlLnNvcnQgIT09IGN1cnJlbnQuc29ydCB8fCB0aGF0Ll9sYXN0X2hlYWRlcl9zdGF0ZS5vcmRlciAhPT0gY3VycmVudC5vcmRlcikge1xuICAgICAgICAgICAgdGhhdC5fbGFzdF9oZWFkZXJfc3RhdGUgPSBjdXJyZW50O1xuICAgICAgICAgICAgdGhhdC5pZCgnZGF0YWdyaWRfdGFibGVfaGVhZGVyJykucmVuZGVyKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBVcGRhdGUgcGFnaW5hdGlvbiBvbmx5IGlmIHZhbHVlcyBjaGFuZ2VkXG4gICAgdXBkYXRlX3BhZ2luYXRpb24oKSB7XG4gICAgICAgIGxldCB0aGF0ID0gdGhpcztcblxuICAgICAgICAvLyBUcmFjayBsYXN0IHJlbmRlcmVkIHN0YXRlXG4gICAgICAgIGlmICghdGhhdC5fbGFzdF9wYWdpbmF0aW9uX3N0YXRlKSB7XG4gICAgICAgICAgICB0aGF0Ll9sYXN0X3BhZ2luYXRpb25fc3RhdGUgPSB7fTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGN1cnJlbnQgPSB7XG4gICAgICAgICAgICBwYWdlOiB0aGF0LmRhdGEucGFnZSxcbiAgICAgICAgICAgIHBlcl9wYWdlOiB0aGF0LmRhdGEucGVyX3BhZ2UsXG4gICAgICAgICAgICB0b3RhbDogdGhhdC5kYXRhLnRvdGFsLFxuICAgICAgICAgICAgdG90YWxfcGFnZXM6IHRoYXQuZGF0YS50b3RhbF9wYWdlcyxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBPbmx5IHJlbmRlciBpZiB2YWx1ZXMgY2hhbmdlZFxuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGF0Ll9sYXN0X3BhZ2luYXRpb25fc3RhdGUucGFnZSAhPT0gY3VycmVudC5wYWdlIHx8XG4gICAgICAgICAgICB0aGF0Ll9sYXN0X3BhZ2luYXRpb25fc3RhdGUucGVyX3BhZ2UgIT09IGN1cnJlbnQucGVyX3BhZ2UgfHxcbiAgICAgICAgICAgIHRoYXQuX2xhc3RfcGFnaW5hdGlvbl9zdGF0ZS50b3RhbCAhPT0gY3VycmVudC50b3RhbCB8fFxuICAgICAgICAgICAgdGhhdC5fbGFzdF9wYWdpbmF0aW9uX3N0YXRlLnRvdGFsX3BhZ2VzICE9PSBjdXJyZW50LnRvdGFsX3BhZ2VzXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhhdC5fbGFzdF9wYWdpbmF0aW9uX3N0YXRlID0gY3VycmVudDtcbiAgICAgICAgICAgIHRoYXQuaWQoJ3BhZ2luYXRpb25faW5mbycpLnJlbmRlcigpO1xuICAgICAgICAgICAgdGhhdC5pZCgncGFnaW5hdGlvbl9jb250cm9scycpLnJlbmRlcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gTG9hZCBkYXRhIGZvciBzcGVjaWZpZWQgcGFnZSBhbmQgcmUtcmVuZGVyIGRhdGFcbiAgICBhc3luYyBsb2FkX3BhZ2UocGFnZSkge1xuICAgICAgICBsZXQgdGhhdCA9IHRoaXM7XG5cbiAgICAgICAgLy8gU2V0IGxvYWRpbmcgc3RhdGVcbiAgICAgICAgdGhhdC5kYXRhLmxvYWRpbmcgPSB0cnVlO1xuICAgICAgICB0aGF0LmRhdGEucGFnZSA9IHBhZ2U7XG5cbiAgICAgICAgLy8gVXBkYXRlIFVJIHdpdGggcmVxdWVzdGVkIHZhbHVlcyAob3B0aW1pc3RpYyB1cGRhdGUpXG4gICAgICAgIHRoYXQudXBkYXRlX2hlYWRlcigpO1xuICAgICAgICB0aGF0LnVwZGF0ZV9wYWdpbmF0aW9uKCk7XG5cbiAgICAgICAgLy8gT25seSByZW5kZXIgbG9hZGluZyBzdGF0ZSBpZiBubyBkYXRhIHlldCAoaW5pdGlhbCBsb2FkKVxuICAgICAgICBpZiAodGhhdC5kYXRhLnJvd3MubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aGF0LmlkKCdkYXRhZ3JpZF90YWJsZV9ib2R5JykucmVuZGVyKCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IEFqYXguY2FsbCh0aGF0LmFyZ3MuZGF0YV9zb3VyY2UsIHtcbiAgICAgICAgICAgIHBhZ2U6IHBhZ2UsXG4gICAgICAgICAgICBwZXJfcGFnZTogdGhhdC5kYXRhLnBlcl9wYWdlLFxuICAgICAgICAgICAgc29ydDogdGhhdC5kYXRhLnNvcnQsXG4gICAgICAgICAgICBvcmRlcjogdGhhdC5kYXRhLm9yZGVyLFxuICAgICAgICAgICAgZmlsdGVyOiB0aGF0LmRhdGEuZmlsdGVyLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBVcGRhdGUgZGF0YVxuICAgICAgICB0aGF0LmRhdGEubG9hZGluZyA9IGZhbHNlO1xuICAgICAgICB0aGF0LmRhdGEubG9hZGVkID0gdHJ1ZTtcbiAgICAgICAgdGhhdC5kYXRhLnJvd3MgPSByZXNwb25zZS5yZWNvcmRzO1xuICAgICAgICB0aGF0LmRhdGEucGFnZSA9IHJlc3BvbnNlLnBhZ2U7XG4gICAgICAgIHRoYXQuZGF0YS5wZXJfcGFnZSA9IHJlc3BvbnNlLnBlcl9wYWdlO1xuICAgICAgICB0aGF0LmRhdGEudG90YWwgPSByZXNwb25zZS50b3RhbDtcbiAgICAgICAgdGhhdC5kYXRhLnRvdGFsX3BhZ2VzID0gcmVzcG9uc2UudG90YWxfcGFnZXM7XG4gICAgICAgIHRoYXQuZGF0YS5zb3J0ID0gcmVzcG9uc2Uuc29ydDtcbiAgICAgICAgdGhhdC5kYXRhLm9yZGVyID0gcmVzcG9uc2Uub3JkZXI7XG4gICAgICAgIHRoYXQuZGF0YS5pc19lbXB0eSA9IHJlc3BvbnNlLnJlY29yZHMubGVuZ3RoID09PSAwO1xuXG4gICAgICAgIC8vIFBlcnNpc3Qgc3RhdGUgdG8gVVJMIGhhc2ggZm9yIGJvb2ttYXJraW5nL3NoYXJpbmdcbiAgICAgICAgLy8gT25seSBzZXQgdmFsdWVzIHRoYXQgZGlmZmVyIGZyb20gZGVmYXVsdHMgKG51bGwgcmVtb3ZlcyB0aGUga2V5KVxuICAgICAgICBjb25zdCBzdGF0ZSA9IHt9O1xuICAgICAgICBzdGF0ZVt0aGF0Ll9jaWQgKyAnX3BhZ2UnXSA9IHRoYXQuZGF0YS5wYWdlICE9PSB0aGF0LmRhdGEuZGVmYXVsdF9wYWdlID8gdGhhdC5kYXRhLnBhZ2UgOiBudWxsO1xuICAgICAgICBzdGF0ZVt0aGF0Ll9jaWQgKyAnX3NvcnQnXSA9IHRoYXQuZGF0YS5zb3J0ICE9PSB0aGF0LmRhdGEuZGVmYXVsdF9zb3J0ID8gdGhhdC5kYXRhLnNvcnQgOiBudWxsO1xuICAgICAgICBzdGF0ZVt0aGF0Ll9jaWQgKyAnX29yZGVyJ10gPSB0aGF0LmRhdGEub3JkZXIgIT09IHRoYXQuZGF0YS5kZWZhdWx0X29yZGVyID8gdGhhdC5kYXRhLm9yZGVyIDogbnVsbDtcbiAgICAgICAgc3RhdGVbdGhhdC5fY2lkICsgJ19maWx0ZXInXSA9IHRoYXQuZGF0YS5maWx0ZXIgIT09IHRoYXQuZGF0YS5kZWZhdWx0X2ZpbHRlciA/IHRoYXQuZGF0YS5maWx0ZXIgOiBudWxsO1xuXG4gICAgICAgIFJzeC5zZXRfYWxsX3BhZ2Vfc3RhdGUoc3RhdGUpO1xuXG4gICAgICAgIC8vIFVwZGF0ZSBVSSB3aXRoIHNlcnZlciByZXNwb25zZSAob25seSByZW5kZXJzIGlmIGNoYW5nZWQpXG4gICAgICAgIHRoYXQuaWQoJ2RhdGFncmlkX3RhYmxlX2JvZHknKS5yZW5kZXIoKTtcbiAgICAgICAgdGhhdC51cGRhdGVfaGVhZGVyKCk7XG4gICAgICAgIHRoYXQudXBkYXRlX3BhZ2luYXRpb24oKTtcblxuICAgICAgICAvLyBTY3JvbGwgdG8gdG9wIG9mIGRhdGFncmlkIGlmIGl0J3Mgbm90IGN1cnJlbnRseSB2aXNpYmxlXG4gICAgICAgIHRoYXQuc2Nyb2xsX3RvX3RvcF9pZl9uZWVkZWQoKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgY2FsbGJhY2tzIGluIHRoaXMgZnVuY3Rpb24gZmlyZSBhZnRlciBlYWNoIHRhcmdldGVkIGNvbXBvbmVudCByZS1yZW5kZXJzXG4gICAgcmVnaXN0ZXJfcmVuZGVyX2NhbGxiYWNrcygpIHtcbiAgICAgICAgbGV0IHRoYXQgPSB0aGlzO1xuXG4gICAgICAgIC8vIEF0dGFjaCByb3cgY2xpY2sgaGFuZGxlciAtIHJlLXJ1bnMgZXZlcnkgdGltZSBkYXRhZ3JpZF90YWJsZV9ib2R5IHJlbmRlcnNcbiAgICAgICAgdGhhdC5pZCgnZGF0YWdyaWRfdGFibGVfYm9keScpLm9uKCdyZW5kZXInLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnREdUQl9SJyk7XG4gICAgICAgICAgICAvLyBTdGVwIDE6IFdyYXAgY2VsbHMgaW4gZGF0YS1ocmVmIHJvd3Mgd2l0aCBhbmNob3IgdGFnc1xuICAgICAgICAgICAgJCh0aGlzKVxuICAgICAgICAgICAgICAgIC5maW5kKCd0cltkYXRhLWhyZWZdJylcbiAgICAgICAgICAgICAgICAuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCAkcm93ID0gJCh0aGlzKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGhyZWYgPSAkcm93LmF0dHIoJ2RhdGEtaHJlZicpO1xuXG4gICAgICAgICAgICAgICAgICAgICRyb3cuZmluZCgndGQnKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGxldCAkY29sID0gJCh0aGlzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC8vIFNraXAgaWYgY2VsbCBhbHJlYWR5IGNvbnRhaW5zIGludGVyYWN0aXZlIGVsZW1lbnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpZiAoJGNvbC5maW5kKCdhLCBidXR0b24sIGlucHV0LCBzZWxlY3QsIHRleHRhcmVhJykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC8vIFdyYXAgZW50aXJlIGNlbGwgY29udGVudHMgaW4gYW4gYW5jaG9yIChwcmVzZXJ2ZSBET00gbm9kZXMgZm9yIGNvbXBvbmVudCBsaWZlY3ljbGUpXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBsZXQgJGFuY2hvciA9ICQoJzxhPicsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICBocmVmOiBocmVmLFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgIGNsYXNzOiAnZGF0YWdyaWQtcm93LWxpbmsnXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC8vIE1vdmUgZXhpc3RpbmcgY2hpbGQgbm9kZXMgaW50byBhbmNob3IgKHByZXNlcnZlcyBjb21wb25lbnRzIGFuZCB0aGVpciBzdGF0ZSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICRjb2wuY29udGVudHMoKS5hcHBlbmRUbygkYW5jaG9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC8vIEFkZCBhbmNob3IgdG8gY2VsbFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gJGNvbC5hcHBlbmQoJGFuY2hvcik7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBTdGVwIDI6IEZpbmQgYWxsIGNlbGxzIHdpdGggc2luZ2xlIGFuY2hvciBhcyBvbmx5IGNoaWxkIGFuZCBhcHBseSBmdWxsLXdpZHRoIHN0eWxpbmdcbiAgICAgICAgICAgICQodGhpcylcbiAgICAgICAgICAgICAgICAuZmluZCgndGQnKVxuICAgICAgICAgICAgICAgIC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0ICRjb2wgPSAkKHRoaXMpO1xuICAgICAgICAgICAgICAgICAgICBsZXQgJGNoaWxkcmVuID0gJGNvbC5jaGlsZHJlbigpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIENoZWNrIGlmIGNlbGwgY29udGFpbnMgZXhhY3RseSBvbmUgZGlyZWN0IGNoaWxkIHRoYXQgaXMgYW4gYW5jaG9yXG4gICAgICAgICAgICAgICAgICAgIGlmICgkY2hpbGRyZW4ubGVuZ3RoID09PSAxICYmICRjaGlsZHJlbi5maXJzdCgpLmlzKCdhJykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkZCBjbGFzcyB0byB0cmFuc2ZlciBwYWRkaW5nIGZyb20gY2VsbCB0byBhbmNob3JcbiAgICAgICAgICAgICAgICAgICAgICAgICRjb2wuYWRkQ2xhc3MoJ2hhcy1mdWxsLWxpbmsnKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiBjZWxsIGNvbnRhaW5zIG9ubHkgdGV4dCAobm8gY2hpbGQgZWxlbWVudHMpXG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKCRjaGlsZHJlbi5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkZCBjbGFzcyB0byBhcHBseSB2ZXJ0aWNhbCBwYWRkaW5nIHRvIHRleHQtb25seSBjZWxsc1xuICAgICAgICAgICAgICAgICAgICAgICAgJGNvbC5hZGRDbGFzcygnaGFzLW9ubHktdGV4dCcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEF0dGFjaCBzb3J0YWJsZSBoZWFkZXIgY2xpY2sgaGFuZGxlciAtIHJlLXJ1bnMgZXZlcnkgdGltZSBkYXRhZ3JpZF90YWJsZV9oZWFkZXIgcmVuZGVyc1xuICAgICAgICB0aGF0LmlkKCdkYXRhZ3JpZF90YWJsZV9oZWFkZXInKS5vbigncmVuZGVyJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgLy8gVHJhbnNmb3JtIHRoW2RhdGEtc29ydGJ5XSBlbGVtZW50cyBieSB3cmFwcGluZyBjb250ZW50cyBpbiBjbGlja2FibGUgbGlua1xuICAgICAgICAgICAgJCh0aGlzKVxuICAgICAgICAgICAgICAgIC5maW5kKCd0aFtkYXRhLXNvcnRieV0nKVxuICAgICAgICAgICAgICAgIC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0ICR0aCA9ICQodGhpcyk7XG4gICAgICAgICAgICAgICAgICAgIGxldCBzb3J0YnkgPSAkdGguYXR0cignZGF0YS1zb3J0YnknKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBUT0RPOiBGaW5kIG91dCB3aHkgdGhpcyBvbigncmVuZGVyJykgY2FsbGJhY2sgaXMgYmVpbmcgY2FsbGVkIHR3aWNlL29uIGFscmVhZHktcHJvY2Vzc2VkIEhUTUxcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhpcyB1bndyYXAgbG9naWMgc2hvdWxkbid0IGJlIG5lY2Vzc2FyeSAtIHRlbXBsYXRlIHNob3VsZCByZW5kZXIgZnJlc2ggZWFjaCB0aW1lXG4gICAgICAgICAgICAgICAgICAgIC8vIEZvciBub3csIHVud3JhcCBhbHJlYWR5LXdyYXBwZWQgY29udGVudCB0byBwcmV2ZW50IGRvdWJsZS13cmFwcGluZ1xuICAgICAgICAgICAgICAgICAgICBsZXQgJGV4aXN0aW5nX2xpbmsgPSAkdGguZmluZCgnYS5zb3J0YWJsZS1oZWFkZXInKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGNvbnRlbnRzO1xuICAgICAgICAgICAgICAgICAgICBpZiAoJGV4aXN0aW5nX2xpbmsubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVW53cmFwIC0gZ2V0IHRoZSB0ZXh0IGNvbnRlbnQgd2l0aG91dCB0aGUgd3JhcHBlciBhbmQgYXJyb3dzXG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZW50cyA9ICRleGlzdGluZ19saW5rLmNsb25lKCkuZmluZCgnaS5iaScpLnJlbW92ZSgpLmVuZCgpLmh0bWwoKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnRzID0gJHRoLmh0bWwoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEJ1aWxkIHRoZSBhcnJvdyBpY29uIEhUTUwgaWYgdGhpcyBjb2x1bW4gaXMgY3VycmVudGx5IHNvcnRlZFxuICAgICAgICAgICAgICAgICAgICBsZXQgYXJyb3cgPSAnJztcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoYXQuZGF0YS5zb3J0ID09PSBzb3J0YnkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFycm93ID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGF0LmRhdGEub3JkZXIgPT09ICdkZXNjJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA/ICc8aSBjbGFzcz1cImJpIGJpLWNoZXZyb24tdXAgbXMtMVwiPjwvaT4nXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogJzxpIGNsYXNzPVwiYmkgYmktY2hldnJvbi1kb3duIG1zLTFcIj48L2k+JztcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJlcGxhY2UgY29udGVudHMgd2l0aCB3cmFwcGVkIGxpbmsgKGZyZXNoIHdyYXBwZXIgZXZlcnkgdGltZSlcbiAgICAgICAgICAgICAgICAgICAgJHRoLmh0bWwoYDxhIGhyZWY9XCIjXCIgY2xhc3M9XCJzb3J0YWJsZS1oZWFkZXJcIiBkYXRhLXNvcnRieT1cIiR7c29ydGJ5fVwiPiR7Y29udGVudHN9JHthcnJvd308L2E+YCk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIEF0dGFjaCBjbGljayBoYW5kbGVycyB0byB0aGUgc29ydGFibGUgbGlua3Mgd2UganVzdCBjcmVhdGVkXG4gICAgICAgICAgICAkKHRoaXMpXG4gICAgICAgICAgICAgICAgLmZpbmQoJ2Euc29ydGFibGUtaGVhZGVyW2RhdGEtc29ydGJ5XScpXG4gICAgICAgICAgICAgICAgLm9uKCdjbGljaycsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc29ydGJ5ID0gJCh0aGlzKS5hdHRyKCdkYXRhLXNvcnRieScpO1xuICAgICAgICAgICAgICAgICAgICB0aGF0LnNvcnRfYnkoc29ydGJ5KTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gQXR0YWNoIHBhZ2luYXRpb24gY2xpY2sgaGFuZGxlciAtIHJlLXJ1bnMgZXZlcnkgdGltZSBwYWdpbmF0aW9uX2NvbnRyb2xzIHJlbmRlcnNcbiAgICAgICAgdGhhdC5pZCgncGFnaW5hdGlvbl9jb250cm9scycpLm9uKCdyZW5kZXInLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAkKHRoaXMpXG4gICAgICAgICAgICAgICAgLmZpbmQoJy5wYWdlLWxpbmsnKVxuICAgICAgICAgICAgICAgIC5vbignY2xpY2snLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgJGxpbmsgPSAkKHRoaXMpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBwYWdlID0gaW50KCRsaW5rLmF0dHIoJ2RhdGEtcGFnZScpKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJZ25vcmUgZGlzYWJsZWQvZWxsaXBzaXMgY2xpY2tzXG4gICAgICAgICAgICAgICAgICAgIGlmICghcGFnZSB8fCBpc05hTihwYWdlKSB8fCAkbGluay5wYXJlbnQoKS5oYXNDbGFzcygnZGlzYWJsZWQnKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gTG9hZCB0aGUgcmVxdWVzdGVkIHBhZ2VcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5sb2FkX3BhZ2UocGFnZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIEF0dGFjaCBjbGVhciBmaWx0ZXIgYnV0dG9uIGhhbmRsZXIgLSByZS1ydW5zIGV2ZXJ5IHRpbWUgZGF0YWdyaWRfdGFibGVfYm9keSByZW5kZXJzXG4gICAgICAgIHRoYXQuaWQoJ2RhdGFncmlkX3RhYmxlX2JvZHknKS5vbigncmVuZGVyJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgY29uc3QgJGNsZWFyX2J0biA9IHRoYXQuJGlkKCdjbGVhcl9maWx0ZXJfYnRuJyk7XG4gICAgICAgICAgICBpZiAoJGNsZWFyX2J0biAmJiAkY2xlYXJfYnRuLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAkY2xlYXJfYnRuLm9uKCdjbGljaycsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5jbGVhcl9maWx0ZXIoKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gU29ydCBieSBzcGVjaWZpZWQgY29sdW1uLCB0b2dnbGluZyBvcmRlciBpZiBhbHJlYWR5IHNvcnRlZCBieSB0aGF0IGNvbHVtblxuICAgIHNvcnRfYnkoY29sdW1uKSB7XG4gICAgICAgIGxldCB0aGF0ID0gdGhpcztcblxuICAgICAgICAvLyBUb2dnbGUgb3JkZXIgaWYgY2xpY2tpbmcgc2FtZSBjb2x1bW4sIG90aGVyd2lzZSBkZWZhdWx0IHRvIGFzY1xuICAgICAgICBpZiAodGhhdC5kYXRhLnNvcnQgPT09IGNvbHVtbikge1xuICAgICAgICAgICAgdGhhdC5kYXRhLm9yZGVyID0gdGhhdC5kYXRhLm9yZGVyID09PSAnYXNjJyA/ICdkZXNjJyA6ICdhc2MnO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhhdC5kYXRhLnNvcnQgPSBjb2x1bW47XG4gICAgICAgICAgICB0aGF0LmRhdGEub3JkZXIgPSAnYXNjJztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJlbG9hZCBjdXJyZW50IHBhZ2Ugd2l0aCBuZXcgc29ydFxuICAgICAgICB0aGF0LmlkKCdkYXRhZ3JpZF90YWJsZV9oZWFkZXInKS5yZW5kZXIoKTtcbiAgICAgICAgdGhhdC5sb2FkX3BhZ2UodGhhdC5kYXRhLnBhZ2UpO1xuICAgIH1cblxuICAgIC8vIFJlZ2lzdGVyIGZpbHRlciBpbnB1dCBoYW5kbGVyc1xuICAgIHJlZ2lzdGVyX2ZpbHRlcl9oYW5kbGVycygpIHtcbiAgICAgICAgbGV0IHRoYXQgPSB0aGlzO1xuXG4gICAgICAgIC8vIEZpbmQgZmlsdGVyIGlucHV0IGJ5IGNvbW1vbiBpZGVudGlmaWVyc1xuICAgICAgICBsZXQgJGZpbHRlciA9IHRoYXQuJGlkKCdmaWx0ZXJfaW5wdXQnKTtcbiAgICAgICAgaWYgKCEkZmlsdGVyIHx8ICRmaWx0ZXIubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAkZmlsdGVyID0gdGhhdC4kLmZpbmQoJ2lucHV0W3R5cGU9XCJzZWFyY2hcIl0sIGlucHV0W3R5cGU9XCJ0ZXh0XCJdLmZpbHRlci1pbnB1dCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCRmaWx0ZXIgJiYgJGZpbHRlci5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAkZmlsdGVyLm9uKCdpbnB1dCBrZXl1cCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBmaWx0ZXJfdmFsdWUgPSAkKHRoaXMpLnZhbCgpO1xuICAgICAgICAgICAgICAgIHRoYXQuZmlsdGVyX2NoYW5nZWQoZmlsdGVyX3ZhbHVlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZmlsdGVyX2NoYW5nZWQoZmlsdGVyKSB7XG4gICAgICAgIGxldCB0aGF0ID0gdGhpcztcblxuICAgICAgICB0aGF0LmRhdGEuZmlsdGVyID0gZmlsdGVyO1xuICAgICAgICB0aGF0LmxvYWRfcGFnZSgxKTtcbiAgICB9XG5cbiAgICAvLyBTY3JvbGwgdG8gZGF0YWdyaWQgdG9wIGlmIHRoZSB0b3AgZWRnZSBpcyBub3QgY3VycmVudGx5IHZpc2libGUgaW4gdmlld3BvcnRcbiAgICBzY3JvbGxfdG9fdG9wX2lmX25lZWRlZCgpIHtcbiAgICAgICAgbGV0IHRoYXQgPSB0aGlzO1xuXG4gICAgICAgIGNvbnN0ICRkYXRhZ3JpZCA9IHRoYXQuJDtcbiAgICAgICAgY29uc3QgZGF0YWdyaWRUb3AgPSAkZGF0YWdyaWQub2Zmc2V0KCkudG9wO1xuICAgICAgICBjb25zdCBzY3JvbGxUb3AgPSAkKHdpbmRvdykuc2Nyb2xsVG9wKCk7XG5cbiAgICAgICAgLy8gSWYgZGF0YWdyaWQgdG9wIGlzIGFib3ZlIHRoZSBjdXJyZW50IHZpZXdwb3J0LCBzY3JvbGwgdG8gc2hvdyBpdFxuICAgICAgICBpZiAoZGF0YWdyaWRUb3AgPCBzY3JvbGxUb3ApIHtcbiAgICAgICAgICAgIC8vIElmIGRhdGFncmlkIGlzIHdpdGhpbiAzMDBweCBvZiBwYWdlIHRvcCwgc2Nyb2xsIHRvIDBcbiAgICAgICAgICAgIGlmIChkYXRhZ3JpZFRvcCA8PSAzMDApIHtcbiAgICAgICAgICAgICAgICB3aW5kb3cuc2Nyb2xsVG8oeyB0b3A6IDAsIGJlaGF2aW9yOiAnaW5zdGFudCcgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIFNjcm9sbCB0byAyMHB4IGFib3ZlIGRhdGFncmlkXG4gICAgICAgICAgICAgICAgd2luZG93LnNjcm9sbFRvKHsgdG9wOiBkYXRhZ3JpZFRvcCAtIDIwLCBiZWhhdmlvcjogJ2luc3RhbnQnIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gTWVhc3VyZSBhY3R1YWwgcm93IGhlaWdodCBhbmQgc2V0IGZpeGVkIHRib2R5IG1pbi1oZWlnaHRcbiAgICAvLyBBbGwgaGFwcGVucyBpbiBvbmUgYW5pbWF0aW9uIGZyYW1lIHNvIHVzZXIgZG9lc24ndCBzZWUgaXRcbiAgICBhc3luYyBtZWFzdXJlX2FuZF9zZXRfZml4ZWRfaGVpZ2h0KCkge1xuICAgICAgICBsZXQgdGhhdCA9IHRoaXM7XG5cbiAgICAgICAgLy8gV2FpdCBmb3IgbmV4dCBhbmltYXRpb24gZnJhbWUgdG8gZW5zdXJlIERPTSBpcyByZWFkeVxuICAgICAgICBhd2FpdCBzbGVlcCgwKTtcblxuICAgICAgICBjb25zdCAkdGJvZHkgPSB0aGF0LmlkKCdkYXRhZ3JpZF90YWJsZV9ib2R5JykuJDtcblxuICAgICAgICAvLyBUZW1wb3JhcmlseSByZW5kZXIgYSBzaW5nbGUgbWVhc3VyZW1lbnQgcm93XG4gICAgICAgIGNvbnN0ICRtZWFzdXJlbWVudF9yb3cgPSAkKCc8dHI+JykuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpLmh0bWwoJzx0ZD5NZWFzdXJpbmcuLi48L3RkPicpO1xuICAgICAgICAkdGJvZHkuYXBwZW5kKCRtZWFzdXJlbWVudF9yb3cpO1xuXG4gICAgICAgIC8vIE1lYXN1cmUgdGhlIHJvdyBoZWlnaHRcbiAgICAgICAgY29uc3Qgcm93X2hlaWdodCA9ICRtZWFzdXJlbWVudF9yb3cub3V0ZXJIZWlnaHQoKTtcblxuICAgICAgICAvLyBSZW1vdmUgbWVhc3VyZW1lbnQgcm93XG4gICAgICAgICRtZWFzdXJlbWVudF9yb3cucmVtb3ZlKCk7XG5cbiAgICAgICAgLy8gQ2FsY3VsYXRlIGFuZCBzZXQgbWluLWhlaWdodCBiYXNlZCBvbiBwZXJfcGFnZVxuICAgICAgICBjb25zdCBtaW5faGVpZ2h0ID0gcm93X2hlaWdodCAqIHRoYXQuZGF0YS5wZXJfcGFnZTtcbiAgICAgICAgJHRib2R5LmNzcygnbWluLWhlaWdodCcsIG1pbl9oZWlnaHQgKyAncHgnKTtcblxuICAgICAgICAvLyBTdG9yZSBmb3IgZnV0dXJlIHJlZmVyZW5jZVxuICAgICAgICB0aGF0LmRhdGEucm93X2hlaWdodCA9IHJvd19oZWlnaHQ7XG4gICAgICAgIHRoYXQuZGF0YS50Ym9keV9taW5faGVpZ2h0ID0gbWluX2hlaWdodDtcbiAgICB9XG5cbiAgICAvLyBDbGVhciBmaWx0ZXIgYW5kIHJlc2V0IHRvIHBhZ2UgMVxuICAgIGNsZWFyX2ZpbHRlcigpIHtcbiAgICAgICAgbGV0IHRoYXQgPSB0aGlzO1xuXG4gICAgICAgIHRoYXQuZGF0YS5maWx0ZXIgPSAnJztcblxuICAgICAgICAvLyBDbGVhciB0aGUgZmlsdGVyIGlucHV0XG4gICAgICAgIGNvbnN0ICRmaWx0ZXIgPSB0aGF0LiRpZCgnZmlsdGVyX2lucHV0Jyk7XG4gICAgICAgIGlmICgkZmlsdGVyICYmICRmaWx0ZXIubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgJGZpbHRlci52YWwoJycpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVsb2FkIGZyb20gcGFnZSAxXG4gICAgICAgIHRoYXQubG9hZF9wYWdlKDEpO1xuICAgIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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
|