code wiki / _hdl_build / nx_uiq_responsive.nx
nx_uiq_responsive.nx source
↩ module page · 466 lines · 20061 B
1// nx_uiq_responsive.nx -- THE SEVENTH nx_uiq_* RULER: the responsive-layout auditor the family lacked.
2//
3// WHY THIS EXISTS (measured 2026-08-10): the estate had SIX nx_uiq_* rulers (contrast/wire/perf/visual/
4// atree/sentinel) and NOT ONE measured responsive layout. nx_uiq_perf's only "media" reference is
5// `unsized_media` (a CLS proxy). Consequence, measured on the live site: nx_page_verify returned
6// VERDICT=GREEN / a11y-issues=0 on nishifamily.com/games while that page's Connect Four board is a
7// FIXED 368px grid that overflows every phone -- and it had been live for ~53 days.
8// => A GREEN FROM AN INSTRUMENT THAT CANNOT SEE THE DEFECT READS AS "THE PAGE IS FINE".
9//
10// THE RULER IS NOT INVENTED (family doctrine: name a real external bar, never a taste).
11// PRIMARY : W3C WCAG 2.1 SC 1.4.10 "Reflow" (Level AA) -- content must reflow to 320 CSS px
12// WITHOUT requiring scrolling in two dimensions. => a fixed-track grid whose own
13// minimum width exceeds 320px cannot conform, whatever the rest of the page does.
14// SECONDARY: SC 2.5.8 "Target Size (Minimum)" (AA) = 24x24 CSS px floor for pointer targets.
15// SECONDARY: SC 1.4.4 "Resize Text" (AA) -- suppressing zoom (user-scalable=no / maximum-scale=1)
16// fails it outright.
17//
18// WHAT IT COMPUTES (arithmetic, never a vibe). For every `repeat(<N>,<W>px)` track list it finds the
19// ENCLOSING RULE BLOCK and sums that grid's own intrinsic minimum width:
20// min_width = N*W + (N-1)*gap + 2*padding_horizontal
21// The live Connect Four board is the worked example this organ was built against:
22// 7*46 + 6*5 + 2*8 = 322 + 30 + 16 = 368 > 320 => RED
23// `repeat(auto-fill,minmax(...))` and other non-numeric counts parse as NOT-FIXED and are skipped --
24// that shape IS responsive, so counting it would be a false positive.
25//
26// DECLARED IMPRECISION (family law: document the imprecision or the next reader trusts it as exact):
27// * The gate compares the grid's OWN min width against 320 and deliberately does NOT add ancestor
28// container padding. Attributing padding across nesting needs a cascade model a flat scan does not
29// have, and over-counting it would manufacture false positives. So T1 is a LOWER BOUND on the width
30// actually required: it fires only when the board ALONE cannot fit. `container_pad_max` is REPORTED
31// (not gated) so a reader can see the real budget is 320 - that.
32// * Tap-target sizing is read from blocks declaring `cursor:pointer`. A target sized purely by content
33// or by a shorthand this scan does not model is reported as UNKNOWN, never as a pass.
34// * This is a STATIC auditor. It proves the source-visible causes of a reflow failure; it does not
35// render. A PASS here is NECESSARY, NOT SUFFICIENT -- same honest envelope as nx_uiq_perf.
36//
37// Composes the family lib (DRY: io + find + syscalls) rather than re-implementing them.
38// usage: nx_uiq_responsive --kat | <html-file-path>
39// exit : 0 GREEN | 1 RED | 2 cannot-read <- THE EXIT CODE CARRIES THE VERDICT (family law: a gate
40// whose exit code does not carry its verdict silently blesses every failure it finds).
41// license_tier: ORIGINAL expect_exit: 0
42import "nx_uiq_color.nx"
43const K_MAGIC_2097152: i64 = 2097152
44const RSP_REFLOW_PX: i64 = 320 // WCAG 2.1 SC 1.4.10 Reflow bar
45const RSP_TAP_MIN_PX: i64 = 24 // WCAG 2.2 SC 2.5.8 Target Size (Minimum), AA
46
47// ---------- tiny scanners ----------
48
49// literal search from `from`; byte offset or -1.
50func rsp_find_from(buf: *u8, n: i64, pat: *u8, from: i64) -> i64 {
51 var pl: i64=0
52 while pat[pl]!=(0 as u8) { pl=pl+1 }
53 if pl==0 { return 0-1 }
54 var i: i64=from
55 if i<0 { i=0 }
56 while i+pl<=n {
57 var j: i64=0
58 var ok: i64=1
59 while j<pl { if buf[i+j]!=pat[j] { ok=0; j=pl } else { j=j+1 } }
60 if ok==1 { return i }
61 i=i+1
62 }
63 return 0-1
64}
65
66// count occurrences of a literal.
67func rsp_count(buf: *u8, n: i64, pat: *u8) -> i64 {
68 var pl: i64=0
69 while pat[pl]!=(0 as u8) { pl=pl+1 }
70 if pl==0 { return 0 }
71 var c: i64=0
72 var i: i64 = rsp_find_from(buf,n,pat,0)
73 while i>=0 { c=c+1; i=rsp_find_from(buf,n,pat,i+pl) }
74 return c
75}
76
77// skip spaces only.
78func rsp_sp(buf: *u8, n: i64, i: i64) -> i64 {
79 var j: i64=i
80 var run: i64=1
81 while run==1 {
82 if j<n { if buf[j]==(32 as u8) { j=j+1 } else { run=0 } } else { run=0 }
83 }
84 return j
85}
86// skip spaces and commas (track-list separators).
87func rsp_sepc(buf: *u8, n: i64, i: i64) -> i64 {
88 var j: i64=i
89 var run: i64=1
90 while run==1 {
91 if j<n {
92 let c: i64=buf[j] as i64
93 if c==32 { j=j+1 } else { if c==44 { j=j+1 } else { run=0 } }
94 } else { run=0 }
95 }
96 return j
97}
98// skip an alphabetic unit run (px, em, rem, ...).
99func rsp_unit(buf: *u8, n: i64, i: i64) -> i64 {
100 var j: i64=i
101 var run: i64=1
102 while run==1 {
103 if j<n {
104 let c: i64=buf[j] as i64
105 var al: i64=0
106 if c>=97 { if c<=122 { al=1 } }
107 if c>=65 { if c<=90 { al=1 } }
108 if al==1 { j=j+1 } else { run=0 }
109 } else { run=0 }
110 }
111 return j
112}
113
114// parse a decimal at i. returns value or -1 when no digit is present. end index lands in pend[0].
115// NOTE: a separate `pend` out-slot rather than clobbering the cursor -- family law: a loop that breaks
116// by clobbering its own cursor cannot also report where it stopped.
117func rsp_num(buf: *u8, n: i64, i: i64, pend: *i64) -> i64 {
118 var v: i64=0
119 var j: i64=i
120 var any: i64=0
121 var run: i64=1
122 while run==1 {
123 if j<n {
124 let c: i64=buf[j] as i64
125 if c>=48 {
126 if c<=57 { v=v*10+(c-48); j=j+1; any=1 } else { run=0 }
127 } else { run=0 }
128 } else { run=0 }
129 }
130 pend[0]=j
131 if any==0 { return 0-1 }
132 return v
133}
134
135// enclosing declaration block for a byte offset: first '{' at/behind i, and first '}' at/after i.
136func rsp_blk_start(buf: *u8, i: i64) -> i64 {
137 var j: i64=i
138 var run: i64=1
139 while run==1 {
140 if j>0 { if buf[j]==(123 as u8) { run=0 } else { j=j-1 } } else { run=0 }
141 }
142 return j
143}
144func rsp_blk_end(buf: *u8, n: i64, i: i64) -> i64 {
145 var j: i64=i
146 var run: i64=1
147 while run==1 {
148 if j<n { if buf[j]==(125 as u8) { run=0 } else { j=j+1 } } else { run=0 }
149 }
150 return j
151}
152
153// FIRST px value of `prop` inside [a,b). -1 = absent.
154func rsp_prop_px(buf: *u8, a: i64, b: i64, prop: *u8) -> i64 {
155 var pl: i64=0
156 while prop[pl]!=(0 as u8) { pl=pl+1 }
157 if pl==0 { return 0-1 }
158 let pe: *i64 = sys_mmap(16) as *i64
159 var found: i64=0-1
160 var i: i64=a
161 var stop: i64=0
162 while stop==0 {
163 if i+pl>b { stop=1 } else {
164 var j: i64=0
165 var ok: i64=1
166 while j<pl { if buf[i+j]!=prop[j] { ok=0; j=pl } else { j=j+1 } }
167 if ok==1 {
168 var k: i64 = rsp_sp(buf,b,i+pl)
169 if k<b {
170 if buf[k]==(58 as u8) {
171 k = rsp_sp(buf,b,k+1)
172 let v: i64 = rsp_num(buf,b,k,pe)
173 if v>=0 { found=v; stop=1 } else { i=i+1 }
174 } else { i=i+1 }
175 } else { i=i+1 }
176 } else { i=i+1 }
177 }
178 }
179 return found
180}
181
182// HORIZONTAL px value of a 1-or-2-value shorthand inside [a,b): `padding:8px` -> 8 ;
183// `padding:10px 0` -> 0 ; `padding:0 20px` -> 20. CSS shorthand semantics: 1 value = all sides,
184// 2 values = vertical horizontal. -1 = absent.
185func rsp_prop_px_h(buf: *u8, a: i64, b: i64, prop: *u8) -> i64 {
186 var pl: i64=0
187 while prop[pl]!=(0 as u8) { pl=pl+1 }
188 if pl==0 { return 0-1 }
189 let pe: *i64 = sys_mmap(16) as *i64
190 var found: i64=0-1
191 var i: i64=a
192 var stop: i64=0
193 while stop==0 {
194 if i+pl>b { stop=1 } else {
195 var j: i64=0
196 var ok: i64=1
197 while j<pl { if buf[i+j]!=prop[j] { ok=0; j=pl } else { j=j+1 } }
198 if ok==1 {
199 var k: i64 = rsp_sp(buf,b,i+pl)
200 if k<b {
201 if buf[k]==(58 as u8) {
202 k = rsp_sp(buf,b,k+1)
203 let v1: i64 = rsp_num(buf,b,k,pe)
204 if v1>=0 {
205 var m: i64 = rsp_unit(buf,b,pe[0])
206 m = rsp_sp(buf,b,m)
207 let v2: i64 = rsp_num(buf,b,m,pe)
208 if v2>=0 { found=v2 } else { found=v1 }
209 stop=1
210 } else { i=i+1 }
211 } else { i=i+1 }
212 } else { i=i+1 }
213 } else { i=i+1 }
214 }
215 }
216 return found
217}
218
219// largest horizontal container padding declared anywhere (REPORTED, never gated -- see the
220// DECLARED IMPRECISION note in the header).
221func rsp_container_pad(buf: *u8, n: i64) -> i64 {
222 var worst: i64=0
223 var i: i64 = rsp_find_from(buf,n,"padding" as *u8,0)
224 while i>=0 {
225 let a: i64 = rsp_blk_start(buf,i)
226 let b: i64 = rsp_blk_end(buf,n,i)
227 let p: i64 = rsp_prop_px_h(buf,a,b,"padding" as *u8)
228 if p>worst { worst=p }
229 i = rsp_find_from(buf,n,"padding" as *u8,i+7)
230 }
231 return worst
232}
233
234// ---------- the reflow measurement ----------
235// res[0]=fixed_grids res[1]=worst_min_px res[2]=reflow_fails res[3]=widest_cols
236func rsp_grids(buf: *u8, n: i64, res: *i64) -> i64 {
237 let pe: *i64 = sys_mmap(16) as *i64
238 var grids: i64=0
239 var worst: i64=0
240 var fails: i64=0
241 var wcols: i64=0
242 var i: i64 = rsp_find_from(buf,n,"repeat(" as *u8,0)
243 while i>=0 {
244 var k: i64 = rsp_sepc(buf,n,i+7)
245 let cnt: i64 = rsp_num(buf,n,k,pe)
246 if cnt>0 {
247 k = rsp_sepc(buf,n,pe[0])
248 let w: i64 = rsp_num(buf,n,k,pe)
249 if w>0 {
250 // the track width must be an absolute px length; anything else is not a fixed track.
251 var ispx: i64=0
252 let q: i64 = pe[0]
253 if q+1<n { if buf[q]==(112 as u8) { if buf[q+1]==(120 as u8) { ispx=1 } } }
254 if ispx==1 {
255 let a: i64 = rsp_blk_start(buf,i)
256 let b: i64 = rsp_blk_end(buf,n,i)
257 var gap: i64 = rsp_prop_px(buf,a,b,"gap" as *u8)
258 if gap<0 { gap=0 }
259 var pad: i64 = rsp_prop_px_h(buf,a,b,"padding" as *u8)
260 if pad<0 { pad=0 }
261 let mw: i64 = cnt*w + (cnt-1)*gap + 2*pad
262 grids=grids+1
263 if mw>worst { worst=mw; wcols=cnt }
264 if mw>RSP_REFLOW_PX { fails=fails+1 }
265 }
266 }
267 }
268 i = rsp_find_from(buf,n,"repeat(" as *u8,i+7)
269 }
270 res[0]=grids; res[1]=worst; res[2]=fails; res[3]=wcols
271 return fails
272}
273
274// ---------- tap targets ----------
275// smallest declared pointer-target edge, or -1 when none is DECLARED (UNKNOWN, never a pass).
276func rsp_tap_min(buf: *u8, n: i64) -> i64 {
277 var smallest: i64=0-1
278 var i: i64 = rsp_find_from(buf,n,"cursor" as *u8,0)
279 while i>=0 {
280 let a: i64 = rsp_blk_start(buf,i)
281 let b: i64 = rsp_blk_end(buf,n,i)
282 if rsp_find_from(buf,b,"pointer" as *u8,a)>=0 {
283 let w: i64 = rsp_prop_px(buf,a,b,"width" as *u8)
284 let h: i64 = rsp_prop_px(buf,a,b,"height" as *u8)
285 var e: i64 = 0-1
286 if w>=0 { e=w }
287 if h>=0 { if e<0 { e=h } else { if h<e { e=h } } }
288 if e>=0 { if smallest<0 { smallest=e } else { if e<smallest { smallest=e } } }
289 }
290 i = rsp_find_from(buf,n,"cursor" as *u8,i+6)
291 }
292 return smallest
293}
294
295// ---------- zoom / viewport ----------
296// bit0 = viewport meta declares width=device-width ; bit1 = zoom is suppressed (SC 1.4.4 fail)
297func rsp_zoom(buf: *u8, n: i64) -> i64 {
298 var f: i64=0
299 if rsp_find_from(buf,n,"width=device-width" as *u8,0)>=0 { f=f+1 }
300 if rsp_find_from(buf,n,"user-scalable=no" as *u8,0)>=0 { f=f+2 }
301 if rsp_find_from(buf,n,"maximum-scale=1" as *u8,0)>=0 { if ((f/2) & 1)==0 { f=f+2 } }
302 return f
303}
304
305// ---------- audit ----------
306// emit=1 -> JSON. returns total issues (0 = GREEN).
307func rsp_audit(buf: *u8, n: i64, emit: i64) -> i64 {
308 let res: *i64 = sys_mmap(64) as *i64
309 rsp_grids(buf,n,res)
310 let grids: i64=res[0]
311 let worst: i64=res[1]
312 let reflow: i64=res[2]
313 let wcols: i64=res[3]
314 let tap: i64 = rsp_tap_min(buf,n)
315 let zf: i64 = rsp_zoom(buf,n)
316 let vp: i64 = zf & 1
317 let nozoom: i64 = (zf/2) & 1
318 let media: i64 = rsp_count(buf,n,"@media" as *u8)
319 let cpad: i64 = rsp_container_pad(buf,n)
320
321 var tapfail: i64=0
322 if tap>=0 { if tap<RSP_TAP_MIN_PX { tapfail=1 } }
323 var vpfail: i64=0
324 if vp==0 { vpfail=1 }
325 // ADAPTIVE: fixed-track grids with no media query at all cannot adapt. Bound to its denominator
326 // (family law: a tooth that passes on the empty set is not a tooth) -- only asserted when grids>0.
327 var adapt: i64=0
328 if grids>0 { if media==0 { adapt=1 } }
329
330 let issues: i64 = reflow + tapfail + nozoom + vpfail + adapt
331
332 if emit==1 {
333 uiq_w("{\"bar\":\"WCAG 2.1 SC 1.4.10 Reflow @ " as *u8); uiq_pn(RSP_REFLOW_PX); uiq_w("px\"" as *u8)
334 uiq_w(",\"bytes\":" as *u8); uiq_pn(n)
335 uiq_w(",\"fixed_grids\":" as *u8); uiq_pn(grids)
336 uiq_w(",\"worst_grid_min_px\":" as *u8); uiq_pn(worst)
337 uiq_w(",\"worst_grid_cols\":" as *u8); uiq_pn(wcols)
338 uiq_w(",\"reflow_fails\":" as *u8); uiq_pn(reflow)
339 uiq_w(",\"container_pad_max_px\":" as *u8); uiq_pn(cpad)
340 uiq_w(",\"effective_budget_px\":" as *u8); uiq_pn(RSP_REFLOW_PX-cpad)
341 uiq_w(",\"tap_min_px\":" as *u8)
342 if tap<0 { uiq_w("\"UNKNOWN\"" as *u8) } else { uiq_pn(tap) }
343 uiq_w(",\"tap_fail\":" as *u8); uiq_pn(tapfail)
344 uiq_w(",\"viewport_meta_ok\":" as *u8); uiq_pn(vp)
345 uiq_w(",\"zoom_suppressed\":" as *u8); uiq_pn(nozoom)
346 uiq_w(",\"media_queries\":" as *u8); uiq_pn(media)
347 uiq_w(",\"no_adaptive_rule\":" as *u8); uiq_pn(adapt)
348 uiq_w(",\"issues\":" as *u8); uiq_pn(issues)
349 uiq_w(",\"verdict\":\"" as *u8)
350 if issues==0 { uiq_w("GREEN" as *u8) } else { uiq_w("RED" as *u8) }
351 uiq_w("\"}" as *u8)
352 let nl: *u8 = sys_mmap(2); nl[0]=10 as u8
353 sys_write(1,nl,1)
354 }
355 return issues
356}
357
358func rsp_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8) { n=n+1 } return n }
359
360// ---------- self-test: BOTH DIRECTIONS, and it asserts the ARITHMETIC not just the branch ----------
361// Family law: a green that never had a corresponding red is unverified; and a deny-guard ships with a
362// POSITIVE control (an input that MUST be allowed) or a guard that refuses everything passes every
363// negative test.
364func rsp_selftest() -> i64 {
365 var f: i64=0
366 let res: *i64 = sys_mmap(64) as *i64
367
368 // (1) NEG-CONTROL / THE REAL DEFECT: the live Connect Four board, verbatim shape.
369 // 7*46 + 6*5 + 2*8 = 368. Assert the NUMBER -- proving the branch fired is not proving the maths.
370 let c4: *u8 = "#c4{display:inline-grid;grid-template-columns:repeat(7,46px);grid-gap:5px;background:#0e2a4a;padding:8px;border-radius:10px;margin:10px 0}" as *u8
371 rsp_grids(c4, rsp_len(c4), res)
372 if res[0]!=1 { f=f+1 } // exactly one fixed grid found
373 if res[1]!=368 { f=f+1 } // the arithmetic itself
374 if res[2]!=1 { f=f+1 } // and it fails the 320px bar
375 if res[3]!=7 { f=f+1 } // 7 columns
376
377 // (2) POSITIVE CONTROL: the live Tic-Tac-Toe board FITS -- 3*72 + 2*6 = 228 <= 320.
378 // Without this, a ruler that flagged every fixed grid would score 100% on (1).
379 let ttt: *u8 = "#ttt{display:grid;grid-template-columns:repeat(3,72px);grid-gap:6px;margin:10px 0}" as *u8
380 rsp_grids(ttt, rsp_len(ttt), res)
381 if res[0]!=1 { f=f+1 }
382 if res[1]!=228 { f=f+1 }
383 if res[2]!=0 { f=f+1 } // must NOT fire
384
385 // (3) auto-fill/minmax is genuinely responsive -> must parse as NOT a fixed grid (no false positive).
386 let af: *u8 = ".grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));grid-gap:12px}" as *u8
387 rsp_grids(af, rsp_len(af), res)
388 if res[0]!=0 { f=f+1 }
389 if res[2]!=0 { f=f+1 }
390
391 // (4) ANTI-VACUITY: no grid at all -> zero found AND no reflow claim. Bounds the tooth to its
392 // denominator so it cannot "pass" on an empty population.
393 let ng: *u8 = "body{margin:0;color:#111}" as *u8
394 rsp_grids(ng, rsp_len(ng), res)
395 if res[0]!=0 { f=f+1 }
396 if res[2]!=0 { f=f+1 }
397
398 // (5) shorthand horizontal padding semantics: 1 value = all, 2 values = vertical horizontal.
399 let p1: *u8 = "x{padding:8px}" as *u8
400 if rsp_prop_px_h(p1,0,rsp_len(p1),"padding" as *u8)!=8 { f=f+1 }
401 let p2: *u8 = "x{padding:0 20px}" as *u8
402 if rsp_prop_px_h(p2,0,rsp_len(p2),"padding" as *u8)!=20 { f=f+1 }
403 let p3: *u8 = "x{padding:10px 0}" as *u8
404 if rsp_prop_px_h(p3,0,rsp_len(p3),"padding" as *u8)!=0 { f=f+1 }
405
406 // (6) zoom suppression (SC 1.4.4) is caught, and a clean viewport is not falsely accused.
407 let z1: *u8 = "<meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'>" as *u8
408 let zr1: i64 = rsp_zoom(z1,rsp_len(z1))
409 if (zr1 & 1)!=1 { f=f+1 }
410 if ((zr1/2) & 1)!=1 { f=f+1 }
411 let z2: *u8 = "<meta name='viewport' content='width=device-width,initial-scale=1'>" as *u8
412 let zr2: i64 = rsp_zoom(z2,rsp_len(z2))
413 if (zr2 & 1)!=1 { f=f+1 }
414 if ((zr2/2) & 1)!=0 { f=f+1 }
415
416 // (7) tap target: an UNDECLARED size must report UNKNOWN (-1), never a pass.
417 let t0: *u8 = "a{color:#111}" as *u8
418 if rsp_tap_min(t0,rsp_len(t0))!=(0-1) { f=f+1 }
419 let t1: *u8 = ".d{width:18px;height:18px;cursor:pointer}" as *u8
420 if rsp_tap_min(t1,rsp_len(t1))!=18 { f=f+1 }
421
422 // (8) END-TO-END both directions on whole-page fixtures.
423 // RED: fixed 368px board, no media query.
424 let bad: *u8 = "<meta name='viewport' content='width=device-width,initial-scale=1'><style>#c4{display:inline-grid;grid-template-columns:repeat(7,46px);grid-gap:5px;padding:8px}</style>" as *u8
425 if rsp_audit(bad,rsp_len(bad),0)<1 { f=f+1 }
426 // GREEN: fluid grid + a media query + a compliant viewport.
427 let good: *u8 = "<meta name='viewport' content='width=device-width,initial-scale=1'><style>.g{display:grid;grid-template-columns:repeat(auto-fill,minmax(90px,1fr));gap:8px}@media(max-width:640px){.g{gap:6px}}</style>" as *u8
428 if rsp_audit(good,rsp_len(good),0)!=0 { f=f+1 }
429 return f
430}
431
432func rsp_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
433 let fd: i64 = sys_openat_rd(path)
434 if fd<0 { return 0 }
435 var total: i64=0
436 var nrd: i64=sys_read(fd, buf, cap)
437 while nrd>0 {
438 total=total+nrd
439 if total>=cap { nrd=0 } else { nrd=sys_read(fd, ((buf as i64)+total) as *u8, cap-total) }
440 }
441 sys_close(fd)
442 return total
443}
444
445func main(argc: i64, argv: *i64) -> i64 {
446 if argc>=2 {
447 let a1: *u8 = argv[1] as *u8
448 if a1[0]==(45 as u8) {
449 uiq_w("=== nx_uiq_responsive --kat (WCAG 2.1 SC 1.4.10 Reflow @ 320px) ===\n" as *u8)
450 let f: i64 = rsp_selftest()
451 uiq_w("checks failed=" as *u8); uiq_pn(f)
452 uiq_w(" (c4-368-neg-control + ttt-228-pos-control + autofill-no-false-positive + anti-vacuity + shorthand + zoom + tap + e2e-both-directions)\n" as *u8)
453 if f==0 { uiq_w("VERDICT=GREEN\n" as *u8); sys_exit(0); return 0 }
454 uiq_w("VERDICT=RED\n" as *u8); sys_exit(1); return 1
455 }
456 let cap: i64 = K_MAGIC_2097152
457 let buf: *u8 = sys_mmap(cap)
458 let n: i64 = rsp_slurp(a1, buf, cap)
459 if n<=0 { uiq_w("{\"error\":\"cannot read page\"}\n" as *u8); sys_exit(2); return 2 }
460 let issues: i64 = rsp_audit(buf, n, 1)
461 if issues==0 { sys_exit(0); return 0 }
462 sys_exit(1); return 1
463 }
464 uiq_w("usage: nx_uiq_responsive --kat | <html-file-path>\n" as *u8)
465 sys_exit(2); return 2
466}