com.phloxui
Version:
PhloxUI Ng2+ Framework
175 lines (174 loc) • 18.6 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { Injectable } from '@angular/core';
import { ObservableManager } from './ObservableManager.service';
const /** @type {?} */ FOCUS_TOPIC_NAME = 'needfocus.focus';
const /** @type {?} */ LOST_FOCUS_TOPIC_NAME = 'needfocus.lostfocus';
const /** @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]]
*/
export class NeedFocusService {
/**
* @param {?} obsvMgr
*/
constructor(obsvMgr) {
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, (component) => {
this.setFocusingComponent(component);
});
}
/**
* @param {?} component
* @return {?}
*/
getDataParent(component) {
if (component === null || typeof component === 'undefined') {
return null;
}
let /** @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 {?}
*/
getDataAncestorChain(component) {
let /** @type {?} */ ancestors = [];
if (component !== null && typeof component !== 'undefined') {
ancestors.push(component);
let /** @type {?} */ parent = this.getDataParent(component);
while (parent !== null && typeof parent !== 'undefined') {
ancestors.push(parent);
parent = this.getDataParent(parent);
}
}
return ancestors;
}
/**
* <p style="text-indent: 1em;">
* Get the component instance currently being focused.
* </p>
* @return {?}
*/
getFocusingComponent() {
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 {?}
*/
setFocusingComponent(component, event) {
if (this.focusingComponent === component) {
// The component is currently focused. Do nothing.
return;
}
let /** @type {?} */ losingFocusChain = this.getDataAncestorChain(this.focusingComponent);
let /** @type {?} */ focusingChain = this.getDataAncestorChain(component);
// Chain losing focus to ancestors.
for (let /** @type {?} */ comp of losingFocusChain) {
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);
}
}
this.focusingComponent = component;
// Chain focusing to ancestors.
for (let /** @type {?} */ comp of focusingChain) {
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);
}
}
}
/**
* <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 {?}
*/
resetFocusingComponent(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 = () => [
{ type: ObservableManager, },
];
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTmVlZEZvY3VzU2VydmljZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vY29tLnBobG94dWkvIiwic291cmNlcyI6WyJsaWIvc2VydmljZS9OZWVkRm9jdXNTZXJ2aWNlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFJM0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFaEUsdUJBQU0sZ0JBQWdCLEdBQVcsaUJBQWlCLENBQUM7QUFDbkQsdUJBQU0scUJBQXFCLEdBQVcscUJBQXFCLENBQUM7QUFDNUQsdUJBQU0sb0JBQW9CLEdBQVcscUJBQXFCLENBQUM7Ozs7Ozs7Ozs7Ozs7QUFlM0QsTUFBTTs7OztJQVdKLFlBQVksT0FBMEI7UUFDcEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUM7O1FBRzdCLElBQUksQ0FBQyxZQUFZLEdBQUcsT0FBTyxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzdFLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDLGdCQUFnQixDQUFDLHFCQUFxQixDQUFDLENBQUM7O1FBR3RGLE9BQU8sQ0FBQyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsb0JBQW9CLEVBQUUsQ0FBQyxTQUFjLEVBQUUsRUFBRTtZQUMxRSxJQUFJLENBQUMsb0JBQW9CLENBQUMsU0FBUyxDQUFDLENBQUM7U0FDdEMsQ0FBQyxDQUFDO0tBQ0o7Ozs7O0lBRU8sYUFBYSxDQUFDLFNBQWM7UUFDbEMsRUFBRSxDQUFDLENBQUMsU0FBUyxLQUFLLElBQUksSUFBSSxPQUFPLFNBQVMsS0FBSyxXQUFXLENBQUMsQ0FBQyxDQUFDO1lBQzNELE1BQU0sQ0FBQyxJQUFJLENBQUM7U0FDYjtRQUVELHFCQUFJLE1BQU0sR0FBUSxJQUFJLENBQUM7O1FBR3ZCLEVBQUUsQ0FB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Q0FDWCxxQkFBcUI7d0NBQ3RCLG9CQUFvQjs7WUFMM0UsVUFBVTs7OztZQWxCRixpQkFBaUIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcy9TdWJqZWN0JztcblxuaW1wb3J0IHsgSU5lZWRGb2N1cyB9IGZyb20gJy4uL2NvbXBvbmVudC9JTmVlZEZvY3VzJztcbmltcG9ydCB7IE9ic2VydmFibGVNYW5hZ2VyIH0gZnJvbSAnLi9PYnNlcnZhYmxlTWFuYWdlci5zZXJ2aWNlJztcblxuY29uc3QgRk9DVVNfVE9QSUNfTkFNRTogc3RyaW5nID0gJ25lZWRmb2N1cy5mb2N1cyc7XG5jb25zdCBMT1NUX0ZPQ1VTX1RPUElDX05BTUU6IHN0cmluZyA9ICduZWVkZm9jdXMubG9zdGZvY3VzJztcbmNvbnN0IEZPQ1VTX0NNRF9UT1BJQ19OQU1FOiBzdHJpbmcgPSAnbmVlZGZvY3VzLmNtZC5mb2N1cyc7XG5cbi8qKlxuICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMmVtO1wiPlxuICogQSA8Y29kZT5uZzwvY29kZT4gc2VydmljZSBjbGFzcyBtYWlubHkgaGFuZGxlcyB0aGUgbG9naWMgb2YgVUkgY29tcG9uZW50IHVzZXIncyBmb2N1cy4gRm9yIGV4YW1wbGUsIGEgbm90aWZpY2F0aW9uIHBvcCB1cCB3aGljaCB3aWxsIGJlIGRpc2FwcGVyZWQgd2hlblxuICogYSB1c2VyIGNsaWNrcyBvbiBhbnl3aGVyZSBlbHNlIG91dCBvZiBpdHMgYXJlYSAtLW9yLCBzYXlpbmcgdGhhdCBsb3NpbmcgaXRzIGZvY3VzLiBBIG5vdGlmaWNhdGlvbiBwb3AgdXAgY29tcG9uZW50IGNsYXNzIG11c3QgaW1wbGVtZW50IHRoZSBbW0lOZWVkRm9jdXNdXVxuICogaW50ZXJmYWNlIGFuZCByZWdpc3RlciBpdHNlbGYgdG8gPGNvZGU+dGhpczwvY29kZT4gc2VydmljZSB2aWEgW1tzZXRGb2N1c2luZ0NvbXBvbmVudF1dIG1ldGhvZCB0byBvYnRhaW4gdGhlIHVzZXIncyBmb2N1cy4gVGhlbiwgaXQgbXVzdCBpbXBsZW1lbnQgdGhlXG4gKiBbW0lOZWVkRm9jdXMub25Mb3N0Rm9jdXNdXSBtZXRob2QgdG8gaGlkZSBpdHNlbGYgd2hlbiBsb3NpbmcgdGhlIGZvY3VzLiBUaGUgW1tOZWVkRm9jdXNTZXJ2aWNlXV0gd2lsbCBtYXJrIGEgY29tcG9uZW50IGxvc2luZyB0aGUgZm9jdXMgd2hlbiB0aGVcbiAqIFtbcmVzZXRGb2N1c2luZ0NvbXBvbmVudF1dIG1ldGhvZCBpcyBjYWxsZWQgb3IgYW5vdGhlciBbW0lOZWVkRm9jdXNdXSBjb21wb25lbnQgaXMgZ2V0dGluZyBmb2N1cyBpbnN0ZWFkLlxuICogPC9wPlxuICpcbiAqIEBhdXRob3Igc2hpb3JpbiwgdGVlNGN1dGVcbiAqIEBzZWUgW1tJTmVlZEZvY3VzXV1cbiAqL1xuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIE5lZWRGb2N1c1NlcnZpY2Uge1xuXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgRk9DVVNfVE9QSUNfTkFNRTogc3RyaW5nID0gRk9DVVNfVE9QSUNfTkFNRTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBMT1NUX0ZPQ1VTX1RPUElDX05BTUU6IHN0cmluZyA9IExPU1RfRk9DVVNfVE9QSUNfTkFNRTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBGT0NVU19DTURfVE9QSUNfTkFNRTogc3RyaW5nID0gRk9DVVNfQ01EX1RPUElDX05BTUU7XG5cbiAgcHJpdmF0ZSBvYnNlcnZhYmxlTWdyOiBPYnNlcnZhYmxlTWFuYWdlcjtcbiAgcHJpdmF0ZSBmb2N1c2luZ0NvbXBvbmVudDogSU5lZWRGb2N1cztcbiAgcHJpdmF0ZSBmb2N1c1N1YmplY3Q6IFN1YmplY3Q8YW55PjtcbiAgcHJpdmF0ZSBsb3N0Rm9jdXNTdWJqZWN0OiBTdWJqZWN0PGFueT47XG5cbiAgY29uc3RydWN0b3Iob2Jzdk1ncjogT2JzZXJ2YWJsZU1hbmFnZXIpIHtcbiAgICB0aGlzLm9ic2VydmFibGVNZ3IgPSBvYnN2TWdyO1xuXG4gICAgLy8gSW5pdCBPYnNlcnZlciB0b3BpY3NcbiAgICB0aGlzLmZvY3VzU3ViamVjdCA9IG9ic3ZNZ3IuY3JlYXRlU3ViamVjdChOZWVkRm9jdXNTZXJ2aWNlLkZPQ1VTX1RPUElDX05BTUUpO1xuICAgIHRoaXMubG9zdEZvY3VzU3ViamVjdCA9IG9ic3ZNZ3IuY3JlYXRlU3ViamVjdChOZWVkRm9jdXNTZXJ2aWNlLkxPU1RfRk9DVVNfVE9QSUNfTkFNRSk7XG5cbiAgICAvLyBTdWJzY3JpYmUgdG8gY21kIHRvcGljc1xuICAgIG9ic3ZNZ3Iuc3Vic2NyaWJlKE5lZWRGb2N1c1NlcnZpY2UuRk9DVVNfQ01EX1RPUElDX05BTUUsIChjb21wb25lbnQ6IGFueSkgPT4ge1xuICAgICAgdGhpcy5zZXRGb2N1c2luZ0NvbXBvbmVudChjb21wb25lbnQpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXREYXRhUGFyZW50KGNvbXBvbmVudDogYW55KTogYW55IHtcbiAgICBpZiAoY29tcG9uZW50ID09PSBudWxsIHx8IHR5cGVvZiBjb21wb25lbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBsZXQgcGFyZW50OiBhbnkgPSBudWxsO1xuXG4gICAgLy8gVHJ5IHRvIHJlc29sdmUgcGFyZW50IGZyb20gZ2V0RGF0YVBhcmVudCgpIG1ldGhvZC5cbiAgICBpZiAodHlwZW9mIGNvbXBvbmVudFsnZ2V0RGF0YVBhcmVudCddID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBwYXJlbnQgPSBjb21wb25lbnQuZ2V0RGF0YVBhcmVudCgpO1xuICAgIH1cblxuICAgIGlmIChwYXJlbnQgIT09IG51bGwgJiYgdHlwZW9mIHBhcmVudCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHJldHVybiBwYXJlbnQ7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIHJlc29sdmUgcGFyZW50IGZyb20gZmllbGQgXCJkYXRhUGFyZW50XCIuXG4gICAgcmV0dXJuIGNvbXBvbmVudFsnZGF0YVBhcmVudCddO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXREYXRhQW5jZXN0b3JDaGFpbihjb21wb25lbnQ6IGFueSk6IGFueVtdIHtcbiAgICBsZXQgYW5jZXN0b3JzOiBhbnlbXSA9IFtdO1xuXG4gICAgaWYgKGNvbXBvbmVudCAhPT0gbnVsbCAmJiB0eXBlb2YgY29tcG9uZW50ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgYW5jZXN0b3JzLnB1c2goY29tcG9uZW50KTtcblxuICAgICAgbGV0IHBhcmVudDogYW55ID0gdGhpcy5nZXREYXRhUGFyZW50KGNvbXBvbmVudCk7XG4gICAgICB3aGlsZSAocGFyZW50ICE9PSBudWxsICYmIHR5cGVvZiBwYXJlbnQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGFuY2VzdG9ycy5wdXNoKHBhcmVudCk7XG5cbiAgICAgICAgcGFyZW50ID0gdGhpcy5nZXREYXRhUGFyZW50KHBhcmVudCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGFuY2VzdG9ycztcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEdldCB0aGUgY29tcG9uZW50IGluc3RhbmNlIGN1cnJlbnRseSBiZWluZyBmb2N1c2VkLlxuICAgKiA8L3A+XG4gICAqL1xuICBwdWJsaWMgZ2V0Rm9jdXNpbmdDb21wb25lbnQoKTogSU5lZWRGb2N1cyB7XG4gICAgcmV0dXJuIHRoaXMuZm9jdXNpbmdDb21wb25lbnQ7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBTZXQgZm9jdXNpbmcgY29tcG9uZW50IHRvIHRoZSBnaXZlbiA8Y29kZT48Yj5jb21wb25lbnQ8L2I+PC9jb2RlPi4gSWYgdGhlcmUgaXMgY3VycmVudCBmb2N1c2luZyBjb21wb25lbnQsIHRoZSBbW05lZWRGb2N1c1NlcnZpY2VdXVxuICAgKiB3aWxsIGF1dG9tYXRpY2FsbHkgY2FsbCBbW0lOZWVkRm9jdXMub25Mb3N0Rm9jdXNdXSBjYWxsYmFjayBtZXRob2Qgb24gdGhlIGN1cnJlbnQgZm9jdXNpbmcgY29tcG9uZW50IGJlZm9yZSBzZXR0aW5nIGZvY3VzIHRvIGEgbmV3XG4gICAqIG9uZS5cbiAgICogPC9wPlxuICAgKlxuICAgKiBAcGFyYW0gY29tcG9uZW50IFRoZSBjb21wb25lbnQgdG8gc2V0IGZvY3VzIHRvLlxuICAgKiBAcGFyYW0gZXZlbnQgVGhlIHNvdXJjZSBVSSBldmVudCAtLWZvciBleGFtcGxlLCBjbGljayBldmVudHMsIGV0Yy4tLSBjYXVzaW5nIHRoaXMgPGNvZGU+PGI+Y29tcG9uZW50PC9iPjwvY29kZT4gdG8gYmUgZm9jdXNlZC5cbiAgICovXG4gIHB1YmxpYyBzZXRGb2N1c2luZ0NvbXBvbmVudChjb21wb25lbnQ6IElOZWVkRm9jdXMsIGV2ZW50PzogYW55KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZm9jdXNpbmdDb21wb25lbnQgPT09IGNvbXBvbmVudCkge1xuICAgICAgLy8gVGhlIGNvbXBvbmVudCBpcyBjdXJyZW50bHkgZm9jdXNlZC4gRG8gbm90aGluZy5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsZXQgbG9zaW5nRm9jdXNDaGFpbjogYW55W10gPSB0aGlzLmdldERhdGFBbmNlc3RvckNoYWluKHRoaXMuZm9jdXNpbmdDb21wb25lbnQpO1xuICAgIGxldCBmb2N1c2luZ0NoYWluOiBhbnlbXSA9IHRoaXMuZ2V0RGF0YUFuY2VzdG9yQ2hhaW4oY29tcG9uZW50KTtcblxuICAgIC8vIENoYWluIGxvc2luZyBmb2N1cyB0byBhbmNlc3RvcnMuXG4gICAgZm9yIChsZXQgY29tcCBvZiBsb3NpbmdGb2N1c0NoYWluKSB7XG4gICAgICBpZiAoZm9jdXNpbmdDaGFpbi5pbmRleE9mKGNvbXApID49IDApIHtcbiAgICAgICAgLy8gSWYgY3VycmVudCBsb3NpbmcgZm9jdXMgY2hhaW4gaXMgZm91bmQgaW4gZm9jdXNpbmcgY2hhaW4sXG4gICAgICAgIC8vIGJyZWFrIGl0IGhlcmUgKG5vdCB0byBjaGFpbiBhbnltb3JlKS5cbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlb2YgY29tcC5vbkxvc3RGb2N1cyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAvLyBDYWxsIG9uTG9zdEZvY3VzKCkgbWV0aG9kLlxuICAgICAgICBjb21wLm9uTG9zdEZvY3VzKGV2ZW50KTtcblxuICAgICAgICAvLyBQdWJsaXNoIGV2ZW50IHRvIG9ic2VydmFibGVNZ3JcbiAgICAgICAgdGhpcy5sb3N0Rm9jdXNTdWJqZWN0Lm5leHQoY29tcCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5mb2N1c2luZ0NvbXBvbmVudCA9IGNvbXBvbmVudDtcblxuICAgIC8vIENoYWluIGZvY3VzaW5nIHRvIGFuY2VzdG9ycy5cbiAgICBmb3IgKGxldCBjb21wIG9mIGZvY3VzaW5nQ2hhaW4pIHtcbiAgICAgIGlmIChsb3NpbmdGb2N1c0NoYWluLmluZGV4T2YoY29tcCkgPj0gMCkge1xuICAgICAgICAvLyBJZiBjdXJyZW50IGZvY3VzaW5nIGNoYWluIGlzIGZvdW5kIGluIGxvc2luZyBmb2N1cyBjaGFpbixcbiAgICAgICAgLy8gYnJlYWsgaXQgaGVyZSAobm90IHRvIGNoYWluIGFueW1vcmUpLlxuICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgaWYgKHR5cGVvZiBjb21wLm9uRm9jdXMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgLy8gQ2FsbCBvbkZvY3VzKCkgbWV0aG9kLlxuICAgICAgICBjb21wLm9uRm9jdXMoZXZlbnQpO1xuXG4gICAgICAgIC8vIFB1Ymxpc2ggZXZlbnQgdG8gb2JzZXJ2YWJsZU1nclxuICAgICAgICB0aGlzLmZvY3VzU3ViamVjdC5uZXh0KGNvbXApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFJlc2V0IHRoZSBmb2N1c2luZyBjb21wb25lbnQuIFRoaXMgbWV0aG9kIHdpbGwgYXV0b21hdGljYWxseSBjYWxsIFtbSU5lZWRGb2N1cy5vbkxvc3RGb2N1c11dIGNhbGxiYWNrIG1ldGhvZCBvbiB0aGUgY3VycmVudCBmb2N1c2luZyBjb21wb25lbnQuXG4gICAqIElmIHRoZXJlIGlzIG5vIGN1cnJlbnQgZm9jdXNpbmcgY29tcG9uZW50LCB0aGlzIG1ldGhvZCB3aWxsIGRvIG5vdGhpbmcuXG4gICAqIDwvcD5cbiAgICpcbiAgICogQHBhcmFtIGV2ZW50IFRoZSBzb3VyY2UgVUkgZXZlbnQgLS1mb3IgZXhhbXBsZSwgY2xpY2sgZXZlbnRzLCBldGMuLS0gY2F1c2luZyB0aGUgY29tcG9uZW50J3MgZm9jdXMgdG8gYmUgcmVzZXQuXG4gICAqL1xuICBwdWJsaWMgcmVzZXRGb2N1c2luZ0NvbXBvbmVudChldmVudD86IGFueSk6IHZvaWQge1xuICAgIHRoaXMuc2V0Rm9jdXNpbmdDb21wb25lbnQobnVsbCwgZXZlbnQpO1xuICB9XG5cbn1cbiJdfQ==