@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,235 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+
4
+ const slug = 'forensic-tlc-ink-simulator';
5
+ const title = '法医TLC墨水色谱模拟器';
6
+ const description = '模拟可疑书写墨水的薄层色谱分析,可视化溶剂前沿的展开,分离染料带,并计算每个色素的精确Rf值。';
7
+
8
+ const howTo = [
9
+ {
10
+ name: '选择可疑墨水或对比笔迹',
11
+ text: '选择勒索信墨水或候选笔型配置。每种墨水都含有不同的染料成分,对固定相的亲和力和极性各不相同。',
12
+ },
13
+ {
14
+ name: '选择移动相',
15
+ text: '改变溶剂系统以观察溶剂极性如何改变毛细展开以及各染料带的相对迁移。',
16
+ },
17
+ {
18
+ name: '展开TLC薄层板',
19
+ text: '移动展开时间滑块,观察溶剂前沿随薄层板上升,而分离的色带显示在原线之上。',
20
+ },
21
+ {
22
+ name: '读取Rf值表',
23
+ text: '比较每个色素距离与溶剂前沿距离。模拟器通过将色素距离除以溶剂前沿距离来计算Rf。',
24
+ },
25
+ ];
26
+
27
+ const faq = [
28
+ {
29
+ key: 'faq-1',
30
+ question: '薄层色谱中的Rf值是什么意思?',
31
+ answer: 'Rf是比移值(Retention factor):化合物迁移的距离除以溶剂前沿从同一原线迁移的距离。它是无量纲的,通常范围在0到1之间。',
32
+ },
33
+ {
34
+ key: 'faq-2',
35
+ question: 'TLC分析能否证明两个墨水样本来自同一支笔?',
36
+ answer: '不能。TLC可以显示染料分离图案是否一致,但来源判定需要经过验证的对比方法、对照样品、文书记录以及专家的综合解释。',
37
+ },
38
+ {
39
+ key: 'faq-3',
40
+ question: '为什么更换溶剂会改变色带图案?',
41
+ answer: '染料在固定相和移动相之间的分配行为不同。极性匹配更好的溶剂能将染料携带得更远,从而增加其Rf值。',
42
+ },
43
+ {
44
+ key: 'faq-4',
45
+ question: '为什么原线(起始线)很重要?',
46
+ answer: '溶剂前沿距离和色素迁移距离都必须从原线开始测量。从薄层板底部测量会导致错误的Rf值。',
47
+ },
48
+ ];
49
+
50
+ export const content: ToolLocaleContent = {
51
+ slug,
52
+ title,
53
+ description,
54
+ ui: {
55
+ chamberAria: '带有展开板的薄层色谱展开室',
56
+ rulerAria: '用于测量溶剂前沿和色素色带的虚拟毫米刻度尺',
57
+ rulerMarks: '80,60,40,20,0',
58
+ units: '单位制',
59
+ metric: '公制',
60
+ imperial: '英制',
61
+ unitMillimeter: '毫米',
62
+ unitInch: '英寸',
63
+ unitMinute: '分钟',
64
+ inkSample: '墨水样本',
65
+ ransomNote: '可疑勒索信墨水',
66
+ bluePen: '扣押的蓝色圆珠笔',
67
+ blackPen: '扣押的黑色圆珠笔',
68
+ gelPen: '扣押的中性笔',
69
+ solventSystem: '移动相',
70
+ ethanolWater: '乙醇 / 水',
71
+ butanolAcetic: '丁醇 / 乙酸',
72
+ isopropanolAmmonia: '异丙醇 / 氨水',
73
+ developmentTime: '展开时间',
74
+ frontDistance: '溶剂迁移路程',
75
+ matchScore: '图案相似度',
76
+ solventFront: '溶剂前沿',
77
+ originLine: '原线(起点)',
78
+ pigment: '色素带',
79
+ pigmentCyanDye: '青色染料',
80
+ pigmentVioletDye: '紫色染料',
81
+ pigmentGrayCarrier: '灰色载体',
82
+ pigmentNavyDye: '深蓝色染料',
83
+ pigmentYellowDye: '黄色染料',
84
+ pigmentRedDye: '红色染料',
85
+ pigmentBlueDye: '蓝色染料',
86
+ pigmentDarkBinder: '暗色粘合剂',
87
+ pigmentTealDye: '蓝绿色染料',
88
+ pigmentMagentaDye: '洋红色染料',
89
+ pigmentGelBinder: '凝胶粘合剂',
90
+ distance: '距离',
91
+ rfValue: 'Rf值',
92
+ disclaimer: '仅用于教学模拟。法医墨水对比需要原始文件、经验证的实验室方法、参考标准品以及合格的文书鉴定人员。',
93
+ },
94
+ seo: [
95
+ {
96
+ type: 'title',
97
+ text: '用于法医墨水对比的薄层色谱分析(TLC)',
98
+ level: 2,
99
+ },
100
+ {
101
+ type: 'diagnostic',
102
+ variant: 'info',
103
+ icon: 'mdi:test-tube',
104
+ badge: '教学模拟器',
105
+ title: '此TLC墨水模拟器如何帮助您理解色谱分析',
106
+ html: '本工具解释了<strong>书写墨水的薄层色谱分析</strong>如何将一条肉眼可见的墨水线分离成多个染料带。它专为法医学学生、文件鉴定初学者以及任何试图理解如何从已展开的TLC板计算Rf值的人而设计。',
107
+ },
108
+ {
109
+ type: 'stats',
110
+ columns: 4,
111
+ items: [
112
+ { value: 'Rf = d 谱带 / d 溶剂', label: '比移值(Rf)计算公式', icon: 'mdi:division' },
113
+ { value: '4', label: '对比的墨水配置文件', icon: 'mdi:pen' },
114
+ { value: '3', label: '模拟的移动相', icon: 'mdi:flask-outline' },
115
+ { value: '2', label: '公制与英制读数显示', icon: 'mdi:swap-horizontal' },
116
+ ],
117
+ },
118
+ {
119
+ type: 'summary',
120
+ title: '正确的TLC测量步骤清单',
121
+ items: [
122
+ 'In展开开始前,在溶剂液面之上标记好铅笔原线。',
123
+ '在溶剂到达顶端边缘前取出薄层板。',
124
+ '立即标记溶剂前沿,因为溶剂可能会蒸发或变得难以看清。',
125
+ '从同一条原线起测量色素迁移距离和溶剂迁移距离。',
126
+ '在报告Rf值时,请务必注明溶剂系统、薄层板类型、展开条件以及对照组。',
127
+ ],
128
+ },
129
+ {
130
+ type: 'comparative',
131
+ columns: 2,
132
+ items: [
133
+ {
134
+ title: 'TLC分析可以支持的结论',
135
+ icon: 'mdi:check-circle-outline',
136
+ highlight: true,
137
+ description: 'TLC可以显示可疑墨水和已知墨水在相同条件下是否具有相似的染料分离行为。',
138
+ points: ['筛查性对比', '染料图案可视化', 'Rf值文件记录', '选择用于确证性测试的样本'],
139
+ },
140
+ {
141
+ title: 'TLC单独不能证明的结论',
142
+ icon: 'mdi:alert-circle-outline',
143
+ description: '单独的TLC分析不能唯一识别某支笔、确定文件日期或证明书写人身份。',
144
+ points: ['不能实现唯一来源判定', '不能识别书写人', '默认不能得出墨水老化结论', '不能替代经验证的专业规程'],
145
+ },
146
+ ],
147
+ },
148
+ {
149
+ type: 'table',
150
+ headers: ['常见用户提问', '涉及的TLC概念', '审慎的解答'],
151
+ rows: [
152
+ ['如何计算Rf值?', '染料的距离除以溶剂前沿的距离。', '均从原线开始测量,然后相除。结果是无量纲的无单位数值。'],
153
+ ['为什么墨水会分裂成不同颜色?', '不同的染料对固定相和移动相具有不同的亲和力。', '单次书写笔画中可能包含多种迁移速率不同的着色剂。'],
154
+ ['两支笔可能会有相同的TLC色谱图案吗?', '会,相似的墨水配方会产生非常接近的分离图案。', '图案相似性仅能证明化学一致性,而非对某一特定笔的个体化识别。'],
155
+ ['为什么我的Rf值改变了?', '溶剂、薄层板、湿度、展开室饱和度、温度以及点样大小都会影响迁移。', 'Rf值只有在条件得到完全控制和记录的情况下才具有可比性。'],
156
+ ],
157
+ },
158
+ {
159
+ type: 'title',
160
+ text: '模拟器如何模拟分离过程',
161
+ level: 3,
162
+ },
163
+ {
164
+ type: 'paragraph',
165
+ html: '该模型将溶剂前沿的运动处理为随时间减速的毛细上升过程,同时根据两个简化的属性为每种染料分配Rf值:它对移动溶剂的亲和力以及它与所选移动相的极性匹配。这属于教学用简化模型,而非分析仪器级别的化学过程,但它保留了用户需要学习的核心物理关系:溶剂首先移动,染料在两相之间分配,然后从测得的迁移距离计算Rf。',
166
+ },
167
+ {
168
+ type: 'glossary',
169
+ items: [
170
+ { term: 'Stationary phase', definition: 'TLC薄层板上的涂层(通常为硅胶),它与化合物相互作用并减缓其运动。' },
171
+ { term: 'Mobile phase', definition: '在薄层板上上升并携带染料成分共同迁移的溶剂系统。' },
172
+ { term: 'Origin line', definition: '在展开前,将墨水样本点样到薄层板上时所画的铅笔线。' },
173
+ { term: 'Solvent front', definition: '在薄层板被取出之前,移动相上升到达的最高点。' },
174
+ { term: 'Rf value', definition: '比移值:化合物迁移距离除以溶剂前沿迁移距离所得的比值。' },
175
+ ],
176
+ },
177
+ {
178
+ type: 'tip',
179
+ title: '实际鉴定判读建议',
180
+ html: '在法医文书鉴定工作中,色谱图案"不匹配"特别有用,因为它可以直接排除某支候选笔的配方。而"匹配"的TLC色谱图论证力较弱:它仅说明样本在这些条件下具有化学一致性,并不意味着它们必然来自同一支笔。',
181
+ },
182
+ {
183
+ type: 'proscons',
184
+ title: 'TLC墨水对比的优势与局限性',
185
+ items: [
186
+ { pro: '对于分离墨水染料而言,快速、廉价且视觉直观。', con: '通常具有破坏性,因为必须从文件上提取微量样本。' },
187
+ { pro: 'Rf值为比较可疑样本和已知样本提供了一种结构化的方法。', con: '当溶剂、薄层板、湿度和展开条件发生变化时,Rf值会发生漂移。' },
188
+ { pro: '在进行更高级的分析之前,非常适合作为一种筛查方法。', con: '如果没有更广泛的证据支持,不能直接得出唯一的笔源结论。' },
189
+ ],
190
+ },
191
+ {
192
+ type: 'diagnostic',
193
+ variant: 'warning',
194
+ icon: 'mdi:scale-balance',
195
+ badge: '法医警示',
196
+ title: '切勿夸大墨水色谱分析的论证作用',
197
+ html: '浏览器模拟无法检查纸张、墨水年龄、提取化学过程、薄层板质量、污染或进行仪器确证。使用它来学习测量逻辑和解释限制,而在处理实际案件证据时,请完全依赖经过验证的专业法医文书检验鉴定方法。',
198
+ },
199
+ ],
200
+ faq,
201
+ bibliography,
202
+ howTo,
203
+ schemas: [
204
+ {
205
+ '@context': 'https://schema.org',
206
+ '@type': 'SoftwareApplication',
207
+ name: title,
208
+ description,
209
+ applicationCategory: 'ForensicApplication',
210
+ operatingSystem: 'Any',
211
+ },
212
+ {
213
+ '@context': 'https://schema.org',
214
+ '@type': 'FAQPage',
215
+ mainEntity: faq.map((item) => ({
216
+ '@type': 'Question',
217
+ name: item.question,
218
+ acceptedAnswer: {
219
+ '@type': 'Answer',
220
+ text: item.answer,
221
+ },
222
+ })),
223
+ },
224
+ {
225
+ '@context': 'https://schema.org',
226
+ '@type': 'HowTo',
227
+ name: title,
228
+ step: howTo.map((step) => ({
229
+ '@type': 'HowToStep',
230
+ name: step.name,
231
+ text: step.text,
232
+ })),
233
+ },
234
+ ],
235
+ };
@@ -0,0 +1,11 @@
1
+ import { forensicTlcInkSimulator } from './entry';
2
+ import type { ToolDefinition } from '../../types';
3
+
4
+ export * from './entry';
5
+
6
+ export const FORENSIC_TLC_INK_SIMULATOR_TOOL: ToolDefinition = {
7
+ entry: forensicTlcInkSimulator,
8
+ Component: () => import('./component.astro'),
9
+ SEOComponent: () => import('./seo.astro'),
10
+ BibliographyComponent: () => import('./bibliography.astro'),
11
+ };
@@ -0,0 +1,152 @@
1
+ export type SolventSystem = 'ethanolWater' | 'butanolAcetic' | 'isopropanolAmmonia';
2
+ export type InkSample = 'ransomNote' | 'bluePen' | 'blackPen' | 'gelPen';
3
+
4
+ export interface PigmentProfile {
5
+ id: string;
6
+ labelKey: string;
7
+ color: string;
8
+ affinity: number;
9
+ polarity: number;
10
+ }
11
+
12
+ export interface InkProfile {
13
+ id: InkSample;
14
+ pigments: PigmentProfile[];
15
+ }
16
+
17
+ export interface SolventProfile {
18
+ id: SolventSystem;
19
+ polarityPower: number;
20
+ capillaryRate: number;
21
+ }
22
+
23
+ export interface TlcBand {
24
+ id: string;
25
+ labelKey: string;
26
+ color: string;
27
+ distanceMm: number;
28
+ rf: number;
29
+ widthMm: number;
30
+ }
31
+
32
+ export interface TlcSimulation {
33
+ timeMinutes: number;
34
+ solventFrontMm: number;
35
+ plateHeightMm: number;
36
+ originMm: number;
37
+ solvent: SolventProfile;
38
+ ink: InkProfile;
39
+ bands: TlcBand[];
40
+ matchScore: number;
41
+ }
42
+
43
+ export const SOLVENTS: Record<SolventSystem, SolventProfile> = {
44
+ ethanolWater: {
45
+ id: 'ethanolWater',
46
+ polarityPower: 0.62,
47
+ capillaryRate: 23,
48
+ },
49
+ butanolAcetic: {
50
+ id: 'butanolAcetic',
51
+ polarityPower: 0.78,
52
+ capillaryRate: 18,
53
+ },
54
+ isopropanolAmmonia: {
55
+ id: 'isopropanolAmmonia',
56
+ polarityPower: 0.88,
57
+ capillaryRate: 21,
58
+ },
59
+ };
60
+
61
+ export const INKS: Record<InkSample, InkProfile> = {
62
+ ransomNote: {
63
+ id: 'ransomNote',
64
+ pigments: [
65
+ { id: 'r-blue', labelKey: 'pigmentCyanDye', color: '#0ea5e9', affinity: 0.72, polarity: 0.68 },
66
+ { id: 'r-violet', labelKey: 'pigmentVioletDye', color: '#8b5cf6', affinity: 0.54, polarity: 0.74 },
67
+ { id: 'r-gray', labelKey: 'pigmentGrayCarrier', color: '#475569', affinity: 0.31, polarity: 0.42 },
68
+ ],
69
+ },
70
+ bluePen: {
71
+ id: 'bluePen',
72
+ pigments: [
73
+ { id: 'b-cyan', labelKey: 'pigmentCyanDye', color: '#0284c7', affinity: 0.71, polarity: 0.66 },
74
+ { id: 'b-violet', labelKey: 'pigmentVioletDye', color: '#7c3aed', affinity: 0.55, polarity: 0.72 },
75
+ { id: 'b-navy', labelKey: 'pigmentNavyDye', color: '#1e3a8a', affinity: 0.36, polarity: 0.5 },
76
+ ],
77
+ },
78
+ blackPen: {
79
+ id: 'blackPen',
80
+ pigments: [
81
+ { id: 'k-yellow', labelKey: 'pigmentYellowDye', color: '#eab308', affinity: 0.83, polarity: 0.58 },
82
+ { id: 'k-red', labelKey: 'pigmentRedDye', color: '#dc2626', affinity: 0.58, polarity: 0.64 },
83
+ { id: 'k-blue', labelKey: 'pigmentBlueDye', color: '#2563eb', affinity: 0.42, polarity: 0.71 },
84
+ { id: 'k-carbon', labelKey: 'pigmentDarkBinder', color: '#111827', affinity: 0.18, polarity: 0.32 },
85
+ ],
86
+ },
87
+ gelPen: {
88
+ id: 'gelPen',
89
+ pigments: [
90
+ { id: 'g-teal', labelKey: 'pigmentTealDye', color: '#14b8a6', affinity: 0.66, polarity: 0.75 },
91
+ { id: 'g-magenta', labelKey: 'pigmentMagentaDye', color: '#db2777', affinity: 0.49, polarity: 0.8 },
92
+ { id: 'g-black', labelKey: 'pigmentGelBinder', color: '#334155', affinity: 0.22, polarity: 0.38 },
93
+ ],
94
+ },
95
+ };
96
+
97
+ function clamp(value: number, min: number, max: number): number {
98
+ return Math.max(min, Math.min(max, value));
99
+ }
100
+
101
+ export class ChromatographyPhysics {
102
+ private readonly plateHeightMm = 80;
103
+ private readonly originMm = 8;
104
+
105
+ simulate(timeMinutes: number, inkSample: InkSample, solventSystem: SolventSystem): TlcSimulation {
106
+ const ink = INKS[inkSample] ?? INKS.ransomNote;
107
+ const solvent = SOLVENTS[solventSystem] ?? SOLVENTS.ethanolWater;
108
+ const usableHeight = this.plateHeightMm - this.originMm - 7;
109
+ const solventFrontMm = this.originMm + clamp(Math.sqrt(timeMinutes) * solvent.capillaryRate, 8, usableHeight);
110
+ const travelMm = solventFrontMm - this.originMm;
111
+ const bands = ink.pigments.map((pigment, index) => {
112
+ const polarityFit = 1 - Math.abs(pigment.polarity - solvent.polarityPower);
113
+ const rf = clamp((pigment.affinity * 0.72) + (polarityFit * 0.24) - (index * 0.025), 0.08, 0.94);
114
+ const distanceMm = travelMm * rf;
115
+
116
+ return {
117
+ id: pigment.id,
118
+ labelKey: pigment.labelKey,
119
+ color: pigment.color,
120
+ distanceMm: Number(distanceMm.toFixed(1)),
121
+ rf: Number(rf.toFixed(2)),
122
+ widthMm: Number((3.6 + (1 - polarityFit) * 5).toFixed(1)),
123
+ };
124
+ });
125
+
126
+ return {
127
+ timeMinutes,
128
+ solventFrontMm: Number(solventFrontMm.toFixed(1)),
129
+ plateHeightMm: this.plateHeightMm,
130
+ originMm: this.originMm,
131
+ solvent,
132
+ ink,
133
+ bands,
134
+ matchScore: this.compareToRansomPattern(bands, solventFrontMm - this.originMm),
135
+ };
136
+ }
137
+
138
+ private compareToRansomPattern(bands: TlcBand[], solventTravelMm: number): number {
139
+ const reference = INKS.ransomNote.pigments.map((pigment) => pigment.affinity).sort((a, b) => a - b);
140
+ const observed = bands.map((band) => band.distanceMm / solventTravelMm).sort((a, b) => a - b);
141
+ const comparisons = Math.min(reference.length, observed.length);
142
+ let penalty = Math.abs(reference.length - observed.length) * 18;
143
+
144
+ for (let index = 0; index < comparisons; index++) {
145
+ const refVal = reference[index] ?? 0;
146
+ const obsVal = observed[index] ?? 0;
147
+ penalty += Math.abs(refVal - obsVal) * 100;
148
+ }
149
+
150
+ return Math.round(clamp(100 - penalty, 0, 100));
151
+ }
152
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { forensicTlcInkSimulator } 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 forensicTlcInkSimulator.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: 'Di Maio, V. J. M. Gunshot Wounds: Practical Aspects of Firearms, Ballistics, and Forensic Techniques.',
6
+ url: 'https://ia800508.us.archive.org/3/items/Gunshot_Wounds_Practical_Aspects_Of_Firearms_Ballistics_Forensic_Techniques/Gunshot_Wounds_Practical_Aspects_Of_Firearms_Ballistics__Forensic_Techniques.pdf',
7
+ },
8
+ {
9
+ name: 'ASTM E1588 - Standard Practice for Gunshot Residue Analysis by Scanning Electron Microscopy/Energy Dispersive X-Ray Spectrometry.',
10
+ url: 'https://www.nist.gov/system/files/documents/2020/03/20/OSAC%20GSR%20SC%20E1588%20for%20SAC.pdf',
11
+ },
12
+ {
13
+ name: 'National Institute of Justice. Firearms Examiner Training: Gunshot Residue Distance Determination.',
14
+ url: 'https://nij.ojp.gov/nij-hosted-online-training-courses/firearms-examiner-training/module-12',
15
+ },
16
+ ];