code wiki / _hdl_build / nx_vizsla_dedup.nx
nx_vizsla_dedup.nx source
↩ module page · 460 lines · 18868 B
1// nx_vizsla_dedup.nx -- NISHI VIZSLA: DEDUP / MERGE (PRM/CRM depth). Operator 2026-06-23: real-system depth +
2// "import my linkedin my email my phone" -- imports from multiple sources create DUPLICATES of the same person.
3// A real CRM detects them and merges into one canonical contact WITHOUT losing data. This:
4// detect <prefix> <key> contacts sharing the same CURRENT value for <key> (e.g. email) =
5// duplicate candidates (>=2 distinct ids on one value).
6// merge <prefix> <survivor> <loser> <date> record a merge as an ADDITIVE "mrg:" record (rule 13:
7// NEVER deletes the loser -- history sacred, soft-merge, reversible).
8// canonical <prefix> <id> resolve the merge chain (transitive, latest-by-date) to the survivor.
9// view <prefix> <id> the UNIFIED profile: resolve to canonical, union the fields of the
10// survivor + every merged-in loser (latest-value-per-key wins).
11// Composes the fld: store (nx_vizsla_contact) for fields; mrg: records for the merge graph. Local, no cloud.
12// license_tier: ORIGINAL
13import "nx_syscalls.nx"
14import "nx_canon_cid.nx"
15import "nx_seg_store.nx"
16const K_MAGIC_1970: i64 = 1970
17const K_MAGIC_146097: i64 = 146097
18const K_MAGIC_719468: i64 = 719468
19const K_MAGIC_4096: i64 = 4096
20const K_MAGIC_1024: i64 = 1024
21const K_MAGIC_65536: i64 = 65536
22const K_MAGIC_2048: i64 = 2048
23
24func vd_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
25func vd_p(s: *u8) -> i64 { sys_write(1, s, vd_slen(s)); return 0 }
26
27func vd_eq(a: *u8, b: *u8) -> i64 {
28 var i: i64 = 0
29 var go: i64 = 1
30 while go == 1 { if a[i] != b[i] { return 0 } if a[i] == (0 as u8) { return 1 } i = i + 1 }
31 return 0
32}
33
34func vd_dup(s: *u8) -> *u8 {
35 let n: i64 = vd_slen(s)
36 let d: *u8 = sys_mmap(n + 2)
37 var i: i64 = 0
38 while i <= n { d[i] = s[i]; i = i + 1 }
39 return d
40}
41
42func vd_cpy(out: *u8, cap: i64, s: *u8) -> i64 {
43 var i: i64 = 0
44 while s[i] != (0 as u8) { if i < cap - 1 { out[i] = s[i] } i = i + 1 }
45 if i > cap - 1 { i = cap - 1 }
46 out[i] = 0 as u8
47 return i
48}
49
50func vd_cat(dst: *u8, off: i64, s: *u8) -> i64 {
51 var i: i64 = 0
52 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
53 return off + i
54}
55
56func vd_catn(dst: *u8, off: i64, v: i64) -> i64 {
57 var o: i64 = off
58 var m: i64 = v
59 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
60 let t: *u8 = sys_mmap(28)
61 var k: i64 = 0
62 if m == 0 { t[0] = 48 as u8; k = 1 }
63 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
64 var i: i64 = 0
65 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 }
66 return o + k
67}
68
69func vd_kmemeq(b: *u8, off: i64, n: i64, s: *u8) -> i64 {
70 if vd_slen(s) != n { return 0 }
71 var i: i64 = 0
72 while i < n { if b[off + i] != s[i] { return 0 } i = i + 1 }
73 return 1
74}
75
76func vd_iskind(b: *u8, koff: i64, kl: i64, pfx: *u8) -> i64 {
77 let pl: i64 = vd_slen(pfx)
78 if kl <= pl { return 0 }
79 return vd_kmemeq(b, koff, pl, pfx)
80}
81
82func vd_field(rec: *u8, rl: i64, want: *u8, out: *u8, cap: i64) -> i64 {
83 if rl < 8 { return 0 }
84 let nf: i64 = ss_r32(rec, 4)
85 var off: i64 = 8
86 var fi: i64 = 0
87 while fi < nf {
88 if off + 8 > rl { return 0 }
89 let kl: i64 = ss_r32(rec, off)
90 let koff: i64 = off + 4
91 let vl: i64 = ss_r32(rec, koff + kl)
92 let voff: i64 = koff + kl + 4
93 if vd_kmemeq(rec, koff, kl, want) == 1 {
94 var t: i64 = 0
95 while t < vl { if t < cap - 1 { out[t] = rec[voff + t] } t = t + 1 }
96 if t > cap - 1 { t = cap - 1 }
97 out[t] = 0 as u8
98 return 1
99 }
100 off = voff + vl
101 fi = fi + 1
102 }
103 return 0
104}
105
106func vd_datedays(s: *u8) -> i64 {
107 let nums: *i64 = sys_mmap(8 * 4) as *i64
108 var nn: i64 = 0
109 var cur: i64 = 0
110 var indig: i64 = 0
111 var i: i64 = 0
112 var go: i64 = 1
113 while go == 1 {
114 let c: i64 = s[i] as i64
115 var isd: i64 = 0
116 if c >= 48 { if c <= 57 { isd = 1 } }
117 if isd == 1 { cur = cur * 10 + (c - 48); indig = 1 }
118 if isd == 0 { if indig == 1 { if nn < 4 { nums[nn] = cur; nn = nn + 1 } cur = 0; indig = 0 } }
119 if c == 0 { go = 0 }
120 i = i + 1
121 }
122 if nn != 3 { return 0 - 1 }
123 var y: i64 = nums[0]
124 let m: i64 = nums[1]
125 let d: i64 = nums[2]
126 if y < K_MAGIC_1970 { return 0 - 1 }
127 if m < 1 { return 0 - 1 }
128 if m > 12 { return 0 - 1 }
129 if d < 1 { return 0 - 1 }
130 if d > 31 { return 0 - 1 }
131 if m <= 2 { y = y - 1 }
132 let era: i64 = y / 400
133 let yoe: i64 = y - era * 400
134 var mp: i64 = m - 3
135 if m <= 2 { mp = m + 9 }
136 let doy: i64 = (153 * mp + 2) / 5 + d - 1
137 let doe: i64 = yoe * 365 + yoe / 4 - yoe / 100 + doy
138 return era * K_MAGIC_146097 + doe - K_MAGIC_719468
139}
140
141// ----- fld: collection (composes nx_vizsla_contact's data plane) -----
142func vd_collect_fld(prefix: *u8, rct: *i64, rkey: *i64, rval: *i64, rdate: *i64) -> i64 {
143 var n: i64 = 0
144 let segs: *i64 = sys_mmap(8 * 260) as *i64
145 let nseg: i64 = ss_manifest(prefix, segs)
146 let fa: *u8 = sys_mmap(128)
147 let fb: *u8 = sys_mmap(128)
148 let fc: *u8 = sys_mmap(256)
149 let fdt: *u8 = sys_mmap(128)
150 var s: i64 = 0
151 while s < nseg {
152 let path: *u8 = sys_mmap(512)
153 var po: i64 = 0
154 po = vd_cat(path, po, prefix); po = vd_cat(path, po, segs[s] as *u8); po = vd_cat(path, po, ".docs" as *u8)
155 path[po] = 0 as u8
156 let szp: *i64 = sys_mmap(16) as *i64
157 let b: *u8 = ss_readall(path, szp)
158 let sz: i64 = szp[0]
159 var j: i64 = 0
160 while j + 9 <= sz {
161 let kind: i64 = b[j]
162 let kl: i64 = ss_r32(b, j + 1)
163 let koff: i64 = j + 5
164 let vl: i64 = ss_r32(b, koff + kl)
165 let voff: i64 = koff + kl + 4
166 var take: i64 = 0
167 if kind == 1 { take = vd_iskind(b, koff, kl, "fld:" as *u8) }
168 if take == 1 {
169 let rec: *u8 = (b as i64 + voff) as *u8
170 if vd_field(rec, vl, "contact" as *u8, fa, 128) == 1 {
171 vd_field(rec, vl, "key" as *u8, fb, 128)
172 vd_field(rec, vl, "value" as *u8, fc, 256)
173 vd_field(rec, vl, "date" as *u8, fdt, 128)
174 if n < K_MAGIC_4096 { rct[n] = vd_dup(fa) as i64; rkey[n] = vd_dup(fb) as i64; rval[n] = vd_dup(fc) as i64; rdate[n] = vd_datedays(fdt); n = n + 1 }
175 }
176 }
177 j = voff + vl
178 }
179 s = s + 1
180 }
181 return n
182}
183
184func vd_latest_fld(rct: *i64, rkey: *i64, rval: *i64, rdate: *i64, n: i64, contact: *u8, key: *u8, out: *u8, cap: i64) -> i64 {
185 var best: i64 = 0 - 1
186 var found: i64 = 0
187 var i: i64 = 0
188 while i < n {
189 if vd_eq(rct[i] as *u8, contact) == 1 { if vd_eq(rkey[i] as *u8, key) == 1 { if rdate[i] > best {
190 best = rdate[i]; vd_cpy(out, cap, rval[i] as *u8); found = 1
191 } } }
192 i = i + 1
193 }
194 return found
195}
196
197// ----- mrg: collection + chain resolution -----
198func vd_collect_mrg(prefix: *u8, ml: *i64, ms: *i64, md: *i64) -> i64 {
199 var n: i64 = 0
200 let segs: *i64 = sys_mmap(8 * 260) as *i64
201 let nseg: i64 = ss_manifest(prefix, segs)
202 let fl: *u8 = sys_mmap(128)
203 let fs: *u8 = sys_mmap(128)
204 let fdt: *u8 = sys_mmap(128)
205 var s: i64 = 0
206 while s < nseg {
207 let path: *u8 = sys_mmap(512)
208 var po: i64 = 0
209 po = vd_cat(path, po, prefix); po = vd_cat(path, po, segs[s] as *u8); po = vd_cat(path, po, ".docs" as *u8)
210 path[po] = 0 as u8
211 let szp: *i64 = sys_mmap(16) as *i64
212 let b: *u8 = ss_readall(path, szp)
213 let sz: i64 = szp[0]
214 var j: i64 = 0
215 while j + 9 <= sz {
216 let kind: i64 = b[j]
217 let kl: i64 = ss_r32(b, j + 1)
218 let koff: i64 = j + 5
219 let vl: i64 = ss_r32(b, koff + kl)
220 let voff: i64 = koff + kl + 4
221 var take: i64 = 0
222 if kind == 1 { take = vd_iskind(b, koff, kl, "mrg:" as *u8) }
223 if take == 1 {
224 let rec: *u8 = (b as i64 + voff) as *u8
225 if vd_field(rec, vl, "loser" as *u8, fl, 128) == 1 {
226 vd_field(rec, vl, "survivor" as *u8, fs, 128)
227 vd_field(rec, vl, "date" as *u8, fdt, 128)
228 if n < K_MAGIC_4096 { ml[n] = vd_dup(fl) as i64; ms[n] = vd_dup(fs) as i64; md[n] = vd_datedays(fdt); n = n + 1 }
229 }
230 }
231 j = voff + vl
232 }
233 s = s + 1
234 }
235 return n
236}
237
238// resolve id -> canonical survivor (transitive; latest-by-date per loser; cycle-guarded)
239func vd_canonical(ml: *i64, ms: *i64, md: *i64, m: i64, id: *u8, out: *u8, cap: i64) -> i64 {
240 let cur: *u8 = sys_mmap(256)
241 vd_cpy(cur, 256, id)
242 var iter: i64 = 0
243 var go: i64 = 1
244 while go == 1 {
245 var best: i64 = 0 - 1
246 var bsurv: i64 = 0
247 var i: i64 = 0
248 while i < m { if vd_eq(ml[i] as *u8, cur) == 1 { if md[i] > best { best = md[i]; bsurv = ms[i] } } i = i + 1 }
249 if best < 0 { go = 0 }
250 else {
251 vd_cpy(cur, 256, bsurv as *u8)
252 iter = iter + 1
253 if iter > 64 { go = 0 }
254 }
255 }
256 vd_cpy(out, cap, cur)
257 return 0
258}
259
260// ---------------- DETECT ----------------
261func vd_cmd_detect(argc: i64, argv: *i64) -> i64 {
262 if argc < 4 { vd_p("VIZSLA-DEDUP detect needs <prefix> <key> -- fail loud\n" as *u8); return 1 }
263 let prefix: *u8 = argv[2] as *u8
264 let key: *u8 = argv[3] as *u8
265 let rct: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
266 let rkey: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
267 let rval: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
268 let rdate: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
269 let n: i64 = vd_collect_fld(prefix, rct, rkey, rval, rdate)
270
271 // distinct contacts having <key>, with their latest value
272 let dc_id: *i64 = sys_mmap(8 * K_MAGIC_1024) as *i64
273 let dc_val: *i64 = sys_mmap(8 * K_MAGIC_1024) as *i64
274 var ndc: i64 = 0
275 let lv: *u8 = sys_mmap(256)
276 var i: i64 = 0
277 while i < n {
278 if vd_eq(rkey[i] as *u8, key) == 1 {
279 var dup: i64 = 0
280 var k: i64 = 0
281 while k < ndc { if vd_eq(dc_id[k] as *u8, rct[i] as *u8) == 1 { dup = 1; k = ndc } k = k + 1 }
282 if dup == 0 { vd_latest_fld(rct, rkey, rval, rdate, n, rct[i] as *u8, key, lv, 256); if ndc < K_MAGIC_1024 { dc_id[ndc] = rct[i]; dc_val[ndc] = vd_dup(lv) as i64; ndc = ndc + 1 } }
283 }
284 i = i + 1
285 }
286
287 // group by value -> emit groups with >=2 contacts
288 let vseen: *i64 = sys_mmap(8 * K_MAGIC_1024) as *i64
289 var nvs: i64 = 0
290 let rep: *u8 = sys_mmap(K_MAGIC_65536)
291 var o: i64 = 0
292 var cands: i64 = 0
293 var a: i64 = 0
294 while a < ndc {
295 var vdup: i64 = 0
296 var k: i64 = 0
297 while k < nvs { if vd_eq(vseen[k] as *u8, dc_val[a] as *u8) == 1 { vdup = 1; k = nvs } k = k + 1 }
298 if vdup == 0 {
299 if nvs < K_MAGIC_1024 { vseen[nvs] = dc_val[a]; nvs = nvs + 1 }
300 var cnt: i64 = 0
301 var b: i64 = 0
302 while b < ndc { if vd_eq(dc_val[b] as *u8, dc_val[a] as *u8) == 1 { cnt = cnt + 1 } b = b + 1 }
303 if cnt >= 2 {
304 o = vd_cat(rep, o, "VIZSLA-DEDUP-CANDIDATE key=" as *u8); o = vd_cat(rep, o, key)
305 o = vd_cat(rep, o, " value=" as *u8); o = vd_cat(rep, o, dc_val[a] as *u8)
306 o = vd_cat(rep, o, " count=" as *u8); o = vd_catn(rep, o, cnt)
307 o = vd_cat(rep, o, " contacts=" as *u8)
308 var first: i64 = 1
309 var c2: i64 = 0
310 while c2 < ndc {
311 if vd_eq(dc_val[c2] as *u8, dc_val[a] as *u8) == 1 { if first == 0 { o = vd_cat(rep, o, "," as *u8) } o = vd_cat(rep, o, dc_id[c2] as *u8); first = 0 }
312 c2 = c2 + 1
313 }
314 o = vd_cat(rep, o, "\n" as *u8)
315 cands = cands + 1
316 }
317 }
318 a = a + 1
319 }
320 o = vd_cat(rep, o, "VIZSLA-DEDUP-DETECT key=" as *u8); o = vd_cat(rep, o, key)
321 o = vd_cat(rep, o, " candidates=" as *u8); o = vd_catn(rep, o, cands); o = vd_cat(rep, o, "\n" as *u8)
322 sys_write(1, rep, o)
323 return 0
324}
325
326// ---------------- MERGE ----------------
327func vd_cmd_merge(argc: i64, argv: *i64) -> i64 {
328 if argc < 6 { vd_p("VIZSLA-DEDUP merge needs <prefix> <survivor> <loser> <date> -- fail loud\n" as *u8); return 1 }
329 let prefix: *u8 = argv[2] as *u8
330 let survivor: *u8 = argv[3] as *u8
331 let loser: *u8 = argv[4] as *u8
332 let date: *u8 = argv[5] as *u8
333 if vd_datedays(date) < 0 { vd_p("VIZSLA-DEDUP merge: bad date (YYYY-MM-DD) -- fail loud\n" as *u8); return 1 }
334 if vd_eq(survivor, loser) == 1 { vd_p("VIZSLA-DEDUP merge: survivor==loser refused -- fail loud\n" as *u8); return 1 }
335
336 let keys: *i64 = sys_mmap(8 * 8) as *i64
337 let vals: *i64 = sys_mmap(8 * 8) as *i64
338 keys[0] = "kind" as *u8 as i64; keys[1] = "loser" as *u8 as i64; keys[2] = "survivor" as *u8 as i64; keys[3] = "date" as *u8 as i64
339 vals[0] = "mrg" as *u8 as i64; vals[1] = loser as i64; vals[2] = survivor as i64; vals[3] = date as i64
340
341 let enc: *u8 = sys_mmap(K_MAGIC_2048)
342 let el: i64 = canon_encode(keys, vals, 4, enc)
343 let cid: *u8 = sys_mmap(96)
344 cid_of(enc, el, cid)
345 let kbuf: *u8 = sys_mmap(160)
346 var ko: i64 = 0
347 ko = vd_cat(kbuf, ko, "mrg:" as *u8); ko = vd_cat(kbuf, ko, cid); kbuf[ko] = 0 as u8
348
349 var new: i64 = 1
350 let pp: *i64 = sys_mmap(16) as *i64
351 let ll: *i64 = sys_mmap(16) as *i64
352 if ss_get_idx(prefix, kbuf, pp, ll) == 1 { new = 0 }
353 var committed: i64 = 0
354 let segid: i64 = sys_now_us()
355 if new == 1 {
356 let wr: *i64 = ss_begin()
357 if ss_add(wr, 1, kbuf, enc, el) != 0 { vd_p("VIZSLA-DEDUP merge: writer full -- fail loud\n" as *u8); return 1 }
358 if ss_commit(prefix, wr, segid) != 0 { vd_p("VIZSLA-DEDUP merge: commit FAILED -- fail loud\n" as *u8); return 1 }
359 committed = 1
360 }
361 let rep: *u8 = sys_mmap(K_MAGIC_1024)
362 var o: i64 = 0
363 o = vd_cat(rep, o, "VIZSLA-DEDUP-MERGE survivor=" as *u8); o = vd_cat(rep, o, survivor)
364 o = vd_cat(rep, o, " loser=" as *u8); o = vd_cat(rep, o, loser)
365 o = vd_cat(rep, o, " new=" as *u8); o = vd_catn(rep, o, new)
366 o = vd_cat(rep, o, " segment=" as *u8)
367 if committed == 1 { o = vd_cat(rep, o, "seg-" as *u8); o = vd_catn(rep, o, segid) } else { o = vd_cat(rep, o, "none" as *u8) }
368 o = vd_cat(rep, o, "\n" as *u8)
369 sys_write(1, rep, o)
370 return 0
371}
372
373// ---------------- CANONICAL ----------------
374func vd_cmd_canonical(argc: i64, argv: *i64) -> i64 {
375 if argc < 4 { vd_p("VIZSLA-DEDUP canonical needs <prefix> <id> -- fail loud\n" as *u8); return 1 }
376 let prefix: *u8 = argv[2] as *u8
377 let id: *u8 = argv[3] as *u8
378 let ml: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
379 let ms: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
380 let md: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
381 let m: i64 = vd_collect_mrg(prefix, ml, ms, md)
382 let c: *u8 = sys_mmap(256)
383 vd_canonical(ml, ms, md, m, id, c, 256)
384 let rep: *u8 = sys_mmap(K_MAGIC_1024)
385 var o: i64 = 0
386 o = vd_cat(rep, o, "VIZSLA-DEDUP-CANONICAL id=" as *u8); o = vd_cat(rep, o, id)
387 o = vd_cat(rep, o, " canonical=" as *u8); o = vd_cat(rep, o, c); o = vd_cat(rep, o, "\n" as *u8)
388 sys_write(1, rep, o)
389 return 0
390}
391
392// ---------------- VIEW (unified merged profile) ----------------
393func vd_cmd_view(argc: i64, argv: *i64) -> i64 {
394 if argc < 4 { vd_p("VIZSLA-DEDUP view needs <prefix> <id> -- fail loud\n" as *u8); return 1 }
395 let prefix: *u8 = argv[2] as *u8
396 let id: *u8 = argv[3] as *u8
397 let rct: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
398 let rkey: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
399 let rval: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
400 let rdate: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
401 let n: i64 = vd_collect_fld(prefix, rct, rkey, rval, rdate)
402 let ml: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
403 let ms: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
404 let md: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
405 let m: i64 = vd_collect_mrg(prefix, ml, ms, md)
406
407 let c: *u8 = sys_mmap(256)
408 vd_canonical(ml, ms, md, m, id, c, 256)
409
410 // precompute canonical of every fld record's contact
411 let rcanon: *i64 = sys_mmap(8 * K_MAGIC_4096) as *i64
412 var i: i64 = 0
413 while i < n {
414 let cc: *u8 = sys_mmap(256)
415 vd_canonical(ml, ms, md, m, rct[i] as *u8, cc, 256)
416 rcanon[i] = cc as i64
417 i = i + 1
418 }
419
420 // distinct keys among in-set records (canonical(contact)==c); latest value across the merge set
421 let emitted: *i64 = sys_mmap(8 * 512) as *i64
422 var ne: i64 = 0
423 let rep: *u8 = sys_mmap(K_MAGIC_65536)
424 var o: i64 = 0
425 var fields: i64 = 0
426 let bv: *u8 = sys_mmap(256)
427 var a: i64 = 0
428 while a < n {
429 var inset: i64 = 0
430 if vd_eq(rcanon[a] as *u8, c) == 1 { inset = 1 }
431 var done: i64 = 0
432 if inset == 1 { var k: i64 = 0; while k < ne { if vd_eq(emitted[k] as *u8, rkey[a] as *u8) == 1 { done = 1; k = ne } k = k + 1 } }
433 if inset == 1 { if done == 0 {
434 var best: i64 = 0 - 1
435 var b: i64 = 0
436 while b < n { if vd_eq(rcanon[b] as *u8, c) == 1 { if vd_eq(rkey[b] as *u8, rkey[a] as *u8) == 1 { if rdate[b] > best { best = rdate[b]; vd_cpy(bv, 256, rval[b] as *u8) } } } b = b + 1 }
437 o = vd_cat(rep, o, "VIZSLA-DEDUP-VIEW contact=" as *u8); o = vd_cat(rep, o, c)
438 o = vd_cat(rep, o, " key=" as *u8); o = vd_cat(rep, o, rkey[a] as *u8)
439 o = vd_cat(rep, o, " value=" as *u8); o = vd_cat(rep, o, bv); o = vd_cat(rep, o, "\n" as *u8)
440 if ne < 512 { emitted[ne] = rkey[a]; ne = ne + 1 }
441 fields = fields + 1
442 } }
443 a = a + 1
444 }
445 o = vd_cat(rep, o, "VIZSLA-DEDUP-VIEW-SUMMARY contact=" as *u8); o = vd_cat(rep, o, c)
446 o = vd_cat(rep, o, " fields=" as *u8); o = vd_catn(rep, o, fields); o = vd_cat(rep, o, "\n" as *u8)
447 sys_write(1, rep, o)
448 return 0
449}
450
451func main(argc: i64, argv: *i64) -> i64 {
452 if argc < 2 { vd_p("VIZSLA-DEDUP usage: detect|merge|canonical|view -- fail loud\n" as *u8); return 1 }
453 let cmd: *u8 = argv[1] as *u8
454 if vd_eq(cmd, "detect" as *u8) == 1 { return vd_cmd_detect(argc, argv) }
455 if vd_eq(cmd, "merge" as *u8) == 1 { return vd_cmd_merge(argc, argv) }
456 if vd_eq(cmd, "canonical" as *u8) == 1 { return vd_cmd_canonical(argc, argv) }
457 if vd_eq(cmd, "view" as *u8) == 1 { return vd_cmd_view(argc, argv) }
458 vd_p("VIZSLA-DEDUP unknown command (detect|merge|canonical|view) -- fail loud\n" as *u8)
459 return 1
460}