cry-vetzdravila 1.0.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.
- package/.claude/settings.local.json +17 -0
- package/CLAUDE.md +82 -0
- package/LICENSE.md +16 -0
- package/README.md +376 -0
- package/a.txt +1643 -0
- package/bun.lock +197 -0
- package/dist/atcvet/opisATCvetKode.d.ts +23 -0
- package/dist/atcvet/podatkiATCvetKode.d.ts +20 -0
- package/dist/atcvet/pomeniNivojevATCvet.d.ts +1 -0
- package/dist/atcvet/types/AtcvetFile.d.ts +19 -0
- package/dist/generated/AtcVet.d.ts +9 -0
- package/dist/generated/RegisterZdravil.d.ts +8 -0
- package/dist/generated/seznamZdravil.d.ts +8 -0
- package/dist/index.d.ts +244 -0
- package/dist/index.js +141786 -0
- package/dist/register/MIN_OCENA_PODOBNOSTI.d.ts +2 -0
- package/dist/register/helper/normalizirajNaziv.d.ts +176 -0
- package/dist/register/helper/oblikujRezultatIskanja.d.ts +8 -0
- package/dist/register/helper/oceniPodobnost.d.ts +37 -0
- package/dist/register/helper/poisciZivalskoVrsto.d.ts +33 -0
- package/dist/register/helper/razcleniNaziv.d.ts +2 -0
- package/dist/register/podobnaZdravilaPoATC.d.ts +16 -0
- package/dist/register/podobnaZdravilaPoUcinkovinah.d.ts +18 -0
- package/dist/register/registerZdravil.d.ts +9 -0
- package/dist/register/types/KarencaZdravila.d.ts +24 -0
- package/dist/register/types/PotUporabeZdravila.d.ts +21 -0
- package/dist/register/types/RazclembaZdravila.d.ts +9 -0
- package/dist/register/types/RegisterZdravil.d.ts +2 -0
- package/dist/register/types/UcinkovinaZdravila.d.ts +20 -0
- package/dist/register/types/Zdravilo.d.ts +65 -0
- package/dist/register/types/ZdraviloZUtemeljitvijo.d.ts +9 -0
- package/dist/register/types/ZivalskeVrste.d.ts +158 -0
- package/dist/register/uganiZdravilo.d.ts +43 -0
- package/dist/register/zdravilaZaAtcVetKodo.d.ts +8 -0
- package/dist/register/zdraviloJeVakcinaZa.d.ts +18 -0
- package/docs/vakcine.md +195 -0
- package/package.json +39 -0
- package/src/atcvet/CLAUDE.md +18 -0
- package/src/atcvet/downloadLatestAtcvetPdf.ts +107 -0
- package/src/atcvet/opisATCvetKode.ts +116 -0
- package/src/atcvet/parseAtcvetPdf.ts +215 -0
- package/src/atcvet/podatkiATCvetKode.ts +34 -0
- package/src/atcvet/pomeniNivojevATCvet.ts +8 -0
- package/src/atcvet/types/AtcvetFile.ts +22 -0
- package/src/generate.ts +111 -0
- package/src/generated/AtcVet.ts +56704 -0
- package/src/generated/seznamZdravil.ts +44833 -0
- package/src/importParseAndBuildAll.ts +97 -0
- package/src/index.ts +289 -0
- package/src/interactive.ts +428 -0
- package/src/register/CLAUDE.md +230 -0
- package/src/register/MIN_OCENA_PODOBNOSTI.ts +3 -0
- package/src/register/downloadRegister.ts +148 -0
- package/src/register/helper/analizaVakcin.ts +90 -0
- package/src/register/helper/checkVrste.ts +72 -0
- package/src/register/helper/hashString.ts +27 -0
- package/src/register/helper/normalizirajNaziv.ts +493 -0
- package/src/register/helper/oblikujRezultatIskanja.ts +15 -0
- package/src/register/helper/oceniPodobnost.ts +194 -0
- package/src/register/helper/poisciZivalskoVrsto.ts +100 -0
- package/src/register/helper/razcleniNaziv.ts +105 -0
- package/src/register/helper/testNormalizacije.ts +89 -0
- package/src/register/helper/testPodobnosti.ts +238 -0
- package/src/register/helper/testVakcin.ts +103 -0
- package/src/register/parseRegister.ts +464 -0
- package/src/register/podobnaZdravilaPoATC.ts +71 -0
- package/src/register/podobnaZdravilaPoUcinkovinah.ts +136 -0
- package/src/register/registerZdravil.ts +22 -0
- package/src/register/stats.ts +114 -0
- package/src/register/types/KarencaZdravila.ts +26 -0
- package/src/register/types/PotUporabeZdravila.ts +21 -0
- package/src/register/types/RazclembaZdravila.ts +10 -0
- package/src/register/types/RegisterRaw.ts +23 -0
- package/src/register/types/RegisterZdravil.ts +3 -0
- package/src/register/types/UcinkovinaZdravila.ts +21 -0
- package/src/register/types/Zdravilo.ts +84 -0
- package/src/register/types/ZdraviloZUtemeljitvijo.ts +11 -0
- package/src/register/types/ZivalskeVrste.ts +7 -0
- package/src/register/uganiZdravilo.ts +142 -0
- package/src/register/zdravilaZaAtcVetKodo.ts +28 -0
- package/src/register/zdraviloJeVakcinaZa.ts +202 -0
- package/src/test/testPodobnosti.test.ts +126 -0
- package/src/test/zdravila.json +38693 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prenos xlsx datoteke s seznamom veterinarskih zdravil iz JAZMP
|
|
3
|
+
*
|
|
4
|
+
* Funkcija poišče najnovejšo xlsx datoteko na spletni strani in jo prenese v mapo data.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const BASE_URL = "https://www.jazmp.si/veterinarska-zdravila/podatki-o-zdravilih/seznam-zdravil";
|
|
8
|
+
const HREF_PREFIX = "https://www.jazmp.si/fileadmin/datoteke/seznami/SRZV";
|
|
9
|
+
const DATA_DIR = "./data";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Iz HTML vsebine poišče vse href atribute, ki se začnejo z HREF_PREFIX
|
|
13
|
+
*/
|
|
14
|
+
function findXlsxLinks(html: string): string[] {
|
|
15
|
+
const links: string[] = [];
|
|
16
|
+
// Poišči vse <a> elemente s href atributom
|
|
17
|
+
const hrefRegex = /href=["']([^"']*?)["']/gi;
|
|
18
|
+
let match;
|
|
19
|
+
|
|
20
|
+
while ((match = hrefRegex.exec(html)) !== null) {
|
|
21
|
+
const href = match[1];
|
|
22
|
+
if (href.startsWith(HREF_PREFIX) && href.endsWith(".xlsx")) {
|
|
23
|
+
links.push(href);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return links;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Iz URL-ja izlušči datum in ga pretvori v Date objekt
|
|
32
|
+
* Primer URL: https://www.jazmp.si/fileadmin/datoteke/seznami/SRZV/20-11-2025.xlsx
|
|
33
|
+
* Vrne: Date objekt za 20. november 2025
|
|
34
|
+
*/
|
|
35
|
+
function extractDateFromUrl(url: string): Date | null {
|
|
36
|
+
const filename = url.split("/").pop();
|
|
37
|
+
if (!filename) return null;
|
|
38
|
+
|
|
39
|
+
// Format: DD-MM-YYYY.xlsx
|
|
40
|
+
const dateMatch = filename.match(/(\d{1,2})-(\d{1,2})-(\d{4})\.xlsx/);
|
|
41
|
+
if (!dateMatch) return null;
|
|
42
|
+
|
|
43
|
+
const [, day, month, year] = dateMatch;
|
|
44
|
+
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Poišče najnovejšo xlsx datoteko med podanimi linki
|
|
49
|
+
*/
|
|
50
|
+
function findNewestLink(links: string[]): string | null {
|
|
51
|
+
if (links.length === 0) return null;
|
|
52
|
+
|
|
53
|
+
let newestLink = links[0];
|
|
54
|
+
let newestDate = extractDateFromUrl(links[0]);
|
|
55
|
+
|
|
56
|
+
for (const link of links) {
|
|
57
|
+
const date = extractDateFromUrl(link);
|
|
58
|
+
if (date && newestDate && date > newestDate) {
|
|
59
|
+
newestDate = date;
|
|
60
|
+
newestLink = link;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return newestLink;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Prenese xlsx datoteko in jo shrani v data mapo
|
|
69
|
+
*/
|
|
70
|
+
async function downloadFile(url: string): Promise<string> {
|
|
71
|
+
const response = await fetch(url);
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`Napaka pri prenosu datoteke: ${response.status} ${response.statusText}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
77
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
78
|
+
|
|
79
|
+
// Shrani vedno kot register.xlsx
|
|
80
|
+
const filepath = `${DATA_DIR}/register.xlsx`;
|
|
81
|
+
|
|
82
|
+
await Bun.write(filepath, buffer);
|
|
83
|
+
|
|
84
|
+
return filepath;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Glavna funkcija - prenese najnovejšo xlsx datoteko s JAZMP spletne strani
|
|
89
|
+
*/
|
|
90
|
+
export async function downloadRegister(): Promise<string> {
|
|
91
|
+
console.log("Pridobivam HTML iz JAZMP...");
|
|
92
|
+
|
|
93
|
+
// Prenesi HTML strani
|
|
94
|
+
const response = await fetch(BASE_URL);
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`Napaka pri dostopu do spletne strani: ${response.status}`);
|
|
97
|
+
}
|
|
98
|
+
const html = await response.text();
|
|
99
|
+
|
|
100
|
+
// Poišči vse xlsx linke
|
|
101
|
+
console.log("Iščem xlsx povezave...");
|
|
102
|
+
const links = findXlsxLinks(html);
|
|
103
|
+
|
|
104
|
+
if (links.length === 0) {
|
|
105
|
+
throw new Error("Ni najdenih xlsx datotek na spletni strani");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.log(`Najdenih ${links.length} xlsx datotek`);
|
|
109
|
+
|
|
110
|
+
// Poišči najnovejšo
|
|
111
|
+
const newestLink = findNewestLink(links);
|
|
112
|
+
if (!newestLink) {
|
|
113
|
+
throw new Error("Ni mogoče določiti najnovejše datoteke");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log(`Najnovejša datoteka: ${newestLink}`);
|
|
117
|
+
|
|
118
|
+
// Prenesi datoteko
|
|
119
|
+
console.log("Prenašam datoteko...");
|
|
120
|
+
const filepath = await downloadFile(newestLink);
|
|
121
|
+
|
|
122
|
+
console.log(`Datoteka uspešno prenesena: ${filepath}`);
|
|
123
|
+
|
|
124
|
+
return filepath;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Vrne pot do register.xlsx če obstaja
|
|
129
|
+
*/
|
|
130
|
+
export async function getLatestLocalFile(): Promise<string | null> {
|
|
131
|
+
const filepath = `${DATA_DIR}/register.xlsx`;
|
|
132
|
+
const file = Bun.file(filepath);
|
|
133
|
+
if (await file.exists()) {
|
|
134
|
+
return filepath;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Če se izvaja direktno
|
|
140
|
+
if (import.meta.main) {
|
|
141
|
+
try {
|
|
142
|
+
const filepath = await downloadRegister();
|
|
143
|
+
console.log(`\nUspeh! Datoteka shranjena: ${filepath}`);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error("Napaka:", error);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analiza vakcin v registru
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { parseRegister } from "../parseRegister";
|
|
6
|
+
|
|
7
|
+
const register = parseRegister("./data/register.xlsx");
|
|
8
|
+
|
|
9
|
+
// Poišči ATC kode za vakcine (začnejo z QI)
|
|
10
|
+
const vakcine = register.zdravila.filter((z) => z.atcKoda?.startsWith("QI"));
|
|
11
|
+
|
|
12
|
+
console.log("Skupno število vakcin:", vakcine.length);
|
|
13
|
+
|
|
14
|
+
// Razvrsti po ATC kodi
|
|
15
|
+
const poATC = new Map<string, typeof vakcine>();
|
|
16
|
+
for (const z of vakcine) {
|
|
17
|
+
const atc = z.atcKoda?.substring(0, 5) || "neznano";
|
|
18
|
+
if (!poATC.has(atc)) poATC.set(atc, []);
|
|
19
|
+
poATC.get(atc)!.push(z);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log("\nVakcine po ATC kodah:");
|
|
23
|
+
for (const [atc, zdravila] of [...poATC.entries()].sort()) {
|
|
24
|
+
console.log("");
|
|
25
|
+
console.log(atc + " (" + zdravila.length + " zdravil):");
|
|
26
|
+
for (const z of zdravila.slice(0, 3)) {
|
|
27
|
+
console.log(" -", z.ime.substring(0, 70));
|
|
28
|
+
}
|
|
29
|
+
if (zdravila.length > 3) console.log(" ... in še", zdravila.length - 3);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Poišči vakcine proti steklini
|
|
33
|
+
console.log("\n\n=== VAKCINE PROTI STEKLINI ===");
|
|
34
|
+
const steklina = vakcine.filter((z) => {
|
|
35
|
+
const imeLower = z.ime.toLowerCase();
|
|
36
|
+
const ucinkovineLower = z.ucinkovine?.map((u) => u.ucinkovina.toLowerCase()).join(" ") || "";
|
|
37
|
+
return (
|
|
38
|
+
imeLower.includes("rabies") ||
|
|
39
|
+
imeLower.includes("stekl") ||
|
|
40
|
+
ucinkovineLower.includes("rabies") ||
|
|
41
|
+
ucinkovineLower.includes("stekl")
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
for (const z of steklina) {
|
|
45
|
+
console.log("-", z.ime);
|
|
46
|
+
console.log(" ATC:", z.atcKoda);
|
|
47
|
+
console.log(" Učinkovine:", z.ucinkovine?.map((u) => u.ucinkovina).join(", "));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Poišči vakcine proti leptospirozi
|
|
51
|
+
console.log("\n\n=== VAKCINE PROTI LEPTOSPIROZI ===");
|
|
52
|
+
const leptospiroza = vakcine.filter((z) => {
|
|
53
|
+
const imeLower = z.ime.toLowerCase();
|
|
54
|
+
const ucinkovineLower = z.ucinkovine?.map((u) => u.ucinkovina.toLowerCase()).join(" ") || "";
|
|
55
|
+
return imeLower.includes("lept") || ucinkovineLower.includes("leptospir");
|
|
56
|
+
});
|
|
57
|
+
for (const z of leptospiroza) {
|
|
58
|
+
console.log("-", z.ime);
|
|
59
|
+
console.log(" ATC:", z.atcKoda);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Poišči vakcine proti kužnim boleznim (pasja kuga, parvo, hepatitis)
|
|
63
|
+
console.log("\n\n=== VAKCINE PROTI KUŽNIM BOLEZNIM (psi) ===");
|
|
64
|
+
const kuzne = vakcine.filter((z) => {
|
|
65
|
+
const imeLower = z.ime.toLowerCase();
|
|
66
|
+
const ucinkovineLower = z.ucinkovine?.map((u) => u.ucinkovina.toLowerCase()).join(" ") || "";
|
|
67
|
+
return (
|
|
68
|
+
imeLower.includes("dhpp") ||
|
|
69
|
+
imeLower.includes("distemper") ||
|
|
70
|
+
ucinkovineLower.includes("pasje kuge") ||
|
|
71
|
+
ucinkovineLower.includes("parvo") ||
|
|
72
|
+
ucinkovineLower.includes("adenovirus")
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
for (const z of kuzne) {
|
|
76
|
+
console.log("-", z.ime);
|
|
77
|
+
console.log(" ATC:", z.atcKoda);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Statistika ATC kod
|
|
81
|
+
console.log("\n\n=== LEGENDA ATC KOD ZA VAKCINE ===");
|
|
82
|
+
console.log("QI01 - Vakcine za ptice (perutnina)");
|
|
83
|
+
console.log("QI02 - Vakcine za govedo");
|
|
84
|
+
console.log("QI04 - Vakcine za ovce in koze");
|
|
85
|
+
console.log("QI05 - Vakcine za prašiče");
|
|
86
|
+
console.log("QI06 - Vakcine za konje");
|
|
87
|
+
console.log("QI07 - Vakcine za pse");
|
|
88
|
+
console.log("QI08 - Vakcine za mačke");
|
|
89
|
+
console.log("QI09 - Vakcine za več vrst");
|
|
90
|
+
console.log("QI20 - Druge vakcine");
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preveri katere vrste iz karenc nimajo zadetka v _match
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { skupneEntitete } from "cry-klikvet-logic";
|
|
6
|
+
import { parseRegister } from "../parseRegister";
|
|
7
|
+
|
|
8
|
+
const ZivalskeVrste = skupneEntitete.vrsteZivali;
|
|
9
|
+
|
|
10
|
+
// Dodatni vzorci iz parseRegister
|
|
11
|
+
const DODATNI_VZORCI_VRST: [RegExp, string][] = [
|
|
12
|
+
[/krav|telic|molznic/i, "govedo"],
|
|
13
|
+
[/race|brojler|jarki|mladic|fazan|prepelic|jerebic/i, "perutnina"],
|
|
14
|
+
[/osl[ie]|ponij/i, "konji"],
|
|
15
|
+
[/postrv/i, "ribe"],
|
|
16
|
+
[/^mačke$/i, "mačke"],
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const register = parseRegister("./data/register.xlsx");
|
|
20
|
+
|
|
21
|
+
// Zberi vse unikatne vrste iz karenc
|
|
22
|
+
const vrsteVKarencah = new Set<string>();
|
|
23
|
+
for (const z of register.zdravila) {
|
|
24
|
+
for (const k of z.karence) {
|
|
25
|
+
vrsteVKarencah.add(String(k.vrsta).toLowerCase());
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function findMatch(vrsta: string): { key: string; nadrejena: string | null } | null {
|
|
30
|
+
// 1. Poskusi z _match
|
|
31
|
+
for (const [key, vrstaDef] of Object.entries(ZivalskeVrste)) {
|
|
32
|
+
if (vrstaDef?._match?.test(vrsta)) {
|
|
33
|
+
const nadrejena = vrstaDef.vrsta !== key ? vrstaDef.vrsta : null;
|
|
34
|
+
return { key, nadrejena };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. Poskusi z dodatnimi vzorci
|
|
39
|
+
for (const [pattern, nadrejena] of DODATNI_VZORCI_VRST) {
|
|
40
|
+
if (pattern.test(vrsta)) {
|
|
41
|
+
return { key: vrsta, nadrejena: vrsta !== nadrejena.toLowerCase() ? nadrejena : null };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log("=== VRSTE BREZ ZADETKA ===\n");
|
|
49
|
+
|
|
50
|
+
const brezZadetka: string[] = [];
|
|
51
|
+
for (const vrsta of vrsteVKarencah) {
|
|
52
|
+
const match = findMatch(vrsta);
|
|
53
|
+
if (!match) {
|
|
54
|
+
brezZadetka.push(vrsta);
|
|
55
|
+
console.log(`${vrsta} → NI ZADETKA`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log("\n=== VRSTE Z ZADETKOM ===\n");
|
|
60
|
+
|
|
61
|
+
for (const vrsta of vrsteVKarencah) {
|
|
62
|
+
const match = findMatch(vrsta);
|
|
63
|
+
if (match) {
|
|
64
|
+
console.log(`${vrsta} → ${match.key}` + (match.nadrejena ? ` (nadrejena: ${match.nadrejena})` : ""));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(`\n=== POVZETEK ===`);
|
|
69
|
+
console.log(`Vrst brez zadetka: ${brezZadetka.length}`);
|
|
70
|
+
if (brezZadetka.length > 0) {
|
|
71
|
+
console.log(`Manjkajoče: ${brezZadetka.join(", ")}`);
|
|
72
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fast, high-specificity 32-bit hash (xxHash32-style avalanche) -> unsigned number
|
|
3
|
+
* If !text returns undefined
|
|
4
|
+
**/
|
|
5
|
+
export function hashString(text: string | undefined): number | undefined {
|
|
6
|
+
|
|
7
|
+
if (!text) return undefined;
|
|
8
|
+
|
|
9
|
+
let h = 0x9e3779b1 ^ text.length; // seed mixed with length
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < text.length; i++) {
|
|
12
|
+
h ^= text.charCodeAt(i);
|
|
13
|
+
// h *= 0x85ebca6b (done via Math.imul for 32-bit overflow semantics)
|
|
14
|
+
h = Math.imul(h, 0x85ebca6b);
|
|
15
|
+
// rotate left 13
|
|
16
|
+
h = (h << 13) | (h >>> 19);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// final avalanche (fmix32-like)
|
|
20
|
+
h ^= h >>> 16;
|
|
21
|
+
h = Math.imul(h, 0x7feb352d);
|
|
22
|
+
h ^= h >>> 15;
|
|
23
|
+
h = Math.imul(h, 0x846ca68b);
|
|
24
|
+
h ^= h >>> 16;
|
|
25
|
+
|
|
26
|
+
return h >>> 0; // 0 .. 4294967295
|
|
27
|
+
}
|