UNPKG

ngx-editor

Version:

The Rich Text Editor for Angular, Built on ProseMirror

105 lines 19 kB
import { Component, HostListener, } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { NodeSelection } from 'prosemirror-state'; import { Image as ImageCommand } from '../MenuCommands'; import * as i0 from "@angular/core"; import * as i1 from "../../../editor.service"; import * as i2 from "../menu.service"; import * as i3 from "@angular/common"; import * as i4 from "@angular/forms"; import * as i5 from "../../../pipes/sanitize/sanitize-html.pipe"; export class ImageComponent { constructor(el, ngxeService, menuService) { this.el = el; this.ngxeService = ngxeService; this.menuService = menuService; this.showPopup = false; this.isActive = false; this.form = new FormGroup({ src: new FormControl('', [ Validators.required, Validators.pattern('(https?://)?([\\da-z.-]+)\\.([a-z.]{2,6})[/\\w .-]*/??([^#\n\r]*)?#?([^\n\r]*)'), ]), alt: new FormControl(''), title: new FormControl(''), }); this.update = (view) => { const { state } = view; this.isActive = ImageCommand.isActive(state); }; } get icon() { return this.ngxeService.getIcon('image'); } get src() { return this.form.get('src'); } onDocumentClick(e) { if (!this.el.nativeElement.contains(e.target) && this.showPopup) { this.hideForm(); } } getLabel(key) { return this.ngxeService.locals.get(key); } hideForm() { this.showPopup = false; this.form.reset({ src: '', alt: '', title: '', }); } onMouseDown(e) { if (e.button !== 0) { return; } this.showPopup = !this.showPopup; if (this.showPopup) { this.fillForm(); } } fillForm() { const { state } = this.editorView; const { selection } = state; if (selection instanceof NodeSelection && this.isActive) { const { src, alt = '', title = '' } = selection.node.attrs; this.form.setValue({ src, alt, title, }); } } insertLink(e) { e.preventDefault(); const { src, alt, title } = this.form.getRawValue(); const { dispatch, state } = this.editorView; const attrs = { alt, title, }; ImageCommand.insert(src, attrs)(state, dispatch); this.editorView.focus(); this.hideForm(); } ngOnInit() { this.editorView = this.menuService.editor.view; this.updateSubscription = this.menuService.editor.update.subscribe((view) => { this.update(view); }); } ngOnDestroy() { this.updateSubscription.unsubscribe(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ElementRef }, { token: i1.NgxEditorService }, { token: i2.MenuService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.1", type: ImageComponent, selector: "ngx-image", host: { listeners: { "document:mousedown": "onDocumentClick($event)" } }, ngImport: i0, template: "<div class=\"NgxEditor__MenuItem--IconContainer\" [class.NgxEditor__MenuItem--Active]=\"isActive || showPopup\"\n [innerHTML]=\"icon | sanitizeHtml\" (mousedown)=\"onMouseDown($event)\" [title]=\"getLabel('insertImage') | async\">\n</div>\n\n<!-- popup -->\n<div *ngIf=\"showPopup\" class=\"NgxEditor__Popup\">\n <form class=\"NgxEditor__Popup--Form\" [formGroup]=\"form\" (ngSubmit)=\"insertLink($event)\">\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('url') | async}}</label>\n <input type=\"href\" id=\"href\" formControlName=\"src\" autofocus autocomplete=\"off\" />\n <div *ngIf=\"src.touched && src.invalid\" class=\"NgxEditor__HelpText NgxEditor__HelpText--Error\">\n {{ src.errors?.['pattern'] && 'Please enter valid url.' }}\n </div>\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('altText') | async}}</label>\n <input type=\"text\" formControlName=\"alt\" autocomplete=\"off\" />\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('title') | async}}</label>\n <input type=\"text\" formControlName=\"title\" autocomplete=\"off\" />\n </div>\n </div>\n\n <button type=\"submit\" [disabled]=\"!form.valid || !form.dirty\">{{getLabel('insert') | async}}</button>\n\n </form>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.SanitizeHtmlPipe, name: "sanitizeHtml" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.1", ngImport: i0, type: ImageComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-image', template: "<div class=\"NgxEditor__MenuItem--IconContainer\" [class.NgxEditor__MenuItem--Active]=\"isActive || showPopup\"\n [innerHTML]=\"icon | sanitizeHtml\" (mousedown)=\"onMouseDown($event)\" [title]=\"getLabel('insertImage') | async\">\n</div>\n\n<!-- popup -->\n<div *ngIf=\"showPopup\" class=\"NgxEditor__Popup\">\n <form class=\"NgxEditor__Popup--Form\" [formGroup]=\"form\" (ngSubmit)=\"insertLink($event)\">\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('url') | async}}</label>\n <input type=\"href\" id=\"href\" formControlName=\"src\" autofocus autocomplete=\"off\" />\n <div *ngIf=\"src.touched && src.invalid\" class=\"NgxEditor__HelpText NgxEditor__HelpText--Error\">\n {{ src.errors?.['pattern'] && 'Please enter valid url.' }}\n </div>\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('altText') | async}}</label>\n <input type=\"text\" formControlName=\"alt\" autocomplete=\"off\" />\n </div>\n </div>\n\n <div class=\"NgxEditor__Popup--FormGroup\">\n <div class=\"NgxEditor__Popup--Col\">\n <label class=\"NgxEditor__Popup--Label\">{{getLabel('title') | async}}</label>\n <input type=\"text\" formControlName=\"title\" autocomplete=\"off\" />\n </div>\n </div>\n\n <button type=\"submit\" [disabled]=\"!form.valid || !form.dirty\">{{getLabel('insert') | async}}</button>\n\n </form>\n</div>\n" }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.NgxEditorService }, { type: i2.MenuService }]; }, propDecorators: { onDocumentClick: [{ type: HostListener, args: ['document:mousedown', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWVkaXRvci9zcmMvbGliL21vZHVsZXMvbWVudS9pbWFnZS9pbWFnZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZWRpdG9yL3NyYy9saWIvbW9kdWxlcy9tZW51L2ltYWdlL2ltYWdlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBbUIsV0FBVyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFNbEQsT0FBTyxFQUFFLEtBQUssSUFBSSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7OztBQVF4RCxNQUFNLE9BQU8sY0FBYztJQWdCekIsWUFDVSxFQUFjLEVBQ2QsV0FBNkIsRUFDN0IsV0FBd0I7UUFGeEIsT0FBRSxHQUFGLEVBQUUsQ0FBWTtRQUNkLGdCQUFXLEdBQVgsV0FBVyxDQUFrQjtRQUM3QixnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQWxCbEMsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixhQUFRLEdBQUcsS0FBSyxDQUFDO1FBR2pCLFNBQUksR0FBRyxJQUFJLFNBQVMsQ0FBQztZQUNuQixHQUFHLEVBQUUsSUFBSSxXQUFXLENBQUMsRUFBRSxFQUFFO2dCQUN2QixVQUFVLENBQUMsUUFBUTtnQkFDbkIsVUFBVSxDQUFDLE9BQU8sQ0FBQyxnRkFBZ0YsQ0FBQzthQUNyRyxDQUFDO1lBQ0YsR0FBRyxFQUFFLElBQUksV0FBVyxDQUFDLEVBQUUsQ0FBQztZQUN4QixLQUFLLEVBQUUsSUFBSSxXQUFXLENBQUMsRUFB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QUMsTUFBTSxDQUFDLElBQUksQ0FBQztRQUUvQyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQWdCLEVBQUUsRUFBRTtZQUN0RixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3BCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELFdBQVc7UUFDVCxJQUFJLENBQUMsa0JBQWtCLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDeEMsQ0FBQzs4R0F6R1UsY0FBYztrR0FBZCxjQUFjLDJIQ25CM0IsOGxEQW9DQTs7MkZEakJhLGNBQWM7a0JBTDFCLFNBQVM7K0JBQ0UsV0FBVzswSkFrQzJCLGVBQWU7c0JBQTlELFlBQVk7dUJBQUMsb0JBQW9CLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsIEVsZW1lbnRSZWYsXG4gIEhvc3RMaXN0ZW5lciwgT25EZXN0cm95LCBPbkluaXQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBGb3JtQ29udHJvbCwgRm9ybUdyb3VwLCBWYWxpZGF0b3JzIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgTm9kZVNlbGVjdGlvbiB9IGZyb20gJ3Byb3NlbWlycm9yLXN0YXRlJztcbmltcG9ydCB7IEVkaXRvclZpZXcgfSBmcm9tICdwcm9zZW1pcnJvci12aWV3JztcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBOZ3hFZGl0b3JTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vLi4vZWRpdG9yLnNlcnZpY2UnO1xuaW1wb3J0IHsgTWVudVNlcnZpY2UgfSBmcm9tICcuLi9tZW51LnNlcnZpY2UnO1xuaW1wb3J0IHsgSW1hZ2UgYXMgSW1hZ2VDb21tYW5kIH0gZnJvbSAnLi4vTWVudUNvbW1hbmRzJztcbmltcG9ydCB7IEhUTUwgfSBmcm9tICcuLi8uLi8uLi90cnVzdGVkVHlwZXNVdGlsJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmd4LWltYWdlJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2ltYWdlLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vaW1hZ2UuY29tcG9uZW50LnNjc3MnXSxcbn0pXG5leHBvcnQgY2xhc3MgSW1hZ2VDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSB7XG4gIHNob3dQb3B1cCA9IGZhbHNlO1xuICBpc0FjdGl2ZSA9IGZhbHNlO1xuICBwcml2YXRlIHVwZGF0ZVN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIGZvcm0gPSBuZXcgRm9ybUdyb3VwKHtcbiAgICBzcmM6IG5ldyBGb3JtQ29udHJvbCgnJywgW1xuICAgICAgVmFsaWRhdG9ycy5yZXF1aXJlZCxcbiAgICAgIFZhbGlkYXRvcnMucGF0dGVybignKGh0dHBzPzovLyk/KFtcXFxcZGEtei4tXSspXFxcXC4oW2Etei5dezIsNn0pWy9cXFxcdyAuLV0qLz8/KFteI1xcblxccl0qKT8jPyhbXlxcblxccl0qKScpLFxuICAgIF0pLFxuICAgIGFsdDogbmV3IEZvcm1Db250cm9sKCcnKSxcbiAgICB0aXRsZTogbmV3IEZvcm1Db250cm9sKCcnKSxcbiAgfSk7XG5cbiAgcHJpdmF0ZSBlZGl0b3JWaWV3OiBFZGl0b3JWaWV3O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgZWw6IEVsZW1lbnRSZWYsXG4gICAgcHJpdmF0ZSBuZ3hlU2VydmljZTogTmd4RWRpdG9yU2VydmljZSxcbiAgICBwcml2YXRlIG1lbnVTZXJ2aWNlOiBNZW51U2VydmljZSxcbiAgKSB7IH1cblxuICBnZXQgaWNvbigpOiBIVE1MIHtcbiAgICByZXR1cm4gdGhpcy5uZ3hlU2VydmljZS5nZXRJY29uKCdpbWFnZScpO1xuICB9XG5cbiAgZ2V0IHNyYygpOiBBYnN0cmFjdENvbnRyb2wge1xuICAgIHJldHVybiB0aGlzLmZvcm0uZ2V0KCdzcmMnKTtcbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50Om1vdXNlZG93bicsIFsnJGV2ZW50J10pIG9uRG9jdW1lbnRDbGljayhlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmVsLm5hdGl2ZUVsZW1lbnQuY29udGFpbnMoZS50YXJnZXQpICYmIHRoaXMuc2hvd1BvcHVwKSB7XG4gICAgICB0aGlzLmhpZGVGb3JtKCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0TGFiZWwoa2V5OiBzdHJpbmcpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgIHJldHVybiB0aGlzLm5neGVTZXJ2aWNlLmxvY2Fscy5nZXQoa2V5KTtcbiAgfVxuXG4gIHByaXZhdGUgaGlkZUZvcm0oKTogdm9pZCB7XG4gICAgdGhpcy5zaG93UG9wdXAgPSBmYWxzZTtcbiAgICB0aGlzLmZvcm0ucmVzZXQoe1xuICAgICAgc3JjOiAnJyxcbiAgICAgIGFsdDogJycsXG4gICAgICB0aXRsZTogJycsXG4gICAgfSk7XG4gIH1cblxuICBvbk1vdXNlRG93bihlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKGUuYnV0dG9uICE9PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zaG93UG9wdXAgPSAhdGhpcy5zaG93UG9wdXA7XG5cbiAgICBpZiAodGhpcy5zaG93UG9wdXApIHtcbiAgICAgIHRoaXMuZmlsbEZvcm0oKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGZpbGxGb3JtKCk6IHZvaWQge1xuICAgIGNvbnN0IHsgc3RhdGUgfSA9IHRoaXMuZWRpdG9yVmlldztcbiAgICBjb25zdCB7IHNlbGVjdGlvbiB9ID0gc3RhdGU7XG4gICAgaWYgKHNlbGVjdGlvbiBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24gJiYgdGhpcy5pc0FjdGl2ZSkge1xuICAgICAgY29uc3QgeyBzcmMsIGFsdCA9ICcnLCB0aXRsZSA9ICcnIH0gPSBzZWxlY3Rpb24ubm9kZS5hdHRycztcblxuICAgICAgdGhpcy5mb3JtLnNldFZhbHVlKHtcbiAgICAgICAgc3JjLFxuICAgICAgICBhbHQsXG4gICAgICAgIHRpdGxlLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGUgPSAodmlldzogRWRpdG9yVmlldykgPT4ge1xuICAgIGNvbnN0IHsgc3RhdGUgfSA9IHZpZXc7XG4gICAgdGhpcy5pc0FjdGl2ZSA9IEltYWdlQ29tbWFuZC5pc0FjdGl2ZShzdGF0ZSk7XG4gIH07XG5cbiAgaW5zZXJ0TGluayhlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IHsgc3JjLCBhbHQsIHRpdGxlIH0gPSB0aGlzLmZvcm0uZ2V0UmF3VmFsdWUoKTtcbiAgICBjb25zdCB7IGRpc3BhdGNoLCBzdGF0ZSB9ID0gdGhpcy5lZGl0b3JWaWV3O1xuXG4gICAgY29uc3QgYXR0cnMgPSB7XG4gICAgICBhbHQsXG4gICAgICB0aXRsZSxcbiAgICB9O1xuXG4gICAgSW1hZ2VDb21tYW5kLmluc2VydChzcmMsIGF0dHJzKShzdGF0ZSwgZGlzcGF0Y2gpO1xuICAgIHRoaXMuZWRpdG9yVmlldy5mb2N1cygpO1xuICAgIHRoaXMuaGlkZUZvcm0oKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZWRpdG9yVmlldyA9IHRoaXMubWVudVNlcnZpY2UuZWRpdG9yLnZpZXc7XG5cbiAgICB0aGlzLnVwZGF0ZVN1YnNjcmlwdGlvbiA9IHRoaXMubWVudVNlcnZpY2UuZWRpdG9yLnVwZGF0ZS5zdWJzY3JpYmUoKHZpZXc6IEVkaXRvclZpZXcpID0+IHtcbiAgICAgIHRoaXMudXBkYXRlKHZpZXcpO1xuICAgIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy51cGRhdGVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cIk5neEVkaXRvcl9fTWVudUl0ZW0tLUljb25Db250YWluZXJcIiBbY2xhc3MuTmd4RWRpdG9yX19NZW51SXRlbS0tQWN0aXZlXT1cImlzQWN0aXZlIHx8IHNob3dQb3B1cFwiXG4gIFtpbm5lckhUTUxdPVwiaWNvbiB8IHNhbml0aXplSHRtbFwiIChtb3VzZWRvd24pPVwib25Nb3VzZURvd24oJGV2ZW50KVwiIFt0aXRsZV09XCJnZXRMYWJlbCgnaW5zZXJ0SW1hZ2UnKSB8IGFzeW5jXCI+XG48L2Rpdj5cblxuPCEtLSBwb3B1cCAtLT5cbjxkaXYgKm5nSWY9XCJzaG93UG9wdXBcIiBjbGFzcz1cIk5neEVkaXRvcl9fUG9wdXBcIj5cbiAgPGZvcm0gY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtXCIgW2Zvcm1Hcm91cF09XCJmb3JtXCIgKG5nU3VibWl0KT1cImluc2VydExpbmsoJGV2ZW50KVwiPlxuXG4gICAgPGRpdiBjbGFzcz1cIk5neEVkaXRvcl9fUG9wdXAtLUZvcm1Hcm91cFwiPlxuICAgICAgPGRpdiBjbGFzcz1cIk5neEVkaXRvcl9fUG9wdXAtLUNvbFwiPlxuICAgICAgICA8bGFiZWwgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1MYWJlbFwiPnt7Z2V0TGFiZWwoJ3VybCcpIHwgYXN5bmN9fTwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCB0eXBlPVwiaHJlZlwiIGlkPVwiaHJlZlwiIGZvcm1Db250cm9sTmFtZT1cInNyY1wiIGF1dG9mb2N1cyBhdXRvY29tcGxldGU9XCJvZmZcIiAvPlxuICAgICAgICA8ZGl2ICpuZ0lmPVwic3JjLnRvdWNoZWQgJiYgc3JjLmludmFsaWRcIiBjbGFzcz1cIk5neEVkaXRvcl9fSGVscFRleHQgTmd4RWRpdG9yX19IZWxwVGV4dC0tRXJyb3JcIj5cbiAgICAgICAgICB7eyBzcmMuZXJyb3JzPy5bJ3BhdHRlcm4nXSAmJiAnUGxlYXNlIGVudGVyIHZhbGlkIHVybC4nIH19XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2IGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tRm9ybUdyb3VwXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tQ29sXCI+XG4gICAgICAgIDxsYWJlbCBjbGFzcz1cIk5neEVkaXRvcl9fUG9wdXAtLUxhYmVsXCI+e3tnZXRMYWJlbCgnYWx0VGV4dCcpIHwgYXN5bmN9fTwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIGZvcm1Db250cm9sTmFtZT1cImFsdFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCd0aXRsZScpIHwgYXN5bmN9fTwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIGZvcm1Db250cm9sTmFtZT1cInRpdGxlXCIgYXV0b2NvbXBsZXRlPVwib2ZmXCIgLz5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCIgW2Rpc2FibGVkXT1cIiFmb3JtLnZhbGlkIHx8ICFmb3JtLmRpcnR5XCI+e3tnZXRMYWJlbCgnaW5zZXJ0JykgfCBhc3luY319PC9idXR0b24+XG5cbiAgPC9mb3JtPlxuPC9kaXY+XG4iXX0=