com.phloxui
Version:
PhloxUI Ng2+ Framework
604 lines (603 loc) • 56.4 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import * as tslib_1 from "tslib";
import { AbstractNavItem } from './AbstractNavItem';
import { AbstractI18NApplicable } from '../share/AbstractI18NApplicable';
var /** @type {?} */ TOPIC_NAME_PREFIX = 'nav-menu.';
var /** @type {?} */ NAVIGATE_SUFFIX = 'navigate';
var /** @type {?} */ NAVIGATE_CMD_SUFFIX = 'cmd.navigate';
var /** @type {?} */ NAVIGATE_TOPIC_NAME = TOPIC_NAME_PREFIX + NAVIGATE_SUFFIX;
var /** @type {?} */ NAVIGATE_CMD_TOPIC_NAME = TOPIC_NAME_PREFIX + NAVIGATE_CMD_SUFFIX;
// unsupported: template constraints.
/**
* <p style="text-indent: 2em;">
* An abstract base class for <code>nav menu</code>. A <code>nav menu</code> may consist of one or more <code>nav item</code>s
* ([[AbstractNavItem]]). The only difference between stadard <code>menu</code> ([[AbstractMenu]]) and <code>nav menu</code> is that
* the <code>nav menu</code> has a main purpose on <code>navigation</code>. It also automatically publishes an event to the
* [[ObservableManager]] on the topic "<code>nav-menu.[sub-topic-name].navigate</code>" when a navigation is performed. Furthermore,
* to remotely control the navigation on this <code>nav menu</code> instance at runtime without having direct object reference,
* you can use [[ObservableManager]]'s topic "<code>nav-menu.[sub-topic-name].cmd.navigate</code>" to publish a navigation
* <code>command</code> to this <code>nav menu</code>.
* </p>
*
* @author shiorin, tee4cute
* @see [[AbstractNavItem]]
* @see [[INavigator]]
* @see [[ObservableManager]]
* @abstract
* @template T
*/
var AbstractNavMenu = /** @class */ (function (_super) {
tslib_1.__extends(AbstractNavMenu, _super);
function AbstractNavMenu(subTopicName, obsvMgr) {
var _this = _super.call(this) || this;
_this.items = [];
_this.subTopicName = subTopicName;
_this.navigateSubjects = [];
_this.observableMgr = obsvMgr;
return _this;
}
/**
* <p style="text-indent: 1em;">
* Get the navigation event topic name with the given <code><b>subTopicName</b></code>. The returning topic name will be prefixed by
* [[NAVIGATE_TOPIC_NAME]].
* </p>
* @param {?} subTopicName
* @return {?}
*/
AbstractNavMenu.getNavigateTopicName = /**
* <p style="text-indent: 1em;">
* Get the navigation event topic name with the given <code><b>subTopicName</b></code>. The returning topic name will be prefixed by
* [[NAVIGATE_TOPIC_NAME]].
* </p>
* @param {?} subTopicName
* @return {?}
*/
function (subTopicName) {
if (subTopicName === null || typeof subTopicName === 'undefined' || subTopicName === '') {
return AbstractNavMenu.NAVIGATE_TOPIC_NAME;
}
if (subTopicName.charAt(0) === '.') {
subTopicName = subTopicName.substring(1);
}
if (subTopicName === '') {
return AbstractNavMenu.NAVIGATE_TOPIC_NAME;
}
if (subTopicName.charAt(subTopicName.length - 1) !== '.') {
subTopicName += '.';
}
return TOPIC_NAME_PREFIX + subTopicName + NAVIGATE_SUFFIX;
};
/**
* <p style="text-indent: 1em;">
* Get the navigation cmd topic name with the given <code><b>subTopicName</b></code>. The returning topic name will be prefixed by
* [[NAVIGATE_CMD_TOPIC_NAME]].
* </p>
* @param {?} subTopicName
* @return {?}
*/
AbstractNavMenu.getNavigateCmdTopicName = /**
* <p style="text-indent: 1em;">
* Get the navigation cmd topic name with the given <code><b>subTopicName</b></code>. The returning topic name will be prefixed by
* [[NAVIGATE_CMD_TOPIC_NAME]].
* </p>
* @param {?} subTopicName
* @return {?}
*/
function (subTopicName) {
if (subTopicName === null || typeof subTopicName === 'undefined' || subTopicName === '') {
return AbstractNavMenu.NAVIGATE_CMD_TOPIC_NAME;
}
if (subTopicName.charAt(0) === '.') {
subTopicName = subTopicName.substring(1);
}
if (subTopicName === '') {
return AbstractNavMenu.NAVIGATE_CMD_TOPIC_NAME;
}
if (subTopicName.charAt(subTopicName.length - 1) !== '.') {
subTopicName += '.';
}
return TOPIC_NAME_PREFIX + subTopicName + NAVIGATE_CMD_SUFFIX;
};
/**
* @param {?} navigate
* @param {?} navigateCmd
* @return {?}
*/
AbstractNavMenu.prototype.initNavMenuEventTopics = /**
* @param {?} navigate
* @param {?} navigateCmd
* @return {?}
*/
function (navigate, navigateCmd) {
var _this = this;
// Create change event observable topics
if (navigate !== null && typeof navigate === 'string') {
this.navigateSubjects.push(this.observableMgr.createSubject(navigate));
}
// Subscribe on CMD topics
if (navigateCmd !== null && typeof navigateCmd === 'string') {
this.observableMgr.subscribe(navigateCmd, function (item) {
if (item instanceof AbstractNavItem) {
_this.navigateTo(/** @type {?} */ (item)); // open here
}
});
}
};
/**
* @return {?}
*/
AbstractNavMenu.prototype.ngOnInit = /**
* @return {?}
*/
function () {
// Init super class event topics
this.initNavMenuEventTopics(AbstractNavMenu.NAVIGATE_TOPIC_NAME, AbstractNavMenu.NAVIGATE_CMD_TOPIC_NAME);
if (this.subTopicName !== null && this.subTopicName !== '' || typeof this.subTopicName !== 'undefined') {
// Init sub topic event topics
this.initNavMenuEventTopics(AbstractNavMenu.getNavigateTopicName(this.subTopicName), AbstractNavMenu.getNavigateCmdTopicName(this.subTopicName));
}
};
/**
* <p style="text-indent: 1em;">
* Get <code>nav item</code>s ([[AbstractNavItem]]) of this <code>nav menu</code>.
* </p>
* @return {?}
*/
AbstractNavMenu.prototype.getItems = /**
* <p style="text-indent: 1em;">
* Get <code>nav item</code>s ([[AbstractNavItem]]) of this <code>nav menu</code>.
* </p>
* @return {?}
*/
function () {
return this.items;
};
/**
* <p style="text-indent: 1em;">
* Get [[ObservableManager]]'s sub topic name associated with this <code>nav menu</code>.
* </p>
* @return {?}
*/
AbstractNavMenu.prototype.getSubTopicName = /**
* <p style="text-indent: 1em;">
* Get [[ObservableManager]]'s sub topic name associated with this <code>nav menu</code>.
* </p>
* @return {?}
*/
function () {
return this.subTopicName;
};
/**
* <p style="text-indent: 1em;">
* Get <code>nav item</code>s count in this <code>nav menu</code>.
* </p>
* @return {?}
*/
AbstractNavMenu.prototype.getItemCount = /**
* <p style="text-indent: 1em;">
* Get <code>nav item</code>s count in this <code>nav menu</code>.
* </p>
* @return {?}
*/
function () {
return this.items.length;
};
/**
* <p style="text-indent: 1em;">
* Get an active <code>nav item</code> index of this <code>nav menu</code>.
* </p>
*
* @return {?} Returns <code>-1</code> if there is no current active item. Otherwise, return the array index of current
* active item.
*/
AbstractNavMenu.prototype.getActiveIndex = /**
* <p style="text-indent: 1em;">
* Get an active <code>nav item</code> index of this <code>nav menu</code>.
* </p>
*
* @return {?} Returns <code>-1</code> if there is no current active item. Otherwise, return the array index of current
* active item.
*/
function () {
for (var /** @type {?} */ i = 0; i < this.items.length; i++) {
if (this.items[i].isActive()) {
return i;
}
}
return -1;
};
/**
* <p style="text-indent: 1em;">
* Get an active <code>nav item</code> of this <code>nav menu</code>.
* </p>
*
* @return {?} Returns <code>null</code> if there is no current active item.
*/
AbstractNavMenu.prototype.getActiveItem = /**
* <p style="text-indent: 1em;">
* Get an active <code>nav item</code> of this <code>nav menu</code>.
* </p>
*
* @return {?} Returns <code>null</code> if there is no current active item.
*/
function () {
var /** @type {?} */ idx = this.getActiveIndex();
if (idx < 0) {
return null;
}
return this.items[idx];
};
/**
* <p style="text-indent: 1em;">
* Set <code>nav item</code>s of this <code>nav menu</code>.
* </p>
* @param {?} items
* @return {?}
*/
AbstractNavMenu.prototype.setItems = /**
* <p style="text-indent: 1em;">
* Set <code>nav item</code>s of this <code>nav menu</code>.
* </p>
* @param {?} items
* @return {?}
*/
function (items) {
this.items = items;
};
/**
* <p style="text-indent: 1em;">
* Add a new <code>nav item</code> into this <code>nav menu</code>. If there already is the given <code><b>item</b></code> in this
* <code>nav menu</code>, this method will do nothing and return <code>false</code>.
* </p>
*
* @param {?} item A new <code>nav item</code> to be added into this <code>nav menu</code>.
*
* @return {?} Returns <code>true</code> if the given <code><b>item</b></code> is added into this <code>nav menu</code>. Otherwise, returns <code>false</code>.
*/
AbstractNavMenu.prototype.addItem = /**
* <p style="text-indent: 1em;">
* Add a new <code>nav item</code> into this <code>nav menu</code>. If there already is the given <code><b>item</b></code> in this
* <code>nav menu</code>, this method will do nothing and return <code>false</code>.
* </p>
*
* @param {?} item A new <code>nav item</code> to be added into this <code>nav menu</code>.
*
* @return {?} Returns <code>true</code> if the given <code><b>item</b></code> is added into this <code>nav menu</code>. Otherwise, returns <code>false</code>.
*/
function (item) {
if (this.containsItem(item)) {
return false;
}
this.items.push(item);
return true;
};
/**
* <p style="text-indent: 1em;">
* Remove the given <code><b>item</b></code> from this <code>nav menu</code>. If the given <code><b>item</b></code> is not in this <code>nav menu</code>, this method
* will do nothing and return <code>false</code>. If the <code><b>item</b></code> being removed is a current active item, this <code>nav menu</code> will be navigated
* to the first <code>nav item</code>.
* </p>
*
* @param {?} item A <code>nav item</code> to be removed from this <code>nav menu</code>.
*
* @return {?} Returns <code>true</code> if the given <code><b>item</b></code> is found and removed from this <code>nav menu</code>. Otherwise, returns <code>false</code>.
*/
AbstractNavMenu.prototype.removeItem = /**
* <p style="text-indent: 1em;">
* Remove the given <code><b>item</b></code> from this <code>nav menu</code>. If the given <code><b>item</b></code> is not in this <code>nav menu</code>, this method
* will do nothing and return <code>false</code>. If the <code><b>item</b></code> being removed is a current active item, this <code>nav menu</code> will be navigated
* to the first <code>nav item</code>.
* </p>
*
* @param {?} item A <code>nav item</code> to be removed from this <code>nav menu</code>.
*
* @return {?} Returns <code>true</code> if the given <code><b>item</b></code> is found and removed from this <code>nav menu</code>. Otherwise, returns <code>false</code>.
*/
function (item) {
var /** @type {?} */ idx = this.items.indexOf(item);
if (idx < 0) {
return false;
}
this.items.splice(idx, 1);
if (item.active) {
// Set page active to false.
item.active = false;
// If it is currently active page, we've to navigate to another one.
this.navigateToIndex(0);
}
return true;
};
/**
* <p style="text-indent: 1em;">
* To check that the given <code><b>item</b></code> is in this <code>nav menu</code> or not.
* </p>
*
* @param {?} item A <code>nav item</code> to check that it is in this <code>nav menu</code> or not.
*
* @return {?} Returns <code>true</code> if the given <code><b>item</b></code> is in this <code>nav menu</code>.
*/
AbstractNavMenu.prototype.containsItem = /**
* <p style="text-indent: 1em;">
* To check that the given <code><b>item</b></code> is in this <code>nav menu</code> or not.
* </p>
*
* @param {?} item A <code>nav item</code> to check that it is in this <code>nav menu</code> or not.
*
* @return {?} Returns <code>true</code> if the given <code><b>item</b></code> is in this <code>nav menu</code>.
*/
function (item) {
return this.items.indexOf(item) >= 0;
};
/**
* <p style="text-indent: 1em;">
* Get a <code>nav item</code> ([[AbstractNavItem]]) from the given index (<code><b>idx</b></code>).
* </p>
*
* @param {?} idx The index of <code>nav item</code> to get.
*
* @return {?} Returns an instance of <code>nav item</code> ([[AbstractNavItem]]) at the specified index (<code><b>idx</b></code>).
* Returns <code>null</code> if the given index is out of range.
*/
AbstractNavMenu.prototype.getItemByIndex = /**
* <p style="text-indent: 1em;">
* Get a <code>nav item</code> ([[AbstractNavItem]]) from the given index (<code><b>idx</b></code>).
* </p>
*
* @param {?} idx The index of <code>nav item</code> to get.
*
* @return {?} Returns an instance of <code>nav item</code> ([[AbstractNavItem]]) at the specified index (<code><b>idx</b></code>).
* Returns <code>null</code> if the given index is out of range.
*/
function (idx) {
if (idx === null || typeof idx === 'undefined' || idx < 0 || idx >= this.items.length) {
return null;
}
return this.items[idx];
};
/**
* <p style="text-indent: 1em;">
* Get a <code>nav item</code> ([[AbstractNavItem]]) by the given <code><b>name</b></code>.
* </p>
*
* @param {?} name The name of a <code>nav item</code> to get.
*
* @return {?} Returns an instance of <code>nav item</code> ([[AbstractNavItem]]) with the given <code><b>name</b></code>.
* Returns <code>null</code> if not found.
*/
AbstractNavMenu.prototype.getItemByName = /**
* <p style="text-indent: 1em;">
* Get a <code>nav item</code> ([[AbstractNavItem]]) by the given <code><b>name</b></code>.
* </p>
*
* @param {?} name The name of a <code>nav item</code> to get.
*
* @return {?} Returns an instance of <code>nav item</code> ([[AbstractNavItem]]) with the given <code><b>name</b></code>.
* Returns <code>null</code> if not found.
*/
function (name) {
var /** @type {?} */ idx = this.getItemIndexByName(name);
if (idx < 0) {
return null;
}
return this.items[idx];
};
/**
* <p style="text-indent: 1em;">
* Get the index of the given <code>nav item</code> (<code><b>item</b></code>).
* </p>
*
* @param {?} item The <code>nav item</code> to find index.
*
* @return {?} Returns an index of the specified <code><b>item</b></code>. Returns <code>-1</code> if not found.
*/
AbstractNavMenu.prototype.getItemIndex = /**
* <p style="text-indent: 1em;">
* Get the index of the given <code>nav item</code> (<code><b>item</b></code>).
* </p>
*
* @param {?} item The <code>nav item</code> to find index.
*
* @return {?} Returns an index of the specified <code><b>item</b></code>. Returns <code>-1</code> if not found.
*/
function (item) {
return this.items.indexOf(item);
};
/**
* <p style="text-indent: 1em;">
* Get the index of the given item <code><b>name</b></code>.
* </p>
*
* @param {?} name The item name to find index.
*
* @return {?} Returns an index of <code>nav item</code> having the specified <code><b>name</b></code>. Returns <code>-1</code> if not found.
*/
AbstractNavMenu.prototype.getItemIndexByName = /**
* <p style="text-indent: 1em;">
* Get the index of the given item <code><b>name</b></code>.
* </p>
*
* @param {?} name The item name to find index.
*
* @return {?} Returns an index of <code>nav item</code> having the specified <code><b>name</b></code>. Returns <code>-1</code> if not found.
*/
function (name) {
if (name === null || typeof name === 'undefined') {
return -1;
}
for (var /** @type {?} */ i = 0; i < this.items.length; i++) {
if (this.items[i].getName() === name) {
return i;
}
}
return -1;
};
/**
* <p style="text-indent: 1em;">
* Navigate this <code>nav menu</code> to the specified <code>nav <b>item</b></code>. This method returns <code>Promise</code> to support
* asynchronous execution. The <code>result</code> value of returned <code>Promise</code> is a boolean indicating the navigation result.
* The result value must be <code>true</code> if the navigation is successful. Otherwise, for example, if the given <code><b>item</b></code>
* does not exist, the result value will be <code>false</code>.
* </p>
*
* @param {?} item The <code>nav item</code> to navigate to.
*
* @return {?} Returns a <code>Promise</code> which will be resolved when the navigation is done. The <code>Promise</code>'s result will be a
* boolean value which its value will be <code>true</code> if the navigation is successful.
*/
AbstractNavMenu.prototype.navigateTo = /**
* <p style="text-indent: 1em;">
* Navigate this <code>nav menu</code> to the specified <code>nav <b>item</b></code>. This method returns <code>Promise</code> to support
* asynchronous execution. The <code>result</code> value of returned <code>Promise</code> is a boolean indicating the navigation result.
* The result value must be <code>true</code> if the navigation is successful. Otherwise, for example, if the given <code><b>item</b></code>
* does not exist, the result value will be <code>false</code>.
* </p>
*
* @param {?} item The <code>nav item</code> to navigate to.
*
* @return {?} Returns a <code>Promise</code> which will be resolved when the navigation is done. The <code>Promise</code>'s result will be a
* boolean value which its value will be <code>true</code> if the navigation is successful.
*/
function (item) {
var _this = this;
if (item === null || typeof item === 'undefined') {
return Promise.resolve(false);
}
if (item.isActive()) {
// The item is currently active. Do nothing ...
return Promise.resolve(false);
}
return this.doNavigate(item).then(function (success) {
if (success) {
var /** @type {?} */ curActive = _this.getActiveItem();
if (curActive !== null) {
// Set current page active to false
curActive.active = false;
}
item.active = true;
// Emit change event
if (Array.isArray(_this.navigateSubjects)) {
_this.navigateSubjects.forEach(function (obsv, idx) {
obsv.next(item);
});
}
}
else {
console.debug('Not navigate to "' + item.getName() + '".');
}
return Promise.resolve(success);
});
};
/**
* <p style="text-indent: 1em;">
* Navigate this <code>nav menu</code> to the specified index (<code><b>idx</b></code>). This method returns <code>Promise</code> to support
* asynchronous execution. The <code>result</code> value of returned <code>Promise</code> is a boolean indicating the navigation result.
* The result value must be <code>true</code> if the navigation is successful. Otherwise, the result value will be <code>false</code>.
* </p>
*
* @param {?} idx The item index to navigate to.
*
* @return {?} Returns a <code>Promise</code> which will be resolved when the navigation is done. The <code>Promise</code>'s result will be a
* boolean value which its value will be <code>true</code> if the navigation is successful.
*/
AbstractNavMenu.prototype.navigateToIndex = /**
* <p style="text-indent: 1em;">
* Navigate this <code>nav menu</code> to the specified index (<code><b>idx</b></code>). This method returns <code>Promise</code> to support
* asynchronous execution. The <code>result</code> value of returned <code>Promise</code> is a boolean indicating the navigation result.
* The result value must be <code>true</code> if the navigation is successful. Otherwise, the result value will be <code>false</code>.
* </p>
*
* @param {?} idx The item index to navigate to.
*
* @return {?} Returns a <code>Promise</code> which will be resolved when the navigation is done. The <code>Promise</code>'s result will be a
* boolean value which its value will be <code>true</code> if the navigation is successful.
*/
function (idx) {
var /** @type {?} */ page = this.getItemByIndex(idx);
if (page === null) {
return Promise.resolve(false);
}
return this.navigateTo(page);
};
/**
* <p style="text-indent: 1em;">
* Navigate this <code>nav menu</code> to a <code>nav item</code> having the specified <code><b>name</b></code>. This method returns
* <code>Promise</code> to support asynchronous execution. The <code>result</code> value of returned <code>Promise</code> is a boolean indicating
* the navigation result. The result value must be <code>true</code> if the navigation is successful. Otherwise, for example, if the given <code><b>item</b></code>
* does not exist, the result value will be <code>false</code>.
* </p>
*
* @param {?} name The name of a <code>nav item</code> to navigate to.
*
* @return {?} Returns a <code>Promise</code> which will be resolved when the navigation is done. The <code>Promise</code>'s result will be a
* boolean value which its value will be <code>true</code> if the navigation is successful.
*/
AbstractNavMenu.prototype.navigateToName = /**
* <p style="text-indent: 1em;">
* Navigate this <code>nav menu</code> to a <code>nav item</code> having the specified <code><b>name</b></code>. This method returns
* <code>Promise</code> to support asynchronous execution. The <code>result</code> value of returned <code>Promise</code> is a boolean indicating
* the navigation result. The result value must be <code>true</code> if the navigation is successful. Otherwise, for example, if the given <code><b>item</b></code>
* does not exist, the result value will be <code>false</code>.
* </p>
*
* @param {?} name The name of a <code>nav item</code> to navigate to.
*
* @return {?} Returns a <code>Promise</code> which will be resolved when the navigation is done. The <code>Promise</code>'s result will be a
* boolean value which its value will be <code>true</code> if the navigation is successful.
*/
function (name) {
var /** @type {?} */ page = this.getItemByName(name);
if (page === null) {
return Promise.resolve(false);
}
return this.navigateTo(page);
};
/**
* <p style="text-indent: 1em;">
* Reset this <code>nav menu</code>. This method simply navigates back to the item at index <code>0</code>.
* </p>
* @return {?}
*/
AbstractNavMenu.prototype.reset = /**
* <p style="text-indent: 1em;">
* Reset this <code>nav menu</code>. This method simply navigates back to the item at index <code>0</code>.
* </p>
* @return {?}
*/
function () {
this.navigateToIndex(0);
};
AbstractNavMenu.NAVIGATE_TOPIC_NAME = NAVIGATE_TOPIC_NAME;
AbstractNavMenu.NAVIGATE_CMD_TOPIC_NAME = NAVIGATE_CMD_TOPIC_NAME;
return AbstractNavMenu;
}(AbstractI18NApplicable));
export { AbstractNavMenu };
function AbstractNavMenu_tsickle_Closure_declarations() {
/** @type {?} */
AbstractNavMenu.NAVIGATE_TOPIC_NAME;
/** @type {?} */
AbstractNavMenu.NAVIGATE_CMD_TOPIC_NAME;
/** @type {?} */
AbstractNavMenu.prototype.items;
/** @type {?} */
AbstractNavMenu.prototype.subTopicName;
/** @type {?} */
AbstractNavMenu.prototype.navigateSubjects;
/** @type {?} */
AbstractNavMenu.prototype.observableMgr;
/**
* <p style="text-indent: 1em;">
* A method to perform the actual navigation, for example, changing a router's path, etc.
* </p>
*
* @abstract
* @param {?} item A <code>nav item</code> to navigate to.
*
* @return {?} Returns a <code>Promise</code> which will be resolved when the navigation is done. The <code>Promise</code>'s result will be a
* boolean value which its value will be <code>true</code> if the navigation is successful.
*/
AbstractNavMenu.prototype.doNavigate = function (item) { };
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3ROYXZNZW51LmpzIiwic291cmNlUm9vdCI6Im5nOi8vY29tLnBobG94dWkvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50L0Fic3RyYWN0TmF2TWVudS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUlBLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUlwRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUV6RSxxQkFBTSxpQkFBaUIsR0FBVyxXQUFXLENBQUM7QUFFOUMscUJBQU0sZUFBZSxHQUFXLFVBQVUsQ0FBQztBQUMzQyxxQkFBTSxtQkFBbUIsR0FBVyxjQUFjLENBQUM7QUFFbkQscUJBQU0sbUJBQW1CLEdBQVcsaUJBQWlCLEdBQUcsZUFBZSxDQUFDO0FBQ3hFLHFCQUFNLHVCQUF1QixHQUFXLGlCQUFpQixHQUFHLG1CQUFtQixDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7SUFrQlAsMkNBQXNCO0lBOEQ3Rix5QkFBWSxZQUFvQixFQUFFLE9BQTBCO1FBQTVELFlBQ0UsaUJBQU8sU0FNUjtRQUpDLEtBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLEtBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLEtBQUksQ0FBQyxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7UUFDM0IsS0FBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUM7O0tBQzlCOzs7Ozs7Ozs7SUExRGEsb0NBQW9COzs7Ozs7OztjQUFDLFlBQW9CO1FBQ3JELEVBQUUsQ0FBQyxDQUFDLFlBQVksS0FBSyxJQUFJLElBQUksT0FBTyxZQUFZLEtBQUssV0FBVyxJQUFJLFlBQVksS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ3hGLE1BQU0sQ0FBQyxlQUFlLENBQUMsbUJBQW1CLENBQUM7U0FDNUM7UUFFRCxFQUFFLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFL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QU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUMvQjtRQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7SUFnQnhCLHdDQUFjOzs7Ozs7Ozs7Ozs7O2NBQUMsSUFBWTtRQUNoQyxxQkFBSSxJQUFJLEdBQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUV2QyxFQUFFLENBQUMsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQztZQUNsQixNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUMvQjtRQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDOzs7Ozs7OztJQVF4QiwrQkFBSzs7Ozs7OztRQUNWLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7OzBDQXhaMkIsbUJBQW1COzhDQUNmLHVCQUF1QjswQkFyQ2xGO0VBa0N5RSxzQkFBc0I7U0FBekUsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMvU3ViamVjdCc7XG5cbmltcG9ydCB7IElOYXZpZ2F0b3IgfSBmcm9tICcuL0lOYXZpZ2F0b3InO1xuaW1wb3J0IHsgQWJzdHJhY3ROYXZJdGVtIH0gZnJvbSAnLi9BYnN0cmFjdE5hdkl0ZW0nO1xuXG5pbXBvcnQgeyBPYnNlcnZhYmxlTWFuYWdlciB9IGZyb20gJy4uL3NlcnZpY2Uvc2VydmljZXMnO1xuXG5pbXBvcnQgeyBBYnN0cmFjdEkxOE5BcHBsaWNhYmxlIH0gZnJvbSAnLi4vc2hhcmUvQWJzdHJhY3RJMThOQXBwbGljYWJsZSc7XG5cbmNvbnN0IFRPUElDX05BTUVfUFJFRklYOiBzdHJpbmcgPSAnbmF2LW1lbnUuJztcblxuY29uc3QgTkFWSUdBVEVfU1VGRklYOiBzdHJpbmcgPSAnbmF2aWdhdGUnO1xuY29uc3QgTkFWSUdBVEVfQ01EX1NVRkZJWDogc3RyaW5nID0gJ2NtZC5uYXZpZ2F0ZSc7XG5cbmNvbnN0IE5BVklHQVRFX1RPUElDX05BTUU6IHN0cmluZyA9IFRPUElDX05BTUVfUFJFRklYICsgTkFWSUdBVEVfU1VGRklYO1xuY29uc3QgTkFWSUdBVEVfQ01EX1RPUElDX05BTUU6IHN0cmluZyA9IFRPUElDX05BTUVfUFJFRklYICsgTkFWSUdBVEVfQ01EX1NVRkZJWDtcblxuLyoqXG4gKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAyZW07XCI+XG4gKiBBbiBhYnN0cmFjdCBiYXNlIGNsYXNzIGZvciA8Y29kZT5uYXYgbWVudTwvY29kZT4uIEEgPGNvZGU+bmF2IG1lbnU8L2NvZGU+IG1heSBjb25zaXN0IG9mIG9uZSBvciBtb3JlIDxjb2RlPm5hdiBpdGVtPC9jb2RlPnNcbiAqIChbW0Fic3RyYWN0TmF2SXRlbV1dKS4gVGhlIG9ubHkgZGlmZmVyZW5jZSBiZXR3ZWVuIHN0YWRhcmQgPGNvZGU+bWVudTwvY29kZT4gKFtbQWJzdHJhY3RNZW51XV0pIGFuZCA8Y29kZT5uYXYgbWVudTwvY29kZT4gaXMgdGhhdFxuICogdGhlIDxjb2RlPm5hdiBtZW51PC9jb2RlPiBoYXMgYSBtYWluIHB1cnBvc2Ugb24gPGNvZGU+bmF2aWdhdGlvbjwvY29kZT4uIEl0IGFsc28gYXV0b21hdGljYWxseSBwdWJsaXNoZXMgYW4gZXZlbnQgdG8gdGhlXG4gKiBbW09ic2VydmFibGVNYW5hZ2VyXV0gb24gdGhlIHRvcGljIFwiPGNvZGU+bmF2LW1lbnUuW3N1Yi10b3BpYy1uYW1lXS5uYXZpZ2F0ZTwvY29kZT5cIiB3aGVuIGEgbmF2aWdhdGlvbiBpcyBwZXJmb3JtZWQuIEZ1cnRoZXJtb3JlLFxuICogdG8gcmVtb3RlbHkgY29udHJvbCB0aGUgbmF2aWdhdGlvbiBvbiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPiBpbnN0YW5jZSBhdCBydW50aW1lIHdpdGhvdXQgaGF2aW5nIGRpcmVjdCBvYmplY3QgcmVmZXJlbmNlLFxuICogeW91IGNhbiB1c2UgW1tPYnNlcnZhYmxlTWFuYWdlcl1dJ3MgdG9waWMgXCI8Y29kZT5uYXYtbWVudS5bc3ViLXRvcGljLW5hbWVdLmNtZC5uYXZpZ2F0ZTwvY29kZT5cIiB0byBwdWJsaXNoIGEgbmF2aWdhdGlvblxuICogPGNvZGU+Y29tbWFuZDwvY29kZT4gdG8gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uXG4gKiA8L3A+XG4gKlxuICogQGF1dGhvciBzaGlvcmluLCB0ZWU0Y3V0ZVxuICogQHNlZSBbW0Fic3RyYWN0TmF2SXRlbV1dXG4gKiBAc2VlIFtbSU5hdmlnYXRvcl1dXG4gKiBAc2VlIFtbT2JzZXJ2YWJsZU1hbmFnZXJdXVxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQWJzdHJhY3ROYXZNZW51PFQgZXh0ZW5kcyBBYnN0cmFjdE5hdkl0ZW0+IGV4dGVuZHMgQWJzdHJhY3RJMThOQXBwbGljYWJsZSBpbXBsZW1lbnRzIElOYXZpZ2F0b3I8VD4sIE9uSW5pdCB7XG5cbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBOQVZJR0FURV9UT1BJQ19OQU1FOiBzdHJpbmcgPSBOQVZJR0FURV9UT1BJQ19OQU1FO1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IE5BVklHQVRFX0NNRF9UT1BJQ19OQU1FOiBzdHJpbmcgPSBOQVZJR0FURV9DTURfVE9QSUNfTkFNRTtcblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgdGhlIG5hdmlnYXRpb24gZXZlbnQgdG9waWMgbmFtZSB3aXRoIHRoZSBnaXZlbiA8Y29kZT48Yj5zdWJUb3BpY05hbWU8L2I+PC9jb2RlPi4gVGhlIHJldHVybmluZyB0b3BpYyBuYW1lIHdpbGwgYmUgcHJlZml4ZWQgYnlcbiAgICogW1tOQVZJR0FURV9UT1BJQ19OQU1FXV0uXG4gICAqIDwvcD5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ2V0TmF2aWdhdGVUb3BpY05hbWUoc3ViVG9waWNOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmIChzdWJUb3BpY05hbWUgPT09IG51bGwgfHwgdHlwZW9mIHN1YlRvcGljTmFtZSA9PT0gJ3VuZGVmaW5lZCcgfHwgc3ViVG9waWNOYW1lID09PSAnJykge1xuICAgICAgcmV0dXJuIEFic3RyYWN0TmF2TWVudS5OQVZJR0FURV9UT1BJQ19OQU1FO1xuICAgIH1cblxuICAgIGlmIChzdWJUb3BpY05hbWUuY2hhckF0KDApID09PSAnLicpIHtcbiAgICAgIHN1YlRvcGljTmFtZSA9IHN1YlRvcGljTmFtZS5zdWJzdHJpbmcoMSk7XG4gICAgfVxuXG4gICAgaWYgKHN1YlRvcGljTmFtZSA9PT0gJycpIHtcbiAgICAgIHJldHVybiBBYnN0cmFjdE5hdk1lbnUuTkFWSUdBVEVfVE9QSUNfTkFNRTtcbiAgICB9XG5cbiAgICBpZiAoc3ViVG9waWNOYW1lLmNoYXJBdChzdWJUb3BpY05hbWUubGVuZ3RoIC0gMSkgIT09ICcuJykge1xuICAgICAgc3ViVG9waWNOYW1lICs9ICcuJztcbiAgICB9XG5cbiAgICByZXR1cm4gVE9QSUNfTkFNRV9QUkVGSVggKyBzdWJUb3BpY05hbWUgKyBOQVZJR0FURV9TVUZGSVg7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgdGhlIG5hdmlnYXRpb24gY21kIHRvcGljIG5hbWUgd2l0aCB0aGUgZ2l2ZW4gPGNvZGU+PGI+c3ViVG9waWNOYW1lPC9iPjwvY29kZT4uIFRoZSByZXR1cm5pbmcgdG9waWMgbmFtZSB3aWxsIGJlIHByZWZpeGVkIGJ5XG4gICAqIFtbTkFWSUdBVEVfQ01EX1RPUElDX05BTUVdXS5cbiAgICogPC9wPlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBnZXROYXZpZ2F0ZUNtZFRvcGljTmFtZShzdWJUb3BpY05hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKHN1YlRvcGljTmFtZSA9PT0gbnVsbCB8fCB0eXBlb2Ygc3ViVG9waWNOYW1lID09PSAndW5kZWZpbmVkJyB8fCBzdWJUb3BpY05hbWUgPT09ICcnKSB7XG4gICAgICByZXR1cm4gQWJzdHJhY3ROYXZNZW51Lk5BVklHQVRFX0NNRF9UT1BJQ19OQU1FO1xuICAgIH1cblxuICAgIGlmIChzdWJUb3BpY05hbWUuY2hhckF0KDApID09PSAnLicpIHtcbiAgICAgIHN1YlRvcGljTmFtZSA9IHN1YlRvcGljTmFtZS5zdWJzdHJpbmcoMSk7XG4gICAgfVxuXG4gICAgaWYgKHN1YlRvcGljTmFtZSA9PT0gJycpIHtcbiAgICAgIHJldHVybiBBYnN0cmFjdE5hdk1lbnUuTkFWSUdBVEVfQ01EX1RPUElDX05BTUU7XG4gICAgfVxuXG4gICAgaWYgKHN1YlRvcGljTmFtZS5jaGFyQXQoc3ViVG9waWNOYW1lLmxlbmd0aCAtIDEpICE9PSAnLicpIHtcbiAgICAgIHN1YlRvcGljTmFtZSArPSAnLic7XG4gICAgfVxuXG4gICAgcmV0dXJuIFRPUElDX05BTUVfUFJFRklYICsgc3ViVG9waWNOYW1lICsgTkFWSUdBVEVfQ01EX1NVRkZJWDtcbiAgfVxuXG4gIHByb3RlY3RlZCBpdGVtczogVFtdO1xuICBwcm90ZWN0ZWQgc3ViVG9waWNOYW1lOiBzdHJpbmc7XG4gIHByb3RlY3RlZCBuYXZpZ2F0ZVN1YmplY3RzOiBTdWJqZWN0PGFueT5bXTtcbiAgcHJvdGVjdGVkIG9ic2VydmFibGVNZ3I6IE9ic2VydmFibGVNYW5hZ2VyO1xuXG4gIGNvbnN0cnVjdG9yKHN1YlRvcGljTmFtZTogc3RyaW5nLCBvYnN2TWdyOiBPYnNlcnZhYmxlTWFuYWdlcikge1xuICAgIHN1cGVyKCk7XG5cbiAgICB0aGlzLml0ZW1zID0gW107XG4gICAgdGhpcy5zdWJUb3BpY05hbWUgPSBzdWJUb3BpY05hbWU7XG4gICAgdGhpcy5uYXZpZ2F0ZVN1YmplY3RzID0gW107XG4gICAgdGhpcy5vYnNlcnZhYmxlTWdyID0gb2Jzdk1ncjtcbiAgfVxuXG4gIHByaXZhdGUgaW5pdE5hdk1lbnVFdmVudFRvcGljcyhuYXZpZ2F0ZTogc3RyaW5nLCBuYXZpZ2F0ZUNtZDogc3RyaW5nKTogdm9pZCB7XG4gICAgLy8gQ3JlYXRlIGNoYW5nZSBldmVudCBvYnNlcnZhYmxlIHRvcGljc1xuICAgIGlmIChuYXZpZ2F0ZSAhPT0gbnVsbCAmJiB0eXBlb2YgbmF2aWdhdGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICB0aGlzLm5hdmlnYXRlU3ViamVjdHMucHVzaCh0aGlzLm9ic2VydmFibGVNZ3IuY3JlYXRlU3ViamVjdChuYXZpZ2F0ZSkpO1xuICAgIH1cblxuICAgIC8vIFN1YnNjcmliZSBvbiBDTUQgdG9waWNzXG4gICAgaWYgKG5hdmlnYXRlQ21kICE9PSBudWxsICYmIHR5cGVvZiBuYXZpZ2F0ZUNtZCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHRoaXMub2JzZXJ2YWJsZU1nci5zdWJzY3JpYmUobmF2aWdhdGVDbWQsIChpdGVtOiBhbnkpID0+IHtcbiAgICAgICAgaWYgKGl0ZW0gaW5zdGFuY2VvZiBBYnN0cmFjdE5hdkl0ZW0pIHtcbiAgICAgICAgICB0aGlzLm5hdmlnYXRlVG8oPFQ+aXRlbSk7IC8vIG9wZW4gaGVyZVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgLy8gSW5pdCBzdXBlciBjbGFzcyBldmVudCB0b3BpY3NcbiAgICB0aGlzLmluaXROYXZNZW51RXZlbnRUb3BpY3MoXG4gICAgICBBYnN0cmFjdE5hdk1lbnUuTkFWSUdBVEVfVE9QSUNfTkFNRSxcbiAgICAgIEFic3RyYWN0TmF2TWVudS5OQVZJR0FURV9DTURfVE9QSUNfTkFNRVxuICAgICk7XG5cbiAgICBpZiAodGhpcy5zdWJUb3BpY05hbWUgIT09IG51bGwgJiYgdGhpcy5zdWJUb3BpY05hbWUgIT09ICcnIHx8IHR5cGVvZiB0aGlzLnN1YlRvcGljTmFtZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIC8vIEluaXQgc3ViIHRvcGljIGV2ZW50IHRvcGljc1xuICAgICAgdGhpcy5pbml0TmF2TWVudUV2ZW50VG9waWNzKFxuICAgICAgICBBYnN0cmFjdE5hdk1lbnUuZ2V0TmF2aWdhdGVUb3BpY05hbWUodGhpcy5zdWJUb3BpY05hbWUpLFxuICAgICAgICBBYnN0cmFjdE5hdk1lbnUuZ2V0TmF2aWdhdGVDbWRUb3BpY05hbWUodGhpcy5zdWJUb3BpY05hbWUpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCA8Y29kZT5uYXYgaXRlbTwvY29kZT5zIChbW0Fic3RyYWN0TmF2SXRlbV1dKSBvZiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi5cbiAgICogPC9wPlxuICAgKi9cbiAgcHVibGljIGdldEl0ZW1zKCk6IFRbXSB7XG4gICAgcmV0dXJuIHRoaXMuaXRlbXM7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgW1tPYnNlcnZhYmxlTWFuYWdlcl1dJ3Mgc3ViIHRvcGljIG5hbWUgYXNzb2NpYXRlZCB3aXRoIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqL1xuICBwdWJsaWMgZ2V0U3ViVG9waWNOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc3ViVG9waWNOYW1lO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IDxjb2RlPm5hdiBpdGVtPC9jb2RlPnMgY291bnQgaW4gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uXG4gICAqIDwvcD5cbiAgICovXG4gIHB1YmxpYyBnZXRJdGVtQ291bnQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5pdGVtcy5sZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgYW4gYWN0aXZlIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiBpbmRleCBvZiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgPGNvZGU+LTE8L2NvZGU+IGlmIHRoZXJlIGlzIG5vIGN1cnJlbnQgYWN0aXZlIGl0ZW0uIE90aGVyd2lzZSwgcmV0dXJuIHRoZSBhcnJheSBpbmRleCBvZiBjdXJyZW50XG4gICAqIGFjdGl2ZSBpdGVtLlxuICAgKi9cbiAgcHVibGljIGdldEFjdGl2ZUluZGV4KCk6IG51bWJlciB7XG4gICAgZm9yIChsZXQgaTogbnVtYmVyID0gMDsgaSA8IHRoaXMuaXRlbXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh0aGlzLml0ZW1zW2ldLmlzQWN0aXZlKCkpIHtcbiAgICAgICAgcmV0dXJuIGk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIC0xO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IGFuIGFjdGl2ZSA8Y29kZT5uYXYgaXRlbTwvY29kZT4gb2YgdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHJldHVybiBSZXR1cm5zIDxjb2RlPm51bGw8L2NvZGU+IGlmIHRoZXJlIGlzIG5vIGN1cnJlbnQgYWN0aXZlIGl0ZW0uXG4gICAqL1xuICBwdWJsaWMgZ2V0QWN0aXZlSXRlbSgpOiBUIHtcbiAgICBsZXQgaWR4OiBudW1iZXIgPSB0aGlzLmdldEFjdGl2ZUluZGV4KCk7XG5cbiAgICBpZiAoaWR4IDwgMCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuaXRlbXNbaWR4XTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFNldCA8Y29kZT5uYXYgaXRlbTwvY29kZT5zIG9mIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqL1xuICBwdWJsaWMgc2V0SXRlbXMoaXRlbXM6IFRbXSk6IHZvaWQge1xuICAgIHRoaXMuaXRlbXMgPSBpdGVtcztcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEFkZCBhIG5ldyA8Y29kZT5uYXYgaXRlbTwvY29kZT4gaW50byB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi4gSWYgdGhlcmUgYWxyZWFkeSBpcyB0aGUgZ2l2ZW4gPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+IGluIHRoaXNcbiAgICogPGNvZGU+bmF2IG1lbnU8L2NvZGU+LCB0aGlzIG1ldGhvZCB3aWxsIGRvIG5vdGhpbmcgYW5kIHJldHVybiA8Y29kZT5mYWxzZTwvY29kZT4uXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIGl0ZW0gQSBuZXcgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IHRvIGJlIGFkZGVkIGludG8gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgZ2l2ZW4gPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+IGlzIGFkZGVkIGludG8gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uIE90aGVyd2lzZSwgcmV0dXJucyA8Y29kZT5mYWxzZTwvY29kZT4uXG4gICAqL1xuICBwdWJsaWMgYWRkSXRlbShpdGVtOiBUKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuY29udGFpbnNJdGVtKGl0ZW0pKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdGhpcy5pdGVtcy5wdXNoKGl0ZW0pO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBSZW1vdmUgdGhlIGdpdmVuIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPiBmcm9tIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LiBJZiB0aGUgZ2l2ZW4gPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+IGlzIG5vdCBpbiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPiwgdGhpcyBtZXRob2RcbiAgICogd2lsbCBkbyBub3RoaW5nIGFuZCByZXR1cm4gPGNvZGU+ZmFsc2U8L2NvZGU+LiBJZiB0aGUgPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+IGJlaW5nIHJlbW92ZWQgaXMgYSBjdXJyZW50IGFjdGl2ZSBpdGVtLCB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPiB3aWxsIGJlIG5hdmlnYXRlZFxuICAgKiB0byB0aGUgZmlyc3QgPGNvZGU+bmF2IGl0ZW08L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBwYXJhbSBpdGVtIEEgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IHRvIGJlIHJlbW92ZWQgZnJvbSB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi5cbiAgICpcbiAgICogQHJldHVybiBSZXR1cm5zIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSBnaXZlbiA8Y29kZT48Yj5pdGVtPC9iPjwvY29kZT4gaXMgZm91bmQgYW5kIHJlbW92ZWQgZnJvbSB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi4gT3RoZXJ3aXNlLCByZXR1cm5zIDxjb2RlPmZhbHNlPC9jb2RlPi5cbiAgICovXG4gIHB1YmxpYyByZW1vdmVJdGVtKGl0ZW06IFQpOiBib29sZWFuIHtcbiAgICBsZXQgaWR4OiBudW1iZXIgPSB0aGlzLml0ZW1zLmluZGV4T2YoaXRlbSk7XG5cbiAgICBpZiAoaWR4IDwgMCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMuaXRlbXMuc3BsaWNlKGlkeCwgMSk7XG5cbiAgICBpZiAoaXRlbS5hY3RpdmUpIHtcbiAgICAgIC8vIFNldCBwYWdlIGFjdGl2ZSB0byBmYWxzZS5cbiAgICAgIGl0ZW0uYWN0aXZlID0gZmFsc2U7XG5cbiAgICAgIC8vIElmIGl0IGlzIGN1cnJlbnRseSBhY3RpdmUgcGFnZSwgd2UndmUgdG8gbmF2aWdhdGUgdG8gYW5vdGhlciBvbmUuXG4gICAgICB0aGlzLm5hdmlnYXRlVG9JbmRleCgwKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFRvIGNoZWNrIHRoYXQgdGhlIGdpdmVuIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPiBpcyBpbiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPiBvciBub3QuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIGl0ZW0gQSA8Y29kZT5uYXYgaXRlbTwvY29kZT4gdG8gY2hlY2sgdGhhdCBpdCBpcyBpbiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPiBvciBub3QuXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgZ2l2ZW4gPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+IGlzIGluIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LlxuICAgKi9cbiAgcHVibGljIGNvbnRhaW5zSXRlbShpdGVtOiBUKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXRlbXMuaW5kZXhPZihpdGVtKSA+PSAwO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IGEgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IChbW0Fic3RyYWN0TmF2SXRlbV1dKSBmcm9tIHRoZSBnaXZlbiBpbmRleCAoPGNvZGU+PGI+aWR4PC9iPjwvY29kZT4pLlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBwYXJhbSBpZHggVGhlIGluZGV4IG9mIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiB0byBnZXQuXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyBhbiBpbnN0YW5jZSBvZiA8Y29kZT5uYXYgaXRlbTwvY29kZT4gKFtbQWJzdHJhY3ROYXZJdGVtXV0pIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXggKDxjb2RlPjxiPmlkeDwvYj48L2NvZGU+KS5cbiAgICogUmV0dXJucyA8Y29kZT5udWxsPC9jb2RlPiBpZiB0aGUgZ2l2ZW4gaW5kZXggaXMgb3V0IG9mIHJhbmdlLlxuICAgKi9cbiAgcHVibGljIGdldEl0ZW1CeUluZGV4KGlkeDogbnVtYmVyKTogVCB7XG4gICAgaWYgKGlkeCA9PT0gbnVsbCB8fCB0eXBlb2YgaWR4ID09PSAndW5kZWZpbmVkJyB8fCBpZHggPCAwIHx8IGlkeCA+PSB0aGlzLml0ZW1zLmxlbmd0aCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuaXRlbXNbaWR4XTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCBhIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiAoW1tBYnN0cmFjdE5hdkl0ZW1dXSkgYnkgdGhlIGdpdmVuIDxjb2RlPjxiPm5hbWU8L2I+PC9jb2RlPi5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgbmFtZSBvZiBhIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiB0byBnZXQuXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyBhbiBpbnN0YW5jZSBvZiA8Y29kZT5uYXYgaXRlbTwvY29kZT4gKFtbQWJzdHJhY3ROYXZJdGVtXV0pIHdpdGggdGhlIGdpdmVuIDxjb2RlPjxiPm5hbWU8L2I+PC9jb2RlPi5cbiAgICogUmV0dXJucyA8Y29kZT5udWxsPC9jb2RlPiBpZiBub3QgZm91bmQuXG4gICAqL1xuICBwdWJsaWMgZ2V0SXRlbUJ5TmFtZShuYW1lOiBzdHJpbmcpOiBUIHtcbiAgICBsZXQgaWR4OiBudW1iZXIgPSB0aGlzLmdldEl0ZW1JbmRleEJ5TmFtZShuYW1lKTtcblxuICAgIGlmIChpZHggPCAwKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5pdGVtc1tpZHhdO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IHRoZSBpbmRleCBvZiB0aGUgZ2l2ZW4gPGNvZGU+bmF2IGl0ZW08L2NvZGU+ICg8Y29kZT48Yj5pdGVtPC9iPjwvY29kZT4pLlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBwYXJhbSBpdGVtIFRoZSA8Y29kZT5uYXYgaXRlbTwvY29kZT4gdG8gZmluZCBpbmRleC5cbiAgICpcbiAgICogQHJldHVybiBSZXR1cm5zIGFuIGluZGV4IG9mIHRoZSBzcGVjaWZpZWQgPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+LiBSZXR1cm5zIDxjb2RlPi0xPC9jb2RlPiBpZiBub3QgZm91bmQuXG4gICAqL1xuICBwdWJsaWMgZ2V0SXRlbUluZGV4KGl0ZW06IFQpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLml0ZW1zLmluZGV4T2YoaXRlbSk7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgdGhlIGluZGV4IG9mIHRoZSBnaXZlbiBpdGVtIDxjb2RlPjxiPm5hbWU8L2I+PC9jb2RlPi5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgaXRlbSBuYW1lIHRvIGZpbmQgaW5kZXguXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyBhbiBpbmRleCBvZiA8Y29kZT5uYXYgaXRlbTwvY29kZT4gaGF2aW5nIHRoZSBzcGVjaWZpZWQgPGNvZGU+PGI+bmFtZTwvYj48L2NvZGU+LiBSZXR1cm5zIDxjb2RlPi0xPC9jb2RlPiBpZiBub3QgZm91bmQuXG4gICAqL1xuICBwdWJsaWMgZ2V0SXRlbUluZGV4QnlOYW1lKG5hbWU6IHN0cmluZyk6IG51bWJlciB7XG4gICAgaWYgKG5hbWUgPT09IG51bGwgfHwgdHlwZW9mIG5hbWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gLTE7XG4gICAgfVxuXG4gICAgZm9yIChsZXQga