UNPKG

@ckeditor/ckeditor5-angular

Version:

Official Angular component for CKEditor 5 – the best browser-based rich text editor.

430 lines 52.2 kB
/** * @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