UNPKG

com.phloxui

Version:

PhloxUI Ng2+ Framework

425 lines (424 loc) 47.3 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ import { AbstractNavItem } from './AbstractNavItem'; import { AbstractI18NApplicable } from '../share/AbstractI18NApplicable'; const /** @type {?} */ TOPIC_NAME_PREFIX = 'nav-menu.'; const /** @type {?} */ NAVIGATE_SUFFIX = 'navigate'; const /** @type {?} */ NAVIGATE_CMD_SUFFIX = 'cmd.navigate'; const /** @type {?} */ NAVIGATE_TOPIC_NAME = TOPIC_NAME_PREFIX + NAVIGATE_SUFFIX; const /** @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 */ export class AbstractNavMenu extends AbstractI18NApplicable { /** * @param {?} subTopicName * @param {?} obsvMgr */ constructor(subTopicName, obsvMgr) { super(); this.items = []; this.subTopicName = subTopicName; this.navigateSubjects = []; this.observableMgr = obsvMgr; } /** * <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 {?} */ static getNavigateTopicName(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 {?} */ static getNavigateCmdTopicName(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 {?} */ initNavMenuEventTopics(navigate, navigateCmd) { // 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, (item) => { if (item instanceof AbstractNavItem) { this.navigateTo(/** @type {?} */ (item)); // open here } }); } } /** * @return {?} */ ngOnInit() { // 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 {?} */ getItems() { return this.items; } /** * <p style="text-indent: 1em;"> * Get [[ObservableManager]]'s sub topic name associated with this <code>nav menu</code>. * </p> * @return {?} */ getSubTopicName() { return this.subTopicName; } /** * <p style="text-indent: 1em;"> * Get <code>nav item</code>s count in this <code>nav menu</code>. * </p> * @return {?} */ getItemCount() { 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. */ getActiveIndex() { for (let /** @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. */ getActiveItem() { let /** @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 {?} */ setItems(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>. */ addItem(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>. */ removeItem(item) { let /** @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>. */ containsItem(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. */ getItemByIndex(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. */ getItemByName(name) { let /** @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. */ getItemIndex(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. */ getItemIndexByName(name) { if (name === null || typeof name === 'undefined') { return -1; } for (let /** @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. */ navigateTo(item) { 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((success) => { if (success) { let /** @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((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. */ navigateToIndex(idx) { let /** @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. */ navigateToName(name) { let /** @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 {?} */ reset() { this.navigateToIndex(0); } } AbstractNavMenu.NAVIGATE_TOPIC_NAME = NAVIGATE_TOPIC_NAME; AbstractNavMenu.NAVIGATE_CMD_TOPIC_NAME = NAVIGATE_CMD_TOPIC_NAME; 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3ROYXZNZW51LmpzIiwic291cmNlUm9vdCI6Im5nOi8vY29tLnBobG94dWkvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50L0Fic3RyYWN0TmF2TWVudS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBSUEsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBSXBELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRXpFLHVCQUFNLGlCQUFpQixHQUFXLFdBQVcsQ0FBQztBQUU5Qyx1QkFBTSxlQUFlLEdBQVcsVUFBVSxDQUFDO0FBQzNDLHVCQUFNLG1CQUFtQixHQUFXLGNBQWMsQ0FBQztBQUVuRCx1QkFBTSxtQkFBbUIsR0FBVyxpQkFBaUIsR0FBRyxlQUFlLENBQUM7QUFDeEUsdUJBQU0sdUJBQXVCLEdBQVcsaUJBQWlCLEdBQUcsbUJBQW1CLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBa0JoRixNQUFNLHNCQUEyRCxTQUFRLHNCQUFzQjs7Ozs7SUE4RDdGLFlBQVksWUFBb0IsRUFBRSxPQUEwQjtRQUMxRCxLQUFLLEVBQUUsQ0FBQztRQUVSLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7UUFDM0IsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUM7S0FDOUI7Ozs7Ozs7OztJQTFETSxNQUFNLENBQUMsb0JBQW9CLENBQUMsWUFBb0I7UUFDckQsRUFBRSxDQUFDLENBQUMsWUFBWSxLQUFLLElBQUksSUFBSSxPQUFPLFlBQVksS0FBSyxXQUFXLElBQUksWUFBWSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDeEYsTUFBTSxDQUFDLGVBQWUsQ0FBQyxtQkFBbUIsQ0FBQztTQUM1QztRQUVELEVBQUUsQ0FBQyxDQUFDLFlBQVksQ0FBQyxNQUFN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QWdCeEIsY0FBYyxDQUFDLElBQVk7UUFDaEMscUJBQUksSUFBSSxHQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFdkMsRUFBRSxDQUFDLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDbEIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDL0I7UUFFRCxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQzs7Ozs7Ozs7SUFReEIsS0FBSztRQUNWLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7OztzQ0F4WjJCLG1CQUFtQjswQ0FDZix1QkFBdUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBPbkluaXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzL1N1YmplY3QnO1xuXG5pbXBvcnQgeyBJTmF2aWdhdG9yIH0gZnJvbSAnLi9JTmF2aWdhdG9yJztcbmltcG9ydCB7IEFic3RyYWN0TmF2SXRlbSB9IGZyb20gJy4vQWJzdHJhY3ROYXZJdGVtJztcblxuaW1wb3J0IHsgT2JzZXJ2YWJsZU1hbmFnZXIgfSBmcm9tICcuLi9zZXJ2aWNlL3NlcnZpY2VzJztcblxuaW1wb3J0IHsgQWJzdHJhY3RJMThOQXBwbGljYWJsZSB9IGZyb20gJy4uL3NoYXJlL0Fic3RyYWN0STE4TkFwcGxpY2FibGUnO1xuXG5jb25zdCBUT1BJQ19OQU1FX1BSRUZJWDogc3RyaW5nID0gJ25hdi1tZW51Lic7XG5cbmNvbnN0IE5BVklHQVRFX1NVRkZJWDogc3RyaW5nID0gJ25hdmlnYXRlJztcbmNvbnN0IE5BVklHQVRFX0NNRF9TVUZGSVg6IHN0cmluZyA9ICdjbWQubmF2aWdhdGUnO1xuXG5jb25zdCBOQVZJR0FURV9UT1BJQ19OQU1FOiBzdHJpbmcgPSBUT1BJQ19OQU1FX1BSRUZJWCArIE5BVklHQVRFX1NVRkZJWDtcbmNvbnN0IE5BVklHQVRFX0NNRF9UT1BJQ19OQU1FOiBzdHJpbmcgPSBUT1BJQ19OQU1FX1BSRUZJWCArIE5BVklHQVRFX0NNRF9TVUZGSVg7XG5cbi8qKlxuICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMmVtO1wiPlxuICogQW4gYWJzdHJhY3QgYmFzZSBjbGFzcyBmb3IgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LiBBIDxjb2RlPm5hdiBtZW51PC9jb2RlPiBtYXkgY29uc2lzdCBvZiBvbmUgb3IgbW9yZSA8Y29kZT5uYXYgaXRlbTwvY29kZT5zXG4gKiAoW1tBYnN0cmFjdE5hdkl0ZW1dXSkuIFRoZSBvbmx5IGRpZmZlcmVuY2UgYmV0d2VlbiBzdGFkYXJkIDxjb2RlPm1lbnU8L2NvZGU+IChbW0Fic3RyYWN0TWVudV1dKSBhbmQgPGNvZGU+bmF2IG1lbnU8L2NvZGU+IGlzIHRoYXRcbiAqIHRoZSA8Y29kZT5uYXYgbWVudTwvY29kZT4gaGFzIGEgbWFpbiBwdXJwb3NlIG9uIDxjb2RlPm5hdmlnYXRpb248L2NvZGU+LiBJdCBhbHNvIGF1dG9tYXRpY2FsbHkgcHVibGlzaGVzIGFuIGV2ZW50IHRvIHRoZVxuICogW1tPYnNlcnZhYmxlTWFuYWdlcl1dIG9uIHRoZSB0b3BpYyBcIjxjb2RlPm5hdi1tZW51LltzdWItdG9waWMtbmFtZV0ubmF2aWdhdGU8L2NvZGU+XCIgd2hlbiBhIG5hdmlnYXRpb24gaXMgcGVyZm9ybWVkLiBGdXJ0aGVybW9yZSxcbiAqIHRvIHJlbW90ZWx5IGNvbnRyb2wgdGhlIG5hdmlnYXRpb24gb24gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4gaW5zdGFuY2UgYXQgcnVudGltZSB3aXRob3V0IGhhdmluZyBkaXJlY3Qgb2JqZWN0IHJlZmVyZW5jZSxcbiAqIHlvdSBjYW4gdXNlIFtbT2JzZXJ2YWJsZU1hbmFnZXJdXSdzIHRvcGljIFwiPGNvZGU+bmF2LW1lbnUuW3N1Yi10b3BpYy1uYW1lXS5jbWQubmF2aWdhdGU8L2NvZGU+XCIgdG8gcHVibGlzaCBhIG5hdmlnYXRpb25cbiAqIDxjb2RlPmNvbW1hbmQ8L2NvZGU+IHRvIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LlxuICogPC9wPlxuICpcbiAqIEBhdXRob3Igc2hpb3JpbiwgdGVlNGN1dGVcbiAqIEBzZWUgW1tBYnN0cmFjdE5hdkl0ZW1dXVxuICogQHNlZSBbW0lOYXZpZ2F0b3JdXVxuICogQHNlZSBbW09ic2VydmFibGVNYW5hZ2VyXV1cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEFic3RyYWN0TmF2TWVudTxUIGV4dGVuZHMgQWJzdHJhY3ROYXZJdGVtPiBleHRlbmRzIEFic3RyYWN0STE4TkFwcGxpY2FibGUgaW1wbGVtZW50cyBJTmF2aWdhdG9yPFQ+LCBPbkluaXQge1xuXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgTkFWSUdBVEVfVE9QSUNfTkFNRTogc3RyaW5nID0gTkFWSUdBVEVfVE9QSUNfTkFNRTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBOQVZJR0FURV9DTURfVE9QSUNfTkFNRTogc3RyaW5nID0gTkFWSUdBVEVfQ01EX1RPUElDX05BTUU7XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IHRoZSBuYXZpZ2F0aW9uIGV2ZW50IHRvcGljIG5hbWUgd2l0aCB0aGUgZ2l2ZW4gPGNvZGU+PGI+c3ViVG9waWNOYW1lPC9iPjwvY29kZT4uIFRoZSByZXR1cm5pbmcgdG9waWMgbmFtZSB3aWxsIGJlIHByZWZpeGVkIGJ5XG4gICAqIFtbTkFWSUdBVEVfVE9QSUNfTkFNRV1dLlxuICAgKiA8L3A+XG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldE5hdmlnYXRlVG9waWNOYW1lKHN1YlRvcGljTmFtZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAoc3ViVG9waWNOYW1lID09PSBudWxsIHx8IHR5cGVvZiBzdWJUb3BpY05hbWUgPT09ICd1bmRlZmluZWQnIHx8IHN1YlRvcGljTmFtZSA9PT0gJycpIHtcbiAgICAgIHJldHVybiBBYnN0cmFjdE5hdk1lbnUuTkFWSUdBVEVfVE9QSUNfTkFNRTtcbiAgICB9XG5cbiAgICBpZiAoc3ViVG9waWNOYW1lLmNoYXJBdCgwKSA9PT0gJy4nKSB7XG4gICAgICBzdWJUb3BpY05hbWUgPSBzdWJUb3BpY05hbWUuc3Vic3RyaW5nKDEpO1xuICAgIH1cblxuICAgIGlmIChzdWJUb3BpY05hbWUgPT09ICcnKSB7XG4gICAgICByZXR1cm4gQWJzdHJhY3ROYXZNZW51Lk5BVklHQVRFX1RPUElDX05BTUU7XG4gICAgfVxuXG4gICAgaWYgKHN1YlRvcGljTmFtZS5jaGFyQXQoc3ViVG9waWNOYW1lLmxlbmd0aCAtIDEpICE9PSAnLicpIHtcbiAgICAgIHN1YlRvcGljTmFtZSArPSAnLic7XG4gICAgfVxuXG4gICAgcmV0dXJuIFRPUElDX05BTUVfUFJFRklYICsgc3ViVG9waWNOYW1lICsgTkFWSUdBVEVfU1VGRklYO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IHRoZSBuYXZpZ2F0aW9uIGNtZCB0b3BpYyBuYW1lIHdpdGggdGhlIGdpdmVuIDxjb2RlPjxiPnN1YlRvcGljTmFtZTwvYj48L2NvZGU+LiBUaGUgcmV0dXJuaW5nIHRvcGljIG5hbWUgd2lsbCBiZSBwcmVmaXhlZCBieVxuICAgKiBbW05BVklHQVRFX0NNRF9UT1BJQ19OQU1FXV0uXG4gICAqIDwvcD5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ2V0TmF2aWdhdGVDbWRUb3BpY05hbWUoc3ViVG9waWNOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmIChzdWJUb3BpY05hbWUgPT09IG51bGwgfHwgdHlwZW9mIHN1YlRvcGljTmFtZSA9PT0gJ3VuZGVmaW5lZCcgfHwgc3ViVG9waWNOYW1lID09PSAnJykge1xuICAgICAgcmV0dXJuIEFic3RyYWN0TmF2TWVudS5OQVZJR0FURV9DTURfVE9QSUNfTkFNRTtcbiAgICB9XG5cbiAgICBpZiAoc3ViVG9waWNOYW1lLmNoYXJBdCgwKSA9PT0gJy4nKSB7XG4gICAgICBzdWJUb3BpY05hbWUgPSBzdWJUb3BpY05hbWUuc3Vic3RyaW5nKDEpO1xuICAgIH1cblxuICAgIGlmIChzdWJUb3BpY05hbWUgPT09ICcnKSB7XG4gICAgICByZXR1cm4gQWJzdHJhY3ROYXZNZW51Lk5BVklHQVRFX0NNRF9UT1BJQ19OQU1FO1xuICAgIH1cblxuICAgIGlmIChzdWJUb3BpY05hbWUuY2hhckF0KHN1YlRvcGljTmFtZS5sZW5ndGggLSAxKSAhPT0gJy4nKSB7XG4gICAgICBzdWJUb3BpY05hbWUgKz0gJy4nO1xuICAgIH1cblxuICAgIHJldHVybiBUT1BJQ19OQU1FX1BSRUZJWCArIHN1YlRvcGljTmFtZSArIE5BVklHQVRFX0NNRF9TVUZGSVg7XG4gIH1cblxuICBwcm90ZWN0ZWQgaXRlbXM6IFRbXTtcbiAgcHJvdGVjdGVkIHN1YlRvcGljTmFtZTogc3RyaW5nO1xuICBwcm90ZWN0ZWQgbmF2aWdhdGVTdWJqZWN0czogU3ViamVjdDxhbnk+W107XG4gIHByb3RlY3RlZCBvYnNlcnZhYmxlTWdyOiBPYnNlcnZhYmxlTWFuYWdlcjtcblxuICBjb25zdHJ1Y3RvcihzdWJUb3BpY05hbWU6IHN0cmluZywgb2Jzdk1ncjogT2JzZXJ2YWJsZU1hbmFnZXIpIHtcbiAgICBzdXBlcigpO1xuXG4gICAgdGhpcy5pdGVtcyA9IFtdO1xuICAgIHRoaXMuc3ViVG9waWNOYW1lID0gc3ViVG9waWNOYW1lO1xuICAgIHRoaXMubmF2aWdhdGVTdWJqZWN0cyA9IFtdO1xuICAgIHRoaXMub2JzZXJ2YWJsZU1nciA9IG9ic3ZNZ3I7XG4gIH1cblxuICBwcml2YXRlIGluaXROYXZNZW51RXZlbnRUb3BpY3MobmF2aWdhdGU6IHN0cmluZywgbmF2aWdhdGVDbWQ6IHN0cmluZyk6IHZvaWQge1xuICAgIC8vIENyZWF0ZSBjaGFuZ2UgZXZlbnQgb2JzZXJ2YWJsZSB0b3BpY3NcbiAgICBpZiAobmF2aWdhdGUgIT09IG51bGwgJiYgdHlwZW9mIG5hdmlnYXRlID09PSAnc3RyaW5nJykge1xuICAgICAgdGhpcy5uYXZpZ2F0ZVN1YmplY3RzLnB1c2godGhpcy5vYnNlcnZhYmxlTWdyLmNyZWF0ZVN1YmplY3QobmF2aWdhdGUpKTtcbiAgICB9XG5cbiAgICAvLyBTdWJzY3JpYmUgb24gQ01EIHRvcGljc1xuICAgIGlmIChuYXZpZ2F0ZUNtZCAhPT0gbnVsbCAmJiB0eXBlb2YgbmF2aWdhdGVDbWQgPT09ICdzdHJpbmcnKSB7XG4gICAgICB0aGlzLm9ic2VydmFibGVNZ3Iuc3Vic2NyaWJlKG5hdmlnYXRlQ21kLCAoaXRlbTogYW55KSA9PiB7XG4gICAgICAgIGlmIChpdGVtIGluc3RhbmNlb2YgQWJzdHJhY3ROYXZJdGVtKSB7XG4gICAgICAgICAgdGhpcy5uYXZpZ2F0ZVRvKDxUPml0ZW0pOyAvLyBvcGVuIGhlcmVcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIC8vIEluaXQgc3VwZXIgY2xhc3MgZXZlbnQgdG9waWNzXG4gICAgdGhpcy5pbml0TmF2TWVudUV2ZW50VG9waWNzKFxuICAgICAgQWJzdHJhY3ROYXZNZW51Lk5BVklHQVRFX1RPUElDX05BTUUsXG4gICAgICBBYnN0cmFjdE5hdk1lbnUuTkFWSUdBVEVfQ01EX1RPUElDX05BTUVcbiAgICApO1xuXG4gICAgaWYgKHRoaXMuc3ViVG9waWNOYW1lICE9PSBudWxsICYmIHRoaXMuc3ViVG9waWNOYW1lICE9PSAnJyB8fCB0eXBlb2YgdGhpcy5zdWJUb3BpY05hbWUgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAvLyBJbml0IHN1YiB0b3BpYyBldmVudCB0b3BpY3NcbiAgICAgIHRoaXMuaW5pdE5hdk1lbnVFdmVudFRvcGljcyhcbiAgICAgICAgQWJzdHJhY3ROYXZNZW51LmdldE5hdmlnYXRlVG9waWNOYW1lKHRoaXMuc3ViVG9waWNOYW1lKSxcbiAgICAgICAgQWJzdHJhY3ROYXZNZW51LmdldE5hdmlnYXRlQ21kVG9waWNOYW1lKHRoaXMuc3ViVG9waWNOYW1lKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgPGNvZGU+bmF2IGl0ZW08L2NvZGU+cyAoW1tBYnN0cmFjdE5hdkl0ZW1dXSkgb2YgdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uXG4gICAqIDwvcD5cbiAgICovXG4gIHB1YmxpYyBnZXRJdGVtcygpOiBUW10ge1xuICAgIHJldHVybiB0aGlzLml0ZW1zO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IFtbT2JzZXJ2YWJsZU1hbmFnZXJdXSdzIHN1YiB0b3BpYyBuYW1lIGFzc29jaWF0ZWQgd2l0aCB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi5cbiAgICogPC9wPlxuICAgKi9cbiAgcHVibGljIGdldFN1YlRvcGljTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnN1YlRvcGljTmFtZTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCA8Y29kZT5uYXYgaXRlbTwvY29kZT5zIGNvdW50IGluIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqL1xuICBwdWJsaWMgZ2V0SXRlbUNvdW50KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaXRlbXMubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IGFuIGFjdGl2ZSA8Y29kZT5uYXYgaXRlbTwvY29kZT4gaW5kZXggb2YgdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHJldHVybiBSZXR1cm5zIDxjb2RlPi0xPC9jb2RlPiBpZiB0aGVyZSBpcyBubyBjdXJyZW50IGFjdGl2ZSBpdGVtLiBPdGhlcndpc2UsIHJldHVybiB0aGUgYXJyYXkgaW5kZXggb2YgY3VycmVudFxuICAgKiBhY3RpdmUgaXRlbS5cbiAgICovXG4gIHB1YmxpYyBnZXRBY3RpdmVJbmRleCgpOiBudW1iZXIge1xuICAgIGZvciAobGV0IGk6IG51bWJlciA9IDA7IGkgPCB0aGlzLml0ZW1zLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAodGhpcy5pdGVtc1tpXS5pc0FjdGl2ZSgpKSB7XG4gICAgICAgIHJldHVybiBpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiAtMTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCBhbiBhY3RpdmUgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IG9mIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyA8Y29kZT5udWxsPC9jb2RlPiBpZiB0aGVyZSBpcyBubyBjdXJyZW50IGFjdGl2ZSBpdGVtLlxuICAgKi9cbiAgcHVibGljIGdldEFjdGl2ZUl0ZW0oKTogVCB7XG4gICAgbGV0IGlkeDogbnVtYmVyID0gdGhpcy5nZXRBY3RpdmVJbmRleCgpO1xuXG4gICAgaWYgKGlkeCA8IDApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLml0ZW1zW2lkeF07XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBTZXQgPGNvZGU+bmF2IGl0ZW08L2NvZGU+cyBvZiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi5cbiAgICogPC9wPlxuICAgKi9cbiAgcHVibGljIHNldEl0ZW1zKGl0ZW1zOiBUW10pOiB2b2lkIHtcbiAgICB0aGlzLml0ZW1zID0gaXRlbXM7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBBZGQgYSBuZXcgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IGludG8gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uIElmIHRoZXJlIGFscmVhZHkgaXMgdGhlIGdpdmVuIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPiBpbiB0aGlzXG4gICAqIDxjb2RlPm5hdiBtZW51PC9jb2RlPiwgdGhpcyBtZXRob2Qgd2lsbCBkbyBub3RoaW5nIGFuZCByZXR1cm4gPGNvZGU+ZmFsc2U8L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBwYXJhbSBpdGVtIEEgbmV3IDxjb2RlPm5hdiBpdGVtPC9jb2RlPiB0byBiZSBhZGRlZCBpbnRvIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhlIGdpdmVuIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPiBpcyBhZGRlZCBpbnRvIHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LiBPdGhlcndpc2UsIHJldHVybnMgPGNvZGU+ZmFsc2U8L2NvZGU+LlxuICAgKi9cbiAgcHVibGljIGFkZEl0ZW0oaXRlbTogVCk6IGJvb2xlYW4ge1xuICAgIGlmICh0aGlzLmNvbnRhaW5zSXRlbShpdGVtKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMuaXRlbXMucHVzaChpdGVtKTtcblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogUmVtb3ZlIHRoZSBnaXZlbiA8Y29kZT48Yj5pdGVtPC9iPjwvY29kZT4gZnJvbSB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi4gSWYgdGhlIGdpdmVuIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPiBpcyBub3QgaW4gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4sIHRoaXMgbWV0aG9kXG4gICAqIHdpbGwgZG8gbm90aGluZyBhbmQgcmV0dXJuIDxjb2RlPmZhbHNlPC9jb2RlPi4gSWYgdGhlIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPiBiZWluZyByZW1vdmVkIGlzIGEgY3VycmVudCBhY3RpdmUgaXRlbSwgdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4gd2lsbCBiZSBuYXZpZ2F0ZWRcbiAgICogdG8gdGhlIGZpcnN0IDxjb2RlPm5hdiBpdGVtPC9jb2RlPi5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gaXRlbSBBIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiB0byBiZSByZW1vdmVkIGZyb20gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgZ2l2ZW4gPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+IGlzIGZvdW5kIGFuZCByZW1vdmVkIGZyb20gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4uIE90aGVyd2lzZSwgcmV0dXJucyA8Y29kZT5mYWxzZTwvY29kZT4uXG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlSXRlbShpdGVtOiBUKTogYm9vbGVhbiB7XG4gICAgbGV0IGlkeDogbnVtYmVyID0gdGhpcy5pdGVtcy5pbmRleE9mKGl0ZW0pO1xuXG4gICAgaWYgKGlkeCA8IDApIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB0aGlzLml0ZW1zLnNwbGljZShpZHgsIDEpO1xuXG4gICAgaWYgKGl0ZW0uYWN0aXZlKSB7XG4gICAgICAvLyBTZXQgcGFnZSBhY3RpdmUgdG8gZmFsc2UuXG4gICAgICBpdGVtLmFjdGl2ZSA9IGZhbHNlO1xuXG4gICAgICAvLyBJZiBpdCBpcyBjdXJyZW50bHkgYWN0aXZlIHBhZ2UsIHdlJ3ZlIHRvIG5hdmlnYXRlIHRvIGFub3RoZXIgb25lLlxuICAgICAgdGhpcy5uYXZpZ2F0ZVRvSW5kZXgoMCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBUbyBjaGVjayB0aGF0IHRoZSBnaXZlbiA8Y29kZT48Yj5pdGVtPC9iPjwvY29kZT4gaXMgaW4gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4gb3Igbm90LlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBwYXJhbSBpdGVtIEEgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IHRvIGNoZWNrIHRoYXQgaXQgaXMgaW4gdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4gb3Igbm90LlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhlIGdpdmVuIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPiBpcyBpbiB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPi5cbiAgICovXG4gIHB1YmxpYyBjb250YWluc0l0ZW0oaXRlbTogVCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLml0ZW1zLmluZGV4T2YoaXRlbSkgPj0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCBhIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiAoW1tBYnN0cmFjdE5hdkl0ZW1dXSkgZnJvbSB0aGUgZ2l2ZW4gaW5kZXggKDxjb2RlPjxiPmlkeDwvYj48L2NvZGU+KS5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gaWR4IFRoZSBpbmRleCBvZiA8Y29kZT5uYXYgaXRlbTwvY29kZT4gdG8gZ2V0LlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgYW4gaW5zdGFuY2Ugb2YgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IChbW0Fic3RyYWN0TmF2SXRlbV1dKSBhdCB0aGUgc3BlY2lmaWVkIGluZGV4ICg8Y29kZT48Yj5pZHg8L2I+PC9jb2RlPikuXG4gICAqIFJldHVybnMgPGNvZGU+bnVsbDwvY29kZT4gaWYgdGhlIGdpdmVuIGluZGV4IGlzIG91dCBvZiByYW5nZS5cbiAgICovXG4gIHB1YmxpYyBnZXRJdGVtQnlJbmRleChpZHg6IG51bWJlcik6IFQge1xuICAgIGlmIChpZHggPT09IG51bGwgfHwgdHlwZW9mIGlkeCA9PT0gJ3VuZGVmaW5lZCcgfHwgaWR4IDwgMCB8fCBpZHggPj0gdGhpcy5pdGVtcy5sZW5ndGgpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLml0ZW1zW2lkeF07XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgYSA8Y29kZT5uYXYgaXRlbTwvY29kZT4gKFtbQWJzdHJhY3ROYXZJdGVtXV0pIGJ5IHRoZSBnaXZlbiA8Y29kZT48Yj5uYW1lPC9iPjwvY29kZT4uXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIG5hbWUgVGhlIG5hbWUgb2YgYSA8Y29kZT5uYXYgaXRlbTwvY29kZT4gdG8gZ2V0LlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgYW4gaW5zdGFuY2Ugb2YgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IChbW0Fic3RyYWN0TmF2SXRlbV1dKSB3aXRoIHRoZSBnaXZlbiA8Y29kZT48Yj5uYW1lPC9iPjwvY29kZT4uXG4gICAqIFJldHVybnMgPGNvZGU+bnVsbDwvY29kZT4gaWYgbm90IGZvdW5kLlxuICAgKi9cbiAgcHVibGljIGdldEl0ZW1CeU5hbWUobmFtZTogc3RyaW5nKTogVCB7XG4gICAgbGV0IGlkeDogbnVtYmVyID0gdGhpcy5nZXRJdGVtSW5kZXhCeU5hbWUobmFtZSk7XG5cbiAgICBpZiAoaWR4IDwgMCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuaXRlbXNbaWR4XTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCB0aGUgaW5kZXggb2YgdGhlIGdpdmVuIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiAoPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+KS5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gaXRlbSBUaGUgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IHRvIGZpbmQgaW5kZXguXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyBhbiBpbmRleCBvZiB0aGUgc3BlY2lmaWVkIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPi4gUmV0dXJucyA8Y29kZT4tMTwvY29kZT4gaWYgbm90IGZvdW5kLlxuICAgKi9cbiAgcHVibGljIGdldEl0ZW1JbmRleChpdGVtOiBUKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5pdGVtcy5pbmRleE9mKGl0ZW0pO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IHRoZSBpbmRleCBvZiB0aGUgZ2l2ZW4gaXRlbSA8Y29kZT48Yj5uYW1lPC9iPjwvY29kZT4uXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIG5hbWUgVGhlIGl0ZW0gbmFtZSB0byBmaW5kIGluZGV4LlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgYW4gaW5kZXggb2YgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IGhhdmluZyB0aGUgc3BlY2lmaWVkIDxjb2RlPjxiPm5hbWU8L2I+PC9jb2RlPi4gUmV0dXJucyA8Y29kZT4tMTwvY29kZT4gaWYgbm90IGZvdW5kLlxuICAgKi9cbiAgcHVibGljIGdldEl0ZW1JbmRleEJ5TmFtZShuYW1lOiBzdHJpbmcpOiBudW1iZXIge1xuICAgIGlmIChuYW1lID09PSBudWxsIHx8IHR5cGVvZiBuYW1lID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH1cblxuICAgIGZvciAobGV0IGk6IG51bWJlciA9IDA7IGkgPCB0aGlzLml0ZW1zLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAodGhpcy5pdGVtc1tpXS5nZXROYW1lKCkgPT09IG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIGk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIC0xO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogTmF2aWdhdGUgdGhpcyA8Y29kZT5uYXYgbWVudTwvY29kZT4gdG8gdGhlIHNwZWNpZmllZCA8Y29kZT5uYXYgPGI+aXRlbTwvYj48L2NvZGU+LiBUaGlzIG1ldGhvZCByZXR1cm5zIDxjb2RlPlByb21pc2U8L2NvZGU+IHRvIHN1cHBvcnRcbiAgICogYXN5bmNocm9ub3VzIGV4ZWN1dGlvbi4gVGhlIDxjb2RlPnJlc3VsdDwvY29kZT4gdmFsdWUgb2YgcmV0dXJuZWQgPGNvZGU+UHJvbWlzZTwvY29kZT4gaXMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG5hdmlnYXRpb24gcmVzdWx0LlxuICAgKiBUaGUgcmVzdWx0IHZhbHVlIG11c3QgYmUgPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhlIG5hdmlnYXRpb24gaXMgc3VjY2Vzc2Z1bC4gT3RoZXJ3aXNlLCBmb3IgZXhhbXBsZSwgaWYgdGhlIGdpdmVuIDxjb2RlPjxiPml0ZW08L2I+PC9jb2RlPlxuICAgKiBkb2VzIG5vdCBleGlzdCwgdGhlIHJlc3VsdCB2YWx1ZSB3aWxsIGJlIDxjb2RlPmZhbHNlPC9jb2RlPi5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gaXRlbSBUaGUgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IHRvIG5hdmlnYXRlIHRvLlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgYSA8Y29kZT5Qcm9taXNlPC9jb2RlPiB3aGljaCB3aWxsIGJlIHJlc29sdmVkIHdoZW4gdGhlIG5hdmlnYXRpb24gaXMgZG9uZS4gVGhlIDxjb2RlPlByb21pc2U8L2NvZGU+J3MgcmVzdWx0IHdpbGwgYmUgYVxuICAgKiBib29sZWFuIHZhbHVlIHdoaWNoIGl0cyB2YWx1ZSB3aWxsIGJlIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSBuYXZpZ2F0aW9uIGlzIHN1Y2Nlc3NmdWwuXG4gICAqL1xuICBwdWJsaWMgbmF2aWdhdGVUbyhpdGVtOiBUKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKGl0ZW0gPT09IG51bGwgfHwgdHlwZW9mIGl0ZW0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGZhbHNlKTtcbiAgICB9XG5cbiAgICBpZiAoaXRlbS5pc0FjdGl2ZSgpKSB7XG4gICAgICAvLyBUaGUgaXRlbSBpcyBjdXJyZW50bHkgYWN0aXZlLiBEbyBub3RoaW5nIC4uLlxuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuZG9OYXZpZ2F0ZShpdGVtKS50aGVuKChzdWNjZXNzKSA9PiB7XG4gICAgICBpZiAoc3VjY2Vzcykge1xuICAgICAgICBsZXQgY3VyQWN0aXZlOiBUID0gdGhpcy5nZXRBY3RpdmVJdGVtKCk7XG4gICAgICAgIGlmIChjdXJBY3RpdmUgIT09IG51bGwpIHtcbiAgICAgICAgICAvLyBTZXQgY3VycmVudCBwYWdlIGFjdGl2ZSB0byBmYWxzZVxuICAgICAgICAgIGN1ckFjdGl2ZS5hY3RpdmUgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGl0ZW0uYWN0aXZlID0gdHJ1ZTtcblxuICAgICAgICAvLyBFbWl0IGNoYW5nZSBldmVudFxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh0aGlzLm5hdmlnYXRlU3ViamVjdHMpKSB7XG4gICAgICAgICAgdGhpcy5uYXZpZ2F0ZVN1YmplY3RzLmZvckVhY2goKG9ic3YsIGlkeCkgPT4ge1xuICAgICAgICAgICAgb2Jzdi5uZXh0KGl0ZW0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmRlYnVnKCdOb3QgbmF2aWdhdGUgdG8gXCInICsgaXRlbS5nZXROYW1lKCkgKyAnXCIuJyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoc3VjY2Vzcyk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBOYXZpZ2F0ZSB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPiB0byB0aGUgc3BlY2lmaWVkIGluZGV4ICg8Y29kZT48Yj5pZHg8L2I+PC9jb2RlPikuIFRoaXMgbWV0aG9kIHJldHVybnMgPGNvZGU+UHJvbWlzZTwvY29kZT4gdG8gc3VwcG9ydFxuICAgKiBhc3luY2hyb25vdXMgZXhlY3V0aW9uLiBUaGUgPGNvZGU+cmVzdWx0PC9jb2RlPiB2YWx1ZSBvZiByZXR1cm5lZCA8Y29kZT5Qcm9taXNlPC9jb2RlPiBpcyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgbmF2aWdhdGlvbiByZXN1bHQuXG4gICAqIFRoZSByZXN1bHQgdmFsdWUgbXVzdCBiZSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgbmF2aWdhdGlvbiBpcyBzdWNjZXNzZnVsLiBPdGhlcndpc2UsIHRoZSByZXN1bHQgdmFsdWUgd2lsbCBiZSA8Y29kZT5mYWxzZTwvY29kZT4uXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIGlkeCBUaGUgaXRlbSBpbmRleCB0byBuYXZpZ2F0ZSB0by5cbiAgICpcbiAgICogQHJldHVybiBSZXR1cm5zIGEgPGNvZGU+UHJvbWlzZTwvY29kZT4gd2hpY2ggd2lsbCBiZSByZXNvbHZlZCB3aGVuIHRoZSBuYXZpZ2F0aW9uIGlzIGRvbmUuIFRoZSA8Y29kZT5Qcm9taXNlPC9jb2RlPidzIHJlc3VsdCB3aWxsIGJlIGFcbiAgICogYm9vbGVhbiB2YWx1ZSB3aGljaCBpdHMgdmFsdWUgd2lsbCBiZSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgbmF2aWdhdGlvbiBpcyBzdWNjZXNzZnVsLlxuICAgKi9cbiAgcHVibGljIG5hdmlnYXRlVG9JbmRleChpZHg6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGxldCBwYWdlOiBUID0gdGhpcy5nZXRJdGVtQnlJbmRleChpZHgpO1xuXG4gICAgaWYgKHBhZ2UgPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLm5hdmlnYXRlVG8ocGFnZSk7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBOYXZpZ2F0ZSB0aGlzIDxjb2RlPm5hdiBtZW51PC9jb2RlPiB0byBhIDxjb2RlPm5hdiBpdGVtPC9jb2RlPiBoYXZpbmcgdGhlIHNwZWNpZmllZCA8Y29kZT48Yj5uYW1lPC9iPjwvY29kZT4uIFRoaXMgbWV0aG9kIHJldHVybnNcbiAgICogPGNvZGU+UHJvbWlzZTwvY29kZT4gdG8gc3VwcG9ydCBhc3luY2hyb25vdXMgZXhlY3V0aW9uLiBUaGUgPGNvZGU+cmVzdWx0PC9jb2RlPiB2YWx1ZSBvZiByZXR1cm5lZCA8Y29kZT5Qcm9taXNlPC9jb2RlPiBpcyBhIGJvb2xlYW4gaW5kaWNhdGluZ1xuICAgKiB0aGUgbmF2aWdhdGlvbiByZXN1bHQuIFRoZSByZXN1bHQgdmFsdWUgbXVzdCBiZSA8Y29kZT50cnVlPC9jb2RlPiBpZiB0aGUgbmF2aWdhdGlvbiBpcyBzdWNjZXNzZnVsLiBPdGhlcndpc2UsIGZvciBleGFtcGxlLCBpZiB0aGUgZ2l2ZW4gPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+XG4gICAqIGRvZXMgbm90IGV4aXN0LCB0aGUgcmVzdWx0IHZhbHVlIHdpbGwgYmUgPGNvZGU+ZmFsc2U8L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBwYXJhbSBuYW1lIFRoZSBuYW1lIG9mIGEgPGNvZGU+bmF2IGl0ZW08L2NvZGU+IHRvIG5hdmlnYXRlIHRvLlxuICAgKlxuICAgKiBAcmV0dXJuIFJldHVybnMgYSA8Y29kZT5Qcm9taXNlPC9jb2RlPiB3aGljaCB3aWxsIGJlIHJlc29sdmVkIHdoZW4gdGhlIG5hdmlnYXRpb24gaXMgZG9uZS4gVGhlIDxjb2RlPlByb21pc2U8L2NvZGU+J3MgcmVzdWx0IHdpbGwgYmUgYVxuICAgKiBib29sZWFuIHZhbHVlIHdoaWNoIGl0cyB2YWx1ZSB3aWxsIGJlIDxjb2RlPnRydWU8L2NvZGU+IGlmIHRoZSBuYXZpZ2F0aW9uIGlzIHN1Y2Nlc3NmdWwuXG4gICAqL1xuICBwdWJsaWMgbmF2aWdhdGVUb05hbWUobmFtZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgbGV0IHBhZ2U6IFQgPSB0aGlzLmdldEl0ZW1CeU5hbWUobmFtZSk7XG5cbiAgICBpZiAocGFnZSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMubmF2aWdhdGVUbyhwYWdlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFJlc2V0IHRoaXMgPGNvZGU+bmF2IG1lbnU8L2NvZGU+LiBUaGlzIG1ldGhvZCBzaW1wbHkgbmF2aWdhdGVzIGJhY2sgdG8gdGhlIGl0ZW0gYXQgaW5kZXggPGNvZGU+MDwvY29kZT4uXG4gICAqIDwvcD5cbiAgICovXG4gIHB1YmxpYyByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLm5hdmlnYXRlVG9JbmRleCgwKTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEEgbWV0aG9kIHRvIHBlcmZvcm0gdGhlIGFjdHVhbCBuYXZpZ2F0aW9uLCBmb3IgZXhhbXBsZSwgY2hhbmdpbmcgYSByb3V0ZXIncyBwYXRoLCBldGMuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIGl0ZW0gQSA8Y29kZT5uYXYgaXRlbTwvY29kZT4gdG8gbmF2aWdhdGUgdG8uXG4gICAqXG4gICAqIEByZXR1cm4gUmV0dXJucyBhIDxjb2RlPlByb21pc2U8L2NvZGU+IHdoaWNoIHdpbGwgYmUgcmVzb2x2ZWQgd2hlbiB0aGUgbmF2aWdhdGlvbiBpcyBkb25lLiBUaGUgPGNvZGU+UHJvbWlzZTwvY29kZT4ncyByZXN1bHQgd2lsbCBiZSBhXG4gICAqIGJvb2xlYW4gdmFsdWUgd2hpY2ggaXRzIHZhbHVlIHdpbGwgYmUgPGNvZGU+dHJ1ZTwvY29kZT4gaWYgdGhlIG5hdmlnYXRpb24gaXMgc3VjY2Vzc2Z1bC5cbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCBkb05hdmlnYXRlKGl0ZW06IFQpOiBQcm9taXNlPGJvb2xlYW4+O1xuXG59XG4iXX0=