@jjlmoya/utils-forensic-science 1.1.0

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 (316) hide show
  1. package/package.json +69 -0
  2. package/scripts/crystal-lattice-catalog-translations.mjs +459 -0
  3. package/scripts/postinstall.mjs +27 -0
  4. package/scripts/sync-crystal-lattice-i18n.mjs +50 -0
  5. package/src/category/i18n/de.ts +55 -0
  6. package/src/category/i18n/en.ts +55 -0
  7. package/src/category/i18n/es.ts +55 -0
  8. package/src/category/i18n/fr.ts +55 -0
  9. package/src/category/i18n/id.ts +55 -0
  10. package/src/category/i18n/it.ts +55 -0
  11. package/src/category/i18n/ja.ts +56 -0
  12. package/src/category/i18n/ko.ts +56 -0
  13. package/src/category/i18n/nl.ts +55 -0
  14. package/src/category/i18n/pl.ts +55 -0
  15. package/src/category/i18n/pt.ts +55 -0
  16. package/src/category/i18n/ru.ts +55 -0
  17. package/src/category/i18n/sv.ts +55 -0
  18. package/src/category/i18n/tr.ts +55 -0
  19. package/src/category/i18n/zh.ts +56 -0
  20. package/src/category/index.ts +48 -0
  21. package/src/category/seo.astro +15 -0
  22. package/src/components/PreviewNavSidebar.astro +116 -0
  23. package/src/components/PreviewToolbar.astro +143 -0
  24. package/src/data.ts +10 -0
  25. package/src/entries.ts +48 -0
  26. package/src/env.d.ts +5 -0
  27. package/src/index.ts +29 -0
  28. package/src/layouts/PreviewLayout.astro +117 -0
  29. package/src/pages/[locale]/[slug].astro +162 -0
  30. package/src/pages/[locale].astro +261 -0
  31. package/src/pages/index.astro +3 -0
  32. package/src/tests/diacritics_density.test.ts +140 -0
  33. package/src/tests/faq_count.test.ts +19 -0
  34. package/src/tests/i18n_coverage.test.ts +36 -0
  35. package/src/tests/inverted_punctuation.test.ts +84 -0
  36. package/src/tests/locale_completeness.test.ts +24 -0
  37. package/src/tests/mocks/astro_mock.js +2 -0
  38. package/src/tests/no_en_dash.test.ts +70 -0
  39. package/src/tests/no_h1_in_components.test.ts +48 -0
  40. package/src/tests/schemas_fulfillment.test.ts +23 -0
  41. package/src/tests/script_density.test.ts +94 -0
  42. package/src/tests/seo_length.test.ts +46 -0
  43. package/src/tests/shared-test-helpers.ts +56 -0
  44. package/src/tests/slug_language_code_format.test.ts +23 -0
  45. package/src/tests/slug_uniqueness.test.ts +81 -0
  46. package/src/tests/title_quality.test.ts +55 -0
  47. package/src/tests/tool_exports.test.ts +34 -0
  48. package/src/tests/tool_validation.test.ts +16 -0
  49. package/src/tests/widmark.test.ts +28 -0
  50. package/src/tool/forensic-age-estimator/bibliography.astro +14 -0
  51. package/src/tool/forensic-age-estimator/bibliography.ts +16 -0
  52. package/src/tool/forensic-age-estimator/component.astro +321 -0
  53. package/src/tool/forensic-age-estimator/dental-skeletal-third-molar-age-estimator.css +634 -0
  54. package/src/tool/forensic-age-estimator/entry.ts +32 -0
  55. package/src/tool/forensic-age-estimator/i18n/de.ts +245 -0
  56. package/src/tool/forensic-age-estimator/i18n/en.ts +245 -0
  57. package/src/tool/forensic-age-estimator/i18n/es.ts +245 -0
  58. package/src/tool/forensic-age-estimator/i18n/fr.ts +245 -0
  59. package/src/tool/forensic-age-estimator/i18n/id.ts +245 -0
  60. package/src/tool/forensic-age-estimator/i18n/it.ts +245 -0
  61. package/src/tool/forensic-age-estimator/i18n/ja.ts +245 -0
  62. package/src/tool/forensic-age-estimator/i18n/ko.ts +245 -0
  63. package/src/tool/forensic-age-estimator/i18n/nl.ts +245 -0
  64. package/src/tool/forensic-age-estimator/i18n/pl.ts +245 -0
  65. package/src/tool/forensic-age-estimator/i18n/pt.ts +245 -0
  66. package/src/tool/forensic-age-estimator/i18n/ru.ts +245 -0
  67. package/src/tool/forensic-age-estimator/i18n/sv.ts +245 -0
  68. package/src/tool/forensic-age-estimator/i18n/tr.ts +245 -0
  69. package/src/tool/forensic-age-estimator/i18n/zh.ts +246 -0
  70. package/src/tool/forensic-age-estimator/index.ts +11 -0
  71. package/src/tool/forensic-age-estimator/logic.ts +81 -0
  72. package/src/tool/forensic-age-estimator/seo.astro +15 -0
  73. package/src/tool/forensic-blood-test-simulator/bibliography.astro +6 -0
  74. package/src/tool/forensic-blood-test-simulator/bibliography.ts +12 -0
  75. package/src/tool/forensic-blood-test-simulator/component.astro +168 -0
  76. package/src/tool/forensic-blood-test-simulator/dom-utils.ts +40 -0
  77. package/src/tool/forensic-blood-test-simulator/entry.ts +32 -0
  78. package/src/tool/forensic-blood-test-simulator/forensic-presumptive-blood-testing-luminol-kastle-meyer-simulator.css +532 -0
  79. package/src/tool/forensic-blood-test-simulator/helpers.ts +16 -0
  80. package/src/tool/forensic-blood-test-simulator/i18n/de.ts +185 -0
  81. package/src/tool/forensic-blood-test-simulator/i18n/en.ts +185 -0
  82. package/src/tool/forensic-blood-test-simulator/i18n/es.ts +185 -0
  83. package/src/tool/forensic-blood-test-simulator/i18n/fr.ts +220 -0
  84. package/src/tool/forensic-blood-test-simulator/i18n/id.ts +220 -0
  85. package/src/tool/forensic-blood-test-simulator/i18n/it.ts +220 -0
  86. package/src/tool/forensic-blood-test-simulator/i18n/ja.ts +220 -0
  87. package/src/tool/forensic-blood-test-simulator/i18n/ko.ts +220 -0
  88. package/src/tool/forensic-blood-test-simulator/i18n/nl.ts +220 -0
  89. package/src/tool/forensic-blood-test-simulator/i18n/pl.ts +220 -0
  90. package/src/tool/forensic-blood-test-simulator/i18n/pt.ts +220 -0
  91. package/src/tool/forensic-blood-test-simulator/i18n/ru.ts +220 -0
  92. package/src/tool/forensic-blood-test-simulator/i18n/sv.ts +220 -0
  93. package/src/tool/forensic-blood-test-simulator/i18n/tr.ts +220 -0
  94. package/src/tool/forensic-blood-test-simulator/i18n/zh.ts +220 -0
  95. package/src/tool/forensic-blood-test-simulator/index.ts +11 -0
  96. package/src/tool/forensic-blood-test-simulator/logic.ts +174 -0
  97. package/src/tool/forensic-blood-test-simulator/script.ts +192 -0
  98. package/src/tool/forensic-blood-test-simulator/seo.astro +15 -0
  99. package/src/tool/forensic-fiber-comparison-microscope/bibliography.astro +6 -0
  100. package/src/tool/forensic-fiber-comparison-microscope/bibliography.ts +16 -0
  101. package/src/tool/forensic-fiber-comparison-microscope/component.astro +146 -0
  102. package/src/tool/forensic-fiber-comparison-microscope/entry.ts +32 -0
  103. package/src/tool/forensic-fiber-comparison-microscope/forensic-fiber-comparison-microscope.css +629 -0
  104. package/src/tool/forensic-fiber-comparison-microscope/i18n/de.ts +250 -0
  105. package/src/tool/forensic-fiber-comparison-microscope/i18n/en.ts +246 -0
  106. package/src/tool/forensic-fiber-comparison-microscope/i18n/es.ts +246 -0
  107. package/src/tool/forensic-fiber-comparison-microscope/i18n/fr.ts +246 -0
  108. package/src/tool/forensic-fiber-comparison-microscope/i18n/id.ts +250 -0
  109. package/src/tool/forensic-fiber-comparison-microscope/i18n/it.ts +246 -0
  110. package/src/tool/forensic-fiber-comparison-microscope/i18n/ja.ts +250 -0
  111. package/src/tool/forensic-fiber-comparison-microscope/i18n/ko.ts +246 -0
  112. package/src/tool/forensic-fiber-comparison-microscope/i18n/nl.ts +246 -0
  113. package/src/tool/forensic-fiber-comparison-microscope/i18n/pl.ts +250 -0
  114. package/src/tool/forensic-fiber-comparison-microscope/i18n/pt.ts +250 -0
  115. package/src/tool/forensic-fiber-comparison-microscope/i18n/ru.ts +250 -0
  116. package/src/tool/forensic-fiber-comparison-microscope/i18n/sv.ts +250 -0
  117. package/src/tool/forensic-fiber-comparison-microscope/i18n/tr.ts +246 -0
  118. package/src/tool/forensic-fiber-comparison-microscope/i18n/zh.ts +250 -0
  119. package/src/tool/forensic-fiber-comparison-microscope/index.ts +11 -0
  120. package/src/tool/forensic-fiber-comparison-microscope/logic.ts +244 -0
  121. package/src/tool/forensic-fiber-comparison-microscope/render.ts +265 -0
  122. package/src/tool/forensic-fiber-comparison-microscope/seo.astro +15 -0
  123. package/src/tool/forensic-fiber-comparison-microscope/view.ts +267 -0
  124. package/src/tool/forensic-glass-becke-line-simulator/bibliography.astro +6 -0
  125. package/src/tool/forensic-glass-becke-line-simulator/bibliography.ts +16 -0
  126. package/src/tool/forensic-glass-becke-line-simulator/component.astro +81 -0
  127. package/src/tool/forensic-glass-becke-line-simulator/entry.ts +32 -0
  128. package/src/tool/forensic-glass-becke-line-simulator/forensic-glass-becke-line-simulator.css +392 -0
  129. package/src/tool/forensic-glass-becke-line-simulator/i18n/de.ts +231 -0
  130. package/src/tool/forensic-glass-becke-line-simulator/i18n/en.ts +231 -0
  131. package/src/tool/forensic-glass-becke-line-simulator/i18n/es.ts +231 -0
  132. package/src/tool/forensic-glass-becke-line-simulator/i18n/fr.ts +231 -0
  133. package/src/tool/forensic-glass-becke-line-simulator/i18n/id.ts +231 -0
  134. package/src/tool/forensic-glass-becke-line-simulator/i18n/it.ts +231 -0
  135. package/src/tool/forensic-glass-becke-line-simulator/i18n/ja.ts +231 -0
  136. package/src/tool/forensic-glass-becke-line-simulator/i18n/ko.ts +231 -0
  137. package/src/tool/forensic-glass-becke-line-simulator/i18n/nl.ts +231 -0
  138. package/src/tool/forensic-glass-becke-line-simulator/i18n/pl.ts +231 -0
  139. package/src/tool/forensic-glass-becke-line-simulator/i18n/pt.ts +231 -0
  140. package/src/tool/forensic-glass-becke-line-simulator/i18n/ru.ts +231 -0
  141. package/src/tool/forensic-glass-becke-line-simulator/i18n/sv.ts +231 -0
  142. package/src/tool/forensic-glass-becke-line-simulator/i18n/tr.ts +231 -0
  143. package/src/tool/forensic-glass-becke-line-simulator/i18n/zh.ts +231 -0
  144. package/src/tool/forensic-glass-becke-line-simulator/index.ts +11 -0
  145. package/src/tool/forensic-glass-becke-line-simulator/logic.ts +100 -0
  146. package/src/tool/forensic-glass-becke-line-simulator/seo.astro +15 -0
  147. package/src/tool/forensic-glass-becke-line-simulator/view.ts +281 -0
  148. package/src/tool/forensic-image-authenticity-analyzer/bibliography.astro +9 -0
  149. package/src/tool/forensic-image-authenticity-analyzer/bibliography.ts +7 -0
  150. package/src/tool/forensic-image-authenticity-analyzer/component.astro +250 -0
  151. package/src/tool/forensic-image-authenticity-analyzer/entry.ts +29 -0
  152. package/src/tool/forensic-image-authenticity-analyzer/forensic-image-metadata-authenticity-analyzer.css +679 -0
  153. package/src/tool/forensic-image-authenticity-analyzer/i18n/de.ts +105 -0
  154. package/src/tool/forensic-image-authenticity-analyzer/i18n/en.ts +105 -0
  155. package/src/tool/forensic-image-authenticity-analyzer/i18n/es.ts +105 -0
  156. package/src/tool/forensic-image-authenticity-analyzer/i18n/fr.ts +105 -0
  157. package/src/tool/forensic-image-authenticity-analyzer/i18n/id.ts +76 -0
  158. package/src/tool/forensic-image-authenticity-analyzer/i18n/it.ts +105 -0
  159. package/src/tool/forensic-image-authenticity-analyzer/i18n/ja.ts +72 -0
  160. package/src/tool/forensic-image-authenticity-analyzer/i18n/ko.ts +72 -0
  161. package/src/tool/forensic-image-authenticity-analyzer/i18n/nl.ts +75 -0
  162. package/src/tool/forensic-image-authenticity-analyzer/i18n/pl.ts +75 -0
  163. package/src/tool/forensic-image-authenticity-analyzer/i18n/pt.ts +105 -0
  164. package/src/tool/forensic-image-authenticity-analyzer/i18n/ru.ts +75 -0
  165. package/src/tool/forensic-image-authenticity-analyzer/i18n/sv.ts +76 -0
  166. package/src/tool/forensic-image-authenticity-analyzer/i18n/tr.ts +76 -0
  167. package/src/tool/forensic-image-authenticity-analyzer/i18n/zh.ts +71 -0
  168. package/src/tool/forensic-image-authenticity-analyzer/index.ts +11 -0
  169. package/src/tool/forensic-image-authenticity-analyzer/logic.ts +283 -0
  170. package/src/tool/forensic-image-authenticity-analyzer/seo.astro +10 -0
  171. package/src/tool/forensic-microcrystal-drug-simulator/bibliography.astro +6 -0
  172. package/src/tool/forensic-microcrystal-drug-simulator/bibliography.ts +12 -0
  173. package/src/tool/forensic-microcrystal-drug-simulator/component.astro +240 -0
  174. package/src/tool/forensic-microcrystal-drug-simulator/entry.ts +32 -0
  175. package/src/tool/forensic-microcrystal-drug-simulator/forensic-microcrystal-drug-simulator.css +430 -0
  176. package/src/tool/forensic-microcrystal-drug-simulator/i18n/de.ts +244 -0
  177. package/src/tool/forensic-microcrystal-drug-simulator/i18n/en.ts +244 -0
  178. package/src/tool/forensic-microcrystal-drug-simulator/i18n/es.ts +244 -0
  179. package/src/tool/forensic-microcrystal-drug-simulator/i18n/fr.ts +244 -0
  180. package/src/tool/forensic-microcrystal-drug-simulator/i18n/id.ts +244 -0
  181. package/src/tool/forensic-microcrystal-drug-simulator/i18n/it.ts +244 -0
  182. package/src/tool/forensic-microcrystal-drug-simulator/i18n/ja.ts +244 -0
  183. package/src/tool/forensic-microcrystal-drug-simulator/i18n/ko.ts +244 -0
  184. package/src/tool/forensic-microcrystal-drug-simulator/i18n/nl.ts +244 -0
  185. package/src/tool/forensic-microcrystal-drug-simulator/i18n/pl.ts +244 -0
  186. package/src/tool/forensic-microcrystal-drug-simulator/i18n/pt.ts +244 -0
  187. package/src/tool/forensic-microcrystal-drug-simulator/i18n/ru.ts +244 -0
  188. package/src/tool/forensic-microcrystal-drug-simulator/i18n/sv.ts +244 -0
  189. package/src/tool/forensic-microcrystal-drug-simulator/i18n/tr.ts +244 -0
  190. package/src/tool/forensic-microcrystal-drug-simulator/i18n/zh.ts +244 -0
  191. package/src/tool/forensic-microcrystal-drug-simulator/index.ts +11 -0
  192. package/src/tool/forensic-microcrystal-drug-simulator/logic.ts +189 -0
  193. package/src/tool/forensic-microcrystal-drug-simulator/seo.astro +15 -0
  194. package/src/tool/forensic-sex-determinator/bibliography.astro +14 -0
  195. package/src/tool/forensic-sex-determinator/bibliography.ts +12 -0
  196. package/src/tool/forensic-sex-determinator/component.astro +463 -0
  197. package/src/tool/forensic-sex-determinator/entry.ts +32 -0
  198. package/src/tool/forensic-sex-determinator/forensic-sex-determinator.css +413 -0
  199. package/src/tool/forensic-sex-determinator/i18n/de.ts +211 -0
  200. package/src/tool/forensic-sex-determinator/i18n/en.ts +211 -0
  201. package/src/tool/forensic-sex-determinator/i18n/es.ts +211 -0
  202. package/src/tool/forensic-sex-determinator/i18n/fr.ts +211 -0
  203. package/src/tool/forensic-sex-determinator/i18n/id.ts +211 -0
  204. package/src/tool/forensic-sex-determinator/i18n/it.ts +211 -0
  205. package/src/tool/forensic-sex-determinator/i18n/ja.ts +211 -0
  206. package/src/tool/forensic-sex-determinator/i18n/ko.ts +211 -0
  207. package/src/tool/forensic-sex-determinator/i18n/nl.ts +211 -0
  208. package/src/tool/forensic-sex-determinator/i18n/pl.ts +211 -0
  209. package/src/tool/forensic-sex-determinator/i18n/pt.ts +211 -0
  210. package/src/tool/forensic-sex-determinator/i18n/ru.ts +211 -0
  211. package/src/tool/forensic-sex-determinator/i18n/sv.ts +211 -0
  212. package/src/tool/forensic-sex-determinator/i18n/tr.ts +211 -0
  213. package/src/tool/forensic-sex-determinator/i18n/zh.ts +211 -0
  214. package/src/tool/forensic-sex-determinator/index.ts +11 -0
  215. package/src/tool/forensic-sex-determinator/logic.ts +89 -0
  216. package/src/tool/forensic-sex-determinator/seo.astro +15 -0
  217. package/src/tool/forensic-stature-estimator/bibliography.astro +14 -0
  218. package/src/tool/forensic-stature-estimator/bibliography.ts +12 -0
  219. package/src/tool/forensic-stature-estimator/component.astro +49 -0
  220. package/src/tool/forensic-stature-estimator/components/EstimationPanel.astro +65 -0
  221. package/src/tool/forensic-stature-estimator/components/OsteometricBoard.astro +39 -0
  222. package/src/tool/forensic-stature-estimator/components/OsteometricSelector.astro +109 -0
  223. package/src/tool/forensic-stature-estimator/dom-utils.ts +71 -0
  224. package/src/tool/forensic-stature-estimator/entry.ts +32 -0
  225. package/src/tool/forensic-stature-estimator/forensic-stature-estimator.css +689 -0
  226. package/src/tool/forensic-stature-estimator/helpers.ts +51 -0
  227. package/src/tool/forensic-stature-estimator/i18n/de.ts +196 -0
  228. package/src/tool/forensic-stature-estimator/i18n/en.ts +196 -0
  229. package/src/tool/forensic-stature-estimator/i18n/es.ts +196 -0
  230. package/src/tool/forensic-stature-estimator/i18n/fr.ts +196 -0
  231. package/src/tool/forensic-stature-estimator/i18n/id.ts +196 -0
  232. package/src/tool/forensic-stature-estimator/i18n/it.ts +196 -0
  233. package/src/tool/forensic-stature-estimator/i18n/ja.ts +196 -0
  234. package/src/tool/forensic-stature-estimator/i18n/ko.ts +196 -0
  235. package/src/tool/forensic-stature-estimator/i18n/nl.ts +196 -0
  236. package/src/tool/forensic-stature-estimator/i18n/pl.ts +196 -0
  237. package/src/tool/forensic-stature-estimator/i18n/pt.ts +196 -0
  238. package/src/tool/forensic-stature-estimator/i18n/ru.ts +196 -0
  239. package/src/tool/forensic-stature-estimator/i18n/sv.ts +196 -0
  240. package/src/tool/forensic-stature-estimator/i18n/tr.ts +196 -0
  241. package/src/tool/forensic-stature-estimator/i18n/zh.ts +196 -0
  242. package/src/tool/forensic-stature-estimator/index.ts +11 -0
  243. package/src/tool/forensic-stature-estimator/logic.ts +119 -0
  244. package/src/tool/forensic-stature-estimator/script.ts +288 -0
  245. package/src/tool/forensic-stature-estimator/seo.astro +15 -0
  246. package/src/tool/forensic-tlc-ink-simulator/bibliography.astro +6 -0
  247. package/src/tool/forensic-tlc-ink-simulator/bibliography.ts +16 -0
  248. package/src/tool/forensic-tlc-ink-simulator/component.astro +245 -0
  249. package/src/tool/forensic-tlc-ink-simulator/entry.ts +32 -0
  250. package/src/tool/forensic-tlc-ink-simulator/forensic-tlc-ink-simulator.css +462 -0
  251. package/src/tool/forensic-tlc-ink-simulator/i18n/de.ts +243 -0
  252. package/src/tool/forensic-tlc-ink-simulator/i18n/en.ts +243 -0
  253. package/src/tool/forensic-tlc-ink-simulator/i18n/es.ts +243 -0
  254. package/src/tool/forensic-tlc-ink-simulator/i18n/fr.ts +243 -0
  255. package/src/tool/forensic-tlc-ink-simulator/i18n/id.ts +243 -0
  256. package/src/tool/forensic-tlc-ink-simulator/i18n/it.ts +243 -0
  257. package/src/tool/forensic-tlc-ink-simulator/i18n/ja.ts +235 -0
  258. package/src/tool/forensic-tlc-ink-simulator/i18n/ko.ts +235 -0
  259. package/src/tool/forensic-tlc-ink-simulator/i18n/nl.ts +243 -0
  260. package/src/tool/forensic-tlc-ink-simulator/i18n/pl.ts +243 -0
  261. package/src/tool/forensic-tlc-ink-simulator/i18n/pt.ts +243 -0
  262. package/src/tool/forensic-tlc-ink-simulator/i18n/ru.ts +243 -0
  263. package/src/tool/forensic-tlc-ink-simulator/i18n/sv.ts +243 -0
  264. package/src/tool/forensic-tlc-ink-simulator/i18n/tr.ts +243 -0
  265. package/src/tool/forensic-tlc-ink-simulator/i18n/zh.ts +235 -0
  266. package/src/tool/forensic-tlc-ink-simulator/index.ts +11 -0
  267. package/src/tool/forensic-tlc-ink-simulator/logic.ts +152 -0
  268. package/src/tool/forensic-tlc-ink-simulator/seo.astro +15 -0
  269. package/src/tool/gsr-dispersion-calculator/bibliography.astro +6 -0
  270. package/src/tool/gsr-dispersion-calculator/bibliography.ts +16 -0
  271. package/src/tool/gsr-dispersion-calculator/component.astro +294 -0
  272. package/src/tool/gsr-dispersion-calculator/entry.ts +32 -0
  273. package/src/tool/gsr-dispersion-calculator/gsr-dispersion-calculator.css +305 -0
  274. package/src/tool/gsr-dispersion-calculator/i18n/de.ts +272 -0
  275. package/src/tool/gsr-dispersion-calculator/i18n/en.ts +272 -0
  276. package/src/tool/gsr-dispersion-calculator/i18n/es.ts +272 -0
  277. package/src/tool/gsr-dispersion-calculator/i18n/fr.ts +272 -0
  278. package/src/tool/gsr-dispersion-calculator/i18n/id.ts +272 -0
  279. package/src/tool/gsr-dispersion-calculator/i18n/it.ts +272 -0
  280. package/src/tool/gsr-dispersion-calculator/i18n/ja.ts +272 -0
  281. package/src/tool/gsr-dispersion-calculator/i18n/ko.ts +272 -0
  282. package/src/tool/gsr-dispersion-calculator/i18n/nl.ts +272 -0
  283. package/src/tool/gsr-dispersion-calculator/i18n/pl.ts +272 -0
  284. package/src/tool/gsr-dispersion-calculator/i18n/pt.ts +272 -0
  285. package/src/tool/gsr-dispersion-calculator/i18n/ru.ts +272 -0
  286. package/src/tool/gsr-dispersion-calculator/i18n/sv.ts +272 -0
  287. package/src/tool/gsr-dispersion-calculator/i18n/tr.ts +272 -0
  288. package/src/tool/gsr-dispersion-calculator/i18n/zh.ts +272 -0
  289. package/src/tool/gsr-dispersion-calculator/index.ts +11 -0
  290. package/src/tool/gsr-dispersion-calculator/logic.ts +148 -0
  291. package/src/tool/gsr-dispersion-calculator/seo.astro +15 -0
  292. package/src/tool/widmark-alcohol-simulator/bibliography.astro +14 -0
  293. package/src/tool/widmark-alcohol-simulator/bibliography.ts +12 -0
  294. package/src/tool/widmark-alcohol-simulator/component.astro +453 -0
  295. package/src/tool/widmark-alcohol-simulator/entry.ts +32 -0
  296. package/src/tool/widmark-alcohol-simulator/i18n/de.ts +193 -0
  297. package/src/tool/widmark-alcohol-simulator/i18n/en.ts +206 -0
  298. package/src/tool/widmark-alcohol-simulator/i18n/es.ts +193 -0
  299. package/src/tool/widmark-alcohol-simulator/i18n/fr.ts +193 -0
  300. package/src/tool/widmark-alcohol-simulator/i18n/id.ts +193 -0
  301. package/src/tool/widmark-alcohol-simulator/i18n/it.ts +193 -0
  302. package/src/tool/widmark-alcohol-simulator/i18n/ja.ts +193 -0
  303. package/src/tool/widmark-alcohol-simulator/i18n/ko.ts +193 -0
  304. package/src/tool/widmark-alcohol-simulator/i18n/nl.ts +193 -0
  305. package/src/tool/widmark-alcohol-simulator/i18n/pl.ts +193 -0
  306. package/src/tool/widmark-alcohol-simulator/i18n/pt.ts +193 -0
  307. package/src/tool/widmark-alcohol-simulator/i18n/ru.ts +193 -0
  308. package/src/tool/widmark-alcohol-simulator/i18n/sv.ts +193 -0
  309. package/src/tool/widmark-alcohol-simulator/i18n/tr.ts +193 -0
  310. package/src/tool/widmark-alcohol-simulator/i18n/zh.ts +193 -0
  311. package/src/tool/widmark-alcohol-simulator/index.ts +11 -0
  312. package/src/tool/widmark-alcohol-simulator/logic.ts +97 -0
  313. package/src/tool/widmark-alcohol-simulator/seo.astro +15 -0
  314. package/src/tool/widmark-alcohol-simulator/widmark-alcohol-simulator.css +386 -0
  315. package/src/tools.ts +27 -0
  316. package/src/types.ts +70 -0
@@ -0,0 +1,192 @@
1
+ import { ChemicalReactionEngine } from './logic';
2
+ import type { SampleType, ReagentType, ReactionState } from './logic';
3
+ import { getReactionColor, getGlowOpacity } from './helpers';
4
+ import { animateDrop, applyPetriReaction } from './dom-utils';
5
+
6
+ const uiDataEl = document.getElementById('blood-test-ui-data');
7
+ const ui = uiDataEl ? JSON.parse(uiDataEl.textContent || '{}') : {};
8
+
9
+ const petriDish = document.getElementById('petri-dish'),
10
+ petriSpecimen = document.getElementById('petri-specimen'),
11
+ chemicalDrop = document.getElementById('chemical-drop'),
12
+ viewport = document.getElementById('workbench-viewport');
13
+
14
+ const statusBadge = document.getElementById('status-badge'),
15
+ explanationText = document.getElementById('explanation-text'),
16
+ valCompounds = document.getElementById('val-compounds'),
17
+ valSpeed = document.getElementById('val-speed'),
18
+ valDuration = document.getElementById('val-duration'),
19
+ valSpecimenBase = document.getElementById('val-specimen-base');
20
+
21
+ const btnReset = document.getElementById('btn-reset-workbench');
22
+ const btnToggleLights = document.getElementById('btn-toggle-lights');
23
+
24
+ let selectedSample: SampleType = 'blood';
25
+ const addedReagents: ReagentType[] = [];
26
+ let lightingMode: 'on' | 'off' = 'on';
27
+
28
+ let glowInterval: number | null = null;
29
+ let glowElapsed = 0;
30
+
31
+ function getSampleName(sample: SampleType): string {
32
+ const map: Record<SampleType, string> = {
33
+ blood: ui.sampleBlood,
34
+ rust: ui.sampleRust,
35
+ bleach: ui.sampleBleach,
36
+ potato: ui.samplePotato,
37
+ saliva: ui.sampleSaliva
38
+ };
39
+ return map[sample] || '';
40
+ }
41
+
42
+ function getReagentName(reagent: ReagentType): string {
43
+ const map: Record<ReagentType, string> = {
44
+ km: ui.reagentKM,
45
+ h2o2: ui.reagentH2O2,
46
+ luminol: ui.reagentLuminol
47
+ };
48
+ return map[reagent] || '';
49
+ }
50
+
51
+ function clearGlowTimer() {
52
+ if (glowInterval) {
53
+ clearInterval(glowInterval);
54
+ glowInterval = null;
55
+ }
56
+ }
57
+
58
+ function updateTextContent(el: HTMLElement | null, text: string) {
59
+ if (el) {
60
+ el.textContent = text;
61
+ }
62
+ }
63
+
64
+ function updateBadgeState(result: ReactionState) {
65
+ if (!statusBadge) return;
66
+ const key = result.resultType.split('-').map((s: string) => s.charAt(0).toUpperCase() + s.slice(1)).join('');
67
+ statusBadge.textContent = ui[`result${key}`] || '';
68
+ statusBadge.className = `status-badge status-${result.resultType}`;
69
+ }
70
+
71
+ function renderReactionState(result: ReactionState, currentOpacity: number) {
72
+ updateBadgeState(result);
73
+ updateTextContent(explanationText, ui[result.descriptionKey] || '');
74
+
75
+ const compoundsText = result.addedReagents.map(getReagentName).join(' + ') || '-';
76
+ updateTextContent(valCompounds, compoundsText);
77
+
78
+ const speedText = result.intensity > 0 ? `${(result.intensity * 100).toFixed(0)}%` : '-';
79
+ updateTextContent(valSpeed, speedText);
80
+
81
+ const durationText = result.durationMs > 0 ? `${(result.durationMs / 1000).toFixed(1)}s` : '∞';
82
+ updateTextContent(valDuration, durationText);
83
+
84
+ updateTextContent(valSpecimenBase, getSampleName(selectedSample));
85
+
86
+ const showGlow = result.glow && lightingMode === 'off';
87
+ const appliedColor = getReactionColor(result.color, result.intensity);
88
+
89
+ applyPetriReaction(petriSpecimen, {
90
+ color: appliedColor,
91
+ glow: showGlow,
92
+ glowColor: result.glowColor,
93
+ opacity: currentOpacity
94
+ });
95
+ }
96
+
97
+ function startGlowAnimation(result: ReactionState) {
98
+ clearGlowTimer();
99
+ glowElapsed = 0;
100
+
101
+ glowInterval = window.setInterval(() => {
102
+ glowElapsed += 100;
103
+ const opacity = getGlowOpacity(glowElapsed, result.durationMs);
104
+ renderReactionState(result, opacity);
105
+
106
+ if (glowElapsed >= result.durationMs) {
107
+ clearGlowTimer();
108
+ }
109
+ }, 100);
110
+ }
111
+
112
+ function triggerReactionUpdate() {
113
+ const result = ChemicalReactionEngine.getReaction(selectedSample, addedReagents);
114
+
115
+ if (result.glow && lightingMode === 'off' && result.durationMs > 0) {
116
+ startGlowAnimation(result);
117
+ } else {
118
+ clearGlowTimer();
119
+ renderReactionState(result, 1);
120
+ }
121
+ }
122
+
123
+ function selectSample(sample: SampleType) {
124
+ selectedSample = sample;
125
+ addedReagents.length = 0;
126
+ clearGlowTimer();
127
+ triggerReactionUpdate();
128
+
129
+ document.querySelectorAll('.specimen-tube').forEach(node => {
130
+ node.classList.toggle('selected', node.getAttribute('data-sample') === sample);
131
+ });
132
+ }
133
+
134
+ function applyReagentDrop(reagent: ReagentType) {
135
+ if (reagent === 'luminol') {
136
+ addedReagents.length = 0;
137
+ addedReagents.push('luminol');
138
+ } else {
139
+ if (addedReagents.includes('luminol')) {
140
+ addedReagents.length = 0;
141
+ }
142
+ if (!addedReagents.includes(reagent)) {
143
+ addedReagents.push(reagent);
144
+ }
145
+ }
146
+
147
+ animateDrop(chemicalDrop, petriDish, () => {
148
+ triggerReactionUpdate();
149
+ });
150
+ }
151
+
152
+ function toggleLighting() {
153
+ const nextMode = lightingMode === 'on' ? 'off' : 'on';
154
+ lightingMode = nextMode;
155
+ if (viewport) {
156
+ viewport.classList.toggle('workbench-lights-off', nextMode === 'off');
157
+ }
158
+ if (btnToggleLights) {
159
+ btnToggleLights.classList.toggle('lights-off', nextMode === 'off');
160
+ }
161
+ triggerReactionUpdate();
162
+ }
163
+
164
+ document.querySelectorAll('.specimen-tube').forEach(node => {
165
+ node.addEventListener('click', () => {
166
+ const s = node.getAttribute('data-sample') as SampleType;
167
+ if (s) selectSample(s);
168
+ });
169
+ });
170
+
171
+ document.querySelectorAll('.btn-dispense-fluid').forEach(btn => {
172
+ btn.addEventListener('click', () => {
173
+ const r = btn.getAttribute('data-reagent') as ReagentType;
174
+ if (r) applyReagentDrop(r);
175
+ });
176
+ });
177
+
178
+ if (btnToggleLights) {
179
+ btnToggleLights.addEventListener('click', () => {
180
+ toggleLighting();
181
+ });
182
+ }
183
+
184
+ if (btnReset) {
185
+ btnReset.addEventListener('click', () => {
186
+ addedReagents.length = 0;
187
+ clearGlowTimer();
188
+ triggerReactionUpdate();
189
+ });
190
+ }
191
+
192
+ triggerReactionUpdate();
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { forensicBloodTestSimulator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const content = await forensicBloodTestSimulator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo && content.seo.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,6 @@
1
+ ---
2
+ import { Bibliography as BibliographyRenderer } from '@jjlmoya/utils-shared';
3
+ import { bibliography } from './bibliography';
4
+ ---
5
+
6
+ <BibliographyRenderer links={bibliography} />
@@ -0,0 +1,16 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ {
5
+ name: 'Forensic Fiber Examination Guidelines.',
6
+ url: 'https://www.ojp.gov/ncjrs/virtual-library/abstracts/forensic-fiber-examinations-guidelines',
7
+ },
8
+ {
9
+ name: 'Standard Guide for Microscopical Examination of Textile Fibers.',
10
+ url: 'https://www.physicsnorm.com/NewSamples/ASTM/193661856/ASTM-E2228-19-1.pdf',
11
+ },
12
+ {
13
+ name: 'With a Trace: Analyzing Crime Scene Clues',
14
+ url: 'https://archives.fbi.gov/archives/news/stories/2007/july/trace070207',
15
+ },
16
+ ];
@@ -0,0 +1,146 @@
1
+ ---
2
+ import './forensic-fiber-comparison-microscope.css';
3
+
4
+ interface Props {
5
+ ui: Record<string, string>;
6
+ }
7
+
8
+ const { ui } = Astro.props;
9
+ ---
10
+
11
+ <section class="fiber-lab" data-fiber-tool>
12
+ <div class="fiber-stage">
13
+ <div class="fiber-ocular" aria-label={ui.viewerAria}>
14
+ <canvas id="fiber-canvas" width="860" height="560"></canvas>
15
+ <div class="fiber-split" aria-hidden="true"></div>
16
+ <div class="fiber-label fiber-label-left" id="fiber-left-label">-</div>
17
+ <div class="fiber-label fiber-label-right" id="fiber-right-label">-</div>
18
+ <div class="fiber-score">
19
+ <span>{ui.combinedMatch}</span>
20
+ <strong id="fiber-combined-score">-</strong>
21
+ </div>
22
+ </div>
23
+
24
+ <aside class="fiber-controls">
25
+ <div class="fiber-field">
26
+ <span>{ui.questionedSample}</span>
27
+ <select id="fiber-left" class="fiber-native-select" aria-hidden="true" tabindex="-1">
28
+ <option value="questionedCotton">{ui.questionedCotton}</option>
29
+ </select>
30
+ <div class="fiber-builder-head">
31
+ <span id="fiber-left-choice">{ui.questionedCotton}</span>
32
+ <small id="fiber-left-summary">{ui.builderSummaryDefault}</small>
33
+ </div>
34
+ <div class="fiber-builder-grid">
35
+ <div class="fiber-builder-group">
36
+ <small>{ui.material}</small>
37
+ <div class="fiber-pill-row" role="group" aria-label={ui.material}>
38
+ <button type="button" data-fiber-builder="material" data-builder-value="cotton" data-active="true">{ui.cotton}</button>
39
+ <button type="button" data-fiber-builder="material" data-builder-value="wool" data-active="false">{ui.woolMaterial}</button>
40
+ <button type="button" data-fiber-builder="material" data-builder-value="polyester" data-active="false">{ui.polyesterMaterial}</button>
41
+ <button type="button" data-fiber-builder="material" data-builder-value="nylon" data-active="false">{ui.nylonMaterial}</button>
42
+ </div>
43
+ </div>
44
+ <div class="fiber-builder-group">
45
+ <small>{ui.twist}</small>
46
+ <div class="fiber-pill-row" role="group" aria-label={ui.twist}>
47
+ <button type="button" data-fiber-builder="twist" data-builder-value="irregular" data-active="true">{ui.irregularTwist}</button>
48
+ <button type="button" data-fiber-builder="twist" data-builder-value="S" data-active="false">{ui.sTwist}</button>
49
+ <button type="button" data-fiber-builder="twist" data-builder-value="Z" data-active="false">{ui.zTwist}</button>
50
+ </div>
51
+ </div>
52
+ <label class="fiber-mini-slider">
53
+ <span>{ui.diameter}</span>
54
+ <strong id="fiber-diameter-label">18 µm</strong>
55
+ <input id="fiber-diameter" type="range" min="8" max="36" value="18" />
56
+ </label>
57
+ <label class="fiber-mini-slider">
58
+ <span>{ui.polarResponse}</span>
59
+ <strong id="fiber-birefringence-label">0.032</strong>
60
+ <input id="fiber-questioned-birefringence" type="range" min="10" max="65" value="32" />
61
+ </label>
62
+ <div class="fiber-builder-group fiber-builder-wide">
63
+ <small>{ui.dyeProfile}</small>
64
+ <div class="fiber-pill-row" role="group" aria-label={ui.dyeProfile}>
65
+ <button type="button" data-fiber-builder="dyePreset" data-builder-value="indigo" data-active="true">{ui.indigoDye}</button>
66
+ <button type="button" data-fiber-builder="dyePreset" data-builder-value="crimson" data-active="false">{ui.crimsonDye}</button>
67
+ <button type="button" data-fiber-builder="dyePreset" data-builder-value="navy" data-active="false">{ui.navyDye}</button>
68
+ <button type="button" data-fiber-builder="dyePreset" data-builder-value="violet" data-active="false">{ui.violetDye}</button>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="fiber-field">
75
+ <span>{ui.knownSample}</span>
76
+ <select id="fiber-right" class="fiber-native-select" aria-hidden="true" tabindex="-1">
77
+ <option value="suspectCotton">{ui.suspectCotton}</option>
78
+ <option value="wool">{ui.wool}</option>
79
+ <option value="polyester">{ui.polyester}</option>
80
+ <option value="nylon">{ui.nylon}</option>
81
+ </select>
82
+ <button class="fiber-choice-trigger" type="button" data-fiber-choice-trigger="right" aria-haspopup="listbox" aria-expanded="false">
83
+ <span id="fiber-right-choice">{ui.suspectCotton}</span>
84
+ <span class="fiber-choice-mark" aria-hidden="true"></span>
85
+ </button>
86
+ <div class="fiber-choice-menu" data-fiber-choice-menu="right" role="listbox" aria-label={ui.knownSample}>
87
+ <button type="button" role="option" data-fiber-choice="right" data-fiber-value="suspectCotton" aria-selected="true">{ui.suspectCotton}</button>
88
+ <button type="button" role="option" data-fiber-choice="right" data-fiber-value="wool" aria-selected="false">{ui.wool}</button>
89
+ <button type="button" role="option" data-fiber-choice="right" data-fiber-value="polyester" aria-selected="false">{ui.polyester}</button>
90
+ <button type="button" role="option" data-fiber-choice="right" data-fiber-value="nylon" aria-selected="false">{ui.nylon}</button>
91
+ </div>
92
+ </div>
93
+
94
+ <label class="fiber-slider fiber-focus">
95
+ <span>{ui.focus}</span>
96
+ <strong id="fiber-focus-label">-</strong>
97
+ <input id="fiber-focus" type="range" min="0" max="100" value="62" />
98
+ </label>
99
+
100
+ <label class="fiber-slider fiber-polar">
101
+ <span>{ui.polarizer}</span>
102
+ <strong id="fiber-polar-label">-</strong>
103
+ <input id="fiber-polarizer" type="range" min="0" max="180" value="45" />
104
+ </label>
105
+
106
+ <div class="fiber-readouts">
107
+ <div>
108
+ <span>{ui.morphology}</span>
109
+ <strong id="fiber-morphology-score">-</strong>
110
+ </div>
111
+ <div>
112
+ <span>{ui.spectrum}</span>
113
+ <strong id="fiber-spectrum-score">-</strong>
114
+ </div>
115
+ <div>
116
+ <span>{ui.birefringence}</span>
117
+ <strong id="fiber-birefringence">-</strong>
118
+ </div>
119
+ </div>
120
+
121
+ <article class="fiber-verdict" id="fiber-verdict-panel" data-verdict="partial" aria-live="polite">
122
+ <div class="fiber-verdict-head">
123
+ <span id="fiber-verdict-status">-</span>
124
+ <strong id="fiber-verdict-score">-</strong>
125
+ </div>
126
+ <div class="fiber-verdict-meter" aria-hidden="true">
127
+ <span id="fiber-verdict-meter"></span>
128
+ </div>
129
+ <p id="fiber-verdict">-</p>
130
+ </article>
131
+ </aside>
132
+
133
+ <div class="fiber-chart" aria-label={ui.chartAria}>
134
+ <svg id="fiber-spectrum-chart" viewBox="0 0 720 270" role="img"></svg>
135
+ </div>
136
+
137
+ <p class="fiber-disclaimer">{ui.disclaimer}</p>
138
+ </div>
139
+ </section>
140
+
141
+ <script id="fiber-ui" type="application/json" set:html={JSON.stringify(ui)}></script>
142
+ <script>
143
+ import { initFiberComparisonMicroscope } from './view';
144
+
145
+ initFiberComparisonMicroscope(JSON.parse(document.getElementById('fiber-ui')?.textContent || '{}'));
146
+ </script>
@@ -0,0 +1,32 @@
1
+ import type { ScienceToolEntry, ToolLocaleContent } from '../../types';
2
+
3
+ export interface FiberComparisonMicroscopeUI {
4
+ [key: string]: string;
5
+ }
6
+
7
+ export type FiberComparisonMicroscopeLocaleContent = ToolLocaleContent<FiberComparisonMicroscopeUI>;
8
+
9
+ export const forensicFiberComparisonMicroscope: ScienceToolEntry<FiberComparisonMicroscopeUI> = {
10
+ id: 'forensic-fiber-comparison-microscope',
11
+ icons: {
12
+ bg: 'mdi:microscope',
13
+ fg: 'mdi:vector-polyline',
14
+ },
15
+ i18n: {
16
+ en: () => import('./i18n/en').then((m) => m.content),
17
+ de: () => import('./i18n/de').then((m) => m.content),
18
+ es: () => import('./i18n/es').then((m) => m.content),
19
+ fr: () => import('./i18n/fr').then((m) => m.content),
20
+ id: () => import('./i18n/id').then((m) => m.content),
21
+ it: () => import('./i18n/it').then((m) => m.content),
22
+ ja: () => import('./i18n/ja').then((m) => m.content),
23
+ ko: () => import('./i18n/ko').then((m) => m.content),
24
+ nl: () => import('./i18n/nl').then((m) => m.content),
25
+ pl: () => import('./i18n/pl').then((m) => m.content),
26
+ pt: () => import('./i18n/pt').then((m) => m.content),
27
+ ru: () => import('./i18n/ru').then((m) => m.content),
28
+ sv: () => import('./i18n/sv').then((m) => m.content),
29
+ tr: () => import('./i18n/tr').then((m) => m.content),
30
+ zh: () => import('./i18n/zh').then((m) => m.content),
31
+ },
32
+ };