UNPKG

ngx-editor

Version:

Rich Text Editor for angular using ProseMirror

112 lines 19.1 kB
import { Component, HostBinding, 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 valid() { return this.isActive || this.showPopup; } 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.5", 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.5", type: ImageComponent, selector: "ngx-image", host: { listeners: { "document:mousedown": "onDocumentClick($event)" }, properties: { "class.NgxEditor__MenuItem--Active": "this.valid" } }, ngImport: i0, template: "<div class=\"NgxEditor__MenuItem--IconContainer\" [innerHTML]=\"icon | sanitizeHtml\" (mousedown)=\"onMouseDown($event)\"\n [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.5", ngImport: i0, type: ImageComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-image', template: "<div class=\"NgxEditor__MenuItem--IconContainer\" [innerHTML]=\"icon | sanitizeHtml\" (mousedown)=\"onMouseDown($event)\"\n [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: { valid: [{ type: HostBinding, args: ['class.NgxEditor__MenuItem--Active'] }], onDocumentClick: [{ type: HostListener, args: ['document:mousedown', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWVkaXRvci9zcmMvbGliL21vZHVsZXMvbWVudS9pbWFnZS9pbWFnZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZWRpdG9yL3NyYy9saWIvbW9kdWxlcy9tZW51L2ltYWdlL2ltYWdlLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQWMsV0FBVyxFQUNsQyxZQUFZLEdBQ2IsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFtQixXQUFXLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3JGLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQU1sRCxPQUFPLElBQUksTUFBTSxnQkFBZ0IsQ0FBQztBQUNsQyxPQUFPLEVBQUUsS0FBSyxJQUFJLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDOzs7Ozs7O0FBT3hELE1BQU0sT0FBTyxjQUFjO0lBZ0J6QixZQUNVLEVBQWMsRUFDZCxXQUE2QixFQUM3QixXQUF3QjtRQUZ4QixPQUFFLEdBQUYsRUFBRSxDQUFZO1FBQ2QsZ0JBQVcsR0FBWCxXQUFXLENBQWtCO1FBQzdCLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBbEJsQyxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ2xCLGFBQVEsR0FBRyxLQUFLLENBQUM7UUFHakIsU0FBSSxHQUFHLElBQUksU0FBUyxDQUFDO1lBQ25CLEdBQUcsRUFBRSxJQUFJLFdBQVcsQ0FBQyxFQUFFLEVBQUU7Z0JBQ3ZCLFVBQVUsQ0FBQyxRQUFRO2dCQUNuQixVQUFVLENBQUMsT0FBTyxDQUFDLGdGQUFnRixDQUFDO2FBQ3JHLENBQUM7WUFDRixHQUFHLEVBQUUsSUFBSSxXQUFXLENBQUMs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QUMsS0FBSyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ2xCLENBQUM7SUFFRCxRQUFRO1FBQ04sSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7UUFFL0MsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFnQixFQUFFLEVBQUU7WUFDdEYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNwQixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ3hDLENBQUM7OzJHQTdHVSxjQUFjOytGQUFkLGNBQWMsOExDbkIzQix3L0NBb0NBOzJGRGpCYSxjQUFjO2tCQUwxQixTQUFTOytCQUNFLFdBQVc7MEpBMEJpQyxLQUFLO3NCQUExRCxXQUFXO3VCQUFDLG1DQUFtQztnQkFZQSxlQUFlO3NCQUE5RCxZQUFZO3VCQUFDLG9CQUFvQixFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LCBFbGVtZW50UmVmLCBIb3N0QmluZGluZyxcbiAgSG9zdExpc3RlbmVyLCBPbkRlc3Ryb3ksIE9uSW5pdCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1Db250cm9sLCBGb3JtR3JvdXAsIFZhbGlkYXRvcnMgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBOb2RlU2VsZWN0aW9uIH0gZnJvbSAncHJvc2VtaXJyb3Itc3RhdGUnO1xuaW1wb3J0IHsgRWRpdG9yVmlldyB9IGZyb20gJ3Byb3NlbWlycm9yLXZpZXcnO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5cbmltcG9ydCB7IE5neEVkaXRvclNlcnZpY2UgfSBmcm9tICcuLi8uLi8uLi9lZGl0b3Iuc2VydmljZSc7XG5pbXBvcnQgeyBNZW51U2VydmljZSB9IGZyb20gJy4uL21lbnUuc2VydmljZSc7XG5pbXBvcnQgSWNvbiBmcm9tICcuLi8uLi8uLi9pY29ucyc7XG5pbXBvcnQgeyBJbWFnZSBhcyBJbWFnZUNvbW1hbmQgfSBmcm9tICcuLi9NZW51Q29tbWFuZHMnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtaW1hZ2UnLFxuICB0ZW1wbGF0ZVVybDogJy4vaW1hZ2UuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9pbWFnZS5jb21wb25lbnQuc2NzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBJbWFnZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgc2hvd1BvcHVwID0gZmFsc2U7XG4gIGlzQWN0aXZlID0gZmFsc2U7XG4gIHByaXZhdGUgdXBkYXRlU3Vic2NyaXB0aW9uOiBTdWJzY3JpcHRpb247XG5cbiAgZm9ybSA9IG5ldyBGb3JtR3JvdXAoe1xuICAgIHNyYzogbmV3IEZvcm1Db250cm9sKCcnLCBbXG4gICAgICBWYWxpZGF0b3JzLnJlcXVpcmVkLFxuICAgICAgVmFsaWRhdG9ycy5wYXR0ZXJuKCcoaHR0cHM/Oi8vKT8oW1xcXFxkYS16Li1dKylcXFxcLihbYS16Ll17Miw2fSlbL1xcXFx3IC4tXSovPz8oW14jXFxuXFxyXSopPyM/KFteXFxuXFxyXSopJyksXG4gICAgXSksXG4gICAgYWx0OiBuZXcgRm9ybUNvbnRyb2woJycpLFxuICAgIHRpdGxlOiBuZXcgRm9ybUNvbnRyb2woJycpLFxuICB9KTtcblxuICBwcml2YXRlIGVkaXRvclZpZXc6IEVkaXRvclZpZXc7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBlbDogRWxlbWVudFJlZixcbiAgICBwcml2YXRlIG5neGVTZXJ2aWNlOiBOZ3hFZGl0b3JTZXJ2aWNlLFxuICAgIHByaXZhdGUgbWVudVNlcnZpY2U6IE1lbnVTZXJ2aWNlLFxuICApIHsgfVxuXG4gIEBIb3N0QmluZGluZygnY2xhc3MuTmd4RWRpdG9yX19NZW51SXRlbS0tQWN0aXZlJykgZ2V0IHZhbGlkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzQWN0aXZlIHx8IHRoaXMuc2hvd1BvcHVwO1xuICB9XG5cbiAgZ2V0IGljb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gSWNvbi5nZXQoJ2ltYWdlJyk7XG4gIH1cblxuICBnZXQgc3JjKCk6IEFic3RyYWN0Q29udHJvbCB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybS5nZXQoJ3NyYycpO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6bW91c2Vkb3duJywgWyckZXZlbnQnXSkgb25Eb2N1bWVudENsaWNrKGU6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZWwubmF0aXZlRWxlbWVudC5jb250YWlucyhlLnRhcmdldCkgJiYgdGhpcy5zaG93UG9wdXApIHtcbiAgICAgIHRoaXMuaGlkZUZvcm0oKTtcbiAgICB9XG4gIH1cblxuICBnZXRMYWJlbChrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubmd4ZVNlcnZpY2UubG9jYWxzLmdldChrZXkpO1xuICB9XG5cbiAgcHJpdmF0ZSBoaWRlRm9ybSgpOiB2b2lkIHtcbiAgICB0aGlzLnNob3dQb3B1cCA9IGZhbHNlO1xuICAgIHRoaXMuZm9ybS5yZXNldCh7XG4gICAgICBzcmM6ICcnLFxuICAgICAgYWx0OiAnJyxcbiAgICAgIHRpdGxlOiAnJyxcbiAgICB9KTtcbiAgfVxuXG4gIG9uTW91c2VEb3duKGU6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBpZiAoZS5idXR0b24gIT09IDApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnNob3dQb3B1cCA9ICF0aGlzLnNob3dQb3B1cDtcblxuICAgIGlmICh0aGlzLnNob3dQb3B1cCkge1xuICAgICAgdGhpcy5maWxsRm9ybSgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmlsbEZvcm0oKTogdm9pZCB7XG4gICAgY29uc3QgeyBzdGF0ZSB9ID0gdGhpcy5lZGl0b3JWaWV3O1xuICAgIGNvbnN0IHsgc2VsZWN0aW9uIH0gPSBzdGF0ZTtcbiAgICBpZiAoc2VsZWN0aW9uIGluc3RhbmNlb2YgTm9kZVNlbGVjdGlvbiAmJiB0aGlzLmlzQWN0aXZlKSB7XG4gICAgICBjb25zdCB7IHNyYywgYWx0ID0gJycsIHRpdGxlID0gJycgfSA9IHNlbGVjdGlvbi5ub2RlLmF0dHJzO1xuXG4gICAgICB0aGlzLmZvcm0uc2V0VmFsdWUoe1xuICAgICAgICBzcmMsXG4gICAgICAgIGFsdCxcbiAgICAgICAgdGl0bGUsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZSA9ICh2aWV3OiBFZGl0b3JWaWV3KSA9PiB7XG4gICAgY29uc3QgeyBzdGF0ZSB9ID0gdmlldztcbiAgICB0aGlzLmlzQWN0aXZlID0gSW1hZ2VDb21tYW5kLmlzQWN0aXZlKHN0YXRlKTtcbiAgfTtcblxuICBpbnNlcnRMaW5rKGU6IE1vdXNlRXZlbnQpOiB2b2lkIHtcbiAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgY29uc3QgeyBzcmMsIGFsdCwgdGl0bGUgfSA9IHRoaXMuZm9ybS5nZXRSYXdWYWx1ZSgpO1xuICAgIGNvbnN0IHsgZGlzcGF0Y2gsIHN0YXRlIH0gPSB0aGlzLmVkaXRvclZpZXc7XG5cbiAgICBjb25zdCBhdHRycyA9IHtcbiAgICAgIGFsdCxcbiAgICAgIHRpdGxlLFxuICAgIH07XG5cbiAgICBJbWFnZUNvbW1hbmQuaW5zZXJ0KHNyYywgYXR0cnMpKHN0YXRlLCBkaXNwYXRjaCk7XG4gICAgdGhpcy5lZGl0b3JWaWV3LmZvY3VzKCk7XG4gICAgdGhpcy5oaWRlRm9ybSgpO1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5lZGl0b3JWaWV3ID0gdGhpcy5tZW51U2VydmljZS5lZGl0b3IudmlldztcblxuICAgIHRoaXMudXBkYXRlU3Vic2NyaXB0aW9uID0gdGhpcy5tZW51U2VydmljZS5lZGl0b3IudXBkYXRlLnN1YnNjcmliZSgodmlldzogRWRpdG9yVmlldykgPT4ge1xuICAgICAgdGhpcy51cGRhdGUodmlldyk7XG4gICAgfSk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnVwZGF0ZVN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiTmd4RWRpdG9yX19NZW51SXRlbS0tSWNvbkNvbnRhaW5lclwiIFtpbm5lckhUTUxdPVwiaWNvbiB8IHNhbml0aXplSHRtbFwiIChtb3VzZWRvd24pPVwib25Nb3VzZURvd24oJGV2ZW50KVwiXG4gIFt0aXRsZV09XCJnZXRMYWJlbCgnaW5zZXJ0SW1hZ2UnKVwiPlxuPC9kaXY+XG5cbjwhLS0gcG9wdXAgLS0+XG48ZGl2ICpuZ0lmPVwic2hvd1BvcHVwXCIgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwXCI+XG4gIDxmb3JtIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tRm9ybVwiIFtmb3JtR3JvdXBdPVwiZm9ybVwiIChuZ1N1Ym1pdCk9XCJpbnNlcnRMaW5rKCRldmVudClcIj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCd1cmwnKX19PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IHR5cGU9XCJocmVmXCIgaWQ9XCJocmVmXCIgZm9ybUNvbnRyb2xOYW1lPVwic3JjXCIgYXV0b2ZvY3VzIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICAgIDxkaXYgKm5nSWY9XCJzcmMudG91Y2hlZCAmJiBzcmMuaW52YWxpZFwiIGNsYXNzPVwiTmd4RWRpdG9yX19IZWxwVGV4dCBOZ3hFZGl0b3JfX0hlbHBUZXh0LS1FcnJvclwiPlxuICAgICAgICAgIHt7IHNyYy5lcnJvcnM/LlsncGF0dGVybiddICYmICdQbGVhc2UgZW50ZXIgdmFsaWQgdXJsLicgfX1cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCdhbHRUZXh0Jyl9fTwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIGZvcm1Db250cm9sTmFtZT1cImFsdFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Gb3JtR3JvdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJOZ3hFZGl0b3JfX1BvcHVwLS1Db2xcIj5cbiAgICAgICAgPGxhYmVsIGNsYXNzPVwiTmd4RWRpdG9yX19Qb3B1cC0tTGFiZWxcIj57e2dldExhYmVsKCd0aXRsZScpfX08L2xhYmVsPlxuICAgICAgICA8aW5wdXQgdHlwZT1cInRleHRcIiBmb3JtQ29udHJvbE5hbWU9XCJ0aXRsZVwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIC8+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiIFtkaXNhYmxlZF09XCIhZm9ybS52YWxpZCB8fCAhZm9ybS5kaXJ0eVwiPnt7Z2V0TGFiZWwoJ2luc2VydCcpfX08L2J1dHRvbj5cblxuICA8L2Zvcm0+XG48L2Rpdj5cbiJdfQ==