@cachly-dev/mcp-server 0.10.129 → 0.10.131

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 (223) hide show
  1. package/README.md +2 -2
  2. package/dist/index.js +1 -7
  3. package/dist/packages/telegram-notify/client.js +2 -75
  4. package/dist/src/ambient-cli.js +7 -253
  5. package/dist/src/ambient-deps.js +1 -55
  6. package/dist/src/ambient-hooks.js +5 -278
  7. package/dist/src/ambient-ledger.js +6 -95
  8. package/dist/src/ambient-memory.js +1 -67
  9. package/dist/src/ambient-recall.js +1 -221
  10. package/dist/src/aussetzer.js +1 -225
  11. package/dist/src/auth.js +9 -140
  12. package/dist/src/autor-abzeichen.js +1 -56
  13. package/dist/src/autor.js +1 -136
  14. package/dist/src/bauabdruck.js +1 -93
  15. package/dist/src/bedeutung.js +2 -323
  16. package/dist/src/bench/cachly-bench.js +4 -249
  17. package/dist/src/bench/external-corpus.js +4 -135
  18. package/dist/src/bench/fixtures.js +1 -225
  19. package/dist/src/brain-export.js +16 -119
  20. package/dist/src/brain-watch-hook.js +8 -86
  21. package/dist/src/cachly-url.js +1 -21
  22. package/dist/src/ckg.js +1 -108
  23. package/dist/src/cls-hook.js +8 -94
  24. package/dist/src/confidence.js +1 -50
  25. package/dist/src/credentials.js +1 -85
  26. package/dist/src/deutsch.js +1 -223
  27. package/dist/src/doctor.js +2 -248
  28. package/dist/src/editor.js +1 -63
  29. package/dist/src/eingaenge-nachruesten.js +1 -290
  30. package/dist/src/eingaenge.js +2 -260
  31. package/dist/src/embeddings.js +13 -223
  32. package/dist/src/feldreparatur.js +3 -113
  33. package/dist/src/first-contact.js +4 -108
  34. package/dist/src/first-recall-proof.js +4 -41
  35. package/dist/src/funnel-milestones.js +2 -48
  36. package/dist/src/geliefert.js +1 -114
  37. package/dist/src/handlers/advanced.js +38 -537
  38. package/dist/src/handlers/brain.js +69 -4397
  39. package/dist/src/handlers/cache.js +59 -638
  40. package/dist/src/handlers/context.js +17 -182
  41. package/dist/src/handlers/fedbrain.js +40 -1436
  42. package/dist/src/handlers/instances.js +16 -201
  43. package/dist/src/handlers/roadmap.js +13 -175
  44. package/dist/src/handlers/share.js +19 -530
  45. package/dist/src/handlers/syndicate.js +38 -904
  46. package/dist/src/handlers/team.js +89 -1865
  47. package/dist/src/handlers/viz.js +3 -148
  48. package/dist/src/index.js +321 -4281
  49. package/dist/src/interferenz.js +1 -141
  50. package/dist/src/kostprobe.js +7 -125
  51. package/dist/src/lesson-preview.js +2 -133
  52. package/dist/src/namespace.js +1 -128
  53. package/dist/src/notifier.js +1 -6
  54. package/dist/src/rangfolge-stellschrauben.js +1 -0
  55. package/dist/src/rangfolge.js +1 -249
  56. package/dist/src/raumkorrektur.js +1 -197
  57. package/dist/src/recall-tiefe.js +1 -42
  58. package/dist/src/rerank.js +1 -154
  59. package/dist/src/resonanz.js +1 -140
  60. package/dist/src/search.js +1 -2104
  61. package/dist/src/seltenheitsbestand.js +1 -92
  62. package/dist/src/speicherlage.js +1 -84
  63. package/dist/src/spuren.js +1 -150
  64. package/dist/src/starter-corpus.js +1 -165
  65. package/dist/src/telemetry-types.js +0 -13
  66. package/dist/src/tools.js +10 -2465
  67. package/dist/src/toolspecs.js +1 -121
  68. package/dist/src/upgrade-nudge.js +1 -29
  69. package/dist/src/utils.js +1 -89
  70. package/dist/src/versuch.js +1 -264
  71. package/dist/src/vorspann.js +1 -146
  72. package/dist/src/wartung/vektoren-verdichten.js +1 -200
  73. package/dist/src/werkzeug-nutzung.js +1 -72
  74. package/dist/src/wertbeitrag.js +1 -203
  75. package/dist/src/wirkungsspur.js +1 -0
  76. package/glama.json +1 -1
  77. package/package.json +8 -7
  78. package/server.json +3 -3
  79. package/dist/index.d.ts +0 -1
  80. package/dist/index.js.map +0 -1
  81. package/dist/packages/telegram-notify/client.d.ts +0 -19
  82. package/dist/packages/telegram-notify/client.js.map +0 -1
  83. package/dist/src/ambient-cli.d.ts +0 -101
  84. package/dist/src/ambient-cli.js.map +0 -1
  85. package/dist/src/ambient-deps.d.ts +0 -26
  86. package/dist/src/ambient-deps.js.map +0 -1
  87. package/dist/src/ambient-hooks.d.ts +0 -137
  88. package/dist/src/ambient-hooks.js.map +0 -1
  89. package/dist/src/ambient-ledger.d.ts +0 -19
  90. package/dist/src/ambient-ledger.js.map +0 -1
  91. package/dist/src/ambient-memory.d.ts +0 -12
  92. package/dist/src/ambient-memory.js.map +0 -1
  93. package/dist/src/ambient-recall.d.ts +0 -127
  94. package/dist/src/ambient-recall.js.map +0 -1
  95. package/dist/src/aussetzer.d.ts +0 -156
  96. package/dist/src/aussetzer.js.map +0 -1
  97. package/dist/src/auth.d.ts +0 -43
  98. package/dist/src/auth.js.map +0 -1
  99. package/dist/src/autor-abzeichen.d.ts +0 -41
  100. package/dist/src/autor-abzeichen.js.map +0 -1
  101. package/dist/src/autor.d.ts +0 -101
  102. package/dist/src/autor.js.map +0 -1
  103. package/dist/src/bauabdruck-daten.generiert.json +0 -5
  104. package/dist/src/bauabdruck.d.ts +0 -38
  105. package/dist/src/bauabdruck.js.map +0 -1
  106. package/dist/src/bedeutung.d.ts +0 -168
  107. package/dist/src/bedeutung.js.map +0 -1
  108. package/dist/src/bench/cachly-bench.d.ts +0 -61
  109. package/dist/src/bench/cachly-bench.js.map +0 -1
  110. package/dist/src/bench/external-corpus.d.ts +0 -44
  111. package/dist/src/bench/external-corpus.js.map +0 -1
  112. package/dist/src/bench/fixtures.d.ts +0 -37
  113. package/dist/src/bench/fixtures.js.map +0 -1
  114. package/dist/src/brain-export.d.ts +0 -64
  115. package/dist/src/brain-export.js.map +0 -1
  116. package/dist/src/brain-watch-hook.d.ts +0 -21
  117. package/dist/src/brain-watch-hook.js.map +0 -1
  118. package/dist/src/cachly-url.d.ts +0 -68
  119. package/dist/src/cachly-url.js.map +0 -1
  120. package/dist/src/ckg.d.ts +0 -54
  121. package/dist/src/ckg.js.map +0 -1
  122. package/dist/src/cls-hook.d.ts +0 -15
  123. package/dist/src/cls-hook.js.map +0 -1
  124. package/dist/src/confidence.d.ts +0 -19
  125. package/dist/src/confidence.js.map +0 -1
  126. package/dist/src/credentials.d.ts +0 -37
  127. package/dist/src/credentials.js.map +0 -1
  128. package/dist/src/deutsch.d.ts +0 -98
  129. package/dist/src/deutsch.js.map +0 -1
  130. package/dist/src/doctor.d.ts +0 -47
  131. package/dist/src/doctor.js.map +0 -1
  132. package/dist/src/editor.d.ts +0 -9
  133. package/dist/src/editor.js.map +0 -1
  134. package/dist/src/eingaenge-nachruesten.d.ts +0 -41
  135. package/dist/src/eingaenge-nachruesten.js.map +0 -1
  136. package/dist/src/eingaenge.d.ts +0 -159
  137. package/dist/src/eingaenge.js.map +0 -1
  138. package/dist/src/embeddings.d.ts +0 -48
  139. package/dist/src/embeddings.js.map +0 -1
  140. package/dist/src/feldreparatur.d.ts +0 -58
  141. package/dist/src/feldreparatur.js.map +0 -1
  142. package/dist/src/first-contact.d.ts +0 -56
  143. package/dist/src/first-contact.js.map +0 -1
  144. package/dist/src/first-recall-proof.d.ts +0 -19
  145. package/dist/src/first-recall-proof.js.map +0 -1
  146. package/dist/src/funnel-milestones.d.ts +0 -5
  147. package/dist/src/funnel-milestones.js.map +0 -1
  148. package/dist/src/geliefert.d.ts +0 -63
  149. package/dist/src/geliefert.js.map +0 -1
  150. package/dist/src/handlers/advanced.d.ts +0 -6
  151. package/dist/src/handlers/advanced.js.map +0 -1
  152. package/dist/src/handlers/brain.d.ts +0 -41
  153. package/dist/src/handlers/brain.js.map +0 -1
  154. package/dist/src/handlers/cache.d.ts +0 -6
  155. package/dist/src/handlers/cache.js.map +0 -1
  156. package/dist/src/handlers/context.d.ts +0 -6
  157. package/dist/src/handlers/context.js.map +0 -1
  158. package/dist/src/handlers/fedbrain.d.ts +0 -18
  159. package/dist/src/handlers/fedbrain.js.map +0 -1
  160. package/dist/src/handlers/instances.d.ts +0 -33
  161. package/dist/src/handlers/instances.js.map +0 -1
  162. package/dist/src/handlers/roadmap.d.ts +0 -6
  163. package/dist/src/handlers/roadmap.js.map +0 -1
  164. package/dist/src/handlers/share.d.ts +0 -8
  165. package/dist/src/handlers/share.js.map +0 -1
  166. package/dist/src/handlers/syndicate.d.ts +0 -6
  167. package/dist/src/handlers/syndicate.js.map +0 -1
  168. package/dist/src/handlers/team.d.ts +0 -45
  169. package/dist/src/handlers/team.js.map +0 -1
  170. package/dist/src/handlers/viz.d.ts +0 -6
  171. package/dist/src/handlers/viz.js.map +0 -1
  172. package/dist/src/index.d.ts +0 -93
  173. package/dist/src/index.js.map +0 -1
  174. package/dist/src/interferenz.d.ts +0 -111
  175. package/dist/src/interferenz.js.map +0 -1
  176. package/dist/src/kostprobe.d.ts +0 -25
  177. package/dist/src/kostprobe.js.map +0 -1
  178. package/dist/src/lesson-preview.d.ts +0 -81
  179. package/dist/src/lesson-preview.js.map +0 -1
  180. package/dist/src/namespace.d.ts +0 -20
  181. package/dist/src/namespace.js.map +0 -1
  182. package/dist/src/notifier.d.ts +0 -5
  183. package/dist/src/notifier.js.map +0 -1
  184. package/dist/src/rangfolge.d.ts +0 -205
  185. package/dist/src/rangfolge.js.map +0 -1
  186. package/dist/src/raumkorrektur.d.ts +0 -100
  187. package/dist/src/raumkorrektur.js.map +0 -1
  188. package/dist/src/recall-tiefe.d.ts +0 -48
  189. package/dist/src/recall-tiefe.js.map +0 -1
  190. package/dist/src/rerank.d.ts +0 -48
  191. package/dist/src/rerank.js.map +0 -1
  192. package/dist/src/resonanz.d.ts +0 -85
  193. package/dist/src/resonanz.js.map +0 -1
  194. package/dist/src/search.d.ts +0 -153
  195. package/dist/src/search.js.map +0 -1
  196. package/dist/src/seltenheitsbestand.d.ts +0 -53
  197. package/dist/src/seltenheitsbestand.js.map +0 -1
  198. package/dist/src/speicherlage.d.ts +0 -51
  199. package/dist/src/speicherlage.js.map +0 -1
  200. package/dist/src/spuren.d.ts +0 -97
  201. package/dist/src/spuren.js.map +0 -1
  202. package/dist/src/starter-corpus.d.ts +0 -28
  203. package/dist/src/starter-corpus.js.map +0 -1
  204. package/dist/src/telemetry-types.d.ts +0 -87
  205. package/dist/src/telemetry-types.js.map +0 -1
  206. package/dist/src/tools.d.ts +0 -2933
  207. package/dist/src/tools.js.map +0 -1
  208. package/dist/src/toolspecs.d.ts +0 -43
  209. package/dist/src/toolspecs.js.map +0 -1
  210. package/dist/src/upgrade-nudge.d.ts +0 -15
  211. package/dist/src/upgrade-nudge.js.map +0 -1
  212. package/dist/src/utils.d.ts +0 -34
  213. package/dist/src/utils.js.map +0 -1
  214. package/dist/src/versuch.d.ts +0 -187
  215. package/dist/src/versuch.js.map +0 -1
  216. package/dist/src/vorspann.d.ts +0 -73
  217. package/dist/src/vorspann.js.map +0 -1
  218. package/dist/src/wartung/vektoren-verdichten.d.ts +0 -50
  219. package/dist/src/wartung/vektoren-verdichten.js.map +0 -1
  220. package/dist/src/werkzeug-nutzung.d.ts +0 -62
  221. package/dist/src/werkzeug-nutzung.js.map +0 -1
  222. package/dist/src/wertbeitrag.d.ts +0 -148
  223. package/dist/src/wertbeitrag.js.map +0 -1
@@ -1,2104 +1 @@
1
- // ── Search Engine (BM25+ with enhancements, works without embedding) ──────────
2
- //
3
- // Features beyond standard BM25:
4
- // • BM25+ (delta=1) — fixes BM25's "long document penalty" bug
5
- // • Bigram proximity boost — adjacent query terms in doc score 2× more
6
- // • Recency boost — newer entries rank higher (exponential decay, 7-day half-life)
7
- // • Multi-query splitting — numbered lists, semicolons, conjunctions
8
- // • Fuzzy matching with Levenshtein distance ≤ 2
9
- // • Multilingual stopwords (EN, DE, FR, ES, IT, PT, ZH, JA, KO, AR, HE)
10
- // • CJK character bigram extraction — handles Chinese, Japanese, Korean
11
- // • RTL language support (Arabic, Hebrew) — word tokenization + light stemming
12
- // • Romanization matching — katakana → romaji tokens for romaji queries
13
- // • Cross-language retrieval — tech term synonyms EN↔JA↔ZH↔KO↔AR↔HE
14
- // • Pipeline Redis reads for performance
15
- //
16
- /**
17
- * Stopwords — filtered out during tokenization.
18
- * Covers: English, German, French, Spanish, Italian, Portuguese,
19
- * Chinese (Simplified + Traditional), Japanese, Korean.
20
- * Keeps the index small and scores meaningful.
21
- */
22
- const STOPWORDS = new Set([
23
- // ── English ──
24
- 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
25
- 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing',
26
- 'will', 'would', 'could', 'should', 'may', 'might', 'shall', 'can',
27
- 'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'as',
28
- 'into', 'through', 'during', 'before', 'after', 'above', 'below',
29
- 'between', 'about', 'against', 'among', 'around', 'without', 'within',
30
- 'along', 'across', 'behind', 'beyond', 'upon', 'toward', 'towards',
31
- 'and', 'but', 'or', 'not', 'no', 'nor', 'so', 'if', 'then', 'than',
32
- 'too', 'very', 'quite', 'rather', 'just', 'also', 'only', 'even',
33
- 'it', 'its', 'this', 'that', 'these', 'those', 'here', 'there',
34
- 'my', 'your', 'his', 'her', 'our', 'their', 'mine', 'yours', 'ours',
35
- 'what', 'which', 'who', 'whom', 'whose', 'how', 'when', 'where', 'why',
36
- 'all', 'each', 'every', 'both', 'few', 'more', 'most', 'much', 'many',
37
- 'other', 'some', 'such', 'own', 'same', 'any', 'either', 'neither',
38
- 'been', 'being', 'because', 'until', 'while', 'once', 'again', 'further',
39
- 'already', 'always', 'never', 'sometimes', 'often', 'still', 'yet',
40
- // ── German ──
41
- 'der', 'die', 'das', 'den', 'dem', 'des', 'ein', 'eine', 'einen',
42
- 'einem', 'einer', 'eines', 'und', 'oder', 'aber', 'denn', 'weil',
43
- 'ist', 'sind', 'war', 'waren', 'sein', 'wird', 'werden', 'wurde',
44
- 'hat', 'haben', 'hatte', 'hatten', 'kann', 'können', 'konnte',
45
- 'soll', 'sollen', 'sollte', 'muss', 'müssen', 'musste', 'darf',
46
- 'mag', 'möchte', 'wollen', 'wollte', 'würde', 'könnte', 'sollte',
47
- 'mit', 'für', 'auf', 'von', 'aus', 'bei', 'nach', 'über', 'unter',
48
- 'vor', 'hinter', 'neben', 'zwischen', 'durch', 'gegen', 'ohne',
49
- 'um', 'bis', 'seit', 'während', 'wegen', 'trotz', 'statt',
50
- 'wie', 'was', 'wer', 'wen', 'wem', 'wessen', 'wo', 'wann', 'warum',
51
- 'nicht', 'noch', 'auch', 'schon', 'nur', 'sehr', 'mehr', 'viel',
52
- 'alle', 'jeder', 'jede', 'jedes', 'dieser', 'diese', 'dieses',
53
- 'jener', 'jene', 'jenes', 'mein', 'dein', 'sein', 'ihr', 'unser',
54
- 'euer', 'kein', 'keine', 'sich', 'mir', 'dir', 'ihm', 'uns', 'euch',
55
- 'ich', 'du', 'er', 'sie', 'es', 'wir', 'ihr', 'man',
56
- 'hier', 'dort', 'da', 'dann', 'also', 'doch', 'mal', 'eben', 'ganz',
57
- // ── French ──
58
- 'le', 'la', 'les', 'un', 'une', 'des', 'du', 'de', 'au', 'aux',
59
- 'et', 'ou', 'mais', 'donc', 'car', 'ni', 'que', 'qui', 'quoi',
60
- 'est', 'sont', 'était', 'ont', 'avoir', 'être', 'fait', 'faire',
61
- 'pour', 'par', 'avec', 'dans', 'sur', 'sous', 'entre', 'vers',
62
- 'chez', 'sans', 'avant', 'après', 'pendant', 'depuis', 'contre',
63
- 'ce', 'cette', 'ces', 'mon', 'ton', 'son', 'notre', 'votre', 'leur',
64
- 'je', 'tu', 'il', 'elle', 'nous', 'vous', 'ils', 'elles', 'on',
65
- 'ne', 'pas', 'plus', 'très', 'bien', 'aussi', 'tout', 'tous', 'toute',
66
- 'même', 'autre', 'quel', 'quelle', 'comment', 'quand', 'où', 'pourquoi',
67
- // ── Spanish ──
68
- 'el', 'la', 'los', 'las', 'un', 'una', 'unos', 'unas', 'del', 'al',
69
- 'lo', 'que', 'en', 'es', 'por', 'con', 'para', 'como', 'pero', 'más',
70
- 'fue', 'ser', 'hay', 'está', 'han', 'son', 'tiene', 'había', 'era',
71
- 'su', 'sus', 'este', 'esta', 'estos', 'estas', 'ese', 'esa', 'esos',
72
- 'mi', 'tu', 'yo', 'él', 'ella', 'nosotros', 'ellos', 'ellas', 'usted',
73
- 'no', 'ya', 'sí', 'sin', 'sobre', 'entre', 'hasta', 'desde', 'donde',
74
- 'muy', 'todo', 'toda', 'todos', 'cada', 'otro', 'otra', 'otros',
75
- 'cuando', 'porque', 'aunque', 'también', 'solo', 'después', 'antes',
76
- // ── Italian ──
77
- 'il', 'lo', 'la', 'li', 'le', 'gli', 'uno', 'una', 'dei', 'del',
78
- 'che', 'di', 'da', 'per', 'con', 'tra', 'fra', 'sul', 'nel', 'al',
79
- 'è', 'sono', 'ha', 'hanno', 'era', 'essere', 'fare', 'fatto', 'stato',
80
- 'suo', 'sua', 'suoi', 'questo', 'questa', 'questi', 'quello', 'quella',
81
- 'io', 'tu', 'lui', 'lei', 'noi', 'voi', 'loro', 'ci', 'si',
82
- 'non', 'più', 'molto', 'anche', 'solo', 'tutto', 'tutti', 'ogni',
83
- 'come', 'dove', 'quando', 'perché', 'ancora', 'già', 'sempre', 'mai',
84
- // ── Portuguese ──
85
- 'um', 'uma', 'uns', 'umas', 'do', 'da', 'dos', 'das', 'no', 'na',
86
- 'ao', 'aos', 'em', 'por', 'com', 'para', 'sem', 'sob', 'sobre',
87
- 'que', 'se', 'mas', 'ou', 'como', 'mais', 'entre', 'até', 'desde',
88
- 'é', 'são', 'foi', 'tem', 'ser', 'ter', 'estar', 'fazer', 'havia',
89
- 'seu', 'sua', 'seus', 'suas', 'este', 'esta', 'esse', 'essa', 'aquele',
90
- 'eu', 'tu', 'ele', 'ela', 'nós', 'eles', 'elas', 'você', 'vocês',
91
- 'não', 'já', 'sim', 'bem', 'muito', 'também', 'ainda', 'sempre',
92
- 'todo', 'toda', 'todos', 'cada', 'outro', 'outra', 'quando', 'porque',
93
- // ── Chinese (Simplified + Traditional) — high-frequency function characters ──
94
- '的', '了', '是', '在', '不', '和', '我', '他', '这', '中', '大', '为',
95
- '上', '个', '国', '以', '要', '就', '出', '说', '们', '有', '来', '到',
96
- '时', '地', '年', '得', '着', '那', '过', '后', '还', '与', '也', '可',
97
- '于', '从', '但', '而', '被', '把', '让', '使', '对', '很', '都', '一',
98
- '会', '没', '人', '它', '这个', '那个', '什么', '如果', '因为', '所以',
99
- '已经', '可以', '这些', '那些', '我们', '他们', '她们', '它们',
100
- // ── Japanese — common hiragana particles and auxiliary verbs ──
101
- 'の', 'は', 'が', 'を', 'に', 'で', 'と', 'も', 'や', 'か', 'な', 'ね',
102
- 'よ', 'わ', 'て', 'い', 'う', 'え', 'お', 'き', 'く', 'け', 'こ', 'さ',
103
- 'し', 'す', 'せ', 'そ', 'た', 'ち', 'つ', 'ぬ', 'ん', 'から', 'まで',
104
- 'より', 'へ', 'です', 'ます', 'ない', 'ある', 'いる', 'する', 'こと',
105
- 'もの', 'ので', 'では', 'には', 'との', 'への', 'から', 'まで',
106
- // ── Korean — common particles and auxiliary forms ──
107
- '이', '가', '은', '는', '을', '를', '의', '에', '와', '과', '도',
108
- '로', '에서', '한', '하', '있', '없', '것', '수', '않', '들',
109
- '이다', '하다', '이고', '이며', '라고', '에게', '에서', '으로',
110
- // ── Arabic — high-frequency function words & particles ──
111
- 'في', 'من', 'إلى', 'على', 'عن', 'مع', 'هذا', 'هذه', 'ذلك', 'تلك',
112
- 'الذي', 'التي', 'الذين', 'اللواتي', 'هو', 'هي', 'هم', 'هن', 'نحن',
113
- 'أنت', 'أنتم', 'أنا', 'كان', 'كانت', 'كانوا', 'يكون', 'تكون',
114
- 'أن', 'إن', 'لأن', 'لكن', 'أو', 'بل', 'ثم', 'حتى', 'إذا', 'كي',
115
- 'قد', 'لقد', 'لم', 'لن', 'ما', 'لا', 'ليس', 'غير', 'بعض', 'كل',
116
- 'جميع', 'أي', 'كيف', 'متى', 'أين', 'لماذا', 'ماذا', 'هل', 'ال',
117
- 'و', 'ف', 'ب', 'ل', 'ك', 'يا', 'أم', 'إلا', 'عند', 'بين',
118
- // ── Hebrew — common particles, pronouns, conjunctions ──
119
- 'של', 'את', 'אל', 'על', 'עם', 'לא', 'הוא', 'היא', 'הם', 'הן',
120
- 'אני', 'אתה', 'אנחנו', 'אתם', 'כי', 'אם', 'אבל', 'גם', 'כבר',
121
- 'רק', 'עוד', 'יש', 'אין', 'מה', 'זה', 'זאת', 'אלה', 'כל', 'כן',
122
- 'לו', 'לה', 'להם', 'בו', 'בה', 'בהם', 'שם', 'כך', 'כן', 'מי',
123
- 'אשר', 'אחרי', 'לפני', 'תחת', 'בין', 'מאז', 'עד', 'כמו', 'אז',
124
- // ── Farsi/Persian — common function words, prepositions, pronouns ──
125
- 'در', 'از', 'به', 'با', 'که', 'این', 'آن', 'را', 'است',
126
- 'بود', 'باشد', 'شد', 'شده', 'می', 'نه', 'نیست', 'هم', 'هر',
127
- 'یک', 'اما', 'و', 'یا', 'تا', 'اگر', 'برای', 'چون', 'چه',
128
- 'کجا', 'کی', 'چطور', 'وقتی', 'بعد', 'قبل', 'مثل', 'همه', 'بعضی',
129
- 'هیچ', 'آیا', 'خود', 'چند', 'دیگر', 'هنوز', 'همان', 'آنها', 'اینها',
130
- 'ما', 'شما', 'آنان', 'من', 'تو', 'او', 'آنان', 'ایشان',
131
- 'روی', 'زیر', 'بین', 'پیش', 'پس', 'طرف', 'داخل', 'خارج', 'کنار',
132
- 'همچنین', 'مگر', 'ولی', 'وگرنه', 'چرا', 'چگونه', 'کدام',
133
- // ── Hindi — common particles, postpositions, pronouns, auxiliary verbs ──
134
- 'है', 'में', 'से', 'को', 'का', 'की', 'के', 'पर', 'और', 'या',
135
- 'नहीं', 'यह', 'वह', 'एक', 'इस', 'उस', 'भी', 'हो', 'था', 'थी',
136
- 'थे', 'हैं', 'हूँ', 'लिए', 'तक', 'साथ', 'बाद', 'पहले', 'जो',
137
- 'जब', 'कैसे', 'क्यों', 'क्या', 'कहाँ', 'कौन', 'हम', 'आप', 'वे',
138
- 'मैं', 'तुम', 'उन', 'इन', 'ने', 'बहुत', 'सब', 'कुछ', 'फिर',
139
- 'अब', 'तो', 'ही', 'तरह', 'जैसे', 'करना', 'होना', 'रहा', 'रही',
140
- 'रहे', 'गया', 'गई', 'गए', 'किया', 'किए', 'कर', 'हुआ', 'हुई',
141
- // ── Russian — common prepositions, pronouns, auxiliary verbs ───────────────
142
- 'в', 'на', 'не', 'с', 'и', 'а', 'но', 'по', 'за', 'из', 'от', 'до',
143
- 'к', 'у', 'о', 'об', 'во', 'при', 'под', 'над', 'без', 'для',
144
- 'что', 'как', 'это', 'все', 'так', 'уже', 'или', 'же', 'ли',
145
- 'если', 'то', 'да', 'нет', 'был', 'была', 'были', 'быть', 'есть',
146
- 'его', 'её', 'их', 'этот', 'эта', 'эти', 'который', 'которая',
147
- 'которые', 'который', 'мой', 'моя', 'мои', 'ваш', 'ваша', 'ваши',
148
- 'он', 'она', 'они', 'мы', 'вы', 'я', 'ты', 'тот', 'та', 'те',
149
- 'очень', 'тоже', 'также', 'когда', 'где', 'как', 'почему', 'зачем',
150
- 'сейчас', 'здесь', 'там', 'потому', 'поэтому', 'чтобы', 'тут',
151
- // ── Turkish — common particles, postpositions, copulas ─────────────────────
152
- 'bir', 'bu', 'şu', 'o', 've', 'ile', 'de', 'da', 'için', 'gibi',
153
- 'ama', 'fakat', 'ancak', 'ya', 'ne', 'ki', 'mi', 'mı', 'mu', 'mü',
154
- 'var', 'yok', 'olan', 'oldu', 'olur', 'olarak', 'ise', 'daha',
155
- 'çok', 'en', 'her', 'hiç', 'bazı', 'tüm', 'bütün', 'hem', 'veya',
156
- 'bu', 'şu', 'ben', 'sen', 'biz', 'siz', 'onlar', 'benim', 'senin',
157
- 'nasıl', 'neden', 'niçin', 'nerede', 'ne', 'hangi', 'kaç',
158
- // ── Polish — common prepositions, pronouns, particles ─────────────────────
159
- 'w', 'na', 'z', 'do', 'się', 'że', 'to', 'jest', 'i', 'a', 'nie',
160
- 'tak', 'jak', 'czy', 'po', 'o', 'ale', 'go', 'mu', 'jej', 'ich',
161
- 'tego', 'tej', 'te', 'ten', 'ta', 'są', 'był', 'była', 'było', 'byli',
162
- 'będzie', 'będą', 'ma', 'mam', 'masz', 'mają', 'ze', 'co', 'już',
163
- 'przez', 'przy', 'za', 'bez', 'nad', 'pod', 'przed', 'po', 'między',
164
- 'kiedy', 'gdzie', 'dlaczego', 'który', 'która', 'które', 'tylko', 'też',
165
- // ── Czech — common words ──────────────────────────────────────────────────
166
- 'v', 'na', 'z', 'do', 'se', 'že', 'to', 'je', 'a', 'ne', 'pro',
167
- 'ale', 'jak', 'by', 'byl', 'být', 'jsem', 'jsou', 'má', 'mám',
168
- 'ten', 'ta', 'ty', 'tato', 'jeho', 'její', 'jejich', 'také', 'jen',
169
- 'kde', 'kdy', 'proč', 'který', 'která', 'které', 'co', 'při', 'bez',
170
- // ── Bengali — common particles, pronouns, verbs ───────────────────────────
171
- 'এই', 'এটি', 'এটা', 'এর', 'তার', 'তারা', 'আমি', 'তুমি', 'সে', 'আমরা',
172
- 'এবং', 'কিন্তু', 'বা', 'না', 'হ্যাঁ', 'যে', 'কি', 'কে', 'কী', 'থেকে',
173
- 'দিয়ে', 'জন্য', 'সাথে', 'মধ্যে', 'উপর', 'নিচে', 'আছে', 'ছিল', 'হয়',
174
- 'করা', 'করে', 'করেছে', 'হবে', 'হয়েছে', 'একটি', 'একটা', 'অনেক', 'সব',
175
- // ── Vietnamese — common particles, pronouns, auxiliary words ─────────────
176
- 'tôi', 'bạn', 'anh', 'chị', 'em', 'họ', 'chúng', 'ta', 'mình',
177
- 'là', 'có', 'không', 'và', 'với', 'của', 'cho', 'trong', 'về',
178
- 'từ', 'đến', 'để', 'khi', 'nếu', 'thì', 'mà', 'nhưng', 'vì',
179
- 'đây', 'đó', 'này', 'kia', 'rất', 'cũng', 'đã', 'sẽ', 'đang',
180
- 'được', 'bị', 'những', 'các', 'một', 'hai', 'ba', 'nhiều', 'ít',
181
- 'nào', 'ai', 'gì', 'đâu', 'sao', 'bao', 'giờ', 'lúc', 'sau',
182
- ]);
183
- // CJK Unicode ranges used for bigram extraction
184
- const CJK_RE = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/;
185
- const SEGMENT_RE = /([\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+|[^\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+)/g;
186
- // RTL Unicode ranges: Arabic (U+0600–U+06FF + extended), Hebrew (U+0590–U+05FF)
187
- const RTL_RE = /[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufb4f\ufb50-\ufdff\ufe70-\ufeff]/;
188
- // Distinguish Arabic from Hebrew within RTL segments
189
- const HEBREW_CHAR_RE = /[\u0590-\u05ff\ufb1d-\ufb4f]/;
190
- const _ARABIC_CHAR_RE = /[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb50-\ufdff\ufe70-\ufeff]/;
191
- // Persian/Farsi: exclusive chars not in Arabic (U+067E=پ, U+0686=چ, U+0698=ژ, U+06AF=گ, U+06CC=ی)
192
- const FARSI_CHAR_RE = /[\u067e\u0686\u0698\u06af\u06cc]/;
193
- // Devanagari (Hindi, Sanskrit, Marathi …) — U+0900–U+097F + extended
194
- const DEVANAGARI_RE = /[\u0900-\u097f]/;
195
- // Cyrillic (Russian, Bulgarian, Ukrainian, Serbian …) — U+0400–U+04FF
196
- const CYRILLIC_RE = /[\u0400-\u04ff]/;
197
- // Turkish uses Latin alphabet but has unique chars (ğ, ş, ı, ö, ü, ç) — detected by these
198
- const TURKISH_CHAR_RE = /[\u011f\u015f\u0131\u0130\u00e7]/; // ğ ş ı İ ç
199
- // Bengali (Bangla) — U+0980–U+09FF
200
- const BENGALI_RE = /[\u0980-\u09ff]/;
201
- // Vietnamese uses Latin + Latin Extended Additional (U+1EA0–U+1EF9) for tone marks
202
- // e.g. ắ ặ ầ ổ ợ ụ ừ — detected by chars exclusive to Vietnamese diacritics
203
- const _VIETNAMESE_CHAR_RE = /[\u1ea0-\u1ef9]/;
204
- // ── Katakana → Romaji conversion table (Hepburn system) ──────────────────────
205
- // Digraphs must be listed before single chars so they match first.
206
- const KATA_ROMAJI_TABLE = [
207
- // Special combinations for loanwords
208
- ['ファ', 'fa'], ['フィ', 'fi'], ['フェ', 'fe'], ['フォ', 'fo'],
209
- ['ティ', 'ti'], ['ディ', 'di'], ['トゥ', 'tu'], ['ドゥ', 'du'],
210
- ['ウィ', 'wi'], ['ウェ', 'we'], ['ウォ', 'wo'],
211
- ['チェ', 'che'], ['ジェ', 'je'], ['シェ', 'she'],
212
- ['イェ', 'ye'], ['ヴァ', 'va'], ['ヴィ', 'vi'], ['ヴェ', 've'], ['ヴォ', 'vo'],
213
- // Digraphs (2-char → romaji)
214
- ['キャ', 'kya'], ['キュ', 'kyu'], ['キョ', 'kyo'],
215
- ['シャ', 'sha'], ['シュ', 'shu'], ['ショ', 'sho'],
216
- ['チャ', 'cha'], ['チュ', 'chu'], ['チョ', 'cho'],
217
- ['ニャ', 'nya'], ['ニュ', 'nyu'], ['ニョ', 'nyo'],
218
- ['ヒャ', 'hya'], ['ヒュ', 'hyu'], ['ヒョ', 'hyo'],
219
- ['ミャ', 'mya'], ['ミュ', 'myu'], ['ミョ', 'myo'],
220
- ['リャ', 'rya'], ['リュ', 'ryu'], ['リョ', 'ryo'],
221
- ['ギャ', 'gya'], ['ギュ', 'gyu'], ['ギョ', 'gyo'],
222
- ['ジャ', 'ja'], ['ジュ', 'ju'], ['ジョ', 'jo'],
223
- ['ビャ', 'bya'], ['ビュ', 'byu'], ['ビョ', 'byo'],
224
- ['ピャ', 'pya'], ['ピュ', 'pyu'], ['ピョ', 'pyo'],
225
- // Single chars
226
- ['ア', 'a'], ['イ', 'i'], ['ウ', 'u'], ['エ', 'e'], ['オ', 'o'],
227
- ['カ', 'ka'], ['キ', 'ki'], ['ク', 'ku'], ['ケ', 'ke'], ['コ', 'ko'],
228
- ['サ', 'sa'], ['シ', 'shi'], ['ス', 'su'], ['セ', 'se'], ['ソ', 'so'],
229
- ['タ', 'ta'], ['チ', 'chi'], ['ツ', 'tsu'], ['テ', 'te'], ['ト', 'to'],
230
- ['ナ', 'na'], ['ニ', 'ni'], ['ヌ', 'nu'], ['ネ', 'ne'], ['ノ', 'no'],
231
- ['ハ', 'ha'], ['ヒ', 'hi'], ['フ', 'fu'], ['ヘ', 'he'], ['ホ', 'ho'],
232
- ['マ', 'ma'], ['ミ', 'mi'], ['ム', 'mu'], ['メ', 'me'], ['モ', 'mo'],
233
- ['ヤ', 'ya'], ['ユ', 'yu'], ['ヨ', 'yo'],
234
- ['ラ', 'ra'], ['リ', 'ri'], ['ル', 'ru'], ['レ', 're'], ['ロ', 'ro'],
235
- ['ワ', 'wa'], ['ヲ', 'wo'], ['ン', 'n'],
236
- // Voiced
237
- ['ガ', 'ga'], ['ギ', 'gi'], ['グ', 'gu'], ['ゲ', 'ge'], ['ゴ', 'go'],
238
- ['ザ', 'za'], ['ジ', 'ji'], ['ズ', 'zu'], ['ゼ', 'ze'], ['ゾ', 'zo'],
239
- ['ダ', 'da'], ['ヂ', 'ji'], ['ヅ', 'zu'], ['デ', 'de'], ['ド', 'do'],
240
- ['バ', 'ba'], ['ビ', 'bi'], ['ブ', 'bu'], ['ベ', 'be'], ['ボ', 'bo'],
241
- ['パ', 'pa'], ['ピ', 'pi'], ['プ', 'pu'], ['ペ', 'pe'], ['ポ', 'po'],
242
- ['ヴ', 'v'],
243
- // Long vowel / small chars
244
- ['ー', ''], ['ァ', 'a'], ['ィ', 'i'], ['ゥ', 'u'], ['ェ', 'e'], ['ォ', 'o'],
245
- ['ッ', ''], // handled separately (doubles next consonant)
246
- ];
247
- const KATA_MAP = new Map(KATA_ROMAJI_TABLE);
248
- /**
249
- * Convert a katakana string to Hepburn romaji.
250
- * Handles digraphs, geminate consonants (ッ), and long vowel marks (ー).
251
- */
252
- function katakanaToRomaji(kata) {
253
- let result = '';
254
- let i = 0;
255
- while (i < kata.length) {
256
- // Geminate consonant: ッ doubles the following consonant
257
- if (kata[i] === 'ッ' && i + 1 < kata.length) {
258
- const next = KATA_MAP.get(kata[i + 1]) ?? KATA_MAP.get(kata[i + 1] + kata[i + 2]) ?? '';
259
- if (next.length > 0)
260
- result += next[0]; // double first consonant
261
- i++;
262
- continue;
263
- }
264
- // Try 2-char digraph first
265
- if (i + 1 < kata.length) {
266
- const two = kata[i] + kata[i + 1];
267
- const r2 = KATA_MAP.get(two);
268
- if (r2 !== undefined) {
269
- result += r2;
270
- i += 2;
271
- continue;
272
- }
273
- }
274
- // Single char
275
- const r1 = KATA_MAP.get(kata[i]);
276
- if (r1 !== undefined)
277
- result += r1;
278
- i++;
279
- }
280
- return result;
281
- }
282
- /**
283
- * Arabic light stemmer — strips definite article and common prefix particles.
284
- * Handles: ال (al-), و (wa-), ب (bi-), ل (li-), ف (fa-), ك (ka-).
285
- * Runs iteratively (max 3 passes) so compound prefixes like فال- are fully
286
- * resolved: فالخطأ → الخطأ → خطأ.
287
- * Only strips when the result is still ≥ 3 chars to avoid over-stemming.
288
- */
289
- function arabicLightStem(word) {
290
- let result = word;
291
- for (let i = 0; i < 3; i++) {
292
- const prev = result;
293
- if (result.startsWith('ال') && result.length > 4) {
294
- result = result.slice(2);
295
- }
296
- else if (result.length > 3 && 'وبلفك'.includes(result[0]) && RTL_RE.test(result[1])) {
297
- result = result.slice(1);
298
- }
299
- if (result === prev)
300
- break; // stable — no more prefixes to strip
301
- }
302
- return result;
303
- }
304
- /**
305
- * Hebrew light stemmer — strips the definite article and common prefix particles
306
- * that attach directly to words (no space) in Hebrew.
307
- *
308
- * Handles:
309
- * ה (ha-) — definite article: הפריסה → פריסה
310
- * ו (ve-/u-) — conjunction “and”: ופריסה → פריסה
311
- * ב (be-/bi-) — preposition “in”: בסביבה → סביבה
312
- * ל (le-/li-) — preposition “for”: לשרת → שרת
313
- * מ (mi-/me-) — preposition “from”: מהשרת → השרת → שרת
314
- * כ (ke-/ki-) — preposition “like”: כשרת → שרת
315
- *
316
- * Iterative (max 3 passes): מהפריסה → הפריסה → פריסה.
317
- * Only strips when result is still ≥ 3 chars.
318
- */
319
- function hebrewLightStem(word) {
320
- let result = word;
321
- for (let i = 0; i < 3; i++) {
322
- const prev = result;
323
- if (result.length > 3 && 'הובלמכ'.includes(result[0]) && HEBREW_CHAR_RE.test(result[1])) {
324
- result = result.slice(1);
325
- }
326
- if (result === prev)
327
- break;
328
- }
329
- return result;
330
- }
331
- /**
332
- * Farsi/Persian light stemmer — handles Persian morphology.
333
- * Strips:
334
- * \u0647\u0627 / \u0647\u0627\u06cc (ha/haye) — plural suffixes: \u0633\u0631\u0648\u0631\u0647\u0627 \u2192 \u0633\u0631\u0648\u0631
335
- * \u0645\u06cc\u200c / \u0645\u06cc (mi-) — present-tense prefix: \u0645\u06cc\u200c\u06a9\u0646\u062f \u2192 \u06a9\u0646\u062f
336
- * \u0646\u0645\u06cc\u200c (nami-) — negated present: \u0646\u0645\u06cc\u200c\u0634\u0648\u062f \u2192 \u0634\u0648\u062f
337
- * Only strips when the result is still \u2265 3 chars.
338
- */
339
- function farsiLightStem(word) {
340
- let result = word;
341
- // Suffixes first (longest first)
342
- if (result.endsWith('\u0647\u0627\u06cc') && result.length > 5)
343
- result = result.slice(0, -3);
344
- else if (result.endsWith('\u0647\u0627') && result.length > 4)
345
- result = result.slice(0, -2);
346
- // Prefixes
347
- if (result.startsWith('\u0646\u0645\u06cc\u200c') && result.length > 5)
348
- result = result.slice(4);
349
- else if (result.startsWith('\u0645\u06cc\u200c') && result.length > 4)
350
- result = result.slice(3);
351
- else if (result.startsWith('\u0645\u06cc') && result.length > 4)
352
- result = result.slice(2);
353
- return result;
354
- }
355
- /**
356
- * Hindi light stemmer — strips the most common inflectional suffixes.
357
- * Handles basic verb forms and oblique plural markers.
358
- * Avoids over-stemming loanwords (most tech terms in Hindi are English loanwords).
359
- * Only strips when result is still \u2265 3 chars.
360
- */
361
- function hindiLightStem(word) {
362
- const result = word;
363
- // Infinitive / verb suffixes (longest first to avoid partial match)
364
- if (result.endsWith('\u0928\u093e') && result.length > 4)
365
- return result.slice(0, -2); // \u0928\u093e (nā) infinitive
366
- if (result.endsWith('\u0928\u0947') && result.length > 4)
367
- return result.slice(0, -2); // \u0928\u0947 (ne) ergative
368
- if (result.endsWith('\u0928\u0940') && result.length > 4)
369
- return result.slice(0, -2); // \u0928\u0940 (nī) fem infinitive
370
- if (result.endsWith('\u0924\u093e') && result.length > 4)
371
- return result.slice(0, -2); // \u0924\u093e (tā) m present participle
372
- if (result.endsWith('\u0924\u0940') && result.length > 4)
373
- return result.slice(0, -2); // \u0924\u0940 (tī) f present participle
374
- if (result.endsWith('\u0915\u0930') && result.length > 4)
375
- return result.slice(0, -2); // \u0915\u0930 (kar) conjunctive
376
- if (result.endsWith('\u0913\u0902') && result.length > 4)
377
- return result.slice(0, -2); // \u0913\u0902 (oṃ) oblique plural
378
- if (result.endsWith('\u0907\u092f\u093e\u0902') && result.length > 5)
379
- return result.slice(0, -4); // \u0907\u092f\u093e\u0902 (iyāṃ) f plural
380
- if (result.endsWith('\u0940\u092f\u093e\u0902') && result.length > 5)
381
- return result.slice(0, -4); // \u0940\u092f\u093e\u0102 (īyāṃ)
382
- return result;
383
- }
384
- /**
385
- * Russian light stemmer — strips common inflectional suffixes.
386
- * Handles the most frequent verb/noun/adjective endings to improve recall.
387
- * Only strips when result is still ≥ 3 chars.
388
- *
389
- * Covers:
390
- * ошибки/ошибка → ошибк (noun plural/genitive)
391
- * развёртывание → развёртыва (gerund → stem)
392
- * установить → установ (infinitive)
393
- * настройки → настройк (genitive plural)
394
- */
395
- function russianLightStem(word) {
396
- const w = word;
397
- // Longest first to avoid partial stripping
398
- // Verb infinitives / gerunds
399
- if (w.endsWith('ывание') && w.length > 7)
400
- return w.slice(0, -6);
401
- if (w.endsWith('ивание') && w.length > 7)
402
- return w.slice(0, -6);
403
- if (w.endsWith('ование') && w.length > 7)
404
- return w.slice(0, -6);
405
- if (w.endsWith('вание') && w.length > 6)
406
- return w.slice(0, -5);
407
- if (w.endsWith('ение') && w.length > 5)
408
- return w.slice(0, -4);
409
- if (w.endsWith('ание') && w.length > 5)
410
- return w.slice(0, -4);
411
- if (w.endsWith('ить') && w.length > 4)
412
- return w.slice(0, -3);
413
- if (w.endsWith('ать') && w.length > 4)
414
- return w.slice(0, -3);
415
- if (w.endsWith('еть') && w.length > 4)
416
- return w.slice(0, -3);
417
- if (w.endsWith('уть') && w.length > 4)
418
- return w.slice(0, -3);
419
- // Noun plural/genitive
420
- if (w.endsWith('ки') && w.length > 4)
421
- return w.slice(0, -2);
422
- if (w.endsWith('ги') && w.length > 4)
423
- return w.slice(0, -2);
424
- if (w.endsWith('ов') && w.length > 4)
425
- return w.slice(0, -2);
426
- if (w.endsWith('ев') && w.length > 4)
427
- return w.slice(0, -2);
428
- if (w.endsWith('ей') && w.length > 4)
429
- return w.slice(0, -2);
430
- if (w.endsWith('ий') && w.length > 4)
431
- return w.slice(0, -2);
432
- if (w.endsWith('ый') && w.length > 4)
433
- return w.slice(0, -2);
434
- if (w.endsWith('ая') && w.length > 4)
435
- return w.slice(0, -2);
436
- if (w.endsWith('ое') && w.length > 4)
437
- return w.slice(0, -2);
438
- if (w.endsWith('ую') && w.length > 4)
439
- return w.slice(0, -2);
440
- // Verb present tense
441
- if (w.endsWith('ет') && w.length > 4)
442
- return w.slice(0, -2);
443
- if (w.endsWith('ют') && w.length > 4)
444
- return w.slice(0, -2);
445
- if (w.endsWith('ут') && w.length > 4)
446
- return w.slice(0, -2);
447
- if (w.endsWith('ят') && w.length > 4)
448
- return w.slice(0, -2);
449
- return w;
450
- }
451
- /**
452
- * Turkish light stemmer — strips common agglutinative suffixes.
453
- * Turkish is highly agglutinative; this covers the most common inflectional ends.
454
- *
455
- * Covers:
456
- * hatalar → hata (-lar/-ler plural)
457
- * sunucuda → sunucu (-da/-de locative)
458
- * dağıtımı → dağıtım (-ı/-i/-u/-ü accusative)
459
- * yüklemek → yükle (-mek/-mak infinitive)
460
- */
461
- function turkishLightStem(word) {
462
- const w = word;
463
- // Suffixes longest-first
464
- if (w.endsWith('lardaki') && w.length > 7)
465
- return w.slice(0, -7);
466
- if (w.endsWith('lerdeki') && w.length > 7)
467
- return w.slice(0, -7);
468
- if (w.endsWith('ların') && w.length > 6)
469
- return w.slice(0, -5);
470
- if (w.endsWith('lerin') && w.length > 6)
471
- return w.slice(0, -5);
472
- if (w.endsWith('larda') && w.length > 6)
473
- return w.slice(0, -5);
474
- if (w.endsWith('lerde') && w.length > 6)
475
- return w.slice(0, -5);
476
- if (w.endsWith('ları') && w.length > 5)
477
- return w.slice(0, -4);
478
- if (w.endsWith('leri') && w.length > 5)
479
- return w.slice(0, -4);
480
- if (w.endsWith('mek') && w.length > 4)
481
- return w.slice(0, -3);
482
- if (w.endsWith('mak') && w.length > 4)
483
- return w.slice(0, -3);
484
- if (w.endsWith('ler') && w.length > 4)
485
- return w.slice(0, -3);
486
- if (w.endsWith('lar') && w.length > 4)
487
- return w.slice(0, -3);
488
- if (w.endsWith('nın') && w.length > 4)
489
- return w.slice(0, -3);
490
- if (w.endsWith('nin') && w.length > 4)
491
- return w.slice(0, -3);
492
- if (w.endsWith('nun') && w.length > 4)
493
- return w.slice(0, -3);
494
- if (w.endsWith('nün') && w.length > 4)
495
- return w.slice(0, -3);
496
- if (w.endsWith('da') && w.length > 4)
497
- return w.slice(0, -2);
498
- if (w.endsWith('de') && w.length > 4)
499
- return w.slice(0, -2);
500
- if (w.endsWith('ta') && w.length > 4)
501
- return w.slice(0, -2);
502
- if (w.endsWith('te') && w.length > 4)
503
- return w.slice(0, -2);
504
- if (w.endsWith('dan') && w.length > 4)
505
- return w.slice(0, -3);
506
- if (w.endsWith('den') && w.length > 4)
507
- return w.slice(0, -3);
508
- if (w.endsWith('tan') && w.length > 4)
509
- return w.slice(0, -3);
510
- if (w.endsWith('ten') && w.length > 4)
511
- return w.slice(0, -3);
512
- if (w.endsWith('ın') && w.length > 4)
513
- return w.slice(0, -2);
514
- if (w.endsWith('in') && w.length > 4)
515
- return w.slice(0, -2);
516
- if (w.endsWith('un') && w.length > 4)
517
- return w.slice(0, -2);
518
- if (w.endsWith('ün') && w.length > 4)
519
- return w.slice(0, -2);
520
- if (w.endsWith('ı') && w.length > 4)
521
- return w.slice(0, -1);
522
- if (w.endsWith('i') && w.length > 4)
523
- return w.slice(0, -1);
524
- if (w.endsWith('u') && w.length > 4)
525
- return w.slice(0, -1);
526
- if (w.endsWith('ü') && w.length > 4)
527
- return w.slice(0, -1);
528
- return w;
529
- }
530
- /**
531
- * Bengali (Bangla) light stemmer — strips common verbal and nominal suffixes.
532
- * Bengali is an Indo-Aryan language with moderate morphological complexity.
533
- * Only strips when result is still ≥ 2 chars.
534
- *
535
- * Covers:
536
- * করছে/করেছে → কর (progressive/perfect aspect)
537
- * সার্ভারগুলো → সার্ভার (-গুলো plural)
538
- * সমস্যাটি → সমস্যা (-টি singular marker)
539
- */
540
- function bengaliLightStem(word) {
541
- const w = word;
542
- // Plural / collective markers (longest first)
543
- if (w.endsWith('\u0997\u09c1\u09b2\u09cb') && w.length > 5)
544
- return w.slice(0, -4); // গুলো (-gulo plural)
545
- if (w.endsWith('\u0997\u09c1\u09b2\u09bf') && w.length > 5)
546
- return w.slice(0, -4); // গুলি (-guli plural)
547
- if (w.endsWith('\u09a6\u09c7\u09b0') && w.length > 4)
548
- return w.slice(0, -3); // দের (genitive plural)
549
- if (w.endsWith('\u09a6\u09bf\u0997\u09c7') && w.length > 5)
550
- return w.slice(0, -4); // দিগে
551
- // Definiteness / case markers
552
- if (w.endsWith('\u099f\u09bf') && w.length > 3)
553
- return w.slice(0, -2); // টি (singular definite)
554
- if (w.endsWith('\u099f\u09be') && w.length > 3)
555
- return w.slice(0, -2); // টা (singular definite)
556
- if (w.endsWith('\u0996\u09be\u09a8\u09be') && w.length > 5)
557
- return w.slice(0, -4); // খানা
558
- // Verbal suffixes
559
- if (w.endsWith('\u099b\u09c7') && w.length > 3)
560
- return w.slice(0, -2); // ছে (progressive)
561
- if (w.endsWith('\u099b\u09bf\u09b2') && w.length > 4)
562
- return w.slice(0, -3); // ছিল (past progressive)
563
- if (w.endsWith('\u09af\u09be\u09ac\u09c7') && w.length > 5)
564
- return w.slice(0, -4); // যাবে (future)
565
- if (w.endsWith('\u0995\u09b0\u09be') && w.length > 4)
566
- return w.slice(0, -3); // করা (infinitive)
567
- if (w.endsWith('\u0995\u09b0\u09c7') && w.length > 4)
568
- return w.slice(0, -3); // করে (present)
569
- if (w.endsWith('\u09b9\u09df') && w.length > 3)
570
- return w.slice(0, -2); // হয় (is/becomes)
571
- if (w.endsWith('\u09b9\u09ac\u09c7') && w.length > 4)
572
- return w.slice(0, -3); // হবে (will be)
573
- return w;
574
- }
575
- /**
576
- * Pre-process text BEFORE tokenization to split code identifiers.
577
- * Handles camelCase, PascalCase, snake_case, and kebab-case.
578
- *
579
- * Examples:
580
- * deployServer → deploy Server (then lowercased → deploy server)
581
- * HTMLParser → HTML Parser
582
- * my_api_key → my api key
583
- * get-user-by-id → get user by id (hyphens preserved in regex, spaces also fine)
584
- * BackendServiceImpl → Backend Service Impl
585
- */
586
- function preprocessText(text) {
587
- return text
588
- // camelCase boundary: lowercase/digit → uppercase
589
- .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
590
- // Consecutive uppercase → uppercase+lowercase boundary: HTMLParser → HTML Parser
591
- .replace(/([A-Z]{2,})([A-Z][a-z])/g, '$1 $2')
592
- // snake_case: replace underscores with spaces
593
- .replace(/_/g, ' ');
594
- }
595
- // Maps tokens (English, Japanese katakana, Chinese, Korean, Arabic, Hebrew)
596
- // to their equivalents in other languages. Used to expand tokens at search time
597
- // so "deploy" finds documents containing "デプロイ" / "部署" / "배포", and vice versa.
598
- //
599
- // Keys must be lowercase. CJK values will be bigram-expanded at use time.
600
- import { ohneUmlaute, deutscherStamm, ohneRueckumlaut, zerlegeKompositum, DEUTSCHE_FACHWOERTER, } from './deutsch.js';
601
- const CROSS_LINGUAL_MAP = new Map([
602
- // ── Tech / Ecosystem synonyms (language-agnostic) ─────────────────────────
603
- ['javascript', ['js', 'node', 'nodejs', 'ecmascript']],
604
- ['js', ['javascript', 'node', 'nodejs']],
605
- ['typescript', ['ts', 'javascript', 'js', 'tsc']],
606
- ['ts', ['typescript', 'javascript', 'js']],
607
- ['python', ['py', 'pip', 'django', 'flask', 'fastapi']],
608
- ['py', ['python', 'pip']],
609
- ['golang', ['go', 'gopher', 'goroutine']],
610
- ['go', ['golang', 'goroutine']],
611
- ['rust', ['cargo', 'rustlang', 'crates']],
612
- ['cargo', ['rust', 'rustlang']],
613
- ['java', ['jvm', 'maven', 'gradle', 'spring']],
614
- ['kotlin', ['jvm', 'android', 'coroutine']],
615
- ['dotnet', ['csharp', 'asp', 'nuget', 'aspnet']],
616
- ['postgresql', ['postgres', 'pg', 'psql']],
617
- ['postgres', ['postgresql', 'pg', 'psql']],
618
- ['mysql', ['mariadb', 'sql']],
619
- ['mongodb', ['mongo', 'nosql', 'bson', 'mongoose']],
620
- ['mongo', ['mongodb', 'nosql', 'bson']],
621
- ['elasticsearch', ['elastic', 'opensearch', 'lucene', 'kibana']],
622
- ['elastic', ['elasticsearch', 'opensearch']],
623
- ['kubernetes', ['k8s', 'kube', 'kubectl', 'helm', 'k3s']],
624
- ['k8s', ['kubernetes', 'kube', 'kubectl', 'helm']],
625
- ['helm', ['kubernetes', 'k8s', 'chart']],
626
- ['terraform', ['tf', 'hcl', 'iac', 'opentofu']],
627
- ['ansible', ['playbook', 'automation']],
628
- ['grafana', ['dashboard', 'visualization', 'metrics']],
629
- ['prometheus', ['metrics', 'alert', 'scrape', 'grafana']],
630
- ['nginx', ['proxy', 'webserver', 'ingress']],
631
- ['traefik', ['proxy', 'ingress', 'router']],
632
- ['rabbitmq', ['amqp', 'queue', 'broker', 'messaging']],
633
- ['kafka', ['messaging', 'stream', 'broker']],
634
- ['grpc', ['protobuf', 'proto', 'rpc']],
635
- ['graphql', ['gql', 'resolver', 'schema']],
636
- ['react', ['jsx', 'hooks', 'component', 'redux']],
637
- ['nextjs', ['next', 'react', 'ssr', 'vercel']],
638
- ['vue', ['vuejs', 'vite', 'nuxt']],
639
- ['angular', ['ng', 'rxjs', 'typescript']],
640
- ['aws', ['amazon', 'ec2', 's3', 'lambda', 'cloudwatch', 'ecs', 'eks']],
641
- ['gcp', ['google cloud', 'gke', 'bigquery']],
642
- ['azure', ['microsoft cloud', 'aks', 'devops']],
643
- ['s3', ['bucket', 'object storage', 'aws']],
644
- ['lambda', ['serverless', 'function', 'faas', 'aws']],
645
- ['jwt', ['token', 'bearer', 'oauth', 'auth']],
646
- ['oauth', ['oidc', 'auth', 'token', 'sso']],
647
- ['webhook', ['callback', 'event', 'trigger']],
648
- ['cron', ['schedule', 'job', 'timer']],
649
- ['yaml', ['yml', 'config', 'manifest']],
650
- ['dotenv', ['env', 'environment', 'envfile']],
651
- ['github', ['git', 'actions', 'repo', 'ci']],
652
- ['gitlab', ['git', 'pipeline', 'runner']],
653
- ['wireguard', ['vpn', 'tunnel', 'wg']],
654
- ['prisma', ['orm', 'database', 'schema', 'migration']],
655
- ['npm', ['node', 'package', 'registry', 'yarn', 'pnpm']],
656
- ['yarn', ['npm', 'package', 'node']],
657
- ['pip', ['python', 'package', 'pypi']],
658
- ['brew', ['homebrew', 'macos', 'package']],
659
- // English → all
660
- ['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação', 'развёртывание', 'развертывание', 'dağıtım', 'dağıtmak', 'triển khai']],
661
- ['deployment', ['デプロイ', '部署', '배포', 'deploy', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação', 'развёртывание', 'dağıtım', 'triển khai']],
662
- ['container', ['コンテナ', '容器', '컨테이너', 'docker']],
663
- ['server', ['サーバー', 'サーバ', '服务器', '서버', 'سيرفر', 'שרת', 'سرور', 'सर्वर', 'сервер', 'sunucu', 'máy chủ']],
664
- ['database', ['データベース', '数据库', '데이터베이스', 'db', 'قاعدة البيانات', 'datenbank', 'پایگاه داده', 'डेटाबेس', 'base de données', 'base de datos', 'banco de dados']],
665
- ['cache', ['キャッシュ', '缓存', '캐시', 'كاش', 'מטמון', 'کش', 'कैश', 'кэш', 'önbellek', 'bộ đệm']],
666
- ['error', ['エラー', '错误', '오류', 'خطأ', 'שגיאה', 'خطا', 'त्रुटि', 'गलती', 'exception', 'err', 'fehler', 'erreur', 'fallo', 'errore', 'erro', 'ошибка', 'hata', 'hatalı', 'lỗi']],
667
- ['bug', ['バグ', '缺陷', '버그', 'issue', 'defect', 'خلل', 'اشکال', 'बग']],
668
- ['fix', ['修正', '修复', '수정', 'bugfix', 'patch', 'hotfix', 'إصلاح', 'תיקון', 'رفع', 'सुधार', 'beheben', 'behoben', 'réparer', 'correction', 'arreglar', 'corrección', 'correggere', 'corrigir', 'исправить', 'исправление', 'düzeltmek', 'düzeltme']],
669
- ['build', ['ビルド', '构建', '빌드', 'بناء', 'בנייה', 'ساخت', 'निर्माण', 'bauen', 'construire', 'construir', 'costruire', 'сборка', 'собрать', 'derleme', 'derlemek']],
670
- ['test', ['テスト', '测试', '테스트', 'اختبار', 'בדיקה', 'آزمایش', 'परीक्षण', 'testen', 'tester', 'probar', 'testare', 'testar', 'тест', 'тестирование', 'test', 'testlemek']],
671
- ['auth', ['認証', '认证', '인증', 'authentication', 'login', 'oauth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', 'authentifizierung', 'authentification', 'autenticación', 'autenticazione', 'autenticação', 'аутентификация', 'авторизация', 'kimlik doğrulama', 'yetkilendirme']],
672
- ['authentication', ['auth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', '認証', '认证', '인증', 'login', 'oauth', 'аутентификация', 'авторизация', 'kimlik doğrulama']],
673
- ['environment', ['環境', '环境', '환경', 'env', 'بيئة', 'סביבה', 'umgebung', 'environnement', 'entorno', 'ambiente', 'среда', 'окружение', 'ortam']],
674
- ['secret', ['key', 'token', 'password', 'jwt', 'مفتاح', 'מפתח', 'geheimnis', 'schlüssel', 'clave', 'clé', 'chiave', 'chave', 'секрет', 'ключ', 'gizli', 'anahtar']],
675
- ['problem', ['error', 'issue', 'bug', 'failure', 'مشكلة', '問題', '오류', 'fehler', 'problème', 'problema', 'проблема', 'ошибка', 'sorun', 'problem']],
676
- ['kubernetes', ['クベルネテス', 'k8s', 'kube']],
677
- ['network', ['ネットワーク', '网络', '네트워크', 'شبكة', 'רשת', 'شبکه', 'नेटवर्क', 'netzwerk', 'réseau', 'red', 'rete', 'rede', 'сеть', 'ağ']],
678
- ['timeout', ['タイムアウト', '超时', '타임아웃', 'مهلة']],
679
- ['memory', ['メモリ', '内存', '메모리', 'ram', 'ذاكرة', 'זיכרון', 'حافظه', 'मेमोरी', 'speicher', 'mémoire', 'memoria', 'memória', 'память', 'bellek', 'hafıza']],
680
- ['config', ['設定', '配置', '설정', 'configuration', 'settings', 'conf', 'إعدادات', 'הגדרות', 'پیکربندی', 'कॉन्फ़िग', 'konfiguration', 'einstellungen', 'configuración', 'configurazione', 'configuração', 'конфигурация', 'настройки', 'yapılandırma', 'ayarlar']],
681
- ['install', ['インストール', '安装', '설치', 'تثبيت', 'התקנה', 'نصب', 'इंस्टॉल', 'installieren', 'installer', 'instalar', 'installare', 'установить', 'установка', 'yüklemek', 'kurulum']],
682
- ['update', ['アップデート', '更新', '업데이트', 'upgrade', 'تحديث', 'עדכון', 'به‌روزرسانی', 'अपडेट', 'aktualisieren', 'aktualisierung', 'actualizar', 'aggiornare', 'atualizar', 'обновление', 'обновить', 'güncelleme']],
683
- ['log', ['ログ', '日志', '로그', 'logging', 'سجل', 'יומן', 'ثبت', 'लॉग', 'protokoll', 'protokolle', 'journal', 'registro', 'журнал', 'лог', 'günlük']],
684
- ['port', ['ポート', '端口', '포트', 'منفذ', 'פורט']],
685
- ['file', ['ファイル', '文件', '파일', 'ملف', 'קובץ']],
686
- ['image', ['イメージ', '镜像', '이미지', 'صورة', 'תמונה', 'abbild', 'imagen', 'imagem']],
687
- ['volume', ['ボリューム', '卷', '볼륨']],
688
- ['cluster', ['クラスター', '集群', '클러스터']],
689
- ['node', ['ノード', '节点', '노드']],
690
- ['service', ['サービス', '服务', '서비스', 'svc', 'خدمة', 'שירות', 'dienst', 'servicio', 'servizio', 'serviço', 'сервис', 'служба', 'servis', 'hizmet']],
691
- ['certificate', ['証明書', '证书', '인증서', 'cert', 'ssl', 'tls', 'شهادة', 'תעודה']],
692
- ['password', ['パスワード', '密码', '비밀번호', 'passwd', 'pwd', 'كلمة المرور', 'סיסמה']],
693
- ['token', ['トークン', '令牌', '토큰', 'jwt', 'secret', 'رمز', 'אסימון']],
694
- ['health', ['ヘルス', '健康', '헬스', 'healthcheck', 'probe', 'صحة']],
695
- ['migration', ['マイグレーション', '迁移', '마이그레이션', 'migrate', 'هجرة']],
696
- ['backup', ['バックアップ', '备份', '백업', 'نسخ احتياطي', 'גיבוי', 'پشتیبان‌گیری', 'बैकअप', 'sicherung', 'sauvegarde', 'respaldo', 'cópia de segurança', 'резервная копия', 'резерв', 'yedekleme']],
697
- ['monitor', ['モニター', '监控', '모니터링', 'monitoring', 'metrics', 'alert', 'مراقبة', 'ניטור', 'نظارت', 'निगरानी', 'überwachung', 'surveiller', 'monitoreo', 'monitorare', 'monitorar', 'мониторинг', 'наблюдение', 'izleme']],
698
- ['performance', ['パフォーマンス', '性能', '성능', 'latency', 'throughput', 'عملکرد', 'प्रदर्शन', 'leistung', 'performances', 'rendimiento', 'prestazioni', 'desempenho', 'производительность', 'быстродействие', 'performans']],
699
- ['connection', ['接続', '连接', '연결', 'conn', 'socket', 'اتصال', 'חיבור', 'اتصال', 'कनेक्शन', 'verbindung', 'connexion', 'conexión', 'connessione', 'conexão']],
700
- ['queue', ['キュー', '队列', '큐', 'طابور', 'warteschlange', 'file d\'attente', 'cola', 'coda', 'fila']],
701
- ['redis', ['レディス', '레디스']],
702
- ['nginx', ['エンジンエックス']],
703
- ['linux', ['リナックス', 'لينكس']],
704
- ['api', ['エーピーアイ', '接口', 'endpoint', 'واجهة برمجية', 'ממשק']],
705
- ['healthcheck', ['ヘルスチェック', 'health', 'probe', 'فحص الصحة']],
706
- ['loadbalancer', ['ロードバランサー', '负载均衡', '로드밸런서', 'lb']],
707
- ['ssl', ['tls', 'https', 'certificate', 'cert']],
708
- ['tls', ['ssl', 'https', 'certificate', 'cert']],
709
- ['docker', ['container', 'コンテナ', '容器', '컨테이너', 'دوكر']],
710
- ['git', ['version control', 'repo', 'repository', 'commit', 'push', 'pull']],
711
- ['ci', ['pipeline', 'github actions', 'gitlab', 'jenkins', 'build']],
712
- ['cd', ['deploy', 'deployment', 'release']],
713
- ['debug', ['デバッグ', '调试', '디버그', 'debugging', 'breakpoint', 'تصحيح', 'איתור באגים', 'اشکال‌زدایی', 'डीबग', 'debuggen', 'déboguer', 'depurar', 'отладка', 'дебаг', 'hata ayıklama']],
714
- ['crash', ['クラッシュ', '崩溃', '크래시', 'panic', 'segfault', 'انهيار', 'קריסה', 'خرابی', 'क्रैश', 'absturz', 'panne', 'plantage', 'caída', 'falha', 'сбой', 'крэш', 'çökme', 'çöküş']],
715
- ['restart', ['再起動', '重启', '재시작', 'reboot', 'إعادة تشغيل', 'הפעלה מחדש', 'راه‌اندازی مجدد', 'पुنरारंभ', 'neustart', 'redémarrer', 'reiniciar', 'riavviare']],
716
- ['permission', ['権限', '权限', '권한', 'access', 'acl', 'chmod', 'صلاحية', 'הרשאה', 'مجوز', 'अनुमति', 'berechtigung', 'berechtigungen', 'permiso', 'permesso', 'permissão', 'разрешение', 'доступ', 'izin', 'yetki']],
717
- // Japanese katakana → English
718
- ['デプロイ', ['deploy', 'deployment']],
719
- ['コンテナ', ['container', 'docker']],
720
- ['サーバー', ['server']],
721
- ['サーバ', ['server']],
722
- ['データベース', ['database', 'db']],
723
- ['キャッシュ', ['cache']],
724
- ['エラー', ['error', 'err']],
725
- ['バグ', ['bug', 'issue']],
726
- ['ビルド', ['build']],
727
- ['テスト', ['test']],
728
- ['認証', ['auth', 'authentication']],
729
- ['設定', ['config', 'configuration']],
730
- ['インストール', ['install']],
731
- ['アップデート', ['update', 'upgrade']],
732
- ['ログ', ['log', 'logs']],
733
- ['ポート', ['port']],
734
- ['ファイル', ['file']],
735
- ['イメージ', ['image']],
736
- ['クラスター', ['cluster']],
737
- ['ノード', ['node']],
738
- ['サービス', ['service']],
739
- ['パスワード', ['password']],
740
- ['トークン', ['token']],
741
- ['バックアップ', ['backup']],
742
- ['モニター', ['monitor', 'monitoring']],
743
- ['接続', ['connection']],
744
- ['キュー', ['queue']],
745
- ['ヘルスチェック', ['healthcheck', 'health check', 'health']],
746
- ['ロードバランサー', ['loadbalancer', 'load balancer']],
747
- ['デバッグ', ['debug']],
748
- ['クラッシュ', ['crash', 'panic']],
749
- ['再起動', ['restart', 'reboot']],
750
- ['権限', ['permission', 'access']],
751
- // Chinese → English
752
- ['部署', ['deploy', 'deployment']],
753
- ['容器', ['container', 'docker']],
754
- ['服务器', ['server']],
755
- ['数据库', ['database']],
756
- ['缓存', ['cache']],
757
- ['错误', ['error']],
758
- ['修复', ['fix', 'bugfix']],
759
- ['构建', ['build']],
760
- ['测试', ['test']],
761
- ['认证', ['auth']],
762
- ['配置', ['config']],
763
- ['安装', ['install']],
764
- ['更新', ['update']],
765
- ['日志', ['log']],
766
- ['端口', ['port']],
767
- ['镜像', ['image']],
768
- ['集群', ['cluster']],
769
- ['节点', ['node']],
770
- ['服务', ['service']],
771
- ['密码', ['password']],
772
- ['令牌', ['token']],
773
- ['备份', ['backup']],
774
- ['监控', ['monitor']],
775
- ['连接', ['connection']],
776
- ['队列', ['queue']],
777
- ['性能', ['performance']],
778
- ['内存', ['memory']],
779
- ['调试', ['debug']],
780
- ['崩溃', ['crash']],
781
- ['重启', ['restart']],
782
- ['权限', ['permission']],
783
- // Korean → English
784
- ['배포', ['deploy', 'deployment']],
785
- ['컨테이너', ['container']],
786
- ['서버', ['server']],
787
- ['데이터베이스', ['database']],
788
- ['캐시', ['cache']],
789
- ['오류', ['error']],
790
- ['수정', ['fix']],
791
- ['빌드', ['build']],
792
- ['테스트', ['test']],
793
- ['인증', ['auth']],
794
- ['설정', ['config']],
795
- ['설치', ['install']],
796
- ['업데이트', ['update']],
797
- ['로그', ['log']],
798
- ['포트', ['port']],
799
- ['이미지', ['image']],
800
- ['클러스터', ['cluster']],
801
- ['노드', ['node']],
802
- ['서비스', ['service']],
803
- ['토큰', ['token']],
804
- ['백업', ['backup']],
805
- ['모니터링', ['monitor']],
806
- ['연결', ['connection']],
807
- ['큐', ['queue']],
808
- ['성능', ['performance']],
809
- ['메모리', ['memory']],
810
- ['디버그', ['debug']],
811
- ['크래시', ['crash']],
812
- ['재시작', ['restart']],
813
- ['권한', ['permission']],
814
- // Arabic → English
815
- ['خطأ', ['error']],
816
- ['إصلاح', ['fix']],
817
- ['بناء', ['build']],
818
- ['اختبار', ['test']],
819
- ['مصادقة', ['auth', 'authentication']],
820
- ['إعدادات', ['config', 'configuration']],
821
- ['تثبيت', ['install']],
822
- ['تحديث', ['update', 'upgrade']],
823
- ['سجل', ['log']],
824
- ['صورة', ['image']],
825
- ['خدمة', ['service']],
826
- ['نسخ احتياطي', ['backup']],
827
- ['مراقبة', ['monitor', 'monitoring']],
828
- ['اتصال', ['connection']],
829
- ['ذاكرة', ['memory']],
830
- ['تصحيح', ['debug', 'debugging']],
831
- ['شبكة', ['network']],
832
- // Additional Arabic → English (covering blog post examples + common terms)
833
- ['نشر', ['deploy', 'deployment']],
834
- ['انهيار', ['crash', 'panic']],
835
- ['طابور', ['queue']],
836
- ['رمز', ['token', 'secret']],
837
- ['كاش', ['cache']],
838
- ['منفذ', ['port']],
839
- ['سيرفر', ['server']],
840
- ['قاعدة البيانات', ['database', 'db']],
841
- ['إعادة تشغيل', ['restart', 'reboot']],
842
- ['صلاحية', ['permission', 'access']],
843
- ['تطبيق', ['application', 'app']],
844
- ['مفتاح', ['key', 'token', 'secret']],
845
- ['واجهة برمجية', ['api', 'interface']],
846
- ['فحص الصحة', ['healthcheck', 'health']],
847
- ['حاوية', ['container', 'docker']],
848
- ['عقدة', ['node']],
849
- ['سرعة', ['performance', 'speed']],
850
- ['قرص', ['disk', 'storage']],
851
- ['خادم', ['server']],
852
- ['برنامج', ['application', 'software', 'app']],
853
- // Arabic terms from blog examples
854
- ['مشكلة', ['error', 'issue', 'bug', 'problem', 'failure']],
855
- ['بيئة', ['environment', 'env']],
856
- ['متغيرات', ['variables', 'env', 'environment']],
857
- ['إنتاج', ['production', 'prod']],
858
- ['سري', ['secret', 'key', 'token']],
859
- ['مفتاح سري', ['secret', 'key']],
860
- // Hebrew → English
861
- ['שגיאה', ['error']],
862
- ['תיקון', ['fix']],
863
- ['בנייה', ['build']],
864
- ['בדיקה', ['test']],
865
- ['אימות', ['auth', 'authentication']],
866
- ['הגדרות', ['config', 'configuration']],
867
- ['התקנה', ['install']],
868
- ['עדכון', ['update', 'upgrade']],
869
- ['יומן', ['log']],
870
- ['שרת', ['server']],
871
- ['שירות', ['service']],
872
- ['גיבוי', ['backup']],
873
- ['ניטור', ['monitor', 'monitoring']],
874
- ['חיבור', ['connection']],
875
- ['זיכרון', ['memory']],
876
- ['רשת', ['network']],
877
- ['תמונה', ['image']],
878
- ['סיסמה', ['password']],
879
- ['הרשאה', ['permission', 'access']],
880
- // Additional Hebrew → English (covering blog post examples + common terms)
881
- ['קריסה', ['crash', 'panic']],
882
- ['תור', ['queue']],
883
- ['מטמון', ['cache']],
884
- ['אסימון', ['token', 'secret']],
885
- ['פורט', ['port']],
886
- ['איתור באגים', ['debug', 'debugging']],
887
- ['הפעלה מחדש', ['restart', 'reboot']],
888
- ['מיכל', ['container', 'docker']],
889
- ['יישום', ['application', 'app']],
890
- ['מפתח', ['key', 'token', 'secret']],
891
- ['בדיקת תקינות', ['healthcheck', 'health']],
892
- ['ממשק תכנות', ['api', 'interface']],
893
- ['ביצועים', ['performance']],
894
- ['אחסון', ['storage', 'disk']],
895
- // Hebrew terms from blog examples
896
- ['פריסה', ['deploy', 'deployment']],
897
- ['בעיה', ['error', 'issue', 'bug', 'problem']],
898
- ['סביבה', ['environment', 'env']],
899
- ['ייצור', ['production', 'prod']],
900
- ['סודי', ['secret', 'key', 'token']],
901
- ['מפתח סודי', ['secret', 'key']],
902
- // ── Farsi/Persian → English ───────────────────────────────────────────────
903
- ['استقرار', ['deploy', 'deployment']],
904
- ['خطا', ['error', 'err']], // Farsi: خطا vs Arabic: خطأ
905
- ['اشکال', ['bug', 'issue', 'error']],
906
- ['رفع اشکال', ['fix', 'debug', 'debugging']],
907
- ['ساخت', ['build']],
908
- ['آزمایش', ['test']],
909
- ['احراز هویت', ['auth', 'authentication']],
910
- ['پیکربندی', ['config', 'configuration']],
911
- ['نصب', ['install']],
912
- ['به‌روزرسانی', ['update', 'upgrade']],
913
- ['ثبت', ['log']],
914
- ['سرور', ['server']],
915
- ['پایگاه داده', ['database', 'db']],
916
- ['شبکه', ['network']], // Farsi شبکه vs Arabic شبكة
917
- ['حافظه', ['memory', 'ram']], // Farsi حافظه vs Arabic ذاكرة
918
- ['کش', ['cache']],
919
- ['اشکال‌زدایی', ['debug', 'debugging']],
920
- ['خرابی', ['crash', 'failure', 'error']],
921
- ['راه‌اندازی مجدد', ['restart', 'reboot']],
922
- ['مجوز', ['permission', 'access']],
923
- ['پشتیبان‌گیری', ['backup']],
924
- ['عملکرد', ['performance']],
925
- ['مشکل', ['problem', 'issue', 'error']],
926
- ['سرویس', ['service']],
927
- ['کلید', ['key', 'token', 'secret']],
928
- ['محیط', ['environment', 'env']],
929
- ['تولید', ['production', 'prod']],
930
- ['رمز', ['secret', 'key', 'token']],
931
- ['اتصال', ['connection', 'conn']],
932
- // ── Hindi (Devanagari) → English ──────────────────────────────────────────
933
- ['तैनाती', ['deploy', 'deployment']],
934
- ['तैना', ['deploy', 'deployment']], // stemmed form
935
- ['त्रुटि', ['error', 'err']],
936
- ['गलती', ['error', 'bug', 'issue']],
937
- ['सुधार', ['fix', 'bugfix']],
938
- ['निर्माण', ['build']],
939
- ['परीक्षण', ['test']],
940
- ['प्रमाणीकरण', ['auth', 'authentication']],
941
- ['विन्यास', ['config', 'configuration']],
942
- ['कॉन्फ़िगरेशन', ['config', 'configuration']],
943
- ['इंस्टॉल', ['install']],
944
- ['अपडेट', ['update', 'upgrade']],
945
- ['लॉग', ['log']],
946
- ['सर्वर', ['server']],
947
- ['डेटाबेस', ['database', 'db']],
948
- ['नेटवर्क', ['network']],
949
- ['मेमोरी', ['memory', 'ram']],
950
- ['कैश', ['cache']],
951
- ['डीबग', ['debug', 'debugging']],
952
- ['क्रैश', ['crash', 'panic']],
953
- ['पुनरारंभ', ['restart', 'reboot']],
954
- ['अनुमति', ['permission', 'access']],
955
- ['बैकअप', ['backup']],
956
- ['प्रदर्शन', ['performance']],
957
- ['समस्या', ['problem', 'issue', 'error']],
958
- ['सेवा', ['service']],
959
- ['कनेक्शन', ['connection', 'conn']],
960
- ['पासवर्ड', ['password']],
961
- ['टोकन', ['token', 'secret']],
962
- ['वातावरण', ['environment', 'env']],
963
- ['उत्पादन', ['production', 'prod']],
964
- // ── European languages → English ─────────────────────────────────────────
965
- // German (Deutsch) → English
966
- ['fehler', ['error', 'err']],
967
- ['absturz', ['crash', 'panic']],
968
- ['bug', ['bug', 'issue']], // same word, keep for completeness
969
- ['beheben', ['fix', 'bugfix']],
970
- ['behoben', ['fix', 'fixed']],
971
- ['lösung', ['solution', 'fix']],
972
- ['bauen', ['build']],
973
- ['testen', ['test']],
974
- ['authentifizierung', ['auth', 'authentication']],
975
- ['konfiguration', ['config', 'configuration']],
976
- ['einstellungen', ['config', 'settings']],
977
- ['installieren', ['install']],
978
- ['installiert', ['install', 'installed']],
979
- ['aktualisieren', ['update', 'upgrade']],
980
- ['aktualisierung', ['update', 'upgrade']],
981
- ['protokoll', ['log']],
982
- ['protokolle', ['log', 'logs']],
983
- ['abbild', ['image']],
984
- ['knoten', ['node']],
985
- ['dienst', ['service']],
986
- ['sicherung', ['backup']],
987
- ['überwachung', ['monitor', 'monitoring']],
988
- ['verbindung', ['connection', 'conn']],
989
- ['warteschlange', ['queue']],
990
- ['leistung', ['performance']],
991
- ['speicher', ['memory', 'storage']],
992
- ['debuggen', ['debug', 'debugging']],
993
- ['neustart', ['restart', 'reboot']],
994
- ['berechtigung', ['permission', 'access']],
995
- ['berechtigungen', ['permission', 'access', 'acl']],
996
- ['netzwerk', ['network']],
997
- ['datenbank', ['database', 'db']],
998
- ['bereitstellen', ['deploy', 'deployment']],
999
- ['bereitstellung', ['deploy', 'deployment']],
1000
- // 'container' and 'server' are the same in German/French/Spanish/Italian/Portuguese
1001
- ['kaputt', ['broken', 'error', 'crash']],
1002
- ['funktioniert', ['works', 'working']],
1003
- ['geht nicht', ['not working', 'broken', 'error']],
1004
- ['schlüssel', ['key', 'token', 'secret']],
1005
- ['zertifikat', ['certificate', 'cert', 'ssl', 'tls']],
1006
- ['umgebung', ['environment', 'env']],
1007
- ['variablen', ['variables', 'env', 'environment']],
1008
- ['aufgabe', ['task', 'job']],
1009
- ['wartung', ['maintenance']],
1010
- ['speicherleck', ['memory leak', 'memory']],
1011
- ['schnittstelle', ['interface', 'api']],
1012
- // French (Français) → English
1013
- ['erreur', ['error', 'err']],
1014
- ['réparer', ['fix']],
1015
- ['correction', ['fix', 'bugfix']],
1016
- ['construire', ['build']],
1017
- ['tester', ['test']],
1018
- ['authentification', ['auth', 'authentication']],
1019
- ['configuration', ['config', 'configuration']],
1020
- ['installer', ['install']],
1021
- ['installation', ['install']],
1022
- ['mettre', ['update', 'upgrade']],
1023
- ['journal', ['log', 'logs']],
1024
- ['nœud', ['node']],
1025
- ['sauvegarde', ['backup']],
1026
- ['surveiller', ['monitor', 'monitoring']],
1027
- ['connexion', ['connection']],
1028
- ['mémoire', ['memory']],
1029
- ['déboguer', ['debug']],
1030
- ['redémarrer', ['restart', 'reboot']],
1031
- ['réseau', ['network']],
1032
- ['base de données', ['database', 'db']],
1033
- ['déployer', ['deploy']],
1034
- ['déploiement', ['deploy', 'deployment']],
1035
- ['clé', ['key', 'token']],
1036
- ['certificat', ['certificate', 'cert', 'ssl']],
1037
- ['environnement', ['environment', 'env']],
1038
- ['panne', ['crash', 'outage', 'failure']],
1039
- ['plantage', ['crash', 'panic']],
1040
- ['interface', ['interface', 'api']],
1041
- ['performances', ['performance']],
1042
- ['stockage', ['storage', 'disk']],
1043
- ['file attente', ['queue']],
1044
- // Spanish (Español) → English
1045
- ['arreglar', ['fix']],
1046
- ['corrección', ['fix', 'bugfix']],
1047
- ['construir', ['build']],
1048
- ['probar', ['test']],
1049
- ['autenticación', ['auth', 'authentication']],
1050
- ['configuración', ['config', 'configuration']],
1051
- ['instalar', ['install']],
1052
- ['actualizar', ['update', 'upgrade']],
1053
- ['actualización', ['update', 'upgrade']],
1054
- ['registro', ['log', 'registry']],
1055
- ['nodo', ['node']],
1056
- ['servicio', ['service']],
1057
- ['contraseña', ['password']],
1058
- ['copia de seguridad', ['backup']],
1059
- ['respaldo', ['backup']],
1060
- ['monitorear', ['monitor']],
1061
- ['monitoreo', ['monitoring']],
1062
- ['conexión', ['connection']],
1063
- ['rendimiento', ['performance']],
1064
- ['memoria', ['memory']],
1065
- ['depurar', ['debug']],
1066
- ['fallo', ['crash', 'failure', 'error']],
1067
- ['caída', ['crash', 'outage']],
1068
- ['reiniciar', ['restart', 'reboot']],
1069
- ['permiso', ['permission']],
1070
- ['permisos', ['permission', 'access']],
1071
- ['red', ['network']],
1072
- ['base de datos', ['database', 'db']],
1073
- ['desplegar', ['deploy']],
1074
- ['despliegue', ['deploy', 'deployment']],
1075
- ['clave', ['key', 'token', 'secret']],
1076
- ['certificado', ['certificate', 'cert', 'ssl']],
1077
- ['entorno', ['environment', 'env']],
1078
- ['cola', ['queue']],
1079
- ['interfaz', ['interface', 'api']],
1080
- ['imagen', ['image']],
1081
- // Italian (Italiano) → English
1082
- ['errore', ['error', 'err']],
1083
- ['correggere', ['fix']],
1084
- ['costruire', ['build']],
1085
- ['testare', ['test']],
1086
- ['autenticazione', ['auth', 'authentication']],
1087
- ['configurazione', ['config', 'configuration']],
1088
- ['installare', ['install']],
1089
- ['aggiornare', ['update', 'upgrade']],
1090
- ['aggiornamento', ['update', 'upgrade']],
1091
- ['registro', ['log']],
1092
- ['nodo', ['node']],
1093
- ['servizio', ['service']],
1094
- ['password', ['password']],
1095
- ['backup', ['backup']],
1096
- ['monitorare', ['monitor']],
1097
- ['connessione', ['connection']],
1098
- ['prestazioni', ['performance']],
1099
- ['memoria', ['memory']],
1100
- ['debug', ['debug']],
1101
- ['arresto anomalo', ['crash']],
1102
- ['riavviare', ['restart']],
1103
- ['permesso', ['permission']],
1104
- ['rete', ['network']],
1105
- ['database', ['database', 'db']],
1106
- ['distribuire', ['deploy']],
1107
- ['distribuzione', ['deploy', 'deployment']],
1108
- ['chiave', ['key', 'token', 'secret']],
1109
- ['certificato', ['certificate', 'cert']],
1110
- ['ambiente', ['environment', 'env']],
1111
- ['coda', ['queue']],
1112
- ['immagine', ['image']],
1113
- // Portuguese (Português) → English
1114
- ['erro', ['error', 'err']],
1115
- ['corrigir', ['fix']],
1116
- ['construir', ['build']],
1117
- ['testar', ['test']],
1118
- ['autenticação', ['auth', 'authentication']],
1119
- ['configuração', ['config', 'configuration']],
1120
- ['instalar', ['install']],
1121
- ['atualizar', ['update', 'upgrade']],
1122
- ['atualização', ['update', 'upgrade']],
1123
- ['registro', ['log']],
1124
- ['nó', ['node']],
1125
- ['serviço', ['service']],
1126
- ['senha', ['password']],
1127
- ['cópia de segurança', ['backup']],
1128
- ['monitorar', ['monitor']],
1129
- ['conexão', ['connection']],
1130
- ['desempenho', ['performance']],
1131
- ['memória', ['memory']],
1132
- ['depurar', ['debug']],
1133
- ['falha', ['crash', 'failure', 'error']],
1134
- ['reiniciar', ['restart']],
1135
- ['permissão', ['permission']],
1136
- ['rede', ['network']],
1137
- ['banco de dados', ['database', 'db']],
1138
- ['implantar', ['deploy']],
1139
- ['implantação', ['deploy', 'deployment']],
1140
- ['chave', ['key', 'token', 'secret']],
1141
- ['certificado', ['certificate', 'cert']],
1142
- ['ambiente', ['environment', 'env']],
1143
- ['fila', ['queue']],
1144
- ['imagem', ['image']],
1145
- // ── Russian (Cyrillic) → English ──────────────────────────────────────────
1146
- ['ошибка', ['error', 'err']],
1147
- ['ошибки', ['error', 'err']],
1148
- ['сбой', ['crash', 'failure', 'error']],
1149
- ['крэш', ['crash', 'panic']],
1150
- ['баг', ['bug', 'issue']],
1151
- ['исправить', ['fix', 'bugfix']],
1152
- ['исправление', ['fix', 'patch']],
1153
- ['сборка', ['build']],
1154
- ['собрать', ['build']],
1155
- ['тест', ['test']],
1156
- ['тестирование', ['test', 'testing']],
1157
- ['аутентификация', ['auth', 'authentication']],
1158
- ['авторизация', ['auth', 'authorization']],
1159
- ['конфигурация', ['config', 'configuration']],
1160
- ['настройки', ['config', 'settings']],
1161
- ['установить', ['install']],
1162
- ['установка', ['install']],
1163
- ['обновление', ['update', 'upgrade']],
1164
- ['обновить', ['update', 'upgrade']],
1165
- ['журнал', ['log']],
1166
- ['лог', ['log', 'logs']],
1167
- ['сервер', ['server']],
1168
- ['база данных', ['database', 'db']],
1169
- ['сеть', ['network']],
1170
- ['память', ['memory', 'ram']],
1171
- ['кэш', ['cache']],
1172
- ['отладка', ['debug', 'debugging']],
1173
- ['перезапуск', ['restart', 'reboot']],
1174
- ['перезагрузка', ['restart', 'reboot']],
1175
- ['разрешение', ['permission', 'access']],
1176
- ['доступ', ['permission', 'access']],
1177
- ['резерв', ['backup']],
1178
- ['производительность', ['performance']],
1179
- ['проблема', ['problem', 'issue', 'error']],
1180
- ['сервис', ['service']],
1181
- ['служба', ['service']],
1182
- ['подключение', ['connection', 'conn']],
1183
- ['соединение', ['connection', 'conn']],
1184
- ['развёртывание', ['deploy', 'deployment']],
1185
- ['развертывание', ['deploy', 'deployment']],
1186
- ['развёрт', ['deploy', 'deployment']], // stemmed form
1187
- ['разверт', ['deploy', 'deployment']], // stemmed form
1188
- ['контейнер', ['container', 'docker']],
1189
- ['образ', ['image']],
1190
- ['кластер', ['cluster']],
1191
- ['узел', ['node']],
1192
- ['секрет', ['secret', 'key', 'token']],
1193
- ['ключ', ['key', 'token', 'secret']],
1194
- ['пароль', ['password']],
1195
- ['токен', ['token', 'secret']],
1196
- ['мониторинг', ['monitor', 'monitoring']],
1197
- ['наблюдение', ['monitor', 'monitoring']],
1198
- ['мигрировать', ['migrate', 'migration']],
1199
- ['миграция', ['migrate', 'migration']],
1200
- // ── Turkish (Latin + special chars ğ/ş/ı) → English ─────────────────────
1201
- ['hata', ['error', 'err']],
1202
- ['hatalı', ['error', 'err']],
1203
- ['çökme', ['crash', 'panic']],
1204
- ['çöküş', ['crash', 'failure']],
1205
- ['düzeltmek', ['fix', 'bugfix']],
1206
- ['düzeltme', ['fix', 'patch']],
1207
- ['derleme', ['build']],
1208
- ['derlemek', ['build']],
1209
- ['test', ['test']],
1210
- ['testlemek', ['test', 'testing']],
1211
- ['kimlik doğrulama', ['auth', 'authentication']],
1212
- ['yetkilendirme', ['auth', 'authorization']],
1213
- ['yapılandırma', ['config', 'configuration']],
1214
- ['ayarlar', ['config', 'settings']],
1215
- ['yüklemek', ['install']],
1216
- ['kurulum', ['install']],
1217
- ['güncelleme', ['update', 'upgrade']],
1218
- ['günlük', ['log']],
1219
- ['sunucu', ['server']],
1220
- ['veritabanı', ['database', 'db']],
1221
- ['ağ', ['network']],
1222
- ['bellek', ['memory', 'ram']],
1223
- ['önbellek', ['cache']],
1224
- ['hata ayıklama', ['debug', 'debugging']],
1225
- ['yeniden başlatma', ['restart', 'reboot']],
1226
- ['izin', ['permission', 'access']],
1227
- ['yetki', ['permission', 'access', 'acl']],
1228
- ['yedekleme', ['backup']],
1229
- ['performans', ['performance']],
1230
- ['sorun', ['problem', 'issue', 'error']],
1231
- ['servis', ['service']],
1232
- ['hizmet', ['service']],
1233
- ['bağlantı', ['connection', 'conn']],
1234
- ['dağıtım', ['deploy', 'deployment']],
1235
- ['dağıtmak', ['deploy']],
1236
- ['konteyner', ['container', 'docker']],
1237
- ['küme', ['cluster']],
1238
- ['düğüm', ['node']],
1239
- ['gizli', ['secret', 'key']],
1240
- ['anahtar', ['key', 'token', 'secret']],
1241
- ['şifre', ['password']],
1242
- ['izleme', ['monitor', 'monitoring']],
1243
- ['göç', ['migrate', 'migration']],
1244
- // ── Vietnamese (Latin + Latin Extended Additional U+1EA0–U+1EF9) → English ─
1245
- ['triển khai', ['deploy', 'deployment']],
1246
- ['triển', ['deploy', 'deployment']], // split token form
1247
- ['lỗi', ['error', 'err']],
1248
- ['sửa lỗi', ['fix', 'bugfix', 'debug']],
1249
- ['xây dựng', ['build']],
1250
- ['kiểm tra', ['test']],
1251
- ['xác thực', ['auth', 'authentication']],
1252
- ['cấu hình', ['config', 'configuration']],
1253
- ['cài đặt', ['install']],
1254
- ['cập nhật', ['update', 'upgrade']],
1255
- ['nhật ký', ['log']],
1256
- ['máy chủ', ['server']],
1257
- ['cơ sở dữ liệu', ['database', 'db']],
1258
- ['mạng', ['network']],
1259
- ['bộ nhớ', ['memory', 'ram']],
1260
- ['bộ đệm', ['cache']],
1261
- ['gỡ lỗi', ['debug', 'debugging']],
1262
- ['sự cố', ['crash', 'failure', 'error']],
1263
- ['khởi động lại', ['restart', 'reboot']],
1264
- ['quyền', ['permission', 'access']],
1265
- ['sao lưu', ['backup']],
1266
- ['hiệu suất', ['performance']],
1267
- ['vấn đề', ['problem', 'issue', 'error']],
1268
- ['dịch vụ', ['service']],
1269
- ['kết nối', ['connection', 'conn']],
1270
- ['vùng chứa', ['container', 'docker']],
1271
- ['nút', ['node']],
1272
- ['khóa', ['key', 'token', 'secret']],
1273
- ['mật khẩu', ['password']],
1274
- ['giám sát', ['monitor', 'monitoring']],
1275
- ['di chuyển', ['migrate', 'migration']],
1276
- ]);
1277
- /**
1278
- * Expand a token to its cross-lingual synonyms.
1279
- * Returns synonyms to be added to the token stream (pre-tokenized).
1280
- * CJK synonyms are NOT pre-bigram'd here — caller handles that.
1281
- */
1282
- /**
1283
- * Die deutschen Eintraege werden NACH dem Aufbau der Haupttabelle ergaenzt und
1284
- * dabei umlautfrei geschrieben.
1285
- *
1286
- * Warum umlautfrei: die vorhandenen deutschen Eintraege standen mit echten
1287
- * Umlauten (`loesung` als `lösung`), waehrend Lektionen und Fragen oft `ae/oe/ue`
1288
- * tippen. Damit fand `ueberwachung` den Eintrag `überwachung` nie — zwei
1289
- * Schreibweisen desselben Wortes, und die Suche hielt sie fuer verschieden.
1290
- * Gemessen am 19.08.2026.
1291
- *
1292
- * Der bestehende Schluessel bleibt stehen; es kommt nur die umlautfreie Form
1293
- * dazu. Wer `überwachung` tippt, wird beim Zerlegen ohnehin auf `ueberwachung`
1294
- * gebracht.
1295
- */
1296
- for (const [wort, synonyme] of CROSS_LINGUAL_MAP) {
1297
- const ohne = ohneUmlaute(wort);
1298
- if (ohne !== wort && !CROSS_LINGUAL_MAP.has(ohne))
1299
- CROSS_LINGUAL_MAP.set(ohne, synonyme);
1300
- }
1301
- for (const [wort, synonyme] of DEUTSCHE_FACHWOERTER) {
1302
- const vorhanden = CROSS_LINGUAL_MAP.get(wort);
1303
- CROSS_LINGUAL_MAP.set(wort, vorhanden ? [...new Set([...vorhanden, ...synonyme])] : [...synonyme]);
1304
- }
1305
- /**
1306
- * Grundwoerter fuer die Zerlegung zusammengesetzter Woerter.
1307
- *
1308
- * Es ist die Wortliste selbst — bewusst KEINE zweite Liste. Wer ein Wortpaar
1309
- * eintraegt, macht es damit auch als Grundwort verfuegbar. Eine Wahrheit an
1310
- * zwei Orten zu pflegen ist die Fehlerklasse, die uns hier am haeufigsten
1311
- * trifft.
1312
- */
1313
- const GRUNDWOERTER = new Set([...CROSS_LINGUAL_MAP.keys()].filter(k => k.length >= 4 && /^[a-z]+$/.test(ohneUmlaute(k))).map(ohneUmlaute));
1314
- function expandCrossLingual(token) {
1315
- const direkt = CROSS_LINGUAL_MAP.get(token);
1316
- if (direkt)
1317
- return direkt;
1318
- // Umlautfreie Schreibweise probieren, bevor aufgegeben wird.
1319
- const ohne = ohneUmlaute(token);
1320
- return ohne !== token ? (CROSS_LINGUAL_MAP.get(ohne) ?? []) : [];
1321
- }
1322
- /**
1323
- * Tokenize text into meaningful keywords.
1324
- * Handles accented Latin, RTL (Arabic, Hebrew), and CJK (Chinese, Japanese, Korean).
1325
- *
1326
- * Features:
1327
- * • CJK → character bigrams
1328
- * • Katakana → additionally emits Hepburn romaji tokens (enables romaji queries)
1329
- * • Arabic → word tokenization + iterative prefix stemming (ال/و/ب/ل/ف/ك)
1330
- * • Hebrew → word tokenization + iterative prefix stemming (ה/ו/ב/ל/מ/כ)
1331
- * • Farsi → word tokenization + suffix/prefix stemming (ها/های plural, می prefix)
1332
- * • Hindi → Devanagari word tokenization + light suffix stemming
1333
- * • All scripts → cross-lingual synonym expansion (EN↔JA↔ZH↔KO↔AR↔HE↔FA↔HI↔DE↔FR↔ES↔IT↔PT)
1334
- */
1335
- /**
1336
- * Tokenize text for BM25 indexing or query expansion.
1337
- *
1338
- * @param text - The text to tokenize
1339
- * @param options.crossLingualExpand - When true (default), adds cross-lingual synonym
1340
- * tokens for every base token. Set to false when indexing DOCUMENTS so that
1341
- * English documents don't get indexed with all Arabic/Japanese/etc. synonyms of
1342
- * every word they contain — that inflates BM25 scores catastrophically when a query
1343
- * also expands the same term. Query tokenization keeps expansion enabled so a
1344
- * Japanese query still finds English documents (query "デプロイ" → expands to "deploy").
1345
- */
1346
- function tokenize(text, options) {
1347
- const doCrossLingualExpand = options?.crossLingualExpand ?? true;
1348
- const tokens = [];
1349
- // Pre-process: split camelCase/PascalCase identifiers and snake_case before lowercasing
1350
- const lower = preprocessText(text).toLowerCase();
1351
- for (const [seg] of lower.matchAll(SEGMENT_RE)) {
1352
- if (CJK_RE.test(seg)) {
1353
- // CJK segment — extract overlapping character bigrams
1354
- for (let i = 0; i < seg.length - 1; i++) {
1355
- const bigram = seg[i] + seg[i + 1];
1356
- if (!STOPWORDS.has(seg[i]) && !STOPWORDS.has(bigram)) {
1357
- tokens.push(bigram);
1358
- }
1359
- }
1360
- // Trailing single character (for 1-char CJK terms)
1361
- if (seg.length >= 1) {
1362
- const last = seg[seg.length - 1];
1363
- if (!STOPWORDS.has(last))
1364
- tokens.push(last);
1365
- }
1366
- // Whole-segment cross-lingual lookup (for known tech terms like デプロイ, 部署, 배포)
1367
- // This ensures CJK full-words map to their English equivalents
1368
- const segSyns = expandCrossLingual(seg);
1369
- for (const syn of segSyns) {
1370
- if (!CJK_RE.test(syn)) {
1371
- syn.split(/\s+/).filter(w => w.length > 1 && !STOPWORDS.has(w)).forEach(w => tokens.push(w));
1372
- }
1373
- }
1374
- // Romanization: extract katakana-only portion and emit romaji tokens.
1375
- // This allows users to search "kontena" or "depuroi" to find katakana docs.
1376
- const kataOnly = seg.replace(/[^\u30a0-\u30ff]/g, '');
1377
- if (kataOnly.length >= 2) {
1378
- const romaji = katakanaToRomaji(kataOnly);
1379
- if (romaji.length >= 2 && romaji.length <= 40 && !STOPWORDS.has(romaji)) {
1380
- tokens.push(romaji);
1381
- }
1382
- }
1383
- }
1384
- else if (RTL_RE.test(seg)) {
1385
- // RTL segment — 3-way branch: Farsi / Hebrew / Arabic
1386
- const words = seg.trim().split(/\s+/);
1387
- let stemFn;
1388
- if (FARSI_CHAR_RE.test(seg))
1389
- stemFn = farsiLightStem;
1390
- else if (HEBREW_CHAR_RE.test(seg))
1391
- stemFn = hebrewLightStem;
1392
- else
1393
- stemFn = arabicLightStem;
1394
- for (const w of words) {
1395
- if (w.length <= 1 || STOPWORDS.has(w))
1396
- continue;
1397
- const stemmed = stemFn(w);
1398
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1399
- tokens.push(stemmed);
1400
- }
1401
- }
1402
- else if (DEVANAGARI_RE.test(seg)) {
1403
- // Devanagari segment (Hindi / Marathi) — naturally space-separated
1404
- const words = seg.trim().split(/[\s\u200c\u200d]+/); // handle zero-width joiners
1405
- for (const w of words) {
1406
- const deva = w.replace(/[^\u0900-\u097f0-9]/g, '');
1407
- if (deva.length <= 1 || STOPWORDS.has(deva))
1408
- continue;
1409
- const stemmed = hindiLightStem(deva);
1410
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1411
- tokens.push(stemmed);
1412
- }
1413
- }
1414
- else if (BENGALI_RE.test(seg)) {
1415
- // Bengali (Bangla) segment — space-separated words, Bengali script
1416
- const words = seg.trim().split(/[\s\u200c\u200d]+/);
1417
- for (const w of words) {
1418
- const bn = w.replace(/[^\u0980-\u09ff0-9]/g, '');
1419
- if (bn.length <= 1 || STOPWORDS.has(bn))
1420
- continue;
1421
- const stemmed = bengaliLightStem(bn);
1422
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1423
- tokens.push(stemmed);
1424
- }
1425
- }
1426
- else if (CYRILLIC_RE.test(seg)) {
1427
- // Cyrillic segment (Russian, Bulgarian, Ukrainian, Serbian …)
1428
- const words = seg.trim().split(/\s+/);
1429
- for (const w of words) {
1430
- const cyr = w.replace(/[^\u0400-\u04ff]/g, '');
1431
- if (cyr.length <= 1 || STOPWORDS.has(cyr))
1432
- continue;
1433
- const stemmed = russianLightStem(cyr);
1434
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1435
- tokens.push(stemmed);
1436
- }
1437
- }
1438
- else {
1439
- // Latin / other — includes Turkish (ğ/ş/ı), Polish (ą/ę/ł/ń/ó/ś/ź/ż/ć),
1440
- // Czech (č/š/ž/ě/ů/ř), Hungarian (ő/ű), Romanian (ș/ț), Vietnamese (ắặầổợụừ…)
1441
- const words = seg
1442
- .replace(/[^a-záàâãäåæçéèêëíìîïñóòôõöúùûüýÿßœğşıİąćęłńśźżčšžěůřőűșț\u1ea0-\u1ef90-9:\-./]/g, ' ')
1443
- .split(/\s+/)
1444
- .filter(w => w.length > 1 && !STOPWORDS.has(w));
1445
- // Turkish: apply light stemmer to words with Turkish-specific chars
1446
- for (const w of words) {
1447
- if (TURKISH_CHAR_RE.test(w)) {
1448
- const stemmed = turkishLightStem(w);
1449
- if (stemmed !== w && stemmed.length > 1 && !STOPWORDS.has(stemmed)) {
1450
- tokens.push(stemmed);
1451
- }
1452
- }
1453
- tokens.push(w);
1454
- // ── Deutsch ──────────────────────────────────────────────────────────
1455
- //
1456
- // Drei Schritte, alle am 19.08.2026 an echten Fragen belegt. Fuer
1457
- // sieben Sprachen gab es hier einen Stemmer, fuer Deutsch nicht.
1458
- //
1459
- // Wichtig: alles wird ZUSAETZLICH ausgegeben, nie ersetzend. Das
1460
- // Originalwort bleibt der staerkste Treffer; die Ableitungen sind
1461
- // Bruecken, keine Umleitungen.
1462
- // 1. Umlaute vereinheitlichen. `Loesung` und `Lösung` sind dasselbe
1463
- // Wort — vorher waren es zwei.
1464
- const ohneU = ohneUmlaute(w);
1465
- if (ohneU !== w && !STOPWORDS.has(ohneU))
1466
- tokens.push(ohneU);
1467
- // 2. Wortform. `Abhaengigkeiten` und `Abhaengigkeit` sollen sich
1468
- // finden.
1469
- const stamm = deutscherStamm(w);
1470
- if (stamm !== w && stamm !== ohneU && stamm.length > 3 && !STOPWORDS.has(stamm)) {
1471
- tokens.push(stamm);
1472
- // Rueckumlautung: `Eintraege` -> `eintraeg` -> `eintrag`.
1473
- const zurueck = ohneRueckumlaut(stamm);
1474
- if (zurueck && zurueck.length > 3 && !STOPWORDS.has(zurueck))
1475
- tokens.push(zurueck);
1476
- }
1477
- // 3. Zusammengesetzte Woerter. Die deutsche Besonderheit und die
1478
- // groesste Luecke: `Arbeitsspeicher` enthaelt `speicher`, und
1479
- // `speicher` stand laengst in der Wortliste — nur kam niemand
1480
- // dort an.
1481
- if (ohneU.length >= 10) {
1482
- for (const teil of zerlegeKompositum(ohneU, GRUNDWOERTER)) {
1483
- if (!STOPWORDS.has(teil))
1484
- tokens.push(teil);
1485
- }
1486
- }
1487
- }
1488
- }
1489
- }
1490
- // ── Cross-lingual expansion (query mode only) ────────────────────────────
1491
- // Only run when tokenizing queries. Skipped for documents to prevent the
1492
- // symmetric-expansion inflation bug: if both query and document expand "error"
1493
- // to 28 synonyms, BM25 counts all 28 as exact matches — a single common word
1494
- // inflates any document's score 28×, burying topic-specific matches.
1495
- if (!doCrossLingualExpand)
1496
- return tokens;
1497
- // For each token, look up synonyms in other languages and add them.
1498
- // CJK synonyms are bigram-expanded inline; Latin/RTL synonyms added as-is.
1499
- const expansions = [];
1500
- const seen = new Set(tokens);
1501
- for (const tok of tokens) {
1502
- const syns = expandCrossLingual(tok);
1503
- for (const syn of syns) {
1504
- if (seen.has(syn))
1505
- continue;
1506
- seen.add(syn);
1507
- if (CJK_RE.test(syn)) {
1508
- // CJK synonym → expand to character bigrams
1509
- for (let i = 0; i < syn.length - 1; i++) {
1510
- const bg = syn[i] + syn[i + 1];
1511
- if (!STOPWORDS.has(syn[i]) && !STOPWORDS.has(bg))
1512
- expansions.push(bg);
1513
- }
1514
- if (syn.length >= 1) {
1515
- const last = syn[syn.length - 1];
1516
- if (!STOPWORDS.has(last))
1517
- expansions.push(last);
1518
- }
1519
- }
1520
- else if (RTL_RE.test(syn)) {
1521
- // RTL synonym — apply correct stemmer per language
1522
- const rtlStem = FARSI_CHAR_RE.test(syn) ? farsiLightStem
1523
- : HEBREW_CHAR_RE.test(syn) ? hebrewLightStem
1524
- : arabicLightStem;
1525
- const stemmed = rtlStem(syn);
1526
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1527
- expansions.push(stemmed);
1528
- }
1529
- else if (DEVANAGARI_RE.test(syn)) {
1530
- // Devanagari synonym (Hindi)
1531
- const stemmed = hindiLightStem(syn);
1532
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1533
- expansions.push(stemmed);
1534
- }
1535
- else if (BENGALI_RE.test(syn)) {
1536
- // Bengali synonym
1537
- const stemmed = bengaliLightStem(syn);
1538
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1539
- expansions.push(stemmed);
1540
- }
1541
- else if (CYRILLIC_RE.test(syn)) {
1542
- // Cyrillic synonym (Russian)
1543
- const cyr = syn.replace(/[^\u0400-\u04ff]/g, '');
1544
- const stemmed = russianLightStem(cyr);
1545
- if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
1546
- expansions.push(stemmed);
1547
- }
1548
- else {
1549
- // Latin synonym (includes Turkish) — split in case of multi-word
1550
- const parts = syn.split(/\s+/).filter(w => {
1551
- if (w.length <= 1 || STOPWORDS.has(w))
1552
- return false;
1553
- return true;
1554
- });
1555
- for (const p of parts) {
1556
- expansions.push(p);
1557
- // Apply Turkish stemmer if it has Turkish-specific characters
1558
- if (TURKISH_CHAR_RE.test(p)) {
1559
- const stemmed = turkishLightStem(p);
1560
- if (stemmed !== p && stemmed.length > 1 && !STOPWORDS.has(stemmed)) {
1561
- expansions.push(stemmed);
1562
- }
1563
- }
1564
- }
1565
- }
1566
- }
1567
- }
1568
- tokens.push(...expansions);
1569
- return tokens;
1570
- }
1571
- /**
1572
- * Split a multi-topic query into sub-queries.
1573
- * Detects numbered lists, semicolons, "and also", line breaks, etc.
1574
- *
1575
- * Example: "deploy API fix routing and also check auth" →
1576
- * ["deploy API fix routing", "check auth"]
1577
- *
1578
- * Example: "1. deploy 2. fix routing 3. auth" →
1579
- * ["deploy", "fix routing", "auth"]
1580
- */
1581
- function splitMultiQuery(query) {
1582
- // Numbered list: "1. foo 2. bar 3. baz"
1583
- const numberedParts = query.split(/\d+[.)]\s*/g).filter(s => s.trim().length > 2);
1584
- if (numberedParts.length >= 2)
1585
- return numberedParts.map(s => s.trim());
1586
- // Semicolons or newlines
1587
- const semiParts = query.split(/[;\n]+/).filter(s => s.trim().length > 2);
1588
- if (semiParts.length >= 2)
1589
- return semiParts.map(s => s.trim());
1590
- // Conjunctions (EN + DE + FR + ES + IT + PT + RU + TR)
1591
- const conjParts = query.split(/\b(?:and also|also noch|außerdem|plus|additionally|furthermore|de plus|además|inoltre|além disso|а также|и также|кроме того|плюс|ayrıca|bunun yanı sıra|همچنین|وأيضاً|وكذلك|وهمچنین|और भी|इसके अलावा)\b/i).filter(s => s.trim().length > 2);
1592
- if (conjParts.length >= 2)
1593
- return conjParts.map(s => s.trim());
1594
- // Comma-separated with 3+ parts (likely a list)
1595
- const commaParts = query.split(/,\s*/).filter(s => s.trim().length > 2);
1596
- if (commaParts.length >= 3)
1597
- return commaParts.map(s => s.trim());
1598
- // Single query
1599
- return [query];
1600
- }
1601
- // ── BM25+ Scoring ─────────────────────────────────────────────────────────────
1602
- //
1603
- // BM25+ fixes the "long document under-scoring" bug in classic BM25.
1604
- // Paper: Lv & Zhai (2011) "Lower-Bounding Term Frequency Normalization"
1605
- //
1606
- // Improvements over standard BM25:
1607
- // 1. δ=1 additive term → guarantees TF>0 terms always contribute positively
1608
- // 2. Bigram proximity boost → adjacent query terms in doc get 2× weight
1609
- // 3. Recency boost → entries with timestamps get exp-decay bonus (7d half-life)
1610
- // 4. Levenshtein fuzzy match → typo-tolerant (distance ≤ 2)
1611
- //
1612
- /** BM25+ parameters */
1613
- const BM25_K1 = 1.2; // term frequency saturation
1614
- const BM25_B = 0.75; // length normalization
1615
- // BM25+ gibt jedem gefundenen Wort einen Sockelbetrag, damit lange Dokumente
1616
- // nicht ganz durchfallen. Bei 1.0 belohnte das Breite statt Genauigkeit: ein
1617
- // Datensatz, der zehn allgemeine Woerter traf, schlug einen, der zwei genaue
1618
- // traf. Gemessen 19.08.2026 an 498 Lektionen — Median-Platz 101 bei 1.0,
1619
- // 95 bei 0.25, 77 bei 0.
1620
- const BM25_DELTA = 0.25;
1621
- // Wie stark Frische die Rangfolge bewegen darf: ±5 Prozent. Begruendung und
1622
- // Messreihe stehen bei recencyBoost().
1623
- const RECENCY_SPANNE = 0.05;
1624
- // Wie stark ein von uns ergaenztes Synonym zaehlt, verglichen mit einem Wort,
1625
- // das der Mensch getippt hat.
1626
- //
1627
- // Gemessen 19.08.2026 an 499 Lektionen mit 100 Fragen:
1628
- //
1629
- // Gewicht Platz 1 Top 3 Median
1630
- // 1.0 20 31 14
1631
- // 0.5 21 33 12
1632
- // 0.35 22 31 13
1633
- //
1634
- // 0.5 ist auf drei von vier Massen vorn. Der Unterschied ist EINE Frage — das
1635
- // ist kein Beleg, sondern eine Richtung. Wer hier dreht, misst nach.
1636
- const SYNONYM_GEWICHT = 0.5;
1637
- // Wie viele vorhandene Woerter je Fragewort als unscharfer Treffer infrage
1638
- // kommen. Messreihe steht bei fuzzyKandidaten().
1639
- const FUZZY_KANDIDATEN = 64;
1640
- /** Recency boost: half-life in days. Entry from 7 days ago gets 0.5× boost. */
1641
- const RECENCY_HALF_LIFE_DAYS = 7;
1642
- const ZERO_RESULTS_LOG = [];
1643
- const ZERO_RESULTS_MAX = 500;
1644
- let zeroResultsTotal = 0;
1645
- function logZeroResult(query) {
1646
- zeroResultsTotal++;
1647
- if (ZERO_RESULTS_LOG.length >= ZERO_RESULTS_MAX)
1648
- ZERO_RESULTS_LOG.shift();
1649
- ZERO_RESULTS_LOG.push({ query, ts: Date.now() });
1650
- }
1651
- /** Global index vocabulary — rebuilt on each keywordSearch call from the doc set. */
1652
- let _indexVocab = new Set();
1653
- /**
1654
- * Levenshtein distance — edit distance between two strings.
1655
- * Used for typo-tolerant fuzzy matching (distance ≤ 2 = match).
1656
- * O(n*m) but strings are short (tokens), so this is fast.
1657
- */
1658
- function levenshtein(a, b) {
1659
- if (a === b)
1660
- return 0;
1661
- if (a.length === 0)
1662
- return b.length;
1663
- if (b.length === 0)
1664
- return a.length;
1665
- // Skip if length diff > 2 (can't be ≤ 2 edits)
1666
- if (Math.abs(a.length - b.length) > 2)
1667
- return 3;
1668
- const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
1669
- for (let i = 1; i <= a.length; i++) {
1670
- let corner = i - 1;
1671
- prev[0] = i;
1672
- for (let j = 1; j <= b.length; j++) {
1673
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
1674
- const cur = Math.min(prev[j] + 1, prev[j - 1] + 1, corner + cost);
1675
- corner = prev[j];
1676
- prev[j] = cur;
1677
- }
1678
- }
1679
- return prev[b.length];
1680
- }
1681
- /** Extract a timestamp from JSON content (looks for "ts" or "created" fields). */
1682
- function extractTimestamp(content) {
1683
- // Fast regex for ISO dates in JSON: "ts":"2026-04-17T..." or "created":"..."
1684
- const match = content.match(/"(?:ts|created|created_at|timestamp)"\s*:\s*"([^"]+)"/);
1685
- if (match) {
1686
- const ms = Date.parse(match[1]);
1687
- if (!isNaN(ms))
1688
- return ms;
1689
- }
1690
- return undefined;
1691
- }
1692
- /** Recency multiplier: 1.0 for now, 0.5 after half-life days, exponential decay. */
1693
- // The GENTLE, ranking-only age curve — deliberately NOT the sharp staleness
1694
- // curve in confidence.ts (calculateConfidence). Ranking must nudge, not punish:
1695
- // a 7-day half-life bounded to [0.5,1.5] keeps a still-relevant older lesson in
1696
- // contention. This is bench-tuned; swapping in the sharp confidence curve here
1697
- // regressed every Cachly-Bench floor and was reverted (PR #228). If you touch
1698
- // this, run `npm run bench:gate` — the rerank.test.ts guard alone is too loose.
1699
- /**
1700
- * Frische als STICHENTSCHEID, nicht als Treiber.
1701
- *
1702
- * ── Was hier schiefging, und wie lange ──────────────────────────────────────
1703
- *
1704
- * Bis zum 19.08.2026 lag der Bereich bei [0.5, 1.5]. Eine ganz frische Lektion
1705
- * bekam damit das DREIFACHE einer 79 Tage alten — unabhaengig davon, wie gut
1706
- * sie zur Frage passt. Bei einem Bestand, in dem viele Datensaetze aehnlich
1707
- * mittelmaessig passen, entscheidet ein solcher Faktor die Rangfolge allein.
1708
- *
1709
- * Gemessen an 498 echten Lektionen mit 20 Fragen. Nur diesen Bereich zu
1710
- * verschmaelern, sonst nichts:
1711
- *
1712
- * Bereich auf Platz 1 Median-Platz
1713
- * [0.5, 1.5] 1/20 101
1714
- * [0.75, 1.25] 2/20 53
1715
- * [0.9, 1.1] 3/20 39
1716
- * [0.95, 1.05] 5/20 36
1717
- * ohne Frische 6/20 29
1718
- *
1719
- * ── Warum trotzdem nicht ganz weg ───────────────────────────────────────────
1720
- *
1721
- * Weil Lektionen einander korrigieren. kanzlei:coach-timeout-root-cause traegt
1722
- * woertlich "korrigiert eine frueher falsch gespeicherte Lesson". Ohne jede
1723
- * Frische gewinnt bei gleichwertigem Text die falsche alte Fassung, und zwar
1724
- * fuer immer.
1725
- *
1726
- * ±5 Prozent heisst in der Praxis: die Reihenfolge aendert sich nur zwischen
1727
- * Datensaetzen, die ohnehin fast gleich gut passen. Genau das soll ein
1728
- * Stichentscheid tun.
1729
- *
1730
- * Ohne Frische mass sich um EINE Frage besser. Bei 20 Fragen ist das kein
1731
- * Unterschied, auf den man eine Entscheidung stuetzt.
1732
- *
1733
- * ── Warum es Monate unentdeckt blieb ────────────────────────────────────────
1734
- *
1735
- * Der Fixture-Bench hat 17 Lektionen, mit Zeitstempeln und fast derselben
1736
- * Altersspanne (2,7x gegen 3,0x). Am fehlenden Zeitstempel lag es also NICHT.
1737
- * Es lag an der Menge: bei 16 Mitbewerbern gewinnt der Textabgleich auch gegen
1738
- * den Faktor 3, weil ein seltenes Wort rund zehnmal so schwer wiegt wie ein
1739
- * haeufiges. Bei 497 Mitbewerbern gibt es genug Datensaetze mit aehnlichem
1740
- * Textwert — und dann entscheidet der Faktor.
1741
- *
1742
- * Ein Fehler, der erst ab einer gewissen Menge auftritt, ist auf einem kleinen
1743
- * Pruefstand unsichtbar. Nicht schwer zu finden. Unsichtbar.
1744
- */
1745
- function recencyBoost(timestampMs) {
1746
- if (!timestampMs)
1747
- return 1.0;
1748
- const ageDays = (Date.now() - timestampMs) / (1000 * 60 * 60 * 24);
1749
- const frisch = ageDays <= 0 ? 1 : Math.pow(0.5, ageDays / RECENCY_HALF_LIFE_DAYS);
1750
- return 1 - RECENCY_SPANNE + 2 * RECENCY_SPANNE * frisch;
1751
- }
1752
- const WORTBESTAND_FRISCHE_MS = 60_000;
1753
- /**
1754
- * Ein Bestand JE VERBINDUNG, nicht je Muster.
1755
- *
1756
- * Der erste Entwurf benannte den Zwischenspeicher nur nach dem Suchmuster.
1757
- * Das war falsch, und zwei Tests haben es sofort gezeigt: derselbe
1758
- * MCP-Prozess bedient MEHRERE Instanzen (`getConnection(instance_id)`), und
1759
- * `cachly:lesson:best:*` heisst in jeder davon etwas anderes. Ein Bestand nur
1760
- * nach Muster haette die Lektionen der einen Kanzlei an die naechste
1761
- * ausgeliefert.
1762
- *
1763
- * Deshalb eine WeakMap auf das Verbindungsobjekt: geht die Verbindung, geht
1764
- * der Bestand mit — ohne dass ihn jemand aufraeumen muesste.
1765
- */
1766
- const _wortbestand = new WeakMap();
1767
- /** Nur fuer die Zaehlung in Tests — die WeakMap laesst sich nicht zaehlen. */
1768
- let _wortbestandZaehler = 0;
1769
- /**
1770
- * Wirft alle Bestaende weg. Ruft der Schreibpfad auf, wenn eine Lektion neu
1771
- * geschrieben wurde — ohne das waere sie bis zu eine Minute unsichtbar.
1772
- *
1773
- * Absichtlich ALLE und nicht nur die betroffene Verbindung: der Aufrufer
1774
- * kennt die Verbindung an dieser Stelle nicht immer, und ein Bestand zu viel
1775
- * neu zu bauen kostet eine Sekunde. Einen zu wenig zu entwerten kostet eine
1776
- * Minute Unsichtbarkeit.
1777
- */
1778
- export function wortindexEntwerten() {
1779
- _entwertetAb = Date.now();
1780
- _wortbestandZaehler = 0;
1781
- }
1782
- /** Alles, was vor diesem Zeitpunkt gebaut wurde, gilt als veraltet. */
1783
- let _entwertetAb = 0;
1784
- /** Nur fuer Tests: wie viele Bestaende seit dem letzten Entwerten stehen. */
1785
- export function wortindexStand() {
1786
- return _wortbestandZaehler;
1787
- }
1788
- async function keywordSearch(redis, patterns, query, topK = 10) {
1789
- const bestandsSchluessel = patterns.slice().sort().join('|');
1790
- const jeVerbindung = _wortbestand.get(redis);
1791
- const stehend = jeVerbindung?.get(bestandsSchluessel);
1792
- if (stehend
1793
- && stehend.gebaut > _entwertetAb
1794
- && Date.now() - stehend.gebaut < WORTBESTAND_FRISCHE_MS) {
1795
- return keywordSearchMitBestand(stehend, query, topK);
1796
- }
1797
- // ── Step 1: Collect all matching keys — patterns scanned in parallel ──
1798
- const keyBatches = await Promise.all(patterns.map(pattern => {
1799
- const keys = [];
1800
- const stream = redis.scanStream({ match: pattern, count: 500 });
1801
- return new Promise((resolve, reject) => {
1802
- stream.on('data', (batch) => {
1803
- keys.push(...batch.filter((k) => !k.endsWith(':meta')));
1804
- });
1805
- stream.on('end', () => resolve(keys));
1806
- stream.on('error', reject);
1807
- });
1808
- }));
1809
- // Deduplicate across patterns (a key may match multiple globs)
1810
- const allKeys = [...new Set(keyBatches.flat())];
1811
- if (allKeys.length === 0)
1812
- return [];
1813
- // Pipeline GET for speed
1814
- const pipeline = redis.pipeline();
1815
- for (const key of allKeys)
1816
- pipeline.get(key);
1817
- const results = await pipeline.exec();
1818
- const docs = [];
1819
- let totalTokens = 0;
1820
- for (let i = 0; i < allKeys.length; i++) {
1821
- const content = results?.[i]?.[1];
1822
- if (!content)
1823
- continue;
1824
- // Indiziert wird der ROHE Inhalt, nicht eine Auswahl von Feldern.
1825
- //
1826
- // Am 19.08.2026 wurde genau das versucht: nur die bedeutungstragenden
1827
- // Felder indizieren (Thema dreifach, dann what_worked, what_failed, tags,
1828
- // commands, file_paths) und Pruefspur, Zahlen und Feldnamen weglassen. Das
1829
- // Argument dafuer war gut: die Dokumentlaenge sollte nicht von einer langen
1830
- // Pruefspur aufgeblaeht werden.
1831
- //
1832
- // Gemessen an 499 Lektionen mit 100 Fragen kostete es in JEDER Einstellung
1833
- // einen Treffer:
1834
- //
1835
- // Synonymgewicht mit Feldauswahl ohne
1836
- // 1.0 19 20
1837
- // 0.5 20 21
1838
- // 0.35 21 22
1839
- //
1840
- // Steht hier, damit es niemand — auch ich nicht — ein zweites Mal fuer eine
1841
- // gute Idee haelt. Das Argument war plausibel und falsch, und genau diese
1842
- // Sorte Aenderung hat uns die `score^0.3`-Stauchung eingebracht.
1843
- const tokens = tokenize(`${allKeys[i]} ${content}`, { crossLingualExpand: false });
1844
- if (tokens.length === 0)
1845
- continue;
1846
- // Term frequency map
1847
- const tokenFreq = new Map();
1848
- for (const t of tokens) {
1849
- tokenFreq.set(t, (tokenFreq.get(t) ?? 0) + 1);
1850
- }
1851
- // Bigrams — adjacent token pairs for proximity detection
1852
- const bigrams = new Set();
1853
- for (let j = 0; j < tokens.length - 1; j++) {
1854
- bigrams.add(`${tokens[j]}|${tokens[j + 1]}`);
1855
- }
1856
- const timestamp = extractTimestamp(content);
1857
- // Key tokens for title-boost: terms appearing in the Redis key get extra weight
1858
- const keyTokens = new Set(tokenize(allKeys[i]));
1859
- docs.push({ key: allKeys[i], content, tokens, tokenFreq, bigrams, keyTokens, timestamp });
1860
- totalTokens += tokens.length;
1861
- }
1862
- if (docs.length === 0)
1863
- return [];
1864
- const avgDL = totalTokens / docs.length;
1865
- // ── Step 2: IDF (inverse document frequency) ──
1866
- const docFreq = new Map();
1867
- for (const doc of docs) {
1868
- const seen = new Set();
1869
- for (const t of doc.tokens) {
1870
- if (!seen.has(t)) {
1871
- docFreq.set(t, (docFreq.get(t) ?? 0) + 1);
1872
- seen.add(t);
1873
- }
1874
- }
1875
- }
1876
- const gebauter = { docs, avgDL, docFreq, gebaut: Date.now() };
1877
- const fach = _wortbestand.get(redis) ?? new Map();
1878
- if (!fach.has(bestandsSchluessel))
1879
- _wortbestandZaehler++;
1880
- fach.set(bestandsSchluessel, gebauter);
1881
- _wortbestand.set(redis, fach);
1882
- return keywordSearchMitBestand(gebauter, query, topK);
1883
- }
1884
- /**
1885
- * Die Bewertung selbst — alles, was von der FRAGE abhaengt.
1886
- *
1887
- * Unveraendert aus keywordSearch herausgeloest: dieselbe Reihenfolge,
1888
- * dieselben Formeln. Getrennt wurde nur, was je Bestand gilt, von dem, was je
1889
- * Frage gilt.
1890
- */
1891
- function keywordSearchMitBestand(bestand, query, topK) {
1892
- const { docs, avgDL, docFreq } = bestand;
1893
- const N = docs.length;
1894
- function idf(term) {
1895
- const df = docFreq.get(term) ?? 0;
1896
- return Math.log((N - df + 0.5) / (df + 0.5) + 1);
1897
- }
1898
- /**
1899
- * BM25+ score for a term in a document.
1900
- * Classic BM25: TF_norm = tf*(k1+1) / (tf + k1*(1 - b + b*dl/avgdl))
1901
- * BM25+ adds: + δ (guarantees long docs with the term still score positively)
1902
- */
1903
- function bm25PlusTerm(term, doc) {
1904
- const tf = doc.tokenFreq.get(term) ?? 0;
1905
- if (tf === 0)
1906
- return 0;
1907
- const dl = doc.tokens.length;
1908
- const tfNorm = (tf * (BM25_K1 + 1)) / (tf + BM25_K1 * (1 - BM25_B + BM25_B * (dl / avgDL)));
1909
- return idf(term) * (tfNorm + BM25_DELTA);
1910
- }
1911
- // Die frueher hier stehende Funktion `fuzzyMatch(qt, docTermSet)` ist am
1912
- // 19.08.2026 entfallen. Sie lief je Frage UND je Dokument und durchsuchte den
1913
- // Wortvorrat des Dokuments bis zu viermal — bei 499 Lektionen rund 540 der
1914
- // 788 Millisekunden je Frage.
1915
- //
1916
- // An ihre Stelle tritt `fuzzyKandidaten(qt)` weiter unten: die passenden
1917
- // Woerter werden EINMAL je Frage gegen den Gesamtwortschatz bestimmt, danach
1918
- // ist die Pruefung je Dokument ein Nachschlagen.
1919
- // ── Step 3: Score each sub-query independently ──
1920
- const subQueries = splitMultiQuery(query);
1921
- const allMatches = new Map();
1922
- for (const sq of subQueries) {
1923
- const queryTokens = tokenize(sq);
1924
- if (queryTokens.length === 0)
1925
- continue;
1926
- // ── Unscharfe Treffer einmal aufloesen, nicht je Dokument ──────────────
1927
- //
1928
- // Vorher stand im Bewertungsteil `fuzzyMatch(qt, new Set(doc.tokens))` —
1929
- // pro Frage UND pro Dokument. Bei 499 Lektionen mit je rund 300 Woertern
1930
- // und 40 Fragewoertern waren das ueber zwanzig Millionen Zeichenvergleiche,
1931
- // viele davon Levenshtein.
1932
- //
1933
- // Gemessen am 19.08.2026: von 788 ms je Frage entfielen 249 ms auf den
1934
- // Indexaufbau und rund 540 ms auf genau diese Schleife.
1935
- //
1936
- // Der Wortschatz ist fuer alle Dokumente derselbe. Also wird je Fragewort
1937
- // EINMAL bestimmt, welche vorhandenen Woerter dazu passen — danach ist die
1938
- // Pruefung je Dokument ein Nachschlagen in einer Map.
1939
- //
1940
- // Nebeneffekt: das Ergebnis wird VERLAESSLICHER. Vorher nahm fuzzyMatch das
1941
- // erste passende Wort in der Reihenfolge, in der die Woerter eines
1942
- // Dokuments zufaellig standen — dasselbe Fragewort konnte in zwei
1943
- // Dokumenten auf verschiedene Woerter treffen.
1944
- const fuzzySpeicher = new Map();
1945
- const fuzzyKandidaten = (qt) => {
1946
- const da = fuzzySpeicher.get(qt);
1947
- if (da)
1948
- return da;
1949
- // Alle Kandidaten je Stufe sammeln — NICHT nach den ersten acht
1950
- // abbrechen.
1951
- //
1952
- // Die erste Fassung tat genau das und kostete 15 von 100 Fragen: sie
1953
- // nahm die ersten acht Woerter in der Reihenfolge, in der sie zufaellig
1954
- // im Wortschatz standen, und die passten meist nicht zu dem Dokument,
1955
- // um das es ging. Schneller und schlechter ist kein Fortschritt.
1956
- const sammle = (passt, gewichtung) => {
1957
- const aus = [];
1958
- for (const dt of docFreq.keys())
1959
- if (passt(dt))
1960
- aus.push([dt, gewichtung]);
1961
- // Seltene Woerter zuerst: sie unterscheiden. Ein Wort, das in 300 von
1962
- // 499 Lektionen steht, sagt nichts darueber, welche gemeint ist.
1963
- aus.sort((a, b) => (docFreq.get(a[0]) ?? 0) - (docFreq.get(b[0]) ?? 0));
1964
- return aus.slice(0, FUZZY_KANDIDATEN);
1965
- };
1966
- let aus = [];
1967
- if (qt.length >= 4) {
1968
- aus = sammle((dt) => dt.length > qt.length && dt.startsWith(qt), 0.85);
1969
- }
1970
- if (aus.length === 0 && qt.length >= 4) {
1971
- aus = sammle((dt) => dt.length >= 4 && dt.length < qt.length && qt.startsWith(dt), 0.75);
1972
- }
1973
- if (aus.length === 0 && qt.length > 3) {
1974
- aus = sammle((dt) => dt.length > 3 && (dt.includes(qt) || qt.includes(dt)), 0.6);
1975
- }
1976
- if (aus.length === 0 && qt.length >= 4) {
1977
- aus = sammle((dt) => dt.length >= 4 && levenshtein(qt, dt) <= 2, 0.4);
1978
- }
1979
- fuzzySpeicher.set(qt, aus);
1980
- return aus;
1981
- };
1982
- // Die Woerter, die der Mensch WIRKLICH getippt hat — ohne Synonyme.
1983
- //
1984
- // Gebraucht wird das fuer den Titel-Bonus weiter unten. Der teilte bisher
1985
- // durch die ERWEITERTE Fragelaenge, und das ist ein Fehler mit Ansage:
1986
- // eine deutsche Frage wird auf ein Vielfaches aufgeblasen (Englisch,
1987
- // Japanisch, Chinesisch, Koreanisch, Arabisch, Russisch ...), also sank
1988
- // der Bonus mit jedem Synonym, das wir der Tabelle hinzufuegten.
1989
- //
1990
- // Gemessen am 19.08.2026: "Jeder Build laedt alle Abhaengigkeiten neu ..."
1991
- // ergab 26 Tokens fuer 12 getippte Woerter. Ein Titeltreffer zaehlte damit
1992
- // 3/26 statt 3/12 — der Bonus fiel von 1,13 auf 1,06.
1993
- //
1994
- // Das ist die unangenehme Sorte Fehler: die Suche zu verbessern (mehr
1995
- // Synonyme) machte den Titel-Bonus schwaecher. Zwei Stellschrauben, die
1996
- // gegeneinander arbeiteten, ohne dass es jemandem auffiel.
1997
- const kernTokens = new Set(tokenize(sq, { crossLingualExpand: false }));
1998
- // Pre-compute query bigrams for proximity boost
1999
- const queryBigrams = new Set();
2000
- for (let j = 0; j < queryTokens.length - 1; j++) {
2001
- queryBigrams.add(`${queryTokens[j]}|${queryTokens[j + 1]}`);
2002
- }
2003
- for (const doc of docs) {
2004
- let score = 0;
2005
- const matchedWords = [];
2006
- for (const qt of queryTokens) {
2007
- // Ein Wort, das der Mensch getippt hat, zaehlt voll. Ein Synonym, das
2008
- // WIR ergaenzt haben, zaehlt weniger.
2009
- //
2010
- // Grund: die Bruecke von einer Sprache in die andere landet meistens
2011
- // bei allgemeinen Woertern. `Zugriffsprotokoll` wird ueber `protokoll`
2012
- // zu `log`, und `log` steht in hunderten Lektionen. Zaehlt das genauso
2013
- // viel wie ein getipptes seltenes Wort, gewinnt die Breite gegen die
2014
- // Genauigkeit.
2015
- const gewicht = kernTokens.has(qt) ? 1 : SYNONYM_GEWICHT;
2016
- const exactScore = bm25PlusTerm(qt, doc);
2017
- if (exactScore > 0) {
2018
- score += exactScore * gewicht;
2019
- matchedWords.push(qt);
2020
- continue;
2021
- }
2022
- // Unscharfer Treffer — die Kandidaten stehen schon fest, siehe unten.
2023
- for (const [term, gewichtung] of fuzzyKandidaten(qt)) {
2024
- if (!doc.tokenFreq.has(term))
2025
- continue;
2026
- score += bm25PlusTerm(term, doc) * gewichtung * gewicht;
2027
- matchedWords.push(`~${qt}`);
2028
- break;
2029
- }
2030
- }
2031
- // Bigram proximity boost: +50% for each adjacent query term pair found in doc
2032
- if (queryBigrams.size > 0) {
2033
- let bigramHits = 0;
2034
- for (const bg of queryBigrams) {
2035
- if (doc.bigrams.has(bg))
2036
- bigramHits++;
2037
- }
2038
- if (bigramHits > 0) {
2039
- score *= 1 + 0.5 * (bigramHits / queryBigrams.size);
2040
- }
2041
- }
2042
- // Phrase-match boost: if the raw (lowercased) query appears verbatim in content, 2× boost
2043
- // This rewards docs where the exact phrase exists (vs scattered tokens).
2044
- if (!process.env.AUS_PHRASE && sq.length >= 4 && doc.content.toLowerCase().includes(sq.toLowerCase())) {
2045
- score *= 2.0;
2046
- }
2047
- // Key/title boost: if query terms appear in the Redis key (=title), 1.5× boost
2048
- // Keys often encode the primary topic (e.g. "deploy:api:server"), so key hits are high-precision.
2049
- // Der Titel (Redis-Schluessel) ist das dichteste Feld, das wir haben:
2050
- // `ci:node3-disk-full-zombie-deploy` traegt die Antwort im Namen. Ein
2051
- // Treffer dort ist mehr wert als drei im Fliesstext.
2052
- //
2053
- // Bezugsgroesse sind deshalb die GETIPPTEN Woerter, nicht die erweiterten
2054
- // — siehe kernTokens oben. Und die Obergrenze ist hoeher (2,0 statt 1,5),
2055
- // weil der bisherige Deckel bei langen Fragen nie erreicht wurde.
2056
- if (score > 0) {
2057
- let keyHits = 0;
2058
- let kernHits = 0;
2059
- for (const qt of queryTokens) {
2060
- if (!doc.keyTokens.has(qt))
2061
- continue;
2062
- keyHits++;
2063
- if (kernTokens.has(qt))
2064
- kernHits++;
2065
- }
2066
- if (keyHits > 0) {
2067
- const anteil = kernHits / Math.max(1, kernTokens.size);
2068
- score *= 1 + 1.0 * Math.min(1, anteil * 2);
2069
- }
2070
- }
2071
- // Recency boost
2072
- score *= recencyBoost(doc.timestamp);
2073
- if (score > 0) {
2074
- const existing = allMatches.get(doc.key);
2075
- if (!existing || score > existing.score) {
2076
- allMatches.set(doc.key, {
2077
- key: doc.key,
2078
- content: doc.content,
2079
- score,
2080
- matchedWords: [...new Set(matchedWords)],
2081
- subQuery: subQueries.length > 1 ? sq : undefined,
2082
- });
2083
- }
2084
- }
2085
- }
2086
- }
2087
- // ── Step 4: Sort by score, return top-K ──
2088
- const sorted = [...allMatches.values()].sort((a, b) => b.score - a.score);
2089
- const topResults = sorted.slice(0, topK);
2090
- // ── Step 5: Zero-results logging + Did-You-Mean ───────────────────────────
2091
- if (topResults.length === 0) {
2092
- logZeroResult(query);
2093
- // Rebuild index vocab for Did-You-Mean suggestions
2094
- _indexVocab = new Set();
2095
- for (const doc of docs)
2096
- for (const t of doc.tokens)
2097
- _indexVocab.add(t);
2098
- }
2099
- return topResults;
2100
- }
2101
- // ── Exported for testing ──────────────────────────────────────────────────────
2102
- export { tokenize, splitMultiQuery, levenshtein, recencyBoost, extractTimestamp, STOPWORDS, katakanaToRomaji, arabicLightStem, expandCrossLingual, CROSS_LINGUAL_MAP };
2103
- export { keywordSearch, ZERO_RESULTS_LOG, logZeroResult, _indexVocab as indexVocab, zeroResultsTotal };
2104
- //# sourceMappingURL=search.js.map
1
+ const h=new Set(["the","a","an","is","are","was","were","be","been","being","have","has","had","having","do","does","did","doing","will","would","could","should","may","might","shall","can","to","of","in","for","on","with","at","by","from","as","into","through","during","before","after","above","below","between","about","against","among","around","without","within","along","across","behind","beyond","upon","toward","towards","and","but","or","not","no","nor","so","if","then","than","too","very","quite","rather","just","also","only","even","it","its","this","that","these","those","here","there","my","your","his","her","our","their","mine","yours","ours","what","which","who","whom","whose","how","when","where","why","all","each","every","both","few","more","most","much","many","other","some","such","own","same","any","either","neither","been","being","because","until","while","once","again","further","already","always","never","sometimes","often","still","yet","der","die","das","den","dem","des","ein","eine","einen","einem","einer","eines","und","oder","aber","denn","weil","ist","sind","war","waren","sein","wird","werden","wurde","hat","haben","hatte","hatten","kann","k\xF6nnen","konnte","soll","sollen","sollte","muss","m\xFCssen","musste","darf","mag","m\xF6chte","wollen","wollte","w\xFCrde","k\xF6nnte","sollte","mit","f\xFCr","auf","von","aus","bei","nach","\xFCber","unter","vor","hinter","neben","zwischen","durch","gegen","ohne","um","bis","seit","w\xE4hrend","wegen","trotz","statt","wie","was","wer","wen","wem","wessen","wo","wann","warum","nicht","noch","auch","schon","nur","sehr","mehr","viel","alle","jeder","jede","jedes","dieser","diese","dieses","jener","jene","jenes","mein","dein","sein","ihr","unser","euer","kein","keine","sich","mir","dir","ihm","uns","euch","ich","du","er","sie","es","wir","ihr","man","hier","dort","da","dann","also","doch","mal","eben","ganz","le","la","les","un","une","des","du","de","au","aux","et","ou","mais","donc","car","ni","que","qui","quoi","est","sont","\xE9tait","ont","avoir","\xEAtre","fait","faire","pour","par","avec","dans","sur","sous","entre","vers","chez","sans","avant","apr\xE8s","pendant","depuis","contre","ce","cette","ces","mon","ton","son","notre","votre","leur","je","tu","il","elle","nous","vous","ils","elles","on","ne","pas","plus","tr\xE8s","bien","aussi","tout","tous","toute","m\xEAme","autre","quel","quelle","comment","quand","o\xF9","pourquoi","el","la","los","las","un","una","unos","unas","del","al","lo","que","en","es","por","con","para","como","pero","m\xE1s","fue","ser","hay","est\xE1","han","son","tiene","hab\xEDa","era","su","sus","este","esta","estos","estas","ese","esa","esos","mi","tu","yo","\xE9l","ella","nosotros","ellos","ellas","usted","no","ya","s\xED","sin","sobre","entre","hasta","desde","donde","muy","todo","toda","todos","cada","otro","otra","otros","cuando","porque","aunque","tambi\xE9n","solo","despu\xE9s","antes","il","lo","la","li","le","gli","uno","una","dei","del","che","di","da","per","con","tra","fra","sul","nel","al","\xE8","sono","ha","hanno","era","essere","fare","fatto","stato","suo","sua","suoi","questo","questa","questi","quello","quella","io","tu","lui","lei","noi","voi","loro","ci","si","non","pi\xF9","molto","anche","solo","tutto","tutti","ogni","come","dove","quando","perch\xE9","ancora","gi\xE0","sempre","mai","um","uma","uns","umas","do","da","dos","das","no","na","ao","aos","em","por","com","para","sem","sob","sobre","que","se","mas","ou","como","mais","entre","at\xE9","desde","\xE9","s\xE3o","foi","tem","ser","ter","estar","fazer","havia","seu","sua","seus","suas","este","esta","esse","essa","aquele","eu","tu","ele","ela","n\xF3s","eles","elas","voc\xEA","voc\xEAs","n\xE3o","j\xE1","sim","bem","muito","tamb\xE9m","ainda","sempre","todo","toda","todos","cada","outro","outra","quando","porque","\u7684","\u4E86","\u662F","\u5728","\u4E0D","\u548C","\u6211","\u4ED6","\u8FD9","\u4E2D","\u5927","\u4E3A","\u4E0A","\u4E2A","\u56FD","\u4EE5","\u8981","\u5C31","\u51FA","\u8BF4","\u4EEC","\u6709","\u6765","\u5230","\u65F6","\u5730","\u5E74","\u5F97","\u7740","\u90A3","\u8FC7","\u540E","\u8FD8","\u4E0E","\u4E5F","\u53EF","\u4E8E","\u4ECE","\u4F46","\u800C","\u88AB","\u628A","\u8BA9","\u4F7F","\u5BF9","\u5F88","\u90FD","\u4E00","\u4F1A","\u6CA1","\u4EBA","\u5B83","\u8FD9\u4E2A","\u90A3\u4E2A","\u4EC0\u4E48","\u5982\u679C","\u56E0\u4E3A","\u6240\u4EE5","\u5DF2\u7ECF","\u53EF\u4EE5","\u8FD9\u4E9B","\u90A3\u4E9B","\u6211\u4EEC","\u4ED6\u4EEC","\u5979\u4EEC","\u5B83\u4EEC","\u306E","\u306F","\u304C","\u3092","\u306B","\u3067","\u3068","\u3082","\u3084","\u304B","\u306A","\u306D","\u3088","\u308F","\u3066","\u3044","\u3046","\u3048","\u304A","\u304D","\u304F","\u3051","\u3053","\u3055","\u3057","\u3059","\u305B","\u305D","\u305F","\u3061","\u3064","\u306C","\u3093","\u304B\u3089","\u307E\u3067","\u3088\u308A","\u3078","\u3067\u3059","\u307E\u3059","\u306A\u3044","\u3042\u308B","\u3044\u308B","\u3059\u308B","\u3053\u3068","\u3082\u306E","\u306E\u3067","\u3067\u306F","\u306B\u306F","\u3068\u306E","\u3078\u306E","\u304B\u3089","\u307E\u3067","\uC774","\uAC00","\uC740","\uB294","\uC744","\uB97C","\uC758","\uC5D0","\uC640","\uACFC","\uB3C4","\uB85C","\uC5D0\uC11C","\uD55C","\uD558","\uC788","\uC5C6","\uAC83","\uC218","\uC54A","\uB4E4","\uC774\uB2E4","\uD558\uB2E4","\uC774\uACE0","\uC774\uBA70","\uB77C\uACE0","\uC5D0\uAC8C","\uC5D0\uC11C","\uC73C\uB85C","\u0641\u064A","\u0645\u0646","\u0625\u0644\u0649","\u0639\u0644\u0649","\u0639\u0646","\u0645\u0639","\u0647\u0630\u0627","\u0647\u0630\u0647","\u0630\u0644\u0643","\u062A\u0644\u0643","\u0627\u0644\u0630\u064A","\u0627\u0644\u062A\u064A","\u0627\u0644\u0630\u064A\u0646","\u0627\u0644\u0644\u0648\u0627\u062A\u064A","\u0647\u0648","\u0647\u064A","\u0647\u0645","\u0647\u0646","\u0646\u062D\u0646","\u0623\u0646\u062A","\u0623\u0646\u062A\u0645","\u0623\u0646\u0627","\u0643\u0627\u0646","\u0643\u0627\u0646\u062A","\u0643\u0627\u0646\u0648\u0627","\u064A\u0643\u0648\u0646","\u062A\u0643\u0648\u0646","\u0623\u0646","\u0625\u0646","\u0644\u0623\u0646","\u0644\u0643\u0646","\u0623\u0648","\u0628\u0644","\u062B\u0645","\u062D\u062A\u0649","\u0625\u0630\u0627","\u0643\u064A","\u0642\u062F","\u0644\u0642\u062F","\u0644\u0645","\u0644\u0646","\u0645\u0627","\u0644\u0627","\u0644\u064A\u0633","\u063A\u064A\u0631","\u0628\u0639\u0636","\u0643\u0644","\u062C\u0645\u064A\u0639","\u0623\u064A","\u0643\u064A\u0641","\u0645\u062A\u0649","\u0623\u064A\u0646","\u0644\u0645\u0627\u0630\u0627","\u0645\u0627\u0630\u0627","\u0647\u0644","\u0627\u0644","\u0648","\u0641","\u0628","\u0644","\u0643","\u064A\u0627","\u0623\u0645","\u0625\u0644\u0627","\u0639\u0646\u062F","\u0628\u064A\u0646","\u05E9\u05DC","\u05D0\u05EA","\u05D0\u05DC","\u05E2\u05DC","\u05E2\u05DD","\u05DC\u05D0","\u05D4\u05D5\u05D0","\u05D4\u05D9\u05D0","\u05D4\u05DD","\u05D4\u05DF","\u05D0\u05E0\u05D9","\u05D0\u05EA\u05D4","\u05D0\u05E0\u05D7\u05E0\u05D5","\u05D0\u05EA\u05DD","\u05DB\u05D9","\u05D0\u05DD","\u05D0\u05D1\u05DC","\u05D2\u05DD","\u05DB\u05D1\u05E8","\u05E8\u05E7","\u05E2\u05D5\u05D3","\u05D9\u05E9","\u05D0\u05D9\u05DF","\u05DE\u05D4","\u05D6\u05D4","\u05D6\u05D0\u05EA","\u05D0\u05DC\u05D4","\u05DB\u05DC","\u05DB\u05DF","\u05DC\u05D5","\u05DC\u05D4","\u05DC\u05D4\u05DD","\u05D1\u05D5","\u05D1\u05D4","\u05D1\u05D4\u05DD","\u05E9\u05DD","\u05DB\u05DA","\u05DB\u05DF","\u05DE\u05D9","\u05D0\u05E9\u05E8","\u05D0\u05D7\u05E8\u05D9","\u05DC\u05E4\u05E0\u05D9","\u05EA\u05D7\u05EA","\u05D1\u05D9\u05DF","\u05DE\u05D0\u05D6","\u05E2\u05D3","\u05DB\u05DE\u05D5","\u05D0\u05D6","\u062F\u0631","\u0627\u0632","\u0628\u0647","\u0628\u0627","\u06A9\u0647","\u0627\u06CC\u0646","\u0622\u0646","\u0631\u0627","\u0627\u0633\u062A","\u0628\u0648\u062F","\u0628\u0627\u0634\u062F","\u0634\u062F","\u0634\u062F\u0647","\u0645\u06CC","\u0646\u0647","\u0646\u06CC\u0633\u062A","\u0647\u0645","\u0647\u0631","\u06CC\u06A9","\u0627\u0645\u0627","\u0648","\u06CC\u0627","\u062A\u0627","\u0627\u06AF\u0631","\u0628\u0631\u0627\u06CC","\u0686\u0648\u0646","\u0686\u0647","\u06A9\u062C\u0627","\u06A9\u06CC","\u0686\u0637\u0648\u0631","\u0648\u0642\u062A\u06CC","\u0628\u0639\u062F","\u0642\u0628\u0644","\u0645\u062B\u0644","\u0647\u0645\u0647","\u0628\u0639\u0636\u06CC","\u0647\u06CC\u0686","\u0622\u06CC\u0627","\u062E\u0648\u062F","\u0686\u0646\u062F","\u062F\u06CC\u06AF\u0631","\u0647\u0646\u0648\u0632","\u0647\u0645\u0627\u0646","\u0622\u0646\u0647\u0627","\u0627\u06CC\u0646\u0647\u0627","\u0645\u0627","\u0634\u0645\u0627","\u0622\u0646\u0627\u0646","\u0645\u0646","\u062A\u0648","\u0627\u0648","\u0622\u0646\u0627\u0646","\u0627\u06CC\u0634\u0627\u0646","\u0631\u0648\u06CC","\u0632\u06CC\u0631","\u0628\u06CC\u0646","\u067E\u06CC\u0634","\u067E\u0633","\u0637\u0631\u0641","\u062F\u0627\u062E\u0644","\u062E\u0627\u0631\u062C","\u06A9\u0646\u0627\u0631","\u0647\u0645\u0686\u0646\u06CC\u0646","\u0645\u06AF\u0631","\u0648\u0644\u06CC","\u0648\u06AF\u0631\u0646\u0647","\u0686\u0631\u0627","\u0686\u06AF\u0648\u0646\u0647","\u06A9\u062F\u0627\u0645","\u0939\u0948","\u092E\u0947\u0902","\u0938\u0947","\u0915\u094B","\u0915\u093E","\u0915\u0940","\u0915\u0947","\u092A\u0930","\u0914\u0930","\u092F\u093E","\u0928\u0939\u0940\u0902","\u092F\u0939","\u0935\u0939","\u090F\u0915","\u0907\u0938","\u0909\u0938","\u092D\u0940","\u0939\u094B","\u0925\u093E","\u0925\u0940","\u0925\u0947","\u0939\u0948\u0902","\u0939\u0942\u0901","\u0932\u093F\u090F","\u0924\u0915","\u0938\u093E\u0925","\u092C\u093E\u0926","\u092A\u0939\u0932\u0947","\u091C\u094B","\u091C\u092C","\u0915\u0948\u0938\u0947","\u0915\u094D\u092F\u094B\u0902","\u0915\u094D\u092F\u093E","\u0915\u0939\u093E\u0901","\u0915\u094C\u0928","\u0939\u092E","\u0906\u092A","\u0935\u0947","\u092E\u0948\u0902","\u0924\u0941\u092E","\u0909\u0928","\u0907\u0928","\u0928\u0947","\u092C\u0939\u0941\u0924","\u0938\u092C","\u0915\u0941\u091B","\u092B\u093F\u0930","\u0905\u092C","\u0924\u094B","\u0939\u0940","\u0924\u0930\u0939","\u091C\u0948\u0938\u0947","\u0915\u0930\u0928\u093E","\u0939\u094B\u0928\u093E","\u0930\u0939\u093E","\u0930\u0939\u0940","\u0930\u0939\u0947","\u0917\u092F\u093E","\u0917\u0908","\u0917\u090F","\u0915\u093F\u092F\u093E","\u0915\u093F\u090F","\u0915\u0930","\u0939\u0941\u0906","\u0939\u0941\u0908","\u0432","\u043D\u0430","\u043D\u0435","\u0441","\u0438","\u0430","\u043D\u043E","\u043F\u043E","\u0437\u0430","\u0438\u0437","\u043E\u0442","\u0434\u043E","\u043A","\u0443","\u043E","\u043E\u0431","\u0432\u043E","\u043F\u0440\u0438","\u043F\u043E\u0434","\u043D\u0430\u0434","\u0431\u0435\u0437","\u0434\u043B\u044F","\u0447\u0442\u043E","\u043A\u0430\u043A","\u044D\u0442\u043E","\u0432\u0441\u0435","\u0442\u0430\u043A","\u0443\u0436\u0435","\u0438\u043B\u0438","\u0436\u0435","\u043B\u0438","\u0435\u0441\u043B\u0438","\u0442\u043E","\u0434\u0430","\u043D\u0435\u0442","\u0431\u044B\u043B","\u0431\u044B\u043B\u0430","\u0431\u044B\u043B\u0438","\u0431\u044B\u0442\u044C","\u0435\u0441\u0442\u044C","\u0435\u0433\u043E","\u0435\u0451","\u0438\u0445","\u044D\u0442\u043E\u0442","\u044D\u0442\u0430","\u044D\u0442\u0438","\u043A\u043E\u0442\u043E\u0440\u044B\u0439","\u043A\u043E\u0442\u043E\u0440\u0430\u044F","\u043A\u043E\u0442\u043E\u0440\u044B\u0435","\u043A\u043E\u0442\u043E\u0440\u044B\u0439","\u043C\u043E\u0439","\u043C\u043E\u044F","\u043C\u043E\u0438","\u0432\u0430\u0448","\u0432\u0430\u0448\u0430","\u0432\u0430\u0448\u0438","\u043E\u043D","\u043E\u043D\u0430","\u043E\u043D\u0438","\u043C\u044B","\u0432\u044B","\u044F","\u0442\u044B","\u0442\u043E\u0442","\u0442\u0430","\u0442\u0435","\u043E\u0447\u0435\u043D\u044C","\u0442\u043E\u0436\u0435","\u0442\u0430\u043A\u0436\u0435","\u043A\u043E\u0433\u0434\u0430","\u0433\u0434\u0435","\u043A\u0430\u043A","\u043F\u043E\u0447\u0435\u043C\u0443","\u0437\u0430\u0447\u0435\u043C","\u0441\u0435\u0439\u0447\u0430\u0441","\u0437\u0434\u0435\u0441\u044C","\u0442\u0430\u043C","\u043F\u043E\u0442\u043E\u043C\u0443","\u043F\u043E\u044D\u0442\u043E\u043C\u0443","\u0447\u0442\u043E\u0431\u044B","\u0442\u0443\u0442","bir","bu","\u015Fu","o","ve","ile","de","da","i\xE7in","gibi","ama","fakat","ancak","ya","ne","ki","mi","m\u0131","mu","m\xFC","var","yok","olan","oldu","olur","olarak","ise","daha","\xE7ok","en","her","hi\xE7","baz\u0131","t\xFCm","b\xFCt\xFCn","hem","veya","bu","\u015Fu","ben","sen","biz","siz","onlar","benim","senin","nas\u0131l","neden","ni\xE7in","nerede","ne","hangi","ka\xE7","w","na","z","do","si\u0119","\u017Ce","to","jest","i","a","nie","tak","jak","czy","po","o","ale","go","mu","jej","ich","tego","tej","te","ten","ta","s\u0105","by\u0142","by\u0142a","by\u0142o","byli","b\u0119dzie","b\u0119d\u0105","ma","mam","masz","maj\u0105","ze","co","ju\u017C","przez","przy","za","bez","nad","pod","przed","po","mi\u0119dzy","kiedy","gdzie","dlaczego","kt\xF3ry","kt\xF3ra","kt\xF3re","tylko","te\u017C","v","na","z","do","se","\u017Ee","to","je","a","ne","pro","ale","jak","by","byl","b\xFDt","jsem","jsou","m\xE1","m\xE1m","ten","ta","ty","tato","jeho","jej\xED","jejich","tak\xE9","jen","kde","kdy","pro\u010D","kter\xFD","kter\xE1","kter\xE9","co","p\u0159i","bez","\u098F\u0987","\u098F\u099F\u09BF","\u098F\u099F\u09BE","\u098F\u09B0","\u09A4\u09BE\u09B0","\u09A4\u09BE\u09B0\u09BE","\u0986\u09AE\u09BF","\u09A4\u09C1\u09AE\u09BF","\u09B8\u09C7","\u0986\u09AE\u09B0\u09BE","\u098F\u09AC\u0982","\u0995\u09BF\u09A8\u09CD\u09A4\u09C1","\u09AC\u09BE","\u09A8\u09BE","\u09B9\u09CD\u09AF\u09BE\u0981","\u09AF\u09C7","\u0995\u09BF","\u0995\u09C7","\u0995\u09C0","\u09A5\u09C7\u0995\u09C7","\u09A6\u09BF\u09AF\u09BC\u09C7","\u099C\u09A8\u09CD\u09AF","\u09B8\u09BE\u09A5\u09C7","\u09AE\u09A7\u09CD\u09AF\u09C7","\u0989\u09AA\u09B0","\u09A8\u09BF\u099A\u09C7","\u0986\u099B\u09C7","\u099B\u09BF\u09B2","\u09B9\u09AF\u09BC","\u0995\u09B0\u09BE","\u0995\u09B0\u09C7","\u0995\u09B0\u09C7\u099B\u09C7","\u09B9\u09AC\u09C7","\u09B9\u09AF\u09BC\u09C7\u099B\u09C7","\u098F\u0995\u099F\u09BF","\u098F\u0995\u099F\u09BE","\u0985\u09A8\u09C7\u0995","\u09B8\u09AC","t\xF4i","b\u1EA1n","anh","ch\u1ECB","em","h\u1ECD","ch\xFAng","ta","m\xECnh","l\xE0","c\xF3","kh\xF4ng","v\xE0","v\u1EDBi","c\u1EE7a","cho","trong","v\u1EC1","t\u1EEB","\u0111\u1EBFn","\u0111\u1EC3","khi","n\u1EBFu","th\xEC","m\xE0","nh\u01B0ng","v\xEC","\u0111\xE2y","\u0111\xF3","n\xE0y","kia","r\u1EA5t","c\u0169ng","\u0111\xE3","s\u1EBD","\u0111ang","\u0111\u01B0\u1EE3c","b\u1ECB","nh\u1EEFng","c\xE1c","m\u1ED9t","hai","ba","nhi\u1EC1u","\xEDt","n\xE0o","ai","g\xEC","\u0111\xE2u","sao","bao","gi\u1EDD","l\xFAc","sau"]),T=/[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/,he=/([\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+|[^\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+)/g,M=/[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufb4f\ufb50-\ufdff\ufe70-\ufeff]/,C=/[\u0590-\u05ff\ufb1d-\ufb4f]/,Se=/[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb50-\ufdff\ufe70-\ufeff]/,F=/[\u067e\u0686\u0698\u06af\u06cc]/,O=/[\u0900-\u097f]/,P=/[\u0400-\u04ff]/,$=/[\u011f\u015f\u0131\u0130\u00e7]/,U=/[\u0980-\u09ff]/,Ee=/[\u1ea0-\u1ef9]/,de=[["\u30D5\u30A1","fa"],["\u30D5\u30A3","fi"],["\u30D5\u30A7","fe"],["\u30D5\u30A9","fo"],["\u30C6\u30A3","ti"],["\u30C7\u30A3","di"],["\u30C8\u30A5","tu"],["\u30C9\u30A5","du"],["\u30A6\u30A3","wi"],["\u30A6\u30A7","we"],["\u30A6\u30A9","wo"],["\u30C1\u30A7","che"],["\u30B8\u30A7","je"],["\u30B7\u30A7","she"],["\u30A4\u30A7","ye"],["\u30F4\u30A1","va"],["\u30F4\u30A3","vi"],["\u30F4\u30A7","ve"],["\u30F4\u30A9","vo"],["\u30AD\u30E3","kya"],["\u30AD\u30E5","kyu"],["\u30AD\u30E7","kyo"],["\u30B7\u30E3","sha"],["\u30B7\u30E5","shu"],["\u30B7\u30E7","sho"],["\u30C1\u30E3","cha"],["\u30C1\u30E5","chu"],["\u30C1\u30E7","cho"],["\u30CB\u30E3","nya"],["\u30CB\u30E5","nyu"],["\u30CB\u30E7","nyo"],["\u30D2\u30E3","hya"],["\u30D2\u30E5","hyu"],["\u30D2\u30E7","hyo"],["\u30DF\u30E3","mya"],["\u30DF\u30E5","myu"],["\u30DF\u30E7","myo"],["\u30EA\u30E3","rya"],["\u30EA\u30E5","ryu"],["\u30EA\u30E7","ryo"],["\u30AE\u30E3","gya"],["\u30AE\u30E5","gyu"],["\u30AE\u30E7","gyo"],["\u30B8\u30E3","ja"],["\u30B8\u30E5","ju"],["\u30B8\u30E7","jo"],["\u30D3\u30E3","bya"],["\u30D3\u30E5","byu"],["\u30D3\u30E7","byo"],["\u30D4\u30E3","pya"],["\u30D4\u30E5","pyu"],["\u30D4\u30E7","pyo"],["\u30A2","a"],["\u30A4","i"],["\u30A6","u"],["\u30A8","e"],["\u30AA","o"],["\u30AB","ka"],["\u30AD","ki"],["\u30AF","ku"],["\u30B1","ke"],["\u30B3","ko"],["\u30B5","sa"],["\u30B7","shi"],["\u30B9","su"],["\u30BB","se"],["\u30BD","so"],["\u30BF","ta"],["\u30C1","chi"],["\u30C4","tsu"],["\u30C6","te"],["\u30C8","to"],["\u30CA","na"],["\u30CB","ni"],["\u30CC","nu"],["\u30CD","ne"],["\u30CE","no"],["\u30CF","ha"],["\u30D2","hi"],["\u30D5","fu"],["\u30D8","he"],["\u30DB","ho"],["\u30DE","ma"],["\u30DF","mi"],["\u30E0","mu"],["\u30E1","me"],["\u30E2","mo"],["\u30E4","ya"],["\u30E6","yu"],["\u30E8","yo"],["\u30E9","ra"],["\u30EA","ri"],["\u30EB","ru"],["\u30EC","re"],["\u30ED","ro"],["\u30EF","wa"],["\u30F2","wo"],["\u30F3","n"],["\u30AC","ga"],["\u30AE","gi"],["\u30B0","gu"],["\u30B2","ge"],["\u30B4","go"],["\u30B6","za"],["\u30B8","ji"],["\u30BA","zu"],["\u30BC","ze"],["\u30BE","zo"],["\u30C0","da"],["\u30C2","ji"],["\u30C5","zu"],["\u30C7","de"],["\u30C9","do"],["\u30D0","ba"],["\u30D3","bi"],["\u30D6","bu"],["\u30D9","be"],["\u30DC","bo"],["\u30D1","pa"],["\u30D4","pi"],["\u30D7","pu"],["\u30DA","pe"],["\u30DD","po"],["\u30F4","v"],["\u30FC",""],["\u30A1","a"],["\u30A3","i"],["\u30A5","u"],["\u30A7","e"],["\u30A9","o"],["\u30C3",""]],A=new Map(de);function Z(t){let e="",o=0;for(;o<t.length;){if(t[o]==="\u30C3"&&o+1<t.length){const m=A.get(t[o+1])??A.get(t[o+1]+t[o+2])??"";m.length>0&&(e+=m[0]),o++;continue}if(o+1<t.length){const m=t[o]+t[o+1],u=A.get(m);if(u!==void 0){e+=u,o+=2;continue}}const a=A.get(t[o]);a!==void 0&&(e+=a),o++}return e}function N(t){let e=t;for(let o=0;o<3;o++){const a=e;if(e.startsWith("\u0627\u0644")&&e.length>4?e=e.slice(2):e.length>3&&"\u0648\u0628\u0644\u0641\u0643".includes(e[0])&&M.test(e[1])&&(e=e.slice(1)),e===a)break}return e}function K(t){let e=t;for(let o=0;o<3;o++){const a=e;if(e.length>3&&"\u05D4\u05D5\u05D1\u05DC\u05DE\u05DB".includes(e[0])&&C.test(e[1])&&(e=e.slice(1)),e===a)break}return e}function G(t){let e=t;return e.endsWith("\u0647\u0627\u06CC")&&e.length>5?e=e.slice(0,-3):e.endsWith("\u0647\u0627")&&e.length>4&&(e=e.slice(0,-2)),e.startsWith("\u0646\u0645\u06CC\u200C")&&e.length>5?e=e.slice(4):e.startsWith("\u0645\u06CC\u200C")&&e.length>4?e=e.slice(3):e.startsWith("\u0645\u06CC")&&e.length>4&&(e=e.slice(2)),e}function Y(t){const e=t;return e.endsWith("\u0928\u093E")&&e.length>4||e.endsWith("\u0928\u0947")&&e.length>4||e.endsWith("\u0928\u0940")&&e.length>4||e.endsWith("\u0924\u093E")&&e.length>4||e.endsWith("\u0924\u0940")&&e.length>4||e.endsWith("\u0915\u0930")&&e.length>4||e.endsWith("\u0913\u0902")&&e.length>4?e.slice(0,-2):e.endsWith("\u0907\u092F\u093E\u0902")&&e.length>5||e.endsWith("\u0940\u092F\u093E\u0902")&&e.length>5?e.slice(0,-4):e}function V(t){const e=t;return e.endsWith("\u044B\u0432\u0430\u043D\u0438\u0435")&&e.length>7||e.endsWith("\u0438\u0432\u0430\u043D\u0438\u0435")&&e.length>7||e.endsWith("\u043E\u0432\u0430\u043D\u0438\u0435")&&e.length>7?e.slice(0,-6):e.endsWith("\u0432\u0430\u043D\u0438\u0435")&&e.length>6?e.slice(0,-5):e.endsWith("\u0435\u043D\u0438\u0435")&&e.length>5||e.endsWith("\u0430\u043D\u0438\u0435")&&e.length>5?e.slice(0,-4):e.endsWith("\u0438\u0442\u044C")&&e.length>4||e.endsWith("\u0430\u0442\u044C")&&e.length>4||e.endsWith("\u0435\u0442\u044C")&&e.length>4||e.endsWith("\u0443\u0442\u044C")&&e.length>4?e.slice(0,-3):e.endsWith("\u043A\u0438")&&e.length>4||e.endsWith("\u0433\u0438")&&e.length>4||e.endsWith("\u043E\u0432")&&e.length>4||e.endsWith("\u0435\u0432")&&e.length>4||e.endsWith("\u0435\u0439")&&e.length>4||e.endsWith("\u0438\u0439")&&e.length>4||e.endsWith("\u044B\u0439")&&e.length>4||e.endsWith("\u0430\u044F")&&e.length>4||e.endsWith("\u043E\u0435")&&e.length>4||e.endsWith("\u0443\u044E")&&e.length>4||e.endsWith("\u0435\u0442")&&e.length>4||e.endsWith("\u044E\u0442")&&e.length>4||e.endsWith("\u0443\u0442")&&e.length>4||e.endsWith("\u044F\u0442")&&e.length>4?e.slice(0,-2):e}function Q(t){const e=t;return e.endsWith("lardaki")&&e.length>7||e.endsWith("lerdeki")&&e.length>7?e.slice(0,-7):e.endsWith("lar\u0131n")&&e.length>6||e.endsWith("lerin")&&e.length>6||e.endsWith("larda")&&e.length>6||e.endsWith("lerde")&&e.length>6?e.slice(0,-5):e.endsWith("lar\u0131")&&e.length>5||e.endsWith("leri")&&e.length>5?e.slice(0,-4):e.endsWith("mek")&&e.length>4||e.endsWith("mak")&&e.length>4||e.endsWith("ler")&&e.length>4||e.endsWith("lar")&&e.length>4||e.endsWith("n\u0131n")&&e.length>4||e.endsWith("nin")&&e.length>4||e.endsWith("nun")&&e.length>4||e.endsWith("n\xFCn")&&e.length>4?e.slice(0,-3):e.endsWith("da")&&e.length>4||e.endsWith("de")&&e.length>4||e.endsWith("ta")&&e.length>4||e.endsWith("te")&&e.length>4?e.slice(0,-2):e.endsWith("dan")&&e.length>4||e.endsWith("den")&&e.length>4||e.endsWith("tan")&&e.length>4||e.endsWith("ten")&&e.length>4?e.slice(0,-3):e.endsWith("\u0131n")&&e.length>4||e.endsWith("in")&&e.length>4||e.endsWith("un")&&e.length>4||e.endsWith("\xFCn")&&e.length>4?e.slice(0,-2):e.endsWith("\u0131")&&e.length>4||e.endsWith("i")&&e.length>4||e.endsWith("u")&&e.length>4||e.endsWith("\xFC")&&e.length>4?e.slice(0,-1):e}function J(t){const e=t;return e.endsWith("\u0997\u09C1\u09B2\u09CB")&&e.length>5||e.endsWith("\u0997\u09C1\u09B2\u09BF")&&e.length>5?e.slice(0,-4):e.endsWith("\u09A6\u09C7\u09B0")&&e.length>4?e.slice(0,-3):e.endsWith("\u09A6\u09BF\u0997\u09C7")&&e.length>5?e.slice(0,-4):e.endsWith("\u099F\u09BF")&&e.length>3||e.endsWith("\u099F\u09BE")&&e.length>3?e.slice(0,-2):e.endsWith("\u0996\u09BE\u09A8\u09BE")&&e.length>5?e.slice(0,-4):e.endsWith("\u099B\u09C7")&&e.length>3?e.slice(0,-2):e.endsWith("\u099B\u09BF\u09B2")&&e.length>4?e.slice(0,-3):e.endsWith("\u09AF\u09BE\u09AC\u09C7")&&e.length>5?e.slice(0,-4):e.endsWith("\u0995\u09B0\u09BE")&&e.length>4||e.endsWith("\u0995\u09B0\u09C7")&&e.length>4?e.slice(0,-3):e.endsWith("\u09B9\u09DF")&&e.length>3?e.slice(0,-2):e.endsWith("\u09B9\u09AC\u09C7")&&e.length>4?e.slice(0,-3):e}function ge(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1 $2").replace(/_/g," ")}import{ohneUmlaute as R,deutscherStamm as fe,ohneRueckumlaut as me,zerlegeKompositum as pe,DEUTSCHE_FACHWOERTER as be}from"./deutsch.js";const j=new Map([["javascript",["js","node","nodejs","ecmascript"]],["js",["javascript","node","nodejs"]],["typescript",["ts","javascript","js","tsc"]],["ts",["typescript","javascript","js"]],["python",["py","pip","django","flask","fastapi"]],["py",["python","pip"]],["golang",["go","gopher","goroutine"]],["go",["golang","goroutine"]],["rust",["cargo","rustlang","crates"]],["cargo",["rust","rustlang"]],["java",["jvm","maven","gradle","spring"]],["kotlin",["jvm","android","coroutine"]],["dotnet",["csharp","asp","nuget","aspnet"]],["postgresql",["postgres","pg","psql"]],["postgres",["postgresql","pg","psql"]],["mysql",["mariadb","sql"]],["mongodb",["mongo","nosql","bson","mongoose"]],["mongo",["mongodb","nosql","bson"]],["elasticsearch",["elastic","opensearch","lucene","kibana"]],["elastic",["elasticsearch","opensearch"]],["kubernetes",["k8s","kube","kubectl","helm","k3s"]],["k8s",["kubernetes","kube","kubectl","helm"]],["helm",["kubernetes","k8s","chart"]],["terraform",["tf","hcl","iac","opentofu"]],["ansible",["playbook","automation"]],["grafana",["dashboard","visualization","metrics"]],["prometheus",["metrics","alert","scrape","grafana"]],["nginx",["proxy","webserver","ingress"]],["traefik",["proxy","ingress","router"]],["rabbitmq",["amqp","queue","broker","messaging"]],["kafka",["messaging","stream","broker"]],["grpc",["protobuf","proto","rpc"]],["graphql",["gql","resolver","schema"]],["react",["jsx","hooks","component","redux"]],["nextjs",["next","react","ssr","vercel"]],["vue",["vuejs","vite","nuxt"]],["angular",["ng","rxjs","typescript"]],["aws",["amazon","ec2","s3","lambda","cloudwatch","ecs","eks"]],["gcp",["google cloud","gke","bigquery"]],["azure",["microsoft cloud","aks","devops"]],["s3",["bucket","object storage","aws"]],["lambda",["serverless","function","faas","aws"]],["jwt",["token","bearer","oauth","auth"]],["oauth",["oidc","auth","token","sso"]],["webhook",["callback","event","trigger"]],["cron",["schedule","job","timer"]],["yaml",["yml","config","manifest"]],["dotenv",["env","environment","envfile"]],["github",["git","actions","repo","ci"]],["gitlab",["git","pipeline","runner"]],["wireguard",["vpn","tunnel","wg"]],["prisma",["orm","database","schema","migration"]],["npm",["node","package","registry","yarn","pnpm"]],["yarn",["npm","package","node"]],["pip",["python","package","pypi"]],["brew",["homebrew","macos","package"]],["deploy",["\u30C7\u30D7\u30ED\u30A4","\u90E8\u7F72","\uBC30\uD3EC","deployment","deploying","\u0646\u0634\u0631","\u05E4\u05E8\u05D9\u05E1\u05D4","\u0627\u0633\u062A\u0642\u0631\u0627\u0631","\u0924\u0948\u0928\u093E\u0924\u0940","bereitstellen","bereitstellung","d\xE9ployer","d\xE9ploiement","desplegar","despliegue","distribuire","distribuzione","implantar","implanta\xE7\xE3o","\u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435","\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435","da\u011F\u0131t\u0131m","da\u011F\u0131tmak","tri\u1EC3n khai"]],["deployment",["\u30C7\u30D7\u30ED\u30A4","\u90E8\u7F72","\uBC30\uD3EC","deploy","\u0646\u0634\u0631","\u05E4\u05E8\u05D9\u05E1\u05D4","\u0627\u0633\u062A\u0642\u0631\u0627\u0631","\u0924\u0948\u0928\u093E\u0924\u0940","bereitstellung","d\xE9ploiement","despliegue","distribuzione","implanta\xE7\xE3o","\u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435","da\u011F\u0131t\u0131m","tri\u1EC3n khai"]],["container",["\u30B3\u30F3\u30C6\u30CA","\u5BB9\u5668","\uCEE8\uD14C\uC774\uB108","docker"]],["server",["\u30B5\u30FC\u30D0\u30FC","\u30B5\u30FC\u30D0","\u670D\u52A1\u5668","\uC11C\uBC84","\u0633\u064A\u0631\u0641\u0631","\u05E9\u05E8\u05EA","\u0633\u0631\u0648\u0631","\u0938\u0930\u094D\u0935\u0930","\u0441\u0435\u0440\u0432\u0435\u0440","sunucu","m\xE1y ch\u1EE7"]],["database",["\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9","\u6570\u636E\u5E93","\uB370\uC774\uD130\uBCA0\uC774\uC2A4","db","\u0642\u0627\u0639\u062F\u0629 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A","datenbank","\u067E\u0627\u06CC\u06AF\u0627\u0647 \u062F\u0627\u062F\u0647","\u0921\u0947\u091F\u093E\u092C\u0947\u0633","base de donn\xE9es","base de datos","banco de dados"]],["cache",["\u30AD\u30E3\u30C3\u30B7\u30E5","\u7F13\u5B58","\uCE90\uC2DC","\u0643\u0627\u0634","\u05DE\u05D8\u05DE\u05D5\u05DF","\u06A9\u0634","\u0915\u0948\u0936","\u043A\u044D\u0448","\xF6nbellek","b\u1ED9 \u0111\u1EC7m"]],["error",["\u30A8\u30E9\u30FC","\u9519\u8BEF","\uC624\uB958","\u062E\u0637\u0623","\u05E9\u05D2\u05D9\u05D0\u05D4","\u062E\u0637\u0627","\u0924\u094D\u0930\u0941\u091F\u093F","\u0917\u0932\u0924\u0940","exception","err","fehler","erreur","fallo","errore","erro","\u043E\u0448\u0438\u0431\u043A\u0430","hata","hatal\u0131","l\u1ED7i"]],["bug",["\u30D0\u30B0","\u7F3A\u9677","\uBC84\uADF8","issue","defect","\u062E\u0644\u0644","\u0627\u0634\u06A9\u0627\u0644","\u092C\u0917"]],["fix",["\u4FEE\u6B63","\u4FEE\u590D","\uC218\uC815","bugfix","patch","hotfix","\u0625\u0635\u0644\u0627\u062D","\u05EA\u05D9\u05E7\u05D5\u05DF","\u0631\u0641\u0639","\u0938\u0941\u0927\u093E\u0930","beheben","behoben","r\xE9parer","correction","arreglar","correcci\xF3n","correggere","corrigir","\u0438\u0441\u043F\u0440\u0430\u0432\u0438\u0442\u044C","\u0438\u0441\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435","d\xFCzeltmek","d\xFCzeltme"]],["build",["\u30D3\u30EB\u30C9","\u6784\u5EFA","\uBE4C\uB4DC","\u0628\u0646\u0627\u0621","\u05D1\u05E0\u05D9\u05D9\u05D4","\u0633\u0627\u062E\u062A","\u0928\u093F\u0930\u094D\u092E\u093E\u0923","bauen","construire","construir","costruire","\u0441\u0431\u043E\u0440\u043A\u0430","\u0441\u043E\u0431\u0440\u0430\u0442\u044C","derleme","derlemek"]],["test",["\u30C6\u30B9\u30C8","\u6D4B\u8BD5","\uD14C\uC2A4\uD2B8","\u0627\u062E\u062A\u0628\u0627\u0631","\u05D1\u05D3\u05D9\u05E7\u05D4","\u0622\u0632\u0645\u0627\u06CC\u0634","\u092A\u0930\u0940\u0915\u094D\u0937\u0923","testen","tester","probar","testare","testar","\u0442\u0435\u0441\u0442","\u0442\u0435\u0441\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435","test","testlemek"]],["auth",["\u8A8D\u8A3C","\u8BA4\u8BC1","\uC778\uC99D","authentication","login","oauth","\u0645\u0635\u0627\u062F\u0642\u0629","\u05D0\u05D9\u05DE\u05D5\u05EA","\u0627\u062D\u0631\u0627\u0632 \u0647\u0648\u06CC\u062A","\u092A\u094D\u0930\u092E\u093E\u0923\u0940\u0915\u0930\u0923","authentifizierung","authentification","autenticaci\xF3n","autenticazione","autentica\xE7\xE3o","\u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F","\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F","kimlik do\u011Frulama","yetkilendirme"]],["authentication",["auth","\u0645\u0635\u0627\u062F\u0642\u0629","\u05D0\u05D9\u05DE\u05D5\u05EA","\u0627\u062D\u0631\u0627\u0632 \u0647\u0648\u06CC\u062A","\u092A\u094D\u0930\u092E\u093E\u0923\u0940\u0915\u0930\u0923","\u8A8D\u8A3C","\u8BA4\u8BC1","\uC778\uC99D","login","oauth","\u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F","\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F","kimlik do\u011Frulama"]],["environment",["\u74B0\u5883","\u73AF\u5883","\uD658\uACBD","env","\u0628\u064A\u0626\u0629","\u05E1\u05D1\u05D9\u05D1\u05D4","umgebung","environnement","entorno","ambiente","\u0441\u0440\u0435\u0434\u0430","\u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435","ortam"]],["secret",["key","token","password","jwt","\u0645\u0641\u062A\u0627\u062D","\u05DE\u05E4\u05EA\u05D7","geheimnis","schl\xFCssel","clave","cl\xE9","chiave","chave","\u0441\u0435\u043A\u0440\u0435\u0442","\u043A\u043B\u044E\u0447","gizli","anahtar"]],["problem",["error","issue","bug","failure","\u0645\u0634\u0643\u0644\u0629","\u554F\u984C","\uC624\uB958","fehler","probl\xE8me","problema","\u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430","\u043E\u0448\u0438\u0431\u043A\u0430","sorun","problem"]],["kubernetes",["\u30AF\u30D9\u30EB\u30CD\u30C6\u30B9","k8s","kube"]],["network",["\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF","\u7F51\u7EDC","\uB124\uD2B8\uC6CC\uD06C","\u0634\u0628\u0643\u0629","\u05E8\u05E9\u05EA","\u0634\u0628\u06A9\u0647","\u0928\u0947\u091F\u0935\u0930\u094D\u0915","netzwerk","r\xE9seau","red","rete","rede","\u0441\u0435\u0442\u044C","a\u011F"]],["timeout",["\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8","\u8D85\u65F6","\uD0C0\uC784\uC544\uC6C3","\u0645\u0647\u0644\u0629"]],["memory",["\u30E1\u30E2\u30EA","\u5185\u5B58","\uBA54\uBAA8\uB9AC","ram","\u0630\u0627\u0643\u0631\u0629","\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF","\u062D\u0627\u0641\u0638\u0647","\u092E\u0947\u092E\u094B\u0930\u0940","speicher","m\xE9moire","memoria","mem\xF3ria","\u043F\u0430\u043C\u044F\u0442\u044C","bellek","haf\u0131za"]],["config",["\u8A2D\u5B9A","\u914D\u7F6E","\uC124\uC815","configuration","settings","conf","\u0625\u0639\u062F\u0627\u062F\u0627\u062A","\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA","\u067E\u06CC\u06A9\u0631\u0628\u0646\u062F\u06CC","\u0915\u0949\u0928\u094D\u092B\u093C\u093F\u0917","konfiguration","einstellungen","configuraci\xF3n","configurazione","configura\xE7\xE3o","\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F","\u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438","yap\u0131land\u0131rma","ayarlar"]],["install",["\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB","\u5B89\u88C5","\uC124\uCE58","\u062A\u062B\u0628\u064A\u062A","\u05D4\u05EA\u05E7\u05E0\u05D4","\u0646\u0635\u0628","\u0907\u0902\u0938\u094D\u091F\u0949\u0932","installieren","installer","instalar","installare","\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C","\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430","y\xFCklemek","kurulum"]],["update",["\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8","\u66F4\u65B0","\uC5C5\uB370\uC774\uD2B8","upgrade","\u062A\u062D\u062F\u064A\u062B","\u05E2\u05D3\u05DB\u05D5\u05DF","\u0628\u0647\u200C\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06CC","\u0905\u092A\u0921\u0947\u091F","aktualisieren","aktualisierung","actualizar","aggiornare","atualizar","\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435","\u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C","g\xFCncelleme"]],["log",["\u30ED\u30B0","\u65E5\u5FD7","\uB85C\uADF8","logging","\u0633\u062C\u0644","\u05D9\u05D5\u05DE\u05DF","\u062B\u0628\u062A","\u0932\u0949\u0917","protokoll","protokolle","journal","registro","\u0436\u0443\u0440\u043D\u0430\u043B","\u043B\u043E\u0433","g\xFCnl\xFCk"]],["port",["\u30DD\u30FC\u30C8","\u7AEF\u53E3","\uD3EC\uD2B8","\u0645\u0646\u0641\u0630","\u05E4\u05D5\u05E8\u05D8"]],["file",["\u30D5\u30A1\u30A4\u30EB","\u6587\u4EF6","\uD30C\uC77C","\u0645\u0644\u0641","\u05E7\u05D5\u05D1\u05E5"]],["image",["\u30A4\u30E1\u30FC\u30B8","\u955C\u50CF","\uC774\uBBF8\uC9C0","\u0635\u0648\u0631\u0629","\u05EA\u05DE\u05D5\u05E0\u05D4","abbild","imagen","imagem"]],["volume",["\u30DC\u30EA\u30E5\u30FC\u30E0","\u5377","\uBCFC\uB968"]],["cluster",["\u30AF\u30E9\u30B9\u30BF\u30FC","\u96C6\u7FA4","\uD074\uB7EC\uC2A4\uD130"]],["node",["\u30CE\u30FC\u30C9","\u8282\u70B9","\uB178\uB4DC"]],["service",["\u30B5\u30FC\u30D3\u30B9","\u670D\u52A1","\uC11C\uBE44\uC2A4","svc","\u062E\u062F\u0645\u0629","\u05E9\u05D9\u05E8\u05D5\u05EA","dienst","servicio","servizio","servi\xE7o","\u0441\u0435\u0440\u0432\u0438\u0441","\u0441\u043B\u0443\u0436\u0431\u0430","servis","hizmet"]],["certificate",["\u8A3C\u660E\u66F8","\u8BC1\u4E66","\uC778\uC99D\uC11C","cert","ssl","tls","\u0634\u0647\u0627\u062F\u0629","\u05EA\u05E2\u05D5\u05D3\u05D4"]],["password",["\u30D1\u30B9\u30EF\u30FC\u30C9","\u5BC6\u7801","\uBE44\uBC00\uBC88\uD638","passwd","pwd","\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631","\u05E1\u05D9\u05E1\u05DE\u05D4"]],["token",["\u30C8\u30FC\u30AF\u30F3","\u4EE4\u724C","\uD1A0\uD070","jwt","secret","\u0631\u0645\u0632","\u05D0\u05E1\u05D9\u05DE\u05D5\u05DF"]],["health",["\u30D8\u30EB\u30B9","\u5065\u5EB7","\uD5EC\uC2A4","healthcheck","probe","\u0635\u062D\u0629"]],["migration",["\u30DE\u30A4\u30B0\u30EC\u30FC\u30B7\u30E7\u30F3","\u8FC1\u79FB","\uB9C8\uC774\uADF8\uB808\uC774\uC158","migrate","\u0647\u062C\u0631\u0629"]],["backup",["\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7","\u5907\u4EFD","\uBC31\uC5C5","\u0646\u0633\u062E \u0627\u062D\u062A\u064A\u0627\u0637\u064A","\u05D2\u05D9\u05D1\u05D5\u05D9","\u067E\u0634\u062A\u06CC\u0628\u0627\u0646\u200C\u06AF\u06CC\u0631\u06CC","\u092C\u0948\u0915\u0905\u092A","sicherung","sauvegarde","respaldo","c\xF3pia de seguran\xE7a","\u0440\u0435\u0437\u0435\u0440\u0432\u043D\u0430\u044F \u043A\u043E\u043F\u0438\u044F","\u0440\u0435\u0437\u0435\u0440\u0432","yedekleme"]],["monitor",["\u30E2\u30CB\u30BF\u30FC","\u76D1\u63A7","\uBAA8\uB2C8\uD130\uB9C1","monitoring","metrics","alert","\u0645\u0631\u0627\u0642\u0628\u0629","\u05E0\u05D9\u05D8\u05D5\u05E8","\u0646\u0638\u0627\u0631\u062A","\u0928\u093F\u0917\u0930\u093E\u0928\u0940","\xFCberwachung","surveiller","monitoreo","monitorare","monitorar","\u043C\u043E\u043D\u0438\u0442\u043E\u0440\u0438\u043D\u0433","\u043D\u0430\u0431\u043B\u044E\u0434\u0435\u043D\u0438\u0435","izleme"]],["performance",["\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9","\u6027\u80FD","\uC131\uB2A5","latency","throughput","\u0639\u0645\u0644\u06A9\u0631\u062F","\u092A\u094D\u0930\u0926\u0930\u094D\u0936\u0928","leistung","performances","rendimiento","prestazioni","desempenho","\u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C","\u0431\u044B\u0441\u0442\u0440\u043E\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435","performans"]],["connection",["\u63A5\u7D9A","\u8FDE\u63A5","\uC5F0\uACB0","conn","socket","\u0627\u062A\u0635\u0627\u0644","\u05D7\u05D9\u05D1\u05D5\u05E8","\u0627\u062A\u0635\u0627\u0644","\u0915\u0928\u0947\u0915\u094D\u0936\u0928","verbindung","connexion","conexi\xF3n","connessione","conex\xE3o"]],["queue",["\u30AD\u30E5\u30FC","\u961F\u5217","\uD050","\u0637\u0627\u0628\u0648\u0631","warteschlange","file d'attente","cola","coda","fila"]],["redis",["\u30EC\u30C7\u30A3\u30B9","\uB808\uB514\uC2A4"]],["nginx",["\u30A8\u30F3\u30B8\u30F3\u30A8\u30C3\u30AF\u30B9"]],["linux",["\u30EA\u30CA\u30C3\u30AF\u30B9","\u0644\u064A\u0646\u0643\u0633"]],["api",["\u30A8\u30FC\u30D4\u30FC\u30A2\u30A4","\u63A5\u53E3","endpoint","\u0648\u0627\u062C\u0647\u0629 \u0628\u0631\u0645\u062C\u064A\u0629","\u05DE\u05DE\u05E9\u05E7"]],["healthcheck",["\u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF","health","probe","\u0641\u062D\u0635 \u0627\u0644\u0635\u062D\u0629"]],["loadbalancer",["\u30ED\u30FC\u30C9\u30D0\u30E9\u30F3\u30B5\u30FC","\u8D1F\u8F7D\u5747\u8861","\uB85C\uB4DC\uBC38\uB7F0\uC11C","lb"]],["ssl",["tls","https","certificate","cert"]],["tls",["ssl","https","certificate","cert"]],["docker",["container","\u30B3\u30F3\u30C6\u30CA","\u5BB9\u5668","\uCEE8\uD14C\uC774\uB108","\u062F\u0648\u0643\u0631"]],["git",["version control","repo","repository","commit","push","pull"]],["ci",["pipeline","github actions","gitlab","jenkins","build"]],["cd",["deploy","deployment","release"]],["debug",["\u30C7\u30D0\u30C3\u30B0","\u8C03\u8BD5","\uB514\uBC84\uADF8","debugging","breakpoint","\u062A\u0635\u062D\u064A\u062D","\u05D0\u05D9\u05EA\u05D5\u05E8 \u05D1\u05D0\u05D2\u05D9\u05DD","\u0627\u0634\u06A9\u0627\u0644\u200C\u0632\u062F\u0627\u06CC\u06CC","\u0921\u0940\u092C\u0917","debuggen","d\xE9boguer","depurar","\u043E\u0442\u043B\u0430\u0434\u043A\u0430","\u0434\u0435\u0431\u0430\u0433","hata ay\u0131klama"]],["crash",["\u30AF\u30E9\u30C3\u30B7\u30E5","\u5D29\u6E83","\uD06C\uB798\uC2DC","panic","segfault","\u0627\u0646\u0647\u064A\u0627\u0631","\u05E7\u05E8\u05D9\u05E1\u05D4","\u062E\u0631\u0627\u0628\u06CC","\u0915\u094D\u0930\u0948\u0936","absturz","panne","plantage","ca\xEDda","falha","\u0441\u0431\u043E\u0439","\u043A\u0440\u044D\u0448","\xE7\xF6kme","\xE7\xF6k\xFC\u015F"]],["restart",["\u518D\u8D77\u52D5","\u91CD\u542F","\uC7AC\uC2DC\uC791","reboot","\u0625\u0639\u0627\u062F\u0629 \u062A\u0634\u063A\u064A\u0644","\u05D4\u05E4\u05E2\u05DC\u05D4 \u05DE\u05D7\u05D3\u05E9","\u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u0645\u062C\u062F\u062F","\u092A\u0941\u0646\u0930\u093E\u0930\u0902\u092D","neustart","red\xE9marrer","reiniciar","riavviare"]],["permission",["\u6A29\u9650","\u6743\u9650","\uAD8C\uD55C","access","acl","chmod","\u0635\u0644\u0627\u062D\u064A\u0629","\u05D4\u05E8\u05E9\u05D0\u05D4","\u0645\u062C\u0648\u0632","\u0905\u0928\u0941\u092E\u0924\u093F","berechtigung","berechtigungen","permiso","permesso","permiss\xE3o","\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435","\u0434\u043E\u0441\u0442\u0443\u043F","izin","yetki"]],["\u30C7\u30D7\u30ED\u30A4",["deploy","deployment"]],["\u30B3\u30F3\u30C6\u30CA",["container","docker"]],["\u30B5\u30FC\u30D0\u30FC",["server"]],["\u30B5\u30FC\u30D0",["server"]],["\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9",["database","db"]],["\u30AD\u30E3\u30C3\u30B7\u30E5",["cache"]],["\u30A8\u30E9\u30FC",["error","err"]],["\u30D0\u30B0",["bug","issue"]],["\u30D3\u30EB\u30C9",["build"]],["\u30C6\u30B9\u30C8",["test"]],["\u8A8D\u8A3C",["auth","authentication"]],["\u8A2D\u5B9A",["config","configuration"]],["\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",["install"]],["\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8",["update","upgrade"]],["\u30ED\u30B0",["log","logs"]],["\u30DD\u30FC\u30C8",["port"]],["\u30D5\u30A1\u30A4\u30EB",["file"]],["\u30A4\u30E1\u30FC\u30B8",["image"]],["\u30AF\u30E9\u30B9\u30BF\u30FC",["cluster"]],["\u30CE\u30FC\u30C9",["node"]],["\u30B5\u30FC\u30D3\u30B9",["service"]],["\u30D1\u30B9\u30EF\u30FC\u30C9",["password"]],["\u30C8\u30FC\u30AF\u30F3",["token"]],["\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7",["backup"]],["\u30E2\u30CB\u30BF\u30FC",["monitor","monitoring"]],["\u63A5\u7D9A",["connection"]],["\u30AD\u30E5\u30FC",["queue"]],["\u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF",["healthcheck","health check","health"]],["\u30ED\u30FC\u30C9\u30D0\u30E9\u30F3\u30B5\u30FC",["loadbalancer","load balancer"]],["\u30C7\u30D0\u30C3\u30B0",["debug"]],["\u30AF\u30E9\u30C3\u30B7\u30E5",["crash","panic"]],["\u518D\u8D77\u52D5",["restart","reboot"]],["\u6A29\u9650",["permission","access"]],["\u90E8\u7F72",["deploy","deployment"]],["\u5BB9\u5668",["container","docker"]],["\u670D\u52A1\u5668",["server"]],["\u6570\u636E\u5E93",["database"]],["\u7F13\u5B58",["cache"]],["\u9519\u8BEF",["error"]],["\u4FEE\u590D",["fix","bugfix"]],["\u6784\u5EFA",["build"]],["\u6D4B\u8BD5",["test"]],["\u8BA4\u8BC1",["auth"]],["\u914D\u7F6E",["config"]],["\u5B89\u88C5",["install"]],["\u66F4\u65B0",["update"]],["\u65E5\u5FD7",["log"]],["\u7AEF\u53E3",["port"]],["\u955C\u50CF",["image"]],["\u96C6\u7FA4",["cluster"]],["\u8282\u70B9",["node"]],["\u670D\u52A1",["service"]],["\u5BC6\u7801",["password"]],["\u4EE4\u724C",["token"]],["\u5907\u4EFD",["backup"]],["\u76D1\u63A7",["monitor"]],["\u8FDE\u63A5",["connection"]],["\u961F\u5217",["queue"]],["\u6027\u80FD",["performance"]],["\u5185\u5B58",["memory"]],["\u8C03\u8BD5",["debug"]],["\u5D29\u6E83",["crash"]],["\u91CD\u542F",["restart"]],["\u6743\u9650",["permission"]],["\uBC30\uD3EC",["deploy","deployment"]],["\uCEE8\uD14C\uC774\uB108",["container"]],["\uC11C\uBC84",["server"]],["\uB370\uC774\uD130\uBCA0\uC774\uC2A4",["database"]],["\uCE90\uC2DC",["cache"]],["\uC624\uB958",["error"]],["\uC218\uC815",["fix"]],["\uBE4C\uB4DC",["build"]],["\uD14C\uC2A4\uD2B8",["test"]],["\uC778\uC99D",["auth"]],["\uC124\uC815",["config"]],["\uC124\uCE58",["install"]],["\uC5C5\uB370\uC774\uD2B8",["update"]],["\uB85C\uADF8",["log"]],["\uD3EC\uD2B8",["port"]],["\uC774\uBBF8\uC9C0",["image"]],["\uD074\uB7EC\uC2A4\uD130",["cluster"]],["\uB178\uB4DC",["node"]],["\uC11C\uBE44\uC2A4",["service"]],["\uD1A0\uD070",["token"]],["\uBC31\uC5C5",["backup"]],["\uBAA8\uB2C8\uD130\uB9C1",["monitor"]],["\uC5F0\uACB0",["connection"]],["\uD050",["queue"]],["\uC131\uB2A5",["performance"]],["\uBA54\uBAA8\uB9AC",["memory"]],["\uB514\uBC84\uADF8",["debug"]],["\uD06C\uB798\uC2DC",["crash"]],["\uC7AC\uC2DC\uC791",["restart"]],["\uAD8C\uD55C",["permission"]],["\u062E\u0637\u0623",["error"]],["\u0625\u0635\u0644\u0627\u062D",["fix"]],["\u0628\u0646\u0627\u0621",["build"]],["\u0627\u062E\u062A\u0628\u0627\u0631",["test"]],["\u0645\u0635\u0627\u062F\u0642\u0629",["auth","authentication"]],["\u0625\u0639\u062F\u0627\u062F\u0627\u062A",["config","configuration"]],["\u062A\u062B\u0628\u064A\u062A",["install"]],["\u062A\u062D\u062F\u064A\u062B",["update","upgrade"]],["\u0633\u062C\u0644",["log"]],["\u0635\u0648\u0631\u0629",["image"]],["\u062E\u062F\u0645\u0629",["service"]],["\u0646\u0633\u062E \u0627\u062D\u062A\u064A\u0627\u0637\u064A",["backup"]],["\u0645\u0631\u0627\u0642\u0628\u0629",["monitor","monitoring"]],["\u0627\u062A\u0635\u0627\u0644",["connection"]],["\u0630\u0627\u0643\u0631\u0629",["memory"]],["\u062A\u0635\u062D\u064A\u062D",["debug","debugging"]],["\u0634\u0628\u0643\u0629",["network"]],["\u0646\u0634\u0631",["deploy","deployment"]],["\u0627\u0646\u0647\u064A\u0627\u0631",["crash","panic"]],["\u0637\u0627\u0628\u0648\u0631",["queue"]],["\u0631\u0645\u0632",["token","secret"]],["\u0643\u0627\u0634",["cache"]],["\u0645\u0646\u0641\u0630",["port"]],["\u0633\u064A\u0631\u0641\u0631",["server"]],["\u0642\u0627\u0639\u062F\u0629 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A",["database","db"]],["\u0625\u0639\u0627\u062F\u0629 \u062A\u0634\u063A\u064A\u0644",["restart","reboot"]],["\u0635\u0644\u0627\u062D\u064A\u0629",["permission","access"]],["\u062A\u0637\u0628\u064A\u0642",["application","app"]],["\u0645\u0641\u062A\u0627\u062D",["key","token","secret"]],["\u0648\u0627\u062C\u0647\u0629 \u0628\u0631\u0645\u062C\u064A\u0629",["api","interface"]],["\u0641\u062D\u0635 \u0627\u0644\u0635\u062D\u0629",["healthcheck","health"]],["\u062D\u0627\u0648\u064A\u0629",["container","docker"]],["\u0639\u0642\u062F\u0629",["node"]],["\u0633\u0631\u0639\u0629",["performance","speed"]],["\u0642\u0631\u0635",["disk","storage"]],["\u062E\u0627\u062F\u0645",["server"]],["\u0628\u0631\u0646\u0627\u0645\u062C",["application","software","app"]],["\u0645\u0634\u0643\u0644\u0629",["error","issue","bug","problem","failure"]],["\u0628\u064A\u0626\u0629",["environment","env"]],["\u0645\u062A\u063A\u064A\u0631\u0627\u062A",["variables","env","environment"]],["\u0625\u0646\u062A\u0627\u062C",["production","prod"]],["\u0633\u0631\u064A",["secret","key","token"]],["\u0645\u0641\u062A\u0627\u062D \u0633\u0631\u064A",["secret","key"]],["\u05E9\u05D2\u05D9\u05D0\u05D4",["error"]],["\u05EA\u05D9\u05E7\u05D5\u05DF",["fix"]],["\u05D1\u05E0\u05D9\u05D9\u05D4",["build"]],["\u05D1\u05D3\u05D9\u05E7\u05D4",["test"]],["\u05D0\u05D9\u05DE\u05D5\u05EA",["auth","authentication"]],["\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA",["config","configuration"]],["\u05D4\u05EA\u05E7\u05E0\u05D4",["install"]],["\u05E2\u05D3\u05DB\u05D5\u05DF",["update","upgrade"]],["\u05D9\u05D5\u05DE\u05DF",["log"]],["\u05E9\u05E8\u05EA",["server"]],["\u05E9\u05D9\u05E8\u05D5\u05EA",["service"]],["\u05D2\u05D9\u05D1\u05D5\u05D9",["backup"]],["\u05E0\u05D9\u05D8\u05D5\u05E8",["monitor","monitoring"]],["\u05D7\u05D9\u05D1\u05D5\u05E8",["connection"]],["\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF",["memory"]],["\u05E8\u05E9\u05EA",["network"]],["\u05EA\u05DE\u05D5\u05E0\u05D4",["image"]],["\u05E1\u05D9\u05E1\u05DE\u05D4",["password"]],["\u05D4\u05E8\u05E9\u05D0\u05D4",["permission","access"]],["\u05E7\u05E8\u05D9\u05E1\u05D4",["crash","panic"]],["\u05EA\u05D5\u05E8",["queue"]],["\u05DE\u05D8\u05DE\u05D5\u05DF",["cache"]],["\u05D0\u05E1\u05D9\u05DE\u05D5\u05DF",["token","secret"]],["\u05E4\u05D5\u05E8\u05D8",["port"]],["\u05D0\u05D9\u05EA\u05D5\u05E8 \u05D1\u05D0\u05D2\u05D9\u05DD",["debug","debugging"]],["\u05D4\u05E4\u05E2\u05DC\u05D4 \u05DE\u05D7\u05D3\u05E9",["restart","reboot"]],["\u05DE\u05D9\u05DB\u05DC",["container","docker"]],["\u05D9\u05D9\u05E9\u05D5\u05DD",["application","app"]],["\u05DE\u05E4\u05EA\u05D7",["key","token","secret"]],["\u05D1\u05D3\u05D9\u05E7\u05EA \u05EA\u05E7\u05D9\u05E0\u05D5\u05EA",["healthcheck","health"]],["\u05DE\u05DE\u05E9\u05E7 \u05EA\u05DB\u05E0\u05D5\u05EA",["api","interface"]],["\u05D1\u05D9\u05E6\u05D5\u05E2\u05D9\u05DD",["performance"]],["\u05D0\u05D7\u05E1\u05D5\u05DF",["storage","disk"]],["\u05E4\u05E8\u05D9\u05E1\u05D4",["deploy","deployment"]],["\u05D1\u05E2\u05D9\u05D4",["error","issue","bug","problem"]],["\u05E1\u05D1\u05D9\u05D1\u05D4",["environment","env"]],["\u05D9\u05D9\u05E6\u05D5\u05E8",["production","prod"]],["\u05E1\u05D5\u05D3\u05D9",["secret","key","token"]],["\u05DE\u05E4\u05EA\u05D7 \u05E1\u05D5\u05D3\u05D9",["secret","key"]],["\u0627\u0633\u062A\u0642\u0631\u0627\u0631",["deploy","deployment"]],["\u062E\u0637\u0627",["error","err"]],["\u0627\u0634\u06A9\u0627\u0644",["bug","issue","error"]],["\u0631\u0641\u0639 \u0627\u0634\u06A9\u0627\u0644",["fix","debug","debugging"]],["\u0633\u0627\u062E\u062A",["build"]],["\u0622\u0632\u0645\u0627\u06CC\u0634",["test"]],["\u0627\u062D\u0631\u0627\u0632 \u0647\u0648\u06CC\u062A",["auth","authentication"]],["\u067E\u06CC\u06A9\u0631\u0628\u0646\u062F\u06CC",["config","configuration"]],["\u0646\u0635\u0628",["install"]],["\u0628\u0647\u200C\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06CC",["update","upgrade"]],["\u062B\u0628\u062A",["log"]],["\u0633\u0631\u0648\u0631",["server"]],["\u067E\u0627\u06CC\u06AF\u0627\u0647 \u062F\u0627\u062F\u0647",["database","db"]],["\u0634\u0628\u06A9\u0647",["network"]],["\u062D\u0627\u0641\u0638\u0647",["memory","ram"]],["\u06A9\u0634",["cache"]],["\u0627\u0634\u06A9\u0627\u0644\u200C\u0632\u062F\u0627\u06CC\u06CC",["debug","debugging"]],["\u062E\u0631\u0627\u0628\u06CC",["crash","failure","error"]],["\u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u0645\u062C\u062F\u062F",["restart","reboot"]],["\u0645\u062C\u0648\u0632",["permission","access"]],["\u067E\u0634\u062A\u06CC\u0628\u0627\u0646\u200C\u06AF\u06CC\u0631\u06CC",["backup"]],["\u0639\u0645\u0644\u06A9\u0631\u062F",["performance"]],["\u0645\u0634\u06A9\u0644",["problem","issue","error"]],["\u0633\u0631\u0648\u06CC\u0633",["service"]],["\u06A9\u0644\u06CC\u062F",["key","token","secret"]],["\u0645\u062D\u06CC\u0637",["environment","env"]],["\u062A\u0648\u0644\u06CC\u062F",["production","prod"]],["\u0631\u0645\u0632",["secret","key","token"]],["\u0627\u062A\u0635\u0627\u0644",["connection","conn"]],["\u0924\u0948\u0928\u093E\u0924\u0940",["deploy","deployment"]],["\u0924\u0948\u0928\u093E",["deploy","deployment"]],["\u0924\u094D\u0930\u0941\u091F\u093F",["error","err"]],["\u0917\u0932\u0924\u0940",["error","bug","issue"]],["\u0938\u0941\u0927\u093E\u0930",["fix","bugfix"]],["\u0928\u093F\u0930\u094D\u092E\u093E\u0923",["build"]],["\u092A\u0930\u0940\u0915\u094D\u0937\u0923",["test"]],["\u092A\u094D\u0930\u092E\u093E\u0923\u0940\u0915\u0930\u0923",["auth","authentication"]],["\u0935\u093F\u0928\u094D\u092F\u093E\u0938",["config","configuration"]],["\u0915\u0949\u0928\u094D\u092B\u093C\u093F\u0917\u0930\u0947\u0936\u0928",["config","configuration"]],["\u0907\u0902\u0938\u094D\u091F\u0949\u0932",["install"]],["\u0905\u092A\u0921\u0947\u091F",["update","upgrade"]],["\u0932\u0949\u0917",["log"]],["\u0938\u0930\u094D\u0935\u0930",["server"]],["\u0921\u0947\u091F\u093E\u092C\u0947\u0938",["database","db"]],["\u0928\u0947\u091F\u0935\u0930\u094D\u0915",["network"]],["\u092E\u0947\u092E\u094B\u0930\u0940",["memory","ram"]],["\u0915\u0948\u0936",["cache"]],["\u0921\u0940\u092C\u0917",["debug","debugging"]],["\u0915\u094D\u0930\u0948\u0936",["crash","panic"]],["\u092A\u0941\u0928\u0930\u093E\u0930\u0902\u092D",["restart","reboot"]],["\u0905\u0928\u0941\u092E\u0924\u093F",["permission","access"]],["\u092C\u0948\u0915\u0905\u092A",["backup"]],["\u092A\u094D\u0930\u0926\u0930\u094D\u0936\u0928",["performance"]],["\u0938\u092E\u0938\u094D\u092F\u093E",["problem","issue","error"]],["\u0938\u0947\u0935\u093E",["service"]],["\u0915\u0928\u0947\u0915\u094D\u0936\u0928",["connection","conn"]],["\u092A\u093E\u0938\u0935\u0930\u094D\u0921",["password"]],["\u091F\u094B\u0915\u0928",["token","secret"]],["\u0935\u093E\u0924\u093E\u0935\u0930\u0923",["environment","env"]],["\u0909\u0924\u094D\u092A\u093E\u0926\u0928",["production","prod"]],["fehler",["error","err"]],["absturz",["crash","panic"]],["bug",["bug","issue"]],["beheben",["fix","bugfix"]],["behoben",["fix","fixed"]],["l\xF6sung",["solution","fix"]],["bauen",["build"]],["testen",["test"]],["authentifizierung",["auth","authentication"]],["konfiguration",["config","configuration"]],["einstellungen",["config","settings"]],["installieren",["install"]],["installiert",["install","installed"]],["aktualisieren",["update","upgrade"]],["aktualisierung",["update","upgrade"]],["protokoll",["log"]],["protokolle",["log","logs"]],["abbild",["image"]],["knoten",["node"]],["dienst",["service"]],["sicherung",["backup"]],["\xFCberwachung",["monitor","monitoring"]],["verbindung",["connection","conn"]],["warteschlange",["queue"]],["leistung",["performance"]],["speicher",["memory","storage"]],["debuggen",["debug","debugging"]],["neustart",["restart","reboot"]],["berechtigung",["permission","access"]],["berechtigungen",["permission","access","acl"]],["netzwerk",["network"]],["datenbank",["database","db"]],["bereitstellen",["deploy","deployment"]],["bereitstellung",["deploy","deployment"]],["kaputt",["broken","error","crash"]],["funktioniert",["works","working"]],["geht nicht",["not working","broken","error"]],["schl\xFCssel",["key","token","secret"]],["zertifikat",["certificate","cert","ssl","tls"]],["umgebung",["environment","env"]],["variablen",["variables","env","environment"]],["aufgabe",["task","job"]],["wartung",["maintenance"]],["speicherleck",["memory leak","memory"]],["schnittstelle",["interface","api"]],["erreur",["error","err"]],["r\xE9parer",["fix"]],["correction",["fix","bugfix"]],["construire",["build"]],["tester",["test"]],["authentification",["auth","authentication"]],["configuration",["config","configuration"]],["installer",["install"]],["installation",["install"]],["mettre",["update","upgrade"]],["journal",["log","logs"]],["n\u0153ud",["node"]],["sauvegarde",["backup"]],["surveiller",["monitor","monitoring"]],["connexion",["connection"]],["m\xE9moire",["memory"]],["d\xE9boguer",["debug"]],["red\xE9marrer",["restart","reboot"]],["r\xE9seau",["network"]],["base de donn\xE9es",["database","db"]],["d\xE9ployer",["deploy"]],["d\xE9ploiement",["deploy","deployment"]],["cl\xE9",["key","token"]],["certificat",["certificate","cert","ssl"]],["environnement",["environment","env"]],["panne",["crash","outage","failure"]],["plantage",["crash","panic"]],["interface",["interface","api"]],["performances",["performance"]],["stockage",["storage","disk"]],["file attente",["queue"]],["arreglar",["fix"]],["correcci\xF3n",["fix","bugfix"]],["construir",["build"]],["probar",["test"]],["autenticaci\xF3n",["auth","authentication"]],["configuraci\xF3n",["config","configuration"]],["instalar",["install"]],["actualizar",["update","upgrade"]],["actualizaci\xF3n",["update","upgrade"]],["registro",["log","registry"]],["nodo",["node"]],["servicio",["service"]],["contrase\xF1a",["password"]],["copia de seguridad",["backup"]],["respaldo",["backup"]],["monitorear",["monitor"]],["monitoreo",["monitoring"]],["conexi\xF3n",["connection"]],["rendimiento",["performance"]],["memoria",["memory"]],["depurar",["debug"]],["fallo",["crash","failure","error"]],["ca\xEDda",["crash","outage"]],["reiniciar",["restart","reboot"]],["permiso",["permission"]],["permisos",["permission","access"]],["red",["network"]],["base de datos",["database","db"]],["desplegar",["deploy"]],["despliegue",["deploy","deployment"]],["clave",["key","token","secret"]],["certificado",["certificate","cert","ssl"]],["entorno",["environment","env"]],["cola",["queue"]],["interfaz",["interface","api"]],["imagen",["image"]],["errore",["error","err"]],["correggere",["fix"]],["costruire",["build"]],["testare",["test"]],["autenticazione",["auth","authentication"]],["configurazione",["config","configuration"]],["installare",["install"]],["aggiornare",["update","upgrade"]],["aggiornamento",["update","upgrade"]],["registro",["log"]],["nodo",["node"]],["servizio",["service"]],["password",["password"]],["backup",["backup"]],["monitorare",["monitor"]],["connessione",["connection"]],["prestazioni",["performance"]],["memoria",["memory"]],["debug",["debug"]],["arresto anomalo",["crash"]],["riavviare",["restart"]],["permesso",["permission"]],["rete",["network"]],["database",["database","db"]],["distribuire",["deploy"]],["distribuzione",["deploy","deployment"]],["chiave",["key","token","secret"]],["certificato",["certificate","cert"]],["ambiente",["environment","env"]],["coda",["queue"]],["immagine",["image"]],["erro",["error","err"]],["corrigir",["fix"]],["construir",["build"]],["testar",["test"]],["autentica\xE7\xE3o",["auth","authentication"]],["configura\xE7\xE3o",["config","configuration"]],["instalar",["install"]],["atualizar",["update","upgrade"]],["atualiza\xE7\xE3o",["update","upgrade"]],["registro",["log"]],["n\xF3",["node"]],["servi\xE7o",["service"]],["senha",["password"]],["c\xF3pia de seguran\xE7a",["backup"]],["monitorar",["monitor"]],["conex\xE3o",["connection"]],["desempenho",["performance"]],["mem\xF3ria",["memory"]],["depurar",["debug"]],["falha",["crash","failure","error"]],["reiniciar",["restart"]],["permiss\xE3o",["permission"]],["rede",["network"]],["banco de dados",["database","db"]],["implantar",["deploy"]],["implanta\xE7\xE3o",["deploy","deployment"]],["chave",["key","token","secret"]],["certificado",["certificate","cert"]],["ambiente",["environment","env"]],["fila",["queue"]],["imagem",["image"]],["\u043E\u0448\u0438\u0431\u043A\u0430",["error","err"]],["\u043E\u0448\u0438\u0431\u043A\u0438",["error","err"]],["\u0441\u0431\u043E\u0439",["crash","failure","error"]],["\u043A\u0440\u044D\u0448",["crash","panic"]],["\u0431\u0430\u0433",["bug","issue"]],["\u0438\u0441\u043F\u0440\u0430\u0432\u0438\u0442\u044C",["fix","bugfix"]],["\u0438\u0441\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435",["fix","patch"]],["\u0441\u0431\u043E\u0440\u043A\u0430",["build"]],["\u0441\u043E\u0431\u0440\u0430\u0442\u044C",["build"]],["\u0442\u0435\u0441\u0442",["test"]],["\u0442\u0435\u0441\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435",["test","testing"]],["\u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F",["auth","authentication"]],["\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F",["auth","authorization"]],["\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F",["config","configuration"]],["\u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438",["config","settings"]],["\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C",["install"]],["\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430",["install"]],["\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435",["update","upgrade"]],["\u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C",["update","upgrade"]],["\u0436\u0443\u0440\u043D\u0430\u043B",["log"]],["\u043B\u043E\u0433",["log","logs"]],["\u0441\u0435\u0440\u0432\u0435\u0440",["server"]],["\u0431\u0430\u0437\u0430 \u0434\u0430\u043D\u043D\u044B\u0445",["database","db"]],["\u0441\u0435\u0442\u044C",["network"]],["\u043F\u0430\u043C\u044F\u0442\u044C",["memory","ram"]],["\u043A\u044D\u0448",["cache"]],["\u043E\u0442\u043B\u0430\u0434\u043A\u0430",["debug","debugging"]],["\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A",["restart","reboot"]],["\u043F\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0430",["restart","reboot"]],["\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435",["permission","access"]],["\u0434\u043E\u0441\u0442\u0443\u043F",["permission","access"]],["\u0440\u0435\u0437\u0435\u0440\u0432",["backup"]],["\u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C",["performance"]],["\u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430",["problem","issue","error"]],["\u0441\u0435\u0440\u0432\u0438\u0441",["service"]],["\u0441\u043B\u0443\u0436\u0431\u0430",["service"]],["\u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435",["connection","conn"]],["\u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435",["connection","conn"]],["\u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435",["deploy","deployment"]],["\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435",["deploy","deployment"]],["\u0440\u0430\u0437\u0432\u0451\u0440\u0442",["deploy","deployment"]],["\u0440\u0430\u0437\u0432\u0435\u0440\u0442",["deploy","deployment"]],["\u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440",["container","docker"]],["\u043E\u0431\u0440\u0430\u0437",["image"]],["\u043A\u043B\u0430\u0441\u0442\u0435\u0440",["cluster"]],["\u0443\u0437\u0435\u043B",["node"]],["\u0441\u0435\u043A\u0440\u0435\u0442",["secret","key","token"]],["\u043A\u043B\u044E\u0447",["key","token","secret"]],["\u043F\u0430\u0440\u043E\u043B\u044C",["password"]],["\u0442\u043E\u043A\u0435\u043D",["token","secret"]],["\u043C\u043E\u043D\u0438\u0442\u043E\u0440\u0438\u043D\u0433",["monitor","monitoring"]],["\u043D\u0430\u0431\u043B\u044E\u0434\u0435\u043D\u0438\u0435",["monitor","monitoring"]],["\u043C\u0438\u0433\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C",["migrate","migration"]],["\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u044F",["migrate","migration"]],["hata",["error","err"]],["hatal\u0131",["error","err"]],["\xE7\xF6kme",["crash","panic"]],["\xE7\xF6k\xFC\u015F",["crash","failure"]],["d\xFCzeltmek",["fix","bugfix"]],["d\xFCzeltme",["fix","patch"]],["derleme",["build"]],["derlemek",["build"]],["test",["test"]],["testlemek",["test","testing"]],["kimlik do\u011Frulama",["auth","authentication"]],["yetkilendirme",["auth","authorization"]],["yap\u0131land\u0131rma",["config","configuration"]],["ayarlar",["config","settings"]],["y\xFCklemek",["install"]],["kurulum",["install"]],["g\xFCncelleme",["update","upgrade"]],["g\xFCnl\xFCk",["log"]],["sunucu",["server"]],["veritaban\u0131",["database","db"]],["a\u011F",["network"]],["bellek",["memory","ram"]],["\xF6nbellek",["cache"]],["hata ay\u0131klama",["debug","debugging"]],["yeniden ba\u015Flatma",["restart","reboot"]],["izin",["permission","access"]],["yetki",["permission","access","acl"]],["yedekleme",["backup"]],["performans",["performance"]],["sorun",["problem","issue","error"]],["servis",["service"]],["hizmet",["service"]],["ba\u011Flant\u0131",["connection","conn"]],["da\u011F\u0131t\u0131m",["deploy","deployment"]],["da\u011F\u0131tmak",["deploy"]],["konteyner",["container","docker"]],["k\xFCme",["cluster"]],["d\xFC\u011F\xFCm",["node"]],["gizli",["secret","key"]],["anahtar",["key","token","secret"]],["\u015Fifre",["password"]],["izleme",["monitor","monitoring"]],["g\xF6\xE7",["migrate","migration"]],["tri\u1EC3n khai",["deploy","deployment"]],["tri\u1EC3n",["deploy","deployment"]],["l\u1ED7i",["error","err"]],["s\u1EEDa l\u1ED7i",["fix","bugfix","debug"]],["x\xE2y d\u1EF1ng",["build"]],["ki\u1EC3m tra",["test"]],["x\xE1c th\u1EF1c",["auth","authentication"]],["c\u1EA5u h\xECnh",["config","configuration"]],["c\xE0i \u0111\u1EB7t",["install"]],["c\u1EADp nh\u1EADt",["update","upgrade"]],["nh\u1EADt k\xFD",["log"]],["m\xE1y ch\u1EE7",["server"]],["c\u01A1 s\u1EDF d\u1EEF li\u1EC7u",["database","db"]],["m\u1EA1ng",["network"]],["b\u1ED9 nh\u1EDB",["memory","ram"]],["b\u1ED9 \u0111\u1EC7m",["cache"]],["g\u1EE1 l\u1ED7i",["debug","debugging"]],["s\u1EF1 c\u1ED1",["crash","failure","error"]],["kh\u1EDFi \u0111\u1ED9ng l\u1EA1i",["restart","reboot"]],["quy\u1EC1n",["permission","access"]],["sao l\u01B0u",["backup"]],["hi\u1EC7u su\u1EA5t",["performance"]],["v\u1EA5n \u0111\u1EC1",["problem","issue","error"]],["d\u1ECBch v\u1EE5",["service"]],["k\u1EBFt n\u1ED1i",["connection","conn"]],["v\xF9ng ch\u1EE9a",["container","docker"]],["n\xFAt",["node"]],["kh\xF3a",["key","token","secret"]],["m\u1EADt kh\u1EA9u",["password"]],["gi\xE1m s\xE1t",["monitor","monitoring"]],["di chuy\u1EC3n",["migrate","migration"]]]);for(const[t,e]of j){const o=R(t);o!==t&&!j.has(o)&&j.set(o,e)}for(const[t,e]of be){const o=j.get(t);j.set(t,o?[...new Set([...o,...e])]:[...e])}const ke=new Set([...j.keys()].filter(t=>t.length>=4&&/^[a-z]+$/.test(R(t))).map(R));function D(t){const e=j.get(t);if(e)return e;const o=R(t);return o!==t?j.get(o)??[]:[]}function q(t,e){const o=e?.crossLingualExpand??!0,a=[],m=ge(t).toLowerCase();for(const[c]of m.matchAll(he))if(T.test(c)){for(let n=0;n<c.length-1;n++){const r=c[n]+c[n+1];!h.has(c[n])&&!h.has(r)&&a.push(r)}if(c.length>=1){const n=c[c.length-1];h.has(n)||a.push(n)}const g=D(c);for(const n of g)T.test(n)||n.split(/\s+/).filter(r=>r.length>1&&!h.has(r)).forEach(r=>a.push(r));const i=c.replace(/[^\u30a0-\u30ff]/g,"");if(i.length>=2){const n=Z(i);n.length>=2&&n.length<=40&&!h.has(n)&&a.push(n)}}else if(M.test(c)){const g=c.trim().split(/\s+/);let i;F.test(c)?i=G:C.test(c)?i=K:i=N;for(const n of g){if(n.length<=1||h.has(n))continue;const r=i(n);r.length>1&&!h.has(r)&&a.push(r)}}else if(O.test(c)){const g=c.trim().split(/[\s\u200c\u200d]+/);for(const i of g){const n=i.replace(/[^\u0900-\u097f0-9]/g,"");if(n.length<=1||h.has(n))continue;const r=Y(n);r.length>1&&!h.has(r)&&a.push(r)}}else if(U.test(c)){const g=c.trim().split(/[\s\u200c\u200d]+/);for(const i of g){const n=i.replace(/[^\u0980-\u09ff0-9]/g,"");if(n.length<=1||h.has(n))continue;const r=J(n);r.length>1&&!h.has(r)&&a.push(r)}}else if(P.test(c)){const g=c.trim().split(/\s+/);for(const i of g){const n=i.replace(/[^\u0400-\u04ff]/g,"");if(n.length<=1||h.has(n))continue;const r=V(n);r.length>1&&!h.has(r)&&a.push(r)}}else{const g=c.replace(/[^a-záàâãäåæçéèêëíìîïñóòôõöúùûüýÿßœğşıİąćęłńśźżčšžěůřőűșț\u1ea0-\u1ef90-9:\-./]/g," ").split(/\s+/).filter(i=>i.length>1&&!h.has(i));for(const i of g){if($.test(i)){const f=Q(i);f!==i&&f.length>1&&!h.has(f)&&a.push(f)}a.push(i);const n=R(i);n!==i&&!h.has(n)&&a.push(n);const r=fe(i);if(r!==i&&r!==n&&r.length>3&&!h.has(r)){a.push(r);const f=me(r);f&&f.length>3&&!h.has(f)&&a.push(f)}if(n.length>=10)for(const f of pe(n,ke))h.has(f)||a.push(f)}}if(!o)return a;const u=[],z=new Set(a);for(const c of a){const g=D(c);for(const i of g)if(!z.has(i))if(z.add(i),T.test(i)){for(let n=0;n<i.length-1;n++){const r=i[n]+i[n+1];!h.has(i[n])&&!h.has(r)&&u.push(r)}if(i.length>=1){const n=i[i.length-1];h.has(n)||u.push(n)}}else if(M.test(i)){const r=(F.test(i)?G:C.test(i)?K:N)(i);r.length>1&&!h.has(r)&&u.push(r)}else if(O.test(i)){const n=Y(i);n.length>1&&!h.has(n)&&u.push(n)}else if(U.test(i)){const n=J(i);n.length>1&&!h.has(n)&&u.push(n)}else if(P.test(i)){const n=i.replace(/[^\u0400-\u04ff]/g,""),r=V(n);r.length>1&&!h.has(r)&&u.push(r)}else{const n=i.split(/\s+/).filter(r=>!(r.length<=1||h.has(r)));for(const r of n)if(u.push(r),$.test(r)){const f=Q(r);f!==r&&f.length>1&&!h.has(f)&&u.push(f)}}}return a.push(...u),a}function X(t){const e=t.split(/\d+[.)]\s*/g).filter(u=>u.trim().length>2);if(e.length>=2)return e.map(u=>u.trim());const o=t.split(/[;\n]+/).filter(u=>u.trim().length>2);if(o.length>=2)return o.map(u=>u.trim());const a=t.split(/\b(?:and also|also noch|außerdem|plus|additionally|furthermore|de plus|además|inoltre|além disso|а также|и также|кроме того|плюс|ayrıca|bunun yanı sıra|همچنین|وأيضاً|وكذلك|وهمچنین|और भी|इसके अलावा)\b/i).filter(u=>u.trim().length>2);if(a.length>=2)return a.map(u=>u.trim());const m=t.split(/,\s*/).filter(u=>u.trim().length>2);return m.length>=3?m.map(u=>u.trim()):[t]}const ee=1.2,te=.75,ye=.25,ne=.05,we=.5,ve=64,We=7,L=[],ze=500;let re=0;function ie(t){re++,L.length>=ze&&L.shift(),L.push({query:t,ts:Date.now()})}let H=new Set;function oe(t,e){if(t===e)return 0;if(t.length===0)return e.length;if(e.length===0)return t.length;if(Math.abs(t.length-e.length)>2)return 3;const o=Array.from({length:e.length+1},(a,m)=>m);for(let a=1;a<=t.length;a++){let m=a-1;o[0]=a;for(let u=1;u<=e.length;u++){const z=t[a-1]===e[u-1]?0:1,c=Math.min(o[u]+1,o[u-1]+1,m+z);m=o[u],o[u]=c}}return o[e.length]}function se(t){const e=t.match(/"(?:ts|created|created_at|timestamp)"\s*:\s*"([^"]+)"/);if(e){const o=Date.parse(e[1]);if(!isNaN(o))return o}}function ae(t){if(!t)return 1;const e=(Date.now()-t)/(1e3*60*60*24),o=e<=0?1:Math.pow(.5,e/We);return 1-ne+2*ne*o}const xe=6e4,I=new WeakMap;let B=0;function Re(){ue=Date.now(),B=0}let ue=0;function qe(){return B}async function je(t,e,o,a=10){const m=e.slice().sort().join("|"),z=I.get(t)?.get(m);if(z&&z.gebaut>ue&&Date.now()-z.gebaut<xe)return ce(z,o,a);const c=await Promise.all(e.map(k=>{const v=[],s=t.scanStream({match:k,count:500});return new Promise((b,W)=>{s.on("data",l=>{v.push(...l.filter(d=>!d.endsWith(":meta")))}),s.on("end",()=>b(v)),s.on("error",W)})})),g=[...new Set(c.flat())];if(g.length===0)return[];const i=t.pipeline();for(const k of g)i.get(k);const n=await i.exec(),r=[];let f=0;for(let k=0;k<g.length;k++){const v=n?.[k]?.[1];if(!v)continue;const s=q(`${g[k]} ${v}`,{crossLingualExpand:!1});if(s.length===0)continue;const b=new Map;for(const y of s)b.set(y,(b.get(y)??0)+1);const W=new Set;for(let y=0;y<s.length-1;y++)W.add(`${s[y]}|${s[y+1]}`);const l=se(v),d=new Set(q(g[k]));r.push({key:g[k],content:v,tokens:s,tokenFreq:b,bigrams:W,keyTokens:d,timestamp:l}),f+=s.length}if(r.length===0)return[];const w=f/r.length,p=new Map;for(const k of r){const v=new Set;for(const s of k.tokens)v.has(s)||(p.set(s,(p.get(s)??0)+1),v.add(s))}const x={docs:r,avgDL:w,docFreq:p,gebaut:Date.now()},S=I.get(t)??new Map;return S.has(m)||B++,S.set(m,x),I.set(t,S),ce(x,o,a)}function ce(t,e,o){const{docs:a,avgDL:m,docFreq:u}=t,z=a.length;function c(w){const p=u.get(w)??0;return Math.log((z-p+.5)/(p+.5)+1)}function g(w,p){const x=p.tokenFreq.get(w)??0;if(x===0)return 0;const S=p.tokens.length,k=x*(ee+1)/(x+ee*(1-te+te*(S/m)));return c(w)*(k+ye)}const i=X(e),n=new Map;for(const w of i){const p=q(w);if(p.length===0)continue;const x=new Map,S=s=>{const b=x.get(s);if(b)return b;const W=(d,y)=>{const E=[];for(const _ of u.keys())d(_)&&E.push([_,y]);return E.sort((_,le)=>(u.get(_[0])??0)-(u.get(le[0])??0)),E.slice(0,ve)};let l=[];return s.length>=4&&(l=W(d=>d.length>s.length&&d.startsWith(s),.85)),l.length===0&&s.length>=4&&(l=W(d=>d.length>=4&&d.length<s.length&&s.startsWith(d),.75)),l.length===0&&s.length>3&&(l=W(d=>d.length>3&&(d.includes(s)||s.includes(d)),.6)),l.length===0&&s.length>=4&&(l=W(d=>d.length>=4&&oe(s,d)<=2,.4)),x.set(s,l),l},k=new Set(q(w,{crossLingualExpand:!1})),v=new Set;for(let s=0;s<p.length-1;s++)v.add(`${p[s]}|${p[s+1]}`);for(const s of a){let b=0;const W=[];for(const l of p){const d=k.has(l)?1:we,y=g(l,s);if(y>0){b+=y*d,W.push(l);continue}for(const[E,_]of S(l))if(s.tokenFreq.has(E)){b+=g(E,s)*_*d,W.push(`~${l}`);break}}if(v.size>0){let l=0;for(const d of v)s.bigrams.has(d)&&l++;l>0&&(b*=1+.5*(l/v.size))}if(!process.env.AUS_PHRASE&&w.length>=4&&s.content.toLowerCase().includes(w.toLowerCase())&&(b*=2),b>0){let l=0,d=0;for(const y of p)s.keyTokens.has(y)&&(l++,k.has(y)&&d++);if(l>0){const y=d/Math.max(1,k.size);b*=1+1*Math.min(1,y*2)}}if(b*=ae(s.timestamp),b>0){const l=n.get(s.key);(!l||b>l.score)&&n.set(s.key,{key:s.key,content:s.content,score:b,matchedWords:[...new Set(W)],subQuery:i.length>1?w:void 0})}}}const f=[...n.values()].sort((w,p)=>p.score-w.score).slice(0,o);if(f.length===0){ie(e),H=new Set;for(const w of a)for(const p of w.tokens)H.add(p)}return f}export{j as CROSS_LINGUAL_MAP,h as STOPWORDS,L as ZERO_RESULTS_LOG,N as arabicLightStem,D as expandCrossLingual,se as extractTimestamp,H as indexVocab,Z as katakanaToRomaji,je as keywordSearch,oe as levenshtein,ie as logZeroResult,ae as recencyBoost,X as splitMultiQuery,q as tokenize,Re as wortindexEntwerten,qe as wortindexStand,re as zeroResultsTotal};