toolshed-8.x-1.x-dev/js/widgets/Autocomplete.js
js/widgets/Autocomplete.js
"use strict";
(({
t,
behaviors,
debounce,
Toolshed: ts
}) => {
/**
* Live region which is used to announce status of widget changes.
*/
class LiveRegion extends ts.Element {
/**
* Initialize a new LiveRegion element.
*
* @param {Object} options
* Options to apply to the Live Regions.
* @param {HTMLElement|ToolshedElement} attachTo
* The element to append this live region to.
*/
constructor(options = {}, attachTo) {
if (ts.isString(options.class)) {
options.class = [options.class];
}
options.class = (options.class || []).concat(['visually-hidden', 'sr-only']);
// Create a wrapper element for the two live update areas.
super('div', options, attachTo || document.body);
// Setup regions for swapping between, for live updating.
const regionOpts = {
role: 'status',
'aria-live': 'polite',
'aria-atomic': 'true'
};
this.active = 1;
this.msg = '';
this.regions = [new ts.Element('div', regionOpts, this), new ts.Element('div', regionOpts, this)];
// Only announce the changes after a short delay to prevent the announcer
// from talking over itself.
this.updateMsg = debounce(() => {
this.regions[this.active].textContent = '';
this.active ^= 1; // eslint-disable-line no-bitwise
this.regions[this.active].textContent = this.msg;
}, 500);
}
/**
* The current text message to announce in the live region.
*
* @return {string}
* Return the current message to be announced.
*/
get message() {
return this.msg;
}
/**
* Set a new message for the live region. Note that there is a small delay
* before the message is announced to avoid collisions of messages which
* are too close together.
*
* @param {string} message
* Message to set for the live region.
*/
set message(message) {
this.msg = message;
this.updateMsg();
}
}
/**
* Object which represents a single autocomplete select option. This object
* manages its own resources and the display text as well as the underlying
* value to pass back to the original input element.
*/
class SuggestItem extends ts.Element {
/**
* Create a new SuggestItem representing values and a selectable element.
*
* @param {SuggestList} list
* The suggestion list that this item is a member of.
* @param {string} id
* The option identifier to use for the element ID.
* @param {Toolshed.Autocomplete} ac
* The callback when the item is clicked on.
*/
constructor(list, id, ac) {
super('a', {
tabindex: 0,
href: '#'
});
this.wrap = new ts.Element('li', {
id,
role: 'option',
class: 'autocomplete__opt'
});
this.wrap.appendChild(this);
this.parent = list;
this.pos = -1;
this.uri = null;
this.on('click', e => {
if (!this.uri) {
e.preventDefault();
e.stopPropagation();
ac.selectItem(this);
}
}, true);
}
/**
* The getter for the SuggestItem element ID.
*/
get id() {
return this.wrap.id;
}
/**
* The setter for SuggestItem element ID.
*
* @param {string} value
* The ID to used for the SuggestItem HTMLElement and descendant ID.
*/
set id(value) {
this.wrap.id = value;
}
/**
* Get the stored URI value of this suggest item.
*/
get url() {
return this.uri;
}
/**
* Set the URL of the suggest item, if the item should work like a link,
* rather than use the autocomplete value.
*
* @param {string} value
* A URL the Suggest item should send select when the item is clicked.
*/
set url(value) {
if (value && value !== '#') {
this.uri = value;
this.el.href = value;
} else {
this.uri = null;
this.el.href = '#';
}
}
/**
* Update this item to show it has focus.
*/
focus() {
this.wrap.addClass('autocomplete__opt--active');
}
/**
* Update this item to show that it doesn't have focus.
*/
blur() {
this.wrap.removeClass('autocomplete__opt--active');
}
/**
* Clean up listeners and other allocated resources.
*
* @param {bool} detach
* Should the suggest item be removed from the DOM?
*/
destroy(detach) {
this.parent = null;
super.destroy(detach);
this.wrap.destroy(detach);
}
}
/**
* A list of SuggestItems, and manage the interactions with the autocomplete
* suggestions traversal, building and clearing.
*/
class SuggestList extends ts.Element {
/**
* Create a new list of SuggestItem objects.
*
* @param {SuggestList|null} list
* An object that contains a list of SuggestItem instances.
* @param {string} wrapTag
* The HTMLElement tag to use to wrap this SuggestList.
* @param {ToolshedAutocomplete} ac
* The autocomplete instance that owns this SuggestList.
*/
constructor(list, wrapTag, ac) {
super('ul', {
class: 'autocomplete__options'
});
this.items = [];
this.parent = list;
this.ac = ac;
this.pos = 0;
this.wrap = new ts.Element(wrapTag);
this.wrap.appendChild(this);
}
/**
* Get the current number of suggests in the list.
*/
get length() {
let ct = 0;
for (let i = 0; i < this.items.length; ++i) {
ct += this.items[i] instanceof SuggestList ? this.items[i].length : 1;
}
return ct;
}
/**
* Is this SuggestList empty of selectable suggestion items?
*
* @return {Boolean}
* Returns true if there are no selectable items currently available
* as suggestions for the autocomplete query.
*/
isEmpty() {
return !this.items.length;
}
/**
* Set the label to display over a set items, if there is a caption.
*
* @param {string} text
* The label text to use as a caption over the SuggestList items.
* @param {string} itemId
* The ID attribute for the wrapper element.
*/
setLabel(text, itemId) {
if (!this.label) {
this.label = new ts.Element('span', {
class: 'autocomplete__group-label'
});
this.wrap.prependChild(this.label);
}
if (itemId) {
this.label.setAttrs({
id: `${itemId}-label`
});
this.setAttrs({
ariaLabelledby: `${itemId}-label`
});
}
this.label.textContent = text && text.length ? text : '';
}
/**
* Add a new SuggestItem to the SuggestList.
*
* @param {SuggestItem} item
* Add a SuggestItem to the end of the SuggestList.
*/
addItem(item) {
this.items.push(item);
this.appendChild(item.wrap);
}
/**
* Get the first item in the list.
*
* @return {SuggestItem|null}
* The first selectable SuggestItem or NULL if not items.
*/
getFirst() {
if (this.items.length) {
return this.items[0] instanceof SuggestList ? this.items[0].getFirst() : this.items[0];
}
return null;
}
/**
* Get the list item in the list.
*
* @return {SuggestItem|null}
* The last selectable SuggestItem in the list or NULL. This includes
* the last item in the nested set of items.
*/
getLast() {
if (this.items.length) {
const idx = this.items.length - 1;
return this.items[idx] instanceof SuggestList ? this.items[idx].getLast() : this.items[idx];
}
return null;
}
/**
* Construct the list of selectable SuggestItems from the passed in data.
*
* @param {array|object} data
* The data representing the autocomplete suggestions / values available.
* @param {string} baseId
* A pool of available SuggestItem to reuse.
*/
buildItems(data, baseId) {
let pos = 0;
data.forEach(row => {
let item;
const itemId = `${baseId}-${pos}`;
if (Array.isArray(row.list)) {
if (!row.list.length) return;
item = new SuggestList(this, 'li', this.ac);
item.setAttrs({
role: 'group'
});
item.setLabel(row.text, itemId);
item.buildItems(row.list, itemId);
} else if (row.value) {
item = new SuggestItem(this, itemId, this.ac);
item.text = row.text || row.value;
item.value = row.value;
if (row.url) item.url = row.url;
this.ac.itemDisplay(item, row);
}
this.addItem(item);
item.pos = pos++;
});
}
/**
* Remove suggestion items from the suggestioned items display.
*/
clear() {
this.items.forEach(item => item.destroy(true));
this.items = [];
}
/**
* Cleans up this autocomplete suggestions list, and frees resources and
* event listeners.
*/
destroy() {
if (this.label) {
this.label.destroy(true);
}
this.clear();
super.destroy(true);
this.wrap.destroy(true);
}
}
/**
* Class which encapsulates the behaviors of and autocomplete widget of a
* textfield. It allows subclasses to override their fetchSuggestions() and
* init() methods to allow for different methods of loading autocomplete
* items to display.
*/
ts.Autocomplete = class ToolshedAutocomplete {
constructor(input, config = {}) {
let ac;
this.input = input;
this.pending = false;
this.config = {
delay: 375,
minLength: 3,
requireSelect: true,
...config
};
// Reassociate a label element to point to the new autocomplete input.
const inputLabel = this.input.id ? document.querySelector(`label[for='${this.input.id}']`) : null;
// Create the main suggestion list wrapper.
const list = new SuggestList(null, 'div', this);
list.setAttrs({
id: `${this.input.id}-listbox`,
role: 'listbox'
});
list.on('blur', this.onBlur);
this.list = list;
if (inputLabel) {
if (!inputLabel.id) inputLabel.id = `${this.input.id}-label`;
list.setAttr('aria-labelledby', inputLabel.id);
}
// Create auto-suggestion pane.
const wrapper = new ts.Element('div', {
class: 'autocomplete__options-pane',
style: {
display: 'none'
}
});
wrapper.on('mousedown', this.onMouseDown.bind(this));
wrapper.appendChild(list.wrap);
wrapper.attachTo(this.input, 'after');
this.suggestWrap = wrapper;
// Create a container for displaying empty results message.
this.emptyMsg = new ts.Element('div', {
class: 'autocomplete__empty-msg',
style: {
display: 'none'
}
}, wrapper);
// Create a live region for announcing result updates.
this.liveRegion = new LiveRegion();
// Determine if the autocomplete value is separate from the displayed
// text. When this value is split, we have a cloned AC textfield.
if (this.config.separateValue) {
ac = new ts.FormElement(this.input.cloneNode(), {
placeholder: this.input.placeholder,
value: this.input.dataset.text || this.formatDisplayValue(this.input.value) || '',
'aria-autocomplete': 'list'
});
ac.removeClass('toolshed-autocomplete');
ac.removeAttrs(['name', 'data-autocomplete']);
this.input.style.display = 'none';
ac.attachTo(this.input, 'after');
// Remove these Drupal properties as this is just a stand-in object
// and we don't want to submit or to catch any Drupal behaviors.
delete ac.dataset.drupalSelector;
delete ac.dataset.autocompletePath;
delete ac.dataset.text;
// Reassociate a label element to point to the new autocomplete input.
if (inputLabel) {
ac.id = `${this.input.id}-autocomplete`;
inputLabel.htmlFor = ac.id;
}
} else {
ac = new ts.FormElement(this.input);
ac.setAttr('aria-autocomplete', 'both');
}
this.ac = ac;
ac.setAttrs({
class: 'form-autocomplete',
autocomplete: 'off',
role: 'combobox',
'aria-owns': list.id,
'aria-haspopup': 'listbox',
'aria-expanded': 'false'
});
// Bind key change events.
ac.on('keydown', this.onTextKeydown.bind(this));
ac.on('input', this.onTextChange.bind(this));
ac.on('focus', this.onFocus.bind(this));
ac.on('blur', this.onBlur.bind(this));
if (this.config.delay > 0) {
this.fetchSuggestions = debounce(this.fetchSuggestions, this.config.delay);
}
if (this.config.params && this.input.form) {
const {
form
} = this.input;
this.onParamChange = this.onParamChange.bind(this);
Object.values(this.config.params).forEach(elemId => {
const el = form.querySelector(`#${elemId}`);
if (el) el.addEventListener('change', this.onParamChange);
});
}
}
/**
* Refresh the autocomplete suggests to display.
*
* @param {Array|Object} [data={}]
* Values to use as the autocomplete suggestions. The property keys are
* the value, and the property values are the display autocomplete value.
*/
createSuggestions(data = {}) {
this.activeItem = null;
if (!this.list.isEmpty()) {
this.list.clear();
}
if (data.list.length) {
if (this.emptyMsg.style.display !== 'none') {
this.emptyMsg.style.display = 'none';
}
this.list.buildItems(data.list, `${this.input.id}-opt`);
} else {
this.emptyMsg.textContent = data.empty ? data.empty : 'No results';
this.emptyMsg.style.display = '';
}
}
/**
* Format the input value to the display text. By default the text that appears before ":" is
* hidden and considered an internal value switch. Subclasses of this autocomplete can
* override this and define their own display text value formatting.
*/
formatDisplayValue(value) {
return value ? value.replace(/^[^:]*?\s*:\s*/, '') : '';
}
/**
* Clear the current input.
*/
clearInput() {
this.ac.value = '';
this.input.value = '';
this.clearSuggestions();
}
/**
* Remove existing autocomplete suggestions.
*/
clearSuggestions() {
this.ac.removeAttrs('aria-activedescendant');
this.activeItem = null;
this.list.clear();
}
/**
* Is the suggestion window open?
*
* @return {Boolean}
* TRUE if the suggestions window is open, otherwise FALSE.
*/
isSuggestionsVisible() {
return this.suggestWrap.style.display !== 'none';
}
/**
* Position and expose the suggestions window if it is not already open.
*/
displaySuggestions() {
if (!this.isSuggestionsVisible()) {
this.suggestWrap.setStyles({
display: '',
width: `${this.ac.el.clientWidth}px`,
top: `${this.ac.el.offsetTop + this.ac.el.offsetHeight}px`,
left: `${this.ac.el.offsetLeft}px`
});
this.ac.setAttrs({
'aria-expanded': 'true'
});
}
const ct = this.list.length;
this.liveRegion.message = ct > 0 ? t('@count results available, use up and down arrow keys to navigate.', {
'@count': ct
}) : t('No search results.');
}
/**
* Hide the suggestions window if it is open and reset the active item.
*/
hideSuggestions() {
this.activeItem = null;
this.suggestWrap.style.display = 'none';
this.ac.setAttrs({
'aria-expanded': 'false'
});
}
/**
* Create the content to display in the autocomplete.
*
* Handles either building a simple text display or building the HTML to
* a complex display, with a text label.
*
* @param {SuggestItem} item
* The suggestion item to change the inner content of.
* @param {Object} data
* The raw data from the autocomplete response.
*/
itemDisplay(item, data) {
// eslint-disable-line class-methods-use-this
if (data.html) {
item.innerHTML = data.html;
item.setAttrs({
'aria-label': data.text || data.value
});
} else {
item.textContent = item.text || item.value;
}
}
/**
* Set a SuggestItem as currently active based on the index. This method
* ensures that any currently active items are blurred (unfocused) and
* if the requested index is out of range, to select no items.
*
* @param {SuggestItem} item
* The item to set as the current active item.
*/
setActiveItem(item) {
if (this.activeItem) this.activeItem.blur();
if (item) {
item.focus();
this.activeItem = item;
if (item.id) {
this.ac.setAttrs({
'aria-activedescendant': item.id
});
}
} else {
this.activeItem = null;
this.ac.removeAttrs('aria-activedescendant');
}
}
/**
* Transfer the values from the passed in item to the form elements.
*
* @param {SuggestItem} item
* Item to apply to as the values of the autocomplete widget.
*/
selectItem(item) {
if (item.url) {
window.location = item.url;
} else {
if (this.ac.el !== this.input) {
this.ac.value = item.text || item.value;
}
this.input.value = item.value;
}
this.hideSuggestions();
}
/**
* Make the necessary requests and calls to get available text values.
*
* @param {string} text
* The text to try to match using the autocomplete service to
* generate suggestions with.
* @param {bool} display
* Should the suggestions list be displayed after fetching suggestions.
*/
fetchSuggestions(text, display = true) {
if (!this.requester) {
this.requester = ts.createRequester(this.config.uri);
}
if (this.pending && !this.pending.promise.isResolved) {
// Abort any previously pending requests, so this late response
// won't overwrite our desired values if it returns out of order.
this.pending.xhr.abort();
}
if (!text || text.length < this.config.minLength) {
if (this.isSuggestionsVisible()) this.hideSuggestions();
return;
}
// Turn on the loading spinner.
this.ac.addClass('ui-autocomplete-loading');
// Apply additional request parameters if there are linked inputs.
const requestParams = {};
if (this.config.params) {
Object.entries(this.config.params).forEach(([key, elemId]) => {
const input = document.getElementById(elemId);
if (input && input.value) requestParams[key] = input.value;
});
}
requestParams.q = text;
this.pending = this.requester(requestParams);
this.pending.promise.then(response => {
this.clearLoading(this.ac);
this.createSuggestions(response);
// If requested to display suggestions after they load.
if (display) this.displaySuggestions();
}, reason => {
// Only remove the autocomplete loading if the request was aborted.
if (!(reason.message && reason.message === 'Cancelled')) {
this.clearLoading(this.ac);
}
});
}
/**
* Clear the autocomplete loading status and displays.
*
* @param {ToolshedElement} el
* Autocomplete element to remove loading status from.
*/
clearLoading(el) {
// Clear the loading spinner.
el.removeClass(['ui-autocomplete-loading', 'is-autocompleting']);
// Hide Claro or other theme autocomplete message elements.
const msg = el.parentElement.querySelector(':scope > [data-drupal-selector="autocomplete-message"]');
if (msg) {
msg.classList.add('hidden');
}
}
/**
* When focus is on the autocomplete input, show suggestions if they exist.
*/
onFocus() {
if (!this.list.isEmpty()) {
this.displaySuggestions();
}
}
/**
* When focus leaves the autocomplete input, hide suggestions.
*
* @param {BlurEvent} e
* The blur event information for when the autocomplete loses focus.
*/
onBlur(e) {
if (this.isSuggestionsVisible()) {
if (!e.relatedTarget || !(e.relatedTarget === this.ac.el || e.relatedTarget.closest('[role=listbox]') === this.list.el)) {
this.hideSuggestions();
}
}
}
/**
* Create a mouse down event which avoids having the AC input lose focus
* from clicking into the suggestions wrapper. This inconveniently prevents
* the click event because it hides the suggestions before the click event
* can occur.
*
* @param {Event} event
* The mouse down event object.
*/
// eslint-disable-next-line class-methods-use-this
onMouseDown(event) {
event.preventDefault();
}
/**
* Callback for updating the input value when the textfield is updated.
*
* @param {Event} event
* The input changed event object.
*/
onTextChange(event) {
if (this.ac.el !== this.input) {
this.input.value = this.config.requireSelect ? '' : this.ac.el.value;
}
this.fetchSuggestions(event.target.value);
}
/**
* Input value changed callback to refresh our input values when a
* dependent parameter changes.
*/
onParamChange() {
this.clearInput();
}
/**
* Respond to keyboard navigation, and move the active item.
*
* @param {KeydownEvent} e
* Respond to a key-up event for the autocomplete input textfield.
*/
onTextKeydown(e) {
if (!this.isSuggestionsVisible()) return;
let inc;
let method;
switch (e.keyCode) {
case 13:
// Enter key
if (this.activeItem) {
e.preventDefault();
this.selectItem(this.activeItem);
return;
}
// eslint-ignore-line no-fallthrough
case 9: // Tab key
case 27:
// Escape key
this.hideSuggestions();
return;
case 40:
// Up key
method = SuggestList.prototype.getFirst;
inc = 1;
break;
case 38:
// Down key
method = SuggestList.prototype.getLast;
inc = -1;
break;
default:
return;
}
e.preventDefault();
let item = this.activeItem;
if (item) {
let p = item.parent;
let i = item.pos + inc;
while (p && (i < 0 || p.items.length === i)) {
item = p;
i = item.pos + inc;
p = item.parent;
}
if (p) {
item = p.items[i];
}
}
item = item || this.list;
if (item instanceof SuggestList) {
item = method.call(item);
}
this.setActiveItem(item);
}
/**
* Clean up DOM and event listeners initialized by this autocompete widget.
*/
destroy() {
// Abort any pending request for this widget.
if (this.pending && !this.pending.promise.isResolved) {
this.pending.xhr.abort();
}
delete this.pending;
if (this.config.params) {
Object.values(this.config.params).forEach(elemId => {
const el = document.getElementById(elemId);
if (el) el.removeEventListener('change', this.onParamChange);
});
}
if (this.ac.el !== this.input) {
if (this.ac.id && this.input.id) {
// Reassociate a label element to point to the original input.
const inputLabel = document.querySelector(`label[for='${this.ac.id}']`);
if (inputLabel) {
inputLabel.htmlFor = this.input.id;
}
}
this.ac.destroy(true);
}
this.list.destroy(true);
this.emptyMsg.destroy(true);
this.suggestWrap.destroy(true);
this.liveRegion.destroy(true);
this.input.style.display = '';
}
};
/**
* Find autocomplete inputs and attach the autocomplete behaviors to it.
*/
behaviors.toolshedAutocomplete = {
// Track instances of Autocomplete objects so they can be detached.
instances: new Map(),
attach(context) {
ts.walkByClass(context, 'toolshed-autocomplete', item => {
const settings = item.dataset.autocomplete ? JSON.parse(item.dataset.autocomplete) : {};
if (item.dataset.params) {
settings.params = JSON.parse(item.dataset.params);
}
if (settings.uri) {
const ac = new ts.Autocomplete(item, settings);
this.instances.set(item.id || item, ac);
}
}, 'autocomplete--processed');
},
detach(context, settings, trigger) {
if (trigger === 'unload') {
ts.walkBySelector(context, '.toolshed-autocomplete.autocomplete--processed', item => {
const ac = this.instances.get(item.id || item);
if (ac) {
item.classList.remove('autocomplete--processed');
this.instances.delete(item);
ac.destroy();
}
});
}
}
};
})(Drupal);
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2lkZ2V0cy9BdXRvY29tcGxldGUuanMiLCJuYW1lcyI6WyJ0IiwiYmVoYXZpb3JzIiwiZGVib3VuY2UiLCJUb29sc2hlZCIsInRzIiwiTGl2ZVJlZ2lvbiIsIkVsZW1lbnQiLCJjb25zdHJ1Y3RvciIsIm9wdGlvbnMiLCJhdHRhY2hUbyIsImlzU3RyaW5nIiwiY2xhc3MiLCJjb25jYXQiLCJkb2N1bWVudCIsImJvZHkiLCJyZWdpb25PcHRzIiwicm9sZSIsImFjdGl2ZSIsIm1zZyIsInJlZ2lvbnMiLCJ1cGRhdGVNc2ciLCJ0ZXh0Q29udGVudCIsIm1lc3NhZ2UiLCJTdWdnZXN0SXRlbSIsImxpc3QiLCJpZCIsImFjIiwidGFiaW5kZXgiLCJocmVmIiwid3JhcCIsImFwcGVuZENoaWxkIiwicGFyZW50IiwicG9zIiwidXJpIiwib24iLCJlIiwicHJldmVudERlZmF1bHQiLCJzdG9wUHJvcGFnYXRpb24iLCJzZWxlY3RJdGVtIiwidmFsdWUiLCJ1cmwiLCJlbCIsImZvY3VzIiwiYWRkQ2xhc3MiLCJibHVyIiwicmVtb3ZlQ2xhc3MiLCJkZXN0cm95IiwiZGV0YWNoIiwiU3VnZ2VzdExpc3QiLCJ3cmFwVGFnIiwiaXRlbXMiLCJsZW5ndGgiLCJjdCIsImkiLCJpc0VtcHR5Iiwic2V0TGFiZWwiLCJ0ZXh0IiwiaXRlbUlkIiwibGFiZWwiLCJwcmVwZW5kQ2hpbGQiLCJzZXRBdHRycyIsImFyaWFMYWJlbGxlZGJ5IiwiYWRkSXRlbSIsIml0ZW0iLCJwdXNoIiwiZ2V0Rmlyc3QiLCJnZXRMYXN0IiwiaWR4IiwiYnVpbGRJdGVtcyIsImRhdGEiLCJiYXNlSWQiLCJmb3JFYWNoIiwicm93IiwiQXJyYXkiLCJpc0FycmF5IiwiaXRlbURpc3BsYXkiLCJjbGVhciIsIkF1dG9jb21wbGV0ZSIsIlRvb2xzaGVkQXV0b2NvbXBsZXRlIiwiaW5wdXQiLCJjb25maWciLCJwZW5kaW5nIiwiZGVsYXkiLCJtaW5MZW5ndGgiLCJyZXF1aXJlU2VsZWN0IiwiaW5wdXRMYWJlbCIsInF1ZXJ5U2VsZWN0b3IiLCJvbkJsdXIiLCJzZXRBdHRyIiwid3JhcHBlciIsInN0eWxlIiwiZGlzcGxheSIsIm9uTW91c2VEb3duIiwiYmluZCIsInN1Z2dlc3RXcmFwIiwiZW1wdHlNc2ciLCJsaXZlUmVnaW9uIiwic2VwYXJhdGVWYWx1ZSIsIkZvcm1FbGVtZW50IiwiY2xvbmVOb2RlIiwicGxhY2Vob2xkZXIiLCJkYXRhc2V0IiwiZm9ybWF0RGlzcGxheVZhbHVlIiwicmVtb3ZlQXR0cnMiLCJkcnVwYWxTZWxlY3RvciIsImF1dG9jb21wbGV0ZVBhdGgiLCJodG1sRm9yIiwiYXV0b2NvbXBsZXRlIiwib25UZXh0S2V5ZG93biIsIm9uVGV4dENoYW5nZSIsIm9uRm9jdXMiLCJmZXRjaFN1Z2dlc3Rpb25zIiwicGFyYW1zIiwiZm9ybSIsIm9uUGFyYW1DaGFuZ2UiLCJPYmplY3QiLCJ2YWx1ZXMiLCJlbGVtSWQiLCJhZGRFdmVudExpc3RlbmVyIiwiY3JlYXRlU3VnZ2VzdGlvbnMiLCJhY3RpdmVJdGVtIiwiZW1wdHkiLCJyZXBsYWNlIiwiY2xlYXJJbnB1dCIsImNsZWFyU3VnZ2VzdGlvbnMiLCJpc1N1Z2dlc3Rpb25zVmlzaWJsZSIsImRpc3BsYXlTdWdnZXN0aW9ucyIsInNldFN0eWxlcyIsIndpZHRoIiwiY2xpZW50V2lkdGgiLCJ0b3AiLCJvZmZzZXRUb3AiLCJvZmZzZXRIZWlnaHQiLCJsZWZ0Iiwib2Zmc2V0TGVmdCIsImhpZGVTdWdnZXN0aW9ucyIsImh0bWwiLCJpbm5lckhUTUwiLCJzZXRBY3RpdmVJdGVtIiwid2luZG93IiwibG9jYXRpb24iLCJyZXF1ZXN0ZXIiLCJjcmVhdGVSZXF1ZXN0ZXIiLCJwcm9taXNlIiwiaXNSZXNvbHZlZCIsInhociIsImFib3J0IiwicmVxdWVzdFBhcmFtcyIsImVudHJpZXMiLCJrZXkiLCJnZXRFbGVtZW50QnlJZCIsInEiLCJ0aGVuIiwicmVzcG9uc2UiLCJjbGVhckxvYWRpbmciLCJyZWFzb24iLCJwYXJlbnRFbGVtZW50IiwiY2xhc3NMaXN0IiwiYWRkIiwicmVsYXRlZFRhcmdldCIsImNsb3Nlc3QiLCJldmVudCIsInRhcmdldCIsImluYyIsIm1ldGhvZCIsImtleUNvZGUiLCJwcm90b3R5cGUiLCJwIiwiY2FsbCIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJ0b29sc2hlZEF1dG9jb21wbGV0ZSIsImluc3RhbmNlcyIsIk1hcCIsImF0dGFjaCIsImNvbnRleHQiLCJ3YWxrQnlDbGFzcyIsInNldHRpbmdzIiwiSlNPTiIsInBhcnNlIiwic2V0IiwidHJpZ2dlciIsIndhbGtCeVNlbGVjdG9yIiwiZ2V0IiwicmVtb3ZlIiwiZGVsZXRlIiwiRHJ1cGFsIl0sInNvdXJjZXMiOlsid2lkZ2V0cy9BdXRvY29tcGxldGUuZXM2LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIigoe1xuICB0LFxuICBiZWhhdmlvcnMsXG4gIGRlYm91bmNlLFxuICBUb29sc2hlZDogdHMsXG59KSA9PiB7XG4gIC8qKlxuICAgKiBMaXZlIHJlZ2lvbiB3aGljaCBpcyB1c2VkIHRvIGFubm91bmNlIHN0YXR1cyBvZiB3aWRnZXQgY2hhbmdlcy5cbiAgICovXG4gIGNsYXNzIExpdmVSZWdpb24gZXh0ZW5kcyB0cy5FbGVtZW50IHtcbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplIGEgbmV3IExpdmVSZWdpb24gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gICAgICogICBPcHRpb25zIHRvIGFwcGx5IHRvIHRoZSBMaXZlIFJlZ2lvbnMuXG4gICAgICogQHBhcmFtIHtIVE1MRWxlbWVudHxUb29sc2hlZEVsZW1lbnR9IGF0dGFjaFRvXG4gICAgICogICBUaGUgZWxlbWVudCB0byBhcHBlbmQgdGhpcyBsaXZlIHJlZ2lvbiB0by5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0ge30sIGF0dGFjaFRvKSB7XG4gICAgICBpZiAodHMuaXNTdHJpbmcob3B0aW9ucy5jbGFzcykpIHtcbiAgICAgICAgb3B0aW9ucy5jbGFzcyA9IFtvcHRpb25zLmNsYXNzXTtcbiAgICAgIH1cblxuICAgICAgb3B0aW9ucy5jbGFzcyA9IChvcHRpb25zLmNsYXNzIHx8IFtdKS5jb25jYXQoWyd2aXN1YWxseS1oaWRkZW4nLCAnc3Itb25seSddKTtcblxuICAgICAgLy8gQ3JlYXRlIGEgd3JhcHBlciBlbGVtZW50IGZvciB0aGUgdHdvIGxpdmUgdXBkYXRlIGFyZWFzLlxuICAgICAgc3VwZXIoJ2RpdicsIG9wdGlvbnMsIGF0dGFjaFRvIHx8IGRvY3VtZW50LmJvZHkpO1xuXG4gICAgICAvLyBTZXR1cCByZWdpb25zIGZvciBzd2FwcGluZyBiZXR3ZWVuLCBmb3IgbGl2ZSB1cGRhdGluZy5cbiAgICAgIGNvbnN0IHJlZ2lvbk9wdHMgPSB7XG4gICAgICAgIHJvbGU6ICdzdGF0dXMnLFxuICAgICAgICAnYXJpYS1saXZlJzogJ3BvbGl0ZScsXG4gICAgICAgICdhcmlhLWF0b21pYyc6ICd0cnVlJyxcbiAgICAgIH07XG5cbiAgICAgIHRoaXMuYWN0aXZlID0gMTtcbiAgICAgIHRoaXMubXNnID0gJyc7XG4gICAgICB0aGlzLnJlZ2lvbnMgPSBbXG4gICAgICAgIG5ldyB0cy5FbGVtZW50KCdkaXYnLCByZWdpb25PcHRzLCB0aGlzKSxcbiAgICAgICAgbmV3IHRzLkVsZW1lbnQoJ2RpdicsIHJlZ2lvbk9wdHMsIHRoaXMpLFxuICAgICAgXTtcblxuICAgICAgLy8gT25seSBhbm5vdW5jZSB0aGUgY2hhbmdlcyBhZnRlciBhIHNob3J0IGRlbGF5IHRvIHByZXZlbnQgdGhlIGFubm91bmNlclxuICAgICAgLy8gZnJvbSB0YWxraW5nIG92ZXIgaXRzZWxmLlxuICAgICAgdGhpcy51cGRhdGVNc2cgPSBkZWJvdW5jZSgoKSA9PiB7XG4gICAgICAgIHRoaXMucmVnaW9uc1t0aGlzLmFjdGl2ZV0udGV4dENvbnRlbnQgPSAnJztcbiAgICAgICAgdGhpcy5hY3RpdmUgXj0gMTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1iaXR3aXNlXG4gICAgICAgIHRoaXMucmVnaW9uc1t0aGlzLmFjdGl2ZV0udGV4dENvbnRlbnQgPSB0aGlzLm1zZztcbiAgICAgIH0sIDUwMCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIGN1cnJlbnQgdGV4dCBtZXNzYWdlIHRvIGFubm91bmNlIGluIHRoZSBsaXZlIHJlZ2lvbi5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge3N0cmluZ31cbiAgICAgKiAgIFJldHVybiB0aGUgY3VycmVudCBtZXNzYWdlIHRvIGJlIGFubm91bmNlZC5cbiAgICAgKi9cbiAgICBnZXQgbWVzc2FnZSgpIHtcbiAgICAgIHJldHVybiB0aGlzLm1zZztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgYSBuZXcgbWVzc2FnZSBmb3IgdGhlIGxpdmUgcmVnaW9uLiBOb3RlIHRoYXQgdGhlcmUgaXMgYSBzbWFsbCBkZWxheVxuICAgICAqIGJlZm9yZSB0aGUgbWVzc2FnZSBpcyBhbm5vdW5jZWQgdG8gYXZvaWQgY29sbGlzaW9ucyBvZiBtZXNzYWdlcyB3aGljaFxuICAgICAqIGFyZSB0b28gY2xvc2UgdG9nZXRoZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICAgICAqICAgTWVzc2FnZSB0byBzZXQgZm9yIHRoZSBsaXZlIHJlZ2lvbi5cbiAgICAgKi9cbiAgICBzZXQgbWVzc2FnZShtZXNzYWdlKSB7XG4gICAgICB0aGlzLm1zZyA9IG1lc3NhZ2U7XG4gICAgICB0aGlzLnVwZGF0ZU1zZygpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBPYmplY3Qgd2hpY2ggcmVwcmVzZW50cyBhIHNpbmdsZSBhdXRvY29tcGxldGUgc2VsZWN0IG9wdGlvbi4gVGhpcyBvYmplY3RcbiAgICogbWFuYWdlcyBpdHMgb3duIHJlc291cmNlcyBhbmQgdGhlIGRpc3BsYXkgdGV4dCBhcyB3ZWxsIGFzIHRoZSB1bmRlcmx5aW5nXG4gICAqIHZhbHVlIHRvIHBhc3MgYmFjayB0byB0aGUgb3JpZ2luYWwgaW5wdXQgZWxlbWVudC5cbiAgICovXG4gIGNsYXNzIFN1Z2dlc3RJdGVtIGV4dGVuZHMgdHMuRWxlbWVudCB7XG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGEgbmV3IFN1Z2dlc3RJdGVtIHJlcHJlc2VudGluZyB2YWx1ZXMgYW5kIGEgc2VsZWN0YWJsZSBlbGVtZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdWdnZXN0TGlzdH0gbGlzdFxuICAgICAqICAgVGhlIHN1Z2dlc3Rpb24gbGlzdCB0aGF0IHRoaXMgaXRlbSBpcyBhIG1lbWJlciBvZi5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gaWRcbiAgICAgKiAgIFRoZSBvcHRpb24gaWRlbnRpZmllciB0byB1c2UgZm9yIHRoZSBlbGVtZW50IElELlxuICAgICAqIEBwYXJhbSB7VG9vbHNoZWQuQXV0b2NvbXBsZXRlfSBhY1xuICAgICAqICAgVGhlIGNhbGxiYWNrIHdoZW4gdGhlIGl0ZW0gaXMgY2xpY2tlZCBvbi5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihsaXN0LCBpZCwgYWMpIHtcbiAgICAgIHN1cGVyKCdhJywgeyB0YWJpbmRleDogMCwgaHJlZjogJyMnIH0pO1xuXG4gICAgICB0aGlzLndyYXAgPSBuZXcgdHMuRWxlbWVudCgnbGknLCB7IGlkLCByb2xlOiAnb3B0aW9uJywgY2xhc3M6ICdhdXRvY29tcGxldGVfX29wdCcgfSk7XG4gICAgICB0aGlzLndyYXAuYXBwZW5kQ2hpbGQodGhpcyk7XG5cbiAgICAgIHRoaXMucGFyZW50ID0gbGlzdDtcbiAgICAgIHRoaXMucG9zID0gLTE7XG4gICAgICB0aGlzLnVyaSA9IG51bGw7XG5cbiAgICAgIHRoaXMub24oJ2NsaWNrJywgKGUpID0+IHtcbiAgICAgICAgaWYgKCF0aGlzLnVyaSkge1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgIGFjLnNlbGVjdEl0ZW0odGhpcyk7XG4gICAgICAgIH1cbiAgICAgIH0sIHRydWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBnZXR0ZXIgZm9yIHRoZSBTdWdnZXN0SXRlbSBlbGVtZW50IElELlxuICAgICAqL1xuICAgIGdldCBpZCgpIHtcbiAgICAgIHJldHVybiB0aGlzLndyYXAuaWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIHNldHRlciBmb3IgU3VnZ2VzdEl0ZW0gZWxlbWVudCBJRC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZVxuICAgICAqICAgVGhlIElEIHRvIHVzZWQgZm9yIHRoZSBTdWdnZXN0SXRlbSBIVE1MRWxlbWVudCBhbmQgZGVzY2VuZGFudCBJRC5cbiAgICAgKi9cbiAgICBzZXQgaWQodmFsdWUpIHtcbiAgICAgIHRoaXMud3JhcC5pZCA9IHZhbHVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgc3RvcmVkIFVSSSB2YWx1ZSBvZiB0aGlzIHN1Z2dlc3QgaXRlbS5cbiAgICAgKi9cbiAgICBnZXQgdXJsKCkge1xuICAgICAgcmV0dXJuIHRoaXMudXJpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgVVJMIG9mIHRoZSBzdWdnZXN0IGl0ZW0sIGlmIHRoZSBpdGVtIHNob3VsZCB3b3JrIGxpa2UgYSBsaW5rLFxuICAgICAqIHJhdGhlciB0aGFuIHVzZSB0aGUgYXV0b2NvbXBsZXRlIHZhbHVlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHZhbHVlXG4gICAgICogICBBIFVSTCB0aGUgU3VnZ2VzdCBpdGVtIHNob3VsZCBzZW5kIHNlbGVjdCB3aGVuIHRoZSBpdGVtIGlzIGNsaWNrZWQuXG4gICAgICovXG4gICAgc2V0IHVybCh2YWx1ZSkge1xuICAgICAgaWYgKHZhbHVlICYmIHZhbHVlICE9PSAnIycpIHtcbiAgICAgICAgdGhpcy51cmkgPSB2YWx1ZTtcbiAgICAgICAgdGhpcy5lbC5ocmVmID0gdmFsdWU7XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgdGhpcy51cmkgPSBudWxsO1xuICAgICAgICB0aGlzLmVsLmhyZWYgPSAnIyc7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlIHRoaXMgaXRlbSB0byBzaG93IGl0IGhhcyBmb2N1cy5cbiAgICAgKi9cbiAgICBmb2N1cygpIHtcbiAgICAgIHRoaXMud3JhcC5hZGRDbGFzcygnYXV0b2NvbXBsZXRlX19vcHQtLWFjdGl2ZScpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZSB0aGlzIGl0ZW0gdG8gc2hvdyB0aGF0IGl0IGRvZXNuJ3QgaGF2ZSBmb2N1cy5cbiAgICAgKi9cbiAgICBibHVyKCkge1xuICAgICAgdGhpcy53cmFwLnJlbW92ZUNsYXNzKCdhdXRvY29tcGxldGVfX29wdC0tYWN0aXZlJyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xlYW4gdXAgbGlzdGVuZXJzIGFuZCBvdGhlciBhbGxvY2F0ZWQgcmVzb3VyY2VzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtib29sfSBkZXRhY2hcbiAgICAgKiAgIFNob3VsZCB0aGUgc3VnZ2VzdCBpdGVtIGJlIHJlbW92ZWQgZnJvbSB0aGUgRE9NP1xuICAgICAqL1xuICAgIGRlc3Ryb3koZGV0YWNoKSB7XG4gICAgICB0aGlzLnBhcmVudCA9IG51bGw7XG4gICAgICBzdXBlci5kZXN0cm95KGRldGFjaCk7XG4gICAgICB0aGlzLndyYXAuZGVzdHJveShkZXRhY2gpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBIGxpc3Qgb2YgU3VnZ2VzdEl0ZW1zLCBhbmQgbWFuYWdlIHRoZSBpbnRlcmFjdGlvbnMgd2l0aCB0aGUgYXV0b2NvbXBsZXRlXG4gICAqIHN1Z2dlc3Rpb25zIHRyYXZlcnNhbCwgYnVpbGRpbmcgYW5kIGNsZWFyaW5nLlxuICAgKi9cbiAgY2xhc3MgU3VnZ2VzdExpc3QgZXh0ZW5kcyB0cy5FbGVtZW50IHtcbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYSBuZXcgbGlzdCBvZiBTdWdnZXN0SXRlbSBvYmplY3RzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdWdnZXN0TGlzdHxudWxsfSBsaXN0XG4gICAgICogICBBbiBvYmplY3QgdGhhdCBjb250YWlucyBhIGxpc3Qgb2YgU3VnZ2VzdEl0ZW0gaW5zdGFuY2VzLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB3cmFwVGFnXG4gICAgICogICBUaGUgSFRNTEVsZW1lbnQgdGFnIHRvIHVzZSB0byB3cmFwIHRoaXMgU3VnZ2VzdExpc3QuXG4gICAgICogQHBhcmFtIHtUb29sc2hlZEF1dG9jb21wbGV0ZX0gYWNcbiAgICAgKiAgIFRoZSBhdXRvY29tcGxldGUgaW5zdGFuY2UgdGhhdCBvd25zIHRoaXMgU3VnZ2VzdExpc3QuXG4gICAgICovXG4gICAgY29uc3RydWN0b3IobGlzdCwgd3JhcFRhZywgYWMpIHtcbiAgICAgIHN1cGVyKCd1bCcsIHsgY2xhc3M6ICdhdXRvY29tcGxldGVfX29wdGlvbnMnIH0pO1xuXG4gICAgICB0aGlzLml0ZW1zID0gW107XG4gICAgICB0aGlzLnBhcmVudCA9IGxpc3Q7XG4gICAgICB0aGlzLmFjID0gYWM7XG4gICAgICB0aGlzLnBvcyA9IDA7XG5cbiAgICAgIHRoaXMud3JhcCA9IG5ldyB0cy5FbGVtZW50KHdyYXBUYWcpO1xuICAgICAgdGhpcy53cmFwLmFwcGVuZENoaWxkKHRoaXMpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgY3VycmVudCBudW1iZXIgb2Ygc3VnZ2VzdHMgaW4gdGhlIGxpc3QuXG4gICAgICovXG4gICAgZ2V0IGxlbmd0aCgpIHtcbiAgICAgIGxldCBjdCA9IDA7XG5cbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5pdGVtcy5sZW5ndGg7ICsraSkge1xuICAgICAgICBjdCArPSAodGhpcy5pdGVtc1tpXSBpbnN0YW5jZW9mIFN1Z2dlc3RMaXN0KSA/IHRoaXMuaXRlbXNbaV0ubGVuZ3RoIDogMTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGN0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIElzIHRoaXMgU3VnZ2VzdExpc3QgZW1wdHkgb2Ygc2VsZWN0YWJsZSBzdWdnZXN0aW9uIGl0ZW1zP1xuICAgICAqXG4gICAgICogQHJldHVybiB7Qm9vbGVhbn1cbiAgICAgKiAgIFJldHVybnMgdHJ1ZSBpZiB0aGVyZSBhcmUgbm8gc2VsZWN0YWJsZSBpdGVtcyBjdXJyZW50bHkgYXZhaWxhYmxlXG4gICAgICogICBhcyBzdWdnZXN0aW9ucyBmb3IgdGhlIGF1dG9jb21wbGV0ZSBxdWVyeS5cbiAgICAgKi9cbiAgICBpc0VtcHR5KCkge1xuICAgICAgcmV0dXJuICF0aGlzLml0ZW1zLmxlbmd0aDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIGxhYmVsIHRvIGRpc3BsYXkgb3ZlciBhIHNldCBpdGVtcywgaWYgdGhlcmUgaXMgYSBjYXB0aW9uLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHRcbiAgICAgKiAgIFRoZSBsYWJlbCB0ZXh0IHRvIHVzZSBhcyBhIGNhcHRpb24gb3ZlciB0aGUgU3VnZ2VzdExpc3QgaXRlbXMuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGl0ZW1JZFxuICAgICAqICAgVGhlIElEIGF0dHJpYnV0ZSBmb3IgdGhlIHdyYXBwZXIgZWxlbWVudC5cbiAgICAgKi9cbiAgICBzZXRMYWJlbCh0ZXh0LCBpdGVtSWQpIHtcbiAgICAgIGlmICghdGhpcy5sYWJlbCkge1xuICAgICAgICB0aGlzLmxhYmVsID0gbmV3IHRzLkVsZW1lbnQoJ3NwYW4nLCB7IGNsYXNzOiAnYXV0b2NvbXBsZXRlX19ncm91cC1sYWJlbCcgfSk7XG4gICAgICAgIHRoaXMud3JhcC5wcmVwZW5kQ2hpbGQodGhpcy5sYWJlbCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpdGVtSWQpIHtcbiAgICAgICAgdGhpcy5sYWJlbC5zZXRBdHRycyh7IGlkOiBgJHtpdGVtSWR9LWxhYmVsYCB9KTtcbiAgICAgICAgdGhpcy5zZXRBdHRycyh7IGFyaWFMYWJlbGxlZGJ5OiBgJHtpdGVtSWR9LWxhYmVsYCB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5sYWJlbC50ZXh0Q29udGVudCA9ICh0ZXh0ICYmIHRleHQubGVuZ3RoKSA/IHRleHQgOiAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgYSBuZXcgU3VnZ2VzdEl0ZW0gdG8gdGhlIFN1Z2dlc3RMaXN0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdWdnZXN0SXRlbX0gaXRlbVxuICAgICAqICAgQWRkIGEgU3VnZ2VzdEl0ZW0gdG8gdGhlIGVuZCBvZiB0aGUgU3VnZ2VzdExpc3QuXG4gICAgICovXG4gICAgYWRkSXRlbShpdGVtKSB7XG4gICAgICB0aGlzLml0ZW1zLnB1c2goaXRlbSk7XG4gICAgICB0aGlzLmFwcGVuZENoaWxkKGl0ZW0ud3JhcCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBmaXJzdCBpdGVtIGluIHRoZSBsaXN0LlxuICAgICAqXG4gICAgICogQHJldHVybiB7U3VnZ2VzdEl0ZW18bnVsbH1cbiAgICAgKiAgIFRoZSBmaXJzdCBzZWxlY3RhYmxlIFN1Z2dlc3RJdGVtIG9yIE5VTEwgaWYgbm90IGl0ZW1zLlxuICAgICAqL1xuICAgIGdldEZpcnN0KCkge1xuICAgICAgaWYgKHRoaXMuaXRlbXMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLml0ZW1zWzBdIGluc3RhbmNlb2YgU3VnZ2VzdExpc3QgPyB0aGlzLml0ZW1zWzBdLmdldEZpcnN0KCkgOiB0aGlzLml0ZW1zWzBdO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIGxpc3QgaXRlbSBpbiB0aGUgbGlzdC5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge1N1Z2dlc3RJdGVtfG51bGx9XG4gICAgICogICBUaGUgbGFzdCBzZWxlY3RhYmxlIFN1Z2dlc3RJdGVtIGluIHRoZSBsaXN0IG9yIE5VTEwuIFRoaXMgaW5jbHVkZXNcbiAgICAgKiAgIHRoZSBsYXN0IGl0ZW0gaW4gdGhlIG5lc3RlZCBzZXQgb2YgaXRlbXMuXG4gICAgICovXG4gICAgZ2V0TGFzdCgpIHtcbiAgICAgIGlmICh0aGlzLml0ZW1zLmxlbmd0aCkge1xuICAgICAgICBjb25zdCBpZHggPSB0aGlzLml0ZW1zLmxlbmd0aCAtIDE7XG4gICAgICAgIHJldHVybiB0aGlzLml0ZW1zW2lkeF0gaW5zdGFuY2VvZiBTdWdnZXN0TGlzdCA/IHRoaXMuaXRlbXNbaWR4XS5nZXRMYXN0KCkgOiB0aGlzLml0ZW1zW2lkeF07XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCB0aGUgbGlzdCBvZiBzZWxlY3RhYmxlIFN1Z2dlc3RJdGVtcyBmcm9tIHRoZSBwYXNzZWQgaW4gZGF0YS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7YXJyYXl8b2JqZWN0fSBkYXRhXG4gICAgICogICBUaGUgZGF0YSByZXByZXNlbnRpbmcgdGhlIGF1dG9jb21wbGV0ZSBzdWdnZXN0aW9ucyAvIHZhbHVlcyBhdmFpbGFibGUuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGJhc2VJZFxuICAgICAqICAgQSBwb29sIG9mIGF2YWlsYWJsZSBTdWdnZXN0SXRlbSB0byByZXVzZS5cbiAgICAgKi9cbiAgICBidWlsZEl0ZW1zKGRhdGEsIGJhc2VJZCkge1xuICAgICAgbGV0IHBvcyA9IDA7XG5cbiAgICAgIGRhdGEuZm9yRWFjaCgocm93KSA9PiB7XG4gICAgICAgIGxldCBpdGVtO1xuICAgICAgICBjb25zdCBpdGVtSWQgPSBgJHtiYXNlSWR9LSR7cG9zfWA7XG5cbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocm93Lmxpc3QpKSB7XG4gICAgICAgICAgaWYgKCFyb3cubGlzdC5sZW5ndGgpIHJldHVybjtcblxuICAgICAgICAgIGl0ZW0gPSBuZXcgU3VnZ2VzdExpc3QodGhpcywgJ2xpJywgdGhpcy5hYyk7XG4gICAgICAgICAgaXRlbS5zZXRBdHRycyh7IHJvbGU6ICdncm91cCcgfSk7XG4gICAgICAgICAgaXRlbS5zZXRMYWJlbChyb3cudGV4dCwgaXRlbUlkKTtcbiAgICAgICAgICBpdGVtLmJ1aWxkSXRlbXMocm93Lmxpc3QsIGl0ZW1JZCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocm93LnZhbHVlKSB7XG4gICAgICAgICAgaXRlbSA9IG5ldyBTdWdnZXN0SXRlbSh0aGlzLCBpdGVtSWQsIHRoaXMuYWMpO1xuICAgICAgICAgIGl0ZW0udGV4dCA9IChyb3cudGV4dCB8fCByb3cudmFsdWUpO1xuICAgICAgICAgIGl0ZW0udmFsdWUgPSByb3cudmFsdWU7XG5cbiAgICAgICAgICBpZiAocm93LnVybCkgaXRlbS51cmwgPSByb3cudXJsO1xuXG4gICAgICAgICAgdGhpcy5hYy5pdGVtRGlzcGxheShpdGVtLCByb3cpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5hZGRJdGVtKGl0ZW0pO1xuICAgICAgICBpdGVtLnBvcyA9IHBvcysrO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIHN1Z2dlc3Rpb24gaXRlbXMgZnJvbSB0aGUgc3VnZ2VzdGlvbmVkIGl0ZW1zIGRpc3BsYXkuXG4gICAgICovXG4gICAgY2xlYXIoKSB7XG4gICAgICB0aGlzLml0ZW1zLmZvckVhY2goKGl0ZW0pID0+IGl0ZW0uZGVzdHJveSh0cnVlKSk7XG4gICAgICB0aGlzLml0ZW1zID0gW107XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xlYW5zIHVwIHRoaXMgYXV0b2NvbXBsZXRlIHN1Z2dlc3Rpb25zIGxpc3QsIGFuZCBmcmVlcyByZXNvdXJjZXMgYW5kXG4gICAgICogZXZlbnQgbGlzdGVuZXJzLlxuICAgICAqL1xuICAgIGRlc3Ryb3koKSB7XG4gICAgICBpZiAodGhpcy5sYWJlbCkge1xuICAgICAgICB0aGlzLmxhYmVsLmRlc3Ryb3kodHJ1ZSk7XG4gICAgICB9XG4gICAgICB0aGlzLmNsZWFyKCk7XG5cbiAgICAgIHN1cGVyLmRlc3Ryb3kodHJ1ZSk7XG4gICAgICB0aGlzLndyYXAuZGVzdHJveSh0cnVlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2xhc3Mgd2hpY2ggZW5jYXBzdWxhdGVzIHRoZSBiZWhhdmlvcnMgb2YgYW5kIGF1dG9jb21wbGV0ZSB3aWRnZXQgb2YgYVxuICAgKiB0ZXh0ZmllbGQuIEl0IGFsbG93cyBzdWJjbGFzc2VzIHRvIG92ZXJyaWRlIHRoZWlyIGZldGNoU3VnZ2VzdGlvbnMoKSBhbmRcbiAgICogaW5pdCgpIG1ldGhvZHMgdG8gYWxsb3cgZm9yIGRpZmZlcmVudCBtZXRob2RzIG9mIGxvYWRpbmcgYXV0b2NvbXBsZXRlXG4gICAqIGl0ZW1zIHRvIGRpc3BsYXkuXG4gICAqL1xuICB0cy5BdXRvY29tcGxldGUgPSBjbGFzcyBUb29sc2hlZEF1dG9jb21wbGV0ZSB7XG4gICAgY29uc3RydWN0b3IoaW5wdXQsIGNvbmZpZyA9IHt9KSB7XG4gICAgICBsZXQgYWM7XG5cbiAgICAgIHRoaXMuaW5wdXQgPSBpbnB1dDtcbiAgICAgIHRoaXMucGVuZGluZyA9IGZhbHNlO1xuICAgICAgdGhpcy5jb25maWcgPSB7XG4gICAgICAgIGRlbGF5OiAzNzUsXG4gICAgICAgIG1pbkxlbmd0aDogMyxcbiAgICAgICAgcmVxdWlyZVNlbGVjdDogdHJ1ZSxcbiAgICAgICAgLi4uY29uZmlnLFxuICAgICAgfTtcblxuICAgICAgLy8gUmVhc3NvY2lhdGUgYSBsYWJlbCBlbGVtZW50IHRvIHBvaW50IHRvIHRoZSBuZXcgYXV0b2NvbXBsZXRlIGlucHV0LlxuICAgICAgY29uc3QgaW5wdXRMYWJlbCA9ICh0aGlzLmlucHV0LmlkKVxuICAgICAgICA/IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYGxhYmVsW2Zvcj0nJHt0aGlzLmlucHV0LmlkfSddYCkgOiBudWxsO1xuXG4gICAgICAvLyBDcmVhdGUgdGhlIG1haW4gc3VnZ2VzdGlvbiBsaXN0IHdyYXBwZXIuXG4gICAgICBjb25zdCBsaXN0ID0gbmV3IFN1Z2dlc3RMaXN0KG51bGwsICdkaXYnLCB0aGlzKTtcbiAgICAgIGxpc3Quc2V0QXR0cnMoeyBpZDogYCR7dGhpcy5pbnB1dC5pZH0tbGlzdGJveGAsIHJvbGU6ICdsaXN0Ym94JyB9KTtcbiAgICAgIGxpc3Qub24oJ2JsdXInLCB0aGlzLm9uQmx1cik7XG4gICAgICB0aGlzLmxpc3QgPSBsaXN0O1xuXG4gICAgICBpZiAoaW5wdXRMYWJlbCkge1xuICAgICAgICBpZiAoIWlucHV0TGFiZWwuaWQpIGlucHV0TGFiZWwuaWQgPSBgJHt0aGlzLmlucHV0LmlkfS1sYWJlbGA7XG4gICAgICAgIGxpc3Quc2V0QXR0cignYXJpYS1sYWJlbGxlZGJ5JywgaW5wdXRMYWJlbC5pZCk7XG4gICAgICB9XG5cbiAgICAgIC8vIENyZWF0ZSBhdXRvLXN1Z2dlc3Rpb24gcGFuZS5cbiAgICAgIGNvbnN0IHdyYXBwZXIgPSBuZXcgdHMuRWxlbWVudCgnZGl2JywgeyBjbGFzczogJ2F1dG9jb21wbGV0ZV9fb3B0aW9ucy1wYW5lJywgc3R5bGU6IHsgZGlzcGxheTogJ25vbmUnIH0gfSk7XG4gICAgICB3cmFwcGVyLm9uKCdtb3VzZWRvd24nLCB0aGlzLm9uTW91c2VEb3duLmJpbmQodGhpcykpO1xuICAgICAgd3JhcHBlci5hcHBlbmRDaGlsZChsaXN0LndyYXApO1xuICAgICAgd3JhcHBlci5hdHRhY2hUbyh0aGlzLmlucHV0LCAnYWZ0ZXInKTtcbiAgICAgIHRoaXMuc3VnZ2VzdFdyYXAgPSB3cmFwcGVyO1xuXG4gICAgICAvLyBDcmVhdGUgYSBjb250YWluZXIgZm9yIGRpc3BsYXlpbmcgZW1wdHkgcmVzdWx0cyBtZXNzYWdlLlxuICAgICAgdGhpcy5lbXB0eU1zZyA9IG5ldyB0cy5FbGVtZW50KCdkaXYnLCB7XG4gICAgICAgIGNsYXNzOiAnYXV0b2NvbXBsZXRlX19lbXB0eS1tc2cnLFxuICAgICAgICBzdHlsZTogeyBkaXNwbGF5OiAnbm9uZScgfSxcbiAgICAgIH0sIHdyYXBwZXIpO1xuXG4gICAgICAvLyBDcmVhdGUgYSBsaXZlIHJlZ2lvbiBmb3IgYW5ub3VuY2luZyByZXN1bHQgdXBkYXRlcy5cbiAgICAgIHRoaXMubGl2ZVJlZ2lvbiA9IG5ldyBMaXZlUmVnaW9uKCk7XG5cbiAgICAgIC8vIERldGVybWluZSBpZiB0aGUgYXV0b2NvbXBsZXRlIHZhbHVlIGlzIHNlcGFyYXRlIGZyb20gdGhlIGRpc3BsYXllZFxuICAgICAgLy8gdGV4dC4gV2hlbiB0aGlzIHZhbHVlIGlzIHNwbGl0LCB3ZSBoYXZlIGEgY2xvbmVkIEFDIHRleHRmaWVsZC5cbiAgICAgIGlmICh0aGlzLmNvbmZpZy5zZXBhcmF0ZVZhbHVlKSB7XG4gICAgICAgIGFjID0gbmV3IHRzLkZvcm1FbGVtZW50KHRoaXMuaW5wdXQuY2xvbmVOb2RlKCksIHtcbiAgICAgICAgICBwbGFjZWhvbGRlcjogdGhpcy5pbnB1dC5wbGFjZWhvbGRlcixcbiAgICAgICAgICB2YWx1ZTogdGhpcy5pbnB1dC5kYXRhc2V0LnRleHQgfHwgdGhpcy5mb3JtYXREaXNwbGF5VmFsdWUodGhpcy5pbnB1dC52YWx1ZSkgfHwgJycsXG4gICAgICAgICAgJ2FyaWEtYXV0b2NvbXBsZXRlJzogJ2xpc3QnLFxuICAgICAgICB9KTtcbiAgICAgICAgYWMucmVtb3ZlQ2xhc3MoJ3Rvb2xzaGVkLWF1dG9jb21wbGV0ZScpO1xuICAgICAgICBhYy5yZW1vdmVBdHRycyhbJ25hbWUnLCAnZGF0YS1hdXRvY29tcGxldGUnXSk7XG5cbiAgICAgICAgdGhpcy5pbnB1dC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgICBhYy5hdHRhY2hUbyh0aGlzLmlucHV0LCAnYWZ0ZXInKTtcblxuICAgICAgICAvLyBSZW1vdmUgdGhlc2UgRHJ1cGFsIHByb3BlcnRpZXMgYXMgdGhpcyBpcyBqdXN0IGEgc3RhbmQtaW4gb2JqZWN0XG4gICAgICAgIC8vIGFuZCB3ZSBkb24ndCB3YW50IHRvIHN1Ym1pdCBvciB0byBjYXRjaCBhbnkgRHJ1cGFsIGJlaGF2aW9ycy5cbiAgICAgICAgZGVsZXRlIGFjLmRhdGFzZXQuZHJ1cGFsU2VsZWN0b3I7XG4gICAgICAgIGRlbGV0ZSBhYy5kYXRhc2V0LmF1dG9jb21wbGV0ZVBhdGg7XG4gICAgICAgIGRlbGV0ZSBhYy5kYXRhc2V0LnRleHQ7XG5cbiAgICAgICAgLy8gUmVhc3NvY2lhdGUgYSBsYWJlbCBlbGVtZW50IHRvIHBvaW50IHRvIHRoZSBuZXcgYXV0b2NvbXBsZXRlIGlucHV0LlxuICAgICAgICBpZiAoaW5wdXRMYWJlbCkge1xuICAgICAgICAgIGFjLmlkID0gYCR7dGhpcy5pbnB1dC5pZH0tYXV0b2NvbXBsZXRlYDtcbiAgICAgICAgICBpbnB1dExhYmVsLmh0bWxGb3IgPSBhYy5pZDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSB7XG4gICAgICAgIGFjID0gbmV3IHRzLkZvcm1FbGVtZW50KHRoaXMuaW5wdXQpO1xuICAgICAgICBhYy5zZXRBdHRyKCdhcmlhLWF1dG9jb21wbGV0ZScsICdib3RoJyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYWMgPSBhYztcbiAgICAgIGFjLnNldEF0dHJzKHtcbiAgICAgICAgY2xhc3M6ICdmb3JtLWF1dG9jb21wbGV0ZScsXG4gICAgICAgIGF1dG9jb21wbGV0ZTogJ29mZicsXG4gICAgICAgIHJvbGU6ICdjb21ib2JveCcsXG4gICAgICAgICdhcmlhLW93bnMnOiBsaXN0LmlkLFxuICAgICAgICAnYXJpYS1oYXNwb3B1cCc6ICdsaXN0Ym94JyxcbiAgICAgICAgJ2FyaWEtZXhwYW5kZWQnOiAnZmFsc2UnLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIEJpbmQga2V5IGNoYW5nZSBldmVudHMuXG4gICAgICBhYy5vbigna2V5ZG93bicsIHRoaXMub25UZXh0S2V5ZG93bi5iaW5kKHRoaXMpKTtcbiAgICAgIGFjLm9uKCdpbnB1dCcsIHRoaXMub25UZXh0Q2hhbmdlLmJpbmQodGhpcykpO1xuICAgICAgYWMub24oJ2ZvY3VzJywgdGhpcy5vbkZvY3VzLmJpbmQodGhpcykpO1xuICAgICAgYWMub24oJ2JsdXInLCB0aGlzLm9uQmx1ci5iaW5kKHRoaXMpKTtcblxuICAgICAgaWYgKHRoaXMuY29uZmlnLmRlbGF5ID4gMCkge1xuICAgICAgICB0aGlzLmZldGNoU3VnZ2VzdGlvbnMgPSBkZWJvdW5jZSh0aGlzLmZldGNoU3VnZ2VzdGlvbnMsIHRoaXMuY29uZmlnLmRlbGF5KTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuY29uZmlnLnBhcmFtcyAmJiB0aGlzLmlucHV0LmZvcm0pIHtcbiAgICAgICAgY29uc3QgeyBmb3JtIH0gPSB0aGlzLmlucHV0O1xuICAgICAgICB0aGlzLm9uUGFyYW1DaGFuZ2UgPSB0aGlzLm9uUGFyYW1DaGFuZ2UuYmluZCh0aGlzKTtcblxuICAgICAgICBPYmplY3QudmFsdWVzKHRoaXMuY29uZmlnLnBhcmFtcykuZm9yRWFjaCgoZWxlbUlkKSA9PiB7XG4gICAgICAgICAgY29uc3QgZWwgPSBmb3JtLnF1ZXJ5U2VsZWN0b3IoYCMke2VsZW1JZH1gKTtcblxuICAgICAgICAgIGlmIChlbCkgZWwuYWRkRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgdGhpcy5vblBhcmFtQ2hhbmdlKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVmcmVzaCB0aGUgYXV0b2NvbXBsZXRlIHN1Z2dlc3RzIHRvIGRpc3BsYXkuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdH0gW2RhdGE9e31dXG4gICAgICogICBWYWx1ZXMgdG8gdXNlIGFzIHRoZSBhdXRvY29tcGxldGUgc3VnZ2VzdGlvbnMuIFRoZSBwcm9wZXJ0eSBrZXlzIGFyZVxuICAgICAqICAgdGhlIHZhbHVlLCBhbmQgdGhlIHByb3BlcnR5IHZhbHVlcyBhcmUgdGhlIGRpc3BsYXkgYXV0b2NvbXBsZXRlIHZhbHVlLlxuICAgICAqL1xuICAgIGNyZWF0ZVN1Z2dlc3Rpb25zKGRhdGEgPSB7fSkge1xuICAgICAgdGhpcy5hY3RpdmVJdGVtID0gbnVsbDtcblxuICAgICAgaWYgKCF0aGlzLmxpc3QuaXNFbXB0eSgpKSB7XG4gICAgICAgIHRoaXMubGlzdC5jbGVhcigpO1xuICAgICAgfVxuXG4gICAgICBpZiAoZGF0YS5saXN0Lmxlbmd0aCkge1xuICAgICAgICBpZiAodGhpcy5lbXB0eU1zZy5zdHlsZS5kaXNwbGF5ICE9PSAnbm9uZScpIHtcbiAgICAgICAgICB0aGlzLmVtcHR5TXNnLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmxpc3QuYnVpbGRJdGVtcyhkYXRhLmxpc3QsIGAke3RoaXMuaW5wdXQuaWR9LW9wdGApO1xuICAgICAgfVxuICAgICAgZWxzZSB7XG4gICAgICAgIHRoaXMuZW1wdHlNc2cudGV4dENvbnRlbnQgPSAoZGF0YS5lbXB0eSkgPyBkYXRhLmVtcHR5IDogJ05vIHJlc3VsdHMnO1xuICAgICAgICB0aGlzLmVtcHR5TXNnLnN0eWxlLmRpc3BsYXkgPSAnJztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGb3JtYXQgdGhlIGlucHV0IHZhbHVlIHRvIHRoZSBkaXNwbGF5IHRleHQuIEJ5IGRlZmF1bHQgdGhlIHRleHQgdGhhdCBhcHBlYXJzIGJlZm9yZSBcIjpcIiBpc1xuICAgICAqIGhpZGRlbiBhbmQgY29uc2lkZXJlZCBhbiBpbnRlcm5hbCB2YWx1ZSBzd2l0Y2guIFN1YmNsYXNzZXMgb2YgdGhpcyBhdXRvY29tcGxldGUgY2FuXG4gICAgICogb3ZlcnJpZGUgdGhpcyBhbmQgZGVmaW5lIHRoZWlyIG93biBkaXNwbGF5IHRleHQgdmFsdWUgZm9ybWF0dGluZy5cbiAgICAgKi9cbiAgICBmb3JtYXREaXNwbGF5VmFsdWUodmFsdWUpIHtcbiAgICAgIHJldHVybiB2YWx1ZSA/IHZhbHVlLnJlcGxhY2UoL15bXjpdKj9cXHMqOlxccyovLCAnJykgOiAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGVhciB0aGUgY3VycmVudCBpbnB1dC5cbiAgICAgKi9cbiAgICBjbGVhcklucHV0KCkge1xuICAgICAgdGhpcy5hYy52YWx1ZSA9ICcnO1xuICAgICAgdGhpcy5pbnB1dC52YWx1ZSA9ICcnO1xuICAgICAgdGhpcy5jbGVhclN1Z2dlc3Rpb25zKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGV4aXN0aW5nIGF1dG9jb21wbGV0ZSBzdWdnZXN0aW9ucy5cbiAgICAgKi9cbiAgICBjbGVhclN1Z2dlc3Rpb25zKCkge1xuICAgICAgdGhpcy5hYy5yZW1vdmVBdHRycygnYXJpYS1hY3RpdmVkZXNjZW5kYW50Jyk7XG4gICAgICB0aGlzLmFjdGl2ZUl0ZW0gPSBudWxsO1xuICAgICAgdGhpcy5saXN0LmNsZWFyKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSXMgdGhlIHN1Z2dlc3Rpb24gd2luZG93IG9wZW4/XG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtCb29sZWFufVxuICAgICAqICAgVFJVRSBpZiB0aGUgc3VnZ2VzdGlvbnMgd2luZG93IGlzIG9wZW4sIG90aGVyd2lzZSBGQUxTRS5cbiAgICAgKi9cbiAgICBpc1N1Z2dlc3Rpb25zVmlzaWJsZSgpIHtcbiAgICAgIHJldHVybiB0aGlzLnN1Z2dlc3RXcmFwLnN0eWxlLmRpc3BsYXkgIT09ICdub25lJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQb3NpdGlvbiBhbmQgZXhwb3NlIHRoZSBzdWdnZXN0aW9ucyB3aW5kb3cgaWYgaXQgaXMgbm90IGFscmVhZHkgb3Blbi5cbiAgICAgKi9cbiAgICBkaXNwbGF5U3VnZ2VzdGlvbnMoKSB7XG4gICAgICBpZiAoIXRoaXMuaXNTdWdnZXN0aW9uc1Zpc2libGUoKSkge1xuICAgICAgICB0aGlzLnN1Z2dlc3RXcmFwLnNldFN0eWxlcyh7XG4gICAgICAgICAgZGlzcGxheTogJycsXG4gICAgICAgICAgd2lkdGg6IGAke3RoaXMuYWMuZWwuY2xpZW50V2lkdGh9cHhgLFxuICAgICAgICAgIHRvcDogYCR7dGhpcy5hYy5lbC5vZmZzZXRUb3AgKyB0aGlzLmFjLmVsLm9mZnNldEhlaWdodH1weGAsXG4gICAgICAgICAgbGVmdDogYCR7dGhpcy5hYy5lbC5vZmZzZXRMZWZ0fXB4YCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5hYy5zZXRBdHRycyh7ICdhcmlhLWV4cGFuZGVkJzogJ3RydWUnIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBjdCA9IHRoaXMubGlzdC5sZW5ndGg7XG4gICAgICB0aGlzLmxpdmVSZWdpb24ubWVzc2FnZSA9IGN0ID4gMFxuICAgICAgICA/IHQoJ0Bjb3VudCByZXN1bHRzIGF2YWlsYWJsZSwgdXNlIHVwIGFuZCBkb3duIGFycm93IGtleXMgdG8gbmF2aWdhdGUuJywgeyAnQGNvdW50JzogY3QgfSlcbiAgICAgICAgOiB0KCdObyBzZWFyY2ggcmVzdWx0cy4nKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIaWRlIHRoZSBzdWdnZXN0aW9ucyB3aW5kb3cgaWYgaXQgaXMgb3BlbiBhbmQgcmVzZXQgdGhlIGFjdGl2ZSBpdGVtLlxuICAgICAqL1xuICAgIGhpZGVTdWdnZXN0aW9ucygpIHtcbiAgICAgIHRoaXMuYWN0aXZlSXRlbSA9IG51bGw7XG4gICAgICB0aGlzLnN1Z2dlc3RXcmFwLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICB0aGlzLmFjLnNldEF0dHJzKHsgJ2FyaWEtZXhwYW5kZWQnOiAnZmFsc2UnIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSB0aGUgY29udGVudCB0byBkaXNwbGF5IGluIHRoZSBhdXRvY29tcGxldGUuXG4gICAgICpcbiAgICAgKiBIYW5kbGVzIGVpdGhlciBidWlsZGluZyBhIHNpbXBsZSB0ZXh0IGRpc3BsYXkgb3IgYnVpbGRpbmcgdGhlIEhUTUwgdG9cbiAgICAgKiBhIGNvbXBsZXggZGlzcGxheSwgd2l0aCBhIHRleHQgbGFiZWwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1N1Z2dlc3RJdGVtfSBpdGVtXG4gICAgICogICBUaGUgc3VnZ2VzdGlvbiBpdGVtIHRvIGNoYW5nZSB0aGUgaW5uZXIgY29udGVudCBvZi5cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICAgICAqICAgVGhlIHJhdyBkYXRhIGZyb20gdGhlIGF1dG9jb21wbGV0ZSByZXNwb25zZS5cbiAgICAgKi9cbiAgICBpdGVtRGlzcGxheShpdGVtLCBkYXRhKSB7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgY2xhc3MtbWV0aG9kcy11c2UtdGhpc1xuICAgICAgaWYgKGRhdGEuaHRtbCkge1xuICAgICAgICBpdGVtLmlubmVySFRNTCA9IGRhdGEuaHRtbDtcbiAgICAgICAgaXRlbS5zZXRBdHRycyh7ICdhcmlhLWxhYmVsJzogZGF0YS50ZXh0IHx8IGRhdGEudmFsdWUgfSk7XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgaXRlbS50ZXh0Q29udGVudCA9IGl0ZW0udGV4dCB8fCBpdGVtLnZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBhIFN1Z2dlc3RJdGVtIGFzIGN1cnJlbnRseSBhY3RpdmUgYmFzZWQgb24gdGhlIGluZGV4LiBUaGlzIG1ldGhvZFxuICAgICAqIGVuc3VyZXMgdGhhdCBhbnkgY3VycmVudGx5IGFjdGl2ZSBpdGVtcyBhcmUgYmx1cnJlZCAodW5mb2N1c2VkKSBhbmRcbiAgICAgKiBpZiB0aGUgcmVxdWVzdGVkIGluZGV4IGlzIG91dCBvZiByYW5nZSwgdG8gc2VsZWN0IG5vIGl0ZW1zLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdWdnZXN0SXRlbX0gaXRlbVxuICAgICAqICAgVGhlIGl0ZW0gdG8gc2V0IGFzIHRoZSBjdXJyZW50IGFjdGl2ZSBpdGVtLlxuICAgICAqL1xuICAgIHNldEFjdGl2ZUl0ZW0oaXRlbSkge1xuICAgICAgaWYgKHRoaXMuYWN0aXZlSXRlbSkgdGhpcy5hY3RpdmVJdGVtLmJsdXIoKTtcblxuICAgICAgaWYgKGl0ZW0pIHtcbiAgICAgICAgaXRlbS5mb2N1cygpO1xuICAgICAgICB0aGlzLmFjdGl2ZUl0ZW0gPSBpdGVtO1xuXG4gICAgICAgIGlmIChpdGVtLmlkKSB7XG4gICAgICAgICAgdGhpcy5hYy5zZXRBdHRycyh7ICdhcmlhLWFjdGl2ZWRlc2NlbmRhbnQnOiBpdGVtLmlkIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5hY3RpdmVJdGVtID0gbnVsbDtcbiAgICAgICAgdGhpcy5hYy5yZW1vdmVBdHRycygnYXJpYS1hY3RpdmVkZXNjZW5kYW50Jyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJhbnNmZXIgdGhlIHZhbHVlcyBmcm9tIHRoZSBwYXNzZWQgaW4gaXRlbSB0byB0aGUgZm9ybSBlbGVtZW50cy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7U3VnZ2VzdEl0ZW19IGl0ZW1cbiAgICAgKiAgIEl0ZW0gdG8gYXBwbHkgdG8gYXMgdGhlIHZhbHVlcyBvZiB0aGUgYXV0b2NvbXBsZXRlIHdpZGdldC5cbiAgICAgKi9cbiAgICBzZWxlY3RJdGVtKGl0ZW0pIHtcbiAgICAgIGlmIChpdGVtLnVybCkge1xuICAgICAgICB3aW5kb3cubG9jYXRpb24gPSBpdGVtLnVybDtcbiAgICAgIH1cbiAgICAgIGVsc2Uge1xuICAgICAgICBpZiAodGhpcy5hYy5lbCAhPT0gdGhpcy5pbnB1dCkge1xuICAgICAgICAgIHRoaXMuYWMudmFsdWUgPSBpdGVtLnRleHQgfHwgaXRlbS52YWx1ZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmlucHV0LnZhbHVlID0gaXRlbS52YWx1ZTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5oaWRlU3VnZ2VzdGlvbnMoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNYWtlIHRoZSBuZWNlc3NhcnkgcmVxdWVzdHMgYW5kIGNhbGxzIHRvIGdldCBhdmFpbGFibGUgdGV4dCB2YWx1ZXMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dFxuICAgICAqICAgVGhlIHRleHQgdG8gdHJ5IHRvIG1hdGNoIHVzaW5nIHRoZSBhdXRvY29tcGxldGUgc2VydmljZSB0b1xuICAgICAqICAgZ2VuZXJhdGUgc3VnZ2VzdGlvbnMgd2l0aC5cbiAgICAgKiBAcGFyYW0ge2Jvb2x9IGRpc3BsYXlcbiAgICAgKiAgIFNob3VsZCB0aGUgc3VnZ2VzdGlvbnMgbGlzdCBiZSBkaXNwbGF5ZWQgYWZ0ZXIgZmV0Y2hpbmcgc3VnZ2VzdGlvbnMuXG4gICAgICovXG4gICAgZmV0Y2hTdWdnZXN0aW9ucyh0ZXh0LCBkaXNwbGF5ID0gdHJ1ZSkge1xuICAgICAgaWYgKCF0aGlzLnJlcXVlc3Rlcikge1xuICAgICAgICB0aGlzLnJlcXVlc3RlciA9IHRzLmNyZWF0ZVJlcXVlc3Rlcih0aGlzLmNvbmZpZy51cmkpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5wZW5kaW5nICYmICF0aGlzLnBlbmRpbmcucHJvbWlzZS5pc1Jlc29sdmVkKSB7XG4gICAgICAgIC8vIEFib3J0IGFueSBwcmV2aW91c2x5IHBlbmRpbmcgcmVxdWVzdHMsIHNvIHRoaXMgbGF0ZSByZXNwb25zZVxuICAgICAgICAvLyB3b24ndCBvdmVyd3JpdGUgb3VyIGRlc2lyZWQgdmFsdWVzIGlmIGl0IHJldHVybnMgb3V0IG9mIG9yZGVyLlxuICAgICAgICB0aGlzLnBlbmRpbmcueGhyLmFib3J0KCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghdGV4dCB8fCB0ZXh0Lmxlbmd0aCA8IHRoaXMuY29uZmlnLm1pbkxlbmd0aCkge1xuICAgICAgICBpZiAodGhpcy5pc1N1Z2dlc3Rpb25zVmlzaWJsZSgpKSB0aGlzLmhpZGVTdWdnZXN0aW9ucygpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIFR1cm4gb24gdGhlIGxvYWRpbmcgc3Bpbm5lci5cbiAgICAgIHRoaXMuYWMuYWRkQ2xhc3MoJ3VpLWF1dG9jb21wbGV0ZS1sb2FkaW5nJyk7XG5cbiAgICAgIC8vIEFwcGx5IGFkZGl0aW9uYWwgcmVxdWVzdCBwYXJhbWV0ZXJzIGlmIHRoZXJlIGFyZSBsaW5rZWQgaW5wdXRzLlxuICAgICAgY29uc3QgcmVxdWVzdFBhcmFtcyA9IHt9O1xuICAgICAgaWYgKHRoaXMuY29uZmlnLnBhcmFtcykge1xuICAgICAgICBPYmplY3QuZW50cmllcyh0aGlzLmNvbmZpZy5wYXJhbXMpLmZvckVhY2goKFtrZXksIGVsZW1JZF0pID0+IHtcbiAgICAgICAgICBjb25zdCBpbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGVsZW1JZCk7XG5cbiAgICAgICAgICBpZiAoaW5wdXQgJiYgaW5wdXQudmFsdWUpIHJlcXVlc3RQYXJhbXNba2V5XSA9IGlucHV0LnZhbHVlO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJlcXVlc3RQYXJhbXMucSA9IHRleHQ7XG5cbiAgICAgIHRoaXMucGVuZGluZyA9IHRoaXMucmVxdWVzdGVyKHJlcXVlc3RQYXJhbXMpO1xuICAgICAgdGhpcy5wZW5kaW5nLnByb21pc2UudGhlbihcbiAgICAgICAgKHJlc3BvbnNlKSA9PiB7XG4gICAgICAgICAgdGhpcy5jbGVhckxvYWRpbmcodGhpcy5hYyk7XG4gICAgICAgICAgdGhpcy5jcmVhdGVTdWdnZXN0aW9ucyhyZXNwb25zZSk7XG5cbiAgICAgICAgICAvLyBJZiByZXF1ZXN0ZWQgdG8gZGlzcGxheSBzdWdnZXN0aW9ucyBhZnRlciB0aGV5IGxvYWQuXG4gICAgICAgICAgaWYgKGRpc3BsYXkpIHRoaXMuZGlzcGxheVN1Z2dlc3Rpb25zKCk7XG4gICAgICAgIH0sXG4gICAgICAgIChyZWFzb24pID0+IHtcbiAgICAgICAgICAvLyBPbmx5IHJlbW92ZSB0aGUgYXV0b2NvbXBsZXRlIGxvYWRpbmcgaWYgdGhlIHJlcXVlc3Qgd2FzIGFib3J0ZWQuXG4gICAgICAgICAgaWYgKCEocmVhc29uLm1lc3NhZ2UgJiYgcmVhc29uLm1lc3NhZ2UgPT09ICdDYW5jZWxsZWQnKSkge1xuICAgICAgICAgICAgdGhpcy5jbGVhckxvYWRpbmcodGhpcy5hYyk7XG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGVhciB0aGUgYXV0b2NvbXBsZXRlIGxvYWRpbmcgc3RhdHVzIGFuZCBkaXNwbGF5cy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7VG9vbHNoZWRFbGVtZW50fSBlbFxuICAgICAqICAgQXV0b2NvbXBsZXRlIGVsZW1lbnQgdG8gcmVtb3ZlIGxvYWRpbmcgc3RhdHVzIGZyb20uXG4gICAgICovXG4gICAgY2xlYXJMb2FkaW5nKGVsKSB7XG4gICAgICAvLyBDbGVhciB0aGUgbG9hZGluZyBzcGlubmVyLlxuICAgICAgZWwucmVtb3ZlQ2xhc3MoWyd1aS1hdXRvY29tcGxldGUtbG9hZGluZycsICdpcy1hdXRvY29tcGxldGluZyddKTtcblxuICAgICAgLy8gSGlkZSBDbGFybyBvciBvdGhlciB0aGVtZSBhdXRvY29tcGxldGUgbWVzc2FnZSBlbGVtZW50cy5cbiAgICAgIGNvbnN0IG1zZyA9IGVsLnBhcmVudEVsZW1lbnQucXVlcnlTZWxlY3RvcignOnNjb3BlID4gW2RhdGEtZHJ1cGFsLXNlbGVjdG9yPVwiYXV0b2NvbXBsZXRlLW1lc3NhZ2VcIl0nKTtcbiAgICAgIGlmIChtc2cpIHtcbiAgICAgICAgbXNnLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdoZW4gZm9jdXMgaXMgb24gdGhlIGF1dG9jb21wbGV0ZSBpbnB1dCwgc2hvdyBzdWdnZXN0aW9ucyBpZiB0aGV5IGV4aXN0LlxuICAgICAqL1xuICAgIG9uRm9jdXMoKSB7XG4gICAgICBpZiAoIXRoaXMubGlzdC5pc0VtcHR5KCkpIHtcbiAgICAgICAgdGhpcy5kaXNwbGF5U3VnZ2VzdGlvbnMoKTtcbiAgICAgIH1cbiAgICB9XG5cblxuICAgIC8qKlxuICAgICAqIFdoZW4gZm9jdXMgbGVhdmVzIHRoZSBhdXRvY29tcGxldGUgaW5wdXQsIGhpZGUgc3VnZ2VzdGlvbnMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0JsdXJFdmVudH0gZVxuICAgICAqICAgVGhlIGJsdXIgZXZlbnQgaW5mb3JtYXRpb24gZm9yIHdoZW4gdGhlIGF1dG9jb21wbGV0ZSBsb3NlcyBmb2N1cy5cbiAgICAgKi9cbiAgICBvbkJsdXIoZSkge1xuICAgICAgaWYgKHRoaXMuaXNTdWdnZXN0aW9uc1Zpc2libGUoKSkge1xuICAgICAgICBpZiAoIWUucmVsYXRlZFRhcmdldCB8fCAhKGUucmVsYXRlZFRhcmdldCA9PT0gdGhpcy5hYy5lbCB8fCBlLnJlbGF0ZWRUYXJnZXQuY2xvc2VzdCgnW3JvbGU9bGlzdGJveF0nKSA9PT0gdGhpcy5saXN0LmVsKSkge1xuICAgICAgICAgIHRoaXMuaGlkZVN1Z2dlc3Rpb25zKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYSBtb3VzZSBkb3duIGV2ZW50IHdoaWNoIGF2b2lkcyBoYXZpbmcgdGhlIEFDIGlucHV0IGxvc2UgZm9jdXNcbiAgICAgKiBmcm9tIGNsaWNraW5nIGludG8gdGhlIHN1Z2dlc3Rpb25zIHdyYXBwZXIuIFRoaXMgaW5jb252ZW5pZW50bHkgcHJldmVudHNcbiAgICAgKiB0aGUgY2xpY2sgZXZlbnQgYmVjYXVzZSBpdCBoaWRlcyB0aGUgc3VnZ2VzdGlvbnMgYmVmb3JlIHRoZSBjbGljayBldmVudFxuICAgICAqIGNhbiBvY2N1ci5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7RXZlbnR9IGV2ZW50XG4gICAgICogICBUaGUgbW91c2UgZG93biBldmVudCBvYmplY3QuXG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNsYXNzLW1ldGhvZHMtdXNlLXRoaXNcbiAgICBvbk1vdXNlRG93bihldmVudCkge1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDYWxsYmFjayBmb3IgdXBkYXRpbmcgdGhlIGlucHV0IHZhbHVlIHdoZW4gdGhlIHRleHRmaWVsZCBpcyB1cGRhdGVkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtFdmVudH0gZXZlbnRcbiAgICAgKiAgIFRoZSBpbnB1dCBjaGFuZ2VkIGV2ZW50IG9iamVjdC5cbiAgICAgKi9cbiAgICBvblRleHRDaGFuZ2UoZXZlbnQpIHtcbiAgICAgIGlmICh0aGlzLmFjLmVsICE9PSB0aGlzLmlucHV0KSB7XG4gICAgICAgIHRoaXMuaW5wdXQudmFsdWUgPSB0aGlzLmNvbmZpZy5yZXF1aXJlU2VsZWN0ID8gJycgOiB0aGlzLmFjLmVsLnZhbHVlO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmZldGNoU3VnZ2VzdGlvbnMoZXZlbnQudGFyZ2V0LnZhbHVlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnB1dCB2YWx1ZSBjaGFuZ2VkIGNhbGxiYWNrIHRvIHJlZnJlc2ggb3VyIGlucHV0IHZhbHVlcyB3aGVuIGFcbiAgICAgKiBkZXBlbmRlbnQgcGFyYW1ldGVyIGNoYW5nZXMuXG4gICAgICovXG4gICAgb25QYXJhbUNoYW5nZSgpIHtcbiAgICAgIHRoaXMuY2xlYXJJbnB1dCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlc3BvbmQgdG8ga2V5Ym9hcmQgbmF2aWdhdGlvbiwgYW5kIG1vdmUgdGhlIGFjdGl2ZSBpdGVtLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtLZXlkb3duRXZlbnR9IGVcbiAgICAgKiAgIFJlc3BvbmQgdG8gYSBrZXktdXAgZXZlbnQgZm9yIHRoZSBhdXRvY29tcGxldGUgaW5wdXQgdGV4dGZpZWxkLlxuICAgICAqL1xuICAgIG9uVGV4dEtleWRvd24oZSkge1xuICAgICAgaWYgKCF0aGlzLmlzU3VnZ2VzdGlvbnNWaXNpYmxlKCkpIHJldHVybjtcblxuICAgICAgbGV0IGluYztcbiAgICAgIGxldCBtZXRob2Q7XG5cbiAgICAgIHN3aXRjaCAoZS5rZXlDb2RlKSB7XG4gICAgICAgIGNhc2UgMTM6IC8vIEVudGVyIGtleVxuICAgICAgICAgIGlmICh0aGlzLmFjdGl2ZUl0ZW0pIHtcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIHRoaXMuc2VsZWN0SXRlbSh0aGlzLmFjdGl2ZUl0ZW0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAvLyBlc2xpbnQtaWdub3JlLWxpbmUgbm8tZmFsbHRocm91Z2hcbiAgICAgICAgY2FzZSA5OiAvLyBUYWIga2V5XG4gICAgICAgIGNhc2UgMjc6IC8vIEVzY2FwZSBrZXlcbiAgICAgICAgICB0aGlzLmhpZGVTdWdnZXN0aW9ucygpO1xuICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBjYXNlIDQwOiAvLyBVcCBrZXlcbiAgICAgICAgICBtZXRob2QgPSBTdWdnZXN0TGlzdC5wcm90b3R5cGUuZ2V0Rmlyc3Q7XG4gICAgICAgICAgaW5jID0gMTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlIDM4OiAvLyBEb3duIGtleVxuICAgICAgICAgIG1ldGhvZCA9IFN1Z2dlc3RMaXN0LnByb3RvdHlwZS5nZXRMYXN0O1xuICAgICAgICAgIGluYyA9IC0xO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgIGxldCBpdGVtID0gdGhpcy5hY3RpdmVJdGVtO1xuICAgICAgaWYgKGl0ZW0pIHtcbiAgICAgICAgbGV0IHAgPSBpdGVtLnBhcmVudDtcbiAgICAgICAgbGV0IGkgPSBpdGVtLnBvcyArIGluYztcblxuICAgICAgICB3aGlsZSAocCAmJiAoaSA8IDAgfHwgcC5pdGVtcy5sZW5ndGggPT09IGkpKSB7XG4gICAgICAgICAgaXRlbSA9IHA7XG4gICAgICAgICAgaSA9IGl0ZW0ucG9zICsgaW5jO1xuICAgICAgICAgIHAgPSBpdGVtLnBhcmVudDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwKSB7XG4gICAgICAgICAgaXRlbSA9IHAuaXRlbXNbaV07XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaXRlbSA9IGl0ZW0gfHwgdGhpcy5saXN0O1xuICAgICAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBTdWdnZXN0TGlzdCkge1xuICAgICAgICBpdGVtID0gbWV0aG9kLmNhbGwoaXRlbSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuc2V0QWN0aXZlSXRlbShpdGVtKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGVhbiB1cCBET00gYW5kIGV2ZW50IGxpc3RlbmVycyBpbml0aWFsaXplZCBieSB0aGlzIGF1dG9jb21wZXRlIHdpZGdldC5cbiAgICAgKi9cbiAgICBkZXN0cm95KCkge1xuICAgICAgLy8gQWJvcnQgYW55IHBlbmRpbmcgcmVxdWVzdCBmb3IgdGhpcyB3aWRnZXQuXG4gICAgICBpZiAodGhpcy5wZW5kaW5nICYmICF0aGlzLnBlbmRpbmcucHJvbWlzZS5pc1Jlc29sdmVkKSB7XG4gICAgICAgIHRoaXMucGVuZGluZy54aHIuYWJvcnQoKTtcbiAgICAgIH1cbiAgICAgIGRlbGV0ZSB0aGlzLnBlbmRpbmc7XG5cbiAgICAgIGlmICh0aGlzLmNvbmZpZy5wYXJhbXMpIHtcbiAgICAgICAgT2JqZWN0LnZhbHVlcyh0aGlzLmNvbmZpZy5wYXJhbXMpLmZvckVhY2goKGVsZW1JZCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoZWxlbUlkKTtcblxuICAgICAgICAgIGlmIChlbCkgZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcignY2hhbmdlJywgdGhpcy5vblBhcmFtQ2hhbmdlKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmFjLmVsICE9PSB0aGlzLmlucHV0KSB7XG4gICAgICAgIGlmICh0aGlzLmFjLmlkICYmIHRoaXMuaW5wdXQuaWQpIHtcbiAgICAgICAgICAvLyBSZWFzc29jaWF0ZSBhIGxhYmVsIGVsZW1lbnQgdG8gcG9pbnQgdG8gdGhlIG9yaWdpbmFsIGlucHV0LlxuICAgICAgICAgIGNvbnN0IGlucHV0TGFiZWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGBsYWJlbFtmb3I9JyR7dGhpcy5hYy5pZH0nXWApO1xuICAgICAgICAgIGlmIChpbnB1dExhYmVsKSB7XG4gICAgICAgICAgICBpbnB1dExhYmVsLmh0bWxGb3IgPSB0aGlzLmlucHV0LmlkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuYWMuZGVzdHJveSh0cnVlKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5saXN0LmRlc3Ryb3kodHJ1ZSk7XG4gICAgICB0aGlzLmVtcHR5TXNnLmRlc3Ryb3kodHJ1ZSk7XG4gICAgICB0aGlzLnN1Z2dlc3RXcmFwLmRlc3Ryb3kodHJ1ZSk7XG4gICAgICB0aGlzLmxpdmVSZWdpb24uZGVzdHJveSh0cnVlKTtcbiAgICAgIHRoaXMuaW5wdXQuc3R5bGUuZGlzcGxheSA9ICcnO1xuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogRmluZCBhdXRvY29tcGxldGUgaW5wdXRzIGFuZCBhdHRhY2ggdGhlIGF1dG9jb21wbGV0ZSBiZWhhdmlvcnMgdG8gaXQuXG4gICAqL1xuICBiZWhhdmlvcnMudG9vbHNoZWRBdXRvY29tcGxldGUgPSB7XG4gICAgLy8gVHJhY2sgaW5zdGFuY2VzIG9mIEF1dG9jb21wbGV0ZSBvYmplY3RzIHNvIHRoZXkgY2FuIGJlIGRldGFjaGVkLlxuICAgIGluc3RhbmNlczogbmV3IE1hcCgpLFxuXG4gICAgYXR0YWNoKGNvbnRleHQpIHtcbiAgICAgIHRzLndhbGtCeUNsYXNzKGNvbnRleHQsICd0b29sc2hlZC1hdXRvY29tcGxldGUnLCAoaXRlbSkgPT4ge1xuICAgICAgICBjb25zdCBzZXR0aW5ncyA9IGl0ZW0uZGF0YXNldC5hdXRvY29tcGxldGUgPyBKU09OLnBhcnNlKGl0ZW0uZGF0YXNldC5hdXRvY29tcGxldGUpIDoge307XG5cbiAgICAgICAgaWYgKGl0ZW0uZGF0YXNldC5wYXJhbXMpIHtcbiAgICAgICAgICBzZXR0aW5ncy5wYXJhbXMgPSBKU09OLnBhcnNlKGl0ZW0uZGF0YXNldC5wYXJhbXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNldHRpbmdzLnVyaSkge1xuICAgICAgICAgIGNvbnN0IGFjID0gbmV3IHRzLkF1dG9jb21wbGV0ZShpdGVtLCBzZXR0aW5ncyk7XG4gICAgICAgICAgdGhpcy5pbnN0YW5jZXMuc2V0KGl0ZW0uaWQgfHwgaXRlbSwgYWMpO1xuICAgICAgICB9XG4gICAgICB9LCAnYXV0b2NvbXBsZXRlLS1wcm9jZXNzZWQnKTtcbiAgICB9LFxuXG4gICAgZGV0YWNoKGNvbnRleHQsIHNldHRpbmdzLCB0cmlnZ2VyKSB7XG4gICAgICBpZiAodHJpZ2dlciA9PT0gJ3VubG9hZCcpIHtcbiAgICAgICAgdHMud2Fsa0J5U2VsZWN0b3IoY29udGV4dCwgJy50b29sc2hlZC1hdXRvY29tcGxldGUuYXV0b2NvbXBsZXRlLS1wcm9jZXNzZWQnLCAoaXRlbSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGFjID0gdGhpcy5pbnN0YW5jZXMuZ2V0KGl0ZW0uaWQgfHwgaXRlbSk7XG5cbiAgICAgICAgICBpZiAoYWMpIHtcbiAgICAgICAgICAgIGl0ZW0uY2xhc3NMaXN0LnJlbW92ZSgnYXV0b2NvbXBsZXRlLS1wcm9jZXNzZWQnKTtcbiAgICAgICAgICAgIHRoaXMuaW5zdGFuY2VzLmRlbGV0ZShpdGVtKTtcbiAgICAgICAgICAgIGFjLmRlc3Ryb3koKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0sXG4gIH07XG59KShEcnVwYWwpO1xuIl0sIm1hcHBpbmdzIjoiOztBQUFBLENBQUMsQ0FBQztFQUNBQSxDQUFDO0VBQ0RDLFNBQVM7RUFDVEMsUUFBUTtFQUNSQyxRQUFRLEVBQUVDO0FBQ1osQ0FBQyxLQUFLO0VBQ0o7QUFDRjtB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
