Remove unused blade settings pages not linked from UI Convert remaining frontend pages to SPA actions Convert settings user_settings and general to SPA actions Convert settings profile pages to SPA actions Convert contacts and projects add/edit pages to SPA actions Convert clients add/edit page to SPA action with loading pattern Refactor component scoped IDs from $id to $sid Fix jqhtml comment syntax and implement universal error component system Update all application code to use new unified error system Remove all backwards compatibility - unified error system complete Phase 5: Remove old response classes Phase 3-4: Ajax response handler sends new format, old helpers deprecated Phase 2: Add client-side unified error foundation Phase 1: Add server-side unified error foundation Add unified Ajax error response system with constants 🤖 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.$sid('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.$sid('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.$sid('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.$sid('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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
|