@kephas/angular-ace
Version:
Provides the integration of the Ace editor with Kephas and Angular.
363 lines • 36.7 kB
JavaScript
import { ValueEditorBase, provideWidget, provideValueAccessor } from '@kephas/angular';
import { ViewContainerRef, ElementRef, Component, Input } from '@angular/core';
import { edit } from 'brace';
import 'brace/theme/monokai';
import 'brace/mode/abap';
import 'brace/mode/lua';
import 'brace/mode/sh';
import 'brace/mode/sql';
import 'brace/mode/powershell';
import 'brace/mode/text';
import 'brace/mode/json';
/**
* Value editor based on Ace.
*
* @export
* @class AceComponent
* @extends {(ValueEditorBase<string | {} | null>)}
*/
export class AceComponent extends ValueEditorBase {
/**
* Creates an instance of AceComponent.
*
* @param {ElementRef} elementRef The element reference.
* @param {ViewContainerRef} viewContainerRef The view container reference.
* @memberof AceComponent
*/
constructor(elementRef, viewContainerRef) {
super(elementRef, viewContainerRef);
this._theme = 'monokai';
this._editorType = 'json';
this._valueIsObject = false;
}
/**
* Gets or sets the editor type.
*
* @type {string}
* @memberof AceComponent
*/
get editorType() {
return this._editorType;
}
set editorType(value) {
if (this._editorType === value) {
return;
}
this._editorType = value;
this.setEditorType(value);
}
/**
* Gets or sets the editor options.
*
* @memberof AceComponent
*/
set options(value) {
if (this.editor) {
this.editor.setOptions(value || {});
}
}
get options() {
return this.editor && this.editor.getOptions();
}
/**
* Gets or sets the editor theme.
*
* @type {string}
* @memberof AceComponent
*/
get theme() {
return this._theme;
}
set theme(value) {
if (this._theme === value) {
return;
}
this._theme = value;
this.setEditorTheme(value);
}
/**
* Gets or sets a value indicating whether the bound value is an object or not.
*
* @readonly
* @type {boolean}
* @memberof AceComponent
*/
get valueIsObject() {
return this._valueIsObject;
}
set valueIsObject(value) {
this._valueIsObject = value;
}
/**
* A callback method that is invoked immediately after the
* default change detector has checked the directive's
* data-bound properties for the first time,
* and before any of the view or content children have been checked.
* It is invoked only once when the directive is instantiated.
*
* @memberof AceComponent
*/
ngOnInit() {
super.ngOnInit();
const hostElement = this.elementRef.nativeElement.children[0];
this.editor = edit(hostElement);
this.editor.setShowPrintMargin(false);
this.setEditorTheme(this._theme);
this.setEditorType(this._editorType);
this.setEditorReadOnly(this.readonly);
this.setEditorValue(this.value);
this.editor.on('change', e => this.onEditorChange(e));
this.editor.on('paste', e => this.onEditorChange(e));
this.editor.commands.addCommand({
name: 'formatDocumentCommand',
bindKey: { win: 'Ctrl-Shift-F', mac: 'Command-Shift-F' },
exec: (e) => {
this.formatDocument();
}
});
}
/**
* A callback method that is invoked immediately after
* Angular has completed initialization of a component's view.
* It is invoked only once when the view is instantiated.
*
* @memberof AceComponent
*/
ngAfterViewInit() {
super.ngAfterViewInit();
if (!this.observeVisibilityOf) {
return;
}
this.observeVisibility(this.observeVisibilityOf);
}
/**
* A callback method that performs custom clean-up, invoked immediately
* after a directive, pipe, or service instance is destroyed.
*
* @memberof AceComponent
*/
ngOnDestroy() {
super.ngOnDestroy();
if (this._observer) {
this._observer.disconnect();
}
}
/**
* Observes the visibility of the elements in the query string,
* and if they are visible, it will trigger an editor resize.
* This is required to fix a problem in the ACE editor when
* setValue doesn't work if the editor is hidden.
*
* See also https://github.com/ajaxorg/ace/issues/3070.
* See also https://github.com/Starcounter/Content/commit/91a757d8750523431fc1637fdf57409d0fcb13db.
*
* @param {string} queryString
* @memberof ScriptEditorComponent
*/
observeVisibility(queryStrings) {
if (this._observer) {
this._observer.disconnect();
}
if (typeof queryStrings === 'string') {
queryStrings = [queryStrings];
}
this._observer = new MutationObserver(mutations => {
const changedTargets = [];
mutations.forEach(mutationRecord => {
if (changedTargets.findIndex(e => e === mutationRecord.target) < 0) {
changedTargets.push(mutationRecord.target);
}
});
changedTargets.forEach(t => {
if (this._isAceVisible(t) && this.editor) {
this.editor.resize(true);
}
});
});
for (const queryString of queryStrings) {
const query = top.document.querySelectorAll(queryString);
for (let i = 0; i < query.length; i++) {
this._observer.observe(query[i], { attributes: true, attributeFilter: ['style'] });
}
}
}
/**
* Formats the JSON document inside the editor.
*
* @protected
* @returns
* @memberof AceComponent
*/
formatDocument() {
if (!this.editor) {
return;
}
if (this.editorType.toLowerCase() === 'json') {
let stringValue = this.editor.getValue();
try {
const objectValue = JSON.parse(stringValue);
stringValue = this._getFormattedJson(objectValue);
this.editor.setValue(stringValue);
}
catch (error) {
// too bad we could not format
this.notification.notifyWarning(error);
}
}
}
/**
* Sets the value of the underlying editor.
*
* @protected
* @param {string | {} | null} value
* @memberof ValueEditorBase
*/
setEditorValue(value) {
if (!this.editor) {
return;
}
let stringValue = '';
if (typeof value === 'object') {
this._valueIsObject = true;
stringValue = this._getFormattedJson(value);
}
else if (typeof value === 'string') {
if (value) {
this._valueIsObject = false;
}
stringValue = value;
}
else {
stringValue = value && value.toString();
}
this.editor.setValue(stringValue || '');
this.editor.clearSelection();
}
/**
* Gets the underlying editor's value.
*
* @protected
* @returns {string | {} | null} The widget value.
* @memberof ValueEditorBase
*/
getEditorValue() {
if (!this.editor) {
return null;
}
const stringValue = this.editor.getValue();
if (this._valueIsObject) {
if (!stringValue) {
return stringValue;
}
try {
const objectValue = JSON.parse(stringValue);
return objectValue;
}
catch (error) {
return stringValue;
}
}
return stringValue;
}
/**
* When overridden in a derived class, this method is called when the read only state changes.
*
* @protected
* @param {boolean} oldValue The old value.
* @param {boolean} newValue The new value.
*
* @memberof EditorBase
*/
onReadOnlyChanged(oldValue, newValue) {
if (this.editor) {
this.setEditorReadOnly(newValue);
}
}
/**
* Sets the readonly state of the editor.
*
* @protected
* @param {boolean} value
* @memberof AceComponent
*/
setEditorReadOnly(value) {
if (this.editor) {
this.editor.setReadOnly(value);
}
}
/**
* Sets the editor theme.
*
* @protected
* @param {string} theme
* @memberof AceComponent
*/
setEditorTheme(theme) {
if (this.editor && theme) {
this.editor.setTheme(`ace/theme/${theme}`);
}
}
/**
* Sets the editor type.
*
* @protected
* @param {string} editorType
* @memberof AceComponent
*/
setEditorType(editorType) {
if (this.editor && editorType) {
const mode = this.getEditorMode(editorType);
this.editor.getSession().setMode(`ace/mode/${mode}`);
this.editor.$blockScrolling = Infinity;
}
}
/**
* Gets the editor mode based on the provided editor type.
*
* @protected
* @param {string} editorType The editor type.
* @returns {string}
* @memberof AceComponent
*/
getEditorMode(editorType) {
return editorType;
}
/**
* Updates the underlying editor with the provided value.
*
* @protected
* @param {TValue} value The value to be set in the underlying component.
* @returns {boolean}
* @memberof AceComponent
*/
updateEditor(value) {
value = value || '';
return super.updateEditor(value);
}
_getFormattedJson(obj) {
return JSON.stringify(obj, null, 4);
}
_isAceVisible(element) {
const style = window.getComputedStyle(element);
return !(style.display === 'none');
}
}
AceComponent.decorators = [
{ type: Component, args: [{
selector: 'ace',
template: `<div class="form-control ace"></div>`,
providers: [provideWidget(AceComponent), provideValueAccessor(AceComponent)]
},] }
];
AceComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: ViewContainerRef }
];
AceComponent.propDecorators = {
observeVisibilityOf: [{ type: Input }],
editorType: [{ type: Input }],
options: [{ type: Input }],
theme: [{ type: Input }],
valueIsObject: [{ type: Input }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLWFjZS9zcmMvIiwic291cmNlcyI6WyJsaWIvY29tcG9uZW50cy9hY2UuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDSCxlQUFlLEVBQUUsYUFBYSxFQUFFLG9CQUFvQixFQUN2RCxNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFDSCxnQkFBZ0IsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFFakQsTUFBTSxlQUFlLENBQUE7QUFFdEIsT0FBTyxFQUFVLElBQUksRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUVyQyxPQUFPLHFCQUFxQixDQUFDO0FBRTdCLE9BQU8saUJBQWlCLENBQUM7QUFDekIsT0FBTyxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLGVBQWUsQ0FBQztBQUN2QixPQUFPLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLGlCQUFpQixDQUFDO0FBRXpCOzs7Ozs7R0FNRztBQU1ILE1BQU0sT0FBTyxZQUFhLFNBQVEsZUFBbUM7SUFlakU7Ozs7OztPQU1HO0lBQ0gsWUFDSSxVQUFzQixFQUN0QixnQkFBa0M7UUFFbEMsS0FBSyxDQUFDLFVBQVUsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1FBaEJoQyxXQUFNLEdBQUcsU0FBUyxDQUFDO1FBQ25CLGdCQUFXLEdBQVcsTUFBTSxDQUFDO1FBQzdCLG1CQUFjLEdBQUcsS0FBSyxDQUFDO0lBZS9CLENBQUM7SUFXRDs7Ozs7T0FLRztJQUNILElBQ0ksVUFBVTtRQUNWLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUM1QixDQUFDO0lBQ0QsSUFBSSxVQUFVLENBQUMsS0FBYTtRQUN4QixJQUFJLElBQUksQ0FBQyxXQUFXLEtBQUssS0FBSyxFQUFFO1lBQzVCLE9BQU87U0FDVjtR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LE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMvQyxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxLQUFLLE1BQU0sQ0FBQyxDQUFBO0lBQ3RDLENBQUM7OztZQW5ZSixTQUFTLFNBQUM7Z0JBQ1AsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsUUFBUSxFQUFFLHNDQUFzQztnQkFDaEQsU0FBUyxFQUFFLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxFQUFFLG9CQUFvQixDQUFDLFlBQVksQ0FBQyxDQUFDO2FBQy9FOzs7WUEzQnFCLFVBQVU7WUFBNUIsZ0JBQWdCOzs7a0NBK0RmLEtBQUs7eUJBU0wsS0FBSztzQkFrQkwsS0FBSztvQkFlTCxLQUFLOzRCQW9CTCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICAgIFZhbHVlRWRpdG9yQmFzZSwgcHJvdmlkZVdpZGdldCwgcHJvdmlkZVZhbHVlQWNjZXNzb3JcclxufSBmcm9tICdAa2VwaGFzL2FuZ3VsYXInO1xyXG5pbXBvcnQge1xyXG4gICAgVmlld0NvbnRhaW5lclJlZiwgRWxlbWVudFJlZiwgQ29tcG9uZW50LCBJbnB1dCwgT25Jbml0LFxyXG4gICAgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95XHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSdcclxuXHJcbmltcG9ydCB7IEVkaXRvciwgZWRpdCB9IGZyb20gJ2JyYWNlJztcclxuXHJcbmltcG9ydCAnYnJhY2UvdGhlbWUvbW9ub2thaSc7XHJcblxyXG5pbXBvcnQgJ2JyYWNlL21vZGUvYWJhcCc7XHJcbmltcG9ydCAnYnJhY2UvbW9kZS9sdWEnO1xyXG5pbXBvcnQgJ2JyYWNlL21vZGUvc2gnO1xyXG5pbXBvcnQgJ2JyYWNlL21vZGUvc3FsJztcclxuaW1wb3J0ICdicmFjZS9tb2RlL3Bvd2Vyc2hlbGwnO1xyXG5pbXBvcnQgJ2JyYWNlL21vZGUvdGV4dCc7XHJcbmltcG9ydCAnYnJhY2UvbW9kZS9qc29uJztcclxuXHJcbi8qKlxyXG4gKiBWYWx1ZSBlZGl0b3IgYmFzZWQgb24gQWNlLlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBjbGFzcyBBY2VDb21wb25lbnRcclxuICogQGV4dGVuZHMgeyhWYWx1ZUVkaXRvckJhc2U8c3RyaW5nIHwge30gfCBudWxsPil9XHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuICAgIHNlbGVjdG9yOiAnYWNlJyxcclxuICAgIHRlbXBsYXRlOiBgPGRpdiBjbGFzcz1cImZvcm0tY29udHJvbCBhY2VcIj48L2Rpdj5gLFxyXG4gICAgcHJvdmlkZXJzOiBbcHJvdmlkZVdpZGdldChBY2VDb21wb25lbnQpLCBwcm92aWRlVmFsdWVBY2Nlc3NvcihBY2VDb21wb25lbnQpXVxyXG59KVxyXG5leHBvcnQgY2xhc3MgQWNlQ29tcG9uZW50IGV4dGVuZHMgVmFsdWVFZGl0b3JCYXNlPHN0cmluZyB8IHt9IHwgbnVsbD5cclxuICAgIGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xyXG4gICAgLyoqXHJcbiAgICAgKiBHZXRzIG9yIHNldHMgdGhlIEFjZSBlZGl0b3IuXHJcbiAgICAgKlxyXG4gICAgICogQHR5cGUge2FjZS5FZGl0b3J9XHJcbiAgICAgKiBAbWVtYmVyb2YgQWNlQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBlZGl0b3I/OiBFZGl0b3I7XHJcblxyXG4gICAgcHJpdmF0ZSBfdGhlbWUgPSAnbW9ub2thaSc7XHJcbiAgICBwcml2YXRlIF9lZGl0b3JUeXBlOiBzdHJpbmcgPSAnanNvbic7XHJcbiAgICBwcml2YXRlIF92YWx1ZUlzT2JqZWN0ID0gZmFsc2U7XHJcbiAgICBwcml2YXRlIF9vYnNlcnZlcj86IE11dGF0aW9uT2JzZXJ2ZXI7XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIEFjZUNvbXBvbmVudC5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge0VsZW1lbnRSZWZ9IGVsZW1lbnRSZWYgVGhlIGVsZW1lbnQgcmVmZXJlbmNlLlxyXG4gICAgICogQHBhcmFtIHtWaWV3Q29udGFpbmVyUmVmfSB2aWV3Q29udGFpbmVyUmVmIFRoZSB2aWV3IGNvbnRhaW5lciByZWZlcmVuY2UuXHJcbiAgICAgKiBAbWVtYmVyb2YgQWNlQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIGNvbnN0cnVjdG9yKFxyXG4gICAgICAgIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYsXHJcbiAgICAgICAgdmlld0NvbnRhaW5lclJlZjogVmlld0NvbnRhaW5lclJlZixcclxuICAgICkge1xyXG4gICAgICAgIHN1cGVyKGVsZW1lbnRSZWYsIHZpZXdDb250YWluZXJSZWYpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyBvciBzZXRzIGEgdmFsdWUgaW5kaWNhdGluZ1xyXG4gICAgICpcclxuICAgICAqIEB0eXBlIHsoc3RyaW5nIHwgc3RyaW5nW10pfVxyXG4gICAgICogQG1lbWJlcm9mIEFjZUNvbXBvbmVudFxyXG4gICAgICovXHJcbiAgICBASW5wdXQoKVxyXG4gICAgcHVibGljIG9ic2VydmVWaXNpYmlsaXR5T2Y/OiBzdHJpbmcgfCBzdHJpbmdbXTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEdldHMgb3Igc2V0cyB0aGUgZWRpdG9yIHR5cGUuXHJcbiAgICAgKlxyXG4gICAgICogQHR5cGUge3N0cmluZ31cclxuICAgICAqIEBtZW1iZXJvZiBBY2VDb21wb25lbnRcclxuICAgICAqL1xyXG4gICAgQElucHV0KClcclxuICAgIGdldCBlZGl0b3JUeXBlKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2VkaXRvclR5cGU7XHJcbiAgICB9XHJcbiAgICBzZXQgZWRpdG9yVHlwZSh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuX2VkaXRvclR5cGUgPT09IHZhbHVlKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuX2VkaXRvclR5cGUgPSB2YWx1ZTtcclxuICAgICAgICB0aGlzLnNldEVkaXRvclR5cGUodmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyBvciBzZXRzIHRoZSBlZGl0b3Igb3B0aW9ucy5cclxuICAgICAqXHJcbiAgICAgKiBAbWVtYmVyb2YgQWNlQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIEBJbnB1dCgpIHNldCBvcHRpb25zKHZhbHVlOiBhbnkpIHtcclxuICAgICAgICBpZiAodGhpcy5lZGl0b3IpIHtcclxuICAgICAgICAgICAgdGhpcy5lZGl0b3Iuc2V0T3B0aW9ucyh2YWx1ZSB8fCB7fSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgZ2V0IG9wdGlvbnMoKTogYW55IHtcclxuICAgICAgICByZXR1cm4gdGhpcy5lZGl0b3IgJiYgdGhpcy5lZGl0b3IuZ2V0T3B0aW9ucygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyBvciBzZXRzIHRoZSBlZGl0b3IgdGhlbWUuXHJcbiAgICAgKlxyXG4gICAgICogQHR5cGUge3N0cmluZ31cclxuICAgICAqIEBtZW1iZXJvZiBBY2VDb21wb25lbnRcclxuICAgICAqL1xyXG4gICAgQElucHV0KClcclxuICAgIGdldCB0aGVtZSgpOiBzdHJpbmcge1xyXG4gICAgICAgIHJldHVybiB0aGlzLl90aGVtZTtcclxuICAgIH1cclxuICAgIHNldCB0aGVtZSh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICAgICAgaWYgKHRoaXMuX3RoZW1lID09PSB2YWx1ZSkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLl90aGVtZSA9IHZhbHVlO1xyXG4gICAgICAgIHRoaXMuc2V0RWRpdG9yVGhlbWUodmFsdWUpO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyBvciBzZXRzIGEgdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBib3VuZCB2YWx1ZSBpcyBhbiBvYmplY3Qgb3Igbm90LlxyXG4gICAgICpcclxuICAgICAqIEByZWFkb25seVxyXG4gICAgICogQHR5cGUge2Jvb2xlYW59XHJcbiAgICAgKiBAbWVtYmVyb2YgQWNlQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIEBJbnB1dCgpXHJcbiAgICBnZXQgdmFsdWVJc09iamVjdCgpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gdGhpcy5fdmFsdWVJc09iamVjdDtcclxuICAgIH1cclxuICAgIHNldCB2YWx1ZUlzT2JqZWN0KHZhbHVlOiBib29sZWFuKSB7XHJcbiAgICAgICAgdGhpcy5fdmFsdWVJc09iamVjdCA9IHZhbHVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQSBjYWxsYmFjayBtZXRob2QgdGhhdCBpcyBpbnZva2VkIGltbWVkaWF0ZWx5IGFmdGVyIHRoZVxyXG4gICAgICogZGVmYXVsdCBjaGFuZ2UgZGV0ZWN0b3IgaGFzIGNoZWNrZWQgdGhlIGRpcmVjdGl2ZSdzXHJcbiAgICAgKiBkYXRhLWJvdW5kIHByb3BlcnRpZXMgZm9yIHRoZSBmaXJzdCB0aW1lLFxyXG4gICAgICogYW5kIGJlZm9yZSBhbnkgb2YgdGhlIHZpZXcgb3IgY29udGVudCBjaGlsZHJlbiBoYXZlIGJlZW4gY2hlY2tlZC5cclxuICAgICAqIEl0IGlzIGludm9rZWQgb25seSBvbmNlIHdoZW4gdGhlIGRpcmVjdGl2ZSBpcyBpbnN0YW50aWF0ZWQuXHJcbiAgICAgKlxyXG4gICAgICogQG1lbWJlcm9mIEFjZUNvbXBvbmVudFxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICAgICAgc3VwZXIubmdPbkluaXQoKTtcclxuXHJcbiAgICAgICAgY29uc3QgaG9zdEVsZW1lbnQgPSAodGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQgYXMgSFRNTEVsZW1lbnQpLmNoaWxkcmVuWzBdIGFzIEhUTUxFbGVtZW50O1xyXG5cclxuICAgICAgICB0aGlzLmVkaXRvciA9IGVkaXQoaG9zdEVsZW1lbnQpO1xyXG4gICAgICAgIHRoaXMuZWRpdG9yLnNldFNob3dQcmludE1hcmdpbihmYWxzZSk7XHJcbiAgICAgICAgdGhpcy5zZXRFZGl0b3JUaGVtZSh0aGlzLl90aGVtZSk7XHJcbiAgICAgICAgdGhpcy5zZXRFZGl0b3JUeXBlKHRoaXMuX2VkaXRvclR5cGUpO1xyXG4gICAgICAgIHRoaXMuc2V0RWRpdG9yUmVhZE9ubHkodGhpcy5yZWFkb25seSk7XHJcbiAgICAgICAgdGhpcy5zZXRFZGl0b3JWYWx1ZSh0aGlzLnZhbHVlKTtcclxuICAgICAgICB0aGlzLmVkaXRvci5vbignY2hhbmdlJywgZSA9PiB0aGlzLm9uRWRpdG9yQ2hhbmdlKGUpKTtcclxuICAgICAgICB0aGlzLmVkaXRvci5vbigncGFzdGUnLCBlID0+IHRoaXMub25FZGl0b3JDaGFuZ2UoZSkpO1xyXG4gICAgICAgIHRoaXMuZWRpdG9yLmNvbW1hbmRzLmFkZENvbW1hbmQoe1xyXG4gICAgICAgICAgICBuYW1lOiAnZm9ybWF0RG9jdW1lbnRDb21tYW5kJyxcclxuICAgICAgICAgICAgYmluZEtleTogeyB3aW46ICdDdHJsLVNoaWZ0LUYnLCBtYWM6ICdDb21tYW5kLVNoaWZ0LUYnIH0sXHJcbiAgICAgICAgICAgIGV4ZWM6IChlOiBFZGl0b3IpID0+IHtcclxuICAgICAgICAgICAgICAgIHRoaXMuZm9ybWF0RG9jdW1lbnQoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQSBjYWxsYmFjayBtZXRob2QgdGhhdCBpcyBpbnZva2VkIGltbWVkaWF0ZWx5IGFmdGVyXHJcbiAgICAgKiBBbmd1bGFyIGhhcyBjb21wbGV0ZWQgaW5pdGlhbGl6YXRpb24gb2YgYSBjb21wb25lbnQncyB2aWV3LlxyXG4gICAgICogSXQgaXMgaW52b2tlZCBvbmx5IG9uY2Ugd2hlbiB0aGUgdmlldyBpcyBpbnN0YW50aWF0ZWQuXHJcbiAgICAgKlxyXG4gICAgICogQG1lbWJlcm9mIEFjZUNvbXBvbmVudFxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgbmdBZnRlclZpZXdJbml0KCkge1xyXG4gICAgICAgIHN1cGVyLm5nQWZ0ZXJWaWV3SW5pdCgpO1xyXG4gICAgICAgIGlmICghdGhpcy5vYnNlcnZlVmlzaWJpbGl0eU9mKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMub2JzZXJ2ZVZpc2liaWxpdHkodGhpcy5vYnNlcnZlVmlzaWJpbGl0eU9mKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEEgY2FsbGJhY2sgbWV0aG9kIHRoYXQgcGVyZm9ybXMgY3VzdG9tIGNsZWFuLXVwLCBpbnZva2VkIGltbWVkaWF0ZWx5XHJcbiAgICAgKiBhZnRlciBhIGRpcmVjdGl2ZSwgcGlwZSwgb3Igc2VydmljZSBpbnN0YW5jZSBpcyBkZXN0cm95ZWQuXHJcbiAgICAgKlxyXG4gICAgICogQG1lbWJlcm9mIEFjZUNvbXBvbmVudFxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgbmdPbkRlc3Ryb3koKSB7XHJcbiAgICAgICAgc3VwZXIubmdPbkRlc3Ryb3koKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuX29ic2VydmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX29ic2VydmVyLmRpc2Nvbm5lY3QoKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBPYnNlcnZlcyB0aGUgdmlzaWJpbGl0eSBvZiB0aGUgZWxlbWVudHMgaW4gdGhlIHF1ZXJ5IHN0cmluZyxcclxuICAgICAqIGFuZCBpZiB0aGV5IGFyZSB2aXNpYmxlLCBpdCB3aWxsIHRyaWdnZXIgYW4gZWRpdG9yIHJlc2l6ZS5cclxuICAgICAqIFRoaXMgaXMgcmVxdWlyZWQgdG8gZml4IGEgcHJvYmxlbSBpbiB0aGUgQUNFIGVkaXRvciB3aGVuXHJcbiAgICAgKiBzZXRWYWx1ZSBkb2Vzbid0IHdvcmsgaWYgdGhlIGVkaXRvciBpcyBoaWRkZW4uXHJcbiAgICAgKlxyXG4gICAgICogU2VlIGFsc28gaHR0cHM6Ly9naXRodWIuY29tL2FqYXhvcmcvYWNlL2lzc3Vlcy8zMDcwLlxyXG4gICAgICogU2VlIGFsc28gaHR0cHM6Ly9naXRodWIuY29tL1N0YXJjb3VudGVyL0NvbnRlbnQvY29tbWl0LzkxYTc1N2Q4NzUwNTIzNDMxZmMxNjM3ZmRmNTc0MDlkMGZjYjEzZGIuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHF1ZXJ5U3RyaW5nXHJcbiAgICAgKiBAbWVtYmVyb2YgU2NyaXB0RWRpdG9yQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBvYnNlcnZlVmlzaWJpbGl0eShxdWVyeVN0cmluZ3M6IHN0cmluZyB8IHN0cmluZ1tdKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKHRoaXMuX29ic2VydmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX29ic2VydmVyLmRpc2Nvbm5lY3QoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICh0eXBlb2YgcXVlcnlTdHJpbmdzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAgICAgICBxdWVyeVN0cmluZ3MgPSBbcXVlcnlTdHJpbmdzXTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuX29ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIobXV0YXRpb25zID0+IHtcclxuICAgICAgICAgICAgY29uc3QgY2hhbmdlZFRhcmdldHM6IE5vZGVbXSA9IFtdO1xyXG5cclxuICAgICAgICAgICAgbXV0YXRpb25zLmZvckVhY2gobXV0YXRpb25SZWNvcmQgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKGNoYW5nZWRUYXJnZXRzLmZpbmRJbmRleChlID0+IGUgPT09IG11dGF0aW9uUmVjb3JkLnRhcmdldCkgPCAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY2hhbmdlZFRhcmdldHMucHVzaChtdXRhdGlvblJlY29yZC50YXJnZXQpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgIGNoYW5nZWRUYXJnZXRzLmZvckVhY2godCA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5faXNBY2VWaXNpYmxlKHQgYXMgRWxlbWVudCkgJiYgdGhpcy5lZGl0b3IpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmVkaXRvci5yZXNpemUodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICBmb3IgKGNvbnN0IHF1ZXJ5U3RyaW5nIG9mIHF1ZXJ5U3RyaW5ncykge1xyXG4gICAgICAgICAgICBjb25zdCBxdWVyeSA9IHRvcC5kb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKHF1ZXJ5U3RyaW5nKTtcclxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBxdWVyeS5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5fb2JzZXJ2ZXIub2JzZXJ2ZShxdWVyeVtpXSwgeyBhdHRyaWJ1dGVzOiB0cnVlLCBhdHRyaWJ1dGVGaWx0ZXI6IFsnc3R5bGUnXSB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEZvcm1hdHMgdGhlIEpTT04gZG9jdW1lbnQgaW5zaWRlIHRoZSBlZGl0b3IuXHJcbiAgICAgKlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICogQHJldHVybnNcclxuICAgICAqIEBtZW1iZXJvZiBBY2VDb21wb25lbnRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGZvcm1hdERvY3VtZW50KCkge1xyXG4gICAgICAgIGlmICghdGhpcy5lZGl0b3IpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMuZWRpdG9yVHlwZS50b0xvd2VyQ2FzZSgpID09PSAnanNvbicpIHtcclxuICAgICAgICAgICAgbGV0IHN0cmluZ1ZhbHVlID0gdGhpcy5lZGl0b3IuZ2V0VmFsdWUoKTtcclxuICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IG9iamVjdFZhbHVlID0gSlNPTi5wYXJzZShzdHJpbmdWYWx1ZSk7XHJcbiAgICAgICAgICAgICAgICBzdHJpbmdWYWx1ZSA9IHRoaXMuX2dldEZvcm1hdHRlZEpzb24ob2JqZWN0VmFsdWUpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5lZGl0b3Iuc2V0VmFsdWUoc3RyaW5nVmFsdWUpO1xyXG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgLy8gdG9vIGJhZCB3ZSBjb3VsZCBub3QgZm9ybWF0XHJcbiAgICAgICAgICAgICAgICB0aGlzLm5vdGlmaWNhdGlvbi5ub3RpZnlXYXJuaW5nKGVycm9yKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNldHMgdGhlIHZhbHVlIG9mIHRoZSB1bmRlcmx5aW5nIGVkaXRvci5cclxuICAgICAqXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKiBAcGFyYW0ge3N0cmluZyB8IHt9IHwgbnVsbH0gdmFsdWVcclxuICAgICAqIEBtZW1iZXJvZiBWYWx1ZUVkaXRvckJhc2VcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHNldEVkaXRvclZhbHVlKHZhbHVlOiBzdHJpbmcgfCB7fSB8IG51bGwpOiB2b2lkIHtcclxuICAgICAgICBpZiAoIXRoaXMuZWRpdG9yKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGxldCBzdHJpbmdWYWx1ZSA9ICcnO1xyXG4gICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3ZhbHVlSXNPYmplY3QgPSB0cnVlO1xyXG4gICAgICAgICAgICBzdHJpbmdWYWx1ZSA9IHRoaXMuX2dldEZvcm1hdHRlZEpzb24odmFsdWUhKTtcclxuICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgICAgICAgaWYgKHZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLl92YWx1ZUlzT2JqZWN0ID0gZmFsc2U7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgc3RyaW5nVmFsdWUgPSB2YWx1ZTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBzdHJpbmdWYWx1ZSA9IHZhbHVlICYmIHZhbHVlLnRvU3RyaW5nKCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLmVkaXRvci5zZXRWYWx1ZShzdHJpbmdWYWx1ZSB8fCAnJyk7XHJcbiAgICAgICAgdGhpcy5lZGl0b3IuY2xlYXJTZWxlY3Rpb24oKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIEdldHMgdGhlIHVuZGVybHlpbmcgZWRpdG9yJ3MgdmFsdWUuXHJcbiAgICAgKlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICogQHJldHVybnMge3N0cmluZyB8IHt9IHwgbnVsbH0gVGhlIHdpZGdldCB2YWx1ZS5cclxuICAgICAqIEBtZW1iZXJvZiBWYWx1ZUVkaXRvckJhc2VcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIGdldEVkaXRvclZhbHVlKCk6IHN0cmluZyB8IHt9IHwgbnVsbCB7XHJcbiAgICAgICAgaWYgKCF0aGlzLmVkaXRvcikge1xyXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNvbnN0IHN0cmluZ1ZhbHVlID0gdGhpcy5lZGl0b3IuZ2V0VmFsdWUoKTtcclxuICAgICAgICBpZiAodGhpcy5fdmFsdWVJc09iamVjdCkge1xyXG4gICAgICAgICAgICBpZiAoIXN0cmluZ1ZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gc3RyaW5nVmFsdWU7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBvYmplY3RWYWx1ZSA9IEpTT04ucGFyc2Uoc3RyaW5nVmFsdWUpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9iamVjdFZhbHVlO1xyXG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0cmluZ1ZhbHVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICByZXR1cm4gc3RyaW5nVmFsdWU7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBXaGVuIG92ZXJyaWRkZW4gaW4gYSBkZXJpdmVkIGNsYXNzLCB0aGlzIG1ldGhvZCBpcyBjYWxsZWQgd2hlbiB0aGUgcmVhZCBvbmx5IHN0YXRlIGNoYW5nZXMuXHJcbiAgICAgKlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICogQHBhcmFtIHtib29sZWFufSBvbGRWYWx1ZSBUaGUgb2xkIHZhbHVlLlxyXG4gICAgICogQHBhcmFtIHtib29sZWFufSBuZXdWYWx1ZSBUaGUgbmV3IHZhbHVlLlxyXG4gICAgICpcclxuICAgICAqIEBtZW1iZXJvZiBFZGl0b3JCYXNlXHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBvblJlYWRPbmx5Q2hhbmdlZChvbGRWYWx1ZTogYm9vbGVhbiwgbmV3VmFsdWU6IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgICAgICBpZiAodGhpcy5lZGl0b3IpIHtcclxuICAgICAgICAgICAgdGhpcy5zZXRFZGl0b3JSZWFkT25seShuZXdWYWx1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2V0cyB0aGUgcmVhZG9ubHkgc3RhdGUgb2YgdGhlIGVkaXRvci5cclxuICAgICAqXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IHZhbHVlXHJcbiAgICAgKiBAbWVtYmVyb2YgQWNlQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBzZXRFZGl0b3JSZWFkT25seSh2YWx1ZTogYm9vbGVhbikge1xyXG4gICAgICAgIGlmICh0aGlzLmVkaXRvcikge1xyXG4gICAgICAgICAgICB0aGlzLmVkaXRvci5zZXRSZWFkT25seSh2YWx1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2V0cyB0aGUgZWRpdG9yIHRoZW1lLlxyXG4gICAgICpcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0aGVtZVxyXG4gICAgICogQG1lbWJlcm9mIEFjZUNvbXBvbmVudFxyXG4gICAgICovXHJcbiAgICBwcm90ZWN0ZWQgc2V0RWRpdG9yVGhlbWUodGhlbWU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgICAgIGlmICh0aGlzLmVkaXRvciAmJiB0aGVtZSkge1xyXG4gICAgICAgICAgICB0aGlzLmVkaXRvci5zZXRUaGVtZShgYWNlL3RoZW1lLyR7dGhlbWV9YCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2V0cyB0aGUgZWRpdG9yIHR5cGUuXHJcbiAgICAgKlxyXG4gICAgICogQHByb3RlY3RlZFxyXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGVkaXRvclR5cGVcclxuICAgICAqIEBtZW1iZXJvZiBBY2VDb21wb25lbnRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHNldEVkaXRvclR5cGUoZWRpdG9yVHlwZTogc3RyaW5nKTogdm9pZCB7XHJcbiAgICAgICAgaWYgKHRoaXMuZWRpdG9yICYmIGVkaXRvclR5cGUpIHtcclxuICAgICAgICAgICAgY29uc3QgbW9kZSA9IHRoaXMuZ2V0RWRpdG9yTW9kZShlZGl0b3JUeXBlKTtcclxuICAgICAgICAgICAgdGhpcy5lZGl0b3IuZ2V0U2Vzc2lvbigpLnNldE1vZGUoYGFjZS9tb2RlLyR7bW9kZX1gKTtcclxuICAgICAgICAgICAgdGhpcy5lZGl0b3IuJGJsb2NrU2Nyb2xsaW5nID0gSW5maW5pdHk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogR2V0cyB0aGUgZWRpdG9yIG1vZGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGVkaXRvciB0eXBlLlxyXG4gICAgICpcclxuICAgICAqIEBwcm90ZWN0ZWRcclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBlZGl0b3JUeXBlIFRoZSBlZGl0b3IgdHlwZS5cclxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9XHJcbiAgICAgKiBAbWVtYmVyb2YgQWNlQ29tcG9uZW50XHJcbiAgICAgKi9cclxuICAgIHByb3RlY3RlZCBnZXRFZGl0b3JNb2RlKGVkaXRvclR5cGU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIGVkaXRvclR5cGU7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBVcGRhdGVzIHRoZSB1bmRlcmx5aW5nIGVkaXRvciB3aXRoIHRoZSBwcm92aWRlZCB2YWx1ZS5cclxuICAgICAqXHJcbiAgICAgKiBAcHJvdGVjdGVkXHJcbiAgICAgKiBAcGFyYW0ge1RWYWx1ZX0gdmFsdWUgVGhlIHZhbHVlIHRvIGJlIHNldCBpbiB0aGUgdW5kZXJseWluZyBjb21wb25lbnQuXHJcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICAgICAqIEBtZW1iZXJvZiBBY2VDb21wb25lbnRcclxuICAgICAqL1xyXG4gICAgcHJvdGVjdGVkIHVwZGF0ZUVkaXRvcih2YWx1ZTogc3RyaW5nKTogYm9vbGVhbiB7XHJcbiAgICAgICAgdmFsdWUgPSB2YWx1ZSB8fCAnJztcclxuICAgICAgICByZXR1cm4gc3VwZXIudXBkYXRlRWRpdG9yKHZhbHVlKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIF9nZXRGb3JtYXR0ZWRKc29uKG9iajoge30pIHtcclxuICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob2JqLCBudWxsLCA0KTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIF9pc0FjZVZpc2libGUoZWxlbWVudDogRWxlbWVudCk6IGJvb2xlYW4ge1xyXG4gICAgICAgIGNvbnN0IHN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoZWxlbWVudCk7XHJcbiAgICAgICAgcmV0dXJuICEoc3R5bGUuZGlzcGxheSA9PT0gJ25vbmUnKVxyXG4gICAgfVxyXG59XHJcbiJdfQ==