UNPKG

ngx-editor

Version:

Rich Text Editor for angular using ProseMirror

106 lines 18.7 kB
import { Component, HostListener, } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { NodeSelection } from 'prosemirror-state'; import Icon from '../../../icons'; 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 Icon.get('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(); } } ImageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: ImageComponent, deps: [{ token: i0.ElementRef }, { token: i1.NgxEditorService }, { token: i2.MenuService }], target: i0.ɵɵFactoryTarget.Component }); ImageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.7", 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')\">\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')}}</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')}}</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')}}</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')}}</button>\n\n </form>\n</div>\n", styles: [""], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { 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]" }, { type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }], pipes: { "sanitizeHtml": i5.SanitizeHtmlPipe } }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", 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')\">\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')}}</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')}}</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')}}</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')}}</button>\n\n </form>\n</div>\n", styles: [""] }] }], 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWVkaXRvci9zcmMvbGliL21vZHVsZXMvbWVudS9pbWFnZS9pbWFnZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZWRpdG9yL3NyYy9saWIvbW9kdWxlcy9tZW51L2ltYWdlL2ltYWdlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxHQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBbUIsV0FBVyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFNbEQsT0FBTyxJQUFJLE1BQU0sZ0JBQWdCLENBQUM7QUFDbEMsT0FBTyxFQUFFLEtBQUssSUFBSSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7OztBQU94RCxNQUFNLE9BQU8sY0FBYztJQWdCekIsWUFDVSxFQUFjLEVBQ2QsV0FBNkIsRUFDN0IsV0FBd0I7UUFGeEIsT0FBRSxHQUFGLEVBQUUsQ0FBWTtRQUNkLGdCQUFXLEdBQVgsV0FBVyxDQUFrQjtRQUM3QixnQkFBVyxHQUFYLFdBQVcsQ0FBYTtRQWxCbEMsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixhQUFRLEdBQUcsS0FBSyxDQUFDO1FBR2pCLFNBQUksR0FBRyxJQUFJLFNBQVMsQ0FBQztZQUNuQixHQUFHLEVBQUUsSUFBSSxXQUFXLENBQUMsRUFBRSxFQUFFO2dCQUN2QixVQUFVLENBQUMsUUFBUTtnQkFDbkIsVUFBVSxDQUFDLE9BQU8sQ0FBQyxnRkFBZ0YsQ0FBQzthQUNyRyxDQUFDO1lBQ0YsR0FBRyxFQUFFLElBQUksV0FBVyxDQUFDLEVBQUUsQ0FBQztZ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LEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO1FBRS9DLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBZ0IsRUFBRSxFQUFFO1lBQ3RGLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDcEIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUN4QyxDQUFDOzsyR0F6R1UsY0FBYzsrRkFBZCxjQUFjLDJIQ25CM0Isc2pEQW9DQTsyRkRqQmEsY0FBYztrQkFMMUIsU0FBUzsrQkFDRSxXQUFXOzBKQWtDMkIsZUFBZTtzQkFBOUQsWUFBWTt1QkFBQyxvQkFBb0IsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCwgRWxlbWVudFJlZixcbiAgSG9zdExpc3RlbmVyLCBPbkRlc3Ryb3ksIE9uSW5pdCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1Db250cm9sLCBGb3JtR3JvdXAsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBOb2RlU2VsZWN0aW9uIH0gZnJvbSAncHJvc2VtaXJyb3Itc3RhdGUnO1xuaW1wb3J0IHsgRWRpdG9yVmlldyB9IGZyb20gJ3Byb3NlbWlycm9yLXZpZXcnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IE5neEVkaXRvclNlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9lZGl0b3Iuc2VydmljZSc7XG5pbXBvcnQgeyBNZW51U2VydmljZSB9IGZyb20gJy4uL21lbnUuc2VydmljZSc7XG5pbXBvcnQgSWNvbiBmcm9tICcuLi8uLi8uLi9pY29ucyc7XG5pbXBvcnQgeyBJbWFnZSBhcyBJbWFnZUNvbW1hbmQgfSBmcm9tICcuLi9NZW51Q29tbWFuZHMnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtaW1hZ2UnLFxuICB0ZW1wbGF0ZVVybDogJy4vaW1hZ2UuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9pbWFnZS5jb21wb25lbnQuc2NzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBJbWFnZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgc2hvd1BvcHVwID0gZmFsc2U7XG4gIGlzQWN0aXZlID0gZmFsc2U7XG4gIHByaXZhdGUgdXBkYXRlU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG5cbiAgZm9ybSA9IG5ldyBGb3JtR3JvdXAoe1xuICAgIHNyYzogbmV3IEZvcm1Db250cm9sKCcnLCBbXG4gICAgICBWYWxpZGF0b3JzLnJlcXVpcmVkLFxuICAgICAgVmFsaWRhdG9ycy5wYXR0ZXJuKCcoaHR0cHM/Oi8vKT8oW1xcXFxkYS16Li1dKylcXFxcLihbYS16Ll17Miw2fSlbL1xcXFx3IC4tXSovPz8oW14jXFxuXFxyXSopPyM/KFteXFxuXFxyXSopJyksXG4gICAgXSksXG4gICAgYWx0OiBuZXcgRm9ybUNvbnRyb2woJycpLFxuICAgIHRpdGxlOiBuZXcgRm9ybUNvbnRyb2woJycpLFxuICB9KTtcblxuICBwcml2YXRlIGVkaXRvclZpZXc6IEVkaXRvclZpZXc7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBlbDogRWxlbWVudFJlZixcbiAgICBwcml2YXRlIG5neGVTZXJ2aWNlOiBOZ3hFZGl0b3JTZXJ2aWNlLFxuICAgIHByaXZhdGUgbWVudVNlcnZpY2U6IE1lbnVTZXJ2aWNlLFxuICApIHsgfVxuXG4gIGdldCBpY29uKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIEljb24uZ2V0KCdpbWFnZScpO1xuICB9XG5cbiAgZ2V0IHNyYygpOiBBYnN0cmFjdENvbnRyb2wge1xuICAgIHJldHVybiB0aGlzLmZvcm0uZ2V0KCdzcmMnKTtcbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50Om1vdXNlZG93bicsIFsnJGV2ZW50J10pIG9uRG9jdW1lbnRDbGljayhlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmVsLm5hdGl2ZUVsZW1lbnQuY29udGFpbnMoZS50YXJnZXQpICYmIHRoaXMuc2hvd1BvcHVwKSB7XG4gICAgICB0aGlzLmhpZGVGb3JtKCk7XG4gICAgfVxuICB9XG5cbiAgZ2V0TGFiZWwoa2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm5neGVTZXJ2aWNlLmxvY2Fscy5nZXQoa2V5KTtcbiAgfVxuXG4gIHByaXZhdGUgaGlkZUZvcm0oKTogdm9pZCB7XG4gICAgdGhpcy5zaG93UG9wdXAgPSBmYWxzZTtcbiAgICB0aGlzLmZvcm0ucmVzZXQoe1xuICAgICAgc3JjOiAnJyxcbiAgICAgIGFsdDogJycsXG4gICAgICB0aXRsZTogJycsXG4gICAgfSk7XG4gIH1cblxuICBvbk1vdXNlRG93bihlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgaWYgKGUuYnV0dG9uICE9PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zaG93UG9wdXAgPSAhdGhpcy5zaG93UG9wdXA7XG5cbiAgICBpZiAodGhpcy5zaG93UG9wdXApIHtcbiAgICAgIHRoaXMuZmlsbEZvcm0oKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGZpbGxGb3JtKCk6IHZvaWQge1xuICAgIGNvbnN0IHsgc3RhdGUgfSA9IHRoaXMuZWRpdG9yVmlldztcbiAgICBjb25zdCB7IHNlbGVjdGlvbiB9ID0gc3RhdGU7XG4gICAgaWYgKHNlbGVjdGlvbiBpbnN0YW5jZW9mIE5vZGVTZWxlY3Rpb24gJiYgdGhpcy5pc0FjdGl2ZSkge1xuICAgICAgY29uc3QgeyBzcmMsIGFsdCA9ICcnLCB0aXRsZSA9ICcnIH0gPSBzZWxlY3Rpb24ubm9kZS5hdHRycztcblxuICAgICAgdGhpcy5mb3JtLnNldFZhbHVlKHtcbiAgICAgICAgc3JjLFxuICAgICAgICBhbHQsXG4gICAgICAgIHRpdGxlLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGUgPSAodmlldzogRWRpdG9yVmlldykgPT4ge1xuICAgIGNvbnN0IHsgc3RhdGUgfSA9IHZpZXc7XG4gICAgdGhpcy5pc0FjdGl2ZSA9IEltYWdlQ29tbWFuZC5pc0FjdGl2ZShzdGF0ZSk7XG4gIH07XG5cbiAgaW5zZXJ0TGluayhlOiBNb3VzZUV2ZW50KTogdm9pZCB7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IHsgc3JjLCBhbHQsIHRpdGxlIH0gPSB0aGlzLmZvcm0uZ2V0UmF3VmFsdWUoKTtcbiAgICBjb25zdCB7IGRpc3BhdGNoLCBzdGF0ZSB9ID0gdGhpcy5lZGl0b3JWaWV3O1xuXG4gICAgY29uc3QgYXR0cnMgPSB7XG4gICAgICBhbHQsXG4gICAgICB0aXRsZSxcbiAgICB9O1xuXG4gICAgSW1hZ2VDb21tYW5kLmluc2VydChzcmMsIGF0dHJzKShzdGF0ZSwgZGlzcGF0Y2gpO1xuICAgIHRoaXMuZWRpdG9yVmlldy5mb2N1cygpO1xuICAgIHRoaXMuaGlkZUZvcm0oKTtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZWRpdG9yVmlldyA9IHRoaXMubWVudVNlcnZpY2UuZWRpdG9yLnZpZXc7XG5cbiAgICB0aGlzLnVwZGF0ZVN1YnNjcmlwdGlvbiA9IHRoaXMubWVudVNlcnZpY2UuZWRpdG9yLnVwZGF0ZS5zdWJzY3JpYmUoKHZpZXc6IEVkaXRvclZpZXcpID0+IHtcbiAgICAgIHRoaXMudXBkYXRlKHZpZXcpO1xuICAgIH0pO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy51cGRhdGVTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cIk5neEVkaXRvcl9fTWVudUl0ZW0tLUljb25Db250YWluZXJcIiBbY2xhc3MuTmd4RWRpdG9yX19NZW51SXRlbS0tQWN0aXZlXT1cImlzQWN0aXZlIHx8IHNob3dQb3B1cFwiXG4gIFtpbm5lckhUTUxdPVwiaWNvbiB8IHNhbml0aXplSHRtbFwiIChtb3VzZWRvd24pPVwib25Nb3VzZURvd24oJGV2ZW50KVwiIFt0aXRsZV09XCJnZXRMYWJlbCgnaW5zZXJ0SW1hZ2UnKVwiPlxuPC9kaXY+XG5cbjwhLS0gcG9wdXAgLS0+XG48ZGl2ICpuZ0lmPVwic2hvd1BvcHVwXCIgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwXCI+XG4gIDxmb3JtIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tRm9ybVwiIFtmb3JtR3JvdXBdPVwiZm9ybVwiIChuZ1N1Ym1pdCk9XCJpbnNlcnRMaW5rKCRldmVudClcIj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCd1cmwnKX19PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IHR5cGU9XCJocmVmXCIgaWQ9XCJocmVmXCIgZm9ybUNvbnRyb2xOYW1lPVwic3JjXCIgYXV0b2ZvY3VzIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICAgIDxkaXYgKm5nSWY9XCJzcmMudG91Y2hlZCAmJiBzcmMuaW52YWxpZFwiIGNsYXNzPVwiTmd4RWRpdG9yX19IZWxwVGV4dCBOZ3hFZGl0b3JfX0hlbHBUZXh0LS1FcnJvclwiPlxuICAgICAgICAgIHt7IHNyYy5lcnJvcnM/LlsncGF0dGVybiddICYmICdQbGVhc2UgZW50ZXIgdmFsaWQgdXJsLicgfX1cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCdhbHRUZXh0Jyl9fTwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIGZvcm1Db250cm9sTmFtZT1cImFsdFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCd0aXRsZScpfX08L2xhYmVsPlxuICAgICAgICA8aW5wdXQgdHlwZT1cInRleHRcIiBmb3JtQ29udHJvbE5hbWU9XCJ0aXRsZVwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiIFtkaXNhYmxlZF09XCIhZm9ybS52YWxpZCB8fCAhZm9ybS5kaXJ0eVwiPnt7Z2V0TGFiZWwoJ2luc2VydCcpfX08L2J1dHRvbj5cblxuICA8L2Zvcm0+XG48L2Rpdj5cbiJdfQ==