com.phloxui
Version:
PhloxUI Ng2+ Framework
643 lines (642 loc) • 59.8 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { Component, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { PhloxAppInfoService } from '../service/PhloxAppInfoService.service';
import { PhloxAppService } from '../service/PhloxAppService.service';
import { ObservableManager } from '../service/ObservableManager.service';
import { NeedFocusService } from '../service/NeedFocusService.service';
import { DialogService } from '../service/DialogService.service';
import { BackgroundProcessManager } from '../service/BackgroundProcessManager.service';
import { AbstractNavLeftLayout } from './AbstractNavLeftLayout';
import { MaterialBarLoader } from '../theme/material/component/MaterialBarLoader.component';
const /** @type {?} */ TYPE_NAME = "phx-app";
/**
* <p style="text-indent: 2em;">
* A main bootstrap component class for <code>PhloxUI</code> application. This class implements the [[INavigator]] interface having pages ([[AbstractPage]])
* as <code>navigatee</code> items ([[INavigatee]]). An <code>application</code> may consist of various pages, for example, it may have a login page to allow the user to
* login, once the user is logged on, it will navigate the user to the main page, etc.
* </p>
*
* @author shiorin, tee4cute
*/
export class PhloxApp {
/**
* @param {?} router
* @param {?} appInfoService
* @param {?} appSvc
* @param {?} observableMgr
* @param {?} needFocusService
* @param {?} dialogService
* @param {?} bgProcessMgr
*/
constructor(router, appInfoService, appSvc, observableMgr, needFocusService, dialogService, bgProcessMgr) {
this.curRouterLoading = {
"path": null,
"resolve": null,
"reject": null
};
this.pages = [];
this.router = router;
this.appInfoService = appInfoService;
this.observableMgr = observableMgr;
this.needFocusService = needFocusService;
this.reloadAppInfo();
this.dialogService = dialogService;
this.bgProcessMgr = bgProcessMgr;
this._showLoader = false;
// Set app instance to PhloxAppService to allow others to access this instance.
appSvc.setInstance(this);
// init dialog service
this.dialogService.init(this);
this.observableMgr.subscribe(BackgroundProcessManager.PROCESS_START_TOPIC_NAME, (startBGProcess) => {
if (startBGProcess.type === 'connection.page') {
this.runPageLoader();
}
});
this.observableMgr.subscribe(BackgroundProcessManager.PROCESS_END_TOPIC_NAME, (endBGProcess) => {
if (endBGProcess.type === 'connection.page') {
if (this.bgProcessMgr.getRunningProcessesCount('connection.page', null) <= 0) {
this.stopPageLoader();
}
}
});
this.observableMgr.subscribe(BackgroundProcessManager.PROCESS_ERROR_TOPIC_NAME, (errorBGProcess) => {
if (errorBGProcess.type === 'connection.page') {
if (this.bgProcessMgr.getRunningProcessesCount('connection.page', null) <= 0) {
this.stopPageLoader();
}
}
});
}
/**
* @return {?}
*/
ngOnInit() {
this.observableMgr.subscribe(AbstractNavLeftLayout.FIXED_CHANGE_TOPIC_NAME, (layout) => {
console.log('Nav left "' + layout.getSubTopicName() + '" fixed: ' + layout.fixed);
});
this.observableMgr.subscribe(AbstractNavLeftLayout.TOGGLED_CHANGE_TOPIC_NAME, (layout) => {
console.log('Nav left "' + layout.getSubTopicName() + '" toggled: ' + layout.toggled);
});
// fixed=false, toggled=true
setTimeout(() => {
this.observableMgr.publish(AbstractNavLeftLayout.TOGGLED_CMD_TOPIC_NAME, true);
}, 1500);
// fixed=false, toggled=false
setTimeout(() => {
this.observableMgr.publish(AbstractNavLeftLayout.TOGGLED_CMD_TOPIC_NAME, false);
}, 3000);
// fixed=true, toggled=false
setTimeout(() => {
this.observableMgr.publish(AbstractNavLeftLayout.FIXED_CMD_TOPIC_NAME, true);
}, 3500);
// fixed=true, toggled=true
setTimeout(() => {
this.observableMgr.publish(AbstractNavLeftLayout.TOGGLED_CMD_TOPIC_NAME, true);
}, 4500);
// fixed=true, toggled=false
setTimeout(() => {
this.observableMgr.publish(AbstractNavLeftLayout.TOGGLED_CMD_TOPIC_NAME, false);
}, 6000);
// fixed=false, toggled=false
setTimeout(() => {
this.observableMgr.publish(AbstractNavLeftLayout.FIXED_CMD_TOPIC_NAME, false);
}, 6500);
}
/**
* @return {?}
*/
isShowLoader() {
return this._showLoader;
}
/**
* <p style="text-indent: 1em;">
* Get app info of currently opened <code>application</code>.
* </p>
* @return {?}
*/
getAppInfo() {
return this.appInfo;
}
/**
* <p style="text-indent: 1em;">
* Reload the app info from <code>PhloxAppInfoService</code>.
* </p>
* @return {?}
*/
reloadAppInfo() {
return this.appInfoService.reload().then((result) => {
this.appInfo = result;
return Promise.resolve(this.appInfo);
});
}
/**
* @return {?}
*/
getRouter() {
return this.router;
}
/**
* <p style="text-indent: 1em;">
* Get all available <code>pages</code> ([[AbstractPage]]) in this <code>application</code>.
* </p>
*
* @see [[INavigator.getItems]]
* @return {?}
*/
getItems() {
return this.pages;
}
/**
* <p style="text-indent: 1em;">
* Get all available <code>page</code> count ([[AbstractPage]]) in this <code>application</code>.
* </p>
*
* @see [[INavigator.getItemCount]]
* @return {?}
*/
getItemCount() {
return this.pages.length;
}
/**
* <p style="text-indent: 1em;">
* Get current active <code>page</code> ([[AbstractPage]]) index in the array returned from [[getItems]] method.
* </p>
*
* @see [[INavigator.getActiveIndex]]
* @return {?} Returns <code>-1</code> if there is no current active <code>page</code>.
*/
getActiveIndex() {
for (let /** @type {?} */ i = 0; i < this.pages.length; i++) {
if (this.pages[i].isActive()) {
return i;
}
}
return -1;
}
/**
* <p style="text-indent: 1em;">
* Get current active <code>page</code> ([[AbstractPage]]) object instance.
* </p>
*
* @see [[INavigator.getActiveItem]]
* @return {?} Returns <code>null</code> if there is no current active <code>page</code>.
*/
getActiveItem() {
let /** @type {?} */ idx = this.getActiveIndex();
if (idx < 0) {
return null;
}
return this.pages[idx];
}
/**
* <p style="text-indent: 1em;">
* An implementation of [[INavigator.setItems]] method. Please see the documentation of super class or super interface for more details.
* </p>
*
* @see [[INavigator.setItems]]
* @param {?} items
* @return {?}
*/
setItems(items) {
this.pages = items;
}
/**
* <p style="text-indent: 1em;">
* Add a new <code>page</code> ([[AbstractPage]]) into this <code>application</code>. If the <code>page</code> (<code><b>item</b></code>) being added is the
* first <code>page</code> of this <code>application</code>, this method will automatically show the given <code>page</code> and set its <code>active</code>
* flag to <code>true</code>.
* </p>
*
* @see [[INavigator.addItem]]
* @param {?} item
* @return {?}
*/
addItem(item) {
if (this.containsItem(item)) {
return false;
}
this.pages.push(item);
if (this.pages.length === 1) {
// This is the first one. So, it should be active!
item.active = true;
}
return true;
}
/**
* <p style="text-indent: 1em;">
* Remove the given <code>page</code> ([[AbstractPage]]) from this <code>application</code>. If the <code>page</code> (<code><b>item</b></code>) being removed is
* currently active, this method will automatically unset its <code>active</code> flag and show the first <code>page</code> (if available) in the array returned from
* [[getItems]] method instead.
* </p>
*
* @see [[INavigator.removeItem]]
* @param {?} item
* @return {?}
*/
removeItem(item) {
let /** @type {?} */ idx = this.pages.indexOf(item);
if (idx < 0) {
return false;
}
this.pages = this.pages.slice(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;">
* An implementation of [[INavigator.containsItem]] method. Please see the documentation of super class or super interface for more details.
* </p>
*
* @see [[INavigator.containsItem]]
* @param {?} item
* @return {?}
*/
containsItem(item) {
return this.pages.indexOf(item) >= 0;
}
/**
* <p style="text-indent: 1em;">
* An implementation of [[INavigator.getItemByIndex]] method. Please see the documentation of super class or super interface for more details.
* </p>
*
* @see [[INavigator.getItemByIndex]]
* @param {?} idx
* @return {?}
*/
getItemByIndex(idx) {
if (idx < 0 || idx >= this.pages.length) {
return null;
}
return this.pages[idx];
}
/**
* <p style="text-indent: 1em;">
* An implementation of [[INavigator.getItemByName]] method. Please see the documentation of super class or super interface for more details.
* </p>
*
* @see [[INavigator.getItemByName]]
* @param {?} name
* @return {?}
*/
getItemByName(name) {
let /** @type {?} */ idx = this.getItemIndexByName(name);
if (idx < 0) {
return null;
}
return this.pages[idx];
}
/**
* <p style="text-indent: 1em;">
* An implementation of [[INavigator.getItemIndex]] method. Please see the documentation of super class or super interface for more details.
* </p>
*
* @see [[INavigator.getItemIndex]]
* @param {?} item
* @return {?}
*/
getItemIndex(item) {
return this.pages.indexOf(item);
}
/**
* <p style="text-indent: 1em;">
* An implementation of [[INavigator.getItemIndexByName]] method. Please see the documentation of super class or super interface for more details.
* </p>
*
* @see [[INavigator.getItemIndexByName]]
* @param {?} name
* @return {?}
*/
getItemIndexByName(name) {
for (let /** @type {?} */ i = 0; i < this.pages.length; i++) {
if (this.pages[i].getName() === name) {
return i;
}
}
return -1;
}
/**
* <p style="text-indent: 1em;">
* An alias method of [[navigateToName]] passing <code>page</code>'s name ([[AbstractPage.getName]]) as a parameter.
* </p>
*
* @see [[INavigator.navigateTo]]
* @see [[navigateToName]]
* @param {?} item
* @param {?=} options
* @return {?}
*/
navigateTo(item, options) {
return this.navigateToName(item.getName(), options);
}
/**
* <p style="text-indent: 1em;">
* An alias method of [[navigateTo]] passing <code>page</code> instance at the given index (<code><b>idx</b></code>) as a parameter.
* </p>
*
* @see [[INavigator.navigateToIndex]]
* @see [[navigateTo]]
* @param {?} idx
* @param {?=} options
* @return {?}
*/
navigateToIndex(idx, options) {
let /** @type {?} */ page = this.getItemByIndex(idx);
if (page === null) {
return Promise.resolve(false);
}
return this.navigateTo(page, options);
}
/**
* <p style="text-indent: 1em;">
* Navigate this <code>application</code> to the given <code>page</code> <code><b>name</b></code>. The <code>page</code> name is also a
* <code>router</code>'s uri path specified in [[PHLOX_ROUTES]].
* </p>
*
* @see [[INavigator.navigateToName]]
* @see [[PHLOX_ROUTES]]
* @param {?} name
* @param {?=} options
* @return {?}
*/
navigateToName(name, options) {
let /** @type {?} */ link = name;
if (link === null || typeof link !== 'string') {
return Promise.resolve(false);
}
if (link.length <= 0) {
return Promise.resolve(false);
}
if (link.charAt(0) !== '/') {
link = '/' + link;
}
if (this.router.url === link) {
// Currently active
return Promise.resolve(false);
}
let /** @type {?} */ nav = [link];
if (options !== null && options !== undefined) {
nav.push(options);
}
// Navigate to specified link
return this.router.navigate(nav).then((success) => {
if (success) {
let /** @type {?} */ curActive = this.getActiveItem();
if (curActive !== null) {
// Set current page active to false
curActive.active = false;
}
let /** @type {?} */ newPage = this.getItemByName(link.substring(1));
if (newPage !== null) {
newPage.active = true;
}
}
else {
console.warn('Could not navigate to "' + name + '".');
}
return Promise.resolve(success);
});
}
/**
* <p style="text-indent: 1em;">
* Try to navigate this <code>application</code> back to the first <code>page</code>.
* </p>
*
* @see [[INavigator.reset]]
* @return {?}
*/
reset() {
this.navigateToIndex(0);
}
/**
* <p style="text-indent: 1em;">
* A delegator method passing method call to <code>[[needFocusService]].setFocusingComponent()</code>.
* </p>
*
* @see [[NeedFocusService.setFocusingComponent]]
* @param {?} component
* @param {?=} event
* @return {?}
*/
setFocusingComponent(component, event) {
this.needFocusService.setFocusingComponent(component, event);
}
/**
* <p style="text-indent: 1em;">
* A delegator method passing method call to <code>[[needFocusService]].getFocusingComponent()</code>.
* </p>
*
* @see [[NeedFocusService.getFocusingComponent]]
* @return {?}
*/
getFocusingComponent() {
return this.needFocusService.getFocusingComponent();
}
/**
* <p style="text-indent: 1em;">
* A delegator method passing method call to <code>[[needFocusService]].resetFocusingComponent()</code>.
* </p>
*
* @see [[NeedFocusService.resetFocusingComponent]]
* @param {?=} event
* @return {?}
*/
resetFocusingComponent(event) {
this.needFocusService.resetFocusingComponent(event);
}
/**
* <p style="text-indent: 1em;">
* A delegator method passing method call to <code>[[phloxDialog]].hideDialog()</code>.
* </p>
*
* @see [[PhloxDialog.hideDialog]]
* @return {?}
*/
hideDialog() {
if (this.phloxDialog != null) {
return this.phloxDialog.hideDialog();
}
}
/**
* <p style="text-indent: 1em;">
* A delegator method passing method call to <code>[[phloxDialog]].showConfirmDialog()</code>.
* </p>
*
* @see [[PhloxDialog.showConfirmDialog]]
* @param {?} title
* @param {?} message
* @param {?} showCancelBtn
* @param {?=} width
* @param {?=} height
* @return {?}
*/
showConfirmDialog(title, message, showCancelBtn, width, height) {
if (this.phloxDialog != null) {
return this.phloxDialog.showConfirmDialog(title, message, showCancelBtn, width, height);
}
return new Promise((resolve, reject) => {
reject('Could not find PhloxDialog instance.');
});
}
/**
* <p style="text-indent: 1em;">
* A delegator method passing method call to <code>[[phloxDialog]].showMessageDialog()</code>.
* </p>
*
* @see [[PhloxDialog.showMessageDialog]]
* @param {?} title
* @param {?} message
* @param {?=} width
* @param {?=} height
* @return {?}
*/
showMessageDialog(title, message, width, height) {
if (this.phloxDialog != null) {
return this.phloxDialog.showMessageDialog(title, message, width, height);
}
return new Promise((resolve, reject) => {
reject('Could not find PhloxDialog instance.');
});
}
/**
* <p style="text-indent: 1em;">
* A delegator method passing method call to <code>[[phloxDialog]].showComponentDialog()</code>.
* </p>
*
* @see [[PhloxDialog.showComponentDialog]]
* @param {?} componentDialogModel
* @return {?}
*/
showComponentDialog(componentDialogModel) {
if (this.phloxDialog != null) {
return this.phloxDialog.showComponentDialog(componentDialogModel);
}
return new Promise((resolve, reject) => {
reject('Could not find PhloxDialog instance.');
});
}
/**
* @return {?}
*/
runPageLoader() {
if (this.barloader === null || typeof this.barloader === 'undefined') {
return;
}
this._showLoader = true;
if (!this.barloader.isRunning()) {
this.barloader.start();
}
}
/**
* @return {?}
*/
stopPageLoader() {
if (this.barloader === null || typeof this.barloader === 'undefined') {
return;
}
this._showLoader = false;
if (this.barloader.isRunning()) {
this.barloader.stop();
}
}
}
PhloxApp.TYPE_NAME = TYPE_NAME;
PhloxApp.decorators = [
{ type: Component, args: [{
moduleId: module.id,
selector: 'phx-app',
template: `<div class="phlox-app-bar-container" [class.show]="isShowLoader()">
<material-bar-loader #barloader></material-bar-loader>
</div>
<router-outlet></router-outlet>
<phx-dialog #dialog></phx-dialog>
`
},] },
];
/** @nocollapse */
PhloxApp.ctorParameters = () => [
{ type: Router, },
{ type: PhloxAppInfoService, },
{ type: PhloxAppService, },
{ type: ObservableManager, },
{ type: NeedFocusService, },
{ type: DialogService, },
{ type: BackgroundProcessManager, },
];
PhloxApp.propDecorators = {
"phloxDialog": [{ type: ViewChild, args: ['dialog',] },],
"barloader": [{ type: ViewChild, args: ["barloader",] },],
};
function PhloxApp_tsickle_Closure_declarations() {
/** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */
PhloxApp.decorators;
/**
* @nocollapse
* @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
*/
PhloxApp.ctorParameters;
/** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */
PhloxApp.propDecorators;
/** @type {?} */
PhloxApp.TYPE_NAME;
/**
* This field will be automatically injected by <code>ng</code>.
* @type {?}
*/
PhloxApp.prototype.appInfoService;
/**
* This field will be automatically injected by <code>ng</code>.
* @type {?}
*/
PhloxApp.prototype.observableMgr;
/**
* This field will be automatically injected by <code>ng</code>.
* @type {?}
*/
PhloxApp.prototype.needFocusService;
/**
* A field keeping cache for the last successfully loaded [[PhloxAppInfo]] from method [[reloadAppInfo]].
* @type {?}
*/
PhloxApp.prototype.appInfo;
/**
* An array keeping all <code>page</code>s of this <code>application</code>.
* @type {?}
*/
PhloxApp.prototype.pages;
/**
* This field will be automatically injected by <code>ng</code>.
* @type {?}
*/
PhloxApp.prototype.router;
/**
* This field will be automatically injected by <code>ng</code>.
* @type {?}
*/
PhloxApp.prototype.dialogService;
/**
* This field will be automatically injected by <code>ng</code>.
* @type {?}
*/
PhloxApp.prototype.bgProcessMgr;
/**
* A [[PhloxDialog]] child component instance of this component.
* @type {?}
*/
PhloxApp.prototype.phloxDialog;
/** @type {?} */
PhloxApp.prototype.barloader;
/** @type {?} */
PhloxApp.prototype._showLoader;
/** @type {?} */
PhloxApp.prototype.curRouterLoading;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGhsb3hBcHAuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vY29tLnBobG94dWkvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50L1BobG94QXBwLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBVSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXpDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHdDQUF3QyxDQUFDO0FBQzdFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUNyRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUN6RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN2RSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDakUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFJdkYsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDaEUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seURBQXlELENBQUM7QUFFNUYsdUJBQU0sU0FBUyxHQUFXLFNBQVMsQ0FBQzs7Ozs7Ozs7OztBQXFCcEMsTUFBTTs7Ozs7Ozs7OztJQWtESixZQUFZLE1BQWMsRUFBRSxjQUFtQyxFQUFFLE1BQXVCLEVBQUUsYUFBZ0MsRUFBRSxnQkFBa0MsRUFDNUosYUFBNEIsRUFBRSxZQUFzQztnQ0FQdEM7WUFDOUIsTUFBTSxFQUFFLElBQUk7WUFDWixTQUFTLEVBQUUsSUFBSTtZQUNmLFFBQVEsRUFBRSxJQUFJO1NBQ2Y7UUFJQyxJQUFJLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQztRQUNoQixJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJ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T25Jbml0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBQaGxveEFwcEluZm8sIENvbXBvbmVudERpYWxvZ01vZGVsIH0gZnJvbSAnLi9tb2RlbC9tb2RlbHMnO1xuaW1wb3J0IHsgUGhsb3hBcHBJbmZvU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2UvUGhsb3hBcHBJbmZvU2VydmljZS5zZXJ2aWNlJztcbmltcG9ydCB7IFBobG94QXBwU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2UvUGhsb3hBcHBTZXJ2aWNlLnNlcnZpY2UnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZU1hbmFnZXIgfSBmcm9tICcuLi9zZXJ2aWNlL09ic2VydmFibGVNYW5hZ2VyLnNlcnZpY2UnO1xuaW1wb3J0IHsgTmVlZEZvY3VzU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2UvTmVlZEZvY3VzU2VydmljZS5zZXJ2aWNlJztcbmltcG9ydCB7IERpYWxvZ1NlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlL0RpYWxvZ1NlcnZpY2Uuc2VydmljZSc7XG5pbXBvcnQgeyBCYWNrZ3JvdW5kUHJvY2Vzc01hbmFnZXIgfSBmcm9tICcuLi9zZXJ2aWNlL0JhY2tncm91bmRQcm9jZXNzTWFuYWdlci5zZXJ2aWNlJztcbmltcG9ydCB7IElOYXZpZ2F0b3IgfSBmcm9tICcuL0lOYXZpZ2F0b3InO1xuaW1wb3J0IHsgSU5lZWRGb2N1cyB9IGZyb20gJy4vSU5lZWRGb2N1cyc7XG5pbXBvcnQgeyBBYnN0cmFjdFBhZ2UgfSBmcm9tICcuL0Fic3RyYWN0UGFnZSc7XG5pbXBvcnQgeyBBYnN0cmFjdE5hdkxlZnRMYXlvdXQgfSBmcm9tICcuL0Fic3RyYWN0TmF2TGVmdExheW91dCc7XG5pbXBvcnQgeyBNYXRlcmlhbEJhckxvYWRlciB9IGZyb20gJy4uL3RoZW1lL21hdGVyaWFsL2NvbXBvbmVudC9NYXRlcmlhbEJhckxvYWRlci5jb21wb25lbnQnO1xuXG5jb25zdCBUWVBFX05BTUU6IHN0cmluZyA9IFwicGh4LWFwcFwiO1xuXG4vKipcbiAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDJlbTtcIj5cbiAqIEEgbWFpbiBib290c3RyYXAgY29tcG9uZW50IGNsYXNzIGZvciA8Y29kZT5QaGxveFVJPC9jb2RlPiBhcHBsaWNhdGlvbi4gVGhpcyBjbGFzcyBpbXBsZW1lbnRzIHRoZSBbW0lOYXZpZ2F0b3JdXSBpbnRlcmZhY2UgaGF2aW5nIHBhZ2VzIChbW0Fic3RyYWN0UGFnZV1dKVxuICogYXMgPGNvZGU+bmF2aWdhdGVlPC9jb2RlPiBpdGVtcyAoW1tJTmF2aWdhdGVlXV0pLiBBbiA8Y29kZT5hcHBsaWNhdGlvbjwvY29kZT4gbWF5IGNvbnNpc3Qgb2YgdmFyaW91cyBwYWdlcywgZm9yIGV4YW1wbGUsIGl0IG1heSBoYXZlIGEgbG9naW4gcGFnZSB0byBhbGxvdyB0aGUgdXNlciB0b1xuICogbG9naW4sIG9uY2UgdGhlIHVzZXIgaXMgbG9nZ2VkIG9uLCBpdCB3aWxsIG5hdmlnYXRlIHRoZSB1c2VyIHRvIHRoZSBtYWluIHBhZ2UsIGV0Yy5cbiAqIDwvcD5cbiAqXG4gKiBAYXV0aG9yIHNoaW9yaW4sIHRlZTRjdXRlXG4gKi9cbkBDb21wb25lbnQoe1xuICBtb2R1bGVJZDogbW9kdWxlLmlkLFxuICBzZWxlY3RvcjogJ3BoeC1hcHAnLFxuICB0ZW1wbGF0ZTogYDxkaXYgY2xhc3M9XCJwaGxveC1hcHAtYmFyLWNvbnRhaW5lclwiIFtjbGFzcy5zaG93XT1cImlzU2hvd0xvYWRlcigpXCI+XG4gIDxtYXRlcmlhbC1iYXItbG9hZGVyICNiYXJsb2FkZXI+PC9tYXRlcmlhbC1iYXItbG9hZGVyPlxuPC9kaXY+XG48cm91dGVyLW91dGxldD48L3JvdXRlci1vdXRsZXQ+XG48cGh4LWRpYWxvZyAjZGlhbG9nPjwvcGh4LWRpYWxvZz5cbmBcbn0pXG5leHBvcnQgY2xhc3MgUGhsb3hBcHAgaW1wbGVtZW50cyBJTmF2aWdhdG9yPEFic3RyYWN0UGFnZT4sIE9uSW5pdCB7XG5cbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBUWVBFX05BTUU6IHN0cmluZyA9IFRZUEVfTkFNRTtcblxuICAvKipcbiAgICogVGhpcyBmaWVsZCB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgaW5qZWN0ZWQgYnkgPGNvZGU+bmc8L2NvZGU+LlxuICAgKi9cbiAgcHJpdmF0ZSBhcHBJbmZvU2VydmljZTogUGhsb3hBcHBJbmZvU2VydmljZTtcbiAgLyoqXG4gICAqIFRoaXMgZmllbGQgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGluamVjdGVkIGJ5IDxjb2RlPm5nPC9jb2RlPi5cbiAgICovXG4gIHByaXZhdGUgb2JzZXJ2YWJsZU1ncjogT2JzZXJ2YWJsZU1hbmFnZXI7XG4gIC8qKlxuICAgKiBUaGlzIGZpZWxkIHdpbGwgYmUgYXV0b21hdGljYWxseSBpbmplY3RlZCBieSA8Y29kZT5uZzwvY29kZT4uXG4gICAqL1xuICBwcml2YXRlIG5lZWRGb2N1c1NlcnZpY2U6IE5lZWRGb2N1c1NlcnZpY2U7XG4gIC8qKlxuICAgKiBBIGZpZWxkIGtlZXBpbmcgY2FjaGUgZm9yIHRoZSBsYXN0IHN1Y2Nlc3NmdWxseSBsb2FkZWQgW1tQaGxveEFwcEluZm9dXSBmcm9tIG1ldGhvZCBbW3JlbG9hZEFwcEluZm9dXS5cbiAgICovXG4gIHByaXZhdGUgYXBwSW5mbzogUGhsb3hBcHBJbmZvO1xuICAvKipcbiAgICogQW4gYXJyYXkga2VlcGluZyBhbGwgPGNvZGU+cGFnZTwvY29kZT5zIG9mIHRoaXMgPGNvZGU+YXBwbGljYXRpb248L2NvZGU+LlxuICAgKi9cbiAgcHJpdmF0ZSBwYWdlczogQWJzdHJhY3RQYWdlW107XG4gIC8qKlxuICAgKiBUaGlzIGZpZWxkIHdpbGwgYmUgYXV0b21hdGljYWxseSBpbmplY3RlZCBieSA8Y29kZT5uZzwvY29kZT4uXG4gICAqL1xuICBwcml2YXRlIHJvdXRlcjogUm91dGVyO1xuICAvKipcbiAgICogVGhpcyBmaWVsZCB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgaW5qZWN0ZWQgYnkgPGNvZGU+bmc8L2NvZGU+LlxuICAgKi9cbiAgcHJpdmF0ZSBkaWFsb2dTZXJ2aWNlOiBEaWFsb2dTZXJ2aWNlO1xuICAvKipcbiAgICogVGhpcyBmaWVsZCB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgaW5qZWN0ZWQgYnkgPGNvZGU+bmc8L2NvZGU+LlxuICAgKi9cbiAgcHJpdmF0ZSBiZ1Byb2Nlc3NNZ3I6IEJhY2tncm91bmRQcm9jZXNzTWFuYWdlcjtcbiAgLyoqXG4gICAqIEEgW1tQaGxveERpYWxvZ11dIGNoaWxkIGNvbXBvbmVudCBpbnN0YW5jZSBvZiB0aGlzIGNvbXBvbmVudC5cbiAgICovXG4gIEBWaWV3Q2hpbGQoJ2RpYWxvZycpXG4gIHByaXZhdGUgcGhsb3hEaWFsb2c6IGFueTtcbiAgQFZpZXdDaGlsZChcImJhcmxvYWRlclwiKVxuICBwcml2YXRlIGJhcmxvYWRlcjogTWF0ZXJpYWxCYXJMb2FkZXI7XG4gIHByaXZhdGUgX3Nob3dMb2FkZXI6IGJvb2xlYW47XG4gIHByaXZhdGUgY3VyUm91dGVyTG9hZGluZzogYW55ID0ge1xuICAgIFwicGF0aFwiOiBudWxsLFxuICAgIFwicmVzb2x2ZVwiOiBudWxsLFxuICAgIFwicmVqZWN0XCI6IG51bGxcbiAgfTtcblxuICBjb25zdHJ1Y3Rvcihyb3V0ZXI6IFJvdXRlciwgYXBwSW5mb1NlcnZpY2U6IFBobG94QXBwSW5mb1NlcnZpY2UsIGFwcFN2YzogUGhsb3hBcHBTZXJ2aWNlLCBvYnNlcnZhYmxlTWdyOiBPYnNlcnZhYmxlTWFuYWdlciwgbmVlZEZvY3VzU2VydmljZTogTmVlZEZvY3VzU2VydmljZSxcbiAgICBkaWFsb2dTZXJ2aWNlOiBEaWFsb2dTZXJ2aWNlLCBiZ1Byb2Nlc3NNZ3I6IEJhY2tncm91bmRQcm9jZXNzTWFuYWdlcikge1xuICAgIHRoaXMucGFnZXMgPSBbXTtcbiAgICB0aGlzLnJvdXRlciA9IHJvdXRlcjtcbiAgICB0aGlzLmFwcEluZm9TZXJ2aWNlID0gYXBwSW5mb1NlcnZpY2U7XG4gICAgdGhpcy5vYnNlcnZhYmxlTWdyID0gb2JzZXJ2YWJsZU1ncjtcbiAgICB0aGlzLm5lZWRGb2N1c1NlcnZpY2UgPSBuZWVkRm9jdXNTZXJ2aWNlO1xuICAgIHRoaXMucmVsb2FkQXBwSW5mbygpO1xuICAgIHRoaXMuZGlhbG9nU2VydmljZSA9IGRpYWxvZ1NlcnZpY2U7XG4gICAgdGhpcy5iZ1Byb2Nlc3NNZ3IgPSBiZ1Byb2Nlc3NNZ3I7XG4gICAgdGhpcy5fc2hvd0xvYWRlciA9IGZhbHNlO1xuXG4gICAgLy8gU2V0IGFwcCBpbnN0YW5jZSB0byBQaGxveEFwcFNlcnZpY2UgdG8gYWxsb3cgb3RoZXJzIHRvIGFjY2VzcyB0aGlzIGluc3RhbmNlLlxuICAgIGFwcFN2Yy5zZXRJbnN0YW5jZSh0aGlzKTtcblxuICAgIC8vIGluaXQgZGlhbG9nIHNlcnZpY2VcbiAgICB0aGlzLmRpYWxvZ1NlcnZpY2UuaW5pdCh0aGlzKTtcblxuICAgIHRoaXMub2JzZXJ2YWJsZU1nci5zdWJzY3JpYmUoQmFja2dyb3VuZFByb2Nlc3NNYW5hZ2VyLlBST0NFU1NfU1RBUlRfVE9QSUNfTkFNRSwgKHN0YXJ0QkdQcm9jZXNzOiBhbnkpID0+IHtcbiAgICAgIGlmIChzdGFydEJHUHJvY2Vzcy50eXBlID09PSAnY29ubmVjdGlvbi5wYWdlJykge1xuICAgICAgICB0aGlzLnJ1blBhZ2VMb2FkZXIoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLm9ic2VydmFibGVNZ3Iuc3Vic2NyaWJlKEJhY2tncm91bmRQcm9jZXNzTWFuYWdlci5QUk9DRVNTX0VORF9UT1BJQ19OQU1FLCAoZW5kQkdQcm9jZXNzOiBhbnkpID0+IHtcbiAgICAgIGlmIChlbmRCR1Byb2Nlc3MudHlwZSA9PT0gJ2Nvbm5lY3Rpb24ucGFnZScpIHtcbiAgICAgICAgaWYgKHRoaXMuYmdQcm9jZXNzTWdyLmdldFJ1bm5pbmdQcm9jZXNzZXNDb3VudCgnY29ubmVjdGlvbi5wYWdlJywgbnVsbCkgPD0gMCkge1xuICAgICAgICAgIHRoaXMuc3RvcFBhZ2VMb2FkZXIoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMub2JzZXJ2YWJsZU1nci5zdWJzY3JpYmUoQmFja2dyb3VuZFByb2Nlc3NNYW5hZ2VyLlBST0NFU1NfRVJST1JfVE9QSUNfTkFNRSwgKGVycm9yQkdQcm9jZXNzOiBhbnkpID0+IHtcbiAgICAgIGlmIChlcnJvckJHUHJvY2Vzcy50eXBlID09PSAnY29ubmVjdGlvbi5wYWdlJykge1xuICAgICAgICBpZiAodGhpcy5iZ1Byb2Nlc3NNZ3IuZ2V0UnVubmluZ1Byb2Nlc3Nlc0NvdW50KCdjb25uZWN0aW9uLnBhZ2UnLCBudWxsKSA8PSAwKSB7XG4gICAgICAgICAgdGhpcy5zdG9wUGFnZUxvYWRlcigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5vYnNlcnZhYmxlTWdyLnN1YnNjcmliZShBYnN0cmFjdE5hdkxlZnRMYXlvdXQuRklYRURfQ0hBTkdFX1RPUElDX05BTUUsIChsYXlvdXQ6IGFueSkgPT4ge1xuICAgICAgY29uc29sZS5sb2coJ05hdiBsZWZ0IFwiJyArIGxheW91dC5nZXRTdWJUb3BpY05hbWUoKSArICdcIiBmaXhlZDogJyArIGxheW91dC5maXhlZCk7XG4gICAgfSk7XG4gICAgdGhpcy5vYnNlcnZhYmxlTWdyLnN1YnNjcmliZShBYnN0cmFjdE5hdkxlZnRMYXlvdXQuVE9HR0xFRF9DSEFOR0VfVE9QSUNfTkFNRSwgKGxheW91dDogYW55KSA9PiB7XG4gICAgICBjb25zb2xlLmxvZygnTmF2IGxlZnQgXCInICsgbGF5b3V0LmdldFN1YlRvcGljTmFtZSgpICsgJ1wiIHRvZ2dsZWQ6ICcgKyBsYXlvdXQudG9nZ2xlZCk7XG4gICAgfSk7XG5cbiAgICAvLyBmaXhlZD1mYWxzZSwgdG9nZ2xlZD10cnVlXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLm9ic2VydmFibGVNZ3IucHVibGlzaChBYnN0cmFjdE5hdkxlZnRMYXlvdXQuVE9HR0xFRF9DTURfVE9QSUNfTkFNRSwgdHJ1ZSk7XG4gICAgfSwgMTUwMCk7XG4gICAgLy8gZml4ZWQ9ZmFsc2UsIHRvZ2dsZWQ9ZmFsc2VcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMub2JzZXJ2YWJsZU1nci5wdWJsaXNoKEFic3RyYWN0TmF2TGVmdExheW91dC5UT0dHTEVEX0NNRF9UT1BJQ19OQU1FLCBmYWxzZSk7XG4gICAgfSwgMzAwMCk7XG4gICAgLy8gZml4ZWQ9dHJ1ZSwgdG9nZ2xlZD1mYWxzZVxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgdGhpcy5vYnNlcnZhYmxlTWdyLnB1Ymxpc2goQWJzdHJhY3ROYXZMZWZ0TGF5b3V0LkZJWEVEX0NNRF9UT1BJQ19OQU1FLCB0cnVlKTtcbiAgICB9LCAzNTAwKTtcbiAgICAvLyBmaXhlZD10cnVlLCB0b2dnbGVkPXRydWVcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMub2JzZXJ2YWJsZU1nci5wdWJsaXNoKEFic3RyYWN0TmF2TGVmdExheW91dC5UT0dHTEVEX0NNRF9UT1BJQ19OQU1FLCB0cnVlKTtcbiAgICB9LCA0NTAwKTtcbiAgICAvLyBmaXhlZD10cnVlLCB0b2dnbGVkPWZhbHNlXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLm9ic2VydmFibGVNZ3IucHVibGlzaChBYnN0cmFjdE5hdkxlZnRMYXlvdXQuVE9HR0xFRF9DTURfVE9QSUNfTkFNRSwgZmFsc2UpO1xuICAgIH0sIDYwMDApO1xuICAgIC8vIGZpeGVkPWZhbHNlLCB0b2dnbGVkPWZhbHNlXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLm9ic2VydmFibGVNZ3IucHVibGlzaChBYnN0cmFjdE5hdkxlZnRMYXlvdXQuRklYRURfQ01EX1RPUElDX05BTUUsIGZhbHNlKTtcbiAgICB9LCA2NTAwKTtcbiAgfVxuXG4gIHB1YmxpYyBpc1Nob3dMb2FkZXIoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX3Nob3dMb2FkZXI7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgYXBwIGluZm8gb2YgY3VycmVudGx5IG9wZW5lZCA8Y29kZT5hcHBsaWNhdGlvbjwvY29kZT4uXG4gICAqIDwvcD5cbiAgICovXG4gIHB1YmxpYyBnZXRBcHBJbmZvKCk6IFBobG94QXBwSW5mbyB7XG4gICAgcmV0dXJuIHRoaXMuYXBwSW5mbztcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFJlbG9hZCB0aGUgYXBwIGluZm8gZnJvbSA8Y29kZT5QaGxveEFwcEluZm9TZXJ2aWNlPC9jb2RlPi5cbiAgICogPC9wPlxuICAgKi9cbiAgcHVibGljIHJlbG9hZEFwcEluZm8oKTogUHJvbWlzZTxQaGxveEFwcEluZm8+IHtcbiAgICByZXR1cm4gdGhpcy5hcHBJbmZvU2VydmljZS5yZWxvYWQoKS50aGVuKChyZXN1bHQ6IFBobG94QXBwSW5mbykgPT4ge1xuICAgICAgdGhpcy5hcHBJbmZvID0gcmVzdWx0O1xuXG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMuYXBwSW5mbyk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgZ2V0Um91dGVyKCk6IFJvdXRlciB7XG4gICAgcmV0dXJuIHRoaXMucm91dGVyO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IGFsbCBhdmFpbGFibGUgPGNvZGU+cGFnZXM8L2NvZGU+IChbW0Fic3RyYWN0UGFnZV1dKSBpbiB0aGlzIDxjb2RlPmFwcGxpY2F0aW9uPC9jb2RlPi5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAc2VlIFtbSU5hdmlnYXRvci5nZXRJdGVtc11dXG4gICAqL1xuICBwdWJsaWMgZ2V0SXRlbXMoKTogQWJzdHJhY3RQYWdlW10ge1xuICAgIHJldHVybiB0aGlzLnBhZ2VzO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IGFsbCBhdmFpbGFibGUgPGNvZGU+cGFnZTwvY29kZT4gY291bnQgKFtbQWJzdHJhY3RQYWdlXV0pIGluIHRoaXMgPGNvZGU+YXBwbGljYXRpb248L2NvZGU+LlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBzZWUgW1tJTmF2aWdhdG9yLmdldEl0ZW1Db3VudF1dXG4gICAqL1xuICBwdWJsaWMgZ2V0SXRlbUNvdW50KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucGFnZXMubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogR2V0IGN1cnJlbnQgYWN0aXZlIDxjb2RlPnBhZ2U8L2NvZGU+IChbW0Fic3RyYWN0UGFnZV1dKSBpbmRleCBpbiB0aGUgYXJyYXkgcmV0dXJuZWQgZnJvbSBbW2dldEl0ZW1zXV0gbWV0aG9kLlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBzZWUgW1tJTmF2aWdhdG9yLmdldEFjdGl2ZUluZGV4XV1cbiAgICogQHJldHVybnMgUmV0dXJucyA8Y29kZT4tMTwvY29kZT4gaWYgdGhlcmUgaXMgbm8gY3VycmVudCBhY3RpdmUgPGNvZGU+cGFnZTwvY29kZT4uXG4gICAqL1xuICBwdWJsaWMgZ2V0QWN0aXZlSW5kZXgoKTogbnVtYmVyIHtcbiAgICBmb3IgKGxldCBpOiBudW1iZXIgPSAwOyBpIDwgdGhpcy5wYWdlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHRoaXMucGFnZXNbaV0uaXNBY3RpdmUoKSkge1xuICAgICAgICByZXR1cm4gaTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gLTE7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBHZXQgY3VycmVudCBhY3RpdmUgPGNvZGU+cGFnZTwvY29kZT4gKFtbQWJzdHJhY3RQYWdlXV0pIG9iamVjdCBpbnN0YW5jZS5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAc2VlIFtbSU5hdmlnYXRvci5nZXRBY3RpdmVJdGVtXV1cbiAgICogQHJldHVybnMgUmV0dXJucyA8Y29kZT5udWxsPC9jb2RlPiBpZiB0aGVyZSBpcyBubyBjdXJyZW50IGFjdGl2ZSA8Y29kZT5wYWdlPC9jb2RlPi5cbiAgICovXG4gIHB1YmxpYyBnZXRBY3RpdmVJdGVtKCk6IEFic3RyYWN0UGFnZSB7XG4gICAgbGV0IGlkeDogbnVtYmVyID0gdGhpcy5nZXRBY3RpdmVJbmRleCgpO1xuXG4gICAgaWYgKGlkeCA8IDApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnBhZ2VzW2lkeF07XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBBbiBpbXBsZW1lbnRhdGlvbiBvZiBbW0lOYXZpZ2F0b3Iuc2V0SXRlbXNdXSBtZXRob2QuIFBsZWFzZSBzZWUgdGhlIGRvY3VtZW50YXRpb24gb2Ygc3VwZXIgY2xhc3Mgb3Igc3VwZXIgaW50ZXJmYWNlIGZvciBtb3JlIGRldGFpbHMuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHNlZSBbW0lOYXZpZ2F0b3Iuc2V0SXRlbXNdXVxuICAgKi9cbiAgcHVibGljIHNldEl0ZW1zKGl0ZW1zOiBBYnN0cmFjdFBhZ2VbXSk6IHZvaWQge1xuICAgIHRoaXMucGFnZXMgPSBpdGVtcztcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEFkZCBhIG5ldyA8Y29kZT5wYWdlPC9jb2RlPiAoW1tBYnN0cmFjdFBhZ2VdXSkgaW50byB0aGlzIDxjb2RlPmFwcGxpY2F0aW9uPC9jb2RlPi4gSWYgdGhlIDxjb2RlPnBhZ2U8L2NvZGU+ICg8Y29kZT48Yj5pdGVtPC9iPjwvY29kZT4pIGJlaW5nIGFkZGVkIGlzIHRoZVxuICAgKiBmaXJzdCA8Y29kZT5wYWdlPC9jb2RlPiBvZiB0aGlzIDxjb2RlPmFwcGxpY2F0aW9uPC9jb2RlPiwgdGhpcyBtZXRob2Qgd2lsbCBhdXRvbWF0aWNhbGx5IHNob3cgdGhlIGdpdmVuIDxjb2RlPnBhZ2U8L2NvZGU+IGFuZCBzZXQgaXRzIDxjb2RlPmFjdGl2ZTwvY29kZT5cbiAgICogZmxhZyB0byA8Y29kZT50cnVlPC9jb2RlPi5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAc2VlIFtbSU5hdmlnYXRvci5hZGRJdGVtXV1cbiAgICovXG4gIHB1YmxpYyBhZGRJdGVtKGl0ZW06IEFic3RyYWN0UGFnZSk6IGJvb2xlYW4ge1xuICAgIGlmICh0aGlzLmNvbnRhaW5zSXRlbShpdGVtKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMucGFnZXMucHVzaChpdGVtKTtcblxuICAgIGlmICh0aGlzLnBhZ2VzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgLy8gVGhpcyBpcyB0aGUgZmlyc3Qgb25lLiBTbywgaXQgc2hvdWxkIGJlIGFjdGl2ZSFcbiAgICAgIGl0ZW0uYWN0aXZlID0gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFJlbW92ZSB0aGUgZ2l2ZW4gPGNvZGU+cGFnZTwvY29kZT4gKFtbQWJzdHJhY3RQYWdlXV0pIGZyb20gdGhpcyA8Y29kZT5hcHBsaWNhdGlvbjwvY29kZT4uIElmIHRoZSA8Y29kZT5wYWdlPC9jb2RlPiAoPGNvZGU+PGI+aXRlbTwvYj48L2NvZGU+KSBiZWluZyByZW1vdmVkIGlzXG4gICAqIGN1cnJlbnRseSBhY3RpdmUsIHRoaXMgbWV0aG9kIHdpbGwgYXV0b21hdGljYWxseSB1bnNldCBpdHMgPGNvZGU+YWN0aXZlPC9jb2RlPiBmbGFnIGFuZCBzaG93IHRoZSBmaXJzdCA8Y29kZT5wYWdlPC9jb2RlPiAoaWYgYXZhaWxhYmxlKSBpbiB0aGUgYXJyYXkgcmV0dXJuZWQgZnJvbVxuICAgKiBbW2dldEl0ZW1zXV0gbWV0aG9kIGluc3RlYWQuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHNlZSBbW0lOYXZpZ2F0b3IucmVtb3ZlSXRlbV1dXG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlSXRlbShpdGVtOiBBYnN0cmFjdFBhZ2UpOiBib29sZWFuIHtcbiAgICBsZXQgaWR4OiBudW1iZXIgPSB0aGlzLnBhZ2VzLmluZGV4T2YoaXRlbSk7XG5cbiAgICBpZiAoaWR4IDwgMCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMucGFnZXMgPSB0aGlzLnBhZ2VzLnNsaWNlKGlkeCwgMSk7XG5cbiAgICBpZiAoaXRlbS5hY3RpdmUpIHtcbiAgICAgIC8vIFNldCBwYWdlIGFjdGl2ZSB0byBmYWxzZS5cbiAgICAgIGl0ZW0uYWN0aXZlID0gZmFsc2U7XG5cbiAgICAgIC8vIElmIGl0IGlzIGN1cnJlbnRseSBhY3RpdmUgcGFnZSwgd2UndmUgdG8gbmF2aWdhdGUgdG8gYW5vdGhlciBvbmUuXG4gICAgICB0aGlzLm5hdmlnYXRlVG9JbmRleCgwKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEFuIGltcGxlbWVudGF0aW9uIG9mIFtbSU5hdmlnYXRvci5jb250YWluc0l0ZW1dXSBtZXRob2QuIFBsZWFzZSBzZWUgdGhlIGRvY3VtZW50YXRpb24gb2Ygc3VwZXIgY2xhc3Mgb3Igc3VwZXIgaW50ZXJmYWNlIGZvciBtb3JlIGRldGFpbHMuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHNlZSBbW0lOYXZpZ2F0b3IuY29udGFpbnNJdGVtXV1cbiAgICovXG4gIHB1YmxpYyBjb250YWluc0l0ZW0oaXRlbTogQWJzdHJhY3RQYWdlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucGFnZXMuaW5kZXhPZihpdGVtKSA+PSAwO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogQW4gaW1wbGVtZW50YXRpb24gb2YgW1tJTmF2aWdhdG9yLmdldEl0ZW1CeUluZGV4XV0gbWV0aG9kLiBQbGVhc2Ugc2VlIHRoZSBkb2N1bWVudGF0aW9uIG9mIHN1cGVyIGNsYXNzIG9yIHN1cGVyIGludGVyZmFjZSBmb3IgbW9yZSBkZXRhaWxzLlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBzZWUgW1tJTmF2aWdhdG9yLmdldEl0ZW1CeUluZGV4XV1cbiAgICovXG4gIHB1YmxpYyBnZXRJdGVtQnlJbmRleChpZHg6IG51bWJlcik6IEFic3RyYWN0UGFnZSB7XG4gICAgaWYgKGlkeCA8IDAgfHwgaWR4ID49IHRoaXMucGFnZXMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5wYWdlc1tpZHhdO1xuICB9XG5cbiAgLyoqXG4gICAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDFlbTtcIj5cbiAgICogQW4gaW1wbGVtZW50YXRpb24gb2YgW1tJTmF2aWdhdG9yLmdldEl0ZW1CeU5hbWVdXSBtZXRob2QuIFBsZWFzZSBzZWUgdGhlIGRvY3VtZW50YXRpb24gb2Ygc3VwZXIgY2xhc3Mgb3Igc3VwZXIgaW50ZXJmYWNlIGZvciBtb3JlIGRldGFpbHMuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHNlZSBbW0lOYXZpZ2F0b3IuZ2V0SXRlbUJ5TmFtZV1dXG4gICAqL1xuICBwdWJsaWMgZ2V0SXRlbUJ5TmFtZShuYW1lOiBzdHJpbmcpO