com.phloxui
Version:
PhloxUI Ng2+ Framework
231 lines (230 loc) • 21.6 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import * as tslib_1 from "tslib";
import { Injectable } from '@angular/core';
import { ObservableManager } from './ObservableManager.service';
var /** @type {?} */ FOCUS_TOPIC_NAME = 'needfocus.focus';
var /** @type {?} */ LOST_FOCUS_TOPIC_NAME = 'needfocus.lostfocus';
var /** @type {?} */ FOCUS_CMD_TOPIC_NAME = 'needfocus.cmd.focus';
/**
* <p style="text-indent: 2em;">
* A <code>ng</code> service class mainly handles the logic of UI component user's focus. For example, a notification pop up which will be disappered when
* a user clicks on anywhere else out of its area --or, saying that losing its focus. A notification pop up component class must implement the [[INeedFocus]]
* interface and register itself to <code>this</code> service via [[setFocusingComponent]] method to obtain the user's focus. Then, it must implement the
* [[INeedFocus.onLostFocus]] method to hide itself when losing the focus. The [[NeedFocusService]] will mark a component losing the focus when the
* [[resetFocusingComponent]] method is called or another [[INeedFocus]] component is getting focus instead.
* </p>
*
* @author shiorin, tee4cute
* @see [[INeedFocus]]
*/
var NeedFocusService = /** @class */ (function () {
function NeedFocusService(obsvMgr) {
var _this = this;
this.observableMgr = obsvMgr;
// Init Observer topics
this.focusSubject = obsvMgr.createSubject(NeedFocusService.FOCUS_TOPIC_NAME);
this.lostFocusSubject = obsvMgr.createSubject(NeedFocusService.LOST_FOCUS_TOPIC_NAME);
// Subscribe to cmd topics
obsvMgr.subscribe(NeedFocusService.FOCUS_CMD_TOPIC_NAME, function (component) {
_this.setFocusingComponent(component);
});
}
/**
* @param {?} component
* @return {?}
*/
NeedFocusService.prototype.getDataParent = /**
* @param {?} component
* @return {?}
*/
function (component) {
if (component === null || typeof component === 'undefined') {
return null;
}
var /** @type {?} */ parent = null;
// Try to resolve parent from getDataParent() method.
if (typeof component['getDataParent'] === 'function') {
parent = component.getDataParent();
}
if (parent !== null && typeof parent !== 'undefined') {
return parent;
}
// Try to resolve parent from field "dataParent".
return component['dataParent'];
};
/**
* @param {?} component
* @return {?}
*/
NeedFocusService.prototype.getDataAncestorChain = /**
* @param {?} component
* @return {?}
*/
function (component) {
var /** @type {?} */ ancestors = [];
if (component !== null && typeof component !== 'undefined') {
ancestors.push(component);
var /** @type {?} */ parent_1 = this.getDataParent(component);
while (parent_1 !== null && typeof parent_1 !== 'undefined') {
ancestors.push(parent_1);
parent_1 = this.getDataParent(parent_1);
}
}
return ancestors;
};
/**
* <p style="text-indent: 1em;">
* Get the component instance currently being focused.
* </p>
* @return {?}
*/
NeedFocusService.prototype.getFocusingComponent = /**
* <p style="text-indent: 1em;">
* Get the component instance currently being focused.
* </p>
* @return {?}
*/
function () {
return this.focusingComponent;
};
/**
* <p style="text-indent: 1em;">
* Set focusing component to the given <code><b>component</b></code>. If there is current focusing component, the [[NeedFocusService]]
* will automatically call [[INeedFocus.onLostFocus]] callback method on the current focusing component before setting focus to a new
* one.
* </p>
*
* @param {?} component The component to set focus to.
* @param {?=} event The source UI event --for example, click events, etc.-- causing this <code><b>component</b></code> to be focused.
* @return {?}
*/
NeedFocusService.prototype.setFocusingComponent = /**
* <p style="text-indent: 1em;">
* Set focusing component to the given <code><b>component</b></code>. If there is current focusing component, the [[NeedFocusService]]
* will automatically call [[INeedFocus.onLostFocus]] callback method on the current focusing component before setting focus to a new
* one.
* </p>
*
* @param {?} component The component to set focus to.
* @param {?=} event The source UI event --for example, click events, etc.-- causing this <code><b>component</b></code> to be focused.
* @return {?}
*/
function (component, event) {
if (this.focusingComponent === component) {
// The component is currently focused. Do nothing.
return;
}
var /** @type {?} */ losingFocusChain = this.getDataAncestorChain(this.focusingComponent);
var /** @type {?} */ focusingChain = this.getDataAncestorChain(component);
try {
// Chain losing focus to ancestors.
for (var losingFocusChain_1 = tslib_1.__values(losingFocusChain), losingFocusChain_1_1 = losingFocusChain_1.next(); !losingFocusChain_1_1.done; losingFocusChain_1_1 = losingFocusChain_1.next()) {
var comp = losingFocusChain_1_1.value;
if (focusingChain.indexOf(comp) >= 0) {
// If current losing focus chain is found in focusing chain,
// break it here (not to chain anymore).
break;
}
if (typeof comp.onLostFocus === 'function') {
// Call onLostFocus() method.
comp.onLostFocus(event);
// Publish event to observableMgr
this.lostFocusSubject.next(comp);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (losingFocusChain_1_1 && !losingFocusChain_1_1.done && (_a = losingFocusChain_1.return)) _a.call(losingFocusChain_1);
}
finally { if (e_1) throw e_1.error; }
}
this.focusingComponent = component;
try {
// Chain focusing to ancestors.
for (var focusingChain_1 = tslib_1.__values(focusingChain), focusingChain_1_1 = focusingChain_1.next(); !focusingChain_1_1.done; focusingChain_1_1 = focusingChain_1.next()) {
var comp = focusingChain_1_1.value;
if (losingFocusChain.indexOf(comp) >= 0) {
// If current focusing chain is found in losing focus chain,
// break it here (not to chain anymore).
break;
}
if (typeof comp.onFocus === 'function') {
// Call onFocus() method.
comp.onFocus(event);
// Publish event to observableMgr
this.focusSubject.next(comp);
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (focusingChain_1_1 && !focusingChain_1_1.done && (_b = focusingChain_1.return)) _b.call(focusingChain_1);
}
finally { if (e_2) throw e_2.error; }
}
var e_1, _a, e_2, _b;
};
/**
* <p style="text-indent: 1em;">
* Reset the focusing component. This method will automatically call [[INeedFocus.onLostFocus]] callback method on the current focusing component.
* If there is no current focusing component, this method will do nothing.
* </p>
*
* @param {?=} event The source UI event --for example, click events, etc.-- causing the component's focus to be reset.
* @return {?}
*/
NeedFocusService.prototype.resetFocusingComponent = /**
* <p style="text-indent: 1em;">
* Reset the focusing component. This method will automatically call [[INeedFocus.onLostFocus]] callback method on the current focusing component.
* If there is no current focusing component, this method will do nothing.
* </p>
*
* @param {?=} event The source UI event --for example, click events, etc.-- causing the component's focus to be reset.
* @return {?}
*/
function (event) {
this.setFocusingComponent(null, event);
};
NeedFocusService.FOCUS_TOPIC_NAME = FOCUS_TOPIC_NAME;
NeedFocusService.LOST_FOCUS_TOPIC_NAME = LOST_FOCUS_TOPIC_NAME;
NeedFocusService.FOCUS_CMD_TOPIC_NAME = FOCUS_CMD_TOPIC_NAME;
NeedFocusService.decorators = [
{ type: Injectable },
];
/** @nocollapse */
NeedFocusService.ctorParameters = function () { return [
{ type: ObservableManager, },
]; };
return NeedFocusService;
}());
export { NeedFocusService };
function NeedFocusService_tsickle_Closure_declarations() {
/** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */
NeedFocusService.decorators;
/**
* @nocollapse
* @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
*/
NeedFocusService.ctorParameters;
/** @type {?} */
NeedFocusService.FOCUS_TOPIC_NAME;
/** @type {?} */
NeedFocusService.LOST_FOCUS_TOPIC_NAME;
/** @type {?} */
NeedFocusService.FOCUS_CMD_TOPIC_NAME;
/** @type {?} */
NeedFocusService.prototype.observableMgr;
/** @type {?} */
NeedFocusService.prototype.focusingComponent;
/** @type {?} */
NeedFocusService.prototype.focusSubject;
/** @type {?} */
NeedFocusService.prototype.lostFocusSubject;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTmVlZEZvY3VzU2VydmljZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vY29tLnBobG94dWkvIiwic291cmNlcyI6WyJsaWIvc2VydmljZS9OZWVkRm9jdXNTZXJ2aWNlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBSTNDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRWhFLHFCQUFNLGdCQUFnQixHQUFXLGlCQUFpQixDQUFDO0FBQ25ELHFCQUFNLHFCQUFxQixHQUFXLHFCQUFxQixDQUFDO0FBQzVELHFCQUFNLG9CQUFvQixHQUFXLHFCQUFxQixDQUFDOzs7Ozs7Ozs7Ozs7OztJQTBCekQsMEJBQVksT0FBMEI7UUFBdEMsaUJBV0M7UUFWQyxJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQzs7UUFHN0IsSUFBSSxDQUFDLFlBQVksR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDLGdCQUFnQixDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDN0UsSUFBSSxDQUFDLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsZ0JBQWdCLENBQUMscUJBQXFCLENBQUMsQ0FBQzs7UUFHdEYsT0FBTyxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxvQkFBb0IsRUFBRSxVQUFDLFNBQWM7WUFDdEUsS0FBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1NBQ3RDLENBQUMsQ0FBQztLQUNKOzs7OztJQUVPLHdDQUFhOzs7O2NBQUMsU0FBYztRQUNsQyxFQUFFLENBQUMsQ0FBQyxTQUFTLEtBQUssSUFBSSxJQUFJLE9BQU8sU0FBUyxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUM7WUFDM0QsTUFBTSxDQUFDLElBQUksQ0FBQztTQUNiO1FBRUQscUJBQUksTUFBTSxHQUFRLElBQUksQ0FBQzs7UUFHdkIsRUFBRSxDQUFDLENB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Ozs7Ozs7Ozs7Ozs7SUFXSSxpREFBc0I7Ozs7Ozs7OztjQUFDLEtBQVc7UUFDdkMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQzs7d0NBcklTLGdCQUFnQjs2Q0FDWCxxQkFBcUI7NENBQ3RCLG9CQUFvQjs7Z0JBTDNFLFVBQVU7Ozs7Z0JBbEJGLGlCQUFpQjs7MkJBSjFCOztTQXVCYSxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcy9TdWJqZWN0JztcblxuaW1wb3J0IHsgSU5lZWRGb2N1cyB9IGZyb20gJy4uL2NvbXBvbmVudC9JTmVlZEZvY3VzJztcbmltcG9ydCB7IE9ic2VydmFibGVNYW5hZ2VyIH0gZnJvbSAnLi9PYnNlcnZhYmxlTWFuYWdlci5zZXJ2aWNlJztcblxuY29uc3QgRk9DVVNfVE9QSUNfTkFNRTogc3RyaW5nID0gJ25lZWRmb2N1cy5mb2N1cyc7XG5jb25zdCBMT1NUX0ZPQ1VTX1RPUElDX05BTUU6IHN0cmluZyA9ICduZWVkZm9jdXMubG9zdGZvY3VzJztcbmNvbnN0IEZPQ1VTX0NNRF9UT1BJQ19OQU1FOiBzdHJpbmcgPSAnbmVlZGZvY3VzLmNtZC5mb2N1cyc7XG5cbi8qKlxuICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMmVtO1wiPlxuICogQSA8Y29kZT5uZzwvY29kZT4gc2VydmljZSBjbGFzcyBtYWlubHkgaGFuZGxlcyB0aGUgbG9naWMgb2YgVUkgY29tcG9uZW50IHVzZXIncyBmb2N1cy4gRm9yIGV4YW1wbGUsIGEgbm90aWZpY2F0aW9uIHBvcCB1cCB3aGljaCB3aWxsIGJlIGRpc2FwcGVyZWQgd2hlblxuICogYSB1c2VyIGNsaWNrcyBvbiBhbnl3aGVyZSBlbHNlIG91dCBvZiBpdHMgYXJlYSAtLW9yLCBzYXlpbmcgdGhhdCBsb3NpbmcgaXRzIGZvY3VzLiBBIG5vdGlmaWNhdGlvbiBwb3AgdXAgY29tcG9uZW50IGNsYXNzIG11c3QgaW1wbGVtZW50IHRoZSBbW0lOZWVkRm9jdXNdXVxuICogaW50ZXJmYWNlIGFuZCByZWdpc3RlciBpdHNlbGYgdG8gPGNvZGU+dGhpczwvY29kZT4gc2VydmljZSB2aWEgW1tzZXRGb2N1c2luZ0NvbXBvbmVudF1dIG1ldGhvZCB0byBvYnRhaW4gdGhlIHVzZXIncyBmb2N1cy4gVGhlbiwgaXQgbXVzdCBpbXBsZW1lbnQgdGhlXG4gKiBbW0lOZWVkRm9jdXMub25Mb3N0Rm9jdXNdXSBtZXRob2QgdG8gaGlkZSBpdHNlbGYgd2hlbiBsb3NpbmcgdGhlIGZvY3VzLiBUaGUgW1tOZWVkRm9jdXNTZXJ2aWNlXV0gd2lsbCBtYXJrIGEgY29tcG9uZW50IGxvc2luZyB0aGUgZm9jdXMgd2hlbiB0aGVcbiAqIFtbcmVzZXRGb2N1c2luZ0NvbXBvbmVudF1dIG1ldGhvZCBpcyBjYWxsZWQgb3IgYW5vdGhlciBbW0lOZWVkRm9jdXNdXSBjb21wb25lbnQgaXMgZ2V0dGluZyBmb2N1cyBpbnN0ZWFkLlxuICogPC9wPlxuICpcbiAqIEBhdXRob3Igc2hpb3JpbiwgdGVlNGN1dGVcbiAqIEBzZWUgW1tJTmVlZEZvY3VzXV1cbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIE5lZWRGb2N1c1NlcnZpY2Uge1xuXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgRk9DVVNfVE9QSUNfTkFNRTogc3RyaW5nID0gRk9DVVNfVE9QSUNfTkFNRTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBMT1NUX0ZPQ1VTX1RPUElDX05BTUU6IHN0cmluZyA9IExPU1RfRk9DVVNfVE9QSUNfTkFNRTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBGT0NVU19DTURfVE9QSUNfTkFNRTogc3RyaW5nID0gRk9DVVNfQ01EX1RPUElDX05BTUU7XG5cbiAgcHJpdmF0ZSBvYnNlcnZhYmxlTWdyOiBPYnNlcnZhYmxlTWFuYWdlcjtcbiAgcHJpdmF0ZSBmb2N1c2luZ0NvbXBvbmVudDogSU5lZWRGb2N1cztcbiAgcHJpdmF0ZSBmb2N1c1N1YmplY3Q6IFN1YmplY3Q8YW55PjtcbiAgcHJpdmF0ZSBsb3N0Rm9jdXNTdWJqZWN0OiBTdWJqZWN0PGFueT47XG5cbiAgY29uc3RydWN0b3Iob2Jzdk1ncjogT2JzZXJ2YWJsZU1hbmFnZXIpIHtcbiAgICB0aGlzLm9ic2VydmFibGVNZ3IgPSBvYnN2TWdyO1xuXG4gICAgLy8gSW5pdCBPYnNlcnZlciB0b3BpY3NcbiAgICB0aGlzLmZvY3VzU3ViamVjdCA9IG9ic3ZNZ3IuY3JlYXRlU3ViamVjdChOZWVkRm9jdXNTZXJ2aWNlLkZPQ1VTX1RPUElDX05BTUUpO1xuICAgIHRoaXMubG9zdEZvY3VzU3ViamVjdCA9IG9ic3ZNZ3IuY3JlYXRlU3ViamVjdChOZWVkRm9jdXNTZXJ2aWNlLkxPU1RfRk9DVVNfVE9QSUNfTkFNRSk7XG5cbiAgICAvLyBTdWJzY3JpYmUgdG8gY21kIHRvcGljc1xuICAgIG9ic3ZNZ3Iuc3Vic2NyaWJlKE5lZWRGb2N1c1NlcnZpY2UuRk9DVVNfQ01EX1RPUElDX05BTUUsIChjb21wb25lbnQ6IGFueSkgPT4ge1xuICAgICAgdGhpcy5zZXRGb2N1c2luZ0NvbXBvbmVudChjb21wb25lbnQpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXREYXRhUGFyZW50KGNvbXBvbmVudDogYW55KTogYW55IHtcbiAgICBpZiAoY29tcG9uZW50ID09PSBudWxsIHx8IHR5cGVvZiBjb21wb25lbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBsZXQgcGFyZW50OiBhbnkgPSBudWxsO1xuXG4gICAgLy8gVHJ5IHRvIHJlc29sdmUgcGFyZW50IGZyb20gZ2V0RGF0YVBhcmVudCgpIG1ldGhvZC5cbiAgICBpZiAodHlwZW9mIGNvbXBvbmVudFsnZ2V0RGF0YVBhcmVudCddID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBwYXJlbnQgPSBjb21wb25lbnQuZ2V0RGF0YVBhcmVudCgpO1xuICAgIH1cblxuICAgIGlmIChwYXJlbnQgIT09IG51bGwgJiYgdHlwZW9mIHBhcmVudCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHJldHVybiBwYXJlbnQ7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIHJlc29sdmUgcGFyZW50IGZyb20gZmllbGQgXCJkYXRhUGFyZW50XCIuXG4gICAgcmV0dXJuIGNvbXBvbmVudFsnZGF0YVBhcmVudCddO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXREYXRhQW5jZXN0b3JDaGFpbihjb21wb25lbnQ6IGFueSk6IGFueVtdIHtcbiAgICBsZXQgYW5jZXN0b3JzOiBhbnlbXSA9IFtdO1xuXG4gICAgaWYgKGNvbXBvbmVudCAhPT0gbnVsbCAmJiB0eXBlb2YgY29tcG9uZW50ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgYW5jZXN0b3JzLnB1c2goY29tcG9uZW50KTtcblxuICAgICAgbGV0IHBhcmVudDogYW55ID0gdGhpcy5nZXREYXRhUGFyZW50KGNvbXBvbmVudCk7XG4gICAgICB3aGlsZSAocGFyZW50ICE9PSBudWxsICYmIHR5cGVvZiBwYXJlbnQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGFuY2VzdG9ycy5wdXNoKHBhcmVudCk7XG5cbiAgICAgICAgcGFyZW50ID0gdGhpcy5nZXREYXRhUGFyZW50KHBhcmVudCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGFuY2VzdG9ycztcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCB0aGUgY29tcG9uZW50IGluc3RhbmNlIGN1cnJlbnRseSBiZWluZyBmb2N1c2VkLlxuICAgKiA8L3A+XG4gICAqL1xuICBwdWJsaWMgZ2V0Rm9jdXNpbmdDb21wb25lbnQoKTogSU5lZWRGb2N1cyB7XG4gICAgcmV0dXJuIHRoaXMuZm9jdXNpbmdDb21wb25lbnQ7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBTZXQgZm9jdXNpbmcgY29tcG9uZW50IHRvIHRoZSBnaXZlbiA8Y29kZT48Yj5jb21wb25lbnQ8L2I+PC9jb2RlPi4gSWYgdGhlcmUgaXMgY3VycmVudCBmb2N1c2luZyBjb21wb25lbnQsIHRoZSBbW05lZWRGb2N1c1NlcnZpY2VdXVxuICAgKiB3aWxsIGF1dG9tYXRpY2FsbHkgY2FsbCBbW0lOZWVkRm9jdXMub25Mb3N0Rm9jdXNdXSBjYWxsYmFjayBtZXRob2Qgb24gdGhlIGN1cnJlbnQgZm9jdXNpbmcgY29tcG9uZW50IGJlZm9yZSBzZXR0aW5nIGZvY3VzIHRvIGEgbmV3XG4gICAqIG9uZS5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gY29tcG9uZW50IFRoZSBjb21wb25lbnQgdG8gc2V0IGZvY3VzIHRvLlxuICAgKiBAcGFyYW0gZXZlbnQgVGhlIHNvdXJjZSBVSSBldmVudCAtLWZvciBleGFtcGxlLCBjbGljayBldmVudHMsIGV0Yy4tLSBjYXVzaW5nIHRoaXMgPGNvZGU+PGI+Y29tcG9uZW50PC9iPjwvY29kZT4gdG8gYmUgZm9jdXNlZC5cbiAgICovXG4gIHB1YmxpYyBzZXRGb2N1c2luZ0NvbXBvbmVudChjb21wb25lbnQ6IElOZWVkRm9jdXMsIGV2ZW50PzogYW55KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZm9jdXNpbmdDb21wb25lbnQgPT09IGNvbXBvbmVudCkge1xuICAgICAgLy8gVGhlIGNvbXBvbmVudCBpcyBjdXJyZW50bHkgZm9jdXNlZC4gRG8gbm90aGluZy5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsZXQgbG9zaW5nRm9jdXNDaGFpbjogYW55W10gPSB0aGlzLmdldERhdGFBbmNlc3RvckNoYWluKHRoaXMuZm9jdXNpbmdDb21wb25lbnQpO1xuICAgIGxldCBmb2N1c2luZ0NoYWluOiBhbnlbXSA9IHRoaXMuZ2V0RGF0YUFuY2VzdG9yQ2hhaW4oY29tcG9uZW50KTtcblxuICAgIC8vIENoYWluIGxvc2luZyBmb2N1cyB0byBhbmNlc3RvcnMuXG4gICAgZm9yIChsZXQgY29tcCBvZiBsb3NpbmdGb2N1c0NoYWluKSB7XG4gICAgICBpZiAoZm9jdXNpbmdDaGFpbi5pbmRleE9mKGNvbXApID49IDApIHtcbiAgICAgICAgLy8gSWYgY3VycmVudCBsb3NpbmcgZm9jdXMgY2hhaW4gaXMgZm91bmQgaW4gZm9jdXNpbmcgY2hhaW4sXG4gICAgICAgIC8vIGJyZWFrIGl0IGhlcmUgKG5vdCB0byBjaGFpbiBhbnltb3JlKS5cbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlb2YgY29tcC5vbkxvc3RGb2N1cyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAvLyBDYWxsIG9uTG9zdEZvY3VzKCkgbWV0aG9kLlxuICAgICAgICBjb21wLm9uTG9zdEZvY3VzKGV2ZW50KTtcblxuICAgICAgICAvLyBQdWJsaXNoIGV2ZW50IHRvIG9ic2VydmFibGVNZ3JcbiAgICAgICAgdGhpcy5sb3N0Rm9jdXNTdWJqZWN0Lm5leHQoY29tcCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5mb2N1c2luZ0NvbXBvbmVudCA9IGNvbXBvbmVudDtcblxuICAgIC8vIENoYWluIGZvY3VzaW5nIHRvIGFuY2VzdG9ycy5cbiAgICBmb3IgKGxldCBjb21wIG9mIGZvY3VzaW5nQ2hhaW4pIHtcbiAgICAgIGlmIChsb3NpbmdGb2N1c0NoYWluLmluZGV4T2YoY29tcCkgPj0gMCkge1xuICAgICAgICAvLyBJZiBjdXJyZW50IGZvY3VzaW5nIGNoYWluIGlzIGZvdW5kIGluIGxvc2luZyBmb2N1cyBjaGFpbixcbiAgICAgICAgLy8gYnJlYWsgaXQgaGVyZSAobm90IHRvIGNoYWluIGFueW1vcmUpLlxuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgaWYgKHR5cGVvZiBjb21wLm9uRm9jdXMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgLy8gQ2FsbCBvbkZvY3VzKCkgbWV0aG9kLlxuICAgICAgICBjb21wLm9uRm9jdXMoZXZlbnQpO1xuXG4gICAgICAgIC8vIFB1Ymxpc2ggZXZlbnQgdG8gb2JzZXJ2YWJsZU1nclxuICAgICAgICB0aGlzLmZvY3VzU3ViamVjdC5uZXh0KGNvbXApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFJlc2V0IHRoZSBmb2N1c2luZyBjb21wb25lbnQuIFRoaXMgbWV0aG9kIHdpbGwgYXV0b21hdGljYWxseSBjYWxsIFtbSU5lZWRGb2N1cy5vbkxvc3RGb2N1c11dIGNhbGxiYWNrIG1ldGhvZCBvbiB0aGUgY3VycmVudCBmb2N1c2luZyBjb21wb25lbnQuXG4gICAqIElmIHRoZXJlIGlzIG5vIGN1cnJlbnQgZm9jdXNpbmcgY29tcG9uZW50LCB0aGlzIG1ldGhvZCB3aWxsIGRvIG5vdGhpbmcuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIGV2ZW50IFRoZSBzb3VyY2UgVUkgZXZlbnQgLS1mb3IgZXhhbXBsZSwgY2xpY2sgZXZlbnRzLCBldGMuLS0gY2F1c2luZyB0aGUgY29tcG9uZW50J3MgZm9jdXMgdG8gYmUgcmVzZXQuXG4gICAqL1xuICBwdWJsaWMgcmVzZXRGb2N1c2luZ0NvbXBvbmVudChldmVudD86IGFueSk6IHZvaWQge1xuICAgIHRoaXMuc2V0Rm9jdXNpbmdDb21wb25lbnQobnVsbCwgZXZlbnQpO1xuICB9XG5cbn1cbiJdfQ==