code wiki / _hdl_build / nx_meshpose.nx
nx_meshpose.nx source
↩ module page · 419 lines · 18090 B
1// nx_meshpose.nx -- THE POSE-MATCH INSTRUMENT (form ladder 1785935557; measured rung 2026-08-05:
2// the per-part table showed error growing MONOTONICALLY along each kinematic chain -- shoulder 10mm
3// to fingertips 357mm -- the signature of pose mismatch about the joint, not form error).
4// Rotates declared REGIONS of a mesh about declared PIVOTS, region and pivot and angle all DATA rows,
5// never code. Per-vertex selection (a boundary triangle STRETCHES rather than tears -- a crude skin).
6// v1 rotates about the Z axis (lateral raise in the XY plane) -- the measured need; other axes are
7// named rungs. Discipline: `report` measures the cluster ranges FIRST so pose rows are chosen from
8// measurement, not from eyeballing a render.
9//
10// nx_meshpose report <in.nxmesh> <ylo_pm> <yhi_pm> -> x-cluster RANGES (per-mille) in that band
11// nx_meshpose apply <in.nxmesh> <out.nxmesh> <posefile> -> rotated copy (layers/colors preserved)
12// nx_meshpose selftest
13// POSE ROWS (tab-separated): rot <xlo> <xhi> <ylo> <yhi> <pivotx_pm> <pivoty_pm> <deg>
14// bounds+pivot in per-mille of the mesh's own bbox; deg positive = counter-clockwise in +x-right/+y-up.
15// license_tier: ORIGINAL expect_exit: 0
16import "nx_syscalls.nx"
17import "nx_itrig.nx"
18const PZ_MAGIC_65536: i64 = 65536
19const PZ_MAGIC_4096: i64 = 4096
20const PZ_MAGIC_500000: i64 = 500000
21const PZ_MAGIC_100000: i64 = 100000
22const PZ_MAGIC_400000: i64 = 400000
23const PZ_MAGIC_98000: i64 = 98000
24const PZ_MAGIC_102000: i64 = 102000
25const PZ_MAGIC_402000: i64 = 402000
26const PZ_MAGIC_398000: i64 = 398000
27
28const PZ_CAP: i64 = 33554432
29const PZ_BINS: i64 = 128
30const PZ_GAP: i64 = 2
31const PZ_M8388607: i64 = 8388607
32const PZ_M8388608: i64 = 8388608
33const PZ_BIG: i64 = 4611686018427387903
34const PZ_TAB: i64 = 9
35const PZ_NL: i64 = 10
36const PZ_TWOPI: i64 = 25736
37
38func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
39func pn(v: i64) -> i64 { let b: *u8=sys_mmap(32) as *u8; var x: i64=v; var ng: i64=0; if x<0{ng=1;x=0-x} var i: i64=31; if x==0{b[i]=48 as u8;i=i-1} while x>0{b[i]=(48+x%10) as u8;x=x/10;i=i-1} if ng==1{b[i]=45 as u8;i=i-1} sys_write(1,(b as i64+i+1) as *u8,31-i); return 0 }
40func pz_u32(b: *u8, o: i64) -> i64 { return (b[o] as i64) + ((b[o+1] as i64)<<8) + ((b[o+2] as i64)<<16) + ((b[o+3] as i64)<<24) }
41func pz_w32(b: *u8, o: i64, v: i64) -> i64 { b[o]=(v&255) as u8; b[o+1]=((v>>8)&255) as u8; b[o+2]=((v>>16)&255) as u8; b[o+3]=((v>>24)&255) as u8; return 0 }
42// f32 bits (mm) -> um and back
43func pz_f2um(w: i64) -> i64 {
44 let sign: i64 = (w >> 31) & 1
45 let expo: i64 = (w >> 23) & 255
46 if expo == 0 { return 0 }
47 var mant: i64 = (w & PZ_M8388607) | PZ_M8388608
48 let sh: i64 = expo - 127
49 var v: i64 = 0
50 if sh >= 23 { if sh - 23 > 30 { return 0 } }
51 if sh >= 23 { v = mant * 1000 * (1 << (sh - 23)) }
52 if sh < 23 { if 23 - sh > 62 { return 0 } }
53 if sh < 23 { v = (mant * 1000) >> (23 - sh) }
54 if sign == 1 { return 0 - v }
55 return v
56}
57func pz_um2f(v: i64) -> i64 {
58 if v == 0 { return 0 }
59 var neg: i64 = 0
60 var m: i64 = v
61 if m < 0 { neg = 1; m = 0-m }
62 var e: i64 = 0
63 var num: i64 = m
64 var den: i64 = 1000
65 while num >= den*2 { den = den*2; e = e+1 }
66 while num < den { num = num*2; e = e-1 }
67 let frac: i64 = ((num - den)*PZ_M8388608)/den
68 var bits: i64 = ((e+127) << 23) | (frac & PZ_M8388607)
69 if neg == 1 { bits = bits | (1<<31) }
70 return bits
71}
72func pz_refuse(reason: *u8) -> i64 { hw("MESHPOSE REFUSED: " as *u8); hw(reason); hw("\n" as *u8); return 0 }
73func pz_readall(path: *u8, buf: *u8, cap: i64) -> i64 {
74 let fd: i64 = sys_openat_rd(path)
75 if fd < 0 { return 0 - 1 }
76 var n: i64 = 0
77 var go: i64 = 1
78 while go == 1 {
79 let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, cap - n)
80 if r <= 0 { go = 0 } else { n = n + r }
81 if n >= cap { go = 0 }
82 }
83 sys_close(fd)
84 return n
85}
86func pz_argint(s: *u8) -> i64 {
87 var v: i64 = 0
88 var neg: i64 = 0
89 var i: i64 = 0
90 if s[0] == (45 as u8) { neg = 1; i = 1 }
91 while s[i] != (0 as u8) {
92 let ch: i64 = s[i] as i64
93 if ch >= 48 { if ch <= 57 { v = v*10 + (ch-48) } }
94 i = i + 1
95 }
96 if neg == 1 { return 0 - v }
97 return v
98}
99func pz_int(b: *u8, a: i64, e: i64) -> i64 {
100 var v: i64 = 0
101 var neg: i64 = 0
102 var i: i64 = a
103 if i < e { if b[i] == (45 as u8) { neg = 1; i = i + 1 } }
104 while i < e {
105 let ch: i64 = b[i] as i64
106 if ch >= 48 { if ch <= 57 { v = v*10 + (ch-48) } }
107 i = i + 1
108 }
109 if neg == 1 { return 0 - v }
110 return v
111}
112func pz_eol(b: *u8, n: i64, i: i64) -> i64 {
113 var e: i64 = i
114 var f: i64 = 0
115 while f == 0 { if e >= n { f = 1 } else { if b[e] == (PZ_NL as u8) { f = 1 } else { e = e + 1 } } }
116 return e
117}
118func pz_cols(b: *u8, ls: i64, le: i64, col: *i64, maxc: i64) -> i64 {
119 var c: i64 = 0
120 var p: i64 = ls
121 while c < maxc {
122 var q: i64 = p
123 var f: i64 = 0
124 while f == 0 { if q >= le { f = 1 } else { if b[q] == (PZ_TAB as u8) { f = 1 } else { q = q + 1 } } }
125 col[c*2] = p
126 col[c*2+1] = q
127 if q >= le { c = c + 1; while c < maxc { col[c*2] = le; col[c*2+1] = le; c = c + 1 } return c }
128 p = q + 1
129 c = c + 1
130 }
131 return c
132}
133
134// header sanity + bbox over all vertex coords; fills bb[0..5] = mnx mxx mny mxy mnz mxz (um)
135func pz_bbox(b: *u8, n: i64, bb: *i64) -> i64 {
136 if n < 44 { return 0 - 1 }
137 if b[0] != (78 as u8) { return 0 - 1 }
138 if b[5] != (50 as u8) { return 0 - 1 }
139 let nlay: i64 = pz_u32(b, 8)
140 let nt: i64 = pz_u32(b, 12)
141 if nt <= 0 { return 0 - 1 }
142 let hdr: i64 = 16 + nlay*24
143 if hdr + nt*84 > n { return 0 - 1 }
144 bb[0] = PZ_BIG
145 bb[1] = 0-PZ_BIG
146 bb[2] = PZ_BIG
147 bb[3] = 0-PZ_BIG
148 bb[4] = PZ_BIG
149 bb[5] = 0-PZ_BIG
150 var t: i64 = 0
151 while t < nt {
152 var c: i64 = 0
153 while c < 3 {
154 let x: i64 = pz_f2um(pz_u32(b, hdr + t*84 + c*12))
155 let y: i64 = pz_f2um(pz_u32(b, hdr + t*84 + c*12 + 4))
156 let z: i64 = pz_f2um(pz_u32(b, hdr + t*84 + c*12 + 8))
157 if x < bb[0] { bb[0] = x }
158 if x > bb[1] { bb[1] = x }
159 if y < bb[2] { bb[2] = y }
160 if y > bb[3] { bb[3] = y }
161 if z < bb[4] { bb[4] = z }
162 if z > bb[5] { bb[5] = z }
163 c = c + 1
164 }
165 t = t + 1
166 }
167 return nt
168}
169
170// report: x-cluster RANGES (per-mille) among vertices whose y falls in [ylo_pm, yhi_pm]
171func pz_report(path: *u8, ylo: i64, yhi: i64) -> i64 {
172 let b: *u8 = sys_mmap(PZ_CAP + 64)
173 let n: i64 = pz_readall(path, b, PZ_CAP)
174 let bb: *i64 = sys_mmap(64) as *i64
175 let nt: i64 = pz_bbox(b, n, bb)
176 if nt < 0 { pz_refuse("mesh unreadable or not NXMSH2" as *u8); return 3 }
177 let nlay: i64 = pz_u32(b, 8)
178 let hdr: i64 = 16 + nlay*24
179 var wid: i64 = bb[1] - bb[0]
180 if wid < 1 { wid = 1 }
181 var hgt: i64 = bb[3] - bb[2]
182 if hgt < 1 { hgt = 1 }
183 let occ: *i64 = sys_mmap(PZ_BINS*8) as *i64
184 var i: i64 = 0
185 while i < PZ_BINS { occ[i] = 0; i = i + 1 }
186 var t: i64 = 0
187 while t < nt {
188 var c: i64 = 0
189 while c < 3 {
190 let x: i64 = pz_f2um(pz_u32(b, hdr + t*84 + c*12))
191 let y: i64 = pz_f2um(pz_u32(b, hdr + t*84 + c*12 + 4))
192 let ypm: i64 = (y - bb[2])*1000/hgt
193 if ypm >= ylo { if ypm <= yhi {
194 var xi: i64 = (x - bb[0])*PZ_BINS/wid
195 if xi < 0 { xi = 0 }
196 if xi >= PZ_BINS { xi = PZ_BINS-1 }
197 occ[xi] = occ[xi] + 1
198 } }
199 c = c + 1
200 }
201 t = t + 1
202 }
203 hw("{\x22organ\x22:\x22nx_meshpose\x22,\x22verb\x22:\x22report\x22,\x22band_pm\x22:[" as *u8); pn(ylo)
204 hw("," as *u8); pn(yhi)
205 hw("]" as *u8)
206 hw(",\x22clusters\x22:[" as *u8)
207 var inrun: i64 = 0
208 var empty: i64 = 0
209 var lo: i64 = 0
210 var first: i64 = 1
211 i = 0
212 while i < PZ_BINS {
213 if occ[i] > 0 {
214 if inrun == 0 { lo = i; inrun = 1 }
215 empty = 0
216 } else {
217 if inrun == 1 {
218 empty = empty + 1
219 if empty >= PZ_GAP {
220 if first == 0 { hw("," as *u8) }
221 first = 0
222 hw("[" as *u8); pn(lo*1000/PZ_BINS); hw("," as *u8); pn((i-empty+1)*1000/PZ_BINS); hw("]" as *u8)
223 inrun = 0
224 }
225 }
226 }
227 i = i + 1
228 }
229 if inrun == 1 {
230 if first == 0 { hw("," as *u8) }
231 hw("[" as *u8); pn(lo*1000/PZ_BINS); hw("," as *u8); pn(1000); hw("]" as *u8)
232 }
233 hw("],\x22bbox_um\x22:[" as *u8); pn(bb[0]); hw("," as *u8); pn(bb[1]); hw("," as *u8); pn(bb[2]); hw("," as *u8); pn(bb[3])
234 hw("]}\n" as *u8)
235 return 0
236}
237
238// apply: rotate region vertices about pivot in the XY plane; normals rotate too (no translation)
239func pz_apply(inp: *u8, outp: *u8, posep: *u8) -> i64 {
240 let b: *u8 = sys_mmap(PZ_CAP + 64)
241 let n: i64 = pz_readall(inp, b, PZ_CAP)
242 let bb: *i64 = sys_mmap(64) as *i64
243 let nt: i64 = pz_bbox(b, n, bb)
244 if nt < 0 { pz_refuse("mesh unreadable or not NXMSH2" as *u8); return 3 }
245 let pb: *u8 = sys_mmap(PZ_MAGIC_65536)
246 let pnn: i64 = pz_readall(posep, pb, PZ_MAGIC_65536)
247 if pnn <= 0 { pz_refuse("pose file unreadable or empty -- refusing to guess a pose" as *u8); return 4 }
248 let nlay: i64 = pz_u32(b, 8)
249 let hdr: i64 = 16 + nlay*24
250 var wid: i64 = bb[1] - bb[0]
251 if wid < 1 { wid = 1 }
252 var hgt: i64 = bb[3] - bb[2]
253 if hgt < 1 { hgt = 1 }
254 let col: *i64 = sys_mmap(16*2*8) as *i64
255 var nrot: i64 = 0
256 var moved: i64 = 0
257 var pi: i64 = 0
258 while pi < pnn {
259 let le: i64 = pz_eol(pb, pnn, pi)
260 if le > pi {
261 pz_cols(pb, pi, le, col, 8)
262 // rot row: fields 1..7 = xlo xhi ylo yhi pivx pivy deg
263 if pb[col[0]] == (114 as u8) {
264 nrot = nrot + 1
265 let xlo: i64 = pz_int(pb, col[2], col[3])
266 let xhi: i64 = pz_int(pb, col[4], col[5])
267 let ylo2: i64 = pz_int(pb, col[6], col[7])
268 let yhi2: i64 = pz_int(pb, col[8], col[9])
269 let pvx: i64 = bb[0] + pz_int(pb, col[10], col[11])*wid/1000
270 let pvy: i64 = bb[2] + pz_int(pb, col[12], col[13])*hgt/1000
271 let deg: i64 = pz_int(pb, col[14], col[15])
272 let ang: i64 = deg * PZ_TWOPI / 360
273 let s: i64 = it_sin4096(ang)
274 let cz: i64 = it_cos4096(ang)
275 var t: i64 = 0
276 while t < nt {
277 var c: i64 = 0
278 while c < 3 {
279 let po: i64 = hdr + t*84 + c*12
280 let x: i64 = pz_f2um(pz_u32(b, po))
281 let y: i64 = pz_f2um(pz_u32(b, po + 4))
282 let xpm: i64 = (x - bb[0])*1000/wid
283 let ypm: i64 = (y - bb[2])*1000/hgt
284 var inr: i64 = 0
285 if xpm >= xlo { if xpm <= xhi { if ypm >= ylo2 { if ypm <= yhi2 { inr = 1 } } } }
286 if inr == 1 {
287 let dx: i64 = x - pvx
288 let dy: i64 = y - pvy
289 let nx: i64 = pvx + (cz*dx - s*dy)/PZ_MAGIC_4096
290 let ny: i64 = pvy + (s*dx + cz*dy)/PZ_MAGIC_4096
291 pz_w32(b, po, pz_um2f(nx))
292 pz_w32(b, po + 4, pz_um2f(ny))
293 // rotate the vertex normal too (offsets 36 + c*12 within the record)
294 let no: i64 = hdr + t*84 + 36 + c*12
295 let nxo: i64 = pz_f2um(pz_u32(b, no))
296 let nyo: i64 = pz_f2um(pz_u32(b, no + 4))
297 pz_w32(b, no, pz_um2f((cz*nxo - s*nyo)/PZ_MAGIC_4096))
298 pz_w32(b, no + 4, pz_um2f((s*nxo + cz*nyo)/PZ_MAGIC_4096))
299 moved = moved + 1
300 }
301 c = c + 1
302 }
303 t = t + 1
304 }
305 }
306 }
307 pi = le + 1
308 }
309 if nrot == 0 { pz_refuse("no rot rows in the pose file" as *u8); return 4 }
310 if moved == 0 { pz_refuse("rot rows matched ZERO vertices -- region bounds select nothing (measure with `report` first)" as *u8); return 5 }
311 let fd: i64 = sys_openat_wr(outp, 420)
312 if fd < 0 { pz_refuse("output unwritable" as *u8); return 6 }
313 sys_write(fd, b, n)
314 sys_close(fd)
315 hw("{\x22organ\x22:\x22nx_meshpose\x22,\x22verb\x22:\x22apply\x22,\x22rot_rows\x22:" as *u8); pn(nrot)
316 hw(",\x22vertices_moved\x22:" as *u8); pn(moved)
317 hw(",\x22tris\x22:" as *u8); pn(nt)
318 hw(",\x22note\x22:\x22per-vertex region selection: boundary triangles stretch (crude skin), never tear; layers/colors preserved byte-for-byte\x22}\n" as *u8)
319 return 0
320}
321
322// ---- teeth (literal-args discipline: nx_cc wrong-slot bug 1785936860) ----
323func st_w32(b: *u8, o: i64, v: i64) -> i64 { return pz_w32(b, o, v) }
324func st_fix(path: *u8) -> i64 {
325 // one tri arm: (0,-500)(100,-500)(0,-400) mm hanging below origin
326 let b: *u8 = sys_mmap(256)
327 b[0]=78 as u8; b[1]=88 as u8; b[2]=77 as u8; b[3]=83 as u8
328 b[4]=72 as u8; b[5]=50 as u8; b[6]=0 as u8; b[7]=0 as u8
329 st_w32(b, 8, 1)
330 st_w32(b, 12, 1)
331 var q: i64 = 0
332 while q < 16 { b[16+q] = 0 as u8; q = q + 1 }
333 b[16]=115 as u8
334 st_w32(b, 32, 0)
335 st_w32(b, 36, 1)
336 var k: i64 = 0
337 while k < 21 { st_w32(b, 40 + k*4, 0); k = k + 1 }
338 st_w32(b, 40, 0)
339 st_w32(b, 44, pz_um2f(0-PZ_MAGIC_500000))
340 st_w32(b, 52, pz_um2f(PZ_MAGIC_100000))
341 st_w32(b, 56, pz_um2f(0-PZ_MAGIC_500000))
342 st_w32(b, 64, 0)
343 st_w32(b, 68, pz_um2f(0-PZ_MAGIC_400000))
344 st_w32(b, 124, 0)
345 let fd: i64 = sys_openat_wr(path, 420)
346 if fd < 0 { return 0 - 1 }
347 sys_write(fd, b, 128)
348 sys_close(fd)
349 return 0
350}
351func st_wr(path: *u8, s: *u8) -> i64 {
352 var n: i64 = 0
353 while s[n] != (0 as u8) { n = n + 1 }
354 let fd: i64 = sys_openat_wr(path, 420)
355 if fd < 0 { return 0 - 1 }
356 sys_write(fd, s, n)
357 sys_close(fd)
358 return 0
359}
360func pz_selftest() -> i64 {
361 var fails: i64 = 0
362 st_fix("/tmp/pz_arm.nxmesh" as *u8)
363 // whole mesh is the region; pivot at bbox top-left corner (0 pm, 1000 pm) = (0, -400mm); +90 deg
364 st_wr("/tmp/pz_pose.txt" as *u8, "rot\t0\t1000\t0\t1000\t0\t1000\t90\n" as *u8)
365 hw("T0 rotate hanging arm +90 about its shoulder -> tip must land at (-100, -500)->( -100? ): expect x flip\n" as *u8)
366 if pz_apply("/tmp/pz_arm.nxmesh" as *u8, "/tmp/pz_out.nxmesh" as *u8, "/tmp/pz_pose.txt" as *u8) != 0 { fails = fails + 1; hw("T0 FAIL apply refused\n" as *u8) } else {
367 let b2: *u8 = sys_mmap(PZ_MAGIC_4096)
368 let n2: i64 = pz_readall("/tmp/pz_out.nxmesh" as *u8, b2, PZ_MAGIC_4096)
369 if n2 < 128 { fails = fails + 1; hw("T0 FAIL output short\n" as *u8) } else {
370 // v0 was (0,-500) rel pivot (0,-400): d=(0,-100) -> +90 -> (100, 0) -> abs (100000, -400000)
371 let vx: i64 = pz_f2um(pz_u32(b2, 40))
372 let vy: i64 = pz_f2um(pz_u32(b2, 44))
373 var ok: i64 = 1
374 if vx < PZ_MAGIC_98000 { ok = 0 }
375 if vx > PZ_MAGIC_102000 { ok = 0 }
376 if vy < 0-PZ_MAGIC_402000 { ok = 0 }
377 if vy > 0-PZ_MAGIC_398000 { ok = 0 }
378 if ok == 1 { hw("T0 PASS v0 rotated to (~100mm, ~-400mm) analytic\n" as *u8) } else { fails = fails + 1; hw("T0 FAIL v0 at (" as *u8); pn(vx); hw("," as *u8); pn(vy); hw(") expected (~100000,~-400000)\n" as *u8) }
379 }
380 }
381 // ⚠first fixture used [0..10]pm^2 -- which CONTAINS the bbox corner vertex at (0pm,0pm). A region
382 // meant to select nothing must avoid the corners: the tri's vertices sit at (0,0)(1000,0)(0,1000)pm,
383 // so the centre square is honestly empty.
384 st_wr("/tmp/pz_none.txt" as *u8, "rot\t400\t600\t400\t600\t0\t0\t90\n" as *u8)
385 hw("T1 region selecting nothing must REFUSE (measure first, never silently no-op):\n" as *u8)
386 if pz_apply("/tmp/pz_arm.nxmesh" as *u8, "/tmp/pz_x.nxmesh" as *u8, "/tmp/pz_none.txt" as *u8) == 0 { fails = fails + 1; hw("T1 FAIL empty region accepted\n" as *u8) } else { hw("T1 PASS refused\n" as *u8) }
387 hw("T2 absent pose file must REFUSE:\n" as *u8)
388 if pz_apply("/tmp/pz_arm.nxmesh" as *u8, "/tmp/pz_y.nxmesh" as *u8, "/tmp/pz_absent_zz.txt" as *u8) == 0 { fails = fails + 1; hw("T2 FAIL\n" as *u8) } else { hw("T2 PASS\n" as *u8) }
389 hw("T3 report on the fixture: vertex-binned, so a 1-tri fixture reads its CORNERS as 2 clusters (real bodies are dense; the fixture is the degenerate case, stated not hidden):\n" as *u8)
390 if pz_report("/tmp/pz_arm.nxmesh" as *u8, 0, 1000) != 0 { fails = fails + 1; hw("T3 FAIL report refused\n" as *u8) } else { hw("T3 PASS\n" as *u8) }
391 if fails == 0 { hw("MESHPOSE-SELFTEST GREEN 4/4\n" as *u8); return 0 }
392 hw("MESHPOSE-SELFTEST RED fails=" as *u8); pn(fails); hw("\n" as *u8)
393 return 1
394}
395
396func main(argc: i64, argv: *i64) -> i64 {
397 if argc < 2 {
398 hw("usage: nx_meshpose report <in> <ylo_pm> <yhi_pm> | apply <in> <out> <posefile> | selftest\n" as *u8)
399 sys_exit(2)
400 return 2
401 }
402 let a1: *u8 = argv[1] as *u8
403 if a1[0] == (115 as u8) { let rc: i64 = pz_selftest(); sys_exit(rc); return rc }
404 if a1[0] == (114 as u8) {
405 if argc < 5 { hw("usage: nx_meshpose report <in> <ylo_pm> <yhi_pm>\n" as *u8); sys_exit(2); return 2 }
406 let rc2: i64 = pz_report(argv[2] as *u8, pz_argint(argv[3] as *u8), pz_argint(argv[4] as *u8))
407 sys_exit(rc2)
408 return rc2
409 }
410 if a1[0] == (97 as u8) {
411 if argc < 5 { hw("usage: nx_meshpose apply <in> <out> <posefile>\n" as *u8); sys_exit(2); return 2 }
412 let rc3: i64 = pz_apply(argv[2] as *u8, argv[3] as *u8, argv[4] as *u8)
413 sys_exit(rc3)
414 return rc3
415 }
416 hw("unknown verb\n" as *u8)
417 sys_exit(2)
418 return 2
419}