@flogeez/angular-tiptap-editor 2.3.0 → 2.4.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 (105) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +132 -93
  3. package/esm2022/flogeez-angular-tiptap-editor.mjs +5 -0
  4. package/esm2022/lib/ate-editor.provider.mjs +38 -0
  5. package/esm2022/lib/components/bubble-menus/base/ate-base-bubble-menu.mjs +207 -0
  6. package/esm2022/lib/components/bubble-menus/base/ate-base-sub-bubble-menu.mjs +133 -0
  7. package/esm2022/lib/components/bubble-menus/color/ate-color-bubble-menu.component.mjs +365 -0
  8. package/esm2022/lib/components/bubble-menus/image/ate-image-bubble-menu.component.mjs +226 -0
  9. package/esm2022/lib/components/bubble-menus/link/ate-link-bubble-menu.component.mjs +247 -0
  10. package/esm2022/lib/components/bubble-menus/table/ate-cell-bubble-menu.component.mjs +121 -0
  11. package/esm2022/lib/components/bubble-menus/table/ate-table-bubble-menu.component.mjs +266 -0
  12. package/esm2022/lib/components/bubble-menus/text/ate-bubble-menu.component.mjs +294 -0
  13. package/esm2022/lib/components/color-picker/ate-color-picker.component.mjs +122 -0
  14. package/esm2022/lib/components/edit-toggle/ate-edit-toggle.component.mjs +42 -0
  15. package/esm2022/lib/components/editor/angular-tiptap-editor.component.mjs +953 -0
  16. package/esm2022/lib/components/slash-commands/ate-slash-commands.component.mjs +329 -0
  17. package/esm2022/lib/components/toolbar/ate-toolbar.component.mjs +531 -0
  18. package/esm2022/lib/components/ui/ate-button.component.mjs +90 -0
  19. package/esm2022/lib/components/ui/ate-separator.component.mjs +31 -0
  20. package/esm2022/lib/config/ate-editor.config.mjs +76 -0
  21. package/esm2022/lib/config/ate-global-config.token.mjs +6 -0
  22. package/esm2022/lib/config/ate-slash-commands.config.mjs +130 -0
  23. package/esm2022/lib/directives/ate-noop-value-accessor.directive.mjs +40 -0
  24. package/esm2022/lib/extensions/ate-link-click-behavior.extension.mjs +32 -0
  25. package/esm2022/lib/extensions/ate-resizable-image.extension.mjs +270 -0
  26. package/esm2022/lib/extensions/ate-table.extension.mjs +29 -0
  27. package/esm2022/lib/extensions/ate-tiptap-state.extension.mjs +85 -0
  28. package/esm2022/lib/extensions/ate-upload-progress.extension.mjs +195 -0
  29. package/esm2022/lib/extensions/calculators/ate-discovery.calculator.mjs +62 -0
  30. package/esm2022/lib/extensions/calculators/ate-image.calculator.mjs +8 -0
  31. package/esm2022/lib/extensions/calculators/ate-marks.calculator.mjs +75 -0
  32. package/esm2022/lib/extensions/calculators/ate-selection.calculator.mjs +35 -0
  33. package/esm2022/lib/extensions/calculators/ate-structure.calculator.mjs +34 -0
  34. package/esm2022/lib/extensions/calculators/ate-table.calculator.mjs +38 -0
  35. package/esm2022/lib/models/ate-bubble-menu.model.mjs +49 -0
  36. package/esm2022/lib/models/ate-editor-config.model.mjs +2 -0
  37. package/esm2022/lib/models/ate-editor-state.model.mjs +90 -0
  38. package/esm2022/lib/models/ate-image.model.mjs +2 -0
  39. package/esm2022/lib/models/ate-toolbar.model.mjs +35 -0
  40. package/esm2022/lib/node-view/ate-angular-node-view.mjs +97 -0
  41. package/esm2022/lib/node-view/ate-injector.registry.mjs +16 -0
  42. package/esm2022/lib/node-view/ate-node-view.factory.mjs +125 -0
  43. package/esm2022/lib/node-view/ate-node-view.models.mjs +2 -0
  44. package/esm2022/lib/node-view/ate-node-view.renderer.mjs +154 -0
  45. package/esm2022/lib/node-view/ate-register-angular-component.mjs +49 -0
  46. package/esm2022/lib/services/ate-color-picker.service.mjs +193 -0
  47. package/esm2022/lib/services/ate-editor-commands.service.mjs +465 -0
  48. package/esm2022/lib/services/ate-i18n.service.mjs +410 -0
  49. package/esm2022/lib/services/ate-image.service.mjs +368 -0
  50. package/esm2022/lib/services/ate-link.service.mjs +97 -0
  51. package/esm2022/lib/utils/ate-color.utils.mjs +60 -0
  52. package/esm2022/public-api.mjs +93 -0
  53. package/fesm2022/flogeez-angular-tiptap-editor.mjs +1178 -1100
  54. package/fesm2022/flogeez-angular-tiptap-editor.mjs.map +1 -1
  55. package/index.d.ts +3 -1562
  56. package/lib/ate-editor.provider.d.ts +21 -0
  57. package/lib/components/bubble-menus/base/ate-base-bubble-menu.d.ts +71 -0
  58. package/lib/components/bubble-menus/base/ate-base-sub-bubble-menu.d.ts +60 -0
  59. package/lib/components/bubble-menus/color/ate-color-bubble-menu.component.d.ts +77 -0
  60. package/lib/components/bubble-menus/image/ate-image-bubble-menu.component.d.ts +52 -0
  61. package/lib/components/bubble-menus/link/ate-link-bubble-menu.component.d.ts +55 -0
  62. package/lib/components/bubble-menus/table/ate-cell-bubble-menu.component.d.ts +12 -0
  63. package/lib/components/bubble-menus/table/ate-table-bubble-menu.component.d.ts +24 -0
  64. package/lib/components/bubble-menus/text/ate-bubble-menu.component.d.ts +53 -0
  65. package/lib/components/color-picker/ate-color-picker.component.d.ts +54 -0
  66. package/lib/components/edit-toggle/ate-edit-toggle.component.d.ts +13 -0
  67. package/lib/components/editor/angular-tiptap-editor.component.d.ts +235 -0
  68. package/lib/components/slash-commands/ate-slash-commands.component.d.ts +43 -0
  69. package/lib/components/toolbar/ate-toolbar.component.d.ts +47 -0
  70. package/lib/components/ui/ate-button.component.d.ts +25 -0
  71. package/lib/components/ui/ate-separator.component.d.ts +7 -0
  72. package/lib/config/ate-editor.config.d.ts +7 -0
  73. package/lib/config/ate-global-config.token.d.ts +6 -0
  74. package/lib/config/ate-slash-commands.config.d.ts +41 -0
  75. package/lib/directives/ate-noop-value-accessor.directive.d.ts +13 -0
  76. package/lib/extensions/ate-link-click-behavior.extension.d.ts +2 -0
  77. package/lib/extensions/ate-resizable-image.extension.d.ts +27 -0
  78. package/lib/extensions/ate-table.extension.d.ts +2 -0
  79. package/lib/extensions/ate-tiptap-state.extension.d.ts +7 -0
  80. package/lib/extensions/ate-upload-progress.extension.d.ts +7 -0
  81. package/lib/extensions/calculators/ate-discovery.calculator.d.ts +7 -0
  82. package/lib/extensions/calculators/ate-image.calculator.d.ts +2 -0
  83. package/lib/extensions/calculators/ate-marks.calculator.d.ts +2 -0
  84. package/lib/extensions/calculators/ate-selection.calculator.d.ts +2 -0
  85. package/lib/extensions/calculators/ate-structure.calculator.d.ts +2 -0
  86. package/lib/extensions/calculators/ate-table.calculator.d.ts +2 -0
  87. package/lib/models/ate-bubble-menu.model.d.ts +33 -0
  88. package/lib/models/ate-editor-config.model.d.ts +100 -0
  89. package/lib/models/ate-editor-state.model.d.ts +109 -0
  90. package/lib/models/ate-image.model.d.ts +104 -0
  91. package/lib/models/ate-toolbar.model.d.ts +18 -0
  92. package/lib/node-view/ate-angular-node-view.d.ts +115 -0
  93. package/lib/node-view/ate-injector.registry.d.ts +3 -0
  94. package/lib/node-view/ate-node-view.factory.d.ts +10 -0
  95. package/lib/node-view/ate-node-view.models.d.ts +138 -0
  96. package/lib/node-view/ate-node-view.renderer.d.ts +23 -0
  97. package/lib/node-view/ate-register-angular-component.d.ts +35 -0
  98. package/lib/services/ate-color-picker.service.d.ts +65 -0
  99. package/lib/services/ate-editor-commands.service.d.ts +72 -0
  100. package/lib/services/ate-i18n.service.d.ts +394 -0
  101. package/lib/services/ate-image.service.d.ts +71 -0
  102. package/lib/services/ate-link.service.d.ts +42 -0
  103. package/lib/utils/ate-color.utils.d.ts +12 -0
  104. package/package.json +3 -1
  105. package/public-api.d.ts +112 -0
@@ -0,0 +1,368 @@
1
+ import { Injectable, signal, computed, inject } from "@angular/core";
2
+ import { isObservable, firstValueFrom } from "rxjs";
3
+ import { AteI18nService } from "./ate-i18n.service";
4
+ import * as i0 from "@angular/core";
5
+ export class AteImageService {
6
+ constructor() {
7
+ /** Signals for image state */
8
+ this.selectedImage = signal(null);
9
+ this.isImageSelected = computed(() => this.selectedImage() !== null);
10
+ /** Resizing state */
11
+ this.isResizing = signal(false);
12
+ this.i18n = inject(AteI18nService);
13
+ this.t = this.i18n.imageUpload;
14
+ /** Upload state signals */
15
+ this.isUploading = signal(false);
16
+ this.uploadProgress = signal(0);
17
+ this.uploadMessage = signal("");
18
+ /**
19
+ * Custom upload handler.
20
+ * If set, this handler replaces the default base64 conversion.
21
+ */
22
+ this.uploadHandler = null;
23
+ this.currentEditor = null;
24
+ }
25
+ /** Select and track an image from the editor */
26
+ selectImage(editor) {
27
+ if (editor.isActive("resizableImage")) {
28
+ const attrs = editor.getAttributes("resizableImage");
29
+ this.selectedImage.set({
30
+ src: attrs["src"],
31
+ alt: attrs["alt"],
32
+ title: attrs["title"],
33
+ width: attrs["width"],
34
+ height: attrs["height"],
35
+ });
36
+ }
37
+ else {
38
+ this.selectedImage.set(null);
39
+ }
40
+ }
41
+ clearSelection() {
42
+ this.selectedImage.set(null);
43
+ }
44
+ /** Insert a new image and ensure it's selected */
45
+ insertImage(editor, imageData) {
46
+ const { from } = editor.state.selection;
47
+ editor.chain().focus().setResizableImage(imageData).setNodeSelection(from).run();
48
+ }
49
+ /** Update attributes of the currently active image */
50
+ updateImageAttributes(editor, attributes) {
51
+ if (editor.isActive("resizableImage")) {
52
+ const pos = editor.state.selection.from;
53
+ editor
54
+ .chain()
55
+ .focus()
56
+ .updateAttributes("resizableImage", attributes)
57
+ .setNodeSelection(pos)
58
+ .run();
59
+ this.updateSelectedImage(attributes);
60
+ }
61
+ }
62
+ /** Resize image with optional aspect ratio maintenance */
63
+ resizeImage(editor, options) {
64
+ if (!editor.isActive("resizableImage")) {
65
+ return;
66
+ }
67
+ const currentAttrs = editor.getAttributes("resizableImage");
68
+ let newWidth = options.width;
69
+ let newHeight = options.height;
70
+ // Maintain aspect ratio if requested
71
+ if (options.maintainAspectRatio !== false && currentAttrs["width"] && currentAttrs["height"]) {
72
+ const aspectRatio = currentAttrs["width"] / currentAttrs["height"];
73
+ if (newWidth && !newHeight) {
74
+ newHeight = Math.round(newWidth / aspectRatio);
75
+ }
76
+ else if (newHeight && !newWidth) {
77
+ newWidth = Math.round(newHeight * aspectRatio);
78
+ }
79
+ }
80
+ // Apply minimum limits
81
+ if (newWidth) {
82
+ newWidth = Math.max(50, newWidth);
83
+ }
84
+ if (newHeight) {
85
+ newHeight = Math.max(50, newHeight);
86
+ }
87
+ this.updateImageAttributes(editor, {
88
+ width: newWidth,
89
+ height: newHeight,
90
+ });
91
+ }
92
+ /** Predetermined resize helpers used by UI */
93
+ resizeImageToSmall(editor) {
94
+ this.resizeImage(editor, { width: 300, height: 200, maintainAspectRatio: true });
95
+ }
96
+ resizeImageToMedium(editor) {
97
+ this.resizeImage(editor, { width: 500, height: 350, maintainAspectRatio: true });
98
+ }
99
+ resizeImageToLarge(editor) {
100
+ this.resizeImage(editor, { width: 800, height: 600, maintainAspectRatio: true });
101
+ }
102
+ resizeImageToOriginal(editor) {
103
+ if (!editor.isActive("resizableImage")) {
104
+ return;
105
+ }
106
+ const img = new Image();
107
+ img.onload = () => {
108
+ this.resizeImage(editor, { width: img.naturalWidth, height: img.naturalHeight });
109
+ };
110
+ img.src = editor.getAttributes("resizableImage")["src"];
111
+ }
112
+ /** Get current image dimensions */
113
+ getImageDimensions(editor) {
114
+ if (!editor.isActive("resizableImage")) {
115
+ return null;
116
+ }
117
+ const attrs = editor.getAttributes("resizableImage");
118
+ return {
119
+ width: attrs["width"] || 0,
120
+ height: attrs["height"] || 0,
121
+ };
122
+ }
123
+ /** Remove the selected image */
124
+ deleteImage(editor) {
125
+ if (editor.isActive("resizableImage")) {
126
+ editor.chain().focus().deleteSelection().run();
127
+ this.clearSelection();
128
+ }
129
+ }
130
+ updateSelectedImage(attributes) {
131
+ const current = this.selectedImage();
132
+ if (current) {
133
+ this.selectedImage.set({ ...current, ...attributes });
134
+ }
135
+ }
136
+ /** Validate file type and size */
137
+ validateImage(file, options) {
138
+ const maxSize = options?.maxSize || 10 * 1024 * 1024;
139
+ const allowedTypes = options?.allowedTypes || [];
140
+ if (allowedTypes.length > 0 && !allowedTypes.includes(file.type)) {
141
+ return { valid: false, error: this.t().invalidFileType };
142
+ }
143
+ if (file.size > maxSize) {
144
+ return {
145
+ valid: false,
146
+ error: `${this.t().imageTooLarge} (max ${Math.round(maxSize / 1024 / 1024)}MB)`,
147
+ };
148
+ }
149
+ return { valid: true };
150
+ }
151
+ /** Compress and process image on client side */
152
+ async compressImage(file, quality = 0.8, maxWidth = 1920, maxHeight = 1200) {
153
+ return new Promise((resolve, reject) => {
154
+ const canvas = document.createElement("canvas");
155
+ const ctx = canvas.getContext("2d");
156
+ const img = new Image();
157
+ img.onload = () => {
158
+ if (this.isUploading()) {
159
+ this.uploadProgress.set(40);
160
+ this.uploadMessage.set(this.t().resizing);
161
+ }
162
+ let { width, height } = img;
163
+ if (width > maxWidth || height > maxHeight) {
164
+ const ratio = Math.min(maxWidth / width, maxHeight / height);
165
+ width *= ratio;
166
+ height *= ratio;
167
+ }
168
+ canvas.width = width;
169
+ canvas.height = height;
170
+ ctx?.drawImage(img, 0, 0, width, height);
171
+ if (this.isUploading()) {
172
+ this.uploadProgress.set(60);
173
+ this.uploadMessage.set(this.t().compressing);
174
+ }
175
+ canvas.toBlob(blob => {
176
+ if (blob) {
177
+ const reader = new FileReader();
178
+ reader.onload = e => {
179
+ const base64 = e.target?.result;
180
+ resolve({
181
+ src: base64,
182
+ name: file.name,
183
+ size: blob.size,
184
+ type: file.type,
185
+ width: Math.round(width),
186
+ height: Math.round(height),
187
+ originalSize: file.size,
188
+ });
189
+ };
190
+ reader.readAsDataURL(blob);
191
+ }
192
+ else {
193
+ reject(new Error(this.t().compressionError));
194
+ }
195
+ }, file.type, quality);
196
+ };
197
+ img.onerror = () => reject(new Error(this.t().loadError));
198
+ img.src = URL.createObjectURL(file);
199
+ });
200
+ }
201
+ /** Core upload logic with progress tracking */
202
+ async uploadImageWithProgress(editor, file, insertionStrategy, actionMessage, options) {
203
+ try {
204
+ this.currentEditor = editor;
205
+ this.isUploading.set(true);
206
+ this.uploadProgress.set(10);
207
+ this.uploadMessage.set(this.t().validating);
208
+ this.forceEditorUpdate();
209
+ const validation = this.validateImage(file, {
210
+ maxSize: options?.maxSize,
211
+ allowedTypes: options?.allowedTypes,
212
+ });
213
+ if (!validation.valid) {
214
+ throw new Error(validation.error);
215
+ }
216
+ this.uploadProgress.set(30);
217
+ this.uploadMessage.set(this.t().compressing);
218
+ this.forceEditorUpdate();
219
+ const result = await this.compressImage(file, options?.quality || 0.8, options?.maxWidth || 1920, options?.maxHeight || 1200);
220
+ this.uploadProgress.set(70);
221
+ // Handle custom upload if handler is provided
222
+ if (this.uploadHandler) {
223
+ this.uploadMessage.set(this.t().uploadingToServer);
224
+ this.forceEditorUpdate();
225
+ try {
226
+ const handlerResponse = this.uploadHandler({
227
+ file,
228
+ width: result.width || 0,
229
+ height: result.height || 0,
230
+ type: result.type,
231
+ base64: result.src,
232
+ });
233
+ const handlerResult = isObservable(handlerResponse)
234
+ ? await firstValueFrom(handlerResponse)
235
+ : await handlerResponse;
236
+ result.src = handlerResult.src;
237
+ if (handlerResult.alt) {
238
+ result.name = handlerResult.alt;
239
+ }
240
+ }
241
+ catch (handlerError) {
242
+ console.error(this.t().uploadError, handlerError);
243
+ throw handlerError;
244
+ }
245
+ }
246
+ this.uploadProgress.set(90);
247
+ this.uploadMessage.set(actionMessage);
248
+ this.forceEditorUpdate();
249
+ // Final insertion
250
+ insertionStrategy(editor, result);
251
+ this.resetUploadState();
252
+ }
253
+ catch (error) {
254
+ this.resetUploadState();
255
+ console.error(this.t().uploadError, error);
256
+ throw error;
257
+ }
258
+ }
259
+ resetUploadState() {
260
+ this.isUploading.set(false);
261
+ this.uploadProgress.set(0);
262
+ this.uploadMessage.set("");
263
+ this.forceEditorUpdate();
264
+ this.currentEditor = null;
265
+ }
266
+ /** Main entry point for file upload and insertion */
267
+ async uploadAndInsertImage(editor, file, options) {
268
+ return this.uploadImageWithProgress(editor, file, (ed, result) => {
269
+ this.insertImage(ed, {
270
+ src: result.src,
271
+ alt: result.name,
272
+ title: `${result.name} (${result.width}×${result.height})`,
273
+ width: result.width,
274
+ height: result.height,
275
+ });
276
+ }, this.t().insertingImage, options);
277
+ }
278
+ /** Trigger an editor transaction to force decoration update */
279
+ forceEditorUpdate() {
280
+ if (this.currentEditor) {
281
+ const { tr } = this.currentEditor.state;
282
+ this.currentEditor.view.dispatch(tr);
283
+ }
284
+ }
285
+ /** Generic helper to open file picker and process selection */
286
+ async selectFileAndProcess(editor, uploadMethod, options) {
287
+ return new Promise((resolve, reject) => {
288
+ const input = document.createElement("input");
289
+ input.type = "file";
290
+ // Use allowedTypes if provided, otherwise default to image/*
291
+ if (options?.allowedTypes && options.allowedTypes.length > 0) {
292
+ input.accept = options.allowedTypes.join(",");
293
+ }
294
+ else {
295
+ input.accept = "image/*";
296
+ }
297
+ input.style.display = "none";
298
+ input.addEventListener("change", async (e) => {
299
+ const file = e.target.files?.[0];
300
+ if (file && file.type.startsWith("image/")) {
301
+ try {
302
+ await uploadMethod(editor, file, options);
303
+ resolve();
304
+ }
305
+ catch (error) {
306
+ reject(error);
307
+ }
308
+ }
309
+ else {
310
+ reject(new Error(this.t().noFileSelected));
311
+ }
312
+ document.body.removeChild(input);
313
+ });
314
+ input.addEventListener("cancel", () => {
315
+ document.body.removeChild(input);
316
+ reject(new Error(this.t().selectionCancelled));
317
+ });
318
+ document.body.appendChild(input);
319
+ input.click();
320
+ });
321
+ }
322
+ /** Select file and upload as new image */
323
+ async selectAndUploadImage(editor, options) {
324
+ return this.selectFileAndProcess(editor, this.uploadAndInsertImage.bind(this), options);
325
+ }
326
+ /** Select file and replace currently selected image */
327
+ async selectAndReplaceImage(editor, options) {
328
+ // No need for complicated backup/restore now that we don't delete prematurely.
329
+ // The uploadAndReplaceImage will handle the atomic replacement.
330
+ return this.selectFileAndProcess(editor, this.uploadAndReplaceImage.bind(this), options);
331
+ }
332
+ /** Internal helper used by replacement logic */
333
+ async uploadAndReplaceImage(editor, file, options) {
334
+ // Store current position to ensure we can re-select the image even if selection blurs during upload
335
+ const pos = editor.state.selection.from;
336
+ const wasActive = editor.isActive("resizableImage");
337
+ await this.uploadImageWithProgress(editor, file, (ed, result) => {
338
+ const imageData = {
339
+ src: result.src,
340
+ alt: result.name,
341
+ title: `${result.name} (${result.width}×${result.height})`,
342
+ width: result.width,
343
+ height: result.height,
344
+ };
345
+ // If the image was active or is still active, update it atomically
346
+ if (wasActive || ed.isActive("resizableImage")) {
347
+ ed.chain()
348
+ .focus()
349
+ .updateAttributes("resizableImage", imageData)
350
+ .setNodeSelection(pos)
351
+ .run();
352
+ this.updateSelectedImage(imageData);
353
+ }
354
+ else {
355
+ // Otherwise replace whatever is selected (or insert at cursor)
356
+ this.insertImage(ed, imageData);
357
+ }
358
+ // After replacement, ensure the image is tracked in our signals
359
+ this.selectImage(ed);
360
+ }, this.t().replacingImage, options);
361
+ }
362
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
363
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageService }); }
364
+ }
365
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteImageService, decorators: [{
366
+ type: Injectable
367
+ }] });
368
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXRlLWltYWdlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9hbmd1bGFyLXRpcHRhcC1lZGl0b3Ivc3JjL2xpYi9zZXJ2aWNlcy9hdGUtaW1hZ2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXJFLE9BQU8sRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQzs7QUFVcEQsTUFBTSxPQUFPLGVBQWU7SUFENUI7UUFFRSw4QkFBOEI7UUFDOUIsa0JBQWEsR0FBRyxNQUFNLENBQXNCLElBQUksQ0FBQyxDQUFDO1FBQ2xELG9CQUFlLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUVoRSxxQkFBcUI7UUFDckIsZUFBVSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVuQixTQUFJLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ3JCLE1BQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQztRQUUzQywyQkFBMkI7UUFDM0IsZ0JBQVcsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUIsbUJBQWMsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDM0Isa0JBQWEsR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFM0I7OztXQUdHO1FBQ0gsa0JBQWEsR0FBaUMsSUFBSSxDQUFDO1FBRTNDLGtCQUFhLEdBQWtCLElBQUksQ0FBQztLQThhN0M7SUE1YUMsZ0RBQWdEO0lBQ2hELFdBQVcsQ0FBQyxNQUFjO1FB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QUFTLElBQUksRUFBRSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLENBQUM7Z0JBQy9DLEVBQUUsQ0FBQyxLQUFLLEVBQUU7cUJBQ1AsS0FBSyxFQUFFO3FCQUNQLGdCQUFnQixDQUFDLGdCQUFnQixFQUFFLFNBQVMsQ0FBQztxQkFDN0MsZ0JBQWdCLENBQUMsR0FBRyxDQUFDO3FCQUNyQixHQUFHLEVBQUUsQ0FBQztnQkFDVCxJQUFJLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDdEMsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLCtEQUErRDtnQkFDL0QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxFQUFFLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDbEMsQ0FBQztZQUVELGdFQUFnRTtZQUNoRSxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZCLENBQUMsRUFDRCxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsY0FBYyxFQUN2QixPQUFPLENBQ1IsQ0FBQztJQUNKLENBQUM7K0dBbmNVLGVBQWU7bUhBQWYsZUFBZTs7NEZBQWYsZUFBZTtrQkFEM0IsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIHNpZ25hbCwgY29tcHV0ZWQsIGluamVjdCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgeyBFZGl0b3IgfSBmcm9tIFwiQHRpcHRhcC9jb3JlXCI7XG5pbXBvcnQgeyBpc09ic2VydmFibGUsIGZpcnN0VmFsdWVGcm9tIH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IEF0ZUkxOG5TZXJ2aWNlIH0gZnJvbSBcIi4vYXRlLWkxOG4uc2VydmljZVwiO1xuaW1wb3J0IHtcbiAgQXRlUmVzaXplT3B0aW9ucyxcbiAgQXRlSW1hZ2VVcGxvYWRPcHRpb25zLFxuICBBdGVJbWFnZVVwbG9hZEhhbmRsZXIsXG4gIEF0ZUltYWdlVXBsb2FkUmVzdWx0LFxuICBBdGVJbWFnZURhdGEsXG59IGZyb20gXCIuLi9tb2RlbHMvYXRlLWltYWdlLm1vZGVsXCI7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBBdGVJbWFnZVNlcnZpY2Uge1xuICAvKiogU2lnbmFscyBmb3IgaW1hZ2Ugc3RhdGUgKi9cbiAgc2VsZWN0ZWRJbWFnZSA9IHNpZ25hbDxBdGVJbWFnZURhdGEgfCBudWxsPihudWxsKTtcbiAgaXNJbWFnZVNlbGVjdGVkID0gY29tcHV0ZWQoKCkgPT4gdGhpcy5zZWxlY3RlZEltYWdlKCkgIT09IG51bGwpO1xuXG4gIC8qKiBSZXNpemluZyBzdGF0ZSAqL1xuICBpc1Jlc2l6aW5nID0gc2lnbmFsKGZhbHNlKTtcblxuICBwcml2YXRlIGkxOG4gPSBpbmplY3QoQXRlSTE4blNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IHQgPSB0aGlzLmkxOG4uaW1hZ2VVcGxvYWQ7XG5cbiAgLyoqIFVwbG9hZCBzdGF0ZSBzaWduYWxzICovXG4gIGlzVXBsb2FkaW5nID0gc2lnbmFsKGZhbHNlKTtcbiAgdXBsb2FkUHJvZ3Jlc3MgPSBzaWduYWwoMCk7XG4gIHVwbG9hZE1lc3NhZ2UgPSBzaWduYWwoXCJcIik7XG5cbiAgLyoqXG4gICAqIEN1c3RvbSB1cGxvYWQgaGFuZGxlci5cbiAgICogSWYgc2V0LCB0aGlzIGhhbmRsZXIgcmVwbGFjZXMgdGhlIGRlZmF1bHQgYmFzZTY0IGNvbnZlcnNpb24uXG4gICAqL1xuICB1cGxvYWRIYW5kbGVyOiBBdGVJbWFnZVVwbG9hZEhhbmRsZXIgfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIGN1cnJlbnRFZGl0b3I6IEVkaXRvciB8IG51bGwgPSBudWxsO1xuXG4gIC8qKiBTZWxlY3QgYW5kIHRyYWNrIGFuIGltYWdlIGZyb20gdGhlIGVkaXRvciAqL1xuICBzZWxlY3RJbWFnZShlZGl0b3I6IEVkaXRvcik6IHZvaWQge1xuICAgIGlmIChlZGl0b3IuaXNBY3RpdmUoXCJyZXNpemFibGVJbWFnZVwiKSkge1xuICAgICAgY29uc3QgYXR0cnMgPSBlZGl0b3IuZ2V0QXR0cmlidXRlcyhcInJlc2l6YWJsZUltYWdlXCIpO1xuICAgICAgdGhpcy5zZWxlY3RlZEltYWdlLnNldCh7XG4gICAgICAgIHNyYzogYXR0cnNbXCJzcmNcIl0sXG4gICAgICAgIGFsdDogYXR0cnNbXCJhbHRcIl0sXG4gICAgICAgIHRpdGxlOiBhdHRyc1tcInRpdGxlXCJdLFxuICAgICAgICB3aWR0aDogYXR0cnNbXCJ3aWR0aFwiXSxcbiAgICAgICAgaGVpZ2h0OiBhdHRyc1tcImhlaWdodFwiXSxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNlbGVjdGVkSW1hZ2Uuc2V0KG51bGwpO1xuICAgIH1cbiAgfVxuXG4gIGNsZWFyU2VsZWN0aW9uKCk6IHZvaWQge1xuICAgIHRoaXMuc2VsZWN0ZWRJbWFnZS5zZXQobnVsbCk7XG4gIH1cblxuICAvKiogSW5zZXJ0IGEgbmV3IGltYWdlIGFuZCBlbnN1cmUgaXQncyBzZWxlY3RlZCAqL1xuICBpbnNlcnRJbWFnZShlZGl0b3I6IEVkaXRvciwgaW1hZ2VEYXRhOiBBdGVJbWFnZURhdGEpOiB2b2lkIHtcbiAgICBjb25zdCB7IGZyb20gfSA9IGVkaXRvci5zdGF0ZS5zZWxlY3Rpb247XG4gICAgZWRpdG9yLmNoYWluKCkuZm9jdXMoKS5zZXRSZXNpemFibGVJbWFnZShpbWFnZURhdGEpLnNldE5vZGVTZWxlY3Rpb24oZnJvbSkucnVuKCk7XG4gIH1cblxuICAvKiogVXBkYXRlIGF0dHJpYnV0ZXMgb2YgdGhlIGN1cnJlbnRseSBhY3RpdmUgaW1hZ2UgKi9cbiAgdXBkYXRlSW1hZ2VBdHRyaWJ1dGVzKGVkaXRvcjogRWRpdG9yLCBhdHRyaWJ1dGVzOiBQYXJ0aWFsPEF0ZUltYWdlRGF0YT4pOiB2b2lkIHtcbiAgICBpZiAoZWRpdG9yLmlzQWN0aXZlKFwicmVzaXphYmxlSW1hZ2VcIikpIHtcbiAgICAgIGNvbnN0IHBvcyA9IGVkaXRvci5zdGF0ZS5zZWxlY3Rpb24uZnJvbTtcbiAgICAgIGVkaXRvclxuICAgICAgICAuY2hhaW4oKVxuICAgICAgICAuZm9jdXMoKVxuICAgICAgICAudXBkYXRlQXR0cmlidXRlcyhcInJlc2l6YWJsZUltYWdlXCIsIGF0dHJpYnV0ZXMpXG4gICAgICAgIC5zZXROb2RlU2VsZWN0aW9uKHBvcylcbiAgICAgICAgLnJ1bigpO1xuICAgICAgdGhpcy51cGRhdGVTZWxlY3RlZEltYWdlKGF0dHJpYnV0ZXMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSZXNpemUgaW1hZ2Ugd2l0aCBvcHRpb25hbCBhc3BlY3QgcmF0aW8gbWFpbnRlbmFuY2UgKi9cbiAgcmVzaXplSW1hZ2UoZWRpdG9yOiBFZGl0b3IsIG9wdGlvbnM6IEF0ZVJlc2l6ZU9wdGlvbnMpOiB2b2lkIHtcbiAgICBpZiAoIWVkaXRvci5pc0FjdGl2ZShcInJlc2l6YWJsZUltYWdlXCIpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY3VycmVudEF0dHJzID0gZWRpdG9yLmdldEF0dHJpYnV0ZXMoXCJyZXNpemFibGVJbWFnZVwiKTtcbiAgICBsZXQgbmV3V2lkdGggPSBvcHRpb25zLndpZHRoO1xuICAgIGxldCBuZXdIZWlnaHQgPSBvcHRpb25zLmhlaWdodDtcblxuICAgIC8vIE1haW50YWluIGFzcGVjdCByYXRpbyBpZiByZXF1ZXN0ZWRcbiAgICBpZiAob3B0aW9ucy5tYWludGFpbkFzcGVjdFJhdGlvICE9PSBmYWxzZSAmJiBjdXJyZW50QXR0cnNbXCJ3aWR0aFwiXSAmJiBjdXJyZW50QXR0cnNbXCJoZWlnaHRcIl0pIHtcbiAgICAgIGNvbnN0IGFzcGVjdFJhdGlvID0gY3VycmVudEF0dHJzW1wid2lkdGhcIl0gLyBjdXJyZW50QXR0cnNbXCJoZWlnaHRcIl07XG5cbiAgICAgIGlmIChuZXdXaWR0aCAmJiAhbmV3SGVpZ2h0KSB7XG4gICAgICAgIG5ld0hlaWdodCA9IE1hdGgucm91bmQobmV3V2lkdGggLyBhc3BlY3RSYXRpbyk7XG4gICAgICB9IGVsc2UgaWYgKG5ld0hlaWdodCAmJiAhbmV3V2lkdGgpIHtcbiAgICAgICAgbmV3V2lkdGggPSBNYXRoLnJvdW5kKG5ld0hlaWdodCAqIGFzcGVjdFJhdGlvKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBcHBseSBtaW5pbXVtIGxpbWl0c1xuICAgIGlmIChuZXdXaWR0aCkge1xuICAgICAgbmV3V2lkdGggPSBNYXRoLm1heCg1MCwgbmV3V2lkdGgpO1xuICAgIH1cbiAgICBpZiAobmV3SGVpZ2h0KSB7XG4gICAgICBuZXdIZWlnaHQgPSBNYXRoLm1heCg1MCwgbmV3SGVpZ2h0KTtcbiAgICB9XG5cbiAgICB0aGlzLnVwZGF0ZUltYWdlQXR0cmlidXRlcyhlZGl0b3IsIHtcbiAgICAgIHdpZHRoOiBuZXdXaWR0aCxcbiAgICAgIGhlaWdodDogbmV3SGVpZ2h0LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqIFByZWRldGVybWluZWQgcmVzaXplIGhlbHBlcnMgdXNlZCBieSBVSSAqL1xuICByZXNpemVJbWFnZVRvU21hbGwoZWRpdG9yOiBFZGl0b3IpOiB2b2lkIHtcbiAgICB0aGlzLnJlc2l6ZUltYWdlKGVkaXRvciwgeyB3aWR0aDogMzAwLCBoZWlnaHQ6IDIwMCwgbWFpbnRhaW5Bc3BlY3RSYXRpbzogdHJ1ZSB9KTtcbiAgfVxuXG4gIHJlc2l6ZUltYWdlVG9NZWRpdW0oZWRpdG9yOiBFZGl0b3IpOiB2b2lkIHtcbiAgICB0aGlzLnJlc2l6ZUltYWdlKGVkaXRvciwgeyB3aWR0aDogNTAwLCBoZWlnaHQ6IDM1MCwgbWFpbnRhaW5Bc3BlY3RSYXRpbzogdHJ1ZSB9KTtcbiAgfVxuXG4gIHJlc2l6ZUltYWdlVG9MYXJnZShlZGl0b3I6IEVkaXRvcik6IHZvaWQge1xuICAgIHRoaXMucmVzaXplSW1hZ2UoZWRpdG9yLCB7IHdpZHRoOiA4MDAsIGhlaWdodDogNjAwLCBtYWludGFpbkFzcGVjdFJhdGlvOiB0cnVlIH0pO1xuICB9XG5cbiAgcmVzaXplSW1hZ2VUb09yaWdpbmFsKGVkaXRvcjogRWRpdG9yKTogdm9pZCB7XG4gICAgaWYgKCFlZGl0b3IuaXNBY3RpdmUoXCJyZXNpemFibGVJbWFnZVwiKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcbiAgICBpbWcub25sb2FkID0gKCkgPT4ge1xuICAgICAgdGhpcy5yZXNpemVJbWFnZShlZGl0b3IsIHsgd2lkdGg6IGltZy5uYXR1cmFsV2lkdGgsIGhlaWdodDogaW1nLm5hdHVyYWxIZWlnaHQgfSk7XG4gICAgfTtcbiAgICBpbWcuc3JjID0gZWRpdG9yLmdldEF0dHJpYnV0ZXMoXCJyZXNpemFibGVJbWFnZVwiKVtcInNyY1wiXTtcbiAgfVxuXG4gIC8qKiBHZXQgY3VycmVudCBpbWFnZSBkaW1lbnNpb25zICovXG4gIGdldEltYWdlRGltZW5zaW9ucyhlZGl0b3I6IEVkaXRvcik6IHsgd2lkdGg6IG51bWJlcjsgaGVpZ2h0OiBudW1iZXIgfSB8IG51bGwge1xuICAgIGlmICghZWRpdG9yLmlzQWN0aXZlKFwicmVzaXphYmxlSW1hZ2VcIikpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBjb25zdCBhdHRycyA9IGVkaXRvci5nZXRBdHRyaWJ1dGVzKFwicmVzaXphYmxlSW1hZ2VcIik7XG4gICAgcmV0dXJuIHtcbiAgICAgIHdpZHRoOiBhdHRyc1tcIndpZHRoXCJdIHx8IDAsXG4gICAgICBoZWlnaHQ6IGF0dHJzW1wiaGVpZ2h0XCJdIHx8IDAsXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBSZW1vdmUgdGhlIHNlbGVjdGVkIGltYWdlICovXG4gIGRlbGV0ZUltYWdlKGVkaXRvcjogRWRpdG9yKTogdm9pZCB7XG4gICAgaWYgKGVkaXRvci5pc0FjdGl2ZShcInJlc2l6YWJsZUltYWdlXCIpKSB7XG4gICAgICBlZGl0b3IuY2hhaW4oKS5mb2N1cygpLmRlbGV0ZVNlbGVjdGlvbigpLnJ1bigpO1xuICAgICAgdGhpcy5jbGVhclNlbGVjdGlvbigpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU2VsZWN0ZWRJbWFnZShhdHRyaWJ1dGVzOiBQYXJ0aWFsPEF0ZUltYWdlRGF0YT4pOiB2b2lkIHtcbiAgICBjb25zdCBjdXJyZW50ID0gdGhpcy5zZWxlY3RlZEltYWdlKCk7XG4gICAgaWYgKGN1cnJlbnQpIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWRJbWFnZS5zZXQoeyAuLi5jdXJyZW50LCAuLi5hdHRyaWJ1dGVzIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBWYWxpZGF0ZSBmaWxlIHR5cGUgYW5kIHNpemUgKi9cbiAgdmFsaWRhdGVJbWFnZShcbiAgICBmaWxlOiBGaWxlLFxuICAgIG9wdGlvbnM/OiB7IG1heFNpemU/OiBudW1iZXI7IGFsbG93ZWRUeXBlcz86IHN0cmluZ1tdIH1cbiAgKTogeyB2YWxpZDogYm9vbGVhbjsgZXJyb3I/OiBzdHJpbmcgfSB7XG4gICAgY29uc3QgbWF4U2l6ZSA9IG9wdGlvbnM/Lm1heFNpemUgfHwgMTAgKiAxMDI0ICogMTAyNDtcbiAgICBjb25zdCBhbGxvd2VkVHlwZXMgPSBvcHRpb25zPy5hbGxvd2VkVHlwZXMgfHwgW107XG5cbiAgICBpZiAoYWxsb3dlZFR5cGVzLmxlbmd0aCA+IDAgJiYgIWFsbG93ZWRUeXBlcy5pbmNsdWRlcyhmaWxlLnR5cGUpKSB7XG4gICAgICByZXR1cm4geyB2YWxpZDogZmFsc2UsIGVycm9yOiB0aGlzLnQoKS5pbnZhbGlkRmlsZVR5cGUgfTtcbiAgICB9XG5cbiAgICBpZiAoZmlsZS5zaXplID4gbWF4U2l6ZSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsaWQ6IGZhbHNlLFxuICAgICAgICBlcnJvcjogYCR7dGhpcy50KCkuaW1hZ2VUb29MYXJnZX0gKG1heCAke01hdGgucm91bmQobWF4U2l6ZSAvIDEwMjQgLyAxMDI0KX1NQilgLFxuICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIHsgdmFsaWQ6IHRydWUgfTtcbiAgfVxuXG4gIC8qKiBDb21wcmVzcyBhbmQgcHJvY2VzcyBpbWFnZSBvbiBjbGllbnQgc2lkZSAqL1xuICBhc3luYyBjb21wcmVzc0ltYWdlKFxuICAgIGZpbGU6IEZpbGUsXG4gICAgcXVhbGl0eSA9IDAuOCxcbiAgICBtYXhXaWR0aCA9IDE5MjAsXG4gICAgbWF4SGVpZ2h0ID0gMTIwMFxuICApOiBQcm9taXNlPEF0ZUltYWdlVXBsb2FkUmVzdWx0PiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJjYW52YXNcIik7XG4gICAgICBjb25zdCBjdHggPSBjYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpO1xuICAgICAgY29uc3QgaW1nID0gbmV3IEltYWdlKCk7XG5cbiAgICAgIGltZy5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmlzVXBsb2FkaW5nKCkpIHtcbiAgICAgICAgICB0aGlzLnVwbG9hZFByb2dyZXNzLnNldCg0MCk7XG4gICAgICAgICAgdGhpcy51cGxvYWRNZXNzYWdlLnNldCh0aGlzLnQoKS5yZXNpemluZyk7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgeyB3aWR0aCwgaGVpZ2h0IH0gPSBpbWc7XG4gICAgICAgIGlmICh3aWR0aCA+IG1heFdpZHRoIHx8IGhlaWdodCA+IG1heEhlaWdodCkge1xuICAgICAgICAgIGNvbnN0IHJhdGlvID0gTWF0aC5taW4obWF4V2lkdGggLyB3aWR0aCwgbWF4SGVpZ2h0IC8gaGVpZ2h0KTtcbiAgICAgICAgICB3aWR0aCAqPSByYXRpbztcbiAgICAgICAgICBoZWlnaHQgKj0gcmF0aW87XG4gICAgICAgIH1cblxuICAgICAgICBjYW52YXMud2lkdGggPSB3aWR0aDtcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDtcbiAgICAgICAgY3R4Py5kcmF3SW1hZ2UoaW1nLCAwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcblxuICAgICAgICBpZiAodGhpcy5pc1VwbG9hZGluZygpKSB7XG4gICAgICAgICAgdGhpcy51cGxvYWRQcm9ncmVzcy5zZXQoNjApO1xuICAgICAgICAgIHRoaXMudXBsb2FkTWVzc2FnZS5zZXQodGhpcy50KCkuY29tcHJlc3NpbmcpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FudmFzLnRvQmxvYihcbiAgICAgICAgICBibG9iID0+IHtcbiAgICAgICAgICAgIGlmIChibG9iKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XG4gICAgICAgICAgICAgIHJlYWRlci5vbmxvYWQgPSBlID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBiYXNlNjQgPSBlLnRhcmdldD8ucmVzdWx0IGFzIHN0cmluZztcbiAgICAgICAgICAgICAgICByZXNvbHZlKHtcbiAgICAgICAgICAgICAgICAgIHNyYzogYmFzZTY0LFxuICAgICAgICAgICAgICAgICAgbmFtZTogZmlsZS5uYW1lLFxuICAgICAgICAgICAgICAgICAgc2l6ZTogYmxvYi5zaXplLFxuICAgICAgICAgICAgICAgICAgdHlwZTogZmlsZS50eXBlLFxuICAgICAgICAgICAgICAgICAgd2lkdGg6IE1hdGgucm91bmQod2lkdGgpLFxuICAgICAgICAgICAgICAgICAgaGVpZ2h0OiBNYXRoLnJvdW5kKGhlaWdodCksXG4gICAgICAgICAgICAgICAgICBvcmlnaW5hbFNpemU6IGZpbGUuc2l6ZSxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgcmVhZGVyLnJlYWRBc0RhdGFVUkwoYmxvYik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICByZWplY3QobmV3IEVycm9yKHRoaXMudCgpLmNvbXByZXNzaW9uRXJyb3IpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIGZpbGUudHlwZSxcbiAgICAgICAgICBxdWFsaXR5XG4gICAgICAgICk7XG4gICAgICB9O1xuXG4gICAgICBpbWcub25lcnJvciA9ICgpID0+IHJlamVjdChuZXcgRXJyb3IodGhpcy50KCkubG9hZEVycm9yKSk7XG4gICAgICBpbWcuc3JjID0gVVJMLmNyZWF0ZU9iamVjdFVSTChmaWxlKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKiBDb3JlIHVwbG9hZCBsb2dpYyB3aXRoIHByb2dyZXNzIHRyYWNraW5nICovXG4gIHByaXZhdGUgYXN5bmMgdXBsb2FkSW1hZ2VXaXRoUHJvZ3Jlc3MoXG4gICAgZWRpdG9yOiBFZGl0b3IsXG4gICAgZmlsZTogRmlsZSxcbiAgICBpbnNlcnRpb25TdHJhdGVneTogKGVkaXRvcjogRWRpdG9yLCByZXN1bHQ6IEF0ZUltYWdlVXBsb2FkUmVzdWx0KSA9PiB2b2lkLFxuICAgIGFjdGlvbk1lc3NhZ2U6IHN0cmluZyxcbiAgICBvcHRpb25zPzogQXRlSW1hZ2VVcGxvYWRPcHRpb25zXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmN1cnJlbnRFZGl0b3IgPSBlZGl0b3I7XG4gICAgICB0aGlzLmlzVXBsb2FkaW5nLnNldCh0cnVlKTtcbiAgICAgIHRoaXMudXBsb2FkUHJvZ3Jlc3Muc2V0KDEwKTtcbiAgICAgIHRoaXMudXBsb2FkTWVzc2FnZS5zZXQodGhpcy50KCkudmFsaWRhdGluZyk7XG4gICAgICB0aGlzLmZvcmNlRWRpdG9yVXBkYXRlKCk7XG5cbiAgICAgIGNvbnN0IHZhbGlkYXRpb24gPSB0aGlzLnZhbGlkYXRlSW1hZ2UoZmlsZSwge1xuICAgICAgICBtYXhTaXplOiBvcHRpb25zPy5tYXhTaXplLFxuICAgICAgICBhbGxvd2VkVHlwZXM6IG9wdGlvbnM/LmFsbG93ZWRUeXBlcyxcbiAgICAgIH0pO1xuICAgICAgaWYgKCF2YWxpZGF0aW9uLnZhbGlkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcih2YWxpZGF0aW9uLmVycm9yKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy51cGxvYWRQcm9ncmVzcy5zZXQoMzApO1xuICAgICAgdGhpcy51cGxvYWRNZXNzYWdlLnNldCh0aGlzLnQoKS5jb21wcmVzc2luZyk7XG4gICAgICB0aGlzLmZvcmNlRWRpdG9yVXBkYXRlKCk7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuY29tcHJlc3NJbWFnZShcbiAgICAgICAgZmlsZSxcbiAgICAgICAgb3B0aW9ucz8ucXVhbGl0eSB8fCAwLjgsXG4gICAgICAgIG9wdGlvbnM/Lm1heFdpZHRoIHx8IDE5MjAsXG4gICAgICAgIG9wdGlvbnM/Lm1heEhlaWdodCB8fCAxMjAwXG4gICAgICApO1xuXG4gICAgICB0aGlzLnVwbG9hZFByb2dyZXNzLnNldCg3MCk7XG5cbiAgICAgIC8vIEhhbmRsZSBjdXN0b20gdXBsb2FkIGlmIGhhbmRsZXIgaXMgcHJvdmlkZWRcbiAgICAgIGlmICh0aGlzLnVwbG9hZEhhbmRsZXIpIHtcbiAgICAgICAgdGhpcy51cGxvYWRNZXNzYWdlLnNldCh0aGlzLnQoKS51cGxvYWRpbmdUb1NlcnZlcik7XG4gICAgICAgIHRoaXMuZm9yY2VFZGl0b3JVcGRhdGUoKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IGhhbmRsZXJSZXNwb25zZSA9IHRoaXMudXBsb2FkSGFuZGxlcih7XG4gICAgICAgICAgICBmaWxlLFxuICAgICAgICAgICAgd2lkdGg6IHJlc3VsdC53aWR0aCB8fCAwLFxuICAgICAgICAgICAgaGVpZ2h0OiByZXN1bHQuaGVpZ2h0IHx8IDAsXG4gICAgICAgICAgICB0eXBlOiByZXN1bHQudHlwZSxcbiAgICAgICAgICAgIGJhc2U2NDogcmVzdWx0LnNyYyxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGNvbnN0IGhhbmRsZXJSZXN1bHQgPSBpc09ic2VydmFibGUoaGFuZGxlclJlc3BvbnNlKVxuICAgICAgICAgICAgPyBhd2FpdCBmaXJzdFZhbHVlRnJvbShoYW5kbGVyUmVzcG9uc2UpXG4gICAgICAgICAgICA6IGF3YWl0IGhhbmRsZXJSZXNwb25zZTtcblxuICAgICAgICAgIHJlc3VsdC5zcmMgPSBoYW5kbGVyUmVzdWx0LnNyYztcbiAgICAgICAgICBpZiAoaGFuZGxlclJlc3VsdC5hbHQpIHtcbiAgICAgICAgICAgIHJlc3VsdC5uYW1lID0gaGFuZGxlclJlc3VsdC5hbHQ7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChoYW5kbGVyRXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKHRoaXMudCgpLnVwbG9hZEVycm9yLCBoYW5kbGVyRXJyb3IpO1xuICAgICAgICAgIHRocm93IGhhbmRsZXJFcnJvcjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLnVwbG9hZFByb2dyZXNzLnNldCg5MCk7XG4gICAgICB0aGlzLnVwbG9hZE1lc3NhZ2Uuc2V0KGFjdGlvbk1lc3NhZ2UpO1xuICAgICAgdGhpcy5mb3JjZUVkaXRvclVwZGF0ZSgpO1xuXG4gICAgICAvLyBGaW5hbCBpbnNlcnRpb25cbiAgICAgIGluc2VydGlvblN0cmF0ZWd5KGVkaXRvciwgcmVzdWx0KTtcblxuICAgICAgdGhpcy5yZXNldFVwbG9hZFN0YXRlKCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMucmVzZXRVcGxvYWRTdGF0ZSgpO1xuICAgICAgY29uc29sZS5lcnJvcih0aGlzLnQoKS51cGxvYWRFcnJvciwgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZXNldFVwbG9hZFN0YXRlKCkge1xuICAgIHRoaXMuaXNVcGxvYWRpbmcuc2V0KGZhbHNlKTtcbiAgICB0aGlzLnVwbG9hZFByb2dyZXNzLnNldCgwKTtcbiAgICB0aGlzLnVwbG9hZE1lc3NhZ2Uuc2V0KFwiXCIpO1xuICAgIHRoaXMuZm9yY2VFZGl0b3JVcGRhdGUoKTtcbiAgICB0aGlzLmN1cnJlbnRFZGl0b3IgPSBudWxsO1xuICB9XG5cbiAgLyoqIE1haW4gZW50cnkgcG9pbnQgZm9yIGZpbGUgdXBsb2FkIGFuZCBpbnNlcnRpb24gKi9cbiAgYXN5bmMgdXBsb2FkQW5kSW5zZXJ0SW1hZ2UoXG4gICAgZWRpdG9yOiBFZGl0b3IsXG4gICAgZmlsZTogRmlsZSxcbiAgICBvcHRpb25zPzogQXRlSW1hZ2VVcGxvYWRPcHRpb25zXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLnVwbG9hZEltYWdlV2l0aFByb2dyZXNzKFxuICAgICAgZWRpdG9yLFxuICAgICAgZmlsZSxcbiAgICAgIChlZCwgcmVzdWx0KSA9PiB7XG4gICAgICAgIHRoaXMuaW5zZXJ0SW1hZ2UoZWQsIHtcbiAgICAgICAgICBzcmM6IHJlc3VsdC5zcmMsXG4gICAgICAgICAgYWx0OiByZXN1bHQubmFtZSxcbiAgICAgICAgICB0aXRsZTogYCR7cmVzdWx0Lm5hbWV9ICgke3Jlc3VsdC53aWR0aH3DlyR7cmVzdWx0LmhlaWdodH0pYCxcbiAgICAgICAgICB3aWR0aDogcmVzdWx0LndpZHRoLFxuICAgICAgICAgIGhlaWdodDogcmVzdWx0LmhlaWdodCxcbiAgICAgICAgfSk7XG4gICAgICB9LFxuICAgICAgdGhpcy50KCkuaW5zZXJ0aW5nSW1hZ2UsXG4gICAgICBvcHRpb25zXG4gICAgKTtcbiAgfVxuXG4gIC8qKiBUcmlnZ2VyIGFuIGVkaXRvciB0cmFuc2FjdGlvbiB0byBmb3JjZSBkZWNvcmF0aW9uIHVwZGF0ZSAqL1xuICBwcml2YXRlIGZvcmNlRWRpdG9yVXBkYXRlKCkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRFZGl0b3IpIHtcbiAgICAgIGNvbnN0IHsgdHIgfSA9IHRoaXMuY3VycmVudEVkaXRvci5zdGF0ZTtcbiAgICAgIHRoaXMuY3VycmVudEVkaXRvci52aWV3LmRpc3BhdGNoKHRyKTtcbiAgICB9XG4gIH1cblxuICAvKiogR2VuZXJpYyBoZWxwZXIgdG8gb3BlbiBmaWxlIHBpY2tlciBhbmQgcHJvY2VzcyBzZWxlY3Rpb24gKi9cbiAgcHJpdmF0ZSBhc3luYyBzZWxlY3RGaWxlQW5kUHJvY2VzcyhcbiAgICBlZGl0b3I6IEVkaXRvcixcbiAgICB1cGxvYWRNZXRob2Q6IChlZGl0b3I6IEVkaXRvciwgZmlsZTogRmlsZSwgb3B0aW9ucz86IEF0ZUltYWdlVXBsb2FkT3B0aW9ucykgPT4gUHJvbWlzZTx2b2lkPixcbiAgICBvcHRpb25zPzogQXRlSW1hZ2VVcGxvYWRPcHRpb25zXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpbnB1dFwiKTtcbiAgICAgIGlucHV0LnR5cGUgPSBcImZpbGVcIjtcblxuICAgICAgLy8gVXNlIGFsbG93ZWRUeXBlcyBpZiBwcm92aWRlZCwgb3RoZXJ3aXNlIGRlZmF1bHQgdG8gaW1hZ2UvKlxuICAgICAgaWYgKG9wdGlvbnM/LmFsbG93ZWRUeXBlcyAmJiBvcHRpb25zLmFsbG93ZWRUeXBlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGlucHV0LmFjY2VwdCA9IG9wdGlvbnMuYWxsb3dlZFR5cGVzLmpvaW4oXCIsXCIpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaW5wdXQuYWNjZXB0ID0gXCJpbWFnZS8qXCI7XG4gICAgICB9XG5cbiAgICAgIGlucHV0LnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcblxuICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImNoYW5nZVwiLCBhc3luYyBlID0+IHtcbiAgICAgICAgY29uc3QgZmlsZSA9IChlLnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS5maWxlcz8uWzBdO1xuICAgICAgICBpZiAoZmlsZSAmJiBmaWxlLnR5cGUuc3RhcnRzV2l0aChcImltYWdlL1wiKSkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB1cGxvYWRNZXRob2QoZWRpdG9yLCBmaWxlLCBvcHRpb25zKTtcbiAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcih0aGlzLnQoKS5ub0ZpbGVTZWxlY3RlZCkpO1xuICAgICAgICB9XG4gICAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQoaW5wdXQpO1xuICAgICAgfSk7XG5cbiAgICAgIGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoXCJjYW5jZWxcIiwgKCkgPT4ge1xuICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGlucHV0KTtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcih0aGlzLnQoKS5zZWxlY3Rpb25DYW5jZWxsZWQpKTtcbiAgICAgIH0pO1xuXG4gICAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGlucHV0KTtcbiAgICAgIGlucHV0LmNsaWNrKCk7XG4gICAgfSk7XG4gIH1cblxuICAvKiogU2VsZWN0IGZpbGUgYW5kIHVwbG9hZCBhcyBuZXcgaW1hZ2UgKi9cbiAgYXN5bmMgc2VsZWN0QW5kVXBsb2FkSW1hZ2UoZWRpdG9yOiBFZGl0b3IsIG9wdGlvbnM/OiBBdGVJbWFnZVVwbG9hZE9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RGaWxlQW5kUHJvY2VzcyhlZGl0b3IsIHRoaXMudXBsb2FkQW5kSW5zZXJ0SW1hZ2UuYmluZCh0aGlzKSwgb3B0aW9ucyk7XG4gIH1cblxuICAvKiogU2VsZWN0IGZpbGUgYW5kIHJlcGxhY2UgY3VycmVudGx5IHNlbGVjdGVkIGltYWdlICovXG4gIGFzeW5jIHNlbGVjdEFuZFJlcGxhY2VJbWFnZShlZGl0b3I6IEVkaXRvciwgb3B0aW9ucz86IEF0ZUltYWdlVXBsb2FkT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIE5vIG5lZWQgZm9yIGNvbXBsaWNhdGVkIGJhY2t1cC9yZXN0b3JlIG5vdyB0aGF0IHdlIGRvbid0IGRlbGV0ZSBwcmVtYXR1cmVseS5cbiAgICAvLyBUaGUgdXBsb2FkQW5kUmVwbGFjZUltYWdlIHdpbGwgaGFuZGxlIHRoZSBhdG9taWMgcmVwbGFjZW1lbnQuXG4gICAgcmV0dXJuIHRoaXMuc2VsZWN0RmlsZUFuZFByb2Nlc3MoZWRpdG9yLCB0aGlzLnVwbG9hZEFuZFJlcGxhY2VJbWFnZS5iaW5kKHRoaXMpLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKiBJbnRlcm5hbCBoZWxwZXIgdXNlZCBieSByZXBsYWNlbWVudCBsb2dpYyAqL1xuICBhc3luYyB1cGxvYWRBbmRSZXBsYWNlSW1hZ2UoXG4gICAgZWRpdG9yOiBFZGl0b3IsXG4gICAgZmlsZTogRmlsZSxcbiAgICBvcHRpb25zPzogQXRlSW1hZ2VVcGxvYWRPcHRpb25zXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIFN0b3JlIGN1cnJlbnQgcG9zaXRpb24gdG8gZW5zdXJlIHdlIGNhbiByZS1zZWxlY3QgdGhlIGltYWdlIGV2ZW4gaWYgc2VsZWN0aW9uIGJsdXJzIGR1cmluZyB1cGxvYWRcbiAgICBjb25zdCBwb3MgPSBlZGl0b3Iuc3RhdGUuc2VsZWN0aW9uLmZyb207XG4gICAgY29uc3Qgd2FzQWN0aXZlID0gZWRpdG9yLmlzQWN0aXZlKFwicmVzaXphYmxlSW1hZ2VcIik7XG5cbiAgICBhd2FpdCB0aGlzLnVwbG9hZEltYWdlV2l0aFByb2dyZXNzKFxuICAgICAgZWRpdG9yLFxuICAgICAgZmlsZSxcbiAgICAgIChlZCwgcmVzdWx0KSA9PiB7XG4gICAgICAgIGNvbnN0IGltYWdlRGF0YSA9IHtcbiAgICAgICAgICBzcmM6IHJlc3VsdC5zcmMsXG4gICAgICAgICAgYWx0OiByZXN1bHQubmFtZSxcbiAgICAgICAgICB0aXRsZTogYCR7cmVzdWx0Lm5hbWV9ICgke3Jlc3VsdC53aWR0aH3DlyR7cmVzdWx0LmhlaWdodH0pYCxcbiAgICAgICAgICB3aWR0aDogcmVzdWx0LndpZHRoLFxuICAgICAgICAgIGhlaWdodDogcmVzdWx0LmhlaWdodCxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBJZiB0aGUgaW1hZ2Ugd2FzIGFjdGl2ZSBvciBpcyBzdGlsbCBhY3RpdmUsIHVwZGF0ZSBpdCBhdG9taWNhbGx5XG4gICAgICAgIGlmICh3YXNBY3RpdmUgfHwgZWQuaXNBY3RpdmUoXCJyZXNpemFibGVJbWFnZVwiKSkge1xuICAgICAgICAgIGVkLmNoYWluKClcbiAgICAgICAgICAgIC5mb2N1cygpXG4gICAgICAgICAgICAudXBkYXRlQXR0cmlidXRlcyhcInJlc2l6YWJsZUltYWdlXCIsIGltYWdlRGF0YSlcbiAgICAgICAgICAgIC5zZXROb2RlU2VsZWN0aW9uKHBvcylcbiAgICAgICAgICAgIC5ydW4oKTtcbiAgICAgICAgICB0aGlzLnVwZGF0ZVNlbGVjdGVkSW1hZ2UoaW1hZ2VEYXRhKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBPdGhlcndpc2UgcmVwbGFjZSB3aGF0ZXZlciBpcyBzZWxlY3RlZCAob3IgaW5zZXJ0IGF0IGN1cnNvcilcbiAgICAgICAgICB0aGlzLmluc2VydEltYWdlKGVkLCBpbWFnZURhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQWZ0ZXIgcmVwbGFjZW1lbnQsIGVuc3VyZSB0aGUgaW1hZ2UgaXMgdHJhY2tlZCBpbiBvdXIgc2lnbmFsc1xuICAgICAgICB0aGlzLnNlbGVjdEltYWdlKGVkKTtcbiAgICAgIH0sXG4gICAgICB0aGlzLnQoKS5yZXBsYWNpbmdJbWFnZSxcbiAgICAgIG9wdGlvbnNcbiAgICApO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,97 @@
1
+ import { Injectable, signal } from "@angular/core";
2
+ import * as i0 from "@angular/core";
3
+ export class AteLinkService {
4
+ constructor() {
5
+ // ============================================
6
+ // State Signals (owned by this service)
7
+ // ============================================
8
+ /** Whether link edit mode is active */
9
+ this.editMode = signal(false);
10
+ /** Reference to the element that triggered the menu (for anchoring) */
11
+ this.menuTrigger = signal(null);
12
+ /** Whether the user is currently interacting with the link UI (input focus) */
13
+ this.isInteracting = signal(false);
14
+ }
15
+ // ============================================
16
+ // Menu Lifecycle Methods
17
+ // ============================================
18
+ /**
19
+ * Open the link edit menu.
20
+ */
21
+ open(trigger) {
22
+ this.menuTrigger.set(trigger || null);
23
+ this.editMode.set(true);
24
+ }
25
+ /**
26
+ * Close the link edit menu.
27
+ */
28
+ close() {
29
+ this.editMode.set(false);
30
+ this.isInteracting.set(false);
31
+ }
32
+ /**
33
+ * Final cleanup (called after UI is hidden)
34
+ */
35
+ done() {
36
+ this.menuTrigger.set(null);
37
+ }
38
+ /**
39
+ * Set interaction state
40
+ */
41
+ setInteracting(value) {
42
+ this.isInteracting.set(value);
43
+ }
44
+ /**
45
+ * Toggle link mode from UI.
46
+ * If a URL string is provided, applies the link and closes.
47
+ * If an Event is provided, extracts the trigger for anchoring.
48
+ */
49
+ toggle(editor, urlOrEvent) {
50
+ if (!editor) {
51
+ return;
52
+ }
53
+ // If a string URL is provided, set the link and close
54
+ if (urlOrEvent && typeof urlOrEvent === "string") {
55
+ this.setLink(editor, urlOrEvent);
56
+ return;
57
+ }
58
+ // If an Event is provided, extract the trigger element
59
+ let trigger;
60
+ if (urlOrEvent && typeof urlOrEvent !== "string") {
61
+ const target = urlOrEvent.target;
62
+ trigger =
63
+ urlOrEvent.currentTarget || target?.closest("button") || target;
64
+ }
65
+ // Open the edit menu
66
+ this.open(trigger);
67
+ }
68
+ // ============================================
69
+ // Link Commands
70
+ // ============================================
71
+ /**
72
+ * Apply a link to the current selection.
73
+ */
74
+ setLink(editor, url) {
75
+ if (!editor) {
76
+ return;
77
+ }
78
+ editor.chain().focus().extendMarkRange("link").setLink({ href: url }).run();
79
+ this.close();
80
+ }
81
+ /**
82
+ * Remove link from the current selection.
83
+ */
84
+ unsetLink(editor) {
85
+ if (!editor) {
86
+ return;
87
+ }
88
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
89
+ this.close();
90
+ }
91
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
92
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkService }); }
93
+ }
94
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AteLinkService, decorators: [{
95
+ type: Injectable
96
+ }] });
97
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXRlLWxpbmsuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItdGlwdGFwLWVkaXRvci9zcmMvbGliL3NlcnZpY2VzL2F0ZS1saW5rLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBSW5ELE1BQU0sT0FBTyxjQUFjO0lBRDNCO1FBRUUsK0NBQStDO1FBQy9DLHdDQUF3QztRQUN4QywrQ0FBK0M7UUFFL0MsdUNBQXVDO1FBQzlCLGFBQVEsR0FBRyxNQUFNLENBQVUsS0FBSyxDQUFDLENBQUM7UUFFM0MsdUVBQXVFO1FBQzlELGdCQUFXLEdBQUcsTUFBTSxDQUFxQixJQUFJLENBQUMsQ0FBQztRQUV4RCwrRUFBK0U7UUFDdEUsa0JBQWEsR0FBRyxNQUFNLENBQVUsS0FBSyxDQUFDLENBQUM7S0F5RmpEO0lBdkZDLCtDQUErQztJQUMvQyx5QkFBeUI7SUFDekIsK0NBQStDO0lBRS9DOztPQUVHO0lBQ0gsSUFBSSxDQUFDLE9BQXFCO1FBQ3hCLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsQ0FBQztRQUN0QyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMxQixDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLO1FBQ0gsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDekIsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSTtRQUNGLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWMsQ0FBQyxLQUFjO1FBQzNCLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsTUFBTSxDQUFDLE1BQWMsRUFBRSxVQUEyQjtRQUNoRCxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixPQUFPO1FBQ1QsQ0FBQztRQUVELHNEQUFzRDtRQUN0RCxJQUFJLFVBQVUsSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUNqRCxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsQ0FBQztZQUNqQyxPQUFPO1FBQ1QsQ0FBQztRQUVELHVEQUF1RDtRQUN2RCxJQUFJLE9BQWdDLENBQUM7UUFDckMsSUFBSSxVQUFVLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDakQsTUFBTSxNQUFNLEdBQUksVUFBb0IsQ0FBQyxNQUFxQixDQUFDO1lBQzNELE9BQU87Z0JBQ0gsVUFBb0IsQ0FBQyxhQUE2QixJQUFJLE1BQU0sRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksTUFBTSxDQUFDO1FBQ2hHLENBQUM7UUFFRCxxQkFBcUI7UUFDckIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNyQixDQUFDO0lBRUQsK0NBQStDO0lBQy9DLGdCQUFnQjtJQUNoQiwrQ0FBK0M7SUFFL0M7O09BRUc7SUFDSCxPQUFPLENBQUMsTUFBYyxFQUFFLEdBQVc7UUFDakMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osT0FBTztRQUNULENBQUM7UUFDRCxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQzVFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNmLENBQUM7SUFFRDs7T0FFRztJQUNILFNBQVMsQ0FBQyxNQUFjO1FBQ3RCLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNaLE9BQU87UUFDVCxDQUFDO1FBQ0QsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNqRSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDZixDQUFDOytHQXBHVSxjQUFjO21IQUFkLGNBQWM7OzRGQUFkLGNBQWM7a0JBRDFCLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBzaWduYWwgfSBmcm9tIFwiQGFuZ3VsYXIvY29yZVwiO1xuaW1wb3J0IHR5cGUgeyBFZGl0b3IgfSBmcm9tIFwiQHRpcHRhcC9jb3JlXCI7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBBdGVMaW5rU2VydmljZSB7XG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFN0YXRlIFNpZ25hbHMgKG93bmVkIGJ5IHRoaXMgc2VydmljZSlcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKiogV2hldGhlciBsaW5rIGVkaXQgbW9kZSBpcyBhY3RpdmUgKi9cbiAgcmVhZG9ubHkgZWRpdE1vZGUgPSBzaWduYWw8Ym9vbGVhbj4oZmFsc2UpO1xuXG4gIC8qKiBSZWZlcmVuY2UgdG8gdGhlIGVsZW1lbnQgdGhhdCB0cmlnZ2VyZWQgdGhlIG1lbnUgKGZvciBhbmNob3JpbmcpICovXG4gIHJlYWRvbmx5IG1lbnVUcmlnZ2VyID0gc2lnbmFsPEhUTUxFbGVtZW50IHwgbnVsbD4obnVsbCk7XG5cbiAgLyoqIFdoZXRoZXIgdGhlIHVzZXIgaXMgY3VycmVudGx5IGludGVyYWN0aW5nIHdpdGggdGhlIGxpbmsgVUkgKGlucHV0IGZvY3VzKSAqL1xuICByZWFkb25seSBpc0ludGVyYWN0aW5nID0gc2lnbmFsPGJvb2xlYW4+KGZhbHNlKTtcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBNZW51IExpZmVjeWNsZSBNZXRob2RzXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIE9wZW4gdGhlIGxpbmsgZWRpdCBtZW51LlxuICAgKi9cbiAgb3Blbih0cmlnZ2VyPzogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICB0aGlzLm1lbnVUcmlnZ2VyLnNldCh0cmlnZ2VyIHx8IG51bGwpO1xuICAgIHRoaXMuZWRpdE1vZGUuc2V0KHRydWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlIHRoZSBsaW5rIGVkaXQgbWVudS5cbiAgICovXG4gIGNsb3NlKCk6IHZvaWQge1xuICAgIHRoaXMuZWRpdE1vZGUuc2V0KGZhbHNlKTtcbiAgICB0aGlzLmlzSW50ZXJhY3Rpbmcuc2V0KGZhbHNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbCBjbGVhbnVwIChjYWxsZWQgYWZ0ZXIgVUkgaXMgaGlkZGVuKVxuICAgKi9cbiAgZG9uZSgpOiB2b2lkIHtcbiAgICB0aGlzLm1lbnVUcmlnZ2VyLnNldChudWxsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgaW50ZXJhY3Rpb24gc3RhdGVcbiAgICovXG4gIHNldEludGVyYWN0aW5nKHZhbHVlOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5pc0ludGVyYWN0aW5nLnNldCh2YWx1ZSk7XG4gIH1cblxuICAvKipcbiAgICogVG9nZ2xlIGxpbmsgbW9kZSBmcm9tIFVJLlxuICAgKiBJZiBhIFVSTCBzdHJpbmcgaXMgcHJvdmlkZWQsIGFwcGxpZXMgdGhlIGxpbmsgYW5kIGNsb3Nlcy5cbiAgICogSWYgYW4gRXZlbnQgaXMgcHJvdmlkZWQsIGV4dHJhY3RzIHRoZSB0cmlnZ2VyIGZvciBhbmNob3JpbmcuXG4gICAqL1xuICB0b2dnbGUoZWRpdG9yOiBFZGl0b3IsIHVybE9yRXZlbnQ/OiBzdHJpbmcgfCBFdmVudCk6IHZvaWQge1xuICAgIGlmICghZWRpdG9yKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSWYgYSBzdHJpbmcgVVJMIGlzIHByb3ZpZGVkLCBzZXQgdGhlIGxpbmsgYW5kIGNsb3NlXG4gICAgaWYgKHVybE9yRXZlbnQgJiYgdHlwZW9mIHVybE9yRXZlbnQgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHRoaXMuc2V0TGluayhlZGl0b3IsIHVybE9yRXZlbnQpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIElmIGFuIEV2ZW50IGlzIHByb3ZpZGVkLCBleHRyYWN0IHRoZSB0cmlnZ2VyIGVsZW1lbnRcbiAgICBsZXQgdHJpZ2dlcjogSFRNTEVsZW1lbnQgfCB1bmRlZmluZWQ7XG4gICAgaWYgKHVybE9yRXZlbnQgJiYgdHlwZW9mIHVybE9yRXZlbnQgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgIGNvbnN0IHRhcmdldCA9ICh1cmxPckV2ZW50IGFzIEV2ZW50KS50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XG4gICAgICB0cmlnZ2VyID1cbiAgICAgICAgKCh1cmxPckV2ZW50IGFzIEV2ZW50KS5jdXJyZW50VGFyZ2V0IGFzIEhUTUxFbGVtZW50KSB8fCB0YXJnZXQ/LmNsb3Nlc3QoXCJidXR0b25cIikgfHwgdGFyZ2V0O1xuICAgIH1cblxuICAgIC8vIE9wZW4gdGhlIGVkaXQgbWVudVxuICAgIHRoaXMub3Blbih0cmlnZ2VyKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIExpbmsgQ29tbWFuZHNcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKipcbiAgICogQXBwbHkgYSBsaW5rIHRvIHRoZSBjdXJyZW50IHNlbGVjdGlvbi5cbiAgICovXG4gIHNldExpbmsoZWRpdG9yOiBFZGl0b3IsIHVybDogc3RyaW5nKTogdm9pZCB7XG4gICAgaWYgKCFlZGl0b3IpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZWRpdG9yLmNoYWluKCkuZm9jdXMoKS5leHRlbmRNYXJrUmFuZ2UoXCJsaW5rXCIpLnNldExpbmsoeyBocmVmOiB1cmwgfSkucnVuKCk7XG4gICAgdGhpcy5jbG9zZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBsaW5rIGZyb20gdGhlIGN1cnJlbnQgc2VsZWN0aW9uLlxuICAgKi9cbiAgdW5zZXRMaW5rKGVkaXRvcjogRWRpdG9yKTogdm9pZCB7XG4gICAgaWYgKCFlZGl0b3IpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZWRpdG9yLmNoYWluKCkuZm9jdXMoKS5leHRlbmRNYXJrUmFuZ2UoXCJsaW5rXCIpLnVuc2V0TGluaygpLnJ1bigpO1xuICAgIHRoaXMuY2xvc2UoKTtcbiAgfVxufVxuIl19
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Normalizes color values (rgb/rgba to hex).
3
+ */
4
+ export function normalizeColor(color) {
5
+ if (!color || color === "transparent" || color === "rgba(0, 0, 0, 0)") {
6
+ return null;
7
+ }
8
+ if (color.startsWith("#")) {
9
+ return color;
10
+ }
11
+ // Support both comma-separated (legacy) and space-separated (modern) rgb/rgba
12
+ const rgbMatch = color
13
+ .trim()
14
+ .match(/^rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:[,\s/]+([\d.]+))?\s*\)$/i);
15
+ // If it's a named color or something else we don't recognize,
16
+ // we can't easily normalize it to hex without a heavy dictionary.
17
+ // However, getComputedStyle usually returns rgb() which we handle above.
18
+ if (!rgbMatch) {
19
+ // Simple fallback for common named colors if getComputedStyle fails to return rgb
20
+ const named = { black: "#000000", white: "#ffffff", red: "#ff0000" };
21
+ if (named[color.toLowerCase()]) {
22
+ return named[color.toLowerCase()];
23
+ }
24
+ return null;
25
+ }
26
+ const r = Math.max(0, Math.min(255, Math.round(parseFloat(rgbMatch[1]))));
27
+ const g = Math.max(0, Math.min(255, Math.round(parseFloat(rgbMatch[2]))));
28
+ const b = Math.max(0, Math.min(255, Math.round(parseFloat(rgbMatch[3]))));
29
+ const a = rgbMatch[4] ? parseFloat(rgbMatch[4]) : 1;
30
+ // If completely transparent, return null
31
+ if (a === 0) {
32
+ return null;
33
+ }
34
+ return ("#" +
35
+ [r, g, b]
36
+ .map(n => n.toString(16).padStart(2, "0"))
37
+ .join("")
38
+ .toLowerCase());
39
+ }
40
+ /**
41
+ * Calculate luminance (0-255).
42
+ */
43
+ export function getLuminance(color) {
44
+ const normalized = normalizeColor(color);
45
+ if (!normalized) {
46
+ return 0;
47
+ } // Default to dark (luminance 0) if no color
48
+ const hex = normalized.replace("#", "");
49
+ const r = parseInt(hex.substring(0, 2), 16);
50
+ const g = parseInt(hex.substring(2, 4), 16);
51
+ const b = parseInt(hex.substring(4, 6), 16);
52
+ return (r * 299 + g * 587 + b * 114) / 1000;
53
+ }
54
+ /**
55
+ * Returns contrast color for readability.
56
+ */
57
+ export function getContrastColor(color) {
58
+ return getLuminance(color) > 128 ? "black" : "white";
59
+ }
60
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXRlLWNvbG9yLnV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci10aXB0YXAtZWRpdG9yL3NyYy9saWIvdXRpbHMvYXRlLWNvbG9yLnV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxLQUFnQztJQUM3RCxJQUFJLENBQUMsS0FBSyxJQUFJLEtBQUssS0FBSyxhQUFhLElBQUksS0FBSyxLQUFLLGtCQUFrQixFQUFFLENBQUM7UUFDdEUsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsOEVBQThFO0lBQzlFLE1BQU0sUUFBUSxHQUFHLEtBQUs7U0FDbkIsSUFBSSxFQUFFO1NBQ04sS0FBSyxDQUFDLDRFQUE0RSxDQUFDLENBQUM7SUFFdkYsOERBQThEO0lBQzlELGtFQUFrRTtJQUNsRSx5RUFBeUU7SUFDekUsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ2Qsa0ZBQWtGO1FBQ2xGLE1BQU0sS0FBSyxHQUEyQixFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLENBQUM7UUFDN0YsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUMvQixPQUFPLEtBQUssQ0FBQyxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUUsQ0FBQztRQUNyQyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0UsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0UsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0UsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUVwRCx5Q0FBeUM7SUFDekMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDWixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxPQUFPLENBQ0wsR0FBRztRQUNILENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7YUFDTixHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7YUFDekMsSUFBSSxDQUFDLEVBQUUsQ0FBQzthQUNSLFdBQVcsRUFBRSxDQUNqQixDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxLQUFnQztJQUMzRCxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDekMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2hCLE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQyxDQUFDLDRDQUE0QztJQUM5QyxNQUFNLEdBQUcsR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN4QyxNQUFNLENBQUMsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDNUMsTUFBTSxDQUFDLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQzVDLE1BQU0sQ0FBQyxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM1QyxPQUFPLENBQUMsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUM7QUFDOUMsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLEtBQWE7SUFDNUMsT0FBTyxZQUFZLENBQUMsS0FBSyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztBQUN2RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBOb3JtYWxpemVzIGNvbG9yIHZhbHVlcyAocmdiL3JnYmEgdG8gaGV4KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZUNvbG9yKGNvbG9yOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmICghY29sb3IgfHwgY29sb3IgPT09IFwidHJhbnNwYXJlbnRcIiB8fCBjb2xvciA9PT0gXCJyZ2JhKDAsIDAsIDAsIDApXCIpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBpZiAoY29sb3Iuc3RhcnRzV2l0aChcIiNcIikpIHtcbiAgICByZXR1cm4gY29sb3I7XG4gIH1cblxuICAvLyBTdXBwb3J0IGJvdGggY29tbWEtc2VwYXJhdGVkIChsZWdhY3kpIGFuZCBzcGFjZS1zZXBhcmF0ZWQgKG1vZGVybikgcmdiL3JnYmFcbiAgY29uc3QgcmdiTWF0Y2ggPSBjb2xvclxuICAgIC50cmltKClcbiAgICAubWF0Y2goL15yZ2JhP1xcKFxccyooW1xcZC5dKylbLFxcc10rKFtcXGQuXSspWyxcXHNdKyhbXFxkLl0rKSg/OlssXFxzL10rKFtcXGQuXSspKT9cXHMqXFwpJC9pKTtcblxuICAvLyBJZiBpdCdzIGEgbmFtZWQgY29sb3Igb3Igc29tZXRoaW5nIGVsc2Ugd2UgZG9uJ3QgcmVjb2duaXplLFxuICAvLyB3ZSBjYW4ndCBlYXNpbHkgbm9ybWFsaXplIGl0IHRvIGhleCB3aXRob3V0IGEgaGVhdnkgZGljdGlvbmFyeS5cbiAgLy8gSG93ZXZlciwgZ2V0Q29tcHV0ZWRTdHlsZSB1c3VhbGx5IHJldHVybnMgcmdiKCkgd2hpY2ggd2UgaGFuZGxlIGFib3ZlLlxuICBpZiAoIXJnYk1hdGNoKSB7XG4gICAgLy8gU2ltcGxlIGZhbGxiYWNrIGZvciBjb21tb24gbmFtZWQgY29sb3JzIGlmIGdldENvbXB1dGVkU3R5bGUgZmFpbHMgdG8gcmV0dXJuIHJnYlxuICAgIGNvbnN0IG5hbWVkOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0geyBibGFjazogXCIjMDAwMDAwXCIsIHdoaXRlOiBcIiNmZmZmZmZcIiwgcmVkOiBcIiNmZjAwMDBcIiB9O1xuICAgIGlmIChuYW1lZFtjb2xvci50b0xvd2VyQ2FzZSgpXSkge1xuICAgICAgcmV0dXJuIG5hbWVkW2NvbG9yLnRvTG93ZXJDYXNlKCldITtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCByID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oMjU1LCBNYXRoLnJvdW5kKHBhcnNlRmxvYXQocmdiTWF0Y2hbMV0hKSkpKTtcbiAgY29uc3QgZyA9IE1hdGgubWF4KDAsIE1hdGgubWluKDI1NSwgTWF0aC5yb3VuZChwYXJzZUZsb2F0KHJnYk1hdGNoWzJdISkpKSk7XG4gIGNvbnN0IGIgPSBNYXRoLm1heCgwLCBNYXRoLm1pbigyNTUsIE1hdGgucm91bmQocGFyc2VGbG9hdChyZ2JNYXRjaFszXSEpKSkpO1xuICBjb25zdCBhID0gcmdiTWF0Y2hbNF0gPyBwYXJzZUZsb2F0KHJnYk1hdGNoWzRdKSA6IDE7XG5cbiAgLy8gSWYgY29tcGxldGVseSB0cmFuc3BhcmVudCwgcmV0dXJuIG51bGxcbiAgaWYgKGEgPT09IDApIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgXCIjXCIgK1xuICAgIFtyLCBnLCBiXVxuICAgICAgLm1hcChuID0+IG4udG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsIFwiMFwiKSlcbiAgICAgIC5qb2luKFwiXCIpXG4gICAgICAudG9Mb3dlckNhc2UoKVxuICApO1xufVxuXG4vKipcbiAqIENhbGN1bGF0ZSBsdW1pbmFuY2UgKDAtMjU1KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEx1bWluYW5jZShjb2xvcjogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCk6IG51bWJlciB7XG4gIGNvbnN0IG5vcm1hbGl6ZWQgPSBub3JtYWxpemVDb2xvcihjb2xvcik7XG4gIGlmICghbm9ybWFsaXplZCkge1xuICAgIHJldHVybiAwO1xuICB9IC8vIERlZmF1bHQgdG8gZGFyayAobHVtaW5hbmNlIDApIGlmIG5vIGNvbG9yXG4gIGNvbnN0IGhleCA9IG5vcm1hbGl6ZWQucmVwbGFjZShcIiNcIiwgXCJcIik7XG4gIGNvbnN0IHIgPSBwYXJzZUludChoZXguc3Vic3RyaW5nKDAsIDIpLCAxNik7XG4gIGNvbnN0IGcgPSBwYXJzZUludChoZXguc3Vic3RyaW5nKDIsIDQpLCAxNik7XG4gIGNvbnN0IGIgPSBwYXJzZUludChoZXguc3Vic3RyaW5nKDQsIDYpLCAxNik7XG4gIHJldHVybiAociAqIDI5OSArIGcgKiA1ODcgKyBiICogMTE0KSAvIDEwMDA7XG59XG5cbi8qKlxuICogUmV0dXJucyBjb250cmFzdCBjb2xvciBmb3IgcmVhZGFiaWxpdHkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRDb250cmFzdENvbG9yKGNvbG9yOiBzdHJpbmcpOiBcImJsYWNrXCIgfCBcIndoaXRlXCIge1xuICByZXR1cm4gZ2V0THVtaW5hbmNlKGNvbG9yKSA+IDEyOCA/IFwiYmxhY2tcIiA6IFwid2hpdGVcIjtcbn1cbiJdfQ==