ngx-editor-custom
Version:
WYSIWYG Editor for Angular Applications
539 lines (538 loc) • 38.3 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
import { Component, Input, Output, ViewChild, EventEmitter, Renderer2, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import * as CodeMirror from 'codemirror';
import 'codemirror/addon/display/placeholder.js';
import 'codemirror/mode/htmlmixed/htmlmixed.js';
import { CommandExecutorService } from './common/services/command-executor.service';
import { MessageService } from './common/services/message.service';
import { ngxEditorConfig, codeMirrorConfig } from './common/ngx-editor.defaults';
import * as Utils from './common/utils/ngx-editor.utils';
var NgxEditorComponent = /** @class */ (function () {
/**
* @param _messageService service to send message to the editor message component
* @param _commandExecutor executes command from the toolbar
* @param _renderer access and manipulate the dom element
*/
function NgxEditorComponent(_messageService, _commandExecutor, _renderer) {
this._messageService = _messageService;
this._commandExecutor = _commandExecutor;
this._renderer = _renderer;
/**
* The editor can be resized vertically.
*
* `basic` resizer enables the html5 reszier. Check here https://www.w3schools.com/cssref/css3_pr_resize.asp
*
* `stack` resizer enable a resizer that looks like as if in https://stackoverflow.com
*/
this.resizer = 'stack';
/**
* The config property is a JSON object
*
* All avaibale inputs inputs can be provided in the configuration as JSON
* inputs provided directly are considered as top priority
*/
this.config = ngxEditorConfig;
/**
* emits `blur` event when focused out from the textarea
*/
this.blur = new EventEmitter();
/**
* emits `focus` event when focused in to the textarea
*/
this.focus = new EventEmitter();
this.chooseImageGallery = new EventEmitter();
this.Utils = Utils;
this.codeEditorMode = false;
this.ngxCodeMirror = undefined;
}
/**
* events
*/
/**
* events
* @return {?}
*/
NgxEditorComponent.prototype.onTextAreaFocus = /**
* events
* @return {?}
*/
function () {
this.focus.emit('focus');
};
/** focus the text area when the editor is focussed */
/**
* focus the text area when the editor is focussed
* @return {?}
*/
NgxEditorComponent.prototype.onEditorFocus = /**
* focus the text area when the editor is focussed
* @return {?}
*/
function () {
this.textArea.nativeElement.focus();
};
/**
* Executed from the contenteditable section while the input property changes
* @param html html string from contenteditable
*/
/**
* Executed from the contenteditable section while the input property changes
* @param {?} innerHTML
* @return {?}
*/
NgxEditorComponent.prototype.onContentChange = /**
* Executed from the contenteditable section while the input property changes
* @param {?} innerHTML
* @return {?}
*/
function (innerHTML) {
if (typeof this.onChange === 'function') {
this.onChange(innerHTML);
this.togglePlaceholder(innerHTML);
}
};
/**
* @return {?}
*/
NgxEditorComponent.prototype.onTextAreaBlur = /**
* @return {?}
*/
function () {
/** save selection if focussed out */
this._commandExecutor.savedSelection = Utils.saveSelection();
if (typeof this.onTouched === 'function') {
this.onTouched();
}
this.blur.emit('blur');
};
/**
* resizing text area
*
* @param offsetY vertical height of the eidtable portion of the editor
*/
/**
* resizing text area
*
* @param {?} offsetY vertical height of the eidtable portion of the editor
* @return {?}
*/
NgxEditorComponent.prototype.resizeTextArea = /**
* resizing text area
*
* @param {?} offsetY vertical height of the eidtable portion of the editor
* @return {?}
*/
function (offsetY) {
/** @type {?} */
var newHeight = parseInt(this.height, 10);
newHeight += offsetY;
this.height = newHeight + 'px';
this.textArea.nativeElement.style.height = this.height;
/**
* update code-editor height only on editor mode
*/
if (this.codeEditorMode) {
this.ngxCodeMirror.setSize('100%', this.height);
}
return;
};
/**
* editor actions, i.e., executes command from toolbar
*
* @param commandName name of the command to be executed
*/
/**
* editor actions, i.e., executes command from toolbar
*
* @param {?} commandName name of the command to be executed
* @return {?}
*/
NgxEditorComponent.prototype.executeCommand = /**
* editor actions, i.e., executes command from toolbar
*
* @param {?} commandName name of the command to be executed
* @return {?}
*/
function (commandName) {
if (commandName === 'refresh') {
/** @type {?} */
var value = this.textArea.nativeElement.innerHTML;
this.onContentChange(value);
return;
}
if (commandName === 'code') {
this.toggleCodeEditor();
return;
}
try {
this._commandExecutor.execute(commandName);
}
catch (error) {
this._messageService.sendMessage(error.message);
}
};
/**
* Write a new value to the element.
*
* @param value value to be executed when there is a change in contenteditable
*/
/**
* Write a new value to the element.
*
* @param {?} value value to be executed when there is a change in contenteditable
* @return {?}
*/
NgxEditorComponent.prototype.writeValue = /**
* Write a new value to the element.
*
* @param {?} value value to be executed when there is a change in contenteditable
* @return {?}
*/
function (value) {
this.togglePlaceholder(value);
if (value === null || value === undefined || value === '' || value === '<br>') {
value = null;
}
this.refreshView(value);
};
/**
* Set the function to be called
* when the control receives a change event.
*
* @param fn a function
*/
/**
* Set the function to be called
* when the control receives a change event.
*
* @param {?} fn a function
* @return {?}
*/
NgxEditorComponent.prototype.registerOnChange = /**
* Set the function to be called
* when the control receives a change event.
*
* @param {?} fn a function
* @return {?}
*/
function (fn) {
this.onChange = fn;
};
/**
* Set the function to be called
* when the control receives a touch event.
*
* @param fn a function
*/
/**
* Set the function to be called
* when the control receives a touch event.
*
* @param {?} fn a function
* @return {?}
*/
NgxEditorComponent.prototype.registerOnTouched = /**
* Set the function to be called
* when the control receives a touch event.
*
* @param {?} fn a function
* @return {?}
*/
function (fn) {
this.onTouched = fn;
};
/**
* refresh view/HTML of the editor
*
* @param value html string from the editor
*/
/**
* refresh view/HTML of the editor
*
* @param {?} value html string from the editor
* @return {?}
*/
NgxEditorComponent.prototype.refreshView = /**
* refresh view/HTML of the editor
*
* @param {?} value html string from the editor
* @return {?}
*/
function (value) {
/** @type {?} */
var normalizedValue = value === null ? '' : value;
this._renderer.setProperty(this.textArea.nativeElement, 'innerHTML', normalizedValue);
};
/**
* toggle between codeview and editor
*/
/**
* toggle between codeview and editor
* @return {?}
*/
NgxEditorComponent.prototype.toggleCodeEditor = /**
* toggle between codeview and editor
* @return {?}
*/
function () {
this.codeEditorMode = !this.codeEditorMode;
if (this.codeEditorMode) {
this.ngxCodeMirror = CodeMirror.fromTextArea(this.codeEditor.nativeElement, codeMirrorConfig);
/** set value of the code editor */
this.ngxCodeMirror.setValue(this.textArea.nativeElement.innerHTML);
/** sets height of the code editor as same as the height of the textArea */
this.ngxCodeMirror.setSize('100%', this.height);
}
else {
/** remove/ destroy code editor */
this.ngxCodeMirror.toTextArea();
/** update the model value and html content on the contenteditable */
this.refreshView(this.ngxCodeMirror.getValue());
this.onContentChange(this.ngxCodeMirror.getValue());
}
return;
};
/**
* toggles placeholder based on input string
*
* @param value A HTML string from the editor
*/
/**
* toggles placeholder based on input string
*
* @param {?} value A HTML string from the editor
* @return {?}
*/
NgxEditorComponent.prototype.togglePlaceholder = /**
* toggles placeholder based on input string
*
* @param {?} value A HTML string from the editor
* @return {?}
*/
function (value) {
if (!value || value === '<br>' || value === '') {
this._renderer.addClass(this.ngxWrapper.nativeElement, 'show-placeholder');
}
else {
this._renderer.removeClass(this.ngxWrapper.nativeElement, 'show-placeholder');
}
};
/**
* returns a json containing input params
*/
/**
* returns a json containing input params
* @return {?}
*/
NgxEditorComponent.prototype.getCollectiveParams = /**
* returns a json containing input params
* @return {?}
*/
function () {
return {
editable: this.editable,
spellcheck: this.spellcheck,
placeholder: this.placeholder,
translate: this.translate,
height: this.height,
minHeight: this.minHeight,
width: this.width,
minWidth: this.minWidth,
enableToolbar: this.enableToolbar,
showToolbar: this.showToolbar,
imageEndPoint: this.imageEndPoint,
toolbar: this.toolbar
};
};
/**
* @return {?}
*/
NgxEditorComponent.prototype.ngOnInit = /**
* @return {?}
*/
function () {
/**
* set configuartion
*/
this.config = this.Utils.getEditorConfiguration(this.config, ngxEditorConfig, this.getCollectiveParams());
this.height = this.height || this.textArea.nativeElement.offsetHeight;
this.executeCommand('enableObjectResizing');
};
/**
* @param {?} event
* @return {?}
*/
NgxEditorComponent.prototype.chooseImageGalleryFunc = /**
* @param {?} event
* @return {?}
*/
function (event) {
this.chooseImageGallery.emit(event);
};
NgxEditorComponent.decorators = [
{ type: Component, args: [{
selector: 'app-ngx-editor',
template: "<div class=\"ngx-editor\"\n id=\"ngxEditor\"\n [style.width]=\"config['width']\"\n [style.minWidth]=\"config['minWidth']\" tabindex=\"0\"\n (focus)=\"onEditorFocus()\"\n (click)=\"onEditorFocus()\">\n\n <app-ngx-editor-toolbar\n [config]=\"config\"\n (execute)=\"executeCommand($event)\"\n (chooseImageGallery)=\"chooseImageGalleryFunc($event)\"\n ></app-ngx-editor-toolbar>\n\n <!-- text area -->\n <div class=\"ngx-wrapper\" [hidden]=\"codeEditorMode\" #ngxWrapper>\n <div class=\"ngx-editor-textarea\" [attr.contenteditable]=\"config['editable']\" (input)=\"onContentChange($event.target.innerHTML)\"\n [attr.translate]=\"config['translate']\" [attr.spellcheck]=\"config['spellcheck']\" [style.height]=\"config['height']\"\n [style.minHeight]=\"config['minHeight']\" [style.resize]=\"Utils?.canResize(resizer)\" (focus)=\"onTextAreaFocus()\"\n (blur)=\"onTextAreaBlur()\" #ngxTextArea></div>\n\n <span class=\"ngx-editor-placeholder\">{{ placeholder || config['placeholder'] }}</span>\n </div>\n\n <textarea [attr.placeholder]=\"placeholder || config['placeholder']\" [hidden]=\"true\" #ngxCodeEditor></textarea>\n\n <app-ngx-editor-message></app-ngx-editor-message>\n <app-ngx-grippie *ngIf=\"resizer === 'stack'\"></app-ngx-grippie>\n\n</div>\n",
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(function () { return NgxEditorComponent; }),
multi: true
}],
styles: [".ngx-editor{position:relative}.ngx-editor ::ng-deep [contenteditable=true]:empty:before{content:attr(placeholder);display:block;color:#868e96;opacity:1}.ngx-editor .ngx-wrapper{position:relative}.ngx-editor .ngx-wrapper .ngx-editor-textarea{min-height:5rem;padding:.5rem .8rem 1rem;border:1px solid #ddd;background-color:transparent;overflow-x:hidden;overflow-y:auto;z-index:2;position:relative}.ngx-editor .ngx-wrapper .ngx-editor-textarea.focus,.ngx-editor .ngx-wrapper .ngx-editor-textarea:focus{outline:0}.ngx-editor .ngx-wrapper .ngx-editor-textarea ::ng-deep blockquote{margin-left:1rem;border-left:.2em solid #dfe2e5;padding-left:.5rem}.ngx-editor .ngx-wrapper ::ng-deep p{margin-bottom:0}.ngx-editor .ngx-wrapper .ngx-editor-placeholder{display:none;position:absolute;top:0;padding:.5rem .8rem 1rem .9rem;z-index:1;color:#6c757d;opacity:1}.ngx-editor .ngx-wrapper.show-placeholder .ngx-editor-placeholder{display:block}.ngx-editor ::ng-deep .CodeMirror{border:1px solid #ddd;z-index:2}.ngx-editor ::ng-deep .CodeMirror .CodeMirror-placeholder{color:#6c757d}"]
}] }
];
/** @nocollapse */
NgxEditorComponent.ctorParameters = function () { return [
{ type: MessageService },
{ type: CommandExecutorService },
{ type: Renderer2 }
]; };
NgxEditorComponent.propDecorators = {
editable: [{ type: Input }],
spellcheck: [{ type: Input }],
placeholder: [{ type: Input }],
translate: [{ type: Input }],
height: [{ type: Input }],
minHeight: [{ type: Input }],
width: [{ type: Input }],
minWidth: [{ type: Input }],
toolbar: [{ type: Input }],
resizer: [{ type: Input }],
config: [{ type: Input }],
showToolbar: [{ type: Input }],
enableToolbar: [{ type: Input }],
imageEndPoint: [{ type: Input }],
blur: [{ type: Output }],
focus: [{ type: Output }],
chooseImageGallery: [{ type: Output }],
textArea: [{ type: ViewChild, args: ['ngxTextArea',] }],
codeEditor: [{ type: ViewChild, args: ['ngxCodeEditor',] }],
ngxWrapper: [{ type: ViewChild, args: ['ngxWrapper',] }]
};
return NgxEditorComponent;
}());
export { NgxEditorComponent };
if (false) {
/**
* Specifies weather the textarea to be editable or not
* @type {?}
*/
NgxEditorComponent.prototype.editable;
/**
* The spellcheck property specifies whether the element is to have its spelling and grammar checked or not.
* @type {?}
*/
NgxEditorComponent.prototype.spellcheck;
/**
* Placeholder for the textArea
* @type {?}
*/
NgxEditorComponent.prototype.placeholder;
/**
* The translate property specifies whether the content of an element should be translated or not.
*
* Check https://www.w3schools.com/tags/att_global_translate.asp for more information and browser support
* @type {?}
*/
NgxEditorComponent.prototype.translate;
/**
* Sets height of the editor
* @type {?}
*/
NgxEditorComponent.prototype.height;
/**
* Sets minimum height for the editor
* @type {?}
*/
NgxEditorComponent.prototype.minHeight;
/**
* Sets Width of the editor
* @type {?}
*/
NgxEditorComponent.prototype.width;
/**
* Sets minimum width of the editor
* @type {?}
*/
NgxEditorComponent.prototype.minWidth;
/**
* Toolbar accepts an array which specifies the options to be enabled for the toolbar
*
* Check ngxEditorConfig for toolbar configuration
*
* Passing an empty array will enable all toolbar
* @type {?}
*/
NgxEditorComponent.prototype.toolbar;
/**
* The editor can be resized vertically.
*
* `basic` resizer enables the html5 reszier. Check here https://www.w3schools.com/cssref/css3_pr_resize.asp
*
* `stack` resizer enable a resizer that looks like as if in https://stackoverflow.com
* @type {?}
*/
NgxEditorComponent.prototype.resizer;
/**
* The config property is a JSON object
*
* All avaibale inputs inputs can be provided in the configuration as JSON
* inputs provided directly are considered as top priority
* @type {?}
*/
NgxEditorComponent.prototype.config;
/**
* Weather to show or hide toolbar
* @type {?}
*/
NgxEditorComponent.prototype.showToolbar;
/**
* Weather to enable or disable the toolbar
* @type {?}
*/
NgxEditorComponent.prototype.enableToolbar;
/**
* Endpoint for which the image to be uploaded
* @type {?}
*/
NgxEditorComponent.prototype.imageEndPoint;
/**
* emits `blur` event when focused out from the textarea
* @type {?}
*/
NgxEditorComponent.prototype.blur;
/**
* emits `focus` event when focused in to the textarea
* @type {?}
*/
NgxEditorComponent.prototype.focus;
/** @type {?} */
NgxEditorComponent.prototype.chooseImageGallery;
/** @type {?} */
NgxEditorComponent.prototype.textArea;
/** @type {?} */
NgxEditorComponent.prototype.codeEditor;
/** @type {?} */
NgxEditorComponent.prototype.ngxWrapper;
/** @type {?} */
NgxEditorComponent.prototype.Utils;
/** @type {?} */
NgxEditorComponent.prototype.codeEditorMode;
/** @type {?} */
NgxEditorComponent.prototype.ngxCodeMirror;
/** @type {?} */
NgxEditorComponent.prototype.onChange;
/** @type {?} */
NgxEditorComponent.prototype.onTouched;
/** @type {?} */
NgxEditorComponent.prototype._messageService;
/** @type {?} */
NgxEditorComponent.prototype._commandExecutor;
/** @type {?} */
NgxEditorComponent.prototype._renderer;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWVkaXRvci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtZWRpdG9yLWN1c3RvbS8iLCJzb3VyY2VzIjpbImFwcC9uZ3gtZWRpdG9yL25neC1lZGl0b3IuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUFVLEtBQUssRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUMzQyxZQUFZLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFDcEMsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGlCQUFpQixFQUF3QixNQUFNLGdCQUFnQixDQUFDO0FBQ3pFLE9BQU8sS0FBSyxVQUFVLE1BQU0sWUFBWSxDQUFDO0FBQ3pDLE9BQU8seUNBQXlDLENBQUM7QUFDakQsT0FBTyx3Q0FBd0MsQ0FBQztBQUVoRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUNwRixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFFbkUsT0FBTyxFQUFFLGVBQWUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2pGLE9BQU8sS0FBSyxLQUFLLE1BQU0saUNBQWlDLENBQUM7O0lBa0Z2RDs7OztPQUlHO0lBQ0gsNEJBQ1UsaUJBQ0Esa0JBQ0E7UUFGQSxvQkFBZSxHQUFmLGVBQWU7UUFDZixxQkFBZ0IsR0FBaEIsZ0JBQWdCO1FBQ2hCLGNBQVMsR0FBVCxTQUFTOzs7Ozs7Ozt1QkF6Q0EsT0FBTzs7Ozs7OztzQkFPUixlQUFlOzs7O29CQVNNLElBQUksWUFBWSxFQUFVOzs7O3FCQUV6QixJQUFJLFlBQVksRUFBVTtrQ0FFaEIsSUFBSSxZQUFZLEVBQUU7cUJBTXZELEtBQUs7OEJBQ0QsS0FBSzs2QkFFTyxTQUFTO0tBWUg7SUFFbkM7O09BRUc7Ozs7O0lBQ0gsNENBQWU7Ozs7SUFBZjtRQUNFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE9B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QUFDLHNCQUFzQixDQUFDLENBQUM7S0FDN0M7Ozs7O0lBRUQsbURBQXNCOzs7O0lBQXRCLFVBQXVCLEtBQUs7UUFDMUIsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztLQUNyQzs7Z0JBL1JGLFNBQVMsU0FBQztvQkFDVCxRQUFRLEVBQUUsZ0JBQWdCO29CQUMxQixtekNBQTBDO29CQUUxQyxTQUFTLEVBQUUsQ0FBQzs0QkFDVixPQUFPLEVBQUUsaUJBQWlCOzRCQUMxQixXQUFXLEVBQUUsVUFBVSxDQUFDLGNBQU0sT0FBQSxrQkFBa0IsRUFBbEIsQ0FBa0IsQ0FBQzs0QkFDakQsS0FBSyxFQUFFLElBQUk7eUJBQ1osQ0FBQzs7aUJBQ0g7Ozs7Z0JBZFEsY0FBYztnQkFEZCxzQkFBc0I7Z0JBUGYsU0FBUzs7OzJCQTBCdEIsS0FBSzs2QkFFTCxLQUFLOzhCQUVMLEtBQUs7NEJBTUwsS0FBSzt5QkFFTCxLQUFLOzRCQUVMLEtBQUs7d0JBRUwsS0FBSzsyQkFFTCxLQUFLOzBCQVFMLEtBQUs7MEJBUUwsS0FBSzt5QkFPTCxLQUFLOzhCQUVMLEtBQUs7Z0NBRUwsS0FBSztnQ0FFTCxLQUFLO3VCQUdMLE1BQU07d0JBRU4sTUFBTTtxQ0FFTixNQUFNOzJCQUVOLFNBQVMsU0FBQyxhQUFhOzZCQUN2QixTQUFTLFNBQUMsZUFBZTs2QkFDekIsU0FBUyxTQUFDLFlBQVk7OzZCQXRGekI7O1NBMEJhLGtCQUFrQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCwgT25Jbml0LCBJbnB1dCwgT3V0cHV0LCBWaWV3Q2hpbGQsXG4gIEV2ZW50RW1pdHRlciwgUmVuZGVyZXIyLCBmb3J3YXJkUmVmXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTkdfVkFMVUVfQUNDRVNTT1IsIENvbnRyb2xWYWx1ZUFjY2Vzc29yIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0ICogYXMgQ29kZU1pcnJvciBmcm9tICdjb2RlbWlycm9yJztcbmltcG9ydCAnY29kZW1pcnJvci9hZGRvbi9kaXNwbGF5L3BsYWNlaG9sZGVyLmpzJztcbmltcG9ydCAnY29kZW1pcnJvci9tb2RlL2h0bWxtaXhlZC9odG1sbWl4ZWQuanMnO1xuXG5pbXBvcnQgeyBDb21tYW5kRXhlY3V0b3JTZXJ2aWNlIH0gZnJvbSAnLi9jb21tb24vc2VydmljZXMvY29tbWFuZC1leGVjdXRvci5zZXJ2aWNlJztcbmltcG9ydCB7IE1lc3NhZ2VTZXJ2aWNlIH0gZnJvbSAnLi9jb21tb24vc2VydmljZXMvbWVzc2FnZS5zZXJ2aWNlJztcblxuaW1wb3J0IHsgbmd4RWRpdG9yQ29uZmlnLCBjb2RlTWlycm9yQ29uZmlnIH0gZnJvbSAnLi9jb21tb24vbmd4LWVkaXRvci5kZWZhdWx0cyc7XG5pbXBvcnQgKiBhcyBVdGlscyBmcm9tICcuL2NvbW1vbi91dGlscy9uZ3gtZWRpdG9yLnV0aWxzJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYXBwLW5neC1lZGl0b3InLFxuICB0ZW1wbGF0ZVVybDogJy4vbmd4LWVkaXRvci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL25neC1lZGl0b3IuY29tcG9uZW50LnNjc3MnXSxcbiAgcHJvdmlkZXJzOiBbe1xuICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IE5neEVkaXRvckNvbXBvbmVudCksXG4gICAgbXVsdGk6IHRydWVcbiAgfV1cbn0pXG5cbmV4cG9ydCBjbGFzcyBOZ3hFZGl0b3JDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcbiAgLyoqIFNwZWNpZmllcyB3ZWF0aGVyIHRoZSB0ZXh0YXJlYSB0byBiZSBlZGl0YWJsZSBvciBub3QgKi9cbiAgQElucHV0KCkgZWRpdGFibGU6IGJvb2xlYW47XG4gIC8qKiBUaGUgc3BlbGxjaGVjayBwcm9wZXJ0eSBzcGVjaWZpZXMgd2hldGhlciB0aGUgZWxlbWVudCBpcyB0byBoYXZlIGl0cyBzcGVsbGluZyBhbmQgZ3JhbW1hciBjaGVja2VkIG9yIG5vdC4gKi9cbiAgQElucHV0KCkgc3BlbGxjaGVjazogYm9vbGVhbjtcbiAgLyoqIFBsYWNlaG9sZGVyIGZvciB0aGUgdGV4dEFyZWEgKi9cbiAgQElucHV0KCkgcGxhY2Vob2xkZXI6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSB0cmFuc2xhdGUgcHJvcGVydHkgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIGNvbnRlbnQgb2YgYW4gZWxlbWVudCBzaG91bGQgYmUgdHJhbnNsYXRlZCBvciBub3QuXG4gICAqXG4gICAqIENoZWNrIGh0dHBzOi8vd3d3Lnczc2Nob29scy5jb20vdGFncy9hdHRfZ2xvYmFsX3RyYW5zbGF0ZS5hc3AgZm9yIG1vcmUgaW5mb3JtYXRpb24gYW5kIGJyb3dzZXIgc3VwcG9ydFxuICAgKi9cbiAgQElucHV0KCkgdHJhbnNsYXRlOiBzdHJpbmc7XG4gIC8qKiBTZXRzIGhlaWdodCBvZiB0aGUgZWRpdG9yICovXG4gIEBJbnB1dCgpIGhlaWdodDogc3RyaW5nO1xuICAvKiogU2V0cyBtaW5pbXVtIGhlaWdodCBmb3IgdGhlIGVkaXRvciAqL1xuICBASW5wdXQoKSBtaW5IZWlnaHQ6IHN0cmluZztcbiAgLyoqIFNldHMgV2lkdGggb2YgdGhlIGVkaXRvciAqL1xuICBASW5wdXQoKSB3aWR0aDogc3RyaW5nO1xuICAvKiogU2V0cyBtaW5pbXVtIHdpZHRoIG9mIHRoZSBlZGl0b3IgKi9cbiAgQElucHV0KCkgbWluV2lkdGg6IHN0cmluZztcbiAgLyoqXG4gICAqIFRvb2xiYXIgYWNjZXB0cyBhbiBhcnJheSB3aGljaCBzcGVjaWZpZXMgdGhlIG9wdGlvbnMgdG8gYmUgZW5hYmxlZCBmb3IgdGhlIHRvb2xiYXJcbiAgICpcbiAgICogQ2hlY2sgbmd4RWRpdG9yQ29uZmlnIGZvciB0b29sYmFyIGNvbmZpZ3VyYXRpb25cbiAgICpcbiAgICogUGFzc2luZyBhbiBlbXB0eSBhcnJheSB3aWxsIGVuYWJsZSBhbGwgdG9vbGJhclxuICAgKi9cbiAgQElucHV0KCkgdG9vbGJhcjogT2JqZWN0O1xuICAvKipcbiAgICogVGhlIGVkaXRvciBjYW4gYmUgcmVzaXplZCB2ZXJ0aWNhbGx5LlxuICAgKlxuICAgKiBgYmFzaWNgIHJlc2l6ZXIgZW5hYmxlcyB0aGUgaHRtbDUgcmVzemllci4gQ2hlY2sgaGVyZSBodHRwczovL3d3dy53M3NjaG9vbHMuY29tL2Nzc3JlZi9jc3MzX3ByX3Jlc2l6ZS5hc3BcbiAgICpcbiAgICogYHN0YWNrYCByZXNpemVyIGVuYWJsZSBhIHJlc2l6ZXIgdGhhdCBsb29rcyBsaWtlIGFzIGlmIGluIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb21cbiAgICovXG4gIEBJbnB1dCgpIHJlc2l6ZXIgPSAnc3RhY2snO1xuICAvKipcbiAgICogVGhlIGNvbmZpZyBwcm9wZXJ0eSBpcyBhIEpTT04gb2JqZWN0XG4gICAqXG4gICAqIEFsbCBhdmFpYmFsZSBpbnB1dHMgaW5wdXRzIGNhbiBiZSBwcm92aWRlZCBpbiB0aGUgY29uZmlndXJhdGlvbiBhcyBKU09OXG4gICAqIGlucHV0cyBwcm92aWRlZCBkaXJlY3RseSBhcmUgY29uc2lkZXJlZCBhcyB0b3AgcHJpb3JpdHlcbiAgICovXG4gIEBJbnB1dCgpIGNvbmZpZyA9IG5neEVkaXRvckNvbmZpZztcbiAgLyoqIFdlYXRoZXIgdG8gc2hvdyBvciBoaWRlIHRvb2xiYXIgKi9cbiAgQElucHV0KCkgc2hvd1Rvb2xiYXI6IGJvb2xlYW47XG4gIC8qKiBXZWF0aGVyIHRvIGVuYWJsZSBvciBkaXNhYmxlIHRoZSB0b29sYmFyICovXG4gIEBJbnB1dCgpIGVuYWJsZVRvb2xiYXI6IGJvb2xlYW47XG4gIC8qKiBFbmRwb2ludCBmb3Igd2hpY2ggdGhlIGltYWdlIHRvIGJlIHVwbG9hZGVkICovXG4gIEBJbnB1dCgpIGltYWdlRW5kUG9pbnQ6IHN0cmluZztcblxuICAvKiogZW1pdHMgYGJsdXJgIGV2ZW50IHdoZW4gZm9jdXNlZCBvdXQgZnJvbSB0aGUgdGV4dGFyZWEgKi9cbiAgQE91dHB1dCgpIGJsdXI6IEV2ZW50RW1pdHRlcjxzdHJpbmc+ID0gbmV3IEV2ZW50RW1pdHRlcjxzdHJpbmc+KCk7XG4gIC8qKiBlbWl0cyBgZm9jdXNgIGV2ZW50IHdoZW4gZm9jdXNlZCBpbiB0byB0aGUgdGV4dGFyZWEgKi9cbiAgQE91dHB1dCgpIGZvY3VzOiBFdmVudEVtaXR0ZXI8c3RyaW5nPiA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuXG4gIEBPdXRwdXQoKSBjaG9vc2VJbWFnZUdhbGxlcnk6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG4gIEBWaWV3Q2hpbGQoJ25neFRleHRBcmVhJykgdGV4dEFyZWE6IGFueTtcbiAgQFZpZXdDaGlsZCgnbmd4Q29kZUVkaXRvcicpIGNvZGVFZGl0b3I6IGFueTtcbiAgQFZpZXdDaGlsZCgnbmd4V3JhcHBlcicpIG5neFdyYXBwZXI6IGFueTtcblxuICBVdGlsczogYW55ID0gVXRpbHM7XG4gIGNvZGVFZGl0b3JNb2RlID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBuZ3hDb2RlTWlycm9yOiBhbnkgPSB1bmRlZmluZWQ7XG4gIHByaXZhdGUgb25DaGFuZ2U6ICh2YWx1ZTogc3RyaW5nKSA9PiB2b2lkO1xuICBwcml2YXRlIG9uVG91Y2hlZDogKCkgPT4gdm9pZDtcblxuICAvKipcbiAgICogQHBhcmFtIF9tZXNzYWdlU2VydmljZSBzZXJ2aWNlIHRvIHNlbmQgbWVzc2FnZSB0byB0aGUgZWRpdG9yIG1lc3NhZ2UgY29tcG9uZW50XG4gICAqIEBwYXJhbSBfY29tbWFuZEV4ZWN1dG9yIGV4ZWN1dGVzIGNvbW1hbmQgZnJvbSB0aGUgdG9vbGJhclxuICAgKiBAcGFyYW0gX3JlbmRlcmVyIGFjY2VzcyBhbmQgbWFuaXB1bGF0ZSB0aGUgZG9tIGVsZW1lbnRcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgX21lc3NhZ2VTZXJ2aWNlOiBNZXNzYWdlU2VydmljZSxcbiAgICBwcml2YXRlIF9jb21tYW5kRXhlY3V0b3I6IENvbW1hbmRFeGVjdXRvclNlcnZpY2UsXG4gICAgcHJpdmF0ZSBfcmVuZGVyZXI6IFJlbmRlcmVyMikgeyB9XG5cbiAgLyoqXG4gICAqIGV2ZW50c1xuICAgKi9cbiAgb25UZXh0QXJlYUZvY3VzKCk6IHZvaWQge1xuICAgIHRoaXMuZm9jdXMuZW1pdCgnZm9jdXMnKTtcbiAgfVxuXG4gIC8qKiBmb2N1cyB0aGUgdGV4dCBhcmVhIHdoZW4gdGhlIGVkaXRvciBpcyBmb2N1c3NlZCAqL1xuICBvbkVkaXRvckZvY3VzKCkge1xuICAgIHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudC5mb2N1cygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGVkIGZyb20gdGhlIGNvbnRlbnRlZGl0YWJsZSBzZWN0aW9uIHdoaWxlIHRoZSBpbnB1dCBwcm9wZXJ0eSBjaGFuZ2VzXG4gICAqIEBwYXJhbSBodG1sIGh0bWwgc3RyaW5nIGZyb20gY29udGVudGVkaXRhYmxlXG4gICAqL1xuICBvbkNvbnRlbnRDaGFuZ2UoaW5uZXJIVE1MOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAodHlwZW9mIHRoaXMub25DaGFuZ2UgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHRoaXMub25DaGFuZ2UoaW5uZXJIVE1MKTtcbiAgICAgIHRoaXMudG9nZ2xlUGxhY2Vob2xkZXIoaW5uZXJIVE1MKTtcbiAgICB9XG4gIH1cblxuICBvblRleHRBcmVhQmx1cigpOiB2b2lkIHtcbiAgICAvKiogc2F2ZSBzZWxlY3Rpb24gaWYgZm9jdXNzZWQgb3V0ICovXG4gICAgdGhpcy5fY29tbWFuZEV4ZWN1dG9yLnNhdmVkU2VsZWN0aW9uID0gVXRpbHMuc2F2ZVNlbGVjdGlvbigpO1xuXG4gICAgaWYgKHR5cGVvZiB0aGlzLm9uVG91Y2hlZCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgICB9XG4gICAgdGhpcy5ibHVyLmVtaXQoJ2JsdXInKTtcbiAgfVxuXG4gIC8qKlxuICAgKiByZXNpemluZyB0ZXh0IGFyZWFcbiAgICpcbiAgICogQHBhcmFtIG9mZnNldFkgdmVydGljYWwgaGVpZ2h0IG9mIHRoZSBlaWR0YWJsZSBwb3J0aW9uIG9mIHRoZSBlZGl0b3JcbiAgICovXG4gIHJlc2l6ZVRleHRBcmVhKG9mZnNldFk6IG51bWJlcik6IHZvaWQge1xuICAgIGxldCBuZXdIZWlnaHQgPSBwYXJzZUludCh0aGlzLmhlaWdodCwgMTApO1xuICAgIG5ld0hlaWdodCArPSBvZmZzZXRZO1xuICAgIHRoaXMuaGVpZ2h0ID0gbmV3SGVpZ2h0ICsgJ3B4JztcbiAgICB0aGlzLnRleHRBcmVhLm5hdGl2ZUVsZW1lbnQuc3R5bGUuaGVpZ2h0ID0gdGhpcy5oZWlnaHQ7XG5cbiAgICAvKipcbiAgICAgKiB1cGRhdGUgY29kZS1lZGl0b3IgaGVpZ2h0IG9ubHkgb24gZWRpdG9yIG1vZGVcbiAgICAgKi9cbiAgICBpZiAodGhpcy5jb2RlRWRpdG9yTW9kZSkge1xuICAgICAgdGhpcy5uZ3hDb2RlTWlycm9yLnNldFNpemUoJzEwMCUnLCB0aGlzLmhlaWdodCk7XG4gICAgfVxuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLyoqXG4gICAqIGVkaXRvciBhY3Rpb25zLCBpLmUuLCBleGVjdXRlcyBjb21tYW5kIGZyb20gdG9vbGJhclxuICAgKlxuICAgKiBAcGFyYW0gY29tbWFuZE5hbWUgbmFtZSBvZiB0aGUgY29tbWFuZCB0byBiZSBleGVjdXRlZFxuICAgKi9cbiAgZXhlY3V0ZUNvbW1hbmQoY29tbWFuZE5hbWU6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmIChjb21tYW5kTmFtZSA9PT0gJ3JlZnJlc2gnKSB7XG4gICAgICBjb25zdCB2YWx1ZSA9IHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudC5pbm5lckhUTUw7XG4gICAgICB0aGlzLm9uQ29udGVudENoYW5nZSh2YWx1ZSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChjb21tYW5kTmFtZSA9PT0gJ2NvZGUnKSB7XG4gICAgICB0aGlzLnRvZ2dsZUNvZGVFZGl0b3IoKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgdGhpcy5fY29tbWFuZEV4ZWN1dG9yLmV4ZWN1dGUoY29tbWFuZE5hbWUpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLl9tZXNzYWdlU2VydmljZS5zZW5kTWVzc2FnZShlcnJvci5tZXNzYWdlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogV3JpdGUgYSBuZXcgdmFsdWUgdG8gdGhlIGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSB2YWx1ZSB0byBiZSBleGVjdXRlZCB3aGVuIHRoZXJlIGlzIGEgY2hhbmdlIGluIGNvbnRlbnRlZGl0YWJsZVxuICAgKi9cbiAgd3JpdGVWYWx1ZSh2YWx1ZTogYW55KTogdm9pZCB7XG4gICAgdGhpcy50b2dnbGVQbGFjZWhvbGRlcih2YWx1ZSk7XG5cbiAgICBpZiAodmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gJycgfHwgdmFsdWUgPT09ICc8YnI+Jykge1xuICAgICAgdmFsdWUgPSBudWxsO1xuICAgIH1cblxuICAgIHRoaXMucmVmcmVzaFZpZXcodmFsdWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkXG4gICAqIHdoZW4gdGhlIGNvbnRyb2wgcmVjZWl2ZXMgYSBjaGFuZ2UgZXZlbnQuXG4gICAqXG4gICAqIEBwYXJhbSBmbiBhIGZ1bmN0aW9uXG4gICAqL1xuICByZWdpc3Rlck9uQ2hhbmdlKGZuOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLm9uQ2hhbmdlID0gZm47XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBmdW5jdGlvbiB0byBiZSBjYWxsZWRcbiAgICogd2hlbiB0aGUgY29udHJvbCByZWNlaXZlcyBhIHRvdWNoIGV2ZW50LlxuICAgKlxuICAgKiBAcGFyYW0gZm4gYSBmdW5jdGlvblxuICAgKi9cbiAgcmVnaXN0ZXJPblRvdWNoZWQoZm46IGFueSk6IHZvaWQge1xuICAgIHRoaXMub25Ub3VjaGVkID0gZm47XG4gIH1cblxuICAvKipcbiAgICogcmVmcmVzaCB2aWV3L0hUTUwgb2YgdGhlIGVkaXRvclxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgaHRtbCBzdHJpbmcgZnJvbSB0aGUgZWRpdG9yXG4gICAqL1xuICByZWZyZXNoVmlldyh2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3Qgbm9ybWFsaXplZFZhbHVlID0gdmFsdWUgPT09IG51bGwgPyAnJyA6IHZhbHVlO1xuICAgIHRoaXMuX3JlbmRlcmVyLnNldFByb3BlcnR5KHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudCwgJ2lubmVySFRNTCcsIG5vcm1hbGl6ZWRWYWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogdG9nZ2xlIGJldHdlZW4gY29kZXZpZXcgYW5kIGVkaXRvclxuICAgKi9cbiAgdG9nZ2xlQ29kZUVkaXRvcigpOiB2b2lkIHtcbiAgICB0aGlzLmNvZGVFZGl0b3JNb2RlID0gIXRoaXMuY29kZUVkaXRvck1vZGU7XG5cbiAgICBpZiAodGhpcy5jb2RlRWRpdG9yTW9kZSkge1xuXG4gICAgICB0aGlzLm5neENvZGVNaXJyb3IgPSBDb2RlTWlycm9yLmZyb21UZXh0QXJlYSh0aGlzLmNvZGVFZGl0b3IubmF0aXZlRWxlbWVudCwgY29kZU1pcnJvckNvbmZpZyk7XG5cbiAgICAgIC8qKiBzZXQgdmFsdWUgb2YgdGhlIGNvZGUgZWRpdG9yICovXG4gICAgICB0aGlzLm5neENvZGVNaXJyb3Iuc2V0VmFsdWUodGhpcy50ZXh0QXJlYS5uYXRpdmVFbGVtZW50LmlubmVySFRNTCk7XG5cbiAgICAgIC8qKiBzZXRzIGhlaWdodCBvZiB0aGUgY29kZSBlZGl0b3IgYXMgc2FtZSBhcyB0aGUgaGVpZ2h0IG9mIHRoZSB0ZXh0QXJlYSAqL1xuICAgICAgdGhpcy5uZ3hDb2RlTWlycm9yLnNldFNpemUoJzEwMCUnLCB0aGlzLmhlaWdodCk7XG5cbiAgICB9IGVsc2Uge1xuXG4gICAgICAvKiogcmVtb3ZlLyBkZXN0cm95IGNvZGUgZWRpdG9yICovXG4gICAgICB0aGlzLm5neENvZGVNaXJyb3IudG9UZXh0QXJlYSgpO1xuXG4gICAgICAvKiogdXBkYXRlIHRoZSBtb2RlbCB2YWx1ZSBhbmQgaHRtbCBjb250ZW50IG9uIHRoZSBjb250ZW50ZWRpdGFibGUgKi9cbiAgICAgIHRoaXMucmVmcmVzaFZpZXcodGhpcy5uZ3hDb2RlTWlycm9yLmdldFZhbHVlKCkpO1xuICAgICAgdGhpcy5vbkNvbnRlbnRDaGFuZ2UodGhpcy5uZ3hDb2RlTWlycm9yLmdldFZhbHVlKCkpO1xuXG4gICAgfVxuICAgIHJldHVybjtcbiAgfVxuXG4gIC8qKlxuICAgKiB0b2dnbGVzIHBsYWNlaG9sZGVyIGJhc2VkIG9uIGlucHV0IHN0cmluZ1xuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgQSBIVE1MIHN0cmluZyBmcm9tIHRoZSBlZGl0b3JcbiAgICovXG4gIHRvZ2dsZVBsYWNlaG9sZGVyKHZhbHVlOiBhbnkpOiB2b2lkIHtcbiAgICBpZiAoIXZhbHVlIHx8IHZhbHVlID09PSAnPGJyPicgfHwgdmFsdWUgPT09ICcnKSB7XG4gICAgICB0aGlzLl9yZW5kZXJlci5hZGRDbGFzcyh0aGlzLm5neFdyYXBwZXIubmF0aXZlRWxlbWVudCwgJ3Nob3ctcGxhY2Vob2xkZXInKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fcmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5uZ3hXcmFwcGVyLm5hdGl2ZUVsZW1lbnQsICdzaG93LXBsYWNlaG9sZGVyJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIHJldHVybnMgYSBqc29uIGNvbnRhaW5pbmcgaW5wdXQgcGFyYW1zXG4gICAqL1xuICBnZXRDb2xsZWN0aXZlUGFyYW1zKCk6IGFueSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGVkaXRhYmxlOiB0aGlzLmVkaXRhYmxlLFxuICAgICAgc3BlbGxjaGVjazogdGhpcy5zcGVsbGNoZWNrLFxuICAgICAgcGxhY2Vob2xkZXI6IHRoaXMucGxhY2Vob2xkZXIsXG4gICAgICB0cmFuc2xhdGU6IHRoaXMudHJhbnNsYXRlLFxuICAgICAgaGVpZ2h0OiB0aGlzLmhlaWdodCxcbiAgICAgIG1pbkhlaWdodDogdGhpcy5taW5IZWlnaHQsXG4gICAgICB3aWR0aDogdGhpcy53aWR0aCxcbiAgICAgIG1pbldpZHRoOiB0aGlzLm1pbldpZHRoLFxuICAgICAgZW5hYmxlVG9vbGJhcjogdGhpcy5lbmFibGVUb29sYmFyLFxuICAgICAgc2hvd1Rvb2xiYXI6IHRoaXMuc2hvd1Rvb2xiYXIsXG4gICAgICBpbWFnZUVuZFBvaW50OiB0aGlzLmltYWdlRW5kUG9pbnQsXG4gICAgICB0b29sYmFyOiB0aGlzLnRvb2xiYXJcbiAgICB9O1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgLyoqXG4gICAgICogc2V0IGNvbmZpZ3VhcnRpb25cbiAgICAgKi9cbiAgICB0aGlzLmNvbmZpZyA9IHRoaXMuVXRpbHMuZ2V0RWRpdG9yQ29uZmlndXJhdGlvbih0aGlzLmNvbmZpZywgbmd4RWRpdG9yQ29uZmlnLCB0aGlzLmdldENvbGxlY3RpdmVQYXJhbXMoKSk7XG5cbiAgICB0aGlzLmhlaWdodCA9IHRoaXMuaGVpZ2h0IHx8IHRoaXMudGV4dEFyZWEubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQ7XG5cbiAgICB0aGlzLmV4ZWN1dGVDb21tYW5kKCdlbmFibGVPYmplY3RSZXNpemluZycpO1xuICB9XG5cbiAgY2hvb3NlSW1hZ2VHYWxsZXJ5RnVuYyhldmVudCkge1xuICAgIHRoaXMuY2hvb3NlSW1hZ2VHYWxsZXJ5LmVtaXQoZXZlbnQpO1xuICB9XG59XG4iXX0=