code wiki / _hdl_build / nx_surrogate.nx

nx_surrogate.nx source

↩ module page · 212 lines · 20213 B

1// nx_surrogate.nx -- the KEYSTONE data structure of the Nishi clean-view sandbox (per the 17-agent browser- 2// hardening-sota spec): a DATA-DRIVEN SURROGATE/ACTION table, superset of nx_web_filter. The winning discipline 3// is SURROGATE-AND-SATISFY, not strip-and-block: every delete/block is read-back-detectable and the hostile page 4// re-walls. Instead, each rule carries (a) an ACTION on a ladder block->synthesize->scrub_forward->allow that 5// nx_extract_heal walks UP on an observed re-wall, and (b) a SURROGATE payload = the engine-native decoy to hand 6// back on "synthesize" (a stub global, a fake-window, a synthesized Response, a filled bait div, a byte-exact 7// source replay). Same [kind,pat,patlen,category] matcher as nx_web_filter, plus action/surrogate/confidence/ 8// heal-origin columns. This is the single SSOT every sandbox behavior reads from. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_media_signal.nx" // xt_find substring 11 12// what TRIGGERS a rule (the query context -- keeps a popup "*" from matching a network URL, etc.) 13const SM_URL: i64 = 1 // a network request URL (fetch/xhr/beacon/pixel) 14const SM_GLOBAL: i64 = 2 // a global-name read (window.FuckAdBlock, ga, gtag...) 15const SM_SELECTOR: i64 = 3 // a DOM selector (bait ad-div) 16const SM_CNAME: i64 = 4 // a resolved CNAME canonical host 17const SM_POPUP: i64 = 5 // a window.open() target 18// ACTION ladder (ascending -- heal graduates UP on re-wall) 19const SA_BLOCK: i64 = 1 20const SA_SYNTHESIZE: i64 = 2 21const SA_SCRUB: i64 = 3 // scrub_forward: send the REAL request, PII/exfil-params stripped 22const SA_ALLOW: i64 = 4 23// SURROGATE kind (what to hand back on synthesize) 24const SK_NONE: i64 = 0 25const SK_GLOBAL_STUB: i64 = 1 // define window.<name> as engine-native no-op(s) 26const SK_FAKE_WINDOW: i64 = 2 // VAL_WINDOWPROXY decoy Window 27const SK_RESPONSE: i64 = 3 // synthesized native Response / true 28const SK_RESTIMING: i64 = 4 // mint a PerformanceResourceTiming entry 29const SK_BAIT_FILL: i64 = 5 // leave bait DOM + force success geometry/attrs 30const SK_SOURCE_REPLAY: i64 = 6 // byte-exact toString replay of a captured lib 31const SK_HIDE: i64 = 7 // hide the element in the rendered clean-view (overlay walls) 32// category 33const SC_AD: i64 = 1 34const SC_TRACK: i64 = 2 35const SC_MINER: i64 = 3 36const SC_POPUP: i64 = 4 37const SC_ANTIADBLOCK: i64 = 5 38const SC_OVERLAY: i64 = 6 // full-page wall / interstitial / paywall / cookie-consent overlay (hide in render) 39// provenance 40const SO_SEEDED: i64 = 0 41const SO_LEARNED: i64 = 1 42 43const SG_STRIDE: i64 = 10 // [match_kind, pat_ptr, patlen, category, action, surr_kind, conf, origin, aux_ptr, aux_len] 44const SG_MAX: i64 = 2048 45 46func sg_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 47func sg_new() -> *i64 { let t: *i64 = sys_mmap(8 * (1 + SG_MAX * SG_STRIDE)) as *i64; t[0] = 0; return t } 48func sg_add(t: *i64, mk: i64, pat: *u8, patlen: i64, cat: i64, action: i64, sk: i64, conf: i64, origin: i64, aux: *u8, auxlen: i64) -> i64 { 49 if t[0] >= SG_MAX { return 0 - 1 } 50 let b: i64 = 1 + t[0] * SG_STRIDE 51 t[b]=mk; t[b+1]=pat as i64; t[b+2]=patlen; t[b+3]=cat; t[b+4]=action; t[b+5]=sk; t[b+6]=conf; t[b+7]=origin; t[b+8]=aux as i64; t[b+9]=auxlen 52 let row: i64 = t[0] 53 t[0] = t[0] + 1 54 return row 55} 56func sg_addc(t: *i64, mk: i64, pat: *u8, cat: i64, action: i64, sk: i64, conf: i64, origin: i64, aux: *u8) -> i64 { 57 return sg_add(t, mk, pat, sg_slen(pat), cat, action, sk, conf, origin, aux, sg_slen(aux)) 58} 59// SEED with the spec's keystone entries (the 4 exemplars + the core global stubs). 60func sg_seed(t: *i64) -> i64 { 61 // 1. GA4 collect endpoints -> synthesize a native cors Response (never drop; a dropped beacon is a tell) 62 sg_addc(t, SM_URL, "/g/collect" as *u8, SC_TRACK, SA_SYNTHESIZE, SK_RESPONSE, 100, SO_SEEDED, "type=cors;transferSize=35;latency=30-180" as *u8) 63 sg_addc(t, SM_URL, "/mp/collect" as *u8, SC_TRACK, SA_SYNTHESIZE, SK_RESPONSE, 100, SO_SEEDED, "type=cors;transferSize=35;latency=30-180" as *u8) 64 sg_addc(t, SM_URL, "google-analytics.com" as *u8, SC_TRACK, SA_SYNTHESIZE, SK_RESPONSE, 95, SO_SEEDED, "type=cors;transferSize=35" as *u8) 65 sg_addc(t, SM_URL, "/collect?" as *u8, SC_TRACK, SA_SYNTHESIZE, SK_RESPONSE, 90, SO_SEEDED, "type=cors;transferSize=35" as *u8) 66 // GA / gtag globals -> engine-native no-op stubs, event_callback fired on a timer 67 sg_addc(t, SM_GLOBAL, "gtag" as *u8, SC_TRACK, SA_SYNTHESIZE, SK_GLOBAL_STUB, 100, SO_SEEDED, "noop;fire_event_callback_on_timer" as *u8) 68 sg_addc(t, SM_GLOBAL, "ga" as *u8, SC_TRACK, SA_SYNTHESIZE, SK_GLOBAL_STUB, 100, SO_SEEDED, "noop;q_shim" as *u8) 69 sg_addc(t, SM_GLOBAL, "dataLayer" as *u8, SC_TRACK, SA_SYNTHESIZE, SK_GLOBAL_STUB, 100, SO_SEEDED, "array;push_noop" as *u8) 70 // 2. window.open (non-gesture) -> fake-window surrogate; nx_popup_allow gates a real gesture'd first-party open 71 sg_addc(t, SM_POPUP, "*" as *u8, SC_POPUP, SA_SYNTHESIZE, SK_FAKE_WINDOW, 100, SO_SEEDED, "distinct_per_call;coherent_closed;xorigin_throws;native_open" as *u8) 72 // 3. anti-adblock detectors -> byte-exact source-replay stub + fake success globals (heal fills captured_src) 73 sg_addc(t, SM_GLOBAL, "FuckAdBlock" as *u8, SC_ANTIADBLOCK, SA_SYNTHESIZE, SK_SOURCE_REPLAY, 90, SO_SEEDED, "canRunAds=true;keep_bait_geometry;emit_no_detected" as *u8) 74 sg_addc(t, SM_GLOBAL, "BlockAdBlock" as *u8, SC_ANTIADBLOCK, SA_SYNTHESIZE, SK_SOURCE_REPLAY, 90, SO_SEEDED, "canRunAds=true;keep_bait_geometry" as *u8) 75 sg_addc(t, SM_GLOBAL, "adsbygoogle" as *u8, SC_AD, SA_SYNTHESIZE, SK_GLOBAL_STUB, 100, SO_SEEDED, "array_subclass;push_fills_container" as *u8) 76 // 4. bait ad-div selectors -> leave intact + force success DOM (size-inferred box, data-ad-status, child, RT) 77 sg_addc(t, SM_SELECTOR, ".ad-slot" as *u8, SC_AD, SA_SYNTHESIZE, SK_BAIT_FILL, 100, SO_SEEDED, "force_box=300x250;data-ad-status=filled;inject_sized_child;mint_resource_timing" as *u8) 78 sg_addc(t, SM_SELECTOR, "ins.adsbygoogle" as *u8, SC_AD, SA_SYNTHESIZE, SK_BAIT_FILL, 100, SO_SEEDED, "force_box=728x90;data-ad-status=filled;mint_resource_timing" as *u8) 79 sg_addc(t, SM_SELECTOR, "[data-ad-client]" as *u8, SC_AD, SA_SYNTHESIZE, SK_BAIT_FILL, 95, SO_SEEDED, "force_box=300x250;data-ad-status=filled" as *u8) 80 // crypto-miner loaders -> block outright (no gate to satisfy; containment is the point) 81 sg_addc(t, SM_URL, "coinhive" as *u8, SC_MINER, SA_BLOCK, SK_NONE, 100, SO_SEEDED, "" as *u8) 82 sg_addc(t, SM_URL, "/miner.js" as *u8, SC_MINER, SA_BLOCK, SK_NONE, 100, SO_SEEDED, "" as *u8) 83 // OVERLAY WALLS -> hidden in the rendered clean-view (CSS selectors; single-quoted so no \" in the literal). 84 // Conservative, wall-specific patterns (adblock/interstitial/paywall/consent/backdrop) -- not generic "modal". 85 sg_addc(t, SM_SELECTOR, "[class*='disable-adblock']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 100, SO_SEEDED, "" as *u8) 86 sg_addc(t, SM_SELECTOR, "[class*='adblock-']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 95, SO_SEEDED, "" as *u8) 87 sg_addc(t, SM_SELECTOR, "[class*='-adblock']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 95, SO_SEEDED, "" as *u8) 88 sg_addc(t, SM_SELECTOR, "[id*='adblock']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 95, SO_SEEDED, "" as *u8) 89 sg_addc(t, SM_SELECTOR, "[class*='interstitial']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 90, SO_SEEDED, "" as *u8) 90 sg_addc(t, SM_SELECTOR, "[class*='paywall']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 90, SO_SEEDED, "" as *u8) 91 sg_addc(t, SM_SELECTOR, "[class*='modal-backdrop']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 85, SO_SEEDED, "" as *u8) 92 sg_addc(t, SM_SELECTOR, "[class*='overlay-backdrop']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 85, SO_SEEDED, "" as *u8) 93 sg_addc(t, SM_SELECTOR, "[class*='cookie-wall']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 80, SO_SEEDED, "" as *u8) 94 sg_addc(t, SM_SELECTOR, "[id*='gdpr']" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 75, SO_SEEDED, "" as *u8) 95 sg_addc(t, SM_SELECTOR, ".fc-consent-root" as *u8, SC_OVERLAY, SA_BLOCK, SK_HIDE, 90, SO_SEEDED, "" as *u8) 96 return 0 97} 98// BUILD OVERLAY-NEUTRALIZER CSS: restore scroll (walls freeze body overflow) + hide the SC_OVERLAY selectors. 99// Injected into the rendered clean-view <head>. Data-driven -> nx_extract_heal can add a new wall selector. 100func sg_build_overlay_css(t: *i64, out: *u8, cap: i64) -> i64 { 101 var o: i64 = sg_puts(out, 0, "html{overflow:auto !important;overflow-y:auto !important}body{overflow:auto !important;position:static !important;height:auto !important}" as *u8) 102 var i: i64 = 0 103 while i < t[0] { 104 let b: i64 = 1 + i * SG_STRIDE 105 if t[b+3] == SC_OVERLAY { 106 let pat: *u8 = (t[b+1]) as *u8; let pl: i64 = t[b+2] 107 var k: i64 = 0 108 while k < pl { if o < (cap - 60) { out[o] = pat[k]; o = o + 1 } k = k + 1 } 109 o = sg_puts(out, o, "{display:none !important;visibility:hidden !important;opacity:0 !important;pointer-events:none !important}" as *u8) 110 } 111 i = i + 1 112 } 113 out[o] = 0 as u8 114 return o 115} 116// is a pattern the wildcard "*"? 117func sg_is_wild(pat: *u8, patlen: i64) -> i64 { if patlen == 1 { if (pat[0]&0xff) == 42 { return 1 } } return 0 } 118// MATCH: find the best (highest-confidence) rule for (match_kind, key). Returns row index or -1. 119func sg_match(t: *i64, mk: i64, key: *u8, keylen: i64) -> i64 { 120 var best: i64 = 0 - 1 121 var bestconf: i64 = 0 - 1 122 var i: i64 = 0 123 while i < t[0] { 124 let b: i64 = 1 + i * SG_STRIDE 125 if t[b] == mk { 126 let pat: *u8 = (t[b+1]) as *u8; let pl: i64 = t[b+2] 127 var hit: i64 = 0 128 if sg_is_wild(pat, pl) == 1 { hit = 1 } else { if xt_find(key, keylen, pat, pl, 0) >= 0 { hit = 1 } } 129 if hit == 1 { if t[b+6] > bestconf { bestconf = t[b+6]; best = i } } 130 } 131 i = i + 1 132 } 133 return best 134} 135// row field accessors 136func sg_action(t: *i64, row: i64) -> i64 { return t[1 + row*SG_STRIDE + 4] } 137func sg_surrogate(t: *i64, row: i64) -> i64 { return t[1 + row*SG_STRIDE + 5] } 138func sg_category(t: *i64, row: i64) -> i64 { return t[1 + row*SG_STRIDE + 3] } 139func sg_conf(t: *i64, row: i64) -> i64 { return t[1 + row*SG_STRIDE + 6] } 140func sg_origin(t: *i64, row: i64) -> i64 { return t[1 + row*SG_STRIDE + 7] } 141func sg_aux(t: *i64, row: i64) -> *u8 { return (t[1 + row*SG_STRIDE + 8]) as *u8 } 142func sg_aux_len(t: *i64, row: i64) -> i64 { return t[1 + row*SG_STRIDE + 9] } 143// GRADUATE: on an observed re-wall (our decoy was detected), walk the action ladder UP one step, capped at ALLOW. 144// This is the nx_extract_heal move -- a rule self-escalates block->synthesize->scrub_forward->allow with no code. 145func sg_graduate(t: *i64, row: i64) -> i64 { 146 let idx: i64 = 1 + row*SG_STRIDE + 4 147 if t[idx] < SA_ALLOW { t[idx] = t[idx] + 1 } 148 return t[idx] 149} 150// LEARN: heal adds a learned rule (a site's new detector/tracker signature -> a synthesize surrogate). Returns row. 151func sg_learn(t: *i64, mk: i64, pat: *u8, cat: i64, sk: i64, aux: *u8) -> i64 { 152 return sg_addc(t, mk, pat, cat, SA_SYNTHESIZE, sk, 55, SO_LEARNED, aux) 153} 154// CLASSIFY a network URL in one call -> action + surrogate kind (the fetch/beacon/pixel entry point). 155func sg_classify_url(t: *i64, url: *u8, ulen: i64, out_action: *i64, out_kind: *i64) -> i64 { 156 let row: i64 = sg_match(t, SM_URL, url, ulen) 157 if row < 0 { out_action[0] = SA_ALLOW; out_kind[0] = SK_NONE; return 0 - 1 } 158 out_action[0] = sg_action(t, row); out_kind[0] = sg_surrogate(t, row) 159 return row 160} 161func sg_puts(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off]=s[i];off=off+1;i=i+1} return off } 162// BUILD PREAMBLE: emit the surrogate scriptlet JS that runs in the sandbox BEFORE the page's own scripts, so the 163// page's anti-adblock / tracker gates read back as SUCCESS and the gated media fetch fires. This is the "satisfy" 164// half of surrogate-and-satisfy, in pure JS (userland now; the native-builtin registry hardens toString later). 165// Defensive: shims window/document/navigator if the engine lacks them, so a page that assumes a browser runs. 166// Returns the preamble length. (Emitted as ONE line-safe program; the sandbox concatenates the page after it.) 167func sg_build_preamble(t: *i64, out: *u8, cap: i64) -> i64 { 168 var o: i64 = 0 169 // ⚠ ENGINE FACTS (diagnosed): native document/navigator/location/window EXIST + native bindings are 170 // non-writable (re-shimming throws); NEW window.* props ARE writable; arrays REJECT named props (.loaded 171 // throws) but functions accept them (.q/.queue ok); and `window.X=v` does NOT alias the bare global `X`. 172 // So every stub is defined BOTH as a bare `var X` (bare reads) AND `window.X` (window-scoped reads). 173 o = sg_puts(out, o, "var window=(typeof window!=='undefined')?window:this;var self=window;var top=window;var parent=window;" as *u8) 174 // anti-adblock success globals 175 o = sg_puts(out, o, "var canRunAds=true;var isAdBlockActive=false;var adblockDetector=false;var google_ad_status=1;window.canRunAds=true;window.google_ad_status=1;window.google_ad_modifications={ad_frame:1};" as *u8) 176 // tracker no-op stubs (bare + window). ga/gtag/fbq = functions w/ expected side-props; dataLayer/adsbygoogle 177 // = REAL arrays (native push harmless; overriding push or adding named props throws in this engine). 178 o = sg_puts(out, o, "var ga=function(){};ga.q=[];ga.l=1;window.ga=ga;var gtag=function(){};window.gtag=gtag;var __gaTracker=function(){};window.__gaTracker=__gaTracker;var fbq=function(){};fbq.queue=[];window.fbq=fbq;" as *u8) 179 o = sg_puts(out, o, "var dataLayer=(window.dataLayer||[]);window.dataLayer=dataLayer;var _gaq=[];window._gaq=_gaq;var adsbygoogle=(window.adsbygoogle||[]);window.adsbygoogle=adsbygoogle;" as *u8) 180 // anti-adblock DEFUSERS (FuckAdBlock/BlockAdBlock family -> always report NOT detected + fire the not-detected cb) 181 o = sg_puts(out, o, "var __FAB=function(){this.onDetected=function(){return this};this.onNotDetected=function(f){if(f){f()}return this};this.on=function(a,f){if(f){f()}return this};this.check=function(){return this};this.setOption=function(){return this};this.emitEvent=function(){return this};this.clearEvent=function(){return this}};" as *u8) 182 o = sg_puts(out, o, "var FuckAdBlock=__FAB;window.FuckAdBlock=__FAB;var BlockAdBlock=__FAB;window.BlockAdBlock=__FAB;var fuckAdBlock=new __FAB();window.fuckAdBlock=fuckAdBlock;var blockAdBlock=new __FAB();window.blockAdBlock=blockAdBlock;window.sniffAdBlock=new __FAB();window.DetectAdBlock=__FAB;" as *u8) 183 // fake window.open -> decoy Window (self-referential, coherent lifecycle) so popups "succeed" without opening. 184 o = sg_puts(out, o, "window.open=function(u,n,f){var w={};w.closed=false;w.focus=function(){};w.blur=function(){};w.close=function(){w.closed=true};w.postMessage=function(){};w.location={href:(u||''),replace:function(){},assign:function(){},reload:function(){}};w.document={write:function(){},writeln:function(){},close:function(){},open:function(){}};w.opener=null;w.name=(n||'');w.self=w;w.window=w;w.top=w;w.parent=w;w.frames=w;w.length=0;return w};" as *u8) 185 // DOM-LIFECYCLE shims: player-init in jQuery/others is deferred to $(document).ready / DOMContentLoaded / onload. 186 // Our engine leaves document.readyState undefined + document.addEventListener a no-op, so that init NEVER runs 187 // and the stream is never fetched. Present an ALREADY-LOADED document: readyState='complete' -> jQuery schedules 188 // ready via setTimeout (which el_drain pumps); documentElement/body/head stubs so jQuery's doScroll/feature 189 // probes don't throw. These props are undefined here -> fresh writable props on `document` (native ones aren't). 190 // nodeType=9 (Document) is LOAD-BEARING: jQuery/Sizzle setDocument() bails `if(doc.nodeType!==9)` -> without it 191 // Sizzle's document var stays undefined and every selector feature-detect (assert->createElement) throws. The 192 // documentElement stub carries nodeType=1 (Element) + nodeName='HTML' so isXMLDoc() classifies it HTML (not XML). 193 // documentElement/body/head STUBS (kept as stubs -- a REAL tree node here loops Sizzle's support asserts 194 // which mutate docElem). BUT borrow a real element's native `matches`/`querySelectorAll` onto the stub so 195 // Sizzle's support.matchesSelector/qsa feature-detects (rnative.test on docElem.matches) PASS -> jQuery 196 // routes .is/.not/.filter(sel)/matchesSelector through our WORKING element.matches instead of its own 197 // (class-blind) compiled matcher. matches.call(realElem, sel) uses the real elem as `this`, so it works. 198 o = sg_puts(out, o, "try{document.readyState='complete';document.nodeType=9;}catch(_ra){}try{if(!document.documentElement){var _pb=document.createElement('div');document.documentElement={nodeType:1,nodeName:'HTML',style:{},doScroll:null,className:'',appendChild:function(){},setAttribute:function(){},getAttribute:function(){return null},matches:_pb.matches,matchesSelector:_pb.matches,webkitMatchesSelector:_pb.matches,mozMatchesSelector:_pb.matches,msMatchesSelector:_pb.matches};}}catch(_de){}try{var _bd0=document.getElementsByTagName?document.getElementsByTagName('body'):[];if(_bd0&&_bd0[0]){document.body=_bd0[0]}else{if(!document.body){document.body={nodeType:1,nodeName:'BODY',style:{},appendChild:function(){},setAttribute:function(){},className:''}}}}catch(_bd){}try{if(!document.head){document.head={nodeType:1,nodeName:'HEAD',appendChild:function(){}};}}catch(_hd){}" as *u8) 199 // createDocumentFragment: jQuery's support detects do `C.createDocumentFragment().appendChild(createElement)` -- 200 // UNCAUGHT (not in an assert), so it must exist. A fragment stub (nodeType 11) whose appendChild returns its 201 // child + cloneNode/removeChild no-ops. The native document has no fragment support in EITHER mode, so this is 202 // the only source (headless feature-detects; tree-mode fragment building is a separate follow-on). 203 o = sg_puts(out, o, "try{if(!document.createDocumentFragment){document.createDocumentFragment=function(){return{nodeType:11,childNodes:[],firstChild:null,lastChild:null,appendChild:function(c){this.firstChild=c;this.lastChild=c;return c},removeChild:function(c){return c},insertBefore:function(c){return c},cloneNode:function(){return document.createDocumentFragment()},querySelectorAll:function(){return[]},getElementById:function(){return null}};};}}catch(_df){}" as *u8) 204 // document.implementation.createHTMLDocument: jQuery.parseHTML's support-detect makes a fresh doc, sets 205 // body.innerHTML, counts childNodes. Body/head/documentElement are REAL createElement nodes so in DOM_TREE 206 // mode innerHTML actually parses (dt_set_inner_html) + childNodes navigation counts correctly. 207 o = sg_puts(out, o, "try{if(!document.implementation){document.implementation={createHTMLDocument:function(t){var d={nodeType:9};d.body=document.createElement('body');d.head=document.createElement('head');d.documentElement=document.createElement('html');d.createElement=function(g){return document.createElement(g)};d.createElementNS=function(n,g){return document.createElement(g)};d.createTextNode=function(x){return document.createTextNode?document.createTextNode(x):document.createElement('span')};d.createDocumentFragment=function(){return document.createDocumentFragment()};d.getElementsByTagName=function(g){return document.getElementsByTagName?document.getElementsByTagName(g):[]};d.getElementById=function(i){return document.getElementById?document.getElementById(i):null};return d;},hasFeature:function(){return true}};}}catch(_im){}" as *u8) 208 // $(document).ready / jQuery(fn): if a page uses the shorthand before jQuery decides, keep the timer path warm. 209 o = sg_puts(out, o, "try{if(document.addEventListener){var __oael=document.addEventListener;document.addEventListener=function(t,f,c){try{if((t==='DOMContentLoaded'||t==='load')&&typeof f==='function'){setTimeout(f,0);}}catch(_ae){}return __oael?__oael.call(document,t,f,c):undefined;};}}catch(_ov){}" as *u8) 210 out[o] = 0 as u8 211 return o 212}