@ckeditor/ckeditor5-angular
Version:
Official Angular component for CKEditor 5 – the best browser-based rich text editor.
430 lines • 52.2 kB
JavaScript
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
import { Component, ElementRef, EventEmitter, forwardRef, Inject, Input, NgZone, Output } from '@angular/core';
import { first } from 'rxjs/operators';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { uid } from '@ckeditor/ckeditor5-integrations-common';
import { appendAllIntegrationPluginsToConfig } from './plugins/append-all-integration-plugins-to-config';
import * as i0 from "@angular/core";
const ANGULAR_INTEGRATION_READ_ONLY_LOCK_ID = 'Lock from Angular integration (@ckeditor/ckeditor5-angular)';
class CKEditorComponent {
/**
* The reference to the DOM element created by the component.
*/
elementRef;
/**
* The constructor of the editor to be used for the instance of the component.
* It can be e.g. the `ClassicEditorBuild`, `InlineEditorBuild` or some custom editor.
*/
editor;
/**
* The configuration of the editor.
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html
* to learn more.
*/
config = {
licenseKey: 'GPL'
};
/**
* The initial data of the editor. Useful when not using the ngModel.
* See https://angular.io/api/forms/NgModel to learn more.
*/
data = '';
/**
* Tag name of the editor component.
*
* The default tag is 'div'.
*/
tagName = 'div';
// TODO Change to ContextWatchdog<Editor, HTMLElement> after new ckeditor5 alpha release
/**
* The context watchdog.
*/
watchdog;
/**
* Config for the EditorWatchdog.
*/
editorWatchdogConfig;
/**
* Allows disabling the two-way data binding mechanism. Disabling it can boost performance for large documents.
*
* When a component is connected using the [(ngModel)] or [formControl] directives and this value is set to true then none of the data
* will ever be synchronized.
*
* An integrator must call `editor.data.get()` manually once the application needs the editor's data.
* An editor instance can be received in the `ready()` callback.
*/
disableTwoWayDataBinding = false;
/**
* When set `true`, the editor becomes read-only.
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#member-isReadOnly
* to learn more.
*/
set disabled(isDisabled) {
this.setDisabledState(isDisabled);
}
get disabled() {
if (this.editorInstance) {
return this.editorInstance.isReadOnly;
}
return this.initiallyDisabled;
}
/**
* Fires when the editor is ready. It corresponds with the `editor#ready`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html#event-ready
* event.
*/
ready = new EventEmitter();
/**
* Fires when the content of the editor has changed. It corresponds with the `editor.model.document#change`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_document-Document.html#event-change
* event.
*/
change = new EventEmitter();
/**
* Fires when the editing view of the editor is blurred. It corresponds with the `editor.editing.view.document#blur`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_view_document-Document.html#event-event:blur
* event.
*/
blur = new EventEmitter();
/**
* Fires when the editing view of the editor is focused. It corresponds with the `editor.editing.view.document#focus`
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_view_document-Document.html#event-event:focus
* event.
*/
focus = new EventEmitter();
/**
* Fires when the editor component crashes.
*/
error = new EventEmitter();
/**
* The instance of the editor created by this component.
*/
get editorInstance() {
let editorWatchdog = this.editorWatchdog;
if (this.watchdog) {
// Temporarily use the `_watchdogs` internal map as the `getItem()` method throws
// an error when the item is not registered yet.
// See https://github.com/ckeditor/ckeditor5-angular/issues/177.
// TODO should be able to change when new chages in Watcdog are released.
editorWatchdog = this.watchdog._watchdogs.get(this.id);
}
if (editorWatchdog) {
return editorWatchdog.editor;
}
return null;
}
/**
* The editor watchdog. It is created when the context watchdog is not passed to the component.
* It keeps the editor running.
*/
editorWatchdog;
/**
* If the component is read–only before the editor instance is created, it remembers that state,
* so the editor can become read–only once it is ready.
*/
initiallyDisabled = false;
/**
* An instance of https://angular.io/api/core/NgZone to allow the interaction with the editor
* withing the Angular event loop.
*/
ngZone;
/**
* A callback executed when the content of the editor changes. Part of the
* `ControlValueAccessor` (https://angular.io/api/forms/ControlValueAccessor) interface.
*
* Note: Unset unless the component uses the `ngModel`.
*/
cvaOnChange;
/**
* A callback executed when the editor has been blurred. Part of the
* `ControlValueAccessor` (https://angular.io/api/forms/ControlValueAccessor) interface.
*
* Note: Unset unless the component uses the `ngModel`.
*/
cvaOnTouched;
/**
* Reference to the source element used by the editor.
*/
editorElement;
/**
* A lock flag preventing from calling the `cvaOnChange()` during setting editor data.
*/
isEditorSettingData = false;
id = uid();
getId() {
return this.id;
}
constructor(elementRef, ngZone) {
this.ngZone = ngZone;
this.elementRef = elementRef;
this.checkVersion();
}
checkVersion() {
// To avoid issues with the community typings and CKEditor 5, let's treat window as any. See #342.
const { CKEDITOR_VERSION } = window;
if (!CKEDITOR_VERSION) {
return console.warn('Cannot find the "CKEDITOR_VERSION" in the "window" scope.');
}
const [major] = CKEDITOR_VERSION.split('.').map(Number);
if (major >= 42 || CKEDITOR_VERSION.startsWith('0.0.0')) {
return;
}
console.warn('The <CKEditor> component requires using CKEditor 5 in version 42+ or nightly build.');
}
// Implementing the OnChanges interface. Whenever the `data` property is changed, update the editor content.
ngOnChanges(changes) {
if (Object.prototype.hasOwnProperty.call(changes, 'data') && changes.data && !changes.data.isFirstChange()) {
this.writeValue(changes.data.currentValue);
}
}
// Implementing the AfterViewInit interface.
ngAfterViewInit() {
this.attachToWatchdog();
}
// Implementing the OnDestroy interface.
async ngOnDestroy() {
if (this.watchdog) {
await this.watchdog.remove(this.id);
}
else if (this.editorWatchdog && this.editorWatchdog.editor) {
await this.editorWatchdog.destroy();
this.editorWatchdog = undefined;
}
}
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
writeValue(value) {
// This method is called with the `null` value when the form resets.
// A component's responsibility is to restore to the initial state.
if (value === null) {
value = '';
}
// If already initialized.
if (this.editorInstance) {
// The lock mechanism prevents from calling `cvaOnChange()` during changing
// the editor state. See #139
this.isEditorSettingData = true;
this.editorInstance.data.set(value);
this.isEditorSettingData = false;
}
// If not, wait for it to be ready; store the data.
else {
// If the editor element is already available, then update its content.
this.data = value;
// If not, then wait until it is ready
// and change data only for the first `ready` event.
this.ready
.pipe(first())
.subscribe(editor => {
editor.data.set(this.data);
});
}
}
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
registerOnChange(callback) {
this.cvaOnChange = callback;
}
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
registerOnTouched(callback) {
this.cvaOnTouched = callback;
}
// Implementing the ControlValueAccessor interface (only when binding to ngModel).
setDisabledState(isDisabled) {
// If already initialized.
if (this.editorInstance) {
if (isDisabled) {
this.editorInstance.enableReadOnlyMode(ANGULAR_INTEGRATION_READ_ONLY_LOCK_ID);
}
else {
this.editorInstance.disableReadOnlyMode(ANGULAR_INTEGRATION_READ_ONLY_LOCK_ID);
}
}
// Store the state anyway to use it once the editor is created.
this.initiallyDisabled = isDisabled;
}
/**
* Creates the editor instance, sets initial editor data, then integrates
* the editor with the Angular component. This method does not use the `editor.data.set()`
* because of the issue in the collaboration mode (#6).
*/
attachToWatchdog() {
// TODO: elementOrData parameter type can be simplified to HTMLElemen after templated Watchdog will be released.
const creator = ((elementOrData, config) => {
return this.ngZone.runOutsideAngular(async () => {
this.elementRef.nativeElement.appendChild(elementOrData);
const editor = await this.editor.create(elementOrData, config);
if (this.initiallyDisabled) {
editor.enableReadOnlyMode(ANGULAR_INTEGRATION_READ_ONLY_LOCK_ID);
}
this.ngZone.run(() => {
this.ready.emit(editor);
});
this.setUpEditorEvents(editor);
return editor;
});
});
const destructor = async (editor) => {
await editor.destroy();
this.elementRef.nativeElement.removeChild(this.editorElement);
};
const emitError = (e) => {
// Do not run change detection by re-entering the Angular zone if the `error`
// emitter doesn't have any subscribers.
// Subscribers are pushed onto the list whenever `error` is listened inside the template:
// `<ckeditor (error)="onError(...)"></ckeditor>`.
if (hasObservers(this.error)) {
this.ngZone.run(() => this.error.emit(e));
}
else {
// Print error to the console when there are no subscribers to the `error` event.
console.error(e);
}
};
const element = document.createElement(this.tagName);
const config = this.getConfig();
this.editorElement = element;
// Based on the presence of the watchdog decide how to initialize the editor.
if (this.watchdog) {
// When the context watchdog is passed add the new item to it based on the passed configuration.
this.watchdog.add({
id: this.id,
type: 'editor',
creator,
destructor,
sourceElementOrData: element,
config
}).catch(e => {
emitError(e);
});
this.watchdog.on('itemError', (_, { itemId }) => {
if (itemId === this.id) {
emitError();
}
});
}
else {
// In the other case create the watchdog by hand to keep the editor running.
const editorWatchdog = new this.editor.EditorWatchdog(this.editor, this.editorWatchdogConfig);
editorWatchdog.setCreator(creator);
editorWatchdog.setDestructor(destructor);
editorWatchdog.on('error', emitError);
this.editorWatchdog = editorWatchdog;
this.ngZone.runOutsideAngular(() => {
// Note: must be called outside of the Angular zone too because `create` is calling
// `_startErrorHandling` within a microtask which sets up `error` listener on the window.
editorWatchdog.create(element, config).catch(e => {
emitError(e);
});
});
}
}
getConfig() {
if (this.data && this.config.initialData) {
throw new Error('Editor data should be provided either using `config.initialData` or `data` properties.');
}
const config = { ...this.config };
// Merge two possible ways of providing data into the `config.initialData` field.
const initialData = this.config.initialData || this.data;
if (initialData) {
// Define the `config.initialData` only when the initial content is specified.
config.initialData = initialData;
}
return appendAllIntegrationPluginsToConfig(config);
}
/**
* Integrates the editor with the component by attaching related event listeners.
*/
setUpEditorEvents(editor) {
const modelDocument = editor.model.document;
const viewDocument = editor.editing.view.document;
modelDocument.on('change:data', evt => {
this.ngZone.run(() => {
if (this.disableTwoWayDataBinding) {
return;
}
if (this.cvaOnChange && !this.isEditorSettingData) {
const data = editor.data.get();
this.cvaOnChange(data);
}
this.change.emit({ event: evt, editor });
});
});
viewDocument.on('focus', evt => {
this.ngZone.run(() => {
this.focus.emit({ event: evt, editor });
});
});
viewDocument.on('blur', evt => {
this.ngZone.run(() => {
if (this.cvaOnTouched) {
this.cvaOnTouched();
}
this.blur.emit({ event: evt, editor });
});
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CKEditorComponent, deps: [{ token: ElementRef }, { token: NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: CKEditorComponent, selector: "ckeditor", inputs: { editor: "editor", config: "config", data: "data", tagName: "tagName", watchdog: "watchdog", editorWatchdogConfig: "editorWatchdogConfig", disableTwoWayDataBinding: "disableTwoWayDataBinding", disabled: "disabled" }, outputs: { ready: "ready", change: "change", blur: "blur", focus: "focus", error: "error" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CKEditorComponent),
multi: true
}
], usesOnChanges: true, ngImport: i0, template: '<ng-template></ng-template>', isInline: true });
}
export { CKEditorComponent };
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CKEditorComponent, decorators: [{
type: Component,
args: [{
selector: 'ckeditor',
template: '<ng-template></ng-template>',
// Integration with @angular/forms.
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CKEditorComponent),
multi: true
}
]
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef, decorators: [{
type: Inject,
args: [ElementRef]
}] }, { type: i0.NgZone, decorators: [{
type: Inject,
args: [NgZone]
}] }]; }, propDecorators: { editor: [{
type: Input
}], config: [{
type: Input
}], data: [{
type: Input
}], tagName: [{
type: Input
}], watchdog: [{
type: Input
}], editorWatchdogConfig: [{
type: Input
}], disableTwoWayDataBinding: [{
type: Input
}], disabled: [{
type: Input
}], ready: [{
type: Output
}], change: [{
type: Output
}], blur: [{
type: Output
}], focus: [{
type: Output
}], error: [{
type: Output
}] } });
function hasObservers(emitter) {
// Cast to `any` because `observed` property is available in RxJS >= 7.2.0.
// Fallback to checking `observers` list if this property is not defined.
return emitter.observed || emitter.observers.length > 0;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2tlZGl0b3IuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NrZWRpdG9yL2NrZWRpdG9yLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEVBQ04sU0FBUyxFQUNULFVBQVUsRUFDVixZQUFZLEVBQ1osVUFBVSxFQUNWLE1BQU0sRUFDTixLQUFLLEVBQ0wsTUFBTSxFQUNOLE1BQU0sRUFLTixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdkMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFnQm5ELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUM5RCxPQUFPLEVBQUUsbUNBQW1DLEVBQUUsTUFBTSxvREFBb0QsQ0FBQzs7QUFFekcsTUFBTSxxQ0FBcUMsR0FBRyw2REFBNkQsQ0FBQztBQWlCNUcsTUFhYSxpQkFBaUI7SUFDN0I7O09BRUc7SUFDSyxVQUFVLENBQTJCO0lBRTdDOzs7T0FHRztJQUNhLE1BQU0sQ0FHcEI7SUFFRjs7OztPQUlHO0lBQ2EsTUFBTSxHQUFpQjtRQUN0QyxVQUFVLEVBQUUsS0FBSztLQUNqQixDQUFDO0lBRUY7OztPQUdHO0lBQ2EsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUUxQjs7OztPQUlHO0lBQ2EsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUVoQyx3RkFBd0Y7SUFDeEY7O09BRUc7SUFDYSxRQUFRLENBQW1CO0lBRTNDOztPQUVHO0lBQ2Esb0JBQW9CLENBQWtCO0lBRXREOzs7Ozs7OztPQVFHO0lBQ2Esd0JBQXdCLEdBQUcsS0FBSyxDQUFDO0lBRWpEOzs7O09BSUc7SUFDSCxJQUFvQixRQUFRLENBQUUsVUFBbUI7UUFDaEQsSUFBSSxDQUFDLGdCQUFnQixDQUFFLFVBQVUsQ0FBRSxDQUFDO0lBQ3JDLENBQUM7SUFF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QVU7b0JBQ3BCLFFBQVEsRUFBRSw2QkFBNkI7b0JBRXZDLG1DQUFtQztvQkFDbkMsU0FBUyxFQUFFO3dCQUNWOzRCQUNDLE9BQU8sRUFBRSxpQkFBaUI7NEJBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUUsR0FBRyxFQUFFLGtCQUFrQixDQUFFOzRCQUNsRCxLQUFLLEVBQUUsSUFBSTt5QkFDWDtxQkFDRDtpQkFDRDs7MEJBcUxxQixNQUFNOzJCQUFFLFVBQVU7OzBCQUE0QixNQUFNOzJCQUFFLE1BQU07NENBMUtqRSxNQUFNO3NCQUFyQixLQUFLO2dCQVVVLE1BQU07c0JBQXJCLEtBQUs7Z0JBUVUsSUFBSTtzQkFBbkIsS0FBSztnQkFPVSxPQUFPO3NCQUF0QixLQUFLO2dCQU1VLFFBQVE7c0JBQXZCLEtBQUs7Z0JBS1Usb0JBQW9CO3NCQUFuQyxLQUFLO2dCQVdVLHdCQUF3QjtzQkFBdkMsS0FBSztnQkFPYyxRQUFRO3NCQUEzQixLQUFLO2dCQWlCVyxLQUFLO3NCQUFyQixNQUFNO2dCQU9VLE1BQU07c0JBQXRCLE1BQU07Z0JBT1UsSUFBSTtzQkFBcEIsTUFBTTtnQkFPVSxLQUFLO3NCQUFyQixNQUFNO2dCQUtVLEtBQUs7c0JBQXJCLE1BQU07O0FBc1VSLFNBQVMsWUFBWSxDQUFLLE9BQXdCO0lBQ2pELDJFQUEyRTtJQUMzRSx5RUFBeUU7SUFDekUsT0FBUyxPQUFnQixDQUFDLFFBQVEsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7QUFDcEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2UgQ29weXJpZ2h0IChjKSAyMDAzLTIwMjUsIENLU291cmNlIEhvbGRpbmcgc3AuIHogby5vLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogRm9yIGxpY2Vuc2luZywgc2VlIExJQ0VOU0UubWQgb3IgaHR0cHM6Ly9ja2VkaXRvci5jb20vbGVnYWwvY2tlZGl0b3ItbGljZW5zaW5nLW9wdGlvbnNcbiAqL1xuXG5pbXBvcnQge1xuXHRDb21wb25lbnQsXG5cdEVsZW1lbnRSZWYsXG5cdEV2ZW50RW1pdHRlcixcblx0Zm9yd2FyZFJlZixcblx0SW5qZWN0LFxuXHRJbnB1dCxcblx0Tmdab25lLFxuXHRPdXRwdXQsXG5cdHR5cGUgQWZ0ZXJWaWV3SW5pdCxcblx0dHlwZSBPbkNoYW5nZXMsXG5cdHR5cGUgT25EZXN0cm95LFxuXHR0eXBlIFNpbXBsZUNoYW5nZXNcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IGZpcnN0IH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5cbmltcG9ydCB0eXBlIHtcblx0Q29udGV4dFdhdGNoZG9nLFxuXHRFZGl0b3JXYXRjaGRvZyxcblx0V2F0Y2hkb2dDb25maWcsXG5cdEVkaXRvcixcblx0RWRpdG9yQ29uZmlnLFxuXHRHZXRFdmVudEluZm8sXG5cdE1vZGVsRG9jdW1lbnRDaGFuZ2VFdmVudCxcblx0RWRpdG9yV2F0Y2hkb2dDcmVhdG9yRnVuY3Rpb24sXG5cdFZpZXdEb2N1bWVudEJsdXJFdmVudCxcblx0Vmlld0RvY3VtZW50Rm9jdXNFdmVudFxufSBmcm9tICdja2VkaXRvcjUnO1xuaW1wb3J0IHR5cGUgeyBDb250cm9sVmFsdWVBY2Nlc3NvciB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuaW1wb3J0IHsgdWlkIH0gZnJvbSAnQGNrZWRpdG9yL2NrZWRpdG9yNS1pbnRlZ3JhdGlvbnMtY29tbW9uJztcbmltcG9ydCB7IGFwcGVuZEFsbEludGVncmF0aW9uUGx1Z2luc1RvQ29uZmlnIH0gZnJvbSAnLi9wbHVnaW5zL2FwcGVuZC1hbGwtaW50ZWdyYXRpb24tcGx1Z2lucy10by1jb25maWcnO1xuXG5jb25zdCBBTkdVTEFSX0lOVEVHUkFUSU9OX1JFQURfT05MWV9MT0NLX0lEID0gJ0xvY2sgZnJvbSBBbmd1bGFyIGludGVncmF0aW9uIChAY2tlZGl0b3IvY2tlZGl0b3I1LWFuZ3VsYXIpJztcblxuZXhwb3J0IGludGVyZmFjZSBCbHVyRXZlbnQ8VEVkaXRvciBleHRlbmRzIEVkaXRvciA9IEVkaXRvcj4ge1xuXHRldmVudDogR2V0RXZlbnRJbmZvPFZpZXdEb2N1bWVudEJsdXJFdmVudD47XG5cdGVkaXRvcjogVEVkaXRvcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGb2N1c0V2ZW50PFRFZGl0b3IgZXh0ZW5kcyBFZGl0b3IgPSBFZGl0b3I+IHtcblx0ZXZlbnQ6IEdldEV2ZW50SW5mbzxWaWV3RG9jdW1lbnRGb2N1c0V2ZW50Pjtcblx0ZWRpdG9yOiBURWRpdG9yO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENoYW5nZUV2ZW50PFRFZGl0b3IgZXh0ZW5kcyBFZGl0b3IgPSBFZGl0b3I+IHtcblx0ZXZlbnQ6IEdldEV2ZW50SW5mbzxNb2RlbERvY3VtZW50Q2hhbmdlRXZlbnQ+O1xuXHRlZGl0b3I6IFRFZGl0b3I7XG59XG5cbkBDb21wb25lbnQoIHtcblx0c2VsZWN0b3I6ICdja2VkaXRvcicsXG5cdHRlbXBsYXRlOiAnPG5nLXRlbXBsYXRlPjwvbmctdGVtcGxhdGU+JyxcblxuXHQvLyBJbnRlZ3JhdGlvbiB3aXRoIEBhbmd1bGFyL2Zvcm1zLlxuXHRwcm92aWRlcnM6IFtcblx0XHR7XG5cdFx0XHRwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcblx0XHRcdHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCAoKSA9PiBDS0VkaXRvckNvbXBvbmVudCApLFxuXHRcdFx0bXVsdGk6IHRydWVcblx0XHR9XG5cdF1cbn0gKVxuZXhwb3J0IGNsYXNzIENLRWRpdG9yQ29tcG9uZW50PFRFZGl0b3IgZXh0ZW5kcyBFZGl0b3IgPSBFZGl0b3I+IGltcGxlbWVudHMgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95LCBPbkNoYW5nZXMsIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcblx0LyoqXG5cdCAqIFRoZSByZWZlcmVuY2UgdG8gdGhlIERPTSBlbGVtZW50IGNyZWF0ZWQgYnkgdGhlIGNvbXBvbmVudC5cblx0ICovXG5cdHByaXZhdGUgZWxlbWVudFJlZiE6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xuXG5cdC8qKlxuXHQgKiBUaGUgY29uc3RydWN0b3Igb2YgdGhlIGVkaXRvciB0byBiZSB1c2VkIGZvciB0aGUgaW5zdGFuY2Ugb2YgdGhlIGNvbXBvbmVudC5cblx0ICogSXQgY2FuIGJlIGUuZy4gdGhlIGBDbGFzc2ljRWRpdG9yQnVpbGRgLCBgSW5saW5lRWRpdG9yQnVpbGRgIG9yIHNvbWUgY3VzdG9tIGVkaXRvci5cblx0ICovXG5cdEBJbnB1dCgpIHB1YmxpYyBlZGl0b3I/OiB7XG5cdFx0Y3JlYXRlKCBzb3VyY2VFbGVtZW50T3JEYXRhOiBIVE1MRWxlbWVudCB8IHN0cmluZywgY29uZmlnPzogRWRpdG9yQ29uZmlnICk6IFByb21pc2U8VEVkaXRvcj47XG5cdFx0RWRpdG9yV2F0Y2hkb2c6IHR5cGVvZiBFZGl0b3JXYXRjaGRvZztcblx0fTtcblxuXHQvKipcblx0ICogVGhlIGNvbmZpZ3VyYXRpb24gb2YgdGhlIGVkaXRvci5cblx0ICogU2VlIGh0dHBzOi8vY2tlZGl0b3IuY29tL2RvY3MvY2tlZGl0b3I1L2xhdGVzdC9hcGkvbW9kdWxlX2NvcmVfZWRpdG9yX2VkaXRvcmNvbmZpZy1FZGl0b3JDb25maWcuaHRtbFxuXHQgKiB0byBsZWFybiBtb3JlLlxuXHQgKi9cblx0QElucHV0KCkgcHVibGljIGNvbmZpZzogRWRpdG9yQ29uZmlnID0ge1xuXHRcdGxpY2Vuc2VLZXk6ICdHUEwnXG5cdH07XG5cblx0LyoqXG5cdCAqIFRoZSBpbml0aWFsIGRhdGEgb2YgdGhlIGVkaXRvci4gVXNlZnVsIHdoZW4gbm90IHVzaW5nIHRoZSBuZ01vZGVsLlxuXHQgKiBTZWUgaHR0cHM6Ly9hbmd1bGFyLmlvL2FwaS9mb3Jtcy9OZ01vZGVsIHRvIGxlYXJuIG1vcmUuXG5cdCAqL1xuXHRASW5wdXQoKSBwdWJsaWMgZGF0YSA9ICcnO1xuXG5cdC8qKlxuXHQgKiBUYWcgbmFtZSBvZiB0aGUgZWRpdG9yIGNvbXBvbmVudC5cblx0ICpcblx0ICogVGhlIGRlZmF1bHQgdGFnIGlzICdkaXYnLlxuXHQgKi9cblx0QElucHV0KCkgcHVibGljIHRhZ05hbWUgPSAnZGl2JztcblxuXHQvLyBUT0RPIENoYW5nZSB0byBDb250ZXh0V2F0Y2hkb2c8RWRpdG9yLCBIVE1MRWxlbWVudD4gYWZ0ZXIgbmV3IGNrZWRpdG9yNSBhbHBoYSByZWxlYXNlXG5cdC8qKlxuXHQgKiBUaGUgY29udGV4dCB3YXRjaGRvZy5cblx0ICovXG5cdEBJbnB1dCgpIHB1YmxpYyB3YXRjaGRvZz86IENvbnRleHRXYXRjaGRvZztcblxuXHQvKipcblx0ICogQ29uZmlnIGZvciB0aGUgRWRpdG9yV2F0Y2hkb2cuXG5cdCAqL1xuXHRASW5wdXQoKSBwdWJsaWMgZWRpdG9yV2F0Y2hkb2dDb25maWc/OiBXYXRjaGRvZ0NvbmZpZztcblxuXHQvKipcblx0ICogQWxsb3dzIGRpc2FibGluZyB0aGUgdHdvLXdheSBkYXRhIGJpbmRpbmcgbWVjaGFuaXNtLiBEaXNhYmxpbmcgaXQgY2FuIGJvb3N0IHBlcmZvcm1hbmNlIGZvciBsYXJnZSBkb2N1bWVudHMuXG5cdCAqXG5cdCAqIFdoZW4gYSBjb21wb25lbnQgaXMgY29ubmVjdGVkIHVzaW5nIHRoZSBbKG5nTW9kZWwpXSBvciBbZm9ybUNvbnRyb2xdIGRpcmVjdGl2ZXMgYW5kIHRoaXMgdmFsdWUgaXMgc2V0IHRvIHRydWUgdGhlbiBub25lIG9mIHRoZSBkYXRhXG5cdCAqIHdpbGwgZXZlciBiZSBzeW5jaHJvbml6ZWQuXG5cdCAqXG5cdCAqIEFuIGludGVncmF0b3IgbXVzdCBjYWxsIGBlZGl0b3IuZGF0YS5nZXQoKWAgbWFudWFsbHkgb25jZSB0aGUgYXBwbGljYXRpb24gbmVlZHMgdGhlIGVkaXRvcidzIGRhdGEuXG5cdCAqIEFuIGVkaXRvciBpbnN0YW5jZSBjYW4gYmUgcmVjZWl2ZWQgaW4gdGhlIGByZWFkeSgpYCBjYWxsYmFjay5cblx0ICovXG5cdEBJbnB1dCgpIHB1YmxpYyBkaXNhYmxlVHdvV2F5RGF0YUJpbmRpbmcgPSBmYWxzZTtcblxuXHQvKipcblx0ICogV2hlbiBzZXQgYHRydWVgLCB0aGUgZWRpdG9yIGJlY29tZXMgcmVhZC1vbmx5LlxuXHQgKiBTZWUgaHR0cHM6Ly9ja2VkaXRvci5jb20vZG9jcy9ja2VkaXRvcjUvbGF0ZXN0L2FwaS9tb2R1bGVfY29yZV9lZGl0b3JfZWRpdG9yLUVkaXRvci5odG1sI21lbWJlci1pc1JlYWRPbmx5XG5cdCAqIHRvIGxlYXJuIG1vcmUuXG5cdCAqL1xuXHRASW5wdXQoKSBwdWJsaWMgc2V0IGRpc2FibGVkKCBpc0Rpc2FibGVkOiBib29sZWFuICkge1xuXHRcdHRoaXMuc2V0RGlzYWJsZWRTdGF0ZSggaXNEaXNhYmxlZCApO1xuXHR9XG5cblx0cHVibGljIGdldCBkaXNhYmxlZCgpOiBib29sZWFuIHtcblx0XHRpZiAoIHRoaXMuZWRpdG9ySW5zdGFuY2UgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lZGl0b3JJbnN0YW5jZS5pc1JlYWRPbmx5O1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmluaXRpYWxseURpc2FibGVkO1xuXHR9XG5cblx0LyoqXG5cdCAqIEZpcmVzIHdoZW4gdGhlIGVkaXRvciBpcyByZWFkeS4gSXQgY29ycmVzcG9uZHMgd2l0aCB0aGUgYGVkaXRvciNyZWFkeWBcblx0ICogaHR0cHM6Ly9ja2VkaXRvci5jb20vZG9jcy9ja2VkaXRvcjUvbGF0ZXN0L2FwaS9tb2R1bGVfY29yZV9lZGl0b3JfZWRpdG9yLUVkaXRvci5odG1sI2V2ZW50LXJlYWR5XG5cdCAqIGV2ZW50LlxuXHQgKi9cblx0QE91dHB1dCgpIHB1YmxpYyByZWFkeSA9IG5ldyBFdmVudEVtaXR0ZXI8VEVkaXRvcj4oKTtcblxuXHQvKipcblx0ICogRmlyZXMgd2hlbiB0aGUgY29udGVudCBvZiB0aGUgZWRpdG9yIGhhcyBjaGFuZ2VkLiBJdCBjb3JyZXNwb25kcyB3aXRoIHRoZSBgZWRpdG9yLm1vZGVsLmRvY3VtZW50I2NoYW5nZWBcblx0ICogaHR0cHM6Ly9ja2VkaXRvci5jb20vZG9jcy9ja2VkaXRvcjUvbGF0ZXN0L2FwaS9tb2R1bGVfZW5naW5lX21vZGVsX2RvY3VtZW50LURvY3VtZW50Lmh0bWwjZXZlbnQtY2hhbmdlXG5cdCAqIGV2ZW50LlxuXHQgKi9cblx0QE91dHB1dCgpIHB1YmxpYyBjaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPENoYW5nZUV2ZW50PFRFZGl0b3I+PigpO1xuXG5cdC8qKlxuXHQgKiBGaXJlcyB3aGVuIHRoZSBlZGl0aW5nIHZpZXcgb2YgdGhlIGVkaXRvciBpcyBibHVycmVkLiBJdCBjb3JyZXNwb25kcyB3aXRoIHRoZSBgZWRpdG9yLmVkaXRpbmcudmlldy5kb2N1bWVudCNibHVyYFxuXHQgKiBodHRwczovL2NrZWRpdG9yLmNvbS9kb2NzL2NrZWRpdG9yNS9sYXRlc3QvYXBpL21vZHVsZV9lbmdpbmVfdmlld19kb2N1bWVudC1Eb2N1bWVudC5odG1sI2V2ZW50LWV2ZW50OmJsdXJcblx0ICogZXZlbnQuXG5cdCAqL1xuXHRAT3V0cHV0KCkgcHVibGljIGJsdXIgPSBuZXcgRXZlbnRFbWl0dGVyPEJsdXJFdmVudDxURWRpdG9yPj4oKTtcblxuXHQvKipcblx0ICogRmlyZXMgd2hlbiB0aGUgZWRpdGluZyB2aWV3IG9mIHRoZSBlZGl0b3IgaXMgZm9jdXNlZC4gSXQgY29ycmVzcG9uZHMgd2l0aCB0aGUgYGVkaXRvci5lZGl0aW5nLnZpZXcuZG9jdW1lbnQjZm9jdXNgXG5cdCAqIGh0dHBzOi8vY2tlZGl0b3IuY29tL2RvY3MvY2tlZGl0b3I1L2xhdGVzdC9hcGkvbW9kdWxlX2VuZ2luZV92aWV3X2RvY3VtZW50LURvY3VtZW50Lmh0bWwjZXZlbnQtZXZlbnQ6Zm9jdXNcblx0ICogZXZlbnQuXG5cdCAqL1xuXHRAT3V0cHV0KCkgcHVibGljIGZvY3VzID0gbmV3IEV2ZW50RW1pdHRlcjxGb2N1c0V2ZW50PFRFZGl0b3I+PigpO1xuXG5cdC8qKlxuXHQgKiBGaXJlcyB3aGVuIHRoZSBlZGl0b3IgY29tcG9uZW50IGNyYXNoZXMuXG5cdCAqL1xuXHRAT3V0cHV0KCkgcHVibGljIGVycm9yID0gbmV3IEV2ZW50RW1pdHRlcjx1bmtub3duPigpO1xuXG5cdC8qKlxuXHQgKiBUaGUgaW5zdGFuY2Ugb2YgdGhlIGVkaXRvciBjcmVhdGVkIGJ5IHRoaXMgY29tcG9uZW50LlxuXHQgKi9cblx0cHVibGljIGdldCBlZGl0b3JJbnN0YW5jZSgpOiBURWRpdG9yIHwgbnVsbCB7XG5cdFx0bGV0IGVkaXRvcldhdGNoZG9nID0gdGhpcy5lZGl0b3JXYXRjaGRvZztcblxuXHRcdGlmICggdGhpcy53YXRjaGRvZyApIHtcblx0XHRcdC8vIFRlbXBvcmFyaWx5IHVzZSB0aGUgYF93YXRjaGRvZ3NgIGludGVybmFsIG1hcCBhcyB0aGUgYGdldEl0ZW0oKWAgbWV0aG9kIHRocm93c1xuXHRcdFx0Ly8gYW4gZXJyb3Igd2hlbiB0aGUgaXRlbSBpcyBub3QgcmVnaXN0ZXJlZCB5ZXQuXG5cdFx0XHQvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2NrZWRpdG9yL2NrZWRpdG9yNS1hbmd1bGFyL2lzc3Vlcy8xNzcuXG5cdFx0XHQvLyBUT0RPIHNob3VsZCBiZSBhYmxlIHRvIGNoYW5nZSB3aGVuIG5ldyBjaGFnZXMgaW4gV2F0Y2RvZyBhcmUgcmVsZWFzZWQuXG5cdFx0XHRlZGl0b3JXYXRjaGRvZyA9ICggdGhpcy53YXRjaGRvZyBhcyBhbnkgKS5fd2F0Y2hkb2dzLmdldCggdGhpcy5pZCApO1xuXHRcdH1cblxuXHRcdGlmICggZWRpdG9yV2F0Y2hkb2cgKSB7XG5cdFx0XHRyZXR1cm4gZWRpdG9yV2F0Y2hkb2cuZWRpdG9yO1xuXHRcdH1cblxuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0LyoqXG5cdCAqIFRoZSBlZGl0b3Igd2F0Y2hkb2cuIEl0IGlzIGNyZWF0ZWQgd2hlbiB0aGUgY29udGV4dCB3YXRjaGRvZyBpcyBub3QgcGFzc2VkIHRvIHRoZSBjb21wb25lbnQuXG5cdCAqIEl0IGtlZXBzIHRoZSBlZGl0b3IgcnVubmluZy5cblx0ICovXG5cdHByaXZhdGUgZWRpdG9yV2F0Y2hkb2c/OiBFZGl0b3JXYXRjaGRvZzxURWRpdG9yPjtcblxuXHQvKipcblx0ICogSWYgdGhlIGNvbXBvbmVudCBpcyByZWFk4oCTb25seSBiZWZvcmUgdGhlIGVkaXRvciBpbnN0YW5jZSBpcyBjcmVhdGVkLCBpdCByZW1lbWJlcnMgdGhhdCBzdGF0ZSxcblx0ICogc28gdGhlIGVkaXRvciBjYW4gYmVjb21lIHJlYWTigJNvbmx5IG9uY2UgaXQgaXMgcmVhZHkuXG5cdCAqL1xuXHRwcml2YXRlIGluaXRpYWxseURpc2FibGVkID0gZmFsc2U7XG5cblx0LyoqXG5cdCAqIEFuIGluc3RhbmNlIG9mIGh0dHBzOi8vYW5ndWxhci5pby9hcGkvY29yZS9OZ1pvbmUgdG8gYWxsb3cgdGhlIGludGVyYWN0aW9uIHdpdGggdGhlIGVkaXRvclxuXHQgKiB3aXRoaW5nIHRoZSBBbmd1bGFyIGV2ZW50IGxvb3AuXG5cdCAqL1xuXHRwcml2YXRlIG5nWm9uZTogTmdab25lO1xuXG5cdC8qKlxuXHQgKiBBIGNhbGxiYWNrIGV4ZWN1dGVkIHdoZW4gdGhlIGNvbnRlbnQgb2YgdGhlIGVkaXRvciBjaGFuZ2VzLiBQYXJ0IG9mIHRoZVxuXHQgKiBgQ29udHJvbFZhbHVlQWNjZXNzb3JgIChodHRwczovL2FuZ3VsYXIuaW8vYXBpL2Zvcm1zL0NvbnRyb2xWYWx1ZUFjY2Vzc29yKSBpbnRlcmZhY2UuXG5cdCAqXG5cdCAqIE5vdGU6IFVuc2V0IHVubGVzcyB0aGUgY29tcG9uZW50IHVzZXMgdGhlIGBuZ01vZGVsYC5cblx0ICovXG5cdHByaXZhdGUgY3ZhT25DaGFuZ2U/OiAoIGRhdGE6IHN0cmluZyApID0+IHZvaWQ7XG5cblx0LyoqXG5cdCAqIEEgY2FsbGJhY2sgZXhlY3V0ZWQgd2hlbiB0aGUgZWRpdG9yIGhhcyBiZWVuIGJsdXJyZWQuIFBhcnQgb2YgdGhlXG5cdCAqIGBDb250cm9sVmFsdWVBY2Nlc3NvcmAgKGh0dHBzOi8vYW5ndWxhci5pby9hcGkvZm9ybXMvQ29udHJvbFZhbHVlQWNjZXNzb3IpIGludGVyZmFjZS5cblx0ICpcblx0ICogTm90ZTogVW5zZXQgdW5sZXNzIHRoZSBjb21wb25lbnQgdXNlcyB0aGUgYG5nTW9kZWxgLlxuXHQgKi9cblx0cHJpdmF0ZSBjdmFPblRvdWNoZWQ/OiAoKSA9PiB2b2lkO1xuXG5cdC8qKlxuXHQgKiBSZWZlcmVuY2UgdG8gdGhlIHNvdXJjZSBlbGVtZW50IHVzZWQgYnkgdGhlIGVkaXRvci5cblx0ICovXG5cdHByaXZhdGUgZWRpdG9yRWxlbWVudD86IEhUTUxFbGVtZW50O1xuXG5cdC8qKlxuXHQgKiBBIGxvY2sgZmxhZyBwcmV2ZW50aW5nIGZyb20gY2FsbGluZyB0aGUgYGN2YU9uQ2hhbmdlKClgIGR1cmluZyBzZXR0aW5nIGVkaXRvciBkYXRhLlxuXHQgKi9cblx0cHJpdmF0ZSBpc0VkaXRvclNldHRpbmdEYXRhID0gZmFsc2U7XG5cblx0cHJpdmF0ZSBpZCA9IHVpZCgpO1xuXG5cdHB1YmxpYyBnZXRJZCgpOiBzdHJpbmcge1xuXHRcdHJldHVybiB0aGlzLmlkO1xuXHR9XG5cblx0cHVibGljIGNvbnN0cnVjdG9yKCBASW5qZWN0KCBFbGVtZW50UmVmICkgZWxlbWVudFJlZjogRWxlbWVudFJlZiwgQEluamVjdCggTmdab25lICkgbmdab25lOiBOZ1pvbmUgKSB7XG5cdFx0dGhpcy5uZ1pvbmUgPSBuZ1pvbmU7XG5cdFx0dGhpcy5lbGVtZW50UmVmID0gZWxlbWVudFJlZjtcblxuXHRcdHRoaXMuY2hlY2tWZXJzaW9uKCk7XG5cdH1cblxuXHRwcml2YXRlIGNoZWNrVmVyc2lvbigpIHtcblx0XHQvLyBUbyBhdm9pZCBpc3N1ZXMgd2l0aCB0aGUgY29tbXVuaXR5IHR5cGluZ3MgYW5kIENLRWRpdG9yIDUsIGxldCdzIHRyZWF0IHdpbmRvdyBhcyBhbnkuIFNlZSAjMzQyLlxuXHRcdGNvbnN0IHsgQ0tFRElUT1JfVkVSU0lPTiB9ID0gKCB3aW5kb3cgYXMgYW55ICk7XG5cblx0XHRpZiAoICFDS0VESVRPUl9WRVJTSU9OICkge1xuXHRcdFx0cmV0dXJuIGNvbnNvbGUud2FybiggJ0Nhbm5vdCBmaW5kIHRoZSBcIkNLRURJVE9SX1ZFUlNJT05cIiBpbiB0aGUgXCJ3aW5kb3dcIiBzY29wZS4nICk7XG5cdFx0fVxuXG5cdFx0Y29uc3QgWyBtYWpvciBdID0gQ0tFRElUT1JfVkVSU0lPTi5zcGxpdCggJy4nICkubWFwKCBOdW1iZXIgKTtcblxuXHRcdGlmICggbWFqb3IgPj0gNDIgfHwgQ0tFRElUT1JfVkVSU0lPTi5zdGFydHNXaXRoKCAnMC4wLjAnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Y29uc29sZS53YXJuKCAnVGhlIDxDS0VkaXRvcj4gY29tcG9uZW50IHJlcXVpcmVzIHVzaW5nIENLRWRpdG9yIDUgaW4gdmVyc2lvbiA0Misgb3IgbmlnaHRseSBidWlsZC4nICk7XG5cdH1cblxuXHQvLyBJbXBsZW1lbnRpbmcgdGhlIE9uQ2hhbmdlcyBpbnRlcmZhY2UuIFdoZW5ldmVyIHRoZSBgZGF0YWAgcHJvcGVydHkgaXMgY2hhbmdlZCwgdXBkYXRlIHRoZSBlZGl0b3IgY29udGVudC5cblx0cHVibGljIG5nT25DaGFuZ2VzKCBjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzICk6IHZvaWQge1xuXHRcdGlmICggT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKCBjaGFuZ2VzLCAnZGF0YScgKSAmJiBjaGFuZ2VzLmRhdGEgJiYgIWNoYW5nZXMuZGF0YS5pc0ZpcnN0Q2hhbmdlKCkgKSB7XG5cdFx0XHR0aGlzLndyaXRlVmFsdWUoIGNoYW5nZXMuZGF0YS5jdXJyZW50VmFsdWUgKTtcblx0XHR9XG5cdH1cblxuXHQvLyBJbXBsZW1lbnRpbmcgdGhlIEFmdGVyVmlld0luaXQgaW50ZXJmYWNlLlxuXHRwdWJsaWMgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuXHRcdHRoaXMuYXR0YWNoVG9XYXRjaGRvZygpO1xuXHR9XG5cblx0Ly8gSW1wbGVtZW50aW5nIHRoZSBPbkRlc3Ryb3kgaW50ZXJmYWNlLlxuXHRwdWJsaWMgYXN5bmMgbmdPbkRlc3Ryb3koKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0aWYgKCB0aGlzLndhdGNoZG9nICkge1xuXHRcdFx0YXdhaXQgdGhpcy53YXRjaGRvZy5yZW1vdmUoIHRoaXMuaWQgKTtcblx0XHR9IGVsc2UgaWYgKCB0aGlzLmVkaXRvcldhdGNoZG9nICYmIHRoaXMuZWRpdG9yV2F0Y2hkb2cuZWRpdG9yICkge1xuXHRcdFx0YXdhaXQgdGhpcy5lZGl0b3JXYXRjaGRvZy5kZXN0cm95KCk7XG5cblx0XHRcdHRoaXMuZWRpdG9yV2F0Y2hkb2cgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHR9XG5cblx0Ly8gSW1wbGVtZW50aW5nIHRoZSBDb250cm9sVmFsdWVBY2Nlc3NvciBpbnRlcmZhY2UgKG9ubHkgd2hlbiBiaW5kaW5nIHRvIG5nTW9kZWwpLlxuXHRwdWJsaWMgd3JpdGVWYWx1ZSggdmFsdWU6IHN0cmluZyB8IG51bGwgKTogdm9pZCB7XG5cdFx0Ly8gVGhpcyBtZXRob2QgaXMgY2FsbGVkIHdpdGggdGhlIGBudWxsYCB2YWx1ZSB3aGVuIHRoZSBmb3JtIHJlc2V0cy5cblx0XHQvLyBBIGNvbXBvbmVudCdzIHJlc3BvbnNpYmlsaXR5IGlzIHRvIHJlc3RvcmUgdG8gdGhlIGluaXRpYWwgc3RhdGUuXG5cdFx0aWYgKCB2YWx1ZSA9PT0gbnVsbCApIHtcblx0XHRcdHZhbHVlID0gJyc7XG5cdFx0fVxuXG5cdFx0Ly8gSWYgYWxyZWFkeSBpbml0aWFsaXplZC5cblx0XHRpZiAoIHRoaXMuZWRpdG9ySW5zdGFuY2UgKSB7XG5cdFx0XHQvLyBUaGUgbG9jayBtZWNoYW5pc20gcHJldmVudHMgZnJvbSBjYWxsaW5nIGBjdmFPbkNoYW5nZSgpYCBkdXJpbmcgY2hhbmdpbmdcblx0XHRcdC8vIHRoZSBlZGl0b3Igc3RhdGUuIFNlZSAjMTM5XG5cdFx0XHR0aGlzLmlzRWRpdG9yU2V0dGluZ0RhdGEgPSB0cnVlO1xuXHRcdFx0dGhpcy5lZGl0b3JJbnN0YW5jZS5kYXRhLnNldCggdmFsdWUgKTtcblx0XHRcdHRoaXMuaXNFZGl0b3JTZXR0aW5nRGF0YSA9IGZhbHNlO1xuXHRcdH1cblx0XHQvLyBJZiBub3QsIHdhaXQgZm9yIGl0IHRvIGJlIHJlYWR5OyBzdG9yZSB0aGUgZGF0YS5cblx0XHRlbHNlIHtcblx0XHRcdC8vIElmIHRoZSBlZGl0b3IgZWxlbWVudCBpcyBhbHJlYWR5IGF2YWlsYWJsZSwgdGhlbiB1cGRhdGUgaXRzIGNvbnRlbnQuXG5cdFx0XHR0aGlzLmRhdGEgPSB2YWx1ZTtcblxuXHRcdFx0Ly8gSWYgbm90LCB0aGVuIHdhaXQgdW50aWwgaXQgaXMgcmVhZHlcblx0XHRcdC8vIGFuZCBjaGFuZ2UgZGF0YSBvbmx5IGZvciB0aGUgZmlyc3QgYHJlYWR5YCBldmVudC5cblx0XHRcdHRoaXMucmVhZHlcblx0XHRcdFx0LnBpcGUoIGZpcnN0KCkgKVxuXHRcdFx0XHQuc3Vic2NyaWJlKCBlZGl0b3IgPT4ge1xuXHRcdFx0XHRcdGVkaXRvci5kYXRhLnNldCggdGhpcy5kYXRhICk7XG5cdFx0XHRcdH0gKTtcblx0XHR9XG5cdH1cblxuXHQvLyBJbXBsZW1lbnRpbmcgdGhlIENvbnRyb2xWYWx1ZUFjY2Vzc29yIGludGVyZmFjZSAob25seSB3aGVuIGJpbmRpbmcgdG8gbmdNb2RlbCkuXG5cdHB1YmxpYyByZWdpc3Rlck9uQ2hhbmdlKCBjYWxsYmFjazogKCBkYXRhOiBzdHJpbmcgKSA9PiB2b2lkICk6IHZvaWQge1xuXHRcdHRoaXMuY3ZhT25DaGFuZ2UgPSBjYWxsYmFjaztcblx0fVxuXG5cdC8vIEltcGxlbWVudGluZyB0aGUgQ29udHJvbFZhbHVlQWNjZXNzb3IgaW50ZXJmYWNlIChvbmx5IHdoZW4gYmluZGluZyB0byBuZ01vZGVsKS5cblx0cHVibGljIHJlZ2lzdGVyT25Ub3VjaGVkKCBjYWxsYmFjazogKCkgPT4gdm9pZCApOiB2b2lkIHtcblx0XHR0aGlzLmN2YU9uVG91Y2hlZCA9IGNhbGxiYWNrO1xuXHR9XG5cblx0Ly8gSW1wbGVtZW50aW5nIHRoZSBDb250cm9sVmFsdWVBY2Nlc3NvciBpbnRlcmZhY2UgKG9ubHkgd2hlbiBiaW5kaW5nIHRvIG5nTW9kZWwpLlxuXHRwdWJsaWMgc2V0RGlzYWJsZWRTdGF0ZSggaXNEaXNhYmxlZDogYm9vbGVhbiApOiB2b2lkIHtcblx0XHQvLyBJZiBhbHJlYWR5IGluaXRpYWxpemVkLlxuXHRcdGlmICggdGhpcy5lZGl0b3JJbnN0YW5jZSApIHtcblx0XHRcdGlmICggaXNEaXNhYmxlZCApIHtcblx0XHRcdFx0dGhpcy5lZGl0b3JJbnN0YW5jZS5lbmFibGVSZWFkT25seU1vZGUoIEFOR1VMQVJfSU5URUdSQVRJT05fUkVBRF9PTkxZX0xPQ0tfSUQgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuZWRpdG9ySW5zdGFuY2UuZGlzYWJsZVJlYWRPbmx5TW9kZSggQU5HVUxBUl9JTlRFR1JBVElPTl9SRUFEX09OTFlfTE9DS19JRCApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIFN0b3JlIHRoZSBzdGF0ZSBhbnl3YXkgdG8gdXNlIGl0IG9uY2UgdGhlIGVkaXRvciBpcyBjcmVhdGVkLlxuXHRcdHRoaXMuaW5pdGlhbGx5RGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgdGhlIGVkaXRvciBpbnN0YW5jZSwgc2V0cyBpbml0aWFsIGVkaXRvciBkYXRhLCB0aGVuIGludGVncmF0ZXNcblx0ICogdGhlIGVkaXRvciB3aXRoIHRoZSBBbmd1bGFyIGNvbXBvbmVudC4gVGhpcyBtZXRob2QgZG9lcyBub3QgdXNlIHRoZSBgZWRpdG9yLmRhdGEuc2V0KClgXG5cdCAqIGJlY2F1c2Ugb2YgdGhlIGlzc3VlIGluIHRoZSBjb2xsYWJvcmF0aW9uIG1vZGUgKCM2KS5cblx0ICovXG5cdHByaXZhdGUgYXR0YWNoVG9XYXRjaGRvZygpIHtcblx0XHQvLyBUT0RPOiBlbGVtZW50T3JEYXRhIHBhcmFtZXRlciB0eXBlIGNhbiBiZSBzaW1wbGlmaWVkIHRvIEhUTUxFbGVtZW4gYWZ0ZXIgdGVtcGxhdGVkIFdhdGNoZG9nIHdpbGwgYmUgcmVsZWFzZWQuXG5cdFx0Y29uc3QgY3JlYXRvcjogRWRpdG9yV2F0Y2hkb2dDcmVhdG9yRnVuY3Rpb248VEVkaXRvcj4gPSAoICggZWxlbWVudE9yRGF0YSwgY29uZmlnICkgPT4ge1xuXHRcdFx0cmV0dXJuIHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCBhc3luYyAoKSA9PiB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LmFwcGVuZENoaWxkKCBlbGVtZW50T3JEYXRhIGFzIEhUTUxFbGVtZW50ICk7XG5cblx0XHRcdFx0Y29uc3QgZWRpdG9yID0gYXdhaXQgdGhpcy5lZGl0b3IhLmNyZWF0ZSggZWxlbWVudE9yRGF0YSBhcyBIVE1MRWxlbWVudCwgY29uZmlnICk7XG5cblx0XHRcdFx0aWYgKCB0aGlzLmluaXRpYWxseURpc2FibGVkICkge1xuXHRcdFx0XHRcdGVkaXRvci5lbmFibGVSZWFkT25seU1vZGUoIEFOR1VMQVJfSU5URUdSQVRJT05fUkVBRF9PTkxZX0xPQ0tfSUQgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoaXMubmdab25lLnJ1biggKCkgPT4ge1xuXHRcdFx0XHRcdHRoaXMucmVhZHkuZW1pdCggZWRpdG9yICk7XG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0XHR0aGlzLnNldFVwRWRpdG9yRXZlbnRzKCBlZGl0b3IgKTtcblxuXHRcdFx0XHRyZXR1cm4gZWRpdG9yO1xuXHRcdFx0fSApO1xuXHRcdH0gKTtcblxuXHRcdGNvbnN0IGRlc3RydWN0b3IgPSBhc3luYyAoIGVkaXRvcjogRWRpdG9yICkgPT4ge1xuXHRcdFx0YXdhaXQgZWRpdG9yLmRlc3Ryb3koKTtcblxuXHRcdFx0dGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQucmVtb3ZlQ2hpbGQoIHRoaXMuZWRpdG9yRWxlbWVudCEgKTtcblx0XHR9O1xuXG5cdFx0Y29uc3QgZW1pdEVycm9yID0gKCBlPzogdW5rbm93biApID0+IHtcblx0XHRcdC8vIERvIG5vdCBydW4gY2hhbmdlIGRldGVjdGlvbiBieSByZS1lbnRlcmluZyB0aGUgQW5ndWxhciB6b25lIGlmIHRoZSBgZXJyb3JgXG5cdFx0XHQvLyBlbWl0dGVyIGRvZXNuJ3QgaGF2ZSBhbnkgc3Vic2NyaWJlcnMuXG5cdFx0XHQvLyBTdWJzY3JpYmVycyBhcmUgcHVzaGVkIG9udG8gdGhlIGxpc3Qgd2hlbmV2ZXIgYGVycm9yYCBpcyBsaXN0ZW5lZCBpbnNpZGUgdGhlIHRlbXBsYXRlOlxuXHRcdFx0Ly8gYDxja2VkaXRvciAoZXJyb3IpPVwib25FcnJvciguLi4pXCI+PC9ja2VkaXRvcj5gLlxuXHRcdFx0aWYgKCBoYXNPYnNlcnZlcnMoIHRoaXMuZXJyb3IgKSApIHtcblx0XHRcdFx0dGhpcy5uZ1pvbmUucnVuKCAoKSA9PiB0aGlzLmVycm9yLmVtaXQoIGUgKSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gUHJpbnQgZXJyb3IgdG8gdGhlIGNvbnNvbGUgd2hlbiB0aGVyZSBhcmUgbm8gc3Vic2NyaWJlcnMgdG8gdGhlIGBlcnJvcmAgZXZlbnQuXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGUgKTtcblx0XHRcdH1cblx0XHR9O1xuXHRcdGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCB0aGlzLnRhZ05hbWUgKTtcblx0XHRjb25zdCBjb25maWcgPSB0aGlzLmdldENvbmZpZygpO1xuXG5cdFx0dGhpcy5lZGl0b3JFbGVtZW50ID0gZWxlbWVudDtcblxuXHRcdC8vIEJhc2VkIG9uIHRoZSBwcmVzZW5jZSBvZiB0aGUgd2F0Y2hkb2cgZGVjaWRlIGhvdyB0byBpbml0aWFsaXplIHRoZSBlZGl0b3IuXG5cdFx0aWYgKCB0aGlzLndhdGNoZG9nICkge1xuXHRcdFx0Ly8gV2hlbiB0aGUgY29udGV4dCB3YXRjaGRvZyBpcyBwYXNzZWQgYWRkIHRoZSBuZXcgaXRlbSB0byBpdCBiYXNlZCBvbiB0aGUgcGFzc2VkIGNvbmZpZ3VyYXRpb24uXG5cdFx0XHR0aGlzLndhdGNoZG9nLmFkZCgge1xuXHRcdFx0XHRpZDogdGhpcy5pZCxcblx0XHRcdFx0dHlwZTogJ2VkaXRvcicsXG5cdFx0XHRcdGNyZWF0b3IsXG5cdFx0XHRcdGRlc3RydWN0b3IsXG5cdFx0XHRcdHNvdXJjZUVsZW1lbnRPckRhdGE6IGVsZW1lbnQsXG5cdFx0XHRcdGNvbmZpZ1xuXHRcdFx0fSApLmNhdGNoKCBlID0+IHtcblx0XHRcdFx0ZW1pdEVycm9yKCBlICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMud2F0Y2hkb2cub24oICdpdGVtRXJyb3InLCAoIF8sIHsgaXRlbUlkIH0gKSA9PiB7XG5cdFx0XHRcdGlmICggaXRlbUlkID09PSB0aGlzLmlkICkge1xuXHRcdFx0XHRcdGVtaXRFcnJvcigpO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIEluIHRoZSBvdGhlciBjYXNlIGNyZWF0ZSB0aGUgd2F0Y2hkb2cgYnkgaGFuZCB0byBrZWVwIHRoZSBlZGl0b3IgcnVubmluZy5cblx0XHRcdGNvbnN0IGVkaXRvcldhdGNoZG9nID0gbmV3IHRoaXMuZWRpdG9yIS5FZGl0b3JXYXRjaGRvZyhcblx0XHRcdFx0dGhpcy5lZGl0b3IhLFxuXHRcdFx0XHR0aGlzLmVkaXRvcldhdGNoZG9nQ29uZmlnXG5cdFx0XHQpO1xuXG5cdFx0XHRlZGl0b3JXYXRjaGRvZy5zZXRDcmVhdG9yKCBjcmVhdG9yICk7XG5cdFx0XHRlZGl0b3JXYXRjaGRvZy5zZXREZXN0cnVjdG9yKCBkZXN0cnVjdG9yICk7XG5cdFx0XHRlZGl0b3JXYXRjaGRvZy5vbiggJ2Vycm9yJywgZW1pdEVycm9yICk7XG5cblx0XHRcdHRoaXMuZWRpdG9yV2F0Y2hkb2cgPSBlZGl0b3JXYXRjaGRvZztcblx0XHRcdHRoaXMubmdab25lLnJ1bk91dHNpZGVBbmd1bGFyKCAoKSA9PiB7XG5cdFx0XHRcdC8vIE5vdGU6IG11c3QgYmUgY2FsbGVkIG91dHNpZGUgb2YgdGhlIEFuZ3VsYXIgem9uZSB0b28gYmVjYXVzZSBgY3JlYXRlYCBpcyBjYWxsaW5nXG5cdFx0XHRcdC8vIGBfc3RhcnRFcnJvckhhbmRsaW5nYCB3aXRoaW4gYSBtaWNyb3Rhc2sgd2hpY2ggc2V0cyB1cCBgZXJyb3JgIGxpc3RlbmVyIG9uIHRoZSB3aW5kb3cuXG5cdFx0XHRcdGVkaXRvcldhdGNoZG9nLmNyZWF0ZSggZWxlbWVudCwgY29uZmlnICkuY2F0Y2goIGUgPT4ge1xuXHRcdFx0XHRcdGVtaXRFcnJvciggZSApO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBnZXRDb25maWcoKSB7XG5cdFx0aWYgKCB0aGlzLmRhdGEgJiYgdGhpcy5jb25maWcuaW5pdGlhbERhdGEgKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdFZGl0b3IgZGF0YSBzaG91bGQgYmUgcHJvdmlkZWQgZWl0aGVyIHVzaW5nIGBjb25maWcuaW5pdGlhbERhdGFgIG9yIGBkYXRhYCBwcm9wZXJ0aWVzLicgKTtcblx0XHR9XG5cblx0XHRjb25zdCBjb25maWcgPSB7IC4uLnRoaXMuY29uZmlnIH07XG5cblx0XHQvLyBNZXJnZSB0d28gcG9zc2libGUgd2F5cyBvZiBwcm92aWRpbmcgZGF0YSBpbnRvIHRoZSBgY29uZmlnLmluaXRpYWxEYXRhYCBmaWVsZC5cblx0XHRjb25zdCBpbml0aWFsRGF0YSA9IHRoaXMuY29uZmlnLmluaXRpYWxEYXRhIHx8IHRoaXMuZGF0YTtcblxuXHRcdGlmICggaW5pdGlhbERhdGEgKSB7XG5cdFx0X