@searpent/react-image-annotate 2.0.80 → 2.0.82-cand

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 (56) hide show
  1. package/Annotator/examplePhotos.js +28 -28
  2. package/Annotator/index.js +15 -21
  3. package/Annotator/reducers/combine-reducers.js +18 -3
  4. package/Annotator/reducers/convert-expanding-line-to-polygon.js +15 -16
  5. package/Annotator/reducers/get-implied-video-regions.js +18 -30
  6. package/ClassSelectionMenu/index.js +8 -8
  7. package/Crosshairs/index.js +2 -2
  8. package/DebugSidebarBox/index.js +4 -4
  9. package/DemoSite/Editor.js +15 -15
  10. package/DemoSite/ErrorBoundaryDialog.js +3 -5
  11. package/DemoSite/index.js +3 -3
  12. package/Editor/annotation-plugin/annotation.js +1 -3
  13. package/Editor/index.js +12 -31
  14. package/Editor/readOnly.js +395 -47
  15. package/Errorer/index.js +2 -2
  16. package/FullImageSegmentationAnnotator/index.js +1 -1
  17. package/GroupSelectorSidebarBox/index.js +7 -7
  18. package/GroupsEditorSidebarBox/index.js +11 -11
  19. package/HelpSidebarBox/index.js +4 -4
  20. package/HighlightBox/index.js +3 -3
  21. package/HistorySidebarBox/index.js +8 -8
  22. package/ImageCanvas/index.js +16 -16
  23. package/ImageMask/index.js +1 -1
  24. package/ImageSelectorSidebarBox/index.js +7 -7
  25. package/KeyframeTimeline/index.js +30 -14
  26. package/KeyframesSelectorSidebarBox/index.js +8 -8
  27. package/LandingPage/index.js +12 -12
  28. package/Locker/index.js +2 -2
  29. package/MainLayout/RightSidebarItemsWrapper.js +1 -1
  30. package/MainLayout/icon-dictionary.js +11 -11
  31. package/MainLayout/index.js +25 -23
  32. package/MetadataEditorSidebarBox/index.js +18 -18
  33. package/PageSelector/index.js +21 -21
  34. package/PointDistances/index.js +4 -4
  35. package/PreventScrollToParents/index.js +3 -3
  36. package/RegionLabel/index.js +24 -24
  37. package/RegionSelectAndTransformBoxes/index.js +8 -8
  38. package/RegionSelectorSidebarBox/index.js +33 -33
  39. package/RegionShapes/index.js +22 -22
  40. package/RegionTags/index.js +6 -6
  41. package/SettingsDialog/index.js +4 -4
  42. package/SettingsProvider/index.js +1 -1
  43. package/Shortcuts/ShortcutField.js +3 -3
  44. package/Shortcuts/index.js +2 -2
  45. package/ShortcutsManager/index.js +9 -9
  46. package/Sidebar/index.js +7 -7
  47. package/SidebarBoxContainer/index.js +3 -3
  48. package/SmallToolButton/index.js +2 -2
  49. package/TagsSidebarBox/index.js +6 -6
  50. package/TaskDescriptionSidebarBox/index.js +4 -4
  51. package/Theme/index.js +2 -2
  52. package/VideoOrImageCanvasBackground/index.js +5 -5
  53. package/package.json +4 -3
  54. package/utils/blocks-to-article.js +3 -3
  55. package/utils/get-landmarks-with-transform.js +13 -15
  56. package/utils/spellcheck-nspell.js +553 -0
@@ -0,0 +1,553 @@
1
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
3
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
4
+
5
+ function _createForOfIteratorHelper(o) { if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) { var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
6
+
7
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8
+
9
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
10
+
11
+ /**
12
+ * Multi-language spellcheck system with priority-based language detection
13
+ *
14
+ * Language Detection Priority:
15
+ * 1. Explicit spellcheck language setting (setSpellcheckLanguage())
16
+ * 2. Text content analysis (character frequency)
17
+ * 3. Browser language preferences
18
+ * 4. Default fallback (en-US)
19
+ *
20
+ * Usage:
21
+ * - setSpellcheckLanguage('cs-CZ') // Set explicit language
22
+ * - setSpellcheckLanguage(null) // Clear setting (use auto-detection)
23
+ * - highlightMisspellingsInHtml(html, 'auto') // Auto-detect with priority
24
+ */
25
+ // Simple nspell loader usable in the browser. It lazy-loads the aff/dic
26
+ // and exposes a singleton spell instance plus a helper to check words.
27
+ // Cache for different language spellcheckers
28
+ var spellInstances = new Map();
29
+ var loadPromises = new Map();
30
+ export function getSpell() {
31
+ return _getSpell.apply(this, arguments);
32
+ } // Available dictionaries mapping
33
+
34
+ function _getSpell() {
35
+ _getSpell = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
36
+ var lang,
37
+ promise,
38
+ _args2 = arguments;
39
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
40
+ while (1) {
41
+ switch (_context2.prev = _context2.next) {
42
+ case 0:
43
+ lang = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : 'en-US';
44
+
45
+ if (AVAILABLE_DICTIONARIES[lang]) {
46
+ _context2.next = 3;
47
+ break;
48
+ }
49
+
50
+ throw new Error("Dictionary not available for language: ".concat(lang));
51
+
52
+ case 3:
53
+ if (!spellInstances.has(lang)) {
54
+ _context2.next = 5;
55
+ break;
56
+ }
57
+
58
+ return _context2.abrupt("return", spellInstances.get(lang));
59
+
60
+ case 5:
61
+ if (!loadPromises.has(lang)) {
62
+ _context2.next = 7;
63
+ break;
64
+ }
65
+
66
+ return _context2.abrupt("return", loadPromises.get(lang));
67
+
68
+ case 7:
69
+ promise = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
70
+ var _yield$import, nspell, dictName, affUrl, dicUrl, _yield$Promise$all, _yield$Promise$all2, affRes, dicRes, _yield$Promise$all3, _yield$Promise$all4, affBuf, dicBuf, utf8Decoder, affUtf8, enc, setMatch, raw, map, mapped, decoder, aff, dic, spellInstance;
71
+
72
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
73
+ while (1) {
74
+ switch (_context.prev = _context.next) {
75
+ case 0:
76
+ _context.next = 2;
77
+ return import('nspell');
78
+
79
+ case 2:
80
+ _yield$import = _context.sent;
81
+ nspell = _yield$import.default;
82
+ // Use the mapped dictionary name
83
+ dictName = AVAILABLE_DICTIONARIES[lang];
84
+ affUrl = "/dicts/".concat(dictName, ".aff");
85
+ dicUrl = "/dicts/".concat(dictName, ".dic");
86
+ console.log('Loading dictionary files:', affUrl, dicUrl);
87
+ _context.next = 10;
88
+ return Promise.all([fetch(affUrl, {
89
+ mode: 'cors'
90
+ }), fetch(dicUrl, {
91
+ mode: 'cors'
92
+ })]);
93
+
94
+ case 10:
95
+ _yield$Promise$all = _context.sent;
96
+ _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 2);
97
+ affRes = _yield$Promise$all2[0];
98
+ dicRes = _yield$Promise$all2[1];
99
+ console.log('Fetch responses:', affRes.status, dicRes.status);
100
+
101
+ if (!(!affRes.ok || !dicRes.ok)) {
102
+ _context.next = 17;
103
+ break;
104
+ }
105
+
106
+ throw new Error("Failed to load dictionary files: ".concat(affUrl, " (").concat(affRes.status, "), ").concat(dicUrl, " (").concat(dicRes.status, ")"));
107
+
108
+ case 17:
109
+ _context.next = 19;
110
+ return Promise.all([affRes.arrayBuffer(), dicRes.arrayBuffer()]);
111
+
112
+ case 19:
113
+ _yield$Promise$all3 = _context.sent;
114
+ _yield$Promise$all4 = _slicedToArray(_yield$Promise$all3, 2);
115
+ affBuf = _yield$Promise$all4[0];
116
+ dicBuf = _yield$Promise$all4[1];
117
+ // Decode .aff as UTF-8 first to read SET <encoding>
118
+ utf8Decoder = new TextDecoder('utf-8');
119
+ affUtf8 = utf8Decoder.decode(affBuf);
120
+ enc = 'utf-8';
121
+ setMatch = /\n\s*SET\s+([^\r\n]+)/i.exec("\n" + affUtf8);
122
+
123
+ if (setMatch) {
124
+ raw = setMatch[1].trim(); // Map common Hunspell enc names to TextDecoder labels
125
+
126
+ map = {
127
+ 'UTF-8': 'utf-8',
128
+ 'UTF8': 'utf-8',
129
+ 'ISO8859-1': 'iso-8859-1',
130
+ 'ISO-8859-1': 'iso-8859-1',
131
+ 'ISO8859-2': 'iso-8859-2',
132
+ 'ISO-8859-2': 'iso-8859-2',
133
+ 'ISO8859-5': 'iso-8859-5',
134
+ 'ISO-8859-5': 'iso-8859-5',
135
+ 'KOI8-R': 'koi8-r',
136
+ 'KOI8-U': 'koi8-u',
137
+ 'WINDOWS-1250': 'windows-1250',
138
+ 'CP1250': 'windows-1250',
139
+ 'WINDOWS-1251': 'windows-1251',
140
+ 'CP1251': 'windows-1251',
141
+ 'WINDOWS-1252': 'windows-1252',
142
+ 'CP1252': 'windows-1252',
143
+ 'MICROSOFT-CP1251': 'windows-1251',
144
+ 'microsoft-cp1251': 'windows-1251'
145
+ };
146
+ mapped = map[raw.toUpperCase()] || raw;
147
+
148
+ try {
149
+ // Probe if browser supports it
150
+ new TextDecoder(mapped);
151
+ enc = mapped;
152
+ } catch (_) {
153
+ console.warn("Unsupported dictionary encoding '".concat(raw, "' resolved to '").concat(mapped, "'. Falling back to UTF-8."));
154
+ }
155
+ }
156
+
157
+ decoder = new TextDecoder(enc);
158
+ aff = enc === 'utf-8' ? affUtf8 : decoder.decode(affBuf);
159
+ dic = decoder.decode(dicBuf);
160
+ spellInstance = nspell(aff, dic);
161
+ spellInstances.set(lang, spellInstance);
162
+ console.log("Dictionary loaded successfully for ".concat(lang));
163
+ return _context.abrupt("return", spellInstance);
164
+
165
+ case 35:
166
+ case "end":
167
+ return _context.stop();
168
+ }
169
+ }
170
+ }, _callee);
171
+ }))();
172
+ loadPromises.set(lang, promise);
173
+ return _context2.abrupt("return", promise);
174
+
175
+ case 10:
176
+ case "end":
177
+ return _context2.stop();
178
+ }
179
+ }
180
+ }, _callee2);
181
+ }));
182
+ return _getSpell.apply(this, arguments);
183
+ }
184
+
185
+ var AVAILABLE_DICTIONARIES = {
186
+ 'en-US': 'en_US',
187
+ 'en': 'en_US',
188
+ 'cs-CZ': 'cs_CZ',
189
+ 'cs': 'cs_CZ',
190
+ 'sk-SK': 'sk_SK',
191
+ 'sk': 'sk_SK',
192
+ 'pt-BR': 'pt_BR',
193
+ 'pt_BR': 'pt_BR',
194
+ 'pt': 'pt_BR',
195
+ 'mk-MK': 'mk_MK',
196
+ 'mk': 'mk_MK'
197
+ }; // Spellcheck language setting (can be set by user)
198
+
199
+ var spellcheckLanguageSetting = null; // Function to set spellcheck language preference
200
+
201
+ export function setSpellcheckLanguage(lang) {
202
+ if (lang && AVAILABLE_DICTIONARIES[lang]) {
203
+ spellcheckLanguageSetting = lang;
204
+ console.log("Spellcheck language set to: ".concat(lang));
205
+ } else if (lang === null) {
206
+ spellcheckLanguageSetting = null;
207
+ console.log('Spellcheck language setting cleared');
208
+ } else {
209
+ console.warn("Invalid spellcheck language: ".concat(lang, ". Available: ").concat(Object.keys(AVAILABLE_DICTIONARIES).join(', ')));
210
+ }
211
+ } // Function to get current spellcheck language setting
212
+
213
+ export function getSpellcheckLanguage() {
214
+ return spellcheckLanguageSetting;
215
+ } // Get browser language preferences for spellcheck
216
+
217
+ function getBrowserSpellcheckLanguage() {
218
+ if (typeof navigator === 'undefined') return 'en-US'; // Get browser language preferences
219
+
220
+ var languages = navigator.languages || [navigator.language || navigator.userLanguage || 'en-US']; // Find first available language
221
+
222
+ var _iterator = _createForOfIteratorHelper(languages),
223
+ _step;
224
+
225
+ try {
226
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
227
+ var lang = _step.value;
228
+ var normalized = lang.toLowerCase(); // Direct match
229
+
230
+ if (AVAILABLE_DICTIONARIES[lang]) return lang; // Match by prefix (e.g., 'en-US' matches 'en')
231
+
232
+ var prefix = normalized.split('-')[0];
233
+ if (AVAILABLE_DICTIONARIES[prefix]) return prefix; // Match by full language code
234
+
235
+ if (AVAILABLE_DICTIONARIES[normalized]) return normalized;
236
+ }
237
+ } catch (err) {
238
+ _iterator.e(err);
239
+ } finally {
240
+ _iterator.f();
241
+ }
242
+
243
+ return 'en-US'; // fallback
244
+ } // Enhanced language detection with priority: spellcheck setting → text analysis → browser settings
245
+
246
+
247
+ function detectLanguage(text) {
248
+ var browserLang = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
249
+ var spellcheckLang = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
250
+
251
+ // console.log(`Language detection inputs - browserLang: ${browserLang}, spellcheckLang: ${spellcheckLang}, text length: ${text ? text.length : 0}`)
252
+ // Priority 1: Use explicit spellcheck language setting if available
253
+ if (spellcheckLang && AVAILABLE_DICTIONARIES[spellcheckLang]) {
254
+ console.log("Using explicit spellcheck language: ".concat(spellcheckLang));
255
+ return spellcheckLang;
256
+ } // Priority 2: Detect from text content if available
257
+
258
+
259
+ if (text) {
260
+ // Check for Czech-specific characters first (highest priority for distinctive characters)
261
+ var czechChars = text.match(/[áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ]/g) || [];
262
+ var czechScore = czechChars.length; // Check for Slovak-specific characters
263
+
264
+ var slovakChars = text.match(/[áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ]/g) || [];
265
+ var slovakScore = slovakChars.length; // Check for Portuguese-specific characters (including Brazilian Portuguese)
266
+
267
+ var portugueseChars = text.match(/[áàâãäéêëíîïóôõöúûüçÁÀÂÃÄÉÊËÍÎÏÓÔÕÖÚÛÜÇ]/g) || [];
268
+ var portugueseScore = portugueseChars.length; // Check for Macedonian-specific Cyrillic characters
269
+ // Macedonian uses letters like ѓ (U+0453), ќ (U+045C), ѕ (U+0455), џ (U+045F), ј (U+0458)
270
+ // and their uppercase counterparts Ѓ (U+0403), Ќ (U+040C), Ѕ (U+0405), Џ (U+040F), Ј (U+0408)
271
+ // We also include the broader Cyrillic range to capture words.
272
+
273
+ var macedonianChars = text.match(/[ЃЌЅЏЈѓќѕџјА-Яа-яЀ-Џѐ-џ]/g) || [];
274
+ var macedonianScore = macedonianChars.length; // console.log(`Language detection scores - Czech: ${czechScore}, Slovak: ${slovakScore}, Portuguese: ${portugueseScore}`)
275
+ // Find the language with the highest score
276
+
277
+ var languageScores = [{
278
+ lang: 'cs-CZ',
279
+ score: czechScore,
280
+ name: 'Czech'
281
+ }, {
282
+ lang: 'sk-SK',
283
+ score: slovakScore,
284
+ name: 'Slovak'
285
+ }, {
286
+ lang: 'pt-BR',
287
+ score: portugueseScore,
288
+ name: 'Portuguese'
289
+ }, {
290
+ lang: 'mk-MK',
291
+ score: macedonianScore,
292
+ name: 'Macedonian'
293
+ }]; // Filter out languages with no score and check if dictionary is available
294
+
295
+ var validLanguages = languageScores.filter(function (lang) {
296
+ return lang.score > 0 && AVAILABLE_DICTIONARIES[lang.lang];
297
+ });
298
+
299
+ if (validLanguages.length > 0) {
300
+ // Sort by score (highest first) and return the top language
301
+ var bestMatch = validLanguages.sort(function (a, b) {
302
+ return b.score - a.score;
303
+ })[0]; // console.log(`Detected language from text: ${bestMatch.lang} (${bestMatch.name} diacritics: ${bestMatch.score})`)
304
+
305
+ return bestMatch.lang;
306
+ } // If we have text but no distinctive diacritics, it's likely English
307
+
308
+
309
+ if (text.trim().length > 0) {
310
+ // console.log(`Detected language from text: en-US (no distinctive diacritics found)`)
311
+ return 'en-US';
312
+ }
313
+ } // Priority 3: Fall back to browser language if available
314
+
315
+
316
+ if (browserLang && AVAILABLE_DICTIONARIES[browserLang]) {
317
+ console.log("Using browser language: ".concat(browserLang));
318
+ return browserLang;
319
+ } // Final fallback
320
+
321
+
322
+ console.log('Using default language: en-US');
323
+ return 'en-US';
324
+ }
325
+
326
+ export function findMisspellings(_x) {
327
+ return _findMisspellings.apply(this, arguments);
328
+ }
329
+
330
+ function _findMisspellings() {
331
+ _findMisspellings = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(text) {
332
+ var lang,
333
+ browserLang,
334
+ spellcheckLang,
335
+ detectedLang,
336
+ spell,
337
+ wordRegex,
338
+ words,
339
+ miss,
340
+ _iterator2,
341
+ _step2,
342
+ w,
343
+ word,
344
+ _args3 = arguments;
345
+
346
+ return _regeneratorRuntime.wrap(function _callee3$(_context3) {
347
+ while (1) {
348
+ switch (_context3.prev = _context3.next) {
349
+ case 0:
350
+ lang = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : 'auto';
351
+ _context3.prev = 1;
352
+ // Get browser language preferences
353
+ browserLang = getBrowserSpellcheckLanguage(); // Get spellcheck language setting
354
+
355
+ spellcheckLang = getSpellcheckLanguage(); // Auto-detect language if not specified
356
+
357
+ detectedLang = lang === 'auto' ? detectLanguage(text, browserLang, spellcheckLang) : lang; // Check if dictionary is available
358
+
359
+ if (AVAILABLE_DICTIONARIES[detectedLang]) {
360
+ _context3.next = 8;
361
+ break;
362
+ }
363
+
364
+ console.warn("Dictionary not available for ".concat(detectedLang, ", skipping spellcheck"));
365
+ return _context3.abrupt("return", []);
366
+
367
+ case 8:
368
+ _context3.next = 10;
369
+ return getSpell(detectedLang);
370
+
371
+ case 10:
372
+ spell = _context3.sent;
373
+ // Unicode-aware word extraction across scripts (Latin, Cyrillic, etc.)
374
+ // Matches sequences of letters, allowing internal apostrophes/dashes.
375
+ wordRegex = /(?:[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDEC0-\uDEEB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])(?:['\x2DA-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2019\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDEC0-\uDEEB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])*/g;
376
+ words = text.match(wordRegex) || [];
377
+ miss = new Set();
378
+ _iterator2 = _createForOfIteratorHelper(words);
379
+ _context3.prev = 15;
380
+
381
+ _iterator2.s();
382
+
383
+ case 17:
384
+ if ((_step2 = _iterator2.n()).done) {
385
+ _context3.next = 25;
386
+ break;
387
+ }
388
+
389
+ w = _step2.value;
390
+ word = w.replace(/^'+|'+$/g, '');
391
+
392
+ if (word) {
393
+ _context3.next = 22;
394
+ break;
395
+ }
396
+
397
+ return _context3.abrupt("continue", 23);
398
+
399
+ case 22:
400
+ if (!spell.correct(word)) miss.add(word);
401
+
402
+ case 23:
403
+ _context3.next = 17;
404
+ break;
405
+
406
+ case 25:
407
+ _context3.next = 30;
408
+ break;
409
+
410
+ case 27:
411
+ _context3.prev = 27;
412
+ _context3.t0 = _context3["catch"](15);
413
+
414
+ _iterator2.e(_context3.t0);
415
+
416
+ case 30:
417
+ _context3.prev = 30;
418
+
419
+ _iterator2.f();
420
+
421
+ return _context3.finish(30);
422
+
423
+ case 33:
424
+ return _context3.abrupt("return", Array.from(miss));
425
+
426
+ case 36:
427
+ _context3.prev = 36;
428
+ _context3.t1 = _context3["catch"](1);
429
+ console.warn("Spellcheck failed for language ".concat(lang, ":"), _context3.t1);
430
+ return _context3.abrupt("return", []);
431
+
432
+ case 40:
433
+ case "end":
434
+ return _context3.stop();
435
+ }
436
+ }
437
+ }, _callee3, null, [[1, 36], [15, 27, 30, 33]]);
438
+ }));
439
+ return _findMisspellings.apply(this, arguments);
440
+ }
441
+
442
+ export function highlightMisspellingsInHtml(_x2) {
443
+ return _highlightMisspellingsInHtml.apply(this, arguments);
444
+ }
445
+
446
+ function _highlightMisspellingsInHtml() {
447
+ _highlightMisspellingsInHtml = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(html) {
448
+ var lang,
449
+ textForSpellcheck,
450
+ browserLang,
451
+ spellcheckLang,
452
+ detectedLang,
453
+ miss,
454
+ segments,
455
+ wrapped,
456
+ _args4 = arguments;
457
+ return _regeneratorRuntime.wrap(function _callee4$(_context4) {
458
+ while (1) {
459
+ switch (_context4.prev = _context4.next) {
460
+ case 0:
461
+ lang = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : 'auto';
462
+
463
+ if (html) {
464
+ _context4.next = 3;
465
+ break;
466
+ }
467
+
468
+ return _context4.abrupt("return", html);
469
+
470
+ case 3:
471
+ _context4.prev = 3;
472
+ // Decode HTML entities for spellchecking, but preserve original HTML
473
+ textForSpellcheck = html.replace(/<[^>]+>/g, ' ') // strip tags
474
+ .replace(/&nbsp;/g, ' ') // convert non-breaking spaces to regular spaces
475
+ .replace(/&[a-zA-Z0-9#]+;/g, ' ') // remove other HTML entities
476
+ .replace(/\s+/g, ' ') // normalize whitespace
477
+ .trim();
478
+ browserLang = getBrowserSpellcheckLanguage();
479
+ spellcheckLang = getSpellcheckLanguage();
480
+ detectedLang = lang === 'auto' ? detectLanguage(textForSpellcheck, browserLang, spellcheckLang) : lang; // Check if dictionary is available
481
+
482
+ if (AVAILABLE_DICTIONARIES[detectedLang]) {
483
+ _context4.next = 11;
484
+ break;
485
+ }
486
+
487
+ console.warn("Dictionary not available for ".concat(detectedLang, ", skipping spellcheck"));
488
+ return _context4.abrupt("return", html);
489
+
490
+ case 11:
491
+ _context4.next = 13;
492
+ return findMisspellings(textForSpellcheck, detectedLang);
493
+
494
+ case 13:
495
+ miss = _context4.sent;
496
+
497
+ if (!(miss.length === 0)) {
498
+ _context4.next = 16;
499
+ break;
500
+ }
501
+
502
+ return _context4.abrupt("return", html);
503
+
504
+ case 16:
505
+ // Replace whole-word occurrences with span wrapper. Do not touch inside tags or HTML entities
506
+ // We split on tags and HTML entities, only operate on text segments.
507
+ segments = html.split(/(<[^>]+>|&[a-zA-Z0-9#]+;)/g);
508
+ wrapped = segments.map(function (seg) {
509
+ if (/^<[^>]+>$/.test(seg) || /^&[a-zA-Z0-9#]+;$/.test(seg)) {
510
+ return seg; // tag or HTML entity segment - leave unchanged
511
+ }
512
+
513
+ var out = seg;
514
+
515
+ var _iterator3 = _createForOfIteratorHelper(miss),
516
+ _step3;
517
+
518
+ try {
519
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
520
+ var m = _step3.value;
521
+ // Use Unicode-aware boundaries: ensure preceding/following chars are not letters
522
+ var re = new RegExp("(?<!\\p{L})".concat(escapeRegExp(m), "(?!\\p{L})"), 'gu');
523
+ out = out.replace(re, "<span class=\"spell-error\">$&</span>");
524
+ }
525
+ } catch (err) {
526
+ _iterator3.e(err);
527
+ } finally {
528
+ _iterator3.f();
529
+ }
530
+
531
+ return out;
532
+ });
533
+ return _context4.abrupt("return", wrapped.join(''));
534
+
535
+ case 21:
536
+ _context4.prev = 21;
537
+ _context4.t0 = _context4["catch"](3);
538
+ console.warn('Spellcheck failed, returning original HTML:', _context4.t0);
539
+ return _context4.abrupt("return", html);
540
+
541
+ case 25:
542
+ case "end":
543
+ return _context4.stop();
544
+ }
545
+ }
546
+ }, _callee4, null, [[3, 21]]);
547
+ }));
548
+ return _highlightMisspellingsInHtml.apply(this, arguments);
549
+ }
550
+
551
+ function escapeRegExp(s) {
552
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
553
+ }