com.phloxui
Version:
PhloxUI Ng2+ Framework
551 lines (550 loc) • 56.5 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { Component, ViewChild } from '@angular/core';
import { DialogModel, ConfirmDialogModel } from './model/models';
import { PhloxAppInfoService } from '../service/PhloxAppInfoService.service';
import { NeedFocusService } from '../service/NeedFocusService.service';
import { ConfirmDialog } from './dialog.internal/ConfirmDialog.component';
import { MessageDialog } from './dialog.internal/MessageDialog.component';
import { ComponentDialog } from './dialog.internal/ComponentDialog.component';
var /** @type {?} */ TYPE_NAME = "phx-dialog";
var /** @type {?} */ CONFIRM_DIALOG = 'confirm';
var /** @type {?} */ MESSAGE_DIALOG = 'message';
var /** @type {?} */ COMPONENT_DIALOG = 'component';
/**
* <p style="text-indent: 2em;">
* A <code>singleton</code> UI component controlling <code>application</code> pop-up dialog logic. This dialog is a <code>modal</code> dialog, saying that,
* when it is displayed, all user's UI actions will be blocked and the user will be forced to focus on this dialog. When the user completes the interaction
* with this dialog, for example, clicking on "OK" button, this dialog will be hidden and the user can resume normal UI operations. Normally, you <b>should
* NOT</b> directly access this component instance but you could control it via <b>[[DialogService]]</b>.
* </p>
* <p style="text-indent: 2em;">
* Please note that there is a dialog <code>display queue</code> operating behind the scenes. This <code>display queue</code> is a <code>FIFO</code> queue
* keeping all dialog models ([[DialogModel]]) --which are automatically generated and kept in the queue when <code><i>show...Dialog</i></code> methods are called--
* but those dialog models cannot be displayed suddenly. For example, if there already is a dialog being displayed currently, but, there is also someone else
* calling <code><i>show...Dialog</i></code> method simultaneously, the dialog model generated from the later <code><i>show...Dialog</i></code> method will
* not be showed suddenly. Nevertheless, it'll be showed immediately when the first dialog is closed. For this mechanism, the dialog model can be firstly kept
* in the queue, then, it will be showed and removed from the queue when its preceding dialog is closed.
* </p>
* <p style="text-indent: 2em;">
* If you want to implement your own <b>custom dialog</b>, you should do it using <code>component dialog</code> rather than building it all up from scratches. The only thing
* which you need to do is just implementing the component being displayed inside the dialog body. All other mechanisms, such as dialog <code>display queue</code>
* listed above, should be left to be handled by the framework or by this class. For more information about building custom dialog, please see [[showComponentDialog]].
* </p>
*
* @author shiorin, tee4cute
* @see [[DialogService]]
*/
var PhloxDialog = /** @class */ (function () {
function PhloxDialog(phloxAppService, needFocusService) {
var _this = this;
this.show = false;
this.dialogQueue = [];
this.dialogResolverQueue = [];
this.needFocusService = needFocusService;
if (phloxAppService != null) {
phloxAppService.getAppInfo().then(function (result) {
_this.phloxAppInfo = result;
});
}
if (window.history && window.history.pushState) {
$(window).on('popstate', function (event) {
_this.hideDialog();
});
}
}
Object.defineProperty(PhloxDialog.prototype, "show", {
get: /**
* @return {?}
*/
function () {
return this._show;
},
set: /**
* @param {?} show
* @return {?}
*/
function (show) {
this._show = show;
if (this._show) {
// if true add class to body
$("body").addClass("phx-dialog-fixed");
}
else {
// if false remove class from body
$("body").removeClass("phx-dialog-fixed");
}
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
PhloxDialog.prototype.showNextDialog = /**
* @return {?}
*/
function () {
this.currentModel = null;
if (this.dialogQueue.length > 0) {
this.currentModel = this.dialogQueue[0];
this.dialogQueue.splice(0, 1);
if (this.dialogResolverQueue.length > 0) {
this.currentResolver = this.dialogResolverQueue[0];
this.dialogResolverQueue.splice(0, 1);
}
if (this.currentModel !== null && typeof this.currentModel !== 'undefined') {
this.showDialog();
return true;
}
else {
this.currentResolver = null;
this.hideDialog();
return false;
}
}
return false;
};
/**
* @param {?} key
* @return {?}
*/
PhloxDialog.prototype.getI18NMessage = /**
* @param {?} key
* @return {?}
*/
function (key) {
if (this.phloxAppInfo != null && this.phloxAppInfo.i18n != null) {
if (this.phloxAppInfo.i18n[key] !== null && typeof this.phloxAppInfo.i18n[key] !== 'undefined') {
return this.phloxAppInfo.i18n[key];
}
}
return key;
};
/**
* @param {?} model
* @param {?} resolve
* @param {?} reject
* @return {?}
*/
PhloxDialog.prototype.getResolverWrapper = /**
* @param {?} model
* @param {?} resolve
* @param {?} reject
* @return {?}
*/
function (model, resolve, reject) {
var /** @type {?} */ result = {
model: model,
resolve: resolve,
reject: reject
};
return result;
};
/**
* @return {?}
*/
PhloxDialog.prototype.getDialogWidth = /**
* @return {?}
*/
function () {
if (this.currentModel !== null && typeof this.currentModel !== 'undefined') {
if (this.currentModel.width !== null && typeof this.currentModel.width === 'string') {
return this.currentModel.width;
}
}
return "";
};
/**
* @return {?}
*/
PhloxDialog.prototype.getDialogHeight = /**
* @return {?}
*/
function () {
if (this.currentModel !== null && typeof this.currentModel !== 'undefined') {
if (this.currentModel.height !== null && typeof this.currentModel.height === 'string') {
return this.currentModel.height;
}
}
return "";
};
/**
* @param {?} dialogType
* @return {?}
*/
PhloxDialog.prototype.getDialogResult = /**
* @param {?} dialogType
* @return {?}
*/
function (dialogType) {
if (dialogType === null || typeof dialogType === 'undefined') {
return null;
}
if (dialogType === CONFIRM_DIALOG) {
if (this.confirmDialog !== null && typeof this.confirmDialog !== 'undefined') {
return this.confirmDialog.getDialogResult();
}
}
else if (dialogType === MESSAGE_DIALOG) {
if (this.messageDialog !== null && typeof this.messageDialog !== 'undefined') {
return this.messageDialog.getDialogResult();
}
}
else if (dialogType === COMPONENT_DIALOG) {
if (this.componentDialog !== null && typeof this.componentDialog !== 'undefined') {
return this.componentDialog.getDialogResult();
}
}
return null;
};
/**
* @return {?}
*/
PhloxDialog.prototype._showDialog = /**
* @return {?}
*/
function () {
this.show = true;
};
/**
* <p style="text-indent: 1em;">
* Show current dialog described by the <code><b>[[currentModel]]</b></code>. This usually be the last model generated by
* the last <code><i>show...Dialog</i></code> method call.
* </p>
* @return {?}
*/
PhloxDialog.prototype.showDialog = /**
* <p style="text-indent: 1em;">
* Show current dialog described by the <code><b>[[currentModel]]</b></code>. This usually be the last model generated by
* the last <code><i>show...Dialog</i></code> method call.
* </p>
* @return {?}
*/
function () {
if (this.currentModel !== null && typeof this.currentModel !== 'undefined') {
var /** @type {?} */ dialogType = this.currentModel.type;
if (typeof dialogType === 'string') {
if (dialogType === CONFIRM_DIALOG) {
if (this.confirmDialog !== null && typeof this.confirmDialog !== 'undefined') {
this.confirmDialog.showDialog();
this._showDialog();
}
}
else if (dialogType === MESSAGE_DIALOG) {
if (this.messageDialog !== null && typeof this.messageDialog !== 'undefined') {
this.messageDialog.showDialog();
this._showDialog();
}
}
else if (dialogType === COMPONENT_DIALOG) {
if (this.componentDialog !== null && typeof this.componentDialog !== 'undefined') {
this.componentDialog.showDialog();
this._showDialog();
}
}
}
}
};
/**
* <p style="text-indent: 1em;">
* Hide the current showing dialog and show the next dialog in the queue (if any).
* </p>
* @return {?}
*/
PhloxDialog.prototype.hideDialog = /**
* <p style="text-indent: 1em;">
* Hide the current showing dialog and show the next dialog in the queue (if any).
* </p>
* @return {?}
*/
function () {
// hide all dialog
if (this.confirmDialog !== null && typeof this.confirmDialog !== 'undefined') {
this.confirmDialog.hideDialog();
}
if (this.messageDialog !== null && typeof this.messageDialog !== 'undefined') {
this.messageDialog.hideDialog();
}
if (this.componentDialog !== null && typeof this.componentDialog !== 'undefined') {
this.componentDialog.hideDialog();
}
// resolve
if (this.currentResolver !== null && typeof this.currentResolver !== 'undefined') {
if (this.currentModel !== null && typeof this.currentModel !== 'undefined') {
this.currentResolver.resolve(this.getDialogResult(this.currentModel.type));
}
else {
this.currentResolver.resolve(null);
}
}
this.currentModel = null;
this.currentResolver = null;
if (this.showNextDialog()) {
return;
}
this.show = false;
};
/**
* <p style="text-indent: 1em;">
* Display a confirmation dialog on the screen.
* </p>
*
* @see [[ConfirmDialog]]
* @param {?} title The dialog title text.
* @param {?} message The dialog message which will be displayed in the dialog body.
* @param {?} showCancelBtn To display the <code>CANCEL</code> button or not. By default, the confirmation dialog will contain only
* <code>YES</code> and <code>NO</code> button.
* @param {?=} width The css <code>"width"</code> style value governing dialog width e.g. <code>100px</code>, <code>50pt</code>.
* @param {?=} height The css <code>"height"</code> style value governing dialog height e.g. <code>100px</code>, <code>50pt</code>.
*
* @return {?} The <code>promise</code> which will be resolved when this dialog is closed. The resolving result will be the value
* returned from [[ConfirmDialog.getDialogResult]] method.
*
*/
PhloxDialog.prototype.showConfirmDialog = /**
* <p style="text-indent: 1em;">
* Display a confirmation dialog on the screen.
* </p>
*
* @see [[ConfirmDialog]]
* @param {?} title The dialog title text.
* @param {?} message The dialog message which will be displayed in the dialog body.
* @param {?} showCancelBtn To display the <code>CANCEL</code> button or not. By default, the confirmation dialog will contain only
* <code>YES</code> and <code>NO</code> button.
* @param {?=} width The css <code>"width"</code> style value governing dialog width e.g. <code>100px</code>, <code>50pt</code>.
* @param {?=} height The css <code>"height"</code> style value governing dialog height e.g. <code>100px</code>, <code>50pt</code>.
*
* @return {?} The <code>promise</code> which will be resolved when this dialog is closed. The resolving result will be the value
* returned from [[ConfirmDialog.getDialogResult]] method.
*
*/
function (title, message, showCancelBtn, width, height) {
var _this = this;
return new Promise(function (resolve, reject) {
var /** @type {?} */ confirmDialog = new ConfirmDialogModel(title, message, CONFIRM_DIALOG, showCancelBtn, width, height);
var /** @type {?} */ resolver = _this.getResolverWrapper(confirmDialog, resolve, reject);
_this.currentResolver = resolver;
if (_this.currentModel == null) {
_this.currentModel = confirmDialog;
if (_this.confirmDialog != null) {
_this.confirmDialog.showDialog();
_this._showDialog();
}
}
else {
// stack in
// stack in
_this.dialogQueue.push(confirmDialog);
_this.dialogResolverQueue.push(resolver);
}
});
};
/**
* <p style="text-indent: 1em;">
* Display a message dialog on the screen.
* </p>
*
* @see [[MessageDialog]]
* @param {?} title The dialog title text.
* @param {?} message The dialog message which will be displayed in the dialog body.
* @param {?=} width The css <code>"width"</code> style value governing dialog width e.g. <code>100px</code>, <code>50pt</code>.
* @param {?=} height The css <code>"height"</code> style value governing dialog height e.g. <code>100px</code>, <code>50pt</code>.
*
* @return {?} The <code>promise</code> which will be resolved when this dialog is closed. The resolving result will be the value
* returned from [[MessageDialog.getDialogResult]] method (which always returns <code>true</code>).
*
*/
PhloxDialog.prototype.showMessageDialog = /**
* <p style="text-indent: 1em;">
* Display a message dialog on the screen.
* </p>
*
* @see [[MessageDialog]]
* @param {?} title The dialog title text.
* @param {?} message The dialog message which will be displayed in the dialog body.
* @param {?=} width The css <code>"width"</code> style value governing dialog width e.g. <code>100px</code>, <code>50pt</code>.
* @param {?=} height The css <code>"height"</code> style value governing dialog height e.g. <code>100px</code>, <code>50pt</code>.
*
* @return {?} The <code>promise</code> which will be resolved when this dialog is closed. The resolving result will be the value
* returned from [[MessageDialog.getDialogResult]] method (which always returns <code>true</code>).
*
*/
function (title, message, width, height) {
var _this = this;
return new Promise(function (resolve, reject) {
var /** @type {?} */ messageDialog = new DialogModel(title, message, MESSAGE_DIALOG, width, height);
var /** @type {?} */ resolver = _this.getResolverWrapper(messageDialog, resolve, reject);
_this.currentResolver = resolver;
if (_this.currentModel == null) {
_this.currentModel = messageDialog;
if (_this.messageDialog != null) {
_this.messageDialog.showDialog();
_this._showDialog();
}
}
else {
// stack in
// stack in
_this.dialogQueue.push(messageDialog);
_this.dialogResolverQueue.push(resolver);
}
});
};
/**
* <p style="text-indent: 1em;">
* Display a component dialog on the screen. A component dialog is a dialog allowing you to display your own custom dialog by specifying
* a <code>component type</code> being displayed as its body. That <code>component type</code> must be a class which is an instance of
* [[IDialogController]].
* </p>
*
* @see [[ComponentDialog]]
* @param {?} componentDialogModel A dialog model being displayed.
*
* @return {?} The <code>promise</code> which will be resolved when this dialog is closed. The resolving result will be the value returned
* from [[IDialogController.getDialogResult]] method.
*
*/
PhloxDialog.prototype.showComponentDialog = /**
* <p style="text-indent: 1em;">
* Display a component dialog on the screen. A component dialog is a dialog allowing you to display your own custom dialog by specifying
* a <code>component type</code> being displayed as its body. That <code>component type</code> must be a class which is an instance of
* [[IDialogController]].
* </p>
*
* @see [[ComponentDialog]]
* @param {?} componentDialogModel A dialog model being displayed.
*
* @return {?} The <code>promise</code> which will be resolved when this dialog is closed. The resolving result will be the value returned
* from [[IDialogController.getDialogResult]] method.
*
*/
function (componentDialogModel) {
var _this = this;
if (componentDialogModel === null || typeof componentDialogModel === 'undefined') {
return Promise.resolve(null);
}
return new Promise(function (resolve, reject) {
var /** @type {?} */ componentDialog = componentDialogModel;
componentDialog.type = COMPONENT_DIALOG;
var /** @type {?} */ resolver = _this.getResolverWrapper(componentDialog, resolve, reject);
_this.currentResolver = resolver;
if (componentDialogModel.dialogStyleClass !== undefined && componentDialogModel.dialogStyleClass !== null) {
_this.dialogClass = componentDialogModel.dialogStyleClass;
}
else {
_this.dialogClass = [];
}
if (_this.currentModel == null) {
_this.currentModel = componentDialog;
if (_this.componentDialog != null) {
_this.componentDialog.showDialog();
_this._showDialog();
}
}
else {
// stack in
// stack in
_this.dialogQueue.push(componentDialog);
_this.dialogResolverQueue.push(resolver);
}
});
};
/**
* @return {?}
*/
PhloxDialog.prototype.isShow = /**
* @return {?}
*/
function () {
return this.show;
};
/**
* @return {?}
*/
PhloxDialog.prototype.getCurrentModel = /**
* @return {?}
*/
function () {
return this.currentModel;
};
/**
* @return {?}
*/
PhloxDialog.prototype.getDialogClass = /**
* @return {?}
*/
function () {
return this.dialogClass;
};
PhloxDialog.TYPE_NAME = TYPE_NAME;
PhloxDialog.CONFIRM_DIALOG = CONFIRM_DIALOG;
PhloxDialog.MESSAGE_DIALOG = MESSAGE_DIALOG;
PhloxDialog.COMPONENT_DIALOG = COMPONENT_DIALOG;
PhloxDialog.decorators = [
{ type: Component, args: [{
moduleId: module.id,
selector: TYPE_NAME,
template: "<div class=\"phx-dialog-background\" [class.show]=\"isShow()\">\n\t<div class=\"phx-dialog\" [ngClass]=\"getDialogClass()\" [class.show]=\"isShow()\" [style.width]=\"getDialogWidth()\" [style.height]=\"getDialogHeight()\">\n\t\t<phx-confirm-dialog #confirmdialog [model]=\"getCurrentModel()\" [dialog]=\"this\"></phx-confirm-dialog>\n\t\t<phx-message-dialog #messagedialog [model]=\"getCurrentModel()\" [dialog]=\"this\"></phx-message-dialog>\n\t\t<phx-component-dialog #componentdialog [model]=\"getCurrentModel()\" [dialog]=\"this\"></phx-component-dialog>\n\t</div>\n</div>\n"
},] },
];
/** @nocollapse */
PhloxDialog.ctorParameters = function () { return [
{ type: PhloxAppInfoService, },
{ type: NeedFocusService, },
]; };
PhloxDialog.propDecorators = {
"confirmDialog": [{ type: ViewChild, args: ['confirmdialog',] },],
"messageDialog": [{ type: ViewChild, args: ['messagedialog',] },],
"componentDialog": [{ type: ViewChild, args: ['componentdialog',] },],
};
return PhloxDialog;
}());
export { PhloxDialog };
function PhloxDialog_tsickle_Closure_declarations() {
/** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */
PhloxDialog.decorators;
/**
* @nocollapse
* @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
*/
PhloxDialog.ctorParameters;
/** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */
PhloxDialog.propDecorators;
/** @type {?} */
PhloxDialog.TYPE_NAME;
/** @type {?} */
PhloxDialog.CONFIRM_DIALOG;
/** @type {?} */
PhloxDialog.MESSAGE_DIALOG;
/** @type {?} */
PhloxDialog.COMPONENT_DIALOG;
/** @type {?} */
PhloxDialog.prototype.dialogQueue;
/** @type {?} */
PhloxDialog.prototype.dialogClass;
/** @type {?} */
PhloxDialog.prototype.dialogResolverQueue;
/** @type {?} */
PhloxDialog.prototype.confirmDialog;
/** @type {?} */
PhloxDialog.prototype.messageDialog;
/** @type {?} */
PhloxDialog.prototype.componentDialog;
/** @type {?} */
PhloxDialog.prototype.currentModel;
/** @type {?} */
PhloxDialog.prototype.currentResolver;
/** @type {?} */
PhloxDialog.prototype.phloxAppInfo;
/** @type {?} */
PhloxDialog.prototype.needFocusService;
/** @type {?} */
PhloxDialog.prototype._show;
}
export { YES, NO, CANCEL, ConfirmDialog } from './dialog.internal/ConfirmDialog.component';
export { MessageDialog } from './dialog.internal/MessageDialog.component';
export { ComponentDialog } from './dialog.internal/ComponentDialog.component';
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGhsb3hEaWFsb2cuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vY29tLnBobG94dWkvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50L1BobG94RGlhbG9nLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDckQsT0FBTyxFQUFFLFdBQVcsRUFBc0Msa0JBQWtCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUM3RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN2RSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFDMUUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDJDQUEyQyxDQUFDO0FBQzFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUU5RSxxQkFBTSxTQUFTLEdBQVcsWUFBWSxDQUFDO0FBRXZDLHFCQUFNLGNBQWMsR0FBVyxTQUFTLENBQUM7QUFDekMscUJBQU0sY0FBYyxHQUFXLFNBQVMsQ0FBQztBQUN6QyxxQkFBTSxnQkFBZ0IsR0FBVyxXQUFXLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0lBOEUzQyxxQkFBWSxlQUFvQyxFQUFFLGdCQUFrQztRQUFwRixpQkFpQkM7UUFoQkMsSUFBSSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUM7UUFDbEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLG1CQUFtQixHQUFHLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUM7UUFFekMsRUFBRSxDQUFDLENBQUMsZUFBZSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDNUIsZUFBZSxDQUFD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Q0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDOzs0QkFwVmlCLFNBQVM7aUNBRUosY0FBYztpQ0FDZCxjQUFjO21DQUNaLGdCQUFnQjs7Z0JBbEJuRSxTQUFTLFNBQUM7b0JBQ1QsUUFBUSxFQUFFLE1BQU0sQ0FBQyxFQUFFO29CQUNuQixRQUFRLEVBQUUsU0FBUztvQkFDbkIsUUFBUSxFQUFFLG9rQkFPWDtpQkFDQTs7OztnQkEvQ1EsbUJBQW1CO2dCQUNuQixnQkFBZ0I7OztrQ0EwRHRCLFNBQVMsU0FBQyxlQUFlO2tDQUV6QixTQUFTLFNBQUMsZUFBZTtvQ0FFekIsU0FBUyxTQUFDLGlCQUFpQjs7c0JBakU5Qjs7U0FrRGEsV0FBVzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBMFZ4QiwrQ0FBYywyQ0FBMkMsQ0FBQztBQUMxRCw4QkFBYywyQ0FBMkMsQ0FBQztBQUMxRCxnQ0FBYyw2Q0FBNkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBEaWFsb2dNb2RlbCwgUGhsb3hBcHBJbmZvLCBDb21wb25lbnREaWFsb2dNb2RlbCwgQ29uZmlybURpYWxvZ01vZGVsIH0gZnJvbSAnLi9tb2RlbC9tb2RlbHMnO1xuaW1wb3J0IHsgUGhsb3hBcHBJbmZvU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2UvUGhsb3hBcHBJbmZvU2VydmljZS5zZXJ2aWNlJztcbmltcG9ydCB7IE5lZWRGb2N1c1NlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlL05lZWRGb2N1c1NlcnZpY2Uuc2VydmljZSc7XG5pbXBvcnQgeyBDb25maXJtRGlhbG9nIH0gZnJvbSAnLi9kaWFsb2cuaW50ZXJuYWwvQ29uZmlybURpYWxvZy5jb21wb25lbnQnO1xuaW1wb3J0IHsgTWVzc2FnZURpYWxvZyB9IGZyb20gJy4vZGlhbG9nLmludGVybmFsL01lc3NhZ2VEaWFsb2cuY29tcG9uZW50JztcbmltcG9ydCB7IENvbXBvbmVudERpYWxvZyB9IGZyb20gJy4vZGlhbG9nLmludGVybmFsL0NvbXBvbmVudERpYWxvZy5jb21wb25lbnQnO1xuXG5jb25zdCBUWVBFX05BTUU6IHN0cmluZyA9IFwicGh4LWRpYWxvZ1wiO1xuXG5jb25zdCBDT05GSVJNX0RJQUxPRzogc3RyaW5nID0gJ2NvbmZpcm0nO1xuY29uc3QgTUVTU0FHRV9ESUFMT0c6IHN0cmluZyA9ICdtZXNzYWdlJztcbmNvbnN0IENPTVBPTkVOVF9ESUFMT0c6IHN0cmluZyA9ICdjb21wb25lbnQnO1xuXG4vKipcbiAqIDxwIHN0eWxlPVwidGV4dC1pbmRlbnQ6IDJlbTtcIj5cbiAqIEEgPGNvZGU+c2luZ2xldG9uPC9jb2RlPiBVSSBjb21wb25lbnQgY29udHJvbGxpbmcgPGNvZGU+YXBwbGljYXRpb248L2NvZGU+IHBvcC11cCBkaWFsb2cgbG9naWMuIFRoaXMgZGlhbG9nIGlzIGEgPGNvZGU+bW9kYWw8L2NvZGU+IGRpYWxvZywgc2F5aW5nIHRoYXQsXG4gKiB3aGVuIGl0IGlzIGRpc3BsYXllZCwgYWxsIHVzZXIncyBVSSBhY3Rpb25zIHdpbGwgYmUgYmxvY2tlZCBhbmQgdGhlIHVzZXIgd2lsbCBiZSBmb3JjZWQgdG8gZm9jdXMgb24gdGhpcyBkaWFsb2cuIFdoZW4gdGhlIHVzZXIgY29tcGxldGVzIHRoZSBpbnRlcmFjdGlvblxuICogd2l0aCB0aGlzIGRpYWxvZywgZm9yIGV4YW1wbGUsIGNsaWNraW5nIG9uIFwiT0tcIiBidXR0b24sIHRoaXMgZGlhbG9nIHdpbGwgYmUgaGlkZGVuIGFuZCB0aGUgdXNlciBjYW4gcmVzdW1lIG5vcm1hbCBVSSBvcGVyYXRpb25zLiBOb3JtYWxseSwgeW91IDxiPnNob3VsZFxuICogTk9UPC9iPiBkaXJlY3RseSBhY2Nlc3MgdGhpcyBjb21wb25lbnQgaW5zdGFuY2UgYnV0IHlvdSBjb3VsZCBjb250cm9sIGl0IHZpYSA8Yj5bW0RpYWxvZ1NlcnZpY2VdXTwvYj4uXG4gKiA8L3A+XG4gKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAyZW07XCI+XG4gKiBQbGVhc2Ugbm90ZSB0aGF0IHRoZXJlIGlzIGEgZGlhbG9nIDxjb2RlPmRpc3BsYXkgcXVldWU8L2NvZGU+IG9wZXJhdGluZyBiZWhpbmQgdGhlIHNjZW5lcy4gVGhpcyA8Y29kZT5kaXNwbGF5IHF1ZXVlPC9jb2RlPiBpcyBhIDxjb2RlPkZJRk88L2NvZGU+IHF1ZXVlXG4gKiBrZWVwaW5nIGFsbCBkaWFsb2cgbW9kZWxzIChbW0RpYWxvZ01vZGVsXV0pIC0td2hpY2ggYXJlIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIGFuZCBrZXB0IGluIHRoZSBxdWV1ZSB3aGVuIDxjb2RlPjxpPnNob3cuLi5EaWFsb2c8L2k+PC9jb2RlPiBtZXRob2RzIGFyZSBjYWxsZWQtLVxuICogYnV0IHRob3NlIGRpYWxvZyBtb2RlbHMgY2Fubm90IGJlIGRpc3BsYXllZCBzdWRkZW5seS4gRm9yIGV4YW1wbGUsIGlmIHRoZXJlIGFscmVhZHkgaXMgYSBkaWFsb2cgYmVpbmcgZGlzcGxheWVkIGN1cnJlbnRseSwgYnV0LCB0aGVyZSBpcyBhbHNvIHNvbWVvbmUgZWxzZVxuICogY2FsbGluZyA8Y29kZT48aT5zaG93Li4uRGlhbG9nPC9pPjwvY29kZT4gbWV0aG9kIHNpbXVsdGFuZW91c2x5LCB0aGUgZGlhbG9nIG1vZGVsIGdlbmVyYXRlZCBmcm9tIHRoZSBsYXRlciA8Y29kZT48aT5zaG93Li4uRGlhbG9nPC9pPjwvY29kZT4gbWV0aG9kIHdpbGxcbiAqIG5vdCBiZSBzaG93ZWQgc3VkZGVubHkuIE5ldmVydGhlbGVzcywgaXQnbGwgYmUgc2hvd2VkIGltbWVkaWF0ZWx5IHdoZW4gdGhlIGZpcnN0IGRpYWxvZyBpcyBjbG9zZWQuIEZvciB0aGlzIG1lY2hhbmlzbSwgdGhlIGRpYWxvZyBtb2RlbCBjYW4gYmUgZmlyc3RseSBrZXB0XG4gKiBpbiB0aGUgcXVldWUsIHRoZW4sIGl0IHdpbGwgYmUgc2hvd2VkIGFuZCByZW1vdmVkIGZyb20gdGhlIHF1ZXVlIHdoZW4gaXRzIHByZWNlZGluZyBkaWFsb2cgaXMgY2xvc2VkLlxuICogPC9wPlxuICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMmVtO1wiPlxuICogSWYgeW91IHdhbnQgdG8gaW1wbGVtZW50IHlvdXIgb3duIDxiPmN1c3RvbSBkaWFsb2c8L2I+LCB5b3Ugc2hvdWxkIGRvIGl0IHVzaW5nIDxjb2RlPmNvbXBvbmVudCBkaWFsb2c8L2NvZGU+IHJhdGhlciB0aGFuIGJ1aWxkaW5nIGl0IGFsbCB1cCBmcm9tIHNjcmF0Y2hlcy4gVGhlIG9ubHkgdGhpbmdcbiAqIHdoaWNoIHlvdSBuZWVkIHRvIGRvIGlzIGp1c3QgaW1wbGVtZW50aW5nIHRoZSBjb21wb25lbnQgYmVpbmcgZGlzcGxheWVkIGluc2lkZSB0aGUgZGlhbG9nIGJvZHkuIEFsbCBvdGhlciBtZWNoYW5pc21zLCBzdWNoIGFzIGRpYWxvZyA8Y29kZT5kaXNwbGF5IHF1ZXVlPC9jb2RlPlxuICogbGlzdGVkIGFib3ZlLCBzaG91bGQgYmUgbGVmdCB0byBiZSBoYW5kbGVkIGJ5IHRoZSBmcmFtZXdvcmsgb3IgYnkgdGhpcyBjbGFzcy4gRm9yIG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgYnVpbGRpbmcgY3VzdG9tIGRpYWxvZywgcGxlYXNlIHNlZSBbW3Nob3dDb21wb25lbnREaWFsb2ddXS5cbiAqIDwvcD5cbiAqXG4gKiBAYXV0aG9yIHNoaW9yaW4sIHRlZTRjdXRlXG4gKiBAc2VlIFtbRGlhbG9nU2VydmljZV1dXG4gKi9cbkBDb21wb25lbnQoe1xuICBtb2R1bGVJZDogbW9kdWxlLmlkLFxuICBzZWxlY3RvcjogVFlQRV9OQU1FLFxuICB0ZW1wbGF0ZTogYDxkaXYgY2xhc3M9XCJwaHgtZGlhbG9nLWJhY2tncm91bmRcIiBbY2xhc3Muc2hvd109XCJpc1Nob3coKVwiPlxuXHQ8ZGl2IGNsYXNzPVwicGh4LWRpYWxvZ1wiIFtuZ0NsYXNzXT1cImdldERpYWxvZ0NsYXNzKClcIiBbY2xhc3Muc2hvd109XCJpc1Nob3coKVwiIFtzdHlsZS53aWR0aF09XCJnZXREaWFsb2dXaWR0aCgpXCIgW3N0eWxlLmhlaWdodF09XCJnZXREaWFsb2dIZWlnaHQoKVwiPlxuXHRcdDxwaHgtY29uZmlybS1kaWFsb2cgI2NvbmZpcm1kaWFsb2cgW21vZGVsXT1cImdldEN1cnJlbnRNb2RlbCgpXCIgW2RpYWxvZ109XCJ0aGlzXCI+PC9waHgtY29uZmlybS1kaWFsb2c+XG5cdFx0PHBoeC1tZXNzYWdlLWRpYWxvZyAjbWVzc2FnZWRpYWxvZyBbbW9kZWxdPVwiZ2V0Q3VycmVudE1vZGVsKClcIiBbZGlhbG9nXT1cInRoaXNcIj48L3BoeC1tZXNzYWdlLWRpYWxvZz5cblx0XHQ8cGh4LWNvbXBvbmVudC1kaWFsb2cgI2NvbXBvbmVudGRpYWxvZyBbbW9kZWxdPVwiZ2V0Q3VycmVudE1vZGVsKClcIiBbZGlhbG9nXT1cInRoaXNcIj48L3BoeC1jb21wb25lbnQtZGlhbG9nPlxuXHQ8L2Rpdj5cbjwvZGl2PlxuYFxufSlcbmV4cG9ydCBjbGFzcyBQaGxveERpYWxvZyB7XG5cbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBUWVBFX05BTUU6IHN0cmluZyA9IFRZUEVfTkFNRTtcblxuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IENPTkZJUk1fRElBTE9HOiBzdHJpbmcgPSBDT05GSVJNX0RJQUxPRztcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBNRVNTQUdFX0RJQUxPRzogc3RyaW5nID0gTUVTU0FHRV9ESUFMT0c7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQ09NUE9ORU5UX0RJQUxPRzogc3RyaW5nID0gQ09NUE9ORU5UX0RJQUxPRztcblxuICBwcml2YXRlIGRpYWxvZ1F1ZXVlOiBEaWFsb2dNb2RlbFtdO1xuICBwcml2YXRlIGRpYWxvZ0NsYXNzOiBzdHJpbmdbXTtcbiAgcHJpdmF0ZSBkaWFsb2dSZXNvbHZlclF1ZXVlOiBhbnlbXTtcbiAgQFZpZXdDaGlsZCgnY29uZmlybWRpYWxvZycpXG4gIHByaXZhdGUgY29uZmlybURpYWxvZzogQ29uZmlybURpYWxvZztcbiAgQFZpZXdDaGlsZCgnbWVzc2FnZWRpYWxvZycpXG4gIHByaXZhdGUgbWVzc2FnZURpYWxvZzogTWVzc2FnZURpYWxvZztcbiAgQFZpZXdDaGlsZCgnY29tcG9uZW50ZGlhbG9nJylcbiAgcHJpdmF0ZSBjb21wb25lbnREaWFsb2c6IENvbXBvbmVudERpYWxvZztcbiAgcHJpdmF0ZSBjdXJyZW50TW9kZWw6IERpYWxvZ01vZGVsO1xuICBwcml2YXRlIGN1cnJlbnRSZXNvbHZlcjogYW55O1xuICBwcml2YXRlIHBobG94QXBwSW5mbzogUGhsb3hBcHBJbmZvO1xuICBwcml2YXRlIG5lZWRGb2N1c1NlcnZpY2U6IE5lZWRGb2N1c1NlcnZpY2U7XG4gIHByaXZhdGUgX3Nob3c6IGJvb2xlYW47XG5cbiAgcHJpdmF0ZSBzZXQgc2hvdyhzaG93OiBib29sZWFuKSB7XG4gICAgdGhpcy5fc2hvdyA9IHNob3c7XG5cblxuICAgIGlmICh0aGlzLl9zaG93KSB7XG4gICAgICAvLyBpZiB0cnVlIGFkZCBjbGFzcyB0byBib2R5XG4gICAgICAkKFwiYm9keVwiKS5hZGRDbGFzcyhcInBoeC1kaWFsb2ctZml4ZWRcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGlmIGZhbHNlIHJlbW92ZSBjbGFzcyBmcm9tIGJvZHlcbiAgICAgICQoXCJib2R5XCIpLnJlbW92ZUNsYXNzKFwicGh4LWRpYWxvZy1maXhlZFwiKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGdldCBzaG93KCkge1xuICAgIHJldHVybiB0aGlzLl9zaG93O1xuICB9XG5cbiAgY29uc3RydWN0b3IocGhsb3hBcHBTZXJ2aWNlOiBQaGxveEFwcEluZm9TZXJ2aWNlLCBuZWVkRm9jdXNTZXJ2aWNlOiBOZWVkRm9jdXNTZXJ2aWNlKSB7XG4gICAgdGhpcy5zaG93ID0gZmFsc2U7XG4gICAgdGhpcy5kaWFsb2dRdWV1ZSA9IFtdO1xuICAgIHRoaXMuZGlhbG9nUmVzb2x2ZXJRdWV1ZSA9IFtdO1xuICAgIHRoaXMubmVlZEZvY3VzU2VydmljZSA9IG5lZWRGb2N1c1NlcnZpY2U7XG5cbiAgICBpZiAocGhsb3hBcHBTZXJ2aWNlICE9IG51bGwpIHtcbiAgICAgIHBobG94QXBwU2VydmljZS5nZXRBcHBJbmZvKCkudGhlbigocmVzdWx0KSA9PiB7XG4gICAgICAgIHRoaXMucGhsb3hBcHBJbmZvID0gcmVzdWx0O1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHdpbmRvdy5oaXN0b3J5ICYmIHdpbmRvdy5oaXN0b3J5LnB1c2hTdGF0ZSkge1xuICAgICAgJCh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIChldmVudCkgPT4ge1xuICAgICAgICB0aGlzLmhpZGVEaWFsb2coKTtcbiAgICAgIH0pXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzaG93TmV4dERpYWxvZygpOiBib29sZWFuIHtcbiAgICB0aGlzLmN1cnJlbnRNb2RlbCA9IG51bGw7XG4gICAgaWYgKHRoaXMuZGlhbG9nUXVldWUubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy5jdXJyZW50TW9kZWwgPSB0aGlzLmRpYWxvZ1F1ZXVlWzBdO1xuICAgICAgdGhpcy5kaWFsb2dRdWV1ZS5zcGxpY2UoMCwgMSk7XG5cbiAgICAgIGlmICh0aGlzLmRpYWxvZ1Jlc29sdmVyUXVldWUubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLmN1cnJlbnRSZXNvbHZlciA9IHRoaXMuZGlhbG9nUmVzb2x2ZXJRdWV1ZVswXTtcbiAgICAgICAgdGhpcy5kaWFsb2dSZXNvbHZlclF1ZXVlLnNwbGljZSgwLCAxKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuY3VycmVudE1vZGVsICE9PSBudWxsICYmIHR5cGVvZiB0aGlzLmN1cnJlbnRNb2RlbCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgdGhpcy5zaG93RGlhbG9nKCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5jdXJyZW50UmVzb2x2ZXIgPSBudWxsO1xuICAgICAgICB0aGlzLmhpZGVEaWFsb2coKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0STE4Tk1lc3NhZ2Uoa2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICh0aGlzLnBobG94QXBwSW5mbyAhPSBudWxsICYmIHRoaXMucGhsb3hBcHBJbmZvLmkxOG4gIT0gbnVsbCkge1xuICAgICAgaWYgKHRoaXMucGhsb3hBcHBJbmZvLmkxOG5ba2V5XSAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5waGxveEFwcEluZm8uaTE4bltrZXldICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICByZXR1cm4gdGhpcy5waGxveEFwcEluZm8uaTE4bltrZXldO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4ga2V5O1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRSZXNvbHZlcldyYXBwZXIobW9kZWw6IGFueSwgcmVzb2x2ZTogYW55LCByZWplY3Q6IGFueSk6IGFueSB7XG4gICAgbGV0IHJlc3VsdCA9IHtcbiAgICAgIG1vZGVsOiBtb2RlbCxcbiAgICAgIHJlc29sdmU6IHJlc29sdmUsXG4gICAgICByZWplY3Q6IHJlamVjdFxuICAgIH07XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHVibGljIGdldERpYWxvZ1dpZHRoKCk6IHN0cmluZyB7XG4gICAgaWYgKHRoaXMuY3VycmVudE1vZGVsICE9PSBudWxsICYmIHR5cGVvZiB0aGlzLmN1cnJlbnRNb2RlbCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGlmICh0aGlzLmN1cnJlbnRNb2RlbC53aWR0aCAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5jdXJyZW50TW9kZWwud2lkdGggPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmN1cnJlbnRNb2RlbC53aWR0aDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gXCJcIjtcbiAgfVxuXG4gIHB1YmxpYyBnZXREaWFsb2dIZWlnaHQoKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5jdXJyZW50TW9kZWwgIT09IG51bGwgJiYgdHlwZW9mIHRoaXMuY3VycmVudE1vZGVsICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgaWYgKHRoaXMuY3VycmVudE1vZGVsLmhlaWdodCAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5jdXJyZW50TW9kZWwuaGVpZ2h0ID09PSAnc3RyaW5nJykge1xuICAgICAgICByZXR1cm4gdGhpcy5jdXJyZW50TW9kZWwuaGVpZ2h0O1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBcIlwiO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXREaWFsb2dSZXN1bHQoZGlhbG9nVHlwZTogc3RyaW5nKTogYW55IHtcbiAgICBpZiAoZGlhbG9nVHlwZSA9PT0gbnVsbCB8fCB0eXBlb2YgZGlhbG9nVHlwZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGlmIChkaWFsb2dUeXBlID09PSBDT05GSVJNX0RJQUxPRykge1xuICAgICAgaWYgKHRoaXMuY29uZmlybURpYWxvZyAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5jb25maXJtRGlhbG9nICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maXJtRGlhbG9nLmdldERpYWxvZ1Jlc3VsdCgpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoZGlhbG9nVHlwZSA9PT0gTUVTU0FHRV9ESUFMT0cpIHtcbiAgICAgIGlmICh0aGlzLm1lc3NhZ2VEaWFsb2cgIT09IG51bGwgJiYgdHlwZW9mIHRoaXMubWVzc2FnZURpYWxvZyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWVzc2FnZURpYWxvZy5nZXREaWFsb2dSZXN1bHQoKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGRpYWxvZ1R5cGUgPT09IENPTVBPTkVOVF9ESUFMT0cpIHtcbiAgICAgIGlmICh0aGlzLmNvbXBvbmVudERpYWxvZyAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5jb21wb25lbnREaWFsb2cgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbXBvbmVudERpYWxvZy5nZXREaWFsb2dSZXN1bHQoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgX3Nob3dEaWFsb2coKTogdm9pZCB7XG4gICAgdGhpcy5zaG93ID0gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIFNob3cgY3VycmVudCBkaWFsb2cgZGVzY3JpYmVkIGJ5IHRoZSA8Y29kZT48Yj5bW2N1cnJlbnRNb2RlbF1dPC9iPjwvY29kZT4uIFRoaXMgdXN1YWxseSBiZSB0aGUgbGFzdCBtb2RlbCBnZW5lcmF0ZWQgYnlcbiAgICogdGhlIGxhc3QgPGNvZGU+PGk+c2hvdy4uLkRpYWxvZzwvaT48L2NvZGU+IG1ldGhvZCBjYWxsLlxuICAgKiA8L3A+XG4gICAqL1xuICBwdWJsaWMgc2hvd0RpYWxvZygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5jdXJyZW50TW9kZWwgIT09IG51bGwgJiYgdHlwZW9mIHRoaXMuY3VycmVudE1vZGVsICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgbGV0IGRpYWxvZ1R5cGUgPSB0aGlzLmN1cnJlbnRNb2RlbC50eXBlO1xuICAgICAgaWYgKHR5cGVvZiBkaWFsb2dUeXBlID09PSAnc3RyaW5nJykge1xuICAgICAgICBpZiAoZGlhbG9nVHlwZSA9PT0gQ09ORklSTV9ESUFMT0cpIHtcbiAgICAgICAgICBpZiAodGhpcy5jb25maXJtRGlhbG9nICE9PSBudWxsICYmIHR5cGVvZiB0aGlzLmNvbmZpcm1EaWFsb2cgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpcm1EaWFsb2cuc2hvd0RpYWxvZygpO1xuICAgICAgICAgICAgdGhpcy5fc2hvd0RpYWxvZygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChkaWFsb2dUeXBlID09PSBNRVNTQUdFX0RJQUxPRykge1xuICAgICAgICAgIGlmICh0aGlzLm1lc3NhZ2VEaWFsb2cgIT09IG51bGwgJiYgdHlwZW9mIHRoaXMubWVzc2FnZURpYWxvZyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHRoaXMubWVzc2FnZURpYWxvZy5zaG93RGlhbG9nKCk7XG4gICAgICAgICAgICB0aGlzLl9zaG93RGlhbG9nKCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGRpYWxvZ1R5cGUgPT09IENPTVBPTkVOVF9ESUFMT0cpIHtcbiAgICAgICAgICBpZiAodGhpcy5jb21wb25lbnREaWFsb2cgIT09IG51bGwgJiYgdHlwZW9mIHRoaXMuY29tcG9uZW50RGlhbG9nICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgdGhpcy5jb21wb25lbnREaWFsb2cuc2hvd0RpYWxvZygpO1xuICAgICAgICAgICAgdGhpcy5fc2hvd0RpYWxvZygpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiA8cCBzdHlsZT1cInRleHQtaW5kZW50OiAxZW07XCI+XG4gICAqIEhpZGUgdGhlIGN1cnJlbnQgc2hvd2luZyBkaWFsb2cgYW5kIHNob3cgdGhlIG5leHQgZGlhbG9nIGluIHRoZSBxdWV1ZSAoaWYgYW55KS5cbiAgICogPC9wPlxuICAgKi9cbiAgcHVibGljIGhpZGVEaWFsb2coKTogdm9pZCB7XG4gICAgLy8gaGlkZSBhbGwgZGlhbG9nXG4gICAgaWYgKHRoaXMuY29uZmlybURpYWxvZyAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5jb25maXJtRGlhbG9nICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgdGhpcy5jb25maXJtRGlhbG9nLmhpZGVEaWFsb2coKTtcbiAgICB9XG4gICAgaWYgKHRoaXMubWVzc2FnZURpYWxvZyAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5tZXNzYWdlRGlhbG9nICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgdGhpcy5tZXNzYWdlRGlhbG9nLmhpZGVEaWFsb2coKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuY29tcG9uZW50RGlhbG9nICE9PSBudWxsICYmIHR5cGVvZiB0aGlzLmNvbXBvbmVudERpYWxvZyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHRoaXMuY29tcG9uZW50RGlhbG9nLmhpZGVEaWFsb2coKTtcbiAgICB9XG5cbiAgICAvLyByZXNvbHZlXG4gICAgaWYgKHRoaXMuY3VycmVudFJlc29sdmVyICE9PSBudWxsICYmIHR5cGVvZiB0aGlzLmN1cnJlbnRSZXNvbHZlciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIGlmICh0aGlzLmN1cnJlbnRNb2RlbCAhPT0gbnVsbCAmJiB0eXBlb2YgdGhpcy5jdXJyZW50TW9kZWwgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHRoaXMuY3VycmVudFJlc29sdmVyLnJlc29sdmUodGhpcy5nZXREaWFsb2dSZXN1bHQodGhpcy5jdXJyZW50TW9kZWwudHlwZSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5jdXJyZW50UmVzb2x2ZXIucmVzb2x2ZShudWxsKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmN1cnJlbnRNb2RlbCA9IG51bGw7XG4gICAgdGhpcy5jdXJyZW50UmVzb2x2ZXIgPSBudWxsO1xuICAgIGlmICh0aGlzLnNob3dOZXh0RGlhbG9nKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5zaG93ID0gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogPHAgc3R5bGU9XCJ0ZXh0LWluZGVudDogMWVtO1wiPlxuICAgKiBEaXNwbGF5IGEgY29uZmlybWF0aW9uIGRpYWxvZyBvbiB0aGUgc2NyZWVuLlxuICAgKiA8L3A+XG4gICAqXG4gICAqIEBwYXJhbSB0aXRsZSBUaGUgZGlhbG9nIHRpdGxlIHRleHQuXG4gICAqIEBwYXJhbSBtZXNzYWdlIFRoZSBkaWFsb2cgbWVzc2FnZSB3aGljaCB3aWxsIGJlIGRpc3BsYXllZCBpbiB0aGUgZGlhbG9nIGJvZHkuXG4gICAqIEBwYXJhbSBzaG93Q2FuY2VsQnRuIFRvIGRpc3BsYXkgdGhlIDxjb2RlPkNBTkNFTDwvY29kZT4gYnV0dG9uIG9yIG5vdC4gQnkgZGVmYXVsdCwgdGhlIGNvbmZpcm1hdGlvbiBkaWFsb2cgd2lsbCBjb250YWluIG9ubHlcbiAgICogPGNvZGU+WUVTPC9jb2RlPiBhbmQgPGNvZGU+Tk88L2NvZGU+IGJ1dHRvbi5cbiAgICogQHBhcmFtIHdpZHRoIFRoZSBjc3MgPGNvZGU+XCJ3aWR0aFwiPC9jb2RlPiBzdHlsZSB2YWx1ZSBnb3Zlcm5pbmcgZGlhbG9nIHdpZHRoIGUuZy4gPGNvZGU+MTAwcHg8L2NvZGU+LCA8Y29kZT41MHB0PC9jb2RlPi5cbiAgICogQHBhcmFtIGhlaWdodCBUaGUgY3NzIDxjb2RlPlwiaGVpZ2h0XCI8L2NvZGU+IHN0e