@myrmidon/gve-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +83 -0
  2. package/esm2022/lib/components/animation-timeline/animation-timeline.component.mjs +176 -0
  3. package/esm2022/lib/components/animation-tween/animation-tween.component.mjs +161 -0
  4. package/esm2022/lib/components/animation-vars/animation-vars.component.mjs +141 -0
  5. package/esm2022/lib/components/base-text-char/base-text-char.component.mjs +37 -0
  6. package/esm2022/lib/components/base-text-editor/base-text-editor.component.mjs +111 -0
  7. package/esm2022/lib/components/base-text-view/base-text-view.component.mjs +125 -0
  8. package/esm2022/lib/components/chain-operation-editor/chain-operation-editor.component.mjs +512 -0
  9. package/esm2022/lib/components/chain-result-view/chain-result-view.component.mjs +190 -0
  10. package/esm2022/lib/components/feature-editor/feature-editor.component.mjs +185 -0
  11. package/esm2022/lib/components/feature-set-editor/feature-set-editor.component.mjs +152 -0
  12. package/esm2022/lib/components/feature-set-view/feature-set-view.component.mjs +80 -0
  13. package/esm2022/lib/components/ln-heights-editor/ln-heights-editor.component.mjs +95 -0
  14. package/esm2022/lib/components/operation-source-editor/operation-source-editor.component.mjs +106 -0
  15. package/esm2022/lib/components/simple-tree/simple-tree.component.mjs +56 -0
  16. package/esm2022/lib/components/snapshot-editor/snapshot-editor.component.mjs +510 -0
  17. package/esm2022/lib/components/steps-map/steps-map.component.mjs +55 -0
  18. package/esm2022/lib/models.mjs +2 -0
  19. package/esm2022/lib/services/gve-api.service.mjs +52 -0
  20. package/esm2022/lib/services/settings.service.mjs +86 -0
  21. package/esm2022/lib/validators/svg-validators.mjs +28 -0
  22. package/esm2022/myrmidon-gve-core.mjs +5 -0
  23. package/esm2022/public-api.mjs +23 -0
  24. package/fesm2022/myrmidon-gve-core.mjs +2592 -0
  25. package/fesm2022/myrmidon-gve-core.mjs.map +1 -0
  26. package/index.d.ts +5 -0
  27. package/lib/components/animation-timeline/animation-timeline.component.d.ts +42 -0
  28. package/lib/components/animation-tween/animation-tween.component.d.ts +47 -0
  29. package/lib/components/animation-vars/animation-vars.component.d.ts +30 -0
  30. package/lib/components/base-text-char/base-text-char.component.d.ts +29 -0
  31. package/lib/components/base-text-editor/base-text-editor.component.d.ts +40 -0
  32. package/lib/components/base-text-view/base-text-view.component.d.ts +29 -0
  33. package/lib/components/chain-operation-editor/chain-operation-editor.component.d.ts +102 -0
  34. package/lib/components/chain-result-view/chain-result-view.component.d.ts +44 -0
  35. package/lib/components/feature-editor/feature-editor.component.d.ts +72 -0
  36. package/lib/components/feature-set-editor/feature-set-editor.component.d.ts +55 -0
  37. package/lib/components/feature-set-view/feature-set-view.component.d.ts +36 -0
  38. package/lib/components/ln-heights-editor/ln-heights-editor.component.d.ts +22 -0
  39. package/lib/components/operation-source-editor/operation-source-editor.component.d.ts +24 -0
  40. package/lib/components/simple-tree/simple-tree.component.d.ts +16 -0
  41. package/lib/components/snapshot-editor/snapshot-editor.component.d.ts +105 -0
  42. package/lib/components/steps-map/steps-map.component.d.ts +29 -0
  43. package/lib/models.d.ts +7 -0
  44. package/lib/services/gve-api.service.d.ts +57 -0
  45. package/lib/services/settings.service.d.ts +53 -0
  46. package/lib/validators/svg-validators.d.ts +4 -0
  47. package/package.json +45 -0
  48. package/public-api.d.ts +19 -0
@@ -0,0 +1,141 @@
1
+ import { Component, EventEmitter, Input, Output, ViewChild, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { ReactiveFormsModule, Validators, } from '@angular/forms';
4
+ import { MatButtonModule } from '@angular/material/button';
5
+ import { MatCheckboxModule } from '@angular/material/checkbox';
6
+ import { MatFormFieldModule } from '@angular/material/form-field';
7
+ import { MatIconModule } from '@angular/material/icon';
8
+ import { MatInputModule } from '@angular/material/input';
9
+ import { MatSelectModule } from '@angular/material/select';
10
+ import { MatTooltipModule } from '@angular/material/tooltip';
11
+ import * as i0 from "@angular/core";
12
+ import * as i1 from "@angular/forms";
13
+ import * as i2 from "@angular/common";
14
+ import * as i3 from "@angular/material/button";
15
+ import * as i4 from "@angular/material/form-field";
16
+ import * as i5 from "@angular/material/icon";
17
+ import * as i6 from "@angular/material/input";
18
+ import * as i7 from "@angular/material/tooltip";
19
+ export class AnimationVarsComponent {
20
+ get vars() {
21
+ return this._vars;
22
+ }
23
+ set vars(value) {
24
+ if (this._vars === value) {
25
+ return;
26
+ }
27
+ this._vars = value;
28
+ this.updateForm(value);
29
+ }
30
+ constructor(formBuilder) {
31
+ this._vars = {};
32
+ this.varsChange = new EventEmitter();
33
+ this.editedVars = [];
34
+ this.name = formBuilder.control('', {
35
+ nonNullable: true,
36
+ validators: [Validators.required, Validators.maxLength(100)],
37
+ });
38
+ this.value = formBuilder.control('', {
39
+ nonNullable: true,
40
+ validators: [Validators.required, Validators.maxLength(1000)],
41
+ });
42
+ this.form = formBuilder.group({
43
+ name: this.name,
44
+ value: this.value,
45
+ });
46
+ }
47
+ updateForm(vars) {
48
+ this.editedVars = Object.entries(vars)
49
+ .map(([name, value]) => ({ name, value }))
50
+ .sort((a, b) => a.name.localeCompare(b.name));
51
+ }
52
+ getVars() {
53
+ return this.editedVars.reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {});
54
+ }
55
+ addVar() {
56
+ this.form.reset();
57
+ // focus the name input
58
+ setTimeout(() => this.nameInput?.nativeElement.focus(), 0);
59
+ }
60
+ editVar(index) {
61
+ const { name, value } = this.editedVars[index];
62
+ this.form.setValue({ name, value });
63
+ this.form.markAsPristine();
64
+ // focus the name input
65
+ setTimeout(() => this.nameInput?.nativeElement.focus(), 0);
66
+ }
67
+ deleteVar(index) {
68
+ this.editedVars = this.editedVars.filter((_, i) => i !== index);
69
+ this.varsChange.emit(this.getVars());
70
+ }
71
+ parseValue(value) {
72
+ if (!value) {
73
+ return '';
74
+ }
75
+ if (value === 'true') {
76
+ return true;
77
+ }
78
+ else if (value === 'false') {
79
+ return false;
80
+ }
81
+ else if (/^\d+$/.test(value)) {
82
+ return parseInt(value, 10);
83
+ }
84
+ else if (/^\d+\.\d+$/.test(value)) {
85
+ return parseFloat(value);
86
+ }
87
+ return value;
88
+ }
89
+ saveVar() {
90
+ if (this.form.invalid) {
91
+ return;
92
+ }
93
+ const { name, value } = this.form.value;
94
+ // parse value assuming that if it looks like a boolean/number
95
+ // its value should be a boolean/number rather than a string
96
+ const v = this.parseValue(value);
97
+ const editedVars = [...this.editedVars];
98
+ // if name already exists, update the value; else add it
99
+ const existingIndex = this.editedVars.findIndex((vr) => vr.name === name);
100
+ if (existingIndex !== -1) {
101
+ editedVars[existingIndex] = { name, value: v };
102
+ this.editedVars = editedVars;
103
+ return;
104
+ }
105
+ else {
106
+ editedVars.push({ name, value: v });
107
+ this.editedVars = editedVars.sort((a, b) => a.name.localeCompare(b.name));
108
+ }
109
+ this.varsChange.emit(this.getVars());
110
+ setTimeout(() => {
111
+ this.nameInput?.nativeElement.focus();
112
+ this.form.reset();
113
+ this.form.markAsPristine();
114
+ this.form.updateValueAndValidity();
115
+ }, 0);
116
+ }
117
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: AnimationVarsComponent, deps: [{ token: i1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
118
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.4", type: AnimationVarsComponent, isStandalone: true, selector: "gve-animation-vars", inputs: { vars: "vars" }, outputs: { varsChange: "varsChange" }, viewQueries: [{ propertyName: "nameInput", first: true, predicate: ["vname"], descendants: true, static: true }], ngImport: i0, template: "<div>\r\n <div>\r\n <button type=\"button\" mat-raised-button color=\"primary\" (click)=\"addVar()\">\r\n <mat-icon>add</mat-icon>\r\n property\r\n </button>\r\n </div>\r\n\r\n @if (editedVars.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>name</th>\r\n <th>value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (v of editedVars; track v.name; let index=$index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n (click)=\"editVar(index)\"\r\n matTooltip=\"Edit this property\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n (click)=\"deleteVar(index)\"\r\n matTooltip=\"Delete this property\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ v.name }}</td>\r\n <td>{{ v.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n } @else {\r\n <p class=\"muted\">(no vars)</p>\r\n }\r\n\r\n <form [formGroup]=\"form\" (submit)=\"saveVar()\">\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- name -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <input matInput [formControl]=\"name\" #vname />\r\n <mat-error\r\n *ngIf=\"$any(name).errors?.required && (name.dirty || name.touched)\"\r\n >name required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(name).errors?.maxLength && (name.dirty || name.touched)\"\r\n >name too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- value -->\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(value).errors?.required && (value.dirty || value.touched)\r\n \"\r\n >value required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(value).errors?.maxLength && (value.dirty || value.touched)\r\n \"\r\n >value too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n color=\"primary\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">add_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}fieldset{border:1px solid silver;border-radius:4px;padding:8px;margin:8px 0}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
119
+ }
120
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: AnimationVarsComponent, decorators: [{
121
+ type: Component,
122
+ args: [{ selector: 'gve-animation-vars', standalone: true, imports: [
123
+ CommonModule,
124
+ ReactiveFormsModule,
125
+ MatButtonModule,
126
+ MatCheckboxModule,
127
+ MatFormFieldModule,
128
+ MatIconModule,
129
+ MatInputModule,
130
+ MatSelectModule,
131
+ MatTooltipModule,
132
+ ], template: "<div>\r\n <div>\r\n <button type=\"button\" mat-raised-button color=\"primary\" (click)=\"addVar()\">\r\n <mat-icon>add</mat-icon>\r\n property\r\n </button>\r\n </div>\r\n\r\n @if (editedVars.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>name</th>\r\n <th>value</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (v of editedVars; track v.name; let index=$index) {\r\n <tr>\r\n <td class=\"fit-width\">\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"primary\"\r\n (click)=\"editVar(index)\"\r\n matTooltip=\"Edit this property\"\r\n >\r\n <mat-icon class=\"mat-primary\">edit</mat-icon>\r\n </button>\r\n <button\r\n type=\"button\"\r\n mat-icon-button\r\n color=\"warn\"\r\n (click)=\"deleteVar(index)\"\r\n matTooltip=\"Delete this property\"\r\n >\r\n <mat-icon class=\"mat-warn\">remove_circle</mat-icon>\r\n </button>\r\n </td>\r\n <td>{{ v.name }}</td>\r\n <td>{{ v.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n } @else {\r\n <p class=\"muted\">(no vars)</p>\r\n }\r\n\r\n <form [formGroup]=\"form\" (submit)=\"saveVar()\">\r\n <fieldset>\r\n <div class=\"form-row\">\r\n <!-- name -->\r\n <mat-form-field>\r\n <mat-label>name</mat-label>\r\n <input matInput [formControl]=\"name\" #vname />\r\n <mat-error\r\n *ngIf=\"$any(name).errors?.required && (name.dirty || name.touched)\"\r\n >name required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"$any(name).errors?.maxLength && (name.dirty || name.touched)\"\r\n >name too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <!-- value -->\r\n <mat-form-field>\r\n <mat-label>value</mat-label>\r\n <input matInput [formControl]=\"value\" />\r\n <mat-error\r\n *ngIf=\"\r\n $any(value).errors?.required && (value.dirty || value.touched)\r\n \"\r\n >value required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(value).errors?.maxLength && (value.dirty || value.touched)\r\n \"\r\n >value too long</mat-error\r\n >\r\n </mat-form-field>\r\n\r\n <button\r\n type=\"submit\"\r\n mat-icon-button\r\n color=\"primary\"\r\n [disabled]=\"form.invalid\"\r\n >\r\n <mat-icon class=\"mat-primary\">add_circle</mat-icon>\r\n </button>\r\n </div>\r\n </fieldset>\r\n </form>\r\n</div>\r\n", styles: [".form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}fieldset{border:1px solid silver;border-radius:4px;padding:8px;margin:8px 0}table{width:100%;border-collapse:collapse}th{color:#909090;font-weight:400;text-align:left;background-color:#e1e0e0}th,td{padding:4px;border-bottom:1px solid silver}tbody tr:nth-child(2n){background-color:#e8e8e8}td.fit-width{width:1px;white-space:nowrap}\n"] }]
133
+ }], ctorParameters: () => [{ type: i1.FormBuilder }], propDecorators: { vars: [{
134
+ type: Input
135
+ }], varsChange: [{
136
+ type: Output
137
+ }], nameInput: [{
138
+ type: ViewChild,
139
+ args: ['vname', { static: true }]
140
+ }] } });
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5pbWF0aW9uLXZhcnMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbXlybWlkb24vZ3ZlLWNvcmUvc3JjL2xpYi9jb21wb25lbnRzL2FuaW1hdGlvbi12YXJzL2FuaW1hdGlvbi12YXJzLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL215cm1pZG9uL2d2ZS1jb3JlL3NyYy9saWIvY29tcG9uZW50cy9hbmltYXRpb24tdmFycy9hbmltYXRpb24tdmFycy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUVULFlBQVksRUFDWixLQUFLLEVBQ0wsTUFBTSxFQUNOLFNBQVMsR0FDVixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUlMLG1CQUFtQixFQUNuQixVQUFVLEdBQ1gsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7Ozs7Ozs7OztBQTBCN0QsTUFBTSxPQUFPLHNCQUFzQjtJQUdqQyxJQUNXLElBQUk7UUFDYixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FB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ZSx3VUFDZixpQkFBaUIsOEJBQ2pCLGtCQUFrQix1WUFDbEIsYUFBYSxtTEFDYixjQUFjLDBXQUNkLGVBQWUsOEJBQ2YsZ0JBQWdCOzsyRkFLUCxzQkFBc0I7a0JBakJsQyxTQUFTOytCQUNFLG9CQUFvQixjQUNsQixJQUFJLFdBQ1A7d0JBQ1AsWUFBWTt3QkFDWixtQkFBbUI7d0JBQ25CLGVBQWU7d0JBQ2YsaUJBQWlCO3dCQUNqQixrQkFBa0I7d0JBQ2xCLGFBQWE7d0JBQ2IsY0FBYzt3QkFDZCxlQUFlO3dCQUNmLGdCQUFnQjtxQkFDakI7Z0ZBUVUsSUFBSTtzQkFEZCxLQUFLO2dCQWFDLFVBQVU7c0JBRGhCLE1BQU07Z0JBS0EsU0FBUztzQkFEZixTQUFTO3VCQUFDLE9BQU8sRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIENvbXBvbmVudCxcclxuICBFbGVtZW50UmVmLFxyXG4gIEV2ZW50RW1pdHRlcixcclxuICBJbnB1dCxcclxuICBPdXRwdXQsXHJcbiAgVmlld0NoaWxkLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5cclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHtcclxuICBGb3JtQnVpbGRlcixcclxuICBGb3JtQ29udHJvbCxcclxuICBGb3JtR3JvdXAsXHJcbiAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcclxuICBWYWxpZGF0b3JzLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgTWF0QnV0dG9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcclxuaW1wb3J0IHsgTWF0Q2hlY2tib3hNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jaGVja2JveCc7XHJcbmltcG9ydCB7IE1hdEZvcm1GaWVsZE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xyXG5pbXBvcnQgeyBNYXRJY29uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvbic7XHJcbmltcG9ydCB7IE1hdElucHV0TW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaW5wdXQnO1xyXG5pbXBvcnQgeyBNYXRTZWxlY3RNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zZWxlY3QnO1xyXG5pbXBvcnQgeyBNYXRUb29sdGlwTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdG9vbHRpcCc7XHJcblxyXG5pbXBvcnQgeyBHdmVBbmltYXRpb25WYXJzIH0gZnJvbSAnQG15cm1pZG9uL2d2ZS1zbmFwc2hvdC12aWV3JztcclxuXHJcbmludGVyZmFjZSBWYXJWaWV3TW9kZWwge1xyXG4gIG5hbWU6IHN0cmluZztcclxuICB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbjtcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdndmUtYW5pbWF0aW9uLXZhcnMnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1xyXG4gICAgQ29tbW9uTW9kdWxlLFxyXG4gICAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcclxuICAgIE1hdEJ1dHRvbk1vZHVsZSxcclxuICAgIE1hdENoZWNrYm94TW9kdWxlLFxyXG4gICAgTWF0Rm9ybUZpZWxkTW9kdWxlLFxyXG4gICAgTWF0SWNvbk1vZHVsZSxcclxuICAgIE1hdElucHV0TW9kdWxlLFxyXG4gICAgTWF0U2VsZWN0TW9kdWxlLFxyXG4gICAgTWF0VG9vbHRpcE1vZHVsZSxcclxuICBdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9hbmltYXRpb24tdmFycy5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmw6ICcuL2FuaW1hdGlvbi12YXJzLmNvbXBvbmVudC5jc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQW5pbWF0aW9uVmFyc0NvbXBvbmVudCB7XHJcbiAgcHJpdmF0ZSBfdmFyczogR3ZlQW5pbWF0aW9uVmFycyA9IHt9O1xyXG5cclxuICBASW5wdXQoKVxyXG4gIHB1YmxpYyBnZXQgdmFycygpOiBHdmVBbmltYXRpb25WYXJzIHtcclxuICAgIHJldHVybiB0aGlzLl92YXJzO1xyXG4gIH1cclxuICBwdWJsaWMgc2V0IHZhcnModmFsdWU6IEd2ZUFuaW1hdGlvblZhcnMpIHtcclxuICAgIGlmICh0aGlzLl92YXJzID09PSB2YWx1ZSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICB0aGlzLl92YXJzID0gdmFsdWU7XHJcbiAgICB0aGlzLnVwZGF0ZUZvcm0odmFsdWUpO1xyXG4gIH1cclxuXHJcbiAgQE91dHB1dCgpXHJcbiAgcHVibGljIHZhcnNDaGFuZ2U6IEV2ZW50RW1pdHRlcjxHdmVBbmltYXRpb25WYXJzPiA9XHJcbiAgICBuZXcgRXZlbnRFbWl0dGVyPEd2ZUFuaW1hdGlvblZhcnM+KCk7XHJcblxyXG4gIEBWaWV3Q2hpbGQoJ3ZuYW1lJywgeyBzdGF0aWM6IHRydWUgfSlcclxuICBwdWJsaWMgbmFtZUlucHV0PzogRWxlbWVudFJlZjtcclxuXHJcbiAgcHVibGljIG5hbWU6IEZvcm1Db250cm9sPHN0cmluZz47XHJcbiAgcHVibGljIHZhbHVlOiBGb3JtQ29udHJvbDxzdHJpbmc+O1xyXG4gIHB1YmxpYyBmb3JtOiBGb3JtR3JvdXA7XHJcblxyXG4gIHB1YmxpYyBlZGl0ZWRWYXJzOiBWYXJWaWV3TW9kZWxbXSA9IFtdO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihmb3JtQnVpbGRlcjogRm9ybUJ1aWxkZXIpIHtcclxuICAgIHRoaXMubmFtZSA9IGZvcm1CdWlsZGVyLmNvbnRyb2w8c3RyaW5nPignJywge1xyXG4gICAgICBub25OdWxsYWJsZTogdHJ1ZSxcclxuICAgICAgdmFsaWRhdG9yczogW1ZhbGlkYXRvcnMucmVxdWlyZWQsIFZhbGlkYXRvcnMubWF4TGVuZ3RoKDEwMCldLFxyXG4gICAgfSk7XHJcbiAgICB0aGlzLnZhbHVlID0gZm9ybUJ1aWxkZXIuY29udHJvbDxzdHJpbmc+KCcnLCB7XHJcbiAgICAgIG5vbk51bGxhYmxlOiB0cnVlLFxyXG4gICAgICB2YWxpZGF0b3JzOiBbVmFsaWRhdG9ycy5yZXF1aXJlZCwgVmFsaWRhdG9ycy5tYXhMZW5ndGgoMTAwMCldLFxyXG4gICAgfSk7XHJcbiAgICB0aGlzLmZvcm0gPSBmb3JtQnVpbGRlci5ncm91cCh7XHJcbiAgICAgIG5hbWU6IHRoaXMubmFtZSxcclxuICAgICAgdmFsdWU6IHRoaXMudmFsdWUsXHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlRm9ybSh2YXJzOiBHdmVBbmltYXRpb25WYXJzKTogdm9pZCB7XHJcbiAgICB0aGlzLmVkaXRlZFZhcnMgPSBPYmplY3QuZW50cmllcyh2YXJzKVxyXG4gICAgICAubWFwKChbbmFtZSwgdmFsdWVdKSA9PiAoeyBuYW1lLCB2YWx1ZSB9KSlcclxuICAgICAgLnNvcnQoKGEsIGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBnZXRWYXJzKCk6IEd2ZUFuaW1hdGlvblZhcnMge1xyXG4gICAgcmV0dXJuIHRoaXMuZWRpdGVkVmFycy5yZWR1Y2UoXHJcbiAgICAgIChhY2MsIHsgbmFtZSwgdmFsdWUgfSkgPT4gKHsgLi4uYWNjLCBbbmFtZV06IHZhbHVlIH0pLFxyXG4gICAgICB7fVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBhZGRWYXIoKTogdm9pZCB7XHJcbiAgICB0aGlzLmZvcm0ucmVzZXQoKTtcclxuICAgIC8vIGZvY3VzIHRoZSBuYW1lIGlucHV0XHJcbiAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMubmFtZUlucHV0Py5uYXRpdmVFbGVtZW50LmZvY3VzKCksIDApO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGVkaXRWYXIoaW5kZXg6IG51bWJlcik6IHZvaWQge1xyXG4gICAgY29uc3QgeyBuYW1lLCB2YWx1ZSB9ID0gdGhpcy5lZGl0ZWRWYXJzW2luZGV4XTtcclxuICAgIHRoaXMuZm9ybS5zZXRWYWx1ZSh7IG5hbWUsIHZhbHVlIH0pO1xyXG4gICAgdGhpcy5mb3JtLm1hcmtBc1ByaXN0aW5lKCk7XHJcbiAgICAvLyBmb2N1cyB0aGUgbmFtZSBpbnB1dFxyXG4gICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLm5hbWVJbnB1dD8ubmF0aXZlRWxlbWVudC5mb2N1cygpLCAwKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBkZWxldGVWYXIoaW5kZXg6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy5lZGl0ZWRWYXJzID0gdGhpcy5lZGl0ZWRWYXJzLmZpbHRlcigoXywgaSkgPT4gaSAhPT0gaW5kZXgpO1xyXG4gICAgdGhpcy52YXJzQ2hhbmdlLmVtaXQodGhpcy5nZXRWYXJzKCkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwYXJzZVZhbHVlKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcgfCBudW1iZXIgfCBib29sZWFuIHtcclxuICAgIGlmICghdmFsdWUpIHtcclxuICAgICAgcmV0dXJuICcnO1xyXG4gICAgfVxyXG4gICAgaWYgKHZhbHVlID09PSAndHJ1ZScpIHtcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKHZhbHVlID09PSAnZmFsc2UnKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH0gZWxzZSBpZiAoL15cXGQrJC8udGVzdCh2YWx1ZSkpIHtcclxuICAgICAgcmV0dXJuIHBhcnNlSW50KHZhbHVlLCAxMCk7XHJcbiAgICB9IGVsc2UgaWYgKC9eXFxkK1xcLlxcZCskLy50ZXN0KHZhbHVlKSkge1xyXG4gICAgICByZXR1cm4gcGFyc2VGbG9hdCh2YWx1ZSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgc2F2ZVZhcigpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmZvcm0uaW52YWxpZCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgICBjb25zdCB7IG5hbWUsIHZhbHVlIH0gPSB0aGlzLmZvcm0udmFsdWU7XHJcblxyXG4gICAgLy8gcGFyc2UgdmFsdWUgYXNzdW1pbmcgdGhhdCBpZiBpdCBsb29rcyBsaWtlIGEgYm9vbGVhbi9udW1iZXJcclxuICAgIC8vIGl0cyB2YWx1ZSBzaG91bGQgYmUgYSBib29sZWFuL251bWJlciByYXRoZXIgdGhhbiBhIHN0cmluZ1xyXG4gICAgY29uc3QgdiA9IHRoaXMucGFyc2VWYWx1ZSh2YWx1ZSk7XHJcblxyXG4gICAgY29uc3QgZWRpdGVkVmFycyA9IFsuLi50aGlzLmVkaXRlZFZhcnNdO1xyXG5cclxuICAgIC8vIGlmIG5hbWUgYWxyZWFkeSBleGlzdHMsIHVwZGF0ZSB0aGUgdmFsdWU7IGVsc2UgYWRkIGl0XHJcbiAgICBjb25zdCBleGlzdGluZ0luZGV4ID0gdGhpcy5lZGl0ZWRWYXJzLmZpbmRJbmRleCgodnIpID0+IHZyLm5hbWUgPT09IG5hbWUpO1xyXG4gICAgaWYgKGV4aXN0aW5nSW5kZXggIT09IC0xKSB7XHJcbiAgICAgIGVkaXRlZFZhcnNbZXhpc3RpbmdJbmRleF0gPSB7IG5hbWUsIHZhbHVlOiB2IH07XHJcbiAgICAgIHRoaXMuZWRpdGVkVmFycyA9IGVkaXRlZFZhcnM7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGVkaXRlZFZhcnMucHVzaCh7IG5hbWUsIHZhbHVlOiB2IH0pO1xyXG4gICAgICB0aGlzLmVkaXRlZFZhcnMgPSBlZGl0ZWRWYXJzLnNvcnQoKGEsIGIpID0+IGEubmFtZS5sb2NhbGVDb21wYXJlKGIubmFtZSkpO1xyXG4gICAgfVxyXG4gICAgdGhpcy52YXJzQ2hhbmdlLmVtaXQodGhpcy5nZXRWYXJzKCkpO1xyXG5cclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLm5hbWVJbnB1dD8ubmF0aXZlRWxlbWVudC5mb2N1cygpO1xyXG4gICAgICB0aGlzLmZvcm0ucmVzZXQoKTtcclxuICAgICAgdGhpcy5mb3JtLm1hcmtBc1ByaXN0aW5lKCk7XHJcbiAgICAgIHRoaXMuZm9ybS51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7XHJcbiAgICB9LCAwKTtcclxuICB9XHJcbn1cclxuIiwiPGRpdj5cclxuICA8ZGl2PlxyXG4gICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgbWF0LXJhaXNlZC1idXR0b24gY29sb3I9XCJwcmltYXJ5XCIgKGNsaWNrKT1cImFkZFZhcigpXCI+XHJcbiAgICAgIDxtYXQtaWNvbj5hZGQ8L21hdC1pY29uPlxyXG4gICAgICBwcm9wZXJ0eVxyXG4gICAgPC9idXR0b24+XHJcbiAgPC9kaXY+XHJcblxyXG4gIEBpZiAoZWRpdGVkVmFycy5sZW5ndGgpIHtcclxuICA8dGFibGU+XHJcbiAgICA8dGhlYWQ+XHJcbiAgICAgIDx0cj5cclxuICAgICAgICA8dGg+PC90aD5cclxuICAgICAgICA8dGg+bmFtZTwvdGg+XHJcbiAgICAgICAgPHRoPnZhbHVlPC90aD5cclxuICAgICAgPC90cj5cclxuICAgIDwvdGhlYWQ+XHJcbiAgICA8dGJvZHk+XHJcbiAgICAgIEBmb3IgKHYgb2YgZWRpdGVkVmFyczsgdHJhY2sgdi5uYW1lOyBsZXQgaW5kZXg9JGluZGV4KSB7XHJcbiAgICAgIDx0cj5cclxuICAgICAgICA8dGQgY2xhc3M9XCJmaXQtd2lkdGhcIj5cclxuICAgICAgICAgIDxidXR0b25cclxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxyXG4gICAgICAgICAgICBjb2xvcj1cInByaW1hcnlcIlxyXG4gICAgICAgICAgICAoY2xpY2spPVwiZWRpdFZhcihpbmRleClcIlxyXG4gICAgICAgICAgICBtYXRUb29sdGlwPVwiRWRpdCB0aGlzIHByb3BlcnR5XCJcclxuICAgICAgICAgID5cclxuICAgICAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwibWF0LXByaW1hcnlcIj5lZGl0PC9tYXQtaWNvbj5cclxuICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICAgICAgbWF0LWljb24tYnV0dG9uXHJcbiAgICAgICAgICAgIGNvbG9yPVwid2FyblwiXHJcbiAgICAgICAgICAgIChjbGljayk9XCJkZWxldGVWYXIoaW5kZXgpXCJcclxuICAgICAgICAgICAgbWF0VG9vbHRpcD1cIkRlbGV0ZSB0aGlzIHByb3BlcnR5XCJcclxuICAgICAgICAgID5cclxuICAgICAgICAgICAgPG1hdC1pY29uIGNsYXNzPVwibWF0LXdhcm5cIj5yZW1vdmVfY2lyY2xlPC9tYXQtaWNvbj5cclxuICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgIDwvdGQ+XHJcbiAgICAgICAgPHRkPnt7IHYubmFtZSB9fTwvdGQ+XHJcbiAgICAgICAgPHRkPnt7IHYudmFsdWUgfX08L3RkPlxyXG4gICAgICA8L3RyPlxyXG4gICAgICB9XHJcbiAgICA8L3Rib2R5PlxyXG4gIDwvdGFibGU+XHJcbiAgfSBAZWxzZSB7XHJcbiAgPHAgY2xhc3M9XCJtdXRlZFwiPihubyB2YXJzKTwvcD5cclxuICB9XHJcblxyXG4gIDxmb3JtIFtmb3JtR3JvdXBdPVwiZm9ybVwiIChzdWJtaXQpPVwic2F2ZVZhcigpXCI+XHJcbiAgICA8ZmllbGRzZXQ+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxyXG4gICAgICAgIDwhLS0gbmFtZSAtLT5cclxuICAgICAgICA8bWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgICA8bWF0LWxhYmVsPm5hbWU8L21hdC1sYWJlbD5cclxuICAgICAgICAgIDxpbnB1dCBtYXRJbnB1dCBbZm9ybUNvbnRyb2xdPVwibmFtZVwiICN2bmFtZSAvPlxyXG4gICAgICAgICAgPG1hdC1lcnJvclxyXG4gICAgICAgICAgICAqbmdJZj1cIiRhbnkobmFtZSkuZXJyb3JzPy5yZXF1aXJlZCAmJiAobmFtZS5kaXJ0eSB8fCBuYW1lLnRvdWNoZWQpXCJcclxuICAgICAgICAgICAgPm5hbWUgcmVxdWlyZWQ8L21hdC1lcnJvclxyXG4gICAgICAgICAgPlxyXG4gICAgICAgICAgPG1hdC1lcnJvclxyXG4gICAgICAgICAgICAqbmdJZj1cIiRhbnkobmFtZSkuZXJyb3JzPy5tYXhMZW5ndGggJiYgKG5hbWUuZGlydHkgfHwgbmFtZS50b3VjaGVkKVwiXHJcbiAgICAgICAgICAgID5uYW1lIHRvbyBsb25nPC9tYXQtZXJyb3JcclxuICAgICAgICAgID5cclxuICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG5cclxuICAgICAgICA8IS0tIHZhbHVlIC0tPlxyXG4gICAgICAgIDxtYXQtZm9ybS1maWVsZD5cclxuICAgICAgICAgIDxtYXQtbGFiZWw+dmFsdWU8L21hdC1sYWJlbD5cclxuICAgICAgICAgIDxpbnB1dCBtYXRJbnB1dCBbZm9ybUNvbnRyb2xdPVwidmFsdWVcIiAvPlxyXG4gICAgICAgICAgPG1hdC1lcnJvclxyXG4gICAgICAgICAgICAqbmdJZj1cIlxyXG4gICAgICAgICAgICAgICRhbnkodmFsdWUpLmVycm9ycz8ucmVxdWlyZWQgJiYgKHZhbHVlLmRpcnR5IHx8IHZhbHVlLnRvdWNoZWQpXHJcbiAgICAgICAgICAgIFwiXHJcbiAgICAgICAgICAgID52YWx1ZSByZXF1aXJlZDwvbWF0LWVycm9yXHJcbiAgICAgICAgICA+XHJcbiAgICAgICAgICA8bWF0LWVycm9yXHJcbiAgICAgICAgICAgICpuZ0lmPVwiXHJcbiAgICAgICAgICAgICAgJGFueSh2YWx1ZSkuZXJyb3JzPy5tYXhMZW5ndGggJiYgKHZhbHVlLmRpcnR5IHx8IHZhbHVlLnRvdWNoZWQpXHJcbiAgICAgICAgICAgIFwiXHJcbiAgICAgICAgICAgID52YWx1ZSB0b28gbG9uZzwvbWF0LWVycm9yXHJcbiAgICAgICAgICA+XHJcbiAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuXHJcbiAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgdHlwZT1cInN1Ym1pdFwiXHJcbiAgICAgICAgICBtYXQtaWNvbi1idXR0b25cclxuICAgICAgICAgIGNvbG9yPVwicHJpbWFyeVwiXHJcbiAgICAgICAgICBbZGlzYWJsZWRdPVwiZm9ybS5pbnZhbGlkXCJcclxuICAgICAgICA+XHJcbiAgICAgICAgICA8bWF0LWljb24gY2xhc3M9XCJtYXQtcHJpbWFyeVwiPmFkZF9jaXJjbGU8L21hdC1pY29uPlxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICA8L2Rpdj5cclxuICAgIDwvZmllbGRzZXQ+XHJcbiAgPC9mb3JtPlxyXG48L2Rpdj5cclxuIl19
@@ -0,0 +1,37 @@
1
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
2
+ import { MatRippleModule } from '@angular/material/core';
3
+ import { NgToolsModule } from '@myrmidon/ng-tools';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/material/core";
6
+ import * as i2 from "@myrmidon/ng-tools";
7
+ /**
8
+ * A component that displays a single character from a base text.
9
+ */
10
+ export class BaseTextCharComponent {
11
+ constructor() {
12
+ this.defaultColor = '#D8D8D8';
13
+ this.defaultBorderColor = '#D8D8D8';
14
+ this.defaultEmSize = 1.5;
15
+ this.charPick = new EventEmitter();
16
+ }
17
+ get char() {
18
+ return this._char;
19
+ }
20
+ set char(value) {
21
+ this._char = value || undefined;
22
+ }
23
+ onCharClick(event) {
24
+ this.charPick.emit({ char: this._char, event });
25
+ }
26
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: BaseTextCharComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.4", type: BaseTextCharComponent, isStandalone: true, selector: "gve-base-text-char", inputs: { char: "char" }, outputs: { charPick: "charPick" }, ngImport: i0, template: "@if (char) {\r\n<div matRipple id=\"container\" (click)=\"onCharClick($event)\">\r\n <div\r\n id=\"c-label\"\r\n [style.fontSize]=\"char.emSize + 'em'\"\r\n [style.borderColor]=\"char.borderColor\"\r\n >\r\n {{ char.label }}\r\n </div>\r\n <div\r\n id=\"c-id\"\r\n [style.fontSize]=\"char.emSize / 2 + 'em'\"\r\n [style.color]=\"char.color | colorToContrast\"\r\n [style.borderColor]=\"char.borderColor\"\r\n [style.backgroundColor]=\"char.color\"\r\n >\r\n {{ char.id }}\r\n </div>\r\n</div>\r\n}\r\n", styles: ["div#container{cursor:pointer;flex-direction:column;align-items:center}div#c-label{border:1px solid silver;border-radius:6px;padding:6px;height:1.5em;align-items:center;justify-content:center;text-align:center}div#c-id{margin-top:4px;margin-bottom:16px;border:1px solid silver;border-radius:6px;padding:6px;align-items:center;justify-content:center;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i1.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: NgToolsModule }, { kind: "pipe", type: i2.ColorToContrastPipe, name: "colorToContrast" }] }); }
28
+ }
29
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: BaseTextCharComponent, decorators: [{
30
+ type: Component,
31
+ args: [{ selector: 'gve-base-text-char', standalone: true, imports: [MatRippleModule, NgToolsModule], template: "@if (char) {\r\n<div matRipple id=\"container\" (click)=\"onCharClick($event)\">\r\n <div\r\n id=\"c-label\"\r\n [style.fontSize]=\"char.emSize + 'em'\"\r\n [style.borderColor]=\"char.borderColor\"\r\n >\r\n {{ char.label }}\r\n </div>\r\n <div\r\n id=\"c-id\"\r\n [style.fontSize]=\"char.emSize / 2 + 'em'\"\r\n [style.color]=\"char.color | colorToContrast\"\r\n [style.borderColor]=\"char.borderColor\"\r\n [style.backgroundColor]=\"char.color\"\r\n >\r\n {{ char.id }}\r\n </div>\r\n</div>\r\n}\r\n", styles: ["div#container{cursor:pointer;flex-direction:column;align-items:center}div#c-label{border:1px solid silver;border-radius:6px;padding:6px;height:1.5em;align-items:center;justify-content:center;text-align:center}div#c-id{margin-top:4px;margin-bottom:16px;border:1px solid silver;border-radius:6px;padding:6px;align-items:center;justify-content:center;text-align:center}\n"] }]
32
+ }], propDecorators: { char: [{
33
+ type: Input
34
+ }], charPick: [{
35
+ type: Output
36
+ }] } });
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS10ZXh0LWNoYXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbXlybWlkb24vZ3ZlLWNvcmUvc3JjL2xpYi9jb21wb25lbnRzL2Jhc2UtdGV4dC1jaGFyL2Jhc2UtdGV4dC1jaGFyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL215cm1pZG9uL2d2ZS1jb3JlL3NyYy9saWIvY29tcG9uZW50cy9iYXNlLXRleHQtY2hhci9iYXNlLXRleHQtY2hhci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUV6RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7Ozs7QUFnQm5EOztHQUVHO0FBUUgsTUFBTSxPQUFPLHFCQUFxQjtJQVBsQztRQVVTLGlCQUFZLEdBQUcsU0FBUyxDQUFDO1FBQ3pCLHVCQUFrQixHQUFHLFNBQVMsQ0FBQztRQUMvQixrQkFBYSxHQUFHLEdBQUcsQ0FBQztRQVdwQixhQUFRLEdBQ2IsSUFBSSxZQUFZLEVBQXFCLENBQUM7S0FLekM7SUFmQyxJQUNXLElBQUk7UUFDYixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUNELElBQVcsSUFBSSxDQUFDLEtBQXNDO1FBQ3BELElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxJQUFJLFNBQVMsQ0FBQztJQUNsQyxDQUFDO0lBTU0sV0FBVyxDQUFDLEtBQWlCO1FBQ2xDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUNuRCxDQUFDOzhHQXJCVSxxQkFBcUI7a0dBQXJCLHFCQUFxQiwySUM3QmxDLDJoQkFvQkEseWFES1ksZUFBZSxrU0FBRSxhQUFhOzsyRkFJN0IscUJBQXFCO2tCQVBqQyxTQUFTOytCQUNFLG9CQUFvQixjQUNsQixJQUFJLFdBQ1AsQ0FBQyxlQUFlLEVBQUUsYUFBYSxDQUFDOzhCQVk5QixJQUFJO3NCQURkLEtBQUs7Z0JBU0MsUUFBUTtzQkFEZCxNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgTWF0UmlwcGxlTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvY29yZSc7XHJcblxyXG5pbXBvcnQgeyBOZ1Rvb2xzTW9kdWxlIH0gZnJvbSAnQG15cm1pZG9uL25nLXRvb2xzJztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQmFzZVRleHRDaGFyIHtcclxuICBpZDogbnVtYmVyO1xyXG4gIHZhbHVlOiBzdHJpbmc7XHJcbiAgbGFiZWw6IHN0cmluZztcclxuICBjb2xvcjogc3RyaW5nO1xyXG4gIGJvcmRlckNvbG9yOiBzdHJpbmc7XHJcbiAgZW1TaXplOiBudW1iZXI7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQmFzZVRleHRDaGFyRXZlbnQge1xyXG4gIGNoYXI6IEJhc2VUZXh0Q2hhcjtcclxuICBldmVudDogTW91c2VFdmVudDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEEgY29tcG9uZW50IHRoYXQgZGlzcGxheXMgYSBzaW5nbGUgY2hhcmFjdGVyIGZyb20gYSBiYXNlIHRleHQuXHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2d2ZS1iYXNlLXRleHQtY2hhcicsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbTWF0UmlwcGxlTW9kdWxlLCBOZ1Rvb2xzTW9kdWxlXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vYmFzZS10ZXh0LWNoYXIuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsOiAnLi9iYXNlLXRleHQtY2hhci5jb21wb25lbnQuY3NzJyxcclxufSlcclxuZXhwb3J0IGNsYXNzIEJhc2VUZXh0Q2hhckNvbXBvbmVudCB7XHJcbiAgcHJpdmF0ZSBfY2hhcjogQmFzZVRleHRDaGFyIHwgdW5kZWZpbmVkO1xyXG5cclxuICBwdWJsaWMgZGVmYXVsdENvbG9yID0gJyNEOEQ4RDgnO1xyXG4gIHB1YmxpYyBkZWZhdWx0Qm9yZGVyQ29sb3IgPSAnI0Q4RDhEOCc7XHJcbiAgcHVibGljIGRlZmF1bHRFbVNpemUgPSAxLjU7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGdldCBjaGFyKCk6IEJhc2VUZXh0Q2hhciB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gdGhpcy5fY2hhcjtcclxuICB9XHJcbiAgcHVibGljIHNldCBjaGFyKHZhbHVlOiBCYXNlVGV4dENoYXIgfCB1bmRlZmluZWQgfCBudWxsKSB7XHJcbiAgICB0aGlzLl9jaGFyID0gdmFsdWUgfHwgdW5kZWZpbmVkO1xyXG4gIH1cclxuXHJcbiAgQE91dHB1dCgpXHJcbiAgcHVibGljIGNoYXJQaWNrOiBFdmVudEVtaXR0ZXI8QmFzZVRleHRDaGFyRXZlbnQ+ID1cclxuICAgIG5ldyBFdmVudEVtaXR0ZXI8QmFzZVRleHRDaGFyRXZlbnQ+KCk7XHJcblxyXG4gIHB1YmxpYyBvbkNoYXJDbGljayhldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xyXG4gICAgdGhpcy5jaGFyUGljay5lbWl0KHsgY2hhcjogdGhpcy5fY2hhciEsIGV2ZW50IH0pO1xyXG4gIH1cclxufVxyXG4iLCJAaWYgKGNoYXIpIHtcclxuPGRpdiBtYXRSaXBwbGUgaWQ9XCJjb250YWluZXJcIiAoY2xpY2spPVwib25DaGFyQ2xpY2soJGV2ZW50KVwiPlxyXG4gIDxkaXZcclxuICAgIGlkPVwiYy1sYWJlbFwiXHJcbiAgICBbc3R5bGUuZm9udFNpemVdPVwiY2hhci5lbVNpemUgKyAnZW0nXCJcclxuICAgIFtzdHlsZS5ib3JkZXJDb2xvcl09XCJjaGFyLmJvcmRlckNvbG9yXCJcclxuICA+XHJcbiAgICB7eyBjaGFyLmxhYmVsIH19XHJcbiAgPC9kaXY+XHJcbiAgPGRpdlxyXG4gICAgaWQ9XCJjLWlkXCJcclxuICAgIFtzdHlsZS5mb250U2l6ZV09XCJjaGFyLmVtU2l6ZSAvIDIgKyAnZW0nXCJcclxuICAgIFtzdHlsZS5jb2xvcl09XCJjaGFyLmNvbG9yIHwgY29sb3JUb0NvbnRyYXN0XCJcclxuICAgIFtzdHlsZS5ib3JkZXJDb2xvcl09XCJjaGFyLmJvcmRlckNvbG9yXCJcclxuICAgIFtzdHlsZS5iYWNrZ3JvdW5kQ29sb3JdPVwiY2hhci5jb2xvclwiXHJcbiAgPlxyXG4gICAge3sgY2hhci5pZCB9fVxyXG4gIDwvZGl2PlxyXG48L2Rpdj5cclxufVxyXG4iXX0=
@@ -0,0 +1,111 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
3
+ import { ReactiveFormsModule, Validators, } from '@angular/forms';
4
+ import { MatButtonModule } from '@angular/material/button';
5
+ import { MatFormFieldModule } from '@angular/material/form-field';
6
+ import { MatIconModule } from '@angular/material/icon';
7
+ import { MatInputModule } from '@angular/material/input';
8
+ import { MatTooltipModule } from '@angular/material/tooltip';
9
+ import { SnapshotViewService, } from '@myrmidon/gve-snapshot-view';
10
+ import { BaseTextViewComponent, } from '../base-text-view/base-text-view.component';
11
+ import { FeatureSetEditorComponent } from '../feature-set-editor/feature-set-editor.component';
12
+ import * as i0 from "@angular/core";
13
+ import * as i1 from "@angular/forms";
14
+ import * as i2 from "@myrmidon/ng-mat-tools";
15
+ import * as i3 from "@angular/common";
16
+ import * as i4 from "@angular/material/button";
17
+ import * as i5 from "@angular/material/form-field";
18
+ import * as i6 from "@angular/material/input";
19
+ import * as i7 from "@angular/material/tooltip";
20
+ /**
21
+ * Editor for snapshot's base text. This can receive a string or an array
22
+ * of `CharNode` objects, and lets the user edit the text, character by
23
+ * character, optionally also setting its features.
24
+ */
25
+ export class BaseTextEditorComponent {
26
+ /**
27
+ * The text to edit. In input this can be a string, an array of `CharNode`
28
+ * objects. In output this will be an array of `CharNode` objects.
29
+ */
30
+ get text() {
31
+ return this._text;
32
+ }
33
+ set text(value) {
34
+ this.resetSelectedChar();
35
+ if (this._text === value) {
36
+ return;
37
+ }
38
+ if (!value) {
39
+ this._text = [];
40
+ }
41
+ else {
42
+ this._text = Array.isArray(value)
43
+ ? value
44
+ : SnapshotViewService.stringToBaseChars(value);
45
+ }
46
+ }
47
+ constructor(formBuilder, _dialogService) {
48
+ this._dialogService = _dialogService;
49
+ this._text = [];
50
+ /**
51
+ * Emits the edited text as an array of `CharNode`'s whenever it changes.
52
+ */
53
+ this.textChange = new EventEmitter();
54
+ this.userText = formBuilder.control('', {
55
+ nonNullable: true,
56
+ validators: [Validators.required, Validators.maxLength(10000)],
57
+ });
58
+ this.form = formBuilder.group({
59
+ userText: this.userText,
60
+ });
61
+ }
62
+ resetSelectedChar() {
63
+ this.selectedChar = undefined;
64
+ this.selectedCharLabel = undefined;
65
+ }
66
+ onSelectedChar(event) {
67
+ this.selectedChar = this._text.find((c) => c.id === event.char.id);
68
+ this.selectedCharLabel = event.char.label;
69
+ }
70
+ onFeaturesChange(features) {
71
+ this.selectedChar.features = features;
72
+ this.textChange.emit(this._text);
73
+ }
74
+ onRangePick(range) {
75
+ this.textRange = range;
76
+ }
77
+ patchTextFromUser() {
78
+ // TODO
79
+ }
80
+ setTextFromUser() {
81
+ this._dialogService
82
+ .confirm('Confirm', 'Reset text?')
83
+ .subscribe((yes) => {
84
+ if (yes) {
85
+ this.text = this.userText.value;
86
+ this.textChange.emit(this._text);
87
+ }
88
+ });
89
+ }
90
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: BaseTextEditorComponent, deps: [{ token: i1.FormBuilder }, { token: i2.DialogService }], target: i0.ɵɵFactoryTarget.Component }); }
91
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.4", type: BaseTextEditorComponent, isStandalone: true, selector: "gve-base-text-editor", inputs: { text: "text" }, outputs: { textChange: "textChange" }, ngImport: i0, template: "<form [formGroup]=\"form\" (submit)=\"setTextFromUser()\">\r\n <!-- text -->\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>text</mat-label>\r\n <textarea matInput [formControl]=\"userText\" rows=\"5\"></textarea>\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.required &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.maxLength &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <!-- set -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-warn\"\r\n matTooltip=\"Reset characters to newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"setTextFromUser()\"\r\n >\r\n set\r\n </button>\r\n <!-- patch -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n matTooltip=\"Patch characters with newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"patchTextFromUser()\"\r\n >\r\n patch\r\n </button>\r\n </div>\r\n\r\n <!-- base text -->\r\n <div id=\"text-view\">\r\n <gve-base-text-view\r\n [text]=\"text\"\r\n (charPick)=\"onSelectedChar($event)\"\r\n (rangePick)=\"textRange = $event\"\r\n />\r\n\r\n <!-- text range -->\r\n @if (textRange) {\r\n <div id=\"text-range\">{{ textRange.at }} \u00D7 {{ textRange.run }}</div>\r\n }\r\n </div>\r\n\r\n <!-- char features -->\r\n @if (selectedChar) {\r\n <fieldset>\r\n <legend>features</legend>\r\n <gve-feature-set-editor\r\n [features]=\"selectedChar.features || []\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n</form>\r\n", styles: [".full-width{width:100%}#text-view{margin:8px 0}fieldset{border:1px solid #ccc;padding:10px;margin:10px 0;border-radius:5px}legend{color:silver}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: BaseTextViewComponent, selector: "gve-base-text-view", inputs: ["defaultColor", "defaultBorderColor", "selectionColor", "hasLineNumber", "text"], outputs: ["charPick", "rangePick"] }, { kind: "component", type: FeatureSetEditorComponent, selector: "gve-feature-set-editor", inputs: ["isVar", "featNames", "featValues", "noFilter", "features"], outputs: ["featuresChange"] }] }); }
92
+ }
93
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: BaseTextEditorComponent, decorators: [{
94
+ type: Component,
95
+ args: [{ selector: 'gve-base-text-editor', standalone: true, imports: [
96
+ CommonModule,
97
+ ReactiveFormsModule,
98
+ MatButtonModule,
99
+ MatFormFieldModule,
100
+ MatIconModule,
101
+ MatInputModule,
102
+ MatTooltipModule,
103
+ BaseTextViewComponent,
104
+ FeatureSetEditorComponent,
105
+ ], template: "<form [formGroup]=\"form\" (submit)=\"setTextFromUser()\">\r\n <!-- text -->\r\n <div>\r\n <mat-form-field class=\"full-width\">\r\n <mat-label>text</mat-label>\r\n <textarea matInput [formControl]=\"userText\" rows=\"5\"></textarea>\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.required &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text required</mat-error\r\n >\r\n <mat-error\r\n *ngIf=\"\r\n $any(userText).errors?.maxLength &&\r\n (userText.dirty || userText.touched)\r\n \"\r\n >text too long</mat-error\r\n >\r\n </mat-form-field>\r\n </div>\r\n <!-- buttons -->\r\n <div class=\"form-row\">\r\n <!-- set -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-warn\"\r\n matTooltip=\"Reset characters to newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"setTextFromUser()\"\r\n >\r\n set\r\n </button>\r\n <!-- patch -->\r\n <button\r\n type=\"button\"\r\n mat-flat-button\r\n class=\"mat-primary\"\r\n matTooltip=\"Patch characters with newly entered text\"\r\n [disabled]=\"!userText.value\"\r\n (click)=\"patchTextFromUser()\"\r\n >\r\n patch\r\n </button>\r\n </div>\r\n\r\n <!-- base text -->\r\n <div id=\"text-view\">\r\n <gve-base-text-view\r\n [text]=\"text\"\r\n (charPick)=\"onSelectedChar($event)\"\r\n (rangePick)=\"textRange = $event\"\r\n />\r\n\r\n <!-- text range -->\r\n @if (textRange) {\r\n <div id=\"text-range\">{{ textRange.at }} \u00D7 {{ textRange.run }}</div>\r\n }\r\n </div>\r\n\r\n <!-- char features -->\r\n @if (selectedChar) {\r\n <fieldset>\r\n <legend>features</legend>\r\n <gve-feature-set-editor\r\n [features]=\"selectedChar.features || []\"\r\n (featuresChange)=\"onFeaturesChange($event)\"\r\n />\r\n </fieldset>\r\n }\r\n</form>\r\n", styles: [".full-width{width:100%}#text-view{margin:8px 0}fieldset{border:1px solid #ccc;padding:10px;margin:10px 0;border-radius:5px}legend{color:silver}.form-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.form-row *{flex:0 0 auto}\n"] }]
106
+ }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.DialogService }], propDecorators: { text: [{
107
+ type: Input
108
+ }], textChange: [{
109
+ type: Output
110
+ }] } });
111
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS10ZXh0LWVkaXRvci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9teXJtaWRvbi9ndmUtY29yZS9zcmMvbGliL2NvbXBvbmVudHMvYmFzZS10ZXh0LWVkaXRvci9iYXNlLXRleHQtZWRpdG9yLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL215cm1pZG9uL2d2ZS1jb3JlL3NyYy9saWIvY29tcG9uZW50cy9iYXNlLXRleHQtZWRpdG9yL2Jhc2UtdGV4dC1lZGl0b3IuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdkUsT0FBTyxFQUlMLG1CQUFtQixFQUNuQixVQUFVLEdBQ1gsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUU3RCxPQUFPLEVBR0wsbUJBQW1CLEdBQ3BCLE1BQU0sNkJBQTZCLENBQUM7QUFJckMsT0FBTyxFQUNMLHFCQUFxQixHQUV0QixNQUFNLDRDQUE0QyxDQUFDO0FBQ3BELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLG9EQUFvRCxDQUFDOzs7Ozs7Ozs7QUFFL0Y7Ozs7R0FJRztBQWtCSCxNQUFNLE9BQU8s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LDhCQUNiLGNBQWMsMFdBQ2QsZ0JBQWdCLDZUQUNoQixxQkFBcUIsOExBQ3JCLHlCQUF5Qjs7MkZBS2hCLHVCQUF1QjtrQkFqQm5DLFNBQVM7K0JBQ0Usc0JBQXNCLGNBQ3BCLElBQUksV0FDUDt3QkFDUCxZQUFZO3dCQUNaLG1CQUFtQjt3QkFDbkIsZUFBZTt3QkFDZixrQkFBa0I7d0JBQ2xCLGFBQWE7d0JBQ2IsY0FBYzt3QkFDZCxnQkFBZ0I7d0JBQ2hCLHFCQUFxQjt3QkFDckIseUJBQXlCO3FCQUMxQjs0R0FZVSxJQUFJO3NCQURkLEtBQUs7Z0JBc0JVLFVBQVU7c0JBRHpCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE91dHB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQge1xyXG4gIEZvcm1CdWlsZGVyLFxyXG4gIEZvcm1Db250cm9sLFxyXG4gIEZvcm1Hcm91cCxcclxuICBSZWFjdGl2ZUZvcm1zTW9kdWxlLFxyXG4gIFZhbGlkYXRvcnMsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgeyBNYXRCdXR0b25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9idXR0b24nO1xyXG5pbXBvcnQgeyBNYXRGb3JtRmllbGRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9mb3JtLWZpZWxkJztcclxuaW1wb3J0IHsgTWF0SWNvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2ljb24nO1xyXG5pbXBvcnQgeyBNYXRJbnB1dE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2lucHV0JztcclxuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xyXG5cclxuaW1wb3J0IHtcclxuICBDaGFyTm9kZSxcclxuICBGZWF0dXJlLFxyXG4gIFNuYXBzaG90Vmlld1NlcnZpY2UsXHJcbn0gZnJvbSAnQG15cm1pZG9uL2d2ZS1zbmFwc2hvdC12aWV3JztcclxuaW1wb3J0IHsgRGlhbG9nU2VydmljZSB9IGZyb20gJ0BteXJtaWRvbi9uZy1tYXQtdG9vbHMnO1xyXG5cclxuaW1wb3J0IHsgQmFzZVRleHRDaGFyRXZlbnQgfSBmcm9tICcuLi9iYXNlLXRleHQtY2hhci9iYXNlLXRleHQtY2hhci5jb21wb25lbnQnO1xyXG5pbXBvcnQge1xyXG4gIEJhc2VUZXh0Vmlld0NvbXBvbmVudCxcclxuICBWYXJCYXNlVGV4dFJhbmdlLFxyXG59IGZyb20gJy4uL2Jhc2UtdGV4dC12aWV3L2Jhc2UtdGV4dC12aWV3LmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IEZlYXR1cmVTZXRFZGl0b3JDb21wb25lbnQgfSBmcm9tICcuLi9mZWF0dXJlLXNldC1lZGl0b3IvZmVhdHVyZS1zZXQtZWRpdG9yLmNvbXBvbmVudCc7XHJcblxyXG4vKipcclxuICogRWRpdG9yIGZvciBzbmFwc2hvdCdzIGJhc2UgdGV4dC4gVGhpcyBjYW4gcmVjZWl2ZSBhIHN0cmluZyBvciBhbiBhcnJheVxyXG4gKiBvZiBgQ2hhck5vZGVgIG9iamVjdHMsIGFuZCBsZXRzIHRoZSB1c2VyIGVkaXQgdGhlIHRleHQsIGNoYXJhY3RlciBieVxyXG4gKiBjaGFyYWN0ZXIsIG9wdGlvbmFsbHkgYWxzbyBzZXR0aW5nIGl0cyBmZWF0dXJlcy5cclxuICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnZ3ZlLWJhc2UtdGV4dC1lZGl0b3InLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1xyXG4gICAgQ29tbW9uTW9kdWxlLFxyXG4gICAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcclxuICAgIE1hdEJ1dHRvbk1vZHVsZSxcclxuICAgIE1hdEZvcm1GaWVsZE1vZHVsZSxcclxuICAgIE1hdEljb25Nb2R1bGUsXHJcbiAgICBNYXRJbnB1dE1vZHVsZSxcclxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXHJcbiAgICBCYXNlVGV4dFZpZXdDb21wb25lbnQsXHJcbiAgICBGZWF0dXJlU2V0RWRpdG9yQ29tcG9uZW50LFxyXG4gIF0sXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2Jhc2UtdGV4dC1lZGl0b3IuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsOiAnLi9iYXNlLXRleHQtZWRpdG9yLmNvbXBvbmVudC5jc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQmFzZVRleHRFZGl0b3JDb21wb25lbnQge1xyXG4gIHByaXZhdGUgX3RleHQ6IENoYXJOb2RlW10gPSBbXTtcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIHRleHQgdG8gZWRpdC4gSW4gaW5wdXQgdGhpcyBjYW4gYmUgYSBzdHJpbmcsIGFuIGFycmF5IG9mIGBDaGFyTm9kZWBcclxuICAgKiBvYmplY3RzLiBJbiBvdXRwdXQgdGhpcyB3aWxsIGJlIGFuIGFycmF5IG9mIGBDaGFyTm9kZWAgb2JqZWN0cy5cclxuICAgKi9cclxuICBASW5wdXQoKVxyXG4gIHB1YmxpYyBnZXQgdGV4dCgpOiBDaGFyTm9kZVtdIHtcclxuICAgIHJldHVybiB0aGlzLl90ZXh0O1xyXG4gIH1cclxuICBwdWJsaWMgc2V0IHRleHQodmFsdWU6IHN0cmluZyB8IENoYXJOb2RlW10gfCB1bmRlZmluZWQgfCBudWxsKSB7XHJcbiAgICB0aGlzLnJlc2V0U2VsZWN0ZWRDaGFyKCk7XHJcbiAgICBpZiAodGhpcy5fdGV4dCA9PT0gdmFsdWUpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKCF2YWx1ZSkge1xyXG4gICAgICB0aGlzLl90ZXh0ID0gW107XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLl90ZXh0ID0gQXJyYXkuaXNBcnJheSh2YWx1ZSlcclxuICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgOiBTbmFwc2hvdFZpZXdTZXJ2aWNlLnN0cmluZ1RvQmFzZUNoYXJzKHZhbHVlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVtaXRzIHRoZSBlZGl0ZWQgdGV4dCBhcyBhbiBhcnJheSBvZiBgQ2hhck5vZGVgJ3Mgd2hlbmV2ZXIgaXQgY2hhbmdlcy5cclxuICAgKi9cclxuICBAT3V0cHV0KClcclxuICBwdWJsaWMgcmVhZG9ubHkgdGV4dENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8Q2hhck5vZGVbXT4oKTtcclxuXHJcbiAgcHVibGljIHVzZXJUZXh0OiBGb3JtQ29udHJvbDxzdHJpbmc+O1xyXG4gIHB1YmxpYyBmb3JtOiBGb3JtR3JvdXA7XHJcblxyXG4gIHB1YmxpYyBzZWxlY3RlZENoYXI/OiBDaGFyTm9kZTtcclxuICBwdWJsaWMgc2VsZWN0ZWRDaGFyTGFiZWw/OiBzdHJpbmc7XHJcbiAgcHVibGljIHRleHRSYW5nZT86IFZhckJhc2VUZXh0UmFuZ2U7XHJcblxyXG4gIGNvbnN0cnVjdG9yKGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlciwgcHJpdmF0ZSBfZGlhbG9nU2VydmljZTogRGlhbG9nU2VydmljZSkge1xyXG4gICAgdGhpcy51c2VyVGV4dCA9IGZvcm1CdWlsZGVyLmNvbnRyb2woJycsIHtcclxuICAgICAgbm9uTnVsbGFibGU6IHRydWUsXHJcbiAgICAgIHZhbGlkYXRvcnM6IFtWYWxpZGF0b3JzLnJlcXVpcmVkLCBWYWxpZGF0b3JzLm1heExlbmd0aCgxMDAwMCldLFxyXG4gICAgfSk7XHJcbiAgICB0aGlzLmZvcm0gPSBmb3JtQnVpbGRlci5ncm91cCh7XHJcbiAgICAgIHVzZXJUZXh0OiB0aGlzLnVzZXJUZXh0LFxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHJlc2V0U2VsZWN0ZWRDaGFyKCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZWxlY3RlZENoYXIgPSB1bmRlZmluZWQ7XHJcbiAgICB0aGlzLnNlbGVjdGVkQ2hhckxhYmVsID0gdW5kZWZpbmVkO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIG9uU2VsZWN0ZWRDaGFyKGV2ZW50OiBCYXNlVGV4dENoYXJFdmVudCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZWxlY3RlZENoYXIgPSB0aGlzLl90ZXh0LmZpbmQoKGMpID0+IGMuaWQgPT09IGV2ZW50LmNoYXIuaWQpO1xyXG4gICAgdGhpcy5zZWxlY3RlZENoYXJMYWJlbCA9IGV2ZW50LmNoYXIubGFiZWw7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgb25GZWF0dXJlc0NoYW5nZShmZWF0dXJlczogRmVhdHVyZVtdKTogdm9pZCB7XHJcbiAgICB0aGlzLnNlbGVjdGVkQ2hhciEuZmVhdHVyZXMgPSBmZWF0dXJlcztcclxuICAgIHRoaXMudGV4dENoYW5nZS5lbWl0KHRoaXMuX3RleHQpO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIG9uUmFuZ2VQaWNrKHJhbmdlOiBWYXJCYXNlVGV4dFJhbmdlKSB7XHJcbiAgICB0aGlzLnRleHRSYW5nZSA9IHJhbmdlO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHBhdGNoVGV4dEZyb21Vc2VyKCk6IHZvaWQge1xyXG4gICAgLy8gVE9ET1xyXG4gIH1cclxuXHJcbiAgcHVibGljIHNldFRleHRGcm9tVXNlcigpOiB2b2lkIHtcclxuICAgIHRoaXMuX2RpYWxvZ1NlcnZpY2VcclxuICAgICAgLmNvbmZpcm0oJ0NvbmZpcm0nLCAnUmVzZXQgdGV4dD8nKVxyXG4gICAgICAuc3Vic2NyaWJlKCh5ZXM6IGJvb2xlYW4pID0+IHtcclxuICAgICAgICBpZiAoeWVzKSB7XHJcbiAgICAgICAgICB0aGlzLnRleHQgPSB0aGlzLnVzZXJUZXh0LnZhbHVlO1xyXG4gICAgICAgICAgdGhpcy50ZXh0Q2hhbmdlLmVtaXQodGhpcy5fdGV4dCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICB9XHJcbn1cclxuIiwiPGZvcm0gW2Zvcm1Hcm91cF09XCJmb3JtXCIgKHN1Ym1pdCk9XCJzZXRUZXh0RnJvbVVzZXIoKVwiPlxyXG4gIDwhLS0gdGV4dCAtLT5cclxuICA8ZGl2PlxyXG4gICAgPG1hdC1mb3JtLWZpZWxkIGNsYXNzPVwiZnVsbC13aWR0aFwiPlxyXG4gICAgICA8bWF0LWxhYmVsPnRleHQ8L21hdC1sYWJlbD5cclxuICAgICAgPHRleHRhcmVhIG1hdElucHV0IFtmb3JtQ29udHJvbF09XCJ1c2VyVGV4dFwiIHJvd3M9XCI1XCI+PC90ZXh0YXJlYT5cclxuICAgICAgPG1hdC1lcnJvclxyXG4gICAgICAgICpuZ0lmPVwiXHJcbiAgICAgICAgICAkYW55KHVzZXJUZXh0KS5lcnJvcnM/LnJlcXVpcmVkICYmXHJcbiAgICAgICAgICAodXNlclRleHQuZGlydHkgfHwgdXNlclRleHQudG91Y2hlZClcclxuICAgICAgICBcIlxyXG4gICAgICAgID50ZXh0IHJlcXVpcmVkPC9tYXQtZXJyb3JcclxuICAgICAgPlxyXG4gICAgICA8bWF0LWVycm9yXHJcbiAgICAgICAgKm5nSWY9XCJcclxuICAgICAgICAgICRhbnkodXNlclRleHQpLmVycm9ycz8ubWF4TGVuZ3RoICYmXHJcbiAgICAgICAgICAodXNlclRleHQuZGlydHkgfHwgdXNlclRleHQudG91Y2hlZClcclxuICAgICAgICBcIlxyXG4gICAgICAgID50ZXh0IHRvbyBsb25nPC9tYXQtZXJyb3JcclxuICAgICAgPlxyXG4gICAgPC9tYXQtZm9ybS1maWVsZD5cclxuICA8L2Rpdj5cclxuICA8IS0tIGJ1dHRvbnMgLS0+XHJcbiAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XHJcbiAgICA8IS0tIHNldCAtLT5cclxuICAgIDxidXR0b25cclxuICAgICAgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgIG1hdC1mbGF0LWJ1dHRvblxyXG4gICAgICBjbGFzcz1cIm1hdC13YXJuXCJcclxuICAgICAgbWF0VG9vbHRpcD1cIlJlc2V0IGNoYXJhY3RlcnMgdG8gbmV3bHkgZW50ZXJlZCB0ZXh0XCJcclxuICAgICAgW2Rpc2FibGVkXT1cIiF1c2VyVGV4dC52YWx1ZVwiXHJcbiAgICAgIChjbGljayk9XCJzZXRUZXh0RnJvbVVzZXIoKVwiXHJcbiAgICA+XHJcbiAgICAgIHNldFxyXG4gICAgPC9idXR0b24+XHJcbiAgICA8IS0tIHBhdGNoIC0tPlxyXG4gICAgPGJ1dHRvblxyXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgbWF0LWZsYXQtYnV0dG9uXHJcbiAgICAgIGNsYXNzPVwibWF0LXByaW1hcnlcIlxyXG4gICAgICBtYXRUb29sdGlwPVwiUGF0Y2ggY2hhcmFjdGVycyB3aXRoIG5ld2x5IGVudGVyZWQgdGV4dFwiXHJcbiAgICAgIFtkaXNhYmxlZF09XCIhdXNlclRleHQudmFsdWVcIlxyXG4gICAgICAoY2xpY2spPVwicGF0Y2hUZXh0RnJvbVVzZXIoKVwiXHJcbiAgICA+XHJcbiAgICAgIHBhdGNoXHJcbiAgICA8L2J1dHRvbj5cclxuICA8L2Rpdj5cclxuXHJcbiAgPCEtLSBiYXNlIHRleHQgLS0+XHJcbiAgPGRpdiBpZD1cInRleHQtdmlld1wiPlxyXG4gICAgPGd2ZS1iYXNlLXRleHQtdmlld1xyXG4gICAgICBbdGV4dF09XCJ0ZXh0XCJcclxuICAgICAgKGNoYXJQaWNrKT1cIm9uU2VsZWN0ZWRDaGFyKCRldmVudClcIlxyXG4gICAgICAocmFuZ2VQaWNrKT1cInRleHRSYW5nZSA9ICRldmVudFwiXHJcbiAgICAvPlxyXG5cclxuICAgIDwhLS0gdGV4dCByYW5nZSAtLT5cclxuICAgIEBpZiAodGV4dFJhbmdlKSB7XHJcbiAgICA8ZGl2IGlkPVwidGV4dC1yYW5nZVwiPnt7IHRleHRSYW5nZS5hdCB9fSDDlyB7eyB0ZXh0UmFuZ2UucnVuIH19PC9kaXY+XHJcbiAgICB9XHJcbiAgPC9kaXY+XHJcblxyXG4gIDwhLS0gY2hhciBmZWF0dXJlcyAtLT5cclxuICBAaWYgKHNlbGVjdGVkQ2hhcikge1xyXG4gIDxmaWVsZHNldD5cclxuICAgIDxsZWdlbmQ+ZmVhdHVyZXM8L2xlZ2VuZD5cclxuICAgIDxndmUtZmVhdHVyZS1zZXQtZWRpdG9yXHJcbiAgICAgIFtmZWF0dXJlc109XCJzZWxlY3RlZENoYXIuZmVhdHVyZXMgfHwgW11cIlxyXG4gICAgICAoZmVhdHVyZXNDaGFuZ2UpPVwib25GZWF0dXJlc0NoYW5nZSgkZXZlbnQpXCJcclxuICAgIC8+XHJcbiAgPC9maWVsZHNldD5cclxuICB9XHJcbjwvZm9ybT5cclxuIl19
@@ -0,0 +1,125 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { Component, EventEmitter, Input, Output } from '@angular/core';
3
+ import { BaseTextCharComponent, } from '../base-text-char/base-text-char.component';
4
+ import { SnapshotViewService } from '@myrmidon/gve-snapshot-view';
5
+ import * as i0 from "@angular/core";
6
+ /**
7
+ * A component to display a selectable base text.
8
+ */
9
+ export class BaseTextViewComponent {
10
+ constructor() {
11
+ this.defaultColor = '#DBDBDB';
12
+ this.defaultBorderColor = '#DBDBDB';
13
+ this.selectionColor = '#3E92CC';
14
+ this.hasLineNumber = false;
15
+ this.charPick = new EventEmitter();
16
+ this.rangePick = new EventEmitter();
17
+ this.lines = [];
18
+ }
19
+ get text() {
20
+ return this._text;
21
+ }
22
+ set text(value) {
23
+ this._text = value || undefined;
24
+ this.buildLines();
25
+ }
26
+ buildLines() {
27
+ if (!this._text) {
28
+ this.lines = [];
29
+ return;
30
+ }
31
+ const newLines = [];
32
+ newLines.push([]);
33
+ if (Array.isArray(this._text)) {
34
+ const nodes = this._text;
35
+ for (let i = 0; i < nodes.length; i++) {
36
+ const char = {
37
+ id: nodes[i].id,
38
+ value: nodes[i].data,
39
+ label: nodes[i].label,
40
+ color: this.defaultColor,
41
+ borderColor: this.defaultBorderColor,
42
+ emSize: 1.5,
43
+ };
44
+ newLines[newLines.length - 1].push(char);
45
+ if (char.value === '\n') {
46
+ newLines.push([]);
47
+ }
48
+ }
49
+ }
50
+ else {
51
+ for (let i = 0; i < this._text.length; i++) {
52
+ const char = {
53
+ id: i + 1,
54
+ value: this._text[i],
55
+ label: SnapshotViewService.translateSpecialChar(this._text[i]),
56
+ color: this.defaultColor,
57
+ borderColor: this.defaultBorderColor,
58
+ emSize: 1.5,
59
+ };
60
+ newLines[newLines.length - 1].push(char);
61
+ if (char.value === '\n') {
62
+ newLines.push([]);
63
+ }
64
+ }
65
+ }
66
+ this.lines = newLines;
67
+ }
68
+ resetColors() {
69
+ for (const line of this.lines) {
70
+ for (const c of line) {
71
+ c.color = this.defaultColor;
72
+ c.borderColor = this.defaultBorderColor;
73
+ }
74
+ }
75
+ }
76
+ onCharPick(event) {
77
+ this.resetColors();
78
+ if (this._lastSelectedChar &&
79
+ this._lastSelectedChar !== event.char &&
80
+ event.event.ctrlKey) {
81
+ const minId = Math.min(this._lastSelectedChar.id, event.char.id);
82
+ const maxId = Math.max(this._lastSelectedChar.id, event.char.id);
83
+ for (const line of this.lines) {
84
+ for (const c of line) {
85
+ if (c.id >= minId && c.id <= maxId) {
86
+ c.color = this.selectionColor;
87
+ c.borderColor = this.selectionColor;
88
+ }
89
+ }
90
+ }
91
+ this.charPick.emit(event);
92
+ this.rangePick.emit({ at: minId, run: maxId - minId + 1 });
93
+ return;
94
+ }
95
+ else {
96
+ // select current char
97
+ event.char.color = this.selectionColor;
98
+ event.char.borderColor = this.selectionColor;
99
+ this.charPick.emit(event);
100
+ this.rangePick.emit({ at: event.char.id, run: 1 });
101
+ }
102
+ this._lastSelectedChar = event.char;
103
+ }
104
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: BaseTextViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
105
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.4", type: BaseTextViewComponent, isStandalone: true, selector: "gve-base-text-view", inputs: { defaultColor: "defaultColor", defaultBorderColor: "defaultBorderColor", selectionColor: "selectionColor", hasLineNumber: "hasLineNumber", text: "text" }, outputs: { charPick: "charPick", rangePick: "rangePick" }, ngImport: i0, template: "<div id=\"text\">\r\n @for (line of lines; track line) {\r\n <div class=\"line\">\r\n @if (hasLineNumber) {\r\n <div class=\"nr\">\r\n {{ lines.indexOf(line) + 1 }}\r\n </div>\r\n } @for (c of line; track c.id) {\r\n <gve-base-text-char [char]=\"c\" (charPick)=\"onCharPick($event)\" />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".line{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.line *{flex:0 0 auto}.nr{font-size:.8em;font-weight:700;color:silver;margin:0 4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: BaseTextCharComponent, selector: "gve-base-text-char", inputs: ["char"], outputs: ["charPick"] }] }); }
106
+ }
107
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.4", ngImport: i0, type: BaseTextViewComponent, decorators: [{
108
+ type: Component,
109
+ args: [{ selector: 'gve-base-text-view', standalone: true, imports: [CommonModule, BaseTextCharComponent], template: "<div id=\"text\">\r\n @for (line of lines; track line) {\r\n <div class=\"line\">\r\n @if (hasLineNumber) {\r\n <div class=\"nr\">\r\n {{ lines.indexOf(line) + 1 }}\r\n </div>\r\n } @for (c of line; track c.id) {\r\n <gve-base-text-char [char]=\"c\" (charPick)=\"onCharPick($event)\" />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".line{display:flex;gap:8px;align-items:center;flex-wrap:wrap}.line *{flex:0 0 auto}.nr{font-size:.8em;font-weight:700;color:silver;margin:0 4px}\n"] }]
110
+ }], propDecorators: { defaultColor: [{
111
+ type: Input
112
+ }], defaultBorderColor: [{
113
+ type: Input
114
+ }], selectionColor: [{
115
+ type: Input
116
+ }], hasLineNumber: [{
117
+ type: Input
118
+ }], text: [{
119
+ type: Input
120
+ }], charPick: [{
121
+ type: Output
122
+ }], rangePick: [{
123
+ type: Output
124
+ }] } });
125
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS10ZXh0LXZpZXcuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbXlybWlkb24vZ3ZlLWNvcmUvc3JjL2xpYi9jb21wb25lbnRzL2Jhc2UtdGV4dC12aWV3L2Jhc2UtdGV4dC12aWV3LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL215cm1pZG9uL2d2ZS1jb3JlL3NyYy9saWIvY29tcG9uZW50cy9iYXNlLXRleHQtdmlldy9iYXNlLXRleHQtdmlldy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUV2RSxPQUFPLEVBRUwscUJBQXFCLEdBRXRCLE1BQU0sNENBQTRDLENBQUM7QUFDcEQsT0FBTyxFQUFZLG1CQUFtQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7O0FBTzVFOztHQUVHO0FBUUgsTUFBTSxPQUFPLHFCQUFxQjtJQVBsQztRQVlTLGlCQUFZLEdBQUcsU0FBUyxDQUFDO1FBR3pCLHVCQUFrQixHQUFHLFNBQVMsQ0FBQztRQUcvQixtQkFBYyxHQUFHLFNBQVMsQ0FBQztRQUczQixrQkFBYSxHQUFHLEtBQUssQ0FBQztRQVl0QixhQUFRLEdBQ2IsSUFBSSxZQUFZLEVBQXFCLENBQUM7UUFHakMsY0FBUyxHQUNkLElBQUksWUFBWSxFQUFvQixDQUFDO1FBRWhDLFVBQUssR0FBcUIsRUFBRSxDQUFDO0tBMkZyQztJQTVHQyxJQUNXLElBQUk7UUFDYixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUNELElBQVcsSUFBSSxDQUFDLEtBQTZDO1FBQzNELElBQUksQ0FBQyxLQUFLLEdBQUcsS0FB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QUMsV0FBVyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUM7WUFDN0MsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDMUIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDckQsQ0FBQztRQUVELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDO0lBQ3RDLENBQUM7OEdBM0hVLHFCQUFxQjtrR0FBckIscUJBQXFCLDZTQ3pCbEMsZ1dBYUEsMk1EUVksWUFBWSwrQkFBRSxxQkFBcUI7OzJGQUlsQyxxQkFBcUI7a0JBUGpDLFNBQVM7K0JBQ0Usb0JBQW9CLGNBQ2xCLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSxxQkFBcUIsQ0FBQzs4QkFTdkMsWUFBWTtzQkFEbEIsS0FBSztnQkFJQyxrQkFBa0I7c0JBRHhCLEtBQUs7Z0JBSUMsY0FBYztzQkFEcEIsS0FBSztnQkFJQyxhQUFhO3NCQURuQixLQUFLO2dCQUlLLElBQUk7c0JBRGQsS0FBSztnQkFVQyxRQUFRO3NCQURkLE1BQU07Z0JBS0EsU0FBUztzQkFEZixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuXHJcbmltcG9ydCB7XHJcbiAgQmFzZVRleHRDaGFyLFxyXG4gIEJhc2VUZXh0Q2hhckNvbXBvbmVudCxcclxuICBCYXNlVGV4dENoYXJFdmVudCxcclxufSBmcm9tICcuLi9iYXNlLXRleHQtY2hhci9iYXNlLXRleHQtY2hhci5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBDaGFyTm9kZSwgU25hcHNob3RWaWV3U2VydmljZSB9IGZyb20gJ0BteXJtaWRvbi9ndmUtc25hcHNob3Qtdmlldyc7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFZhckJhc2VUZXh0UmFuZ2Uge1xyXG4gIGF0OiBudW1iZXI7XHJcbiAgcnVuOiBudW1iZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBIGNvbXBvbmVudCB0byBkaXNwbGF5IGEgc2VsZWN0YWJsZSBiYXNlIHRleHQuXHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2d2ZS1iYXNlLXRleHQtdmlldycsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBCYXNlVGV4dENoYXJDb21wb25lbnRdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9iYXNlLXRleHQtdmlldy5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmw6ICcuL2Jhc2UtdGV4dC12aWV3LmNvbXBvbmVudC5jc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQmFzZVRleHRWaWV3Q29tcG9uZW50IHtcclxuICBwcml2YXRlIF90ZXh0Pzogc3RyaW5nIHwgQ2hhck5vZGVbXTtcclxuICBwcml2YXRlIF9sYXN0U2VsZWN0ZWRDaGFyPzogQmFzZVRleHRDaGFyO1xyXG5cclxuICBASW5wdXQoKVxyXG4gIHB1YmxpYyBkZWZhdWx0Q29sb3IgPSAnI0RCREJEQic7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGRlZmF1bHRCb3JkZXJDb2xvciA9ICcjREJEQkRCJztcclxuXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgc2VsZWN0aW9uQ29sb3IgPSAnIzNFOTJDQyc7XHJcblxyXG4gIEBJbnB1dCgpXHJcbiAgcHVibGljIGhhc0xpbmVOdW1iZXIgPSBmYWxzZTtcclxuXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgZ2V0IHRleHQoKTogc3RyaW5nIHwgQ2hhck5vZGVbXSB8IHVuZGVmaW5lZCB7XHJcbiAgICByZXR1cm4gdGhpcy5fdGV4dDtcclxuICB9XHJcbiAgcHVibGljIHNldCB0ZXh0KHZhbHVlOiBzdHJpbmcgfCBDaGFyTm9kZVtdIHwgdW5kZWZpbmVkIHwgbnVsbCkge1xyXG4gICAgdGhpcy5fdGV4dCA9IHZhbHVlIHx8IHVuZGVmaW5lZDtcclxuICAgIHRoaXMuYnVpbGRMaW5lcygpO1xyXG4gIH1cclxuXHJcbiAgQE91dHB1dCgpXHJcbiAgcHVibGljIGNoYXJQaWNrOiBFdmVudEVtaXR0ZXI8QmFzZVRleHRDaGFyRXZlbnQ+ID1cclxuICAgIG5ldyBFdmVudEVtaXR0ZXI8QmFzZVRleHRDaGFyRXZlbnQ+KCk7XHJcblxyXG4gIEBPdXRwdXQoKVxyXG4gIHB1YmxpYyByYW5nZVBpY2s6IEV2ZW50RW1pdHRlcjxWYXJCYXNlVGV4dFJhbmdlPiA9XHJcbiAgICBuZXcgRXZlbnRFbWl0dGVyPFZhckJhc2VUZXh0UmFuZ2U+KCk7XHJcblxyXG4gIHB1YmxpYyBsaW5lczogQmFzZVRleHRDaGFyW11bXSA9IFtdO1xyXG5cclxuICBwcml2YXRlIGJ1aWxkTGluZXMoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMuX3RleHQpIHtcclxuICAgICAgdGhpcy5saW5lcyA9IFtdO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgbmV3TGluZXM6IEJhc2VUZXh0Q2hhcltdW10gPSBbXTtcclxuICAgIG5ld0xpbmVzLnB1c2goW10pO1xyXG5cclxuICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMuX3RleHQpKSB7XHJcbiAgICAgIGNvbnN0IG5vZGVzID0gdGhpcy5fdGV4dCBhcyBDaGFyTm9kZVtdO1xyXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgY29uc3QgY2hhcjogQmFzZVRleHRDaGFyID0ge1xyXG4gICAgICAgICAgaWQ6IG5vZGVzW2ldLmlkLFxyXG4gICAgICAgICAgdmFsdWU6IG5vZGVzW2ldLmRhdGEsXHJcbiAgICAgICAgICBsYWJlbDogbm9kZXNbaV0ubGFiZWwsXHJcbiAgICAgICAgICBjb2xvcjogdGhpcy5kZWZhdWx0Q29sb3IsXHJcbiAgICAgICAgICBib3JkZXJDb2xvcjogdGhpcy5kZWZhdWx0Qm9yZGVyQ29sb3IsXHJcbiAgICAgICAgICBlbVNpemU6IDEuNSxcclxuICAgICAgICB9O1xyXG4gICAgICAgIG5ld0xpbmVzW25ld0xpbmVzLmxlbmd0aCAtIDFdLnB1c2goY2hhcik7XHJcblxyXG4gICAgICAgIGlmIChjaGFyLnZhbHVlID09PSAnXFxuJykge1xyXG4gICAgICAgICAgbmV3TGluZXMucHVzaChbXSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuX3RleHQubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICBjb25zdCBjaGFyOiBCYXNlVGV4dENoYXIgPSB7XHJcbiAgICAgICAgICBpZDogaSArIDEsXHJcbiAgICAgICAgICB2YWx1ZTogdGhpcy5fdGV4dFtpXSxcclxuICAgICAgICAgIGxhYmVsOiBTbmFwc2hvdFZpZXdTZXJ2aWNlLnRyYW5zbGF0ZVNwZWNpYWxDaGFyKHRoaXMuX3RleHRbaV0pLFxyXG4gICAgICAgICAgY29sb3I6IHRoaXMuZGVmYXVsdENvbG9yLFxyXG4gICAgICAgICAgYm9yZGVyQ29sb3I6IHRoaXMuZGVmYXVsdEJvcmRlckNvbG9yLFxyXG4gICAgICAgICAgZW1TaXplOiAxLjUsXHJcbiAgICAgICAgfTtcclxuICAgICAgICBuZXdMaW5lc1tuZXdMaW5lcy5sZW5ndGggLSAxXS5wdXNoKGNoYXIpO1xyXG5cclxuICAgICAgICBpZiAoY2hhci52YWx1ZSA9PT0gJ1xcbicpIHtcclxuICAgICAgICAgIG5ld0xpbmVzLnB1c2goW10pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMubGluZXMgPSBuZXdMaW5lcztcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcmVzZXRDb2xvcnMoKTogdm9pZCB7XHJcbiAgICBmb3IgKGNvbnN0IGxpbmUgb2YgdGhpcy5saW5lcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGMgb2YgbGluZSkge1xyXG4gICAgICAgIGMuY29sb3IgPSB0aGlzLmRlZmF1bHRDb2xvcjtcclxuICAgICAgICBjLmJvcmRlckNvbG9yID0gdGhpcy5kZWZhdWx0Qm9yZGVyQ29sb3I7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHB1YmxpYyBvbkNoYXJQaWNrKGV2ZW50OiBCYXNlVGV4dENoYXJFdmVudCk6IHZvaWQge1xyXG4gICAgdGhpcy5yZXNldENvbG9ycygpO1xyXG5cclxuICAgIGlmIChcclxuICAgICAgdGhpcy5fbGFzdFNlbGVjdGVkQ2hhciAmJlxyXG4gICAgICB0aGlzLl9sYXN0U2VsZWN0ZWRDaGFyICE9PSBldmVudC5jaGFyICYmXHJcbiAgICAgIGV2ZW50LmV2ZW50LmN0cmxLZXlcclxuICAgICkge1xyXG4gICAgICBjb25zdCBtaW5JZCA9IE1hdGgubWluKHRoaXMuX2xhc3RTZWxlY3RlZENoYXIuaWQsIGV2ZW50LmNoYXIuaWQpO1xyXG4gICAgICBjb25zdCBtYXhJZCA9IE1hdGgubWF4KHRoaXMuX2xhc3RTZWxlY3RlZENoYXIuaWQsIGV2ZW50LmNoYXIuaWQpO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBsaW5lIG9mIHRoaXMubGluZXMpIHtcclxuICAgICAgICBmb3IgKGNvbnN0IGMgb2YgbGluZSkge1xyXG4gICAgICAgICAgaWYgKGMuaWQgPj0gbWluSWQgJiYgYy5pZCA8PSBtYXhJZCkge1xyXG4gICAgICAgICAgICBjLmNvbG9yID0gdGhpcy5zZWxlY3Rpb25Db2xvcjtcclxuICAgICAgICAgICAgYy5ib3JkZXJDb2xvciA9IHRoaXMuc2VsZWN0aW9uQ29sb3I7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzLmNoYXJQaWNrLmVtaXQoZXZlbnQpO1xyXG4gICAgICB0aGlzLnJhbmdlUGljay5lbWl0KHsgYXQ6IG1pbklkLCBydW46IG1heElkIC0gbWluSWQgKyAxIH0pO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBzZWxlY3QgY3VycmVudCBjaGFyXHJcbiAgICAgIGV2ZW50LmNoYXIuY29sb3IgPSB0aGlzLnNlbGVjdGlvbkNvbG9yO1xyXG4gICAgICBldmVudC5jaGFyLmJvcmRlckNvbG9yID0gdGhpcy5zZWxlY3Rpb25Db2xvcjtcclxuICAgICAgdGhpcy5jaGFyUGljay5lbWl0KGV2ZW50KTtcclxuICAgICAgdGhpcy5yYW5nZVBpY2suZW1pdCh7IGF0OiBldmVudC5jaGFyLmlkLCBydW46IDEgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fbGFzdFNlbGVjdGVkQ2hhciA9IGV2ZW50LmNoYXI7XHJcbiAgfVxyXG59XHJcbiIsIjxkaXYgaWQ9XCJ0ZXh0XCI+XHJcbiAgQGZvciAobGluZSBvZiBsaW5lczsgdHJhY2sgbGluZSkge1xyXG4gIDxkaXYgY2xhc3M9XCJsaW5lXCI+XHJcbiAgICBAaWYgKGhhc0xpbmVOdW1iZXIpIHtcclxuICAgIDxkaXYgY2xhc3M9XCJuclwiPlxyXG4gICAgICB7eyBsaW5lcy5pbmRleE9mKGxpbmUpICsgMSB9fVxyXG4gICAgPC9kaXY+XHJcbiAgICB9IEBmb3IgKGMgb2YgbGluZTsgdHJhY2sgYy5pZCkge1xyXG4gICAgPGd2ZS1iYXNlLXRleHQtY2hhciBbY2hhcl09XCJjXCIgKGNoYXJQaWNrKT1cIm9uQ2hhclBpY2soJGV2ZW50KVwiIC8+XHJcbiAgICB9XHJcbiAgPC9kaXY+XHJcbiAgfVxyXG48L2Rpdj5cclxuIl19